* Re: [PATCH 1/2] backlight: arcxcnn: add support for ArticSand devices
From: Lee Jones @ 2016-11-09 15:53 UTC (permalink / raw)
To: Olimpiu Dejeu
Cc: robh-DgEjT+Ai2ygdnm+yROfE0A, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, jg1.han-Sze3O3UU22JBDgjK7y7TUQ
In-Reply-To: <1477513778-31297-1-git-send-email-olimpiu-eV7fy4qpoLhpLGFMi4vTTA@public.gmane.org>
Jingoo?
On Wed, 26 Oct 2016, Olimpiu Dejeu wrote:
> Resubmition of arcxcnn backliught driver adding devicetree entries
> for all registers
>
> Signed-off-by: Olimpiu Dejeu <olimpiu-eV7fy4qpoLhpLGFMi4vTTA@public.gmane.org>
>
> ---
> drivers/video/backlight/Kconfig | 7 +
> drivers/video/backlight/Makefile | 1 +
> drivers/video/backlight/arcxcnn_bl.c | 541 +++++++++++++++++++++++++++++++++++
> include/linux/i2c/arcxcnn.h | 67 +++++
> 4 files changed, 616 insertions(+)
> create mode 100644 drivers/video/backlight/arcxcnn_bl.c
> create mode 100644 include/linux/i2c/arcxcnn.h
>
> diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
> index 5ffa4b4..4e1d2ad 100644
> --- a/drivers/video/backlight/Kconfig
> +++ b/drivers/video/backlight/Kconfig
> @@ -460,6 +460,13 @@ config BACKLIGHT_BD6107
> help
> If you have a Rohm BD6107 say Y to enable the backlight driver.
>
> +config BACKLIGHT_ARCXCNN
> + tristate "Backlight driver for the Arctic Sands ARCxCnnnn family"
> + depends on I2C
> + help
> + If you have an ARCxCnnnn family backlight say Y to enable
> + the backlight driver.
> +
> endif # BACKLIGHT_CLASS_DEVICE
>
> endif # BACKLIGHT_LCD_SUPPORT
> diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
> index 16ec534..8905129 100644
> --- a/drivers/video/backlight/Makefile
> +++ b/drivers/video/backlight/Makefile
> @@ -55,3 +55,4 @@ obj-$(CONFIG_BACKLIGHT_SKY81452) += sky81452-backlight.o
> obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o
> obj-$(CONFIG_BACKLIGHT_TPS65217) += tps65217_bl.o
> obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o
> +obj-$(CONFIG_BACKLIGHT_ARCXCNN) += arcxcnn_bl.o
> diff --git a/drivers/video/backlight/arcxcnn_bl.c b/drivers/video/backlight/arcxcnn_bl.c
> new file mode 100644
> index 0000000..1dad680
> --- /dev/null
> +++ b/drivers/video/backlight/arcxcnn_bl.c
> @@ -0,0 +1,541 @@
> +/*
> + * Backlight driver for ArcticSand ARC_X_C_0N_0N Devices
> + *
> + * Copyright 2016 ArcticSand, Inc.
> + *
> + * Licensed under the GPL-2 or later.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/i2c.h>
> +#include <linux/backlight.h>
> +#include <linux/err.h>
> +#include <linux/of.h>
> +#include <linux/pwm.h>
> +#include <linux/regulator/consumer.h>
> +
> +#include "linux/i2c/arcxcnn.h"
> +
> +#define ARCXCNN_CMD (0x00) /* Command Register */
> +#define ARCXCNN_CMD_STDBY (0x80) /* I2C Standby */
> +#define ARCXCNN_CMD_RESET (0x40) /* Reset */
> +#define ARCXCNN_CMD_BOOST (0x10) /* Boost */
> +#define ARCXCNN_CMD_OVP_MASK (0x0C) /* --- Over Voltage Threshold */
> +#define ARCXCNN_CMD_OVP_XXV (0x0C) /* <rsvrd> Over Voltage Threshold */
> +#define ARCXCNN_CMD_OVP_20V (0x08) /* 20v Over Voltage Threshold */
> +#define ARCXCNN_CMD_OVP_24V (0x04) /* 24v Over Voltage Threshold */
> +#define ARCXCNN_CMD_OVP_31V (0x00) /* 31.4v Over Voltage Threshold */
> +#define ARCXCNN_CMD_EXT_COMP (0x01) /* part (0) or full (1) external comp */
> +
> +#define ARCXCNN_CONFIG (0x01) /* Configuration */
> +#define ARCXCNN_STATUS1 (0x02) /* Status 1 */
> +#define ARCXCNN_STATUS2 (0x03) /* Status 2 */
> +#define ARCXCNN_FADECTRL (0x04) /* Fading Control */
> +#define ARCXCNN_ILED_CONFIG (0x05) /* ILED Configuration */
> +
> +#define ARCXCNN_LEDEN (0x06) /* LED Enable Register */
> +#define ARCXCNN_LEDEN_ISETEXT (0x80) /* Full-scale current set externally */
> +#define ARCXCNN_LEDEN_MASK (0x3F) /* LED string enables */
> +#define ARCXCNN_LEDEN_LED1 (0x01)
> +#define ARCXCNN_LEDEN_LED2 (0x02)
> +#define ARCXCNN_LEDEN_LED3 (0x04)
> +#define ARCXCNN_LEDEN_LED4 (0x08)
> +#define ARCXCNN_LEDEN_LED5 (0x10)
> +#define ARCXCNN_LEDEN_LED6 (0x20)
> +
> +#define ARCXCNN_WLED_ISET_LSB (0x07) /* LED ISET LSB (in upper nibble) */
> +#define ARCXCNN_WLED_ISET_MSB (0x08) /* LED ISET MSB (8 bits) */
> +
> +#define ARCXCNN_DIMFREQ (0x09)
> +#define ARCXCNN_COMP_CONFIG (0x0A)
> +#define ARCXCNN_FILT_CONFIG (0x0B)
> +#define ARCXCNN_IMAXTUNE (0x0C)
> +
> +#define DEFAULT_BL_NAME "arctic_bl"
> +#define MAX_BRIGHTNESS 4095
> +
> +static int s_no_reset_on_remove;
> +module_param_named(noreset, s_no_reset_on_remove, int, 0644);
> +MODULE_PARM_DESC(noreset, "No reset on module removal");
> +
> +static int s_ibright = 60;
> +module_param_named(ibright, s_ibright, int, 0644);
> +MODULE_PARM_DESC(ibright, "Initial brightness (when no plat data)");
> +
> +static int s_iledstr = 0x3F;
> +module_param_named(iledstr, s_iledstr, int, 0644);
> +MODULE_PARM_DESC(iledstr, "Initial LED String (when no plat data)");
> +
> +static int s_retries = 2; /* 1 == only one try */
> +module_param_named(retries, s_retries, int, 0644);
> +MODULE_PARM_DESC(retries, "I2C retries attempted");
> +
> +enum arcxcnn_brightness_ctrl_mode {
> + PWM_BASED = 1,
> + REGISTER_BASED,
> +};
> +
> +struct arcxcnn;
> +
> +struct arcxcnn {
> + char chipname[64];
> + enum arcxcnn_chip_id chip_id;
> + enum arcxcnn_brightness_ctrl_mode mode;
> + struct i2c_client *client;
> + struct backlight_device *bl;
> + struct device *dev;
> + struct arcxcnn_platform_data *pdata;
> + struct pwm_device *pwm;
> + struct regulator *supply; /* regulator for VDD input */
> +};
> +
> +static int arcxcnn_write_byte(struct arcxcnn *lp, u8 reg, u8 data)
> +{
> + s32 ret = -1;
> + int att;
> +
> + for (att = 0; att < s_retries; att++) {
> + ret = i2c_smbus_write_byte_data(lp->client, reg, data);
> + if (ret >= 0)
> + return 0;
> + }
> + return ret;
> +}
> +
> +static u8 arcxcnn_read_byte(struct arcxcnn *lp, u8 reg)
> +{
> + int val;
> + int att;
> +
> + for (att = 0; att < s_retries; att++) {
> + val = i2c_smbus_read_byte_data(lp->client, reg);
> + if (val >= 0)
> + return (u8)val;
> + }
> + return 0;
> +}
> +
> +static int arcxcnn_update_bit(struct arcxcnn *lp, u8 reg, u8 mask, u8 data)
> +{
> + int ret, att;
> + u8 tmp;
> +
> + for (att = 0, ret = -1; att < s_retries; att++) {
> + ret = i2c_smbus_read_byte_data(lp->client, reg);
> + if (ret >= 0)
> + break;
> + }
> + if (ret < 0) {
> + dev_err(lp->dev, "failed to read 0x%.2x\n", reg);
> + return ret;
> + }
> +
> + tmp = (u8)ret;
> + tmp &= ~mask;
> + tmp |= data & mask;
> +
> + return arcxcnn_write_byte(lp, reg, tmp);
> +}
> +
> +static int arcxcnn_set_brightness(struct arcxcnn *lp, u32 brightness)
> +{
> + int ret;
> + u8 val;
> +
> + val = (brightness & 0xF) << 4;
> + ret = arcxcnn_write_byte(lp, ARCXCNN_WLED_ISET_LSB, val);
> + if (ret < 0)
> + return ret;
> + val = (brightness >> 4);
> + ret = arcxcnn_write_byte(lp, ARCXCNN_WLED_ISET_MSB, val);
> + return ret;
> +}
> +
> +static int arcxcnn_bl_update_status(struct backlight_device *bl)
> +{
> + struct arcxcnn *lp = bl_get_data(bl);
> + u32 brightness = bl->props.brightness;
> +
> + if (bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
> + brightness = 0;
> +
> + /* set brightness */
> + if (lp->mode == PWM_BASED)
> + ; /* via pwm */
> + else if (lp->mode == REGISTER_BASED)
> + arcxcnn_set_brightness(lp, brightness);
> +
> + /* set power-on/off/save modes */
> + if (bl->props.power == 0)
> + /* take out of standby */
> + arcxcnn_update_bit(lp, ARCXCNN_CMD, ARCXCNN_CMD_STDBY, 0);
> + else
> + /* 1-3 == power save, 4 = off
> + * place in low-power standby mode
> + */
> + arcxcnn_update_bit(lp, ARCXCNN_CMD,
> + ARCXCNN_CMD_STDBY, ARCXCNN_CMD_STDBY);
> + return 0;
> +}
> +
> +static const struct backlight_ops arcxcnn_bl_ops = {
> + .options = BL_CORE_SUSPENDRESUME,
> + .update_status = arcxcnn_bl_update_status,
> +};
> +
> +static int arcxcnn_backlight_register(struct arcxcnn *lp)
> +{
> + struct backlight_device *bl;
> + struct backlight_properties props;
> + struct arcxcnn_platform_data *pdata = lp->pdata;
> + const char *name = pdata->name ? : DEFAULT_BL_NAME;
> +
> + memset(&props, 0, sizeof(props));
> + props.type = BACKLIGHT_PLATFORM;
> + props.max_brightness = MAX_BRIGHTNESS;
> +
> + if (pdata->initial_brightness > props.max_brightness)
> + pdata->initial_brightness = props.max_brightness;
> +
> + props.brightness = pdata->initial_brightness;
> +
> + bl = devm_backlight_device_register(lp->dev, name, lp->dev, lp,
> + &arcxcnn_bl_ops, &props);
> + if (IS_ERR(bl))
> + return PTR_ERR(bl);
> +
> + lp->bl = bl;
> +
> + return 0;
> +}
> +
> +static ssize_t arcxcnn_get_chip_id(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct arcxcnn *lp = dev_get_drvdata(dev);
> +
> + return scnprintf(buf, PAGE_SIZE, "%s\n", lp->chipname);
> +}
> +
> +static ssize_t arcxcnn_get_led_str(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct arcxcnn *lp = dev_get_drvdata(dev);
> +
> + return scnprintf(buf, PAGE_SIZE, "%02X\n", lp->pdata->led_str);
> +}
> +
> +static ssize_t arcxcnn_set_led_str(struct device *dev,
> + struct device_attribute *attr, const char *buf, size_t len)
> +{
> + struct arcxcnn *lp = dev_get_drvdata(dev);
> + unsigned long ledstr;
> +
> + if (kstrtoul(buf, 0, &ledstr))
> + return 0;
> +
> + if (ledstr != lp->pdata->led_str) {
> + /* don't allow 0 for ledstr, use power to turn all off */
> + if (ledstr == 0)
> + return 0;
> + lp->pdata->led_str = ledstr & 0x3F;
> + arcxcnn_update_bit(lp, ARCXCNN_LEDEN,
> + ARCXCNN_LEDEN_MASK, lp->pdata->led_str);
> + }
> + return len;
> +}
> +
> +static ssize_t arcxcnn_get_bl_ctl_mode(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct arcxcnn *lp = dev_get_drvdata(dev);
> + char *strmode = NULL;
> +
> + if (lp->mode == PWM_BASED)
> + strmode = "pwm based";
> + else if (lp->mode == REGISTER_BASED)
> + strmode = "register based";
> +
> + return scnprintf(buf, PAGE_SIZE, "%s\n", strmode);
> +}
> +
> +static DEVICE_ATTR(chip_id, 0444, arcxcnn_get_chip_id, NULL);
> +static DEVICE_ATTR(led_str, 0664, arcxcnn_get_led_str, arcxcnn_set_led_str);
> +static DEVICE_ATTR(bl_ctl_mode, 0444, arcxcnn_get_bl_ctl_mode, NULL);
> +
> +static struct attribute *arcxcnn_attributes[] = {
> + &dev_attr_chip_id.attr,
> + &dev_attr_led_str.attr,
> + &dev_attr_bl_ctl_mode.attr,
> + NULL,
> +};
> +
> +static const struct attribute_group arcxcnn_attr_group = {
> + .attrs = arcxcnn_attributes,
> +};
> +
> +#ifdef CONFIG_OF
> +static int arcxcnn_parse_dt(struct arcxcnn *lp)
> +{
> + struct device *dev = lp->dev;
> + struct device_node *node = dev->of_node;
> + u32 prog_val, num_entry, sources[6];
> + int ret;
> +
> + if (!node) {
> + dev_err(dev, "no platform data.\n");
> + return -EINVAL;
> + }
> + lp->pdata->led_config_0_set = false;
> + lp->pdata->led_config_1_set = false;
> + lp->pdata->dim_freq_set = false;
> + lp->pdata->comp_config_set = false;
> + lp->pdata->filter_config_set = false;
> + lp->pdata->trim_config_set = false;
> +
> + ret = of_property_read_string(node, "label", &lp->pdata->name);
> + if (ret < 0)
> + lp->pdata->name = NULL;
> +
> + ret = of_property_read_u32(node, "default-brightness", &prog_val);
> + if (ret < 0)
> + prog_val = s_ibright;
> + lp->pdata->initial_brightness = prog_val;
> + if (lp->pdata->initial_brightness > MAX_BRIGHTNESS)
> + lp->pdata->initial_brightness = MAX_BRIGHTNESS;
> +
> + ret = of_property_read_u32(node, "arcticsand,led-config-0", &prog_val);
> + if (ret == 0) {
> + lp->pdata->led_config_0 = (u8)prog_val;
> + lp->pdata->led_config_0_set = true;
> + }
> + ret = of_property_read_u32(node, "arcticsand,led-config-1", &prog_val);
> + if (ret == 0) {
> + lp->pdata->led_config_1 = (u8)prog_val;
> + lp->pdata->led_config_1_set = true;
> + }
> + ret = of_property_read_u32(node, "arcticsand,dim-freq", &prog_val);
> + if (ret == 0) {
> + lp->pdata->dim_freq = (u8)prog_val;
> + lp->pdata->dim_freq_set = true;
> + }
> + ret = of_property_read_u32(node, "arcticsand,comp-config", &prog_val);
> + if (ret == 0) {
> + lp->pdata->comp_config = (u8)prog_val;
> + lp->pdata->comp_config_set = true;
> + }
> + ret = of_property_read_u32(node, "arcticsand,filter-config", &prog_val);
> + if (ret == 0) {
> + lp->pdata->filter_config = (u8)prog_val;
> + lp->pdata->filter_config_set = true;
> + }
> + ret = of_property_read_u32(node, "arcticsand,trim-config", &prog_val);
> + if (ret == 0) {
> + lp->pdata->trim_config = (u8)prog_val;
> + lp->pdata->trim_config_set = true;
> + }
> + ret = of_property_count_u32_elems(node, "led-sources");
> + if (ret < 0)
> + lp->pdata->led_str = 0x3F;
> + else {
> + num_entry = ret;
> + if (num_entry > 6)
> + num_entry = 6;
> +
> + ret = of_property_read_u32_array(node, "led-sources", sources,
> + num_entry);
> + if (ret < 0) {
> + dev_err(dev, "led-sources node is invalid.\n");
> + return -EINVAL;
> + }
> +
> + lp->pdata->led_str = 0;
> + while (num_entry > 0)
> + lp->pdata->led_str |= (1 << sources[--num_entry]);
> + }
> + return 0;
> +}
> +#else
> +static int arcxcnn_parse_dt(struct arcxcnn *lp)
> +{
> + return -EINVAL;
> +}
> +#endif
> +
> +static int arcxcnn_probe(struct i2c_client *cl, const struct i2c_device_id *id)
> +{
> + struct arcxcnn *lp;
> + int ret;
> + u8 regval;
> + u16 chipid;
> +
> + if (!i2c_check_functionality(cl->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
> + return -EIO;
> +
> + lp = devm_kzalloc(&cl->dev, sizeof(*lp), GFP_KERNEL);
> + if (!lp)
> + return -ENOMEM;
> +
> + lp->client = cl;
> + lp->dev = &cl->dev;
> + lp->chip_id = id->driver_data;
> + lp->pdata = dev_get_platdata(&cl->dev);
> +
> + if (!lp->pdata) {
> + lp->pdata = devm_kzalloc(lp->dev,
> + sizeof(*lp->pdata), GFP_KERNEL);
> + if (!lp->pdata)
> + return -ENOMEM;
> +
> + /* no platform data, parse the device-tree for info. if there
> + * is no device tree entry, we are being told we exist because
> + * user-land said so, so make up the info we need
> + */
> + ret = arcxcnn_parse_dt(lp);
> + if (ret < 0) {
> + /* no device tree, use defaults based on module params
> + */
> + lp->pdata->led_config_0_set = false;
> + lp->pdata->led_config_1_set = false;
> + lp->pdata->dim_freq_set = false;
> + lp->pdata->comp_config_set = false;
> + lp->pdata->filter_config_set = false;
> + lp->pdata->trim_config_set = false;
> +
> + lp->pdata->name = NULL;
> + lp->pdata->initial_brightness = s_ibright;
> + lp->pdata->led_str = s_iledstr;
> + }
> + }
> +
> + if (lp->pdata->dim_freq_set)
> + lp->mode = PWM_BASED;
> + else
> + lp->mode = REGISTER_BASED;
> +
> + i2c_set_clientdata(cl, lp);
> +
> + /* read device ID */
> + regval = arcxcnn_read_byte(lp, 0x1E);
> + chipid = regval;
> + chipid <<= 8;
> + regval = arcxcnn_read_byte(lp, 0x1F);
> + chipid |= regval;
> +
> + /* make sure it belongs to this driver
> + * TODO - handle specific ids
> + */
> + if (chipid != 0x02A5) {
> + #if 1
> + dev_info(&cl->dev, "Chip Id is %04X\n", chipid);
> + #else
> + dev_err(&cl->dev, "%04X is not ARC2C\n", chipid);
> + return -ENODEV;
> + #endif
> + }
> + /* reset the device */
> + arcxcnn_write_byte(lp, ARCXCNN_CMD, ARCXCNN_CMD_RESET);
> +
> + /* set initial brightness */
> + arcxcnn_set_brightness(lp, lp->pdata->initial_brightness);
> +
> + /* if fadectrl set in DT, set the value directly, else leave default */
> + if (lp->pdata->led_config_0_set)
> + arcxcnn_write_byte(lp, ARCXCNN_FADECTRL,
> + lp->pdata->led_config_0);
> +
> + /* if iled config set in DT, set the value, else internal mode */
> + if (lp->pdata->led_config_1_set)
> + arcxcnn_write_byte(lp, ARCXCNN_ILED_CONFIG,
> + lp->pdata->led_config_1);
> + else
> + arcxcnn_write_byte(lp, ARCXCNN_ILED_CONFIG, 0x57);
> +
> + /* other misc DT settings */
> + if (lp->pdata->dim_freq_set)
> + arcxcnn_write_byte(lp, ARCXCNN_FADECTRL, lp->pdata->dim_freq);
> + if (lp->pdata->comp_config_set)
> + arcxcnn_write_byte(lp, ARCXCNN_COMP_CONFIG,
> + lp->pdata->comp_config);
> + if (lp->pdata->filter_config_set)
> + arcxcnn_write_byte(lp, ARCXCNN_FILT_CONFIG,
> + lp->pdata->filter_config);
> + if (lp->pdata->trim_config_set)
> + arcxcnn_write_byte(lp, ARCXCNN_IMAXTUNE,
> + lp->pdata->trim_config);
> +
> + /* set initial LED Strings */
> + arcxcnn_update_bit(lp, ARCXCNN_LEDEN,
> + ARCXCNN_LEDEN_MASK, lp->pdata->led_str);
> +
> + snprintf(lp->chipname, sizeof(lp->chipname),
> + "%s-%04X", id->name, chipid);
> +
> + ret = arcxcnn_backlight_register(lp);
> + if (ret) {
> + dev_err(lp->dev,
> + "failed to register backlight. err: %d\n", ret);
> + return ret;
> + }
> +
> + ret = sysfs_create_group(&lp->dev->kobj, &arcxcnn_attr_group);
> + if (ret) {
> + dev_err(lp->dev, "failed to register sysfs. err: %d\n", ret);
> + return ret;
> + }
> +
> + backlight_update_status(lp->bl);
> + return 0;
> +}
> +
> +static int arcxcnn_remove(struct i2c_client *cl)
> +{
> + struct arcxcnn *lp = i2c_get_clientdata(cl);
> +
> + if (!s_no_reset_on_remove) {
> + /* disable all strings */
> + arcxcnn_write_byte(lp, ARCXCNN_LEDEN, 0x00);
> + /* reset the device */
> + arcxcnn_write_byte(lp, ARCXCNN_CMD, ARCXCNN_CMD_RESET);
> + }
> + lp->bl->props.brightness = 0;
> + backlight_update_status(lp->bl);
> + if (lp->supply)
> + regulator_disable(lp->supply);
> + sysfs_remove_group(&lp->dev->kobj, &arcxcnn_attr_group);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id arcxcnn_dt_ids[] = {
> + { .compatible = "arc,arc2c0608" },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, arcxcnn_dt_ids);
> +
> +/* Note that the device/chip ID is not fixed in silicon so
> + * auto-probing of these devices on the bus is most likely
> + * not possible, use device tree to set i2c bus address
> + */
> +static const struct i2c_device_id arcxcnn_ids[] = {
> + {"arc2c0608", ARC2C0608},
> + { }
> +};
> +MODULE_DEVICE_TABLE(i2c, arcxcnn_ids);
> +
> +static struct i2c_driver arcxcnn_driver = {
> + .driver = {
> + .name = "arcxcnn_bl",
> + .of_match_table = of_match_ptr(arcxcnn_dt_ids),
> + },
> + .probe = arcxcnn_probe,
> + .remove = arcxcnn_remove,
> + .id_table = arcxcnn_ids,
> +};
> +
> +module_i2c_driver(arcxcnn_driver);
> +
> +MODULE_LICENSE("GPL v2");
> +MODULE_AUTHOR("Brian Dodge <bdodge09-1ViLX0X+lBJBDgjK7y7TUQ@public.gmane.org>");
> +MODULE_DESCRIPTION("ARCXCNN Backlight driver");
> diff --git a/include/linux/i2c/arcxcnn.h b/include/linux/i2c/arcxcnn.h
> new file mode 100644
> index 0000000..1c681dd
> --- /dev/null
> +++ b/include/linux/i2c/arcxcnn.h
> @@ -0,0 +1,67 @@
> +/*
> + * Backlight driver for ArcticSand ARC2C0608 Backlight Devices
> + *
> + * Copyright 2016 ArcticSand, Inc.
> + *
> + * Licensed under the GPL-2 or later.
> + */
> +
> +#ifndef _ARCXCNN_H
> +#define _ARCXCNN_H
> +
> +enum arcxcnn_chip_id {
> + ARC2C0608
> +};
> +
> +enum arcxcnn_brightness_source {
> + ARCXCNN_PWM_ONLY,
> + ARCXCNN_I2C_ONLY = 2,
> +};
> +
> +#define ARCXCNN_MAX_PROGENTRIES 48 /* max a/v pairs for custom */
> +
> +/**
> + * struct arcxcnn_platform_data
> + * @name : Backlight driver name. If it is not defined, default name is set.
> + * @initial_brightness : initial value of backlight brightness
> + * @led_str : initial LED string enables, upper bit is global on/off
> + * @led_config_0 : fading speed (period between intensity steps)
> + * @led_config_1 : misc settings, see datasheet
> + * @dim_freq : pwm dimming frequency if in pwm mode
> + * @comp_config : misc config, see datasheet
> + * @filter_config: RC/PWM filter config, see datasheet
> + * @trim_config : full scale current trim, see datasheet
> + * @led_config_0_set : the value in led_config_0 is valid
> + * @led_config_1_set : the value in led_config_1 is valid
> + * @dim_freq_set : the value in dim_freq is valid
> + * @comp_config_set : the value in comp_config is valid
> + * @filter_config_set : the value in filter_config is valid
> + * @trim_config_set : the value in trim_config is valid
> + *
> + * the _set flags are used to indicate that the value was explicitly set
> + * in the device tree or platform data. settings not set are left as default
> + * power-on default values of the chip except for led_str and led_config_1
> + * which are set by the driver (led_str is specified indirectly in the
> + * device tree via "led-sources")
> + */
> +struct arcxcnn_platform_data {
> + const char *name;
> + u16 initial_brightness;
> + u8 led_str;
> +
> + u8 led_config_0;
> + u8 led_config_1;
> + u8 dim_freq;
> + u8 comp_config;
> + u8 filter_config;
> + u8 trim_config;
> +
> + bool led_config_0_set;
> + bool led_config_1_set;
> + bool dim_freq_set;
> + bool comp_config_set;
> + bool filter_config_set;
> + bool trim_config_set;
> +};
> +
> +#endif
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH 1/2] backlight: arcxcnn: add support for ArticSand devices
From: Lee Jones @ 2016-11-09 15:53 UTC (permalink / raw)
To: Olimpiu Dejeu
Cc: robh-DgEjT+Ai2ygdnm+yROfE0A, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-fbdev-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, jg1.han-Sze3O3UU22JBDgjK7y7TUQ
In-Reply-To: <1477513778-31297-1-git-send-email-olimpiu-eV7fy4qpoLhpLGFMi4vTTA@public.gmane.org>
Jingoo?
On Wed, 26 Oct 2016, Olimpiu Dejeu wrote:
> Resubmition of arcxcnn backliught driver adding devicetree entries
> for all registers
>
> Signed-off-by: Olimpiu Dejeu <olimpiu@arcticsand.com>
>
> ---
> drivers/video/backlight/Kconfig | 7 +
> drivers/video/backlight/Makefile | 1 +
> drivers/video/backlight/arcxcnn_bl.c | 541 +++++++++++++++++++++++++++++++++++
> include/linux/i2c/arcxcnn.h | 67 +++++
> 4 files changed, 616 insertions(+)
> create mode 100644 drivers/video/backlight/arcxcnn_bl.c
> create mode 100644 include/linux/i2c/arcxcnn.h
>
> diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
> index 5ffa4b4..4e1d2ad 100644
> --- a/drivers/video/backlight/Kconfig
> +++ b/drivers/video/backlight/Kconfig
> @@ -460,6 +460,13 @@ config BACKLIGHT_BD6107
> help
> If you have a Rohm BD6107 say Y to enable the backlight driver.
>
> +config BACKLIGHT_ARCXCNN
> + tristate "Backlight driver for the Arctic Sands ARCxCnnnn family"
> + depends on I2C
> + help
> + If you have an ARCxCnnnn family backlight say Y to enable
> + the backlight driver.
> +
> endif # BACKLIGHT_CLASS_DEVICE
>
> endif # BACKLIGHT_LCD_SUPPORT
> diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
> index 16ec534..8905129 100644
> --- a/drivers/video/backlight/Makefile
> +++ b/drivers/video/backlight/Makefile
> @@ -55,3 +55,4 @@ obj-$(CONFIG_BACKLIGHT_SKY81452) += sky81452-backlight.o
> obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o
> obj-$(CONFIG_BACKLIGHT_TPS65217) += tps65217_bl.o
> obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o
> +obj-$(CONFIG_BACKLIGHT_ARCXCNN) += arcxcnn_bl.o
> diff --git a/drivers/video/backlight/arcxcnn_bl.c b/drivers/video/backlight/arcxcnn_bl.c
> new file mode 100644
> index 0000000..1dad680
> --- /dev/null
> +++ b/drivers/video/backlight/arcxcnn_bl.c
> @@ -0,0 +1,541 @@
> +/*
> + * Backlight driver for ArcticSand ARC_X_C_0N_0N Devices
> + *
> + * Copyright 2016 ArcticSand, Inc.
> + *
> + * Licensed under the GPL-2 or later.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/i2c.h>
> +#include <linux/backlight.h>
> +#include <linux/err.h>
> +#include <linux/of.h>
> +#include <linux/pwm.h>
> +#include <linux/regulator/consumer.h>
> +
> +#include "linux/i2c/arcxcnn.h"
> +
> +#define ARCXCNN_CMD (0x00) /* Command Register */
> +#define ARCXCNN_CMD_STDBY (0x80) /* I2C Standby */
> +#define ARCXCNN_CMD_RESET (0x40) /* Reset */
> +#define ARCXCNN_CMD_BOOST (0x10) /* Boost */
> +#define ARCXCNN_CMD_OVP_MASK (0x0C) /* --- Over Voltage Threshold */
> +#define ARCXCNN_CMD_OVP_XXV (0x0C) /* <rsvrd> Over Voltage Threshold */
> +#define ARCXCNN_CMD_OVP_20V (0x08) /* 20v Over Voltage Threshold */
> +#define ARCXCNN_CMD_OVP_24V (0x04) /* 24v Over Voltage Threshold */
> +#define ARCXCNN_CMD_OVP_31V (0x00) /* 31.4v Over Voltage Threshold */
> +#define ARCXCNN_CMD_EXT_COMP (0x01) /* part (0) or full (1) external comp */
> +
> +#define ARCXCNN_CONFIG (0x01) /* Configuration */
> +#define ARCXCNN_STATUS1 (0x02) /* Status 1 */
> +#define ARCXCNN_STATUS2 (0x03) /* Status 2 */
> +#define ARCXCNN_FADECTRL (0x04) /* Fading Control */
> +#define ARCXCNN_ILED_CONFIG (0x05) /* ILED Configuration */
> +
> +#define ARCXCNN_LEDEN (0x06) /* LED Enable Register */
> +#define ARCXCNN_LEDEN_ISETEXT (0x80) /* Full-scale current set externally */
> +#define ARCXCNN_LEDEN_MASK (0x3F) /* LED string enables */
> +#define ARCXCNN_LEDEN_LED1 (0x01)
> +#define ARCXCNN_LEDEN_LED2 (0x02)
> +#define ARCXCNN_LEDEN_LED3 (0x04)
> +#define ARCXCNN_LEDEN_LED4 (0x08)
> +#define ARCXCNN_LEDEN_LED5 (0x10)
> +#define ARCXCNN_LEDEN_LED6 (0x20)
> +
> +#define ARCXCNN_WLED_ISET_LSB (0x07) /* LED ISET LSB (in upper nibble) */
> +#define ARCXCNN_WLED_ISET_MSB (0x08) /* LED ISET MSB (8 bits) */
> +
> +#define ARCXCNN_DIMFREQ (0x09)
> +#define ARCXCNN_COMP_CONFIG (0x0A)
> +#define ARCXCNN_FILT_CONFIG (0x0B)
> +#define ARCXCNN_IMAXTUNE (0x0C)
> +
> +#define DEFAULT_BL_NAME "arctic_bl"
> +#define MAX_BRIGHTNESS 4095
> +
> +static int s_no_reset_on_remove;
> +module_param_named(noreset, s_no_reset_on_remove, int, 0644);
> +MODULE_PARM_DESC(noreset, "No reset on module removal");
> +
> +static int s_ibright = 60;
> +module_param_named(ibright, s_ibright, int, 0644);
> +MODULE_PARM_DESC(ibright, "Initial brightness (when no plat data)");
> +
> +static int s_iledstr = 0x3F;
> +module_param_named(iledstr, s_iledstr, int, 0644);
> +MODULE_PARM_DESC(iledstr, "Initial LED String (when no plat data)");
> +
> +static int s_retries = 2; /* 1 = only one try */
> +module_param_named(retries, s_retries, int, 0644);
> +MODULE_PARM_DESC(retries, "I2C retries attempted");
> +
> +enum arcxcnn_brightness_ctrl_mode {
> + PWM_BASED = 1,
> + REGISTER_BASED,
> +};
> +
> +struct arcxcnn;
> +
> +struct arcxcnn {
> + char chipname[64];
> + enum arcxcnn_chip_id chip_id;
> + enum arcxcnn_brightness_ctrl_mode mode;
> + struct i2c_client *client;
> + struct backlight_device *bl;
> + struct device *dev;
> + struct arcxcnn_platform_data *pdata;
> + struct pwm_device *pwm;
> + struct regulator *supply; /* regulator for VDD input */
> +};
> +
> +static int arcxcnn_write_byte(struct arcxcnn *lp, u8 reg, u8 data)
> +{
> + s32 ret = -1;
> + int att;
> +
> + for (att = 0; att < s_retries; att++) {
> + ret = i2c_smbus_write_byte_data(lp->client, reg, data);
> + if (ret >= 0)
> + return 0;
> + }
> + return ret;
> +}
> +
> +static u8 arcxcnn_read_byte(struct arcxcnn *lp, u8 reg)
> +{
> + int val;
> + int att;
> +
> + for (att = 0; att < s_retries; att++) {
> + val = i2c_smbus_read_byte_data(lp->client, reg);
> + if (val >= 0)
> + return (u8)val;
> + }
> + return 0;
> +}
> +
> +static int arcxcnn_update_bit(struct arcxcnn *lp, u8 reg, u8 mask, u8 data)
> +{
> + int ret, att;
> + u8 tmp;
> +
> + for (att = 0, ret = -1; att < s_retries; att++) {
> + ret = i2c_smbus_read_byte_data(lp->client, reg);
> + if (ret >= 0)
> + break;
> + }
> + if (ret < 0) {
> + dev_err(lp->dev, "failed to read 0x%.2x\n", reg);
> + return ret;
> + }
> +
> + tmp = (u8)ret;
> + tmp &= ~mask;
> + tmp |= data & mask;
> +
> + return arcxcnn_write_byte(lp, reg, tmp);
> +}
> +
> +static int arcxcnn_set_brightness(struct arcxcnn *lp, u32 brightness)
> +{
> + int ret;
> + u8 val;
> +
> + val = (brightness & 0xF) << 4;
> + ret = arcxcnn_write_byte(lp, ARCXCNN_WLED_ISET_LSB, val);
> + if (ret < 0)
> + return ret;
> + val = (brightness >> 4);
> + ret = arcxcnn_write_byte(lp, ARCXCNN_WLED_ISET_MSB, val);
> + return ret;
> +}
> +
> +static int arcxcnn_bl_update_status(struct backlight_device *bl)
> +{
> + struct arcxcnn *lp = bl_get_data(bl);
> + u32 brightness = bl->props.brightness;
> +
> + if (bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
> + brightness = 0;
> +
> + /* set brightness */
> + if (lp->mode = PWM_BASED)
> + ; /* via pwm */
> + else if (lp->mode = REGISTER_BASED)
> + arcxcnn_set_brightness(lp, brightness);
> +
> + /* set power-on/off/save modes */
> + if (bl->props.power = 0)
> + /* take out of standby */
> + arcxcnn_update_bit(lp, ARCXCNN_CMD, ARCXCNN_CMD_STDBY, 0);
> + else
> + /* 1-3 = power save, 4 = off
> + * place in low-power standby mode
> + */
> + arcxcnn_update_bit(lp, ARCXCNN_CMD,
> + ARCXCNN_CMD_STDBY, ARCXCNN_CMD_STDBY);
> + return 0;
> +}
> +
> +static const struct backlight_ops arcxcnn_bl_ops = {
> + .options = BL_CORE_SUSPENDRESUME,
> + .update_status = arcxcnn_bl_update_status,
> +};
> +
> +static int arcxcnn_backlight_register(struct arcxcnn *lp)
> +{
> + struct backlight_device *bl;
> + struct backlight_properties props;
> + struct arcxcnn_platform_data *pdata = lp->pdata;
> + const char *name = pdata->name ? : DEFAULT_BL_NAME;
> +
> + memset(&props, 0, sizeof(props));
> + props.type = BACKLIGHT_PLATFORM;
> + props.max_brightness = MAX_BRIGHTNESS;
> +
> + if (pdata->initial_brightness > props.max_brightness)
> + pdata->initial_brightness = props.max_brightness;
> +
> + props.brightness = pdata->initial_brightness;
> +
> + bl = devm_backlight_device_register(lp->dev, name, lp->dev, lp,
> + &arcxcnn_bl_ops, &props);
> + if (IS_ERR(bl))
> + return PTR_ERR(bl);
> +
> + lp->bl = bl;
> +
> + return 0;
> +}
> +
> +static ssize_t arcxcnn_get_chip_id(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct arcxcnn *lp = dev_get_drvdata(dev);
> +
> + return scnprintf(buf, PAGE_SIZE, "%s\n", lp->chipname);
> +}
> +
> +static ssize_t arcxcnn_get_led_str(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct arcxcnn *lp = dev_get_drvdata(dev);
> +
> + return scnprintf(buf, PAGE_SIZE, "%02X\n", lp->pdata->led_str);
> +}
> +
> +static ssize_t arcxcnn_set_led_str(struct device *dev,
> + struct device_attribute *attr, const char *buf, size_t len)
> +{
> + struct arcxcnn *lp = dev_get_drvdata(dev);
> + unsigned long ledstr;
> +
> + if (kstrtoul(buf, 0, &ledstr))
> + return 0;
> +
> + if (ledstr != lp->pdata->led_str) {
> + /* don't allow 0 for ledstr, use power to turn all off */
> + if (ledstr = 0)
> + return 0;
> + lp->pdata->led_str = ledstr & 0x3F;
> + arcxcnn_update_bit(lp, ARCXCNN_LEDEN,
> + ARCXCNN_LEDEN_MASK, lp->pdata->led_str);
> + }
> + return len;
> +}
> +
> +static ssize_t arcxcnn_get_bl_ctl_mode(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct arcxcnn *lp = dev_get_drvdata(dev);
> + char *strmode = NULL;
> +
> + if (lp->mode = PWM_BASED)
> + strmode = "pwm based";
> + else if (lp->mode = REGISTER_BASED)
> + strmode = "register based";
> +
> + return scnprintf(buf, PAGE_SIZE, "%s\n", strmode);
> +}
> +
> +static DEVICE_ATTR(chip_id, 0444, arcxcnn_get_chip_id, NULL);
> +static DEVICE_ATTR(led_str, 0664, arcxcnn_get_led_str, arcxcnn_set_led_str);
> +static DEVICE_ATTR(bl_ctl_mode, 0444, arcxcnn_get_bl_ctl_mode, NULL);
> +
> +static struct attribute *arcxcnn_attributes[] = {
> + &dev_attr_chip_id.attr,
> + &dev_attr_led_str.attr,
> + &dev_attr_bl_ctl_mode.attr,
> + NULL,
> +};
> +
> +static const struct attribute_group arcxcnn_attr_group = {
> + .attrs = arcxcnn_attributes,
> +};
> +
> +#ifdef CONFIG_OF
> +static int arcxcnn_parse_dt(struct arcxcnn *lp)
> +{
> + struct device *dev = lp->dev;
> + struct device_node *node = dev->of_node;
> + u32 prog_val, num_entry, sources[6];
> + int ret;
> +
> + if (!node) {
> + dev_err(dev, "no platform data.\n");
> + return -EINVAL;
> + }
> + lp->pdata->led_config_0_set = false;
> + lp->pdata->led_config_1_set = false;
> + lp->pdata->dim_freq_set = false;
> + lp->pdata->comp_config_set = false;
> + lp->pdata->filter_config_set = false;
> + lp->pdata->trim_config_set = false;
> +
> + ret = of_property_read_string(node, "label", &lp->pdata->name);
> + if (ret < 0)
> + lp->pdata->name = NULL;
> +
> + ret = of_property_read_u32(node, "default-brightness", &prog_val);
> + if (ret < 0)
> + prog_val = s_ibright;
> + lp->pdata->initial_brightness = prog_val;
> + if (lp->pdata->initial_brightness > MAX_BRIGHTNESS)
> + lp->pdata->initial_brightness = MAX_BRIGHTNESS;
> +
> + ret = of_property_read_u32(node, "arcticsand,led-config-0", &prog_val);
> + if (ret = 0) {
> + lp->pdata->led_config_0 = (u8)prog_val;
> + lp->pdata->led_config_0_set = true;
> + }
> + ret = of_property_read_u32(node, "arcticsand,led-config-1", &prog_val);
> + if (ret = 0) {
> + lp->pdata->led_config_1 = (u8)prog_val;
> + lp->pdata->led_config_1_set = true;
> + }
> + ret = of_property_read_u32(node, "arcticsand,dim-freq", &prog_val);
> + if (ret = 0) {
> + lp->pdata->dim_freq = (u8)prog_val;
> + lp->pdata->dim_freq_set = true;
> + }
> + ret = of_property_read_u32(node, "arcticsand,comp-config", &prog_val);
> + if (ret = 0) {
> + lp->pdata->comp_config = (u8)prog_val;
> + lp->pdata->comp_config_set = true;
> + }
> + ret = of_property_read_u32(node, "arcticsand,filter-config", &prog_val);
> + if (ret = 0) {
> + lp->pdata->filter_config = (u8)prog_val;
> + lp->pdata->filter_config_set = true;
> + }
> + ret = of_property_read_u32(node, "arcticsand,trim-config", &prog_val);
> + if (ret = 0) {
> + lp->pdata->trim_config = (u8)prog_val;
> + lp->pdata->trim_config_set = true;
> + }
> + ret = of_property_count_u32_elems(node, "led-sources");
> + if (ret < 0)
> + lp->pdata->led_str = 0x3F;
> + else {
> + num_entry = ret;
> + if (num_entry > 6)
> + num_entry = 6;
> +
> + ret = of_property_read_u32_array(node, "led-sources", sources,
> + num_entry);
> + if (ret < 0) {
> + dev_err(dev, "led-sources node is invalid.\n");
> + return -EINVAL;
> + }
> +
> + lp->pdata->led_str = 0;
> + while (num_entry > 0)
> + lp->pdata->led_str |= (1 << sources[--num_entry]);
> + }
> + return 0;
> +}
> +#else
> +static int arcxcnn_parse_dt(struct arcxcnn *lp)
> +{
> + return -EINVAL;
> +}
> +#endif
> +
> +static int arcxcnn_probe(struct i2c_client *cl, const struct i2c_device_id *id)
> +{
> + struct arcxcnn *lp;
> + int ret;
> + u8 regval;
> + u16 chipid;
> +
> + if (!i2c_check_functionality(cl->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
> + return -EIO;
> +
> + lp = devm_kzalloc(&cl->dev, sizeof(*lp), GFP_KERNEL);
> + if (!lp)
> + return -ENOMEM;
> +
> + lp->client = cl;
> + lp->dev = &cl->dev;
> + lp->chip_id = id->driver_data;
> + lp->pdata = dev_get_platdata(&cl->dev);
> +
> + if (!lp->pdata) {
> + lp->pdata = devm_kzalloc(lp->dev,
> + sizeof(*lp->pdata), GFP_KERNEL);
> + if (!lp->pdata)
> + return -ENOMEM;
> +
> + /* no platform data, parse the device-tree for info. if there
> + * is no device tree entry, we are being told we exist because
> + * user-land said so, so make up the info we need
> + */
> + ret = arcxcnn_parse_dt(lp);
> + if (ret < 0) {
> + /* no device tree, use defaults based on module params
> + */
> + lp->pdata->led_config_0_set = false;
> + lp->pdata->led_config_1_set = false;
> + lp->pdata->dim_freq_set = false;
> + lp->pdata->comp_config_set = false;
> + lp->pdata->filter_config_set = false;
> + lp->pdata->trim_config_set = false;
> +
> + lp->pdata->name = NULL;
> + lp->pdata->initial_brightness = s_ibright;
> + lp->pdata->led_str = s_iledstr;
> + }
> + }
> +
> + if (lp->pdata->dim_freq_set)
> + lp->mode = PWM_BASED;
> + else
> + lp->mode = REGISTER_BASED;
> +
> + i2c_set_clientdata(cl, lp);
> +
> + /* read device ID */
> + regval = arcxcnn_read_byte(lp, 0x1E);
> + chipid = regval;
> + chipid <<= 8;
> + regval = arcxcnn_read_byte(lp, 0x1F);
> + chipid |= regval;
> +
> + /* make sure it belongs to this driver
> + * TODO - handle specific ids
> + */
> + if (chipid != 0x02A5) {
> + #if 1
> + dev_info(&cl->dev, "Chip Id is %04X\n", chipid);
> + #else
> + dev_err(&cl->dev, "%04X is not ARC2C\n", chipid);
> + return -ENODEV;
> + #endif
> + }
> + /* reset the device */
> + arcxcnn_write_byte(lp, ARCXCNN_CMD, ARCXCNN_CMD_RESET);
> +
> + /* set initial brightness */
> + arcxcnn_set_brightness(lp, lp->pdata->initial_brightness);
> +
> + /* if fadectrl set in DT, set the value directly, else leave default */
> + if (lp->pdata->led_config_0_set)
> + arcxcnn_write_byte(lp, ARCXCNN_FADECTRL,
> + lp->pdata->led_config_0);
> +
> + /* if iled config set in DT, set the value, else internal mode */
> + if (lp->pdata->led_config_1_set)
> + arcxcnn_write_byte(lp, ARCXCNN_ILED_CONFIG,
> + lp->pdata->led_config_1);
> + else
> + arcxcnn_write_byte(lp, ARCXCNN_ILED_CONFIG, 0x57);
> +
> + /* other misc DT settings */
> + if (lp->pdata->dim_freq_set)
> + arcxcnn_write_byte(lp, ARCXCNN_FADECTRL, lp->pdata->dim_freq);
> + if (lp->pdata->comp_config_set)
> + arcxcnn_write_byte(lp, ARCXCNN_COMP_CONFIG,
> + lp->pdata->comp_config);
> + if (lp->pdata->filter_config_set)
> + arcxcnn_write_byte(lp, ARCXCNN_FILT_CONFIG,
> + lp->pdata->filter_config);
> + if (lp->pdata->trim_config_set)
> + arcxcnn_write_byte(lp, ARCXCNN_IMAXTUNE,
> + lp->pdata->trim_config);
> +
> + /* set initial LED Strings */
> + arcxcnn_update_bit(lp, ARCXCNN_LEDEN,
> + ARCXCNN_LEDEN_MASK, lp->pdata->led_str);
> +
> + snprintf(lp->chipname, sizeof(lp->chipname),
> + "%s-%04X", id->name, chipid);
> +
> + ret = arcxcnn_backlight_register(lp);
> + if (ret) {
> + dev_err(lp->dev,
> + "failed to register backlight. err: %d\n", ret);
> + return ret;
> + }
> +
> + ret = sysfs_create_group(&lp->dev->kobj, &arcxcnn_attr_group);
> + if (ret) {
> + dev_err(lp->dev, "failed to register sysfs. err: %d\n", ret);
> + return ret;
> + }
> +
> + backlight_update_status(lp->bl);
> + return 0;
> +}
> +
> +static int arcxcnn_remove(struct i2c_client *cl)
> +{
> + struct arcxcnn *lp = i2c_get_clientdata(cl);
> +
> + if (!s_no_reset_on_remove) {
> + /* disable all strings */
> + arcxcnn_write_byte(lp, ARCXCNN_LEDEN, 0x00);
> + /* reset the device */
> + arcxcnn_write_byte(lp, ARCXCNN_CMD, ARCXCNN_CMD_RESET);
> + }
> + lp->bl->props.brightness = 0;
> + backlight_update_status(lp->bl);
> + if (lp->supply)
> + regulator_disable(lp->supply);
> + sysfs_remove_group(&lp->dev->kobj, &arcxcnn_attr_group);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id arcxcnn_dt_ids[] = {
> + { .compatible = "arc,arc2c0608" },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, arcxcnn_dt_ids);
> +
> +/* Note that the device/chip ID is not fixed in silicon so
> + * auto-probing of these devices on the bus is most likely
> + * not possible, use device tree to set i2c bus address
> + */
> +static const struct i2c_device_id arcxcnn_ids[] = {
> + {"arc2c0608", ARC2C0608},
> + { }
> +};
> +MODULE_DEVICE_TABLE(i2c, arcxcnn_ids);
> +
> +static struct i2c_driver arcxcnn_driver = {
> + .driver = {
> + .name = "arcxcnn_bl",
> + .of_match_table = of_match_ptr(arcxcnn_dt_ids),
> + },
> + .probe = arcxcnn_probe,
> + .remove = arcxcnn_remove,
> + .id_table = arcxcnn_ids,
> +};
> +
> +module_i2c_driver(arcxcnn_driver);
> +
> +MODULE_LICENSE("GPL v2");
> +MODULE_AUTHOR("Brian Dodge <bdodge09@outlook.com>");
> +MODULE_DESCRIPTION("ARCXCNN Backlight driver");
> diff --git a/include/linux/i2c/arcxcnn.h b/include/linux/i2c/arcxcnn.h
> new file mode 100644
> index 0000000..1c681dd
> --- /dev/null
> +++ b/include/linux/i2c/arcxcnn.h
> @@ -0,0 +1,67 @@
> +/*
> + * Backlight driver for ArcticSand ARC2C0608 Backlight Devices
> + *
> + * Copyright 2016 ArcticSand, Inc.
> + *
> + * Licensed under the GPL-2 or later.
> + */
> +
> +#ifndef _ARCXCNN_H
> +#define _ARCXCNN_H
> +
> +enum arcxcnn_chip_id {
> + ARC2C0608
> +};
> +
> +enum arcxcnn_brightness_source {
> + ARCXCNN_PWM_ONLY,
> + ARCXCNN_I2C_ONLY = 2,
> +};
> +
> +#define ARCXCNN_MAX_PROGENTRIES 48 /* max a/v pairs for custom */
> +
> +/**
> + * struct arcxcnn_platform_data
> + * @name : Backlight driver name. If it is not defined, default name is set.
> + * @initial_brightness : initial value of backlight brightness
> + * @led_str : initial LED string enables, upper bit is global on/off
> + * @led_config_0 : fading speed (period between intensity steps)
> + * @led_config_1 : misc settings, see datasheet
> + * @dim_freq : pwm dimming frequency if in pwm mode
> + * @comp_config : misc config, see datasheet
> + * @filter_config: RC/PWM filter config, see datasheet
> + * @trim_config : full scale current trim, see datasheet
> + * @led_config_0_set : the value in led_config_0 is valid
> + * @led_config_1_set : the value in led_config_1 is valid
> + * @dim_freq_set : the value in dim_freq is valid
> + * @comp_config_set : the value in comp_config is valid
> + * @filter_config_set : the value in filter_config is valid
> + * @trim_config_set : the value in trim_config is valid
> + *
> + * the _set flags are used to indicate that the value was explicitly set
> + * in the device tree or platform data. settings not set are left as default
> + * power-on default values of the chip except for led_str and led_config_1
> + * which are set by the driver (led_str is specified indirectly in the
> + * device tree via "led-sources")
> + */
> +struct arcxcnn_platform_data {
> + const char *name;
> + u16 initial_brightness;
> + u8 led_str;
> +
> + u8 led_config_0;
> + u8 led_config_1;
> + u8 dim_freq;
> + u8 comp_config;
> + u8 filter_config;
> + u8 trim_config;
> +
> + bool led_config_0_set;
> + bool led_config_1_set;
> + bool dim_freq_set;
> + bool comp_config_set;
> + bool filter_config_set;
> + bool trim_config_set;
> +};
> +
> +#endif
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* Re: [PATCH] net: ipv4: ip_send_unicast_reply should set oif only if it is L3 master
From: David Ahern @ 2016-11-09 15:52 UTC (permalink / raw)
To: Lorenzo Colitti; +Cc: netdev@vger.kernel.org, David Miller
In-Reply-To: <CAKD1Yr3v8qYn0eRwJttBr_1KpPBLrPbDLp0+WanQSBKDkD6+0Q@mail.gmail.com>
On 11/8/16 11:38 PM, Lorenzo Colitti wrote:
> On Wed, Nov 9, 2016 at 7:50 AM, David Ahern <dsa@cumulusnetworks.com> wrote:
>> @@ -1577,7 +1577,8 @@ void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb,
>
> Tested-by: Lorenzo Colitti <lorenzo@google.com>
>
> This fixes the IPv4 test, thanks. I notice that 4.8 didn't have
> e0d56fdd73, so if this patch can get into 4.9 then there will be no
> release that had the behaviour change. Not sure if that's possible any
> more though.
This patch is for net so 4.9.
>
> Can you also fix tcp_v6_send_response, which suffers from the same
> problem? Perhaps revert this hunk of e0d56fdd73 ("net: l3mdev: remove
> redundant calls"):
>
Let me add it to this patch and re-send.
^ permalink raw reply
* Re: [PATCH 2/3] ipmi/bt-bmc: maintain a request expiry list
From: Corey Minyard @ 2016-11-09 15:52 UTC (permalink / raw)
To: Cédric Le Goater,
openipmi-developer-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Joel Stanley
Cc: Rob Herring, Arnd Bergmann, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
Brendan Higgins
In-Reply-To: <6117c1fd-b969-9394-0be5-d46f64269cac-Bxea+6Xhats@public.gmane.org>
On 11/09/2016 08:30 AM, Cédric Le Goater wrote:
> On 11/07/2016 08:04 PM, Corey Minyard wrote:
>> On 11/02/2016 02:57 AM, Cédric Le Goater wrote:
>>> Regarding the response expiration handling, the IPMI spec says :
>>>
>>> The BMC must not return a given response once the corresponding
>>> Request-to-Response interval has passed. The BMC can ensure this
>>> by maintaining its own internal list of outstanding requests through
>>> the interface. The BMC could age and expire the entries in the list
>>> by expiring the entries at an interval that is somewhat shorter than
>>> the specified Request-to-Response interval....
>>>
>>> To handle such case, we maintain list of received requests using the
>>> seq number of the BT message to identify them. The list is updated
>>> each time a request is received and a response is sent. The expiration
>>> of the reponses is handled at each updates but also with a timer.
>> This looks correct, but it seems awfully complicated.
>>
>> Why can't you get the current time before the wait_event_interruptible()
>> and then compare the time before you do the write? That would seem to
>> accomplish the same thing without any lists or extra locks.
> Well, the expiry list needs a request identifier and it is currently using
> the Seq byte for this purpose. So the BT message needs to be read to grab
> that byte. The request is added to a list and that involves some locking.
>
> When the response is written, the first matching request is removed from
> the list and a garbage collector loop is also run. Then, as we might not
> get any responses to run that loop, we use a timer to empty the list from
> any expired requests.
>
> The read/write ops of the driver are protected with a mutex, the list and
> the timer add their share of locking. That could have been done with RCU
> surely but we don't really need performance in this driver.
>
> Caveats :
>
> bt_bmc_remove_request() should not be done in the writing loop though.
> It needs a fix.
>
> The request identifier is currently Seq but the spec say we should use
> Seq, NetFn, and Command or an internal Seq value as a request identifier.
> Google is also working on an OEM/Group extension (Brendan in CC: )
> which has a different message format. I need to look closer at what
> should be done in this case.
I'm still not sure why the list is necessary. You have a separate
thread of execution for each writer, why not just time it in that
thread?
What about the following, not even compile-tested, patch? I'm
sure my mailer will munge this up, I can send you a clean version
if you like.
From 1a73585a9c1c74ac1d59d82f22e05b30447619a6 Mon Sep 17 00:00:00 2001
From: Corey Minyard <cminyard-Igf4POYTYCDQT0dZR+AlfA@public.gmane.org>
Date: Wed, 9 Nov 2016 09:07:48 -0600
Subject: [PATCH] ipmi:bt-bmc: Fix a multi-user race, time out responses
The IPMI spec says to time out responses after a given amount of
time, so don't let a writer send something after an amount of time
has elapsed.
Also, fix a race condition in the same area where if you have two
writers at the same time, one can get a EIO return when it should
still be waiting its turn to send. A mutex_lock_interruptible_timeout()
would be handy here, but it doesn't exist.
Signed-off-by: Corey Minyard <cminyard-Igf4POYTYCDQT0dZR+AlfA@public.gmane.org>
---
drivers/char/ipmi/bt-bmc.c | 39 ++++++++++++++++++++++++---------------
1 file changed, 24 insertions(+), 15 deletions(-)
diff --git a/drivers/char/ipmi/bt-bmc.c b/drivers/char/ipmi/bt-bmc.c
index b49e613..5be94cf 100644
--- a/drivers/char/ipmi/bt-bmc.c
+++ b/drivers/char/ipmi/bt-bmc.c
@@ -57,6 +57,8 @@
#define BT_BMC_BUFFER_SIZE 256
+#define BT_BMC_RESPONSE_JIFFIES (5 * HZ)
+
struct bt_bmc {
struct device dev;
struct miscdevice miscdev;
@@ -190,14 +192,12 @@ static ssize_t bt_bmc_read(struct file *file, char
__user *buf,
WARN_ON(*ppos);
- if (wait_event_interruptible(bt_bmc->queue,
- bt_inb(bt_bmc, BT_CTRL) & BT_CTRL_H2B_ATN))
+ if (mutex_lock_interruptible(&bt_bmc->mutex))
return -ERESTARTSYS;
- mutex_lock(&bt_bmc->mutex);
-
- if (unlikely(!(bt_inb(bt_bmc, BT_CTRL) & BT_CTRL_H2B_ATN))) {
- ret = -EIO;
+ if (wait_event_interruptible(bt_bmc->queue,
+ bt_inb(bt_bmc, BT_CTRL) & BT_CTRL_H2B_ATN)) {
+ ret = -ERESTARTSYS;
goto out_unlock;
}
@@ -251,6 +251,7 @@ static ssize_t bt_bmc_write(struct file *file, const
char __user *buf,
u8 kbuffer[BT_BMC_BUFFER_SIZE];
ssize_t ret = 0;
ssize_t nwritten;
+ unsigned long start_jiffies = jiffies, wait_time;
/*
* send a minimum response size
@@ -263,23 +264,31 @@ static ssize_t bt_bmc_write(struct file *file,
const char __user *buf,
WARN_ON(*ppos);
+ if (mutex_lock_interruptible(&bt_bmc->mutex))
+ return -ERESTARTSYS;
+
+ wait_time = jiffies - start_jiffies;
+ if (wait_time >= BT_BMC_RESPONSE_TIME_JIFFIES) {
+ ret = -ETIMEDOUT;
+ goto out_unlock;
+ }
+ wait_time = BT_BMC_RESPONSE_TIME_JIFFIES - wait_time;
+
/*
* There's no interrupt for clearing bmc busy so we have to
* poll
*/
- if (wait_event_interruptible(bt_bmc->queue,
+ ret = wait_event_interruptible_timeout(bt_bmc->queue,
!(bt_inb(bt_bmc, BT_CTRL) &
- (BT_CTRL_H_BUSY | BT_CTRL_B2H_ATN))))
- return -ERESTARTSYS;
-
- mutex_lock(&bt_bmc->mutex);
-
- if (unlikely(bt_inb(bt_bmc, BT_CTRL) &
- (BT_CTRL_H_BUSY | BT_CTRL_B2H_ATN))) {
- ret = -EIO;
+ (BT_CTRL_H_BUSY | BT_CTRL_B2H_ATN)),
+ wait_time);
+ if (ret <= 0) {
+ if (ret == 0)
+ ret = -ETIMEDOUT;
goto out_unlock;
}
+ ret = 0;
clr_wr_ptr(bt_bmc);
while (count) {
--
2.7.4
>> Also, if you are going to have multiple writers on this interface, I don't
>> think the interface will work correctly. I think you need to claim the
>> mutex first. Otherwise you might get into a situation where two writers
>> will wake up at the same time, the first writes and releases the mutex,
>> then the second will find that the interface is busy and fail.
> yes. that is a current problem in the driver and it is not really an
> elegant way to handle concurrency. We are fine for the moment as we
> only have one single threaded process using the device.
>
>> If I am correct, the mutex will need to become interruptible and come
>> first, I think. (And the timing would have to start before the mutex,
>> of course.) This applies to both the read and write interface.
> OK. I will look into fixing this problem first.
>
>> Another thing is that this is request-to-release time. If a request takes
>> a long time to process (say, a write to a flash device) the timeout would
>> need to be decreased by the processing time.
> Hmm, how would that fit with the "BT Interface Capabilities" which
> defines :
>
> BMC Request-to-Response time, in seconds, 1 based. 30 seconds, maximum.
>
> This is a fixed value. And the spec only say :
>
> The BMC could age and expire the entries in the list by expiring
> the entries at an interval that is somewhat shorter than the
> specified Request-to-Response interval.
>
> May be I am misunderstanding.
Yeah, as usual, the IPMI spec is kind of vague about this. You have
to think about the problem from the host driver's point of view to
know what this means.
From a host driver point of view, it's going to send a request and wait
for a response with the same sequence number. It should time out the
request in "BMC Request-to-Response time" seconds. After that point,
it's free to re-use the sequence number. So what a BMC cannot do is
send that response after the timeout.
If the timeout is 5 seconds, and the BMC gets a flash write request that
takes 3 seconds then sits waiting for 2 seconds, it should not send the
response because the host driver may mistake it for a request it just
sent. So the timeout should be based on when the BMC got the request,
not when the response was queued for write, and that's the reason that
the BMC timer should be somewhat shorter than the host timer, as it
says.
I don't see an easy way to do this. Some possibilities I can think of are:
* Switch to using an ioctl to do the read/write operation. That's
kind of ugly. It's what the IPMI driver interface does, and it
has been somewhat of a pain.
* You could define a "header" that is put into the read message
and write message. You could add an ioctl to query the header
size; if the ioctl fails then the driver doesn't have a header.
Add a jiffie to the header of the read message that the
BMC userland must put into the header of the write message.
You could even have the ioctl enable the header, to preserve
backwards compatibility.
* Define some sort of structure that you read/write. This has all
sorts of issues.
I think my preference is the second, it allows for backwards
compatibility and lets the kernel do basically whatever it wants with
the data.
>> It's probably ok to not do that for the moment, but you may want to add
>> a note. Fixing that would require adding a timeout for each message.
> Thanks,
>
> C.
>
>> -corey
>>
>>
>>> Signed-off-by: Cédric Le Goater <clg-Bxea+6Xhats@public.gmane.org>
>>> ---
>>> drivers/char/ipmi/bt-bmc.c | 132 +++++++++++++++++++++++++++++++++++++++++++++
>>> 1 file changed, 132 insertions(+)
>>>
>>> diff --git a/drivers/char/ipmi/bt-bmc.c b/drivers/char/ipmi/bt-bmc.c
>>> index fc9e8891eae3..e751e4a754b7 100644
>>> --- a/drivers/char/ipmi/bt-bmc.c
>>> +++ b/drivers/char/ipmi/bt-bmc.c
>>> @@ -17,6 +17,7 @@
>>> #include <linux/platform_device.h>
>>> #include <linux/poll.h>
>>> #include <linux/sched.h>
>>> +#include <linux/slab.h>
>>> #include <linux/timer.h>
>>> /*
>>> @@ -57,6 +58,15 @@
>>> #define BT_BMC_BUFFER_SIZE 256
>>> +#define BT_BMC_RESPONSE_TIME 5 /* seconds */
>>> +
>>> +struct ipmi_request {
>>> + struct list_head list;
>>> +
>>> + u8 seq;
>>> + unsigned long expires;
>>> +};
>>> +
>>> struct bt_bmc {
>>> struct device dev;
>>> struct miscdevice miscdev;
>>> @@ -65,6 +75,11 @@ struct bt_bmc {
>>> wait_queue_head_t queue;
>>> struct timer_list poll_timer;
>>> struct mutex mutex;
>>> +
>>> + unsigned int response_time;
>>> + struct timer_list requests_timer;
>>> + spinlock_t requests_lock;
>>> + struct list_head requests;
>>> };
>>> static atomic_t open_count = ATOMIC_INIT(0);
>>> @@ -163,6 +178,94 @@ static int bt_bmc_open(struct inode *inode, struct file *file)
>>> }
>>> /*
>>> + * lock should be held
>>> + */
>>> +static void drop_expired_requests(struct bt_bmc *bt_bmc)
>>> +{
>>> + unsigned long flags = 0;
>>> + struct ipmi_request *req, *next;
>>> + unsigned long next_expires = 0;
>>> + int start_timer = 0;
>>> +
>>> + spin_lock_irqsave(&bt_bmc->requests_lock, flags);
>>> + list_for_each_entry_safe(req, next, &bt_bmc->requests, list) {
>>> + if (time_after_eq(jiffies, req->expires)) {
>>> + pr_warn("BT: request seq:%d has expired. dropping\n",
>>> + req->seq);
>>> + list_del(&req->list);
>>> + kfree(req);
>>> + continue;
>>> + }
>>> + if (!start_timer) {
>>> + start_timer = 1;
>>> + next_expires = req->expires;
>>> + } else {
>>> + next_expires = min(next_expires, req->expires);
>>> + }
>>> + }
>>> + spin_unlock_irqrestore(&bt_bmc->requests_lock, flags);
>>> +
>>> + /* and possibly restart */
>>> + if (start_timer)
>>> + mod_timer(&bt_bmc->requests_timer, next_expires);
>>> +}
>>> +
>>> +static void requests_timer(unsigned long data)
>>> +{
>>> + struct bt_bmc *bt_bmc = (void *)data;
>>> +
>>> + drop_expired_requests(bt_bmc);
>>> +}
>>> +
>>> +static int bt_bmc_add_request(struct bt_bmc *bt_bmc, u8 seq)
>>> +{
>>> + struct ipmi_request *req;
>>> +
>>> + req = kmalloc(sizeof(*req), GFP_KERNEL);
>>> + if (!req)
>>> + return -ENOMEM;
>>> +
>>> + req->seq = seq;
>>> + req->expires = jiffies +
>>> + msecs_to_jiffies(bt_bmc->response_time * 1000);
>>> +
>>> + spin_lock(&bt_bmc->requests_lock);
>>> + list_add(&req->list, &bt_bmc->requests);
>>> + spin_unlock(&bt_bmc->requests_lock);
>>> +
>>> + drop_expired_requests(bt_bmc);
>>> + return 0;
>>> +}
>>> +
>>> +static int bt_bmc_remove_request(struct bt_bmc *bt_bmc, u8 seq)
>>> +{
>>> + struct ipmi_request *req, *next;
>>> + int ret = -EBADRQC; /* Invalid request code */
>>> +
>>> + spin_lock(&bt_bmc->requests_lock);
>>> + list_for_each_entry_safe(req, next, &bt_bmc->requests, list) {
>>> + /*
>>> + * The sequence number should be unique, so remove the
>>> + * first matching request found. If there are others,
>>> + * they should expire
>>> + */
>>> + if (req->seq == seq) {
>>> + list_del(&req->list);
>>> + kfree(req);
>>> + ret = 0;
>>> + break;
>>> + }
>>> + }
>>> + spin_unlock(&bt_bmc->requests_lock);
>>> +
>>> + if (ret)
>>> + pr_warn("BT: request seq:%d is invalid\n", seq);
>>> +
>>> + drop_expired_requests(bt_bmc);
>>> + return ret;
>>> +}
>>> +
>>> +/*
>>> * The BT (Block Transfer) interface means that entire messages are
>>> * buffered by the host before a notification is sent to the BMC that
>>> * there is data to be read. The first byte is the length and the
>>> @@ -231,6 +334,13 @@ static ssize_t bt_bmc_read(struct file *file, char __user *buf,
>>> len_byte = 0;
>>> }
>>> + if (ret > 0) {
>>> + int ret2 = bt_bmc_add_request(bt_bmc, kbuffer[2]);
>>> +
>>> + if (ret2)
>>> + ret = ret2;
>>> + }
>>> +
>>> clr_b_busy(bt_bmc);
>>> out_unlock:
>>> @@ -283,12 +393,20 @@ static ssize_t bt_bmc_write(struct file *file, const char __user *buf,
>>> clr_wr_ptr(bt_bmc);
>>> while (count) {
>>> + int ret2;
>>> +
>>> nwritten = min_t(ssize_t, count, sizeof(kbuffer));
>>> if (copy_from_user(&kbuffer, buf, nwritten)) {
>>> ret = -EFAULT;
>>> break;
>>> }
>>> + ret2 = bt_bmc_remove_request(bt_bmc, kbuffer[2]);
>>> + if (ret2) {
>>> + ret = ret2;
>>> + break;
>>> + }
>>> +
>>> bt_writen(bt_bmc, kbuffer, nwritten);
>>> count -= nwritten;
>>> @@ -438,6 +556,8 @@ static int bt_bmc_probe(struct platform_device *pdev)
>>> mutex_init(&bt_bmc->mutex);
>>> init_waitqueue_head(&bt_bmc->queue);
>>> + INIT_LIST_HEAD(&bt_bmc->requests);
>>> + spin_lock_init(&bt_bmc->requests_lock);
>>> bt_bmc->miscdev.minor = MISC_DYNAMIC_MINOR,
>>> bt_bmc->miscdev.name = DEVICE_NAME,
>>> @@ -451,6 +571,8 @@ static int bt_bmc_probe(struct platform_device *pdev)
>>> bt_bmc_config_irq(bt_bmc, pdev);
>>> + bt_bmc->response_time = BT_BMC_RESPONSE_TIME;
>>> +
>>> if (bt_bmc->irq) {
>>> dev_info(dev, "Using IRQ %d\n", bt_bmc->irq);
>>> } else {
>>> @@ -468,6 +590,9 @@ static int bt_bmc_probe(struct platform_device *pdev)
>>> BT_CR0_ENABLE_IBT,
>>> bt_bmc->base + BT_CR0);
>>> + setup_timer(&bt_bmc->requests_timer, requests_timer,
>>> + (unsigned long)bt_bmc);
>>> +
>>> clr_b_busy(bt_bmc);
>>> return 0;
>>> @@ -476,10 +601,17 @@ static int bt_bmc_probe(struct platform_device *pdev)
>>> static int bt_bmc_remove(struct platform_device *pdev)
>>> {
>>> struct bt_bmc *bt_bmc = dev_get_drvdata(&pdev->dev);
>>> + struct ipmi_request *req, *next;
>>> misc_deregister(&bt_bmc->miscdev);
>>> if (!bt_bmc->irq)
>>> del_timer_sync(&bt_bmc->poll_timer);
>>> +
>>> + del_timer_sync(&bt_bmc->requests_timer);
>>> + list_for_each_entry_safe(req, next, &bt_bmc->requests, list) {
>>> + list_del(&req->list);
>>> + kfree(req);
>>> + }
>>> return 0;
>>> }
>>>
>>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH 2/3] ipmi/bt-bmc: maintain a request expiry list
From: Corey Minyard @ 2016-11-09 15:52 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <6117c1fd-b969-9394-0be5-d46f64269cac@kaod.org>
On 11/09/2016 08:30 AM, C?dric Le Goater wrote:
> On 11/07/2016 08:04 PM, Corey Minyard wrote:
>> On 11/02/2016 02:57 AM, C?dric Le Goater wrote:
>>> Regarding the response expiration handling, the IPMI spec says :
>>>
>>> The BMC must not return a given response once the corresponding
>>> Request-to-Response interval has passed. The BMC can ensure this
>>> by maintaining its own internal list of outstanding requests through
>>> the interface. The BMC could age and expire the entries in the list
>>> by expiring the entries at an interval that is somewhat shorter than
>>> the specified Request-to-Response interval....
>>>
>>> To handle such case, we maintain list of received requests using the
>>> seq number of the BT message to identify them. The list is updated
>>> each time a request is received and a response is sent. The expiration
>>> of the reponses is handled at each updates but also with a timer.
>> This looks correct, but it seems awfully complicated.
>>
>> Why can't you get the current time before the wait_event_interruptible()
>> and then compare the time before you do the write? That would seem to
>> accomplish the same thing without any lists or extra locks.
> Well, the expiry list needs a request identifier and it is currently using
> the Seq byte for this purpose. So the BT message needs to be read to grab
> that byte. The request is added to a list and that involves some locking.
>
> When the response is written, the first matching request is removed from
> the list and a garbage collector loop is also run. Then, as we might not
> get any responses to run that loop, we use a timer to empty the list from
> any expired requests.
>
> The read/write ops of the driver are protected with a mutex, the list and
> the timer add their share of locking. That could have been done with RCU
> surely but we don't really need performance in this driver.
>
> Caveats :
>
> bt_bmc_remove_request() should not be done in the writing loop though.
> It needs a fix.
>
> The request identifier is currently Seq but the spec say we should use
> Seq, NetFn, and Command or an internal Seq value as a request identifier.
> Google is also working on an OEM/Group extension (Brendan in CC: )
> which has a different message format. I need to look closer at what
> should be done in this case.
I'm still not sure why the list is necessary. You have a separate
thread of execution for each writer, why not just time it in that
thread?
What about the following, not even compile-tested, patch? I'm
sure my mailer will munge this up, I can send you a clean version
if you like.
From 1a73585a9c1c74ac1d59d82f22e05b30447619a6 Mon Sep 17 00:00:00 2001
From: Corey Minyard <cminyard@mvista.com>
Date: Wed, 9 Nov 2016 09:07:48 -0600
Subject: [PATCH] ipmi:bt-bmc: Fix a multi-user race, time out responses
The IPMI spec says to time out responses after a given amount of
time, so don't let a writer send something after an amount of time
has elapsed.
Also, fix a race condition in the same area where if you have two
writers at the same time, one can get a EIO return when it should
still be waiting its turn to send. A mutex_lock_interruptible_timeout()
would be handy here, but it doesn't exist.
Signed-off-by: Corey Minyard <cminyard@mvista.com>
---
drivers/char/ipmi/bt-bmc.c | 39 ++++++++++++++++++++++++---------------
1 file changed, 24 insertions(+), 15 deletions(-)
diff --git a/drivers/char/ipmi/bt-bmc.c b/drivers/char/ipmi/bt-bmc.c
index b49e613..5be94cf 100644
--- a/drivers/char/ipmi/bt-bmc.c
+++ b/drivers/char/ipmi/bt-bmc.c
@@ -57,6 +57,8 @@
#define BT_BMC_BUFFER_SIZE 256
+#define BT_BMC_RESPONSE_JIFFIES (5 * HZ)
+
struct bt_bmc {
struct device dev;
struct miscdevice miscdev;
@@ -190,14 +192,12 @@ static ssize_t bt_bmc_read(struct file *file, char
__user *buf,
WARN_ON(*ppos);
- if (wait_event_interruptible(bt_bmc->queue,
- bt_inb(bt_bmc, BT_CTRL) & BT_CTRL_H2B_ATN))
+ if (mutex_lock_interruptible(&bt_bmc->mutex))
return -ERESTARTSYS;
- mutex_lock(&bt_bmc->mutex);
-
- if (unlikely(!(bt_inb(bt_bmc, BT_CTRL) & BT_CTRL_H2B_ATN))) {
- ret = -EIO;
+ if (wait_event_interruptible(bt_bmc->queue,
+ bt_inb(bt_bmc, BT_CTRL) & BT_CTRL_H2B_ATN)) {
+ ret = -ERESTARTSYS;
goto out_unlock;
}
@@ -251,6 +251,7 @@ static ssize_t bt_bmc_write(struct file *file, const
char __user *buf,
u8 kbuffer[BT_BMC_BUFFER_SIZE];
ssize_t ret = 0;
ssize_t nwritten;
+ unsigned long start_jiffies = jiffies, wait_time;
/*
* send a minimum response size
@@ -263,23 +264,31 @@ static ssize_t bt_bmc_write(struct file *file,
const char __user *buf,
WARN_ON(*ppos);
+ if (mutex_lock_interruptible(&bt_bmc->mutex))
+ return -ERESTARTSYS;
+
+ wait_time = jiffies - start_jiffies;
+ if (wait_time >= BT_BMC_RESPONSE_TIME_JIFFIES) {
+ ret = -ETIMEDOUT;
+ goto out_unlock;
+ }
+ wait_time = BT_BMC_RESPONSE_TIME_JIFFIES - wait_time;
+
/*
* There's no interrupt for clearing bmc busy so we have to
* poll
*/
- if (wait_event_interruptible(bt_bmc->queue,
+ ret = wait_event_interruptible_timeout(bt_bmc->queue,
!(bt_inb(bt_bmc, BT_CTRL) &
- (BT_CTRL_H_BUSY | BT_CTRL_B2H_ATN))))
- return -ERESTARTSYS;
-
- mutex_lock(&bt_bmc->mutex);
-
- if (unlikely(bt_inb(bt_bmc, BT_CTRL) &
- (BT_CTRL_H_BUSY | BT_CTRL_B2H_ATN))) {
- ret = -EIO;
+ (BT_CTRL_H_BUSY | BT_CTRL_B2H_ATN)),
+ wait_time);
+ if (ret <= 0) {
+ if (ret == 0)
+ ret = -ETIMEDOUT;
goto out_unlock;
}
+ ret = 0;
clr_wr_ptr(bt_bmc);
while (count) {
--
2.7.4
>> Also, if you are going to have multiple writers on this interface, I don't
>> think the interface will work correctly. I think you need to claim the
>> mutex first. Otherwise you might get into a situation where two writers
>> will wake up at the same time, the first writes and releases the mutex,
>> then the second will find that the interface is busy and fail.
> yes. that is a current problem in the driver and it is not really an
> elegant way to handle concurrency. We are fine for the moment as we
> only have one single threaded process using the device.
>
>> If I am correct, the mutex will need to become interruptible and come
>> first, I think. (And the timing would have to start before the mutex,
>> of course.) This applies to both the read and write interface.
> OK. I will look into fixing this problem first.
>
>> Another thing is that this is request-to-release time. If a request takes
>> a long time to process (say, a write to a flash device) the timeout would
>> need to be decreased by the processing time.
> Hmm, how would that fit with the "BT Interface Capabilities" which
> defines :
>
> BMC Request-to-Response time, in seconds, 1 based. 30 seconds, maximum.
>
> This is a fixed value. And the spec only say :
>
> The BMC could age and expire the entries in the list by expiring
> the entries at an interval that is somewhat shorter than the
> specified Request-to-Response interval.
>
> May be I am misunderstanding.
Yeah, as usual, the IPMI spec is kind of vague about this. You have
to think about the problem from the host driver's point of view to
know what this means.
From a host driver point of view, it's going to send a request and wait
for a response with the same sequence number. It should time out the
request in "BMC Request-to-Response time" seconds. After that point,
it's free to re-use the sequence number. So what a BMC cannot do is
send that response after the timeout.
If the timeout is 5 seconds, and the BMC gets a flash write request that
takes 3 seconds then sits waiting for 2 seconds, it should not send the
response because the host driver may mistake it for a request it just
sent. So the timeout should be based on when the BMC got the request,
not when the response was queued for write, and that's the reason that
the BMC timer should be somewhat shorter than the host timer, as it
says.
I don't see an easy way to do this. Some possibilities I can think of are:
* Switch to using an ioctl to do the read/write operation. That's
kind of ugly. It's what the IPMI driver interface does, and it
has been somewhat of a pain.
* You could define a "header" that is put into the read message
and write message. You could add an ioctl to query the header
size; if the ioctl fails then the driver doesn't have a header.
Add a jiffie to the header of the read message that the
BMC userland must put into the header of the write message.
You could even have the ioctl enable the header, to preserve
backwards compatibility.
* Define some sort of structure that you read/write. This has all
sorts of issues.
I think my preference is the second, it allows for backwards
compatibility and lets the kernel do basically whatever it wants with
the data.
>> It's probably ok to not do that for the moment, but you may want to add
>> a note. Fixing that would require adding a timeout for each message.
> Thanks,
>
> C.
>
>> -corey
>>
>>
>>> Signed-off-by: C?dric Le Goater <clg@kaod.org>
>>> ---
>>> drivers/char/ipmi/bt-bmc.c | 132 +++++++++++++++++++++++++++++++++++++++++++++
>>> 1 file changed, 132 insertions(+)
>>>
>>> diff --git a/drivers/char/ipmi/bt-bmc.c b/drivers/char/ipmi/bt-bmc.c
>>> index fc9e8891eae3..e751e4a754b7 100644
>>> --- a/drivers/char/ipmi/bt-bmc.c
>>> +++ b/drivers/char/ipmi/bt-bmc.c
>>> @@ -17,6 +17,7 @@
>>> #include <linux/platform_device.h>
>>> #include <linux/poll.h>
>>> #include <linux/sched.h>
>>> +#include <linux/slab.h>
>>> #include <linux/timer.h>
>>> /*
>>> @@ -57,6 +58,15 @@
>>> #define BT_BMC_BUFFER_SIZE 256
>>> +#define BT_BMC_RESPONSE_TIME 5 /* seconds */
>>> +
>>> +struct ipmi_request {
>>> + struct list_head list;
>>> +
>>> + u8 seq;
>>> + unsigned long expires;
>>> +};
>>> +
>>> struct bt_bmc {
>>> struct device dev;
>>> struct miscdevice miscdev;
>>> @@ -65,6 +75,11 @@ struct bt_bmc {
>>> wait_queue_head_t queue;
>>> struct timer_list poll_timer;
>>> struct mutex mutex;
>>> +
>>> + unsigned int response_time;
>>> + struct timer_list requests_timer;
>>> + spinlock_t requests_lock;
>>> + struct list_head requests;
>>> };
>>> static atomic_t open_count = ATOMIC_INIT(0);
>>> @@ -163,6 +178,94 @@ static int bt_bmc_open(struct inode *inode, struct file *file)
>>> }
>>> /*
>>> + * lock should be held
>>> + */
>>> +static void drop_expired_requests(struct bt_bmc *bt_bmc)
>>> +{
>>> + unsigned long flags = 0;
>>> + struct ipmi_request *req, *next;
>>> + unsigned long next_expires = 0;
>>> + int start_timer = 0;
>>> +
>>> + spin_lock_irqsave(&bt_bmc->requests_lock, flags);
>>> + list_for_each_entry_safe(req, next, &bt_bmc->requests, list) {
>>> + if (time_after_eq(jiffies, req->expires)) {
>>> + pr_warn("BT: request seq:%d has expired. dropping\n",
>>> + req->seq);
>>> + list_del(&req->list);
>>> + kfree(req);
>>> + continue;
>>> + }
>>> + if (!start_timer) {
>>> + start_timer = 1;
>>> + next_expires = req->expires;
>>> + } else {
>>> + next_expires = min(next_expires, req->expires);
>>> + }
>>> + }
>>> + spin_unlock_irqrestore(&bt_bmc->requests_lock, flags);
>>> +
>>> + /* and possibly restart */
>>> + if (start_timer)
>>> + mod_timer(&bt_bmc->requests_timer, next_expires);
>>> +}
>>> +
>>> +static void requests_timer(unsigned long data)
>>> +{
>>> + struct bt_bmc *bt_bmc = (void *)data;
>>> +
>>> + drop_expired_requests(bt_bmc);
>>> +}
>>> +
>>> +static int bt_bmc_add_request(struct bt_bmc *bt_bmc, u8 seq)
>>> +{
>>> + struct ipmi_request *req;
>>> +
>>> + req = kmalloc(sizeof(*req), GFP_KERNEL);
>>> + if (!req)
>>> + return -ENOMEM;
>>> +
>>> + req->seq = seq;
>>> + req->expires = jiffies +
>>> + msecs_to_jiffies(bt_bmc->response_time * 1000);
>>> +
>>> + spin_lock(&bt_bmc->requests_lock);
>>> + list_add(&req->list, &bt_bmc->requests);
>>> + spin_unlock(&bt_bmc->requests_lock);
>>> +
>>> + drop_expired_requests(bt_bmc);
>>> + return 0;
>>> +}
>>> +
>>> +static int bt_bmc_remove_request(struct bt_bmc *bt_bmc, u8 seq)
>>> +{
>>> + struct ipmi_request *req, *next;
>>> + int ret = -EBADRQC; /* Invalid request code */
>>> +
>>> + spin_lock(&bt_bmc->requests_lock);
>>> + list_for_each_entry_safe(req, next, &bt_bmc->requests, list) {
>>> + /*
>>> + * The sequence number should be unique, so remove the
>>> + * first matching request found. If there are others,
>>> + * they should expire
>>> + */
>>> + if (req->seq == seq) {
>>> + list_del(&req->list);
>>> + kfree(req);
>>> + ret = 0;
>>> + break;
>>> + }
>>> + }
>>> + spin_unlock(&bt_bmc->requests_lock);
>>> +
>>> + if (ret)
>>> + pr_warn("BT: request seq:%d is invalid\n", seq);
>>> +
>>> + drop_expired_requests(bt_bmc);
>>> + return ret;
>>> +}
>>> +
>>> +/*
>>> * The BT (Block Transfer) interface means that entire messages are
>>> * buffered by the host before a notification is sent to the BMC that
>>> * there is data to be read. The first byte is the length and the
>>> @@ -231,6 +334,13 @@ static ssize_t bt_bmc_read(struct file *file, char __user *buf,
>>> len_byte = 0;
>>> }
>>> + if (ret > 0) {
>>> + int ret2 = bt_bmc_add_request(bt_bmc, kbuffer[2]);
>>> +
>>> + if (ret2)
>>> + ret = ret2;
>>> + }
>>> +
>>> clr_b_busy(bt_bmc);
>>> out_unlock:
>>> @@ -283,12 +393,20 @@ static ssize_t bt_bmc_write(struct file *file, const char __user *buf,
>>> clr_wr_ptr(bt_bmc);
>>> while (count) {
>>> + int ret2;
>>> +
>>> nwritten = min_t(ssize_t, count, sizeof(kbuffer));
>>> if (copy_from_user(&kbuffer, buf, nwritten)) {
>>> ret = -EFAULT;
>>> break;
>>> }
>>> + ret2 = bt_bmc_remove_request(bt_bmc, kbuffer[2]);
>>> + if (ret2) {
>>> + ret = ret2;
>>> + break;
>>> + }
>>> +
>>> bt_writen(bt_bmc, kbuffer, nwritten);
>>> count -= nwritten;
>>> @@ -438,6 +556,8 @@ static int bt_bmc_probe(struct platform_device *pdev)
>>> mutex_init(&bt_bmc->mutex);
>>> init_waitqueue_head(&bt_bmc->queue);
>>> + INIT_LIST_HEAD(&bt_bmc->requests);
>>> + spin_lock_init(&bt_bmc->requests_lock);
>>> bt_bmc->miscdev.minor = MISC_DYNAMIC_MINOR,
>>> bt_bmc->miscdev.name = DEVICE_NAME,
>>> @@ -451,6 +571,8 @@ static int bt_bmc_probe(struct platform_device *pdev)
>>> bt_bmc_config_irq(bt_bmc, pdev);
>>> + bt_bmc->response_time = BT_BMC_RESPONSE_TIME;
>>> +
>>> if (bt_bmc->irq) {
>>> dev_info(dev, "Using IRQ %d\n", bt_bmc->irq);
>>> } else {
>>> @@ -468,6 +590,9 @@ static int bt_bmc_probe(struct platform_device *pdev)
>>> BT_CR0_ENABLE_IBT,
>>> bt_bmc->base + BT_CR0);
>>> + setup_timer(&bt_bmc->requests_timer, requests_timer,
>>> + (unsigned long)bt_bmc);
>>> +
>>> clr_b_busy(bt_bmc);
>>> return 0;
>>> @@ -476,10 +601,17 @@ static int bt_bmc_probe(struct platform_device *pdev)
>>> static int bt_bmc_remove(struct platform_device *pdev)
>>> {
>>> struct bt_bmc *bt_bmc = dev_get_drvdata(&pdev->dev);
>>> + struct ipmi_request *req, *next;
>>> misc_deregister(&bt_bmc->miscdev);
>>> if (!bt_bmc->irq)
>>> del_timer_sync(&bt_bmc->poll_timer);
>>> +
>>> + del_timer_sync(&bt_bmc->requests_timer);
>>> + list_for_each_entry_safe(req, next, &bt_bmc->requests, list) {
>>> + list_del(&req->list);
>>> + kfree(req);
>>> + }
>>> return 0;
>>> }
>>>
>>
^ permalink raw reply related
* Re: [linux-3.10 test] 102032: regressions - FAIL
From: Ian Jackson @ 2016-11-09 15:51 UTC (permalink / raw)
To: xen-devel
In-Reply-To: <osstest-102032-mainreport@xen.org>
osstest service owner writes ("[linux-3.10 test] 102032: regressions - FAIL"):
> flight 102032 linux-3.10 real [real]
> http://logs.test-lab.xenproject.org/osstest/logs/102032/
>
> Regressions :-(
>
> Tests which did not succeed and are blocking,
> including tests which could not be run:
> test-amd64-amd64-xl 6 xen-boot fail REGR. vs. 100648
Etc.
The system seems to boot normally but fails to find the disk
controller. I think this must mean that the disk controller is simply
not in Linux 3.10, which would be quite plausible. 3.4 is failing
too.
I will configure the noblings to reject 3.10 and earlier.
Ian.
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
https://lists.xen.org/xen-devel
^ permalink raw reply
* Re: [PATCH] perf/x86: Fix overlap counter scheduling bug
From: Peter Zijlstra @ 2016-11-09 15:51 UTC (permalink / raw)
To: Robert Richter
Cc: Liang, Kan, Andi Kleen, Jiri Olsa, Vince Weaver, lkml,
Ingo Molnar
In-Reply-To: <20161109142515.GY25086@rric.localdomain>
On Wed, Nov 09, 2016 at 03:25:15PM +0100, Robert Richter wrote:
> On 08.11.16 19:27:39, Peter Zijlstra wrote:
> > The comment with EVENT_CONSTRAINT_OVERLAP states: "This is the case if
> > the counter mask of such an event is not a subset of any other counter
> > mask of a constraint with an equal or higher weight".
> >
> > Esp. that latter part is of interest here I think, our overlapping mask
> > is 0x0e, that has 3 bits set and is the highest weight mask in on the
> > PMU, therefore it will be placed last. Can we still create a scenario
> > where we would need to rewind that?
> >
> > The scenario for AMD Fam15h is we're having masks like:
> >
> > 0x3F -- 111111
> > 0x38 -- 111000
> > 0x07 -- 000111
> >
> > 0x09 -- 001001
> >
> > And we mark 0x09 as overlapping, because it is not a direct subset of
> > 0x38 or 0x07 and has less weight than either of those. This means we'll
> > first try and place the 0x09 event, then try and place 0x38/0x07 events.
> > Now imagine we have:
> >
> > 3 * 0x07 + 0x09
> >
> > and the initial pick for the 0x09 event is counter 0, then we'll fail to
> > place all 0x07 events. So we'll pop back, try counter 4 for the 0x09
> > event, and then re-try all 0x07 events, which will now work.
> >
> >
> >
> > But given, that in the uncore case, the overlapping event is the
> > heaviest mask, I don't think this can happen. Or did I overlook
> > something.... takes a bit to page all this back in.
>
> Right, IMO 0xE mask may not be marked as overlapping. It is placed
> last and if there is no space left we are lost. There is no other
> combination or state we could try then. So the fix is to remove the
> overlapping bit for that counter, the state is then never saved.
>
> This assumes there are no other counters than 0x3 and 0xc that overlap
> with 0xe. It becomes a bit tricky if there is another counter with the
> same or higher weight that overlaps with 0xe, e.g. 0x7.
As per a prior mail, the masks on the PMU in question are:
0x01 - 0001
0x03 - 0011
0x0e - 1110
0x0c - 1100
But since all the masks that have overlap (0xe -> {0xc,0x3}) and (0x3 ->
0x1) are of heavier weight, it should all work out I think.
So yes, something like the below (removing the OVERLAP bit) looks like
its sufficient.
---
arch/x86/events/intel/uncore_snbep.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/x86/events/intel/uncore_snbep.c b/arch/x86/events/intel/uncore_snbep.c
index 272427700d48..e6832be714bc 100644
--- a/arch/x86/events/intel/uncore_snbep.c
+++ b/arch/x86/events/intel/uncore_snbep.c
@@ -669,7 +669,7 @@ static struct event_constraint snbep_uncore_cbox_constraints[] = {
UNCORE_EVENT_CONSTRAINT(0x1c, 0xc),
UNCORE_EVENT_CONSTRAINT(0x1d, 0xc),
UNCORE_EVENT_CONSTRAINT(0x1e, 0xc),
- EVENT_CONSTRAINT_OVERLAP(0x1f, 0xe, 0xff),
+ UNCORE_EVENT_CONSTRAINT(0x1f, 0xe),
UNCORE_EVENT_CONSTRAINT(0x21, 0x3),
UNCORE_EVENT_CONSTRAINT(0x23, 0x3),
UNCORE_EVENT_CONSTRAINT(0x31, 0x3),
^ permalink raw reply related
* Re: [PATCH] megaraid_sas: fix macro MEGASAS_IS_LOGICAL to avoid regression caused by commit 1e793f6fc0db920400574211c48f9157a37e3945
From: Tomas Henzl @ 2016-11-09 15:51 UTC (permalink / raw)
To: Sumit Saxena, linux-scsi
Cc: martin.petersen, jejb, kashyap.desai, shivasharan.srikanteshwara,
axboe, stable
In-Reply-To: <1478689182-10854-1-git-send-email-sumit.saxena@broadcom.com>
On 9.11.2016 11:59, Sumit Saxena wrote:
> This patch will fix regression caused by below commit-
> 1e793f6 scsi: megaraid_sas: Fix data integrity failure for JBOD (passthrough) devices
>
> The problem was MEGASAS_IS_LOGICAL macro does not have braces and because of above commit
> using this macro was exposing lot of non-existing SCSI devices(all SCSI commands to channels-1,2,3 was
> returned as SUCCESS-DID_OK by driver).
>
> Fixes: 1e793f6fc0db920400574211c48f9157a37e3945
> Reported-by: Jens Axboe <axboe@kernel.dk>
> CC: stable@vger.kernel.org
> Signed-off-by: Kashyap Desai <kashyap.desai@broadcom.com>
> Signed-off-by: Sumit Saxena <sumit.saxena@broadcom.com>
> Tested-by: Sumit Saxena <sumit.saxena@broadcom.com>
Reviewed-by: Tomas Henzl <thenzl@redhat.com>
Tomas
^ permalink raw reply
* Re: Aw: hppa qemu and string functions
From: Jeff Law @ 2016-11-09 15:51 UTC (permalink / raw)
To: Helge Deller, Richard Henderson; +Cc: linux-parisc, GNU C Library
In-Reply-To: <trinity-8a5a9da3-1e08-4571-bbfb-b230bd20f15b-1478703076818@3capp-gmx-bs52>
On 11/09/2016 07:51 AM, Helge Deller wrote:
> Hi Richard,
>
>> Off and on, I've been working on a user-only target of hppa to qemu. It's now
>> about 95% working. If anyone would like to try it out, it's available at
>> git://github.com/rth7680/qemu.git tgt-hppa
>
> COOL!
> I'm happy to test, but can you shortly describe the required steps how I can build & test it?
>
> With "user-only target of hppa" I assume this means that I can run hppa binaries
> on e.g. x86-64, similiar to what is described here: https://wiki.debian.org/QemuUserEmulation ?
>
>> While implementing the unit-type instructions, I wondered why no one (outside
>> hp?) had written a version of the string routines utilizing the UXOR insn, with
>> the SomeByteZero and NoByteZero conditions.
>
> Interesting.
> I assume nobody did, because there are a few hppa/linux/glibc users anyway ? :-)
Probably a safe assumption. I'm pretty sure the hpux string routines
used uxor. There was also at least one hpux routine in libc which used
the branch-in-delay-slot-of-branch trick, but I can't recall why it was
useful.
jeff
^ permalink raw reply
* Re: [PATCH 1/2] backlight: arcxcnn: add support for ArticSand devices
From: Lee Jones @ 2016-11-09 15:53 UTC (permalink / raw)
To: Olimpiu Dejeu; +Cc: robh, linux-kernel, linux-fbdev, devicetree, jg1.han
In-Reply-To: <1477513778-31297-1-git-send-email-olimpiu@arcticsand.com>
Jingoo?
On Wed, 26 Oct 2016, Olimpiu Dejeu wrote:
> Resubmition of arcxcnn backliught driver adding devicetree entries
> for all registers
>
> Signed-off-by: Olimpiu Dejeu <olimpiu@arcticsand.com>
>
> ---
> drivers/video/backlight/Kconfig | 7 +
> drivers/video/backlight/Makefile | 1 +
> drivers/video/backlight/arcxcnn_bl.c | 541 +++++++++++++++++++++++++++++++++++
> include/linux/i2c/arcxcnn.h | 67 +++++
> 4 files changed, 616 insertions(+)
> create mode 100644 drivers/video/backlight/arcxcnn_bl.c
> create mode 100644 include/linux/i2c/arcxcnn.h
>
> diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
> index 5ffa4b4..4e1d2ad 100644
> --- a/drivers/video/backlight/Kconfig
> +++ b/drivers/video/backlight/Kconfig
> @@ -460,6 +460,13 @@ config BACKLIGHT_BD6107
> help
> If you have a Rohm BD6107 say Y to enable the backlight driver.
>
> +config BACKLIGHT_ARCXCNN
> + tristate "Backlight driver for the Arctic Sands ARCxCnnnn family"
> + depends on I2C
> + help
> + If you have an ARCxCnnnn family backlight say Y to enable
> + the backlight driver.
> +
> endif # BACKLIGHT_CLASS_DEVICE
>
> endif # BACKLIGHT_LCD_SUPPORT
> diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
> index 16ec534..8905129 100644
> --- a/drivers/video/backlight/Makefile
> +++ b/drivers/video/backlight/Makefile
> @@ -55,3 +55,4 @@ obj-$(CONFIG_BACKLIGHT_SKY81452) += sky81452-backlight.o
> obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o
> obj-$(CONFIG_BACKLIGHT_TPS65217) += tps65217_bl.o
> obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o
> +obj-$(CONFIG_BACKLIGHT_ARCXCNN) += arcxcnn_bl.o
> diff --git a/drivers/video/backlight/arcxcnn_bl.c b/drivers/video/backlight/arcxcnn_bl.c
> new file mode 100644
> index 0000000..1dad680
> --- /dev/null
> +++ b/drivers/video/backlight/arcxcnn_bl.c
> @@ -0,0 +1,541 @@
> +/*
> + * Backlight driver for ArcticSand ARC_X_C_0N_0N Devices
> + *
> + * Copyright 2016 ArcticSand, Inc.
> + *
> + * Licensed under the GPL-2 or later.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/i2c.h>
> +#include <linux/backlight.h>
> +#include <linux/err.h>
> +#include <linux/of.h>
> +#include <linux/pwm.h>
> +#include <linux/regulator/consumer.h>
> +
> +#include "linux/i2c/arcxcnn.h"
> +
> +#define ARCXCNN_CMD (0x00) /* Command Register */
> +#define ARCXCNN_CMD_STDBY (0x80) /* I2C Standby */
> +#define ARCXCNN_CMD_RESET (0x40) /* Reset */
> +#define ARCXCNN_CMD_BOOST (0x10) /* Boost */
> +#define ARCXCNN_CMD_OVP_MASK (0x0C) /* --- Over Voltage Threshold */
> +#define ARCXCNN_CMD_OVP_XXV (0x0C) /* <rsvrd> Over Voltage Threshold */
> +#define ARCXCNN_CMD_OVP_20V (0x08) /* 20v Over Voltage Threshold */
> +#define ARCXCNN_CMD_OVP_24V (0x04) /* 24v Over Voltage Threshold */
> +#define ARCXCNN_CMD_OVP_31V (0x00) /* 31.4v Over Voltage Threshold */
> +#define ARCXCNN_CMD_EXT_COMP (0x01) /* part (0) or full (1) external comp */
> +
> +#define ARCXCNN_CONFIG (0x01) /* Configuration */
> +#define ARCXCNN_STATUS1 (0x02) /* Status 1 */
> +#define ARCXCNN_STATUS2 (0x03) /* Status 2 */
> +#define ARCXCNN_FADECTRL (0x04) /* Fading Control */
> +#define ARCXCNN_ILED_CONFIG (0x05) /* ILED Configuration */
> +
> +#define ARCXCNN_LEDEN (0x06) /* LED Enable Register */
> +#define ARCXCNN_LEDEN_ISETEXT (0x80) /* Full-scale current set externally */
> +#define ARCXCNN_LEDEN_MASK (0x3F) /* LED string enables */
> +#define ARCXCNN_LEDEN_LED1 (0x01)
> +#define ARCXCNN_LEDEN_LED2 (0x02)
> +#define ARCXCNN_LEDEN_LED3 (0x04)
> +#define ARCXCNN_LEDEN_LED4 (0x08)
> +#define ARCXCNN_LEDEN_LED5 (0x10)
> +#define ARCXCNN_LEDEN_LED6 (0x20)
> +
> +#define ARCXCNN_WLED_ISET_LSB (0x07) /* LED ISET LSB (in upper nibble) */
> +#define ARCXCNN_WLED_ISET_MSB (0x08) /* LED ISET MSB (8 bits) */
> +
> +#define ARCXCNN_DIMFREQ (0x09)
> +#define ARCXCNN_COMP_CONFIG (0x0A)
> +#define ARCXCNN_FILT_CONFIG (0x0B)
> +#define ARCXCNN_IMAXTUNE (0x0C)
> +
> +#define DEFAULT_BL_NAME "arctic_bl"
> +#define MAX_BRIGHTNESS 4095
> +
> +static int s_no_reset_on_remove;
> +module_param_named(noreset, s_no_reset_on_remove, int, 0644);
> +MODULE_PARM_DESC(noreset, "No reset on module removal");
> +
> +static int s_ibright = 60;
> +module_param_named(ibright, s_ibright, int, 0644);
> +MODULE_PARM_DESC(ibright, "Initial brightness (when no plat data)");
> +
> +static int s_iledstr = 0x3F;
> +module_param_named(iledstr, s_iledstr, int, 0644);
> +MODULE_PARM_DESC(iledstr, "Initial LED String (when no plat data)");
> +
> +static int s_retries = 2; /* 1 == only one try */
> +module_param_named(retries, s_retries, int, 0644);
> +MODULE_PARM_DESC(retries, "I2C retries attempted");
> +
> +enum arcxcnn_brightness_ctrl_mode {
> + PWM_BASED = 1,
> + REGISTER_BASED,
> +};
> +
> +struct arcxcnn;
> +
> +struct arcxcnn {
> + char chipname[64];
> + enum arcxcnn_chip_id chip_id;
> + enum arcxcnn_brightness_ctrl_mode mode;
> + struct i2c_client *client;
> + struct backlight_device *bl;
> + struct device *dev;
> + struct arcxcnn_platform_data *pdata;
> + struct pwm_device *pwm;
> + struct regulator *supply; /* regulator for VDD input */
> +};
> +
> +static int arcxcnn_write_byte(struct arcxcnn *lp, u8 reg, u8 data)
> +{
> + s32 ret = -1;
> + int att;
> +
> + for (att = 0; att < s_retries; att++) {
> + ret = i2c_smbus_write_byte_data(lp->client, reg, data);
> + if (ret >= 0)
> + return 0;
> + }
> + return ret;
> +}
> +
> +static u8 arcxcnn_read_byte(struct arcxcnn *lp, u8 reg)
> +{
> + int val;
> + int att;
> +
> + for (att = 0; att < s_retries; att++) {
> + val = i2c_smbus_read_byte_data(lp->client, reg);
> + if (val >= 0)
> + return (u8)val;
> + }
> + return 0;
> +}
> +
> +static int arcxcnn_update_bit(struct arcxcnn *lp, u8 reg, u8 mask, u8 data)
> +{
> + int ret, att;
> + u8 tmp;
> +
> + for (att = 0, ret = -1; att < s_retries; att++) {
> + ret = i2c_smbus_read_byte_data(lp->client, reg);
> + if (ret >= 0)
> + break;
> + }
> + if (ret < 0) {
> + dev_err(lp->dev, "failed to read 0x%.2x\n", reg);
> + return ret;
> + }
> +
> + tmp = (u8)ret;
> + tmp &= ~mask;
> + tmp |= data & mask;
> +
> + return arcxcnn_write_byte(lp, reg, tmp);
> +}
> +
> +static int arcxcnn_set_brightness(struct arcxcnn *lp, u32 brightness)
> +{
> + int ret;
> + u8 val;
> +
> + val = (brightness & 0xF) << 4;
> + ret = arcxcnn_write_byte(lp, ARCXCNN_WLED_ISET_LSB, val);
> + if (ret < 0)
> + return ret;
> + val = (brightness >> 4);
> + ret = arcxcnn_write_byte(lp, ARCXCNN_WLED_ISET_MSB, val);
> + return ret;
> +}
> +
> +static int arcxcnn_bl_update_status(struct backlight_device *bl)
> +{
> + struct arcxcnn *lp = bl_get_data(bl);
> + u32 brightness = bl->props.brightness;
> +
> + if (bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK))
> + brightness = 0;
> +
> + /* set brightness */
> + if (lp->mode == PWM_BASED)
> + ; /* via pwm */
> + else if (lp->mode == REGISTER_BASED)
> + arcxcnn_set_brightness(lp, brightness);
> +
> + /* set power-on/off/save modes */
> + if (bl->props.power == 0)
> + /* take out of standby */
> + arcxcnn_update_bit(lp, ARCXCNN_CMD, ARCXCNN_CMD_STDBY, 0);
> + else
> + /* 1-3 == power save, 4 = off
> + * place in low-power standby mode
> + */
> + arcxcnn_update_bit(lp, ARCXCNN_CMD,
> + ARCXCNN_CMD_STDBY, ARCXCNN_CMD_STDBY);
> + return 0;
> +}
> +
> +static const struct backlight_ops arcxcnn_bl_ops = {
> + .options = BL_CORE_SUSPENDRESUME,
> + .update_status = arcxcnn_bl_update_status,
> +};
> +
> +static int arcxcnn_backlight_register(struct arcxcnn *lp)
> +{
> + struct backlight_device *bl;
> + struct backlight_properties props;
> + struct arcxcnn_platform_data *pdata = lp->pdata;
> + const char *name = pdata->name ? : DEFAULT_BL_NAME;
> +
> + memset(&props, 0, sizeof(props));
> + props.type = BACKLIGHT_PLATFORM;
> + props.max_brightness = MAX_BRIGHTNESS;
> +
> + if (pdata->initial_brightness > props.max_brightness)
> + pdata->initial_brightness = props.max_brightness;
> +
> + props.brightness = pdata->initial_brightness;
> +
> + bl = devm_backlight_device_register(lp->dev, name, lp->dev, lp,
> + &arcxcnn_bl_ops, &props);
> + if (IS_ERR(bl))
> + return PTR_ERR(bl);
> +
> + lp->bl = bl;
> +
> + return 0;
> +}
> +
> +static ssize_t arcxcnn_get_chip_id(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct arcxcnn *lp = dev_get_drvdata(dev);
> +
> + return scnprintf(buf, PAGE_SIZE, "%s\n", lp->chipname);
> +}
> +
> +static ssize_t arcxcnn_get_led_str(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct arcxcnn *lp = dev_get_drvdata(dev);
> +
> + return scnprintf(buf, PAGE_SIZE, "%02X\n", lp->pdata->led_str);
> +}
> +
> +static ssize_t arcxcnn_set_led_str(struct device *dev,
> + struct device_attribute *attr, const char *buf, size_t len)
> +{
> + struct arcxcnn *lp = dev_get_drvdata(dev);
> + unsigned long ledstr;
> +
> + if (kstrtoul(buf, 0, &ledstr))
> + return 0;
> +
> + if (ledstr != lp->pdata->led_str) {
> + /* don't allow 0 for ledstr, use power to turn all off */
> + if (ledstr == 0)
> + return 0;
> + lp->pdata->led_str = ledstr & 0x3F;
> + arcxcnn_update_bit(lp, ARCXCNN_LEDEN,
> + ARCXCNN_LEDEN_MASK, lp->pdata->led_str);
> + }
> + return len;
> +}
> +
> +static ssize_t arcxcnn_get_bl_ctl_mode(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct arcxcnn *lp = dev_get_drvdata(dev);
> + char *strmode = NULL;
> +
> + if (lp->mode == PWM_BASED)
> + strmode = "pwm based";
> + else if (lp->mode == REGISTER_BASED)
> + strmode = "register based";
> +
> + return scnprintf(buf, PAGE_SIZE, "%s\n", strmode);
> +}
> +
> +static DEVICE_ATTR(chip_id, 0444, arcxcnn_get_chip_id, NULL);
> +static DEVICE_ATTR(led_str, 0664, arcxcnn_get_led_str, arcxcnn_set_led_str);
> +static DEVICE_ATTR(bl_ctl_mode, 0444, arcxcnn_get_bl_ctl_mode, NULL);
> +
> +static struct attribute *arcxcnn_attributes[] = {
> + &dev_attr_chip_id.attr,
> + &dev_attr_led_str.attr,
> + &dev_attr_bl_ctl_mode.attr,
> + NULL,
> +};
> +
> +static const struct attribute_group arcxcnn_attr_group = {
> + .attrs = arcxcnn_attributes,
> +};
> +
> +#ifdef CONFIG_OF
> +static int arcxcnn_parse_dt(struct arcxcnn *lp)
> +{
> + struct device *dev = lp->dev;
> + struct device_node *node = dev->of_node;
> + u32 prog_val, num_entry, sources[6];
> + int ret;
> +
> + if (!node) {
> + dev_err(dev, "no platform data.\n");
> + return -EINVAL;
> + }
> + lp->pdata->led_config_0_set = false;
> + lp->pdata->led_config_1_set = false;
> + lp->pdata->dim_freq_set = false;
> + lp->pdata->comp_config_set = false;
> + lp->pdata->filter_config_set = false;
> + lp->pdata->trim_config_set = false;
> +
> + ret = of_property_read_string(node, "label", &lp->pdata->name);
> + if (ret < 0)
> + lp->pdata->name = NULL;
> +
> + ret = of_property_read_u32(node, "default-brightness", &prog_val);
> + if (ret < 0)
> + prog_val = s_ibright;
> + lp->pdata->initial_brightness = prog_val;
> + if (lp->pdata->initial_brightness > MAX_BRIGHTNESS)
> + lp->pdata->initial_brightness = MAX_BRIGHTNESS;
> +
> + ret = of_property_read_u32(node, "arcticsand,led-config-0", &prog_val);
> + if (ret == 0) {
> + lp->pdata->led_config_0 = (u8)prog_val;
> + lp->pdata->led_config_0_set = true;
> + }
> + ret = of_property_read_u32(node, "arcticsand,led-config-1", &prog_val);
> + if (ret == 0) {
> + lp->pdata->led_config_1 = (u8)prog_val;
> + lp->pdata->led_config_1_set = true;
> + }
> + ret = of_property_read_u32(node, "arcticsand,dim-freq", &prog_val);
> + if (ret == 0) {
> + lp->pdata->dim_freq = (u8)prog_val;
> + lp->pdata->dim_freq_set = true;
> + }
> + ret = of_property_read_u32(node, "arcticsand,comp-config", &prog_val);
> + if (ret == 0) {
> + lp->pdata->comp_config = (u8)prog_val;
> + lp->pdata->comp_config_set = true;
> + }
> + ret = of_property_read_u32(node, "arcticsand,filter-config", &prog_val);
> + if (ret == 0) {
> + lp->pdata->filter_config = (u8)prog_val;
> + lp->pdata->filter_config_set = true;
> + }
> + ret = of_property_read_u32(node, "arcticsand,trim-config", &prog_val);
> + if (ret == 0) {
> + lp->pdata->trim_config = (u8)prog_val;
> + lp->pdata->trim_config_set = true;
> + }
> + ret = of_property_count_u32_elems(node, "led-sources");
> + if (ret < 0)
> + lp->pdata->led_str = 0x3F;
> + else {
> + num_entry = ret;
> + if (num_entry > 6)
> + num_entry = 6;
> +
> + ret = of_property_read_u32_array(node, "led-sources", sources,
> + num_entry);
> + if (ret < 0) {
> + dev_err(dev, "led-sources node is invalid.\n");
> + return -EINVAL;
> + }
> +
> + lp->pdata->led_str = 0;
> + while (num_entry > 0)
> + lp->pdata->led_str |= (1 << sources[--num_entry]);
> + }
> + return 0;
> +}
> +#else
> +static int arcxcnn_parse_dt(struct arcxcnn *lp)
> +{
> + return -EINVAL;
> +}
> +#endif
> +
> +static int arcxcnn_probe(struct i2c_client *cl, const struct i2c_device_id *id)
> +{
> + struct arcxcnn *lp;
> + int ret;
> + u8 regval;
> + u16 chipid;
> +
> + if (!i2c_check_functionality(cl->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
> + return -EIO;
> +
> + lp = devm_kzalloc(&cl->dev, sizeof(*lp), GFP_KERNEL);
> + if (!lp)
> + return -ENOMEM;
> +
> + lp->client = cl;
> + lp->dev = &cl->dev;
> + lp->chip_id = id->driver_data;
> + lp->pdata = dev_get_platdata(&cl->dev);
> +
> + if (!lp->pdata) {
> + lp->pdata = devm_kzalloc(lp->dev,
> + sizeof(*lp->pdata), GFP_KERNEL);
> + if (!lp->pdata)
> + return -ENOMEM;
> +
> + /* no platform data, parse the device-tree for info. if there
> + * is no device tree entry, we are being told we exist because
> + * user-land said so, so make up the info we need
> + */
> + ret = arcxcnn_parse_dt(lp);
> + if (ret < 0) {
> + /* no device tree, use defaults based on module params
> + */
> + lp->pdata->led_config_0_set = false;
> + lp->pdata->led_config_1_set = false;
> + lp->pdata->dim_freq_set = false;
> + lp->pdata->comp_config_set = false;
> + lp->pdata->filter_config_set = false;
> + lp->pdata->trim_config_set = false;
> +
> + lp->pdata->name = NULL;
> + lp->pdata->initial_brightness = s_ibright;
> + lp->pdata->led_str = s_iledstr;
> + }
> + }
> +
> + if (lp->pdata->dim_freq_set)
> + lp->mode = PWM_BASED;
> + else
> + lp->mode = REGISTER_BASED;
> +
> + i2c_set_clientdata(cl, lp);
> +
> + /* read device ID */
> + regval = arcxcnn_read_byte(lp, 0x1E);
> + chipid = regval;
> + chipid <<= 8;
> + regval = arcxcnn_read_byte(lp, 0x1F);
> + chipid |= regval;
> +
> + /* make sure it belongs to this driver
> + * TODO - handle specific ids
> + */
> + if (chipid != 0x02A5) {
> + #if 1
> + dev_info(&cl->dev, "Chip Id is %04X\n", chipid);
> + #else
> + dev_err(&cl->dev, "%04X is not ARC2C\n", chipid);
> + return -ENODEV;
> + #endif
> + }
> + /* reset the device */
> + arcxcnn_write_byte(lp, ARCXCNN_CMD, ARCXCNN_CMD_RESET);
> +
> + /* set initial brightness */
> + arcxcnn_set_brightness(lp, lp->pdata->initial_brightness);
> +
> + /* if fadectrl set in DT, set the value directly, else leave default */
> + if (lp->pdata->led_config_0_set)
> + arcxcnn_write_byte(lp, ARCXCNN_FADECTRL,
> + lp->pdata->led_config_0);
> +
> + /* if iled config set in DT, set the value, else internal mode */
> + if (lp->pdata->led_config_1_set)
> + arcxcnn_write_byte(lp, ARCXCNN_ILED_CONFIG,
> + lp->pdata->led_config_1);
> + else
> + arcxcnn_write_byte(lp, ARCXCNN_ILED_CONFIG, 0x57);
> +
> + /* other misc DT settings */
> + if (lp->pdata->dim_freq_set)
> + arcxcnn_write_byte(lp, ARCXCNN_FADECTRL, lp->pdata->dim_freq);
> + if (lp->pdata->comp_config_set)
> + arcxcnn_write_byte(lp, ARCXCNN_COMP_CONFIG,
> + lp->pdata->comp_config);
> + if (lp->pdata->filter_config_set)
> + arcxcnn_write_byte(lp, ARCXCNN_FILT_CONFIG,
> + lp->pdata->filter_config);
> + if (lp->pdata->trim_config_set)
> + arcxcnn_write_byte(lp, ARCXCNN_IMAXTUNE,
> + lp->pdata->trim_config);
> +
> + /* set initial LED Strings */
> + arcxcnn_update_bit(lp, ARCXCNN_LEDEN,
> + ARCXCNN_LEDEN_MASK, lp->pdata->led_str);
> +
> + snprintf(lp->chipname, sizeof(lp->chipname),
> + "%s-%04X", id->name, chipid);
> +
> + ret = arcxcnn_backlight_register(lp);
> + if (ret) {
> + dev_err(lp->dev,
> + "failed to register backlight. err: %d\n", ret);
> + return ret;
> + }
> +
> + ret = sysfs_create_group(&lp->dev->kobj, &arcxcnn_attr_group);
> + if (ret) {
> + dev_err(lp->dev, "failed to register sysfs. err: %d\n", ret);
> + return ret;
> + }
> +
> + backlight_update_status(lp->bl);
> + return 0;
> +}
> +
> +static int arcxcnn_remove(struct i2c_client *cl)
> +{
> + struct arcxcnn *lp = i2c_get_clientdata(cl);
> +
> + if (!s_no_reset_on_remove) {
> + /* disable all strings */
> + arcxcnn_write_byte(lp, ARCXCNN_LEDEN, 0x00);
> + /* reset the device */
> + arcxcnn_write_byte(lp, ARCXCNN_CMD, ARCXCNN_CMD_RESET);
> + }
> + lp->bl->props.brightness = 0;
> + backlight_update_status(lp->bl);
> + if (lp->supply)
> + regulator_disable(lp->supply);
> + sysfs_remove_group(&lp->dev->kobj, &arcxcnn_attr_group);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id arcxcnn_dt_ids[] = {
> + { .compatible = "arc,arc2c0608" },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, arcxcnn_dt_ids);
> +
> +/* Note that the device/chip ID is not fixed in silicon so
> + * auto-probing of these devices on the bus is most likely
> + * not possible, use device tree to set i2c bus address
> + */
> +static const struct i2c_device_id arcxcnn_ids[] = {
> + {"arc2c0608", ARC2C0608},
> + { }
> +};
> +MODULE_DEVICE_TABLE(i2c, arcxcnn_ids);
> +
> +static struct i2c_driver arcxcnn_driver = {
> + .driver = {
> + .name = "arcxcnn_bl",
> + .of_match_table = of_match_ptr(arcxcnn_dt_ids),
> + },
> + .probe = arcxcnn_probe,
> + .remove = arcxcnn_remove,
> + .id_table = arcxcnn_ids,
> +};
> +
> +module_i2c_driver(arcxcnn_driver);
> +
> +MODULE_LICENSE("GPL v2");
> +MODULE_AUTHOR("Brian Dodge <bdodge09@outlook.com>");
> +MODULE_DESCRIPTION("ARCXCNN Backlight driver");
> diff --git a/include/linux/i2c/arcxcnn.h b/include/linux/i2c/arcxcnn.h
> new file mode 100644
> index 0000000..1c681dd
> --- /dev/null
> +++ b/include/linux/i2c/arcxcnn.h
> @@ -0,0 +1,67 @@
> +/*
> + * Backlight driver for ArcticSand ARC2C0608 Backlight Devices
> + *
> + * Copyright 2016 ArcticSand, Inc.
> + *
> + * Licensed under the GPL-2 or later.
> + */
> +
> +#ifndef _ARCXCNN_H
> +#define _ARCXCNN_H
> +
> +enum arcxcnn_chip_id {
> + ARC2C0608
> +};
> +
> +enum arcxcnn_brightness_source {
> + ARCXCNN_PWM_ONLY,
> + ARCXCNN_I2C_ONLY = 2,
> +};
> +
> +#define ARCXCNN_MAX_PROGENTRIES 48 /* max a/v pairs for custom */
> +
> +/**
> + * struct arcxcnn_platform_data
> + * @name : Backlight driver name. If it is not defined, default name is set.
> + * @initial_brightness : initial value of backlight brightness
> + * @led_str : initial LED string enables, upper bit is global on/off
> + * @led_config_0 : fading speed (period between intensity steps)
> + * @led_config_1 : misc settings, see datasheet
> + * @dim_freq : pwm dimming frequency if in pwm mode
> + * @comp_config : misc config, see datasheet
> + * @filter_config: RC/PWM filter config, see datasheet
> + * @trim_config : full scale current trim, see datasheet
> + * @led_config_0_set : the value in led_config_0 is valid
> + * @led_config_1_set : the value in led_config_1 is valid
> + * @dim_freq_set : the value in dim_freq is valid
> + * @comp_config_set : the value in comp_config is valid
> + * @filter_config_set : the value in filter_config is valid
> + * @trim_config_set : the value in trim_config is valid
> + *
> + * the _set flags are used to indicate that the value was explicitly set
> + * in the device tree or platform data. settings not set are left as default
> + * power-on default values of the chip except for led_str and led_config_1
> + * which are set by the driver (led_str is specified indirectly in the
> + * device tree via "led-sources")
> + */
> +struct arcxcnn_platform_data {
> + const char *name;
> + u16 initial_brightness;
> + u8 led_str;
> +
> + u8 led_config_0;
> + u8 led_config_1;
> + u8 dim_freq;
> + u8 comp_config;
> + u8 filter_config;
> + u8 trim_config;
> +
> + bool led_config_0_set;
> + bool led_config_1_set;
> + bool dim_freq_set;
> + bool comp_config_set;
> + bool filter_config_set;
> + bool trim_config_set;
> +};
> +
> +#endif
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* Re: [PATCH 2/4] usb: musb: Fix sleeping function called from invalid context for hdrc glue
From: Johan Hovold @ 2016-11-09 15:50 UTC (permalink / raw)
To: Tony Lindgren
Cc: Johan Hovold, Bin Liu, Boris Brezillon, Greg Kroah-Hartman,
Andreas Kemnade, Felipe Balbi, George Cherian,
Kishon Vijay Abraham I, Ivaylo Dimitrov, Ladislav Michl,
Laurent Pinchart, Sergei Shtylyov,
linux-usb-u79uwXL29TY76Z2rM5mHXA,
linux-omap-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20161109153409.GU2428-4v6yS6AI5VpBDgjK7y7TUQ@public.gmane.org>
On Wed, Nov 09, 2016 at 08:34:10AM -0700, Tony Lindgren wrote:
> * Tony Lindgren <tony-4v6yS6AI5VpBDgjK7y7TUQ@public.gmane.org> [161108 18:26]:
> > * Johan Hovold <johan-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> [161108 12:03]:
> > +int musb_queue_resume_work(struct musb *musb,
> > + int (*callback)(struct musb *musb, void *data),
> > + void *data)
> > +{
> > + struct musb_pending_work *w;
> > + unsigned long flags;
> > + int error;
> > +
> > + if (WARN_ON(!callback))
> > + return -EINVAL;
> > +
> > + if (pm_runtime_active(musb->controller))
> > + return callback(musb, data);
> > +
> > + w = devm_kzalloc(musb->controller, sizeof(*w), GFP_ATOMIC);
> > + if (!w)
> > + return -ENOMEM;
> > +
> > + w->callback = callback;
> > + w->data = data;
> > + spin_lock_irqsave(&musb->list_lock, flags);
> > + if (musb->is_runtime_suspended) {
> > + list_add_tail(&w->node, &musb->pending_list);
> > + error = 0;
> > + } else {
> > + dev_err(musb->controller, "could not add resume work %p\n",
> > + callback);
> > + devm_kfree(musb->controller, w);
> > + error = -EINPROGRESS;
> > + }
> > + spin_unlock_irqrestore(&musb->list_lock, flags);
> > +
> > + if (pm_runtime_active(musb->controller))
> > + return musb_run_resume_work(musb);
> > +
> > + return error;
> > +}
>
> Hmm I think we can also leave out musb_run_resume_work() at the end,
> we should not hit that case any longer.
That seems to be the case, yes. But we still need to process that work
somehow also when racing with runtime_resume() (e.g. here or at every
call site).
Johan
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [U-Boot] [PATCH v3 1/3] ARM: bcm283x: Implement EFI RTS reset_system
From: Stephen Warren @ 2016-11-09 15:50 UTC (permalink / raw)
To: u-boot
In-Reply-To: <d2741f75-5f1e-2a11-1d8d-927a2d4b0990@suse.de>
On 11/09/2016 04:43 AM, Alexander Graf wrote:
>
>
> On 07/11/2016 22:26, Stephen Warren wrote:
>> On 11/06/2016 03:24 AM, Alexander Graf wrote:
>>>
>>>
>>> On 05/11/2016 23:01, Stephen Warren wrote:
>>>> On 11/02/2016 03:36 AM, Alexander Graf wrote:
>>>>> The rpi has a pretty simple way of resetting the whole system. All it
>>>>> takes
>>>>> is to poke a few registers at a well defined location in MMIO space.
>>>>>
>>>>> This patch adds support for the EFI loader implementation to allow an
>>>>> OS to
>>>>> reset and power off the system when we're outside of boot time.
>>>>
>>>> (As an aside, I'm not sure why someone wanting EFI wouldn't just use a
>>>> complete EFI implementation such as TianoCore.)
>>>>
>>>>> diff --git a/arch/arm/mach-bcm283x/reset.c
>>>>> b/arch/arm/mach-bcm283x/reset.c
>>>>
>>>>> +__efi_runtime_data struct bcm2835_wdog_regs *wdog_regs =
>>>>> + (struct bcm2835_wdog_regs *)BCM2835_WDOG_PHYSADDR;
>>>>> +
>>>>> +void __efi_runtime reset_cpu(ulong addr)
>>>>> {
>>>>> - struct bcm2835_wdog_regs *regs =
>>>>> - (struct bcm2835_wdog_regs *)BCM2835_WDOG_PHYSADDR;
>>>>
>>>> I'm not sure why that change is required. The value of the variable is
>>>> the same in both cases?
>>>
>>> Take a look a few lines down in the patch:
>>>
>>>> +void efi_reset_system_init(void)
>>>> +{
>>>> + efi_add_runtime_mmio(&wdog_regs, sizeof(*wdog_regs));
>>>> +}
>>>
>>> What this does is register a *pointer* as run time service pointer. What
>>> does that mean?
>>>
>>> When we enter RTS, Linux can map any region in the EFI memory map into a
>>> different place in its own virtual memory map. So any pointers we use
>>> inside RTS have to be relocated to the new locations.
>>>
>>> For normal relocations, we move the relocations from linker time to run
>>> time, so that we can relocate ourselves when Linux does the switch-over
>>> to a new address space.
>>>
>>> However, for MMIO that's trickier. That's where the
>>> efi_add_runtime_mmio() function comes into play. It takes care of adding
>>> the page around the references address to the EFI memory map as RTS MMIO
>>> and relocates the pointer when Linux switches us into the new address
>>> space.
>>>
>>> Does that explain why we need to move from an inline address to an
>>> address stored in a memory location?
>>
>> So EFI RTS runs in the same exception level as the rich OS, and not in
>> EL3? I would have expected EFI to run in EL3 with a completely separate
>> MMU configuration. If that's not the case, then this part of the patch
>> does make sense.
>
> Right, it runs in EL2/EL1 with a virtual memory layout that is provided
> by the OS.
>
>>
>>>> Perhaps it's trying to ensure that if this gets compiled into an ldr
>>>> instruction, the referenced data value is in a linker section that's
>>>> still around when EFI runs? If so fine, but how is that ensured for all
>>>> the other constants that this code uses, and if that happens
>>>> automatically due to the __efi_runtime marker above, why doesn't it
>>>> work
>>>> for this one constant?
>>>>
>>>> Does U-Boot have a halt/poweroff/shutdown shell command? If so, it
>>>> might
>>>> be nice to enable it as part of this series, since the code to perform
>>>> that operation is now present.
>>>
>>> That's what I originally wanted, yes :). Unfortunately due to the
>>> relocation explained above, it's basically impossible for any reset
>>> function that calls into MMIO space.
>>>
>>> However, we do have it now for PSCI. If you have a PSCI enabled system,
>>> we don't need to call into MMIO space and thus make the common reset
>>> function available as RTS.
>>
>> Can't the same U-Boot function be called both (a) during U-Boot runtime,
>> where wdog_regs are pre-initialized to match U-Boot's MMU configuration,
>> and (b) once the OS has booted, where wdog_regs has been modified
>> according to the new memory map?
>
> That's exactly what this patch does, no?
I assume not, since you said just a few lines above that doing so was
impossible, hence why it doesn't implement any halt/poweroff/shutdown
shell commands.
^ permalink raw reply
* Re: Question about 2 gp8psk patches I noticed, and possible bug.
From: VDR User @ 2016-11-09 15:49 UTC (permalink / raw)
To: Mauro Carvalho Chehab; +Cc: mailing list: linux-media
In-Reply-To: <CAA7C2qhK0x9bwHH-Q8ufz3zdOgiPs3c=d27s0BRNfmcv9+T+Gg@mail.gmail.com>
$ gdb /usr/src/linux/vmlinux
GNU gdb (Debian 7.11.1-2) 7.11.1
...
Reading symbols from /usr/src/linux/vmlinux...done.
(gdb) l *module_put+0x67
0xc10a4b87 is in module_put (kernel/module.c:1108).
1103 int ret;
1104
1105 if (module) {
1106 preempt_disable();
1107 ret = atomic_dec_if_positive(&module->refcnt);
1108 WARN_ON(ret < 0); /* Failed to put refcount */
1109 trace_module_put(module, _RET_IP_);
1110 preempt_enable();
1111 }
1112 }
^ permalink raw reply
* Re: linux.git: printk() problem
From: Petr Mladek @ 2016-11-09 15:47 UTC (permalink / raw)
To: Linus Torvalds
Cc: Sergey Senozhatsky, Sergey Senozhatsky, Joe Perches,
Geert Uytterhoeven, Tetsuo Handa, Linux Kernel Mailing List,
Tejun Heo, Calvin Owens, Steven Rostedt, Andrew Morton
In-Reply-To: <CA+55aFwKYnrMJr_vSE+GfDGszeUGyd=CPUD15-zZ8yWQW61GBA@mail.gmail.com>
On Mon 2016-10-24 19:22:59, Linus Torvalds wrote:
> On Mon, Oct 24, 2016 at 7:06 PM, Linus Torvalds
> <torvalds@linux-foundation.org> wrote:
> > On Mon, Oct 24, 2016 at 6:55 PM, Sergey Senozhatsky
> > <sergey.senozhatsky.work@gmail.com> wrote:
> >>
> >> I think cont_flush() should grab the logbuf_lock lock, because
> >> it does log_store() and touches the cont.len. so something like
> >> this perhaps
> >
> > Absolutely. Good catch.
>
> Actually, you can't do it the way you did (inside cont_flush), because
> "cont_flush()" is already called with logbuf_lock held in most cases
> (see "cont_add()").
>
> So it's really just the timer function that needs to take the
> logbuf_lock before it calls cont_flush().
>
> So here's a new version. How does this look to you?
>
> Again, this still tests "cont.len" outside the lock (not just in
> console_unlock(), but also in deferred_cont_flush()). And it's fine:
> even if it sees the "wrong" value due to some race, it does so either
> because cont.len was just set to non-zero (and whoever set it will
> force the re-check anyway), or it got cleared just as it was tested
> (and at worst you end up with an extra timer invocation).
This patch really seems to reduce the number of too-early flushed
continuous lines. It reduces the scattered output. But I am not sure
if we want to add a timer code into the printk calls at this stage
(for 4.9-rc5).
Well, the patch looks fine, except that we call cont_flush() without
poking console. It is not a regression because only newlines triggered
console in the past and they still do but...
I would suggest to revert the commit bfd8d3f23b51018388be
("printk: make reading the kernel log flush pending lines") for
4.9. Then we could test/fix it properly for 4.10. Me and Sergey would
happily help with it.
Just in case, you still want to commit this patch. I would suggest
to apply the one below on top.
>From 7a0ad7ce2347346fc81872fe42a95ad5dfba4098 Mon Sep 17 00:00:00 2001
From: Petr Mladek <pmladek@suse.com>
Date: Tue, 25 Oct 2016 15:23:13 +0200
Subject: [PATCH] printk: Poke console and other loggers when cont buffer is
flushed
The commit bfd8d3f23b51018388be041 ("printk: make reading the kernel
log flush pending lines") allows to add new message into the log
buffer without flushing it to the console and waking other loggers.
This patch adds wake_up_console() and calls it when the cont
buffer is flushed. The function name will make more sense once
we switch to the async printk.
Note that it is enough to poke console. The other loggers
are waken from console_unlock() when there is a new message.
The patch also renames PRINTK_PENDING flags and wake_up_klogd_work*
stuff to reduce confusion. First, there are more possible log
daemons, e.g. klogd, syslogd. Second, the word "console" is more
descriptive than "output".
This patch is based on top of the fix proposed at
https://lkml.kernel.org/r/CA+55aFwKYnrMJr_vSE+GfDGszeUGyd=CPUD15-zZ8yWQW61GBA@mail.gmail.com
Signed-off-by: Petr Mladek <pmladek@suse.com>
---
kernel/printk/printk.c | 60 ++++++++++++++++++++++++++++++++++----------------
1 file changed, 41 insertions(+), 19 deletions(-)
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index e63aa679614e..f0e72de6ddbc 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -780,6 +780,7 @@ static ssize_t devkmsg_write(struct kiocb *iocb, struct iov_iter *from)
}
static void deferred_cont_flush(void);
+static void __wake_up_console(void);
static ssize_t devkmsg_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
@@ -1620,13 +1621,11 @@ static bool cont_flush(void)
static void flush_timer(unsigned long data)
{
unsigned long flags;
- bool did_flush;
raw_spin_lock_irqsave(&logbuf_lock, flags);
- did_flush = cont_flush();
+ if (cont_flush())
+ __wake_up_console();
raw_spin_unlock_irqrestore(&logbuf_lock, flags);
- if (did_flush)
- wake_up_klogd();
}
static void deferred_cont_flush(void)
@@ -2730,40 +2729,57 @@ static int __init printk_late_init(void)
#if defined CONFIG_PRINTK
/*
- * Delayed printk version, for scheduler-internal messages:
+ * Handle console and wakeup loggers via IRQ work so that it can be done
+ * from any context.
*/
-#define PRINTK_PENDING_WAKEUP 0x01
-#define PRINTK_PENDING_OUTPUT 0x02
+#define PRINTK_PENDING_LOGGERS 0x01
+#define PRINTK_PENDING_CONSOLE 0x02
static DEFINE_PER_CPU(int, printk_pending);
-static void wake_up_klogd_work_func(struct irq_work *irq_work)
+static void printk_pending_func(struct irq_work *irq_work)
{
int pending = __this_cpu_xchg(printk_pending, 0);
- if (pending & PRINTK_PENDING_OUTPUT) {
+ if (pending & PRINTK_PENDING_CONSOLE) {
/* If trylock fails, someone else is doing the printing */
if (console_trylock())
console_unlock();
}
- if (pending & PRINTK_PENDING_WAKEUP)
+ if (pending & PRINTK_PENDING_LOGGERS)
wake_up_interruptible(&log_wait);
+
deferred_cont_flush();
}
-static DEFINE_PER_CPU(struct irq_work, wake_up_klogd_work) = {
- .func = wake_up_klogd_work_func,
+static DEFINE_PER_CPU(struct irq_work, printk_pending_work) = {
+ .func = printk_pending_func,
.flags = IRQ_WORK_LAZY,
};
void wake_up_klogd(void)
{
preempt_disable();
+
if (waitqueue_active(&log_wait)) {
- this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP);
- irq_work_queue(this_cpu_ptr(&wake_up_klogd_work));
+ this_cpu_or(printk_pending, PRINTK_PENDING_LOGGERS);
+ irq_work_queue(this_cpu_ptr(&printk_pending_work));
}
+
+ preempt_enable();
+}
+
+static void __wake_up_console(void)
+{
+ this_cpu_or(printk_pending, PRINTK_PENDING_CONSOLE);
+ irq_work_queue(this_cpu_ptr(&printk_pending_work));
+}
+
+static void wake_up_console(void)
+{
+ preempt_disable();
+ __wake_up_console();
preempt_enable();
}
@@ -2777,8 +2793,7 @@ int printk_deferred(const char *fmt, ...)
r = vprintk_emit(0, LOGLEVEL_SCHED, NULL, 0, fmt, args);
va_end(args);
- __this_cpu_or(printk_pending, PRINTK_PENDING_OUTPUT);
- irq_work_queue(this_cpu_ptr(&wake_up_klogd_work));
+ __wake_up_console();
preempt_enable();
return r;
@@ -2893,6 +2908,7 @@ void kmsg_dump(enum kmsg_dump_reason reason)
{
struct kmsg_dumper *dumper;
unsigned long flags;
+ int did_flush = 0;
if ((reason > KMSG_DUMP_OOPS) && !always_kmsg_dump)
return;
@@ -2906,7 +2922,7 @@ void kmsg_dump(enum kmsg_dump_reason reason)
dumper->active = true;
raw_spin_lock_irqsave(&logbuf_lock, flags);
- cont_flush();
+ did_flush |= cont_flush();
dumper->cur_seq = clear_seq;
dumper->cur_idx = clear_idx;
dumper->next_seq = log_next_seq;
@@ -2920,6 +2936,9 @@ void kmsg_dump(enum kmsg_dump_reason reason)
dumper->active = false;
}
rcu_read_unlock();
+
+ if (did_flush)
+ wake_up_console();
}
/**
@@ -2997,7 +3016,8 @@ bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog,
bool ret;
raw_spin_lock_irqsave(&logbuf_lock, flags);
- cont_flush();
+ if (cont_flush())
+ __wake_up_console();
ret = kmsg_dump_get_line_nolock(dumper, syslog, line, size, len);
raw_spin_unlock_irqrestore(&logbuf_lock, flags);
@@ -3039,7 +3059,9 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
goto out;
raw_spin_lock_irqsave(&logbuf_lock, flags);
- cont_flush();
+ if (cont_flush())
+ __wake_up_console();
+
if (dumper->cur_seq < log_first_seq) {
/* messages are gone, move to first available one */
dumper->cur_seq = log_first_seq;
--
1.8.5.6
^ permalink raw reply related
* [PATCH] mfd: qcom-pm8xxx: Clean up PM8XXX namespace
From: Lee Jones @ 2016-11-09 15:47 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1477487453-15801-1-git-send-email-linus.walleij@linaro.org>
On Wed, 26 Oct 2016, Linus Walleij wrote:
> The Kconfig and file naming for the PM8xxx driver is totally
> confusing:
>
> - Kconfig options MFD_PM8XXX and MFD_PM8921_CORE, some in-kernel
> users depending on or selecting either at random.
> - A driver file named pm8921-core.c even if it is indeed
> used by the whole PM8xxx family of chips.
> - An irqchip named pm8xxx since it was (I guess) realized that
> the driver was generic for all pm8xxx PMICs.
>
> As I may want to add support for PM8901 this is starting to get
> really messy. Fix this situation by:
>
> - Remove the MFD_PM8921_CORE symbol and rely solely on MFD_PM8XXX
> and convert all users, including LEDs Kconfig and ARM defconfigs
> for qcom and multi_v7 to use that single symbol.
> - Renaming the driver to qcom-pm8xxx.c to fit along the two
> other qcom* prefixed drivers.
> - Rename functions withing the driver from 8921 to 8xxx to
> indicate it is generic.
> - Just drop the =m config from the pxa_defconfig, I have no clue
> why it is even there, it is not a Qualcomm platform. (Possibly
> older Kconfig noise from saveconfig.)
>
> Cc: Stephen Boyd <sboyd@codeaurora.org>
> Cc: Bjorn Andersson <bjorn.andersson@linaro.org>
> Cc: Neil Armstrong <narmstrong@baylibre.com>
> Cc: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
> ---
> I do NOT think it is a good idea to try to split this commit up,
> I rather prefer that Lee simply merge it into MFD.
>
> The reason is that files like qcom_defconfig already contain both
> the right symbols, but the MFD_PM8921_CORE symbol cannot be removed
> until this rename has happened, whereas multi_v7_defconfig needs
> it added etc, and this is just a clean nice cut.
>
> Jacek, ARM SoC person: please ACK this patch to get merged into
> MFD.
> ---
> arch/arm/configs/multi_v7_defconfig | 2 +-
> arch/arm/configs/pxa_defconfig | 1 -
> arch/arm/configs/qcom_defconfig | 1 -
> drivers/leds/Kconfig | 2 +-
> drivers/mfd/Kconfig | 14 ++++------
> drivers/mfd/Makefile | 2 +-
> drivers/mfd/{pm8921-core.c => qcom-pm8xxx.c} | 42 ++++++++++++++--------------
For my own reference:
Acked-for-MFD-by: Lee Jones <lee.jones@linaro.org>
> 7 files changed, 29 insertions(+), 35 deletions(-)
> rename drivers/mfd/{pm8921-core.c => qcom-pm8xxx.c} (92%)
How many more Acks do we need?
[...]
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* Re: [PATCH] mfd: qcom-pm8xxx: Clean up PM8XXX namespace
From: Lee Jones @ 2016-11-09 15:47 UTC (permalink / raw)
To: Linus Walleij
Cc: Neil Armstrong, linux-arm-msm, Abhijeet Dharmapurikar,
Stephen Boyd, linux-kernel, Bjorn Andersson, arm, Andy Gross,
Jacek Anaszewski, linux-arm-kernel
In-Reply-To: <1477487453-15801-1-git-send-email-linus.walleij@linaro.org>
On Wed, 26 Oct 2016, Linus Walleij wrote:
> The Kconfig and file naming for the PM8xxx driver is totally
> confusing:
>
> - Kconfig options MFD_PM8XXX and MFD_PM8921_CORE, some in-kernel
> users depending on or selecting either at random.
> - A driver file named pm8921-core.c even if it is indeed
> used by the whole PM8xxx family of chips.
> - An irqchip named pm8xxx since it was (I guess) realized that
> the driver was generic for all pm8xxx PMICs.
>
> As I may want to add support for PM8901 this is starting to get
> really messy. Fix this situation by:
>
> - Remove the MFD_PM8921_CORE symbol and rely solely on MFD_PM8XXX
> and convert all users, including LEDs Kconfig and ARM defconfigs
> for qcom and multi_v7 to use that single symbol.
> - Renaming the driver to qcom-pm8xxx.c to fit along the two
> other qcom* prefixed drivers.
> - Rename functions withing the driver from 8921 to 8xxx to
> indicate it is generic.
> - Just drop the =m config from the pxa_defconfig, I have no clue
> why it is even there, it is not a Qualcomm platform. (Possibly
> older Kconfig noise from saveconfig.)
>
> Cc: Stephen Boyd <sboyd@codeaurora.org>
> Cc: Bjorn Andersson <bjorn.andersson@linaro.org>
> Cc: Neil Armstrong <narmstrong@baylibre.com>
> Cc: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
> ---
> I do NOT think it is a good idea to try to split this commit up,
> I rather prefer that Lee simply merge it into MFD.
>
> The reason is that files like qcom_defconfig already contain both
> the right symbols, but the MFD_PM8921_CORE symbol cannot be removed
> until this rename has happened, whereas multi_v7_defconfig needs
> it added etc, and this is just a clean nice cut.
>
> Jacek, ARM SoC person: please ACK this patch to get merged into
> MFD.
> ---
> arch/arm/configs/multi_v7_defconfig | 2 +-
> arch/arm/configs/pxa_defconfig | 1 -
> arch/arm/configs/qcom_defconfig | 1 -
> drivers/leds/Kconfig | 2 +-
> drivers/mfd/Kconfig | 14 ++++------
> drivers/mfd/Makefile | 2 +-
> drivers/mfd/{pm8921-core.c => qcom-pm8xxx.c} | 42 ++++++++++++++--------------
For my own reference:
Acked-for-MFD-by: Lee Jones <lee.jones@linaro.org>
> 7 files changed, 29 insertions(+), 35 deletions(-)
> rename drivers/mfd/{pm8921-core.c => qcom-pm8xxx.c} (92%)
How many more Acks do we need?
[...]
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH] drbd: Fix kernel_sendmsg() usage
From: Richard Weinberger @ 2016-11-09 15:47 UTC (permalink / raw)
To: Jens Axboe, wolfgang.glas, christoph.lechleitner, philipp.reisner,
stable, linux-kernel, viro, drbd-dev
In-Reply-To: <20161109153209.GK1382@soda.linbit>
On 09.11.2016 16:32, Lars Ellenberg wrote:
> On Tue, Nov 08, 2016 at 09:52:04AM -0700, Jens Axboe wrote:
>>>> This should go into 4.9,
>>>> and into all stable branches since and including v4.0,
>>>> which is the first to contain the exposing change.
>>>>
>>>> It is correct for all stable branches older than that as well
>>>> (which contain the DRBD driver; which is 2.6.33 and up).
>>>>
>>>> It requires a small "conflict" resolution for v4.4 and earlier, with v4.5
>>>> we dropped the comment block immediately preceding the kernel_sendmsg().
>>>>
>>>> Cc: stable@vger.kernel.org
>>>> Cc: viro@zeniv.linux.org.uk
>>>> Cc: christoph.lechleitner@iteg.at
>>>> Cc: wolfgang.glas@iteg.at
>>>> Reported-by: Christoph Lechleitner <christoph.lechleitner@iteg.at>
>>>> Tested-by: Christoph Lechleitner <christoph.lechleitner@iteg.at>
>>>> Signed-off-by: Richard Weinberger <richard@nod.at>
>>>> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
>>>
>>> Changing my patch is perfectly fine, but please clearly state it.
>>> I.e. by adding something like that before your S-o-b.
>>> [Lars: Massaged patch to match my personal taste...]
>>
>
>> Lars, are you sending a new one? If you do, add the stable tag as well.
>
> So my "change" against his original patch was
> - rv = kernel_sendmsg(sock, &msg, &iov, 1, size - sent);
> + rv = kernel_sendmsg(sock, &msg, &iov, 1, iov.iov_len);
> to make it "more obviously correct" from looking just at the one line
> without even having to read the context. And a more verbose commit message.
>
> If that requires yet additional noise, sure, so be it :)
>
> Should I sent two patches, one that applies to 4.5 and later,
> and one that applies to 2.6.33 ... 4.4, or are you or stable
> willing to resolve the trivial "missing comment block" conflict yourself?
BTW: Why did you drop the "Fixes:" tag too?
Thanks,
//richard
^ permalink raw reply
* Re: [Qemu-devel] [PATCH] vhost: Use vbus var instead of VIRTIO_BUS() macro
From: Michael S. Tsirkin @ 2016-11-09 15:47 UTC (permalink / raw)
To: Paolo Bonzini; +Cc: Felipe Franciosi, Stefan Hajnoczi, qemu-devel@nongnu.org
In-Reply-To: <22f2ee5c-8dc4-c142-f0a9-130fde997c3f@redhat.com>
On Wed, Nov 09, 2016 at 02:22:42PM +0100, Paolo Bonzini wrote:
>
>
> On 09/11/2016 14:18, Felipe Franciosi wrote:
> > Recent changes on vhost_dev_enable/disable_notifiers() produced a
> > VirtioBusState vbus variable which can be used instead of the
> > VIRTIO_BUS() macro. This commit just makes the code a little bit cleaner
> > and more consistent.
> >
> > Signed-off-by: Felipe Franciosi <felipe@nutanix.com>
>
> Michael, what do you think? Perhaps it's simplest to just squash the
> two patches (v2 of "vhost: Update 'ioeventfd_started' with host
> notifiers" and this one).
>
> Paolo
I think I'll apply both but why bother squashing?
> > ---
> > hw/virtio/vhost.c | 14 ++++++--------
> > 1 file changed, 6 insertions(+), 8 deletions(-)
> >
> > diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
> > index 1290963..7d29dad 100644
> > --- a/hw/virtio/vhost.c
> > +++ b/hw/virtio/vhost.c
> > @@ -1198,20 +1198,18 @@ int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev)
> >
> > virtio_device_stop_ioeventfd(vdev);
> > for (i = 0; i < hdev->nvqs; ++i) {
> > - r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), hdev->vq_index + i,
> > - true);
> > + r = virtio_bus_set_host_notifier(vbus, hdev->vq_index + i, true);
> > if (r < 0) {
> > error_report("vhost VQ %d notifier binding failed: %d", i, -r);
> > goto fail_vq;
> > }
> > }
> > - VIRTIO_BUS(qbus)->ioeventfd_started = true;
> > + vbus->ioeventfd_started = true;
> >
> > return 0;
> > fail_vq:
> > while (--i >= 0) {
> > - e = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), hdev->vq_index + i,
> > - false);
> > + e = virtio_bus_set_host_notifier(vbus, hdev->vq_index + i, false);
> > if (e < 0) {
> > error_report("vhost VQ %d notifier cleanup error: %d", i, -r);
> > }
> > @@ -1230,17 +1228,17 @@ fail:
> > void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev)
> > {
> > BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
> > + VirtioBusState *vbus = VIRTIO_BUS(qbus);
> > int i, r;
> >
> > for (i = 0; i < hdev->nvqs; ++i) {
> > - r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), hdev->vq_index + i,
> > - false);
> > + r = virtio_bus_set_host_notifier(vbus, hdev->vq_index + i, false);
> > if (r < 0) {
> > error_report("vhost VQ %d notifier cleanup failed: %d", i, -r);
> > }
> > assert (r >= 0);
> > }
> > - VIRTIO_BUS(qbus)->ioeventfd_started = false;
> > + vbus->ioeventfd_started = false;
> > virtio_device_start_ioeventfd(vdev);
> > }
> >
> >
^ permalink raw reply
* Re: [Qemu-devel] [PATCH v2 1/5] target-tricore: Added FTOUZ instruction
From: Bastian Koppelmann @ 2016-11-09 15:46 UTC (permalink / raw)
To: Richard Henderson, qemu-devel
In-Reply-To: <bc0ac028-75e6-e676-4821-541b0a6dcf0e@twiddle.net>
On 11/08/2016 04:25 PM, Richard Henderson wrote:
> On 11/08/2016 04:12 PM, Bastian Koppelmann wrote:
>> On 11/08/2016 04:06 PM, Richard Henderson wrote:
>>> On 11/08/2016 02:37 PM, Bastian Koppelmann wrote:
>>>> Consider 0x836d4e86 as an input which is clearly negative, however
>>>> float_flag_invalid is not set. The hardware on the other hand does set
>>>> it.
>>>
>>> Hmm. This is -0x1.da9d0cp-121. Softfloat claims that we should round
>>> to zero first, and only if the result is still < 0, raise invalid.
>>> Which does sound plausible as a common behaviour.
>>
>> TriCore does it the other way round.
>>
>>>
>>> Does your hardware raise invalid for true -0.0, i.e. 0x80000000?
>>
>> No, -0.0 does not raise invalid.
>
> Then I suppose the check should look like
>
> flags = f_get_excp_flags(env);
> if (flags & float_flag_invalid) {
> flags &= ~float_flag_inexact;
> } else if (float32_lt_quiet(f_arg, 0, &env->status)) {
> flags = float_flag_invalid;
> }
> if (flags) {
> f_update_psw_flags(env, flags);
> }
>
> Note that the 0.0 that you use is truncated to 0 by C for the uint32_t
> argument.
Not quite -- it does not catch that an input NaN results in 0 as opposed
to -1 returned by softfloat.
But otherwise thanks for the review. This resulted in much nicer code.
Cheers,
Bastian
^ permalink raw reply
* [ANNOUNCE] 4.4.30-rt41
From: Steven Rostedt @ 2016-11-09 15:46 UTC (permalink / raw)
To: LKML, linux-rt-users
Cc: Thomas Gleixner, Carsten Emde, John Kacur,
Sebastian Andrzej Siewior
Dear RT Folks,
I'm pleased to announce the 4.4.30-rt41 stable release.
This release is just an update to the new stable 4.4.30 version
and no RT specific changes have been made.
You can get this release via the git tree at:
git://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-stable-rt.git
branch: v4.4-rt
Head SHA1: 4db7ec2e7bd93dfb285e12537e61af3dc693e866
Or to build 4.4.30-rt41 directly, the following patches should be applied:
http://www.kernel.org/pub/linux/kernel/v4.x/linux-4.4.tar.xz
http://www.kernel.org/pub/linux/kernel/v4.x/patch-4.4.30.xz
http://www.kernel.org/pub/linux/kernel/projects/rt/4.4/patch-4.4.30-rt41.patch.xz
Enjoy,
-- Steve
^ permalink raw reply
* [PATCH] pinctrl: vt8500: make bool drivers explicitly non-modular
From: Paul Gortmaker @ 2016-11-09 15:45 UTC (permalink / raw)
To: linux-kernel; +Cc: Paul Gortmaker, Tony Prisk, Linus Walleij, linux-gpio
None of the Kconfigs for any of these drivers are tristate, meaning
that they currently are not being built as a module by anyone.
Lets remove the modular code that is essentially orphaned, so that
when reading the drivers there is no doubt they are builtin-only. All
drivers get the exact same change, so they are handled in batch.
Changes are (1) use builtin_platform_driver, (2) use init.h header
(3) delete module_exit related code, (4) delete MODULE_DEVICE_TABLE,
(5) delete MODULE_LICENCE/MODULE_AUTHOR and associated tags and (6)
drop ".remove" code and prevent sysfs unbind attempts to call ".remove".
Once this is done, the shared remove function in wmt.[ch] is no longer
used and hence it is removed as well.
Since module_platform_driver() uses the same init level priority as
builtin_platform_driver() the init ordering remains unchanged with
this commit.
Also note that MODULE_DEVICE_TABLE is a no-op for non-modular code.
We also delete the MODULE_LICENSE etc. tags since all that information
is already contained at the top of each file in the comments.
Cc: Tony Prisk <linux@prisktech.co.nz>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: linux-gpio@vger.kernel.org
Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
---
[build tested allmodconfig + all the below C files individually on arm]
drivers/pinctrl/vt8500/pinctrl-vt8500.c | 17 +++--------------
drivers/pinctrl/vt8500/pinctrl-wm8505.c | 17 +++--------------
drivers/pinctrl/vt8500/pinctrl-wm8650.c | 17 +++--------------
drivers/pinctrl/vt8500/pinctrl-wm8750.c | 17 +++--------------
drivers/pinctrl/vt8500/pinctrl-wm8850.c | 17 +++--------------
drivers/pinctrl/vt8500/pinctrl-wmt.c | 10 ----------
drivers/pinctrl/vt8500/pinctrl-wmt.h | 1 -
7 files changed, 15 insertions(+), 81 deletions(-)
diff --git a/drivers/pinctrl/vt8500/pinctrl-vt8500.c b/drivers/pinctrl/vt8500/pinctrl-vt8500.c
index ca946b3dbdb4..767f340d6b11 100644
--- a/drivers/pinctrl/vt8500/pinctrl-vt8500.c
+++ b/drivers/pinctrl/vt8500/pinctrl-vt8500.c
@@ -14,7 +14,7 @@
*/
#include <linux/io.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -473,11 +473,6 @@ static int vt8500_pinctrl_probe(struct platform_device *pdev)
return wmt_pinctrl_probe(pdev, data);
}
-static int vt8500_pinctrl_remove(struct platform_device *pdev)
-{
- return wmt_pinctrl_remove(pdev);
-}
-
static const struct of_device_id wmt_pinctrl_of_match[] = {
{ .compatible = "via,vt8500-pinctrl" },
{ /* sentinel */ },
@@ -485,16 +480,10 @@ static const struct of_device_id wmt_pinctrl_of_match[] = {
static struct platform_driver wmt_pinctrl_driver = {
.probe = vt8500_pinctrl_probe,
- .remove = vt8500_pinctrl_remove,
.driver = {
.name = "pinctrl-vt8500",
.of_match_table = wmt_pinctrl_of_match,
+ .suppress_bind_attrs = true,
},
};
-
-module_platform_driver(wmt_pinctrl_driver);
-
-MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
-MODULE_DESCRIPTION("VIA VT8500 Pincontrol driver");
-MODULE_LICENSE("GPL v2");
-MODULE_DEVICE_TABLE(of, wmt_pinctrl_of_match);
+builtin_platform_driver(wmt_pinctrl_driver);
diff --git a/drivers/pinctrl/vt8500/pinctrl-wm8505.c b/drivers/pinctrl/vt8500/pinctrl-wm8505.c
index 626fc7ec0174..a56fdbd87e42 100644
--- a/drivers/pinctrl/vt8500/pinctrl-wm8505.c
+++ b/drivers/pinctrl/vt8500/pinctrl-wm8505.c
@@ -14,7 +14,7 @@
*/
#include <linux/io.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -504,11 +504,6 @@ static int wm8505_pinctrl_probe(struct platform_device *pdev)
return wmt_pinctrl_probe(pdev, data);
}
-static int wm8505_pinctrl_remove(struct platform_device *pdev)
-{
- return wmt_pinctrl_remove(pdev);
-}
-
static const struct of_device_id wmt_pinctrl_of_match[] = {
{ .compatible = "wm,wm8505-pinctrl" },
{ /* sentinel */ },
@@ -516,16 +511,10 @@ static const struct of_device_id wmt_pinctrl_of_match[] = {
static struct platform_driver wmt_pinctrl_driver = {
.probe = wm8505_pinctrl_probe,
- .remove = wm8505_pinctrl_remove,
.driver = {
.name = "pinctrl-wm8505",
.of_match_table = wmt_pinctrl_of_match,
+ .suppress_bind_attrs = true,
},
};
-
-module_platform_driver(wmt_pinctrl_driver);
-
-MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
-MODULE_DESCRIPTION("Wondermedia WM8505 Pincontrol driver");
-MODULE_LICENSE("GPL v2");
-MODULE_DEVICE_TABLE(of, wmt_pinctrl_of_match);
+builtin_platform_driver(wmt_pinctrl_driver);
diff --git a/drivers/pinctrl/vt8500/pinctrl-wm8650.c b/drivers/pinctrl/vt8500/pinctrl-wm8650.c
index 8953aba8bfc2..270dd491f5a1 100644
--- a/drivers/pinctrl/vt8500/pinctrl-wm8650.c
+++ b/drivers/pinctrl/vt8500/pinctrl-wm8650.c
@@ -14,7 +14,7 @@
*/
#include <linux/io.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -342,11 +342,6 @@ static int wm8650_pinctrl_probe(struct platform_device *pdev)
return wmt_pinctrl_probe(pdev, data);
}
-static int wm8650_pinctrl_remove(struct platform_device *pdev)
-{
- return wmt_pinctrl_remove(pdev);
-}
-
static const struct of_device_id wmt_pinctrl_of_match[] = {
{ .compatible = "wm,wm8650-pinctrl" },
{ /* sentinel */ },
@@ -354,16 +349,10 @@ static const struct of_device_id wmt_pinctrl_of_match[] = {
static struct platform_driver wmt_pinctrl_driver = {
.probe = wm8650_pinctrl_probe,
- .remove = wm8650_pinctrl_remove,
.driver = {
.name = "pinctrl-wm8650",
.of_match_table = wmt_pinctrl_of_match,
+ .suppress_bind_attrs = true,
},
};
-
-module_platform_driver(wmt_pinctrl_driver);
-
-MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
-MODULE_DESCRIPTION("Wondermedia WM8650 Pincontrol driver");
-MODULE_LICENSE("GPL v2");
-MODULE_DEVICE_TABLE(of, wmt_pinctrl_of_match);
+builtin_platform_driver(wmt_pinctrl_driver);
diff --git a/drivers/pinctrl/vt8500/pinctrl-wm8750.c b/drivers/pinctrl/vt8500/pinctrl-wm8750.c
index c79053d430db..74f7b3a18f3a 100644
--- a/drivers/pinctrl/vt8500/pinctrl-wm8750.c
+++ b/drivers/pinctrl/vt8500/pinctrl-wm8750.c
@@ -14,7 +14,7 @@
*/
#include <linux/io.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -381,11 +381,6 @@ static int wm8750_pinctrl_probe(struct platform_device *pdev)
return wmt_pinctrl_probe(pdev, data);
}
-static int wm8750_pinctrl_remove(struct platform_device *pdev)
-{
- return wmt_pinctrl_remove(pdev);
-}
-
static const struct of_device_id wmt_pinctrl_of_match[] = {
{ .compatible = "wm,wm8750-pinctrl" },
{ /* sentinel */ },
@@ -393,16 +388,10 @@ static const struct of_device_id wmt_pinctrl_of_match[] = {
static struct platform_driver wmt_pinctrl_driver = {
.probe = wm8750_pinctrl_probe,
- .remove = wm8750_pinctrl_remove,
.driver = {
.name = "pinctrl-wm8750",
.of_match_table = wmt_pinctrl_of_match,
+ .suppress_bind_attrs = true,
},
};
-
-module_platform_driver(wmt_pinctrl_driver);
-
-MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
-MODULE_DESCRIPTION("Wondermedia WM8750 Pincontrol driver");
-MODULE_LICENSE("GPL v2");
-MODULE_DEVICE_TABLE(of, wmt_pinctrl_of_match);
+builtin_platform_driver(wmt_pinctrl_driver);
diff --git a/drivers/pinctrl/vt8500/pinctrl-wm8850.c b/drivers/pinctrl/vt8500/pinctrl-wm8850.c
index f232b163c735..45792aa7a06e 100644
--- a/drivers/pinctrl/vt8500/pinctrl-wm8850.c
+++ b/drivers/pinctrl/vt8500/pinctrl-wm8850.c
@@ -14,7 +14,7 @@
*/
#include <linux/io.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -360,11 +360,6 @@ static int wm8850_pinctrl_probe(struct platform_device *pdev)
return wmt_pinctrl_probe(pdev, data);
}
-static int wm8850_pinctrl_remove(struct platform_device *pdev)
-{
- return wmt_pinctrl_remove(pdev);
-}
-
static const struct of_device_id wmt_pinctrl_of_match[] = {
{ .compatible = "wm,wm8850-pinctrl" },
{ /* sentinel */ },
@@ -372,16 +367,10 @@ static const struct of_device_id wmt_pinctrl_of_match[] = {
static struct platform_driver wmt_pinctrl_driver = {
.probe = wm8850_pinctrl_probe,
- .remove = wm8850_pinctrl_remove,
.driver = {
.name = "pinctrl-wm8850",
.of_match_table = wmt_pinctrl_of_match,
+ .suppress_bind_attrs = true,
},
};
-
-module_platform_driver(wmt_pinctrl_driver);
-
-MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
-MODULE_DESCRIPTION("Wondermedia WM8850 Pincontrol driver");
-MODULE_LICENSE("GPL v2");
-MODULE_DEVICE_TABLE(of, wmt_pinctrl_of_match);
+builtin_platform_driver(wmt_pinctrl_driver);
diff --git a/drivers/pinctrl/vt8500/pinctrl-wmt.c b/drivers/pinctrl/vt8500/pinctrl-wmt.c
index cbc638631678..270ca2a47a8c 100644
--- a/drivers/pinctrl/vt8500/pinctrl-wmt.c
+++ b/drivers/pinctrl/vt8500/pinctrl-wmt.c
@@ -18,7 +18,6 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
-#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/pinctrl/consumer.h>
@@ -608,12 +607,3 @@ fail_range:
gpiochip_remove(&data->gpio_chip);
return err;
}
-
-int wmt_pinctrl_remove(struct platform_device *pdev)
-{
- struct wmt_pinctrl_data *data = platform_get_drvdata(pdev);
-
- gpiochip_remove(&data->gpio_chip);
-
- return 0;
-}
diff --git a/drivers/pinctrl/vt8500/pinctrl-wmt.h b/drivers/pinctrl/vt8500/pinctrl-wmt.h
index 41f5f2deb5d6..885613396fe7 100644
--- a/drivers/pinctrl/vt8500/pinctrl-wmt.h
+++ b/drivers/pinctrl/vt8500/pinctrl-wmt.h
@@ -76,4 +76,3 @@ struct wmt_pinctrl_data {
int wmt_pinctrl_probe(struct platform_device *pdev,
struct wmt_pinctrl_data *data);
-int wmt_pinctrl_remove(struct platform_device *pdev);
--
2.7.4
^ permalink raw reply related
* [PATCH] pinctrl: vt8500: make bool drivers explicitly non-modular
From: Paul Gortmaker @ 2016-11-09 15:45 UTC (permalink / raw)
To: linux-kernel; +Cc: Paul Gortmaker, Tony Prisk, Linus Walleij, linux-gpio
None of the Kconfigs for any of these drivers are tristate, meaning
that they currently are not being built as a module by anyone.
Lets remove the modular code that is essentially orphaned, so that
when reading the drivers there is no doubt they are builtin-only. All
drivers get the exact same change, so they are handled in batch.
Changes are (1) use builtin_platform_driver, (2) use init.h header
(3) delete module_exit related code, (4) delete MODULE_DEVICE_TABLE,
(5) delete MODULE_LICENCE/MODULE_AUTHOR and associated tags and (6)
drop ".remove" code and prevent sysfs unbind attempts to call ".remove".
Once this is done, the shared remove function in wmt.[ch] is no longer
used and hence it is removed as well.
Since module_platform_driver() uses the same init level priority as
builtin_platform_driver() the init ordering remains unchanged with
this commit.
Also note that MODULE_DEVICE_TABLE is a no-op for non-modular code.
We also delete the MODULE_LICENSE etc. tags since all that information
is already contained at the top of each file in the comments.
Cc: Tony Prisk <linux@prisktech.co.nz>
Cc: Linus Walleij <linus.walleij@linaro.org>
Cc: linux-gpio@vger.kernel.org
Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
---
[build tested allmodconfig + all the below C files individually on arm]
drivers/pinctrl/vt8500/pinctrl-vt8500.c | 17 +++--------------
drivers/pinctrl/vt8500/pinctrl-wm8505.c | 17 +++--------------
drivers/pinctrl/vt8500/pinctrl-wm8650.c | 17 +++--------------
drivers/pinctrl/vt8500/pinctrl-wm8750.c | 17 +++--------------
drivers/pinctrl/vt8500/pinctrl-wm8850.c | 17 +++--------------
drivers/pinctrl/vt8500/pinctrl-wmt.c | 10 ----------
drivers/pinctrl/vt8500/pinctrl-wmt.h | 1 -
7 files changed, 15 insertions(+), 81 deletions(-)
diff --git a/drivers/pinctrl/vt8500/pinctrl-vt8500.c b/drivers/pinctrl/vt8500/pinctrl-vt8500.c
index ca946b3dbdb4..767f340d6b11 100644
--- a/drivers/pinctrl/vt8500/pinctrl-vt8500.c
+++ b/drivers/pinctrl/vt8500/pinctrl-vt8500.c
@@ -14,7 +14,7 @@
*/
#include <linux/io.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -473,11 +473,6 @@ static int vt8500_pinctrl_probe(struct platform_device *pdev)
return wmt_pinctrl_probe(pdev, data);
}
-static int vt8500_pinctrl_remove(struct platform_device *pdev)
-{
- return wmt_pinctrl_remove(pdev);
-}
-
static const struct of_device_id wmt_pinctrl_of_match[] = {
{ .compatible = "via,vt8500-pinctrl" },
{ /* sentinel */ },
@@ -485,16 +480,10 @@ static const struct of_device_id wmt_pinctrl_of_match[] = {
static struct platform_driver wmt_pinctrl_driver = {
.probe = vt8500_pinctrl_probe,
- .remove = vt8500_pinctrl_remove,
.driver = {
.name = "pinctrl-vt8500",
.of_match_table = wmt_pinctrl_of_match,
+ .suppress_bind_attrs = true,
},
};
-
-module_platform_driver(wmt_pinctrl_driver);
-
-MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
-MODULE_DESCRIPTION("VIA VT8500 Pincontrol driver");
-MODULE_LICENSE("GPL v2");
-MODULE_DEVICE_TABLE(of, wmt_pinctrl_of_match);
+builtin_platform_driver(wmt_pinctrl_driver);
diff --git a/drivers/pinctrl/vt8500/pinctrl-wm8505.c b/drivers/pinctrl/vt8500/pinctrl-wm8505.c
index 626fc7ec0174..a56fdbd87e42 100644
--- a/drivers/pinctrl/vt8500/pinctrl-wm8505.c
+++ b/drivers/pinctrl/vt8500/pinctrl-wm8505.c
@@ -14,7 +14,7 @@
*/
#include <linux/io.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -504,11 +504,6 @@ static int wm8505_pinctrl_probe(struct platform_device *pdev)
return wmt_pinctrl_probe(pdev, data);
}
-static int wm8505_pinctrl_remove(struct platform_device *pdev)
-{
- return wmt_pinctrl_remove(pdev);
-}
-
static const struct of_device_id wmt_pinctrl_of_match[] = {
{ .compatible = "wm,wm8505-pinctrl" },
{ /* sentinel */ },
@@ -516,16 +511,10 @@ static const struct of_device_id wmt_pinctrl_of_match[] = {
static struct platform_driver wmt_pinctrl_driver = {
.probe = wm8505_pinctrl_probe,
- .remove = wm8505_pinctrl_remove,
.driver = {
.name = "pinctrl-wm8505",
.of_match_table = wmt_pinctrl_of_match,
+ .suppress_bind_attrs = true,
},
};
-
-module_platform_driver(wmt_pinctrl_driver);
-
-MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
-MODULE_DESCRIPTION("Wondermedia WM8505 Pincontrol driver");
-MODULE_LICENSE("GPL v2");
-MODULE_DEVICE_TABLE(of, wmt_pinctrl_of_match);
+builtin_platform_driver(wmt_pinctrl_driver);
diff --git a/drivers/pinctrl/vt8500/pinctrl-wm8650.c b/drivers/pinctrl/vt8500/pinctrl-wm8650.c
index 8953aba8bfc2..270dd491f5a1 100644
--- a/drivers/pinctrl/vt8500/pinctrl-wm8650.c
+++ b/drivers/pinctrl/vt8500/pinctrl-wm8650.c
@@ -14,7 +14,7 @@
*/
#include <linux/io.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -342,11 +342,6 @@ static int wm8650_pinctrl_probe(struct platform_device *pdev)
return wmt_pinctrl_probe(pdev, data);
}
-static int wm8650_pinctrl_remove(struct platform_device *pdev)
-{
- return wmt_pinctrl_remove(pdev);
-}
-
static const struct of_device_id wmt_pinctrl_of_match[] = {
{ .compatible = "wm,wm8650-pinctrl" },
{ /* sentinel */ },
@@ -354,16 +349,10 @@ static const struct of_device_id wmt_pinctrl_of_match[] = {
static struct platform_driver wmt_pinctrl_driver = {
.probe = wm8650_pinctrl_probe,
- .remove = wm8650_pinctrl_remove,
.driver = {
.name = "pinctrl-wm8650",
.of_match_table = wmt_pinctrl_of_match,
+ .suppress_bind_attrs = true,
},
};
-
-module_platform_driver(wmt_pinctrl_driver);
-
-MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
-MODULE_DESCRIPTION("Wondermedia WM8650 Pincontrol driver");
-MODULE_LICENSE("GPL v2");
-MODULE_DEVICE_TABLE(of, wmt_pinctrl_of_match);
+builtin_platform_driver(wmt_pinctrl_driver);
diff --git a/drivers/pinctrl/vt8500/pinctrl-wm8750.c b/drivers/pinctrl/vt8500/pinctrl-wm8750.c
index c79053d430db..74f7b3a18f3a 100644
--- a/drivers/pinctrl/vt8500/pinctrl-wm8750.c
+++ b/drivers/pinctrl/vt8500/pinctrl-wm8750.c
@@ -14,7 +14,7 @@
*/
#include <linux/io.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -381,11 +381,6 @@ static int wm8750_pinctrl_probe(struct platform_device *pdev)
return wmt_pinctrl_probe(pdev, data);
}
-static int wm8750_pinctrl_remove(struct platform_device *pdev)
-{
- return wmt_pinctrl_remove(pdev);
-}
-
static const struct of_device_id wmt_pinctrl_of_match[] = {
{ .compatible = "wm,wm8750-pinctrl" },
{ /* sentinel */ },
@@ -393,16 +388,10 @@ static const struct of_device_id wmt_pinctrl_of_match[] = {
static struct platform_driver wmt_pinctrl_driver = {
.probe = wm8750_pinctrl_probe,
- .remove = wm8750_pinctrl_remove,
.driver = {
.name = "pinctrl-wm8750",
.of_match_table = wmt_pinctrl_of_match,
+ .suppress_bind_attrs = true,
},
};
-
-module_platform_driver(wmt_pinctrl_driver);
-
-MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
-MODULE_DESCRIPTION("Wondermedia WM8750 Pincontrol driver");
-MODULE_LICENSE("GPL v2");
-MODULE_DEVICE_TABLE(of, wmt_pinctrl_of_match);
+builtin_platform_driver(wmt_pinctrl_driver);
diff --git a/drivers/pinctrl/vt8500/pinctrl-wm8850.c b/drivers/pinctrl/vt8500/pinctrl-wm8850.c
index f232b163c735..45792aa7a06e 100644
--- a/drivers/pinctrl/vt8500/pinctrl-wm8850.c
+++ b/drivers/pinctrl/vt8500/pinctrl-wm8850.c
@@ -14,7 +14,7 @@
*/
#include <linux/io.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -360,11 +360,6 @@ static int wm8850_pinctrl_probe(struct platform_device *pdev)
return wmt_pinctrl_probe(pdev, data);
}
-static int wm8850_pinctrl_remove(struct platform_device *pdev)
-{
- return wmt_pinctrl_remove(pdev);
-}
-
static const struct of_device_id wmt_pinctrl_of_match[] = {
{ .compatible = "wm,wm8850-pinctrl" },
{ /* sentinel */ },
@@ -372,16 +367,10 @@ static const struct of_device_id wmt_pinctrl_of_match[] = {
static struct platform_driver wmt_pinctrl_driver = {
.probe = wm8850_pinctrl_probe,
- .remove = wm8850_pinctrl_remove,
.driver = {
.name = "pinctrl-wm8850",
.of_match_table = wmt_pinctrl_of_match,
+ .suppress_bind_attrs = true,
},
};
-
-module_platform_driver(wmt_pinctrl_driver);
-
-MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
-MODULE_DESCRIPTION("Wondermedia WM8850 Pincontrol driver");
-MODULE_LICENSE("GPL v2");
-MODULE_DEVICE_TABLE(of, wmt_pinctrl_of_match);
+builtin_platform_driver(wmt_pinctrl_driver);
diff --git a/drivers/pinctrl/vt8500/pinctrl-wmt.c b/drivers/pinctrl/vt8500/pinctrl-wmt.c
index cbc638631678..270ca2a47a8c 100644
--- a/drivers/pinctrl/vt8500/pinctrl-wmt.c
+++ b/drivers/pinctrl/vt8500/pinctrl-wmt.c
@@ -18,7 +18,6 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
-#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/pinctrl/consumer.h>
@@ -608,12 +607,3 @@ fail_range:
gpiochip_remove(&data->gpio_chip);
return err;
}
-
-int wmt_pinctrl_remove(struct platform_device *pdev)
-{
- struct wmt_pinctrl_data *data = platform_get_drvdata(pdev);
-
- gpiochip_remove(&data->gpio_chip);
-
- return 0;
-}
diff --git a/drivers/pinctrl/vt8500/pinctrl-wmt.h b/drivers/pinctrl/vt8500/pinctrl-wmt.h
index 41f5f2deb5d6..885613396fe7 100644
--- a/drivers/pinctrl/vt8500/pinctrl-wmt.h
+++ b/drivers/pinctrl/vt8500/pinctrl-wmt.h
@@ -76,4 +76,3 @@ struct wmt_pinctrl_data {
int wmt_pinctrl_probe(struct platform_device *pdev,
struct wmt_pinctrl_data *data);
-int wmt_pinctrl_remove(struct platform_device *pdev);
--
2.7.4
^ permalink raw reply related
* Re: stable-rc build: 72 warnings 1 failures (stable-rc/v4.4.30-35-gf821e08)
From: Arnd Bergmann @ 2016-11-09 15:44 UTC (permalink / raw)
To: Eric W. Biederman
Cc: kernel-build-reports, Olof's autobuilder, olof, stable,
Greg KH
In-Reply-To: <87pom5qy4e.fsf@xmission.com>
On Tuesday, November 8, 2016 6:45:53 PM CET Eric W. Biederman wrote:
> Arnd Bergmann <arnd@arndb.de> writes:
> > On Tuesday, November 8, 2016 9:16:28 AM CET Olof's autobuilder wrote:
> >> Here are the build results from automated periodic testing.
> > I think this was accidentally fixed by eedf265aa003 ("devpts: Make each mount of
> > devpts an independent filesystem."), which unfortunately is not a
> > candidate for stable
>
> Well eedf265aa003 ("devpts: Make each mount of devpts an independent
> filesystem.") does contain a somewhat serious bug fix, and it was tested
> to ensure it works everywhere so that might possibly be a canidate for
> stable.
>
> Certainly that is a change I would aim at vendor trees that care about
> containers.
>
> >> 1 net/netfilter/xt_owner.c:27:23: warning: self-comparison always evaluates to false [-Wtautological-compare]
> >
> > Apparently also fixed as a side-effect of a larger patch:
> >
> > 9847371a84b0 ("netfilter: Allow xt_owner in any user namespace")
> >
> > This one might be appropriate for a stable backport, Eric Biederman
> > would know for sure.
>
> Well it is a feature patch. This sounds like an error message that is
> only generated when user namespace support is disabled. And we are
> making it go away by making the code more expensive.
Ah, so both of these were exactly the opposite of what I expected ;-)
> I am not a great fan of that warning being on by default, as it seems to
> encourage more expensive code to be generated by macros. Has that
> warning caught any real bugs yet?
I fixed up all instanced I could find on ARM, see "git log --oneline
--grep=tautological". I'd categorize three of them as bugs:
0a938697d7fb drm/exynos: fix error handling in exynos_drm_subdrv_open
0fb504001192 [media] am437x-vfpe: fix typo in vpfe_get_app_input_index
86d65b7e7a0c nouveau: fix nv40_perfctr_next() cleanup regression
and four others as false-positive:
dd665be0e243 ARM: 8584/1: floppy: avoid gcc-6 warning
f419a08fb329 drivers/memstick/host/r592.c: avoid gcc-6 warning
e3ebd894f084 smc91x: avoid self-comparison warning
0335695dfa4d cred/userns: define current_user_ns() as a function
which is not a bad ratio at all. The last of those is probably
sufficient to address most of the gcc-6 warnings on stable-4.4.
I also did a patch to shut up four more warnings on x86, but never
got around to submitting them properly. These are all false-positive,
see patch below (I folded this into one).
Arnd
commit 28624e5166a2d33c386b6d5b7f627d84939cabce
Author: Arnd Bergmann <arnd@arndb.de>
Date: Fri Oct 7 14:15:06 2016 +0200
x86: treewide: hide -Wtautological-compare warnings
proc/kcore: hide a harmless warning
fs/proc/kcore.c: In function ‘add_modules_range’:
fs/proc/kcore.c:622:161: error: self-comparison always evaluates to false [-Werror=tautological-compare]
if (/*MODULES_VADDR != VMALLOC_START && */MODULES_END != VMALLOC_END) {
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
acpi: thermal: fix gcc-6/ccache warning
drivers/acpi/processor_thermal.c: In function ‘cpufreq_set_cur_state’:
drivers/acpi/processor_thermal.c:137:36: error: self-comparison always evaluates to true [-Werror=tautological-compare]
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
x86: microcode/amd: avoid ccache/gcc-6 warning
/git/arm-soc/arch/x86/kernel/cpu/microcode/amd.c: In function ‘load_microcode_amd’:
/git/arm-soc/arch/x86/kernel/cpu/microcode/amd.c:878:30: error: self-comparison always evaluates to true [-Werror=tautological-compare]
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
sfi: avoid ccache warning
With ccache in combination with gcc-6, we get a harmless warning for the sfi subsystem,
as ccache only sees the preprocessed source:
drivers/sfi/sfi_core.c: In function ‘sfi_map_table’:
drivers/sfi/sfi_core.c:175:53: error: self-comparison always evaluates to true [-Werror=tautological-compare]
Using an inline function to do the comparison tells the compiler what is
going on even for preprocessed files, and avoids the warning.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c
index 6f353bdb3a25..64a457da4a4c 100644
--- a/arch/x86/kernel/cpu/microcode/amd.c
+++ b/arch/x86/kernel/cpu/microcode/amd.c
@@ -854,6 +854,7 @@ static enum ucode_state
load_microcode_amd(int cpu, u8 family, const u8 *data, size_t size)
{
enum ucode_state ret;
+ int bootcpu = boot_cpu_data.cpu_index;
/* free old equiv table */
free_equiv_cpu_table();
@@ -865,7 +866,7 @@ load_microcode_amd(int cpu, u8 family, const u8 *data, size_t size)
#ifdef CONFIG_X86_32
/* save BSP's matching patch for early load */
- if (cpu_data(cpu).cpu_index == boot_cpu_data.cpu_index) {
+ if (cpu_data(cpu).cpu_index == bootcpu) {
struct ucode_patch *p = find_patch(cpu);
if (p) {
memset(amd_ucode_patch, 0, PATCH_MAX_SIZE);
diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c
index 1fed84a092c2..8cde6715537b 100644
--- a/drivers/acpi/processor_thermal.c
+++ b/drivers/acpi/processor_thermal.c
@@ -122,20 +122,22 @@ static int cpufreq_get_cur_state(unsigned int cpu)
static int cpufreq_set_cur_state(unsigned int cpu, int state)
{
int i;
+ int id;
if (!cpu_has_cpufreq(cpu))
return 0;
reduction_pctg(cpu) = state;
+ id = topology_physical_package_id(cpu);
+
/*
* Update all the CPUs in the same package because they all
* contribute to the temperature and often share the same
* frequency.
*/
for_each_online_cpu(i) {
- if (topology_physical_package_id(i) ==
- topology_physical_package_id(cpu))
+ if (topology_physical_package_id(i) == id)
cpufreq_update_policy(i);
}
return 0;
diff --git a/drivers/sfi/sfi_core.c b/drivers/sfi/sfi_core.c
index 296db7a69c27..a8f2313a2613 100644
--- a/drivers/sfi/sfi_core.c
+++ b/drivers/sfi/sfi_core.c
@@ -71,9 +71,12 @@
#include "sfi_core.h"
-#define ON_SAME_PAGE(addr1, addr2) \
- (((unsigned long)(addr1) & PAGE_MASK) == \
- ((unsigned long)(addr2) & PAGE_MASK))
+static inline bool on_same_page(unsigned long addr1, unsigned long addr2)
+{
+ return (addr1 & PAGE_MASK) == (addr2 & PAGE_MASK);
+}
+
+#define ON_SAME_PAGE(addr1, addr2) on_same_page((unsigned long)addr1, (unsigned long)addr2)
#define TABLE_ON_PAGE(page, table, size) (ON_SAME_PAGE(page, table) && \
ON_SAME_PAGE(page, table + size))
diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c
index 5c89a07e3d7f..8ca8de0d13eb 100644
--- a/fs/proc/kcore.c
+++ b/fs/proc/kcore.c
@@ -616,12 +616,14 @@ static void __init proc_kcore_text_init(void)
/*
* MODULES_VADDR has no intersection with VMALLOC_ADDR.
*/
-struct kcore_list kcore_modules;
+static struct kcore_list kcore_modules;
static void __init add_modules_range(void)
{
- if (MODULES_VADDR != VMALLOC_START && MODULES_END != VMALLOC_END) {
- kclist_add(&kcore_modules, (void *)MODULES_VADDR,
- MODULES_END - MODULES_VADDR, KCORE_VMALLOC);
+ void *start = (void *)MODULES_VADDR;
+ size_t len = MODULES_END - MODULES_VADDR;
+
+ if (start != (void *)VMALLOC_START && len != VMALLOC_END - VMALLOC_START) {
+ kclist_add(&kcore_modules, start, len, KCORE_VMALLOC);
}
}
#else
^ permalink raw reply related
* Re: [PATCH] hpsa: switch to pci_alloc_irq_vectors
From: Hannes Reinecke @ 2016-11-09 15:45 UTC (permalink / raw)
To: Christoph Hellwig, Don Brace
Cc: Martin K. Petersen, James Bottomley, linux-scsi@vger.kernel.org,
Hannes Reinecke
In-Reply-To: <20161109153628.GA23452@lst.de>
On 11/09/2016 04:36 PM, Christoph Hellwig wrote:
> On Wed, Nov 09, 2016 at 03:32:48PM +0000, Don Brace wrote:
>> Do we need to add an entry for map_queues?
>
> The existing driver only supports a single submission queue.
> If some of the devices support more than one submission queue
> we could enhance the driver to support it, but we'd need docs
> and hardware.
>
Hardware is not an issue :-)
However, I'm still curious about the layout of the queues.
Are all queues (in performant mode) identical and can we use them for
parallel submission? Or do we have to treat them differently?
(There were some rumours that it actually uses the queues for different
I/O sizes ...)
Once that is cleared up it shouldn't be too hard moving to full
multiqueue support.
(If we have identical queues, that is :-)
Cheers,
Hannes
--
Dr. Hannes Reinecke Teamlead Storage & Networking
hare@suse.de +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)
^ permalink raw reply
* [PATCH 4/5] doc_rst: media: New SDR formats SC16, SC18 & SC20
From: Ramesh Shanmugasundaram @ 2016-11-09 15:44 UTC (permalink / raw)
To: robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
mchehab-DgEjT+Ai2ygdnm+yROfE0A, hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
sakari.ailus-VuQAYsv1563Yd54FQh9/CA, crope-X3B1VOXEql0
Cc: chris.paterson2-zM6kxYcvzFBBDgjK7y7TUQ,
laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw,
geert+renesas-gXvu3+zWzMSzQB+pC5nmwQ,
linux-media-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-renesas-soc-u79uwXL29TY76Z2rM5mHXA, Ramesh Shanmugasundaram
In-Reply-To: <1478706284-59134-1-git-send-email-ramesh.shanmugasundaram-kTT6dE0pTRh9uiUsa/gSgQ@public.gmane.org>
This patch adds documentation for the three new SDR formats
V4L2_SDR_FMT_SCU16BE
V4L2_SDR_FMT_SCU18BE
V4L2_SDR_FMT_SCU20BE
Signed-off-by: Ramesh Shanmugasundaram <ramesh.shanmugasundaram-kTT6dE0pTRh9uiUsa/gSgQ@public.gmane.org>
---
.../media/uapi/v4l/pixfmt-sdr-scu16be.rst | 80 ++++++++++++++++++++++
.../media/uapi/v4l/pixfmt-sdr-scu18be.rst | 80 ++++++++++++++++++++++
.../media/uapi/v4l/pixfmt-sdr-scu20be.rst | 80 ++++++++++++++++++++++
Documentation/media/uapi/v4l/sdr-formats.rst | 3 +
4 files changed, 243 insertions(+)
create mode 100644 Documentation/media/uapi/v4l/pixfmt-sdr-scu16be.rst
create mode 100644 Documentation/media/uapi/v4l/pixfmt-sdr-scu18be.rst
create mode 100644 Documentation/media/uapi/v4l/pixfmt-sdr-scu20be.rst
diff --git a/Documentation/media/uapi/v4l/pixfmt-sdr-scu16be.rst b/Documentation/media/uapi/v4l/pixfmt-sdr-scu16be.rst
new file mode 100644
index 0000000..7525378
--- /dev/null
+++ b/Documentation/media/uapi/v4l/pixfmt-sdr-scu16be.rst
@@ -0,0 +1,80 @@
+.. -*- coding: utf-8; mode: rst -*-
+
+.. _V4L2-SDR-FMT-SCU16BE:
+
+******************************
+V4L2_SDR_FMT_SCU16BE ('SC16')
+******************************
+
+Sliced complex unsigned 16-bit big endian IQ sample
+
+Description
+===========
+
+This format contains a sequence of complex number samples. Each complex
+number consist of two parts called In-phase and Quadrature (IQ). Both I
+and Q are represented as a 16 bit unsigned big endian number stored in
+32 bit space. The remaining unused bits within the 32 bit space will be
+padded with 0. I value starts first and Q value starts at an offset
+equalling half of the buffer size (i.e.) offset = buffersize/2. Out of
+the 16 bits, bit 15:2 (14 bit) is data and bit 1:0 (2 bit) can be any
+value.
+
+**Byte Order.**
+Each cell is one byte.
+
+.. flat-table::
+ :header-rows: 1
+ :stub-columns: 0
+
+ * - Offset:
+
+ - Byte B0
+
+ - Byte B1
+
+ - Byte B2
+
+ - Byte B3
+
+ * - start + 0:
+
+ - I'\ :sub:`0[13:6]`
+
+ - I'\ :sub:`0[5:0]; B1[1:0]=pad`
+
+ - pad
+
+ - pad
+
+ * - start + 4:
+
+ - I'\ :sub:`1[13:6]`
+
+ - I'\ :sub:`1[5:0]; B1[1:0]=pad`
+
+ - pad
+
+ - pad
+
+ * - ...
+
+ * - start + offset:
+
+ - Q'\ :sub:`0[13:6]`
+
+ - Q'\ :sub:`0[5:0]; B1[1:0]=pad`
+
+ - pad
+
+ - pad
+
+ * - start + offset + 4:
+
+ - Q'\ :sub:`1[13:6]`
+
+ - Q'\ :sub:`1[5:0]; B1[1:0]=pad`
+
+ - pad
+
+ - pad
diff --git a/Documentation/media/uapi/v4l/pixfmt-sdr-scu18be.rst b/Documentation/media/uapi/v4l/pixfmt-sdr-scu18be.rst
new file mode 100644
index 0000000..0ce714d
--- /dev/null
+++ b/Documentation/media/uapi/v4l/pixfmt-sdr-scu18be.rst
@@ -0,0 +1,80 @@
+.. -*- coding: utf-8; mode: rst -*-
+
+.. _V4L2-SDR-FMT-SCU18BE:
+
+******************************
+V4L2_SDR_FMT_SCU18BE ('SC18')
+******************************
+
+Sliced complex unsigned 18-bit big endian IQ sample
+
+Description
+===========
+
+This format contains a sequence of complex number samples. Each complex
+number consist of two parts called In-phase and Quadrature (IQ). Both I
+and Q are represented as a 18 bit unsigned big endian number stored in
+32 bit space. The remaining unused bits within the 32 bit space will be
+padded with 0. I value starts first and Q value starts at an offset
+equalling half of the buffer size (i.e.) offset = buffersize/2. Out of
+the 18 bits, bit 17:2 (16 bit) is data and bit 1:0 (2 bit) can be any
+value.
+
+**Byte Order.**
+Each cell is one byte.
+
+.. flat-table::
+ :header-rows: 1
+ :stub-columns: 0
+
+ * - Offset:
+
+ - Byte B0
+
+ - Byte B1
+
+ - Byte B2
+
+ - Byte B3
+
+ * - start + 0:
+
+ - I'\ :sub:`0[17:10]`
+
+ - I'\ :sub:`0[9:2]`
+
+ - I'\ :sub:`0[1:0]; B2[5:0]=pad`
+
+ - pad
+
+ * - start + 4:
+
+ - I'\ :sub:`1[17:10]`
+
+ - I'\ :sub:`1[9:2]`
+
+ - I'\ :sub:`1[1:0]; B2[5:0]=pad`
+
+ - pad
+
+ * - ...
+
+ * - start + offset:
+
+ - Q'\ :sub:`0[17:10]`
+
+ - Q'\ :sub:`0[9:2]`
+
+ - Q'\ :sub:`0[1:0]; B2[5:0]=pad`
+
+ - pad
+
+ * - start + offset + 4:
+
+ - Q'\ :sub:`1[17:10]`
+
+ - Q'\ :sub:`1[9:2]`
+
+ - Q'\ :sub:`1[1:0]; B2[5:0]=pad`
+
+ - pad
diff --git a/Documentation/media/uapi/v4l/pixfmt-sdr-scu20be.rst b/Documentation/media/uapi/v4l/pixfmt-sdr-scu20be.rst
new file mode 100644
index 0000000..ff2fe51
--- /dev/null
+++ b/Documentation/media/uapi/v4l/pixfmt-sdr-scu20be.rst
@@ -0,0 +1,80 @@
+.. -*- coding: utf-8; mode: rst -*-
+
+.. _V4L2-SDR-FMT-SCU20BE:
+
+******************************
+V4L2_SDR_FMT_SCU20BE ('SC20')
+******************************
+
+Sliced complex unsigned 20-bit big endian IQ sample
+
+Description
+===========
+
+This format contains a sequence of complex number samples. Each complex
+number consist of two parts called In-phase and Quadrature (IQ). Both I
+and Q are represented as a 20 bit unsigned big endian number stored in
+32 bit space. The remaining unused bits within the 32 bit space will be
+padded with 0. I value starts first and Q value starts at an offset
+equalling half of the buffer size (i.e.) offset = buffersize/2. Out of
+the 20 bits, bit 19:2 (18 bit) is data and bit 1:0 (2 bit) can be any
+value.
+
+**Byte Order.**
+Each cell is one byte.
+
+.. flat-table::
+ :header-rows: 1
+ :stub-columns: 0
+
+ * - Offset:
+
+ - Byte B0
+
+ - Byte B1
+
+ - Byte B2
+
+ - Byte B3
+
+ * - start + 0:
+
+ - I'\ :sub:`0[19:12]`
+
+ - I'\ :sub:`0[11:4]`
+
+ - I'\ :sub:`0[3:0]; B2[3:0]=pad`
+
+ - pad
+
+ * - start + 4:
+
+ - I'\ :sub:`1[19:12]`
+
+ - I'\ :sub:`1[11:4]`
+
+ - I'\ :sub:`1[3:0]; B2[3:0]=pad`
+
+ - pad
+
+ * - ...
+
+ * - start + offset:
+
+ - Q'\ :sub:`0[19:12]`
+
+ - Q'\ :sub:`0[11:4]`
+
+ - Q'\ :sub:`0[3:0]; B2[3:0]=pad`
+
+ - pad
+
+ * - start + offset + 4:
+
+ - Q'\ :sub:`1[19:12]`
+
+ - Q'\ :sub:`1[11:4]`
+
+ - Q'\ :sub:`1[3:0]; B2[3:0]=pad`
+
+ - pad
diff --git a/Documentation/media/uapi/v4l/sdr-formats.rst b/Documentation/media/uapi/v4l/sdr-formats.rst
index f863c08..4c01cf9 100644
--- a/Documentation/media/uapi/v4l/sdr-formats.rst
+++ b/Documentation/media/uapi/v4l/sdr-formats.rst
@@ -17,3 +17,6 @@ These formats are used for :ref:`SDR <sdr>` interface only.
pixfmt-sdr-cs08
pixfmt-sdr-cs14le
pixfmt-sdr-ru12le
+ pixfmt-sdr-scu16be
+ pixfmt-sdr-scu18be
+ pixfmt-sdr-scu20be
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.