diff options
Diffstat (limited to 'drivers')
315 files changed, 21677 insertions, 7448 deletions
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig index 6b331061d34b..97ab5ad171d4 100644 --- a/drivers/bus/Kconfig +++ b/drivers/bus/Kconfig @@ -150,6 +150,15 @@ config TEGRA_GMI Driver for the Tegra Generic Memory Interface bus which can be used to attach devices such as NOR, UART, FPGA and more. +config TI_PWMSS + bool + default y if (ARCH_OMAP2PLUS) && (PWM_TIECAP || PWM_TIEHRPWM || TI_EQEP) + help + PWM Subsystem driver support for AM33xx SOC. + + PWM submodules require PWM config space access from submodule + drivers and require common parent driver support. + config TI_SYSC bool "TI sysc interconnect target module driver" depends on ARCH_OMAP2PLUS diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index 16b43d3468c6..1320bcf9fa9d 100644 --- a/drivers/bus/Makefile +++ b/drivers/bus/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_SUNXI_RSB) += sunxi-rsb.o obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o obj-$(CONFIG_TEGRA_ACONNECT) += tegra-aconnect.o obj-$(CONFIG_TEGRA_GMI) += tegra-gmi.o +obj-$(CONFIG_TI_PWMSS) += ti-pwmss.o obj-$(CONFIG_TI_SYSC) += ti-sysc.o obj-$(CONFIG_TS_NBUS) += ts-nbus.o obj-$(CONFIG_UNIPHIER_SYSTEM_BUS) += uniphier-system-bus.o diff --git a/drivers/pwm/pwm-tipwmss.c b/drivers/bus/ti-pwmss.c index e9c26c94251b..e9c26c94251b 100644 --- a/drivers/pwm/pwm-tipwmss.c +++ b/drivers/bus/ti-pwmss.c diff --git a/drivers/counter/104-quad-8.c b/drivers/counter/104-quad-8.c index 00b113f4b958..17e67a84777d 100644 --- a/drivers/counter/104-quad-8.c +++ b/drivers/counter/104-quad-8.c @@ -562,11 +562,10 @@ static const struct iio_chan_spec quad8_channels[] = { }; static int quad8_signal_read(struct counter_device *counter, - struct counter_signal *signal, struct counter_signal_read_value *val) + struct counter_signal *signal, enum counter_signal_value *val) { const struct quad8_iio *const priv = counter->priv; unsigned int state; - enum counter_signal_level level; /* Only Index signal levels can be read */ if (signal->id < 16) @@ -575,22 +574,19 @@ static int quad8_signal_read(struct counter_device *counter, state = inb(priv->base + QUAD8_REG_INDEX_INPUT_LEVELS) & BIT(signal->id - 16); - level = (state) ? COUNTER_SIGNAL_LEVEL_HIGH : COUNTER_SIGNAL_LEVEL_LOW; - - counter_signal_read_value_set(val, COUNTER_SIGNAL_LEVEL, &level); + *val = (state) ? COUNTER_SIGNAL_HIGH : COUNTER_SIGNAL_LOW; return 0; } static int quad8_count_read(struct counter_device *counter, - struct counter_count *count, struct counter_count_read_value *val) + struct counter_count *count, unsigned long *val) { const struct quad8_iio *const priv = counter->priv; const int base_offset = priv->base + 2 * count->id; unsigned int flags; unsigned int borrow; unsigned int carry; - unsigned long position; int i; flags = inb(base_offset + 1); @@ -598,36 +594,27 @@ static int quad8_count_read(struct counter_device *counter, carry = !!(flags & QUAD8_FLAG_CT); /* Borrow XOR Carry effectively doubles count range */ - position = (unsigned long)(borrow ^ carry) << 24; + *val = (unsigned long)(borrow ^ carry) << 24; /* Reset Byte Pointer; transfer Counter to Output Latch */ outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_CNTR_OUT, base_offset + 1); for (i = 0; i < 3; i++) - position |= (unsigned long)inb(base_offset) << (8 * i); - - counter_count_read_value_set(val, COUNTER_COUNT_POSITION, &position); + *val |= (unsigned long)inb(base_offset) << (8 * i); return 0; } static int quad8_count_write(struct counter_device *counter, - struct counter_count *count, struct counter_count_write_value *val) + struct counter_count *count, unsigned long val) { const struct quad8_iio *const priv = counter->priv; const int base_offset = priv->base + 2 * count->id; - int err; - unsigned long position; int i; - err = counter_count_write_value_get(&position, COUNTER_COUNT_POSITION, - val); - if (err) - return err; - /* Only 24-bit values are supported */ - if (position > 0xFFFFFF) + if (val > 0xFFFFFF) return -EINVAL; /* Reset Byte Pointer */ @@ -635,7 +622,7 @@ static int quad8_count_write(struct counter_device *counter, /* Counter can only be set via Preset Register */ for (i = 0; i < 3; i++) - outb(position >> (8 * i), base_offset); + outb(val >> (8 * i), base_offset); /* Transfer Preset Register to Counter */ outb(QUAD8_CTR_RLD | QUAD8_RLD_PRESET_CNTR, base_offset + 1); @@ -644,9 +631,9 @@ static int quad8_count_write(struct counter_device *counter, outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP, base_offset + 1); /* Set Preset Register back to original value */ - position = priv->preset[count->id]; + val = priv->preset[count->id]; for (i = 0; i < 3; i++) - outb(position >> (8 * i), base_offset); + outb(val >> (8 * i), base_offset); /* Reset Borrow, Carry, Compare, and Sign flags */ outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_FLAGS, base_offset + 1); diff --git a/drivers/counter/Kconfig b/drivers/counter/Kconfig index 2967d0a9ff91..c80fa76bb531 100644 --- a/drivers/counter/Kconfig +++ b/drivers/counter/Kconfig @@ -49,6 +49,17 @@ config STM32_LPTIMER_CNT To compile this driver as a module, choose M here: the module will be called stm32-lptimer-cnt. +config TI_EQEP + tristate "TI eQEP counter driver" + depends on (SOC_AM33XX || COMPILE_TEST) + select REGMAP_MMIO + help + Select this option to enable the Texas Instruments Enhanced Quadrature + Encoder Pulse (eQEP) counter driver. + + To compile this driver as a module, choose M here: the module will be + called ti-eqep. + config FTM_QUADDEC tristate "Flex Timer Module Quadrature decoder driver" depends on HAS_IOMEM && OF diff --git a/drivers/counter/Makefile b/drivers/counter/Makefile index 40d35522937d..55142d1f4c43 100644 --- a/drivers/counter/Makefile +++ b/drivers/counter/Makefile @@ -8,4 +8,5 @@ obj-$(CONFIG_COUNTER) += counter.o obj-$(CONFIG_104_QUAD_8) += 104-quad-8.o obj-$(CONFIG_STM32_TIMER_CNT) += stm32-timer-cnt.o obj-$(CONFIG_STM32_LPTIMER_CNT) += stm32-lptimer-cnt.o +obj-$(CONFIG_TI_EQEP) += ti-eqep.o obj-$(CONFIG_FTM_QUADDEC) += ftm-quaddec.o diff --git a/drivers/counter/counter.c b/drivers/counter/counter.c index 106bc7180cd8..6a683d086008 100644 --- a/drivers/counter/counter.c +++ b/drivers/counter/counter.c @@ -220,86 +220,6 @@ ssize_t counter_device_enum_available_read(struct counter_device *counter, } EXPORT_SYMBOL_GPL(counter_device_enum_available_read); -static const char *const counter_signal_level_str[] = { - [COUNTER_SIGNAL_LEVEL_LOW] = "low", - [COUNTER_SIGNAL_LEVEL_HIGH] = "high" -}; - -/** - * counter_signal_read_value_set - set counter_signal_read_value data - * @val: counter_signal_read_value structure to set - * @type: property Signal data represents - * @data: Signal data - * - * This function sets an opaque counter_signal_read_value structure with the - * provided Signal data. - */ -void counter_signal_read_value_set(struct counter_signal_read_value *const val, - const enum counter_signal_value_type type, - void *const data) -{ - if (type == COUNTER_SIGNAL_LEVEL) - val->len = sprintf(val->buf, "%s\n", - counter_signal_level_str[*(enum counter_signal_level *)data]); - else - val->len = 0; -} -EXPORT_SYMBOL_GPL(counter_signal_read_value_set); - -/** - * counter_count_read_value_set - set counter_count_read_value data - * @val: counter_count_read_value structure to set - * @type: property Count data represents - * @data: Count data - * - * This function sets an opaque counter_count_read_value structure with the - * provided Count data. - */ -void counter_count_read_value_set(struct counter_count_read_value *const val, - const enum counter_count_value_type type, - void *const data) -{ - switch (type) { - case COUNTER_COUNT_POSITION: - val->len = sprintf(val->buf, "%lu\n", *(unsigned long *)data); - break; - default: - val->len = 0; - } -} -EXPORT_SYMBOL_GPL(counter_count_read_value_set); - -/** - * counter_count_write_value_get - get counter_count_write_value data - * @data: Count data - * @type: property Count data represents - * @val: counter_count_write_value structure containing data - * - * This function extracts Count data from the provided opaque - * counter_count_write_value structure and stores it at the address provided by - * @data. - * - * RETURNS: - * 0 on success, negative error number on failure. - */ -int counter_count_write_value_get(void *const data, - const enum counter_count_value_type type, - const struct counter_count_write_value *const val) -{ - int err; - - switch (type) { - case COUNTER_COUNT_POSITION: - err = kstrtoul(val->buf, 0, data); - if (err) - return err; - break; - } - - return 0; -} -EXPORT_SYMBOL_GPL(counter_count_write_value_get); - struct counter_attr_parm { struct counter_device_attr_group *group; const char *prefix; @@ -369,6 +289,11 @@ struct counter_signal_unit { struct counter_signal *signal; }; +static const char *const counter_signal_value_str[] = { + [COUNTER_SIGNAL_LOW] = "low", + [COUNTER_SIGNAL_HIGH] = "high" +}; + static ssize_t counter_signal_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -377,13 +302,13 @@ static ssize_t counter_signal_show(struct device *dev, const struct counter_signal_unit *const component = devattr->component; struct counter_signal *const signal = component->signal; int err; - struct counter_signal_read_value val = { .buf = buf }; + enum counter_signal_value val; err = counter->ops->signal_read(counter, signal, &val); if (err) return err; - return val.len; + return sprintf(buf, "%s\n", counter_signal_value_str[val]); } struct counter_name_unit { @@ -788,13 +713,13 @@ static ssize_t counter_count_show(struct device *dev, const struct counter_count_unit *const component = devattr->component; struct counter_count *const count = component->count; int err; - struct counter_count_read_value val = { .buf = buf }; + unsigned long val; err = counter->ops->count_read(counter, count, &val); if (err) return err; - return val.len; + return sprintf(buf, "%lu\n", val); } static ssize_t counter_count_store(struct device *dev, @@ -806,9 +731,13 @@ static ssize_t counter_count_store(struct device *dev, const struct counter_count_unit *const component = devattr->component; struct counter_count *const count = component->count; int err; - struct counter_count_write_value val = { .buf = buf }; + unsigned long val; + + err = kstrtoul(buf, 0, &val); + if (err) + return err; - err = counter->ops->count_write(counter, count, &val); + err = counter->ops->count_write(counter, count, val); if (err) return err; diff --git a/drivers/counter/ftm-quaddec.c b/drivers/counter/ftm-quaddec.c index 4046aa9f9234..c2b3fdfd8b77 100644 --- a/drivers/counter/ftm-quaddec.c +++ b/drivers/counter/ftm-quaddec.c @@ -178,31 +178,25 @@ static const enum counter_count_function ftm_quaddec_count_functions[] = { static int ftm_quaddec_count_read(struct counter_device *counter, struct counter_count *count, - struct counter_count_read_value *val) + unsigned long *val) { struct ftm_quaddec *const ftm = counter->priv; uint32_t cntval; ftm_read(ftm, FTM_CNT, &cntval); - counter_count_read_value_set(val, COUNTER_COUNT_POSITION, &cntval); + *val = cntval; return 0; } static int ftm_quaddec_count_write(struct counter_device *counter, struct counter_count *count, - struct counter_count_write_value *val) + const unsigned long val) { struct ftm_quaddec *const ftm = counter->priv; - u32 cnt; - int err; - err = counter_count_write_value_get(&cnt, COUNTER_COUNT_POSITION, val); - if (err) - return err; - - if (cnt != 0) { + if (val != 0) { dev_warn(&ftm->pdev->dev, "Can only accept '0' as new counter value\n"); return -EINVAL; } diff --git a/drivers/counter/stm32-lptimer-cnt.c b/drivers/counter/stm32-lptimer-cnt.c index bbc930a5962c..8e276eb655f5 100644 --- a/drivers/counter/stm32-lptimer-cnt.c +++ b/drivers/counter/stm32-lptimer-cnt.c @@ -347,7 +347,7 @@ static const struct iio_chan_spec stm32_lptim_cnt_channels = { }; /** - * stm32_lptim_cnt_function - enumerates stm32 LPTimer counter & encoder modes + * enum stm32_lptim_cnt_function - enumerates LPTimer counter & encoder modes * @STM32_LPTIM_COUNTER_INCREASE: up count on IN1 rising, falling or both edges * @STM32_LPTIM_ENCODER_BOTH_EDGE: count on both edges (IN1 & IN2 quadrature) */ @@ -377,8 +377,7 @@ static enum counter_synapse_action stm32_lptim_cnt_synapse_actions[] = { }; static int stm32_lptim_cnt_read(struct counter_device *counter, - struct counter_count *count, - struct counter_count_read_value *val) + struct counter_count *count, unsigned long *val) { struct stm32_lptim_cnt *const priv = counter->priv; u32 cnt; @@ -388,7 +387,7 @@ static int stm32_lptim_cnt_read(struct counter_device *counter, if (ret) return ret; - counter_count_read_value_set(val, COUNTER_COUNT_POSITION, &cnt); + *val = cnt; return 0; } diff --git a/drivers/counter/stm32-timer-cnt.c b/drivers/counter/stm32-timer-cnt.c index 644ba18a72ad..3eafccec3beb 100644 --- a/drivers/counter/stm32-timer-cnt.c +++ b/drivers/counter/stm32-timer-cnt.c @@ -28,7 +28,7 @@ struct stm32_timer_cnt { }; /** - * stm32_count_function - enumerates stm32 timer counter encoder modes + * enum stm32_count_function - enumerates stm32 timer counter encoder modes * @STM32_COUNT_SLAVE_MODE_DISABLED: counts on internal clock when CEN=1 * @STM32_COUNT_ENCODER_MODE_1: counts TI1FP1 edges, depending on TI2FP2 level * @STM32_COUNT_ENCODER_MODE_2: counts TI2FP2 edges, depending on TI1FP1 level @@ -48,34 +48,27 @@ static enum counter_count_function stm32_count_functions[] = { }; static int stm32_count_read(struct counter_device *counter, - struct counter_count *count, - struct counter_count_read_value *val) + struct counter_count *count, unsigned long *val) { struct stm32_timer_cnt *const priv = counter->priv; u32 cnt; regmap_read(priv->regmap, TIM_CNT, &cnt); - counter_count_read_value_set(val, COUNTER_COUNT_POSITION, &cnt); + *val = cnt; return 0; } static int stm32_count_write(struct counter_device *counter, struct counter_count *count, - struct counter_count_write_value *val) + const unsigned long val) { struct stm32_timer_cnt *const priv = counter->priv; - u32 cnt; - int err; - - err = counter_count_write_value_get(&cnt, COUNTER_COUNT_POSITION, val); - if (err) - return err; - if (cnt > priv->ceiling) + if (val > priv->ceiling) return -EINVAL; - return regmap_write(priv->regmap, TIM_CNT, cnt); + return regmap_write(priv->regmap, TIM_CNT, val); } static int stm32_count_function_get(struct counter_device *counter, @@ -219,8 +212,8 @@ static ssize_t stm32_count_enable_write(struct counter_device *counter, if (enable) { regmap_read(priv->regmap, TIM_CR1, &cr1); - if (!(cr1 & TIM_CR1_CEN)) - clk_enable(priv->clk); + if (!(cr1 & TIM_CR1_CEN)) + clk_enable(priv->clk); regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, TIM_CR1_CEN); diff --git a/drivers/counter/ti-eqep.c b/drivers/counter/ti-eqep.c new file mode 100644 index 000000000000..1ff07faef27f --- /dev/null +++ b/drivers/counter/ti-eqep.c @@ -0,0 +1,466 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2019 David Lechner <david@lechnology.com> + * + * Counter driver for Texas Instruments Enhanced Quadrature Encoder Pulse (eQEP) + */ + +#include <linux/bitops.h> +#include <linux/counter.h> +#include <linux/kernel.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> + +/* 32-bit registers */ +#define QPOSCNT 0x0 +#define QPOSINIT 0x4 +#define QPOSMAX 0x8 +#define QPOSCMP 0xc +#define QPOSILAT 0x10 +#define QPOSSLAT 0x14 +#define QPOSLAT 0x18 +#define QUTMR 0x1c +#define QUPRD 0x20 + +/* 16-bit registers */ +#define QWDTMR 0x0 /* 0x24 */ +#define QWDPRD 0x2 /* 0x26 */ +#define QDECCTL 0x4 /* 0x28 */ +#define QEPCTL 0x6 /* 0x2a */ +#define QCAPCTL 0x8 /* 0x2c */ +#define QPOSCTL 0xa /* 0x2e */ +#define QEINT 0xc /* 0x30 */ +#define QFLG 0xe /* 0x32 */ +#define QCLR 0x10 /* 0x34 */ +#define QFRC 0x12 /* 0x36 */ +#define QEPSTS 0x14 /* 0x38 */ +#define QCTMR 0x16 /* 0x3a */ +#define QCPRD 0x18 /* 0x3c */ +#define QCTMRLAT 0x1a /* 0x3e */ +#define QCPRDLAT 0x1c /* 0x40 */ + +#define QDECCTL_QSRC_SHIFT 14 +#define QDECCTL_QSRC GENMASK(15, 14) +#define QDECCTL_SOEN BIT(13) +#define QDECCTL_SPSEL BIT(12) +#define QDECCTL_XCR BIT(11) +#define QDECCTL_SWAP BIT(10) +#define QDECCTL_IGATE BIT(9) +#define QDECCTL_QAP BIT(8) +#define QDECCTL_QBP BIT(7) +#define QDECCTL_QIP BIT(6) +#define QDECCTL_QSP BIT(5) + +#define QEPCTL_FREE_SOFT GENMASK(15, 14) +#define QEPCTL_PCRM GENMASK(13, 12) +#define QEPCTL_SEI GENMASK(11, 10) +#define QEPCTL_IEI GENMASK(9, 8) +#define QEPCTL_SWI BIT(7) +#define QEPCTL_SEL BIT(6) +#define QEPCTL_IEL GENMASK(5, 4) +#define QEPCTL_PHEN BIT(3) +#define QEPCTL_QCLM BIT(2) +#define QEPCTL_UTE BIT(1) +#define QEPCTL_WDE BIT(0) + +/* EQEP Inputs */ +enum { + TI_EQEP_SIGNAL_QEPA, /* QEPA/XCLK */ + TI_EQEP_SIGNAL_QEPB, /* QEPB/XDIR */ +}; + +/* Position Counter Input Modes */ +enum { + TI_EQEP_COUNT_FUNC_QUAD_COUNT, + TI_EQEP_COUNT_FUNC_DIR_COUNT, + TI_EQEP_COUNT_FUNC_UP_COUNT, + TI_EQEP_COUNT_FUNC_DOWN_COUNT, +}; + +enum { + TI_EQEP_SYNAPSE_ACTION_BOTH_EDGES, + TI_EQEP_SYNAPSE_ACTION_RISING_EDGE, + TI_EQEP_SYNAPSE_ACTION_NONE, +}; + +struct ti_eqep_cnt { + struct counter_device counter; + struct regmap *regmap32; + struct regmap *regmap16; +}; + +static int ti_eqep_count_read(struct counter_device *counter, + struct counter_count *count, unsigned long *val) +{ + struct ti_eqep_cnt *priv = counter->priv; + u32 cnt; + + regmap_read(priv->regmap32, QPOSCNT, &cnt); + *val = cnt; + + return 0; +} + +static int ti_eqep_count_write(struct counter_device *counter, + struct counter_count *count, unsigned long val) +{ + struct ti_eqep_cnt *priv = counter->priv; + u32 max; + + regmap_read(priv->regmap32, QPOSMAX, &max); + if (val > max) + return -EINVAL; + + return regmap_write(priv->regmap32, QPOSCNT, val); +} + +static int ti_eqep_function_get(struct counter_device *counter, + struct counter_count *count, size_t *function) +{ + struct ti_eqep_cnt *priv = counter->priv; + u32 qdecctl; + + regmap_read(priv->regmap16, QDECCTL, &qdecctl); + *function = (qdecctl & QDECCTL_QSRC) >> QDECCTL_QSRC_SHIFT; + + return 0; +} + +static int ti_eqep_function_set(struct counter_device *counter, + struct counter_count *count, size_t function) +{ + struct ti_eqep_cnt *priv = counter->priv; + + return regmap_write_bits(priv->regmap16, QDECCTL, QDECCTL_QSRC, + function << QDECCTL_QSRC_SHIFT); +} + +static int ti_eqep_action_get(struct counter_device *counter, + struct counter_count *count, + struct counter_synapse *synapse, size_t *action) +{ + struct ti_eqep_cnt *priv = counter->priv; + size_t function; + u32 qdecctl; + int err; + + err = ti_eqep_function_get(counter, count, &function); + if (err) + return err; + + switch (function) { + case TI_EQEP_COUNT_FUNC_QUAD_COUNT: + /* In quadrature mode, the rising and falling edge of both + * QEPA and QEPB trigger QCLK. + */ + *action = TI_EQEP_SYNAPSE_ACTION_BOTH_EDGES; + break; + case TI_EQEP_COUNT_FUNC_DIR_COUNT: + /* In direction-count mode only rising edge of QEPA is counted + * and QEPB gives direction. + */ + switch (synapse->signal->id) { + case TI_EQEP_SIGNAL_QEPA: + *action = TI_EQEP_SYNAPSE_ACTION_RISING_EDGE; + break; + default: + *action = TI_EQEP_SYNAPSE_ACTION_NONE; + break; + } + break; + case TI_EQEP_COUNT_FUNC_UP_COUNT: + case TI_EQEP_COUNT_FUNC_DOWN_COUNT: + /* In up/down-count modes only QEPA is counted and QEPB is not + * used. + */ + switch (synapse->signal->id) { + case TI_EQEP_SIGNAL_QEPA: + err = regmap_read(priv->regmap16, QDECCTL, &qdecctl); + if (err) + return err; + + if (qdecctl & QDECCTL_XCR) + *action = TI_EQEP_SYNAPSE_ACTION_BOTH_EDGES; + else + *action = TI_EQEP_SYNAPSE_ACTION_RISING_EDGE; + break; + default: + *action = TI_EQEP_SYNAPSE_ACTION_NONE; + break; + } + break; + } + + return 0; +} + +static const struct counter_ops ti_eqep_counter_ops = { + .count_read = ti_eqep_count_read, + .count_write = ti_eqep_count_write, + .function_get = ti_eqep_function_get, + .function_set = ti_eqep_function_set, + .action_get = ti_eqep_action_get, +}; + +static ssize_t ti_eqep_position_ceiling_read(struct counter_device *counter, + struct counter_count *count, + void *ext_priv, char *buf) +{ + struct ti_eqep_cnt *priv = counter->priv; + u32 qposmax; + + regmap_read(priv->regmap32, QPOSMAX, &qposmax); + + return sprintf(buf, "%u\n", qposmax); +} + +static ssize_t ti_eqep_position_ceiling_write(struct counter_device *counter, + struct counter_count *count, + void *ext_priv, const char *buf, + size_t len) +{ + struct ti_eqep_cnt *priv = counter->priv; + int err; + u32 res; + + err = kstrtouint(buf, 0, &res); + if (err < 0) + return err; + + regmap_write(priv->regmap32, QPOSMAX, res); + + return len; +} + +static ssize_t ti_eqep_position_floor_read(struct counter_device *counter, + struct counter_count *count, + void *ext_priv, char *buf) +{ + struct ti_eqep_cnt *priv = counter->priv; + u32 qposinit; + + regmap_read(priv->regmap32, QPOSINIT, &qposinit); + + return sprintf(buf, "%u\n", qposinit); +} + +static ssize_t ti_eqep_position_floor_write(struct counter_device *counter, + struct counter_count *count, + void *ext_priv, const char *buf, + size_t len) +{ + struct ti_eqep_cnt *priv = counter->priv; + int err; + u32 res; + + err = kstrtouint(buf, 0, &res); + if (err < 0) + return err; + + regmap_write(priv->regmap32, QPOSINIT, res); + + return len; +} + +static ssize_t ti_eqep_position_enable_read(struct counter_device *counter, + struct counter_count *count, + void *ext_priv, char *buf) +{ + struct ti_eqep_cnt *priv = counter->priv; + u32 qepctl; + + regmap_read(priv->regmap16, QEPCTL, &qepctl); + + return sprintf(buf, "%u\n", !!(qepctl & QEPCTL_PHEN)); +} + +static ssize_t ti_eqep_position_enable_write(struct counter_device *counter, + struct counter_count *count, + void *ext_priv, const char *buf, + size_t len) +{ + struct ti_eqep_cnt *priv = counter->priv; + int err; + bool res; + + err = kstrtobool(buf, &res); + if (err < 0) + return err; + + regmap_write_bits(priv->regmap16, QEPCTL, QEPCTL_PHEN, res ? -1 : 0); + + return len; +} + +static struct counter_count_ext ti_eqep_position_ext[] = { + { + .name = "ceiling", + .read = ti_eqep_position_ceiling_read, + .write = ti_eqep_position_ceiling_write, + }, + { + .name = "floor", + .read = ti_eqep_position_floor_read, + .write = ti_eqep_position_floor_write, + }, + { + .name = "enable", + .read = ti_eqep_position_enable_read, + .write = ti_eqep_position_enable_write, + }, +}; + +static struct counter_signal ti_eqep_signals[] = { + [TI_EQEP_SIGNAL_QEPA] = { + .id = TI_EQEP_SIGNAL_QEPA, + .name = "QEPA" + }, + [TI_EQEP_SIGNAL_QEPB] = { + .id = TI_EQEP_SIGNAL_QEPB, + .name = "QEPB" + }, +}; + +static const enum counter_count_function ti_eqep_position_functions[] = { + [TI_EQEP_COUNT_FUNC_QUAD_COUNT] = COUNTER_COUNT_FUNCTION_QUADRATURE_X4, + [TI_EQEP_COUNT_FUNC_DIR_COUNT] = COUNTER_COUNT_FUNCTION_PULSE_DIRECTION, + [TI_EQEP_COUNT_FUNC_UP_COUNT] = COUNTER_COUNT_FUNCTION_INCREASE, + [TI_EQEP_COUNT_FUNC_DOWN_COUNT] = COUNTER_COUNT_FUNCTION_DECREASE, +}; + +static const enum counter_synapse_action ti_eqep_position_synapse_actions[] = { + [TI_EQEP_SYNAPSE_ACTION_BOTH_EDGES] = COUNTER_SYNAPSE_ACTION_BOTH_EDGES, + [TI_EQEP_SYNAPSE_ACTION_RISING_EDGE] = COUNTER_SYNAPSE_ACTION_RISING_EDGE, + [TI_EQEP_SYNAPSE_ACTION_NONE] = COUNTER_SYNAPSE_ACTION_NONE, +}; + +static struct counter_synapse ti_eqep_position_synapses[] = { + { + .actions_list = ti_eqep_position_synapse_actions, + .num_actions = ARRAY_SIZE(ti_eqep_position_synapse_actions), + .signal = &ti_eqep_signals[TI_EQEP_SIGNAL_QEPA], + }, + { + .actions_list = ti_eqep_position_synapse_actions, + .num_actions = ARRAY_SIZE(ti_eqep_position_synapse_actions), + .signal = &ti_eqep_signals[TI_EQEP_SIGNAL_QEPB], + }, +}; + +static struct counter_count ti_eqep_counts[] = { + { + .id = 0, + .name = "QPOSCNT", + .functions_list = ti_eqep_position_functions, + .num_functions = ARRAY_SIZE(ti_eqep_position_functions), + .synapses = ti_eqep_position_synapses, + .num_synapses = ARRAY_SIZE(ti_eqep_position_synapses), + .ext = ti_eqep_position_ext, + .num_ext = ARRAY_SIZE(ti_eqep_position_ext), + }, +}; + +static const struct regmap_config ti_eqep_regmap32_config = { + .name = "32-bit", + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = 0x24, +}; + +static const struct regmap_config ti_eqep_regmap16_config = { + .name = "16-bit", + .reg_bits = 16, + .val_bits = 16, + .reg_stride = 2, + .max_register = 0x1e, +}; + +static int ti_eqep_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ti_eqep_cnt *priv; + void __iomem *base; + int err; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + priv->regmap32 = devm_regmap_init_mmio(dev, base, + &ti_eqep_regmap32_config); + if (IS_ERR(priv->regmap32)) + return PTR_ERR(priv->regmap32); + + priv->regmap16 = devm_regmap_init_mmio(dev, base + 0x24, + &ti_eqep_regmap16_config); + if (IS_ERR(priv->regmap16)) + return PTR_ERR(priv->regmap16); + + priv->counter.name = dev_name(dev); + priv->counter.parent = dev; + priv->counter.ops = &ti_eqep_counter_ops; + priv->counter.counts = ti_eqep_counts; + priv->counter.num_counts = ARRAY_SIZE(ti_eqep_counts); + priv->counter.signals = ti_eqep_signals; + priv->counter.num_signals = ARRAY_SIZE(ti_eqep_signals); + priv->counter.priv = priv; + + platform_set_drvdata(pdev, priv); + + /* + * Need to make sure power is turned on. On AM33xx, this comes from the + * parent PWMSS bus driver. On AM17xx, this comes from the PSC power + * domain. + */ + pm_runtime_enable(dev); + pm_runtime_get_sync(dev); + + err = counter_register(&priv->counter); + if (err < 0) { + pm_runtime_put_sync(dev); + pm_runtime_disable(dev); + return err; + } + + return 0; +} + +static int ti_eqep_remove(struct platform_device *pdev) +{ + struct ti_eqep_cnt *priv = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; + + counter_unregister(&priv->counter); + pm_runtime_put_sync(dev), + pm_runtime_disable(dev); + + return 0; +} + +static const struct of_device_id ti_eqep_of_match[] = { + { .compatible = "ti,am3352-eqep", }, + { }, +}; +MODULE_DEVICE_TABLE(of, ti_eqep_of_match); + +static struct platform_driver ti_eqep_driver = { + .probe = ti_eqep_probe, + .remove = ti_eqep_remove, + .driver = { + .name = "ti-eqep-cnt", + .of_match_table = ti_eqep_of_match, + }, +}; +module_platform_driver(ti_eqep_driver); + +MODULE_AUTHOR("David Lechner <david@lechnology.com>"); +MODULE_DESCRIPTION("TI eQEP counter driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 13a6b4afb4b3..5308c59d7001 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -40,7 +40,8 @@ comment "Native drivers" config SENSORS_AB8500 tristate "AB8500 thermal monitoring" - depends on AB8500_GPADC && AB8500_BM + depends on AB8500_GPADC && AB8500_BM && (IIO = y) + default n help If you say yes here you get support for the thermal sensor part of the AB8500 chip. The driver includes thermal management for diff --git a/drivers/hwmon/ab8500.c b/drivers/hwmon/ab8500.c index 207f77f85a40..53f3379d799d 100644 --- a/drivers/hwmon/ab8500.c +++ b/drivers/hwmon/ab8500.c @@ -17,20 +17,24 @@ #include <linux/hwmon-sysfs.h> #include <linux/mfd/abx500.h> #include <linux/mfd/abx500/ab8500-bm.h> -#include <linux/mfd/abx500/ab8500-gpadc.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/power/ab8500.h> #include <linux/reboot.h> #include <linux/slab.h> #include <linux/sysfs.h> +#include <linux/iio/consumer.h> #include "abx500.h" #define DEFAULT_POWER_OFF_DELAY (HZ * 10) #define THERMAL_VCC 1800 #define PULL_UP_RESISTOR 47000 -/* Number of monitored sensors should not greater than NUM_SENSORS */ -#define NUM_MONITORED_SENSORS 4 + +#define AB8500_SENSOR_AUX1 0 +#define AB8500_SENSOR_AUX2 1 +#define AB8500_SENSOR_BTEMP_BALL 2 +#define AB8500_SENSOR_BAT_CTRL 3 +#define NUM_MONITORED_SENSORS 4 struct ab8500_gpadc_cfg { const struct abx500_res_to_temp *temp_tbl; @@ -40,7 +44,8 @@ struct ab8500_gpadc_cfg { }; struct ab8500_temp { - struct ab8500_gpadc *gpadc; + struct iio_channel *aux1; + struct iio_channel *aux2; struct ab8500_btemp *btemp; struct delayed_work power_off_work; struct ab8500_gpadc_cfg cfg; @@ -82,15 +87,21 @@ static int ab8500_read_sensor(struct abx500_temp *data, u8 sensor, int *temp) int voltage, ret; struct ab8500_temp *ab8500_data = data->plat_data; - if (sensor == BAT_CTRL) { - *temp = ab8500_btemp_get_batctrl_temp(ab8500_data->btemp); - } else if (sensor == BTEMP_BALL) { + if (sensor == AB8500_SENSOR_BTEMP_BALL) { *temp = ab8500_btemp_get_temp(ab8500_data->btemp); - } else { - voltage = ab8500_gpadc_convert(ab8500_data->gpadc, sensor); - if (voltage < 0) - return voltage; - + } else if (sensor == AB8500_SENSOR_BAT_CTRL) { + *temp = ab8500_btemp_get_batctrl_temp(ab8500_data->btemp); + } else if (sensor == AB8500_SENSOR_AUX1) { + ret = iio_read_channel_processed(ab8500_data->aux1, &voltage); + if (ret < 0) + return ret; + ret = ab8500_voltage_to_temp(&ab8500_data->cfg, voltage, temp); + if (ret < 0) + return ret; + } else if (sensor == AB8500_SENSOR_AUX2) { + ret = iio_read_channel_processed(ab8500_data->aux2, &voltage); + if (ret < 0) + return ret; ret = ab8500_voltage_to_temp(&ab8500_data->cfg, voltage, temp); if (ret < 0) return ret; @@ -164,10 +175,6 @@ int abx500_hwmon_init(struct abx500_temp *data) if (!ab8500_data) return -ENOMEM; - ab8500_data->gpadc = ab8500_gpadc_get("ab8500-gpadc.0"); - if (IS_ERR(ab8500_data->gpadc)) - return PTR_ERR(ab8500_data->gpadc); - ab8500_data->btemp = ab8500_btemp_get(); if (IS_ERR(ab8500_data->btemp)) return PTR_ERR(ab8500_data->btemp); @@ -181,15 +188,25 @@ int abx500_hwmon_init(struct abx500_temp *data) ab8500_data->cfg.tbl_sz = ab8500_temp_tbl_a_size; data->plat_data = ab8500_data; + ab8500_data->aux1 = devm_iio_channel_get(&data->pdev->dev, "aux1"); + if (IS_ERR(ab8500_data->aux1)) { + if (PTR_ERR(ab8500_data->aux1) == -ENODEV) + return -EPROBE_DEFER; + dev_err(&data->pdev->dev, "failed to get AUX1 ADC channel\n"); + return PTR_ERR(ab8500_data->aux1); + } + ab8500_data->aux2 = devm_iio_channel_get(&data->pdev->dev, "aux2"); + if (IS_ERR(ab8500_data->aux2)) { + if (PTR_ERR(ab8500_data->aux2) == -ENODEV) + return -EPROBE_DEFER; + dev_err(&data->pdev->dev, "failed to get AUX2 ADC channel\n"); + return PTR_ERR(ab8500_data->aux2); + } - /* - * ADC_AUX1 and ADC_AUX2, connected to external NTC - * BTEMP_BALL and BAT_CTRL, fixed usage - */ - data->gpadc_addr[0] = ADC_AUX1; - data->gpadc_addr[1] = ADC_AUX2; - data->gpadc_addr[2] = BTEMP_BALL; - data->gpadc_addr[3] = BAT_CTRL; + data->gpadc_addr[0] = AB8500_SENSOR_AUX1; + data->gpadc_addr[1] = AB8500_SENSOR_AUX2; + data->gpadc_addr[2] = AB8500_SENSOR_BTEMP_BALL; + data->gpadc_addr[3] = AB8500_SENSOR_BAT_CTRL; data->monitored_sensors = NUM_MONITORED_SENSORS; data->ops.read_sensor = ab8500_read_sensor; diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index 2e37f8a6d8cf..7b837641f166 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -15,7 +15,6 @@ #include <linux/types.h> #include <linux/interrupt.h> #include <linux/i2c.h> -#include <linux/gpio.h> #include <linux/irq.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index f0af3a42f53c..9554890a3200 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -6,6 +6,16 @@ menu "Analog to digital converters" +config AB8500_GPADC + bool "ST-Ericsson AB8500 GPADC driver" + depends on AB8500_CORE && REGULATOR_AB8500 + default y + help + AB8500 Analog Baseband, mixed signal integrated circuit GPADC + (General Purpose Analog to Digital Converter) driver used to monitor + internal voltages, convert accessory and battery, AC (charger, mains) + and USB voltages integral to the U8500 platform. + config AD_SIGMA_DELTA tristate select IIO_BUFFER @@ -432,6 +442,17 @@ config INGENIC_ADC This driver can also be built as a module. If so, the module will be called ingenic_adc. +config INTEL_MRFLD_ADC + tristate "Intel Merrifield Basin Cove ADC driver" + depends on INTEL_SOC_PMIC_MRFLD + help + Say yes here to have support for Basin Cove power management IC (PMIC) ADC + device. Depending on platform configuration, this general purpose ADC can + be used for sampling sensors such as thermal resistors. + + To compile this driver as a module, choose M here: the module will be + called intel_mrfld_adc. + config IMX7D_ADC tristate "Freescale IMX7D ADC driver" depends on ARCH_MXC || COMPILE_TEST @@ -508,8 +529,8 @@ config MAX1027 select IIO_BUFFER select IIO_TRIGGERED_BUFFER help - Say yes here to build support for Maxim SPI ADC models - max1027, max1029 and max1031. + Say yes here to build support for Maxim SPI {10,12}-bit ADC models: + max1027, max1029, max1031, max1227, max1229 and max1231. To compile this driver as a module, choose M here: the module will be called max1027. diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index ef9cc485fb67..5ecc481c2967 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -4,6 +4,7 @@ # # When adding new entries keep the list in alphabetical order +obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o obj-$(CONFIG_AD7124) += ad7124.o obj-$(CONFIG_AD7266) += ad7266.o @@ -42,6 +43,7 @@ obj-$(CONFIG_HX711) += hx711.o obj-$(CONFIG_IMX7D_ADC) += imx7d_adc.o obj-$(CONFIG_INA2XX_ADC) += ina2xx-adc.o obj-$(CONFIG_INGENIC_ADC) += ingenic-adc.o +obj-$(CONFIG_INTEL_MRFLD_ADC) += intel_mrfld_adc.o obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o diff --git a/drivers/iio/adc/ab8500-gpadc.c b/drivers/iio/adc/ab8500-gpadc.c new file mode 100644 index 000000000000..fd5b18d7f0c2 --- /dev/null +++ b/drivers/iio/adc/ab8500-gpadc.c @@ -0,0 +1,1218 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * Author: Arun R Murthy <arun.murthy@stericsson.com> + * Author: Daniel Willerud <daniel.willerud@stericsson.com> + * Author: Johan Palsson <johan.palsson@stericsson.com> + * Author: M'boumba Cedric Madianga + * Author: Linus Walleij <linus.walleij@linaro.org> + * + * AB8500 General Purpose ADC driver. The AB8500 uses reference voltages: + * VinVADC, and VADC relative to GND to do its job. It monitors main and backup + * battery voltages, AC (mains) voltage, USB cable voltage, as well as voltages + * representing the temperature of the chip die and battery, accessory + * detection by resistance measurements using relative voltages and GSM burst + * information. + * + * Some of the voltages are measured on external pins on the IC, such as + * battery temperature or "ADC aux" 1 and 2. Other voltages are internal rails + * from other parts of the ASIC such as main charger voltage, main and battery + * backup voltage or USB VBUS voltage. For this reason drivers for other + * parts of the system are required to obtain handles to the ADC to do work + * for them and the IIO driver provides arbitration among these consumers. + */ +#include <linux/init.h> +#include <linux/bits.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/device.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/delay.h> +#include <linux/pm_runtime.h> +#include <linux/platform_device.h> +#include <linux/completion.h> +#include <linux/regulator/consumer.h> +#include <linux/random.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/mfd/abx500.h> +#include <linux/mfd/abx500/ab8500.h> + +/* GPADC register offsets and bit definitions */ + +#define AB8500_GPADC_CTRL1_REG 0x00 +/* GPADC control register 1 bits */ +#define AB8500_GPADC_CTRL1_DISABLE 0x00 +#define AB8500_GPADC_CTRL1_ENABLE BIT(0) +#define AB8500_GPADC_CTRL1_TRIG_ENA BIT(1) +#define AB8500_GPADC_CTRL1_START_SW_CONV BIT(2) +#define AB8500_GPADC_CTRL1_BTEMP_PULL_UP BIT(3) +/* 0 = use rising edge, 1 = use falling edge */ +#define AB8500_GPADC_CTRL1_TRIG_EDGE BIT(4) +/* 0 = use VTVOUT, 1 = use VRTC as pull-up supply for battery temp NTC */ +#define AB8500_GPADC_CTRL1_PUPSUPSEL BIT(5) +#define AB8500_GPADC_CTRL1_BUF_ENA BIT(6) +#define AB8500_GPADC_CTRL1_ICHAR_ENA BIT(7) + +#define AB8500_GPADC_CTRL2_REG 0x01 +#define AB8500_GPADC_CTRL3_REG 0x02 +/* + * GPADC control register 2 and 3 bits + * the bit layout is the same for SW and HW conversion set-up + */ +#define AB8500_GPADC_CTRL2_AVG_1 0x00 +#define AB8500_GPADC_CTRL2_AVG_4 BIT(5) +#define AB8500_GPADC_CTRL2_AVG_8 BIT(6) +#define AB8500_GPADC_CTRL2_AVG_16 (BIT(5) | BIT(6)) + +enum ab8500_gpadc_channel { + AB8500_GPADC_CHAN_UNUSED = 0x00, + AB8500_GPADC_CHAN_BAT_CTRL = 0x01, + AB8500_GPADC_CHAN_BAT_TEMP = 0x02, + /* This is not used on AB8505 */ + AB8500_GPADC_CHAN_MAIN_CHARGER = 0x03, + AB8500_GPADC_CHAN_ACC_DET_1 = 0x04, + AB8500_GPADC_CHAN_ACC_DET_2 = 0x05, + AB8500_GPADC_CHAN_ADC_AUX_1 = 0x06, + AB8500_GPADC_CHAN_ADC_AUX_2 = 0x07, + AB8500_GPADC_CHAN_VBAT_A = 0x08, + AB8500_GPADC_CHAN_VBUS = 0x09, + AB8500_GPADC_CHAN_MAIN_CHARGER_CURRENT = 0x0a, + AB8500_GPADC_CHAN_USB_CHARGER_CURRENT = 0x0b, + AB8500_GPADC_CHAN_BACKUP_BAT = 0x0c, + /* Only on AB8505 */ + AB8505_GPADC_CHAN_DIE_TEMP = 0x0d, + AB8500_GPADC_CHAN_ID = 0x0e, + AB8500_GPADC_CHAN_INTERNAL_TEST_1 = 0x0f, + AB8500_GPADC_CHAN_INTERNAL_TEST_2 = 0x10, + AB8500_GPADC_CHAN_INTERNAL_TEST_3 = 0x11, + /* FIXME: Applicable to all ASIC variants? */ + AB8500_GPADC_CHAN_XTAL_TEMP = 0x12, + AB8500_GPADC_CHAN_VBAT_TRUE_MEAS = 0x13, + /* FIXME: Doesn't seem to work with pure AB8500 */ + AB8500_GPADC_CHAN_BAT_CTRL_AND_IBAT = 0x1c, + AB8500_GPADC_CHAN_VBAT_MEAS_AND_IBAT = 0x1d, + AB8500_GPADC_CHAN_VBAT_TRUE_MEAS_AND_IBAT = 0x1e, + AB8500_GPADC_CHAN_BAT_TEMP_AND_IBAT = 0x1f, + /* + * Virtual channel used only for ibat conversion to ampere. + * Battery current conversion (ibat) cannot be requested as a + * single conversion but it is always requested in combination + * with other input requests. + */ + AB8500_GPADC_CHAN_IBAT_VIRTUAL = 0xFF, +}; + +#define AB8500_GPADC_AUTO_TIMER_REG 0x03 + +#define AB8500_GPADC_STAT_REG 0x04 +#define AB8500_GPADC_STAT_BUSY BIT(0) + +#define AB8500_GPADC_MANDATAL_REG 0x05 +#define AB8500_GPADC_MANDATAH_REG 0x06 +#define AB8500_GPADC_AUTODATAL_REG 0x07 +#define AB8500_GPADC_AUTODATAH_REG 0x08 +#define AB8500_GPADC_MUX_CTRL_REG 0x09 +#define AB8540_GPADC_MANDATA2L_REG 0x09 +#define AB8540_GPADC_MANDATA2H_REG 0x0A +#define AB8540_GPADC_APEAAX_REG 0x10 +#define AB8540_GPADC_APEAAT_REG 0x11 +#define AB8540_GPADC_APEAAM_REG 0x12 +#define AB8540_GPADC_APEAAH_REG 0x13 +#define AB8540_GPADC_APEAAL_REG 0x14 + +/* + * OTP register offsets + * Bank : 0x15 + */ +#define AB8500_GPADC_CAL_1 0x0F +#define AB8500_GPADC_CAL_2 0x10 +#define AB8500_GPADC_CAL_3 0x11 +#define AB8500_GPADC_CAL_4 0x12 +#define AB8500_GPADC_CAL_5 0x13 +#define AB8500_GPADC_CAL_6 0x14 +#define AB8500_GPADC_CAL_7 0x15 +/* New calibration for 8540 */ +#define AB8540_GPADC_OTP4_REG_7 0x38 +#define AB8540_GPADC_OTP4_REG_6 0x39 +#define AB8540_GPADC_OTP4_REG_5 0x3A + +#define AB8540_GPADC_DIS_ZERO 0x00 +#define AB8540_GPADC_EN_VBIAS_XTAL_TEMP 0x02 + +/* GPADC constants from AB8500 spec, UM0836 */ +#define AB8500_ADC_RESOLUTION 1024 +#define AB8500_ADC_CH_BTEMP_MIN 0 +#define AB8500_ADC_CH_BTEMP_MAX 1350 +#define AB8500_ADC_CH_DIETEMP_MIN 0 +#define AB8500_ADC_CH_DIETEMP_MAX 1350 +#define AB8500_ADC_CH_CHG_V_MIN 0 +#define AB8500_ADC_CH_CHG_V_MAX 20030 +#define AB8500_ADC_CH_ACCDET2_MIN 0 +#define AB8500_ADC_CH_ACCDET2_MAX 2500 +#define AB8500_ADC_CH_VBAT_MIN 2300 +#define AB8500_ADC_CH_VBAT_MAX 4800 +#define AB8500_ADC_CH_CHG_I_MIN 0 +#define AB8500_ADC_CH_CHG_I_MAX 1500 +#define AB8500_ADC_CH_BKBAT_MIN 0 +#define AB8500_ADC_CH_BKBAT_MAX 3200 + +/* GPADC constants from AB8540 spec */ +#define AB8500_ADC_CH_IBAT_MIN (-6000) /* mA range measured by ADC for ibat */ +#define AB8500_ADC_CH_IBAT_MAX 6000 +#define AB8500_ADC_CH_IBAT_MIN_V (-60) /* mV range measured by ADC for ibat */ +#define AB8500_ADC_CH_IBAT_MAX_V 60 +#define AB8500_GPADC_IBAT_VDROP_L (-56) /* mV */ +#define AB8500_GPADC_IBAT_VDROP_H 56 + +/* This is used to not lose precision when dividing to get gain and offset */ +#define AB8500_GPADC_CALIB_SCALE 1000 +/* + * Number of bits shift used to not lose precision + * when dividing to get ibat gain. + */ +#define AB8500_GPADC_CALIB_SHIFT_IBAT 20 + +/* Time in ms before disabling regulator */ +#define AB8500_GPADC_AUTOSUSPEND_DELAY 1 + +#define AB8500_GPADC_CONVERSION_TIME 500 /* ms */ + +enum ab8500_cal_channels { + AB8500_CAL_VMAIN = 0, + AB8500_CAL_BTEMP, + AB8500_CAL_VBAT, + AB8500_CAL_IBAT, + AB8500_CAL_NR, +}; + +/** + * struct ab8500_adc_cal_data - Table for storing gain and offset for the + * calibrated ADC channels + * @gain: Gain of the ADC channel + * @offset: Offset of the ADC channel + * @otp_calib_hi: Calibration from OTP + * @otp_calib_lo: Calibration from OTP + */ +struct ab8500_adc_cal_data { + s64 gain; + s64 offset; + u16 otp_calib_hi; + u16 otp_calib_lo; +}; + +/** + * struct ab8500_gpadc_chan_info - per-channel GPADC info + * @name: name of the channel + * @id: the internal AB8500 ID number for the channel + * @hardware_control: indicate that we want to use hardware ADC control + * on this channel, the default is software ADC control. Hardware control + * is normally only used to test the battery voltage during GSM bursts + * and needs a hardware trigger on the GPADCTrig pin of the ASIC. + * @falling_edge: indicate that we want to trigger on falling edge + * rather than rising edge, rising edge is the default + * @avg_sample: how many samples to average: must be 1, 4, 8 or 16. + * @trig_timer: how long to wait for the trigger, in 32kHz periods: + * 0 .. 255 periods + */ +struct ab8500_gpadc_chan_info { + const char *name; + u8 id; + bool hardware_control; + bool falling_edge; + u8 avg_sample; + u8 trig_timer; +}; + +/** + * struct ab8500_gpadc - AB8500 GPADC device information + * @dev: pointer to the containing device + * @ab8500: pointer to the parent AB8500 device + * @chans: internal per-channel information container + * @nchans: number of channels + * @complete: pointer to the completion that indicates + * the completion of an gpadc conversion cycle + * @vddadc: pointer to the regulator supplying VDDADC + * @irq_sw: interrupt number that is used by gpadc for software ADC conversion + * @irq_hw: interrupt number that is used by gpadc for hardware ADC conversion + * @cal_data: array of ADC calibration data structs + */ +struct ab8500_gpadc { + struct device *dev; + struct ab8500 *ab8500; + struct ab8500_gpadc_chan_info *chans; + unsigned int nchans; + struct completion complete; + struct regulator *vddadc; + int irq_sw; + int irq_hw; + struct ab8500_adc_cal_data cal_data[AB8500_CAL_NR]; +}; + +static struct ab8500_gpadc_chan_info * +ab8500_gpadc_get_channel(struct ab8500_gpadc *gpadc, u8 chan) +{ + struct ab8500_gpadc_chan_info *ch; + int i; + + for (i = 0; i < gpadc->nchans; i++) { + ch = &gpadc->chans[i]; + if (ch->id == chan) + break; + } + if (i == gpadc->nchans) + return NULL; + + return ch; +} + +/** + * ab8500_gpadc_ad_to_voltage() - Convert a raw ADC value to a voltage + * @gpadc: GPADC instance + * @ch: the sampled channel this raw value is coming from + * @ad_value: the raw value + */ +static int ab8500_gpadc_ad_to_voltage(struct ab8500_gpadc *gpadc, + enum ab8500_gpadc_channel ch, + int ad_value) +{ + int res; + + switch (ch) { + case AB8500_GPADC_CHAN_MAIN_CHARGER: + /* No calibration data available: just interpolate */ + if (!gpadc->cal_data[AB8500_CAL_VMAIN].gain) { + res = AB8500_ADC_CH_CHG_V_MIN + (AB8500_ADC_CH_CHG_V_MAX - + AB8500_ADC_CH_CHG_V_MIN) * ad_value / + AB8500_ADC_RESOLUTION; + break; + } + /* Here we can use calibration */ + res = (int) (ad_value * gpadc->cal_data[AB8500_CAL_VMAIN].gain + + gpadc->cal_data[AB8500_CAL_VMAIN].offset) / AB8500_GPADC_CALIB_SCALE; + break; + + case AB8500_GPADC_CHAN_BAT_CTRL: + case AB8500_GPADC_CHAN_BAT_TEMP: + case AB8500_GPADC_CHAN_ACC_DET_1: + case AB8500_GPADC_CHAN_ADC_AUX_1: + case AB8500_GPADC_CHAN_ADC_AUX_2: + case AB8500_GPADC_CHAN_XTAL_TEMP: + /* No calibration data available: just interpolate */ + if (!gpadc->cal_data[AB8500_CAL_BTEMP].gain) { + res = AB8500_ADC_CH_BTEMP_MIN + (AB8500_ADC_CH_BTEMP_MAX - + AB8500_ADC_CH_BTEMP_MIN) * ad_value / + AB8500_ADC_RESOLUTION; + break; + } + /* Here we can use calibration */ + res = (int) (ad_value * gpadc->cal_data[AB8500_CAL_BTEMP].gain + + gpadc->cal_data[AB8500_CAL_BTEMP].offset) / AB8500_GPADC_CALIB_SCALE; + break; + + case AB8500_GPADC_CHAN_VBAT_A: + case AB8500_GPADC_CHAN_VBAT_TRUE_MEAS: + /* No calibration data available: just interpolate */ + if (!gpadc->cal_data[AB8500_CAL_VBAT].gain) { + res = AB8500_ADC_CH_VBAT_MIN + (AB8500_ADC_CH_VBAT_MAX - + AB8500_ADC_CH_VBAT_MIN) * ad_value / + AB8500_ADC_RESOLUTION; + break; + } + /* Here we can use calibration */ + res = (int) (ad_value * gpadc->cal_data[AB8500_CAL_VBAT].gain + + gpadc->cal_data[AB8500_CAL_VBAT].offset) / AB8500_GPADC_CALIB_SCALE; + break; + + case AB8505_GPADC_CHAN_DIE_TEMP: + res = AB8500_ADC_CH_DIETEMP_MIN + + (AB8500_ADC_CH_DIETEMP_MAX - AB8500_ADC_CH_DIETEMP_MIN) * ad_value / + AB8500_ADC_RESOLUTION; + break; + + case AB8500_GPADC_CHAN_ACC_DET_2: + res = AB8500_ADC_CH_ACCDET2_MIN + + (AB8500_ADC_CH_ACCDET2_MAX - AB8500_ADC_CH_ACCDET2_MIN) * ad_value / + AB8500_ADC_RESOLUTION; + break; + + case AB8500_GPADC_CHAN_VBUS: + res = AB8500_ADC_CH_CHG_V_MIN + + (AB8500_ADC_CH_CHG_V_MAX - AB8500_ADC_CH_CHG_V_MIN) * ad_value / + AB8500_ADC_RESOLUTION; + break; + + case AB8500_GPADC_CHAN_MAIN_CHARGER_CURRENT: + case AB8500_GPADC_CHAN_USB_CHARGER_CURRENT: + res = AB8500_ADC_CH_CHG_I_MIN + + (AB8500_ADC_CH_CHG_I_MAX - AB8500_ADC_CH_CHG_I_MIN) * ad_value / + AB8500_ADC_RESOLUTION; + break; + + case AB8500_GPADC_CHAN_BACKUP_BAT: + res = AB8500_ADC_CH_BKBAT_MIN + + (AB8500_ADC_CH_BKBAT_MAX - AB8500_ADC_CH_BKBAT_MIN) * ad_value / + AB8500_ADC_RESOLUTION; + break; + + case AB8500_GPADC_CHAN_IBAT_VIRTUAL: + /* No calibration data available: just interpolate */ + if (!gpadc->cal_data[AB8500_CAL_IBAT].gain) { + res = AB8500_ADC_CH_IBAT_MIN + (AB8500_ADC_CH_IBAT_MAX - + AB8500_ADC_CH_IBAT_MIN) * ad_value / + AB8500_ADC_RESOLUTION; + break; + } + /* Here we can use calibration */ + res = (int) (ad_value * gpadc->cal_data[AB8500_CAL_IBAT].gain + + gpadc->cal_data[AB8500_CAL_IBAT].offset) + >> AB8500_GPADC_CALIB_SHIFT_IBAT; + break; + + default: + dev_err(gpadc->dev, + "unknown channel ID: %d, not possible to convert\n", + ch); + res = -EINVAL; + break; + + } + + return res; +} + +static int ab8500_gpadc_read(struct ab8500_gpadc *gpadc, + const struct ab8500_gpadc_chan_info *ch, + int *ibat) +{ + int ret; + int looplimit = 0; + unsigned long completion_timeout; + u8 val; + u8 low_data, high_data, low_data2, high_data2; + u8 ctrl1; + u8 ctrl23; + unsigned int delay_min = 0; + unsigned int delay_max = 0; + u8 data_low_addr, data_high_addr; + + if (!gpadc) + return -ENODEV; + + /* check if conversion is supported */ + if ((gpadc->irq_sw <= 0) && !ch->hardware_control) + return -ENOTSUPP; + if ((gpadc->irq_hw <= 0) && ch->hardware_control) + return -ENOTSUPP; + + /* Enable vddadc by grabbing PM runtime */ + pm_runtime_get_sync(gpadc->dev); + + /* Check if ADC is not busy, lock and proceed */ + do { + ret = abx500_get_register_interruptible(gpadc->dev, + AB8500_GPADC, AB8500_GPADC_STAT_REG, &val); + if (ret < 0) + goto out; + if (!(val & AB8500_GPADC_STAT_BUSY)) + break; + msleep(20); + } while (++looplimit < 10); + if (looplimit >= 10 && (val & AB8500_GPADC_STAT_BUSY)) { + dev_err(gpadc->dev, "gpadc_conversion: GPADC busy"); + ret = -EINVAL; + goto out; + } + + /* Enable GPADC */ + ctrl1 = AB8500_GPADC_CTRL1_ENABLE; + + /* Select the channel source and set average samples */ + switch (ch->avg_sample) { + case 1: + ctrl23 = ch->id | AB8500_GPADC_CTRL2_AVG_1; + break; + case 4: + ctrl23 = ch->id | AB8500_GPADC_CTRL2_AVG_4; + break; + case 8: + ctrl23 = ch->id | AB8500_GPADC_CTRL2_AVG_8; + break; + default: + ctrl23 = ch->id | AB8500_GPADC_CTRL2_AVG_16; + break; + } + + if (ch->hardware_control) { + ret = abx500_set_register_interruptible(gpadc->dev, + AB8500_GPADC, AB8500_GPADC_CTRL3_REG, ctrl23); + ctrl1 |= AB8500_GPADC_CTRL1_TRIG_ENA; + if (ch->falling_edge) + ctrl1 |= AB8500_GPADC_CTRL1_TRIG_EDGE; + } else { + ret = abx500_set_register_interruptible(gpadc->dev, + AB8500_GPADC, AB8500_GPADC_CTRL2_REG, ctrl23); + } + if (ret < 0) { + dev_err(gpadc->dev, + "gpadc_conversion: set avg samples failed\n"); + goto out; + } + + /* + * Enable ADC, buffering, select rising edge and enable ADC path + * charging current sense if it needed, ABB 3.0 needs some special + * treatment too. + */ + switch (ch->id) { + case AB8500_GPADC_CHAN_MAIN_CHARGER_CURRENT: + case AB8500_GPADC_CHAN_USB_CHARGER_CURRENT: + ctrl1 |= AB8500_GPADC_CTRL1_BUF_ENA | + AB8500_GPADC_CTRL1_ICHAR_ENA; + break; + case AB8500_GPADC_CHAN_BAT_TEMP: + if (!is_ab8500_2p0_or_earlier(gpadc->ab8500)) { + ctrl1 |= AB8500_GPADC_CTRL1_BUF_ENA | + AB8500_GPADC_CTRL1_BTEMP_PULL_UP; + /* + * Delay might be needed for ABB8500 cut 3.0, if not, + * remove when hardware will be available + */ + delay_min = 1000; /* Delay in micro seconds */ + delay_max = 10000; /* large range optimises sleepmode */ + break; + } + /* Fall through */ + default: + ctrl1 |= AB8500_GPADC_CTRL1_BUF_ENA; + break; + } + + /* Write configuration to control register 1 */ + ret = abx500_set_register_interruptible(gpadc->dev, + AB8500_GPADC, AB8500_GPADC_CTRL1_REG, ctrl1); + if (ret < 0) { + dev_err(gpadc->dev, + "gpadc_conversion: set Control register failed\n"); + goto out; + } + + if (delay_min != 0) + usleep_range(delay_min, delay_max); + + if (ch->hardware_control) { + /* Set trigger delay timer */ + ret = abx500_set_register_interruptible(gpadc->dev, + AB8500_GPADC, AB8500_GPADC_AUTO_TIMER_REG, + ch->trig_timer); + if (ret < 0) { + dev_err(gpadc->dev, + "gpadc_conversion: trig timer failed\n"); + goto out; + } + completion_timeout = 2 * HZ; + data_low_addr = AB8500_GPADC_AUTODATAL_REG; + data_high_addr = AB8500_GPADC_AUTODATAH_REG; + } else { + /* Start SW conversion */ + ret = abx500_mask_and_set_register_interruptible(gpadc->dev, + AB8500_GPADC, AB8500_GPADC_CTRL1_REG, + AB8500_GPADC_CTRL1_START_SW_CONV, + AB8500_GPADC_CTRL1_START_SW_CONV); + if (ret < 0) { + dev_err(gpadc->dev, + "gpadc_conversion: start s/w conv failed\n"); + goto out; + } + completion_timeout = msecs_to_jiffies(AB8500_GPADC_CONVERSION_TIME); + data_low_addr = AB8500_GPADC_MANDATAL_REG; + data_high_addr = AB8500_GPADC_MANDATAH_REG; + } + + /* Wait for completion of conversion */ + if (!wait_for_completion_timeout(&gpadc->complete, + completion_timeout)) { + dev_err(gpadc->dev, + "timeout didn't receive GPADC conv interrupt\n"); + ret = -EINVAL; + goto out; + } + + /* Read the converted RAW data */ + ret = abx500_get_register_interruptible(gpadc->dev, + AB8500_GPADC, data_low_addr, &low_data); + if (ret < 0) { + dev_err(gpadc->dev, + "gpadc_conversion: read low data failed\n"); + goto out; + } + + ret = abx500_get_register_interruptible(gpadc->dev, + AB8500_GPADC, data_high_addr, &high_data); + if (ret < 0) { + dev_err(gpadc->dev, + "gpadc_conversion: read high data failed\n"); + goto out; + } + + /* Check if double conversion is required */ + if ((ch->id == AB8500_GPADC_CHAN_BAT_CTRL_AND_IBAT) || + (ch->id == AB8500_GPADC_CHAN_VBAT_MEAS_AND_IBAT) || + (ch->id == AB8500_GPADC_CHAN_VBAT_TRUE_MEAS_AND_IBAT) || + (ch->id == AB8500_GPADC_CHAN_BAT_TEMP_AND_IBAT)) { + + if (ch->hardware_control) { + /* not supported */ + ret = -ENOTSUPP; + dev_err(gpadc->dev, + "gpadc_conversion: only SW double conversion supported\n"); + goto out; + } else { + /* Read the converted RAW data 2 */ + ret = abx500_get_register_interruptible(gpadc->dev, + AB8500_GPADC, AB8540_GPADC_MANDATA2L_REG, + &low_data2); + if (ret < 0) { + dev_err(gpadc->dev, + "gpadc_conversion: read sw low data 2 failed\n"); + goto out; + } + + ret = abx500_get_register_interruptible(gpadc->dev, + AB8500_GPADC, AB8540_GPADC_MANDATA2H_REG, + &high_data2); + if (ret < 0) { + dev_err(gpadc->dev, + "gpadc_conversion: read sw high data 2 failed\n"); + goto out; + } + if (ibat != NULL) { + *ibat = (high_data2 << 8) | low_data2; + } else { + dev_warn(gpadc->dev, + "gpadc_conversion: ibat not stored\n"); + } + + } + } + + /* Disable GPADC */ + ret = abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC, + AB8500_GPADC_CTRL1_REG, AB8500_GPADC_CTRL1_DISABLE); + if (ret < 0) { + dev_err(gpadc->dev, "gpadc_conversion: disable gpadc failed\n"); + goto out; + } + + /* This eventually drops the regulator */ + pm_runtime_mark_last_busy(gpadc->dev); + pm_runtime_put_autosuspend(gpadc->dev); + + return (high_data << 8) | low_data; + +out: + /* + * It has shown to be needed to turn off the GPADC if an error occurs, + * otherwise we might have problem when waiting for the busy bit in the + * GPADC status register to go low. In V1.1 there wait_for_completion + * seems to timeout when waiting for an interrupt.. Not seen in V2.0 + */ + (void) abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC, + AB8500_GPADC_CTRL1_REG, AB8500_GPADC_CTRL1_DISABLE); + pm_runtime_put(gpadc->dev); + dev_err(gpadc->dev, + "gpadc_conversion: Failed to AD convert channel %d\n", ch->id); + + return ret; +} + +/** + * ab8500_bm_gpadcconvend_handler() - isr for gpadc conversion completion + * @irq: irq number + * @data: pointer to the data passed during request irq + * + * This is a interrupt service routine for gpadc conversion completion. + * Notifies the gpadc completion is completed and the converted raw value + * can be read from the registers. + * Returns IRQ status(IRQ_HANDLED) + */ +static irqreturn_t ab8500_bm_gpadcconvend_handler(int irq, void *data) +{ + struct ab8500_gpadc *gpadc = data; + + complete(&gpadc->complete); + + return IRQ_HANDLED; +} + +static int otp_cal_regs[] = { + AB8500_GPADC_CAL_1, + AB8500_GPADC_CAL_2, + AB8500_GPADC_CAL_3, + AB8500_GPADC_CAL_4, + AB8500_GPADC_CAL_5, + AB8500_GPADC_CAL_6, + AB8500_GPADC_CAL_7, +}; + +static int otp4_cal_regs[] = { + AB8540_GPADC_OTP4_REG_7, + AB8540_GPADC_OTP4_REG_6, + AB8540_GPADC_OTP4_REG_5, +}; + +static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc) +{ + int i; + int ret[ARRAY_SIZE(otp_cal_regs)]; + u8 gpadc_cal[ARRAY_SIZE(otp_cal_regs)]; + int ret_otp4[ARRAY_SIZE(otp4_cal_regs)]; + u8 gpadc_otp4[ARRAY_SIZE(otp4_cal_regs)]; + int vmain_high, vmain_low; + int btemp_high, btemp_low; + int vbat_high, vbat_low; + int ibat_high, ibat_low; + s64 V_gain, V_offset, V2A_gain, V2A_offset; + + /* First we read all OTP registers and store the error code */ + for (i = 0; i < ARRAY_SIZE(otp_cal_regs); i++) { + ret[i] = abx500_get_register_interruptible(gpadc->dev, + AB8500_OTP_EMUL, otp_cal_regs[i], &gpadc_cal[i]); + if (ret[i] < 0) { + /* Continue anyway: maybe the other registers are OK */ + dev_err(gpadc->dev, "%s: read otp reg 0x%02x failed\n", + __func__, otp_cal_regs[i]); + } else { + /* Put this in the entropy pool as device-unique */ + add_device_randomness(&ret[i], sizeof(ret[i])); + } + } + + /* + * The ADC calibration data is stored in OTP registers. + * The layout of the calibration data is outlined below and a more + * detailed description can be found in UM0836 + * + * vm_h/l = vmain_high/low + * bt_h/l = btemp_high/low + * vb_h/l = vbat_high/low + * + * Data bits 8500/9540: + * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 + * |.......|.......|.......|.......|.......|.......|.......|....... + * | | vm_h9 | vm_h8 + * |.......|.......|.......|.......|.......|.......|.......|....... + * | | vm_h7 | vm_h6 | vm_h5 | vm_h4 | vm_h3 | vm_h2 + * |.......|.......|.......|.......|.......|.......|.......|....... + * | vm_h1 | vm_h0 | vm_l4 | vm_l3 | vm_l2 | vm_l1 | vm_l0 | bt_h9 + * |.......|.......|.......|.......|.......|.......|.......|....... + * | bt_h8 | bt_h7 | bt_h6 | bt_h5 | bt_h4 | bt_h3 | bt_h2 | bt_h1 + * |.......|.......|.......|.......|.......|.......|.......|....... + * | bt_h0 | bt_l4 | bt_l3 | bt_l2 | bt_l1 | bt_l0 | vb_h9 | vb_h8 + * |.......|.......|.......|.......|.......|.......|.......|....... + * | vb_h7 | vb_h6 | vb_h5 | vb_h4 | vb_h3 | vb_h2 | vb_h1 | vb_h0 + * |.......|.......|.......|.......|.......|.......|.......|....... + * | vb_l5 | vb_l4 | vb_l3 | vb_l2 | vb_l1 | vb_l0 | + * |.......|.......|.......|.......|.......|.......|.......|....... + * + * Data bits 8540: + * OTP2 + * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 + * |.......|.......|.......|.......|.......|.......|.......|....... + * | + * |.......|.......|.......|.......|.......|.......|.......|....... + * | vm_h9 | vm_h8 | vm_h7 | vm_h6 | vm_h5 | vm_h4 | vm_h3 | vm_h2 + * |.......|.......|.......|.......|.......|.......|.......|....... + * | vm_h1 | vm_h0 | vm_l4 | vm_l3 | vm_l2 | vm_l1 | vm_l0 | bt_h9 + * |.......|.......|.......|.......|.......|.......|.......|....... + * | bt_h8 | bt_h7 | bt_h6 | bt_h5 | bt_h4 | bt_h3 | bt_h2 | bt_h1 + * |.......|.......|.......|.......|.......|.......|.......|....... + * | bt_h0 | bt_l4 | bt_l3 | bt_l2 | bt_l1 | bt_l0 | vb_h9 | vb_h8 + * |.......|.......|.......|.......|.......|.......|.......|....... + * | vb_h7 | vb_h6 | vb_h5 | vb_h4 | vb_h3 | vb_h2 | vb_h1 | vb_h0 + * |.......|.......|.......|.......|.......|.......|.......|....... + * | vb_l5 | vb_l4 | vb_l3 | vb_l2 | vb_l1 | vb_l0 | + * |.......|.......|.......|.......|.......|.......|.......|....... + * + * Data bits 8540: + * OTP4 + * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 + * |.......|.......|.......|.......|.......|.......|.......|....... + * | | ib_h9 | ib_h8 | ib_h7 + * |.......|.......|.......|.......|.......|.......|.......|....... + * | ib_h6 | ib_h5 | ib_h4 | ib_h3 | ib_h2 | ib_h1 | ib_h0 | ib_l5 + * |.......|.......|.......|.......|.......|.......|.......|....... + * | ib_l4 | ib_l3 | ib_l2 | ib_l1 | ib_l0 | + * + * + * Ideal output ADC codes corresponding to injected input voltages + * during manufacturing is: + * + * vmain_high: Vin = 19500mV / ADC ideal code = 997 + * vmain_low: Vin = 315mV / ADC ideal code = 16 + * btemp_high: Vin = 1300mV / ADC ideal code = 985 + * btemp_low: Vin = 21mV / ADC ideal code = 16 + * vbat_high: Vin = 4700mV / ADC ideal code = 982 + * vbat_low: Vin = 2380mV / ADC ideal code = 33 + */ + + if (is_ab8540(gpadc->ab8500)) { + /* Calculate gain and offset for VMAIN if all reads succeeded*/ + if (!(ret[1] < 0 || ret[2] < 0)) { + vmain_high = (((gpadc_cal[1] & 0xFF) << 2) | + ((gpadc_cal[2] & 0xC0) >> 6)); + vmain_low = ((gpadc_cal[2] & 0x3E) >> 1); + + gpadc->cal_data[AB8500_CAL_VMAIN].otp_calib_hi = + (u16)vmain_high; + gpadc->cal_data[AB8500_CAL_VMAIN].otp_calib_lo = + (u16)vmain_low; + + gpadc->cal_data[AB8500_CAL_VMAIN].gain = AB8500_GPADC_CALIB_SCALE * + (19500 - 315) / (vmain_high - vmain_low); + gpadc->cal_data[AB8500_CAL_VMAIN].offset = AB8500_GPADC_CALIB_SCALE * + 19500 - (AB8500_GPADC_CALIB_SCALE * (19500 - 315) / + (vmain_high - vmain_low)) * vmain_high; + } else { + gpadc->cal_data[AB8500_CAL_VMAIN].gain = 0; + } + + /* Read IBAT calibration Data */ + for (i = 0; i < ARRAY_SIZE(otp4_cal_regs); i++) { + ret_otp4[i] = abx500_get_register_interruptible( + gpadc->dev, AB8500_OTP_EMUL, + otp4_cal_regs[i], &gpadc_otp4[i]); + if (ret_otp4[i] < 0) + dev_err(gpadc->dev, + "%s: read otp4 reg 0x%02x failed\n", + __func__, otp4_cal_regs[i]); + } + + /* Calculate gain and offset for IBAT if all reads succeeded */ + if (!(ret_otp4[0] < 0 || ret_otp4[1] < 0 || ret_otp4[2] < 0)) { + ibat_high = (((gpadc_otp4[0] & 0x07) << 7) | + ((gpadc_otp4[1] & 0xFE) >> 1)); + ibat_low = (((gpadc_otp4[1] & 0x01) << 5) | + ((gpadc_otp4[2] & 0xF8) >> 3)); + + gpadc->cal_data[AB8500_CAL_IBAT].otp_calib_hi = + (u16)ibat_high; + gpadc->cal_data[AB8500_CAL_IBAT].otp_calib_lo = + (u16)ibat_low; + + V_gain = ((AB8500_GPADC_IBAT_VDROP_H - AB8500_GPADC_IBAT_VDROP_L) + << AB8500_GPADC_CALIB_SHIFT_IBAT) / (ibat_high - ibat_low); + + V_offset = (AB8500_GPADC_IBAT_VDROP_H << AB8500_GPADC_CALIB_SHIFT_IBAT) - + (((AB8500_GPADC_IBAT_VDROP_H - AB8500_GPADC_IBAT_VDROP_L) << + AB8500_GPADC_CALIB_SHIFT_IBAT) / (ibat_high - ibat_low)) + * ibat_high; + /* + * Result obtained is in mV (at a scale factor), + * we need to calculate gain and offset to get mA + */ + V2A_gain = (AB8500_ADC_CH_IBAT_MAX - AB8500_ADC_CH_IBAT_MIN)/ + (AB8500_ADC_CH_IBAT_MAX_V - AB8500_ADC_CH_IBAT_MIN_V); + V2A_offset = ((AB8500_ADC_CH_IBAT_MAX_V * AB8500_ADC_CH_IBAT_MIN - + AB8500_ADC_CH_IBAT_MAX * AB8500_ADC_CH_IBAT_MIN_V) + << AB8500_GPADC_CALIB_SHIFT_IBAT) + / (AB8500_ADC_CH_IBAT_MAX_V - AB8500_ADC_CH_IBAT_MIN_V); + + gpadc->cal_data[AB8500_CAL_IBAT].gain = + V_gain * V2A_gain; + gpadc->cal_data[AB8500_CAL_IBAT].offset = + V_offset * V2A_gain + V2A_offset; + } else { + gpadc->cal_data[AB8500_CAL_IBAT].gain = 0; + } + } else { + /* Calculate gain and offset for VMAIN if all reads succeeded */ + if (!(ret[0] < 0 || ret[1] < 0 || ret[2] < 0)) { + vmain_high = (((gpadc_cal[0] & 0x03) << 8) | + ((gpadc_cal[1] & 0x3F) << 2) | + ((gpadc_cal[2] & 0xC0) >> 6)); + vmain_low = ((gpadc_cal[2] & 0x3E) >> 1); + + gpadc->cal_data[AB8500_CAL_VMAIN].otp_calib_hi = + (u16)vmain_high; + gpadc->cal_data[AB8500_CAL_VMAIN].otp_calib_lo = + (u16)vmain_low; + + gpadc->cal_data[AB8500_CAL_VMAIN].gain = AB8500_GPADC_CALIB_SCALE * + (19500 - 315) / (vmain_high - vmain_low); + + gpadc->cal_data[AB8500_CAL_VMAIN].offset = AB8500_GPADC_CALIB_SCALE * + 19500 - (AB8500_GPADC_CALIB_SCALE * (19500 - 315) / + (vmain_high - vmain_low)) * vmain_high; + } else { + gpadc->cal_data[AB8500_CAL_VMAIN].gain = 0; + } + } + + /* Calculate gain and offset for BTEMP if all reads succeeded */ + if (!(ret[2] < 0 || ret[3] < 0 || ret[4] < 0)) { + btemp_high = (((gpadc_cal[2] & 0x01) << 9) | + (gpadc_cal[3] << 1) | ((gpadc_cal[4] & 0x80) >> 7)); + btemp_low = ((gpadc_cal[4] & 0x7C) >> 2); + + gpadc->cal_data[AB8500_CAL_BTEMP].otp_calib_hi = (u16)btemp_high; + gpadc->cal_data[AB8500_CAL_BTEMP].otp_calib_lo = (u16)btemp_low; + + gpadc->cal_data[AB8500_CAL_BTEMP].gain = + AB8500_GPADC_CALIB_SCALE * (1300 - 21) / (btemp_high - btemp_low); + gpadc->cal_data[AB8500_CAL_BTEMP].offset = AB8500_GPADC_CALIB_SCALE * 1300 - + (AB8500_GPADC_CALIB_SCALE * (1300 - 21) / (btemp_high - btemp_low)) + * btemp_high; + } else { + gpadc->cal_data[AB8500_CAL_BTEMP].gain = 0; + } + + /* Calculate gain and offset for VBAT if all reads succeeded */ + if (!(ret[4] < 0 || ret[5] < 0 || ret[6] < 0)) { + vbat_high = (((gpadc_cal[4] & 0x03) << 8) | gpadc_cal[5]); + vbat_low = ((gpadc_cal[6] & 0xFC) >> 2); + + gpadc->cal_data[AB8500_CAL_VBAT].otp_calib_hi = (u16)vbat_high; + gpadc->cal_data[AB8500_CAL_VBAT].otp_calib_lo = (u16)vbat_low; + + gpadc->cal_data[AB8500_CAL_VBAT].gain = AB8500_GPADC_CALIB_SCALE * + (4700 - 2380) / (vbat_high - vbat_low); + gpadc->cal_data[AB8500_CAL_VBAT].offset = AB8500_GPADC_CALIB_SCALE * 4700 - + (AB8500_GPADC_CALIB_SCALE * (4700 - 2380) / + (vbat_high - vbat_low)) * vbat_high; + } else { + gpadc->cal_data[AB8500_CAL_VBAT].gain = 0; + } +} + +static int ab8500_gpadc_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct ab8500_gpadc *gpadc = iio_priv(indio_dev); + const struct ab8500_gpadc_chan_info *ch; + int raw_val; + int processed; + + ch = ab8500_gpadc_get_channel(gpadc, chan->address); + if (!ch) { + dev_err(gpadc->dev, "no such channel %lu\n", + chan->address); + return -EINVAL; + } + + raw_val = ab8500_gpadc_read(gpadc, ch, NULL); + if (raw_val < 0) + return raw_val; + + if (mask == IIO_CHAN_INFO_RAW) { + *val = raw_val; + return IIO_VAL_INT; + } + + if (mask == IIO_CHAN_INFO_PROCESSED) { + processed = ab8500_gpadc_ad_to_voltage(gpadc, ch->id, raw_val); + if (processed < 0) + return processed; + + /* Return millivolt or milliamps or millicentigrades */ + *val = processed * 1000; + return IIO_VAL_INT; + } + + return -EINVAL; +} + +static int ab8500_gpadc_of_xlate(struct iio_dev *indio_dev, + const struct of_phandle_args *iiospec) +{ + int i; + + for (i = 0; i < indio_dev->num_channels; i++) + if (indio_dev->channels[i].channel == iiospec->args[0]) + return i; + + return -EINVAL; +} + +static const struct iio_info ab8500_gpadc_info = { + .of_xlate = ab8500_gpadc_of_xlate, + .read_raw = ab8500_gpadc_read_raw, +}; + +#ifdef CONFIG_PM +static int ab8500_gpadc_runtime_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ab8500_gpadc *gpadc = iio_priv(indio_dev); + + regulator_disable(gpadc->vddadc); + + return 0; +} + +static int ab8500_gpadc_runtime_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct ab8500_gpadc *gpadc = iio_priv(indio_dev); + int ret; + + ret = regulator_enable(gpadc->vddadc); + if (ret) + dev_err(dev, "Failed to enable vddadc: %d\n", ret); + + return ret; +} +#endif + +/** + * ab8500_gpadc_parse_channel() - process devicetree channel configuration + * @dev: pointer to containing device + * @np: device tree node for the channel to configure + * @ch: channel info to fill in + * @iio_chan: IIO channel specification to fill in + * + * The devicetree will set up the channel for use with the specific device, + * and define usage for things like AUX GPADC inputs more precisely. + */ +static int ab8500_gpadc_parse_channel(struct device *dev, + struct device_node *np, + struct ab8500_gpadc_chan_info *ch, + struct iio_chan_spec *iio_chan) +{ + const char *name = np->name; + u32 chan; + int ret; + + ret = of_property_read_u32(np, "reg", &chan); + if (ret) { + dev_err(dev, "invalid channel number %s\n", name); + return ret; + } + if (chan > AB8500_GPADC_CHAN_BAT_TEMP_AND_IBAT) { + dev_err(dev, "%s channel number out of range %d\n", name, chan); + return -EINVAL; + } + + iio_chan->channel = chan; + iio_chan->datasheet_name = name; + iio_chan->indexed = 1; + iio_chan->address = chan; + iio_chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_PROCESSED); + /* Most are voltages (also temperatures), some are currents */ + if ((chan == AB8500_GPADC_CHAN_MAIN_CHARGER_CURRENT) || + (chan == AB8500_GPADC_CHAN_USB_CHARGER_CURRENT)) + iio_chan->type = IIO_CURRENT; + else + iio_chan->type = IIO_VOLTAGE; + + ch->id = chan; + + /* Sensible defaults */ + ch->avg_sample = 16; + ch->hardware_control = false; + ch->falling_edge = false; + ch->trig_timer = 0; + + return 0; +} + +/** + * ab8500_gpadc_parse_channels() - Parse the GPADC channels from DT + * @gpadc: the GPADC to configure the channels for + * @np: device tree node containing the channel configurations + * @chans: the IIO channels we parsed + * @nchans: the number of IIO channels we parsed + */ +static int ab8500_gpadc_parse_channels(struct ab8500_gpadc *gpadc, + struct device_node *np, + struct iio_chan_spec **chans_parsed, + unsigned int *nchans_parsed) +{ + struct device_node *child; + struct ab8500_gpadc_chan_info *ch; + struct iio_chan_spec *iio_chans; + unsigned int nchans; + int i; + + nchans = of_get_available_child_count(np); + if (!nchans) { + dev_err(gpadc->dev, "no channel children\n"); + return -ENODEV; + } + dev_info(gpadc->dev, "found %d ADC channels\n", nchans); + + iio_chans = devm_kcalloc(gpadc->dev, nchans, + sizeof(*iio_chans), GFP_KERNEL); + if (!iio_chans) + return -ENOMEM; + + gpadc->chans = devm_kcalloc(gpadc->dev, nchans, + sizeof(*gpadc->chans), GFP_KERNEL); + if (!gpadc->chans) + return -ENOMEM; + + i = 0; + for_each_available_child_of_node(np, child) { + struct iio_chan_spec *iio_chan; + int ret; + + ch = &gpadc->chans[i]; + iio_chan = &iio_chans[i]; + + ret = ab8500_gpadc_parse_channel(gpadc->dev, child, ch, + iio_chan); + if (ret) { + of_node_put(child); + return ret; + } + i++; + } + gpadc->nchans = nchans; + *chans_parsed = iio_chans; + *nchans_parsed = nchans; + + return 0; +} + +static int ab8500_gpadc_probe(struct platform_device *pdev) +{ + struct ab8500_gpadc *gpadc; + struct iio_dev *indio_dev; + struct device *dev = &pdev->dev; + struct device_node *np = pdev->dev.of_node; + struct iio_chan_spec *iio_chans; + unsigned int n_iio_chans; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*gpadc)); + if (!indio_dev) + return -ENOMEM; + + platform_set_drvdata(pdev, indio_dev); + gpadc = iio_priv(indio_dev); + + gpadc->dev = dev; + gpadc->ab8500 = dev_get_drvdata(dev->parent); + + ret = ab8500_gpadc_parse_channels(gpadc, np, &iio_chans, &n_iio_chans); + if (ret) + return ret; + + gpadc->irq_sw = platform_get_irq_byname(pdev, "SW_CONV_END"); + if (gpadc->irq_sw < 0) { + dev_err(dev, "failed to get platform sw_conv_end irq\n"); + return gpadc->irq_sw; + } + + gpadc->irq_hw = platform_get_irq_byname(pdev, "HW_CONV_END"); + if (gpadc->irq_hw < 0) { + dev_err(dev, "failed to get platform hw_conv_end irq\n"); + return gpadc->irq_hw; + } + + /* Initialize completion used to notify completion of conversion */ + init_completion(&gpadc->complete); + + /* Request interrupts */ + ret = devm_request_threaded_irq(dev, gpadc->irq_sw, NULL, + ab8500_bm_gpadcconvend_handler, IRQF_NO_SUSPEND | IRQF_ONESHOT, + "ab8500-gpadc-sw", gpadc); + if (ret < 0) { + dev_err(dev, + "failed to request sw conversion irq %d\n", + gpadc->irq_sw); + return ret; + } + + ret = devm_request_threaded_irq(dev, gpadc->irq_hw, NULL, + ab8500_bm_gpadcconvend_handler, IRQF_NO_SUSPEND | IRQF_ONESHOT, + "ab8500-gpadc-hw", gpadc); + if (ret < 0) { + dev_err(dev, + "Failed to request hw conversion irq: %d\n", + gpadc->irq_hw); + return ret; + } + + /* The VTVout LDO used to power the AB8500 GPADC */ + gpadc->vddadc = devm_regulator_get(dev, "vddadc"); + if (IS_ERR(gpadc->vddadc)) { + ret = PTR_ERR(gpadc->vddadc); + dev_err(dev, "failed to get vddadc\n"); + return ret; + } + + ret = regulator_enable(gpadc->vddadc); + if (ret) { + dev_err(dev, "failed to enable vddadc: %d\n", ret); + return ret; + } + + /* Enable runtime PM */ + pm_runtime_get_noresume(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + pm_runtime_set_autosuspend_delay(dev, AB8500_GPADC_AUTOSUSPEND_DELAY); + pm_runtime_use_autosuspend(dev); + + ab8500_gpadc_read_calibration_data(gpadc); + + pm_runtime_put(dev); + + indio_dev->dev.parent = dev; + indio_dev->dev.of_node = np; + indio_dev->name = "ab8500-gpadc"; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &ab8500_gpadc_info; + indio_dev->channels = iio_chans; + indio_dev->num_channels = n_iio_chans; + + ret = devm_iio_device_register(dev, indio_dev); + if (ret) + goto out_dis_pm; + + return 0; + +out_dis_pm: + pm_runtime_get_sync(dev); + pm_runtime_put_noidle(dev); + pm_runtime_disable(dev); + regulator_disable(gpadc->vddadc); + + return ret; +} + +static int ab8500_gpadc_remove(struct platform_device *pdev) +{ + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct ab8500_gpadc *gpadc = iio_priv(indio_dev); + + pm_runtime_get_sync(gpadc->dev); + pm_runtime_put_noidle(gpadc->dev); + pm_runtime_disable(gpadc->dev); + regulator_disable(gpadc->vddadc); + + return 0; +} + +static const struct dev_pm_ops ab8500_gpadc_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(ab8500_gpadc_runtime_suspend, + ab8500_gpadc_runtime_resume, + NULL) +}; + +static struct platform_driver ab8500_gpadc_driver = { + .probe = ab8500_gpadc_probe, + .remove = ab8500_gpadc_remove, + .driver = { + .name = "ab8500-gpadc", + .pm = &ab8500_gpadc_pm_ops, + }, +}; +builtin_platform_driver(ab8500_gpadc_driver); diff --git a/drivers/iio/adc/ad7949.c b/drivers/iio/adc/ad7949.c index ac0ffff6c5ae..5c2b3446fa4a 100644 --- a/drivers/iio/adc/ad7949.c +++ b/drivers/iio/adc/ad7949.c @@ -54,38 +54,20 @@ struct ad7949_adc_chip { u8 resolution; u16 cfg; unsigned int current_channel; - u32 buffer ____cacheline_aligned; + u16 buffer ____cacheline_aligned; }; -static bool ad7949_spi_cfg_is_read_back(struct ad7949_adc_chip *ad7949_adc) -{ - if (!(ad7949_adc->cfg & AD7949_CFG_READ_BACK)) - return true; - - return false; -} - -static int ad7949_spi_bits_per_word(struct ad7949_adc_chip *ad7949_adc) -{ - int ret = ad7949_adc->resolution; - - if (ad7949_spi_cfg_is_read_back(ad7949_adc)) - ret += AD7949_CFG_REG_SIZE_BITS; - - return ret; -} - static int ad7949_spi_write_cfg(struct ad7949_adc_chip *ad7949_adc, u16 val, u16 mask) { int ret; - int bits_per_word = ad7949_spi_bits_per_word(ad7949_adc); + int bits_per_word = ad7949_adc->resolution; int shift = bits_per_word - AD7949_CFG_REG_SIZE_BITS; struct spi_message msg; struct spi_transfer tx[] = { { .tx_buf = &ad7949_adc->buffer, - .len = 4, + .len = 2, .bits_per_word = bits_per_word, }, }; @@ -107,13 +89,13 @@ static int ad7949_spi_read_channel(struct ad7949_adc_chip *ad7949_adc, int *val, unsigned int channel) { int ret; - int bits_per_word = ad7949_spi_bits_per_word(ad7949_adc); + int bits_per_word = ad7949_adc->resolution; int mask = GENMASK(ad7949_adc->resolution, 0); struct spi_message msg; struct spi_transfer tx[] = { { .rx_buf = &ad7949_adc->buffer, - .len = 4, + .len = 2, .bits_per_word = bits_per_word, }, }; @@ -138,10 +120,7 @@ static int ad7949_spi_read_channel(struct ad7949_adc_chip *ad7949_adc, int *val, ad7949_adc->current_channel = channel; - if (ad7949_spi_cfg_is_read_back(ad7949_adc)) - *val = (ad7949_adc->buffer >> AD7949_CFG_REG_SIZE_BITS) & mask; - else - *val = ad7949_adc->buffer & mask; + *val = ad7949_adc->buffer & mask; return 0; } diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c index 2640b75fb774..8ba90486c787 100644 --- a/drivers/iio/adc/ad_sigma_delta.c +++ b/drivers/iio/adc/ad_sigma_delta.c @@ -205,7 +205,7 @@ int ad_sd_reset(struct ad_sigma_delta *sigma_delta, } EXPORT_SYMBOL_GPL(ad_sd_reset); -static int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta, +int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta, unsigned int mode, unsigned int channel) { int ret; @@ -242,6 +242,7 @@ out: return ret; } +EXPORT_SYMBOL_GPL(ad_sd_calibrate); /** * ad_sd_calibrate_all() - Performs channel calibration diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c index a2837a0e7cba..e1850f3d5cf3 100644 --- a/drivers/iio/adc/at91-sama5d2_adc.c +++ b/drivers/iio/adc/at91-sama5d2_adc.c @@ -1483,7 +1483,7 @@ dma_free_area: st->dma_st.rx_buf, st->dma_st.rx_dma_buf); dma_chan_disable: dma_release_channel(st->dma_st.dma_chan); - st->dma_st.dma_chan = 0; + st->dma_st.dma_chan = NULL; dma_exit: dev_info(&pdev->dev, "continuing without DMA support\n"); } @@ -1506,7 +1506,7 @@ static void at91_adc_dma_disable(struct platform_device *pdev) dma_free_coherent(st->dma_st.dma_chan->device->dev, pages * PAGE_SIZE, st->dma_st.rx_buf, st->dma_st.rx_dma_buf); dma_release_channel(st->dma_st.dma_chan); - st->dma_st.dma_chan = 0; + st->dma_st.dma_chan = NULL; dev_info(&pdev->dev, "continuing without DMA support\n"); } diff --git a/drivers/iio/adc/cpcap-adc.c b/drivers/iio/adc/cpcap-adc.c index 2d616cafe75f..5086a337f4c9 100644 --- a/drivers/iio/adc/cpcap-adc.c +++ b/drivers/iio/adc/cpcap-adc.c @@ -1008,7 +1008,7 @@ static int cpcap_adc_probe(struct platform_device *pdev) error = devm_request_threaded_irq(&pdev->dev, ddata->irq, NULL, cpcap_adc_irq_thread, - IRQF_TRIGGER_NONE, + IRQF_TRIGGER_NONE | IRQF_ONESHOT, "cpcap-adc", indio_dev); if (error) { dev_err(&pdev->dev, "could not get irq: %i\n", diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c index 42a3ced11fbd..2df7d057b249 100644 --- a/drivers/iio/adc/exynos_adc.c +++ b/drivers/iio/adc/exynos_adc.c @@ -651,7 +651,7 @@ static irqreturn_t exynos_ts_isr(int irq, void *dev_id) input_sync(info->input); usleep_range(1000, 1100); - }; + } writel(0, ADC_V1_CLRINTPNDNUP(info->regs)); @@ -769,7 +769,6 @@ static int exynos_adc_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct s3c2410_ts_mach_info *pdata = dev_get_platdata(&pdev->dev); struct iio_dev *indio_dev = NULL; - struct resource *mem; bool has_ts = false; int ret = -ENODEV; int irq; @@ -788,8 +787,7 @@ static int exynos_adc_probe(struct platform_device *pdev) return -EINVAL; } - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - info->regs = devm_ioremap_resource(&pdev->dev, mem); + info->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(info->regs)) return PTR_ERR(info->regs); diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c index 62e6c8badd22..c8686558429b 100644 --- a/drivers/iio/adc/hx711.c +++ b/drivers/iio/adc/hx711.c @@ -23,6 +23,7 @@ /* gain to pulse and scale conversion */ #define HX711_GAIN_MAX 3 +#define HX711_RESET_GAIN 128 struct hx711_gain_to_scale { int gain; @@ -185,8 +186,7 @@ static int hx711_wait_for_ready(struct hx711_data *hx711_data) static int hx711_reset(struct hx711_data *hx711_data) { - int ret; - int val = gpiod_get_value(hx711_data->gpiod_dout); + int val = hx711_wait_for_ready(hx711_data); if (val) { /* @@ -202,22 +202,10 @@ static int hx711_reset(struct hx711_data *hx711_data) msleep(10); gpiod_set_value(hx711_data->gpiod_pd_sck, 0); - ret = hx711_wait_for_ready(hx711_data); - if (ret) - return ret; - /* - * after a reset the gain is 128 so we do a dummy read - * to set the gain for the next read - */ - ret = hx711_read(hx711_data); - if (ret < 0) - return ret; - - /* - * after a dummy read we need to wait vor readiness - * for not mixing gain pulses with the clock - */ val = hx711_wait_for_ready(hx711_data); + + /* after a reset the gain is 128 */ + hx711_data->gain_set = HX711_RESET_GAIN; } return val; diff --git a/drivers/iio/adc/ingenic-adc.c b/drivers/iio/adc/ingenic-adc.c index e234970b7150..7a53c2f8d438 100644 --- a/drivers/iio/adc/ingenic-adc.c +++ b/drivers/iio/adc/ingenic-adc.c @@ -25,9 +25,13 @@ #define JZ_ADC_REG_ADSDAT 0x20 #define JZ_ADC_REG_ADCLK 0x28 +#define JZ_ADC_REG_ENABLE_PD BIT(7) +#define JZ_ADC_REG_CFG_AUX_MD (BIT(0) | BIT(1)) #define JZ_ADC_REG_CFG_BAT_MD BIT(4) #define JZ_ADC_REG_ADCLK_CLKDIV_LSB 0 -#define JZ_ADC_REG_ADCLK_CLKDIV10US_LSB 16 +#define JZ4725B_ADC_REG_ADCLK_CLKDIV10US_LSB 16 +#define JZ4770_ADC_REG_ADCLK_CLKDIV10US_LSB 8 +#define JZ4770_ADC_REG_ADCLK_CLKDIVMS_LSB 16 #define JZ_ADC_AUX_VREF 3300 #define JZ_ADC_AUX_VREF_BITS 12 @@ -37,6 +41,8 @@ #define JZ4725B_ADC_BATTERY_HIGH_VREF_BITS 10 #define JZ4740_ADC_BATTERY_HIGH_VREF (7500 * 0.986) #define JZ4740_ADC_BATTERY_HIGH_VREF_BITS 12 +#define JZ4770_ADC_BATTERY_VREF 6600 +#define JZ4770_ADC_BATTERY_VREF_BITS 12 struct ingenic_adc; @@ -47,6 +53,8 @@ struct ingenic_adc_soc_data { size_t battery_raw_avail_size; const int *battery_scale_avail; size_t battery_scale_avail_size; + unsigned int battery_vref_mode: 1; + unsigned int has_aux2: 1; int (*init_clk_div)(struct device *dev, struct ingenic_adc *adc); }; @@ -54,6 +62,7 @@ struct ingenic_adc { void __iomem *base; struct clk *clk; struct mutex lock; + struct mutex aux_lock; const struct ingenic_adc_soc_data *soc_data; bool low_vref_mode; }; @@ -120,6 +129,8 @@ static int ingenic_adc_write_raw(struct iio_dev *iio_dev, case IIO_CHAN_INFO_SCALE: switch (chan->channel) { case INGENIC_ADC_BATTERY: + if (!adc->soc_data->battery_vref_mode) + return -EINVAL; if (val > JZ_ADC_BATTERY_LOW_VREF) { ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_BAT_MD, @@ -158,6 +169,14 @@ static const int jz4740_adc_battery_scale_avail[] = { JZ_ADC_BATTERY_LOW_VREF, JZ_ADC_BATTERY_LOW_VREF_BITS, }; +static const int jz4770_adc_battery_raw_avail[] = { + 0, 1, (1 << JZ4770_ADC_BATTERY_VREF_BITS) - 1, +}; + +static const int jz4770_adc_battery_scale_avail[] = { + JZ4770_ADC_BATTERY_VREF, JZ4770_ADC_BATTERY_VREF_BITS, +}; + static int jz4725b_adc_init_clk_div(struct device *dev, struct ingenic_adc *adc) { struct clk *parent_clk; @@ -187,7 +206,45 @@ static int jz4725b_adc_init_clk_div(struct device *dev, struct ingenic_adc *adc) /* We also need a divider that produces a 10us clock. */ div_10us = DIV_ROUND_UP(rate, 100000); - writel(((div_10us - 1) << JZ_ADC_REG_ADCLK_CLKDIV10US_LSB) | + writel(((div_10us - 1) << JZ4725B_ADC_REG_ADCLK_CLKDIV10US_LSB) | + (div_main - 1) << JZ_ADC_REG_ADCLK_CLKDIV_LSB, + adc->base + JZ_ADC_REG_ADCLK); + + return 0; +} + +static int jz4770_adc_init_clk_div(struct device *dev, struct ingenic_adc *adc) +{ + struct clk *parent_clk; + unsigned long parent_rate, rate; + unsigned int div_main, div_ms, div_10us; + + parent_clk = clk_get_parent(adc->clk); + if (!parent_clk) { + dev_err(dev, "ADC clock has no parent\n"); + return -ENODEV; + } + parent_rate = clk_get_rate(parent_clk); + + /* + * The JZ4770 ADC works at 20 kHz to 200 kHz. + * We pick the highest rate possible. + */ + div_main = DIV_ROUND_UP(parent_rate, 200000); + div_main = clamp(div_main, 1u, 256u); + rate = parent_rate / div_main; + if (rate < 20000 || rate > 200000) { + dev_err(dev, "No valid divider for ADC main clock\n"); + return -EINVAL; + } + + /* We also need a divider that produces a 10us clock. */ + div_10us = DIV_ROUND_UP(rate, 10000); + /* And another, which produces a 1ms clock. */ + div_ms = DIV_ROUND_UP(rate, 1000); + + writel(((div_ms - 1) << JZ4770_ADC_REG_ADCLK_CLKDIVMS_LSB) | + ((div_10us - 1) << JZ4770_ADC_REG_ADCLK_CLKDIV10US_LSB) | (div_main - 1) << JZ_ADC_REG_ADCLK_CLKDIV_LSB, adc->base + JZ_ADC_REG_ADCLK); @@ -201,6 +258,8 @@ static const struct ingenic_adc_soc_data jz4725b_adc_soc_data = { .battery_raw_avail_size = ARRAY_SIZE(jz4725b_adc_battery_raw_avail), .battery_scale_avail = jz4725b_adc_battery_scale_avail, .battery_scale_avail_size = ARRAY_SIZE(jz4725b_adc_battery_scale_avail), + .battery_vref_mode = true, + .has_aux2 = false, .init_clk_div = jz4725b_adc_init_clk_div, }; @@ -211,9 +270,23 @@ static const struct ingenic_adc_soc_data jz4740_adc_soc_data = { .battery_raw_avail_size = ARRAY_SIZE(jz4740_adc_battery_raw_avail), .battery_scale_avail = jz4740_adc_battery_scale_avail, .battery_scale_avail_size = ARRAY_SIZE(jz4740_adc_battery_scale_avail), + .battery_vref_mode = true, + .has_aux2 = false, .init_clk_div = NULL, /* no ADCLK register on JZ4740 */ }; +static const struct ingenic_adc_soc_data jz4770_adc_soc_data = { + .battery_high_vref = JZ4770_ADC_BATTERY_VREF, + .battery_high_vref_bits = JZ4770_ADC_BATTERY_VREF_BITS, + .battery_raw_avail = jz4770_adc_battery_raw_avail, + .battery_raw_avail_size = ARRAY_SIZE(jz4770_adc_battery_raw_avail), + .battery_scale_avail = jz4770_adc_battery_scale_avail, + .battery_scale_avail_size = ARRAY_SIZE(jz4770_adc_battery_scale_avail), + .battery_vref_mode = false, + .has_aux2 = true, + .init_clk_div = jz4770_adc_init_clk_div, +}; + static int ingenic_adc_read_avail(struct iio_dev *iio_dev, struct iio_chan_spec const *chan, const int **vals, @@ -239,6 +312,42 @@ static int ingenic_adc_read_avail(struct iio_dev *iio_dev, }; } +static int ingenic_adc_read_chan_info_raw(struct ingenic_adc *adc, + struct iio_chan_spec const *chan, + int *val) +{ + int bit, ret, engine = (chan->channel == INGENIC_ADC_BATTERY); + + /* We cannot sample AUX/AUX2 in parallel. */ + mutex_lock(&adc->aux_lock); + if (adc->soc_data->has_aux2 && engine == 0) { + bit = BIT(chan->channel == INGENIC_ADC_AUX2); + ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_AUX_MD, bit); + } + + clk_enable(adc->clk); + ret = ingenic_adc_capture(adc, engine); + if (ret) + goto out; + + switch (chan->channel) { + case INGENIC_ADC_AUX: + case INGENIC_ADC_AUX2: + *val = readw(adc->base + JZ_ADC_REG_ADSDAT); + break; + case INGENIC_ADC_BATTERY: + *val = readw(adc->base + JZ_ADC_REG_ADBDAT); + break; + } + + ret = IIO_VAL_INT; +out: + clk_disable(adc->clk); + mutex_unlock(&adc->aux_lock); + + return ret; +} + static int ingenic_adc_read_raw(struct iio_dev *iio_dev, struct iio_chan_spec const *chan, int *val, @@ -246,32 +355,14 @@ static int ingenic_adc_read_raw(struct iio_dev *iio_dev, long m) { struct ingenic_adc *adc = iio_priv(iio_dev); - int ret; switch (m) { case IIO_CHAN_INFO_RAW: - clk_enable(adc->clk); - ret = ingenic_adc_capture(adc, chan->channel); - if (ret) { - clk_disable(adc->clk); - return ret; - } - - switch (chan->channel) { - case INGENIC_ADC_AUX: - *val = readw(adc->base + JZ_ADC_REG_ADSDAT); - break; - case INGENIC_ADC_BATTERY: - *val = readw(adc->base + JZ_ADC_REG_ADBDAT); - break; - } - - clk_disable(adc->clk); - - return IIO_VAL_INT; + return ingenic_adc_read_chan_info_raw(adc, chan, val); case IIO_CHAN_INFO_SCALE: switch (chan->channel) { case INGENIC_ADC_AUX: + case INGENIC_ADC_AUX2: *val = JZ_ADC_AUX_VREF; *val2 = JZ_ADC_AUX_VREF_BITS; break; @@ -322,6 +413,14 @@ static const struct iio_chan_spec ingenic_channels[] = { .indexed = 1, .channel = INGENIC_ADC_BATTERY, }, + { /* Must always be last in the array. */ + .extend_name = "aux2", + .type = IIO_VOLTAGE, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + .indexed = 1, + .channel = INGENIC_ADC_AUX2, + }, }; static int ingenic_adc_probe(struct platform_device *pdev) @@ -343,6 +442,7 @@ static int ingenic_adc_probe(struct platform_device *pdev) adc = iio_priv(iio_dev); mutex_init(&adc->lock); + mutex_init(&adc->aux_lock); adc->soc_data = soc_data; mem_base = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -374,6 +474,7 @@ static int ingenic_adc_probe(struct platform_device *pdev) /* Put hardware in a known passive state. */ writeb(0x00, adc->base + JZ_ADC_REG_ENABLE); writeb(0xff, adc->base + JZ_ADC_REG_CTRL); + usleep_range(2000, 3000); /* Must wait at least 2ms. */ clk_disable(adc->clk); ret = devm_add_action_or_reset(dev, ingenic_adc_clk_cleanup, adc->clk); @@ -387,6 +488,9 @@ static int ingenic_adc_probe(struct platform_device *pdev) iio_dev->modes = INDIO_DIRECT_MODE; iio_dev->channels = ingenic_channels; iio_dev->num_channels = ARRAY_SIZE(ingenic_channels); + /* Remove AUX2 from the list of supported channels. */ + if (!adc->soc_data->has_aux2) + iio_dev->num_channels -= 1; iio_dev->info = &ingenic_adc_info; ret = devm_iio_device_register(dev, iio_dev); @@ -400,6 +504,7 @@ static int ingenic_adc_probe(struct platform_device *pdev) static const struct of_device_id ingenic_adc_of_match[] = { { .compatible = "ingenic,jz4725b-adc", .data = &jz4725b_adc_soc_data, }, { .compatible = "ingenic,jz4740-adc", .data = &jz4740_adc_soc_data, }, + { .compatible = "ingenic,jz4770-adc", .data = &jz4770_adc_soc_data, }, { }, }; MODULE_DEVICE_TABLE(of, ingenic_adc_of_match); diff --git a/drivers/iio/adc/intel_mrfld_adc.c b/drivers/iio/adc/intel_mrfld_adc.c new file mode 100644 index 000000000000..67d096f8180d --- /dev/null +++ b/drivers/iio/adc/intel_mrfld_adc.c @@ -0,0 +1,262 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ADC driver for Basin Cove PMIC + * + * Copyright (C) 2012 Intel Corporation + * Author: Bin Yang <bin.yang@intel.com> + * + * Rewritten for upstream by: + * Vincent Pelletier <plr.vincent@gmail.com> + * Andy Shevchenko <andriy.shevchenko@linux.intel.com> + */ + +#include <linux/bitops.h> +#include <linux/completion.h> +#include <linux/interrupt.h> +#include <linux/mfd/intel_soc_pmic.h> +#include <linux/mfd/intel_soc_pmic_mrfld.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> + +#include <linux/iio/driver.h> +#include <linux/iio/iio.h> +#include <linux/iio/machine.h> + +#include <asm/unaligned.h> + +#define BCOVE_GPADCREQ 0xDC +#define BCOVE_GPADCREQ_BUSY BIT(0) +#define BCOVE_GPADCREQ_IRQEN BIT(1) + +#define BCOVE_ADCIRQ_ALL ( \ + BCOVE_ADCIRQ_BATTEMP | \ + BCOVE_ADCIRQ_SYSTEMP | \ + BCOVE_ADCIRQ_BATTID | \ + BCOVE_ADCIRQ_VIBATT | \ + BCOVE_ADCIRQ_CCTICK) + +#define BCOVE_ADC_TIMEOUT msecs_to_jiffies(1000) + +static const u8 mrfld_adc_requests[] = { + BCOVE_ADCIRQ_VIBATT, + BCOVE_ADCIRQ_BATTID, + BCOVE_ADCIRQ_VIBATT, + BCOVE_ADCIRQ_SYSTEMP, + BCOVE_ADCIRQ_BATTEMP, + BCOVE_ADCIRQ_BATTEMP, + BCOVE_ADCIRQ_SYSTEMP, + BCOVE_ADCIRQ_SYSTEMP, + BCOVE_ADCIRQ_SYSTEMP, +}; + +struct mrfld_adc { + struct regmap *regmap; + struct completion completion; + /* Lock to protect the IPC transfers */ + struct mutex lock; +}; + +static irqreturn_t mrfld_adc_thread_isr(int irq, void *data) +{ + struct iio_dev *indio_dev = data; + struct mrfld_adc *adc = iio_priv(indio_dev); + + complete(&adc->completion); + return IRQ_HANDLED; +} + +static int mrfld_adc_single_conv(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *result) +{ + struct mrfld_adc *adc = iio_priv(indio_dev); + struct regmap *regmap = adc->regmap; + unsigned int req; + long timeout; + u8 buf[2]; + int ret; + + reinit_completion(&adc->completion); + + regmap_update_bits(regmap, BCOVE_MADCIRQ, BCOVE_ADCIRQ_ALL, 0); + regmap_update_bits(regmap, BCOVE_MIRQLVL1, BCOVE_LVL1_ADC, 0); + + ret = regmap_read_poll_timeout(regmap, BCOVE_GPADCREQ, req, + !(req & BCOVE_GPADCREQ_BUSY), + 2000, 1000000); + if (ret) + goto done; + + req = mrfld_adc_requests[chan->channel]; + ret = regmap_write(regmap, BCOVE_GPADCREQ, BCOVE_GPADCREQ_IRQEN | req); + if (ret) + goto done; + + timeout = wait_for_completion_interruptible_timeout(&adc->completion, + BCOVE_ADC_TIMEOUT); + if (timeout < 0) { + ret = timeout; + goto done; + } + if (timeout == 0) { + ret = -ETIMEDOUT; + goto done; + } + + ret = regmap_bulk_read(regmap, chan->address, buf, 2); + if (ret) + goto done; + + *result = get_unaligned_be16(buf); + ret = IIO_VAL_INT; + +done: + regmap_update_bits(regmap, BCOVE_MIRQLVL1, BCOVE_LVL1_ADC, 0xff); + regmap_update_bits(regmap, BCOVE_MADCIRQ, BCOVE_ADCIRQ_ALL, 0xff); + + return ret; +} + +static int mrfld_adc_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct mrfld_adc *adc = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + mutex_lock(&adc->lock); + ret = mrfld_adc_single_conv(indio_dev, chan, val); + mutex_unlock(&adc->lock); + return ret; + default: + return -EINVAL; + } +} + +static const struct iio_info mrfld_adc_iio_info = { + .read_raw = &mrfld_adc_read_raw, +}; + +#define BCOVE_ADC_CHANNEL(_type, _channel, _datasheet_name, _address) \ + { \ + .indexed = 1, \ + .type = _type, \ + .channel = _channel, \ + .address = _address, \ + .datasheet_name = _datasheet_name, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + } + +static const struct iio_chan_spec mrfld_adc_channels[] = { + BCOVE_ADC_CHANNEL(IIO_VOLTAGE, 0, "CH0", 0xE9), + BCOVE_ADC_CHANNEL(IIO_RESISTANCE, 1, "CH1", 0xEB), + BCOVE_ADC_CHANNEL(IIO_CURRENT, 2, "CH2", 0xED), + BCOVE_ADC_CHANNEL(IIO_TEMP, 3, "CH3", 0xCC), + BCOVE_ADC_CHANNEL(IIO_TEMP, 4, "CH4", 0xC8), + BCOVE_ADC_CHANNEL(IIO_TEMP, 5, "CH5", 0xCA), + BCOVE_ADC_CHANNEL(IIO_TEMP, 6, "CH6", 0xC2), + BCOVE_ADC_CHANNEL(IIO_TEMP, 7, "CH7", 0xC4), + BCOVE_ADC_CHANNEL(IIO_TEMP, 8, "CH8", 0xC6), +}; + +static struct iio_map iio_maps[] = { + IIO_MAP("CH0", "bcove-battery", "VBATRSLT"), + IIO_MAP("CH1", "bcove-battery", "BATTID"), + IIO_MAP("CH2", "bcove-battery", "IBATRSLT"), + IIO_MAP("CH3", "bcove-temp", "PMICTEMP"), + IIO_MAP("CH4", "bcove-temp", "BATTEMP0"), + IIO_MAP("CH5", "bcove-temp", "BATTEMP1"), + IIO_MAP("CH6", "bcove-temp", "SYSTEMP0"), + IIO_MAP("CH7", "bcove-temp", "SYSTEMP1"), + IIO_MAP("CH8", "bcove-temp", "SYSTEMP2"), + {} +}; + +static int mrfld_adc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct intel_soc_pmic *pmic = dev_get_drvdata(dev->parent); + struct iio_dev *indio_dev; + struct mrfld_adc *adc; + int irq; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*indio_dev)); + if (!indio_dev) + return -ENOMEM; + + adc = iio_priv(indio_dev); + + mutex_init(&adc->lock); + init_completion(&adc->completion); + adc->regmap = pmic->regmap; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + ret = devm_request_threaded_irq(dev, irq, NULL, mrfld_adc_thread_isr, + IRQF_ONESHOT | IRQF_SHARED, pdev->name, + indio_dev); + if (ret) + return ret; + + platform_set_drvdata(pdev, indio_dev); + + indio_dev->dev.parent = dev; + indio_dev->name = pdev->name; + + indio_dev->channels = mrfld_adc_channels; + indio_dev->num_channels = ARRAY_SIZE(mrfld_adc_channels); + indio_dev->info = &mrfld_adc_iio_info; + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = iio_map_array_register(indio_dev, iio_maps); + if (ret) + return ret; + + ret = devm_iio_device_register(dev, indio_dev); + if (ret < 0) + goto err_array_unregister; + + return 0; + +err_array_unregister: + iio_map_array_unregister(indio_dev); + return ret; +} + +static int mrfld_adc_remove(struct platform_device *pdev) +{ + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + + iio_map_array_unregister(indio_dev); + + return 0; +} + +static const struct platform_device_id mrfld_adc_id_table[] = { + { .name = "mrfld_bcove_adc" }, + {} +}; +MODULE_DEVICE_TABLE(platform, mrfld_adc_id_table); + +static struct platform_driver mrfld_adc_driver = { + .driver = { + .name = "mrfld_bcove_adc", + }, + .probe = mrfld_adc_probe, + .remove = mrfld_adc_remove, + .id_table = mrfld_adc_id_table, +}; +module_platform_driver(mrfld_adc_driver); + +MODULE_AUTHOR("Bin Yang <bin.yang@intel.com>"); +MODULE_AUTHOR("Vincent Pelletier <plr.vincent@gmail.com>"); +MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>"); +MODULE_DESCRIPTION("ADC driver for Basin Cove PMIC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/max1027.c b/drivers/iio/adc/max1027.c index 214883458582..e171db20c04a 100644 --- a/drivers/iio/adc/max1027.c +++ b/drivers/iio/adc/max1027.c @@ -63,12 +63,18 @@ enum max1027_id { max1027, max1029, max1031, + max1227, + max1229, + max1231, }; static const struct spi_device_id max1027_id[] = { {"max1027", max1027}, {"max1029", max1029}, {"max1031", max1031}, + {"max1227", max1227}, + {"max1229", max1229}, + {"max1231", max1231}, {} }; MODULE_DEVICE_TABLE(spi, max1027_id); @@ -78,12 +84,15 @@ static const struct of_device_id max1027_adc_dt_ids[] = { { .compatible = "maxim,max1027" }, { .compatible = "maxim,max1029" }, { .compatible = "maxim,max1031" }, + { .compatible = "maxim,max1227" }, + { .compatible = "maxim,max1229" }, + { .compatible = "maxim,max1231" }, {}, }; MODULE_DEVICE_TABLE(of, max1027_adc_dt_ids); #endif -#define MAX1027_V_CHAN(index) \ +#define MAX1027_V_CHAN(index, depth) \ { \ .type = IIO_VOLTAGE, \ .indexed = 1, \ @@ -93,7 +102,7 @@ MODULE_DEVICE_TABLE(of, max1027_adc_dt_ids); .scan_index = index + 1, \ .scan_type = { \ .sign = 'u', \ - .realbits = 10, \ + .realbits = depth, \ .storagebits = 16, \ .shift = 2, \ .endianness = IIO_BE, \ @@ -115,52 +124,54 @@ MODULE_DEVICE_TABLE(of, max1027_adc_dt_ids); }, \ } +#define MAX1X27_CHANNELS(depth) \ + MAX1027_T_CHAN, \ + MAX1027_V_CHAN(0, depth), \ + MAX1027_V_CHAN(1, depth), \ + MAX1027_V_CHAN(2, depth), \ + MAX1027_V_CHAN(3, depth), \ + MAX1027_V_CHAN(4, depth), \ + MAX1027_V_CHAN(5, depth), \ + MAX1027_V_CHAN(6, depth), \ + MAX1027_V_CHAN(7, depth) + +#define MAX1X29_CHANNELS(depth) \ + MAX1X27_CHANNELS(depth), \ + MAX1027_V_CHAN(8, depth), \ + MAX1027_V_CHAN(9, depth), \ + MAX1027_V_CHAN(10, depth), \ + MAX1027_V_CHAN(11, depth) + +#define MAX1X31_CHANNELS(depth) \ + MAX1X27_CHANNELS(depth), \ + MAX1X29_CHANNELS(depth), \ + MAX1027_V_CHAN(12, depth), \ + MAX1027_V_CHAN(13, depth), \ + MAX1027_V_CHAN(14, depth), \ + MAX1027_V_CHAN(15, depth) + static const struct iio_chan_spec max1027_channels[] = { - MAX1027_T_CHAN, - MAX1027_V_CHAN(0), - MAX1027_V_CHAN(1), - MAX1027_V_CHAN(2), - MAX1027_V_CHAN(3), - MAX1027_V_CHAN(4), - MAX1027_V_CHAN(5), - MAX1027_V_CHAN(6), - MAX1027_V_CHAN(7) + MAX1X27_CHANNELS(10), }; static const struct iio_chan_spec max1029_channels[] = { - MAX1027_T_CHAN, - MAX1027_V_CHAN(0), - MAX1027_V_CHAN(1), - MAX1027_V_CHAN(2), - MAX1027_V_CHAN(3), - MAX1027_V_CHAN(4), - MAX1027_V_CHAN(5), - MAX1027_V_CHAN(6), - MAX1027_V_CHAN(7), - MAX1027_V_CHAN(8), - MAX1027_V_CHAN(9), - MAX1027_V_CHAN(10), - MAX1027_V_CHAN(11) + MAX1X29_CHANNELS(10), }; static const struct iio_chan_spec max1031_channels[] = { - MAX1027_T_CHAN, - MAX1027_V_CHAN(0), - MAX1027_V_CHAN(1), - MAX1027_V_CHAN(2), - MAX1027_V_CHAN(3), - MAX1027_V_CHAN(4), - MAX1027_V_CHAN(5), - MAX1027_V_CHAN(6), - MAX1027_V_CHAN(7), - MAX1027_V_CHAN(8), - MAX1027_V_CHAN(9), - MAX1027_V_CHAN(10), - MAX1027_V_CHAN(11), - MAX1027_V_CHAN(12), - MAX1027_V_CHAN(13), - MAX1027_V_CHAN(14), - MAX1027_V_CHAN(15) + MAX1X31_CHANNELS(10), +}; + +static const struct iio_chan_spec max1227_channels[] = { + MAX1X27_CHANNELS(12), +}; + +static const struct iio_chan_spec max1229_channels[] = { + MAX1X29_CHANNELS(12), +}; + +static const struct iio_chan_spec max1231_channels[] = { + MAX1X31_CHANNELS(12), }; static const unsigned long max1027_available_scan_masks[] = { @@ -200,6 +211,21 @@ static const struct max1027_chip_info max1027_chip_info_tbl[] = { .num_channels = ARRAY_SIZE(max1031_channels), .available_scan_masks = max1031_available_scan_masks, }, + [max1227] = { + .channels = max1227_channels, + .num_channels = ARRAY_SIZE(max1227_channels), + .available_scan_masks = max1027_available_scan_masks, + }, + [max1229] = { + .channels = max1229_channels, + .num_channels = ARRAY_SIZE(max1229_channels), + .available_scan_masks = max1029_available_scan_masks, + }, + [max1231] = { + .channels = max1231_channels, + .num_channels = ARRAY_SIZE(max1231_channels), + .available_scan_masks = max1031_available_scan_masks, + }, }; struct max1027_state { @@ -284,7 +310,7 @@ static int max1027_read_raw(struct iio_dev *indio_dev, break; case IIO_VOLTAGE: *val = 2500; - *val2 = 10; + *val2 = chan->scan_type.realbits; ret = IIO_VAL_FRACTIONAL_LOG2; break; default: @@ -309,8 +335,11 @@ static int max1027_debugfs_reg_access(struct iio_dev *indio_dev, struct max1027_state *st = iio_priv(indio_dev); u8 *val = (u8 *)st->buffer; - if (readval != NULL) - return -EINVAL; + if (readval) { + int ret = spi_read(st->spi, val, 2); + *readval = be16_to_cpu(st->buffer[0]); + return ret; + } *val = (u8)writeval; return spi_write(st->spi, val, 1); @@ -427,34 +456,47 @@ static int max1027_probe(struct spi_device *spi) return -ENOMEM; } - ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, - &iio_pollfunc_store_time, - &max1027_trigger_handler, NULL); - if (ret < 0) { - dev_err(&indio_dev->dev, "Failed to setup buffer\n"); - return ret; - } + if (spi->irq) { + ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, + &iio_pollfunc_store_time, + &max1027_trigger_handler, + NULL); + if (ret < 0) { + dev_err(&indio_dev->dev, "Failed to setup buffer\n"); + return ret; + } - st->trig = devm_iio_trigger_alloc(&spi->dev, "%s-trigger", - indio_dev->name); - if (st->trig == NULL) { - ret = -ENOMEM; - dev_err(&indio_dev->dev, "Failed to allocate iio trigger\n"); - return ret; - } + st->trig = devm_iio_trigger_alloc(&spi->dev, "%s-trigger", + indio_dev->name); + if (st->trig == NULL) { + ret = -ENOMEM; + dev_err(&indio_dev->dev, + "Failed to allocate iio trigger\n"); + return ret; + } - st->trig->ops = &max1027_trigger_ops; - st->trig->dev.parent = &spi->dev; - iio_trigger_set_drvdata(st->trig, indio_dev); - iio_trigger_register(st->trig); + st->trig->ops = &max1027_trigger_ops; + st->trig->dev.parent = &spi->dev; + iio_trigger_set_drvdata(st->trig, indio_dev); + iio_trigger_register(st->trig); + + ret = devm_request_threaded_irq(&spi->dev, spi->irq, + iio_trigger_generic_data_rdy_poll, + NULL, + IRQF_TRIGGER_FALLING, + spi->dev.driver->name, + st->trig); + if (ret < 0) { + dev_err(&indio_dev->dev, "Failed to allocate IRQ.\n"); + return ret; + } + } - ret = devm_request_threaded_irq(&spi->dev, spi->irq, - iio_trigger_generic_data_rdy_poll, - NULL, - IRQF_TRIGGER_FALLING, - spi->dev.driver->name, st->trig); + /* Internal reset */ + st->reg = MAX1027_RST_REG; + ret = spi_write(st->spi, &st->reg, 1); if (ret < 0) { - dev_err(&indio_dev->dev, "Failed to allocate IRQ.\n"); + dev_err(&indio_dev->dev, "Failed to reset the ADC\n"); return ret; } @@ -480,5 +522,5 @@ static struct spi_driver max1027_driver = { module_spi_driver(max1027_driver); MODULE_AUTHOR("Philippe Reynes <tremyfr@yahoo.fr>"); -MODULE_DESCRIPTION("MAX1027/MAX1029/MAX1031 ADC"); +MODULE_DESCRIPTION("MAX1X27/MAX1X29/MAX1X31 ADC"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/mcp320x.c b/drivers/iio/adc/mcp320x.c index 38bf10085696..465c7625a55a 100644 --- a/drivers/iio/adc/mcp320x.c +++ b/drivers/iio/adc/mcp320x.c @@ -164,7 +164,7 @@ static int mcp320x_adc_conversion(struct mcp320x *adc, u8 channel, case mcp3550_60: case mcp3551: case mcp3553: { - u32 raw = be32_to_cpup((u32 *)adc->rx_buf); + u32 raw = be32_to_cpup((__be32 *)adc->rx_buf); if (!(adc->spi->mode & SPI_CPOL)) raw <<= 1; /* strip Data Ready bit in SPI mode 0,0 */ diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c index 7b27306330a3..22a470db9ef8 100644 --- a/drivers/iio/adc/meson_saradc.c +++ b/drivers/iio/adc/meson_saradc.c @@ -1187,7 +1187,6 @@ static int meson_sar_adc_probe(struct platform_device *pdev) const struct meson_sar_adc_data *match_data; struct meson_sar_adc_priv *priv; struct iio_dev *indio_dev; - struct resource *res; void __iomem *base; int irq, ret; @@ -1214,8 +1213,7 @@ static int meson_sar_adc_probe(struct platform_device *pdev) indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &meson_sar_adc_iio_info; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); diff --git a/drivers/iio/adc/sc27xx_adc.c b/drivers/iio/adc/sc27xx_adc.c index a6c046575ec3..66b387f9b36d 100644 --- a/drivers/iio/adc/sc27xx_adc.c +++ b/drivers/iio/adc/sc27xx_adc.c @@ -477,13 +477,6 @@ static void sc27xx_adc_disable(void *_data) SC27XX_MODULE_ADC_EN, 0); } -static void sc27xx_adc_free_hwlock(void *_data) -{ - struct hwspinlock *hwlock = _data; - - hwspin_lock_free(hwlock); -} - static int sc27xx_adc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -520,19 +513,12 @@ static int sc27xx_adc_probe(struct platform_device *pdev) return ret; } - sc27xx_data->hwlock = hwspin_lock_request_specific(ret); + sc27xx_data->hwlock = devm_hwspin_lock_request_specific(dev, ret); if (!sc27xx_data->hwlock) { dev_err(dev, "failed to request hwspinlock\n"); return -ENXIO; } - ret = devm_add_action_or_reset(dev, sc27xx_adc_free_hwlock, - sc27xx_data->hwlock); - if (ret) { - dev_err(dev, "failed to add hwspinlock action\n"); - return ret; - } - sc27xx_data->dev = dev; ret = sc27xx_adc_enable(sc27xx_data); diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c index 93a096a91f8c..20c626c289ed 100644 --- a/drivers/iio/adc/stm32-adc-core.c +++ b/drivers/iio/adc/stm32-adc-core.c @@ -38,12 +38,12 @@ #define HAS_ANASWVDD BIT(1) /** - * stm32_adc_common_regs - stm32 common registers, compatible dependent data + * struct stm32_adc_common_regs - stm32 common registers * @csr: common status register offset * @ccr: common control register offset - * @eoc1: adc1 end of conversion flag in @csr - * @eoc2: adc2 end of conversion flag in @csr - * @eoc3: adc3 end of conversion flag in @csr + * @eoc1_msk: adc1 end of conversion flag in @csr + * @eoc2_msk: adc2 end of conversion flag in @csr + * @eoc3_msk: adc3 end of conversion flag in @csr * @ier: interrupt enable register offset for each adc * @eocie_msk: end of conversion interrupt enable mask in @ier */ @@ -60,7 +60,7 @@ struct stm32_adc_common_regs { struct stm32_adc_priv; /** - * stm32_adc_priv_cfg - stm32 core compatible configuration data + * struct stm32_adc_priv_cfg - stm32 core compatible configuration data * @regs: common registers for all instances * @clk_sel: clock selection routine * @max_clk_rate_hz: maximum analog clock rate (Hz, from datasheet) @@ -117,6 +117,7 @@ static int stm32f4_pclk_div[] = {2, 4, 6, 8}; /** * stm32f4_adc_clk_sel() - Select stm32f4 ADC common clock prescaler + * @pdev: platform device * @priv: stm32 ADC core private data * Select clock prescaler used for analog conversions, before using ADC. */ diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index 73aee5949b6b..3b291d72701c 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -102,7 +102,7 @@ struct stm32_adc_calib { }; /** - * stm32_adc_regs - stm32 ADC misc registers & bitfield desc + * struct stm32_adc_regs - stm32 ADC misc registers & bitfield desc * @reg: register offset * @mask: bitfield mask * @shift: left shift @@ -114,7 +114,7 @@ struct stm32_adc_regs { }; /** - * stm32_adc_regspec - stm32 registers definition, compatible dependent data + * struct stm32_adc_regspec - stm32 registers definition * @dr: data register offset * @ier_eoc: interrupt enable register & eocie bitfield * @isr_eoc: interrupt status register & eoc bitfield @@ -140,7 +140,7 @@ struct stm32_adc_regspec { struct stm32_adc; /** - * stm32_adc_cfg - stm32 compatible configuration data + * struct stm32_adc_cfg - stm32 compatible configuration data * @regs: registers descriptions * @adc_info: per instance input channels definitions * @trigs: external trigger sources @@ -183,8 +183,8 @@ struct stm32_adc_cfg { * @rx_buf: dma rx buffer cpu address * @rx_dma_buf: dma rx buffer bus address * @rx_buf_sz: dma rx buffer size - * @difsel bitmask to set single-ended/differential channel - * @pcsel bitmask to preselect channels on some devices + * @difsel: bitmask to set single-ended/differential channel + * @pcsel: bitmask to preselect channels on some devices * @smpr_val: sampling time settings (e.g. smpr1 / smpr2) * @cal: optional calibration data on some devices * @chan_name: channel name array @@ -254,7 +254,7 @@ static const struct stm32_adc_info stm32h7_adc_info = { .num_res = ARRAY_SIZE(stm32h7_adc_resolutions), }; -/** +/* * stm32f4_sq - describe regular sequence registers * - L: sequence len (register & bit field) * - SQ1..SQ16: sequence entries (register & bit field) @@ -301,7 +301,7 @@ static struct stm32_adc_trig_info stm32f4_adc_trigs[] = { {}, /* sentinel */ }; -/** +/* * stm32f4_smp_bits[] - describe sampling time register index & bit fields * Sorted so it can be indexed by channel number. */ @@ -392,7 +392,7 @@ static struct stm32_adc_trig_info stm32h7_adc_trigs[] = { {}, }; -/** +/* * stm32h7_smp_bits - describe sampling time register index & bit fields * Sorted so it can be indexed by channel number. */ @@ -994,6 +994,7 @@ static int stm32_adc_conf_scan_seq(struct iio_dev *indio_dev, /** * stm32_adc_get_trig_extsel() - Get external trigger selection + * @indio_dev: IIO device structure * @trig: trigger * * Returns trigger extsel value, if trig matches, -EINVAL otherwise. @@ -1297,6 +1298,10 @@ static int stm32_adc_of_xlate(struct iio_dev *indio_dev, /** * stm32_adc_debugfs_reg_access - read or write register value + * @indio_dev: IIO device structure + * @reg: register offset + * @writeval: value to write + * @readval: value to read * * To read a value from an ADC register: * echo [ADC reg offset] > direct_reg_access diff --git a/drivers/iio/adc/stmpe-adc.c b/drivers/iio/adc/stmpe-adc.c index bd72727fc417..0f88048ea48f 100644 --- a/drivers/iio/adc/stmpe-adc.c +++ b/drivers/iio/adc/stmpe-adc.c @@ -175,7 +175,7 @@ static int stmpe_read_raw(struct iio_dev *indio_dev, static irqreturn_t stmpe_adc_isr(int irq, void *dev_id) { struct stmpe_adc *info = (struct stmpe_adc *)dev_id; - u16 data; + __be16 data; if (info->channel <= STMPE_ADC_LAST_NR) { int int_sta; diff --git a/drivers/iio/adc/twl4030-madc.c b/drivers/iio/adc/twl4030-madc.c index 55c5119fe575..472b08f37fea 100644 --- a/drivers/iio/adc/twl4030-madc.c +++ b/drivers/iio/adc/twl4030-madc.c @@ -495,7 +495,7 @@ static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc) ret = twl4030_madc_disable_irq(madc, i); if (ret < 0) dev_dbg(madc->dev, "Disable interrupt failed %d\n", i); - madc->requests[i].result_pending = 1; + madc->requests[i].result_pending = true; } for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) { r = &madc->requests[i]; @@ -507,8 +507,8 @@ static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc) len = twl4030_madc_read_channels(madc, method->rbase, r->channels, r->rbuf, r->raw); /* Free request */ - r->result_pending = 0; - r->active = 0; + r->result_pending = false; + r->active = false; } mutex_unlock(&madc->lock); @@ -521,15 +521,15 @@ err_i2c: */ for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) { r = &madc->requests[i]; - if (r->active == 0) + if (!r->active) continue; method = &twl4030_conversion_methods[r->method]; /* Read results */ len = twl4030_madc_read_channels(madc, method->rbase, r->channels, r->rbuf, r->raw); /* Free request */ - r->result_pending = 0; - r->active = 0; + r->result_pending = false; + r->active = false; } mutex_unlock(&madc->lock); @@ -652,16 +652,16 @@ static int twl4030_madc_conversion(struct twl4030_madc_request *req) ret = twl4030_madc_start_conversion(twl4030_madc, req->method); if (ret < 0) goto out; - twl4030_madc->requests[req->method].active = 1; + twl4030_madc->requests[req->method].active = true; /* Wait until conversion is ready (ctrl register returns EOC) */ ret = twl4030_madc_wait_conversion_ready(twl4030_madc, 5, method->ctrl); if (ret) { - twl4030_madc->requests[req->method].active = 0; + twl4030_madc->requests[req->method].active = false; goto out; } ret = twl4030_madc_read_channels(twl4030_madc, method->rbase, req->channels, req->rbuf, req->raw); - twl4030_madc->requests[req->method].active = 0; + twl4030_madc->requests[req->method].active = false; out: mutex_unlock(&twl4030_madc->lock); diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c index 4fd389678dba..ec227b358cd6 100644 --- a/drivers/iio/adc/xilinx-xadc-core.c +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -1150,7 +1150,6 @@ static int xadc_probe(struct platform_device *pdev) const struct of_device_id *id; struct iio_dev *indio_dev; unsigned int bipolar_mask; - struct resource *mem; unsigned int conf0; struct xadc *xadc; int ret; @@ -1180,8 +1179,7 @@ static int xadc_probe(struct platform_device *pdev) spin_lock_init(&xadc->lock); INIT_DELAYED_WORK(&xadc->zynq_unmask_work, xadc_zynq_unmask_worker); - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - xadc->base = devm_ioremap_resource(&pdev->dev, mem); + xadc->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(xadc->base)) return PTR_ERR(xadc->base); diff --git a/drivers/iio/chemical/atlas-ph-sensor.c b/drivers/iio/chemical/atlas-ph-sensor.c index 3a20cb5d9bff..6c175eb1c7a7 100644 --- a/drivers/iio/chemical/atlas-ph-sensor.c +++ b/drivers/iio/chemical/atlas-ph-sensor.c @@ -323,16 +323,16 @@ static int atlas_buffer_predisable(struct iio_dev *indio_dev) struct atlas_data *data = iio_priv(indio_dev); int ret; - ret = iio_triggered_buffer_predisable(indio_dev); + ret = atlas_set_interrupt(data, false); if (ret) return ret; - ret = atlas_set_interrupt(data, false); + pm_runtime_mark_last_busy(&data->client->dev); + ret = pm_runtime_put_autosuspend(&data->client->dev); if (ret) return ret; - pm_runtime_mark_last_busy(&data->client->dev); - return pm_runtime_put_autosuspend(&data->client->dev); + return iio_triggered_buffer_predisable(indio_dev); } static const struct iio_trigger_ops atlas_interrupt_trigger_ops = { diff --git a/drivers/iio/chemical/sgp30.c b/drivers/iio/chemical/sgp30.c index 8cc8fe5e356d..403e8803471a 100644 --- a/drivers/iio/chemical/sgp30.c +++ b/drivers/iio/chemical/sgp30.c @@ -483,7 +483,7 @@ static void sgp_init(struct sgp_data *data) data->iaq_defval_skip_jiffies = 43 * data->measure_interval_jiffies; break; - }; + } } static const struct iio_info sgp_info = { diff --git a/drivers/iio/chemical/sps30.c b/drivers/iio/chemical/sps30.c index edbb956e81e8..acb9f8ecbb3d 100644 --- a/drivers/iio/chemical/sps30.c +++ b/drivers/iio/chemical/sps30.c @@ -117,7 +117,7 @@ static int sps30_do_cmd(struct sps30_state *state, u16 cmd, u8 *data, int size) break; case SPS30_READ_AUTO_CLEANING_PERIOD: buf[0] = SPS30_AUTO_CLEANING_PERIOD >> 8; - buf[1] = (u8)SPS30_AUTO_CLEANING_PERIOD; + buf[1] = (u8)(SPS30_AUTO_CLEANING_PERIOD & 0xff); /* fall through */ case SPS30_READ_DATA_READY_FLAG: case SPS30_READ_DATA: diff --git a/drivers/iio/dac/ad7303.c b/drivers/iio/dac/ad7303.c index 8de9f40226e6..14bbac6bee98 100644 --- a/drivers/iio/dac/ad7303.c +++ b/drivers/iio/dac/ad7303.c @@ -41,6 +41,7 @@ struct ad7303_state { struct regulator *vdd_reg; struct regulator *vref_reg; + struct mutex lock; /* * DMA (thus cache coherency maintenance) requires the * transfer buffers to live in their own cache lines. @@ -79,7 +80,7 @@ static ssize_t ad7303_write_dac_powerdown(struct iio_dev *indio_dev, if (ret) return ret; - mutex_lock(&indio_dev->mlock); + mutex_lock(&st->lock); if (pwr_down) st->config |= AD7303_CFG_POWER_DOWN(chan->channel); @@ -90,7 +91,7 @@ static ssize_t ad7303_write_dac_powerdown(struct iio_dev *indio_dev, * mode, so just write one of the DAC channels again */ ad7303_write(st, chan->channel, st->dac_cache[chan->channel]); - mutex_unlock(&indio_dev->mlock); + mutex_unlock(&st->lock); return len; } @@ -116,7 +117,9 @@ static int ad7303_read_raw(struct iio_dev *indio_dev, switch (info) { case IIO_CHAN_INFO_RAW: + mutex_lock(&st->lock); *val = st->dac_cache[chan->channel]; + mutex_unlock(&st->lock); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: vref_uv = ad7303_get_vref(st, chan); @@ -144,11 +147,11 @@ static int ad7303_write_raw(struct iio_dev *indio_dev, if (val >= (1 << chan->scan_type.realbits) || val < 0) return -EINVAL; - mutex_lock(&indio_dev->mlock); + mutex_lock(&st->lock); ret = ad7303_write(st, chan->address, val); if (ret == 0) st->dac_cache[chan->channel] = val; - mutex_unlock(&indio_dev->mlock); + mutex_unlock(&st->lock); break; default: ret = -EINVAL; @@ -211,6 +214,8 @@ static int ad7303_probe(struct spi_device *spi) st->spi = spi; + mutex_init(&st->lock); + st->vdd_reg = devm_regulator_get(&spi->dev, "Vdd"); if (IS_ERR(st->vdd_reg)) return PTR_ERR(st->vdd_reg); diff --git a/drivers/iio/dac/stm32-dac-core.c b/drivers/iio/dac/stm32-dac-core.c index d0fb3124de07..9e6b4cd0a5cc 100644 --- a/drivers/iio/dac/stm32-dac-core.c +++ b/drivers/iio/dac/stm32-dac-core.c @@ -11,6 +11,7 @@ #include <linux/delay.h> #include <linux/module.h> #include <linux/of_platform.h> +#include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> #include <linux/reset.h> @@ -50,6 +51,41 @@ static const struct regmap_config stm32_dac_regmap_cfg = { .max_register = 0x3fc, }; +static int stm32_dac_core_hw_start(struct device *dev) +{ + struct stm32_dac_common *common = dev_get_drvdata(dev); + struct stm32_dac_priv *priv = to_stm32_dac_priv(common); + int ret; + + ret = regulator_enable(priv->vref); + if (ret < 0) { + dev_err(dev, "vref enable failed: %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(priv->pclk); + if (ret < 0) { + dev_err(dev, "pclk enable failed: %d\n", ret); + goto err_regulator_disable; + } + + return 0; + +err_regulator_disable: + regulator_disable(priv->vref); + + return ret; +} + +static void stm32_dac_core_hw_stop(struct device *dev) +{ + struct stm32_dac_common *common = dev_get_drvdata(dev); + struct stm32_dac_priv *priv = to_stm32_dac_priv(common); + + clk_disable_unprepare(priv->pclk); + regulator_disable(priv->vref); +} + static int stm32_dac_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -66,6 +102,8 @@ static int stm32_dac_probe(struct platform_device *pdev) priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; + platform_set_drvdata(pdev, &priv->common); + cfg = (const struct stm32_dac_cfg *) of_match_device(dev->driver->of_match_table, dev)->data; @@ -74,11 +112,19 @@ static int stm32_dac_probe(struct platform_device *pdev) if (IS_ERR(mmio)) return PTR_ERR(mmio); - regmap = devm_regmap_init_mmio(dev, mmio, &stm32_dac_regmap_cfg); + regmap = devm_regmap_init_mmio_clk(dev, "pclk", mmio, + &stm32_dac_regmap_cfg); if (IS_ERR(regmap)) return PTR_ERR(regmap); priv->common.regmap = regmap; + priv->pclk = devm_clk_get(dev, "pclk"); + if (IS_ERR(priv->pclk)) { + ret = PTR_ERR(priv->pclk); + dev_err(dev, "pclk get failed\n"); + return ret; + } + priv->vref = devm_regulator_get(dev, "vref"); if (IS_ERR(priv->vref)) { ret = PTR_ERR(priv->vref); @@ -86,33 +132,22 @@ static int stm32_dac_probe(struct platform_device *pdev) return ret; } - ret = regulator_enable(priv->vref); - if (ret < 0) { - dev_err(dev, "vref enable failed\n"); - return ret; - } + pm_runtime_get_noresume(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + ret = stm32_dac_core_hw_start(dev); + if (ret) + goto err_pm_stop; ret = regulator_get_voltage(priv->vref); if (ret < 0) { dev_err(dev, "vref get voltage failed, %d\n", ret); - goto err_vref; + goto err_hw_stop; } priv->common.vref_mv = ret / 1000; dev_dbg(dev, "vref+=%dmV\n", priv->common.vref_mv); - priv->pclk = devm_clk_get(dev, "pclk"); - if (IS_ERR(priv->pclk)) { - ret = PTR_ERR(priv->pclk); - dev_err(dev, "pclk get failed\n"); - goto err_vref; - } - - ret = clk_prepare_enable(priv->pclk); - if (ret < 0) { - dev_err(dev, "pclk enable failed\n"); - goto err_vref; - } - priv->rst = devm_reset_control_get_exclusive(dev, NULL); if (!IS_ERR(priv->rst)) { reset_control_assert(priv->rst); @@ -128,39 +163,79 @@ static int stm32_dac_probe(struct platform_device *pdev) priv->common.hfsel ? STM32H7_DAC_CR_HFSEL : 0); if (ret) - goto err_pclk; + goto err_hw_stop; } - platform_set_drvdata(pdev, &priv->common); ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, dev); if (ret < 0) { dev_err(dev, "failed to populate DT children\n"); - goto err_pclk; + goto err_hw_stop; } + pm_runtime_put(dev); + return 0; -err_pclk: - clk_disable_unprepare(priv->pclk); -err_vref: - regulator_disable(priv->vref); +err_hw_stop: + stm32_dac_core_hw_stop(dev); +err_pm_stop: + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); + pm_runtime_put_noidle(dev); return ret; } static int stm32_dac_remove(struct platform_device *pdev) { - struct stm32_dac_common *common = platform_get_drvdata(pdev); + pm_runtime_get_sync(&pdev->dev); + of_platform_depopulate(&pdev->dev); + stm32_dac_core_hw_stop(&pdev->dev); + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + + return 0; +} + +static int __maybe_unused stm32_dac_core_resume(struct device *dev) +{ + struct stm32_dac_common *common = dev_get_drvdata(dev); struct stm32_dac_priv *priv = to_stm32_dac_priv(common); + int ret; - of_platform_depopulate(&pdev->dev); - clk_disable_unprepare(priv->pclk); - regulator_disable(priv->vref); + if (priv->common.hfsel) { + /* restore hfsel (maybe lost under low power state) */ + ret = regmap_update_bits(priv->common.regmap, STM32_DAC_CR, + STM32H7_DAC_CR_HFSEL, + STM32H7_DAC_CR_HFSEL); + if (ret) + return ret; + } + + return pm_runtime_force_resume(dev); +} + +static int __maybe_unused stm32_dac_core_runtime_suspend(struct device *dev) +{ + stm32_dac_core_hw_stop(dev); return 0; } +static int __maybe_unused stm32_dac_core_runtime_resume(struct device *dev) +{ + return stm32_dac_core_hw_start(dev); +} + +static const struct dev_pm_ops stm32_dac_core_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, stm32_dac_core_resume) + SET_RUNTIME_PM_OPS(stm32_dac_core_runtime_suspend, + stm32_dac_core_runtime_resume, + NULL) +}; + static const struct stm32_dac_cfg stm32h7_dac_cfg = { .has_hfsel = true, }; @@ -182,6 +257,7 @@ static struct platform_driver stm32_dac_driver = { .driver = { .name = "stm32-dac-core", .of_match_table = stm32_dac_of_match, + .pm = &stm32_dac_core_pm_ops, }, }; module_platform_driver(stm32_dac_driver); diff --git a/drivers/iio/dac/stm32-dac.c b/drivers/iio/dac/stm32-dac.c index cce26a3a6627..f22c1d9129b2 100644 --- a/drivers/iio/dac/stm32-dac.c +++ b/drivers/iio/dac/stm32-dac.c @@ -13,6 +13,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include "stm32-dac-core.h" @@ -20,6 +21,8 @@ #define STM32_DAC_CHANNEL_2 2 #define STM32_DAC_IS_CHAN_1(ch) ((ch) & STM32_DAC_CHANNEL_1) +#define STM32_DAC_AUTO_SUSPEND_DELAY_MS 2000 + /** * struct stm32_dac - private data of DAC driver * @common: reference to DAC common data @@ -49,15 +52,34 @@ static int stm32_dac_set_enable_state(struct iio_dev *indio_dev, int ch, bool enable) { struct stm32_dac *dac = iio_priv(indio_dev); + struct device *dev = indio_dev->dev.parent; u32 msk = STM32_DAC_IS_CHAN_1(ch) ? STM32_DAC_CR_EN1 : STM32_DAC_CR_EN2; u32 en = enable ? msk : 0; int ret; + /* already enabled / disabled ? */ + mutex_lock(&indio_dev->mlock); + ret = stm32_dac_is_enabled(indio_dev, ch); + if (ret < 0 || enable == !!ret) { + mutex_unlock(&indio_dev->mlock); + return ret < 0 ? ret : 0; + } + + if (enable) { + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + pm_runtime_put_noidle(dev); + mutex_unlock(&indio_dev->mlock); + return ret; + } + } + ret = regmap_update_bits(dac->common->regmap, STM32_DAC_CR, msk, en); + mutex_unlock(&indio_dev->mlock); if (ret < 0) { dev_err(&indio_dev->dev, "%s failed\n", en ? "Enable" : "Disable"); - return ret; + goto err_put_pm; } /* @@ -68,7 +90,20 @@ static int stm32_dac_set_enable_state(struct iio_dev *indio_dev, int ch, if (en && dac->common->hfsel) udelay(1); + if (!enable) { + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + } + return 0; + +err_put_pm: + if (enable) { + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + } + + return ret; } static int stm32_dac_get_value(struct stm32_dac *dac, int channel, int *val) @@ -272,6 +307,7 @@ static int stm32_dac_chan_of_init(struct iio_dev *indio_dev) static int stm32_dac_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; struct iio_dev *indio_dev; struct stm32_dac *dac; int ret; @@ -296,9 +332,61 @@ static int stm32_dac_probe(struct platform_device *pdev) if (ret < 0) return ret; - return devm_iio_device_register(&pdev->dev, indio_dev); + /* Get stm32-dac-core PM online */ + pm_runtime_get_noresume(dev); + pm_runtime_set_active(dev); + pm_runtime_set_autosuspend_delay(dev, STM32_DAC_AUTO_SUSPEND_DELAY_MS); + pm_runtime_use_autosuspend(dev); + pm_runtime_enable(dev); + + ret = iio_device_register(indio_dev); + if (ret) + goto err_pm_put; + + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + + return 0; + +err_pm_put: + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); + pm_runtime_put_noidle(dev); + + return ret; } +static int stm32_dac_remove(struct platform_device *pdev) +{ + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + + pm_runtime_get_sync(&pdev->dev); + iio_device_unregister(indio_dev); + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + + return 0; +} + +static int __maybe_unused stm32_dac_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + int channel = indio_dev->channels[0].channel; + int ret; + + /* Ensure DAC is disabled before suspend */ + ret = stm32_dac_is_enabled(indio_dev, channel); + if (ret) + return ret < 0 ? ret : -EBUSY; + + return pm_runtime_force_suspend(dev); +} + +static const struct dev_pm_ops stm32_dac_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(stm32_dac_suspend, pm_runtime_force_resume) +}; + static const struct of_device_id stm32_dac_of_match[] = { { .compatible = "st,stm32-dac", }, {}, @@ -307,9 +395,11 @@ MODULE_DEVICE_TABLE(of, stm32_dac_of_match); static struct platform_driver stm32_dac_driver = { .probe = stm32_dac_probe, + .remove = stm32_dac_remove, .driver = { .name = "stm32-dac", .of_match_table = stm32_dac_of_match, + .pm = &stm32_dac_pm_ops, }, }; module_platform_driver(stm32_dac_driver); diff --git a/drivers/iio/gyro/adis16080.c b/drivers/iio/gyro/adis16080.c index 236220d6de02..1b84b8e112fe 100644 --- a/drivers/iio/gyro/adis16080.c +++ b/drivers/iio/gyro/adis16080.c @@ -38,10 +38,12 @@ struct adis16080_chip_info { * @us: actual spi_device to write data * @info: chip specific parameters * @buf: transmit or receive buffer + * @lock lock to protect buffer during reads **/ struct adis16080_state { struct spi_device *us; const struct adis16080_chip_info *info; + struct mutex lock; __be16 buf ____cacheline_aligned; }; @@ -82,9 +84,9 @@ static int adis16080_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - mutex_lock(&indio_dev->mlock); + mutex_lock(&st->lock); ret = adis16080_read_sample(indio_dev, chan->address, val); - mutex_unlock(&indio_dev->mlock); + mutex_unlock(&st->lock); return ret ? ret : IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: switch (chan->type) { @@ -196,6 +198,8 @@ static int adis16080_probe(struct spi_device *spi) /* this is only used for removal purposes */ spi_set_drvdata(spi, indio_dev); + mutex_init(&st->lock); + /* Allocate the comms buffers */ st->us = spi; st->info = &adis16080_chip_info[id->driver_data]; diff --git a/drivers/iio/gyro/adis16130.c b/drivers/iio/gyro/adis16130.c index de3f66f89496..79e63c8a2ea8 100644 --- a/drivers/iio/gyro/adis16130.c +++ b/drivers/iio/gyro/adis16130.c @@ -76,9 +76,7 @@ static int adis16130_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: /* Take the iio_dev status lock */ - mutex_lock(&indio_dev->mlock); ret = adis16130_spi_read(indio_dev, chan->address, &temp); - mutex_unlock(&indio_dev->mlock); if (ret) return ret; *val = temp; diff --git a/drivers/iio/gyro/itg3200_core.c b/drivers/iio/gyro/itg3200_core.c index 998fb8d66fe3..981ae2291505 100644 --- a/drivers/iio/gyro/itg3200_core.c +++ b/drivers/iio/gyro/itg3200_core.c @@ -154,7 +154,7 @@ static int itg3200_write_raw(struct iio_dev *indio_dev, t); mutex_unlock(&indio_dev->mlock); - return ret; + return ret; default: return -EINVAL; diff --git a/drivers/iio/gyro/mpu3050-core.c b/drivers/iio/gyro/mpu3050-core.c index 80154bca18b6..8e908a749f95 100644 --- a/drivers/iio/gyro/mpu3050-core.c +++ b/drivers/iio/gyro/mpu3050-core.c @@ -543,7 +543,7 @@ static irqreturn_t mpu3050_trigger_handler(int irq, void *p) toread = bytes_per_datum; offset = 1; /* Put in some dummy value */ - fifo_values[0] = 0xAAAA; + fifo_values[0] = cpu_to_be16(0xAAAA); } ret = regmap_bulk_read(mpu3050->map, diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c index c0acbb5d2ffb..57be68b291fa 100644 --- a/drivers/iio/gyro/st_gyro_core.c +++ b/drivers/iio/gyro/st_gyro_core.c @@ -14,7 +14,6 @@ #include <linux/types.h> #include <linux/interrupt.h> #include <linux/i2c.h> -#include <linux/gpio.h> #include <linux/irq.h> #include <linux/delay.h> #include <linux/iio/iio.h> diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig index f3c7282321a8..60bb1029e759 100644 --- a/drivers/iio/imu/Kconfig +++ b/drivers/iio/imu/Kconfig @@ -40,6 +40,33 @@ config ADIS16480 source "drivers/iio/imu/bmi160/Kconfig" +config FXOS8700 + tristate + +config FXOS8700_I2C + tristate "NXP FXOS8700 I2C driver" + depends on I2C + select FXOS8700 + select REGMAP_I2C + help + Say yes here to build support for the NXP FXOS8700 m+g combo + sensor on I2C. + + This driver can also be built as a module. If so, the module will be + called fxos8700_i2c. + +config FXOS8700_SPI + tristate "NXP FXOS8700 SPI driver" + depends on SPI + select FXOS8700 + select REGMAP_SPI + help + Say yes here to build support for the NXP FXOS8700 m+g combo + sensor on SPI. + + This driver can also be built as a module. If so, the module will be + called fxos8700_spi. + config KMX61 tristate "Kionix KMX61 6-axis accelerometer and magnetometer" depends on I2C diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile index 4a6958865504..5237fd4bc384 100644 --- a/drivers/iio/imu/Makefile +++ b/drivers/iio/imu/Makefile @@ -14,6 +14,11 @@ adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_buffer.o obj-$(CONFIG_IIO_ADIS_LIB) += adis_lib.o obj-y += bmi160/ + +obj-$(CONFIG_FXOS8700) += fxos8700_core.o +obj-$(CONFIG_FXOS8700_I2C) += fxos8700_i2c.o +obj-$(CONFIG_FXOS8700_SPI) += fxos8700_spi.o + obj-y += inv_mpu6050/ obj-$(CONFIG_KMX61) += kmx61.o diff --git a/drivers/iio/imu/fxos8700.h b/drivers/iio/imu/fxos8700.h new file mode 100644 index 000000000000..6dfb8d7099e4 --- /dev/null +++ b/drivers/iio/imu/fxos8700.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef FXOS8700_H_ +#define FXOS8700_H_ + +extern const struct regmap_config fxos8700_regmap_config; + +int fxos8700_core_probe(struct device *dev, struct regmap *regmap, + const char *name, bool use_spi); + +#endif /* FXOS8700_H_ */ diff --git a/drivers/iio/imu/fxos8700_core.c b/drivers/iio/imu/fxos8700_core.c new file mode 100644 index 000000000000..7b47be44ea59 --- /dev/null +++ b/drivers/iio/imu/fxos8700_core.c @@ -0,0 +1,649 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * FXOS8700 - NXP IMU (accelerometer plus magnetometer) + * + * IIO core driver for FXOS8700, with support for I2C/SPI busses + * + * TODO: Buffer, trigger, and IRQ support + */ +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/acpi.h> +#include <linux/bitops.h> + +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> + +#include "fxos8700.h" + +/* Register Definitions */ +#define FXOS8700_STATUS 0x00 +#define FXOS8700_OUT_X_MSB 0x01 +#define FXOS8700_OUT_X_LSB 0x02 +#define FXOS8700_OUT_Y_MSB 0x03 +#define FXOS8700_OUT_Y_LSB 0x04 +#define FXOS8700_OUT_Z_MSB 0x05 +#define FXOS8700_OUT_Z_LSB 0x06 +#define FXOS8700_F_SETUP 0x09 +#define FXOS8700_TRIG_CFG 0x0a +#define FXOS8700_SYSMOD 0x0b +#define FXOS8700_INT_SOURCE 0x0c +#define FXOS8700_WHO_AM_I 0x0d +#define FXOS8700_XYZ_DATA_CFG 0x0e +#define FXOS8700_HP_FILTER_CUTOFF 0x0f +#define FXOS8700_PL_STATUS 0x10 +#define FXOS8700_PL_CFG 0x11 +#define FXOS8700_PL_COUNT 0x12 +#define FXOS8700_PL_BF_ZCOMP 0x13 +#define FXOS8700_PL_THS_REG 0x14 +#define FXOS8700_A_FFMT_CFG 0x15 +#define FXOS8700_A_FFMT_SRC 0x16 +#define FXOS8700_A_FFMT_THS 0x17 +#define FXOS8700_A_FFMT_COUNT 0x18 +#define FXOS8700_TRANSIENT_CFG 0x1d +#define FXOS8700_TRANSIENT_SRC 0x1e +#define FXOS8700_TRANSIENT_THS 0x1f +#define FXOS8700_TRANSIENT_COUNT 0x20 +#define FXOS8700_PULSE_CFG 0x21 +#define FXOS8700_PULSE_SRC 0x22 +#define FXOS8700_PULSE_THSX 0x23 +#define FXOS8700_PULSE_THSY 0x24 +#define FXOS8700_PULSE_THSZ 0x25 +#define FXOS8700_PULSE_TMLT 0x26 +#define FXOS8700_PULSE_LTCY 0x27 +#define FXOS8700_PULSE_WIND 0x28 +#define FXOS8700_ASLP_COUNT 0x29 +#define FXOS8700_CTRL_REG1 0x2a +#define FXOS8700_CTRL_REG2 0x2b +#define FXOS8700_CTRL_REG3 0x2c +#define FXOS8700_CTRL_REG4 0x2d +#define FXOS8700_CTRL_REG5 0x2e +#define FXOS8700_OFF_X 0x2f +#define FXOS8700_OFF_Y 0x30 +#define FXOS8700_OFF_Z 0x31 +#define FXOS8700_M_DR_STATUS 0x32 +#define FXOS8700_M_OUT_X_MSB 0x33 +#define FXOS8700_M_OUT_X_LSB 0x34 +#define FXOS8700_M_OUT_Y_MSB 0x35 +#define FXOS8700_M_OUT_Y_LSB 0x36 +#define FXOS8700_M_OUT_Z_MSB 0x37 +#define FXOS8700_M_OUT_Z_LSB 0x38 +#define FXOS8700_CMP_X_MSB 0x39 +#define FXOS8700_CMP_X_LSB 0x3a +#define FXOS8700_CMP_Y_MSB 0x3b +#define FXOS8700_CMP_Y_LSB 0x3c +#define FXOS8700_CMP_Z_MSB 0x3d +#define FXOS8700_CMP_Z_LSB 0x3e +#define FXOS8700_M_OFF_X_MSB 0x3f +#define FXOS8700_M_OFF_X_LSB 0x40 +#define FXOS8700_M_OFF_Y_MSB 0x41 +#define FXOS8700_M_OFF_Y_LSB 0x42 +#define FXOS8700_M_OFF_Z_MSB 0x43 +#define FXOS8700_M_OFF_Z_LSB 0x44 +#define FXOS8700_MAX_X_MSB 0x45 +#define FXOS8700_MAX_X_LSB 0x46 +#define FXOS8700_MAX_Y_MSB 0x47 +#define FXOS8700_MAX_Y_LSB 0x48 +#define FXOS8700_MAX_Z_MSB 0x49 +#define FXOS8700_MAX_Z_LSB 0x4a +#define FXOS8700_MIN_X_MSB 0x4b +#define FXOS8700_MIN_X_LSB 0x4c +#define FXOS8700_MIN_Y_MSB 0x4d +#define FXOS8700_MIN_Y_LSB 0x4e +#define FXOS8700_MIN_Z_MSB 0x4f +#define FXOS8700_MIN_Z_LSB 0x50 +#define FXOS8700_TEMP 0x51 +#define FXOS8700_M_THS_CFG 0x52 +#define FXOS8700_M_THS_SRC 0x53 +#define FXOS8700_M_THS_X_MSB 0x54 +#define FXOS8700_M_THS_X_LSB 0x55 +#define FXOS8700_M_THS_Y_MSB 0x56 +#define FXOS8700_M_THS_Y_LSB 0x57 +#define FXOS8700_M_THS_Z_MSB 0x58 +#define FXOS8700_M_THS_Z_LSB 0x59 +#define FXOS8700_M_THS_COUNT 0x5a +#define FXOS8700_M_CTRL_REG1 0x5b +#define FXOS8700_M_CTRL_REG2 0x5c +#define FXOS8700_M_CTRL_REG3 0x5d +#define FXOS8700_M_INT_SRC 0x5e +#define FXOS8700_A_VECM_CFG 0x5f +#define FXOS8700_A_VECM_THS_MSB 0x60 +#define FXOS8700_A_VECM_THS_LSB 0x61 +#define FXOS8700_A_VECM_CNT 0x62 +#define FXOS8700_A_VECM_INITX_MSB 0x63 +#define FXOS8700_A_VECM_INITX_LSB 0x64 +#define FXOS8700_A_VECM_INITY_MSB 0x65 +#define FXOS8700_A_VECM_INITY_LSB 0x66 +#define FXOS8700_A_VECM_INITZ_MSB 0x67 +#define FXOS8700_A_VECM_INITZ_LSB 0x68 +#define FXOS8700_M_VECM_CFG 0x69 +#define FXOS8700_M_VECM_THS_MSB 0x6a +#define FXOS8700_M_VECM_THS_LSB 0x6b +#define FXOS8700_M_VECM_CNT 0x6c +#define FXOS8700_M_VECM_INITX_MSB 0x6d +#define FXOS8700_M_VECM_INITX_LSB 0x6e +#define FXOS8700_M_VECM_INITY_MSB 0x6f +#define FXOS8700_M_VECM_INITY_LSB 0x70 +#define FXOS8700_M_VECM_INITZ_MSB 0x71 +#define FXOS8700_M_VECM_INITZ_LSB 0x72 +#define FXOS8700_A_FFMT_THS_X_MSB 0x73 +#define FXOS8700_A_FFMT_THS_X_LSB 0x74 +#define FXOS8700_A_FFMT_THS_Y_MSB 0x75 +#define FXOS8700_A_FFMT_THS_Y_LSB 0x76 +#define FXOS8700_A_FFMT_THS_Z_MSB 0x77 +#define FXOS8700_A_FFMT_THS_Z_LSB 0x78 +#define FXOS8700_A_TRAN_INIT_MSB 0x79 +#define FXOS8700_A_TRAN_INIT_LSB_X 0x7a +#define FXOS8700_A_TRAN_INIT_LSB_Y 0x7b +#define FXOS8700_A_TRAN_INIT_LSB_Z 0x7d +#define FXOS8700_TM_NVM_LOCK 0x7e +#define FXOS8700_NVM_DATA0_35 0x80 +#define FXOS8700_NVM_DATA_BNK3 0xa4 +#define FXOS8700_NVM_DATA_BNK2 0xa5 +#define FXOS8700_NVM_DATA_BNK1 0xa6 +#define FXOS8700_NVM_DATA_BNK0 0xa7 + +/* Bit definitions for FXOS8700_CTRL_REG1 */ +#define FXOS8700_CTRL_ODR_MSK 0x38 +#define FXOS8700_CTRL_ODR_MAX 0x00 +#define FXOS8700_CTRL_ODR_MIN GENMASK(4, 3) + +/* Bit definitions for FXOS8700_M_CTRL_REG1 */ +#define FXOS8700_HMS_MASK GENMASK(1, 0) +#define FXOS8700_OS_MASK GENMASK(4, 2) + +/* Bit definitions for FXOS8700_M_CTRL_REG2 */ +#define FXOS8700_MAXMIN_RST BIT(2) +#define FXOS8700_MAXMIN_DIS_THS BIT(3) +#define FXOS8700_MAXMIN_DIS BIT(4) + +#define FXOS8700_ACTIVE 0x01 +#define FXOS8700_ACTIVE_MIN_USLEEP 4000 /* from table 6 in datasheet */ + +#define FXOS8700_DEVICE_ID 0xC7 +#define FXOS8700_PRE_DEVICE_ID 0xC4 +#define FXOS8700_DATA_BUF_SIZE 3 + +struct fxos8700_data { + struct regmap *regmap; + struct iio_trigger *trig; + __be16 buf[FXOS8700_DATA_BUF_SIZE] ____cacheline_aligned; +}; + +/* Regmap info */ +static const struct regmap_range read_range[] = { + { + .range_min = FXOS8700_STATUS, + .range_max = FXOS8700_A_FFMT_COUNT, + }, { + .range_min = FXOS8700_TRANSIENT_CFG, + .range_max = FXOS8700_A_FFMT_THS_Z_LSB, + }, +}; + +static const struct regmap_range write_range[] = { + { + .range_min = FXOS8700_F_SETUP, + .range_max = FXOS8700_TRIG_CFG, + }, { + .range_min = FXOS8700_XYZ_DATA_CFG, + .range_max = FXOS8700_HP_FILTER_CUTOFF, + }, { + .range_min = FXOS8700_PL_CFG, + .range_max = FXOS8700_A_FFMT_CFG, + }, { + .range_min = FXOS8700_A_FFMT_THS, + .range_max = FXOS8700_TRANSIENT_CFG, + }, { + .range_min = FXOS8700_TRANSIENT_THS, + .range_max = FXOS8700_PULSE_CFG, + }, { + .range_min = FXOS8700_PULSE_THSX, + .range_max = FXOS8700_OFF_Z, + }, { + .range_min = FXOS8700_M_OFF_X_MSB, + .range_max = FXOS8700_M_OFF_Z_LSB, + }, { + .range_min = FXOS8700_M_THS_CFG, + .range_max = FXOS8700_M_THS_CFG, + }, { + .range_min = FXOS8700_M_THS_X_MSB, + .range_max = FXOS8700_M_CTRL_REG3, + }, { + .range_min = FXOS8700_A_VECM_CFG, + .range_max = FXOS8700_A_FFMT_THS_Z_LSB, + }, +}; + +static const struct regmap_access_table driver_read_table = { + .yes_ranges = read_range, + .n_yes_ranges = ARRAY_SIZE(read_range), +}; + +static const struct regmap_access_table driver_write_table = { + .yes_ranges = write_range, + .n_yes_ranges = ARRAY_SIZE(write_range), +}; + +const struct regmap_config fxos8700_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = FXOS8700_NVM_DATA_BNK0, + .rd_table = &driver_read_table, + .wr_table = &driver_write_table, +}; +EXPORT_SYMBOL(fxos8700_regmap_config); + +#define FXOS8700_CHANNEL(_type, _axis) { \ + .type = _type, \ + .modified = 1, \ + .channel2 = IIO_MOD_##_axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ +} + +enum fxos8700_accel_scale_bits { + MODE_2G = 0, + MODE_4G, + MODE_8G, +}; + +/* scan indexes follow DATA register order */ +enum fxos8700_scan_axis { + FXOS8700_SCAN_ACCEL_X = 0, + FXOS8700_SCAN_ACCEL_Y, + FXOS8700_SCAN_ACCEL_Z, + FXOS8700_SCAN_MAGN_X, + FXOS8700_SCAN_MAGN_Y, + FXOS8700_SCAN_MAGN_Z, + FXOS8700_SCAN_RHALL, + FXOS8700_SCAN_TIMESTAMP, +}; + +enum fxos8700_sensor { + FXOS8700_ACCEL = 0, + FXOS8700_MAGN, + FXOS8700_NUM_SENSORS /* must be last */ +}; + +enum fxos8700_int_pin { + FXOS8700_PIN_INT1, + FXOS8700_PIN_INT2 +}; + +struct fxos8700_scale { + u8 bits; + int uscale; +}; + +struct fxos8700_odr { + u8 bits; + int odr; + int uodr; +}; + +static const struct fxos8700_scale fxos8700_accel_scale[] = { + { MODE_2G, 244}, + { MODE_4G, 488}, + { MODE_8G, 976}, +}; + +/* + * Accellerometer and magnetometer have the same ODR options, set in the + * CTRL_REG1 register. ODR is halved when using both sensors at once in + * hybrid mode. + */ +static const struct fxos8700_odr fxos8700_odr[] = { + {0x00, 800, 0}, + {0x01, 400, 0}, + {0x02, 200, 0}, + {0x03, 100, 0}, + {0x04, 50, 0}, + {0x05, 12, 500000}, + {0x06, 6, 250000}, + {0x07, 1, 562500}, +}; + +static const struct iio_chan_spec fxos8700_channels[] = { + FXOS8700_CHANNEL(IIO_ACCEL, X), + FXOS8700_CHANNEL(IIO_ACCEL, Y), + FXOS8700_CHANNEL(IIO_ACCEL, Z), + FXOS8700_CHANNEL(IIO_MAGN, X), + FXOS8700_CHANNEL(IIO_MAGN, Y), + FXOS8700_CHANNEL(IIO_MAGN, Z), + IIO_CHAN_SOFT_TIMESTAMP(FXOS8700_SCAN_TIMESTAMP), +}; + +static enum fxos8700_sensor fxos8700_to_sensor(enum iio_chan_type iio_type) +{ + switch (iio_type) { + case IIO_ACCEL: + return FXOS8700_ACCEL; + case IIO_ANGL_VEL: + return FXOS8700_MAGN; + default: + return -EINVAL; + } +} + +static int fxos8700_set_active_mode(struct fxos8700_data *data, + enum fxos8700_sensor t, bool mode) +{ + int ret; + + ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1, mode); + if (ret) + return ret; + + usleep_range(FXOS8700_ACTIVE_MIN_USLEEP, + FXOS8700_ACTIVE_MIN_USLEEP + 1000); + + return 0; +} + +static int fxos8700_set_scale(struct fxos8700_data *data, + enum fxos8700_sensor t, int uscale) +{ + int i; + static const int scale_num = ARRAY_SIZE(fxos8700_accel_scale); + struct device *dev = regmap_get_device(data->regmap); + + if (t == FXOS8700_MAGN) { + dev_err(dev, "Magnetometer scale is locked at 1200uT\n"); + return -EINVAL; + } + + for (i = 0; i < scale_num; i++) + if (fxos8700_accel_scale[i].uscale == uscale) + break; + + if (i == scale_num) + return -EINVAL; + + return regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG, + fxos8700_accel_scale[i].bits); +} + +static int fxos8700_get_scale(struct fxos8700_data *data, + enum fxos8700_sensor t, int *uscale) +{ + int i, ret, val; + static const int scale_num = ARRAY_SIZE(fxos8700_accel_scale); + + if (t == FXOS8700_MAGN) { + *uscale = 1200; /* Magnetometer is locked at 1200uT */ + return 0; + } + + ret = regmap_read(data->regmap, FXOS8700_XYZ_DATA_CFG, &val); + if (ret) + return ret; + + for (i = 0; i < scale_num; i++) { + if (fxos8700_accel_scale[i].bits == (val & 0x3)) { + *uscale = fxos8700_accel_scale[i].uscale; + return 0; + } + } + + return -EINVAL; +} + +static int fxos8700_get_data(struct fxos8700_data *data, int chan_type, + int axis, int *val) +{ + u8 base, reg; + int ret; + enum fxos8700_sensor type = fxos8700_to_sensor(chan_type); + + base = type ? FXOS8700_OUT_X_MSB : FXOS8700_M_OUT_X_MSB; + + /* Block read 6 bytes of device output registers to avoid data loss */ + ret = regmap_bulk_read(data->regmap, base, data->buf, + FXOS8700_DATA_BUF_SIZE); + if (ret) + return ret; + + /* Convert axis to buffer index */ + reg = axis - IIO_MOD_X; + + /* Convert to native endianness */ + *val = sign_extend32(be16_to_cpu(data->buf[reg]), 15); + + return 0; +} + +static int fxos8700_set_odr(struct fxos8700_data *data, enum fxos8700_sensor t, + int odr, int uodr) +{ + int i, ret, val; + bool active_mode; + static const int odr_num = ARRAY_SIZE(fxos8700_odr); + + ret = regmap_read(data->regmap, FXOS8700_CTRL_REG1, &val); + if (ret) + return ret; + + active_mode = val & FXOS8700_ACTIVE; + + if (active_mode) { + /* + * The device must be in standby mode to change any of the + * other fields within CTRL_REG1 + */ + ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1, + val & ~FXOS8700_ACTIVE); + if (ret) + return ret; + } + + for (i = 0; i < odr_num; i++) + if (fxos8700_odr[i].odr == odr && fxos8700_odr[i].uodr == uodr) + break; + + if (i >= odr_num) + return -EINVAL; + + return regmap_update_bits(data->regmap, + FXOS8700_CTRL_REG1, + FXOS8700_CTRL_ODR_MSK + FXOS8700_ACTIVE, + fxos8700_odr[i].bits << 3 | active_mode); +} + +static int fxos8700_get_odr(struct fxos8700_data *data, enum fxos8700_sensor t, + int *odr, int *uodr) +{ + int i, val, ret; + static const int odr_num = ARRAY_SIZE(fxos8700_odr); + + ret = regmap_read(data->regmap, FXOS8700_CTRL_REG1, &val); + if (ret) + return ret; + + val &= FXOS8700_CTRL_ODR_MSK; + + for (i = 0; i < odr_num; i++) + if (val == fxos8700_odr[i].bits) + break; + + if (i >= odr_num) + return -EINVAL; + + *odr = fxos8700_odr[i].odr; + *uodr = fxos8700_odr[i].uodr; + + return 0; +} + +static int fxos8700_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + int ret; + struct fxos8700_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = fxos8700_get_data(data, chan->type, chan->channel2, val); + if (ret) + return ret; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + *val = 0; + ret = fxos8700_get_scale(data, fxos8700_to_sensor(chan->type), + val2); + return ret ? ret : IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_SAMP_FREQ: + ret = fxos8700_get_odr(data, fxos8700_to_sensor(chan->type), + val, val2); + return ret ? ret : IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } +} + +static int fxos8700_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct fxos8700_data *data = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + return fxos8700_set_scale(data, fxos8700_to_sensor(chan->type), + val2); + case IIO_CHAN_INFO_SAMP_FREQ: + return fxos8700_set_odr(data, fxos8700_to_sensor(chan->type), + val, val2); + default: + return -EINVAL; + } +} + +static IIO_CONST_ATTR(in_accel_sampling_frequency_available, + "1.5625 6.25 12.5 50 100 200 400 800"); +static IIO_CONST_ATTR(in_magn_sampling_frequency_available, + "1.5625 6.25 12.5 50 100 200 400 800"); +static IIO_CONST_ATTR(in_accel_scale_available, "0.000244 0.000488 0.000976"); +static IIO_CONST_ATTR(in_magn_scale_available, "0.000001200"); + +static struct attribute *fxos8700_attrs[] = { + &iio_const_attr_in_accel_sampling_frequency_available.dev_attr.attr, + &iio_const_attr_in_magn_sampling_frequency_available.dev_attr.attr, + &iio_const_attr_in_accel_scale_available.dev_attr.attr, + &iio_const_attr_in_magn_scale_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group fxos8700_attrs_group = { + .attrs = fxos8700_attrs, +}; + +static const struct iio_info fxos8700_info = { + .read_raw = fxos8700_read_raw, + .write_raw = fxos8700_write_raw, + .attrs = &fxos8700_attrs_group, +}; + +static int fxos8700_chip_init(struct fxos8700_data *data, bool use_spi) +{ + int ret; + unsigned int val; + struct device *dev = regmap_get_device(data->regmap); + + ret = regmap_read(data->regmap, FXOS8700_WHO_AM_I, &val); + if (ret) { + dev_err(dev, "Error reading chip id\n"); + return ret; + } + if (val != FXOS8700_DEVICE_ID && val != FXOS8700_PRE_DEVICE_ID) { + dev_err(dev, "Wrong chip id, got %x expected %x or %x\n", + val, FXOS8700_DEVICE_ID, FXOS8700_PRE_DEVICE_ID); + return -ENODEV; + } + + ret = fxos8700_set_active_mode(data, FXOS8700_ACCEL, true); + if (ret) + return ret; + + ret = fxos8700_set_active_mode(data, FXOS8700_MAGN, true); + if (ret) + return ret; + + /* + * The device must be in standby mode to change any of the other fields + * within CTRL_REG1 + */ + ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1, 0x00); + if (ret) + return ret; + + /* Set max oversample ratio (OSR) and both devices active */ + ret = regmap_write(data->regmap, FXOS8700_M_CTRL_REG1, + FXOS8700_HMS_MASK | FXOS8700_OS_MASK); + if (ret) + return ret; + + /* Disable and rst min/max measurements & threshold */ + ret = regmap_write(data->regmap, FXOS8700_M_CTRL_REG2, + FXOS8700_MAXMIN_RST | FXOS8700_MAXMIN_DIS_THS | + FXOS8700_MAXMIN_DIS); + if (ret) + return ret; + + /* Max ODR (800Hz individual or 400Hz hybrid), active mode */ + ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1, + FXOS8700_CTRL_ODR_MAX | FXOS8700_ACTIVE); + if (ret) + return ret; + + /* Set for max full-scale range (+/-8G) */ + return regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG, MODE_8G); +} + +static void fxos8700_chip_uninit(void *data) +{ + struct fxos8700_data *fxos8700_data = data; + + fxos8700_set_active_mode(fxos8700_data, FXOS8700_ACCEL, false); + fxos8700_set_active_mode(fxos8700_data, FXOS8700_MAGN, false); +} + +int fxos8700_core_probe(struct device *dev, struct regmap *regmap, + const char *name, bool use_spi) +{ + struct iio_dev *indio_dev; + struct fxos8700_data *data; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + dev_set_drvdata(dev, indio_dev); + data->regmap = regmap; + + ret = fxos8700_chip_init(data, use_spi); + if (ret) + return ret; + + ret = devm_add_action_or_reset(dev, fxos8700_chip_uninit, data); + if (ret) + return ret; + + indio_dev->dev.parent = dev; + indio_dev->channels = fxos8700_channels; + indio_dev->num_channels = ARRAY_SIZE(fxos8700_channels); + indio_dev->name = name ? name : "fxos8700"; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &fxos8700_info; + + return devm_iio_device_register(dev, indio_dev); +} +EXPORT_SYMBOL_GPL(fxos8700_core_probe); + +MODULE_AUTHOR("Robert Jones <rjones@gateworks.com>"); +MODULE_DESCRIPTION("FXOS8700 6-Axis Acc and Mag Combo Sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/imu/fxos8700_i2c.c b/drivers/iio/imu/fxos8700_i2c.c new file mode 100644 index 000000000000..3ceb76366313 --- /dev/null +++ b/drivers/iio/imu/fxos8700_i2c.c @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * FXOS8700 - NXP IMU, I2C bits + * + * 7-bit I2C slave address determined by SA1 and SA0 logic level + * inputs represented in the following table: + * SA1 | SA0 | Slave Address + * 0 | 0 | 0x1E + * 0 | 1 | 0x1D + * 1 | 0 | 0x1C + * 1 | 1 | 0x1F + */ +#include <linux/acpi.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/regmap.h> + +#include "fxos8700.h" + +static int fxos8700_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct regmap *regmap; + const char *name = NULL; + + regmap = devm_regmap_init_i2c(client, &fxos8700_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&client->dev, "Failed to register i2c regmap %d\n", + (int)PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + + if (id) + name = id->name; + + return fxos8700_core_probe(&client->dev, regmap, name, false); +} + +static const struct i2c_device_id fxos8700_i2c_id[] = { + {"fxos8700", 0}, + { } +}; +MODULE_DEVICE_TABLE(i2c, fxos8700_i2c_id); + +static const struct acpi_device_id fxos8700_acpi_match[] = { + {"FXOS8700", 0}, + { } +}; +MODULE_DEVICE_TABLE(acpi, fxos8700_acpi_match); + +static const struct of_device_id fxos8700_of_match[] = { + { .compatible = "nxp,fxos8700" }, + { } +}; +MODULE_DEVICE_TABLE(of, fxos8700_of_match); + +static struct i2c_driver fxos8700_i2c_driver = { + .driver = { + .name = "fxos8700_i2c", + .acpi_match_table = ACPI_PTR(fxos8700_acpi_match), + .of_match_table = fxos8700_of_match, + }, + .probe = fxos8700_i2c_probe, + .id_table = fxos8700_i2c_id, +}; +module_i2c_driver(fxos8700_i2c_driver); + +MODULE_AUTHOR("Robert Jones <rjones@gateworks.com>"); +MODULE_DESCRIPTION("FXOS8700 I2C driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/imu/fxos8700_spi.c b/drivers/iio/imu/fxos8700_spi.c new file mode 100644 index 000000000000..57e7bb6444e7 --- /dev/null +++ b/drivers/iio/imu/fxos8700_spi.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * FXOS8700 - NXP IMU, SPI bits + */ +#include <linux/acpi.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/regmap.h> +#include <linux/spi/spi.h> + +#include "fxos8700.h" + +static int fxos8700_spi_probe(struct spi_device *spi) +{ + struct regmap *regmap; + const struct spi_device_id *id = spi_get_device_id(spi); + + regmap = devm_regmap_init_spi(spi, &fxos8700_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&spi->dev, "Failed to register spi regmap %d\n", + (int)PTR_ERR(regmap)); + return PTR_ERR(regmap); + } + + return fxos8700_core_probe(&spi->dev, regmap, id->name, true); +} + +static const struct spi_device_id fxos8700_spi_id[] = { + {"fxos8700", 0}, + { } +}; +MODULE_DEVICE_TABLE(spi, fxos8700_spi_id); + +static const struct acpi_device_id fxos8700_acpi_match[] = { + {"FXOS8700", 0}, + { } +}; +MODULE_DEVICE_TABLE(acpi, fxos8700_acpi_match); + +static const struct of_device_id fxos8700_of_match[] = { + { .compatible = "nxp,fxos8700" }, + { } +}; +MODULE_DEVICE_TABLE(of, fxos8700_of_match); + +static struct spi_driver fxos8700_spi_driver = { + .probe = fxos8700_spi_probe, + .id_table = fxos8700_spi_id, + .driver = { + .acpi_match_table = ACPI_PTR(fxos8700_acpi_match), + .of_match_table = fxos8700_of_match, + .name = "fxos8700_spi", + }, +}; +module_spi_driver(fxos8700_spi_driver); + +MODULE_AUTHOR("Robert Jones <rjones@gateworks.com>"); +MODULE_DESCRIPTION("FXOS8700 SPI driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/imu/inv_mpu6050/Makefile b/drivers/iio/imu/inv_mpu6050/Makefile index 70ffe0d13d8c..c103441a906b 100644 --- a/drivers/iio/imu/inv_mpu6050/Makefile +++ b/drivers/iio/imu/inv_mpu6050/Makefile @@ -4,10 +4,11 @@ # obj-$(CONFIG_INV_MPU6050_IIO) += inv-mpu6050.o -inv-mpu6050-objs := inv_mpu_core.o inv_mpu_ring.o inv_mpu_trigger.o +inv-mpu6050-y := inv_mpu_core.o inv_mpu_ring.o inv_mpu_trigger.o \ + inv_mpu_aux.o inv_mpu_magn.o obj-$(CONFIG_INV_MPU6050_I2C) += inv-mpu6050-i2c.o -inv-mpu6050-i2c-objs := inv_mpu_i2c.o inv_mpu_acpi.o +inv-mpu6050-i2c-y := inv_mpu_i2c.o inv_mpu_acpi.o obj-$(CONFIG_INV_MPU6050_SPI) += inv-mpu6050-spi.o -inv-mpu6050-spi-objs := inv_mpu_spi.o +inv-mpu6050-spi-y := inv_mpu_spi.o diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c new file mode 100644 index 000000000000..7327e5723f96 --- /dev/null +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.c @@ -0,0 +1,204 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 TDK-InvenSense, Inc. + */ + +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/regmap.h> +#include <linux/delay.h> + +#include "inv_mpu_aux.h" +#include "inv_mpu_iio.h" + +/* + * i2c master auxiliary bus transfer function. + * Requires the i2c operations to be correctly setup before. + */ +static int inv_mpu_i2c_master_xfer(const struct inv_mpu6050_state *st) +{ + /* use 50hz frequency for xfer */ + const unsigned int freq = 50; + const unsigned int period_ms = 1000 / freq; + uint8_t d; + unsigned int user_ctrl; + int ret; + + /* set sample rate */ + d = INV_MPU6050_FIFO_RATE_TO_DIVIDER(freq); + ret = regmap_write(st->map, st->reg->sample_rate_div, d); + if (ret) + return ret; + + /* start i2c master */ + user_ctrl = st->chip_config.user_ctrl | INV_MPU6050_BIT_I2C_MST_EN; + ret = regmap_write(st->map, st->reg->user_ctrl, user_ctrl); + if (ret) + goto error_restore_rate; + + /* wait for xfer: 1 period + half-period margin */ + msleep(period_ms + period_ms / 2); + + /* stop i2c master */ + user_ctrl = st->chip_config.user_ctrl; + ret = regmap_write(st->map, st->reg->user_ctrl, user_ctrl); + if (ret) + goto error_stop_i2c; + + /* restore sample rate */ + d = st->chip_config.divider; + ret = regmap_write(st->map, st->reg->sample_rate_div, d); + if (ret) + goto error_restore_rate; + + return 0; + +error_stop_i2c: + regmap_write(st->map, st->reg->user_ctrl, st->chip_config.user_ctrl); +error_restore_rate: + regmap_write(st->map, st->reg->sample_rate_div, st->chip_config.divider); + return ret; +} + +/** + * inv_mpu_aux_init() - init i2c auxiliary bus + * @st: driver internal state + * + * Returns 0 on success, a negative error code otherwise. + */ +int inv_mpu_aux_init(const struct inv_mpu6050_state *st) +{ + unsigned int val; + int ret; + + /* configure i2c master */ + val = INV_MPU6050_BITS_I2C_MST_CLK_400KHZ | + INV_MPU6050_BIT_WAIT_FOR_ES; + ret = regmap_write(st->map, INV_MPU6050_REG_I2C_MST_CTRL, val); + if (ret) + return ret; + + /* configure i2c master delay */ + ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV4_CTRL, 0); + if (ret) + return ret; + + val = INV_MPU6050_BIT_I2C_SLV0_DLY_EN | + INV_MPU6050_BIT_I2C_SLV1_DLY_EN | + INV_MPU6050_BIT_I2C_SLV2_DLY_EN | + INV_MPU6050_BIT_I2C_SLV3_DLY_EN | + INV_MPU6050_BIT_DELAY_ES_SHADOW; + return regmap_write(st->map, INV_MPU6050_REG_I2C_MST_DELAY_CTRL, val); +} + +/** + * inv_mpu_aux_read() - read register function for i2c auxiliary bus + * @st: driver internal state. + * @addr: chip i2c Address + * @reg: chip register address + * @val: buffer for storing read bytes + * @size: number of bytes to read + * + * Returns 0 on success, a negative error code otherwise. + */ +int inv_mpu_aux_read(const struct inv_mpu6050_state *st, uint8_t addr, + uint8_t reg, uint8_t *val, size_t size) +{ + unsigned int status; + int ret; + + if (size > 0x0F) + return -EINVAL; + + /* setup i2c SLV0 control: i2c addr, register, enable + size */ + ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_ADDR(0), + INV_MPU6050_BIT_I2C_SLV_RNW | addr); + if (ret) + return ret; + ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_REG(0), reg); + if (ret) + return ret; + ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), + INV_MPU6050_BIT_SLV_EN | size); + if (ret) + return ret; + + /* do i2c xfer */ + ret = inv_mpu_i2c_master_xfer(st); + if (ret) + goto error_disable_i2c; + + /* disable i2c slave */ + ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), 0); + if (ret) + goto error_disable_i2c; + + /* check i2c status */ + ret = regmap_read(st->map, INV_MPU6050_REG_I2C_MST_STATUS, &status); + if (ret) + return ret; + if (status & INV_MPU6050_BIT_I2C_SLV0_NACK) + return -EIO; + + /* read data in registers */ + return regmap_bulk_read(st->map, INV_MPU6050_REG_EXT_SENS_DATA, + val, size); + +error_disable_i2c: + regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), 0); + return ret; +} + +/** + * inv_mpu_aux_write() - write register function for i2c auxiliary bus + * @st: driver internal state. + * @addr: chip i2c Address + * @reg: chip register address + * @val: 1 byte value to write + * + * Returns 0 on success, a negative error code otherwise. + */ +int inv_mpu_aux_write(const struct inv_mpu6050_state *st, uint8_t addr, + uint8_t reg, uint8_t val) +{ + unsigned int status; + int ret; + + /* setup i2c SLV0 control: i2c addr, register, value, enable + size */ + ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_ADDR(0), addr); + if (ret) + return ret; + ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_REG(0), reg); + if (ret) + return ret; + ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_DO(0), val); + if (ret) + return ret; + ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), + INV_MPU6050_BIT_SLV_EN | 1); + if (ret) + return ret; + + /* do i2c xfer */ + ret = inv_mpu_i2c_master_xfer(st); + if (ret) + goto error_disable_i2c; + + /* disable i2c slave */ + ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), 0); + if (ret) + goto error_disable_i2c; + + /* check i2c status */ + ret = regmap_read(st->map, INV_MPU6050_REG_I2C_MST_STATUS, &status); + if (ret) + return ret; + if (status & INV_MPU6050_BIT_I2C_SLV0_NACK) + return -EIO; + + return 0; + +error_disable_i2c: + regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), 0); + return ret; +} diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.h new file mode 100644 index 000000000000..b66997545762 --- /dev/null +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_aux.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2019 TDK-InvenSense, Inc. + */ + +#ifndef INV_MPU_AUX_H_ +#define INV_MPU_AUX_H_ + +#include "inv_mpu_iio.h" + +int inv_mpu_aux_init(const struct inv_mpu6050_state *st); + +int inv_mpu_aux_read(const struct inv_mpu6050_state *st, uint8_t addr, + uint8_t reg, uint8_t *val, size_t size); + +int inv_mpu_aux_write(const struct inv_mpu6050_state *st, uint8_t addr, + uint8_t reg, uint8_t val); + +#endif /* INV_MPU_AUX_H_ */ diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index 868281b8adb0..9f9acde229c8 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -17,6 +17,7 @@ #include <linux/platform_device.h> #include <linux/regulator/consumer.h> #include "inv_mpu_iio.h" +#include "inv_mpu_magn.h" /* * this is the gyro scale translated from dynamic range plus/minus @@ -103,6 +104,7 @@ static const struct inv_mpu6050_chip_config chip_config_6050 = { .divider = INV_MPU6050_FIFO_RATE_TO_DIVIDER(INV_MPU6050_INIT_FIFO_RATE), .gyro_fifo_enable = false, .accl_fifo_enable = false, + .magn_fifo_enable = false, .accl_fs = INV_MPU6050_FS_02G, .user_ctrl = 0, }; @@ -341,6 +343,11 @@ static int inv_mpu6050_init_config(struct iio_dev *indio_dev) */ st->chip_period = NSEC_PER_MSEC; + /* magn chip init, noop if not present in the chip */ + result = inv_mpu_magn_probe(st); + if (result) + goto error_power_off; + return inv_mpu6050_set_power_itg(st, false); error_power_off: @@ -420,6 +427,9 @@ static int inv_mpu6050_read_channel_data(struct iio_dev *indio_dev, ret = inv_mpu6050_sensor_show(st, st->reg->temperature, IIO_MOD_X, val); break; + case IIO_MAGN: + ret = inv_mpu_magn_read(st, chan->channel2, val); + break; default: ret = -EINVAL; break; @@ -478,6 +488,8 @@ inv_mpu6050_read_raw(struct iio_dev *indio_dev, *val2 = INV_MPU6050_TEMP_SCALE; return IIO_VAL_INT_PLUS_MICRO; + case IIO_MAGN: + return inv_mpu_magn_get_scale(st, chan, val, val2); default: return -EINVAL; } @@ -719,6 +731,11 @@ inv_mpu6050_fifo_rate_store(struct device *dev, struct device_attribute *attr, if (result) goto fifo_rate_fail_power_off; + /* update rate for magn, noop if not present in chip */ + result = inv_mpu_magn_set_rate(st, fifo_rate); + if (result) + goto fifo_rate_fail_power_off; + fifo_rate_fail_power_off: result |= inv_mpu6050_set_power_itg(st, false); fifo_rate_fail_unlock: @@ -804,8 +821,14 @@ inv_get_mount_matrix(const struct iio_dev *indio_dev, const struct iio_chan_spec *chan) { struct inv_mpu6050_state *data = iio_priv(indio_dev); + const struct iio_mount_matrix *matrix; - return &data->orientation; + if (chan->type == IIO_MAGN) + matrix = &data->magn_orient; + else + matrix = &data->orientation; + + return matrix; } static const struct iio_chan_spec_ext_info inv_ext_info[] = { @@ -873,6 +896,98 @@ static const unsigned long inv_mpu_scan_masks[] = { 0, }; +#define INV_MPU9X50_MAGN_CHAN(_chan2, _bits, _index) \ + { \ + .type = IIO_MAGN, \ + .modified = 1, \ + .channel2 = _chan2, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_RAW), \ + .scan_index = _index, \ + .scan_type = { \ + .sign = 's', \ + .realbits = _bits, \ + .storagebits = 16, \ + .shift = 0, \ + .endianness = IIO_BE, \ + }, \ + .ext_info = inv_ext_info, \ + } + +static const struct iio_chan_spec inv_mpu9250_channels[] = { + IIO_CHAN_SOFT_TIMESTAMP(INV_MPU9X50_SCAN_TIMESTAMP), + /* + * Note that temperature should only be via polled reading only, + * not the final scan elements output. + */ + { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) + | BIT(IIO_CHAN_INFO_OFFSET) + | BIT(IIO_CHAN_INFO_SCALE), + .scan_index = -1, + }, + INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_X, INV_MPU6050_SCAN_GYRO_X), + INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Y, INV_MPU6050_SCAN_GYRO_Y), + INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Z, INV_MPU6050_SCAN_GYRO_Z), + + INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_X, INV_MPU6050_SCAN_ACCL_X), + INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Y, INV_MPU6050_SCAN_ACCL_Y), + INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Z, INV_MPU6050_SCAN_ACCL_Z), + + /* Magnetometer resolution is 16 bits */ + INV_MPU9X50_MAGN_CHAN(IIO_MOD_X, 16, INV_MPU9X50_SCAN_MAGN_X), + INV_MPU9X50_MAGN_CHAN(IIO_MOD_Y, 16, INV_MPU9X50_SCAN_MAGN_Y), + INV_MPU9X50_MAGN_CHAN(IIO_MOD_Z, 16, INV_MPU9X50_SCAN_MAGN_Z), +}; + +static const unsigned long inv_mpu9x50_scan_masks[] = { + /* 3-axis accel */ + BIT(INV_MPU6050_SCAN_ACCL_X) + | BIT(INV_MPU6050_SCAN_ACCL_Y) + | BIT(INV_MPU6050_SCAN_ACCL_Z), + /* 3-axis gyro */ + BIT(INV_MPU6050_SCAN_GYRO_X) + | BIT(INV_MPU6050_SCAN_GYRO_Y) + | BIT(INV_MPU6050_SCAN_GYRO_Z), + /* 3-axis magn */ + BIT(INV_MPU9X50_SCAN_MAGN_X) + | BIT(INV_MPU9X50_SCAN_MAGN_Y) + | BIT(INV_MPU9X50_SCAN_MAGN_Z), + /* 6-axis accel + gyro */ + BIT(INV_MPU6050_SCAN_ACCL_X) + | BIT(INV_MPU6050_SCAN_ACCL_Y) + | BIT(INV_MPU6050_SCAN_ACCL_Z) + | BIT(INV_MPU6050_SCAN_GYRO_X) + | BIT(INV_MPU6050_SCAN_GYRO_Y) + | BIT(INV_MPU6050_SCAN_GYRO_Z), + /* 6-axis accel + magn */ + BIT(INV_MPU6050_SCAN_ACCL_X) + | BIT(INV_MPU6050_SCAN_ACCL_Y) + | BIT(INV_MPU6050_SCAN_ACCL_Z) + | BIT(INV_MPU9X50_SCAN_MAGN_X) + | BIT(INV_MPU9X50_SCAN_MAGN_Y) + | BIT(INV_MPU9X50_SCAN_MAGN_Z), + /* 6-axis gyro + magn */ + BIT(INV_MPU6050_SCAN_GYRO_X) + | BIT(INV_MPU6050_SCAN_GYRO_Y) + | BIT(INV_MPU6050_SCAN_GYRO_Z) + | BIT(INV_MPU9X50_SCAN_MAGN_X) + | BIT(INV_MPU9X50_SCAN_MAGN_Y) + | BIT(INV_MPU9X50_SCAN_MAGN_Z), + /* 9-axis accel + gyro + magn */ + BIT(INV_MPU6050_SCAN_ACCL_X) + | BIT(INV_MPU6050_SCAN_ACCL_Y) + | BIT(INV_MPU6050_SCAN_ACCL_Z) + | BIT(INV_MPU6050_SCAN_GYRO_X) + | BIT(INV_MPU6050_SCAN_GYRO_Y) + | BIT(INV_MPU6050_SCAN_GYRO_Z) + | BIT(INV_MPU9X50_SCAN_MAGN_X) + | BIT(INV_MPU9X50_SCAN_MAGN_Y) + | BIT(INV_MPU9X50_SCAN_MAGN_Z), + 0, +}; + static const struct iio_chan_spec inv_icm20602_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(INV_ICM20602_SCAN_TIMESTAMP), { @@ -1154,6 +1269,11 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, return result; } + /* fill magnetometer orientation */ + result = inv_mpu_magn_set_orient(st); + if (result) + return result; + /* power is turned on inside check chip type*/ result = inv_check_and_setup_chip(st); if (result) @@ -1165,9 +1285,6 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, return result; } - if (inv_mpu_bus_setup) - inv_mpu_bus_setup(indio_dev); - dev_set_drvdata(dev, indio_dev); indio_dev->dev.parent = dev; /* name will be NULL when enumerated via ACPI */ @@ -1176,14 +1293,37 @@ int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, else indio_dev->name = dev_name(dev); - if (chip_type == INV_ICM20602) { + /* requires parent device set in indio_dev */ + if (inv_mpu_bus_setup) + inv_mpu_bus_setup(indio_dev); + + switch (chip_type) { + case INV_MPU9250: + case INV_MPU9255: + /* + * Use magnetometer inside the chip only if there is no i2c + * auxiliary device in use. + */ + if (!st->magn_disabled) { + indio_dev->channels = inv_mpu9250_channels; + indio_dev->num_channels = ARRAY_SIZE(inv_mpu9250_channels); + indio_dev->available_scan_masks = inv_mpu9x50_scan_masks; + } else { + indio_dev->channels = inv_mpu_channels; + indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels); + indio_dev->available_scan_masks = inv_mpu_scan_masks; + } + break; + case INV_ICM20602: indio_dev->channels = inv_icm20602_channels; indio_dev->num_channels = ARRAY_SIZE(inv_icm20602_channels); indio_dev->available_scan_masks = inv_icm20602_scan_masks; - } else { + break; + default: indio_dev->channels = inv_mpu_channels; indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels); indio_dev->available_scan_masks = inv_mpu_scan_masks; + break; } indio_dev->info = &mpu_info; diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c index 4b8b5a87398c..389cc8505e0e 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c @@ -68,6 +68,56 @@ static const char *inv_mpu_match_acpi_device(struct device *dev, return dev_name(dev); } +static bool inv_mpu_i2c_aux_bus(struct device *dev) +{ + struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(dev)); + + switch (st->chip_type) { + case INV_ICM20608: + case INV_ICM20602: + /* no i2c auxiliary bus on the chip */ + return false; + case INV_MPU9250: + case INV_MPU9255: + if (st->magn_disabled) + return true; + else + return false; + default: + return true; + } +} + +/* + * MPU9xxx magnetometer support requires to disable i2c auxiliary bus support. + * To ensure backward compatibility with existing setups, do not disable + * i2c auxiliary bus if it used. + * Check for i2c-gate node in devicetree and set magnetometer disabled. + * Only MPU6500 is supported by ACPI, no need to check. + */ +static int inv_mpu_magn_disable(struct iio_dev *indio_dev) +{ + struct inv_mpu6050_state *st = iio_priv(indio_dev); + struct device *dev = indio_dev->dev.parent; + struct device_node *mux_node; + + switch (st->chip_type) { + case INV_MPU9250: + case INV_MPU9255: + mux_node = of_get_child_by_name(dev->of_node, "i2c-gate"); + if (mux_node != NULL) { + st->magn_disabled = true; + dev_warn(dev, "disable internal use of magnetometer\n"); + } + of_node_put(mux_node); + break; + default: + break; + } + + return 0; +} + /** * inv_mpu_probe() - probe function. * @client: i2c client. @@ -112,17 +162,12 @@ static int inv_mpu_probe(struct i2c_client *client, } result = inv_mpu_core_probe(regmap, client->irq, name, - NULL, chip_type); + inv_mpu_magn_disable, chip_type); if (result < 0) return result; st = iio_priv(dev_get_drvdata(&client->dev)); - switch (st->chip_type) { - case INV_ICM20608: - case INV_ICM20602: - /* no i2c auxiliary bus on the chip */ - break; - default: + if (inv_mpu_i2c_aux_bus(&client->dev)) { /* declare i2c auxiliary bus */ st->muxc = i2c_mux_alloc(client->adapter, &client->dev, 1, 0, I2C_MUX_LOCKED | I2C_MUX_GATE, @@ -137,7 +182,6 @@ static int inv_mpu_probe(struct i2c_client *client, result = inv_mpu_acpi_create_mux_client(client); if (result) goto out_del_mux; - break; } return 0; diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h index 51235677c534..5f6bbe880d78 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h @@ -2,6 +2,10 @@ /* * Copyright (C) 2012 Invensense, Inc. */ + +#ifndef INV_MPU_IIO_H_ +#define INV_MPU_IIO_H_ + #include <linux/i2c.h> #include <linux/i2c-mux.h> #include <linux/mutex.h> @@ -82,6 +86,7 @@ enum inv_devices { * @accl_fs: accel full scale range. * @accl_fifo_enable: enable accel data output * @gyro_fifo_enable: enable gyro data output + * @magn_fifo_enable: enable magn data output * @divider: chip sample rate divider (sample rate divider - 1) */ struct inv_mpu6050_chip_config { @@ -90,6 +95,7 @@ struct inv_mpu6050_chip_config { unsigned int accl_fs:2; unsigned int accl_fifo_enable:1; unsigned int gyro_fifo_enable:1; + unsigned int magn_fifo_enable:1; u8 divider; u8 user_ctrl; }; @@ -127,6 +133,9 @@ struct inv_mpu6050_hw { * @it_timestamp: timestamp from previous interrupt. * @data_timestamp: timestamp for next data sample. * @vddio_supply voltage regulator for the chip. + * @magn_disabled: magnetometer disabled for backward compatibility reason. + * @magn_raw_to_gauss: coefficient to convert mag raw value to Gauss. + * @magn_orient: magnetometer sensor chip orientation if available. */ struct inv_mpu6050_state { struct mutex lock; @@ -148,6 +157,9 @@ struct inv_mpu6050_state { s64 it_timestamp; s64 data_timestamp; struct regulator *vddio_supply; + bool magn_disabled; + s32 magn_raw_to_gauss[3]; + struct iio_mount_matrix magn_orient; }; /*register and associated bit definition*/ @@ -160,9 +172,41 @@ struct inv_mpu6050_state { #define INV_MPU6050_REG_ACCEL_CONFIG 0x1C #define INV_MPU6050_REG_FIFO_EN 0x23 +#define INV_MPU6050_BIT_SLAVE_0 0x01 +#define INV_MPU6050_BIT_SLAVE_1 0x02 +#define INV_MPU6050_BIT_SLAVE_2 0x04 #define INV_MPU6050_BIT_ACCEL_OUT 0x08 #define INV_MPU6050_BITS_GYRO_OUT 0x70 +#define INV_MPU6050_REG_I2C_MST_CTRL 0x24 +#define INV_MPU6050_BITS_I2C_MST_CLK_400KHZ 0x0D +#define INV_MPU6050_BIT_I2C_MST_P_NSR 0x10 +#define INV_MPU6050_BIT_SLV3_FIFO_EN 0x20 +#define INV_MPU6050_BIT_WAIT_FOR_ES 0x40 +#define INV_MPU6050_BIT_MULT_MST_EN 0x80 + +/* control I2C slaves from 0 to 3 */ +#define INV_MPU6050_REG_I2C_SLV_ADDR(_x) (0x25 + 3 * (_x)) +#define INV_MPU6050_BIT_I2C_SLV_RNW 0x80 + +#define INV_MPU6050_REG_I2C_SLV_REG(_x) (0x26 + 3 * (_x)) + +#define INV_MPU6050_REG_I2C_SLV_CTRL(_x) (0x27 + 3 * (_x)) +#define INV_MPU6050_BIT_SLV_GRP 0x10 +#define INV_MPU6050_BIT_SLV_REG_DIS 0x20 +#define INV_MPU6050_BIT_SLV_BYTE_SW 0x40 +#define INV_MPU6050_BIT_SLV_EN 0x80 + +/* I2C master delay register */ +#define INV_MPU6050_REG_I2C_SLV4_CTRL 0x34 +#define INV_MPU6050_BITS_I2C_MST_DLY(_x) ((_x) & 0x1F) + +#define INV_MPU6050_REG_I2C_MST_STATUS 0x36 +#define INV_MPU6050_BIT_I2C_SLV0_NACK 0x01 +#define INV_MPU6050_BIT_I2C_SLV1_NACK 0x02 +#define INV_MPU6050_BIT_I2C_SLV2_NACK 0x04 +#define INV_MPU6050_BIT_I2C_SLV3_NACK 0x08 + #define INV_MPU6050_REG_INT_ENABLE 0x38 #define INV_MPU6050_BIT_DATA_RDY_EN 0x01 #define INV_MPU6050_BIT_DMP_INT_EN 0x02 @@ -175,6 +219,18 @@ struct inv_mpu6050_state { #define INV_MPU6050_BIT_FIFO_OVERFLOW_INT 0x10 #define INV_MPU6050_BIT_RAW_DATA_RDY_INT 0x01 +#define INV_MPU6050_REG_EXT_SENS_DATA 0x49 + +/* I2C slaves data output from 0 to 3 */ +#define INV_MPU6050_REG_I2C_SLV_DO(_x) (0x63 + (_x)) + +#define INV_MPU6050_REG_I2C_MST_DELAY_CTRL 0x67 +#define INV_MPU6050_BIT_I2C_SLV0_DLY_EN 0x01 +#define INV_MPU6050_BIT_I2C_SLV1_DLY_EN 0x02 +#define INV_MPU6050_BIT_I2C_SLV2_DLY_EN 0x04 +#define INV_MPU6050_BIT_I2C_SLV3_DLY_EN 0x08 +#define INV_MPU6050_BIT_DELAY_ES_SHADOW 0x80 + #define INV_MPU6050_REG_USER_CTRL 0x6A #define INV_MPU6050_BIT_FIFO_RST 0x04 #define INV_MPU6050_BIT_DMP_RST 0x08 @@ -202,6 +258,9 @@ struct inv_mpu6050_state { #define INV_MPU6050_BYTES_PER_3AXIS_SENSOR 6 #define INV_MPU6050_FIFO_COUNT_BYTE 2 +/* MPU9X50 9-axis magnetometer */ +#define INV_MPU9X50_BYTES_MAGN 7 + /* ICM20602 FIFO samples include temperature readings */ #define INV_ICM20602_BYTES_PER_TEMP_SENSOR 2 @@ -229,8 +288,8 @@ struct inv_mpu6050_state { #define INV_ICM20602_TEMP_OFFSET 8170 #define INV_ICM20602_TEMP_SCALE 3060 -/* 6 + 6 round up and plus 8 */ -#define INV_MPU6050_OUTPUT_DATA_SIZE 24 +/* 6 + 6 + 7 (for MPU9x50) = 19 round up to 24 and plus 8 */ +#define INV_MPU6050_OUTPUT_DATA_SIZE 32 #define INV_MPU6050_REG_INT_PIN_CFG 0x37 #define INV_MPU6050_ACTIVE_HIGH 0x00 @@ -279,6 +338,11 @@ enum inv_mpu6050_scan { INV_MPU6050_SCAN_GYRO_Y, INV_MPU6050_SCAN_GYRO_Z, INV_MPU6050_SCAN_TIMESTAMP, + + INV_MPU9X50_SCAN_MAGN_X = INV_MPU6050_SCAN_GYRO_Z + 1, + INV_MPU9X50_SCAN_MAGN_Y, + INV_MPU9X50_SCAN_MAGN_Z, + INV_MPU9X50_SCAN_TIMESTAMP, }; /* scan element definition for ICM20602, which includes temperature */ @@ -344,3 +408,5 @@ void inv_mpu_acpi_delete_mux_client(struct i2c_client *client); int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, int (*inv_mpu_bus_setup)(struct iio_dev *), int chip_type); extern const struct dev_pm_ops inv_mpu_pmops; + +#endif diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c new file mode 100644 index 000000000000..02735af152c8 --- /dev/null +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.c @@ -0,0 +1,356 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 TDK-InvenSense, Inc. + */ + +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/string.h> + +#include "inv_mpu_aux.h" +#include "inv_mpu_iio.h" +#include "inv_mpu_magn.h" + +/* + * MPU9250 magnetometer is an AKM AK8963 chip on I2C aux bus + */ +#define INV_MPU_MAGN_I2C_ADDR 0x0C + +#define INV_MPU_MAGN_REG_WIA 0x00 +#define INV_MPU_MAGN_BITS_WIA 0x48 + +#define INV_MPU_MAGN_REG_ST1 0x02 +#define INV_MPU_MAGN_BIT_DRDY 0x01 +#define INV_MPU_MAGN_BIT_DOR 0x02 + +#define INV_MPU_MAGN_REG_DATA 0x03 + +#define INV_MPU_MAGN_REG_ST2 0x09 +#define INV_MPU_MAGN_BIT_HOFL 0x08 +#define INV_MPU_MAGN_BIT_BITM 0x10 + +#define INV_MPU_MAGN_REG_CNTL1 0x0A +#define INV_MPU_MAGN_BITS_MODE_PWDN 0x00 +#define INV_MPU_MAGN_BITS_MODE_SINGLE 0x01 +#define INV_MPU_MAGN_BITS_MODE_FUSE 0x0F +#define INV_MPU_MAGN_BIT_OUTPUT_BIT 0x10 + +#define INV_MPU_MAGN_REG_CNTL2 0x0B +#define INV_MPU_MAGN_BIT_SRST 0x01 + +#define INV_MPU_MAGN_REG_ASAX 0x10 +#define INV_MPU_MAGN_REG_ASAY 0x11 +#define INV_MPU_MAGN_REG_ASAZ 0x12 + +/* Magnetometer maximum frequency */ +#define INV_MPU_MAGN_FREQ_HZ_MAX 50 + +static bool inv_magn_supported(const struct inv_mpu6050_state *st) +{ + switch (st->chip_type) { + case INV_MPU9250: + case INV_MPU9255: + return true; + default: + return false; + } +} + +/* init magnetometer chip */ +static int inv_magn_init(struct inv_mpu6050_state *st) +{ + uint8_t val; + uint8_t asa[3]; + int ret; + + /* check whoami */ + ret = inv_mpu_aux_read(st, INV_MPU_MAGN_I2C_ADDR, INV_MPU_MAGN_REG_WIA, + &val, sizeof(val)); + if (ret) + return ret; + if (val != INV_MPU_MAGN_BITS_WIA) + return -ENODEV; + + /* reset chip */ + ret = inv_mpu_aux_write(st, INV_MPU_MAGN_I2C_ADDR, + INV_MPU_MAGN_REG_CNTL2, + INV_MPU_MAGN_BIT_SRST); + if (ret) + return ret; + + /* read fuse ROM data */ + ret = inv_mpu_aux_write(st, INV_MPU_MAGN_I2C_ADDR, + INV_MPU_MAGN_REG_CNTL1, + INV_MPU_MAGN_BITS_MODE_FUSE); + if (ret) + return ret; + + ret = inv_mpu_aux_read(st, INV_MPU_MAGN_I2C_ADDR, INV_MPU_MAGN_REG_ASAX, + asa, sizeof(asa)); + if (ret) + return ret; + + /* switch back to power-down */ + ret = inv_mpu_aux_write(st, INV_MPU_MAGN_I2C_ADDR, + INV_MPU_MAGN_REG_CNTL1, + INV_MPU_MAGN_BITS_MODE_PWDN); + if (ret) + return ret; + + /* + * Sensitivity adjustement and scale to Gauss + * + * Hadj = H * (((ASA - 128) * 0.5 / 128) + 1) + * Factor simplification: + * Hadj = H * ((ASA + 128) / 256) + * + * Sensor sentivity + * 0.15 uT in 16 bits mode + * 1 uT = 0.01 G and value is in micron (1e6) + * sensitvity = 0.15 uT * 0.01 * 1e6 + * + * raw_to_gauss = Hadj * 1500 + */ + st->magn_raw_to_gauss[0] = (((int32_t)asa[0] + 128) * 1500) / 256; + st->magn_raw_to_gauss[1] = (((int32_t)asa[1] + 128) * 1500) / 256; + st->magn_raw_to_gauss[2] = (((int32_t)asa[2] + 128) * 1500) / 256; + + return 0; +} + +/** + * inv_mpu_magn_probe() - probe and setup magnetometer chip + * @st: driver internal state + * + * Returns 0 on success, a negative error code otherwise + * + * It is probing the chip and setting up all needed i2c transfers. + * Noop if there is no magnetometer in the chip. + */ +int inv_mpu_magn_probe(struct inv_mpu6050_state *st) +{ + int ret; + + /* quit if chip is not supported */ + if (!inv_magn_supported(st)) + return 0; + + /* configure i2c master aux port */ + ret = inv_mpu_aux_init(st); + if (ret) + return ret; + + /* check and init mag chip */ + ret = inv_magn_init(st); + if (ret) + return ret; + + /* + * configure mpu i2c master accesses + * i2c SLV0: read sensor data, 7 bytes data(6)-ST2 + * Byte swap data to store them in big-endian in impair address groups + */ + ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_ADDR(0), + INV_MPU6050_BIT_I2C_SLV_RNW | INV_MPU_MAGN_I2C_ADDR); + if (ret) + return ret; + + ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_REG(0), + INV_MPU_MAGN_REG_DATA); + if (ret) + return ret; + + ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(0), + INV_MPU6050_BIT_SLV_EN | + INV_MPU6050_BIT_SLV_BYTE_SW | + INV_MPU6050_BIT_SLV_GRP | + INV_MPU9X50_BYTES_MAGN); + if (ret) + return ret; + + /* i2c SLV1: launch single measurement */ + ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_ADDR(1), + INV_MPU_MAGN_I2C_ADDR); + if (ret) + return ret; + + ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_REG(1), + INV_MPU_MAGN_REG_CNTL1); + if (ret) + return ret; + + /* add 16 bits mode */ + ret = regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_DO(1), + INV_MPU_MAGN_BITS_MODE_SINGLE | + INV_MPU_MAGN_BIT_OUTPUT_BIT); + if (ret) + return ret; + + return regmap_write(st->map, INV_MPU6050_REG_I2C_SLV_CTRL(1), + INV_MPU6050_BIT_SLV_EN | 1); +} + +/** + * inv_mpu_magn_set_rate() - set magnetometer sampling rate + * @st: driver internal state + * @fifo_rate: mpu set fifo rate + * + * Returns 0 on success, a negative error code otherwise + * + * Limit sampling frequency to the maximum value supported by the + * magnetometer chip. Resulting in duplicated data for higher frequencies. + * Noop if there is no magnetometer in the chip. + */ +int inv_mpu_magn_set_rate(const struct inv_mpu6050_state *st, int fifo_rate) +{ + uint8_t d; + + /* quit if chip is not supported */ + if (!inv_magn_supported(st)) + return 0; + + /* + * update i2c master delay to limit mag sampling to max frequency + * compute fifo_rate divider d: rate = fifo_rate / (d + 1) + */ + if (fifo_rate > INV_MPU_MAGN_FREQ_HZ_MAX) + d = fifo_rate / INV_MPU_MAGN_FREQ_HZ_MAX - 1; + else + d = 0; + + return regmap_write(st->map, INV_MPU6050_REG_I2C_SLV4_CTRL, d); +} + +/** + * inv_mpu_magn_set_orient() - fill magnetometer mounting matrix + * @st: driver internal state + * + * Returns 0 on success, a negative error code otherwise + * + * Fill magnetometer mounting matrix using the provided chip matrix. + */ +int inv_mpu_magn_set_orient(struct inv_mpu6050_state *st) +{ + const char *orient; + char *str; + int i; + + /* fill magnetometer orientation */ + switch (st->chip_type) { + case INV_MPU9250: + case INV_MPU9255: + /* x <- y */ + st->magn_orient.rotation[0] = st->orientation.rotation[3]; + st->magn_orient.rotation[1] = st->orientation.rotation[4]; + st->magn_orient.rotation[2] = st->orientation.rotation[5]; + /* y <- x */ + st->magn_orient.rotation[3] = st->orientation.rotation[0]; + st->magn_orient.rotation[4] = st->orientation.rotation[1]; + st->magn_orient.rotation[5] = st->orientation.rotation[2]; + /* z <- -z */ + for (i = 0; i < 3; ++i) { + orient = st->orientation.rotation[6 + i]; + /* use length + 2 for adding minus sign if needed */ + str = devm_kzalloc(regmap_get_device(st->map), + strlen(orient) + 2, GFP_KERNEL); + if (str == NULL) + return -ENOMEM; + if (strcmp(orient, "0") == 0) { + strcpy(str, orient); + } else if (orient[0] == '-') { + strcpy(str, &orient[1]); + } else { + str[0] = '-'; + strcpy(&str[1], orient); + } + st->magn_orient.rotation[6 + i] = str; + } + break; + default: + st->magn_orient = st->orientation; + break; + } + + return 0; +} + +/** + * inv_mpu_magn_read() - read magnetometer data + * @st: driver internal state + * @axis: IIO modifier axis value + * @val: store corresponding axis value + * + * Returns 0 on success, a negative error code otherwise + */ +int inv_mpu_magn_read(const struct inv_mpu6050_state *st, int axis, int *val) +{ + unsigned int user_ctrl, status; + __be16 data[3]; + uint8_t addr; + uint8_t d; + unsigned int period_ms; + int ret; + + /* quit if chip is not supported */ + if (!inv_magn_supported(st)) + return -ENODEV; + + /* Mag data: X - Y - Z */ + switch (axis) { + case IIO_MOD_X: + addr = 0; + break; + case IIO_MOD_Y: + addr = 1; + break; + case IIO_MOD_Z: + addr = 2; + break; + default: + return -EINVAL; + } + + /* set sample rate to max mag freq */ + d = INV_MPU6050_FIFO_RATE_TO_DIVIDER(INV_MPU_MAGN_FREQ_HZ_MAX); + ret = regmap_write(st->map, st->reg->sample_rate_div, d); + if (ret) + return ret; + + /* start i2c master, wait for xfer, stop */ + user_ctrl = st->chip_config.user_ctrl | INV_MPU6050_BIT_I2C_MST_EN; + ret = regmap_write(st->map, st->reg->user_ctrl, user_ctrl); + if (ret) + return ret; + + /* need to wait 2 periods + half-period margin */ + period_ms = 1000 / INV_MPU_MAGN_FREQ_HZ_MAX; + msleep(period_ms * 2 + period_ms / 2); + user_ctrl = st->chip_config.user_ctrl; + ret = regmap_write(st->map, st->reg->user_ctrl, user_ctrl); + if (ret) + return ret; + + /* restore sample rate */ + d = st->chip_config.divider; + ret = regmap_write(st->map, st->reg->sample_rate_div, d); + if (ret) + return ret; + + /* check i2c status and read raw data */ + ret = regmap_read(st->map, INV_MPU6050_REG_I2C_MST_STATUS, &status); + if (ret) + return ret; + + if (status & INV_MPU6050_BIT_I2C_SLV0_NACK || + status & INV_MPU6050_BIT_I2C_SLV1_NACK) + return -EIO; + + ret = regmap_bulk_read(st->map, INV_MPU6050_REG_EXT_SENS_DATA, + data, sizeof(data)); + if (ret) + return ret; + + *val = (int16_t)be16_to_cpu(data[addr]); + + return IIO_VAL_INT; +} diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.h new file mode 100644 index 000000000000..b41bd0578478 --- /dev/null +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_magn.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2019 TDK-InvenSense, Inc. + */ + +#ifndef INV_MPU_MAGN_H_ +#define INV_MPU_MAGN_H_ + +#include <linux/kernel.h> + +#include "inv_mpu_iio.h" + +int inv_mpu_magn_probe(struct inv_mpu6050_state *st); + +/** + * inv_mpu_magn_get_scale() - get magnetometer scale value + * @st: driver internal state + * + * Returns IIO data format. + */ +static inline int inv_mpu_magn_get_scale(const struct inv_mpu6050_state *st, + const struct iio_chan_spec *chan, + int *val, int *val2) +{ + *val = 0; + *val2 = st->magn_raw_to_gauss[chan->address]; + return IIO_VAL_INT_PLUS_MICRO; +} + +int inv_mpu_magn_set_rate(const struct inv_mpu6050_state *st, int fifo_rate); + +int inv_mpu_magn_set_orient(struct inv_mpu6050_state *st); + +int inv_mpu_magn_read(const struct inv_mpu6050_state *st, int axis, int *val); + +#endif /* INV_MPU_MAGN_H_ */ diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c index 72d8c5790076..10d16ec5104b 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c @@ -124,7 +124,8 @@ int inv_reset_fifo(struct iio_dev *indio_dev) /* enable interrupt */ if (st->chip_config.accl_fifo_enable || - st->chip_config.gyro_fifo_enable) { + st->chip_config.gyro_fifo_enable || + st->chip_config.magn_fifo_enable) { result = regmap_write(st->map, st->reg->int_enable, INV_MPU6050_BIT_DATA_RDY_EN); if (result) @@ -141,6 +142,8 @@ int inv_reset_fifo(struct iio_dev *indio_dev) d |= INV_MPU6050_BITS_GYRO_OUT; if (st->chip_config.accl_fifo_enable) d |= INV_MPU6050_BIT_ACCEL_OUT; + if (st->chip_config.magn_fifo_enable) + d |= INV_MPU6050_BIT_SLAVE_0; result = regmap_write(st->map, st->reg->fifo_en, d); if (result) goto reset_fifo_fail; @@ -187,7 +190,8 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) } if (!(st->chip_config.accl_fifo_enable | - st->chip_config.gyro_fifo_enable)) + st->chip_config.gyro_fifo_enable | + st->chip_config.magn_fifo_enable)) goto end_session; bytes_per_datum = 0; if (st->chip_config.accl_fifo_enable) @@ -199,6 +203,9 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p) if (st->chip_type == INV_ICM20602) bytes_per_datum += INV_ICM20602_BYTES_PER_TEMP_SENSOR; + if (st->chip_config.magn_fifo_enable) + bytes_per_datum += INV_MPU9X50_BYTES_MAGN; + /* * read fifo_count register to know how many bytes are inside the FIFO * right now diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c index dd55e70b6f77..d7d951927a44 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c @@ -5,7 +5,7 @@ #include "inv_mpu_iio.h" -static void inv_scan_query(struct iio_dev *indio_dev) +static void inv_scan_query_mpu6050(struct iio_dev *indio_dev) { struct inv_mpu6050_state *st = iio_priv(indio_dev); @@ -26,6 +26,60 @@ static void inv_scan_query(struct iio_dev *indio_dev) indio_dev->active_scan_mask); } +static void inv_scan_query_mpu9x50(struct iio_dev *indio_dev) +{ + struct inv_mpu6050_state *st = iio_priv(indio_dev); + + inv_scan_query_mpu6050(indio_dev); + + /* no magnetometer if i2c auxiliary bus is used */ + if (st->magn_disabled) + return; + + st->chip_config.magn_fifo_enable = + test_bit(INV_MPU9X50_SCAN_MAGN_X, + indio_dev->active_scan_mask) || + test_bit(INV_MPU9X50_SCAN_MAGN_Y, + indio_dev->active_scan_mask) || + test_bit(INV_MPU9X50_SCAN_MAGN_Z, + indio_dev->active_scan_mask); +} + +static void inv_scan_query(struct iio_dev *indio_dev) +{ + struct inv_mpu6050_state *st = iio_priv(indio_dev); + + switch (st->chip_type) { + case INV_MPU9250: + case INV_MPU9255: + return inv_scan_query_mpu9x50(indio_dev); + default: + return inv_scan_query_mpu6050(indio_dev); + } +} + +static unsigned int inv_compute_skip_samples(const struct inv_mpu6050_state *st) +{ + unsigned int gyro_skip = 0; + unsigned int magn_skip = 0; + unsigned int skip_samples; + + /* gyro first sample is out of specs, skip it */ + if (st->chip_config.gyro_fifo_enable) + gyro_skip = 1; + + /* mag first sample is always not ready, skip it */ + if (st->chip_config.magn_fifo_enable) + magn_skip = 1; + + /* compute first samples to skip */ + skip_samples = gyro_skip; + if (magn_skip > skip_samples) + skip_samples = magn_skip; + + return skip_samples; +} + /** * inv_mpu6050_set_enable() - enable chip functions. * @indio_dev: Device driver instance. @@ -34,6 +88,7 @@ static void inv_scan_query(struct iio_dev *indio_dev) static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable) { struct inv_mpu6050_state *st = iio_priv(indio_dev); + uint8_t d; int result; if (enable) { @@ -41,14 +96,11 @@ static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable) if (result) return result; inv_scan_query(indio_dev); - st->skip_samples = 0; if (st->chip_config.gyro_fifo_enable) { result = inv_mpu6050_switch_engine(st, true, INV_MPU6050_BIT_PWR_GYRO_STBY); if (result) goto error_power_off; - /* gyro first sample is out of specs, skip it */ - st->skip_samples = 1; } if (st->chip_config.accl_fifo_enable) { result = inv_mpu6050_switch_engine(st, true, @@ -56,22 +108,32 @@ static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable) if (result) goto error_gyro_off; } + if (st->chip_config.magn_fifo_enable) { + d = st->chip_config.user_ctrl | + INV_MPU6050_BIT_I2C_MST_EN; + result = regmap_write(st->map, st->reg->user_ctrl, d); + if (result) + goto error_accl_off; + st->chip_config.user_ctrl = d; + } + st->skip_samples = inv_compute_skip_samples(st); result = inv_reset_fifo(indio_dev); if (result) - goto error_accl_off; + goto error_magn_off; } else { result = regmap_write(st->map, st->reg->fifo_en, 0); if (result) - goto error_accl_off; + goto error_magn_off; result = regmap_write(st->map, st->reg->int_enable, 0); if (result) - goto error_accl_off; + goto error_magn_off; - result = regmap_write(st->map, st->reg->user_ctrl, - st->chip_config.user_ctrl); + d = st->chip_config.user_ctrl & ~INV_MPU6050_BIT_I2C_MST_EN; + result = regmap_write(st->map, st->reg->user_ctrl, d); if (result) - goto error_accl_off; + goto error_magn_off; + st->chip_config.user_ctrl = d; result = inv_mpu6050_switch_engine(st, false, INV_MPU6050_BIT_PWR_ACCL_STBY); @@ -90,6 +152,10 @@ static int inv_mpu6050_set_enable(struct iio_dev *indio_dev, bool enable) return 0; +error_magn_off: + /* always restore user_ctrl to disable fifo properly */ + st->chip_config.user_ctrl &= ~INV_MPU6050_BIT_I2C_MST_EN; + regmap_write(st->map, st->reg->user_ctrl, st->chip_config.user_ctrl); error_accl_off: if (st->chip_config.accl_fifo_enable) inv_mpu6050_switch_engine(st, false, diff --git a/drivers/iio/imu/st_lsm6dsx/Kconfig b/drivers/iio/imu/st_lsm6dsx/Kconfig index 77aa0e77212d..28f59d09208a 100644 --- a/drivers/iio/imu/st_lsm6dsx/Kconfig +++ b/drivers/iio/imu/st_lsm6dsx/Kconfig @@ -12,7 +12,8 @@ config IIO_ST_LSM6DSX Say yes here to build support for STMicroelectronics LSM6DSx imu sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm, ism330dlc, lsm6dso, lsm6dsox, asm330lhh, lsm6dsr, lsm6ds3tr-c, - ism330dhcx and the accelerometer/gyroscope of lsm9ds1. + ism330dhcx, lsm6dsrx, lsm6ds0 and the accelerometer/gyroscope + of lsm9ds1. To compile this driver as a module, choose M here: the module will be called st_lsm6dsx. diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index 0fe6999b8257..37e499fe6bcf 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -12,6 +12,7 @@ #define ST_LSM6DSX_H #include <linux/device.h> +#include <linux/iio/iio.h> #define ST_LSM6DS3_DEV_NAME "lsm6ds3" #define ST_LSM6DS3H_DEV_NAME "lsm6ds3h" @@ -25,6 +26,8 @@ #define ST_LSM6DS3TRC_DEV_NAME "lsm6ds3tr-c" #define ST_ISM330DHCX_DEV_NAME "ism330dhcx" #define ST_LSM9DS1_DEV_NAME "lsm9ds1-imu" +#define ST_LSM6DS0_DEV_NAME "lsm6ds0" +#define ST_LSM6DSRX_DEV_NAME "lsm6dsrx" enum st_lsm6dsx_hw_id { ST_LSM6DS3_ID, @@ -39,6 +42,8 @@ enum st_lsm6dsx_hw_id { ST_LSM6DS3TRC_ID, ST_ISM330DHCX_ID, ST_LSM9DS1_ID, + ST_LSM6DS0_ID, + ST_LSM6DSRX_ID, ST_LSM6DSX_MAX_ID, }; @@ -54,6 +59,26 @@ enum st_lsm6dsx_hw_id { * ST_LSM6DSX_TAGGED_SAMPLE_SIZE) #define ST_LSM6DSX_SHIFT_VAL(val, mask) (((val) << __ffs(mask)) & (mask)) +#define ST_LSM6DSX_CHANNEL_ACC(chan_type, addr, mod, scan_idx) \ +{ \ + .type = chan_type, \ + .address = addr, \ + .modified = 1, \ + .channel2 = mod, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .scan_index = scan_idx, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_LE, \ + }, \ + .event_spec = &st_lsm6dsx_event, \ + .num_event_specs = 1, \ +} + #define ST_LSM6DSX_CHANNEL(chan_type, addr, mod, scan_idx) \ { \ .type = chan_type, \ @@ -132,12 +157,14 @@ struct st_lsm6dsx_fifo_ops { * @hr_timer: Hw timer resolution register info (addr + mask). * @fifo_en: Hw timer FIFO enable register info (addr + mask). * @decimator: Hw timer FIFO decimator register info (addr + mask). + * @freq_fine: Difference in % of ODR with respect to the typical. */ struct st_lsm6dsx_hw_ts_settings { struct st_lsm6dsx_reg timer_en; struct st_lsm6dsx_reg hr_timer; struct st_lsm6dsx_reg fifo_en; struct st_lsm6dsx_reg decimator; + u8 freq_fine; }; /** @@ -164,6 +191,16 @@ struct st_lsm6dsx_shub_settings { u8 batch_en; }; +struct st_lsm6dsx_event_settings { + struct st_lsm6dsx_reg enable_reg; + struct st_lsm6dsx_reg wakeup_reg; + u8 wakeup_src_reg; + u8 wakeup_src_status_mask; + u8 wakeup_src_z_mask; + u8 wakeup_src_y_mask; + u8 wakeup_src_x_mask; +}; + enum st_lsm6dsx_ext_sensor_id { ST_LSM6DSX_ID_MAGN, }; @@ -207,12 +244,14 @@ struct st_lsm6dsx_ext_dev_settings { /** * struct st_lsm6dsx_settings - ST IMU sensor settings * @wai: Sensor WhoAmI default value. - * @int1_addr: Control Register address for INT1 - * @int2_addr: Control Register address for INT2 - * @reset_addr: register address for reset/reboot + * @reset: register address for reset. + * @boot: register address for boot. + * @bdu: register address for Block Data Update. * @max_fifo_size: Sensor max fifo length in FIFO words. * @id: List of hw id/device name supported by the driver configuration. * @channels: IIO channels supported by the device. + * @irq_config: interrupts related registers. + * @drdy_mask: register info for data-ready mask (addr + mask). * @odr_table: Hw sensors odr table (Hz + val). * @fs_table: Hw sensors gain table (gain + val). * @decimator: List of decimator register info (addr + mask). @@ -223,9 +262,9 @@ struct st_lsm6dsx_ext_dev_settings { */ struct st_lsm6dsx_settings { u8 wai; - u8 int1_addr; - u8 int2_addr; - u8 reset_addr; + struct st_lsm6dsx_reg reset; + struct st_lsm6dsx_reg boot; + struct st_lsm6dsx_reg bdu; u16 max_fifo_size; struct { enum st_lsm6dsx_hw_id hw_id; @@ -235,6 +274,17 @@ struct st_lsm6dsx_settings { const struct iio_chan_spec *chan; int len; } channels[2]; + struct { + struct st_lsm6dsx_reg irq1; + struct st_lsm6dsx_reg irq2; + struct st_lsm6dsx_reg irq1_func; + struct st_lsm6dsx_reg irq2_func; + struct st_lsm6dsx_reg lir; + struct st_lsm6dsx_reg clear_on_read; + struct st_lsm6dsx_reg hla; + struct st_lsm6dsx_reg od; + } irq_config; + struct st_lsm6dsx_reg drdy_mask; struct st_lsm6dsx_odr_table_entry odr_table[2]; struct st_lsm6dsx_fs_table_entry fs_table[2]; struct st_lsm6dsx_reg decimator[ST_LSM6DSX_MAX_ID]; @@ -242,6 +292,7 @@ struct st_lsm6dsx_settings { struct st_lsm6dsx_fifo_ops fifo_ops; struct st_lsm6dsx_hw_ts_settings ts_settings; struct st_lsm6dsx_shub_settings shub_settings; + struct st_lsm6dsx_event_settings event_settings; }; enum st_lsm6dsx_sensor_id { @@ -301,9 +352,13 @@ struct st_lsm6dsx_sensor { * @fifo_mode: FIFO operating mode supported by the device. * @suspend_mask: Suspended sensor bitmask. * @enable_mask: Enabled sensor bitmask. + * @ts_gain: Hw timestamp rate after internal calibration. * @ts_sip: Total number of timestamp samples in a given pattern. * @sip: Total number of samples (acc/gyro/ts) in a given pattern. * @buff: Device read buffer. + * @irq_routing: pointer to interrupt routing configuration. + * @event_threshold: wakeup event threshold. + * @enable_event: enabled event bitmask. * @iio_devs: Pointers to acc/gyro iio_dev instances. * @settings: Pointer to the specific sensor settings in use. */ @@ -319,9 +374,14 @@ struct st_lsm6dsx_hw { enum st_lsm6dsx_fifo_mode fifo_mode; u8 suspend_mask; u8 enable_mask; + s64 ts_gain; u8 ts_sip; u8 sip; + const struct st_lsm6dsx_reg *irq_routing; + u8 event_threshold; + u8 enable_event; + u8 *buff; struct iio_dev *iio_devs[ST_LSM6DSX_ID_MAX]; @@ -329,6 +389,13 @@ struct st_lsm6dsx_hw { const struct st_lsm6dsx_settings *settings; }; +static const struct iio_event_spec st_lsm6dsx_event = { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_EITHER, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE) +}; + static const unsigned long st_lsm6dsx_available_scan_masks[] = {0x7, 0x0}; extern const struct dev_pm_ops st_lsm6dsx_pm_ops; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c index b0f3da1976e4..31cd90d2c60e 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c @@ -14,10 +14,10 @@ * (e.g. Gx, Gy, Gz, Ax, Ay, Az), then data are repeated depending on the * value of the decimation factor and ODR set for each FIFO data set. * - * LSM6DSO/LSM6DSOX/ASM330LHH/LSM6DSR/ISM330DHCX: The FIFO buffer can be - * configured to store data from gyroscope and accelerometer. Each sample - * is queued with a tag (1B) indicating data source (gyroscope, accelerometer, - * hw timer). + * LSM6DSO/LSM6DSOX/ASM330LHH/LSM6DSR/LSM6DSRX/ISM330DHCX: + * The FIFO buffer can be configured to store data from gyroscope and + * accelerometer. Each sample is queued with a tag (1B) indicating data + * source (gyroscope, accelerometer, hw timer). * * FIFO supported modes: * - BYPASS: FIFO disabled @@ -30,8 +30,6 @@ * Denis Ciocca <denis.ciocca@st.com> */ #include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/irq.h> #include <linux/iio/kfifo_buf.h> #include <linux/iio/iio.h> #include <linux/iio/buffer.h> @@ -42,10 +40,6 @@ #include "st_lsm6dsx.h" -#define ST_LSM6DSX_REG_HLACTIVE_ADDR 0x12 -#define ST_LSM6DSX_REG_HLACTIVE_MASK BIT(5) -#define ST_LSM6DSX_REG_PP_OD_ADDR 0x12 -#define ST_LSM6DSX_REG_PP_OD_MASK BIT(4) #define ST_LSM6DSX_REG_FIFO_MODE_ADDR 0x0a #define ST_LSM6DSX_FIFO_MODE_MASK GENMASK(2, 0) #define ST_LSM6DSX_FIFO_ODR_MASK GENMASK(6, 3) @@ -56,7 +50,6 @@ #define ST_LSM6DSX_MAX_FIFO_ODR_VAL 0x08 -#define ST_LSM6DSX_TS_SENSITIVITY 25000UL /* 25us */ #define ST_LSM6DSX_TS_RESET_VAL 0xaa struct st_lsm6dsx_decimator_entry { @@ -429,7 +422,7 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw) */ if (!reset_ts && ts >= 0xff0000) reset_ts = true; - ts *= ST_LSM6DSX_TS_SENSITIVITY; + ts *= hw->ts_gain; offset += ST_LSM6DSX_SAMPLE_SIZE; } @@ -456,13 +449,19 @@ int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw) return read_len; } +#define ST_LSM6DSX_INVALID_SAMPLE 0x7ffd static int st_lsm6dsx_push_tagged_data(struct st_lsm6dsx_hw *hw, u8 tag, u8 *data, s64 ts) { + s16 val = le16_to_cpu(*(__le16 *)data); struct st_lsm6dsx_sensor *sensor; struct iio_dev *iio_dev; + /* invalid sample during bootstrap phase */ + if (val >= ST_LSM6DSX_INVALID_SAMPLE) + return -EINVAL; + /* * EXT_TAG are managed in FIFO fashion so ST_LSM6DSX_EXT0_TAG * corresponds to the first enabled channel, ST_LSM6DSX_EXT1_TAG @@ -572,7 +571,7 @@ int st_lsm6dsx_read_tagged_fifo(struct st_lsm6dsx_hw *hw) */ if (!reset_ts && ts >= 0xffff0000) reset_ts = true; - ts *= ST_LSM6DSX_TS_SENSITIVITY; + ts *= hw->ts_gain; } else { st_lsm6dsx_push_tagged_data(hw, tag, iio_buff, ts); @@ -592,6 +591,9 @@ int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw) { int err; + if (!hw->settings->fifo_ops.read_fifo) + return -ENOTSUPP; + mutex_lock(&hw->fifo_lock); hw->settings->fifo_ops.read_fifo(hw); @@ -654,25 +656,6 @@ out: return err; } -static irqreturn_t st_lsm6dsx_handler_irq(int irq, void *private) -{ - struct st_lsm6dsx_hw *hw = private; - - return hw->sip > 0 ? IRQ_WAKE_THREAD : IRQ_NONE; -} - -static irqreturn_t st_lsm6dsx_handler_thread(int irq, void *private) -{ - struct st_lsm6dsx_hw *hw = private; - int count; - - mutex_lock(&hw->fifo_lock); - count = hw->settings->fifo_ops.read_fifo(hw); - mutex_unlock(&hw->fifo_lock); - - return count ? IRQ_HANDLED : IRQ_NONE; -} - static int st_lsm6dsx_buffer_preenable(struct iio_dev *iio_dev) { struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); @@ -702,59 +685,8 @@ static const struct iio_buffer_setup_ops st_lsm6dsx_buffer_ops = { int st_lsm6dsx_fifo_setup(struct st_lsm6dsx_hw *hw) { - struct device_node *np = hw->dev->of_node; - struct st_sensors_platform_data *pdata; struct iio_buffer *buffer; - unsigned long irq_type; - bool irq_active_low; - int i, err; - - irq_type = irqd_get_trigger_type(irq_get_irq_data(hw->irq)); - - switch (irq_type) { - case IRQF_TRIGGER_HIGH: - case IRQF_TRIGGER_RISING: - irq_active_low = false; - break; - case IRQF_TRIGGER_LOW: - case IRQF_TRIGGER_FALLING: - irq_active_low = true; - break; - default: - dev_info(hw->dev, "mode %lx unsupported\n", irq_type); - return -EINVAL; - } - - err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_HLACTIVE_ADDR, - ST_LSM6DSX_REG_HLACTIVE_MASK, - FIELD_PREP(ST_LSM6DSX_REG_HLACTIVE_MASK, - irq_active_low)); - if (err < 0) - return err; - - pdata = (struct st_sensors_platform_data *)hw->dev->platform_data; - if ((np && of_property_read_bool(np, "drive-open-drain")) || - (pdata && pdata->open_drain)) { - err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_PP_OD_ADDR, - ST_LSM6DSX_REG_PP_OD_MASK, - FIELD_PREP(ST_LSM6DSX_REG_PP_OD_MASK, - 1)); - if (err < 0) - return err; - - irq_type |= IRQF_SHARED; - } - - err = devm_request_threaded_irq(hw->dev, hw->irq, - st_lsm6dsx_handler_irq, - st_lsm6dsx_handler_thread, - irq_type | IRQF_ONESHOT, - "lsm6dsx", hw); - if (err) { - dev_err(hw->dev, "failed to request trigger irq %d\n", - hw->irq); - return err; - } + int i; for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) { if (!hw->iio_devs[i]) diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index fd5ebe1e1594..1f28a7733fc0 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -32,7 +32,7 @@ * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 * - FIFO size: 3KB * - * - LSM9DS1: + * - LSM9DS1/LSM6DS0: * - Accelerometer supported ODR [Hz]: 10, 50, 119, 238, 476, 952 * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 * - Gyroscope supported ODR [Hz]: 15, 60, 119, 238, 476, 952 @@ -48,8 +48,11 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/delay.h> +#include <linux/iio/events.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> +#include <linux/interrupt.h> +#include <linux/irq.h> #include <linux/pm.h> #include <linux/regmap.h> #include <linux/bitfield.h> @@ -58,17 +61,14 @@ #include "st_lsm6dsx.h" -#define ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK BIT(3) #define ST_LSM6DSX_REG_WHOAMI_ADDR 0x0f -#define ST_LSM6DSX_REG_RESET_MASK BIT(0) -#define ST_LSM6DSX_REG_BOOT_MASK BIT(7) -#define ST_LSM6DSX_REG_BDU_ADDR 0x12 -#define ST_LSM6DSX_REG_BDU_MASK BIT(6) + +#define ST_LSM6DSX_TS_SENSITIVITY 25000UL /* 25us */ static const struct iio_chan_spec st_lsm6dsx_acc_channels[] = { - ST_LSM6DSX_CHANNEL(IIO_ACCEL, 0x28, IIO_MOD_X, 0), - ST_LSM6DSX_CHANNEL(IIO_ACCEL, 0x2a, IIO_MOD_Y, 1), - ST_LSM6DSX_CHANNEL(IIO_ACCEL, 0x2c, IIO_MOD_Z, 2), + ST_LSM6DSX_CHANNEL_ACC(IIO_ACCEL, 0x28, IIO_MOD_X, 0), + ST_LSM6DSX_CHANNEL_ACC(IIO_ACCEL, 0x2a, IIO_MOD_Y, 1), + ST_LSM6DSX_CHANNEL_ACC(IIO_ACCEL, 0x2c, IIO_MOD_Z, 2), IIO_CHAN_SOFT_TIMESTAMP(3), }; @@ -89,14 +89,26 @@ static const struct iio_chan_spec st_lsm6ds0_gyro_channels[] = { static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { { .wai = 0x68, - .int1_addr = 0x0c, - .int2_addr = 0x0d, - .reset_addr = 0x22, + .reset = { + .addr = 0x22, + .mask = BIT(0), + }, + .boot = { + .addr = 0x22, + .mask = BIT(7), + }, + .bdu = { + .addr = 0x22, + .mask = BIT(6), + }, .max_fifo_size = 32, .id = { { .hw_id = ST_LSM9DS1_ID, .name = ST_LSM9DS1_DEV_NAME, + }, { + .hw_id = ST_LSM6DS0_ID, + .name = ST_LSM6DS0_DEV_NAME, }, }, .channels = { @@ -152,18 +164,46 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x10, .mask = GENMASK(4, 3), }, - .fs_avl[0] = { IIO_DEGREE_TO_RAD(245), 0x0 }, - .fs_avl[1] = { IIO_DEGREE_TO_RAD(500), 0x1 }, - .fs_avl[2] = { IIO_DEGREE_TO_RAD(2000), 0x3 }, + + .fs_avl[0] = { IIO_DEGREE_TO_RAD(8750), 0x0 }, + .fs_avl[1] = { IIO_DEGREE_TO_RAD(17500), 0x1 }, + .fs_avl[2] = { IIO_DEGREE_TO_RAD(70000), 0x3 }, .fs_len = 3, }, }, + .irq_config = { + .irq1 = { + .addr = 0x0c, + .mask = BIT(3), + }, + .irq2 = { + .addr = 0x0d, + .mask = BIT(3), + }, + .hla = { + .addr = 0x22, + .mask = BIT(5), + }, + .od = { + .addr = 0x22, + .mask = BIT(4), + }, + }, }, { .wai = 0x69, - .int1_addr = 0x0d, - .int2_addr = 0x0e, - .reset_addr = 0x12, + .reset = { + .addr = 0x12, + .mask = BIT(0), + }, + .boot = { + .addr = 0x12, + .mask = BIT(7), + }, + .bdu = { + .addr = 0x12, + .mask = BIT(6), + }, .max_fifo_size = 1365, .id = { { @@ -231,6 +271,36 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .fs_len = 4, }, }, + .irq_config = { + .irq1 = { + .addr = 0x0d, + .mask = BIT(3), + }, + .irq2 = { + .addr = 0x0e, + .mask = BIT(3), + }, + .lir = { + .addr = 0x58, + .mask = BIT(0), + }, + .irq1_func = { + .addr = 0x5e, + .mask = BIT(5), + }, + .irq2_func = { + .addr = 0x5f, + .mask = BIT(5), + }, + .hla = { + .addr = 0x12, + .mask = BIT(5), + }, + .od = { + .addr = 0x12, + .mask = BIT(4), + }, + }, .decimator = { [ST_LSM6DSX_ID_ACC] = { .addr = 0x08, @@ -272,12 +342,32 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .mask = GENMASK(5, 3), }, }, + .event_settings = { + .wakeup_reg = { + .addr = 0x5B, + .mask = GENMASK(5, 0), + }, + .wakeup_src_reg = 0x1b, + .wakeup_src_status_mask = BIT(3), + .wakeup_src_z_mask = BIT(0), + .wakeup_src_y_mask = BIT(1), + .wakeup_src_x_mask = BIT(2), + }, }, { .wai = 0x69, - .int1_addr = 0x0d, - .int2_addr = 0x0e, - .reset_addr = 0x12, + .reset = { + .addr = 0x12, + .mask = BIT(0), + }, + .boot = { + .addr = 0x12, + .mask = BIT(7), + }, + .bdu = { + .addr = 0x12, + .mask = BIT(6), + }, .max_fifo_size = 682, .id = { { @@ -345,6 +435,36 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .fs_len = 4, }, }, + .irq_config = { + .irq1 = { + .addr = 0x0d, + .mask = BIT(3), + }, + .irq2 = { + .addr = 0x0e, + .mask = BIT(3), + }, + .lir = { + .addr = 0x58, + .mask = BIT(0), + }, + .irq1_func = { + .addr = 0x5e, + .mask = BIT(5), + }, + .irq2_func = { + .addr = 0x5f, + .mask = BIT(5), + }, + .hla = { + .addr = 0x12, + .mask = BIT(5), + }, + .od = { + .addr = 0x12, + .mask = BIT(4), + }, + }, .decimator = { [ST_LSM6DSX_ID_ACC] = { .addr = 0x08, @@ -386,12 +506,32 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .mask = GENMASK(5, 3), }, }, + .event_settings = { + .wakeup_reg = { + .addr = 0x5B, + .mask = GENMASK(5, 0), + }, + .wakeup_src_reg = 0x1b, + .wakeup_src_status_mask = BIT(3), + .wakeup_src_z_mask = BIT(0), + .wakeup_src_y_mask = BIT(1), + .wakeup_src_x_mask = BIT(2), + }, }, { .wai = 0x6a, - .int1_addr = 0x0d, - .int2_addr = 0x0e, - .reset_addr = 0x12, + .reset = { + .addr = 0x12, + .mask = BIT(0), + }, + .boot = { + .addr = 0x12, + .mask = BIT(7), + }, + .bdu = { + .addr = 0x12, + .mask = BIT(6), + }, .max_fifo_size = 682, .id = { { @@ -468,6 +608,36 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .fs_len = 4, }, }, + .irq_config = { + .irq1 = { + .addr = 0x0d, + .mask = BIT(3), + }, + .irq2 = { + .addr = 0x0e, + .mask = BIT(3), + }, + .lir = { + .addr = 0x58, + .mask = BIT(0), + }, + .irq1_func = { + .addr = 0x5e, + .mask = BIT(5), + }, + .irq2_func = { + .addr = 0x5f, + .mask = BIT(5), + }, + .hla = { + .addr = 0x12, + .mask = BIT(5), + }, + .od = { + .addr = 0x12, + .mask = BIT(4), + }, + }, .decimator = { [ST_LSM6DSX_ID_ACC] = { .addr = 0x08, @@ -509,12 +679,36 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .mask = GENMASK(5, 3), }, }, + .event_settings = { + .enable_reg = { + .addr = 0x58, + .mask = BIT(7), + }, + .wakeup_reg = { + .addr = 0x5B, + .mask = GENMASK(5, 0), + }, + .wakeup_src_reg = 0x1b, + .wakeup_src_status_mask = BIT(3), + .wakeup_src_z_mask = BIT(0), + .wakeup_src_y_mask = BIT(1), + .wakeup_src_x_mask = BIT(2), + }, }, { .wai = 0x6c, - .int1_addr = 0x0d, - .int2_addr = 0x0e, - .reset_addr = 0x12, + .reset = { + .addr = 0x12, + .mask = BIT(0), + }, + .boot = { + .addr = 0x12, + .mask = BIT(7), + }, + .bdu = { + .addr = 0x12, + .mask = BIT(6), + }, .max_fifo_size = 512, .id = { { @@ -535,6 +729,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .len = ARRAY_SIZE(st_lsm6dsx_gyro_channels), }, }, + .drdy_mask = { + .addr = 0x13, + .mask = BIT(3), + }, .odr_table = { [ST_LSM6DSX_ID_ACC] = { .reg = { @@ -585,6 +783,40 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .fs_len = 4, }, }, + .irq_config = { + .irq1 = { + .addr = 0x0d, + .mask = BIT(3), + }, + .irq2 = { + .addr = 0x0e, + .mask = BIT(3), + }, + .lir = { + .addr = 0x56, + .mask = BIT(0), + }, + .clear_on_read = { + .addr = 0x56, + .mask = BIT(6), + }, + .irq1_func = { + .addr = 0x5e, + .mask = BIT(5), + }, + .irq2_func = { + .addr = 0x5f, + .mask = BIT(5), + }, + .hla = { + .addr = 0x12, + .mask = BIT(5), + }, + .od = { + .addr = 0x12, + .mask = BIT(4), + }, + }, .batch = { [ST_LSM6DSX_ID_ACC] = { .addr = 0x09, @@ -617,6 +849,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x0a, .mask = GENMASK(7, 6), }, + .freq_fine = 0x63, }, .shub_settings = { .page_mux = { @@ -643,13 +876,37 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .slv0_addr = 0x15, .dw_slv0_addr = 0x21, .batch_en = BIT(3), - } + }, + .event_settings = { + .enable_reg = { + .addr = 0x58, + .mask = BIT(7), + }, + .wakeup_reg = { + .addr = 0x5b, + .mask = GENMASK(5, 0), + }, + .wakeup_src_reg = 0x1b, + .wakeup_src_status_mask = BIT(3), + .wakeup_src_z_mask = BIT(0), + .wakeup_src_y_mask = BIT(1), + .wakeup_src_x_mask = BIT(2), + }, }, { .wai = 0x6b, - .int1_addr = 0x0d, - .int2_addr = 0x0e, - .reset_addr = 0x12, + .reset = { + .addr = 0x12, + .mask = BIT(0), + }, + .boot = { + .addr = 0x12, + .mask = BIT(7), + }, + .bdu = { + .addr = 0x12, + .mask = BIT(6), + }, .max_fifo_size = 512, .id = { { @@ -667,6 +924,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .len = ARRAY_SIZE(st_lsm6dsx_gyro_channels), }, }, + .drdy_mask = { + .addr = 0x13, + .mask = BIT(3), + }, .odr_table = { [ST_LSM6DSX_ID_ACC] = { .reg = { @@ -717,6 +978,40 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .fs_len = 4, }, }, + .irq_config = { + .irq1 = { + .addr = 0x0d, + .mask = BIT(3), + }, + .irq2 = { + .addr = 0x0e, + .mask = BIT(3), + }, + .lir = { + .addr = 0x56, + .mask = BIT(0), + }, + .clear_on_read = { + .addr = 0x56, + .mask = BIT(6), + }, + .irq1_func = { + .addr = 0x5e, + .mask = BIT(5), + }, + .irq2_func = { + .addr = 0x5f, + .mask = BIT(5), + }, + .hla = { + .addr = 0x12, + .mask = BIT(5), + }, + .od = { + .addr = 0x12, + .mask = BIT(4), + }, + }, .batch = { [ST_LSM6DSX_ID_ACC] = { .addr = 0x09, @@ -749,13 +1044,38 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x0a, .mask = GENMASK(7, 6), }, + .freq_fine = 0x63, + }, + .event_settings = { + .enable_reg = { + .addr = 0x58, + .mask = BIT(7), + }, + .wakeup_reg = { + .addr = 0x5B, + .mask = GENMASK(5, 0), + }, + .wakeup_src_reg = 0x1b, + .wakeup_src_status_mask = BIT(3), + .wakeup_src_z_mask = BIT(0), + .wakeup_src_y_mask = BIT(1), + .wakeup_src_x_mask = BIT(2), }, }, { .wai = 0x6b, - .int1_addr = 0x0d, - .int2_addr = 0x0e, - .reset_addr = 0x12, + .reset = { + .addr = 0x12, + .mask = BIT(0), + }, + .boot = { + .addr = 0x12, + .mask = BIT(7), + }, + .bdu = { + .addr = 0x12, + .mask = BIT(6), + }, .max_fifo_size = 512, .id = { { @@ -764,6 +1084,9 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { }, { .hw_id = ST_ISM330DHCX_ID, .name = ST_ISM330DHCX_DEV_NAME, + }, { + .hw_id = ST_LSM6DSRX_ID, + .name = ST_LSM6DSRX_DEV_NAME, }, }, .channels = { @@ -776,6 +1099,10 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .len = ARRAY_SIZE(st_lsm6dsx_gyro_channels), }, }, + .drdy_mask = { + .addr = 0x13, + .mask = BIT(3), + }, .odr_table = { [ST_LSM6DSX_ID_ACC] = { .reg = { @@ -826,6 +1153,40 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .fs_len = 4, }, }, + .irq_config = { + .irq1 = { + .addr = 0x0d, + .mask = BIT(3), + }, + .irq2 = { + .addr = 0x0e, + .mask = BIT(3), + }, + .lir = { + .addr = 0x56, + .mask = BIT(0), + }, + .clear_on_read = { + .addr = 0x56, + .mask = BIT(6), + }, + .irq1_func = { + .addr = 0x5e, + .mask = BIT(5), + }, + .irq2_func = { + .addr = 0x5f, + .mask = BIT(5), + }, + .hla = { + .addr = 0x12, + .mask = BIT(5), + }, + .od = { + .addr = 0x12, + .mask = BIT(4), + }, + }, .batch = { [ST_LSM6DSX_ID_ACC] = { .addr = 0x09, @@ -858,6 +1219,7 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .addr = 0x0a, .mask = GENMASK(7, 6), }, + .freq_fine = 0x63, }, .shub_settings = { .page_mux = { @@ -884,6 +1246,21 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .slv0_addr = 0x15, .dw_slv0_addr = 0x21, .batch_en = BIT(3), + }, + .event_settings = { + .enable_reg = { + .addr = 0x58, + .mask = BIT(7), + }, + .wakeup_reg = { + .addr = 0x5B, + .mask = GENMASK(5, 0), + }, + .wakeup_src_reg = 0x1b, + .wakeup_src_status_mask = BIT(3), + .wakeup_src_z_mask = BIT(0), + .wakeup_src_y_mask = BIT(1), + .wakeup_src_x_mask = BIT(2), } }, }; @@ -1091,7 +1468,8 @@ static int st_lsm6dsx_read_oneshot(struct st_lsm6dsx_sensor *sensor, if (err < 0) return err; - st_lsm6dsx_sensor_set_enable(sensor, false); + if (!hw->enable_event) + st_lsm6dsx_sensor_set_enable(sensor, false); *val = (s16)le16_to_cpu(data); @@ -1164,6 +1542,144 @@ static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev, return err; } +static int st_lsm6dsx_event_setup(struct st_lsm6dsx_hw *hw, int state) +{ + const struct st_lsm6dsx_reg *reg; + unsigned int data; + int err; + + if (!hw->settings->irq_config.irq1_func.addr) + return -ENOTSUPP; + + reg = &hw->settings->event_settings.enable_reg; + if (reg->addr) { + data = ST_LSM6DSX_SHIFT_VAL(state, reg->mask); + err = st_lsm6dsx_update_bits_locked(hw, reg->addr, + reg->mask, data); + if (err < 0) + return err; + } + + /* Enable wakeup interrupt */ + data = ST_LSM6DSX_SHIFT_VAL(state, hw->irq_routing->mask); + return st_lsm6dsx_update_bits_locked(hw, hw->irq_routing->addr, + hw->irq_routing->mask, data); +} + +static int st_lsm6dsx_read_event(struct iio_dev *iio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int *val, int *val2) +{ + struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); + struct st_lsm6dsx_hw *hw = sensor->hw; + + if (type != IIO_EV_TYPE_THRESH) + return -EINVAL; + + *val2 = 0; + *val = hw->event_threshold; + + return IIO_VAL_INT; +} + +static int +st_lsm6dsx_write_event(struct iio_dev *iio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, + int val, int val2) +{ + struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); + struct st_lsm6dsx_hw *hw = sensor->hw; + const struct st_lsm6dsx_reg *reg; + unsigned int data; + int err; + + if (type != IIO_EV_TYPE_THRESH) + return -EINVAL; + + if (val < 0 || val > 31) + return -EINVAL; + + reg = &hw->settings->event_settings.wakeup_reg; + data = ST_LSM6DSX_SHIFT_VAL(val, reg->mask); + err = st_lsm6dsx_update_bits_locked(hw, reg->addr, + reg->mask, data); + if (err < 0) + return -EINVAL; + + hw->event_threshold = val; + + return 0; +} + +static int +st_lsm6dsx_read_event_config(struct iio_dev *iio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); + struct st_lsm6dsx_hw *hw = sensor->hw; + + if (type != IIO_EV_TYPE_THRESH) + return -EINVAL; + + return !!(hw->enable_event & BIT(chan->channel2)); +} + +static int +st_lsm6dsx_write_event_config(struct iio_dev *iio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, int state) +{ + struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); + struct st_lsm6dsx_hw *hw = sensor->hw; + u8 enable_event; + int err = 0; + + if (type != IIO_EV_TYPE_THRESH) + return -EINVAL; + + if (state) { + enable_event = hw->enable_event | BIT(chan->channel2); + + /* do not enable events if they are already enabled */ + if (hw->enable_event) + goto out; + } else { + enable_event = hw->enable_event & ~BIT(chan->channel2); + + /* only turn off sensor if no events is enabled */ + if (enable_event) + goto out; + } + + /* stop here if no changes have been made */ + if (hw->enable_event == enable_event) + return 0; + + err = st_lsm6dsx_event_setup(hw, state); + if (err < 0) + return err; + + mutex_lock(&hw->conf_lock); + err = st_lsm6dsx_sensor_set_enable(sensor, state); + mutex_unlock(&hw->conf_lock); + if (err < 0) + return err; + +out: + hw->enable_event = enable_event; + + return 0; +} + int st_lsm6dsx_set_watermark(struct iio_dev *iio_dev, unsigned int val) { struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev); @@ -1243,6 +1759,10 @@ static const struct iio_info st_lsm6dsx_acc_info = { .attrs = &st_lsm6dsx_acc_attribute_group, .read_raw = st_lsm6dsx_read_raw, .write_raw = st_lsm6dsx_write_raw, + .read_event_value = st_lsm6dsx_read_event, + .write_event_value = st_lsm6dsx_write_event, + .read_event_config = st_lsm6dsx_read_event_config, + .write_event_config = st_lsm6dsx_write_event_config, .hwfifo_set_watermark = st_lsm6dsx_set_watermark, }; @@ -1273,7 +1793,9 @@ static int st_lsm6dsx_of_get_drdy_pin(struct st_lsm6dsx_hw *hw, int *drdy_pin) return of_property_read_u32(np, "st,drdy-int-pin", drdy_pin); } -static int st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw, u8 *drdy_reg) +static int +st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw, + const struct st_lsm6dsx_reg **drdy_reg) { int err = 0, drdy_pin; @@ -1287,10 +1809,12 @@ static int st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw, u8 *drdy_reg) switch (drdy_pin) { case 1: - *drdy_reg = hw->settings->int1_addr; + hw->irq_routing = &hw->settings->irq_config.irq1_func; + *drdy_reg = &hw->settings->irq_config.irq1; break; case 2: - *drdy_reg = hw->settings->int2_addr; + hw->irq_routing = &hw->settings->irq_config.irq2_func; + *drdy_reg = &hw->settings->irq_config.irq2; break; default: dev_err(hw->dev, "unsupported data ready pin\n"); @@ -1381,51 +1905,95 @@ static int st_lsm6dsx_init_hw_timer(struct st_lsm6dsx_hw *hw) if (err < 0) return err; } + + /* calibrate timestamp sensitivity */ + hw->ts_gain = ST_LSM6DSX_TS_SENSITIVITY; + if (ts_settings->freq_fine) { + err = regmap_read(hw->regmap, ts_settings->freq_fine, &val); + if (err < 0) + return err; + + /* + * linearize the AN5192 formula: + * 1 / (1 + x) ~= 1 - x (Taylor’s Series) + * ttrim[s] = 1 / (40000 * (1 + 0.0015 * val)) + * ttrim[ns] ~= 25000 - 37.5 * val + * ttrim[ns] ~= 25000 - (37500 * val) / 1000 + */ + hw->ts_gain -= ((s8)val * 37500) / 1000; + } + return 0; } static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw) { - u8 drdy_int_reg; + const struct st_lsm6dsx_reg *reg; int err; /* device sw reset */ - err = regmap_update_bits(hw->regmap, hw->settings->reset_addr, - ST_LSM6DSX_REG_RESET_MASK, - FIELD_PREP(ST_LSM6DSX_REG_RESET_MASK, 1)); + reg = &hw->settings->reset; + err = regmap_update_bits(hw->regmap, reg->addr, reg->mask, + ST_LSM6DSX_SHIFT_VAL(1, reg->mask)); if (err < 0) return err; msleep(50); /* reload trimming parameter */ - err = regmap_update_bits(hw->regmap, hw->settings->reset_addr, - ST_LSM6DSX_REG_BOOT_MASK, - FIELD_PREP(ST_LSM6DSX_REG_BOOT_MASK, 1)); + reg = &hw->settings->boot; + err = regmap_update_bits(hw->regmap, reg->addr, reg->mask, + ST_LSM6DSX_SHIFT_VAL(1, reg->mask)); if (err < 0) return err; msleep(50); /* enable Block Data Update */ - err = regmap_update_bits(hw->regmap, ST_LSM6DSX_REG_BDU_ADDR, - ST_LSM6DSX_REG_BDU_MASK, - FIELD_PREP(ST_LSM6DSX_REG_BDU_MASK, 1)); + reg = &hw->settings->bdu; + err = regmap_update_bits(hw->regmap, reg->addr, reg->mask, + ST_LSM6DSX_SHIFT_VAL(1, reg->mask)); if (err < 0) return err; /* enable FIFO watermak interrupt */ - err = st_lsm6dsx_get_drdy_reg(hw, &drdy_int_reg); + err = st_lsm6dsx_get_drdy_reg(hw, ®); if (err < 0) return err; - err = regmap_update_bits(hw->regmap, drdy_int_reg, - ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK, - FIELD_PREP(ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK, - 1)); + err = regmap_update_bits(hw->regmap, reg->addr, reg->mask, + ST_LSM6DSX_SHIFT_VAL(1, reg->mask)); if (err < 0) return err; + /* enable Latched interrupts for device events */ + if (hw->settings->irq_config.lir.addr) { + reg = &hw->settings->irq_config.lir; + err = regmap_update_bits(hw->regmap, reg->addr, reg->mask, + ST_LSM6DSX_SHIFT_VAL(1, reg->mask)); + if (err < 0) + return err; + + /* enable clear on read for latched interrupts */ + if (hw->settings->irq_config.clear_on_read.addr) { + reg = &hw->settings->irq_config.clear_on_read; + err = regmap_update_bits(hw->regmap, + reg->addr, reg->mask, + ST_LSM6DSX_SHIFT_VAL(1, reg->mask)); + if (err < 0) + return err; + } + } + + /* enable drdy-mas if available */ + if (hw->settings->drdy_mask.addr) { + reg = &hw->settings->drdy_mask; + err = regmap_update_bits(hw->regmap, reg->addr, reg->mask, + ST_LSM6DSX_SHIFT_VAL(1, reg->mask)); + if (err < 0) + return err; + } + err = st_lsm6dsx_init_shub(hw); if (err < 0) return err; @@ -1476,10 +2044,138 @@ static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw, return iio_dev; } +static bool +st_lsm6dsx_report_motion_event(struct st_lsm6dsx_hw *hw) +{ + const struct st_lsm6dsx_event_settings *event_settings; + int err, data; + s64 timestamp; + + if (!hw->enable_event) + return false; + + event_settings = &hw->settings->event_settings; + err = st_lsm6dsx_read_locked(hw, event_settings->wakeup_src_reg, + &data, sizeof(data)); + if (err < 0) + return false; + + timestamp = iio_get_time_ns(hw->iio_devs[ST_LSM6DSX_ID_ACC]); + if ((data & hw->settings->event_settings.wakeup_src_z_mask) && + (hw->enable_event & BIT(IIO_MOD_Z))) + iio_push_event(hw->iio_devs[ST_LSM6DSX_ID_ACC], + IIO_MOD_EVENT_CODE(IIO_ACCEL, + 0, + IIO_MOD_Z, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_EITHER), + timestamp); + + if ((data & hw->settings->event_settings.wakeup_src_y_mask) && + (hw->enable_event & BIT(IIO_MOD_Y))) + iio_push_event(hw->iio_devs[ST_LSM6DSX_ID_ACC], + IIO_MOD_EVENT_CODE(IIO_ACCEL, + 0, + IIO_MOD_Y, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_EITHER), + timestamp); + + if ((data & hw->settings->event_settings.wakeup_src_x_mask) && + (hw->enable_event & BIT(IIO_MOD_X))) + iio_push_event(hw->iio_devs[ST_LSM6DSX_ID_ACC], + IIO_MOD_EVENT_CODE(IIO_ACCEL, + 0, + IIO_MOD_X, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_EITHER), + timestamp); + + return data & event_settings->wakeup_src_status_mask; +} + +static irqreturn_t st_lsm6dsx_handler_thread(int irq, void *private) +{ + struct st_lsm6dsx_hw *hw = private; + bool event; + int count; + + event = st_lsm6dsx_report_motion_event(hw); + + if (!hw->settings->fifo_ops.read_fifo) + return event ? IRQ_HANDLED : IRQ_NONE; + + mutex_lock(&hw->fifo_lock); + count = hw->settings->fifo_ops.read_fifo(hw); + mutex_unlock(&hw->fifo_lock); + + return count || event ? IRQ_HANDLED : IRQ_NONE; +} + +static int st_lsm6dsx_irq_setup(struct st_lsm6dsx_hw *hw) +{ + struct device_node *np = hw->dev->of_node; + struct st_sensors_platform_data *pdata; + const struct st_lsm6dsx_reg *reg; + unsigned long irq_type; + bool irq_active_low; + int err; + + irq_type = irqd_get_trigger_type(irq_get_irq_data(hw->irq)); + + switch (irq_type) { + case IRQF_TRIGGER_HIGH: + case IRQF_TRIGGER_RISING: + irq_active_low = false; + break; + case IRQF_TRIGGER_LOW: + case IRQF_TRIGGER_FALLING: + irq_active_low = true; + break; + default: + dev_info(hw->dev, "mode %lx unsupported\n", irq_type); + return -EINVAL; + } + + reg = &hw->settings->irq_config.hla; + err = regmap_update_bits(hw->regmap, reg->addr, reg->mask, + ST_LSM6DSX_SHIFT_VAL(irq_active_low, + reg->mask)); + if (err < 0) + return err; + + pdata = (struct st_sensors_platform_data *)hw->dev->platform_data; + if ((np && of_property_read_bool(np, "drive-open-drain")) || + (pdata && pdata->open_drain)) { + reg = &hw->settings->irq_config.od; + err = regmap_update_bits(hw->regmap, reg->addr, reg->mask, + ST_LSM6DSX_SHIFT_VAL(1, reg->mask)); + if (err < 0) + return err; + + irq_type |= IRQF_SHARED; + } + + err = devm_request_threaded_irq(hw->dev, hw->irq, + NULL, + st_lsm6dsx_handler_thread, + irq_type | IRQF_ONESHOT, + "lsm6dsx", hw); + if (err) { + dev_err(hw->dev, "failed to request trigger irq %d\n", + hw->irq); + return err; + } + + return 0; +} + int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, struct regmap *regmap) { + struct st_sensors_platform_data *pdata = dev->platform_data; const struct st_lsm6dsx_shub_settings *hub_settings; + struct device_node *np = dev->of_node; struct st_lsm6dsx_hw *hw; const char *name = NULL; int i, err; @@ -1524,6 +2220,10 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, } if (hw->irq > 0) { + err = st_lsm6dsx_irq_setup(hw); + if (err < 0) + return err; + err = st_lsm6dsx_fifo_setup(hw); if (err < 0) return err; @@ -1538,6 +2238,10 @@ int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id, return err; } + if ((np && of_property_read_bool(np, "wakeup-source")) || + (pdata && pdata->wakeup_source)) + device_init_wakeup(dev, true); + return 0; } EXPORT_SYMBOL(st_lsm6dsx_probe); @@ -1556,6 +2260,13 @@ static int __maybe_unused st_lsm6dsx_suspend(struct device *dev) if (!(hw->enable_mask & BIT(sensor->id))) continue; + if (device_may_wakeup(dev) && + sensor->id == ST_LSM6DSX_ID_ACC && hw->enable_event) { + /* Enable wake from IRQ */ + enable_irq_wake(hw->irq); + continue; + } + if (sensor->id == ST_LSM6DSX_ID_EXT0 || sensor->id == ST_LSM6DSX_ID_EXT1 || sensor->id == ST_LSM6DSX_ID_EXT2) @@ -1585,6 +2296,10 @@ static int __maybe_unused st_lsm6dsx_resume(struct device *dev) continue; sensor = iio_priv(hw->iio_devs[i]); + if (device_may_wakeup(dev) && + sensor->id == ST_LSM6DSX_ID_ACC && hw->enable_event) + disable_irq_wake(hw->irq); + if (!(hw->suspend_mask & BIT(sensor->id))) continue; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c index f52511059545..cd47ec1fedcb 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c @@ -87,6 +87,14 @@ static const struct of_device_id st_lsm6dsx_i2c_of_match[] = { .compatible = "st,lsm9ds1-imu", .data = (void *)ST_LSM9DS1_ID, }, + { + .compatible = "st,lsm6ds0", + .data = (void *)ST_LSM6DS0_ID, + }, + { + .compatible = "st,lsm6dsrx", + .data = (void *)ST_LSM6DSRX_ID, + }, {}, }; MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match); @@ -104,6 +112,8 @@ static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = { { ST_LSM6DS3TRC_DEV_NAME, ST_LSM6DS3TRC_ID }, { ST_ISM330DHCX_DEV_NAME, ST_ISM330DHCX_ID }, { ST_LSM9DS1_DEV_NAME, ST_LSM9DS1_ID }, + { ST_LSM6DS0_DEV_NAME, ST_LSM6DS0_ID }, + { ST_LSM6DSRX_DEV_NAME, ST_LSM6DSRX_ID }, {}, }; MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table); diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c index 344b28dddebb..67ff36eac247 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c @@ -87,6 +87,14 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = { .compatible = "st,lsm9ds1-imu", .data = (void *)ST_LSM9DS1_ID, }, + { + .compatible = "st,lsm6ds0", + .data = (void *)ST_LSM6DS0_ID, + }, + { + .compatible = "st,lsm6dsrx", + .data = (void *)ST_LSM6DSRX_ID, + }, {}, }; MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match); @@ -104,6 +112,8 @@ static const struct spi_device_id st_lsm6dsx_spi_id_table[] = { { ST_LSM6DS3TRC_DEV_NAME, ST_LSM6DS3TRC_ID }, { ST_ISM330DHCX_DEV_NAME, ST_ISM330DHCX_ID }, { ST_LSM9DS1_DEV_NAME, ST_LSM9DS1_ID }, + { ST_LSM6DS0_DEV_NAME, ST_LSM6DS0_ID }, + { ST_LSM6DSRX_DEV_NAME, ST_LSM6DSRX_ID }, {}, }; MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table); diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 524a686077ca..f72c2dc5f703 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -1238,6 +1238,16 @@ static ssize_t iio_show_dev_name(struct device *dev, static DEVICE_ATTR(name, S_IRUGO, iio_show_dev_name, NULL); +static ssize_t iio_show_dev_label(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + return snprintf(buf, PAGE_SIZE, "%s\n", indio_dev->label); +} + +static DEVICE_ATTR(label, S_IRUGO, iio_show_dev_label, NULL); + static ssize_t iio_show_timestamp_clock(struct device *dev, struct device_attribute *attr, char *buf) @@ -1354,6 +1364,8 @@ static int iio_device_register_sysfs(struct iio_dev *indio_dev) if (indio_dev->name) attrcount++; + if (indio_dev->label) + attrcount++; if (clk) attrcount++; @@ -1376,6 +1388,8 @@ static int iio_device_register_sysfs(struct iio_dev *indio_dev) indio_dev->chan_attr_group.attrs[attrn++] = &p->dev_attr.attr; if (indio_dev->name) indio_dev->chan_attr_group.attrs[attrn++] = &dev_attr_name.attr; + if (indio_dev->label) + indio_dev->chan_attr_group.attrs[attrn++] = &dev_attr_label.attr; if (clk) indio_dev->chan_attr_group.attrs[attrn++] = clk; @@ -1647,6 +1661,9 @@ int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod) if (!indio_dev->dev.of_node && indio_dev->dev.parent) indio_dev->dev.of_node = indio_dev->dev.parent->of_node; + indio_dev->label = of_get_property(indio_dev->dev.of_node, "label", + NULL); + ret = iio_check_unique_scan_index(indio_dev); if (ret < 0) return ret; diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index 4a1a883dc061..d793c1541705 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -32,6 +32,17 @@ config ADJD_S311 This driver can also be built as a module. If so, the module will be called adjd_s311. +config ADUX1020 + tristate "ADUX1020 photometric sensor" + select REGMAP_I2C + depends on I2C + help + Say Y here if you want to build a driver for the Analog Devices + ADUX1020 photometric sensor. + + To compile this driver as a module, choose M here: the + module will be called adux1020. + config AL3320A tristate "AL3320A ambient light sensor" depends on I2C diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index 00d1f9b98f39..5d650ce46a40 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -6,6 +6,7 @@ # When adding new entries keep the list in alphabetical order obj-$(CONFIG_ACPI_ALS) += acpi-als.o obj-$(CONFIG_ADJD_S311) += adjd_s311.o +obj-$(CONFIG_ADUX1020) += adux1020.o obj-$(CONFIG_AL3320A) += al3320a.o obj-$(CONFIG_APDS9300) += apds9300.o obj-$(CONFIG_APDS9960) += apds9960.o diff --git a/drivers/iio/light/adux1020.c b/drivers/iio/light/adux1020.c new file mode 100644 index 000000000000..b07797ac10d7 --- /dev/null +++ b/drivers/iio/light/adux1020.c @@ -0,0 +1,849 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * adux1020.c - Support for Analog Devices ADUX1020 photometric sensor + * + * Copyright (C) 2019 Linaro Ltd. + * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> + * + * TODO: Triggered buffer support + */ + +#include <linux/bitfield.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/regmap.h> + +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/events.h> + +#define ADUX1020_REGMAP_NAME "adux1020_regmap" +#define ADUX1020_DRV_NAME "adux1020" + +/* System registers */ +#define ADUX1020_REG_CHIP_ID 0x08 +#define ADUX1020_REG_SLAVE_ADDRESS 0x09 + +#define ADUX1020_REG_SW_RESET 0x0f +#define ADUX1020_REG_INT_ENABLE 0x1c +#define ADUX1020_REG_INT_POLARITY 0x1d +#define ADUX1020_REG_PROX_TH_ON1 0x2a +#define ADUX1020_REG_PROX_TH_OFF1 0x2b +#define ADUX1020_REG_PROX_TYPE 0x2f +#define ADUX1020_REG_TEST_MODES_3 0x32 +#define ADUX1020_REG_FORCE_MODE 0x33 +#define ADUX1020_REG_FREQUENCY 0x40 +#define ADUX1020_REG_LED_CURRENT 0x41 +#define ADUX1020_REG_OP_MODE 0x45 +#define ADUX1020_REG_INT_MASK 0x48 +#define ADUX1020_REG_INT_STATUS 0x49 +#define ADUX1020_REG_DATA_BUFFER 0x60 + +/* Chip ID bits */ +#define ADUX1020_CHIP_ID_MASK GENMASK(11, 0) +#define ADUX1020_CHIP_ID 0x03fc + +#define ADUX1020_SW_RESET BIT(1) +#define ADUX1020_FIFO_FLUSH BIT(15) +#define ADUX1020_OP_MODE_MASK GENMASK(3, 0) +#define ADUX1020_DATA_OUT_MODE_MASK GENMASK(7, 4) +#define ADUX1020_DATA_OUT_PROX_I FIELD_PREP(ADUX1020_DATA_OUT_MODE_MASK, 1) + +#define ADUX1020_MODE_INT_MASK GENMASK(7, 0) +#define ADUX1020_INT_ENABLE 0x2094 +#define ADUX1020_INT_DISABLE 0x2090 +#define ADUX1020_PROX_INT_ENABLE 0x00f0 +#define ADUX1020_PROX_ON1_INT BIT(0) +#define ADUX1020_PROX_OFF1_INT BIT(1) +#define ADUX1020_FIFO_INT_ENABLE 0x7f +#define ADUX1020_MODE_INT_DISABLE 0xff +#define ADUX1020_MODE_INT_STATUS_MASK GENMASK(7, 0) +#define ADUX1020_FIFO_STATUS_MASK GENMASK(15, 8) +#define ADUX1020_INT_CLEAR 0xff +#define ADUX1020_PROX_TYPE BIT(15) + +#define ADUX1020_INT_PROX_ON1 BIT(0) +#define ADUX1020_INT_PROX_OFF1 BIT(1) + +#define ADUX1020_FORCE_CLOCK_ON 0x0f4f +#define ADUX1020_FORCE_CLOCK_RESET 0x0040 +#define ADUX1020_ACTIVE_4_STATE 0x0008 + +#define ADUX1020_PROX_FREQ_MASK GENMASK(7, 4) +#define ADUX1020_PROX_FREQ(x) FIELD_PREP(ADUX1020_PROX_FREQ_MASK, x) + +#define ADUX1020_LED_CURRENT_MASK GENMASK(3, 0) +#define ADUX1020_LED_PIREF_EN BIT(12) + +/* Operating modes */ +enum adux1020_op_modes { + ADUX1020_MODE_STANDBY, + ADUX1020_MODE_PROX_I, + ADUX1020_MODE_PROX_XY, + ADUX1020_MODE_GEST, + ADUX1020_MODE_SAMPLE, + ADUX1020_MODE_FORCE = 0x0e, + ADUX1020_MODE_IDLE = 0x0f, +}; + +struct adux1020_data { + struct i2c_client *client; + struct iio_dev *indio_dev; + struct mutex lock; + struct regmap *regmap; +}; + +struct adux1020_mode_data { + u8 bytes; + u8 buf_len; + u16 int_en; +}; + +static const struct adux1020_mode_data adux1020_modes[] = { + [ADUX1020_MODE_PROX_I] = { + .bytes = 2, + .buf_len = 1, + .int_en = ADUX1020_PROX_INT_ENABLE, + }, +}; + +static const struct regmap_config adux1020_regmap_config = { + .name = ADUX1020_REGMAP_NAME, + .reg_bits = 8, + .val_bits = 16, + .max_register = 0x6F, + .cache_type = REGCACHE_NONE, +}; + +static const struct reg_sequence adux1020_def_conf[] = { + { 0x000c, 0x000f }, + { 0x0010, 0x1010 }, + { 0x0011, 0x004c }, + { 0x0012, 0x5f0c }, + { 0x0013, 0xada5 }, + { 0x0014, 0x0080 }, + { 0x0015, 0x0000 }, + { 0x0016, 0x0600 }, + { 0x0017, 0x0000 }, + { 0x0018, 0x2693 }, + { 0x0019, 0x0004 }, + { 0x001a, 0x4280 }, + { 0x001b, 0x0060 }, + { 0x001c, 0x2094 }, + { 0x001d, 0x0020 }, + { 0x001e, 0x0001 }, + { 0x001f, 0x0100 }, + { 0x0020, 0x0320 }, + { 0x0021, 0x0A13 }, + { 0x0022, 0x0320 }, + { 0x0023, 0x0113 }, + { 0x0024, 0x0000 }, + { 0x0025, 0x2412 }, + { 0x0026, 0x2412 }, + { 0x0027, 0x0022 }, + { 0x0028, 0x0000 }, + { 0x0029, 0x0300 }, + { 0x002a, 0x0700 }, + { 0x002b, 0x0600 }, + { 0x002c, 0x6000 }, + { 0x002d, 0x4000 }, + { 0x002e, 0x0000 }, + { 0x002f, 0x0000 }, + { 0x0030, 0x0000 }, + { 0x0031, 0x0000 }, + { 0x0032, 0x0040 }, + { 0x0033, 0x0008 }, + { 0x0034, 0xE400 }, + { 0x0038, 0x8080 }, + { 0x0039, 0x8080 }, + { 0x003a, 0x2000 }, + { 0x003b, 0x1f00 }, + { 0x003c, 0x2000 }, + { 0x003d, 0x2000 }, + { 0x003e, 0x0000 }, + { 0x0040, 0x8069 }, + { 0x0041, 0x1f2f }, + { 0x0042, 0x4000 }, + { 0x0043, 0x0000 }, + { 0x0044, 0x0008 }, + { 0x0046, 0x0000 }, + { 0x0048, 0x00ef }, + { 0x0049, 0x0000 }, + { 0x0045, 0x0000 }, +}; + +static const int adux1020_rates[][2] = { + { 0, 100000 }, + { 0, 200000 }, + { 0, 500000 }, + { 1, 0 }, + { 2, 0 }, + { 5, 0 }, + { 10, 0 }, + { 20, 0 }, + { 50, 0 }, + { 100, 0 }, + { 190, 0 }, + { 450, 0 }, + { 820, 0 }, + { 1400, 0 }, +}; + +static const int adux1020_led_currents[][2] = { + { 0, 25000 }, + { 0, 40000 }, + { 0, 55000 }, + { 0, 70000 }, + { 0, 85000 }, + { 0, 100000 }, + { 0, 115000 }, + { 0, 130000 }, + { 0, 145000 }, + { 0, 160000 }, + { 0, 175000 }, + { 0, 190000 }, + { 0, 205000 }, + { 0, 220000 }, + { 0, 235000 }, + { 0, 250000 }, +}; + +static int adux1020_flush_fifo(struct adux1020_data *data) +{ + int ret; + + /* Force Idle mode */ + ret = regmap_write(data->regmap, ADUX1020_REG_FORCE_MODE, + ADUX1020_ACTIVE_4_STATE); + if (ret < 0) + return ret; + + ret = regmap_update_bits(data->regmap, ADUX1020_REG_OP_MODE, + ADUX1020_OP_MODE_MASK, ADUX1020_MODE_FORCE); + if (ret < 0) + return ret; + + ret = regmap_update_bits(data->regmap, ADUX1020_REG_OP_MODE, + ADUX1020_OP_MODE_MASK, ADUX1020_MODE_IDLE); + if (ret < 0) + return ret; + + /* Flush FIFO */ + ret = regmap_write(data->regmap, ADUX1020_REG_TEST_MODES_3, + ADUX1020_FORCE_CLOCK_ON); + if (ret < 0) + return ret; + + ret = regmap_write(data->regmap, ADUX1020_REG_INT_STATUS, + ADUX1020_FIFO_FLUSH); + if (ret < 0) + return ret; + + return regmap_write(data->regmap, ADUX1020_REG_TEST_MODES_3, + ADUX1020_FORCE_CLOCK_RESET); +} + +static int adux1020_read_fifo(struct adux1020_data *data, u16 *buf, u8 buf_len) +{ + unsigned int regval; + int i, ret; + + /* Enable 32MHz clock */ + ret = regmap_write(data->regmap, ADUX1020_REG_TEST_MODES_3, + ADUX1020_FORCE_CLOCK_ON); + if (ret < 0) + return ret; + + for (i = 0; i < buf_len; i++) { + ret = regmap_read(data->regmap, ADUX1020_REG_DATA_BUFFER, + ®val); + if (ret < 0) + return ret; + + buf[i] = regval; + } + + /* Set 32MHz clock to be controlled by internal state machine */ + return regmap_write(data->regmap, ADUX1020_REG_TEST_MODES_3, + ADUX1020_FORCE_CLOCK_RESET); +} + +static int adux1020_set_mode(struct adux1020_data *data, + enum adux1020_op_modes mode) +{ + int ret; + + /* Switch to standby mode before changing the mode */ + ret = regmap_write(data->regmap, ADUX1020_REG_OP_MODE, + ADUX1020_MODE_STANDBY); + if (ret < 0) + return ret; + + /* Set data out and switch to the desired mode */ + switch (mode) { + case ADUX1020_MODE_PROX_I: + ret = regmap_update_bits(data->regmap, ADUX1020_REG_OP_MODE, + ADUX1020_DATA_OUT_MODE_MASK, + ADUX1020_DATA_OUT_PROX_I); + if (ret < 0) + return ret; + + ret = regmap_update_bits(data->regmap, ADUX1020_REG_OP_MODE, + ADUX1020_OP_MODE_MASK, + ADUX1020_MODE_PROX_I); + if (ret < 0) + return ret; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int adux1020_measure(struct adux1020_data *data, + enum adux1020_op_modes mode, + u16 *val) +{ + unsigned int status; + int ret, tries = 50; + + /* Disable INT pin as polling is going to be used */ + ret = regmap_write(data->regmap, ADUX1020_REG_INT_ENABLE, + ADUX1020_INT_DISABLE); + if (ret < 0) + return ret; + + /* Enable mode interrupt */ + ret = regmap_update_bits(data->regmap, ADUX1020_REG_INT_MASK, + ADUX1020_MODE_INT_MASK, + adux1020_modes[mode].int_en); + if (ret < 0) + return ret; + + while (tries--) { + ret = regmap_read(data->regmap, ADUX1020_REG_INT_STATUS, + &status); + if (ret < 0) + return ret; + + status &= ADUX1020_FIFO_STATUS_MASK; + if (status >= adux1020_modes[mode].bytes) + break; + msleep(20); + } + + if (tries < 0) + return -EIO; + + ret = adux1020_read_fifo(data, val, adux1020_modes[mode].buf_len); + if (ret < 0) + return ret; + + /* Clear mode interrupt */ + ret = regmap_write(data->regmap, ADUX1020_REG_INT_STATUS, + (~adux1020_modes[mode].int_en)); + if (ret < 0) + return ret; + + /* Disable mode interrupts */ + return regmap_update_bits(data->regmap, ADUX1020_REG_INT_MASK, + ADUX1020_MODE_INT_MASK, + ADUX1020_MODE_INT_DISABLE); +} + +static int adux1020_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct adux1020_data *data = iio_priv(indio_dev); + u16 buf[3]; + int ret = -EINVAL; + unsigned int regval; + + mutex_lock(&data->lock); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + switch (chan->type) { + case IIO_PROXIMITY: + ret = adux1020_set_mode(data, ADUX1020_MODE_PROX_I); + if (ret < 0) + goto fail; + + ret = adux1020_measure(data, ADUX1020_MODE_PROX_I, buf); + if (ret < 0) + goto fail; + + *val = buf[0]; + ret = IIO_VAL_INT; + break; + default: + break; + } + break; + case IIO_CHAN_INFO_PROCESSED: + switch (chan->type) { + case IIO_CURRENT: + ret = regmap_read(data->regmap, + ADUX1020_REG_LED_CURRENT, ®val); + if (ret < 0) + goto fail; + + regval = regval & ADUX1020_LED_CURRENT_MASK; + + *val = adux1020_led_currents[regval][0]; + *val2 = adux1020_led_currents[regval][1]; + + ret = IIO_VAL_INT_PLUS_MICRO; + break; + default: + break; + } + break; + case IIO_CHAN_INFO_SAMP_FREQ: + switch (chan->type) { + case IIO_PROXIMITY: + ret = regmap_read(data->regmap, ADUX1020_REG_FREQUENCY, + ®val); + if (ret < 0) + goto fail; + + regval = FIELD_GET(ADUX1020_PROX_FREQ_MASK, regval); + + *val = adux1020_rates[regval][0]; + *val2 = adux1020_rates[regval][1]; + + ret = IIO_VAL_INT_PLUS_MICRO; + break; + default: + break; + } + break; + default: + break; + } + +fail: + mutex_unlock(&data->lock); + + return ret; +}; + +static inline int adux1020_find_index(const int array[][2], int count, int val, + int val2) +{ + int i; + + for (i = 0; i < count; i++) + if (val == array[i][0] && val2 == array[i][1]) + return i; + + return -EINVAL; +} + +static int adux1020_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct adux1020_data *data = iio_priv(indio_dev); + int i, ret = -EINVAL; + + mutex_lock(&data->lock); + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + if (chan->type == IIO_PROXIMITY) { + i = adux1020_find_index(adux1020_rates, + ARRAY_SIZE(adux1020_rates), + val, val2); + if (i < 0) { + ret = i; + goto fail; + } + + ret = regmap_update_bits(data->regmap, + ADUX1020_REG_FREQUENCY, + ADUX1020_PROX_FREQ_MASK, + ADUX1020_PROX_FREQ(i)); + } + break; + case IIO_CHAN_INFO_PROCESSED: + if (chan->type == IIO_CURRENT) { + i = adux1020_find_index(adux1020_led_currents, + ARRAY_SIZE(adux1020_led_currents), + val, val2); + if (i < 0) { + ret = i; + goto fail; + } + + ret = regmap_update_bits(data->regmap, + ADUX1020_REG_LED_CURRENT, + ADUX1020_LED_CURRENT_MASK, i); + } + break; + default: + break; + } + +fail: + mutex_unlock(&data->lock); + + return ret; +} + +static int adux1020_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, int state) +{ + struct adux1020_data *data = iio_priv(indio_dev); + int ret, mask; + + mutex_lock(&data->lock); + + ret = regmap_write(data->regmap, ADUX1020_REG_INT_ENABLE, + ADUX1020_INT_ENABLE); + if (ret < 0) + goto fail; + + ret = regmap_write(data->regmap, ADUX1020_REG_INT_POLARITY, 0); + if (ret < 0) + goto fail; + + switch (chan->type) { + case IIO_PROXIMITY: + if (dir == IIO_EV_DIR_RISING) + mask = ADUX1020_PROX_ON1_INT; + else + mask = ADUX1020_PROX_OFF1_INT; + + if (state) + state = 0; + else + state = mask; + + ret = regmap_update_bits(data->regmap, ADUX1020_REG_INT_MASK, + mask, state); + if (ret < 0) + goto fail; + + /* + * Trigger proximity interrupt when the intensity is above + * or below threshold + */ + ret = regmap_update_bits(data->regmap, ADUX1020_REG_PROX_TYPE, + ADUX1020_PROX_TYPE, + ADUX1020_PROX_TYPE); + if (ret < 0) + goto fail; + + /* Set proximity mode */ + ret = adux1020_set_mode(data, ADUX1020_MODE_PROX_I); + break; + default: + ret = -EINVAL; + break; + } + +fail: + mutex_unlock(&data->lock); + + return ret; +} + +static int adux1020_read_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + struct adux1020_data *data = iio_priv(indio_dev); + int ret, mask; + unsigned int regval; + + switch (chan->type) { + case IIO_PROXIMITY: + if (dir == IIO_EV_DIR_RISING) + mask = ADUX1020_PROX_ON1_INT; + else + mask = ADUX1020_PROX_OFF1_INT; + break; + default: + return -EINVAL; + } + + ret = regmap_read(data->regmap, ADUX1020_REG_INT_MASK, ®val); + if (ret < 0) + return ret; + + return !(regval & mask); +} + +static int adux1020_read_thresh(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, int *val, int *val2) +{ + struct adux1020_data *data = iio_priv(indio_dev); + u8 reg; + int ret; + unsigned int regval; + + switch (chan->type) { + case IIO_PROXIMITY: + if (dir == IIO_EV_DIR_RISING) + reg = ADUX1020_REG_PROX_TH_ON1; + else + reg = ADUX1020_REG_PROX_TH_OFF1; + break; + default: + return -EINVAL; + } + + ret = regmap_read(data->regmap, reg, ®val); + if (ret < 0) + return ret; + + *val = regval; + + return IIO_VAL_INT; +} + +static int adux1020_write_thresh(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, int val, int val2) +{ + struct adux1020_data *data = iio_priv(indio_dev); + u8 reg; + + switch (chan->type) { + case IIO_PROXIMITY: + if (dir == IIO_EV_DIR_RISING) + reg = ADUX1020_REG_PROX_TH_ON1; + else + reg = ADUX1020_REG_PROX_TH_OFF1; + break; + default: + return -EINVAL; + } + + /* Full scale threshold value is 0-65535 */ + if (val < 0 || val > 65535) + return -EINVAL; + + return regmap_write(data->regmap, reg, val); +} + +static const struct iio_event_spec adux1020_proximity_event[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_separate = BIT(IIO_EV_INFO_VALUE) | + BIT(IIO_EV_INFO_ENABLE), + }, +}; + +static const struct iio_chan_spec adux1020_channels[] = { + { + .type = IIO_PROXIMITY, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SAMP_FREQ), + .event_spec = adux1020_proximity_event, + .num_event_specs = ARRAY_SIZE(adux1020_proximity_event), + }, + { + .type = IIO_CURRENT, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + .extend_name = "led", + .output = 1, + }, +}; + +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL( + "0.1 0.2 0.5 1 2 5 10 20 50 100 190 450 820 1400"); + +static struct attribute *adux1020_attributes[] = { + &iio_const_attr_sampling_frequency_available.dev_attr.attr, + NULL +}; + +static const struct attribute_group adux1020_attribute_group = { + .attrs = adux1020_attributes, +}; + +static const struct iio_info adux1020_info = { + .attrs = &adux1020_attribute_group, + .read_raw = adux1020_read_raw, + .write_raw = adux1020_write_raw, + .read_event_config = adux1020_read_event_config, + .write_event_config = adux1020_write_event_config, + .read_event_value = adux1020_read_thresh, + .write_event_value = adux1020_write_thresh, +}; + +static irqreturn_t adux1020_interrupt_handler(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct adux1020_data *data = iio_priv(indio_dev); + int ret, status; + + ret = regmap_read(data->regmap, ADUX1020_REG_INT_STATUS, &status); + if (ret < 0) + return IRQ_HANDLED; + + status &= ADUX1020_MODE_INT_STATUS_MASK; + + if (status & ADUX1020_INT_PROX_ON1) { + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_RISING), + iio_get_time_ns(indio_dev)); + } + + if (status & ADUX1020_INT_PROX_OFF1) { + iio_push_event(indio_dev, + IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0, + IIO_EV_TYPE_THRESH, + IIO_EV_DIR_FALLING), + iio_get_time_ns(indio_dev)); + } + + regmap_update_bits(data->regmap, ADUX1020_REG_INT_STATUS, + ADUX1020_MODE_INT_MASK, ADUX1020_INT_CLEAR); + + return IRQ_HANDLED; +} + +static int adux1020_chip_init(struct adux1020_data *data) +{ + struct i2c_client *client = data->client; + int ret; + unsigned int val; + + ret = regmap_read(data->regmap, ADUX1020_REG_CHIP_ID, &val); + if (ret < 0) + return ret; + + if ((val & ADUX1020_CHIP_ID_MASK) != ADUX1020_CHIP_ID) { + dev_err(&client->dev, "invalid chip id 0x%04x\n", val); + return -ENODEV; + } + + dev_dbg(&client->dev, "Detected ADUX1020 with chip id: 0x%04x\n", val); + + ret = regmap_update_bits(data->regmap, ADUX1020_REG_SW_RESET, + ADUX1020_SW_RESET, ADUX1020_SW_RESET); + if (ret < 0) + return ret; + + /* Load default configuration */ + ret = regmap_multi_reg_write(data->regmap, adux1020_def_conf, + ARRAY_SIZE(adux1020_def_conf)); + if (ret < 0) + return ret; + + ret = adux1020_flush_fifo(data); + if (ret < 0) + return ret; + + /* Use LED_IREF for proximity mode */ + ret = regmap_update_bits(data->regmap, ADUX1020_REG_LED_CURRENT, + ADUX1020_LED_PIREF_EN, 0); + if (ret < 0) + return ret; + + /* Mask all interrupts */ + return regmap_update_bits(data->regmap, ADUX1020_REG_INT_MASK, + ADUX1020_MODE_INT_MASK, ADUX1020_MODE_INT_DISABLE); +} + +static int adux1020_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct adux1020_data *data; + struct iio_dev *indio_dev; + int ret; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + indio_dev->dev.parent = &client->dev; + indio_dev->info = &adux1020_info; + indio_dev->name = ADUX1020_DRV_NAME; + indio_dev->channels = adux1020_channels; + indio_dev->num_channels = ARRAY_SIZE(adux1020_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + + data = iio_priv(indio_dev); + + data->regmap = devm_regmap_init_i2c(client, &adux1020_regmap_config); + if (IS_ERR(data->regmap)) { + dev_err(&client->dev, "regmap initialization failed.\n"); + return PTR_ERR(data->regmap); + } + + data->client = client; + data->indio_dev = indio_dev; + mutex_init(&data->lock); + + ret = adux1020_chip_init(data); + if (ret) + return ret; + + if (client->irq) { + ret = devm_request_threaded_irq(&client->dev, client->irq, + NULL, adux1020_interrupt_handler, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + ADUX1020_DRV_NAME, indio_dev); + if (ret) { + dev_err(&client->dev, "irq request error %d\n", -ret); + return ret; + } + } + + return devm_iio_device_register(&client->dev, indio_dev); +} + +static const struct i2c_device_id adux1020_id[] = { + { "adux1020", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, adux1020_id); + +static const struct of_device_id adux1020_of_match[] = { + { .compatible = "adi,adux1020" }, + { } +}; +MODULE_DEVICE_TABLE(of, adux1020_of_match); + +static struct i2c_driver adux1020_driver = { + .driver = { + .name = ADUX1020_DRV_NAME, + .of_match_table = adux1020_of_match, + }, + .probe = adux1020_probe, + .id_table = adux1020_id, +}; +module_i2c_driver(adux1020_driver); + +MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>"); +MODULE_DESCRIPTION("ADUX1020 photometric sensor"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/light/bh1750.c b/drivers/iio/light/bh1750.c index 28347df78cff..adb5ab9e3439 100644 --- a/drivers/iio/light/bh1750.c +++ b/drivers/iio/light/bh1750.c @@ -59,9 +59,9 @@ struct bh1750_chip_info { u16 int_time_low_mask; u16 int_time_high_mask; -} +}; -static const bh1750_chip_info_tbl[] = { +static const struct bh1750_chip_info bh1750_chip_info_tbl[] = { [BH1710] = { 140, 1022, 300, 400, 250000000, 2, 0x001F, 0x03E0 }, [BH1721] = { 140, 1020, 300, 400, 250000000, 2, 0x0010, 0x03E0 }, [BH1750] = { 31, 254, 69, 1740, 57500000, 1, 0x001F, 0x00E0 }, diff --git a/drivers/iio/light/cm36651.c b/drivers/iio/light/cm36651.c index 1019d625adb1..90e38fcc974b 100644 --- a/drivers/iio/light/cm36651.c +++ b/drivers/iio/light/cm36651.c @@ -532,7 +532,7 @@ static int cm36651_write_prox_event_config(struct iio_dev *indio_dev, int state) { struct cm36651_data *cm36651 = iio_priv(indio_dev); - int cmd, ret = -EINVAL; + int cmd, ret; mutex_lock(&cm36651->lock); diff --git a/drivers/iio/light/tcs3414.c b/drivers/iio/light/tcs3414.c index 7c0291c5fe76..b542e5619ead 100644 --- a/drivers/iio/light/tcs3414.c +++ b/drivers/iio/light/tcs3414.c @@ -240,32 +240,42 @@ static const struct iio_info tcs3414_info = { .attrs = &tcs3414_attribute_group, }; -static int tcs3414_buffer_preenable(struct iio_dev *indio_dev) +static int tcs3414_buffer_postenable(struct iio_dev *indio_dev) { struct tcs3414_data *data = iio_priv(indio_dev); + int ret; + + ret = iio_triggered_buffer_postenable(indio_dev); + if (ret) + return ret; data->control |= TCS3414_CONTROL_ADC_EN; - return i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL, + ret = i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL, data->control); + if (ret) + iio_triggered_buffer_predisable(indio_dev); + + return ret; } static int tcs3414_buffer_predisable(struct iio_dev *indio_dev) { struct tcs3414_data *data = iio_priv(indio_dev); - int ret; - - ret = iio_triggered_buffer_predisable(indio_dev); - if (ret < 0) - return ret; + int ret, ret2; data->control &= ~TCS3414_CONTROL_ADC_EN; - return i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL, + ret = i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL, data->control); + + ret2 = iio_triggered_buffer_predisable(indio_dev); + if (!ret) + ret = ret2; + + return ret; } static const struct iio_buffer_setup_ops tcs3414_buffer_setup_ops = { - .preenable = tcs3414_buffer_preenable, - .postenable = &iio_triggered_buffer_postenable, + .postenable = tcs3414_buffer_postenable, .predisable = tcs3414_buffer_predisable, }; diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index a3a268ee2896..e68184a93a6d 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -14,7 +14,6 @@ #include <linux/types.h> #include <linux/interrupt.h> #include <linux/i2c.h> -#include <linux/gpio.h> #include <linux/irq.h> #include <linux/delay.h> #include <linux/iio/iio.h> diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index 8d0f15f27dc5..29c209cc1108 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -74,6 +74,12 @@ struct bmp280_calib { s8 H6; }; +static const char *const bmp280_supply_names[] = { + "vddd", "vdda" +}; + +#define BMP280_NUM_SUPPLIES ARRAY_SIZE(bmp280_supply_names) + struct bmp280_data { struct device *dev; struct mutex lock; @@ -85,8 +91,7 @@ struct bmp280_data { struct bmp180_calib bmp180; struct bmp280_calib bmp280; } calib; - struct regulator *vddd; - struct regulator *vdda; + struct regulator_bulk_data supplies[BMP280_NUM_SUPPLIES]; unsigned int start_up_time; /* in microseconds */ /* log of base 2 of oversampling rate */ @@ -148,6 +153,8 @@ static int bmp280_read_calib(struct bmp280_data *data, { int ret; unsigned int tmp; + __le16 l16; + __be16 b16; struct device *dev = data->dev; __le16 t_buf[BMP280_COMP_TEMP_REG_COUNT / 2]; __le16 p_buf[BMP280_COMP_PRESS_REG_COUNT / 2]; @@ -207,12 +214,12 @@ static int bmp280_read_calib(struct bmp280_data *data, } calib->H1 = tmp; - ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H2, &tmp, 2); + ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H2, &l16, 2); if (ret < 0) { dev_err(dev, "failed to read H2 comp value\n"); return ret; } - calib->H2 = sign_extend32(le16_to_cpu(tmp), 15); + calib->H2 = sign_extend32(le16_to_cpu(l16), 15); ret = regmap_read(data->regmap, BMP280_REG_COMP_H3, &tmp); if (ret < 0) { @@ -221,20 +228,20 @@ static int bmp280_read_calib(struct bmp280_data *data, } calib->H3 = tmp; - ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H4, &tmp, 2); + ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H4, &b16, 2); if (ret < 0) { dev_err(dev, "failed to read H4 comp value\n"); return ret; } - calib->H4 = sign_extend32(((be16_to_cpu(tmp) >> 4) & 0xff0) | - (be16_to_cpu(tmp) & 0xf), 11); + calib->H4 = sign_extend32(((be16_to_cpu(b16) >> 4) & 0xff0) | + (be16_to_cpu(b16) & 0xf), 11); - ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H5, &tmp, 2); + ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H5, &l16, 2); if (ret < 0) { dev_err(dev, "failed to read H5 comp value\n"); return ret; } - calib->H5 = sign_extend32(((le16_to_cpu(tmp) >> 4) & 0xfff), 11); + calib->H5 = sign_extend32(((le16_to_cpu(l16) >> 4) & 0xfff), 11); ret = regmap_read(data->regmap, BMP280_REG_COMP_H6, &tmp); if (ret < 0) { @@ -979,6 +986,22 @@ static int bmp085_fetch_eoc_irq(struct device *dev, return 0; } +static void bmp280_pm_disable(void *data) +{ + struct device *dev = data; + + pm_runtime_get_sync(dev); + pm_runtime_put_noidle(dev); + pm_runtime_disable(dev); +} + +static void bmp280_regulators_disable(void *data) +{ + struct regulator_bulk_data *supplies = data; + + regulator_bulk_disable(BMP280_NUM_SUPPLIES, supplies); +} + int bmp280_common_probe(struct device *dev, struct regmap *regmap, unsigned int chip, @@ -1033,27 +1056,28 @@ int bmp280_common_probe(struct device *dev, } /* Bring up regulators */ - data->vddd = devm_regulator_get(dev, "vddd"); - if (IS_ERR(data->vddd)) { - dev_err(dev, "failed to get VDDD regulator\n"); - return PTR_ERR(data->vddd); - } - ret = regulator_enable(data->vddd); + regulator_bulk_set_supply_names(data->supplies, + bmp280_supply_names, + BMP280_NUM_SUPPLIES); + + ret = devm_regulator_bulk_get(dev, + BMP280_NUM_SUPPLIES, data->supplies); if (ret) { - dev_err(dev, "failed to enable VDDD regulator\n"); + dev_err(dev, "failed to get regulators\n"); return ret; } - data->vdda = devm_regulator_get(dev, "vdda"); - if (IS_ERR(data->vdda)) { - dev_err(dev, "failed to get VDDA regulator\n"); - ret = PTR_ERR(data->vdda); - goto out_disable_vddd; - } - ret = regulator_enable(data->vdda); + + ret = regulator_bulk_enable(BMP280_NUM_SUPPLIES, data->supplies); if (ret) { - dev_err(dev, "failed to enable VDDA regulator\n"); - goto out_disable_vddd; + dev_err(dev, "failed to enable regulators\n"); + return ret; } + + ret = devm_add_action_or_reset(dev, bmp280_regulators_disable, + data->supplies); + if (ret) + return ret; + /* Wait to make sure we started up properly */ usleep_range(data->start_up_time, data->start_up_time + 100); @@ -1068,17 +1092,16 @@ int bmp280_common_probe(struct device *dev, data->regmap = regmap; ret = regmap_read(regmap, BMP280_REG_ID, &chip_id); if (ret < 0) - goto out_disable_vdda; + return ret; if (chip_id != chip) { dev_err(dev, "bad chip id: expected %x got %x\n", chip, chip_id); - ret = -EINVAL; - goto out_disable_vdda; + return -EINVAL; } ret = data->chip_info->chip_config(data); if (ret < 0) - goto out_disable_vdda; + return ret; dev_set_drvdata(dev, indio_dev); @@ -1092,14 +1115,14 @@ int bmp280_common_probe(struct device *dev, if (ret < 0) { dev_err(data->dev, "failed to read calibration coefficients\n"); - goto out_disable_vdda; + return ret; } } else if (chip_id == BMP280_CHIP_ID || chip_id == BME280_CHIP_ID) { ret = bmp280_read_calib(data, &data->calib.bmp280, chip_id); if (ret < 0) { dev_err(data->dev, "failed to read calibration coefficients\n"); - goto out_disable_vdda; + return ret; } } @@ -1111,7 +1134,7 @@ int bmp280_common_probe(struct device *dev, if (irq > 0 || (chip_id == BMP180_CHIP_ID)) { ret = bmp085_fetch_eoc_irq(dev, name, irq, data); if (ret) - goto out_disable_vdda; + return ret; } /* Enable runtime PM */ @@ -1126,51 +1149,21 @@ int bmp280_common_probe(struct device *dev, pm_runtime_use_autosuspend(dev); pm_runtime_put(dev); - ret = iio_device_register(indio_dev); + ret = devm_add_action_or_reset(dev, bmp280_pm_disable, dev); if (ret) - goto out_runtime_pm_disable; - - - return 0; + return ret; -out_runtime_pm_disable: - pm_runtime_get_sync(data->dev); - pm_runtime_put_noidle(data->dev); - pm_runtime_disable(data->dev); -out_disable_vdda: - regulator_disable(data->vdda); -out_disable_vddd: - regulator_disable(data->vddd); - return ret; + return devm_iio_device_register(dev, indio_dev); } EXPORT_SYMBOL(bmp280_common_probe); -int bmp280_common_remove(struct device *dev) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct bmp280_data *data = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - pm_runtime_get_sync(data->dev); - pm_runtime_put_noidle(data->dev); - pm_runtime_disable(data->dev); - regulator_disable(data->vdda); - regulator_disable(data->vddd); - return 0; -} -EXPORT_SYMBOL(bmp280_common_remove); - #ifdef CONFIG_PM static int bmp280_runtime_suspend(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); struct bmp280_data *data = iio_priv(indio_dev); - int ret; - ret = regulator_disable(data->vdda); - if (ret) - return ret; - return regulator_disable(data->vddd); + return regulator_bulk_disable(BMP280_NUM_SUPPLIES, data->supplies); } static int bmp280_runtime_resume(struct device *dev) @@ -1179,10 +1172,7 @@ static int bmp280_runtime_resume(struct device *dev) struct bmp280_data *data = iio_priv(indio_dev); int ret; - ret = regulator_enable(data->vddd); - if (ret) - return ret; - ret = regulator_enable(data->vdda); + ret = regulator_bulk_enable(BMP280_NUM_SUPPLIES, data->supplies); if (ret) return ret; usleep_range(data->start_up_time, data->start_up_time + 100); diff --git a/drivers/iio/pressure/bmp280-i2c.c b/drivers/iio/pressure/bmp280-i2c.c index acd9a3784fb4..3109c8e2cc11 100644 --- a/drivers/iio/pressure/bmp280-i2c.c +++ b/drivers/iio/pressure/bmp280-i2c.c @@ -38,11 +38,6 @@ static int bmp280_i2c_probe(struct i2c_client *client, client->irq); } -static int bmp280_i2c_remove(struct i2c_client *client) -{ - return bmp280_common_remove(&client->dev); -} - static const struct acpi_device_id bmp280_acpi_i2c_match[] = { {"BMP0280", BMP280_CHIP_ID }, {"BMP0180", BMP180_CHIP_ID }, @@ -82,7 +77,6 @@ static struct i2c_driver bmp280_i2c_driver = { .pm = &bmp280_dev_pm_ops, }, .probe = bmp280_i2c_probe, - .remove = bmp280_i2c_remove, .id_table = bmp280_i2c_id, }; module_i2c_driver(bmp280_i2c_driver); diff --git a/drivers/iio/pressure/bmp280-spi.c b/drivers/iio/pressure/bmp280-spi.c index 9d57b7a3b134..625b86878ad8 100644 --- a/drivers/iio/pressure/bmp280-spi.c +++ b/drivers/iio/pressure/bmp280-spi.c @@ -86,11 +86,6 @@ static int bmp280_spi_probe(struct spi_device *spi) spi->irq); } -static int bmp280_spi_remove(struct spi_device *spi) -{ - return bmp280_common_remove(&spi->dev); -} - static const struct of_device_id bmp280_of_spi_match[] = { { .compatible = "bosch,bmp085", }, { .compatible = "bosch,bmp180", }, @@ -118,7 +113,6 @@ static struct spi_driver bmp280_spi_driver = { }, .id_table = bmp280_spi_id, .probe = bmp280_spi_probe, - .remove = bmp280_spi_remove, }; module_spi_driver(bmp280_spi_driver); diff --git a/drivers/iio/pressure/bmp280.h b/drivers/iio/pressure/bmp280.h index eda50ef65706..57ba0e85db91 100644 --- a/drivers/iio/pressure/bmp280.h +++ b/drivers/iio/pressure/bmp280.h @@ -112,7 +112,6 @@ int bmp280_common_probe(struct device *dev, unsigned int chip, const char *name, int irq); -int bmp280_common_remove(struct device *dev); /* PM ops */ extern const struct dev_pm_ops bmp280_dev_pm_ops; diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index ca6863b32a5f..bd972cec4830 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -14,7 +14,6 @@ #include <linux/types.h> #include <linux/interrupt.h> #include <linux/i2c.h> -#include <linux/gpio.h> #include <linux/irq.h> #include <linux/delay.h> #include <linux/iio/iio.h> diff --git a/drivers/iio/pressure/zpa2326.c b/drivers/iio/pressure/zpa2326.c index 9d0d07930236..99dfe33ee402 100644 --- a/drivers/iio/pressure/zpa2326.c +++ b/drivers/iio/pressure/zpa2326.c @@ -1243,6 +1243,11 @@ static int zpa2326_postenable_buffer(struct iio_dev *indio_dev) const struct zpa2326_private *priv = iio_priv(indio_dev); int err; + /* Plug our own trigger event handler. */ + err = iio_triggered_buffer_postenable(indio_dev); + if (err) + goto err; + if (!priv->waken) { /* * We were already power supplied. Just clear hardware FIFO to @@ -1250,7 +1255,7 @@ static int zpa2326_postenable_buffer(struct iio_dev *indio_dev) */ err = zpa2326_clear_fifo(indio_dev, 0); if (err) - goto err; + goto err_buffer_predisable; } if (!iio_trigger_using_own(indio_dev) && priv->waken) { @@ -1260,16 +1265,13 @@ static int zpa2326_postenable_buffer(struct iio_dev *indio_dev) */ err = zpa2326_config_oneshot(indio_dev, priv->irq); if (err) - goto err; + goto err_buffer_predisable; } - /* Plug our own trigger event handler. */ - err = iio_triggered_buffer_postenable(indio_dev); - if (err) - goto err; - return 0; +err_buffer_predisable: + iio_triggered_buffer_predisable(indio_dev); err: zpa2326_err(indio_dev, "failed to enable buffering (%d)", err); diff --git a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c index 47af54f14756..5b369645ef49 100644 --- a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c +++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c @@ -136,12 +136,13 @@ static inline int lidar_write_power(struct lidar_data *data, int val) static int lidar_read_measurement(struct lidar_data *data, u16 *reg) { + __be16 value; int ret = data->xfer(data, LIDAR_REG_DATA_HBYTE | (data->i2c_enabled ? LIDAR_REG_DATA_WORD_READ : 0), - (u8 *) reg, 2); + (u8 *) &value, 2); if (!ret) - *reg = be16_to_cpu(*reg); + *reg = be16_to_cpu(value); return ret; } diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c index 612f79c53cfc..287d288e40c2 100644 --- a/drivers/iio/proximity/sx9500.c +++ b/drivers/iio/proximity/sx9500.c @@ -675,11 +675,15 @@ out: return IRQ_HANDLED; } -static int sx9500_buffer_preenable(struct iio_dev *indio_dev) +static int sx9500_buffer_postenable(struct iio_dev *indio_dev) { struct sx9500_data *data = iio_priv(indio_dev); int ret = 0, i; + ret = iio_triggered_buffer_postenable(indio_dev); + if (ret) + return ret; + mutex_lock(&data->mutex); for (i = 0; i < SX9500_NUM_CHANNELS; i++) @@ -696,6 +700,9 @@ static int sx9500_buffer_preenable(struct iio_dev *indio_dev) mutex_unlock(&data->mutex); + if (ret) + iio_triggered_buffer_predisable(indio_dev); + return ret; } @@ -704,8 +711,6 @@ static int sx9500_buffer_predisable(struct iio_dev *indio_dev) struct sx9500_data *data = iio_priv(indio_dev); int ret = 0, i; - iio_triggered_buffer_predisable(indio_dev); - mutex_lock(&data->mutex); for (i = 0; i < SX9500_NUM_CHANNELS; i++) @@ -722,12 +727,13 @@ static int sx9500_buffer_predisable(struct iio_dev *indio_dev) mutex_unlock(&data->mutex); + iio_triggered_buffer_predisable(indio_dev); + return ret; } static const struct iio_buffer_setup_ops sx9500_buffer_setup_ops = { - .preenable = sx9500_buffer_preenable, - .postenable = iio_triggered_buffer_postenable, + .postenable = sx9500_buffer_postenable, .predisable = sx9500_buffer_predisable, }; diff --git a/drivers/iio/temperature/Kconfig b/drivers/iio/temperature/Kconfig index 737faa0901fe..e1ccb4003015 100644 --- a/drivers/iio/temperature/Kconfig +++ b/drivers/iio/temperature/Kconfig @@ -4,6 +4,17 @@ # menu "Temperature sensors" +config LTC2983 + tristate "Analog Devices Multi-Sensor Digital Temperature Measurement System" + depends on SPI + select REGMAP_SPI + help + Say yes here to build support for the LTC2983 Multi-Sensor + high accuracy digital temperature measurement system. + + To compile this driver as a module, choose M here: the module + will be called ltc2983. + config MAXIM_THERMOCOUPLE tristate "Maxim thermocouple sensors" depends on SPI diff --git a/drivers/iio/temperature/Makefile b/drivers/iio/temperature/Makefile index baca4776ca0d..d6b850b0cf63 100644 --- a/drivers/iio/temperature/Makefile +++ b/drivers/iio/temperature/Makefile @@ -3,6 +3,7 @@ # Makefile for industrial I/O temperature drivers # +obj-$(CONFIG_LTC2983) += ltc2983.o obj-$(CONFIG_HID_SENSOR_TEMP) += hid-sensor-temperature.o obj-$(CONFIG_MAXIM_THERMOCOUPLE) += maxim_thermocouple.o obj-$(CONFIG_MAX31856) += max31856.o diff --git a/drivers/iio/temperature/ltc2983.c b/drivers/iio/temperature/ltc2983.c new file mode 100644 index 000000000000..ddf47023364b --- /dev/null +++ b/drivers/iio/temperature/ltc2983.c @@ -0,0 +1,1557 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Analog Devices LTC2983 Multi-Sensor Digital Temperature Measurement System + * driver + * + * Copyright 2019 Analog Devices Inc. + */ +#include <linux/bitfield.h> +#include <linux/completion.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/iio/iio.h> +#include <linux/interrupt.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/of_gpio.h> +#include <linux/regmap.h> +#include <linux/spi/spi.h> + +/* register map */ +#define LTC2983_STATUS_REG 0x0000 +#define LTC2983_TEMP_RES_START_REG 0x0010 +#define LTC2983_TEMP_RES_END_REG 0x005F +#define LTC2983_GLOBAL_CONFIG_REG 0x00F0 +#define LTC2983_MULT_CHANNEL_START_REG 0x00F4 +#define LTC2983_MULT_CHANNEL_END_REG 0x00F7 +#define LTC2983_MUX_CONFIG_REG 0x00FF +#define LTC2983_CHAN_ASSIGN_START_REG 0x0200 +#define LTC2983_CHAN_ASSIGN_END_REG 0x024F +#define LTC2983_CUST_SENS_TBL_START_REG 0x0250 +#define LTC2983_CUST_SENS_TBL_END_REG 0x03CF + +#define LTC2983_DIFFERENTIAL_CHAN_MIN 2 +#define LTC2983_MAX_CHANNELS_NR 20 +#define LTC2983_MIN_CHANNELS_NR 1 +#define LTC2983_SLEEP 0x97 +#define LTC2983_CUSTOM_STEINHART_SIZE 24 +#define LTC2983_CUSTOM_SENSOR_ENTRY_SZ 6 +#define LTC2983_CUSTOM_STEINHART_ENTRY_SZ 4 + +#define LTC2983_CHAN_START_ADDR(chan) \ + (((chan - 1) * 4) + LTC2983_CHAN_ASSIGN_START_REG) +#define LTC2983_CHAN_RES_ADDR(chan) \ + (((chan - 1) * 4) + LTC2983_TEMP_RES_START_REG) +#define LTC2983_THERMOCOUPLE_DIFF_MASK BIT(3) +#define LTC2983_THERMOCOUPLE_SGL(x) \ + FIELD_PREP(LTC2983_THERMOCOUPLE_DIFF_MASK, x) +#define LTC2983_THERMOCOUPLE_OC_CURR_MASK GENMASK(1, 0) +#define LTC2983_THERMOCOUPLE_OC_CURR(x) \ + FIELD_PREP(LTC2983_THERMOCOUPLE_OC_CURR_MASK, x) +#define LTC2983_THERMOCOUPLE_OC_CHECK_MASK BIT(2) +#define LTC2983_THERMOCOUPLE_OC_CHECK(x) \ + FIELD_PREP(LTC2983_THERMOCOUPLE_OC_CHECK_MASK, x) + +#define LTC2983_THERMISTOR_DIFF_MASK BIT(2) +#define LTC2983_THERMISTOR_SGL(x) \ + FIELD_PREP(LTC2983_THERMISTOR_DIFF_MASK, x) +#define LTC2983_THERMISTOR_R_SHARE_MASK BIT(1) +#define LTC2983_THERMISTOR_R_SHARE(x) \ + FIELD_PREP(LTC2983_THERMISTOR_R_SHARE_MASK, x) +#define LTC2983_THERMISTOR_C_ROTATE_MASK BIT(0) +#define LTC2983_THERMISTOR_C_ROTATE(x) \ + FIELD_PREP(LTC2983_THERMISTOR_C_ROTATE_MASK, x) + +#define LTC2983_DIODE_DIFF_MASK BIT(2) +#define LTC2983_DIODE_SGL(x) \ + FIELD_PREP(LTC2983_DIODE_DIFF_MASK, x) +#define LTC2983_DIODE_3_CONV_CYCLE_MASK BIT(1) +#define LTC2983_DIODE_3_CONV_CYCLE(x) \ + FIELD_PREP(LTC2983_DIODE_3_CONV_CYCLE_MASK, x) +#define LTC2983_DIODE_AVERAGE_ON_MASK BIT(0) +#define LTC2983_DIODE_AVERAGE_ON(x) \ + FIELD_PREP(LTC2983_DIODE_AVERAGE_ON_MASK, x) + +#define LTC2983_RTD_4_WIRE_MASK BIT(3) +#define LTC2983_RTD_ROTATION_MASK BIT(1) +#define LTC2983_RTD_C_ROTATE(x) \ + FIELD_PREP(LTC2983_RTD_ROTATION_MASK, x) +#define LTC2983_RTD_KELVIN_R_SENSE_MASK GENMASK(3, 2) +#define LTC2983_RTD_N_WIRES_MASK GENMASK(3, 2) +#define LTC2983_RTD_N_WIRES(x) \ + FIELD_PREP(LTC2983_RTD_N_WIRES_MASK, x) +#define LTC2983_RTD_R_SHARE_MASK BIT(0) +#define LTC2983_RTD_R_SHARE(x) \ + FIELD_PREP(LTC2983_RTD_R_SHARE_MASK, 1) + +#define LTC2983_COMMON_HARD_FAULT_MASK GENMASK(31, 30) +#define LTC2983_COMMON_SOFT_FAULT_MASK GENMASK(27, 25) + +#define LTC2983_STATUS_START_MASK BIT(7) +#define LTC2983_STATUS_START(x) FIELD_PREP(LTC2983_STATUS_START_MASK, x) + +#define LTC2983_STATUS_CHAN_SEL_MASK GENMASK(4, 0) +#define LTC2983_STATUS_CHAN_SEL(x) \ + FIELD_PREP(LTC2983_STATUS_CHAN_SEL_MASK, x) + +#define LTC2983_TEMP_UNITS_MASK BIT(2) +#define LTC2983_TEMP_UNITS(x) FIELD_PREP(LTC2983_TEMP_UNITS_MASK, x) + +#define LTC2983_NOTCH_FREQ_MASK GENMASK(1, 0) +#define LTC2983_NOTCH_FREQ(x) FIELD_PREP(LTC2983_NOTCH_FREQ_MASK, x) + +#define LTC2983_RES_VALID_MASK BIT(24) +#define LTC2983_DATA_MASK GENMASK(23, 0) +#define LTC2983_DATA_SIGN_BIT 23 + +#define LTC2983_CHAN_TYPE_MASK GENMASK(31, 27) +#define LTC2983_CHAN_TYPE(x) FIELD_PREP(LTC2983_CHAN_TYPE_MASK, x) + +/* cold junction for thermocouples and rsense for rtd's and thermistor's */ +#define LTC2983_CHAN_ASSIGN_MASK GENMASK(26, 22) +#define LTC2983_CHAN_ASSIGN(x) FIELD_PREP(LTC2983_CHAN_ASSIGN_MASK, x) + +#define LTC2983_CUSTOM_LEN_MASK GENMASK(5, 0) +#define LTC2983_CUSTOM_LEN(x) FIELD_PREP(LTC2983_CUSTOM_LEN_MASK, x) + +#define LTC2983_CUSTOM_ADDR_MASK GENMASK(11, 6) +#define LTC2983_CUSTOM_ADDR(x) FIELD_PREP(LTC2983_CUSTOM_ADDR_MASK, x) + +#define LTC2983_THERMOCOUPLE_CFG_MASK GENMASK(21, 18) +#define LTC2983_THERMOCOUPLE_CFG(x) \ + FIELD_PREP(LTC2983_THERMOCOUPLE_CFG_MASK, x) +#define LTC2983_THERMOCOUPLE_HARD_FAULT_MASK GENMASK(31, 29) +#define LTC2983_THERMOCOUPLE_SOFT_FAULT_MASK GENMASK(28, 25) + +#define LTC2983_RTD_CFG_MASK GENMASK(21, 18) +#define LTC2983_RTD_CFG(x) FIELD_PREP(LTC2983_RTD_CFG_MASK, x) +#define LTC2983_RTD_EXC_CURRENT_MASK GENMASK(17, 14) +#define LTC2983_RTD_EXC_CURRENT(x) \ + FIELD_PREP(LTC2983_RTD_EXC_CURRENT_MASK, x) +#define LTC2983_RTD_CURVE_MASK GENMASK(13, 12) +#define LTC2983_RTD_CURVE(x) FIELD_PREP(LTC2983_RTD_CURVE_MASK, x) + +#define LTC2983_THERMISTOR_CFG_MASK GENMASK(21, 19) +#define LTC2983_THERMISTOR_CFG(x) \ + FIELD_PREP(LTC2983_THERMISTOR_CFG_MASK, x) +#define LTC2983_THERMISTOR_EXC_CURRENT_MASK GENMASK(18, 15) +#define LTC2983_THERMISTOR_EXC_CURRENT(x) \ + FIELD_PREP(LTC2983_THERMISTOR_EXC_CURRENT_MASK, x) + +#define LTC2983_DIODE_CFG_MASK GENMASK(26, 24) +#define LTC2983_DIODE_CFG(x) FIELD_PREP(LTC2983_DIODE_CFG_MASK, x) +#define LTC2983_DIODE_EXC_CURRENT_MASK GENMASK(23, 22) +#define LTC2983_DIODE_EXC_CURRENT(x) \ + FIELD_PREP(LTC2983_DIODE_EXC_CURRENT_MASK, x) +#define LTC2983_DIODE_IDEAL_FACTOR_MASK GENMASK(21, 0) +#define LTC2983_DIODE_IDEAL_FACTOR(x) \ + FIELD_PREP(LTC2983_DIODE_IDEAL_FACTOR_MASK, x) + +#define LTC2983_R_SENSE_VAL_MASK GENMASK(26, 0) +#define LTC2983_R_SENSE_VAL(x) FIELD_PREP(LTC2983_R_SENSE_VAL_MASK, x) + +#define LTC2983_ADC_SINGLE_ENDED_MASK BIT(26) +#define LTC2983_ADC_SINGLE_ENDED(x) \ + FIELD_PREP(LTC2983_ADC_SINGLE_ENDED_MASK, x) + +enum { + LTC2983_SENSOR_THERMOCOUPLE = 1, + LTC2983_SENSOR_THERMOCOUPLE_CUSTOM = 9, + LTC2983_SENSOR_RTD = 10, + LTC2983_SENSOR_RTD_CUSTOM = 18, + LTC2983_SENSOR_THERMISTOR = 19, + LTC2983_SENSOR_THERMISTOR_STEINHART = 26, + LTC2983_SENSOR_THERMISTOR_CUSTOM = 27, + LTC2983_SENSOR_DIODE = 28, + LTC2983_SENSOR_SENSE_RESISTOR = 29, + LTC2983_SENSOR_DIRECT_ADC = 30, +}; + +#define to_thermocouple(_sensor) \ + container_of(_sensor, struct ltc2983_thermocouple, sensor) + +#define to_rtd(_sensor) \ + container_of(_sensor, struct ltc2983_rtd, sensor) + +#define to_thermistor(_sensor) \ + container_of(_sensor, struct ltc2983_thermistor, sensor) + +#define to_diode(_sensor) \ + container_of(_sensor, struct ltc2983_diode, sensor) + +#define to_rsense(_sensor) \ + container_of(_sensor, struct ltc2983_rsense, sensor) + +#define to_adc(_sensor) \ + container_of(_sensor, struct ltc2983_adc, sensor) + +struct ltc2983_data { + struct regmap *regmap; + struct spi_device *spi; + struct mutex lock; + struct completion completion; + struct iio_chan_spec *iio_chan; + struct ltc2983_sensor **sensors; + u32 mux_delay_config; + u32 filter_notch_freq; + u16 custom_table_size; + u8 num_channels; + u8 iio_channels; + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + * Holds the converted temperature + */ + __be32 temp ____cacheline_aligned; +}; + +struct ltc2983_sensor { + int (*fault_handler)(const struct ltc2983_data *st, const u32 result); + int (*assign_chan)(struct ltc2983_data *st, + const struct ltc2983_sensor *sensor); + /* specifies the sensor channel */ + u32 chan; + /* sensor type */ + u32 type; +}; + +struct ltc2983_custom_sensor { + /* raw table sensor data */ + u8 *table; + size_t size; + /* address offset */ + s8 offset; + bool is_steinhart; +}; + +struct ltc2983_thermocouple { + struct ltc2983_sensor sensor; + struct ltc2983_custom_sensor *custom; + u32 sensor_config; + u32 cold_junction_chan; +}; + +struct ltc2983_rtd { + struct ltc2983_sensor sensor; + struct ltc2983_custom_sensor *custom; + u32 sensor_config; + u32 r_sense_chan; + u32 excitation_current; + u32 rtd_curve; +}; + +struct ltc2983_thermistor { + struct ltc2983_sensor sensor; + struct ltc2983_custom_sensor *custom; + u32 sensor_config; + u32 r_sense_chan; + u32 excitation_current; +}; + +struct ltc2983_diode { + struct ltc2983_sensor sensor; + u32 sensor_config; + u32 excitation_current; + u32 ideal_factor_value; +}; + +struct ltc2983_rsense { + struct ltc2983_sensor sensor; + u32 r_sense_val; +}; + +struct ltc2983_adc { + struct ltc2983_sensor sensor; + bool single_ended; +}; + +/* + * Convert to Q format numbers. These number's are integers where + * the number of integer and fractional bits are specified. The resolution + * is given by 1/@resolution and tell us the number of fractional bits. For + * instance a resolution of 2^-10 means we have 10 fractional bits. + */ +static u32 __convert_to_raw(const u64 val, const u32 resolution) +{ + u64 __res = val * resolution; + + /* all values are multiplied by 1000000 to remove the fraction */ + do_div(__res, 1000000); + + return __res; +} + +static u32 __convert_to_raw_sign(const u64 val, const u32 resolution) +{ + s64 __res = -(s32)val; + + __res = __convert_to_raw(__res, resolution); + + return (u32)-__res; +} + +static int __ltc2983_fault_handler(const struct ltc2983_data *st, + const u32 result, const u32 hard_mask, + const u32 soft_mask) +{ + const struct device *dev = &st->spi->dev; + + if (result & hard_mask) { + dev_err(dev, "Invalid conversion: Sensor HARD fault\n"); + return -EIO; + } else if (result & soft_mask) { + /* just print a warning */ + dev_warn(dev, "Suspicious conversion: Sensor SOFT fault\n"); + } + + return 0; +} + +static int __ltc2983_chan_assign_common(const struct ltc2983_data *st, + const struct ltc2983_sensor *sensor, + u32 chan_val) +{ + u32 reg = LTC2983_CHAN_START_ADDR(sensor->chan); + __be32 __chan_val; + + chan_val |= LTC2983_CHAN_TYPE(sensor->type); + dev_dbg(&st->spi->dev, "Assign reg:0x%04X, val:0x%08X\n", reg, + chan_val); + __chan_val = cpu_to_be32(chan_val); + return regmap_bulk_write(st->regmap, reg, &__chan_val, + sizeof(__chan_val)); +} + +static int __ltc2983_chan_custom_sensor_assign(struct ltc2983_data *st, + struct ltc2983_custom_sensor *custom, + u32 *chan_val) +{ + u32 reg; + u8 mult = custom->is_steinhart ? LTC2983_CUSTOM_STEINHART_ENTRY_SZ : + LTC2983_CUSTOM_SENSOR_ENTRY_SZ; + const struct device *dev = &st->spi->dev; + /* + * custom->size holds the raw size of the table. However, when + * configuring the sensor channel, we must write the number of + * entries of the table minus 1. For steinhart sensors 0 is written + * since the size is constant! + */ + const u8 len = custom->is_steinhart ? 0 : + (custom->size / LTC2983_CUSTOM_SENSOR_ENTRY_SZ) - 1; + /* + * Check if the offset was assigned already. It should be for steinhart + * sensors. When coming from sleep, it should be assigned for all. + */ + if (custom->offset < 0) { + /* + * This needs to be done again here because, from the moment + * when this test was done (successfully) for this custom + * sensor, a steinhart sensor might have been added changing + * custom_table_size... + */ + if (st->custom_table_size + custom->size > + (LTC2983_CUST_SENS_TBL_END_REG - + LTC2983_CUST_SENS_TBL_START_REG) + 1) { + dev_err(dev, + "Not space left(%d) for new custom sensor(%zu)", + st->custom_table_size, + custom->size); + return -EINVAL; + } + + custom->offset = st->custom_table_size / + LTC2983_CUSTOM_SENSOR_ENTRY_SZ; + st->custom_table_size += custom->size; + } + + reg = (custom->offset * mult) + LTC2983_CUST_SENS_TBL_START_REG; + + *chan_val |= LTC2983_CUSTOM_LEN(len); + *chan_val |= LTC2983_CUSTOM_ADDR(custom->offset); + dev_dbg(dev, "Assign custom sensor, reg:0x%04X, off:%d, sz:%zu", + reg, custom->offset, + custom->size); + /* write custom sensor table */ + return regmap_bulk_write(st->regmap, reg, custom->table, custom->size); +} + +static struct ltc2983_custom_sensor *__ltc2983_custom_sensor_new( + struct ltc2983_data *st, + const struct device_node *np, + const char *propname, + const bool is_steinhart, + const u32 resolution, + const bool has_signed) +{ + struct ltc2983_custom_sensor *new_custom; + u8 index, n_entries, tbl = 0; + struct device *dev = &st->spi->dev; + /* + * For custom steinhart, the full u32 is taken. For all the others + * the MSB is discarded. + */ + const u8 n_size = (is_steinhart == true) ? 4 : 3; + const u8 e_size = (is_steinhart == true) ? sizeof(u32) : sizeof(u64); + + n_entries = of_property_count_elems_of_size(np, propname, e_size); + /* n_entries must be an even number */ + if (!n_entries || (n_entries % 2) != 0) { + dev_err(dev, "Number of entries either 0 or not even\n"); + return ERR_PTR(-EINVAL); + } + + new_custom = devm_kzalloc(dev, sizeof(*new_custom), GFP_KERNEL); + if (!new_custom) + return ERR_PTR(-ENOMEM); + + new_custom->size = n_entries * n_size; + /* check Steinhart size */ + if (is_steinhart && new_custom->size != LTC2983_CUSTOM_STEINHART_SIZE) { + dev_err(dev, "Steinhart sensors size(%zu) must be 24", + new_custom->size); + return ERR_PTR(-EINVAL); + } + /* Check space on the table. */ + if (st->custom_table_size + new_custom->size > + (LTC2983_CUST_SENS_TBL_END_REG - + LTC2983_CUST_SENS_TBL_START_REG) + 1) { + dev_err(dev, "No space left(%d) for new custom sensor(%zu)", + st->custom_table_size, new_custom->size); + return ERR_PTR(-EINVAL); + } + + /* allocate the table */ + new_custom->table = devm_kzalloc(dev, new_custom->size, GFP_KERNEL); + if (!new_custom->table) + return ERR_PTR(-ENOMEM); + + for (index = 0; index < n_entries; index++) { + u64 temp = 0, j; + /* + * Steinhart sensors are configured with raw values in the + * devicetree. For the other sensors we must convert the + * value to raw. The odd index's correspond to temperarures + * and always have 1/1024 of resolution. Temperatures also + * come in kelvin, so signed values is not possible + */ + if (!is_steinhart) { + of_property_read_u64_index(np, propname, index, &temp); + + if ((index % 2) != 0) + temp = __convert_to_raw(temp, 1024); + else if (has_signed && (s64)temp < 0) + temp = __convert_to_raw_sign(temp, resolution); + else + temp = __convert_to_raw(temp, resolution); + } else { + of_property_read_u32_index(np, propname, index, + (u32 *)&temp); + } + + for (j = 0; j < n_size; j++) + new_custom->table[tbl++] = + temp >> (8 * (n_size - j - 1)); + } + + new_custom->is_steinhart = is_steinhart; + /* + * This is done to first add all the steinhart sensors to the table, + * in order to maximize the table usage. If we mix adding steinhart + * with the other sensors, we might have to do some roundup to make + * sure that sensor_addr - 0x250(start address) is a multiple of 4 + * (for steinhart), and a multiple of 6 for all the other sensors. + * Since we have const 24 bytes for steinhart sensors and 24 is + * also a multiple of 6, we guarantee that the first non-steinhart + * sensor will sit in a correct address without the need of filling + * addresses. + */ + if (is_steinhart) { + new_custom->offset = st->custom_table_size / + LTC2983_CUSTOM_STEINHART_ENTRY_SZ; + st->custom_table_size += new_custom->size; + } else { + /* mark as unset. This is checked later on the assign phase */ + new_custom->offset = -1; + } + + return new_custom; +} + +static int ltc2983_thermocouple_fault_handler(const struct ltc2983_data *st, + const u32 result) +{ + return __ltc2983_fault_handler(st, result, + LTC2983_THERMOCOUPLE_HARD_FAULT_MASK, + LTC2983_THERMOCOUPLE_SOFT_FAULT_MASK); +} + +static int ltc2983_common_fault_handler(const struct ltc2983_data *st, + const u32 result) +{ + return __ltc2983_fault_handler(st, result, + LTC2983_COMMON_HARD_FAULT_MASK, + LTC2983_COMMON_SOFT_FAULT_MASK); +} + +static int ltc2983_thermocouple_assign_chan(struct ltc2983_data *st, + const struct ltc2983_sensor *sensor) +{ + struct ltc2983_thermocouple *thermo = to_thermocouple(sensor); + u32 chan_val; + + chan_val = LTC2983_CHAN_ASSIGN(thermo->cold_junction_chan); + chan_val |= LTC2983_THERMOCOUPLE_CFG(thermo->sensor_config); + + if (thermo->custom) { + int ret; + + ret = __ltc2983_chan_custom_sensor_assign(st, thermo->custom, + &chan_val); + if (ret) + return ret; + } + return __ltc2983_chan_assign_common(st, sensor, chan_val); +} + +static int ltc2983_rtd_assign_chan(struct ltc2983_data *st, + const struct ltc2983_sensor *sensor) +{ + struct ltc2983_rtd *rtd = to_rtd(sensor); + u32 chan_val; + + chan_val = LTC2983_CHAN_ASSIGN(rtd->r_sense_chan); + chan_val |= LTC2983_RTD_CFG(rtd->sensor_config); + chan_val |= LTC2983_RTD_EXC_CURRENT(rtd->excitation_current); + chan_val |= LTC2983_RTD_CURVE(rtd->rtd_curve); + + if (rtd->custom) { + int ret; + + ret = __ltc2983_chan_custom_sensor_assign(st, rtd->custom, + &chan_val); + if (ret) + return ret; + } + return __ltc2983_chan_assign_common(st, sensor, chan_val); +} + +static int ltc2983_thermistor_assign_chan(struct ltc2983_data *st, + const struct ltc2983_sensor *sensor) +{ + struct ltc2983_thermistor *thermistor = to_thermistor(sensor); + u32 chan_val; + + chan_val = LTC2983_CHAN_ASSIGN(thermistor->r_sense_chan); + chan_val |= LTC2983_THERMISTOR_CFG(thermistor->sensor_config); + chan_val |= + LTC2983_THERMISTOR_EXC_CURRENT(thermistor->excitation_current); + + if (thermistor->custom) { + int ret; + + ret = __ltc2983_chan_custom_sensor_assign(st, + thermistor->custom, + &chan_val); + if (ret) + return ret; + } + return __ltc2983_chan_assign_common(st, sensor, chan_val); +} + +static int ltc2983_diode_assign_chan(struct ltc2983_data *st, + const struct ltc2983_sensor *sensor) +{ + struct ltc2983_diode *diode = to_diode(sensor); + u32 chan_val; + + chan_val = LTC2983_DIODE_CFG(diode->sensor_config); + chan_val |= LTC2983_DIODE_EXC_CURRENT(diode->excitation_current); + chan_val |= LTC2983_DIODE_IDEAL_FACTOR(diode->ideal_factor_value); + + return __ltc2983_chan_assign_common(st, sensor, chan_val); +} + +static int ltc2983_r_sense_assign_chan(struct ltc2983_data *st, + const struct ltc2983_sensor *sensor) +{ + struct ltc2983_rsense *rsense = to_rsense(sensor); + u32 chan_val; + + chan_val = LTC2983_R_SENSE_VAL(rsense->r_sense_val); + + return __ltc2983_chan_assign_common(st, sensor, chan_val); +} + +static int ltc2983_adc_assign_chan(struct ltc2983_data *st, + const struct ltc2983_sensor *sensor) +{ + struct ltc2983_adc *adc = to_adc(sensor); + u32 chan_val; + + chan_val = LTC2983_ADC_SINGLE_ENDED(adc->single_ended); + + return __ltc2983_chan_assign_common(st, sensor, chan_val); +} + +static struct ltc2983_sensor *ltc2983_thermocouple_new( + const struct device_node *child, + struct ltc2983_data *st, + const struct ltc2983_sensor *sensor) +{ + struct ltc2983_thermocouple *thermo; + struct device_node *phandle; + u32 oc_current; + int ret; + + thermo = devm_kzalloc(&st->spi->dev, sizeof(*thermo), GFP_KERNEL); + if (!thermo) + return ERR_PTR(-ENOMEM); + + if (of_property_read_bool(child, "adi,single-ended")) + thermo->sensor_config = LTC2983_THERMOCOUPLE_SGL(1); + + ret = of_property_read_u32(child, "adi,sensor-oc-current-microamp", + &oc_current); + if (!ret) { + switch (oc_current) { + case 10: + thermo->sensor_config |= + LTC2983_THERMOCOUPLE_OC_CURR(0); + break; + case 100: + thermo->sensor_config |= + LTC2983_THERMOCOUPLE_OC_CURR(1); + break; + case 500: + thermo->sensor_config |= + LTC2983_THERMOCOUPLE_OC_CURR(2); + break; + case 1000: + thermo->sensor_config |= + LTC2983_THERMOCOUPLE_OC_CURR(3); + break; + default: + dev_err(&st->spi->dev, + "Invalid open circuit current:%u", oc_current); + return ERR_PTR(-EINVAL); + } + + thermo->sensor_config |= LTC2983_THERMOCOUPLE_OC_CHECK(1); + } + /* validate channel index */ + if (!(thermo->sensor_config & LTC2983_THERMOCOUPLE_DIFF_MASK) && + sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) { + dev_err(&st->spi->dev, + "Invalid chann:%d for differential thermocouple", + sensor->chan); + return ERR_PTR(-EINVAL); + } + + phandle = of_parse_phandle(child, "adi,cold-junction-handle", 0); + if (phandle) { + int ret; + + ret = of_property_read_u32(phandle, "reg", + &thermo->cold_junction_chan); + if (ret) { + /* + * This would be catched later but we can just return + * the error right away. + */ + dev_err(&st->spi->dev, "Property reg must be given\n"); + of_node_put(phandle); + return ERR_PTR(-EINVAL); + } + } + + /* check custom sensor */ + if (sensor->type == LTC2983_SENSOR_THERMOCOUPLE_CUSTOM) { + const char *propname = "adi,custom-thermocouple"; + + thermo->custom = __ltc2983_custom_sensor_new(st, child, + propname, false, + 16384, true); + if (IS_ERR(thermo->custom)) { + of_node_put(phandle); + return ERR_CAST(thermo->custom); + } + } + + /* set common parameters */ + thermo->sensor.fault_handler = ltc2983_thermocouple_fault_handler; + thermo->sensor.assign_chan = ltc2983_thermocouple_assign_chan; + + of_node_put(phandle); + return &thermo->sensor; +} + +static struct ltc2983_sensor *ltc2983_rtd_new(const struct device_node *child, + struct ltc2983_data *st, + const struct ltc2983_sensor *sensor) +{ + struct ltc2983_rtd *rtd; + int ret = 0; + struct device *dev = &st->spi->dev; + struct device_node *phandle; + u32 excitation_current = 0, n_wires = 0; + + rtd = devm_kzalloc(dev, sizeof(*rtd), GFP_KERNEL); + if (!rtd) + return ERR_PTR(-ENOMEM); + + phandle = of_parse_phandle(child, "adi,rsense-handle", 0); + if (!phandle) { + dev_err(dev, "Property adi,rsense-handle missing or invalid"); + return ERR_PTR(-EINVAL); + } + + ret = of_property_read_u32(phandle, "reg", &rtd->r_sense_chan); + if (ret) { + dev_err(dev, "Property reg must be given\n"); + goto fail; + } + + ret = of_property_read_u32(child, "adi,number-of-wires", &n_wires); + if (!ret) { + switch (n_wires) { + case 2: + rtd->sensor_config = LTC2983_RTD_N_WIRES(0); + break; + case 3: + rtd->sensor_config = LTC2983_RTD_N_WIRES(1); + break; + case 4: + rtd->sensor_config = LTC2983_RTD_N_WIRES(2); + break; + case 5: + /* 4 wires, Kelvin Rsense */ + rtd->sensor_config = LTC2983_RTD_N_WIRES(3); + break; + default: + dev_err(dev, "Invalid number of wires:%u\n", n_wires); + ret = -EINVAL; + goto fail; + } + } + + if (of_property_read_bool(child, "adi,rsense-share")) { + /* Current rotation is only available with rsense sharing */ + if (of_property_read_bool(child, "adi,current-rotate")) { + if (n_wires == 2 || n_wires == 3) { + dev_err(dev, + "Rotation not allowed for 2/3 Wire RTDs"); + ret = -EINVAL; + goto fail; + } + rtd->sensor_config |= LTC2983_RTD_C_ROTATE(1); + } else { + rtd->sensor_config |= LTC2983_RTD_R_SHARE(1); + } + } + /* + * rtd channel indexes are a bit more complicated to validate. + * For 4wire RTD with rotation, the channel selection cannot be + * >=19 since the chann + 1 is used in this configuration. + * For 4wire RTDs with kelvin rsense, the rsense channel cannot be + * <=1 since chanel - 1 and channel - 2 are used. + */ + if (rtd->sensor_config & LTC2983_RTD_4_WIRE_MASK) { + /* 4-wire */ + u8 min = LTC2983_DIFFERENTIAL_CHAN_MIN, + max = LTC2983_MAX_CHANNELS_NR; + + if (rtd->sensor_config & LTC2983_RTD_ROTATION_MASK) + max = LTC2983_MAX_CHANNELS_NR - 1; + + if (((rtd->sensor_config & LTC2983_RTD_KELVIN_R_SENSE_MASK) + == LTC2983_RTD_KELVIN_R_SENSE_MASK) && + (rtd->r_sense_chan <= min)) { + /* kelvin rsense*/ + dev_err(dev, + "Invalid rsense chann:%d to use in kelvin rsense", + rtd->r_sense_chan); + + ret = -EINVAL; + goto fail; + } + + if (sensor->chan < min || sensor->chan > max) { + dev_err(dev, "Invalid chann:%d for the rtd config", + sensor->chan); + + ret = -EINVAL; + goto fail; + } + } else { + /* same as differential case */ + if (sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) { + dev_err(&st->spi->dev, + "Invalid chann:%d for RTD", sensor->chan); + + ret = -EINVAL; + goto fail; + } + } + + /* check custom sensor */ + if (sensor->type == LTC2983_SENSOR_RTD_CUSTOM) { + rtd->custom = __ltc2983_custom_sensor_new(st, child, + "adi,custom-rtd", + false, 2048, false); + if (IS_ERR(rtd->custom)) { + of_node_put(phandle); + return ERR_CAST(rtd->custom); + } + } + + /* set common parameters */ + rtd->sensor.fault_handler = ltc2983_common_fault_handler; + rtd->sensor.assign_chan = ltc2983_rtd_assign_chan; + + ret = of_property_read_u32(child, "adi,excitation-current-microamp", + &excitation_current); + if (ret) { + /* default to 5uA */ + rtd->excitation_current = 1; + } else { + switch (excitation_current) { + case 5: + rtd->excitation_current = 0x01; + break; + case 10: + rtd->excitation_current = 0x02; + break; + case 25: + rtd->excitation_current = 0x03; + break; + case 50: + rtd->excitation_current = 0x04; + break; + case 100: + rtd->excitation_current = 0x05; + break; + case 250: + rtd->excitation_current = 0x06; + break; + case 500: + rtd->excitation_current = 0x07; + break; + case 1000: + rtd->excitation_current = 0x08; + break; + default: + dev_err(&st->spi->dev, + "Invalid value for excitation current(%u)", + excitation_current); + ret = -EINVAL; + goto fail; + } + } + + of_property_read_u32(child, "adi,rtd-curve", &rtd->rtd_curve); + + of_node_put(phandle); + return &rtd->sensor; +fail: + of_node_put(phandle); + return ERR_PTR(ret); +} + +static struct ltc2983_sensor *ltc2983_thermistor_new( + const struct device_node *child, + struct ltc2983_data *st, + const struct ltc2983_sensor *sensor) +{ + struct ltc2983_thermistor *thermistor; + struct device *dev = &st->spi->dev; + struct device_node *phandle; + u32 excitation_current = 0; + int ret = 0; + + thermistor = devm_kzalloc(dev, sizeof(*thermistor), GFP_KERNEL); + if (!thermistor) + return ERR_PTR(-ENOMEM); + + phandle = of_parse_phandle(child, "adi,rsense-handle", 0); + if (!phandle) { + dev_err(dev, "Property adi,rsense-handle missing or invalid"); + return ERR_PTR(-EINVAL); + } + + ret = of_property_read_u32(phandle, "reg", &thermistor->r_sense_chan); + if (ret) { + dev_err(dev, "rsense channel must be configured...\n"); + goto fail; + } + + if (of_property_read_bool(child, "adi,single-ended")) { + thermistor->sensor_config = LTC2983_THERMISTOR_SGL(1); + } else if (of_property_read_bool(child, "adi,rsense-share")) { + /* rotation is only possible if sharing rsense */ + if (of_property_read_bool(child, "adi,current-rotate")) + thermistor->sensor_config = + LTC2983_THERMISTOR_C_ROTATE(1); + else + thermistor->sensor_config = + LTC2983_THERMISTOR_R_SHARE(1); + } + /* validate channel index */ + if (!(thermistor->sensor_config & LTC2983_THERMISTOR_DIFF_MASK) && + sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) { + dev_err(&st->spi->dev, + "Invalid chann:%d for differential thermistor", + sensor->chan); + ret = -EINVAL; + goto fail; + } + + /* check custom sensor */ + if (sensor->type >= LTC2983_SENSOR_THERMISTOR_STEINHART) { + bool steinhart = false; + const char *propname; + + if (sensor->type == LTC2983_SENSOR_THERMISTOR_STEINHART) { + steinhart = true; + propname = "adi,custom-steinhart"; + } else { + propname = "adi,custom-thermistor"; + } + + thermistor->custom = __ltc2983_custom_sensor_new(st, child, + propname, + steinhart, + 64, false); + if (IS_ERR(thermistor->custom)) { + of_node_put(phandle); + return ERR_CAST(thermistor->custom); + } + } + /* set common parameters */ + thermistor->sensor.fault_handler = ltc2983_common_fault_handler; + thermistor->sensor.assign_chan = ltc2983_thermistor_assign_chan; + + ret = of_property_read_u32(child, "adi,excitation-current-nanoamp", + &excitation_current); + if (ret) { + /* Auto range is not allowed for custom sensors */ + if (sensor->type >= LTC2983_SENSOR_THERMISTOR_STEINHART) + /* default to 1uA */ + thermistor->excitation_current = 0x03; + else + /* default to auto-range */ + thermistor->excitation_current = 0x0c; + } else { + switch (excitation_current) { + case 0: + /* auto range */ + if (sensor->type >= + LTC2983_SENSOR_THERMISTOR_STEINHART) { + dev_err(&st->spi->dev, + "Auto Range not allowed for custom sensors\n"); + ret = -EINVAL; + goto fail; + } + thermistor->excitation_current = 0x0c; + break; + case 250: + thermistor->excitation_current = 0x01; + break; + case 500: + thermistor->excitation_current = 0x02; + break; + case 1000: + thermistor->excitation_current = 0x03; + break; + case 5000: + thermistor->excitation_current = 0x04; + break; + case 10000: + thermistor->excitation_current = 0x05; + break; + case 25000: + thermistor->excitation_current = 0x06; + break; + case 50000: + thermistor->excitation_current = 0x07; + break; + case 100000: + thermistor->excitation_current = 0x08; + break; + case 250000: + thermistor->excitation_current = 0x09; + break; + case 500000: + thermistor->excitation_current = 0x0a; + break; + case 1000000: + thermistor->excitation_current = 0x0b; + break; + default: + dev_err(&st->spi->dev, + "Invalid value for excitation current(%u)", + excitation_current); + ret = -EINVAL; + goto fail; + } + } + + of_node_put(phandle); + return &thermistor->sensor; +fail: + of_node_put(phandle); + return ERR_PTR(ret); +} + +static struct ltc2983_sensor *ltc2983_diode_new( + const struct device_node *child, + const struct ltc2983_data *st, + const struct ltc2983_sensor *sensor) +{ + struct ltc2983_diode *diode; + u32 temp = 0, excitation_current = 0; + int ret; + + diode = devm_kzalloc(&st->spi->dev, sizeof(*diode), GFP_KERNEL); + if (!diode) + return ERR_PTR(-ENOMEM); + + if (of_property_read_bool(child, "adi,single-ended")) + diode->sensor_config = LTC2983_DIODE_SGL(1); + + if (of_property_read_bool(child, "adi,three-conversion-cycles")) + diode->sensor_config |= LTC2983_DIODE_3_CONV_CYCLE(1); + + if (of_property_read_bool(child, "adi,average-on")) + diode->sensor_config |= LTC2983_DIODE_AVERAGE_ON(1); + + /* validate channel index */ + if (!(diode->sensor_config & LTC2983_DIODE_DIFF_MASK) && + sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) { + dev_err(&st->spi->dev, + "Invalid chann:%d for differential thermistor", + sensor->chan); + return ERR_PTR(-EINVAL); + } + /* set common parameters */ + diode->sensor.fault_handler = ltc2983_common_fault_handler; + diode->sensor.assign_chan = ltc2983_diode_assign_chan; + + ret = of_property_read_u32(child, "adi,excitation-current-microamp", + &excitation_current); + if (!ret) { + switch (excitation_current) { + case 10: + diode->excitation_current = 0x00; + break; + case 20: + diode->excitation_current = 0x01; + break; + case 40: + diode->excitation_current = 0x02; + break; + case 80: + diode->excitation_current = 0x03; + break; + default: + dev_err(&st->spi->dev, + "Invalid value for excitation current(%u)", + excitation_current); + return ERR_PTR(-EINVAL); + } + } + + of_property_read_u32(child, "adi,ideal-factor-value", &temp); + + /* 2^20 resolution */ + diode->ideal_factor_value = __convert_to_raw(temp, 1048576); + + return &diode->sensor; +} + +static struct ltc2983_sensor *ltc2983_r_sense_new(struct device_node *child, + struct ltc2983_data *st, + const struct ltc2983_sensor *sensor) +{ + struct ltc2983_rsense *rsense; + int ret; + u32 temp; + + rsense = devm_kzalloc(&st->spi->dev, sizeof(*rsense), GFP_KERNEL); + if (!rsense) + return ERR_PTR(-ENOMEM); + + /* validate channel index */ + if (sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) { + dev_err(&st->spi->dev, "Invalid chann:%d for r_sense", + sensor->chan); + return ERR_PTR(-EINVAL); + } + + ret = of_property_read_u32(child, "adi,rsense-val-milli-ohms", &temp); + if (ret) { + dev_err(&st->spi->dev, "Property adi,rsense-val-milli-ohms missing\n"); + return ERR_PTR(-EINVAL); + } + /* + * Times 1000 because we have milli-ohms and __convert_to_raw + * expects scales of 1000000 which are used for all other + * properties. + * 2^10 resolution + */ + rsense->r_sense_val = __convert_to_raw((u64)temp * 1000, 1024); + + /* set common parameters */ + rsense->sensor.assign_chan = ltc2983_r_sense_assign_chan; + + return &rsense->sensor; +} + +static struct ltc2983_sensor *ltc2983_adc_new(struct device_node *child, + struct ltc2983_data *st, + const struct ltc2983_sensor *sensor) +{ + struct ltc2983_adc *adc; + + adc = devm_kzalloc(&st->spi->dev, sizeof(*adc), GFP_KERNEL); + if (!adc) + return ERR_PTR(-ENOMEM); + + if (of_property_read_bool(child, "adi,single-ended")) + adc->single_ended = true; + + if (!adc->single_ended && + sensor->chan < LTC2983_DIFFERENTIAL_CHAN_MIN) { + dev_err(&st->spi->dev, "Invalid chan:%d for differential adc\n", + sensor->chan); + return ERR_PTR(-EINVAL); + } + /* set common parameters */ + adc->sensor.assign_chan = ltc2983_adc_assign_chan; + adc->sensor.fault_handler = ltc2983_common_fault_handler; + + return &adc->sensor; +} + +static int ltc2983_chan_read(struct ltc2983_data *st, + const struct ltc2983_sensor *sensor, int *val) +{ + u32 start_conversion = 0; + int ret; + unsigned long time; + + start_conversion = LTC2983_STATUS_START(true); + start_conversion |= LTC2983_STATUS_CHAN_SEL(sensor->chan); + dev_dbg(&st->spi->dev, "Start conversion on chan:%d, status:%02X\n", + sensor->chan, start_conversion); + /* start conversion */ + ret = regmap_write(st->regmap, LTC2983_STATUS_REG, start_conversion); + if (ret) + return ret; + + reinit_completion(&st->completion); + /* + * wait for conversion to complete. + * 300 ms should be more than enough to complete the conversion. + * Depending on the sensor configuration, there are 2/3 conversions + * cycles of 82ms. + */ + time = wait_for_completion_timeout(&st->completion, + msecs_to_jiffies(300)); + if (!time) { + dev_warn(&st->spi->dev, "Conversion timed out\n"); + return -ETIMEDOUT; + } + + /* read the converted data */ + ret = regmap_bulk_read(st->regmap, LTC2983_CHAN_RES_ADDR(sensor->chan), + &st->temp, sizeof(st->temp)); + if (ret) + return ret; + + *val = __be32_to_cpu(st->temp); + + if (!(LTC2983_RES_VALID_MASK & *val)) { + dev_err(&st->spi->dev, "Invalid conversion detected\n"); + return -EIO; + } + + ret = sensor->fault_handler(st, *val); + if (ret) + return ret; + + *val = sign_extend32((*val) & LTC2983_DATA_MASK, LTC2983_DATA_SIGN_BIT); + return 0; +} + +static int ltc2983_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct ltc2983_data *st = iio_priv(indio_dev); + int ret; + + /* sanity check */ + if (chan->address >= st->num_channels) { + dev_err(&st->spi->dev, "Invalid chan address:%ld", + chan->address); + return -EINVAL; + } + + switch (mask) { + case IIO_CHAN_INFO_RAW: + mutex_lock(&st->lock); + ret = ltc2983_chan_read(st, st->sensors[chan->address], val); + mutex_unlock(&st->lock); + return ret ?: IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_TEMP: + /* value in milli degrees */ + *val = 1000; + /* 2^10 */ + *val2 = 1024; + return IIO_VAL_FRACTIONAL; + case IIO_VOLTAGE: + /* value in millivolt */ + *val = 1000; + /* 2^21 */ + *val2 = 2097152; + return IIO_VAL_FRACTIONAL; + default: + return -EINVAL; + } + } + + return -EINVAL; +} + +static int ltc2983_reg_access(struct iio_dev *indio_dev, + unsigned int reg, + unsigned int writeval, + unsigned int *readval) +{ + struct ltc2983_data *st = iio_priv(indio_dev); + + if (readval) + return regmap_read(st->regmap, reg, readval); + else + return regmap_write(st->regmap, reg, writeval); +} + +static irqreturn_t ltc2983_irq_handler(int irq, void *data) +{ + struct ltc2983_data *st = data; + + complete(&st->completion); + return IRQ_HANDLED; +} + +#define LTC2983_CHAN(__type, index, __address) ({ \ + struct iio_chan_spec __chan = { \ + .type = __type, \ + .indexed = 1, \ + .channel = index, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .address = __address, \ + }; \ + __chan; \ +}) + +static int ltc2983_parse_dt(struct ltc2983_data *st) +{ + struct device_node *child; + struct device *dev = &st->spi->dev; + int ret = 0, chan = 0, channel_avail_mask = 0; + + of_property_read_u32(dev->of_node, "adi,mux-delay-config-us", + &st->mux_delay_config); + + of_property_read_u32(dev->of_node, "adi,filter-notch-freq", + &st->filter_notch_freq); + + st->num_channels = of_get_available_child_count(dev->of_node); + st->sensors = devm_kcalloc(dev, st->num_channels, sizeof(*st->sensors), + GFP_KERNEL); + if (!st->sensors) + return -ENOMEM; + + st->iio_channels = st->num_channels; + for_each_available_child_of_node(dev->of_node, child) { + struct ltc2983_sensor sensor; + + ret = of_property_read_u32(child, "reg", &sensor.chan); + if (ret) { + dev_err(dev, "reg property must given for child nodes\n"); + return ret; + } + + /* check if we have a valid channel */ + if (sensor.chan < LTC2983_MIN_CHANNELS_NR || + sensor.chan > LTC2983_MAX_CHANNELS_NR) { + dev_err(dev, + "chan:%d must be from 1 to 20\n", sensor.chan); + return -EINVAL; + } else if (channel_avail_mask & BIT(sensor.chan)) { + dev_err(dev, "chan:%d already in use\n", sensor.chan); + return -EINVAL; + } + + ret = of_property_read_u32(child, "adi,sensor-type", + &sensor.type); + if (ret) { + dev_err(dev, + "adi,sensor-type property must given for child nodes\n"); + return ret; + } + + dev_dbg(dev, "Create new sensor, type %u, chann %u", + sensor.type, + sensor.chan); + + if (sensor.type >= LTC2983_SENSOR_THERMOCOUPLE && + sensor.type <= LTC2983_SENSOR_THERMOCOUPLE_CUSTOM) { + st->sensors[chan] = ltc2983_thermocouple_new(child, st, + &sensor); + } else if (sensor.type >= LTC2983_SENSOR_RTD && + sensor.type <= LTC2983_SENSOR_RTD_CUSTOM) { + st->sensors[chan] = ltc2983_rtd_new(child, st, &sensor); + } else if (sensor.type >= LTC2983_SENSOR_THERMISTOR && + sensor.type <= LTC2983_SENSOR_THERMISTOR_CUSTOM) { + st->sensors[chan] = ltc2983_thermistor_new(child, st, + &sensor); + } else if (sensor.type == LTC2983_SENSOR_DIODE) { + st->sensors[chan] = ltc2983_diode_new(child, st, + &sensor); + } else if (sensor.type == LTC2983_SENSOR_SENSE_RESISTOR) { + st->sensors[chan] = ltc2983_r_sense_new(child, st, + &sensor); + /* don't add rsense to iio */ + st->iio_channels--; + } else if (sensor.type == LTC2983_SENSOR_DIRECT_ADC) { + st->sensors[chan] = ltc2983_adc_new(child, st, &sensor); + } else { + dev_err(dev, "Unknown sensor type %d\n", sensor.type); + return -EINVAL; + } + + if (IS_ERR(st->sensors[chan])) { + dev_err(dev, "Failed to create sensor %ld", + PTR_ERR(st->sensors[chan])); + return PTR_ERR(st->sensors[chan]); + } + /* set generic sensor parameters */ + st->sensors[chan]->chan = sensor.chan; + st->sensors[chan]->type = sensor.type; + + channel_avail_mask |= BIT(sensor.chan); + chan++; + } + + return 0; +} + +static int ltc2983_setup(struct ltc2983_data *st, bool assign_iio) +{ + u32 iio_chan_t = 0, iio_chan_v = 0, chan, iio_idx = 0; + int ret; + unsigned long time; + + /* make sure the device is up */ + time = wait_for_completion_timeout(&st->completion, + msecs_to_jiffies(250)); + + if (!time) { + dev_err(&st->spi->dev, "Device startup timed out\n"); + return -ETIMEDOUT; + } + + st->iio_chan = devm_kzalloc(&st->spi->dev, + st->iio_channels * sizeof(*st->iio_chan), + GFP_KERNEL); + + if (!st->iio_chan) + return -ENOMEM; + + ret = regmap_update_bits(st->regmap, LTC2983_GLOBAL_CONFIG_REG, + LTC2983_NOTCH_FREQ_MASK, + LTC2983_NOTCH_FREQ(st->filter_notch_freq)); + if (ret) + return ret; + + ret = regmap_write(st->regmap, LTC2983_MUX_CONFIG_REG, + st->mux_delay_config); + if (ret) + return ret; + + for (chan = 0; chan < st->num_channels; chan++) { + u32 chan_type = 0, *iio_chan; + + ret = st->sensors[chan]->assign_chan(st, st->sensors[chan]); + if (ret) + return ret; + /* + * The assign_iio flag is necessary for when the device is + * coming out of sleep. In that case, we just need to + * re-configure the device channels. + * We also don't assign iio channels for rsense. + */ + if (st->sensors[chan]->type == LTC2983_SENSOR_SENSE_RESISTOR || + !assign_iio) + continue; + + /* assign iio channel */ + if (st->sensors[chan]->type != LTC2983_SENSOR_DIRECT_ADC) { + chan_type = IIO_TEMP; + iio_chan = &iio_chan_t; + } else { + chan_type = IIO_VOLTAGE; + iio_chan = &iio_chan_v; + } + + /* + * add chan as the iio .address so that, we can directly + * reference the sensor given the iio_chan_spec + */ + st->iio_chan[iio_idx++] = LTC2983_CHAN(chan_type, (*iio_chan)++, + chan); + } + + return 0; +} + +static const struct regmap_range ltc2983_reg_ranges[] = { + regmap_reg_range(LTC2983_STATUS_REG, LTC2983_STATUS_REG), + regmap_reg_range(LTC2983_TEMP_RES_START_REG, LTC2983_TEMP_RES_END_REG), + regmap_reg_range(LTC2983_GLOBAL_CONFIG_REG, LTC2983_GLOBAL_CONFIG_REG), + regmap_reg_range(LTC2983_MULT_CHANNEL_START_REG, + LTC2983_MULT_CHANNEL_END_REG), + regmap_reg_range(LTC2983_MUX_CONFIG_REG, LTC2983_MUX_CONFIG_REG), + regmap_reg_range(LTC2983_CHAN_ASSIGN_START_REG, + LTC2983_CHAN_ASSIGN_END_REG), + regmap_reg_range(LTC2983_CUST_SENS_TBL_START_REG, + LTC2983_CUST_SENS_TBL_END_REG), +}; + +static const struct regmap_access_table ltc2983_reg_table = { + .yes_ranges = ltc2983_reg_ranges, + .n_yes_ranges = ARRAY_SIZE(ltc2983_reg_ranges), +}; + +/* + * The reg_bits are actually 12 but the device needs the first *complete* + * byte for the command (R/W). + */ +static const struct regmap_config ltc2983_regmap_config = { + .reg_bits = 24, + .val_bits = 8, + .wr_table = <c2983_reg_table, + .rd_table = <c2983_reg_table, + .read_flag_mask = GENMASK(1, 0), + .write_flag_mask = BIT(1), +}; + +static const struct iio_info ltc2983_iio_info = { + .read_raw = ltc2983_read_raw, + .debugfs_reg_access = ltc2983_reg_access, +}; + +static int ltc2983_probe(struct spi_device *spi) +{ + struct ltc2983_data *st; + struct iio_dev *indio_dev; + const char *name = spi_get_device_id(spi)->name; + int ret; + + indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + + st->regmap = devm_regmap_init_spi(spi, <c2983_regmap_config); + if (IS_ERR(st->regmap)) { + dev_err(&spi->dev, "Failed to initialize regmap\n"); + return PTR_ERR(st->regmap); + } + + mutex_init(&st->lock); + init_completion(&st->completion); + st->spi = spi; + spi_set_drvdata(spi, st); + + ret = ltc2983_parse_dt(st); + if (ret) + return ret; + /* + * let's request the irq now so it is used to sync the device + * startup in ltc2983_setup() + */ + ret = devm_request_irq(&spi->dev, spi->irq, ltc2983_irq_handler, + IRQF_TRIGGER_RISING, name, st); + if (ret) { + dev_err(&spi->dev, "failed to request an irq, %d", ret); + return ret; + } + + ret = ltc2983_setup(st, true); + if (ret) + return ret; + + indio_dev->dev.parent = &spi->dev; + indio_dev->name = name; + indio_dev->num_channels = st->iio_channels; + indio_dev->channels = st->iio_chan; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = <c2983_iio_info; + + return devm_iio_device_register(&spi->dev, indio_dev); +} + +static int __maybe_unused ltc2983_resume(struct device *dev) +{ + struct ltc2983_data *st = spi_get_drvdata(to_spi_device(dev)); + int dummy; + + /* dummy read to bring the device out of sleep */ + regmap_read(st->regmap, LTC2983_STATUS_REG, &dummy); + /* we need to re-assign the channels */ + return ltc2983_setup(st, false); +} + +static int __maybe_unused ltc2983_suspend(struct device *dev) +{ + struct ltc2983_data *st = spi_get_drvdata(to_spi_device(dev)); + + return regmap_write(st->regmap, LTC2983_STATUS_REG, LTC2983_SLEEP); +} + +static SIMPLE_DEV_PM_OPS(ltc2983_pm_ops, ltc2983_suspend, ltc2983_resume); + +static const struct spi_device_id ltc2983_id_table[] = { + { "ltc2983" }, + {}, +}; +MODULE_DEVICE_TABLE(spi, ltc2983_id_table); + +static const struct of_device_id ltc2983_of_match[] = { + { .compatible = "adi,ltc2983" }, + {}, +}; +MODULE_DEVICE_TABLE(of, ltc2983_of_match); + +static struct spi_driver ltc2983_driver = { + .driver = { + .name = "ltc2983", + .of_match_table = ltc2983_of_match, + .pm = <c2983_pm_ops, + }, + .probe = ltc2983_probe, + .id_table = ltc2983_id_table, +}; + +module_spi_driver(ltc2983_driver); + +MODULE_AUTHOR("Nuno Sa <nuno.sa@analog.com>"); +MODULE_DESCRIPTION("Analog Devices LTC2983 SPI Temperature sensors"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/temperature/max31856.c b/drivers/iio/temperature/max31856.c index f184ba5601d9..73ed550e3fc9 100644 --- a/drivers/iio/temperature/max31856.c +++ b/drivers/iio/temperature/max31856.c @@ -284,6 +284,8 @@ static int max31856_probe(struct spi_device *spi) spi_set_drvdata(spi, indio_dev); indio_dev->info = &max31856_info; + indio_dev->dev.parent = &spi->dev; + indio_dev->dev.of_node = spi->dev.of_node; indio_dev->name = id->name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = max31856_channels; diff --git a/drivers/iio/temperature/maxim_thermocouple.c b/drivers/iio/temperature/maxim_thermocouple.c index 2ab68282d0b6..d1360605209c 100644 --- a/drivers/iio/temperature/maxim_thermocouple.c +++ b/drivers/iio/temperature/maxim_thermocouple.c @@ -194,7 +194,7 @@ static int maxim_thermocouple_read_raw(struct iio_dev *indio_dev, default: *val = 250; /* 1000 * 0.25 */ ret = IIO_VAL_INT; - }; + } break; } diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index ae24d3ea68ea..420900852166 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -1210,13 +1210,6 @@ config AB8500_DEBUG Select this option if you want debug information using the debug filesystem, debugfs. -config AB8500_GPADC - bool "ST-Ericsson AB8500 GPADC driver" - depends on AB8500_CORE && REGULATOR_AB8500 - default y - help - AB8500 GPADC driver used to convert Acc and battery/ac/usb voltage - config MFD_DB8500_PRCMU bool "ST-Ericsson DB8500 Power Reset Control Management Unit" depends on UX500_SOC_DB8500 diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index c1067ea46204..aed99f08739f 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -177,7 +177,6 @@ obj-$(CONFIG_ABX500_CORE) += abx500-core.o obj-$(CONFIG_AB3100_CORE) += ab3100-core.o obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o -obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o # ab8500-core need to come after db8500-prcmu (which provides the channel) obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c index f4e26b6e5362..1a9a3414d4fa 100644 --- a/drivers/mfd/ab8500-debugfs.c +++ b/drivers/mfd/ab8500-debugfs.c @@ -84,7 +84,6 @@ #include <linux/mfd/abx500.h> #include <linux/mfd/abx500/ab8500.h> -#include <linux/mfd/abx500/ab8500-gpadc.h> #ifdef CONFIG_DEBUG_FS #include <linux/string.h> @@ -103,11 +102,6 @@ static int num_irqs; static struct device_attribute **dev_attr; static char **event_name; -static u8 avg_sample = SAMPLE_16; -static u8 trig_edge = RISING_EDGE; -static u8 conv_type = ADC_SW; -static u8 trig_timer; - /** * struct ab8500_reg_range * @first: the first address of the range @@ -152,7 +146,6 @@ static struct hwreg_cfg hwreg_cfg = { }; #define AB8500_NAME_STRING "ab8500" -#define AB8500_ADC_NAME_STRING "gpadc" #define AB8500_NUM_BANKS AB8500_DEBUG_FIELD_LAST #define AB8500_REV_REG 0x80 @@ -1646,633 +1639,6 @@ report_write_failure: DEFINE_SHOW_ATTRIBUTE(ab8500_modem); -static int ab8500_gpadc_bat_ctrl_show(struct seq_file *s, void *p) -{ - int bat_ctrl_raw; - int bat_ctrl_convert; - struct ab8500_gpadc *gpadc; - - gpadc = ab8500_gpadc_get("ab8500-gpadc.0"); - bat_ctrl_raw = ab8500_gpadc_read_raw(gpadc, BAT_CTRL, - avg_sample, trig_edge, trig_timer, conv_type); - bat_ctrl_convert = ab8500_gpadc_ad_to_voltage(gpadc, - BAT_CTRL, bat_ctrl_raw); - - seq_printf(s, "%d,0x%X\n", bat_ctrl_convert, bat_ctrl_raw); - - return 0; -} - -DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_bat_ctrl); - -static int ab8500_gpadc_btemp_ball_show(struct seq_file *s, void *p) -{ - int btemp_ball_raw; - int btemp_ball_convert; - struct ab8500_gpadc *gpadc; - - gpadc = ab8500_gpadc_get("ab8500-gpadc.0"); - btemp_ball_raw = ab8500_gpadc_read_raw(gpadc, BTEMP_BALL, - avg_sample, trig_edge, trig_timer, conv_type); - btemp_ball_convert = ab8500_gpadc_ad_to_voltage(gpadc, BTEMP_BALL, - btemp_ball_raw); - - seq_printf(s, "%d,0x%X\n", btemp_ball_convert, btemp_ball_raw); - - return 0; -} - -DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_btemp_ball); - -static int ab8500_gpadc_main_charger_v_show(struct seq_file *s, void *p) -{ - int main_charger_v_raw; - int main_charger_v_convert; - struct ab8500_gpadc *gpadc; - - gpadc = ab8500_gpadc_get("ab8500-gpadc.0"); - main_charger_v_raw = ab8500_gpadc_read_raw(gpadc, MAIN_CHARGER_V, - avg_sample, trig_edge, trig_timer, conv_type); - main_charger_v_convert = ab8500_gpadc_ad_to_voltage(gpadc, - MAIN_CHARGER_V, main_charger_v_raw); - - seq_printf(s, "%d,0x%X\n", main_charger_v_convert, main_charger_v_raw); - - return 0; -} - -DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_main_charger_v); - -static int ab8500_gpadc_acc_detect1_show(struct seq_file *s, void *p) -{ - int acc_detect1_raw; - int acc_detect1_convert; - struct ab8500_gpadc *gpadc; - - gpadc = ab8500_gpadc_get("ab8500-gpadc.0"); - acc_detect1_raw = ab8500_gpadc_read_raw(gpadc, ACC_DETECT1, - avg_sample, trig_edge, trig_timer, conv_type); - acc_detect1_convert = ab8500_gpadc_ad_to_voltage(gpadc, ACC_DETECT1, - acc_detect1_raw); - - seq_printf(s, "%d,0x%X\n", acc_detect1_convert, acc_detect1_raw); - - return 0; -} - -DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_acc_detect1); - -static int ab8500_gpadc_acc_detect2_show(struct seq_file *s, void *p) -{ - int acc_detect2_raw; - int acc_detect2_convert; - struct ab8500_gpadc *gpadc; - - gpadc = ab8500_gpadc_get("ab8500-gpadc.0"); - acc_detect2_raw = ab8500_gpadc_read_raw(gpadc, ACC_DETECT2, - avg_sample, trig_edge, trig_timer, conv_type); - acc_detect2_convert = ab8500_gpadc_ad_to_voltage(gpadc, - ACC_DETECT2, acc_detect2_raw); - - seq_printf(s, "%d,0x%X\n", acc_detect2_convert, acc_detect2_raw); - - return 0; -} - -DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_acc_detect2); - -static int ab8500_gpadc_aux1_show(struct seq_file *s, void *p) -{ - int aux1_raw; - int aux1_convert; - struct ab8500_gpadc *gpadc; - - gpadc = ab8500_gpadc_get("ab8500-gpadc.0"); - aux1_raw = ab8500_gpadc_read_raw(gpadc, ADC_AUX1, - avg_sample, trig_edge, trig_timer, conv_type); - aux1_convert = ab8500_gpadc_ad_to_voltage(gpadc, ADC_AUX1, - aux1_raw); - - seq_printf(s, "%d,0x%X\n", aux1_convert, aux1_raw); - - return 0; -} - -DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_aux1); - -static int ab8500_gpadc_aux2_show(struct seq_file *s, void *p) -{ - int aux2_raw; - int aux2_convert; - struct ab8500_gpadc *gpadc; - - gpadc = ab8500_gpadc_get("ab8500-gpadc.0"); - aux2_raw = ab8500_gpadc_read_raw(gpadc, ADC_AUX2, - avg_sample, trig_edge, trig_timer, conv_type); - aux2_convert = ab8500_gpadc_ad_to_voltage(gpadc, ADC_AUX2, - aux2_raw); - - seq_printf(s, "%d,0x%X\n", aux2_convert, aux2_raw); - - return 0; -} - -DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_aux2); - -static int ab8500_gpadc_main_bat_v_show(struct seq_file *s, void *p) -{ - int main_bat_v_raw; - int main_bat_v_convert; - struct ab8500_gpadc *gpadc; - - gpadc = ab8500_gpadc_get("ab8500-gpadc.0"); - main_bat_v_raw = ab8500_gpadc_read_raw(gpadc, MAIN_BAT_V, - avg_sample, trig_edge, trig_timer, conv_type); - main_bat_v_convert = ab8500_gpadc_ad_to_voltage(gpadc, MAIN_BAT_V, - main_bat_v_raw); - - seq_printf(s, "%d,0x%X\n", main_bat_v_convert, main_bat_v_raw); - - return 0; -} - -DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_main_bat_v); - -static int ab8500_gpadc_vbus_v_show(struct seq_file *s, void *p) -{ - int vbus_v_raw; - int vbus_v_convert; - struct ab8500_gpadc *gpadc; - - gpadc = ab8500_gpadc_get("ab8500-gpadc.0"); - vbus_v_raw = ab8500_gpadc_read_raw(gpadc, VBUS_V, - avg_sample, trig_edge, trig_timer, conv_type); - vbus_v_convert = ab8500_gpadc_ad_to_voltage(gpadc, VBUS_V, - vbus_v_raw); - - seq_printf(s, "%d,0x%X\n", vbus_v_convert, vbus_v_raw); - - return 0; -} - -DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_vbus_v); - -static int ab8500_gpadc_main_charger_c_show(struct seq_file *s, void *p) -{ - int main_charger_c_raw; - int main_charger_c_convert; - struct ab8500_gpadc *gpadc; - - gpadc = ab8500_gpadc_get("ab8500-gpadc.0"); - main_charger_c_raw = ab8500_gpadc_read_raw(gpadc, MAIN_CHARGER_C, - avg_sample, trig_edge, trig_timer, conv_type); - main_charger_c_convert = ab8500_gpadc_ad_to_voltage(gpadc, - MAIN_CHARGER_C, main_charger_c_raw); - - seq_printf(s, "%d,0x%X\n", main_charger_c_convert, main_charger_c_raw); - - return 0; -} - -DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_main_charger_c); - -static int ab8500_gpadc_usb_charger_c_show(struct seq_file *s, void *p) -{ - int usb_charger_c_raw; - int usb_charger_c_convert; - struct ab8500_gpadc *gpadc; - - gpadc = ab8500_gpadc_get("ab8500-gpadc.0"); - usb_charger_c_raw = ab8500_gpadc_read_raw(gpadc, USB_CHARGER_C, - avg_sample, trig_edge, trig_timer, conv_type); - usb_charger_c_convert = ab8500_gpadc_ad_to_voltage(gpadc, - USB_CHARGER_C, usb_charger_c_raw); - - seq_printf(s, "%d,0x%X\n", usb_charger_c_convert, usb_charger_c_raw); - - return 0; -} - -DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_usb_charger_c); - -static int ab8500_gpadc_bk_bat_v_show(struct seq_file *s, void *p) -{ - int bk_bat_v_raw; - int bk_bat_v_convert; - struct ab8500_gpadc *gpadc; - - gpadc = ab8500_gpadc_get("ab8500-gpadc.0"); - bk_bat_v_raw = ab8500_gpadc_read_raw(gpadc, BK_BAT_V, - avg_sample, trig_edge, trig_timer, conv_type); - bk_bat_v_convert = ab8500_gpadc_ad_to_voltage(gpadc, - BK_BAT_V, bk_bat_v_raw); - - seq_printf(s, "%d,0x%X\n", bk_bat_v_convert, bk_bat_v_raw); - - return 0; -} - -DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_bk_bat_v); - -static int ab8500_gpadc_die_temp_show(struct seq_file *s, void *p) -{ - int die_temp_raw; - int die_temp_convert; - struct ab8500_gpadc *gpadc; - - gpadc = ab8500_gpadc_get("ab8500-gpadc.0"); - die_temp_raw = ab8500_gpadc_read_raw(gpadc, DIE_TEMP, - avg_sample, trig_edge, trig_timer, conv_type); - die_temp_convert = ab8500_gpadc_ad_to_voltage(gpadc, DIE_TEMP, - die_temp_raw); - - seq_printf(s, "%d,0x%X\n", die_temp_convert, die_temp_raw); - - return 0; -} - -DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_die_temp); - -static int ab8500_gpadc_usb_id_show(struct seq_file *s, void *p) -{ - int usb_id_raw; - int usb_id_convert; - struct ab8500_gpadc *gpadc; - - gpadc = ab8500_gpadc_get("ab8500-gpadc.0"); - usb_id_raw = ab8500_gpadc_read_raw(gpadc, USB_ID, - avg_sample, trig_edge, trig_timer, conv_type); - usb_id_convert = ab8500_gpadc_ad_to_voltage(gpadc, USB_ID, - usb_id_raw); - - seq_printf(s, "%d,0x%X\n", usb_id_convert, usb_id_raw); - - return 0; -} - -DEFINE_SHOW_ATTRIBUTE(ab8500_gpadc_usb_id); - -static int ab8540_gpadc_xtal_temp_show(struct seq_file *s, void *p) -{ - int xtal_temp_raw; - int xtal_temp_convert; - struct ab8500_gpadc *gpadc; - - gpadc = ab8500_gpadc_get("ab8500-gpadc.0"); - xtal_temp_raw = ab8500_gpadc_read_raw(gpadc, XTAL_TEMP, - avg_sample, trig_edge, trig_timer, conv_type); - xtal_temp_convert = ab8500_gpadc_ad_to_voltage(gpadc, XTAL_TEMP, - xtal_temp_raw); - - seq_printf(s, "%d,0x%X\n", xtal_temp_convert, xtal_temp_raw); - - return 0; -} - -DEFINE_SHOW_ATTRIBUTE(ab8540_gpadc_xtal_temp); - -static int ab8540_gpadc_vbat_true_meas_show(struct seq_file *s, void *p) -{ - int vbat_true_meas_raw; - int vbat_true_meas_convert; - struct ab8500_gpadc *gpadc; - - gpadc = ab8500_gpadc_get("ab8500-gpadc.0"); - vbat_true_meas_raw = ab8500_gpadc_read_raw(gpadc, VBAT_TRUE_MEAS, - avg_sample, trig_edge, trig_timer, conv_type); - vbat_true_meas_convert = - ab8500_gpadc_ad_to_voltage(gpadc, VBAT_TRUE_MEAS, - vbat_true_meas_raw); - - seq_printf(s, "%d,0x%X\n", vbat_true_meas_convert, vbat_true_meas_raw); - - return 0; -} - -DEFINE_SHOW_ATTRIBUTE(ab8540_gpadc_vbat_true_meas); - -static int ab8540_gpadc_bat_ctrl_and_ibat_show(struct seq_file *s, void *p) -{ - int bat_ctrl_raw; - int bat_ctrl_convert; - int ibat_raw; - int ibat_convert; - struct ab8500_gpadc *gpadc; - - gpadc = ab8500_gpadc_get("ab8500-gpadc.0"); - bat_ctrl_raw = ab8500_gpadc_double_read_raw(gpadc, BAT_CTRL_AND_IBAT, - avg_sample, trig_edge, trig_timer, conv_type, &ibat_raw); - - bat_ctrl_convert = ab8500_gpadc_ad_to_voltage(gpadc, BAT_CTRL, - bat_ctrl_raw); - ibat_convert = ab8500_gpadc_ad_to_voltage(gpadc, IBAT_VIRTUAL_CHANNEL, - ibat_raw); - - seq_printf(s, - "%d,0x%X\n" - "%d,0x%X\n", - bat_ctrl_convert, bat_ctrl_raw, - ibat_convert, ibat_raw); - - return 0; -} - -DEFINE_SHOW_ATTRIBUTE(ab8540_gpadc_bat_ctrl_and_ibat); - -static int ab8540_gpadc_vbat_meas_and_ibat_show(struct seq_file *s, void *p) -{ - int vbat_meas_raw; - int vbat_meas_convert; - int ibat_raw; - int ibat_convert; - struct ab8500_gpadc *gpadc; - - gpadc = ab8500_gpadc_get("ab8500-gpadc.0"); - vbat_meas_raw = ab8500_gpadc_double_read_raw(gpadc, VBAT_MEAS_AND_IBAT, - avg_sample, trig_edge, trig_timer, conv_type, &ibat_raw); - vbat_meas_convert = ab8500_gpadc_ad_to_voltage(gpadc, MAIN_BAT_V, - vbat_meas_raw); - ibat_convert = ab8500_gpadc_ad_to_voltage(gpadc, IBAT_VIRTUAL_CHANNEL, - ibat_raw); - - seq_printf(s, - "%d,0x%X\n" - "%d,0x%X\n", - vbat_meas_convert, vbat_meas_raw, - ibat_convert, ibat_raw); - - return 0; -} - -DEFINE_SHOW_ATTRIBUTE(ab8540_gpadc_vbat_meas_and_ibat); - -static int ab8540_gpadc_vbat_true_meas_and_ibat_show(struct seq_file *s, void *p) -{ - int vbat_true_meas_raw; - int vbat_true_meas_convert; - int ibat_raw; - int ibat_convert; - struct ab8500_gpadc *gpadc; - - gpadc = ab8500_gpadc_get("ab8500-gpadc.0"); - vbat_true_meas_raw = ab8500_gpadc_double_read_raw(gpadc, - VBAT_TRUE_MEAS_AND_IBAT, avg_sample, trig_edge, - trig_timer, conv_type, &ibat_raw); - vbat_true_meas_convert = ab8500_gpadc_ad_to_voltage(gpadc, - VBAT_TRUE_MEAS, vbat_true_meas_raw); - ibat_convert = ab8500_gpadc_ad_to_voltage(gpadc, IBAT_VIRTUAL_CHANNEL, - ibat_raw); - - seq_printf(s, - "%d,0x%X\n" - "%d,0x%X\n", - vbat_true_meas_convert, vbat_true_meas_raw, - ibat_convert, ibat_raw); - - return 0; -} - -DEFINE_SHOW_ATTRIBUTE(ab8540_gpadc_vbat_true_meas_and_ibat); - -static int ab8540_gpadc_bat_temp_and_ibat_show(struct seq_file *s, void *p) -{ - int bat_temp_raw; - int bat_temp_convert; - int ibat_raw; - int ibat_convert; - struct ab8500_gpadc *gpadc; - - gpadc = ab8500_gpadc_get("ab8500-gpadc.0"); - bat_temp_raw = ab8500_gpadc_double_read_raw(gpadc, BAT_TEMP_AND_IBAT, - avg_sample, trig_edge, trig_timer, conv_type, &ibat_raw); - bat_temp_convert = ab8500_gpadc_ad_to_voltage(gpadc, BTEMP_BALL, - bat_temp_raw); - ibat_convert = ab8500_gpadc_ad_to_voltage(gpadc, IBAT_VIRTUAL_CHANNEL, - ibat_raw); - - seq_printf(s, - "%d,0x%X\n" - "%d,0x%X\n", - bat_temp_convert, bat_temp_raw, - ibat_convert, ibat_raw); - - return 0; -} - -DEFINE_SHOW_ATTRIBUTE(ab8540_gpadc_bat_temp_and_ibat); - -static int ab8540_gpadc_otp_calib_show(struct seq_file *s, void *p) -{ - struct ab8500_gpadc *gpadc; - u16 vmain_l, vmain_h, btemp_l, btemp_h; - u16 vbat_l, vbat_h, ibat_l, ibat_h; - - gpadc = ab8500_gpadc_get("ab8500-gpadc.0"); - ab8540_gpadc_get_otp(gpadc, &vmain_l, &vmain_h, &btemp_l, &btemp_h, - &vbat_l, &vbat_h, &ibat_l, &ibat_h); - seq_printf(s, - "VMAIN_L:0x%X\n" - "VMAIN_H:0x%X\n" - "BTEMP_L:0x%X\n" - "BTEMP_H:0x%X\n" - "VBAT_L:0x%X\n" - "VBAT_H:0x%X\n" - "IBAT_L:0x%X\n" - "IBAT_H:0x%X\n", - vmain_l, vmain_h, btemp_l, btemp_h, - vbat_l, vbat_h, ibat_l, ibat_h); - - return 0; -} - -DEFINE_SHOW_ATTRIBUTE(ab8540_gpadc_otp_calib); - -static int ab8500_gpadc_avg_sample_print(struct seq_file *s, void *p) -{ - seq_printf(s, "%d\n", avg_sample); - - return 0; -} - -static int ab8500_gpadc_avg_sample_open(struct inode *inode, struct file *file) -{ - return single_open(file, ab8500_gpadc_avg_sample_print, - inode->i_private); -} - -static ssize_t ab8500_gpadc_avg_sample_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct device *dev = ((struct seq_file *)(file->private_data))->private; - unsigned long user_avg_sample; - int err; - - err = kstrtoul_from_user(user_buf, count, 0, &user_avg_sample); - if (err) - return err; - - if ((user_avg_sample == SAMPLE_1) || (user_avg_sample == SAMPLE_4) - || (user_avg_sample == SAMPLE_8) - || (user_avg_sample == SAMPLE_16)) { - avg_sample = (u8) user_avg_sample; - } else { - dev_err(dev, - "debugfs err input: should be egal to 1, 4, 8 or 16\n"); - return -EINVAL; - } - - return count; -} - -static const struct file_operations ab8500_gpadc_avg_sample_fops = { - .open = ab8500_gpadc_avg_sample_open, - .read = seq_read, - .write = ab8500_gpadc_avg_sample_write, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static int ab8500_gpadc_trig_edge_print(struct seq_file *s, void *p) -{ - seq_printf(s, "%d\n", trig_edge); - - return 0; -} - -static int ab8500_gpadc_trig_edge_open(struct inode *inode, struct file *file) -{ - return single_open(file, ab8500_gpadc_trig_edge_print, - inode->i_private); -} - -static ssize_t ab8500_gpadc_trig_edge_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct device *dev = ((struct seq_file *)(file->private_data))->private; - unsigned long user_trig_edge; - int err; - - err = kstrtoul_from_user(user_buf, count, 0, &user_trig_edge); - if (err) - return err; - - if ((user_trig_edge == RISING_EDGE) - || (user_trig_edge == FALLING_EDGE)) { - trig_edge = (u8) user_trig_edge; - } else { - dev_err(dev, "Wrong input:\n" - "Enter 0. Rising edge\n" - "Enter 1. Falling edge\n"); - return -EINVAL; - } - - return count; -} - -static const struct file_operations ab8500_gpadc_trig_edge_fops = { - .open = ab8500_gpadc_trig_edge_open, - .read = seq_read, - .write = ab8500_gpadc_trig_edge_write, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static int ab8500_gpadc_trig_timer_print(struct seq_file *s, void *p) -{ - seq_printf(s, "%d\n", trig_timer); - - return 0; -} - -static int ab8500_gpadc_trig_timer_open(struct inode *inode, struct file *file) -{ - return single_open(file, ab8500_gpadc_trig_timer_print, - inode->i_private); -} - -static ssize_t ab8500_gpadc_trig_timer_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct device *dev = ((struct seq_file *)(file->private_data))->private; - unsigned long user_trig_timer; - int err; - - err = kstrtoul_from_user(user_buf, count, 0, &user_trig_timer); - if (err) - return err; - - if (user_trig_timer & ~0xFF) { - dev_err(dev, - "debugfs error input: should be between 0 to 255\n"); - return -EINVAL; - } - - trig_timer = (u8) user_trig_timer; - - return count; -} - -static const struct file_operations ab8500_gpadc_trig_timer_fops = { - .open = ab8500_gpadc_trig_timer_open, - .read = seq_read, - .write = ab8500_gpadc_trig_timer_write, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - -static int ab8500_gpadc_conv_type_print(struct seq_file *s, void *p) -{ - seq_printf(s, "%d\n", conv_type); - - return 0; -} - -static int ab8500_gpadc_conv_type_open(struct inode *inode, struct file *file) -{ - return single_open(file, ab8500_gpadc_conv_type_print, - inode->i_private); -} - -static ssize_t ab8500_gpadc_conv_type_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct device *dev = ((struct seq_file *)(file->private_data))->private; - unsigned long user_conv_type; - int err; - - err = kstrtoul_from_user(user_buf, count, 0, &user_conv_type); - if (err) - return err; - - if ((user_conv_type == ADC_SW) - || (user_conv_type == ADC_HW)) { - conv_type = (u8) user_conv_type; - } else { - dev_err(dev, "Wrong input:\n" - "Enter 0. ADC SW conversion\n" - "Enter 1. ADC HW conversion\n"); - return -EINVAL; - } - - return count; -} - -static const struct file_operations ab8500_gpadc_conv_type_fops = { - .open = ab8500_gpadc_conv_type_open, - .read = seq_read, - .write = ab8500_gpadc_conv_type_write, - .llseek = seq_lseek, - .release = single_release, - .owner = THIS_MODULE, -}; - /* * return length of an ASCII numerical value, 0 is string is not a * numerical value. @@ -2647,7 +2013,6 @@ static const struct file_operations ab8500_hwreg_fops = { static int ab8500_debug_probe(struct platform_device *plf) { struct dentry *ab8500_dir; - struct dentry *ab8500_gpadc_dir; struct ab8500 *ab8500; struct resource *res; @@ -2689,9 +2054,6 @@ static int ab8500_debug_probe(struct platform_device *plf) ab8500_dir = debugfs_create_dir(AB8500_NAME_STRING, NULL); - ab8500_gpadc_dir = debugfs_create_dir(AB8500_ADC_NAME_STRING, - ab8500_dir); - debugfs_create_file("all-bank-registers", S_IRUGO, ab8500_dir, &plf->dev, &ab8500_bank_registers_fops); debugfs_create_file("all-banks", S_IRUGO, ab8500_dir, @@ -2727,83 +2089,6 @@ static int ab8500_debug_probe(struct platform_device *plf) &plf->dev, &ab8500_hwreg_fops); debugfs_create_file("all-modem-registers", (S_IRUGO | S_IWUSR | S_IWGRP), ab8500_dir, &plf->dev, &ab8500_modem_fops); - debugfs_create_file("bat_ctrl", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8500_gpadc_bat_ctrl_fops); - debugfs_create_file("btemp_ball", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8500_gpadc_btemp_ball_fops); - debugfs_create_file("main_charger_v", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8500_gpadc_main_charger_v_fops); - debugfs_create_file("acc_detect1", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8500_gpadc_acc_detect1_fops); - debugfs_create_file("acc_detect2", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8500_gpadc_acc_detect2_fops); - debugfs_create_file("adc_aux1", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8500_gpadc_aux1_fops); - debugfs_create_file("adc_aux2", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8500_gpadc_aux2_fops); - debugfs_create_file("main_bat_v", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8500_gpadc_main_bat_v_fops); - debugfs_create_file("vbus_v", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8500_gpadc_vbus_v_fops); - debugfs_create_file("main_charger_c", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8500_gpadc_main_charger_c_fops); - debugfs_create_file("usb_charger_c", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8500_gpadc_usb_charger_c_fops); - debugfs_create_file("bk_bat_v", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8500_gpadc_bk_bat_v_fops); - debugfs_create_file("die_temp", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8500_gpadc_die_temp_fops); - debugfs_create_file("usb_id", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8500_gpadc_usb_id_fops); - if (is_ab8540(ab8500)) { - debugfs_create_file("xtal_temp", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8540_gpadc_xtal_temp_fops); - debugfs_create_file("vbattruemeas", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8540_gpadc_vbat_true_meas_fops); - debugfs_create_file("batctrl_and_ibat", (S_IRUGO | S_IWUGO), - ab8500_gpadc_dir, &plf->dev, - &ab8540_gpadc_bat_ctrl_and_ibat_fops); - debugfs_create_file("vbatmeas_and_ibat", (S_IRUGO | S_IWUGO), - ab8500_gpadc_dir, &plf->dev, - &ab8540_gpadc_vbat_meas_and_ibat_fops); - debugfs_create_file("vbattruemeas_and_ibat", (S_IRUGO | S_IWUGO), - ab8500_gpadc_dir, &plf->dev, - &ab8540_gpadc_vbat_true_meas_and_ibat_fops); - debugfs_create_file("battemp_and_ibat", (S_IRUGO | S_IWUGO), - ab8500_gpadc_dir, &plf->dev, - &ab8540_gpadc_bat_temp_and_ibat_fops); - debugfs_create_file("otp_calib", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8540_gpadc_otp_calib_fops); - } - debugfs_create_file("avg_sample", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8500_gpadc_avg_sample_fops); - debugfs_create_file("trig_edge", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8500_gpadc_trig_edge_fops); - debugfs_create_file("trig_timer", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8500_gpadc_trig_timer_fops); - debugfs_create_file("conv_type", (S_IRUGO | S_IWUSR | S_IWGRP), - ab8500_gpadc_dir, &plf->dev, - &ab8500_gpadc_conv_type_fops); return 0; } diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c deleted file mode 100644 index 005f9ee34cd1..000000000000 --- a/drivers/mfd/ab8500-gpadc.c +++ /dev/null @@ -1,1075 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) ST-Ericsson SA 2010 - * - * Author: Arun R Murthy <arun.murthy@stericsson.com> - * Author: Daniel Willerud <daniel.willerud@stericsson.com> - * Author: Johan Palsson <johan.palsson@stericsson.com> - * Author: M'boumba Cedric Madianga - */ -#include <linux/init.h> -#include <linux/device.h> -#include <linux/interrupt.h> -#include <linux/spinlock.h> -#include <linux/delay.h> -#include <linux/pm_runtime.h> -#include <linux/platform_device.h> -#include <linux/completion.h> -#include <linux/regulator/consumer.h> -#include <linux/err.h> -#include <linux/slab.h> -#include <linux/list.h> -#include <linux/mfd/abx500.h> -#include <linux/mfd/abx500/ab8500.h> -#include <linux/mfd/abx500/ab8500-gpadc.h> - -/* - * GPADC register offsets - * Bank : 0x0A - */ -#define AB8500_GPADC_CTRL1_REG 0x00 -#define AB8500_GPADC_CTRL2_REG 0x01 -#define AB8500_GPADC_CTRL3_REG 0x02 -#define AB8500_GPADC_AUTO_TIMER_REG 0x03 -#define AB8500_GPADC_STAT_REG 0x04 -#define AB8500_GPADC_MANDATAL_REG 0x05 -#define AB8500_GPADC_MANDATAH_REG 0x06 -#define AB8500_GPADC_AUTODATAL_REG 0x07 -#define AB8500_GPADC_AUTODATAH_REG 0x08 -#define AB8500_GPADC_MUX_CTRL_REG 0x09 -#define AB8540_GPADC_MANDATA2L_REG 0x09 -#define AB8540_GPADC_MANDATA2H_REG 0x0A -#define AB8540_GPADC_APEAAX_REG 0x10 -#define AB8540_GPADC_APEAAT_REG 0x11 -#define AB8540_GPADC_APEAAM_REG 0x12 -#define AB8540_GPADC_APEAAH_REG 0x13 -#define AB8540_GPADC_APEAAL_REG 0x14 - -/* - * OTP register offsets - * Bank : 0x15 - */ -#define AB8500_GPADC_CAL_1 0x0F -#define AB8500_GPADC_CAL_2 0x10 -#define AB8500_GPADC_CAL_3 0x11 -#define AB8500_GPADC_CAL_4 0x12 -#define AB8500_GPADC_CAL_5 0x13 -#define AB8500_GPADC_CAL_6 0x14 -#define AB8500_GPADC_CAL_7 0x15 -/* New calibration for 8540 */ -#define AB8540_GPADC_OTP4_REG_7 0x38 -#define AB8540_GPADC_OTP4_REG_6 0x39 -#define AB8540_GPADC_OTP4_REG_5 0x3A - -/* gpadc constants */ -#define EN_VINTCORE12 0x04 -#define EN_VTVOUT 0x02 -#define EN_GPADC 0x01 -#define DIS_GPADC 0x00 -#define AVG_1 0x00 -#define AVG_4 0x20 -#define AVG_8 0x40 -#define AVG_16 0x60 -#define ADC_SW_CONV 0x04 -#define EN_ICHAR 0x80 -#define BTEMP_PULL_UP 0x08 -#define EN_BUF 0x40 -#define DIS_ZERO 0x00 -#define GPADC_BUSY 0x01 -#define EN_FALLING 0x10 -#define EN_TRIG_EDGE 0x02 -#define EN_VBIAS_XTAL_TEMP 0x02 - -/* GPADC constants from AB8500 spec, UM0836 */ -#define ADC_RESOLUTION 1024 -#define ADC_CH_BTEMP_MIN 0 -#define ADC_CH_BTEMP_MAX 1350 -#define ADC_CH_DIETEMP_MIN 0 -#define ADC_CH_DIETEMP_MAX 1350 -#define ADC_CH_CHG_V_MIN 0 -#define ADC_CH_CHG_V_MAX 20030 -#define ADC_CH_ACCDET2_MIN 0 -#define ADC_CH_ACCDET2_MAX 2500 -#define ADC_CH_VBAT_MIN 2300 -#define ADC_CH_VBAT_MAX 4800 -#define ADC_CH_CHG_I_MIN 0 -#define ADC_CH_CHG_I_MAX 1500 -#define ADC_CH_BKBAT_MIN 0 -#define ADC_CH_BKBAT_MAX 3200 - -/* GPADC constants from AB8540 spec */ -#define ADC_CH_IBAT_MIN (-6000) /* mA range measured by ADC for ibat */ -#define ADC_CH_IBAT_MAX 6000 -#define ADC_CH_IBAT_MIN_V (-60) /* mV range measured by ADC for ibat */ -#define ADC_CH_IBAT_MAX_V 60 -#define IBAT_VDROP_L (-56) /* mV */ -#define IBAT_VDROP_H 56 - -/* This is used to not lose precision when dividing to get gain and offset */ -#define CALIB_SCALE 1000 -/* - * Number of bits shift used to not lose precision - * when dividing to get ibat gain. - */ -#define CALIB_SHIFT_IBAT 20 - -/* Time in ms before disabling regulator */ -#define GPADC_AUDOSUSPEND_DELAY 1 - -#define CONVERSION_TIME 500 /* ms */ - -enum cal_channels { - ADC_INPUT_VMAIN = 0, - ADC_INPUT_BTEMP, - ADC_INPUT_VBAT, - ADC_INPUT_IBAT, - NBR_CAL_INPUTS, -}; - -/** - * struct adc_cal_data - Table for storing gain and offset for the calibrated - * ADC channels - * @gain: Gain of the ADC channel - * @offset: Offset of the ADC channel - */ -struct adc_cal_data { - s64 gain; - s64 offset; - u16 otp_calib_hi; - u16 otp_calib_lo; -}; - -/** - * struct ab8500_gpadc - AB8500 GPADC device information - * @dev: pointer to the struct device - * @node: a list of AB8500 GPADCs, hence prepared for - reentrance - * @parent: pointer to the struct ab8500 - * @ab8500_gpadc_complete: pointer to the struct completion, to indicate - * the completion of gpadc conversion - * @ab8500_gpadc_lock: structure of type mutex - * @regu: pointer to the struct regulator - * @irq_sw: interrupt number that is used by gpadc for Sw - * conversion - * @irq_hw: interrupt number that is used by gpadc for Hw - * conversion - * @cal_data array of ADC calibration data structs - */ -struct ab8500_gpadc { - struct device *dev; - struct list_head node; - struct ab8500 *parent; - struct completion ab8500_gpadc_complete; - struct mutex ab8500_gpadc_lock; - struct regulator *regu; - int irq_sw; - int irq_hw; - struct adc_cal_data cal_data[NBR_CAL_INPUTS]; -}; - -static LIST_HEAD(ab8500_gpadc_list); - -/** - * ab8500_gpadc_get() - returns a reference to the primary AB8500 GPADC - * (i.e. the first GPADC in the instance list) - */ -struct ab8500_gpadc *ab8500_gpadc_get(char *name) -{ - struct ab8500_gpadc *gpadc; - - list_for_each_entry(gpadc, &ab8500_gpadc_list, node) { - if (!strcmp(name, dev_name(gpadc->dev))) - return gpadc; - } - - return ERR_PTR(-ENOENT); -} -EXPORT_SYMBOL(ab8500_gpadc_get); - -/** - * ab8500_gpadc_ad_to_voltage() - Convert a raw ADC value to a voltage - */ -int ab8500_gpadc_ad_to_voltage(struct ab8500_gpadc *gpadc, u8 channel, - int ad_value) -{ - int res; - - switch (channel) { - case MAIN_CHARGER_V: - /* For some reason we don't have calibrated data */ - if (!gpadc->cal_data[ADC_INPUT_VMAIN].gain) { - res = ADC_CH_CHG_V_MIN + (ADC_CH_CHG_V_MAX - - ADC_CH_CHG_V_MIN) * ad_value / - ADC_RESOLUTION; - break; - } - /* Here we can use the calibrated data */ - res = (int) (ad_value * gpadc->cal_data[ADC_INPUT_VMAIN].gain + - gpadc->cal_data[ADC_INPUT_VMAIN].offset) / CALIB_SCALE; - break; - - case XTAL_TEMP: - case BAT_CTRL: - case BTEMP_BALL: - case ACC_DETECT1: - case ADC_AUX1: - case ADC_AUX2: - /* For some reason we don't have calibrated data */ - if (!gpadc->cal_data[ADC_INPUT_BTEMP].gain) { - res = ADC_CH_BTEMP_MIN + (ADC_CH_BTEMP_MAX - - ADC_CH_BTEMP_MIN) * ad_value / - ADC_RESOLUTION; - break; - } - /* Here we can use the calibrated data */ - res = (int) (ad_value * gpadc->cal_data[ADC_INPUT_BTEMP].gain + - gpadc->cal_data[ADC_INPUT_BTEMP].offset) / CALIB_SCALE; - break; - - case MAIN_BAT_V: - case VBAT_TRUE_MEAS: - /* For some reason we don't have calibrated data */ - if (!gpadc->cal_data[ADC_INPUT_VBAT].gain) { - res = ADC_CH_VBAT_MIN + (ADC_CH_VBAT_MAX - - ADC_CH_VBAT_MIN) * ad_value / - ADC_RESOLUTION; - break; - } - /* Here we can use the calibrated data */ - res = (int) (ad_value * gpadc->cal_data[ADC_INPUT_VBAT].gain + - gpadc->cal_data[ADC_INPUT_VBAT].offset) / CALIB_SCALE; - break; - - case DIE_TEMP: - res = ADC_CH_DIETEMP_MIN + - (ADC_CH_DIETEMP_MAX - ADC_CH_DIETEMP_MIN) * ad_value / - ADC_RESOLUTION; - break; - - case ACC_DETECT2: - res = ADC_CH_ACCDET2_MIN + - (ADC_CH_ACCDET2_MAX - ADC_CH_ACCDET2_MIN) * ad_value / - ADC_RESOLUTION; - break; - - case VBUS_V: - res = ADC_CH_CHG_V_MIN + - (ADC_CH_CHG_V_MAX - ADC_CH_CHG_V_MIN) * ad_value / - ADC_RESOLUTION; - break; - - case MAIN_CHARGER_C: - case USB_CHARGER_C: - res = ADC_CH_CHG_I_MIN + - (ADC_CH_CHG_I_MAX - ADC_CH_CHG_I_MIN) * ad_value / - ADC_RESOLUTION; - break; - - case BK_BAT_V: - res = ADC_CH_BKBAT_MIN + - (ADC_CH_BKBAT_MAX - ADC_CH_BKBAT_MIN) * ad_value / - ADC_RESOLUTION; - break; - - case IBAT_VIRTUAL_CHANNEL: - /* For some reason we don't have calibrated data */ - if (!gpadc->cal_data[ADC_INPUT_IBAT].gain) { - res = ADC_CH_IBAT_MIN + (ADC_CH_IBAT_MAX - - ADC_CH_IBAT_MIN) * ad_value / - ADC_RESOLUTION; - break; - } - /* Here we can use the calibrated data */ - res = (int) (ad_value * gpadc->cal_data[ADC_INPUT_IBAT].gain + - gpadc->cal_data[ADC_INPUT_IBAT].offset) - >> CALIB_SHIFT_IBAT; - break; - - default: - dev_err(gpadc->dev, - "unknown channel, not possible to convert\n"); - res = -EINVAL; - break; - - } - return res; -} -EXPORT_SYMBOL(ab8500_gpadc_ad_to_voltage); - -/** - * ab8500_gpadc_sw_hw_convert() - gpadc conversion - * @channel: analog channel to be converted to digital data - * @avg_sample: number of ADC sample to average - * @trig_egde: selected ADC trig edge - * @trig_timer: selected ADC trigger delay timer - * @conv_type: selected conversion type (HW or SW conversion) - * - * This function converts the selected analog i/p to digital - * data. - */ -int ab8500_gpadc_sw_hw_convert(struct ab8500_gpadc *gpadc, u8 channel, - u8 avg_sample, u8 trig_edge, u8 trig_timer, u8 conv_type) -{ - int ad_value; - int voltage; - - ad_value = ab8500_gpadc_read_raw(gpadc, channel, avg_sample, - trig_edge, trig_timer, conv_type); - - /* On failure retry a second time */ - if (ad_value < 0) - ad_value = ab8500_gpadc_read_raw(gpadc, channel, avg_sample, - trig_edge, trig_timer, conv_type); - if (ad_value < 0) { - dev_err(gpadc->dev, "GPADC raw value failed ch: %d\n", - channel); - return ad_value; - } - - voltage = ab8500_gpadc_ad_to_voltage(gpadc, channel, ad_value); - if (voltage < 0) - dev_err(gpadc->dev, - "GPADC to voltage conversion failed ch: %d AD: 0x%x\n", - channel, ad_value); - - return voltage; -} -EXPORT_SYMBOL(ab8500_gpadc_sw_hw_convert); - -/** - * ab8500_gpadc_read_raw() - gpadc read - * @channel: analog channel to be read - * @avg_sample: number of ADC sample to average - * @trig_edge: selected trig edge - * @trig_timer: selected ADC trigger delay timer - * @conv_type: selected conversion type (HW or SW conversion) - * - * This function obtains the raw ADC value for an hardware conversion, - * this then needs to be converted by calling ab8500_gpadc_ad_to_voltage() - */ -int ab8500_gpadc_read_raw(struct ab8500_gpadc *gpadc, u8 channel, - u8 avg_sample, u8 trig_edge, u8 trig_timer, u8 conv_type) -{ - return ab8500_gpadc_double_read_raw(gpadc, channel, avg_sample, - trig_edge, trig_timer, conv_type, - NULL); -} - -int ab8500_gpadc_double_read_raw(struct ab8500_gpadc *gpadc, u8 channel, - u8 avg_sample, u8 trig_edge, u8 trig_timer, u8 conv_type, - int *ibat) -{ - int ret; - int looplimit = 0; - unsigned long completion_timeout; - u8 val, low_data, high_data, low_data2, high_data2; - u8 val_reg1 = 0; - unsigned int delay_min = 0; - unsigned int delay_max = 0; - u8 data_low_addr, data_high_addr; - - if (!gpadc) - return -ENODEV; - - /* check if convertion is supported */ - if ((gpadc->irq_sw < 0) && (conv_type == ADC_SW)) - return -ENOTSUPP; - if ((gpadc->irq_hw < 0) && (conv_type == ADC_HW)) - return -ENOTSUPP; - - mutex_lock(&gpadc->ab8500_gpadc_lock); - /* Enable VTVout LDO this is required for GPADC */ - pm_runtime_get_sync(gpadc->dev); - - /* Check if ADC is not busy, lock and proceed */ - do { - ret = abx500_get_register_interruptible(gpadc->dev, - AB8500_GPADC, AB8500_GPADC_STAT_REG, &val); - if (ret < 0) - goto out; - if (!(val & GPADC_BUSY)) - break; - msleep(20); - } while (++looplimit < 10); - if (looplimit >= 10 && (val & GPADC_BUSY)) { - dev_err(gpadc->dev, "gpadc_conversion: GPADC busy"); - ret = -EINVAL; - goto out; - } - - /* Enable GPADC */ - val_reg1 |= EN_GPADC; - - /* Select the channel source and set average samples */ - switch (avg_sample) { - case SAMPLE_1: - val = channel | AVG_1; - break; - case SAMPLE_4: - val = channel | AVG_4; - break; - case SAMPLE_8: - val = channel | AVG_8; - break; - default: - val = channel | AVG_16; - break; - } - - if (conv_type == ADC_HW) { - ret = abx500_set_register_interruptible(gpadc->dev, - AB8500_GPADC, AB8500_GPADC_CTRL3_REG, val); - val_reg1 |= EN_TRIG_EDGE; - if (trig_edge) - val_reg1 |= EN_FALLING; - } else - ret = abx500_set_register_interruptible(gpadc->dev, - AB8500_GPADC, AB8500_GPADC_CTRL2_REG, val); - if (ret < 0) { - dev_err(gpadc->dev, - "gpadc_conversion: set avg samples failed\n"); - goto out; - } - - /* - * Enable ADC, buffering, select rising edge and enable ADC path - * charging current sense if it needed, ABB 3.0 needs some special - * treatment too. - */ - switch (channel) { - case MAIN_CHARGER_C: - case USB_CHARGER_C: - val_reg1 |= EN_BUF | EN_ICHAR; - break; - case BTEMP_BALL: - if (!is_ab8500_2p0_or_earlier(gpadc->parent)) { - val_reg1 |= EN_BUF | BTEMP_PULL_UP; - /* - * Delay might be needed for ABB8500 cut 3.0, if not, - * remove when hardware will be availible - */ - delay_min = 1000; /* Delay in micro seconds */ - delay_max = 10000; /* large range optimises sleepmode */ - break; - } - /* Intentional fallthrough */ - default: - val_reg1 |= EN_BUF; - break; - } - - /* Write configuration to register */ - ret = abx500_set_register_interruptible(gpadc->dev, - AB8500_GPADC, AB8500_GPADC_CTRL1_REG, val_reg1); - if (ret < 0) { - dev_err(gpadc->dev, - "gpadc_conversion: set Control register failed\n"); - goto out; - } - - if (delay_min != 0) - usleep_range(delay_min, delay_max); - - if (conv_type == ADC_HW) { - /* Set trigger delay timer */ - ret = abx500_set_register_interruptible(gpadc->dev, - AB8500_GPADC, AB8500_GPADC_AUTO_TIMER_REG, trig_timer); - if (ret < 0) { - dev_err(gpadc->dev, - "gpadc_conversion: trig timer failed\n"); - goto out; - } - completion_timeout = 2 * HZ; - data_low_addr = AB8500_GPADC_AUTODATAL_REG; - data_high_addr = AB8500_GPADC_AUTODATAH_REG; - } else { - /* Start SW conversion */ - ret = abx500_mask_and_set_register_interruptible(gpadc->dev, - AB8500_GPADC, AB8500_GPADC_CTRL1_REG, - ADC_SW_CONV, ADC_SW_CONV); - if (ret < 0) { - dev_err(gpadc->dev, - "gpadc_conversion: start s/w conv failed\n"); - goto out; - } - completion_timeout = msecs_to_jiffies(CONVERSION_TIME); - data_low_addr = AB8500_GPADC_MANDATAL_REG; - data_high_addr = AB8500_GPADC_MANDATAH_REG; - } - - /* wait for completion of conversion */ - if (!wait_for_completion_timeout(&gpadc->ab8500_gpadc_complete, - completion_timeout)) { - dev_err(gpadc->dev, - "timeout didn't receive GPADC conv interrupt\n"); - ret = -EINVAL; - goto out; - } - - /* Read the converted RAW data */ - ret = abx500_get_register_interruptible(gpadc->dev, - AB8500_GPADC, data_low_addr, &low_data); - if (ret < 0) { - dev_err(gpadc->dev, "gpadc_conversion: read low data failed\n"); - goto out; - } - - ret = abx500_get_register_interruptible(gpadc->dev, - AB8500_GPADC, data_high_addr, &high_data); - if (ret < 0) { - dev_err(gpadc->dev, "gpadc_conversion: read high data failed\n"); - goto out; - } - - /* Check if double convertion is required */ - if ((channel == BAT_CTRL_AND_IBAT) || - (channel == VBAT_MEAS_AND_IBAT) || - (channel == VBAT_TRUE_MEAS_AND_IBAT) || - (channel == BAT_TEMP_AND_IBAT)) { - - if (conv_type == ADC_HW) { - /* not supported */ - ret = -ENOTSUPP; - dev_err(gpadc->dev, - "gpadc_conversion: only SW double conversion supported\n"); - goto out; - } else { - /* Read the converted RAW data 2 */ - ret = abx500_get_register_interruptible(gpadc->dev, - AB8500_GPADC, AB8540_GPADC_MANDATA2L_REG, - &low_data2); - if (ret < 0) { - dev_err(gpadc->dev, - "gpadc_conversion: read sw low data 2 failed\n"); - goto out; - } - - ret = abx500_get_register_interruptible(gpadc->dev, - AB8500_GPADC, AB8540_GPADC_MANDATA2H_REG, - &high_data2); - if (ret < 0) { - dev_err(gpadc->dev, - "gpadc_conversion: read sw high data 2 failed\n"); - goto out; - } - if (ibat != NULL) { - *ibat = (high_data2 << 8) | low_data2; - } else { - dev_warn(gpadc->dev, - "gpadc_conversion: ibat not stored\n"); - } - - } - } - - /* Disable GPADC */ - ret = abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC, - AB8500_GPADC_CTRL1_REG, DIS_GPADC); - if (ret < 0) { - dev_err(gpadc->dev, "gpadc_conversion: disable gpadc failed\n"); - goto out; - } - - /* Disable VTVout LDO this is required for GPADC */ - pm_runtime_mark_last_busy(gpadc->dev); - pm_runtime_put_autosuspend(gpadc->dev); - - mutex_unlock(&gpadc->ab8500_gpadc_lock); - - return (high_data << 8) | low_data; - -out: - /* - * It has shown to be needed to turn off the GPADC if an error occurs, - * otherwise we might have problem when waiting for the busy bit in the - * GPADC status register to go low. In V1.1 there wait_for_completion - * seems to timeout when waiting for an interrupt.. Not seen in V2.0 - */ - (void) abx500_set_register_interruptible(gpadc->dev, AB8500_GPADC, - AB8500_GPADC_CTRL1_REG, DIS_GPADC); - pm_runtime_put(gpadc->dev); - mutex_unlock(&gpadc->ab8500_gpadc_lock); - dev_err(gpadc->dev, - "gpadc_conversion: Failed to AD convert channel %d\n", channel); - return ret; -} -EXPORT_SYMBOL(ab8500_gpadc_read_raw); - -/** - * ab8500_bm_gpadcconvend_handler() - isr for gpadc conversion completion - * @irq: irq number - * @data: pointer to the data passed during request irq - * - * This is a interrupt service routine for gpadc conversion completion. - * Notifies the gpadc completion is completed and the converted raw value - * can be read from the registers. - * Returns IRQ status(IRQ_HANDLED) - */ -static irqreturn_t ab8500_bm_gpadcconvend_handler(int irq, void *_gpadc) -{ - struct ab8500_gpadc *gpadc = _gpadc; - - complete(&gpadc->ab8500_gpadc_complete); - - return IRQ_HANDLED; -} - -static int otp_cal_regs[] = { - AB8500_GPADC_CAL_1, - AB8500_GPADC_CAL_2, - AB8500_GPADC_CAL_3, - AB8500_GPADC_CAL_4, - AB8500_GPADC_CAL_5, - AB8500_GPADC_CAL_6, - AB8500_GPADC_CAL_7, -}; - -static int otp4_cal_regs[] = { - AB8540_GPADC_OTP4_REG_7, - AB8540_GPADC_OTP4_REG_6, - AB8540_GPADC_OTP4_REG_5, -}; - -static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc) -{ - int i; - int ret[ARRAY_SIZE(otp_cal_regs)]; - u8 gpadc_cal[ARRAY_SIZE(otp_cal_regs)]; - int ret_otp4[ARRAY_SIZE(otp4_cal_regs)]; - u8 gpadc_otp4[ARRAY_SIZE(otp4_cal_regs)]; - int vmain_high, vmain_low; - int btemp_high, btemp_low; - int vbat_high, vbat_low; - int ibat_high, ibat_low; - s64 V_gain, V_offset, V2A_gain, V2A_offset; - struct ab8500 *ab8500; - - ab8500 = gpadc->parent; - - /* First we read all OTP registers and store the error code */ - for (i = 0; i < ARRAY_SIZE(otp_cal_regs); i++) { - ret[i] = abx500_get_register_interruptible(gpadc->dev, - AB8500_OTP_EMUL, otp_cal_regs[i], &gpadc_cal[i]); - if (ret[i] < 0) - dev_err(gpadc->dev, "%s: read otp reg 0x%02x failed\n", - __func__, otp_cal_regs[i]); - } - - /* - * The ADC calibration data is stored in OTP registers. - * The layout of the calibration data is outlined below and a more - * detailed description can be found in UM0836 - * - * vm_h/l = vmain_high/low - * bt_h/l = btemp_high/low - * vb_h/l = vbat_high/low - * - * Data bits 8500/9540: - * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 - * |.......|.......|.......|.......|.......|.......|.......|....... - * | | vm_h9 | vm_h8 - * |.......|.......|.......|.......|.......|.......|.......|....... - * | | vm_h7 | vm_h6 | vm_h5 | vm_h4 | vm_h3 | vm_h2 - * |.......|.......|.......|.......|.......|.......|.......|....... - * | vm_h1 | vm_h0 | vm_l4 | vm_l3 | vm_l2 | vm_l1 | vm_l0 | bt_h9 - * |.......|.......|.......|.......|.......|.......|.......|....... - * | bt_h8 | bt_h7 | bt_h6 | bt_h5 | bt_h4 | bt_h3 | bt_h2 | bt_h1 - * |.......|.......|.......|.......|.......|.......|.......|....... - * | bt_h0 | bt_l4 | bt_l3 | bt_l2 | bt_l1 | bt_l0 | vb_h9 | vb_h8 - * |.......|.......|.......|.......|.......|.......|.......|....... - * | vb_h7 | vb_h6 | vb_h5 | vb_h4 | vb_h3 | vb_h2 | vb_h1 | vb_h0 - * |.......|.......|.......|.......|.......|.......|.......|....... - * | vb_l5 | vb_l4 | vb_l3 | vb_l2 | vb_l1 | vb_l0 | - * |.......|.......|.......|.......|.......|.......|.......|....... - * - * Data bits 8540: - * OTP2 - * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 - * |.......|.......|.......|.......|.......|.......|.......|....... - * | - * |.......|.......|.......|.......|.......|.......|.......|....... - * | vm_h9 | vm_h8 | vm_h7 | vm_h6 | vm_h5 | vm_h4 | vm_h3 | vm_h2 - * |.......|.......|.......|.......|.......|.......|.......|....... - * | vm_h1 | vm_h0 | vm_l4 | vm_l3 | vm_l2 | vm_l1 | vm_l0 | bt_h9 - * |.......|.......|.......|.......|.......|.......|.......|....... - * | bt_h8 | bt_h7 | bt_h6 | bt_h5 | bt_h4 | bt_h3 | bt_h2 | bt_h1 - * |.......|.......|.......|.......|.......|.......|.......|....... - * | bt_h0 | bt_l4 | bt_l3 | bt_l2 | bt_l1 | bt_l0 | vb_h9 | vb_h8 - * |.......|.......|.......|.......|.......|.......|.......|....... - * | vb_h7 | vb_h6 | vb_h5 | vb_h4 | vb_h3 | vb_h2 | vb_h1 | vb_h0 - * |.......|.......|.......|.......|.......|.......|.......|....... - * | vb_l5 | vb_l4 | vb_l3 | vb_l2 | vb_l1 | vb_l0 | - * |.......|.......|.......|.......|.......|.......|.......|....... - * - * Data bits 8540: - * OTP4 - * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 - * |.......|.......|.......|.......|.......|.......|.......|....... - * | | ib_h9 | ib_h8 | ib_h7 - * |.......|.......|.......|.......|.......|.......|.......|....... - * | ib_h6 | ib_h5 | ib_h4 | ib_h3 | ib_h2 | ib_h1 | ib_h0 | ib_l5 - * |.......|.......|.......|.......|.......|.......|.......|....... - * | ib_l4 | ib_l3 | ib_l2 | ib_l1 | ib_l0 | - * - * - * Ideal output ADC codes corresponding to injected input voltages - * during manufacturing is: - * - * vmain_high: Vin = 19500mV / ADC ideal code = 997 - * vmain_low: Vin = 315mV / ADC ideal code = 16 - * btemp_high: Vin = 1300mV / ADC ideal code = 985 - * btemp_low: Vin = 21mV / ADC ideal code = 16 - * vbat_high: Vin = 4700mV / ADC ideal code = 982 - * vbat_low: Vin = 2380mV / ADC ideal code = 33 - */ - - if (is_ab8540(ab8500)) { - /* Calculate gain and offset for VMAIN if all reads succeeded*/ - if (!(ret[1] < 0 || ret[2] < 0)) { - vmain_high = (((gpadc_cal[1] & 0xFF) << 2) | - ((gpadc_cal[2] & 0xC0) >> 6)); - vmain_low = ((gpadc_cal[2] & 0x3E) >> 1); - - gpadc->cal_data[ADC_INPUT_VMAIN].otp_calib_hi = - (u16)vmain_high; - gpadc->cal_data[ADC_INPUT_VMAIN].otp_calib_lo = - (u16)vmain_low; - - gpadc->cal_data[ADC_INPUT_VMAIN].gain = CALIB_SCALE * - (19500 - 315) / (vmain_high - vmain_low); - gpadc->cal_data[ADC_INPUT_VMAIN].offset = CALIB_SCALE * - 19500 - (CALIB_SCALE * (19500 - 315) / - (vmain_high - vmain_low)) * vmain_high; - } else { - gpadc->cal_data[ADC_INPUT_VMAIN].gain = 0; - } - - /* Read IBAT calibration Data */ - for (i = 0; i < ARRAY_SIZE(otp4_cal_regs); i++) { - ret_otp4[i] = abx500_get_register_interruptible( - gpadc->dev, AB8500_OTP_EMUL, - otp4_cal_regs[i], &gpadc_otp4[i]); - if (ret_otp4[i] < 0) - dev_err(gpadc->dev, - "%s: read otp4 reg 0x%02x failed\n", - __func__, otp4_cal_regs[i]); - } - - /* Calculate gain and offset for IBAT if all reads succeeded */ - if (!(ret_otp4[0] < 0 || ret_otp4[1] < 0 || ret_otp4[2] < 0)) { - ibat_high = (((gpadc_otp4[0] & 0x07) << 7) | - ((gpadc_otp4[1] & 0xFE) >> 1)); - ibat_low = (((gpadc_otp4[1] & 0x01) << 5) | - ((gpadc_otp4[2] & 0xF8) >> 3)); - - gpadc->cal_data[ADC_INPUT_IBAT].otp_calib_hi = - (u16)ibat_high; - gpadc->cal_data[ADC_INPUT_IBAT].otp_calib_lo = - (u16)ibat_low; - - V_gain = ((IBAT_VDROP_H - IBAT_VDROP_L) - << CALIB_SHIFT_IBAT) / (ibat_high - ibat_low); - - V_offset = (IBAT_VDROP_H << CALIB_SHIFT_IBAT) - - (((IBAT_VDROP_H - IBAT_VDROP_L) << - CALIB_SHIFT_IBAT) / (ibat_high - ibat_low)) - * ibat_high; - /* - * Result obtained is in mV (at a scale factor), - * we need to calculate gain and offset to get mA - */ - V2A_gain = (ADC_CH_IBAT_MAX - ADC_CH_IBAT_MIN)/ - (ADC_CH_IBAT_MAX_V - ADC_CH_IBAT_MIN_V); - V2A_offset = ((ADC_CH_IBAT_MAX_V * ADC_CH_IBAT_MIN - - ADC_CH_IBAT_MAX * ADC_CH_IBAT_MIN_V) - << CALIB_SHIFT_IBAT) - / (ADC_CH_IBAT_MAX_V - ADC_CH_IBAT_MIN_V); - - gpadc->cal_data[ADC_INPUT_IBAT].gain = - V_gain * V2A_gain; - gpadc->cal_data[ADC_INPUT_IBAT].offset = - V_offset * V2A_gain + V2A_offset; - } else { - gpadc->cal_data[ADC_INPUT_IBAT].gain = 0; - } - - dev_dbg(gpadc->dev, "IBAT gain %llu offset %llu\n", - gpadc->cal_data[ADC_INPUT_IBAT].gain, - gpadc->cal_data[ADC_INPUT_IBAT].offset); - } else { - /* Calculate gain and offset for VMAIN if all reads succeeded */ - if (!(ret[0] < 0 || ret[1] < 0 || ret[2] < 0)) { - vmain_high = (((gpadc_cal[0] & 0x03) << 8) | - ((gpadc_cal[1] & 0x3F) << 2) | - ((gpadc_cal[2] & 0xC0) >> 6)); - vmain_low = ((gpadc_cal[2] & 0x3E) >> 1); - - gpadc->cal_data[ADC_INPUT_VMAIN].otp_calib_hi = - (u16)vmain_high; - gpadc->cal_data[ADC_INPUT_VMAIN].otp_calib_lo = - (u16)vmain_low; - - gpadc->cal_data[ADC_INPUT_VMAIN].gain = CALIB_SCALE * - (19500 - 315) / (vmain_high - vmain_low); - - gpadc->cal_data[ADC_INPUT_VMAIN].offset = CALIB_SCALE * - 19500 - (CALIB_SCALE * (19500 - 315) / - (vmain_high - vmain_low)) * vmain_high; - } else { - gpadc->cal_data[ADC_INPUT_VMAIN].gain = 0; - } - } - - /* Calculate gain and offset for BTEMP if all reads succeeded */ - if (!(ret[2] < 0 || ret[3] < 0 || ret[4] < 0)) { - btemp_high = (((gpadc_cal[2] & 0x01) << 9) | - (gpadc_cal[3] << 1) | ((gpadc_cal[4] & 0x80) >> 7)); - btemp_low = ((gpadc_cal[4] & 0x7C) >> 2); - - gpadc->cal_data[ADC_INPUT_BTEMP].otp_calib_hi = (u16)btemp_high; - gpadc->cal_data[ADC_INPUT_BTEMP].otp_calib_lo = (u16)btemp_low; - - gpadc->cal_data[ADC_INPUT_BTEMP].gain = - CALIB_SCALE * (1300 - 21) / (btemp_high - btemp_low); - gpadc->cal_data[ADC_INPUT_BTEMP].offset = CALIB_SCALE * 1300 - - (CALIB_SCALE * (1300 - 21) / (btemp_high - btemp_low)) - * btemp_high; - } else { - gpadc->cal_data[ADC_INPUT_BTEMP].gain = 0; - } - - /* Calculate gain and offset for VBAT if all reads succeeded */ - if (!(ret[4] < 0 || ret[5] < 0 || ret[6] < 0)) { - vbat_high = (((gpadc_cal[4] & 0x03) << 8) | gpadc_cal[5]); - vbat_low = ((gpadc_cal[6] & 0xFC) >> 2); - - gpadc->cal_data[ADC_INPUT_VBAT].otp_calib_hi = (u16)vbat_high; - gpadc->cal_data[ADC_INPUT_VBAT].otp_calib_lo = (u16)vbat_low; - - gpadc->cal_data[ADC_INPUT_VBAT].gain = CALIB_SCALE * - (4700 - 2380) / (vbat_high - vbat_low); - gpadc->cal_data[ADC_INPUT_VBAT].offset = CALIB_SCALE * 4700 - - (CALIB_SCALE * (4700 - 2380) / - (vbat_high - vbat_low)) * vbat_high; - } else { - gpadc->cal_data[ADC_INPUT_VBAT].gain = 0; - } - - dev_dbg(gpadc->dev, "VMAIN gain %llu offset %llu\n", - gpadc->cal_data[ADC_INPUT_VMAIN].gain, - gpadc->cal_data[ADC_INPUT_VMAIN].offset); - - dev_dbg(gpadc->dev, "BTEMP gain %llu offset %llu\n", - gpadc->cal_data[ADC_INPUT_BTEMP].gain, - gpadc->cal_data[ADC_INPUT_BTEMP].offset); - - dev_dbg(gpadc->dev, "VBAT gain %llu offset %llu\n", - gpadc->cal_data[ADC_INPUT_VBAT].gain, - gpadc->cal_data[ADC_INPUT_VBAT].offset); -} - -#ifdef CONFIG_PM -static int ab8500_gpadc_runtime_suspend(struct device *dev) -{ - struct ab8500_gpadc *gpadc = dev_get_drvdata(dev); - - regulator_disable(gpadc->regu); - return 0; -} - -static int ab8500_gpadc_runtime_resume(struct device *dev) -{ - struct ab8500_gpadc *gpadc = dev_get_drvdata(dev); - int ret; - - ret = regulator_enable(gpadc->regu); - if (ret) - dev_err(dev, "Failed to enable vtvout LDO: %d\n", ret); - return ret; -} -#endif - -#ifdef CONFIG_PM_SLEEP -static int ab8500_gpadc_suspend(struct device *dev) -{ - struct ab8500_gpadc *gpadc = dev_get_drvdata(dev); - - mutex_lock(&gpadc->ab8500_gpadc_lock); - - pm_runtime_get_sync(dev); - - regulator_disable(gpadc->regu); - return 0; -} - -static int ab8500_gpadc_resume(struct device *dev) -{ - struct ab8500_gpadc *gpadc = dev_get_drvdata(dev); - int ret; - - ret = regulator_enable(gpadc->regu); - if (ret) - dev_err(dev, "Failed to enable vtvout LDO: %d\n", ret); - - pm_runtime_mark_last_busy(gpadc->dev); - pm_runtime_put_autosuspend(gpadc->dev); - - mutex_unlock(&gpadc->ab8500_gpadc_lock); - return ret; -} -#endif - -static int ab8500_gpadc_probe(struct platform_device *pdev) -{ - int ret = 0; - struct ab8500_gpadc *gpadc; - - gpadc = devm_kzalloc(&pdev->dev, - sizeof(struct ab8500_gpadc), GFP_KERNEL); - if (!gpadc) - return -ENOMEM; - - gpadc->irq_sw = platform_get_irq_byname(pdev, "SW_CONV_END"); - if (gpadc->irq_sw < 0) - dev_err(gpadc->dev, "failed to get platform sw_conv_end irq\n"); - - gpadc->irq_hw = platform_get_irq_byname(pdev, "HW_CONV_END"); - if (gpadc->irq_hw < 0) - dev_err(gpadc->dev, "failed to get platform hw_conv_end irq\n"); - - gpadc->dev = &pdev->dev; - gpadc->parent = dev_get_drvdata(pdev->dev.parent); - mutex_init(&gpadc->ab8500_gpadc_lock); - - /* Initialize completion used to notify completion of conversion */ - init_completion(&gpadc->ab8500_gpadc_complete); - - /* Register interrupts */ - if (gpadc->irq_sw >= 0) { - ret = request_threaded_irq(gpadc->irq_sw, NULL, - ab8500_bm_gpadcconvend_handler, - IRQF_NO_SUSPEND | IRQF_SHARED | IRQF_ONESHOT, - "ab8500-gpadc-sw", - gpadc); - if (ret < 0) { - dev_err(gpadc->dev, - "Failed to register interrupt irq: %d\n", - gpadc->irq_sw); - goto fail; - } - } - - if (gpadc->irq_hw >= 0) { - ret = request_threaded_irq(gpadc->irq_hw, NULL, - ab8500_bm_gpadcconvend_handler, - IRQF_NO_SUSPEND | IRQF_SHARED | IRQF_ONESHOT, - "ab8500-gpadc-hw", - gpadc); - if (ret < 0) { - dev_err(gpadc->dev, - "Failed to register interrupt irq: %d\n", - gpadc->irq_hw); - goto fail_irq; - } - } - - /* VTVout LDO used to power up ab8500-GPADC */ - gpadc->regu = devm_regulator_get(&pdev->dev, "vddadc"); - if (IS_ERR(gpadc->regu)) { - ret = PTR_ERR(gpadc->regu); - dev_err(gpadc->dev, "failed to get vtvout LDO\n"); - goto fail_irq; - } - - platform_set_drvdata(pdev, gpadc); - - ret = regulator_enable(gpadc->regu); - if (ret) { - dev_err(gpadc->dev, "Failed to enable vtvout LDO: %d\n", ret); - goto fail_enable; - } - - pm_runtime_set_autosuspend_delay(gpadc->dev, GPADC_AUDOSUSPEND_DELAY); - pm_runtime_use_autosuspend(gpadc->dev); - pm_runtime_set_active(gpadc->dev); - pm_runtime_enable(gpadc->dev); - - ab8500_gpadc_read_calibration_data(gpadc); - list_add_tail(&gpadc->node, &ab8500_gpadc_list); - dev_dbg(gpadc->dev, "probe success\n"); - - return 0; - -fail_enable: -fail_irq: - free_irq(gpadc->irq_sw, gpadc); - free_irq(gpadc->irq_hw, gpadc); -fail: - return ret; -} - -static int ab8500_gpadc_remove(struct platform_device *pdev) -{ - struct ab8500_gpadc *gpadc = platform_get_drvdata(pdev); - - /* remove this gpadc entry from the list */ - list_del(&gpadc->node); - /* remove interrupt - completion of Sw ADC conversion */ - if (gpadc->irq_sw >= 0) - free_irq(gpadc->irq_sw, gpadc); - if (gpadc->irq_hw >= 0) - free_irq(gpadc->irq_hw, gpadc); - - pm_runtime_get_sync(gpadc->dev); - pm_runtime_disable(gpadc->dev); - - regulator_disable(gpadc->regu); - - pm_runtime_set_suspended(gpadc->dev); - - pm_runtime_put_noidle(gpadc->dev); - - return 0; -} - -static const struct dev_pm_ops ab8500_gpadc_pm_ops = { - SET_RUNTIME_PM_OPS(ab8500_gpadc_runtime_suspend, - ab8500_gpadc_runtime_resume, - NULL) - SET_SYSTEM_SLEEP_PM_OPS(ab8500_gpadc_suspend, - ab8500_gpadc_resume) - -}; - -static struct platform_driver ab8500_gpadc_driver = { - .probe = ab8500_gpadc_probe, - .remove = ab8500_gpadc_remove, - .driver = { - .name = "ab8500-gpadc", - .pm = &ab8500_gpadc_pm_ops, - }, -}; - -static int __init ab8500_gpadc_init(void) -{ - return platform_driver_register(&ab8500_gpadc_driver); -} -subsys_initcall_sync(ab8500_gpadc_init); - -/** - * ab8540_gpadc_get_otp() - returns OTP values - * - */ -void ab8540_gpadc_get_otp(struct ab8500_gpadc *gpadc, - u16 *vmain_l, u16 *vmain_h, u16 *btemp_l, u16 *btemp_h, - u16 *vbat_l, u16 *vbat_h, u16 *ibat_l, u16 *ibat_h) -{ - *vmain_l = gpadc->cal_data[ADC_INPUT_VMAIN].otp_calib_lo; - *vmain_h = gpadc->cal_data[ADC_INPUT_VMAIN].otp_calib_hi; - *btemp_l = gpadc->cal_data[ADC_INPUT_BTEMP].otp_calib_lo; - *btemp_h = gpadc->cal_data[ADC_INPUT_BTEMP].otp_calib_hi; - *vbat_l = gpadc->cal_data[ADC_INPUT_VBAT].otp_calib_lo; - *vbat_h = gpadc->cal_data[ADC_INPUT_VBAT].otp_calib_hi; - *ibat_l = gpadc->cal_data[ADC_INPUT_IBAT].otp_calib_lo; - *ibat_h = gpadc->cal_data[ADC_INPUT_IBAT].otp_calib_hi; -} diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index c84a7b1caeb6..27164a1d3c7c 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -629,7 +629,7 @@ config BATTERY_GAUGE_LTC2941 config AB8500_BM bool "AB8500 Battery Management Driver" - depends on AB8500_CORE && AB8500_GPADC + depends on AB8500_CORE && AB8500_GPADC && (IIO = y) help Say Y to include support for AB8500 battery management. diff --git a/drivers/power/supply/ab8500_btemp.c b/drivers/power/supply/ab8500_btemp.c index 8fe81259bfd9..ad8c51ef8b8b 100644 --- a/drivers/power/supply/ab8500_btemp.c +++ b/drivers/power/supply/ab8500_btemp.c @@ -26,7 +26,7 @@ #include <linux/mfd/abx500.h> #include <linux/mfd/abx500/ab8500.h> #include <linux/mfd/abx500/ab8500-bm.h> -#include <linux/mfd/abx500/ab8500-gpadc.h> +#include <linux/iio/consumer.h> #define VTVOUT_V 1800 @@ -79,7 +79,8 @@ struct ab8500_btemp_ranges { * @bat_temp: Dispatched battery temperature in degree Celsius * @prev_bat_temp Last measured battery temperature in degree Celsius * @parent: Pointer to the struct ab8500 - * @gpadc: Pointer to the struct gpadc + * @adc_btemp_ball: ADC channel for the battery ball temperature + * @adc_bat_ctrl: ADC channel for the battery control * @fg: Pointer to the struct fg * @bm: Platform specific battery management information * @btemp_psy: Structure for BTEMP specific battery properties @@ -96,7 +97,8 @@ struct ab8500_btemp { int bat_temp; int prev_bat_temp; struct ab8500 *parent; - struct ab8500_gpadc *gpadc; + struct iio_channel *btemp_ball; + struct iio_channel *bat_ctrl; struct ab8500_fg *fg; struct abx500_bm_data *bm; struct power_supply *btemp_psy; @@ -177,13 +179,13 @@ static int ab8500_btemp_batctrl_volt_to_res(struct ab8500_btemp *di, */ static int ab8500_btemp_read_batctrl_voltage(struct ab8500_btemp *di) { - int vbtemp; + int vbtemp, ret; static int prev; - vbtemp = ab8500_gpadc_convert(di->gpadc, BAT_CTRL); - if (vbtemp < 0) { + ret = iio_read_channel_processed(di->bat_ctrl, &vbtemp); + if (ret < 0) { dev_err(di->dev, - "%s gpadc conversion failed, using previous value", + "%s ADC conversion failed, using previous value", __func__); return prev; } @@ -455,7 +457,7 @@ static int ab8500_btemp_res_to_temp(struct ab8500_btemp *di, */ static int ab8500_btemp_measure_temp(struct ab8500_btemp *di) { - int temp; + int temp, ret; static int prev; int rbat, rntc, vntc; u8 id; @@ -480,10 +482,10 @@ static int ab8500_btemp_measure_temp(struct ab8500_btemp *di) di->bm->bat_type[id].r_to_t_tbl, di->bm->bat_type[id].n_temp_tbl_elements, rbat); } else { - vntc = ab8500_gpadc_convert(di->gpadc, BTEMP_BALL); - if (vntc < 0) { + ret = iio_read_channel_processed(di->btemp_ball, &vntc); + if (ret < 0) { dev_err(di->dev, - "%s gpadc conversion failed," + "%s ADC conversion failed," " using previous value\n", __func__); return prev; } @@ -1024,7 +1026,22 @@ static int ab8500_btemp_probe(struct platform_device *pdev) /* get parent data */ di->dev = &pdev->dev; di->parent = dev_get_drvdata(pdev->dev.parent); - di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0"); + + /* Get ADC channels */ + di->btemp_ball = devm_iio_channel_get(&pdev->dev, "btemp_ball"); + if (IS_ERR(di->btemp_ball)) { + if (PTR_ERR(di->btemp_ball) == -ENODEV) + return -EPROBE_DEFER; + dev_err(&pdev->dev, "failed to get BTEMP BALL ADC channel\n"); + return PTR_ERR(di->btemp_ball); + } + di->bat_ctrl = devm_iio_channel_get(&pdev->dev, "bat_ctrl"); + if (IS_ERR(di->bat_ctrl)) { + if (PTR_ERR(di->bat_ctrl) == -ENODEV) + return -EPROBE_DEFER; + dev_err(&pdev->dev, "failed to get BAT CTRL ADC channel\n"); + return PTR_ERR(di->bat_ctrl); + } di->initialized = false; diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c index e51d0e72beea..c053ede47eb2 100644 --- a/drivers/power/supply/ab8500_charger.c +++ b/drivers/power/supply/ab8500_charger.c @@ -29,10 +29,10 @@ #include <linux/mfd/abx500/ab8500.h> #include <linux/mfd/abx500.h> #include <linux/mfd/abx500/ab8500-bm.h> -#include <linux/mfd/abx500/ab8500-gpadc.h> #include <linux/mfd/abx500/ux500_chargalg.h> #include <linux/usb/otg.h> #include <linux/mutex.h> +#include <linux/iio/consumer.h> /* Charger constants */ #define NO_PW_CONN 0 @@ -233,7 +233,10 @@ struct ab8500_charger_max_usb_in_curr { * @current_stepping_sessions: * Counter for current stepping sessions * @parent: Pointer to the struct ab8500 - * @gpadc: Pointer to the struct gpadc + * @adc_main_charger_v ADC channel for main charger voltage + * @adc_main_charger_c ADC channel for main charger current + * @adc_vbus_v ADC channel for USB charger voltage + * @adc_usb_charger_c ADC channel for USB charger current * @bm: Platform specific battery management information * @flags: Structure for information about events triggered * @usb_state: Structure for usb stack information @@ -283,7 +286,10 @@ struct ab8500_charger { int is_aca_rid; atomic_t current_stepping_sessions; struct ab8500 *parent; - struct ab8500_gpadc *gpadc; + struct iio_channel *adc_main_charger_v; + struct iio_channel *adc_main_charger_c; + struct iio_channel *adc_vbus_v; + struct iio_channel *adc_usb_charger_c; struct abx500_bm_data *bm; struct ab8500_charger_event_flags flags; struct ab8500_charger_usb_state usb_state; @@ -459,13 +465,13 @@ static void ab8500_charger_set_usb_connected(struct ab8500_charger *di, */ static int ab8500_charger_get_ac_voltage(struct ab8500_charger *di) { - int vch; + int vch, ret; /* Only measure voltage if the charger is connected */ if (di->ac.charger_connected) { - vch = ab8500_gpadc_convert(di->gpadc, MAIN_CHARGER_V); - if (vch < 0) - dev_err(di->dev, "%s gpadc conv failed,\n", __func__); + ret = iio_read_channel_processed(di->adc_main_charger_v, &vch); + if (ret < 0) + dev_err(di->dev, "%s ADC conv failed,\n", __func__); } else { vch = 0; } @@ -510,13 +516,13 @@ static int ab8500_charger_ac_cv(struct ab8500_charger *di) */ static int ab8500_charger_get_vbus_voltage(struct ab8500_charger *di) { - int vch; + int vch, ret; /* Only measure voltage if the charger is connected */ if (di->usb.charger_connected) { - vch = ab8500_gpadc_convert(di->gpadc, VBUS_V); - if (vch < 0) - dev_err(di->dev, "%s gpadc conv failed\n", __func__); + ret = iio_read_channel_processed(di->adc_vbus_v, &vch); + if (ret < 0) + dev_err(di->dev, "%s ADC conv failed,\n", __func__); } else { vch = 0; } @@ -532,13 +538,13 @@ static int ab8500_charger_get_vbus_voltage(struct ab8500_charger *di) */ static int ab8500_charger_get_usb_current(struct ab8500_charger *di) { - int ich; + int ich, ret; /* Only measure current if the charger is online */ if (di->usb.charger_online) { - ich = ab8500_gpadc_convert(di->gpadc, USB_CHARGER_C); - if (ich < 0) - dev_err(di->dev, "%s gpadc conv failed\n", __func__); + ret = iio_read_channel_processed(di->adc_usb_charger_c, &ich); + if (ret < 0) + dev_err(di->dev, "%s ADC conv failed,\n", __func__); } else { ich = 0; } @@ -554,13 +560,13 @@ static int ab8500_charger_get_usb_current(struct ab8500_charger *di) */ static int ab8500_charger_get_ac_current(struct ab8500_charger *di) { - int ich; + int ich, ret; /* Only measure current if the charger is online */ if (di->ac.charger_online) { - ich = ab8500_gpadc_convert(di->gpadc, MAIN_CHARGER_C); - if (ich < 0) - dev_err(di->dev, "%s gpadc conv failed\n", __func__); + ret = iio_read_channel_processed(di->adc_main_charger_c, &ich); + if (ret < 0) + dev_err(di->dev, "%s ADC conv failed,\n", __func__); } else { ich = 0; } @@ -3371,7 +3377,39 @@ static int ab8500_charger_probe(struct platform_device *pdev) /* get parent data */ di->dev = &pdev->dev; di->parent = dev_get_drvdata(pdev->dev.parent); - di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0"); + + /* Get ADC channels */ + di->adc_main_charger_v = devm_iio_channel_get(&pdev->dev, + "main_charger_v"); + if (IS_ERR(di->adc_main_charger_v)) { + if (PTR_ERR(di->adc_main_charger_v) == -ENODEV) + return -EPROBE_DEFER; + dev_err(&pdev->dev, "failed to get ADC main charger voltage\n"); + return PTR_ERR(di->adc_main_charger_v); + } + di->adc_main_charger_c = devm_iio_channel_get(&pdev->dev, + "main_charger_c"); + if (IS_ERR(di->adc_main_charger_c)) { + if (PTR_ERR(di->adc_main_charger_c) == -ENODEV) + return -EPROBE_DEFER; + dev_err(&pdev->dev, "failed to get ADC main charger current\n"); + return PTR_ERR(di->adc_main_charger_v); + } + di->adc_vbus_v = devm_iio_channel_get(&pdev->dev, "vbus_v"); + if (IS_ERR(di->adc_vbus_v)) { + if (PTR_ERR(di->adc_vbus_v) == -ENODEV) + return -EPROBE_DEFER; + dev_err(&pdev->dev, "failed to get ADC USB charger voltage\n"); + return PTR_ERR(di->adc_vbus_v); + } + di->adc_usb_charger_c = devm_iio_channel_get(&pdev->dev, + "usb_charger_c"); + if (IS_ERR(di->adc_usb_charger_c)) { + if (PTR_ERR(di->adc_usb_charger_c) == -ENODEV) + return -EPROBE_DEFER; + dev_err(&pdev->dev, "failed to get ADC USB charger current\n"); + return PTR_ERR(di->adc_usb_charger_c); + } /* initialize lock */ spin_lock_init(&di->usb_state.usb_lock); diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c index 6fc4bc30644c..f7909dfd3b61 100644 --- a/drivers/power/supply/ab8500_fg.c +++ b/drivers/power/supply/ab8500_fg.c @@ -32,7 +32,7 @@ #include <linux/mfd/abx500.h> #include <linux/mfd/abx500/ab8500.h> #include <linux/mfd/abx500/ab8500-bm.h> -#include <linux/mfd/abx500/ab8500-gpadc.h> +#include <linux/iio/consumer.h> #include <linux/kernel.h> #define MILLI_TO_MICRO 1000 @@ -182,7 +182,7 @@ struct inst_curr_result_list { * @bat_cap: Structure for battery capacity specific parameters * @avg_cap: Average capacity filter * @parent: Pointer to the struct ab8500 - * @gpadc: Pointer to the struct gpadc + * @main_bat_v: ADC channel for the main battery voltage * @bm: Platform specific battery management information * @fg_psy: Structure that holds the FG specific battery properties * @fg_wq: Work queue for running the FG algorithm @@ -224,7 +224,7 @@ struct ab8500_fg { struct ab8500_fg_battery_capacity bat_cap; struct ab8500_fg_avg_cap avg_cap; struct ab8500 *parent; - struct ab8500_gpadc *gpadc; + struct iio_channel *main_bat_v; struct abx500_bm_data *bm; struct power_supply *fg_psy; struct workqueue_struct *fg_wq; @@ -829,13 +829,13 @@ exit: */ static int ab8500_fg_bat_voltage(struct ab8500_fg *di) { - int vbat; + int vbat, ret; static int prev; - vbat = ab8500_gpadc_convert(di->gpadc, MAIN_BAT_V); - if (vbat < 0) { + ret = iio_read_channel_processed(di->main_bat_v, &vbat); + if (ret < 0) { dev_err(di->dev, - "%s gpadc conversion failed, using previous value\n", + "%s ADC conversion failed, using previous value\n", __func__); return prev; } @@ -3066,7 +3066,14 @@ static int ab8500_fg_probe(struct platform_device *pdev) /* get parent data */ di->dev = &pdev->dev; di->parent = dev_get_drvdata(pdev->dev.parent); - di->gpadc = ab8500_gpadc_get("ab8500-gpadc.0"); + + di->main_bat_v = devm_iio_channel_get(&pdev->dev, "main_bat_v"); + if (IS_ERR(di->main_bat_v)) { + if (PTR_ERR(di->main_bat_v) == -ENODEV) + return -EPROBE_DEFER; + dev_err(&pdev->dev, "failed to get main battery ADC channel\n"); + return PTR_ERR(di->main_bat_v); + } psy_cfg.supplied_to = supply_interface; psy_cfg.num_supplicants = ARRAY_SIZE(supply_interface); diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index e3a2518503ed..bd21655c37a6 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -508,15 +508,6 @@ config PWM_TIEHRPWM To compile this driver as a module, choose M here: the module will be called pwm-tiehrpwm. -config PWM_TIPWMSS - bool - default y if (ARCH_OMAP2PLUS) && (PWM_TIECAP || PWM_TIEHRPWM) - help - PWM Subsystem driver support for AM33xx SOC. - - PWM submodules require PWM config space access from submodule - drivers and require common parent driver support. - config PWM_TWL tristate "TWL4030/6030 PWM support" depends on TWL4030_CORE diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index 26326adf71d7..9a475073dafc 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -50,7 +50,6 @@ obj-$(CONFIG_PWM_SUN4I) += pwm-sun4i.o obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o obj-$(CONFIG_PWM_TIEHRPWM) += pwm-tiehrpwm.o -obj-$(CONFIG_PWM_TIPWMSS) += pwm-tipwmss.o obj-$(CONFIG_PWM_TWL) += pwm-twl.o obj-$(CONFIG_PWM_TWL_LED) += pwm-twl-led.o obj-$(CONFIG_PWM_VT8500) += pwm-vt8500.o diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 927d29eb92c6..0f19b086865a 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -127,4 +127,6 @@ source "drivers/staging/qlge/Kconfig" source "drivers/staging/vboxsf/Kconfig" +source "drivers/staging/wfx/Kconfig" + endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index f01f04199073..b7c31b9fe044 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -54,3 +54,4 @@ obj-$(CONFIG_USB_WUSB) += wusbcore/ obj-$(CONFIG_EXFAT_FS) += exfat/ obj-$(CONFIG_QLGE) += qlge/ obj-$(CONFIG_VBOXSF_FS) += vboxsf/ +obj-$(CONFIG_WFX) += wfx/ diff --git a/drivers/staging/axis-fifo/axis-fifo.c b/drivers/staging/axis-fifo/axis-fifo.c index 805437fa249a..39e6c59df1e9 100644 --- a/drivers/staging/axis-fifo/axis-fifo.c +++ b/drivers/staging/axis-fifo/axis-fifo.c @@ -125,7 +125,6 @@ MODULE_PARM_DESC(write_timeout, "ms to wait before blocking write() timing out; struct axis_fifo { int irq; /* interrupt */ - struct resource *mem; /* physical memory */ void __iomem *base_addr; /* kernel space memory */ unsigned int rx_fifo_depth; /* max words in the receive fifo */ @@ -701,6 +700,68 @@ static int get_dts_property(struct axis_fifo *fifo, return 0; } +static int axis_fifo_parse_dt(struct axis_fifo *fifo) +{ + int ret; + unsigned int value; + + ret = get_dts_property(fifo, "xlnx,axi-str-rxd-tdata-width", &value); + if (ret) { + dev_err(fifo->dt_device, "missing xlnx,axi-str-rxd-tdata-width property\n"); + goto end; + } else if (value != 32) { + dev_err(fifo->dt_device, "xlnx,axi-str-rxd-tdata-width only supports 32 bits\n"); + ret = -EIO; + goto end; + } + + ret = get_dts_property(fifo, "xlnx,axi-str-txd-tdata-width", &value); + if (ret) { + dev_err(fifo->dt_device, "missing xlnx,axi-str-txd-tdata-width property\n"); + goto end; + } else if (value != 32) { + dev_err(fifo->dt_device, "xlnx,axi-str-txd-tdata-width only supports 32 bits\n"); + ret = -EIO; + goto end; + } + + ret = get_dts_property(fifo, "xlnx,rx-fifo-depth", + &fifo->rx_fifo_depth); + if (ret) { + dev_err(fifo->dt_device, "missing xlnx,rx-fifo-depth property\n"); + ret = -EIO; + goto end; + } + + ret = get_dts_property(fifo, "xlnx,tx-fifo-depth", + &fifo->tx_fifo_depth); + if (ret) { + dev_err(fifo->dt_device, "missing xlnx,tx-fifo-depth property\n"); + ret = -EIO; + goto end; + } + + /* IP sets TDFV to fifo depth - 4 so we will do the same */ + fifo->tx_fifo_depth -= 4; + + ret = get_dts_property(fifo, "xlnx,use-rx-data", &fifo->has_rx_fifo); + if (ret) { + dev_err(fifo->dt_device, "missing xlnx,use-rx-data property\n"); + ret = -EIO; + goto end; + } + + ret = get_dts_property(fifo, "xlnx,use-tx-data", &fifo->has_tx_fifo); + if (ret) { + dev_err(fifo->dt_device, "missing xlnx,use-tx-data property\n"); + ret = -EIO; + goto end; + } + +end: + return ret; +} + static int axis_fifo_probe(struct platform_device *pdev) { struct resource *r_irq; /* interrupt resources */ @@ -712,34 +773,6 @@ static int axis_fifo_probe(struct platform_device *pdev) int rc = 0; /* error return value */ - /* IP properties from device tree */ - unsigned int rxd_tdata_width; - unsigned int txc_tdata_width; - unsigned int txd_tdata_width; - unsigned int tdest_width; - unsigned int tid_width; - unsigned int tuser_width; - unsigned int data_interface_type; - unsigned int has_tdest; - unsigned int has_tid; - unsigned int has_tkeep; - unsigned int has_tstrb; - unsigned int has_tuser; - unsigned int rx_fifo_depth; - unsigned int rx_programmable_empty_threshold; - unsigned int rx_programmable_full_threshold; - unsigned int axi_id_width; - unsigned int axi4_data_width; - unsigned int select_xpm; - unsigned int tx_fifo_depth; - unsigned int tx_programmable_empty_threshold; - unsigned int tx_programmable_full_threshold; - unsigned int use_rx_cut_through; - unsigned int use_rx_data; - unsigned int use_tx_control; - unsigned int use_tx_cut_through; - unsigned int use_tx_data; - /* ---------------------------- * init wrapper device * ---------------------------- @@ -772,32 +805,19 @@ static int axis_fifo_probe(struct platform_device *pdev) goto err_initial; } - fifo->mem = r_mem; - /* request physical memory */ - if (!request_mem_region(fifo->mem->start, resource_size(fifo->mem), - DRIVER_NAME)) { - dev_err(fifo->dt_device, - "couldn't lock memory region at 0x%pa\n", - &fifo->mem->start); - rc = -EBUSY; + fifo->base_addr = devm_ioremap_resource(fifo->dt_device, r_mem); + if (IS_ERR(fifo->base_addr)) { + rc = PTR_ERR(fifo->base_addr); + dev_err(fifo->dt_device, "can't remap IO resource (%d)\n", rc); goto err_initial; } - dev_dbg(fifo->dt_device, "got memory location [0x%pa - 0x%pa]\n", - &fifo->mem->start, &fifo->mem->end); - - /* map physical memory to kernel virtual address space */ - fifo->base_addr = ioremap(fifo->mem->start, resource_size(fifo->mem)); - if (!fifo->base_addr) { - dev_err(fifo->dt_device, "couldn't map physical memory\n"); - rc = -ENOMEM; - goto err_mem; - } + dev_dbg(fifo->dt_device, "remapped memory to 0x%p\n", fifo->base_addr); /* create unique device name */ snprintf(device_name, sizeof(device_name), "%s_%pa", - DRIVER_NAME, &fifo->mem->start); + DRIVER_NAME, &r_mem->start); dev_dbg(fifo->dt_device, "device name [%s]\n", device_name); @@ -806,164 +826,9 @@ static int axis_fifo_probe(struct platform_device *pdev) * ---------------------------- */ - /* retrieve device tree properties */ - rc = get_dts_property(fifo, "xlnx,axi-str-rxd-tdata-width", - &rxd_tdata_width); - if (rc) - goto err_unmap; - rc = get_dts_property(fifo, "xlnx,axi-str-txc-tdata-width", - &txc_tdata_width); - if (rc) - goto err_unmap; - rc = get_dts_property(fifo, "xlnx,axi-str-txd-tdata-width", - &txd_tdata_width); - if (rc) - goto err_unmap; - rc = get_dts_property(fifo, "xlnx,axis-tdest-width", &tdest_width); - if (rc) - goto err_unmap; - rc = get_dts_property(fifo, "xlnx,axis-tid-width", &tid_width); - if (rc) - goto err_unmap; - rc = get_dts_property(fifo, "xlnx,axis-tuser-width", &tuser_width); - if (rc) - goto err_unmap; - rc = get_dts_property(fifo, "xlnx,data-interface-type", - &data_interface_type); - if (rc) - goto err_unmap; - rc = get_dts_property(fifo, "xlnx,has-axis-tdest", &has_tdest); - if (rc) - goto err_unmap; - rc = get_dts_property(fifo, "xlnx,has-axis-tid", &has_tid); - if (rc) - goto err_unmap; - rc = get_dts_property(fifo, "xlnx,has-axis-tkeep", &has_tkeep); - if (rc) - goto err_unmap; - rc = get_dts_property(fifo, "xlnx,has-axis-tstrb", &has_tstrb); - if (rc) - goto err_unmap; - rc = get_dts_property(fifo, "xlnx,has-axis-tuser", &has_tuser); - if (rc) - goto err_unmap; - rc = get_dts_property(fifo, "xlnx,rx-fifo-depth", &rx_fifo_depth); - if (rc) - goto err_unmap; - rc = get_dts_property(fifo, "xlnx,rx-fifo-pe-threshold", - &rx_programmable_empty_threshold); - if (rc) - goto err_unmap; - rc = get_dts_property(fifo, "xlnx,rx-fifo-pf-threshold", - &rx_programmable_full_threshold); - if (rc) - goto err_unmap; - rc = get_dts_property(fifo, "xlnx,s-axi-id-width", &axi_id_width); - if (rc) - goto err_unmap; - rc = get_dts_property(fifo, "xlnx,s-axi4-data-width", &axi4_data_width); - if (rc) - goto err_unmap; - rc = get_dts_property(fifo, "xlnx,select-xpm", &select_xpm); + rc = axis_fifo_parse_dt(fifo); if (rc) - goto err_unmap; - rc = get_dts_property(fifo, "xlnx,tx-fifo-depth", &tx_fifo_depth); - if (rc) - goto err_unmap; - rc = get_dts_property(fifo, "xlnx,tx-fifo-pe-threshold", - &tx_programmable_empty_threshold); - if (rc) - goto err_unmap; - rc = get_dts_property(fifo, "xlnx,tx-fifo-pf-threshold", - &tx_programmable_full_threshold); - if (rc) - goto err_unmap; - rc = get_dts_property(fifo, "xlnx,use-rx-cut-through", - &use_rx_cut_through); - if (rc) - goto err_unmap; - rc = get_dts_property(fifo, "xlnx,use-rx-data", &use_rx_data); - if (rc) - goto err_unmap; - rc = get_dts_property(fifo, "xlnx,use-tx-ctrl", &use_tx_control); - if (rc) - goto err_unmap; - rc = get_dts_property(fifo, "xlnx,use-tx-cut-through", - &use_tx_cut_through); - if (rc) - goto err_unmap; - rc = get_dts_property(fifo, "xlnx,use-tx-data", &use_tx_data); - if (rc) - goto err_unmap; - - /* check validity of device tree properties */ - if (rxd_tdata_width != 32) { - dev_err(fifo->dt_device, - "rxd_tdata_width width [%u] unsupported\n", - rxd_tdata_width); - rc = -EIO; - goto err_unmap; - } - if (txd_tdata_width != 32) { - dev_err(fifo->dt_device, - "txd_tdata_width width [%u] unsupported\n", - txd_tdata_width); - rc = -EIO; - goto err_unmap; - } - if (has_tdest) { - dev_err(fifo->dt_device, "tdest not supported\n"); - rc = -EIO; - goto err_unmap; - } - if (has_tid) { - dev_err(fifo->dt_device, "tid not supported\n"); - rc = -EIO; - goto err_unmap; - } - if (has_tkeep) { - dev_err(fifo->dt_device, "tkeep not supported\n"); - rc = -EIO; - goto err_unmap; - } - if (has_tstrb) { - dev_err(fifo->dt_device, "tstrb not supported\n"); - rc = -EIO; - goto err_unmap; - } - if (has_tuser) { - dev_err(fifo->dt_device, "tuser not supported\n"); - rc = -EIO; - goto err_unmap; - } - if (use_rx_cut_through) { - dev_err(fifo->dt_device, "rx cut-through not supported\n"); - rc = -EIO; - goto err_unmap; - } - if (use_tx_cut_through) { - dev_err(fifo->dt_device, "tx cut-through not supported\n"); - rc = -EIO; - goto err_unmap; - } - if (use_tx_control) { - dev_err(fifo->dt_device, "tx control not supported\n"); - rc = -EIO; - goto err_unmap; - } - - /* TODO - * these exist in the device tree but it's unclear what they do - * - select-xpm - * - data-interface-type - */ - - /* set device wrapper properties based on IP config */ - fifo->rx_fifo_depth = rx_fifo_depth; - /* IP sets TDFV to fifo depth - 4 so we will do the same */ - fifo->tx_fifo_depth = tx_fifo_depth - 4; - fifo->has_rx_fifo = use_rx_data; - fifo->has_tx_fifo = use_tx_data; + goto err_initial; reset_ip_core(fifo); @@ -976,18 +841,19 @@ static int axis_fifo_probe(struct platform_device *pdev) r_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!r_irq) { dev_err(fifo->dt_device, "no IRQ found for 0x%pa\n", - &fifo->mem->start); + &r_mem->start); rc = -EIO; - goto err_unmap; + goto err_initial; } /* request IRQ */ fifo->irq = r_irq->start; - rc = request_irq(fifo->irq, &axis_fifo_irq, 0, DRIVER_NAME, fifo); + rc = devm_request_irq(fifo->dt_device, fifo->irq, &axis_fifo_irq, 0, + DRIVER_NAME, fifo); if (rc) { dev_err(fifo->dt_device, "couldn't allocate interrupt %i\n", fifo->irq); - goto err_unmap; + goto err_initial; } /* ---------------------------- @@ -998,7 +864,7 @@ static int axis_fifo_probe(struct platform_device *pdev) /* allocate device number */ rc = alloc_chrdev_region(&fifo->devt, 0, 1, DRIVER_NAME); if (rc < 0) - goto err_irq; + goto err_initial; dev_dbg(fifo->dt_device, "allocated device number major %i minor %i\n", MAJOR(fifo->devt), MINOR(fifo->devt)); @@ -1022,14 +888,14 @@ static int axis_fifo_probe(struct platform_device *pdev) } /* create sysfs entries */ - rc = sysfs_create_group(&fifo->device->kobj, &axis_fifo_attrs_group); + rc = devm_device_add_group(fifo->device, &axis_fifo_attrs_group); if (rc < 0) { dev_err(fifo->dt_device, "couldn't register sysfs group\n"); goto err_cdev; } dev_info(fifo->dt_device, "axis-fifo created at %pa mapped to 0x%pa, irq=%i, major=%i, minor=%i\n", - &fifo->mem->start, &fifo->base_addr, fifo->irq, + &r_mem->start, &fifo->base_addr, fifo->irq, MAJOR(fifo->devt), MINOR(fifo->devt)); return 0; @@ -1040,12 +906,6 @@ err_dev: device_destroy(axis_fifo_driver_class, fifo->devt); err_chrdev_region: unregister_chrdev_region(fifo->devt, 1); -err_irq: - free_irq(fifo->irq, fifo); -err_unmap: - iounmap(fifo->base_addr); -err_mem: - release_mem_region(fifo->mem->start, resource_size(fifo->mem)); err_initial: dev_set_drvdata(dev, NULL); return rc; @@ -1056,15 +916,12 @@ static int axis_fifo_remove(struct platform_device *pdev) struct device *dev = &pdev->dev; struct axis_fifo *fifo = dev_get_drvdata(dev); - sysfs_remove_group(&fifo->device->kobj, &axis_fifo_attrs_group); cdev_del(&fifo->char_device); dev_set_drvdata(fifo->device, NULL); device_destroy(axis_fifo_driver_class, fifo->devt); unregister_chrdev_region(fifo->devt, 1); - free_irq(fifo->irq, fifo); - iounmap(fifo->base_addr); - release_mem_region(fifo->mem->start, resource_size(fifo->mem)); dev_set_drvdata(dev, NULL); + return 0; } diff --git a/drivers/staging/axis-fifo/axis-fifo.txt b/drivers/staging/axis-fifo/axis-fifo.txt index 85d88c010e72..5828e1b8e822 100644 --- a/drivers/staging/axis-fifo/axis-fifo.txt +++ b/drivers/staging/axis-fifo/axis-fifo.txt @@ -25,10 +25,10 @@ Required properties: - xlnx,axi-str-txc-tdata-width: Should be <0x20> - xlnx,axi-str-txd-protocol: Should be "XIL_AXI_STREAM_ETH_DATA" - xlnx,axi-str-txd-tdata-width: Should be <0x20> -- xlnx,axis-tdest-width: AXI-Stream TDEST width -- xlnx,axis-tid-width: AXI-Stream TID width -- xlnx,axis-tuser-width: AXI-Stream TUSER width -- xlnx,data-interface-type: Should be <0x0> +- xlnx,axis-tdest-width: AXI-Stream TDEST width (ignored by the driver) +- xlnx,axis-tid-width: AXI-Stream TID width (ignored by the driver) +- xlnx,axis-tuser-width: AXI-Stream TUSER width (ignored by the driver) +- xlnx,data-interface-type: Should be <0x0> (ignored by the driver) - xlnx,has-axis-tdest: Should be <0x0> (this feature isn't supported) - xlnx,has-axis-tid: Should be <0x0> (this feature isn't supported) - xlnx,has-axis-tkeep: Should be <0x0> (this feature isn't supported) @@ -36,13 +36,17 @@ Required properties: - xlnx,has-axis-tuser: Should be <0x0> (this feature isn't supported) - xlnx,rx-fifo-depth: Depth of RX FIFO in words - xlnx,rx-fifo-pe-threshold: RX programmable empty interrupt threshold + (ignored by the driver) - xlnx,rx-fifo-pf-threshold: RX programmable full interrupt threshold -- xlnx,s-axi-id-width: Should be <0x4> -- xlnx,s-axi4-data-width: Should be <0x20> -- xlnx,select-xpm: Should be <0x0> + (ignored by the driver) +- xlnx,s-axi-id-width: Should be <0x4> (ignored by the driver) +- xlnx,s-axi4-data-width: Should be <0x20> (ignored by the driver) +- xlnx,select-xpm: Should be <0x0> (ignored by the driver) - xlnx,tx-fifo-depth: Depth of TX FIFO in words - xlnx,tx-fifo-pe-threshold: TX programmable empty interrupt threshold + (ignored by the driver) - xlnx,tx-fifo-pf-threshold: TX programmable full interrupt threshold + (ignored by the driver) - xlnx,use-rx-cut-through: Should be <0x0> (this feature isn't supported) - xlnx,use-rx-data: <0x1> if RX FIFO is enabled, <0x0> otherwise - xlnx,use-tx-ctrl: Should be <0x0> (this feature isn't supported) diff --git a/drivers/staging/board/armadillo800eva.c b/drivers/staging/board/armadillo800eva.c index 962cc0c79988..0225234dd7aa 100644 --- a/drivers/staging/board/armadillo800eva.c +++ b/drivers/staging/board/armadillo800eva.c @@ -50,16 +50,8 @@ static struct sh_mobile_lcdc_info lcdc0_info = { }; static struct resource lcdc0_resources[] = { - [0] = { - .name = "LCD0", - .start = 0xfe940000, - .end = 0xfe943fff, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = 177 + 32, - .flags = IORESOURCE_IRQ, - }, + DEFINE_RES_MEM_NAMED(0xfe940000, 0x4000, "LCD0"), + DEFINE_RES_IRQ(177 + 32), }; static struct platform_device lcdc0_device = { diff --git a/drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c b/drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c index 15b7a82f4b1e..e52a64be93f3 100644 --- a/drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c +++ b/drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c @@ -135,7 +135,6 @@ static int clk_wzrd_probe(struct platform_device *pdev) unsigned long rate; const char *clk_name; struct clk_wzrd *clk_wzrd; - struct resource *mem; struct device_node *np = pdev->dev.of_node; clk_wzrd = devm_kzalloc(&pdev->dev, sizeof(*clk_wzrd), GFP_KERNEL); @@ -143,8 +142,7 @@ static int clk_wzrd_probe(struct platform_device *pdev) return -ENOMEM; platform_set_drvdata(pdev, clk_wzrd); - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - clk_wzrd->base = devm_ioremap_resource(&pdev->dev, mem); + clk_wzrd->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(clk_wzrd->base)) return PTR_ERR(clk_wzrd->base); diff --git a/drivers/staging/comedi/drivers/dt3000.c b/drivers/staging/comedi/drivers/dt3000.c index caf4d4df4bd3..f7c365b70106 100644 --- a/drivers/staging/comedi/drivers/dt3000.c +++ b/drivers/staging/comedi/drivers/dt3000.c @@ -508,12 +508,11 @@ static int dt3k_ai_insn_read(struct comedi_device *dev, unsigned int *data) { int i; - unsigned int chan, gain, aref; + unsigned int chan, gain; chan = CR_CHAN(insn->chanspec); gain = CR_RANGE(insn->chanspec); /* XXX docs don't explain how to select aref */ - aref = CR_AREF(insn->chanspec); for (i = 0; i < insn->n; i++) data[i] = dt3k_readsingle(dev, DPR_SUBSYS_AI, chan, gain); diff --git a/drivers/staging/comedi/drivers/ni_routes.c b/drivers/staging/comedi/drivers/ni_routes.c index eb61494dc2bd..673d732dcb8f 100644 --- a/drivers/staging/comedi/drivers/ni_routes.c +++ b/drivers/staging/comedi/drivers/ni_routes.c @@ -49,8 +49,6 @@ /* Helper for accessing data. */ #define RVi(table, src, dest) ((table)[(dest) * NI_NUM_NAMES + (src)]) -static const size_t route_table_size = NI_NUM_NAMES * NI_NUM_NAMES; - /* * Find the proper route_values and ni_device_routes tables for this particular * device. diff --git a/drivers/staging/emxx_udc/emxx_udc.c b/drivers/staging/emxx_udc/emxx_udc.c index 147481bf680c..03929b9d3a8b 100644 --- a/drivers/staging/emxx_udc/emxx_udc.c +++ b/drivers/staging/emxx_udc/emxx_udc.c @@ -1072,9 +1072,8 @@ static int _nbu2ss_epn_in_pio(struct nbu2ss_udc *udc, struct nbu2ss_ep *ep, if (i_word_length > 0) { for (i = 0; i < i_word_length; i++) { _nbu2ss_writel( - &preg->EP_REGS[ep->epnum - 1].EP_WRITE - , p_buf_32->dw - ); + &preg->EP_REGS[ep->epnum - 1].EP_WRITE, + p_buf_32->dw); p_buf_32++; } @@ -2661,20 +2660,18 @@ static int nbu2ss_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) /* make sure it's actually queued on this endpoint */ list_for_each_entry(req, &ep->queue, queue) { - if (&req->req == _req) - break; - } - if (&req->req != _req) { - spin_unlock_irqrestore(&udc->lock, flags); - pr_debug("%s no queue(EINVAL)\n", __func__); - return -EINVAL; + if (&req->req == _req) { + _nbu2ss_ep_done(ep, req, -ECONNRESET); + spin_unlock_irqrestore(&udc->lock, flags); + return 0; + } } - _nbu2ss_ep_done(ep, req, -ECONNRESET); - spin_unlock_irqrestore(&udc->lock, flags); - return 0; + pr_debug("%s no queue(EINVAL)\n", __func__); + + return -EINVAL; } /*-------------------------------------------------------------------------*/ @@ -3078,7 +3075,6 @@ static int nbu2ss_drv_probe(struct platform_device *pdev) { int status = -ENODEV; struct nbu2ss_udc *udc; - struct resource *r; int irq; void __iomem *mmio_base; @@ -3088,8 +3084,7 @@ static int nbu2ss_drv_probe(struct platform_device *pdev) platform_set_drvdata(pdev, udc); /* require I/O memory and IRQ to be provided as resources */ - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - mmio_base = devm_ioremap_resource(&pdev->dev, r); + mmio_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(mmio_base)) return PTR_ERR(mmio_base); diff --git a/drivers/staging/exfat/TODO b/drivers/staging/exfat/TODO index a3eb282f9efc..b60e50b9cf4e 100644 --- a/drivers/staging/exfat/TODO +++ b/drivers/staging/exfat/TODO @@ -3,6 +3,15 @@ same for ffsWriteFile. exfat_core.c - fs_sync(sb,0) all over the place looks fishy as hell. There's only one place that calls it with a non-zero argument. +Randomly removing fs_sync() calls is *not* the right answer, especially +if the removal then leaves a call to fs_set_vol_flags(VOL_CLEAN), as that +says the file system is clean and synced when we *know* it isn't. +The proper fix here is to go through and actually analyze how DELAYED_SYNC +should work, and any time we're setting VOL_CLEAN, ensure the file system +has in fact been synced to disk. In other words, changing the 'false' to +'true' is probably more correct. Also, it's likely that the one current +place where it actually does an bdev_sync isn't sufficient in the DELAYED_SYNC +case. ffsTruncateFile - if (old_size <= new_size) { That doesn't look right. How did it ever work? Are they relying on lazy diff --git a/drivers/staging/exfat/exfat.h b/drivers/staging/exfat/exfat.h index 3abab33e932c..acb73f47a253 100644 --- a/drivers/staging/exfat/exfat.h +++ b/drivers/staging/exfat/exfat.h @@ -214,18 +214,10 @@ static inline u16 get_row_index(u16 i) #define FFS_NOTMOUNTED 4 #define FFS_ALIGNMENTERR 5 #define FFS_SEMAPHOREERR 6 -#define FFS_INVALIDPATH 7 #define FFS_INVALIDFID 8 -#define FFS_NOTFOUND 9 -#define FFS_FILEEXIST 10 -#define FFS_PERMISSIONERR 11 #define FFS_NOTOPENED 12 #define FFS_MAXOPENED 13 -#define FFS_FULL 14 #define FFS_EOF 15 -#define FFS_DIRBUSY 16 -#define FFS_MEMORYERR 17 -#define FFS_NAMETOOLONG 18 #define FFS_ERROR 19 #define NUM_UPCASE 2918 @@ -618,7 +610,7 @@ struct fs_info_t { u32 dev_ejected; /* block device operation error flag */ struct fs_func *fs_func; - struct semaphore v_sem; + struct mutex v_mutex; /* FAT cache */ struct buf_cache_t FAT_cache_array[FAT_CACHE_SIZE]; diff --git a/drivers/staging/exfat/exfat_cache.c b/drivers/staging/exfat/exfat_cache.c index e1b001718709..467b93630d86 100644 --- a/drivers/staging/exfat/exfat_cache.c +++ b/drivers/staging/exfat/exfat_cache.c @@ -12,8 +12,8 @@ #define DIRTYBIT 0x02 /* Local variables */ -static DEFINE_SEMAPHORE(f_sem); -static DEFINE_SEMAPHORE(b_sem); +static DEFINE_MUTEX(f_mutex); +static DEFINE_MUTEX(b_mutex); static struct buf_cache_t *FAT_cache_find(struct super_block *sb, sector_t sec) { @@ -315,9 +315,9 @@ int FAT_read(struct super_block *sb, u32 loc, u32 *content) { s32 ret; - down(&f_sem); + mutex_lock(&f_mutex); ret = __FAT_read(sb, loc, content); - up(&f_sem); + mutex_unlock(&f_mutex); return ret; } @@ -434,9 +434,9 @@ int FAT_write(struct super_block *sb, u32 loc, u32 content) { s32 ret; - down(&f_sem); + mutex_lock(&f_mutex); ret = __FAT_write(sb, loc, content); - up(&f_sem); + mutex_unlock(&f_mutex); return ret; } @@ -490,7 +490,7 @@ void FAT_release_all(struct super_block *sb) struct buf_cache_t *bp; struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - down(&f_sem); + mutex_lock(&f_mutex); bp = p_fs->FAT_cache_lru_list.next; while (bp != &p_fs->FAT_cache_lru_list) { @@ -507,7 +507,7 @@ void FAT_release_all(struct super_block *sb) bp = bp->next; } - up(&f_sem); + mutex_unlock(&f_mutex); } void FAT_sync(struct super_block *sb) @@ -515,7 +515,7 @@ void FAT_sync(struct super_block *sb) struct buf_cache_t *bp; struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - down(&f_sem); + mutex_lock(&f_mutex); bp = p_fs->FAT_cache_lru_list.next; while (bp != &p_fs->FAT_cache_lru_list) { @@ -526,7 +526,7 @@ void FAT_sync(struct super_block *sb) bp = bp->next; } - up(&f_sem); + mutex_unlock(&f_mutex); } static struct buf_cache_t *buf_cache_find(struct super_block *sb, sector_t sec) @@ -600,9 +600,9 @@ u8 *buf_getblk(struct super_block *sb, sector_t sec) { u8 *buf; - down(&b_sem); + mutex_lock(&b_mutex); buf = __buf_getblk(sb, sec); - up(&b_sem); + mutex_unlock(&b_mutex); return buf; } @@ -611,7 +611,7 @@ void buf_modify(struct super_block *sb, sector_t sec) { struct buf_cache_t *bp; - down(&b_sem); + mutex_lock(&b_mutex); bp = buf_cache_find(sb, sec); if (likely(bp)) @@ -620,14 +620,14 @@ void buf_modify(struct super_block *sb, sector_t sec) WARN(!bp, "[EXFAT] failed to find buffer_cache(sector:%llu).\n", (unsigned long long)sec); - up(&b_sem); + mutex_unlock(&b_mutex); } void buf_lock(struct super_block *sb, sector_t sec) { struct buf_cache_t *bp; - down(&b_sem); + mutex_lock(&b_mutex); bp = buf_cache_find(sb, sec); if (likely(bp)) @@ -636,14 +636,14 @@ void buf_lock(struct super_block *sb, sector_t sec) WARN(!bp, "[EXFAT] failed to find buffer_cache(sector:%llu).\n", (unsigned long long)sec); - up(&b_sem); + mutex_unlock(&b_mutex); } void buf_unlock(struct super_block *sb, sector_t sec) { struct buf_cache_t *bp; - down(&b_sem); + mutex_lock(&b_mutex); bp = buf_cache_find(sb, sec); if (likely(bp)) @@ -652,7 +652,7 @@ void buf_unlock(struct super_block *sb, sector_t sec) WARN(!bp, "[EXFAT] failed to find buffer_cache(sector:%llu).\n", (unsigned long long)sec); - up(&b_sem); + mutex_unlock(&b_mutex); } void buf_release(struct super_block *sb, sector_t sec) @@ -660,7 +660,7 @@ void buf_release(struct super_block *sb, sector_t sec) struct buf_cache_t *bp; struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - down(&b_sem); + mutex_lock(&b_mutex); bp = buf_cache_find(sb, sec); if (likely(bp)) { @@ -676,7 +676,7 @@ void buf_release(struct super_block *sb, sector_t sec) move_to_lru(bp, &p_fs->buf_cache_lru_list); } - up(&b_sem); + mutex_unlock(&b_mutex); } void buf_release_all(struct super_block *sb) @@ -684,7 +684,7 @@ void buf_release_all(struct super_block *sb) struct buf_cache_t *bp; struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - down(&b_sem); + mutex_lock(&b_mutex); bp = p_fs->buf_cache_lru_list.next; while (bp != &p_fs->buf_cache_lru_list) { @@ -701,7 +701,7 @@ void buf_release_all(struct super_block *sb) bp = bp->next; } - up(&b_sem); + mutex_unlock(&b_mutex); } void buf_sync(struct super_block *sb) @@ -709,7 +709,7 @@ void buf_sync(struct super_block *sb) struct buf_cache_t *bp; struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); - down(&b_sem); + mutex_lock(&b_mutex); bp = p_fs->buf_cache_lru_list.next; while (bp != &p_fs->buf_cache_lru_list) { @@ -720,5 +720,5 @@ void buf_sync(struct super_block *sb) bp = bp->next; } - up(&b_sem); + mutex_unlock(&b_mutex); } diff --git a/drivers/staging/exfat/exfat_core.c b/drivers/staging/exfat/exfat_core.c index 79174e5c4145..b23fbf3ebaa5 100644 --- a/drivers/staging/exfat/exfat_core.c +++ b/drivers/staging/exfat/exfat_core.c @@ -470,7 +470,8 @@ s32 exfat_count_used_clusters(struct super_block *sb) struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); - map_i = map_b = 0; + map_i = 0; + map_b = 0; for (i = 2; i < p_fs->num_clusters; i += 8) { k = *(((u8 *)p_fs->vol_amap[map_i]->b_data) + map_b); @@ -544,13 +545,13 @@ s32 load_alloc_bitmap(struct super_block *sb) sizeof(struct buffer_head *), GFP_KERNEL); if (!p_fs->vol_amap) - return FFS_MEMORYERR; + return -ENOMEM; sector = START_SECTOR(p_fs->map_clu); for (j = 0; j < p_fs->map_sectors; j++) { p_fs->vol_amap[j] = NULL; - ret = sector_read(sb, sector + j, &(p_fs->vol_amap[j]), 1); + ret = sector_read(sb, sector + j, &p_fs->vol_amap[j], 1); if (ret != FFS_SUCCESS) { /* release all buffers and free vol_amap */ i = 0; @@ -712,10 +713,10 @@ static s32 __load_upcase_table(struct super_block *sb, sector_t sector, u32 checksum = 0; - upcase_table = p_fs->vol_utbl = kmalloc(UTBL_COL_COUNT * sizeof(u16 *), - GFP_KERNEL); + upcase_table = kmalloc_array(UTBL_COL_COUNT, sizeof(u16 *), GFP_KERNEL); + p_fs->vol_utbl = upcase_table; if (!upcase_table) - return FFS_MEMORYERR; + return -ENOMEM; memset(upcase_table, 0, UTBL_COL_COUNT * sizeof(u16 *)); while (sector < end_sector) { @@ -755,7 +756,7 @@ static s32 __load_upcase_table(struct super_block *sb, sector_t sector, upcase_table[col_index] = kmalloc_array(UTBL_ROW_COUNT, sizeof(u16), GFP_KERNEL); if (!upcase_table[col_index]) { - ret = FFS_MEMORYERR; + ret = -ENOMEM; goto error; } @@ -792,10 +793,10 @@ static s32 __load_default_upcase_table(struct super_block *sb) u16 uni = 0; u16 **upcase_table; - upcase_table = p_fs->vol_utbl = kmalloc(UTBL_COL_COUNT * sizeof(u16 *), - GFP_KERNEL); + upcase_table = kmalloc_array(UTBL_COL_COUNT, sizeof(u16 *), GFP_KERNEL); + p_fs->vol_utbl = upcase_table; if (!upcase_table) - return FFS_MEMORYERR; + return -ENOMEM; memset(upcase_table, 0, UTBL_COL_COUNT * sizeof(u16 *)); for (i = 0; index <= 0xFFFF && i < NUM_UPCASE * 2; i += 2) { @@ -818,7 +819,7 @@ static s32 __load_default_upcase_table(struct super_block *sb) sizeof(u16), GFP_KERNEL); if (!upcase_table[col_index]) { - ret = FFS_MEMORYERR; + ret = -ENOMEM; goto error; } @@ -910,10 +911,10 @@ u32 fat_get_entry_type(struct dentry_t *p_entry) { struct dos_dentry_t *ep = (struct dos_dentry_t *)p_entry; - if (*(ep->name) == 0x0) + if (*ep->name == 0x0) return TYPE_UNUSED; - else if (*(ep->name) == 0xE5) + else if (*ep->name == 0xE5) return TYPE_DELETED; else if (ep->attr == ATTR_EXTEND) @@ -978,10 +979,10 @@ void fat_set_entry_type(struct dentry_t *p_entry, u32 type) struct dos_dentry_t *ep = (struct dos_dentry_t *)p_entry; if (type == TYPE_UNUSED) - *(ep->name) = 0x0; + *ep->name = 0x0; else if (type == TYPE_DELETED) - *(ep->name) = 0xE5; + *ep->name = 0xE5; else if (type == TYPE_EXTEND) ep->attr = ATTR_EXTEND; @@ -1502,7 +1503,7 @@ void fat_delete_dir_entry(struct super_block *sb, struct chain_t *p_dir, } void exfat_delete_dir_entry(struct super_block *sb, struct chain_t *p_dir, - s32 entry, s32 order, s32 num_entries) + s32 entry, s32 order, s32 num_entries) { int i; sector_t sector; @@ -1562,7 +1563,7 @@ void update_dir_checksum_with_entry_set(struct super_block *sb, u16 chksum = 0; s32 chksum_type = CS_DIR_ENTRY, i; - ep = (struct dentry_t *)&(es->__buf); + ep = (struct dentry_t *)&es->__buf; for (i = 0; i < es->num_entries; i++) { pr_debug("%s ep %p\n", __func__, ep); chksum = calc_checksum_2byte((void *)ep, DENTRY_SIZE, chksum, @@ -1571,7 +1572,7 @@ void update_dir_checksum_with_entry_set(struct super_block *sb, chksum_type = CS_DEFAULT; } - ep = (struct dentry_t *)&(es->__buf); + ep = (struct dentry_t *)&es->__buf; SET16_A(((struct file_dentry_t *)ep)->checksum, chksum); write_whole_entry_set(sb, es); } @@ -1703,7 +1704,7 @@ struct entry_set_cache_t *get_entry_set_in_dir(struct super_block *sb, size_t bufsize; pr_debug("%s entered p_dir dir %u flags %x size %d\n", - __func__, p_dir->dir, p_dir->flags, p_dir->size); + __func__, p_dir->dir, p_dir->flags, p_dir->size); byte_offset = entry << DENTRY_SIZE_BITS; ret = _walk_fat_chain(sb, p_dir, byte_offset, &clu); @@ -1727,8 +1728,7 @@ struct entry_set_cache_t *get_entry_set_in_dir(struct super_block *sb, ep = (struct dentry_t *)(buf + off); entry_type = p_fs->fs_func->get_entry_type(ep); - if ((entry_type != TYPE_FILE) - && (entry_type != TYPE_DIR)) + if ((entry_type != TYPE_FILE) && (entry_type != TYPE_DIR)) goto err_out; if (type == ES_ALL_ENTRIES) @@ -1832,11 +1832,11 @@ struct entry_set_cache_t *get_entry_set_in_dir(struct super_block *sb, } if (file_ep) - *file_ep = (struct dentry_t *)&(es->__buf); + *file_ep = (struct dentry_t *)&es->__buf; pr_debug("%s exiting es %p sec %llu offset %d flags %d, num_entries %u buf ptr %p\n", - __func__, es, (unsigned long long)es->sector, es->offset, - es->alloc_flag, es->num_entries, &es->__buf); + __func__, es, (unsigned long long)es->sector, es->offset, + es->alloc_flag, es->num_entries, &es->__buf); return es; err_out: pr_debug("%s exited NULL (es %p)\n", __func__, es); @@ -1859,10 +1859,10 @@ static s32 __write_partial_entries_in_entry_set(struct super_block *sb, struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); u32 clu; - u8 *buf, *esbuf = (u8 *)&(es->__buf); + u8 *buf, *esbuf = (u8 *)&es->__buf; pr_debug("%s entered es %p sec %llu off %d count %d\n", - __func__, es, (unsigned long long)sec, off, count); + __func__, es, (unsigned long long)sec, off, count); num_entries = count; while (num_entries) { @@ -1876,8 +1876,8 @@ static s32 __write_partial_entries_in_entry_set(struct super_block *sb, goto err_out; pr_debug("es->buf %p buf_off %u\n", esbuf, buf_off); pr_debug("copying %d entries from %p to sector %llu\n", - copy_entries, (esbuf + buf_off), - (unsigned long long)sec); + copy_entries, (esbuf + buf_off), + (unsigned long long)sec); memcpy(buf + off, esbuf + buf_off, copy_entries << DENTRY_SIZE_BITS); buf_modify(sb, sec); @@ -1919,7 +1919,8 @@ s32 write_whole_entry_set(struct super_block *sb, struct entry_set_cache_t *es) /* write back some entries in entry set */ s32 write_partial_entries_in_entry_set(struct super_block *sb, - struct entry_set_cache_t *es, struct dentry_t *ep, u32 count) + struct entry_set_cache_t *es, + struct dentry_t *ep, u32 count) { s32 ret, byte_offset, off; u32 clu = 0; @@ -1929,7 +1930,7 @@ s32 write_partial_entries_in_entry_set(struct super_block *sb, struct chain_t dir; /* vaidity check */ - if (ep + count > ((struct dentry_t *)&(es->__buf)) + es->num_entries) + if (ep + count > ((struct dentry_t *)&es->__buf) + es->num_entries) return FFS_ERROR; dir.dir = GET_CLUSTER_FROM_SECTOR(es->sector); @@ -1938,7 +1939,7 @@ s32 write_partial_entries_in_entry_set(struct super_block *sb, byte_offset = (es->sector - START_SECTOR(dir.dir)) << p_bd->sector_size_bits; - byte_offset += ((void **)ep - &(es->__buf)) + es->offset; + byte_offset += ((void **)ep - &es->__buf) + es->offset; ret = _walk_fat_chain(sb, &dir, byte_offset, &clu); if (ret != FFS_SUCCESS) @@ -2122,7 +2123,7 @@ s32 find_empty_entry(struct inode *inode, struct chain_t *p_dir, s32 num_entries p_fs->fs_func->set_entry_flag(ep, p_dir->flags); buf_modify(sb, sector); - update_dir_checksum(sb, &(fid->dir), + update_dir_checksum(sb, &fid->dir, fid->entry); } } @@ -2571,7 +2572,7 @@ s32 get_num_entries_and_dos_name(struct super_block *sb, struct chain_t *p_dir, num_entries = p_fs->fs_func->calc_num_entries(p_uniname); if (num_entries == 0) - return FFS_INVALIDPATH; + return -EINVAL; if (p_fs->vol_type != EXFAT) { nls_uniname_to_dosname(sb, p_dosname, p_uniname, &lossy); @@ -2583,7 +2584,7 @@ s32 get_num_entries_and_dos_name(struct super_block *sb, struct chain_t *p_dir, } else { for (r = reserved_names; *r; r++) { if (!strncmp((void *)p_dosname->name, *r, 8)) - return FFS_INVALIDPATH; + return -EINVAL; } if (p_dosname->name_case != 0xFF) @@ -2828,7 +2829,7 @@ s32 fat_generate_dos_name(struct super_block *sb, struct chain_t *p_dir, } if ((count == 0) || (count >= 1024)) - return FFS_FILEEXIST; + return -EEXIST; fat_attach_count_to_dos_name(p_dosname->name, count); /* Now dos_name has DOS~????.EXT */ @@ -2962,11 +2963,11 @@ s32 resolve_path(struct inode *inode, char *path, struct chain_t *p_dir, struct file_id_t *fid = &(EXFAT_I(inode)->fid); if (strscpy(name_buf, path, sizeof(name_buf)) < 0) - return FFS_INVALIDPATH; + return -EINVAL; nls_cstring_to_uniname(sb, p_uniname, name_buf, &lossy); if (lossy) - return FFS_INVALIDPATH; + return -EINVAL; fid->size = i_size_read(inode); @@ -3216,7 +3217,7 @@ s32 create_dir(struct inode *inode, struct chain_t *p_dir, /* find_empty_entry must be called before alloc_cluster */ dentry = find_empty_entry(inode, p_dir, num_entries); if (dentry < 0) - return FFS_FULL; + return -ENOSPC; clu.dir = CLUSTER_32(~0); clu.size = 0; @@ -3227,7 +3228,7 @@ s32 create_dir(struct inode *inode, struct chain_t *p_dir, if (ret < 0) return FFS_MEDIAERR; else if (ret == 0) - return FFS_FULL; + return -ENOSPC; ret = clear_cluster(sb, clu.dir); if (ret != FFS_SUCCESS) @@ -3319,7 +3320,7 @@ s32 create_file(struct inode *inode, struct chain_t *p_dir, /* find_empty_entry must be called before alloc_cluster() */ dentry = find_empty_entry(inode, p_dir, num_entries); if (dentry < 0) - return FFS_FULL; + return -ENOSPC; /* (1) update the directory entry */ /* fill the dos name directory entry information of the created file. @@ -3418,7 +3419,7 @@ s32 rename_file(struct inode *inode, struct chain_t *p_dir, s32 oldentry, newentry = find_empty_entry(inode, p_dir, num_new_entries); if (newentry < 0) { buf_unlock(sb, sector_old); - return FFS_FULL; + return -ENOSPC; } epnew = get_entry_in_dir(sb, p_dir, newentry, §or_new); @@ -3506,7 +3507,7 @@ s32 move_file(struct inode *inode, struct chain_t *p_olddir, s32 oldentry, /* check if the source and target directory is the same */ if (fs_func->get_entry_type(epmov) == TYPE_DIR && fs_func->get_entry_clu0(epmov) == p_newdir->dir) - return FFS_INVALIDPATH; + return -EINVAL; buf_lock(sb, sector_mov); @@ -3529,7 +3530,7 @@ s32 move_file(struct inode *inode, struct chain_t *p_olddir, s32 oldentry, newentry = find_empty_entry(inode, p_newdir, num_new_entries); if (newentry < 0) { buf_unlock(sb, sector_mov); - return FFS_FULL; + return -ENOSPC; } epnew = get_entry_in_dir(sb, p_newdir, newentry, §or_new); diff --git a/drivers/staging/exfat/exfat_super.c b/drivers/staging/exfat/exfat_super.c index 3b2b0ceb7297..1ae5a7750348 100644 --- a/drivers/staging/exfat/exfat_super.c +++ b/drivers/staging/exfat/exfat_super.c @@ -284,7 +284,7 @@ static const struct dentry_operations exfat_dentry_ops = { .d_compare = exfat_cmp, }; -static DEFINE_SEMAPHORE(z_sem); +static DEFINE_MUTEX(z_mutex); static inline void fs_sync(struct super_block *sb, bool do_sync) { @@ -353,11 +353,11 @@ static int ffsMountVol(struct super_block *sb) pr_info("[EXFAT] trying to mount...\n"); - down(&z_sem); + mutex_lock(&z_mutex); buf_init(sb); - sema_init(&p_fs->v_sem, 1); + mutex_init(&p_fs->v_mutex); p_fs->dev_ejected = 0; /* open the block device */ @@ -396,7 +396,7 @@ static int ffsMountVol(struct super_block *sb) if (i < 53) { #ifdef CONFIG_EXFAT_DONT_MOUNT_VFAT ret = -EINVAL; - printk(KERN_INFO "EXFAT: Attempted to mount VFAT filesystem\n"); + pr_info("EXFAT: Attempted to mount VFAT filesystem\n"); goto out; #else if (GET16(p_pbr->bpb + 11)) /* num_fat_sectors */ @@ -442,7 +442,7 @@ static int ffsMountVol(struct super_block *sb) pr_info("[EXFAT] mounted successfully\n"); out: - up(&z_sem); + mutex_unlock(&z_mutex); return ret; } @@ -454,12 +454,12 @@ static int ffsUmountVol(struct super_block *sb) pr_info("[EXFAT] trying to unmount...\n"); - down(&z_sem); + mutex_lock(&z_mutex); /* acquire the lock for file system critical section */ - down(&p_fs->v_sem); + mutex_lock(&p_fs->v_mutex); - fs_sync(sb, false); + fs_sync(sb, true); fs_set_vol_flags(sb, VOL_CLEAN); if (p_fs->vol_type == EXFAT) { @@ -481,8 +481,8 @@ static int ffsUmountVol(struct super_block *sb) buf_shutdown(sb); /* release the lock for file system critical section */ - up(&p_fs->v_sem); - up(&z_sem); + mutex_unlock(&p_fs->v_mutex); + mutex_unlock(&z_mutex); pr_info("[EXFAT] unmounted successfully\n"); @@ -499,7 +499,7 @@ static int ffsGetVolInfo(struct super_block *sb, struct vol_info_t *info) return FFS_ERROR; /* acquire the lock for file system critical section */ - down(&p_fs->v_sem); + mutex_lock(&p_fs->v_mutex); if (p_fs->used_clusters == UINT_MAX) p_fs->used_clusters = p_fs->fs_func->count_used_clusters(sb); @@ -514,7 +514,7 @@ static int ffsGetVolInfo(struct super_block *sb, struct vol_info_t *info) err = FFS_MEDIAERR; /* release the lock for file system critical section */ - up(&p_fs->v_sem); + mutex_unlock(&p_fs->v_mutex); return err; } @@ -525,7 +525,7 @@ static int ffsSyncVol(struct super_block *sb, bool do_sync) struct fs_info_t *p_fs = &(EXFAT_SB(sb)->fs_info); /* acquire the lock for file system critical section */ - down(&p_fs->v_sem); + mutex_lock(&p_fs->v_mutex); /* synchronize the file system */ fs_sync(sb, do_sync); @@ -535,7 +535,7 @@ static int ffsSyncVol(struct super_block *sb, bool do_sync) err = FFS_MEDIAERR; /* release the lock for file system critical section */ - up(&p_fs->v_sem); + mutex_unlock(&p_fs->v_mutex); return err; } @@ -562,7 +562,7 @@ static int ffsLookupFile(struct inode *inode, char *path, struct file_id_t *fid) return FFS_ERROR; /* acquire the lock for file system critical section */ - down(&p_fs->v_sem); + mutex_lock(&p_fs->v_mutex); /* check the validity of directory name in the given pathname */ ret = resolve_path(inode, path, &dir, &uni_name); @@ -578,7 +578,7 @@ static int ffsLookupFile(struct inode *inode, char *path, struct file_id_t *fid) dentry = p_fs->fs_func->find_dir_entry(sb, &dir, &uni_name, num_entries, &dos_name, TYPE_ALL); if (dentry < -1) { - ret = FFS_NOTFOUND; + ret = -ENOENT; goto out; } @@ -636,7 +636,7 @@ static int ffsLookupFile(struct inode *inode, char *path, struct file_id_t *fid) ret = FFS_MEDIAERR; out: /* release the lock for file system critical section */ - up(&p_fs->v_sem); + mutex_unlock(&p_fs->v_mutex); return ret; } @@ -655,7 +655,7 @@ static int ffsCreateFile(struct inode *inode, char *path, u8 mode, return FFS_ERROR; /* acquire the lock for file system critical section */ - down(&p_fs->v_sem); + mutex_lock(&p_fs->v_mutex); /* check the validity of directory name in the given pathname */ ret = resolve_path(inode, path, &dir, &uni_name); @@ -667,8 +667,8 @@ static int ffsCreateFile(struct inode *inode, char *path, u8 mode, /* create a new file */ ret = create_file(inode, &dir, &uni_name, mode, fid); -#ifdef CONFIG_EXFAT_DELAYED_SYNC - fs_sync(sb, false); +#ifndef CONFIG_EXFAT_DELAYED_SYNC + fs_sync(sb, true); fs_set_vol_flags(sb, VOL_CLEAN); #endif @@ -677,7 +677,7 @@ static int ffsCreateFile(struct inode *inode, char *path, u8 mode, out: /* release the lock for file system critical section */ - up(&p_fs->v_sem); + mutex_unlock(&p_fs->v_mutex); return ret; } @@ -704,11 +704,11 @@ static int ffsReadFile(struct inode *inode, struct file_id_t *fid, void *buffer, return FFS_ERROR; /* acquire the lock for file system critical section */ - down(&p_fs->v_sem); + mutex_lock(&p_fs->v_mutex); /* check if the given file ID is opened */ if (fid->type != TYPE_FILE) { - ret = FFS_PERMISSIONERR; + ret = -EPERM; goto out; } @@ -743,8 +743,10 @@ static int ffsReadFile(struct inode *inode, struct file_id_t *fid, void *buffer, while (clu_offset > 0) { /* clu = FAT_read(sb, clu); */ - if (FAT_read(sb, clu, &clu) == -1) - return FFS_MEDIAERR; + if (FAT_read(sb, clu, &clu) == -1) { + ret = FFS_MEDIAERR; + goto out; + } clu_offset--; } @@ -801,7 +803,7 @@ err_out: out: /* release the lock for file system critical section */ - up(&p_fs->v_sem); + mutex_unlock(&p_fs->v_mutex); return ret; } @@ -834,11 +836,11 @@ static int ffsWriteFile(struct inode *inode, struct file_id_t *fid, return FFS_ERROR; /* acquire the lock for file system critical section */ - down(&p_fs->v_sem); + mutex_lock(&p_fs->v_mutex); /* check if the given file ID is opened */ if (fid->type != TYPE_FILE) { - ret = FFS_PERMISSIONERR; + ret = -EPERM; goto out; } @@ -864,7 +866,8 @@ static int ffsWriteFile(struct inode *inode, struct file_id_t *fid, while (count > 0) { clu_offset = (s32)(fid->rwoffset >> p_fs->cluster_size_bits); - clu = last_clu = fid->start_clu; + clu = fid->start_clu; + last_clu = fid->start_clu; if (fid->flags == 0x03) { if ((clu_offset > 0) && (clu != CLUSTER_32(~0))) { @@ -1003,13 +1006,13 @@ static int ffsWriteFile(struct inode *inode, struct file_id_t *fid, /* (3) update the direcoty entry */ if (p_fs->vol_type == EXFAT) { - es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry, + es = get_entry_set_in_dir(sb, &fid->dir, fid->entry, ES_ALL_ENTRIES, &ep); if (!es) goto err_out; ep2 = ep + 1; } else { - ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, §or); + ep = get_entry_in_dir(sb, &fid->dir, fid->entry, §or); if (!ep) goto err_out; ep2 = ep; @@ -1040,8 +1043,8 @@ static int ffsWriteFile(struct inode *inode, struct file_id_t *fid, release_entry_set(es); } -#ifdef CONFIG_EXFAT_DELAYED_SYNC - fs_sync(sb, false); +#ifndef CONFIG_EXFAT_DELAYED_SYNC + fs_sync(sb, true); fs_set_vol_flags(sb, VOL_CLEAN); #endif @@ -1051,14 +1054,14 @@ err_out: *wcount = write_bytes; if (num_alloced == 0) - ret = FFS_FULL; + ret = -ENOSPC; else if (p_fs->dev_ejected) ret = FFS_MEDIAERR; out: /* release the lock for file system critical section */ - up(&p_fs->v_sem); + mutex_unlock(&p_fs->v_mutex); return ret; } @@ -1081,11 +1084,11 @@ static int ffsTruncateFile(struct inode *inode, u64 old_size, u64 new_size) new_size); /* acquire the lock for file system critical section */ - down(&p_fs->v_sem); + mutex_lock(&p_fs->v_mutex); /* check if the given file ID is opened */ if (fid->type != TYPE_FILE) { - ret = FFS_PERMISSIONERR; + ret = -EPERM; goto out; } @@ -1142,7 +1145,7 @@ static int ffsTruncateFile(struct inode *inode, u64 old_size, u64 new_size) } ep2 = ep + 1; } else { - ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, §or); + ep = get_entry_in_dir(sb, &fid->dir, fid->entry, §or); if (!ep) { ret = FFS_MEDIAERR; goto out; @@ -1180,8 +1183,8 @@ static int ffsTruncateFile(struct inode *inode, u64 old_size, u64 new_size) if (fid->rwoffset > fid->size) fid->rwoffset = fid->size; -#ifdef CONFIG_EXFAT_DELAYED_SYNC - fs_sync(sb, false); +#ifndef CONFIG_EXFAT_DELAYED_SYNC + fs_sync(sb, true); fs_set_vol_flags(sb, VOL_CLEAN); #endif @@ -1191,7 +1194,7 @@ static int ffsTruncateFile(struct inode *inode, u64 old_size, u64 new_size) out: pr_debug("%s exited (%d)\n", __func__, ret); /* release the lock for file system critical section */ - up(&p_fs->v_sem); + mutex_unlock(&p_fs->v_mutex); return ret; } @@ -1239,7 +1242,7 @@ static int ffsMoveFile(struct inode *old_parent_inode, struct file_id_t *fid, return FFS_ERROR; /* acquire the lock for file system critical section */ - down(&p_fs->v_sem); + mutex_lock(&p_fs->v_mutex); update_parent_info(fid, old_parent_inode); @@ -1252,7 +1255,7 @@ static int ffsMoveFile(struct inode *old_parent_inode, struct file_id_t *fid, /* check if the old file is "." or ".." */ if (p_fs->vol_type != EXFAT) { if ((olddir.dir != p_fs->root_dir) && (dentry < 2)) { - ret = FFS_PERMISSIONERR; + ret = -EPERM; goto out2; } } @@ -1264,7 +1267,7 @@ static int ffsMoveFile(struct inode *old_parent_inode, struct file_id_t *fid, } if (p_fs->fs_func->get_entry_attr(ep) & ATTR_READONLY) { - ret = FFS_PERMISSIONERR; + ret = -EPERM; goto out2; } @@ -1277,7 +1280,7 @@ static int ffsMoveFile(struct inode *old_parent_inode, struct file_id_t *fid, update_parent_info(new_fid, new_parent_inode); - p_dir = &(new_fid->dir); + p_dir = &new_fid->dir; new_entry = new_fid->entry; ep = get_entry_in_dir(sb, p_dir, new_entry, NULL); if (!ep) @@ -1294,7 +1297,7 @@ static int ffsMoveFile(struct inode *old_parent_inode, struct file_id_t *fid, new_clu.flags = new_fid->flags; if (!is_dir_empty(sb, &new_clu)) { - ret = FFS_FILEEXIST; + ret = -EEXIST; goto out; } } @@ -1328,8 +1331,8 @@ static int ffsMoveFile(struct inode *old_parent_inode, struct file_id_t *fid, num_entries + 1); } out: -#ifdef CONFIG_EXFAT_DELAYED_SYNC - fs_sync(sb, false); +#ifndef CONFIG_EXFAT_DELAYED_SYNC + fs_sync(sb, true); fs_set_vol_flags(sb, VOL_CLEAN); #endif @@ -1337,7 +1340,7 @@ out: ret = FFS_MEDIAERR; out2: /* release the lock for file system critical section */ - up(&p_fs->v_sem); + mutex_unlock(&p_fs->v_mutex); return ret; } @@ -1356,7 +1359,7 @@ static int ffsRemoveFile(struct inode *inode, struct file_id_t *fid) return FFS_INVALIDFID; /* acquire the lock for file system critical section */ - down(&p_fs->v_sem); + mutex_lock(&p_fs->v_mutex); dir.dir = fid->dir.dir; dir.size = fid->dir.size; @@ -1371,7 +1374,7 @@ static int ffsRemoveFile(struct inode *inode, struct file_id_t *fid) } if (p_fs->fs_func->get_entry_attr(ep) & ATTR_READONLY) { - ret = FFS_PERMISSIONERR; + ret = -EPERM; goto out; } fs_set_vol_flags(sb, VOL_DIRTY); @@ -1390,8 +1393,8 @@ static int ffsRemoveFile(struct inode *inode, struct file_id_t *fid) fid->start_clu = CLUSTER_32(~0); fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; -#ifdef CONFIG_EXFAT_DELAYED_SYNC - fs_sync(sb, false); +#ifndef CONFIG_EXFAT_DELAYED_SYNC + fs_sync(sb, true); fs_set_vol_flags(sb, VOL_CLEAN); #endif @@ -1399,7 +1402,7 @@ static int ffsRemoveFile(struct inode *inode, struct file_id_t *fid) ret = FFS_MEDIAERR; out: /* release the lock for file system critical section */ - up(&p_fs->v_sem); + mutex_unlock(&p_fs->v_mutex); return ret; } @@ -1434,18 +1437,18 @@ static int ffsSetAttr(struct inode *inode, u32 attr) } /* acquire the lock for file system critical section */ - down(&p_fs->v_sem); + mutex_lock(&p_fs->v_mutex); /* get the directory entry of given file */ if (p_fs->vol_type == EXFAT) { - es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry, + es = get_entry_set_in_dir(sb, &fid->dir, fid->entry, ES_ALL_ENTRIES, &ep); if (!es) { ret = FFS_MEDIAERR; goto out; } } else { - ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, §or); + ep = get_entry_in_dir(sb, &fid->dir, fid->entry, §or); if (!ep) { ret = FFS_MEDIAERR; goto out; @@ -1479,8 +1482,8 @@ static int ffsSetAttr(struct inode *inode, u32 attr) release_entry_set(es); } -#ifdef CONFIG_EXFAT_DELAYED_SYNC - fs_sync(sb, false); +#ifndef CONFIG_EXFAT_DELAYED_SYNC + fs_sync(sb, true); fs_set_vol_flags(sb, VOL_CLEAN); #endif @@ -1488,7 +1491,7 @@ static int ffsSetAttr(struct inode *inode, u32 attr) ret = FFS_MEDIAERR; out: /* release the lock for file system critical section */ - up(&p_fs->v_sem); + mutex_unlock(&p_fs->v_mutex); return ret; } @@ -1512,7 +1515,7 @@ static int ffsReadStat(struct inode *inode, struct dir_entry_t *info) pr_debug("%s entered\n", __func__); /* acquire the lock for file system critical section */ - down(&p_fs->v_sem); + mutex_lock(&p_fs->v_mutex); if (is_dir) { if ((fid->dir.dir == p_fs->root_dir) && @@ -1554,7 +1557,7 @@ static int ffsReadStat(struct inode *inode, struct dir_entry_t *info) /* get the directory entry of given file or directory */ if (p_fs->vol_type == EXFAT) { - es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry, + es = get_entry_set_in_dir(sb, &fid->dir, fid->entry, ES_2_ENTRIES, &ep); if (!es) { ret = FFS_MEDIAERR; @@ -1562,7 +1565,7 @@ static int ffsReadStat(struct inode *inode, struct dir_entry_t *info) } ep2 = ep + 1; } else { - ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, §or); + ep = get_entry_in_dir(sb, &fid->dir, fid->entry, §or); if (!ep) { ret = FFS_MEDIAERR; goto out; @@ -1594,11 +1597,11 @@ static int ffsReadStat(struct inode *inode, struct dir_entry_t *info) memset((char *)&info->AccessTimestamp, 0, sizeof(struct date_time_t)); - *(uni_name.name) = 0x0; + *uni_name.name = 0x0; /* XXX this is very bad for exfat cuz name is already included in es. * API should be revised */ - p_fs->fs_func->get_uni_name_from_ext_entry(sb, &(fid->dir), fid->entry, + p_fs->fs_func->get_uni_name_from_ext_entry(sb, &fid->dir, fid->entry, uni_name.name); if (*uni_name.name == 0x0 && p_fs->vol_type != EXFAT) get_uni_name_from_dos_entry(sb, (struct dos_dentry_t *)ep, @@ -1641,7 +1644,7 @@ static int ffsReadStat(struct inode *inode, struct dir_entry_t *info) out: /* release the lock for file system critical section */ - up(&p_fs->v_sem); + mutex_unlock(&p_fs->v_mutex); pr_debug("%s exited successfully\n", __func__); return ret; @@ -1662,7 +1665,7 @@ static int ffsWriteStat(struct inode *inode, struct dir_entry_t *info) pr_debug("%s entered (inode %p info %p\n", __func__, inode, info); /* acquire the lock for file system critical section */ - down(&p_fs->v_sem); + mutex_lock(&p_fs->v_mutex); if (is_dir) { if ((fid->dir.dir == p_fs->root_dir) && @@ -1678,7 +1681,7 @@ static int ffsWriteStat(struct inode *inode, struct dir_entry_t *info) /* get the directory entry of given file or directory */ if (p_fs->vol_type == EXFAT) { - es = get_entry_set_in_dir(sb, &(fid->dir), fid->entry, + es = get_entry_set_in_dir(sb, &fid->dir, fid->entry, ES_ALL_ENTRIES, &ep); if (!es) { ret = FFS_MEDIAERR; @@ -1687,7 +1690,7 @@ static int ffsWriteStat(struct inode *inode, struct dir_entry_t *info) ep2 = ep + 1; } else { /* for other than exfat */ - ep = get_entry_in_dir(sb, &(fid->dir), fid->entry, §or); + ep = get_entry_in_dir(sb, &fid->dir, fid->entry, §or); if (!ep) { ret = FFS_MEDIAERR; goto out; @@ -1728,7 +1731,7 @@ static int ffsWriteStat(struct inode *inode, struct dir_entry_t *info) out: /* release the lock for file system critical section */ - up(&p_fs->v_sem); + mutex_unlock(&p_fs->v_mutex); pr_debug("%s exited (%d)\n", __func__, ret); @@ -1754,7 +1757,7 @@ static int ffsMapCluster(struct inode *inode, s32 clu_offset, u32 *clu) return FFS_ERROR; /* acquire the lock for file system critical section */ - down(&p_fs->v_sem); + mutex_lock(&p_fs->v_mutex); fid->rwoffset = (s64)(clu_offset) << p_fs->cluster_size_bits; @@ -1807,7 +1810,7 @@ static int ffsMapCluster(struct inode *inode, s32 clu_offset, u32 *clu) ret = FFS_MEDIAERR; goto out; } else if (num_alloced == 0) { - ret = FFS_FULL; + ret = -ENOSPC; goto out; } @@ -1845,7 +1848,7 @@ static int ffsMapCluster(struct inode *inode, s32 clu_offset, u32 *clu) /* (3) update directory entry */ if (modified) { if (p_fs->vol_type != EXFAT) { - ep = get_entry_in_dir(sb, &(fid->dir), + ep = get_entry_in_dir(sb, &fid->dir, fid->entry, §or); if (!ep) { ret = FFS_MEDIAERR; @@ -1882,7 +1885,7 @@ static int ffsMapCluster(struct inode *inode, s32 clu_offset, u32 *clu) out: /* release the lock for file system critical section */ - up(&p_fs->v_sem); + mutex_unlock(&p_fs->v_mutex); return ret; } @@ -1906,7 +1909,7 @@ static int ffsCreateDir(struct inode *inode, char *path, struct file_id_t *fid) return FFS_ERROR; /* acquire the lock for file system critical section */ - down(&p_fs->v_sem); + mutex_lock(&p_fs->v_mutex); /* check the validity of directory name in the given old pathname */ ret = resolve_path(inode, path, &dir, &uni_name); @@ -1917,8 +1920,8 @@ static int ffsCreateDir(struct inode *inode, char *path, struct file_id_t *fid) ret = create_dir(inode, &dir, &uni_name, fid); -#ifdef CONFIG_EXFAT_DELAYED_SYNC - fs_sync(sb, false); +#ifndef CONFIG_EXFAT_DELAYED_SYNC + fs_sync(sb, true); fs_set_vol_flags(sb, VOL_CLEAN); #endif @@ -1926,7 +1929,7 @@ static int ffsCreateDir(struct inode *inode, char *path, struct file_id_t *fid) ret = FFS_MEDIAERR; out: /* release the lock for file system critical section */ - up(&p_fs->v_sem); + mutex_unlock(&p_fs->v_mutex); return ret; } @@ -1953,10 +1956,10 @@ static int ffsReadDir(struct inode *inode, struct dir_entry_t *dir_entry) /* check if the given file ID is opened */ if (fid->type != TYPE_DIR) - return FFS_PERMISSIONERR; + return -EPERM; /* acquire the lock for file system critical section */ - down(&p_fs->v_sem); + mutex_lock(&p_fs->v_mutex); if (fid->entry == -1) { dir.dir = p_fs->root_dir; @@ -2058,7 +2061,7 @@ static int ffsReadDir(struct inode *inode, struct dir_entry_t *dir_entry) memset((char *)&dir_entry->AccessTimestamp, 0, sizeof(struct date_time_t)); - *(uni_name.name) = 0x0; + *uni_name.name = 0x0; fs_func->get_uni_name_from_ext_entry(sb, &dir, dentry, uni_name.name); if (*uni_name.name == 0x0 && p_fs->vol_type != EXFAT) @@ -2116,7 +2119,7 @@ static int ffsReadDir(struct inode *inode, struct dir_entry_t *dir_entry) } } - *(dir_entry->Name) = '\0'; + *dir_entry->Name = '\0'; fid->rwoffset = (s64)(++dentry); @@ -2125,7 +2128,7 @@ static int ffsReadDir(struct inode *inode, struct dir_entry_t *dir_entry) out: /* release the lock for file system critical section */ - up(&p_fs->v_sem); + mutex_unlock(&p_fs->v_mutex); return ret; } @@ -2151,18 +2154,18 @@ static int ffsRemoveDir(struct inode *inode, struct file_id_t *fid) /* check if the file is "." or ".." */ if (p_fs->vol_type != EXFAT) { if ((dir.dir != p_fs->root_dir) && (dentry < 2)) - return FFS_PERMISSIONERR; + return -EPERM; } /* acquire the lock for file system critical section */ - down(&p_fs->v_sem); + mutex_lock(&p_fs->v_mutex); clu_to_free.dir = fid->start_clu; clu_to_free.size = (s32)((fid->size - 1) >> p_fs->cluster_size_bits) + 1; clu_to_free.flags = fid->flags; if (!is_dir_empty(sb, &clu_to_free)) { - ret = FFS_FILEEXIST; + ret = -EEXIST; goto out; } @@ -2178,8 +2181,8 @@ static int ffsRemoveDir(struct inode *inode, struct file_id_t *fid) fid->start_clu = CLUSTER_32(~0); fid->flags = (p_fs->vol_type == EXFAT) ? 0x03 : 0x01; -#ifdef CONFIG_EXFAT_DELAYED_SYNC - fs_sync(sb, false); +#ifndef CONFIG_EXFAT_DELAYED_SYNC + fs_sync(sb, true); fs_set_vol_flags(sb, VOL_CLEAN); #endif @@ -2188,7 +2191,7 @@ static int ffsRemoveDir(struct inode *inode, struct file_id_t *fid) out: /* release the lock for file system critical section */ - up(&p_fs->v_sem); + mutex_unlock(&p_fs->v_mutex); return ret; } @@ -2202,7 +2205,7 @@ static int exfat_readdir(struct file *filp, struct dir_context *ctx) struct inode *inode = file_inode(filp); struct super_block *sb = inode->i_sb; struct exfat_sb_info *sbi = EXFAT_SB(sb); - struct fs_info_t *p_fs = &(sbi->fs_info); + struct fs_info_t *p_fs = &sbi->fs_info; struct bd_info_t *p_bd = &(EXFAT_SB(sb)->bd_info); struct dir_entry_t de; unsigned long inum; @@ -2293,7 +2296,7 @@ static int exfat_ioctl_volume_id(struct inode *dir) { struct super_block *sb = dir->i_sb; struct exfat_sb_info *sbi = EXFAT_SB(sb); - struct fs_info_t *p_fs = &(sbi->fs_info); + struct fs_info_t *p_fs = &sbi->fs_info; return p_fs->vol_id; } @@ -2351,6 +2354,7 @@ static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl) { struct super_block *sb = dir->i_sb; + struct timespec64 curtime; struct inode *inode; struct file_id_t fid; loff_t i_pos; @@ -2362,20 +2366,23 @@ static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, err = ffsCreateFile(dir, (u8 *)dentry->d_name.name, FM_REGULAR, &fid); if (err) { - if (err == FFS_INVALIDPATH) + if (err == -EINVAL) err = -EINVAL; - else if (err == FFS_FILEEXIST) + else if (err == -EEXIST) err = -EEXIST; - else if (err == FFS_FULL) + else if (err == -ENOSPC) err = -ENOSPC; - else if (err == FFS_NAMETOOLONG) + else if (err == -ENAMETOOLONG) err = -ENAMETOOLONG; else err = -EIO; goto out; } INC_IVERSION(dir); - dir->i_ctime = dir->i_mtime = dir->i_atime = current_time(dir); + curtime = current_time(dir); + dir->i_ctime = curtime; + dir->i_mtime = curtime; + dir->i_atime = curtime; if (IS_DIRSYNC(dir)) (void)exfat_sync_inode(dir); else @@ -2389,7 +2396,10 @@ static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, goto out; } INC_IVERSION(inode); - inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); + curtime = current_time(inode); + inode->i_mtime = curtime; + inode->i_atime = curtime; + inode->i_ctime = curtime; /* * timestamp is already written, so mark_inode_dirty() is unnecessary. */ @@ -2522,6 +2532,7 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry) { struct inode *inode = dentry->d_inode; struct super_block *sb = dir->i_sb; + struct timespec64 curtime; int err; __lock_super(sb); @@ -2532,21 +2543,25 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry) err = ffsRemoveFile(dir, &(EXFAT_I(inode)->fid)); if (err) { - if (err == FFS_PERMISSIONERR) + if (err == -EPERM) err = -EPERM; else err = -EIO; goto out; } INC_IVERSION(dir); - dir->i_mtime = dir->i_atime = current_time(dir); + curtime = current_time(dir); + dir->i_mtime = curtime; + dir->i_atime = curtime; if (IS_DIRSYNC(dir)) (void)exfat_sync_inode(dir); else mark_inode_dirty(dir); clear_nlink(inode); - inode->i_mtime = inode->i_atime = current_time(inode); + curtime = current_time(inode); + inode->i_mtime = curtime; + inode->i_atime = curtime; exfat_detach(inode); remove_inode_hash(inode); @@ -2560,6 +2575,7 @@ static int exfat_symlink(struct inode *dir, struct dentry *dentry, const char *target) { struct super_block *sb = dir->i_sb; + struct timespec64 curtime; struct inode *inode; struct file_id_t fid; loff_t i_pos; @@ -2573,11 +2589,11 @@ static int exfat_symlink(struct inode *dir, struct dentry *dentry, err = ffsCreateFile(dir, (u8 *)dentry->d_name.name, FM_SYMLINK, &fid); if (err) { - if (err == FFS_INVALIDPATH) + if (err == -EINVAL) err = -EINVAL; - else if (err == FFS_FILEEXIST) + else if (err == -EEXIST) err = -EEXIST; - else if (err == FFS_FULL) + else if (err == -ENOSPC) err = -ENOSPC; else err = -EIO; @@ -2589,7 +2605,7 @@ static int exfat_symlink(struct inode *dir, struct dentry *dentry, if (err) { ffsRemoveFile(dir, &fid); - if (err == FFS_FULL) + if (err == -ENOSPC) err = -ENOSPC; else err = -EIO; @@ -2597,7 +2613,10 @@ static int exfat_symlink(struct inode *dir, struct dentry *dentry, } INC_IVERSION(dir); - dir->i_ctime = dir->i_mtime = dir->i_atime = current_time(dir); + curtime = current_time(dir); + dir->i_ctime = curtime; + dir->i_mtime = curtime; + dir->i_atime = curtime; if (IS_DIRSYNC(dir)) (void)exfat_sync_inode(dir); else @@ -2611,7 +2630,10 @@ static int exfat_symlink(struct inode *dir, struct dentry *dentry, goto out; } INC_IVERSION(inode); - inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); + curtime = current_time(inode); + inode->i_mtime = curtime; + inode->i_atime = curtime; + inode->i_ctime = curtime; /* timestamp is already written, so mark_inode_dirty() is unneeded. */ EXFAT_I(inode)->target = kmemdup(target, len + 1, GFP_KERNEL); @@ -2632,6 +2654,7 @@ out: static int exfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { struct super_block *sb = dir->i_sb; + struct timespec64 curtime; struct inode *inode; struct file_id_t fid; loff_t i_pos; @@ -2643,20 +2666,23 @@ static int exfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) err = ffsCreateDir(dir, (u8 *)dentry->d_name.name, &fid); if (err) { - if (err == FFS_INVALIDPATH) + if (err == -EINVAL) err = -EINVAL; - else if (err == FFS_FILEEXIST) + else if (err == -EEXIST) err = -EEXIST; - else if (err == FFS_FULL) + else if (err == -ENOSPC) err = -ENOSPC; - else if (err == FFS_NAMETOOLONG) + else if (err == -ENAMETOOLONG) err = -ENAMETOOLONG; else err = -EIO; goto out; } INC_IVERSION(dir); - dir->i_ctime = dir->i_mtime = dir->i_atime = current_time(dir); + curtime = current_time(dir); + dir->i_ctime = curtime; + dir->i_mtime = curtime; + dir->i_atime = curtime; if (IS_DIRSYNC(dir)) (void)exfat_sync_inode(dir); else @@ -2671,7 +2697,10 @@ static int exfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) goto out; } INC_IVERSION(inode); - inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); + curtime = current_time(inode); + inode->i_mtime = curtime; + inode->i_atime = curtime; + inode->i_ctime = curtime; /* timestamp is already written, so mark_inode_dirty() is unneeded. */ dentry->d_time = GET_IVERSION(dentry->d_parent->d_inode); @@ -2687,6 +2716,7 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry) { struct inode *inode = dentry->d_inode; struct super_block *sb = dir->i_sb; + struct timespec64 curtime; int err; __lock_super(sb); @@ -2697,20 +2727,22 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry) err = ffsRemoveDir(dir, &(EXFAT_I(inode)->fid)); if (err) { - if (err == FFS_INVALIDPATH) + if (err == -EINVAL) err = -EINVAL; - else if (err == FFS_FILEEXIST) + else if (err == -EEXIST) err = -ENOTEMPTY; - else if (err == FFS_NOTFOUND) + else if (err == -ENOENT) err = -ENOENT; - else if (err == FFS_DIRBUSY) + else if (err == -EBUSY) err = -EBUSY; else err = -EIO; goto out; } INC_IVERSION(dir); - dir->i_mtime = dir->i_atime = current_time(dir); + curtime = current_time(dir); + dir->i_mtime = curtime; + dir->i_atime = curtime; if (IS_DIRSYNC(dir)) (void)exfat_sync_inode(dir); else @@ -2718,7 +2750,9 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry) drop_nlink(dir); clear_nlink(inode); - inode->i_mtime = inode->i_atime = current_time(inode); + curtime = current_time(inode); + inode->i_mtime = curtime; + inode->i_atime = curtime; exfat_detach(inode); remove_inode_hash(inode); @@ -2734,6 +2768,7 @@ static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry, { struct inode *old_inode, *new_inode; struct super_block *sb = old_dir->i_sb; + struct timespec64 curtime; loff_t i_pos; int err; @@ -2752,23 +2787,26 @@ static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry, err = ffsMoveFile(old_dir, &(EXFAT_I(old_inode)->fid), new_dir, new_dentry); if (err) { - if (err == FFS_PERMISSIONERR) + if (err == -EPERM) err = -EPERM; - else if (err == FFS_INVALIDPATH) + else if (err == -EINVAL) err = -EINVAL; - else if (err == FFS_FILEEXIST) + else if (err == -EEXIST) err = -EEXIST; - else if (err == FFS_NOTFOUND) + else if (err == -ENOENT) err = -ENOENT; - else if (err == FFS_FULL) + else if (err == -ENOSPC) err = -ENOSPC; else err = -EIO; goto out; } INC_IVERSION(new_dir); - new_dir->i_ctime = new_dir->i_mtime = new_dir->i_atime = - current_time(new_dir); + curtime = current_time(new_dir); + new_dir->i_ctime = curtime; + new_dir->i_mtime = curtime; + new_dir->i_atime = curtime; + if (IS_DIRSYNC(new_dir)) (void)exfat_sync_inode(new_dir); else @@ -2790,7 +2828,9 @@ static int exfat_rename(struct inode *old_dir, struct dentry *old_dentry, inc_nlink(new_dir); } INC_IVERSION(old_dir); - old_dir->i_ctime = old_dir->i_mtime = current_time(old_dir); + curtime = current_time(old_dir); + old_dir->i_ctime = curtime; + old_dir->i_mtime = curtime; if (IS_DIRSYNC(old_dir)) (void)exfat_sync_inode(old_dir); else @@ -2814,13 +2854,16 @@ static int exfat_cont_expand(struct inode *inode, loff_t size) { struct address_space *mapping = inode->i_mapping; loff_t start = i_size_read(inode), count = size - i_size_read(inode); + struct timespec64 curtime; int err, err2; err = generic_cont_expand_simple(inode, size); if (err != 0) return err; - inode->i_ctime = inode->i_mtime = current_time(inode); + curtime = current_time(inode); + inode->i_ctime = curtime; + inode->i_mtime = curtime; mark_inode_dirty(inode); if (IS_SYNC(inode)) { @@ -2895,7 +2938,8 @@ static void exfat_truncate(struct inode *inode, loff_t old_size) { struct super_block *sb = inode->i_sb; struct exfat_sb_info *sbi = EXFAT_SB(sb); - struct fs_info_t *p_fs = &(sbi->fs_info); + struct fs_info_t *p_fs = &sbi->fs_info; + struct timespec64 curtime; int err; __lock_super(sb); @@ -2914,7 +2958,9 @@ static void exfat_truncate(struct inode *inode, loff_t old_size) if (err) goto out; - inode->i_ctime = inode->i_mtime = current_time(inode); + curtime = current_time(inode); + inode->i_ctime = curtime; + inode->i_mtime = curtime; if (IS_DIRSYNC(inode)) (void)exfat_sync_inode(inode); else @@ -2936,8 +2982,8 @@ static int exfat_setattr(struct dentry *dentry, struct iattr *attr) pr_debug("%s entered\n", __func__); - if ((attr->ia_valid & ATTR_SIZE) - && (attr->ia_size > i_size_read(inode))) { + if ((attr->ia_valid & ATTR_SIZE) && + attr->ia_size > i_size_read(inode)) { error = exfat_cont_expand(inode, attr->ia_size); if (error || attr->ia_valid == ATTR_SIZE) return error; @@ -2946,8 +2992,8 @@ static int exfat_setattr(struct dentry *dentry, struct iattr *attr) ia_valid = attr->ia_valid; - if ((ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) - && exfat_allow_set_time(sbi, inode)) { + if ((ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) && + exfat_allow_set_time(sbi, inode)) { attr->ia_valid &= ~(ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET); @@ -3073,8 +3119,8 @@ static int exfat_bmap(struct inode *inode, sector_t sector, sector_t *phys, { struct super_block *sb = inode->i_sb; struct exfat_sb_info *sbi = EXFAT_SB(sb); - struct fs_info_t *p_fs = &(sbi->fs_info); - struct bd_info_t *p_bd = &(sbi->bd_info); + struct fs_info_t *p_fs = &sbi->fs_info; + struct bd_info_t *p_bd = &sbi->bd_info; const unsigned long blocksize = sb->s_blocksize; const unsigned char blocksize_bits = sb->s_blocksize_bits; sector_t last_block; @@ -3115,7 +3161,7 @@ static int exfat_bmap(struct inode *inode, sector_t sector, sector_t *phys, err = ffsMapCluster(inode, clu_offset, &cluster); if (err) { - if (err == FFS_FULL) + if (err == -ENOSPC) return -ENOSPC; else return -EIO; @@ -3215,6 +3261,7 @@ static int exfat_write_end(struct file *file, struct address_space *mapping, { struct inode *inode = mapping->host; struct file_id_t *fid = &(EXFAT_I(inode)->fid); + struct timespec64 curtime; int err; err = generic_write_end(file, mapping, pos, len, copied, pagep, fsdata); @@ -3223,7 +3270,9 @@ static int exfat_write_end(struct file *file, struct address_space *mapping, exfat_write_failed(mapping, pos + len); if (!(err < 0) && !(fid->attr & ATTR_ARCHIVE)) { - inode->i_mtime = inode->i_ctime = current_time(inode); + curtime = current_time(inode); + inode->i_mtime = curtime; + inode->i_ctime = curtime; fid->attr |= ATTR_ARCHIVE; mark_inode_dirty(inode); } @@ -3302,7 +3351,7 @@ static struct inode *exfat_iget(struct super_block *sb, loff_t i_pos) static int exfat_fill_inode(struct inode *inode, struct file_id_t *fid) { struct exfat_sb_info *sbi = EXFAT_SB(inode->i_sb); - struct fs_info_t *p_fs = &(sbi->fs_info); + struct fs_info_t *p_fs = &sbi->fs_info; struct dir_entry_t info; memcpy(&(EXFAT_I(inode)->fid), fid, sizeof(struct file_id_t)); @@ -3674,7 +3723,8 @@ static int parse_options(char *options, int silent, int *debug, opts->fs_uid = current_uid(); opts->fs_gid = current_gid(); - opts->fs_fmask = opts->fs_dmask = current->fs->umask; + opts->fs_fmask = current->fs->umask; + opts->fs_dmask = current->fs->umask; opts->allow_utime = U16_MAX; opts->codepage = exfat_default_codepage; opts->iocharset = exfat_default_iocharset; @@ -3787,7 +3837,8 @@ static int exfat_read_root(struct inode *inode) { struct super_block *sb = inode->i_sb; struct exfat_sb_info *sbi = EXFAT_SB(sb); - struct fs_info_t *p_fs = &(sbi->fs_info); + struct fs_info_t *p_fs = &sbi->fs_info; + struct timespec64 curtime; struct dir_entry_t info; EXFAT_I(inode)->fid.dir.dir = p_fs->root_dir; @@ -3818,7 +3869,10 @@ static int exfat_read_root(struct inode *inode) EXFAT_I(inode)->mmu_private = i_size_read(inode); exfat_save_attr(inode, ATTR_SUBDIR); - inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); + curtime = current_time(inode); + inode->i_mtime = curtime; + inode->i_atime = curtime; + inode->i_ctime = curtime; set_nlink(inode, info.NumSubdirs + 2); return 0; @@ -3984,10 +4038,10 @@ static void exfat_debug_kill_sb(struct super_block *sb) * invalidate_bdev drops all device cache include * dirty. We use this to simulate device removal. */ - down(&p_fs->v_sem); + mutex_lock(&p_fs->v_mutex); FAT_release_all(sb); buf_release_all(sb); - up(&p_fs->v_sem); + mutex_unlock(&p_fs->v_mutex); invalidate_bdev(bdev); } diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig index cb61c2a772bd..d994aea84b21 100644 --- a/drivers/staging/fbtft/Kconfig +++ b/drivers/staging/fbtft/Kconfig @@ -112,6 +112,13 @@ config FB_TFT_S6D1121 help Generic Framebuffer support for S6D1121 +config FB_TFT_SEPS525 + tristate "FB driver for the SEPS525 LCD Controller" + depends on FB_TFT + help + Generic Framebuffer support for SEPS525 + Say Y if you have such a display that utilizes this controller. + config FB_TFT_SH1106 tristate "FB driver for the SH1106 OLED Controller" depends on FB_TFT diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile index 27af43f32f81..e87193f7df14 100644 --- a/drivers/staging/fbtft/Makefile +++ b/drivers/staging/fbtft/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_FB_TFT_PCD8544) += fb_pcd8544.o obj-$(CONFIG_FB_TFT_RA8875) += fb_ra8875.o obj-$(CONFIG_FB_TFT_S6D02A1) += fb_s6d02a1.o obj-$(CONFIG_FB_TFT_S6D1121) += fb_s6d1121.o +obj-$(CONFIG_FB_TFT_SEPS525) += fb_seps525.o obj-$(CONFIG_FB_TFT_SH1106) += fb_sh1106.o obj-$(CONFIG_FB_TFT_SSD1289) += fb_ssd1289.o obj-$(CONFIG_FB_TFT_SSD1305) += fb_ssd1305.o diff --git a/drivers/staging/fbtft/fb_seps525.c b/drivers/staging/fbtft/fb_seps525.c new file mode 100644 index 000000000000..05882e2cde7f --- /dev/null +++ b/drivers/staging/fbtft/fb_seps525.c @@ -0,0 +1,213 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * FB driver for the NHD-1.69-160128UGC3 (Newhaven Display International, Inc.) + * using the SEPS525 (Syncoam) LCD Controller + * + * Copyright (C) 2016 Analog Devices Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/gpio.h> +#include <linux/delay.h> + +#include "fbtft.h" + +#define DRVNAME "fb_seps525" +#define WIDTH 160 +#define HEIGHT 128 + +#define SEPS525_INDEX 0x00 +#define SEPS525_STATUS_RD 0x01 +#define SEPS525_OSC_CTL 0x02 +#define SEPS525_IREF 0x80 +#define SEPS525_CLOCK_DIV 0x03 +#define SEPS525_REDUCE_CURRENT 0x04 +#define SEPS525_SOFT_RST 0x05 +#define SEPS525_DISP_ONOFF 0x06 +#define SEPS525_PRECHARGE_TIME_R 0x08 +#define SEPS525_PRECHARGE_TIME_G 0x09 +#define SEPS525_PRECHARGE_TIME_B 0x0A +#define SEPS525_PRECHARGE_CURRENT_R 0x0B +#define SEPS525_PRECHARGE_CURRENT_G 0x0C +#define SEPS525_PRECHARGE_CURRENT_B 0x0D +#define SEPS525_DRIVING_CURRENT_R 0x10 +#define SEPS525_DRIVING_CURRENT_G 0x11 +#define SEPS525_DRIVING_CURRENT_B 0x12 +#define SEPS525_DISPLAYMODE_SET 0x13 +#define SEPS525_RGBIF 0x14 +#define SEPS525_RGB_POL 0x15 +#define SEPS525_MEMORY_WRITEMODE 0x16 +#define SEPS525_MX1_ADDR 0x17 +#define SEPS525_MX2_ADDR 0x18 +#define SEPS525_MY1_ADDR 0x19 +#define SEPS525_MY2_ADDR 0x1A +#define SEPS525_MEMORY_ACCESS_POINTER_X 0x20 +#define SEPS525_MEMORY_ACCESS_POINTER_Y 0x21 +#define SEPS525_DDRAM_DATA_ACCESS_PORT 0x22 +#define SEPS525_GRAY_SCALE_TABLE_INDEX 0x50 +#define SEPS525_GRAY_SCALE_TABLE_DATA 0x51 +#define SEPS525_DUTY 0x28 +#define SEPS525_DSL 0x29 +#define SEPS525_D1_DDRAM_FAC 0x2E +#define SEPS525_D1_DDRAM_FAR 0x2F +#define SEPS525_D2_DDRAM_SAC 0x31 +#define SEPS525_D2_DDRAM_SAR 0x32 +#define SEPS525_SCR1_FX1 0x33 +#define SEPS525_SCR1_FX2 0x34 +#define SEPS525_SCR1_FY1 0x35 +#define SEPS525_SCR1_FY2 0x36 +#define SEPS525_SCR2_SX1 0x37 +#define SEPS525_SCR2_SX2 0x38 +#define SEPS525_SCR2_SY1 0x39 +#define SEPS525_SCR2_SY2 0x3A +#define SEPS525_SCREEN_SAVER_CONTEROL 0x3B +#define SEPS525_SS_SLEEP_TIMER 0x3C +#define SEPS525_SCREEN_SAVER_MODE 0x3D +#define SEPS525_SS_SCR1_FU 0x3E +#define SEPS525_SS_SCR1_MXY 0x3F +#define SEPS525_SS_SCR2_FU 0x40 +#define SEPS525_SS_SCR2_MXY 0x41 +#define SEPS525_MOVING_DIRECTION 0x42 +#define SEPS525_SS_SCR2_SX1 0x47 +#define SEPS525_SS_SCR2_SX2 0x48 +#define SEPS525_SS_SCR2_SY1 0x49 +#define SEPS525_SS_SCR2_SY2 0x4A + +/* SEPS525_DISPLAYMODE_SET */ +#define MODE_SWAP_BGR BIT(7) +#define MODE_SM BIT(6) +#define MODE_RD BIT(5) +#define MODE_CD BIT(4) + +#define seps525_use_window 0 /* FBTFT doesn't really use it today */ + +/* Init sequence taken from: Arduino Library for the Adafruit 2.2" display */ +static int init_display(struct fbtft_par *par) +{ + par->fbtftops.reset(par); + + usleep_range(1000, 5000); + + /* Disable Oscillator Power Down */ + write_reg(par, SEPS525_REDUCE_CURRENT, 0x03); + usleep_range(1000, 5000); + /* Set Normal Driving Current */ + write_reg(par, SEPS525_REDUCE_CURRENT, 0x00); + usleep_range(1000, 5000); + + write_reg(par, SEPS525_SCREEN_SAVER_CONTEROL, 0x00); + /* Set EXPORT1 Pin at Internal Clock */ + write_reg(par, SEPS525_OSC_CTL, 0x01); + /* Set Clock as 120 Frames/Sec */ + write_reg(par, SEPS525_CLOCK_DIV, 0x90); + /* Set Reference Voltage Controlled by External Resister */ + write_reg(par, SEPS525_IREF, 0x01); + + /* precharge time R G B */ + write_reg(par, SEPS525_PRECHARGE_TIME_R, 0x04); + write_reg(par, SEPS525_PRECHARGE_TIME_G, 0x05); + write_reg(par, SEPS525_PRECHARGE_TIME_B, 0x05); + + /* precharge current R G B (uA) */ + write_reg(par, SEPS525_PRECHARGE_CURRENT_R, 0x9D); + write_reg(par, SEPS525_PRECHARGE_CURRENT_G, 0x8C); + write_reg(par, SEPS525_PRECHARGE_CURRENT_B, 0x57); + + /* driving current R G B (uA) */ + write_reg(par, SEPS525_DRIVING_CURRENT_R, 0x56); + write_reg(par, SEPS525_DRIVING_CURRENT_G, 0x4D); + write_reg(par, SEPS525_DRIVING_CURRENT_B, 0x46); + /* Set Color Sequence */ + write_reg(par, SEPS525_DISPLAYMODE_SET, 0xA0); + write_reg(par, SEPS525_RGBIF, 0x01); /* Set MCU Interface Mode */ + /* Set Memory Write Mode */ + write_reg(par, SEPS525_MEMORY_WRITEMODE, 0x66); + write_reg(par, SEPS525_DUTY, 0x7F); /* 1/128 Duty (0x0F~0x7F) */ + /* Set Mapping RAM Display Start Line (0x00~0x7F) */ + write_reg(par, SEPS525_DSL, 0x00); + write_reg(par, SEPS525_DISP_ONOFF, 0x01); /* Display On (0x00/0x01) */ + /* Set All Internal Register Value as Normal Mode */ + write_reg(par, SEPS525_SOFT_RST, 0x00); + /* Set RGB Interface Polarity as Active Low */ + write_reg(par, SEPS525_RGB_POL, 0x00); + + write_reg(par, SEPS525_DDRAM_DATA_ACCESS_PORT); + + return 0; +} + +static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye) +{ + if (seps525_use_window) { + /* Set Window Xs,Ys Xe,Ye*/ + write_reg(par, SEPS525_MX1_ADDR, xs); + write_reg(par, SEPS525_MX2_ADDR, xe); + write_reg(par, SEPS525_MY1_ADDR, ys); + write_reg(par, SEPS525_MY2_ADDR, ye); + } + /* start position X,Y */ + write_reg(par, SEPS525_MEMORY_ACCESS_POINTER_X, xs); + write_reg(par, SEPS525_MEMORY_ACCESS_POINTER_Y, ys); + + write_reg(par, SEPS525_DDRAM_DATA_ACCESS_PORT); +} + +static int set_var(struct fbtft_par *par) +{ + u8 val; + + switch (par->info->var.rotate) { + case 0: + val = 0; + break; + case 180: + val = MODE_RD | MODE_CD; + break; + case 90: + case 270: + + default: + return -EINVAL; + } + /* Memory Access Control */ + write_reg(par, SEPS525_DISPLAYMODE_SET, val | + (par->bgr ? MODE_SWAP_BGR : 0)); + + write_reg(par, SEPS525_DDRAM_DATA_ACCESS_PORT); + + return 0; +} + +static struct fbtft_display display = { + .regwidth = 8, + .width = WIDTH, + .height = HEIGHT, + .fbtftops = { + .init_display = init_display, + .set_addr_win = set_addr_win, + .set_var = set_var, + }, +}; + +FBTFT_REGISTER_DRIVER(DRVNAME, "syncoam,seps525", &display); + +MODULE_ALIAS("spi:" DRVNAME); +MODULE_ALIAS("platform:" DRVNAME); +MODULE_ALIAS("spi:seps525"); +MODULE_ALIAS("platform:seps525"); + +MODULE_DESCRIPTION("FB driver for the SEPS525 LCD Controller"); +MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/fbtft/fb_uc1611.c b/drivers/staging/fbtft/fb_uc1611.c index 65681d0fe200..e763205e9e4f 100644 --- a/drivers/staging/fbtft/fb_uc1611.c +++ b/drivers/staging/fbtft/fb_uc1611.c @@ -91,7 +91,7 @@ static int init_display(struct fbtft_par *par) write_reg(par, 0x2C | (pump & 0x03)); /* Set inverse display */ - write_reg(par, 0xA6 | (0x01 & 0x01)); + write_reg(par, 0xA6 | 0x01); /* Set 4-bit grayscale mode */ write_reg(par, 0xD0 | (0x02 & 0x03)); @@ -157,8 +157,8 @@ static int set_var(struct fbtft_par *par) /* Set RAM address control */ write_reg(par, 0x88 | (0x0 & 0x1) << 2 /* Increment positively */ - | (0x1 & 0x1) << 1 /* Increment page first */ - | (0x1 & 0x1)); /* Wrap around (default) */ + | (0x1 << 1) /* Increment page first */ + | 0x1); /* Wrap around (default) */ /* Set LCD mapping */ write_reg(par, 0xC0 @@ -171,11 +171,11 @@ static int set_var(struct fbtft_par *par) write_reg(par, 0x88 | (0x0 & 0x1) << 2 /* Increment positively */ | (0x0 & 0x1) << 1 /* Increment column first */ - | (0x1 & 0x1)); /* Wrap around (default) */ + | 0x1); /* Wrap around (default) */ /* Set LCD mapping */ write_reg(par, 0xC0 - | (0x1 & 0x1) << 2 /* Mirror Y ON */ + | (0x1 << 2) /* Mirror Y ON */ | (0x0 & 0x1) << 1 /* Mirror X OFF */ | (0x0 & 0x1)); /* MS nibble last (default) */ break; @@ -183,13 +183,13 @@ static int set_var(struct fbtft_par *par) /* Set RAM address control */ write_reg(par, 0x88 | (0x0 & 0x1) << 2 /* Increment positively */ - | (0x1 & 0x1) << 1 /* Increment page first */ - | (0x1 & 0x1)); /* Wrap around (default) */ + | (0x1 << 1) /* Increment page first */ + | 0x1); /* Wrap around (default) */ /* Set LCD mapping */ write_reg(par, 0xC0 - | (0x1 & 0x1) << 2 /* Mirror Y ON */ - | (0x1 & 0x1) << 1 /* Mirror X ON */ + | (0x1 << 2) /* Mirror Y ON */ + | (0x1 << 1) /* Mirror X ON */ | (0x0 & 0x1)); /* MS nibble last (default) */ break; default: @@ -197,12 +197,12 @@ static int set_var(struct fbtft_par *par) write_reg(par, 0x88 | (0x0 & 0x1) << 2 /* Increment positively */ | (0x0 & 0x1) << 1 /* Increment column first */ - | (0x1 & 0x1)); /* Wrap around (default) */ + | 0x1); /* Wrap around (default) */ /* Set LCD mapping */ write_reg(par, 0xC0 | (0x0 & 0x1) << 2 /* Mirror Y OFF */ - | (0x1 & 0x1) << 1 /* Mirror X ON */ + | (0x1 << 1) /* Mirror X ON */ | (0x0 & 0x1)); /* MS nibble last (default) */ break; } diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c index a0a67aa517f0..63d36f21eb98 100644 --- a/drivers/staging/fbtft/fbtft-core.c +++ b/drivers/staging/fbtft/fbtft-core.c @@ -317,7 +317,7 @@ static void fbtft_mkdirty(struct fb_info *info, int y, int height) /* special case, needed ? */ if (y == -1) { y = 0; - height = info->var.yres - 1; + height = info->var.yres; } /* Mark display lines/area as dirty */ diff --git a/drivers/staging/fieldbus/anybuss/anybuss-client.h b/drivers/staging/fieldbus/anybuss/anybuss-client.h index 0c4b6a1ffe10..8ee1f1baccf1 100644 --- a/drivers/staging/fieldbus/anybuss/anybuss-client.h +++ b/drivers/staging/fieldbus/anybuss/anybuss-client.h @@ -12,6 +12,9 @@ #include <linux/types.h> #include <linux/poll.h> +/* move to <linux/fieldbus_dev.h> when taking this out of staging */ +#include "../fieldbus_dev.h" + struct anybuss_host; struct anybuss_client { @@ -61,12 +64,6 @@ anybuss_set_drvdata(struct anybuss_client *client, void *data) int anybuss_set_power(struct anybuss_client *client, bool power_on); -enum anybuss_offl_mode { - AB_OFFL_MODE_CLEAR = 0, - AB_OFFL_MODE_FREEZE, - AB_OFFL_MODE_SET -}; - struct anybuss_memcfg { u16 input_io; u16 input_dpram; @@ -76,7 +73,7 @@ struct anybuss_memcfg { u16 output_dpram; u16 output_total; - enum anybuss_offl_mode offl_mode; + enum fieldbus_dev_offl_mode offl_mode; }; int anybuss_start_init(struct anybuss_client *client, diff --git a/drivers/staging/fieldbus/anybuss/arcx-anybus.c b/drivers/staging/fieldbus/anybuss/arcx-anybus.c index 2ecffa42e561..5b8d0bae9ff3 100644 --- a/drivers/staging/fieldbus/anybuss/arcx-anybus.c +++ b/drivers/staging/fieldbus/anybuss/arcx-anybus.c @@ -127,12 +127,10 @@ static const struct regmap_config arcx_regmap_cfg = { static struct regmap *create_parallel_regmap(struct platform_device *pdev, int idx) { - struct resource *res; void __iomem *base; struct device *dev = &pdev->dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, idx + 1); - base = devm_ioremap_resource(dev, res); + base = devm_platform_ioremap_resource(pdev, idx + 1); if (IS_ERR(base)) return ERR_CAST(base); return devm_regmap_init_mmio(dev, base, &arcx_regmap_cfg); @@ -230,7 +228,6 @@ static int controller_probe(struct platform_device *pdev) struct regulator_config config = { }; struct regulator_dev *regulator; int err, id; - struct resource *res; struct anybuss_host *host; u8 status1, cap; @@ -244,8 +241,7 @@ static int controller_probe(struct platform_device *pdev) return PTR_ERR(cd->reset_gpiod); /* CPLD control memory, sits at index 0 */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - cd->cpld_base = devm_ioremap_resource(dev, res); + cd->cpld_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(cd->cpld_base)) { dev_err(dev, "failed to map cpld base address\n"); diff --git a/drivers/staging/fieldbus/anybuss/hms-profinet.c b/drivers/staging/fieldbus/anybuss/hms-profinet.c index 5446843e35f4..31c43a0a5776 100644 --- a/drivers/staging/fieldbus/anybuss/hms-profinet.c +++ b/drivers/staging/fieldbus/anybuss/hms-profinet.c @@ -96,7 +96,7 @@ static int __profi_enable(struct profi_priv *priv) .output_io = 220, .output_dpram = PROFI_DPRAM_SIZE, .output_total = PROFI_DPRAM_SIZE, - .offl_mode = AB_OFFL_MODE_CLEAR, + .offl_mode = FIELDBUS_DEV_OFFL_MODE_CLEAR, }; /* diff --git a/drivers/staging/fieldbus/anybuss/host.c b/drivers/staging/fieldbus/anybuss/host.c index f69dc4930457..549cb7d51af8 100644 --- a/drivers/staging/fieldbus/anybuss/host.c +++ b/drivers/staging/fieldbus/anybuss/host.c @@ -1022,13 +1022,13 @@ int anybuss_start_init(struct anybuss_client *client, }; switch (cfg->offl_mode) { - case AB_OFFL_MODE_CLEAR: + case FIELDBUS_DEV_OFFL_MODE_CLEAR: op_mode = 0; break; - case AB_OFFL_MODE_FREEZE: + case FIELDBUS_DEV_OFFL_MODE_FREEZE: op_mode = OP_MODE_FBFC; break; - case AB_OFFL_MODE_SET: + case FIELDBUS_DEV_OFFL_MODE_SET: op_mode = OP_MODE_FBS; break; default: diff --git a/drivers/staging/fieldbus/dev_core.c b/drivers/staging/fieldbus/dev_core.c index f6f5b92ba914..1ba0234cc60d 100644 --- a/drivers/staging/fieldbus/dev_core.c +++ b/drivers/staging/fieldbus/dev_core.c @@ -23,9 +23,6 @@ static dev_t fieldbus_devt; static DEFINE_IDA(fieldbus_ida); static DEFINE_MUTEX(fieldbus_mtx); -static const char ctrl_enabled[] = "enabled"; -static const char ctrl_disabled[] = "disabled"; - static ssize_t online_show(struct device *dev, struct device_attribute *attr, char *buf) { diff --git a/drivers/staging/fieldbus/fieldbus_dev.h b/drivers/staging/fieldbus/fieldbus_dev.h index a10fc3b446dc..301dca3b8d71 100644 --- a/drivers/staging/fieldbus/fieldbus_dev.h +++ b/drivers/staging/fieldbus/fieldbus_dev.h @@ -15,6 +15,12 @@ enum fieldbus_dev_type { FIELDBUS_DEV_TYPE_PROFINET, }; +enum fieldbus_dev_offl_mode { + FIELDBUS_DEV_OFFL_MODE_CLEAR = 0, + FIELDBUS_DEV_OFFL_MODE_FREEZE, + FIELDBUS_DEV_OFFL_MODE_SET +}; + /** * struct fieldbus_dev - Fieldbus device * @read_area: [DRIVER] function to read the process data area of the diff --git a/drivers/staging/gasket/gasket_ioctl.c b/drivers/staging/gasket/gasket_ioctl.c index 240f9bb10b71..e3047d36d8db 100644 --- a/drivers/staging/gasket/gasket_ioctl.c +++ b/drivers/staging/gasket/gasket_ioctl.c @@ -34,8 +34,8 @@ static int gasket_set_event_fd(struct gasket_dev *gasket_dev, trace_gasket_ioctl_eventfd_data(die.interrupt, die.event_fd); - return gasket_interrupt_set_eventfd( - gasket_dev->interrupt_data, die.interrupt, die.event_fd); + return gasket_interrupt_set_eventfd(gasket_dev->interrupt_data, + die.interrupt, die.event_fd); } /* Read the size of the page table. */ @@ -54,9 +54,9 @@ static int gasket_read_page_table_size(struct gasket_dev *gasket_dev, ibuf.size = gasket_page_table_num_entries( gasket_dev->page_table[ibuf.page_table_index]); - trace_gasket_ioctl_page_table_data( - ibuf.page_table_index, ibuf.size, ibuf.host_address, - ibuf.device_address); + trace_gasket_ioctl_page_table_data(ibuf.page_table_index, ibuf.size, + ibuf.host_address, + ibuf.device_address); if (copy_to_user(argp, &ibuf, sizeof(ibuf))) return -EFAULT; @@ -101,9 +101,9 @@ static int gasket_partition_page_table(struct gasket_dev *gasket_dev, if (copy_from_user(&ibuf, argp, sizeof(struct gasket_page_table_ioctl))) return -EFAULT; - trace_gasket_ioctl_page_table_data( - ibuf.page_table_index, ibuf.size, ibuf.host_address, - ibuf.device_address); + trace_gasket_ioctl_page_table_data(ibuf.page_table_index, ibuf.size, + ibuf.host_address, + ibuf.device_address); if (ibuf.page_table_index >= gasket_dev->num_page_tables) return -EFAULT; diff --git a/drivers/staging/iio/accel/adis16240.c b/drivers/staging/iio/accel/adis16240.c index 82099db4bf0c..a480409090c0 100644 --- a/drivers/staging/iio/accel/adis16240.c +++ b/drivers/staging/iio/accel/adis16240.c @@ -7,7 +7,6 @@ #include <linux/interrupt.h> #include <linux/irq.h> -#include <linux/gpio.h> #include <linux/delay.h> #include <linux/device.h> #include <linux/kernel.h> diff --git a/drivers/staging/iio/adc/ad7192.c b/drivers/staging/iio/adc/ad7192.c index e6b660489165..bf3e2a9cc07f 100644 --- a/drivers/staging/iio/adc/ad7192.c +++ b/drivers/staging/iio/adc/ad7192.c @@ -155,6 +155,11 @@ * The DOUT/RDY output must also be wired to an interrupt capable GPIO. */ +enum { + AD7192_SYSCALIB_ZERO_SCALE, + AD7192_SYSCALIB_FULL_SCALE, +}; + struct ad7192_state { struct regulator *avdd; struct regulator *dvdd; @@ -169,10 +174,80 @@ struct ad7192_state { u8 devid; u8 clock_sel; struct mutex lock; /* protect sensor state */ + u8 syscalib_mode[8]; struct ad_sigma_delta sd; }; +static const char * const ad7192_syscalib_modes[] = { + [AD7192_SYSCALIB_ZERO_SCALE] = "zero_scale", + [AD7192_SYSCALIB_FULL_SCALE] = "full_scale", +}; + +static int ad7192_set_syscalib_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + unsigned int mode) +{ + struct ad7192_state *st = iio_priv(indio_dev); + + st->syscalib_mode[chan->channel] = mode; + + return 0; +} + +static int ad7192_get_syscalib_mode(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct ad7192_state *st = iio_priv(indio_dev); + + return st->syscalib_mode[chan->channel]; +} + +static ssize_t ad7192_write_syscalib(struct iio_dev *indio_dev, + uintptr_t private, + const struct iio_chan_spec *chan, + const char *buf, size_t len) +{ + struct ad7192_state *st = iio_priv(indio_dev); + bool sys_calib; + int ret, temp; + + ret = strtobool(buf, &sys_calib); + if (ret) + return ret; + + temp = st->syscalib_mode[chan->channel]; + if (sys_calib) { + if (temp == AD7192_SYSCALIB_ZERO_SCALE) + ret = ad_sd_calibrate(&st->sd, AD7192_MODE_CAL_SYS_ZERO, + chan->address); + else + ret = ad_sd_calibrate(&st->sd, AD7192_MODE_CAL_SYS_FULL, + chan->address); + } + + return ret ? ret : len; +} + +static const struct iio_enum ad7192_syscalib_mode_enum = { + .items = ad7192_syscalib_modes, + .num_items = ARRAY_SIZE(ad7192_syscalib_modes), + .set = ad7192_set_syscalib_mode, + .get = ad7192_get_syscalib_mode +}; + +static const struct iio_chan_spec_ext_info ad7192_calibsys_ext_info[] = { + { + .name = "sys_calibration", + .write = ad7192_write_syscalib, + .shared = IIO_SEPARATE, + }, + IIO_ENUM("sys_calibration_mode", IIO_SEPARATE, + &ad7192_syscalib_mode_enum), + IIO_ENUM_AVAILABLE("sys_calibration_mode", &ad7192_syscalib_mode_enum), + {} +}; + static struct ad7192_state *ad_sigma_delta_to_ad7192(struct ad_sigma_delta *sd) { return container_of(sd, struct ad7192_state, sd); @@ -770,9 +845,11 @@ static int ad7192_channels_config(struct iio_dev *indio_dev) *chan = channels[i]; chan->info_mask_shared_by_all |= BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY); - if (chan->type != IIO_TEMP) + if (chan->type != IIO_TEMP) { chan->info_mask_shared_by_type_available |= BIT(IIO_CHAN_INFO_SCALE); + chan->ext_info = ad7192_calibsys_ext_info; + } chan++; } diff --git a/drivers/staging/iio/frequency/ad9834.c b/drivers/staging/iio/frequency/ad9834.c index 038d6732c3fd..23026978a5a5 100644 --- a/drivers/staging/iio/frequency/ad9834.c +++ b/drivers/staging/iio/frequency/ad9834.c @@ -417,6 +417,10 @@ static int ad9834_probe(struct spi_device *spi) st = iio_priv(indio_dev); mutex_init(&st->lock); st->mclk = devm_clk_get(&spi->dev, NULL); + if (IS_ERR(st->mclk)) { + ret = PTR_ERR(st->mclk); + goto error_disable_reg; + } ret = clk_prepare_enable(st->mclk); if (ret) { diff --git a/drivers/staging/isdn/avm/b1.c b/drivers/staging/isdn/avm/b1.c index 40ca1e8fa09f..32ec8cf31fd0 100644 --- a/drivers/staging/isdn/avm/b1.c +++ b/drivers/staging/isdn/avm/b1.c @@ -261,9 +261,10 @@ int b1_loaded(avmcard *card) b1_put_byte(base, SEND_POLL); for (stop = jiffies + tout * HZ; time_before(jiffies, stop);) { if (b1_rx_full(base)) { - if ((ans = b1_get_byte(base)) == RECEIVE_POLL) { + ans = b1_get_byte(base); + if (ans == RECEIVE_POLL) return 1; - } + printk(KERN_ERR "%s: b1_loaded: got 0x%x, firmware not running\n", card->name, ans); return 0; @@ -284,8 +285,9 @@ int b1_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) int retval; b1_reset(port); + retval = b1_load_t4file(card, &data->firmware); - if ((retval = b1_load_t4file(card, &data->firmware))) { + if (retval) { b1_reset(port); printk(KERN_ERR "%s: failed to load t4file!!\n", card->name); @@ -295,7 +297,8 @@ int b1_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) b1_disable_irq(port); if (data->configuration.len > 0 && data->configuration.data) { - if ((retval = b1_load_config(card, &data->configuration))) { + retval = b1_load_config(card, &data->configuration); + if (retval) { b1_reset(port); printk(KERN_ERR "%s: failed to load config!!\n", card->name); @@ -525,7 +528,9 @@ irqreturn_t b1_interrupt(int interrupt, void *devptr) MsgLen = 30; CAPIMSG_SETLEN(card->msgbuf, 30); } - if (!(skb = alloc_skb(DataB3Len + MsgLen, GFP_ATOMIC))) { + + skb = alloc_skb(DataB3Len + MsgLen, GFP_ATOMIC); + if (!skb) { printk(KERN_ERR "%s: incoming packet dropped\n", card->name); } else { @@ -539,7 +544,9 @@ irqreturn_t b1_interrupt(int interrupt, void *devptr) ApplId = (unsigned) b1_get_word(card->port); MsgLen = b1_get_slice(card->port, card->msgbuf); - if (!(skb = alloc_skb(MsgLen, GFP_ATOMIC))) { + skb = alloc_skb(MsgLen, GFP_ATOMIC); + + if (!skb) { printk(KERN_ERR "%s: incoming packet dropped\n", card->name); spin_unlock_irqrestore(&card->lock, flags); @@ -663,11 +670,17 @@ int b1_proc_show(struct seq_file *m, void *v) seq_printf(m, "%-16s %s\n", "type", s); if (card->cardtype == avm_t1isa) seq_printf(m, "%-16s %d\n", "cardnr", card->cardnr); - if ((s = cinfo->version[VER_DRIVER]) != NULL) + + s = cinfo->version[VER_DRIVER]; + if (s) seq_printf(m, "%-16s %s\n", "ver_driver", s); - if ((s = cinfo->version[VER_CARDTYPE]) != NULL) + + s = cinfo->version[VER_CARDTYPE]; + if (s) seq_printf(m, "%-16s %s\n", "ver_cardtype", s); - if ((s = cinfo->version[VER_SERIAL]) != NULL) + + s = cinfo->version[VER_SERIAL]; + if (s) seq_printf(m, "%-16s %s\n", "ver_serial", s); if (card->cardtype != avm_m1) { @@ -784,13 +797,15 @@ static int __init b1_init(void) char *p; char rev[32]; - if ((p = strchr(revision, ':')) != NULL && p[1]) { + p = strchr(revision, ':'); + if (p && p[1]) { strlcpy(rev, p + 2, 32); - if ((p = strchr(rev, '$')) != NULL && p > rev) + p = strchr(rev, '$'); + if (p && p > rev) *(p - 1) = 0; - } else + } else { strcpy(rev, "1.0"); - + } printk(KERN_INFO "b1: revision %s\n", rev); return 0; diff --git a/drivers/staging/isdn/gigaset/interface.c b/drivers/staging/isdn/gigaset/interface.c index 17fa615a8c68..9ddadd07e707 100644 --- a/drivers/staging/isdn/gigaset/interface.c +++ b/drivers/staging/isdn/gigaset/interface.c @@ -518,7 +518,7 @@ void gigaset_if_init(struct cardstate *cs) if (!IS_ERR(cs->tty_dev)) dev_set_drvdata(cs->tty_dev, cs); else { - pr_warning("could not register device to the tty subsystem\n"); + pr_warn("could not register device to the tty subsystem\n"); cs->tty_dev = NULL; } mutex_unlock(&cs->mutex); diff --git a/drivers/staging/kpc2000/kpc2000_i2c.c b/drivers/staging/kpc2000/kpc2000_i2c.c index bc02534d8dc3..5460bf973c9c 100644 --- a/drivers/staging/kpc2000/kpc2000_i2c.c +++ b/drivers/staging/kpc2000/kpc2000_i2c.c @@ -99,7 +99,8 @@ struct i2c_device { #define SMBHSTSTS_INTR 0x02 #define SMBHSTSTS_HOST_BUSY 0x01 -#define STATUS_FLAGS (SMBHSTSTS_BYTE_DONE | SMBHSTSTS_FAILED | SMBHSTSTS_BUS_ERR | SMBHSTSTS_DEV_ERR | SMBHSTSTS_INTR) +#define STATUS_FLAGS (SMBHSTSTS_BYTE_DONE | SMBHSTSTS_FAILED | \ + SMBHSTSTS_BUS_ERR | SMBHSTSTS_DEV_ERR | SMBHSTSTS_INTR) /* Older devices have their ID defined in <linux/pci_ids.h> */ #define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS 0x1c22 @@ -136,17 +137,18 @@ static int i801_check_pre(struct i2c_device *priv) status = inb_p(SMBHSTSTS(priv)); if (status & SMBHSTSTS_HOST_BUSY) { - dev_err(&priv->adapter.dev, "SMBus is busy, can't use it! (status=%x)\n", status); + dev_err(&priv->adapter.dev, + "SMBus is busy, can't use it! (status=%x)\n", status); return -EBUSY; } status &= STATUS_FLAGS; if (status) { - //dev_dbg(&priv->adapter.dev, "Clearing status flags (%02x)\n", status); outb_p(status, SMBHSTSTS(priv)); status = inb_p(SMBHSTSTS(priv)) & STATUS_FLAGS; if (status) { - dev_err(&priv->adapter.dev, "Failed clearing status flags (%02x)\n", status); + dev_err(&priv->adapter.dev, + "Failed clearing status flags (%02x)\n", status); return -EBUSY; } } @@ -162,15 +164,20 @@ static int i801_check_post(struct i2c_device *priv, int status, int timeout) if (timeout) { dev_err(&priv->adapter.dev, "Transaction timeout\n"); /* try to stop the current command */ - dev_dbg(&priv->adapter.dev, "Terminating the current operation\n"); - outb_p(inb_p(SMBHSTCNT(priv)) | SMBHSTCNT_KILL, SMBHSTCNT(priv)); + dev_dbg(&priv->adapter.dev, + "Terminating the current operation\n"); + outb_p(inb_p(SMBHSTCNT(priv)) | SMBHSTCNT_KILL, + SMBHSTCNT(priv)); usleep_range(1000, 2000); - outb_p(inb_p(SMBHSTCNT(priv)) & (~SMBHSTCNT_KILL), SMBHSTCNT(priv)); + outb_p(inb_p(SMBHSTCNT(priv)) & (~SMBHSTCNT_KILL), + SMBHSTCNT(priv)); /* Check if it worked */ status = inb_p(SMBHSTSTS(priv)); - if ((status & SMBHSTSTS_HOST_BUSY) || !(status & SMBHSTSTS_FAILED)) - dev_err(&priv->adapter.dev, "Failed terminating the transaction\n"); + if ((status & SMBHSTSTS_HOST_BUSY) || + !(status & SMBHSTSTS_FAILED)) + dev_err(&priv->adapter.dev, + "Failed terminating the transaction\n"); outb_p(STATUS_FLAGS, SMBHSTSTS(priv)); return -ETIMEDOUT; } @@ -244,7 +251,9 @@ static void i801_wait_hwpec(struct i2c_device *priv) outb_p(status, SMBHSTSTS(priv)); } -static int i801_block_transaction_by_block(struct i2c_device *priv, union i2c_smbus_data *data, char read_write, int hwpec) +static int i801_block_transaction_by_block(struct i2c_device *priv, + union i2c_smbus_data *data, + char read_write, int hwpec) { int i, len; int status; @@ -259,7 +268,8 @@ static int i801_block_transaction_by_block(struct i2c_device *priv, union i2c_sm outb_p(data->block[i + 1], SMBBLKDAT(priv)); } - status = i801_transaction(priv, I801_BLOCK_DATA | ENABLE_INT9 | I801_PEC_EN * hwpec); + status = i801_transaction(priv, + I801_BLOCK_DATA | ENABLE_INT9 | I801_PEC_EN * hwpec); if (status) return status; @@ -275,7 +285,10 @@ static int i801_block_transaction_by_block(struct i2c_device *priv, union i2c_sm return 0; } -static int i801_block_transaction_byte_by_byte(struct i2c_device *priv, union i2c_smbus_data *data, char read_write, int command, int hwpec) +static int i801_block_transaction_byte_by_byte(struct i2c_device *priv, + union i2c_smbus_data *data, + char read_write, int command, + int hwpec) { int i, len; int smbcmd; @@ -301,7 +314,8 @@ static int i801_block_transaction_byte_by_byte(struct i2c_device *priv, union i2 else smbcmd = I801_BLOCK_LAST; } else { - if (command == I2C_SMBUS_I2C_BLOCK_DATA && read_write == I2C_SMBUS_READ) + if (command == I2C_SMBUS_I2C_BLOCK_DATA && + read_write == I2C_SMBUS_READ) smbcmd = I801_I2C_BLOCK_DATA; else smbcmd = I801_BLOCK_DATA; @@ -309,25 +323,33 @@ static int i801_block_transaction_byte_by_byte(struct i2c_device *priv, union i2 outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT(priv)); if (i == 1) - outb_p(inb(SMBHSTCNT(priv)) | I801_START, SMBHSTCNT(priv)); + outb_p(inb(SMBHSTCNT(priv)) | I801_START, + SMBHSTCNT(priv)); /* We will always wait for a fraction of a second! */ timeout = 0; do { usleep_range(250, 500); status = inb_p(SMBHSTSTS(priv)); - } while ((!(status & SMBHSTSTS_BYTE_DONE)) && (timeout++ < MAX_RETRIES)); + } while (!(status & SMBHSTSTS_BYTE_DONE) && + (timeout++ < MAX_RETRIES)); result = i801_check_post(priv, status, timeout > MAX_RETRIES); if (result < 0) return result; - if (i == 1 && read_write == I2C_SMBUS_READ && command != I2C_SMBUS_I2C_BLOCK_DATA) { + if (i == 1 && read_write == I2C_SMBUS_READ && + command != I2C_SMBUS_I2C_BLOCK_DATA) { len = inb_p(SMBHSTDAT0(priv)); if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) { - dev_err(&priv->adapter.dev, "Illegal SMBus block read size %d\n", len); + dev_err(&priv->adapter.dev, + "Illegal SMBus block read size %d\n", + len); /* Recover */ - while (inb_p(SMBHSTSTS(priv)) & SMBHSTSTS_HOST_BUSY) - outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv)); - outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv)); + while (inb_p(SMBHSTSTS(priv)) & + SMBHSTSTS_HOST_BUSY) + outb_p(SMBHSTSTS_BYTE_DONE, + SMBHSTSTS(priv)); + outb_p(SMBHSTSTS_INTR, + SMBHSTSTS(priv)); return -EPROTO; } data->block[0] = len; @@ -354,7 +376,9 @@ static int i801_set_block_buffer_mode(struct i2c_device *priv) } /* Block transaction function */ -static int i801_block_transaction(struct i2c_device *priv, union i2c_smbus_data *data, char read_write, int command, int hwpec) +static int i801_block_transaction(struct i2c_device *priv, + union i2c_smbus_data *data, char read_write, + int command, int hwpec) { int result = 0; //unsigned char hostc; @@ -366,12 +390,14 @@ static int i801_block_transaction(struct i2c_device *priv, union i2c_smbus_data //pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &hostc); //pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hostc | SMBHSTCFG_I2C_EN); } else if (!(priv->features & FEATURE_I2C_BLOCK_READ)) { - dev_err(&priv->adapter.dev, "I2C block read is unsupported!\n"); + dev_err(&priv->adapter.dev, + "I2C block read is unsupported!\n"); return -EOPNOTSUPP; } } - if (read_write == I2C_SMBUS_WRITE || command == I2C_SMBUS_I2C_BLOCK_DATA) { + if (read_write == I2C_SMBUS_WRITE || + command == I2C_SMBUS_I2C_BLOCK_DATA) { if (data->block[0] < 1) data->block[0] = 1; if (data->block[0] > I2C_SMBUS_BLOCK_MAX) @@ -384,13 +410,21 @@ static int i801_block_transaction(struct i2c_device *priv, union i2c_smbus_data * SMBus (not I2C) block transactions, even though the datasheet * doesn't mention this limitation. */ - if ((priv->features & FEATURE_BLOCK_BUFFER) && command != I2C_SMBUS_I2C_BLOCK_DATA && i801_set_block_buffer_mode(priv) == 0) - result = i801_block_transaction_by_block(priv, data, read_write, hwpec); - else - result = i801_block_transaction_byte_by_byte(priv, data, read_write, command, hwpec); + if ((priv->features & FEATURE_BLOCK_BUFFER) && + command != I2C_SMBUS_I2C_BLOCK_DATA && + i801_set_block_buffer_mode(priv) == 0) { + result = i801_block_transaction_by_block(priv, data, + read_write, hwpec); + } else { + result = i801_block_transaction_byte_by_byte(priv, data, + read_write, + command, hwpec); + } + if (result == 0 && hwpec) i801_wait_hwpec(priv); - if (command == I2C_SMBUS_I2C_BLOCK_DATA && read_write == I2C_SMBUS_WRITE) { + if (command == I2C_SMBUS_I2C_BLOCK_DATA && + read_write == I2C_SMBUS_WRITE) { /* restore saved configuration register value */ //TODO: Figure out the right thing to do here... //pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hostc); @@ -399,32 +433,41 @@ static int i801_block_transaction(struct i2c_device *priv, union i2c_smbus_data } /* Return negative errno on error. */ -static s32 i801_access(struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data *data) +static s32 i801_access(struct i2c_adapter *adap, u16 addr, + unsigned short flags, char read_write, u8 command, + int size, union i2c_smbus_data *data) { int hwpec; int block = 0; int ret, xact = 0; struct i2c_device *priv = i2c_get_adapdata(adap); - hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA; + hwpec = (priv->features & FEATURE_SMBUS_PEC) && + (flags & I2C_CLIENT_PEC) && + size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA; switch (size) { case I2C_SMBUS_QUICK: dev_dbg(&priv->adapter.dev, " [acc] SMBUS_QUICK\n"); - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD(priv)); + outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), + SMBHSTADD(priv)); + xact = I801_QUICK; break; case I2C_SMBUS_BYTE: dev_dbg(&priv->adapter.dev, " [acc] SMBUS_BYTE\n"); - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD(priv)); + outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), + SMBHSTADD(priv)); if (read_write == I2C_SMBUS_WRITE) outb_p(command, SMBHSTCMD(priv)); xact = I801_BYTE; break; case I2C_SMBUS_BYTE_DATA: dev_dbg(&priv->adapter.dev, " [acc] SMBUS_BYTE_DATA\n"); - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD(priv)); + outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), + SMBHSTADD(priv)); + outb_p(command, SMBHSTCMD(priv)); if (read_write == I2C_SMBUS_WRITE) outb_p(data->byte, SMBHSTDAT0(priv)); @@ -432,7 +475,9 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr, unsigned short flags, break; case I2C_SMBUS_WORD_DATA: dev_dbg(&priv->adapter.dev, " [acc] SMBUS_WORD_DATA\n"); - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD(priv)); + outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), + SMBHSTADD(priv)); + outb_p(command, SMBHSTCMD(priv)); if (read_write == I2C_SMBUS_WRITE) { outb_p(data->word & 0xff, SMBHSTDAT0(priv)); @@ -442,7 +487,9 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr, unsigned short flags, break; case I2C_SMBUS_BLOCK_DATA: dev_dbg(&priv->adapter.dev, " [acc] SMBUS_BLOCK_DATA\n"); - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), SMBHSTADD(priv)); + outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), + SMBHSTADD(priv)); + outb_p(command, SMBHSTCMD(priv)); block = 1; break; @@ -463,7 +510,8 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr, unsigned short flags, block = 1; break; default: - dev_dbg(&priv->adapter.dev, " [acc] Unsupported transaction %d\n", size); + dev_dbg(&priv->adapter.dev, + " [acc] Unsupported transaction %d\n", size); return -EOPNOTSUPP; } @@ -472,13 +520,14 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr, unsigned short flags, outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_CRC, SMBAUXCTL(priv)); } else { dev_dbg(&priv->adapter.dev, " [acc] hwpec: no\n"); - outb_p(inb_p(SMBAUXCTL(priv)) & (~SMBAUXCTL_CRC), SMBAUXCTL(priv)); + outb_p(inb_p(SMBAUXCTL(priv)) & + (~SMBAUXCTL_CRC), SMBAUXCTL(priv)); } if (block) { - //ret = 0; dev_dbg(&priv->adapter.dev, " [acc] block: yes\n"); - ret = i801_block_transaction(priv, data, read_write, size, hwpec); + ret = i801_block_transaction(priv, data, read_write, size, + hwpec); } else { dev_dbg(&priv->adapter.dev, " [acc] block: no\n"); ret = i801_transaction(priv, xact | ENABLE_INT9); @@ -490,7 +539,8 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr, unsigned short flags, */ if (hwpec || block) { dev_dbg(&priv->adapter.dev, " [acc] hwpec || block\n"); - outb_p(inb_p(SMBAUXCTL(priv)) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv)); + outb_p(inb_p(SMBAUXCTL(priv)) & ~(SMBAUXCTL_CRC | + SMBAUXCTL_E32B), SMBAUXCTL(priv)); } if (block) { dev_dbg(&priv->adapter.dev, " [acc] block\n"); @@ -501,19 +551,22 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr, unsigned short flags, return ret; } if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK)) { - dev_dbg(&priv->adapter.dev, " [acc] I2C_SMBUS_WRITE || I801_QUICK -> ret 0\n"); + dev_dbg(&priv->adapter.dev, + " [acc] I2C_SMBUS_WRITE || I801_QUICK -> ret 0\n"); return 0; } switch (xact & 0x7f) { case I801_BYTE: /* Result put in SMBHSTDAT0 */ case I801_BYTE_DATA: - dev_dbg(&priv->adapter.dev, " [acc] I801_BYTE or I801_BYTE_DATA\n"); + dev_dbg(&priv->adapter.dev, + " [acc] I801_BYTE or I801_BYTE_DATA\n"); data->byte = inb_p(SMBHSTDAT0(priv)); break; case I801_WORD_DATA: dev_dbg(&priv->adapter.dev, " [acc] I801_WORD_DATA\n"); - data->word = inb_p(SMBHSTDAT0(priv)) + (inb_p(SMBHSTDAT1(priv)) << 8); + data->word = inb_p(SMBHSTDAT0(priv)) + + (inb_p(SMBHSTDAT1(priv)) << 8); break; } return 0; @@ -535,30 +588,47 @@ static u32 i801_func(struct i2c_adapter *adapter) // http://lxr.free-electrons.com/source/include/uapi/linux/i2c.h#L85 u32 f = - I2C_FUNC_I2C | /* 0x00000001 (I enabled this one) */ - !I2C_FUNC_10BIT_ADDR | /* 0x00000002 */ - !I2C_FUNC_PROTOCOL_MANGLING | /* 0x00000004 */ - ((priv->features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) | /* 0x00000008 */ - !I2C_FUNC_SMBUS_BLOCK_PROC_CALL | /* 0x00008000 */ - I2C_FUNC_SMBUS_QUICK | /* 0x00010000 */ - !I2C_FUNC_SMBUS_READ_BYTE | /* 0x00020000 */ - !I2C_FUNC_SMBUS_WRITE_BYTE | /* 0x00040000 */ - !I2C_FUNC_SMBUS_READ_BYTE_DATA | /* 0x00080000 */ - !I2C_FUNC_SMBUS_WRITE_BYTE_DATA | /* 0x00100000 */ - !I2C_FUNC_SMBUS_READ_WORD_DATA | /* 0x00200000 */ - !I2C_FUNC_SMBUS_WRITE_WORD_DATA | /* 0x00400000 */ - !I2C_FUNC_SMBUS_PROC_CALL | /* 0x00800000 */ - !I2C_FUNC_SMBUS_READ_BLOCK_DATA | /* 0x01000000 */ - !I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | /* 0x02000000 */ - ((priv->features & FEATURE_I2C_BLOCK_READ) ? I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0) | /* 0x04000000 */ - I2C_FUNC_SMBUS_WRITE_I2C_BLOCK | /* 0x08000000 */ + I2C_FUNC_I2C | /* 0x00000001(I enabled this + * one) + */ + !I2C_FUNC_10BIT_ADDR | /* 0x00000002 */ + !I2C_FUNC_PROTOCOL_MANGLING | /* 0x00000004 */ + ((priv->features & FEATURE_SMBUS_PEC) ? + I2C_FUNC_SMBUS_PEC : 0) | /* 0x00000008 */ + !I2C_FUNC_SMBUS_BLOCK_PROC_CALL | /* 0x00008000 */ + I2C_FUNC_SMBUS_QUICK | /* 0x00010000 */ + !I2C_FUNC_SMBUS_READ_BYTE | /* 0x00020000 */ + !I2C_FUNC_SMBUS_WRITE_BYTE | /* 0x00040000 */ + !I2C_FUNC_SMBUS_READ_BYTE_DATA | /* 0x00080000 */ + !I2C_FUNC_SMBUS_WRITE_BYTE_DATA | /* 0x00100000 */ + !I2C_FUNC_SMBUS_READ_WORD_DATA | /* 0x00200000 */ + !I2C_FUNC_SMBUS_WRITE_WORD_DATA | /* 0x00400000 */ + !I2C_FUNC_SMBUS_PROC_CALL | /* 0x00800000 */ + !I2C_FUNC_SMBUS_READ_BLOCK_DATA | /* 0x01000000 */ + !I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | /* 0x02000000 */ + ((priv->features & FEATURE_I2C_BLOCK_READ) ? + I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0) | /* 0x04000000 */ + I2C_FUNC_SMBUS_WRITE_I2C_BLOCK | /* 0x08000000 */ I2C_FUNC_SMBUS_BYTE | /* _READ_BYTE _WRITE_BYTE */ - I2C_FUNC_SMBUS_BYTE_DATA | /* _READ_BYTE_DATA _WRITE_BYTE_DATA */ - I2C_FUNC_SMBUS_WORD_DATA | /* _READ_WORD_DATA _WRITE_WORD_DATA */ - I2C_FUNC_SMBUS_BLOCK_DATA | /* _READ_BLOCK_DATA _WRITE_BLOCK_DATA */ - !I2C_FUNC_SMBUS_I2C_BLOCK | /* _READ_I2C_BLOCK _WRITE_I2C_BLOCK */ - !I2C_FUNC_SMBUS_EMUL; /* _QUICK _BYTE _BYTE_DATA _WORD_DATA _PROC_CALL _WRITE_BLOCK_DATA _I2C_BLOCK _PEC */ + I2C_FUNC_SMBUS_BYTE_DATA | /* _READ_BYTE_DATA + * _WRITE_BYTE_DATA + */ + I2C_FUNC_SMBUS_WORD_DATA | /* _READ_WORD_DATA + * _WRITE_WORD_DATA + */ + I2C_FUNC_SMBUS_BLOCK_DATA | /* _READ_BLOCK_DATA + * _WRITE_BLOCK_DATA + */ + !I2C_FUNC_SMBUS_I2C_BLOCK | /* _READ_I2C_BLOCK + * _WRITE_I2C_BLOCK + */ + !I2C_FUNC_SMBUS_EMUL; /* _QUICK _BYTE + * _BYTE_DATA _WORD_DATA + * _PROC_CALL + * _WRITE_BLOCK_DATA + * _I2C_BLOCK _PEC + */ return f; } @@ -610,8 +680,8 @@ static int pi2c_probe(struct platform_device *pldev) /* Retry up to 3 times on lost arbitration */ priv->adapter.retries = 3; - //snprintf(priv->adapter.name, sizeof(priv->adapter.name), "Fake SMBus I801 adapter at %04lx", priv->smba); - snprintf(priv->adapter.name, sizeof(priv->adapter.name), "Fake SMBus I801 adapter"); + snprintf(priv->adapter.name, sizeof(priv->adapter.name), + "Fake SMBus I801 adapter"); err = i2c_add_adapter(&priv->adapter); if (err) { diff --git a/drivers/staging/kpc2000/kpc2000_spi.c b/drivers/staging/kpc2000/kpc2000_spi.c index 3be33c450cab..8becf972af9c 100644 --- a/drivers/staging/kpc2000/kpc2000_spi.c +++ b/drivers/staging/kpc2000/kpc2000_spi.c @@ -50,6 +50,7 @@ static struct flash_platform_data p2kr0_spi0_pdata = { .nr_parts = ARRAY_SIZE(p2kr0_spi0_parts), .parts = p2kr0_spi0_parts, }; + static struct flash_platform_data p2kr0_spi1_pdata = { .name = "SPI1", .nr_parts = ARRAY_SIZE(p2kr0_spi1_parts), @@ -162,14 +163,12 @@ union kp_spi_ffctrl { kp_spi_read_reg(struct kp_spi_controller_state *cs, int idx) { u64 __iomem *addr = cs->base; - u64 val; addr += idx; if ((idx == KP_SPI_REG_CONFIG) && (cs->conf_cache >= 0)) return cs->conf_cache; - val = readq(addr); - return val; + return readq(addr); } static inline void @@ -227,8 +226,7 @@ kp_spi_txrx_pio(struct spi_device *spidev, struct spi_transfer *transfer) kp_spi_write_reg(cs, KP_SPI_REG_TXDATA, val); processed++; } - } - else if (rx) { + } else if (rx) { for (i = 0 ; i < c ; i++) { char test = 0; @@ -315,19 +313,19 @@ kp_spi_transfer_one_message(struct spi_master *master, struct spi_message *m) if (transfer->speed_hz > KP_SPI_CLK || (len && !(rx_buf || tx_buf))) { dev_dbg(kpspi->dev, " transfer: %d Hz, %d %s%s, %d bpw\n", - transfer->speed_hz, - len, - tx_buf ? "tx" : "", - rx_buf ? "rx" : "", - transfer->bits_per_word); + transfer->speed_hz, + len, + tx_buf ? "tx" : "", + rx_buf ? "rx" : "", + transfer->bits_per_word); dev_dbg(kpspi->dev, " transfer -EINVAL\n"); return -EINVAL; } if (transfer->speed_hz && transfer->speed_hz < (KP_SPI_CLK >> 15)) { dev_dbg(kpspi->dev, "speed_hz %d below minimum %d Hz\n", - transfer->speed_hz, - KP_SPI_CLK >> 15); + transfer->speed_hz, + KP_SPI_CLK >> 15); dev_dbg(kpspi->dev, " speed_hz -EINVAL\n"); return -EINVAL; } @@ -478,7 +476,7 @@ kp_spi_probe(struct platform_device *pldev) /* register the slave boards */ #define NEW_SPI_DEVICE_FROM_BOARD_INFO_TABLE(table) \ for (i = 0 ; i < ARRAY_SIZE(table) ; i++) { \ - spi_new_device(master, &(table[i])); \ + spi_new_device(master, &table[i]); \ } switch ((drvdata->card_id & 0xFFFF0000) >> 16) { diff --git a/drivers/staging/media/allegro-dvt/nal-h264.c b/drivers/staging/media/allegro-dvt/nal-h264.c index 4e14b77851e1..bd48b8883572 100644 --- a/drivers/staging/media/allegro-dvt/nal-h264.c +++ b/drivers/staging/media/allegro-dvt/nal-h264.c @@ -235,7 +235,7 @@ static inline int rbsp_write_bit(struct rbsp *rbsp, bool value) rbsp->pos++; - if (value == 1 || + if (value || (rbsp->num_consecutive_zeros < 7 && (rbsp->pos % 8 == 0))) { rbsp->num_consecutive_zeros = 0; } else { diff --git a/drivers/staging/most/configfs.c b/drivers/staging/most/configfs.c index 025495657b68..c06cf849c04d 100644 --- a/drivers/staging/most/configfs.c +++ b/drivers/staging/most/configfs.c @@ -164,6 +164,7 @@ static ssize_t mdev_link_direction_store(struct config_item *item, !sysfs_streq(page, "dir_tx") && !sysfs_streq(page, "tx")) return -EINVAL; strcpy(mdev_link->direction, page); + strim(mdev_link->direction); return count; } @@ -182,6 +183,7 @@ static ssize_t mdev_link_datatype_store(struct config_item *item, !sysfs_streq(page, "isoc_avp")) return -EINVAL; strcpy(mdev_link->datatype, page); + strim(mdev_link->datatype); return count; } @@ -196,6 +198,7 @@ static ssize_t mdev_link_device_store(struct config_item *item, struct mdev_link *mdev_link = to_mdev_link(item); strcpy(mdev_link->device, page); + strim(mdev_link->device); return count; } @@ -210,6 +213,7 @@ static ssize_t mdev_link_channel_store(struct config_item *item, struct mdev_link *mdev_link = to_mdev_link(item); strcpy(mdev_link->channel, page); + strim(mdev_link->channel); return count; } @@ -487,7 +491,7 @@ static struct config_item *most_snd_grp_make_item(struct config_group *group, return ERR_PTR(-ENOMEM); config_item_init_type_name(&mdev_link->item, name, &mdev_link_type); - mdev_link->create_link = 0; + mdev_link->create_link = false; strcpy(mdev_link->name, name); strcpy(mdev_link->comp, "sound"); return &mdev_link->item; diff --git a/drivers/staging/most/core.c b/drivers/staging/most/core.c index 8e9a0b67c6ed..f7d2c7850cf5 100644 --- a/drivers/staging/most/core.c +++ b/drivers/staging/most/core.c @@ -84,11 +84,11 @@ static const struct { int most_ch_data_type; const char *name; } ch_data_type[] = { - { MOST_CH_CONTROL, "control\n" }, - { MOST_CH_ASYNC, "async\n" }, - { MOST_CH_SYNC, "sync\n" }, - { MOST_CH_ISOC, "isoc\n"}, - { MOST_CH_ISOC, "isoc_avp\n"}, + { MOST_CH_CONTROL, "control" }, + { MOST_CH_ASYNC, "async" }, + { MOST_CH_SYNC, "sync" }, + { MOST_CH_ISOC, "isoc"}, + { MOST_CH_ISOC, "isoc_avp"}, }; /** @@ -675,13 +675,13 @@ int most_set_cfg_direction(char *mdev, char *mdev_ch, char *buf) if (!c) return -ENODEV; - if (!strcmp(buf, "dir_rx\n")) { + if (!strcmp(buf, "dir_rx")) { c->cfg.direction = MOST_CH_RX; - } else if (!strcmp(buf, "rx\n")) { + } else if (!strcmp(buf, "rx")) { c->cfg.direction = MOST_CH_RX; - } else if (!strcmp(buf, "dir_tx\n")) { + } else if (!strcmp(buf, "dir_tx")) { c->cfg.direction = MOST_CH_TX; - } else if (!strcmp(buf, "tx\n")) { + } else if (!strcmp(buf, "tx")) { c->cfg.direction = MOST_CH_TX; } else { pr_info("Invalid direction\n"); diff --git a/drivers/staging/mt7621-dma/mtk-hsdma.c b/drivers/staging/mt7621-dma/mtk-hsdma.c index d964642d95a3..20b898954416 100644 --- a/drivers/staging/mt7621-dma/mtk-hsdma.c +++ b/drivers/staging/mt7621-dma/mtk-hsdma.c @@ -208,8 +208,8 @@ static void mtk_hsdma_reset_chan(struct mtk_hsdam_engine *hsdma, static void hsdma_dump_reg(struct mtk_hsdam_engine *hsdma) { - dev_dbg(hsdma->ddev.dev, "tbase %08x, tcnt %08x, " \ - "tctx %08x, tdtx: %08x, rbase %08x, " \ + dev_dbg(hsdma->ddev.dev, "tbase %08x, tcnt %08x, " + "tctx %08x, tdtx: %08x, rbase %08x, " "rcnt %08x, rctx %08x, rdtx %08x\n", mtk_hsdma_read(hsdma, HSDMA_REG_TX_BASE), mtk_hsdma_read(hsdma, HSDMA_REG_TX_CNT), @@ -220,7 +220,7 @@ static void hsdma_dump_reg(struct mtk_hsdam_engine *hsdma) mtk_hsdma_read(hsdma, HSDMA_REG_RX_CRX), mtk_hsdma_read(hsdma, HSDMA_REG_RX_DRX)); - dev_dbg(hsdma->ddev.dev, "info %08x, glo %08x, delay %08x, " \ + dev_dbg(hsdma->ddev.dev, "info %08x, glo %08x, delay %08x, " "intr_stat %08x, intr_mask %08x\n", mtk_hsdma_read(hsdma, HSDMA_REG_INFO), mtk_hsdma_read(hsdma, HSDMA_REG_GLO_CFG), @@ -243,9 +243,9 @@ static void hsdma_dump_desc(struct mtk_hsdam_engine *hsdma, tx_desc = &chan->tx_ring[i]; rx_desc = &chan->rx_ring[i]; - dev_dbg(hsdma->ddev.dev, "%d tx addr0: %08x, flags %08x, " \ + dev_dbg(hsdma->ddev.dev, "%d tx addr0: %08x, flags %08x, " "tx addr1: %08x, rx addr0 %08x, flags %08x\n", - i, tx_desc->addr0, tx_desc->flags, \ + i, tx_desc->addr0, tx_desc->flags, tx_desc->addr1, rx_desc->addr0, rx_desc->flags); } } @@ -548,7 +548,8 @@ static int mtk_hsdam_alloc_desc(struct mtk_hsdam_engine *hsdma, int i; chan->tx_ring = dma_alloc_coherent(hsdma->ddev.dev, - 2 * HSDMA_DESCS_NUM * sizeof(*chan->tx_ring), + 2 * HSDMA_DESCS_NUM * + sizeof(*chan->tx_ring), &chan->desc_addr, GFP_ATOMIC | __GFP_ZERO); if (!chan->tx_ring) goto no_mem; @@ -569,8 +570,8 @@ static void mtk_hsdam_free_desc(struct mtk_hsdam_engine *hsdma, { if (chan->tx_ring) { dma_free_coherent(hsdma->ddev.dev, - 2 * HSDMA_DESCS_NUM * sizeof(*chan->tx_ring), - chan->tx_ring, chan->desc_addr); + 2 * HSDMA_DESCS_NUM * sizeof(*chan->tx_ring), + chan->tx_ring, chan->desc_addr); chan->tx_ring = NULL; chan->rx_ring = NULL; } @@ -650,7 +651,6 @@ static int mtk_hsdma_probe(struct platform_device *pdev) struct mtk_hsdma_chan *chan; struct mtk_hsdam_engine *hsdma; struct dma_device *dd; - struct resource *res; int ret; int irq; void __iomem *base; @@ -667,8 +667,7 @@ static int mtk_hsdma_probe(struct platform_device *pdev) if (!hsdma) return -EINVAL; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); hsdma->base = base + HSDMA_BASE_OFFSET; diff --git a/drivers/staging/mt7621-pci/pci-mt7621.c b/drivers/staging/mt7621-pci/pci-mt7621.c index 6b98827da57f..3633c924848e 100644 --- a/drivers/staging/mt7621-pci/pci-mt7621.c +++ b/drivers/staging/mt7621-pci/pci-mt7621.c @@ -29,15 +29,14 @@ #include <linux/phy/phy.h> #include <linux/platform_device.h> #include <linux/reset.h> +#include <linux/sys_soc.h> #include <mt7621.h> #include <ralink_regs.h> #include "../../pci/pci.h" /* sysctl */ -#define MT7621_CHIP_REV_ID 0x0c #define MT7621_GPIO_MODE 0x60 -#define CHIP_REV_MT7621_E2 0x0101 /* MediaTek specific configuration registers */ #define PCIE_FTS_NUM 0x70c @@ -126,6 +125,8 @@ struct mt7621_pcie_port { * @ports: pointer to PCIe port information * @perst: gpio reset * @rst: pointer to pcie reset + * @resets_inverted: depends on chip revision + * reset lines are inverted. */ struct mt7621_pcie { void __iomem *base; @@ -140,6 +141,7 @@ struct mt7621_pcie { struct list_head ports; struct gpio_desc *perst; struct reset_control *rst; + bool resets_inverted; }; static inline u32 pcie_read(struct mt7621_pcie *pcie, u32 reg) @@ -229,9 +231,9 @@ static inline void mt7621_pcie_port_clk_disable(struct mt7621_pcie_port *port) static inline void mt7621_control_assert(struct mt7621_pcie_port *port) { - u32 chip_rev_id = rt_sysc_r32(MT7621_CHIP_REV_ID); + struct mt7621_pcie *pcie = port->pcie; - if ((chip_rev_id & 0xFFFF) == CHIP_REV_MT7621_E2) + if (pcie->resets_inverted) reset_control_assert(port->pcie_rst); else reset_control_deassert(port->pcie_rst); @@ -239,9 +241,9 @@ static inline void mt7621_control_assert(struct mt7621_pcie_port *port) static inline void mt7621_control_deassert(struct mt7621_pcie_port *port) { - u32 chip_rev_id = rt_sysc_r32(MT7621_CHIP_REV_ID); + struct mt7621_pcie *pcie = port->pcie; - if ((chip_rev_id & 0xFFFF) == CHIP_REV_MT7621_E2) + if (pcie->resets_inverted) reset_control_deassert(port->pcie_rst); else reset_control_assert(port->pcie_rst); @@ -641,9 +643,14 @@ static int mt7621_pcie_register_host(struct pci_host_bridge *host, return pci_host_probe(host); } +static const struct soc_device_attribute mt7621_pci_quirks_match[] = { + { .soc_id = "mt7621", .revision = "E2" } +}; + static int mt7621_pci_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + const struct soc_device_attribute *attr; struct mt7621_pcie *pcie; struct pci_host_bridge *bridge; int err; @@ -661,6 +668,10 @@ static int mt7621_pci_probe(struct platform_device *pdev) platform_set_drvdata(pdev, pcie); INIT_LIST_HEAD(&pcie->ports); + attr = soc_device_match(mt7621_pci_quirks_match); + if (attr) + pcie->resets_inverted = true; + err = mt7621_pcie_parse_dt(pcie); if (err) { dev_err(dev, "Parsing DT failed\n"); diff --git a/drivers/staging/netlogic/TODO b/drivers/staging/netlogic/TODO index 8f172b017b94..20e22ecb9903 100644 --- a/drivers/staging/netlogic/TODO +++ b/drivers/staging/netlogic/TODO @@ -1,6 +1,6 @@ * Implementing 64bit stat counter in software * All memory allocation should be changed to DMA allocations -* Changing comments in to linux standred format +* Changing comments into linux standard format Please send patches To: diff --git a/drivers/staging/netlogic/xlr_net.c b/drivers/staging/netlogic/xlr_net.c index 05079f7be841..204fcdfc022f 100644 --- a/drivers/staging/netlogic/xlr_net.c +++ b/drivers/staging/netlogic/xlr_net.c @@ -976,8 +976,7 @@ static int xlr_net_probe(struct platform_device *pdev) priv->ndev = ndev; priv->port_id = (pdev->id * 4) + port; priv->nd = (struct xlr_net_data *)pdev->dev.platform_data; - res = platform_get_resource(pdev, IORESOURCE_MEM, port); - priv->base_addr = devm_ioremap_resource(&pdev->dev, res); + priv->base_addr = devm_platform_ioremap_resource(pdev, port); if (IS_ERR(priv->base_addr)) { err = PTR_ERR(priv->base_addr); goto err_gmac; diff --git a/drivers/staging/octeon-usb/octeon-hcd.c b/drivers/staging/octeon-usb/octeon-hcd.c index a5321cc692c5..582c9187559d 100644 --- a/drivers/staging/octeon-usb/octeon-hcd.c +++ b/drivers/staging/octeon-usb/octeon-hcd.c @@ -1836,8 +1836,7 @@ static void cvmx_usb_start_channel(struct octeon_hcd *usb, int channel, * * Returns: Pipe or NULL if none are ready */ -static struct cvmx_usb_pipe *cvmx_usb_find_ready_pipe( - struct octeon_hcd *usb, +static struct cvmx_usb_pipe *cvmx_usb_find_ready_pipe(struct octeon_hcd *usb, enum cvmx_usb_transfer xfer_type) { struct list_head *list = usb->active_pipes + xfer_type; diff --git a/drivers/staging/octeon/ethernet-mdio.c b/drivers/staging/octeon/ethernet-mdio.c index ffac0c4b3f5c..c798672d61b2 100644 --- a/drivers/staging/octeon/ethernet-mdio.c +++ b/drivers/staging/octeon/ethernet-mdio.c @@ -65,7 +65,7 @@ int cvm_oct_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) } void cvm_oct_note_carrier(struct octeon_ethernet *priv, - cvmx_helper_link_info_t li) + union cvmx_helper_link_info li) { if (li.s.link_up) { pr_notice_ratelimited("%s: %u Mbps %s duplex, port %d, queue %d\n", @@ -81,7 +81,7 @@ void cvm_oct_note_carrier(struct octeon_ethernet *priv, void cvm_oct_adjust_link(struct net_device *dev) { struct octeon_ethernet *priv = netdev_priv(dev); - cvmx_helper_link_info_t link_info; + union cvmx_helper_link_info link_info; link_info.u64 = 0; link_info.s.link_up = dev->phydev->link ? 1 : 0; @@ -106,7 +106,7 @@ int cvm_oct_common_stop(struct net_device *dev) { struct octeon_ethernet *priv = netdev_priv(dev); int interface = INTERFACE(priv->port); - cvmx_helper_link_info_t link_info; + union cvmx_helper_link_info link_info; union cvmx_gmxx_prtx_cfg gmx_cfg; int index = INDEX(priv->port); diff --git a/drivers/staging/octeon/ethernet-rgmii.c b/drivers/staging/octeon/ethernet-rgmii.c index d91fd5ce9e68..0c4fac31540a 100644 --- a/drivers/staging/octeon/ethernet-rgmii.c +++ b/drivers/staging/octeon/ethernet-rgmii.c @@ -53,7 +53,7 @@ static void cvm_oct_set_hw_preamble(struct octeon_ethernet *priv, bool enable) static void cvm_oct_check_preamble_errors(struct net_device *dev) { struct octeon_ethernet *priv = netdev_priv(dev); - cvmx_helper_link_info_t link_info; + union cvmx_helper_link_info link_info; unsigned long flags; link_info.u64 = priv->link_info; @@ -103,7 +103,7 @@ static void cvm_oct_check_preamble_errors(struct net_device *dev) static void cvm_oct_rgmii_poll(struct net_device *dev) { struct octeon_ethernet *priv = netdev_priv(dev); - cvmx_helper_link_info_t link_info; + union cvmx_helper_link_info link_info; bool status_change; link_info = cvmx_helper_link_get(priv->port); diff --git a/drivers/staging/octeon/ethernet-rx.c b/drivers/staging/octeon/ethernet-rx.c index 0e65955c746b..2c16230f993c 100644 --- a/drivers/staging/octeon/ethernet-rx.c +++ b/drivers/staging/octeon/ethernet-rx.c @@ -60,7 +60,7 @@ static irqreturn_t cvm_oct_do_interrupt(int irq, void *napi_id) * * Returns Non-zero if the packet can be dropped, zero otherwise. */ -static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work) +static inline int cvm_oct_check_rcv_error(struct cvmx_wqe *work) { int port; @@ -135,7 +135,7 @@ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work) return 0; } -static void copy_segments_to_skb(cvmx_wqe_t *work, struct sk_buff *skb) +static void copy_segments_to_skb(struct cvmx_wqe *work, struct sk_buff *skb) { int segments = work->word2.s.bufs; union cvmx_buf_ptr segment_ptr = work->packet_ptr; @@ -215,7 +215,7 @@ static int cvm_oct_poll(struct oct_rx_group *rx_group, int budget) struct sk_buff *skb = NULL; struct sk_buff **pskb = NULL; int skb_in_hw; - cvmx_wqe_t *work; + struct cvmx_wqe *work; int port; if (USE_ASYNC_IOBDMA && did_work_request) diff --git a/drivers/staging/octeon/ethernet-tx.c b/drivers/staging/octeon/ethernet-tx.c index 83469061a542..b334cf89794e 100644 --- a/drivers/staging/octeon/ethernet-tx.c +++ b/drivers/staging/octeon/ethernet-tx.c @@ -127,7 +127,7 @@ static void cvm_oct_free_tx_skbs(struct net_device *dev) */ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev) { - cvmx_pko_command_word0_t pko_command; + union cvmx_pko_command_word0 pko_command; union cvmx_buf_ptr hw_buffer; u64 old_scratch; u64 old_scratch2; @@ -514,7 +514,7 @@ int cvm_oct_xmit_pow(struct sk_buff *skb, struct net_device *dev) void *copy_location; /* Get a work queue entry */ - cvmx_wqe_t *work = cvmx_fpa_alloc(CVMX_FPA_WQE_POOL); + struct cvmx_wqe *work = cvmx_fpa_alloc(CVMX_FPA_WQE_POOL); if (unlikely(!work)) { printk_ratelimited("%s: Failed to allocate a work queue entry\n", @@ -598,7 +598,7 @@ int cvm_oct_xmit_pow(struct sk_buff *skb, struct net_device *dev) #endif work->word2.s.is_frag = !((ip_hdr(skb)->frag_off == 0) || (ip_hdr(skb)->frag_off == - 1 << 14)); + cpu_to_be16(1 << 14))); #if 0 /* Assume Linux is sending a good packet */ work->word2.s.IP_exc = 0; diff --git a/drivers/staging/octeon/ethernet.c b/drivers/staging/octeon/ethernet.c index cf8e9a23ebf9..f42c3816ce49 100644 --- a/drivers/staging/octeon/ethernet.c +++ b/drivers/staging/octeon/ethernet.c @@ -172,7 +172,7 @@ static void cvm_oct_configure_common_hw(void) */ int cvm_oct_free_work(void *work_queue_entry) { - cvmx_wqe_t *work = work_queue_entry; + struct cvmx_wqe *work = work_queue_entry; int segments = work->word2.s.bufs; union cvmx_buf_ptr segment_ptr = work->packet_ptr; @@ -460,7 +460,7 @@ int cvm_oct_common_open(struct net_device *dev, struct octeon_ethernet *priv = netdev_priv(dev); int interface = INTERFACE(priv->port); int index = INDEX(priv->port); - cvmx_helper_link_info_t link_info; + union cvmx_helper_link_info link_info; int rv; rv = cvm_oct_phy_setup_device(dev); @@ -496,7 +496,7 @@ int cvm_oct_common_open(struct net_device *dev, void cvm_oct_link_poll(struct net_device *dev) { struct octeon_ethernet *priv = netdev_priv(dev); - cvmx_helper_link_info_t link_info; + union cvmx_helper_link_info link_info; link_info = cvmx_helper_link_get(priv->port); if (link_info.u64 == priv->link_info) diff --git a/drivers/staging/octeon/octeon-ethernet.h b/drivers/staging/octeon/octeon-ethernet.h index a8a864b40913..a6140705706f 100644 --- a/drivers/staging/octeon/octeon-ethernet.h +++ b/drivers/staging/octeon/octeon-ethernet.h @@ -14,7 +14,7 @@ #include <linux/of.h> #include <linux/phy.h> -#ifdef CONFIG_MIPS +#ifdef CONFIG_CAVIUM_OCTEON_SOC #include <asm/octeon/octeon.h> @@ -91,7 +91,7 @@ int cvm_oct_common_stop(struct net_device *dev); int cvm_oct_common_open(struct net_device *dev, void (*link_poll)(struct net_device *)); void cvm_oct_note_carrier(struct octeon_ethernet *priv, - cvmx_helper_link_info_t li); + union cvmx_helper_link_info li); void cvm_oct_link_poll(struct net_device *dev); extern int always_use_pow; diff --git a/drivers/staging/octeon/octeon-stubs.h b/drivers/staging/octeon/octeon-stubs.h index b78ce9eaab85..d53bd801f440 100644 --- a/drivers/staging/octeon/octeon-stubs.h +++ b/drivers/staging/octeon/octeon-stubs.h @@ -1,5 +1,8 @@ #define CONFIG_CAVIUM_OCTEON_CVMSEG_SIZE 512 -#define XKPHYS_TO_PHYS(p) (p) + +#ifndef XKPHYS_TO_PHYS +# define XKPHYS_TO_PHYS(p) (p) +#endif #define OCTEON_IRQ_WORKQ0 0 #define OCTEON_IRQ_RML 0 @@ -38,7 +41,7 @@ #define CVMX_NPI_RSL_INT_BLOCKS 0 #define CVMX_POW_WQ_INT_PC 0 -typedef union { +union cvmx_pip_wqe_word2 { uint64_t u64; struct { uint64_t bufs:8; @@ -114,13 +117,13 @@ typedef union { uint64_t err_code:8; } snoip; -} cvmx_pip_wqe_word2; +}; union cvmx_pip_wqe_word0 { struct { uint64_t next_ptr:40; uint8_t unused; - uint16_t hw_chksum; + __wsum hw_chksum; } cn38xx; struct { uint64_t pknd:6; /* 0..5 */ @@ -180,15 +183,15 @@ union cvmx_buf_ptr { } s; }; -typedef struct { +struct cvmx_wqe { union cvmx_wqe_word0 word0; union cvmx_wqe_word1 word1; - cvmx_pip_wqe_word2 word2; + union cvmx_pip_wqe_word2 word2; union cvmx_buf_ptr packet_ptr; uint8_t packet_data[96]; -} cvmx_wqe_t; +}; -typedef union { +union cvmx_helper_link_info { uint64_t u64; struct { uint64_t reserved_20_63:44; @@ -196,18 +199,18 @@ typedef union { uint64_t full_duplex:1; /**< 1 if the link is full duplex */ uint64_t speed:18; /**< Speed of the link in Mbps */ } s; -} cvmx_helper_link_info_t; +}; -typedef enum { +enum cvmx_fau_reg_32 { CVMX_FAU_REG_32_START = 0, -} cvmx_fau_reg_32_t; +}; -typedef enum { +enum cvmx_fau_op_size { CVMX_FAU_OP_SIZE_8 = 0, CVMX_FAU_OP_SIZE_16 = 1, CVMX_FAU_OP_SIZE_32 = 2, CVMX_FAU_OP_SIZE_64 = 3 -} cvmx_fau_op_size_t; +}; typedef enum { CVMX_SPI_MODE_UNKNOWN = 0, @@ -1134,7 +1137,7 @@ union cvmx_npi_rsl_int_blocks { } cn50xx; }; -typedef union { +union cvmx_pko_command_word0 { uint64_t u64; struct { uint64_t total_bytes:16; @@ -1154,7 +1157,7 @@ typedef union { uint64_t size0:2; uint64_t size1:2; } s; -} cvmx_pko_command_word0_t; +}; union cvmx_ciu_timx { uint64_t u64; @@ -1175,16 +1178,18 @@ union cvmx_gmxx_rxx_rx_inbnd { } s; }; -static inline int32_t cvmx_fau_fetch_and_add32(cvmx_fau_reg_32_t reg, +static inline int32_t cvmx_fau_fetch_and_add32(enum cvmx_fau_reg_32 reg, int32_t value) { return value; } -static inline void cvmx_fau_atomic_add32(cvmx_fau_reg_32_t reg, int32_t value) +static inline void cvmx_fau_atomic_add32(enum cvmx_fau_reg_32 reg, + int32_t value) { } -static inline void cvmx_fau_atomic_write32(cvmx_fau_reg_32_t reg, int32_t value) +static inline void cvmx_fau_atomic_write32(enum cvmx_fau_reg_32 reg, + int32_t value) { } static inline uint64_t cvmx_scratch_read64(uint64_t address) @@ -1195,7 +1200,7 @@ static inline uint64_t cvmx_scratch_read64(uint64_t address) static inline void cvmx_scratch_write64(uint64_t address, uint64_t value) { } -static inline int cvmx_wqe_get_grp(cvmx_wqe_t *work) +static inline int cvmx_wqe_get_grp(struct cvmx_wqe *work) { return 0; } @@ -1264,15 +1269,15 @@ static inline cvmx_helper_interface_mode_t cvmx_helper_interface_get_mode(int return 0; } -static inline cvmx_helper_link_info_t cvmx_helper_link_get(int ipd_port) +static inline union cvmx_helper_link_info cvmx_helper_link_get(int ipd_port) { - cvmx_helper_link_info_t ret = { .u64 = 0 }; + union cvmx_helper_link_info ret = { .u64 = 0 }; return ret; } static inline int cvmx_helper_link_set(int ipd_port, - cvmx_helper_link_info_t link_info) + union cvmx_helper_link_info link_info) { return 0; } @@ -1342,14 +1347,14 @@ static inline void cvmx_pow_work_request_async(int scr_addr, cvmx_pow_wait_t wait) { } -static inline cvmx_wqe_t *cvmx_pow_work_response_async(int scr_addr) +static inline struct cvmx_wqe *cvmx_pow_work_response_async(int scr_addr) { - cvmx_wqe_t *wqe = (void *)(unsigned long)scr_addr; + struct cvmx_wqe *wqe = (void *)(unsigned long)scr_addr; return wqe; } -static inline cvmx_wqe_t *cvmx_pow_work_request_sync(cvmx_pow_wait_t wait) +static inline struct cvmx_wqe *cvmx_pow_work_request_sync(cvmx_pow_wait_t wait) { return (void *)(unsigned long)wait; } @@ -1361,7 +1366,7 @@ static inline int cvmx_spi_restart_interface(int interface, } static inline void cvmx_fau_async_fetch_and_add32(uint64_t scraddr, - cvmx_fau_reg_32_t reg, + enum cvmx_fau_reg_32 reg, int32_t value) { } @@ -1379,29 +1384,27 @@ static inline void cvmx_pko_send_packet_prepare(uint64_t port, uint64_t queue, { } static inline cvmx_pko_status_t cvmx_pko_send_packet_finish(uint64_t port, - uint64_t queue, cvmx_pko_command_word0_t pko_command, + uint64_t queue, union cvmx_pko_command_word0 pko_command, union cvmx_buf_ptr packet, cvmx_pko_lock_t use_locking) { - cvmx_pko_status_t ret = 0; - - return ret; + return 0; } -static inline void cvmx_wqe_set_port(cvmx_wqe_t *work, int port) +static inline void cvmx_wqe_set_port(struct cvmx_wqe *work, int port) { } -static inline void cvmx_wqe_set_qos(cvmx_wqe_t *work, int qos) +static inline void cvmx_wqe_set_qos(struct cvmx_wqe *work, int qos) { } -static inline int cvmx_wqe_get_qos(cvmx_wqe_t *work) +static inline int cvmx_wqe_get_qos(struct cvmx_wqe *work) { return 0; } -static inline void cvmx_wqe_set_grp(cvmx_wqe_t *work, int grp) +static inline void cvmx_wqe_set_grp(struct cvmx_wqe *work, int grp) { } -static inline void cvmx_pow_work_submit(cvmx_wqe_t *wqp, uint32_t tag, +static inline void cvmx_pow_work_submit(struct cvmx_wqe *wqp, uint32_t tag, enum cvmx_pow_tag_type tag_type, uint64_t qos, uint64_t grp) { } diff --git a/drivers/staging/olpc_dcon/Kconfig b/drivers/staging/olpc_dcon/Kconfig index f5c716bb3413..d1a0dea09ef0 100644 --- a/drivers/staging/olpc_dcon/Kconfig +++ b/drivers/staging/olpc_dcon/Kconfig @@ -3,7 +3,7 @@ config FB_OLPC_DCON tristate "One Laptop Per Child Display CONtroller support" depends on OLPC && FB depends on I2C - depends on (GPIO_CS5535 || GPIO_CS5535=n) + depends on GPIO_CS5535 && ACPI select BACKLIGHT_CLASS_DEVICE help In order to support very low power operation, the XO laptop uses a @@ -15,22 +15,3 @@ config FB_OLPC_DCON This controller is only available on OLPC platforms. Unless you have one of these platforms, you will want to say 'N'. -config FB_OLPC_DCON_1 - bool "OLPC XO-1 DCON support" - depends on FB_OLPC_DCON && GPIO_CS5535 - default y - help - Enable support for the DCON in XO-1 model laptops. The kernel - communicates with the DCON using model-specific code. If you - have an XO-1 (or if you're unsure what model you have), you should - say 'Y'. - -config FB_OLPC_DCON_1_5 - bool "OLPC XO-1.5 DCON support" - depends on FB_OLPC_DCON && ACPI - default y - help - Enable support for the DCON in XO-1.5 model laptops. The kernel - communicates with the DCON using model-specific code. If you - have an XO-1.5 (or if you're unsure what model you have), you - should say 'Y'. diff --git a/drivers/staging/olpc_dcon/Makefile b/drivers/staging/olpc_dcon/Makefile index cb1248c5c162..734b2ce26066 100644 --- a/drivers/staging/olpc_dcon/Makefile +++ b/drivers/staging/olpc_dcon/Makefile @@ -1,7 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -olpc-dcon-objs += olpc_dcon.o -olpc-dcon-$(CONFIG_FB_OLPC_DCON_1) += olpc_dcon_xo_1.o -olpc-dcon-$(CONFIG_FB_OLPC_DCON_1_5) += olpc_dcon_xo_1_5.o +olpc-dcon-objs += olpc_dcon.o olpc_dcon_xo_1.o olpc_dcon_xo_1_5.o obj-$(CONFIG_FB_OLPC_DCON) += olpc-dcon.o diff --git a/drivers/staging/olpc_dcon/TODO b/drivers/staging/olpc_dcon/TODO index d8296f2ae872..7c263358b44a 100644 --- a/drivers/staging/olpc_dcon/TODO +++ b/drivers/staging/olpc_dcon/TODO @@ -8,7 +8,6 @@ TODO: internals, but isn't properly integrated, is not the correct solution. - see if vx855 gpio API can be made similar enough to cs5535 so we can share more code - - allow simultaneous XO-1 and XO-1.5 support Please send patches to Greg Kroah-Hartman <greg@kroah.com> and copy: diff --git a/drivers/staging/olpc_dcon/olpc_dcon.c b/drivers/staging/olpc_dcon/olpc_dcon.c index a254238be181..a0d6d90f4cc8 100644 --- a/drivers/staging/olpc_dcon/olpc_dcon.c +++ b/drivers/staging/olpc_dcon/olpc_dcon.c @@ -790,15 +790,11 @@ static struct i2c_driver dcon_driver = { static int __init olpc_dcon_init(void) { -#ifdef CONFIG_FB_OLPC_DCON_1_5 /* XO-1.5 */ if (olpc_board_at_least(olpc_board(0xd0))) pdata = &dcon_pdata_xo_1_5; -#endif -#ifdef CONFIG_FB_OLPC_DCON_1 - if (!pdata) + else pdata = &dcon_pdata_xo_1; -#endif return i2c_add_driver(&dcon_driver); } diff --git a/drivers/staging/olpc_dcon/olpc_dcon.h b/drivers/staging/olpc_dcon/olpc_dcon.h index 22d976a09785..41bd1360b56e 100644 --- a/drivers/staging/olpc_dcon/olpc_dcon.h +++ b/drivers/staging/olpc_dcon/olpc_dcon.h @@ -106,12 +106,7 @@ struct dcon_gpio { irqreturn_t dcon_interrupt(int irq, void *id); -#ifdef CONFIG_FB_OLPC_DCON_1 extern struct dcon_platform_data dcon_pdata_xo_1; -#endif - -#ifdef CONFIG_FB_OLPC_DCON_1_5 extern struct dcon_platform_data dcon_pdata_xo_1_5; -#endif #endif diff --git a/drivers/staging/qlge/TODO b/drivers/staging/qlge/TODO index 51c509084e80..f93f7428f5d5 100644 --- a/drivers/staging/qlge/TODO +++ b/drivers/staging/qlge/TODO @@ -1,6 +1,3 @@ -* reception stalls permanently (until admin intervention) if the rx buffer - queues become empty because of allocation failures (ex. under memory - pressure) * commit 7c734359d350 ("qlge: Size RX buffers based on MTU.", v2.6.33-rc1) introduced dead code in the receive routines, which should be rewritten anyways by the admission of the author himself, see the comment above diff --git a/drivers/staging/qlge/qlge.h b/drivers/staging/qlge/qlge.h index ad7c5eb8a3b6..6ec7e3ce3863 100644 --- a/drivers/staging/qlge/qlge.h +++ b/drivers/staging/qlge/qlge.h @@ -34,8 +34,13 @@ #define NUM_TX_RING_ENTRIES 256 #define NUM_RX_RING_ENTRIES 256 -#define NUM_SMALL_BUFFERS 512 -#define NUM_LARGE_BUFFERS 512 +/* Use the same len for sbq and lbq. Note that it seems like the device might + * support different sizes. + */ +#define QLGE_BQ_SHIFT 9 +#define QLGE_BQ_LEN BIT(QLGE_BQ_SHIFT) +#define QLGE_BQ_SIZE (QLGE_BQ_LEN * sizeof(__le64)) + #define DB_PAGE_SIZE 4096 /* Calculate the number of (4k) pages required to @@ -46,8 +51,8 @@ (((x * sizeof(u64)) % DB_PAGE_SIZE) ? 1 : 0)) #define RX_RING_SHADOW_SPACE (sizeof(u64) + \ - MAX_DB_PAGES_PER_BQ(NUM_SMALL_BUFFERS) * sizeof(u64) + \ - MAX_DB_PAGES_PER_BQ(NUM_LARGE_BUFFERS) * sizeof(u64)) + MAX_DB_PAGES_PER_BQ(QLGE_BQ_LEN) * sizeof(u64) + \ + MAX_DB_PAGES_PER_BQ(QLGE_BQ_LEN) * sizeof(u64)) #define LARGE_BUFFER_MAX_SIZE 8192 #define LARGE_BUFFER_MIN_SIZE 2048 @@ -77,6 +82,11 @@ #define LSD(x) ((u32)((u64)(x))) #define MSD(x) ((u32)((((u64)(x)) >> 32))) +/* In some cases, the device interprets a value of 0x0000 as 65536. These + * cases are marked using the following macro. + */ +#define QLGE_FIT16(value) ((u16)(value)) + /* MPI test register definitions. This register * is used for determining alternate NIC function's * PCI->func number. @@ -1358,25 +1368,6 @@ struct tx_ring_desc { struct tx_ring_desc *next; }; -struct page_chunk { - struct page *page; /* master page */ - char *va; /* virt addr for this chunk */ - u64 map; /* mapping for master */ - unsigned int offset; /* offset for this chunk */ - unsigned int last_flag; /* flag set for last chunk in page */ -}; - -struct bq_desc { - union { - struct page_chunk pg_chunk; - struct sk_buff *skb; - } p; - __le64 *addr; - u32 index; - DEFINE_DMA_UNMAP_ADDR(mapaddr); - DEFINE_DMA_UNMAP_LEN(maplen); -}; - #define QL_TXQ_IDX(qdev, skb) (smp_processor_id()%(qdev->tx_ring_count)) struct tx_ring { @@ -1406,15 +1397,68 @@ struct tx_ring { u64 tx_errors; }; -/* - * Type of inbound queue. - */ -enum { - DEFAULT_Q = 2, /* Handles slow queue and chip/MPI events. */ - TX_Q = 3, /* Handles outbound completions. */ - RX_Q = 4, /* Handles inbound completions. */ +struct qlge_page_chunk { + struct page *page; + void *va; /* virt addr including offset */ + unsigned int offset; }; +struct qlge_bq_desc { + union { + /* for large buffers */ + struct qlge_page_chunk pg_chunk; + /* for small buffers */ + struct sk_buff *skb; + } p; + dma_addr_t dma_addr; + /* address in ring where the buffer address is written for the device */ + __le64 *buf_ptr; + u32 index; +}; + +/* buffer queue */ +struct qlge_bq { + __le64 *base; + dma_addr_t base_dma; + __le64 *base_indirect; + dma_addr_t base_indirect_dma; + struct qlge_bq_desc *queue; + /* prod_idx is the index of the first buffer that may NOT be used by + * hw, ie. one after the last. Advanced by sw. + */ + void __iomem *prod_idx_db_reg; + /* next index where sw should refill a buffer for hw */ + u16 next_to_use; + /* next index where sw expects to find a buffer filled by hw */ + u16 next_to_clean; + enum { + QLGE_SB, /* small buffer */ + QLGE_LB, /* large buffer */ + } type; +}; + +#define QLGE_BQ_CONTAINER(bq) \ +({ \ + typeof(bq) _bq = bq; \ + (struct rx_ring *)((char *)_bq - (_bq->type == QLGE_SB ? \ + offsetof(struct rx_ring, sbq) : \ + offsetof(struct rx_ring, lbq))); \ +}) + +/* Experience shows that the device ignores the low 4 bits of the tail index. + * Refill up to a x16 multiple. + */ +#define QLGE_BQ_ALIGN(index) ALIGN_DOWN(index, 16) + +#define QLGE_BQ_WRAP(index) ((index) & (QLGE_BQ_LEN - 1)) + +#define QLGE_BQ_HW_OWNED(bq) \ +({ \ + typeof(bq) _bq = bq; \ + QLGE_BQ_WRAP(QLGE_BQ_ALIGN((_bq)->next_to_use) - \ + (_bq)->next_to_clean); \ +}) + struct rx_ring { struct cqicb cqicb; /* The chip's completion queue init control block. */ @@ -1432,40 +1476,17 @@ struct rx_ring { void __iomem *valid_db_reg; /* PCI doorbell mem area + 0x04 */ /* Large buffer queue elements. */ - u32 lbq_len; /* entry count */ - u32 lbq_size; /* size in bytes of queue */ - u32 lbq_buf_size; - void *lbq_base; - dma_addr_t lbq_base_dma; - void *lbq_base_indirect; - dma_addr_t lbq_base_indirect_dma; - struct page_chunk pg_chunk; /* current page for chunks */ - struct bq_desc *lbq; /* array of control blocks */ - void __iomem *lbq_prod_idx_db_reg; /* PCI doorbell mem area + 0x18 */ - u32 lbq_prod_idx; /* current sw prod idx */ - u32 lbq_curr_idx; /* next entry we expect */ - u32 lbq_clean_idx; /* beginning of new descs */ - u32 lbq_free_cnt; /* free buffer desc cnt */ + struct qlge_bq lbq; + struct qlge_page_chunk master_chunk; + dma_addr_t chunk_dma_addr; /* Small buffer queue elements. */ - u32 sbq_len; /* entry count */ - u32 sbq_size; /* size in bytes of queue */ - u32 sbq_buf_size; - void *sbq_base; - dma_addr_t sbq_base_dma; - void *sbq_base_indirect; - dma_addr_t sbq_base_indirect_dma; - struct bq_desc *sbq; /* array of control blocks */ - void __iomem *sbq_prod_idx_db_reg; /* PCI doorbell mem area + 0x1c */ - u32 sbq_prod_idx; /* current sw prod idx */ - u32 sbq_curr_idx; /* next entry we expect */ - u32 sbq_clean_idx; /* beginning of new descs */ - u32 sbq_free_cnt; /* free buffer desc cnt */ + struct qlge_bq sbq; /* Misc. handler elements. */ - u32 type; /* Type of queue, tx, rx. */ u32 irq; /* Which vector this ring is assigned. */ u32 cpu; /* Which CPU this should run on. */ + struct delayed_work refill_work; char name[IFNAMSIZ + 5]; struct napi_struct napi; u8 reserved; @@ -1982,11 +2003,6 @@ struct intr_context { u32 intr_dis_mask; /* value/mask used to disable this intr */ u32 intr_read_mask; /* value/mask used to read this intr */ char name[IFNAMSIZ * 2]; - atomic_t irq_cnt; /* irq_cnt is used in single vector - * environment. It's incremented for each - * irq handler that is scheduled. When each - * handler finishes it decrements irq_cnt and - * enables interrupts if it's zero. */ irq_handler_t handler; }; @@ -2074,7 +2090,6 @@ struct ql_adapter { u32 port; /* Port number this adapter */ spinlock_t adapter_lock; - spinlock_t hw_lock; spinlock_t stats_lock; /* PCI Bus Relative Register Addresses */ @@ -2115,6 +2130,7 @@ struct ql_adapter { struct rx_ring rx_ring[MAX_RX_RINGS]; struct tx_ring tx_ring[MAX_TX_RINGS]; unsigned int lbq_buf_order; + u32 lbq_buf_size; int rx_csum; u32 default_rx_queue; @@ -2235,7 +2251,6 @@ void ql_mpi_reset_work(struct work_struct *work); void ql_mpi_core_to_log(struct work_struct *work); int ql_wait_reg_rdy(struct ql_adapter *qdev, u32 reg, u32 bit, u32 ebit); void ql_queue_asic_error(struct ql_adapter *qdev); -u32 ql_enable_completion_interrupt(struct ql_adapter *qdev, u32 intr); void ql_set_ethtool_ops(struct net_device *ndev); int ql_read_xgmac_reg64(struct ql_adapter *qdev, u32 reg, u64 *data); void ql_mpi_idc_work(struct work_struct *work); diff --git a/drivers/staging/qlge/qlge_dbg.c b/drivers/staging/qlge/qlge_dbg.c index 31389ab8bdf7..83f34ca43aa4 100644 --- a/drivers/staging/qlge/qlge_dbg.c +++ b/drivers/staging/qlge/qlge_dbg.c @@ -7,7 +7,7 @@ /* Read a NIC register from the alternate function. */ static u32 ql_read_other_func_reg(struct ql_adapter *qdev, - u32 reg) + u32 reg) { u32 register_to_read; u32 reg_val; @@ -26,7 +26,7 @@ static u32 ql_read_other_func_reg(struct ql_adapter *qdev, /* Write a NIC register from the alternate function. */ static int ql_write_other_func_reg(struct ql_adapter *qdev, - u32 reg, u32 reg_val) + u32 reg, u32 reg_val) { u32 register_to_read; int status = 0; @@ -41,7 +41,7 @@ static int ql_write_other_func_reg(struct ql_adapter *qdev, } static int ql_wait_other_func_reg_rdy(struct ql_adapter *qdev, u32 reg, - u32 bit, u32 err_bit) + u32 bit, u32 err_bit) { u32 temp; int count = 10; @@ -61,22 +61,22 @@ static int ql_wait_other_func_reg_rdy(struct ql_adapter *qdev, u32 reg, } static int ql_read_other_func_serdes_reg(struct ql_adapter *qdev, u32 reg, - u32 *data) + u32 *data) { int status; /* wait for reg to come ready */ status = ql_wait_other_func_reg_rdy(qdev, XG_SERDES_ADDR / 4, - XG_SERDES_ADDR_RDY, 0); + XG_SERDES_ADDR_RDY, 0); if (status) goto exit; /* set up for reg read */ - ql_write_other_func_reg(qdev, XG_SERDES_ADDR/4, reg | PROC_ADDR_R); + ql_write_other_func_reg(qdev, XG_SERDES_ADDR / 4, reg | PROC_ADDR_R); /* wait for reg to come ready */ status = ql_wait_other_func_reg_rdy(qdev, XG_SERDES_ADDR / 4, - XG_SERDES_ADDR_RDY, 0); + XG_SERDES_ADDR_RDY, 0); if (status) goto exit; @@ -111,8 +111,8 @@ exit: } static void ql_get_both_serdes(struct ql_adapter *qdev, u32 addr, - u32 *direct_ptr, u32 *indirect_ptr, - unsigned int direct_valid, unsigned int indirect_valid) + u32 *direct_ptr, u32 *indirect_ptr, + bool direct_valid, bool indirect_valid) { unsigned int status; @@ -133,16 +133,15 @@ static void ql_get_both_serdes(struct ql_adapter *qdev, u32 addr, } static int ql_get_serdes_regs(struct ql_adapter *qdev, - struct ql_mpi_coredump *mpi_coredump) + struct ql_mpi_coredump *mpi_coredump) { int status; - unsigned int xfi_direct_valid, xfi_indirect_valid, xaui_direct_valid; - unsigned int xaui_indirect_valid, i; + bool xfi_direct_valid = false, xfi_indirect_valid = false; + bool xaui_direct_valid = true, xaui_indirect_valid = true; + unsigned int i; u32 *direct_ptr, temp; u32 *indirect_ptr; - xfi_direct_valid = xfi_indirect_valid = 0; - xaui_direct_valid = xaui_indirect_valid = 1; /* The XAUI needs to be read out per port */ status = ql_read_other_func_serdes_reg(qdev, @@ -152,7 +151,7 @@ static int ql_get_serdes_regs(struct ql_adapter *qdev, if ((temp & XG_SERDES_ADDR_XAUI_PWR_DOWN) == XG_SERDES_ADDR_XAUI_PWR_DOWN) - xaui_indirect_valid = 0; + xaui_indirect_valid = false; status = ql_read_serdes_reg(qdev, XG_SERDES_XAUI_HSS_PCS_START, &temp); @@ -161,7 +160,7 @@ static int ql_get_serdes_regs(struct ql_adapter *qdev, if ((temp & XG_SERDES_ADDR_XAUI_PWR_DOWN) == XG_SERDES_ADDR_XAUI_PWR_DOWN) - xaui_direct_valid = 0; + xaui_direct_valid = false; /* * XFI register is shared so only need to read one @@ -176,18 +175,18 @@ static int ql_get_serdes_regs(struct ql_adapter *qdev, /* now see if i'm NIC 1 or NIC 2 */ if (qdev->func & 1) /* I'm NIC 2, so the indirect (NIC1) xfi is up. */ - xfi_indirect_valid = 1; + xfi_indirect_valid = true; else - xfi_direct_valid = 1; + xfi_direct_valid = true; } if ((temp & XG_SERDES_ADDR_XFI2_PWR_UP) == XG_SERDES_ADDR_XFI2_PWR_UP) { /* now see if i'm NIC 1 or NIC 2 */ if (qdev->func & 1) /* I'm NIC 2, so the indirect (NIC1) xfi is up. */ - xfi_direct_valid = 1; + xfi_direct_valid = true; else - xfi_indirect_valid = 1; + xfi_indirect_valid = true; } /* Get XAUI_AN register block. */ @@ -203,7 +202,7 @@ static int ql_get_serdes_regs(struct ql_adapter *qdev, for (i = 0; i <= 0x000000034; i += 4, direct_ptr++, indirect_ptr++) ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr, - xaui_direct_valid, xaui_indirect_valid); + xaui_direct_valid, xaui_indirect_valid); /* Get XAUI_HSS_PCS register block. */ if (qdev->func & 1) { @@ -220,7 +219,7 @@ static int ql_get_serdes_regs(struct ql_adapter *qdev, for (i = 0x800; i <= 0x880; i += 4, direct_ptr++, indirect_ptr++) ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr, - xaui_direct_valid, xaui_indirect_valid); + xaui_direct_valid, xaui_indirect_valid); /* Get XAUI_XFI_AN register block. */ if (qdev->func & 1) { @@ -233,7 +232,7 @@ static int ql_get_serdes_regs(struct ql_adapter *qdev, for (i = 0x1000; i <= 0x1034; i += 4, direct_ptr++, indirect_ptr++) ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr, - xfi_direct_valid, xfi_indirect_valid); + xfi_direct_valid, xfi_indirect_valid); /* Get XAUI_XFI_TRAIN register block. */ if (qdev->func & 1) { @@ -248,7 +247,7 @@ static int ql_get_serdes_regs(struct ql_adapter *qdev, for (i = 0x1050; i <= 0x107c; i += 4, direct_ptr++, indirect_ptr++) ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr, - xfi_direct_valid, xfi_indirect_valid); + xfi_direct_valid, xfi_indirect_valid); /* Get XAUI_XFI_HSS_PCS register block. */ if (qdev->func & 1) { @@ -265,7 +264,7 @@ static int ql_get_serdes_regs(struct ql_adapter *qdev, for (i = 0x1800; i <= 0x1838; i += 4, direct_ptr++, indirect_ptr++) ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr, - xfi_direct_valid, xfi_indirect_valid); + xfi_direct_valid, xfi_indirect_valid); /* Get XAUI_XFI_HSS_TX register block. */ if (qdev->func & 1) { @@ -280,7 +279,7 @@ static int ql_get_serdes_regs(struct ql_adapter *qdev, } for (i = 0x1c00; i <= 0x1c1f; i++, direct_ptr++, indirect_ptr++) ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr, - xfi_direct_valid, xfi_indirect_valid); + xfi_direct_valid, xfi_indirect_valid); /* Get XAUI_XFI_HSS_RX register block. */ if (qdev->func & 1) { @@ -296,7 +295,7 @@ static int ql_get_serdes_regs(struct ql_adapter *qdev, for (i = 0x1c40; i <= 0x1c5f; i++, direct_ptr++, indirect_ptr++) ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr, - xfi_direct_valid, xfi_indirect_valid); + xfi_direct_valid, xfi_indirect_valid); /* Get XAUI_XFI_HSS_PLL register block. */ @@ -313,18 +312,18 @@ static int ql_get_serdes_regs(struct ql_adapter *qdev, } for (i = 0x1e00; i <= 0x1e1f; i++, direct_ptr++, indirect_ptr++) ql_get_both_serdes(qdev, i, direct_ptr, indirect_ptr, - xfi_direct_valid, xfi_indirect_valid); + xfi_direct_valid, xfi_indirect_valid); return 0; } static int ql_read_other_func_xgmac_reg(struct ql_adapter *qdev, u32 reg, - u32 *data) + u32 *data) { int status = 0; /* wait for reg to come ready */ status = ql_wait_other_func_reg_rdy(qdev, XGMAC_ADDR / 4, - XGMAC_ADDR_RDY, XGMAC_ADDR_XME); + XGMAC_ADDR_RDY, XGMAC_ADDR_XME); if (status) goto exit; @@ -333,7 +332,7 @@ static int ql_read_other_func_xgmac_reg(struct ql_adapter *qdev, u32 reg, /* wait for reg to come ready */ status = ql_wait_other_func_reg_rdy(qdev, XGMAC_ADDR / 4, - XGMAC_ADDR_RDY, XGMAC_ADDR_XME); + XGMAC_ADDR_RDY, XGMAC_ADDR_XME); if (status) goto exit; @@ -347,17 +346,17 @@ exit: * skipping unused locations. */ static int ql_get_xgmac_regs(struct ql_adapter *qdev, u32 *buf, - unsigned int other_function) + unsigned int other_function) { int status = 0; int i; for (i = PAUSE_SRC_LO; i < XGMAC_REGISTER_END; i += 4, buf++) { /* We're reading 400 xgmac registers, but we filter out - * serveral locations that are non-responsive to reads. + * several locations that are non-responsive to reads. */ if ((i == 0x00000114) || - (i == 0x00000118) || + (i == 0x00000118) || (i == 0x0000013c) || (i == 0x00000140) || (i > 0x00000150 && i < 0x000001fc) || @@ -389,7 +388,6 @@ static int ql_get_xgmac_regs(struct ql_adapter *qdev, u32 *buf, static int ql_get_ets_regs(struct ql_adapter *qdev, u32 *buf) { - int status = 0; int i; for (i = 0; i < 8; i++, buf++) { @@ -402,7 +400,7 @@ static int ql_get_ets_regs(struct ql_adapter *qdev, u32 *buf) *buf = ql_read32(qdev, CNA_ETS); } - return status; + return 0; } static void ql_get_intr_states(struct ql_adapter *qdev, u32 *buf) @@ -411,7 +409,7 @@ static void ql_get_intr_states(struct ql_adapter *qdev, u32 *buf) for (i = 0; i < qdev->rx_ring_count; i++, buf++) { ql_write32(qdev, INTR_EN, - qdev->intr_context[i].intr_read_mask); + qdev->intr_context[i].intr_read_mask); *buf = ql_read32(qdev, INTR_EN); } } @@ -427,7 +425,7 @@ static int ql_get_cam_entries(struct ql_adapter *qdev, u32 *buf) for (i = 0; i < 16; i++) { status = ql_get_mac_addr_reg(qdev, - MAC_ADDR_TYPE_CAM_MAC, i, value); + MAC_ADDR_TYPE_CAM_MAC, i, value); if (status) { netif_err(qdev, drv, qdev->ndev, "Failed read of mac index register\n"); @@ -439,7 +437,7 @@ static int ql_get_cam_entries(struct ql_adapter *qdev, u32 *buf) } for (i = 0; i < 32; i++) { status = ql_get_mac_addr_reg(qdev, - MAC_ADDR_TYPE_MULTI_MAC, i, value); + MAC_ADDR_TYPE_MULTI_MAC, i, value); if (status) { netif_err(qdev, drv, qdev->ndev, "Failed read of mac index register\n"); @@ -498,7 +496,7 @@ end: /* Read the MPI Processor core registers */ static int ql_get_mpi_regs(struct ql_adapter *qdev, u32 *buf, - u32 offset, u32 count) + u32 offset, u32 count) { int i, status = 0; for (i = 0; i < count; i++, buf++) { @@ -511,7 +509,7 @@ static int ql_get_mpi_regs(struct ql_adapter *qdev, u32 *buf, /* Read the ASIC probe dump */ static unsigned int *ql_get_probe(struct ql_adapter *qdev, u32 clock, - u32 valid, u32 *buf) + u32 valid, u32 *buf) { u32 module, mux_sel, probe, lo_val, hi_val; @@ -546,13 +544,13 @@ static int ql_get_probe_dump(struct ql_adapter *qdev, unsigned int *buf) /* First we have to enable the probe mux */ ql_write_mpi_reg(qdev, MPI_TEST_FUNC_PRB_CTL, MPI_TEST_FUNC_PRB_EN); buf = ql_get_probe(qdev, PRB_MX_ADDR_SYS_CLOCK, - PRB_MX_ADDR_VALID_SYS_MOD, buf); + PRB_MX_ADDR_VALID_SYS_MOD, buf); buf = ql_get_probe(qdev, PRB_MX_ADDR_PCI_CLOCK, - PRB_MX_ADDR_VALID_PCI_MOD, buf); + PRB_MX_ADDR_VALID_PCI_MOD, buf); buf = ql_get_probe(qdev, PRB_MX_ADDR_XGM_CLOCK, - PRB_MX_ADDR_VALID_XGM_MOD, buf); + PRB_MX_ADDR_VALID_XGM_MOD, buf); buf = ql_get_probe(qdev, PRB_MX_ADDR_FC_CLOCK, - PRB_MX_ADDR_VALID_FC_MOD, buf); + PRB_MX_ADDR_VALID_FC_MOD, buf); return 0; } @@ -667,7 +665,7 @@ static void ql_get_mac_protocol_registers(struct ql_adapter *qdev, u32 *buf) result_index = 0; while ((result_index & MAC_ADDR_MR) == 0) { result_index = ql_read32(qdev, - MAC_ADDR_IDX); + MAC_ADDR_IDX); } result_data = ql_read32(qdev, MAC_ADDR_DATA); *buf = result_index; @@ -741,7 +739,7 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) /* Insert the global header */ memset(&(mpi_coredump->mpi_global_header), 0, - sizeof(struct mpi_coredump_global_header)); + sizeof(struct mpi_coredump_global_header)); mpi_coredump->mpi_global_header.cookie = MPI_COREDUMP_COOKIE; mpi_coredump->mpi_global_header.headerSize = sizeof(struct mpi_coredump_global_header); @@ -752,23 +750,23 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) /* Get generic NIC reg dump */ ql_build_coredump_seg_header(&mpi_coredump->nic_regs_seg_hdr, - NIC1_CONTROL_SEG_NUM, + NIC1_CONTROL_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->nic_regs), "NIC1 Registers"); ql_build_coredump_seg_header(&mpi_coredump->nic2_regs_seg_hdr, - NIC2_CONTROL_SEG_NUM, + NIC2_CONTROL_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->nic2_regs), "NIC2 Registers"); /* Get XGMac registers. (Segment 18, Rev C. step 21) */ ql_build_coredump_seg_header(&mpi_coredump->xgmac1_seg_hdr, - NIC1_XGMAC_SEG_NUM, + NIC1_XGMAC_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->xgmac1), "NIC1 XGMac Registers"); ql_build_coredump_seg_header(&mpi_coredump->xgmac2_seg_hdr, - NIC2_XGMAC_SEG_NUM, + NIC2_XGMAC_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->xgmac2), "NIC2 XGMac Registers"); @@ -799,97 +797,97 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) /* Rev C. Step 20a */ ql_build_coredump_seg_header(&mpi_coredump->xaui_an_hdr, - XAUI_AN_SEG_NUM, + XAUI_AN_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->serdes_xaui_an), "XAUI AN Registers"); /* Rev C. Step 20b */ ql_build_coredump_seg_header(&mpi_coredump->xaui_hss_pcs_hdr, - XAUI_HSS_PCS_SEG_NUM, + XAUI_HSS_PCS_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->serdes_xaui_hss_pcs), "XAUI HSS PCS Registers"); ql_build_coredump_seg_header(&mpi_coredump->xfi_an_hdr, XFI_AN_SEG_NUM, - sizeof(struct mpi_coredump_segment_header) + + sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->serdes_xfi_an), "XFI AN Registers"); ql_build_coredump_seg_header(&mpi_coredump->xfi_train_hdr, - XFI_TRAIN_SEG_NUM, + XFI_TRAIN_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->serdes_xfi_train), "XFI TRAIN Registers"); ql_build_coredump_seg_header(&mpi_coredump->xfi_hss_pcs_hdr, - XFI_HSS_PCS_SEG_NUM, + XFI_HSS_PCS_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->serdes_xfi_hss_pcs), "XFI HSS PCS Registers"); ql_build_coredump_seg_header(&mpi_coredump->xfi_hss_tx_hdr, - XFI_HSS_TX_SEG_NUM, + XFI_HSS_TX_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->serdes_xfi_hss_tx), "XFI HSS TX Registers"); ql_build_coredump_seg_header(&mpi_coredump->xfi_hss_rx_hdr, - XFI_HSS_RX_SEG_NUM, + XFI_HSS_RX_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->serdes_xfi_hss_rx), "XFI HSS RX Registers"); ql_build_coredump_seg_header(&mpi_coredump->xfi_hss_pll_hdr, - XFI_HSS_PLL_SEG_NUM, + XFI_HSS_PLL_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->serdes_xfi_hss_pll), "XFI HSS PLL Registers"); ql_build_coredump_seg_header(&mpi_coredump->xaui2_an_hdr, - XAUI2_AN_SEG_NUM, + XAUI2_AN_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->serdes2_xaui_an), "XAUI2 AN Registers"); ql_build_coredump_seg_header(&mpi_coredump->xaui2_hss_pcs_hdr, - XAUI2_HSS_PCS_SEG_NUM, + XAUI2_HSS_PCS_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->serdes2_xaui_hss_pcs), "XAUI2 HSS PCS Registers"); ql_build_coredump_seg_header(&mpi_coredump->xfi2_an_hdr, - XFI2_AN_SEG_NUM, + XFI2_AN_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->serdes2_xfi_an), "XFI2 AN Registers"); ql_build_coredump_seg_header(&mpi_coredump->xfi2_train_hdr, - XFI2_TRAIN_SEG_NUM, + XFI2_TRAIN_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->serdes2_xfi_train), "XFI2 TRAIN Registers"); ql_build_coredump_seg_header(&mpi_coredump->xfi2_hss_pcs_hdr, - XFI2_HSS_PCS_SEG_NUM, + XFI2_HSS_PCS_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->serdes2_xfi_hss_pcs), "XFI2 HSS PCS Registers"); ql_build_coredump_seg_header(&mpi_coredump->xfi2_hss_tx_hdr, - XFI2_HSS_TX_SEG_NUM, + XFI2_HSS_TX_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->serdes2_xfi_hss_tx), "XFI2 HSS TX Registers"); ql_build_coredump_seg_header(&mpi_coredump->xfi2_hss_rx_hdr, - XFI2_HSS_RX_SEG_NUM, + XFI2_HSS_RX_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->serdes2_xfi_hss_rx), "XFI2 HSS RX Registers"); ql_build_coredump_seg_header(&mpi_coredump->xfi2_hss_pll_hdr, - XFI2_HSS_PLL_SEG_NUM, + XFI2_HSS_PLL_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->serdes2_xfi_hss_pll), "XFI2 HSS PLL Registers"); @@ -903,7 +901,7 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) } ql_build_coredump_seg_header(&mpi_coredump->core_regs_seg_hdr, - CORE_SEG_NUM, + CORE_SEG_NUM, sizeof(mpi_coredump->core_regs_seg_hdr) + sizeof(mpi_coredump->mpi_core_regs) + sizeof(mpi_coredump->mpi_core_sh_regs), @@ -922,7 +920,7 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) /* Get the Test Logic Registers */ ql_build_coredump_seg_header(&mpi_coredump->test_logic_regs_seg_hdr, - TEST_LOGIC_SEG_NUM, + TEST_LOGIC_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->test_logic_regs), "Test Logic Regs"); @@ -933,7 +931,7 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) /* Get the RMII Registers */ ql_build_coredump_seg_header(&mpi_coredump->rmii_regs_seg_hdr, - RMII_SEG_NUM, + RMII_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->rmii_regs), "RMII Registers"); @@ -944,7 +942,7 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) /* Get the FCMAC1 Registers */ ql_build_coredump_seg_header(&mpi_coredump->fcmac1_regs_seg_hdr, - FCMAC1_SEG_NUM, + FCMAC1_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->fcmac1_regs), "FCMAC1 Registers"); @@ -956,7 +954,7 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) /* Get the FCMAC2 Registers */ ql_build_coredump_seg_header(&mpi_coredump->fcmac2_regs_seg_hdr, - FCMAC2_SEG_NUM, + FCMAC2_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->fcmac2_regs), "FCMAC2 Registers"); @@ -968,7 +966,7 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) /* Get the FC1 MBX Registers */ ql_build_coredump_seg_header(&mpi_coredump->fc1_mbx_regs_seg_hdr, - FC1_MBOX_SEG_NUM, + FC1_MBOX_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->fc1_mbx_regs), "FC1 MBox Regs"); @@ -979,7 +977,7 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) /* Get the IDE Registers */ ql_build_coredump_seg_header(&mpi_coredump->ide_regs_seg_hdr, - IDE_SEG_NUM, + IDE_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->ide_regs), "IDE Registers"); @@ -990,7 +988,7 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) /* Get the NIC1 MBX Registers */ ql_build_coredump_seg_header(&mpi_coredump->nic1_mbx_regs_seg_hdr, - NIC1_MBOX_SEG_NUM, + NIC1_MBOX_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->nic1_mbx_regs), "NIC1 MBox Regs"); @@ -1001,7 +999,7 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) /* Get the SMBus Registers */ ql_build_coredump_seg_header(&mpi_coredump->smbus_regs_seg_hdr, - SMBUS_SEG_NUM, + SMBUS_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->smbus_regs), "SMBus Registers"); @@ -1012,7 +1010,7 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) /* Get the FC2 MBX Registers */ ql_build_coredump_seg_header(&mpi_coredump->fc2_mbx_regs_seg_hdr, - FC2_MBOX_SEG_NUM, + FC2_MBOX_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->fc2_mbx_regs), "FC2 MBox Regs"); @@ -1023,7 +1021,7 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) /* Get the NIC2 MBX Registers */ ql_build_coredump_seg_header(&mpi_coredump->nic2_mbx_regs_seg_hdr, - NIC2_MBOX_SEG_NUM, + NIC2_MBOX_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->nic2_mbx_regs), "NIC2 MBox Regs"); @@ -1034,7 +1032,7 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) /* Get the I2C Registers */ ql_build_coredump_seg_header(&mpi_coredump->i2c_regs_seg_hdr, - I2C_SEG_NUM, + I2C_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->i2c_regs), "I2C Registers"); @@ -1045,7 +1043,7 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) /* Get the MEMC Registers */ ql_build_coredump_seg_header(&mpi_coredump->memc_regs_seg_hdr, - MEMC_SEG_NUM, + MEMC_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->memc_regs), "MEMC Registers"); @@ -1056,7 +1054,7 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) /* Get the PBus Registers */ ql_build_coredump_seg_header(&mpi_coredump->pbus_regs_seg_hdr, - PBUS_SEG_NUM, + PBUS_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->pbus_regs), "PBUS Registers"); @@ -1067,7 +1065,7 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) /* Get the MDE Registers */ ql_build_coredump_seg_header(&mpi_coredump->mde_regs_seg_hdr, - MDE_SEG_NUM, + MDE_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->mde_regs), "MDE Registers"); @@ -1077,7 +1075,7 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) goto err; ql_build_coredump_seg_header(&mpi_coredump->misc_nic_seg_hdr, - MISC_NIC_INFO_SEG_NUM, + MISC_NIC_INFO_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->misc_nic_info), "MISC NIC INFO"); @@ -1089,14 +1087,14 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) /* Segment 31 */ /* Get indexed register values. */ ql_build_coredump_seg_header(&mpi_coredump->intr_states_seg_hdr, - INTR_STATES_SEG_NUM, + INTR_STATES_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->intr_states), "INTR States"); ql_get_intr_states(qdev, &mpi_coredump->intr_states[0]); ql_build_coredump_seg_header(&mpi_coredump->cam_entries_seg_hdr, - CAM_ENTRIES_SEG_NUM, + CAM_ENTRIES_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->cam_entries), "CAM Entries"); @@ -1105,18 +1103,18 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) goto err; ql_build_coredump_seg_header(&mpi_coredump->nic_routing_words_seg_hdr, - ROUTING_WORDS_SEG_NUM, + ROUTING_WORDS_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->nic_routing_words), "Routing Words"); status = ql_get_routing_entries(qdev, - &mpi_coredump->nic_routing_words[0]); + &mpi_coredump->nic_routing_words[0]); if (status) goto err; /* Segment 34 (Rev C. step 23) */ ql_build_coredump_seg_header(&mpi_coredump->ets_seg_hdr, - ETS_SEG_NUM, + ETS_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->ets), "ETS Registers"); @@ -1125,24 +1123,24 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) goto err; ql_build_coredump_seg_header(&mpi_coredump->probe_dump_seg_hdr, - PROBE_DUMP_SEG_NUM, + PROBE_DUMP_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->probe_dump), "Probe Dump"); ql_get_probe_dump(qdev, &mpi_coredump->probe_dump[0]); ql_build_coredump_seg_header(&mpi_coredump->routing_reg_seg_hdr, - ROUTING_INDEX_SEG_NUM, + ROUTING_INDEX_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->routing_regs), "Routing Regs"); status = ql_get_routing_index_registers(qdev, - &mpi_coredump->routing_regs[0]); + &mpi_coredump->routing_regs[0]); if (status) goto err; ql_build_coredump_seg_header(&mpi_coredump->mac_prot_reg_seg_hdr, - MAC_PROTOCOL_SEG_NUM, + MAC_PROTOCOL_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->mac_prot_regs), "MAC Prot Regs"); @@ -1150,7 +1148,7 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) /* Get the semaphore registers for all 5 functions */ ql_build_coredump_seg_header(&mpi_coredump->sem_regs_seg_hdr, - SEM_REGS_SEG_NUM, + SEM_REGS_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->sem_regs), "Sem Registers"); @@ -1176,12 +1174,12 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) } ql_build_coredump_seg_header(&mpi_coredump->code_ram_seg_hdr, - WCS_RAM_SEG_NUM, + WCS_RAM_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->code_ram), "WCS RAM"); status = ql_dump_risc_ram_area(qdev, &mpi_coredump->code_ram[0], - CODE_RAM_ADDR, CODE_RAM_CNT); + CODE_RAM_ADDR, CODE_RAM_CNT); if (status) { netif_err(qdev, drv, qdev->ndev, "Failed Dump of CODE RAM. Status = 0x%.08x\n", @@ -1191,12 +1189,12 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) /* Insert the segment header */ ql_build_coredump_seg_header(&mpi_coredump->memc_ram_seg_hdr, - MEMC_RAM_SEG_NUM, + MEMC_RAM_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->memc_ram), "MEMC RAM"); status = ql_dump_risc_ram_area(qdev, &mpi_coredump->memc_ram[0], - MEMC_RAM_ADDR, MEMC_RAM_CNT); + MEMC_RAM_ADDR, MEMC_RAM_CNT); if (status) { netif_err(qdev, drv, qdev->ndev, "Failed Dump of MEMC RAM. Status = 0x%.08x\n", @@ -1231,7 +1229,7 @@ static void ql_gen_reg_dump(struct ql_adapter *qdev, memset(&(mpi_coredump->mpi_global_header), 0, - sizeof(struct mpi_coredump_global_header)); + sizeof(struct mpi_coredump_global_header)); mpi_coredump->mpi_global_header.cookie = MPI_COREDUMP_COOKIE; mpi_coredump->mpi_global_header.headerSize = sizeof(struct mpi_coredump_global_header); @@ -1243,7 +1241,7 @@ static void ql_gen_reg_dump(struct ql_adapter *qdev, /* segment 16 */ ql_build_coredump_seg_header(&mpi_coredump->misc_nic_seg_hdr, - MISC_NIC_INFO_SEG_NUM, + MISC_NIC_INFO_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->misc_nic_info), "MISC NIC INFO"); @@ -1254,7 +1252,7 @@ static void ql_gen_reg_dump(struct ql_adapter *qdev, /* Segment 16, Rev C. Step 18 */ ql_build_coredump_seg_header(&mpi_coredump->nic_regs_seg_hdr, - NIC1_CONTROL_SEG_NUM, + NIC1_CONTROL_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->nic_regs), "NIC Registers"); @@ -1265,14 +1263,14 @@ static void ql_gen_reg_dump(struct ql_adapter *qdev, /* Segment 31 */ /* Get indexed register values. */ ql_build_coredump_seg_header(&mpi_coredump->intr_states_seg_hdr, - INTR_STATES_SEG_NUM, + INTR_STATES_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->intr_states), "INTR States"); ql_get_intr_states(qdev, &mpi_coredump->intr_states[0]); ql_build_coredump_seg_header(&mpi_coredump->cam_entries_seg_hdr, - CAM_ENTRIES_SEG_NUM, + CAM_ENTRIES_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->cam_entries), "CAM Entries"); @@ -1281,18 +1279,18 @@ static void ql_gen_reg_dump(struct ql_adapter *qdev, return; ql_build_coredump_seg_header(&mpi_coredump->nic_routing_words_seg_hdr, - ROUTING_WORDS_SEG_NUM, + ROUTING_WORDS_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->nic_routing_words), "Routing Words"); status = ql_get_routing_entries(qdev, - &mpi_coredump->nic_routing_words[0]); + &mpi_coredump->nic_routing_words[0]); if (status) return; /* Segment 34 (Rev C. step 23) */ ql_build_coredump_seg_header(&mpi_coredump->ets_seg_hdr, - ETS_SEG_NUM, + ETS_SEG_NUM, sizeof(struct mpi_coredump_segment_header) + sizeof(mpi_coredump->ets), "ETS Registers"); @@ -1630,6 +1628,7 @@ void ql_dump_qdev(struct ql_adapter *qdev) DUMP_QDEV_FIELD(qdev, "0x%08x", xg_sem_mask); DUMP_QDEV_FIELD(qdev, "0x%08x", port_link_up); DUMP_QDEV_FIELD(qdev, "0x%08x", port_init); + DUMP_QDEV_FIELD(qdev, "%u", lbq_buf_size); } #endif @@ -1650,7 +1649,7 @@ void ql_dump_wqicb(struct wqicb *wqicb) void ql_dump_tx_ring(struct tx_ring *tx_ring) { - if (tx_ring == NULL) + if (!tx_ring) return; pr_err("===================== Dumping tx_ring %d ===============\n", tx_ring->wq_id); @@ -1730,16 +1729,24 @@ void ql_dump_cqicb(struct cqicb *cqicb) le16_to_cpu(cqicb->sbq_len)); } +static const char *qlge_rx_ring_type_name(struct rx_ring *rx_ring) +{ + struct ql_adapter *qdev = rx_ring->qdev; + + if (rx_ring->cq_id < qdev->rss_ring_count) + return "RX COMPLETION"; + else + return "TX COMPLETION"; +}; + void ql_dump_rx_ring(struct rx_ring *rx_ring) { - if (rx_ring == NULL) + if (!rx_ring) return; pr_err("===================== Dumping rx_ring %d ===============\n", rx_ring->cq_id); - pr_err("Dumping rx_ring %d, type = %s%s%s\n", - rx_ring->cq_id, rx_ring->type == DEFAULT_Q ? "DEFAULT" : "", - rx_ring->type == TX_Q ? "OUTBOUND COMPLETIONS" : "", - rx_ring->type == RX_Q ? "INBOUND_COMPLETIONS" : ""); + pr_err("Dumping rx_ring %d, type = %s\n", rx_ring->cq_id, + qlge_rx_ring_type_name(rx_ring)); pr_err("rx_ring->cqicb = %p\n", &rx_ring->cqicb); pr_err("rx_ring->cq_base = %p\n", rx_ring->cq_base); pr_err("rx_ring->cq_base_dma = %llx\n", @@ -1758,41 +1765,33 @@ void ql_dump_rx_ring(struct rx_ring *rx_ring) pr_err("rx_ring->curr_entry = %p\n", rx_ring->curr_entry); pr_err("rx_ring->valid_db_reg = %p\n", rx_ring->valid_db_reg); - pr_err("rx_ring->lbq_base = %p\n", rx_ring->lbq_base); - pr_err("rx_ring->lbq_base_dma = %llx\n", - (unsigned long long) rx_ring->lbq_base_dma); - pr_err("rx_ring->lbq_base_indirect = %p\n", - rx_ring->lbq_base_indirect); - pr_err("rx_ring->lbq_base_indirect_dma = %llx\n", - (unsigned long long) rx_ring->lbq_base_indirect_dma); - pr_err("rx_ring->lbq = %p\n", rx_ring->lbq); - pr_err("rx_ring->lbq_len = %d\n", rx_ring->lbq_len); - pr_err("rx_ring->lbq_size = %d\n", rx_ring->lbq_size); - pr_err("rx_ring->lbq_prod_idx_db_reg = %p\n", - rx_ring->lbq_prod_idx_db_reg); - pr_err("rx_ring->lbq_prod_idx = %d\n", rx_ring->lbq_prod_idx); - pr_err("rx_ring->lbq_curr_idx = %d\n", rx_ring->lbq_curr_idx); + pr_err("rx_ring->lbq.base = %p\n", rx_ring->lbq.base); + pr_err("rx_ring->lbq.base_dma = %llx\n", + (unsigned long long)rx_ring->lbq.base_dma); + pr_err("rx_ring->lbq.base_indirect = %p\n", + rx_ring->lbq.base_indirect); + pr_err("rx_ring->lbq.base_indirect_dma = %llx\n", + (unsigned long long)rx_ring->lbq.base_indirect_dma); + pr_err("rx_ring->lbq = %p\n", rx_ring->lbq.queue); + pr_err("rx_ring->lbq.prod_idx_db_reg = %p\n", + rx_ring->lbq.prod_idx_db_reg); + pr_err("rx_ring->lbq.next_to_use = %d\n", rx_ring->lbq.next_to_use); + pr_err("rx_ring->lbq.next_to_clean = %d\n", rx_ring->lbq.next_to_clean); pr_err("rx_ring->lbq_clean_idx = %d\n", rx_ring->lbq_clean_idx); pr_err("rx_ring->lbq_free_cnt = %d\n", rx_ring->lbq_free_cnt); - pr_err("rx_ring->lbq_buf_size = %d\n", rx_ring->lbq_buf_size); - - pr_err("rx_ring->sbq_base = %p\n", rx_ring->sbq_base); - pr_err("rx_ring->sbq_base_dma = %llx\n", - (unsigned long long) rx_ring->sbq_base_dma); - pr_err("rx_ring->sbq_base_indirect = %p\n", - rx_ring->sbq_base_indirect); - pr_err("rx_ring->sbq_base_indirect_dma = %llx\n", - (unsigned long long) rx_ring->sbq_base_indirect_dma); - pr_err("rx_ring->sbq = %p\n", rx_ring->sbq); - pr_err("rx_ring->sbq_len = %d\n", rx_ring->sbq_len); - pr_err("rx_ring->sbq_size = %d\n", rx_ring->sbq_size); - pr_err("rx_ring->sbq_prod_idx_db_reg addr = %p\n", - rx_ring->sbq_prod_idx_db_reg); - pr_err("rx_ring->sbq_prod_idx = %d\n", rx_ring->sbq_prod_idx); - pr_err("rx_ring->sbq_curr_idx = %d\n", rx_ring->sbq_curr_idx); - pr_err("rx_ring->sbq_clean_idx = %d\n", rx_ring->sbq_clean_idx); - pr_err("rx_ring->sbq_free_cnt = %d\n", rx_ring->sbq_free_cnt); - pr_err("rx_ring->sbq_buf_size = %d\n", rx_ring->sbq_buf_size); + + pr_err("rx_ring->sbq.base = %p\n", rx_ring->sbq.base); + pr_err("rx_ring->sbq.base_dma = %llx\n", + (unsigned long long)rx_ring->sbq.base_dma); + pr_err("rx_ring->sbq.base_indirect = %p\n", + rx_ring->sbq.base_indirect); + pr_err("rx_ring->sbq.base_indirect_dma = %llx\n", + (unsigned long long)rx_ring->sbq.base_indirect_dma); + pr_err("rx_ring->sbq = %p\n", rx_ring->sbq.queue); + pr_err("rx_ring->sbq.prod_idx_db_reg addr = %p\n", + rx_ring->sbq.prod_idx_db_reg); + pr_err("rx_ring->sbq.next_to_use = %d\n", rx_ring->sbq.next_to_use); + pr_err("rx_ring->sbq.next_to_clean = %d\n", rx_ring->sbq.next_to_clean); pr_err("rx_ring->cq_id = %d\n", rx_ring->cq_id); pr_err("rx_ring->irq = %d\n", rx_ring->irq); pr_err("rx_ring->cpu = %d\n", rx_ring->cpu); @@ -1806,7 +1805,7 @@ void ql_dump_hw_cb(struct ql_adapter *qdev, int size, u32 bit, u16 q_id) pr_err("%s: Enter\n", __func__); ptr = kmalloc(size, GFP_ATOMIC); - if (ptr == NULL) + if (!ptr) return; if (ql_write_cfg(qdev, ptr, size, bit, q_id)) { @@ -1992,7 +1991,7 @@ void ql_dump_ib_mac_rsp(struct ib_mac_iocb_rsp *ib_mac_rsp) le16_to_cpu(ib_mac_rsp->vlan_id)); pr_err("flags4 = %s%s%s\n", - ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HV ? "HV " : "", + ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HV ? "HV " : "", ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HS ? "HS " : "", ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HL ? "HL " : ""); diff --git a/drivers/staging/qlge/qlge_main.c b/drivers/staging/qlge/qlge_main.c index 6cae33072496..6ad4515311f7 100644 --- a/drivers/staging/qlge/qlge_main.c +++ b/drivers/staging/qlge/qlge_main.c @@ -167,9 +167,9 @@ void ql_sem_unlock(struct ql_adapter *qdev, u32 sem_mask) int ql_wait_reg_rdy(struct ql_adapter *qdev, u32 reg, u32 bit, u32 err_bit) { u32 temp; - int count = UDELAY_COUNT; + int count; - while (count) { + for (count = 0; count < UDELAY_COUNT; count++) { temp = ql_read32(qdev, reg); /* check for errors */ @@ -181,7 +181,6 @@ int ql_wait_reg_rdy(struct ql_adapter *qdev, u32 reg, u32 bit, u32 err_bit) } else if (temp & bit) return 0; udelay(UDELAY_DELAY); - count--; } netif_alert(qdev, probe, qdev->ndev, "Timed out waiting for reg %x to come ready.\n", reg); @@ -193,17 +192,16 @@ int ql_wait_reg_rdy(struct ql_adapter *qdev, u32 reg, u32 bit, u32 err_bit) */ static int ql_wait_cfg(struct ql_adapter *qdev, u32 bit) { - int count = UDELAY_COUNT; + int count; u32 temp; - while (count) { + for (count = 0; count < UDELAY_COUNT; count++) { temp = ql_read32(qdev, CFG); if (temp & CFG_LE) return -EIO; if (!(temp & bit)) return 0; udelay(UDELAY_DELAY); - count--; } return -ETIMEDOUT; } @@ -625,75 +623,26 @@ static void ql_disable_interrupts(struct ql_adapter *qdev) ql_write32(qdev, INTR_EN, (INTR_EN_EI << 16)); } -/* If we're running with multiple MSI-X vectors then we enable on the fly. - * Otherwise, we may have multiple outstanding workers and don't want to - * enable until the last one finishes. In this case, the irq_cnt gets - * incremented every time we queue a worker and decremented every time - * a worker finishes. Once it hits zero we enable the interrupt. - */ -u32 ql_enable_completion_interrupt(struct ql_adapter *qdev, u32 intr) +static void ql_enable_completion_interrupt(struct ql_adapter *qdev, u32 intr) { - u32 var = 0; - unsigned long hw_flags = 0; - struct intr_context *ctx = qdev->intr_context + intr; - - if (likely(test_bit(QL_MSIX_ENABLED, &qdev->flags) && intr)) { - /* Always enable if we're MSIX multi interrupts and - * it's not the default (zeroeth) interrupt. - */ - ql_write32(qdev, INTR_EN, - ctx->intr_en_mask); - var = ql_read32(qdev, STS); - return var; - } + struct intr_context *ctx = &qdev->intr_context[intr]; - spin_lock_irqsave(&qdev->hw_lock, hw_flags); - if (atomic_dec_and_test(&ctx->irq_cnt)) { - ql_write32(qdev, INTR_EN, - ctx->intr_en_mask); - var = ql_read32(qdev, STS); - } - spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); - return var; + ql_write32(qdev, INTR_EN, ctx->intr_en_mask); } -static u32 ql_disable_completion_interrupt(struct ql_adapter *qdev, u32 intr) +static void ql_disable_completion_interrupt(struct ql_adapter *qdev, u32 intr) { - u32 var = 0; - struct intr_context *ctx; - - /* HW disables for us if we're MSIX multi interrupts and - * it's not the default (zeroeth) interrupt. - */ - if (likely(test_bit(QL_MSIX_ENABLED, &qdev->flags) && intr)) - return 0; + struct intr_context *ctx = &qdev->intr_context[intr]; - ctx = qdev->intr_context + intr; - spin_lock(&qdev->hw_lock); - if (!atomic_read(&ctx->irq_cnt)) { - ql_write32(qdev, INTR_EN, - ctx->intr_dis_mask); - var = ql_read32(qdev, STS); - } - atomic_inc(&ctx->irq_cnt); - spin_unlock(&qdev->hw_lock); - return var; + ql_write32(qdev, INTR_EN, ctx->intr_dis_mask); } static void ql_enable_all_completion_interrupts(struct ql_adapter *qdev) { int i; - for (i = 0; i < qdev->intr_count; i++) { - /* The enable call does a atomic_dec_and_test - * and enables only if the result is zero. - * So we precharge it here. - */ - if (unlikely(!test_bit(QL_MSIX_ENABLED, &qdev->flags) || - i == 0)) - atomic_set(&qdev->intr_context[i].irq_cnt, 1); - ql_enable_completion_interrupt(qdev, i); - } + for (i = 0; i < qdev->intr_count; i++) + ql_enable_completion_interrupt(qdev, i); } static int ql_validate_flash(struct ql_adapter *qdev, u32 size, const char *str) @@ -1027,48 +976,32 @@ static inline unsigned int ql_lbq_block_size(struct ql_adapter *qdev) return PAGE_SIZE << qdev->lbq_buf_order; } -/* Get the next large buffer. */ -static struct bq_desc *ql_get_curr_lbuf(struct rx_ring *rx_ring) +static struct qlge_bq_desc *qlge_get_curr_buf(struct qlge_bq *bq) { - struct bq_desc *lbq_desc = &rx_ring->lbq[rx_ring->lbq_curr_idx]; - rx_ring->lbq_curr_idx++; - if (rx_ring->lbq_curr_idx == rx_ring->lbq_len) - rx_ring->lbq_curr_idx = 0; - rx_ring->lbq_free_cnt++; - return lbq_desc; + struct qlge_bq_desc *bq_desc; + + bq_desc = &bq->queue[bq->next_to_clean]; + bq->next_to_clean = QLGE_BQ_WRAP(bq->next_to_clean + 1); + + return bq_desc; } -static struct bq_desc *ql_get_curr_lchunk(struct ql_adapter *qdev, - struct rx_ring *rx_ring) +static struct qlge_bq_desc *ql_get_curr_lchunk(struct ql_adapter *qdev, + struct rx_ring *rx_ring) { - struct bq_desc *lbq_desc = ql_get_curr_lbuf(rx_ring); + struct qlge_bq_desc *lbq_desc = qlge_get_curr_buf(&rx_ring->lbq); - pci_dma_sync_single_for_cpu(qdev->pdev, - dma_unmap_addr(lbq_desc, mapaddr), - rx_ring->lbq_buf_size, - PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(qdev->pdev, lbq_desc->dma_addr, + qdev->lbq_buf_size, PCI_DMA_FROMDEVICE); - /* If it's the last chunk of our master page then - * we unmap it. - */ - if ((lbq_desc->p.pg_chunk.offset + rx_ring->lbq_buf_size) - == ql_lbq_block_size(qdev)) - pci_unmap_page(qdev->pdev, - lbq_desc->p.pg_chunk.map, - ql_lbq_block_size(qdev), - PCI_DMA_FROMDEVICE); - return lbq_desc; -} + if ((lbq_desc->p.pg_chunk.offset + qdev->lbq_buf_size) == + ql_lbq_block_size(qdev)) { + /* last chunk of the master page */ + pci_unmap_page(qdev->pdev, lbq_desc->dma_addr, + ql_lbq_block_size(qdev), PCI_DMA_FROMDEVICE); + } -/* Get the next small buffer. */ -static struct bq_desc *ql_get_curr_sbuf(struct rx_ring *rx_ring) -{ - struct bq_desc *sbq_desc = &rx_ring->sbq[rx_ring->sbq_curr_idx]; - rx_ring->sbq_curr_idx++; - if (rx_ring->sbq_curr_idx == rx_ring->sbq_len) - rx_ring->sbq_curr_idx = 0; - rx_ring->sbq_free_cnt++; - return sbq_desc; + return lbq_desc; } /* Update an rx ring index. */ @@ -1087,178 +1020,192 @@ static void ql_write_cq_idx(struct rx_ring *rx_ring) ql_write_db_reg(rx_ring->cnsmr_idx, rx_ring->cnsmr_idx_db_reg); } -static int ql_get_next_chunk(struct ql_adapter *qdev, struct rx_ring *rx_ring, - struct bq_desc *lbq_desc) +static const char * const bq_type_name[] = { + [QLGE_SB] = "sbq", + [QLGE_LB] = "lbq", +}; + +/* return 0 or negative error */ +static int qlge_refill_sb(struct rx_ring *rx_ring, + struct qlge_bq_desc *sbq_desc, gfp_t gfp) { - if (!rx_ring->pg_chunk.page) { - u64 map; - rx_ring->pg_chunk.page = alloc_pages(__GFP_COMP | GFP_ATOMIC, - qdev->lbq_buf_order); - if (unlikely(!rx_ring->pg_chunk.page)) { - netif_err(qdev, drv, qdev->ndev, - "page allocation failed.\n"); + struct ql_adapter *qdev = rx_ring->qdev; + struct sk_buff *skb; + + if (sbq_desc->p.skb) + return 0; + + netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, + "ring %u sbq: getting new skb for index %d.\n", + rx_ring->cq_id, sbq_desc->index); + + skb = __netdev_alloc_skb(qdev->ndev, SMALL_BUFFER_SIZE, gfp); + if (!skb) + return -ENOMEM; + skb_reserve(skb, QLGE_SB_PAD); + + sbq_desc->dma_addr = pci_map_single(qdev->pdev, skb->data, + SMALL_BUF_MAP_SIZE, + PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(qdev->pdev, sbq_desc->dma_addr)) { + netif_err(qdev, ifup, qdev->ndev, "PCI mapping failed.\n"); + dev_kfree_skb_any(skb); + return -EIO; + } + *sbq_desc->buf_ptr = cpu_to_le64(sbq_desc->dma_addr); + + sbq_desc->p.skb = skb; + return 0; +} + +/* return 0 or negative error */ +static int qlge_refill_lb(struct rx_ring *rx_ring, + struct qlge_bq_desc *lbq_desc, gfp_t gfp) +{ + struct ql_adapter *qdev = rx_ring->qdev; + struct qlge_page_chunk *master_chunk = &rx_ring->master_chunk; + + if (!master_chunk->page) { + struct page *page; + dma_addr_t dma_addr; + + page = alloc_pages(gfp | __GFP_COMP, qdev->lbq_buf_order); + if (unlikely(!page)) return -ENOMEM; - } - rx_ring->pg_chunk.offset = 0; - map = pci_map_page(qdev->pdev, rx_ring->pg_chunk.page, - 0, ql_lbq_block_size(qdev), + dma_addr = pci_map_page(qdev->pdev, page, 0, + ql_lbq_block_size(qdev), PCI_DMA_FROMDEVICE); - if (pci_dma_mapping_error(qdev->pdev, map)) { - __free_pages(rx_ring->pg_chunk.page, - qdev->lbq_buf_order); - rx_ring->pg_chunk.page = NULL; + if (pci_dma_mapping_error(qdev->pdev, dma_addr)) { + __free_pages(page, qdev->lbq_buf_order); netif_err(qdev, drv, qdev->ndev, "PCI mapping failed.\n"); - return -ENOMEM; + return -EIO; } - rx_ring->pg_chunk.map = map; - rx_ring->pg_chunk.va = page_address(rx_ring->pg_chunk.page); + master_chunk->page = page; + master_chunk->va = page_address(page); + master_chunk->offset = 0; + rx_ring->chunk_dma_addr = dma_addr; } - /* Copy the current master pg_chunk info - * to the current descriptor. - */ - lbq_desc->p.pg_chunk = rx_ring->pg_chunk; + lbq_desc->p.pg_chunk = *master_chunk; + lbq_desc->dma_addr = rx_ring->chunk_dma_addr; + *lbq_desc->buf_ptr = cpu_to_le64(lbq_desc->dma_addr + + lbq_desc->p.pg_chunk.offset); /* Adjust the master page chunk for next * buffer get. */ - rx_ring->pg_chunk.offset += rx_ring->lbq_buf_size; - if (rx_ring->pg_chunk.offset == ql_lbq_block_size(qdev)) { - rx_ring->pg_chunk.page = NULL; - lbq_desc->p.pg_chunk.last_flag = 1; + master_chunk->offset += qdev->lbq_buf_size; + if (master_chunk->offset == ql_lbq_block_size(qdev)) { + master_chunk->page = NULL; } else { - rx_ring->pg_chunk.va += rx_ring->lbq_buf_size; - get_page(rx_ring->pg_chunk.page); - lbq_desc->p.pg_chunk.last_flag = 0; + master_chunk->va += qdev->lbq_buf_size; + get_page(master_chunk->page); } + return 0; } -/* Process (refill) a large buffer queue. */ -static void ql_update_lbq(struct ql_adapter *qdev, struct rx_ring *rx_ring) + +/* return 0 or negative error */ +static int qlge_refill_bq(struct qlge_bq *bq, gfp_t gfp) { - u32 clean_idx = rx_ring->lbq_clean_idx; - u32 start_idx = clean_idx; - struct bq_desc *lbq_desc; - u64 map; + struct rx_ring *rx_ring = QLGE_BQ_CONTAINER(bq); + struct ql_adapter *qdev = rx_ring->qdev; + struct qlge_bq_desc *bq_desc; + int refill_count; + int retval; int i; - while (rx_ring->lbq_free_cnt > 32) { - for (i = (rx_ring->lbq_clean_idx % 16); i < 16; i++) { - netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, - "lbq: try cleaning clean_idx = %d.\n", - clean_idx); - lbq_desc = &rx_ring->lbq[clean_idx]; - if (ql_get_next_chunk(qdev, rx_ring, lbq_desc)) { - rx_ring->lbq_clean_idx = clean_idx; - netif_err(qdev, ifup, qdev->ndev, - "Could not get a page chunk, i=%d, clean_idx =%d .\n", - i, clean_idx); - return; - } + refill_count = QLGE_BQ_WRAP(QLGE_BQ_ALIGN(bq->next_to_clean - 1) - + bq->next_to_use); + if (!refill_count) + return 0; + + i = bq->next_to_use; + bq_desc = &bq->queue[i]; + i -= QLGE_BQ_LEN; + do { + netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, + "ring %u %s: try cleaning idx %d\n", + rx_ring->cq_id, bq_type_name[bq->type], i); - map = lbq_desc->p.pg_chunk.map + - lbq_desc->p.pg_chunk.offset; - dma_unmap_addr_set(lbq_desc, mapaddr, map); - dma_unmap_len_set(lbq_desc, maplen, - rx_ring->lbq_buf_size); - *lbq_desc->addr = cpu_to_le64(map); - - pci_dma_sync_single_for_device(qdev->pdev, map, - rx_ring->lbq_buf_size, - PCI_DMA_FROMDEVICE); - clean_idx++; - if (clean_idx == rx_ring->lbq_len) - clean_idx = 0; + if (bq->type == QLGE_SB) + retval = qlge_refill_sb(rx_ring, bq_desc, gfp); + else + retval = qlge_refill_lb(rx_ring, bq_desc, gfp); + if (retval < 0) { + netif_err(qdev, ifup, qdev->ndev, + "ring %u %s: Could not get a page chunk, idx %d\n", + rx_ring->cq_id, bq_type_name[bq->type], i); + break; } - rx_ring->lbq_clean_idx = clean_idx; - rx_ring->lbq_prod_idx += 16; - if (rx_ring->lbq_prod_idx == rx_ring->lbq_len) - rx_ring->lbq_prod_idx = 0; - rx_ring->lbq_free_cnt -= 16; - } + bq_desc++; + i++; + if (unlikely(!i)) { + bq_desc = &bq->queue[0]; + i -= QLGE_BQ_LEN; + } + refill_count--; + } while (refill_count); + i += QLGE_BQ_LEN; - if (start_idx != clean_idx) { - netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, - "lbq: updating prod idx = %d.\n", - rx_ring->lbq_prod_idx); - ql_write_db_reg(rx_ring->lbq_prod_idx, - rx_ring->lbq_prod_idx_db_reg); + if (bq->next_to_use != i) { + if (QLGE_BQ_ALIGN(bq->next_to_use) != QLGE_BQ_ALIGN(i)) { + netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, + "ring %u %s: updating prod idx = %d.\n", + rx_ring->cq_id, bq_type_name[bq->type], + i); + ql_write_db_reg(i, bq->prod_idx_db_reg); + } + bq->next_to_use = i; } + + return retval; } -/* Process (refill) a small buffer queue. */ -static void ql_update_sbq(struct ql_adapter *qdev, struct rx_ring *rx_ring) +static void ql_update_buffer_queues(struct rx_ring *rx_ring, gfp_t gfp, + unsigned long delay) { - u32 clean_idx = rx_ring->sbq_clean_idx; - u32 start_idx = clean_idx; - struct bq_desc *sbq_desc; - u64 map; - int i; - - while (rx_ring->sbq_free_cnt > 16) { - for (i = (rx_ring->sbq_clean_idx % 16); i < 16; i++) { - sbq_desc = &rx_ring->sbq[clean_idx]; - netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, - "sbq: try cleaning clean_idx = %d.\n", - clean_idx); - if (sbq_desc->p.skb == NULL) { - netif_printk(qdev, rx_status, KERN_DEBUG, - qdev->ndev, - "sbq: getting new skb for index %d.\n", - sbq_desc->index); - sbq_desc->p.skb = - netdev_alloc_skb(qdev->ndev, - SMALL_BUFFER_SIZE); - if (sbq_desc->p.skb == NULL) { - rx_ring->sbq_clean_idx = clean_idx; - return; - } - skb_reserve(sbq_desc->p.skb, QLGE_SB_PAD); - map = pci_map_single(qdev->pdev, - sbq_desc->p.skb->data, - rx_ring->sbq_buf_size, - PCI_DMA_FROMDEVICE); - if (pci_dma_mapping_error(qdev->pdev, map)) { - netif_err(qdev, ifup, qdev->ndev, - "PCI mapping failed.\n"); - rx_ring->sbq_clean_idx = clean_idx; - dev_kfree_skb_any(sbq_desc->p.skb); - sbq_desc->p.skb = NULL; - return; - } - dma_unmap_addr_set(sbq_desc, mapaddr, map); - dma_unmap_len_set(sbq_desc, maplen, - rx_ring->sbq_buf_size); - *sbq_desc->addr = cpu_to_le64(map); - } + bool sbq_fail, lbq_fail; - clean_idx++; - if (clean_idx == rx_ring->sbq_len) - clean_idx = 0; - } - rx_ring->sbq_clean_idx = clean_idx; - rx_ring->sbq_prod_idx += 16; - if (rx_ring->sbq_prod_idx == rx_ring->sbq_len) - rx_ring->sbq_prod_idx = 0; - rx_ring->sbq_free_cnt -= 16; - } + sbq_fail = !!qlge_refill_bq(&rx_ring->sbq, gfp); + lbq_fail = !!qlge_refill_bq(&rx_ring->lbq, gfp); - if (start_idx != clean_idx) { - netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, - "sbq: updating prod idx = %d.\n", - rx_ring->sbq_prod_idx); - ql_write_db_reg(rx_ring->sbq_prod_idx, - rx_ring->sbq_prod_idx_db_reg); - } + /* Minimum number of buffers needed to be able to receive at least one + * frame of any format: + * sbq: 1 for header + 1 for data + * lbq: mtu 9000 / lb size + * Below this, the queue might stall. + */ + if ((sbq_fail && QLGE_BQ_HW_OWNED(&rx_ring->sbq) < 2) || + (lbq_fail && QLGE_BQ_HW_OWNED(&rx_ring->lbq) < + DIV_ROUND_UP(9000, LARGE_BUFFER_MAX_SIZE))) + /* Allocations can take a long time in certain cases (ex. + * reclaim). Therefore, use a workqueue for long-running + * work items. + */ + queue_delayed_work_on(smp_processor_id(), system_long_wq, + &rx_ring->refill_work, delay); } -static void ql_update_buffer_queues(struct ql_adapter *qdev, - struct rx_ring *rx_ring) +static void qlge_slow_refill(struct work_struct *work) { - ql_update_sbq(qdev, rx_ring); - ql_update_lbq(qdev, rx_ring); + struct rx_ring *rx_ring = container_of(work, struct rx_ring, + refill_work.work); + struct napi_struct *napi = &rx_ring->napi; + + napi_disable(napi); + ql_update_buffer_queues(rx_ring, GFP_KERNEL, HZ / 2); + napi_enable(napi); + + local_bh_disable(); + /* napi_disable() might have prevented incomplete napi work from being + * rescheduled. + */ + napi_schedule(napi); + /* trigger softirq processing */ + local_bh_enable(); } /* Unmaps tx buffers. Can be called from send() if a pci mapping @@ -1495,7 +1442,7 @@ static void ql_process_mac_rx_gro_page(struct ql_adapter *qdev, u16 vlan_id) { struct sk_buff *skb; - struct bq_desc *lbq_desc = ql_get_curr_lchunk(qdev, rx_ring); + struct qlge_bq_desc *lbq_desc = ql_get_curr_lchunk(qdev, rx_ring); struct napi_struct *napi = &rx_ring->napi; /* Frame error, so drop the packet. */ @@ -1544,7 +1491,7 @@ static void ql_process_mac_rx_page(struct ql_adapter *qdev, struct net_device *ndev = qdev->ndev; struct sk_buff *skb = NULL; void *addr; - struct bq_desc *lbq_desc = ql_get_curr_lchunk(qdev, rx_ring); + struct qlge_bq_desc *lbq_desc = ql_get_curr_lchunk(qdev, rx_ring); struct napi_struct *napi = &rx_ring->napi; size_t hlen = ETH_HLEN; @@ -1634,31 +1581,24 @@ static void ql_process_mac_rx_skb(struct ql_adapter *qdev, u32 length, u16 vlan_id) { + struct qlge_bq_desc *sbq_desc = qlge_get_curr_buf(&rx_ring->sbq); struct net_device *ndev = qdev->ndev; - struct sk_buff *skb = NULL; - struct sk_buff *new_skb = NULL; - struct bq_desc *sbq_desc = ql_get_curr_sbuf(rx_ring); + struct sk_buff *skb, *new_skb; skb = sbq_desc->p.skb; /* Allocate new_skb and copy */ new_skb = netdev_alloc_skb(qdev->ndev, length + NET_IP_ALIGN); - if (new_skb == NULL) { + if (!new_skb) { rx_ring->rx_dropped++; return; } skb_reserve(new_skb, NET_IP_ALIGN); - pci_dma_sync_single_for_cpu(qdev->pdev, - dma_unmap_addr(sbq_desc, mapaddr), - dma_unmap_len(sbq_desc, maplen), - PCI_DMA_FROMDEVICE); + pci_dma_sync_single_for_cpu(qdev->pdev, sbq_desc->dma_addr, + SMALL_BUF_MAP_SIZE, PCI_DMA_FROMDEVICE); skb_put_data(new_skb, skb->data, length); - pci_dma_sync_single_for_device(qdev->pdev, - dma_unmap_addr(sbq_desc, mapaddr), - dma_unmap_len(sbq_desc, maplen), - PCI_DMA_FROMDEVICE); skb = new_skb; /* Frame error, so drop the packet. */ @@ -1759,11 +1699,10 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev, struct rx_ring *rx_ring, struct ib_mac_iocb_rsp *ib_mac_rsp) { - struct bq_desc *lbq_desc; - struct bq_desc *sbq_desc; - struct sk_buff *skb = NULL; u32 length = le32_to_cpu(ib_mac_rsp->data_len); u32 hdr_len = le32_to_cpu(ib_mac_rsp->hdr_len); + struct qlge_bq_desc *lbq_desc, *sbq_desc; + struct sk_buff *skb = NULL; size_t hlen = ETH_HLEN; /* @@ -1776,11 +1715,9 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev, /* * Headers fit nicely into a small buffer. */ - sbq_desc = ql_get_curr_sbuf(rx_ring); - pci_unmap_single(qdev->pdev, - dma_unmap_addr(sbq_desc, mapaddr), - dma_unmap_len(sbq_desc, maplen), - PCI_DMA_FROMDEVICE); + sbq_desc = qlge_get_curr_buf(&rx_ring->sbq); + pci_unmap_single(qdev->pdev, sbq_desc->dma_addr, + SMALL_BUF_MAP_SIZE, PCI_DMA_FROMDEVICE); skb = sbq_desc->p.skb; ql_realign_skb(skb, hdr_len); skb_put(skb, hdr_len); @@ -1808,35 +1745,22 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev, * from the "data" small buffer to the "header" small * buffer. */ - sbq_desc = ql_get_curr_sbuf(rx_ring); + sbq_desc = qlge_get_curr_buf(&rx_ring->sbq); pci_dma_sync_single_for_cpu(qdev->pdev, - dma_unmap_addr - (sbq_desc, mapaddr), - dma_unmap_len - (sbq_desc, maplen), + sbq_desc->dma_addr, + SMALL_BUF_MAP_SIZE, PCI_DMA_FROMDEVICE); skb_put_data(skb, sbq_desc->p.skb->data, length); - pci_dma_sync_single_for_device(qdev->pdev, - dma_unmap_addr - (sbq_desc, - mapaddr), - dma_unmap_len - (sbq_desc, - maplen), - PCI_DMA_FROMDEVICE); } else { netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, "%d bytes in a single small buffer.\n", length); - sbq_desc = ql_get_curr_sbuf(rx_ring); + sbq_desc = qlge_get_curr_buf(&rx_ring->sbq); skb = sbq_desc->p.skb; ql_realign_skb(skb, length); skb_put(skb, length); - pci_unmap_single(qdev->pdev, - dma_unmap_addr(sbq_desc, - mapaddr), - dma_unmap_len(sbq_desc, - maplen), + pci_unmap_single(qdev->pdev, sbq_desc->dma_addr, + SMALL_BUF_MAP_SIZE, PCI_DMA_FROMDEVICE); sbq_desc->p.skb = NULL; } @@ -1868,15 +1792,13 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev, */ lbq_desc = ql_get_curr_lchunk(qdev, rx_ring); skb = netdev_alloc_skb(qdev->ndev, length); - if (skb == NULL) { + if (!skb) { netif_printk(qdev, probe, KERN_DEBUG, qdev->ndev, "No skb available, drop the packet.\n"); return NULL; } - pci_unmap_page(qdev->pdev, - dma_unmap_addr(lbq_desc, - mapaddr), - dma_unmap_len(lbq_desc, maplen), + pci_unmap_page(qdev->pdev, lbq_desc->dma_addr, + qdev->lbq_buf_size, PCI_DMA_FROMDEVICE); skb_reserve(skb, NET_IP_ALIGN); netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, @@ -1907,11 +1829,9 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev, * eventually be in trouble. */ int size, i = 0; - sbq_desc = ql_get_curr_sbuf(rx_ring); - pci_unmap_single(qdev->pdev, - dma_unmap_addr(sbq_desc, mapaddr), - dma_unmap_len(sbq_desc, maplen), - PCI_DMA_FROMDEVICE); + sbq_desc = qlge_get_curr_buf(&rx_ring->sbq); + pci_unmap_single(qdev->pdev, sbq_desc->dma_addr, + SMALL_BUF_MAP_SIZE, PCI_DMA_FROMDEVICE); if (!(ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HS)) { /* * This is an non TCP/UDP IP frame, so @@ -1931,8 +1851,7 @@ static struct sk_buff *ql_build_rx_skb(struct ql_adapter *qdev, } do { lbq_desc = ql_get_curr_lchunk(qdev, rx_ring); - size = (length < rx_ring->lbq_buf_size) ? length : - rx_ring->lbq_buf_size; + size = min(length, qdev->lbq_buf_size); netif_printk(qdev, rx_status, KERN_DEBUG, qdev->ndev, "Adding page %d to skb for %d bytes.\n", @@ -2286,7 +2205,7 @@ static int ql_clean_inbound_rx_ring(struct rx_ring *rx_ring, int budget) if (count == budget) break; } - ql_update_buffer_queues(qdev, rx_ring); + ql_update_buffer_queues(rx_ring, GFP_ATOMIC, 0); ql_write_cq_idx(rx_ring); return count; } @@ -2500,21 +2419,22 @@ static irqreturn_t qlge_isr(int irq, void *dev_id) u32 var; int work_done = 0; - spin_lock(&qdev->hw_lock); - if (atomic_read(&qdev->intr_context[0].irq_cnt)) { - netif_printk(qdev, intr, KERN_DEBUG, qdev->ndev, - "Shared Interrupt, Not ours!\n"); - spin_unlock(&qdev->hw_lock); - return IRQ_NONE; - } - spin_unlock(&qdev->hw_lock); + /* Experience shows that when using INTx interrupts, interrupts must + * be masked manually. + * When using MSI mode, INTR_EN_EN must be explicitly disabled + * (even though it is auto-masked), otherwise a later command to + * enable it is not effective. + */ + if (!test_bit(QL_MSIX_ENABLED, &qdev->flags)) + ql_disable_completion_interrupt(qdev, 0); - var = ql_disable_completion_interrupt(qdev, intr_context->intr); + var = ql_read32(qdev, STS); /* * Check for fatal error. */ if (var & STS_FE) { + ql_disable_completion_interrupt(qdev, 0); ql_queue_asic_error(qdev); netdev_err(qdev->ndev, "Got fatal error, STS = %x.\n", var); var = ql_read32(qdev, ERR_STS); @@ -2534,7 +2454,6 @@ static irqreturn_t qlge_isr(int irq, void *dev_id) */ netif_err(qdev, intr, qdev->ndev, "Got MPI processor interrupt.\n"); - ql_disable_completion_interrupt(qdev, intr_context->intr); ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16)); queue_delayed_work_on(smp_processor_id(), qdev->workqueue, &qdev->mpi_work, 0); @@ -2550,11 +2469,18 @@ static irqreturn_t qlge_isr(int irq, void *dev_id) if (var & intr_context->irq_mask) { netif_info(qdev, intr, qdev->ndev, "Waking handler for rx_ring[0].\n"); - ql_disable_completion_interrupt(qdev, intr_context->intr); napi_schedule(&rx_ring->napi); work_done++; + } else { + /* Experience shows that the device sometimes signals an + * interrupt but no work is scheduled from this function. + * Nevertheless, the interrupt is auto-masked. Therefore, we + * systematically re-enable the interrupt if we didn't + * schedule napi. + */ + ql_enable_completion_interrupt(qdev, 0); } - ql_enable_completion_interrupt(qdev, intr_context->intr); + return work_done ? IRQ_HANDLED : IRQ_NONE; } @@ -2737,7 +2663,7 @@ static int ql_alloc_shadow_space(struct ql_adapter *qdev) qdev->rx_ring_shadow_reg_area = pci_zalloc_consistent(qdev->pdev, PAGE_SIZE, &qdev->rx_ring_shadow_reg_dma); - if (qdev->rx_ring_shadow_reg_area == NULL) { + if (!qdev->rx_ring_shadow_reg_area) { netif_err(qdev, ifup, qdev->ndev, "Allocation of RX shadow space failed.\n"); return -ENOMEM; @@ -2746,7 +2672,7 @@ static int ql_alloc_shadow_space(struct ql_adapter *qdev) qdev->tx_ring_shadow_reg_area = pci_zalloc_consistent(qdev->pdev, PAGE_SIZE, &qdev->tx_ring_shadow_reg_dma); - if (qdev->tx_ring_shadow_reg_area == NULL) { + if (!qdev->tx_ring_shadow_reg_area) { netif_err(qdev, ifup, qdev->ndev, "Allocation of TX shadow space failed.\n"); goto err_wqp_sh_area; @@ -2798,14 +2724,14 @@ static int ql_alloc_tx_resources(struct ql_adapter *qdev, pci_alloc_consistent(qdev->pdev, tx_ring->wq_size, &tx_ring->wq_base_dma); - if ((tx_ring->wq_base == NULL) || + if (!tx_ring->wq_base || tx_ring->wq_base_dma & WQ_ADDR_ALIGN) goto pci_alloc_err; tx_ring->q = kmalloc_array(tx_ring->wq_len, sizeof(struct tx_ring_desc), GFP_KERNEL); - if (tx_ring->q == NULL) + if (!tx_ring->q) goto err; return 0; @@ -2820,54 +2746,46 @@ pci_alloc_err: static void ql_free_lbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring) { - struct bq_desc *lbq_desc; + struct qlge_bq *lbq = &rx_ring->lbq; + unsigned int last_offset; - uint32_t curr_idx, clean_idx; + last_offset = ql_lbq_block_size(qdev) - qdev->lbq_buf_size; + while (lbq->next_to_clean != lbq->next_to_use) { + struct qlge_bq_desc *lbq_desc = + &lbq->queue[lbq->next_to_clean]; - curr_idx = rx_ring->lbq_curr_idx; - clean_idx = rx_ring->lbq_clean_idx; - while (curr_idx != clean_idx) { - lbq_desc = &rx_ring->lbq[curr_idx]; - - if (lbq_desc->p.pg_chunk.last_flag) { - pci_unmap_page(qdev->pdev, - lbq_desc->p.pg_chunk.map, - ql_lbq_block_size(qdev), + if (lbq_desc->p.pg_chunk.offset == last_offset) + pci_unmap_page(qdev->pdev, lbq_desc->dma_addr, + ql_lbq_block_size(qdev), PCI_DMA_FROMDEVICE); - lbq_desc->p.pg_chunk.last_flag = 0; - } - put_page(lbq_desc->p.pg_chunk.page); - lbq_desc->p.pg_chunk.page = NULL; - - if (++curr_idx == rx_ring->lbq_len) - curr_idx = 0; + lbq->next_to_clean = QLGE_BQ_WRAP(lbq->next_to_clean + 1); } - if (rx_ring->pg_chunk.page) { - pci_unmap_page(qdev->pdev, rx_ring->pg_chunk.map, - ql_lbq_block_size(qdev), PCI_DMA_FROMDEVICE); - put_page(rx_ring->pg_chunk.page); - rx_ring->pg_chunk.page = NULL; + + if (rx_ring->master_chunk.page) { + pci_unmap_page(qdev->pdev, rx_ring->chunk_dma_addr, + ql_lbq_block_size(qdev), PCI_DMA_FROMDEVICE); + put_page(rx_ring->master_chunk.page); + rx_ring->master_chunk.page = NULL; } } static void ql_free_sbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring) { int i; - struct bq_desc *sbq_desc; - for (i = 0; i < rx_ring->sbq_len; i++) { - sbq_desc = &rx_ring->sbq[i]; - if (sbq_desc == NULL) { + for (i = 0; i < QLGE_BQ_LEN; i++) { + struct qlge_bq_desc *sbq_desc = &rx_ring->sbq.queue[i]; + + if (!sbq_desc) { netif_err(qdev, ifup, qdev->ndev, "sbq_desc %d is NULL.\n", i); return; } if (sbq_desc->p.skb) { - pci_unmap_single(qdev->pdev, - dma_unmap_addr(sbq_desc, mapaddr), - dma_unmap_len(sbq_desc, maplen), + pci_unmap_single(qdev->pdev, sbq_desc->dma_addr, + SMALL_BUF_MAP_SIZE, PCI_DMA_FROMDEVICE); dev_kfree_skb(sbq_desc->p.skb); sbq_desc->p.skb = NULL; @@ -2881,89 +2799,83 @@ static void ql_free_sbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring static void ql_free_rx_buffers(struct ql_adapter *qdev) { int i; - struct rx_ring *rx_ring; for (i = 0; i < qdev->rx_ring_count; i++) { - rx_ring = &qdev->rx_ring[i]; - if (rx_ring->lbq) + struct rx_ring *rx_ring = &qdev->rx_ring[i]; + + if (rx_ring->lbq.queue) ql_free_lbq_buffers(qdev, rx_ring); - if (rx_ring->sbq) + if (rx_ring->sbq.queue) ql_free_sbq_buffers(qdev, rx_ring); } } static void ql_alloc_rx_buffers(struct ql_adapter *qdev) { - struct rx_ring *rx_ring; int i; - for (i = 0; i < qdev->rx_ring_count; i++) { - rx_ring = &qdev->rx_ring[i]; - if (rx_ring->type != TX_Q) - ql_update_buffer_queues(qdev, rx_ring); - } + for (i = 0; i < qdev->rss_ring_count; i++) + ql_update_buffer_queues(&qdev->rx_ring[i], GFP_KERNEL, + HZ / 2); } -static void ql_init_lbq_ring(struct ql_adapter *qdev, - struct rx_ring *rx_ring) +static int qlge_init_bq(struct qlge_bq *bq) { + struct rx_ring *rx_ring = QLGE_BQ_CONTAINER(bq); + struct ql_adapter *qdev = rx_ring->qdev; + struct qlge_bq_desc *bq_desc; + __le64 *buf_ptr; int i; - struct bq_desc *lbq_desc; - __le64 *bq = rx_ring->lbq_base; - memset(rx_ring->lbq, 0, rx_ring->lbq_len * sizeof(struct bq_desc)); - for (i = 0; i < rx_ring->lbq_len; i++) { - lbq_desc = &rx_ring->lbq[i]; - memset(lbq_desc, 0, sizeof(*lbq_desc)); - lbq_desc->index = i; - lbq_desc->addr = bq; - bq++; + bq->base = pci_alloc_consistent(qdev->pdev, QLGE_BQ_SIZE, + &bq->base_dma); + if (!bq->base) { + netif_err(qdev, ifup, qdev->ndev, + "ring %u %s allocation failed.\n", rx_ring->cq_id, + bq_type_name[bq->type]); + return -ENOMEM; } -} -static void ql_init_sbq_ring(struct ql_adapter *qdev, - struct rx_ring *rx_ring) -{ - int i; - struct bq_desc *sbq_desc; - __le64 *bq = rx_ring->sbq_base; + bq->queue = kmalloc_array(QLGE_BQ_LEN, sizeof(struct qlge_bq_desc), + GFP_KERNEL); + if (!bq->queue) + return -ENOMEM; - memset(rx_ring->sbq, 0, rx_ring->sbq_len * sizeof(struct bq_desc)); - for (i = 0; i < rx_ring->sbq_len; i++) { - sbq_desc = &rx_ring->sbq[i]; - memset(sbq_desc, 0, sizeof(*sbq_desc)); - sbq_desc->index = i; - sbq_desc->addr = bq; - bq++; + buf_ptr = bq->base; + bq_desc = &bq->queue[0]; + for (i = 0; i < QLGE_BQ_LEN; i++, buf_ptr++, bq_desc++) { + bq_desc->p.skb = NULL; + bq_desc->index = i; + bq_desc->buf_ptr = buf_ptr; } + + return 0; } static void ql_free_rx_resources(struct ql_adapter *qdev, struct rx_ring *rx_ring) { /* Free the small buffer queue. */ - if (rx_ring->sbq_base) { - pci_free_consistent(qdev->pdev, - rx_ring->sbq_size, - rx_ring->sbq_base, rx_ring->sbq_base_dma); - rx_ring->sbq_base = NULL; + if (rx_ring->sbq.base) { + pci_free_consistent(qdev->pdev, QLGE_BQ_SIZE, + rx_ring->sbq.base, rx_ring->sbq.base_dma); + rx_ring->sbq.base = NULL; } /* Free the small buffer queue control blocks. */ - kfree(rx_ring->sbq); - rx_ring->sbq = NULL; + kfree(rx_ring->sbq.queue); + rx_ring->sbq.queue = NULL; /* Free the large buffer queue. */ - if (rx_ring->lbq_base) { - pci_free_consistent(qdev->pdev, - rx_ring->lbq_size, - rx_ring->lbq_base, rx_ring->lbq_base_dma); - rx_ring->lbq_base = NULL; + if (rx_ring->lbq.base) { + pci_free_consistent(qdev->pdev, QLGE_BQ_SIZE, + rx_ring->lbq.base, rx_ring->lbq.base_dma); + rx_ring->lbq.base = NULL; } /* Free the large buffer queue control blocks. */ - kfree(rx_ring->lbq); - rx_ring->lbq = NULL; + kfree(rx_ring->lbq.queue); + rx_ring->lbq.queue = NULL; /* Free the rx queue. */ if (rx_ring->cq_base) { @@ -2987,67 +2899,18 @@ static int ql_alloc_rx_resources(struct ql_adapter *qdev, pci_alloc_consistent(qdev->pdev, rx_ring->cq_size, &rx_ring->cq_base_dma); - if (rx_ring->cq_base == NULL) { + if (!rx_ring->cq_base) { netif_err(qdev, ifup, qdev->ndev, "rx_ring alloc failed.\n"); return -ENOMEM; } - if (rx_ring->sbq_len) { - /* - * Allocate small buffer queue. - */ - rx_ring->sbq_base = - pci_alloc_consistent(qdev->pdev, rx_ring->sbq_size, - &rx_ring->sbq_base_dma); - - if (rx_ring->sbq_base == NULL) { - netif_err(qdev, ifup, qdev->ndev, - "Small buffer queue allocation failed.\n"); - goto err_mem; - } - - /* - * Allocate small buffer queue control blocks. - */ - rx_ring->sbq = kmalloc_array(rx_ring->sbq_len, - sizeof(struct bq_desc), - GFP_KERNEL); - if (rx_ring->sbq == NULL) - goto err_mem; - - ql_init_sbq_ring(qdev, rx_ring); - } - - if (rx_ring->lbq_len) { - /* - * Allocate large buffer queue. - */ - rx_ring->lbq_base = - pci_alloc_consistent(qdev->pdev, rx_ring->lbq_size, - &rx_ring->lbq_base_dma); - - if (rx_ring->lbq_base == NULL) { - netif_err(qdev, ifup, qdev->ndev, - "Large buffer queue allocation failed.\n"); - goto err_mem; - } - /* - * Allocate large buffer queue control blocks. - */ - rx_ring->lbq = kmalloc_array(rx_ring->lbq_len, - sizeof(struct bq_desc), - GFP_KERNEL); - if (rx_ring->lbq == NULL) - goto err_mem; - - ql_init_lbq_ring(qdev, rx_ring); + if (rx_ring->cq_id < qdev->rss_ring_count && + (qlge_init_bq(&rx_ring->sbq) || qlge_init_bq(&rx_ring->lbq))) { + ql_free_rx_resources(qdev, rx_ring); + return -ENOMEM; } return 0; - -err_mem: - ql_free_rx_resources(qdev, rx_ring); - return -ENOMEM; } static void ql_tx_ring_clean(struct ql_adapter *qdev) @@ -3133,7 +2996,6 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) void __iomem *doorbell_area = qdev->doorbell_area + (DB_PAGE_SIZE * (128 + rx_ring->cq_id)); int err = 0; - u16 bq_len; u64 tmp; __le64 *base_indirect_ptr; int page_entries; @@ -3144,12 +3006,12 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) *rx_ring->prod_idx_sh_reg = 0; shadow_reg += sizeof(u64); shadow_reg_dma += sizeof(u64); - rx_ring->lbq_base_indirect = shadow_reg; - rx_ring->lbq_base_indirect_dma = shadow_reg_dma; - shadow_reg += (sizeof(u64) * MAX_DB_PAGES_PER_BQ(rx_ring->lbq_len)); - shadow_reg_dma += (sizeof(u64) * MAX_DB_PAGES_PER_BQ(rx_ring->lbq_len)); - rx_ring->sbq_base_indirect = shadow_reg; - rx_ring->sbq_base_indirect_dma = shadow_reg_dma; + rx_ring->lbq.base_indirect = shadow_reg; + rx_ring->lbq.base_indirect_dma = shadow_reg_dma; + shadow_reg += (sizeof(u64) * MAX_DB_PAGES_PER_BQ(QLGE_BQ_LEN)); + shadow_reg_dma += (sizeof(u64) * MAX_DB_PAGES_PER_BQ(QLGE_BQ_LEN)); + rx_ring->sbq.base_indirect = shadow_reg; + rx_ring->sbq.base_indirect_dma = shadow_reg_dma; /* PCI doorbell mem area + 0x00 for consumer index register */ rx_ring->cnsmr_idx_db_reg = (u32 __iomem *) doorbell_area; @@ -3160,16 +3022,16 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) rx_ring->valid_db_reg = doorbell_area + 0x04; /* PCI doorbell mem area + 0x18 for large buffer consumer */ - rx_ring->lbq_prod_idx_db_reg = (u32 __iomem *) (doorbell_area + 0x18); + rx_ring->lbq.prod_idx_db_reg = (u32 __iomem *)(doorbell_area + 0x18); /* PCI doorbell mem area + 0x1c */ - rx_ring->sbq_prod_idx_db_reg = (u32 __iomem *) (doorbell_area + 0x1c); + rx_ring->sbq.prod_idx_db_reg = (u32 __iomem *)(doorbell_area + 0x1c); memset((void *)cqicb, 0, sizeof(struct cqicb)); cqicb->msix_vect = rx_ring->irq; - bq_len = (rx_ring->cq_len == 65536) ? 0 : (u16) rx_ring->cq_len; - cqicb->len = cpu_to_le16(bq_len | LEN_V | LEN_CPP_CONT); + cqicb->len = cpu_to_le16(QLGE_FIT16(rx_ring->cq_len) | LEN_V | + LEN_CPP_CONT); cqicb->addr = cpu_to_le64(rx_ring->cq_base_dma); @@ -3181,59 +3043,42 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) cqicb->flags = FLAGS_LC | /* Load queue base address */ FLAGS_LV | /* Load MSI-X vector */ FLAGS_LI; /* Load irq delay values */ - if (rx_ring->lbq_len) { + if (rx_ring->cq_id < qdev->rss_ring_count) { cqicb->flags |= FLAGS_LL; /* Load lbq values */ - tmp = (u64)rx_ring->lbq_base_dma; - base_indirect_ptr = rx_ring->lbq_base_indirect; + tmp = (u64)rx_ring->lbq.base_dma; + base_indirect_ptr = rx_ring->lbq.base_indirect; page_entries = 0; do { *base_indirect_ptr = cpu_to_le64(tmp); tmp += DB_PAGE_SIZE; base_indirect_ptr++; page_entries++; - } while (page_entries < MAX_DB_PAGES_PER_BQ(rx_ring->lbq_len)); - cqicb->lbq_addr = - cpu_to_le64(rx_ring->lbq_base_indirect_dma); - bq_len = (rx_ring->lbq_buf_size == 65536) ? 0 : - (u16) rx_ring->lbq_buf_size; - cqicb->lbq_buf_size = cpu_to_le16(bq_len); - bq_len = (rx_ring->lbq_len == 65536) ? 0 : - (u16) rx_ring->lbq_len; - cqicb->lbq_len = cpu_to_le16(bq_len); - rx_ring->lbq_prod_idx = 0; - rx_ring->lbq_curr_idx = 0; - rx_ring->lbq_clean_idx = 0; - rx_ring->lbq_free_cnt = rx_ring->lbq_len; - } - if (rx_ring->sbq_len) { + } while (page_entries < MAX_DB_PAGES_PER_BQ(QLGE_BQ_LEN)); + cqicb->lbq_addr = cpu_to_le64(rx_ring->lbq.base_indirect_dma); + cqicb->lbq_buf_size = + cpu_to_le16(QLGE_FIT16(qdev->lbq_buf_size)); + cqicb->lbq_len = cpu_to_le16(QLGE_FIT16(QLGE_BQ_LEN)); + rx_ring->lbq.next_to_use = 0; + rx_ring->lbq.next_to_clean = 0; + cqicb->flags |= FLAGS_LS; /* Load sbq values */ - tmp = (u64)rx_ring->sbq_base_dma; - base_indirect_ptr = rx_ring->sbq_base_indirect; + tmp = (u64)rx_ring->sbq.base_dma; + base_indirect_ptr = rx_ring->sbq.base_indirect; page_entries = 0; do { *base_indirect_ptr = cpu_to_le64(tmp); tmp += DB_PAGE_SIZE; base_indirect_ptr++; page_entries++; - } while (page_entries < MAX_DB_PAGES_PER_BQ(rx_ring->sbq_len)); + } while (page_entries < MAX_DB_PAGES_PER_BQ(QLGE_BQ_LEN)); cqicb->sbq_addr = - cpu_to_le64(rx_ring->sbq_base_indirect_dma); - cqicb->sbq_buf_size = - cpu_to_le16((u16)(rx_ring->sbq_buf_size)); - bq_len = (rx_ring->sbq_len == 65536) ? 0 : - (u16) rx_ring->sbq_len; - cqicb->sbq_len = cpu_to_le16(bq_len); - rx_ring->sbq_prod_idx = 0; - rx_ring->sbq_curr_idx = 0; - rx_ring->sbq_clean_idx = 0; - rx_ring->sbq_free_cnt = rx_ring->sbq_len; - } - switch (rx_ring->type) { - case TX_Q: - cqicb->irq_delay = cpu_to_le16(qdev->tx_coalesce_usecs); - cqicb->pkt_delay = cpu_to_le16(qdev->tx_max_coalesced_frames); - break; - case RX_Q: + cpu_to_le64(rx_ring->sbq.base_indirect_dma); + cqicb->sbq_buf_size = cpu_to_le16(SMALL_BUFFER_SIZE); + cqicb->sbq_len = cpu_to_le16(QLGE_FIT16(QLGE_BQ_LEN)); + rx_ring->sbq.next_to_use = 0; + rx_ring->sbq.next_to_clean = 0; + } + if (rx_ring->cq_id < qdev->rss_ring_count) { /* Inbound completion handling rx_rings run in * separate NAPI contexts. */ @@ -3241,10 +3086,9 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) 64); cqicb->irq_delay = cpu_to_le16(qdev->rx_coalesce_usecs); cqicb->pkt_delay = cpu_to_le16(qdev->rx_max_coalesced_frames); - break; - default: - netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev, - "Invalid rx_ring->type = %d.\n", rx_ring->type); + } else { + cqicb->irq_delay = cpu_to_le16(qdev->tx_coalesce_usecs); + cqicb->pkt_delay = cpu_to_le16(qdev->tx_max_coalesced_frames); } err = ql_write_cfg(qdev, cqicb, sizeof(struct cqicb), CFG_LCQ, rx_ring->cq_id); @@ -3366,6 +3210,7 @@ msi: } } qlge_irq_type = LEG_IRQ; + set_bit(QL_LEGACY_ENABLED, &qdev->flags); netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev, "Running with legacy interrupts.\n"); } @@ -3509,6 +3354,16 @@ static void ql_resolve_queues_to_irqs(struct ql_adapter *qdev) intr_context->intr_dis_mask = INTR_EN_TYPE_MASK | INTR_EN_INTR_MASK | INTR_EN_TYPE_DISABLE; + if (test_bit(QL_LEGACY_ENABLED, &qdev->flags)) { + /* Experience shows that when using INTx interrupts, + * the device does not always auto-mask INTR_EN_EN. + * Moreover, masking INTR_EN_EN manually does not + * immediately prevent interrupt generation. + */ + intr_context->intr_en_mask |= INTR_EN_EI << 16 | + INTR_EN_EI; + intr_context->intr_dis_mask |= INTR_EN_EI << 16; + } intr_context->intr_read_mask = INTR_EN_TYPE_MASK | INTR_EN_INTR_MASK | INTR_EN_TYPE_READ; /* @@ -3557,7 +3412,6 @@ static int ql_request_irq(struct ql_adapter *qdev) ql_resolve_queues_to_irqs(qdev); for (i = 0; i < qdev->intr_count; i++, intr_context++) { - atomic_set(&intr_context->irq_cnt, 0); if (test_bit(QL_MSIX_ENABLED, &qdev->flags)) { status = request_irq(qdev->msi_x_entry[i].vector, intr_context->handler, @@ -3591,12 +3445,7 @@ static int ql_request_irq(struct ql_adapter *qdev) goto err_irq; netif_err(qdev, ifup, qdev->ndev, - "Hooked intr %d, queue type %s, with name %s.\n", - i, - qdev->rx_ring[0].type == DEFAULT_Q ? - "DEFAULT_Q" : - qdev->rx_ring[0].type == TX_Q ? "TX_Q" : - qdev->rx_ring[0].type == RX_Q ? "RX_Q" : "", + "Hooked intr 0, queue type RX_Q, with name %s.\n", intr_context->name); } intr_context->hooked = 1; @@ -4072,6 +3921,7 @@ static int ql_get_adapter_resources(struct ql_adapter *qdev) static int qlge_close(struct net_device *ndev) { struct ql_adapter *qdev = netdev_priv(ndev); + int i; /* If we hit pci_channel_io_perm_failure * failure condition, then we already @@ -4089,21 +3939,31 @@ static int qlge_close(struct net_device *ndev) */ while (!test_bit(QL_ADAPTER_UP, &qdev->flags)) msleep(1); + + /* Make sure refill_work doesn't re-enable napi */ + for (i = 0; i < qdev->rss_ring_count; i++) + cancel_delayed_work_sync(&qdev->rx_ring[i].refill_work); + ql_adapter_down(qdev); ql_release_adapter_resources(qdev); return 0; } +static void qlge_set_lb_size(struct ql_adapter *qdev) +{ + if (qdev->ndev->mtu <= 1500) + qdev->lbq_buf_size = LARGE_BUFFER_MIN_SIZE; + else + qdev->lbq_buf_size = LARGE_BUFFER_MAX_SIZE; + qdev->lbq_buf_order = get_order(qdev->lbq_buf_size); +} + static int ql_configure_rings(struct ql_adapter *qdev) { int i; struct rx_ring *rx_ring; struct tx_ring *tx_ring; int cpu_cnt = min(MAX_CPUS, (int)num_online_cpus()); - unsigned int lbq_buf_len = (qdev->ndev->mtu > 1500) ? - LARGE_BUFFER_MAX_SIZE : LARGE_BUFFER_MIN_SIZE; - - qdev->lbq_buf_order = get_order(lbq_buf_len); /* In a perfect world we have one RSS ring for each CPU * and each has it's own vector. To do that we ask for @@ -4148,15 +4008,10 @@ static int ql_configure_rings(struct ql_adapter *qdev) rx_ring->cq_len = qdev->rx_ring_size; rx_ring->cq_size = rx_ring->cq_len * sizeof(struct ql_net_rsp_iocb); - rx_ring->lbq_len = NUM_LARGE_BUFFERS; - rx_ring->lbq_size = - rx_ring->lbq_len * sizeof(__le64); - rx_ring->lbq_buf_size = (u16)lbq_buf_len; - rx_ring->sbq_len = NUM_SMALL_BUFFERS; - rx_ring->sbq_size = - rx_ring->sbq_len * sizeof(__le64); - rx_ring->sbq_buf_size = SMALL_BUF_MAP_SIZE; - rx_ring->type = RX_Q; + rx_ring->lbq.type = QLGE_LB; + rx_ring->sbq.type = QLGE_SB; + INIT_DELAYED_WORK(&rx_ring->refill_work, + &qlge_slow_refill); } else { /* * Outbound queue handles outbound completions only. @@ -4165,13 +4020,6 @@ static int ql_configure_rings(struct ql_adapter *qdev) rx_ring->cq_len = qdev->tx_ring_size; rx_ring->cq_size = rx_ring->cq_len * sizeof(struct ql_net_rsp_iocb); - rx_ring->lbq_len = 0; - rx_ring->lbq_size = 0; - rx_ring->lbq_buf_size = 0; - rx_ring->sbq_len = 0; - rx_ring->sbq_size = 0; - rx_ring->sbq_buf_size = 0; - rx_ring->type = TX_Q; } } return 0; @@ -4186,6 +4034,7 @@ static int qlge_open(struct net_device *ndev) if (err) return err; + qlge_set_lb_size(qdev); err = ql_configure_rings(qdev); if (err) return err; @@ -4207,9 +4056,7 @@ error_up: static int ql_change_rx_buffers(struct ql_adapter *qdev) { - struct rx_ring *rx_ring; - int i, status; - u32 lbq_buf_len; + int status; /* Wait for an outstanding reset to complete. */ if (!test_bit(QL_ADAPTER_UP, &qdev->flags)) { @@ -4232,16 +4079,7 @@ static int ql_change_rx_buffers(struct ql_adapter *qdev) if (status) goto error; - /* Get the new rx buffer size. */ - lbq_buf_len = (qdev->ndev->mtu > 1500) ? - LARGE_BUFFER_MAX_SIZE : LARGE_BUFFER_MIN_SIZE; - qdev->lbq_buf_order = get_order(lbq_buf_len); - - for (i = 0; i < qdev->rss_ring_count; i++) { - rx_ring = &qdev->rx_ring[i]; - /* Set the new size. */ - rx_ring->lbq_buf_size = lbq_buf_len; - } + qlge_set_lb_size(qdev); status = ql_adapter_up(qdev); if (status) @@ -4642,13 +4480,12 @@ static int ql_init_device(struct pci_dev *pdev, struct net_device *ndev, goto err_out2; } qdev->msg_enable = netif_msg_init(debug, default_msg); - spin_lock_init(&qdev->hw_lock); spin_lock_init(&qdev->stats_lock); if (qlge_mpi_coredump) { qdev->mpi_coredump = vmalloc(sizeof(struct ql_mpi_coredump)); - if (qdev->mpi_coredump == NULL) { + if (!qdev->mpi_coredump) { err = -ENOMEM; goto err_out2; } diff --git a/drivers/staging/qlge/qlge_mpi.c b/drivers/staging/qlge/qlge_mpi.c index 957c72985a06..9e422bbbb6ab 100644 --- a/drivers/staging/qlge/qlge_mpi.c +++ b/drivers/staging/qlge/qlge_mpi.c @@ -1257,7 +1257,6 @@ void ql_mpi_work(struct work_struct *work) /* End polled mode for MPI */ ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16) | INTR_MASK_PI); mutex_unlock(&qdev->mpi_mutex); - ql_enable_completion_interrupt(qdev, 0); } void ql_mpi_reset_work(struct work_struct *work) diff --git a/drivers/staging/ralink-gdma/ralink-gdma.c b/drivers/staging/ralink-gdma/ralink-gdma.c index 900424db9b97..eabf1093328e 100644 --- a/drivers/staging/ralink-gdma/ralink-gdma.c +++ b/drivers/staging/ralink-gdma/ralink-gdma.c @@ -796,7 +796,6 @@ static int gdma_dma_probe(struct platform_device *pdev) struct gdma_dma_dev *dma_dev; struct dma_device *dd; unsigned int i; - struct resource *res; int ret; int irq; void __iomem *base; @@ -818,8 +817,7 @@ static int gdma_dma_probe(struct platform_device *pdev) return -EINVAL; dma_dev->data = data; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); dma_dev->base = base; diff --git a/drivers/staging/rtl8188eu/core/rtw_ap.c b/drivers/staging/rtl8188eu/core/rtw_ap.c index 51a5b71f8c25..88e42cc1d837 100644 --- a/drivers/staging/rtl8188eu/core/rtw_ap.c +++ b/drivers/staging/rtl8188eu/core/rtw_ap.c @@ -440,15 +440,9 @@ static void update_bmc_sta(struct adapter *padapter) tx_ra_bitmap |= rtw_get_bit_value_from_ieee_value(psta->bssrateset[i] & 0x7f); } - if (pcur_network->Configuration.DSConfig > 14) { - /* force to A mode. 5G doesn't support CCK rates */ - network_type = WIRELESS_11A; - tx_ra_bitmap = 0x150; /* 6, 12, 24 Mbps */ - } else { - /* force to b mode */ - network_type = WIRELESS_11B; - tx_ra_bitmap = 0xf; - } + /* force to b mode */ + network_type = WIRELESS_11B; + tx_ra_bitmap = 0xf; raid = networktype_to_raid(network_type); init_rate = get_highest_rate_idx(tx_ra_bitmap & 0x0fffffff) & 0x3f; @@ -560,29 +554,24 @@ void update_sta_info_apmode(struct adapter *padapter, struct sta_info *psta) static void update_hw_ht_param(struct adapter *padapter) { - unsigned char max_AMPDU_len; - unsigned char min_MPDU_spacing; - struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; - struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + u8 max_ampdu_len; + u8 min_mpdu_spacing; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; DBG_88E("%s\n", __func__); - /* handle A-MPDU parameter field */ - /* - ampdu_params_info [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k - ampdu_params_info [4:2]:Min MPDU Start Spacing - */ - max_AMPDU_len = pmlmeinfo->HT_caps.ampdu_params_info & 0x03; - - min_MPDU_spacing = (pmlmeinfo->HT_caps.ampdu_params_info & 0x1c) >> 2; - - rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_MIN_SPACE, (u8 *)(&min_MPDU_spacing)); + /* handle A-MPDU parameter field + * ampdu_params_info [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k + * ampdu_params_info [4:2]:Min MPDU Start Spacing + */ + max_ampdu_len = pmlmeinfo->HT_caps.ampdu_params_info & 0x03; + min_mpdu_spacing = (pmlmeinfo->HT_caps.ampdu_params_info & 0x1c) >> 2; - rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&max_AMPDU_len)); + rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_MIN_SPACE, &min_mpdu_spacing); + rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_FACTOR, &max_ampdu_len); - /* */ - /* Config SM Power Save setting */ - /* */ + /* Config SM Power Save setting */ pmlmeinfo->SM_PS = (le16_to_cpu(pmlmeinfo->HT_caps.cap_info) & 0x0C) >> 2; if (pmlmeinfo->SM_PS == WLAN_HT_CAP_SM_PS_STATIC) DBG_88E("%s(): WLAN_HT_CAP_SM_PS_STATIC\n", __func__); diff --git a/drivers/staging/rtl8188eu/core/rtw_efuse.c b/drivers/staging/rtl8188eu/core/rtw_efuse.c index 02c476f45b33..d9b0f9e6235c 100644 --- a/drivers/staging/rtl8188eu/core/rtw_efuse.c +++ b/drivers/staging/rtl8188eu/core/rtw_efuse.c @@ -25,7 +25,7 @@ enum{ * When we want to enable write operation, we should change to pwr on state. * When we stop write, we should switch to 500k mode and disable LDO 2.5V. */ -void efuse_power_switch(struct adapter *pAdapter, u8 write, u8 pwrstate) +static void efuse_power_switch(struct adapter *pAdapter, u8 write, u8 pwrstate) { u8 tempval; u16 tmpv16; @@ -615,10 +615,9 @@ static bool hal_EfusePgPacketWrite1ByteHeader(struct adapter *pAdapter, u8 efuse static bool hal_EfusePgPacketWriteData(struct adapter *pAdapter, u8 efuseType, u16 *pAddr, struct pgpkt *pTargetPkt) { u16 efuse_addr = *pAddr; - u8 badworden = 0; + u8 badworden; u32 PgWriteSuccess = 0; - badworden = 0x0f; badworden = Efuse_WordEnableDataWrite(pAdapter, efuse_addr + 1, pTargetPkt->word_en, pTargetPkt->data); if (badworden == 0x0F) { /* write ok */ diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme.c b/drivers/staging/rtl8188eu/core/rtw_mlme.c index 1ec3b237212e..e764436e120f 100644 --- a/drivers/staging/rtl8188eu/core/rtw_mlme.c +++ b/drivers/staging/rtl8188eu/core/rtw_mlme.c @@ -2045,9 +2045,9 @@ void _rtw_roaming(struct adapter *padapter, struct wlan_network *tgt_network) while (1) { do_join_r = rtw_do_join(padapter); - if (do_join_r == _SUCCESS) { + if (do_join_r == _SUCCESS) break; - } + DBG_88E("roaming do_join return %d\n", do_join_r); pmlmepriv->to_roaming--; diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c index 18dc9fc1c04a..e984b4605e91 100644 --- a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c @@ -507,7 +507,7 @@ static void issue_probersp(struct adapter *padapter, unsigned char *da) pwps_ie = rtw_get_wps_ie(cur_network->ies+_FIXED_IE_LENGTH_, cur_network->ie_length-_FIXED_IE_LENGTH_, NULL, &wps_ielen); /* inerset & update wps_probe_resp_ie */ - if ((pmlmepriv->wps_probe_resp_ie != NULL) && pwps_ie && (wps_ielen > 0)) { + if (pmlmepriv->wps_probe_resp_ie && pwps_ie && wps_ielen > 0) { uint wps_offset, remainder_ielen; u8 *premainder_ie; diff --git a/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c b/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c index 7b16632048b7..03dc7e5fcc38 100644 --- a/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c +++ b/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c @@ -514,7 +514,7 @@ void rtw_init_pwrctrl_priv(struct adapter *padapter) pwrctrlpriv->power_mgnt = PS_MODE_ACTIVE; else pwrctrlpriv->power_mgnt = padapter->registrypriv.power_mgnt;/* PS_MODE_MIN; */ - pwrctrlpriv->bLeisurePs = (pwrctrlpriv->power_mgnt != PS_MODE_ACTIVE) ? true : false; + pwrctrlpriv->bLeisurePs = (pwrctrlpriv->power_mgnt != PS_MODE_ACTIVE); pwrctrlpriv->bFwCurrentInPSMode = false; @@ -621,7 +621,7 @@ int rtw_pm_set_lps(struct adapter *padapter, u8 mode) else pwrctrlpriv->LpsIdleCount = 2; pwrctrlpriv->power_mgnt = mode; - pwrctrlpriv->bLeisurePs = (pwrctrlpriv->power_mgnt != PS_MODE_ACTIVE) ? true : false; + pwrctrlpriv->bLeisurePs = (pwrctrlpriv->power_mgnt != PS_MODE_ACTIVE); } } else { ret = -EINVAL; diff --git a/drivers/staging/rtl8188eu/core/rtw_sta_mgt.c b/drivers/staging/rtl8188eu/core/rtw_sta_mgt.c index 91a30142c567..73f2cb5ebaa6 100644 --- a/drivers/staging/rtl8188eu/core/rtw_sta_mgt.c +++ b/drivers/staging/rtl8188eu/core/rtw_sta_mgt.c @@ -83,7 +83,8 @@ u32 _rtw_init_sta_priv(struct sta_priv *pstapriv) INIT_LIST_HEAD(&pstapriv->sta_hash[i]); - list_add_tail(&psta->list, get_list_head(&pstapriv->free_sta_queue)); + list_add_tail(&psta->list, + get_list_head(&pstapriv->free_sta_queue)); psta++; } @@ -134,31 +135,30 @@ u32 _rtw_free_sta_priv(struct sta_priv *pstapriv) struct recv_reorder_ctrl *preorder_ctrl; int index; - if (pstapriv) { - /* delete all reordering_ctrl_timer */ - spin_lock_bh(&pstapriv->sta_hash_lock); - for (index = 0; index < NUM_STA; index++) { - phead = &pstapriv->sta_hash[index]; - plist = phead->next; + if (!pstapriv) + return _SUCCESS; - while (phead != plist) { - int i; + /* delete all reordering_ctrl_timer */ + spin_lock_bh(&pstapriv->sta_hash_lock); + for (index = 0; index < NUM_STA; index++) { + phead = &pstapriv->sta_hash[index]; + plist = phead->next; - psta = container_of(plist, struct sta_info, - hash_list); - plist = plist->next; + while (phead != plist) { + int i; - for (i = 0; i < 16; i++) { - preorder_ctrl = &psta->recvreorder_ctrl[i]; - del_timer_sync(&preorder_ctrl->reordering_ctrl_timer); - } + psta = container_of(plist, struct sta_info, hash_list); + plist = plist->next; + + for (i = 0; i < 16; i++) { + preorder_ctrl = &psta->recvreorder_ctrl[i]; + del_timer_sync(&preorder_ctrl->reordering_ctrl_timer); } } - spin_unlock_bh(&pstapriv->sta_hash_lock); - /*===============================*/ - - vfree(pstapriv->pallocated_stainfo_buf); } + spin_unlock_bh(&pstapriv->sta_hash_lock); + + vfree(pstapriv->pallocated_stainfo_buf); return _SUCCESS; } @@ -167,7 +167,7 @@ struct sta_info *rtw_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) { s32 index; struct list_head *phash_list; - struct sta_info *psta; + struct sta_info *psta; struct __queue *pfree_sta_queue; struct recv_reorder_ctrl *preorder_ctrl; int i = 0; @@ -180,65 +180,70 @@ struct sta_info *rtw_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) struct sta_info, list); if (!psta) { spin_unlock_bh(&pfree_sta_queue->lock); - } else { - list_del_init(&psta->list); - spin_unlock_bh(&pfree_sta_queue->lock); - _rtw_init_stainfo(psta); - memcpy(psta->hwaddr, hwaddr, ETH_ALEN); - index = wifi_mac_hash(hwaddr); - RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_info_, ("%s: index=%x", __func__, index)); - if (index >= NUM_STA) { - RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_, ("ERROR => %s: index >= NUM_STA", __func__)); - psta = NULL; - goto exit; - } - phash_list = &pstapriv->sta_hash[index]; - - spin_lock_bh(&pstapriv->sta_hash_lock); - list_add_tail(&psta->hash_list, phash_list); - pstapriv->asoc_sta_count++; - spin_unlock_bh(&pstapriv->sta_hash_lock); + return NULL; + } -/* Commented by Albert 2009/08/13 */ -/* For the SMC router, the sequence number of first packet of WPS handshake will be 0. */ -/* In this case, this packet will be dropped by recv_decache function if we use the 0x00 as the default value for tid_rxseq variable. */ -/* So, we initialize the tid_rxseq variable as the 0xffff. */ + list_del_init(&psta->list); + spin_unlock_bh(&pfree_sta_queue->lock); + _rtw_init_stainfo(psta); + memcpy(psta->hwaddr, hwaddr, ETH_ALEN); + index = wifi_mac_hash(hwaddr); + RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_info_, + ("%s: index=%x", __func__, index)); + if (index >= NUM_STA) { + RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_, + ("ERROR => %s: index >= NUM_STA", __func__)); + return NULL; + } + phash_list = &pstapriv->sta_hash[index]; - for (i = 0; i < 16; i++) - memcpy(&psta->sta_recvpriv.rxcache.tid_rxseq[i], &wRxSeqInitialValue, 2); + spin_lock_bh(&pstapriv->sta_hash_lock); + list_add_tail(&psta->hash_list, phash_list); + pstapriv->asoc_sta_count++; + spin_unlock_bh(&pstapriv->sta_hash_lock); - RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_info_, - ("alloc number_%d stainfo with hwaddr = %pM\n", - pstapriv->asoc_sta_count, hwaddr)); + /* Commented by Albert 2009/08/13 + * For the SMC router, the sequence number of first packet of + * WPS handshake will be 0. In this case, this packet will be + * dropped by recv_decache function if we use the 0x00 as the + * default value for tid_rxseq variable. So, we initialize the + * tid_rxseq variable as the 0xffff. + */ - init_addba_retry_timer(pstapriv->padapter, psta); + for (i = 0; i < 16; i++) + memcpy(&psta->sta_recvpriv.rxcache.tid_rxseq[i], + &wRxSeqInitialValue, 2); - /* for A-MPDU Rx reordering buffer control */ - for (i = 0; i < 16; i++) { - preorder_ctrl = &psta->recvreorder_ctrl[i]; + RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_info_, + ("alloc number_%d stainfo with hwaddr = %pM\n", + pstapriv->asoc_sta_count, hwaddr)); - preorder_ctrl->padapter = pstapriv->padapter; + init_addba_retry_timer(pstapriv->padapter, psta); - preorder_ctrl->enable = false; + /* for A-MPDU Rx reordering buffer control */ + for (i = 0; i < 16; i++) { + preorder_ctrl = &psta->recvreorder_ctrl[i]; - preorder_ctrl->indicate_seq = 0xffff; - preorder_ctrl->wend_b = 0xffff; - preorder_ctrl->wsize_b = 64;/* 64; */ + preorder_ctrl->padapter = pstapriv->padapter; - _rtw_init_queue(&preorder_ctrl->pending_recvframe_queue); + preorder_ctrl->enable = false; - rtw_init_recv_timer(preorder_ctrl); - } + preorder_ctrl->indicate_seq = 0xffff; + preorder_ctrl->wend_b = 0xffff; + preorder_ctrl->wsize_b = 64;/* 64; */ - /* init for DM */ - psta->rssi_stat.UndecoratedSmoothedPWDB = -1; - psta->rssi_stat.UndecoratedSmoothedCCK = -1; + _rtw_init_queue(&preorder_ctrl->pending_recvframe_queue); - /* init for the sequence number of received management frame */ - psta->RxMgmtFrameSeqNum = 0xffff; + rtw_init_recv_timer(preorder_ctrl); } -exit: + /* init for DM */ + psta->rssi_stat.UndecoratedSmoothedPWDB = -1; + psta->rssi_stat.UndecoratedSmoothedCCK = -1; + + /* init for the sequence number of received management frame */ + psta->RxMgmtFrameSeqNum = 0xffff; + return psta; } @@ -296,7 +301,9 @@ u32 rtw_free_stainfo(struct adapter *padapter, struct sta_info *psta) del_timer_sync(&psta->addba_retry_timer); - /* for A-MPDU Rx reordering buffer control, cancel reordering_ctrl_timer */ + /* for A-MPDU Rx reordering buffer control, cancel + * reordering_ctrl_timer + */ for (i = 0; i < 16; i++) { struct list_head *phead, *plist; struct recv_frame *prframe; @@ -311,7 +318,7 @@ u32 rtw_free_stainfo(struct adapter *padapter, struct sta_info *psta) spin_lock_bh(&ppending_recvframe_queue->lock); - phead = get_list_head(ppending_recvframe_queue); + phead = get_list_head(ppending_recvframe_queue); plist = phead->next; while (!list_empty(phead)) { @@ -444,23 +451,21 @@ struct sta_info *rtw_get_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) u32 rtw_init_bcmc_stainfo(struct adapter *padapter) { struct sta_info *psta; - u32 res = _SUCCESS; - unsigned char bcast_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; struct sta_priv *pstapriv = &padapter->stapriv; - psta = rtw_alloc_stainfo(pstapriv, bcast_addr); + psta = rtw_alloc_stainfo(pstapriv, bc_addr); if (!psta) { - res = _FAIL; - RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_, ("rtw_alloc_stainfo fail")); - goto exit; + RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_, + ("rtw_alloc_stainfo fail")); + return _FAIL; } /* default broadcast & multicast use macid 1 */ psta->mac_id = 1; -exit: - return res; + return _SUCCESS; } struct sta_info *rtw_get_bcmc_stainfo(struct adapter *padapter) @@ -471,13 +476,13 @@ struct sta_info *rtw_get_bcmc_stainfo(struct adapter *padapter) return rtw_get_stainfo(pstapriv, bc_addr); } -u8 rtw_access_ctrl(struct adapter *padapter, u8 *mac_addr) +bool rtw_access_ctrl(struct adapter *padapter, u8 *mac_addr) { - u8 res = true; + bool res = true; #ifdef CONFIG_88EU_AP_MODE struct list_head *plist, *phead; struct rtw_wlan_acl_node *paclnode; - u8 match = false; + bool match = false; struct sta_priv *pstapriv = &padapter->stapriv; struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; struct __queue *pacl_node_q = &pacl_list->acl_node_q; @@ -499,9 +504,9 @@ u8 rtw_access_ctrl(struct adapter *padapter, u8 *mac_addr) spin_unlock_bh(&pacl_node_q->lock); if (pacl_list->mode == 1)/* accept unless in deny list */ - res = (match) ? false : true; + res = !match; else if (pacl_list->mode == 2)/* deny unless in accept list */ - res = (match) ? true : false; + res = match; else res = true; diff --git a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c index c985b1468d41..af8a79ce8736 100644 --- a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c +++ b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c @@ -667,7 +667,7 @@ static void bwmode_update_check(struct adapter *padapter, struct ndis_802_11_var void HT_caps_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE) { unsigned int i; - u8 max_AMPDU_len, min_MPDU_spacing; + u8 max_ampdu_len, min_mpdu_spacing; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; @@ -689,16 +689,16 @@ void HT_caps_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE) } else { /* modify from fw by Thomas 2010/11/17 */ if ((pmlmeinfo->HT_caps.ampdu_params_info & 0x3) > (pIE->data[i] & 0x3)) - max_AMPDU_len = pIE->data[i] & 0x3; + max_ampdu_len = pIE->data[i] & 0x3; else - max_AMPDU_len = pmlmeinfo->HT_caps.ampdu_params_info & 0x3; + max_ampdu_len = pmlmeinfo->HT_caps.ampdu_params_info & 0x3; if ((pmlmeinfo->HT_caps.ampdu_params_info & 0x1c) > (pIE->data[i] & 0x1c)) - min_MPDU_spacing = pmlmeinfo->HT_caps.ampdu_params_info & 0x1c; + min_mpdu_spacing = pmlmeinfo->HT_caps.ampdu_params_info & 0x1c; else - min_MPDU_spacing = pIE->data[i] & 0x1c; + min_mpdu_spacing = pIE->data[i] & 0x1c; - pmlmeinfo->HT_caps.ampdu_params_info = max_AMPDU_len | min_MPDU_spacing; + pmlmeinfo->HT_caps.ampdu_params_info = max_ampdu_len | min_mpdu_spacing; } } @@ -729,8 +729,8 @@ void HT_info_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE) void HTOnAssocRsp(struct adapter *padapter) { - unsigned char max_AMPDU_len; - unsigned char min_MPDU_spacing; + u8 max_ampdu_len; + u8 min_mpdu_spacing; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; @@ -748,13 +748,11 @@ void HTOnAssocRsp(struct adapter *padapter) * AMPDU_para [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k * AMPDU_para [4:2]:Min MPDU Start Spacing */ - max_AMPDU_len = pmlmeinfo->HT_caps.ampdu_params_info & 0x03; + max_ampdu_len = pmlmeinfo->HT_caps.ampdu_params_info & 0x03; + min_mpdu_spacing = (pmlmeinfo->HT_caps.ampdu_params_info & 0x1c) >> 2; - min_MPDU_spacing = (pmlmeinfo->HT_caps.ampdu_params_info & 0x1c) >> 2; - - rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_MIN_SPACE, (u8 *)(&min_MPDU_spacing)); - - rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&max_AMPDU_len)); + rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_MIN_SPACE, &min_mpdu_spacing); + rtw_hal_set_hwreg(padapter, HW_VAR_AMPDU_FACTOR, &max_ampdu_len); } void ERP_IE_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE) diff --git a/drivers/staging/rtl8188eu/core/rtw_xmit.c b/drivers/staging/rtl8188eu/core/rtw_xmit.c index 952f2ab51347..c37591657bac 100644 --- a/drivers/staging/rtl8188eu/core/rtw_xmit.c +++ b/drivers/staging/rtl8188eu/core/rtw_xmit.c @@ -776,7 +776,7 @@ s32 rtw_make_wlanhdr(struct adapter *padapter, u8 *hdr, struct pkt_attrib *pattr memcpy(pwlanhdr->addr2, get_bssid(pmlmepriv), ETH_ALEN); memcpy(pwlanhdr->addr3, pattrib->src, ETH_ALEN); - if (psta->qos_option) + if (psta && psta->qos_option) qos_option = true; } else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) || check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) { @@ -784,7 +784,7 @@ s32 rtw_make_wlanhdr(struct adapter *padapter, u8 *hdr, struct pkt_attrib *pattr memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN); memcpy(pwlanhdr->addr3, get_bssid(pmlmepriv), ETH_ALEN); - if (psta->qos_option) + if (psta && psta->qos_option) qos_option = true; } else { RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("fw_state:%x is not allowed to xmit frame\n", get_fwstate(pmlmepriv))); diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c b/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c index 47352f210c0b..7646167a0b36 100644 --- a/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c +++ b/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c @@ -47,8 +47,6 @@ static u8 _is_fw_read_cmd_down(struct adapter *adapt, u8 msgbox_num) ******************************************/ static s32 FillH2CCmd_88E(struct adapter *adapt, u8 ElementID, u32 CmdLen, u8 *pCmdBuffer) { - u8 bcmd_down = false; - s32 retry_cnts = 100; u8 h2c_box_num; u32 msgbox_addr; u32 msgbox_ex_addr; @@ -71,39 +69,34 @@ static s32 FillH2CCmd_88E(struct adapter *adapt, u8 ElementID, u32 CmdLen, u8 *p goto exit; /* pay attention to if race condition happened in H2C cmd setting. */ - do { - h2c_box_num = adapt->HalData->LastHMEBoxNum; - - if (!_is_fw_read_cmd_down(adapt, h2c_box_num)) { - DBG_88E(" fw read cmd failed...\n"); - goto exit; - } - - *(u8 *)(&h2c_cmd) = ElementID; - - if (CmdLen <= 3) { - memcpy((u8 *)(&h2c_cmd)+1, pCmdBuffer, CmdLen); - } else { - memcpy((u8 *)(&h2c_cmd)+1, pCmdBuffer, 3); - ext_cmd_len = CmdLen-3; - memcpy((u8 *)(&h2c_cmd_ex), pCmdBuffer+3, ext_cmd_len); + h2c_box_num = adapt->HalData->LastHMEBoxNum; - /* Write Ext command */ - msgbox_ex_addr = REG_HMEBOX_EXT_0 + (h2c_box_num * RTL88E_EX_MESSAGE_BOX_SIZE); - for (cmd_idx = 0; cmd_idx < ext_cmd_len; cmd_idx++) - usb_write8(adapt, msgbox_ex_addr+cmd_idx, *((u8 *)(&h2c_cmd_ex)+cmd_idx)); - } - /* Write command */ - msgbox_addr = REG_HMEBOX_0 + (h2c_box_num * RTL88E_MESSAGE_BOX_SIZE); - for (cmd_idx = 0; cmd_idx < RTL88E_MESSAGE_BOX_SIZE; cmd_idx++) - usb_write8(adapt, msgbox_addr+cmd_idx, *((u8 *)(&h2c_cmd)+cmd_idx)); + if (!_is_fw_read_cmd_down(adapt, h2c_box_num)) { + DBG_88E(" fw read cmd failed...\n"); + goto exit; + } - bcmd_down = true; + *(u8 *)(&h2c_cmd) = ElementID; - adapt->HalData->LastHMEBoxNum = - (h2c_box_num+1) % RTL88E_MAX_H2C_BOX_NUMS; + if (CmdLen <= 3) { + memcpy((u8 *)(&h2c_cmd) + 1, pCmdBuffer, CmdLen); + } else { + memcpy((u8 *)(&h2c_cmd) + 1, pCmdBuffer, 3); + ext_cmd_len = CmdLen - 3; + memcpy((u8 *)(&h2c_cmd_ex), pCmdBuffer + 3, ext_cmd_len); + + /* Write Ext command */ + msgbox_ex_addr = REG_HMEBOX_EXT_0 + (h2c_box_num * RTL88E_EX_MESSAGE_BOX_SIZE); + for (cmd_idx = 0; cmd_idx < ext_cmd_len; cmd_idx++) + usb_write8(adapt, msgbox_ex_addr + cmd_idx, *((u8 *)(&h2c_cmd_ex) + cmd_idx)); + } + /* Write command */ + msgbox_addr = REG_HMEBOX_0 + (h2c_box_num * RTL88E_MESSAGE_BOX_SIZE); + for (cmd_idx = 0; cmd_idx < RTL88E_MESSAGE_BOX_SIZE; cmd_idx++) + usb_write8(adapt, msgbox_addr + cmd_idx, *((u8 *)(&h2c_cmd) + cmd_idx)); - } while ((!bcmd_down) && (retry_cnts--)); + adapt->HalData->LastHMEBoxNum = + (h2c_box_num + 1) % RTL88E_MAX_H2C_BOX_NUMS; ret = _SUCCESS; diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c index 086f98d38cba..57ae0e83dd3e 100644 --- a/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c +++ b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c @@ -552,7 +552,6 @@ void Hal_ReadAntennaDiversity88E(struct adapter *pAdapter, u8 *PROMContent, bool pHalData->AntDivCfg = 1; /* 0xC1[3] is ignored. */ } else { pHalData->AntDivCfg = 0; - pHalData->TRxAntDivType = pHalData->TRxAntDivType; /* The value in the driver setting of device manager. */ } DBG_88E("EEPROM : AntDivCfg = %x, TRxAntDivType = %x\n", pHalData->AntDivCfg, pHalData->TRxAntDivType); } diff --git a/drivers/staging/rtl8188eu/include/rtw_efuse.h b/drivers/staging/rtl8188eu/include/rtw_efuse.h index 3ec53761e9fd..7a9c8ff0daa9 100644 --- a/drivers/staging/rtl8188eu/include/rtw_efuse.h +++ b/drivers/staging/rtl8188eu/include/rtw_efuse.h @@ -82,7 +82,6 @@ u8 efuse_OneByteWrite(struct adapter *adapter, u16 addr, u8 data); void efuse_ReadEFuse(struct adapter *Adapter, u8 efuseType, u16 _offset, u16 _size_byte, u8 *pbuf); -void efuse_power_switch(struct adapter *adapt, u8 write, u8 pwrstate); int Efuse_PgPacketRead(struct adapter *adapt, u8 offset, u8 *data); bool Efuse_PgPacketWrite(struct adapter *adapter, u8 offset, u8 word, u8 *data); void efuse_WordEnableDataRead(u8 word_en, u8 *sourdata, u8 *targetdata); diff --git a/drivers/staging/rtl8188eu/include/sta_info.h b/drivers/staging/rtl8188eu/include/sta_info.h index dc685a14aeb8..6165adafc451 100644 --- a/drivers/staging/rtl8188eu/include/sta_info.h +++ b/drivers/staging/rtl8188eu/include/sta_info.h @@ -354,6 +354,6 @@ void rtw_free_all_stainfo(struct adapter *adapt); struct sta_info *rtw_get_stainfo(struct sta_priv *stapriv, u8 *hwaddr); u32 rtw_init_bcmc_stainfo(struct adapter *adapt); struct sta_info *rtw_get_bcmc_stainfo(struct adapter *padapter); -u8 rtw_access_ctrl(struct adapter *padapter, u8 *mac_addr); +bool rtw_access_ctrl(struct adapter *padapter, u8 *mac_addr); #endif /* _STA_INFO_H_ */ diff --git a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c index ec5835d1aa8c..710c33fd4965 100644 --- a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c +++ b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c @@ -148,17 +148,10 @@ static char *translate_scan(struct adapter *padapter, else snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11bg"); } else { - if (pnetwork->network.Configuration.DSConfig > 14) { - if (ht_cap) - snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11an"); - else - snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11a"); - } else { - if (ht_cap) - snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11gn"); - else - snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11g"); - } + if (ht_cap) + snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11gn"); + else + snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11g"); } start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN); @@ -650,17 +643,10 @@ static int rtw_wx_get_name(struct net_device *dev, else snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11bg"); } else { - if (pcur_bss->Configuration.DSConfig > 14) { - if (ht_cap) - snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11an"); - else - snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11a"); - } else { - if (ht_cap) - snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11gn"); - else - snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11g"); - } + if (ht_cap) + snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11gn"); + else + snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11g"); } } else { snprintf(wrqu->name, IFNAMSIZ, "unassociated"); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index f932cb15e4e5..dace81a7d1ba 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -715,8 +715,8 @@ void rtl92e_set_wireless_mode(struct net_device *dev, u8 wireless_mode) if ((wireless_mode == WIRELESS_MODE_N_24G) || (wireless_mode == WIRELESS_MODE_N_5G)) { priv->rtllib->pHTInfo->bEnableHT = 1; - RT_TRACE(COMP_DBG, "%s(), wireless_mode:%x, bEnableHT = 1\n", - __func__, wireless_mode); + RT_TRACE(COMP_DBG, "%s(), wireless_mode:%x, bEnableHT = 1\n", + __func__, wireless_mode); } else { priv->rtllib->pHTInfo->bEnableHT = 0; RT_TRACE(COMP_DBG, "%s(), wireless_mode:%x, bEnableHT = 0\n", @@ -1616,14 +1616,15 @@ static void _rtl92e_hard_data_xmit(struct sk_buff *skb, struct net_device *dev, memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev)); skb_push(skb, priv->rtllib->tx_headroom); ret = _rtl92e_tx(dev, skb); - if (ret != 0) - kfree_skb(skb); if (queue_index != MGNT_QUEUE) { priv->rtllib->stats.tx_bytes += (skb->len - priv->rtllib->tx_headroom); priv->rtllib->stats.tx_packets++; } + + if (ret != 0) + kfree_skb(skb); } static int _rtl92e_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c index 5c33bcb0db2e..00fea127bdc3 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_rx.c @@ -1620,7 +1620,7 @@ int ieee80211_parse_info_param(struct ieee80211_device *ieee, for (i = 0; i < network->rates_len; i++) { network->rates[i] = info_element->data[i]; #ifdef CONFIG_IEEE80211_DEBUG - p += snprintf(p, sizeof(rates_str) - + p += scnprintf(p, sizeof(rates_str) - (p - rates_str), "%02X ", network->rates[i]); #endif @@ -1647,7 +1647,7 @@ int ieee80211_parse_info_param(struct ieee80211_device *ieee, for (i = 0; i < network->rates_ex_len; i++) { network->rates_ex[i] = info_element->data[i]; #ifdef CONFIG_IEEE80211_DEBUG - p += snprintf(p, sizeof(rates_str) - + p += scnprintf(p, sizeof(rates_str) - (p - rates_str), "%02X ", network->rates_ex[i]); #endif diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c index 9dd5c04181ea..33c596f9ec96 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c @@ -109,7 +109,7 @@ static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee, /* Add basic and extended rates */ max_rate = 0; p = custom; - p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): "); + p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): "); for (i = 0, j = 0; i < network->rates_len; ) { if (j < network->rates_ex_len && ((network->rates_ex[j] & 0x7F) < @@ -119,12 +119,12 @@ static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee, rate = network->rates[i++] & 0x7F; if (rate > max_rate) max_rate = rate; - p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), + p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom), "%d%s ", rate >> 1, (rate & 1) ? ".5" : ""); } for (; j < network->rates_ex_len; j++) { rate = network->rates_ex[j] & 0x7F; - p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), + p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom), "%d%s ", rate >> 1, (rate & 1) ? ".5" : ""); if (rate > max_rate) max_rate = rate; @@ -214,7 +214,7 @@ static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee, * for given network. */ iwe.cmd = IWEVCUSTOM; p = custom; - p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), + p += scnprintf(p, MAX_CUSTOM_LEN - (p - custom), " Last beacon: %lums ago", (jiffies - network->last_scanned) / (HZ / 100)); iwe.u.data.length = p - custom; if (iwe.u.data.length) diff --git a/drivers/staging/rtl8192u/r8190_rtl8256.c b/drivers/staging/rtl8192u/r8190_rtl8256.c index b169460b9f26..63e0f7b1b852 100644 --- a/drivers/staging/rtl8192u/r8190_rtl8256.c +++ b/drivers/staging/rtl8192u/r8190_rtl8256.c @@ -43,8 +43,8 @@ void phy_set_rf8256_bandwidth(struct net_device *dev, enum ht_channel_width Band switch (Bandwidth) { case HT_CHANNEL_WIDTH_20: if (priv->card_8192_version == VERSION_819XU_A || - priv->card_8192_version == - VERSION_819XU_B) { /* 8256 D-cut, E-cut, xiong: consider it later! */ + priv->card_8192_version == VERSION_819XU_B) { + /* 8256 D-cut, E-cut, xiong: consider it later! */ rtl8192_phy_SetRFReg(dev, (enum rf90_radio_path_e)eRFPath, 0x0b, bMask12Bits, 0x100); /* phy para:1ba */ diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c index 2821411878ce..48f1591ed5b4 100644 --- a/drivers/staging/rtl8192u/r8192U_core.c +++ b/drivers/staging/rtl8192u/r8192U_core.c @@ -98,8 +98,6 @@ static char *ifname = "wlan%d"; static int hwwep = 1; /* default use hw. set 0 to use software security */ static int channels = 0x3fff; - - module_param(ifname, charp, 0644); module_param(hwwep, int, 0644); module_param(channels, int, 0644); @@ -112,7 +110,6 @@ static int rtl8192_usb_probe(struct usb_interface *intf, const struct usb_device_id *id); static void rtl8192_usb_disconnect(struct usb_interface *intf); - static struct usb_driver rtl8192_usb_driver = { .name = RTL819XU_MODULE_NAME, /* Driver name */ .id_table = rtl8192_usb_id_tbl, /* PCI_ID table */ @@ -122,7 +119,6 @@ static struct usb_driver rtl8192_usb_driver = { .resume = NULL, /* PM resume fn */ }; - struct CHANNEL_LIST { u8 Channel[32]; u8 Len; @@ -207,9 +203,6 @@ static void rtl819x_set_channel_map(u8 channel_plan, struct r8192_priv *priv) } } - - - static void CamResetAllEntry(struct net_device *dev) { u32 ulcommand = 0; @@ -297,7 +290,6 @@ int write_nic_byte(struct net_device *dev, int indx, u8 data) return 0; } - int write_nic_word(struct net_device *dev, int indx, u16 data) { int status; @@ -324,7 +316,6 @@ int write_nic_word(struct net_device *dev, int indx, u16 data) return 0; } - int write_nic_dword(struct net_device *dev, int indx, u32 data) { int status; @@ -343,7 +334,6 @@ int write_nic_dword(struct net_device *dev, int indx, u32 data) usbdata, 4, HZ / 2); kfree(usbdata); - if (status < 0) { netdev_err(dev, "%s TimeOut! status: %d\n", __func__, status); return status; @@ -352,8 +342,6 @@ int write_nic_dword(struct net_device *dev, int indx, u32 data) return 0; } - - int read_nic_byte(struct net_device *dev, int indx, u8 *data) { int status; @@ -379,8 +367,6 @@ int read_nic_byte(struct net_device *dev, int indx, u8 *data) return 0; } - - int read_nic_word(struct net_device *dev, int indx, u16 *data) { int status; @@ -628,13 +614,13 @@ static void rtl8192_proc_init_one(struct net_device *dev) return; proc_create_single("stats-rx", S_IFREG | S_IRUGO, dir, - proc_get_stats_rx); + proc_get_stats_rx); proc_create_single("stats-tx", S_IFREG | S_IRUGO, dir, - proc_get_stats_tx); + proc_get_stats_tx); proc_create_single("stats-ap", S_IFREG | S_IRUGO, dir, - proc_get_stats_ap); + proc_get_stats_ap); proc_create_single("registers", S_IFREG | S_IRUGO, dir, - proc_get_registers); + proc_get_registers); } static void rtl8192_proc_remove_one(struct net_device *dev) @@ -788,7 +774,6 @@ void rtl8192_set_rxconf(struct net_device *dev) rxconf = rxconf | RCR_CBSSID; } - if (priv->ieee80211->iw_mode == IW_MODE_MONITOR) { rxconf = rxconf | RCR_AICV; rxconf = rxconf | RCR_APWRMGT; @@ -797,7 +782,6 @@ void rtl8192_set_rxconf(struct net_device *dev) if (priv->crcmon == 1 && priv->ieee80211->iw_mode == IW_MODE_MONITOR) rxconf = rxconf | RCR_ACRC32; - rxconf = rxconf & ~RX_FIFO_THRESHOLD_MASK; rxconf = rxconf | (RX_FIFO_THRESHOLD_NONE << RX_FIFO_THRESHOLD_SHIFT); rxconf = rxconf & ~MAX_RX_DMA_MASK; @@ -901,13 +885,11 @@ static u32 rtl819xusb_rx_command_packet(struct net_device *dev, return status; } - static void rtl8192_data_hard_stop(struct net_device *dev) { /* FIXME !! */ } - static void rtl8192_data_hard_resume(struct net_device *dev) { /* FIXME !! */ @@ -951,7 +933,6 @@ static int rtl8192_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) struct cb_desc *tcb_desc = (struct cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE); u8 queue_index = tcb_desc->queue_index; - spin_lock_irqsave(&priv->tx_lock, flags); memcpy((unsigned char *)(skb->cb), &dev, sizeof(dev)); @@ -1123,7 +1104,6 @@ static void rtl8192_config_rate(struct net_device *dev, u16 *rate_config) } } - #define SHORT_SLOT_TIME 9 #define NON_SHORT_SLOT_TIME 20 @@ -1188,7 +1168,6 @@ static void rtl8192_net_update(struct net_device *dev) */ void rtl819xusb_beacon_tx(struct net_device *dev, u16 tx_rate) { - } short rtl819xU_tx_cmd(struct net_device *dev, struct sk_buff *skb) @@ -1232,6 +1211,8 @@ short rtl819xU_tx_cmd(struct net_device *dev, struct sk_buff *skb) return 0; DMESGE("Error TX CMD URB, error %d", status); + dev_kfree_skb(skb); + usb_free_urb(tx_urb); return -1; } @@ -1389,7 +1370,6 @@ static u8 MRateToHwRate8190Pci(u8 rate) return ret; } - static u8 QueryIsShort(u8 TxHT, u8 TxRate, struct cb_desc *tcb_desc) { u8 tmp_Short; @@ -1422,7 +1402,7 @@ short rtl8192_tx(struct net_device *dev, struct sk_buff *skb) (struct tx_fwinfo_819x_usb *)(skb->data + USB_HWDESC_HEADER_LEN); struct usb_device *udev = priv->udev; int pend; - int status; + int status, rt = -1; struct urb *tx_urb = NULL, *tx_urb_zero = NULL; unsigned int idx_pipe; @@ -1566,8 +1546,10 @@ short rtl8192_tx(struct net_device *dev, struct sk_buff *skb) } if (bSend0Byte) { tx_urb_zero = usb_alloc_urb(0, GFP_ATOMIC); - if (!tx_urb_zero) - return -ENOMEM; + if (!tx_urb_zero) { + rt = -ENOMEM; + goto error; + } usb_fill_bulk_urb(tx_urb_zero, udev, usb_sndbulkpipe(udev, idx_pipe), &zero, 0, tx_zero_isr, dev); @@ -1577,7 +1559,7 @@ short rtl8192_tx(struct net_device *dev, struct sk_buff *skb) "Error TX URB for zero byte %d, error %d", atomic_read(&priv->tx_pending[tcb_desc->queue_index]), status); - return -1; + goto error; } } netif_trans_update(dev); @@ -1588,7 +1570,12 @@ short rtl8192_tx(struct net_device *dev, struct sk_buff *skb) RT_TRACE(COMP_ERR, "Error TX URB %d, error %d", atomic_read(&priv->tx_pending[tcb_desc->queue_index]), status); - return -1; + +error: + dev_kfree_skb_any(skb); + usb_free_urb(tx_urb); + usb_free_urb(tx_urb_zero); + return rt; } static short rtl8192_usb_initendpoints(struct net_device *dev) @@ -1742,7 +1729,6 @@ static const struct ieee80211_qos_parameters def_qos_parameters = { {0, 0, 0, 0} /* tx_op_limit */ }; - static void rtl8192_update_beacon(struct work_struct *work) { struct r8192_priv *priv = container_of(work, struct r8192_priv, @@ -1913,15 +1899,12 @@ static int rtl8192_qos_association_resp(struct r8192_priv *priv, if (set_qos_param == 1) schedule_work(&priv->qos_activate); - return 0; } - -static int rtl8192_handle_assoc_response( - struct net_device *dev, - struct ieee80211_assoc_response_frame *resp, - struct ieee80211_network *network) +static int rtl8192_handle_assoc_response(struct net_device *dev, + struct ieee80211_assoc_response_frame *resp, + struct ieee80211_network *network) { struct r8192_priv *priv = ieee80211_priv(dev); @@ -1929,7 +1912,6 @@ static int rtl8192_handle_assoc_response( return 0; } - static void rtl8192_update_ratr_table(struct net_device *dev) { struct r8192_priv *priv = ieee80211_priv(dev); @@ -2218,7 +2200,6 @@ static void rtl8192_init_priv_task(struct net_device *dev) { struct r8192_priv *priv = ieee80211_priv(dev); - INIT_WORK(&priv->reset_wq, rtl8192_restart); INIT_DELAYED_WORK(&priv->watch_dog_wq, @@ -2515,7 +2496,6 @@ static int rtl8192_read_eeprom_info(struct net_device *dev) break; } - if (priv->rf_type == RF_1T2R) RT_TRACE(COMP_EPROM, "\n1T2R config\n"); else @@ -2668,7 +2648,6 @@ static void rtl8192_hwconfig(struct net_device *dev) /* Set Auto Rate fallback control */ } - /* InitializeAdapter and PhyCfg */ static bool rtl8192_adapter_start(struct net_device *dev) { @@ -2803,14 +2782,12 @@ static bool rtl8192_adapter_start(struct net_device *dev) RT_TRACE(COMP_INIT, "%s():after phy RF config\n", __func__); } - if (priv->ieee80211->FwRWRF) /* We can force firmware to do RF-R/W */ priv->Rf_Mode = RF_OP_By_FW; else priv->Rf_Mode = RF_OP_By_SW_3wire; - rtl8192_phy_updateInitGain(dev); /*--set CCK and OFDM Block "ON"--*/ rtl8192_setBBreg(dev, rFPGA0_RFMOD, bCCKEn, 0x1); @@ -2865,7 +2842,6 @@ static bool rtl8192_adapter_start(struct net_device *dev) } write_nic_byte(dev, 0x87, 0x0); - return init_status; } @@ -2996,7 +2972,6 @@ static RESET_TYPE RxCheckStuck(struct net_device *dev) return RESET_TYPE_NORESET; } - /** * This function is called by Checkforhang to check whether we should * ask OS to reset driver @@ -3052,8 +3027,6 @@ static void rtl8192_cancel_deferred_work(struct r8192_priv *priv); static int _rtl8192_up(struct net_device *dev); static int rtl8192_close(struct net_device *dev); - - static void CamRestoreAllEntry(struct net_device *dev) { u8 EntryId = 0; @@ -3070,7 +3043,6 @@ static void CamRestoreAllEntry(struct net_device *dev) RT_TRACE(COMP_SEC, "%s:\n", __func__); - if ((priv->ieee80211->pairwise_key_type == KEY_TYPE_WEP40) || (priv->ieee80211->pairwise_key_type == KEY_TYPE_WEP104)) { for (EntryId = 0; EntryId < 4; EntryId++) { @@ -3096,8 +3068,6 @@ static void CamRestoreAllEntry(struct net_device *dev) MacAddr, 0, NULL); } - - if (priv->ieee80211->group_key_type == KEY_TYPE_TKIP) { MacAddr = CAM_CONST_BROAD; for (EntryId = 1; EntryId < 4; EntryId++) { @@ -3134,7 +3104,6 @@ static void rtl819x_ifsilentreset(struct net_device *dev) int reset_status = 0; struct ieee80211_device *ieee = priv->ieee80211; - /* If we need to check CCK stop, please uncomment this line. */ /* bStuck = Adapter->HalFunc.CheckHWStopHandler(Adapter); */ @@ -3258,7 +3227,6 @@ static void rtl819x_update_rxcounts(struct r8192_priv *priv, u32 *TotalRxBcnNum, } } - static void rtl819x_watchdog_wqcallback(struct work_struct *work) { struct delayed_work *dwork = to_delayed_work(work); @@ -3369,7 +3337,6 @@ static int _rtl8192_up(struct net_device *dev) return 0; } - static int rtl8192_open(struct net_device *dev) { struct r8192_priv *priv = ieee80211_priv(dev); @@ -3381,7 +3348,6 @@ static int rtl8192_open(struct net_device *dev) return ret; } - int rtl8192_up(struct net_device *dev) { struct r8192_priv *priv = ieee80211_priv(dev); @@ -3392,7 +3358,6 @@ int rtl8192_up(struct net_device *dev) return _rtl8192_up(dev); } - static int rtl8192_close(struct net_device *dev) { struct r8192_priv *priv = ieee80211_priv(dev); @@ -3440,7 +3405,6 @@ int rtl8192_down(struct net_device *dev) deinit_hal_dm(dev); del_timer_sync(&priv->watch_dog_timer); - ieee80211_softmac_stop_protocol(priv->ieee80211); memset(&priv->ieee80211->current_network, 0, offsetof(struct ieee80211_network, list)); @@ -3449,7 +3413,6 @@ int rtl8192_down(struct net_device *dev) return 0; } - void rtl8192_commit(struct net_device *dev) { struct r8192_priv *priv = ieee80211_priv(dev); @@ -3495,7 +3458,6 @@ static void r8192_set_multicast(struct net_device *dev) priv->promisc = promisc; } - static int r8192_set_mac_adr(struct net_device *dev, void *mac) { struct r8192_priv *priv = ieee80211_priv(dev); @@ -3525,7 +3487,6 @@ static int rtl8192_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) mutex_lock(&priv->wx_mutex); - if (p->length < sizeof(struct ieee_param) || !p->pointer) { ret = -EINVAL; goto out; @@ -3778,7 +3739,6 @@ static long rtl819x_translate_todbm(u8 signal_strength_index) return signal_power; } - /* We can not declare RSSI/EVM total value of sliding window to * be a local static. Otherwise, it may increase when we return from S3/S4. The * value will be kept in memory or disk. Declare the value in the adaptor @@ -3841,7 +3801,6 @@ static void rtl8192_process_phyinfo(struct r8192_priv *priv, u8 *buffer, if (!bcheck) return; - /* only rtl8190 supported * rtl8190_process_cck_rxpathsel(priv,pprevious_stats); */ @@ -3851,17 +3810,15 @@ static void rtl8192_process_phyinfo(struct r8192_priv *priv, u8 *buffer, /* record the general signal strength to the sliding window. */ - /* <2> Showed on UI for engineering * hardware does not provide rssi information for each rf path in CCK */ if (!pprevious_stats->bIsCCK && (pprevious_stats->bPacketToSelf || pprevious_stats->bToSelfBA)) { for (rfpath = RF90_PATH_A; rfpath < priv->NumTotalRFPath; rfpath++) { - if (!rtl8192_phy_CheckIsLegalRFPath( - priv->ieee80211->dev, rfpath)) + if (!rtl8192_phy_CheckIsLegalRFPath(priv->ieee80211->dev, + rfpath)) continue; - if (priv->stats.rx_rssi_percentage[rfpath] == 0) priv->stats.rx_rssi_percentage[rfpath] = pprevious_stats->RxMIMOSignalStrength[rfpath]; @@ -3881,7 +3838,6 @@ static void rtl8192_process_phyinfo(struct r8192_priv *priv, u8 *buffer, } } - /* Check PWDB. */ RT_TRACE(COMP_RXDESC, "Smooth %s PWDB = %d\n", pprevious_stats->bIsCCK ? "CCK" : "OFDM", @@ -3908,7 +3864,6 @@ static void rtl8192_process_phyinfo(struct r8192_priv *priv, u8 *buffer, pprevious_stats->bIsCCK ? "CCK" : "OFDM", pprevious_stats->RxPWDBAll); - if (pprevious_stats->bPacketToSelf || pprevious_stats->bPacketBeacon || pprevious_stats->bToSelfBA) { @@ -4083,7 +4038,6 @@ static void rtl8192_query_rxphystatus(struct r8192_priv *priv, u8 rf_rx_num = 0; u8 sq; - priv->stats.numqry_phystatus++; is_cck_rate = rx_hal_is_cck_rate(pdrvinfo); @@ -4192,8 +4146,7 @@ static void rtl8192_query_rxphystatus(struct r8192_priv *priv, else continue; - if (!rtl8192_phy_CheckIsLegalRFPath( - priv->ieee80211->dev, i)) + if (!rtl8192_phy_CheckIsLegalRFPath(priv->ieee80211->dev, i)) continue; rx_pwr[i] = @@ -4214,7 +4167,6 @@ static void rtl8192_query_rxphystatus(struct r8192_priv *priv, precord_stats->RxMIMOSignalStrength[i] = (u8)RSSI; } - /* (2)PWDB, Average PWDB calculated by hardware * (for rate adaptive) */ @@ -4259,7 +4211,6 @@ static void rtl8192_query_rxphystatus(struct r8192_priv *priv, evm & 0xff; } - /* record rx statistics for debug */ rxsc_sgien_exflg = pofdm_buf->rxsc_sgien_exflg; prxsc = (struct phy_ofdm_rx_status_rxsc_sgien_exintfflag *) @@ -4288,16 +4239,14 @@ static void rtl8192_query_rxphystatus(struct r8192_priv *priv, } } /* QueryRxPhyStatus8190Pci */ -static void rtl8192_record_rxdesc_forlateruse( - struct ieee80211_rx_stats *psrc_stats, - struct ieee80211_rx_stats *ptarget_stats) +static void rtl8192_record_rxdesc_forlateruse(struct ieee80211_rx_stats *psrc_stats, + struct ieee80211_rx_stats *ptarget_stats) { ptarget_stats->bIsAMPDU = psrc_stats->bIsAMPDU; ptarget_stats->bFirstMPDU = psrc_stats->bFirstMPDU; ptarget_stats->Seq_Num = psrc_stats->Seq_Num; } - static void TranslateRxSignalStuff819xUsb(struct sk_buff *skb, struct ieee80211_rx_stats *pstats, struct rx_drvinfo_819x_usb *pdrvinfo) @@ -4341,8 +4290,6 @@ static void TranslateRxSignalStuff819xUsb(struct sk_buff *skb, bToSelfBA = true; } - - if (bpacket_match_bssid) priv->stats.numpacket_matchbssid++; if (bpacket_toself) @@ -4383,7 +4330,6 @@ UpdateReceivedRateHistogramStatistics8190(struct net_device *dev, /* 1: short preamble/GI, 0: long preamble/GI */ u32 preamble_guardinterval; - if (stats->bCRC) rcvType = 2; else if (stats->bICV) @@ -4491,7 +4437,6 @@ UpdateReceivedRateHistogramStatistics8190(struct net_device *dev, priv->stats.received_rate_histogram[rcvType][rateIndex]++; } - static void query_rxdesc_status(struct sk_buff *skb, struct ieee80211_rx_stats *stats, bool bIsRxAggrSubframe) @@ -4526,8 +4471,7 @@ static void query_rxdesc_status(struct sk_buff *skb, * Driver info are written to the RxBuffer following rx desc */ if (stats->RxDrvInfoSize != 0) { - driver_info = (struct rx_drvinfo_819x_usb *)( - skb->data + driver_info = (struct rx_drvinfo_819x_usb *)(skb->data + sizeof(struct rx_desc_819x_usb) + stats->RxBufShift ); @@ -4556,7 +4500,6 @@ static void query_rxdesc_status(struct sk_buff *skb, stats->bShortPreamble = driver_info->SPLCP; - UpdateReceivedRateHistogramStatistics8190(dev, stats); stats->bIsAMPDU = (driver_info->PartAggr == 1); @@ -4569,7 +4512,7 @@ static void query_rxdesc_status(struct sk_buff *skb, /* Rx A-MPDU */ if (driver_info->FirstAGGR == 1 || driver_info->PartAggr == 1) RT_TRACE(COMP_RXDESC, - "driver_info->FirstAGGR = %d, driver_info->PartAggr = %d\n", + "driver_info->FirstAGGR = %d, driver_info->PartAggr = %d\n", driver_info->FirstAGGR, driver_info->PartAggr); } @@ -4636,9 +4579,8 @@ static void rtl8192_rx_nomal(struct sk_buff *skb) } } -static void rtl819xusb_process_received_packet( - struct net_device *dev, - struct ieee80211_rx_stats *pstats) +static void rtl819xusb_process_received_packet(struct net_device *dev, + struct ieee80211_rx_stats *pstats) { struct r8192_priv *priv = ieee80211_priv(dev); @@ -4671,8 +4613,6 @@ static void rtl819xusb_process_received_packet( #ifdef SW_CRC_CHECK SwCrcCheck(); #endif - - } static void query_rx_cmdpkt_desc_status(struct sk_buff *skb, @@ -4691,7 +4631,6 @@ static void query_rx_cmdpkt_desc_status(struct sk_buff *skb, stats->ntotalfrag = 1; } - static void rtl8192_rx_cmd(struct sk_buff *skb) { struct rtl8192_rx_info *info = (struct rtl8192_rx_info *)skb->cb; @@ -4759,7 +4698,6 @@ static const struct net_device_ops rtl8192_netdev_ops = { .ndo_start_xmit = ieee80211_xmit, }; - /**************************************************************************** * ---------------------------- USB_STUFF--------------------------- *****************************************************************************/ @@ -4815,7 +4753,6 @@ static int rtl8192_usb_probe(struct usb_interface *intf, RT_TRACE(COMP_INIT, "dev name=======> %s\n", dev->name); rtl8192_proc_init_one(dev); - RT_TRACE(COMP_INIT, "Driver probe completed\n"); return 0; @@ -4843,7 +4780,6 @@ static void rtl8192_cancel_deferred_work(struct r8192_priv *priv) cancel_work_sync(&priv->qos_activate); } - static void rtl8192_usb_disconnect(struct usb_interface *intf) { struct net_device *dev = usb_get_intfdata(intf); @@ -4907,7 +4843,6 @@ static int __init rtl8192_usb_module_init(void) return usb_register(&rtl8192_usb_driver); } - static void __exit rtl8192_usb_module_exit(void) { usb_deregister(&rtl8192_usb_driver); @@ -4949,7 +4884,6 @@ void EnableHWSecurityConfig8192(struct net_device *dev) write_nic_byte(dev, SECR, SECR_value); } - void setKey(struct net_device *dev, u8 EntryNo, u8 KeyIndex, u16 KeyType, u8 *MacAddr, u8 DefaultKey, u32 *KeyContent) { @@ -4970,7 +4904,6 @@ void setKey(struct net_device *dev, u8 EntryNo, u8 KeyIndex, u16 KeyType, else usConfig |= BIT(15) | (KeyType << 2) | KeyIndex; - for (i = 0; i < CAM_CONTENT_COUNT; i++) { TargetCommand = i + CAM_CONTENT_COUNT * EntryNo; TargetCommand |= BIT(31) | BIT(16); diff --git a/drivers/staging/rtl8712/rtl8712_led.c b/drivers/staging/rtl8712/rtl8712_led.c index db99129d3169..5901026949f2 100644 --- a/drivers/staging/rtl8712/rtl8712_led.c +++ b/drivers/staging/rtl8712/rtl8712_led.c @@ -75,7 +75,7 @@ static void BlinkWorkItemCallback(struct work_struct *work); * Initialize an LED_871x object. */ static void InitLed871x(struct _adapter *padapter, struct LED_871x *pLed, - enum LED_PIN_871x LedPin) + enum LED_PIN_871x LedPin) { pLed->padapter = padapter; pLed->LedPin = LedPin; diff --git a/drivers/staging/rtl8712/rtl8712_recv.c b/drivers/staging/rtl8712/rtl8712_recv.c index 9901815604f4..06de031be6a9 100644 --- a/drivers/staging/rtl8712/rtl8712_recv.c +++ b/drivers/staging/rtl8712/rtl8712_recv.c @@ -61,13 +61,13 @@ void r8712_init_recv_priv(struct recv_priv *precvpriv, precvbuf->ref_cnt = 0; precvbuf->adapter = padapter; list_add_tail(&precvbuf->list, - &(precvpriv->free_recv_buf_queue.queue)); + &(precvpriv->free_recv_buf_queue.queue)); precvbuf++; } precvpriv->free_recv_buf_queue_cnt = NR_RECVBUFF; tasklet_init(&precvpriv->recv_tasklet, - (void(*)(unsigned long))recv_tasklet, - (unsigned long)padapter); + (void(*)(unsigned long))recv_tasklet, + (unsigned long)padapter); skb_queue_head_init(&precvpriv->rx_skb_queue); skb_queue_head_init(&precvpriv->free_recv_skb_queue); @@ -119,7 +119,7 @@ void r8712_init_recvbuf(struct _adapter *padapter, struct recv_buf *precvbuf) } void r8712_free_recvframe(union recv_frame *precvframe, - struct __queue *pfree_recv_queue) + struct __queue *pfree_recv_queue) { unsigned long irqL; struct _adapter *padapter = precvframe->u.hdr.adapter; @@ -140,7 +140,7 @@ void r8712_free_recvframe(union recv_frame *precvframe, } static void update_recvframe_attrib_from_recvstat(struct rx_pkt_attrib *pattrib, - struct recv_stat *prxstat) + struct recv_stat *prxstat) { u16 drvinfo_sz; @@ -177,7 +177,7 @@ static void update_recvframe_attrib_from_recvstat(struct rx_pkt_attrib *pattrib, /*perform defrag*/ static union recv_frame *recvframe_defrag(struct _adapter *adapter, - struct __queue *defrag_q) + struct __queue *defrag_q) { struct list_head *plist, *phead; u8 wlanhdr_offset; @@ -289,7 +289,6 @@ union recv_frame *r8712_recvframe_chk_defrag(struct _adapter *padapter, r8712_free_recvframe(precv_frame, pfree_recv_queue); prtnframe = NULL; } - } if ((ismfrag == 0) && (fragnum != 0)) { /* the last fragment frame @@ -379,26 +378,26 @@ static void amsdu_to_msdu(struct _adapter *padapter, union recv_frame *prframe) /* convert hdr + possible LLC headers into Ethernet header */ eth_type = (sub_skb->data[6] << 8) | sub_skb->data[7]; if (sub_skb->len >= 8 && - ((!memcmp(sub_skb->data, rfc1042_header, SNAP_SIZE) && - eth_type != ETH_P_AARP && eth_type != ETH_P_IPX) || - !memcmp(sub_skb->data, bridge_tunnel_header, SNAP_SIZE))) { + ((!memcmp(sub_skb->data, rfc1042_header, SNAP_SIZE) && + eth_type != ETH_P_AARP && eth_type != ETH_P_IPX) || + !memcmp(sub_skb->data, bridge_tunnel_header, SNAP_SIZE))) { /* remove RFC1042 or Bridge-Tunnel encapsulation and * replace EtherType */ skb_pull(sub_skb, SNAP_SIZE); memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->src, - ETH_ALEN); + ETH_ALEN); memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->dst, - ETH_ALEN); + ETH_ALEN); } else { __be16 len; /* Leave Ethernet header part of hdr and full payload */ len = htons(sub_skb->len); memcpy(skb_push(sub_skb, 2), &len, 2); memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->src, - ETH_ALEN); + ETH_ALEN); memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->dst, - ETH_ALEN); + ETH_ALEN); } /* Indicate the packets to upper layer */ if (sub_skb) { @@ -438,7 +437,6 @@ void r8712_rxcmd_event_hdl(struct _adapter *padapter, void *prxcmdbuf) r8712_event_handle(padapter, (__le32 *)poffset); poffset += (cmd_len + 8);/*8 bytes alignment*/ } while (le32_to_cpu(voffset) & BIT(31)); - } static int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, @@ -472,7 +470,7 @@ static int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, } static int enqueue_reorder_recvframe(struct recv_reorder_ctrl *preorder_ctrl, - union recv_frame *prframe) + union recv_frame *prframe) { struct list_head *phead, *plist; union recv_frame *pnextrframe; @@ -499,8 +497,8 @@ static int enqueue_reorder_recvframe(struct recv_reorder_ctrl *preorder_ctrl, } int r8712_recv_indicatepkts_in_order(struct _adapter *padapter, - struct recv_reorder_ctrl *preorder_ctrl, - int bforced) + struct recv_reorder_ctrl *preorder_ctrl, + int bforced) { struct list_head *phead, *plist; union recv_frame *prframe; @@ -530,7 +528,7 @@ int r8712_recv_indicatepkts_in_order(struct _adapter *padapter, plist = plist->next; list_del_init(&(prframe->u.hdr.list)); if (SN_EQUAL(preorder_ctrl->indicate_seq, - pattrib->seq_num)) + pattrib->seq_num)) preorder_ctrl->indicate_seq = (preorder_ctrl->indicate_seq + 1) % 4096; /*indicate this recv_frame*/ @@ -555,7 +553,7 @@ int r8712_recv_indicatepkts_in_order(struct _adapter *padapter, } static int recv_indicatepkt_reorder(struct _adapter *padapter, - union recv_frame *prframe) + union recv_frame *prframe) { unsigned long irql; struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib; @@ -624,7 +622,7 @@ void r8712_reordering_ctrl_timeout_handler(void *pcontext) } static int r8712_process_recv_indicatepkts(struct _adapter *padapter, - union recv_frame *prframe) + union recv_frame *prframe) { int retval = _SUCCESS; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c index 944336e0d2e2..363b82e3e7c6 100644 --- a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c +++ b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c @@ -142,9 +142,9 @@ static noinline_for_stack char *translate_scan_wpa(struct iw_request_info *info, memset(buf, 0, MAX_WPA_IE_LEN); n = sprintf(buf, "wpa_ie="); for (i = 0; i < wpa_len; i++) { - n += snprintf(buf + n, MAX_WPA_IE_LEN - n, + n += scnprintf(buf + n, MAX_WPA_IE_LEN - n, "%02x", wpa_ie[i]); - if (n >= MAX_WPA_IE_LEN) + if (n == MAX_WPA_IE_LEN-1) break; } memset(iwe, 0, sizeof(*iwe)); @@ -162,9 +162,9 @@ static noinline_for_stack char *translate_scan_wpa(struct iw_request_info *info, memset(buf, 0, MAX_WPA_IE_LEN); n = sprintf(buf, "rsn_ie="); for (i = 0; i < rsn_len; i++) { - n += snprintf(buf + n, MAX_WPA_IE_LEN - n, + n += scnprintf(buf + n, MAX_WPA_IE_LEN - n, "%02x", rsn_ie[i]); - if (n >= MAX_WPA_IE_LEN) + if (n == MAX_WPA_IE_LEN-1) break; } memset(iwe, 0, sizeof(*iwe)); diff --git a/drivers/staging/rtl8712/rtl871x_mp_ioctl.c b/drivers/staging/rtl8712/rtl871x_mp_ioctl.c index aa8f8500cbb2..29b85330815f 100644 --- a/drivers/staging/rtl8712/rtl871x_mp_ioctl.c +++ b/drivers/staging/rtl8712/rtl871x_mp_ioctl.c @@ -231,8 +231,7 @@ end_of_mp_stop_test: return _SUCCESS; } -uint oid_rt_pro_set_data_rate_hdl(struct oid_par_priv - *poid_par_priv) +uint oid_rt_pro_set_data_rate_hdl(struct oid_par_priv *poid_par_priv) { struct _adapter *Adapter = (struct _adapter *) (poid_par_priv->adapter_context); @@ -283,17 +282,15 @@ uint oid_rt_pro_stop_test_hdl(struct oid_par_priv *poid_par_priv) { struct _adapter *Adapter = (struct _adapter *) (poid_par_priv->adapter_context); - uint status = RNDIS_STATUS_SUCCESS; if (poid_par_priv->type_of_oid != SET_OID) return RNDIS_STATUS_NOT_ACCEPTED; if (mp_stop_test(Adapter) == _FAIL) - status = RNDIS_STATUS_NOT_ACCEPTED; - return status; + return RNDIS_STATUS_NOT_ACCEPTED; + return RNDIS_STATUS_SUCCESS; } -uint oid_rt_pro_set_channel_direct_call_hdl(struct oid_par_priv - *poid_par_priv) +uint oid_rt_pro_set_channel_direct_call_hdl(struct oid_par_priv *poid_par_priv) { struct _adapter *Adapter = (struct _adapter *) (poid_par_priv->adapter_context); @@ -328,8 +325,7 @@ uint oid_rt_pro_set_antenna_bb_hdl(struct oid_par_priv *poid_par_priv) return RNDIS_STATUS_SUCCESS; } -uint oid_rt_pro_set_tx_power_control_hdl( - struct oid_par_priv *poid_par_priv) +uint oid_rt_pro_set_tx_power_control_hdl(struct oid_par_priv *poid_par_priv) { struct _adapter *Adapter = (struct _adapter *) (poid_par_priv->adapter_context); @@ -347,71 +343,61 @@ uint oid_rt_pro_set_tx_power_control_hdl( return RNDIS_STATUS_SUCCESS; } -uint oid_rt_pro_query_tx_packet_sent_hdl( - struct oid_par_priv *poid_par_priv) +uint oid_rt_pro_query_tx_packet_sent_hdl(struct oid_par_priv *poid_par_priv) { - uint status = RNDIS_STATUS_SUCCESS; struct _adapter *Adapter = (struct _adapter *) (poid_par_priv->adapter_context); - if (poid_par_priv->type_of_oid != QUERY_OID) { - status = RNDIS_STATUS_NOT_ACCEPTED; - return status; - } + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + if (poid_par_priv->information_buf_len == sizeof(u32)) { *(u32 *)poid_par_priv->information_buf = Adapter->mppriv.tx_pktcount; *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; } else { - status = RNDIS_STATUS_INVALID_LENGTH; + return RNDIS_STATUS_INVALID_LENGTH; } - return status; + return RNDIS_STATUS_SUCCESS; } -uint oid_rt_pro_query_rx_packet_received_hdl( - struct oid_par_priv *poid_par_priv) +uint oid_rt_pro_query_rx_packet_received_hdl(struct oid_par_priv *poid_par_priv) { - uint status = RNDIS_STATUS_SUCCESS; struct _adapter *Adapter = (struct _adapter *) (poid_par_priv->adapter_context); - if (poid_par_priv->type_of_oid != QUERY_OID) { - status = RNDIS_STATUS_NOT_ACCEPTED; - return status; - } + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + if (poid_par_priv->information_buf_len == sizeof(u32)) { *(u32 *)poid_par_priv->information_buf = Adapter->mppriv.rx_pktcount; *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; } else { - status = RNDIS_STATUS_INVALID_LENGTH; + return RNDIS_STATUS_INVALID_LENGTH; } - return status; + return RNDIS_STATUS_SUCCESS; } -uint oid_rt_pro_query_rx_packet_crc32_error_hdl( - struct oid_par_priv *poid_par_priv) +uint oid_rt_pro_query_rx_packet_crc32_error_hdl(struct oid_par_priv *poid_par_priv) { - uint status = RNDIS_STATUS_SUCCESS; struct _adapter *Adapter = (struct _adapter *) (poid_par_priv->adapter_context); - if (poid_par_priv->type_of_oid != QUERY_OID) { - status = RNDIS_STATUS_NOT_ACCEPTED; - return status; - } + if (poid_par_priv->type_of_oid != QUERY_OID) + return RNDIS_STATUS_NOT_ACCEPTED; + if (poid_par_priv->information_buf_len == sizeof(u32)) { *(u32 *)poid_par_priv->information_buf = Adapter->mppriv.rx_crcerrpktcount; *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len; } else { - status = RNDIS_STATUS_INVALID_LENGTH; + return RNDIS_STATUS_INVALID_LENGTH; } - return status; + return RNDIS_STATUS_SUCCESS; } -uint oid_rt_pro_reset_tx_packet_sent_hdl(struct oid_par_priv - *poid_par_priv) +uint oid_rt_pro_reset_tx_packet_sent_hdl(struct oid_par_priv *poid_par_priv) { struct _adapter *Adapter = (struct _adapter *) (poid_par_priv->adapter_context); @@ -422,10 +408,8 @@ uint oid_rt_pro_reset_tx_packet_sent_hdl(struct oid_par_priv return RNDIS_STATUS_SUCCESS; } -uint oid_rt_pro_reset_rx_packet_received_hdl(struct oid_par_priv - *poid_par_priv) +uint oid_rt_pro_reset_rx_packet_received_hdl(struct oid_par_priv *poid_par_priv) { - uint status = RNDIS_STATUS_SUCCESS; struct _adapter *Adapter = (struct _adapter *) (poid_par_priv->adapter_context); @@ -435,13 +419,12 @@ uint oid_rt_pro_reset_rx_packet_received_hdl(struct oid_par_priv Adapter->mppriv.rx_pktcount = 0; Adapter->mppriv.rx_crcerrpktcount = 0; } else { - status = RNDIS_STATUS_INVALID_LENGTH; + return RNDIS_STATUS_INVALID_LENGTH; } - return status; + return RNDIS_STATUS_SUCCESS; } -uint oid_rt_reset_phy_rx_packet_count_hdl(struct oid_par_priv - *poid_par_priv) +uint oid_rt_reset_phy_rx_packet_count_hdl(struct oid_par_priv *poid_par_priv) { struct _adapter *Adapter = (struct _adapter *) (poid_par_priv->adapter_context); @@ -452,8 +435,7 @@ uint oid_rt_reset_phy_rx_packet_count_hdl(struct oid_par_priv return RNDIS_STATUS_SUCCESS; } -uint oid_rt_get_phy_rx_packet_received_hdl(struct oid_par_priv - *poid_par_priv) +uint oid_rt_get_phy_rx_packet_received_hdl(struct oid_par_priv *poid_par_priv) { struct _adapter *Adapter = (struct _adapter *) (poid_par_priv->adapter_context); @@ -468,8 +450,7 @@ uint oid_rt_get_phy_rx_packet_received_hdl(struct oid_par_priv return RNDIS_STATUS_SUCCESS; } -uint oid_rt_get_phy_rx_packet_crc32_error_hdl(struct oid_par_priv - *poid_par_priv) +uint oid_rt_get_phy_rx_packet_crc32_error_hdl(struct oid_par_priv *poid_par_priv) { struct _adapter *Adapter = (struct _adapter *) (poid_par_priv->adapter_context); @@ -484,8 +465,7 @@ uint oid_rt_get_phy_rx_packet_crc32_error_hdl(struct oid_par_priv return RNDIS_STATUS_SUCCESS; } -uint oid_rt_pro_set_modulation_hdl(struct oid_par_priv - *poid_par_priv) +uint oid_rt_pro_set_modulation_hdl(struct oid_par_priv *poid_par_priv) { struct _adapter *Adapter = (struct _adapter *) (poid_par_priv->adapter_context); @@ -497,8 +477,7 @@ uint oid_rt_pro_set_modulation_hdl(struct oid_par_priv return RNDIS_STATUS_SUCCESS; } -uint oid_rt_pro_set_continuous_tx_hdl(struct oid_par_priv - *poid_par_priv) +uint oid_rt_pro_set_continuous_tx_hdl(struct oid_par_priv *poid_par_priv) { struct _adapter *Adapter = (struct _adapter *) (poid_par_priv->adapter_context); @@ -511,8 +490,7 @@ uint oid_rt_pro_set_continuous_tx_hdl(struct oid_par_priv return RNDIS_STATUS_SUCCESS; } -uint oid_rt_pro_set_single_carrier_tx_hdl(struct oid_par_priv - *poid_par_priv) +uint oid_rt_pro_set_single_carrier_tx_hdl(struct oid_par_priv *poid_par_priv) { struct _adapter *Adapter = (struct _adapter *) (poid_par_priv->adapter_context); @@ -525,8 +503,7 @@ uint oid_rt_pro_set_single_carrier_tx_hdl(struct oid_par_priv return RNDIS_STATUS_SUCCESS; } -uint oid_rt_pro_set_carrier_suppression_tx_hdl(struct oid_par_priv - *poid_par_priv) +uint oid_rt_pro_set_carrier_suppression_tx_hdl(struct oid_par_priv *poid_par_priv) { struct _adapter *Adapter = (struct _adapter *) (poid_par_priv->adapter_context); @@ -539,8 +516,7 @@ uint oid_rt_pro_set_carrier_suppression_tx_hdl(struct oid_par_priv return RNDIS_STATUS_SUCCESS; } -uint oid_rt_pro_set_single_tone_tx_hdl(struct oid_par_priv - *poid_par_priv) +uint oid_rt_pro_set_single_tone_tx_hdl(struct oid_par_priv *poid_par_priv) { struct _adapter *Adapter = (struct _adapter *) (poid_par_priv->adapter_context); @@ -553,8 +529,7 @@ uint oid_rt_pro_set_single_tone_tx_hdl(struct oid_par_priv return RNDIS_STATUS_SUCCESS; } -uint oid_rt_pro_read_register_hdl(struct oid_par_priv - *poid_par_priv) +uint oid_rt_pro_read_register_hdl(struct oid_par_priv *poid_par_priv) { struct _adapter *Adapter = (struct _adapter *) (poid_par_priv->adapter_context); @@ -735,8 +710,7 @@ uint oid_rt_pro_write_efuse_hdl(struct oid_par_priv *poid_par_priv) } /*----------------------------------------------------------------------*/ -uint oid_rt_get_efuse_current_size_hdl(struct oid_par_priv - *poid_par_priv) +uint oid_rt_get_efuse_current_size_hdl(struct oid_par_priv *poid_par_priv) { struct _adapter *Adapter = (struct _adapter *) (poid_par_priv->adapter_context); @@ -829,8 +803,7 @@ uint oid_rt_set_bandwidth_hdl(struct oid_par_priv *poid_par_priv) return RNDIS_STATUS_SUCCESS; } -uint oid_rt_set_rx_packet_type_hdl(struct oid_par_priv - *poid_par_priv) +uint oid_rt_set_rx_packet_type_hdl(struct oid_par_priv *poid_par_priv) { struct _adapter *Adapter = (struct _adapter *) (poid_par_priv->adapter_context); diff --git a/drivers/staging/rtl8723bs/core/rtw_ap.c b/drivers/staging/rtl8723bs/core/rtw_ap.c index 6d18d23acdc0..7117d16a30f9 100644 --- a/drivers/staging/rtl8723bs/core/rtw_ap.c +++ b/drivers/staging/rtl8723bs/core/rtw_ap.c @@ -216,8 +216,9 @@ void expire_timeout_chk(struct adapter *padapter) /* check auth_queue */ #ifdef DBG_EXPIRATION_CHK if (phead != plist) { - DBG_871X(FUNC_NDEV_FMT" auth_list, cnt:%u\n" - , FUNC_NDEV_ARG(padapter->pnetdev), pstapriv->auth_list_cnt); + DBG_871X(FUNC_NDEV_FMT " auth_list, cnt:%u\n", + FUNC_NDEV_ARG(padapter->pnetdev), + pstapriv->auth_list_cnt); } #endif while (phead != plist) { @@ -1446,14 +1447,14 @@ u8 rtw_ap_set_pairwise_key(struct adapter *padapter, struct sta_info *psta) u8 res = _SUCCESS; ph2c = rtw_zmalloc(sizeof(struct cmd_obj)); - if (ph2c == NULL) { + if (!ph2c) { res = _FAIL; goto exit; } psetstakey_para = rtw_zmalloc(sizeof(struct set_stakey_parm)); if (psetstakey_para == NULL) { - kfree((u8 *)ph2c); + kfree(ph2c); res = _FAIL; goto exit; } @@ -1496,7 +1497,7 @@ static int rtw_ap_set_key( } psetkeyparm = rtw_zmalloc(sizeof(struct setkey_parm)); if (psetkeyparm == NULL) { - kfree((unsigned char *)pcmd); + kfree(pcmd); res = _FAIL; goto exit; } diff --git a/drivers/staging/rtl8723bs/core/rtw_cmd.c b/drivers/staging/rtl8723bs/core/rtw_cmd.c index 8d93c2f26890..13a9b54b4561 100644 --- a/drivers/staging/rtl8723bs/core/rtw_cmd.c +++ b/drivers/staging/rtl8723bs/core/rtw_cmd.c @@ -372,13 +372,13 @@ void rtw_free_cmd_obj(struct cmd_obj *pcmd) if ((pcmd->cmdcode != _JoinBss_CMD_) && (pcmd->cmdcode != _CreateBss_CMD_)) { /* free parmbuf in cmd_obj */ - kfree((unsigned char *)pcmd->parmbuf); + kfree(pcmd->parmbuf); } if (pcmd->rsp != NULL) { if (pcmd->rspsz != 0) { /* free rsp in cmd_obj */ - kfree((unsigned char *)pcmd->rsp); + kfree(pcmd->rsp); } } @@ -507,19 +507,9 @@ post_process: cmd_process_time = jiffies_to_msecs(jiffies - cmd_start_time); if (cmd_process_time > 1000) { - if (pcmd->cmdcode == GEN_CMD_CODE(_Set_Drv_Extra)) { - DBG_871X(ADPT_FMT" cmd =%d process_time =%lu > 1 sec\n", - ADPT_ARG(pcmd->padapter), pcmd->cmdcode, cmd_process_time); - /* rtw_warn_on(1); */ - } else if (pcmd->cmdcode == GEN_CMD_CODE(_Set_MLME_EVT)) { - DBG_871X(ADPT_FMT" cmd =%d, process_time =%lu > 1 sec\n", - ADPT_ARG(pcmd->padapter), pcmd->cmdcode, cmd_process_time); - /* rtw_warn_on(1); */ - } else { - DBG_871X(ADPT_FMT" cmd =%d, process_time =%lu > 1 sec\n", - ADPT_ARG(pcmd->padapter), pcmd->cmdcode, cmd_process_time); - /* rtw_warn_on(1); */ - } + DBG_871X(ADPT_FMT "cmd= %d process_time= %lu > 1 sec\n", + ADPT_ARG(pcmd->padapter), pcmd->cmdcode, + cmd_process_time); } /* call callback function for post-processed */ diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme.c b/drivers/staging/rtl8723bs/core/rtw_mlme.c index 34adf5789c98..71fcb466019a 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme.c @@ -19,7 +19,7 @@ int rtw_init_mlme_priv(struct adapter *padapter) int i; u8 *pbuf; struct wlan_network *pnetwork; - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; int res = _SUCCESS; pmlmepriv->nic_hdl = (u8 *)padapter; @@ -40,7 +40,7 @@ int rtw_init_mlme_priv(struct adapter *padapter) pbuf = vzalloc(array_size(MAX_BSS_CNT, sizeof(struct wlan_network))); - if (pbuf == NULL) { + if (!pbuf) { res = _FAIL; goto exit; } @@ -112,9 +112,8 @@ void _rtw_free_mlme_priv(struct mlme_priv *pmlmepriv) { if (pmlmepriv) { rtw_free_mlme_priv_ie_data(pmlmepriv); - if (pmlmepriv->free_bss_buf) { + if (pmlmepriv->free_bss_buf) vfree(pmlmepriv->free_bss_buf); - } } } @@ -185,10 +184,10 @@ void _rtw_free_network(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwor /* _irqL irqL; */ struct __queue *free_queue = &(pmlmepriv->free_bss_pool); - if (pnetwork == NULL) + if (!pnetwork) return; - if (pnetwork->fixed == true) + if (pnetwork->fixed) return; if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) || @@ -209,7 +208,6 @@ void _rtw_free_network(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwor pmlmepriv->num_of_scanned--; - /* DBG_871X("_rtw_free_network:SSID =%s\n", pnetwork->network.Ssid.Ssid); */ spin_unlock_bh(&free_queue->lock); @@ -220,10 +218,10 @@ void _rtw_free_network_nolock(struct mlme_priv *pmlmepriv, struct wlan_network * struct __queue *free_queue = &(pmlmepriv->free_bss_pool); - if (pnetwork == NULL) + if (!pnetwork) return; - if (pnetwork->fixed == true) + if (pnetwork->fixed) return; /* spin_lock_irqsave(&free_queue->lock, irqL); */ @@ -301,12 +299,8 @@ void rtw_free_network_queue(struct adapter *padapter, u8 isfreeall) spin_unlock_bh(&scanned_queue->lock); } - - - sint rtw_if_up(struct adapter *padapter) { - sint res; if (padapter->bDriverStopped || padapter->bSurpriseRemoved || @@ -318,7 +312,6 @@ sint rtw_if_up(struct adapter *padapter) return res; } - void rtw_generate_random_ibss(u8 *pibss) { unsigned long curtime = jiffies; @@ -329,7 +322,6 @@ void rtw_generate_random_ibss(u8 *pibss) pibss[3] = (u8)(curtime & 0xff) ;/* p[0]; */ pibss[4] = (u8)((curtime>>8) & 0xff) ;/* p[1]; */ pibss[5] = (u8)((curtime>>16) & 0xff) ;/* p[2]; */ - return; } u8 *rtw_get_capability_from_ie(u8 *ie) @@ -337,7 +329,6 @@ u8 *rtw_get_capability_from_ie(u8 *ie) return ie + 8 + 2; } - u16 rtw_get_capability(struct wlan_bssid_ex *bss) { __le16 val; @@ -425,7 +416,6 @@ int is_same_network(struct wlan_bssid_ex *src, struct wlan_bssid_ex *dst, u8 fea memcpy((u8 *)&tmps, rtw_get_capability_from_ie(src->IEs), 2); memcpy((u8 *)&tmpd, rtw_get_capability_from_ie(dst->IEs), 2); - s_cap = le16_to_cpu(tmps); d_cap = le16_to_cpu(tmpd); @@ -467,7 +457,6 @@ struct wlan_network *rtw_get_oldest_wlan_network(struct __queue *scanned_queue) { struct list_head *plist, *phead; - struct wlan_network *pwlan = NULL; struct wlan_network *oldest = NULL; @@ -482,7 +471,7 @@ struct wlan_network *rtw_get_oldest_wlan_network(struct __queue *scanned_queue) pwlan = LIST_CONTAINOR(plist, struct wlan_network, list); - if (pwlan->fixed != true) { + if (!pwlan->fixed) { if (oldest == NULL || time_after(oldest->last_scanned, pwlan->last_scanned)) oldest = pwlan; } @@ -579,12 +568,8 @@ static void update_current_network(struct adapter *adapter, struct wlan_bssid_ex } } - /* - Caller must hold pmlmepriv->lock first. - - */ void rtw_update_scanned_network(struct adapter *adapter, struct wlan_bssid_ex *target) { @@ -625,7 +610,6 @@ void rtw_update_scanned_network(struct adapter *adapter, struct wlan_bssid_ex *t } - /* If we didn't find a match, then get a new network slot to initialize * with this beacon's information */ /* if (phead == plist) { */ @@ -634,7 +618,7 @@ void rtw_update_scanned_network(struct adapter *adapter, struct wlan_bssid_ex *t /* If there are no more slots, expire the oldest */ /* list_del_init(&oldest->list); */ pnetwork = oldest; - if (pnetwork == NULL) { + if (!pnetwork) { RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("\n\n\nsomething wrong here\n\n\n")); goto exit; } @@ -655,7 +639,7 @@ void rtw_update_scanned_network(struct adapter *adapter, struct wlan_bssid_ex *t pnetwork = rtw_alloc_network(pmlmepriv); /* will update scan_time */ - if (pnetwork == NULL) { + if (!pnetwork) { RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("\n\n\nsomething wrong here\n\n\n")); goto exit; } @@ -739,7 +723,7 @@ int rtw_is_desired_network(struct adapter *adapter, struct wlan_network *pnetwor privacy = pnetwork->network.Privacy; if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) { - if (rtw_get_wps_ie(pnetwork->network.IEs+_FIXED_IE_LENGTH_, pnetwork->network.IELength-_FIXED_IE_LENGTH_, NULL, &wps_ielen) != NULL) + if (rtw_get_wps_ie(pnetwork->network.IEs+_FIXED_IE_LENGTH_, pnetwork->network.IELength-_FIXED_IE_LENGTH_, NULL, &wps_ielen)) return true; else return false; @@ -754,15 +738,13 @@ int rtw_is_desired_network(struct adapter *adapter, struct wlan_network *pnetwor if (psecuritypriv->ndisauthtype == Ndis802_11AuthModeWPA2PSK) { p = rtw_get_ie(pnetwork->network.IEs + _BEACON_IE_OFFSET_, _RSN_IE_2_, &ie_len, (pnetwork->network.IELength - _BEACON_IE_OFFSET_)); - if (p && ie_len > 0) { + if (p && ie_len > 0) bselected = true; - } else { + else bselected = false; - } } } - if ((desired_encmode != Ndis802_11EncryptionDisabled) && (privacy == 0)) { DBG_871X("desired_encmode: %d, privacy: %d\n", desired_encmode, privacy); bselected = false; @@ -773,7 +755,6 @@ int rtw_is_desired_network(struct adapter *adapter, struct wlan_network *pnetwor bselected = false; } - return bselected; } @@ -783,7 +764,6 @@ void rtw_atimdone_event_callback(struct adapter *adapter, u8 *pbuf) RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("receive atimdone_event\n")); } - void rtw_survey_event_callback(struct adapter *adapter, u8 *pbuf) { u32 len; @@ -800,7 +780,6 @@ void rtw_survey_event_callback(struct adapter *adapter, u8 *pbuf) return; } - spin_lock_bh(&pmlmepriv->lock); /* update IBSS_network 's timestamp */ @@ -823,21 +802,16 @@ void rtw_survey_event_callback(struct adapter *adapter, u8 *pbuf) /* lock pmlmepriv->lock when you accessing network_q */ if ((check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) == false) { - if (pnetwork->Ssid.Ssid[0] == 0) { + if (pnetwork->Ssid.Ssid[0] == 0) pnetwork->Ssid.SsidLength = 0; - } rtw_add_network(adapter, pnetwork); } exit: spin_unlock_bh(&pmlmepriv->lock); - - return; } - - void rtw_surveydone_event_callback(struct adapter *adapter, u8 *pbuf) { u8 timer_cancelled = false; @@ -868,12 +842,11 @@ void rtw_surveydone_event_callback(struct adapter *adapter, u8 *pbuf) if (timer_cancelled) _cancel_timer(&pmlmepriv->scan_to_timer, &timer_cancelled); - spin_lock_bh(&pmlmepriv->lock); rtw_set_signal_stat_timer(&adapter->recvpriv); - if (pmlmepriv->to_join == true) { + if (pmlmepriv->to_join) { if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true)) { if (check_fwstate(pmlmepriv, _FW_LINKED) == false) { set_fwstate(pmlmepriv, _FW_UNDER_LINKING); @@ -896,9 +869,8 @@ void rtw_surveydone_event_callback(struct adapter *adapter, u8 *pbuf) pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE; - if (rtw_createbss_cmd(adapter) != _SUCCESS) { - RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Error =>rtw_createbss_cmd status FAIL\n")); - } + if (rtw_createbss_cmd(adapter) != _SUCCESS) + RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Error =>rtw_createbss_cmd status FAIL\n")); pmlmepriv->to_join = false; } @@ -1009,7 +981,6 @@ static void find_network(struct adapter *adapter) else RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("rtw_free_assoc_resources : pwlan == NULL\n\n")); - if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) && (adapter->stapriv.asoc_sta_count == 1)) rtw_free_network_nolock(adapter, pwlan); @@ -1169,9 +1140,8 @@ static struct sta_info *rtw_joinbss_update_stainfo(struct adapter *padapter, str struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; psta = rtw_get_stainfo(pstapriv, pnetwork->network.MacAddress); - if (psta == NULL) { + if (!psta) psta = rtw_alloc_stainfo(pstapriv, pnetwork->network.MacAddress); - } if (psta) { /* update ptarget_sta */ @@ -1189,7 +1159,6 @@ static struct sta_info *rtw_joinbss_update_stainfo(struct adapter *padapter, str psta->wireless_mode = pmlmeext->cur_wireless_mode; psta->raid = networktype_to_raid_ex(padapter, psta); - /* sta mode */ rtw_hal_set_odm_var(padapter, HAL_ODM_STA_INFO, psta, true); @@ -1221,7 +1190,6 @@ static struct sta_info *rtw_joinbss_update_stainfo(struct adapter *padapter, str padapter->securitypriv.wps_ie_len = 0; } - /* for A-MPDU Rx reordering buffer control for bmc_sta & sta_info */ /* if A-MPDU Rx is enabled, resetting rx_ordering_ctrl wstart_b(indicate_seq) to default value = 0xffff */ /* todo: check if AP can send A-MPDU packets */ @@ -1238,7 +1206,6 @@ static struct sta_info *rtw_joinbss_update_stainfo(struct adapter *padapter, str preorder_ctrl->wsize_b = 64;/* max_ampdu_sz;ex. 32(kbytes) -> wsize_b =32 */ } - bmc_sta = rtw_get_bcmc_stainfo(padapter); if (bmc_sta) { for (i = 0; i < 16 ; i++) { @@ -1272,7 +1239,6 @@ static void rtw_joinbss_update_network(struct adapter *padapter, struct wlan_net RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("\nfw_state:%x, BSSID:"MAC_FMT"\n" , get_fwstate(pmlmepriv), MAC_ARG(pnetwork->network.MacAddress))); - /* why not use ptarget_wlan?? */ memcpy(&cur_network->network, &pnetwork->network, pnetwork->network.Length); /* some IEs in pnetwork is wrong, so we should use ptarget_wlan IEs */ @@ -1281,7 +1247,6 @@ static void rtw_joinbss_update_network(struct adapter *padapter, struct wlan_net cur_network->aid = pnetwork->join_res; - rtw_set_signal_stat_timer(&padapter->recvpriv); padapter->recvpriv.signal_strength = ptarget_wlan->network.PhyInfo.SignalStrength; @@ -1349,12 +1314,10 @@ void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf) rtw_get_encrypt_decrypt_from_registrypriv(adapter); - - if (pmlmepriv->assoc_ssid.SsidLength == 0) { + if (pmlmepriv->assoc_ssid.SsidLength == 0) RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("@@@@@ joinbss event call back for Any SSid\n")); - } else { + else RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("@@@@@ rtw_joinbss_event_callback for SSid:%s\n", pmlmepriv->assoc_ssid.Ssid)); - } the_same_macaddr = !memcmp(pnetwork->network.MacAddress, cur_network->network.MacAddress, ETH_ALEN); @@ -1377,7 +1340,7 @@ void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf) if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) { /* s1. find ptarget_wlan */ if (check_fwstate(pmlmepriv, _FW_LINKED)) { - if (the_same_macaddr == true) { + if (the_same_macaddr) { ptarget_wlan = rtw_find_network(&pmlmepriv->scanned_queue, cur_network->network.MacAddress); } else { pcur_wlan = rtw_find_network(&pmlmepriv->scanned_queue, cur_network->network.MacAddress); @@ -1412,11 +1375,10 @@ void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf) goto ignore_joinbss_callback; } - /* s3. find ptarget_sta & update ptarget_sta after update cur_network only for station mode */ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) { ptarget_sta = rtw_joinbss_update_stainfo(adapter, pnetwork); - if (ptarget_sta == NULL) { + if (!ptarget_sta) { RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Can't update stainfo when joinbss_event callback\n")); spin_unlock_bh(&(pmlmepriv->scanned_queue.lock)); goto ignore_joinbss_callback; @@ -1432,7 +1394,6 @@ void rtw_joinbss_event_prehandle(struct adapter *adapter, u8 *pbuf) RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("adhoc mode, fw_state:%x", get_fwstate(pmlmepriv))); } - /* s5. Cancel assoc_timer */ _cancel_timer(&pmlmepriv->assoc_timer, &timer_cancelled); @@ -1506,7 +1467,7 @@ void rtw_sta_media_status_rpt(struct adapter *adapter, struct sta_info *psta, u3 { u16 media_status_rpt; - if (psta == NULL) + if (!psta) return; media_status_rpt = (u16)((psta->mac_id<<8)|mstatus); /* MACID|OPMODE:1 connect */ @@ -1564,7 +1525,7 @@ void rtw_stassoc_event_callback(struct adapter *adapter, u8 *pbuf) /* for AD-HOC mode */ psta = rtw_get_stainfo(&adapter->stapriv, pstassoc->macaddr); - if (psta != NULL) { + if (psta) { /* the sta have been in sta_info_queue => do nothing */ RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Error: rtw_stassoc_event_callback: sta has been in sta_hash_queue\n")); @@ -1573,7 +1534,7 @@ void rtw_stassoc_event_callback(struct adapter *adapter, u8 *pbuf) } psta = rtw_alloc_stainfo(&adapter->stapriv, pstassoc->macaddr); - if (psta == NULL) { + if (!psta) { RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Can't alloc sta_info when rtw_stassoc_event_callback\n")); return; } @@ -1591,7 +1552,6 @@ void rtw_stassoc_event_callback(struct adapter *adapter, u8 *pbuf) if (adapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) psta->dot118021XPrivacy = adapter->securitypriv.dot11PrivacyAlgrthm; - psta->ieee8021x_blocked = false; spin_lock_bh(&pmlmepriv->lock); @@ -1612,7 +1572,6 @@ void rtw_stassoc_event_callback(struct adapter *adapter, u8 *pbuf) spin_unlock_bh(&pmlmepriv->lock); - mlmeext_sta_add_event_callback(adapter, psta); } @@ -1648,7 +1607,6 @@ void rtw_stadel_event_callback(struct adapter *adapter, u8 *pbuf) if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) return; - mlmeext_sta_del_event_callback(adapter); spin_lock_bh(&pmlmepriv->lock); @@ -1726,13 +1684,8 @@ void rtw_stadel_event_callback(struct adapter *adapter, u8 *pbuf) _clr_fwstate_(pmlmepriv, WIFI_ADHOC_STATE); } - if (rtw_createbss_cmd(adapter) != _SUCCESS) { - + if (rtw_createbss_cmd(adapter) != _SUCCESS) RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("***Error =>stadel_event_callback: rtw_createbss_cmd status FAIL***\n ")); - - } - - } } @@ -1750,7 +1703,6 @@ void rtw_cpwm_event_callback(struct adapter *padapter, u8 *pbuf) cpwm_int_hdl(padapter, preportpwrstate); } - void rtw_wmm_event_callback(struct adapter *padapter, u8 *pbuf) { WMMOnAssocRsp(padapter); @@ -1840,8 +1792,6 @@ void rtw_mlme_reset_auto_scan_int(struct adapter *adapter) mlme->auto_scan_int_ms = mlme->roam_scan_int_ms; } else mlme->auto_scan_int_ms = 0; /* disabled */ - - return; } static void rtw_auto_scan_handler(struct adapter *padapter) @@ -1859,7 +1809,7 @@ static void rtw_auto_scan_handler(struct adapter *padapter) goto exit; } - if (pmlmepriv->LinkDetectInfo.bBusyTraffic == true) { + if (pmlmepriv->LinkDetectInfo.bBusyTraffic) { DBG_871X(FUNC_ADPT_FMT" exit BusyTraffic\n", FUNC_ADPT_ARG(padapter)); goto exit; } @@ -1879,20 +1829,20 @@ void rtw_dynamic_check_timer_handler(struct adapter *adapter) if (!adapter) return; - if (adapter->hw_init_completed == false) + if (!adapter->hw_init_completed) return; - if ((adapter->bDriverStopped == true) || (adapter->bSurpriseRemoved == true)) + if (adapter->bDriverStopped || adapter->bSurpriseRemoved) return; - if (adapter->net_closed == true) + if (adapter->net_closed) return; if (is_primary_adapter(adapter)) DBG_871X("IsBtDisabled =%d, IsBtControlLps =%d\n", hal_btcoex_IsBtDisabled(adapter), hal_btcoex_IsBtControlLps(adapter)); - if ((adapter_to_pwrctl(adapter)->bFwCurrentInPSMode == true) - && (hal_btcoex_IsBtControlLps(adapter) == false) + if ((adapter_to_pwrctl(adapter)->bFwCurrentInPSMode) + && !(hal_btcoex_IsBtControlLps(adapter)) ) { u8 bEnterPS; @@ -1907,16 +1857,14 @@ void rtw_dynamic_check_timer_handler(struct adapter *adapter) } } else { - if (is_primary_adapter(adapter)) { + if (is_primary_adapter(adapter)) rtw_dynamic_chk_wk_cmd(adapter); - } } /* auto site survey */ rtw_auto_scan_handler(adapter); } - inline bool rtw_is_scan_deny(struct adapter *adapter) { struct mlme_priv *mlmepriv = &adapter->mlmepriv; @@ -1994,26 +1942,24 @@ int rtw_select_roaming_candidate(struct mlme_priv *mlme) { int ret = _FAIL; struct list_head *phead; - struct adapter *adapter; struct __queue *queue = &(mlme->scanned_queue); struct wlan_network *pnetwork = NULL; struct wlan_network *candidate = NULL; - if (mlme->cur_network_scanned == NULL) { + if (!mlme->cur_network_scanned) { rtw_warn_on(1); return ret; } spin_lock_bh(&(mlme->scanned_queue.lock)); phead = get_list_head(queue); - adapter = (struct adapter *)mlme->nic_hdl; mlme->pscanned = get_next(phead); while (phead != mlme->pscanned) { pnetwork = LIST_CONTAINOR(mlme->pscanned, struct wlan_network, list); - if (pnetwork == NULL) { + if (!pnetwork) { RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s return _FAIL:(pnetwork == NULL)\n", __func__)); ret = _FAIL; goto exit; @@ -2031,7 +1977,7 @@ int rtw_select_roaming_candidate(struct mlme_priv *mlme) } - if (candidate == NULL) { + if (!candidate) { DBG_871X("%s: return _FAIL(candidate == NULL)\n", __func__); ret = _FAIL; goto exit; @@ -2064,9 +2010,8 @@ static int rtw_check_join_candidate(struct mlme_priv *mlme int updated = false; struct adapter *adapter = container_of(mlme, struct adapter, mlmepriv); - /* check bssid, if needed */ - if (mlme->assoc_by_bssid == true) { + if (mlme->assoc_by_bssid) { if (memcmp(competitor->network.MacAddress, mlme->assoc_bssid, ETH_ALEN)) goto exit; } @@ -2115,12 +2060,8 @@ exit: /* Calling context: The caller of the sub-routine will be in critical section... - The caller must hold the following spinlock - pmlmepriv->lock - - */ int rtw_select_and_join_from_scanned_queue(struct mlme_priv *pmlmepriv) @@ -2148,7 +2089,7 @@ int rtw_select_and_join_from_scanned_queue(struct mlme_priv *pmlmepriv) while (phead != pmlmepriv->pscanned) { pnetwork = LIST_CONTAINOR(pmlmepriv->pscanned, struct wlan_network, list); - if (pnetwork == NULL) { + if (!pnetwork) { RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("%s return _FAIL:(pnetwork == NULL)\n", __func__)); ret = _FAIL; goto exit; @@ -2166,7 +2107,7 @@ int rtw_select_and_join_from_scanned_queue(struct mlme_priv *pmlmepriv) } - if (candidate == NULL) { + if (!candidate) { DBG_871X("%s: return _FAIL(candidate == NULL)\n", __func__); #ifdef CONFIG_WOWLAN _clr_fwstate_(pmlmepriv, _FW_LINKED|_FW_UNDER_LINKING); @@ -2207,14 +2148,14 @@ sint rtw_set_auth(struct adapter *adapter, struct security_priv *psecuritypriv) sint res = _SUCCESS; pcmd = rtw_zmalloc(sizeof(struct cmd_obj)); - if (pcmd == NULL) { + if (!pcmd) { res = _FAIL; /* try again */ goto exit; } psetauthparm = rtw_zmalloc(sizeof(struct setauth_parm)); - if (psetauthparm == NULL) { - kfree((unsigned char *)pcmd); + if (!psetauthparm) { + kfree(pcmd); res = _FAIL; goto exit; } @@ -2227,7 +2168,6 @@ sint rtw_set_auth(struct adapter *adapter, struct security_priv *psecuritypriv) pcmd->rsp = NULL; pcmd->rspsz = 0; - INIT_LIST_HEAD(&pcmd->list); RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("after enqueue set_auth_cmd, auth_mode =%x\n", psecuritypriv->dot11AuthAlgrthm)); @@ -2247,7 +2187,7 @@ sint rtw_set_key(struct adapter *adapter, struct security_priv *psecuritypriv, s sint res = _SUCCESS; psetkeyparm = rtw_zmalloc(sizeof(struct setkey_parm)); - if (psetkeyparm == NULL) { + if (!psetkeyparm) { res = _FAIL; goto exit; } @@ -2291,15 +2231,14 @@ sint rtw_set_key(struct adapter *adapter, struct security_priv *psecuritypriv, s default: RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("\n rtw_set_key:psecuritypriv->dot11PrivacyAlgrthm = %x (must be 1 or 2 or 4 or 5)\n", psecuritypriv->dot11PrivacyAlgrthm)); res = _FAIL; - kfree((unsigned char *)psetkeyparm); + kfree(psetkeyparm); goto exit; } - if (enqueue) { pcmd = rtw_zmalloc(sizeof(struct cmd_obj)); - if (pcmd == NULL) { - kfree((unsigned char *)psetkeyparm); + if (!pcmd) { + kfree(psetkeyparm); res = _FAIL; /* try again */ goto exit; } @@ -2315,7 +2254,7 @@ sint rtw_set_key(struct adapter *adapter, struct security_priv *psecuritypriv, s res = rtw_enqueue_cmd(pcmdpriv, pcmd); } else { setkey_hdl(adapter, (u8 *)psetkeyparm); - kfree((u8 *) psetkeyparm); + kfree(psetkeyparm); } exit: return res; @@ -2350,7 +2289,6 @@ int rtw_restruct_wmm_ie(struct adapter *adapter, u8 *in_ie, u8 *out_ie, uint in_ } - /* */ /* Ported from 8185: IsInPreAuthKeyList(). (Renamed from SecIsInPreAuthKeyList(), 2006-10-13.) */ /* Added by Annie, 2006-05-07. */ @@ -2679,7 +2617,7 @@ unsigned int rtw_restructure_ht_ie(struct adapter *padapter, u8 *in_ie, u8 *out_ ht_capie.cap_info |= cpu_to_le16(IEEE80211_HT_CAP_SGI_20); /* Get HT BW */ - if (in_ie == NULL) { + if (!in_ie) { /* TDLS: TODO 20/40 issue */ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { operation_bw = padapter->mlmeextpriv.cur_bwmode; @@ -2794,7 +2732,7 @@ unsigned int rtw_restructure_ht_ie(struct adapter *padapter, u8 *in_ie, u8 *out_ phtpriv->ht_option = true; - if (in_ie != NULL) { + if (in_ie) { p = rtw_get_ie(in_ie, _HT_ADD_INFO_IE_, &ielen, in_len); if (p && (ielen == sizeof(struct ieee80211_ht_addt_info))) { out_len = *pout_len; @@ -2824,7 +2762,6 @@ void rtw_update_ht_cap(struct adapter *padapter, u8 *pie, uint ie_len, u8 channe struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); u8 cbw40_enable = 0; - if (!phtpriv->ht_option) return; @@ -2834,7 +2771,7 @@ void rtw_update_ht_cap(struct adapter *padapter, u8 *pie, uint ie_len, u8 channe DBG_871X("+rtw_update_ht_cap()\n"); /* maybe needs check if ap supports rx ampdu. */ - if ((phtpriv->ampdu_enable == false) && (pregistrypriv->ampdu_enable == 1)) { + if (!(phtpriv->ampdu_enable) && pregistrypriv->ampdu_enable == 1) { if (pregistrypriv->wifi_spec == 1) { /* remove this part because testbed AP should disable RX AMPDU */ /* phtpriv->ampdu_enable = false; */ @@ -2847,7 +2784,6 @@ void rtw_update_ht_cap(struct adapter *padapter, u8 *pie, uint ie_len, u8 channe /* phtpriv->ampdu_enable = true; */ } - /* check Max Rx A-MPDU Size */ len = 0; p = rtw_get_ie(pie+sizeof(struct ndis_802_11_fix_ie), _HT_CAPABILITY_IE_, &len, ie_len-sizeof(struct ndis_802_11_fix_ie)); @@ -2861,7 +2797,6 @@ void rtw_update_ht_cap(struct adapter *padapter, u8 *pie, uint ie_len, u8 channe } - len = 0; p = rtw_get_ie(pie+sizeof(struct ndis_802_11_fix_ie), _HT_ADD_INFO_IE_, &len, ie_len-sizeof(struct ndis_802_11_fix_ie)); if (p && len > 0) { @@ -2961,7 +2896,7 @@ void rtw_issue_addbareq_cmd(struct adapter *padapter, struct xmit_frame *pxmitfr return; } - if (psta == NULL) { + if (!psta) { DBG_871X("%s, psta ==NUL\n", __func__); return; } @@ -2971,10 +2906,9 @@ void rtw_issue_addbareq_cmd(struct adapter *padapter, struct xmit_frame *pxmitfr return; } - phtpriv = &psta->htpriv; - if ((phtpriv->ht_option == true) && (phtpriv->ampdu_enable == true)) { + if (phtpriv->ht_option && phtpriv->ampdu_enable) { issued = (phtpriv->agg_enable_bitmap>>priority)&0x1; issued |= (phtpriv->candidate_tid_bitmap>>priority)&0x1; @@ -2994,10 +2928,8 @@ void rtw_append_exented_cap(struct adapter *padapter, u8 *out_ie, uint *pout_len u8 cap_content[8] = {0}; u8 *pframe; - - if (phtpriv->bss_coexist) { + if (phtpriv->bss_coexist) SET_EXT_CAPABILITY_ELE_BSS_COEXIST(cap_content, 1); - } pframe = rtw_set_ie(out_ie + *pout_len, EID_EXTCapability, 8, cap_content, pout_len); } diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c index 2128886c9924..5e687f6d2c3e 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c @@ -344,7 +344,7 @@ static void init_channel_list(struct adapter *padapter, RT_CHANNEL_INFO *channel struct p2p_channels *channel_list) { - struct p2p_oper_class_map op_class[] = { + static const struct p2p_oper_class_map op_class[] = { { IEEE80211G, 81, 1, 13, 1, BW20 }, { IEEE80211G, 82, 14, 14, 1, BW20 }, { IEEE80211A, 115, 36, 48, 4, BW20 }, @@ -363,7 +363,7 @@ static void init_channel_list(struct adapter *padapter, RT_CHANNEL_INFO *channel for (op = 0; op_class[op].op_class; op++) { u8 ch; - struct p2p_oper_class_map *o = &op_class[op]; + const struct p2p_oper_class_map *o = &op_class[op]; struct p2p_reg_class *reg = NULL; for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) { @@ -2922,7 +2922,8 @@ int issue_probereq_ex(struct adapter *padapter, struct ndis_802_11_ssid *pssid, int i = 0; do { - ret = _issue_probereq(padapter, pssid, da, ch, append_wps, wait_ms > 0?true:false); + ret = _issue_probereq(padapter, pssid, da, ch, append_wps, + wait_ms > 0); i++; @@ -3086,8 +3087,6 @@ void issue_auth(struct adapter *padapter, struct sta_info *psta, unsigned short rtw_wep_encrypt(padapter, (u8 *)pmgntframe); DBG_871X("%s\n", __func__); dump_mgntframe(padapter, pmgntframe); - - return; } @@ -3405,8 +3404,6 @@ exit: rtw_buf_update(&pmlmepriv->assoc_req, &pmlmepriv->assoc_req_len, (u8 *)pwlanhdr, pattrib->pktlen); else rtw_buf_free(&pmlmepriv->assoc_req, &pmlmepriv->assoc_req_len); - - return; } /* when wait_ack is ture, this function shoule be called at process context */ @@ -3513,7 +3510,7 @@ int issue_nulldata(struct adapter *padapter, unsigned char *da, unsigned int pow } do { - ret = _issue_nulldata(padapter, da, power_mode, wait_ms > 0?true:false); + ret = _issue_nulldata(padapter, da, power_mode, wait_ms > 0); i++; @@ -3661,7 +3658,7 @@ int issue_qos_nulldata(struct adapter *padapter, unsigned char *da, u16 tid, int da = get_my_bssid(&(pmlmeinfo->network)); do { - ret = _issue_qos_nulldata(padapter, da, tid, wait_ms > 0?true:false); + ret = _issue_qos_nulldata(padapter, da, tid, wait_ms > 0); i++; @@ -3769,7 +3766,7 @@ int issue_deauth_ex(struct adapter *padapter, u8 *da, unsigned short reason, int int i = 0; do { - ret = _issue_deauth(padapter, da, reason, wait_ms > 0?true:false); + ret = _issue_deauth(padapter, da, reason, wait_ms > 0); i++; @@ -5260,8 +5257,6 @@ void report_del_sta_event(struct adapter *padapter, unsigned char *MacAddr, unsi DBG_871X("report_del_sta_event: delete STA, mac_id =%d\n", mac_id); rtw_enqueue_cmd(pcmdpriv, pcmd_obj); - - return; } void report_add_sta_event(struct adapter *padapter, unsigned char *MacAddr, int cam_idx) @@ -5306,8 +5301,6 @@ void report_add_sta_event(struct adapter *padapter, unsigned char *MacAddr, int DBG_871X("report_add_sta_event: add STA\n"); rtw_enqueue_cmd(pcmdpriv, pcmd_obj); - - return; } /**************************************************************************** @@ -5869,8 +5862,6 @@ void link_timer_hdl(struct timer_list *t) issue_assocreq(padapter); set_link_timer(pmlmeext, REASSOC_TO); } - - return; } void addba_timer_hdl(struct timer_list *t) diff --git a/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c b/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c index 4075de07e0a9..30137f0bd984 100644 --- a/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c +++ b/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c @@ -190,7 +190,6 @@ void rtw_ps_processor(struct adapter *padapter) } exit: pwrpriv->ps_processing = false; - return; } static void pwr_state_check_handler(struct timer_list *t) diff --git a/drivers/staging/rtl8723bs/core/rtw_recv.c b/drivers/staging/rtl8723bs/core/rtw_recv.c index 687ff3c6f09f..7fa8c84cf5f4 100644 --- a/drivers/staging/rtl8723bs/core/rtw_recv.c +++ b/drivers/staging/rtl8723bs/core/rtw_recv.c @@ -1400,10 +1400,8 @@ static sint validate_80211w_mgmt(struct adapter *adapter, union recv_frame *prec struct mlme_priv *pmlmepriv = &adapter->mlmepriv; struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; u8 *ptr = precv_frame->u.hdr.rx_data; - u8 type; u8 subtype; - type = GetFrameType(ptr); subtype = GetFrameSubType(ptr); /* bit(7)~bit(2) */ /* only support station mode */ @@ -1412,9 +1410,8 @@ static sint validate_80211w_mgmt(struct adapter *adapter, union recv_frame *prec /* unicast management frame decrypt */ if (pattrib->privacy && !(IS_MCAST(GetAddr1Ptr(ptr))) && (subtype == WIFI_DEAUTH || subtype == WIFI_DISASSOC || subtype == WIFI_ACTION)) { - u8 *ppp, *mgmt_DATA; + u8 *mgmt_DATA; u32 data_len = 0; - ppp = GetAddr2Ptr(ptr); pattrib->bdecrypted = 0; pattrib->encrypt = _AES_; @@ -1709,7 +1706,7 @@ static union recv_frame *recvframe_defrag(struct adapter *adapter, struct __queue *defrag_q) { struct list_head *plist, *phead; - u8 *data, wlanhdr_offset; + u8 wlanhdr_offset; u8 curfragnum; struct recv_frame_hdr *pfhdr, *pnfhdr; union recv_frame *prframe, *pnextrframe; @@ -1739,8 +1736,6 @@ static union recv_frame *recvframe_defrag(struct adapter *adapter, plist = get_next(plist); - data = get_recvframe_data(prframe); - while (phead != plist) { pnextrframe = (union recv_frame *)plist; pnfhdr = &pnextrframe->u.hdr; diff --git a/drivers/staging/rtl8723bs/core/rtw_security.c b/drivers/staging/rtl8723bs/core/rtw_security.c index 57cfe06d7d73..5aa5910687d1 100644 --- a/drivers/staging/rtl8723bs/core/rtw_security.c +++ b/drivers/staging/rtl8723bs/core/rtw_security.c @@ -303,13 +303,18 @@ void rtw_wep_decrypt(struct adapter *padapter, u8 *precvframe) *((u32 *)crc) = le32_to_cpu(getcrc32(payload, length-4)); if (crc[3] != payload[length-1] || crc[2] != payload[length-2] || crc[1] != payload[length-3] || crc[0] != payload[length-4]) { - RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_wep_decrypt:icv error crc[3](%x)!=payload[length-1](%x) || crc[2](%x)!=payload[length-2](%x) || crc[1](%x)!=payload[length-3](%x) || crc[0](%x)!=payload[length-4](%x)\n", - crc[3], payload[length-1], crc[2], payload[length-2], crc[1], payload[length-3], crc[0], payload[length-4])); + RT_TRACE(_module_rtl871x_security_c_, + _drv_err_, + ("%s:icv error crc[3](%x)!=payload[length-1](%x) || crc[2](%x)!=payload[length-2](%x) || crc[1](%x)!=payload[length-3](%x) || crc[0](%x)!=payload[length-4](%x)\n", + __func__, + crc[3], payload[length - 1], + crc[2], payload[length - 2], + crc[1], payload[length - 3], + crc[0], payload[length - 4])); } WEP_SW_DEC_CNT_INC(psecuritypriv, prxattrib->ra); } - return; } /* 3 =====TKIP related ===== */ @@ -657,11 +662,9 @@ u32 rtw_tkip_encrypt(struct adapter *padapter, u8 *pxmitframe) u8 hw_hdr_offset = 0; struct arc4context mycontext; sint curfragnum, length; - u32 prwskeylen; u8 *pframe, *payload, *iv, *prwskey; union pn48 dot11txpn; - /* struct sta_info *stainfo; */ struct pkt_attrib *pattrib = &((struct xmit_frame *)pxmitframe)->attrib; struct security_priv *psecuritypriv = &padapter->securitypriv; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; @@ -676,36 +679,14 @@ u32 rtw_tkip_encrypt(struct adapter *padapter, u8 *pxmitframe) /* 4 start to encrypt each fragment */ if (pattrib->encrypt == _TKIP_) { -/* - if (pattrib->psta) - { - stainfo = pattrib->psta; - } - else - { - DBG_871X("%s, call rtw_get_stainfo()\n", __func__); - stainfo =rtw_get_stainfo(&padapter->stapriv ,&pattrib->ra[0]); - } -*/ - /* if (stainfo!= NULL) */ { -/* - if (!(stainfo->state &_FW_LINKED)) - { - DBG_871X("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, stainfo->state); - return _FAIL; - } -*/ - RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_tkip_encrypt: stainfo!= NULL!!!\n")); + RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("%s: stainfo!= NULL!!!\n", __func__)); if (IS_MCAST(pattrib->ra)) prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey; else - /* prwskey =&stainfo->dot118021x_UncstKey.skey[0]; */ prwskey = pattrib->dot118021x_UncstKey.skey; - prwskeylen = 16; - for (curfragnum = 0; curfragnum < pattrib->nr_frags; curfragnum++) { iv = pframe+pattrib->hdrlen; payload = pframe+pattrib->iv_len+pattrib->hdrlen; @@ -742,13 +723,6 @@ u32 rtw_tkip_encrypt(struct adapter *padapter, u8 *pxmitframe) TKIP_SW_ENC_CNT_INC(psecuritypriv, pattrib->ra); } -/* - else { - RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_tkip_encrypt: stainfo == NULL!!!\n")); - DBG_871X("%s, psta ==NUL\n", __func__); - res = _FAIL; - } -*/ } return res; @@ -765,14 +739,12 @@ u32 rtw_tkip_decrypt(struct adapter *padapter, u8 *precvframe) u8 crc[4]; struct arc4context mycontext; sint length; - u32 prwskeylen; u8 *pframe, *payload, *iv, *prwskey; union pn48 dot11txpn; struct sta_info *stainfo; struct rx_pkt_attrib *prxattrib = &((union recv_frame *)precvframe)->u.hdr.attrib; struct security_priv *psecuritypriv = &padapter->securitypriv; -/* struct recv_priv *precvpriv =&padapter->recvpriv; */ u32 res = _SUCCESS; pframe = (unsigned char *)((union recv_frame *)precvframe)->u.hdr.rx_data; @@ -817,13 +789,9 @@ u32 rtw_tkip_decrypt(struct adapter *padapter, u8 *precvframe) no_gkey_bc_cnt = 0; no_gkey_mc_cnt = 0; - /* DBG_871X("rx bc/mc packets, to perform sw rtw_tkip_decrypt\n"); */ - /* prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey; */ prwskey = psecuritypriv->dot118021XGrpKey[prxattrib->key_index].skey; - prwskeylen = 16; } else { prwskey = &stainfo->dot118021x_UncstKey.skey[0]; - prwskeylen = 16; } iv = pframe+prxattrib->hdrlen; @@ -846,15 +814,19 @@ u32 rtw_tkip_decrypt(struct adapter *padapter, u8 *precvframe) *((u32 *)crc) = le32_to_cpu(getcrc32(payload, length-4)); if (crc[3] != payload[length-1] || crc[2] != payload[length-2] || crc[1] != payload[length-3] || crc[0] != payload[length-4]) { - RT_TRACE(_module_rtl871x_security_c_, _drv_err_, + RT_TRACE(_module_rtl871x_security_c_, + _drv_err_, ("rtw_wep_decrypt:icv error crc[3](%x)!=payload[length-1](%x) || crc[2](%x)!=payload[length-2](%x) || crc[1](%x)!=payload[length-3](%x) || crc[0](%x)!=payload[length-4](%x)\n", - crc[3], payload[length-1], crc[2], payload[length-2], crc[1], payload[length-3], crc[0], payload[length-4])); + crc[3], payload[length - 1], + crc[2], payload[length - 2], + crc[1], payload[length - 3], + crc[0], payload[length - 4])); res = _FAIL; } TKIP_SW_DEC_CNT_INC(psecuritypriv, prxattrib->ra); } else { - RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_tkip_decrypt: stainfo == NULL!!!\n")); + RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("%s: stainfo == NULL!!!\n", __func__)); res = _FAIL; } @@ -1426,7 +1398,7 @@ static sint aes_cipher(u8 *key, uint hdrlen, aes128k128d(key, chain_buffer, aes_out); for (i = 0; i < num_blocks; i++) { - bitwise_xor(aes_out, &pframe[payload_index], chain_buffer);/* bitwise_xor(aes_out, &message[payload_index], chain_buffer); */ + bitwise_xor(aes_out, &pframe[payload_index], chain_buffer); payload_index += 16; aes128k128d(key, chain_buffer, aes_out); @@ -1437,7 +1409,7 @@ static sint aes_cipher(u8 *key, uint hdrlen, for (j = 0; j < 16; j++) padded_buffer[j] = 0x00; for (j = 0; j < payload_remainder; j++) { - padded_buffer[j] = pframe[payload_index++];/* padded_buffer[j] = message[payload_index++]; */ + padded_buffer[j] = pframe[payload_index++]; } bitwise_xor(aes_out, padded_buffer, chain_buffer); aes128k128d(key, chain_buffer, aes_out); @@ -1449,7 +1421,7 @@ static sint aes_cipher(u8 *key, uint hdrlen, /* Insert MIC into payload */ for (j = 0; j < 8; j++) - pframe[payload_index+j] = mic[j]; /* message[payload_index+j] = mic[j]; */ + pframe[payload_index+j] = mic[j]; payload_index = hdrlen + 8; for (i = 0; i < num_blocks; i++) { @@ -1463,9 +1435,9 @@ static sint aes_cipher(u8 *key, uint hdrlen, frtype ); /* add for CONFIG_IEEE80211W, none 11w also can use */ aes128k128d(key, ctr_preload, aes_out); - bitwise_xor(aes_out, &pframe[payload_index], chain_buffer);/* bitwise_xor(aes_out, &message[payload_index], chain_buffer); */ + bitwise_xor(aes_out, &pframe[payload_index], chain_buffer); for (j = 0; j < 16; j++) - pframe[payload_index++] = chain_buffer[j];/* for (j = 0; j<16;j++) message[payload_index++] = chain_buffer[j]; */ + pframe[payload_index++] = chain_buffer[j]; } if (payload_remainder > 0) { @@ -1484,12 +1456,12 @@ static sint aes_cipher(u8 *key, uint hdrlen, for (j = 0; j < 16; j++) padded_buffer[j] = 0x00; for (j = 0; j < payload_remainder; j++) - padded_buffer[j] = pframe[payload_index+j];/* padded_buffer[j] = message[payload_index+j]; */ + padded_buffer[j] = pframe[payload_index+j]; aes128k128d(key, ctr_preload, aes_out); bitwise_xor(aes_out, padded_buffer, chain_buffer); for (j = 0; j < payload_remainder; j++) - pframe[payload_index++] = chain_buffer[j];/* for (j = 0; j<payload_remainder;j++) message[payload_index++] = chain_buffer[j]; */ + pframe[payload_index++] = chain_buffer[j]; } /* Encrypt the MIC */ @@ -1506,12 +1478,12 @@ static sint aes_cipher(u8 *key, uint hdrlen, for (j = 0; j < 16; j++) padded_buffer[j] = 0x00; for (j = 0; j < 8; j++) - padded_buffer[j] = pframe[j+hdrlen+8+plen];/* padded_buffer[j] = message[j+hdrlen+8+plen]; */ + padded_buffer[j] = pframe[j+hdrlen+8+plen]; aes128k128d(key, ctr_preload, aes_out); bitwise_xor(aes_out, padded_buffer, chain_buffer); for (j = 0; j < 8; j++) - pframe[payload_index++] = chain_buffer[j];/* for (j = 0; j<8;j++) message[payload_index++] = chain_buffer[j]; */ + pframe[payload_index++] = chain_buffer[j]; return _SUCCESS; } @@ -1525,15 +1497,12 @@ u32 rtw_aes_encrypt(struct adapter *padapter, u8 *pxmitframe) /* Intermediate Buffers */ sint curfragnum, length; - u32 prwskeylen; u8 *pframe, *prwskey; /* *payload,*iv */ u8 hw_hdr_offset = 0; - /* struct sta_info *stainfo = NULL; */ struct pkt_attrib *pattrib = &((struct xmit_frame *)pxmitframe)->attrib; struct security_priv *psecuritypriv = &padapter->securitypriv; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; -/* uint offset = 0; */ u32 res = _SUCCESS; if (((struct xmit_frame *)pxmitframe)->buf_addr == NULL) @@ -1544,16 +1513,13 @@ u32 rtw_aes_encrypt(struct adapter *padapter, u8 *pxmitframe) /* 4 start to encrypt each fragment */ if (pattrib->encrypt == _AES_) { - RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_aes_encrypt: stainfo!= NULL!!!\n")); + RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("%s: stainfo!= NULL!!!\n", __func__)); if (IS_MCAST(pattrib->ra)) prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey; else - /* prwskey =&stainfo->dot118021x_UncstKey.skey[0]; */ prwskey = pattrib->dot118021x_UncstKey.skey; - prwskeylen = 16; - for (curfragnum = 0; curfragnum < pattrib->nr_frags; curfragnum++) { if ((curfragnum+1) == pattrib->nr_frags) { /* 4 the last fragment */ length = pattrib->last_txcmdsz-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len; @@ -1574,10 +1540,10 @@ u32 rtw_aes_encrypt(struct adapter *padapter, u8 *pxmitframe) } static sint aes_decipher(u8 *key, uint hdrlen, - u8 *pframe, uint plen) + u8 *pframe, uint plen) { static u8 message[MAX_MSG_SIZE]; - uint qc_exists, a4_exists, i, j, payload_remainder, + uint qc_exists, a4_exists, i, j, payload_remainder, num_blocks, payload_index; sint res = _SUCCESS; u8 pn_vector[6]; @@ -1593,9 +1559,8 @@ static sint aes_decipher(u8 *key, uint hdrlen, u8 mic[8]; -/* uint offset = 0; */ - uint frtype = GetFrameType(pframe); - uint frsubtype = GetFrameSubType(pframe); + uint frtype = GetFrameType(pframe); + uint frsubtype = GetFrameSubType(pframe); frsubtype = frsubtype>>4; @@ -1615,11 +1580,11 @@ static sint aes_decipher(u8 *key, uint hdrlen, payload_remainder = (plen-8) % 16; pn_vector[0] = pframe[hdrlen]; - pn_vector[1] = pframe[hdrlen+1]; - pn_vector[2] = pframe[hdrlen+4]; - pn_vector[3] = pframe[hdrlen+5]; - pn_vector[4] = pframe[hdrlen+6]; - pn_vector[5] = pframe[hdrlen+7]; + pn_vector[1] = pframe[hdrlen + 1]; + pn_vector[2] = pframe[hdrlen + 4]; + pn_vector[3] = pframe[hdrlen + 5]; + pn_vector[4] = pframe[hdrlen + 6]; + pn_vector[5] = pframe[hdrlen + 7]; if ((hdrlen == WLAN_HDR_A3_LEN) || (hdrlen == WLAN_HDR_A3_QOS_LEN)) a4_exists = 0; @@ -1651,15 +1616,10 @@ static sint aes_decipher(u8 *key, uint hdrlen, payload_index = hdrlen + 8; /* 8 is for extiv */ for (i = 0; i < num_blocks; i++) { - construct_ctr_preload( - ctr_preload, - a4_exists, - qc_exists, - pframe, - pn_vector, - i+1, - frtype /* add for CONFIG_IEEE80211W, none 11w also can use */ - ); + construct_ctr_preload(ctr_preload, a4_exists, + qc_exists, pframe, + pn_vector, i + 1, + frtype); /* add for CONFIG_IEEE80211W, none 11w also can use */ aes128k128d(key, ctr_preload, aes_out); bitwise_xor(aes_out, &pframe[payload_index], chain_buffer); @@ -1835,10 +1795,18 @@ static sint aes_decipher(u8 *key, uint hdrlen, /* compare the mic */ for (i = 0; i < 8; i++) { if (pframe[hdrlen+8+plen-8+i] != message[hdrlen+8+plen-8+i]) { - RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("aes_decipher:mic check error mic[%d]: pframe(%x) != message(%x)\n", - i, pframe[hdrlen+8+plen-8+i], message[hdrlen+8+plen-8+i])); - DBG_871X("aes_decipher:mic check error mic[%d]: pframe(%x) != message(%x)\n", - i, pframe[hdrlen+8+plen-8+i], message[hdrlen+8+plen-8+i]); + RT_TRACE(_module_rtl871x_security_c_, + _drv_err_, + ("%s:mic check error mic[%d]: pframe(%x) != message(%x)\n", + __func__, + i, + pframe[hdrlen + 8 + plen - 8 + i], + message[hdrlen + 8 + plen - 8 + i])); + DBG_871X("%s:mic check error mic[%d]: pframe(%x) != message(%x)\n", + __func__, + i, + pframe[hdrlen + 8 + plen - 8 + i], + message[hdrlen + 8 + plen - 8 + i]); res = _FAIL; } } @@ -1861,7 +1829,6 @@ u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe) struct sta_info *stainfo; struct rx_pkt_attrib *prxattrib = &((union recv_frame *)precvframe)->u.hdr.attrib; struct security_priv *psecuritypriv = &padapter->securitypriv; -/* struct recv_priv *precvpriv =&padapter->recvpriv; */ u32 res = _SUCCESS; pframe = (unsigned char *)((union recv_frame *)precvframe)->u.hdr.rx_data; @@ -1869,15 +1836,15 @@ u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe) if (prxattrib->encrypt == _AES_) { stainfo = rtw_get_stainfo(&padapter->stapriv, &prxattrib->ta[0]); if (stainfo != NULL) { - RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_aes_decrypt: stainfo!= NULL!!!\n")); + RT_TRACE(_module_rtl871x_security_c_, + _drv_err_, + ("%s: stainfo!= NULL!!!\n", __func__)); if (IS_MCAST(prxattrib->ra)) { static unsigned long start; static u32 no_gkey_bc_cnt; static u32 no_gkey_mc_cnt; - /* DBG_871X("rx bc/mc packets, to perform sw rtw_aes_decrypt\n"); */ - /* prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey; */ if (psecuritypriv->binstallGrpkey == false) { res = _FAIL; @@ -1927,7 +1894,9 @@ u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe) AES_SW_DEC_CNT_INC(psecuritypriv, prxattrib->ra); } else { - RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_aes_decrypt: stainfo == NULL!!!\n")); + RT_TRACE(_module_rtl871x_security_c_, + _drv_err_, + ("%s: stainfo == NULL!!!\n", __func__)); res = _FAIL; } } diff --git a/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c b/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c index bdc52d8d5625..09d2ca30d653 100644 --- a/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c +++ b/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c @@ -187,7 +187,6 @@ u32 _rtw_free_sta_priv(struct sta_priv *pstapriv) /* struct sta_info *rtw_alloc_stainfo(_queue *pfree_sta_queue, unsigned char *hwaddr) */ struct sta_info *rtw_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) { - uint tmp_aid; s32 index; struct list_head *phash_list; struct sta_info *psta; @@ -211,8 +210,6 @@ struct sta_info *rtw_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) /* spin_unlock_bh(&(pfree_sta_queue->lock)); */ - tmp_aid = psta->aid; - _rtw_init_stainfo(psta); psta->padapter = pstapriv->padapter; diff --git a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c index ea3ea2a6b314..9590e6f351c1 100644 --- a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c +++ b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c @@ -606,19 +606,6 @@ inline void clear_cam_entry(struct adapter *adapter, u8 id) clear_cam_cache(adapter, id); } -inline void write_cam_from_cache(struct adapter *adapter, u8 id) -{ - struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); - struct cam_ctl_t *cam_ctl = &dvobj->cam_ctl; - struct cam_entry_cache cache; - - spin_lock_bh(&cam_ctl->lock); - memcpy(&cache, &dvobj->cam_cache[id], sizeof(struct cam_entry_cache)); - spin_unlock_bh(&cam_ctl->lock); - - _write_cam(adapter, id, cache.ctrl, cache.mac, cache.key); -} - void write_cam_cache(struct adapter *adapter, u8 id, u16 ctrl, u8 *mac, u8 *key) { struct dvobj_priv *dvobj = adapter_to_dvobj(adapter); @@ -1170,8 +1157,6 @@ void HT_info_handler(struct adapter *padapter, struct ndis_80211_var_ie *pIE) pmlmeinfo->HT_info_enable = 1; memcpy(&(pmlmeinfo->HT_info), pIE->data, pIE->Length); - - return; } void HTOnAssocRsp(struct adapter *padapter) @@ -1481,11 +1466,11 @@ int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len) } } - kfree((u8 *)bssid); + kfree(bssid); return _SUCCESS; _mismatch: - kfree((u8 *)bssid); + kfree(bssid); if (pmlmepriv->NumOfBcnInfoChkFail == 0) pmlmepriv->timeBcnInfoChkStart = jiffies; diff --git a/drivers/staging/rtl8723bs/core/rtw_xmit.c b/drivers/staging/rtl8723bs/core/rtw_xmit.c index b5dcb78fb4f4..ab85abecfaaa 100644 --- a/drivers/staging/rtl8723bs/core/rtw_xmit.c +++ b/drivers/staging/rtl8723bs/core/rtw_xmit.c @@ -89,7 +89,7 @@ s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter) pxframe = (struct xmit_frame *) pxmitpriv->pxmit_frame_buf; for (i = 0; i < NR_XMITFRAME; i++) { - INIT_LIST_HEAD(&(pxframe->list)); + INIT_LIST_HEAD(&pxframe->list); pxframe->padapter = padapter; pxframe->frame_tag = NULL_FRAMETAG; @@ -99,7 +99,8 @@ s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter) pxframe->buf_addr = NULL; pxframe->pxmitbuf = NULL; - list_add_tail(&(pxframe->list), &(pxmitpriv->free_xmit_queue.queue)); + list_add_tail(&pxframe->list, + &pxmitpriv->free_xmit_queue.queue); pxframe++; } @@ -150,7 +151,8 @@ s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter) pxmitbuf->flags = XMIT_VO_QUEUE; - list_add_tail(&pxmitbuf->list, &(pxmitpriv->free_xmitbuf_queue.queue)); + list_add_tail(&pxmitbuf->list, + &pxmitpriv->free_xmitbuf_queue.queue); #ifdef DBG_XMIT_BUF pxmitbuf->no = i; #endif @@ -176,7 +178,7 @@ s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter) pxframe = (struct xmit_frame *)pxmitpriv->xframe_ext; for (i = 0; i < NR_XMIT_EXTBUFF; i++) { - INIT_LIST_HEAD(&(pxframe->list)); + INIT_LIST_HEAD(&pxframe->list); pxframe->padapter = padapter; pxframe->frame_tag = NULL_FRAMETAG; @@ -188,7 +190,8 @@ s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter) pxframe->ext_tag = 1; - list_add_tail(&(pxframe->list), &(pxmitpriv->free_xframe_ext_queue.queue)); + list_add_tail(&pxframe->list, + &pxmitpriv->free_xframe_ext_queue.queue); pxframe++; } @@ -227,7 +230,8 @@ s32 _rtw_init_xmit_priv(struct xmit_priv *pxmitpriv, struct adapter *padapter) pxmitbuf->len = 0; pxmitbuf->pdata = pxmitbuf->ptail = pxmitbuf->phead; - list_add_tail(&pxmitbuf->list, &(pxmitpriv->free_xmit_extbuf_queue.queue)); + list_add_tail(&pxmitbuf->list, + &pxmitpriv->free_xmit_extbuf_queue.queue); #ifdef DBG_XMIT_BUF_EXT pxmitbuf->no = i; #endif @@ -372,8 +376,8 @@ static void update_attrib_vcs_info(struct adapter *padapter, struct xmit_frame * u32 sz; struct pkt_attrib *pattrib = &pxmitframe->attrib; /* struct sta_info *psta = pattrib->psta; */ - struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); - struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; if (pattrib->nr_frags != 1) sz = padapter->xmitpriv.frag_len; @@ -675,7 +679,6 @@ static void set_qos(struct pkt_file *ppktfile, struct pkt_attrib *pattrib) static s32 update_attrib(struct adapter *padapter, _pkt *pkt, struct pkt_attrib *pattrib) { - uint i; struct pkt_file pktfile; struct sta_info *psta = NULL; struct ethhdr etherhdr; @@ -689,7 +692,7 @@ static s32 update_attrib(struct adapter *padapter, _pkt *pkt, struct pkt_attrib DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib); _rtw_open_pktfile(pkt, &pktfile); - i = _rtw_pktfile_read(&pktfile, (u8 *)ðerhdr, ETH_HLEN); + _rtw_pktfile_read(&pktfile, (u8 *)ðerhdr, ETH_HLEN); pattrib->ether_type = ntohs(etherhdr.h_proto); @@ -956,7 +959,7 @@ static s32 xmitframe_addmic(struct adapter *padapter, struct xmit_frame *pxmitfr RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("curfragnum =%d length =%d pattrib->icv_len =%d", curfragnum, length, pattrib->icv_len)); } } - rtw_secgetmic(&micdata, &(mic[0])); + rtw_secgetmic(&micdata, &mic[0]); RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic: before add mic code!!!\n")); RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic: pattrib->last_txcmdsz =%d!!!\n", pattrib->last_txcmdsz)); RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic: mic[0]= 0x%.2x , mic[1]= 0x%.2x , mic[2]= 0x%.2x , mic[3]= 0x%.2x\n\ @@ -964,7 +967,7 @@ static s32 xmitframe_addmic(struct adapter *padapter, struct xmit_frame *pxmitfr mic[0], mic[1], mic[2], mic[3], mic[4], mic[5], mic[6], mic[7])); /* add mic code and add the mic code length in last_txcmdsz */ - memcpy(payload, &(mic[0]), 8); + memcpy(payload, &mic[0], 8); pattrib->last_txcmdsz += 8; RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("\n ========last pkt ========\n")); @@ -1030,7 +1033,7 @@ s32 rtw_make_wlanhdr(struct adapter *padapter, u8 *hdr, struct pkt_attrib *pattr SetFrameSubType(fctrl, pattrib->subtype); if (pattrib->subtype & WIFI_DATA_TYPE) { - if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true)) { + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) { /* to_ds = 1, fr_ds = 0; */ { @@ -1045,7 +1048,7 @@ s32 rtw_make_wlanhdr(struct adapter *padapter, u8 *hdr, struct pkt_attrib *pattr if (pqospriv->qos_option) qos_option = true; - } else if ((check_fwstate(pmlmepriv, WIFI_AP_STATE) == true)) { + } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) { /* to_ds = 0, fr_ds = 1; */ SetFrDs(fctrl); memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN); @@ -1410,7 +1413,8 @@ s32 rtw_mgmt_xmitframe_coalesce(struct adapter *padapter, _pkt *pkt, struct xmit pmlmeext->mgnt_80211w_IPN++; /* add MME IE with MIC all zero, MME string doesn't include element id and length */ - pframe = rtw_set_ie(pframe, _MME_IE_, 16, MME, &(pattrib->pktlen)); + pframe = rtw_set_ie(pframe, _MME_IE_, 16, + MME, &pattrib->pktlen); pattrib->last_txcmdsz = pattrib->pktlen; /* total frame length - header length */ frame_body_len = pattrib->pktlen - sizeof(struct ieee80211_hdr_3addr); @@ -1688,7 +1692,7 @@ struct xmit_buf *rtw_alloc_xmitbuf_ext(struct xmit_priv *pxmitpriv) pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list); - list_del_init(&(pxmitbuf->list)); + list_del_init(&pxmitbuf->list); } if (pxmitbuf) { @@ -1728,7 +1732,7 @@ s32 rtw_free_xmitbuf_ext(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) list_del_init(&pxmitbuf->list); - list_add_tail(&(pxmitbuf->list), get_list_head(pfree_queue)); + list_add_tail(&pxmitbuf->list, get_list_head(pfree_queue)); pxmitpriv->free_xmit_extbuf_cnt++; #ifdef DBG_XMIT_BUF_EXT DBG_871X("DBG_XMIT_BUF_EXT FREE no =%d, free_xmit_extbuf_cnt =%d\n", pxmitbuf->no, pxmitpriv->free_xmit_extbuf_cnt); @@ -1760,7 +1764,7 @@ struct xmit_buf *rtw_alloc_xmitbuf(struct xmit_priv *pxmitpriv) pxmitbuf = LIST_CONTAINOR(plist, struct xmit_buf, list); - list_del_init(&(pxmitbuf->list)); + list_del_init(&pxmitbuf->list); } if (pxmitbuf) { @@ -1815,7 +1819,8 @@ s32 rtw_free_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) list_del_init(&pxmitbuf->list); - list_add_tail(&(pxmitbuf->list), get_list_head(pfree_xmitbuf_queue)); + list_add_tail(&pxmitbuf->list, + get_list_head(pfree_xmitbuf_queue)); pxmitpriv->free_xmitbuf_cnt++; /* DBG_871X("FREE, free_xmitbuf_cnt =%d\n", pxmitpriv->free_xmitbuf_cnt); */ @@ -1879,7 +1884,7 @@ struct xmit_frame *rtw_alloc_xmitframe(struct xmit_priv *pxmitpriv)/* _queue *pf pxframe = LIST_CONTAINOR(plist, struct xmit_frame, list); - list_del_init(&(pxframe->list)); + list_del_init(&pxframe->list); pxmitpriv->free_xmitframe_cnt--; RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_alloc_xmitframe():free_xmitframe_cnt =%d\n", pxmitpriv->free_xmitframe_cnt)); } @@ -1906,7 +1911,7 @@ struct xmit_frame *rtw_alloc_xmitframe_ext(struct xmit_priv *pxmitpriv) plist = get_next(phead); pxframe = LIST_CONTAINOR(plist, struct xmit_frame, list); - list_del_init(&(pxframe->list)); + list_del_init(&pxframe->list); pxmitpriv->free_xframe_ext_cnt--; RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_alloc_xmitframe_ext():free_xmitframe_cnt =%d\n", pxmitpriv->free_xframe_ext_cnt)); } @@ -2006,7 +2011,7 @@ void rtw_free_xmitframe_queue(struct xmit_priv *pxmitpriv, struct __queue *pfram struct list_head *plist, *phead; struct xmit_frame *pxmitframe; - spin_lock_bh(&(pframequeue->lock)); + spin_lock_bh(&pframequeue->lock); phead = get_list_head(pframequeue); plist = get_next(phead); @@ -2020,7 +2025,7 @@ void rtw_free_xmitframe_queue(struct xmit_priv *pxmitpriv, struct __queue *pfram rtw_free_xmitframe(pxmitpriv, pxmitframe); } - spin_unlock_bh(&(pframequeue->lock)); + spin_unlock_bh(&pframequeue->lock); } s32 rtw_xmitframe_enqueue(struct adapter *padapter, struct xmit_frame *pxmitframe) @@ -2043,21 +2048,21 @@ struct tx_servq *rtw_get_sta_pending(struct adapter *padapter, struct sta_info * switch (up) { case 1: case 2: - ptxservq = &(psta->sta_xmitpriv.bk_q); + ptxservq = &psta->sta_xmitpriv.bk_q; *(ac) = 3; RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending : BK\n")); break; case 4: case 5: - ptxservq = &(psta->sta_xmitpriv.vi_q); + ptxservq = &psta->sta_xmitpriv.vi_q; *(ac) = 1; RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending : VI\n")); break; case 6: case 7: - ptxservq = &(psta->sta_xmitpriv.vo_q); + ptxservq = &psta->sta_xmitpriv.vo_q; *(ac) = 0; RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending : VO\n")); break; @@ -2065,7 +2070,7 @@ struct tx_servq *rtw_get_sta_pending(struct adapter *padapter, struct sta_info * case 0: case 3: default: - ptxservq = &(psta->sta_xmitpriv.be_q); + ptxservq = &psta->sta_xmitpriv.be_q; *(ac) = 2; RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending : BE\n")); break; @@ -2207,12 +2212,9 @@ s32 rtw_alloc_hwxmits(struct adapter *padapter) void rtw_free_hwxmits(struct adapter *padapter) { - struct hw_xmit *hwxmits; struct xmit_priv *pxmitpriv = &padapter->xmitpriv; - hwxmits = pxmitpriv->hwxmits; - if (hwxmits) - kfree((u8 *)hwxmits); + kfree(pxmitpriv->hwxmits); } void rtw_init_hwxmits(struct hw_xmit *phwxmit, sint entry) @@ -2310,7 +2312,7 @@ s32 rtw_xmit(struct adapter *padapter, _pkt **ppkt) if (!pxmitframe) { drop_cnt++; - RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit: no more pxmitframe\n")); + RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("%s: no more pxmitframe\n", __func__)); DBG_COUNTER(padapter->tx_logs.core_tx_err_pxmitframe); return -1; } @@ -2318,7 +2320,7 @@ s32 rtw_xmit(struct adapter *padapter, _pkt **ppkt) res = update_attrib(padapter, *ppkt, &pxmitframe->attrib); if (res == _FAIL) { - RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit: update attrib fail\n")); + RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("%s: update attrib fail\n", __func__)); #ifdef DBG_TX_DROP_FRAME DBG_871X("DBG_TX_DROP_FRAME %s update attrib fail\n", __func__); #endif @@ -2604,24 +2606,24 @@ void stop_sta_xmit(struct adapter *padapter, struct sta_info *psta) dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->vo_q.sta_pending); - list_del_init(&(pstaxmitpriv->vo_q.tx_pending)); + list_del_init(&pstaxmitpriv->vo_q.tx_pending); dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->vi_q.sta_pending); - list_del_init(&(pstaxmitpriv->vi_q.tx_pending)); + list_del_init(&pstaxmitpriv->vi_q.tx_pending); dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->be_q.sta_pending); - list_del_init(&(pstaxmitpriv->be_q.tx_pending)); + list_del_init(&pstaxmitpriv->be_q.tx_pending); dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->bk_q.sta_pending); - list_del_init(&(pstaxmitpriv->bk_q.tx_pending)); + list_del_init(&pstaxmitpriv->bk_q.tx_pending); /* for BC/MC Frames */ pstaxmitpriv = &psta_bmc->sta_xmitpriv; dequeue_xmitframes_to_sleeping_queue(padapter, psta_bmc, &pstaxmitpriv->be_q.sta_pending); - list_del_init(&(pstaxmitpriv->be_q.tx_pending)); + list_del_init(&pstaxmitpriv->be_q.tx_pending); spin_unlock_bh(&pxmitpriv->lock); } @@ -2690,14 +2692,6 @@ void wakeup_sta_to_xmit(struct adapter *padapter, struct sta_info *psta) pxmitframe->attrib.triggered = 1; -/* - spin_unlock_bh(&psta->sleep_q.lock); - if (rtw_hal_xmit(padapter, pxmitframe) == true) - { - rtw_os_xmit_complete(padapter, pxmitframe); - } - spin_lock_bh(&psta->sleep_q.lock); -*/ rtw_hal_xmitframe_enqueue(padapter, pxmitframe); @@ -2875,7 +2869,7 @@ void enqueue_pending_xmitbuf( list_add_tail(&pxmitbuf->list, get_list_head(pqueue)); spin_unlock_bh(&pqueue->lock); - complete(&(pri_adapter->xmitpriv.xmit_comp)); + complete(&pri_adapter->xmitpriv.xmit_comp); } void enqueue_pending_xmitbuf_to_head( @@ -2992,7 +2986,7 @@ int rtw_xmit_thread(void *context) do { err = rtw_hal_xmit_thread_handler(padapter); flush_signals_thread(); - } while (_SUCCESS == err); + } while (err == _SUCCESS); complete(&padapter->xmitpriv.terminate_xmitthread_comp); @@ -3022,9 +3016,8 @@ int rtw_sctx_wait(struct submit_ctx *sctx, const char *msg) status = sctx->status; } - if (status == RTW_SCTX_DONE_SUCCESS) { + if (status == RTW_SCTX_DONE_SUCCESS) ret = _SUCCESS; - } return ret; } @@ -3075,9 +3068,8 @@ void rtw_ack_tx_done(struct xmit_priv *pxmitpriv, int status) { struct submit_ctx *pack_tx_ops = &pxmitpriv->ack_tx_ops; - if (pxmitpriv->ack_tx) { + if (pxmitpriv->ack_tx) rtw_sctx_done_err(&pack_tx_ops, status); - } else { + else DBG_871X("%s ack_tx not set\n", __func__); - } } diff --git a/drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.c b/drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.c index 3239d37087c8..1ca9063a269f 100644 --- a/drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.c +++ b/drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.c @@ -402,8 +402,6 @@ static void GetDeltaSwingTable_8723B( *TemperatureUP_B = (u8 *)DeltaSwingTableIdx_2GA_P_8188E; *TemperatureDOWN_B = (u8 *)DeltaSwingTableIdx_2GA_N_8188E; } - - return; } diff --git a/drivers/staging/rtl8723bs/hal/hal_btcoex.c b/drivers/staging/rtl8723bs/hal/hal_btcoex.c index 6e4a1fcb8790..d5793e4614bf 100644 --- a/drivers/staging/rtl8723bs/hal/hal_btcoex.c +++ b/drivers/staging/rtl8723bs/hal/hal_btcoex.c @@ -1315,7 +1315,7 @@ void EXhalbtcoutsrc_DisplayBtCoexInfo(PBTC_COEXIST pBtCoexist) /* * Description: - *Run BT-Coexist mechansim or not + *Run BT-Coexist mechanism or not * */ void hal_btcoex_SetBTCoexist(struct adapter *padapter, u8 bBtExist) diff --git a/drivers/staging/rtl8723bs/hal/hal_com.c b/drivers/staging/rtl8723bs/hal/hal_com.c index eddd56abbb2d..109bd85b0cd8 100644 --- a/drivers/staging/rtl8723bs/hal/hal_com.c +++ b/drivers/staging/rtl8723bs/hal/hal_com.c @@ -30,7 +30,6 @@ void rtw_hal_data_deinit(struct adapter *padapter) { if (is_primary_adapter(padapter)) { /* if (padapter->isprimary) */ if (padapter->HalData) { - phy_free_filebuf(padapter); vfree(padapter->HalData); padapter->HalData = NULL; padapter->hal_data_sz = 0; diff --git a/drivers/staging/rtl8723bs/hal/hal_com_phycfg.c b/drivers/staging/rtl8723bs/hal/hal_com_phycfg.c index 6539bee9b5ba..eb7de3617d83 100644 --- a/drivers/staging/rtl8723bs/hal/hal_com_phycfg.c +++ b/drivers/staging/rtl8723bs/hal/hal_com_phycfg.c @@ -2202,1079 +2202,3 @@ void Hal_ChannelPlanToRegulation(struct adapter *Adapter, u16 ChannelPlan) break; } } - - -static char file_path_bs[PATH_MAX]; - -#define GetLineFromBuffer(buffer) strsep(&buffer, "\n") - -int phy_ConfigMACWithParaFile(struct adapter *Adapter, char *pFileName) -{ - struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); - int rlen = 0, rtStatus = _FAIL; - char *szLine, *ptmp; - u32 u4bRegOffset, u4bRegValue, u4bMove; - - if (!(Adapter->registrypriv.load_phy_file & LOAD_MAC_PARA_FILE)) - return rtStatus; - - memset(pHalData->para_file_buf, 0, MAX_PARA_FILE_BUF_LEN); - - if ((pHalData->mac_reg_len == 0) && !pHalData->mac_reg) { - rtw_merge_string(file_path_bs, PATH_MAX, rtw_phy_file_path, pFileName); - - if (rtw_is_file_readable(file_path_bs) == true) { - rlen = rtw_retrive_from_file(file_path_bs, pHalData->para_file_buf, MAX_PARA_FILE_BUF_LEN); - if (rlen > 0) { - rtStatus = _SUCCESS; - pHalData->mac_reg = vzalloc(rlen); - if (pHalData->mac_reg) { - memcpy(pHalData->mac_reg, pHalData->para_file_buf, rlen); - pHalData->mac_reg_len = rlen; - } else - DBG_871X("%s mac_reg alloc fail !\n", __func__); - } - } - } else { - if ((pHalData->mac_reg_len != 0) && (pHalData->mac_reg != NULL)) { - memcpy(pHalData->para_file_buf, pHalData->mac_reg, pHalData->mac_reg_len); - rtStatus = _SUCCESS; - } else - DBG_871X("%s(): Critical Error !!!\n", __func__); - } - - if (rtStatus == _SUCCESS) { - ptmp = pHalData->para_file_buf; - for (szLine = GetLineFromBuffer(ptmp); szLine != NULL; szLine = GetLineFromBuffer(ptmp)) { - if (!IsCommentString(szLine)) { - /* Get 1st hex value as register offset */ - if (GetHexValueFromString(szLine, &u4bRegOffset, &u4bMove)) { - if (u4bRegOffset == 0xffff) /* Ending. */ - break; - - /* Get 2nd hex value as register value. */ - szLine += u4bMove; - if (GetHexValueFromString(szLine, &u4bRegValue, &u4bMove)) - rtw_write8(Adapter, u4bRegOffset, (u8)u4bRegValue); - } - } - } - } else - DBG_871X("%s(): No File %s, Load from HWImg Array!\n", __func__, pFileName); - - return rtStatus; -} - -int phy_ConfigBBWithParaFile( - struct adapter *Adapter, char *pFileName, u32 ConfigType -) -{ - struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); - int rlen = 0, rtStatus = _FAIL; - char *szLine, *ptmp; - u32 u4bRegOffset, u4bRegValue, u4bMove; - char *pBuf = NULL; - u32 *pBufLen = NULL; - - if (!(Adapter->registrypriv.load_phy_file & LOAD_BB_PARA_FILE)) - return rtStatus; - - switch (ConfigType) { - case CONFIG_BB_PHY_REG: - pBuf = pHalData->bb_phy_reg; - pBufLen = &pHalData->bb_phy_reg_len; - break; - case CONFIG_BB_AGC_TAB: - pBuf = pHalData->bb_agc_tab; - pBufLen = &pHalData->bb_agc_tab_len; - break; - default: - DBG_871X("Unknown ConfigType!! %d\r\n", ConfigType); - break; - } - - memset(pHalData->para_file_buf, 0, MAX_PARA_FILE_BUF_LEN); - - if (pBufLen && (*pBufLen == 0) && !pBuf) { - rtw_merge_string(file_path_bs, PATH_MAX, rtw_phy_file_path, pFileName); - - if (rtw_is_file_readable(file_path_bs) == true) { - rlen = rtw_retrive_from_file(file_path_bs, pHalData->para_file_buf, MAX_PARA_FILE_BUF_LEN); - if (rlen > 0) { - rtStatus = _SUCCESS; - pBuf = vzalloc(rlen); - if (pBuf) { - memcpy(pBuf, pHalData->para_file_buf, rlen); - *pBufLen = rlen; - - switch (ConfigType) { - case CONFIG_BB_PHY_REG: - pHalData->bb_phy_reg = pBuf; - break; - case CONFIG_BB_AGC_TAB: - pHalData->bb_agc_tab = pBuf; - break; - } - } else - DBG_871X("%s(): ConfigType %d alloc fail !\n", __func__, ConfigType); - } - } - } else { - if (pBufLen && (*pBufLen == 0) && !pBuf) { - memcpy(pHalData->para_file_buf, pBuf, *pBufLen); - rtStatus = _SUCCESS; - } else - DBG_871X("%s(): Critical Error !!!\n", __func__); - } - - if (rtStatus == _SUCCESS) { - ptmp = pHalData->para_file_buf; - for (szLine = GetLineFromBuffer(ptmp); szLine != NULL; szLine = GetLineFromBuffer(ptmp)) { - if (!IsCommentString(szLine)) { - /* Get 1st hex value as register offset. */ - if (GetHexValueFromString(szLine, &u4bRegOffset, &u4bMove)) { - if (u4bRegOffset == 0xffff) /* Ending. */ - break; - else if (u4bRegOffset == 0xfe || u4bRegOffset == 0xffe) - msleep(50); - else if (u4bRegOffset == 0xfd) - mdelay(5); - else if (u4bRegOffset == 0xfc) - mdelay(1); - else if (u4bRegOffset == 0xfb) - udelay(50); - else if (u4bRegOffset == 0xfa) - udelay(5); - else if (u4bRegOffset == 0xf9) - udelay(1); - - /* Get 2nd hex value as register value. */ - szLine += u4bMove; - if (GetHexValueFromString(szLine, &u4bRegValue, &u4bMove)) { - /* DBG_871X("[BB-ADDR]%03lX =%08lX\n", u4bRegOffset, u4bRegValue); */ - PHY_SetBBReg(Adapter, u4bRegOffset, bMaskDWord, u4bRegValue); - - if (u4bRegOffset == 0xa24) - pHalData->odmpriv.RFCalibrateInfo.RegA24 = u4bRegValue; - - /* Add 1us delay between BB/RF register setting. */ - udelay(1); - } - } - } - } - } else - DBG_871X("%s(): No File %s, Load from HWImg Array!\n", __func__, pFileName); - - return rtStatus; -} - -static void phy_DecryptBBPgParaFile(struct adapter *Adapter, char *buffer) -{ - u32 i = 0, j = 0; - u8 map[95] = {0}; - u8 currentChar; - char *BufOfLines, *ptmp; - - /* DBG_871X("=====>phy_DecryptBBPgParaFile()\n"); */ - /* 32 the ascii code of the first visable char, 126 the last one */ - for (i = 0; i < 95; ++i) - map[i] = (u8) (94 - i); - - ptmp = buffer; - i = 0; - for (BufOfLines = GetLineFromBuffer(ptmp); BufOfLines != NULL; BufOfLines = GetLineFromBuffer(ptmp)) { - /* DBG_871X("Encrypted Line: %s\n", BufOfLines); */ - - for (j = 0; j < strlen(BufOfLines); ++j) { - currentChar = BufOfLines[j]; - - if (currentChar == '\0') - break; - - currentChar -= (u8) ((((i + j) * 3) % 128)); - - BufOfLines[j] = map[currentChar - 32] + 32; - } - /* DBG_871X("Decrypted Line: %s\n", BufOfLines); */ - if (strlen(BufOfLines) != 0) - i++; - BufOfLines[strlen(BufOfLines)] = '\n'; - } -} - -static int phy_ParseBBPgParaFile(struct adapter *Adapter, char *buffer) -{ - int rtStatus = _SUCCESS; - struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); - char *szLine, *ptmp; - u32 u4bRegOffset, u4bRegMask, u4bRegValue; - u32 u4bMove; - bool firstLine = true; - u8 tx_num = 0; - u8 band = 0, rf_path = 0; - - /* DBG_871X("=====>phy_ParseBBPgParaFile()\n"); */ - - if (Adapter->registrypriv.RegDecryptCustomFile == 1) - phy_DecryptBBPgParaFile(Adapter, buffer); - - ptmp = buffer; - for (szLine = GetLineFromBuffer(ptmp); szLine != NULL; szLine = GetLineFromBuffer(ptmp)) { - if (!IsCommentString(szLine)) { - if (isAllSpaceOrTab(szLine, sizeof(*szLine))) - continue; - - /* Get header info (relative value or exact value) */ - if (firstLine) { - if (eqNByte(szLine, (u8 *)("#[v1]"), 5)) { - - pHalData->odmpriv.PhyRegPgVersion = szLine[3] - '0'; - /* DBG_871X("This is a new format PHY_REG_PG.txt\n"); */ - } else if (eqNByte(szLine, (u8 *)("#[v0]"), 5)) { - pHalData->odmpriv.PhyRegPgVersion = szLine[3] - '0'; - /* DBG_871X("This is a old format PHY_REG_PG.txt ok\n"); */ - } else { - DBG_871X("The format in PHY_REG_PG are invalid %s\n", szLine); - return _FAIL; - } - - if (eqNByte(szLine + 5, (u8 *)("[Exact]#"), 8)) { - pHalData->odmpriv.PhyRegPgValueType = PHY_REG_PG_EXACT_VALUE; - /* DBG_871X("The values in PHY_REG_PG are exact values ok\n"); */ - firstLine = false; - continue; - } else if (eqNByte(szLine + 5, (u8 *)("[Relative]#"), 11)) { - pHalData->odmpriv.PhyRegPgValueType = PHY_REG_PG_RELATIVE_VALUE; - /* DBG_871X("The values in PHY_REG_PG are relative values ok\n"); */ - firstLine = false; - continue; - } else { - DBG_871X("The values in PHY_REG_PG are invalid %s\n", szLine); - return _FAIL; - } - } - - if (pHalData->odmpriv.PhyRegPgVersion == 0) { - /* Get 1st hex value as register offset. */ - if (GetHexValueFromString(szLine, &u4bRegOffset, &u4bMove)) { - szLine += u4bMove; - if (u4bRegOffset == 0xffff) /* Ending. */ - break; - - /* Get 2nd hex value as register mask. */ - if (GetHexValueFromString(szLine, &u4bRegMask, &u4bMove)) - szLine += u4bMove; - else - return _FAIL; - - if (pHalData->odmpriv.PhyRegPgValueType == PHY_REG_PG_RELATIVE_VALUE) { - /* Get 3rd hex value as register value. */ - if (GetHexValueFromString(szLine, &u4bRegValue, &u4bMove)) { - PHY_StoreTxPowerByRate(Adapter, 0, 0, 1, u4bRegOffset, u4bRegMask, u4bRegValue); - /* DBG_871X("[ADDR] %03X =%08X Mask =%08x\n", u4bRegOffset, u4bRegValue, u4bRegMask); */ - } else - return _FAIL; - } else if (pHalData->odmpriv.PhyRegPgValueType == PHY_REG_PG_EXACT_VALUE) { - u32 combineValue = 0; - u8 integer = 0, fraction = 0; - - if (GetFractionValueFromString(szLine, &integer, &fraction, &u4bMove)) - szLine += u4bMove; - else - return _FAIL; - - integer *= 2; - if (fraction == 5) - integer += 1; - combineValue |= (((integer / 10) << 4) + (integer % 10)); - /* DBG_871X(" %d", integer); */ - - if (GetFractionValueFromString(szLine, &integer, &fraction, &u4bMove)) - szLine += u4bMove; - else - return _FAIL; - - integer *= 2; - if (fraction == 5) - integer += 1; - combineValue <<= 8; - combineValue |= (((integer / 10) << 4) + (integer % 10)); - /* DBG_871X(" %d", integer); */ - - if (GetFractionValueFromString(szLine, &integer, &fraction, &u4bMove)) - szLine += u4bMove; - else - return _FAIL; - - integer *= 2; - if (fraction == 5) - integer += 1; - combineValue <<= 8; - combineValue |= (((integer / 10) << 4) + (integer % 10)); - /* DBG_871X(" %d", integer); */ - - if (GetFractionValueFromString(szLine, &integer, &fraction, &u4bMove)) - szLine += u4bMove; - else - return _FAIL; - - integer *= 2; - if (fraction == 5) - integer += 1; - combineValue <<= 8; - combineValue |= (((integer / 10) << 4) + (integer % 10)); - /* DBG_871X(" %d", integer); */ - PHY_StoreTxPowerByRate(Adapter, 0, 0, 1, u4bRegOffset, u4bRegMask, combineValue); - - /* DBG_871X("[ADDR] 0x%3x = 0x%4x\n", u4bRegOffset, combineValue); */ - } - } - } else if (pHalData->odmpriv.PhyRegPgVersion > 0) { - u32 index = 0; - - if (eqNByte(szLine, "0xffff", 6)) - break; - - if (!eqNByte("#[END]#", szLine, 7)) { - /* load the table label info */ - if (szLine[0] == '#') { - index = 0; - if (eqNByte(szLine, "#[2.4G]", 7)) { - band = BAND_ON_2_4G; - index += 8; - } else if (eqNByte(szLine, "#[5G]", 5)) { - band = BAND_ON_5G; - index += 6; - } else { - DBG_871X("Invalid band %s in PHY_REG_PG.txt\n", szLine); - return _FAIL; - } - - rf_path = szLine[index] - 'A'; - /* DBG_871X(" Table label Band %d, RfPath %d\n", band, rf_path); */ - } else { /* load rows of tables */ - if (szLine[1] == '1') - tx_num = RF_1TX; - else if (szLine[1] == '2') - tx_num = RF_2TX; - else if (szLine[1] == '3') - tx_num = RF_3TX; - else if (szLine[1] == '4') - tx_num = RF_4TX; - else { - DBG_871X("Invalid row in PHY_REG_PG.txt %c\n", szLine[1]); - return _FAIL; - } - - while (szLine[index] != ']') - ++index; - ++index;/* skip ] */ - - /* Get 2nd hex value as register offset. */ - szLine += index; - if (GetHexValueFromString(szLine, &u4bRegOffset, &u4bMove)) - szLine += u4bMove; - else - return _FAIL; - - /* Get 2nd hex value as register mask. */ - if (GetHexValueFromString(szLine, &u4bRegMask, &u4bMove)) - szLine += u4bMove; - else - return _FAIL; - - if (pHalData->odmpriv.PhyRegPgValueType == PHY_REG_PG_RELATIVE_VALUE) { - /* Get 3rd hex value as register value. */ - if (GetHexValueFromString(szLine, &u4bRegValue, &u4bMove)) { - PHY_StoreTxPowerByRate(Adapter, band, rf_path, tx_num, u4bRegOffset, u4bRegMask, u4bRegValue); - /* DBG_871X("[ADDR] %03X (tx_num %d) =%08X Mask =%08x\n", u4bRegOffset, tx_num, u4bRegValue, u4bRegMask); */ - } else - return _FAIL; - } else if (pHalData->odmpriv.PhyRegPgValueType == PHY_REG_PG_EXACT_VALUE) { - u32 combineValue = 0; - u8 integer = 0, fraction = 0; - - if (GetFractionValueFromString(szLine, &integer, &fraction, &u4bMove)) - szLine += u4bMove; - else - return _FAIL; - - integer *= 2; - if (fraction == 5) - integer += 1; - combineValue |= (((integer / 10) << 4) + (integer % 10)); - /* DBG_871X(" %d", integer); */ - - if (GetFractionValueFromString(szLine, &integer, &fraction, &u4bMove)) - szLine += u4bMove; - else - return _FAIL; - - integer *= 2; - if (fraction == 5) - integer += 1; - combineValue <<= 8; - combineValue |= (((integer / 10) << 4) + (integer % 10)); - /* DBG_871X(" %d", integer); */ - - if (GetFractionValueFromString(szLine, &integer, &fraction, &u4bMove)) - szLine += u4bMove; - else - return _FAIL; - - integer *= 2; - if (fraction == 5) - integer += 1; - combineValue <<= 8; - combineValue |= (((integer / 10) << 4) + (integer % 10)); - /* DBG_871X(" %d", integer); */ - - if (GetFractionValueFromString(szLine, &integer, &fraction, &u4bMove)) - szLine += u4bMove; - else - return _FAIL; - - integer *= 2; - if (fraction == 5) - integer += 1; - combineValue <<= 8; - combineValue |= (((integer / 10) << 4) + (integer % 10)); - /* DBG_871X(" %d", integer); */ - PHY_StoreTxPowerByRate(Adapter, band, rf_path, tx_num, u4bRegOffset, u4bRegMask, combineValue); - - /* DBG_871X("[ADDR] 0x%3x (tx_num %d) = 0x%4x\n", u4bRegOffset, tx_num, combineValue); */ - } - } - } - } - } - } - /* DBG_871X("<=====phy_ParseBBPgParaFile()\n"); */ - return rtStatus; -} - -int phy_ConfigBBWithPgParaFile(struct adapter *Adapter, char *pFileName) -{ - struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); - int rlen = 0, rtStatus = _FAIL; - - if (!(Adapter->registrypriv.load_phy_file & LOAD_BB_PG_PARA_FILE)) - return rtStatus; - - memset(pHalData->para_file_buf, 0, MAX_PARA_FILE_BUF_LEN); - - if ((pHalData->bb_phy_reg_pg_len == 0) && !pHalData->bb_phy_reg_pg) { - rtw_merge_string(file_path_bs, PATH_MAX, rtw_phy_file_path, pFileName); - - if (rtw_is_file_readable(file_path_bs) == true) { - rlen = rtw_retrive_from_file(file_path_bs, pHalData->para_file_buf, MAX_PARA_FILE_BUF_LEN); - if (rlen > 0) { - rtStatus = _SUCCESS; - pHalData->bb_phy_reg_pg = vzalloc(rlen); - if (pHalData->bb_phy_reg_pg) { - memcpy(pHalData->bb_phy_reg_pg, pHalData->para_file_buf, rlen); - pHalData->bb_phy_reg_pg_len = rlen; - } else - DBG_871X("%s bb_phy_reg_pg alloc fail !\n", __func__); - } - } - } else { - if ((pHalData->bb_phy_reg_pg_len != 0) && (pHalData->bb_phy_reg_pg != NULL)) { - memcpy(pHalData->para_file_buf, pHalData->bb_phy_reg_pg, pHalData->bb_phy_reg_pg_len); - rtStatus = _SUCCESS; - } else - DBG_871X("%s(): Critical Error !!!\n", __func__); - } - - if (rtStatus == _SUCCESS) { - /* DBG_871X("phy_ConfigBBWithPgParaFile(): read %s ok\n", pFileName); */ - phy_ParseBBPgParaFile(Adapter, pHalData->para_file_buf); - } else - DBG_871X("%s(): No File %s, Load from HWImg Array!\n", __func__, pFileName); - - return rtStatus; -} - -int PHY_ConfigRFWithParaFile( - struct adapter *Adapter, char *pFileName, u8 eRFPath -) -{ - struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); - int rlen = 0, rtStatus = _FAIL; - char *szLine, *ptmp; - u32 u4bRegOffset, u4bRegValue, u4bMove; - u16 i; - char *pBuf = NULL; - u32 *pBufLen = NULL; - - if (!(Adapter->registrypriv.load_phy_file & LOAD_RF_PARA_FILE)) - return rtStatus; - - switch (eRFPath) { - case ODM_RF_PATH_A: - pBuf = pHalData->rf_radio_a; - pBufLen = &pHalData->rf_radio_a_len; - break; - case ODM_RF_PATH_B: - pBuf = pHalData->rf_radio_b; - pBufLen = &pHalData->rf_radio_b_len; - break; - default: - DBG_871X("Unknown RF path!! %d\r\n", eRFPath); - break; - } - - memset(pHalData->para_file_buf, 0, MAX_PARA_FILE_BUF_LEN); - - if (pBufLen && (*pBufLen == 0) && !pBuf) { - rtw_merge_string(file_path_bs, PATH_MAX, rtw_phy_file_path, pFileName); - - if (rtw_is_file_readable(file_path_bs) == true) { - rlen = rtw_retrive_from_file(file_path_bs, pHalData->para_file_buf, MAX_PARA_FILE_BUF_LEN); - if (rlen > 0) { - rtStatus = _SUCCESS; - pBuf = vzalloc(rlen); - if (pBuf) { - memcpy(pBuf, pHalData->para_file_buf, rlen); - *pBufLen = rlen; - - switch (eRFPath) { - case ODM_RF_PATH_A: - pHalData->rf_radio_a = pBuf; - break; - case ODM_RF_PATH_B: - pHalData->rf_radio_b = pBuf; - break; - } - } else - DBG_871X("%s(): eRFPath =%d alloc fail !\n", __func__, eRFPath); - } - } - } else { - if (pBufLen && (*pBufLen == 0) && !pBuf) { - memcpy(pHalData->para_file_buf, pBuf, *pBufLen); - rtStatus = _SUCCESS; - } else - DBG_871X("%s(): Critical Error !!!\n", __func__); - } - - if (rtStatus == _SUCCESS) { - /* DBG_871X("%s(): read %s successfully\n", __func__, pFileName); */ - - ptmp = pHalData->para_file_buf; - for (szLine = GetLineFromBuffer(ptmp); szLine != NULL; szLine = GetLineFromBuffer(ptmp)) { - if (!IsCommentString(szLine)) { - /* Get 1st hex value as register offset. */ - if (GetHexValueFromString(szLine, &u4bRegOffset, &u4bMove)) { - if (u4bRegOffset == 0xfe || u4bRegOffset == 0xffe) /* Deay specific ms. Only RF configuration require delay. */ - msleep(50); - else if (u4bRegOffset == 0xfd) { - /* mdelay(5); */ - for (i = 0; i < 100; i++) - udelay(MAX_STALL_TIME); - } else if (u4bRegOffset == 0xfc) { - /* mdelay(1); */ - for (i = 0; i < 20; i++) - udelay(MAX_STALL_TIME); - } else if (u4bRegOffset == 0xfb) - udelay(50); - else if (u4bRegOffset == 0xfa) - udelay(5); - else if (u4bRegOffset == 0xf9) - udelay(1); - else if (u4bRegOffset == 0xffff) - break; - - /* Get 2nd hex value as register value. */ - szLine += u4bMove; - if (GetHexValueFromString(szLine, &u4bRegValue, &u4bMove)) { - PHY_SetRFReg(Adapter, eRFPath, u4bRegOffset, bRFRegOffsetMask, u4bRegValue); - - /* Temp add, for frequency lock, if no delay, that may cause */ - /* frequency shift, ex: 2412MHz => 2417MHz */ - /* If frequency shift, the following action may works. */ - /* Fractional-N table in radio_a.txt */ - /* 0x2a 0x00001 channel 1 */ - /* 0x2b 0x00808 frequency divider. */ - /* 0x2b 0x53333 */ - /* 0x2c 0x0000c */ - udelay(1); - } - } - } - } - } else - DBG_871X("%s(): No File %s, Load from HWImg Array!\n", __func__, pFileName); - - return rtStatus; -} - -static void initDeltaSwingIndexTables( - struct adapter *Adapter, - char *Band, - char *Path, - char *Sign, - char *Channel, - char *Rate, - char *Data -) -{ - #define STR_EQUAL_5G(_band, _path, _sign, _rate, _chnl) \ - ((strcmp(Band, _band) == 0) && (strcmp(Path, _path) == 0) && (strcmp(Sign, _sign) == 0) &&\ - (strcmp(Rate, _rate) == 0) && (strcmp(Channel, _chnl) == 0)\ - ) - #define STR_EQUAL_2G(_band, _path, _sign, _rate) \ - ((strcmp(Band, _band) == 0) && (strcmp(Path, _path) == 0) && (strcmp(Sign, _sign) == 0) &&\ - (strcmp(Rate, _rate) == 0)\ - ) - - #define STORE_SWING_TABLE(_array, _iteratedIdx) \ - for (token = strsep(&Data, delim); token != NULL; token = strsep(&Data, delim)) {\ - sscanf(token, "%d", &idx);\ - _array[_iteratedIdx++] = (u8)idx;\ - } \ - - struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); - PDM_ODM_T pDM_Odm = &pHalData->odmpriv; - PODM_RF_CAL_T pRFCalibrateInfo = &(pDM_Odm->RFCalibrateInfo); - u32 j = 0; - char *token; - char delim[] = ","; - u32 idx = 0; - - /* DBG_871X("===>initDeltaSwingIndexTables(): Band: %s;\nPath: %s;\nSign: %s;\nChannel: %s;\nRate: %s;\n, Data: %s;\n", */ - /* Band, Path, Sign, Channel, Rate, Data); */ - - if (STR_EQUAL_2G("2G", "A", "+", "CCK")) { - STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKA_P, j); - } else if (STR_EQUAL_2G("2G", "A", "-", "CCK")) { - STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKA_N, j); - } else if (STR_EQUAL_2G("2G", "B", "+", "CCK")) { - STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKB_P, j); - } else if (STR_EQUAL_2G("2G", "B", "-", "CCK")) { - STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_2GCCKB_N, j); - } else if (STR_EQUAL_2G("2G", "A", "+", "ALL")) { - STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_2GA_P, j); - } else if (STR_EQUAL_2G("2G", "A", "-", "ALL")) { - STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_2GA_N, j); - } else if (STR_EQUAL_2G("2G", "B", "+", "ALL")) { - STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_2GB_P, j); - } else if (STR_EQUAL_2G("2G", "B", "-", "ALL")) { - STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_2GB_N, j); - } else if (STR_EQUAL_5G("5G", "A", "+", "ALL", "0")) { - STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_5GA_P[0], j); - } else if (STR_EQUAL_5G("5G", "A", "-", "ALL", "0")) { - STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_5GA_N[0], j); - } else if (STR_EQUAL_5G("5G", "B", "+", "ALL", "0")) { - STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_5GB_P[0], j); - } else if (STR_EQUAL_5G("5G", "B", "-", "ALL", "0")) { - STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_5GB_N[0], j); - } else if (STR_EQUAL_5G("5G", "A", "+", "ALL", "1")) { - STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_5GA_P[1], j); - } else if (STR_EQUAL_5G("5G", "A", "-", "ALL", "1")) { - STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_5GA_N[1], j); - } else if (STR_EQUAL_5G("5G", "B", "+", "ALL", "1")) { - STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_5GB_P[1], j); - } else if (STR_EQUAL_5G("5G", "B", "-", "ALL", "1")) { - STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_5GB_N[1], j); - } else if (STR_EQUAL_5G("5G", "A", "+", "ALL", "2")) { - STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_5GA_P[2], j); - } else if (STR_EQUAL_5G("5G", "A", "-", "ALL", "2")) { - STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_5GA_N[2], j); - } else if (STR_EQUAL_5G("5G", "B", "+", "ALL", "2")) { - STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_5GB_P[2], j); - } else if (STR_EQUAL_5G("5G", "B", "-", "ALL", "2")) { - STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_5GB_N[2], j); - } else if (STR_EQUAL_5G("5G", "A", "+", "ALL", "3")) { - STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_5GA_P[3], j); - } else if (STR_EQUAL_5G("5G", "A", "-", "ALL", "3")) { - STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_5GA_N[3], j); - } else if (STR_EQUAL_5G("5G", "B", "+", "ALL", "3")) { - STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_5GB_P[3], j); - } else if (STR_EQUAL_5G("5G", "B", "-", "ALL", "3")) { - STORE_SWING_TABLE(pRFCalibrateInfo->DeltaSwingTableIdx_5GB_N[3], j); - } else - DBG_871X("===>initDeltaSwingIndexTables(): The input is invalid!!\n"); -} - -int PHY_ConfigRFWithTxPwrTrackParaFile(struct adapter *Adapter, char *pFileName) -{ - struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); - int rlen = 0, rtStatus = _FAIL; - char *szLine, *ptmp; - - if (!(Adapter->registrypriv.load_phy_file & LOAD_RF_TXPWR_TRACK_PARA_FILE)) - return rtStatus; - - memset(pHalData->para_file_buf, 0, MAX_PARA_FILE_BUF_LEN); - - if ((pHalData->rf_tx_pwr_track_len == 0) && !pHalData->rf_tx_pwr_track) { - rtw_merge_string(file_path_bs, PATH_MAX, rtw_phy_file_path, pFileName); - - if (rtw_is_file_readable(file_path_bs) == true) { - rlen = rtw_retrive_from_file(file_path_bs, pHalData->para_file_buf, MAX_PARA_FILE_BUF_LEN); - if (rlen > 0) { - rtStatus = _SUCCESS; - pHalData->rf_tx_pwr_track = vzalloc(rlen); - if (pHalData->rf_tx_pwr_track) { - memcpy(pHalData->rf_tx_pwr_track, pHalData->para_file_buf, rlen); - pHalData->rf_tx_pwr_track_len = rlen; - } else - DBG_871X("%s rf_tx_pwr_track alloc fail !\n", __func__); - } - } - } else { - if ((pHalData->rf_tx_pwr_track_len != 0) && (pHalData->rf_tx_pwr_track != NULL)) { - memcpy(pHalData->para_file_buf, pHalData->rf_tx_pwr_track, pHalData->rf_tx_pwr_track_len); - rtStatus = _SUCCESS; - } else - DBG_871X("%s(): Critical Error !!!\n", __func__); - } - - if (rtStatus == _SUCCESS) { - /* DBG_871X("%s(): read %s successfully\n", __func__, pFileName); */ - - ptmp = pHalData->para_file_buf; - for (szLine = GetLineFromBuffer(ptmp); szLine != NULL; szLine = GetLineFromBuffer(ptmp)) { - if (!IsCommentString(szLine)) { - char band[5] = "", path[5] = "", sign[5] = ""; - char chnl[5] = "", rate[10] = ""; - char data[300] = ""; /* 100 is too small */ - const int len = strlen(szLine); - int i; - - if (len < 10 || szLine[0] != '[') - continue; - - strncpy(band, szLine+1, 2); - strncpy(path, szLine+5, 1); - strncpy(sign, szLine+8, 1); - - i = 10; /* szLine+10 */ - if (!ParseQualifiedString(szLine, &i, rate, '[', ']')) { - /* DBG_871X("Fail to parse rate!\n"); */ - } - if (!ParseQualifiedString(szLine, &i, chnl, '[', ']')) { - /* DBG_871X("Fail to parse channel group!\n"); */ - } - while (i < len && szLine[i] != '{') - i++; - if (!ParseQualifiedString(szLine, &i, data, '{', '}')) { - /* DBG_871X("Fail to parse data!\n"); */ - } - - initDeltaSwingIndexTables(Adapter, band, path, sign, chnl, rate, data); - } - } - } else - DBG_871X("%s(): No File %s, Load from HWImg Array!\n", __func__, pFileName); - - return rtStatus; -} - -static int phy_ParsePowerLimitTableFile(struct adapter *Adapter, char *buffer) -{ - u32 i = 0, forCnt = 0; - u8 loadingStage = 0, limitValue = 0, fraction = 0; - char *szLine, *ptmp; - int rtStatus = _SUCCESS; - char band[10], bandwidth[10], rateSection[10], - regulation[TXPWR_LMT_MAX_REGULATION_NUM][10], rfPath[10], colNumBuf[10]; - u8 colNum = 0; - - DBG_871X("===>phy_ParsePowerLimitTableFile()\n"); - - if (Adapter->registrypriv.RegDecryptCustomFile == 1) - phy_DecryptBBPgParaFile(Adapter, buffer); - - ptmp = buffer; - for (szLine = GetLineFromBuffer(ptmp); szLine != NULL; szLine = GetLineFromBuffer(ptmp)) { - /* skip comment */ - if (IsCommentString(szLine)) { - continue; - } - - if (loadingStage == 0) { - for (forCnt = 0; forCnt < TXPWR_LMT_MAX_REGULATION_NUM; ++forCnt) - memset((void *) regulation[forCnt], 0, 10); - - memset((void *) band, 0, 10); - memset((void *) bandwidth, 0, 10); - memset((void *) rateSection, 0, 10); - memset((void *) rfPath, 0, 10); - memset((void *) colNumBuf, 0, 10); - - if (szLine[0] != '#' || szLine[1] != '#') - continue; - - /* skip the space */ - i = 2; - while (szLine[i] == ' ' || szLine[i] == '\t') - ++i; - - szLine[--i] = ' '; /* return the space in front of the regulation info */ - - /* Parse the label of the table */ - if (!ParseQualifiedString(szLine, &i, band, ' ', ',')) { - DBG_871X("Fail to parse band!\n"); - return _FAIL; - } - if (!ParseQualifiedString(szLine, &i, bandwidth, ' ', ',')) { - DBG_871X("Fail to parse bandwidth!\n"); - return _FAIL; - } - if (!ParseQualifiedString(szLine, &i, rfPath, ' ', ',')) { - DBG_871X("Fail to parse rf path!\n"); - return _FAIL; - } - if (!ParseQualifiedString(szLine, &i, rateSection, ' ', ',')) { - DBG_871X("Fail to parse rate!\n"); - return _FAIL; - } - - loadingStage = 1; - } else if (loadingStage == 1) { - if (szLine[0] != '#' || szLine[1] != '#') - continue; - - /* skip the space */ - i = 2; - while (szLine[i] == ' ' || szLine[i] == '\t') - ++i; - - if (!eqNByte((u8 *)(szLine + i), (u8 *)("START"), 5)) { - DBG_871X("Lost \"## START\" label\n"); - return _FAIL; - } - - loadingStage = 2; - } else if (loadingStage == 2) { - if (szLine[0] != '#' || szLine[1] != '#') - continue; - - /* skip the space */ - i = 2; - while (szLine[i] == ' ' || szLine[i] == '\t') - ++i; - - if (!ParseQualifiedString(szLine, &i, colNumBuf, '#', '#')) { - DBG_871X("Fail to parse column number!\n"); - return _FAIL; - } - - if (!GetU1ByteIntegerFromStringInDecimal(colNumBuf, &colNum)) - return _FAIL; - - if (colNum > TXPWR_LMT_MAX_REGULATION_NUM) { - DBG_871X( - "invalid col number %d (greater than max %d)\n", - colNum, TXPWR_LMT_MAX_REGULATION_NUM - ); - return _FAIL; - } - - for (forCnt = 0; forCnt < colNum; ++forCnt) { - u8 regulation_name_cnt = 0; - - /* skip the space */ - while (szLine[i] == ' ' || szLine[i] == '\t') - ++i; - - while (szLine[i] != ' ' && szLine[i] != '\t' && szLine[i] != '\0') - regulation[forCnt][regulation_name_cnt++] = szLine[i++]; - /* DBG_871X("regulation %s!\n", regulation[forCnt]); */ - - if (regulation_name_cnt == 0) { - DBG_871X("invalid number of regulation!\n"); - return _FAIL; - } - } - - loadingStage = 3; - } else if (loadingStage == 3) { - char channel[10] = {0}, powerLimit[10] = {0}; - u8 cnt = 0; - - /* the table ends */ - if (szLine[0] == '#' && szLine[1] == '#') { - i = 2; - while (szLine[i] == ' ' || szLine[i] == '\t') - ++i; - - if (eqNByte((u8 *)(szLine + i), (u8 *)("END"), 3)) { - loadingStage = 0; - continue; - } else { - DBG_871X("Wrong format\n"); - DBG_871X("<===== phy_ParsePowerLimitTableFile()\n"); - return _FAIL; - } - } - - if ((szLine[0] != 'c' && szLine[0] != 'C') || - (szLine[1] != 'h' && szLine[1] != 'H')) { - DBG_871X("Meet wrong channel => power limt pair\n"); - continue; - } - i = 2;/* move to the location behind 'h' */ - - /* load the channel number */ - cnt = 0; - while (szLine[i] >= '0' && szLine[i] <= '9') { - channel[cnt] = szLine[i]; - ++cnt; - ++i; - } - /* DBG_871X("chnl %s!\n", channel); */ - - for (forCnt = 0; forCnt < colNum; ++forCnt) { - /* skip the space between channel number and the power limit value */ - while (szLine[i] == ' ' || szLine[i] == '\t') - ++i; - - /* load the power limit value */ - cnt = 0; - fraction = 0; - memset((void *) powerLimit, 0, 10); - while ((szLine[i] >= '0' && szLine[i] <= '9') || szLine[i] == '.') { - if (szLine[i] == '.') { - if ((szLine[i+1] >= '0' && szLine[i+1] <= '9')) { - fraction = szLine[i+1]; - i += 2; - } else { - DBG_871X("Wrong fraction in TXPWR_LMT.txt\n"); - return _FAIL; - } - - break; - } - - powerLimit[cnt] = szLine[i]; - ++cnt; - ++i; - } - - if (powerLimit[0] == '\0') { - powerLimit[0] = '6'; - powerLimit[1] = '3'; - i += 2; - } else { - if (!GetU1ByteIntegerFromStringInDecimal(powerLimit, &limitValue)) - return _FAIL; - - limitValue *= 2; - cnt = 0; - if (fraction == '5') - ++limitValue; - - /* the value is greater or equal to 100 */ - if (limitValue >= 100) { - powerLimit[cnt++] = limitValue/100 + '0'; - limitValue %= 100; - - if (limitValue >= 10) { - powerLimit[cnt++] = limitValue/10 + '0'; - limitValue %= 10; - } else - powerLimit[cnt++] = '0'; - - powerLimit[cnt++] = limitValue + '0'; - } else if (limitValue >= 10) { /* the value is greater or equal to 10 */ - powerLimit[cnt++] = limitValue/10 + '0'; - limitValue %= 10; - powerLimit[cnt++] = limitValue + '0'; - } - /* the value is less than 10 */ - else - powerLimit[cnt++] = limitValue + '0'; - - powerLimit[cnt] = '\0'; - } - - /* DBG_871X("ch%s => %s\n", channel, powerLimit); */ - - /* store the power limit value */ - PHY_SetTxPowerLimit(Adapter, (u8 *)regulation[forCnt], (u8 *)band, - (u8 *)bandwidth, (u8 *)rateSection, (u8 *)rfPath, (u8 *)channel, (u8 *)powerLimit); - - } - } else { - DBG_871X("Abnormal loading stage in phy_ParsePowerLimitTableFile()!\n"); - rtStatus = _FAIL; - break; - } - } - - DBG_871X("<===phy_ParsePowerLimitTableFile()\n"); - return rtStatus; -} - -int PHY_ConfigRFWithPowerLimitTableParaFile( - struct adapter *Adapter, char *pFileName -) -{ - struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); - int rlen = 0, rtStatus = _FAIL; - - if (!(Adapter->registrypriv.load_phy_file & LOAD_RF_TXPWR_LMT_PARA_FILE)) - return rtStatus; - - memset(pHalData->para_file_buf, 0, MAX_PARA_FILE_BUF_LEN); - - if ((pHalData->rf_tx_pwr_lmt_len == 0) && !pHalData->rf_tx_pwr_lmt) { - rtw_merge_string(file_path_bs, PATH_MAX, rtw_phy_file_path, pFileName); - - if (rtw_is_file_readable(file_path_bs) == true) { - rlen = rtw_retrive_from_file(file_path_bs, pHalData->para_file_buf, MAX_PARA_FILE_BUF_LEN); - if (rlen > 0) { - rtStatus = _SUCCESS; - pHalData->rf_tx_pwr_lmt = vzalloc(rlen); - if (pHalData->rf_tx_pwr_lmt) { - memcpy(pHalData->rf_tx_pwr_lmt, pHalData->para_file_buf, rlen); - pHalData->rf_tx_pwr_lmt_len = rlen; - } else - DBG_871X("%s rf_tx_pwr_lmt alloc fail !\n", __func__); - } - } - } else { - if ((pHalData->rf_tx_pwr_lmt_len != 0) && (pHalData->rf_tx_pwr_lmt != NULL)) { - memcpy(pHalData->para_file_buf, pHalData->rf_tx_pwr_lmt, pHalData->rf_tx_pwr_lmt_len); - rtStatus = _SUCCESS; - } else - DBG_871X("%s(): Critical Error !!!\n", __func__); - } - - if (rtStatus == _SUCCESS) { - /* DBG_871X("%s(): read %s ok\n", __func__, pFileName); */ - rtStatus = phy_ParsePowerLimitTableFile(Adapter, pHalData->para_file_buf); - } else - DBG_871X("%s(): No File %s, Load from HWImg Array!\n", __func__, pFileName); - - return rtStatus; -} - -void phy_free_filebuf(struct adapter *padapter) -{ - struct hal_com_data *pHalData = GET_HAL_DATA(padapter); - - if (pHalData->mac_reg) - vfree(pHalData->mac_reg); - if (pHalData->bb_phy_reg) - vfree(pHalData->bb_phy_reg); - if (pHalData->bb_agc_tab) - vfree(pHalData->bb_agc_tab); - if (pHalData->bb_phy_reg_pg) - vfree(pHalData->bb_phy_reg_pg); - if (pHalData->bb_phy_reg_mp) - vfree(pHalData->bb_phy_reg_mp); - if (pHalData->rf_radio_a) - vfree(pHalData->rf_radio_a); - if (pHalData->rf_radio_b) - vfree(pHalData->rf_radio_b); - if (pHalData->rf_tx_pwr_track) - vfree(pHalData->rf_tx_pwr_track); - if (pHalData->rf_tx_pwr_lmt) - vfree(pHalData->rf_tx_pwr_lmt); - -} diff --git a/drivers/staging/rtl8723bs/hal/odm_DIG.c b/drivers/staging/rtl8723bs/hal/odm_DIG.c index 70d98c58ca97..40fe43c62c45 100644 --- a/drivers/staging/rtl8723bs/hal/odm_DIG.c +++ b/drivers/staging/rtl8723bs/hal/odm_DIG.c @@ -1074,7 +1074,6 @@ void odm_FAThresholdCheck( dm_FA_thres[1] = 4000; dm_FA_thres[2] = 5000; } - return; } u8 odm_ForbiddenIGICheck(void *pDM_VOID, u8 DIG_Dynamic_MIN, u8 CurrentIGI) diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_dm.c b/drivers/staging/rtl8723bs/hal/rtl8723b_dm.c index c514cb735afd..650fbedd34e8 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_dm.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_dm.c @@ -188,7 +188,8 @@ void rtl8723b_HalDmWatchDog(struct adapter *Adapter) bBtDisabled = hal_btcoex_IsBtDisabled(Adapter); - ODM_CmnInfoUpdate(&pHalData->odmpriv, ODM_CMNINFO_BT_ENABLED, ((bBtDisabled == true)?false:true)); + ODM_CmnInfoUpdate(&pHalData->odmpriv, ODM_CMNINFO_BT_ENABLED, + !bBtDisabled); ODM_DMWatchdog(&pHalData->odmpriv); } diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c index faeaf24fa833..22931ab3a5fc 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_hal_init.c @@ -3773,7 +3773,6 @@ void C2HPacketHandler_8723B(struct adapter *padapter, u8 *pbuffer, u16 length) process_c2h_event(padapter, &C2hEvent, tmpBuf); /* c2h_handler_8723b(padapter,&C2hEvent); */ - return; } void SetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val) @@ -4157,9 +4156,8 @@ void SetHwReg8723B(struct adapter *padapter, u8 variable, u8 *val) break; } - /* The value of ((usNavUpper + HAL_NAV_UPPER_UNIT_8723B - 1) / HAL_NAV_UPPER_UNIT_8723B) */ - /* is getting the upper integer. */ - usNavUpper = (usNavUpper + HAL_NAV_UPPER_UNIT_8723B - 1) / HAL_NAV_UPPER_UNIT_8723B; + usNavUpper = DIV_ROUND_UP(usNavUpper, + HAL_NAV_UPPER_UNIT_8723B); rtw_write8(padapter, REG_NAV_UPPER, (u8)usNavUpper); } break; diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_phycfg.c b/drivers/staging/rtl8723bs/hal/rtl8723b_phycfg.c index 6df2b58bdc67..cf23414d7224 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_phycfg.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_phycfg.c @@ -362,24 +362,10 @@ void PHY_SetRFReg_8723B( */ s32 PHY_MACConfig8723B(struct adapter *Adapter) { - int rtStatus = _SUCCESS; struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); - s8 *pszMACRegFile; - s8 sz8723MACRegFile[] = RTL8723B_PHY_MACREG; - - - pszMACRegFile = sz8723MACRegFile; - - /* */ - /* Config MAC */ - /* */ - rtStatus = phy_ConfigMACWithParaFile(Adapter, pszMACRegFile); - if (rtStatus == _FAIL) { - ODM_ReadAndConfig_MP_8723B_MAC_REG(&pHalData->odmpriv); - rtStatus = _SUCCESS; - } - return rtStatus; + ODM_ReadAndConfig_MP_8723B_MAC_REG(&pHalData->odmpriv); + return _SUCCESS; } /** @@ -427,17 +413,6 @@ static void phy_InitBBRFRegisterDefinition(struct adapter *Adapter) static int phy_BB8723b_Config_ParaFile(struct adapter *Adapter) { struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); - int rtStatus = _SUCCESS; - u8 sz8723BBRegFile[] = RTL8723B_PHY_REG; - u8 sz8723AGCTableFile[] = RTL8723B_AGC_TAB; - u8 sz8723BBBRegPgFile[] = RTL8723B_PHY_REG_PG; - u8 sz8723BRFTxPwrLmtFile[] = RTL8723B_TXPWR_LMT; - u8 *pszBBRegFile = NULL, *pszAGCTableFile = NULL, *pszBBRegPgFile = NULL, *pszRFTxPwrLmtFile = NULL; - - pszBBRegFile = sz8723BBRegFile; - pszAGCTableFile = sz8723AGCTableFile; - pszBBRegPgFile = sz8723BBBRegPgFile; - pszRFTxPwrLmtFile = sz8723BRFTxPwrLmtFile; /* Read Tx Power Limit File */ PHY_InitTxPowerLimit(Adapter); @@ -445,30 +420,14 @@ static int phy_BB8723b_Config_ParaFile(struct adapter *Adapter) Adapter->registrypriv.RegEnableTxPowerLimit == 1 || (Adapter->registrypriv.RegEnableTxPowerLimit == 2 && pHalData->EEPROMRegulatory == 1) ) { - if (PHY_ConfigRFWithPowerLimitTableParaFile(Adapter, pszRFTxPwrLmtFile) == _FAIL) { - if (HAL_STATUS_SUCCESS != ODM_ConfigRFWithHeaderFile(&pHalData->odmpriv, CONFIG_RF_TXPWR_LMT, (ODM_RF_RADIO_PATH_E)0)) - rtStatus = _FAIL; - } - - if (rtStatus != _SUCCESS) { - DBG_871X("%s():Read Tx power limit fail\n", __func__); - goto phy_BB8190_Config_ParaFile_Fail; - } + ODM_ConfigRFWithHeaderFile(&pHalData->odmpriv, + CONFIG_RF_TXPWR_LMT, 0); } /* */ /* 1. Read PHY_REG.TXT BB INIT!! */ /* */ - if (phy_ConfigBBWithParaFile(Adapter, pszBBRegFile, CONFIG_BB_PHY_REG) == - _FAIL) { - if (HAL_STATUS_SUCCESS != ODM_ConfigBBWithHeaderFile(&pHalData->odmpriv, CONFIG_BB_PHY_REG)) - rtStatus = _FAIL; - } - - if (rtStatus != _SUCCESS) { - DBG_8192C("%s():Write BB Reg Fail!!", __func__); - goto phy_BB8190_Config_ParaFile_Fail; - } + ODM_ConfigBBWithHeaderFile(&pHalData->odmpriv, CONFIG_BB_PHY_REG); /* If EEPROM or EFUSE autoload OK, We must config by PHY_REG_PG.txt */ PHY_InitTxPowerByRate(Adapter); @@ -476,11 +435,8 @@ static int phy_BB8723b_Config_ParaFile(struct adapter *Adapter) Adapter->registrypriv.RegEnableTxPowerByRate == 1 || (Adapter->registrypriv.RegEnableTxPowerByRate == 2 && pHalData->EEPROMRegulatory != 2) ) { - if (phy_ConfigBBWithPgParaFile(Adapter, pszBBRegPgFile) == - _FAIL) { - if (HAL_STATUS_SUCCESS != ODM_ConfigBBWithHeaderFile(&pHalData->odmpriv, CONFIG_BB_PHY_REG_PG)) - rtStatus = _FAIL; - } + ODM_ConfigBBWithHeaderFile(&pHalData->odmpriv, + CONFIG_BB_PHY_REG_PG); if (pHalData->odmpriv.PhyRegPgValueType == PHY_REG_PG_EXACT_VALUE) PHY_TxPowerByRateConfiguration(Adapter); @@ -490,29 +446,14 @@ static int phy_BB8723b_Config_ParaFile(struct adapter *Adapter) (Adapter->registrypriv.RegEnableTxPowerLimit == 2 && pHalData->EEPROMRegulatory == 1) ) PHY_ConvertTxPowerLimitToPowerIndex(Adapter); - - if (rtStatus != _SUCCESS) { - DBG_8192C("%s():BB_PG Reg Fail!!\n", __func__); - } } /* */ /* 2. Read BB AGC table Initialization */ /* */ - if (phy_ConfigBBWithParaFile(Adapter, pszAGCTableFile, - CONFIG_BB_AGC_TAB) == _FAIL) { - if (HAL_STATUS_SUCCESS != ODM_ConfigBBWithHeaderFile(&pHalData->odmpriv, CONFIG_BB_AGC_TAB)) - rtStatus = _FAIL; - } - - if (rtStatus != _SUCCESS) { - DBG_8192C("%s():AGC Table Fail\n", __func__); - goto phy_BB8190_Config_ParaFile_Fail; - } - -phy_BB8190_Config_ParaFile_Fail: + ODM_ConfigBBWithHeaderFile(&pHalData->odmpriv, CONFIG_BB_AGC_TAB); - return rtStatus; + return _SUCCESS; } diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_rf6052.c b/drivers/staging/rtl8723bs/hal/rtl8723b_rf6052.c index d0ffe0af5339..aafceaf9b139 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_rf6052.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_rf6052.c @@ -85,19 +85,8 @@ static int phy_RF6052_Config_ParaFile(struct adapter *Adapter) u32 u4RegValue = 0; u8 eRFPath; struct bb_register_def *pPhyReg; - - int rtStatus = _SUCCESS; struct hal_com_data *pHalData = GET_HAL_DATA(Adapter); - static char sz8723RadioAFile[] = RTL8723B_PHY_RADIO_A; - static char sz8723RadioBFile[] = RTL8723B_PHY_RADIO_B; - static s8 sz8723BTxPwrTrackFile[] = RTL8723B_TXPWR_TRACK; - char *pszRadioAFile, *pszRadioBFile, *pszTxPwrTrackFile; - - pszRadioAFile = sz8723RadioAFile; - pszRadioBFile = sz8723RadioBFile; - pszTxPwrTrackFile = sz8723BTxPwrTrackFile; - /* 3----------------------------------------------------------------- */ /* 3 <2> Initialize RF */ /* 3----------------------------------------------------------------- */ @@ -136,21 +125,11 @@ static int phy_RF6052_Config_ParaFile(struct adapter *Adapter) /*----Initialize RF fom connfiguration file----*/ switch (eRFPath) { case RF_PATH_A: - if (PHY_ConfigRFWithParaFile(Adapter, pszRadioAFile, - eRFPath) == _FAIL) { - if (HAL_STATUS_FAILURE == ODM_ConfigRFWithHeaderFile(&pHalData->odmpriv, CONFIG_RF_RADIO, (ODM_RF_RADIO_PATH_E)eRFPath)) - rtStatus = _FAIL; - } - break; case RF_PATH_B: - if (PHY_ConfigRFWithParaFile(Adapter, pszRadioBFile, - eRFPath) == _FAIL) { - if (HAL_STATUS_FAILURE == ODM_ConfigRFWithHeaderFile(&pHalData->odmpriv, CONFIG_RF_RADIO, (ODM_RF_RADIO_PATH_E)eRFPath)) - rtStatus = _FAIL; - } + ODM_ConfigRFWithHeaderFile(&pHalData->odmpriv, + CONFIG_RF_RADIO, eRFPath); break; case RF_PATH_C: - break; case RF_PATH_D: break; } @@ -166,28 +145,16 @@ static int phy_RF6052_Config_ParaFile(struct adapter *Adapter) PHY_SetBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV << 16, u4RegValue); break; } - - if (rtStatus != _SUCCESS) { - /* RT_TRACE(COMP_FPGA, DBG_LOUD, ("phy_RF6052_Config_ParaFile():Radio[%d] Fail!!", eRFPath)); */ - goto phy_RF6052_Config_ParaFile_Fail; - } - } /* 3 ----------------------------------------------------------------- */ /* 3 Configuration of Tx Power Tracking */ /* 3 ----------------------------------------------------------------- */ - if (PHY_ConfigRFWithTxPwrTrackParaFile(Adapter, pszTxPwrTrackFile) == - _FAIL) { - ODM_ConfigRFWithTxPwrTrackHeaderFile(&pHalData->odmpriv); - } + ODM_ConfigRFWithTxPwrTrackHeaderFile(&pHalData->odmpriv); /* RT_TRACE(COMP_INIT, DBG_LOUD, ("<---phy_RF6052_Config_ParaFile()\n")); */ - return rtStatus; - -phy_RF6052_Config_ParaFile_Fail: - return rtStatus; + return _SUCCESS; } diff --git a/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c b/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c index 0f3301091258..e8577c084bbd 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723bs_recv.c @@ -179,8 +179,6 @@ static void rtl8723bs_c2h_packet_handler(struct adapter *padapter, kfree(tmp); /* DBG_871X("-%s res(%d)\n", __func__, res); */ - - return; } static inline union recv_frame *try_alloc_recvframe(struct recv_priv *precvpriv, diff --git a/drivers/staging/rtl8723bs/hal/sdio_ops.c b/drivers/staging/rtl8723bs/hal/sdio_ops.c index 301d327d0624..b6b4adb5a28a 100644 --- a/drivers/staging/rtl8723bs/hal/sdio_ops.c +++ b/drivers/staging/rtl8723bs/hal/sdio_ops.c @@ -15,7 +15,7 @@ /* */ /* Description: */ -/* The following mapping is for SDIO host local register space. */ +/* The following mapping is for SDIO host local register space. */ /* */ /* Creadted by Roger, 2011.01.31. */ /* */ @@ -61,7 +61,6 @@ static u8 get_deviceid(u32 addr) u8 devide_id; u16 pseudo_id; - pseudo_id = (u16)(addr >> 16); switch (pseudo_id) { case 0x1025: @@ -72,10 +71,6 @@ static u8 get_deviceid(u32 addr) devide_id = WLAN_IOREG_DEVICE_ID; break; -/* case 0x1027: */ -/* devide_id = SDIO_FIRMWARE_FIFO; */ -/* break; */ - case 0x1031: devide_id = WLAN_TX_HIQ_DEVICE_ID; break; @@ -93,7 +88,6 @@ static u8 get_deviceid(u32 addr) break; default: -/* devide_id = (u8)((addr >> 13) & 0xF); */ devide_id = WLAN_IOREG_DEVICE_ID; break; } @@ -111,7 +105,6 @@ static u32 _cvrt2ftaddr(const u32 addr, u8 *pdevice_id, u16 *poffset) u16 offset; u32 ftaddr; - device_id = get_deviceid(addr); offset = 0; @@ -427,20 +420,16 @@ static u32 sdio_read_port( struct adapter *adapter; struct sdio_data *psdio; struct hal_com_data *hal; - u32 oldcnt; s32 err; - adapter = intfhdl->padapter; psdio = &adapter_to_dvobj(adapter)->intf_data; hal = GET_HAL_DATA(adapter); HalSdioGetCmdAddr8723BSdio(adapter, addr, hal->SdioRxFIFOCnt++, &addr); - oldcnt = cnt; if (cnt > psdio->block_transfer_len) cnt = _RND(cnt, psdio->block_transfer_len); -/* cnt = sdio_align_size(cnt); */ err = _sd_read(intfhdl, addr, cnt, mem); @@ -490,7 +479,6 @@ static u32 sdio_write_port( if (cnt > psdio->block_transfer_len) cnt = _RND(cnt, psdio->block_transfer_len); -/* cnt = sdio_align_size(cnt); */ err = sd_write(intfhdl, addr, cnt, xmitbuf->pdata); @@ -538,7 +526,6 @@ static s32 _sdio_local_read( u8 *tmpbuf; u32 n; - intfhdl = &adapter->iopriv.intf; HalSdioGetCmdAddr8723BSdio(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); @@ -711,7 +698,6 @@ static s32 ReadInterrupt8723BSdio(struct adapter *adapter, u32 *phisr) u32 hisr, himr; u8 val8, hisr_len; - if (!phisr) return false; @@ -737,73 +723,48 @@ static s32 ReadInterrupt8723BSdio(struct adapter *adapter, u32 *phisr) } /* */ -/* Description: */ -/* Initialize SDIO Host Interrupt Mask configuration variables for future use. */ +/* Description: */ +/* Initialize SDIO Host Interrupt Mask configuration variables for future use. */ /* */ -/* Assumption: */ -/* Using SDIO Local register ONLY for configuration. */ +/* Assumption: */ +/* Using SDIO Local register ONLY for configuration. */ /* */ -/* Created by Roger, 2011.02.11. */ +/* Created by Roger, 2011.02.11. */ /* */ void InitInterrupt8723BSdio(struct adapter *adapter) { struct hal_com_data *haldata; - haldata = GET_HAL_DATA(adapter); - haldata->sdio_himr = (u32)( \ - SDIO_HIMR_RX_REQUEST_MSK | - SDIO_HIMR_AVAL_MSK | -/* SDIO_HIMR_TXERR_MSK | */ -/* SDIO_HIMR_RXERR_MSK | */ -/* SDIO_HIMR_TXFOVW_MSK | */ -/* SDIO_HIMR_RXFOVW_MSK | */ -/* SDIO_HIMR_TXBCNOK_MSK | */ -/* SDIO_HIMR_TXBCNERR_MSK | */ -/* SDIO_HIMR_BCNERLY_INT_MSK | */ -/* SDIO_HIMR_C2HCMD_MSK | */ -/* SDIO_HIMR_HSISR_IND_MSK | */ -/* SDIO_HIMR_GTINT3_IND_MSK | */ -/* SDIO_HIMR_GTINT4_IND_MSK | */ -/* SDIO_HIMR_PSTIMEOUT_MSK | */ -/* SDIO_HIMR_OCPINT_MSK | */ -/* SDIO_HIMR_ATIMEND_MSK | */ -/* SDIO_HIMR_ATIMEND_E_MSK | */ -/* SDIO_HIMR_CTWEND_MSK | */ - 0); + haldata->sdio_himr = (u32)(SDIO_HIMR_RX_REQUEST_MSK | + SDIO_HIMR_AVAL_MSK | + 0); } /* */ -/* Description: */ -/* Initialize System Host Interrupt Mask configuration variables for future use. */ +/* Description: */ +/* Initialize System Host Interrupt Mask configuration variables for future use. */ /* */ -/* Created by Roger, 2011.08.03. */ +/* Created by Roger, 2011.08.03. */ /* */ void InitSysInterrupt8723BSdio(struct adapter *adapter) { struct hal_com_data *haldata; - haldata = GET_HAL_DATA(adapter); - haldata->SysIntrMask = ( \ -/* HSIMR_GPIO12_0_INT_EN | */ -/* HSIMR_SPS_OCP_INT_EN | */ -/* HSIMR_RON_INT_EN | */ -/* HSIMR_PDNINT_EN | */ -/* HSIMR_GPIO9_INT_EN | */ - 0); + haldata->SysIntrMask = (0); } /* */ -/* Description: */ -/* Enalbe SDIO Host Interrupt Mask configuration on SDIO local domain. */ +/* Description: */ +/* Enalbe SDIO Host Interrupt Mask configuration on SDIO local domain. */ /* */ -/* Assumption: */ -/* 1. Using SDIO Local register ONLY for configuration. */ -/* 2. PASSIVE LEVEL */ +/* Assumption: */ +/* 1. Using SDIO Local register ONLY for configuration. */ +/* 2. PASSIVE LEVEL */ /* */ -/* Created by Roger, 2011.02.11. */ +/* Created by Roger, 2011.02.11. */ /* */ void EnableInterrupt8723BSdio(struct adapter *adapter) { @@ -849,13 +810,13 @@ void EnableInterrupt8723BSdio(struct adapter *adapter) } /* */ -/* Description: */ -/* Disable SDIO Host IMR configuration to mask unnecessary interrupt service. */ +/* Description: */ +/* Disable SDIO Host IMR configuration to mask unnecessary interrupt service. */ /* */ -/* Assumption: */ -/* Using SDIO Local register ONLY for configuration. */ +/* Assumption: */ +/* Using SDIO Local register ONLY for configuration. */ /* */ -/* Created by Roger, 2011.02.11. */ +/* Created by Roger, 2011.02.11. */ /* */ void DisableInterrupt8723BSdio(struct adapter *adapter) { @@ -866,13 +827,13 @@ void DisableInterrupt8723BSdio(struct adapter *adapter) } /* */ -/* Description: */ -/* Using 0x100 to check the power status of FW. */ +/* Description: */ +/* Using 0x100 to check the power status of FW. */ /* */ -/* Assumption: */ -/* Using SDIO Local register ONLY for configuration. */ +/* Assumption: */ +/* Using SDIO Local register ONLY for configuration. */ /* */ -/* Created by Isaac, 2013.09.10. */ +/* Created by Isaac, 2013.09.10. */ /* */ u8 CheckIPSStatus(struct adapter *adapter) { @@ -896,7 +857,6 @@ static struct recv_buf *sd_recv_rxfifo(struct adapter *adapter, u32 size) struct recv_priv *recv_priv; struct recv_buf *recvbuf; - /* Patch for some SDIO Host 4 bytes issue */ /* ex. RK3188 */ readsize = RND4(size); @@ -938,7 +898,6 @@ static struct recv_buf *sd_recv_rxfifo(struct adapter *adapter, u32 size) return NULL; } - /* 3 4. init recvbuf */ recvbuf->len = size; recvbuf->phead = recvbuf->pskb->head; @@ -972,7 +931,6 @@ void sd_int_dpc(struct adapter *adapter) struct intf_hdl *intfhdl = &adapter->iopriv.intf; struct pwrctrl_priv *pwrctl; - hal = GET_HAL_DATA(adapter); dvobj = adapter_to_dvobj(adapter); pwrctl = dvobj_to_pwrctl(dvobj); @@ -992,7 +950,6 @@ void sd_int_dpc(struct adapter *adapter) report.state = SdioLocalCmd52Read1Byte(adapter, SDIO_REG_HCPWM1_8723B); - /* cpwm_int_hdl(adapter, &report); */ _set_workitem(&(pwrctl->cpwm_event)); } @@ -1029,7 +986,7 @@ void sd_int_dpc(struct adapter *adapter) if (c2h_id_filter_ccx_8723b((u8 *)c2h_evt)) { /* Handle CCX report here */ rtw_hal_c2h_handler(adapter, (u8 *)c2h_evt); - kfree((u8 *)c2h_evt); + kfree(c2h_evt); } else { rtw_c2h_wk_cmd(adapter, (u8 *)c2h_evt); } @@ -1049,13 +1006,11 @@ void sd_int_dpc(struct adapter *adapter) if (hal->sdio_hisr & SDIO_HISR_RXERR) DBG_8192C("%s: Rx Error\n", __func__); - if (hal->sdio_hisr & SDIO_HISR_RX_REQUEST) { struct recv_buf *recvbuf; int alloc_fail_time = 0; u32 hisr; -/* DBG_8192C("%s: RX Request, size =%d\n", __func__, hal->SdioRxFIFOSize); */ hal->sdio_hisr ^= SDIO_HISR_RX_REQUEST; do { hal->SdioRxFIFOSize = SdioLocalCmd52Read2Byte(adapter, SDIO_REG_RX0_REQ_LEN); @@ -1090,7 +1045,6 @@ void sd_int_hdl(struct adapter *adapter) { struct hal_com_data *hal; - if ( (adapter->bDriverStopped) || (adapter->bSurpriseRemoved) ) @@ -1120,27 +1074,24 @@ void sd_int_hdl(struct adapter *adapter) } /* */ -/* Description: */ -/* Query SDIO Local register to query current the number of Free TxPacketBuffer page. */ +/* Description: */ +/* Query SDIO Local register to query current the number of Free TxPacketBuffer page. */ /* */ -/* Assumption: */ -/* 1. Running at PASSIVE_LEVEL */ -/* 2. RT_TX_SPINLOCK is NOT acquired. */ +/* Assumption: */ +/* 1. Running at PASSIVE_LEVEL */ +/* 2. RT_TX_SPINLOCK is NOT acquired. */ /* */ -/* Created by Roger, 2011.01.28. */ +/* Created by Roger, 2011.01.28. */ /* */ u8 HalQueryTxBufferStatus8723BSdio(struct adapter *adapter) { struct hal_com_data *hal; u32 numof_free_page; - /* _irql irql; */ - hal = GET_HAL_DATA(adapter); numof_free_page = SdioLocalCmd53Read4Byte(adapter, SDIO_REG_FREE_TXPG); - /* spin_lock_bh(&phal->SdioTxFIFOFreePageLock); */ memcpy(hal->SdioTxFIFOFreePage, &numof_free_page, 4); RT_TRACE(_module_hci_ops_c_, _drv_notice_, ("%s: Free page for HIQ(%#x), MIDQ(%#x), LOWQ(%#x), PUBQ(%#x)\n", @@ -1149,14 +1100,13 @@ u8 HalQueryTxBufferStatus8723BSdio(struct adapter *adapter) hal->SdioTxFIFOFreePage[MID_QUEUE_IDX], hal->SdioTxFIFOFreePage[LOW_QUEUE_IDX], hal->SdioTxFIFOFreePage[PUBLIC_QUEUE_IDX])); - /* spin_unlock_bh(&hal->SdioTxFIFOFreePageLock); */ return true; } /* */ -/* Description: */ -/* Query SDIO Local register to get the current number of TX OQT Free Space. */ +/* Description: */ +/* Query SDIO Local register to get the current number of TX OQT Free Space. */ /* */ void HalQueryTxOQTBufferStatus8723BSdio(struct adapter *adapter) { @@ -1190,7 +1140,6 @@ u8 RecvOnePkt(struct adapter *adapter, u32 size) recvbuf = sd_recv_rxfifo(adapter, size); if (recvbuf) { - /* printk("Completed Recv One Pkt.\n"); */ sd_rxhandler(adapter, recvbuf); res = true; } else { diff --git a/drivers/staging/rtl8723bs/include/drv_types.h b/drivers/staging/rtl8723bs/include/drv_types.h index 8d7fce1e39b7..6ec9087f2eb1 100644 --- a/drivers/staging/rtl8723bs/include/drv_types.h +++ b/drivers/staging/rtl8723bs/include/drv_types.h @@ -197,9 +197,6 @@ struct registry_priv u8 RFE_Type; u8 check_fw_ps; - u8 load_phy_file; - u8 RegDecryptCustomFile; - #ifdef CONFIG_MULTI_VIR_IFACES u8 ext_iface_num;/* primary/secondary iface is excluded */ #endif @@ -693,7 +690,6 @@ void rtw_indicate_wx_disassoc_event(struct adapter *padapter); void indicate_wx_scan_complete_event(struct adapter *padapter); int rtw_change_ifname(struct adapter *padapter, const char *ifname); -extern char *rtw_phy_file_path; extern char *rtw_initmac; extern int rtw_mc2u_disable; extern int rtw_ht_enable; diff --git a/drivers/staging/rtl8723bs/include/hal_com_phycfg.h b/drivers/staging/rtl8723bs/include/hal_com_phycfg.h index 9167f1e7827f..e9a3006a3e20 100644 --- a/drivers/staging/rtl8723bs/include/hal_com_phycfg.h +++ b/drivers/staging/rtl8723bs/include/hal_com_phycfg.h @@ -219,30 +219,4 @@ struct adapter * Adapter, u16 ChannelPlan ); -#define MAX_PARA_FILE_BUF_LEN 25600 - -#define LOAD_MAC_PARA_FILE BIT0 -#define LOAD_BB_PARA_FILE BIT1 -#define LOAD_BB_PG_PARA_FILE BIT2 -#define LOAD_BB_MP_PARA_FILE BIT3 -#define LOAD_RF_PARA_FILE BIT4 -#define LOAD_RF_TXPWR_TRACK_PARA_FILE BIT5 -#define LOAD_RF_TXPWR_LMT_PARA_FILE BIT6 - -int phy_ConfigMACWithParaFile(struct adapter *Adapter, char*pFileName); - -int phy_ConfigBBWithParaFile(struct adapter *Adapter, char*pFileName, u32 ConfigType); - -int phy_ConfigBBWithPgParaFile(struct adapter *Adapter, char*pFileName); - -int phy_ConfigBBWithMpParaFile(struct adapter *Adapter, char*pFileName); - -int PHY_ConfigRFWithParaFile(struct adapter *Adapter, char*pFileName, u8 eRFPath); - -int PHY_ConfigRFWithTxPwrTrackParaFile(struct adapter *Adapter, char*pFileName); - -int PHY_ConfigRFWithPowerLimitTableParaFile(struct adapter *Adapter, char*pFileName); - -void phy_free_filebuf(struct adapter *padapter); - #endif /* __HAL_COMMON_H__ */ diff --git a/drivers/staging/rtl8723bs/include/hal_data.h b/drivers/staging/rtl8723bs/include/hal_data.h index 7d782659a84f..e5e667df6154 100644 --- a/drivers/staging/rtl8723bs/include/hal_data.h +++ b/drivers/staging/rtl8723bs/include/hal_data.h @@ -440,27 +440,6 @@ struct hal_com_data { u32 SysIntrStatus; u32 SysIntrMask; - - char para_file_buf[MAX_PARA_FILE_BUF_LEN]; - char *mac_reg; - u32 mac_reg_len; - char *bb_phy_reg; - u32 bb_phy_reg_len; - char *bb_agc_tab; - u32 bb_agc_tab_len; - char *bb_phy_reg_pg; - u32 bb_phy_reg_pg_len; - char *bb_phy_reg_mp; - u32 bb_phy_reg_mp_len; - char *rf_radio_a; - u32 rf_radio_a_len; - char *rf_radio_b; - u32 rf_radio_b_len; - char *rf_tx_pwr_track; - u32 rf_tx_pwr_track_len; - char *rf_tx_pwr_lmt; - u32 rf_tx_pwr_lmt_len; - #ifdef CONFIG_BACKGROUND_NOISE_MONITOR s16 noise[ODM_MAX_CHANNEL_NUM]; #endif diff --git a/drivers/staging/rtl8723bs/include/osdep_service.h b/drivers/staging/rtl8723bs/include/osdep_service.h index 81a9c19ecc6a..a40cf7b60a69 100644 --- a/drivers/staging/rtl8723bs/include/osdep_service.h +++ b/drivers/staging/rtl8723bs/include/osdep_service.h @@ -171,10 +171,6 @@ extern void rtw_softap_lock_suspend(void); extern void rtw_softap_unlock_suspend(void); #endif -/* File operation APIs, just for linux now */ -extern int rtw_is_file_readable(char *path); -extern int rtw_retrive_from_file(char *path, u8 *buf, u32 sz); - extern void rtw_free_netdev(struct net_device * netdev); diff --git a/drivers/staging/rtl8723bs/include/osdep_service_linux.h b/drivers/staging/rtl8723bs/include/osdep_service_linux.h index c582ede1ac12..a2d9de866c4b 100644 --- a/drivers/staging/rtl8723bs/include/osdep_service_linux.h +++ b/drivers/staging/rtl8723bs/include/osdep_service_linux.h @@ -127,13 +127,6 @@ static inline void rtw_netif_stop_queue(struct net_device *pnetdev) netif_tx_stop_all_queues(pnetdev); } -static inline void rtw_merge_string(char *dst, int dst_len, char *src1, char *src2) -{ - int len = 0; - len += snprintf(dst+len, dst_len - len, "%s", src1); - len += snprintf(dst+len, dst_len - len, "%s", src2); -} - #define rtw_signal_process(pid, sig) kill_pid(find_vpid((pid)), (sig), 1) #define rtw_netdev_priv(netdev) (((struct rtw_netdev_priv_indicator *)netdev_priv(netdev))->priv) diff --git a/drivers/staging/rtl8723bs/include/rtl8723b_hal.h b/drivers/staging/rtl8723bs/include/rtl8723b_hal.h index 8f00ced1c697..f36516fa84c7 100644 --- a/drivers/staging/rtl8723bs/include/rtl8723b_hal.h +++ b/drivers/staging/rtl8723bs/include/rtl8723b_hal.h @@ -21,21 +21,6 @@ #include "hal_phy_cfg.h" /* */ -/* RTL8723B From file */ -/* */ -#define RTL8723B_FW_IMG "rtl8723b/FW_NIC.bin" -#define RTL8723B_FW_WW_IMG "rtl8723b/FW_WoWLAN.bin" -#define RTL8723B_PHY_REG "rtl8723b/PHY_REG.txt" -#define RTL8723B_PHY_RADIO_A "rtl8723b/RadioA.txt" -#define RTL8723B_PHY_RADIO_B "rtl8723b/RadioB.txt" -#define RTL8723B_TXPWR_TRACK "rtl8723b/TxPowerTrack.txt" -#define RTL8723B_AGC_TAB "rtl8723b/AGC_TAB.txt" -#define RTL8723B_PHY_MACREG "rtl8723b/MAC_REG.txt" -#define RTL8723B_PHY_REG_PG "rtl8723b/PHY_REG_PG.txt" -#define RTL8723B_PHY_REG_MP "rtl8723b/PHY_REG_MP.txt" -#define RTL8723B_TXPWR_LMT "rtl8723b/TXPWR_LMT.txt" - -/* */ /* RTL8723B From header */ /* */ diff --git a/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h b/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h index fd3cf955c9f8..73e8ec09b6e1 100644 --- a/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h +++ b/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h @@ -576,7 +576,6 @@ void read_cam(struct adapter *padapter , u8 entry, u8 *get_key); /* modify HW only */ void _write_cam(struct adapter *padapter, u8 entry, u16 ctrl, u8 *mac, u8 *key); void _clear_cam_entry(struct adapter *padapter, u8 entry); -void write_cam_from_cache(struct adapter *adapter, u8 id); /* modify both HW and cache */ void write_cam(struct adapter *padapter, u8 id, u16 ctrl, u8 *mac, u8 *key); diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c index f819abb756dc..52c1f6625038 100644 --- a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c +++ b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c @@ -165,7 +165,7 @@ static void rtw_spt_band_free(struct ieee80211_supported_band *spt_band) + sizeof(struct ieee80211_channel)*RTW_2G_CHANNELS_NUM + sizeof(struct ieee80211_rate)*RTW_G_RATES_NUM; } - kfree((u8 *)spt_band); + kfree(spt_band); } static const struct ieee80211_txrx_stypes @@ -1156,7 +1156,7 @@ static int cfg80211_rtw_add_key(struct wiphy *wiphy, struct net_device *ndev, } addkey_end: - kfree((u8 *)param); + kfree(param); return ret; @@ -1410,19 +1410,19 @@ void rtw_cfg80211_unlink_bss(struct adapter *padapter, struct wlan_network *pnet struct wireless_dev *pwdev = padapter->rtw_wdev; struct wiphy *wiphy = pwdev->wiphy; struct cfg80211_bss *bss = NULL; - struct wlan_bssid_ex select_network = pnetwork->network; + struct wlan_bssid_ex *select_network = &pnetwork->network; bss = cfg80211_get_bss(wiphy, NULL/*notify_channel*/, - select_network.MacAddress, select_network.Ssid.Ssid, - select_network.Ssid.SsidLength, 0/*WLAN_CAPABILITY_ESS*/, + select_network->MacAddress, select_network->Ssid.Ssid, + select_network->Ssid.SsidLength, 0/*WLAN_CAPABILITY_ESS*/, 0/*WLAN_CAPABILITY_ESS*/); if (bss) { cfg80211_unlink_bss(wiphy, bss); - DBG_8192C("%s(): cfg80211_unlink %s!! () ", __func__, select_network.Ssid.Ssid); + DBG_8192C("%s(): cfg80211_unlink %s!! () ", __func__, + select_network->Ssid.Ssid); cfg80211_put_bss(padapter->rtw_wdev->wiphy, bss); } - return; } void rtw_cfg80211_surveydone_event_callback(struct adapter *padapter) @@ -1513,7 +1513,7 @@ static int cfg80211_rtw_scan(struct wiphy *wiphy int i; u8 _status = false; int ret = 0; - struct ndis_802_11_ssid ssid[RTW_SSID_SCAN_AMOUNT]; + struct ndis_802_11_ssid *ssid = NULL; struct rtw_ieee80211_channel ch[RTW_CHANNEL_SCAN_AMOUNT]; u8 survey_times =3; u8 survey_times_for_one_ch =6; @@ -1604,7 +1604,13 @@ static int cfg80211_rtw_scan(struct wiphy *wiphy goto check_need_indicate_scan_done; } - memset(ssid, 0, sizeof(struct ndis_802_11_ssid)*RTW_SSID_SCAN_AMOUNT); + ssid = kzalloc(RTW_SSID_SCAN_AMOUNT * sizeof(struct ndis_802_11_ssid), + GFP_KERNEL); + if (!ssid) { + ret = -ENOMEM; + goto check_need_indicate_scan_done; + } + /* parsing request ssids, n_ssids */ for (i = 0; i < request->n_ssids && i < RTW_SSID_SCAN_AMOUNT; i++) { #ifdef DEBUG_CFG80211 @@ -1648,6 +1654,7 @@ static int cfg80211_rtw_scan(struct wiphy *wiphy } check_need_indicate_scan_done: + kfree(ssid); if (need_indicate_scan_done) { rtw_cfg80211_surveydone_event_callback(padapter); @@ -2194,7 +2201,7 @@ static int cfg80211_rtw_connect(struct wiphy *wiphy, struct net_device *ndev, ret = -EOPNOTSUPP ; } - kfree((u8 *)pwep); + kfree(pwep); if (ret < 0) goto exit; @@ -2433,7 +2440,6 @@ void rtw_cfg80211_indicate_sta_disassoc(struct adapter *padapter, unsigned char static netdev_tx_t rtw_cfg80211_monitor_if_xmit_entry(struct sk_buff *skb, struct net_device *ndev) { - int ret = 0; int rtap_len; int qos_len = 0; int dot11_hdr_len = 24; @@ -2499,9 +2505,7 @@ static netdev_tx_t rtw_cfg80211_monitor_if_xmit_entry(struct sk_buff *skb, struc DBG_8192C("should be eapol packet\n"); /* Use the real net device to transmit the packet */ - ret = _rtw_xmit_entry(skb, padapter->pnetdev); - - return ret; + return _rtw_xmit_entry(skb, padapter->pnetdev); } else if ((frame_control & (IEEE80211_FCTL_FTYPE|IEEE80211_FCTL_STYPE)) @@ -2647,7 +2651,7 @@ static int rtw_cfg80211_add_monitor_if (struct adapter *padapter, char *name, st out: if (ret && mon_wdev) { - kfree((u8 *)mon_wdev); + kfree(mon_wdev); mon_wdev = NULL; } @@ -2808,14 +2812,11 @@ static int cfg80211_rtw_start_ap(struct wiphy *wiphy, struct net_device *ndev, static int cfg80211_rtw_change_beacon(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_beacon_data *info) { - int ret = 0; struct adapter *adapter = (struct adapter *)rtw_netdev_priv(ndev); DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); - ret = rtw_add_beacon(adapter, info->head, info->head_len, info->tail, info->tail_len); - - return ret; + return rtw_add_beacon(adapter, info->head, info->head_len, info->tail, info->tail_len); } static int cfg80211_rtw_stop_ap(struct wiphy *wiphy, struct net_device *ndev) @@ -3503,7 +3504,7 @@ void rtw_wdev_free(struct wireless_dev *wdev) wiphy_free(wdev->wiphy); - kfree((u8 *)wdev); + kfree(wdev); } void rtw_wdev_unregister(struct wireless_dev *wdev) diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c index d1b199e3e5bd..db6528a01229 100644 --- a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c @@ -2425,19 +2425,13 @@ static int rtw_drvext_hdl(struct net_device *dev, struct iw_request_info *info, return 0; } -static int rtw_mp_ioctl_hdl(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - int ret = 0; - return ret; -} - static int rtw_get_ap_info(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { int ret = 0; - u32 cnt = 0, wpa_ielen; + int wpa_ielen; + u32 cnt = 0; struct list_head *plist, *phead; unsigned char *pbuf; u8 bssid[ETH_ALEN]; @@ -2793,7 +2787,7 @@ static int rtw_dbg_port(struct net_device *dev, DBG_871X("oper_ch =%d\n", rtw_get_oper_ch(padapter)); DBG_871X("oper_bw =%d\n", rtw_get_oper_bw(padapter)); - DBG_871X("oper_ch_offet =%d\n", rtw_get_oper_choffset(padapter)); + DBG_871X("oper_ch_offset =%d\n", rtw_get_oper_choffset(padapter)); break; case 0x05: @@ -4458,43 +4452,6 @@ static int rtw_pm_set(struct net_device *dev, return ret; } -static int rtw_mp_efuse_get(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wdata, char *extra) -{ - int err = 0; - return err; -} - -static int rtw_mp_efuse_set(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wdata, char *extra) -{ - int err = 0; - return err; -} - -static int rtw_tdls(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - int ret = 0; - return ret; -} - - -static int rtw_tdls_get(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - int ret = 0; - return ret; -} - - - - - static int rtw_test( struct net_device *dev, struct iw_request_info *info, @@ -4744,7 +4701,7 @@ static iw_handler rtw_private_handler[] = { rtw_wx_write32, /* 0x00 */ rtw_wx_read32, /* 0x01 */ rtw_drvext_hdl, /* 0x02 */ - rtw_mp_ioctl_hdl, /* 0x03 */ + NULL, /* 0x03 */ /* for MM DTV platform */ rtw_get_ap_info, /* 0x04 */ @@ -4771,15 +4728,15 @@ static iw_handler rtw_private_handler[] = { NULL, /* 0x12 */ rtw_p2p_get2, /* 0x13 */ - rtw_tdls, /* 0x14 */ - rtw_tdls_get, /* 0x15 */ + NULL, /* 0x14 */ + NULL, /* 0x15 */ rtw_pm_set, /* 0x16 */ rtw_wx_priv_null, /* 0x17 */ rtw_rereg_nd_name, /* 0x18 */ rtw_wx_priv_null, /* 0x19 */ - rtw_mp_efuse_set, /* 0x1A */ - rtw_mp_efuse_get, /* 0x1B */ + NULL, /* 0x1A */ + NULL, /* 0x1B */ NULL, /* 0x1C is reserved for hostapd */ rtw_test, /* 0x1D */ }; diff --git a/drivers/staging/rtl8723bs/os_dep/os_intfs.c b/drivers/staging/rtl8723bs/os_dep/os_intfs.c index ec3a75485233..47e984d5b7cb 100644 --- a/drivers/staging/rtl8723bs/os_dep/os_intfs.c +++ b/drivers/staging/rtl8723bs/os_dep/os_intfs.c @@ -201,24 +201,6 @@ MODULE_PARM_DESC(rtw_tx_pwr_lmt_enable, "0:Disable, 1:Enable, 2: Depend on efuse module_param(rtw_tx_pwr_by_rate, int, 0644); MODULE_PARM_DESC(rtw_tx_pwr_by_rate, "0:Disable, 1:Enable, 2: Depend on efuse"); -char *rtw_phy_file_path = ""; -module_param(rtw_phy_file_path, charp, 0644); -MODULE_PARM_DESC(rtw_phy_file_path, "The path of phy parameter"); -/* PHY FILE Bit Map */ -/* BIT0 - MAC, 0: non-support, 1: support */ -/* BIT1 - BB, 0: non-support, 1: support */ -/* BIT2 - BB_PG, 0: non-support, 1: support */ -/* BIT3 - BB_MP, 0: non-support, 1: support */ -/* BIT4 - RF, 0: non-support, 1: support */ -/* BIT5 - RF_TXPWR_TRACK, 0: non-support, 1: support */ -/* BIT6 - RF_TXPWR_LMT, 0: non-support, 1: support */ -static int rtw_load_phy_file = (BIT2 | BIT6); -module_param(rtw_load_phy_file, int, 0644); -MODULE_PARM_DESC(rtw_load_phy_file, "PHY File Bit Map"); -static int rtw_decrypt_phy_file; -module_param(rtw_decrypt_phy_file, int, 0644); -MODULE_PARM_DESC(rtw_decrypt_phy_file, "Enable Decrypt PHY File"); - int _netdev_open(struct net_device *pnetdev); int netdev_open (struct net_device *pnetdev); static int netdev_close (struct net_device *pnetdev); @@ -321,8 +303,6 @@ static void loadparam(struct adapter *padapter, _nic_hdl pnetdev) registry_par->bEn_RFE = 1; registry_par->RFE_Type = 64; - registry_par->load_phy_file = (u8)rtw_load_phy_file; - registry_par->RegDecryptCustomFile = (u8)rtw_decrypt_phy_file; registry_par->qos_opt_enable = (u8)rtw_qos_opt_enable; registry_par->hiq_filter = (u8)rtw_hiq_filter; @@ -1141,8 +1121,7 @@ void rtw_ndev_destructor(struct net_device *ndev) { DBG_871X(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev)); - if (ndev->ieee80211_ptr) - kfree((u8 *)ndev->ieee80211_ptr); + kfree(ndev->ieee80211_ptr); } void rtw_dev_unload(struct adapter *padapter) diff --git a/drivers/staging/rtl8723bs/os_dep/osdep_service.c b/drivers/staging/rtl8723bs/os_dep/osdep_service.c index 25a80041ce87..f5614e56371e 100644 --- a/drivers/staging/rtl8723bs/os_dep/osdep_service.c +++ b/drivers/staging/rtl8723bs/os_dep/osdep_service.c @@ -65,142 +65,6 @@ void _rtw_init_queue(struct __queue *pqueue) spin_lock_init(&(pqueue->lock)); } -/* -* Open a file with the specific @param path, @param flag, @param mode -* @param fpp the pointer of struct file pointer to get struct file pointer while file opening is success -* @param path the path of the file to open -* @param flag file operation flags, please refer to linux document -* @param mode please refer to linux document -* @return Linux specific error code -*/ -static int openFile(struct file **fpp, char *path, int flag, int mode) -{ - struct file *fp; - - fp = filp_open(path, flag, mode); - if (IS_ERR(fp)) { - *fpp = NULL; - return PTR_ERR(fp); - } - else { - *fpp = fp; - return 0; - } -} - -/* -* Close the file with the specific @param fp -* @param fp the pointer of struct file to close -* @return always 0 -*/ -static int closeFile(struct file *fp) -{ - filp_close(fp, NULL); - return 0; -} - -static int readFile(struct file *fp, char *buf, int len) -{ - int rlen = 0, sum = 0; - - if (!fp->f_op || !fp->f_op->read) - return -EPERM; - - while (sum < len) { - rlen = kernel_read(fp, buf + sum, len - sum, &fp->f_pos); - if (rlen > 0) - sum += rlen; - else if (0 != rlen) - return rlen; - else - break; - } - - return sum; - -} - -/* -* Test if the specifi @param path is a file and readable -* @param path the path of the file to test -* @return Linux specific error code -*/ -static int isFileReadable(char *path) -{ - struct file *fp; - int ret = 0; - char buf; - - fp = filp_open(path, O_RDONLY, 0); - if (IS_ERR(fp)) - return PTR_ERR(fp); - - if (readFile(fp, &buf, 1) != 1) - ret = -EINVAL; - - filp_close(fp, NULL); - return ret; -} - -/* -* Open the file with @param path and retrive the file content into memory starting from @param buf for @param sz at most -* @param path the path of the file to open and read -* @param buf the starting address of the buffer to store file content -* @param sz how many bytes to read at most -* @return the byte we've read, or Linux specific error code -*/ -static int retriveFromFile(char *path, u8 *buf, u32 sz) -{ - int ret = -1; - struct file *fp; - - if (path && buf) { - ret = openFile(&fp, path, O_RDONLY, 0); - - if (ret == 0) { - DBG_871X("%s openFile path:%s fp =%p\n", __func__, path , fp); - - ret = readFile(fp, buf, sz); - closeFile(fp); - - DBG_871X("%s readFile, ret:%d\n", __func__, ret); - - } else { - DBG_871X("%s openFile path:%s Fail, ret:%d\n", __func__, path, ret); - } - } else { - DBG_871X("%s NULL pointer\n", __func__); - ret = -EINVAL; - } - return ret; -} - -/* -* Test if the specifi @param path is a file and readable -* @param path the path of the file to test -* @return true or false -*/ -int rtw_is_file_readable(char *path) -{ - if (isFileReadable(path) == 0) - return true; - else - return false; -} - -/* -* Open the file with @param path and retrive the file content into memory starting from @param buf for @param sz at most -* @param path the path of the file to open and read -* @param buf the starting address of the buffer to store file content -* @param sz how many bytes to read at most -* @return the byte we've read -*/ -int rtw_retrive_from_file(char *path, u8 *buf, u32 sz) -{ - int ret = retriveFromFile(path, buf, sz); - return ret >= 0 ? ret : 0; -} - struct net_device *rtw_alloc_etherdev_with_old_priv(int sizeof_priv, void *old_priv) { struct net_device *pnetdev; diff --git a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c index d3784c44f6d0..12f683e2e0e2 100644 --- a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c +++ b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c @@ -281,7 +281,6 @@ static void sdio_dvobj_deinit(struct sdio_func *func) sdio_deinit(dvobj); devobj_deinit(dvobj); } - return; } void rtw_set_hal_ops(struct adapter *padapter) diff --git a/drivers/staging/rts5208/ms.c b/drivers/staging/rts5208/ms.c index e853fa9cc950..d53dd138a356 100644 --- a/drivers/staging/rts5208/ms.c +++ b/drivers/staging/rts5208/ms.c @@ -590,7 +590,7 @@ static int ms_identify_media_type(struct rtsx_chip *chip, int switch_8bit_bus) int retval, i; u8 val; - retval = ms_set_rw_reg_addr(chip, Pro_StatusReg, 6, SystemParm, 1); + retval = ms_set_rw_reg_addr(chip, PRO_STATUS_REG, 6, SYSTEM_PARAM, 1); if (retval != STATUS_SUCCESS) return STATUS_FAIL; @@ -840,7 +840,7 @@ static int msxc_change_power(struct rtsx_chip *chip, u8 mode) ms_cleanup_work(chip); - retval = ms_set_rw_reg_addr(chip, 0, 0, Pro_DataCount1, 6); + retval = ms_set_rw_reg_addr(chip, 0, 0, PRO_DATA_COUNT1, 6); if (retval != STATUS_SUCCESS) return STATUS_FAIL; @@ -885,7 +885,7 @@ static int ms_read_attribute_info(struct rtsx_chip *chip) int found_sys_info = 0, found_model_name = 0; #endif - retval = ms_set_rw_reg_addr(chip, Pro_IntReg, 2, Pro_SystemParm, 7); + retval = ms_set_rw_reg_addr(chip, PRO_INT_REG, 2, PRO_SYSTEM_PARAM, 7); if (retval != STATUS_SUCCESS) return STATUS_FAIL; @@ -1232,7 +1232,7 @@ static int ms_read_status_reg(struct rtsx_chip *chip) int retval; u8 val[2]; - retval = ms_set_rw_reg_addr(chip, StatusReg0, 2, 0, 0); + retval = ms_set_rw_reg_addr(chip, STATUS_REG0, 2, 0, 0); if (retval != STATUS_SUCCESS) return STATUS_FAIL; @@ -1255,8 +1255,8 @@ static int ms_read_extra_data(struct rtsx_chip *chip, int retval, i; u8 val, data[10]; - retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, - SystemParm, 6); + retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG, MS_EXTRA_SIZE, + SYSTEM_PARAM, 6); if (retval != STATUS_SUCCESS) return STATUS_FAIL; @@ -1307,8 +1307,8 @@ static int ms_read_extra_data(struct rtsx_chip *chip, if (retval != STATUS_SUCCESS) return STATUS_FAIL; - retval = ms_set_rw_reg_addr(chip, OverwriteFlag, - MS_EXTRA_SIZE, SystemParm, + retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG, + MS_EXTRA_SIZE, SYSTEM_PARAM, 6); if (retval != STATUS_SUCCESS) return STATUS_FAIL; @@ -1339,8 +1339,8 @@ static int ms_write_extra_data(struct rtsx_chip *chip, u16 block_addr, if (!buf || (buf_len < MS_EXTRA_SIZE)) return STATUS_FAIL; - retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, - SystemParm, 6 + MS_EXTRA_SIZE); + retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG, MS_EXTRA_SIZE, + SYSTEM_PARAM, 6 + MS_EXTRA_SIZE); if (retval != STATUS_SUCCESS) return STATUS_FAIL; @@ -1392,8 +1392,8 @@ static int ms_read_page(struct rtsx_chip *chip, u16 block_addr, u8 page_num) int retval; u8 val, data[6]; - retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, - SystemParm, 6); + retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG, MS_EXTRA_SIZE, + SYSTEM_PARAM, 6); if (retval != STATUS_SUCCESS) return STATUS_FAIL; @@ -1465,8 +1465,8 @@ static int ms_set_bad_block(struct rtsx_chip *chip, u16 phy_blk) if (retval != STATUS_SUCCESS) return STATUS_FAIL; - retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, - SystemParm, 7); + retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG, MS_EXTRA_SIZE, + SYSTEM_PARAM, 7); if (retval != STATUS_SUCCESS) return STATUS_FAIL; @@ -1519,8 +1519,8 @@ static int ms_erase_block(struct rtsx_chip *chip, u16 phy_blk) int retval, i = 0; u8 val, data[6]; - retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, - SystemParm, 6); + retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG, MS_EXTRA_SIZE, + SYSTEM_PARAM, 6); if (retval != STATUS_SUCCESS) return STATUS_FAIL; @@ -1579,7 +1579,7 @@ static void ms_set_page_status(u16 log_blk, u8 type, u8 *extra, int extra_len) memset(extra, 0xFF, MS_EXTRA_SIZE); - if (type == setPS_NG) { + if (type == set_PS_NG) { /* set page status as 1:NG,and block status keep 1:OK */ extra[0] = 0xB8; } else { @@ -1670,8 +1670,8 @@ static int ms_copy_page(struct rtsx_chip *chip, u16 old_blk, u16 new_blk, if (retval != STATUS_SUCCESS) return STATUS_FAIL; - retval = ms_set_rw_reg_addr(chip, OverwriteFlag, - MS_EXTRA_SIZE, SystemParm, 6); + retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG, + MS_EXTRA_SIZE, SYSTEM_PARAM, 6); if (retval != STATUS_SUCCESS) return STATUS_FAIL; @@ -1725,7 +1725,7 @@ static int ms_copy_page(struct rtsx_chip *chip, u16 old_blk, u16 new_blk, return STATUS_FAIL; if (uncorrect_flag) { - ms_set_page_status(log_blk, setPS_NG, + ms_set_page_status(log_blk, set_PS_NG, extra, MS_EXTRA_SIZE); if (i == 0) @@ -1738,8 +1738,8 @@ static int ms_copy_page(struct rtsx_chip *chip, u16 old_blk, u16 new_blk, i, extra[0]); MS_SET_BAD_BLOCK_FLG(ms_card); - ms_set_page_status(log_blk, setPS_Error, - extra, + ms_set_page_status(log_blk, + set_PS_error, extra, MS_EXTRA_SIZE); ms_write_extra_data(chip, new_blk, i, extra, @@ -1767,8 +1767,8 @@ static int ms_copy_page(struct rtsx_chip *chip, u16 old_blk, u16 new_blk, } } - retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, - SystemParm, (6 + MS_EXTRA_SIZE)); + retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG, MS_EXTRA_SIZE, + SYSTEM_PARAM, (6 + MS_EXTRA_SIZE)); ms_set_err_code(chip, MS_NO_ERROR); @@ -1822,8 +1822,8 @@ static int ms_copy_page(struct rtsx_chip *chip, u16 old_blk, u16 new_blk, } if (i == 0) { - retval = ms_set_rw_reg_addr(chip, OverwriteFlag, - MS_EXTRA_SIZE, SystemParm, + retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG, + MS_EXTRA_SIZE, SYSTEM_PARAM, 7); if (retval != STATUS_SUCCESS) return STATUS_FAIL; @@ -1980,8 +1980,8 @@ RE_SEARCH: for (reg_addr = BLOCK_SIZE_0; reg_addr <= PAGE_SIZE_1; reg_addr++) rtsx_add_cmd(chip, READ_REG_CMD, reg_addr, 0, 0); - rtsx_add_cmd(chip, READ_REG_CMD, MS_Device_Type, 0, 0); - rtsx_add_cmd(chip, READ_REG_CMD, MS_4bit_Support, 0, 0); + rtsx_add_cmd(chip, READ_REG_CMD, MS_device_type, 0, 0); + rtsx_add_cmd(chip, READ_REG_CMD, MS_4bit_support, 0, 0); retval = rtsx_send_cmd(chip, MS_CARD, 100); if (retval < 0) @@ -2057,7 +2057,7 @@ RE_SEARCH: /* Switch I/F Mode */ if (ptr[15]) { - retval = ms_set_rw_reg_addr(chip, 0, 0, SystemParm, 1); + retval = ms_set_rw_reg_addr(chip, 0, 0, SYSTEM_PARAM, 1); if (retval != STATUS_SUCCESS) return STATUS_FAIL; @@ -2887,7 +2887,7 @@ int mspro_format(struct scsi_cmnd *srb, struct rtsx_chip *chip, if (retval != STATUS_SUCCESS) return STATUS_FAIL; - retval = ms_set_rw_reg_addr(chip, 0x00, 0x00, Pro_TPCParm, 0x01); + retval = ms_set_rw_reg_addr(chip, 0x00, 0x00, PRO_TPC_PARM, 0x01); if (retval != STATUS_SUCCESS) return STATUS_FAIL; @@ -2970,8 +2970,8 @@ static int ms_read_multiple_pages(struct rtsx_chip *chip, u16 phy_blk, } } - retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, - SystemParm, 6); + retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG, MS_EXTRA_SIZE, + SYSTEM_PARAM, 6); if (retval != STATUS_SUCCESS) return STATUS_FAIL; @@ -3026,7 +3026,7 @@ static int ms_read_multiple_pages(struct rtsx_chip *chip, u16 phy_blk, if (!(chip->card_wp & MS_CARD)) { reset_ms(chip); ms_set_page_status - (log_blk, setPS_NG, + (log_blk, set_PS_NG, extra, MS_EXTRA_SIZE); ms_write_extra_data @@ -3131,8 +3131,8 @@ static int ms_write_multiple_pages(struct rtsx_chip *chip, u16 old_blk, u8 *ptr; if (!start_page) { - retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, - SystemParm, 7); + retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG, MS_EXTRA_SIZE, + SYSTEM_PARAM, 7); if (retval != STATUS_SUCCESS) return STATUS_FAIL; @@ -3165,8 +3165,8 @@ static int ms_write_multiple_pages(struct rtsx_chip *chip, u16 old_blk, return STATUS_FAIL; } - retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, - SystemParm, (6 + MS_EXTRA_SIZE)); + retval = ms_set_rw_reg_addr(chip, OVERWRITE_FLAG, MS_EXTRA_SIZE, + SYSTEM_PARAM, (6 + MS_EXTRA_SIZE)); if (retval != STATUS_SUCCESS) return STATUS_FAIL; @@ -3773,9 +3773,9 @@ static int mg_set_tpc_para_sub(struct rtsx_chip *chip, int type, u8 buf[6]; if (type == 0) - retval = ms_set_rw_reg_addr(chip, 0, 0, Pro_TPCParm, 1); + retval = ms_set_rw_reg_addr(chip, 0, 0, PRO_TPC_PARM, 1); else - retval = ms_set_rw_reg_addr(chip, 0, 0, Pro_DataCount1, 6); + retval = ms_set_rw_reg_addr(chip, 0, 0, PRO_DATA_COUNT1, 6); if (retval != STATUS_SUCCESS) return STATUS_FAIL; @@ -4154,7 +4154,7 @@ int mg_set_ICV(struct scsi_cmnd *srb, struct rtsx_chip *chip) } else { set_sense_type(chip, lun, SENSE_TYPE_MG_WRITE_ERR); } - goto SetICVFinish; + goto set_ICV_finish; } #ifdef MG_SET_ICV_SLOW @@ -4195,7 +4195,7 @@ int mg_set_ICV(struct scsi_cmnd *srb, struct rtsx_chip *chip) SENSE_TYPE_MG_WRITE_ERR); } retval = STATUS_FAIL; - goto SetICVFinish; + goto set_ICV_finish; } } #else @@ -4214,11 +4214,11 @@ int mg_set_ICV(struct scsi_cmnd *srb, struct rtsx_chip *chip) } else { set_sense_type(chip, lun, SENSE_TYPE_MG_WRITE_ERR); } - goto SetICVFinish; + goto set_ICV_finish; } #endif -SetICVFinish: +set_ICV_finish: kfree(buf); return retval; } diff --git a/drivers/staging/rts5208/ms.h b/drivers/staging/rts5208/ms.h index 952cc14dd079..33bda9ce36b6 100644 --- a/drivers/staging/rts5208/ms.h +++ b/drivers/staging/rts5208/ms.h @@ -92,37 +92,37 @@ #define PRO_FORMAT 0x10 #define PRO_SLEEP 0x11 -#define IntReg 0x01 -#define StatusReg0 0x02 -#define StatusReg1 0x03 - -#define SystemParm 0x10 -#define BlockAdrs 0x11 -#define CMDParm 0x14 -#define PageAdrs 0x15 - -#define OverwriteFlag 0x16 -#define ManagemenFlag 0x17 -#define LogicalAdrs 0x18 -#define ReserveArea 0x1A - -#define Pro_IntReg 0x01 -#define Pro_StatusReg 0x02 -#define Pro_TypeReg 0x04 -#define Pro_IFModeReg 0x05 -#define Pro_CatagoryReg 0x06 -#define Pro_ClassReg 0x07 - -#define Pro_SystemParm 0x10 -#define Pro_DataCount1 0x11 -#define Pro_DataCount0 0x12 -#define Pro_DataAddr3 0x13 -#define Pro_DataAddr2 0x14 -#define Pro_DataAddr1 0x15 -#define Pro_DataAddr0 0x16 - -#define Pro_TPCParm 0x17 -#define Pro_CMDParm 0x18 +#define INT_REG 0x01 +#define STATUS_REG0 0x02 +#define STATUS_REG1 0x03 + +#define SYSTEM_PARAM 0x10 +#define BLOCK_ADRS 0x11 +#define CMD_PARM 0x14 +#define PAGE_ADRS 0x15 + +#define OVERWRITE_FLAG 0x16 +#define MANAGEMEN_FLAG 0x17 +#define LOGICAL_ADRS 0x18 +#define RESERVE_AREA 0x1A + +#define PRO_INT_REG 0x01 +#define PRO_STATUS_REG 0x02 +#define PRO_TYPE_REG 0x04 +#define PRO_IF_mode_REG 0x05 +#define PRO_CATEGORY_REG 0x06 +#define PRO_CLASS_REG 0x07 + +#define PRO_SYSTEM_PARAM 0x10 +#define PRO_DATA_COUNT1 0x11 +#define PRO_DATA_COUNT0 0x12 +#define PRO_DATA_ADDR3 0x13 +#define PRO_DATA_ADDR2 0x14 +#define PRO_DATA_ADDR1 0x15 +#define PRO_DATA_ADDR0 0x16 + +#define PRO_TPC_PARM 0x17 +#define PRO_CMD_PARM 0x18 #define INT_REG_CED 0x80 #define INT_REG_ERR 0x40 @@ -152,12 +152,12 @@ #define PAGE_SIZE_0 (PPBUF_BASE2 + 0x1a0 + 8) #define PAGE_SIZE_1 (PPBUF_BASE2 + 0x1a0 + 9) -#define MS_Device_Type (PPBUF_BASE2 + 0x1D8) +#define MS_device_type (PPBUF_BASE2 + 0x1D8) -#define MS_4bit_Support (PPBUF_BASE2 + 0x1D3) +#define MS_4bit_support (PPBUF_BASE2 + 0x1D3) -#define setPS_NG 1 -#define setPS_Error 0 +#define set_PS_NG 1 +#define set_PS_error 0 #define PARALLEL_8BIT_IF 0x40 #define PARALLEL_4BIT_IF 0x00 diff --git a/drivers/staging/rts5208/rtsx.c b/drivers/staging/rts5208/rtsx.c index fa597953e9a0..cb95ad6fa4f9 100644 --- a/drivers/staging/rts5208/rtsx.c +++ b/drivers/staging/rts5208/rtsx.c @@ -873,7 +873,8 @@ static int rtsx_probe(struct pci_dev *pci, (unsigned long)(dev->addr), (unsigned long)(dev->remap_addr)); dev->rtsx_resv_buf = dmam_alloc_coherent(&pci->dev, RTSX_RESV_BUF_LEN, - &dev->rtsx_resv_buf_addr, GFP_KERNEL); + &dev->rtsx_resv_buf_addr, + GFP_KERNEL); if (!dev->rtsx_resv_buf) { dev_err(&pci->dev, "alloc dma buffer fail\n"); err = -ENXIO; diff --git a/drivers/staging/rts5208/rtsx_transport.c b/drivers/staging/rts5208/rtsx_transport.c index 561851cc8780..5f1eefe80f1e 100644 --- a/drivers/staging/rts5208/rtsx_transport.c +++ b/drivers/staging/rts5208/rtsx_transport.c @@ -677,8 +677,8 @@ static int rtsx_transfer_buf(struct rtsx_chip *chip, u8 card, void *buf, spin_unlock_irq(&rtsx->reg_lock); /* Wait for TRANS_OK_INT */ - timeleft = wait_for_completion_interruptible_timeout( - &trans_done, msecs_to_jiffies(timeout)); + timeleft = wait_for_completion_interruptible_timeout(&trans_done, + msecs_to_jiffies(timeout)); if (timeleft <= 0) { dev_dbg(rtsx_dev(chip), "Timeout (%s %d)\n", __func__, __LINE__); diff --git a/drivers/staging/rts5208/sd.h b/drivers/staging/rts5208/sd.h index dc9e8cad7a74..f4ff62653b56 100644 --- a/drivers/staging/rts5208/sd.h +++ b/drivers/staging/rts5208/sd.h @@ -232,7 +232,7 @@ #define DCM_LOW_FREQUENCY_MODE 0x01 #define DCM_HIGH_FREQUENCY_MODE_SET 0x0C -#define DCM_Low_FREQUENCY_MODE_SET 0x00 +#define DCM_LOW_FREQUENCY_MODE_SET 0x00 #define MULTIPLY_BY_1 0x00 #define MULTIPLY_BY_2 0x01 diff --git a/drivers/staging/rts5208/xd.c b/drivers/staging/rts5208/xd.c index f3dc96a4c59d..0f369935fb6c 100644 --- a/drivers/staging/rts5208/xd.c +++ b/drivers/staging/rts5208/xd.c @@ -630,13 +630,13 @@ static int reset_xd(struct rtsx_chip *chip) xd_card->zone_cnt = 32; xd_card->capacity = 1024000; break; - case xD_1G_X8_512: + case XD_1G_X8_512: XD_PAGE_512(xd_card); xd_card->addr_cycle = 4; xd_card->zone_cnt = 64; xd_card->capacity = 2048000; break; - case xD_2G_X8_512: + case XD_2G_X8_512: XD_PAGE_512(xd_card); xd_card->addr_cycle = 4; xd_card->zone_cnt = 128; @@ -669,10 +669,10 @@ static int reset_xd(struct rtsx_chip *chip) return STATUS_FAIL; } - retval = xd_read_id(chip, READ_xD_ID, id_buf, 4); + retval = xd_read_id(chip, READ_XD_ID, id_buf, 4); if (retval != STATUS_SUCCESS) return STATUS_FAIL; - dev_dbg(rtsx_dev(chip), "READ_xD_ID: 0x%x 0x%x 0x%x 0x%x\n", + dev_dbg(rtsx_dev(chip), "READ_XD_ID: 0x%x 0x%x 0x%x 0x%x\n", id_buf[0], id_buf[1], id_buf[2], id_buf[3]); if (id_buf[2] != XD_ID_CODE) return STATUS_FAIL; diff --git a/drivers/staging/rts5208/xd.h b/drivers/staging/rts5208/xd.h index 57b94129b26f..98c00f268e56 100644 --- a/drivers/staging/rts5208/xd.h +++ b/drivers/staging/rts5208/xd.h @@ -36,7 +36,7 @@ #define BLK_ERASE_1 0x60 #define BLK_ERASE_2 0xD0 #define READ_STS 0x70 -#define READ_xD_ID 0x9A +#define READ_XD_ID 0x9A #define COPY_BACK_512 0x8A #define COPY_BACK_2K 0x85 #define READ1_1_2 0x30 @@ -72,8 +72,8 @@ #define XD_128M_X16_2048 0xC1 #define XD_4M_X8_512_1 0xE3 #define XD_4M_X8_512_2 0xE5 -#define xD_1G_X8_512 0xD3 -#define xD_2G_X8_512 0xD5 +#define XD_1G_X8_512 0xD3 +#define XD_2G_X8_512 0xD5 #define XD_ID_CODE 0xB5 diff --git a/drivers/staging/sm750fb/ddk750_chip.c b/drivers/staging/sm750fb/ddk750_chip.c index 5a317cc98a4b..02860d3ec365 100644 --- a/drivers/staging/sm750fb/ddk750_chip.c +++ b/drivers/staging/sm750fb/ddk750_chip.c @@ -56,7 +56,6 @@ static unsigned int get_mxclk_freq(void) static void set_chip_clock(unsigned int frequency) { struct pll_value pll; - unsigned int actual_mx_clk; /* Cheok_0509: For SM750LE, the chip clock is fixed. Nothing to set. */ if (sm750_get_chip_type() == SM750LE) @@ -66,8 +65,8 @@ static void set_chip_clock(unsigned int frequency) /* * Set up PLL structure to hold the value to be set in clocks. */ - pll.inputFreq = DEFAULT_INPUT_CLOCK; /* Defined in CLOCK.H */ - pll.clockType = MXCLK_PLL; + pll.input_freq = DEFAULT_INPUT_CLOCK; /* Defined in CLOCK.H */ + pll.clock_type = MXCLK_PLL; /* * Call sm750_calc_pll_value() to fill the other fields @@ -76,7 +75,7 @@ static void set_chip_clock(unsigned int frequency) * Return value of sm750_calc_pll_value gives the actual * possible clock. */ - actual_mx_clk = sm750_calc_pll_value(frequency, &pll); + sm750_calc_pll_value(frequency, &pll); /* Master Clock Control: MXCLK_PLL */ poke32(MXCLK_PLL_CTRL, sm750_format_pll_reg(&pll)); @@ -211,13 +210,13 @@ unsigned int ddk750_get_vm_size(void) return data; } -int ddk750_init_hw(struct initchip_param *pInitParam) +int ddk750_init_hw(struct initchip_param *p_init_param) { unsigned int reg; - if (pInitParam->powerMode != 0) - pInitParam->powerMode = 0; - sm750_set_power_mode(pInitParam->powerMode); + if (p_init_param->power_mode != 0) + p_init_param->power_mode = 0; + sm750_set_power_mode(p_init_param->power_mode); /* Enable display power gate & LOCALMEM power gate*/ reg = peek32(CURRENT_GATE); @@ -238,13 +237,13 @@ int ddk750_init_hw(struct initchip_param *pInitParam) } /* Set the Main Chip Clock */ - set_chip_clock(MHz((unsigned int)pInitParam->chipClock)); + set_chip_clock(MHz((unsigned int)p_init_param->chip_clock)); /* Set up memory clock. */ - set_memory_clock(MHz(pInitParam->memClock)); + set_memory_clock(MHz(p_init_param->mem_clock)); /* Set up master clock */ - set_master_clock(MHz(pInitParam->masterClock)); + set_master_clock(MHz(p_init_param->master_clock)); /* * Reset the memory controller. @@ -252,7 +251,7 @@ int ddk750_init_hw(struct initchip_param *pInitParam) * the system might hang when sw accesses the memory. * The memory should be resetted after changing the MXCLK. */ - if (pInitParam->resetMemory == 1) { + if (p_init_param->reset_memory == 1) { reg = peek32(MISC_CTRL); reg &= ~MISC_CTRL_LOCALMEM_RESET; poke32(MISC_CTRL, reg); @@ -261,7 +260,7 @@ int ddk750_init_hw(struct initchip_param *pInitParam) poke32(MISC_CTRL, reg); } - if (pInitParam->setAllEngOff == 1) { + if (p_init_param->set_all_eng_off == 1) { sm750_enable_2d_engine(0); /* Disable Overlay, if a former application left it on */ @@ -337,13 +336,13 @@ unsigned int sm750_calc_pll_value(unsigned int request_orig, ret = 0; mini_diff = ~0; request = request_orig / 1000; - input = pll->inputFreq / 1000; + input = pll->input_freq / 1000; /* * for MXCLK register, * no POD provided, so need be treated differently */ - if (pll->clockType == MXCLK_PLL) + if (pll->clock_type == MXCLK_PLL) max_d = 3; for (N = 15; N > 1; N--) { @@ -365,7 +364,7 @@ unsigned int sm750_calc_pll_value(unsigned int request_orig, if (M < 256 && M > 0) { unsigned int diff; - tmp_clock = pll->inputFreq * M / N / X; + tmp_clock = pll->input_freq * M / N / X; diff = abs(tmp_clock - request_orig); if (diff < mini_diff) { pll->M = M; @@ -383,14 +382,14 @@ unsigned int sm750_calc_pll_value(unsigned int request_orig, return ret; } -unsigned int sm750_format_pll_reg(struct pll_value *pPLL) +unsigned int sm750_format_pll_reg(struct pll_value *p_PLL) { #ifndef VALIDATION_CHIP - unsigned int POD = pPLL->POD; + unsigned int POD = p_PLL->POD; #endif - unsigned int OD = pPLL->OD; - unsigned int M = pPLL->M; - unsigned int N = pPLL->N; + unsigned int OD = p_PLL->OD; + unsigned int M = p_PLL->M; + unsigned int N = p_PLL->N; /* * Note that all PLL's have the same format. Here, we just use diff --git a/drivers/staging/sm750fb/ddk750_chip.h b/drivers/staging/sm750fb/ddk750_chip.h index 3e92b3297160..ee2e9d90f7dd 100644 --- a/drivers/staging/sm750fb/ddk750_chip.h +++ b/drivers/staging/sm750fb/ddk750_chip.h @@ -40,8 +40,8 @@ enum clock_type { }; struct pll_value { - enum clock_type clockType; - unsigned long inputFreq; /* Input clock frequency to the PLL */ + enum clock_type clock_type; + unsigned long input_freq; /* Input clock frequency to the PLL */ /* Use this when clockType = PANEL_PLL */ unsigned long M; @@ -53,41 +53,41 @@ struct pll_value { /* input struct to initChipParam() function */ struct initchip_param { /* Use power mode 0 or 1 */ - unsigned short powerMode; + unsigned short power_mode; /* * Speed of main chip clock in MHz unit * 0 = keep the current clock setting * Others = the new main chip clock */ - unsigned short chipClock; + unsigned short chip_clock; /* * Speed of memory clock in MHz unit * 0 = keep the current clock setting * Others = the new memory clock */ - unsigned short memClock; + unsigned short mem_clock; /* * Speed of master clock in MHz unit * 0 = keep the current clock setting * Others = the new master clock */ - unsigned short masterClock; + unsigned short master_clock; /* * 0 = leave all engine state untouched. * 1 = make sure they are off: 2D, Overlay, * video alpha, alpha, hardware cursors */ - unsigned short setAllEngOff; + unsigned short set_all_eng_off; /* * 0 = Do not reset the memory controller * 1 = Reset the memory controller */ - unsigned char resetMemory; + unsigned char reset_memory; /* More initialization parameter can be added if needed */ }; @@ -95,7 +95,7 @@ struct initchip_param { enum logical_chip_type sm750_get_chip_type(void); void sm750_set_chip_type(unsigned short dev_id, u8 rev_id); unsigned int sm750_calc_pll_value(unsigned int request, struct pll_value *pll); -unsigned int sm750_format_pll_reg(struct pll_value *pPLL); +unsigned int sm750_format_pll_reg(struct pll_value *p_PLL); unsigned int ddk750_get_vm_size(void); int ddk750_init_hw(struct initchip_param *pinit_param); diff --git a/drivers/staging/sm750fb/ddk750_display.c b/drivers/staging/sm750fb/ddk750_display.c index 887ea8aef43f..172624ff98b0 100644 --- a/drivers/staging/sm750fb/ddk750_display.c +++ b/drivers/staging/sm750fb/ddk750_display.c @@ -147,8 +147,8 @@ void ddk750_set_logical_disp_out(enum disp_output output) if (output & PNL_SEQ_USAGE) { /* set panel sequence */ - sw_panel_power_sequence((output & PNL_SEQ_MASK) >> PNL_SEQ_OFFSET, - 4); + sw_panel_power_sequence((output & PNL_SEQ_MASK) >> + PNL_SEQ_OFFSET, 4); } if (output & DAC_USAGE) diff --git a/drivers/staging/sm750fb/ddk750_mode.c b/drivers/staging/sm750fb/ddk750_mode.c index 4dac691ad1b1..e00a6cb31947 100644 --- a/drivers/staging/sm750fb/ddk750_mode.c +++ b/drivers/staging/sm750fb/ddk750_mode.c @@ -13,8 +13,9 @@ * HW only supports 7 predefined pixel clocks, and clock select is * in bit 29:27 of Display Control register. */ -static unsigned long displayControlAdjust_SM750LE(struct mode_parameter *pModeParam, - unsigned long dispControl) +static unsigned long +displayControlAdjust_SM750LE(struct mode_parameter *pModeParam, + unsigned long dispControl) { unsigned long x, y; @@ -81,7 +82,7 @@ static int programModeRegisters(struct mode_parameter *pModeParam, int cnt = 0; unsigned int tmp, reg; - if (pll->clockType == SECONDARY_PLL) { + if (pll->clock_type == SECONDARY_PLL) { /* programe secondary pixel clock */ poke32(CRT_PLL_CTRL, sm750_format_pll_reg(pll)); @@ -134,7 +135,7 @@ static int programModeRegisters(struct mode_parameter *pModeParam, poke32(CRT_DISPLAY_CTRL, tmp | reg); } - } else if (pll->clockType == PRIMARY_PLL) { + } else if (pll->clock_type == PRIMARY_PLL) { unsigned int reserved; poke32(PANEL_PLL_CTRL, sm750_format_pll_reg(pll)); @@ -209,12 +210,11 @@ static int programModeRegisters(struct mode_parameter *pModeParam, int ddk750_setModeTiming(struct mode_parameter *parm, enum clock_type clock) { struct pll_value pll; - unsigned int uiActualPixelClk; - pll.inputFreq = DEFAULT_INPUT_CLOCK; - pll.clockType = clock; + pll.input_freq = DEFAULT_INPUT_CLOCK; + pll.clock_type = clock; - uiActualPixelClk = sm750_calc_pll_value(parm->pixel_clock, &pll); + sm750_calc_pll_value(parm->pixel_clock, &pll); if (sm750_get_chip_type() == SM750LE) { /* set graphic mode via IO method */ outb_p(0x88, 0x3d4); diff --git a/drivers/staging/sm750fb/ddk750_sii164.c b/drivers/staging/sm750fb/ddk750_sii164.c index c8e856c13912..73e0e9f41ec5 100644 --- a/drivers/staging/sm750fb/ddk750_sii164.c +++ b/drivers/staging/sm750fb/ddk750_sii164.c @@ -39,8 +39,10 @@ unsigned short sii164GetVendorID(void) { unsigned short vendorID; - vendorID = ((unsigned short)i2cReadReg(SII164_I2C_ADDRESS, SII164_VENDOR_ID_HIGH) << 8) | - (unsigned short)i2cReadReg(SII164_I2C_ADDRESS, SII164_VENDOR_ID_LOW); + vendorID = ((unsigned short)i2cReadReg(SII164_I2C_ADDRESS, + SII164_VENDOR_ID_HIGH) << 8) | + (unsigned short)i2cReadReg(SII164_I2C_ADDRESS, + SII164_VENDOR_ID_LOW); return vendorID; } @@ -56,13 +58,18 @@ unsigned short sii164GetDeviceID(void) { unsigned short deviceID; - deviceID = ((unsigned short)i2cReadReg(SII164_I2C_ADDRESS, SII164_DEVICE_ID_HIGH) << 8) | - (unsigned short)i2cReadReg(SII164_I2C_ADDRESS, SII164_DEVICE_ID_LOW); + deviceID = ((unsigned short)i2cReadReg(SII164_I2C_ADDRESS, + SII164_DEVICE_ID_HIGH) << 8) | + (unsigned short)i2cReadReg(SII164_I2C_ADDRESS, + SII164_DEVICE_ID_LOW); return deviceID; } -/* DVI.C will handle all SiI164 chip stuffs and try it best to make code minimal and useful */ +/* + * DVI.C will handle all SiI164 chip stuffs and try its best to make code + * minimal and useful + */ /* * sii164InitChip @@ -133,7 +140,8 @@ long sii164InitChip(unsigned char edge_select, #endif /* Check if SII164 Chip exists */ - if ((sii164GetVendorID() == SII164_VENDOR_ID) && (sii164GetDeviceID() == SII164_DEVICE_ID)) { + if ((sii164GetVendorID() == SII164_VENDOR_ID) && + (sii164GetDeviceID() == SII164_DEVICE_ID)) { /* * Initialize SII164 controller chip. */ @@ -254,7 +262,9 @@ void sii164ResetChip(void) /* * sii164GetChipString - * This function returns a char string name of the current DVI Controller chip. + * This function returns a char string name of the current DVI Controller + * chip. + * * It's convenient for application need to display the chip name. */ char *sii164GetChipString(void) @@ -330,8 +340,8 @@ void sii164EnableHotPlugDetection(unsigned char enableHotPlug) detectReg = i2cReadReg(SII164_I2C_ADDRESS, SII164_DETECT); - /* Depending on each DVI controller, need to enable the hot plug based on each - * individual chip design. + /* Depending on each DVI controller, need to enable the hot plug based + * on each individual chip design. */ if (enableHotPlug != 0) sii164SelectHotPlugDetectionMode(SII164_HOTPLUG_USE_MDI); diff --git a/drivers/staging/sm750fb/ddk750_sii164.h b/drivers/staging/sm750fb/ddk750_sii164.h index 862e7bf27353..d940cb729066 100644 --- a/drivers/staging/sm750fb/ddk750_sii164.h +++ b/drivers/staging/sm750fb/ddk750_sii164.h @@ -6,10 +6,13 @@ /* Hot Plug detection mode structure */ enum sii164_hot_plug_mode { - SII164_HOTPLUG_DISABLE = 0, /* Disable Hot Plug output bit (always high). */ - SII164_HOTPLUG_USE_MDI, /* Use Monitor Detect Interrupt bit. */ - SII164_HOTPLUG_USE_RSEN, /* Use Receiver Sense detect bit. */ - SII164_HOTPLUG_USE_HTPLG /* Use Hot Plug detect bit. */ + SII164_HOTPLUG_DISABLE = 0, /* Disable Hot Plug output bit + * (always high). + */ + + SII164_HOTPLUG_USE_MDI, /* Use Monitor Detect Interrupt bit. */ + SII164_HOTPLUG_USE_RSEN, /* Use Receiver Sense detect bit. */ + SII164_HOTPLUG_USE_HTPLG /* Use Hot Plug detect bit. */ }; /* Silicon Image SiI164 chip prototype */ diff --git a/drivers/staging/sm750fb/sm750_accel.c b/drivers/staging/sm750fb/sm750_accel.c index dbcbbd1055da..8faa601c700b 100644 --- a/drivers/staging/sm750fb/sm750_accel.c +++ b/drivers/staging/sm750fb/sm750_accel.c @@ -130,20 +130,28 @@ int sm750_hw_fillrect(struct lynx_accel *accel, return 0; } -int sm750_hw_copyarea( -struct lynx_accel *accel, -unsigned int sBase, /* Address of source: offset in frame buffer */ -unsigned int sPitch, /* Pitch value of source surface in BYTE */ -unsigned int sx, -unsigned int sy, /* Starting coordinate of source surface */ -unsigned int dBase, /* Address of destination: offset in frame buffer */ -unsigned int dPitch, /* Pitch value of destination surface in BYTE */ -unsigned int Bpp, /* Color depth of destination surface */ -unsigned int dx, -unsigned int dy, /* Starting coordinate of destination surface */ -unsigned int width, -unsigned int height, /* width and height of rectangle in pixel value */ -unsigned int rop2) /* ROP value */ +/** + * sm750_hm_copyarea + * @sBase: Address of source: offset in frame buffer + * @sPitch: Pitch value of source surface in BYTE + * @sx: Starting x coordinate of source surface + * @sy: Starting y coordinate of source surface + * @dBase: Address of destination: offset in frame buffer + * @dPitch: Pitch value of destination surface in BYTE + * @Bpp: Color depth of destination surface + * @dx: Starting x coordinate of destination surface + * @dy: Starting y coordinate of destination surface + * @width: width of rectangle in pixel value + * @height: height of rectangle in pixel value + * @rop2: ROP value + */ +int sm750_hw_copyarea(struct lynx_accel *accel, + unsigned int sBase, unsigned int sPitch, + unsigned int sx, unsigned int sy, + unsigned int dBase, unsigned int dPitch, + unsigned int Bpp, unsigned int dx, unsigned int dy, + unsigned int width, unsigned int height, + unsigned int rop2) { unsigned int nDirection, de_ctrl; @@ -216,7 +224,7 @@ unsigned int rop2) /* ROP value */ /* * Note: - * DE_FOREGROUND are DE_BACKGROUND are don't care. + * DE_FOREGROUND and DE_BACKGROUND are don't care. * DE_COLOR_COMPARE and DE_COLOR_COMPARE_MAKS * are set by set deSetTransparency(). */ @@ -235,21 +243,21 @@ unsigned int rop2) /* ROP value */ */ write_dpr(accel, DE_WINDOW_DESTINATION_BASE, dBase); /* dpr44 */ - /* - * Program pitch (distance between the 1st points of two adjacent lines). - * Note that input pitch is BYTE value, but the 2D Pitch register uses - * pixel values. Need Byte to pixel conversion. - */ + /* + * Program pitch (distance between the 1st points of two adjacent lines). + * Note that input pitch is BYTE value, but the 2D Pitch register uses + * pixel values. Need Byte to pixel conversion. + */ write_dpr(accel, DE_PITCH, ((dPitch / Bpp << DE_PITCH_DESTINATION_SHIFT) & DE_PITCH_DESTINATION_MASK) | (sPitch / Bpp & DE_PITCH_SOURCE_MASK)); /* dpr10 */ - /* - * Screen Window width in Pixels. - * 2D engine uses this value to calculate the linear address in frame buffer - * for a given point. - */ + /* + * Screen Window width in Pixels. + * 2D engine uses this value to calculate the linear address in frame buffer + * for a given point. + */ write_dpr(accel, DE_WINDOW_WIDTH, ((dPitch / Bpp << DE_WINDOW_WIDTH_DST_SHIFT) & DE_WINDOW_WIDTH_DST_MASK) | @@ -288,20 +296,28 @@ static unsigned int deGetTransparency(struct lynx_accel *accel) return de_ctrl; } -int sm750_hw_imageblit(struct lynx_accel *accel, - const char *pSrcbuf, /* pointer to start of source buffer in system memory */ - u32 srcDelta, /* Pitch value (in bytes) of the source buffer, +ive means top down and -ive mean button up */ - u32 startBit, /* Mono data can start at any bit in a byte, this value should be 0 to 7 */ - u32 dBase, /* Address of destination: offset in frame buffer */ - u32 dPitch, /* Pitch value of destination surface in BYTE */ - u32 bytePerPixel, /* Color depth of destination surface */ - u32 dx, - u32 dy, /* Starting coordinate of destination surface */ - u32 width, - u32 height, /* width and height of rectangle in pixel value */ - u32 fColor, /* Foreground color (corresponding to a 1 in the monochrome data */ - u32 bColor, /* Background color (corresponding to a 0 in the monochrome data */ - u32 rop2) /* ROP value */ +/** + * sm750_hw_imageblit + * @pSrcbuf: pointer to start of source buffer in system memory + * @srcDelta: Pitch value (in bytes) of the source buffer, +ive means top down + * and -ive mean button up + * @startBit: Mono data can start at any bit in a byte, this value should be + * 0 to 7 + * @dBase: Address of destination: offset in frame buffer + * @dPitch: Pitch value of destination surface in BYTE + * @bytePerPixel: Color depth of destination surface + * @dx: Starting x coordinate of destination surface + * @dy: Starting y coordinate of destination surface + * @width: width of rectangle in pixel value + * @height: height of rectangle in pixel value + * @fColor: Foreground color (corresponding to a 1 in the monochrome data + * @bColor: Background color (corresponding to a 0 in the monochrome data + * @rop2: ROP value + */ +int sm750_hw_imageblit(struct lynx_accel *accel, const char *pSrcbuf, + u32 srcDelta, u32 startBit, u32 dBase, u32 dPitch, + u32 bytePerPixel, u32 dx, u32 dy, u32 width, + u32 height, u32 fColor, u32 bColor, u32 rop2) { unsigned int ulBytesPerScan; unsigned int ul4BytesPerScan; diff --git a/drivers/staging/sm750fb/sm750_accel.h b/drivers/staging/sm750fb/sm750_accel.h index c4f42002a50f..2c79cb730a0a 100644 --- a/drivers/staging/sm750fb/sm750_accel.h +++ b/drivers/staging/sm750fb/sm750_accel.h @@ -190,37 +190,54 @@ void sm750_hw_set2dformat(struct lynx_accel *accel, int fmt); void sm750_hw_de_init(struct lynx_accel *accel); int sm750_hw_fillrect(struct lynx_accel *accel, - u32 base, u32 pitch, u32 Bpp, - u32 x, u32 y, u32 width, u32 height, - u32 color, u32 rop); - -int sm750_hw_copyarea( -struct lynx_accel *accel, -unsigned int sBase, /* Address of source: offset in frame buffer */ -unsigned int sPitch, /* Pitch value of source surface in BYTE */ -unsigned int sx, -unsigned int sy, /* Starting coordinate of source surface */ -unsigned int dBase, /* Address of destination: offset in frame buffer */ -unsigned int dPitch, /* Pitch value of destination surface in BYTE */ -unsigned int bpp, /* Color depth of destination surface */ -unsigned int dx, -unsigned int dy, /* Starting coordinate of destination surface */ -unsigned int width, -unsigned int height, /* width and height of rectangle in pixel value */ -unsigned int rop2); - -int sm750_hw_imageblit(struct lynx_accel *accel, - const char *pSrcbuf, /* pointer to start of source buffer in system memory */ - u32 srcDelta, /* Pitch value (in bytes) of the source buffer, +ive means top down and -ive mean button up */ - u32 startBit, /* Mono data can start at any bit in a byte, this value should be 0 to 7 */ - u32 dBase, /* Address of destination: offset in frame buffer */ - u32 dPitch, /* Pitch value of destination surface in BYTE */ - u32 bytePerPixel, /* Color depth of destination surface */ - u32 dx, - u32 dy, /* Starting coordinate of destination surface */ - u32 width, - u32 height, /* width and height of rectangle in pixel value */ - u32 fColor, /* Foreground color (corresponding to a 1 in the monochrome data */ - u32 bColor, /* Background color (corresponding to a 0 in the monochrome data */ - u32 rop2); + u32 base, u32 pitch, u32 Bpp, + u32 x, u32 y, u32 width, u32 height, + u32 color, u32 rop); + +/** + * sm750_hm_copyarea + * @sBase: Address of source: offset in frame buffer + * @sPitch: Pitch value of source surface in BYTE + * @sx: Starting x coordinate of source surface + * @sy: Starting y coordinate of source surface + * @dBase: Address of destination: offset in frame buffer + * @dPitch: Pitch value of destination surface in BYTE + * @Bpp: Color depth of destination surface + * @dx: Starting x coordinate of destination surface + * @dy: Starting y coordinate of destination surface + * @width: width of rectangle in pixel value + * @height: height of rectangle in pixel value + * @rop2: ROP value + */ +int sm750_hw_copyarea(struct lynx_accel *accel, + unsigned int sBase, unsigned int sPitch, + unsigned int sx, unsigned int sy, + unsigned int dBase, unsigned int dPitch, + unsigned int Bpp, unsigned int dx, unsigned int dy, + unsigned int width, unsigned int height, + unsigned int rop2); + +/** + * sm750_hw_imageblit + * @pSrcbuf: pointer to start of source buffer in system memory + * @srcDelta: Pitch value (in bytes) of the source buffer, +ive means top down + *>----- and -ive mean button up + * @startBit: Mono data can start at any bit in a byte, this value should be + *>----- 0 to 7 + * @dBase: Address of destination: offset in frame buffer + * @dPitch: Pitch value of destination surface in BYTE + * @bytePerPixel: Color depth of destination surface + * @dx: Starting x coordinate of destination surface + * @dy: Starting y coordinate of destination surface + * @width: width of rectangle in pixel value + * @height: height of rectangle in pixel value + * @fColor: Foreground color (corresponding to a 1 in the monochrome data + * @bColor: Background color (corresponding to a 0 in the monochrome data + * @rop2: ROP value + */ +int sm750_hw_imageblit(struct lynx_accel *accel, const char *pSrcbuf, + u32 srcDelta, u32 startBit, u32 dBase, u32 dPitch, + u32 bytePerPixel, u32 dx, u32 dy, u32 width, + u32 height, u32 fColor, u32 bColor, u32 rop2); + #endif diff --git a/drivers/staging/sm750fb/sm750_cursor.h b/drivers/staging/sm750fb/sm750_cursor.h index 16ac07eb58d6..b59643dd61ed 100644 --- a/drivers/staging/sm750fb/sm750_cursor.h +++ b/drivers/staging/sm750fb/sm750_cursor.h @@ -5,14 +5,11 @@ /* hw_cursor_xxx works for voyager,718 and 750 */ void sm750_hw_cursor_enable(struct lynx_cursor *cursor); void sm750_hw_cursor_disable(struct lynx_cursor *cursor); -void sm750_hw_cursor_setSize(struct lynx_cursor *cursor, - int w, int h); -void sm750_hw_cursor_setPos(struct lynx_cursor *cursor, - int x, int y); -void sm750_hw_cursor_setColor(struct lynx_cursor *cursor, - u32 fg, u32 bg); -void sm750_hw_cursor_setData(struct lynx_cursor *cursor, - u16 rop, const u8 *data, const u8 *mask); -void sm750_hw_cursor_setData2(struct lynx_cursor *cursor, - u16 rop, const u8 *data, const u8 *mask); +void sm750_hw_cursor_setSize(struct lynx_cursor *cursor, int w, int h); +void sm750_hw_cursor_setPos(struct lynx_cursor *cursor, int x, int y); +void sm750_hw_cursor_setColor(struct lynx_cursor *cursor, u32 fg, u32 bg); +void sm750_hw_cursor_setData(struct lynx_cursor *cursor, u16 rop, + const u8 *data, const u8 *mask); +void sm750_hw_cursor_setData2(struct lynx_cursor *cursor, u16 rop, + const u8 *data, const u8 *mask); #endif diff --git a/drivers/staging/uwb/rsv.c b/drivers/staging/uwb/rsv.c index f45a04ff7275..d593a41c3d8d 100644 --- a/drivers/staging/uwb/rsv.c +++ b/drivers/staging/uwb/rsv.c @@ -614,7 +614,7 @@ int uwb_rsv_try_move(struct uwb_rsv *rsv, struct uwb_mas_bm *available) struct uwb_rsv_move *mv; int ret = 0; - if (bow->can_reserve_extra_mases == false) + if (!bow->can_reserve_extra_mases) return -EBUSY; mv = &rsv->mv; @@ -643,7 +643,7 @@ void uwb_rsv_handle_drp_avail_change(struct uwb_rc *rc) struct uwb_rsv *rsv; struct uwb_mas_bm mas; - if (bow->can_reserve_extra_mases == false) + if (!bow->can_reserve_extra_mases) return; list_for_each_entry(rsv, &rc->reservations, rc_node) { diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c index c6f9cf1913d2..73144f1ce45e 100644 --- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c +++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835-vchiq.c @@ -9,7 +9,7 @@ struct bcm2835_audio_instance { struct device *dev; - VCHI_SERVICE_HANDLE_T vchi_handle; + struct vchi_service_handle *vchi_handle; struct completion msg_avail_comp; struct mutex vchi_mutex; struct bcm2835_alsa_stream *alsa_stream; @@ -90,7 +90,7 @@ static int bcm2835_audio_send_simple(struct bcm2835_audio_instance *instance, } static void audio_vchi_callback(void *param, - const VCHI_CALLBACK_REASON_T reason, + const enum vchi_callback_reason reason, void *msg_handle) { struct bcm2835_audio_instance *instance = param; @@ -103,6 +103,9 @@ static void audio_vchi_callback(void *param, status = vchi_msg_dequeue(instance->vchi_handle, &m, sizeof(m), &msg_len, VCHI_FLAGS_NONE); + if (status) + return; + if (m.type == VC_AUDIO_MSG_TYPE_RESULT) { instance->result = m.result.success; complete(&instance->msg_avail_comp); @@ -119,7 +122,7 @@ static void audio_vchi_callback(void *param, } static int -vc_vchi_audio_init(VCHI_INSTANCE_T vchi_instance, +vc_vchi_audio_init(struct vchi_instance_handle *vchi_instance, struct bcm2835_audio_instance *instance) { struct service_creation params = { diff --git a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h index ed0feb34b6c8..d2fe8d36ab7d 100644 --- a/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h +++ b/drivers/staging/vc04_services/bcm2835-audio/bcm2835.h @@ -44,7 +44,7 @@ enum snd_bcm2835_ctrl { }; struct bcm2835_vchi_ctx { - VCHI_INSTANCE_T vchi_instance; + struct vchi_instance_handle *vchi_instance; }; /* definition of the chip-specific record */ diff --git a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c index d4d1e44b16b2..beb6a0063bb8 100644 --- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c +++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c @@ -1090,8 +1090,8 @@ static int mmal_setup_components(struct bm2835_mmal_dev *dev, ret = vchiq_mmal_port_set_format(dev->instance, camera_port); - if (!ret - && camera_port == + if (!ret && + camera_port == &dev->component[COMP_CAMERA]->output[CAM_PORT_VIDEO]) { bool overlay_enabled = !!dev->component[COMP_PREVIEW]->enabled; diff --git a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c index 1c180ead4a20..de03b90021a8 100644 --- a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c +++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c @@ -155,7 +155,7 @@ struct mmal_msg_context { }; struct vchiq_mmal_instance { - VCHI_SERVICE_HANDLE_T handle; + struct vchi_service_handle *handle; /* ensure serialised access to service */ struct mutex vchiq_mutex; @@ -535,7 +535,7 @@ static void bulk_abort_cb(struct vchiq_mmal_instance *instance, /* incoming event service callback */ static void service_callback(void *param, - const VCHI_CALLBACK_REASON_T reason, + const enum vchi_callback_reason reason, void *bulk_ctx) { struct vchiq_mmal_instance *instance = param; @@ -1814,7 +1814,7 @@ int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance) { int status; struct vchiq_mmal_instance *instance; - static VCHI_INSTANCE_T vchi_instance; + static struct vchi_instance_handle *vchi_instance; struct service_creation params = { .version = VCHI_VERSION_EX(VC_MMAL_VER, VC_MMAL_MIN_VER), .service_id = VC_MMAL_SERVER_NAME, diff --git a/drivers/staging/vc04_services/interface/vchi/vchi.h b/drivers/staging/vc04_services/interface/vchi/vchi.h index f85562b9ba9e..56b1037d8e25 100644 --- a/drivers/staging/vc04_services/interface/vchi/vchi.h +++ b/drivers/staging/vc04_services/interface/vchi/vchi.h @@ -8,17 +8,17 @@ #include "interface/vchi/vchi_common.h" /****************************************************************************** - Global defs + * Global defs *****************************************************************************/ -#define VCHI_BULK_ROUND_UP(x) ((((unsigned long)(x))+VCHI_BULK_ALIGN-1) & ~(VCHI_BULK_ALIGN-1)) -#define VCHI_BULK_ROUND_DOWN(x) (((unsigned long)(x)) & ~(VCHI_BULK_ALIGN-1)) -#define VCHI_BULK_ALIGN_NBYTES(x) (VCHI_BULK_ALIGNED(x) ? 0 : (VCHI_BULK_ALIGN - ((unsigned long)(x) & (VCHI_BULK_ALIGN-1)))) +#define VCHI_BULK_ROUND_UP(x) ((((unsigned long)(x)) + VCHI_BULK_ALIGN - 1) & ~(VCHI_BULK_ALIGN - 1)) +#define VCHI_BULK_ROUND_DOWN(x) (((unsigned long)(x)) & ~(VCHI_BULK_ALIGN - 1)) +#define VCHI_BULK_ALIGN_NBYTES(x) (VCHI_BULK_ALIGNED(x) ? 0 : (VCHI_BULK_ALIGN - ((unsigned long)(x) & (VCHI_BULK_ALIGN - 1)))) #ifdef USE_VCHIQ_ARM #define VCHI_BULK_ALIGNED(x) 1 #else -#define VCHI_BULK_ALIGNED(x) (((unsigned long)(x) & (VCHI_BULK_ALIGN-1)) == 0) +#define VCHI_BULK_ALIGNED(x) (((unsigned long)(x) & (VCHI_BULK_ALIGN - 1)) == 0) #endif struct vchi_version { @@ -45,18 +45,19 @@ struct vchi_held_msg { struct service_creation { struct vchi_version version; int32_t service_id; - VCHI_CALLBACK_T callback; + vchi_callback callback; void *callback_param; }; // Opaque handle for a VCHI instance -typedef struct opaque_vchi_instance_handle_t *VCHI_INSTANCE_T; +struct vchi_instance_handle; // Opaque handle for a server or client -typedef struct opaque_vchi_service_handle_t *VCHI_SERVICE_HANDLE_T; +struct vchi_service_handle; /****************************************************************************** - Global funcs - implementation is specific to which side you are on (local / remote) + * Global funcs - implementation is specific to which side you are on + * (local / remote) *****************************************************************************/ #ifdef __cplusplus @@ -64,98 +65,99 @@ extern "C" { #endif // Routine used to initialise the vchi on both local + remote connections -extern int32_t vchi_initialise(VCHI_INSTANCE_T *instance_handle); +extern int32_t vchi_initialise(struct vchi_instance_handle **instance_handle); extern int32_t vchi_exit(void); -extern int32_t vchi_connect(VCHI_INSTANCE_T instance_handle); +extern int32_t vchi_connect(struct vchi_instance_handle *instance_handle); //When this is called, ensure that all services have no data pending. //Bulk transfers can remain 'queued' -extern int32_t vchi_disconnect(VCHI_INSTANCE_T instance_handle); +extern int32_t vchi_disconnect(struct vchi_instance_handle *instance_handle); // helper functions -extern void *vchi_allocate_buffer(VCHI_SERVICE_HANDLE_T handle, uint32_t *length); -extern void vchi_free_buffer(VCHI_SERVICE_HANDLE_T handle, void *address); -extern uint32_t vchi_current_time(VCHI_INSTANCE_T instance_handle); +extern void *vchi_allocate_buffer(struct vchi_service_handle *handle, uint32_t *length); +extern void vchi_free_buffer(struct vchi_service_handle *handle, void *address); +extern uint32_t vchi_current_time(struct vchi_instance_handle *instance_handle); /****************************************************************************** - Global service API + * Global service API *****************************************************************************/ // Routine to destroy a service -extern int32_t vchi_service_destroy(const VCHI_SERVICE_HANDLE_T handle); +extern int32_t vchi_service_destroy(const struct vchi_service_handle *handle); // Routine to open a named service -extern int32_t vchi_service_open(VCHI_INSTANCE_T instance_handle, +extern int32_t vchi_service_open(struct vchi_instance_handle *instance_handle, struct service_creation *setup, - VCHI_SERVICE_HANDLE_T *handle); + struct vchi_service_handle **handle); -extern int32_t vchi_get_peer_version(const VCHI_SERVICE_HANDLE_T handle, +extern int32_t vchi_get_peer_version(const struct vchi_service_handle *handle, short *peer_version); // Routine to close a named service -extern int32_t vchi_service_close(const VCHI_SERVICE_HANDLE_T handle); +extern int32_t vchi_service_close(const struct vchi_service_handle *handle); // Routine to increment ref count on a named service -extern int32_t vchi_service_use(const VCHI_SERVICE_HANDLE_T handle); +extern int32_t vchi_service_use(const struct vchi_service_handle *handle); // Routine to decrement ref count on a named service -extern int32_t vchi_service_release(const VCHI_SERVICE_HANDLE_T handle); +extern int32_t vchi_service_release(const struct vchi_service_handle *handle); // Routine to set a control option for a named service -extern int32_t vchi_service_set_option(const VCHI_SERVICE_HANDLE_T handle, - VCHI_SERVICE_OPTION_T option, - int value); +extern int32_t vchi_service_set_option(const struct vchi_service_handle *handle, + enum vchi_service_option option, + int value); /* Routine to send a message from kernel memory across a service */ extern int -vchi_queue_kernel_message(VCHI_SERVICE_HANDLE_T handle, +vchi_queue_kernel_message(struct vchi_service_handle *handle, void *data, unsigned int size); /* Routine to send a message from user memory across a service */ extern int -vchi_queue_user_message(VCHI_SERVICE_HANDLE_T handle, +vchi_queue_user_message(struct vchi_service_handle *handle, void __user *data, unsigned int size); // Routine to receive a msg from a service // Dequeue is equivalent to hold, copy into client buffer, release -extern int32_t vchi_msg_dequeue(VCHI_SERVICE_HANDLE_T handle, +extern int32_t vchi_msg_dequeue(struct vchi_service_handle *handle, void *data, uint32_t max_data_size_to_read, uint32_t *actual_msg_size, - VCHI_FLAGS_T flags); + enum vchi_flags flags); // Routine to look at a message in place. // The message is not dequeued, so a subsequent call to peek or dequeue // will return the same message. -extern int32_t vchi_msg_peek(VCHI_SERVICE_HANDLE_T handle, +extern int32_t vchi_msg_peek(struct vchi_service_handle *handle, void **data, uint32_t *msg_size, - VCHI_FLAGS_T flags); + enum vchi_flags flags); // Routine to remove a message after it has been read in place with peek // The first message on the queue is dequeued. -extern int32_t vchi_msg_remove(VCHI_SERVICE_HANDLE_T handle); +extern int32_t vchi_msg_remove(struct vchi_service_handle *handle); // Routine to look at a message in place. // The message is dequeued, so the caller is left holding it; the descriptor is // filled in and must be released when the user has finished with the message. -extern int32_t vchi_msg_hold(VCHI_SERVICE_HANDLE_T handle, +extern int32_t vchi_msg_hold(struct vchi_service_handle *handle, void **data, // } may be NULL, as info can be uint32_t *msg_size, // } obtained from HELD_MSG_T - VCHI_FLAGS_T flags, + enum vchi_flags flags, struct vchi_held_msg *message_descriptor); // Initialise an iterator to look through messages in place -extern int32_t vchi_msg_look_ahead(VCHI_SERVICE_HANDLE_T handle, +extern int32_t vchi_msg_look_ahead(struct vchi_service_handle *handle, struct vchi_msg_iter *iter, - VCHI_FLAGS_T flags); + enum vchi_flags flags); -/****************************************************************************** - Global service support API - operations on held messages and message iterators - *****************************************************************************/ +/******************************************************************************* + * Global service support API - operations on held messages + * and message iterators + ******************************************************************************/ // Routine to get the address of a held message extern void *vchi_held_msg_ptr(const struct vchi_held_msg *message); @@ -196,42 +198,42 @@ extern int32_t vchi_msg_iter_hold_next(struct vchi_msg_iter *iter, struct vchi_held_msg *message); /****************************************************************************** - Global bulk API + * Global bulk API *****************************************************************************/ // Routine to prepare interface for a transfer from the other side -extern int32_t vchi_bulk_queue_receive(VCHI_SERVICE_HANDLE_T handle, +extern int32_t vchi_bulk_queue_receive(struct vchi_service_handle *handle, void *data_dst, uint32_t data_size, - VCHI_FLAGS_T flags, + enum vchi_flags flags, void *transfer_handle); // Prepare interface for a transfer from the other side into relocatable memory. -int32_t vchi_bulk_queue_receive_reloc(const VCHI_SERVICE_HANDLE_T handle, +int32_t vchi_bulk_queue_receive_reloc(const struct vchi_service_handle *handle, uint32_t offset, uint32_t data_size, - const VCHI_FLAGS_T flags, + const enum vchi_flags flags, void * const bulk_handle); // Routine to queue up data ready for transfer to the other (once they have signalled they are ready) -extern int32_t vchi_bulk_queue_transmit(VCHI_SERVICE_HANDLE_T handle, +extern int32_t vchi_bulk_queue_transmit(struct vchi_service_handle *handle, const void *data_src, uint32_t data_size, - VCHI_FLAGS_T flags, + enum vchi_flags flags, void *transfer_handle); /****************************************************************************** - Configuration plumbing + * Configuration plumbing *****************************************************************************/ #ifdef __cplusplus } #endif -extern int32_t vchi_bulk_queue_transmit_reloc(VCHI_SERVICE_HANDLE_T handle, +extern int32_t vchi_bulk_queue_transmit_reloc(struct vchi_service_handle *handle, uint32_t offset, uint32_t data_size, - VCHI_FLAGS_T flags, + enum vchi_flags flags, void *transfer_handle); #endif /* VCHI_H_ */ diff --git a/drivers/staging/vc04_services/interface/vchi/vchi_cfg.h b/drivers/staging/vc04_services/interface/vchi/vchi_cfg.h index 89aa4e6122cd..138c36151a22 100644 --- a/drivers/staging/vc04_services/interface/vchi/vchi_cfg.h +++ b/drivers/staging/vc04_services/interface/vchi/vchi_cfg.h @@ -4,13 +4,17 @@ #ifndef VCHI_CFG_H_ #define VCHI_CFG_H_ -/**************************************************************************************** - * Defines in this first section are part of the VCHI API and may be examined by VCHI - * services. - ***************************************************************************************/ - -/* Required alignment of base addresses for bulk transfer, if unaligned transfers are not enabled */ -/* Really determined by the message driver, and should be available from a run-time call. */ +/******************************************************************************* + * Defines in this first section are part of the VCHI API and may be examined by + * VCHI services. + ******************************************************************************/ + +/* + * Required alignment of base addresses for bulk transfer, if unaligned + * transfers are not enabled + * Really determined by the message driver, and should be available from + * a run-time call. + */ #ifndef VCHI_BULK_ALIGN # if __VCCOREVER__ >= 0x04000000 # define VCHI_BULK_ALIGN 32 // Allows for the need to do cache cleans @@ -19,9 +23,13 @@ # endif #endif -/* Required length multiple for bulk transfers, if unaligned transfers are not enabled */ -/* May be less than or greater than VCHI_BULK_ALIGN */ -/* Really determined by the message driver, and should be available from a run-time call. */ +/* + * Required length multiple for bulk transfers, if unaligned transfers are + * not enabled + * May be less than or greater than VCHI_BULK_ALIGN + * Really determined by the message driver, and should be available from + * a run-time call. + */ #ifndef VCHI_BULK_GRANULARITY # if __VCCOREVER__ >= 0x04000000 # define VCHI_BULK_GRANULARITY 32 // Allows for the need to do cache cleans @@ -39,19 +47,24 @@ # endif #endif -/****************************************************************************************** - * Defines below are system configuration options, and should not be used by VCHI services. - *****************************************************************************************/ +/****************************************************************************** + * Defines below are system configuration options, and should not be used by + * VCHI services. + ******************************************************************************/ -/* How many connections can we support? A localhost implementation uses 2 connections, - * 1 for host-app, 1 for VMCS, and these are hooked together by a loopback MPHI VCFW - * driver. */ +/* + * How many connections can we support? A localhost implementation uses + * 2 connections, 1 for host-app, 1 for VMCS, and these are hooked together + * by a loopback MPHI VCFW driver. + */ #ifndef VCHI_MAX_NUM_CONNECTIONS # define VCHI_MAX_NUM_CONNECTIONS 3 #endif -/* How many services can we open per connection? Extending this doesn't cost processing time, just a small - * amount of static memory. */ +/* + * How many services can we open per connection? Extending this doesn't cost + * processing time, just a small amount of static memory. + */ #ifndef VCHI_MAX_SERVICES_PER_CONNECTION # define VCHI_MAX_SERVICES_PER_CONNECTION 36 #endif @@ -66,8 +79,10 @@ # define VCHI_MAX_BULK_RX_CHANNELS_PER_CONNECTION 1 // 1 MPHI #endif -/* How many receive slots do we use. This times VCHI_MAX_MSG_SIZE gives the effective - * receive queue space, less message headers. */ +/* + * How many receive slots do we use. This times VCHI_MAX_MSG_SIZE gives the + * effective receive queue space, less message headers. + */ #ifndef VCHI_NUM_READ_SLOTS # if defined(VCHI_LOCAL_HOST_PORT) # define VCHI_NUM_READ_SLOTS 4 @@ -76,112 +91,141 @@ # endif #endif -/* Do we utilise overrun facility for receive message slots? Can aid peer transmit - * performance. Only define on VideoCore end, talking to host. +/* + * Do we utilise overrun facility for receive message slots? Can aid peer + * transmit performance. Only define on VideoCore end, talking to host. */ //#define VCHI_MSG_RX_OVERRUN -/* How many transmit slots do we use. Generally don't need many, as the hardware driver - * underneath VCHI will usually have its own buffering. */ +/* + * How many transmit slots do we use. Generally don't need many, + * as the hardware driver underneath VCHI will usually have its own buffering. + */ #ifndef VCHI_NUM_WRITE_SLOTS # define VCHI_NUM_WRITE_SLOTS 4 #endif -/* If a service has held or queued received messages in VCHI_XOFF_THRESHOLD or more slots, - * then it's taking up too much buffer space, and the peer service will be told to stop - * transmitting with an XOFF message. For this to be effective, the VCHI_NUM_READ_SLOTS - * needs to be considerably bigger than VCHI_NUM_WRITE_SLOTS, or the transmit latency - * is too high. */ +/* + * If a service has held or queued received messages in VCHI_XOFF_THRESHOLD or + * more slots, then it's taking up too much buffer space, + * and the peer service will be told to stop transmitting with an XOFF message. + * For this to be effective, the VCHI_NUM_READ_SLOTS needs to be considerably + * bigger than VCHI_NUM_WRITE_SLOTS, or the transmit latency is too high. + */ #ifndef VCHI_XOFF_THRESHOLD # define VCHI_XOFF_THRESHOLD (VCHI_NUM_READ_SLOTS / 2) #endif -/* After we've sent an XOFF, the peer will be told to resume transmission once the local - * service has dequeued/released enough messages that it's now occupying - * VCHI_XON_THRESHOLD slots or fewer. */ +/* + * After we've sent an XOFF, the peer will be told to resume transmission + * once the local service has dequeued/released enough messages that it's now + * occupying VCHI_XON_THRESHOLD slots or fewer. + */ #ifndef VCHI_XON_THRESHOLD # define VCHI_XON_THRESHOLD (VCHI_NUM_READ_SLOTS / 4) #endif -/* A size below which a bulk transfer omits the handshake completely and always goes - * via the message channel, if bulk auxiliary is being sent on that service. (The user - * can guarantee this by enabling unaligned transmits). - * Not API. */ +/* + * A size below which a bulk transfer omits the handshake completely and always + * goes via the message channel, if bulk auxiliary is being sent on that + * service. (The user can guarantee this by enabling unaligned transmits). + * Not API. + */ #ifndef VCHI_MIN_BULK_SIZE # define VCHI_MIN_BULK_SIZE (VCHI_MAX_MSG_SIZE / 2 < 4096 ? VCHI_MAX_MSG_SIZE / 2 : 4096) #endif -/* Maximum size of bulk transmission chunks, for each interface type. A trade-off between - * speed and latency; the smaller the chunk size the better change of messages and other - * bulk transmissions getting in when big bulk transfers are happening. Set to 0 to not - * break transmissions into chunks. +/* + * Maximum size of bulk transmission chunks, for each interface type. + * A trade-off between speed and latency; the smaller the chunk size the better + * change of messages and other bulk transmissions getting in when big bulk + * transfers are happening. Set to 0 to not break transmissions into chunks. */ #ifndef VCHI_MAX_BULK_CHUNK_SIZE_MPHI # define VCHI_MAX_BULK_CHUNK_SIZE_MPHI (16 * 1024) #endif -/* NB Chunked CCP2 transmissions violate the letter of the CCP2 spec by using "JPEG8" mode - * with multiple-line frames. Only use if the receiver can cope. */ +/* + * NB Chunked CCP2 transmissions violate the letter of the CCP2 spec + * by using "JPEG8" mode with multiple-line frames. Only use if the receiver + * can cope. + */ #ifndef VCHI_MAX_BULK_CHUNK_SIZE_CCP2 # define VCHI_MAX_BULK_CHUNK_SIZE_CCP2 0 #endif -/* How many TX messages can we have pending in our transmit slots. Once exhausted, - * vchi_msg_queue will be blocked. */ +/* + * How many TX messages can we have pending in our transmit slots. + * Once exhausted, vchi_msg_queue will be blocked. + */ #ifndef VCHI_TX_MSG_QUEUE_SIZE # define VCHI_TX_MSG_QUEUE_SIZE 256 #endif -/* How many RX messages can we have parsed in the receive slots. Once exhausted, parsing - * will be suspended until older messages are dequeued/released. */ +/* + * How many RX messages can we have parsed in the receive slots. Once exhausted, + * parsing will be suspended until older messages are dequeued/released. + */ #ifndef VCHI_RX_MSG_QUEUE_SIZE # define VCHI_RX_MSG_QUEUE_SIZE 256 #endif -/* Really should be able to cope if we run out of received message descriptors, by - * suspending parsing as the comment above says, but we don't. This sweeps the issue - * under the carpet. */ -#if VCHI_RX_MSG_QUEUE_SIZE < (VCHI_MAX_MSG_SIZE/16 + 1) * VCHI_NUM_READ_SLOTS +/* + * Really should be able to cope if we run out of received message descriptors, + * by suspending parsing as the comment above says, but we don't. + * This sweeps the issue under the carpet. + */ +#if VCHI_RX_MSG_QUEUE_SIZE < (VCHI_MAX_MSG_SIZE / 16 + 1) * VCHI_NUM_READ_SLOTS # undef VCHI_RX_MSG_QUEUE_SIZE -# define VCHI_RX_MSG_QUEUE_SIZE ((VCHI_MAX_MSG_SIZE/16 + 1) * VCHI_NUM_READ_SLOTS) +# define VCHI_RX_MSG_QUEUE_SIZE ((VCHI_MAX_MSG_SIZE / 16 + 1) * VCHI_NUM_READ_SLOTS) #endif -/* How many bulk transmits can we have pending. Once exhausted, vchi_bulk_queue_transmit - * will be blocked. */ +/* + * How many bulk transmits can we have pending. Once exhausted, + * vchi_bulk_queue_transmit will be blocked. + */ #ifndef VCHI_TX_BULK_QUEUE_SIZE # define VCHI_TX_BULK_QUEUE_SIZE 64 #endif -/* How many bulk receives can we have pending. Once exhausted, vchi_bulk_queue_receive - * will be blocked. */ +/* + * How many bulk receives can we have pending. Once exhausted, + *vchi_bulk_queue_receive will be blocked. + */ #ifndef VCHI_RX_BULK_QUEUE_SIZE # define VCHI_RX_BULK_QUEUE_SIZE 64 #endif -/* A limit on how many outstanding bulk requests we expect the peer to give us. If - * the peer asks for more than this, VCHI will fail and assert. The number is determined - * by the peer's hardware - it's the number of outstanding requests that can be queued - * on all bulk channels. VC3's MPHI peripheral allows 16. */ +/* + * A limit on how many outstanding bulk requests we expect the peer to give us. + * If the peer asks for more than this, VCHI will fail and assert. + * The number is determined by the peer's hardware + * - it's the number of outstanding requests that can be queued + * on all bulk channels. VC3's MPHI peripheral allows 16. + */ #ifndef VCHI_MAX_PEER_BULK_REQUESTS # define VCHI_MAX_PEER_BULK_REQUESTS 32 #endif -/* Define VCHI_CCP2TX_MANUAL_POWER if the host tells us when to turn the CCP2 +/* + * Define VCHI_CCP2TX_MANUAL_POWER if the host tells us when to turn the CCP2 * transmitter on and off. */ /*#define VCHI_CCP2TX_MANUAL_POWER*/ #ifndef VCHI_CCP2TX_MANUAL_POWER -/* Timeout (in milliseconds) for putting the CCP2TX interface into IDLE state. Set - * negative for no IDLE. +/* + * Timeout (in milliseconds) for putting the CCP2TX interface into IDLE state. + * Set negative for no IDLE. */ # ifndef VCHI_CCP2TX_IDLE_TIMEOUT # define VCHI_CCP2TX_IDLE_TIMEOUT 5 # endif -/* Timeout (in milliseconds) for putting the CCP2TX interface into OFF state. Set - * negative for no OFF. +/* + * Timeout (in milliseconds) for putting the CCP2TX interface into OFF state. + * Set negative for no OFF. */ # ifndef VCHI_CCP2TX_OFF_TIMEOUT # define VCHI_CCP2TX_OFF_TIMEOUT 1000 diff --git a/drivers/staging/vc04_services/interface/vchi/vchi_common.h b/drivers/staging/vc04_services/interface/vchi/vchi_common.h index e7955cbaf26a..141af16ce031 100644 --- a/drivers/staging/vc04_services/interface/vchi/vchi_common.h +++ b/drivers/staging/vc04_services/interface/vchi/vchi_common.h @@ -5,7 +5,7 @@ #define VCHI_COMMON_H_ //flags used when sending messages (must be bitmapped) -typedef enum { +enum vchi_flags { VCHI_FLAGS_NONE = 0x0, VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE = 0x1, // waits for message to be received, or sent (NB. not the same as being seen on other side) VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE = 0x2, // run a callback when message sent @@ -20,17 +20,17 @@ typedef enum { VCHI_FLAGS_BULK_DATA_QUEUED = 0x040000, // internal use only VCHI_FLAGS_BULK_DATA_COMPLETE = 0x080000, // internal use only VCHI_FLAGS_INTERNAL = 0xFF0000 -} VCHI_FLAGS_T; +}; // constants for vchi_crc_control() -typedef enum { +enum vchi_crc_control { VCHI_CRC_NOTHING = -1, VCHI_CRC_PER_SERVICE = 0, VCHI_CRC_EVERYTHING = 1, -} VCHI_CRC_CONTROL_T; +}; //callback reasons when an event occurs on a service -typedef enum { +enum vchi_callback_reason { VCHI_CALLBACK_REASON_MIN, //This indicates that there is data available @@ -73,22 +73,22 @@ typedef enum { VCHI_CALLBACK_BULK_TRANSMIT_ABORTED, VCHI_CALLBACK_REASON_MAX -} VCHI_CALLBACK_REASON_T; +}; // service control options -typedef enum { +enum vchi_service_option { VCHI_SERVICE_OPTION_MIN, VCHI_SERVICE_OPTION_TRACE, VCHI_SERVICE_OPTION_SYNCHRONOUS, VCHI_SERVICE_OPTION_MAX -} VCHI_SERVICE_OPTION_T; +}; //Callback used by all services / bulk transfers -typedef void (*VCHI_CALLBACK_T)(void *callback_param, //my service local param - VCHI_CALLBACK_REASON_T reason, - void *handle); //for transmitting msg's only +typedef void (*vchi_callback)(void *callback_param, //my service local param + enum vchi_callback_reason reason, + void *handle); //for transmitting msg's only /* * Define vector struct for scatter-gather (vector) operations @@ -112,12 +112,6 @@ struct vchi_msg_vector { int32_t vec_len; }; -// Opaque type for a connection API -typedef struct opaque_vchi_connection_api_t VCHI_CONNECTION_API_T; - -// Opaque type for a message driver -typedef struct opaque_vchi_message_driver_t VCHI_MESSAGE_DRIVER_T; - // Iterator structure for reading ahead through received message queue. Allocated by client, // initialised by vchi_msg_look_ahead. Fields are for internal VCHI use only. // Iterates over messages in queue at the instant of the call to vchi_msg_lookahead - diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c index 8dc730cfe7a6..e568e9e6eb95 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c @@ -81,7 +81,6 @@ int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state *state) struct vchiq_drvdata *drvdata = platform_get_drvdata(pdev); struct rpi_firmware *fw = drvdata->fw; struct vchiq_slot_zero *vchiq_slot_zero; - struct resource *res; void *slot_mem; dma_addr_t slot_phys; u32 channelbase; @@ -135,8 +134,7 @@ int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state *state) if (vchiq_init_state(state, vchiq_slot_zero) != VCHIQ_SUCCESS) return -EINVAL; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - g_regs = devm_ioremap_resource(&pdev->dev, res); + g_regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(g_regs)) return PTR_ERR(g_regs); @@ -170,10 +168,10 @@ int vchiq_platform_init(struct platform_device *pdev, struct vchiq_state *state) return 0; } -VCHIQ_STATUS_T +enum vchiq_status vchiq_platform_init_state(struct vchiq_state *state) { - VCHIQ_STATUS_T status = VCHIQ_SUCCESS; + enum vchiq_status status = VCHIQ_SUCCESS; struct vchiq_2835_state *platform_state; state->platform_state = kzalloc(sizeof(*platform_state), GFP_KERNEL); @@ -216,7 +214,7 @@ remote_event_signal(struct remote_event *event) writel(0, g_regs + BELL2); /* trigger vc interrupt */ } -VCHIQ_STATUS_T +enum vchiq_status vchiq_prepare_bulk_data(struct vchiq_bulk *bulk, void *offset, int size, int dir) { @@ -260,13 +258,13 @@ vchiq_dump_platform_state(void *dump_context) vchiq_dump(dump_context, buf, len + 1); } -VCHIQ_STATUS_T +enum vchiq_status vchiq_platform_suspend(struct vchiq_state *state) { return VCHIQ_ERROR; } -VCHIQ_STATUS_T +enum vchiq_status vchiq_platform_resume(struct vchiq_state *state) { return VCHIQ_SUCCESS; @@ -526,11 +524,11 @@ create_pagelist(char __user *buf, size_t count, unsigned short type) return NULL; } - WARN_ON(g_free_fragments == NULL); + WARN_ON(!g_free_fragments); down(&g_free_fragments_mutex); fragments = g_free_fragments; - WARN_ON(fragments == NULL); + WARN_ON(!fragments); g_free_fragments = *(char **) g_free_fragments; up(&g_free_fragments_mutex); pagelist->type = PAGELIST_READ_WITH_FRAGMENTS + diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c index b1595b13dea8..be8b2a71da2d 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c @@ -84,7 +84,7 @@ static void suspend_timer_callback(struct timer_list *t); struct user_service { struct vchiq_service *service; void *userdata; - VCHIQ_INSTANCE_T instance; + struct vchiq_instance *instance; char is_vchi; char dequeue_pending; char close_pending; @@ -103,7 +103,7 @@ struct bulk_waiter_node { struct list_head list; }; -struct vchiq_instance_struct { +struct vchiq_instance { struct vchiq_state *state; struct vchiq_completion_data completions[MAX_COMPLETIONS]; int completion_insert; @@ -172,16 +172,16 @@ static const char *const ioctl_names[] = { vchiq_static_assert(ARRAY_SIZE(ioctl_names) == (VCHIQ_IOC_MAX + 1)); -static VCHIQ_STATUS_T -vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data, - unsigned int size, VCHIQ_BULK_DIR_T dir); +static enum vchiq_status +vchiq_blocking_bulk_transfer(unsigned int handle, void *data, + unsigned int size, enum vchiq_bulk_dir dir); #define VCHIQ_INIT_RETRIES 10 -VCHIQ_STATUS_T vchiq_initialise(VCHIQ_INSTANCE_T *instance_out) +enum vchiq_status vchiq_initialise(struct vchiq_instance **instance_out) { - VCHIQ_STATUS_T status = VCHIQ_ERROR; + enum vchiq_status status = VCHIQ_ERROR; struct vchiq_state *state; - VCHIQ_INSTANCE_T instance = NULL; + struct vchiq_instance *instance = NULL; int i; vchiq_log_trace(vchiq_core_log_level, "%s called", __func__); @@ -230,9 +230,9 @@ failed: } EXPORT_SYMBOL(vchiq_initialise); -VCHIQ_STATUS_T vchiq_shutdown(VCHIQ_INSTANCE_T instance) +enum vchiq_status vchiq_shutdown(struct vchiq_instance *instance) { - VCHIQ_STATUS_T status; + enum vchiq_status status; struct vchiq_state *state = instance->state; vchiq_log_trace(vchiq_core_log_level, @@ -267,14 +267,14 @@ VCHIQ_STATUS_T vchiq_shutdown(VCHIQ_INSTANCE_T instance) } EXPORT_SYMBOL(vchiq_shutdown); -static int vchiq_is_connected(VCHIQ_INSTANCE_T instance) +static int vchiq_is_connected(struct vchiq_instance *instance) { return instance->connected; } -VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance) +enum vchiq_status vchiq_connect(struct vchiq_instance *instance) { - VCHIQ_STATUS_T status; + enum vchiq_status status; struct vchiq_state *state = instance->state; vchiq_log_trace(vchiq_core_log_level, @@ -301,12 +301,12 @@ failed: } EXPORT_SYMBOL(vchiq_connect); -VCHIQ_STATUS_T vchiq_add_service( - VCHIQ_INSTANCE_T instance, +enum vchiq_status vchiq_add_service( + struct vchiq_instance *instance, const struct vchiq_service_params *params, - VCHIQ_SERVICE_HANDLE_T *phandle) + unsigned int *phandle) { - VCHIQ_STATUS_T status; + enum vchiq_status status; struct vchiq_state *state = instance->state; struct vchiq_service *service = NULL; int srvstate; @@ -340,12 +340,12 @@ VCHIQ_STATUS_T vchiq_add_service( } EXPORT_SYMBOL(vchiq_add_service); -VCHIQ_STATUS_T vchiq_open_service( - VCHIQ_INSTANCE_T instance, +enum vchiq_status vchiq_open_service( + struct vchiq_instance *instance, const struct vchiq_service_params *params, - VCHIQ_SERVICE_HANDLE_T *phandle) + unsigned int *phandle) { - VCHIQ_STATUS_T status = VCHIQ_ERROR; + enum vchiq_status status = VCHIQ_ERROR; struct vchiq_state *state = instance->state; struct vchiq_service *service = NULL; @@ -380,11 +380,11 @@ failed: } EXPORT_SYMBOL(vchiq_open_service); -VCHIQ_STATUS_T -vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle, const void *data, - unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode) +enum vchiq_status +vchiq_bulk_transmit(unsigned int handle, const void *data, + unsigned int size, void *userdata, enum vchiq_bulk_mode mode) { - VCHIQ_STATUS_T status; + enum vchiq_status status; switch (mode) { case VCHIQ_BULK_MODE_NOCALLBACK: @@ -405,11 +405,11 @@ vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle, const void *data, } EXPORT_SYMBOL(vchiq_bulk_transmit); -VCHIQ_STATUS_T -vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data, - unsigned int size, void *userdata, VCHIQ_BULK_MODE_T mode) +enum vchiq_status +vchiq_bulk_receive(unsigned int handle, void *data, + unsigned int size, void *userdata, enum vchiq_bulk_mode mode) { - VCHIQ_STATUS_T status; + enum vchiq_status status; switch (mode) { case VCHIQ_BULK_MODE_NOCALLBACK: @@ -429,13 +429,13 @@ vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle, void *data, } EXPORT_SYMBOL(vchiq_bulk_receive); -static VCHIQ_STATUS_T -vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data, - unsigned int size, VCHIQ_BULK_DIR_T dir) +static enum vchiq_status +vchiq_blocking_bulk_transfer(unsigned int handle, void *data, + unsigned int size, enum vchiq_bulk_dir dir) { - VCHIQ_INSTANCE_T instance; + struct vchiq_instance *instance; struct vchiq_service *service; - VCHIQ_STATUS_T status; + enum vchiq_status status; struct bulk_waiter_node *waiter = NULL; service = find_service_by_handle(handle); @@ -515,8 +515,8 @@ vchiq_blocking_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *data, * ***************************************************************************/ -static VCHIQ_STATUS_T -add_completion(VCHIQ_INSTANCE_T instance, VCHIQ_REASON_T reason, +static enum vchiq_status +add_completion(struct vchiq_instance *instance, enum vchiq_reason reason, struct vchiq_header *header, struct user_service *user_service, void *bulk_userdata) { @@ -582,9 +582,9 @@ add_completion(VCHIQ_INSTANCE_T instance, VCHIQ_REASON_T reason, * ***************************************************************************/ -static VCHIQ_STATUS_T -service_callback(VCHIQ_REASON_T reason, struct vchiq_header *header, - VCHIQ_SERVICE_HANDLE_T handle, void *bulk_userdata) +static enum vchiq_status +service_callback(enum vchiq_reason reason, struct vchiq_header *header, + unsigned int handle, void *bulk_userdata) { /* How do we ensure the callback goes to the right client? ** The service_user data points to a user_service record @@ -593,7 +593,7 @@ service_callback(VCHIQ_REASON_T reason, struct vchiq_header *header, */ struct user_service *user_service; struct vchiq_service *service; - VCHIQ_INSTANCE_T instance; + struct vchiq_instance *instance; bool skip_completion = false; DEBUG_INITIALISE(g_state.local) @@ -630,7 +630,7 @@ service_callback(VCHIQ_REASON_T reason, struct vchiq_header *header, */ if ((user_service->message_available_pos - instance->completion_remove) < 0) { - VCHIQ_STATUS_T status; + enum vchiq_status status; vchiq_log_info(vchiq_arm_log_level, "Inserting extra MESSAGE_AVAILABLE"); @@ -772,8 +772,8 @@ static ssize_t vchiq_ioc_copy_element_data(void *context, void *dest, * vchiq_ioc_queue_message * **************************************************************************/ -static VCHIQ_STATUS_T -vchiq_ioc_queue_message(VCHIQ_SERVICE_HANDLE_T handle, +static enum vchiq_status +vchiq_ioc_queue_message(unsigned int handle, struct vchiq_element *elements, unsigned long count) { @@ -804,8 +804,8 @@ vchiq_ioc_queue_message(VCHIQ_SERVICE_HANDLE_T handle, static long vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - VCHIQ_INSTANCE_T instance = file->private_data; - VCHIQ_STATUS_T status = VCHIQ_SUCCESS; + struct vchiq_instance *instance = file->private_data; + enum vchiq_status status = VCHIQ_SUCCESS; struct vchiq_service *service = NULL; long ret = 0; int i, rc; @@ -827,7 +827,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg) /* Remove all services */ i = 0; while ((service = next_service_by_instance(instance->state, - instance, &i)) != NULL) { + instance, &i))) { status = vchiq_remove_service(service->handle); unlock_service(service); if (status != VCHIQ_SUCCESS) @@ -907,7 +907,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg) &args.params, srvstate, instance, user_service_free); - if (service != NULL) { + if (service) { user_service->service = service; user_service->userdata = userdata; user_service->instance = instance; @@ -952,7 +952,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case VCHIQ_IOC_CLOSE_SERVICE: case VCHIQ_IOC_REMOVE_SERVICE: { - VCHIQ_SERVICE_HANDLE_T handle = (VCHIQ_SERVICE_HANDLE_T)arg; + unsigned int handle = (unsigned int)arg; struct user_service *user_service; service = find_service_for_instance(instance, handle); @@ -985,10 +985,10 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case VCHIQ_IOC_USE_SERVICE: case VCHIQ_IOC_RELEASE_SERVICE: { - VCHIQ_SERVICE_HANDLE_T handle = (VCHIQ_SERVICE_HANDLE_T)arg; + unsigned int handle = (unsigned int)arg; service = find_service_for_instance(instance, handle); - if (service != NULL) { + if (service) { status = (cmd == VCHIQ_IOC_USE_SERVICE) ? vchiq_use_service_internal(service) : vchiq_release_service_internal(service); @@ -1021,7 +1021,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg) service = find_service_for_instance(instance, args.handle); - if ((service != NULL) && (args.count <= MAX_ELEMENTS)) { + if (service && (args.count <= MAX_ELEMENTS)) { /* Copy elements into kernel space */ struct vchiq_element elements[MAX_ELEMENTS]; @@ -1042,7 +1042,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg) struct vchiq_queue_bulk_transfer args; struct bulk_waiter_node *waiter = NULL; - VCHIQ_BULK_DIR_T dir = + enum vchiq_bulk_dir dir = (cmd == VCHIQ_IOC_QUEUE_BULK_TRANSMIT) ? VCHIQ_BULK_TRANSMIT : VCHIQ_BULK_RECEIVE; @@ -1107,7 +1107,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } kfree(waiter); } else { - const VCHIQ_BULK_MODE_T mode_waiting = + const enum vchiq_bulk_mode mode_waiting = VCHIQ_BULK_MODE_WAITING; waiter->pid = current->pid; mutex_lock(&instance->bulk_waiter_list_mutex); @@ -1343,11 +1343,11 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg) spin_unlock(&msg_queue_spinlock); complete(&user_service->remove_event); - if (header == NULL) + if (!header) ret = -ENOTCONN; else if (header->size <= args.bufsize) { /* Copy to user space if msgbuf is not NULL */ - if ((args.buf == NULL) || + if (!args.buf || (copy_to_user((void __user *)args.buf, header->data, header->size) == 0)) { @@ -1368,7 +1368,7 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } break; case VCHIQ_IOC_GET_CLIENT_ID: { - VCHIQ_SERVICE_HANDLE_T handle = (VCHIQ_SERVICE_HANDLE_T)arg; + unsigned int handle = (unsigned int)arg; ret = vchiq_get_client_id(handle); } break; @@ -1423,10 +1423,10 @@ vchiq_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } break; case VCHIQ_IOC_CLOSE_DELIVERED: { - VCHIQ_SERVICE_HANDLE_T handle = (VCHIQ_SERVICE_HANDLE_T)arg; + unsigned int handle = (unsigned int)arg; service = find_closed_service_for_instance(instance, handle); - if (service != NULL) { + if (service) { struct user_service *user_service = (struct user_service *)service->base.userdata; close_delivered(user_service); @@ -1611,7 +1611,7 @@ struct vchiq_queue_bulk_transfer32 { compat_uptr_t data; unsigned int size; compat_uptr_t userdata; - VCHIQ_BULK_MODE_T mode; + enum vchiq_bulk_mode mode; }; #define VCHIQ_IOC_QUEUE_BULK_TRANSMIT32 \ @@ -1666,7 +1666,7 @@ vchiq_compat_ioctl_queue_bulk(struct file *file, } struct vchiq_completion_data32 { - VCHIQ_REASON_T reason; + enum vchiq_reason reason; compat_uptr_t header; compat_uptr_t service_userdata; compat_uptr_t bulk_userdata; @@ -1919,7 +1919,7 @@ vchiq_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) static int vchiq_open(struct inode *inode, struct file *file) { struct vchiq_state *state = vchiq_get_state(); - VCHIQ_INSTANCE_T instance; + struct vchiq_instance *instance; vchiq_log_info(vchiq_arm_log_level, "vchiq_open"); @@ -1951,7 +1951,7 @@ static int vchiq_open(struct inode *inode, struct file *file) static int vchiq_release(struct inode *inode, struct file *file) { - VCHIQ_INSTANCE_T instance = file->private_data; + struct vchiq_instance *instance = file->private_data; struct vchiq_state *state = vchiq_get_state(); struct vchiq_service *service; int ret = 0; @@ -2130,7 +2130,7 @@ vchiq_dump_platform_instances(void *dump_context) for (i = 0; i < state->unused_service; i++) { struct vchiq_service *service = state->services[i]; - VCHIQ_INSTANCE_T instance; + struct vchiq_instance *instance; if (service && (service->base.callback == service_callback)) { instance = service->instance; @@ -2141,7 +2141,7 @@ vchiq_dump_platform_instances(void *dump_context) for (i = 0; i < state->unused_service; i++) { struct vchiq_service *service = state->services[i]; - VCHIQ_INSTANCE_T instance; + struct vchiq_instance *instance; if (service && (service->base.callback == service_callback)) { instance = service->instance; @@ -2223,13 +2223,13 @@ struct vchiq_state * vchiq_get_state(void) { - if (g_state.remote == NULL) + if (!g_state.remote) printk(KERN_ERR "%s: g_state.remote == NULL\n", __func__); else if (g_state.remote->initialised != 1) printk(KERN_NOTICE "%s: g_state.remote->initialised != 1 (%d)\n", __func__, g_state.remote->initialised); - return ((g_state.remote != NULL) && + return (g_state.remote && (g_state.remote->initialised == 1)) ? &g_state : NULL; } @@ -2270,10 +2270,10 @@ vchiq_videocore_wanted(struct vchiq_state *state) return 1; } -static VCHIQ_STATUS_T -vchiq_keepalive_vchiq_callback(VCHIQ_REASON_T reason, +static enum vchiq_status +vchiq_keepalive_vchiq_callback(enum vchiq_reason reason, struct vchiq_header *header, - VCHIQ_SERVICE_HANDLE_T service_user, + unsigned int service_user, void *bulk_user) { vchiq_log_error(vchiq_susp_log_level, @@ -2287,9 +2287,9 @@ vchiq_keepalive_thread_func(void *v) struct vchiq_state *state = (struct vchiq_state *)v; struct vchiq_arm_state *arm_state = vchiq_platform_get_arm_state(state); - VCHIQ_STATUS_T status; - VCHIQ_INSTANCE_T instance; - VCHIQ_SERVICE_HANDLE_T ka_handle; + enum vchiq_status status; + struct vchiq_instance *instance; + unsigned int ka_handle; struct vchiq_service_params params = { .fourcc = VCHIQ_MAKE_FOURCC('K', 'E', 'E', 'P'), @@ -2361,7 +2361,7 @@ exit: return 0; } -VCHIQ_STATUS_T +enum vchiq_status vchiq_arm_init_state(struct vchiq_state *state, struct vchiq_arm_state *arm_state) { @@ -2563,10 +2563,10 @@ unblock_resume(struct vchiq_arm_state *arm_state) /* Initiate suspend via slot handler. Should be called with the write lock * held */ -VCHIQ_STATUS_T +enum vchiq_status vchiq_arm_vcsuspend(struct vchiq_state *state) { - VCHIQ_STATUS_T status = VCHIQ_ERROR; + enum vchiq_status status = VCHIQ_ERROR; struct vchiq_arm_state *arm_state = vchiq_platform_get_arm_state(state); if (!arm_state) @@ -2684,12 +2684,12 @@ out: return resume; } -VCHIQ_STATUS_T +enum vchiq_status vchiq_use_internal(struct vchiq_state *state, struct vchiq_service *service, enum USE_TYPE_E use_type) { struct vchiq_arm_state *arm_state = vchiq_platform_get_arm_state(state); - VCHIQ_STATUS_T ret = VCHIQ_SUCCESS; + enum vchiq_status ret = VCHIQ_SUCCESS; char entity[16]; int *entity_uc; int local_uc, local_entity_uc; @@ -2798,7 +2798,7 @@ vchiq_use_internal(struct vchiq_state *state, struct vchiq_service *service, } if (ret == VCHIQ_SUCCESS) { - VCHIQ_STATUS_T status = VCHIQ_SUCCESS; + enum vchiq_status status = VCHIQ_SUCCESS; long ack_cnt = atomic_xchg(&arm_state->ka_use_ack_count, 0); while (ack_cnt && (status == VCHIQ_SUCCESS)) { @@ -2817,11 +2817,11 @@ out: return ret; } -VCHIQ_STATUS_T +enum vchiq_status vchiq_release_internal(struct vchiq_state *state, struct vchiq_service *service) { struct vchiq_arm_state *arm_state = vchiq_platform_get_arm_state(state); - VCHIQ_STATUS_T ret = VCHIQ_SUCCESS; + enum vchiq_status ret = VCHIQ_SUCCESS; char entity[16]; int *entity_uc; @@ -2898,33 +2898,33 @@ vchiq_on_remote_release(struct vchiq_state *state) complete(&arm_state->ka_evt); } -VCHIQ_STATUS_T +enum vchiq_status vchiq_use_service_internal(struct vchiq_service *service) { return vchiq_use_internal(service->state, service, USE_TYPE_SERVICE); } -VCHIQ_STATUS_T +enum vchiq_status vchiq_release_service_internal(struct vchiq_service *service) { return vchiq_release_internal(service->state, service); } struct vchiq_debugfs_node * -vchiq_instance_get_debugfs_node(VCHIQ_INSTANCE_T instance) +vchiq_instance_get_debugfs_node(struct vchiq_instance *instance) { return &instance->debugfs_node; } int -vchiq_instance_get_use_count(VCHIQ_INSTANCE_T instance) +vchiq_instance_get_use_count(struct vchiq_instance *instance) { struct vchiq_service *service; int use_count = 0, i; i = 0; while ((service = next_service_by_instance(instance->state, - instance, &i)) != NULL) { + instance, &i))) { use_count += service->service_use_count; unlock_service(service); } @@ -2932,26 +2932,26 @@ vchiq_instance_get_use_count(VCHIQ_INSTANCE_T instance) } int -vchiq_instance_get_pid(VCHIQ_INSTANCE_T instance) +vchiq_instance_get_pid(struct vchiq_instance *instance) { return instance->pid; } int -vchiq_instance_get_trace(VCHIQ_INSTANCE_T instance) +vchiq_instance_get_trace(struct vchiq_instance *instance) { return instance->trace; } void -vchiq_instance_set_trace(VCHIQ_INSTANCE_T instance, int trace) +vchiq_instance_set_trace(struct vchiq_instance *instance, int trace) { struct vchiq_service *service; int i; i = 0; while ((service = next_service_by_instance(instance->state, - instance, &i)) != NULL) { + instance, &i))) { service->trace = trace; unlock_service(service); } @@ -2969,10 +2969,10 @@ static void suspend_timer_callback(struct timer_list *t) vchiq_check_suspend(state); } -VCHIQ_STATUS_T -vchiq_use_service(VCHIQ_SERVICE_HANDLE_T handle) +enum vchiq_status +vchiq_use_service(unsigned int handle) { - VCHIQ_STATUS_T ret = VCHIQ_ERROR; + enum vchiq_status ret = VCHIQ_ERROR; struct vchiq_service *service = find_service_by_handle(handle); if (service) { @@ -2983,10 +2983,10 @@ vchiq_use_service(VCHIQ_SERVICE_HANDLE_T handle) return ret; } -VCHIQ_STATUS_T -vchiq_release_service(VCHIQ_SERVICE_HANDLE_T handle) +enum vchiq_status +vchiq_release_service(unsigned int handle) { - VCHIQ_STATUS_T ret = VCHIQ_ERROR; + enum vchiq_status ret = VCHIQ_ERROR; struct vchiq_service *service = find_service_by_handle(handle); if (service) { @@ -3088,11 +3088,11 @@ vchiq_dump_service_use_state(struct vchiq_state *state) vchiq_dump_platform_use_state(state); } -VCHIQ_STATUS_T +enum vchiq_status vchiq_check_service(struct vchiq_service *service) { struct vchiq_arm_state *arm_state; - VCHIQ_STATUS_T ret = VCHIQ_ERROR; + enum vchiq_status ret = VCHIQ_ERROR; if (!service || !service->state) goto out; @@ -3128,8 +3128,8 @@ void vchiq_on_remote_use_active(struct vchiq_state *state) } void vchiq_platform_conn_state_changed(struct vchiq_state *state, - VCHIQ_CONNSTATE_T oldstate, - VCHIQ_CONNSTATE_T newstate) + enum vchiq_connstate oldstate, + enum vchiq_connstate newstate) { struct vchiq_arm_state *arm_state = vchiq_platform_get_arm_state(state); diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h index b424323e9613..19d2a2eefb6a 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h @@ -109,13 +109,13 @@ int vchiq_platform_init(struct platform_device *pdev, extern struct vchiq_state * vchiq_get_state(void); -extern VCHIQ_STATUS_T +extern enum vchiq_status vchiq_arm_vcsuspend(struct vchiq_state *state); -extern VCHIQ_STATUS_T +extern enum vchiq_status vchiq_arm_vcresume(struct vchiq_state *state); -extern VCHIQ_STATUS_T +extern enum vchiq_status vchiq_arm_init_state(struct vchiq_state *state, struct vchiq_arm_state *arm_state); @@ -124,16 +124,16 @@ vchiq_check_resume(struct vchiq_state *state); extern void vchiq_check_suspend(struct vchiq_state *state); -VCHIQ_STATUS_T -vchiq_use_service(VCHIQ_SERVICE_HANDLE_T handle); +enum vchiq_status +vchiq_use_service(unsigned int handle); -extern VCHIQ_STATUS_T -vchiq_release_service(VCHIQ_SERVICE_HANDLE_T handle); +extern enum vchiq_status +vchiq_release_service(unsigned int handle); -extern VCHIQ_STATUS_T +extern enum vchiq_status vchiq_check_service(struct vchiq_service *service); -extern VCHIQ_STATUS_T +extern enum vchiq_status vchiq_platform_suspend(struct vchiq_state *state); extern int @@ -154,27 +154,27 @@ vchiq_platform_get_arm_state(struct vchiq_state *state); extern int vchiq_videocore_wanted(struct vchiq_state *state); -extern VCHIQ_STATUS_T +extern enum vchiq_status vchiq_use_internal(struct vchiq_state *state, struct vchiq_service *service, enum USE_TYPE_E use_type); -extern VCHIQ_STATUS_T +extern enum vchiq_status vchiq_release_internal(struct vchiq_state *state, struct vchiq_service *service); extern struct vchiq_debugfs_node * -vchiq_instance_get_debugfs_node(VCHIQ_INSTANCE_T instance); +vchiq_instance_get_debugfs_node(struct vchiq_instance *instance); extern int -vchiq_instance_get_use_count(VCHIQ_INSTANCE_T instance); +vchiq_instance_get_use_count(struct vchiq_instance *instance); extern int -vchiq_instance_get_pid(VCHIQ_INSTANCE_T instance); +vchiq_instance_get_pid(struct vchiq_instance *instance); extern int -vchiq_instance_get_trace(VCHIQ_INSTANCE_T instance); +vchiq_instance_get_trace(struct vchiq_instance *instance); extern void -vchiq_instance_set_trace(VCHIQ_INSTANCE_T instance, int trace); +vchiq_instance_set_trace(struct vchiq_instance *instance, int trace); extern void set_suspend_state(struct vchiq_arm_state *arm_state, diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c index 56a23a297fa4..b9d94f6b9bef 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c @@ -132,7 +132,7 @@ vchiq_set_service_state(struct vchiq_service *service, int newstate) } struct vchiq_service * -find_service_by_handle(VCHIQ_SERVICE_HANDLE_T handle) +find_service_by_handle(unsigned int handle) { struct vchiq_service *service; @@ -177,8 +177,8 @@ find_service_by_port(struct vchiq_state *state, int localport) } struct vchiq_service * -find_service_for_instance(VCHIQ_INSTANCE_T instance, - VCHIQ_SERVICE_HANDLE_T handle) +find_service_for_instance(struct vchiq_instance *instance, + unsigned int handle) { struct vchiq_service *service; @@ -201,8 +201,8 @@ find_service_for_instance(VCHIQ_INSTANCE_T instance, } struct vchiq_service * -find_closed_service_for_instance(VCHIQ_INSTANCE_T instance, - VCHIQ_SERVICE_HANDLE_T handle) +find_closed_service_for_instance(struct vchiq_instance *instance, + unsigned int handle) { struct vchiq_service *service; @@ -227,7 +227,7 @@ find_closed_service_for_instance(VCHIQ_INSTANCE_T instance, } struct vchiq_service * -next_service_by_instance(struct vchiq_state *state, VCHIQ_INSTANCE_T instance, +next_service_by_instance(struct vchiq_state *state, struct vchiq_instance *instance, int *pidx) { struct vchiq_service *service = NULL; @@ -295,7 +295,7 @@ unlock: } int -vchiq_get_client_id(VCHIQ_SERVICE_HANDLE_T handle) +vchiq_get_client_id(unsigned int handle) { struct vchiq_service *service = find_service_by_handle(handle); int id; @@ -308,7 +308,7 @@ vchiq_get_client_id(VCHIQ_SERVICE_HANDLE_T handle) } void * -vchiq_get_service_userdata(VCHIQ_SERVICE_HANDLE_T handle) +vchiq_get_service_userdata(unsigned int handle) { struct vchiq_service *service = handle_to_service(handle); @@ -316,7 +316,7 @@ vchiq_get_service_userdata(VCHIQ_SERVICE_HANDLE_T handle) } int -vchiq_get_service_fourcc(VCHIQ_SERVICE_HANDLE_T handle) +vchiq_get_service_fourcc(unsigned int handle) { struct vchiq_service *service = handle_to_service(handle); @@ -354,11 +354,11 @@ mark_service_closing(struct vchiq_service *service) mark_service_closing_internal(service, 0); } -static inline VCHIQ_STATUS_T -make_service_callback(struct vchiq_service *service, VCHIQ_REASON_T reason, +static inline enum vchiq_status +make_service_callback(struct vchiq_service *service, enum vchiq_reason reason, struct vchiq_header *header, void *bulk_userdata) { - VCHIQ_STATUS_T status; + enum vchiq_status status; vchiq_log_trace(vchiq_core_log_level, "%d: callback:%d (%s, %pK, %pK)", service->state->id, service->localport, reason_names[reason], @@ -375,9 +375,9 @@ make_service_callback(struct vchiq_service *service, VCHIQ_REASON_T reason, } inline void -vchiq_set_conn_state(struct vchiq_state *state, VCHIQ_CONNSTATE_T newstate) +vchiq_set_conn_state(struct vchiq_state *state, enum vchiq_connstate newstate) { - VCHIQ_CONNSTATE_T oldstate = state->conn_state; + enum vchiq_connstate oldstate = state->conn_state; vchiq_log_info(vchiq_core_log_level, "%d: %s->%s", state->id, conn_state_names[oldstate], @@ -542,7 +542,7 @@ reserve_space(struct vchiq_state *state, size_t space, int is_blocking) if (space > slot_space) { struct vchiq_header *header; /* Fill the remaining space with padding */ - WARN_ON(state->tx_data == NULL); + WARN_ON(!state->tx_data); header = (struct vchiq_header *) (state->tx_data + (tx_pos & VCHIQ_SLOT_MASK)); header->msgid = VCHIQ_MSGID_PADDING; @@ -779,7 +779,7 @@ copy_message_data( } /* Called by the slot handler and application threads */ -static VCHIQ_STATUS_T +static enum vchiq_status queue_message(struct vchiq_state *state, struct vchiq_service *service, int msgid, ssize_t (*copy_callback)(void *context, void *dest, @@ -1027,7 +1027,7 @@ queue_message(struct vchiq_state *state, struct vchiq_service *service, } /* Called by the slot handler and application threads */ -static VCHIQ_STATUS_T +static enum vchiq_status queue_message_sync(struct vchiq_state *state, struct vchiq_service *service, int msgid, ssize_t (*copy_callback)(void *context, void *dest, @@ -1178,11 +1178,11 @@ release_slot(struct vchiq_state *state, struct vchiq_slot_info *slot_info, } /* Called by the slot handler - don't hold the bulk mutex */ -static VCHIQ_STATUS_T +static enum vchiq_status notify_bulks(struct vchiq_service *service, struct vchiq_bulk_queue *queue, int retry_poll) { - VCHIQ_STATUS_T status = VCHIQ_SUCCESS; + enum vchiq_status status = VCHIQ_SUCCESS; vchiq_log_trace(vchiq_core_log_level, "%d: nb:%d %cx - p=%x rn=%x r=%x", @@ -1230,7 +1230,7 @@ notify_bulks(struct vchiq_service *service, struct vchiq_bulk_queue *queue, spin_unlock(&bulk_waiter_spinlock); } else if (bulk->mode == VCHIQ_BULK_MODE_CALLBACK) { - VCHIQ_REASON_T reason = (bulk->dir == + enum vchiq_reason reason = (bulk->dir == VCHIQ_BULK_TRANSMIT) ? ((bulk->actual == VCHIQ_BULK_ACTUAL_ABORTED) ? @@ -2078,7 +2078,7 @@ init_bulk_queue(struct vchiq_bulk_queue *queue) } inline const char * -get_conn_state_name(VCHIQ_CONNSTATE_T conn_state) +get_conn_state_name(enum vchiq_connstate conn_state) { return conn_state_names[conn_state]; } @@ -2123,18 +2123,15 @@ vchiq_init_slots(void *mem_base, int mem_size) return slot_zero; } -VCHIQ_STATUS_T +enum vchiq_status vchiq_init_state(struct vchiq_state *state, struct vchiq_slot_zero *slot_zero) { struct vchiq_shared_state *local; struct vchiq_shared_state *remote; - VCHIQ_STATUS_T status; + enum vchiq_status status; char threadname[16]; int i; - vchiq_log_warning(vchiq_core_log_level, - "%s: slot_zero = %pK", __func__, slot_zero); - if (vchiq_states[0]) { pr_err("%s: VCHIQ state already initialized\n", __func__); return VCHIQ_ERROR; @@ -2283,8 +2280,8 @@ fail_free_handler_thread: struct vchiq_service * vchiq_add_service_internal(struct vchiq_state *state, const struct vchiq_service_params *params, - int srvstate, VCHIQ_INSTANCE_T instance, - VCHIQ_USERDATA_TERM_T userdata_term) + int srvstate, struct vchiq_instance *instance, + vchiq_userdata_term userdata_term) { struct vchiq_service *service; struct vchiq_service **pservice = NULL; @@ -2412,7 +2409,7 @@ vchiq_add_service_internal(struct vchiq_state *state, return service; } -VCHIQ_STATUS_T +enum vchiq_status vchiq_open_service_internal(struct vchiq_service *service, int client_id) { struct vchiq_open_payload payload = { @@ -2421,7 +2418,7 @@ vchiq_open_service_internal(struct vchiq_service *service, int client_id) service->version, service->version_min }; - VCHIQ_STATUS_T status = VCHIQ_SUCCESS; + enum vchiq_status status = VCHIQ_SUCCESS; service->client_id = client_id; vchiq_use_service_internal(service); @@ -2519,7 +2516,7 @@ release_service_messages(struct vchiq_service *service) static int do_abort_bulks(struct vchiq_service *service) { - VCHIQ_STATUS_T status; + enum vchiq_status status; /* Abort any outstanding bulk transfers */ if (mutex_lock_killable(&service->bulk_mutex)) @@ -2535,10 +2532,10 @@ do_abort_bulks(struct vchiq_service *service) return (status == VCHIQ_SUCCESS); } -static VCHIQ_STATUS_T +static enum vchiq_status close_service_complete(struct vchiq_service *service, int failstate) { - VCHIQ_STATUS_T status; + enum vchiq_status status; int is_server = (service->public_fourcc != VCHIQ_FOURCC_INVALID); int newstate; @@ -2597,11 +2594,11 @@ close_service_complete(struct vchiq_service *service, int failstate) } /* Called by the slot handler */ -VCHIQ_STATUS_T +enum vchiq_status vchiq_close_service_internal(struct vchiq_service *service, int close_recvd) { struct vchiq_state *state = service->state; - VCHIQ_STATUS_T status = VCHIQ_SUCCESS; + enum vchiq_status status = VCHIQ_SUCCESS; int is_server = (service->public_fourcc != VCHIQ_FOURCC_INVALID); vchiq_log_info(vchiq_core_log_level, "%d: csi:%d,%d (%s)", @@ -2777,8 +2774,8 @@ vchiq_free_service_internal(struct vchiq_service *service) unlock_service(service); } -VCHIQ_STATUS_T -vchiq_connect_internal(struct vchiq_state *state, VCHIQ_INSTANCE_T instance) +enum vchiq_status +vchiq_connect_internal(struct vchiq_state *state, struct vchiq_instance *instance) { struct vchiq_service *service; int i; @@ -2813,8 +2810,8 @@ vchiq_connect_internal(struct vchiq_state *state, VCHIQ_INSTANCE_T instance) return VCHIQ_SUCCESS; } -VCHIQ_STATUS_T -vchiq_shutdown_internal(struct vchiq_state *state, VCHIQ_INSTANCE_T instance) +enum vchiq_status +vchiq_shutdown_internal(struct vchiq_state *state, struct vchiq_instance *instance) { struct vchiq_service *service; int i; @@ -2830,12 +2827,12 @@ vchiq_shutdown_internal(struct vchiq_state *state, VCHIQ_INSTANCE_T instance) return VCHIQ_SUCCESS; } -VCHIQ_STATUS_T -vchiq_close_service(VCHIQ_SERVICE_HANDLE_T handle) +enum vchiq_status +vchiq_close_service(unsigned int handle) { /* Unregister the service */ struct vchiq_service *service = find_service_by_handle(handle); - VCHIQ_STATUS_T status = VCHIQ_SUCCESS; + enum vchiq_status status = VCHIQ_SUCCESS; if (!service) return VCHIQ_ERROR; @@ -2889,12 +2886,12 @@ vchiq_close_service(VCHIQ_SERVICE_HANDLE_T handle) return status; } -VCHIQ_STATUS_T -vchiq_remove_service(VCHIQ_SERVICE_HANDLE_T handle) +enum vchiq_status +vchiq_remove_service(unsigned int handle) { /* Unregister the service */ struct vchiq_service *service = find_service_by_handle(handle); - VCHIQ_STATUS_T status = VCHIQ_SUCCESS; + enum vchiq_status status = VCHIQ_SUCCESS; if (!service) return VCHIQ_ERROR; @@ -2955,10 +2952,10 @@ vchiq_remove_service(VCHIQ_SERVICE_HANDLE_T handle) * When called in blocking mode, the userdata field points to a bulk_waiter * structure. */ -VCHIQ_STATUS_T vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, +enum vchiq_status vchiq_bulk_transfer(unsigned int handle, void *offset, int size, void *userdata, - VCHIQ_BULK_MODE_T mode, - VCHIQ_BULK_DIR_T dir) + enum vchiq_bulk_mode mode, + enum vchiq_bulk_dir dir) { struct vchiq_service *service = find_service_by_handle(handle); struct vchiq_bulk_queue *queue; @@ -2968,7 +2965,7 @@ VCHIQ_STATUS_T vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, const char dir_char = (dir == VCHIQ_BULK_TRANSMIT) ? 't' : 'r'; const int dir_msgtype = (dir == VCHIQ_BULK_TRANSMIT) ? VCHIQ_MSG_BULK_TX : VCHIQ_MSG_BULK_RX; - VCHIQ_STATUS_T status = VCHIQ_ERROR; + enum vchiq_status status = VCHIQ_ERROR; int payload[2]; if (!service || service->srvstate != VCHIQ_SRVSTATE_OPEN || @@ -3103,15 +3100,15 @@ error_exit: return status; } -VCHIQ_STATUS_T -vchiq_queue_message(VCHIQ_SERVICE_HANDLE_T handle, +enum vchiq_status +vchiq_queue_message(unsigned int handle, ssize_t (*copy_callback)(void *context, void *dest, size_t offset, size_t maxsize), void *context, size_t size) { struct vchiq_service *service = find_service_by_handle(handle); - VCHIQ_STATUS_T status = VCHIQ_ERROR; + enum vchiq_status status = VCHIQ_ERROR; if (!service || (vchiq_check_service(service) != VCHIQ_SUCCESS)) @@ -3156,7 +3153,7 @@ error_exit: } void -vchiq_release_message(VCHIQ_SERVICE_HANDLE_T handle, +vchiq_release_message(unsigned int handle, struct vchiq_header *header) { struct vchiq_service *service = find_service_by_handle(handle); @@ -3195,10 +3192,10 @@ release_message_sync(struct vchiq_state *state, struct vchiq_header *header) remote_event_signal(&state->remote->sync_release); } -VCHIQ_STATUS_T -vchiq_get_peer_version(VCHIQ_SERVICE_HANDLE_T handle, short *peer_version) +enum vchiq_status +vchiq_get_peer_version(unsigned int handle, short *peer_version) { - VCHIQ_STATUS_T status = VCHIQ_ERROR; + enum vchiq_status status = VCHIQ_ERROR; struct vchiq_service *service = find_service_by_handle(handle); if (!service || @@ -3224,12 +3221,12 @@ void vchiq_get_config(struct vchiq_config *config) config->version_min = VCHIQ_VERSION_MIN; } -VCHIQ_STATUS_T -vchiq_set_service_option(VCHIQ_SERVICE_HANDLE_T handle, - VCHIQ_SERVICE_OPTION_T option, int value) +enum vchiq_status +vchiq_set_service_option(unsigned int handle, + enum vchiq_service_option option, int value) { struct vchiq_service *service = find_service_by_handle(handle); - VCHIQ_STATUS_T status = VCHIQ_ERROR; + enum vchiq_status status = VCHIQ_ERROR; if (service) { switch (option) { @@ -3527,9 +3524,9 @@ vchiq_loud_error_footer(void) "================"); } -VCHIQ_STATUS_T vchiq_send_remote_use(struct vchiq_state *state) +enum vchiq_status vchiq_send_remote_use(struct vchiq_state *state) { - VCHIQ_STATUS_T status = VCHIQ_RETRY; + enum vchiq_status status = VCHIQ_RETRY; if (state->conn_state != VCHIQ_CONNSTATE_DISCONNECTED) status = queue_message(state, NULL, @@ -3538,9 +3535,9 @@ VCHIQ_STATUS_T vchiq_send_remote_use(struct vchiq_state *state) return status; } -VCHIQ_STATUS_T vchiq_send_remote_use_active(struct vchiq_state *state) +enum vchiq_status vchiq_send_remote_use_active(struct vchiq_state *state) { - VCHIQ_STATUS_T status = VCHIQ_RETRY; + enum vchiq_status status = VCHIQ_RETRY; if (state->conn_state != VCHIQ_CONNSTATE_DISCONNECTED) status = queue_message(state, NULL, @@ -3578,7 +3575,7 @@ void vchiq_log_dump_mem(const char *label, u32 addr, const void *void_mem, } *s++ = '\0'; - if ((label != NULL) && (*label != '\0')) + if (label && (*label != '\0')) vchiq_log_trace(VCHIQ_LOG_TRACE, "%s: %08x: %s", label, addr, line_buf); else diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h index 63f71b2a492f..419bcdd165b4 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h @@ -60,8 +60,8 @@ vchiq_static_assert(IS_POW2(VCHIQ_MAX_SLOTS_PER_SIDE)); #define VCHIQ_SLOT_MASK (VCHIQ_SLOT_SIZE - 1) #define VCHIQ_SLOT_QUEUE_MASK (VCHIQ_MAX_SLOTS_PER_SIDE - 1) -#define VCHIQ_SLOT_ZERO_SLOTS ((sizeof(struct vchiq_slot_zero) + \ - VCHIQ_SLOT_SIZE - 1) / VCHIQ_SLOT_SIZE) +#define VCHIQ_SLOT_ZERO_SLOTS DIV_ROUND_UP(sizeof(struct vchiq_slot_zero), \ + VCHIQ_SLOT_SIZE) #define VCHIQ_MSG_PADDING 0 /* - */ #define VCHIQ_MSG_CONNECT 1 /* - */ @@ -169,7 +169,7 @@ enum { #endif /* VCHIQ_ENABLE_DEBUG */ -typedef enum { +enum vchiq_connstate { VCHIQ_CONNSTATE_DISCONNECTED, VCHIQ_CONNSTATE_CONNECTING, VCHIQ_CONNSTATE_CONNECTED, @@ -179,7 +179,7 @@ typedef enum { VCHIQ_CONNSTATE_RESUMING, VCHIQ_CONNSTATE_PAUSE_TIMEOUT, VCHIQ_CONNSTATE_RESUME_TIMEOUT -} VCHIQ_CONNSTATE_T; +}; enum { VCHIQ_SRVSTATE_FREE, @@ -202,12 +202,12 @@ enum { VCHIQ_POLL_COUNT }; -typedef enum { +enum vchiq_bulk_dir { VCHIQ_BULK_TRANSMIT, VCHIQ_BULK_RECEIVE -} VCHIQ_BULK_DIR_T; +}; -typedef void (*VCHIQ_USERDATA_TERM_T)(void *userdata); +typedef void (*vchiq_userdata_term)(void *userdata); struct vchiq_bulk { short mode; @@ -236,7 +236,7 @@ struct remote_event { u32 __unused; }; -typedef struct opaque_platform_state_t *VCHIQ_PLATFORM_STATE_T; +struct opaque_platform_state; struct vchiq_slot { char data[VCHIQ_SLOT_SIZE]; @@ -250,10 +250,10 @@ struct vchiq_slot_info { struct vchiq_service { struct vchiq_service_base base; - VCHIQ_SERVICE_HANDLE_T handle; + unsigned int handle; unsigned int ref_count; int srvstate; - VCHIQ_USERDATA_TERM_T userdata_term; + vchiq_userdata_term userdata_term; unsigned int localport; unsigned int remoteport; int public_fourcc; @@ -268,7 +268,7 @@ struct vchiq_service { short peer_version; struct vchiq_state *state; - VCHIQ_INSTANCE_T instance; + struct vchiq_instance *instance; int service_use_count; @@ -367,7 +367,7 @@ struct vchiq_slot_zero { struct vchiq_state { int id; int initialised; - VCHIQ_CONNSTATE_T conn_state; + enum vchiq_connstate conn_state; short version_common; struct vchiq_shared_state *local; @@ -382,7 +382,7 @@ struct vchiq_state { /* Mutex protecting services */ struct mutex mutex; - VCHIQ_INSTANCE_T *instance; + struct vchiq_instance **instance; /* Processes incoming messages */ struct task_struct *slot_handler_thread; @@ -468,7 +468,7 @@ struct vchiq_state { struct vchiq_service_quota service_quotas[VCHIQ_MAX_SERVICES]; struct vchiq_slot_info slot_info[VCHIQ_MAX_SLOTS]; - VCHIQ_PLATFORM_STATE_T platform_state; + struct opaque_platform_state *platform_state; }; struct bulk_waiter { @@ -486,27 +486,27 @@ extern int vchiq_sync_log_level; extern struct vchiq_state *vchiq_states[VCHIQ_MAX_STATES]; extern const char * -get_conn_state_name(VCHIQ_CONNSTATE_T conn_state); +get_conn_state_name(enum vchiq_connstate conn_state); extern struct vchiq_slot_zero * vchiq_init_slots(void *mem_base, int mem_size); -extern VCHIQ_STATUS_T +extern enum vchiq_status vchiq_init_state(struct vchiq_state *state, struct vchiq_slot_zero *slot_zero); -extern VCHIQ_STATUS_T -vchiq_connect_internal(struct vchiq_state *state, VCHIQ_INSTANCE_T instance); +extern enum vchiq_status +vchiq_connect_internal(struct vchiq_state *state, struct vchiq_instance *instance); extern struct vchiq_service * vchiq_add_service_internal(struct vchiq_state *state, const struct vchiq_service_params *params, - int srvstate, VCHIQ_INSTANCE_T instance, - VCHIQ_USERDATA_TERM_T userdata_term); + int srvstate, struct vchiq_instance *instance, + vchiq_userdata_term userdata_term); -extern VCHIQ_STATUS_T +extern enum vchiq_status vchiq_open_service_internal(struct vchiq_service *service, int client_id); -extern VCHIQ_STATUS_T +extern enum vchiq_status vchiq_close_service_internal(struct vchiq_service *service, int close_recvd); extern void @@ -515,16 +515,16 @@ vchiq_terminate_service_internal(struct vchiq_service *service); extern void vchiq_free_service_internal(struct vchiq_service *service); -extern VCHIQ_STATUS_T -vchiq_shutdown_internal(struct vchiq_state *state, VCHIQ_INSTANCE_T instance); +extern enum vchiq_status +vchiq_shutdown_internal(struct vchiq_state *state, struct vchiq_instance *instance); extern void remote_event_pollall(struct vchiq_state *state); -extern VCHIQ_STATUS_T -vchiq_bulk_transfer(VCHIQ_SERVICE_HANDLE_T handle, void *offset, int size, - void *userdata, VCHIQ_BULK_MODE_T mode, - VCHIQ_BULK_DIR_T dir); +extern enum vchiq_status +vchiq_bulk_transfer(unsigned int handle, void *offset, int size, + void *userdata, enum vchiq_bulk_mode mode, + enum vchiq_bulk_dir dir); extern void vchiq_dump_state(void *dump_context, struct vchiq_state *state); @@ -543,7 +543,7 @@ request_poll(struct vchiq_state *state, struct vchiq_service *service, int poll_type); static inline struct vchiq_service * -handle_to_service(VCHIQ_SERVICE_HANDLE_T handle) +handle_to_service(unsigned int handle) { struct vchiq_state *state = vchiq_states[(handle / VCHIQ_MAX_SERVICES) & (VCHIQ_MAX_STATES - 1)]; @@ -554,21 +554,21 @@ handle_to_service(VCHIQ_SERVICE_HANDLE_T handle) } extern struct vchiq_service * -find_service_by_handle(VCHIQ_SERVICE_HANDLE_T handle); +find_service_by_handle(unsigned int handle); extern struct vchiq_service * find_service_by_port(struct vchiq_state *state, int localport); extern struct vchiq_service * -find_service_for_instance(VCHIQ_INSTANCE_T instance, - VCHIQ_SERVICE_HANDLE_T handle); +find_service_for_instance(struct vchiq_instance *instance, + unsigned int handle); extern struct vchiq_service * -find_closed_service_for_instance(VCHIQ_INSTANCE_T instance, - VCHIQ_SERVICE_HANDLE_T handle); +find_closed_service_for_instance(struct vchiq_instance *instance, + unsigned int handle); extern struct vchiq_service * -next_service_by_instance(struct vchiq_state *state, VCHIQ_INSTANCE_T instance, +next_service_by_instance(struct vchiq_state *state, struct vchiq_instance *instance, int *pidx); extern void @@ -580,7 +580,7 @@ unlock_service(struct vchiq_service *service); /* The following functions are called from vchiq_core, and external ** implementations must be provided. */ -extern VCHIQ_STATUS_T +extern enum vchiq_status vchiq_prepare_bulk_data(struct vchiq_bulk *bulk, void *offset, int size, int dir); @@ -596,7 +596,7 @@ vchiq_platform_check_suspend(struct vchiq_state *state); extern void vchiq_platform_paused(struct vchiq_state *state); -extern VCHIQ_STATUS_T +extern enum vchiq_status vchiq_platform_resume(struct vchiq_state *state); extern void @@ -615,10 +615,10 @@ extern void vchiq_dump_platform_service_state(void *dump_context, struct vchiq_service *service); -extern VCHIQ_STATUS_T +extern enum vchiq_status vchiq_use_service_internal(struct vchiq_service *service); -extern VCHIQ_STATUS_T +extern enum vchiq_status vchiq_release_service_internal(struct vchiq_service *service); extern void @@ -627,31 +627,31 @@ vchiq_on_remote_use(struct vchiq_state *state); extern void vchiq_on_remote_release(struct vchiq_state *state); -extern VCHIQ_STATUS_T +extern enum vchiq_status vchiq_platform_init_state(struct vchiq_state *state); -extern VCHIQ_STATUS_T +extern enum vchiq_status vchiq_check_service(struct vchiq_service *service); extern void vchiq_on_remote_use_active(struct vchiq_state *state); -extern VCHIQ_STATUS_T +extern enum vchiq_status vchiq_send_remote_use(struct vchiq_state *state); -extern VCHIQ_STATUS_T +extern enum vchiq_status vchiq_send_remote_use_active(struct vchiq_state *state); extern void vchiq_platform_conn_state_changed(struct vchiq_state *state, - VCHIQ_CONNSTATE_T oldstate, - VCHIQ_CONNSTATE_T newstate); + enum vchiq_connstate oldstate, + enum vchiq_connstate newstate); extern void vchiq_platform_handle_timeout(struct vchiq_state *state); extern void -vchiq_set_conn_state(struct vchiq_state *state, VCHIQ_CONNSTATE_T newstate); +vchiq_set_conn_state(struct vchiq_state *state, enum vchiq_connstate newstate); extern void vchiq_log_dump_mem(const char *label, uint32_t addr, const void *voidMem, diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c index f217b78d95a0..89cc52211de4 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.c @@ -117,7 +117,7 @@ static const struct file_operations debugfs_log_fops = { static int debugfs_usecount_show(struct seq_file *f, void *offset) { - VCHIQ_INSTANCE_T instance = f->private; + struct vchiq_instance *instance = f->private; int use_count; use_count = vchiq_instance_get_use_count(instance); @@ -129,7 +129,7 @@ DEFINE_SHOW_ATTRIBUTE(debugfs_usecount); static int debugfs_trace_show(struct seq_file *f, void *offset) { - VCHIQ_INSTANCE_T instance = f->private; + struct vchiq_instance *instance = f->private; int trace; trace = vchiq_instance_get_trace(instance); @@ -148,7 +148,7 @@ static ssize_t debugfs_trace_write(struct file *file, size_t count, loff_t *ppos) { struct seq_file *f = (struct seq_file *)file->private_data; - VCHIQ_INSTANCE_T instance = f->private; + struct vchiq_instance *instance = f->private; char firstchar; if (copy_from_user(&firstchar, buffer, 1)) @@ -184,7 +184,7 @@ static const struct file_operations debugfs_trace_fops = { }; /* add an instance (process) to the debugfs entries */ -void vchiq_debugfs_add_instance(VCHIQ_INSTANCE_T instance) +void vchiq_debugfs_add_instance(struct vchiq_instance *instance) { char pidstr[16]; struct dentry *top; @@ -201,7 +201,7 @@ void vchiq_debugfs_add_instance(VCHIQ_INSTANCE_T instance) vchiq_instance_get_debugfs_node(instance)->dentry = top; } -void vchiq_debugfs_remove_instance(VCHIQ_INSTANCE_T instance) +void vchiq_debugfs_remove_instance(struct vchiq_instance *instance) { struct vchiq_debugfs_node *node = vchiq_instance_get_debugfs_node(instance); @@ -242,11 +242,11 @@ void vchiq_debugfs_deinit(void) { } -void vchiq_debugfs_add_instance(VCHIQ_INSTANCE_T instance) +void vchiq_debugfs_add_instance(struct vchiq_instance *instance) { } -void vchiq_debugfs_remove_instance(VCHIQ_INSTANCE_T instance) +void vchiq_debugfs_remove_instance(struct vchiq_instance *instance) { } diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.h index 9b563d105fdb..ec2f033cdf32 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_debugfs.h @@ -14,8 +14,8 @@ void vchiq_debugfs_init(void); void vchiq_debugfs_deinit(void); -void vchiq_debugfs_add_instance(VCHIQ_INSTANCE_T instance); +void vchiq_debugfs_add_instance(struct vchiq_instance *instance); -void vchiq_debugfs_remove_instance(VCHIQ_INSTANCE_T instance); +void vchiq_debugfs_remove_instance(struct vchiq_instance *instance); #endif /* VCHIQ_DEBUGFS_H */ diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_if.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_if.h index c23bd105c40f..07c6a3db5ab6 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_if.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_if.h @@ -15,7 +15,7 @@ #define VCHIQ_GET_SERVICE_USERDATA(service) vchiq_get_service_userdata(service) #define VCHIQ_GET_SERVICE_FOURCC(service) vchiq_get_service_fourcc(service) -typedef enum { +enum vchiq_reason { VCHIQ_SERVICE_OPENED, /* service, -, - */ VCHIQ_SERVICE_CLOSED, /* service, -, - */ VCHIQ_MESSAGE_AVAILABLE, /* service, header, - */ @@ -23,28 +23,28 @@ typedef enum { VCHIQ_BULK_RECEIVE_DONE, /* service, -, bulk_userdata */ VCHIQ_BULK_TRANSMIT_ABORTED, /* service, -, bulk_userdata */ VCHIQ_BULK_RECEIVE_ABORTED /* service, -, bulk_userdata */ -} VCHIQ_REASON_T; +}; -typedef enum { +enum vchiq_status { VCHIQ_ERROR = -1, VCHIQ_SUCCESS = 0, VCHIQ_RETRY = 1 -} VCHIQ_STATUS_T; +}; -typedef enum { +enum vchiq_bulk_mode { VCHIQ_BULK_MODE_CALLBACK, VCHIQ_BULK_MODE_BLOCKING, VCHIQ_BULK_MODE_NOCALLBACK, VCHIQ_BULK_MODE_WAITING /* Reserved for internal use */ -} VCHIQ_BULK_MODE_T; +}; -typedef enum { +enum vchiq_service_option { VCHIQ_SERVICE_OPTION_AUTOCLOSE, VCHIQ_SERVICE_OPTION_SLOT_QUOTA, VCHIQ_SERVICE_OPTION_MESSAGE_QUOTA, VCHIQ_SERVICE_OPTION_SYNCHRONOUS, VCHIQ_SERVICE_OPTION_TRACE -} VCHIQ_SERVICE_OPTION_T; +}; struct vchiq_header { /* The message identifier - opaque to applications. */ @@ -61,21 +61,19 @@ struct vchiq_element { unsigned int size; }; -typedef unsigned int VCHIQ_SERVICE_HANDLE_T; - -typedef VCHIQ_STATUS_T (*VCHIQ_CALLBACK_T)(VCHIQ_REASON_T, - struct vchiq_header *, - VCHIQ_SERVICE_HANDLE_T, void *); +typedef enum vchiq_status (*vchiq_callback)(enum vchiq_reason, + struct vchiq_header *, + unsigned int, void *); struct vchiq_service_base { int fourcc; - VCHIQ_CALLBACK_T callback; + vchiq_callback callback; void *userdata; }; struct vchiq_service_params { int fourcc; - VCHIQ_CALLBACK_T callback; + vchiq_callback callback; void *userdata; short version; /* Increment for non-trivial changes */ short version_min; /* Update for incompatible changes */ @@ -92,57 +90,57 @@ struct vchiq_config { short version_min; /* The minimum compatible version of VCHIQ */ }; -typedef struct vchiq_instance_struct *VCHIQ_INSTANCE_T; -typedef void (*VCHIQ_REMOTE_USE_CALLBACK_T)(void *cb_arg); +struct vchiq_instance; +typedef void (*vchiq_remote_callback)(void *cb_arg); -extern VCHIQ_STATUS_T vchiq_initialise(VCHIQ_INSTANCE_T *pinstance); -extern VCHIQ_STATUS_T vchiq_shutdown(VCHIQ_INSTANCE_T instance); -extern VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance); -extern VCHIQ_STATUS_T vchiq_add_service(VCHIQ_INSTANCE_T instance, +extern enum vchiq_status vchiq_initialise(struct vchiq_instance **pinstance); +extern enum vchiq_status vchiq_shutdown(struct vchiq_instance *instance); +extern enum vchiq_status vchiq_connect(struct vchiq_instance *instance); +extern enum vchiq_status vchiq_add_service(struct vchiq_instance *instance, const struct vchiq_service_params *params, - VCHIQ_SERVICE_HANDLE_T *pservice); -extern VCHIQ_STATUS_T vchiq_open_service(VCHIQ_INSTANCE_T instance, + unsigned int *pservice); +extern enum vchiq_status vchiq_open_service(struct vchiq_instance *instance, const struct vchiq_service_params *params, - VCHIQ_SERVICE_HANDLE_T *pservice); -extern VCHIQ_STATUS_T vchiq_close_service(VCHIQ_SERVICE_HANDLE_T service); -extern VCHIQ_STATUS_T vchiq_remove_service(VCHIQ_SERVICE_HANDLE_T service); -extern VCHIQ_STATUS_T vchiq_use_service(VCHIQ_SERVICE_HANDLE_T service); -extern VCHIQ_STATUS_T vchiq_release_service(VCHIQ_SERVICE_HANDLE_T service); -extern VCHIQ_STATUS_T -vchiq_queue_message(VCHIQ_SERVICE_HANDLE_T handle, + unsigned int *pservice); +extern enum vchiq_status vchiq_close_service(unsigned int service); +extern enum vchiq_status vchiq_remove_service(unsigned int service); +extern enum vchiq_status vchiq_use_service(unsigned int service); +extern enum vchiq_status vchiq_release_service(unsigned int service); +extern enum vchiq_status +vchiq_queue_message(unsigned int handle, ssize_t (*copy_callback)(void *context, void *dest, size_t offset, size_t maxsize), void *context, size_t size); -extern void vchiq_release_message(VCHIQ_SERVICE_HANDLE_T service, +extern void vchiq_release_message(unsigned int service, struct vchiq_header *header); -extern VCHIQ_STATUS_T vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T service, +extern enum vchiq_status vchiq_bulk_transmit(unsigned int service, const void *data, unsigned int size, void *userdata, - VCHIQ_BULK_MODE_T mode); -extern VCHIQ_STATUS_T vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T service, + enum vchiq_bulk_mode mode); +extern enum vchiq_status vchiq_bulk_receive(unsigned int service, void *data, unsigned int size, void *userdata, - VCHIQ_BULK_MODE_T mode); -extern VCHIQ_STATUS_T vchiq_bulk_transmit_handle(VCHIQ_SERVICE_HANDLE_T service, + enum vchiq_bulk_mode mode); +extern enum vchiq_status vchiq_bulk_transmit_handle(unsigned int service, const void *offset, unsigned int size, - void *userdata, VCHIQ_BULK_MODE_T mode); -extern VCHIQ_STATUS_T vchiq_bulk_receive_handle(VCHIQ_SERVICE_HANDLE_T service, + void *userdata, enum vchiq_bulk_mode mode); +extern enum vchiq_status vchiq_bulk_receive_handle(unsigned int service, void *offset, unsigned int size, void *userdata, - VCHIQ_BULK_MODE_T mode); -extern int vchiq_get_client_id(VCHIQ_SERVICE_HANDLE_T service); -extern void *vchiq_get_service_userdata(VCHIQ_SERVICE_HANDLE_T service); -extern int vchiq_get_service_fourcc(VCHIQ_SERVICE_HANDLE_T service); + enum vchiq_bulk_mode mode); +extern int vchiq_get_client_id(unsigned int service); +extern void *vchiq_get_service_userdata(unsigned int service); +extern int vchiq_get_service_fourcc(unsigned int service); extern void vchiq_get_config(struct vchiq_config *config); -extern VCHIQ_STATUS_T vchiq_set_service_option(VCHIQ_SERVICE_HANDLE_T service, - VCHIQ_SERVICE_OPTION_T option, int value); +extern enum vchiq_status vchiq_set_service_option(unsigned int service, + enum vchiq_service_option option, int value); -extern VCHIQ_STATUS_T vchiq_remote_use(VCHIQ_INSTANCE_T instance, - VCHIQ_REMOTE_USE_CALLBACK_T callback, void *cb_arg); -extern VCHIQ_STATUS_T vchiq_remote_release(VCHIQ_INSTANCE_T instance); +extern enum vchiq_status vchiq_remote_use(struct vchiq_instance *instance, + vchiq_remote_callback callback, void *cb_arg); +extern enum vchiq_status vchiq_remote_release(struct vchiq_instance *instance); -extern VCHIQ_STATUS_T vchiq_dump_phys_mem(VCHIQ_SERVICE_HANDLE_T service, +extern enum vchiq_status vchiq_dump_phys_mem(unsigned int service, void *ptr, size_t num_bytes); -extern VCHIQ_STATUS_T vchiq_get_peer_version(VCHIQ_SERVICE_HANDLE_T handle, +extern enum vchiq_status vchiq_get_peer_version(unsigned int handle, short *peer_version); #endif /* VCHIQ_IF_H */ diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_ioctl.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_ioctl.h index 460ccea088bf..202889b3774f 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_ioctl.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_ioctl.h @@ -28,11 +28,11 @@ struct vchiq_queue_bulk_transfer { void *data; unsigned int size; void *userdata; - VCHIQ_BULK_MODE_T mode; + enum vchiq_bulk_mode mode; }; struct vchiq_completion_data { - VCHIQ_REASON_T reason; + enum vchiq_reason reason; struct vchiq_header *header; void *service_userdata; void *bulk_userdata; @@ -60,7 +60,7 @@ struct vchiq_get_config { struct vchiq_set_service_option { unsigned int handle; - VCHIQ_SERVICE_OPTION_T option; + enum vchiq_service_option option; int value; }; diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_shim.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_shim.c index 17a4f2c8d8b1..0ce3b08b3441 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_shim.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_shim.c @@ -12,22 +12,22 @@ #define vchiq_status_to_vchi(status) ((int32_t)status) struct shim_service { - VCHIQ_SERVICE_HANDLE_T handle; + unsigned int handle; struct vchiu_queue queue; - VCHI_CALLBACK_T callback; + vchi_callback callback; void *callback_param; }; /*********************************************************** * Name: vchi_msg_peek * - * Arguments: const VCHI_SERVICE_HANDLE_T handle, + * Arguments: struct vchi_service_handle *handle, * void **data, * uint32_t *msg_size, - * VCHI_FLAGS_T flags + * enum vchi_flags flags * * Description: Routine to return a pointer to the current message (to allow in * place processing). The message can be removed using @@ -36,10 +36,10 @@ struct shim_service { * Returns: int32_t - success == 0 * ***********************************************************/ -int32_t vchi_msg_peek(VCHI_SERVICE_HANDLE_T handle, - void **data, - uint32_t *msg_size, - VCHI_FLAGS_T flags) +int32_t vchi_msg_peek(struct vchi_service_handle *handle, + void **data, + uint32_t *msg_size, + enum vchi_flags flags) { struct shim_service *service = (struct shim_service *)handle; struct vchiq_header *header; @@ -63,7 +63,7 @@ EXPORT_SYMBOL(vchi_msg_peek); /*********************************************************** * Name: vchi_msg_remove * - * Arguments: const VCHI_SERVICE_HANDLE_T handle, + * Arguments: struct vchi_service_handle *handle, * * Description: Routine to remove a message (after it has been read with * vchi_msg_peek) @@ -71,7 +71,7 @@ EXPORT_SYMBOL(vchi_msg_peek); * Returns: int32_t - success == 0 * ***********************************************************/ -int32_t vchi_msg_remove(VCHI_SERVICE_HANDLE_T handle) +int32_t vchi_msg_remove(struct vchi_service_handle *handle) { struct shim_service *service = (struct shim_service *)handle; struct vchiq_header *header; @@ -87,7 +87,7 @@ EXPORT_SYMBOL(vchi_msg_remove); /*********************************************************** * Name: vchi_msg_queue * - * Arguments: VCHI_SERVICE_HANDLE_T handle, + * Arguments: struct vchi_service_handle *handle, * ssize_t (*copy_callback)(void *context, void *dest, * size_t offset, size_t maxsize), * void *context, @@ -99,14 +99,14 @@ EXPORT_SYMBOL(vchi_msg_remove); * ***********************************************************/ static -int32_t vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle, +int32_t vchi_msg_queue(struct vchi_service_handle *handle, ssize_t (*copy_callback)(void *context, void *dest, size_t offset, size_t maxsize), void *context, uint32_t data_size) { struct shim_service *service = (struct shim_service *)handle; - VCHIQ_STATUS_T status; + enum vchiq_status status; while (1) { status = vchiq_queue_message(service->handle, @@ -139,7 +139,7 @@ vchi_queue_kernel_message_callback(void *context, } int -vchi_queue_kernel_message(VCHI_SERVICE_HANDLE_T handle, +vchi_queue_kernel_message(struct vchi_service_handle *handle, void *data, unsigned int size) { @@ -169,7 +169,7 @@ vchi_queue_user_message_callback(void *context, } int -vchi_queue_user_message(VCHI_SERVICE_HANDLE_T handle, +vchi_queue_user_message(struct vchi_service_handle *handle, void __user *data, unsigned int size) { @@ -190,7 +190,7 @@ EXPORT_SYMBOL(vchi_queue_user_message); * Arguments: VCHI_BULK_HANDLE_T handle, * void *data_dst, * const uint32_t data_size, - * VCHI_FLAGS_T flags + * enum vchi_flags flags * void *bulk_handle * * Description: Routine to setup a rcv buffer @@ -198,15 +198,13 @@ EXPORT_SYMBOL(vchi_queue_user_message); * Returns: int32_t - success == 0 * ***********************************************************/ -int32_t vchi_bulk_queue_receive(VCHI_SERVICE_HANDLE_T handle, - void *data_dst, - uint32_t data_size, - VCHI_FLAGS_T flags, - void *bulk_handle) +int32_t vchi_bulk_queue_receive(struct vchi_service_handle *handle, void *data_dst, + uint32_t data_size, enum vchi_flags flags, + void *bulk_handle) { struct shim_service *service = (struct shim_service *)handle; - VCHIQ_BULK_MODE_T mode; - VCHIQ_STATUS_T status; + enum vchiq_bulk_mode mode; + enum vchiq_status status; switch ((int)flags) { case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE @@ -250,7 +248,7 @@ EXPORT_SYMBOL(vchi_bulk_queue_receive); * Arguments: VCHI_BULK_HANDLE_T handle, * const void *data_src, * uint32_t data_size, - * VCHI_FLAGS_T flags, + * enum vchi_flags flags, * void *bulk_handle * * Description: Routine to transmit some data @@ -258,15 +256,15 @@ EXPORT_SYMBOL(vchi_bulk_queue_receive); * Returns: int32_t - success == 0 * ***********************************************************/ -int32_t vchi_bulk_queue_transmit(VCHI_SERVICE_HANDLE_T handle, - const void *data_src, - uint32_t data_size, - VCHI_FLAGS_T flags, - void *bulk_handle) +int32_t vchi_bulk_queue_transmit(struct vchi_service_handle *handle, + const void *data_src, + uint32_t data_size, + enum vchi_flags flags, + void *bulk_handle) { struct shim_service *service = (struct shim_service *)handle; - VCHIQ_BULK_MODE_T mode; - VCHIQ_STATUS_T status; + enum vchiq_bulk_mode mode; + enum vchiq_status status; switch ((int)flags) { case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE @@ -309,22 +307,20 @@ EXPORT_SYMBOL(vchi_bulk_queue_transmit); /*********************************************************** * Name: vchi_msg_dequeue * - * Arguments: VCHI_SERVICE_HANDLE_T handle, + * Arguments: struct vchi_service_handle *handle, * void *data, * uint32_t max_data_size_to_read, * uint32_t *actual_msg_size - * VCHI_FLAGS_T flags + * enum vchi_flags flags * * Description: Routine to dequeue a message into the supplied buffer * * Returns: int32_t - success == 0 * ***********************************************************/ -int32_t vchi_msg_dequeue(VCHI_SERVICE_HANDLE_T handle, - void *data, - uint32_t max_data_size_to_read, - uint32_t *actual_msg_size, - VCHI_FLAGS_T flags) +int32_t vchi_msg_dequeue(struct vchi_service_handle *handle, void *data, + uint32_t max_data_size_to_read, + uint32_t *actual_msg_size, enum vchi_flags flags) { struct shim_service *service = (struct shim_service *)handle; struct vchiq_header *header; @@ -364,13 +360,13 @@ int32_t vchi_held_msg_release(struct vchi_held_msg *message) { /* * Convert the service field pointer back to an - * VCHIQ_SERVICE_HANDLE_T which is an int. + * unsigned int which is an int. * This pointer is opaque to everything except * vchi_msg_hold which simply upcasted the int * to a pointer. */ - vchiq_release_message((VCHIQ_SERVICE_HANDLE_T)(long)message->service, + vchiq_release_message((unsigned int)(long)message->service, (struct vchiq_header *)message->message); return 0; @@ -380,10 +376,10 @@ EXPORT_SYMBOL(vchi_held_msg_release); /*********************************************************** * Name: vchi_msg_hold * - * Arguments: VCHI_SERVICE_HANDLE_T handle, + * Arguments: struct vchi_service_handle *handle, * void **data, * uint32_t *msg_size, - * VCHI_FLAGS_T flags, + * enum vchi_flags flags, * struct vchi_held_msg *message_handle * * Description: Routine to return a pointer to the current message (to allow @@ -394,11 +390,9 @@ EXPORT_SYMBOL(vchi_held_msg_release); * Returns: int32_t - success == 0 * ***********************************************************/ -int32_t vchi_msg_hold(VCHI_SERVICE_HANDLE_T handle, - void **data, - uint32_t *msg_size, - VCHI_FLAGS_T flags, - struct vchi_held_msg *message_handle) +int32_t vchi_msg_hold(struct vchi_service_handle *handle, void **data, + uint32_t *msg_size, enum vchi_flags flags, + struct vchi_held_msg *message_handle) { struct shim_service *service = (struct shim_service *)handle; struct vchiq_header *header; @@ -416,7 +410,7 @@ int32_t vchi_msg_hold(VCHI_SERVICE_HANDLE_T handle, *msg_size = header->size; /* - * upcast the VCHIQ_SERVICE_HANDLE_T which is an int + * upcast the unsigned int which is an int * to a pointer and stuff it in the held message. * This pointer is opaque to everything except * vchi_held_msg_release which simply downcasts it back @@ -434,7 +428,7 @@ EXPORT_SYMBOL(vchi_msg_hold); /*********************************************************** * Name: vchi_initialise * - * Arguments: VCHI_INSTANCE_T *instance_handle + * Arguments: struct vchi_instance_handle **instance_handle * * Description: Initialises the hardware but does not transmit anything * When run as a Host App this will be called twice hence the need @@ -444,14 +438,14 @@ EXPORT_SYMBOL(vchi_msg_hold); * ***********************************************************/ -int32_t vchi_initialise(VCHI_INSTANCE_T *instance_handle) +int32_t vchi_initialise(struct vchi_instance_handle **instance_handle) { - VCHIQ_INSTANCE_T instance; - VCHIQ_STATUS_T status; + struct vchiq_instance *instance; + enum vchiq_status status; status = vchiq_initialise(&instance); - *instance_handle = (VCHI_INSTANCE_T)instance; + *instance_handle = (struct vchi_instance_handle *)instance; return vchiq_status_to_vchi(status); } @@ -460,7 +454,7 @@ EXPORT_SYMBOL(vchi_initialise); /*********************************************************** * Name: vchi_connect * - * Arguments: VCHI_INSTANCE_T instance_handle + * Arguments: struct vchi_instance_handle *instance_handle * * Description: Starts the command service on each connection, * causing INIT messages to be pinged back and forth @@ -468,9 +462,9 @@ EXPORT_SYMBOL(vchi_initialise); * Returns: 0 if successful, failure otherwise * ***********************************************************/ -int32_t vchi_connect(VCHI_INSTANCE_T instance_handle) +int32_t vchi_connect(struct vchi_instance_handle *instance_handle) { - VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle; + struct vchiq_instance *instance = (struct vchiq_instance *)instance_handle; return vchiq_connect(instance); } @@ -479,7 +473,7 @@ EXPORT_SYMBOL(vchi_connect); /*********************************************************** * Name: vchi_disconnect * - * Arguments: VCHI_INSTANCE_T instance_handle + * Arguments: struct vchi_instance_handle *instance_handle * * Description: Stops the command service on each connection, * causing DE-INIT messages to be pinged back and forth @@ -487,9 +481,9 @@ EXPORT_SYMBOL(vchi_connect); * Returns: 0 if successful, failure otherwise * ***********************************************************/ -int32_t vchi_disconnect(VCHI_INSTANCE_T instance_handle) +int32_t vchi_disconnect(struct vchi_instance_handle *instance_handle) { - VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle; + struct vchiq_instance *instance = (struct vchiq_instance *)instance_handle; return vchiq_status_to_vchi(vchiq_shutdown(instance)); } @@ -499,9 +493,9 @@ EXPORT_SYMBOL(vchi_disconnect); * Name: vchi_service_open * Name: vchi_service_create * - * Arguments: VCHI_INSTANCE_T *instance_handle + * Arguments: struct vchi_instance_handle *instance_handle * struct service_creation *setup, - * VCHI_SERVICE_HANDLE_T *handle + * struct vchi_service_handle **handle * * Description: Routine to open a service * @@ -509,9 +503,9 @@ EXPORT_SYMBOL(vchi_disconnect); * ***********************************************************/ -static VCHIQ_STATUS_T shim_callback(VCHIQ_REASON_T reason, +static enum vchiq_status shim_callback(enum vchiq_reason reason, struct vchiq_header *header, - VCHIQ_SERVICE_HANDLE_T handle, + unsigned int handle, void *bulk_user) { struct shim_service *service = @@ -571,7 +565,7 @@ done: return VCHIQ_SUCCESS; } -static struct shim_service *service_alloc(VCHIQ_INSTANCE_T instance, +static struct shim_service *service_alloc(struct vchiq_instance *instance, struct service_creation *setup) { struct shim_service *service = kzalloc(sizeof(struct shim_service), GFP_KERNEL); @@ -579,7 +573,7 @@ static struct shim_service *service_alloc(VCHIQ_INSTANCE_T instance, (void)instance; if (service) { - if (vchiu_queue_init(&service->queue, 64)) { + if (!vchiu_queue_init(&service->queue, 64)) { service->callback = setup->callback; service->callback_param = setup->callback_param; } else { @@ -599,18 +593,18 @@ static void service_free(struct shim_service *service) } } -int32_t vchi_service_open(VCHI_INSTANCE_T instance_handle, +int32_t vchi_service_open(struct vchi_instance_handle *instance_handle, struct service_creation *setup, - VCHI_SERVICE_HANDLE_T *handle) + struct vchi_service_handle **handle) { - VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)instance_handle; + struct vchiq_instance *instance = (struct vchiq_instance *)instance_handle; struct shim_service *service = service_alloc(instance, setup); - *handle = (VCHI_SERVICE_HANDLE_T)service; + *handle = (struct vchi_service_handle *)service; if (service) { struct vchiq_service_params params; - VCHIQ_STATUS_T status; + enum vchiq_status status; memset(¶ms, 0, sizeof(params)); params.fourcc = setup->service_id; @@ -628,17 +622,17 @@ int32_t vchi_service_open(VCHI_INSTANCE_T instance_handle, } } - return (service != NULL) ? 0 : -1; + return service ? 0 : -1; } EXPORT_SYMBOL(vchi_service_open); -int32_t vchi_service_close(const VCHI_SERVICE_HANDLE_T handle) +int32_t vchi_service_close(const struct vchi_service_handle *handle) { int32_t ret = -1; struct shim_service *service = (struct shim_service *)handle; if (service) { - VCHIQ_STATUS_T status = vchiq_close_service(service->handle); + enum vchiq_status status = vchiq_close_service(service->handle); if (status == VCHIQ_SUCCESS) service_free(service); @@ -648,13 +642,13 @@ int32_t vchi_service_close(const VCHI_SERVICE_HANDLE_T handle) } EXPORT_SYMBOL(vchi_service_close); -int32_t vchi_service_destroy(const VCHI_SERVICE_HANDLE_T handle) +int32_t vchi_service_destroy(const struct vchi_service_handle *handle) { int32_t ret = -1; struct shim_service *service = (struct shim_service *)handle; if (service) { - VCHIQ_STATUS_T status = vchiq_remove_service(service->handle); + enum vchiq_status status = vchiq_remove_service(service->handle); if (status == VCHIQ_SUCCESS) { service_free(service); @@ -667,13 +661,13 @@ int32_t vchi_service_destroy(const VCHI_SERVICE_HANDLE_T handle) } EXPORT_SYMBOL(vchi_service_destroy); -int32_t vchi_service_set_option(const VCHI_SERVICE_HANDLE_T handle, - VCHI_SERVICE_OPTION_T option, +int32_t vchi_service_set_option(const struct vchi_service_handle *handle, + enum vchi_service_option option, int value) { int32_t ret = -1; struct shim_service *service = (struct shim_service *)handle; - VCHIQ_SERVICE_OPTION_T vchiq_option; + enum vchiq_service_option vchiq_option; switch (option) { case VCHI_SERVICE_OPTION_TRACE: @@ -687,7 +681,7 @@ int32_t vchi_service_set_option(const VCHI_SERVICE_HANDLE_T handle, break; } if (service) { - VCHIQ_STATUS_T status = + enum vchiq_status status = vchiq_set_service_option(service->handle, vchiq_option, value); @@ -698,13 +692,13 @@ int32_t vchi_service_set_option(const VCHI_SERVICE_HANDLE_T handle, } EXPORT_SYMBOL(vchi_service_set_option); -int32_t vchi_get_peer_version(const VCHI_SERVICE_HANDLE_T handle, short *peer_version) +int32_t vchi_get_peer_version(const struct vchi_service_handle *handle, short *peer_version) { int32_t ret = -1; struct shim_service *service = (struct shim_service *)handle; if (service) { - VCHIQ_STATUS_T status; + enum vchiq_status status; status = vchiq_get_peer_version(service->handle, peer_version); ret = vchiq_status_to_vchi(status); @@ -716,14 +710,14 @@ EXPORT_SYMBOL(vchi_get_peer_version); /*********************************************************** * Name: vchi_service_use * - * Arguments: const VCHI_SERVICE_HANDLE_T handle + * Arguments: const struct vchi_service_handle *handle * * Description: Routine to increment refcount on a service * * Returns: void * ***********************************************************/ -int32_t vchi_service_use(const VCHI_SERVICE_HANDLE_T handle) +int32_t vchi_service_use(const struct vchi_service_handle *handle) { int32_t ret = -1; @@ -737,14 +731,14 @@ EXPORT_SYMBOL(vchi_service_use); /*********************************************************** * Name: vchi_service_release * - * Arguments: const VCHI_SERVICE_HANDLE_T handle + * Arguments: const struct vchi_service_handle *handle * * Description: Routine to decrement refcount on a service * * Returns: void * ***********************************************************/ -int32_t vchi_service_release(const VCHI_SERVICE_HANDLE_T handle) +int32_t vchi_service_release(const struct vchi_service_handle *handle) { int32_t ret = -1; diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.c index 5e6d3035dc05..644844d88fed 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_util.c @@ -24,9 +24,9 @@ int vchiu_queue_init(struct vchiu_queue *queue, int size) GFP_KERNEL); if (!queue->storage) { vchiu_queue_delete(queue); - return 0; + return -ENOMEM; } - return 1; + return 0; } void vchiu_queue_delete(struct vchiu_queue *queue) diff --git a/drivers/staging/vt6655/card.c b/drivers/staging/vt6655/card.c index eba4ee0750dc..e65c9825ea5a 100644 --- a/drivers/staging/vt6655/card.c +++ b/drivers/staging/vt6655/card.c @@ -79,14 +79,10 @@ static void s_vCalculateOFDMRParameter(unsigned char byRate, u8 bb_type, * * Return Value: none */ -static -void -s_vCalculateOFDMRParameter( - unsigned char byRate, - u8 bb_type, - unsigned char *pbyTxRate, - unsigned char *pbyRsvTime -) +static void s_vCalculateOFDMRParameter(unsigned char byRate, + u8 bb_type, + unsigned char *pbyTxRate, + unsigned char *pbyRsvTime) { switch (byRate) { case RATE_6M: @@ -736,8 +732,7 @@ void CARDvSetRSPINF(struct vnt_private *priv, u8 bb_type) VNSvOutPortW(priv->PortOffset + MAC_REG_RSPINF_A_24, MAKEWORD(byTxRate, byRsvTime)); /* RSPINF_a_36 */ - s_vCalculateOFDMRParameter(CARDwGetOFDMControlRate( - (void *)priv, + s_vCalculateOFDMRParameter(CARDwGetOFDMControlRate((void *)priv, RATE_36M), bb_type, &byTxRate, @@ -745,8 +740,7 @@ void CARDvSetRSPINF(struct vnt_private *priv, u8 bb_type) VNSvOutPortW(priv->PortOffset + MAC_REG_RSPINF_A_36, MAKEWORD(byTxRate, byRsvTime)); /* RSPINF_a_48 */ - s_vCalculateOFDMRParameter(CARDwGetOFDMControlRate( - (void *)priv, + s_vCalculateOFDMRParameter(CARDwGetOFDMControlRate((void *)priv, RATE_48M), bb_type, &byTxRate, @@ -754,8 +748,7 @@ void CARDvSetRSPINF(struct vnt_private *priv, u8 bb_type) VNSvOutPortW(priv->PortOffset + MAC_REG_RSPINF_A_48, MAKEWORD(byTxRate, byRsvTime)); /* RSPINF_a_54 */ - s_vCalculateOFDMRParameter(CARDwGetOFDMControlRate( - (void *)priv, + s_vCalculateOFDMRParameter(CARDwGetOFDMControlRate((void *)priv, RATE_54M), bb_type, &byTxRate, @@ -763,8 +756,7 @@ void CARDvSetRSPINF(struct vnt_private *priv, u8 bb_type) VNSvOutPortW(priv->PortOffset + MAC_REG_RSPINF_A_54, MAKEWORD(byTxRate, byRsvTime)); /* RSPINF_a_72 */ - s_vCalculateOFDMRParameter(CARDwGetOFDMControlRate( - (void *)priv, + s_vCalculateOFDMRParameter(CARDwGetOFDMControlRate((void *)priv, RATE_54M), bb_type, &byTxRate, diff --git a/drivers/staging/vt6655/card.h b/drivers/staging/vt6655/card.h index 887c1692e05b..25867cb9d13d 100644 --- a/drivers/staging/vt6655/card.h +++ b/drivers/staging/vt6655/card.h @@ -45,7 +45,7 @@ void CARDvSetRSPINF(struct vnt_private *priv, u8 bb_type); void CARDvUpdateBasicTopRate(struct vnt_private *priv); bool CARDbIsOFDMinBasicRate(struct vnt_private *priv); void CARDvSetLoopbackMode(struct vnt_private *priv, - unsigned short wLoopbackMode); + unsigned short wLoopbackMode); bool CARDbSoftwareReset(struct vnt_private *priv); void CARDvSetFirstNextTBTT(struct vnt_private *priv, unsigned short wBeaconInterval); diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index 082302944c37..f69fc687d4c3 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -295,7 +295,8 @@ static void device_init_registers(struct vnt_private *priv) /* Get Desire Power Value */ priv->byCurPwr = 0xFF; priv->byCCKPwr = SROMbyReadEmbedded(priv->PortOffset, EEP_OFS_PWR_CCK); - priv->byOFDMPwrG = SROMbyReadEmbedded(priv->PortOffset, EEP_OFS_PWR_OFDMG); + priv->byOFDMPwrG = SROMbyReadEmbedded(priv->PortOffset, + EEP_OFS_PWR_OFDMG); /* Load power Table */ for (ii = 0; ii < CB_MAX_CHANNEL_24G; ii++) { @@ -373,7 +374,7 @@ static void device_init_registers(struct vnt_private *priv) priv->bRadioOff = false; priv->byRadioCtl = SROMbyReadEmbedded(priv->PortOffset, - EEP_OFS_RADIOCTL); + EEP_OFS_RADIOCTL); priv->bHWRadioOff = false; if (priv->byRadioCtl & EEP_RADIOCTL_ENABLE) { @@ -659,12 +660,13 @@ static int device_init_td0_ring(struct vnt_private *priv) desc->td_info->buf = priv->tx0_bufs + i * PKT_BUF_SZ; desc->td_info->buf_dma = priv->tx_bufs_dma0 + i * PKT_BUF_SZ; - desc->next = &(priv->apTD0Rings[(i+1) % priv->opts.tx_descs[0]]); - desc->next_desc = cpu_to_le32(curr + sizeof(struct vnt_tx_desc)); + desc->next = &(priv->apTD0Rings[(i + 1) % priv->opts.tx_descs[0]]); + desc->next_desc = cpu_to_le32(curr + + sizeof(struct vnt_tx_desc)); } if (i > 0) - priv->apTD0Rings[i-1].next_desc = cpu_to_le32(priv->td0_pool_dma); + priv->apTD0Rings[i - 1].next_desc = cpu_to_le32(priv->td0_pool_dma); priv->apTailTD[0] = priv->apCurrTD[0] = &priv->apTD0Rings[0]; return 0; @@ -704,7 +706,7 @@ static int device_init_td1_ring(struct vnt_private *priv) } if (i > 0) - priv->apTD1Rings[i-1].next_desc = cpu_to_le32(priv->td1_pool_dma); + priv->apTD1Rings[i - 1].next_desc = cpu_to_le32(priv->td1_pool_dma); priv->apTailTD[1] = priv->apCurrTD[1] = &priv->apTD1Rings[0]; return 0; diff --git a/drivers/staging/vt6655/power.c b/drivers/staging/vt6655/power.c index 9725de3bca6a..bfd598a93b04 100644 --- a/drivers/staging/vt6655/power.c +++ b/drivers/staging/vt6655/power.c @@ -97,10 +97,7 @@ void PSvEnablePowerSaving(struct vnt_private *priv, * */ -void -PSvDisablePowerSaving( - struct vnt_private *priv -) +void PSvDisablePowerSaving(struct vnt_private *priv) { /* disable power saving hw function */ MACbPSWakeup(priv); @@ -126,10 +123,7 @@ PSvDisablePowerSaving( * */ -bool -PSbIsNextTBTTWakeUp( - struct vnt_private *priv -) +bool PSbIsNextTBTTWakeUp(struct vnt_private *priv) { struct ieee80211_hw *hw = priv->hw; struct ieee80211_conf *conf = &hw->conf; diff --git a/drivers/staging/vt6655/rf.c b/drivers/staging/vt6655/rf.c index e80fed69bafe..fb2855e686a7 100644 --- a/drivers/staging/vt6655/rf.c +++ b/drivers/staging/vt6655/rf.c @@ -436,7 +436,7 @@ static bool s_bAL7230Init(struct vnt_private *priv) ret &= IFRFbWriteEmbedded(priv, (0x3ABA8F00 + (BY_AL7230_REG_LEN << 3) + IFREGCTL_REGW)); MACvTimer0MicroSDelay(priv, 30);/* 30us */ /* TXDCOC:disable, RCK:disable */ - ret &= IFRFbWriteEmbedded(priv, dwAL7230InitTable[CB_AL7230_INIT_SEQ-1]); + ret &= IFRFbWriteEmbedded(priv, dwAL7230InitTable[CB_AL7230_INIT_SEQ - 1]); MACvWordRegBitsOn(iobase, MAC_REG_SOFTPWRCTL, (SOFTPWRCTL_SWPE3 | SOFTPWRCTL_SWPE2 | @@ -558,7 +558,8 @@ static bool RFbAL2230Init(struct vnt_private *priv) MACvTimer0MicroSDelay(priv, 30);/* 30us */ ret &= IFRFbWriteEmbedded(priv, (0x00780f00 + (BY_AL2230_REG_LEN << 3) + IFREGCTL_REGW)); MACvTimer0MicroSDelay(priv, 30);/* 30us */ - ret &= IFRFbWriteEmbedded(priv, dwAL2230InitTable[CB_AL2230_INIT_SEQ-1]); + ret &= IFRFbWriteEmbedded(priv, + dwAL2230InitTable[CB_AL2230_INIT_SEQ - 1]); MACvWordRegBitsOn(iobase, MAC_REG_SOFTPWRCTL, (SOFTPWRCTL_SWPE3 | SOFTPWRCTL_SWPE2 | diff --git a/drivers/staging/vt6655/rf.h b/drivers/staging/vt6655/rf.h index 042ac67a9709..affb70eba10f 100644 --- a/drivers/staging/vt6655/rf.h +++ b/drivers/staging/vt6655/rf.h @@ -61,23 +61,14 @@ bool IFRFbWriteEmbedded(struct vnt_private *priv, unsigned long dwData); bool RFbSelectChannel(struct vnt_private *priv, unsigned char byRFType, u16 byChannel); -bool RFbInit( - struct vnt_private *priv -); +bool RFbInit(struct vnt_private *priv); bool RFvWriteWakeProgSyn(struct vnt_private *priv, unsigned char byRFType, u16 uChannel); bool RFbSetPower(struct vnt_private *priv, unsigned int rate, u16 uCH); -bool RFbRawSetPower( - struct vnt_private *priv, - unsigned char byPwr, - unsigned int rate -); +bool RFbRawSetPower(struct vnt_private *priv, unsigned char byPwr, + unsigned int rate); -void -RFvRSSITodBm( - struct vnt_private *priv, - unsigned char byCurrRSSI, - long *pldBm -); +void RFvRSSITodBm(struct vnt_private *priv, unsigned char byCurrRSSI, + long *pldBm); /* {{ RobertYu: 20050104 */ bool RFbAL7230SelectChannelPostProcess(struct vnt_private *priv, u16 byOldChannel, u16 byNewChannel); diff --git a/drivers/staging/vt6655/rxtx.c b/drivers/staging/vt6655/rxtx.c index a14908895b9e..37fcc42ed000 100644 --- a/drivers/staging/vt6655/rxtx.c +++ b/drivers/staging/vt6655/rxtx.c @@ -1289,7 +1289,7 @@ int vnt_generate_fifo_header(struct vnt_private *priv, u32 dma_idx, current_rate = rate->hw_value; if (priv->wCurrentRate != current_rate && - !(priv->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) { + !(priv->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) { priv->wCurrentRate = current_rate; RFbSetPower(priv, priv->wCurrentRate, @@ -1396,7 +1396,8 @@ int vnt_generate_fifo_header(struct vnt_private *priv, u32 dma_idx, tx_key = info->control.hw_key; if (tx_key->keylen > 0) vnt_fill_txkey(hdr, tx_buffer_head->tx_key, - tx_key, skb, tx_body_size, td_info->mic_hdr); + tx_key, skb, tx_body_size, + td_info->mic_hdr); } return 0; diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c index 856ba97aec4f..4ac85ecb0921 100644 --- a/drivers/staging/vt6656/main_usb.c +++ b/drivers/staging/vt6656/main_usb.c @@ -249,10 +249,10 @@ static int vnt_init_registers(struct vnt_private *priv) } else { priv->tx_antenna_mode = ANT_B; - if (priv->tx_rx_ant_inv) - priv->rx_antenna_mode = ANT_A; - else - priv->rx_antenna_mode = ANT_B; + if (priv->tx_rx_ant_inv) + priv->rx_antenna_mode = ANT_A; + else + priv->rx_antenna_mode = ANT_B; } } @@ -362,7 +362,6 @@ static int vnt_init_registers(struct vnt_private *priv) goto end; } - ret = vnt_mac_set_led(priv, LEDSTS_TMLEN, 0x38); if (ret) goto end; diff --git a/drivers/staging/vt6656/rxtx.c b/drivers/staging/vt6656/rxtx.c index 4e9cfacf75f2..f9020a4f7bbf 100644 --- a/drivers/staging/vt6656/rxtx.c +++ b/drivers/staging/vt6656/rxtx.c @@ -112,11 +112,11 @@ static u32 vnt_get_rsvtime(struct vnt_private *priv, u8 pkt_type, frame_length, rate); if (pkt_type == PK_TYPE_11B) - ack_time = vnt_get_frame_time(priv->preamble_type, pkt_type, - 14, (u16)priv->top_cck_basic_rate); + ack_time = vnt_get_frame_time(priv->preamble_type, pkt_type, 14, + (u16)priv->top_cck_basic_rate); else - ack_time = vnt_get_frame_time(priv->preamble_type, pkt_type, - 14, (u16)priv->top_ofdm_basic_rate); + ack_time = vnt_get_frame_time(priv->preamble_type, pkt_type, 14, + (u16)priv->top_ofdm_basic_rate); if (need_ack) return data_time + priv->sifs + ack_time; diff --git a/drivers/staging/wfx/Documentation/devicetree/bindings/net/wireless/siliabs,wfx.txt b/drivers/staging/wfx/Documentation/devicetree/bindings/net/wireless/siliabs,wfx.txt new file mode 100644 index 000000000000..26de6762b942 --- /dev/null +++ b/drivers/staging/wfx/Documentation/devicetree/bindings/net/wireless/siliabs,wfx.txt @@ -0,0 +1,97 @@ +The WFxxx chip series can be connected via SPI or via SDIO. + +SPI +--- + +You have to declare the WFxxx chip in your device tree. + +Required properties: + - compatible: Should be "silabs,wfx-spi" + - reg: Chip select address of device + - spi-max-frequency: Maximum SPI clocking speed of device in Hz + - interrupts-extended: Should contain interrupt line (interrupt-parent + + interrupt can also been used). Trigger should be `IRQ_TYPE_EDGE_RISING`. + +Optional properties: + - reset-gpios: phandle of gpio that will be used to reset chip during probe. + Without this property, you may encounter issues with warm boot. + +Please consult Documentation/devicetree/bindings/spi/spi-bus.txt for optional +SPI connection related properties, + +Example: + +&spi1 { + wfx { + compatible = "silabs,wfx-spi"; + pinctrl-names = "default"; + pinctrl-0 = <&wfx_irq &wfx_gpios>; + interrupts-extended = <&gpio 16 IRQ_TYPE_EDGE_RISING>; + wakeup-gpios = <&gpio 12 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio 13 GPIO_ACTIVE_HIGH>; + reg = <0>; + spi-max-frequency = <42000000>; + }; +}; + + +SDIO +---- + +The driver is able to detect a WFxxx chip on SDIO bus by matching its Vendor ID +and Product ID. However, driver will only provide limited features in this +case. Thus declaring WFxxx chip in device tree is strongly recommended (and may +become mandatory in the future). + +Required properties: + - compatible: Should be "silabs,wfx-sdio" + - reg: Should be 1 + +In addition, it is recommended to declare a mmc-pwrseq on SDIO host above WFx. +Without it, you may encounter issues with warm boot. mmc-pwrseq should be +compatible with mmc-pwrseq-simple. Please consult +Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt for more +information. + +Example: + +/ { + wfx_pwrseq: wfx_pwrseq { + compatible = "mmc-pwrseq-simple"; + pinctrl-names = "default"; + pinctrl-0 = <&wfx_reset>; + reset-gpios = <&gpio 13 GPIO_ACTIVE_LOW>; + }; +}; + +&mmc1 { + mmc-pwrseq = <&wfx_pwrseq>; + #address-size = <1>; + #size = <0>; + + mmc@1 { + compatible = "silabs,wfx-sdio"; + reg = <1>; + pinctrl-names = "default"; + pinctrl-0 = <&wfx_wakeup>; + wakeup-gpios = <&gpio 12 GPIO_ACTIVE_HIGH>; + }; +}; + +Note that #address-size and #size shoud already be defined in node mmc1, but it +is rarely the case. + +Common properties +----------------- + +Some properties are recognized either by SPI and SDIO versions: + - wakeup-gpios: phandle of gpio that will be used to wake-up chip. Without + this property, driver will disable most of power saving features. + - config-file: Use an alternative file as PDS. Default is `wf200.pds`. Only + necessary for development/debug purpose. + - slk_key: String representing hexadecimal value of secure link key to use. + Must contains 64 hexadecimal digits. Not supported in current version. + +WFx driver also supports `mac-address` and `local-mac-address` as described in +Documentation/devicetree/binding/net/ethernet.txt + diff --git a/drivers/staging/wfx/Kconfig b/drivers/staging/wfx/Kconfig new file mode 100644 index 000000000000..83ee4d0ca8c6 --- /dev/null +++ b/drivers/staging/wfx/Kconfig @@ -0,0 +1,8 @@ +config WFX + tristate "Silicon Labs wireless chips WF200 and further" + depends on MAC80211 + depends on MMC || !MMC # do not allow WFX=y if MMC=m + depends on (SPI || MMC) + help + This is a driver for Silicons Labs WFxxx series (WF200 and further) + chipsets. This chip can be found on SPI or SDIO buses. diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile new file mode 100644 index 000000000000..0d9c1ed092f6 --- /dev/null +++ b/drivers/staging/wfx/Makefile @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0 + +# Necessary for CREATE_TRACE_POINTS +CFLAGS_debug.o = -I$(src) + +wfx-y := \ + bh.o \ + hwio.o \ + fwio.o \ + hif_tx.o \ + hif_rx.o \ + queue.o \ + data_tx.o \ + data_rx.o \ + scan.o \ + sta.o \ + key.o \ + main.o \ + sta.o \ + debug.o +wfx-$(CONFIG_SPI) += bus_spi.o +wfx-$(subst m,y,$(CONFIG_MMC)) += bus_sdio.o + +obj-$(CONFIG_WFX) += wfx.o diff --git a/drivers/staging/wfx/TODO b/drivers/staging/wfx/TODO new file mode 100644 index 000000000000..e44772289af8 --- /dev/null +++ b/drivers/staging/wfx/TODO @@ -0,0 +1,17 @@ +This is a list of things that need to be done to get this driver out of the +staging directory. + + - I have to take a decision about secure link support. I can: + - drop completely + - keep it in an external patch (my preferred option) + - replace call to mbedtls with kernel crypto API (necessitate a + bunch of work) + - pull mbedtls in kernel (non-realistic) + + - mac80211 interface does not (yet) have expected quality to be placed + outside of staging: + - Some processings are redundant with mac80211 ones + - Many members from wfx_dev/wfx_vif can be retrieved from mac80211 + structures + - Some functions are too complex + - ... diff --git a/drivers/staging/wfx/bh.c b/drivers/staging/wfx/bh.c new file mode 100644 index 000000000000..955ed3a1dd73 --- /dev/null +++ b/drivers/staging/wfx/bh.c @@ -0,0 +1,321 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Interrupt bottom half (BH). + * + * Copyright (c) 2017-2019, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include <linux/gpio/consumer.h> +#include <net/mac80211.h> + +#include "bh.h" +#include "wfx.h" +#include "hwio.h" +#include "traces.h" +#include "secure_link.h" +#include "hif_rx.h" +#include "hif_api_cmd.h" + +static void device_wakeup(struct wfx_dev *wdev) +{ + if (!wdev->pdata.gpio_wakeup) + return; + if (gpiod_get_value(wdev->pdata.gpio_wakeup)) + return; + + gpiod_set_value(wdev->pdata.gpio_wakeup, 1); + if (wfx_api_older_than(wdev, 1, 4)) { + if (!completion_done(&wdev->hif.ctrl_ready)) + udelay(2000); + } else { + // completion.h does not provide any function to wait + // completion without consume it (a kind of + // wait_for_completion_done_timeout()). So we have to emulate + // it. + if (wait_for_completion_timeout(&wdev->hif.ctrl_ready, + msecs_to_jiffies(2) + 1)) + complete(&wdev->hif.ctrl_ready); + else + dev_err(wdev->dev, "timeout while wake up chip\n"); + } +} + +static void device_release(struct wfx_dev *wdev) +{ + if (!wdev->pdata.gpio_wakeup) + return; + + gpiod_set_value(wdev->pdata.gpio_wakeup, 0); +} + +static int rx_helper(struct wfx_dev *wdev, size_t read_len, int *is_cnf) +{ + struct sk_buff *skb; + struct hif_msg *hif; + size_t alloc_len; + size_t computed_len; + int release_count; + int piggyback = 0; + + WARN(read_len < 4, "corrupted read"); + WARN(read_len > round_down(0xFFF, 2) * sizeof(u16), + "%s: request exceed WFx capability", __func__); + + // Add 2 to take into account piggyback size + alloc_len = wdev->hwbus_ops->align_size(wdev->hwbus_priv, read_len + 2); + skb = dev_alloc_skb(alloc_len); + if (!skb) + return -ENOMEM; + + if (wfx_data_read(wdev, skb->data, alloc_len)) + goto err; + + piggyback = le16_to_cpup((u16 *)(skb->data + alloc_len - 2)); + _trace_piggyback(piggyback, false); + + hif = (struct hif_msg *)skb->data; + WARN(hif->encrypted & 0x1, "unsupported encryption type"); + if (hif->encrypted == 0x2) { + if (wfx_sl_decode(wdev, (void *)hif)) { + dev_kfree_skb(skb); + // If frame was a confirmation, expect trouble in next + // exchange. However, it is harmless to fail to decode + // an indication frame, so try to continue. Anyway, + // piggyback is probably correct. + return piggyback; + } + le16_to_cpus(&hif->len); + computed_len = round_up(hif->len - sizeof(hif->len), 16) + + sizeof(struct hif_sl_msg) + + sizeof(struct hif_sl_tag); + } else { + le16_to_cpus(&hif->len); + computed_len = round_up(hif->len, 2); + } + if (computed_len != read_len) { + dev_err(wdev->dev, "inconsistent message length: %zu != %zu\n", + computed_len, read_len); + print_hex_dump(KERN_INFO, "hif: ", DUMP_PREFIX_OFFSET, 16, 1, + hif, read_len, true); + goto err; + } + + if (!(hif->id & HIF_ID_IS_INDICATION)) { + (*is_cnf)++; + if (hif->id == HIF_CNF_ID_MULTI_TRANSMIT) + release_count = le32_to_cpu(((struct hif_cnf_multi_transmit *)hif->body)->num_tx_confs); + else + release_count = 1; + WARN(wdev->hif.tx_buffers_used < release_count, "corrupted buffer counter"); + wdev->hif.tx_buffers_used -= release_count; + if (!wdev->hif.tx_buffers_used) + wake_up(&wdev->hif.tx_buffers_empty); + } + _trace_hif_recv(hif, wdev->hif.tx_buffers_used); + + if (hif->id != HIF_IND_ID_EXCEPTION && hif->id != HIF_IND_ID_ERROR) { + if (hif->seqnum != wdev->hif.rx_seqnum) + dev_warn(wdev->dev, "wrong message sequence: %d != %d\n", + hif->seqnum, wdev->hif.rx_seqnum); + wdev->hif.rx_seqnum = (hif->seqnum + 1) % (HIF_COUNTER_MAX + 1); + } + + skb_put(skb, hif->len); + // wfx_handle_rx takes care on SKB livetime + wfx_handle_rx(wdev, skb); + + return piggyback; + +err: + if (skb) + dev_kfree_skb(skb); + return -EIO; +} + +static int bh_work_rx(struct wfx_dev *wdev, int max_msg, int *num_cnf) +{ + size_t len; + int i; + int ctrl_reg, piggyback; + + piggyback = 0; + for (i = 0; i < max_msg; i++) { + if (piggyback & CTRL_NEXT_LEN_MASK) + ctrl_reg = piggyback; + else if (try_wait_for_completion(&wdev->hif.ctrl_ready)) + ctrl_reg = atomic_xchg(&wdev->hif.ctrl_reg, 0); + else + ctrl_reg = 0; + if (!(ctrl_reg & CTRL_NEXT_LEN_MASK)) + return i; + // ctrl_reg units are 16bits words + len = (ctrl_reg & CTRL_NEXT_LEN_MASK) * 2; + piggyback = rx_helper(wdev, len, num_cnf); + if (piggyback < 0) + return i; + if (!(piggyback & CTRL_WLAN_READY)) + dev_err(wdev->dev, "unexpected piggyback value: ready bit not set: %04x\n", + piggyback); + } + if (piggyback & CTRL_NEXT_LEN_MASK) { + ctrl_reg = atomic_xchg(&wdev->hif.ctrl_reg, piggyback); + complete(&wdev->hif.ctrl_ready); + if (ctrl_reg) + dev_err(wdev->dev, "unexpected IRQ happened: %04x/%04x\n", + ctrl_reg, piggyback); + } + return i; +} + +static void tx_helper(struct wfx_dev *wdev, struct hif_msg *hif) +{ + int ret; + void *data; + bool is_encrypted = false; + size_t len = le16_to_cpu(hif->len); + + WARN(len < sizeof(*hif), "try to send corrupted data"); + + hif->seqnum = wdev->hif.tx_seqnum; + wdev->hif.tx_seqnum = (wdev->hif.tx_seqnum + 1) % (HIF_COUNTER_MAX + 1); + + if (wfx_is_secure_command(wdev, hif->id)) { + len = round_up(len - sizeof(hif->len), 16) + sizeof(hif->len) + + sizeof(struct hif_sl_msg_hdr) + + sizeof(struct hif_sl_tag); + // AES support encryption in-place. However, mac80211 access to + // 802.11 header after frame was sent (to get MAC addresses). + // So, keep origin buffer clear. + data = kmalloc(len, GFP_KERNEL); + if (!data) + goto end; + is_encrypted = true; + ret = wfx_sl_encode(wdev, hif, data); + if (ret) + goto end; + } else { + data = hif; + } + WARN(len > wdev->hw_caps.size_inp_ch_buf, + "%s: request exceed WFx capability: %zu > %d\n", __func__, + len, wdev->hw_caps.size_inp_ch_buf); + len = wdev->hwbus_ops->align_size(wdev->hwbus_priv, len); + ret = wfx_data_write(wdev, data, len); + if (ret) + goto end; + + wdev->hif.tx_buffers_used++; + _trace_hif_send(hif, wdev->hif.tx_buffers_used); +end: + if (is_encrypted) + kfree(data); +} + +static int bh_work_tx(struct wfx_dev *wdev, int max_msg) +{ + struct hif_msg *hif; + int i; + + for (i = 0; i < max_msg; i++) { + hif = NULL; + if (wdev->hif.tx_buffers_used < wdev->hw_caps.num_inp_ch_bufs) { + if (try_wait_for_completion(&wdev->hif_cmd.ready)) { + WARN(!mutex_is_locked(&wdev->hif_cmd.lock), "data locking error"); + hif = wdev->hif_cmd.buf_send; + } else { + hif = wfx_tx_queues_get(wdev); + } + } + if (!hif) + return i; + tx_helper(wdev, hif); + } + return i; +} + +/* In SDIO mode, it is necessary to make an access to a register to acknowledge + * last received message. It could be possible to restrict this acknowledge to + * SDIO mode and only if last operation was rx. + */ +static void ack_sdio_data(struct wfx_dev *wdev) +{ + uint32_t cfg_reg; + + config_reg_read(wdev, &cfg_reg); + if (cfg_reg & 0xFF) { + dev_warn(wdev->dev, "chip reports errors: %02x\n", + cfg_reg & 0xFF); + config_reg_write_bits(wdev, 0xFF, 0x00); + } +} + +static void bh_work(struct work_struct *work) +{ + struct wfx_dev *wdev = container_of(work, struct wfx_dev, hif.bh); + int stats_req = 0, stats_cnf = 0, stats_ind = 0; + bool release_chip = false, last_op_is_rx = false; + int num_tx, num_rx; + + device_wakeup(wdev); + do { + num_tx = bh_work_tx(wdev, 32); + stats_req += num_tx; + if (num_tx) + last_op_is_rx = false; + num_rx = bh_work_rx(wdev, 32, &stats_cnf); + stats_ind += num_rx; + if (num_rx) + last_op_is_rx = true; + } while (num_rx || num_tx); + stats_ind -= stats_cnf; + + if (last_op_is_rx) + ack_sdio_data(wdev); + if (!wdev->hif.tx_buffers_used && !work_pending(work) && + !atomic_read(&wdev->scan_in_progress)) { + device_release(wdev); + release_chip = true; + } + _trace_bh_stats(stats_ind, stats_req, stats_cnf, + wdev->hif.tx_buffers_used, release_chip); +} + +/* + * An IRQ from chip did occur + */ +void wfx_bh_request_rx(struct wfx_dev *wdev) +{ + u32 cur, prev; + + control_reg_read(wdev, &cur); + prev = atomic_xchg(&wdev->hif.ctrl_reg, cur); + complete(&wdev->hif.ctrl_ready); + queue_work(system_highpri_wq, &wdev->hif.bh); + + if (!(cur & CTRL_NEXT_LEN_MASK)) + dev_err(wdev->dev, "unexpected control register value: length field is 0: %04x\n", + cur); + if (prev != 0) + dev_err(wdev->dev, "received IRQ but previous data was not (yet) read: %04x/%04x\n", + prev, cur); +} + +/* + * Driver want to send data + */ +void wfx_bh_request_tx(struct wfx_dev *wdev) +{ + queue_work(system_highpri_wq, &wdev->hif.bh); +} + +void wfx_bh_register(struct wfx_dev *wdev) +{ + INIT_WORK(&wdev->hif.bh, bh_work); + init_completion(&wdev->hif.ctrl_ready); + init_waitqueue_head(&wdev->hif.tx_buffers_empty); +} + +void wfx_bh_unregister(struct wfx_dev *wdev) +{ + flush_work(&wdev->hif.bh); +} diff --git a/drivers/staging/wfx/bh.h b/drivers/staging/wfx/bh.h new file mode 100644 index 000000000000..93ca98424e0b --- /dev/null +++ b/drivers/staging/wfx/bh.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Interrupt bottom half. + * + * Copyright (c) 2017-2019, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#ifndef WFX_BH_H +#define WFX_BH_H + +#include <linux/atomic.h> +#include <linux/wait.h> +#include <linux/workqueue.h> + +struct wfx_dev; + +struct wfx_hif { + struct work_struct bh; + struct completion ctrl_ready; + wait_queue_head_t tx_buffers_empty; + atomic_t ctrl_reg; + int rx_seqnum; + int tx_seqnum; + int tx_buffers_used; +}; + +void wfx_bh_register(struct wfx_dev *wdev); +void wfx_bh_unregister(struct wfx_dev *wdev); +void wfx_bh_request_rx(struct wfx_dev *wdev); +void wfx_bh_request_tx(struct wfx_dev *wdev); + +#endif /* WFX_BH_H */ diff --git a/drivers/staging/wfx/bus.h b/drivers/staging/wfx/bus.h new file mode 100644 index 000000000000..62d6ecabe4cb --- /dev/null +++ b/drivers/staging/wfx/bus.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Common bus abstraction layer. + * + * Copyright (c) 2017-2018, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#ifndef WFX_BUS_H +#define WFX_BUS_H + +#include <linux/mmc/sdio_func.h> +#include <linux/spi/spi.h> + +#define WFX_REG_CONFIG 0x0 +#define WFX_REG_CONTROL 0x1 +#define WFX_REG_IN_OUT_QUEUE 0x2 +#define WFX_REG_AHB_DPORT 0x3 +#define WFX_REG_BASE_ADDR 0x4 +#define WFX_REG_SRAM_DPORT 0x5 +#define WFX_REG_SET_GEN_R_W 0x6 +#define WFX_REG_FRAME_OUT 0x7 + +struct hwbus_ops { + int (*copy_from_io)(void *bus_priv, unsigned int addr, + void *dst, size_t count); + int (*copy_to_io)(void *bus_priv, unsigned int addr, + const void *src, size_t count); + void (*lock)(void *bus_priv); + void (*unlock)(void *bus_priv); + size_t (*align_size)(void *bus_priv, size_t size); +}; + +extern struct sdio_driver wfx_sdio_driver; +extern struct spi_driver wfx_spi_driver; + +#endif diff --git a/drivers/staging/wfx/bus_sdio.c b/drivers/staging/wfx/bus_sdio.c new file mode 100644 index 000000000000..375e07d6d9ae --- /dev/null +++ b/drivers/staging/wfx/bus_sdio.c @@ -0,0 +1,269 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * SDIO interface. + * + * Copyright (c) 2017-2019, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include <linux/module.h> +#include <linux/mmc/sdio_func.h> +#include <linux/mmc/card.h> +#include <linux/interrupt.h> +#include <linux/of_irq.h> + +#include "bus.h" +#include "wfx.h" +#include "hwio.h" +#include "main.h" +#include "bh.h" + +static const struct wfx_platform_data wfx_sdio_pdata = { + .file_fw = "wfm_wf200", + .file_pds = "wf200.pds", +}; + +struct wfx_sdio_priv { + struct sdio_func *func; + struct wfx_dev *core; + u8 buf_id_tx; + u8 buf_id_rx; + int of_irq; +}; + +static int wfx_sdio_copy_from_io(void *priv, unsigned int reg_id, + void *dst, size_t count) +{ + struct wfx_sdio_priv *bus = priv; + unsigned int sdio_addr = reg_id << 2; + int ret; + + WARN(reg_id > 7, "chip only has 7 registers"); + WARN(((uintptr_t)dst) & 3, "unaligned buffer size"); + WARN(count & 3, "unaligned buffer address"); + + /* Use queue mode buffers */ + if (reg_id == WFX_REG_IN_OUT_QUEUE) + sdio_addr |= (bus->buf_id_rx + 1) << 7; + ret = sdio_memcpy_fromio(bus->func, dst, sdio_addr, count); + if (!ret && reg_id == WFX_REG_IN_OUT_QUEUE) + bus->buf_id_rx = (bus->buf_id_rx + 1) % 4; + + return ret; +} + +static int wfx_sdio_copy_to_io(void *priv, unsigned int reg_id, + const void *src, size_t count) +{ + struct wfx_sdio_priv *bus = priv; + unsigned int sdio_addr = reg_id << 2; + int ret; + + WARN(reg_id > 7, "chip only has 7 registers"); + WARN(((uintptr_t)src) & 3, "unaligned buffer size"); + WARN(count & 3, "unaligned buffer address"); + + /* Use queue mode buffers */ + if (reg_id == WFX_REG_IN_OUT_QUEUE) + sdio_addr |= bus->buf_id_tx << 7; + // FIXME: discards 'const' qualifier for src + ret = sdio_memcpy_toio(bus->func, sdio_addr, (void *)src, count); + if (!ret && reg_id == WFX_REG_IN_OUT_QUEUE) + bus->buf_id_tx = (bus->buf_id_tx + 1) % 32; + + return ret; +} + +static void wfx_sdio_lock(void *priv) +{ + struct wfx_sdio_priv *bus = priv; + + sdio_claim_host(bus->func); +} + +static void wfx_sdio_unlock(void *priv) +{ + struct wfx_sdio_priv *bus = priv; + + sdio_release_host(bus->func); +} + +static void wfx_sdio_irq_handler(struct sdio_func *func) +{ + struct wfx_sdio_priv *bus = sdio_get_drvdata(func); + + if (bus->core) + wfx_bh_request_rx(bus->core); + else + WARN(!bus->core, "race condition in driver init/deinit"); +} + +static irqreturn_t wfx_sdio_irq_handler_ext(int irq, void *priv) +{ + struct wfx_sdio_priv *bus = priv; + + if (!bus->core) { + WARN(!bus->core, "race condition in driver init/deinit"); + return IRQ_NONE; + } + sdio_claim_host(bus->func); + wfx_bh_request_rx(bus->core); + sdio_release_host(bus->func); + return IRQ_HANDLED; +} + +static int wfx_sdio_irq_subscribe(struct wfx_sdio_priv *bus) +{ + int ret; + + if (bus->of_irq) { + ret = request_irq(bus->of_irq, wfx_sdio_irq_handler_ext, + IRQF_TRIGGER_RISING, "wfx", bus); + } else { + sdio_claim_host(bus->func); + ret = sdio_claim_irq(bus->func, wfx_sdio_irq_handler); + sdio_release_host(bus->func); + } + return ret; +} + +static int wfx_sdio_irq_unsubscribe(struct wfx_sdio_priv *bus) +{ + int ret; + + if (bus->of_irq) { + free_irq(bus->of_irq, bus); + ret = 0; + } else { + sdio_claim_host(bus->func); + ret = sdio_release_irq(bus->func); + sdio_release_host(bus->func); + } + return ret; +} + +static size_t wfx_sdio_align_size(void *priv, size_t size) +{ + struct wfx_sdio_priv *bus = priv; + + return sdio_align_size(bus->func, size); +} + +static const struct hwbus_ops wfx_sdio_hwbus_ops = { + .copy_from_io = wfx_sdio_copy_from_io, + .copy_to_io = wfx_sdio_copy_to_io, + .lock = wfx_sdio_lock, + .unlock = wfx_sdio_unlock, + .align_size = wfx_sdio_align_size, +}; + +static const struct of_device_id wfx_sdio_of_match[]; +static int wfx_sdio_probe(struct sdio_func *func, + const struct sdio_device_id *id) +{ + struct device_node *np = func->dev.of_node; + struct wfx_sdio_priv *bus; + int ret; + + if (func->num != 1) { + dev_err(&func->dev, "SDIO function number is %d while it should always be 1 (unsupported chip?)\n", func->num); + return -ENODEV; + } + + bus = devm_kzalloc(&func->dev, sizeof(*bus), GFP_KERNEL); + if (!bus) + return -ENOMEM; + + if (np) { + if (!of_match_node(wfx_sdio_of_match, np)) { + dev_warn(&func->dev, "no compatible device found in DT\n"); + return -ENODEV; + } + bus->of_irq = irq_of_parse_and_map(np, 0); + } else { + dev_warn(&func->dev, + "device is not declared in DT, features will be limited\n"); + // FIXME: ignore VID/PID and only rely on device tree + // return -ENODEV; + } + + bus->func = func; + sdio_set_drvdata(func, bus); + func->card->quirks |= MMC_QUIRK_LENIENT_FN0 | MMC_QUIRK_BLKSZ_FOR_BYTE_MODE | MMC_QUIRK_BROKEN_BYTE_MODE_512; + + sdio_claim_host(func); + ret = sdio_enable_func(func); + // Block of 64 bytes is more efficient than 512B for frame sizes < 4k + sdio_set_block_size(func, 64); + sdio_release_host(func); + if (ret) + goto err0; + + ret = wfx_sdio_irq_subscribe(bus); + if (ret) + goto err1; + + bus->core = wfx_init_common(&func->dev, &wfx_sdio_pdata, + &wfx_sdio_hwbus_ops, bus); + if (!bus->core) { + ret = -EIO; + goto err2; + } + + ret = wfx_probe(bus->core); + if (ret) + goto err3; + + return 0; + +err3: + wfx_free_common(bus->core); +err2: + wfx_sdio_irq_unsubscribe(bus); +err1: + sdio_claim_host(func); + sdio_disable_func(func); + sdio_release_host(func); +err0: + return ret; +} + +static void wfx_sdio_remove(struct sdio_func *func) +{ + struct wfx_sdio_priv *bus = sdio_get_drvdata(func); + + wfx_release(bus->core); + wfx_free_common(bus->core); + wfx_sdio_irq_unsubscribe(bus); + sdio_claim_host(func); + sdio_disable_func(func); + sdio_release_host(func); +} + +#define SDIO_VENDOR_ID_SILABS 0x0000 +#define SDIO_DEVICE_ID_SILABS_WF200 0x1000 +static const struct sdio_device_id wfx_sdio_ids[] = { + { SDIO_DEVICE(SDIO_VENDOR_ID_SILABS, SDIO_DEVICE_ID_SILABS_WF200) }, + // FIXME: ignore VID/PID and only rely on device tree + // { SDIO_DEVICE(SDIO_ANY_ID, SDIO_ANY_ID) }, + { }, +}; +MODULE_DEVICE_TABLE(sdio, wfx_sdio_ids); + +#ifdef CONFIG_OF +static const struct of_device_id wfx_sdio_of_match[] = { + { .compatible = "silabs,wfx-sdio" }, + { }, +}; +MODULE_DEVICE_TABLE(of, wfx_sdio_of_match); +#endif + +struct sdio_driver wfx_sdio_driver = { + .name = "wfx-sdio", + .id_table = wfx_sdio_ids, + .probe = wfx_sdio_probe, + .remove = wfx_sdio_remove, + .drv = { + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(wfx_sdio_of_match), + } +}; diff --git a/drivers/staging/wfx/bus_spi.c b/drivers/staging/wfx/bus_spi.c new file mode 100644 index 000000000000..ab0cda1e124f --- /dev/null +++ b/drivers/staging/wfx/bus_spi.c @@ -0,0 +1,267 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * SPI interface. + * + * Copyright (c) 2017-2019, Silicon Laboratories, Inc. + * Copyright (c) 2011, Sagrad Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/gpio/consumer.h> +#include <linux/spi/spi.h> +#include <linux/interrupt.h> +#include <linux/of.h> + +#include "bus.h" +#include "wfx.h" +#include "hwio.h" +#include "main.h" +#include "bh.h" + +static int gpio_reset = -2; +module_param(gpio_reset, int, 0644); +MODULE_PARM_DESC(gpio_reset, "gpio number for reset. -1 for none."); + +#define SET_WRITE 0x7FFF /* usage: and operation */ +#define SET_READ 0x8000 /* usage: or operation */ + +static const struct wfx_platform_data wfx_spi_pdata = { + .file_fw = "wfm_wf200", + .file_pds = "wf200.pds", + .use_rising_clk = true, +}; + +struct wfx_spi_priv { + struct spi_device *func; + struct wfx_dev *core; + struct gpio_desc *gpio_reset; + struct work_struct request_rx; + bool need_swab; +}; + +/* + * WFx chip read data 16bits at time and place them directly into (little + * endian) CPU register. So, chip expect byte order like "B1 B0 B3 B2" (while + * LE is "B0 B1 B2 B3" and BE is "B3 B2 B1 B0") + * + * A little endian host with bits_per_word == 16 should do the right job + * natively. The code below to support big endian host and commonly used SPI + * 8bits. + */ +static int wfx_spi_copy_from_io(void *priv, unsigned int addr, + void *dst, size_t count) +{ + struct wfx_spi_priv *bus = priv; + u16 regaddr = (addr << 12) | (count / 2) | SET_READ; + struct spi_message m; + struct spi_transfer t_addr = { + .tx_buf = ®addr, + .len = sizeof(regaddr), + }; + struct spi_transfer t_msg = { + .rx_buf = dst, + .len = count, + }; + u16 *dst16 = dst; + int ret, i; + + WARN(count % 2, "buffer size must be a multiple of 2"); + + cpu_to_le16s(®addr); + if (bus->need_swab) + swab16s(®addr); + + spi_message_init(&m); + spi_message_add_tail(&t_addr, &m); + spi_message_add_tail(&t_msg, &m); + ret = spi_sync(bus->func, &m); + + if (bus->need_swab && addr == WFX_REG_CONFIG) + for (i = 0; i < count / 2; i++) + swab16s(&dst16[i]); + return ret; +} + +static int wfx_spi_copy_to_io(void *priv, unsigned int addr, + const void *src, size_t count) +{ + struct wfx_spi_priv *bus = priv; + u16 regaddr = (addr << 12) | (count / 2); + // FIXME: use a bounce buffer + u16 *src16 = (void *)src; + int ret, i; + struct spi_message m; + struct spi_transfer t_addr = { + .tx_buf = ®addr, + .len = sizeof(regaddr), + }; + struct spi_transfer t_msg = { + .tx_buf = src, + .len = count, + }; + + WARN(count % 2, "buffer size must be a multiple of 2"); + WARN(regaddr & SET_READ, "bad addr or size overflow"); + + cpu_to_le16s(®addr); + + if (bus->need_swab) + swab16s(®addr); + if (bus->need_swab && addr == WFX_REG_CONFIG) + for (i = 0; i < count / 2; i++) + swab16s(&src16[i]); + + spi_message_init(&m); + spi_message_add_tail(&t_addr, &m); + spi_message_add_tail(&t_msg, &m); + ret = spi_sync(bus->func, &m); + + if (bus->need_swab && addr == WFX_REG_CONFIG) + for (i = 0; i < count / 2; i++) + swab16s(&src16[i]); + return ret; +} + +static void wfx_spi_lock(void *priv) +{ +} + +static void wfx_spi_unlock(void *priv) +{ +} + +static irqreturn_t wfx_spi_irq_handler(int irq, void *priv) +{ + struct wfx_spi_priv *bus = priv; + + if (!bus->core) { + WARN(!bus->core, "race condition in driver init/deinit"); + return IRQ_NONE; + } + queue_work(system_highpri_wq, &bus->request_rx); + return IRQ_HANDLED; +} + +static void wfx_spi_request_rx(struct work_struct *work) +{ + struct wfx_spi_priv *bus = + container_of(work, struct wfx_spi_priv, request_rx); + + wfx_bh_request_rx(bus->core); +} + +static size_t wfx_spi_align_size(void *priv, size_t size) +{ + // Most of SPI controllers avoid DMA if buffer size is not 32bit aligned + return ALIGN(size, 4); +} + +static const struct hwbus_ops wfx_spi_hwbus_ops = { + .copy_from_io = wfx_spi_copy_from_io, + .copy_to_io = wfx_spi_copy_to_io, + .lock = wfx_spi_lock, + .unlock = wfx_spi_unlock, + .align_size = wfx_spi_align_size, +}; + +static int wfx_spi_probe(struct spi_device *func) +{ + struct wfx_spi_priv *bus; + int ret; + + if (!func->bits_per_word) + func->bits_per_word = 16; + ret = spi_setup(func); + if (ret) + return ret; + // Trace below is also displayed by spi_setup() if compiled with DEBUG + dev_dbg(&func->dev, "SPI params: CS=%d, mode=%d bits/word=%d speed=%d\n", + func->chip_select, func->mode, func->bits_per_word, + func->max_speed_hz); + if (func->bits_per_word != 16 && func->bits_per_word != 8) + dev_warn(&func->dev, "unusual bits/word value: %d\n", + func->bits_per_word); + if (func->max_speed_hz > 49000000) + dev_warn(&func->dev, "%dHz is a very high speed\n", + func->max_speed_hz); + + bus = devm_kzalloc(&func->dev, sizeof(*bus), GFP_KERNEL); + if (!bus) + return -ENOMEM; + bus->func = func; + if (func->bits_per_word == 8 || IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) + bus->need_swab = true; + spi_set_drvdata(func, bus); + + bus->gpio_reset = wfx_get_gpio(&func->dev, gpio_reset, "reset"); + if (!bus->gpio_reset) { + dev_warn(&func->dev, "try to load firmware anyway\n"); + } else { + gpiod_set_value(bus->gpio_reset, 0); + udelay(100); + gpiod_set_value(bus->gpio_reset, 1); + udelay(2000); + } + + ret = devm_request_irq(&func->dev, func->irq, wfx_spi_irq_handler, + IRQF_TRIGGER_RISING, "wfx", bus); + if (ret) + return ret; + + INIT_WORK(&bus->request_rx, wfx_spi_request_rx); + bus->core = wfx_init_common(&func->dev, &wfx_spi_pdata, + &wfx_spi_hwbus_ops, bus); + if (!bus->core) + return -EIO; + + ret = wfx_probe(bus->core); + if (ret) + wfx_free_common(bus->core); + + return ret; +} + +/* Disconnect Function to be called by SPI stack when device is disconnected */ +static int wfx_spi_disconnect(struct spi_device *func) +{ + struct wfx_spi_priv *bus = spi_get_drvdata(func); + + wfx_release(bus->core); + wfx_free_common(bus->core); + // A few IRQ will be sent during device release. Hopefully, no IRQ + // should happen after wdev/wvif are released. + devm_free_irq(&func->dev, func->irq, bus); + flush_work(&bus->request_rx); + return 0; +} + +/* + * For dynamic driver binding, kernel does not use OF to match driver. It only + * use modalias and modalias is a copy of 'compatible' DT node with vendor + * stripped. + */ +static const struct spi_device_id wfx_spi_id[] = { + { "wfx-spi", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(spi, wfx_spi_id); + +#ifdef CONFIG_OF +static const struct of_device_id wfx_spi_of_match[] = { + { .compatible = "silabs,wfx-spi" }, + { }, +}; +MODULE_DEVICE_TABLE(of, wfx_spi_of_match); +#endif + +struct spi_driver wfx_spi_driver = { + .driver = { + .name = "wfx-spi", + .of_match_table = of_match_ptr(wfx_spi_of_match), + }, + .id_table = wfx_spi_id, + .probe = wfx_spi_probe, + .remove = wfx_spi_disconnect, +}; diff --git a/drivers/staging/wfx/data_rx.c b/drivers/staging/wfx/data_rx.c new file mode 100644 index 000000000000..e7fcce8d0cc4 --- /dev/null +++ b/drivers/staging/wfx/data_rx.c @@ -0,0 +1,213 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Datapath implementation. + * + * Copyright (c) 2017-2019, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include <linux/etherdevice.h> +#include <net/mac80211.h> + +#include "data_rx.h" +#include "wfx.h" +#include "bh.h" +#include "sta.h" + +static int wfx_handle_pspoll(struct wfx_vif *wvif, struct sk_buff *skb) +{ + struct ieee80211_sta *sta; + struct ieee80211_pspoll *pspoll = (struct ieee80211_pspoll *)skb->data; + int link_id = 0; + u32 pspoll_mask = 0; + int i; + + if (wvif->state != WFX_STATE_AP) + return 1; + if (!ether_addr_equal(wvif->vif->addr, pspoll->bssid)) + return 1; + + rcu_read_lock(); + sta = ieee80211_find_sta(wvif->vif, pspoll->ta); + if (sta) + link_id = ((struct wfx_sta_priv *)&sta->drv_priv)->link_id; + rcu_read_unlock(); + if (link_id) + pspoll_mask = BIT(link_id); + else + return 1; + + wvif->pspoll_mask |= pspoll_mask; + /* Do not report pspols if data for given link id is queued already. */ + for (i = 0; i < IEEE80211_NUM_ACS; ++i) { + if (wfx_tx_queue_get_num_queued(&wvif->wdev->tx_queue[i], + pspoll_mask)) { + wfx_bh_request_tx(wvif->wdev); + return 1; + } + } + return 0; +} + +static int wfx_drop_encrypt_data(struct wfx_dev *wdev, struct hif_ind_rx *arg, struct sk_buff *skb) +{ + struct ieee80211_hdr *frame = (struct ieee80211_hdr *) skb->data; + size_t hdrlen = ieee80211_hdrlen(frame->frame_control); + size_t iv_len, icv_len; + + /* Oops... There is no fast way to ask mac80211 about + * IV/ICV lengths. Even defineas are not exposed. + */ + switch (arg->rx_flags.encryp) { + case HIF_RI_FLAGS_WEP_ENCRYPTED: + iv_len = 4 /* WEP_IV_LEN */; + icv_len = 4 /* WEP_ICV_LEN */; + break; + case HIF_RI_FLAGS_TKIP_ENCRYPTED: + iv_len = 8 /* TKIP_IV_LEN */; + icv_len = 4 /* TKIP_ICV_LEN */ + + 8 /*MICHAEL_MIC_LEN*/; + break; + case HIF_RI_FLAGS_AES_ENCRYPTED: + iv_len = 8 /* CCMP_HDR_LEN */; + icv_len = 8 /* CCMP_MIC_LEN */; + break; + case HIF_RI_FLAGS_WAPI_ENCRYPTED: + iv_len = 18 /* WAPI_HDR_LEN */; + icv_len = 16 /* WAPI_MIC_LEN */; + break; + default: + dev_err(wdev->dev, "unknown encryption type %d\n", + arg->rx_flags.encryp); + return -EIO; + } + + /* Firmware strips ICV in case of MIC failure. */ + if (arg->status == HIF_STATUS_MICFAILURE) + icv_len = 0; + + if (skb->len < hdrlen + iv_len + icv_len) { + dev_warn(wdev->dev, "malformed SDU received\n"); + return -EIO; + } + + /* Remove IV, ICV and MIC */ + skb_trim(skb, skb->len - icv_len); + memmove(skb->data + iv_len, skb->data, hdrlen); + skb_pull(skb, iv_len); + return 0; + +} + +void wfx_rx_cb(struct wfx_vif *wvif, struct hif_ind_rx *arg, + struct sk_buff *skb) +{ + int link_id = arg->rx_flags.peer_sta_id; + struct ieee80211_rx_status *hdr = IEEE80211_SKB_RXCB(skb); + struct ieee80211_hdr *frame = (struct ieee80211_hdr *)skb->data; + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; + struct wfx_link_entry *entry = NULL; + bool early_data = false; + + memset(hdr, 0, sizeof(*hdr)); + + // FIXME: Why do we drop these frames? + if (!arg->rcpi_rssi && + (ieee80211_is_probe_resp(frame->frame_control) || + ieee80211_is_beacon(frame->frame_control))) + goto drop; + + if (link_id && link_id <= WFX_MAX_STA_IN_AP_MODE) { + entry = &wvif->link_id_db[link_id - 1]; + entry->timestamp = jiffies; + if (entry->status == WFX_LINK_SOFT && + ieee80211_is_data(frame->frame_control)) + early_data = true; + } + + if (arg->status == HIF_STATUS_MICFAILURE) + hdr->flag |= RX_FLAG_MMIC_ERROR; + else if (arg->status) + goto drop; + + if (skb->len < sizeof(struct ieee80211_pspoll)) { + dev_warn(wvif->wdev->dev, "malformed SDU received\n"); + goto drop; + } + + if (ieee80211_is_pspoll(frame->frame_control)) + if (wfx_handle_pspoll(wvif, skb)) + goto drop; + + hdr->band = NL80211_BAND_2GHZ; + hdr->freq = ieee80211_channel_to_frequency(arg->channel_number, + hdr->band); + + if (arg->rxed_rate >= 14) { + hdr->encoding = RX_ENC_HT; + hdr->rate_idx = arg->rxed_rate - 14; + } else if (arg->rxed_rate >= 4) { + hdr->rate_idx = arg->rxed_rate - 2; + } else { + hdr->rate_idx = arg->rxed_rate; + } + + hdr->signal = arg->rcpi_rssi / 2 - 110; + hdr->antenna = 0; + + if (arg->rx_flags.encryp) { + if (wfx_drop_encrypt_data(wvif->wdev, arg, skb)) + goto drop; + hdr->flag |= RX_FLAG_DECRYPTED | RX_FLAG_IV_STRIPPED; + if (arg->rx_flags.encryp == HIF_RI_FLAGS_TKIP_ENCRYPTED) + hdr->flag |= RX_FLAG_MMIC_STRIPPED; + } + + /* Filter block ACK negotiation: fully controlled by firmware */ + if (ieee80211_is_action(frame->frame_control) && + arg->rx_flags.match_uc_addr && + mgmt->u.action.category == WLAN_CATEGORY_BACK) + goto drop; + if (ieee80211_is_beacon(frame->frame_control) && + !arg->status && wvif->vif && + ether_addr_equal(ieee80211_get_SA(frame), + wvif->vif->bss_conf.bssid)) { + const u8 *tim_ie; + u8 *ies = mgmt->u.beacon.variable; + size_t ies_len = skb->len - (ies - skb->data); + + tim_ie = cfg80211_find_ie(WLAN_EID_TIM, ies, ies_len); + if (tim_ie) { + struct ieee80211_tim_ie *tim = (struct ieee80211_tim_ie *)&tim_ie[2]; + + if (wvif->dtim_period != tim->dtim_period) { + wvif->dtim_period = tim->dtim_period; + schedule_work(&wvif->set_beacon_wakeup_period_work); + } + } + + /* Disable beacon filter once we're associated... */ + if (wvif->disable_beacon_filter && + (wvif->vif->bss_conf.assoc || + wvif->vif->bss_conf.ibss_joined)) { + wvif->disable_beacon_filter = false; + schedule_work(&wvif->update_filtering_work); + } + } + + if (early_data) { + spin_lock_bh(&wvif->ps_state_lock); + /* Double-check status with lock held */ + if (entry->status == WFX_LINK_SOFT) + skb_queue_tail(&entry->rx_queue, skb); + else + ieee80211_rx_irqsafe(wvif->wdev->hw, skb); + spin_unlock_bh(&wvif->ps_state_lock); + } else { + ieee80211_rx_irqsafe(wvif->wdev->hw, skb); + } + + return; + +drop: + dev_kfree_skb(skb); +} diff --git a/drivers/staging/wfx/data_rx.h b/drivers/staging/wfx/data_rx.h new file mode 100644 index 000000000000..b44d15268f83 --- /dev/null +++ b/drivers/staging/wfx/data_rx.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Datapath implementation. + * + * Copyright (c) 2017-2019, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#ifndef WFX_DATA_RX_H +#define WFX_DATA_RX_H + +#include "hif_api_cmd.h" + +struct wfx_vif; +struct sk_buff; + +void wfx_rx_cb(struct wfx_vif *wvif, struct hif_ind_rx *arg, struct sk_buff *skb); + +#endif /* WFX_DATA_RX_H */ diff --git a/drivers/staging/wfx/data_tx.c b/drivers/staging/wfx/data_tx.c new file mode 100644 index 000000000000..ea4205ac2149 --- /dev/null +++ b/drivers/staging/wfx/data_tx.c @@ -0,0 +1,837 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Datapath implementation. + * + * Copyright (c) 2017-2019, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include <net/mac80211.h> + +#include "data_tx.h" +#include "wfx.h" +#include "bh.h" +#include "sta.h" +#include "queue.h" +#include "debug.h" +#include "traces.h" +#include "hif_tx_mib.h" + +#define WFX_INVALID_RATE_ID (0xFF) +#define WFX_LINK_ID_NO_ASSOC 15 +#define WFX_LINK_ID_GC_TIMEOUT ((unsigned long)(10 * HZ)) + +static int wfx_get_hw_rate(struct wfx_dev *wdev, + const struct ieee80211_tx_rate *rate) +{ + if (rate->idx < 0) + return -1; + if (rate->flags & IEEE80211_TX_RC_MCS) { + if (rate->idx > 7) { + WARN(1, "wrong rate->idx value: %d", rate->idx); + return -1; + } + return rate->idx + 14; + } + // WFx only support 2GHz, else band information should be retrieved + // from ieee80211_tx_info + return wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]->bitrates[rate->idx].hw_value; +} + +/* TX policy cache implementation */ + +static void wfx_tx_policy_build(struct wfx_vif *wvif, struct tx_policy *policy, + struct ieee80211_tx_rate *rates) +{ + int i; + size_t count; + struct wfx_dev *wdev = wvif->wdev; + + WARN(rates[0].idx < 0, "invalid rate policy"); + memset(policy, 0, sizeof(*policy)); + for (i = 1; i < IEEE80211_TX_MAX_RATES; i++) + if (rates[i].idx < 0) + break; + count = i; + + /* HACK!!! Device has problems (at least) switching from + * 54Mbps CTS to 1Mbps. This switch takes enormous amount + * of time (100-200 ms), leading to valuable throughput drop. + * As a workaround, additional g-rates are injected to the + * policy. + */ + if (count == 2 && !(rates[0].flags & IEEE80211_TX_RC_MCS) && + rates[0].idx > 4 && rates[0].count > 2 && + rates[1].idx < 2) { + int mid_rate = (rates[0].idx + 4) >> 1; + + /* Decrease number of retries for the initial rate */ + rates[0].count -= 2; + + if (mid_rate != 4) { + /* Keep fallback rate at 1Mbps. */ + rates[3] = rates[1]; + + /* Inject 1 transmission on lowest g-rate */ + rates[2].idx = 4; + rates[2].count = 1; + rates[2].flags = rates[1].flags; + + /* Inject 1 transmission on mid-rate */ + rates[1].idx = mid_rate; + rates[1].count = 1; + + /* Fallback to 1 Mbps is a really bad thing, + * so let's try to increase probability of + * successful transmission on the lowest g rate + * even more + */ + if (rates[0].count >= 3) { + --rates[0].count; + ++rates[2].count; + } + + /* Adjust amount of rates defined */ + count += 2; + } else { + /* Keep fallback rate at 1Mbps. */ + rates[2] = rates[1]; + + /* Inject 2 transmissions on lowest g-rate */ + rates[1].idx = 4; + rates[1].count = 2; + + /* Adjust amount of rates defined */ + count += 1; + } + } + + for (i = 0; i < IEEE80211_TX_MAX_RATES; ++i) { + int rateid; + uint8_t count; + + if (rates[i].idx < 0) + break; + WARN_ON(rates[i].count > 15); + rateid = wfx_get_hw_rate(wdev, &rates[i]); + // Pack two values in each byte of policy->rates + count = rates[i].count; + if (rateid % 2) + count <<= 4; + policy->rates[rateid / 2] |= count; + } +} + +static bool tx_policy_is_equal(const struct tx_policy *a, + const struct tx_policy *b) +{ + return !memcmp(a->rates, b->rates, sizeof(a->rates)); +} + +static int wfx_tx_policy_find(struct tx_policy_cache *cache, + struct tx_policy *wanted) +{ + struct tx_policy *it; + + list_for_each_entry(it, &cache->used, link) + if (tx_policy_is_equal(wanted, it)) + return it - cache->cache; + list_for_each_entry(it, &cache->free, link) + if (tx_policy_is_equal(wanted, it)) + return it - cache->cache; + return -1; +} + +static void wfx_tx_policy_use(struct tx_policy_cache *cache, + struct tx_policy *entry) +{ + ++entry->usage_count; + list_move(&entry->link, &cache->used); +} + +static int wfx_tx_policy_release(struct tx_policy_cache *cache, + struct tx_policy *entry) +{ + int ret = --entry->usage_count; + + if (!ret) + list_move(&entry->link, &cache->free); + return ret; +} + +static int wfx_tx_policy_get(struct wfx_vif *wvif, + struct ieee80211_tx_rate *rates, + bool *renew) +{ + int idx; + struct tx_policy_cache *cache = &wvif->tx_policy_cache; + struct tx_policy wanted; + + wfx_tx_policy_build(wvif, &wanted, rates); + + spin_lock_bh(&cache->lock); + if (WARN_ON(list_empty(&cache->free))) { + spin_unlock_bh(&cache->lock); + return WFX_INVALID_RATE_ID; + } + idx = wfx_tx_policy_find(cache, &wanted); + if (idx >= 0) { + *renew = false; + } else { + struct tx_policy *entry; + *renew = true; + /* If policy is not found create a new one + * using the oldest entry in "free" list + */ + entry = list_entry(cache->free.prev, struct tx_policy, link); + memcpy(entry->rates, wanted.rates, sizeof(entry->rates)); + entry->uploaded = 0; + entry->usage_count = 0; + idx = entry - cache->cache; + } + wfx_tx_policy_use(cache, &cache->cache[idx]); + if (list_empty(&cache->free)) { + /* Lock TX queues. */ + wfx_tx_queues_lock(wvif->wdev); + } + spin_unlock_bh(&cache->lock); + return idx; +} + +static void wfx_tx_policy_put(struct wfx_vif *wvif, int idx) +{ + int usage, locked; + struct tx_policy_cache *cache = &wvif->tx_policy_cache; + + spin_lock_bh(&cache->lock); + locked = list_empty(&cache->free); + usage = wfx_tx_policy_release(cache, &cache->cache[idx]); + if (locked && !usage) { + /* Unlock TX queues. */ + wfx_tx_queues_unlock(wvif->wdev); + } + spin_unlock_bh(&cache->lock); +} + +static int wfx_tx_policy_upload(struct wfx_vif *wvif) +{ + int i; + struct tx_policy_cache *cache = &wvif->tx_policy_cache; + struct hif_mib_set_tx_rate_retry_policy *arg = + kzalloc(struct_size(arg, + tx_rate_retry_policy, + HIF_MIB_NUM_TX_RATE_RETRY_POLICIES), + GFP_KERNEL); + struct hif_mib_tx_rate_retry_policy *dst; + + spin_lock_bh(&cache->lock); + /* Upload only modified entries. */ + for (i = 0; i < HIF_MIB_NUM_TX_RATE_RETRY_POLICIES; ++i) { + struct tx_policy *src = &cache->cache[i]; + + if (!src->uploaded && memzcmp(src->rates, sizeof(src->rates))) { + dst = arg->tx_rate_retry_policy + + arg->num_tx_rate_policies; + + dst->policy_index = i; + dst->short_retry_count = 255; + dst->long_retry_count = 255; + dst->first_rate_sel = 1; + dst->terminate = 1; + dst->count_init = 1; + memcpy(&dst->rates, src->rates, sizeof(src->rates)); + src->uploaded = 1; + arg->num_tx_rate_policies++; + } + } + spin_unlock_bh(&cache->lock); + hif_set_tx_rate_retry_policy(wvif, arg); + kfree(arg); + return 0; +} + +static void wfx_tx_policy_upload_work(struct work_struct *work) +{ + struct wfx_vif *wvif = + container_of(work, struct wfx_vif, tx_policy_upload_work); + + wfx_tx_policy_upload(wvif); + + wfx_tx_unlock(wvif->wdev); + wfx_tx_queues_unlock(wvif->wdev); +} + +void wfx_tx_policy_init(struct wfx_vif *wvif) +{ + struct tx_policy_cache *cache = &wvif->tx_policy_cache; + int i; + + memset(cache, 0, sizeof(*cache)); + + spin_lock_init(&cache->lock); + INIT_LIST_HEAD(&cache->used); + INIT_LIST_HEAD(&cache->free); + INIT_WORK(&wvif->tx_policy_upload_work, wfx_tx_policy_upload_work); + + for (i = 0; i < HIF_MIB_NUM_TX_RATE_RETRY_POLICIES; ++i) + list_add(&cache->cache[i].link, &cache->free); +} + +/* Link ID related functions */ + +static int wfx_alloc_link_id(struct wfx_vif *wvif, const u8 *mac) +{ + int i, ret = 0; + unsigned long max_inactivity = 0; + unsigned long now = jiffies; + + spin_lock_bh(&wvif->ps_state_lock); + for (i = 0; i < WFX_MAX_STA_IN_AP_MODE; ++i) { + if (!wvif->link_id_db[i].status) { + ret = i + 1; + break; + } else if (wvif->link_id_db[i].status != WFX_LINK_HARD && + !wvif->wdev->tx_queue_stats.link_map_cache[i + 1]) { + unsigned long inactivity = + now - wvif->link_id_db[i].timestamp; + + if (inactivity < max_inactivity) + continue; + max_inactivity = inactivity; + ret = i + 1; + } + } + + if (ret) { + struct wfx_link_entry *entry = &wvif->link_id_db[ret - 1]; + + entry->status = WFX_LINK_RESERVE; + ether_addr_copy(entry->mac, mac); + memset(&entry->buffered, 0, WFX_MAX_TID); + skb_queue_head_init(&entry->rx_queue); + wfx_tx_lock(wvif->wdev); + + if (!schedule_work(&wvif->link_id_work)) + wfx_tx_unlock(wvif->wdev); + } else { + dev_info(wvif->wdev->dev, "no more link-id available\n"); + } + spin_unlock_bh(&wvif->ps_state_lock); + return ret; +} + +int wfx_find_link_id(struct wfx_vif *wvif, const u8 *mac) +{ + int i, ret = 0; + + spin_lock_bh(&wvif->ps_state_lock); + for (i = 0; i < WFX_MAX_STA_IN_AP_MODE; ++i) { + if (ether_addr_equal(mac, wvif->link_id_db[i].mac) && + wvif->link_id_db[i].status) { + wvif->link_id_db[i].timestamp = jiffies; + ret = i + 1; + break; + } + } + spin_unlock_bh(&wvif->ps_state_lock); + return ret; +} + +static int wfx_map_link(struct wfx_vif *wvif, + struct wfx_link_entry *link_entry, int sta_id) +{ + int ret; + + ret = hif_map_link(wvif, link_entry->mac, 0, sta_id); + + if (ret == 0) + /* Save the MAC address currently associated with the peer + * for future unmap request + */ + ether_addr_copy(link_entry->old_mac, link_entry->mac); + + return ret; +} + +int wfx_unmap_link(struct wfx_vif *wvif, int sta_id) +{ + u8 *mac_addr = NULL; + + if (sta_id) + mac_addr = wvif->link_id_db[sta_id - 1].old_mac; + + return hif_map_link(wvif, mac_addr, 1, sta_id); +} + +void wfx_link_id_gc_work(struct work_struct *work) +{ + struct wfx_vif *wvif = + container_of(work, struct wfx_vif, link_id_gc_work.work); + unsigned long now = jiffies; + unsigned long next_gc = -1; + long ttl; + u32 mask; + int i; + + if (wvif->state != WFX_STATE_AP) + return; + + wfx_tx_lock_flush(wvif->wdev); + spin_lock_bh(&wvif->ps_state_lock); + for (i = 0; i < WFX_MAX_STA_IN_AP_MODE; ++i) { + bool need_reset = false; + + mask = BIT(i + 1); + if (wvif->link_id_db[i].status == WFX_LINK_RESERVE || + (wvif->link_id_db[i].status == WFX_LINK_HARD && + !(wvif->link_id_map & mask))) { + if (wvif->link_id_map & mask) { + wvif->sta_asleep_mask &= ~mask; + wvif->pspoll_mask &= ~mask; + need_reset = true; + } + wvif->link_id_map |= mask; + if (wvif->link_id_db[i].status != WFX_LINK_HARD) + wvif->link_id_db[i].status = WFX_LINK_SOFT; + + spin_unlock_bh(&wvif->ps_state_lock); + if (need_reset) + wfx_unmap_link(wvif, i + 1); + wfx_map_link(wvif, &wvif->link_id_db[i], i + 1); + next_gc = min(next_gc, WFX_LINK_ID_GC_TIMEOUT); + spin_lock_bh(&wvif->ps_state_lock); + } else if (wvif->link_id_db[i].status == WFX_LINK_SOFT) { + ttl = wvif->link_id_db[i].timestamp - now + + WFX_LINK_ID_GC_TIMEOUT; + if (ttl <= 0) { + need_reset = true; + wvif->link_id_db[i].status = WFX_LINK_OFF; + wvif->link_id_map &= ~mask; + wvif->sta_asleep_mask &= ~mask; + wvif->pspoll_mask &= ~mask; + spin_unlock_bh(&wvif->ps_state_lock); + wfx_unmap_link(wvif, i + 1); + spin_lock_bh(&wvif->ps_state_lock); + } else { + next_gc = min_t(unsigned long, next_gc, ttl); + } + } + if (need_reset) + skb_queue_purge(&wvif->link_id_db[i].rx_queue); + } + spin_unlock_bh(&wvif->ps_state_lock); + if (next_gc != -1) + schedule_delayed_work(&wvif->link_id_gc_work, next_gc); + wfx_tx_unlock(wvif->wdev); +} + +void wfx_link_id_work(struct work_struct *work) +{ + struct wfx_vif *wvif = + container_of(work, struct wfx_vif, link_id_work); + + wfx_tx_flush(wvif->wdev); + wfx_link_id_gc_work(&wvif->link_id_gc_work.work); + wfx_tx_unlock(wvif->wdev); +} + +/* Tx implementation */ + +static bool ieee80211_is_action_back(struct ieee80211_hdr *hdr) +{ + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)hdr; + + if (!ieee80211_is_action(mgmt->frame_control)) + return false; + if (mgmt->u.action.category != WLAN_CATEGORY_BACK) + return false; + return true; +} + +static void wfx_tx_manage_pm(struct wfx_vif *wvif, struct ieee80211_hdr *hdr, + struct wfx_tx_priv *tx_priv, + struct ieee80211_sta *sta) +{ + u32 mask = ~BIT(tx_priv->raw_link_id); + + spin_lock_bh(&wvif->ps_state_lock); + if (ieee80211_is_auth(hdr->frame_control)) { + wvif->sta_asleep_mask &= mask; + wvif->pspoll_mask &= mask; + } + + if (tx_priv->link_id == WFX_LINK_ID_AFTER_DTIM && + !wvif->mcast_buffered) { + wvif->mcast_buffered = true; + if (wvif->sta_asleep_mask) + schedule_work(&wvif->mcast_start_work); + } + + if (tx_priv->raw_link_id) { + wvif->link_id_db[tx_priv->raw_link_id - 1].timestamp = jiffies; + if (tx_priv->tid < WFX_MAX_TID) + wvif->link_id_db[tx_priv->raw_link_id - 1].buffered[tx_priv->tid]++; + } + spin_unlock_bh(&wvif->ps_state_lock); + + if (sta) + ieee80211_sta_set_buffered(sta, tx_priv->tid, true); +} + +static uint8_t wfx_tx_get_raw_link_id(struct wfx_vif *wvif, + struct ieee80211_sta *sta, + struct ieee80211_hdr *hdr) +{ + struct wfx_sta_priv *sta_priv = + sta ? (struct wfx_sta_priv *) &sta->drv_priv : NULL; + const u8 *da = ieee80211_get_DA(hdr); + int ret; + + if (sta_priv && sta_priv->link_id) + return sta_priv->link_id; + if (wvif->vif->type != NL80211_IFTYPE_AP) + return 0; + if (is_multicast_ether_addr(da)) + return 0; + ret = wfx_find_link_id(wvif, da); + if (!ret) + ret = wfx_alloc_link_id(wvif, da); + if (!ret) { + dev_err(wvif->wdev->dev, "no more link-id available\n"); + return WFX_LINK_ID_NO_ASSOC; + } + return ret; +} + +static void wfx_tx_fixup_rates(struct ieee80211_tx_rate *rates) +{ + int i; + bool finished; + + // Firmware is not able to mix rates with differents flags + for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { + if (rates[0].flags & IEEE80211_TX_RC_SHORT_GI) + rates[i].flags |= IEEE80211_TX_RC_SHORT_GI; + if (!(rates[0].flags & IEEE80211_TX_RC_SHORT_GI)) + rates[i].flags &= ~IEEE80211_TX_RC_SHORT_GI; + if (!(rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)) + rates[i].flags &= ~IEEE80211_TX_RC_USE_RTS_CTS; + } + + // Sort rates and remove duplicates + do { + finished = true; + for (i = 0; i < IEEE80211_TX_MAX_RATES - 1; i++) { + if (rates[i + 1].idx == rates[i].idx && + rates[i].idx != -1) { + rates[i].count = + max_t(int, rates[i].count, + rates[i + 1].count); + rates[i + 1].idx = -1; + rates[i + 1].count = 0; + + finished = false; + } + if (rates[i + 1].idx > rates[i].idx) { + swap(rates[i + 1], rates[i]); + finished = false; + } + } + } while (!finished); + // All retries use long GI + for (i = 1; i < IEEE80211_TX_MAX_RATES; i++) + rates[i].flags &= ~IEEE80211_TX_RC_SHORT_GI; +} + +static uint8_t wfx_tx_get_rate_id(struct wfx_vif *wvif, + struct ieee80211_tx_info *tx_info) +{ + bool tx_policy_renew = false; + uint8_t rate_id; + + rate_id = wfx_tx_policy_get(wvif, + tx_info->driver_rates, &tx_policy_renew); + WARN(rate_id == WFX_INVALID_RATE_ID, "unable to get a valid Tx policy"); + + if (tx_policy_renew) { + /* FIXME: It's not so optimal to stop TX queues every now and + * then. Better to reimplement task scheduling with a counter. + */ + wfx_tx_lock(wvif->wdev); + wfx_tx_queues_lock(wvif->wdev); + if (!schedule_work(&wvif->tx_policy_upload_work)) { + wfx_tx_queues_unlock(wvif->wdev); + wfx_tx_unlock(wvif->wdev); + } + } + return rate_id; +} + +static struct hif_ht_tx_parameters wfx_tx_get_tx_parms(struct wfx_dev *wdev, struct ieee80211_tx_info *tx_info) +{ + struct ieee80211_tx_rate *rate = &tx_info->driver_rates[0]; + struct hif_ht_tx_parameters ret = { }; + + if (!(rate->flags & IEEE80211_TX_RC_MCS)) + ret.frame_format = HIF_FRAME_FORMAT_NON_HT; + else if (!(rate->flags & IEEE80211_TX_RC_GREEN_FIELD)) + ret.frame_format = HIF_FRAME_FORMAT_MIXED_FORMAT_HT; + else + ret.frame_format = HIF_FRAME_FORMAT_GF_HT_11N; + if (rate->flags & IEEE80211_TX_RC_SHORT_GI) + ret.short_gi = 1; + if (tx_info->flags & IEEE80211_TX_CTL_STBC) + ret.stbc = 0; // FIXME: Not yet supported by firmware? + return ret; +} + +static uint8_t wfx_tx_get_tid(struct ieee80211_hdr *hdr) +{ + // FIXME: ieee80211_get_tid(hdr) should be sufficient for all cases. + if (!ieee80211_is_data(hdr->frame_control)) + return WFX_MAX_TID; + if (ieee80211_is_data_qos(hdr->frame_control)) + return ieee80211_get_tid(hdr); + else + return 0; +} + +static int wfx_tx_get_icv_len(struct ieee80211_key_conf *hw_key) +{ + int mic_space; + + if (!hw_key) + return 0; + mic_space = (hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) ? 8 : 0; + return hw_key->icv_len + mic_space; +} + +static int wfx_tx_inner(struct wfx_vif *wvif, struct ieee80211_sta *sta, + struct sk_buff *skb) +{ + struct hif_msg *hif_msg; + struct hif_req_tx *req; + struct wfx_tx_priv *tx_priv; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + int queue_id = tx_info->hw_queue; + size_t offset = (size_t) skb->data & 3; + int wmsg_len = sizeof(struct hif_msg) + + sizeof(struct hif_req_tx) + offset; + + WARN(queue_id >= IEEE80211_NUM_ACS, "unsupported queue_id"); + wfx_tx_fixup_rates(tx_info->driver_rates); + + // From now tx_info->control is unusable + memset(tx_info->rate_driver_data, 0, sizeof(struct wfx_tx_priv)); + // Fill tx_priv + tx_priv = (struct wfx_tx_priv *)tx_info->rate_driver_data; + tx_priv->tid = wfx_tx_get_tid(hdr); + tx_priv->raw_link_id = wfx_tx_get_raw_link_id(wvif, sta, hdr); + tx_priv->link_id = tx_priv->raw_link_id; + if (ieee80211_has_protected(hdr->frame_control)) + tx_priv->hw_key = hw_key; + if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) + tx_priv->link_id = WFX_LINK_ID_AFTER_DTIM; + if (sta && (sta->uapsd_queues & BIT(queue_id))) + tx_priv->link_id = WFX_LINK_ID_UAPSD; + + // Fill hif_msg + WARN(skb_headroom(skb) < wmsg_len, "not enough space in skb"); + WARN(offset & 1, "attempt to transmit an unaligned frame"); + skb_put(skb, wfx_tx_get_icv_len(tx_priv->hw_key)); + skb_push(skb, wmsg_len); + memset(skb->data, 0, wmsg_len); + hif_msg = (struct hif_msg *)skb->data; + hif_msg->len = cpu_to_le16(skb->len); + hif_msg->id = HIF_REQ_ID_TX; + hif_msg->interface = wvif->id; + if (skb->len > wvif->wdev->hw_caps.size_inp_ch_buf) { + dev_warn(wvif->wdev->dev, "requested frame size (%d) is larger than maximum supported (%d)\n", + skb->len, wvif->wdev->hw_caps.size_inp_ch_buf); + skb_pull(skb, wmsg_len); + return -EIO; + } + + // Fill tx request + req = (struct hif_req_tx *)hif_msg->body; + req->packet_id = queue_id << 16 | + IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)); + req->data_flags.fc_offset = offset; + req->queue_id.peer_sta_id = tx_priv->raw_link_id; + // Queue index are inverted between firmware and Linux + req->queue_id.queue_id = 3 - queue_id; + req->ht_tx_parameters = wfx_tx_get_tx_parms(wvif->wdev, tx_info); + req->tx_flags.retry_policy_index = wfx_tx_get_rate_id(wvif, tx_info); + + // Auxiliary operations + wfx_tx_manage_pm(wvif, hdr, tx_priv, sta); + wfx_tx_queue_put(wvif->wdev, &wvif->wdev->tx_queue[queue_id], skb); + wfx_bh_request_tx(wvif->wdev); + return 0; +} + +void wfx_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, + struct sk_buff *skb) +{ + struct wfx_dev *wdev = hw->priv; + struct wfx_vif *wvif; + struct ieee80211_sta *sta = control ? control->sta : NULL; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + size_t driver_data_room = FIELD_SIZEOF(struct ieee80211_tx_info, + rate_driver_data); + + compiletime_assert(sizeof(struct wfx_tx_priv) <= driver_data_room, + "struct tx_priv is too large"); + WARN(skb->next || skb->prev, "skb is already member of a list"); + // control.vif can be NULL for injected frames + if (tx_info->control.vif) + wvif = (struct wfx_vif *)tx_info->control.vif->drv_priv; + else + wvif = wvif_iterate(wdev, NULL); + if (WARN_ON(!wvif)) + goto drop; + // FIXME: why? + if (ieee80211_is_action_back(hdr)) { + dev_info(wdev->dev, "drop BA action\n"); + goto drop; + } + if (wfx_tx_inner(wvif, sta, skb)) + goto drop; + + return; + +drop: + ieee80211_tx_status_irqsafe(wdev->hw, skb); +} + +void wfx_tx_confirm_cb(struct wfx_vif *wvif, struct hif_cnf_tx *arg) +{ + int i; + int tx_count; + struct sk_buff *skb; + struct ieee80211_tx_rate *rate; + struct ieee80211_tx_info *tx_info; + const struct wfx_tx_priv *tx_priv; + + skb = wfx_pending_get(wvif->wdev, arg->packet_id); + if (!skb) { + dev_warn(wvif->wdev->dev, + "received unknown packet_id (%#.8x) from chip\n", + arg->packet_id); + return; + } + tx_info = IEEE80211_SKB_CB(skb); + tx_priv = wfx_skb_tx_priv(skb); + _trace_tx_stats(arg, skb, + wfx_pending_get_pkt_us_delay(wvif->wdev, skb)); + + // You can touch to tx_priv, but don't touch to tx_info->status. + tx_count = arg->ack_failures; + if (!arg->status || arg->ack_failures) + tx_count += 1; // Also report success + for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { + rate = &tx_info->status.rates[i]; + if (rate->idx < 0) + break; + if (tx_count < rate->count && arg->status && arg->ack_failures) + dev_dbg(wvif->wdev->dev, "all retries were not consumed: %d != %d\n", + rate->count, tx_count); + if (tx_count <= rate->count && tx_count && + arg->txed_rate != wfx_get_hw_rate(wvif->wdev, rate)) + dev_dbg(wvif->wdev->dev, + "inconsistent tx_info rates: %d != %d\n", + arg->txed_rate, + wfx_get_hw_rate(wvif->wdev, rate)); + if (tx_count > rate->count) { + tx_count -= rate->count; + } else if (!tx_count) { + rate->count = 0; + rate->idx = -1; + } else { + rate->count = tx_count; + tx_count = 0; + } + } + if (tx_count) + dev_dbg(wvif->wdev->dev, + "%d more retries than expected\n", tx_count); + skb_trim(skb, skb->len - wfx_tx_get_icv_len(tx_priv->hw_key)); + + // From now, you can touch to tx_info->status, but do not touch to + // tx_priv anymore + // FIXME: use ieee80211_tx_info_clear_status() + memset(tx_info->rate_driver_data, 0, sizeof(tx_info->rate_driver_data)); + memset(tx_info->pad, 0, sizeof(tx_info->pad)); + + if (!arg->status) { + if (wvif->bss_loss_state && + arg->packet_id == wvif->bss_loss_confirm_id) + wfx_cqm_bssloss_sm(wvif, 0, 1, 0); + tx_info->status.tx_time = + arg->media_delay - arg->tx_queue_delay; + if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) + tx_info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; + else + tx_info->flags |= IEEE80211_TX_STAT_ACK; + } else if (arg->status == HIF_REQUEUE) { + /* "REQUEUE" means "implicit suspend" */ + struct hif_ind_suspend_resume_tx suspend = { + .suspend_resume_flags.resume = 0, + .suspend_resume_flags.bc_mc_only = 1, + }; + + WARN(!arg->tx_result_flags.requeue, "incoherent status and result_flags"); + wfx_suspend_resume(wvif, &suspend); + tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; + } else { + if (wvif->bss_loss_state && + arg->packet_id == wvif->bss_loss_confirm_id) + wfx_cqm_bssloss_sm(wvif, 0, 0, 1); + } + wfx_pending_remove(wvif->wdev, skb); +} + +static void wfx_notify_buffered_tx(struct wfx_vif *wvif, struct sk_buff *skb, + struct hif_req_tx *req) +{ + struct ieee80211_sta *sta; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + int tid = wfx_tx_get_tid(hdr); + int raw_link_id = req->queue_id.peer_sta_id; + u8 *buffered; + + if (raw_link_id && tid < WFX_MAX_TID) { + buffered = wvif->link_id_db[raw_link_id - 1].buffered; + + spin_lock_bh(&wvif->ps_state_lock); + WARN(!buffered[tid], "inconsistent notification"); + buffered[tid]--; + spin_unlock_bh(&wvif->ps_state_lock); + + if (!buffered[tid]) { + rcu_read_lock(); + sta = ieee80211_find_sta(wvif->vif, hdr->addr1); + if (sta) + ieee80211_sta_set_buffered(sta, tid, false); + rcu_read_unlock(); + } + } +} + +void wfx_skb_dtor(struct wfx_dev *wdev, struct sk_buff *skb) +{ + struct hif_msg *hif = (struct hif_msg *)skb->data; + struct hif_req_tx *req = (struct hif_req_tx *)hif->body; + struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface); + unsigned int offset = sizeof(struct hif_req_tx) + + sizeof(struct hif_msg) + + req->data_flags.fc_offset; + + WARN_ON(!wvif); + skb_pull(skb, offset); + wfx_notify_buffered_tx(wvif, skb, req); + wfx_tx_policy_put(wvif, req->tx_flags.retry_policy_index); + ieee80211_tx_status_irqsafe(wdev->hw, skb); +} diff --git a/drivers/staging/wfx/data_tx.h b/drivers/staging/wfx/data_tx.h new file mode 100644 index 000000000000..f74d1988925d --- /dev/null +++ b/drivers/staging/wfx/data_tx.h @@ -0,0 +1,93 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Datapath implementation. + * + * Copyright (c) 2017-2019, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#ifndef WFX_DATA_TX_H +#define WFX_DATA_TX_H + +#include <linux/list.h> +#include <net/mac80211.h> + +#include "hif_api_cmd.h" +#include "hif_api_mib.h" + +// FIXME: use IEEE80211_NUM_TIDS +#define WFX_MAX_TID 8 + +struct wfx_tx_priv; +struct wfx_dev; +struct wfx_vif; + +enum wfx_link_status { + WFX_LINK_OFF, + WFX_LINK_RESERVE, + WFX_LINK_SOFT, + WFX_LINK_HARD, +}; + +struct wfx_link_entry { + unsigned long timestamp; + enum wfx_link_status status; + uint8_t mac[ETH_ALEN]; + uint8_t old_mac[ETH_ALEN]; + uint8_t buffered[WFX_MAX_TID]; + struct sk_buff_head rx_queue; +}; + +struct tx_policy { + struct list_head link; + uint8_t rates[12]; + uint8_t usage_count; + uint8_t uploaded; +}; + +struct tx_policy_cache { + struct tx_policy cache[HIF_MIB_NUM_TX_RATE_RETRY_POLICIES]; + // FIXME: use a trees and drop hash from tx_policy + struct list_head used; + struct list_head free; + spinlock_t lock; +}; + +struct wfx_tx_priv { + ktime_t xmit_timestamp; + struct ieee80211_key_conf *hw_key; + uint8_t link_id; + uint8_t raw_link_id; + uint8_t tid; +} __packed; + +void wfx_tx_policy_init(struct wfx_vif *wvif); + +void wfx_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, + struct sk_buff *skb); +void wfx_tx_confirm_cb(struct wfx_vif *wvif, struct hif_cnf_tx *arg); +void wfx_skb_dtor(struct wfx_dev *wdev, struct sk_buff *skb); + +int wfx_unmap_link(struct wfx_vif *wvif, int link_id); +void wfx_link_id_work(struct work_struct *work); +void wfx_link_id_gc_work(struct work_struct *work); +int wfx_find_link_id(struct wfx_vif *wvif, const u8 *mac); + +static inline struct wfx_tx_priv *wfx_skb_tx_priv(struct sk_buff *skb) +{ + struct ieee80211_tx_info *tx_info; + + if (!skb) + return NULL; + tx_info = IEEE80211_SKB_CB(skb); + return (struct wfx_tx_priv *)tx_info->rate_driver_data; +} + +static inline struct hif_req_tx *wfx_skb_txreq(struct sk_buff *skb) +{ + struct hif_msg *hif = (struct hif_msg *)skb->data; + struct hif_req_tx *req = (struct hif_req_tx *) hif->body; + + return req; +} + +#endif /* WFX_DATA_TX_H */ diff --git a/drivers/staging/wfx/debug.c b/drivers/staging/wfx/debug.c new file mode 100644 index 000000000000..0a9ca109039c --- /dev/null +++ b/drivers/staging/wfx/debug.c @@ -0,0 +1,306 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Debugfs interface. + * + * Copyright (c) 2017-2019, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include <linux/debugfs.h> +#include <linux/seq_file.h> +#include <linux/crc32.h> + +#include "debug.h" +#include "wfx.h" +#include "sta.h" +#include "main.h" +#include "hif_tx.h" +#include "hif_tx_mib.h" + +#define CREATE_TRACE_POINTS +#include "traces.h" + +static const struct trace_print_flags hif_msg_print_map[] = { + hif_msg_list, +}; + +static const struct trace_print_flags hif_mib_print_map[] = { + hif_mib_list, +}; + +static const struct trace_print_flags wfx_reg_print_map[] = { + wfx_reg_list, +}; + +static const char *get_symbol(unsigned long val, + const struct trace_print_flags *symbol_array) +{ + int i; + + for (i = 0; symbol_array[i].mask != -1; i++) { + if (val == symbol_array[i].mask) + return symbol_array[i].name; + } + + return "unknown"; +} + +const char *get_hif_name(unsigned long id) +{ + return get_symbol(id, hif_msg_print_map); +} + +const char *get_mib_name(unsigned long id) +{ + return get_symbol(id, hif_mib_print_map); +} + +const char *get_reg_name(unsigned long id) +{ + return get_symbol(id, wfx_reg_print_map); +} + +static int wfx_counters_show(struct seq_file *seq, void *v) +{ + int ret; + struct wfx_dev *wdev = seq->private; + struct hif_mib_extended_count_table counters; + + ret = hif_get_counters_table(wdev, &counters); + if (ret < 0) + return ret; + if (ret > 0) + return -EIO; + +#define PUT_COUNTER(name) \ + seq_printf(seq, "%24s %d\n", #name ":", le32_to_cpu(counters.count_##name)) + + PUT_COUNTER(tx_packets); + PUT_COUNTER(tx_multicast_frames); + PUT_COUNTER(tx_frames_success); + PUT_COUNTER(tx_frame_failures); + PUT_COUNTER(tx_frames_retried); + PUT_COUNTER(tx_frames_multi_retried); + + PUT_COUNTER(rts_success); + PUT_COUNTER(rts_failures); + PUT_COUNTER(ack_failures); + + PUT_COUNTER(rx_packets); + PUT_COUNTER(rx_frames_success); + PUT_COUNTER(rx_packet_errors); + PUT_COUNTER(plcp_errors); + PUT_COUNTER(fcs_errors); + PUT_COUNTER(rx_decryption_failures); + PUT_COUNTER(rx_mic_failures); + PUT_COUNTER(rx_no_key_failures); + PUT_COUNTER(rx_frame_duplicates); + PUT_COUNTER(rx_multicast_frames); + PUT_COUNTER(rx_cmacicv_errors); + PUT_COUNTER(rx_cmac_replays); + PUT_COUNTER(rx_mgmt_ccmp_replays); + + PUT_COUNTER(rx_beacon); + PUT_COUNTER(miss_beacon); + +#undef PUT_COUNTER + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(wfx_counters); + +static const char * const channel_names[] = { + [0] = "1M", + [1] = "2M", + [2] = "5.5M", + [3] = "11M", + /* Entries 4 and 5 does not exist */ + [6] = "6M", + [7] = "9M", + [8] = "12M", + [9] = "18M", + [10] = "24M", + [11] = "36M", + [12] = "48M", + [13] = "54M", + [14] = "MCS0", + [15] = "MCS1", + [16] = "MCS2", + [17] = "MCS3", + [18] = "MCS4", + [19] = "MCS5", + [20] = "MCS6", + [21] = "MCS7", +}; + +static int wfx_rx_stats_show(struct seq_file *seq, void *v) +{ + struct wfx_dev *wdev = seq->private; + struct hif_rx_stats *st = &wdev->rx_stats; + int i; + + mutex_lock(&wdev->rx_stats_lock); + seq_printf(seq, "Timestamp: %dus\n", st->date); + seq_printf(seq, "Low power clock: frequency %uHz, external %s\n", + st->pwr_clk_freq, + st->is_ext_pwr_clk ? "yes" : "no"); + seq_printf(seq, + "N. of frames: %d, PER (x10e4): %d, Throughput: %dKbps/s\n", + st->nb_rx_frame, st->per_total, st->throughput); + seq_puts(seq, " Num. of PER RSSI SNR CFO\n"); + seq_puts(seq, " frames (x10e4) (dBm) (dB) (kHz)\n"); + for (i = 0; i < ARRAY_SIZE(channel_names); i++) { + if (channel_names[i]) + seq_printf(seq, "%5s %8d %8d %8d %8d %8d\n", + channel_names[i], st->nb_rx_by_rate[i], + st->per[i], st->rssi[i] / 100, + st->snr[i] / 100, st->cfo[i]); + } + mutex_unlock(&wdev->rx_stats_lock); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(wfx_rx_stats); + +static ssize_t wfx_send_pds_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wfx_dev *wdev = file->private_data; + char *buf; + int ret; + + if (*ppos != 0) { + dev_dbg(wdev->dev, "PDS data must be written in one transaction"); + return -EBUSY; + } + buf = memdup_user(user_buf, count); + if (IS_ERR(buf)) + return PTR_ERR(buf); + *ppos = *ppos + count; + ret = wfx_send_pds(wdev, buf, count); + kfree(buf); + if (ret < 0) + return ret; + return count; +} + +static const struct file_operations wfx_send_pds_fops = { + .open = simple_open, + .write = wfx_send_pds_write, +}; + +static ssize_t wfx_burn_slk_key_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wfx_dev *wdev = file->private_data; + + dev_info(wdev->dev, "this driver does not support secure link\n"); + return -EINVAL; +} + +static const struct file_operations wfx_burn_slk_key_fops = { + .open = simple_open, + .write = wfx_burn_slk_key_write, +}; + +struct dbgfs_hif_msg { + struct wfx_dev *wdev; + struct completion complete; + u8 reply[1024]; + int ret; +}; + +static ssize_t wfx_send_hif_msg_write(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct dbgfs_hif_msg *context = file->private_data; + struct wfx_dev *wdev = context->wdev; + struct hif_msg *request; + + if (completion_done(&context->complete)) { + dev_dbg(wdev->dev, "read previous result before start a new one\n"); + return -EBUSY; + } + if (count < sizeof(struct hif_msg)) + return -EINVAL; + + // wfx_cmd_send() chekc that reply buffer is wide enough, but do not + // return precise length read. User have to know how many bytes should + // be read. Filling reply buffer with a memory pattern may help user. + memset(context->reply, 0xFF, sizeof(context->reply)); + request = memdup_user(user_buf, count); + if (IS_ERR(request)) + return PTR_ERR(request); + if (request->len != count) { + kfree(request); + return -EINVAL; + } + context->ret = wfx_cmd_send(wdev, request, context->reply, sizeof(context->reply), false); + + kfree(request); + complete(&context->complete); + return count; +} + +static ssize_t wfx_send_hif_msg_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct dbgfs_hif_msg *context = file->private_data; + int ret; + + if (count > sizeof(context->reply)) + return -EINVAL; + ret = wait_for_completion_interruptible(&context->complete); + if (ret) + return ret; + if (context->ret < 0) + return context->ret; + // Be carefull, write() is waiting for a full message while read() + // only return a payload + if (copy_to_user(user_buf, context->reply, count)) + return -EFAULT; + + return count; +} + +static int wfx_send_hif_msg_open(struct inode *inode, struct file *file) +{ + struct dbgfs_hif_msg *context = kzalloc(sizeof(*context), GFP_KERNEL); + + if (!context) + return -ENOMEM; + context->wdev = inode->i_private; + init_completion(&context->complete); + file->private_data = context; + return 0; +} + +static int wfx_send_hif_msg_release(struct inode *inode, struct file *file) +{ + struct dbgfs_hif_msg *context = file->private_data; + + kfree(context); + return 0; +} + +static const struct file_operations wfx_send_hif_msg_fops = { + .open = wfx_send_hif_msg_open, + .release = wfx_send_hif_msg_release, + .write = wfx_send_hif_msg_write, + .read = wfx_send_hif_msg_read, +}; + +int wfx_debug_init(struct wfx_dev *wdev) +{ + struct dentry *d; + + d = debugfs_create_dir("wfx", wdev->hw->wiphy->debugfsdir); + debugfs_create_file("counters", 0444, d, wdev, &wfx_counters_fops); + debugfs_create_file("rx_stats", 0444, d, wdev, &wfx_rx_stats_fops); + debugfs_create_file("send_pds", 0200, d, wdev, &wfx_send_pds_fops); + debugfs_create_file("burn_slk_key", 0200, d, wdev, &wfx_burn_slk_key_fops); + debugfs_create_file("send_hif_msg", 0600, d, wdev, &wfx_send_hif_msg_fops); + + return 0; +} diff --git a/drivers/staging/wfx/debug.h b/drivers/staging/wfx/debug.h new file mode 100644 index 000000000000..6f2f84d64c9e --- /dev/null +++ b/drivers/staging/wfx/debug.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Debugfs interface. + * + * Copyright (c) 2017-2019, Silicon Laboratories, Inc. + * Copyright (c) 2011, ST-Ericsson + */ +#ifndef WFX_DEBUG_H +#define WFX_DEBUG_H + +struct wfx_dev; + +int wfx_debug_init(struct wfx_dev *wdev); + +const char *get_hif_name(unsigned long id); +const char *get_mib_name(unsigned long id); +const char *get_reg_name(unsigned long id); + +#endif /* WFX_DEBUG_H */ diff --git a/drivers/staging/wfx/fwio.c b/drivers/staging/wfx/fwio.c new file mode 100644 index 000000000000..6d82c6244c7f --- /dev/null +++ b/drivers/staging/wfx/fwio.c @@ -0,0 +1,388 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Firmware loading. + * + * Copyright (c) 2017-2019, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include <linux/firmware.h> +#include <linux/slab.h> +#include <linux/mm.h> +#include <linux/bitfield.h> + +#include "fwio.h" +#include "wfx.h" +#include "hwio.h" + +// Addresses below are in SRAM area +#define WFX_DNLD_FIFO 0x09004000 +#define DNLD_BLOCK_SIZE 0x0400 +#define DNLD_FIFO_SIZE 0x8000 // (32 * DNLD_BLOCK_SIZE) +// Download Control Area (DCA) +#define WFX_DCA_IMAGE_SIZE 0x0900C000 +#define WFX_DCA_PUT 0x0900C004 +#define WFX_DCA_GET 0x0900C008 +#define WFX_DCA_HOST_STATUS 0x0900C00C +#define HOST_READY 0x87654321 +#define HOST_INFO_READ 0xA753BD99 +#define HOST_UPLOAD_PENDING 0xABCDDCBA +#define HOST_UPLOAD_COMPLETE 0xD4C64A99 +#define HOST_OK_TO_JUMP 0x174FC882 +#define WFX_DCA_NCP_STATUS 0x0900C010 +#define NCP_NOT_READY 0x12345678 +#define NCP_READY 0x87654321 +#define NCP_INFO_READY 0xBD53EF99 +#define NCP_DOWNLOAD_PENDING 0xABCDDCBA +#define NCP_DOWNLOAD_COMPLETE 0xCAFEFECA +#define NCP_AUTH_OK 0xD4C64A99 +#define NCP_AUTH_FAIL 0x174FC882 +#define NCP_PUB_KEY_RDY 0x7AB41D19 +#define WFX_DCA_FW_SIGNATURE 0x0900C014 +#define FW_SIGNATURE_SIZE 0x40 +#define WFX_DCA_FW_HASH 0x0900C054 +#define FW_HASH_SIZE 0x08 +#define WFX_DCA_FW_VERSION 0x0900C05C +#define FW_VERSION_SIZE 0x04 +#define WFX_DCA_RESERVED 0x0900C060 +#define DCA_RESERVED_SIZE 0x20 +#define WFX_STATUS_INFO 0x0900C080 +#define WFX_BOOTLOADER_LABEL 0x0900C084 +#define BOOTLOADER_LABEL_SIZE 0x3C +#define WFX_PTE_INFO 0x0900C0C0 +#define PTE_INFO_KEYSET_IDX 0x0D +#define PTE_INFO_SIZE 0x10 +#define WFX_ERR_INFO 0x0900C0D0 +#define ERR_INVALID_SEC_TYPE 0x05 +#define ERR_SIG_VERIF_FAILED 0x0F +#define ERR_AES_CTRL_KEY 0x10 +#define ERR_ECC_PUB_KEY 0x11 +#define ERR_MAC_KEY 0x18 + +#define DCA_TIMEOUT 50 // milliseconds +#define WAKEUP_TIMEOUT 200 // milliseconds + +static const char * const fwio_error_strings[] = { + [ERR_INVALID_SEC_TYPE] = "Invalid section type or wrong encryption", + [ERR_SIG_VERIF_FAILED] = "Signature verification failed", + [ERR_AES_CTRL_KEY] = "AES control key not initialized", + [ERR_ECC_PUB_KEY] = "ECC public key not initialized", + [ERR_MAC_KEY] = "MAC key not initialized", +}; + +/* + * request_firmware() allocate data using vmalloc(). It is not compatible with + * underlying hardware that use DMA. Function below detect this case and + * allocate a bounce buffer if necessary. + * + * Notice that, in doubt, you can enable CONFIG_DEBUG_SG to ask kernel to + * detect this problem at runtime (else, kernel silently fail). + * + * NOTE: it may also be possible to use 'pages' from struct firmware and avoid + * bounce buffer + */ +static int sram_write_dma_safe(struct wfx_dev *wdev, u32 addr, const u8 *buf, + size_t len) +{ + int ret; + const u8 *tmp; + + if (!virt_addr_valid(buf)) { + tmp = kmemdup(buf, len, GFP_KERNEL); + if (!tmp) + return -ENOMEM; + } else { + tmp = buf; + } + ret = sram_buf_write(wdev, addr, tmp, len); + if (!virt_addr_valid(buf)) + kfree(tmp); + return ret; +} + +int get_firmware(struct wfx_dev *wdev, u32 keyset_chip, + const struct firmware **fw, int *file_offset) +{ + int keyset_file; + char filename[256]; + const char *data; + int ret; + + snprintf(filename, sizeof(filename), "%s_%02X.sec", wdev->pdata.file_fw, keyset_chip); + ret = firmware_request_nowarn(fw, filename, wdev->dev); + if (ret) { + dev_info(wdev->dev, "can't load %s, falling back to %s.sec\n", filename, wdev->pdata.file_fw); + snprintf(filename, sizeof(filename), "%s.sec", wdev->pdata.file_fw); + ret = request_firmware(fw, filename, wdev->dev); + if (ret) { + dev_err(wdev->dev, "can't load %s\n", filename); + *fw = NULL; + return ret; + } + } + + data = (*fw)->data; + if (memcmp(data, "KEYSET", 6) != 0) { + // Legacy firmware format + *file_offset = 0; + keyset_file = 0x90; + } else { + *file_offset = 8; + keyset_file = (hex_to_bin(data[6]) * 16) | hex_to_bin(data[7]); + if (keyset_file < 0) { + dev_err(wdev->dev, "%s corrupted\n", filename); + release_firmware(*fw); + *fw = NULL; + return -EINVAL; + } + } + if (keyset_file != keyset_chip) { + dev_err(wdev->dev, "firmware keyset is incompatible with chip (file: 0x%02X, chip: 0x%02X)\n", + keyset_file, keyset_chip); + release_firmware(*fw); + *fw = NULL; + return -ENODEV; + } + wdev->keyset = keyset_file; + return 0; +} + +static int wait_ncp_status(struct wfx_dev *wdev, u32 status) +{ + ktime_t now, start; + u32 reg; + int ret; + + start = ktime_get(); + for (;;) { + ret = sram_reg_read(wdev, WFX_DCA_NCP_STATUS, ®); + if (ret < 0) + return -EIO; + now = ktime_get(); + if (reg == status) + break; + if (ktime_after(now, ktime_add_ms(start, DCA_TIMEOUT))) + return -ETIMEDOUT; + } + if (ktime_compare(now, start)) + dev_dbg(wdev->dev, "chip answer after %lldus\n", ktime_us_delta(now, start)); + else + dev_dbg(wdev->dev, "chip answer immediately\n"); + return 0; +} + +static int upload_firmware(struct wfx_dev *wdev, const u8 *data, size_t len) +{ + int ret; + u32 offs, bytes_done; + ktime_t now, start; + + if (len % DNLD_BLOCK_SIZE) { + dev_err(wdev->dev, "firmware size is not aligned. Buffer overrun will occur\n"); + return -EIO; + } + offs = 0; + while (offs < len) { + start = ktime_get(); + for (;;) { + ret = sram_reg_read(wdev, WFX_DCA_GET, &bytes_done); + if (ret < 0) + return ret; + now = ktime_get(); + if (offs + DNLD_BLOCK_SIZE - bytes_done < DNLD_FIFO_SIZE) + break; + if (ktime_after(now, ktime_add_ms(start, DCA_TIMEOUT))) + return -ETIMEDOUT; + } + if (ktime_compare(now, start)) + dev_dbg(wdev->dev, "answer after %lldus\n", ktime_us_delta(now, start)); + + ret = sram_write_dma_safe(wdev, WFX_DNLD_FIFO + (offs % DNLD_FIFO_SIZE), + data + offs, DNLD_BLOCK_SIZE); + if (ret < 0) + return ret; + + // WFx seems to not support writing 0 in this register during + // first loop + offs += DNLD_BLOCK_SIZE; + ret = sram_reg_write(wdev, WFX_DCA_PUT, offs); + if (ret < 0) + return ret; + } + return 0; +} + +static void print_boot_status(struct wfx_dev *wdev) +{ + u32 val32; + + sram_reg_read(wdev, WFX_STATUS_INFO, &val32); + if (val32 == 0x12345678) { + dev_info(wdev->dev, "no error reported by secure boot\n"); + } else { + sram_reg_read(wdev, WFX_ERR_INFO, &val32); + if (val32 < ARRAY_SIZE(fwio_error_strings) && fwio_error_strings[val32]) + dev_info(wdev->dev, "secure boot error: %s\n", fwio_error_strings[val32]); + else + dev_info(wdev->dev, "secure boot error: Unknown (0x%02x)\n", val32); + } +} + +static int load_firmware_secure(struct wfx_dev *wdev) +{ + const struct firmware *fw = NULL; + int header_size; + int fw_offset; + ktime_t start; + u8 *buf; + int ret; + + BUILD_BUG_ON(PTE_INFO_SIZE > BOOTLOADER_LABEL_SIZE); + buf = kmalloc(BOOTLOADER_LABEL_SIZE + 1, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + sram_reg_write(wdev, WFX_DCA_HOST_STATUS, HOST_READY); + ret = wait_ncp_status(wdev, NCP_INFO_READY); + if (ret) + goto error; + + sram_buf_read(wdev, WFX_BOOTLOADER_LABEL, buf, BOOTLOADER_LABEL_SIZE); + buf[BOOTLOADER_LABEL_SIZE] = 0; + dev_dbg(wdev->dev, "bootloader: \"%s\"\n", buf); + + sram_buf_read(wdev, WFX_PTE_INFO, buf, PTE_INFO_SIZE); + ret = get_firmware(wdev, buf[PTE_INFO_KEYSET_IDX], &fw, &fw_offset); + if (ret) + goto error; + header_size = fw_offset + FW_SIGNATURE_SIZE + FW_HASH_SIZE; + + sram_reg_write(wdev, WFX_DCA_HOST_STATUS, HOST_INFO_READ); + ret = wait_ncp_status(wdev, NCP_READY); + if (ret) + goto error; + + sram_reg_write(wdev, WFX_DNLD_FIFO, 0xFFFFFFFF); // Fifo init + sram_write_dma_safe(wdev, WFX_DCA_FW_VERSION, "\x01\x00\x00\x00", FW_VERSION_SIZE); + sram_write_dma_safe(wdev, WFX_DCA_FW_SIGNATURE, fw->data + fw_offset, FW_SIGNATURE_SIZE); + sram_write_dma_safe(wdev, WFX_DCA_FW_HASH, fw->data + fw_offset + FW_SIGNATURE_SIZE, FW_HASH_SIZE); + sram_reg_write(wdev, WFX_DCA_IMAGE_SIZE, fw->size - header_size); + sram_reg_write(wdev, WFX_DCA_HOST_STATUS, HOST_UPLOAD_PENDING); + ret = wait_ncp_status(wdev, NCP_DOWNLOAD_PENDING); + if (ret) + goto error; + + start = ktime_get(); + ret = upload_firmware(wdev, fw->data + header_size, fw->size - header_size); + if (ret) + goto error; + dev_dbg(wdev->dev, "firmware load after %lldus\n", ktime_us_delta(ktime_get(), start)); + + sram_reg_write(wdev, WFX_DCA_HOST_STATUS, HOST_UPLOAD_COMPLETE); + ret = wait_ncp_status(wdev, NCP_AUTH_OK); + // Legacy ROM support + if (ret < 0) + ret = wait_ncp_status(wdev, NCP_PUB_KEY_RDY); + if (ret < 0) + goto error; + sram_reg_write(wdev, WFX_DCA_HOST_STATUS, HOST_OK_TO_JUMP); + +error: + kfree(buf); + if (fw) + release_firmware(fw); + if (ret) + print_boot_status(wdev); + return ret; +} + +static int init_gpr(struct wfx_dev *wdev) +{ + int ret, i; + static const struct { + int index; + u32 value; + } gpr_init[] = { + { 0x07, 0x208775 }, + { 0x08, 0x2EC020 }, + { 0x09, 0x3C3C3C }, + { 0x0B, 0x322C44 }, + { 0x0C, 0xA06497 }, + }; + + for (i = 0; i < ARRAY_SIZE(gpr_init); i++) { + ret = igpr_reg_write(wdev, gpr_init[i].index, gpr_init[i].value); + if (ret < 0) + return ret; + dev_dbg(wdev->dev, " index %02x: %08x\n", gpr_init[i].index, gpr_init[i].value); + } + return 0; +} + +int wfx_init_device(struct wfx_dev *wdev) +{ + int ret; + int hw_revision, hw_type; + int wakeup_timeout = 50; // ms + ktime_t now, start; + u32 reg; + + reg = CFG_DIRECT_ACCESS_MODE | CFG_CPU_RESET | CFG_WORD_MODE2; + if (wdev->pdata.use_rising_clk) + reg |= CFG_CLK_RISE_EDGE; + ret = config_reg_write(wdev, reg); + if (ret < 0) { + dev_err(wdev->dev, "bus returned an error during first write access. Host configuration error?\n"); + return -EIO; + } + + ret = config_reg_read(wdev, ®); + if (ret < 0) { + dev_err(wdev->dev, "bus returned an error during first read access. Bus configuration error?\n"); + return -EIO; + } + if (reg == 0 || reg == ~0) { + dev_err(wdev->dev, "chip mute. Bus configuration error or chip wasn't reset?\n"); + return -EIO; + } + dev_dbg(wdev->dev, "initial config register value: %08x\n", reg); + + hw_revision = FIELD_GET(CFG_DEVICE_ID_MAJOR, reg); + if (hw_revision == 0 || hw_revision > 2) { + dev_err(wdev->dev, "bad hardware revision number: %d\n", hw_revision); + return -ENODEV; + } + hw_type = FIELD_GET(CFG_DEVICE_ID_TYPE, reg); + if (hw_type == 1) { + dev_notice(wdev->dev, "development hardware detected\n"); + wakeup_timeout = 2000; + } + + ret = init_gpr(wdev); + if (ret < 0) + return ret; + + ret = control_reg_write(wdev, CTRL_WLAN_WAKEUP); + if (ret < 0) + return -EIO; + start = ktime_get(); + for (;;) { + ret = control_reg_read(wdev, ®); + now = ktime_get(); + if (reg & CTRL_WLAN_READY) + break; + if (ktime_after(now, ktime_add_ms(start, wakeup_timeout))) { + dev_err(wdev->dev, "chip didn't wake up. Chip wasn't reset?\n"); + return -ETIMEDOUT; + } + } + dev_dbg(wdev->dev, "chip wake up after %lldus\n", ktime_us_delta(now, start)); + + ret = config_reg_write_bits(wdev, CFG_CPU_RESET, 0); + if (ret < 0) + return ret; + ret = load_firmware_secure(wdev); + if (ret < 0) + return ret; + ret = config_reg_write_bits(wdev, CFG_DIRECT_ACCESS_MODE | CFG_IRQ_ENABLE_DATA | CFG_IRQ_ENABLE_WRDY, CFG_IRQ_ENABLE_DATA); + return ret; +} diff --git a/drivers/staging/wfx/fwio.h b/drivers/staging/wfx/fwio.h new file mode 100644 index 000000000000..6028f92503fe --- /dev/null +++ b/drivers/staging/wfx/fwio.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Firmware loading. + * + * Copyright (c) 2017-2019, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#ifndef WFX_FWIO_H +#define WFX_FWIO_H + +struct wfx_dev; + +int wfx_init_device(struct wfx_dev *wdev); + +#endif /* WFX_FWIO_H */ diff --git a/drivers/staging/wfx/hif_api_cmd.h b/drivers/staging/wfx/hif_api_cmd.h new file mode 100644 index 000000000000..7c5d1ea6098d --- /dev/null +++ b/drivers/staging/wfx/hif_api_cmd.h @@ -0,0 +1,681 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * WFx hardware interface definitions + * + * Copyright (c) 2018-2019, Silicon Laboratories Inc. + */ + +#ifndef WFX_HIF_API_CMD_H +#define WFX_HIF_API_CMD_H + +#include "hif_api_general.h" + +#define HIF_NUM_AC 4 + +#define HIF_API_SSID_SIZE API_SSID_SIZE + +enum hif_requests_ids { + HIF_REQ_ID_RESET = 0x0a, + HIF_REQ_ID_READ_MIB = 0x05, + HIF_REQ_ID_WRITE_MIB = 0x06, + HIF_REQ_ID_START_SCAN = 0x07, + HIF_REQ_ID_STOP_SCAN = 0x08, + HIF_REQ_ID_TX = 0x04, + HIF_REQ_ID_JOIN = 0x0b, + HIF_REQ_ID_SET_PM_MODE = 0x10, + HIF_REQ_ID_SET_BSS_PARAMS = 0x11, + HIF_REQ_ID_ADD_KEY = 0x0c, + HIF_REQ_ID_REMOVE_KEY = 0x0d, + HIF_REQ_ID_EDCA_QUEUE_PARAMS = 0x13, + HIF_REQ_ID_START = 0x17, + HIF_REQ_ID_BEACON_TRANSMIT = 0x18, + HIF_REQ_ID_UPDATE_IE = 0x1b, + HIF_REQ_ID_MAP_LINK = 0x1c, +}; + +enum hif_confirmations_ids { + HIF_CNF_ID_RESET = 0x0a, + HIF_CNF_ID_READ_MIB = 0x05, + HIF_CNF_ID_WRITE_MIB = 0x06, + HIF_CNF_ID_START_SCAN = 0x07, + HIF_CNF_ID_STOP_SCAN = 0x08, + HIF_CNF_ID_TX = 0x04, + HIF_CNF_ID_MULTI_TRANSMIT = 0x1e, + HIF_CNF_ID_JOIN = 0x0b, + HIF_CNF_ID_SET_PM_MODE = 0x10, + HIF_CNF_ID_SET_BSS_PARAMS = 0x11, + HIF_CNF_ID_ADD_KEY = 0x0c, + HIF_CNF_ID_REMOVE_KEY = 0x0d, + HIF_CNF_ID_EDCA_QUEUE_PARAMS = 0x13, + HIF_CNF_ID_START = 0x17, + HIF_CNF_ID_BEACON_TRANSMIT = 0x18, + HIF_CNF_ID_UPDATE_IE = 0x1b, + HIF_CNF_ID_MAP_LINK = 0x1c, +}; + +enum hif_indications_ids { + HIF_IND_ID_RX = 0x84, + HIF_IND_ID_SCAN_CMPL = 0x86, + HIF_IND_ID_JOIN_COMPLETE = 0x8f, + HIF_IND_ID_SET_PM_MODE_CMPL = 0x89, + HIF_IND_ID_SUSPEND_RESUME_TX = 0x8c, + HIF_IND_ID_EVENT = 0x85 +}; + +union hif_commands_ids { + enum hif_requests_ids request; + enum hif_confirmations_ids confirmation; + enum hif_indications_ids indication; +}; + +enum hif_status { + HIF_STATUS_SUCCESS = 0x0, + HIF_STATUS_FAILURE = 0x1, + HIF_INVALID_PARAMETER = 0x2, + HIF_STATUS_WARNING = 0x3, + HIF_ERROR_UNSUPPORTED_MSG_ID = 0x4, + HIF_STATUS_DECRYPTFAILURE = 0x10, + HIF_STATUS_MICFAILURE = 0x11, + HIF_STATUS_NO_KEY_FOUND = 0x12, + HIF_STATUS_RETRY_EXCEEDED = 0x13, + HIF_STATUS_TX_LIFETIME_EXCEEDED = 0x14, + HIF_REQUEUE = 0x15, + HIF_STATUS_REFUSED = 0x16, + HIF_STATUS_BUSY = 0x17 +}; + +struct hif_reset_flags { + uint8_t reset_stat:1; + uint8_t reset_all_int:1; + uint8_t reserved1:6; + uint8_t reserved2[3]; +} __packed; + +struct hif_req_reset { + struct hif_reset_flags reset_flags; +} __packed; + +struct hif_cnf_reset { + uint32_t status; +} __packed; + +struct hif_req_read_mib { + uint16_t mib_id; + uint16_t reserved; +} __packed; + +struct hif_cnf_read_mib { + uint32_t status; + uint16_t mib_id; + uint16_t length; + uint8_t mib_data[]; +} __packed; + +struct hif_req_write_mib { + uint16_t mib_id; + uint16_t length; + uint8_t mib_data[]; +} __packed; + +struct hif_cnf_write_mib { + uint32_t status; +} __packed; + +struct hif_ie_flags { + uint8_t beacon:1; + uint8_t probe_resp:1; + uint8_t probe_req:1; + uint8_t reserved1:5; + uint8_t reserved2; +} __packed; + +struct hif_ie_tlv { + uint8_t type; + uint8_t length; + uint8_t data[]; +} __packed; + +struct hif_req_update_ie { + struct hif_ie_flags ie_flags; + uint16_t num_i_es; + struct hif_ie_tlv ie[]; +} __packed; + +struct hif_cnf_update_ie { + uint32_t status; +} __packed; + +struct hif_scan_type { + uint8_t type:1; + uint8_t mode:1; + uint8_t reserved:6; +} __packed; + +struct hif_scan_flags { + uint8_t fbg:1; + uint8_t reserved1:1; + uint8_t pre:1; + uint8_t reserved2:5; +} __packed; + +struct hif_auto_scan_param { + uint16_t interval; + uint8_t reserved; + int8_t rssi_thr; +} __packed; + +struct hif_ssid_def { + uint32_t ssid_length; + uint8_t ssid[HIF_API_SSID_SIZE]; +} __packed; + +#define HIF_API_MAX_NB_SSIDS 2 +#define HIF_API_MAX_NB_CHANNELS 14 + +struct hif_req_start_scan { + uint8_t band; + struct hif_scan_type scan_type; + struct hif_scan_flags scan_flags; + uint8_t max_transmit_rate; + struct hif_auto_scan_param auto_scan_param; + uint8_t num_of_probe_requests; + uint8_t probe_delay; + uint8_t num_of_ssi_ds; + uint8_t num_of_channels; + uint32_t min_channel_time; + uint32_t max_channel_time; + int32_t tx_power_level; + uint8_t ssid_and_channel_lists[]; +} __packed; + +struct hif_start_scan_req_cstnbssid_body { + uint8_t band; + struct hif_scan_type scan_type; + struct hif_scan_flags scan_flags; + uint8_t max_transmit_rate; + struct hif_auto_scan_param auto_scan_param; + uint8_t num_of_probe_requests; + uint8_t probe_delay; + uint8_t num_of_ssi_ds; + uint8_t num_of_channels; + uint32_t min_channel_time; + uint32_t max_channel_time; + int32_t tx_power_level; + struct hif_ssid_def ssid_def[HIF_API_MAX_NB_SSIDS]; + uint8_t channel_list[]; +} __packed; + +struct hif_cnf_start_scan { + uint32_t status; +} __packed; + +struct hif_cnf_stop_scan { + uint32_t status; +} __packed; + +enum hif_pm_mode_status { + HIF_PM_MODE_ACTIVE = 0x0, + HIF_PM_MODE_PS = 0x1, + HIF_PM_MODE_UNDETERMINED = 0x2 +}; + +struct hif_ind_scan_cmpl { + uint32_t status; + uint8_t pm_mode; + uint8_t num_channels_completed; + uint16_t reserved; +} __packed; + +enum hif_queue_id { + HIF_QUEUE_ID_BACKGROUND = 0x0, + HIF_QUEUE_ID_BESTEFFORT = 0x1, + HIF_QUEUE_ID_VIDEO = 0x2, + HIF_QUEUE_ID_VOICE = 0x3 +}; + +enum hif_frame_format { + HIF_FRAME_FORMAT_NON_HT = 0x0, + HIF_FRAME_FORMAT_MIXED_FORMAT_HT = 0x1, + HIF_FRAME_FORMAT_GF_HT_11N = 0x2 +}; + +enum hif_stbc { + HIF_STBC_NOT_ALLOWED = 0x0, + HIF_STBC_ALLOWED = 0x1 +}; + +struct hif_queue { + uint8_t queue_id:2; + uint8_t peer_sta_id:4; + uint8_t reserved:2; +} __packed; + +struct hif_data_flags { + uint8_t more:1; + uint8_t fc_offset:3; + uint8_t reserved:4; +} __packed; + +struct hif_tx_flags { + uint8_t start_exp:1; + uint8_t reserved:3; + uint8_t retry_policy_index:4; +} __packed; + +struct hif_ht_tx_parameters { + uint8_t frame_format:4; + uint8_t fec_coding:1; + uint8_t short_gi:1; + uint8_t reserved1:1; + uint8_t stbc:1; + uint8_t reserved2; + uint8_t aggregation:1; + uint8_t reserved3:7; + uint8_t reserved4; +} __packed; + +struct hif_req_tx { + uint32_t packet_id; + uint8_t max_tx_rate; + struct hif_queue queue_id; + struct hif_data_flags data_flags; + struct hif_tx_flags tx_flags; + uint32_t reserved; + uint32_t expire_time; + struct hif_ht_tx_parameters ht_tx_parameters; + uint8_t frame[]; +} __packed; + +enum hif_qos_ackplcy { + HIF_QOS_ACKPLCY_NORMAL = 0x0, + HIF_QOS_ACKPLCY_TXNOACK = 0x1, + HIF_QOS_ACKPLCY_NOEXPACK = 0x2, + HIF_QOS_ACKPLCY_BLCKACK = 0x3 +}; + +struct hif_tx_result_flags { + uint8_t aggr:1; + uint8_t requeue:1; + uint8_t ack_policy:2; + uint8_t txop_limit:1; + uint8_t reserved1:3; + uint8_t reserved2; +} __packed; + +struct hif_cnf_tx { + uint32_t status; + uint32_t packet_id; + uint8_t txed_rate; + uint8_t ack_failures; + struct hif_tx_result_flags tx_result_flags; + uint32_t media_delay; + uint32_t tx_queue_delay; +} __packed; + +struct hif_cnf_multi_transmit { + uint32_t num_tx_confs; + struct hif_cnf_tx tx_conf_payload[]; +} __packed; + +enum hif_ri_flags_encrypt { + HIF_RI_FLAGS_UNENCRYPTED = 0x0, + HIF_RI_FLAGS_WEP_ENCRYPTED = 0x1, + HIF_RI_FLAGS_TKIP_ENCRYPTED = 0x2, + HIF_RI_FLAGS_AES_ENCRYPTED = 0x3, + HIF_RI_FLAGS_WAPI_ENCRYPTED = 0x4 +}; + +struct hif_rx_flags { + uint8_t encryp:3; + uint8_t in_aggr:1; + uint8_t first_aggr:1; + uint8_t last_aggr:1; + uint8_t defrag:1; + uint8_t beacon:1; + uint8_t tim:1; + uint8_t bitmap:1; + uint8_t match_ssid:1; + uint8_t match_bssid:1; + uint8_t more:1; + uint8_t reserved1:1; + uint8_t ht:1; + uint8_t stbc:1; + uint8_t match_uc_addr:1; + uint8_t match_mc_addr:1; + uint8_t match_bc_addr:1; + uint8_t key_type:1; + uint8_t key_index:4; + uint8_t reserved2:1; + uint8_t peer_sta_id:4; + uint8_t reserved3:2; + uint8_t reserved4:1; +} __packed; + +struct hif_ind_rx { + uint32_t status; + uint16_t channel_number; + uint8_t rxed_rate; + uint8_t rcpi_rssi; + struct hif_rx_flags rx_flags; + uint8_t frame[]; +} __packed; + + +struct hif_req_edca_queue_params { + uint8_t queue_id; + uint8_t reserved1; + uint8_t aifsn; + uint8_t reserved2; + uint16_t cw_min; + uint16_t cw_max; + uint16_t tx_op_limit; + uint16_t allowed_medium_time; + uint32_t reserved3; +} __packed; + +struct hif_cnf_edca_queue_params { + uint32_t status; +} __packed; + +enum hif_ap_mode { + HIF_MODE_IBSS = 0x0, + HIF_MODE_BSS = 0x1 +}; + +enum hif_preamble { + HIF_PREAMBLE_LONG = 0x0, + HIF_PREAMBLE_SHORT = 0x1, + HIF_PREAMBLE_SHORT_LONG12 = 0x2 +}; + +struct hif_join_flags { + uint8_t reserved1:2; + uint8_t force_no_beacon:1; + uint8_t force_with_ind:1; + uint8_t reserved2:4; +} __packed; + +struct hif_req_join { + uint8_t mode; + uint8_t band; + uint16_t channel_number; + uint8_t bssid[ETH_ALEN]; + uint16_t atim_window; + uint8_t preamble_type; + uint8_t probe_for_join; + uint8_t reserved; + struct hif_join_flags join_flags; + uint32_t ssid_length; + uint8_t ssid[HIF_API_SSID_SIZE]; + uint32_t beacon_interval; + uint32_t basic_rate_set; +} __packed; + +struct hif_cnf_join { + uint32_t status; +} __packed; + +struct hif_ind_join_complete { + uint32_t status; +} __packed; + +struct hif_bss_flags { + uint8_t lost_count_only:1; + uint8_t reserved:7; +} __packed; + +struct hif_req_set_bss_params { + struct hif_bss_flags bss_flags; + uint8_t beacon_lost_count; + uint16_t aid; + uint32_t operational_rate_set; +} __packed; + +struct hif_cnf_set_bss_params { + uint32_t status; +} __packed; + +struct hif_pm_mode { + uint8_t enter_psm:1; + uint8_t reserved:6; + uint8_t fast_psm:1; +} __packed; + +struct hif_req_set_pm_mode { + struct hif_pm_mode pm_mode; + uint8_t fast_psm_idle_period; + uint8_t ap_psm_change_period; + uint8_t min_auto_ps_poll_period; +} __packed; + +struct hif_cnf_set_pm_mode { + uint32_t status; +} __packed; + +struct hif_ind_set_pm_mode_cmpl { + uint32_t status; + uint8_t pm_mode; + uint8_t reserved[3]; +} __packed; + + +struct hif_req_start { + uint8_t mode; + uint8_t band; + uint16_t channel_number; + uint32_t reserved1; + uint32_t beacon_interval; + uint8_t dtim_period; + uint8_t preamble_type; + uint8_t reserved2; + uint8_t ssid_length; + uint8_t ssid[HIF_API_SSID_SIZE]; + uint32_t basic_rate_set; +} __packed; + +struct hif_cnf_start { + uint32_t status; +} __packed; + +enum hif_beacon { + HIF_BEACON_STOP = 0x0, + HIF_BEACON_START = 0x1 +}; + +struct hif_req_beacon_transmit { + uint8_t enable_beaconing; + uint8_t reserved[3]; +} __packed; + +struct hif_cnf_beacon_transmit { + uint32_t status; +} __packed; + +enum hif_sta_map_direction { + HIF_STA_MAP = 0x0, + HIF_STA_UNMAP = 0x1 +}; + +struct hif_map_link_flags { + uint8_t map_direction:1; + uint8_t mfpc:1; + uint8_t reserved:6; +} __packed; + +struct hif_req_map_link { + uint8_t mac_addr[ETH_ALEN]; + struct hif_map_link_flags map_link_flags; + uint8_t peer_sta_id; +} __packed; + +struct hif_cnf_map_link { + uint32_t status; +} __packed; + +struct hif_suspend_resume_flags { + uint8_t resume:1; + uint8_t reserved1:2; + uint8_t bc_mc_only:1; + uint8_t reserved2:4; + uint8_t reserved3; +} __packed; + +struct hif_ind_suspend_resume_tx { + struct hif_suspend_resume_flags suspend_resume_flags; + uint16_t peer_sta_set; +} __packed; + + +#define MAX_KEY_ENTRIES 24 +#define HIF_API_WEP_KEY_DATA_SIZE 16 +#define HIF_API_TKIP_KEY_DATA_SIZE 16 +#define HIF_API_RX_MIC_KEY_SIZE 8 +#define HIF_API_TX_MIC_KEY_SIZE 8 +#define HIF_API_AES_KEY_DATA_SIZE 16 +#define HIF_API_WAPI_KEY_DATA_SIZE 16 +#define HIF_API_MIC_KEY_DATA_SIZE 16 +#define HIF_API_IGTK_KEY_DATA_SIZE 16 +#define HIF_API_RX_SEQUENCE_COUNTER_SIZE 8 +#define HIF_API_IPN_SIZE 8 + +enum hif_key_type { + HIF_KEY_TYPE_WEP_DEFAULT = 0x0, + HIF_KEY_TYPE_WEP_PAIRWISE = 0x1, + HIF_KEY_TYPE_TKIP_GROUP = 0x2, + HIF_KEY_TYPE_TKIP_PAIRWISE = 0x3, + HIF_KEY_TYPE_AES_GROUP = 0x4, + HIF_KEY_TYPE_AES_PAIRWISE = 0x5, + HIF_KEY_TYPE_WAPI_GROUP = 0x6, + HIF_KEY_TYPE_WAPI_PAIRWISE = 0x7, + HIF_KEY_TYPE_IGTK_GROUP = 0x8, + HIF_KEY_TYPE_NONE = 0x9 +}; + +struct hif_wep_pairwise_key { + uint8_t peer_address[ETH_ALEN]; + uint8_t reserved; + uint8_t key_length; + uint8_t key_data[HIF_API_WEP_KEY_DATA_SIZE]; +} __packed; + +struct hif_wep_group_key { + uint8_t key_id; + uint8_t key_length; + uint8_t reserved[2]; + uint8_t key_data[HIF_API_WEP_KEY_DATA_SIZE]; +} __packed; + +struct hif_tkip_pairwise_key { + uint8_t peer_address[ETH_ALEN]; + uint8_t reserved[2]; + uint8_t tkip_key_data[HIF_API_TKIP_KEY_DATA_SIZE]; + uint8_t rx_mic_key[HIF_API_RX_MIC_KEY_SIZE]; + uint8_t tx_mic_key[HIF_API_TX_MIC_KEY_SIZE]; +} __packed; + +struct hif_tkip_group_key { + uint8_t tkip_key_data[HIF_API_TKIP_KEY_DATA_SIZE]; + uint8_t rx_mic_key[HIF_API_RX_MIC_KEY_SIZE]; + uint8_t key_id; + uint8_t reserved[3]; + uint8_t rx_sequence_counter[HIF_API_RX_SEQUENCE_COUNTER_SIZE]; +} __packed; + +struct hif_aes_pairwise_key { + uint8_t peer_address[ETH_ALEN]; + uint8_t reserved[2]; + uint8_t aes_key_data[HIF_API_AES_KEY_DATA_SIZE]; +} __packed; + +struct hif_aes_group_key { + uint8_t aes_key_data[HIF_API_AES_KEY_DATA_SIZE]; + uint8_t key_id; + uint8_t reserved[3]; + uint8_t rx_sequence_counter[HIF_API_RX_SEQUENCE_COUNTER_SIZE]; +} __packed; + +struct hif_wapi_pairwise_key { + uint8_t peer_address[ETH_ALEN]; + uint8_t key_id; + uint8_t reserved; + uint8_t wapi_key_data[HIF_API_WAPI_KEY_DATA_SIZE]; + uint8_t mic_key_data[HIF_API_MIC_KEY_DATA_SIZE]; +} __packed; + +struct hif_wapi_group_key { + uint8_t wapi_key_data[HIF_API_WAPI_KEY_DATA_SIZE]; + uint8_t mic_key_data[HIF_API_MIC_KEY_DATA_SIZE]; + uint8_t key_id; + uint8_t reserved[3]; +} __packed; + +struct hif_igtk_group_key { + uint8_t igtk_key_data[HIF_API_IGTK_KEY_DATA_SIZE]; + uint8_t key_id; + uint8_t reserved[3]; + uint8_t ipn[HIF_API_IPN_SIZE]; +} __packed; + +union hif_privacy_key_data { + struct hif_wep_pairwise_key wep_pairwise_key; + struct hif_wep_group_key wep_group_key; + struct hif_tkip_pairwise_key tkip_pairwise_key; + struct hif_tkip_group_key tkip_group_key; + struct hif_aes_pairwise_key aes_pairwise_key; + struct hif_aes_group_key aes_group_key; + struct hif_wapi_pairwise_key wapi_pairwise_key; + struct hif_wapi_group_key wapi_group_key; + struct hif_igtk_group_key igtk_group_key; +}; + +struct hif_req_add_key { + uint8_t type; + uint8_t entry_index; + uint8_t int_id:2; + uint8_t reserved1:6; + uint8_t reserved2; + union hif_privacy_key_data key; +} __packed; + +struct hif_cnf_add_key { + uint32_t status; +} __packed; + +struct hif_req_remove_key { + uint8_t entry_index; + uint8_t reserved[3]; +} __packed; + +struct hif_cnf_remove_key { + uint32_t status; +} __packed; + +enum hif_event_ind { + HIF_EVENT_IND_BSSLOST = 0x1, + HIF_EVENT_IND_BSSREGAINED = 0x2, + HIF_EVENT_IND_RCPI_RSSI = 0x3, + HIF_EVENT_IND_PS_MODE_ERROR = 0x4, + HIF_EVENT_IND_INACTIVITY = 0x5 +}; + +enum hif_ps_mode_error { + HIF_PS_ERROR_NO_ERROR = 0, + HIF_PS_ERROR_AP_NOT_RESP_TO_POLL = 1, + HIF_PS_ERROR_AP_NOT_RESP_TO_UAPSD_TRIGGER = 2, + HIF_PS_ERROR_AP_SENT_UNICAST_IN_DOZE = 3, + HIF_PS_ERROR_AP_NO_DATA_AFTER_TIM = 4 +}; + +union hif_event_data { + uint8_t rcpi_rssi; + uint32_t ps_mode_error; + uint32_t peer_sta_set; +}; + +struct hif_ind_event { + uint32_t event_id; + union hif_event_data event_data; +} __packed; + + +#endif diff --git a/drivers/staging/wfx/hif_api_general.h b/drivers/staging/wfx/hif_api_general.h new file mode 100644 index 000000000000..d885b55d2882 --- /dev/null +++ b/drivers/staging/wfx/hif_api_general.h @@ -0,0 +1,437 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * WFx hardware interface definitions + * + * Copyright (c) 2018-2019, Silicon Laboratories Inc. + */ + +#ifndef WFX_HIF_API_GENERAL_H +#define WFX_HIF_API_GENERAL_H + +#ifdef __KERNEL__ +#include <linux/types.h> +#include <linux/if_ether.h> +#else +#include <net/ethernet.h> +#include <stdint.h> +#define __packed __attribute__((__packed__)) +#endif + +#define API_SSID_SIZE 32 + +#define HIF_ID_IS_INDICATION 0x80 +#define HIF_COUNTER_MAX 7 + +struct hif_msg { + uint16_t len; + uint8_t id; + uint8_t reserved:1; + uint8_t interface:2; + uint8_t seqnum:3; + uint8_t encrypted:2; + uint8_t body[]; +} __packed; + +enum hif_general_requests_ids { + HIF_REQ_ID_CONFIGURATION = 0x09, + HIF_REQ_ID_CONTROL_GPIO = 0x26, + HIF_REQ_ID_SET_SL_MAC_KEY = 0x27, + HIF_REQ_ID_SL_EXCHANGE_PUB_KEYS = 0x28, + HIF_REQ_ID_SL_CONFIGURE = 0x29, + HIF_REQ_ID_PREVENT_ROLLBACK = 0x2a, + HIF_REQ_ID_PTA_SETTINGS = 0x2b, + HIF_REQ_ID_PTA_PRIORITY = 0x2c, + HIF_REQ_ID_PTA_STATE = 0x2d, + HIF_REQ_ID_SHUT_DOWN = 0x32, +}; + +enum hif_general_confirmations_ids { + HIF_CNF_ID_CONFIGURATION = 0x09, + HIF_CNF_ID_CONTROL_GPIO = 0x26, + HIF_CNF_ID_SET_SL_MAC_KEY = 0x27, + HIF_CNF_ID_SL_EXCHANGE_PUB_KEYS = 0x28, + HIF_CNF_ID_SL_CONFIGURE = 0x29, + HIF_CNF_ID_PREVENT_ROLLBACK = 0x2a, + HIF_CNF_ID_PTA_SETTINGS = 0x2b, + HIF_CNF_ID_PTA_PRIORITY = 0x2c, + HIF_CNF_ID_PTA_STATE = 0x2d, + HIF_CNF_ID_SHUT_DOWN = 0x32, +}; + +enum hif_general_indications_ids { + HIF_IND_ID_EXCEPTION = 0xe0, + HIF_IND_ID_STARTUP = 0xe1, + HIF_IND_ID_WAKEUP = 0xe2, + HIF_IND_ID_GENERIC = 0xe3, + HIF_IND_ID_ERROR = 0xe4, + HIF_IND_ID_SL_EXCHANGE_PUB_KEYS = 0xe5 +}; + +enum hif_hi_status { + HI_STATUS_SUCCESS = 0x0000, + HI_STATUS_FAILURE = 0x0001, + HI_INVALID_PARAMETER = 0x0002, + HI_STATUS_GPIO_WARNING = 0x0003, + HI_ERROR_UNSUPPORTED_MSG_ID = 0x0004, + SL_MAC_KEY_STATUS_SUCCESS = 0x005A, + SL_MAC_KEY_STATUS_FAILED_KEY_ALREADY_BURNED = 0x006B, + SL_MAC_KEY_STATUS_FAILED_RAM_MODE_NOT_ALLOWED = 0x007C, + SL_MAC_KEY_STATUS_FAILED_UNKNOWN_MODE = 0x008D, + SL_PUB_KEY_EXCHANGE_STATUS_SUCCESS = 0x009E, + SL_PUB_KEY_EXCHANGE_STATUS_FAILED = 0x00AF, + PREVENT_ROLLBACK_CNF_SUCCESS = 0x1234, + PREVENT_ROLLBACK_CNF_WRONG_MAGIC_WORD = 0x1256 +}; + +enum hif_api_rate_index { + API_RATE_INDEX_B_1MBPS = 0, + API_RATE_INDEX_B_2MBPS = 1, + API_RATE_INDEX_B_5P5MBPS = 2, + API_RATE_INDEX_B_11MBPS = 3, + API_RATE_INDEX_PBCC_22MBPS = 4, + API_RATE_INDEX_PBCC_33MBPS = 5, + API_RATE_INDEX_G_6MBPS = 6, + API_RATE_INDEX_G_9MBPS = 7, + API_RATE_INDEX_G_12MBPS = 8, + API_RATE_INDEX_G_18MBPS = 9, + API_RATE_INDEX_G_24MBPS = 10, + API_RATE_INDEX_G_36MBPS = 11, + API_RATE_INDEX_G_48MBPS = 12, + API_RATE_INDEX_G_54MBPS = 13, + API_RATE_INDEX_N_6P5MBPS = 14, + API_RATE_INDEX_N_13MBPS = 15, + API_RATE_INDEX_N_19P5MBPS = 16, + API_RATE_INDEX_N_26MBPS = 17, + API_RATE_INDEX_N_39MBPS = 18, + API_RATE_INDEX_N_52MBPS = 19, + API_RATE_INDEX_N_58P5MBPS = 20, + API_RATE_INDEX_N_65MBPS = 21, + API_RATE_NUM_ENTRIES = 22 +}; + + +enum hif_fw_type { + HIF_FW_TYPE_ETF = 0x0, + HIF_FW_TYPE_WFM = 0x1, + HIF_FW_TYPE_WSM = 0x2 +}; + +struct hif_capabilities { + uint8_t link_mode:2; + uint8_t reserved1:6; + uint8_t reserved2; + uint8_t reserved3; + uint8_t reserved4; +} __packed; + +struct hif_otp_regul_sel_mode_info { + uint8_t region_sel_mode:4; + uint8_t reserved:4; +} __packed; + +struct hif_otp_phy_info { + uint8_t phy1_region:3; + uint8_t phy0_region:3; + uint8_t otp_phy_ver:2; +} __packed; + +#define API_OPN_SIZE 14 +#define API_UID_SIZE 8 +#define API_DISABLED_CHANNEL_LIST_SIZE 2 +#define API_FIRMWARE_LABEL_SIZE 128 + +struct hif_ind_startup { + uint32_t status; + uint16_t hardware_id; + uint8_t opn[API_OPN_SIZE]; + uint8_t uid[API_UID_SIZE]; + uint16_t num_inp_ch_bufs; + uint16_t size_inp_ch_buf; + uint8_t num_links_ap; + uint8_t num_interfaces; + uint8_t mac_addr[2][ETH_ALEN]; + uint8_t api_version_minor; + uint8_t api_version_major; + struct hif_capabilities capabilities; + uint8_t firmware_build; + uint8_t firmware_minor; + uint8_t firmware_major; + uint8_t firmware_type; + uint8_t disabled_channel_list[API_DISABLED_CHANNEL_LIST_SIZE]; + struct hif_otp_regul_sel_mode_info regul_sel_mode_info; + struct hif_otp_phy_info otp_phy_info; + uint32_t supported_rate_mask; + uint8_t firmware_label[API_FIRMWARE_LABEL_SIZE]; +} __packed; + +struct hif_ind_wakeup { +} __packed; + +struct hif_req_configuration { + uint16_t length; + uint8_t pds_data[]; +} __packed; + +struct hif_cnf_configuration { + uint32_t status; +} __packed; + +enum hif_gpio_mode { + HIF_GPIO_MODE_D0 = 0x0, + HIF_GPIO_MODE_D1 = 0x1, + HIF_GPIO_MODE_OD0 = 0x2, + HIF_GPIO_MODE_OD1 = 0x3, + HIF_GPIO_MODE_TRISTATE = 0x4, + HIF_GPIO_MODE_TOGGLE = 0x5, + HIF_GPIO_MODE_READ = 0x6 +}; + +struct hif_req_control_gpio { + uint8_t gpio_label; + uint8_t gpio_mode; +} __packed; + +enum hif_gpio_error { + HIF_GPIO_ERROR_0 = 0x0, + HIF_GPIO_ERROR_1 = 0x1, + HIF_GPIO_ERROR_2 = 0x2 +}; + +struct hif_cnf_control_gpio { + uint32_t status; + uint32_t value; +} __packed; + +enum hif_generic_indication_type { + HIF_GENERIC_INDICATION_TYPE_RAW = 0x0, + HIF_GENERIC_INDICATION_TYPE_STRING = 0x1, + HIF_GENERIC_INDICATION_TYPE_RX_STATS = 0x2 +}; + +struct hif_rx_stats { + uint32_t nb_rx_frame; + uint32_t nb_crc_frame; + uint32_t per_total; + uint32_t throughput; + uint32_t nb_rx_by_rate[API_RATE_NUM_ENTRIES]; + uint16_t per[API_RATE_NUM_ENTRIES]; + int16_t snr[API_RATE_NUM_ENTRIES]; + int16_t rssi[API_RATE_NUM_ENTRIES]; + int16_t cfo[API_RATE_NUM_ENTRIES]; + uint32_t date; + uint32_t pwr_clk_freq; + uint8_t is_ext_pwr_clk; + int8_t current_temp; +} __packed; + +union hif_indication_data { + struct hif_rx_stats rx_stats; + uint8_t raw_data[1]; +}; + +struct hif_ind_generic { + uint32_t indication_type; + union hif_indication_data indication_data; +} __packed; + + +#define HIF_EXCEPTION_DATA_SIZE 124 + +struct hif_ind_exception { + uint8_t data[HIF_EXCEPTION_DATA_SIZE]; +} __packed; + + +enum hif_error { + HIF_ERROR_FIRMWARE_ROLLBACK = 0x0, + HIF_ERROR_FIRMWARE_DEBUG_ENABLED = 0x1, + HIF_ERROR_OUTDATED_SESSION_KEY = 0x2, + HIF_ERROR_INVALID_SESSION_KEY = 0x3, + HIF_ERROR_OOR_VOLTAGE = 0x4, + HIF_ERROR_PDS_VERSION = 0x5, + HIF_ERROR_OOR_TEMPERATURE = 0x6, + HIF_ERROR_REQ_DURING_KEY_EXCHANGE = 0x7, + HIF_ERROR_MULTI_TX_CNF_SECURELINK = 0x8, + HIF_ERROR_SECURELINK_OVERFLOW = 0x9, + HIF_ERROR_SECURELINK_DECRYPTION = 0xa +}; + +struct hif_ind_error { + uint32_t type; + uint8_t data[]; +} __packed; + +enum hif_secure_link_state { + SEC_LINK_UNAVAILABLE = 0x0, + SEC_LINK_RESERVED = 0x1, + SEC_LINK_EVAL = 0x2, + SEC_LINK_ENFORCED = 0x3 +}; + +enum hif_sl_encryption_type { + NO_ENCRYPTION = 0, + TX_ENCRYPTION = 1, + RX_ENCRYPTION = 2, + HP_ENCRYPTION = 3 +}; + +struct hif_sl_msg_hdr { + uint32_t seqnum:30; + uint32_t encrypted:2; +} __packed; + +struct hif_sl_msg { + struct hif_sl_msg_hdr hdr; + uint16_t len; + uint8_t payload[]; +} __packed; + +#define AES_CCM_TAG_SIZE 16 + +struct hif_sl_tag { + uint8_t tag[16]; +} __packed; + +enum hif_sl_mac_key_dest { + SL_MAC_KEY_DEST_OTP = 0x78, + SL_MAC_KEY_DEST_RAM = 0x87 +}; + +#define API_KEY_VALUE_SIZE 32 + +struct hif_req_set_sl_mac_key { + uint8_t otp_or_ram; + uint8_t key_value[API_KEY_VALUE_SIZE]; +} __packed; + +struct hif_cnf_set_sl_mac_key { + uint32_t status; +} __packed; + +#define API_HOST_PUB_KEY_SIZE 32 +#define API_HOST_PUB_KEY_MAC_SIZE 64 + +enum hif_sl_session_key_alg { + HIF_SL_CURVE25519 = 0x01, + HIF_SL_KDF = 0x02 +}; + +struct hif_req_sl_exchange_pub_keys { + uint8_t algorithm:2; + uint8_t reserved1:6; + uint8_t reserved2[3]; + uint8_t host_pub_key[API_HOST_PUB_KEY_SIZE]; + uint8_t host_pub_key_mac[API_HOST_PUB_KEY_MAC_SIZE]; +} __packed; + +struct hif_cnf_sl_exchange_pub_keys { + uint32_t status; +} __packed; + +#define API_NCP_PUB_KEY_SIZE 32 +#define API_NCP_PUB_KEY_MAC_SIZE 64 + +struct hif_ind_sl_exchange_pub_keys { + uint32_t status; + uint8_t ncp_pub_key[API_NCP_PUB_KEY_SIZE]; + uint8_t ncp_pub_key_mac[API_NCP_PUB_KEY_MAC_SIZE]; +} __packed; + +#define API_ENCR_BMP_SIZE 32 + +struct hif_req_sl_configure { + uint8_t encr_bmp[API_ENCR_BMP_SIZE]; + uint8_t disable_session_key_protection:1; + uint8_t reserved1:7; + uint8_t reserved2[3]; +} __packed; + +struct hif_cnf_sl_configure { + uint32_t status; +} __packed; + +struct hif_req_prevent_rollback { + uint32_t magic_word; +} __packed; + +struct hif_cnf_prevent_rollback { + uint32_t status; +} __packed; + +enum hif_pta_mode { + PTA_1W_WLAN_MASTER = 0, + PTA_1W_COEX_MASTER = 1, + PTA_2W = 2, + PTA_3W = 3, + PTA_4W = 4 +}; + +enum hif_signal_level { + SIGNAL_LOW = 0, + SIGNAL_HIGH = 1 +}; + +enum hif_coex_type { + COEX_TYPE_GENERIC = 0, + COEX_TYPE_BLE = 1 +}; + +enum hif_grant_state { + NO_GRANT = 0, + GRANT = 1 +}; + +struct hif_req_pta_settings { + uint8_t pta_mode; + uint8_t request_signal_active_level; + uint8_t priority_signal_active_level; + uint8_t freq_signal_active_level; + uint8_t grant_signal_active_level; + uint8_t coex_type; + uint8_t default_grant_state; + uint8_t simultaneous_rx_accesses; + uint8_t priority_sampling_time; + uint8_t tx_rx_sampling_time; + uint8_t freq_sampling_time; + uint8_t grant_valid_time; + uint8_t fem_control_time; + uint8_t first_slot_time; + uint16_t periodic_tx_rx_sampling_time; + uint16_t coex_quota; + uint16_t wlan_quota; +} __packed; + +struct hif_cnf_pta_settings { + uint32_t status; +} __packed; + +enum hif_pta_priority { + HIF_PTA_PRIORITY_COEX_MAXIMIZED = 0x00000562, + HIF_PTA_PRIORITY_COEX_HIGH = 0x00000462, + HIF_PTA_PRIORITY_BALANCED = 0x00001461, + HIF_PTA_PRIORITY_WLAN_HIGH = 0x00001851, + HIF_PTA_PRIORITY_WLAN_MAXIMIZED = 0x00001A51 +}; + +struct hif_req_pta_priority { + uint32_t priority; +} __packed; + +struct hif_cnf_pta_priority { + uint32_t status; +} __packed; + +enum hif_pta_state { + PTA_OFF = 0, + PTA_ON = 1 +}; + +struct hif_req_pta_state { + uint32_t pta_state; +} __packed; + +struct hif_cnf_pta_state { + uint32_t status; +} __packed; + +#endif diff --git a/drivers/staging/wfx/hif_api_mib.h b/drivers/staging/wfx/hif_api_mib.h new file mode 100644 index 000000000000..af657555f894 --- /dev/null +++ b/drivers/staging/wfx/hif_api_mib.h @@ -0,0 +1,558 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * WFx hardware interface definitions + * + * Copyright (c) 2018-2019, Silicon Laboratories Inc. + */ + +#ifndef WFX_HIF_API_MIB_H +#define WFX_HIF_API_MIB_H + +#include "hif_api_general.h" + +#define HIF_API_IPV4_ADDRESS_SIZE 4 +#define HIF_API_IPV6_ADDRESS_SIZE 16 + +enum hif_mib_ids { + HIF_MIB_ID_GL_OPERATIONAL_POWER_MODE = 0x2000, + HIF_MIB_ID_GL_BLOCK_ACK_INFO = 0x2001, + HIF_MIB_ID_GL_SET_MULTI_MSG = 0x2002, + HIF_MIB_ID_CCA_CONFIG = 0x2003, + HIF_MIB_ID_ETHERTYPE_DATAFRAME_CONDITION = 0x2010, + HIF_MIB_ID_PORT_DATAFRAME_CONDITION = 0x2011, + HIF_MIB_ID_MAGIC_DATAFRAME_CONDITION = 0x2012, + HIF_MIB_ID_MAC_ADDR_DATAFRAME_CONDITION = 0x2013, + HIF_MIB_ID_IPV4_ADDR_DATAFRAME_CONDITION = 0x2014, + HIF_MIB_ID_IPV6_ADDR_DATAFRAME_CONDITION = 0x2015, + HIF_MIB_ID_UC_MC_BC_DATAFRAME_CONDITION = 0x2016, + HIF_MIB_ID_CONFIG_DATA_FILTER = 0x2017, + HIF_MIB_ID_SET_DATA_FILTERING = 0x2018, + HIF_MIB_ID_ARP_IP_ADDRESSES_TABLE = 0x2019, + HIF_MIB_ID_NS_IP_ADDRESSES_TABLE = 0x201A, + HIF_MIB_ID_RX_FILTER = 0x201B, + HIF_MIB_ID_BEACON_FILTER_TABLE = 0x201C, + HIF_MIB_ID_BEACON_FILTER_ENABLE = 0x201D, + HIF_MIB_ID_GRP_SEQ_COUNTER = 0x2030, + HIF_MIB_ID_TSF_COUNTER = 0x2031, + HIF_MIB_ID_STATISTICS_TABLE = 0x2032, + HIF_MIB_ID_COUNTERS_TABLE = 0x2033, + HIF_MIB_ID_MAX_TX_POWER_LEVEL = 0x2034, + HIF_MIB_ID_EXTENDED_COUNTERS_TABLE = 0x2035, + HIF_MIB_ID_DOT11_MAC_ADDRESS = 0x2040, + HIF_MIB_ID_DOT11_MAX_TRANSMIT_MSDU_LIFETIME = 0x2041, + HIF_MIB_ID_DOT11_MAX_RECEIVE_LIFETIME = 0x2042, + HIF_MIB_ID_DOT11_WEP_DEFAULT_KEY_ID = 0x2043, + HIF_MIB_ID_DOT11_RTS_THRESHOLD = 0x2044, + HIF_MIB_ID_SLOT_TIME = 0x2045, + HIF_MIB_ID_CURRENT_TX_POWER_LEVEL = 0x2046, + HIF_MIB_ID_NON_ERP_PROTECTION = 0x2047, + HIF_MIB_ID_TEMPLATE_FRAME = 0x2048, + HIF_MIB_ID_BEACON_WAKEUP_PERIOD = 0x2049, + HIF_MIB_ID_RCPI_RSSI_THRESHOLD = 0x204A, + HIF_MIB_ID_BLOCK_ACK_POLICY = 0x204B, + HIF_MIB_ID_OVERRIDE_INTERNAL_TX_RATE = 0x204C, + HIF_MIB_ID_SET_ASSOCIATION_MODE = 0x204D, + HIF_MIB_ID_SET_UAPSD_INFORMATION = 0x204E, + HIF_MIB_ID_SET_TX_RATE_RETRY_POLICY = 0x204F, + HIF_MIB_ID_PROTECTED_MGMT_POLICY = 0x2050, + HIF_MIB_ID_SET_HT_PROTECTION = 0x2051, + HIF_MIB_ID_KEEP_ALIVE_PERIOD = 0x2052, + HIF_MIB_ID_ARP_KEEP_ALIVE_PERIOD = 0x2053, + HIF_MIB_ID_INACTIVITY_TIMER = 0x2054, + HIF_MIB_ID_INTERFACE_PROTECTION = 0x2055, + HIF_MIB_ID_BEACON_STATS = 0x2056, +}; + +#define HIF_OP_POWER_MODE_MASK 0xf + +enum hif_op_power_mode { + HIF_OP_POWER_MODE_ACTIVE = 0x0, + HIF_OP_POWER_MODE_DOZE = 0x1, + HIF_OP_POWER_MODE_QUIESCENT = 0x2 +}; + +struct hif_mib_gl_operational_power_mode { + uint8_t power_mode:4; + uint8_t reserved1:3; + uint8_t wup_ind_activation:1; + uint8_t reserved2[3]; +} __packed; + +struct hif_mib_gl_block_ack_info { + uint8_t rx_buffer_size; + uint8_t rx_max_num_agreements; + uint8_t tx_buffer_size; + uint8_t tx_max_num_agreements; +} __packed; + +struct hif_mib_gl_set_multi_msg { + uint8_t enable_multi_tx_conf:1; + uint8_t reserved1:7; + uint8_t reserved2[3]; +} __packed; + +enum hif_cca_thr_mode { + HIF_CCA_THR_MODE_RELATIVE = 0x0, + HIF_CCA_THR_MODE_ABSOLUTE = 0x1 +}; + +struct hif_mib_gl_cca_config { + uint8_t cca_thr_mode; + uint8_t reserved[3]; +} __packed; + +#define MAX_NUMBER_DATA_FILTERS 0xA + +#define MAX_NUMBER_IPV4_ADDR_CONDITIONS 0x4 +#define MAX_NUMBER_IPV6_ADDR_CONDITIONS 0x4 +#define MAX_NUMBER_MAC_ADDR_CONDITIONS 0x4 +#define MAX_NUMBER_UC_MC_BC_CONDITIONS 0x4 +#define MAX_NUMBER_ETHER_TYPE_CONDITIONS 0x4 +#define MAX_NUMBER_PORT_CONDITIONS 0x4 +#define MAX_NUMBER_MAGIC_CONDITIONS 0x4 +#define MAX_NUMBER_ARP_CONDITIONS 0x2 +#define MAX_NUMBER_NS_CONDITIONS 0x2 + +struct hif_mib_ethertype_data_frame_condition { + uint8_t condition_idx; + uint8_t reserved; + uint16_t ether_type; +} __packed; + +enum hif_udp_tcp_protocol { + HIF_PROTOCOL_UDP = 0x0, + HIF_PROTOCOL_TCP = 0x1, + HIF_PROTOCOL_BOTH_UDP_TCP = 0x2 +}; + +enum hif_which_port { + HIF_PORT_DST = 0x0, + HIF_PORT_SRC = 0x1, + HIF_PORT_SRC_OR_DST = 0x2 +}; + +struct hif_mib_ports_data_frame_condition { + uint8_t condition_idx; + uint8_t protocol; + uint8_t which_port; + uint8_t reserved1; + uint16_t port_number; + uint8_t reserved2[2]; +} __packed; + +#define HIF_API_MAGIC_PATTERN_SIZE 32 + +struct hif_mib_magic_data_frame_condition { + uint8_t condition_idx; + uint8_t offset; + uint8_t magic_pattern_length; + uint8_t reserved; + uint8_t magic_pattern[HIF_API_MAGIC_PATTERN_SIZE]; +} __packed; + +enum hif_mac_addr_type { + HIF_MAC_ADDR_A1 = 0x0, + HIF_MAC_ADDR_A2 = 0x1, + HIF_MAC_ADDR_A3 = 0x2 +}; + +struct hif_mib_mac_addr_data_frame_condition { + uint8_t condition_idx; + uint8_t address_type; + uint8_t mac_address[ETH_ALEN]; +} __packed; + +enum hif_ip_addr_mode { + HIF_IP_ADDR_SRC = 0x0, + HIF_IP_ADDR_DST = 0x1 +}; + +struct hif_mib_ipv4_addr_data_frame_condition { + uint8_t condition_idx; + uint8_t address_mode; + uint8_t reserved[2]; + uint8_t i_pv4_address[HIF_API_IPV4_ADDRESS_SIZE]; +} __packed; + +struct hif_mib_ipv6_addr_data_frame_condition { + uint8_t condition_idx; + uint8_t address_mode; + uint8_t reserved[2]; + uint8_t i_pv6_address[HIF_API_IPV6_ADDRESS_SIZE]; +} __packed; + +union hif_addr_type { + uint8_t value; + struct { + uint8_t type_unicast:1; + uint8_t type_multicast:1; + uint8_t type_broadcast:1; + uint8_t reserved:5; + } bits; +}; + +struct hif_mib_uc_mc_bc_data_frame_condition { + uint8_t condition_idx; + union hif_addr_type param; + uint8_t reserved[2]; +} __packed; + +struct hif_mib_config_data_filter { + uint8_t filter_idx; + uint8_t enable; + uint8_t reserved1[2]; + uint8_t eth_type_cond; + uint8_t port_cond; + uint8_t magic_cond; + uint8_t mac_cond; + uint8_t ipv4_cond; + uint8_t ipv6_cond; + uint8_t uc_mc_bc_cond; + uint8_t reserved2; +} __packed; + +struct hif_mib_set_data_filtering { + uint8_t default_filter; + uint8_t enable; + uint8_t reserved[2]; +} __packed; + +enum hif_arp_ns_frame_treatment { + HIF_ARP_NS_FILTERING_DISABLE = 0x0, + HIF_ARP_NS_FILTERING_ENABLE = 0x1, + HIF_ARP_NS_REPLY_ENABLE = 0x2 +}; + +struct hif_mib_arp_ip_addr_table { + uint8_t condition_idx; + uint8_t arp_enable; + uint8_t reserved[2]; + uint8_t ipv4_address[HIF_API_IPV4_ADDRESS_SIZE]; +} __packed; + +struct hif_mib_ns_ip_addr_table { + uint8_t condition_idx; + uint8_t ns_enable; + uint8_t reserved[2]; + uint8_t ipv6_address[HIF_API_IPV6_ADDRESS_SIZE]; +} __packed; + +struct hif_mib_rx_filter { + uint8_t reserved1:1; + uint8_t bssid_filter:1; + uint8_t reserved2:1; + uint8_t fwd_probe_req:1; + uint8_t keep_alive_filter:1; + uint8_t reserved3:3; + uint8_t reserved4[3]; +} __packed; + +#define HIF_API_OUI_SIZE 3 +#define HIF_API_MATCH_DATA_SIZE 3 + +struct hif_ie_table_entry { + uint8_t ie_id; + uint8_t has_changed:1; + uint8_t no_longer:1; + uint8_t has_appeared:1; + uint8_t reserved:1; + uint8_t num_match_data:4; + uint8_t oui[HIF_API_OUI_SIZE]; + uint8_t match_data[HIF_API_MATCH_DATA_SIZE]; +} __packed; + +struct hif_mib_bcn_filter_table { + uint32_t num_of_info_elmts; + struct hif_ie_table_entry ie_table[]; +} __packed; + +enum hif_beacon_filter { + HIF_BEACON_FILTER_DISABLE = 0x0, + HIF_BEACON_FILTER_ENABLE = 0x1, + HIF_BEACON_FILTER_AUTO_ERP = 0x2 +}; + +struct hif_mib_bcn_filter_enable { + uint32_t enable; + uint32_t bcn_count; +} __packed; + +struct hif_mib_group_seq_counter { + uint32_t bits4716; + uint16_t bits1500; + uint16_t reserved; +} __packed; + +struct hif_mib_tsf_counter { + uint32_t tsf_counterlo; + uint32_t tsf_counterhi; +} __packed; + +struct hif_mib_stats_table { + int16_t latest_snr; + uint8_t latest_rcpi; + int8_t latest_rssi; +} __packed; + +struct hif_mib_extended_count_table { + uint32_t count_plcp_errors; + uint32_t count_fcs_errors; + uint32_t count_tx_packets; + uint32_t count_rx_packets; + uint32_t count_rx_packet_errors; + uint32_t count_rx_decryption_failures; + uint32_t count_rx_mic_failures; + uint32_t count_rx_no_key_failures; + uint32_t count_tx_multicast_frames; + uint32_t count_tx_frames_success; + uint32_t count_tx_frame_failures; + uint32_t count_tx_frames_retried; + uint32_t count_tx_frames_multi_retried; + uint32_t count_rx_frame_duplicates; + uint32_t count_rts_success; + uint32_t count_rts_failures; + uint32_t count_ack_failures; + uint32_t count_rx_multicast_frames; + uint32_t count_rx_frames_success; + uint32_t count_rx_cmacicv_errors; + uint32_t count_rx_cmac_replays; + uint32_t count_rx_mgmt_ccmp_replays; + uint32_t count_rx_bipmic_errors; + uint32_t count_rx_beacon; + uint32_t count_miss_beacon; + uint32_t reserved[15]; +} __packed; + +struct hif_mib_count_table { + uint32_t count_plcp_errors; + uint32_t count_fcs_errors; + uint32_t count_tx_packets; + uint32_t count_rx_packets; + uint32_t count_rx_packet_errors; + uint32_t count_rx_decryption_failures; + uint32_t count_rx_mic_failures; + uint32_t count_rx_no_key_failures; + uint32_t count_tx_multicast_frames; + uint32_t count_tx_frames_success; + uint32_t count_tx_frame_failures; + uint32_t count_tx_frames_retried; + uint32_t count_tx_frames_multi_retried; + uint32_t count_rx_frame_duplicates; + uint32_t count_rts_success; + uint32_t count_rts_failures; + uint32_t count_ack_failures; + uint32_t count_rx_multicast_frames; + uint32_t count_rx_frames_success; + uint32_t count_rx_cmacicv_errors; + uint32_t count_rx_cmac_replays; + uint32_t count_rx_mgmt_ccmp_replays; + uint32_t count_rx_bipmic_errors; +} __packed; + +struct hif_mib_max_tx_power_level { + int32_t max_tx_power_level_rf_port1; + int32_t max_tx_power_level_rf_port2; +} __packed; + +struct hif_mib_beacon_stats { + int32_t latest_tbtt_diff; + uint32_t reserved[4]; +} __packed; + +struct hif_mib_mac_address { + uint8_t mac_addr[ETH_ALEN]; + uint16_t reserved; +} __packed; + +struct hif_mib_dot11_max_transmit_msdu_lifetime { + uint32_t max_life_time; +} __packed; + +struct hif_mib_dot11_max_receive_lifetime { + uint32_t max_life_time; +} __packed; + +struct hif_mib_wep_default_key_id { + uint8_t wep_default_key_id; + uint8_t reserved[3]; +} __packed; + +struct hif_mib_dot11_rts_threshold { + uint32_t threshold; +} __packed; + +struct hif_mib_slot_time { + uint32_t slot_time; +} __packed; + +struct hif_mib_current_tx_power_level { + int32_t power_level; +} __packed; + +struct hif_mib_non_erp_protection { + uint8_t use_cts_to_self:1; + uint8_t reserved1:7; + uint8_t reserved2[3]; +} __packed; + +enum hif_tx_mode { + HIF_TX_MODE_MIXED = 0x0, + HIF_TX_MODE_GREENFIELD = 0x1 +}; + +enum hif_tmplt { + HIF_TMPLT_PRBREQ = 0x0, + HIF_TMPLT_BCN = 0x1, + HIF_TMPLT_NULL = 0x2, + HIF_TMPLT_QOSNUL = 0x3, + HIF_TMPLT_PSPOLL = 0x4, + HIF_TMPLT_PRBRES = 0x5, + HIF_TMPLT_ARP = 0x6, + HIF_TMPLT_NA = 0x7 +}; + +#define HIF_API_MAX_TEMPLATE_FRAME_SIZE 700 + +struct hif_mib_template_frame { + uint8_t frame_type; + uint8_t init_rate:7; + uint8_t mode:1; + uint16_t frame_length; + uint8_t frame[HIF_API_MAX_TEMPLATE_FRAME_SIZE]; +} __packed; + +struct hif_mib_beacon_wake_up_period { + uint8_t wakeup_period_min; + uint8_t receive_dtim:1; + uint8_t reserved1:7; + uint8_t wakeup_period_max; + uint8_t reserved2; +} __packed; + +struct hif_mib_rcpi_rssi_threshold { + uint8_t detection:1; + uint8_t rcpi_rssi:1; + uint8_t upperthresh:1; + uint8_t lowerthresh:1; + uint8_t reserved:4; + uint8_t lower_threshold; + uint8_t upper_threshold; + uint8_t rolling_average_count; +} __packed; + +#define DEFAULT_BA_MAX_RX_BUFFER_SIZE 16 + +struct hif_mib_block_ack_policy { + uint8_t block_ack_tx_tid_policy; + uint8_t reserved1; + uint8_t block_ack_rx_tid_policy; + uint8_t block_ack_rx_max_buffer_size; +} __packed; + +struct hif_mib_override_int_rate { + uint8_t internal_tx_rate; + uint8_t non_erp_internal_tx_rate; + uint8_t reserved[2]; +} __packed; + +enum hif_mpdu_start_spacing { + HIF_MPDU_START_SPACING_NO_RESTRIC = 0x0, + HIF_MPDU_START_SPACING_QUARTER = 0x1, + HIF_MPDU_START_SPACING_HALF = 0x2, + HIF_MPDU_START_SPACING_ONE = 0x3, + HIF_MPDU_START_SPACING_TWO = 0x4, + HIF_MPDU_START_SPACING_FOUR = 0x5, + HIF_MPDU_START_SPACING_EIGHT = 0x6, + HIF_MPDU_START_SPACING_SIXTEEN = 0x7 +}; + +struct hif_mib_set_association_mode { + uint8_t preambtype_use:1; + uint8_t mode:1; + uint8_t rateset:1; + uint8_t spacing:1; + uint8_t reserved:4; + uint8_t preamble_type; + uint8_t mixed_or_greenfield_type; + uint8_t mpdu_start_spacing; + uint32_t basic_rate_set; +} __packed; + +struct hif_mib_set_uapsd_information { + uint8_t trig_bckgrnd:1; + uint8_t trig_be:1; + uint8_t trig_video:1; + uint8_t trig_voice:1; + uint8_t reserved1:4; + uint8_t deliv_bckgrnd:1; + uint8_t deliv_be:1; + uint8_t deliv_video:1; + uint8_t deliv_voice:1; + uint8_t reserved2:4; + uint16_t min_auto_trigger_interval; + uint16_t max_auto_trigger_interval; + uint16_t auto_trigger_step; +} __packed; + +struct hif_mib_tx_rate_retry_policy { + uint8_t policy_index; + uint8_t short_retry_count; + uint8_t long_retry_count; + uint8_t first_rate_sel:2; + uint8_t terminate:1; + uint8_t count_init:1; + uint8_t reserved1:4; + uint8_t rate_recovery_count; + uint8_t reserved2[3]; + uint8_t rates[12]; +} __packed; + +#define HIF_MIB_NUM_TX_RATE_RETRY_POLICIES 15 + +struct hif_mib_set_tx_rate_retry_policy { + uint8_t num_tx_rate_policies; + uint8_t reserved[3]; + struct hif_mib_tx_rate_retry_policy tx_rate_retry_policy[]; +} __packed; + +struct hif_mib_protected_mgmt_policy { + uint8_t pmf_enable:1; + uint8_t unpmf_allowed:1; + uint8_t host_enc_auth_frames:1; + uint8_t reserved1:5; + uint8_t reserved2[3]; +} __packed; + +struct hif_mib_set_ht_protection { + uint8_t dual_cts_prot:1; + uint8_t reserved1:7; + uint8_t reserved2[3]; +} __packed; + +struct hif_mib_keep_alive_period { + uint16_t keep_alive_period; + uint8_t reserved[2]; +} __packed; + +struct hif_mib_arp_keep_alive_period { + uint16_t arp_keep_alive_period; + uint8_t encr_type; + uint8_t reserved; + uint8_t sender_ipv4_address[HIF_API_IPV4_ADDRESS_SIZE]; + uint8_t target_ipv4_address[HIF_API_IPV4_ADDRESS_SIZE]; +} __packed; + +struct hif_mib_inactivity_timer { + uint8_t min_active_time; + uint8_t max_active_time; + uint16_t reserved; +} __packed; + +struct hif_mib_interface_protection { + uint8_t use_cts_prot:1; + uint8_t reserved1:7; + uint8_t reserved2[3]; +} __packed; + + +#endif diff --git a/drivers/staging/wfx/hif_rx.c b/drivers/staging/wfx/hif_rx.c new file mode 100644 index 000000000000..36e171b27ae2 --- /dev/null +++ b/drivers/staging/wfx/hif_rx.c @@ -0,0 +1,336 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Implementation of chip-to-host event (aka indications) of WFxxx Split Mac + * (WSM) API. + * + * Copyright (c) 2017-2019, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include <linux/skbuff.h> +#include <linux/etherdevice.h> + +#include "hif_rx.h" +#include "wfx.h" +#include "scan.h" +#include "bh.h" +#include "sta.h" +#include "data_rx.h" +#include "secure_link.h" +#include "hif_api_cmd.h" + +static int hif_generic_confirm(struct wfx_dev *wdev, struct hif_msg *hif, void *buf) +{ + // All confirm messages start with status + int status = le32_to_cpu(*((__le32 *) buf)); + int cmd = hif->id; + int len = hif->len - 4; // drop header + + WARN(!mutex_is_locked(&wdev->hif_cmd.lock), "data locking error"); + + if (!wdev->hif_cmd.buf_send) { + dev_warn(wdev->dev, "unexpected confirmation: 0x%.2x\n", cmd); + return -EINVAL; + } + + if (cmd != wdev->hif_cmd.buf_send->id) { + dev_warn(wdev->dev, "chip response mismatch request: 0x%.2x vs 0x%.2x\n", + cmd, wdev->hif_cmd.buf_send->id); + return -EINVAL; + } + + if (wdev->hif_cmd.buf_recv) { + if (wdev->hif_cmd.len_recv >= len) + memcpy(wdev->hif_cmd.buf_recv, buf, len); + else + status = -ENOMEM; + } + wdev->hif_cmd.ret = status; + + if (!wdev->hif_cmd.async) { + complete(&wdev->hif_cmd.done); + } else { + wdev->hif_cmd.buf_send = NULL; + mutex_unlock(&wdev->hif_cmd.lock); + if (cmd != HIF_REQ_ID_SL_EXCHANGE_PUB_KEYS) + mutex_unlock(&wdev->hif_cmd.key_renew_lock); + } + return status; +} + +static int hif_tx_confirm(struct wfx_dev *wdev, struct hif_msg *hif, void *buf) +{ + struct hif_cnf_tx *body = buf; + struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface); + + WARN_ON(!wvif); + if (!wvif) + return -EFAULT; + + wfx_tx_confirm_cb(wvif, body); + return 0; +} + +static int hif_multi_tx_confirm(struct wfx_dev *wdev, struct hif_msg *hif, void *buf) +{ + struct hif_cnf_multi_transmit *body = buf; + struct hif_cnf_tx *buf_loc = (struct hif_cnf_tx *) &body->tx_conf_payload; + struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface); + int count = body->num_tx_confs; + int i; + + WARN(count <= 0, "corrupted message"); + WARN_ON(!wvif); + if (!wvif) + return -EFAULT; + + for (i = 0; i < count; ++i) { + wfx_tx_confirm_cb(wvif, buf_loc); + buf_loc++; + } + return 0; +} + +static int hif_startup_indication(struct wfx_dev *wdev, struct hif_msg *hif, void *buf) +{ + struct hif_ind_startup *body = buf; + + if (body->status || body->firmware_type > 4) { + dev_err(wdev->dev, "received invalid startup indication"); + return -EINVAL; + } + memcpy(&wdev->hw_caps, body, sizeof(struct hif_ind_startup)); + le32_to_cpus(&wdev->hw_caps.status); + le16_to_cpus(&wdev->hw_caps.hardware_id); + le16_to_cpus(&wdev->hw_caps.num_inp_ch_bufs); + le16_to_cpus(&wdev->hw_caps.size_inp_ch_buf); + + complete(&wdev->firmware_ready); + return 0; +} + +static int hif_wakeup_indication(struct wfx_dev *wdev, struct hif_msg *hif, void *buf) +{ + if (!wdev->pdata.gpio_wakeup + || !gpiod_get_value(wdev->pdata.gpio_wakeup)) { + dev_warn(wdev->dev, "unexpected wake-up indication\n"); + return -EIO; + } + return 0; +} + +static int hif_keys_indication(struct wfx_dev *wdev, struct hif_msg *hif, void *buf) +{ + struct hif_ind_sl_exchange_pub_keys *body = buf; + + // Compatibility with legacy secure link + if (body->status == SL_PUB_KEY_EXCHANGE_STATUS_SUCCESS) + body->status = 0; + if (body->status) + dev_warn(wdev->dev, "secure link negociation error\n"); + wfx_sl_check_pubkey(wdev, body->ncp_pub_key, body->ncp_pub_key_mac); + return 0; +} + +static int hif_receive_indication(struct wfx_dev *wdev, struct hif_msg *hif, void *buf, struct sk_buff *skb) +{ + struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface); + struct hif_ind_rx *body = buf; + + if (!wvif) { + dev_warn(wdev->dev, "ignore rx data for non-existent vif %d\n", hif->interface); + return 0; + } + skb_pull(skb, sizeof(struct hif_msg) + sizeof(struct hif_ind_rx)); + wfx_rx_cb(wvif, body, skb); + + return 0; +} + +static int hif_event_indication(struct wfx_dev *wdev, struct hif_msg *hif, void *buf) +{ + struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface); + struct hif_ind_event *body = buf; + struct wfx_hif_event *event; + int first; + + WARN_ON(!wvif); + if (!wvif) + return 0; + + event = kzalloc(sizeof(*event), GFP_KERNEL); + if (!event) + return -ENOMEM; + + memcpy(&event->evt, body, sizeof(struct hif_ind_event)); + spin_lock(&wvif->event_queue_lock); + first = list_empty(&wvif->event_queue); + list_add_tail(&event->link, &wvif->event_queue); + spin_unlock(&wvif->event_queue_lock); + + if (first) + schedule_work(&wvif->event_handler_work); + + return 0; +} + +static int hif_pm_mode_complete_indication(struct wfx_dev *wdev, struct hif_msg *hif, void *buf) +{ + struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface); + + WARN_ON(!wvif); + complete(&wvif->set_pm_mode_complete); + + return 0; +} + +static int hif_scan_complete_indication(struct wfx_dev *wdev, struct hif_msg *hif, void *buf) +{ + struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface); + struct hif_ind_scan_cmpl *body = buf; + + WARN_ON(!wvif); + wfx_scan_complete_cb(wvif, body); + + return 0; +} + +static int hif_join_complete_indication(struct wfx_dev *wdev, struct hif_msg *hif, void *buf) +{ + struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface); + + WARN_ON(!wvif); + dev_warn(wdev->dev, "unattended JoinCompleteInd\n"); + + return 0; +} + +static int hif_suspend_resume_indication(struct wfx_dev *wdev, struct hif_msg *hif, void *buf) +{ + struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface); + struct hif_ind_suspend_resume_tx *body = buf; + + WARN_ON(!wvif); + wfx_suspend_resume(wvif, body); + + return 0; +} + +static int hif_error_indication(struct wfx_dev *wdev, struct hif_msg *hif, void *buf) +{ + struct hif_ind_error *body = buf; + u8 *pRollback = (u8 *) body->data; + u32 *pStatus = (u32 *) body->data; + + switch (body->type) { + case HIF_ERROR_FIRMWARE_ROLLBACK: + dev_err(wdev->dev, "asynchronous error: firmware rollback error %d\n", *pRollback); + break; + case HIF_ERROR_FIRMWARE_DEBUG_ENABLED: + dev_err(wdev->dev, "asynchronous error: firmware debug feature enabled\n"); + break; + case HIF_ERROR_OUTDATED_SESSION_KEY: + dev_err(wdev->dev, "asynchronous error: secure link outdated key: %#.8x\n", *pStatus); + break; + case HIF_ERROR_INVALID_SESSION_KEY: + dev_err(wdev->dev, "asynchronous error: invalid session key\n"); + break; + case HIF_ERROR_OOR_VOLTAGE: + dev_err(wdev->dev, "asynchronous error: out-of-range overvoltage: %#.8x\n", *pStatus); + break; + case HIF_ERROR_PDS_VERSION: + dev_err(wdev->dev, "asynchronous error: wrong PDS payload or version: %#.8x\n", *pStatus); + break; + default: + dev_err(wdev->dev, "asynchronous error: unknown (%d)\n", body->type); + break; + } + return 0; +} + +static int hif_generic_indication(struct wfx_dev *wdev, struct hif_msg *hif, void *buf) +{ + struct hif_ind_generic *body = buf; + + switch (body->indication_type) { + case HIF_GENERIC_INDICATION_TYPE_RAW: + return 0; + case HIF_GENERIC_INDICATION_TYPE_STRING: + dev_info(wdev->dev, "firmware says: %s\n", (char *) body->indication_data.raw_data); + return 0; + case HIF_GENERIC_INDICATION_TYPE_RX_STATS: + mutex_lock(&wdev->rx_stats_lock); + // Older firmware send a generic indication beside RxStats + if (!wfx_api_older_than(wdev, 1, 4)) + dev_info(wdev->dev, "Rx test ongoing. Temperature: %d°C\n", body->indication_data.rx_stats.current_temp); + memcpy(&wdev->rx_stats, &body->indication_data.rx_stats, sizeof(wdev->rx_stats)); + mutex_unlock(&wdev->rx_stats_lock); + return 0; + default: + dev_err(wdev->dev, "generic_indication: unknown indication type: %#.8x\n", body->indication_type); + return -EIO; + } +} + +static int hif_exception_indication(struct wfx_dev *wdev, struct hif_msg *hif, void *buf) +{ + size_t len = hif->len - 4; // drop header + dev_err(wdev->dev, "firmware exception\n"); + print_hex_dump_bytes("Dump: ", DUMP_PREFIX_NONE, buf, len); + wdev->chip_frozen = 1; + + return -1; +} + +static const struct { + int msg_id; + int (*handler)(struct wfx_dev *wdev, struct hif_msg *hif, void *buf); +} hif_handlers[] = { + /* Confirmations */ + { HIF_CNF_ID_TX, hif_tx_confirm }, + { HIF_CNF_ID_MULTI_TRANSMIT, hif_multi_tx_confirm }, + /* Indications */ + { HIF_IND_ID_STARTUP, hif_startup_indication }, + { HIF_IND_ID_WAKEUP, hif_wakeup_indication }, + { HIF_IND_ID_JOIN_COMPLETE, hif_join_complete_indication }, + { HIF_IND_ID_SET_PM_MODE_CMPL, hif_pm_mode_complete_indication }, + { HIF_IND_ID_SCAN_CMPL, hif_scan_complete_indication }, + { HIF_IND_ID_SUSPEND_RESUME_TX, hif_suspend_resume_indication }, + { HIF_IND_ID_SL_EXCHANGE_PUB_KEYS, hif_keys_indication }, + { HIF_IND_ID_EVENT, hif_event_indication }, + { HIF_IND_ID_GENERIC, hif_generic_indication }, + { HIF_IND_ID_ERROR, hif_error_indication }, + { HIF_IND_ID_EXCEPTION, hif_exception_indication }, + // FIXME: allocate skb_p from hif_receive_indication and make it generic + //{ HIF_IND_ID_RX, hif_receive_indication }, +}; + +void wfx_handle_rx(struct wfx_dev *wdev, struct sk_buff *skb) +{ + int i; + struct hif_msg *hif = (struct hif_msg *) skb->data; + int hif_id = hif->id; + + if (hif_id == HIF_IND_ID_RX) { + // hif_receive_indication take care of skb lifetime + hif_receive_indication(wdev, hif, hif->body, skb); + return; + } + // Note: mutex_is_lock cause an implicit memory barrier that protect + // buf_send + if (mutex_is_locked(&wdev->hif_cmd.lock) + && wdev->hif_cmd.buf_send + && wdev->hif_cmd.buf_send->id == hif_id) { + hif_generic_confirm(wdev, hif, hif->body); + goto free; + } + for (i = 0; i < ARRAY_SIZE(hif_handlers); i++) { + if (hif_handlers[i].msg_id == hif_id) { + if (hif_handlers[i].handler) + hif_handlers[i].handler(wdev, hif, hif->body); + goto free; + } + } + dev_err(wdev->dev, "unsupported HIF ID %02x\n", hif_id); +free: + dev_kfree_skb(skb); +} diff --git a/drivers/staging/wfx/hif_rx.h b/drivers/staging/wfx/hif_rx.h new file mode 100644 index 000000000000..f07c10c8c6bd --- /dev/null +++ b/drivers/staging/wfx/hif_rx.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Implementation of chip-to-host event (aka indications) of WFxxx Split Mac + * (WSM) API. + * + * Copyright (c) 2017-2019, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + * Copyright (C) 2010, ST-Ericsson SA + */ +#ifndef WFX_HIF_RX_H +#define WFX_HIF_RX_H + +struct wfx_dev; +struct sk_buff; + +void wfx_handle_rx(struct wfx_dev *wdev, struct sk_buff *skb); + +#endif diff --git a/drivers/staging/wfx/hif_tx.c b/drivers/staging/wfx/hif_tx.c new file mode 100644 index 000000000000..2d40225a0fce --- /dev/null +++ b/drivers/staging/wfx/hif_tx.c @@ -0,0 +1,470 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Implementation of host-to-chip commands (aka request/confirmation) of WFxxx + * Split Mac (WSM) API. + * + * Copyright (c) 2017-2019, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include <linux/skbuff.h> +#include <linux/etherdevice.h> + +#include "hif_tx.h" +#include "wfx.h" +#include "bh.h" +#include "hwio.h" +#include "debug.h" +#include "sta.h" + +void wfx_init_hif_cmd(struct wfx_hif_cmd *hif_cmd) +{ + init_completion(&hif_cmd->ready); + init_completion(&hif_cmd->done); + mutex_init(&hif_cmd->lock); + mutex_init(&hif_cmd->key_renew_lock); +} + +static void wfx_fill_header(struct hif_msg *hif, int if_id, unsigned int cmd, size_t size) +{ + if (if_id == -1) + if_id = 2; + + WARN(cmd > 0x3f, "invalid WSM command %#.2x", cmd); + WARN(size > 0xFFF, "requested buffer is too large: %zu bytes", size); + WARN(if_id > 0x3, "invalid interface ID %d", if_id); + + hif->len = cpu_to_le16(size + 4); + hif->id = cmd; + hif->interface = if_id; +} + +static void *wfx_alloc_hif(size_t body_len, struct hif_msg **hif) +{ + *hif = kzalloc(sizeof(struct hif_msg) + body_len, GFP_KERNEL); + if (*hif) + return (*hif)->body; + else + return NULL; +} + +int wfx_cmd_send(struct wfx_dev *wdev, struct hif_msg *request, void *reply, size_t reply_len, bool async) +{ + const char *mib_name = ""; + const char *mib_sep = ""; + int cmd = request->id; + int vif = request->interface; + int ret; + + WARN(wdev->hif_cmd.buf_recv && wdev->hif_cmd.async, "API usage error"); + + // Do not wait for any reply if chip is frozen + if (wdev->chip_frozen) + return -ETIMEDOUT; + + if (cmd != HIF_REQ_ID_SL_EXCHANGE_PUB_KEYS) + mutex_lock(&wdev->hif_cmd.key_renew_lock); + + mutex_lock(&wdev->hif_cmd.lock); + WARN(wdev->hif_cmd.buf_send, "data locking error"); + + // Note: call to complete() below has an implicit memory barrier that + // hopefully protect buf_send + wdev->hif_cmd.buf_send = request; + wdev->hif_cmd.buf_recv = reply; + wdev->hif_cmd.len_recv = reply_len; + wdev->hif_cmd.async = async; + complete(&wdev->hif_cmd.ready); + + wfx_bh_request_tx(wdev); + + // NOTE: no timeout is catched async is enabled + if (async) + return 0; + + ret = wait_for_completion_timeout(&wdev->hif_cmd.done, 1 * HZ); + if (!ret) { + dev_err(wdev->dev, "chip is abnormally long to answer\n"); + reinit_completion(&wdev->hif_cmd.ready); + ret = wait_for_completion_timeout(&wdev->hif_cmd.done, 3 * HZ); + } + if (!ret) { + dev_err(wdev->dev, "chip did not answer\n"); + wfx_pending_dump_old_frames(wdev, 3000); + wdev->chip_frozen = 1; + reinit_completion(&wdev->hif_cmd.done); + ret = -ETIMEDOUT; + } else { + ret = wdev->hif_cmd.ret; + } + + wdev->hif_cmd.buf_send = NULL; + mutex_unlock(&wdev->hif_cmd.lock); + + if (ret && (cmd == HIF_REQ_ID_READ_MIB || cmd == HIF_REQ_ID_WRITE_MIB)) { + mib_name = get_mib_name(((u16 *) request)[2]); + mib_sep = "/"; + } + if (ret < 0) + dev_err(wdev->dev, + "WSM request %s%s%s (%#.2x) on vif %d returned error %d\n", + get_hif_name(cmd), mib_sep, mib_name, cmd, vif, ret); + if (ret > 0) + dev_warn(wdev->dev, + "WSM request %s%s%s (%#.2x) on vif %d returned status %d\n", + get_hif_name(cmd), mib_sep, mib_name, cmd, vif, ret); + + if (cmd != HIF_REQ_ID_SL_EXCHANGE_PUB_KEYS) + mutex_unlock(&wdev->hif_cmd.key_renew_lock); + return ret; +} + +// This function is special. After HIF_REQ_ID_SHUT_DOWN, chip won't reply to any +// request anymore. We need to slightly hack struct wfx_hif_cmd for that job. Be +// carefull to only call this funcion during device unregister. +int hif_shutdown(struct wfx_dev *wdev) +{ + int ret; + struct hif_msg *hif; + + wfx_alloc_hif(0, &hif); + wfx_fill_header(hif, -1, HIF_REQ_ID_SHUT_DOWN, 0); + ret = wfx_cmd_send(wdev, hif, NULL, 0, true); + // After this command, chip won't reply. Be sure to give enough time to + // bh to send buffer: + msleep(100); + wdev->hif_cmd.buf_send = NULL; + if (wdev->pdata.gpio_wakeup) + gpiod_set_value(wdev->pdata.gpio_wakeup, 0); + else + control_reg_write(wdev, 0); + mutex_unlock(&wdev->hif_cmd.lock); + kfree(hif); + return ret; +} + +int hif_configuration(struct wfx_dev *wdev, const u8 *conf, size_t len) +{ + int ret; + size_t buf_len = sizeof(struct hif_req_configuration) + len; + struct hif_msg *hif; + struct hif_req_configuration *body = wfx_alloc_hif(buf_len, &hif); + + body->length = cpu_to_le16(len); + memcpy(body->pds_data, conf, len); + wfx_fill_header(hif, -1, HIF_REQ_ID_CONFIGURATION, buf_len); + ret = wfx_cmd_send(wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int hif_reset(struct wfx_vif *wvif, bool reset_stat) +{ + int ret; + struct hif_msg *hif; + struct hif_req_reset *body = wfx_alloc_hif(sizeof(*body), &hif); + + body->reset_flags.reset_stat = reset_stat; + wfx_fill_header(hif, wvif->id, HIF_REQ_ID_RESET, sizeof(*body)); + ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int hif_read_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, void *val, size_t val_len) +{ + int ret; + struct hif_msg *hif; + int buf_len = sizeof(struct hif_cnf_read_mib) + val_len; + struct hif_req_read_mib *body = wfx_alloc_hif(sizeof(*body), &hif); + struct hif_cnf_read_mib *reply = kmalloc(buf_len, GFP_KERNEL); + + body->mib_id = cpu_to_le16(mib_id); + wfx_fill_header(hif, vif_id, HIF_REQ_ID_READ_MIB, sizeof(*body)); + ret = wfx_cmd_send(wdev, hif, reply, buf_len, false); + + if (!ret && mib_id != reply->mib_id) { + dev_warn(wdev->dev, "%s: confirmation mismatch request\n", __func__); + ret = -EIO; + } + if (ret == -ENOMEM) + dev_err(wdev->dev, "buffer is too small to receive %s (%zu < %d)\n", + get_mib_name(mib_id), val_len, reply->length); + if (!ret) + memcpy(val, &reply->mib_data, reply->length); + else + memset(val, 0xFF, val_len); + kfree(hif); + kfree(reply); + return ret; +} + +int hif_write_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, void *val, size_t val_len) +{ + int ret; + struct hif_msg *hif; + int buf_len = sizeof(struct hif_req_write_mib) + val_len; + struct hif_req_write_mib *body = wfx_alloc_hif(buf_len, &hif); + + body->mib_id = cpu_to_le16(mib_id); + body->length = cpu_to_le16(val_len); + memcpy(&body->mib_data, val, val_len); + wfx_fill_header(hif, vif_id, HIF_REQ_ID_WRITE_MIB, buf_len); + ret = wfx_cmd_send(wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int hif_scan(struct wfx_vif *wvif, const struct wfx_scan_params *arg) +{ + int ret, i; + struct hif_msg *hif; + struct hif_ssid_def *ssids; + size_t buf_len = sizeof(struct hif_req_start_scan) + + arg->scan_req.num_of_channels * sizeof(u8) + + arg->scan_req.num_of_ssi_ds * sizeof(struct hif_ssid_def); + struct hif_req_start_scan *body = wfx_alloc_hif(buf_len, &hif); + u8 *ptr = (u8 *) body + sizeof(*body); + + WARN(arg->scan_req.num_of_channels > HIF_API_MAX_NB_CHANNELS, "invalid params"); + WARN(arg->scan_req.num_of_ssi_ds > 2, "invalid params"); + WARN(arg->scan_req.band > 1, "invalid params"); + + // FIXME: This API is unnecessary complex, fixing NumOfChannels and + // adding a member SsidDef at end of struct hif_req_start_scan would + // simplify that a lot. + memcpy(body, &arg->scan_req, sizeof(*body)); + cpu_to_le32s(&body->min_channel_time); + cpu_to_le32s(&body->max_channel_time); + cpu_to_le32s(&body->tx_power_level); + memcpy(ptr, arg->ssids, arg->scan_req.num_of_ssi_ds * sizeof(struct hif_ssid_def)); + ssids = (struct hif_ssid_def *) ptr; + for (i = 0; i < body->num_of_ssi_ds; ++i) + cpu_to_le32s(&ssids[i].ssid_length); + ptr += arg->scan_req.num_of_ssi_ds * sizeof(struct hif_ssid_def); + memcpy(ptr, arg->ch, arg->scan_req.num_of_channels * sizeof(u8)); + ptr += arg->scan_req.num_of_channels * sizeof(u8); + WARN(buf_len != ptr - (u8 *) body, "allocation size mismatch"); + wfx_fill_header(hif, wvif->id, HIF_REQ_ID_START_SCAN, buf_len); + ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int hif_stop_scan(struct wfx_vif *wvif) +{ + int ret; + struct hif_msg *hif; + // body associated to HIF_REQ_ID_STOP_SCAN is empty + wfx_alloc_hif(0, &hif); + + wfx_fill_header(hif, wvif->id, HIF_REQ_ID_STOP_SCAN, 0); + ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int hif_join(struct wfx_vif *wvif, const struct hif_req_join *arg) +{ + int ret; + struct hif_msg *hif; + struct hif_req_join *body = wfx_alloc_hif(sizeof(*body), &hif); + + memcpy(body, arg, sizeof(struct hif_req_join)); + cpu_to_le16s(&body->channel_number); + cpu_to_le16s(&body->atim_window); + cpu_to_le32s(&body->ssid_length); + cpu_to_le32s(&body->beacon_interval); + cpu_to_le32s(&body->basic_rate_set); + wfx_fill_header(hif, wvif->id, HIF_REQ_ID_JOIN, sizeof(*body)); + ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int hif_set_bss_params(struct wfx_vif *wvif, const struct hif_req_set_bss_params *arg) +{ + int ret; + struct hif_msg *hif; + struct hif_req_set_bss_params *body = wfx_alloc_hif(sizeof(*body), &hif); + + memcpy(body, arg, sizeof(*body)); + cpu_to_le16s(&body->aid); + cpu_to_le32s(&body->operational_rate_set); + wfx_fill_header(hif, wvif->id, HIF_REQ_ID_SET_BSS_PARAMS, sizeof(*body)); + ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int hif_add_key(struct wfx_dev *wdev, const struct hif_req_add_key *arg) +{ + int ret; + struct hif_msg *hif; + // FIXME: only send necessary bits + struct hif_req_add_key *body = wfx_alloc_hif(sizeof(*body), &hif); + + // FIXME: swap bytes as necessary in body + memcpy(body, arg, sizeof(*body)); + if (wfx_api_older_than(wdev, 1, 5)) + // Legacy firmwares expect that add_key to be sent on right + // interface. + wfx_fill_header(hif, arg->int_id, HIF_REQ_ID_ADD_KEY, sizeof(*body)); + else + wfx_fill_header(hif, -1, HIF_REQ_ID_ADD_KEY, sizeof(*body)); + ret = wfx_cmd_send(wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int hif_remove_key(struct wfx_dev *wdev, int idx) +{ + int ret; + struct hif_msg *hif; + struct hif_req_remove_key *body = wfx_alloc_hif(sizeof(*body), &hif); + + body->entry_index = idx; + wfx_fill_header(hif, -1, HIF_REQ_ID_REMOVE_KEY, sizeof(*body)); + ret = wfx_cmd_send(wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int hif_set_edca_queue_params(struct wfx_vif *wvif, const struct hif_req_edca_queue_params *arg) +{ + int ret; + struct hif_msg *hif; + struct hif_req_edca_queue_params *body = wfx_alloc_hif(sizeof(*body), &hif); + + // NOTE: queues numerotation are not the same between WFx and Linux + memcpy(body, arg, sizeof(*body)); + cpu_to_le16s(&body->cw_min); + cpu_to_le16s(&body->cw_max); + cpu_to_le16s(&body->tx_op_limit); + wfx_fill_header(hif, wvif->id, HIF_REQ_ID_EDCA_QUEUE_PARAMS, sizeof(*body)); + ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int hif_set_pm(struct wfx_vif *wvif, const struct hif_req_set_pm_mode *arg) +{ + int ret; + struct hif_msg *hif; + struct hif_req_set_pm_mode *body = wfx_alloc_hif(sizeof(*body), &hif); + + memcpy(body, arg, sizeof(*body)); + wfx_fill_header(hif, wvif->id, HIF_REQ_ID_SET_PM_MODE, sizeof(*body)); + ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int hif_start(struct wfx_vif *wvif, const struct hif_req_start *arg) +{ + int ret; + struct hif_msg *hif; + struct hif_req_start *body = wfx_alloc_hif(sizeof(*body), &hif); + + memcpy(body, arg, sizeof(*body)); + cpu_to_le16s(&body->channel_number); + cpu_to_le32s(&body->beacon_interval); + cpu_to_le32s(&body->basic_rate_set); + wfx_fill_header(hif, wvif->id, HIF_REQ_ID_START, sizeof(*body)); + ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int hif_beacon_transmit(struct wfx_vif *wvif, bool enable_beaconing) +{ + int ret; + struct hif_msg *hif; + struct hif_req_beacon_transmit *body = wfx_alloc_hif(sizeof(*body), &hif); + + body->enable_beaconing = enable_beaconing ? 1 : 0; + wfx_fill_header(hif, wvif->id, HIF_REQ_ID_BEACON_TRANSMIT, sizeof(*body)); + ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int hif_map_link(struct wfx_vif *wvif, u8 *mac_addr, int flags, int sta_id) +{ + int ret; + struct hif_msg *hif; + struct hif_req_map_link *body = wfx_alloc_hif(sizeof(*body), &hif); + + if (mac_addr) + ether_addr_copy(body->mac_addr, mac_addr); + body->map_link_flags = *(struct hif_map_link_flags *) &flags; + body->peer_sta_id = sta_id; + wfx_fill_header(hif, wvif->id, HIF_REQ_ID_MAP_LINK, sizeof(*body)); + ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int hif_update_ie(struct wfx_vif *wvif, const struct hif_ie_flags *target_frame, + const u8 *ies, size_t ies_len) +{ + int ret; + struct hif_msg *hif; + int buf_len = sizeof(struct hif_req_update_ie) + ies_len; + struct hif_req_update_ie *body = wfx_alloc_hif(buf_len, &hif); + + memcpy(&body->ie_flags, target_frame, sizeof(struct hif_ie_flags)); + body->num_i_es = cpu_to_le16(1); + memcpy(body->ie, ies, ies_len); + wfx_fill_header(hif, wvif->id, HIF_REQ_ID_UPDATE_IE, buf_len); + ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int hif_sl_send_pub_keys(struct wfx_dev *wdev, const uint8_t *pubkey, const uint8_t *pubkey_hmac) +{ + int ret; + struct hif_msg *hif; + struct hif_req_sl_exchange_pub_keys *body = wfx_alloc_hif(sizeof(*body), &hif); + + body->algorithm = HIF_SL_CURVE25519; + memcpy(body->host_pub_key, pubkey, sizeof(body->host_pub_key)); + memcpy(body->host_pub_key_mac, pubkey_hmac, sizeof(body->host_pub_key_mac)); + wfx_fill_header(hif, -1, HIF_REQ_ID_SL_EXCHANGE_PUB_KEYS, sizeof(*body)); + ret = wfx_cmd_send(wdev, hif, NULL, 0, false); + kfree(hif); + // Compatibility with legacy secure link + if (ret == SL_PUB_KEY_EXCHANGE_STATUS_SUCCESS) + ret = 0; + return ret; +} + +int hif_sl_config(struct wfx_dev *wdev, const unsigned long *bitmap) +{ + int ret; + struct hif_msg *hif; + struct hif_req_sl_configure *body = wfx_alloc_hif(sizeof(*body), &hif); + + memcpy(body->encr_bmp, bitmap, sizeof(body->encr_bmp)); + wfx_fill_header(hif, -1, HIF_REQ_ID_SL_CONFIGURE, sizeof(*body)); + ret = wfx_cmd_send(wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int hif_sl_set_mac_key(struct wfx_dev *wdev, const uint8_t *slk_key, int destination) +{ + int ret; + struct hif_msg *hif; + struct hif_req_set_sl_mac_key *body = wfx_alloc_hif(sizeof(*body), &hif); + + memcpy(body->key_value, slk_key, sizeof(body->key_value)); + body->otp_or_ram = destination; + wfx_fill_header(hif, -1, HIF_REQ_ID_SET_SL_MAC_KEY, sizeof(*body)); + ret = wfx_cmd_send(wdev, hif, NULL, 0, false); + kfree(hif); + // Compatibility with legacy secure link + if (ret == SL_MAC_KEY_STATUS_SUCCESS) + ret = 0; + return ret; +} diff --git a/drivers/staging/wfx/hif_tx.h b/drivers/staging/wfx/hif_tx.h new file mode 100644 index 000000000000..6f2ea2f3a77d --- /dev/null +++ b/drivers/staging/wfx/hif_tx.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Implementation of host-to-chip commands (aka request/confirmation) of WFxxx + * Split Mac (WSM) API. + * + * Copyright (c) 2017-2019, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + * Copyright (C) 2010, ST-Ericsson SA + */ +#ifndef WFX_HIF_TX_H +#define WFX_HIF_TX_H + +#include "hif_api_cmd.h" + +struct wfx_dev; +struct wfx_vif; + +struct wfx_scan_params { + struct hif_req_start_scan scan_req; + struct hif_ssid_def *ssids; + uint8_t *ch; +}; + +struct wfx_hif_cmd { + struct mutex lock; + struct mutex key_renew_lock; + struct completion ready; + struct completion done; + bool async; + struct hif_msg *buf_send; + void *buf_recv; + size_t len_recv; + int ret; +}; + +void wfx_init_hif_cmd(struct wfx_hif_cmd *wfx_hif_cmd); +int wfx_cmd_send(struct wfx_dev *wdev, struct hif_msg *request, + void *reply, size_t reply_len, bool async); + +int hif_shutdown(struct wfx_dev *wdev); +int hif_configuration(struct wfx_dev *wdev, const u8 *conf, size_t len); +int hif_reset(struct wfx_vif *wvif, bool reset_stat); +int hif_read_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, + void *buf, size_t buf_size); +int hif_write_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, + void *buf, size_t buf_size); +int hif_scan(struct wfx_vif *wvif, const struct wfx_scan_params *arg); +int hif_stop_scan(struct wfx_vif *wvif); +int hif_join(struct wfx_vif *wvif, const struct hif_req_join *arg); +int hif_set_pm(struct wfx_vif *wvif, const struct hif_req_set_pm_mode *arg); +int hif_set_bss_params(struct wfx_vif *wvif, + const struct hif_req_set_bss_params *arg); +int hif_add_key(struct wfx_dev *wdev, const struct hif_req_add_key *arg); +int hif_remove_key(struct wfx_dev *wdev, int idx); +int hif_set_edca_queue_params(struct wfx_vif *wvif, + const struct hif_req_edca_queue_params *arg); +int hif_start(struct wfx_vif *wvif, const struct hif_req_start *arg); +int hif_beacon_transmit(struct wfx_vif *wvif, bool enable); +int hif_map_link(struct wfx_vif *wvif, u8 *mac_addr, int flags, int sta_id); +int hif_update_ie(struct wfx_vif *wvif, const struct hif_ie_flags *target_frame, + const u8 *ies, size_t ies_len); +int hif_sl_set_mac_key(struct wfx_dev *wdev, const uint8_t *slk_key, int destination); +int hif_sl_config(struct wfx_dev *wdev, const unsigned long *bitmap); +int hif_sl_send_pub_keys(struct wfx_dev *wdev, + const uint8_t *pubkey, const uint8_t *pubkey_hmac); + +#endif diff --git a/drivers/staging/wfx/hif_tx_mib.h b/drivers/staging/wfx/hif_tx_mib.h new file mode 100644 index 000000000000..3339ad95f732 --- /dev/null +++ b/drivers/staging/wfx/hif_tx_mib.h @@ -0,0 +1,290 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Implementation of host-to-chip MIBs of WFxxx Split Mac (WSM) API. + * + * Copyright (c) 2017-2019, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + * Copyright (C) 2010, ST-Ericsson SA + */ +#ifndef WFX_HIF_TX_MIB_H +#define WFX_HIF_TX_MIB_H + +#include <linux/etherdevice.h> + +#include "wfx.h" +#include "hif_tx.h" +#include "hif_api_mib.h" + +static inline int hif_set_output_power(struct wfx_vif *wvif, int power_level) +{ + __le32 val = cpu_to_le32(power_level); + + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_CURRENT_TX_POWER_LEVEL, + &val, sizeof(val)); +} + +static inline int hif_set_beacon_wakeup_period(struct wfx_vif *wvif, + unsigned int dtim_interval, + unsigned int listen_interval) +{ + struct hif_mib_beacon_wake_up_period val = { + .wakeup_period_min = dtim_interval, + .receive_dtim = 0, + .wakeup_period_max = cpu_to_le16(listen_interval), + }; + + if (dtim_interval > 0xFF || listen_interval > 0xFFFF) + return -EINVAL; + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_BEACON_WAKEUP_PERIOD, + &val, sizeof(val)); +} + +static inline int hif_set_rcpi_rssi_threshold(struct wfx_vif *wvif, + struct hif_mib_rcpi_rssi_threshold *arg) +{ + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_RCPI_RSSI_THRESHOLD, arg, sizeof(*arg)); +} + +static inline int hif_get_counters_table(struct wfx_dev *wdev, + struct hif_mib_extended_count_table *arg) +{ + if (wfx_api_older_than(wdev, 1, 3)) { + // extended_count_table is wider than count_table + memset(arg, 0xFF, sizeof(*arg)); + return hif_read_mib(wdev, 0, HIF_MIB_ID_COUNTERS_TABLE, + arg, sizeof(struct hif_mib_count_table)); + } else { + return hif_read_mib(wdev, 0, HIF_MIB_ID_EXTENDED_COUNTERS_TABLE, + arg, sizeof(struct hif_mib_extended_count_table)); + } +} + +static inline int hif_set_macaddr(struct wfx_vif *wvif, u8 *mac) +{ + struct hif_mib_mac_address msg = { }; + + if (mac) + ether_addr_copy(msg.mac_addr, mac); + return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_DOT11_MAC_ADDRESS, + &msg, sizeof(msg)); +} + +static inline int hif_set_rx_filter(struct wfx_vif *wvif, bool filter_bssid, + bool fwd_probe_req) +{ + struct hif_mib_rx_filter val = { }; + + if (filter_bssid) + val.bssid_filter = 1; + if (fwd_probe_req) + val.fwd_probe_req = 1; + return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_RX_FILTER, + &val, sizeof(val)); +} + +static inline int hif_set_beacon_filter_table(struct wfx_vif *wvif, + int tbl_len, + struct hif_ie_table_entry *tbl) +{ + int ret; + struct hif_mib_bcn_filter_table *val; + int buf_len = struct_size(val, ie_table, tbl_len); + + val = kzalloc(buf_len, GFP_KERNEL); + if (!val) + return -ENOMEM; + val->num_of_info_elmts = cpu_to_le32(tbl_len); + memcpy(val->ie_table, tbl, tbl_len * sizeof(*tbl)); + ret = hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_BEACON_FILTER_TABLE, val, buf_len); + kfree(val); + return ret; +} + +static inline int hif_beacon_filter_control(struct wfx_vif *wvif, + int enable, int beacon_count) +{ + struct hif_mib_bcn_filter_enable arg = { + .enable = cpu_to_le32(enable), + .bcn_count = cpu_to_le32(beacon_count), + }; + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_BEACON_FILTER_ENABLE, &arg, sizeof(arg)); +} + +static inline int hif_set_operational_mode(struct wfx_dev *wdev, + enum hif_op_power_mode mode) +{ + struct hif_mib_gl_operational_power_mode val = { + .power_mode = mode, + .wup_ind_activation = 1, + }; + + return hif_write_mib(wdev, -1, HIF_MIB_ID_GL_OPERATIONAL_POWER_MODE, + &val, sizeof(val)); +} + +static inline int hif_set_template_frame(struct wfx_vif *wvif, + struct hif_mib_template_frame *arg) +{ + return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_TEMPLATE_FRAME, + arg, sizeof(*arg)); +} + +static inline int hif_set_mfp(struct wfx_vif *wvif, bool capable, bool required) +{ + struct hif_mib_protected_mgmt_policy val = { }; + + WARN(required && !capable, "incoherent arguments"); + if (capable) { + val.pmf_enable = 1; + val.host_enc_auth_frames = 1; + } + if (!required) + val.unpmf_allowed = 1; + cpu_to_le32s((uint32_t *) &val); + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_PROTECTED_MGMT_POLICY, + &val, sizeof(val)); +} + +static inline int hif_set_block_ack_policy(struct wfx_vif *wvif, + u8 tx_tid_policy, u8 rx_tid_policy) +{ + struct hif_mib_block_ack_policy val = { + .block_ack_tx_tid_policy = tx_tid_policy, + .block_ack_rx_tid_policy = rx_tid_policy, + }; + + return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_BLOCK_ACK_POLICY, + &val, sizeof(val)); +} + +static inline int hif_set_association_mode(struct wfx_vif *wvif, + struct hif_mib_set_association_mode *arg) +{ + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_SET_ASSOCIATION_MODE, arg, sizeof(*arg)); +} + +static inline int hif_set_tx_rate_retry_policy(struct wfx_vif *wvif, + struct hif_mib_set_tx_rate_retry_policy *arg) +{ + size_t size = struct_size(arg, tx_rate_retry_policy, arg->num_tx_rate_policies); + + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_SET_TX_RATE_RETRY_POLICY, arg, size); +} + +static inline int hif_set_mac_addr_condition(struct wfx_vif *wvif, + struct hif_mib_mac_addr_data_frame_condition *arg) +{ + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_MAC_ADDR_DATAFRAME_CONDITION, + arg, sizeof(*arg)); +} + +static inline int hif_set_uc_mc_bc_condition(struct wfx_vif *wvif, + struct hif_mib_uc_mc_bc_data_frame_condition *arg) +{ + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_UC_MC_BC_DATAFRAME_CONDITION, + arg, sizeof(*arg)); +} + +static inline int hif_set_config_data_filter(struct wfx_vif *wvif, + struct hif_mib_config_data_filter *arg) +{ + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_CONFIG_DATA_FILTER, arg, sizeof(*arg)); +} + +static inline int hif_set_data_filtering(struct wfx_vif *wvif, + struct hif_mib_set_data_filtering *arg) +{ + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_SET_DATA_FILTERING, arg, sizeof(*arg)); +} + +static inline int hif_keep_alive_period(struct wfx_vif *wvif, int period) +{ + struct hif_mib_keep_alive_period arg = { + .keep_alive_period = cpu_to_le16(period), + }; + + return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_KEEP_ALIVE_PERIOD, + &arg, sizeof(arg)); +}; + +static inline int hif_set_arp_ipv4_filter(struct wfx_vif *wvif, + struct hif_mib_arp_ip_addr_table *fp) +{ + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_ARP_IP_ADDRESSES_TABLE, + fp, sizeof(*fp)); +} + +static inline int hif_use_multi_tx_conf(struct wfx_dev *wdev, + bool enabled) +{ + __le32 arg = enabled ? cpu_to_le32(1) : 0; + + return hif_write_mib(wdev, -1, HIF_MIB_ID_GL_SET_MULTI_MSG, + &arg, sizeof(arg)); +} + +static inline int hif_set_uapsd_info(struct wfx_vif *wvif, + struct hif_mib_set_uapsd_information *arg) +{ + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_SET_UAPSD_INFORMATION, + arg, sizeof(*arg)); +} + +static inline int hif_erp_use_protection(struct wfx_vif *wvif, bool enable) +{ + __le32 arg = enable ? cpu_to_le32(1) : 0; + + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_NON_ERP_PROTECTION, &arg, sizeof(arg)); +} + +static inline int hif_slot_time(struct wfx_vif *wvif, int val) +{ + __le32 arg = cpu_to_le32(val); + + return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_SLOT_TIME, + &arg, sizeof(arg)); +} + +static inline int hif_dual_cts_protection(struct wfx_vif *wvif, bool val) +{ + struct hif_mib_set_ht_protection arg = { + .dual_cts_prot = val, + }; + + return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_SET_HT_PROTECTION, + &arg, sizeof(arg)); +} + +static inline int hif_wep_default_key_id(struct wfx_vif *wvif, int val) +{ + __le32 arg = cpu_to_le32(val); + + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_DOT11_WEP_DEFAULT_KEY_ID, + &arg, sizeof(arg)); +} + +static inline int hif_rts_threshold(struct wfx_vif *wvif, int val) +{ + __le32 arg = cpu_to_le32(val > 0 ? val : 0xFFFF); + + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_DOT11_RTS_THRESHOLD, &arg, sizeof(arg)); +} + +#endif diff --git a/drivers/staging/wfx/hwio.c b/drivers/staging/wfx/hwio.c new file mode 100644 index 000000000000..0cf52aee10e7 --- /dev/null +++ b/drivers/staging/wfx/hwio.c @@ -0,0 +1,338 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Low-level I/O functions. + * + * Copyright (c) 2017-2019, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/slab.h> + +#include "hwio.h" +#include "wfx.h" +#include "bus.h" +#include "traces.h" + +/* + * Internal helpers. + * + * About CONFIG_VMAP_STACK: + * When CONFIG_VMAP_STACK is enabled, it is not possible to run DMA on stack + * allocated data. Functions below that work with registers (aka functions + * ending with "32") automatically reallocate buffers with kmalloc. However, + * functions that work with arbitrary length buffers let's caller to handle + * memory location. In doubt, enable CONFIG_DEBUG_SG to detect badly located + * buffer. + */ + +static int read32(struct wfx_dev *wdev, int reg, u32 *val) +{ + int ret; + __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL); + + *val = ~0; // Never return undefined value + if (!tmp) + return -ENOMEM; + ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, reg, tmp, sizeof(u32)); + if (ret >= 0) + *val = le32_to_cpu(*tmp); + kfree(tmp); + if (ret) + dev_err(wdev->dev, "%s: bus communication error: %d\n", __func__, ret); + return ret; +} + +static int write32(struct wfx_dev *wdev, int reg, u32 val) +{ + int ret; + __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL); + + if (!tmp) + return -ENOMEM; + *tmp = cpu_to_le32(val); + ret = wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, reg, tmp, sizeof(u32)); + kfree(tmp); + if (ret) + dev_err(wdev->dev, "%s: bus communication error: %d\n", __func__, ret); + return ret; +} + +static int read32_locked(struct wfx_dev *wdev, int reg, u32 *val) +{ + int ret; + + wdev->hwbus_ops->lock(wdev->hwbus_priv); + ret = read32(wdev, reg, val); + _trace_io_read32(reg, *val); + wdev->hwbus_ops->unlock(wdev->hwbus_priv); + return ret; +} + +static int write32_locked(struct wfx_dev *wdev, int reg, u32 val) +{ + int ret; + + wdev->hwbus_ops->lock(wdev->hwbus_priv); + ret = write32(wdev, reg, val); + _trace_io_write32(reg, val); + wdev->hwbus_ops->unlock(wdev->hwbus_priv); + return ret; +} + +static int write32_bits_locked(struct wfx_dev *wdev, int reg, u32 mask, u32 val) +{ + int ret; + u32 val_r, val_w; + + WARN_ON(~mask & val); + val &= mask; + wdev->hwbus_ops->lock(wdev->hwbus_priv); + ret = read32(wdev, reg, &val_r); + _trace_io_read32(reg, val_r); + if (ret < 0) + goto err; + val_w = (val_r & ~mask) | val; + if (val_w != val_r) { + ret = write32(wdev, reg, val_w); + _trace_io_write32(reg, val_w); + } +err: + wdev->hwbus_ops->unlock(wdev->hwbus_priv); + return ret; +} + +static int indirect_read(struct wfx_dev *wdev, int reg, u32 addr, void *buf, size_t len) +{ + int ret; + int i; + u32 cfg; + u32 prefetch; + + WARN_ON(len >= 0x2000); + WARN_ON(reg != WFX_REG_AHB_DPORT && reg != WFX_REG_SRAM_DPORT); + + if (reg == WFX_REG_AHB_DPORT) + prefetch = CFG_PREFETCH_AHB; + else if (reg == WFX_REG_SRAM_DPORT) + prefetch = CFG_PREFETCH_SRAM; + else + return -ENODEV; + + ret = write32(wdev, WFX_REG_BASE_ADDR, addr); + if (ret < 0) + goto err; + + ret = read32(wdev, WFX_REG_CONFIG, &cfg); + if (ret < 0) + goto err; + + ret = write32(wdev, WFX_REG_CONFIG, cfg | prefetch); + if (ret < 0) + goto err; + + for (i = 0; i < 20; i++) { + ret = read32(wdev, WFX_REG_CONFIG, &cfg); + if (ret < 0) + goto err; + if (!(cfg & prefetch)) + break; + udelay(200); + } + if (i == 20) { + ret = -ETIMEDOUT; + goto err; + } + + ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, reg, buf, len); + +err: + if (ret < 0) + memset(buf, 0xFF, len); // Never return undefined value + return ret; +} + +static int indirect_write(struct wfx_dev *wdev, int reg, u32 addr, const void *buf, size_t len) +{ + int ret; + + WARN_ON(len >= 0x2000); + WARN_ON(reg != WFX_REG_AHB_DPORT && reg != WFX_REG_SRAM_DPORT); + ret = write32(wdev, WFX_REG_BASE_ADDR, addr); + if (ret < 0) + return ret; + + return wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, reg, buf, len); +} + +static int indirect_read_locked(struct wfx_dev *wdev, int reg, u32 addr, void *buf, size_t len) +{ + int ret; + + wdev->hwbus_ops->lock(wdev->hwbus_priv); + ret = indirect_read(wdev, reg, addr, buf, len); + _trace_io_ind_read(reg, addr, buf, len); + wdev->hwbus_ops->unlock(wdev->hwbus_priv); + return ret; +} + +static int indirect_write_locked(struct wfx_dev *wdev, int reg, u32 addr, const void *buf, size_t len) +{ + int ret; + + wdev->hwbus_ops->lock(wdev->hwbus_priv); + ret = indirect_write(wdev, reg, addr, buf, len); + _trace_io_ind_write(reg, addr, buf, len); + wdev->hwbus_ops->unlock(wdev->hwbus_priv); + return ret; +} + +static int indirect_read32_locked(struct wfx_dev *wdev, int reg, u32 addr, u32 *val) +{ + int ret; + __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL); + + if (!tmp) + return -ENOMEM; + wdev->hwbus_ops->lock(wdev->hwbus_priv); + ret = indirect_read(wdev, reg, addr, tmp, sizeof(u32)); + *val = cpu_to_le32(*tmp); + _trace_io_ind_read32(reg, addr, *val); + wdev->hwbus_ops->unlock(wdev->hwbus_priv); + kfree(tmp); + return ret; +} + +static int indirect_write32_locked(struct wfx_dev *wdev, int reg, u32 addr, u32 val) +{ + int ret; + __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL); + + if (!tmp) + return -ENOMEM; + *tmp = cpu_to_le32(val); + wdev->hwbus_ops->lock(wdev->hwbus_priv); + ret = indirect_write(wdev, reg, addr, tmp, sizeof(u32)); + _trace_io_ind_write32(reg, addr, val); + wdev->hwbus_ops->unlock(wdev->hwbus_priv); + kfree(tmp); + return ret; +} + +int wfx_data_read(struct wfx_dev *wdev, void *buf, size_t len) +{ + int ret; + + WARN((long) buf & 3, "%s: unaligned buffer", __func__); + wdev->hwbus_ops->lock(wdev->hwbus_priv); + ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, WFX_REG_IN_OUT_QUEUE, buf, len); + _trace_io_read(WFX_REG_IN_OUT_QUEUE, buf, len); + wdev->hwbus_ops->unlock(wdev->hwbus_priv); + if (ret) + dev_err(wdev->dev, "%s: bus communication error: %d\n", __func__, ret); + return ret; +} + +int wfx_data_write(struct wfx_dev *wdev, const void *buf, size_t len) +{ + int ret; + + WARN((long) buf & 3, "%s: unaligned buffer", __func__); + wdev->hwbus_ops->lock(wdev->hwbus_priv); + ret = wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, WFX_REG_IN_OUT_QUEUE, buf, len); + _trace_io_write(WFX_REG_IN_OUT_QUEUE, buf, len); + wdev->hwbus_ops->unlock(wdev->hwbus_priv); + if (ret) + dev_err(wdev->dev, "%s: bus communication error: %d\n", __func__, ret); + return ret; +} + +int sram_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len) +{ + return indirect_read_locked(wdev, WFX_REG_SRAM_DPORT, addr, buf, len); +} + +int ahb_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len) +{ + return indirect_read_locked(wdev, WFX_REG_AHB_DPORT, addr, buf, len); +} + +int sram_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len) +{ + return indirect_write_locked(wdev, WFX_REG_SRAM_DPORT, addr, buf, len); +} + +int ahb_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len) +{ + return indirect_write_locked(wdev, WFX_REG_AHB_DPORT, addr, buf, len); +} + +int sram_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val) +{ + return indirect_read32_locked(wdev, WFX_REG_SRAM_DPORT, addr, val); +} + +int ahb_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val) +{ + return indirect_read32_locked(wdev, WFX_REG_AHB_DPORT, addr, val); +} + +int sram_reg_write(struct wfx_dev *wdev, u32 addr, u32 val) +{ + return indirect_write32_locked(wdev, WFX_REG_SRAM_DPORT, addr, val); +} + +int ahb_reg_write(struct wfx_dev *wdev, u32 addr, u32 val) +{ + return indirect_write32_locked(wdev, WFX_REG_AHB_DPORT, addr, val); +} + +int config_reg_read(struct wfx_dev *wdev, u32 *val) +{ + return read32_locked(wdev, WFX_REG_CONFIG, val); +} + +int config_reg_write(struct wfx_dev *wdev, u32 val) +{ + return write32_locked(wdev, WFX_REG_CONFIG, val); +} + +int config_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val) +{ + return write32_bits_locked(wdev, WFX_REG_CONFIG, mask, val); +} + +int control_reg_read(struct wfx_dev *wdev, u32 *val) +{ + return read32_locked(wdev, WFX_REG_CONTROL, val); +} + +int control_reg_write(struct wfx_dev *wdev, u32 val) +{ + return write32_locked(wdev, WFX_REG_CONTROL, val); +} + +int control_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val) +{ + return write32_bits_locked(wdev, WFX_REG_CONTROL, mask, val); +} + +int igpr_reg_read(struct wfx_dev *wdev, int index, u32 *val) +{ + int ret; + + *val = ~0; // Never return undefined value + ret = write32_locked(wdev, WFX_REG_SET_GEN_R_W, IGPR_RW | index << 24); + if (ret) + return ret; + ret = read32_locked(wdev, WFX_REG_SET_GEN_R_W, val); + if (ret) + return ret; + *val &= IGPR_VALUE; + return ret; +} + +int igpr_reg_write(struct wfx_dev *wdev, int index, u32 val) +{ + return write32_locked(wdev, WFX_REG_SET_GEN_R_W, index << 24 | val); +} diff --git a/drivers/staging/wfx/hwio.h b/drivers/staging/wfx/hwio.h new file mode 100644 index 000000000000..906524f71fd1 --- /dev/null +++ b/drivers/staging/wfx/hwio.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Low-level API. + * + * Copyright (c) 2017-2018, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#ifndef WFX_HWIO_H +#define WFX_HWIO_H + +#include <linux/types.h> + +struct wfx_dev; + +int wfx_data_read(struct wfx_dev *wdev, void *buf, size_t buf_len); +int wfx_data_write(struct wfx_dev *wdev, const void *buf, size_t buf_len); + +int sram_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len); +int sram_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len); + +int ahb_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len); +int ahb_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len); + +int sram_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val); +int sram_reg_write(struct wfx_dev *wdev, u32 addr, u32 val); + +int ahb_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val); +int ahb_reg_write(struct wfx_dev *wdev, u32 addr, u32 val); + +#define CFG_ERR_SPI_FRAME 0x00000001 // only with SPI +#define CFG_ERR_SDIO_BUF_MISMATCH 0x00000001 // only with SDIO +#define CFG_ERR_BUF_UNDERRUN 0x00000002 +#define CFG_ERR_DATA_IN_TOO_LARGE 0x00000004 +#define CFG_ERR_HOST_NO_OUT_QUEUE 0x00000008 +#define CFG_ERR_BUF_OVERRUN 0x00000010 +#define CFG_ERR_DATA_OUT_TOO_LARGE 0x00000020 +#define CFG_ERR_HOST_NO_IN_QUEUE 0x00000040 +#define CFG_ERR_HOST_CRC_MISS 0x00000080 // only with SDIO +#define CFG_SPI_IGNORE_CS 0x00000080 // only with SPI +#define CFG_WORD_MODE_MASK 0x00000300 // Bytes ordering (only writable in SPI): +#define CFG_WORD_MODE0 0x00000000 // B1,B0,B3,B2 (In SPI, register address and CONFIG data always use this mode) +#define CFG_WORD_MODE1 0x00000100 // B3,B2,B1,B0 +#define CFG_WORD_MODE2 0x00000200 // B0,B1,B2,B3 (SDIO) +#define CFG_DIRECT_ACCESS_MODE 0x00000400 // Direct or queue access mode +#define CFG_PREFETCH_AHB 0x00000800 +#define CFG_DISABLE_CPU_CLK 0x00001000 +#define CFG_PREFETCH_SRAM 0x00002000 +#define CFG_CPU_RESET 0x00004000 +#define CFG_SDIO_DISABLE_IRQ 0x00008000 // only with SDIO +#define CFG_IRQ_ENABLE_DATA 0x00010000 +#define CFG_IRQ_ENABLE_WRDY 0x00020000 +#define CFG_CLK_RISE_EDGE 0x00040000 +#define CFG_SDIO_DISABLE_CRC_CHK 0x00080000 // only with SDIO +#define CFG_RESERVED 0x00F00000 +#define CFG_DEVICE_ID_MAJOR 0x07000000 +#define CFG_DEVICE_ID_RESERVED 0x78000000 +#define CFG_DEVICE_ID_TYPE 0x80000000 +int config_reg_read(struct wfx_dev *wdev, u32 *val); +int config_reg_write(struct wfx_dev *wdev, u32 val); +int config_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val); + +#define CTRL_NEXT_LEN_MASK 0x00000FFF +#define CTRL_WLAN_WAKEUP 0x00001000 +#define CTRL_WLAN_READY 0x00002000 +int control_reg_read(struct wfx_dev *wdev, u32 *val); +int control_reg_write(struct wfx_dev *wdev, u32 val); +int control_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val); + +#define IGPR_RW 0x80000000 +#define IGPR_INDEX 0x7F000000 +#define IGPR_VALUE 0x00FFFFFF +int igpr_reg_read(struct wfx_dev *wdev, int index, u32 *val); +int igpr_reg_write(struct wfx_dev *wdev, int index, u32 val); + +#endif /* WFX_HWIO_H */ diff --git a/drivers/staging/wfx/key.c b/drivers/staging/wfx/key.c new file mode 100644 index 000000000000..6d03abec20e4 --- /dev/null +++ b/drivers/staging/wfx/key.c @@ -0,0 +1,258 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Key management related functions. + * + * Copyright (c) 2017-2019, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include <net/mac80211.h> + +#include "key.h" +#include "wfx.h" +#include "hif_tx_mib.h" + +static int wfx_alloc_key(struct wfx_dev *wdev) +{ + int idx; + + idx = ffs(~wdev->key_map) - 1; + if (idx < 0 || idx >= MAX_KEY_ENTRIES) + return -1; + + wdev->key_map |= BIT(idx); + wdev->keys[idx].entry_index = idx; + return idx; +} + +static void wfx_free_key(struct wfx_dev *wdev, int idx) +{ + WARN(!(wdev->key_map & BIT(idx)), "inconsistent key allocation"); + memset(&wdev->keys[idx], 0, sizeof(wdev->keys[idx])); + wdev->key_map &= ~BIT(idx); +} + +static uint8_t fill_wep_pair(struct hif_wep_pairwise_key *msg, + struct ieee80211_key_conf *key, u8 *peer_addr) +{ + WARN(key->keylen > sizeof(msg->key_data), "inconsistent data"); + msg->key_length = key->keylen; + memcpy(msg->key_data, key->key, key->keylen); + ether_addr_copy(msg->peer_address, peer_addr); + return HIF_KEY_TYPE_WEP_PAIRWISE; +} + +static uint8_t fill_wep_group(struct hif_wep_group_key *msg, + struct ieee80211_key_conf *key) +{ + WARN(key->keylen > sizeof(msg->key_data), "inconsistent data"); + msg->key_id = key->keyidx; + msg->key_length = key->keylen; + memcpy(msg->key_data, key->key, key->keylen); + return HIF_KEY_TYPE_WEP_DEFAULT; +} + +static uint8_t fill_tkip_pair(struct hif_tkip_pairwise_key *msg, + struct ieee80211_key_conf *key, u8 *peer_addr) +{ + uint8_t *keybuf = key->key; + + WARN(key->keylen != sizeof(msg->tkip_key_data) + + sizeof(msg->tx_mic_key) + + sizeof(msg->rx_mic_key), "inconsistent data"); + memcpy(msg->tkip_key_data, keybuf, sizeof(msg->tkip_key_data)); + keybuf += sizeof(msg->tkip_key_data); + memcpy(msg->tx_mic_key, keybuf, sizeof(msg->tx_mic_key)); + keybuf += sizeof(msg->tx_mic_key); + memcpy(msg->rx_mic_key, keybuf, sizeof(msg->rx_mic_key)); + ether_addr_copy(msg->peer_address, peer_addr); + return HIF_KEY_TYPE_TKIP_PAIRWISE; +} + +static uint8_t fill_tkip_group(struct hif_tkip_group_key *msg, + struct ieee80211_key_conf *key, + struct ieee80211_key_seq *seq, + enum nl80211_iftype iftype) +{ + uint8_t *keybuf = key->key; + + WARN(key->keylen != sizeof(msg->tkip_key_data) + + 2 * sizeof(msg->rx_mic_key), "inconsistent data"); + msg->key_id = key->keyidx; + memcpy(msg->rx_sequence_counter, &seq->tkip.iv16, sizeof(seq->tkip.iv16)); + memcpy(msg->rx_sequence_counter + sizeof(uint16_t), &seq->tkip.iv32, sizeof(seq->tkip.iv32)); + memcpy(msg->tkip_key_data, keybuf, sizeof(msg->tkip_key_data)); + keybuf += sizeof(msg->tkip_key_data); + if (iftype == NL80211_IFTYPE_AP) + // Use Tx MIC Key + memcpy(msg->rx_mic_key, keybuf + 0, sizeof(msg->rx_mic_key)); + else + // Use Rx MIC Key + memcpy(msg->rx_mic_key, keybuf + 8, sizeof(msg->rx_mic_key)); + return HIF_KEY_TYPE_TKIP_GROUP; +} + +static uint8_t fill_ccmp_pair(struct hif_aes_pairwise_key *msg, + struct ieee80211_key_conf *key, u8 *peer_addr) +{ + WARN(key->keylen != sizeof(msg->aes_key_data), "inconsistent data"); + ether_addr_copy(msg->peer_address, peer_addr); + memcpy(msg->aes_key_data, key->key, key->keylen); + return HIF_KEY_TYPE_AES_PAIRWISE; +} + +static uint8_t fill_ccmp_group(struct hif_aes_group_key *msg, + struct ieee80211_key_conf *key, + struct ieee80211_key_seq *seq) +{ + WARN(key->keylen != sizeof(msg->aes_key_data), "inconsistent data"); + memcpy(msg->aes_key_data, key->key, key->keylen); + memcpy(msg->rx_sequence_counter, seq->ccmp.pn, sizeof(seq->ccmp.pn)); + memreverse(msg->rx_sequence_counter, sizeof(seq->ccmp.pn)); + msg->key_id = key->keyidx; + return HIF_KEY_TYPE_AES_GROUP; +} + +static uint8_t fill_sms4_pair(struct hif_wapi_pairwise_key *msg, + struct ieee80211_key_conf *key, u8 *peer_addr) +{ + uint8_t *keybuf = key->key; + + WARN(key->keylen != sizeof(msg->wapi_key_data) + + sizeof(msg->mic_key_data), "inconsistent data"); + ether_addr_copy(msg->peer_address, peer_addr); + memcpy(msg->wapi_key_data, keybuf, sizeof(msg->wapi_key_data)); + keybuf += sizeof(msg->wapi_key_data); + memcpy(msg->mic_key_data, keybuf, sizeof(msg->mic_key_data)); + msg->key_id = key->keyidx; + return HIF_KEY_TYPE_WAPI_PAIRWISE; +} + +static uint8_t fill_sms4_group(struct hif_wapi_group_key *msg, + struct ieee80211_key_conf *key) +{ + uint8_t *keybuf = key->key; + + WARN(key->keylen != sizeof(msg->wapi_key_data) + + sizeof(msg->mic_key_data), "inconsistent data"); + memcpy(msg->wapi_key_data, keybuf, sizeof(msg->wapi_key_data)); + keybuf += sizeof(msg->wapi_key_data); + memcpy(msg->mic_key_data, keybuf, sizeof(msg->mic_key_data)); + msg->key_id = key->keyidx; + return HIF_KEY_TYPE_WAPI_GROUP; +} + +static uint8_t fill_aes_cmac_group(struct hif_igtk_group_key *msg, + struct ieee80211_key_conf *key, + struct ieee80211_key_seq *seq) +{ + WARN(key->keylen != sizeof(msg->igtk_key_data), "inconsistent data"); + memcpy(msg->igtk_key_data, key->key, key->keylen); + memcpy(msg->ipn, seq->aes_cmac.pn, sizeof(seq->aes_cmac.pn)); + memreverse(msg->ipn, sizeof(seq->aes_cmac.pn)); + msg->key_id = key->keyidx; + return HIF_KEY_TYPE_IGTK_GROUP; +} + +static int wfx_add_key(struct wfx_vif *wvif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + int ret; + struct hif_req_add_key *k; + struct ieee80211_key_seq seq; + struct wfx_dev *wdev = wvif->wdev; + int idx = wfx_alloc_key(wvif->wdev); + bool pairwise = key->flags & IEEE80211_KEY_FLAG_PAIRWISE; + + WARN(key->flags & IEEE80211_KEY_FLAG_PAIRWISE && !sta, "inconsistent data"); + ieee80211_get_key_rx_seq(key, 0, &seq); + if (idx < 0) + return -EINVAL; + k = &wdev->keys[idx]; + k->int_id = wvif->id; + if (key->cipher == WLAN_CIPHER_SUITE_WEP40 || key->cipher == WLAN_CIPHER_SUITE_WEP104) { + if (pairwise) + k->type = fill_wep_pair(&k->key.wep_pairwise_key, key, sta->addr); + else + k->type = fill_wep_group(&k->key.wep_group_key, key); + } else if (key->cipher == WLAN_CIPHER_SUITE_TKIP) { + if (pairwise) + k->type = fill_tkip_pair(&k->key.tkip_pairwise_key, key, sta->addr); + else + k->type = fill_tkip_group(&k->key.tkip_group_key, key, &seq, wvif->vif->type); + } else if (key->cipher == WLAN_CIPHER_SUITE_CCMP) { + if (pairwise) + k->type = fill_ccmp_pair(&k->key.aes_pairwise_key, key, sta->addr); + else + k->type = fill_ccmp_group(&k->key.aes_group_key, key, &seq); + } else if (key->cipher == WLAN_CIPHER_SUITE_SMS4) { + if (pairwise) + k->type = fill_sms4_pair(&k->key.wapi_pairwise_key, key, sta->addr); + else + k->type = fill_sms4_group(&k->key.wapi_group_key, key); + } else if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { + k->type = fill_aes_cmac_group(&k->key.igtk_group_key, key, &seq); + } else { + dev_warn(wdev->dev, "unsupported key type %d\n", key->cipher); + wfx_free_key(wdev, idx); + return -EOPNOTSUPP; + } + ret = hif_add_key(wdev, k); + if (ret) { + wfx_free_key(wdev, idx); + return -EOPNOTSUPP; + } + key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE | + IEEE80211_KEY_FLAG_RESERVE_TAILROOM; + key->hw_key_idx = idx; + return 0; +} + +static int wfx_remove_key(struct wfx_vif *wvif, struct ieee80211_key_conf *key) +{ + WARN(key->hw_key_idx >= MAX_KEY_ENTRIES, "corrupted hw_key_idx"); + wfx_free_key(wvif->wdev, key->hw_key_idx); + return hif_remove_key(wvif->wdev, key->hw_key_idx); +} + +int wfx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + int ret = -EOPNOTSUPP; + struct wfx_vif *wvif = (struct wfx_vif *) vif->drv_priv; + + mutex_lock(&wvif->wdev->conf_mutex); + if (cmd == SET_KEY) + ret = wfx_add_key(wvif, sta, key); + if (cmd == DISABLE_KEY) + ret = wfx_remove_key(wvif, key); + mutex_unlock(&wvif->wdev->conf_mutex); + return ret; +} + +int wfx_upload_keys(struct wfx_vif *wvif) +{ + int i; + struct hif_req_add_key *key; + struct wfx_dev *wdev = wvif->wdev; + + for (i = 0; i < ARRAY_SIZE(wdev->keys); i++) { + if (wdev->key_map & BIT(i)) { + key = &wdev->keys[i]; + if (key->int_id == wvif->id) + hif_add_key(wdev, key); + } + } + return 0; +} + +void wfx_wep_key_work(struct work_struct *work) +{ + struct wfx_vif *wvif = container_of(work, struct wfx_vif, wep_key_work); + + wfx_tx_flush(wvif->wdev); + hif_wep_default_key_id(wvif, wvif->wep_default_key_id); + wfx_pending_requeue(wvif->wdev, wvif->wep_pending_skb); + wvif->wep_pending_skb = NULL; + wfx_tx_unlock(wvif->wdev); +} diff --git a/drivers/staging/wfx/key.h b/drivers/staging/wfx/key.h new file mode 100644 index 000000000000..9436ccdf4d3b --- /dev/null +++ b/drivers/staging/wfx/key.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Implementation of mac80211 API. + * + * Copyright (c) 2017-2019, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#ifndef WFX_KEY_H +#define WFX_KEY_H + +#include <net/mac80211.h> + +struct wfx_dev; +struct wfx_vif; + +int wfx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key); +int wfx_upload_keys(struct wfx_vif *wvif); +void wfx_wep_key_work(struct work_struct *work); + +#endif /* WFX_STA_H */ diff --git a/drivers/staging/wfx/main.c b/drivers/staging/wfx/main.c new file mode 100644 index 000000000000..18f07f7ad347 --- /dev/null +++ b/drivers/staging/wfx/main.c @@ -0,0 +1,470 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Device probe and register. + * + * Copyright (c) 2017-2019, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + * Copyright (c) 2008, Johannes Berg <johannes@sipsolutions.net> + * Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de> + * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net> + * Copyright (c) 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al. + */ +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_net.h> +#include <linux/gpio.h> +#include <linux/gpio/consumer.h> +#include <linux/mmc/sdio_func.h> +#include <linux/spi/spi.h> +#include <linux/etherdevice.h> +#include <linux/firmware.h> + +#include "main.h" +#include "wfx.h" +#include "fwio.h" +#include "hwio.h" +#include "bus.h" +#include "bh.h" +#include "sta.h" +#include "key.h" +#include "debug.h" +#include "data_tx.h" +#include "secure_link.h" +#include "hif_tx_mib.h" +#include "hif_api_cmd.h" + +#define WFX_PDS_MAX_SIZE 1500 + +MODULE_DESCRIPTION("Silicon Labs 802.11 Wireless LAN driver for WFx"); +MODULE_AUTHOR("Jérôme Pouiller <jerome.pouiller@silabs.com>"); +MODULE_LICENSE("GPL"); + +static int gpio_wakeup = -2; +module_param(gpio_wakeup, int, 0644); +MODULE_PARM_DESC(gpio_wakeup, "gpio number for wakeup. -1 for none."); + +#define RATETAB_ENT(_rate, _rateid, _flags) { \ + .bitrate = (_rate), \ + .hw_value = (_rateid), \ + .flags = (_flags), \ +} + +static struct ieee80211_rate wfx_rates[] = { + RATETAB_ENT(10, 0, 0), + RATETAB_ENT(20, 1, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(55, 2, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(110, 3, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(60, 6, 0), + RATETAB_ENT(90, 7, 0), + RATETAB_ENT(120, 8, 0), + RATETAB_ENT(180, 9, 0), + RATETAB_ENT(240, 10, 0), + RATETAB_ENT(360, 11, 0), + RATETAB_ENT(480, 12, 0), + RATETAB_ENT(540, 13, 0), +}; + +#define CHAN2G(_channel, _freq, _flags) { \ + .band = NL80211_BAND_2GHZ, \ + .center_freq = (_freq), \ + .hw_value = (_channel), \ + .flags = (_flags), \ + .max_antenna_gain = 0, \ + .max_power = 30, \ +} + +static struct ieee80211_channel wfx_2ghz_chantable[] = { + CHAN2G(1, 2412, 0), + CHAN2G(2, 2417, 0), + CHAN2G(3, 2422, 0), + CHAN2G(4, 2427, 0), + CHAN2G(5, 2432, 0), + CHAN2G(6, 2437, 0), + CHAN2G(7, 2442, 0), + CHAN2G(8, 2447, 0), + CHAN2G(9, 2452, 0), + CHAN2G(10, 2457, 0), + CHAN2G(11, 2462, 0), + CHAN2G(12, 2467, 0), + CHAN2G(13, 2472, 0), + CHAN2G(14, 2484, 0), +}; + +static const struct ieee80211_supported_band wfx_band_2ghz = { + .channels = wfx_2ghz_chantable, + .n_channels = ARRAY_SIZE(wfx_2ghz_chantable), + .bitrates = wfx_rates, + .n_bitrates = ARRAY_SIZE(wfx_rates), + .ht_cap = { + // Receive caps + .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | + IEEE80211_HT_CAP_MAX_AMSDU | (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), + .ht_supported = 1, + .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K, + .ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE, + .mcs = { + .rx_mask = { 0xFF }, // MCS0 to MCS7 + .rx_highest = 65, + .tx_params = IEEE80211_HT_MCS_TX_DEFINED, + }, + }, +}; + +static const struct ieee80211_iface_limit wdev_iface_limits[] = { + { .max = 1, .types = BIT(NL80211_IFTYPE_STATION) }, + { .max = 1, .types = BIT(NL80211_IFTYPE_AP) }, +}; + +static const struct ieee80211_iface_combination wfx_iface_combinations[] = { + { + .num_different_channels = 2, + .max_interfaces = 2, + .limits = wdev_iface_limits, + .n_limits = ARRAY_SIZE(wdev_iface_limits), + } +}; + +static const struct ieee80211_ops wfx_ops = { + .start = wfx_start, + .stop = wfx_stop, + .add_interface = wfx_add_interface, + .remove_interface = wfx_remove_interface, + .config = wfx_config, + .tx = wfx_tx, + .conf_tx = wfx_conf_tx, + .hw_scan = wfx_hw_scan, + .sta_add = wfx_sta_add, + .sta_remove = wfx_sta_remove, + .sta_notify = wfx_sta_notify, + .set_tim = wfx_set_tim, + .set_key = wfx_set_key, + .set_rts_threshold = wfx_set_rts_threshold, + .bss_info_changed = wfx_bss_info_changed, + .prepare_multicast = wfx_prepare_multicast, + .configure_filter = wfx_configure_filter, + .ampdu_action = wfx_ampdu_action, + .flush = wfx_flush, + .add_chanctx = wfx_add_chanctx, + .remove_chanctx = wfx_remove_chanctx, + .change_chanctx = wfx_change_chanctx, + .assign_vif_chanctx = wfx_assign_vif_chanctx, + .unassign_vif_chanctx = wfx_unassign_vif_chanctx, +}; + +bool wfx_api_older_than(struct wfx_dev *wdev, int major, int minor) +{ + if (wdev->hw_caps.api_version_major < major) + return true; + if (wdev->hw_caps.api_version_major > major) + return false; + if (wdev->hw_caps.api_version_minor < minor) + return true; + return false; +} + +struct gpio_desc *wfx_get_gpio(struct device *dev, int override, const char *label) +{ + struct gpio_desc *ret; + char label_buf[256]; + + if (override >= 0) { + snprintf(label_buf, sizeof(label_buf), "wfx_%s", label); + ret = ERR_PTR(devm_gpio_request_one(dev, override, GPIOF_OUT_INIT_LOW, label_buf)); + if (!ret) + ret = gpio_to_desc(override); + } else if (override == -1) { + ret = NULL; + } else { + ret = devm_gpiod_get(dev, label, GPIOD_OUT_LOW); + } + if (IS_ERR(ret) || !ret) { + if (!ret || PTR_ERR(ret) == -ENOENT) + dev_warn(dev, "gpio %s is not defined\n", label); + else + dev_warn(dev, "error while requesting gpio %s\n", label); + ret = NULL; + } else { + dev_dbg(dev, "using gpio %d for %s\n", desc_to_gpio(ret), label); + } + return ret; +} + +/* NOTE: wfx_send_pds() destroy buf */ +int wfx_send_pds(struct wfx_dev *wdev, unsigned char *buf, size_t len) +{ + int ret; + int start, brace_level, i; + + start = 0; + brace_level = 0; + if (buf[0] != '{') { + dev_err(wdev->dev, "valid PDS start with '{'. Did you forget to compress it?\n"); + return -EINVAL; + } + for (i = 1; i < len - 1; i++) { + if (buf[i] == '{') + brace_level++; + if (buf[i] == '}') + brace_level--; + if (buf[i] == '}' && !brace_level) { + i++; + if (i - start + 1 > WFX_PDS_MAX_SIZE) + return -EFBIG; + buf[start] = '{'; + buf[i] = 0; + dev_dbg(wdev->dev, "send PDS '%s}'\n", buf + start); + buf[i] = '}'; + ret = hif_configuration(wdev, buf + start, i - start + 1); + if (ret == HIF_STATUS_FAILURE) { + dev_err(wdev->dev, "PDS bytes %d to %d: invalid data (unsupported options?)\n", start, i); + return -EINVAL; + } + if (ret == -ETIMEDOUT) { + dev_err(wdev->dev, "PDS bytes %d to %d: chip didn't reply (corrupted file?)\n", start, i); + return ret; + } + if (ret) { + dev_err(wdev->dev, "PDS bytes %d to %d: chip returned an unknown error\n", start, i); + return -EIO; + } + buf[i] = ','; + start = i; + } + } + return 0; +} + +static int wfx_send_pdata_pds(struct wfx_dev *wdev) +{ + int ret = 0; + const struct firmware *pds; + unsigned char *tmp_buf; + + ret = request_firmware(&pds, wdev->pdata.file_pds, wdev->dev); + if (ret) { + dev_err(wdev->dev, "can't load PDS file %s\n", wdev->pdata.file_pds); + return ret; + } + tmp_buf = kmemdup(pds->data, pds->size, GFP_KERNEL); + ret = wfx_send_pds(wdev, tmp_buf, pds->size); + kfree(tmp_buf); + release_firmware(pds); + return ret; +} + +struct wfx_dev *wfx_init_common(struct device *dev, + const struct wfx_platform_data *pdata, + const struct hwbus_ops *hwbus_ops, + void *hwbus_priv) +{ + struct ieee80211_hw *hw; + struct wfx_dev *wdev; + + hw = ieee80211_alloc_hw(sizeof(struct wfx_dev), &wfx_ops); + if (!hw) + return NULL; + + SET_IEEE80211_DEV(hw, dev); + + ieee80211_hw_set(hw, NEED_DTIM_BEFORE_ASSOC); + ieee80211_hw_set(hw, TX_AMPDU_SETUP_IN_HW); + ieee80211_hw_set(hw, AMPDU_AGGREGATION); + ieee80211_hw_set(hw, CONNECTION_MONITOR); + ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); + ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); + ieee80211_hw_set(hw, SIGNAL_DBM); + ieee80211_hw_set(hw, SUPPORTS_PS); + ieee80211_hw_set(hw, MFP_CAPABLE); + + hw->vif_data_size = sizeof(struct wfx_vif); + hw->sta_data_size = sizeof(struct wfx_sta_priv); + hw->queues = 4; + hw->max_rates = 8; + hw->max_rate_tries = 15; + hw->extra_tx_headroom = sizeof(struct hif_sl_msg_hdr) + sizeof(struct hif_msg) + + sizeof(struct hif_req_tx) + + 4 /* alignment */ + 8 /* TKIP IV */; + hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_AP); + hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; + hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; + hw->wiphy->max_ap_assoc_sta = WFX_MAX_STA_IN_AP_MODE; + hw->wiphy->max_scan_ssids = 2; + hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; + hw->wiphy->n_iface_combinations = ARRAY_SIZE(wfx_iface_combinations); + hw->wiphy->iface_combinations = wfx_iface_combinations; + hw->wiphy->bands[NL80211_BAND_2GHZ] = devm_kmalloc(dev, sizeof(wfx_band_2ghz), GFP_KERNEL); + // FIXME: also copy wfx_rates and wfx_2ghz_chantable + memcpy(hw->wiphy->bands[NL80211_BAND_2GHZ], &wfx_band_2ghz, sizeof(wfx_band_2ghz)); + + wdev = hw->priv; + wdev->hw = hw; + wdev->dev = dev; + wdev->hwbus_ops = hwbus_ops; + wdev->hwbus_priv = hwbus_priv; + memcpy(&wdev->pdata, pdata, sizeof(*pdata)); + of_property_read_string(dev->of_node, "config-file", &wdev->pdata.file_pds); + wdev->pdata.gpio_wakeup = wfx_get_gpio(dev, gpio_wakeup, "wakeup"); + wfx_sl_fill_pdata(dev, &wdev->pdata); + + mutex_init(&wdev->conf_mutex); + mutex_init(&wdev->rx_stats_lock); + init_completion(&wdev->firmware_ready); + wfx_init_hif_cmd(&wdev->hif_cmd); + wfx_tx_queues_init(wdev); + + return wdev; +} + +void wfx_free_common(struct wfx_dev *wdev) +{ + mutex_destroy(&wdev->rx_stats_lock); + mutex_destroy(&wdev->conf_mutex); + wfx_tx_queues_deinit(wdev); + ieee80211_free_hw(wdev->hw); +} + +int wfx_probe(struct wfx_dev *wdev) +{ + int i; + int err; + const void *macaddr; + struct gpio_desc *gpio_saved; + + // During first part of boot, gpio_wakeup cannot yet been used. So + // prevent bh() to touch it. + gpio_saved = wdev->pdata.gpio_wakeup; + wdev->pdata.gpio_wakeup = NULL; + + wfx_bh_register(wdev); + + err = wfx_init_device(wdev); + if (err) + goto err1; + + err = wait_for_completion_interruptible_timeout(&wdev->firmware_ready, 10 * HZ); + if (err <= 0) { + if (err == 0) { + dev_err(wdev->dev, "timeout while waiting for startup indication. IRQ configuration error?\n"); + err = -ETIMEDOUT; + } else if (err == -ERESTARTSYS) { + dev_info(wdev->dev, "probe interrupted by user\n"); + } + goto err1; + } + + // FIXME: fill wiphy::hw_version + dev_info(wdev->dev, "started firmware %d.%d.%d \"%s\" (API: %d.%d, keyset: %02X, caps: 0x%.8X)\n", + wdev->hw_caps.firmware_major, wdev->hw_caps.firmware_minor, + wdev->hw_caps.firmware_build, wdev->hw_caps.firmware_label, + wdev->hw_caps.api_version_major, wdev->hw_caps.api_version_minor, + wdev->keyset, *((u32 *) &wdev->hw_caps.capabilities)); + snprintf(wdev->hw->wiphy->fw_version, sizeof(wdev->hw->wiphy->fw_version), + "%d.%d.%d", + wdev->hw_caps.firmware_major, + wdev->hw_caps.firmware_minor, + wdev->hw_caps.firmware_build); + + if (wfx_api_older_than(wdev, 1, 0)) { + dev_err(wdev->dev, "unsupported firmware API version (expect 1 while firmware returns %d)\n", + wdev->hw_caps.api_version_major); + err = -ENOTSUPP; + goto err1; + } + + err = wfx_sl_init(wdev); + if (err && wdev->hw_caps.capabilities.link_mode == SEC_LINK_ENFORCED) { + dev_err(wdev->dev, "chip require secure_link, but can't negociate it\n"); + goto err1; + } + + if (wdev->hw_caps.regul_sel_mode_info.region_sel_mode) { + wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]->channels[11].flags |= IEEE80211_CHAN_NO_IR; + wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]->channels[12].flags |= IEEE80211_CHAN_NO_IR; + wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]->channels[13].flags |= IEEE80211_CHAN_DISABLED; + } + + dev_dbg(wdev->dev, "sending configuration file %s\n", wdev->pdata.file_pds); + err = wfx_send_pdata_pds(wdev); + if (err < 0) + goto err1; + + wdev->pdata.gpio_wakeup = gpio_saved; + if (wdev->pdata.gpio_wakeup) { + dev_dbg(wdev->dev, "enable 'quiescent' power mode with gpio %d and PDS file %s\n", + desc_to_gpio(wdev->pdata.gpio_wakeup), wdev->pdata.file_pds); + gpiod_set_value(wdev->pdata.gpio_wakeup, 1); + control_reg_write(wdev, 0); + hif_set_operational_mode(wdev, HIF_OP_POWER_MODE_QUIESCENT); + } else { + hif_set_operational_mode(wdev, HIF_OP_POWER_MODE_DOZE); + } + + hif_use_multi_tx_conf(wdev, true); + + for (i = 0; i < ARRAY_SIZE(wdev->addresses); i++) { + eth_zero_addr(wdev->addresses[i].addr); + macaddr = of_get_mac_address(wdev->dev->of_node); + if (!IS_ERR_OR_NULL(macaddr)) { + ether_addr_copy(wdev->addresses[i].addr, macaddr); + wdev->addresses[i].addr[ETH_ALEN - 1] += i; + } else { + ether_addr_copy(wdev->addresses[i].addr, wdev->hw_caps.mac_addr[i]); + } + if (!is_valid_ether_addr(wdev->addresses[i].addr)) { + dev_warn(wdev->dev, "using random MAC address\n"); + eth_random_addr(wdev->addresses[i].addr); + } + dev_info(wdev->dev, "MAC address %d: %pM\n", i, wdev->addresses[i].addr); + } + wdev->hw->wiphy->n_addresses = ARRAY_SIZE(wdev->addresses); + wdev->hw->wiphy->addresses = wdev->addresses; + + err = ieee80211_register_hw(wdev->hw); + if (err) + goto err1; + + err = wfx_debug_init(wdev); + if (err) + goto err2; + + return 0; + +err2: + ieee80211_unregister_hw(wdev->hw); + ieee80211_free_hw(wdev->hw); +err1: + wfx_bh_unregister(wdev); + return err; +} + +void wfx_release(struct wfx_dev *wdev) +{ + ieee80211_unregister_hw(wdev->hw); + hif_shutdown(wdev); + wfx_bh_unregister(wdev); + wfx_sl_deinit(wdev); +} + +static int __init wfx_core_init(void) +{ + int ret = 0; + + if (IS_ENABLED(CONFIG_SPI)) + ret = spi_register_driver(&wfx_spi_driver); + if (IS_ENABLED(CONFIG_MMC) && !ret) + ret = sdio_register_driver(&wfx_sdio_driver); + return ret; +} +module_init(wfx_core_init); + +static void __exit wfx_core_exit(void) +{ + if (IS_ENABLED(CONFIG_MMC)) + sdio_unregister_driver(&wfx_sdio_driver); + if (IS_ENABLED(CONFIG_SPI)) + spi_unregister_driver(&wfx_spi_driver); +} +module_exit(wfx_core_exit); diff --git a/drivers/staging/wfx/main.h b/drivers/staging/wfx/main.h new file mode 100644 index 000000000000..875f8c227803 --- /dev/null +++ b/drivers/staging/wfx/main.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Device probe and register. + * + * Copyright (c) 2017-2019, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net> + * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al. + */ +#ifndef WFX_MAIN_H +#define WFX_MAIN_H + +#include <linux/device.h> +#include <linux/gpio/consumer.h> + +#include "bus.h" +#include "hif_api_general.h" + +struct wfx_dev; + +struct wfx_platform_data { + /* Keyset and ".sec" extention will appended to this string */ + const char *file_fw; + const char *file_pds; + struct gpio_desc *gpio_wakeup; + /* + * if true HIF D_out is sampled on the rising edge of the clock + * (intended to be used in 50Mhz SDIO) + */ + bool use_rising_clk; +}; + +struct wfx_dev *wfx_init_common(struct device *dev, + const struct wfx_platform_data *pdata, + const struct hwbus_ops *hwbus_ops, + void *hwbus_priv); +void wfx_free_common(struct wfx_dev *wdev); + +int wfx_probe(struct wfx_dev *wdev); +void wfx_release(struct wfx_dev *wdev); + +struct gpio_desc *wfx_get_gpio(struct device *dev, int override, + const char *label); +bool wfx_api_older_than(struct wfx_dev *wdev, int major, int minor); +int wfx_send_pds(struct wfx_dev *wdev, unsigned char *buf, size_t len); + +#endif diff --git a/drivers/staging/wfx/queue.c b/drivers/staging/wfx/queue.c new file mode 100644 index 000000000000..71e92744fed0 --- /dev/null +++ b/drivers/staging/wfx/queue.c @@ -0,0 +1,608 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * O(1) TX queue with built-in allocator. + * + * Copyright (c) 2017-2019, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include <linux/sched.h> +#include <net/mac80211.h> + +#include "queue.h" +#include "wfx.h" +#include "sta.h" +#include "data_tx.h" + +void wfx_tx_lock(struct wfx_dev *wdev) +{ + atomic_inc(&wdev->tx_lock); +} + +void wfx_tx_unlock(struct wfx_dev *wdev) +{ + int tx_lock = atomic_dec_return(&wdev->tx_lock); + + WARN(tx_lock < 0, "inconsistent tx_lock value"); + if (!tx_lock) + wfx_bh_request_tx(wdev); +} + +void wfx_tx_flush(struct wfx_dev *wdev) +{ + int ret; + + WARN(!atomic_read(&wdev->tx_lock), "tx_lock is not locked"); + + // Do not wait for any reply if chip is frozen + if (wdev->chip_frozen) + return; + + mutex_lock(&wdev->hif_cmd.lock); + ret = wait_event_timeout(wdev->hif.tx_buffers_empty, + !wdev->hif.tx_buffers_used, + msecs_to_jiffies(3000)); + if (!ret) { + dev_warn(wdev->dev, "cannot flush tx buffers (%d still busy)\n", wdev->hif.tx_buffers_used); + wfx_pending_dump_old_frames(wdev, 3000); + // FIXME: drop pending frames here + wdev->chip_frozen = 1; + } + mutex_unlock(&wdev->hif_cmd.lock); +} + +void wfx_tx_lock_flush(struct wfx_dev *wdev) +{ + wfx_tx_lock(wdev); + wfx_tx_flush(wdev); +} + +void wfx_tx_queues_lock(struct wfx_dev *wdev) +{ + int i; + struct wfx_queue *queue; + + for (i = 0; i < IEEE80211_NUM_ACS; ++i) { + queue = &wdev->tx_queue[i]; + spin_lock_bh(&queue->queue.lock); + if (queue->tx_locked_cnt++ == 0) + ieee80211_stop_queue(wdev->hw, queue->queue_id); + spin_unlock_bh(&queue->queue.lock); + } +} + +void wfx_tx_queues_unlock(struct wfx_dev *wdev) +{ + int i; + struct wfx_queue *queue; + + for (i = 0; i < IEEE80211_NUM_ACS; ++i) { + queue = &wdev->tx_queue[i]; + spin_lock_bh(&queue->queue.lock); + WARN(!queue->tx_locked_cnt, "queue already unlocked"); + if (--queue->tx_locked_cnt == 0) + ieee80211_wake_queue(wdev->hw, queue->queue_id); + spin_unlock_bh(&queue->queue.lock); + } +} + +/* If successful, LOCKS the TX queue! */ +void wfx_tx_queues_wait_empty_vif(struct wfx_vif *wvif) +{ + int i; + bool done; + struct wfx_queue *queue; + struct sk_buff *item; + struct wfx_dev *wdev = wvif->wdev; + struct hif_msg *hif; + + if (wvif->wdev->chip_frozen) { + wfx_tx_lock_flush(wdev); + wfx_tx_queues_clear(wdev); + return; + } + + do { + done = true; + wfx_tx_lock_flush(wdev); + for (i = 0; i < IEEE80211_NUM_ACS && done; ++i) { + queue = &wdev->tx_queue[i]; + spin_lock_bh(&queue->queue.lock); + skb_queue_walk(&queue->queue, item) { + hif = (struct hif_msg *) item->data; + if (hif->interface == wvif->id) + done = false; + } + spin_unlock_bh(&queue->queue.lock); + } + if (!done) { + wfx_tx_unlock(wdev); + msleep(20); + } + } while (!done); +} + +static void wfx_tx_queue_clear(struct wfx_dev *wdev, struct wfx_queue *queue, struct sk_buff_head *gc_list) +{ + int i; + struct sk_buff *item; + struct wfx_queue_stats *stats = &wdev->tx_queue_stats; + + spin_lock_bh(&queue->queue.lock); + while ((item = __skb_dequeue(&queue->queue)) != NULL) + skb_queue_head(gc_list, item); + spin_lock_bh(&stats->pending.lock); + for (i = 0; i < ARRAY_SIZE(stats->link_map_cache); ++i) { + stats->link_map_cache[i] -= queue->link_map_cache[i]; + queue->link_map_cache[i] = 0; + } + spin_unlock_bh(&stats->pending.lock); + spin_unlock_bh(&queue->queue.lock); +} + +void wfx_tx_queues_clear(struct wfx_dev *wdev) +{ + int i; + struct sk_buff *item; + struct sk_buff_head gc_list; + struct wfx_queue_stats *stats = &wdev->tx_queue_stats; + + skb_queue_head_init(&gc_list); + for (i = 0; i < IEEE80211_NUM_ACS; ++i) + wfx_tx_queue_clear(wdev, &wdev->tx_queue[i], &gc_list); + wake_up(&stats->wait_link_id_empty); + while ((item = skb_dequeue(&gc_list)) != NULL) + wfx_skb_dtor(wdev, item); +} + +void wfx_tx_queues_init(struct wfx_dev *wdev) +{ + int i; + + memset(&wdev->tx_queue_stats, 0, sizeof(wdev->tx_queue_stats)); + memset(wdev->tx_queue, 0, sizeof(wdev->tx_queue)); + skb_queue_head_init(&wdev->tx_queue_stats.pending); + init_waitqueue_head(&wdev->tx_queue_stats.wait_link_id_empty); + + for (i = 0; i < IEEE80211_NUM_ACS; ++i) { + wdev->tx_queue[i].queue_id = i; + skb_queue_head_init(&wdev->tx_queue[i].queue); + } +} + +void wfx_tx_queues_deinit(struct wfx_dev *wdev) +{ + WARN_ON(!skb_queue_empty(&wdev->tx_queue_stats.pending)); + wfx_tx_queues_clear(wdev); +} + +size_t wfx_tx_queue_get_num_queued(struct wfx_queue *queue, + u32 link_id_map) +{ + size_t ret; + int i, bit; + + if (!link_id_map) + return 0; + + spin_lock_bh(&queue->queue.lock); + if (link_id_map == (u32)-1) { + ret = skb_queue_len(&queue->queue); + } else { + ret = 0; + for (i = 0, bit = 1; i < ARRAY_SIZE(queue->link_map_cache); ++i, bit <<= 1) { + if (link_id_map & bit) + ret += queue->link_map_cache[i]; + } + } + spin_unlock_bh(&queue->queue.lock); + return ret; +} + +void wfx_tx_queue_put(struct wfx_dev *wdev, struct wfx_queue *queue, struct sk_buff *skb) +{ + struct wfx_queue_stats *stats = &wdev->tx_queue_stats; + struct wfx_tx_priv *tx_priv = wfx_skb_tx_priv(skb); + + WARN(tx_priv->link_id >= ARRAY_SIZE(stats->link_map_cache), "invalid link-id value"); + spin_lock_bh(&queue->queue.lock); + __skb_queue_tail(&queue->queue, skb); + + ++queue->link_map_cache[tx_priv->link_id]; + + spin_lock_bh(&stats->pending.lock); + ++stats->link_map_cache[tx_priv->link_id]; + spin_unlock_bh(&stats->pending.lock); + spin_unlock_bh(&queue->queue.lock); +} + +static struct sk_buff *wfx_tx_queue_get(struct wfx_dev *wdev, + struct wfx_queue *queue, + u32 link_id_map) +{ + struct sk_buff *skb = NULL; + struct sk_buff *item; + struct wfx_queue_stats *stats = &wdev->tx_queue_stats; + struct wfx_tx_priv *tx_priv; + bool wakeup_stats = false; + + spin_lock_bh(&queue->queue.lock); + skb_queue_walk(&queue->queue, item) { + tx_priv = wfx_skb_tx_priv(item); + if (link_id_map & BIT(tx_priv->link_id)) { + skb = item; + break; + } + } + WARN_ON(!skb); + if (skb) { + tx_priv = wfx_skb_tx_priv(skb); + tx_priv->xmit_timestamp = ktime_get(); + __skb_unlink(skb, &queue->queue); + --queue->link_map_cache[tx_priv->link_id]; + + spin_lock_bh(&stats->pending.lock); + __skb_queue_tail(&stats->pending, skb); + if (!--stats->link_map_cache[tx_priv->link_id]) + wakeup_stats = true; + spin_unlock_bh(&stats->pending.lock); + } + spin_unlock_bh(&queue->queue.lock); + if (wakeup_stats) + wake_up(&stats->wait_link_id_empty); + return skb; +} + +int wfx_pending_requeue(struct wfx_dev *wdev, struct sk_buff *skb) +{ + struct wfx_queue_stats *stats = &wdev->tx_queue_stats; + struct wfx_tx_priv *tx_priv = wfx_skb_tx_priv(skb); + struct wfx_queue *queue = &wdev->tx_queue[skb_get_queue_mapping(skb)]; + + WARN_ON(skb_get_queue_mapping(skb) > 3); + spin_lock_bh(&queue->queue.lock); + ++queue->link_map_cache[tx_priv->link_id]; + + spin_lock_bh(&stats->pending.lock); + ++stats->link_map_cache[tx_priv->link_id]; + __skb_unlink(skb, &stats->pending); + spin_unlock_bh(&stats->pending.lock); + __skb_queue_tail(&queue->queue, skb); + spin_unlock_bh(&queue->queue.lock); + return 0; +} + +int wfx_pending_remove(struct wfx_dev *wdev, struct sk_buff *skb) +{ + struct wfx_queue_stats *stats = &wdev->tx_queue_stats; + + spin_lock_bh(&stats->pending.lock); + __skb_unlink(skb, &stats->pending); + spin_unlock_bh(&stats->pending.lock); + wfx_skb_dtor(wdev, skb); + + return 0; +} + +struct sk_buff *wfx_pending_get(struct wfx_dev *wdev, u32 packet_id) +{ + struct sk_buff *skb; + struct hif_req_tx *req; + struct wfx_queue_stats *stats = &wdev->tx_queue_stats; + + spin_lock_bh(&stats->pending.lock); + skb_queue_walk(&stats->pending, skb) { + req = wfx_skb_txreq(skb); + if (req->packet_id == packet_id) { + spin_unlock_bh(&stats->pending.lock); + return skb; + } + } + spin_unlock_bh(&stats->pending.lock); + WARN(1, "cannot find packet in pending queue"); + return NULL; +} + +void wfx_pending_dump_old_frames(struct wfx_dev *wdev, unsigned int limit_ms) +{ + struct wfx_queue_stats *stats = &wdev->tx_queue_stats; + ktime_t now = ktime_get(); + struct wfx_tx_priv *tx_priv; + struct hif_req_tx *req; + struct sk_buff *skb; + bool first = true; + + spin_lock_bh(&stats->pending.lock); + skb_queue_walk(&stats->pending, skb) { + tx_priv = wfx_skb_tx_priv(skb); + req = wfx_skb_txreq(skb); + if (ktime_after(now, ktime_add_ms(tx_priv->xmit_timestamp, limit_ms))) { + if (first) { + dev_info(wdev->dev, "frames stuck in firmware since %dms or more:\n", + limit_ms); + first = false; + } + dev_info(wdev->dev, " id %08x sent %lldms ago\n", + req->packet_id, + ktime_ms_delta(now, tx_priv->xmit_timestamp)); + } + } + spin_unlock_bh(&stats->pending.lock); +} + +unsigned int wfx_pending_get_pkt_us_delay(struct wfx_dev *wdev, struct sk_buff *skb) +{ + ktime_t now = ktime_get(); + struct wfx_tx_priv *tx_priv = wfx_skb_tx_priv(skb); + + return ktime_us_delta(now, tx_priv->xmit_timestamp); +} + +bool wfx_tx_queues_is_empty(struct wfx_dev *wdev) +{ + int i; + struct sk_buff_head *queue; + bool ret = true; + + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + queue = &wdev->tx_queue[i].queue; + spin_lock_bh(&queue->lock); + if (!skb_queue_empty(queue)) + ret = false; + spin_unlock_bh(&queue->lock); + } + return ret; +} + +static bool hif_handle_tx_data(struct wfx_vif *wvif, struct sk_buff *skb, + struct wfx_queue *queue) +{ + bool handled = false; + struct wfx_tx_priv *tx_priv = wfx_skb_tx_priv(skb); + struct hif_req_tx *req = wfx_skb_txreq(skb); + struct ieee80211_hdr *frame = (struct ieee80211_hdr *) (req->frame + req->data_flags.fc_offset); + + enum { + do_probe, + do_drop, + do_wep, + do_tx, + } action = do_tx; + + switch (wvif->vif->type) { + case NL80211_IFTYPE_STATION: + if (wvif->state < WFX_STATE_PRE_STA) + action = do_drop; + break; + case NL80211_IFTYPE_AP: + if (!wvif->state) { + action = do_drop; + } else if (!(BIT(tx_priv->raw_link_id) & (BIT(0) | wvif->link_id_map))) { + dev_warn(wvif->wdev->dev, "a frame with expired link-id is dropped\n"); + action = do_drop; + } + break; + case NL80211_IFTYPE_ADHOC: + if (wvif->state != WFX_STATE_IBSS) + action = do_drop; + break; + case NL80211_IFTYPE_MONITOR: + default: + action = do_drop; + break; + } + + if (action == do_tx) { + if (ieee80211_is_nullfunc(frame->frame_control)) { + mutex_lock(&wvif->bss_loss_lock); + if (wvif->bss_loss_state) { + wvif->bss_loss_confirm_id = req->packet_id; + req->queue_id.queue_id = HIF_QUEUE_ID_VOICE; + } + mutex_unlock(&wvif->bss_loss_lock); + } else if (ieee80211_has_protected(frame->frame_control) && + tx_priv->hw_key && + tx_priv->hw_key->keyidx != wvif->wep_default_key_id && + (tx_priv->hw_key->cipher == WLAN_CIPHER_SUITE_WEP40 || + tx_priv->hw_key->cipher == WLAN_CIPHER_SUITE_WEP104)) { + action = do_wep; + } + } + + switch (action) { + case do_drop: + wfx_pending_remove(wvif->wdev, skb); + handled = true; + break; + case do_wep: + wfx_tx_lock(wvif->wdev); + wvif->wep_default_key_id = tx_priv->hw_key->keyidx; + wvif->wep_pending_skb = skb; + if (!schedule_work(&wvif->wep_key_work)) + wfx_tx_unlock(wvif->wdev); + handled = true; + break; + case do_tx: + break; + default: + /* Do nothing */ + break; + } + return handled; +} + +static int wfx_get_prio_queue(struct wfx_vif *wvif, + u32 tx_allowed_mask, int *total) +{ + static const int urgent = BIT(WFX_LINK_ID_AFTER_DTIM) | + BIT(WFX_LINK_ID_UAPSD); + struct hif_req_edca_queue_params *edca; + unsigned int score, best = -1; + int winner = -1; + int i; + + /* search for a winner using edca params */ + for (i = 0; i < IEEE80211_NUM_ACS; ++i) { + int queued; + + edca = &wvif->edca.params[i]; + queued = wfx_tx_queue_get_num_queued(&wvif->wdev->tx_queue[i], + tx_allowed_mask); + if (!queued) + continue; + *total += queued; + score = ((edca->aifsn + edca->cw_min) << 16) + + ((edca->cw_max - edca->cw_min) * + (get_random_int() & 0xFFFF)); + if (score < best && (winner < 0 || i != 3)) { + best = score; + winner = i; + } + } + + /* override winner if bursting */ + if (winner >= 0 && wvif->wdev->tx_burst_idx >= 0 && + winner != wvif->wdev->tx_burst_idx && + !wfx_tx_queue_get_num_queued(&wvif->wdev->tx_queue[winner], tx_allowed_mask & urgent) && + wfx_tx_queue_get_num_queued(&wvif->wdev->tx_queue[wvif->wdev->tx_burst_idx], tx_allowed_mask)) + winner = wvif->wdev->tx_burst_idx; + + return winner; +} + +static int wfx_tx_queue_mask_get(struct wfx_vif *wvif, + struct wfx_queue **queue_p, + u32 *tx_allowed_mask_p, + bool *more) +{ + int idx; + u32 tx_allowed_mask; + int total = 0; + + /* Search for a queue with multicast frames buffered */ + if (wvif->mcast_tx) { + tx_allowed_mask = BIT(WFX_LINK_ID_AFTER_DTIM); + idx = wfx_get_prio_queue(wvif, tx_allowed_mask, &total); + if (idx >= 0) { + *more = total > 1; + goto found; + } + } + + /* Search for unicast traffic */ + tx_allowed_mask = ~wvif->sta_asleep_mask; + tx_allowed_mask |= BIT(WFX_LINK_ID_UAPSD); + if (wvif->sta_asleep_mask) { + tx_allowed_mask |= wvif->pspoll_mask; + tx_allowed_mask &= ~BIT(WFX_LINK_ID_AFTER_DTIM); + } else { + tx_allowed_mask |= BIT(WFX_LINK_ID_AFTER_DTIM); + } + idx = wfx_get_prio_queue(wvif, tx_allowed_mask, &total); + if (idx < 0) + return -ENOENT; + +found: + *queue_p = &wvif->wdev->tx_queue[idx]; + *tx_allowed_mask_p = tx_allowed_mask; + return 0; +} + +struct hif_msg *wfx_tx_queues_get(struct wfx_dev *wdev) +{ + struct sk_buff *skb; + struct hif_msg *hif = NULL; + struct hif_req_tx *req = NULL; + struct wfx_queue *queue = NULL; + struct wfx_queue *vif_queue = NULL; + u32 tx_allowed_mask = 0; + u32 vif_tx_allowed_mask = 0; + const struct wfx_tx_priv *tx_priv = NULL; + struct wfx_vif *wvif; + /* More is used only for broadcasts. */ + bool more = false; + bool vif_more = false; + int not_found; + int burst; + + for (;;) { + int ret = -ENOENT; + int queue_num; + struct ieee80211_hdr *hdr; + + if (atomic_read(&wdev->tx_lock)) + return NULL; + + wvif = NULL; + while ((wvif = wvif_iterate(wdev, wvif)) != NULL) { + spin_lock_bh(&wvif->ps_state_lock); + + not_found = wfx_tx_queue_mask_get(wvif, &vif_queue, &vif_tx_allowed_mask, &vif_more); + + if (wvif->mcast_buffered && (not_found || !vif_more) && + (wvif->mcast_tx || !wvif->sta_asleep_mask)) { + wvif->mcast_buffered = false; + if (wvif->mcast_tx) { + wvif->mcast_tx = false; + schedule_work(&wvif->mcast_stop_work); + } + } + + spin_unlock_bh(&wvif->ps_state_lock); + + if (vif_more) { + more = true; + tx_allowed_mask = vif_tx_allowed_mask; + queue = vif_queue; + ret = 0; + break; + } else if (!not_found) { + if (queue && queue != vif_queue) + dev_info(wdev->dev, "vifs disagree about queue priority\n"); + tx_allowed_mask |= vif_tx_allowed_mask; + queue = vif_queue; + ret = 0; + } + } + + if (ret) + return NULL; + + queue_num = queue - wdev->tx_queue; + + skb = wfx_tx_queue_get(wdev, queue, tx_allowed_mask); + if (!skb) + continue; + tx_priv = wfx_skb_tx_priv(skb); + hif = (struct hif_msg *) skb->data; + wvif = wdev_to_wvif(wdev, hif->interface); + WARN_ON(!wvif); + + if (hif_handle_tx_data(wvif, skb, queue)) + continue; /* Handled by WSM */ + + wvif->pspoll_mask &= ~BIT(tx_priv->raw_link_id); + + /* allow bursting if txop is set */ + if (wvif->edca.params[queue_num].tx_op_limit) + burst = (int)wfx_tx_queue_get_num_queued(queue, tx_allowed_mask) + 1; + else + burst = 1; + + /* store index of bursting queue */ + if (burst > 1) + wdev->tx_burst_idx = queue_num; + else + wdev->tx_burst_idx = -1; + + /* more buffered multicast/broadcast frames + * ==> set MoreData flag in IEEE 802.11 header + * to inform PS STAs + */ + if (more) { + req = (struct hif_req_tx *) hif->body; + hdr = (struct ieee80211_hdr *) (req->frame + req->data_flags.fc_offset); + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); + } + return hif; + } +} diff --git a/drivers/staging/wfx/queue.h b/drivers/staging/wfx/queue.h new file mode 100644 index 000000000000..938dbf3469e7 --- /dev/null +++ b/drivers/staging/wfx/queue.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * O(1) TX queue with built-in allocator. + * + * Copyright (c) 2017-2018, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#ifndef WFX_QUEUE_H +#define WFX_QUEUE_H + +#include <linux/skbuff.h> + +#include "hif_api_cmd.h" + +#define WFX_MAX_STA_IN_AP_MODE 14 +#define WFX_LINK_ID_AFTER_DTIM (WFX_MAX_STA_IN_AP_MODE + 1) +#define WFX_LINK_ID_UAPSD (WFX_MAX_STA_IN_AP_MODE + 2) +#define WFX_LINK_ID_MAX (WFX_MAX_STA_IN_AP_MODE + 3) + +struct wfx_dev; +struct wfx_vif; + +struct wfx_queue { + struct sk_buff_head queue; + int tx_locked_cnt; + int link_map_cache[WFX_LINK_ID_MAX]; + u8 queue_id; +}; + +struct wfx_queue_stats { + int link_map_cache[WFX_LINK_ID_MAX]; + struct sk_buff_head pending; + wait_queue_head_t wait_link_id_empty; +}; + +void wfx_tx_lock(struct wfx_dev *wdev); +void wfx_tx_unlock(struct wfx_dev *wdev); +void wfx_tx_flush(struct wfx_dev *wdev); +void wfx_tx_lock_flush(struct wfx_dev *wdev); + +void wfx_tx_queues_init(struct wfx_dev *wdev); +void wfx_tx_queues_deinit(struct wfx_dev *wdev); +void wfx_tx_queues_lock(struct wfx_dev *wdev); +void wfx_tx_queues_unlock(struct wfx_dev *wdev); +void wfx_tx_queues_clear(struct wfx_dev *wdev); +bool wfx_tx_queues_is_empty(struct wfx_dev *wdev); +void wfx_tx_queues_wait_empty_vif(struct wfx_vif *wvif); +struct hif_msg *wfx_tx_queues_get(struct wfx_dev *wdev); + +void wfx_tx_queue_put(struct wfx_dev *wdev, struct wfx_queue *queue, struct sk_buff *skb); +size_t wfx_tx_queue_get_num_queued(struct wfx_queue *queue, u32 link_id_map); + +struct sk_buff *wfx_pending_get(struct wfx_dev *wdev, u32 packet_id); +int wfx_pending_remove(struct wfx_dev *wdev, struct sk_buff *skb); +int wfx_pending_requeue(struct wfx_dev *wdev, struct sk_buff *skb); +unsigned int wfx_pending_get_pkt_us_delay(struct wfx_dev *wdev, struct sk_buff *skb); +void wfx_pending_dump_old_frames(struct wfx_dev *wdev, unsigned int limit_ms); + +#endif /* WFX_QUEUE_H */ diff --git a/drivers/staging/wfx/scan.c b/drivers/staging/wfx/scan.c new file mode 100644 index 000000000000..cba735c1e73c --- /dev/null +++ b/drivers/staging/wfx/scan.c @@ -0,0 +1,289 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Scan related functions. + * + * Copyright (c) 2017-2019, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include <net/mac80211.h> + +#include "scan.h" +#include "wfx.h" +#include "sta.h" +#include "hif_tx_mib.h" + +static void __ieee80211_scan_completed_compat(struct ieee80211_hw *hw, bool aborted) +{ + struct cfg80211_scan_info info = { + .aborted = aborted ? 1 : 0, + }; + + ieee80211_scan_completed(hw, &info); +} + +static void wfx_scan_restart_delayed(struct wfx_vif *wvif) +{ + if (wvif->delayed_unjoin) { + wvif->delayed_unjoin = false; + if (!schedule_work(&wvif->unjoin_work)) + wfx_tx_unlock(wvif->wdev); + } else if (wvif->delayed_link_loss) { + wvif->delayed_link_loss = 0; + wfx_cqm_bssloss_sm(wvif, 1, 0, 0); + } +} + +static int wfx_scan_start(struct wfx_vif *wvif, struct wfx_scan_params *scan) +{ + int ret; + int tmo = 500; + + if (wvif->state == WFX_STATE_PRE_STA) + return -EBUSY; + + tmo += scan->scan_req.num_of_channels * + ((20 * (scan->scan_req.max_channel_time)) + 10); + atomic_set(&wvif->scan.in_progress, 1); + atomic_set(&wvif->wdev->scan_in_progress, 1); + + schedule_delayed_work(&wvif->scan.timeout, msecs_to_jiffies(tmo)); + ret = hif_scan(wvif, scan); + if (ret) { + wfx_scan_failed_cb(wvif); + atomic_set(&wvif->scan.in_progress, 0); + atomic_set(&wvif->wdev->scan_in_progress, 0); + cancel_delayed_work_sync(&wvif->scan.timeout); + wfx_scan_restart_delayed(wvif); + } + return ret; +} + +int wfx_hw_scan(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_scan_request *hw_req) +{ + struct wfx_dev *wdev = hw->priv; + struct wfx_vif *wvif = (struct wfx_vif *) vif->drv_priv; + struct cfg80211_scan_request *req = &hw_req->req; + struct sk_buff *skb; + int i, ret; + struct hif_mib_template_frame *p; + + if (!wvif) + return -EINVAL; + + if (wvif->state == WFX_STATE_AP) + return -EOPNOTSUPP; + + if (req->n_ssids == 1 && !req->ssids[0].ssid_len) + req->n_ssids = 0; + + if (req->n_ssids > HIF_API_MAX_NB_SSIDS) + return -EINVAL; + + skb = ieee80211_probereq_get(hw, wvif->vif->addr, NULL, 0, req->ie_len); + if (!skb) + return -ENOMEM; + + if (req->ie_len) + memcpy(skb_put(skb, req->ie_len), req->ie, req->ie_len); + + mutex_lock(&wdev->conf_mutex); + + p = (struct hif_mib_template_frame *)skb_push(skb, 4); + p->frame_type = HIF_TMPLT_PRBREQ; + p->frame_length = cpu_to_le16(skb->len - 4); + ret = hif_set_template_frame(wvif, p); + skb_pull(skb, 4); + + if (!ret) + /* Host want to be the probe responder. */ + ret = wfx_fwd_probe_req(wvif, true); + if (ret) { + mutex_unlock(&wdev->conf_mutex); + dev_kfree_skb(skb); + return ret; + } + + wfx_tx_lock_flush(wdev); + + WARN(wvif->scan.req, "unexpected concurrent scan"); + wvif->scan.req = req; + wvif->scan.n_ssids = 0; + wvif->scan.status = 0; + wvif->scan.begin = &req->channels[0]; + wvif->scan.curr = wvif->scan.begin; + wvif->scan.end = &req->channels[req->n_channels]; + wvif->scan.output_power = wdev->output_power; + + for (i = 0; i < req->n_ssids; ++i) { + struct hif_ssid_def *dst = &wvif->scan.ssids[wvif->scan.n_ssids]; + + memcpy(&dst->ssid[0], req->ssids[i].ssid, sizeof(dst->ssid)); + dst->ssid_length = req->ssids[i].ssid_len; + ++wvif->scan.n_ssids; + } + + mutex_unlock(&wdev->conf_mutex); + + if (skb) + dev_kfree_skb(skb); + schedule_work(&wvif->scan.work); + return 0; +} + +void wfx_scan_work(struct work_struct *work) +{ + struct wfx_vif *wvif = container_of(work, struct wfx_vif, scan.work); + struct ieee80211_channel **it; + struct wfx_scan_params scan = { + .scan_req.scan_type.type = 0, /* Foreground */ + }; + struct ieee80211_channel *first; + bool first_run = (wvif->scan.begin == wvif->scan.curr && + wvif->scan.begin != wvif->scan.end); + int i; + + down(&wvif->scan.lock); + mutex_lock(&wvif->wdev->conf_mutex); + + if (first_run) { + if (wvif->state == WFX_STATE_STA && + !(wvif->powersave_mode.pm_mode.enter_psm)) { + struct hif_req_set_pm_mode pm = wvif->powersave_mode; + + pm.pm_mode.enter_psm = 1; + wfx_set_pm(wvif, &pm); + } + } + + if (!wvif->scan.req || wvif->scan.curr == wvif->scan.end) { + if (wvif->scan.output_power != wvif->wdev->output_power) + hif_set_output_power(wvif, wvif->wdev->output_power * 10); + + if (wvif->scan.status < 0) + dev_warn(wvif->wdev->dev, "scan failed\n"); + else if (wvif->scan.req) + dev_dbg(wvif->wdev->dev, "scan completed\n"); + else + dev_dbg(wvif->wdev->dev, "scan canceled\n"); + + wvif->scan.req = NULL; + wfx_scan_restart_delayed(wvif); + wfx_tx_unlock(wvif->wdev); + mutex_unlock(&wvif->wdev->conf_mutex); + __ieee80211_scan_completed_compat(wvif->wdev->hw, wvif->scan.status ? 1 : 0); + up(&wvif->scan.lock); + if (wvif->state == WFX_STATE_STA && + !(wvif->powersave_mode.pm_mode.enter_psm)) + wfx_set_pm(wvif, &wvif->powersave_mode); + return; + } + first = *wvif->scan.curr; + + for (it = wvif->scan.curr + 1, i = 1; + it != wvif->scan.end && i < HIF_API_MAX_NB_CHANNELS; + ++it, ++i) { + if ((*it)->band != first->band) + break; + if (((*it)->flags ^ first->flags) & + IEEE80211_CHAN_NO_IR) + break; + if (!(first->flags & IEEE80211_CHAN_NO_IR) && + (*it)->max_power != first->max_power) + break; + } + scan.scan_req.band = first->band; + + if (wvif->scan.req->no_cck) + scan.scan_req.max_transmit_rate = API_RATE_INDEX_G_6MBPS; + else + scan.scan_req.max_transmit_rate = API_RATE_INDEX_B_1MBPS; + scan.scan_req.num_of_probe_requests = + (first->flags & IEEE80211_CHAN_NO_IR) ? 0 : 2; + scan.scan_req.num_of_ssi_ds = wvif->scan.n_ssids; + scan.ssids = &wvif->scan.ssids[0]; + scan.scan_req.num_of_channels = it - wvif->scan.curr; + scan.scan_req.probe_delay = 100; + // FIXME: Check if FW can do active scan while joined. + if (wvif->state == WFX_STATE_STA) { + scan.scan_req.scan_type.type = 1; + scan.scan_req.scan_flags.fbg = 1; + } + + scan.ch = kcalloc(scan.scan_req.num_of_channels, sizeof(u8), GFP_KERNEL); + + if (!scan.ch) { + wvif->scan.status = -ENOMEM; + goto fail; + } + for (i = 0; i < scan.scan_req.num_of_channels; ++i) + scan.ch[i] = wvif->scan.curr[i]->hw_value; + + if (wvif->scan.curr[0]->flags & IEEE80211_CHAN_NO_IR) { + scan.scan_req.min_channel_time = 50; + scan.scan_req.max_channel_time = 150; + } else { + scan.scan_req.min_channel_time = 10; + scan.scan_req.max_channel_time = 50; + } + if (!(first->flags & IEEE80211_CHAN_NO_IR) && + wvif->scan.output_power != first->max_power) { + wvif->scan.output_power = first->max_power; + hif_set_output_power(wvif, wvif->scan.output_power * 10); + } + wvif->scan.status = wfx_scan_start(wvif, &scan); + kfree(scan.ch); + if (wvif->scan.status) + goto fail; + wvif->scan.curr = it; + mutex_unlock(&wvif->wdev->conf_mutex); + return; + +fail: + wvif->scan.curr = wvif->scan.end; + mutex_unlock(&wvif->wdev->conf_mutex); + up(&wvif->scan.lock); + schedule_work(&wvif->scan.work); +} + +static void wfx_scan_complete(struct wfx_vif *wvif) +{ + up(&wvif->scan.lock); + atomic_set(&wvif->wdev->scan_in_progress, 0); + + wfx_scan_work(&wvif->scan.work); +} + +void wfx_scan_failed_cb(struct wfx_vif *wvif) +{ + if (cancel_delayed_work_sync(&wvif->scan.timeout) > 0) { + wvif->scan.status = -EIO; + schedule_work(&wvif->scan.timeout.work); + } +} + +void wfx_scan_complete_cb(struct wfx_vif *wvif, struct hif_ind_scan_cmpl *arg) +{ + if (cancel_delayed_work_sync(&wvif->scan.timeout) > 0) { + wvif->scan.status = 1; + schedule_work(&wvif->scan.timeout.work); + } +} + +void wfx_scan_timeout(struct work_struct *work) +{ + struct wfx_vif *wvif = container_of(work, struct wfx_vif, scan.timeout.work); + + if (atomic_xchg(&wvif->scan.in_progress, 0)) { + if (wvif->scan.status > 0) { + wvif->scan.status = 0; + } else if (!wvif->scan.status) { + dev_warn(wvif->wdev->dev, "timeout waiting for scan complete notification\n"); + wvif->scan.status = -ETIMEDOUT; + wvif->scan.curr = wvif->scan.end; + hif_stop_scan(wvif); + } + wfx_scan_complete(wvif); + } +} diff --git a/drivers/staging/wfx/scan.h b/drivers/staging/wfx/scan.h new file mode 100644 index 000000000000..b4ddd0771a9b --- /dev/null +++ b/drivers/staging/wfx/scan.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Scan related functions. + * + * Copyright (c) 2017-2019, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#ifndef WFX_SCAN_H +#define WFX_SCAN_H + +#include <linux/semaphore.h> +#include <linux/workqueue.h> +#include <net/mac80211.h> + +#include "hif_api_cmd.h" + +struct wfx_dev; +struct wfx_vif; + +struct wfx_scan { + struct semaphore lock; + struct work_struct work; + struct delayed_work timeout; + struct cfg80211_scan_request *req; + struct ieee80211_channel **begin; + struct ieee80211_channel **curr; + struct ieee80211_channel **end; + struct hif_ssid_def ssids[HIF_API_MAX_NB_SSIDS]; + int output_power; + int n_ssids; + int status; + atomic_t in_progress; +}; + +int wfx_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_scan_request *req); +void wfx_scan_work(struct work_struct *work); +void wfx_scan_timeout(struct work_struct *work); +void wfx_scan_complete_cb(struct wfx_vif *wvif, struct hif_ind_scan_cmpl *arg); +void wfx_scan_failed_cb(struct wfx_vif *wvif); + +#endif /* WFX_SCAN_H */ diff --git a/drivers/staging/wfx/secure_link.h b/drivers/staging/wfx/secure_link.h new file mode 100644 index 000000000000..376d7bc4c0c4 --- /dev/null +++ b/drivers/staging/wfx/secure_link.h @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2019, Silicon Laboratories, Inc. + */ +#ifndef WFX_SECURE_LINK_H +#define WFX_SECURE_LINK_H + +#include <linux/of.h> + +#include "hif_api_general.h" + +struct wfx_dev; + + +struct sl_context { +}; + +static inline bool wfx_is_secure_command(struct wfx_dev *wdev, int cmd_id) +{ + return false; +} + +static inline int wfx_sl_decode(struct wfx_dev *wdev, struct hif_sl_msg *m) +{ + return -EIO; +} + +static inline int wfx_sl_encode(struct wfx_dev *wdev, struct hif_msg *input, struct hif_sl_msg *output) +{ + return -EIO; +} + +static inline int wfx_sl_check_pubkey(struct wfx_dev *wdev, uint8_t *ncp_pubkey, uint8_t *ncp_pubmac) +{ + return -EIO; +} + +static inline void wfx_sl_fill_pdata(struct device *dev, + struct wfx_platform_data *pdata) +{ + if (of_find_property(dev->of_node, "slk_key", NULL)) + dev_err(dev, "secure link is not supported by this driver, ignoring provided key\n"); +} + +static inline int wfx_sl_init(struct wfx_dev *wdev) +{ + return -EIO; +} + +static inline void wfx_sl_deinit(struct wfx_dev *wdev) +{ +} + + +#endif diff --git a/drivers/staging/wfx/sta.c b/drivers/staging/wfx/sta.c new file mode 100644 index 000000000000..2ab5ba9742ad --- /dev/null +++ b/drivers/staging/wfx/sta.c @@ -0,0 +1,1636 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Implementation of mac80211 API. + * + * Copyright (c) 2017-2019, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include <net/mac80211.h> + +#include "sta.h" +#include "wfx.h" +#include "fwio.h" +#include "bh.h" +#include "key.h" +#include "scan.h" +#include "debug.h" +#include "hif_tx.h" +#include "hif_tx_mib.h" + +#define TXOP_UNIT 32 +#define HIF_MAX_ARP_IP_ADDRTABLE_ENTRIES 2 + +static u32 wfx_rate_mask_to_hw(struct wfx_dev *wdev, u32 rates) +{ + int i; + u32 ret = 0; + // WFx only support 2GHz + struct ieee80211_supported_band *sband = wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]; + + for (i = 0; i < sband->n_bitrates; i++) { + if (rates & BIT(i)) { + if (i >= sband->n_bitrates) + dev_warn(wdev->dev, "unsupported basic rate\n"); + else + ret |= BIT(sband->bitrates[i].hw_value); + } + } + return ret; +} + +static void __wfx_free_event_queue(struct list_head *list) +{ + struct wfx_hif_event *event, *tmp; + + list_for_each_entry_safe(event, tmp, list, link) { + list_del(&event->link); + kfree(event); + } +} + +static void wfx_free_event_queue(struct wfx_vif *wvif) +{ + LIST_HEAD(list); + + spin_lock(&wvif->event_queue_lock); + list_splice_init(&wvif->event_queue, &list); + spin_unlock(&wvif->event_queue_lock); + + __wfx_free_event_queue(&list); +} + +void wfx_cqm_bssloss_sm(struct wfx_vif *wvif, int init, int good, int bad) +{ + int tx = 0; + + mutex_lock(&wvif->bss_loss_lock); + wvif->delayed_link_loss = 0; + cancel_work_sync(&wvif->bss_params_work); + + /* If we have a pending unjoin */ + if (wvif->delayed_unjoin) + goto end; + + if (init) { + schedule_delayed_work(&wvif->bss_loss_work, HZ); + wvif->bss_loss_state = 0; + + if (!atomic_read(&wvif->wdev->tx_lock)) + tx = 1; + } else if (good) { + cancel_delayed_work_sync(&wvif->bss_loss_work); + wvif->bss_loss_state = 0; + schedule_work(&wvif->bss_params_work); + } else if (bad) { + /* FIXME Should we just keep going until we time out? */ + if (wvif->bss_loss_state < 3) + tx = 1; + } else { + cancel_delayed_work_sync(&wvif->bss_loss_work); + wvif->bss_loss_state = 0; + } + + /* Spit out a NULL packet to our AP if necessary */ + // FIXME: call ieee80211_beacon_loss/ieee80211_connection_loss instead + if (tx) { + struct sk_buff *skb; + + wvif->bss_loss_state++; + + skb = ieee80211_nullfunc_get(wvif->wdev->hw, wvif->vif, false); + if (!skb) + goto end; + memset(IEEE80211_SKB_CB(skb), 0, sizeof(*IEEE80211_SKB_CB(skb))); + IEEE80211_SKB_CB(skb)->control.vif = wvif->vif; + IEEE80211_SKB_CB(skb)->driver_rates[0].idx = 0; + IEEE80211_SKB_CB(skb)->driver_rates[0].count = 1; + IEEE80211_SKB_CB(skb)->driver_rates[1].idx = -1; + wfx_tx(wvif->wdev->hw, NULL, skb); + } +end: + mutex_unlock(&wvif->bss_loss_lock); +} + +static int wfx_set_uapsd_param(struct wfx_vif *wvif, + const struct wfx_edca_params *arg) +{ + /* Here's the mapping AC [queue, bit] + * VO [0,3], VI [1, 2], BE [2, 1], BK [3, 0] + */ + + if (arg->uapsd_enable[IEEE80211_AC_VO]) + wvif->uapsd_info.trig_voice = 1; + else + wvif->uapsd_info.trig_voice = 0; + + if (arg->uapsd_enable[IEEE80211_AC_VI]) + wvif->uapsd_info.trig_video = 1; + else + wvif->uapsd_info.trig_video = 0; + + if (arg->uapsd_enable[IEEE80211_AC_BE]) + wvif->uapsd_info.trig_be = 1; + else + wvif->uapsd_info.trig_be = 0; + + if (arg->uapsd_enable[IEEE80211_AC_BK]) + wvif->uapsd_info.trig_bckgrnd = 1; + else + wvif->uapsd_info.trig_bckgrnd = 0; + + /* Currently pseudo U-APSD operation is not supported, so setting + * MinAutoTriggerInterval, MaxAutoTriggerInterval and + * AutoTriggerStep to 0 + */ + wvif->uapsd_info.min_auto_trigger_interval = 0; + wvif->uapsd_info.max_auto_trigger_interval = 0; + wvif->uapsd_info.auto_trigger_step = 0; + + return hif_set_uapsd_info(wvif, &wvif->uapsd_info); +} + +int wfx_fwd_probe_req(struct wfx_vif *wvif, bool enable) +{ + wvif->fwd_probe_req = enable; + return hif_set_rx_filter(wvif, wvif->filter_bssid, + wvif->fwd_probe_req); +} + +static int wfx_set_mcast_filter(struct wfx_vif *wvif, + struct wfx_grp_addr_table *fp) +{ + int i, ret; + struct hif_mib_config_data_filter config = { }; + struct hif_mib_set_data_filtering filter_data = { }; + struct hif_mib_mac_addr_data_frame_condition filter_addr_val = { }; + struct hif_mib_uc_mc_bc_data_frame_condition filter_addr_type = { }; + + // Temporary workaround for filters + return hif_set_data_filtering(wvif, &filter_data); + + if (!fp->enable) { + filter_data.enable = 0; + return hif_set_data_filtering(wvif, &filter_data); + } + + // A1 Address match on list + for (i = 0; i < fp->num_addresses; i++) { + filter_addr_val.condition_idx = i; + filter_addr_val.address_type = HIF_MAC_ADDR_A1; + ether_addr_copy(filter_addr_val.mac_address, fp->address_list[i]); + ret = hif_set_mac_addr_condition(wvif, &filter_addr_val); + if (ret) + return ret; + config.mac_cond |= 1 << i; + } + + // Accept unicast and broadcast + filter_addr_type.condition_idx = 0; + filter_addr_type.param.bits.type_unicast = 1; + filter_addr_type.param.bits.type_broadcast = 1; + ret = hif_set_uc_mc_bc_condition(wvif, &filter_addr_type); + if (ret) + return ret; + + config.uc_mc_bc_cond = 1; + config.filter_idx = 0; // TODO #define MULTICAST_FILTERING 0 + config.enable = 1; + ret = hif_set_config_data_filter(wvif, &config); + if (ret) + return ret; + + // discard all data frames except match filter + filter_data.enable = 1; + filter_data.default_filter = 1; // discard all + ret = hif_set_data_filtering(wvif, &filter_data); + + return ret; +} + +void wfx_update_filtering(struct wfx_vif *wvif) +{ + int ret; + bool is_sta = wvif->vif && NL80211_IFTYPE_STATION == wvif->vif->type; + bool filter_bssid = wvif->filter_bssid; + bool fwd_probe_req = wvif->fwd_probe_req; + struct hif_mib_bcn_filter_enable bf_ctrl; + struct hif_ie_table_entry filter_ies[] = { + { + .ie_id = WLAN_EID_VENDOR_SPECIFIC, + .has_changed = 1, + .no_longer = 1, + .has_appeared = 1, + .oui = { 0x50, 0x6F, 0x9A }, + }, { + .ie_id = WLAN_EID_HT_OPERATION, + .has_changed = 1, + .no_longer = 1, + .has_appeared = 1, + }, { + .ie_id = WLAN_EID_ERP_INFO, + .has_changed = 1, + .no_longer = 1, + .has_appeared = 1, + } + }; + int n_filter_ies; + + if (wvif->state == WFX_STATE_PASSIVE) + return; + + if (wvif->disable_beacon_filter) { + bf_ctrl.enable = 0; + bf_ctrl.bcn_count = 1; + n_filter_ies = 0; + } else if (!is_sta) { + bf_ctrl.enable = HIF_BEACON_FILTER_ENABLE | HIF_BEACON_FILTER_AUTO_ERP; + bf_ctrl.bcn_count = 0; + n_filter_ies = 2; + } else { + bf_ctrl.enable = HIF_BEACON_FILTER_ENABLE; + bf_ctrl.bcn_count = 0; + n_filter_ies = 3; + } + + ret = hif_set_rx_filter(wvif, filter_bssid, fwd_probe_req); + if (!ret) + ret = hif_set_beacon_filter_table(wvif, n_filter_ies, filter_ies); + if (!ret) + ret = hif_beacon_filter_control(wvif, bf_ctrl.enable, bf_ctrl.bcn_count); + if (!ret) + ret = wfx_set_mcast_filter(wvif, &wvif->mcast_filter); + if (ret) + dev_err(wvif->wdev->dev, "update filtering failed: %d\n", ret); +} + +static void wfx_update_filtering_work(struct work_struct *work) +{ + struct wfx_vif *wvif = container_of(work, struct wfx_vif, update_filtering_work); + + wfx_update_filtering(wvif); +} + +u64 wfx_prepare_multicast(struct ieee80211_hw *hw, struct netdev_hw_addr_list *mc_list) +{ + int i; + struct netdev_hw_addr *ha; + struct wfx_vif *wvif = NULL; + struct wfx_dev *wdev = hw->priv; + int count = netdev_hw_addr_list_count(mc_list); + + while ((wvif = wvif_iterate(wdev, wvif)) != NULL) { + memset(&wvif->mcast_filter, 0x00, sizeof(wvif->mcast_filter)); + if (!count || count > ARRAY_SIZE(wvif->mcast_filter.address_list)) + continue; + + i = 0; + netdev_hw_addr_list_for_each(ha, mc_list) { + ether_addr_copy(wvif->mcast_filter.address_list[i], ha->addr); + i++; + } + wvif->mcast_filter.enable = true; + wvif->mcast_filter.num_addresses = count; + } + + return 0; +} + +void wfx_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + u64 unused) +{ + struct wfx_vif *wvif = NULL; + struct wfx_dev *wdev = hw->priv; + + *total_flags &= FIF_OTHER_BSS | FIF_FCSFAIL | FIF_PROBE_REQ; + + while ((wvif = wvif_iterate(wdev, wvif)) != NULL) { + down(&wvif->scan.lock); + wvif->filter_bssid = (*total_flags & (FIF_OTHER_BSS | FIF_PROBE_REQ)) ? 0 : 1; + wvif->disable_beacon_filter = !(*total_flags & FIF_PROBE_REQ); + wfx_fwd_probe_req(wvif, true); + wfx_update_filtering(wvif); + up(&wvif->scan.lock); + } +} + +int wfx_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u16 queue, const struct ieee80211_tx_queue_params *params) +{ + struct wfx_dev *wdev = hw->priv; + struct wfx_vif *wvif = (struct wfx_vif *) vif->drv_priv; + int ret = 0; + /* To prevent re-applying PM request OID again and again*/ + u16 old_uapsd_flags, new_uapsd_flags; + struct hif_req_edca_queue_params *edca; + + mutex_lock(&wdev->conf_mutex); + + if (queue < hw->queues) { + old_uapsd_flags = *((u16 *) &wvif->uapsd_info); + edca = &wvif->edca.params[queue]; + + wvif->edca.uapsd_enable[queue] = params->uapsd; + edca->aifsn = params->aifs; + edca->cw_min = params->cw_min; + edca->cw_max = params->cw_max; + edca->tx_op_limit = params->txop * TXOP_UNIT; + edca->allowed_medium_time = 0; + ret = hif_set_edca_queue_params(wvif, edca); + if (ret) { + ret = -EINVAL; + goto out; + } + + if (wvif->vif->type == NL80211_IFTYPE_STATION) { + ret = wfx_set_uapsd_param(wvif, &wvif->edca); + new_uapsd_flags = *((u16 *) &wvif->uapsd_info); + if (!ret && wvif->setbssparams_done && + wvif->state == WFX_STATE_STA && + old_uapsd_flags != new_uapsd_flags) + ret = wfx_set_pm(wvif, &wvif->powersave_mode); + } + } else { + ret = -EINVAL; + } + +out: + mutex_unlock(&wdev->conf_mutex); + return ret; +} + +int wfx_set_pm(struct wfx_vif *wvif, const struct hif_req_set_pm_mode *arg) +{ + struct hif_req_set_pm_mode pm = *arg; + u16 uapsd_flags; + int ret; + + if (wvif->state != WFX_STATE_STA || !wvif->bss_params.aid) + return 0; + + memcpy(&uapsd_flags, &wvif->uapsd_info, sizeof(uapsd_flags)); + + if (uapsd_flags != 0) + pm.pm_mode.fast_psm = 0; + + // Kernel disable PowerSave when multiple vifs are in use. In contrary, + // it is absolutly necessary to enable PowerSave for WF200 + if (wvif_count(wvif->wdev) > 1) { + pm.pm_mode.enter_psm = 1; + pm.pm_mode.fast_psm = 0; + } + + if (!wait_for_completion_timeout(&wvif->set_pm_mode_complete, msecs_to_jiffies(300))) + dev_warn(wvif->wdev->dev, "timeout while waiting of set_pm_mode_complete\n"); + ret = hif_set_pm(wvif, &pm); + // FIXME: why ? + if (-ETIMEDOUT == wvif->scan.status) + wvif->scan.status = 1; + return ret; +} + +int wfx_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +{ + struct wfx_dev *wdev = hw->priv; + struct wfx_vif *wvif = NULL; + + while ((wvif = wvif_iterate(wdev, wvif)) != NULL) + hif_rts_threshold(wvif, value); + return 0; +} + +/* If successful, LOCKS the TX queue! */ +static int __wfx_flush(struct wfx_dev *wdev, bool drop) +{ + int ret; + + for (;;) { + if (drop) { + wfx_tx_queues_clear(wdev); + } else { + ret = wait_event_timeout( + wdev->tx_queue_stats.wait_link_id_empty, + wfx_tx_queues_is_empty(wdev), + 2 * HZ); + } + + if (!drop && ret <= 0) { + ret = -ETIMEDOUT; + break; + } + ret = 0; + + wfx_tx_lock_flush(wdev); + if (!wfx_tx_queues_is_empty(wdev)) { + /* Highly unlikely: WSM requeued frames. */ + wfx_tx_unlock(wdev); + continue; + } + break; + } + return ret; +} + +void wfx_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop) +{ + struct wfx_dev *wdev = hw->priv; + struct wfx_vif *wvif; + + if (vif) { + wvif = (struct wfx_vif *) vif->drv_priv; + if (wvif->vif->type == NL80211_IFTYPE_MONITOR) + drop = true; + if (wvif->vif->type == NL80211_IFTYPE_AP && !wvif->enable_beacon) + drop = true; + } + + // FIXME: only flush requested vif + if (!__wfx_flush(wdev, drop)) + wfx_tx_unlock(wdev); +} + +/* WSM callbacks */ + +static void wfx_event_report_rssi(struct wfx_vif *wvif, uint8_t raw_rcpi_rssi) +{ + /* RSSI: signed Q8.0, RCPI: unsigned Q7.1 + * RSSI = RCPI / 2 - 110 + */ + int rcpi_rssi; + int cqm_evt; + + rcpi_rssi = raw_rcpi_rssi / 2 - 110; + if (rcpi_rssi <= wvif->cqm_rssi_thold) + cqm_evt = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW; + else + cqm_evt = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; + ieee80211_cqm_rssi_notify(wvif->vif, cqm_evt, rcpi_rssi, GFP_KERNEL); +} + +static void wfx_event_handler_work(struct work_struct *work) +{ + struct wfx_vif *wvif = + container_of(work, struct wfx_vif, event_handler_work); + struct wfx_hif_event *event; + + LIST_HEAD(list); + + spin_lock(&wvif->event_queue_lock); + list_splice_init(&wvif->event_queue, &list); + spin_unlock(&wvif->event_queue_lock); + + list_for_each_entry(event, &list, link) { + switch (event->evt.event_id) { + case HIF_EVENT_IND_BSSLOST: + cancel_work_sync(&wvif->unjoin_work); + if (!down_trylock(&wvif->scan.lock)) { + wfx_cqm_bssloss_sm(wvif, 1, 0, 0); + up(&wvif->scan.lock); + } else { + /* Scan is in progress. Delay reporting. + * Scan complete will trigger bss_loss_work + */ + wvif->delayed_link_loss = 1; + /* Also start a watchdog. */ + schedule_delayed_work(&wvif->bss_loss_work, 5 * HZ); + } + break; + case HIF_EVENT_IND_BSSREGAINED: + wfx_cqm_bssloss_sm(wvif, 0, 0, 0); + cancel_work_sync(&wvif->unjoin_work); + break; + case HIF_EVENT_IND_RCPI_RSSI: + wfx_event_report_rssi(wvif, event->evt.event_data.rcpi_rssi); + break; + case HIF_EVENT_IND_PS_MODE_ERROR: + dev_warn(wvif->wdev->dev, "error while processing power save request\n"); + break; + default: + dev_warn(wvif->wdev->dev, "unhandled event indication: %.2x\n", event->evt.event_id); + break; + } + } + __wfx_free_event_queue(&list); +} + +static void wfx_bss_loss_work(struct work_struct *work) +{ + struct wfx_vif *wvif = container_of(work, struct wfx_vif, bss_loss_work.work); + + ieee80211_connection_loss(wvif->vif); +} + +static void wfx_bss_params_work(struct work_struct *work) +{ + struct wfx_vif *wvif = container_of(work, struct wfx_vif, bss_params_work); + + mutex_lock(&wvif->wdev->conf_mutex); + wvif->bss_params.bss_flags.lost_count_only = 1; + hif_set_bss_params(wvif, &wvif->bss_params); + wvif->bss_params.bss_flags.lost_count_only = 0; + mutex_unlock(&wvif->wdev->conf_mutex); +} + +static void wfx_set_beacon_wakeup_period_work(struct work_struct *work) +{ + struct wfx_vif *wvif = container_of(work, struct wfx_vif, set_beacon_wakeup_period_work); + + hif_set_beacon_wakeup_period(wvif, wvif->dtim_period, wvif->dtim_period); +} + +static void wfx_do_unjoin(struct wfx_vif *wvif) +{ + mutex_lock(&wvif->wdev->conf_mutex); + + if (atomic_read(&wvif->scan.in_progress)) { + if (wvif->delayed_unjoin) + dev_dbg(wvif->wdev->dev, "delayed unjoin is already scheduled\n"); + else + wvif->delayed_unjoin = true; + goto done; + } + + wvif->delayed_link_loss = false; + + if (!wvif->state) + goto done; + + if (wvif->state == WFX_STATE_AP) + goto done; + + cancel_work_sync(&wvif->update_filtering_work); + cancel_work_sync(&wvif->set_beacon_wakeup_period_work); + wvif->state = WFX_STATE_PASSIVE; + + /* Unjoin is a reset. */ + wfx_tx_flush(wvif->wdev); + hif_keep_alive_period(wvif, 0); + hif_reset(wvif, false); + hif_set_output_power(wvif, wvif->wdev->output_power * 10); + wvif->dtim_period = 0; + hif_set_macaddr(wvif, wvif->vif->addr); + wfx_free_event_queue(wvif); + cancel_work_sync(&wvif->event_handler_work); + wfx_cqm_bssloss_sm(wvif, 0, 0, 0); + + /* Disable Block ACKs */ + hif_set_block_ack_policy(wvif, 0, 0); + + wvif->disable_beacon_filter = false; + wfx_update_filtering(wvif); + memset(&wvif->bss_params, 0, sizeof(wvif->bss_params)); + wvif->setbssparams_done = false; + memset(&wvif->ht_info, 0, sizeof(wvif->ht_info)); + +done: + mutex_unlock(&wvif->wdev->conf_mutex); +} + +static void wfx_set_mfp(struct wfx_vif *wvif, struct cfg80211_bss *bss) +{ + const int pairwise_cipher_suite_count_offset = 8 / sizeof(uint16_t); + const int pairwise_cipher_suite_size = 4 / sizeof(uint16_t); + const int akm_suite_size = 4 / sizeof(uint16_t); + const uint16_t *ptr = NULL; + bool mfpc = false; + bool mfpr = false; + + /* 802.11w protected mgmt frames */ + + /* retrieve MFPC and MFPR flags from beacon or PBRSP */ + + rcu_read_lock(); + if (bss) + ptr = (const uint16_t *) ieee80211_bss_get_ie(bss, WLAN_EID_RSN); + + if (ptr) { + ptr += pairwise_cipher_suite_count_offset; + ptr += 1 + pairwise_cipher_suite_size * *ptr; + ptr += 1 + akm_suite_size * *ptr; + mfpr = *ptr & BIT(6); + mfpc = *ptr & BIT(7); + } + rcu_read_unlock(); + + hif_set_mfp(wvif, mfpc, mfpr); +} + +/* MUST be called with tx_lock held! It will be unlocked for us. */ +static void wfx_do_join(struct wfx_vif *wvif) +{ + const u8 *bssid; + struct ieee80211_bss_conf *conf = &wvif->vif->bss_conf; + struct cfg80211_bss *bss = NULL; + struct hif_req_join join = { + .mode = conf->ibss_joined ? HIF_MODE_IBSS : HIF_MODE_BSS, + .preamble_type = conf->use_short_preamble ? HIF_PREAMBLE_SHORT : HIF_PREAMBLE_LONG, + .probe_for_join = 1, + .atim_window = 0, + .basic_rate_set = wfx_rate_mask_to_hw(wvif->wdev, conf->basic_rates), + }; + + if (wvif->channel->flags & IEEE80211_CHAN_NO_IR) + join.probe_for_join = 0; + + if (wvif->state) + wfx_do_unjoin(wvif); + + bssid = wvif->vif->bss_conf.bssid; + + bss = cfg80211_get_bss(wvif->wdev->hw->wiphy, wvif->channel, bssid, NULL, 0, + IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY); + + if (!bss && !conf->ibss_joined) { + wfx_tx_unlock(wvif->wdev); + return; + } + + mutex_lock(&wvif->wdev->conf_mutex); + + /* Under the conf lock: check scan status and + * bail out if it is in progress. + */ + if (atomic_read(&wvif->scan.in_progress)) { + wfx_tx_unlock(wvif->wdev); + goto done_put; + } + + /* Sanity check basic rates */ + if (!join.basic_rate_set) + join.basic_rate_set = 7; + + /* Sanity check beacon interval */ + if (!wvif->beacon_int) + wvif->beacon_int = 1; + + join.beacon_interval = wvif->beacon_int; + + // DTIM period will be set on first Beacon + wvif->dtim_period = 0; + + join.channel_number = wvif->channel->hw_value; + memcpy(join.bssid, bssid, sizeof(join.bssid)); + + if (!conf->ibss_joined) { + const u8 *ssidie; + + rcu_read_lock(); + ssidie = ieee80211_bss_get_ie(bss, WLAN_EID_SSID); + if (ssidie) { + join.ssid_length = ssidie[1]; + memcpy(join.ssid, &ssidie[2], join.ssid_length); + } + rcu_read_unlock(); + } + + wfx_tx_flush(wvif->wdev); + + if (wvif_count(wvif->wdev) <= 1) + hif_set_block_ack_policy(wvif, 0xFF, 0xFF); + + wfx_set_mfp(wvif, bss); + + /* Perform actual join */ + wvif->wdev->tx_burst_idx = -1; + if (hif_join(wvif, &join)) { + ieee80211_connection_loss(wvif->vif); + wvif->join_complete_status = -1; + /* Tx lock still held, unjoin will clear it. */ + if (!schedule_work(&wvif->unjoin_work)) + wfx_tx_unlock(wvif->wdev); + } else { + wvif->join_complete_status = 0; + if (wvif->vif->type == NL80211_IFTYPE_ADHOC) + wvif->state = WFX_STATE_IBSS; + else + wvif->state = WFX_STATE_PRE_STA; + wfx_tx_unlock(wvif->wdev); + + /* Upload keys */ + wfx_upload_keys(wvif); + + /* Due to beacon filtering it is possible that the + * AP's beacon is not known for the mac80211 stack. + * Disable filtering temporary to make sure the stack + * receives at least one + */ + wvif->disable_beacon_filter = true; + } + wfx_update_filtering(wvif); + +done_put: + mutex_unlock(&wvif->wdev->conf_mutex); + if (bss) + cfg80211_put_bss(wvif->wdev->hw->wiphy, bss); +} + +static void wfx_unjoin_work(struct work_struct *work) +{ + struct wfx_vif *wvif = container_of(work, struct wfx_vif, unjoin_work); + + wfx_do_unjoin(wvif); + wfx_tx_unlock(wvif->wdev); +} + +int wfx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct wfx_dev *wdev = hw->priv; + struct wfx_vif *wvif = (struct wfx_vif *) vif->drv_priv; + struct wfx_sta_priv *sta_priv = (struct wfx_sta_priv *) &sta->drv_priv; + struct wfx_link_entry *entry; + struct sk_buff *skb; + + if (wvif->vif->type != NL80211_IFTYPE_AP) + return 0; + + sta_priv->vif_id = wvif->id; + sta_priv->link_id = wfx_find_link_id(wvif, sta->addr); + if (!sta_priv->link_id) { + dev_warn(wdev->dev, "mo more link-id available\n"); + return -ENOENT; + } + + entry = &wvif->link_id_db[sta_priv->link_id - 1]; + spin_lock_bh(&wvif->ps_state_lock); + if ((sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) == + IEEE80211_WMM_IE_STA_QOSINFO_AC_MASK) + wvif->sta_asleep_mask |= BIT(sta_priv->link_id); + entry->status = WFX_LINK_HARD; + while ((skb = skb_dequeue(&entry->rx_queue))) + ieee80211_rx_irqsafe(wdev->hw, skb); + spin_unlock_bh(&wvif->ps_state_lock); + return 0; +} + +int wfx_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct wfx_dev *wdev = hw->priv; + struct wfx_vif *wvif = (struct wfx_vif *) vif->drv_priv; + struct wfx_sta_priv *sta_priv = (struct wfx_sta_priv *) &sta->drv_priv; + struct wfx_link_entry *entry; + + if (wvif->vif->type != NL80211_IFTYPE_AP || !sta_priv->link_id) + return 0; + + entry = &wvif->link_id_db[sta_priv->link_id - 1]; + spin_lock_bh(&wvif->ps_state_lock); + entry->status = WFX_LINK_RESERVE; + entry->timestamp = jiffies; + wfx_tx_lock(wdev); + if (!schedule_work(&wvif->link_id_work)) + wfx_tx_unlock(wdev); + spin_unlock_bh(&wvif->ps_state_lock); + flush_work(&wvif->link_id_work); + return 0; +} + +static void wfx_set_cts_work(struct work_struct *work) +{ + struct wfx_vif *wvif = container_of(work, struct wfx_vif, set_cts_work); + u8 erp_ie[3] = { WLAN_EID_ERP_INFO, 1, 0 }; + struct hif_ie_flags target_frame = { + .beacon = 1, + }; + + mutex_lock(&wvif->wdev->conf_mutex); + erp_ie[2] = wvif->erp_info; + mutex_unlock(&wvif->wdev->conf_mutex); + + hif_erp_use_protection(wvif, erp_ie[2] & WLAN_ERP_USE_PROTECTION); + + if (wvif->vif->type != NL80211_IFTYPE_STATION) + hif_update_ie(wvif, &target_frame, erp_ie, sizeof(erp_ie)); +} + +static int wfx_start_ap(struct wfx_vif *wvif) +{ + int ret; + struct ieee80211_bss_conf *conf = &wvif->vif->bss_conf; + struct hif_req_start start = { + .channel_number = wvif->channel->hw_value, + .beacon_interval = conf->beacon_int, + .dtim_period = conf->dtim_period, + .preamble_type = conf->use_short_preamble ? HIF_PREAMBLE_SHORT : HIF_PREAMBLE_LONG, + .basic_rate_set = wfx_rate_mask_to_hw(wvif->wdev, conf->basic_rates), + }; + + memset(start.ssid, 0, sizeof(start.ssid)); + if (!conf->hidden_ssid) { + start.ssid_length = conf->ssid_len; + memcpy(start.ssid, conf->ssid, start.ssid_length); + } + + wvif->beacon_int = conf->beacon_int; + wvif->dtim_period = conf->dtim_period; + + memset(&wvif->link_id_db, 0, sizeof(wvif->link_id_db)); + + wvif->wdev->tx_burst_idx = -1; + ret = hif_start(wvif, &start); + if (!ret) + ret = wfx_upload_keys(wvif); + if (!ret) { + if (wvif_count(wvif->wdev) <= 1) + hif_set_block_ack_policy(wvif, 0xFF, 0xFF); + wvif->state = WFX_STATE_AP; + wfx_update_filtering(wvif); + } + return ret; +} + +static int wfx_update_beaconing(struct wfx_vif *wvif) +{ + struct ieee80211_bss_conf *conf = &wvif->vif->bss_conf; + + if (wvif->vif->type == NL80211_IFTYPE_AP) { + /* TODO: check if changed channel, band */ + if (wvif->state != WFX_STATE_AP || + wvif->beacon_int != conf->beacon_int) { + wfx_tx_lock_flush(wvif->wdev); + if (wvif->state != WFX_STATE_PASSIVE) + hif_reset(wvif, false); + wvif->state = WFX_STATE_PASSIVE; + wfx_start_ap(wvif); + wfx_tx_unlock(wvif->wdev); + } else { + } + } + return 0; +} + +static int wfx_upload_beacon(struct wfx_vif *wvif) +{ + int ret = 0; + struct sk_buff *skb = NULL; + struct ieee80211_mgmt *mgmt; + struct hif_mib_template_frame *p; + + if (wvif->vif->type == NL80211_IFTYPE_STATION || + wvif->vif->type == NL80211_IFTYPE_MONITOR || + wvif->vif->type == NL80211_IFTYPE_UNSPECIFIED) + goto done; + + skb = ieee80211_beacon_get(wvif->wdev->hw, wvif->vif); + + if (!skb) + return -ENOMEM; + + p = (struct hif_mib_template_frame *) skb_push(skb, 4); + p->frame_type = HIF_TMPLT_BCN; + p->init_rate = API_RATE_INDEX_B_1MBPS; /* 1Mbps DSSS */ + p->frame_length = cpu_to_le16(skb->len - 4); + + ret = hif_set_template_frame(wvif, p); + + skb_pull(skb, 4); + + if (ret) + goto done; + /* TODO: Distill probe resp; remove TIM and any other beacon-specific + * IEs + */ + mgmt = (void *)skb->data; + mgmt->frame_control = + cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP); + + p->frame_type = HIF_TMPLT_PRBRES; + + ret = hif_set_template_frame(wvif, p); + wfx_fwd_probe_req(wvif, false); + +done: + dev_kfree_skb(skb); + return ret; +} + +static int wfx_is_ht(const struct wfx_ht_info *ht_info) +{ + return ht_info->channel_type != NL80211_CHAN_NO_HT; +} + +static int wfx_ht_greenfield(const struct wfx_ht_info *ht_info) +{ + return wfx_is_ht(ht_info) && + (ht_info->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) && + !(ht_info->operation_mode & + IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); +} + +static int wfx_ht_ampdu_density(const struct wfx_ht_info *ht_info) +{ + if (!wfx_is_ht(ht_info)) + return 0; + return ht_info->ht_cap.ampdu_density; +} + +static void wfx_join_finalize(struct wfx_vif *wvif, struct ieee80211_bss_conf *info) +{ + struct ieee80211_sta *sta = NULL; + struct hif_mib_set_association_mode association_mode = { }; + + if (info->dtim_period) + wvif->dtim_period = info->dtim_period; + wvif->beacon_int = info->beacon_int; + + rcu_read_lock(); + if (info->bssid && !info->ibss_joined) + sta = ieee80211_find_sta(wvif->vif, info->bssid); + if (sta) { + wvif->ht_info.ht_cap = sta->ht_cap; + wvif->bss_params.operational_rate_set = + wfx_rate_mask_to_hw(wvif->wdev, sta->supp_rates[wvif->channel->band]); + wvif->ht_info.operation_mode = info->ht_operation_mode; + } else { + memset(&wvif->ht_info, 0, sizeof(wvif->ht_info)); + wvif->bss_params.operational_rate_set = -1; + } + rcu_read_unlock(); + + /* Non Greenfield stations present */ + if (wvif->ht_info.operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT) + hif_dual_cts_protection(wvif, true); + else + hif_dual_cts_protection(wvif, false); + + association_mode.preambtype_use = 1; + association_mode.mode = 1; + association_mode.rateset = 1; + association_mode.spacing = 1; + association_mode.preamble_type = info->use_short_preamble ? HIF_PREAMBLE_SHORT : HIF_PREAMBLE_LONG; + association_mode.basic_rate_set = cpu_to_le32(wfx_rate_mask_to_hw(wvif->wdev, info->basic_rates)); + association_mode.mixed_or_greenfield_type = wfx_ht_greenfield(&wvif->ht_info); + association_mode.mpdu_start_spacing = wfx_ht_ampdu_density(&wvif->ht_info); + + wfx_cqm_bssloss_sm(wvif, 0, 0, 0); + cancel_work_sync(&wvif->unjoin_work); + + wvif->bss_params.beacon_lost_count = 20; + wvif->bss_params.aid = info->aid; + + if (wvif->dtim_period < 1) + wvif->dtim_period = 1; + + hif_set_association_mode(wvif, &association_mode); + + if (!info->ibss_joined) { + hif_keep_alive_period(wvif, 30 /* sec */); + hif_set_bss_params(wvif, &wvif->bss_params); + wvif->setbssparams_done = true; + wfx_set_beacon_wakeup_period_work(&wvif->set_beacon_wakeup_period_work); + wfx_set_pm(wvif, &wvif->powersave_mode); + } +} + +void wfx_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u32 changed) +{ + struct wfx_dev *wdev = hw->priv; + struct wfx_vif *wvif = (struct wfx_vif *) vif->drv_priv; + bool do_join = false; + int i; + int nb_arp_addr; + + mutex_lock(&wdev->conf_mutex); + + /* TODO: BSS_CHANGED_QOS */ + if (changed & BSS_CHANGED_ARP_FILTER) { + struct hif_mib_arp_ip_addr_table filter = { }; + + nb_arp_addr = info->arp_addr_cnt; + if (nb_arp_addr <= 0 || nb_arp_addr > HIF_MAX_ARP_IP_ADDRTABLE_ENTRIES) + nb_arp_addr = 0; + + for (i = 0; i < HIF_MAX_ARP_IP_ADDRTABLE_ENTRIES; i++) { + filter.condition_idx = i; + if (i < nb_arp_addr) { + // Caution: type of arp_addr_list[i] is __be32 + memcpy(filter.ipv4_address, &info->arp_addr_list[i], sizeof(filter.ipv4_address)); + filter.arp_enable = HIF_ARP_NS_FILTERING_ENABLE; + } else { + filter.arp_enable = HIF_ARP_NS_FILTERING_DISABLE; + } + hif_set_arp_ipv4_filter(wvif, &filter); + } + } + + if (changed & + (BSS_CHANGED_BEACON | BSS_CHANGED_AP_PROBE_RESP | + BSS_CHANGED_BSSID | BSS_CHANGED_SSID | BSS_CHANGED_IBSS)) { + wvif->beacon_int = info->beacon_int; + wfx_update_beaconing(wvif); + wfx_upload_beacon(wvif); + } + + if (changed & BSS_CHANGED_BEACON_ENABLED && wvif->state != WFX_STATE_IBSS) { + if (wvif->enable_beacon != info->enable_beacon) { + hif_beacon_transmit(wvif, info->enable_beacon); + wvif->enable_beacon = info->enable_beacon; + } + } + + /* assoc/disassoc, or maybe AID changed */ + if (changed & BSS_CHANGED_ASSOC) { + wfx_tx_lock_flush(wdev); + wvif->wep_default_key_id = -1; + wfx_tx_unlock(wdev); + } + + if (changed & BSS_CHANGED_ASSOC && !info->assoc && + (wvif->state == WFX_STATE_STA || wvif->state == WFX_STATE_IBSS)) { + /* Shedule unjoin work */ + wfx_tx_lock(wdev); + if (!schedule_work(&wvif->unjoin_work)) + wfx_tx_unlock(wdev); + } else { + if (changed & BSS_CHANGED_BEACON_INT) { + if (info->ibss_joined) + do_join = true; + else if (wvif->state == WFX_STATE_AP) + wfx_update_beaconing(wvif); + } + + if (changed & BSS_CHANGED_BSSID) + do_join = true; + + if (changed & + (BSS_CHANGED_ASSOC | BSS_CHANGED_BSSID | + BSS_CHANGED_IBSS | BSS_CHANGED_BASIC_RATES | BSS_CHANGED_HT)) { + if (info->assoc) { + if (wvif->state < WFX_STATE_PRE_STA) { + ieee80211_connection_loss(vif); + mutex_unlock(&wdev->conf_mutex); + return; + } else if (wvif->state == WFX_STATE_PRE_STA) { + wvif->state = WFX_STATE_STA; + } + } else { + do_join = true; + } + + if (info->assoc || info->ibss_joined) + wfx_join_finalize(wvif, info); + else + memset(&wvif->bss_params, 0, sizeof(wvif->bss_params)); + } + } + + /* ERP Protection */ + if (changed & (BSS_CHANGED_ASSOC | + BSS_CHANGED_ERP_CTS_PROT | + BSS_CHANGED_ERP_PREAMBLE)) { + u32 prev_erp_info = wvif->erp_info; + + if (info->use_cts_prot) + wvif->erp_info |= WLAN_ERP_USE_PROTECTION; + else if (!(prev_erp_info & WLAN_ERP_NON_ERP_PRESENT)) + wvif->erp_info &= ~WLAN_ERP_USE_PROTECTION; + + if (info->use_short_preamble) + wvif->erp_info |= WLAN_ERP_BARKER_PREAMBLE; + else + wvif->erp_info &= ~WLAN_ERP_BARKER_PREAMBLE; + + if (prev_erp_info != wvif->erp_info) + schedule_work(&wvif->set_cts_work); + } + + if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_ERP_SLOT)) + hif_slot_time(wvif, info->use_short_slot ? 9 : 20); + + if (changed & (BSS_CHANGED_ASSOC | BSS_CHANGED_CQM)) { + struct hif_mib_rcpi_rssi_threshold th = { + .rolling_average_count = 8, + .detection = 1, + }; + + wvif->cqm_rssi_thold = info->cqm_rssi_thold; + + if (!info->cqm_rssi_thold && !info->cqm_rssi_hyst) { + th.upperthresh = 1; + th.lowerthresh = 1; + } else { + /* FIXME It's not a correct way of setting threshold. + * Upper and lower must be set equal here and adjusted + * in callback. However current implementation is much + * more reliable and stable. + */ + /* RSSI: signed Q8.0, RCPI: unsigned Q7.1 + * RSSI = RCPI / 2 - 110 + */ + th.upper_threshold = info->cqm_rssi_thold + info->cqm_rssi_hyst; + th.upper_threshold = (th.upper_threshold + 110) * 2; + th.lower_threshold = info->cqm_rssi_thold; + th.lower_threshold = (th.lower_threshold + 110) * 2; + } + hif_set_rcpi_rssi_threshold(wvif, &th); + } + + if (changed & BSS_CHANGED_TXPOWER && info->txpower != wdev->output_power) { + wdev->output_power = info->txpower; + hif_set_output_power(wvif, wdev->output_power * 10); + } + mutex_unlock(&wdev->conf_mutex); + + if (do_join) { + wfx_tx_lock_flush(wdev); + wfx_do_join(wvif); /* Will unlock it for us */ + } +} + +static void wfx_ps_notify(struct wfx_vif *wvif, enum sta_notify_cmd notify_cmd, + int link_id) +{ + u32 bit, prev; + + spin_lock_bh(&wvif->ps_state_lock); + /* Zero link id means "for all link IDs" */ + if (link_id) { + bit = BIT(link_id); + } else if (notify_cmd != STA_NOTIFY_AWAKE) { + dev_warn(wvif->wdev->dev, "unsupported notify command\n"); + bit = 0; + } else { + bit = wvif->link_id_map; + } + prev = wvif->sta_asleep_mask & bit; + + switch (notify_cmd) { + case STA_NOTIFY_SLEEP: + if (!prev) { + if (wvif->mcast_buffered && !wvif->sta_asleep_mask) + schedule_work(&wvif->mcast_start_work); + wvif->sta_asleep_mask |= bit; + } + break; + case STA_NOTIFY_AWAKE: + if (prev) { + wvif->sta_asleep_mask &= ~bit; + wvif->pspoll_mask &= ~bit; + if (link_id && !wvif->sta_asleep_mask) + schedule_work(&wvif->mcast_stop_work); + wfx_bh_request_tx(wvif->wdev); + } + break; + } + spin_unlock_bh(&wvif->ps_state_lock); +} + +void wfx_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + enum sta_notify_cmd notify_cmd, struct ieee80211_sta *sta) +{ + struct wfx_vif *wvif = (struct wfx_vif *) vif->drv_priv; + struct wfx_sta_priv *sta_priv = (struct wfx_sta_priv *) &sta->drv_priv; + + wfx_ps_notify(wvif, notify_cmd, sta_priv->link_id); +} + +static int wfx_set_tim_impl(struct wfx_vif *wvif, bool aid0_bit_set) +{ + struct sk_buff *skb; + struct hif_ie_flags target_frame = { + .beacon = 1, + }; + u16 tim_offset, tim_length; + u8 *tim_ptr; + + skb = ieee80211_beacon_get_tim(wvif->wdev->hw, wvif->vif, + &tim_offset, &tim_length); + if (!skb) { + if (!__wfx_flush(wvif->wdev, true)) + wfx_tx_unlock(wvif->wdev); + return -ENOENT; + } + tim_ptr = skb->data + tim_offset; + + if (tim_offset && tim_length >= 6) { + /* Ignore DTIM count from mac80211: + * firmware handles DTIM internally. + */ + tim_ptr[2] = 0; + + /* Set/reset aid0 bit */ + if (aid0_bit_set) + tim_ptr[4] |= 1; + else + tim_ptr[4] &= ~1; + } + + hif_update_ie(wvif, &target_frame, tim_ptr, tim_length); + dev_kfree_skb(skb); + + return 0; +} + +static void wfx_set_tim_work(struct work_struct *work) +{ + struct wfx_vif *wvif = container_of(work, struct wfx_vif, set_tim_work); + + wfx_set_tim_impl(wvif, wvif->aid0_bit_set); +} + +int wfx_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) +{ + struct wfx_dev *wdev = hw->priv; + struct wfx_sta_priv *sta_dev = (struct wfx_sta_priv *) &sta->drv_priv; + struct wfx_vif *wvif = wdev_to_wvif(wdev, sta_dev->vif_id); + + schedule_work(&wvif->set_tim_work); + return 0; +} + +static void wfx_mcast_start_work(struct work_struct *work) +{ + struct wfx_vif *wvif = container_of(work, struct wfx_vif, mcast_start_work); + long tmo = wvif->dtim_period * TU_TO_JIFFIES(wvif->beacon_int + 20); + + cancel_work_sync(&wvif->mcast_stop_work); + if (!wvif->aid0_bit_set) { + wfx_tx_lock_flush(wvif->wdev); + wfx_set_tim_impl(wvif, true); + wvif->aid0_bit_set = true; + mod_timer(&wvif->mcast_timeout, jiffies + tmo); + wfx_tx_unlock(wvif->wdev); + } +} + +static void wfx_mcast_stop_work(struct work_struct *work) +{ + struct wfx_vif *wvif = container_of(work, struct wfx_vif, mcast_stop_work); + + if (wvif->aid0_bit_set) { + del_timer_sync(&wvif->mcast_timeout); + wfx_tx_lock_flush(wvif->wdev); + wvif->aid0_bit_set = false; + wfx_set_tim_impl(wvif, false); + wfx_tx_unlock(wvif->wdev); + } +} + +static void wfx_mcast_timeout(struct timer_list *t) +{ + struct wfx_vif *wvif = from_timer(wvif, t, mcast_timeout); + + dev_warn(wvif->wdev->dev, "multicast delivery timeout\n"); + spin_lock_bh(&wvif->ps_state_lock); + wvif->mcast_tx = wvif->aid0_bit_set && wvif->mcast_buffered; + if (wvif->mcast_tx) + wfx_bh_request_tx(wvif->wdev); + spin_unlock_bh(&wvif->ps_state_lock); +} + +int wfx_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_ampdu_params *params) +{ + /* Aggregation is implemented fully in firmware, + * including block ack negotiation. Do not allow + * mac80211 stack to do anything: it interferes with + * the firmware. + */ + + /* Note that we still need this function stubbed. */ + + return -ENOTSUPP; +} + +void wfx_suspend_resume(struct wfx_vif *wvif, + struct hif_ind_suspend_resume_tx *arg) +{ + if (arg->suspend_resume_flags.bc_mc_only) { + bool cancel_tmo = false; + + spin_lock_bh(&wvif->ps_state_lock); + if (!arg->suspend_resume_flags.resume) + wvif->mcast_tx = false; + else + wvif->mcast_tx = wvif->aid0_bit_set && wvif->mcast_buffered; + if (wvif->mcast_tx) { + cancel_tmo = true; + wfx_bh_request_tx(wvif->wdev); + } + spin_unlock_bh(&wvif->ps_state_lock); + if (cancel_tmo) + del_timer_sync(&wvif->mcast_timeout); + } else if (arg->suspend_resume_flags.resume) { + // FIXME: should change each station status independently + wfx_ps_notify(wvif, STA_NOTIFY_AWAKE, 0); + wfx_bh_request_tx(wvif->wdev); + } else { + // FIXME: should change each station status independently + wfx_ps_notify(wvif, STA_NOTIFY_SLEEP, 0); + } +} + +int wfx_add_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *conf) +{ + return 0; +} + +void wfx_remove_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *conf) +{ +} + +void wfx_change_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *conf, + u32 changed) +{ +} + +int wfx_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_chanctx_conf *conf) +{ + struct wfx_vif *wvif = (struct wfx_vif *) vif->drv_priv; + struct ieee80211_channel *ch = conf->def.chan; + + WARN(wvif->channel, "channel overwrite"); + wvif->channel = ch; + wvif->ht_info.channel_type = cfg80211_get_chandef_type(&conf->def); + + return 0; +} + +void wfx_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_chanctx_conf *conf) +{ + struct wfx_vif *wvif = (struct wfx_vif *) vif->drv_priv; + struct ieee80211_channel *ch = conf->def.chan; + + WARN(wvif->channel != ch, "channel mismatch"); + wvif->channel = NULL; +} + +int wfx_config(struct ieee80211_hw *hw, u32 changed) +{ + int ret = 0; + struct wfx_dev *wdev = hw->priv; + struct ieee80211_conf *conf = &hw->conf; + struct wfx_vif *wvif; + + // FIXME: Interface id should not been hardcoded + wvif = wdev_to_wvif(wdev, 0); + if (!wvif) { + WARN(1, "interface 0 does not exist anymore"); + return 0; + } + + down(&wvif->scan.lock); + mutex_lock(&wdev->conf_mutex); + if (changed & IEEE80211_CONF_CHANGE_POWER) { + wdev->output_power = conf->power_level; + hif_set_output_power(wvif, wdev->output_power * 10); + } + + if (changed & IEEE80211_CONF_CHANGE_PS) { + wvif = NULL; + while ((wvif = wvif_iterate(wdev, wvif)) != NULL) { + memset(&wvif->powersave_mode, 0, sizeof(wvif->powersave_mode)); + if (conf->flags & IEEE80211_CONF_PS) { + wvif->powersave_mode.pm_mode.enter_psm = 1; + if (conf->dynamic_ps_timeout > 0) { + wvif->powersave_mode.pm_mode.fast_psm = 1; + // Firmware does not support more than 128ms + wvif->powersave_mode.fast_psm_idle_period = + min(conf->dynamic_ps_timeout * 2, 255); + } + } + if (wvif->state == WFX_STATE_STA && wvif->bss_params.aid) + wfx_set_pm(wvif, &wvif->powersave_mode); + } + wvif = wdev_to_wvif(wdev, 0); + } + + mutex_unlock(&wdev->conf_mutex); + up(&wvif->scan.lock); + return ret; +} + +int wfx_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + int i; + struct wfx_dev *wdev = hw->priv; + struct wfx_vif *wvif = (struct wfx_vif *) vif->drv_priv; + // FIXME: parameters are set by kernel juste after interface_add. + // Keep struct hif_req_edca_queue_params blank? + struct hif_req_edca_queue_params default_edca_params[] = { + [IEEE80211_AC_VO] = { + .queue_id = HIF_QUEUE_ID_VOICE, + .aifsn = 2, + .cw_min = 3, + .cw_max = 7, + .tx_op_limit = TXOP_UNIT * 47, + }, + [IEEE80211_AC_VI] = { + .queue_id = HIF_QUEUE_ID_VIDEO, + .aifsn = 2, + .cw_min = 7, + .cw_max = 15, + .tx_op_limit = TXOP_UNIT * 94, + }, + [IEEE80211_AC_BE] = { + .queue_id = HIF_QUEUE_ID_BESTEFFORT, + .aifsn = 3, + .cw_min = 15, + .cw_max = 1023, + .tx_op_limit = TXOP_UNIT * 0, + }, + [IEEE80211_AC_BK] = { + .queue_id = HIF_QUEUE_ID_BACKGROUND, + .aifsn = 7, + .cw_min = 15, + .cw_max = 1023, + .tx_op_limit = TXOP_UNIT * 0, + }, + }; + + BUILD_BUG_ON(ARRAY_SIZE(default_edca_params) != ARRAY_SIZE(wvif->edca.params)); + if (wfx_api_older_than(wdev, 2, 0)) { + default_edca_params[IEEE80211_AC_BE].queue_id = HIF_QUEUE_ID_BACKGROUND; + default_edca_params[IEEE80211_AC_BK].queue_id = HIF_QUEUE_ID_BESTEFFORT; + } + + vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | + IEEE80211_VIF_SUPPORTS_UAPSD | + IEEE80211_VIF_SUPPORTS_CQM_RSSI; + + mutex_lock(&wdev->conf_mutex); + + switch (vif->type) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_AP: + break; + default: + mutex_unlock(&wdev->conf_mutex); + return -EOPNOTSUPP; + } + + for (i = 0; i < ARRAY_SIZE(wdev->vif); i++) { + if (!wdev->vif[i]) { + wdev->vif[i] = vif; + wvif->id = i; + break; + } + } + if (i == ARRAY_SIZE(wdev->vif)) { + mutex_unlock(&wdev->conf_mutex); + return -EOPNOTSUPP; + } + // FIXME: prefer use of container_of() to get vif + wvif->vif = vif; + wvif->wdev = wdev; + + INIT_WORK(&wvif->link_id_work, wfx_link_id_work); + INIT_DELAYED_WORK(&wvif->link_id_gc_work, wfx_link_id_gc_work); + + spin_lock_init(&wvif->ps_state_lock); + INIT_WORK(&wvif->set_tim_work, wfx_set_tim_work); + + INIT_WORK(&wvif->mcast_start_work, wfx_mcast_start_work); + INIT_WORK(&wvif->mcast_stop_work, wfx_mcast_stop_work); + timer_setup(&wvif->mcast_timeout, wfx_mcast_timeout, 0); + + wvif->setbssparams_done = false; + mutex_init(&wvif->bss_loss_lock); + INIT_DELAYED_WORK(&wvif->bss_loss_work, wfx_bss_loss_work); + + wvif->wep_default_key_id = -1; + INIT_WORK(&wvif->wep_key_work, wfx_wep_key_work); + + sema_init(&wvif->scan.lock, 1); + INIT_WORK(&wvif->scan.work, wfx_scan_work); + INIT_DELAYED_WORK(&wvif->scan.timeout, wfx_scan_timeout); + + spin_lock_init(&wvif->event_queue_lock); + INIT_LIST_HEAD(&wvif->event_queue); + INIT_WORK(&wvif->event_handler_work, wfx_event_handler_work); + + init_completion(&wvif->set_pm_mode_complete); + complete(&wvif->set_pm_mode_complete); + INIT_WORK(&wvif->set_beacon_wakeup_period_work, wfx_set_beacon_wakeup_period_work); + INIT_WORK(&wvif->update_filtering_work, wfx_update_filtering_work); + INIT_WORK(&wvif->bss_params_work, wfx_bss_params_work); + INIT_WORK(&wvif->set_cts_work, wfx_set_cts_work); + INIT_WORK(&wvif->unjoin_work, wfx_unjoin_work); + + mutex_unlock(&wdev->conf_mutex); + + hif_set_macaddr(wvif, vif->addr); + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + memcpy(&wvif->edca.params[i], &default_edca_params[i], sizeof(default_edca_params[i])); + wvif->edca.uapsd_enable[i] = false; + hif_set_edca_queue_params(wvif, &wvif->edca.params[i]); + } + wfx_set_uapsd_param(wvif, &wvif->edca); + + wfx_tx_policy_init(wvif); + wvif = NULL; + while ((wvif = wvif_iterate(wdev, wvif)) != NULL) { + // Combo mode does not support Block Acks. We can re-enable them + if (wvif_count(wdev) == 1) + hif_set_block_ack_policy(wvif, 0xFF, 0xFF); + else + hif_set_block_ack_policy(wvif, 0x00, 0x00); + // Combo force powersave mode. We can re-enable it now + wfx_set_pm(wvif, &wvif->powersave_mode); + } + return 0; +} + +void wfx_remove_interface(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct wfx_dev *wdev = hw->priv; + struct wfx_vif *wvif = (struct wfx_vif *) vif->drv_priv; + int i; + + // If scan is in progress, stop it + while (down_trylock(&wvif->scan.lock)) + schedule(); + up(&wvif->scan.lock); + wait_for_completion_timeout(&wvif->set_pm_mode_complete, msecs_to_jiffies(300)); + + mutex_lock(&wdev->conf_mutex); + switch (wvif->state) { + case WFX_STATE_PRE_STA: + case WFX_STATE_STA: + case WFX_STATE_IBSS: + wfx_tx_lock_flush(wdev); + if (!schedule_work(&wvif->unjoin_work)) + wfx_tx_unlock(wdev); + break; + case WFX_STATE_AP: + for (i = 0; wvif->link_id_map; ++i) { + if (wvif->link_id_map & BIT(i)) { + wfx_unmap_link(wvif, i); + wvif->link_id_map &= ~BIT(i); + } + } + memset(wvif->link_id_db, 0, sizeof(wvif->link_id_db)); + wvif->sta_asleep_mask = 0; + wvif->enable_beacon = false; + wvif->mcast_tx = false; + wvif->aid0_bit_set = false; + wvif->mcast_buffered = false; + wvif->pspoll_mask = 0; + /* reset.link_id = 0; */ + hif_reset(wvif, false); + break; + default: + break; + } + + wvif->state = WFX_STATE_PASSIVE; + wfx_tx_queues_wait_empty_vif(wvif); + wfx_tx_unlock(wdev); + + /* FIXME: In add to reset MAC address, try to reset interface */ + hif_set_macaddr(wvif, NULL); + + cancel_delayed_work_sync(&wvif->scan.timeout); + + wfx_cqm_bssloss_sm(wvif, 0, 0, 0); + cancel_work_sync(&wvif->unjoin_work); + cancel_delayed_work_sync(&wvif->link_id_gc_work); + del_timer_sync(&wvif->mcast_timeout); + wfx_free_event_queue(wvif); + + wdev->vif[wvif->id] = NULL; + wvif->vif = NULL; + + mutex_unlock(&wdev->conf_mutex); + wvif = NULL; + while ((wvif = wvif_iterate(wdev, wvif)) != NULL) { + // Combo mode does not support Block Acks. We can re-enable them + if (wvif_count(wdev) == 1) + hif_set_block_ack_policy(wvif, 0xFF, 0xFF); + else + hif_set_block_ack_policy(wvif, 0x00, 0x00); + // Combo force powersave mode. We can re-enable it now + wfx_set_pm(wvif, &wvif->powersave_mode); + } +} + +int wfx_start(struct ieee80211_hw *hw) +{ + return 0; +} + +void wfx_stop(struct ieee80211_hw *hw) +{ + struct wfx_dev *wdev = hw->priv; + + wfx_tx_lock_flush(wdev); + mutex_lock(&wdev->conf_mutex); + wfx_tx_queues_clear(wdev); + mutex_unlock(&wdev->conf_mutex); + wfx_tx_unlock(wdev); + WARN(atomic_read(&wdev->tx_lock), "tx_lock is locked"); +} diff --git a/drivers/staging/wfx/sta.h b/drivers/staging/wfx/sta.h new file mode 100644 index 000000000000..307ed0196110 --- /dev/null +++ b/drivers/staging/wfx/sta.h @@ -0,0 +1,101 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Implementation of mac80211 API. + * + * Copyright (c) 2017-2019, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#ifndef WFX_STA_H +#define WFX_STA_H + +#include <net/mac80211.h> + +#include "hif_api_cmd.h" + +struct wfx_dev; +struct wfx_vif; + +enum wfx_state { + WFX_STATE_PASSIVE = 0, + WFX_STATE_PRE_STA, + WFX_STATE_STA, + WFX_STATE_IBSS, + WFX_STATE_AP, +}; + +struct wfx_ht_info { + struct ieee80211_sta_ht_cap ht_cap; + enum nl80211_channel_type channel_type; + uint16_t operation_mode; +}; + +struct wfx_hif_event { + struct list_head link; + struct hif_ind_event evt; +}; + +struct wfx_edca_params { + /* NOTE: index is a linux queue id. */ + struct hif_req_edca_queue_params params[IEEE80211_NUM_ACS]; + bool uapsd_enable[IEEE80211_NUM_ACS]; +}; + +struct wfx_grp_addr_table { + bool enable; + int num_addresses; + u8 address_list[8][ETH_ALEN]; +}; + +struct wfx_sta_priv { + int link_id; + int vif_id; +}; + +// mac80211 interface +int wfx_start(struct ieee80211_hw *hw); +void wfx_stop(struct ieee80211_hw *hw); +int wfx_config(struct ieee80211_hw *hw, u32 changed); +int wfx_set_rts_threshold(struct ieee80211_hw *hw, u32 value); +u64 wfx_prepare_multicast(struct ieee80211_hw *hw, + struct netdev_hw_addr_list *mc_list); +void wfx_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, + unsigned int *total_flags, u64 unused); + +int wfx_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); +void wfx_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); +void wfx_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop); +int wfx_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u16 queue, const struct ieee80211_tx_queue_params *params); +void wfx_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, u32 changed); +int wfx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); +int wfx_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); +void wfx_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + enum sta_notify_cmd cmd, struct ieee80211_sta *sta); +int wfx_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set); +int wfx_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_ampdu_params *params); +int wfx_add_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *conf); +void wfx_remove_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *conf); +void wfx_change_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *conf, u32 changed); +int wfx_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_chanctx_conf *conf); +void wfx_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_chanctx_conf *conf); + +// WSM Callbacks +void wfx_suspend_resume(struct wfx_vif *wvif, struct hif_ind_suspend_resume_tx *arg); + +// Other Helpers +void wfx_cqm_bssloss_sm(struct wfx_vif *wvif, int init, int good, int bad); +void wfx_update_filtering(struct wfx_vif *wvif); +int wfx_set_pm(struct wfx_vif *wvif, const struct hif_req_set_pm_mode *arg); +int wfx_fwd_probe_req(struct wfx_vif *wvif, bool enable); + +#endif /* WFX_STA_H */ diff --git a/drivers/staging/wfx/traces.h b/drivers/staging/wfx/traces.h new file mode 100644 index 000000000000..67457cda133b --- /dev/null +++ b/drivers/staging/wfx/traces.h @@ -0,0 +1,434 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Tracepoints definitions. + * + * Copyright (c) 2018-2019, Silicon Laboratories, Inc. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM wfx + +#if !defined(_WFX_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define _WFX_TRACE_H + +#include <linux/tracepoint.h> +#include <net/mac80211.h> + +#include "bus.h" +#include "hif_api_cmd.h" +#include "hif_api_mib.h" + +/* The hell below need some explanations. For each symbolic number, we need to + * define it with TRACE_DEFINE_ENUM() and in a list for __print_symbolic. + * + * 1. Define a new macro that call TRACE_DEFINE_ENUM(): + * + * #define xxx_name(sym) TRACE_DEFINE_ENUM(sym); + * + * 2. Define list of all symbols: + * + * #define list_names \ + * ... \ + * xxx_name(XXX) \ + * ... + * + * 3. Instanciate that list_names: + * + * list_names + * + * 4. Redefine xxx_name() as a entry of array for __print_symbolic() + * + * #undef xxx_name + * #define xxx_name(msg) { msg, #msg }, + * + * 5. list_name can now nearlu be used with __print_symbolic() but, + * __print_symbolic() dislike last comma of list. So we define a new list + * with a dummy element: + * + * #define list_for_print_symbolic list_names { -1, NULL } + */ + +#define _hif_msg_list \ + hif_cnf_name(ADD_KEY) \ + hif_cnf_name(BEACON_TRANSMIT) \ + hif_cnf_name(EDCA_QUEUE_PARAMS) \ + hif_cnf_name(JOIN) \ + hif_cnf_name(MAP_LINK) \ + hif_cnf_name(READ_MIB) \ + hif_cnf_name(REMOVE_KEY) \ + hif_cnf_name(RESET) \ + hif_cnf_name(SET_BSS_PARAMS) \ + hif_cnf_name(SET_PM_MODE) \ + hif_cnf_name(START) \ + hif_cnf_name(START_SCAN) \ + hif_cnf_name(STOP_SCAN) \ + hif_cnf_name(TX) \ + hif_cnf_name(MULTI_TRANSMIT) \ + hif_cnf_name(UPDATE_IE) \ + hif_cnf_name(WRITE_MIB) \ + hif_cnf_name(CONFIGURATION) \ + hif_cnf_name(CONTROL_GPIO) \ + hif_cnf_name(PREVENT_ROLLBACK) \ + hif_cnf_name(SET_SL_MAC_KEY) \ + hif_cnf_name(SL_CONFIGURE) \ + hif_cnf_name(SL_EXCHANGE_PUB_KEYS) \ + hif_cnf_name(SHUT_DOWN) \ + hif_ind_name(EVENT) \ + hif_ind_name(JOIN_COMPLETE) \ + hif_ind_name(RX) \ + hif_ind_name(SCAN_CMPL) \ + hif_ind_name(SET_PM_MODE_CMPL) \ + hif_ind_name(SUSPEND_RESUME_TX) \ + hif_ind_name(SL_EXCHANGE_PUB_KEYS) \ + hif_ind_name(ERROR) \ + hif_ind_name(EXCEPTION) \ + hif_ind_name(GENERIC) \ + hif_ind_name(WAKEUP) \ + hif_ind_name(STARTUP) + +#define hif_msg_list_enum _hif_msg_list + +#undef hif_cnf_name +#undef hif_ind_name +#define hif_cnf_name(msg) TRACE_DEFINE_ENUM(HIF_CNF_ID_##msg); +#define hif_ind_name(msg) TRACE_DEFINE_ENUM(HIF_IND_ID_##msg); +hif_msg_list_enum +#undef hif_cnf_name +#undef hif_ind_name +#define hif_cnf_name(msg) { HIF_CNF_ID_##msg, #msg }, +#define hif_ind_name(msg) { HIF_IND_ID_##msg, #msg }, +#define hif_msg_list hif_msg_list_enum { -1, NULL } + +#define _hif_mib_list \ + hif_mib_name(ARP_IP_ADDRESSES_TABLE) \ + hif_mib_name(ARP_KEEP_ALIVE_PERIOD) \ + hif_mib_name(BEACON_FILTER_ENABLE) \ + hif_mib_name(BEACON_FILTER_TABLE) \ + hif_mib_name(BEACON_WAKEUP_PERIOD) \ + hif_mib_name(BLOCK_ACK_POLICY) \ + hif_mib_name(CONFIG_DATA_FILTER) \ + hif_mib_name(COUNTERS_TABLE) \ + hif_mib_name(CURRENT_TX_POWER_LEVEL) \ + hif_mib_name(DOT11_MAC_ADDRESS) \ + hif_mib_name(DOT11_MAX_RECEIVE_LIFETIME) \ + hif_mib_name(DOT11_MAX_TRANSMIT_MSDU_LIFETIME) \ + hif_mib_name(DOT11_RTS_THRESHOLD) \ + hif_mib_name(DOT11_WEP_DEFAULT_KEY_ID) \ + hif_mib_name(GL_BLOCK_ACK_INFO) \ + hif_mib_name(GL_OPERATIONAL_POWER_MODE) \ + hif_mib_name(GL_SET_MULTI_MSG) \ + hif_mib_name(INACTIVITY_TIMER) \ + hif_mib_name(INTERFACE_PROTECTION) \ + hif_mib_name(IPV4_ADDR_DATAFRAME_CONDITION) \ + hif_mib_name(IPV6_ADDR_DATAFRAME_CONDITION) \ + hif_mib_name(KEEP_ALIVE_PERIOD) \ + hif_mib_name(MAC_ADDR_DATAFRAME_CONDITION) \ + hif_mib_name(NON_ERP_PROTECTION) \ + hif_mib_name(NS_IP_ADDRESSES_TABLE) \ + hif_mib_name(OVERRIDE_INTERNAL_TX_RATE) \ + hif_mib_name(PROTECTED_MGMT_POLICY) \ + hif_mib_name(RX_FILTER) \ + hif_mib_name(RCPI_RSSI_THRESHOLD) \ + hif_mib_name(SET_ASSOCIATION_MODE) \ + hif_mib_name(SET_DATA_FILTERING) \ + hif_mib_name(ETHERTYPE_DATAFRAME_CONDITION) \ + hif_mib_name(SET_HT_PROTECTION) \ + hif_mib_name(MAGIC_DATAFRAME_CONDITION) \ + hif_mib_name(SET_TX_RATE_RETRY_POLICY) \ + hif_mib_name(SET_UAPSD_INFORMATION) \ + hif_mib_name(PORT_DATAFRAME_CONDITION) \ + hif_mib_name(SLOT_TIME) \ + hif_mib_name(STATISTICS_TABLE) \ + hif_mib_name(TEMPLATE_FRAME) \ + hif_mib_name(TSF_COUNTER) \ + hif_mib_name(UC_MC_BC_DATAFRAME_CONDITION) + +#define hif_mib_list_enum _hif_mib_list + +#undef hif_mib_name +#define hif_mib_name(mib) TRACE_DEFINE_ENUM(HIF_MIB_ID_##mib); +hif_mib_list_enum +#undef hif_mib_name +#define hif_mib_name(mib) { HIF_MIB_ID_##mib, #mib }, +#define hif_mib_list hif_mib_list_enum { -1, NULL } + +DECLARE_EVENT_CLASS(hif_data, + TP_PROTO(struct hif_msg *hif, int tx_fill_level, bool is_recv), + TP_ARGS(hif, tx_fill_level, is_recv), + TP_STRUCT__entry( + __field(int, tx_fill_level) + __field(int, msg_id) + __field(const char *, msg_type) + __field(int, msg_len) + __field(int, buf_len) + __field(int, if_id) + __field(int, mib) + __array(u8, buf, 128) + ), + TP_fast_assign( + int header_len; + + __entry->tx_fill_level = tx_fill_level; + __entry->msg_len = hif->len; + __entry->msg_id = hif->id; + __entry->if_id = hif->interface; + if (is_recv) + __entry->msg_type = __entry->msg_id & 0x80 ? "IND" : "CNF"; + else + __entry->msg_type = "REQ"; + if (!is_recv && + (__entry->msg_id == HIF_REQ_ID_READ_MIB || __entry->msg_id == HIF_REQ_ID_WRITE_MIB)) { + __entry->mib = le16_to_cpup((u16 *) hif->body); + header_len = 4; + } else { + __entry->mib = -1; + header_len = 0; + } + __entry->buf_len = min_t(int, __entry->msg_len, sizeof(__entry->buf)) + - sizeof(struct hif_msg) - header_len; + memcpy(__entry->buf, hif->body + header_len, __entry->buf_len); + ), + TP_printk("%d:%d:%s_%s%s%s: %s%s (%d bytes)", + __entry->tx_fill_level, + __entry->if_id, + __print_symbolic(__entry->msg_id, hif_msg_list), + __entry->msg_type, + __entry->mib != -1 ? "/" : "", + __entry->mib != -1 ? __print_symbolic(__entry->mib, hif_mib_list) : "", + __print_hex(__entry->buf, __entry->buf_len), + __entry->msg_len > sizeof(__entry->buf) ? " ..." : "", + __entry->msg_len + ) +); +DEFINE_EVENT(hif_data, hif_send, + TP_PROTO(struct hif_msg *hif, int tx_fill_level, bool is_recv), + TP_ARGS(hif, tx_fill_level, is_recv)); +#define _trace_hif_send(hif, tx_fill_level) trace_hif_send(hif, tx_fill_level, false) +DEFINE_EVENT(hif_data, hif_recv, + TP_PROTO(struct hif_msg *hif, int tx_fill_level, bool is_recv), + TP_ARGS(hif, tx_fill_level, is_recv)); +#define _trace_hif_recv(hif, tx_fill_level) trace_hif_recv(hif, tx_fill_level, true) + +#define wfx_reg_list_enum \ + wfx_reg_name(WFX_REG_CONFIG, "CONFIG") \ + wfx_reg_name(WFX_REG_CONTROL, "CONTROL") \ + wfx_reg_name(WFX_REG_IN_OUT_QUEUE, "QUEUE") \ + wfx_reg_name(WFX_REG_AHB_DPORT, "AHB") \ + wfx_reg_name(WFX_REG_BASE_ADDR, "BASE_ADDR") \ + wfx_reg_name(WFX_REG_SRAM_DPORT, "SRAM") \ + wfx_reg_name(WFX_REG_SET_GEN_R_W, "SET_GEN_R_W") \ + wfx_reg_name(WFX_REG_FRAME_OUT, "FRAME_OUT") + +#undef wfx_reg_name +#define wfx_reg_name(sym, name) TRACE_DEFINE_ENUM(sym); +wfx_reg_list_enum +#undef wfx_reg_name +#define wfx_reg_name(sym, name) { sym, name }, +#define wfx_reg_list wfx_reg_list_enum { -1, NULL } + +DECLARE_EVENT_CLASS(io_data, + TP_PROTO(int reg, int addr, const void *io_buf, size_t len), + TP_ARGS(reg, addr, io_buf, len), + TP_STRUCT__entry( + __field(int, reg) + __field(int, addr) + __field(int, msg_len) + __field(int, buf_len) + __array(u8, buf, 32) + __array(u8, addr_str, 10) + ), + TP_fast_assign( + __entry->reg = reg; + __entry->addr = addr; + __entry->msg_len = len; + __entry->buf_len = min_t(int, sizeof(__entry->buf), __entry->msg_len); + memcpy(__entry->buf, io_buf, __entry->buf_len); + if (addr >= 0) + snprintf(__entry->addr_str, 10, "/%08x", addr); + else + __entry->addr_str[0] = 0; + ), + TP_printk("%s%s: %s%s (%d bytes)", + __print_symbolic(__entry->reg, wfx_reg_list), + __entry->addr_str, + __print_hex(__entry->buf, __entry->buf_len), + __entry->msg_len > sizeof(__entry->buf) ? " ..." : "", + __entry->msg_len + ) +); +DEFINE_EVENT(io_data, io_write, + TP_PROTO(int reg, int addr, const void *io_buf, size_t len), + TP_ARGS(reg, addr, io_buf, len)); +#define _trace_io_ind_write(reg, addr, io_buf, len) trace_io_write(reg, addr, io_buf, len) +#define _trace_io_write(reg, io_buf, len) trace_io_write(reg, -1, io_buf, len) +DEFINE_EVENT(io_data, io_read, + TP_PROTO(int reg, int addr, const void *io_buf, size_t len), + TP_ARGS(reg, addr, io_buf, len)); +#define _trace_io_ind_read(reg, addr, io_buf, len) trace_io_read(reg, addr, io_buf, len) +#define _trace_io_read(reg, io_buf, len) trace_io_read(reg, -1, io_buf, len) + +DECLARE_EVENT_CLASS(io_data32, + TP_PROTO(int reg, int addr, u32 val), + TP_ARGS(reg, addr, val), + TP_STRUCT__entry( + __field(int, reg) + __field(int, addr) + __field(int, val) + __array(u8, addr_str, 10) + ), + TP_fast_assign( + __entry->reg = reg; + __entry->addr = addr; + __entry->val = val; + if (addr >= 0) + snprintf(__entry->addr_str, 10, "/%08x", addr); + else + __entry->addr_str[0] = 0; + ), + TP_printk("%s%s: %08x", + __print_symbolic(__entry->reg, wfx_reg_list), + __entry->addr_str, + __entry->val + ) +); +DEFINE_EVENT(io_data32, io_write32, + TP_PROTO(int reg, int addr, u32 val), + TP_ARGS(reg, addr, val)); +#define _trace_io_ind_write32(reg, addr, val) trace_io_write32(reg, addr, val) +#define _trace_io_write32(reg, val) trace_io_write32(reg, -1, val) +DEFINE_EVENT(io_data32, io_read32, + TP_PROTO(int reg, int addr, u32 val), + TP_ARGS(reg, addr, val)); +#define _trace_io_ind_read32(reg, addr, val) trace_io_read32(reg, addr, val) +#define _trace_io_read32(reg, val) trace_io_read32(reg, -1, val) + +DECLARE_EVENT_CLASS(piggyback, + TP_PROTO(u32 val, bool ignored), + TP_ARGS(val, ignored), + TP_STRUCT__entry( + __field(int, val) + __field(bool, ignored) + ), + TP_fast_assign( + __entry->val = val; + __entry->ignored = ignored; + ), + TP_printk("CONTROL: %08x%s", + __entry->val, + __entry->ignored ? " (ignored)" : "" + ) +); +DEFINE_EVENT(piggyback, piggyback, + TP_PROTO(u32 val, bool ignored), + TP_ARGS(val, ignored)); +#define _trace_piggyback(val, ignored) trace_piggyback(val, ignored) + +TRACE_EVENT(bh_stats, + TP_PROTO(int ind, int req, int cnf, int busy, bool release), + TP_ARGS(ind, req, cnf, busy, release), + TP_STRUCT__entry( + __field(int, ind) + __field(int, req) + __field(int, cnf) + __field(int, busy) + __field(bool, release) + ), + TP_fast_assign( + __entry->ind = ind; + __entry->req = req; + __entry->cnf = cnf; + __entry->busy = busy; + __entry->release = release; + ), + TP_printk("IND/REQ/CNF:%3d/%3d/%3d, REQ in progress:%3d, WUP: %s", + __entry->ind, + __entry->req, + __entry->cnf, + __entry->busy, + __entry->release ? "release" : "keep" + ) +); +#define _trace_bh_stats(ind, req, cnf, busy, release) trace_bh_stats(ind, req, cnf, busy, release) + +TRACE_EVENT(tx_stats, + TP_PROTO(struct hif_cnf_tx *tx_cnf, struct sk_buff *skb, int delay), + TP_ARGS(tx_cnf, skb, delay), + TP_STRUCT__entry( + __field(int, pkt_id) + __field(int, delay_media) + __field(int, delay_queue) + __field(int, delay_fw) + __field(int, ack_failures) + __field(int, flags) + __array(int, rate, 4) + __array(int, tx_count, 4) + ), + TP_fast_assign( + // Keep sync with wfx_rates definition in main.c + static const int hw_rate[] = { 0, 1, 2, 3, 6, 7, 8, 9, 10, 11, 12, 13 }; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_tx_rate *rates = tx_info->driver_rates; + int i; + + __entry->pkt_id = tx_cnf->packet_id; + __entry->delay_media = tx_cnf->media_delay; + __entry->delay_queue = tx_cnf->tx_queue_delay; + __entry->delay_fw = delay; + __entry->ack_failures = tx_cnf->ack_failures; + if (!tx_cnf->status || __entry->ack_failures) + __entry->ack_failures += 1; + + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + if (rates[0].flags & IEEE80211_TX_RC_MCS) + __entry->rate[i] = rates[i].idx; + else + __entry->rate[i] = hw_rate[rates[i].idx]; + __entry->tx_count[i] = rates[i].count; + } + __entry->flags = 0; + if (rates[0].flags & IEEE80211_TX_RC_MCS) + __entry->flags |= 0x01; + if (rates[0].flags & IEEE80211_TX_RC_SHORT_GI) + __entry->flags |= 0x02; + if (rates[0].flags & IEEE80211_TX_RC_GREEN_FIELD) + __entry->flags |= 0x04; + if (rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) + __entry->flags |= 0x08; + if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) + __entry->flags |= 0x10; + if (tx_cnf->status) + __entry->flags |= 0x20; + if (tx_cnf->status == HIF_REQUEUE) + __entry->flags |= 0x40; + ), + TP_printk("packet ID: %08x, rate policy: %s %d|%d %d|%d %d|%d %d|%d -> %d attempt, Delays media/queue/total: %4dus/%4dus/%4dus", + __entry->pkt_id, + __print_flags(__entry->flags, NULL, + { 0x01, "M" }, { 0x02, "S" }, { 0x04, "G" }, + { 0x08, "R" }, { 0x10, "D" }, { 0x20, "F" }, + { 0x40, "Q" }), + __entry->rate[0], + __entry->tx_count[0], + __entry->rate[1], + __entry->tx_count[1], + __entry->rate[2], + __entry->tx_count[2], + __entry->rate[3], + __entry->tx_count[3], + __entry->ack_failures, + __entry->delay_media, + __entry->delay_queue, + __entry->delay_fw + ) +); +#define _trace_tx_stats(tx_cnf, skb, delay) trace_tx_stats(tx_cnf, skb, delay) + +#endif + +/* This part must be outside protection */ +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE traces + +#include <trace/define_trace.h> diff --git a/drivers/staging/wfx/wfx.h b/drivers/staging/wfx/wfx.h new file mode 100644 index 000000000000..d678b5a08873 --- /dev/null +++ b/drivers/staging/wfx/wfx.h @@ -0,0 +1,206 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Common private data for Silicon Labs WFx chips. + * + * Copyright (c) 2017-2019, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net> + * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al. + */ +#ifndef WFX_H +#define WFX_H + +#include <linux/completion.h> +#include <linux/workqueue.h> +#include <linux/mutex.h> +#include <linux/nospec.h> +#include <net/mac80211.h> + +#include "bh.h" +#include "data_tx.h" +#include "main.h" +#include "queue.h" +#include "secure_link.h" +#include "sta.h" +#include "scan.h" +#include "hif_tx.h" +#include "hif_api_general.h" + +struct hwbus_ops; + +struct wfx_dev { + struct wfx_platform_data pdata; + struct device *dev; + struct ieee80211_hw *hw; + struct ieee80211_vif *vif[2]; + struct mac_address addresses[2]; + const struct hwbus_ops *hwbus_ops; + void *hwbus_priv; + + u8 keyset; + struct completion firmware_ready; + struct hif_ind_startup hw_caps; + struct wfx_hif hif; + struct sl_context sl; + int chip_frozen; + struct mutex conf_mutex; + + struct wfx_hif_cmd hif_cmd; + struct wfx_queue tx_queue[4]; + struct wfx_queue_stats tx_queue_stats; + int tx_burst_idx; + atomic_t tx_lock; + + u32 key_map; + struct hif_req_add_key keys[MAX_KEY_ENTRIES]; + + struct hif_rx_stats rx_stats; + struct mutex rx_stats_lock; + + int output_power; + atomic_t scan_in_progress; +}; + +struct wfx_vif { + struct wfx_dev *wdev; + struct ieee80211_vif *vif; + struct ieee80211_channel *channel; + int id; + enum wfx_state state; + + int delayed_link_loss; + int bss_loss_state; + u32 bss_loss_confirm_id; + struct mutex bss_loss_lock; + struct delayed_work bss_loss_work; + + u32 link_id_map; + struct wfx_link_entry link_id_db[WFX_MAX_STA_IN_AP_MODE]; + struct delayed_work link_id_gc_work; + struct work_struct link_id_work; + + bool aid0_bit_set; + bool mcast_tx; + bool mcast_buffered; + struct wfx_grp_addr_table mcast_filter; + struct timer_list mcast_timeout; + struct work_struct mcast_start_work; + struct work_struct mcast_stop_work; + + s8 wep_default_key_id; + struct sk_buff *wep_pending_skb; + struct work_struct wep_key_work; + + struct tx_policy_cache tx_policy_cache; + struct work_struct tx_policy_upload_work; + + u32 sta_asleep_mask; + u32 pspoll_mask; + spinlock_t ps_state_lock; + struct work_struct set_tim_work; + + int dtim_period; + int beacon_int; + bool enable_beacon; + struct work_struct set_beacon_wakeup_period_work; + + bool filter_bssid; + bool fwd_probe_req; + bool disable_beacon_filter; + struct work_struct update_filtering_work; + + u32 erp_info; + int cqm_rssi_thold; + bool setbssparams_done; + struct wfx_ht_info ht_info; + struct wfx_edca_params edca; + struct hif_mib_set_uapsd_information uapsd_info; + struct hif_req_set_bss_params bss_params; + struct work_struct bss_params_work; + struct work_struct set_cts_work; + + int join_complete_status; + bool delayed_unjoin; + struct work_struct unjoin_work; + + struct wfx_scan scan; + + struct hif_req_set_pm_mode powersave_mode; + struct completion set_pm_mode_complete; + + struct list_head event_queue; + spinlock_t event_queue_lock; + struct work_struct event_handler_work; +}; + +static inline struct wfx_vif *wdev_to_wvif(struct wfx_dev *wdev, int vif_id) +{ + if (vif_id >= ARRAY_SIZE(wdev->vif)) { + dev_dbg(wdev->dev, "requesting non-existent vif: %d\n", vif_id); + return NULL; + } + vif_id = array_index_nospec(vif_id, ARRAY_SIZE(wdev->vif)); + if (!wdev->vif[vif_id]) { + dev_dbg(wdev->dev, "requesting non-allocated vif: %d\n", vif_id); + return NULL; + } + return (struct wfx_vif *) wdev->vif[vif_id]->drv_priv; +} + +static inline struct wfx_vif *wvif_iterate(struct wfx_dev *wdev, struct wfx_vif *cur) +{ + int i; + int mark = 0; + struct wfx_vif *tmp; + + if (!cur) + mark = 1; + for (i = 0; i < ARRAY_SIZE(wdev->vif); i++) { + tmp = wdev_to_wvif(wdev, i); + if (mark && tmp) + return tmp; + if (tmp == cur) + mark = 1; + } + return NULL; +} + +static inline int wvif_count(struct wfx_dev *wdev) +{ + int i; + int ret = 0; + struct wfx_vif *wvif; + + for (i = 0; i < ARRAY_SIZE(wdev->vif); i++) { + wvif = wdev_to_wvif(wdev, i); + if (wvif) + ret++; + } + return ret; +} + +static inline void memreverse(uint8_t *src, uint8_t length) +{ + uint8_t *lo = src; + uint8_t *hi = src + length - 1; + uint8_t swap; + + while (lo < hi) { + swap = *lo; + *lo++ = *hi; + *hi-- = swap; + } +} + +static inline int memzcmp(void *src, unsigned int size) +{ + uint8_t *buf = src; + + if (!size) + return 0; + if (*buf) + return 1; + return memcmp(buf, buf + 1, size - 1); +} + +#endif /* WFX_H */ diff --git a/drivers/staging/wilc1000/Makefile b/drivers/staging/wilc1000/Makefile index a5a8e806b98e..a3305a0a888a 100644 --- a/drivers/staging/wilc1000/Makefile +++ b/drivers/staging/wilc1000/Makefile @@ -4,11 +4,11 @@ obj-$(CONFIG_WILC1000) += wilc1000.o ccflags-y += -DFIRMWARE_1002=\"atmel/wilc1002_firmware.bin\" \ -DFIRMWARE_1003=\"atmel/wilc1003_firmware.bin\" -wilc1000-objs := wilc_wfi_cfgoperations.o wilc_netdev.o wilc_mon.o \ - wilc_hif.o wilc_wlan_cfg.o wilc_wlan.o +wilc1000-objs := cfg80211.o netdev.o mon.o \ + hif.o wlan_cfg.o wlan.o obj-$(CONFIG_WILC1000_SDIO) += wilc1000-sdio.o -wilc1000-sdio-objs += wilc_sdio.o +wilc1000-sdio-objs += sdio.o obj-$(CONFIG_WILC1000_SPI) += wilc1000-spi.o -wilc1000-spi-objs += wilc_spi.o +wilc1000-spi-objs += spi.o diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c b/drivers/staging/wilc1000/cfg80211.c index 22f21831649b..4863e516ff13 100644 --- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.c +++ b/drivers/staging/wilc1000/cfg80211.c @@ -4,7 +4,7 @@ * All rights reserved. */ -#include "wilc_wfi_cfgoperations.h" +#include "cfg80211.h" #define FRAME_TYPE_ID 0 #define ACTION_CAT_ID 24 @@ -137,6 +137,7 @@ static void cfg_connect_result(enum conn_event conn_disconn_evt, u8 mac_status, struct wilc *wl = vif->wilc; struct host_if_drv *wfi_drv = priv->hif_drv; struct wilc_conn_info *conn_info = &wfi_drv->conn_info; + struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; vif->connecting = false; @@ -158,12 +159,16 @@ static void cfg_connect_result(enum conn_event conn_disconn_evt, u8 mac_status, memcpy(priv->associated_bss, conn_info->bssid, ETH_ALEN); - cfg80211_connect_result(dev, conn_info->bssid, - conn_info->req_ies, - conn_info->req_ies_len, - conn_info->resp_ies, - conn_info->resp_ies_len, connect_status, - GFP_KERNEL); + cfg80211_ref_bss(wiphy, vif->bss); + cfg80211_connect_bss(dev, conn_info->bssid, vif->bss, + conn_info->req_ies, + conn_info->req_ies_len, + conn_info->resp_ies, + conn_info->resp_ies_len, + connect_status, GFP_KERNEL, + NL80211_TIMEOUT_UNSPECIFIED); + + vif->bss = NULL; } else if (conn_disconn_evt == CONN_DISCONN_EVENT_DISCONN_NOTIF) { u16 reason = 0; @@ -186,15 +191,15 @@ static void cfg_connect_result(enum conn_event conn_disconn_evt, u8 mac_status, } } -static struct wilc_vif *wilc_get_wl_to_vif(struct wilc *wl) +struct wilc_vif *wilc_get_wl_to_vif(struct wilc *wl) { - int i; + struct wilc_vif *vif; - for (i = 0; i < wl->vif_num; i++) - if (wl->vif[i]) - return wl->vif[i]; + vif = list_first_or_null_rcu(&wl->vif_list, typeof(*vif), list); + if (!vif) + return ERR_PTR(-EINVAL); - return ERR_PTR(-EINVAL); + return vif; } static int set_channel(struct wiphy *wiphy, @@ -204,11 +209,12 @@ static int set_channel(struct wiphy *wiphy, struct wilc_vif *vif; u32 channelnum; int result; + int srcu_idx; - mutex_lock(&wl->vif_mutex); + srcu_idx = srcu_read_lock(&wl->srcu); vif = wilc_get_wl_to_vif(wl); if (IS_ERR(vif)) { - mutex_unlock(&wl->vif_mutex); + srcu_read_unlock(&wl->srcu, srcu_idx); return PTR_ERR(vif); } @@ -219,7 +225,7 @@ static int set_channel(struct wiphy *wiphy, if (result) netdev_err(vif->ndev, "Error in setting channel\n"); - mutex_unlock(&wl->vif_mutex); + srcu_read_unlock(&wl->srcu, srcu_idx); return result; } @@ -405,6 +411,7 @@ static int connect(struct wiphy *wiphy, struct net_device *dev, goto out_put_bss; } kfree(join_params); + vif->bss = bss; cfg80211_put_bss(wiphy, bss); return 0; @@ -450,6 +457,8 @@ static int disconnect(struct wiphy *wiphy, struct net_device *dev, ret = -EINVAL; } + vif->bss = NULL; + return ret; } @@ -620,29 +629,26 @@ static int del_key(struct wiphy *wiphy, struct net_device *netdev, bool pairwise, const u8 *mac_addr) { - struct wilc *wl = wiphy_priv(wiphy); struct wilc_vif *vif = netdev_priv(netdev); struct wilc_priv *priv = &vif->priv; - if (netdev == wl->vif[0]->ndev) { - if (priv->wilc_gtk[key_index]) { - kfree(priv->wilc_gtk[key_index]->key); - priv->wilc_gtk[key_index]->key = NULL; - kfree(priv->wilc_gtk[key_index]->seq); - priv->wilc_gtk[key_index]->seq = NULL; + if (priv->wilc_gtk[key_index]) { + kfree(priv->wilc_gtk[key_index]->key); + priv->wilc_gtk[key_index]->key = NULL; + kfree(priv->wilc_gtk[key_index]->seq); + priv->wilc_gtk[key_index]->seq = NULL; - kfree(priv->wilc_gtk[key_index]); - priv->wilc_gtk[key_index] = NULL; - } + kfree(priv->wilc_gtk[key_index]); + priv->wilc_gtk[key_index] = NULL; + } - if (priv->wilc_ptk[key_index]) { - kfree(priv->wilc_ptk[key_index]->key); - priv->wilc_ptk[key_index]->key = NULL; - kfree(priv->wilc_ptk[key_index]->seq); - priv->wilc_ptk[key_index]->seq = NULL; - kfree(priv->wilc_ptk[key_index]); - priv->wilc_ptk[key_index] = NULL; - } + if (priv->wilc_ptk[key_index]) { + kfree(priv->wilc_ptk[key_index]->key); + priv->wilc_ptk[key_index]->key = NULL; + kfree(priv->wilc_ptk[key_index]->seq); + priv->wilc_ptk[key_index]->seq = NULL; + kfree(priv->wilc_ptk[key_index]); + priv->wilc_ptk[key_index] = NULL; } if (key_index <= 3 && priv->wep_key_len[key_index]) { @@ -752,33 +758,19 @@ static int change_bss(struct wiphy *wiphy, struct net_device *dev, return 0; } -struct wilc_vif *wilc_get_interface(struct wilc *wl) -{ - int i; - struct wilc_vif *vif = NULL; - - mutex_lock(&wl->vif_mutex); - for (i = 0; i < wl->vif_num; i++) { - if (wl->vif[i]) { - vif = wl->vif[i]; - break; - } - } - mutex_unlock(&wl->vif_mutex); - return vif; -} - static int set_wiphy_params(struct wiphy *wiphy, u32 changed) { - int ret; + int ret = -EINVAL; struct cfg_param_attr cfg_param_val; struct wilc *wl = wiphy_priv(wiphy); struct wilc_vif *vif; struct wilc_priv *priv; + int srcu_idx; - vif = wilc_get_interface(wl); - if (!vif) - return -EINVAL; + srcu_idx = srcu_read_lock(&wl->srcu); + vif = wilc_get_wl_to_vif(wl); + if (IS_ERR(vif)) + goto out; priv = &vif->priv; cfg_param_val.flag = 0; @@ -808,7 +800,7 @@ static int set_wiphy_params(struct wiphy *wiphy, u32 changed) } else { netdev_err(vif->ndev, "Fragmentation threshold out of range\n"); - return -EINVAL; + goto out; } } @@ -821,7 +813,7 @@ static int set_wiphy_params(struct wiphy *wiphy, u32 changed) cfg_param_val.rts_threshold = wiphy->rts_threshold; } else { netdev_err(vif->ndev, "RTS threshold out of range\n"); - return -EINVAL; + goto out; } } @@ -829,6 +821,8 @@ static int set_wiphy_params(struct wiphy *wiphy, u32 changed) if (ret) netdev_err(priv->dev, "Error in setting WIPHY PARAMS\n"); +out: + srcu_read_unlock(&wl->srcu, srcu_idx); return ret; } @@ -1144,7 +1138,7 @@ static int remain_on_channel(struct wiphy *wiphy, cfg80211_ready_on_channel(wdev, *cookie, chan, duration, GFP_KERNEL); mod_timer(&vif->hif_drv->remain_on_ch_timer, - jiffies + msecs_to_jiffies(duration)); + jiffies + msecs_to_jiffies(duration + 1000)); return ret; } @@ -1419,8 +1413,10 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev, if (vif->iftype == WILC_AP_MODE || vif->iftype == WILC_GO_MODE) wilc_wfi_deinit_mon_interface(wl, true); vif->iftype = WILC_STATION_MODE; - wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), - WILC_STATION_MODE, vif->idx); + + if (wl->initialized) + wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), + WILC_STATION_MODE, vif->idx); memset(priv->assoc_stainfo.sta_associated_bss, 0, WILC_MAX_NUM_STA * ETH_ALEN); @@ -1432,8 +1428,10 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev, priv->wdev.iftype = type; vif->monitor_flag = 0; vif->iftype = WILC_CLIENT_MODE; - wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), - WILC_STATION_MODE, vif->idx); + + if (wl->initialized) + wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), + WILC_STATION_MODE, vif->idx); break; case NL80211_IFTYPE_AP: @@ -1450,8 +1448,10 @@ static int change_virtual_intf(struct wiphy *wiphy, struct net_device *dev, dev->ieee80211_ptr->iftype = type; priv->wdev.iftype = type; vif->iftype = WILC_GO_MODE; - wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), - WILC_AP_MODE, vif->idx); + + if (wl->initialized) + wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), + WILC_AP_MODE, vif->idx); break; default: @@ -1557,20 +1557,16 @@ static int change_station(struct wiphy *wiphy, struct net_device *dev, return ret; } -static int wilc_get_vif_from_type(struct wilc *wl, int type) +static struct wilc_vif *wilc_get_vif_from_type(struct wilc *wl, int type) { - int i; + struct wilc_vif *vif; - mutex_lock(&wl->vif_mutex); - for (i = 0; i < wl->vif_num; i++) { - if (wl->vif[i]->iftype == type) { - mutex_unlock(&wl->vif_mutex); - return i; - } + list_for_each_entry_rcu(vif, &wl->vif_list, list) { + if (vif->iftype == type) + return vif; } - mutex_unlock(&wl->vif_mutex); - return -EINVAL; + return NULL; } static struct wireless_dev *add_virtual_intf(struct wiphy *wiphy, @@ -1583,29 +1579,36 @@ static struct wireless_dev *add_virtual_intf(struct wiphy *wiphy, struct wilc_vif *vif; struct wireless_dev *wdev; int iftype; - int ret; if (type == NL80211_IFTYPE_MONITOR) { struct net_device *ndev; - int ap_index = wilc_get_vif_from_type(wl, WILC_AP_MODE); - - if (ap_index < 0) { - ap_index = wilc_get_vif_from_type(wl, WILC_GO_MODE); - if (ap_index < 0) + int srcu_idx; + + srcu_idx = srcu_read_lock(&wl->srcu); + vif = wilc_get_vif_from_type(wl, WILC_AP_MODE); + if (!vif) { + vif = wilc_get_vif_from_type(wl, WILC_GO_MODE); + if (!vif) { + srcu_read_unlock(&wl->srcu, srcu_idx); goto validate_interface; + } } - vif = wl->vif[ap_index]; - if (vif->monitor_flag) + if (vif->monitor_flag) { + srcu_read_unlock(&wl->srcu, srcu_idx); goto validate_interface; + } ndev = wilc_wfi_init_mon_interface(wl, name, vif->ndev); - if (ndev) + if (ndev) { vif->monitor_flag = 1; - else + } else { + srcu_read_unlock(&wl->srcu, srcu_idx); return ERR_PTR(-EINVAL); + } wdev = &vif->priv.wdev; + srcu_read_unlock(&wl->srcu, srcu_idx); return wdev; } @@ -1613,9 +1616,10 @@ validate_interface: mutex_lock(&wl->vif_mutex); if (wl->vif_num == WILC_NUM_CONCURRENT_IFC) { pr_err("Reached maximum number of interface\n"); - ret = -EINVAL; - goto out_err; + mutex_unlock(&wl->vif_mutex); + return ERR_PTR(-EINVAL); } + mutex_unlock(&wl->vif_mutex); switch (type) { case NL80211_IFTYPE_STATION: @@ -1625,30 +1629,20 @@ validate_interface: iftype = WILC_AP_MODE; break; default: - ret = -EOPNOTSUPP; - goto out_err; + return ERR_PTR(-EOPNOTSUPP); } vif = wilc_netdev_ifc_init(wl, name, iftype, type, true); - if (IS_ERR(vif)) { - ret = PTR_ERR(vif); - goto out_err; - } - - mutex_unlock(&wl->vif_mutex); + if (IS_ERR(vif)) + return ERR_CAST(vif); return &vif->priv.wdev; - -out_err: - mutex_unlock(&wl->vif_mutex); - return ERR_PTR(ret); } static int del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) { struct wilc *wl = wiphy_priv(wiphy); struct wilc_vif *vif; - int i; if (wdev->iftype == NL80211_IFTYPE_AP || wdev->iftype == NL80211_IFTYPE_P2P_GO) @@ -1658,22 +1652,12 @@ static int del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) unregister_netdevice(vif->ndev); vif->monitor_flag = 0; - mutex_lock(&wl->vif_mutex); wilc_set_operation_mode(vif, 0, 0, 0); - for (i = vif->idx; i < wl->vif_num; i++) { - if ((i + 1) >= wl->vif_num) { - wl->vif[i] = NULL; - } else { - vif = wl->vif[i + 1]; - vif->idx = i; - wl->vif[i] = vif; - wilc_set_operation_mode(vif, wilc_get_vif_idx(vif), - vif->iftype, vif->idx); - } - } + mutex_lock(&wl->vif_mutex); + list_del_rcu(&vif->list); wl->vif_num--; mutex_unlock(&wl->vif_mutex); - + synchronize_srcu(&wl->srcu); return 0; } @@ -1698,25 +1682,39 @@ static void wilc_set_wakeup(struct wiphy *wiphy, bool enabled) { struct wilc *wl = wiphy_priv(wiphy); struct wilc_vif *vif; + int srcu_idx; - mutex_lock(&wl->vif_mutex); + srcu_idx = srcu_read_lock(&wl->srcu); vif = wilc_get_wl_to_vif(wl); if (IS_ERR(vif)) { - mutex_unlock(&wl->vif_mutex); + srcu_read_unlock(&wl->srcu, srcu_idx); return; } netdev_info(vif->ndev, "cfg set wake up = %d\n", enabled); - mutex_unlock(&wl->vif_mutex); + srcu_read_unlock(&wl->srcu, srcu_idx); } static int set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, enum nl80211_tx_power_setting type, int mbm) { int ret; + int srcu_idx; s32 tx_power = MBM_TO_DBM(mbm); - struct wilc_vif *vif = netdev_priv(wdev->netdev); + struct wilc *wl = wiphy_priv(wiphy); + struct wilc_vif *vif; + + if (!wl->initialized) + return -EIO; + srcu_idx = srcu_read_lock(&wl->srcu); + vif = wilc_get_wl_to_vif(wl); + if (IS_ERR(vif)) { + srcu_read_unlock(&wl->srcu, srcu_idx); + return -EINVAL; + } + + netdev_info(vif->ndev, "Setting tx power %d\n", tx_power); if (tx_power < 0) tx_power = 0; else if (tx_power > 18) @@ -1724,6 +1722,7 @@ static int set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, ret = wilc_set_tx_power(vif, tx_power); if (ret) netdev_err(vif->ndev, "Failed to set tx power\n"); + srcu_read_unlock(&wl->srcu, srcu_idx); return ret; } @@ -1803,6 +1802,17 @@ static void wlan_init_locks(struct wilc *wl) init_completion(&wl->cfg_event); init_completion(&wl->sync_event); init_completion(&wl->txq_thread_started); + init_srcu_struct(&wl->srcu); +} + +void wlan_deinit_locks(struct wilc *wilc) +{ + mutex_destroy(&wilc->hif_cs); + mutex_destroy(&wilc->rxq_cs); + mutex_destroy(&wilc->cfg_cmd_lock); + mutex_destroy(&wilc->txq_add_to_head_cs); + mutex_destroy(&wilc->vif_mutex); + cleanup_srcu_struct(&wilc->srcu); } int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type, @@ -1816,6 +1826,8 @@ int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type, if (!wl) return -EINVAL; + wlan_init_locks(wl); + ret = wilc_wlan_cfg_init(wl); if (ret) goto free_wl; @@ -1826,6 +1838,7 @@ int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type, wl->chip_ps_state = WILC_CHIP_WAKEDUP; INIT_LIST_HEAD(&wl->txq_head.list); INIT_LIST_HEAD(&wl->rxq_head.list); + INIT_LIST_HEAD(&wl->vif_list); wl->hif_workqueue = create_singlethread_workqueue("WILC_wq"); if (!wl->hif_workqueue) { @@ -1839,8 +1852,6 @@ int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type, goto free_hq; } - wlan_init_locks(wl); - return 0; free_hq: @@ -1850,6 +1861,7 @@ free_cfg: wilc_wlan_cfg_deinit(wl); free_wl: + wlan_deinit_locks(wl); wiphy_unregister(wl->wiphy); wiphy_free(wl->wiphy); return ret; diff --git a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.h b/drivers/staging/wilc1000/cfg80211.h index 234faaabdb82..5e5d63f70df2 100644 --- a/drivers/staging/wilc1000/wilc_wfi_cfgoperations.h +++ b/drivers/staging/wilc1000/cfg80211.h @@ -4,9 +4,9 @@ * All rights reserved. */ -#ifndef NM_WFI_CFGOPERATIONS -#define NM_WFI_CFGOPERATIONS -#include "wilc_wfi_netdevice.h" +#ifndef WILC_CFG80211_H +#define WILC_CFG80211_H +#include "netdev.h" struct wiphy *wilc_cfg_alloc(void); int wilc_cfg80211_init(struct wilc **wilc, struct device *dev, int io_type, @@ -24,4 +24,6 @@ struct net_device *wilc_wfi_init_mon_interface(struct wilc *wl, void wilc_mgmt_frame_register(struct wiphy *wiphy, struct wireless_dev *wdev, u16 frame_type, bool reg); struct wilc_vif *wilc_get_interface(struct wilc *wl); +struct wilc_vif *wilc_get_wl_to_vif(struct wilc *wl); +void wlan_deinit_locks(struct wilc *wilc); #endif diff --git a/drivers/staging/wilc1000/wilc_hif.c b/drivers/staging/wilc1000/hif.c index f2b7d5a1be17..5f6706bcedf6 100644 --- a/drivers/staging/wilc1000/wilc_hif.c +++ b/drivers/staging/wilc1000/hif.c @@ -4,7 +4,7 @@ * All rights reserved. */ -#include "wilc_wfi_netdevice.h" +#include "netdev.h" #define WILC_HIF_SCAN_TIMEOUT_MS 5000 #define WILC_HIF_CONNECT_TIMEOUT_MS 9500 @@ -32,7 +32,7 @@ struct wilc_op_mode { }; struct wilc_reg_frame { - bool reg; + u8 reg; u8 reg_id; __le16 frame_type; } __packed; @@ -183,11 +183,17 @@ int wilc_get_vif_idx(struct wilc_vif *vif) static struct wilc_vif *wilc_get_vif_from_idx(struct wilc *wilc, int idx) { int index = idx - 1; + struct wilc_vif *vif; if (index < 0 || index >= WILC_NUM_CONCURRENT_IFC) return NULL; - return wilc->vif[index]; + list_for_each_entry_rcu(vif, &wilc->vif_list, list) { + if (vif->idx == index) + return vif; + } + + return NULL; } static int handle_scan_done(struct wilc_vif *vif, enum scan_event evt) @@ -473,6 +479,8 @@ void *wilc_parse_join_bss_param(struct cfg80211_bss *bss, rates_ie = cfg80211_find_ie(WLAN_EID_SUPP_RATES, ies->data, ies->len); if (rates_ie) { rates_len = rates_ie[1]; + if (rates_len > WILC_MAX_RATES_SUPPORTED) + rates_len = WILC_MAX_RATES_SUPPORTED; param->supp_rates[0] = rates_len; memcpy(¶m->supp_rates[1], rates_ie + 2, rates_len); } @@ -544,7 +552,7 @@ void *wilc_parse_join_bss_param(struct cfg80211_bss *bss, param->mode_802_11i = 2; param->rsn_found = true; - //extract RSN capabilities + /* extract RSN capabilities */ offset += (rsn_ie[offset] * 4) + 2; offset += (rsn_ie[offset] * 4) + 2; memcpy(param->rsn_cap, &rsn_ie[offset], 2); @@ -1776,7 +1784,9 @@ void wilc_frame_register(struct wilc_vif *vif, u16 frame_type, bool reg) wid.val = (u8 *)®_frame; memset(®_frame, 0x0, sizeof(reg_frame)); - reg_frame.reg = reg; + + if (reg) + reg_frame.reg = 1; switch (frame_type) { case IEEE80211_STYPE_ACTION: diff --git a/drivers/staging/wilc1000/wilc_hif.h b/drivers/staging/wilc1000/hif.h index ac5fe57f872b..22ee6fffd599 100644 --- a/drivers/staging/wilc1000/wilc_hif.h +++ b/drivers/staging/wilc1000/hif.h @@ -4,10 +4,10 @@ * All rights reserved. */ -#ifndef HOST_INT_H -#define HOST_INT_H +#ifndef WILC_HIF_H +#define WILC_HIF_H #include <linux/ieee80211.h> -#include "wilc_wlan_if.h" +#include "wlan_if.h" enum { WILC_IDLE_MODE = 0x0, diff --git a/drivers/staging/wilc1000/wilc_mon.c b/drivers/staging/wilc1000/mon.c index d6f14f69ad64..48ac33f06f63 100644 --- a/drivers/staging/wilc1000/wilc_mon.c +++ b/drivers/staging/wilc1000/mon.c @@ -4,7 +4,7 @@ * All rights reserved. */ -#include "wilc_wfi_cfgoperations.h" +#include "cfg80211.h" struct wilc_wfi_radiotap_hdr { struct ieee80211_radiotap_header hdr; @@ -220,7 +220,7 @@ struct net_device *wilc_wfi_init_mon_interface(struct wilc *wl, { struct wilc_wfi_mon_priv *priv; - /*If monitor interface is already initialized, return it*/ + /* If monitor interface is already initialized, return it */ if (wl->monitor_dev) return wl->monitor_dev; diff --git a/drivers/staging/wilc1000/wilc_netdev.c b/drivers/staging/wilc1000/netdev.c index 508acb8bb089..d2c0b0f7cf63 100644 --- a/drivers/staging/wilc1000/wilc_netdev.c +++ b/drivers/staging/wilc1000/netdev.c @@ -10,8 +10,8 @@ #include <linux/netdevice.h> #include <linux/inetdevice.h> -#include "wilc_wfi_cfgoperations.h" -#include "wilc_wlan_cfg.h" +#include "cfg80211.h" +#include "wlan_cfg.h" #define WILC_MULTICAST_TABLE_SIZE 8 @@ -97,29 +97,25 @@ void wilc_mac_indicate(struct wilc *wilc) static struct net_device *get_if_handler(struct wilc *wilc, u8 *mac_header) { u8 *bssid, *bssid1; - int i = 0; struct net_device *ndev = NULL; + struct wilc_vif *vif; bssid = mac_header + 10; bssid1 = mac_header + 4; - mutex_lock(&wilc->vif_mutex); - for (i = 0; i < wilc->vif_num; i++) { - if (wilc->vif[i]->mode == WILC_STATION_MODE) - if (ether_addr_equal_unaligned(bssid, - wilc->vif[i]->bssid)) { - ndev = wilc->vif[i]->ndev; + list_for_each_entry_rcu(vif, &wilc->vif_list, list) { + if (vif->mode == WILC_STATION_MODE) + if (ether_addr_equal_unaligned(bssid, vif->bssid)) { + ndev = vif->ndev; goto out; } - if (wilc->vif[i]->mode == WILC_AP_MODE) - if (ether_addr_equal_unaligned(bssid1, - wilc->vif[i]->bssid)) { - ndev = wilc->vif[i]->ndev; + if (vif->mode == WILC_AP_MODE) + if (ether_addr_equal_unaligned(bssid1, vif->bssid)) { + ndev = vif->ndev; goto out; } } out: - mutex_unlock(&wilc->vif_mutex); return ndev; } @@ -137,13 +133,16 @@ void wilc_wlan_set_bssid(struct net_device *wilc_netdev, u8 *bssid, u8 mode) int wilc_wlan_get_num_conn_ifcs(struct wilc *wilc) { - u8 i = 0; + int srcu_idx; u8 ret_val = 0; + struct wilc_vif *vif; - for (i = 0; i < wilc->vif_num; i++) - if (!is_zero_ether_addr(wilc->vif[i]->bssid)) + srcu_idx = srcu_read_lock(&wilc->srcu); + list_for_each_entry_rcu(vif, &wilc->vif_list, list) { + if (!is_zero_ether_addr(vif->bssid)) ret_val++; - + } + srcu_read_unlock(&wilc->srcu, srcu_idx); return ret_val; } @@ -167,16 +166,16 @@ static int wilc_txq_task(void *vp) do { ret = wilc_wlan_handle_txq(wl, &txq_count); if (txq_count < FLOW_CONTROL_LOWER_THRESHOLD) { - int i; + int srcu_idx; struct wilc_vif *ifc; - mutex_lock(&wl->vif_mutex); - for (i = 0; i < wl->vif_num; i++) { - ifc = wl->vif[i]; + srcu_idx = srcu_read_lock(&wl->srcu); + list_for_each_entry_rcu(ifc, &wl->vif_list, + list) { if (ifc->mac_opened && ifc->ndev) netif_wake_queue(ifc->ndev); } - mutex_unlock(&wl->vif_mutex); + srcu_read_unlock(&wl->srcu, srcu_idx); } } while (ret == -ENOBUFS && !wl->close); } @@ -424,18 +423,6 @@ fail: return -1; } -static void wlan_deinit_locks(struct net_device *dev) -{ - struct wilc_vif *vif = netdev_priv(dev); - struct wilc *wilc = vif->wilc; - - mutex_destroy(&wilc->hif_cs); - mutex_destroy(&wilc->rxq_cs); - mutex_destroy(&wilc->cfg_cmd_lock); - mutex_destroy(&wilc->txq_add_to_head_cs); - mutex_destroy(&wilc->vif_mutex); -} - static void wlan_deinitialize_threads(struct net_device *dev) { struct wilc_vif *vif = netdev_priv(dev); @@ -477,7 +464,6 @@ static void wilc_wlan_deinitialize(struct net_device *dev) wilc_wlan_stop(wl, vif); wilc_wlan_cleanup(dev); - wlan_deinit_locks(dev); wl->initialized = false; @@ -738,14 +724,15 @@ netdev_tx_t wilc_mac_xmit(struct sk_buff *skb, struct net_device *ndev) wilc_tx_complete); if (queue_count > FLOW_CONTROL_UPPER_THRESHOLD) { - int i; + int srcu_idx; + struct wilc_vif *vif; - mutex_lock(&wilc->vif_mutex); - for (i = 0; i < wilc->vif_num; i++) { - if (wilc->vif[i]->mac_opened) - netif_stop_queue(wilc->vif[i]->ndev); + srcu_idx = srcu_read_lock(&wilc->srcu); + list_for_each_entry_rcu(vif, &wilc->vif_list, list) { + if (vif->mac_opened) + netif_stop_queue(vif->ndev); } - mutex_unlock(&wilc->vif_mutex); + srcu_read_unlock(&wilc->srcu, srcu_idx); } return 0; @@ -823,26 +810,22 @@ void wilc_frmw_to_host(struct wilc *wilc, u8 *buff, u32 size, void wilc_wfi_mgmt_rx(struct wilc *wilc, u8 *buff, u32 size) { - int i = 0; + int srcu_idx; struct wilc_vif *vif; - mutex_lock(&wilc->vif_mutex); - for (i = 0; i < wilc->vif_num; i++) { + srcu_idx = srcu_read_lock(&wilc->srcu); + list_for_each_entry_rcu(vif, &wilc->vif_list, list) { u16 type = le16_to_cpup((__le16 *)buff); - vif = netdev_priv(wilc->vif[i]->ndev); - if ((type == vif->frame_reg[0].type && vif->frame_reg[0].reg) || - (type == vif->frame_reg[1].type && vif->frame_reg[1].reg)) { + if (vif->priv.p2p_listen_state && + ((type == vif->frame_reg[0].type && vif->frame_reg[0].reg) || + (type == vif->frame_reg[1].type && vif->frame_reg[1].reg))) wilc_wfi_p2p_rx(vif, buff, size); - break; - } - if (vif->monitor_flag) { + if (vif->monitor_flag) wilc_wfi_monitor_rx(wilc->monitor_dev, buff, size); - break; - } } - mutex_unlock(&wilc->vif_mutex); + srcu_read_unlock(&wilc->srcu, srcu_idx); } static const struct net_device_ops wilc_netdev_ops = { @@ -856,7 +839,8 @@ static const struct net_device_ops wilc_netdev_ops = { void wilc_netdev_cleanup(struct wilc *wilc) { - int i; + struct wilc_vif *vif; + int srcu_idx; if (!wilc) return; @@ -866,21 +850,57 @@ void wilc_netdev_cleanup(struct wilc *wilc) wilc->firmware = NULL; } - for (i = 0; i < wilc->vif_num; i++) { - if (wilc->vif[i] && wilc->vif[i]->ndev) - unregister_netdev(wilc->vif[i]->ndev); + srcu_idx = srcu_read_lock(&wilc->srcu); + list_for_each_entry_rcu(vif, &wilc->vif_list, list) { + if (vif->ndev) + unregister_netdev(vif->ndev); } + srcu_read_unlock(&wilc->srcu, srcu_idx); wilc_wfi_deinit_mon_interface(wilc, false); flush_workqueue(wilc->hif_workqueue); destroy_workqueue(wilc->hif_workqueue); + + do { + mutex_lock(&wilc->vif_mutex); + if (wilc->vif_num <= 0) { + mutex_unlock(&wilc->vif_mutex); + break; + } + vif = wilc_get_wl_to_vif(wilc); + if (!IS_ERR(vif)) + list_del_rcu(&vif->list); + + wilc->vif_num--; + mutex_unlock(&wilc->vif_mutex); + synchronize_srcu(&wilc->srcu); + } while (1); + wilc_wlan_cfg_deinit(wilc); + wlan_deinit_locks(wilc); kfree(wilc->bus_data); wiphy_unregister(wilc->wiphy); wiphy_free(wilc->wiphy); } EXPORT_SYMBOL_GPL(wilc_netdev_cleanup); +static u8 wilc_get_available_idx(struct wilc *wl) +{ + int idx = 0; + struct wilc_vif *vif; + int srcu_idx; + + srcu_idx = srcu_read_lock(&wl->srcu); + list_for_each_entry_rcu(vif, &wl->vif_list, list) { + if (vif->idx == 0) + idx = 1; + else + idx = 0; + } + srcu_read_unlock(&wl->srcu, srcu_idx); + return idx; +} + struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name, int vif_type, enum nl80211_iftype type, bool rtnl_locked) @@ -921,10 +941,14 @@ struct wilc_vif *wilc_netdev_ifc_init(struct wilc *wl, const char *name, ndev->needs_free_netdev = true; vif->iftype = vif_type; - vif->wilc->vif[wl->vif_num] = vif; - vif->idx = wl->vif_num; - wl->vif_num += 1; + vif->idx = wilc_get_available_idx(wl); vif->mac_opened = 0; + mutex_lock(&wl->vif_mutex); + list_add_tail_rcu(&vif->list, &wl->vif_list); + wl->vif_num += 1; + mutex_unlock(&wl->vif_mutex); + synchronize_srcu(&wl->srcu); + return vif; } diff --git a/drivers/staging/wilc1000/wilc_wfi_netdevice.h b/drivers/staging/wilc1000/netdev.h index 978a8bdbfc40..cd8f0d72caaa 100644 --- a/drivers/staging/wilc1000/wilc_wfi_netdevice.h +++ b/drivers/staging/wilc1000/netdev.h @@ -4,8 +4,8 @@ * All rights reserved. */ -#ifndef WILC_WFI_NETDEVICE -#define WILC_WFI_NETDEVICE +#ifndef WILC_NETDEV_H +#define WILC_NETDEV_H #include <linux/tcp.h> #include <linux/ieee80211.h> @@ -14,9 +14,9 @@ #include <linux/if_arp.h> #include <linux/gpio/consumer.h> -#include "wilc_hif.h" -#include "wilc_wlan.h" -#include "wilc_wlan_cfg.h" +#include "hif.h" +#include "wlan.h" +#include "wlan_cfg.h" #define FLOW_CONTROL_LOWER_THRESHOLD 128 #define FLOW_CONTROL_UPPER_THRESHOLD 256 @@ -60,7 +60,7 @@ struct sta_info { u8 sta_associated_bss[WILC_MAX_NUM_STA][ETH_ALEN]; }; -/*Parameters needed for host interface for remaining on channel*/ +/* Parameters needed for host interface for remaining on channel */ struct wilc_wfi_p2p_listen_params { struct ieee80211_channel *listen_ch; u32 listen_duration; @@ -145,11 +145,13 @@ struct wilc_priv { struct wilc_pmkid_attr pmkid_list; u8 wep_key[4][WLAN_KEY_LEN_WEP104]; u8 wep_key_len[4]; + /* The real interface that the monitor is on */ struct net_device *real_ndev; struct wilc_wfi_key *wilc_gtk[WILC_MAX_NUM_STA]; struct wilc_wfi_key *wilc_ptk[WILC_MAX_NUM_STA]; u8 wilc_groupkey; + /* mutexes */ struct mutex scan_req_lock; bool p2p_listen_state; @@ -208,6 +210,8 @@ struct wilc_vif { struct tcp_ack_filter ack_filter; bool connecting; struct wilc_priv priv; + struct list_head list; + struct cfg80211_bss *bss; }; struct wilc { @@ -221,16 +225,22 @@ struct wilc { int dev_irq_num; int close; u8 vif_num; - struct wilc_vif *vif[WILC_NUM_CONCURRENT_IFC]; - /*protect vif list*/ + struct list_head vif_list; + + /* protect vif list */ struct mutex vif_mutex; + struct srcu_struct srcu; u8 open_ifcs; - /*protect head of transmit queue*/ + + /* protect head of transmit queue */ struct mutex txq_add_to_head_cs; - /*protect txq_entry_t transmit queue*/ + + /* protect txq_entry_t transmit queue */ spinlock_t txq_spinlock; - /*protect rxq_entry_t receiver queue*/ + + /* protect rxq_entry_t receiver queue */ struct mutex rxq_cs; + /* lock to protect hif access */ struct mutex hif_cs; @@ -242,6 +252,7 @@ struct wilc { struct task_struct *txq_thread; int quit; + /* lock to protect issue of wid command to firmware */ struct mutex cfg_cmd_lock; struct wilc_cfg_frame cfg_frame; @@ -268,6 +279,7 @@ struct wilc { struct wilc_cfg cfg; void *bus_data; struct net_device *monitor_dev; + /* deinit lock */ struct mutex deinit_lock; u8 sta_ch; diff --git a/drivers/staging/wilc1000/wilc_sdio.c b/drivers/staging/wilc1000/sdio.c index c787c5da8f2b..319e039380b0 100644 --- a/drivers/staging/wilc1000/wilc_sdio.c +++ b/drivers/staging/wilc1000/sdio.c @@ -8,8 +8,8 @@ #include <linux/mmc/sdio_func.h> #include <linux/mmc/host.h> -#include "wilc_wfi_netdevice.h" -#include "wilc_wfi_cfgoperations.h" +#include "netdev.h" +#include "cfg80211.h" #define SDIO_MODALIAS "wilc1000_sdio" diff --git a/drivers/staging/wilc1000/wilc_spi.c b/drivers/staging/wilc1000/spi.c index 3c1ae9e9f9aa..55f8757325f0 100644 --- a/drivers/staging/wilc1000/wilc_spi.c +++ b/drivers/staging/wilc1000/spi.c @@ -4,10 +4,11 @@ * All rights reserved. */ +#include <linux/clk.h> #include <linux/spi/spi.h> -#include "wilc_wfi_netdevice.h" -#include "wilc_wfi_cfgoperations.h" +#include "netdev.h" +#include "cfg80211.h" struct wilc_spi { int crc_off; @@ -132,6 +133,12 @@ static int wilc_bus_probe(struct spi_device *spi) wilc->bus_data = spi_priv; wilc->gpio_irq = gpio; + wilc->rtc_clk = devm_clk_get(&spi->dev, "rtc_clk"); + if (PTR_ERR_OR_ZERO(wilc->rtc_clk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + else if (!IS_ERR(wilc->rtc_clk)) + clk_prepare_enable(wilc->rtc_clk); + return 0; } @@ -142,6 +149,10 @@ static int wilc_bus_remove(struct spi_device *spi) /* free the GPIO in module remove */ if (wilc->gpio_irq) gpiod_put(wilc->gpio_irq); + + if (!IS_ERR(wilc->rtc_clk)) + clk_disable_unprepare(wilc->rtc_clk); + wilc_netdev_cleanup(wilc); return 0; } diff --git a/drivers/staging/wilc1000/wilc_wlan.c b/drivers/staging/wilc1000/wlan.c index 771d8cb68dc1..d3de76126b78 100644 --- a/drivers/staging/wilc1000/wilc_wlan.c +++ b/drivers/staging/wilc1000/wlan.c @@ -6,8 +6,8 @@ #include <linux/if_ether.h> #include <linux/ip.h> -#include "wilc_wfi_cfgoperations.h" -#include "wilc_wlan_cfg.h" +#include "cfg80211.h" +#include "wlan_cfg.h" static inline bool is_wilc1000(u32 id) { diff --git a/drivers/staging/wilc1000/wilc_wlan.h b/drivers/staging/wilc1000/wlan.h index 7469fa47d588..1f6957cf2e9c 100644 --- a/drivers/staging/wilc1000/wilc_wlan.h +++ b/drivers/staging/wilc1000/wlan.h @@ -190,7 +190,7 @@ #define ENABLE_RX_VMM (SEL_VMM_TBL1 | EN_VMM) #define ENABLE_TX_VMM (SEL_VMM_TBL0 | EN_VMM) -/*time for expiring the completion of cfg packets*/ +/* time for expiring the completion of cfg packets */ #define WILC_CFG_PKTS_TIMEOUT msecs_to_jiffies(2000) #define IS_MANAGMEMENT 0x100 diff --git a/drivers/staging/wilc1000/wilc_wlan_cfg.c b/drivers/staging/wilc1000/wlan_cfg.c index 3f53807cee0f..6f6b286788d1 100644 --- a/drivers/staging/wilc1000/wilc_wlan_cfg.c +++ b/drivers/staging/wilc1000/wlan_cfg.c @@ -4,10 +4,10 @@ * All rights reserved. */ -#include "wilc_wlan_if.h" -#include "wilc_wlan.h" -#include "wilc_wlan_cfg.h" -#include "wilc_wfi_netdevice.h" +#include "wlan_if.h" +#include "wlan.h" +#include "wlan_cfg.h" +#include "netdev.h" enum cfg_cmd_type { CFG_BYTE_CMD = 0, @@ -44,6 +44,11 @@ static const struct wilc_cfg_str g_cfg_str[] = { {WID_NIL, NULL} }; +#define WILC_RESP_MSG_TYPE_CONFIG_REPLY 'R' +#define WILC_RESP_MSG_TYPE_STATUS_INFO 'I' +#define WILC_RESP_MSG_TYPE_NETWORK_INFO 'N' +#define WILC_RESP_MSG_TYPE_SCAN_COMPLETE 'S' + /******************************************** * * Configuration Functions @@ -360,33 +365,26 @@ void wilc_wlan_cfg_indicate_rx(struct wilc *wilc, u8 *frame, int size, size -= 4; rsp->type = 0; - /* - * The valid types of response messages are - * 'R' (Response), - * 'I' (Information), and - * 'N' (Network Information) - */ - switch (msg_type) { - case 'R': + case WILC_RESP_MSG_TYPE_CONFIG_REPLY: wilc_wlan_parse_response_frame(wilc, frame, size); rsp->type = WILC_CFG_RSP; rsp->seq_no = msg_id; break; - case 'I': + case WILC_RESP_MSG_TYPE_STATUS_INFO: wilc_wlan_parse_info_frame(wilc, frame); rsp->type = WILC_CFG_RSP_STATUS; rsp->seq_no = msg_id; - /*call host interface info parse as well*/ + /* call host interface info parse as well */ wilc_gnrl_async_info_received(wilc, frame - 4, size + 4); break; - case 'N': + case WILC_RESP_MSG_TYPE_NETWORK_INFO: wilc_network_info_received(wilc, frame - 4, size + 4); break; - case 'S': + case WILC_RESP_MSG_TYPE_SCAN_COMPLETE: wilc_scan_complete_received(wilc, frame - 4, size + 4); break; diff --git a/drivers/staging/wilc1000/wilc_wlan_cfg.h b/drivers/staging/wilc1000/wlan_cfg.h index 614c5673f232..614c5673f232 100644 --- a/drivers/staging/wilc1000/wilc_wlan_cfg.h +++ b/drivers/staging/wilc1000/wlan_cfg.h diff --git a/drivers/staging/wilc1000/wilc_wlan_if.h b/drivers/staging/wilc1000/wlan_if.h index 70eac586f80c..7c7ee66c35f5 100644 --- a/drivers/staging/wilc1000/wilc_wlan_if.h +++ b/drivers/staging/wilc1000/wlan_if.h @@ -750,10 +750,10 @@ enum { WID_REMOVE_KEY = 0x301E, WID_ASSOC_REQ_INFO = 0x301F, WID_ASSOC_RES_INFO = 0x3020, - WID_MANUFACTURER = 0x3026, /*Added for CAPI tool */ - WID_MODEL_NAME = 0x3027, /*Added for CAPI tool */ - WID_MODEL_NUM = 0x3028, /*Added for CAPI tool */ - WID_DEVICE_NAME = 0x3029, /*Added for CAPI tool */ + WID_MANUFACTURER = 0x3026, /* Added for CAPI tool */ + WID_MODEL_NAME = 0x3027, /* Added for CAPI tool */ + WID_MODEL_NUM = 0x3028, /* Added for CAPI tool */ + WID_DEVICE_NAME = 0x3029, /* Added for CAPI tool */ /* NMAC String WID list */ WID_SET_OPERATION_MODE = 0x3079, diff --git a/drivers/staging/wlan-ng/hfa384x.h b/drivers/staging/wlan-ng/hfa384x.h index 5ff740a8837d..bdd7f414fdbb 100644 --- a/drivers/staging/wlan-ng/hfa384x.h +++ b/drivers/staging/wlan-ng/hfa384x.h @@ -1181,8 +1181,6 @@ struct hfa384x_usbctlx { ctlx_cmdcb_t cmdcb; /* Async command callback */ ctlx_usercb_t usercb; /* Async user callback, */ void *usercb_data; /* at CTLX completion */ - - int variant; /* Identifies cmd variant */ }; struct hfa384x_usbctlxq { @@ -1337,7 +1335,9 @@ struct hfa384x { * interface */ - struct hfa384x_caplevel cap_act_sta_mfi; /* sta f/w to modem interface */ + struct hfa384x_caplevel cap_act_sta_mfi; /* + * sta f/w to modem interface + */ struct hfa384x_caplevel cap_act_ap_cfi; /* * ap f/w to controller @@ -1359,7 +1359,9 @@ struct hfa384x { struct hfa384x_inf_frame *scanresults; - struct prism2sta_authlist authlist; /* Authenticated station list. */ + struct prism2sta_authlist authlist; /* + * Authenticated station list. + */ unsigned int accessmode; /* Access mode. */ struct prism2sta_accesslist allow; /* Allowed station list. */ struct prism2sta_accesslist deny; /* Denied station list. */ @@ -1370,12 +1372,13 @@ void hfa384x_create(struct hfa384x *hw, struct usb_device *usb); void hfa384x_destroy(struct hfa384x *hw); int hfa384x_corereset(struct hfa384x *hw, int holdtime, int settletime, - int genesis); + int genesis); int hfa384x_drvr_disable(struct hfa384x *hw, u16 macport); int hfa384x_drvr_enable(struct hfa384x *hw, u16 macport); int hfa384x_drvr_flashdl_enable(struct hfa384x *hw); int hfa384x_drvr_flashdl_disable(struct hfa384x *hw); -int hfa384x_drvr_flashdl_write(struct hfa384x *hw, u32 daddr, void *buf, u32 len); +int hfa384x_drvr_flashdl_write(struct hfa384x *hw, u32 daddr, void *buf, + u32 len); int hfa384x_drvr_getconfig(struct hfa384x *hw, u16 rid, void *buf, u16 len); int hfa384x_drvr_ramdl_enable(struct hfa384x *hw, u32 exeaddr); int hfa384x_drvr_ramdl_disable(struct hfa384x *hw); @@ -1383,7 +1386,8 @@ int hfa384x_drvr_ramdl_write(struct hfa384x *hw, u32 daddr, void *buf, u32 len); int hfa384x_drvr_readpda(struct hfa384x *hw, void *buf, unsigned int len); int hfa384x_drvr_setconfig(struct hfa384x *hw, u16 rid, void *buf, u16 len); -static inline int hfa384x_drvr_getconfig16(struct hfa384x *hw, u16 rid, void *val) +static inline int +hfa384x_drvr_getconfig16(struct hfa384x *hw, u16 rid, void *val) { int result = 0; diff --git a/drivers/staging/wlan-ng/hfa384x_usb.c b/drivers/staging/wlan-ng/hfa384x_usb.c index 28d372a0663a..b71756ab0394 100644 --- a/drivers/staging/wlan-ng/hfa384x_usb.c +++ b/drivers/staging/wlan-ng/hfa384x_usb.c @@ -293,13 +293,11 @@ void dbprint_urb(struct urb *urb) pr_debug("urb->transfer_buffer_length=0x%08x\n", urb->transfer_buffer_length); pr_debug("urb->actual_length=0x%08x\n", urb->actual_length); - pr_debug("urb->bandwidth=0x%08x\n", urb->bandwidth); pr_debug("urb->setup_packet(ctl)=0x%08x\n", (unsigned int)urb->setup_packet); pr_debug("urb->start_frame(iso/irq)=0x%08x\n", urb->start_frame); pr_debug("urb->interval(irq)=0x%08x\n", urb->interval); pr_debug("urb->error_count(iso)=0x%08x\n", urb->error_count); - pr_debug("urb->timeout=0x%08x\n", urb->timeout); pr_debug("urb->context=0x%08x\n", (unsigned int)urb->context); pr_debug("urb->complete=0x%08x\n", (unsigned int)urb->complete); } diff --git a/drivers/staging/wlan-ng/p80211wep.c b/drivers/staging/wlan-ng/p80211wep.c index 8bd92bba0ac1..51d917c8cdc8 100644 --- a/drivers/staging/wlan-ng/p80211wep.c +++ b/drivers/staging/wlan-ng/p80211wep.c @@ -49,6 +49,7 @@ /*================================================================*/ /* System Includes */ +#include <linux/crc32.h> #include <linux/netdevice.h> #include <linux/wireless.h> #include <linux/random.h> @@ -61,61 +62,6 @@ #define WEP_KEY(x) (((x) & 0xC0) >> 6) -static const u32 wep_crc32_table[256] = { - 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, - 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, - 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, - 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, - 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, - 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, - 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, - 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, - 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, - 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, - 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, - 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, - 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, - 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, - 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, - 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, - 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, - 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, - 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, - 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, - 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, - 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, - 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, - 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, - 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, - 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, - 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, - 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, - 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, - 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, - 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, - 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, - 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, - 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, - 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, - 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, - 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, - 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, - 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, - 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, - 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, - 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, - 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, - 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, - 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, - 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, - 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, - 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, - 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, - 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, - 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, - 0x2d02ef8dL -}; - /* keylen in bytes! */ int wep_change_key(struct wlandevice *wlandev, int keynum, u8 *key, int keylen) @@ -184,7 +130,6 @@ int wep_decrypt(struct wlandevice *wlandev, u8 *buf, u32 len, int key_override, } /* Apply the RC4 to the data, update the CRC32 */ - crc = ~0; i = 0; j = 0; for (k = 0; k < len; k++) { @@ -192,9 +137,8 @@ int wep_decrypt(struct wlandevice *wlandev, u8 *buf, u32 len, int key_override, j = (j + s[i]) & 0xff; swap(i, j); buf[k] ^= s[(s[i] + s[j]) & 0xff]; - crc = wep_crc32_table[(crc ^ buf[k]) & 0xff] ^ (crc >> 8); } - crc = ~crc; + crc = ~crc32_le(~0, buf, len); /* now let's check the crc */ c_crc[0] = crc; @@ -257,17 +201,15 @@ int wep_encrypt(struct wlandevice *wlandev, u8 *buf, } /* Update CRC32 then apply RC4 to the data */ - crc = ~0; i = 0; j = 0; for (k = 0; k < len; k++) { - crc = wep_crc32_table[(crc ^ buf[k]) & 0xff] ^ (crc >> 8); i = (i + 1) & 0xff; j = (j + s[i]) & 0xff; swap(i, j); dst[k] = buf[k] ^ s[(s[i] + s[j]) & 0xff]; } - crc = ~crc; + crc = ~crc32_le(~0, buf, len); /* now let's encrypt the crc */ icv[0] = crc; diff --git a/drivers/staging/wlan-ng/prism2usb.c b/drivers/staging/wlan-ng/prism2usb.c index b5ba176004c1..352556f6870a 100644 --- a/drivers/staging/wlan-ng/prism2usb.c +++ b/drivers/staging/wlan-ng/prism2usb.c @@ -137,7 +137,7 @@ static void prism2sta_disconnect_usb(struct usb_interface *interface) { struct wlandevice *wlandev; - wlandev = (struct wlandevice *)usb_get_intfdata(interface); + wlandev = usb_get_intfdata(interface); if (wlandev) { LIST_HEAD(cleanlist); struct hfa384x_usbctlx *ctlx, *temp; @@ -222,7 +222,7 @@ static int prism2sta_suspend(struct usb_interface *interface, struct hfa384x *hw = NULL; struct wlandevice *wlandev; - wlandev = (struct wlandevice *)usb_get_intfdata(interface); + wlandev = usb_get_intfdata(interface); if (!wlandev) return -ENODEV; @@ -245,7 +245,7 @@ static int prism2sta_resume(struct usb_interface *interface) struct hfa384x *hw = NULL; struct wlandevice *wlandev; - wlandev = (struct wlandevice *)usb_get_intfdata(interface); + wlandev = usb_get_intfdata(interface); if (!wlandev) return -ENODEV; |