Rudolf Marek <R.Marek@sh.cvut.cz>
Rui Saraiva <rmps@joel.ist.utl.pt>
Sachin P Sant <ssant@in.ibm.com>
+Sarangdhar Joshi <spjoshi@codeaurora.org>
Sam Ravnborg <sam@mars.ravnborg.org>
Santosh Shilimkar <ssantosh@kernel.org>
Santosh Shilimkar <santosh.shilimkar@oracle.org>
Simon Kelley <simon@thekelleys.org.uk>
Stéphane Witzmann <stephane.witzmann@ubpmes.univ-bpclermont.fr>
Stephen Hemminger <shemminger@osdl.org>
+Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
+Subhash Jadavani <subhashj@codeaurora.org>
Sudeep Holla <sudeep.holla@arm.com> Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com>
Sumit Semwal <sumit.semwal@ti.com>
Tejun Heo <htejun@gmail.com>
Thomas Graf <tgraf@suug.ch>
+Thomas Pedersen <twp@codeaurora.org>
Tony Luck <tony.luck@intel.com>
Tsuneo Yoshioka <Tsuneo.Yoshioka@f-secure.com>
Uwe Kleine-König <ukleinek@informatik.uni-freiburg.de>
Has all of the equivalent parameters as per voltageY. Units
after application of scale and offset are m/s^2.
+What: /sys/bus/iio/devices/iio:deviceX/in_gravity_x_raw
+What: /sys/bus/iio/devices/iio:deviceX/in_gravity_y_raw
+What: /sys/bus/iio/devices/iio:deviceX/in_gravity_z_raw
+KernelVersion: 4.11
+Contact: linux-iio@vger.kernel.org
+Description:
+ Gravity in direction x, y or z (may be arbitrarily assigned
+ but should match other such assignments on device).
+ Units after application of scale and offset are m/s^2.
+
What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_x_raw
What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_y_raw
What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_z_raw
attribute. E.g. if in_voltage0_raw_thresh_rising_value is set to 1200
and in_voltage0_raw_thresh_rising_hysteresis is set to 50. The event
will get activated once in_voltage0_raw goes above 1200 and will become
- deactived again once the value falls below 1150.
+ deactivated again once the value falls below 1150.
What: /sys/.../events/in_accel_x_raw_roc_rising_value
What: /sys/.../events/in_accel_x_raw_roc_falling_value
reflectivity of infrared or ultrasound emitted.
Often these sensors are unit less and as such conversion
to SI units is not possible. Higher proximity measurements
- indicate closer objects, and vice versa.
+ indicate closer objects, and vice versa. Units after
+ application of scale and offset are meters.
What: /sys/.../iio:deviceX/in_illuminance_input
What: /sys/.../iio:deviceX/in_illuminance_raw
--- /dev/null
+What: /sys/bus/iio/devices/triggerX/trigger_polarity
+KernelVersion: 4.11
+Contact: fabrice.gasnier@st.com
+Description:
+ The STM32 ADC can be configured to use external trigger sources
+ (e.g. timers, pwm or exti gpio). Then, it can be tuned to start
+ conversions on external trigger by either:
+ - "rising-edge"
+ - "falling-edge"
+ - "both-edges".
+ Reading returns current trigger polarity.
+ Writing value before enabling conversions sets trigger polarity.
+
+What: /sys/bus/iio/devices/triggerX/trigger_polarity_available
+KernelVersion: 4.11
+Contact: fabrice.gasnier@st.com
+Description:
+ List all available trigger_polarity settings.
--- /dev/null
+What /sys/bus/iio/devices/iio:deviceX/sensor_sensitivity
+Date: January 2017
+KernelVersion: 4.11
+Contact: linux-iio@vger.kernel.org
+Description:
+ Show or set the gain boost of the amp, from 0-31 range.
+ default 31
+
+What /sys/bus/iio/devices/iio:deviceX/sensor_max_range
+Date: January 2017
+KernelVersion: 4.11
+Contact: linux-iio@vger.kernel.org
+Description:
+ Show or set the maximum range between the sensor and the
+ first object echoed in meters. Default value is 6.020.
+ This setting limits the time the driver is waiting for a
+ echo.
+ Showing the range of available values is represented as the
+ minimum value, the step and the maximum value, all enclosed
+ in square brackets.
+ Example:
+ [0.043 0.043 11.008]
--- /dev/null
+What: /sys/bus/iio/devices/triggerX/master_mode_available
+KernelVersion: 4.11
+Contact: benjamin.gaignard@st.com
+Description:
+ Reading returns the list possible master modes which are:
+ - "reset" : The UG bit from the TIMx_EGR register is used as trigger output (TRGO).
+ - "enable" : The Counter Enable signal CNT_EN is used as trigger output.
+ - "update" : The update event is selected as trigger output.
+ For instance a master timer can then be used as a prescaler for a slave timer.
+ - "compare_pulse" : The trigger output send a positive pulse when the CC1IF flag is to be set.
+ - "OC1REF" : OC1REF signal is used as trigger output.
+ - "OC2REF" : OC2REF signal is used as trigger output.
+ - "OC3REF" : OC3REF signal is used as trigger output.
+ - "OC4REF" : OC4REF signal is used as trigger output.
+
+What: /sys/bus/iio/devices/triggerX/master_mode
+KernelVersion: 4.11
+Contact: benjamin.gaignard@st.com
+Description:
+ Reading returns the current master modes.
+ Writing set the master mode
+
+What: /sys/bus/iio/devices/triggerX/sampling_frequency
+KernelVersion: 4.11
+Contact: benjamin.gaignard@st.com
+Description:
+ Reading returns the current sampling frequency.
+ Writing an value different of 0 set and start sampling.
+ Writing 0 stop sampling.
+++ /dev/null
-What: /sys/devices/.../deferred_probe
-Date: August 2016
-Contact: Ben Hutchings <ben.hutchings@codethink.co.uk>
-Description:
- The /sys/devices/.../deferred_probe attribute is
- present for all devices. If a driver detects during
- probing a device that a related device is not yet
- ready, it may defer probing of the first device. The
- kernel will retry probing the first device after any
- other device is successfully probed. This attribute
- reads as 1 if probing of this device is currently
- deferred, or 0 otherwise.
"irq" and "wakeup" names are recognized by I2C core, other names are
left to individual drivers.
+- host-notify
+ device uses SMBus host notify protocol instead of interrupt line.
+
- multi-master
states that there is another master active on this bus. The OS can use
this information to adapt power management to keep the arbitration awake
used by the device. I2C core will assign "irq" interrupt (or the very first
interrupt if not using interrupt names) as primary interrupt for the slave.
+Alternatively, devices supporting SMbus Host Notify, and connected to
+adapters that support this feature, may use "host-notify" property. I2C
+core will create a virtual interrupt for Host Notify and assign it as
+primary interrupt for the slave.
+
Also, if device is marked as a wakeup source, I2C core will set up "wakeup"
interrupt for the device. If "wakeup" interrupt name is not present in the
binding, then primary interrupt will be used as wakeup interrupt.
dallas,ds3232 Extremely Accurate I²C RTC with Integrated Crystal and SRAM
dallas,ds4510 CPU Supervisor with Nonvolatile Memory and Programmable I/O
dallas,ds75 Digital Thermometer and Thermostat
+devantech,srf08 Devantech SRF08 ultrasonic ranger
dlg,da9053 DA9053: flexible system level PMIC with multicore support
dlg,da9063 DA9063: system PMIC for quad-core application processors
domintech,dmard09 DMARD09: 3-axis Accelerometer
Required properties for the SPI bindings:
- - compatible: should be set to "st,lis3lv02d_spi"
+ - compatible: should be set to "st,lis3lv02d-spi"
- reg: the chipselect index
- spi-max-frequency: maximal bus speed, should be set to 1000000 unless
constrained by external circuitry
--- /dev/null
+* Amlogic Meson SAR (Successive Approximation Register) A/D converter
+
+Required properties:
+- compatible: depending on the SoC this should be one of:
+ - "amlogic,meson-gxbb-saradc" for GXBB
+ - "amlogic,meson-gxl-saradc" for GXL
+ - "amlogic,meson-gxm-saradc" for GXM
+ along with the generic "amlogic,meson-saradc"
+- reg: the physical base address and length of the registers
+- clocks: phandle and clock identifier (see clock-names)
+- clock-names: mandatory clocks:
+ - "clkin" for the reference clock (typically XTAL)
+ - "core" for the SAR ADC core clock
+ optional clocks:
+ - "sana" for the analog clock
+ - "adc_clk" for the ADC (sampling) clock
+ - "adc_sel" for the ADC (sampling) clock mux
+- vref-supply: the regulator supply for the ADC reference voltage
+- #io-channel-cells: must be 1, see ../iio-bindings.txt
+
+Example:
+ saradc: adc@8680 {
+ compatible = "amlogic,meson-gxl-saradc", "amlogic,meson-saradc";
+ #io-channel-cells = <1>;
+ reg = <0x0 0x8680 0x0 0x34>;
+ clocks = <&xtal>,
+ <&clkc CLKID_SAR_ADC>,
+ <&clkc CLKID_SANA>,
+ <&clkc CLKID_SAR_ADC_CLK>,
+ <&clkc CLKID_SAR_ADC_SEL>;
+ clock-names = "clkin", "core", "sana", "adc_clk", "adc_sel";
+ };
--- /dev/null
+* AVIA HX711 ADC chip for weight cells
+ Bit-banging driver
+
+Required properties:
+ - compatible: Should be "avia,hx711"
+ - sck-gpios: Definition of the GPIO for the clock
+ - dout-gpios: Definition of the GPIO for data-out
+ See Documentation/devicetree/bindings/gpio/gpio.txt
+ - avdd-supply: Definition of the regulator used as analog supply
+
+Example:
+weight@0 {
+ compatible = "avia,hx711";
+ sck-gpios = <&gpio3 10 GPIO_ACTIVE_HIGH>;
+ dout-gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>;
+ avdd-suppy = <&avdd>;
+};
+
--- /dev/null
+* Maxim max11100 Analog to Digital Converter (ADC)
+
+Required properties:
+ - compatible: Should be "maxim,max11100"
+ - reg: the adc unit address
+ - vref-supply: phandle to the regulator that provides reference voltage
+
+Optional properties:
+ - spi-max-frequency: SPI maximum frequency
+
+Example:
+
+max11100: adc@0 {
+ compatible = "maxim,max11100";
+ reg = <0>;
+ vref-supply = <&adc0_vref>;
+ spi-max-frequency = <240000>;
+};
--- /dev/null
+Qualcomm's PM8xxx voltage XOADC
+
+The Qualcomm PM8xxx PMICs contain a HK/XO ADC (Housekeeping/Crystal
+oscillator ADC) encompassing PM8018, PM8038, PM8058 and PM8921.
+
+Required properties:
+
+- compatible: should be one of:
+ "qcom,pm8018-adc"
+ "qcom,pm8038-adc"
+ "qcom,pm8058-adc"
+ "qcom,pm8921-adc"
+
+- reg: should contain the ADC base address in the PMIC, typically
+ 0x197.
+
+- xoadc-ref-supply: should reference a regulator that can supply
+ a reference voltage on demand. The reference voltage may vary
+ with PMIC variant but is typically something like 2.2 or 1.8V.
+
+The following required properties are standard for IO channels, see
+iio-bindings.txt for more details:
+
+- #address-cells: should be set to <1>
+
+- #size-cells: should be set to <0>
+
+- #io-channel-cells: should be set to <1>
+
+- interrupts: should refer to the parent PMIC interrupt controller
+ and reference the proper ADC interrupt.
+
+Required subnodes:
+
+The ADC channels are configured as subnodes of the ADC. Since some of
+them are used for calibrating the ADC, these nodes are compulsory:
+
+adc-channel@c {
+ reg = <0x0c>;
+};
+
+adc-channel@d {
+ reg = <0x0d>;
+};
+
+adc-channel@f {
+ reg = <0x0f>;
+};
+
+These three nodes are used for absolute and ratiometric calibration
+and only need to have these reg values: they are by hardware definition
+1:1 ratio converters that sample 625, 1250 and 0 milliV and create
+an interpolation calibration for all other ADCs.
+
+Optional subnodes: any channels other than channel 0x0c, 0x0d and
+0x0f are optional.
+
+Required channel node properties:
+
+- reg: should contain the hardware channel number in the range
+ 0 .. 0x0f (4 bits). The hardware only supports 16 channels.
+
+Optional channel node properties:
+
+- qcom,decimation:
+ Value type: <u32>
+ Definition: This parameter is used to decrease the ADC sampling rate.
+ Quicker measurements can be made by reducing the decimation ratio.
+ Valid values are 512, 1024, 2048, 4096.
+ If the property is not found, a default value of 512 will be used.
+
+- qcom,ratiometric:
+ Value type: <u32>
+ Definition: Channel calibration type. If this property is specified
+ VADC will use a special voltage references for channel
+ calibration. The available references are specified in the
+ as a u32 value setting (see below) and it is compulsory
+ to also specify this reference if ratiometric calibration
+ is selected.
+
+ If the property is not found, the channel will be
+ calibrated with the 0.625V and 1.25V reference channels, also
+ known as an absolute calibration.
+ The reference voltage pairs when using ratiometric calibration:
+ 0 = XO_IN/XOADC_GND
+ 1 = PMIC_IN/XOADC_GND
+ 2 = PMIC_IN/BMS_CSP
+ 3 (invalid)
+ 4 = XOADC_GND/XOADC_GND
+ 5 = XOADC_VREF/XOADC_GND
+
+Example:
+
+xoadc: xoadc@197 {
+ compatible = "qcom,pm8058-adc";
+ reg = <0x197>;
+ interrupt-parent = <&pm8058>;
+ interrupts = <76 1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #io-channel-cells = <1>;
+
+ vcoin: adc-channel@0 {
+ reg = <0x00>;
+ };
+ vbat: adc-channel@1 {
+ reg = <0x01>;
+ };
+ dcin: adc-channel@2 {
+ reg = <0x02>;
+ };
+ ichg: adc-channel@3 {
+ reg = <0x03>;
+ };
+ vph_pwr: adc-channel@4 {
+ reg = <0x04>;
+ };
+ usb_vbus: adc-channel@a {
+ reg = <0x0a>;
+ };
+ die_temp: adc-channel@b {
+ reg = <0x0b>;
+ };
+ ref_625mv: adc-channel@c {
+ reg = <0x0c>;
+ };
+ ref_1250mv: adc-channel@d {
+ reg = <0x0d>;
+ };
+ ref_325mv: adc-channel@e {
+ reg = <0x0e>;
+ };
+ ref_muxoff: adc-channel@f {
+ reg = <0x0f>;
+ };
+};
+
+
+/* IIO client node */
+iio-hwmon {
+ compatible = "iio-hwmon";
+ io-channels = <&xoadc 0x01>, /* Battery */
+ <&xoadc 0x02>, /* DC in (charger) */
+ <&xoadc 0x04>, /* VPH the main system voltage */
+ <&xoadc 0x0b>, /* Die temperature */
+ <&xoadc 0x0c>, /* Reference voltage 1.25V */
+ <&xoadc 0x0d>, /* Reference voltage 0.625V */
+ <&xoadc 0x0e>; /* Reference voltage 0.325V */
+};
--- /dev/null
+* Renesas RCar GyroADC device driver
+
+The GyroADC block is a reduced SPI block with up to 8 chipselect lines,
+which supports the SPI protocol of a selected few SPI ADCs. The SPI ADCs
+are sampled by the GyroADC block in a round-robin fashion and the result
+presented in the GyroADC registers.
+
+Required properties:
+- compatible: Should be "<soc-specific>", "renesas,rcar-gyroadc".
+ The <soc-specific> should be one of:
+ renesas,r8a7791-gyroadc - for the GyroADC block present
+ in r8a7791 SoC
+ renesas,r8a7792-gyroadc - for the GyroADC with interrupt
+ block present in r8a7792 SoC
+- reg: Address and length of the register set for the device
+- clocks: References to all the clocks specified in the clock-names
+ property as specified in
+ Documentation/devicetree/bindings/clock/clock-bindings.txt.
+- clock-names: Shall contain "fck" and "if". The "fck" is the GyroADC block
+ clock, the "if" is the interface clock.
+- power-domains: Must contain a reference to the PM domain, if available.
+- #address-cells: Should be <1> (setting for the subnodes) for all ADCs
+ except for "fujitsu,mb88101a". Should be <0> (setting for
+ only subnode) for "fujitsu,mb88101a".
+- #size-cells: Should be <0> (setting for the subnodes)
+
+Sub-nodes:
+You must define subnode(s) which select the connected ADC type and reference
+voltage for the GyroADC channels.
+
+Required properties for subnodes:
+- compatible: Should be either of:
+ "fujitsu,mb88101a"
+ - Fujitsu MB88101A compatible mode,
+ 12bit sampling, up to 4 channels can be sampled in
+ round-robin fashion. One Fujitsu chip supplies four
+ GyroADC channels with data as it contains four ADCs
+ on the chip and thus for 4-channel operation, single
+ MB88101A is required. The Cx chipselect lines of the
+ MB88101A connect directly to two CHS lines of the
+ GyroADC, no demuxer is required. The data out line
+ of each MB88101A connects to a shared input pin of
+ the GyroADC.
+ "ti,adcs7476" or "ti,adc121" or "adi,ad7476"
+ - TI ADCS7476 / TI ADC121 / ADI AD7476 compatible mode,
+ 15bit sampling, up to 8 channels can be sampled in
+ round-robin fashion. One TI/ADI chip supplies single
+ ADC channel with data, thus for 8-channel operation,
+ 8 chips are required. A 3:8 chipselect demuxer is
+ required to connect the nCS line of the TI/ADI chips
+ to the GyroADC, while MISO line of each TI/ADI ADC
+ connects to a shared input pin of the GyroADC.
+ "maxim,max1162" or "maxim,max11100"
+ - Maxim MAX1162 / Maxim MAX11100 compatible mode,
+ 16bit sampling, up to 8 channels can be sampled in
+ round-robin fashion. One Maxim chip supplies single
+ ADC channel with data, thus for 8-channel operation,
+ 8 chips are required. A 3:8 chipselect demuxer is
+ required to connect the nCS line of the MAX chips
+ to the GyroADC, while MISO line of each Maxim ADC
+ connects to a shared input pin of the GyroADC.
+- reg: Should be the number of the analog input. Should be present
+ for all ADCs except "fujitsu,mb88101a".
+- vref-supply: Reference to the channel reference voltage regulator.
+
+Example:
+ vref_max1162: regulator-vref-max1162 {
+ compatible = "regulator-fixed";
+
+ regulator-name = "MAX1162 Vref";
+ regulator-min-microvolt = <4096000>;
+ regulator-max-microvolt = <4096000>;
+ };
+
+ adc@e6e54000 {
+ compatible = "renesas,r8a7791-gyroadc", "renesas,rcar-gyroadc";
+ reg = <0 0xe6e54000 0 64>;
+ clocks = <&mstp9_clks R8A7791_CLK_GYROADC>, <&clk_65m>;
+ clock-names = "fck", "if";
+ power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
+
+ pinctrl-0 = <&adc_pins>;
+ pinctrl-names = "default";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ adc@0 {
+ reg = <0>;
+ compatible = "maxim,max1162";
+ vref-supply = <&vref_max1162>;
+ };
+
+ adc@1 {
+ reg = <1>;
+ compatible = "maxim,max1162";
+ vref-supply = <&vref_max1162>;
+ };
+ };
- #io-channel-cells = <1>: See the IIO bindings section "IIO consumers" in
Documentation/devicetree/bindings/iio/iio-bindings.txt
+Optional properties:
+- dmas: Phandle to dma channel for this ADC instance.
+ See ../../dma/dma.txt for details.
+- dma-names: Must be "rx" when dmas property is being used.
+
Example:
adc: adc@40012000 {
compatible = "st,stm32f4-adc-core";
interrupt-parent = <&adc>;
interrupts = <0>;
st,adc-channels = <8>;
+ dmas = <&dma2 0 0 0x400 0x0>;
+ dma-names = "rx";
};
...
other adc child nodes follow...
--- /dev/null
+* Texas Instruments ADS7950 family of A/DC chips
+
+Required properties:
+ - compatible: Must be one of "ti,ads7950", "ti,ads7951", "ti,ads7952",
+ "ti,ads7953", "ti,ads7954", "ti,ads7955", "ti,ads7956", "ti,ads7957",
+ "ti,ads7958", "ti,ads7959", "ti,ads7960", or "ti,ads7961"
+ - reg: SPI chip select number for the device
+ - #io-channel-cells: Must be 1 as per ../iio-bindings.txt
+ - vref-supply: phandle to a regulator node that supplies the 2.5V or 5V
+ reference voltage
+
+Recommended properties:
+ - spi-max-frequency: Definition as per
+ Documentation/devicetree/bindings/spi/spi-bus.txt
+
+Example:
+adc@0 {
+ compatible = "ti,ads7957";
+ reg = <0>;
+ #io-channel-cells = <1>;
+ vref-supply = <&refin_supply>;
+ spi-max-frequency = <10000000>;
+};
--- /dev/null
+Bosch BMI160 - Inertial Measurement Unit with Accelerometer, Gyroscope
+and externally connectable Magnetometer
+
+https://www.bosch-sensortec.com/bst/products/all_products/bmi160
+
+Required properties:
+ - compatible : should be "bosch,bmi160"
+ - reg : the I2C address or SPI chip select number of the sensor
+ - spi-max-frequency : set maximum clock frequency (only for SPI)
+
+Optional properties:
+ - interrupt-parent : should be the phandle of the interrupt controller
+ - interrupts : interrupt mapping for IRQ, must be IRQ_TYPE_LEVEL_LOW
+ - interrupt-names : set to "INT1" if INT1 pin should be used as interrupt
+ input, set to "INT2" if INT2 pin should be used instead
+
+Examples:
+
+bmi160@68 {
+ compatible = "bosch,bmi160";
+ reg = <0x68>;
+
+ interrupt-parent = <&gpio4>;
+ interrupts = <12 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-names = "INT1";
+};
+
+bmi160@0 {
+ compatible = "bosch,bmi160";
+ reg = <0>;
+ spi-max-frequency = <10000000>;
+
+ interrupt-parent = <&gpio2>;
+ interrupts = <12 IRQ_TYPE_LEVEL_LOW>;
+ interrupt-names = "INT2";
+};
--- /dev/null
+* ST_LSM6DSx driver for STM 6-axis (acc + gyro) imu Mems sensors
+
+Required properties:
+- compatible: must be one of:
+ "st,lsm6ds3"
+ "st,lsm6dsm"
+- reg: i2c address of the sensor / spi cs line
+
+Optional properties:
+- st,drdy-int-pin: the pin on the package that will be used to signal
+ "data ready" (valid values: 1 or 2).
+- interrupt-parent: should be the phandle for the interrupt controller
+- interrupts: interrupt mapping for IRQ. It should be configured with
+ flags IRQ_TYPE_LEVEL_HIGH or IRQ_TYPE_EDGE_RISING.
+
+ Refer to interrupt-controller/interrupts.txt for generic interrupt
+ client node bindings.
+
+Example:
+
+lsm6dsm@6b {
+ compatible = "st,lsm6dsm";
+ reg = <0x6b>;
+ interrupt-parent = <&gpio0>;
+ interrupts = <0 IRQ_TYPE_EDGE_RISING>;
+};
--- /dev/null
+Capella Microsystems CM3605
+Ambient Light and Short Distance Proximity Sensor
+
+The CM3605 is an entirely analog part which however require quite a bit of
+software logic to interface a host operating system.
+
+This ALS and proximity sensor was one of the very first deployed in mobile
+handsets, notably it is used in the very first Nexus One Android phone from
+2010.
+
+Required properties:
+- compatible: must be: "capella,cm3605"
+- aset-gpios: GPIO line controlling the ASET line (drive low
+ to activate the ALS, should be flagged GPIO_ACTIVE_LOW)
+- interrupts: the IRQ line (such as a GPIO) that is connected to
+ the POUT (proximity sensor out) line. The edge detection must
+ be set to IRQ_TYPE_EDGE_BOTH so as to detect movements toward
+ and away from the proximity sensor.
+- io-channels: the ADC channel used for converting the voltage from
+ AOUT to a digital representation.
+- io-channel-names: must be "aout"
+
+Optional properties:
+- vdd-supply: regulator supplying VDD power to the component.
+- capella,aset-resistance-ohms: the sensitivity calibration resistance,
+ in Ohms. Valid values are: 50000, 100000, 300000 and 600000,
+ as these are the resistance values that we are supplied with
+ calibration curves for. If not supplied, 100 kOhm will be assumed
+ but it is strongly recommended to supply this.
+
+Example:
+
+cm3605 {
+ compatible = "capella,cm3605";
+ vdd-supply = <&foo_reg>;
+ aset-gpios = <&foo_gpio 1 GPIO_ACTIVE_LOW>;
+ capella,aset-resistance-ohms = <100000>;
+ interrupts = <1 IRQ_TYPE_EDGE_BOTH>;
+ io-channels = <&adc 0x01>;
+ io-channel-names = "aout";
+};
--- /dev/null
+* Maxim Linear-Taper Digital Potentiometer MAX5481-MAX5484
+
+The node for this driver must be a child node of a SPI controller, hence
+all mandatory properties described in
+
+ Documentation/devicetree/bindings/spi/spi-bus.txt
+
+must be specified.
+
+Required properties:
+ - compatible: Must be one of the following, depending on the
+ model:
+ "maxim,max5481"
+ "maxim,max5482"
+ "maxim,max5483"
+ "maxim,max5484"
+
+Example:
+max548x: max548x@0 {
+ compatible = "maxim,max5482";
+ spi-max-frequency = <7000000>;
+ reg = <0>; /* chip-select */
+};
Valid compatible strings:
Accelerometers:
+- st,lis3lv02d (deprecated, use st,lis3lv02dl-accel)
+- st,lis302dl-spi (deprecated, use st,lis3lv02dl-accel)
- st,lis3lv02dl-accel
- st,lsm303dlh-accel
- st,lsm303dlhc-accel
--- /dev/null
+* TI TMP007 - IR thermopile sensor with integrated math engine
+
+Link to datasheet: http://www.ti.com/lit/ds/symlink/tmp007.pdf
+
+Required properties:
+
+ - compatible: should be "ti,tmp007"
+ - reg: the I2C address of the sensor (changeable via ADR pins)
+ ------------------------------
+ |ADR1 | ADR0 | Device Address|
+ ------------------------------
+ 0 0 0x40
+ 0 1 0x41
+ 0 SDA 0x42
+ 0 SCL 0x43
+ 1 0 0x44
+ 1 1 0x45
+ 1 SDA 0x46
+ 1 SCL 0x47
+
+Optional properties:
+
+ - interrupt-parent: should be the phandle for the interrupt controller
+
+ - interrupts: interrupt mapping for GPIO IRQ (level active low)
+
+Example:
+
+tmp007@40 {
+ compatible = "ti,tmp007";
+ reg = <0x40>;
+ interrupt-parent = <&gpio0>;
+ interrupts = <5 0x08>;
+};
+
--- /dev/null
+STMicroelectronics STM32 Timers IIO timer bindings
+
+Must be a sub-node of an STM32 Timers device tree node.
+See ../mfd/stm32-timers.txt for details about the parent node.
+
+Required parameters:
+- compatible: Must be "st,stm32-timer-trigger".
+- reg: Identify trigger hardware block.
+
+Example:
+ timers@40010000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "st,stm32-timers";
+ reg = <0x40010000 0x400>;
+ clocks = <&rcc 0 160>;
+ clock-names = "clk_int";
+
+ timer@0 {
+ compatible = "st,stm32-timer-trigger";
+ reg = <0>;
+ };
+ };
Second cell specifies the irq distribution mode to cores
0=Round Robin; 1=cpu0, 2=cpu1, 4=cpu2, 8=cpu3
+ The second cell in interrupts property is deprecated and may be ignored by
+ the kernel.
+
intc accessed via the special ARC AUX register interface, hence "reg" property
is not specified.
--- /dev/null
+STM32 Timers driver bindings
+
+This IP provides 3 types of timer along with PWM functionality:
+- advanced-control timers consist of a 16-bit auto-reload counter driven by a programmable
+ prescaler, break input feature, PWM outputs and complementary PWM ouputs channels.
+- general-purpose timers consist of a 16-bit or 32-bit auto-reload counter driven by a
+ programmable prescaler and PWM outputs.
+- basic timers consist of a 16-bit auto-reload counter driven by a programmable prescaler.
+
+Required parameters:
+- compatible: must be "st,stm32-timers"
+
+- reg: Physical base address and length of the controller's
+ registers.
+- clock-names: Set to "int".
+- clocks: Phandle to the clock used by the timer module.
+ For Clk properties, please refer to ../clock/clock-bindings.txt
+
+Optional parameters:
+- resets: Phandle to the parent reset controller.
+ See ../reset/st,stm32-rcc.txt
+
+Optional subnodes:
+- pwm: See ../pwm/pwm-stm32.txt
+- timer: See ../iio/timer/stm32-timer-trigger.txt
+
+Example:
+ timers@40010000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "st,stm32-timers";
+ reg = <0x40010000 0x400>;
+ clocks = <&rcc 0 160>;
+ clock-names = "clk_int";
+
+ pwm {
+ compatible = "st,stm32-pwm";
+ pinctrl-0 = <&pwm1_pins>;
+ pinctrl-names = "default";
+ };
+
+ timer@0 {
+ compatible = "st,stm32-timer-trigger";
+ reg = <0>;
+ };
+ };
- compatible: "sigma,smp8758-nand"
- reg: address/size of nfc_reg, nfc_mem, and pbus_reg
- dmas: reference to the DMA channel used by the controller
-- dma-names: "nfc_sbox"
+- dma-names: "rxtx"
- clocks: reference to the system clock
- #address-cells: <1>
- #size-cells: <0>
nandc: nand-controller@2c000 {
compatible = "sigma,smp8758-nand";
- reg = <0x2c000 0x30 0x2d000 0x800 0x20000 0x1000>;
+ reg = <0x2c000 0x30>, <0x2d000 0x800>, <0x20000 0x1000>;
dmas = <&dma0 3>;
- dma-names = "nfc_sbox";
+ dma-names = "rxtx";
clocks = <&clkgen SYS_CLK>;
#address-cells = <1>;
#size-cells = <0>;
* Ethernet controller node
Required properties:
-- compatible: Should be "mediatek,mt7623-eth"
+- compatible: Should be "mediatek,mt2701-eth"
- reg: Address and length of the register set for the device
- interrupts: Should contain the three frame engines interrupts in numeric
order. These are fe_int0, fe_int1 and fe_int2.
specifications. If neither of these are specified, the default is to
assume clause 22.
- If the phy's identifier is known then the list may contain an entry
- of the form: "ethernet-phy-idAAAA.BBBB" where
+ If the PHY reports an incorrect ID (or none at all) then the
+ "compatible" list may contain an entry with the correct PHY ID in the
+ form: "ethernet-phy-idAAAA.BBBB" where
AAAA - The value of the 16 bit Phy Identifier 1 register as
4 hex digits. This is the chip vendor OUI bits 3:18
BBBB - The value of the 16 bit Phy Identifier 2 register as
Required properties:
- reg - The ID number for the phy, usually a small integer
- ti,rx-internal-delay - RGMII Receive Clock Delay - see dt-bindings/net/ti-dp83867.h
- for applicable values
+ for applicable values. Required only if interface type is
+ PHY_INTERFACE_MODE_RGMII_ID or PHY_INTERFACE_MODE_RGMII_RXID
- ti,tx-internal-delay - RGMII Transmit Clock Delay - see dt-bindings/net/ti-dp83867.h
- for applicable values
+ for applicable values. Required only if interface type is
+ PHY_INTERFACE_MODE_RGMII_ID or PHY_INTERFACE_MODE_RGMII_TXID
- ti,fifo-depth - Transmitt FIFO depth- see dt-bindings/net/ti-dp83867.h
for applicable values
--- /dev/null
+STMicroelectronics STM32 Timers PWM bindings
+
+Must be a sub-node of an STM32 Timers device tree node.
+See ../mfd/stm32-timers.txt for details about the parent node.
+
+Required parameters:
+- compatible: Must be "st,stm32-pwm".
+- pinctrl-names: Set to "default".
+- pinctrl-0: List of phandles pointing to pin configuration nodes for PWM module.
+ For Pinctrl properties see ../pinctrl/pinctrl-bindings.txt
+
+Optional parameters:
+- st,breakinput: One or two <index level filter> to describe break input configurations.
+ "index" indicates on which break input (0 or 1) the configuration
+ should be applied.
+ "level" gives the active level (0=low or 1=high) of the input signal
+ for this configuration.
+ "filter" gives the filtering value to be applied.
+
+Example:
+ timers@40010000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "st,stm32-timers";
+ reg = <0x40010000 0x400>;
+ clocks = <&rcc 0 160>;
+ clock-names = "clk_int";
+
+ pwm {
+ compatible = "st,stm32-pwm";
+ pinctrl-0 = <&pwm1_pins>;
+ pinctrl-names = "default";
+ st,breakinput = <0 1 5>;
+ };
+ };
Renesas MSIOF spi controller
Required properties:
-- compatible : "renesas,msiof-<soctype>" for SoCs,
- "renesas,sh-msiof" for SuperH, or
- "renesas,sh-mobile-msiof" for SH Mobile series.
- Examples with soctypes are:
- "renesas,msiof-r8a7790" (R-Car H2)
+- compatible : "renesas,msiof-r8a7790" (R-Car H2)
"renesas,msiof-r8a7791" (R-Car M2-W)
"renesas,msiof-r8a7792" (R-Car V2H)
"renesas,msiof-r8a7793" (R-Car M2-N)
"renesas,msiof-r8a7794" (R-Car E2)
"renesas,msiof-r8a7796" (R-Car M3-W)
"renesas,msiof-sh73a0" (SH-Mobile AG5)
+ "renesas,sh-mobile-msiof" (generic SH-Mobile compatibile device)
+ "renesas,rcar-gen2-msiof" (generic R-Car Gen2 compatible device)
+ "renesas,rcar-gen3-msiof" (generic R-Car Gen3 compatible device)
+ "renesas,sh-msiof" (deprecated)
+
+ When compatible with the generic version, nodes
+ must list the SoC-specific version corresponding
+ to the platform first followed by the generic
+ version.
+
- reg : A list of offsets and lengths of the register sets for
the device.
If only one register set is present, it is to be used
Example:
msiof0: spi@e6e20000 {
- compatible = "renesas,msiof-r8a7791";
+ compatible = "renesas,msiof-r8a7791",
+ "renesas,rcar-gen2-msiof";
reg = <0 0xe6e20000 0 0x0064>;
interrupts = <0 156 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp0_clks R8A7791_CLK_MSIOF0>;
auo AU Optronics Corporation
auvidea Auvidea GmbH
avago Avago Technologies
+avia avia semiconductor
avic Shanghai AVIC Optoelectronics Co., Ltd.
axentia Axentia Technologies AB
axis Axis Communications AB
davicom DAVICOM Semiconductor, Inc.
delta Delta Electronics, Inc.
denx Denx Software Engineering
+devantech Devantech, Ltd.
digi Digi International Inc.
digilent Diglent, Inc.
dlg Dialog Semiconductor
goodix Shenzhen Huiding Technology Co., Ltd.
google Google, Inc.
grinn Grinn
+grmn Garmin Limited
gumstix Gumstix, Inc.
gw Gateworks Corporation
hannstar HannStar Display Corporation
snapshot of a moment, you can see /proc/<pid>/smaps file and scan page table.
It's slow but very precise.
-Table 1-2: Contents of the status files (as of 4.1)
+Table 1-2: Contents of the status files (as of 4.8)
..............................................................................
Field Content
Name filename of the executable
+ Umask file mode creation mask
State state (R is running, S is sleeping, D is sleeping
in an uninterruptible wait, Z is zombie,
T is traced or stopped)
TracerPid PID of process tracing this process (0 if not)
Uid Real, effective, saved set, and file system UIDs
Gid Real, effective, saved set, and file system GIDs
- Umask file mode creation mask
FDSize number of file descriptor slots currently allocated
Groups supplementary group list
NStgid descendant namespace thread group ID hierarchy
VmPeak peak virtual memory size
VmSize total program size
VmLck locked memory size
+ VmPin pinned memory size
VmHWM peak resident set size ("high water mark")
VmRSS size of memory portions. It contains the three
following parts (VmRSS = RssAnon + RssFile + RssShmem)
The default suspend mode (ie. the one to be used without writing anything into
/sys/power/mem_sleep) is either "deep" (if Suspend-To-RAM is supported) or
"s2idle", but it can be overridden by the value of the "mem_sleep_default"
-parameter in the kernel command line. On some ACPI-based systems, depending on
-the information in the FADT, the default may be "s2idle" even if Suspend-To-RAM
-is supported.
+parameter in the kernel command line.
The properties of all of the sleep states are described below.
--- /dev/null
+Page fragments
+--------------
+
+A page fragment is an arbitrary-length arbitrary-offset area of memory
+which resides within a 0 or higher order compound page. Multiple
+fragments within that page are individually refcounted, in the page's
+reference counter.
+
+The page_frag functions, page_frag_alloc and page_frag_free, provide a
+simple allocation framework for page fragments. This is used by the
+network stack and network device drivers to provide a backing region of
+memory for use as either an sk_buff->head, or to be used in the "frags"
+portion of skb_shared_info.
+
+In order to make use of the page fragment APIs a backing page fragment
+cache is needed. This provides a central point for the fragment allocation
+and tracks allows multiple calls to make use of a cached page. The
+advantage to doing this is that multiple calls to get_page can be avoided
+which can be expensive at allocation time. However due to the nature of
+this caching it is required that any calls to the cache be protected by
+either a per-cpu limitation, or a per-cpu limitation and forcing interrupts
+to be disabled when executing the fragment allocation.
+
+The network stack uses two separate caches per CPU to handle fragment
+allocation. The netdev_alloc_cache is used by callers making use of the
+__netdev_alloc_frag and __netdev_alloc_skb calls. The napi_alloc_cache is
+used by callers of the __napi_alloc_frag and __napi_alloc_skb calls. The
+main difference between these two calls is the context in which they may be
+called. The "netdev" prefixed functions are usable in any context as these
+functions will disable interrupts, while the "napi" prefixed functions are
+only usable within the softirq context.
+
+Many network device drivers use a similar methodology for allocating page
+fragments, but the page fragments are cached at the ring or descriptor
+level. In order to enable these cases it is necessary to provide a generic
+way of tearing down a page cache. For this reason __page_frag_cache_drain
+was implemented. It allows for freeing multiple references from a single
+page via a single call. The advantage to doing this is that it allows for
+cleaning up the multiple references that were added to a page in order to
+avoid calling get_page per allocation.
+
+Alexander Duyck, Nov 29, 2016.
Q: Patchwork web based patch tracking system site
T: SCM tree type and location.
Type is one of: git, hg, quilt, stgit, topgit
- B: Bug tracking system location.
S: Status, one of the following:
Supported: Someone is actually paid to look after this.
Maintained: Someone actually looks after it.
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
W: http://www.armlinux.org.uk/
S: Maintained
+T: git git://git.armlinux.org.uk/~rmk/linux-arm.git
F: arch/arm/
ARM SUB-ARCHITECTURES
M: Russell King <linux@armlinux.org.uk>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
+T: git git://git.armlinux.org.uk/~rmk/linux-arm.git clkdev
F: arch/arm/include/asm/clkdev.h
F: drivers/clk/clkdev.c
R: Javier Martinez Canillas <javier@osg.samsung.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
+Q: https://patchwork.kernel.org/project/linux-samsung-soc/list/
S: Maintained
F: arch/arm/boot/dts/s3c*
F: arch/arm/boot/dts/s5p*
S: Supported
F: sound/soc/atmel
-ATMEL DMA DRIVER
-M: Nicolas Ferre <nicolas.ferre@atmel.com>
-L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S: Supported
-F: drivers/dma/at_hdmac.c
-F: drivers/dma/at_hdmac_regs.h
-F: include/linux/platform_data/dma-atmel.h
-
ATMEL XDMA DRIVER
M: Ludovic Desroches <ludovic.desroches@atmel.com>
L: linux-arm-kernel@lists.infradead.org
F: include/uapi/rdma/cxgb3-abi.h
CXGB4 ETHERNET DRIVER (CXGB4)
-M: Hariprasad S <hariprasad@chelsio.com>
+M: Ganesh Goudar <ganeshgr@chelsio.com>
L: netdev@vger.kernel.org
W: http://www.chelsio.com
S: Supported
DRM DRIVER FOR BOCHS VIRTUAL GPU
M: Gerd Hoffmann <kraxel@redhat.com>
-S: Odd Fixes
+L: virtualization@lists.linux-foundation.org
+T: git git://git.kraxel.org/linux drm-qemu
+S: Maintained
F: drivers/gpu/drm/bochs/
DRM DRIVER FOR QEMU'S CIRRUS DEVICE
M: Dave Airlie <airlied@redhat.com>
-S: Odd Fixes
+M: Gerd Hoffmann <kraxel@redhat.com>
+L: virtualization@lists.linux-foundation.org
+T: git git://git.kraxel.org/linux drm-qemu
+S: Obsolete
+W: https://www.kraxel.org/blog/2014/10/qemu-using-cirrus-considered-harmful/
F: drivers/gpu/drm/cirrus/
RADEON and AMDGPU DRM DRIVERS
M: Alex Deucher <alexander.deucher@amd.com>
M: Christian König <christian.koenig@amd.com>
-L: dri-devel@lists.freedesktop.org
+L: amd-gfx@lists.freedesktop.org
T: git git://people.freedesktop.org/~agd5f/linux
S: Supported
F: drivers/gpu/drm/radeon/
INTEL GVT-g DRIVERS (Intel GPU Virtualization)
M: Zhenyu Wang <zhenyuw@linux.intel.com>
M: Zhi Wang <zhi.a.wang@intel.com>
-L: igvt-g-dev@lists.01.org
+L: intel-gvt-dev@lists.freedesktop.org
L: intel-gfx@lists.freedesktop.org
W: https://01.org/igvt-g
T: git https://github.com/01org/gvt-linux.git
DRM DRIVER FOR QXL VIRTUAL GPU
M: Dave Airlie <airlied@redhat.com>
-S: Odd Fixes
+M: Gerd Hoffmann <kraxel@redhat.com>
+L: virtualization@lists.linux-foundation.org
+T: git git://git.kraxel.org/linux drm-qemu
+S: Maintained
F: drivers/gpu/drm/qxl/
F: include/uapi/drm/qxl_drm.h
F: Documentation/devicetree/bindings/net/dsa/marvell.txt
MARVELL ARMADA DRM SUPPORT
-M: Russell King <rmk+kernel@armlinux.org.uk>
+M: Russell King <linux@armlinux.org.uk>
S: Maintained
+T: git git://git.armlinux.org.uk/~rmk/linux-arm.git drm-armada-devel
+T: git git://git.armlinux.org.uk/~rmk/linux-arm.git drm-armada-fixes
F: drivers/gpu/drm/armada/
F: include/uapi/drm/armada_drm.h
F: Documentation/devicetree/bindings/display/armada/
F: drivers/tty/serial/atmel_serial.c
F: include/linux/atmel_serial.h
+MICROCHIP / ATMEL DMA DRIVER
+M: Ludovic Desroches <ludovic.desroches@microchip.com>
+L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+L: dmaengine@vger.kernel.org
+S: Supported
+F: drivers/dma/at_hdmac.c
+F: drivers/dma/at_hdmac_regs.h
+F: include/linux/platform_data/dma-atmel.h
+
MICROCHIP / ATMEL ISC DRIVER
M: Songjun Wu <songjun.wu@microchip.com>
L: linux-media@vger.kernel.org
F: drivers/nfc/nxp-nci
NXP TDA998X DRM DRIVER
-M: Russell King <rmk+kernel@armlinux.org.uk>
+M: Russell King <linux@armlinux.org.uk>
S: Supported
+T: git git://git.armlinux.org.uk/~rmk/linux-arm.git drm-tda998x-devel
+T: git git://git.armlinux.org.uk/~rmk/linux-arm.git drm-tda998x-fixes
F: drivers/gpu/drm/i2c/tda998x_drv.c
F: include/drm/i2c/tda998x.h
F: include/uapi/linux/qnxtypes.h
QORIQ DPAA2 FSL-MC BUS DRIVER
-M: Stuart Yoder <stuart.yoder@nxp.com>
+M: Stuart Yoder <stuyoder@gmail.com>
+M: Laurentiu Tudor <laurentiu.tudor@nxp.com>
L: linux-kernel@vger.kernel.org
S: Maintained
F: drivers/staging/fsl-mc/
QUALCOMM ATHEROS ATH9K WIRELESS DRIVER
M: QCA ath9k Development <ath9k-devel@qca.qualcomm.com>
L: linux-wireless@vger.kernel.org
-L: ath9k-devel@lists.ath9k.org
W: http://wireless.kernel.org/en/users/Drivers/ath9k
S: Supported
F: drivers/net/wireless/ath/ath9k/
F: drivers/net/ethernet/renesas/
F: include/linux/sh_eth.h
+RENESAS R-CAR GYROADC DRIVER
+M: Marek Vasut <marek.vasut@gmail.com>
+L: linux-iio@vger.kernel.org
+S: Supported
+F: drivers/iio/adc/rcar_gyro_adc.c
+
RENESAS USB2 PHY DRIVER
M: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
L: linux-renesas-soc@vger.kernel.org
F: include/uapi/linux/userio.h
VIRTIO CONSOLE DRIVER
-M: Amit Shah <amit.shah@redhat.com>
+M: Amit Shah <amit@kernel.org>
L: virtualization@lists.linux-foundation.org
S: Maintained
F: drivers/char/virtio_console.c
M: Gerd Hoffmann <kraxel@redhat.com>
L: dri-devel@lists.freedesktop.org
L: virtualization@lists.linux-foundation.org
+T: git git://git.kraxel.org/linux drm-qemu
S: Maintained
F: drivers/gpu/drm/virtio/
F: include/uapi/linux/virtio_gpu.h
X86 PLATFORM DRIVERS
M: Darren Hart <dvhart@infradead.org>
+M: Andy Shevchenko <andy@infradead.org>
L: platform-driver-x86@vger.kernel.org
T: git git://git.infradead.org/users/dvhart/linux-platform-drivers-x86.git
S: Maintained
ZBUD COMPRESSED PAGE ALLOCATOR
M: Seth Jennings <sjenning@redhat.com>
+M: Dan Streetman <ddstreet@ieee.org>
L: linux-mm@kvack.org
S: Maintained
F: mm/zbud.c
ZSWAP COMPRESSED SWAP CACHING
M: Seth Jennings <sjenning@redhat.com>
+M: Dan Streetman <ddstreet@ieee.org>
L: linux-mm@kvack.org
S: Maintained
F: mm/zswap.c
VERSION = 4
PATCHLEVEL = 10
SUBLEVEL = 0
-EXTRAVERSION = -rc3
-NAME = Roaring Lionus
+EXTRAVERSION = -rc7
+NAME = Fearless Coyote
# *DOCUMENTATION*
# To see a list of typical targets execute "make help"
KBUILD_ARFLAGS := $(call ar-option,D)
# check for 'asm goto'
-ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-goto.sh $(CC)), y)
+ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-goto.sh $(CC) $(KBUILD_CFLAGS)), y)
KBUILD_CFLAGS += -DCC_HAVE_ASM_GOTO
KBUILD_AFLAGS += -DCC_HAVE_ASM_GOTO
endif
select HAVE_KPROBES
select HAVE_KRETPROBES
select HAVE_MEMBLOCK
- select HAVE_MOD_ARCH_SPECIFIC if ARC_DW2_UNWIND
+ select HAVE_MOD_ARCH_SPECIFIC
select HAVE_OPROFILE
select HAVE_PERF_EVENTS
select HANDLE_DOMAIN_IRQ
#define ARC_REG_IC_PTAG_HI 0x1F
/* Bit val in IC_CTRL */
-#define IC_CTRL_CACHE_DISABLE 0x1
+#define IC_CTRL_DIS 0x1
/* Data cache related Auxiliary registers */
#define ARC_REG_DC_BCR 0x72 /* Build Config reg */
#define ARC_REG_DC_PTAG_HI 0x5F
/* Bit val in DC_CTRL */
-#define DC_CTRL_INV_MODE_FLUSH 0x40
-#define DC_CTRL_FLUSH_STATUS 0x100
+#define DC_CTRL_DIS 0x001
+#define DC_CTRL_INV_MODE_FLUSH 0x040
+#define DC_CTRL_FLUSH_STATUS 0x100
/*System-level cache (L2 cache) related Auxiliary registers */
#define ARC_REG_SLC_CFG 0x901
#define ARC_REG_SLC_RGN_END 0x916
/* Bit val in SLC_CONTROL */
+#define SLC_CTRL_DIS 0x001
#define SLC_CTRL_IM 0x040
-#define SLC_CTRL_DISABLE 0x001
#define SLC_CTRL_BUSY 0x100
#define SLC_CTRL_RGN_OP_INV 0x200
" lp 1f \n"
" nop \n"
"1: \n"
- : : "r"(loops));
+ :
+ : "r"(loops)
+ : "lp_count");
}
extern void __bad_udelay(void);
;
; Now manually save: r12, sp, fp, gp, r25
+ PUSH r30
PUSH r12
; Saving pt_regs->sp correctly requires some extra work due to the way
POPAX AUX_USER_SP
1:
POP r12
+ POP r30
.endm
#include <asm-generic/module.h>
-#ifdef CONFIG_ARC_DW2_UNWIND
struct mod_arch_specific {
+#ifdef CONFIG_ARC_DW2_UNWIND
void *unw_info;
int unw_sec_idx;
+#endif
const char *secstr;
};
-#endif
#define MODULE_PROC_FAMILY "ARC700"
unsigned long fp;
unsigned long sp; /* user/kernel sp depending on where we came from */
- unsigned long r12;
+ unsigned long r12, r30;
/*------- Below list auto saved by h/w -----------*/
unsigned long r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11;
void setup_processor(void);
void __init setup_arch_memory(void);
+long __init arc_get_mem_sz(void);
/* Helpers used in arc_*_mumbojumbo routines */
#define IS_AVAIL1(v, s) ((v) ? s : "")
GET_CPU_ID r5
cmp r5, 0
mov.nz r0, r5
-#ifdef CONFIG_ARC_SMP_HALT_ON_RESET
- ; Non-Master can proceed as system would be booted sufficiently
- jnz first_lines_of_secondary
-#else
+ bz .Lmaster_proceed
+
; Non-Masters wait for Master to boot enough and bring them up
- jnz arc_platform_smp_wait_to_boot
-#endif
- ; Master falls thru
+ ; when they resume, tail-call to entry point
+ mov blink, @first_lines_of_secondary
+ j arc_platform_smp_wait_to_boot
+
+.Lmaster_proceed:
#endif
; Clear BSS before updating any globals
static void arcv2_irq_mask(struct irq_data *data)
{
- write_aux_reg(AUX_IRQ_SELECT, data->irq);
+ write_aux_reg(AUX_IRQ_SELECT, data->hwirq);
write_aux_reg(AUX_IRQ_ENABLE, 0);
}
static void arcv2_irq_unmask(struct irq_data *data)
{
- write_aux_reg(AUX_IRQ_SELECT, data->irq);
+ write_aux_reg(AUX_IRQ_SELECT, data->hwirq);
write_aux_reg(AUX_IRQ_ENABLE, 1);
}
void arcv2_irq_enable(struct irq_data *data)
{
/* set default priority */
- write_aux_reg(AUX_IRQ_SELECT, data->irq);
+ write_aux_reg(AUX_IRQ_SELECT, data->hwirq);
write_aux_reg(AUX_IRQ_PRIORITY, ARCV2_IRQ_DEF_PRIO);
/*
unsigned int ienb;
ienb = read_aux_reg(AUX_IENABLE);
- ienb &= ~(1 << data->irq);
+ ienb &= ~(1 << data->hwirq);
write_aux_reg(AUX_IENABLE, ienb);
}
unsigned int ienb;
ienb = read_aux_reg(AUX_IENABLE);
- ienb |= (1 << data->irq);
+ ienb |= (1 << data->hwirq);
write_aux_reg(AUX_IENABLE, ienb);
}
#include <linux/smp.h>
#include <linux/irq.h>
+#include <linux/irqchip/chained_irq.h>
#include <linux/spinlock.h>
#include <soc/arc/mcip.h>
#include <asm/irqflags-arcv2.h>
READ_BCR(ARC_REG_MCIP_BCR, mp);
sprintf(smp_cpuinfo_buf,
- "Extn [SMP]\t: ARConnect (v%d): %d cores with %s%s%s%s%s\n",
+ "Extn [SMP]\t: ARConnect (v%d): %d cores with %s%s%s%s\n",
mp.ver, mp.num_cores,
IS_AVAIL1(mp.ipi, "IPI "),
IS_AVAIL1(mp.idu, "IDU "),
- IS_AVAIL1(mp.llm, "LLM "),
IS_AVAIL1(mp.dbg, "DEBUG "),
IS_AVAIL1(mp.gfrc, "GFRC"));
raw_spin_unlock_irqrestore(&mcip_lock, flags);
}
-#ifdef CONFIG_SMP
static int
idu_irq_set_affinity(struct irq_data *data, const struct cpumask *cpumask,
bool force)
return IRQ_SET_MASK_OK;
}
-#endif
+
+static void idu_irq_enable(struct irq_data *data)
+{
+ /*
+ * By default send all common interrupts to all available online CPUs.
+ * The affinity of common interrupts in IDU must be set manually since
+ * in some cases the kernel will not call irq_set_affinity() by itself:
+ * 1. When the kernel is not configured with support of SMP.
+ * 2. When the kernel is configured with support of SMP but upper
+ * interrupt controllers does not support setting of the affinity
+ * and cannot propagate it to IDU.
+ */
+ idu_irq_set_affinity(data, cpu_online_mask, false);
+ idu_irq_unmask(data);
+}
static struct irq_chip idu_irq_chip = {
.name = "MCIP IDU Intc",
.irq_mask = idu_irq_mask,
.irq_unmask = idu_irq_unmask,
+ .irq_enable = idu_irq_enable,
#ifdef CONFIG_SMP
.irq_set_affinity = idu_irq_set_affinity,
#endif
static void idu_cascade_isr(struct irq_desc *desc)
{
struct irq_domain *idu_domain = irq_desc_get_handler_data(desc);
+ struct irq_chip *core_chip = irq_desc_get_chip(desc);
irq_hw_number_t core_hwirq = irqd_to_hwirq(irq_desc_get_irq_data(desc));
irq_hw_number_t idu_hwirq = core_hwirq - idu_first_hwirq;
+ chained_irq_enter(core_chip, desc);
generic_handle_irq(irq_find_mapping(idu_domain, idu_hwirq));
+ chained_irq_exit(core_chip, desc);
}
static int idu_irq_map(struct irq_domain *d, unsigned int virq, irq_hw_number_t hwirq)
const u32 *intspec, unsigned int intsize,
irq_hw_number_t *out_hwirq, unsigned int *out_type)
{
- irq_hw_number_t hwirq = *out_hwirq = intspec[0];
- int distri = intspec[1];
- unsigned long flags;
-
+ /*
+ * Ignore value of interrupt distribution mode for common interrupts in
+ * IDU which resides in intspec[1] since setting an affinity using value
+ * from Device Tree is deprecated in ARC.
+ */
+ *out_hwirq = intspec[0];
*out_type = IRQ_TYPE_NONE;
- /* XXX: validate distribution scheme again online cpu mask */
- if (distri == 0) {
- /* 0 - Round Robin to all cpus, otherwise 1 bit per core */
- raw_spin_lock_irqsave(&mcip_lock, flags);
- idu_set_dest(hwirq, BIT(num_online_cpus()) - 1);
- idu_set_mode(hwirq, IDU_M_TRIG_LEVEL, IDU_M_DISTRI_RR);
- raw_spin_unlock_irqrestore(&mcip_lock, flags);
- } else {
- /*
- * DEST based distribution for Level Triggered intr can only
- * have 1 CPU, so generalize it to always contain 1 cpu
- */
- int cpu = ffs(distri);
-
- if (cpu != fls(distri))
- pr_warn("IDU irq %lx distri mode set to cpu %x\n",
- hwirq, cpu);
-
- raw_spin_lock_irqsave(&mcip_lock, flags);
- idu_set_dest(hwirq, cpu);
- idu_set_mode(hwirq, IDU_M_TRIG_LEVEL, IDU_M_DISTRI_DEST);
- raw_spin_unlock_irqrestore(&mcip_lock, flags);
- }
-
return 0;
}
#ifdef CONFIG_ARC_DW2_UNWIND
mod->arch.unw_sec_idx = 0;
mod->arch.unw_info = NULL;
- mod->arch.secstr = secstr;
#endif
+ mod->arch.secstr = secstr;
return 0;
}
}
+#ifdef CONFIG_ARC_DW2_UNWIND
if (strcmp(module->arch.secstr+sechdrs[tgtsec].sh_name, ".eh_frame") == 0)
module->arch.unw_sec_idx = tgtsec;
+#endif
return 0;
*/
static volatile int wake_flag;
+#ifdef CONFIG_ISA_ARCOMPACT
+
+#define __boot_read(f) f
+#define __boot_write(f, v) f = v
+
+#else
+
+#define __boot_read(f) arc_read_uncached_32(&f)
+#define __boot_write(f, v) arc_write_uncached_32(&f, v)
+
+#endif
+
static void arc_default_smp_cpu_kick(int cpu, unsigned long pc)
{
BUG_ON(cpu == 0);
- wake_flag = cpu;
+
+ __boot_write(wake_flag, cpu);
}
void arc_platform_smp_wait_to_boot(int cpu)
{
- while (wake_flag != cpu)
+ /* for halt-on-reset, we've waited already */
+ if (IS_ENABLED(CONFIG_ARC_SMP_HALT_ON_RESET))
+ return;
+
+ while (__boot_read(wake_flag) != cpu)
;
- wake_flag = 0;
- __asm__ __volatile__("j @first_lines_of_secondary \n");
+ __boot_write(wake_flag, 0);
}
-
const char *arc_platform_smp_cpuinfo(void)
{
return plat_smp_ops.info ? : "";
if (state.fault)
goto fault;
+ /* clear any remanants of delay slot */
if (delay_mode(regs)) {
- regs->ret = regs->bta;
+ regs->ret = regs->bta ~1U;
regs->status32 &= ~STATUS_DE_MASK;
} else {
regs->ret += state.instr_len;
static int l2_line_sz;
static int ioc_exists;
-int slc_enable = 1, ioc_enable = 0;
+int slc_enable = 1, ioc_enable = 1;
unsigned long perip_base = ARC_UNCACHED_ADDR_SPACE; /* legacy value for boot */
unsigned long perip_end = 0xFFFFFFFF; /* legacy value */
/*
* For ARC700 MMUv3 I-cache and D-cache flushes
- * Also reused for HS38 aliasing I-cache configuration
+ * - ARC700 programming model requires paddr and vaddr be passed in seperate
+ * AUX registers (*_IV*L and *_PTAG respectively) irrespective of whether the
+ * caches actually alias or not.
+ * - For HS38, only the aliasing I-cache configuration uses the PTAG reg
+ * (non aliasing I-cache version doesn't; while D-cache can't possibly alias)
*/
static inline
void __cache_line_loop_v3(phys_addr_t paddr, unsigned long vaddr,
__after_dc_op(op);
}
+static inline void __dc_disable(void)
+{
+ const int r = ARC_REG_DC_CTRL;
+
+ __dc_entire_op(OP_FLUSH_N_INV);
+ write_aux_reg(r, read_aux_reg(r) | DC_CTRL_DIS);
+}
+
+static void __dc_enable(void)
+{
+ const int r = ARC_REG_DC_CTRL;
+
+ write_aux_reg(r, read_aux_reg(r) & ~DC_CTRL_DIS);
+}
+
/* For kernel mappings cache operation: index is same as paddr */
#define __dc_line_op_k(p, sz, op) __dc_line_op(p, p, sz, op)
#else
#define __dc_entire_op(op)
+#define __dc_disable()
+#define __dc_enable()
#define __dc_line_op(paddr, vaddr, sz, op)
#define __dc_line_op_k(paddr, sz, op)
#endif
}
+noinline static void slc_entire_op(const int op)
+{
+ unsigned int ctrl, r = ARC_REG_SLC_CTRL;
+
+ ctrl = read_aux_reg(r);
+
+ if (!(op & OP_FLUSH)) /* i.e. OP_INV */
+ ctrl &= ~SLC_CTRL_IM; /* clear IM: Disable flush before Inv */
+ else
+ ctrl |= SLC_CTRL_IM;
+
+ write_aux_reg(r, ctrl);
+
+ write_aux_reg(ARC_REG_SLC_INVALIDATE, 1);
+
+ /* Important to wait for flush to complete */
+ while (read_aux_reg(r) & SLC_CTRL_BUSY);
+}
+
+static inline void arc_slc_disable(void)
+{
+ const int r = ARC_REG_SLC_CTRL;
+
+ slc_entire_op(OP_FLUSH_N_INV);
+ write_aux_reg(r, read_aux_reg(r) | SLC_CTRL_DIS);
+}
+
+static inline void arc_slc_enable(void)
+{
+ const int r = ARC_REG_SLC_CTRL;
+
+ write_aux_reg(r, read_aux_reg(r) & ~SLC_CTRL_DIS);
+}
+
/***********************************************************
* Exported APIs
*/
return 0;
}
-void arc_cache_init(void)
+/*
+ * IO-Coherency (IOC) setup rules:
+ *
+ * 1. Needs to be at system level, so only once by Master core
+ * Non-Masters need not be accessing caches at that time
+ * - They are either HALT_ON_RESET and kick started much later or
+ * - if run on reset, need to ensure that arc_platform_smp_wait_to_boot()
+ * doesn't perturb caches or coherency unit
+ *
+ * 2. caches (L1 and SLC) need to be purged (flush+inv) before setting up IOC,
+ * otherwise any straggler data might behave strangely post IOC enabling
+ *
+ * 3. All Caches need to be disabled when setting up IOC to elide any in-flight
+ * Coherency transactions
+ */
+noinline void __init arc_ioc_setup(void)
{
- unsigned int __maybe_unused cpu = smp_processor_id();
- char str[256];
+ unsigned int ap_sz;
- printk(arc_cache_mumbojumbo(0, str, sizeof(str)));
+ /* Flush + invalidate + disable L1 dcache */
+ __dc_disable();
+
+ /* Flush + invalidate SLC */
+ if (read_aux_reg(ARC_REG_SLC_BCR))
+ slc_entire_op(OP_FLUSH_N_INV);
+
+ /* IOC Aperture start: TDB: handle non default CONFIG_LINUX_LINK_BASE */
+ write_aux_reg(ARC_REG_IO_COH_AP0_BASE, 0x80000);
/*
- * Only master CPU needs to execute rest of function:
- * - Assume SMP so all cores will have same cache config so
- * any geomtry checks will be same for all
- * - IOC setup / dma callbacks only need to be setup once
+ * IOC Aperture size:
+ * decoded as 2 ^ (SIZE + 2) KB: so setting 0x11 implies 512M
+ * TBD: fix for PGU + 1GB of low mem
+ * TBD: fix for PAE
*/
- if (cpu)
- return;
+ ap_sz = order_base_2(arc_get_mem_sz()/1024) - 2;
+ write_aux_reg(ARC_REG_IO_COH_AP0_SIZE, ap_sz);
+
+ write_aux_reg(ARC_REG_IO_COH_PARTIAL, 1);
+ write_aux_reg(ARC_REG_IO_COH_ENABLE, 1);
+
+ /* Re-enable L1 dcache */
+ __dc_enable();
+}
+
+void __init arc_cache_init_master(void)
+{
+ unsigned int __maybe_unused cpu = smp_processor_id();
if (IS_ENABLED(CONFIG_ARC_HAS_ICACHE)) {
struct cpuinfo_arc_cache *ic = &cpuinfo_arc700[cpu].icache;
}
}
- if (is_isa_arcv2() && l2_line_sz && !slc_enable) {
-
- /* IM set : flush before invalidate */
- write_aux_reg(ARC_REG_SLC_CTRL,
- read_aux_reg(ARC_REG_SLC_CTRL) | SLC_CTRL_IM);
+ /* Note that SLC disable not formally supported till HS 3.0 */
+ if (is_isa_arcv2() && l2_line_sz && !slc_enable)
+ arc_slc_disable();
- write_aux_reg(ARC_REG_SLC_INVALIDATE, 1);
-
- /* Important to wait for flush to complete */
- while (read_aux_reg(ARC_REG_SLC_CTRL) & SLC_CTRL_BUSY);
- write_aux_reg(ARC_REG_SLC_CTRL,
- read_aux_reg(ARC_REG_SLC_CTRL) | SLC_CTRL_DISABLE);
- }
+ if (is_isa_arcv2() && ioc_enable)
+ arc_ioc_setup();
if (is_isa_arcv2() && ioc_enable) {
- /* IO coherency base - 0x8z */
- write_aux_reg(ARC_REG_IO_COH_AP0_BASE, 0x80000);
- /* IO coherency aperture size - 512Mb: 0x8z-0xAz */
- write_aux_reg(ARC_REG_IO_COH_AP0_SIZE, 0x11);
- /* Enable partial writes */
- write_aux_reg(ARC_REG_IO_COH_PARTIAL, 1);
- /* Enable IO coherency */
- write_aux_reg(ARC_REG_IO_COH_ENABLE, 1);
-
__dma_cache_wback_inv = __dma_cache_wback_inv_ioc;
__dma_cache_inv = __dma_cache_inv_ioc;
__dma_cache_wback = __dma_cache_wback_ioc;
__dma_cache_wback = __dma_cache_wback_l1;
}
}
+
+void __ref arc_cache_init(void)
+{
+ unsigned int __maybe_unused cpu = smp_processor_id();
+ char str[256];
+
+ printk(arc_cache_mumbojumbo(0, str, sizeof(str)));
+
+ /*
+ * Only master CPU needs to execute rest of function:
+ * - Assume SMP so all cores will have same cache config so
+ * any geomtry checks will be same for all
+ * - IOC setup / dma callbacks only need to be setup once
+ */
+ if (!cpu)
+ arc_cache_init_master();
+}
EXPORT_SYMBOL(node_data);
#endif
+long __init arc_get_mem_sz(void)
+{
+ return low_mem_sz;
+}
+
/* User can over-ride above with "mem=nnn[KkMm]" in cmdline */
static int __init setup_mem_sz(char *str)
{
sun8i-a83t-allwinner-h8homlet-v2.dtb \
sun8i-a83t-cubietruck-plus.dtb \
sun8i-h3-bananapi-m2-plus.dtb \
+ sun8i-h3-nanopi-m1.dtb \
sun8i-h3-nanopi-neo.dtb \
sun8i-h3-orangepi-2.dtb \
sun8i-h3-orangepi-lite.dtb \
AM33XX_IOPAD(0x8fc, PIN_INPUT_PULLUP | MUX_MODE0) /* (G16) mmc0_dat0.mmc0_dat0 */
AM33XX_IOPAD(0x900, PIN_INPUT_PULLUP | MUX_MODE0) /* (G17) mmc0_clk.mmc0_clk */
AM33XX_IOPAD(0x904, PIN_INPUT_PULLUP | MUX_MODE0) /* (G18) mmc0_cmd.mmc0_cmd */
- AM33XX_IOPAD(0x960, PIN_INPUT_PULLUP | MUX_MODE5) /* (C15) spi0_cs1.mmc0_sdcd */
>;
};
axi {
compatible = "simple-bus";
- ranges = <0x00000000 0x18000000 0x0011c40a>;
+ ranges = <0x00000000 0x18000000 0x0011c40c>;
#address-cells = <1>;
#size-cells = <1>;
#size-cells = <1>;
compatible = "m25p64";
spi-max-frequency = <30000000>;
+ m25p,fast-read;
reg = <0>;
partition@0 {
label = "U-Boot-SPL";
phy-names = "sata-phy";
clocks = <&sata_ref_clk>;
ti,hwmods = "sata";
+ ports-implemented = <0x1>;
};
rtc: rtc@48838000 {
ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_25_NS>;
ti,tx-internal-delay = <DP83867_RGMIIDCTL_250_PS>;
ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_8_B_NIB>;
- ti,min-output-imepdance;
+ ti,min-output-impedance;
};
};
compatible = "fsl,imx6q-nitrogen6_max-sgtl5000",
"fsl,imx-audio-sgtl5000";
model = "imx6q-nitrogen6_max-sgtl5000";
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_sgtl5000>;
ssi-controller = <&ssi1>;
audio-codec = <&codec>;
audio-routing =
codec: sgtl5000@0a {
compatible = "fsl,sgtl5000";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_sgtl5000>;
reg = <0x0a>;
clocks = <&clks IMX6QDL_CLK_CKO>;
VDDA-supply = <®_2p5v>;
compatible = "fsl,imx6q-nitrogen6_som2-sgtl5000",
"fsl,imx-audio-sgtl5000";
model = "imx6q-nitrogen6_som2-sgtl5000";
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_sgtl5000>;
ssi-controller = <&ssi1>;
audio-codec = <&codec>;
audio-routing =
codec: sgtl5000@0a {
compatible = "fsl,sgtl5000";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_sgtl5000>;
reg = <0x0a>;
clocks = <&clks IMX6QDL_CLK_CKO>;
VDDA-supply = <®_2p5v>;
&mmc1 {
interrupts-extended = <&intc 83 &omap3_pmx_core 0x11a>;
pinctrl-names = "default";
- pinctrl-0 = <&mmc1_pins &mmc1_cd>;
+ pinctrl-0 = <&mmc1_pins>;
wp-gpios = <&gpio4 30 GPIO_ACTIVE_HIGH>; /* gpio_126 */
cd-gpios = <&gpio4 14 IRQ_TYPE_LEVEL_LOW>; /* gpio_110 */
vmmc-supply = <&vmmc1>;
OMAP3_CORE1_IOPAD(0x214a, PIN_INPUT | MUX_MODE0) /* sdmmc1_dat1.sdmmc1_dat1 */
OMAP3_CORE1_IOPAD(0x214c, PIN_INPUT | MUX_MODE0) /* sdmmc1_dat2.sdmmc1_dat2 */
OMAP3_CORE1_IOPAD(0x214e, PIN_INPUT | MUX_MODE0) /* sdmmc1_dat3.sdmmc1_dat3 */
- OMAP3_CORE1_IOPAD(0x2132, PIN_INPUT_PULLUP | MUX_MODE4) /* cam_strobe.gpio_126 sdmmc1_wp*/
+ OMAP3_CORE1_IOPAD(0x2132, PIN_INPUT_PULLUP | MUX_MODE4) /* cam_strobe.gpio_126 */
+ OMAP3_CORE1_IOPAD(0x212c, PIN_INPUT_PULLUP | MUX_MODE4) /* cam_d11.gpio_110 */
>;
};
OMAP3_WKUP_IOPAD(0x2a16, PIN_OUTPUT | PIN_OFF_OUTPUT_LOW | MUX_MODE4) /* sys_boot6.gpio_8 */
>;
};
-
- mmc1_cd: pinmux_mmc1_cd {
- pinctrl-single,pins = <
- OMAP3_WKUP_IOPAD(0x212c, PIN_INPUT_PULLUP | MUX_MODE4) /* cam_d11.gpio_110 */
- >;
- };
};
phy-names = "sata-phy";
clocks = <&sata_ref_clk>;
ti,hwmods = "sata";
+ ports-implemented = <0x1>;
};
dss: dss@58000000 {
};
amba {
- compatible = "arm,amba-bus";
+ compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
ranges;
cpu-supply = <®_dcdc3>;
};
+&de {
+ status = "okay";
+};
+
&ehci0 {
status = "okay";
};
de: display-engine {
compatible = "allwinner,sun6i-a31-display-engine";
allwinner,pipelines = <&fe0>;
+ status = "disabled";
};
soc@01c00000 {
};
&pio {
- mmc2_pins_nrst: mmc2@0 {
+ mmc2_pins_nrst: mmc2-rst-pin {
allwinner,pins = "PC16";
allwinner,function = "gpio_out";
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
CONFIG_DW_WATCHDOG=y
CONFIG_DIGICOLOR_WATCHDOG=y
CONFIG_BCM2835_WDT=y
-CONFIG_BCM47XX_WATCHDOG=y
+CONFIG_BCM47XX_WDT=y
CONFIG_BCM7038_WDT=m
CONFIG_BCM_KONA_WDT=y
CONFIG_MFD_ACT8945A=y
CONFIG_RASPBERRYPI_FIRMWARE=y
CONFIG_EFI_VARS=m
CONFIG_EFI_CAPSULE_LOADER=m
-CONFIG_CONFIG_BCM47XX_NVRAM=y
+CONFIG_BCM47XX_NVRAM=y
CONFIG_BCM47XX_SPROM=y
CONFIG_EXT4_FS=y
CONFIG_AUTOFS4_FS=y
CONFIG_NETFILTER=y
CONFIG_NF_CONNTRACK=m
CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_DCCP=m
-CONFIG_NF_CT_PROTO_SCTP=m
-CONFIG_NF_CT_PROTO_UDPLITE=m
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
CONFIG_NF_CONNTRACK_AMANDA=m
CONFIG_NF_CONNTRACK_FTP=m
CONFIG_NF_CONNTRACK_H323=m
#define ARM_CPU_XSCALE_ARCH_V2 0x4000
#define ARM_CPU_XSCALE_ARCH_V3 0x6000
+/* Qualcomm implemented cores */
+#define ARM_CPU_PART_SCORPION 0x510002d0
+
extern unsigned int processor_id;
#ifdef CONFIG_CPU_CP15
#define ftrace_return_address(n) return_address(n)
+#define ARCH_HAS_SYSCALL_MATCH_SYM_NAME
+
+static inline bool arch_syscall_match_sym_name(const char *sym,
+ const char *name)
+{
+ if (!strcmp(sym, "sys_mmap2"))
+ sym = "sys_mmap_pgoff";
+ else if (!strcmp(sym, "sys_statfs64_wrapper"))
+ sym = "sys_statfs64";
+ else if (!strcmp(sym, "sys_fstatfs64_wrapper"))
+ sym = "sys_fstatfs64";
+ else if (!strcmp(sym, "sys_arm_fadvise64_64"))
+ sym = "sys_fadvise64_64";
+
+ /* Ignore case since sym may start with "SyS" instead of "sys" */
+ return !strcasecmp(sym, name);
+}
+
#endif /* ifndef __ASSEMBLY__ */
#endif /* _ASM_ARM_FTRACE */
+++ /dev/null
-#ifndef _ASM_TYPES_H
-#define _ASM_TYPES_H
-
-#include <asm-generic/int-ll64.h>
-
-/*
- * The C99 types uintXX_t that are usually defined in 'stdint.h' are not as
- * unambiguous on ARM as you would expect. For the types below, there is a
- * difference on ARM between GCC built for bare metal ARM, GCC built for glibc
- * and the kernel itself, which results in build errors if you try to build with
- * -ffreestanding and include 'stdint.h' (such as when you include 'arm_neon.h'
- * in order to use NEON intrinsics)
- *
- * As the typedefs for these types in 'stdint.h' are based on builtin defines
- * supplied by GCC, we can tweak these to align with the kernel's idea of those
- * types, so 'linux/types.h' and 'stdint.h' can be safely included from the same
- * source file (provided that -ffreestanding is used).
- *
- * int32_t uint32_t uintptr_t
- * bare metal GCC long unsigned long unsigned int
- * glibc GCC int unsigned int unsigned int
- * kernel int unsigned int unsigned long
- */
-
-#ifdef __INT32_TYPE__
-#undef __INT32_TYPE__
-#define __INT32_TYPE__ int
-#endif
-
-#ifdef __UINT32_TYPE__
-#undef __UINT32_TYPE__
-#define __UINT32_TYPE__ unsigned int
-#endif
-
-#ifdef __UINTPTR_TYPE__
-#undef __UINTPTR_TYPE__
-#define __UINTPTR_TYPE__ unsigned long
-#endif
-
-#endif /* _ASM_TYPES_H */
return false;
}
+static inline bool has_vhe(void)
+{
+ return false;
+}
+
/* The section containing the hypervisor idmap text */
extern char __hyp_idmap_text_start[];
extern char __hyp_idmap_text_end[];
--- /dev/null
+#ifndef _UAPI_ASM_TYPES_H
+#define _UAPI_ASM_TYPES_H
+
+#include <asm-generic/int-ll64.h>
+
+/*
+ * The C99 types uintXX_t that are usually defined in 'stdint.h' are not as
+ * unambiguous on ARM as you would expect. For the types below, there is a
+ * difference on ARM between GCC built for bare metal ARM, GCC built for glibc
+ * and the kernel itself, which results in build errors if you try to build with
+ * -ffreestanding and include 'stdint.h' (such as when you include 'arm_neon.h'
+ * in order to use NEON intrinsics)
+ *
+ * As the typedefs for these types in 'stdint.h' are based on builtin defines
+ * supplied by GCC, we can tweak these to align with the kernel's idea of those
+ * types, so 'linux/types.h' and 'stdint.h' can be safely included from the same
+ * source file (provided that -ffreestanding is used).
+ *
+ * int32_t uint32_t uintptr_t
+ * bare metal GCC long unsigned long unsigned int
+ * glibc GCC int unsigned int unsigned int
+ * kernel int unsigned int unsigned long
+ */
+
+#ifdef __INT32_TYPE__
+#undef __INT32_TYPE__
+#define __INT32_TYPE__ int
+#endif
+
+#ifdef __UINT32_TYPE__
+#undef __UINT32_TYPE__
+#define __UINT32_TYPE__ unsigned int
+#endif
+
+#ifdef __UINTPTR_TYPE__
+#undef __UINTPTR_TYPE__
+#define __UINTPTR_TYPE__ unsigned long
+#endif
+
+#endif /* _UAPI_ASM_TYPES_H */
return 0;
}
+ /*
+ * Scorpion CPUs (at least those in APQ8060) seem to set DBGPRSR.SPD
+ * whenever a WFI is issued, even if the core is not powered down, in
+ * violation of the architecture. When DBGPRSR.SPD is set, accesses to
+ * breakpoint and watchpoint registers are treated as undefined, so
+ * this results in boot time and runtime failures when these are
+ * accessed and we unexpectedly take a trap.
+ *
+ * It's not clear if/how this can be worked around, so we blacklist
+ * Scorpion CPUs to avoid these issues.
+ */
+ if (read_cpuid_part() == ARM_CPU_PART_SCORPION) {
+ pr_info("Scorpion CPU detected. Hardware breakpoints and watchpoints disabled\n");
+ return 0;
+ }
+
has_ossr = core_has_os_save_restore();
/* Determine how many BRPs/WRPs are available. */
*/
#include <linux/preempt.h>
#include <linux/smp.h>
+#include <linux/uaccess.h>
#include <asm/smp_plat.h>
#include <asm/tlbflush.h>
static inline void ipi_flush_tlb_page(void *arg)
{
struct tlb_args *ta = (struct tlb_args *)arg;
+ unsigned int __ua_flags = uaccess_save_and_enable();
local_flush_tlb_page(ta->ta_vma, ta->ta_start);
+
+ uaccess_restore(__ua_flags);
}
static inline void ipi_flush_tlb_kernel_page(void *arg)
static inline void ipi_flush_tlb_range(void *arg)
{
struct tlb_args *ta = (struct tlb_args *)arg;
+ unsigned int __ua_flags = uaccess_save_and_enable();
local_flush_tlb_range(ta->ta_vma, ta->ta_start, ta->ta_end);
+
+ uaccess_restore(__ua_flags);
}
static inline void ipi_flush_tlb_kernel_range(void *arg)
__cpu_init_hyp_mode(pgd_ptr, hyp_stack_ptr, vector_ptr);
__cpu_init_stage2();
+ if (is_kernel_in_hyp_mode())
+ kvm_timer_init_vhe();
+
kvm_arm_init_debug();
}
#include "soc.h"
#define OMAP1_DMA_BASE (0xfffed800)
-#define OMAP1_LOGICAL_DMA_CH_COUNT 17
static u32 enable_1510_mode;
goto exit_iounmap;
}
- d->lch_count = OMAP1_LOGICAL_DMA_CH_COUNT;
-
/* Valid attributes for omap1 plus processors */
if (cpu_is_omap15xx())
d->dev_caps = ENABLE_1510_MODE;
d->dev_caps |= CLEAR_CSR_ON_READ;
d->dev_caps |= IS_WORD_16;
- if (cpu_is_omap15xx())
- d->chan_count = 9;
- else if (cpu_is_omap16xx() || cpu_is_omap7xx()) {
- if (!(d->dev_caps & ENABLE_1510_MODE))
- d->chan_count = 16;
+ /* available logical channels */
+ if (cpu_is_omap15xx()) {
+ d->lch_count = 9;
+ } else {
+ if (d->dev_caps & ENABLE_1510_MODE)
+ d->lch_count = 9;
else
- d->chan_count = 9;
+ d->lch_count = 16;
}
p = dma_plat_info;
.nshutdown_gpio = 162,
.dev_name = "/dev/ttyO1",
.flow_cntrl = 1,
- .baud_rate = 300000,
+ .baud_rate = 3000000,
};
static struct platform_device wl128x_device = {
*/
bool prcmu_is_cpu_in_wfi(int cpu)
{
- return readl(PRCM_ARM_WFI_STANDBY) & cpu ? PRCM_ARM_WFI_STANDBY_WFI1 :
- PRCM_ARM_WFI_STANDBY_WFI0;
+ return readl(PRCM_ARM_WFI_STANDBY) &
+ (cpu ? PRCM_ARM_WFI_STANDBY_WFI1 : PRCM_ARM_WFI_STANDBY_WFI0);
}
/*
};
};
+&scpi_clocks {
+ status = "disabled";
+};
+
&uart_AO {
status = "okay";
pinctrl-0 = <&uart_ao_a_pins>;
mboxes = <&mailbox 1 &mailbox 2>;
shmem = <&cpu_scp_lpri &cpu_scp_hpri>;
- clocks {
+ scpi_clocks: clocks {
compatible = "arm,scpi-clocks";
scpi_dvfs: scpi_clocks@0 {
};
amba {
- compatible = "arm,amba-bus";
+ compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
ranges;
stdout-path = "serial0:115200n8";
};
- memory {
+ memory@0 {
device_type = "memory";
reg = <0x0 0x0 0x0 0x40000000>;
};
<1 10 0xf08>;
};
- amba_apu {
+ amba_apu: amba_apu@0 {
compatible = "simple-bus";
#address-cells = <2>;
#size-cells = <1>;
};
i2c0: i2c@ff020000 {
- compatible = "cdns,i2c-r1p10";
+ compatible = "cdns,i2c-r1p14", "cdns,i2c-r1p10";
status = "disabled";
interrupt-parent = <&gic>;
interrupts = <0 17 4>;
};
i2c1: i2c@ff030000 {
- compatible = "cdns,i2c-r1p10";
+ compatible = "cdns,i2c-r1p14", "cdns,i2c-r1p10";
status = "disabled";
interrupt-parent = <&gic>;
interrupts = <0 18 4>;
cbz w6, .Lcbcencloop
ld1 {v0.16b}, [x5] /* get iv */
- enc_prepare w3, x2, x5
+ enc_prepare w3, x2, x6
.Lcbcencloop:
ld1 {v1.16b}, [x1], #16 /* get next pt block */
eor v0.16b, v0.16b, v1.16b /* ..and xor with iv */
- encrypt_block v0, w3, x2, x5, w6
+ encrypt_block v0, w3, x2, x6, w7
st1 {v0.16b}, [x0], #16
subs w4, w4, #1
bne .Lcbcencloop
+ st1 {v0.16b}, [x5] /* return iv */
ret
AES_ENDPROC(aes_cbc_encrypt)
cbz w6, .LcbcdecloopNx
ld1 {v7.16b}, [x5] /* get iv */
- dec_prepare w3, x2, x5
+ dec_prepare w3, x2, x6
.LcbcdecloopNx:
#if INTERLEAVE >= 2
.Lcbcdecloop:
ld1 {v1.16b}, [x1], #16 /* get next ct block */
mov v0.16b, v1.16b /* ...and copy to v0 */
- decrypt_block v0, w3, x2, x5, w6
+ decrypt_block v0, w3, x2, x6, w7
eor v0.16b, v0.16b, v7.16b /* xor with iv => pt */
mov v7.16b, v1.16b /* ct is next iv */
st1 {v0.16b}, [x0], #16
bne .Lcbcdecloop
.Lcbcdecout:
FRAME_POP
+ st1 {v7.16b}, [x5] /* return iv */
ret
AES_ENDPROC(aes_cbc_decrypt)
AES_ENTRY(aes_ctr_encrypt)
FRAME_PUSH
- cbnz w6, .Lctrfirst /* 1st time around? */
- umov x5, v4.d[1] /* keep swabbed ctr in reg */
- rev x5, x5
-#if INTERLEAVE >= 2
- cmn w5, w4 /* 32 bit overflow? */
- bcs .Lctrinc
- add x5, x5, #1 /* increment BE ctr */
- b .LctrincNx
-#else
- b .Lctrinc
-#endif
-.Lctrfirst:
+ cbz w6, .Lctrnotfirst /* 1st time around? */
enc_prepare w3, x2, x6
ld1 {v4.16b}, [x5]
- umov x5, v4.d[1] /* keep swabbed ctr in reg */
- rev x5, x5
+
+.Lctrnotfirst:
+ umov x8, v4.d[1] /* keep swabbed ctr in reg */
+ rev x8, x8
#if INTERLEAVE >= 2
- cmn w5, w4 /* 32 bit overflow? */
+ cmn w8, w4 /* 32 bit overflow? */
bcs .Lctrloop
.LctrloopNx:
subs w4, w4, #INTERLEAVE
#if INTERLEAVE == 2
mov v0.8b, v4.8b
mov v1.8b, v4.8b
- rev x7, x5
- add x5, x5, #1
+ rev x7, x8
+ add x8, x8, #1
ins v0.d[1], x7
- rev x7, x5
- add x5, x5, #1
+ rev x7, x8
+ add x8, x8, #1
ins v1.d[1], x7
ld1 {v2.16b-v3.16b}, [x1], #32 /* get 2 input blocks */
do_encrypt_block2x
st1 {v0.16b-v1.16b}, [x0], #32
#else
ldr q8, =0x30000000200000001 /* addends 1,2,3[,0] */
- dup v7.4s, w5
+ dup v7.4s, w8
mov v0.16b, v4.16b
add v7.4s, v7.4s, v8.4s
mov v1.16b, v4.16b
eor v2.16b, v7.16b, v2.16b
eor v3.16b, v5.16b, v3.16b
st1 {v0.16b-v3.16b}, [x0], #64
- add x5, x5, #INTERLEAVE
+ add x8, x8, #INTERLEAVE
#endif
- cbz w4, .LctroutNx
-.LctrincNx:
- rev x7, x5
+ rev x7, x8
ins v4.d[1], x7
+ cbz w4, .Lctrout
b .LctrloopNx
-.LctroutNx:
- sub x5, x5, #1
- rev x7, x5
- ins v4.d[1], x7
- b .Lctrout
.Lctr1x:
adds w4, w4, #INTERLEAVE
beq .Lctrout
.Lctrloop:
mov v0.16b, v4.16b
encrypt_block v0, w3, x2, x6, w7
+
+ adds x8, x8, #1 /* increment BE ctr */
+ rev x7, x8
+ ins v4.d[1], x7
+ bcs .Lctrcarry /* overflow? */
+
+.Lctrcarrydone:
subs w4, w4, #1
bmi .Lctrhalfblock /* blocks < 0 means 1/2 block */
ld1 {v3.16b}, [x1], #16
eor v3.16b, v0.16b, v3.16b
st1 {v3.16b}, [x0], #16
- beq .Lctrout
-.Lctrinc:
- adds x5, x5, #1 /* increment BE ctr */
- rev x7, x5
- ins v4.d[1], x7
- bcc .Lctrloop /* no overflow? */
- umov x7, v4.d[0] /* load upper word of ctr */
- rev x7, x7 /* ... to handle the carry */
- add x7, x7, #1
- rev x7, x7
- ins v4.d[0], x7
- b .Lctrloop
+ bne .Lctrloop
+
+.Lctrout:
+ st1 {v4.16b}, [x5] /* return next CTR value */
+ FRAME_POP
+ ret
+
.Lctrhalfblock:
ld1 {v3.8b}, [x1]
eor v3.8b, v0.8b, v3.8b
st1 {v3.8b}, [x0]
-.Lctrout:
FRAME_POP
ret
+
+.Lctrcarry:
+ umov x7, v4.d[0] /* load upper word of ctr */
+ rev x7, x7 /* ... to handle the carry */
+ add x7, x7, #1
+ rev x7, x7
+ ins v4.d[0], x7
+ b .Lctrcarrydone
AES_ENDPROC(aes_ctr_encrypt)
.ltorg
/*
* Pseudo-ops for PC-relative adr/ldr/str <reg>, <symbol> where
- * <symbol> is within the range +/- 4 GB of the PC.
+ * <symbol> is within the range +/- 4 GB of the PC when running
+ * in core kernel context. In module context, a movz/movk sequence
+ * is used, since modules may be loaded far away from the kernel
+ * when KASLR is in effect.
*/
/*
* @dst: destination register (64 bit wide)
* @sym: name of the symbol
- * @tmp: optional scratch register to be used if <dst> == sp, which
- * is not allowed in an adrp instruction
*/
- .macro adr_l, dst, sym, tmp=
- .ifb \tmp
+ .macro adr_l, dst, sym
+#ifndef MODULE
adrp \dst, \sym
add \dst, \dst, :lo12:\sym
- .else
- adrp \tmp, \sym
- add \dst, \tmp, :lo12:\sym
- .endif
+#else
+ movz \dst, #:abs_g3:\sym
+ movk \dst, #:abs_g2_nc:\sym
+ movk \dst, #:abs_g1_nc:\sym
+ movk \dst, #:abs_g0_nc:\sym
+#endif
.endm
/*
* the address
*/
.macro ldr_l, dst, sym, tmp=
+#ifndef MODULE
.ifb \tmp
adrp \dst, \sym
ldr \dst, [\dst, :lo12:\sym]
adrp \tmp, \sym
ldr \dst, [\tmp, :lo12:\sym]
.endif
+#else
+ .ifb \tmp
+ adr_l \dst, \sym
+ ldr \dst, [\dst]
+ .else
+ adr_l \tmp, \sym
+ ldr \dst, [\tmp]
+ .endif
+#endif
.endm
/*
* while <src> needs to be preserved.
*/
.macro str_l, src, sym, tmp
+#ifndef MODULE
adrp \tmp, \sym
str \src, [\tmp, :lo12:\sym]
+#else
+ adr_l \tmp, \sym
+ str \src, [\tmp]
+#endif
.endm
/*
#define _virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
#else
#define __virt_to_pgoff(kaddr) (((u64)(kaddr) & ~PAGE_OFFSET) / PAGE_SIZE * sizeof(struct page))
-#define __page_to_voff(page) (((u64)(page) & ~VMEMMAP_START) * PAGE_SIZE / sizeof(struct page))
+#define __page_to_voff(kaddr) (((u64)(kaddr) & ~VMEMMAP_START) * PAGE_SIZE / sizeof(struct page))
#define page_to_virt(page) ((void *)((__page_to_voff(page)) | PAGE_OFFSET))
#define virt_to_page(vaddr) ((struct page *)((__virt_to_pgoff(vaddr)) | VMEMMAP_START))
#include <asm/ptrace.h>
#include <asm/sections.h>
#include <asm/sysreg.h>
+#include <asm/cpufeature.h>
/*
* __boot_cpu_mode records what mode CPUs were booted in.
return read_sysreg(CurrentEL) == CurrentEL_EL2;
}
+static inline bool has_vhe(void)
+{
+ if (cpus_have_const_cap(ARM64_HAS_VIRT_HOST_EXTN))
+ return true;
+
+ return false;
+}
+
#ifdef CONFIG_ARM64_VHE
extern void verify_cpu_run_el(void);
#else
__uint128_t vregs[32];
__u32 fpsr;
__u32 fpcr;
+ __u32 __reserved[2];
};
struct user_hwdebug_state {
mov x0, sp
mov x1, #BAD_SYNC
mov x2, x25
- bl bad_mode
+ bl bad_el0_sync
b ret_to_user
ENDPROC(el0_sync)
/* (address, ctrl) registers */
limit = regset->n * regset->size;
while (count && offset < limit) {
+ if (count < PTRACE_HBP_ADDR_SZ)
+ return -EINVAL;
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &addr,
offset, offset + PTRACE_HBP_ADDR_SZ);
if (ret)
return ret;
offset += PTRACE_HBP_ADDR_SZ;
+ if (!count)
+ break;
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &ctrl,
offset, offset + PTRACE_HBP_CTRL_SZ);
if (ret)
const void *kbuf, const void __user *ubuf)
{
int ret;
- struct user_pt_regs newregs;
+ struct user_pt_regs newregs = task_pt_regs(target)->user_regs;
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newregs, 0, -1);
if (ret)
const void *kbuf, const void __user *ubuf)
{
int ret;
- struct user_fpsimd_state newstate;
+ struct user_fpsimd_state newstate =
+ target->thread.fpsimd_state.user_fpsimd;
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &newstate, 0, -1);
if (ret)
const void *kbuf, const void __user *ubuf)
{
int ret;
- unsigned long tls;
+ unsigned long tls = target->thread.tp_value;
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &tls, 0, -1);
if (ret)
unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf)
{
- int syscallno, ret;
+ int syscallno = task_pt_regs(target)->syscallno;
+ int ret;
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &syscallno, 0, -1);
if (ret)
const void __user *ubuf)
{
int ret;
- compat_ulong_t tls;
+ compat_ulong_t tls = target->thread.tp_value;
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &tls, 0, -1);
if (ret)
* for more details.
*/
+#include <linux/acpi.h>
#include <linux/cpu.h>
#include <linux/cpumask.h>
#include <linux/init.h>
static int __init register_cpufreq_notifier(void)
{
- if (cap_parsing_failed)
+ /*
+ * on ACPI-based systems we need to use the default cpu capacity
+ * until we have the necessary code to parse the cpu capacity, so
+ * skip registering cpufreq notifier.
+ */
+ if (!acpi_disabled || cap_parsing_failed)
return -EINVAL;
if (!alloc_cpumask_var(&cpus_to_visit, GFP_KERNEL)) {
}
/*
- * bad_mode handles the impossible case in the exception vector.
+ * bad_mode handles the impossible case in the exception vector. This is always
+ * fatal.
*/
asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr)
{
- siginfo_t info;
- void __user *pc = (void __user *)instruction_pointer(regs);
console_verbose();
pr_crit("Bad mode in %s handler detected on CPU%d, code 0x%08x -- %s\n",
handler[reason], smp_processor_id(), esr,
esr_get_class_string(esr));
+
+ die("Oops - bad mode", regs, 0);
+ local_irq_disable();
+ panic("bad mode");
+}
+
+/*
+ * bad_el0_sync handles unexpected, but potentially recoverable synchronous
+ * exceptions taken from EL0. Unlike bad_mode, this returns.
+ */
+asmlinkage void bad_el0_sync(struct pt_regs *regs, int reason, unsigned int esr)
+{
+ siginfo_t info;
+ void __user *pc = (void __user *)instruction_pointer(regs);
+ console_verbose();
+
+ pr_crit("Bad EL0 synchronous exception detected on CPU%d, code 0x%08x -- %s\n",
+ smp_processor_id(), esr, esr_get_class_string(esr));
__show_regs(regs);
info.si_signo = SIGILL;
info.si_code = ILL_ILLOPC;
info.si_addr = pc;
- arm64_notify_die("Oops - bad mode", regs, &info, 0);
+ current->thread.fault_address = 0;
+ current->thread.fault_code = 0;
+
+ force_sig_info(info.si_signo, &info, current);
}
void __pte_error(const char *file, int line, unsigned long val)
ncontig = find_num_contig(vma->vm_mm, addr, cpte,
*cpte, &pgsize);
for (i = 0; i < ncontig; ++i, ++cpte, addr += pgsize) {
- changed = ptep_set_access_flags(vma, addr, cpte,
+ changed |= ptep_set_access_flags(vma, addr, cpte,
pfn_pte(pfn,
hugeprot),
dirty);
if (swiotlb_force == SWIOTLB_FORCE ||
max_pfn > (arm64_dma_phys_limit >> PAGE_SHIFT))
swiotlb_init(1);
+ else
+ swiotlb_force = SWIOTLB_NO_FORCE;
set_max_mapnr(pfn_to_page(max_pfn) - mem_map);
#define atomic64_sub_and_test(i,v) (atomic64_sub_return((i), (v)) == 0)
#define atomic64_dec_and_test(v) (atomic64_dec_return((v)) == 0)
#define atomic64_inc_and_test(v) (atomic64_inc_return((v)) == 0)
-
+#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
#define atomic_cmpxchg(v, old, new) (cmpxchg(&(v)->counter, old, new))
#define atomic_xchg(v, new) (xchg(&(v)->counter, new))
return c;
}
+static inline int atomic64_add_unless(atomic64_t *v, long long i, long long u)
+{
+ long long c, old;
+
+ c = atomic64_read(v);
+ for (;;) {
+ if (unlikely(c == u))
+ break;
+ old = atomic64_cmpxchg(v, c, c + i);
+ if (likely(old == c))
+ break;
+ c = old;
+ }
+ return c != u;
+}
+
+static inline long long atomic64_dec_if_positive(atomic64_t *v)
+{
+ long long c, old, dec;
+
+ c = atomic64_read(v);
+ for (;;) {
+ dec = c - 1;
+ if (unlikely(dec < 0))
+ break;
+ old = atomic64_cmpxchg((v), c, dec);
+ if (likely(old == c))
+ break;
+ c = old;
+ }
+ return dec;
+}
+
#define ATOMIC_OP(op) \
static inline int atomic_fetch_##op(int i, atomic_t *v) \
{ \
struct task_struct;
struct thread_struct;
-#if !defined(CONFIG_LAZY_SAVE_FPU)
+#if defined(CONFIG_FPU) && !defined(CONFIG_LAZY_SAVE_FPU)
struct fpu_state_struct;
extern asmlinkage void fpu_save(struct fpu_state_struct *);
#define switch_fpu(prev, next) \
#endif
#include <linux/compiler.h>
-#include <asm/types.h> /* for BITS_PER_LONG/SHIFT_PER_LONG */
+#include <asm/types.h>
#include <asm/byteorder.h>
#include <asm/barrier.h>
#include <linux/atomic.h>
* to include/asm-i386/bitops.h or kerneldoc
*/
+#if __BITS_PER_LONG == 64
+#define SHIFT_PER_LONG 6
+#else
+#define SHIFT_PER_LONG 5
+#endif
+
#define CHOP_SHIFTCOUNT(x) (((unsigned long) (x)) & (BITS_PER_LONG - 1))
#if defined(__LP64__)
#define __BITS_PER_LONG 64
-#define SHIFT_PER_LONG 6
#else
#define __BITS_PER_LONG 32
-#define SHIFT_PER_LONG 5
#endif
#include <asm-generic/bitsperlong.h>
#ifndef _PARISC_SWAB_H
#define _PARISC_SWAB_H
+#include <asm/bitsperlong.h>
#include <linux/types.h>
#include <linux/compiler.h>
}
#define __arch_swab32 __arch_swab32
-#if BITS_PER_LONG > 32
+#if __BITS_PER_LONG > 32
/*
** From "PA-RISC 2.0 Architecture", HP Professional Books.
** See Appendix I page 8 , "Endian Byte Swapping".
return x;
}
#define __arch_swab64 __arch_swab64
-#endif /* BITS_PER_LONG > 32 */
+#endif /* __BITS_PER_LONG > 32 */
#endif /* _PARISC_SWAB_H */
select ARCH_HAS_SCALED_CPUTIME if VIRT_CPU_ACCOUNTING_NATIVE
select HAVE_ARCH_HARDENED_USERCOPY
select HAVE_KERNEL_GZIP
- select HAVE_CC_STACKPROTECTOR
config GENERIC_CSUM
def_bool CPU_LITTLE_ENDIAN
bool "Build a relocatable kernel"
depends on (PPC64 && !COMPILE_TEST) || (FLATMEM && (44x || FSL_BOOKE))
select NONSTATIC_KERNEL
+ select MODULE_REL_CRCS if MODVERSIONS
help
This builds a kernel image that is capable of running at the
location the kernel is loaded at. For ppc32, there is no any
#ifdef CONFIG_HUGETLB_PAGE
static inline int hash__hugepd_ok(hugepd_t hpd)
{
+ unsigned long hpdval = hpd_val(hpd);
/*
* if it is not a pte and have hugepd shift mask
* set, then it is a hugepd directory pointer
*/
- if (!(hpd.pd & _PAGE_PTE) &&
- ((hpd.pd & HUGEPD_SHIFT_MASK) != 0))
+ if (!(hpdval & _PAGE_PTE) &&
+ ((hpdval & HUGEPD_SHIFT_MASK) != 0))
return true;
return false;
}
unsigned long phys);
extern void hash__vmemmap_remove_mapping(unsigned long start,
unsigned long page_size);
+
+int hash__create_section_mapping(unsigned long start, unsigned long end);
+int hash__remove_section_mapping(unsigned long start, unsigned long end);
+
#endif /* !__ASSEMBLY__ */
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_BOOK3S_64_HASH_H */
{
int i;
+#ifndef __clang__ /* clang can't cope with this */
BUILD_BUG_ON(!__builtin_constant_p(feature));
+#endif
#ifdef CONFIG_JUMP_LABEL_FEATURE_CHECK_DEBUG
if (!static_key_initialized) {
* We have only four bits to encode, MMU page size
*/
BUILD_BUG_ON((MMU_PAGE_COUNT - 1) > 0xf);
- return __va(hpd.pd & HUGEPD_ADDR_MASK);
+ return __va(hpd_val(hpd) & HUGEPD_ADDR_MASK);
}
static inline unsigned int hugepd_mmu_psize(hugepd_t hpd)
{
- return (hpd.pd & HUGEPD_SHIFT_MASK) >> 2;
+ return (hpd_val(hpd) & HUGEPD_SHIFT_MASK) >> 2;
}
static inline unsigned int hugepd_shift(hugepd_t hpd)
{
BUG_ON(!hugepd_ok(hpd));
#ifdef CONFIG_PPC_8xx
- return (pte_t *)__va(hpd.pd & ~(_PMD_PAGE_MASK | _PMD_PRESENT_MASK));
+ return (pte_t *)__va(hpd_val(hpd) &
+ ~(_PMD_PAGE_MASK | _PMD_PRESENT_MASK));
#else
- return (pte_t *)((hpd.pd & ~HUGEPD_SHIFT_MASK) | PD_HUGE);
+ return (pte_t *)((hpd_val(hpd) &
+ ~HUGEPD_SHIFT_MASK) | PD_HUGE);
#endif
}
static inline unsigned int hugepd_shift(hugepd_t hpd)
{
#ifdef CONFIG_PPC_8xx
- return ((hpd.pd & _PMD_PAGE_MASK) >> 1) + 17;
+ return ((hpd_val(hpd) & _PMD_PAGE_MASK) >> 1) + 17;
#else
- return hpd.pd & HUGEPD_SHIFT_MASK;
+ return hpd_val(hpd) & HUGEPD_SHIFT_MASK;
#endif
}
{
int i;
+#ifndef __clang__ /* clang can't cope with this */
BUILD_BUG_ON(!__builtin_constant_p(feature));
+#endif
#ifdef CONFIG_JUMP_LABEL_FEATURE_CHECK_DEBUG
if (!static_key_initialized) {
}
#endif
-#if defined(CONFIG_MODVERSIONS) && defined(CONFIG_PPC64)
-#define ARCH_RELOCATES_KCRCTAB
-#define reloc_start PHYSICAL_START
-#endif
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_MODULE_H */
static inline int hugepd_ok(hugepd_t hpd)
{
#ifdef CONFIG_PPC_8xx
- return ((hpd.pd & 0x4) != 0);
+ return ((hpd_val(hpd) & 0x4) != 0);
#else
- return (hpd.pd > 0);
+ /* We clear the top bit to indicate hugepd */
+ return ((hpd_val(hpd) & PD_HUGE) == 0);
#endif
}
#include <asm/pgtable-types.h>
#endif
-typedef struct { signed long pd; } hugepd_t;
#ifndef CONFIG_HUGETLB_PAGE
#define is_hugepd(pdep) (0)
#define pgd_huge(pgd) (0)
#endif /* CONFIG_HUGETLB_PAGE */
-#define __hugepd(x) ((hugepd_t) { (x) })
-
struct page;
extern void clear_user_page(void *page, unsigned long vaddr, struct page *pg);
extern void copy_user_page(void *to, void *from, unsigned long vaddr,
#define PPMU_HAS_SSLOT 0x00000020 /* Has sampled slot in MMCRA */
#define PPMU_HAS_SIER 0x00000040 /* Has SIER */
#define PPMU_ARCH_207S 0x00000080 /* PMC is architecture v2.07S */
+#define PPMU_NO_SIAR 0x00000100 /* Do not use SIAR */
/*
* Values for flags to get_alternatives()
return pmd_raw(old) == prev;
}
+typedef struct { __be64 pdbe; } hugepd_t;
+#define __hugepd(x) ((hugepd_t) { cpu_to_be64(x) })
+
+static inline unsigned long hpd_val(hugepd_t x)
+{
+ return be64_to_cpu(x.pdbe);
+}
+
#endif /* _ASM_POWERPC_PGTABLE_BE_TYPES_H */
}
#endif
+typedef struct { unsigned long pd; } hugepd_t;
+#define __hugepd(x) ((hugepd_t) { (x) })
+static inline unsigned long hpd_val(hugepd_t x)
+{
+ return x.pd;
+}
+
#endif /* _ASM_POWERPC_PGTABLE_TYPES_H */
#define PPC_INST_MCRXR 0x7c000400
#define PPC_INST_MCRXR_MASK 0xfc0007fe
#define PPC_INST_MFSPR_PVR 0x7c1f42a6
-#define PPC_INST_MFSPR_PVR_MASK 0xfc1fffff
+#define PPC_INST_MFSPR_PVR_MASK 0xfc1ffffe
#define PPC_INST_MFTMR 0x7c0002dc
#define PPC_INST_MSGSND 0x7c00019c
#define PPC_INST_MSGCLR 0x7c0001dc
#define PPC_INST_RFDI 0x4c00004e
#define PPC_INST_RFMCI 0x4c00004c
#define PPC_INST_MFSPR_DSCR 0x7c1102a6
-#define PPC_INST_MFSPR_DSCR_MASK 0xfc1fffff
+#define PPC_INST_MFSPR_DSCR_MASK 0xfc1ffffe
#define PPC_INST_MTSPR_DSCR 0x7c1103a6
-#define PPC_INST_MTSPR_DSCR_MASK 0xfc1fffff
+#define PPC_INST_MTSPR_DSCR_MASK 0xfc1ffffe
#define PPC_INST_MFSPR_DSCR_USER 0x7c0302a6
-#define PPC_INST_MFSPR_DSCR_USER_MASK 0xfc1fffff
+#define PPC_INST_MFSPR_DSCR_USER_MASK 0xfc1ffffe
#define PPC_INST_MTSPR_DSCR_USER 0x7c0303a6
-#define PPC_INST_MTSPR_DSCR_USER_MASK 0xfc1fffff
+#define PPC_INST_MTSPR_DSCR_USER_MASK 0xfc1ffffe
#define PPC_INST_MFVSRD 0x7c000066
#define PPC_INST_MTVSRD 0x7c000166
#define PPC_INST_SLBFEE 0x7c0007a7
+++ /dev/null
-/*
- * GCC stack protector support.
- *
- * Stack protector works by putting predefined pattern at the start of
- * the stack frame and verifying that it hasn't been overwritten when
- * returning from the function. The pattern is called stack canary
- * and gcc expects it to be defined by a global variable called
- * "__stack_chk_guard" on PPC. This unfortunately means that on SMP
- * we cannot have a different canary value per task.
- */
-
-#ifndef _ASM_STACKPROTECTOR_H
-#define _ASM_STACKPROTECTOR_H
-
-#include <linux/random.h>
-#include <linux/version.h>
-#include <asm/reg.h>
-
-extern unsigned long __stack_chk_guard;
-
-/*
- * Initialize the stackprotector canary value.
- *
- * NOTE: this must only be called from functions that never return,
- * and it must always be inlined.
- */
-static __always_inline void boot_init_stack_canary(void)
-{
- unsigned long canary;
-
- /* Try to get a semi random initial value. */
- get_random_bytes(&canary, sizeof(canary));
- canary ^= mftb();
- canary ^= LINUX_VERSION_CODE;
-
- current->stack_canary = canary;
- __stack_chk_guard = current->stack_canary;
-}
-
-#endif /* _ASM_STACKPROTECTOR_H */
CFLAGS_btext.o += $(DISABLE_LATENT_ENTROPY_PLUGIN)
CFLAGS_prom.o += $(DISABLE_LATENT_ENTROPY_PLUGIN)
-# -fstack-protector triggers protection checks in this code,
-# but it is being used too early to link to meaningful stack_chk logic.
-CFLAGS_prom_init.o += $(call cc-option, -fno-stack-protector)
-
ifdef CONFIG_FUNCTION_TRACER
# Do not trace early boot code
CFLAGS_REMOVE_cputable.o = -mno-sched-epilog $(CC_FLAGS_FTRACE)
DEFINE(TI_livepatch_sp, offsetof(struct thread_info, livepatch_sp));
#endif
-#ifdef CONFIG_CC_STACKPROTECTOR
- DEFINE(TSK_STACK_CANARY, offsetof(struct task_struct, stack_canary));
-#endif
DEFINE(KSP, offsetof(struct thread_struct, ksp));
DEFINE(PT_REGS, offsetof(struct thread_struct, regs));
#ifdef CONFIG_BOOKE
*
* For pHyp, we have to enable IO for log retrieval. Otherwise,
* 0xFF's is always returned from PCI config space.
+ *
+ * When the @severity is EEH_LOG_PERM, the PE is going to be
+ * removed. Prior to that, the drivers for devices included in
+ * the PE will be closed. The drivers rely on working IO path
+ * to bring the devices to quiet state. Otherwise, PCI traffic
+ * from those devices after they are removed is like to cause
+ * another unexpected EEH error.
*/
if (!(pe->type & EEH_PE_PHB)) {
- if (eeh_has_flag(EEH_ENABLE_IO_FOR_LOG))
+ if (eeh_has_flag(EEH_ENABLE_IO_FOR_LOG) ||
+ severity == EEH_LOG_PERM)
eeh_pci_enable(pe, EEH_OPT_THAW_MMIO);
/*
static void *__eeh_clear_pe_frozen_state(void *data, void *flag)
{
struct eeh_pe *pe = (struct eeh_pe *)data;
- bool *clear_sw_state = flag;
+ bool clear_sw_state = *(bool *)flag;
int i, rc = 1;
for (i = 0; rc && i < 3; i++)
mtspr SPRN_SPEFSCR,r0 /* restore SPEFSCR reg */
END_FTR_SECTION_IFSET(CPU_FTR_SPE)
#endif /* CONFIG_SPE */
-#if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
- lwz r0,TSK_STACK_CANARY(r2)
- lis r4,__stack_chk_guard@ha
- stw r0,__stack_chk_guard@l(r4)
-#endif
+
lwz r0,_CCR(r1)
mtcrf 0xFF,r0
/* r3-r12 are destroyed -- Cort */
for (end = (void *)vers + size; vers < end; vers++)
if (vers->name[0] == '.') {
memmove(vers->name, vers->name+1, strlen(vers->name));
-#ifdef ARCH_RELOCATES_KCRCTAB
- /* The TOC symbol has no CRC computed. To avoid CRC
- * check failing, we must force it to the expected
- * value (see CRC check in module.c).
- */
- if (!strcmp(vers->name, "TOC."))
- vers->crc = -(unsigned long)reloc_start;
-#endif
}
}
#include <linux/kprobes.h>
#include <linux/kdebug.h>
-#ifdef CONFIG_CC_STACKPROTECTOR
-#include <linux/stackprotector.h>
-unsigned long __stack_chk_guard __read_mostly;
-EXPORT_SYMBOL(__stack_chk_guard);
-#endif
-
/* Transactional Memory debug */
#ifdef TM_DEBUG_SW
#define TM_DEBUG(x...) printk(KERN_INFO x)
cpu_pkg = call_prom("instance-to-package", 1, 1, prom_cpu);
+ if (!PHANDLE_VALID(cpu_pkg))
+ return;
+
prom_getprop(cpu_pkg, "reg", &rval, sizeof(rval));
prom.cpu = be32_to_cpu(rval);
flush_fp_to_thread(target);
+ for (i = 0; i < 32 ; i++)
+ buf[i] = target->thread.TS_FPR(i);
+ buf[32] = target->thread.fp_state.fpscr;
+
/* copy to local buffer then write that out */
i = user_regset_copyin(&pos, &count, &kbuf, &ubuf, buf, 0, -1);
if (i)
flush_altivec_to_thread(target);
flush_vsx_to_thread(target);
+ for (i = 0; i < 32 ; i++)
+ buf[i] = target->thread.fp_state.fpr[i][TS_VSRLOWOFFSET];
+
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
buf, 0, 32 * sizeof(double));
if (!ret)
flush_fp_to_thread(target);
flush_altivec_to_thread(target);
+ for (i = 0; i < 32; i++)
+ buf[i] = target->thread.TS_CKFPR(i);
+ buf[32] = target->thread.ckfp_state.fpscr;
+
/* copy to local buffer then write that out */
i = user_regset_copyin(&pos, &count, &kbuf, &ubuf, buf, 0, -1);
if (i)
flush_altivec_to_thread(target);
flush_vsx_to_thread(target);
+ for (i = 0; i < 32 ; i++)
+ buf[i] = target->thread.ckfp_state.fpr[i][TS_VSRLOWOFFSET];
+
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
buf, 0, 32 * sizeof(double));
if (!ret)
}
#ifdef CONFIG_MEMORY_HOTPLUG
-int create_section_mapping(unsigned long start, unsigned long end)
+int hash__create_section_mapping(unsigned long start, unsigned long end)
{
int rc = htab_bolt_mapping(start, end, __pa(start),
pgprot_val(PAGE_KERNEL), mmu_linear_psize,
return rc;
}
-int remove_section_mapping(unsigned long start, unsigned long end)
+int hash__remove_section_mapping(unsigned long start, unsigned long end)
{
int rc = htab_remove_mapping(start, end, mmu_linear_psize,
mmu_kernel_ssize);
int hugepd_ok(hugepd_t hpd)
{
bool is_hugepd;
+ unsigned long hpdval;
+
+ hpdval = hpd_val(hpd);
/*
* We should not find this format in page directory, warn otherwise.
*/
- is_hugepd = (((hpd.pd & 0x3) == 0x0) && ((hpd.pd & HUGEPD_SHIFT_MASK) != 0));
+ is_hugepd = (((hpdval & 0x3) == 0x0) && ((hpdval & HUGEPD_SHIFT_MASK) != 0));
WARN(is_hugepd, "Found wrong page directory format\n");
return 0;
}
static unsigned nr_gpages;
#endif
-#define hugepd_none(hpd) ((hpd).pd == 0)
+#define hugepd_none(hpd) (hpd_val(hpd) == 0)
pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
{
for (i = 0; i < num_hugepd; i++, hpdp++) {
if (unlikely(!hugepd_none(*hpdp)))
break;
- else
+ else {
#ifdef CONFIG_PPC_BOOK3S_64
- hpdp->pd = __pa(new) |
- (shift_to_mmu_psize(pshift) << 2);
+ *hpdp = __hugepd(__pa(new) |
+ (shift_to_mmu_psize(pshift) << 2));
#elif defined(CONFIG_PPC_8xx)
- hpdp->pd = __pa(new) |
- (pshift == PAGE_SHIFT_8M ? _PMD_PAGE_8M :
- _PMD_PAGE_512K) |
- _PMD_PRESENT;
+ *hpdp = __hugepd(__pa(new) |
+ (pshift == PAGE_SHIFT_8M ? _PMD_PAGE_8M :
+ _PMD_PAGE_512K) | _PMD_PRESENT);
#else
/* We use the old format for PPC_FSL_BOOK3E */
- hpdp->pd = ((unsigned long)new & ~PD_HUGE) | pshift;
+ *hpdp = __hugepd(((unsigned long)new & ~PD_HUGE) | pshift);
#endif
+ }
}
/* If we bailed from the for loop early, an error occurred, clean up */
if (i < num_hugepd) {
for (i = i - 1 ; i >= 0; i--, hpdp--)
- hpdp->pd = 0;
+ *hpdp = __hugepd(0);
kmem_cache_free(cachep, new);
}
spin_unlock(&mm->page_table_lock);
return;
for (i = 0; i < num_hugepd; i++, hpdp++)
- hpdp->pd = 0;
+ *hpdp = __hugepd(0);
if (shift >= pdshift)
hugepd_free(tlb, hugepte);
* if we have pdshift and shift value same, we don't
* use pgt cache for hugepd.
*/
- if (pdshift > shift) {
+ if (pdshift > shift)
pgtable_cache_add(pdshift - shift, NULL);
- if (!PGT_CACHE(pdshift - shift))
- panic("hugetlbpage_init(): could not create "
- "pgtable cache for %d bit pagesize\n", shift);
- }
#if defined(CONFIG_PPC_FSL_BOOK3E) || defined(CONFIG_PPC_8xx)
else if (!hugepte_cache) {
/*
else if (mmu_psize_defs[MMU_PAGE_2M].shift)
HPAGE_SHIFT = mmu_psize_defs[MMU_PAGE_2M].shift;
#endif
- else
- panic("%s: Unable to set default huge page size\n", __func__);
-
return 0;
}
align = max_t(unsigned long, align, minalign);
name = kasprintf(GFP_KERNEL, "pgtable-2^%d", shift);
new = kmem_cache_create(name, table_size, align, 0, ctor);
+ if (!new)
+ panic("Could not allocate pgtable cache for order %d", shift);
+
kfree(name);
pgtable_cache[shift - 1] = new;
+
pr_debug("Allocated pgtable cache for order %d\n", shift);
}
{
pgtable_cache_add(PGD_INDEX_SIZE, pgd_ctor);
- if (PMD_INDEX_SIZE && !PGT_CACHE(PMD_INDEX_SIZE))
+ if (PMD_CACHE_INDEX && !PGT_CACHE(PMD_CACHE_INDEX))
pgtable_cache_add(PMD_CACHE_INDEX, pmd_ctor);
/*
* In all current configs, when the PUD index exists it's the
*/
if (PUD_INDEX_SIZE && !PGT_CACHE(PUD_INDEX_SIZE))
pgtable_cache_add(PUD_INDEX_SIZE, pud_ctor);
-
- if (!PGT_CACHE(PGD_INDEX_SIZE))
- panic("Couldn't allocate pgd cache");
- if (PMD_INDEX_SIZE && !PGT_CACHE(PMD_INDEX_SIZE))
- panic("Couldn't allocate pmd pgtable caches");
- if (PUD_INDEX_SIZE && !PGT_CACHE(PUD_INDEX_SIZE))
- panic("Couldn't allocate pud pgtable caches");
}
else if (mmu_hash_ops.hpte_clear_all)
mmu_hash_ops.hpte_clear_all();
}
+
+#ifdef CONFIG_MEMORY_HOTPLUG
+int create_section_mapping(unsigned long start, unsigned long end)
+{
+ if (radix_enabled())
+ return -ENODEV;
+
+ return hash__create_section_mapping(start, end);
+}
+
+int remove_section_mapping(unsigned long start, unsigned long end)
+{
+ if (radix_enabled())
+ return -ENODEV;
+
+ return hash__remove_section_mapping(start, end);
+}
+#endif /* CONFIG_MEMORY_HOTPLUG */
if (!pmdp)
return -ENOMEM;
if (map_page_size == PMD_SIZE) {
- ptep = (pte_t *)pudp;
+ ptep = pmdp_ptep(pmdp);
goto set_the_pte;
}
ptep = pte_alloc_kernel(pmdp, ea);
}
pmdp = pmd_offset(pudp, ea);
if (map_page_size == PMD_SIZE) {
- ptep = (pte_t *)pudp;
+ ptep = pmdp_ptep(pmdp);
goto set_the_pte;
}
if (!pmd_present(*pmdp)) {
*/
if (TRAP(regs) != 0xf00)
use_siar = 0;
+ else if ((ppmu->flags & PPMU_NO_SIAR))
+ use_siar = 0;
else if (marked)
use_siar = 1;
else if ((ppmu->flags & PPMU_NO_CONT_SAMPLING))
EVENT(PM_ICT_NOSLOT_CYC, 0x100f8)
EVENT(PM_CMPLU_STALL, 0x1e054)
EVENT(PM_INST_CMPL, 0x00002)
-EVENT(PM_BRU_CMPL, 0x40060)
+EVENT(PM_BRU_CMPL, 0x10012)
EVENT(PM_BR_MPRED_CMPL, 0x400f6)
/* All L1 D cache load references counted at finish, gated by reject */
.bhrb_filter_map = power9_bhrb_filter_map,
.get_constraint = isa207_get_constraint,
.disable_pmc = isa207_disable_pmc,
- .flags = PPMU_HAS_SIER | PPMU_ARCH_207S,
+ .flags = PPMU_NO_SIAR | PPMU_ARCH_207S,
.n_generic = ARRAY_SIZE(power9_generic_events),
.generic_events = power9_generic_events,
.cache_events = &power9_cache_events,
#include <asm/xics.h>
#include <asm/io.h>
#include <asm/opal.h>
+#include <asm/kvm_ppc.h>
static void icp_opal_teardown_cpu(void)
{
* Should we be flagging idle loop instead?
* Or creating some task to be scheduled?
*/
- opal_int_eoi((0x00 << 24) | XICS_IPI);
+ if (opal_int_eoi((0x00 << 24) | XICS_IPI) > 0)
+ force_external_irq_replay();
+}
+
+static unsigned int icp_opal_get_xirr(void)
+{
+ unsigned int kvm_xirr;
+ __be32 hw_xirr;
+ int64_t rc;
+
+ /* Handle an interrupt latched by KVM first */
+ kvm_xirr = kvmppc_get_xics_latch();
+ if (kvm_xirr)
+ return kvm_xirr;
+
+ /* Then ask OPAL */
+ rc = opal_int_get_xirr(&hw_xirr, false);
+ if (rc < 0)
+ return 0;
+ return be32_to_cpu(hw_xirr);
}
static unsigned int icp_opal_get_irq(void)
unsigned int xirr;
unsigned int vec;
unsigned int irq;
- int64_t rc;
- rc = opal_int_get_xirr(&xirr, false);
- if (rc < 0)
- return 0;
- xirr = be32_to_cpu(xirr);
+ xirr = icp_opal_get_xirr();
vec = xirr & 0x00ffffff;
if (vec == XICS_IRQ_SPURIOUS)
return 0;
xics_mask_unknown_vec(vec);
/* We might learn about it later, so EOI it */
- opal_int_eoi(xirr);
+ if (opal_int_eoi(xirr) > 0)
+ force_external_irq_replay();
return 0;
}
CONFIG_CMA_DEBUG=y
CONFIG_CMA_DEBUGFS=y
CONFIG_MEM_SOFT_DIRTY=y
-CONFIG_ZPOOL=m
+CONFIG_ZSWAP=y
CONFIG_ZBUD=m
CONFIG_ZSMALLOC=m
CONFIG_ZSMALLOC_STAT=y
CONFIG_NF_CONNTRACK_EVENTS=y
CONFIG_NF_CONNTRACK_TIMEOUT=y
CONFIG_NF_CONNTRACK_TIMESTAMP=y
-CONFIG_NF_CT_PROTO_DCCP=m
-CONFIG_NF_CT_PROTO_UDPLITE=m
CONFIG_NF_CONNTRACK_AMANDA=m
CONFIG_NF_CONNTRACK_FTP=m
CONFIG_NF_CONNTRACK_H323=m
CONFIG_NFT_EXTHDR=m
CONFIG_NFT_META=m
CONFIG_NFT_CT=m
-CONFIG_NFT_RBTREE=m
-CONFIG_NFT_HASH=m
CONFIG_NFT_COUNTER=m
CONFIG_NFT_LOG=m
CONFIG_NFT_LIMIT=m
CONFIG_NFT_NAT=m
CONFIG_NFT_COMPAT=m
+CONFIG_NFT_HASH=m
CONFIG_NETFILTER_XT_SET=m
CONFIG_NETFILTER_XT_TARGET_AUDIT=m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
CONFIG_NETFILTER_XT_MATCH_RATEEST=m
CONFIG_NETFILTER_XT_MATCH_REALM=m
CONFIG_NETFILTER_XT_MATCH_RECENT=m
-CONFIG_NETFILTER_XT_MATCH_SOCKET=m
CONFIG_NETFILTER_XT_MATCH_STATE=m
CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
CONFIG_NETFILTER_XT_MATCH_STRING=m
CONFIG_IP_VS_FTP=m
CONFIG_IP_VS_PE_SIP=m
CONFIG_NF_CONNTRACK_IPV4=m
-# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set
CONFIG_NF_TABLES_IPV4=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NF_TABLES_ARP=m
CONFIG_IFB=m
CONFIG_MACVLAN=m
CONFIG_MACVTAP=m
-CONFIG_IPVLAN=m
CONFIG_VXLAN=m
CONFIG_TUN=m
CONFIG_VETH=m
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_ENCRYPTION=y
CONFIG_JBD2_DEBUG=y
CONFIG_JFS_FS=m
CONFIG_JFS_POSIX_ACL=y
CONFIG_DEBUG_LOCKDEP=y
CONFIG_DEBUG_ATOMIC_SLEEP=y
CONFIG_DEBUG_LOCKING_API_SELFTESTS=y
-CONFIG_DEBUG_LIST=y
CONFIG_DEBUG_SG=y
CONFIG_DEBUG_NOTIFIERS=y
CONFIG_DEBUG_CREDENTIALS=y
CONFIG_RCU_TORTURE_TEST=m
CONFIG_RCU_CPU_STALL_TIMEOUT=300
CONFIG_NOTIFIER_ERROR_INJECTION=m
-CONFIG_CPU_NOTIFIER_ERROR_INJECT=m
CONFIG_PM_NOTIFIER_ERROR_INJECT=m
CONFIG_FAULT_INJECTION=y
CONFIG_FAILSLAB=y
CONFIG_BLK_DEV_IO_TRACE=y
CONFIG_UPROBE_EVENT=y
CONFIG_FUNCTION_PROFILER=y
+CONFIG_HIST_TRIGGERS=y
CONFIG_TRACE_ENUM_MAP_FILE=y
CONFIG_LKDTM=m
CONFIG_TEST_LIST_SORT=y
CONFIG_TEST_KSTRTOX=y
CONFIG_DMA_API_DEBUG=y
CONFIG_TEST_BPF=m
+CONFIG_BUG_ON_DATA_CORRUPTION=y
CONFIG_S390_PTDUMP=y
CONFIG_ENCRYPTED_KEYS=m
CONFIG_SECURITY=y
CONFIG_SECURITY_SELINUX_DISABLE=y
CONFIG_IMA=y
CONFIG_IMA_APPRAISE=y
+CONFIG_CRYPTO_RSA=m
+CONFIG_CRYPTO_DH=m
+CONFIG_CRYPTO_ECDH=m
CONFIG_CRYPTO_USER=m
-# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set
CONFIG_CRYPTO_CRYPTD=m
CONFIG_CRYPTO_TEST=m
CONFIG_CRYPTO_CCM=m
CONFIG_CRYPTO_GCM=m
-CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_CHACHA20POLY1305=m
CONFIG_CRYPTO_LRW=m
CONFIG_CRYPTO_PCBC=m
-CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_KEYWRAP=m
CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_VMAC=m
CONFIG_CRYPTO_CRC32=m
CONFIG_CRYPTO_SERPENT=m
CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_TWOFISH=m
-CONFIG_CRYPTO_LZO=m
+CONFIG_CRYPTO_842=m
CONFIG_CRYPTO_LZ4=m
CONFIG_CRYPTO_LZ4HC=m
CONFIG_CRYPTO_USER_API_HASH=m
CONFIG_CRYPTO_USER_API_SKCIPHER=m
+CONFIG_CRYPTO_USER_API_RNG=m
+CONFIG_CRYPTO_USER_API_AEAD=m
CONFIG_ZCRYPT=m
CONFIG_CRYPTO_SHA1_S390=m
CONFIG_CRYPTO_SHA256_S390=m
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_NUMA_BALANCING=y
+# CONFIG_NUMA_BALANCING_DEFAULT_ENABLED is not set
CONFIG_MEMCG=y
CONFIG_MEMCG_SWAP=y
CONFIG_BLK_CGROUP=y
CONFIG_UNIXWARE_DISKLABEL=y
CONFIG_CFQ_GROUP_IOSCHED=y
CONFIG_DEFAULT_DEADLINE=y
+CONFIG_LIVEPATCH=y
CONFIG_TUNE_ZEC12=y
-CONFIG_NR_CPUS=256
+CONFIG_NR_CPUS=512
CONFIG_NUMA=y
CONFIG_HZ_100=y
CONFIG_MEMORY_HOTPLUG=y
CONFIG_CLEANCACHE=y
CONFIG_FRONTSWAP=y
CONFIG_CMA=y
+CONFIG_MEM_SOFT_DIRTY=y
CONFIG_ZSWAP=y
CONFIG_ZBUD=m
CONFIG_ZSMALLOC=m
CONFIG_NF_CONNTRACK_EVENTS=y
CONFIG_NF_CONNTRACK_TIMEOUT=y
CONFIG_NF_CONNTRACK_TIMESTAMP=y
-CONFIG_NF_CT_PROTO_DCCP=m
-CONFIG_NF_CT_PROTO_UDPLITE=m
CONFIG_NF_CONNTRACK_AMANDA=m
CONFIG_NF_CONNTRACK_FTP=m
CONFIG_NF_CONNTRACK_H323=m
CONFIG_NFT_EXTHDR=m
CONFIG_NFT_META=m
CONFIG_NFT_CT=m
-CONFIG_NFT_RBTREE=m
-CONFIG_NFT_HASH=m
CONFIG_NFT_COUNTER=m
CONFIG_NFT_LOG=m
CONFIG_NFT_LIMIT=m
CONFIG_NFT_NAT=m
CONFIG_NFT_COMPAT=m
+CONFIG_NFT_HASH=m
CONFIG_NETFILTER_XT_SET=m
CONFIG_NETFILTER_XT_TARGET_AUDIT=m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
CONFIG_NETFILTER_XT_MATCH_RATEEST=m
CONFIG_NETFILTER_XT_MATCH_REALM=m
CONFIG_NETFILTER_XT_MATCH_RECENT=m
-CONFIG_NETFILTER_XT_MATCH_SOCKET=m
CONFIG_NETFILTER_XT_MATCH_STATE=m
CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
CONFIG_NETFILTER_XT_MATCH_STRING=m
CONFIG_IP_VS_FTP=m
CONFIG_IP_VS_PE_SIP=m
CONFIG_NF_CONNTRACK_IPV4=m
-# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set
CONFIG_NF_TABLES_IPV4=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NF_TABLES_ARP=m
CONFIG_IFB=m
CONFIG_MACVLAN=m
CONFIG_MACVTAP=m
-CONFIG_IPVLAN=m
CONFIG_VXLAN=m
CONFIG_TUN=m
CONFIG_VETH=m
CONFIG_RAW_DRIVER=m
CONFIG_HANGCHECK_TIMER=m
CONFIG_TN3270_FS=y
+# CONFIG_HWMON is not set
CONFIG_WATCHDOG=y
CONFIG_WATCHDOG_NOWAYOUT=y
CONFIG_SOFT_WATCHDOG=m
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_ENCRYPTION=y
CONFIG_JBD2_DEBUG=y
CONFIG_JFS_FS=m
CONFIG_JFS_POSIX_ACL=y
CONFIG_FUSE_FS=y
CONFIG_CUSE=m
CONFIG_OVERLAY_FS=m
+CONFIG_OVERLAY_FS_REDIRECT_DIR=y
CONFIG_FSCACHE=m
CONFIG_CACHEFILES=m
CONFIG_ISO9660_FS=y
CONFIG_UNUSED_SYMBOLS=y
CONFIG_MAGIC_SYSRQ=y
CONFIG_DEBUG_MEMORY_INIT=y
-CONFIG_MEMORY_NOTIFIER_ERROR_INJECT=m
CONFIG_PANIC_ON_OOPS=y
CONFIG_TIMER_STATS=y
CONFIG_RCU_TORTURE_TEST=m
CONFIG_RCU_CPU_STALL_TIMEOUT=60
-CONFIG_NOTIFIER_ERROR_INJECTION=m
-CONFIG_CPU_NOTIFIER_ERROR_INJECT=m
-CONFIG_PM_NOTIFIER_ERROR_INJECT=m
CONFIG_LATENCYTOP=y
+CONFIG_SCHED_TRACER=y
+CONFIG_FTRACE_SYSCALLS=y
+CONFIG_STACK_TRACER=y
CONFIG_BLK_DEV_IO_TRACE=y
-# CONFIG_KPROBE_EVENT is not set
+CONFIG_UPROBE_EVENT=y
+CONFIG_FUNCTION_PROFILER=y
+CONFIG_HIST_TRIGGERS=y
CONFIG_TRACE_ENUM_MAP_FILE=y
CONFIG_LKDTM=m
-CONFIG_RBTREE_TEST=m
-CONFIG_INTERVAL_TREE_TEST=m
CONFIG_PERCPU_TEST=m
CONFIG_ATOMIC64_SELFTEST=y
CONFIG_TEST_BPF=m
+CONFIG_BUG_ON_DATA_CORRUPTION=y
CONFIG_S390_PTDUMP=y
+CONFIG_PERSISTENT_KEYRINGS=y
+CONFIG_BIG_KEYS=y
CONFIG_ENCRYPTED_KEYS=m
CONFIG_SECURITY=y
CONFIG_SECURITY_NETWORK=y
CONFIG_SECURITY_SELINUX_BOOTPARAM=y
CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0
CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_INTEGRITY_SIGNATURE=y
+CONFIG_INTEGRITY_ASYMMETRIC_KEYS=y
CONFIG_IMA=y
+CONFIG_IMA_WRITE_POLICY=y
CONFIG_IMA_APPRAISE=y
+CONFIG_CRYPTO_DH=m
+CONFIG_CRYPTO_ECDH=m
CONFIG_CRYPTO_USER=m
# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set
+CONFIG_CRYPTO_PCRYPT=m
CONFIG_CRYPTO_CRYPTD=m
+CONFIG_CRYPTO_MCRYPTD=m
CONFIG_CRYPTO_TEST=m
CONFIG_CRYPTO_CCM=m
CONFIG_CRYPTO_GCM=m
-CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_CHACHA20POLY1305=m
CONFIG_CRYPTO_LRW=m
CONFIG_CRYPTO_PCBC=m
-CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_KEYWRAP=m
CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_VMAC=m
CONFIG_CRYPTO_CRC32=m
CONFIG_CRYPTO_RMD256=m
CONFIG_CRYPTO_RMD320=m
CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_SHA3=m
CONFIG_CRYPTO_TGR192=m
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_ANUBIS=m
CONFIG_CRYPTO_SERPENT=m
CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_842=m
CONFIG_CRYPTO_LZ4=m
CONFIG_CRYPTO_LZ4HC=m
CONFIG_CRYPTO_USER_API_HASH=m
CONFIG_CRYPTO_USER_API_SKCIPHER=m
+CONFIG_CRYPTO_USER_API_RNG=m
+CONFIG_CRYPTO_USER_API_AEAD=m
CONFIG_ZCRYPT=m
CONFIG_CRYPTO_SHA1_S390=m
CONFIG_CRYPTO_SHA256_S390=m
CONFIG_CRYPTO_AES_S390=m
CONFIG_CRYPTO_GHASH_S390=m
CONFIG_CRYPTO_CRC32_S390=y
-CONFIG_ASYMMETRIC_KEY_TYPE=y
-CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=m
-CONFIG_X509_CERTIFICATE_PARSER=m
CONFIG_CRC7=m
CONFIG_CRC8=m
CONFIG_CORDIC=m
CONFIG_CLEANCACHE=y
CONFIG_FRONTSWAP=y
CONFIG_CMA=y
+CONFIG_MEM_SOFT_DIRTY=y
CONFIG_ZSWAP=y
CONFIG_ZBUD=m
CONFIG_ZSMALLOC=m
CONFIG_NF_CONNTRACK_EVENTS=y
CONFIG_NF_CONNTRACK_TIMEOUT=y
CONFIG_NF_CONNTRACK_TIMESTAMP=y
-CONFIG_NF_CT_PROTO_DCCP=m
-CONFIG_NF_CT_PROTO_UDPLITE=m
CONFIG_NF_CONNTRACK_AMANDA=m
CONFIG_NF_CONNTRACK_FTP=m
CONFIG_NF_CONNTRACK_H323=m
CONFIG_NFT_EXTHDR=m
CONFIG_NFT_META=m
CONFIG_NFT_CT=m
-CONFIG_NFT_RBTREE=m
-CONFIG_NFT_HASH=m
CONFIG_NFT_COUNTER=m
CONFIG_NFT_LOG=m
CONFIG_NFT_LIMIT=m
CONFIG_NFT_NAT=m
CONFIG_NFT_COMPAT=m
+CONFIG_NFT_HASH=m
CONFIG_NETFILTER_XT_SET=m
CONFIG_NETFILTER_XT_TARGET_AUDIT=m
CONFIG_NETFILTER_XT_TARGET_CHECKSUM=m
CONFIG_NETFILTER_XT_MATCH_RATEEST=m
CONFIG_NETFILTER_XT_MATCH_REALM=m
CONFIG_NETFILTER_XT_MATCH_RECENT=m
-CONFIG_NETFILTER_XT_MATCH_SOCKET=m
CONFIG_NETFILTER_XT_MATCH_STATE=m
CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
CONFIG_NETFILTER_XT_MATCH_STRING=m
CONFIG_IP_VS_FTP=m
CONFIG_IP_VS_PE_SIP=m
CONFIG_NF_CONNTRACK_IPV4=m
-# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set
CONFIG_NF_TABLES_IPV4=m
CONFIG_NFT_CHAIN_ROUTE_IPV4=m
CONFIG_NF_TABLES_ARP=m
CONFIG_IFB=m
CONFIG_MACVLAN=m
CONFIG_MACVTAP=m
-CONFIG_IPVLAN=m
CONFIG_VXLAN=m
CONFIG_TUN=m
CONFIG_VETH=m
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_POSIX_ACL=y
CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_ENCRYPTION=y
CONFIG_JBD2_DEBUG=y
CONFIG_JFS_FS=m
CONFIG_JFS_POSIX_ACL=y
CONFIG_FUSE_FS=y
CONFIG_CUSE=m
CONFIG_OVERLAY_FS=m
+CONFIG_OVERLAY_FS_REDIRECT_DIR=y
CONFIG_FSCACHE=m
CONFIG_CACHEFILES=m
CONFIG_ISO9660_FS=y
CONFIG_BLK_DEV_IO_TRACE=y
CONFIG_UPROBE_EVENT=y
CONFIG_FUNCTION_PROFILER=y
+CONFIG_HIST_TRIGGERS=y
CONFIG_TRACE_ENUM_MAP_FILE=y
CONFIG_LKDTM=m
CONFIG_PERCPU_TEST=m
CONFIG_ATOMIC64_SELFTEST=y
CONFIG_TEST_BPF=m
+CONFIG_BUG_ON_DATA_CORRUPTION=y
CONFIG_S390_PTDUMP=y
+CONFIG_PERSISTENT_KEYRINGS=y
+CONFIG_BIG_KEYS=y
CONFIG_ENCRYPTED_KEYS=m
CONFIG_SECURITY=y
CONFIG_SECURITY_NETWORK=y
CONFIG_SECURITY_SELINUX_BOOTPARAM=y
CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE=0
CONFIG_SECURITY_SELINUX_DISABLE=y
+CONFIG_INTEGRITY_SIGNATURE=y
+CONFIG_INTEGRITY_ASYMMETRIC_KEYS=y
CONFIG_IMA=y
+CONFIG_IMA_WRITE_POLICY=y
CONFIG_IMA_APPRAISE=y
+CONFIG_CRYPTO_DH=m
+CONFIG_CRYPTO_ECDH=m
CONFIG_CRYPTO_USER=m
# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set
+CONFIG_CRYPTO_PCRYPT=m
CONFIG_CRYPTO_CRYPTD=m
+CONFIG_CRYPTO_MCRYPTD=m
CONFIG_CRYPTO_TEST=m
CONFIG_CRYPTO_CCM=m
CONFIG_CRYPTO_GCM=m
-CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_CHACHA20POLY1305=m
CONFIG_CRYPTO_LRW=m
CONFIG_CRYPTO_PCBC=m
-CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_KEYWRAP=m
CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_VMAC=m
CONFIG_CRYPTO_CRC32=m
CONFIG_CRYPTO_RMD256=m
CONFIG_CRYPTO_RMD320=m
CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_SHA3=m
CONFIG_CRYPTO_TGR192=m
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_ANUBIS=m
CONFIG_CRYPTO_SERPENT=m
CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_842=m
CONFIG_CRYPTO_LZ4=m
CONFIG_CRYPTO_LZ4HC=m
CONFIG_CRYPTO_USER_API_HASH=m
CONFIG_CRYPTO_USER_API_SKCIPHER=m
+CONFIG_CRYPTO_USER_API_RNG=m
+CONFIG_CRYPTO_USER_API_AEAD=m
CONFIG_ZCRYPT=m
CONFIG_CRYPTO_SHA1_S390=m
CONFIG_CRYPTO_SHA256_S390=m
CONFIG_CRYPTO_AES_S390=m
CONFIG_CRYPTO_GHASH_S390=m
CONFIG_CRYPTO_CRC32_S390=y
-CONFIG_ASYMMETRIC_KEY_TYPE=y
-CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE=m
-CONFIG_X509_CERTIFICATE_PARSER=m
CONFIG_CRC7=m
CONFIG_CRC8=m
CONFIG_CORDIC=m
CONFIG_STATIC_KEYS_SELFTEST=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
-CONFIG_MODVERSIONS=y
CONFIG_BLK_DEV_INTEGRITY=y
CONFIG_PARTITION_ADVANCED=y
CONFIG_IBM_PARTITION=y
CONFIG_EQUALIZER=m
CONFIG_TUN=m
CONFIG_VIRTIO_NET=y
+# CONFIG_NET_VENDOR_ALACRITECH is not set
+# CONFIG_NET_VENDOR_SOLARFLARE is not set
# CONFIG_INPUT is not set
# CONFIG_SERIO is not set
+CONFIG_DEVKMEM=y
CONFIG_RAW_DRIVER=m
CONFIG_VIRTIO_BALLOON=y
CONFIG_EXT4_FS=y
CONFIG_KPROBES_SANITY_TEST=y
CONFIG_S390_PTDUMP=y
CONFIG_CRYPTO_CRYPTD=m
-CONFIG_CRYPTO_AUTHENC=m
CONFIG_CRYPTO_TEST=m
CONFIG_CRYPTO_CCM=m
CONFIG_CRYPTO_GCM=m
BUILD_BUG_ON(sizeof(addrtype) != (high - low + 1) * sizeof(long));\
asm volatile( \
" lctlg %1,%2,%0\n" \
- : : "Q" (*(addrtype *)(&array)), "i" (low), "i" (high));\
+ : \
+ : "Q" (*(addrtype *)(&array)), "i" (low), "i" (high) \
+ : "memory"); \
}
#define __ctl_store(array, low, high) { \
if (target == current)
save_fpu_regs();
+ if (MACHINE_HAS_VX)
+ convert_vx_to_fp(fprs, target->thread.fpu.vxrs);
+ else
+ memcpy(&fprs, target->thread.fpu.fprs, sizeof(fprs));
+
/* If setting FPC, must validate it first. */
if (count > 0 && pos < offsetof(s390_fp_regs, fprs)) {
u32 ufpc[2] = { target->thread.fpu.fpc, 0 };
if (target == current)
save_fpu_regs();
+ for (i = 0; i < __NUM_VXRS_LOW; i++)
+ vxrs[i] = *((__u64 *)(target->thread.fpu.vxrs + i) + 1);
+
rc = user_regset_copyin(&pos, &count, &kbuf, &ubuf, vxrs, 0, -1);
if (rc == 0)
for (i = 0; i < __NUM_VXRS_LOW; i++)
memcpy(&mach->fac_mask, kvm->arch.model.fac_mask,
S390_ARCH_FAC_LIST_SIZE_BYTE);
memcpy((unsigned long *)&mach->fac_list, S390_lowcore.stfle_fac_list,
- S390_ARCH_FAC_LIST_SIZE_BYTE);
+ sizeof(S390_lowcore.stfle_fac_list));
if (copy_to_user((void __user *)attr->addr, mach, sizeof(*mach)))
ret = -EFAULT;
kfree(mach);
/* Populate the facility mask initially. */
memcpy(kvm->arch.model.fac_mask, S390_lowcore.stfle_fac_list,
- S390_ARCH_FAC_LIST_SIZE_BYTE);
+ sizeof(S390_lowcore.stfle_fac_list));
for (i = 0; i < S390_ARCH_FAC_LIST_SIZE_U64; i++) {
if (i < kvm_s390_fac_list_mask_size())
kvm->arch.model.fac_mask[i] &= kvm_s390_fac_list_mask[i];
return pgste;
}
-static inline void ptep_xchg_commit(struct mm_struct *mm,
+static inline pte_t ptep_xchg_commit(struct mm_struct *mm,
unsigned long addr, pte_t *ptep,
pgste_t pgste, pte_t old, pte_t new)
{
} else {
*ptep = new;
}
+ return old;
}
pte_t ptep_xchg_direct(struct mm_struct *mm, unsigned long addr,
preempt_disable();
pgste = ptep_xchg_start(mm, addr, ptep);
old = ptep_flush_direct(mm, addr, ptep);
- ptep_xchg_commit(mm, addr, ptep, pgste, old, new);
+ old = ptep_xchg_commit(mm, addr, ptep, pgste, old, new);
preempt_enable();
return old;
}
preempt_disable();
pgste = ptep_xchg_start(mm, addr, ptep);
old = ptep_flush_lazy(mm, addr, ptep);
- ptep_xchg_commit(mm, addr, ptep, pgste, old, new);
+ old = ptep_xchg_commit(mm, addr, ptep, pgste, old, new);
preempt_enable();
return old;
}
static inline void tsb_context_switch(struct mm_struct *mm)
{
__tsb_context_switch(__pa(mm->pgd),
- &mm->context.tsb_block[0],
+ &mm->context.tsb_block[MM_TSB_BASE],
#if defined(CONFIG_HUGETLB_PAGE) || defined(CONFIG_TRANSPARENT_HUGEPAGE)
- (mm->context.tsb_block[1].tsb ?
- &mm->context.tsb_block[1] :
+ (mm->context.tsb_block[MM_TSB_HUGE].tsb ?
+ &mm->context.tsb_block[MM_TSB_HUGE] :
NULL)
#else
NULL
#endif
- , __pa(&mm->context.tsb_descr[0]));
+ , __pa(&mm->context.tsb_descr[MM_TSB_BASE]));
}
void tsb_grow(struct mm_struct *mm,
unsigned long order = get_order(size);
unsigned long p;
- p = __get_free_pages(GFP_KERNEL, order);
+ p = __get_free_pages(GFP_KERNEL | __GFP_ZERO, order);
if (!p) {
prom_printf("SUN4V: Error, cannot allocate queue.\n");
prom_halt();
"Linux powering off";
static const char rebooting_msg[32] __attribute__((aligned(32))) =
"Linux rebooting";
-static const char panicing_msg[32] __attribute__((aligned(32))) =
- "Linux panicing";
+static const char panicking_msg[32] __attribute__((aligned(32))) =
+ "Linux panicking";
static int sstate_reboot_call(struct notifier_block *np, unsigned long type, void *_unused)
{
static int sstate_panic_event(struct notifier_block *n, unsigned long event, void *ptr)
{
- do_set_sstate(HV_SOFT_STATE_TRANSITION, panicing_msg);
+ do_set_sstate(HV_SOFT_STATE_TRANSITION, panicking_msg);
return NOTIFY_DONE;
}
atomic_inc(&sun4v_resum_oflow_cnt);
}
+/* Given a set of registers, get the virtual addressi that was being accessed
+ * by the faulting instructions at tpc.
+ */
+static unsigned long sun4v_get_vaddr(struct pt_regs *regs)
+{
+ unsigned int insn;
+
+ if (!copy_from_user(&insn, (void __user *)regs->tpc, 4)) {
+ return compute_effective_address(regs, insn,
+ (insn >> 25) & 0x1f);
+ }
+ return 0;
+}
+
+/* Attempt to handle non-resumable errors generated from userspace.
+ * Returns true if the signal was handled, false otherwise.
+ */
+bool sun4v_nonresum_error_user_handled(struct pt_regs *regs,
+ struct sun4v_error_entry *ent) {
+
+ unsigned int attrs = ent->err_attrs;
+
+ if (attrs & SUN4V_ERR_ATTRS_MEMORY) {
+ unsigned long addr = ent->err_raddr;
+ siginfo_t info;
+
+ if (addr == ~(u64)0) {
+ /* This seems highly unlikely to ever occur */
+ pr_emerg("SUN4V NON-RECOVERABLE ERROR: Memory error detected in unknown location!\n");
+ } else {
+ unsigned long page_cnt = DIV_ROUND_UP(ent->err_size,
+ PAGE_SIZE);
+
+ /* Break the unfortunate news. */
+ pr_emerg("SUN4V NON-RECOVERABLE ERROR: Memory failed at %016lX\n",
+ addr);
+ pr_emerg("SUN4V NON-RECOVERABLE ERROR: Claiming %lu ages.\n",
+ page_cnt);
+
+ while (page_cnt-- > 0) {
+ if (pfn_valid(addr >> PAGE_SHIFT))
+ get_page(pfn_to_page(addr >> PAGE_SHIFT));
+ addr += PAGE_SIZE;
+ }
+ }
+ info.si_signo = SIGKILL;
+ info.si_errno = 0;
+ info.si_trapno = 0;
+ force_sig_info(info.si_signo, &info, current);
+
+ return true;
+ }
+ if (attrs & SUN4V_ERR_ATTRS_PIO) {
+ siginfo_t info;
+
+ info.si_signo = SIGBUS;
+ info.si_code = BUS_ADRERR;
+ info.si_addr = (void __user *)sun4v_get_vaddr(regs);
+ force_sig_info(info.si_signo, &info, current);
+
+ return true;
+ }
+
+ /* Default to doing nothing */
+ return false;
+}
+
/* We run with %pil set to PIL_NORMAL_MAX and PSTATE_IE enabled in %pstate.
* Log the event, clear the first word of the entry, and die.
*/
put_cpu();
+ if (!(regs->tstate & TSTATE_PRIV) &&
+ sun4v_nonresum_error_user_handled(regs, &local_copy)) {
+ /* DON'T PANIC: This userspace error was handled. */
+ return;
+ }
+
#ifdef CONFIG_PCI
/* Check for the special PCI poke sequence. */
if (pci_poke_in_progress && pci_poke_cpu == cpu) {
const void *kbuf, const void __user *ubuf)
{
int ret;
- struct pt_regs regs;
+ struct pt_regs regs = *task_pt_regs(target);
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, ®s, 0,
sizeof(regs));
#include <linux/types.h>
#include "ctype.h"
+#include "string.h"
int memcmp(const void *s1, const void *s2, size_t len)
{
#define memset(d,c,l) __builtin_memset(d,c,l)
#define memcmp __builtin_memcmp
+extern int strcmp(const char *str1, const char *str2);
+extern int strncmp(const char *cs, const char *ct, size_t count);
+extern size_t strlen(const char *s);
+extern char *strstr(const char *s1, const char *s2);
+extern size_t strnlen(const char *s, size_t maxlen);
+extern unsigned int atou(const char *s);
+extern unsigned long long simple_strtoull(const char *cp, char **endp,
+ unsigned int base);
+
#endif /* BOOT_STRING_H */
const char *basename;
struct simd_skcipher_alg *simd;
} aesni_simd_skciphers2[] = {
-#if IS_ENABLED(CONFIG_CRYPTO_PCBC)
+#if (defined(MODULE) && IS_ENABLED(CONFIG_CRYPTO_PCBC)) || \
+ IS_BUILTIN(CONFIG_CRYPTO_PCBC)
{
.algname = "pcbc(aes)",
.drvname = "pcbc-aes-aesni",
jmp __switch_to
END(__switch_to_asm)
-/*
- * The unwinder expects the last frame on the stack to always be at the same
- * offset from the end of the page, which allows it to validate the stack.
- * Calling schedule_tail() directly would break that convention because its an
- * asmlinkage function so its argument has to be pushed on the stack. This
- * wrapper creates a proper "end of stack" frame header before the call.
- */
-ENTRY(schedule_tail_wrapper)
- FRAME_BEGIN
-
- pushl %eax
- call schedule_tail
- popl %eax
-
- FRAME_END
- ret
-ENDPROC(schedule_tail_wrapper)
/*
* A newly forked process directly context switches into this address.
*
* edi: kernel thread arg
*/
ENTRY(ret_from_fork)
- call schedule_tail_wrapper
+ FRAME_BEGIN /* help unwinder find end of stack */
+
+ /*
+ * schedule_tail() is asmlinkage so we have to put its 'prev' argument
+ * on the stack.
+ */
+ pushl %eax
+ call schedule_tail
+ popl %eax
testl %ebx, %ebx
jnz 1f /* kernel threads are uncommon */
2:
/* When we fork, we trace the syscall return in the child, too. */
- movl %esp, %eax
+ leal FRAME_OFFSET(%esp), %eax
call syscall_return_slowpath
+ FRAME_END
jmp restore_all
/* kernel thread */
#include <asm/smap.h>
#include <asm/pgtable_types.h>
#include <asm/export.h>
+#include <asm/frame.h>
#include <linux/err.h>
.code64
* r12: kernel thread arg
*/
ENTRY(ret_from_fork)
+ FRAME_BEGIN /* help unwinder find end of stack */
movq %rax, %rdi
- call schedule_tail /* rdi: 'prev' task parameter */
+ call schedule_tail /* rdi: 'prev' task parameter */
- testq %rbx, %rbx /* from kernel_thread? */
- jnz 1f /* kernel threads are uncommon */
+ testq %rbx, %rbx /* from kernel_thread? */
+ jnz 1f /* kernel threads are uncommon */
2:
- movq %rsp, %rdi
+ leaq FRAME_OFFSET(%rsp),%rdi /* pt_regs pointer */
call syscall_return_slowpath /* returns with IRQs disabled */
TRACE_IRQS_ON /* user mode is traced as IRQS on */
SWAPGS
+ FRAME_END
jmp restore_regs_and_iret
1:
* all online cpus.
*/
cpuhp_setup_state(CPUHP_AP_PERF_X86_AMD_IBS_STARTING,
- "perf/x86/amd/ibs:STARTING",
+ "perf/x86/amd/ibs:starting",
x86_pmu_amd_ibs_starting_cpu,
x86_pmu_amd_ibs_dying_cpu);
if (event->attr.precise_ip > precise)
return -EOPNOTSUPP;
+
+ /* There's no sense in having PEBS for non sampling events: */
+ if (!is_sampling_event(event))
+ return -EINVAL;
}
/*
* check that PEBS LBR correction does not conflict with
if (x86_pmu.flags & PMU_FL_EXCL_CNTRS) {
for_each_cpu(i, topology_sibling_cpumask(cpu)) {
+ struct cpu_hw_events *sibling;
struct intel_excl_cntrs *c;
- c = per_cpu(cpu_hw_events, i).excl_cntrs;
+ sibling = &per_cpu(cpu_hw_events, i);
+ c = sibling->excl_cntrs;
if (c && c->core_id == core_id) {
cpuc->kfree_on_online[1] = cpuc->excl_cntrs;
cpuc->excl_cntrs = c;
- cpuc->excl_thread_id = 1;
+ if (!sibling->excl_thread_id)
+ cpuc->excl_thread_id = 1;
break;
}
}
x86_pmu.num_counters, INTEL_PMC_MAX_GENERIC);
x86_pmu.num_counters = INTEL_PMC_MAX_GENERIC;
}
- x86_pmu.intel_ctrl = (1 << x86_pmu.num_counters) - 1;
+ x86_pmu.intel_ctrl = (1ULL << x86_pmu.num_counters) - 1;
if (x86_pmu.num_counters_fixed > INTEL_PMC_MAX_FIXED) {
WARN(1, KERN_ERR "hw perf events fixed %d > max(%d), clipping!",
.stop = cstate_pmu_event_stop,
.read = cstate_pmu_event_update,
.capabilities = PERF_PMU_CAP_NO_INTERRUPT,
+ .module = THIS_MODULE,
};
static struct pmu cstate_pkg_pmu = {
.stop = cstate_pmu_event_stop,
.read = cstate_pmu_event_update,
.capabilities = PERF_PMU_CAP_NO_INTERRUPT,
+ .module = THIS_MODULE,
};
static const struct cstate_model nhm_cstates __initconst = {
continue;
/* log dropped samples number */
- if (error[bit])
+ if (error[bit]) {
perf_log_lost_samples(event, error[bit]);
+ if (perf_event_account_interrupt(event))
+ x86_pmu_stop(event, 0);
+ }
+
if (counts[bit]) {
__intel_pmu_pebs_event(event, iregs, base,
top, bit, counts[bit]);
static inline struct rapl_pmu *cpu_to_rapl_pmu(unsigned int cpu)
{
- return rapl_pmus->pmus[topology_logical_package_id(cpu)];
+ unsigned int pkgid = topology_logical_package_id(cpu);
+
+ /*
+ * The unsigned check also catches the '-1' return value for non
+ * existent mappings in the topology map.
+ */
+ return pkgid < rapl_pmus->maxpkg ? rapl_pmus->pmus[pkgid] : NULL;
}
static inline u64 rapl_read_counter(struct perf_event *event)
/* must be done before validate_group */
pmu = cpu_to_rapl_pmu(event->cpu);
+ if (!pmu)
+ return -EINVAL;
event->cpu = pmu->cpu;
event->pmu_private = pmu;
event->hw.event_base = msr;
struct rapl_pmu *pmu = cpu_to_rapl_pmu(cpu);
int target;
+ if (!pmu) {
+ pmu = kzalloc_node(sizeof(*pmu), GFP_KERNEL, cpu_to_node(cpu));
+ if (!pmu)
+ return -ENOMEM;
+
+ raw_spin_lock_init(&pmu->lock);
+ INIT_LIST_HEAD(&pmu->active_list);
+ pmu->pmu = &rapl_pmus->pmu;
+ pmu->timer_interval = ms_to_ktime(rapl_timer_ms);
+ rapl_hrtimer_init(pmu);
+
+ rapl_pmus->pmus[topology_logical_package_id(cpu)] = pmu;
+ }
+
/*
* Check if there is an online cpu in the package which collects rapl
* events already.
return 0;
}
-static int rapl_cpu_prepare(unsigned int cpu)
-{
- struct rapl_pmu *pmu = cpu_to_rapl_pmu(cpu);
-
- if (pmu)
- return 0;
-
- pmu = kzalloc_node(sizeof(*pmu), GFP_KERNEL, cpu_to_node(cpu));
- if (!pmu)
- return -ENOMEM;
-
- raw_spin_lock_init(&pmu->lock);
- INIT_LIST_HEAD(&pmu->active_list);
- pmu->pmu = &rapl_pmus->pmu;
- pmu->timer_interval = ms_to_ktime(rapl_timer_ms);
- pmu->cpu = -1;
- rapl_hrtimer_init(pmu);
- rapl_pmus->pmus[topology_logical_package_id(cpu)] = pmu;
- return 0;
-}
-
static int rapl_check_hw_unit(bool apply_quirk)
{
u64 msr_rapl_power_unit_bits;
rapl_pmus->pmu.start = rapl_pmu_event_start;
rapl_pmus->pmu.stop = rapl_pmu_event_stop;
rapl_pmus->pmu.read = rapl_pmu_event_read;
+ rapl_pmus->pmu.module = THIS_MODULE;
return 0;
}
/*
* Install callbacks. Core will call them for each online cpu.
*/
-
- ret = cpuhp_setup_state(CPUHP_PERF_X86_RAPL_PREP, "perf/x86/rapl:prepare",
- rapl_cpu_prepare, NULL);
- if (ret)
- goto out;
-
ret = cpuhp_setup_state(CPUHP_AP_PERF_X86_RAPL_ONLINE,
"perf/x86/rapl:online",
rapl_cpu_online, rapl_cpu_offline);
if (ret)
- goto out1;
+ goto out;
ret = perf_pmu_register(&rapl_pmus->pmu, "power", -1);
if (ret)
- goto out2;
+ goto out1;
rapl_advertise();
return 0;
-out2:
- cpuhp_remove_state(CPUHP_AP_PERF_X86_RAPL_ONLINE);
out1:
- cpuhp_remove_state(CPUHP_PERF_X86_RAPL_PREP);
+ cpuhp_remove_state(CPUHP_AP_PERF_X86_RAPL_ONLINE);
out:
pr_warn("Initialization failed (%d), disabled\n", ret);
cleanup_rapl_pmus();
static void __exit intel_rapl_exit(void)
{
cpuhp_remove_state_nocalls(CPUHP_AP_PERF_X86_RAPL_ONLINE);
- cpuhp_remove_state_nocalls(CPUHP_PERF_X86_RAPL_PREP);
perf_pmu_unregister(&rapl_pmus->pmu);
cleanup_rapl_pmus();
}
struct intel_uncore_box *uncore_pmu_to_box(struct intel_uncore_pmu *pmu, int cpu)
{
- return pmu->boxes[topology_logical_package_id(cpu)];
+ unsigned int pkgid = topology_logical_package_id(cpu);
+
+ /*
+ * The unsigned check also catches the '-1' return value for non
+ * existent mappings in the topology map.
+ */
+ return pkgid < max_packages ? pmu->boxes[pkgid] : NULL;
}
u64 uncore_msr_read_counter(struct intel_uncore_box *box, struct perf_event *event)
.start = uncore_pmu_event_start,
.stop = uncore_pmu_event_stop,
.read = uncore_pmu_event_read,
+ .module = THIS_MODULE,
};
} else {
pmu->pmu = *pmu->type->pmu;
pmu->registered = false;
}
-static void __uncore_exit_boxes(struct intel_uncore_type *type, int cpu)
-{
- struct intel_uncore_pmu *pmu = type->pmus;
- struct intel_uncore_box *box;
- int i, pkg;
-
- if (pmu) {
- pkg = topology_physical_package_id(cpu);
- for (i = 0; i < type->num_boxes; i++, pmu++) {
- box = pmu->boxes[pkg];
- if (box)
- uncore_box_exit(box);
- }
- }
-}
-
-static void uncore_exit_boxes(void *dummy)
-{
- struct intel_uncore_type **types;
-
- for (types = uncore_msr_uncores; *types; types++)
- __uncore_exit_boxes(*types++, smp_processor_id());
-}
-
static void uncore_free_boxes(struct intel_uncore_pmu *pmu)
{
int pkg;
}
}
-static int uncore_cpu_dying(unsigned int cpu)
-{
- struct intel_uncore_type *type, **types = uncore_msr_uncores;
- struct intel_uncore_pmu *pmu;
- struct intel_uncore_box *box;
- int i, pkg;
-
- pkg = topology_logical_package_id(cpu);
- for (; *types; types++) {
- type = *types;
- pmu = type->pmus;
- for (i = 0; i < type->num_boxes; i++, pmu++) {
- box = pmu->boxes[pkg];
- if (box && atomic_dec_return(&box->refcnt) == 0)
- uncore_box_exit(box);
- }
- }
- return 0;
-}
-
-static int first_init;
-
-static int uncore_cpu_starting(unsigned int cpu)
-{
- struct intel_uncore_type *type, **types = uncore_msr_uncores;
- struct intel_uncore_pmu *pmu;
- struct intel_uncore_box *box;
- int i, pkg, ncpus = 1;
-
- if (first_init) {
- /*
- * On init we get the number of online cpus in the package
- * and set refcount for all of them.
- */
- ncpus = cpumask_weight(topology_core_cpumask(cpu));
- }
-
- pkg = topology_logical_package_id(cpu);
- for (; *types; types++) {
- type = *types;
- pmu = type->pmus;
- for (i = 0; i < type->num_boxes; i++, pmu++) {
- box = pmu->boxes[pkg];
- if (!box)
- continue;
- /* The first cpu on a package activates the box */
- if (atomic_add_return(ncpus, &box->refcnt) == ncpus)
- uncore_box_init(box);
- }
- }
-
- return 0;
-}
-
-static int uncore_cpu_prepare(unsigned int cpu)
-{
- struct intel_uncore_type *type, **types = uncore_msr_uncores;
- struct intel_uncore_pmu *pmu;
- struct intel_uncore_box *box;
- int i, pkg;
-
- pkg = topology_logical_package_id(cpu);
- for (; *types; types++) {
- type = *types;
- pmu = type->pmus;
- for (i = 0; i < type->num_boxes; i++, pmu++) {
- if (pmu->boxes[pkg])
- continue;
- /* First cpu of a package allocates the box */
- box = uncore_alloc_box(type, cpu_to_node(cpu));
- if (!box)
- return -ENOMEM;
- box->pmu = pmu;
- box->pkgid = pkg;
- pmu->boxes[pkg] = box;
- }
- }
- return 0;
-}
-
static void uncore_change_type_ctx(struct intel_uncore_type *type, int old_cpu,
int new_cpu)
{
static int uncore_event_cpu_offline(unsigned int cpu)
{
- int target;
+ struct intel_uncore_type *type, **types = uncore_msr_uncores;
+ struct intel_uncore_pmu *pmu;
+ struct intel_uncore_box *box;
+ int i, pkg, target;
/* Check if exiting cpu is used for collecting uncore events */
if (!cpumask_test_and_clear_cpu(cpu, &uncore_cpu_mask))
- return 0;
-
+ goto unref;
/* Find a new cpu to collect uncore events */
target = cpumask_any_but(topology_core_cpumask(cpu), cpu);
uncore_change_context(uncore_msr_uncores, cpu, target);
uncore_change_context(uncore_pci_uncores, cpu, target);
+
+unref:
+ /* Clear the references */
+ pkg = topology_logical_package_id(cpu);
+ for (; *types; types++) {
+ type = *types;
+ pmu = type->pmus;
+ for (i = 0; i < type->num_boxes; i++, pmu++) {
+ box = pmu->boxes[pkg];
+ if (box && atomic_dec_return(&box->refcnt) == 0)
+ uncore_box_exit(box);
+ }
+ }
return 0;
}
+static int allocate_boxes(struct intel_uncore_type **types,
+ unsigned int pkg, unsigned int cpu)
+{
+ struct intel_uncore_box *box, *tmp;
+ struct intel_uncore_type *type;
+ struct intel_uncore_pmu *pmu;
+ LIST_HEAD(allocated);
+ int i;
+
+ /* Try to allocate all required boxes */
+ for (; *types; types++) {
+ type = *types;
+ pmu = type->pmus;
+ for (i = 0; i < type->num_boxes; i++, pmu++) {
+ if (pmu->boxes[pkg])
+ continue;
+ box = uncore_alloc_box(type, cpu_to_node(cpu));
+ if (!box)
+ goto cleanup;
+ box->pmu = pmu;
+ box->pkgid = pkg;
+ list_add(&box->active_list, &allocated);
+ }
+ }
+ /* Install them in the pmus */
+ list_for_each_entry_safe(box, tmp, &allocated, active_list) {
+ list_del_init(&box->active_list);
+ box->pmu->boxes[pkg] = box;
+ }
+ return 0;
+
+cleanup:
+ list_for_each_entry_safe(box, tmp, &allocated, active_list) {
+ list_del_init(&box->active_list);
+ kfree(box);
+ }
+ return -ENOMEM;
+}
+
static int uncore_event_cpu_online(unsigned int cpu)
{
- int target;
+ struct intel_uncore_type *type, **types = uncore_msr_uncores;
+ struct intel_uncore_pmu *pmu;
+ struct intel_uncore_box *box;
+ int i, ret, pkg, target;
+
+ pkg = topology_logical_package_id(cpu);
+ ret = allocate_boxes(types, pkg, cpu);
+ if (ret)
+ return ret;
+
+ for (; *types; types++) {
+ type = *types;
+ pmu = type->pmus;
+ for (i = 0; i < type->num_boxes; i++, pmu++) {
+ box = pmu->boxes[pkg];
+ if (!box && atomic_inc_return(&box->refcnt) == 1)
+ uncore_box_init(box);
+ }
+ }
/*
* Check if there is an online cpu in the package
if (cret && pret)
return -ENODEV;
- /*
- * Install callbacks. Core will call them for each online cpu.
- *
- * The first online cpu of each package allocates and takes
- * the refcounts for all other online cpus in that package.
- * If msrs are not enabled no allocation is required and
- * uncore_cpu_prepare() is not called for each online cpu.
- */
- if (!cret) {
- ret = cpuhp_setup_state(CPUHP_PERF_X86_UNCORE_PREP,
- "perf/x86/intel/uncore:prepare",
- uncore_cpu_prepare, NULL);
- if (ret)
- goto err;
- } else {
- cpuhp_setup_state_nocalls(CPUHP_PERF_X86_UNCORE_PREP,
- "perf/x86/intel/uncore:prepare",
- uncore_cpu_prepare, NULL);
- }
- first_init = 1;
- cpuhp_setup_state(CPUHP_AP_PERF_X86_UNCORE_STARTING,
- "perf/x86/uncore:starting",
- uncore_cpu_starting, uncore_cpu_dying);
- first_init = 0;
- cpuhp_setup_state(CPUHP_AP_PERF_X86_UNCORE_ONLINE,
- "perf/x86/uncore:online",
- uncore_event_cpu_online, uncore_event_cpu_offline);
+ /* Install hotplug callbacks to setup the targets for each package */
+ ret = cpuhp_setup_state(CPUHP_AP_PERF_X86_UNCORE_ONLINE,
+ "perf/x86/intel/uncore:online",
+ uncore_event_cpu_online,
+ uncore_event_cpu_offline);
+ if (ret)
+ goto err;
return 0;
err:
- /* Undo box->init_box() */
- on_each_cpu_mask(&uncore_cpu_mask, uncore_exit_boxes, NULL, 1);
uncore_types_exit(uncore_msr_uncores);
uncore_pci_exit();
return ret;
static void __exit intel_uncore_exit(void)
{
- cpuhp_remove_state_nocalls(CPUHP_AP_PERF_X86_UNCORE_ONLINE);
- cpuhp_remove_state_nocalls(CPUHP_AP_PERF_X86_UNCORE_STARTING);
- cpuhp_remove_state_nocalls(CPUHP_PERF_X86_UNCORE_PREP);
+ cpuhp_remove_state(CPUHP_AP_PERF_X86_UNCORE_ONLINE);
uncore_types_exit(uncore_msr_uncores);
uncore_pci_exit();
}
void hswep_uncore_cpu_init(void)
{
- int pkg = topology_phys_to_logical_pkg(0);
+ int pkg = boot_cpu_data.logical_proc_id;
if (hswep_uncore_cbox.num_boxes > boot_cpu_data.x86_max_cores)
hswep_uncore_cbox.num_boxes = boot_cpu_data.x86_max_cores;
#define INTEL_FAM6_ATOM_SILVERMONT2 0x4D /* Avaton/Rangely */
#define INTEL_FAM6_ATOM_AIRMONT 0x4C /* CherryTrail / Braswell */
#define INTEL_FAM6_ATOM_MERRIFIELD 0x4A /* Tangier */
-#define INTEL_FAM6_ATOM_MOOREFIELD 0x5A /* Annidale */
+#define INTEL_FAM6_ATOM_MOOREFIELD 0x5A /* Anniedale */
#define INTEL_FAM6_ATOM_GOLDMONT 0x5C
#define INTEL_FAM6_ATOM_DENVERTON 0x5F /* Goldmont Microserver */
extern void load_ucode_ap(void);
void reload_early_microcode(void);
extern bool get_builtin_firmware(struct cpio_data *cd, const char *name);
+extern bool initrd_gone;
#else
static inline int __init microcode_init(void) { return 0; };
static inline void __init load_ucode_bsp(void) { }
#define exttable_size(et) ((et)->count * EXT_SIGNATURE_SIZE + EXT_HEADER_SIZE)
+static inline u32 intel_get_microcode_revision(void)
+{
+ u32 rev, dummy;
+
+ native_wrmsrl(MSR_IA32_UCODE_REV, 0);
+
+ /* As documented in the SDM: Do a CPUID 1 here */
+ native_cpuid_eax(1);
+
+ /* get the current revision from MSR 0x8B */
+ native_rdmsr(MSR_IA32_UCODE_REV, dummy, rev);
+
+ return rev;
+}
+
#ifdef CONFIG_MICROCODE_INTEL
extern void __init load_ucode_intel_bsp(void);
extern void load_ucode_intel_ap(void);
: "memory");
}
+#define native_cpuid_reg(reg) \
+static inline unsigned int native_cpuid_##reg(unsigned int op) \
+{ \
+ unsigned int eax = op, ebx, ecx = 0, edx; \
+ \
+ native_cpuid(&eax, &ebx, &ecx, &edx); \
+ \
+ return reg; \
+}
+
+/*
+ * Native CPUID functions returning a single datum.
+ */
+native_cpuid_reg(eax)
+native_cpuid_reg(ebx)
+native_cpuid_reg(ecx)
+native_cpuid_reg(edx)
+
static inline void load_cr3(pgd_t *pgdir)
{
write_cr3(__pa(pgdir));
if (task == current)
return __builtin_frame_address(0);
- return (unsigned long *)((struct inactive_task_frame *)task->thread.sp)->bp;
+ return &((struct inactive_task_frame *)task->thread.sp)->bp;
}
#else
static inline unsigned long *
asmlinkage void ret_from_fork(void);
-/* data that is pointed to by thread.sp */
+/*
+ * This is the structure pointed to by thread.sp for an inactive task. The
+ * order of the fields must match the code in __switch_to_asm().
+ */
struct inactive_task_frame {
#ifdef CONFIG_X86_64
unsigned long r15;
unsigned long di;
#endif
unsigned long bx;
+
+ /*
+ * These two fields must be together. They form a stack frame header,
+ * needed by get_frame_pointer().
+ */
unsigned long bp;
unsigned long ret_addr;
};
.irq_ack = irq_chip_ack_parent,
.irq_eoi = ioapic_ack_level,
.irq_set_affinity = ioapic_set_affinity,
+ .irq_retrigger = irq_chip_retrigger_hierarchy,
.flags = IRQCHIP_SKIP_SET_WAKE,
};
.irq_ack = irq_chip_ack_parent,
.irq_eoi = ioapic_ir_ack_level,
.irq_set_affinity = ioapic_set_affinity,
+ .irq_retrigger = irq_chip_retrigger_hierarchy,
.flags = IRQCHIP_SKIP_SET_WAKE,
};
if (idx != -1 && irq_trigger(idx))
unmask_ioapic_irq(irq_get_chip_data(0));
}
+ irq_domain_deactivate_irq(irq_data);
irq_domain_activate_irq(irq_data);
if (timer_irq_works()) {
if (disable_timer_pin_1 > 0)
* legacy devices should be connected to IO APIC #0
*/
replace_pin_at_irq_node(data, node, apic1, pin1, apic2, pin2);
+ irq_domain_deactivate_irq(irq_data);
irq_domain_activate_irq(irq_data);
legacy_pic->unmask(0);
if (timer_irq_works()) {
/* get information required for multi-node processors */
if (boot_cpu_has(X86_FEATURE_TOPOEXT)) {
- u32 eax, ebx, ecx, edx;
- cpuid(0x8000001e, &eax, &ebx, &ecx, &edx);
- node_id = ecx & 7;
-
- /* get compute unit information */
- smp_num_siblings = ((ebx >> 8) & 3) + 1;
- c->x86_max_cores /= smp_num_siblings;
- c->cpu_core_id = ebx & 0xff;
+ node_id = cpuid_ecx(0x8000001e) & 7;
/*
* We may have multiple LLCs if L3 caches exist, so check if we
{
int bit;
- if (get_option(&arg, &bit) && bit < NCAPINTS*32)
+ if (get_option(&arg, &bit) && bit >= 0 && bit < NCAPINTS * 32)
setup_clear_cpu_cap(bit);
else
return 0;
#include <asm/bugs.h>
#include <asm/cpu.h>
#include <asm/intel-family.h>
+#include <asm/microcode_intel.h>
#ifdef CONFIG_X86_64
#include <linux/topology.h>
(c->x86 == 0x6 && c->x86_model >= 0x0e))
set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
- if (c->x86 >= 6 && !cpu_has(c, X86_FEATURE_IA64)) {
- unsigned lower_word;
-
- wrmsr(MSR_IA32_UCODE_REV, 0, 0);
- /* Required by the SDM */
- sync_core();
- rdmsr(MSR_IA32_UCODE_REV, lower_word, c->microcode);
- }
+ if (c->x86 >= 6 && !cpu_has(c, X86_FEATURE_IA64))
+ c->microcode = intel_get_microcode_revision();
/*
* Atom erratum AAE44/AAF40/AAG38/AAH41:
static unsigned long (*mce_adjust_timer)(unsigned long interval) = mce_adjust_timer_default;
-static void __restart_timer(struct timer_list *t, unsigned long interval)
+static void __start_timer(struct timer_list *t, unsigned long interval)
{
unsigned long when = jiffies + interval;
unsigned long flags;
local_irq_save(flags);
- if (timer_pending(t)) {
- if (time_before(when, t->expires))
- mod_timer(t, when);
- } else {
- t->expires = round_jiffies(when);
- add_timer_on(t, smp_processor_id());
- }
+ if (!timer_pending(t) || time_before(when, t->expires))
+ mod_timer(t, round_jiffies(when));
local_irq_restore(flags);
}
done:
__this_cpu_write(mce_next_interval, iv);
- __restart_timer(t, iv);
+ __start_timer(t, iv);
}
/*
struct timer_list *t = this_cpu_ptr(&mce_timer);
unsigned long iv = __this_cpu_read(mce_next_interval);
- __restart_timer(t, interval);
+ __start_timer(t, interval);
if (interval < iv)
__this_cpu_write(mce_next_interval, interval);
}
}
-static void mce_start_timer(unsigned int cpu, struct timer_list *t)
+static void mce_start_timer(struct timer_list *t)
{
unsigned long iv = check_interval * HZ;
if (mca_cfg.ignore_ce || !iv)
return;
- per_cpu(mce_next_interval, cpu) = iv;
-
- t->expires = round_jiffies(jiffies + iv);
- add_timer_on(t, cpu);
+ this_cpu_write(mce_next_interval, iv);
+ __start_timer(t, iv);
}
static void __mcheck_cpu_setup_timer(void)
unsigned int cpu = smp_processor_id();
setup_pinned_timer(t, mce_timer_fn, cpu);
- mce_start_timer(cpu, t);
+ mce_start_timer(t);
}
/* Handle unconfigured int18 (should never happen) */
static int mce_cpu_online(unsigned int cpu)
{
- struct timer_list *t = &per_cpu(mce_timer, cpu);
+ struct timer_list *t = this_cpu_ptr(&mce_timer);
int ret;
mce_device_create(cpu);
return ret;
}
mce_reenable_cpu();
- mce_start_timer(cpu, t);
+ mce_start_timer(t);
return 0;
}
static int mce_cpu_pre_down(unsigned int cpu)
{
- struct timer_list *t = &per_cpu(mce_timer, cpu);
+ struct timer_list *t = this_cpu_ptr(&mce_timer);
mce_disable_cpu();
del_timer_sync(t);
reget:
if (!get_builtin_microcode(&cp, family)) {
#ifdef CONFIG_BLK_DEV_INITRD
- cp = find_cpio_data(ucode_path, (void *)initrd_start,
- initrd_end - initrd_start, NULL);
+ if (!initrd_gone)
+ cp = find_cpio_data(ucode_path, (void *)initrd_start,
+ initrd_end - initrd_start, NULL);
#endif
if (!(cp.data && cp.size)) {
/*
static struct microcode_ops *microcode_ops;
static bool dis_ucode_ldr = true;
+bool initrd_gone;
+
LIST_HEAD(microcode_cache);
/*
static int __init save_microcode_in_initrd(void)
{
struct cpuinfo_x86 *c = &boot_cpu_data;
+ int ret = -EINVAL;
switch (c->x86_vendor) {
case X86_VENDOR_INTEL:
if (c->x86 >= 6)
- return save_microcode_in_initrd_intel();
+ ret = save_microcode_in_initrd_intel();
break;
case X86_VENDOR_AMD:
if (c->x86 >= 0x10)
- return save_microcode_in_initrd_amd(c->x86);
+ ret = save_microcode_in_initrd_amd(c->x86);
break;
default:
break;
}
- return -EINVAL;
+ initrd_gone = true;
+
+ return ret;
}
struct cpio_data find_microcode_in_initrd(const char *path, bool use_pa)
* has the virtual address of the beginning of the initrd. It also
* possibly relocates the ramdisk. In either case, initrd_start contains
* the updated address so use that instead.
+ *
+ * initrd_gone is for the hotplug case where we've thrown out initrd
+ * already.
*/
- if (!use_pa && initrd_start)
- start = initrd_start;
+ if (!use_pa) {
+ if (initrd_gone)
+ return (struct cpio_data){ NULL, 0, "" };
+ if (initrd_start)
+ start = initrd_start;
+ }
return find_cpio_data(path, (void *)start, size, NULL);
#else /* !CONFIG_BLK_DEV_INITRD */
static const char ucode_path[] = "kernel/x86/microcode/GenuineIntel.bin";
-/* Current microcode patch used in early patching */
+/* Current microcode patch used in early patching on the APs. */
struct microcode_intel *intel_ucode_patch;
static inline bool cpu_signatures_match(unsigned int s1, unsigned int p1,
{
struct ucode_patch *p;
- p = kzalloc(size, GFP_KERNEL);
+ p = kzalloc(sizeof(struct ucode_patch), GFP_KERNEL);
if (!p)
return ERR_PTR(-ENOMEM);
return patch;
}
-static void cpuid_1(void)
-{
- /*
- * According to the Intel SDM, Volume 3, 9.11.7:
- *
- * CPUID returns a value in a model specific register in
- * addition to its usual register return values. The
- * semantics of CPUID cause it to deposit an update ID value
- * in the 64-bit model-specific register at address 08BH
- * (IA32_BIOS_SIGN_ID). If no update is present in the
- * processor, the value in the MSR remains unmodified.
- *
- * Use native_cpuid -- this code runs very early and we don't
- * want to mess with paravirt.
- */
- unsigned int eax = 1, ebx, ecx = 0, edx;
-
- native_cpuid(&eax, &ebx, &ecx, &edx);
-}
-
static int collect_cpu_info_early(struct ucode_cpu_info *uci)
{
unsigned int val[2];
native_rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
csig.pf = 1 << ((val[1] >> 18) & 7);
}
- native_wrmsrl(MSR_IA32_UCODE_REV, 0);
-
- /* As documented in the SDM: Do a CPUID 1 here */
- cpuid_1();
-
- /* get the current revision from MSR 0x8B */
- native_rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
- csig.rev = val[1];
+ csig.rev = intel_get_microcode_revision();
uci->cpu_sig = csig;
uci->valid = 1;
static int apply_microcode_early(struct ucode_cpu_info *uci, bool early)
{
struct microcode_intel *mc;
- unsigned int val[2];
+ u32 rev;
mc = uci->mc;
if (!mc)
/* write microcode via MSR 0x79 */
native_wrmsrl(MSR_IA32_UCODE_WRITE, (unsigned long)mc->bits);
- native_wrmsrl(MSR_IA32_UCODE_REV, 0);
-
- /* As documented in the SDM: Do a CPUID 1 here */
- cpuid_1();
- /* get the current revision from MSR 0x8B */
- native_rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
- if (val[1] != mc->hdr.rev)
+ rev = intel_get_microcode_revision();
+ if (rev != mc->hdr.rev)
return -1;
#ifdef CONFIG_X86_64
/* Flush global tlb. This is precaution. */
flush_tlb_early();
#endif
- uci->cpu_sig.rev = val[1];
+ uci->cpu_sig.rev = rev;
if (early)
print_ucode(uci);
struct ucode_cpu_info uci;
struct cpio_data cp;
- /*
- * AP loading didn't find any microcode patch, no need to save anything.
- */
- if (!intel_ucode_patch || IS_ERR(intel_ucode_patch))
- return 0;
-
if (!load_builtin_intel_microcode(&cp))
cp = find_microcode_in_initrd(ucode_path, false);
return 0;
}
-
/*
* @res_patch, output: a pointer to the patch we found.
*/
struct microcode_intel *mc;
struct ucode_cpu_info *uci;
struct cpuinfo_x86 *c;
- unsigned int val[2];
static int prev_rev;
+ u32 rev;
/* We should bind the task to the CPU */
if (WARN_ON(raw_smp_processor_id() != cpu))
/* write microcode via MSR 0x79 */
wrmsrl(MSR_IA32_UCODE_WRITE, (unsigned long)mc->bits);
- wrmsrl(MSR_IA32_UCODE_REV, 0);
-
- /* As documented in the SDM: Do a CPUID 1 here */
- cpuid_1();
- /* get the current revision from MSR 0x8B */
- rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
+ rev = intel_get_microcode_revision();
- if (val[1] != mc->hdr.rev) {
+ if (rev != mc->hdr.rev) {
pr_err("CPU%d update to revision 0x%x failed\n",
cpu, mc->hdr.rev);
return -1;
}
- if (val[1] != prev_rev) {
+ if (rev != prev_rev) {
pr_info("updated to revision 0x%x, date = %04x-%02x-%02x\n",
- val[1],
+ rev,
mc->hdr.date & 0xffff,
mc->hdr.date >> 24,
(mc->hdr.date >> 16) & 0xff);
- prev_rev = val[1];
+ prev_rev = rev;
}
c = &cpu_data(cpu);
- uci->cpu_sig.rev = val[1];
- c->microcode = val[1];
+ uci->cpu_sig.rev = rev;
+ c->microcode = rev;
return 0;
}
u8 *ucode_ptr = data, *new_mc = NULL, *mc = NULL;
int new_rev = uci->cpu_sig.rev;
unsigned int leftover = size;
- unsigned int curr_mc_size = 0;
+ unsigned int curr_mc_size = 0, new_mc_size = 0;
unsigned int csig, cpf;
while (leftover) {
vfree(new_mc);
new_rev = mc_header.rev;
new_mc = mc;
+ new_mc_size = mc_size;
mc = NULL; /* trigger new vmalloc */
}
* permanent memory. So it will be loaded early when a CPU is hot added
* or resumes.
*/
- save_mc_for_early(new_mc, curr_mc_size);
+ save_mc_for_early(new_mc, new_mc_size);
pr_debug("CPU%d found a matching microcode update with version 0x%x (current=0x%x)\n",
cpu, new_rev, uci->cpu_sig.rev);
#include <asm/fpu/regset.h>
#include <asm/fpu/signal.h>
#include <asm/fpu/types.h>
+#include <asm/fpu/xstate.h>
#include <asm/traps.h>
#include <linux/hardirq.h>
* it will #GP. Make sure it is replaced after the memset().
*/
if (static_cpu_has(X86_FEATURE_XSAVES))
- state->xsave.header.xcomp_bv = XCOMP_BV_COMPACTED_FORMAT;
+ state->xsave.header.xcomp_bv = XCOMP_BV_COMPACTED_FORMAT |
+ xfeatures_mask;
if (static_cpu_has(X86_FEATURE_FXSR))
fpstate_init_fxstate(&state->fxsave);
} else {
struct hpet_dev *hdev = EVT_TO_HPET_DEV(evt);
+ irq_domain_deactivate_irq(irq_get_irq_data(hdev->irq));
irq_domain_activate_irq(irq_get_irq_data(hdev->irq));
disable_irq(hdev->irq);
irq_set_affinity(hdev->irq, cpumask_of(hdev->cpu));
crystal_khz = 24000; /* 24.0 MHz */
break;
case INTEL_FAM6_SKYLAKE_X:
+ case INTEL_FAM6_ATOM_DENVERTON:
crystal_khz = 25000; /* 25.0 MHz */
break;
case INTEL_FAM6_ATOM_GOLDMONT:
#define FRAME_HEADER_SIZE (sizeof(long) * 2)
+/*
+ * This disables KASAN checking when reading a value from another task's stack,
+ * since the other task could be running on another CPU and could have poisoned
+ * the stack in the meantime.
+ */
+#define READ_ONCE_TASK_STACK(task, x) \
+({ \
+ unsigned long val; \
+ if (task == current) \
+ val = READ_ONCE(x); \
+ else \
+ val = READ_ONCE_NOCHECK(x); \
+ val; \
+})
+
static void unwind_dump(struct unwind_state *state, unsigned long *sp)
{
static bool dumped_before = false;
if (state->regs && user_mode(state->regs))
return 0;
- addr = ftrace_graph_ret_addr(state->task, &state->graph_idx, *addr_p,
+ addr = READ_ONCE_TASK_STACK(state->task, *addr_p);
+ addr = ftrace_graph_ret_addr(state->task, &state->graph_idx, addr,
addr_p);
return __kernel_text_address(addr) ? addr : 0;
if (state->regs)
next_bp = (unsigned long *)state->regs->bp;
else
- next_bp = (unsigned long *)*state->bp;
+ next_bp = (unsigned long *)READ_ONCE_TASK_STACK(state->task,*state->bp);
/* is the next frame pointer an encoded pointer to pt_regs? */
regs = decode_frame_pointer(next_bp);
return true;
bad_address:
+ /*
+ * When unwinding a non-current task, the task might actually be
+ * running on another CPU, in which case it could be modifying its
+ * stack while we're reading it. This is generally not a problem and
+ * can be ignored as long as the caller understands that unwinding
+ * another task will not always succeed.
+ */
+ if (state->task != current)
+ goto the_end;
+
if (state->regs) {
printk_deferred_once(KERN_WARNING
"WARNING: kernel stack regs at %p in %s:%d has bad 'bp' value %p\n",
return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception);
}
+static int segmented_write_std(struct x86_emulate_ctxt *ctxt,
+ struct segmented_address addr,
+ void *data,
+ unsigned int size)
+{
+ int rc;
+ ulong linear;
+
+ rc = linearize(ctxt, addr, size, true, &linear);
+ if (rc != X86EMUL_CONTINUE)
+ return rc;
+ return ctxt->ops->write_std(ctxt, linear, data, size, &ctxt->exception);
+}
+
/*
* Prefetch the remaining bytes of the instruction without crossing page
* boundary if they are not in fetch_cache yet.
&ctxt->exception);
}
-/* Does not support long mode */
static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
u16 selector, int seg, u8 cpl,
enum x86_transfer_type transfer,
rpl = selector & 3;
- /* NULL selector is not valid for TR, CS and SS (except for long mode) */
- if ((seg == VCPU_SREG_CS
- || (seg == VCPU_SREG_SS
- && (ctxt->mode != X86EMUL_MODE_PROT64 || rpl != cpl))
- || seg == VCPU_SREG_TR)
- && null_selector)
- goto exception;
-
/* TR should be in GDT only */
if (seg == VCPU_SREG_TR && (selector & (1 << 2)))
goto exception;
- if (null_selector) /* for NULL selector skip all following checks */
+ /* NULL selector is not valid for TR, CS and (except for long mode) SS */
+ if (null_selector) {
+ if (seg == VCPU_SREG_CS || seg == VCPU_SREG_TR)
+ goto exception;
+
+ if (seg == VCPU_SREG_SS) {
+ if (ctxt->mode != X86EMUL_MODE_PROT64 || rpl != cpl)
+ goto exception;
+
+ /*
+ * ctxt->ops->set_segment expects the CPL to be in
+ * SS.DPL, so fake an expand-up 32-bit data segment.
+ */
+ seg_desc.type = 3;
+ seg_desc.p = 1;
+ seg_desc.s = 1;
+ seg_desc.dpl = cpl;
+ seg_desc.d = 1;
+ seg_desc.g = 1;
+ }
+
+ /* Skip all following checks */
goto load;
+ }
ret = read_segment_descriptor(ctxt, selector, &seg_desc, &desc_addr);
if (ret != X86EMUL_CONTINUE)
u16 selector, int seg)
{
u8 cpl = ctxt->ops->cpl(ctxt);
+
+ /*
+ * None of MOV, POP and LSS can load a NULL selector in CPL=3, but
+ * they can load it at CPL<3 (Intel's manual says only LSS can,
+ * but it's wrong).
+ *
+ * However, the Intel manual says that putting IST=1/DPL=3 in
+ * an interrupt gate will result in SS=3 (the AMD manual instead
+ * says it doesn't), so allow SS=3 in __load_segment_descriptor
+ * and only forbid it here.
+ */
+ if (seg == VCPU_SREG_SS && selector == 3 &&
+ ctxt->mode == X86EMUL_MODE_PROT64)
+ return emulate_exception(ctxt, GP_VECTOR, 0, true);
+
return __load_segment_descriptor(ctxt, selector, seg, cpl,
X86_TRANSFER_NONE, NULL);
}
}
/* Disable writeback. */
ctxt->dst.type = OP_NONE;
- return segmented_write(ctxt, ctxt->dst.addr.mem,
- &desc_ptr, 2 + ctxt->op_bytes);
+ return segmented_write_std(ctxt, ctxt->dst.addr.mem,
+ &desc_ptr, 2 + ctxt->op_bytes);
}
static int em_sgdt(struct x86_emulate_ctxt *ctxt)
else
size = offsetof(struct fxregs_state, xmm_space[0]);
- return segmented_write(ctxt, ctxt->memop.addr.mem, &fx_state, size);
+ return segmented_write_std(ctxt, ctxt->memop.addr.mem, &fx_state, size);
}
static int fxrstor_fixup(struct x86_emulate_ctxt *ctxt,
if (rc != X86EMUL_CONTINUE)
return rc;
- rc = segmented_read(ctxt, ctxt->memop.addr.mem, &fx_state, 512);
+ rc = segmented_read_std(ctxt, ctxt->memop.addr.mem, &fx_state, 512);
if (rc != X86EMUL_CONTINUE)
return rc;
jump_label_rate_limit(&apic_hw_disabled, HZ);
jump_label_rate_limit(&apic_sw_disabled, HZ);
}
+
+void kvm_lapic_exit(void)
+{
+ static_key_deferred_flush(&apic_hw_disabled);
+ static_key_deferred_flush(&apic_sw_disabled);
+}
int kvm_lapic_enable_pv_eoi(struct kvm_vcpu *vcpu, u64 data);
void kvm_lapic_init(void);
+void kvm_lapic_exit(void);
#define VEC_POS(v) ((v) & (32 - 1))
#define REG_POS(v) (((v) >> 5) << 4)
memcpy(dest, xsave, XSAVE_HDR_OFFSET);
/* Set XSTATE_BV */
+ xstate_bv &= vcpu->arch.guest_supported_xcr0 | XFEATURE_MASK_FPSSE;
*(u64 *)(dest + XSAVE_HDR_OFFSET) = xstate_bv;
/*
switch (cap->cap) {
case KVM_CAP_HYPERV_SYNIC:
+ if (!irqchip_in_kernel(vcpu->kvm))
+ return -EINVAL;
return kvm_hv_activate_synic(vcpu);
default:
return -EINVAL;
void kvm_arch_exit(void)
{
+ kvm_lapic_exit();
perf_unregister_guest_info_callbacks(&kvm_guest_cbs);
if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC))
kvm_x86_ops->patch_hypercall(vcpu, instruction);
- return emulator_write_emulated(ctxt, rip, instruction, 3, NULL);
+ return emulator_write_emulated(ctxt, rip, instruction, 3,
+ &ctxt->exception);
}
static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu)
* We were not able to extract an address from the instruction,
* probably because there was something invalid in it.
*/
- if (info->si_addr == (void *)-1) {
+ if (info->si_addr == (void __user *)-1) {
err = -EINVAL;
goto err_out;
}
set_memory_ro((unsigned long)header, header->pages);
prog->bpf_func = (void *)image;
prog->jited = 1;
+ } else {
+ prog = orig_prog;
}
out_addrs:
DMI_MATCH(DMI_BIOS_VERSION, "6JET85WW (1.43 )"),
},
},
+ /* https://bugzilla.kernel.org/show_bug.cgi?id=42606 */
+ {
+ .callback = set_nouse_crs,
+ .ident = "Supermicro X8DTH",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Supermicro"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "X8DTH-i/6/iF/6F"),
+ DMI_MATCH(DMI_BIOS_VERSION, "2.0a"),
+ },
+ },
/* https://bugzilla.kernel.org/show_bug.cgi?id=15362 */
{
return 0;
}
+#define OVERFLOW_ADDR_SHIFT (64 - EFI_PAGE_SHIFT)
+#define OVERFLOW_ADDR_MASK (U64_MAX << OVERFLOW_ADDR_SHIFT)
+#define U64_HIGH_BIT (~(U64_MAX >> 1))
+
+static bool __init efi_memmap_entry_valid(const efi_memory_desc_t *md, int i)
+{
+ u64 end = (md->num_pages << EFI_PAGE_SHIFT) + md->phys_addr - 1;
+ u64 end_hi = 0;
+ char buf[64];
+
+ if (md->num_pages == 0) {
+ end = 0;
+ } else if (md->num_pages > EFI_PAGES_MAX ||
+ EFI_PAGES_MAX - md->num_pages <
+ (md->phys_addr >> EFI_PAGE_SHIFT)) {
+ end_hi = (md->num_pages & OVERFLOW_ADDR_MASK)
+ >> OVERFLOW_ADDR_SHIFT;
+
+ if ((md->phys_addr & U64_HIGH_BIT) && !(end & U64_HIGH_BIT))
+ end_hi += 1;
+ } else {
+ return true;
+ }
+
+ pr_warn_once(FW_BUG "Invalid EFI memory map entries:\n");
+
+ if (end_hi) {
+ pr_warn("mem%02u: %s range=[0x%016llx-0x%llx%016llx] (invalid)\n",
+ i, efi_md_typeattr_format(buf, sizeof(buf), md),
+ md->phys_addr, end_hi, end);
+ } else {
+ pr_warn("mem%02u: %s range=[0x%016llx-0x%016llx] (invalid)\n",
+ i, efi_md_typeattr_format(buf, sizeof(buf), md),
+ md->phys_addr, end);
+ }
+ return false;
+}
+
+static void __init efi_clean_memmap(void)
+{
+ efi_memory_desc_t *out = efi.memmap.map;
+ const efi_memory_desc_t *in = out;
+ const efi_memory_desc_t *end = efi.memmap.map_end;
+ int i, n_removal;
+
+ for (i = n_removal = 0; in < end; i++) {
+ if (efi_memmap_entry_valid(in, i)) {
+ if (out != in)
+ memcpy(out, in, efi.memmap.desc_size);
+ out = (void *)out + efi.memmap.desc_size;
+ } else {
+ n_removal++;
+ }
+ in = (void *)in + efi.memmap.desc_size;
+ }
+
+ if (n_removal > 0) {
+ u64 size = efi.memmap.nr_map - n_removal;
+
+ pr_warn("Removing %d invalid memory map entries.\n", n_removal);
+ efi_memmap_install(efi.memmap.phys_map, size);
+ }
+}
+
void __init efi_print_memmap(void)
{
efi_memory_desc_t *md;
}
}
+ efi_clean_memmap();
+
if (efi_enabled(EFI_DBG))
efi_print_memmap();
}
efi_scratch.use_pgd = true;
+ /*
+ * Certain firmware versions are way too sentimential and still believe
+ * they are exclusive and unquestionable owners of the first physical page,
+ * even though they explicitly mark it as EFI_CONVENTIONAL_MEMORY
+ * (but then write-access it later during SetVirtualAddressMap()).
+ *
+ * Create a 1:1 mapping for this page, to avoid triple faults during early
+ * boot with such firmware. We are free to hand this page to the BIOS,
+ * as trim_bios_range() will reserve the first page and isolate it away
+ * from memory allocators anyway.
+ */
+ if (kernel_map_pages_in_pgd(pgd, 0x0, 0x0, 1, _PAGE_RW)) {
+ pr_err("Failed to create 1:1 mapping for the first page!\n");
+ return 1;
+ }
+
/*
* When making calls to the firmware everything needs to be 1:1
* mapped and addressable with 32-bit pointers. Map the kernel
new_size = efi.memmap.desc_size * num_entries;
- new_phys = memblock_alloc(new_size, 0);
+ new_phys = efi_memmap_alloc(num_entries);
if (!new_phys) {
pr_err("Could not allocate boot services memmap\n");
return;
}
new_size = efi.memmap.desc_size * num_entries;
- new_phys = memblock_alloc(new_size, 0);
+ new_phys = efi_memmap_alloc(num_entries);
if (!new_phys) {
pr_err("Failed to allocate new EFI memmap\n");
return;
obj-$(subst m,y,$(CONFIG_GPIO_INTEL_PMIC)) += platform_pmic_gpio.o
obj-$(subst m,y,$(CONFIG_INTEL_MFLD_THERMAL)) += platform_msic_thermal.o
# SPI Devices
-obj-$(subst m,y,$(CONFIG_SPI_SPIDEV)) += platform_spidev.o
+obj-$(subst m,y,$(CONFIG_SPI_SPIDEV)) += platform_mrfld_spidev.o
# I2C Devices
obj-$(subst m,y,$(CONFIG_SENSORS_EMC1403)) += platform_emc1403.o
obj-$(subst m,y,$(CONFIG_SENSORS_LIS3LV02D)) += platform_lis331.o
--- /dev/null
+/*
+ * spidev platform data initilization file
+ *
+ * (C) Copyright 2014, 2016 Intel Corporation
+ * Authors: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
+ * Dan O'Donovan <dan@emutex.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/sfi.h>
+#include <linux/spi/pxa2xx_spi.h>
+#include <linux/spi/spi.h>
+
+#include <asm/intel-mid.h>
+
+#define MRFLD_SPI_DEFAULT_DMA_BURST 8
+#define MRFLD_SPI_DEFAULT_TIMEOUT 500
+
+/* GPIO pin for spidev chipselect */
+#define MRFLD_SPIDEV_GPIO_CS 111
+
+static struct pxa2xx_spi_chip spidev_spi_chip = {
+ .dma_burst_size = MRFLD_SPI_DEFAULT_DMA_BURST,
+ .timeout = MRFLD_SPI_DEFAULT_TIMEOUT,
+ .gpio_cs = MRFLD_SPIDEV_GPIO_CS,
+};
+
+static void __init *spidev_platform_data(void *info)
+{
+ struct spi_board_info *spi_info = info;
+
+ if (intel_mid_identify_cpu() != INTEL_MID_CPU_CHIP_TANGIER)
+ return ERR_PTR(-ENODEV);
+
+ spi_info->mode = SPI_MODE_0;
+ spi_info->controller_data = &spidev_spi_chip;
+
+ return NULL;
+}
+
+static const struct devs_id spidev_dev_id __initconst = {
+ .name = "spidev",
+ .type = SFI_DEV_TYPE_SPI,
+ .delay = 0,
+ .get_platform_data = &spidev_platform_data,
+};
+
+sfi_device(spidev_dev_id);
+++ /dev/null
-/*
- * spidev platform data initilization file
- *
- * (C) Copyright 2014, 2016 Intel Corporation
- * Authors: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
- * Dan O'Donovan <dan@emutex.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; version 2
- * of the License.
- */
-
-#include <linux/init.h>
-#include <linux/sfi.h>
-#include <linux/spi/pxa2xx_spi.h>
-#include <linux/spi/spi.h>
-
-#include <asm/intel-mid.h>
-
-#define MRFLD_SPI_DEFAULT_DMA_BURST 8
-#define MRFLD_SPI_DEFAULT_TIMEOUT 500
-
-/* GPIO pin for spidev chipselect */
-#define MRFLD_SPIDEV_GPIO_CS 111
-
-static struct pxa2xx_spi_chip spidev_spi_chip = {
- .dma_burst_size = MRFLD_SPI_DEFAULT_DMA_BURST,
- .timeout = MRFLD_SPI_DEFAULT_TIMEOUT,
- .gpio_cs = MRFLD_SPIDEV_GPIO_CS,
-};
-
-static void __init *spidev_platform_data(void *info)
-{
- struct spi_board_info *spi_info = info;
-
- spi_info->mode = SPI_MODE_0;
- spi_info->controller_data = &spidev_spi_chip;
-
- return NULL;
-}
-
-static const struct devs_id spidev_dev_id __initconst = {
- .name = "spidev",
- .type = SFI_DEV_TYPE_SPI,
- .delay = 0,
- .get_platform_data = &spidev_platform_data,
-};
-
-sfi_device(spidev_dev_id);
void cpu_reset(void)
{
-#if XCHAL_HAVE_PTP_MMU
+#if XCHAL_HAVE_PTP_MMU && IS_ENABLED(CONFIG_MMU)
local_irq_disable();
/*
* We have full MMU: all autoload ways, ways 7, 8 and 9 of DTLB must
if ((sector | nr_sects) & bs_mask)
return -EINVAL;
- if (discard) {
- ret = __blkdev_issue_discard(bdev, sector, nr_sects, gfp_mask,
- BLKDEV_DISCARD_ZERO, biop);
- if (ret == 0 || (ret && ret != -EOPNOTSUPP))
- goto out;
- }
-
ret = __blkdev_issue_write_zeroes(bdev, sector, nr_sects, gfp_mask,
biop);
if (ret == 0 || (ret && ret != -EOPNOTSUPP))
struct bio *bio = NULL;
struct blk_plug plug;
+ if (discard) {
+ if (!blkdev_issue_discard(bdev, sector, nr_sects, gfp_mask,
+ BLKDEV_DISCARD_ZERO))
+ return 0;
+ }
+
blk_start_plug(&plug);
ret = __blkdev_issue_zeroout(bdev, sector, nr_sects, gfp_mask,
&bio, discard);
static void blk_mq_process_rq_list(struct blk_mq_hw_ctx *hctx)
{
LIST_HEAD(rq_list);
- LIST_HEAD(driver_list);
if (unlikely(blk_mq_hctx_stopped(hctx)))
return;
static inline sector_t blk_zone_start(struct request_queue *q,
sector_t sector)
{
- sector_t zone_mask = blk_queue_zone_size(q) - 1;
+ sector_t zone_mask = blk_queue_zone_sectors(q) - 1;
return sector & ~zone_mask;
}
return -EINVAL;
/* Check alignment (handle eventual smaller last zone) */
- zone_sectors = blk_queue_zone_size(q);
+ zone_sectors = blk_queue_zone_sectors(q);
if (sector & (zone_sectors - 1))
return -EINVAL;
struct block_device *bdev,
sector_t from, sector_t size)
{
- unsigned int zone_size = bdev_zone_size(bdev);
+ unsigned int zone_sectors = bdev_zone_sectors(bdev);
/*
* If this function is called, then the disk is a zoned block device
* regular block devices (no zone operation) and their zone size will
* be reported as 0. Allow this case.
*/
- if (!zone_size)
+ if (!zone_sectors)
return true;
/*
* use it. Check the zone size too: it should be a power of 2 number
* of sectors.
*/
- if (WARN_ON_ONCE(!is_power_of_2(zone_size))) {
+ if (WARN_ON_ONCE(!is_power_of_2(zone_sectors))) {
u32 rem;
- div_u64_rem(from, zone_size, &rem);
+ div_u64_rem(from, zone_sectors, &rem);
if (rem)
return false;
if ((from + size) < get_capacity(disk)) {
- div_u64_rem(size, zone_size, &rem);
+ div_u64_rem(size, zone_sectors, &rem);
if (rem)
return false;
}
} else {
- if (from & (zone_size - 1))
+ if (from & (zone_sectors - 1))
return false;
if ((from + size) < get_capacity(disk) &&
- (size & (zone_size - 1)))
+ (size & (zone_sectors - 1)))
return false;
}
struct crypto_larval *larval;
int err;
+ alg->cra_flags &= ~CRYPTO_ALG_DEAD;
err = crypto_check_alg(alg);
if (err)
return err;
ACPI_FUNCTION_TRACE(tb_install_and_load_table);
- (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
-
/* Install the table and load it into the namespace */
status = acpi_tb_install_standard_table(address, flags, TRUE,
override, &i);
if (ACPI_FAILURE(status)) {
- goto unlock_and_exit;
+ goto exit;
}
- (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
status = acpi_tb_load_table(i, acpi_gbl_root_node);
- (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
-unlock_and_exit:
+exit:
*table_index = i;
- (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
return_ACPI_STATUS(status);
}
goto release_and_exit;
}
+ /* Acquire the table lock */
+
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+
if (reload) {
/*
* Validate the incoming table signature.
new_table_desc.signature.integer));
status = AE_BAD_SIGNATURE;
- goto release_and_exit;
+ goto unlock_and_exit;
}
/* Check if table is already registered */
/* Table is still loaded, this is an error */
status = AE_ALREADY_EXISTS;
- goto release_and_exit;
+ goto unlock_and_exit;
} else {
/*
* Table was unloaded, allow it to be reloaded.
* indicate the re-installation.
*/
acpi_tb_uninstall_table(&new_table_desc);
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
*table_index = i;
return_ACPI_STATUS(AE_OK);
}
/* Invoke table handler if present */
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
if (acpi_gbl_table_handler) {
(void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_INSTALL,
new_table_desc.pointer,
acpi_gbl_table_handler_context);
}
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+
+unlock_and_exit:
+
+ /* Release the table lock */
+
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
release_and_exit:
if (acpi_sleep_state_supported(i))
sleep_states[i] = 1;
- /*
- * Use suspend-to-idle by default if ACPI_FADT_LOW_POWER_S0 is set and
- * the default suspend mode was not selected from the command line.
- */
- if (acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0 &&
- mem_sleep_default > PM_SUSPEND_MEM)
- mem_sleep_default = PM_SUSPEND_FREEZE;
-
suspend_set_ops(old_suspend_ordering ?
&acpi_suspend_ops_old : &acpi_suspend_ops);
freeze_set_ops(&acpi_freeze_ops);
DMI_MATCH(DMI_PRODUCT_NAME, "Dell System XPS L702X"),
},
},
- {
- /* https://bugzilla.redhat.com/show_bug.cgi?id=1204476 */
- /* https://bugs.launchpad.net/ubuntu/+source/linux-lts-trusty/+bug/1416940 */
- .callback = video_detect_force_native,
- .ident = "HP Pavilion dv6",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
- DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv6 Notebook PC"),
- },
- },
-
{ },
};
if (qc->err_mask & ~AC_ERR_OTHER)
qc->err_mask &= ~AC_ERR_OTHER;
+ } else if (qc->tf.command == ATA_CMD_REQ_SENSE_DATA) {
+ qc->result_tf.command |= ATA_SENSE;
}
/* finish up */
{ "ST380013AS", "3.20", ATA_HORKAGE_MAX_SEC_1024 },
/*
- * Device times out with higher max sects.
+ * These devices time out with higher max sects.
* https://bugzilla.kernel.org/show_bug.cgi?id=121671
*/
- { "LITEON CX1-JB256-HP", NULL, ATA_HORKAGE_MAX_SEC_1024 },
+ { "LITEON CX1-JB*-HP", NULL, ATA_HORKAGE_MAX_SEC_1024 },
/* Devices we expect to fail diagnostics */
host->iomap = NULL;
hpriv->base = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
+ if (!hpriv->base)
+ return -ENOMEM;
+
hpriv->base -= SATAHC0_REG_BASE;
hpriv->clk = clk_get(&pdev->dev, NULL);
tristate "Holtek Ht16K33 LED controller with keyscan"
depends on FB && OF && I2C && INPUT
select FB_SYS_FOPS
- select FB_CFB_FILLRECT
- select FB_CFB_COPYAREA
- select FB_CFB_IMAGEBLIT
+ select FB_SYS_FILLRECT
+ select FB_SYS_COPYAREA
+ select FB_SYS_IMAGEBLIT
select INPUT_MATRIXKMAP
select FB_BACKLIGHT
help
extern struct kset *devices_kset;
extern void devices_kset_move_last(struct device *dev);
-extern struct device_attribute dev_attr_deferred_probe;
-
#if defined(CONFIG_MODULES) && defined(CONFIG_SYSFS)
extern void module_add_driver(struct module *mod, struct device_driver *drv);
extern void module_remove_driver(struct device_driver *drv);
goto err_remove_dev_groups;
}
- error = device_create_file(dev, &dev_attr_deferred_probe);
- if (error)
- goto err_remove_online;
-
return 0;
- err_remove_online:
- device_remove_file(dev, &dev_attr_online);
err_remove_dev_groups:
device_remove_groups(dev, dev->groups);
err_remove_type_groups:
struct class *class = dev->class;
const struct device_type *type = dev->type;
- device_remove_file(dev, &dev_attr_deferred_probe);
device_remove_file(dev, &dev_attr_online);
device_remove_groups(dev, dev->groups);
static LIST_HEAD(deferred_probe_active_list);
static atomic_t deferred_trigger_count = ATOMIC_INIT(0);
-static ssize_t deferred_probe_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- bool value;
-
- mutex_lock(&deferred_probe_mutex);
- value = !list_empty(&dev->p->deferred_probe);
- mutex_unlock(&deferred_probe_mutex);
-
- return sprintf(buf, "%d\n", value);
-}
-DEVICE_ATTR_RO(deferred_probe);
-
/*
* In some cases, like suspend to RAM or hibernation, It might be reasonable
* to prohibit probing of devices as it could be unsafe.
struct firmware_buf *buf = fw_priv->buf;
__fw_load_abort(buf);
-
- /* avoid user action after loading abort */
- fw_priv->buf = NULL;
}
static LIST_HEAD(pending_fw_head);
mutex_lock(&fw_lock);
fw_buf = fw_priv->buf;
- if (!fw_buf)
+ if (fw_state_is_aborted(&fw_buf->fw_st))
goto out;
switch (loading) {
{
struct memory_block *mem = to_memory_block(dev);
unsigned long start_pfn, end_pfn;
+ unsigned long valid_start, valid_end, valid_pages;
unsigned long nr_pages = PAGES_PER_SECTION * sections_per_block;
- struct page *first_page;
struct zone *zone;
int zone_shift = 0;
start_pfn = section_nr_to_pfn(mem->start_section_nr);
end_pfn = start_pfn + nr_pages;
- first_page = pfn_to_page(start_pfn);
/* The block contains more than one zone can not be offlined. */
- if (!test_pages_in_a_zone(start_pfn, end_pfn))
+ if (!test_pages_in_a_zone(start_pfn, end_pfn, &valid_start, &valid_end))
return sprintf(buf, "none\n");
- zone = page_zone(first_page);
+ zone = page_zone(pfn_to_page(valid_start));
+ valid_pages = valid_end - valid_start;
/* MMOP_ONLINE_KEEP */
sprintf(buf, "%s", zone->name);
/* MMOP_ONLINE_KERNEL */
- zone_shift = zone_can_shift(start_pfn, nr_pages, ZONE_NORMAL);
+ zone_can_shift(valid_start, valid_pages, ZONE_NORMAL, &zone_shift);
if (zone_shift) {
strcat(buf, " ");
strcat(buf, (zone + zone_shift)->name);
}
/* MMOP_ONLINE_MOVABLE */
- zone_shift = zone_can_shift(start_pfn, nr_pages, ZONE_MOVABLE);
+ zone_can_shift(valid_start, valid_pages, ZONE_MOVABLE, &zone_shift);
if (zone_shift) {
strcat(buf, " ");
strcat(buf, (zone + zone_shift)->name);
void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc);
void bcma_core_chipcommon_init(struct bcma_drv_cc *cc);
void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable);
+#ifdef CONFIG_BCMA_DRIVER_MIPS
+void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
+#endif /* CONFIG_BCMA_DRIVER_MIPS */
/* driver_chipcommon_b.c */
int bcma_core_chipcommon_b_init(struct bcma_drv_cc_b *ccb);
#include <linux/platform_device.h>
#include <linux/bcma/bcma.h>
-static void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
-
static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset,
u32 mask, u32 value)
{
if (cc->capabilities & BCMA_CC_CAP_PMU)
bcma_pmu_early_init(cc);
- if (IS_BUILTIN(CONFIG_BCM47XX) && bus->hosttype == BCMA_HOSTTYPE_SOC)
- bcma_chipco_serial_init(cc);
-
if (bus->hosttype == BCMA_HOSTTYPE_SOC)
bcma_core_chipcommon_flash_detect(cc);
return res;
}
-static void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
+#ifdef CONFIG_BCMA_DRIVER_MIPS
+void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
{
-#if IS_BUILTIN(CONFIG_BCM47XX)
unsigned int irq;
u32 baud_base;
u32 i;
ports[i].baud_base = baud_base;
ports[i].reg_shift = 0;
}
-#endif /* CONFIG_BCM47XX */
}
+#endif /* CONFIG_BCMA_DRIVER_MIPS */
void bcma_core_mips_early_init(struct bcma_drv_mips *mcore)
{
+ struct bcma_bus *bus = mcore->core->bus;
+
if (mcore->early_setup_done)
return;
+ bcma_chipco_serial_init(&bus->drv_cc);
bcma_core_mips_nvram_init(mcore);
mcore->early_setup_done = true;
static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd, int index)
{
struct request *req = blk_mq_rq_from_pdu(cmd);
- int result, flags;
+ int result;
struct nbd_request request;
unsigned long size = blk_rq_bytes(req);
struct bio *bio;
if (type != NBD_CMD_WRITE)
return 0;
- flags = 0;
bio = req->bio;
while (bio) {
struct bio *next = bio->bi_next;
bio_for_each_segment(bvec, bio, iter) {
bool is_last = !next && bio_iter_last(bvec, iter);
+ int flags = is_last ? 0 : MSG_MORE;
- if (is_last)
- flags = MSG_MORE;
dev_dbg(nbd_to_dev(nbd), "request %p: sending %d bytes data\n",
cmd, bvec.bv_len);
result = sock_send_bvec(nbd, index, &bvec, flags);
return -ENOMEM;
for (i = 0; i < nbds_max; i++) {
+ struct request_queue *q;
struct gendisk *disk = alloc_disk(1 << part_shift);
if (!disk)
goto out;
* every gendisk to have its very own request_queue struct.
* These structs are big so we dynamically allocate them.
*/
- disk->queue = blk_mq_init_queue(&nbd_dev[i].tag_set);
- if (!disk->queue) {
+ q = blk_mq_init_queue(&nbd_dev[i].tag_set);
+ if (IS_ERR(q)) {
blk_mq_free_tag_set(&nbd_dev[i].tag_set);
put_disk(disk);
goto out;
}
+ disk->queue = q;
/*
* Tell the block layer that we are not a rotational device
struct virtio_blk_outhdr out_hdr;
struct virtio_scsi_inhdr in_hdr;
u8 status;
+ u8 sense[SCSI_SENSE_BUFFERSIZE];
struct scatterlist sg[];
};
}
if (type == cpu_to_virtio32(vq->vdev, VIRTIO_BLK_T_SCSI_CMD)) {
- sg_init_one(&sense, vbr->req->sense, SCSI_SENSE_BUFFERSIZE);
+ memcpy(vbr->sense, vbr->req->sense, SCSI_SENSE_BUFFERSIZE);
+ sg_init_one(&sense, vbr->sense, SCSI_SENSE_BUFFERSIZE);
sgs[num_out + num_in++] = &sense;
sg_init_one(&inhdr, &vbr->in_hdr, sizeof(vbr->in_hdr));
sgs[num_out + num_in++] = &inhdr;
if (err)
goto out_put_disk;
- q = vblk->disk->queue = blk_mq_init_queue(&vblk->tag_set);
+ q = blk_mq_init_queue(&vblk->tag_set);
if (IS_ERR(q)) {
err = -ENOMEM;
goto out_free_tags;
}
+ vblk->disk->queue = q;
q->queuedata = vblk;
/* Number of pages per ring buffer. */
unsigned int nr_ring_pages;
struct request_queue *rq;
- unsigned int feature_flush;
- unsigned int feature_fua;
+ unsigned int feature_flush:1;
+ unsigned int feature_fua:1;
unsigned int feature_discard:1;
unsigned int feature_secdiscard:1;
+ unsigned int feature_persistent:1;
unsigned int discard_granularity;
unsigned int discard_alignment;
- unsigned int feature_persistent:1;
/* Number of 4KB segments handled */
unsigned int max_indirect_segments;
int is_ready;
}
else
grants = info->max_indirect_segments;
- psegs = grants / GRANTS_PER_PSEG;
+ psegs = DIV_ROUND_UP(grants, GRANTS_PER_PSEG);
err = fill_grant_buffer(rinfo,
(grants + INDIRECT_GREFS(grants)) * BLK_RING_SIZE(info));
blkfront_setup_discard(info);
info->feature_persistent =
- xenbus_read_unsigned(info->xbdev->otherend,
- "feature-persistent", 0);
+ !!xenbus_read_unsigned(info->xbdev->otherend,
+ "feature-persistent", 0);
indirect_segments = xenbus_read_unsigned(info->xbdev->otherend,
"feature-max-indirect-segments", 0);
- info->max_indirect_segments = min(indirect_segments,
- xen_blkif_max_segments);
+ if (indirect_segments > xen_blkif_max_segments)
+ indirect_segments = xen_blkif_max_segments;
+ if (indirect_segments <= BLKIF_MAX_SEGMENTS_PER_REQUEST)
+ indirect_segments = 0;
+ info->max_indirect_segments = indirect_segments;
}
/*
if (!xen_domain())
return -ENODEV;
+ if (xen_blkif_max_segments < BLKIF_MAX_SEGMENTS_PER_REQUEST)
+ xen_blkif_max_segments = BLKIF_MAX_SEGMENTS_PER_REQUEST;
+
if (xen_blkif_max_ring_order > XENBUS_MAX_RING_GRANT_ORDER) {
pr_info("Invalid max_ring_order (%d), will use default max: %d.\n",
xen_blkif_max_ring_order, XENBUS_MAX_RING_GRANT_ORDER);
#include <linux/genhd.h>
#include <linux/highmem.h>
#include <linux/slab.h>
+#include <linux/backing-dev.h>
#include <linux/string.h>
#include <linux/vmalloc.h>
#include <linux/err.h>
return bvec->bv_len != PAGE_SIZE;
}
+static void zram_revalidate_disk(struct zram *zram)
+{
+ revalidate_disk(zram->disk);
+ /* revalidate_disk reset the BDI_CAP_STABLE_WRITES so set again */
+ zram->disk->queue->backing_dev_info.capabilities |=
+ BDI_CAP_STABLE_WRITES;
+}
+
/*
* Check if request is within bounds and aligned on zram logical blocks.
*/
zram->comp = comp;
zram->disksize = disksize;
set_capacity(zram->disk, zram->disksize >> SECTOR_SHIFT);
+ zram_revalidate_disk(zram);
up_write(&zram->init_lock);
- /*
- * Revalidate disk out of the init_lock to avoid lockdep splat.
- * It's okay because disk's capacity is protected by init_lock
- * so that revalidate_disk always sees up-to-date capacity.
- */
- revalidate_disk(zram->disk);
-
return len;
out_destroy_comp:
/* Make sure all the pending I/O are finished */
fsync_bdev(bdev);
zram_reset_device(zram);
- revalidate_disk(zram->disk);
+ zram_revalidate_disk(zram);
bdput(bdev);
mutex_lock(&bdev->bd_mutex);
char *kbuf; /* k-addr because vread() takes vmlist_lock rwlock */
int err = 0;
- if (!pfn_valid(PFN_DOWN(p)))
- return -EIO;
-
read = 0;
if (p < (unsigned long) high_memory) {
low_count = count;
* by the kernel or data corruption may occur
*/
kbuf = xlate_dev_kmem_ptr((void *)p);
+ if (!virt_addr_valid(kbuf))
+ return -ENXIO;
if (copy_to_user(buf, kbuf, sz))
return -EFAULT;
* corruption may occur.
*/
ptr = xlate_dev_kmem_ptr((void *)p);
+ if (!virt_addr_valid(ptr))
+ return -ENXIO;
copied = copy_from_user(ptr, buf, sz);
if (copied) {
char *kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */
int err = 0;
- if (!pfn_valid(PFN_DOWN(p)))
- return -EIO;
-
if (p < (unsigned long) high_memory) {
unsigned long to_write = min_t(unsigned long, count,
(unsigned long)high_memory - p);
struct pardevice *pdev = NULL;
char *name;
struct pardev_cb ppdev_cb;
+ int rc = 0;
name = kasprintf(GFP_KERNEL, CHRDEV "%x", minor);
if (name == NULL)
port = parport_find_number(minor);
if (!port) {
pr_warn("%s: no associated port!\n", name);
- kfree(name);
- return -ENXIO;
+ rc = -ENXIO;
+ goto err;
}
memset(&ppdev_cb, 0, sizeof(ppdev_cb));
ppdev_cb.private = pp;
pdev = parport_register_dev_model(port, name, &ppdev_cb, minor);
parport_put_port(port);
- kfree(name);
if (!pdev) {
pr_warn("%s: failed to register device!\n", name);
- return -ENXIO;
+ rc = -ENXIO;
+ goto err;
}
pp->pdev = pdev;
dev_dbg(&pdev->dev, "registered pardevice\n");
- return 0;
+err:
+ kfree(name);
+ return rc;
}
static enum ieee1284_phase init_phase(int mode)
{
struct ports_device *portdev;
- portdev = container_of(work, struct ports_device, control_work);
+ portdev = container_of(work, struct ports_device, config_work);
if (!use_multiport(portdev)) {
struct virtio_device *vdev;
struct port *port;
GATE(CLK_ACLK550_CAM, "aclk550_cam", "mout_user_aclk550_cam",
GATE_BUS_TOP, 24, 0, 0),
GATE(CLK_ACLK432_SCALER, "aclk432_scaler", "mout_user_aclk432_scaler",
- GATE_BUS_TOP, 27, 0, 0),
+ GATE_BUS_TOP, 27, CLK_IS_CRITICAL, 0),
};
static const struct samsung_mux_clock exynos5420_mux_clks[] __initconst = {
GATE(CLK_SMMU_G2D, "smmu_g2d", "aclk333_g2d", GATE_IP_G2D, 7, 0, 0),
GATE(0, "aclk200_fsys", "mout_user_aclk200_fsys",
- GATE_BUS_FSYS0, 9, CLK_IGNORE_UNUSED, 0),
+ GATE_BUS_FSYS0, 9, CLK_IS_CRITICAL, 0),
GATE(0, "aclk200_fsys2", "mout_user_aclk200_fsys2",
GATE_BUS_FSYS0, 10, CLK_IGNORE_UNUSED, 0),
GATE(0, "aclk333_g2d", "mout_user_aclk333_g2d",
GATE_BUS_TOP, 0, CLK_IGNORE_UNUSED, 0),
GATE(0, "aclk266_g2d", "mout_user_aclk266_g2d",
- GATE_BUS_TOP, 1, CLK_IGNORE_UNUSED, 0),
+ GATE_BUS_TOP, 1, CLK_IS_CRITICAL, 0),
GATE(0, "aclk300_jpeg", "mout_user_aclk300_jpeg",
GATE_BUS_TOP, 4, CLK_IGNORE_UNUSED, 0),
GATE(0, "aclk333_432_isp0", "mout_user_aclk333_432_isp0",
GATE_BUS_TOP, 5, 0, 0),
GATE(0, "aclk300_gscl", "mout_user_aclk300_gscl",
- GATE_BUS_TOP, 6, CLK_IGNORE_UNUSED, 0),
+ GATE_BUS_TOP, 6, CLK_IS_CRITICAL, 0),
GATE(0, "aclk333_432_gscl", "mout_user_aclk333_432_gscl",
GATE_BUS_TOP, 7, CLK_IGNORE_UNUSED, 0),
GATE(0, "aclk333_432_isp", "mout_user_aclk333_432_isp",
GATE(0, "aclk166", "mout_user_aclk166",
GATE_BUS_TOP, 14, CLK_IGNORE_UNUSED, 0),
GATE(CLK_ACLK333, "aclk333", "mout_user_aclk333",
- GATE_BUS_TOP, 15, CLK_IGNORE_UNUSED, 0),
+ GATE_BUS_TOP, 15, CLK_IS_CRITICAL, 0),
GATE(0, "aclk400_isp", "mout_user_aclk400_isp",
GATE_BUS_TOP, 16, 0, 0),
GATE(0, "aclk400_mscl", "mout_user_aclk400_mscl",
GATE_BUS_TOP, 17, 0, 0),
GATE(0, "aclk200_disp1", "mout_user_aclk200_disp1",
- GATE_BUS_TOP, 18, 0, 0),
+ GATE_BUS_TOP, 18, CLK_IS_CRITICAL, 0),
GATE(CLK_SCLK_MPHY_IXTAL24, "sclk_mphy_ixtal24", "mphy_refclk_ixtal24",
GATE_BUS_TOP, 28, 0, 0),
GATE(CLK_SCLK_HSIC_12M, "sclk_hsic_12m", "ff_hsic_12m",
GATE_BUS_TOP, 29, 0, 0),
GATE(0, "aclk300_disp1", "mout_user_aclk300_disp1",
- SRC_MASK_TOP2, 24, 0, 0),
+ SRC_MASK_TOP2, 24, CLK_IS_CRITICAL, 0),
GATE(CLK_MAU_EPLL, "mau_epll", "mout_mau_epll_clk",
SRC_MASK_TOP7, 20, 0, 0),
if (mct_int_type == MCT_INT_SPI) {
if (evt->irq != -1)
disable_irq_nosync(evt->irq);
+ exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET);
} else {
disable_percpu_irq(mct_irqs[MCT_L0_IRQ]);
}
limits = &performance_limits;
perf_limits = limits;
}
- if (policy->max >= policy->cpuinfo.max_freq) {
+ if (policy->max >= policy->cpuinfo.max_freq &&
+ !limits->no_turbo) {
pr_debug("set performance\n");
intel_pstate_set_performance_limits(perf_limits);
goto out;
policy->policy != CPUFREQ_POLICY_PERFORMANCE)
return -EINVAL;
+ /* When per-CPU limits are used, sysfs limits are not used */
+ if (!per_cpu_limits) {
+ unsigned int max_freq, min_freq;
+
+ max_freq = policy->cpuinfo.max_freq *
+ limits->max_sysfs_pct / 100;
+ min_freq = policy->cpuinfo.max_freq *
+ limits->min_sysfs_pct / 100;
+ cpufreq_verify_within_limits(policy, min_freq, max_freq);
+ }
+
return 0;
}
/* context for suspend/resume */
unsigned int dma_tdfdq;
+
+ bool is_suspended;
};
#define FIST_COMPLETION_QUEUE 93
BUG_ON(desc_num >= ALLOC_DECS_NUM);
c = cdd->chan_busy[desc_num];
cdd->chan_busy[desc_num] = NULL;
+
+ /* Usecount for chan_busy[], paired with push_desc_queue() */
+ pm_runtime_put(cdd->ddev.dev);
+
return c;
}
while (val) {
u32 desc, len;
- int error;
- error = pm_runtime_get(cdd->ddev.dev);
- if (error < 0)
- dev_err(cdd->ddev.dev, "%s pm runtime get: %i\n",
- __func__, error);
+ /*
+ * This should never trigger, see the comments in
+ * push_desc_queue()
+ */
+ WARN_ON(cdd->is_suspended);
q_num = __fls(val);
val &= ~(1 << q_num);
c->residue = pd_trans_len(c->desc->pd6) - len;
dma_cookie_complete(&c->txd);
dmaengine_desc_get_callback_invoke(&c->txd, NULL);
-
- pm_runtime_mark_last_busy(cdd->ddev.dev);
- pm_runtime_put_autosuspend(cdd->ddev.dev);
}
}
return IRQ_HANDLED;
*/
__iowmb();
+ /*
+ * DMA transfers can take at least 200ms to complete with USB mass
+ * storage connected. To prevent autosuspend timeouts, we must use
+ * pm_runtime_get/put() when chan_busy[] is modified. This will get
+ * cleared in desc_to_chan() or cppi41_stop_chan() depending on the
+ * outcome of the transfer.
+ */
+ pm_runtime_get(cdd->ddev.dev);
+
desc_phys = lower_32_bits(c->desc_phys);
desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc);
WARN_ON(cdd->chan_busy[desc_num]);
cppi_writel(reg, cdd->qmgr_mem + QMGR_QUEUE_D(c->q_num));
}
-static void pending_desc(struct cppi41_channel *c)
+/*
+ * Caller must hold cdd->lock to prevent push_desc_queue()
+ * getting called out of order. We have both cppi41_dma_issue_pending()
+ * and cppi41_runtime_resume() call this function.
+ */
+static void cppi41_run_queue(struct cppi41_dd *cdd)
{
- struct cppi41_dd *cdd = c->cdd;
- unsigned long flags;
+ struct cppi41_channel *c, *_c;
- spin_lock_irqsave(&cdd->lock, flags);
- list_add_tail(&c->node, &cdd->pending);
- spin_unlock_irqrestore(&cdd->lock, flags);
+ list_for_each_entry_safe(c, _c, &cdd->pending, node) {
+ push_desc_queue(c);
+ list_del(&c->node);
+ }
}
static void cppi41_dma_issue_pending(struct dma_chan *chan)
{
struct cppi41_channel *c = to_cpp41_chan(chan);
struct cppi41_dd *cdd = c->cdd;
+ unsigned long flags;
int error;
error = pm_runtime_get(cdd->ddev.dev);
return;
}
- if (likely(pm_runtime_active(cdd->ddev.dev)))
- push_desc_queue(c);
- else
- pending_desc(c);
+ spin_lock_irqsave(&cdd->lock, flags);
+ list_add_tail(&c->node, &cdd->pending);
+ if (!cdd->is_suspended)
+ cppi41_run_queue(cdd);
+ spin_unlock_irqrestore(&cdd->lock, flags);
pm_runtime_mark_last_busy(cdd->ddev.dev);
pm_runtime_put_autosuspend(cdd->ddev.dev);
WARN_ON(!cdd->chan_busy[desc_num]);
cdd->chan_busy[desc_num] = NULL;
+ /* Usecount for chan_busy[], paired with push_desc_queue() */
+ pm_runtime_put(cdd->ddev.dev);
+
return 0;
}
static int __maybe_unused cppi41_runtime_suspend(struct device *dev)
{
struct cppi41_dd *cdd = dev_get_drvdata(dev);
+ unsigned long flags;
+ spin_lock_irqsave(&cdd->lock, flags);
+ cdd->is_suspended = true;
WARN_ON(!list_empty(&cdd->pending));
+ spin_unlock_irqrestore(&cdd->lock, flags);
return 0;
}
static int __maybe_unused cppi41_runtime_resume(struct device *dev)
{
struct cppi41_dd *cdd = dev_get_drvdata(dev);
- struct cppi41_channel *c, *_c;
unsigned long flags;
spin_lock_irqsave(&cdd->lock, flags);
- list_for_each_entry_safe(c, _c, &cdd->pending, node) {
- push_desc_queue(c);
- list_del(&c->node);
- }
+ cdd->is_suspended = false;
+ cppi41_run_queue(cdd);
spin_unlock_irqrestore(&cdd->lock, flags);
return 0;
select DW_DMAC_CORE
help
Support the Synopsys DesignWare AHB DMA controller on the
- platfroms that enumerate it as a PCI device. For example,
+ platforms that enumerate it as a PCI device. For example,
Intel Medfield has integrated this GPDMA controller.
#define PCI_DEVICE_ID_INTEL_IOAT_BDX8 0x6f2e
#define PCI_DEVICE_ID_INTEL_IOAT_BDX9 0x6f2f
+#define PCI_DEVICE_ID_INTEL_IOAT_SKX 0x2021
+
#define IOAT_VER_1_2 0x12 /* Version 1.2 */
#define IOAT_VER_2_0 0x20 /* Version 2.0 */
#define IOAT_VER_3_0 0x30 /* Version 3.0 */
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BDX8) },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BDX9) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SKX) },
+
/* I/OAT v3.3 platforms */
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BWD0) },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BWD1) },
}
}
+static inline bool is_skx_ioat(struct pci_dev *pdev)
+{
+ return (pdev->device == PCI_DEVICE_ID_INTEL_IOAT_SKX) ? true : false;
+}
+
static bool is_xeon_cb32(struct pci_dev *pdev)
{
return is_jf_ioat(pdev) || is_snb_ioat(pdev) || is_ivb_ioat(pdev) ||
- is_hsw_ioat(pdev) || is_bdx_ioat(pdev);
+ is_hsw_ioat(pdev) || is_bdx_ioat(pdev) || is_skx_ioat(pdev);
}
bool is_bwd_ioat(struct pci_dev *pdev)
/* doing 2 32bit writes to mmio since 1 64b write doesn't work */
ioat_chan->completion =
dma_pool_zalloc(ioat_chan->ioat_dma->completion_pool,
- GFP_KERNEL, &ioat_chan->completion_dma);
+ GFP_NOWAIT, &ioat_chan->completion_dma);
if (!ioat_chan->completion)
return -ENOMEM;
ioat_chan->reg_base + IOAT_CHANCMP_OFFSET_HIGH);
order = IOAT_MAX_ORDER;
- ring = ioat_alloc_ring(c, order, GFP_KERNEL);
+ ring = ioat_alloc_ring(c, order, GFP_NOWAIT);
if (!ring)
return -ENOMEM;
device->version = readb(device->reg_base + IOAT_VER_OFFSET);
if (device->version >= IOAT_VER_3_0) {
+ if (is_skx_ioat(pdev))
+ device->version = IOAT_VER_3_2;
err = ioat3_dma_probe(device, ioat_dca_enabled);
if (device->version >= IOAT_VER_3_3)
d->ccr |= CCR_DST_AMODE_POSTINC;
if (port_window) {
d->ccr |= CCR_SRC_AMODE_DBLIDX;
- d->ei = 1;
- /*
- * One frame covers the port_window and by configure
- * the source frame index to be -1 * (port_window - 1)
- * we instruct the sDMA that after a frame is processed
- * it should move back to the start of the window.
- */
- d->fi = -(port_window_bytes - 1);
if (port_window_bytes >= 64)
- d->csdp = CSDP_SRC_BURST_64 | CSDP_SRC_PACKED;
+ d->csdp |= CSDP_SRC_BURST_64;
else if (port_window_bytes >= 32)
- d->csdp = CSDP_SRC_BURST_32 | CSDP_SRC_PACKED;
+ d->csdp |= CSDP_SRC_BURST_32;
else if (port_window_bytes >= 16)
- d->csdp = CSDP_SRC_BURST_16 | CSDP_SRC_PACKED;
+ d->csdp |= CSDP_SRC_BURST_16;
+
} else {
d->ccr |= CCR_SRC_AMODE_CONSTANT;
}
d->ccr |= CCR_SRC_AMODE_POSTINC;
if (port_window) {
d->ccr |= CCR_DST_AMODE_DBLIDX;
+ d->ei = 1;
+ /*
+ * One frame covers the port_window and by configure
+ * the source frame index to be -1 * (port_window - 1)
+ * we instruct the sDMA that after a frame is processed
+ * it should move back to the start of the window.
+ */
+ d->fi = -(port_window_bytes - 1);
if (port_window_bytes >= 64)
- d->csdp = CSDP_DST_BURST_64 | CSDP_DST_PACKED;
+ d->csdp |= CSDP_DST_BURST_64;
else if (port_window_bytes >= 32)
- d->csdp = CSDP_DST_BURST_32 | CSDP_DST_PACKED;
+ d->csdp |= CSDP_DST_BURST_32;
else if (port_window_bytes >= 16)
- d->csdp = CSDP_DST_BURST_16 | CSDP_DST_PACKED;
+ d->csdp |= CSDP_DST_BURST_16;
} else {
d->ccr |= CCR_DST_AMODE_CONSTANT;
}
osg->addr = sg_dma_address(sgent);
osg->en = en;
osg->fn = sg_dma_len(sgent) / frame_bytes;
- if (port_window && dir == DMA_MEM_TO_DEV) {
+ if (port_window && dir == DMA_DEV_TO_MEM) {
osg->ei = 1;
/*
* One frame covers the port_window and by configure
struct omap_dmadev *od;
struct resource *res;
int rc, i, irq;
+ u32 lch_count;
od = devm_kzalloc(&pdev->dev, sizeof(*od), GFP_KERNEL);
if (!od)
spin_lock_init(&od->lock);
spin_lock_init(&od->irq_lock);
- if (!pdev->dev.of_node) {
- od->dma_requests = od->plat->dma_attr->lch_count;
- if (unlikely(!od->dma_requests))
- od->dma_requests = OMAP_SDMA_REQUESTS;
- } else if (of_property_read_u32(pdev->dev.of_node, "dma-requests",
- &od->dma_requests)) {
+ /* Number of DMA requests */
+ od->dma_requests = OMAP_SDMA_REQUESTS;
+ if (pdev->dev.of_node && of_property_read_u32(pdev->dev.of_node,
+ "dma-requests",
+ &od->dma_requests)) {
dev_info(&pdev->dev,
"Missing dma-requests property, using %u.\n",
OMAP_SDMA_REQUESTS);
- od->dma_requests = OMAP_SDMA_REQUESTS;
}
- od->lch_map = devm_kcalloc(&pdev->dev, od->dma_requests,
- sizeof(*od->lch_map), GFP_KERNEL);
+ /* Number of available logical channels */
+ if (!pdev->dev.of_node) {
+ lch_count = od->plat->dma_attr->lch_count;
+ if (unlikely(!lch_count))
+ lch_count = OMAP_SDMA_CHANNELS;
+ } else if (of_property_read_u32(pdev->dev.of_node, "dma-channels",
+ &lch_count)) {
+ dev_info(&pdev->dev,
+ "Missing dma-channels property, using %u.\n",
+ OMAP_SDMA_CHANNELS);
+ lch_count = OMAP_SDMA_CHANNELS;
+ }
+
+ od->lch_map = devm_kcalloc(&pdev->dev, lch_count, sizeof(*od->lch_map),
+ GFP_KERNEL);
if (!od->lch_map)
return -ENOMEM;
/* for cyclic capability */
bool cyclic;
+
+ /* for runtime pm tracking */
+ bool active;
};
struct pl330_dmac {
static struct pl330_thread *pl330_request_channel(struct pl330_dmac *pl330)
{
struct pl330_thread *thrd = NULL;
- unsigned long flags;
int chans, i;
if (pl330->state == DYING)
chans = pl330->pcfg.num_chan;
- spin_lock_irqsave(&pl330->lock, flags);
-
for (i = 0; i < chans; i++) {
thrd = &pl330->channels[i];
if ((thrd->free) && (!_manager_ns(thrd) ||
thrd = NULL;
}
- spin_unlock_irqrestore(&pl330->lock, flags);
-
return thrd;
}
static void pl330_release_channel(struct pl330_thread *thrd)
{
struct pl330_dmac *pl330;
- unsigned long flags;
if (!thrd || thrd->free)
return;
pl330 = thrd->dmac;
- spin_lock_irqsave(&pl330->lock, flags);
_free_event(thrd, thrd->ev);
thrd->free = true;
- spin_unlock_irqrestore(&pl330->lock, flags);
}
/* Initialize the structure for PL330 configuration, that can be used
_stop(pch->thread);
spin_unlock(&pch->thread->dmac->lock);
power_down = true;
+ pch->active = false;
} else {
/* Make sure the PL330 Channel thread is active */
spin_lock(&pch->thread->dmac->lock);
desc->status = PREP;
list_move_tail(&desc->node, &pch->work_list);
if (power_down) {
+ pch->active = true;
spin_lock(&pch->thread->dmac->lock);
_start(pch->thread);
spin_unlock(&pch->thread->dmac->lock);
struct pl330_dmac *pl330 = pch->dmac;
unsigned long flags;
- spin_lock_irqsave(&pch->lock, flags);
+ spin_lock_irqsave(&pl330->lock, flags);
dma_cookie_init(chan);
pch->cyclic = false;
pch->thread = pl330_request_channel(pl330);
if (!pch->thread) {
- spin_unlock_irqrestore(&pch->lock, flags);
+ spin_unlock_irqrestore(&pl330->lock, flags);
return -ENOMEM;
}
tasklet_init(&pch->task, pl330_tasklet, (unsigned long) pch);
- spin_unlock_irqrestore(&pch->lock, flags);
+ spin_unlock_irqrestore(&pl330->lock, flags);
return 1;
}
unsigned long flags;
struct pl330_dmac *pl330 = pch->dmac;
LIST_HEAD(list);
+ bool power_down = false;
pm_runtime_get_sync(pl330->ddma.dev);
spin_lock_irqsave(&pch->lock, flags);
pch->thread->req[0].desc = NULL;
pch->thread->req[1].desc = NULL;
pch->thread->req_running = -1;
+ power_down = pch->active;
+ pch->active = false;
/* Mark all desc done */
list_for_each_entry(desc, &pch->submitted_list, node) {
list_splice_tail_init(&pch->completed_list, &pl330->desc_pool);
spin_unlock_irqrestore(&pch->lock, flags);
pm_runtime_mark_last_busy(pl330->ddma.dev);
+ if (power_down)
+ pm_runtime_put_autosuspend(pl330->ddma.dev);
pm_runtime_put_autosuspend(pl330->ddma.dev);
return 0;
static void pl330_free_chan_resources(struct dma_chan *chan)
{
struct dma_pl330_chan *pch = to_pchan(chan);
+ struct pl330_dmac *pl330 = pch->dmac;
unsigned long flags;
tasklet_kill(&pch->task);
pm_runtime_get_sync(pch->dmac->ddma.dev);
- spin_lock_irqsave(&pch->lock, flags);
+ spin_lock_irqsave(&pl330->lock, flags);
pl330_release_channel(pch->thread);
pch->thread = NULL;
if (pch->cyclic)
list_splice_tail_init(&pch->work_list, &pch->dmac->desc_pool);
- spin_unlock_irqrestore(&pch->lock, flags);
+ spin_unlock_irqrestore(&pl330->lock, flags);
pm_runtime_mark_last_busy(pch->dmac->ddma.dev);
pm_runtime_put_autosuspend(pch->dmac->ddma.dev);
}
* updated on work_list emptiness status.
*/
WARN_ON(list_empty(&pch->submitted_list));
+ pch->active = true;
pm_runtime_get_sync(pch->dmac->ddma.dev);
}
list_splice_tail_init(&pch->submitted_list, &pch->work_list);
{
struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan);
struct rcar_dmac *dmac = to_rcar_dmac(chan->device);
+ struct rcar_dmac_chan_map *map = &rchan->map;
struct rcar_dmac_desc_page *page, *_page;
struct rcar_dmac_desc *desc;
LIST_HEAD(list);
free_page((unsigned long)page);
}
+ /* Remove slave mapping if present. */
+ if (map->slave.xfer_size) {
+ dma_unmap_resource(chan->device->dev, map->addr,
+ map->slave.xfer_size, map->dir, 0);
+ map->slave.xfer_size = 0;
+ }
+
pm_runtime_put(chan->device->dev);
}
struct virt_dma_desc *vdesc;
enum dma_status status;
unsigned long flags;
- u32 residue;
+ u32 residue = 0;
status = dma_cookie_status(c, cookie, state);
if ((status == DMA_COMPLETE) || (!state))
spin_lock_irqsave(&chan->vchan.lock, flags);
vdesc = vchan_find_desc(&chan->vchan, cookie);
- if (cookie == chan->desc->vdesc.tx.cookie) {
+ if (chan->desc && cookie == chan->desc->vdesc.tx.cookie)
residue = stm32_dma_desc_residue(chan, chan->desc,
chan->next_sg);
- } else if (vdesc) {
+ else if (vdesc)
residue = stm32_dma_desc_residue(chan,
to_stm32_dma_desc(vdesc), 0);
- } else {
- residue = 0;
- }
-
dma_set_residue(state, residue);
spin_unlock_irqrestore(&chan->vchan.lock, flags);
struct stm32_dma_chan *chan;
struct dma_chan *c;
- if (dma_spec->args_count < 3)
+ if (dma_spec->args_count < 4)
return NULL;
cfg.channel_id = dma_spec->args[0];
cfg.request_line = dma_spec->args[1];
cfg.stream_config = dma_spec->args[2];
- cfg.threshold = 0;
+ cfg.threshold = dma_spec->args[3];
if ((cfg.channel_id >= STM32_DMA_MAX_CHANNELS) || (cfg.request_line >=
STM32_DMA_MAX_REQUEST_ID))
return NULL;
- if (dma_spec->args_count > 3)
- cfg.threshold = dma_spec->args[3];
-
chan = &dmadev->chan[cfg.channel_id];
c = dma_get_slave_channel(&chan->vchan.chan);
match = of_match_node(ti_am335x_master_match, dma_node);
if (!match) {
dev_err(&pdev->dev, "DMA master is not supported\n");
+ of_node_put(dma_node);
return -EINVAL;
}
match = of_match_node(ti_dra7_master_match, dma_node);
if (!match) {
dev_err(&pdev->dev, "DMA master is not supported\n");
+ of_node_put(dma_node);
return -EINVAL;
}
dev_err(&edev->dev, "out of memory in extcon_set_state\n");
kobject_uevent(&edev->dev.kobj, KOBJ_CHANGE);
- return 0;
+ return -ENOMEM;
}
length = name_show(&edev->dev, NULL, prop_buf);
}
/* allocate memory for new EFI memmap */
- new_memmap_phy = memblock_alloc(efi.memmap.desc_size * new_nr_map,
- PAGE_SIZE);
+ new_memmap_phy = efi_memmap_alloc(new_nr_map);
if (!new_memmap_phy)
return;
unsigned long get_dram_base(efi_system_table_t *sys_table_arg);
-efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,
- unsigned long orig_fdt_size,
- void *fdt, int new_fdt_size, char *cmdline_ptr,
- u64 initrd_addr, u64 initrd_size,
- efi_memory_desc_t *memory_map,
- unsigned long map_size, unsigned long desc_size,
- u32 desc_ver);
-
efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
void *handle,
unsigned long *new_fdt_addr,
#include "efistub.h"
-efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,
- unsigned long orig_fdt_size,
- void *fdt, int new_fdt_size, char *cmdline_ptr,
- u64 initrd_addr, u64 initrd_size,
- efi_memory_desc_t *memory_map,
- unsigned long map_size, unsigned long desc_size,
- u32 desc_ver)
+static efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,
+ unsigned long orig_fdt_size,
+ void *fdt, int new_fdt_size, char *cmdline_ptr,
+ u64 initrd_addr, u64 initrd_size)
{
int node, num_rsv;
int status;
if (status)
goto fdt_set_fail;
- fdt_val64 = cpu_to_fdt64((u64)(unsigned long)memory_map);
+ fdt_val64 = U64_MAX; /* placeholder */
status = fdt_setprop(fdt, node, "linux,uefi-mmap-start",
&fdt_val64, sizeof(fdt_val64));
if (status)
goto fdt_set_fail;
- fdt_val32 = cpu_to_fdt32(map_size);
+ fdt_val32 = U32_MAX; /* placeholder */
status = fdt_setprop(fdt, node, "linux,uefi-mmap-size",
&fdt_val32, sizeof(fdt_val32));
if (status)
goto fdt_set_fail;
- fdt_val32 = cpu_to_fdt32(desc_size);
status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-size",
&fdt_val32, sizeof(fdt_val32));
if (status)
goto fdt_set_fail;
- fdt_val32 = cpu_to_fdt32(desc_ver);
status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-ver",
&fdt_val32, sizeof(fdt_val32));
if (status)
return EFI_LOAD_ERROR;
}
+static efi_status_t update_fdt_memmap(void *fdt, struct efi_boot_memmap *map)
+{
+ int node = fdt_path_offset(fdt, "/chosen");
+ u64 fdt_val64;
+ u32 fdt_val32;
+ int err;
+
+ if (node < 0)
+ return EFI_LOAD_ERROR;
+
+ fdt_val64 = cpu_to_fdt64((unsigned long)*map->map);
+ err = fdt_setprop_inplace(fdt, node, "linux,uefi-mmap-start",
+ &fdt_val64, sizeof(fdt_val64));
+ if (err)
+ return EFI_LOAD_ERROR;
+
+ fdt_val32 = cpu_to_fdt32(*map->map_size);
+ err = fdt_setprop_inplace(fdt, node, "linux,uefi-mmap-size",
+ &fdt_val32, sizeof(fdt_val32));
+ if (err)
+ return EFI_LOAD_ERROR;
+
+ fdt_val32 = cpu_to_fdt32(*map->desc_size);
+ err = fdt_setprop_inplace(fdt, node, "linux,uefi-mmap-desc-size",
+ &fdt_val32, sizeof(fdt_val32));
+ if (err)
+ return EFI_LOAD_ERROR;
+
+ fdt_val32 = cpu_to_fdt32(*map->desc_ver);
+ err = fdt_setprop_inplace(fdt, node, "linux,uefi-mmap-desc-ver",
+ &fdt_val32, sizeof(fdt_val32));
+ if (err)
+ return EFI_LOAD_ERROR;
+
+ return EFI_SUCCESS;
+}
+
#ifndef EFI_FDT_ALIGN
#define EFI_FDT_ALIGN EFI_PAGE_SIZE
#endif
struct exit_boot_struct {
efi_memory_desc_t *runtime_map;
int *runtime_entry_count;
+ void *new_fdt_addr;
};
static efi_status_t exit_boot_func(efi_system_table_t *sys_table_arg,
efi_get_virtmap(*map->map, *map->map_size, *map->desc_size,
p->runtime_map, p->runtime_entry_count);
- return EFI_SUCCESS;
+ return update_fdt_memmap(p->new_fdt_addr, map);
}
/*
goto fail;
}
- /*
- * Now that we have done our final memory allocation (and free)
- * we can get the memory map key needed for
- * exit_boot_services().
- */
- status = efi_get_memory_map(sys_table, &map);
- if (status != EFI_SUCCESS)
- goto fail_free_new_fdt;
-
status = update_fdt(sys_table,
(void *)fdt_addr, fdt_size,
(void *)*new_fdt_addr, new_fdt_size,
- cmdline_ptr, initrd_addr, initrd_size,
- memory_map, map_size, desc_size, desc_ver);
+ cmdline_ptr, initrd_addr, initrd_size);
/* Succeeding the first time is the expected case. */
if (status == EFI_SUCCESS)
/*
* We need to allocate more space for the new
* device tree, so free existing buffer that is
- * too small. Also free memory map, as we will need
- * to get new one that reflects the free/alloc we do
- * on the device tree buffer.
+ * too small.
*/
efi_free(sys_table, new_fdt_size, *new_fdt_addr);
- sys_table->boottime->free_pool(memory_map);
new_fdt_size += EFI_PAGE_SIZE;
} else {
pr_efi_err(sys_table, "Unable to construct new device tree.\n");
- goto fail_free_mmap;
+ goto fail_free_new_fdt;
}
}
- sys_table->boottime->free_pool(memory_map);
priv.runtime_map = runtime_map;
priv.runtime_entry_count = &runtime_entry_count;
+ priv.new_fdt_addr = (void *)*new_fdt_addr;
status = efi_exit_boot_services(sys_table, handle, &map, &priv,
exit_boot_func);
pr_efi_err(sys_table, "Exit boot services failed.\n");
-fail_free_mmap:
- sys_table->boottime->free_pool(memory_map);
-
fail_free_new_fdt:
efi_free(sys_table, new_fdt_size, *new_fdt_addr);
#include <linux/efi.h>
#include <linux/io.h>
#include <asm/early_ioremap.h>
+#include <linux/memblock.h>
+#include <linux/slab.h>
+
+static phys_addr_t __init __efi_memmap_alloc_early(unsigned long size)
+{
+ return memblock_alloc(size, 0);
+}
+
+static phys_addr_t __init __efi_memmap_alloc_late(unsigned long size)
+{
+ unsigned int order = get_order(size);
+ struct page *p = alloc_pages(GFP_KERNEL, order);
+
+ if (!p)
+ return 0;
+
+ return PFN_PHYS(page_to_pfn(p));
+}
+
+/**
+ * efi_memmap_alloc - Allocate memory for the EFI memory map
+ * @num_entries: Number of entries in the allocated map.
+ *
+ * Depending on whether mm_init() has already been invoked or not,
+ * either memblock or "normal" page allocation is used.
+ *
+ * Returns the physical address of the allocated memory map on
+ * success, zero on failure.
+ */
+phys_addr_t __init efi_memmap_alloc(unsigned int num_entries)
+{
+ unsigned long size = num_entries * efi.memmap.desc_size;
+
+ if (slab_is_available())
+ return __efi_memmap_alloc_late(size);
+
+ return __efi_memmap_alloc_early(size);
+}
/**
* __efi_memmap_init - Common code for mapping the EFI memory map
return 0;
}
-static int __init mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base)
+static int mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base)
{
struct irq_chip_generic *gc;
struct irq_chip_type *ct;
/* FIXME: should the legacy sysfs handling be moved to gpio_device? */
gpiochip_sysfs_unregister(gdev);
+ gpiochip_free_hogs(chip);
/* Numb the device, cancelling all outstanding operations */
gdev->chip = NULL;
gpiochip_irqchip_remove(chip);
acpi_gpiochip_remove(chip);
gpiochip_remove_pin_ranges(chip);
- gpiochip_free_hogs(chip);
of_gpiochip_remove(chip);
/*
* We accept no more calls into the driver from this point, so
}
/**
- * _gpiochip_irqchip_add() - adds an irqchip to a gpiochip
+ * gpiochip_irqchip_add_key() - adds an irqchip to a gpiochip
* @gpiochip: the gpiochip to add the irqchip to
* @irqchip: the irqchip to add to the gpiochip
* @first_irq: if not dynamically assigned, the base (first) IRQ to
* the pins on the gpiochip can generate a unique IRQ. Everything else
* need to be open coded.
*/
-int _gpiochip_irqchip_add(struct gpio_chip *gpiochip,
- struct irq_chip *irqchip,
- unsigned int first_irq,
- irq_flow_handler_t handler,
- unsigned int type,
- bool nested,
- struct lock_class_key *lock_key)
+int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
+ struct irq_chip *irqchip,
+ unsigned int first_irq,
+ irq_flow_handler_t handler,
+ unsigned int type,
+ bool nested,
+ struct lock_class_key *lock_key)
{
struct device_node *of_node;
bool irq_base_set = false;
return 0;
}
-EXPORT_SYMBOL_GPL(_gpiochip_irqchip_add);
+EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_key);
#else /* CONFIG_GPIOLIB_IRQCHIP */
else if (type == CGS_UCODE_ID_SMU_SK)
strcpy(fw_name, "amdgpu/polaris10_smc_sk.bin");
break;
+ case CHIP_POLARIS12:
+ strcpy(fw_name, "amdgpu/polaris12_smc.bin");
+ break;
default:
DRM_ERROR("SMC firmware not supported\n");
return -EINVAL;
}
break;
}
+
+ if (!(*out_ring && (*out_ring)->adev)) {
+ DRM_ERROR("Ring %d is not initialized on IP %d\n",
+ ring, ip_type);
+ return -EINVAL;
+ }
+
return 0;
}
"STONEY",
"POLARIS10",
"POLARIS11",
+ "POLARIS12",
"LAST",
};
case CHIP_FIJI:
case CHIP_POLARIS11:
case CHIP_POLARIS10:
+ case CHIP_POLARIS12:
case CHIP_CARRIZO:
case CHIP_STONEY:
if (adev->asic_type == CHIP_CARRIZO || adev->asic_type == CHIP_STONEY)
{0x1002, 0x67CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10},
{0x1002, 0x67CC, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10},
{0x1002, 0x67CF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10},
+ /* Polaris12 */
+ {0x1002, 0x6980, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12},
+ {0x1002, 0x6981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12},
+ {0x1002, 0x6985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12},
+ {0x1002, 0x6986, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12},
+ {0x1002, 0x6987, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12},
+ {0x1002, 0x699F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12},
{0, 0, 0}
};
switch (adev->asic_type) {
case CHIP_POLARIS11:
case CHIP_POLARIS10:
+ case CHIP_POLARIS12:
case CHIP_TONGA:
case CHIP_FIJI:
case CHIP_TOPAZ:
#define FIRMWARE_STONEY "amdgpu/stoney_uvd.bin"
#define FIRMWARE_POLARIS10 "amdgpu/polaris10_uvd.bin"
#define FIRMWARE_POLARIS11 "amdgpu/polaris11_uvd.bin"
+#define FIRMWARE_POLARIS12 "amdgpu/polaris12_uvd.bin"
/**
* amdgpu_uvd_cs_ctx - Command submission parser context
MODULE_FIRMWARE(FIRMWARE_STONEY);
MODULE_FIRMWARE(FIRMWARE_POLARIS10);
MODULE_FIRMWARE(FIRMWARE_POLARIS11);
+MODULE_FIRMWARE(FIRMWARE_POLARIS12);
static void amdgpu_uvd_idle_work_handler(struct work_struct *work);
case CHIP_POLARIS11:
fw_name = FIRMWARE_POLARIS11;
break;
+ case CHIP_POLARIS12:
+ fw_name = FIRMWARE_POLARIS12;
+ break;
default:
return -EINVAL;
}
#define FIRMWARE_STONEY "amdgpu/stoney_vce.bin"
#define FIRMWARE_POLARIS10 "amdgpu/polaris10_vce.bin"
#define FIRMWARE_POLARIS11 "amdgpu/polaris11_vce.bin"
+#define FIRMWARE_POLARIS12 "amdgpu/polaris12_vce.bin"
#ifdef CONFIG_DRM_AMDGPU_CIK
MODULE_FIRMWARE(FIRMWARE_BONAIRE);
MODULE_FIRMWARE(FIRMWARE_STONEY);
MODULE_FIRMWARE(FIRMWARE_POLARIS10);
MODULE_FIRMWARE(FIRMWARE_POLARIS11);
+MODULE_FIRMWARE(FIRMWARE_POLARIS12);
static void amdgpu_vce_idle_work_handler(struct work_struct *work);
case CHIP_POLARIS11:
fw_name = FIRMWARE_POLARIS11;
break;
+ case CHIP_POLARIS12:
+ fw_name = FIRMWARE_POLARIS12;
+ break;
default:
return -EINVAL;
WREG32(mmCUR_POSITION + amdgpu_crtc->crtc_offset, (x << 16) | y);
WREG32(mmCUR_HOT_SPOT + amdgpu_crtc->crtc_offset, (xorigin << 16) | yorigin);
+ WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
+ ((amdgpu_crtc->cursor_width - 1) << 16) | (amdgpu_crtc->cursor_height - 1));
return 0;
}
int32_t hot_y)
{
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
- struct amdgpu_device *adev = crtc->dev->dev_private;
struct drm_gem_object *obj;
struct amdgpu_bo *aobj;
int ret;
dce_v10_0_lock_cursor(crtc, true);
- if (hot_x != amdgpu_crtc->cursor_hot_x ||
+ if (width != amdgpu_crtc->cursor_width ||
+ height != amdgpu_crtc->cursor_height ||
+ hot_x != amdgpu_crtc->cursor_hot_x ||
hot_y != amdgpu_crtc->cursor_hot_y) {
int x, y;
dce_v10_0_cursor_move_locked(crtc, x, y);
- amdgpu_crtc->cursor_hot_x = hot_x;
- amdgpu_crtc->cursor_hot_y = hot_y;
- }
-
- if (width != amdgpu_crtc->cursor_width ||
- height != amdgpu_crtc->cursor_height) {
- WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
- (width - 1) << 16 | (height - 1));
amdgpu_crtc->cursor_width = width;
amdgpu_crtc->cursor_height = height;
+ amdgpu_crtc->cursor_hot_x = hot_x;
+ amdgpu_crtc->cursor_hot_y = hot_y;
}
dce_v10_0_show_cursor(crtc);
static void dce_v10_0_cursor_reset(struct drm_crtc *crtc)
{
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
- struct amdgpu_device *adev = crtc->dev->dev_private;
if (amdgpu_crtc->cursor_bo) {
dce_v10_0_lock_cursor(crtc, true);
dce_v10_0_cursor_move_locked(crtc, amdgpu_crtc->cursor_x,
amdgpu_crtc->cursor_y);
- WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
- (amdgpu_crtc->cursor_width - 1) << 16 |
- (amdgpu_crtc->cursor_height - 1));
-
dce_v10_0_show_cursor(crtc);
dce_v10_0_lock_cursor(crtc, false);
(const u32)ARRAY_SIZE(stoney_golden_settings_a11));
break;
case CHIP_POLARIS11:
+ case CHIP_POLARIS12:
amdgpu_program_register_sequence(adev,
polaris11_golden_settings_a11,
(const u32)ARRAY_SIZE(polaris11_golden_settings_a11));
num_crtc = 6;
break;
case CHIP_POLARIS11:
+ case CHIP_POLARIS12:
num_crtc = 5;
break;
default:
adev->mode_info.audio.num_pins = 8;
break;
case CHIP_POLARIS11:
+ case CHIP_POLARIS12:
adev->mode_info.audio.num_pins = 6;
break;
default:
int pll;
if ((adev->asic_type == CHIP_POLARIS10) ||
- (adev->asic_type == CHIP_POLARIS11)) {
+ (adev->asic_type == CHIP_POLARIS11) ||
+ (adev->asic_type == CHIP_POLARIS12)) {
struct amdgpu_encoder *amdgpu_encoder =
to_amdgpu_encoder(amdgpu_crtc->encoder);
struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv;
WREG32(mmCUR_POSITION + amdgpu_crtc->crtc_offset, (x << 16) | y);
WREG32(mmCUR_HOT_SPOT + amdgpu_crtc->crtc_offset, (xorigin << 16) | yorigin);
+ WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
+ ((amdgpu_crtc->cursor_width - 1) << 16) | (amdgpu_crtc->cursor_height - 1));
return 0;
}
int32_t hot_y)
{
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
- struct amdgpu_device *adev = crtc->dev->dev_private;
struct drm_gem_object *obj;
struct amdgpu_bo *aobj;
int ret;
dce_v11_0_lock_cursor(crtc, true);
- if (hot_x != amdgpu_crtc->cursor_hot_x ||
+ if (width != amdgpu_crtc->cursor_width ||
+ height != amdgpu_crtc->cursor_height ||
+ hot_x != amdgpu_crtc->cursor_hot_x ||
hot_y != amdgpu_crtc->cursor_hot_y) {
int x, y;
dce_v11_0_cursor_move_locked(crtc, x, y);
- amdgpu_crtc->cursor_hot_x = hot_x;
- amdgpu_crtc->cursor_hot_y = hot_y;
- }
-
- if (width != amdgpu_crtc->cursor_width ||
- height != amdgpu_crtc->cursor_height) {
- WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
- (width - 1) << 16 | (height - 1));
amdgpu_crtc->cursor_width = width;
amdgpu_crtc->cursor_height = height;
+ amdgpu_crtc->cursor_hot_x = hot_x;
+ amdgpu_crtc->cursor_hot_y = hot_y;
}
dce_v11_0_show_cursor(crtc);
static void dce_v11_0_cursor_reset(struct drm_crtc *crtc)
{
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
- struct amdgpu_device *adev = crtc->dev->dev_private;
if (amdgpu_crtc->cursor_bo) {
dce_v11_0_lock_cursor(crtc, true);
dce_v11_0_cursor_move_locked(crtc, amdgpu_crtc->cursor_x,
amdgpu_crtc->cursor_y);
- WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
- (amdgpu_crtc->cursor_width - 1) << 16 |
- (amdgpu_crtc->cursor_height - 1));
-
dce_v11_0_show_cursor(crtc);
dce_v11_0_lock_cursor(crtc, false);
return -EINVAL;
if ((adev->asic_type == CHIP_POLARIS10) ||
- (adev->asic_type == CHIP_POLARIS11)) {
+ (adev->asic_type == CHIP_POLARIS11) ||
+ (adev->asic_type == CHIP_POLARIS12)) {
struct amdgpu_encoder *amdgpu_encoder =
to_amdgpu_encoder(amdgpu_crtc->encoder);
int encoder_mode =
adev->mode_info.num_dig = 6;
break;
case CHIP_POLARIS11:
+ case CHIP_POLARIS12:
adev->mode_info.num_hpd = 5;
adev->mode_info.num_dig = 5;
break;
amdgpu_atombios_crtc_powergate_init(adev);
amdgpu_atombios_encoder_init_dig(adev);
if ((adev->asic_type == CHIP_POLARIS10) ||
- (adev->asic_type == CHIP_POLARIS11)) {
+ (adev->asic_type == CHIP_POLARIS11) ||
+ (adev->asic_type == CHIP_POLARIS12)) {
amdgpu_atombios_crtc_set_dce_clock(adev, adev->clock.default_dispclk,
DCE_CLOCK_TYPE_DISPCLK, ATOM_GCK_DFS);
amdgpu_atombios_crtc_set_dce_clock(adev, 0,
struct amdgpu_device *adev = crtc->dev->dev_private;
int xorigin = 0, yorigin = 0;
+ int w = amdgpu_crtc->cursor_width;
+
amdgpu_crtc->cursor_x = x;
amdgpu_crtc->cursor_y = y;
WREG32(mmCUR_POSITION + amdgpu_crtc->crtc_offset, (x << 16) | y);
WREG32(mmCUR_HOT_SPOT + amdgpu_crtc->crtc_offset, (xorigin << 16) | yorigin);
+ WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
+ ((w - 1) << 16) | (amdgpu_crtc->cursor_height - 1));
return 0;
}
int32_t hot_y)
{
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
- struct amdgpu_device *adev = crtc->dev->dev_private;
struct drm_gem_object *obj;
struct amdgpu_bo *aobj;
int ret;
dce_v6_0_lock_cursor(crtc, true);
- if (hot_x != amdgpu_crtc->cursor_hot_x ||
+ if (width != amdgpu_crtc->cursor_width ||
+ height != amdgpu_crtc->cursor_height ||
+ hot_x != amdgpu_crtc->cursor_hot_x ||
hot_y != amdgpu_crtc->cursor_hot_y) {
int x, y;
dce_v6_0_cursor_move_locked(crtc, x, y);
- amdgpu_crtc->cursor_hot_x = hot_x;
- amdgpu_crtc->cursor_hot_y = hot_y;
- }
-
- if (width != amdgpu_crtc->cursor_width ||
- height != amdgpu_crtc->cursor_height) {
- WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
- (width - 1) << 16 | (height - 1));
amdgpu_crtc->cursor_width = width;
amdgpu_crtc->cursor_height = height;
+ amdgpu_crtc->cursor_hot_x = hot_x;
+ amdgpu_crtc->cursor_hot_y = hot_y;
}
dce_v6_0_show_cursor(crtc);
static void dce_v6_0_cursor_reset(struct drm_crtc *crtc)
{
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
- struct amdgpu_device *adev = crtc->dev->dev_private;
if (amdgpu_crtc->cursor_bo) {
dce_v6_0_lock_cursor(crtc, true);
dce_v6_0_cursor_move_locked(crtc, amdgpu_crtc->cursor_x,
amdgpu_crtc->cursor_y);
- WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
- (amdgpu_crtc->cursor_width - 1) << 16 |
- (amdgpu_crtc->cursor_height - 1));
-
dce_v6_0_show_cursor(crtc);
dce_v6_0_lock_cursor(crtc, false);
}
WREG32(mmCUR_POSITION + amdgpu_crtc->crtc_offset, (x << 16) | y);
WREG32(mmCUR_HOT_SPOT + amdgpu_crtc->crtc_offset, (xorigin << 16) | yorigin);
+ WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
+ ((amdgpu_crtc->cursor_width - 1) << 16) | (amdgpu_crtc->cursor_height - 1));
return 0;
}
int32_t hot_y)
{
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
- struct amdgpu_device *adev = crtc->dev->dev_private;
struct drm_gem_object *obj;
struct amdgpu_bo *aobj;
int ret;
dce_v8_0_lock_cursor(crtc, true);
- if (hot_x != amdgpu_crtc->cursor_hot_x ||
+ if (width != amdgpu_crtc->cursor_width ||
+ height != amdgpu_crtc->cursor_height ||
+ hot_x != amdgpu_crtc->cursor_hot_x ||
hot_y != amdgpu_crtc->cursor_hot_y) {
int x, y;
dce_v8_0_cursor_move_locked(crtc, x, y);
- amdgpu_crtc->cursor_hot_x = hot_x;
- amdgpu_crtc->cursor_hot_y = hot_y;
- }
-
- if (width != amdgpu_crtc->cursor_width ||
- height != amdgpu_crtc->cursor_height) {
- WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
- (width - 1) << 16 | (height - 1));
amdgpu_crtc->cursor_width = width;
amdgpu_crtc->cursor_height = height;
+ amdgpu_crtc->cursor_hot_x = hot_x;
+ amdgpu_crtc->cursor_hot_y = hot_y;
}
dce_v8_0_show_cursor(crtc);
static void dce_v8_0_cursor_reset(struct drm_crtc *crtc)
{
struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
- struct amdgpu_device *adev = crtc->dev->dev_private;
if (amdgpu_crtc->cursor_bo) {
dce_v8_0_lock_cursor(crtc, true);
dce_v8_0_cursor_move_locked(crtc, amdgpu_crtc->cursor_x,
amdgpu_crtc->cursor_y);
- WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset,
- (amdgpu_crtc->cursor_width - 1) << 16 |
- (amdgpu_crtc->cursor_height - 1));
-
dce_v8_0_show_cursor(crtc);
dce_v8_0_lock_cursor(crtc, false);
static void dce_virtual_encoder_destroy(struct drm_encoder *encoder)
{
- struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
-
- kfree(amdgpu_encoder->enc_priv);
drm_encoder_cleanup(encoder);
- kfree(amdgpu_encoder);
+ kfree(encoder);
}
static const struct drm_encoder_funcs dce_virtual_encoder_funcs = {
MODULE_FIRMWARE("amdgpu/polaris10_mec2.bin");
MODULE_FIRMWARE("amdgpu/polaris10_rlc.bin");
+MODULE_FIRMWARE("amdgpu/polaris12_ce.bin");
+MODULE_FIRMWARE("amdgpu/polaris12_pfp.bin");
+MODULE_FIRMWARE("amdgpu/polaris12_me.bin");
+MODULE_FIRMWARE("amdgpu/polaris12_mec.bin");
+MODULE_FIRMWARE("amdgpu/polaris12_mec2.bin");
+MODULE_FIRMWARE("amdgpu/polaris12_rlc.bin");
+
static const struct amdgpu_gds_reg_offset amdgpu_gds_reg_offset[] =
{
{mmGDS_VMID0_BASE, mmGDS_VMID0_SIZE, mmGDS_GWS_VMID0, mmGDS_OA_VMID0},
(const u32)ARRAY_SIZE(tonga_golden_common_all));
break;
case CHIP_POLARIS11:
+ case CHIP_POLARIS12:
amdgpu_program_register_sequence(adev,
golden_settings_polaris11_a11,
(const u32)ARRAY_SIZE(golden_settings_polaris11_a11));
case CHIP_POLARIS10:
chip_name = "polaris10";
break;
+ case CHIP_POLARIS12:
+ chip_name = "polaris12";
+ break;
case CHIP_STONEY:
chip_name = "stoney";
break;
gb_addr_config = TONGA_GB_ADDR_CONFIG_GOLDEN;
break;
case CHIP_POLARIS11:
+ case CHIP_POLARIS12:
ret = amdgpu_atombios_get_gfx_info(adev);
if (ret)
return ret;
break;
case CHIP_POLARIS11:
+ case CHIP_POLARIS12:
modearray[0] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
PIPE_CONFIG(ADDR_SURF_P4_16x16) |
TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
*rconf1 |= 0x0;
break;
case CHIP_POLARIS11:
+ case CHIP_POLARIS12:
*rconf |= RB_MAP_PKR0(2) | RB_XSEL2(1) | SE_MAP(2) |
SE_XSEL(1) | SE_YSEL(1);
*rconf1 |= 0x0;
cz_enable_cp_power_gating(adev, true);
else
cz_enable_cp_power_gating(adev, false);
- } else if (adev->asic_type == CHIP_POLARIS11) {
+ } else if ((adev->asic_type == CHIP_POLARIS11) ||
+ (adev->asic_type == CHIP_POLARIS12)) {
gfx_v8_0_init_csb(adev);
gfx_v8_0_init_save_restore_list(adev);
gfx_v8_0_enable_save_restore_machine(adev);
RLC_CGCG_CGLS_CTRL__CGLS_EN_MASK);
WREG32(mmRLC_CGCG_CGLS_CTRL, tmp);
if (adev->asic_type == CHIP_POLARIS11 ||
- adev->asic_type == CHIP_POLARIS10) {
+ adev->asic_type == CHIP_POLARIS10 ||
+ adev->asic_type == CHIP_POLARIS12) {
tmp = RREG32(mmRLC_CGCG_CGLS_CTRL_3D);
tmp &= ~0x3;
WREG32(mmRLC_CGCG_CGLS_CTRL_3D, tmp);
amdgpu_ring_write(ring, 0x0000002A);
break;
case CHIP_POLARIS11:
+ case CHIP_POLARIS12:
amdgpu_ring_write(ring, 0x16000012);
amdgpu_ring_write(ring, 0x00000000);
break;
(adev->asic_type == CHIP_FIJI) ||
(adev->asic_type == CHIP_STONEY) ||
(adev->asic_type == CHIP_POLARIS11) ||
- (adev->asic_type == CHIP_POLARIS10)) {
+ (adev->asic_type == CHIP_POLARIS10) ||
+ (adev->asic_type == CHIP_POLARIS12)) {
WREG32(mmCP_MEC_DOORBELL_RANGE_LOWER,
AMDGPU_DOORBELL_KIQ << 2);
WREG32(mmCP_MEC_DOORBELL_RANGE_UPPER,
mqd->cp_hqd_persistent_state = tmp;
if (adev->asic_type == CHIP_STONEY ||
adev->asic_type == CHIP_POLARIS11 ||
- adev->asic_type == CHIP_POLARIS10) {
+ adev->asic_type == CHIP_POLARIS10 ||
+ adev->asic_type == CHIP_POLARIS12) {
tmp = RREG32(mmCP_ME1_PIPE3_INT_CNTL);
tmp = REG_SET_FIELD(tmp, CP_ME1_PIPE3_INT_CNTL, GENERIC2_INT_ENABLE, 1);
WREG32(mmCP_ME1_PIPE3_INT_CNTL, tmp);
static void gfx_v8_0_enable_gfx_static_mg_power_gating(struct amdgpu_device *adev,
bool enable)
{
- if (adev->asic_type == CHIP_POLARIS11)
+ if ((adev->asic_type == CHIP_POLARIS11) ||
+ (adev->asic_type == CHIP_POLARIS12))
/* Send msg to SMU via Powerplay */
amdgpu_set_powergating_state(adev,
AMD_IP_BLOCK_TYPE_SMC,
gfx_v8_0_enable_gfx_dynamic_mg_power_gating(adev, false);
break;
case CHIP_POLARIS11:
+ case CHIP_POLARIS12:
if ((adev->pg_flags & AMD_PG_SUPPORT_GFX_SMG) && enable)
gfx_v8_0_enable_gfx_static_mg_power_gating(adev, true);
else
MODULE_FIRMWARE("radeon/pitcairn_mc.bin");
MODULE_FIRMWARE("radeon/verde_mc.bin");
MODULE_FIRMWARE("radeon/oland_mc.bin");
+MODULE_FIRMWARE("radeon/si58_mc.bin");
#define MC_SEQ_MISC0__MT__MASK 0xf0000000
#define MC_SEQ_MISC0__MT__GDDR1 0x10000000
const char *chip_name;
char fw_name[30];
int err;
+ bool is_58_fw = false;
DRM_DEBUG("\n");
default: BUG();
}
- snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name);
+ /* this memory configuration requires special firmware */
+ if (((RREG32(mmMC_SEQ_MISC0) & 0xff000000) >> 24) == 0x58)
+ is_58_fw = true;
+
+ if (is_58_fw)
+ snprintf(fw_name, sizeof(fw_name), "radeon/si58_mc.bin");
+ else
+ snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name);
err = request_firmware(&adev->mc.fw, fw_name, adev->dev);
if (err)
goto out;
}
WREG32(mmHDP_REG_COHERENCY_FLUSH_CNTL, 0);
+ if (adev->mode_info.num_crtc)
+ amdgpu_display_set_vga_render_state(adev, false);
+
gmc_v6_0_mc_stop(adev, &save);
if (gmc_v6_0_wait_for_idle((void *)adev)) {
dev_warn(adev->dev, "Wait for MC idle timedout !\n");
}
gmc_v6_0_mc_resume(adev, &save);
- amdgpu_display_set_vga_render_state(adev, false);
}
static int gmc_v6_0_mc_init(struct amdgpu_device *adev)
WREG32(mmVM_CONTEXT1_CNTL,
VM_CONTEXT1_CNTL__ENABLE_CONTEXT_MASK |
(1UL << VM_CONTEXT1_CNTL__PAGE_TABLE_DEPTH__SHIFT) |
- ((amdgpu_vm_block_size - 9) << VM_CONTEXT1_CNTL__PAGE_TABLE_BLOCK_SIZE__SHIFT) |
- VM_CONTEXT1_CNTL__RANGE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK |
- VM_CONTEXT1_CNTL__RANGE_PROTECTION_FAULT_ENABLE_DEFAULT_MASK |
- VM_CONTEXT1_CNTL__DUMMY_PAGE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK |
- VM_CONTEXT1_CNTL__DUMMY_PAGE_PROTECTION_FAULT_ENABLE_DEFAULT_MASK |
- VM_CONTEXT1_CNTL__PDE0_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK |
- VM_CONTEXT1_CNTL__PDE0_PROTECTION_FAULT_ENABLE_DEFAULT_MASK |
- VM_CONTEXT1_CNTL__VALID_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK |
- VM_CONTEXT1_CNTL__VALID_PROTECTION_FAULT_ENABLE_DEFAULT_MASK |
- VM_CONTEXT1_CNTL__READ_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK |
- VM_CONTEXT1_CNTL__READ_PROTECTION_FAULT_ENABLE_DEFAULT_MASK |
- VM_CONTEXT1_CNTL__WRITE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK |
- VM_CONTEXT1_CNTL__WRITE_PROTECTION_FAULT_ENABLE_DEFAULT_MASK);
+ ((amdgpu_vm_block_size - 9) << VM_CONTEXT1_CNTL__PAGE_TABLE_BLOCK_SIZE__SHIFT));
+ if (amdgpu_vm_fault_stop == AMDGPU_VM_FAULT_STOP_ALWAYS)
+ gmc_v6_0_set_fault_enable_default(adev, false);
+ else
+ gmc_v6_0_set_fault_enable_default(adev, true);
gmc_v6_0_gart_flush_gpu_tlb(adev, 0);
dev_info(adev->dev, "PCIE GART of %uM enabled (table at 0x%016llX).\n",
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
- return amdgpu_irq_get(adev, &adev->mc.vm_fault, 0);
+ if (amdgpu_vm_fault_stop != AMDGPU_VM_FAULT_STOP_ALWAYS)
+ return amdgpu_irq_get(adev, &adev->mc.vm_fault, 0);
+ else
+ return 0;
}
static int gmc_v6_0_sw_init(void *handle)
MODULE_FIRMWARE("amdgpu/tonga_mc.bin");
MODULE_FIRMWARE("amdgpu/polaris11_mc.bin");
MODULE_FIRMWARE("amdgpu/polaris10_mc.bin");
+MODULE_FIRMWARE("amdgpu/polaris12_mc.bin");
static const u32 golden_settings_tonga_a11[] =
{
(const u32)ARRAY_SIZE(golden_settings_tonga_a11));
break;
case CHIP_POLARIS11:
+ case CHIP_POLARIS12:
amdgpu_program_register_sequence(adev,
golden_settings_polaris11_a11,
(const u32)ARRAY_SIZE(golden_settings_polaris11_a11));
case CHIP_POLARIS10:
chip_name = "polaris10";
break;
+ case CHIP_POLARIS12:
+ chip_name = "polaris12";
+ break;
case CHIP_FIJI:
case CHIP_CARRIZO:
case CHIP_STONEY:
MODULE_FIRMWARE("amdgpu/polaris10_sdma1.bin");
MODULE_FIRMWARE("amdgpu/polaris11_sdma.bin");
MODULE_FIRMWARE("amdgpu/polaris11_sdma1.bin");
+MODULE_FIRMWARE("amdgpu/polaris12_sdma.bin");
+MODULE_FIRMWARE("amdgpu/polaris12_sdma1.bin");
static const u32 sdma_offsets[SDMA_MAX_INSTANCE] =
(const u32)ARRAY_SIZE(golden_settings_tonga_a11));
break;
case CHIP_POLARIS11:
+ case CHIP_POLARIS12:
amdgpu_program_register_sequence(adev,
golden_settings_polaris11_a11,
(const u32)ARRAY_SIZE(golden_settings_polaris11_a11));
case CHIP_POLARIS10:
chip_name = "polaris10";
break;
+ case CHIP_POLARIS12:
+ chip_name = "polaris12";
+ break;
case CHIP_CARRIZO:
chip_name = "carrizo";
break;
#define BIOS_SCRATCH_4 0x5cd
MODULE_FIRMWARE("radeon/tahiti_smc.bin");
-MODULE_FIRMWARE("radeon/tahiti_k_smc.bin");
MODULE_FIRMWARE("radeon/pitcairn_smc.bin");
MODULE_FIRMWARE("radeon/pitcairn_k_smc.bin");
MODULE_FIRMWARE("radeon/verde_smc.bin");
MODULE_FIRMWARE("radeon/oland_k_smc.bin");
MODULE_FIRMWARE("radeon/hainan_smc.bin");
MODULE_FIRMWARE("radeon/hainan_k_smc.bin");
+MODULE_FIRMWARE("radeon/banks_k_2_smc.bin");
union power_info {
struct _ATOM_POWERPLAY_INFO info;
(adev->pdev->device == 0x6817) ||
(adev->pdev->device == 0x6806))
max_mclk = 120000;
- } else if (adev->asic_type == CHIP_VERDE) {
- if ((adev->pdev->revision == 0x81) ||
- (adev->pdev->revision == 0x83) ||
- (adev->pdev->revision == 0x87) ||
- (adev->pdev->device == 0x6820) ||
- (adev->pdev->device == 0x6821) ||
- (adev->pdev->device == 0x6822) ||
- (adev->pdev->device == 0x6823) ||
- (adev->pdev->device == 0x682A) ||
- (adev->pdev->device == 0x682B)) {
- max_sclk = 75000;
- max_mclk = 80000;
- }
- } else if (adev->asic_type == CHIP_OLAND) {
- if ((adev->pdev->revision == 0xC7) ||
- (adev->pdev->revision == 0x80) ||
- (adev->pdev->revision == 0x81) ||
- (adev->pdev->revision == 0x83) ||
- (adev->pdev->revision == 0x87) ||
- (adev->pdev->device == 0x6604) ||
- (adev->pdev->device == 0x6605)) {
- max_sclk = 75000;
- max_mclk = 80000;
- }
} else if (adev->asic_type == CHIP_HAINAN) {
if ((adev->pdev->revision == 0x81) ||
(adev->pdev->revision == 0x83) ||
(adev->pdev->device == 0x6665) ||
(adev->pdev->device == 0x6667)) {
max_sclk = 75000;
- max_mclk = 80000;
}
}
/* Apply dpm quirks */
chip_name = "tahiti";
break;
case CHIP_PITCAIRN:
- if ((adev->pdev->revision == 0x81) ||
- (adev->pdev->device == 0x6810) ||
- (adev->pdev->device == 0x6811) ||
- (adev->pdev->device == 0x6816) ||
- (adev->pdev->device == 0x6817) ||
- (adev->pdev->device == 0x6806))
+ if ((adev->pdev->revision == 0x81) &&
+ ((adev->pdev->device == 0x6810) ||
+ (adev->pdev->device == 0x6811)))
chip_name = "pitcairn_k";
else
chip_name = "pitcairn";
break;
case CHIP_VERDE:
- if ((adev->pdev->revision == 0x81) ||
- (adev->pdev->revision == 0x83) ||
- (adev->pdev->revision == 0x87) ||
- (adev->pdev->device == 0x6820) ||
- (adev->pdev->device == 0x6821) ||
- (adev->pdev->device == 0x6822) ||
- (adev->pdev->device == 0x6823) ||
- (adev->pdev->device == 0x682A) ||
- (adev->pdev->device == 0x682B))
+ if (((adev->pdev->device == 0x6820) &&
+ ((adev->pdev->revision == 0x81) ||
+ (adev->pdev->revision == 0x83))) ||
+ ((adev->pdev->device == 0x6821) &&
+ ((adev->pdev->revision == 0x83) ||
+ (adev->pdev->revision == 0x87))) ||
+ ((adev->pdev->revision == 0x87) &&
+ ((adev->pdev->device == 0x6823) ||
+ (adev->pdev->device == 0x682b))))
chip_name = "verde_k";
else
chip_name = "verde";
break;
case CHIP_OLAND:
- if ((adev->pdev->revision == 0xC7) ||
- (adev->pdev->revision == 0x80) ||
- (adev->pdev->revision == 0x81) ||
- (adev->pdev->revision == 0x83) ||
- (adev->pdev->revision == 0x87) ||
- (adev->pdev->device == 0x6604) ||
- (adev->pdev->device == 0x6605))
+ if (((adev->pdev->revision == 0x81) &&
+ ((adev->pdev->device == 0x6600) ||
+ (adev->pdev->device == 0x6604) ||
+ (adev->pdev->device == 0x6605) ||
+ (adev->pdev->device == 0x6610))) ||
+ ((adev->pdev->revision == 0x83) &&
+ (adev->pdev->device == 0x6610)))
chip_name = "oland_k";
else
chip_name = "oland";
break;
case CHIP_HAINAN:
- if ((adev->pdev->revision == 0x81) ||
- (adev->pdev->revision == 0x83) ||
- (adev->pdev->revision == 0xC3) ||
- (adev->pdev->device == 0x6664) ||
- (adev->pdev->device == 0x6665) ||
- (adev->pdev->device == 0x6667))
+ if (((adev->pdev->revision == 0x81) &&
+ (adev->pdev->device == 0x6660)) ||
+ ((adev->pdev->revision == 0x83) &&
+ ((adev->pdev->device == 0x6660) ||
+ (adev->pdev->device == 0x6663) ||
+ (adev->pdev->device == 0x6665) ||
+ (adev->pdev->device == 0x6667))))
chip_name = "hainan_k";
+ else if ((adev->pdev->revision == 0xc3) &&
+ (adev->pdev->device == 0x6665))
+ chip_name = "banks_k_2";
else
chip_name = "hainan";
break;
#include "smu/smu_7_0_1_sh_mask.h"
static void uvd_v4_2_mc_resume(struct amdgpu_device *adev);
-static void uvd_v4_2_init_cg(struct amdgpu_device *adev);
static void uvd_v4_2_set_ring_funcs(struct amdgpu_device *adev);
static void uvd_v4_2_set_irq_funcs(struct amdgpu_device *adev);
static int uvd_v4_2_start(struct amdgpu_device *adev);
static void uvd_v4_2_stop(struct amdgpu_device *adev);
static int uvd_v4_2_set_clockgating_state(void *handle,
enum amd_clockgating_state state);
+static void uvd_v4_2_set_dcm(struct amdgpu_device *adev,
+ bool sw_mode);
/**
* uvd_v4_2_ring_get_rptr - get read pointer
*
return r;
}
-
+static void uvd_v4_2_enable_mgcg(struct amdgpu_device *adev,
+ bool enable);
/**
* uvd_v4_2_hw_init - start and test UVD block
*
uint32_t tmp;
int r;
- uvd_v4_2_init_cg(adev);
- uvd_v4_2_set_clockgating_state(adev, AMD_CG_STATE_GATE);
+ uvd_v4_2_enable_mgcg(adev, true);
amdgpu_asic_set_uvd_clocks(adev, 10000, 10000);
r = uvd_v4_2_start(adev);
if (r)
struct amdgpu_ring *ring = &adev->uvd.ring;
uint32_t rb_bufsz;
int i, j, r;
-
/* disable byte swapping */
u32 lmi_swap_cntl = 0;
u32 mp_swap_cntl = 0;
+ WREG32(mmUVD_CGC_GATE, 0);
+ uvd_v4_2_set_dcm(adev, true);
+
uvd_v4_2_mc_resume(adev);
/* disable interupt */
/* Unstall UMC and register bus */
WREG32_P(mmUVD_LMI_CTRL2, 0, ~(1 << 8));
+
+ uvd_v4_2_set_dcm(adev, false);
}
/**
WREG32_UVD_CTX(ixUVD_CGC_CTRL2, tmp2);
}
-static void uvd_v4_2_init_cg(struct amdgpu_device *adev)
-{
- bool hw_mode = true;
-
- if (hw_mode) {
- uvd_v4_2_set_dcm(adev, false);
- } else {
- u32 tmp = RREG32(mmUVD_CGC_CTRL);
- tmp &= ~UVD_CGC_CTRL__DYN_CLOCK_MODE_MASK;
- WREG32(mmUVD_CGC_CTRL, tmp);
- }
-}
-
static bool uvd_v4_2_is_idle(void *handle)
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
static int uvd_v4_2_set_clockgating_state(void *handle,
enum amd_clockgating_state state)
{
- bool gate = false;
- struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
- if (!(adev->cg_flags & AMD_CG_SUPPORT_UVD_MGCG))
- return 0;
-
- if (state == AMD_CG_STATE_GATE)
- gate = true;
-
- uvd_v4_2_enable_mgcg(adev, gate);
-
return 0;
}
*/
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
- if (!(adev->pg_flags & AMD_PG_SUPPORT_UVD))
- return 0;
-
if (state == AMD_PG_STATE_GATE) {
uvd_v4_2_stop(adev);
return 0;
{
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
bool enable = (state == AMD_CG_STATE_GATE) ? true : false;
- static int curstate = -1;
if (!(adev->cg_flags & AMD_CG_SUPPORT_UVD_MGCG))
return 0;
- if (curstate == state)
- return 0;
-
- curstate = state;
if (enable) {
/* wait for STATUS to clear */
if (uvd_v5_0_wait_for_idle(handle))
#define GRBM_GFX_INDEX__VCE_INSTANCE__SHIFT 0x04
#define GRBM_GFX_INDEX__VCE_INSTANCE_MASK 0x10
+#define GRBM_GFX_INDEX__VCE_ALL_PIPE 0x07
+
#define mmVCE_LMI_VCPU_CACHE_40BIT_BAR0 0x8616
#define mmVCE_LMI_VCPU_CACHE_40BIT_BAR1 0x8617
#define mmVCE_LMI_VCPU_CACHE_40BIT_BAR2 0x8618
+#define mmGRBM_GFX_INDEX_DEFAULT 0xE0000000
+
#define VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK 0x02
#define VCE_V3_0_FW_SIZE (384 * 1024)
#define FW_52_8_3 ((52 << 24) | (8 << 16) | (3 << 8))
+#define GET_VCE_INSTANCE(i) ((i) << GRBM_GFX_INDEX__VCE_INSTANCE__SHIFT \
+ | GRBM_GFX_INDEX__VCE_ALL_PIPE)
+
static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx);
static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev);
static void vce_v3_0_set_irq_funcs(struct amdgpu_device *adev);
WREG32(mmVCE_UENC_CLOCK_GATING_2, data);
data = RREG32(mmVCE_UENC_REG_CLOCK_GATING);
- data &= ~0xffc00000;
+ data &= ~0x3ff;
WREG32(mmVCE_UENC_REG_CLOCK_GATING, data);
data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL);
if (adev->vce.harvest_config & (1 << idx))
continue;
- WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, idx);
+ WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(idx));
vce_v3_0_mc_resume(adev, idx);
WREG32_FIELD(VCE_STATUS, JOB_BUSY, 1);
}
}
- WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0);
+ WREG32(mmGRBM_GFX_INDEX, mmGRBM_GFX_INDEX_DEFAULT);
mutex_unlock(&adev->grbm_idx_mutex);
return 0;
if (adev->vce.harvest_config & (1 << idx))
continue;
- WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, idx);
+ WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(idx));
if (adev->asic_type >= CHIP_STONEY)
WREG32_P(mmVCE_VCPU_CNTL, 0, ~0x200001);
vce_v3_0_set_vce_sw_clock_gating(adev, false);
}
- WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0);
+ WREG32(mmGRBM_GFX_INDEX, mmGRBM_GFX_INDEX_DEFAULT);
mutex_unlock(&adev->grbm_idx_mutex);
return 0;
{
u32 tmp;
- /* Fiji, Stoney, Polaris10, Polaris11 are single pipe */
+ /* Fiji, Stoney, Polaris10, Polaris11, Polaris12 are single pipe */
if ((adev->asic_type == CHIP_FIJI) ||
(adev->asic_type == CHIP_STONEY) ||
(adev->asic_type == CHIP_POLARIS10) ||
- (adev->asic_type == CHIP_POLARIS11))
+ (adev->asic_type == CHIP_POLARIS11) ||
+ (adev->asic_type == CHIP_POLARIS12))
return AMDGPU_VCE_HARVEST_VCE1;
/* Tonga and CZ are dual or single pipe */
* VCE team suggest use bit 3--bit 6 for busy status check
*/
mutex_lock(&adev->grbm_idx_mutex);
- WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0);
+ WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(0));
if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) {
srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1);
srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1);
}
- WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0x10);
+ WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(1));
if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) {
srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1);
srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1);
}
- WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0);
+ WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(0));
mutex_unlock(&adev->grbm_idx_mutex);
if (srbm_soft_reset) {
if (adev->vce.harvest_config & (1 << i))
continue;
- WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, i);
+ WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(i));
if (enable) {
/* initialize VCE_CLOCK_GATING_A: Clock ON/OFF delay */
vce_v3_0_set_vce_sw_clock_gating(adev, enable);
}
- WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0);
+ WREG32(mmGRBM_GFX_INDEX, mmGRBM_GFX_INDEX_DEFAULT);
mutex_unlock(&adev->grbm_idx_mutex);
return 0;
MODULE_FIRMWARE("amdgpu/polaris10_smc_sk.bin");
MODULE_FIRMWARE("amdgpu/polaris11_smc.bin");
MODULE_FIRMWARE("amdgpu/polaris11_smc_sk.bin");
+MODULE_FIRMWARE("amdgpu/polaris12_smc.bin");
/*
* Indirect registers accessor
break;
case CHIP_POLARIS11:
case CHIP_POLARIS10:
+ case CHIP_POLARIS12:
default:
break;
}
case CHIP_TONGA:
case CHIP_POLARIS11:
case CHIP_POLARIS10:
+ case CHIP_POLARIS12:
case CHIP_CARRIZO:
case CHIP_STONEY:
asic_register_table = cz_allowed_read_registers;
adev->pg_flags = 0;
adev->external_rev_id = adev->rev_id + 0x50;
break;
+ case CHIP_POLARIS12:
+ adev->cg_flags = AMD_CG_SUPPORT_UVD_MGCG;
+ adev->pg_flags = 0;
+ adev->external_rev_id = adev->rev_id + 0x64;
+ break;
case CHIP_CARRIZO:
adev->cg_flags = AMD_CG_SUPPORT_UVD_MGCG |
AMD_CG_SUPPORT_GFX_MGCG |
case CHIP_TONGA:
case CHIP_POLARIS10:
case CHIP_POLARIS11:
+ case CHIP_POLARIS12:
vi_common_set_clockgating_state_by_smu(adev, state);
default:
break;
break;
case CHIP_POLARIS11:
case CHIP_POLARIS10:
+ case CHIP_POLARIS12:
amdgpu_ip_block_add(adev, &vi_common_ip_block);
amdgpu_ip_block_add(adev, &gmc_v8_1_ip_block);
amdgpu_ip_block_add(adev, &tonga_ih_ip_block);
#ifndef __AMD_SHARED_H__
#define __AMD_SHARED_H__
-#define AMD_MAX_USEC_TIMEOUT 100000 /* 100 ms */
+#define AMD_MAX_USEC_TIMEOUT 200000 /* 200 ms */
/*
* Supported ASIC types
CHIP_STONEY,
CHIP_POLARIS10,
CHIP_POLARIS11,
+ CHIP_POLARIS12,
CHIP_LAST,
};
cgs_set_clockgating_state(
hwmgr->device,
AMD_IP_BLOCK_TYPE_VCE,
- AMD_CG_STATE_UNGATE);
+ AMD_CG_STATE_GATE);
cgs_set_powergating_state(
hwmgr->device,
AMD_IP_BLOCK_TYPE_VCE,
cgs_set_clockgating_state(
hwmgr->device,
AMD_IP_BLOCK_TYPE_VCE,
- AMD_PG_STATE_GATE);
+ AMD_PG_STATE_UNGATE);
cz_dpm_update_vce_dpm(hwmgr);
cz_enable_disable_vce_dpm(hwmgr, true);
return 0;
cz_hwmgr->vce_dpm.hard_min_clk,
PPSMC_MSG_SetEclkHardMin));
} else {
- /*EPR# 419220 -HW limitation to to */
- cz_hwmgr->vce_dpm.hard_min_clk = hwmgr->vce_arbiter.ecclk;
- smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
- PPSMC_MSG_SetEclkHardMin,
- cz_get_eclk_level(hwmgr,
- cz_hwmgr->vce_dpm.hard_min_clk,
- PPSMC_MSG_SetEclkHardMin));
-
+ /*Program HardMin based on the vce_arbiter.ecclk */
+ if (hwmgr->vce_arbiter.ecclk == 0) {
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_SetEclkHardMin, 0);
+ /* disable ECLK DPM 0. Otherwise VCE could hang if
+ * switching SCLK from DPM 0 to 6/7 */
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_SetEclkSoftMin, 1);
+ } else {
+ cz_hwmgr->vce_dpm.hard_min_clk = hwmgr->vce_arbiter.ecclk;
+ smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
+ PPSMC_MSG_SetEclkHardMin,
+ cz_get_eclk_level(hwmgr,
+ cz_hwmgr->vce_dpm.hard_min_clk,
+ PPSMC_MSG_SetEclkHardMin));
+ }
}
return 0;
}
break;
case CHIP_POLARIS11:
case CHIP_POLARIS10:
+ case CHIP_POLARIS12:
polaris_set_asic_special_caps(hwmgr);
hwmgr->feature_mask &= ~(PP_UVD_HANDSHAKE_MASK);
break;
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_TablelessHardwareInterface);
- if (hwmgr->chip_id == CHIP_POLARIS11)
+ if ((hwmgr->chip_id == CHIP_POLARIS11) || (hwmgr->chip_id == CHIP_POLARIS12))
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_SPLLShutdownSupport);
return 0;
PP_ASSERT_WITH_CODE((result == 0), "DIDT Config failed.", return result);
result = smu7_program_pt_config_registers(hwmgr, DIDTConfig_Polaris10);
PP_ASSERT_WITH_CODE((result == 0), "DIDT Config failed.", return result);
- } else if (hwmgr->chip_id == CHIP_POLARIS11) {
+ } else if ((hwmgr->chip_id == CHIP_POLARIS11) || (hwmgr->chip_id == CHIP_POLARIS12)) {
result = smu7_program_pt_config_registers(hwmgr, GCCACConfig_Polaris11);
PP_ASSERT_WITH_CODE((result == 0), "DIDT Config failed.", return result);
result = smu7_program_pt_config_registers(hwmgr, DIDTConfig_Polaris11);
break;
case CHIP_POLARIS11:
case CHIP_POLARIS10:
+ case CHIP_POLARIS12:
polaris10_smum_init(smumgr);
break;
default:
struct ttm_bo_kmap_obj cache_kmap;
int next_cursor;
bool support_wide_screen;
+ bool DisableP2A;
enum ast_tx_chip tx_chip_type;
u8 dp501_maxclk;
} else
*need_post = false;
+ /* Check P2A Access */
+ ast->DisableP2A = true;
+ data = ast_read32(ast, 0xf004);
+ if (data != 0xFFFFFFFF)
+ ast->DisableP2A = false;
+
/* Check if we support wide screen */
switch (ast->chip) {
case AST1180:
ast->support_wide_screen = true;
else {
ast->support_wide_screen = false;
- /* Read SCU7c (silicon revision register) */
- ast_write32(ast, 0xf004, 0x1e6e0000);
- ast_write32(ast, 0xf000, 0x1);
- data = ast_read32(ast, 0x1207c);
- data &= 0x300;
- if (ast->chip == AST2300 && data == 0x0) /* ast1300 */
- ast->support_wide_screen = true;
- if (ast->chip == AST2400 && data == 0x100) /* ast1400 */
- ast->support_wide_screen = true;
+ if (ast->DisableP2A == false) {
+ /* Read SCU7c (silicon revision register) */
+ ast_write32(ast, 0xf004, 0x1e6e0000);
+ ast_write32(ast, 0xf000, 0x1);
+ data = ast_read32(ast, 0x1207c);
+ data &= 0x300;
+ if (ast->chip == AST2300 && data == 0x0) /* ast1300 */
+ ast->support_wide_screen = true;
+ if (ast->chip == AST2400 && data == 0x100) /* ast1400 */
+ ast->support_wide_screen = true;
+ }
}
break;
}
uint32_t data, data2;
uint32_t denum, num, div, ref_pll;
- ast_write32(ast, 0xf004, 0x1e6e0000);
- ast_write32(ast, 0xf000, 0x1);
-
-
- ast_write32(ast, 0x10000, 0xfc600309);
-
- do {
- if (pci_channel_offline(dev->pdev))
- return -EIO;
- } while (ast_read32(ast, 0x10000) != 0x01);
- data = ast_read32(ast, 0x10004);
-
- if (data & 0x40)
+ if (ast->DisableP2A)
+ {
ast->dram_bus_width = 16;
+ ast->dram_type = AST_DRAM_1Gx16;
+ ast->mclk = 396;
+ }
else
- ast->dram_bus_width = 32;
+ {
+ ast_write32(ast, 0xf004, 0x1e6e0000);
+ ast_write32(ast, 0xf000, 0x1);
+ data = ast_read32(ast, 0x10004);
+
+ if (data & 0x40)
+ ast->dram_bus_width = 16;
+ else
+ ast->dram_bus_width = 32;
+
+ if (ast->chip == AST2300 || ast->chip == AST2400) {
+ switch (data & 0x03) {
+ case 0:
+ ast->dram_type = AST_DRAM_512Mx16;
+ break;
+ default:
+ case 1:
+ ast->dram_type = AST_DRAM_1Gx16;
+ break;
+ case 2:
+ ast->dram_type = AST_DRAM_2Gx16;
+ break;
+ case 3:
+ ast->dram_type = AST_DRAM_4Gx16;
+ break;
+ }
+ } else {
+ switch (data & 0x0c) {
+ case 0:
+ case 4:
+ ast->dram_type = AST_DRAM_512Mx16;
+ break;
+ case 8:
+ if (data & 0x40)
+ ast->dram_type = AST_DRAM_1Gx16;
+ else
+ ast->dram_type = AST_DRAM_512Mx32;
+ break;
+ case 0xc:
+ ast->dram_type = AST_DRAM_1Gx32;
+ break;
+ }
+ }
- if (ast->chip == AST2300 || ast->chip == AST2400) {
- switch (data & 0x03) {
- case 0:
- ast->dram_type = AST_DRAM_512Mx16;
- break;
- default:
- case 1:
- ast->dram_type = AST_DRAM_1Gx16;
- break;
- case 2:
- ast->dram_type = AST_DRAM_2Gx16;
- break;
+ data = ast_read32(ast, 0x10120);
+ data2 = ast_read32(ast, 0x10170);
+ if (data2 & 0x2000)
+ ref_pll = 14318;
+ else
+ ref_pll = 12000;
+
+ denum = data & 0x1f;
+ num = (data & 0x3fe0) >> 5;
+ data = (data & 0xc000) >> 14;
+ switch (data) {
case 3:
- ast->dram_type = AST_DRAM_4Gx16;
- break;
- }
- } else {
- switch (data & 0x0c) {
- case 0:
- case 4:
- ast->dram_type = AST_DRAM_512Mx16;
+ div = 0x4;
break;
- case 8:
- if (data & 0x40)
- ast->dram_type = AST_DRAM_1Gx16;
- else
- ast->dram_type = AST_DRAM_512Mx32;
+ case 2:
+ case 1:
+ div = 0x2;
break;
- case 0xc:
- ast->dram_type = AST_DRAM_1Gx32;
+ default:
+ div = 0x1;
break;
}
+ ast->mclk = ref_pll * (num + 2) / (denum + 2) * (div * 1000);
}
-
- data = ast_read32(ast, 0x10120);
- data2 = ast_read32(ast, 0x10170);
- if (data2 & 0x2000)
- ref_pll = 14318;
- else
- ref_pll = 12000;
-
- denum = data & 0x1f;
- num = (data & 0x3fe0) >> 5;
- data = (data & 0xc000) >> 14;
- switch (data) {
- case 3:
- div = 0x4;
- break;
- case 2:
- case 1:
- div = 0x2;
- break;
- default:
- div = 0x1;
- break;
- }
- ast->mclk = ref_pll * (num + 2) / (denum + 2) * (div * 1000);
return 0;
}
ast_open_key(ast);
ast_set_def_ext_reg(dev);
- if (ast->chip == AST2300 || ast->chip == AST2400)
- ast_init_dram_2300(dev);
- else
- ast_init_dram_reg(dev);
+ if (ast->DisableP2A == false)
+ {
+ if (ast->chip == AST2300 || ast->chip == AST2400)
+ ast_init_dram_2300(dev);
+ else
+ ast_init_dram_reg(dev);
- ast_init_3rdtx(dev);
+ ast_init_3rdtx(dev);
+ }
+ else
+ {
+ if (ast->tx_chip_type != AST_TX_NONE)
+ ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3, 0xcf, 0x80); /* Enable DVO */
+ }
}
/* AST 2300 DRAM settings */
pm_runtime_enable(dev);
+ pm_runtime_get_sync(dev);
phy_power_on(dp->phy);
analogix_dp_init_dp(dp);
goto err_disable_pm_runtime;
}
+ phy_power_off(dp->phy);
+ pm_runtime_put(dev);
+
return 0;
err_disable_pm_runtime:
+
+ phy_power_off(dp->phy);
+ pm_runtime_put(dev);
pm_runtime_disable(dev);
return ret;
This is a KMS driver for emulated cirrus device in qemu.
It is *NOT* intended for real cirrus devices. This requires
the modesetting userspace X.org driver.
+
+ Cirrus is obsolete, the hardware was designed in the 90ies
+ and can't keep up with todays needs. More background:
+ https://www.kraxel.org/blog/2014/10/qemu-using-cirrus-considered-harmful/
+
+ Better alternatives are:
+ - stdvga (DRM_BOCHS, qemu -vga std, default in qemu 2.2+)
+ - qxl (DRM_QXL, qemu -vga qxl, works best with spice)
+ - virtio (DRM_VIRTIO_GPU), qemu -vga virtio)
EXPORT_SYMBOL(drm_atomic_get_crtc_state);
static void set_out_fence_for_crtc(struct drm_atomic_state *state,
- struct drm_crtc *crtc, s64 __user *fence_ptr)
+ struct drm_crtc *crtc, s32 __user *fence_ptr)
{
state->crtcs[drm_crtc_index(crtc)].out_fence_ptr = fence_ptr;
}
-static s64 __user *get_out_fence_for_crtc(struct drm_atomic_state *state,
+static s32 __user *get_out_fence_for_crtc(struct drm_atomic_state *state,
struct drm_crtc *crtc)
{
- s64 __user *fence_ptr;
+ s32 __user *fence_ptr;
fence_ptr = state->crtcs[drm_crtc_index(crtc)].out_fence_ptr;
state->crtcs[drm_crtc_index(crtc)].out_fence_ptr = NULL;
state->color_mgmt_changed |= replaced;
return ret;
} else if (property == config->prop_out_fence_ptr) {
- s64 __user *fence_ptr = u64_to_user_ptr(val);
+ s32 __user *fence_ptr = u64_to_user_ptr(val);
if (!fence_ptr)
return 0;
*/
struct drm_out_fence_state {
- s64 __user *out_fence_ptr;
+ s32 __user *out_fence_ptr;
struct sync_file *sync_file;
int fd;
};
return 0;
for_each_crtc_in_state(state, crtc, crtc_state, i) {
- u64 __user *fence_ptr;
+ s32 __user *fence_ptr;
fence_ptr = get_out_fence_for_crtc(crtc_state->state, crtc);
}
for_each_crtc_in_state(state, crtc, crtc_state, i) {
+ struct drm_pending_vblank_event *event = crtc_state->event;
/*
- * TEST_ONLY and PAGE_FLIP_EVENT are mutually
- * exclusive, if they weren't, this code should be
- * called on success for TEST_ONLY too.
+ * Free the allocated event. drm_atomic_helper_setup_commit
+ * can allocate an event too, so only free it if it's ours
+ * to prevent a double free in drm_atomic_state_clear.
*/
- if (crtc_state->event)
- drm_event_cancel_free(dev, &crtc_state->event->base);
+ if (event && (event->base.fence || event->base.file_priv)) {
+ drm_event_cancel_free(dev, &event->base);
+ crtc_state->event = NULL;
+ }
}
if (!fence_state)
if (!nonblock) {
ret = drm_atomic_helper_wait_for_fences(dev, state, true);
- if (ret)
+ if (ret) {
+ drm_atomic_helper_cleanup_planes(dev, state);
return ret;
+ }
}
/*
funcs = plane->helper_private;
- if (!drm_atomic_helper_framebuffer_changed(dev, state, plane_state->crtc))
- continue;
-
if (funcs->prepare_fb) {
ret = funcs->prepare_fb(plane, plane_state);
if (ret)
if (j >= i)
continue;
- if (!drm_atomic_helper_framebuffer_changed(dev, state, plane_state->crtc))
- continue;
-
funcs = plane->helper_private;
if (funcs->cleanup_fb)
for_each_plane_in_state(old_state, plane, plane_state, i) {
const struct drm_plane_helper_funcs *funcs;
- if (!drm_atomic_helper_framebuffer_changed(dev, old_state, plane_state->crtc))
- continue;
-
funcs = plane->helper_private;
if (funcs->cleanup_fb)
INIT_LIST_HEAD(&connector->probed_modes);
INIT_LIST_HEAD(&connector->modes);
+ mutex_init(&connector->mutex);
connector->edid_blob_ptr = NULL;
connector->status = connector_status_unknown;
connector->funcs->atomic_destroy_state(connector,
connector->state);
+ mutex_destroy(&connector->mutex);
+
memset(connector, 0, sizeof(*connector));
}
EXPORT_SYMBOL(drm_connector_cleanup);
*/
int drm_connector_register(struct drm_connector *connector)
{
- int ret;
+ int ret = 0;
- if (connector->registered)
+ if (!connector->dev->registered)
return 0;
+ mutex_lock(&connector->mutex);
+ if (connector->registered)
+ goto unlock;
+
ret = drm_sysfs_connector_add(connector);
if (ret)
- return ret;
+ goto unlock;
ret = drm_debugfs_connector_add(connector);
if (ret) {
drm_mode_object_register(connector->dev, &connector->base);
connector->registered = true;
- return 0;
+ goto unlock;
err_debugfs:
drm_debugfs_connector_remove(connector);
err_sysfs:
drm_sysfs_connector_remove(connector);
+unlock:
+ mutex_unlock(&connector->mutex);
return ret;
}
EXPORT_SYMBOL(drm_connector_register);
*/
void drm_connector_unregister(struct drm_connector *connector)
{
- if (!connector->registered)
+ mutex_lock(&connector->mutex);
+ if (!connector->registered) {
+ mutex_unlock(&connector->mutex);
return;
+ }
if (connector->funcs->early_unregister)
connector->funcs->early_unregister(connector);
drm_debugfs_connector_remove(connector);
connector->registered = false;
+ mutex_unlock(&connector->mutex);
}
EXPORT_SYMBOL(drm_connector_unregister);
if (ret)
goto err_minors;
+ dev->registered = true;
+
if (dev->driver->load) {
ret = dev->driver->load(dev, flags);
if (ret)
drm_lastclose(dev);
+ dev->registered = false;
+
if (drm_core_check_feature(dev, DRIVER_MODESET))
drm_modeset_unregister_all(dev);
return NULL;
mode->type |= DRM_MODE_TYPE_USERDEF;
+ /* fix up 1368x768: GFT/CVT can't express 1366 width due to alignment */
+ if (cmd->xres == 1366 && mode->hdisplay == 1368) {
+ mode->hdisplay = 1366;
+ mode->hsync_start--;
+ mode->hsync_end--;
+ drm_mode_set_name(mode);
+ }
drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
return mode;
}
}
if (dev->mode_config.delayed_event) {
+ /*
+ * FIXME:
+ *
+ * Use short (1s) delay to handle the initial delayed event.
+ * This delay should not be needed, but Optimus/nouveau will
+ * fail in a mysterious way if the delayed event is handled as
+ * soon as possible like it is done in
+ * drm_helper_probe_single_connector_modes() in case the poll
+ * was enabled before.
+ */
poll = true;
- delay = 0;
+ delay = HZ;
}
if (poll)
struct list_head list;
bool found;
+ /*
+ * XXX: The DRM_MM_SEARCH_BELOW is really a hack to trick
+ * drm_mm into giving out a low IOVA after address space
+ * rollover. This needs a proper fix.
+ */
ret = drm_mm_insert_node_in_range(&mmu->mm, node,
size, 0, mmu->last_iova, ~0UL,
- DRM_MM_SEARCH_DEFAULT);
+ mmu->last_iova ? DRM_MM_SEARCH_DEFAULT : DRM_MM_SEARCH_BELOW);
if (ret != -ENOSPC)
break;
BIT_CLKS_ENABLED,
BIT_IRQS_ENABLED,
BIT_WIN_UPDATED,
- BIT_SUSPENDED
+ BIT_SUSPENDED,
+ BIT_REQUEST_UPDATE
};
struct decon_context {
m->crtc_vsync_end = m->crtc_vsync_start + 1;
}
- decon_set_bits(ctx, DECON_VIDCON0, VIDCON0_ENVID, 0);
-
- /* enable clock gate */
- val = CMU_CLKGAGE_MODE_SFR_F | CMU_CLKGAGE_MODE_MEM_F;
- writel(val, ctx->addr + DECON_CMU);
-
if (ctx->out_type & (IFTYPE_I80 | I80_HW_TRG))
decon_setup_trigger(ctx);
/* window enable */
decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, ~0);
+ set_bit(BIT_REQUEST_UPDATE, &ctx->flags);
}
static void decon_disable_plane(struct exynos_drm_crtc *crtc,
return;
decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, 0);
+ set_bit(BIT_REQUEST_UPDATE, &ctx->flags);
}
static void decon_atomic_flush(struct exynos_drm_crtc *crtc)
for (i = ctx->first_win; i < WINDOWS_NR; i++)
decon_shadow_protect_win(ctx, i, false);
- /* standalone update */
- decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0);
+ if (test_and_clear_bit(BIT_REQUEST_UPDATE, &ctx->flags))
+ decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0);
if (ctx->out_type & IFTYPE_I80)
set_bit(BIT_WIN_UPDATED, &ctx->flags);
#include "i915_drv.h"
#include "gvt.h"
-#define MB_TO_BYTES(mb) ((mb) << 20ULL)
-#define BYTES_TO_MB(b) ((b) >> 20ULL)
-
-#define HOST_LOW_GM_SIZE MB_TO_BYTES(128)
-#define HOST_HIGH_GM_SIZE MB_TO_BYTES(384)
-#define HOST_FENCE 4
-
static int alloc_gm(struct intel_vgpu *vgpu, bool high_gm)
{
struct intel_gvt *gvt = vgpu->gvt;
POSTING_READ(fence_reg_lo);
}
+static void _clear_vgpu_fence(struct intel_vgpu *vgpu)
+{
+ int i;
+
+ for (i = 0; i < vgpu_fence_sz(vgpu); i++)
+ intel_vgpu_write_fence(vgpu, i, 0);
+}
+
static void free_vgpu_fence(struct intel_vgpu *vgpu)
{
struct intel_gvt *gvt = vgpu->gvt;
intel_runtime_pm_get(dev_priv);
mutex_lock(&dev_priv->drm.struct_mutex);
+ _clear_vgpu_fence(vgpu);
for (i = 0; i < vgpu_fence_sz(vgpu); i++) {
reg = vgpu->fence.regs[i];
- intel_vgpu_write_fence(vgpu, i, 0);
list_add_tail(®->link,
&dev_priv->mm.fence_list);
}
continue;
list_del(pos);
vgpu->fence.regs[i] = reg;
- intel_vgpu_write_fence(vgpu, i, 0);
if (++i == vgpu_fence_sz(vgpu))
break;
}
if (i != vgpu_fence_sz(vgpu))
goto out_free_fence;
+ _clear_vgpu_fence(vgpu);
+
mutex_unlock(&dev_priv->drm.struct_mutex);
intel_runtime_pm_put(dev_priv);
return 0;
free_resource(vgpu);
}
+/**
+ * intel_vgpu_reset_resource - reset resource state owned by a vGPU
+ * @vgpu: a vGPU
+ *
+ * This function is used to reset resource state owned by a vGPU.
+ *
+ */
+void intel_vgpu_reset_resource(struct intel_vgpu *vgpu)
+{
+ struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv;
+
+ intel_runtime_pm_get(dev_priv);
+ _clear_vgpu_fence(vgpu);
+ intel_runtime_pm_put(dev_priv);
+}
+
/**
* intel_alloc_vgpu_resource - allocate HW resource for a vGPU
* @vgpu: vGPU
}
return 0;
}
+
+/**
+ * intel_vgpu_init_cfg_space - init vGPU configuration space when create vGPU
+ *
+ * @vgpu: a vGPU
+ * @primary: is the vGPU presented as primary
+ *
+ */
+void intel_vgpu_init_cfg_space(struct intel_vgpu *vgpu,
+ bool primary)
+{
+ struct intel_gvt *gvt = vgpu->gvt;
+ const struct intel_gvt_device_info *info = &gvt->device_info;
+ u16 *gmch_ctl;
+ int i;
+
+ memcpy(vgpu_cfg_space(vgpu), gvt->firmware.cfg_space,
+ info->cfg_space_size);
+
+ if (!primary) {
+ vgpu_cfg_space(vgpu)[PCI_CLASS_DEVICE] =
+ INTEL_GVT_PCI_CLASS_VGA_OTHER;
+ vgpu_cfg_space(vgpu)[PCI_CLASS_PROG] =
+ INTEL_GVT_PCI_CLASS_VGA_OTHER;
+ }
+
+ /* Show guest that there isn't any stolen memory.*/
+ gmch_ctl = (u16 *)(vgpu_cfg_space(vgpu) + INTEL_GVT_PCI_GMCH_CONTROL);
+ *gmch_ctl &= ~(BDW_GMCH_GMS_MASK << BDW_GMCH_GMS_SHIFT);
+
+ intel_vgpu_write_pci_bar(vgpu, PCI_BASE_ADDRESS_2,
+ gvt_aperture_pa_base(gvt), true);
+
+ vgpu_cfg_space(vgpu)[PCI_COMMAND] &= ~(PCI_COMMAND_IO
+ | PCI_COMMAND_MEMORY
+ | PCI_COMMAND_MASTER);
+ /*
+ * Clear the bar upper 32bit and let guest to assign the new value
+ */
+ memset(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_1, 0, 4);
+ memset(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_3, 0, 4);
+ memset(vgpu_cfg_space(vgpu) + INTEL_GVT_PCI_OPREGION, 0, 4);
+
+ for (i = 0; i < INTEL_GVT_MAX_BAR_NUM; i++) {
+ vgpu->cfg_space.bar[i].size = pci_resource_len(
+ gvt->dev_priv->drm.pdev, i * 2);
+ vgpu->cfg_space.bar[i].tracked = false;
+ }
+}
+
+/**
+ * intel_vgpu_reset_cfg_space - reset vGPU configuration space
+ *
+ * @vgpu: a vGPU
+ *
+ */
+void intel_vgpu_reset_cfg_space(struct intel_vgpu *vgpu)
+{
+ u8 cmd = vgpu_cfg_space(vgpu)[PCI_COMMAND];
+ bool primary = vgpu_cfg_space(vgpu)[PCI_CLASS_DEVICE] !=
+ INTEL_GVT_PCI_CLASS_VGA_OTHER;
+
+ if (cmd & PCI_COMMAND_MEMORY) {
+ trap_gttmmio(vgpu, false);
+ map_aperture(vgpu, false);
+ }
+
+ /**
+ * Currently we only do such reset when vGPU is not
+ * owned by any VM, so we simply restore entire cfg
+ * space to default value.
+ */
+ intel_vgpu_init_cfg_space(vgpu, primary);
+}
(s->vgpu->gvt->device_info.gmadr_bytes_in_cmd >> 2)
static unsigned long bypass_scan_mask = 0;
-static bool bypass_batch_buffer_scan = true;
/* ring ALL, type = 0 */
static struct sub_op_bits sub_op_mi[] = {
{
struct intel_gvt *gvt = s->vgpu->gvt;
- if (bypass_batch_buffer_scan)
- return 0;
-
if (IS_BROADWELL(gvt->dev_priv) || IS_SKYLAKE(gvt->dev_priv)) {
/* BDW decides privilege based on address space */
if (cmd_val(s, 0) & (1 << 8))
#define get_desc_from_elsp_dwords(ed, i) \
((struct execlist_ctx_descriptor_format *)&((ed)->data[i * 2]))
-
-#define BATCH_BUFFER_ADDR_MASK ((1UL << 32) - (1U << 2))
-#define BATCH_BUFFER_ADDR_HIGH_MASK ((1UL << 16) - (1U))
-static int set_gma_to_bb_cmd(struct intel_shadow_bb_entry *entry_obj,
- unsigned long add, int gmadr_bytes)
-{
- if (WARN_ON(gmadr_bytes != 4 && gmadr_bytes != 8))
- return -1;
-
- *((u32 *)(entry_obj->bb_start_cmd_va + (1 << 2))) = add &
- BATCH_BUFFER_ADDR_MASK;
- if (gmadr_bytes == 8) {
- *((u32 *)(entry_obj->bb_start_cmd_va + (2 << 2))) =
- add & BATCH_BUFFER_ADDR_HIGH_MASK;
- }
-
- return 0;
-}
-
static void prepare_shadow_batch_buffer(struct intel_vgpu_workload *workload)
{
- int gmadr_bytes = workload->vgpu->gvt->device_info.gmadr_bytes_in_cmd;
+ const int gmadr_bytes = workload->vgpu->gvt->device_info.gmadr_bytes_in_cmd;
+ struct intel_shadow_bb_entry *entry_obj;
/* pin the gem object to ggtt */
- if (!list_empty(&workload->shadow_bb)) {
- struct intel_shadow_bb_entry *entry_obj =
- list_first_entry(&workload->shadow_bb,
- struct intel_shadow_bb_entry,
- list);
- struct intel_shadow_bb_entry *temp;
+ list_for_each_entry(entry_obj, &workload->shadow_bb, list) {
+ struct i915_vma *vma;
- list_for_each_entry_safe(entry_obj, temp, &workload->shadow_bb,
- list) {
- struct i915_vma *vma;
-
- vma = i915_gem_object_ggtt_pin(entry_obj->obj, NULL, 0,
- 4, 0);
- if (IS_ERR(vma)) {
- gvt_err("Cannot pin\n");
- return;
- }
-
- /* FIXME: we are not tracking our pinned VMA leaving it
- * up to the core to fix up the stray pin_count upon
- * free.
- */
-
- /* update the relocate gma with shadow batch buffer*/
- set_gma_to_bb_cmd(entry_obj,
- i915_ggtt_offset(vma),
- gmadr_bytes);
+ vma = i915_gem_object_ggtt_pin(entry_obj->obj, NULL, 0, 4, 0);
+ if (IS_ERR(vma)) {
+ gvt_err("Cannot pin\n");
+ return;
}
+
+ /* FIXME: we are not tracking our pinned VMA leaving it
+ * up to the core to fix up the stray pin_count upon
+ * free.
+ */
+
+ /* update the relocate gma with shadow batch buffer*/
+ entry_obj->bb_start_cmd_va[1] = i915_ggtt_offset(vma);
+ if (gmadr_bytes == 8)
+ entry_obj->bb_start_cmd_va[2] = 0;
}
}
INIT_LIST_HEAD(&vgpu->workload_q_head[i]);
}
- vgpu->workloads = kmem_cache_create("gvt-g vgpu workload",
+ vgpu->workloads = kmem_cache_create("gvt-g_vgpu_workload",
sizeof(struct intel_vgpu_workload), 0,
SLAB_HWCACHE_ALIGN,
NULL);
static u64 read_pte64(struct drm_i915_private *dev_priv, unsigned long index)
{
void __iomem *addr = (gen8_pte_t __iomem *)dev_priv->ggtt.gsm + index;
- u64 pte;
-#ifdef readq
- pte = readq(addr);
-#else
- pte = ioread32(addr);
- pte |= (u64)ioread32(addr + 4) << 32;
-#endif
- return pte;
+ return readq(addr);
}
static void write_pte64(struct drm_i915_private *dev_priv,
{
void __iomem *addr = (gen8_pte_t __iomem *)dev_priv->ggtt.gsm + index;
-#ifdef writeq
writeq(pte, addr);
-#else
- iowrite32((u32)pte, addr);
- iowrite32(pte >> 32, addr + 4);
-#endif
+
I915_WRITE(GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN);
POSTING_READ(GFX_FLSH_CNTL_GEN6);
}
info->gtt_entry_size;
mem = kzalloc(mm->has_shadow_page_table ?
mm->page_table_entry_size * 2
- : mm->page_table_entry_size,
- GFP_ATOMIC);
+ : mm->page_table_entry_size, GFP_KERNEL);
if (!mem)
return -ENOMEM;
mm->virtual_page_table = mem;
struct intel_vgpu_mm *mm;
int ret;
- mm = kzalloc(sizeof(*mm), GFP_ATOMIC);
+ mm = kzalloc(sizeof(*mm), GFP_KERNEL);
if (!mm) {
ret = -ENOMEM;
goto fail;
struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops;
int page_entry_num = GTT_PAGE_SIZE >>
vgpu->gvt->device_info.gtt_entry_size_shift;
- struct page *scratch_pt;
+ void *scratch_pt;
unsigned long mfn;
int i;
- void *p;
if (WARN_ON(type < GTT_TYPE_PPGTT_PTE_PT || type >= GTT_TYPE_MAX))
return -EINVAL;
- scratch_pt = alloc_page(GFP_KERNEL | GFP_ATOMIC | __GFP_ZERO);
+ scratch_pt = (void *)get_zeroed_page(GFP_KERNEL);
if (!scratch_pt) {
gvt_err("fail to allocate scratch page\n");
return -ENOMEM;
}
- p = kmap_atomic(scratch_pt);
- mfn = intel_gvt_hypervisor_virt_to_mfn(p);
+ mfn = intel_gvt_hypervisor_virt_to_mfn(scratch_pt);
if (mfn == INTEL_GVT_INVALID_ADDR) {
- gvt_err("fail to translate vaddr:0x%llx\n", (u64)p);
- kunmap_atomic(p);
- __free_page(scratch_pt);
+ gvt_err("fail to translate vaddr:0x%lx\n", (unsigned long)scratch_pt);
+ free_page((unsigned long)scratch_pt);
return -EFAULT;
}
gtt->scratch_pt[type].page_mfn = mfn;
- gtt->scratch_pt[type].page = scratch_pt;
+ gtt->scratch_pt[type].page = virt_to_page(scratch_pt);
gvt_dbg_mm("vgpu%d create scratch_pt: type %d mfn=0x%lx\n",
vgpu->id, type, mfn);
* scratch_pt[type] indicate the scratch pt/scratch page used by the
* 'type' pt.
* e.g. scratch_pt[GTT_TYPE_PPGTT_PDE_PT] is used by
- * GTT_TYPE_PPGTT_PDE_PT level pt, that means this scatch_pt it self
+ * GTT_TYPE_PPGTT_PDE_PT level pt, that means this scratch_pt it self
* is GTT_TYPE_PPGTT_PTE_PT, and full filled by scratch page mfn.
*/
if (type > GTT_TYPE_PPGTT_PTE_PT && type < GTT_TYPE_MAX) {
se.val64 |= PPAT_CACHED_INDEX;
for (i = 0; i < page_entry_num; i++)
- ops->set_entry(p, &se, i, false, 0, vgpu);
+ ops->set_entry(scratch_pt, &se, i, false, 0, vgpu);
}
- kunmap_atomic(p);
-
return 0;
}
int intel_gvt_init_gtt(struct intel_gvt *gvt)
{
int ret;
- void *page_addr;
+ void *page;
gvt_dbg_core("init gtt\n");
return -ENODEV;
}
- gvt->gtt.scratch_ggtt_page =
- alloc_page(GFP_KERNEL | GFP_ATOMIC | __GFP_ZERO);
- if (!gvt->gtt.scratch_ggtt_page) {
+ page = (void *)get_zeroed_page(GFP_KERNEL);
+ if (!page) {
gvt_err("fail to allocate scratch ggtt page\n");
return -ENOMEM;
}
+ gvt->gtt.scratch_ggtt_page = virt_to_page(page);
- page_addr = page_address(gvt->gtt.scratch_ggtt_page);
-
- gvt->gtt.scratch_ggtt_mfn =
- intel_gvt_hypervisor_virt_to_mfn(page_addr);
+ gvt->gtt.scratch_ggtt_mfn = intel_gvt_hypervisor_virt_to_mfn(page);
if (gvt->gtt.scratch_ggtt_mfn == INTEL_GVT_INVALID_ADDR) {
gvt_err("fail to translate scratch ggtt page\n");
__free_page(gvt->gtt.scratch_ggtt_page);
for (offset = 0; offset < num_entries; offset++)
ops->set_entry(NULL, &e, index + offset, false, 0, vgpu);
}
+
+/**
+ * intel_vgpu_reset_gtt - reset the all GTT related status
+ * @vgpu: a vGPU
+ * @dmlr: true for vGPU Device Model Level Reset, false for GT Reset
+ *
+ * This function is called from vfio core to reset reset all
+ * GTT related status, including GGTT, PPGTT, scratch page.
+ *
+ */
+void intel_vgpu_reset_gtt(struct intel_vgpu *vgpu, bool dmlr)
+{
+ int i;
+
+ ppgtt_free_all_shadow_page(vgpu);
+ if (!dmlr)
+ return;
+
+ intel_vgpu_reset_ggtt(vgpu);
+
+ /* clear scratch page for security */
+ for (i = GTT_TYPE_PPGTT_PTE_PT; i < GTT_TYPE_MAX; i++) {
+ if (vgpu->gtt.scratch_pt[i].page != NULL)
+ memset(page_address(vgpu->gtt.scratch_pt[i].page),
+ 0, PAGE_SIZE);
+ }
+}
void intel_vgpu_reset_ggtt(struct intel_vgpu *vgpu);
extern int intel_gvt_init_gtt(struct intel_gvt *gvt);
+extern void intel_vgpu_reset_gtt(struct intel_vgpu *vgpu, bool dmlr);
extern void intel_gvt_clean_gtt(struct intel_gvt *gvt);
extern struct intel_vgpu_mm *intel_gvt_find_ppgtt_mm(struct intel_vgpu *vgpu,
intel_gvt_hypervisor_host_exit(&dev_priv->drm.pdev->dev, gvt);
intel_gvt_clean_vgpu_types(gvt);
+ idr_destroy(&gvt->vgpu_idr);
+
kfree(dev_priv->gvt);
dev_priv->gvt = NULL;
}
gvt_dbg_core("init gvt device\n");
+ idr_init(&gvt->vgpu_idr);
+
mutex_init(&gvt->lock);
gvt->dev_priv = dev_priv;
ret = intel_gvt_setup_mmio_info(gvt);
if (ret)
- return ret;
+ goto out_clean_idr;
ret = intel_gvt_load_firmware(gvt);
if (ret)
intel_gvt_free_firmware(gvt);
out_clean_mmio_info:
intel_gvt_clean_mmio_info(gvt);
+out_clean_idr:
+ idr_destroy(&gvt->vgpu_idr);
kfree(gvt);
return ret;
}
int intel_vgpu_alloc_resource(struct intel_vgpu *vgpu,
struct intel_vgpu_creation_params *param);
+void intel_vgpu_reset_resource(struct intel_vgpu *vgpu);
void intel_vgpu_free_resource(struct intel_vgpu *vgpu);
void intel_vgpu_write_fence(struct intel_vgpu *vgpu,
u32 fence, u64 value);
struct intel_vgpu *intel_gvt_create_vgpu(struct intel_gvt *gvt,
struct intel_vgpu_type *type);
void intel_gvt_destroy_vgpu(struct intel_vgpu *vgpu);
+void intel_gvt_reset_vgpu_locked(struct intel_vgpu *vgpu, bool dmlr,
+ unsigned int engine_mask);
void intel_gvt_reset_vgpu(struct intel_vgpu *vgpu);
int intel_gvt_ggtt_h2g_index(struct intel_vgpu *vgpu, unsigned long h_index,
unsigned long *g_index);
+void intel_vgpu_init_cfg_space(struct intel_vgpu *vgpu,
+ bool primary);
+void intel_vgpu_reset_cfg_space(struct intel_vgpu *vgpu);
+
int intel_vgpu_emulate_cfg_read(struct intel_vgpu *vgpu, unsigned int offset,
void *p_data, unsigned int bytes);
int intel_vgpu_init_opregion(struct intel_vgpu *vgpu, u32 gpa);
int intel_vgpu_emulate_opregion_request(struct intel_vgpu *vgpu, u32 swsci);
-int setup_vgpu_mmio(struct intel_vgpu *vgpu);
void populate_pvinfo_page(struct intel_vgpu *vgpu);
struct intel_gvt_ops {
static int new_mmio_info(struct intel_gvt *gvt,
u32 offset, u32 flags, u32 size,
u32 addr_mask, u32 ro_mask, u32 device,
- void *read, void *write)
+ int (*read)(struct intel_vgpu *, unsigned int, void *, unsigned int),
+ int (*write)(struct intel_vgpu *, unsigned int, void *, unsigned int))
{
struct intel_gvt_mmio_info *info, *p;
u32 start, end, i;
default:
/*should not hit here*/
gvt_err("invalid forcewake offset 0x%x\n", offset);
- return 1;
+ return -EINVAL;
}
} else {
ack_reg_offset = FORCEWAKE_ACK_HSW_REG;
return 0;
}
-static int handle_device_reset(struct intel_vgpu *vgpu, unsigned int offset,
- void *p_data, unsigned int bytes, unsigned long bitmap)
-{
- struct intel_gvt_workload_scheduler *scheduler =
- &vgpu->gvt->scheduler;
-
- vgpu->resetting = true;
-
- intel_vgpu_stop_schedule(vgpu);
- /*
- * The current_vgpu will set to NULL after stopping the
- * scheduler when the reset is triggered by current vgpu.
- */
- if (scheduler->current_vgpu == NULL) {
- mutex_unlock(&vgpu->gvt->lock);
- intel_gvt_wait_vgpu_idle(vgpu);
- mutex_lock(&vgpu->gvt->lock);
- }
-
- intel_vgpu_reset_execlist(vgpu, bitmap);
-
- /* full GPU reset */
- if (bitmap == 0xff) {
- mutex_unlock(&vgpu->gvt->lock);
- intel_vgpu_clean_gtt(vgpu);
- mutex_lock(&vgpu->gvt->lock);
- setup_vgpu_mmio(vgpu);
- populate_pvinfo_page(vgpu);
- intel_vgpu_init_gtt(vgpu);
- }
-
- vgpu->resetting = false;
-
- return 0;
-}
-
static int gdrst_mmio_write(struct intel_vgpu *vgpu, unsigned int offset,
- void *p_data, unsigned int bytes)
+ void *p_data, unsigned int bytes)
{
+ unsigned int engine_mask = 0;
u32 data;
- u64 bitmap = 0;
write_vreg(vgpu, offset, p_data, bytes);
data = vgpu_vreg(vgpu, offset);
if (data & GEN6_GRDOM_FULL) {
gvt_dbg_mmio("vgpu%d: request full GPU reset\n", vgpu->id);
- bitmap = 0xff;
- }
- if (data & GEN6_GRDOM_RENDER) {
- gvt_dbg_mmio("vgpu%d: request RCS reset\n", vgpu->id);
- bitmap |= (1 << RCS);
- }
- if (data & GEN6_GRDOM_MEDIA) {
- gvt_dbg_mmio("vgpu%d: request VCS reset\n", vgpu->id);
- bitmap |= (1 << VCS);
- }
- if (data & GEN6_GRDOM_BLT) {
- gvt_dbg_mmio("vgpu%d: request BCS Reset\n", vgpu->id);
- bitmap |= (1 << BCS);
- }
- if (data & GEN6_GRDOM_VECS) {
- gvt_dbg_mmio("vgpu%d: request VECS Reset\n", vgpu->id);
- bitmap |= (1 << VECS);
- }
- if (data & GEN8_GRDOM_MEDIA2) {
- gvt_dbg_mmio("vgpu%d: request VCS2 Reset\n", vgpu->id);
- if (HAS_BSD2(vgpu->gvt->dev_priv))
- bitmap |= (1 << VCS2);
+ engine_mask = ALL_ENGINES;
+ } else {
+ if (data & GEN6_GRDOM_RENDER) {
+ gvt_dbg_mmio("vgpu%d: request RCS reset\n", vgpu->id);
+ engine_mask |= (1 << RCS);
+ }
+ if (data & GEN6_GRDOM_MEDIA) {
+ gvt_dbg_mmio("vgpu%d: request VCS reset\n", vgpu->id);
+ engine_mask |= (1 << VCS);
+ }
+ if (data & GEN6_GRDOM_BLT) {
+ gvt_dbg_mmio("vgpu%d: request BCS Reset\n", vgpu->id);
+ engine_mask |= (1 << BCS);
+ }
+ if (data & GEN6_GRDOM_VECS) {
+ gvt_dbg_mmio("vgpu%d: request VECS Reset\n", vgpu->id);
+ engine_mask |= (1 << VECS);
+ }
+ if (data & GEN8_GRDOM_MEDIA2) {
+ gvt_dbg_mmio("vgpu%d: request VCS2 Reset\n", vgpu->id);
+ if (HAS_BSD2(vgpu->gvt->dev_priv))
+ engine_mask |= (1 << VCS2);
+ }
}
- return handle_device_reset(vgpu, offset, p_data, bytes, bitmap);
+
+ intel_gvt_reset_vgpu_locked(vgpu, false, engine_mask);
+
+ return 0;
}
static int gmbus_mmio_read(struct intel_vgpu *vgpu, unsigned int offset,
return 0;
}
-static bool sbi_ctl_mmio_write(struct intel_vgpu *vgpu, unsigned int offset,
+static int sbi_ctl_mmio_write(struct intel_vgpu *vgpu, unsigned int offset,
void *p_data, unsigned int bytes)
{
u32 data;
static int gvt_reg_tlb_control_handler(struct intel_vgpu *vgpu,
unsigned int offset, void *p_data, unsigned int bytes)
{
- int rc = 0;
unsigned int id = 0;
write_vreg(vgpu, offset, p_data, bytes);
id = VECS;
break;
default:
- rc = -EINVAL;
- break;
+ return -EINVAL;
}
set_bit(id, (void *)vgpu->tlb_handle_pending);
- return rc;
+ return 0;
}
static int ring_reset_ctl_write(struct intel_vgpu *vgpu,
return NULL;
}
-static ssize_t available_instance_show(struct kobject *kobj, struct device *dev,
- char *buf)
+static ssize_t available_instances_show(struct kobject *kobj,
+ struct device *dev, char *buf)
{
struct intel_vgpu_type *type;
unsigned int num = 0;
type->fence);
}
-static MDEV_TYPE_ATTR_RO(available_instance);
+static MDEV_TYPE_ATTR_RO(available_instances);
static MDEV_TYPE_ATTR_RO(device_api);
static MDEV_TYPE_ATTR_RO(description);
static struct attribute *type_attrs[] = {
- &mdev_type_attr_available_instance.attr,
+ &mdev_type_attr_available_instances.attr,
&mdev_type_attr_device_api.attr,
&mdev_type_attr_description.attr,
NULL,
struct intel_vgpu_type *type;
struct device *pdev;
void *gvt;
+ int ret;
pdev = mdev_parent_dev(mdev);
gvt = kdev_to_i915(pdev)->gvt;
if (!type) {
gvt_err("failed to find type %s to create\n",
kobject_name(kobj));
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
vgpu = intel_gvt_ops->vgpu_create(gvt, type);
if (IS_ERR_OR_NULL(vgpu)) {
- gvt_err("create intel vgpu failed\n");
- return -EINVAL;
+ ret = vgpu == NULL ? -EFAULT : PTR_ERR(vgpu);
+ gvt_err("failed to create intel vgpu: %d\n", ret);
+ goto out;
}
INIT_WORK(&vgpu->vdev.release_work, intel_vgpu_release_work);
gvt_dbg_core("intel_vgpu_create succeeded for mdev: %s\n",
dev_name(mdev_dev(mdev)));
- return 0;
+ ret = 0;
+
+out:
+ return ret;
}
static int intel_vgpu_remove(struct mdev_device *mdev)
if (WARN_ON(!reg_is_mmio(gvt, offset + bytes - 1)))
goto err;
- mmio = intel_gvt_find_mmio_info(gvt, rounddown(offset, 4));
- if (!mmio && !vgpu->mmio.disable_warn_untrack) {
- gvt_err("vgpu%d: read untracked MMIO %x len %d val %x\n",
- vgpu->id, offset, bytes, *(u32 *)p_data);
-
- if (offset == 0x206c) {
- gvt_err("------------------------------------------\n");
- gvt_err("vgpu%d: likely triggers a gfx reset\n",
- vgpu->id);
- gvt_err("------------------------------------------\n");
- vgpu->mmio.disable_warn_untrack = true;
- }
- }
-
if (!intel_gvt_mmio_is_unalign(gvt, offset)) {
if (WARN_ON(!IS_ALIGNED(offset, bytes)))
goto err;
}
+ mmio = intel_gvt_find_mmio_info(gvt, rounddown(offset, 4));
if (mmio) {
if (!intel_gvt_mmio_is_unalign(gvt, mmio->offset)) {
if (WARN_ON(offset + bytes > mmio->offset + mmio->size))
goto err;
}
ret = mmio->read(vgpu, offset, p_data, bytes);
- } else
+ } else {
ret = intel_vgpu_default_mmio_read(vgpu, offset, p_data, bytes);
+ if (!vgpu->mmio.disable_warn_untrack) {
+ gvt_err("vgpu%d: read untracked MMIO %x(%dB) val %x\n",
+ vgpu->id, offset, bytes, *(u32 *)p_data);
+
+ if (offset == 0x206c) {
+ gvt_err("------------------------------------------\n");
+ gvt_err("vgpu%d: likely triggers a gfx reset\n",
+ vgpu->id);
+ gvt_err("------------------------------------------\n");
+ vgpu->mmio.disable_warn_untrack = true;
+ }
+ }
+ }
+
if (ret)
goto err;
mutex_unlock(&gvt->lock);
return ret;
}
+
+
+/**
+ * intel_vgpu_reset_mmio - reset virtual MMIO space
+ * @vgpu: a vGPU
+ *
+ */
+void intel_vgpu_reset_mmio(struct intel_vgpu *vgpu)
+{
+ struct intel_gvt *gvt = vgpu->gvt;
+ const struct intel_gvt_device_info *info = &gvt->device_info;
+
+ memcpy(vgpu->mmio.vreg, gvt->firmware.mmio, info->mmio_size);
+ memcpy(vgpu->mmio.sreg, gvt->firmware.mmio, info->mmio_size);
+
+ vgpu_vreg(vgpu, GEN6_GT_THREAD_STATUS_REG) = 0;
+
+ /* set the bit 0:2(Core C-State ) to C0 */
+ vgpu_vreg(vgpu, GEN6_GT_CORE_STATUS) = 0;
+}
+
+/**
+ * intel_vgpu_init_mmio - init MMIO space
+ * @vgpu: a vGPU
+ *
+ * Returns:
+ * Zero on success, negative error code if failed
+ */
+int intel_vgpu_init_mmio(struct intel_vgpu *vgpu)
+{
+ const struct intel_gvt_device_info *info = &vgpu->gvt->device_info;
+
+ vgpu->mmio.vreg = vzalloc(info->mmio_size * 2);
+ if (!vgpu->mmio.vreg)
+ return -ENOMEM;
+
+ vgpu->mmio.sreg = vgpu->mmio.vreg + info->mmio_size;
+
+ intel_vgpu_reset_mmio(vgpu);
+
+ return 0;
+}
+
+/**
+ * intel_vgpu_clean_mmio - clean MMIO space
+ * @vgpu: a vGPU
+ *
+ */
+void intel_vgpu_clean_mmio(struct intel_vgpu *vgpu)
+{
+ vfree(vgpu->mmio.vreg);
+ vgpu->mmio.vreg = vgpu->mmio.sreg = NULL;
+}
*offset; \
})
+int intel_vgpu_init_mmio(struct intel_vgpu *vgpu);
+void intel_vgpu_reset_mmio(struct intel_vgpu *vgpu);
+void intel_vgpu_clean_mmio(struct intel_vgpu *vgpu);
+
int intel_vgpu_gpa_to_mmio_offset(struct intel_vgpu *vgpu, u64 gpa);
int intel_vgpu_emulate_mmio_read(struct intel_vgpu *vgpu, u64 pa,
vgpu->id))
return -EINVAL;
- vgpu_opregion(vgpu)->va = (void *)__get_free_pages(GFP_ATOMIC |
- GFP_DMA32 | __GFP_ZERO,
- INTEL_GVT_OPREGION_PORDER);
+ vgpu_opregion(vgpu)->va = (void *)__get_free_pages(GFP_KERNEL |
+ __GFP_ZERO,
+ get_order(INTEL_GVT_OPREGION_SIZE));
if (!vgpu_opregion(vgpu)->va)
return -ENOMEM;
if (intel_gvt_host.hypervisor_type == INTEL_GVT_HYPERVISOR_XEN) {
map_vgpu_opregion(vgpu, false);
free_pages((unsigned long)vgpu_opregion(vgpu)->va,
- INTEL_GVT_OPREGION_PORDER);
+ get_order(INTEL_GVT_OPREGION_SIZE));
vgpu_opregion(vgpu)->va = NULL;
}
#define INTEL_GVT_OPREGION_PARM 0x204
#define INTEL_GVT_OPREGION_PAGES 2
-#define INTEL_GVT_OPREGION_PORDER 1
-#define INTEL_GVT_OPREGION_SIZE (2 * 4096)
+#define INTEL_GVT_OPREGION_SIZE (INTEL_GVT_OPREGION_PAGES * PAGE_SIZE)
#define VGT_SPRSTRIDE(pipe) _PIPE(pipe, _SPRA_STRIDE, _PLANE_STRIDE_2_B)
{
struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
struct intel_vgpu_workload *workload;
+ struct intel_vgpu *vgpu;
int event;
mutex_lock(&gvt->lock);
workload = scheduler->current_workload[ring_id];
+ vgpu = workload->vgpu;
- if (!workload->status && !workload->vgpu->resetting) {
+ if (!workload->status && !vgpu->resetting) {
wait_event(workload->shadow_ctx_status_wq,
!atomic_read(&workload->shadow_ctx_active));
for_each_set_bit(event, workload->pending_events,
INTEL_GVT_EVENT_MAX)
- intel_vgpu_trigger_virtual_event(workload->vgpu,
- event);
+ intel_vgpu_trigger_virtual_event(vgpu, event);
}
gvt_dbg_sched("ring id %d complete workload %p status %d\n",
scheduler->current_workload[ring_id] = NULL;
- atomic_dec(&workload->vgpu->running_workload_num);
-
list_del_init(&workload->list);
workload->complete(workload);
+ atomic_dec(&vgpu->running_workload_num);
wake_up(&scheduler->workload_complete_wq);
mutex_unlock(&gvt->lock);
}
gvt_dbg_sched("will complete workload %p\n, status: %d\n",
workload, workload->status);
- complete_current_workload(gvt, ring_id);
-
if (workload->req)
i915_gem_request_put(fetch_and_zero(&workload->req));
+ complete_current_workload(gvt, ring_id);
+
if (need_force_wake)
intel_uncore_forcewake_put(gvt->dev_priv,
FORCEWAKE_ALL);
struct drm_i915_gem_object *obj;
void *va;
unsigned long len;
- void *bb_start_cmd_va;
+ u32 *bb_start_cmd_va;
};
#define workload_q_head(vgpu, ring_id) \
#include "gvt.h"
#include "i915_pvinfo.h"
-static void clean_vgpu_mmio(struct intel_vgpu *vgpu)
-{
- vfree(vgpu->mmio.vreg);
- vgpu->mmio.vreg = vgpu->mmio.sreg = NULL;
-}
-
-int setup_vgpu_mmio(struct intel_vgpu *vgpu)
-{
- struct intel_gvt *gvt = vgpu->gvt;
- const struct intel_gvt_device_info *info = &gvt->device_info;
-
- if (vgpu->mmio.vreg)
- memset(vgpu->mmio.vreg, 0, info->mmio_size * 2);
- else {
- vgpu->mmio.vreg = vzalloc(info->mmio_size * 2);
- if (!vgpu->mmio.vreg)
- return -ENOMEM;
- }
-
- vgpu->mmio.sreg = vgpu->mmio.vreg + info->mmio_size;
-
- memcpy(vgpu->mmio.vreg, gvt->firmware.mmio, info->mmio_size);
- memcpy(vgpu->mmio.sreg, gvt->firmware.mmio, info->mmio_size);
-
- vgpu_vreg(vgpu, GEN6_GT_THREAD_STATUS_REG) = 0;
-
- /* set the bit 0:2(Core C-State ) to C0 */
- vgpu_vreg(vgpu, GEN6_GT_CORE_STATUS) = 0;
- return 0;
-}
-
-static void setup_vgpu_cfg_space(struct intel_vgpu *vgpu,
- struct intel_vgpu_creation_params *param)
-{
- struct intel_gvt *gvt = vgpu->gvt;
- const struct intel_gvt_device_info *info = &gvt->device_info;
- u16 *gmch_ctl;
- int i;
-
- memcpy(vgpu_cfg_space(vgpu), gvt->firmware.cfg_space,
- info->cfg_space_size);
-
- if (!param->primary) {
- vgpu_cfg_space(vgpu)[PCI_CLASS_DEVICE] =
- INTEL_GVT_PCI_CLASS_VGA_OTHER;
- vgpu_cfg_space(vgpu)[PCI_CLASS_PROG] =
- INTEL_GVT_PCI_CLASS_VGA_OTHER;
- }
-
- /* Show guest that there isn't any stolen memory.*/
- gmch_ctl = (u16 *)(vgpu_cfg_space(vgpu) + INTEL_GVT_PCI_GMCH_CONTROL);
- *gmch_ctl &= ~(BDW_GMCH_GMS_MASK << BDW_GMCH_GMS_SHIFT);
-
- intel_vgpu_write_pci_bar(vgpu, PCI_BASE_ADDRESS_2,
- gvt_aperture_pa_base(gvt), true);
-
- vgpu_cfg_space(vgpu)[PCI_COMMAND] &= ~(PCI_COMMAND_IO
- | PCI_COMMAND_MEMORY
- | PCI_COMMAND_MASTER);
- /*
- * Clear the bar upper 32bit and let guest to assign the new value
- */
- memset(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_1, 0, 4);
- memset(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_3, 0, 4);
- memset(vgpu_cfg_space(vgpu) + INTEL_GVT_PCI_OPREGION, 0, 4);
-
- for (i = 0; i < INTEL_GVT_MAX_BAR_NUM; i++) {
- vgpu->cfg_space.bar[i].size = pci_resource_len(
- gvt->dev_priv->drm.pdev, i * 2);
- vgpu->cfg_space.bar[i].tracked = false;
- }
-}
-
void populate_pvinfo_page(struct intel_vgpu *vgpu)
{
/* setup the ballooning information */
if (low_avail / min_low == 0)
break;
gvt->types[i].low_gm_size = min_low;
- gvt->types[i].high_gm_size = 3 * gvt->types[i].low_gm_size;
+ gvt->types[i].high_gm_size = max((min_low<<3), MB_TO_BYTES(384U));
gvt->types[i].fence = 4;
gvt->types[i].max_instance = low_avail / min_low;
gvt->types[i].avail_instance = gvt->types[i].max_instance;
*/
low_gm_avail = MB_TO_BYTES(256) - HOST_LOW_GM_SIZE -
gvt->gm.vgpu_allocated_low_gm_size;
- high_gm_avail = MB_TO_BYTES(256) * 3 - HOST_HIGH_GM_SIZE -
+ high_gm_avail = MB_TO_BYTES(256) * 8UL - HOST_HIGH_GM_SIZE -
gvt->gm.vgpu_allocated_high_gm_size;
fence_avail = gvt_fence_sz(gvt) - HOST_FENCE -
gvt->fence.vgpu_allocated_fence_num;
intel_vgpu_clean_gtt(vgpu);
intel_gvt_hypervisor_detach_vgpu(vgpu);
intel_vgpu_free_resource(vgpu);
- clean_vgpu_mmio(vgpu);
+ intel_vgpu_clean_mmio(vgpu);
vfree(vgpu);
intel_gvt_update_vgpu_types(gvt);
vgpu->gvt = gvt;
bitmap_zero(vgpu->tlb_handle_pending, I915_NUM_ENGINES);
- setup_vgpu_cfg_space(vgpu, param);
+ intel_vgpu_init_cfg_space(vgpu, param->primary);
- ret = setup_vgpu_mmio(vgpu);
+ ret = intel_vgpu_init_mmio(vgpu);
if (ret)
- goto out_free_vgpu;
+ goto out_clean_idr;
ret = intel_vgpu_alloc_resource(vgpu, param);
if (ret)
out_clean_vgpu_resource:
intel_vgpu_free_resource(vgpu);
out_clean_vgpu_mmio:
- clean_vgpu_mmio(vgpu);
+ intel_vgpu_clean_mmio(vgpu);
+out_clean_idr:
+ idr_remove(&gvt->vgpu_idr, vgpu->id);
out_free_vgpu:
vfree(vgpu);
mutex_unlock(&gvt->lock);
}
/**
- * intel_gvt_reset_vgpu - reset a virtual GPU
+ * intel_gvt_reset_vgpu_locked - reset a virtual GPU by DMLR or GT reset
+ * @vgpu: virtual GPU
+ * @dmlr: vGPU Device Model Level Reset or GT Reset
+ * @engine_mask: engines to reset for GT reset
+ *
+ * This function is called when user wants to reset a virtual GPU through
+ * device model reset or GT reset. The caller should hold the gvt lock.
+ *
+ * vGPU Device Model Level Reset (DMLR) simulates the PCI level reset to reset
+ * the whole vGPU to default state as when it is created. This vGPU function
+ * is required both for functionary and security concerns.The ultimate goal
+ * of vGPU FLR is that reuse a vGPU instance by virtual machines. When we
+ * assign a vGPU to a virtual machine we must isse such reset first.
+ *
+ * Full GT Reset and Per-Engine GT Reset are soft reset flow for GPU engines
+ * (Render, Blitter, Video, Video Enhancement). It is defined by GPU Spec.
+ * Unlike the FLR, GT reset only reset particular resource of a vGPU per
+ * the reset request. Guest driver can issue a GT reset by programming the
+ * virtual GDRST register to reset specific virtual GPU engine or all
+ * engines.
+ *
+ * The parameter dev_level is to identify if we will do DMLR or GT reset.
+ * The parameter engine_mask is to specific the engines that need to be
+ * resetted. If value ALL_ENGINES is given for engine_mask, it means
+ * the caller requests a full GT reset that we will reset all virtual
+ * GPU engines. For FLR, engine_mask is ignored.
+ */
+void intel_gvt_reset_vgpu_locked(struct intel_vgpu *vgpu, bool dmlr,
+ unsigned int engine_mask)
+{
+ struct intel_gvt *gvt = vgpu->gvt;
+ struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler;
+
+ gvt_dbg_core("------------------------------------------\n");
+ gvt_dbg_core("resseting vgpu%d, dmlr %d, engine_mask %08x\n",
+ vgpu->id, dmlr, engine_mask);
+ vgpu->resetting = true;
+
+ intel_vgpu_stop_schedule(vgpu);
+ /*
+ * The current_vgpu will set to NULL after stopping the
+ * scheduler when the reset is triggered by current vgpu.
+ */
+ if (scheduler->current_vgpu == NULL) {
+ mutex_unlock(&gvt->lock);
+ intel_gvt_wait_vgpu_idle(vgpu);
+ mutex_lock(&gvt->lock);
+ }
+
+ intel_vgpu_reset_execlist(vgpu, dmlr ? ALL_ENGINES : engine_mask);
+
+ /* full GPU reset or device model level reset */
+ if (engine_mask == ALL_ENGINES || dmlr) {
+ intel_vgpu_reset_gtt(vgpu, dmlr);
+ intel_vgpu_reset_resource(vgpu);
+ intel_vgpu_reset_mmio(vgpu);
+ populate_pvinfo_page(vgpu);
+
+ if (dmlr)
+ intel_vgpu_reset_cfg_space(vgpu);
+ }
+
+ vgpu->resetting = false;
+ gvt_dbg_core("reset vgpu%d done\n", vgpu->id);
+ gvt_dbg_core("------------------------------------------\n");
+}
+
+/**
+ * intel_gvt_reset_vgpu - reset a virtual GPU (Function Level)
* @vgpu: virtual GPU
*
* This function is called when user wants to reset a virtual GPU.
*/
void intel_gvt_reset_vgpu(struct intel_vgpu *vgpu)
{
+ mutex_lock(&vgpu->gvt->lock);
+ intel_gvt_reset_vgpu_locked(vgpu, true, 0);
+ mutex_unlock(&vgpu->gvt->lock);
}
assert_forcewakes_inactive(dev_priv);
- if (!IS_VALLEYVIEW(dev_priv) || !IS_CHERRYVIEW(dev_priv))
+ if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv))
intel_hpd_poll_init(dev_priv);
DRM_DEBUG_KMS("Device suspended\n");
struct work_struct underrun_work;
struct intel_fbc_state_cache {
+ struct i915_vma *vma;
+
struct {
unsigned int mode_flags;
uint32_t hsw_bdw_pixel_rate;
} plane;
struct {
- u64 ilk_ggtt_offset;
uint32_t pixel_format;
unsigned int stride;
- int fence_reg;
- unsigned int tiling_mode;
} fb;
} state_cache;
struct intel_fbc_reg_params {
+ struct i915_vma *vma;
+
struct {
enum pipe pipe;
enum plane plane;
} crtc;
struct {
- u64 ggtt_offset;
uint32_t pixel_format;
unsigned int stride;
- int fence_reg;
} fb;
int cfb_size;
struct i915_frontbuffer_tracking fb_tracking;
+ struct intel_atomic_helper {
+ struct llist_head free_list;
+ struct work_struct free_work;
+ } atomic_helper;
+
u16 orig_clock;
bool mchbar_need_disable;
return i915_gem_obj_to_vma(obj, &to_i915(obj->base.dev)->ggtt.base, view);
}
-static inline unsigned long
-i915_gem_object_ggtt_offset(struct drm_i915_gem_object *o,
- const struct i915_ggtt_view *view)
-{
- return i915_ggtt_offset(i915_gem_object_to_ggtt(o, view));
-}
-
/* i915_gem_fence_reg.c */
int __must_check i915_vma_get_fence(struct i915_vma *vma);
int __must_check i915_vma_put_fence(struct i915_vma *vma);
struct drm_i915_gem_pwrite *args,
struct drm_file *file)
{
- struct drm_device *dev = obj->base.dev;
void *vaddr = obj->phys_handle->vaddr + args->offset;
char __user *user_data = u64_to_user_ptr(args->data_ptr);
- int ret;
/* We manually control the domain here and pretend that it
* remains coherent i.e. in the GTT domain, like shmem_pwrite.
*/
- lockdep_assert_held(&obj->base.dev->struct_mutex);
- ret = i915_gem_object_wait(obj,
- I915_WAIT_INTERRUPTIBLE |
- I915_WAIT_LOCKED |
- I915_WAIT_ALL,
- MAX_SCHEDULE_TIMEOUT,
- to_rps_client(file));
- if (ret)
- return ret;
-
intel_fb_obj_invalidate(obj, ORIGIN_CPU);
- if (__copy_from_user_inatomic_nocache(vaddr, user_data, args->size)) {
- unsigned long unwritten;
-
- /* The physical object once assigned is fixed for the lifetime
- * of the obj, so we can safely drop the lock and continue
- * to access vaddr.
- */
- mutex_unlock(&dev->struct_mutex);
- unwritten = copy_from_user(vaddr, user_data, args->size);
- mutex_lock(&dev->struct_mutex);
- if (unwritten) {
- ret = -EFAULT;
- goto out;
- }
- }
+ if (copy_from_user(vaddr, user_data, args->size))
+ return -EFAULT;
drm_clflush_virt_range(vaddr, args->size);
- i915_gem_chipset_flush(to_i915(dev));
+ i915_gem_chipset_flush(to_i915(obj->base.dev));
-out:
intel_fb_obj_flush(obj, false, ORIGIN_CPU);
- return ret;
+ return 0;
}
void *i915_gem_object_alloc(struct drm_device *dev)
}
/* Unbinding will emit any required flushes */
+ ret = 0;
while (!list_empty(&eviction_list)) {
vma = list_first_entry(&eviction_list,
struct i915_vma,
return ret;
}
+ trace_i915_vma_bind(vma, bind_flags);
ret = vma->vm->bind_vma(vma, cache_level, bind_flags);
if (ret)
return ret;
__drm_atomic_helper_plane_duplicate_state(plane, state);
+ intel_state->vma = NULL;
+
return state;
}
intel_plane_destroy_state(struct drm_plane *plane,
struct drm_plane_state *state)
{
+ struct i915_vma *vma;
+
+ vma = fetch_and_zero(&to_intel_plane_state(state)->vma);
+
+ /*
+ * FIXME: Normally intel_cleanup_plane_fb handles destruction of vma.
+ * We currently don't clear all planes during driver unload, so we have
+ * to be able to unpin vma here for now.
+ *
+ * Normally this can only happen during unload when kmscon is disabled
+ * and userspace doesn't attempt to set a framebuffer at all.
+ */
+ if (vma) {
+ mutex_lock(&plane->dev->struct_mutex);
+ intel_unpin_fb_vma(vma);
+ mutex_unlock(&plane->dev->struct_mutex);
+ }
+
drm_atomic_helper_plane_destroy_state(plane, state);
}
struct drm_i915_private *dev_priv = to_i915(crt->base.base.dev);
struct edid *edid;
struct i2c_adapter *i2c;
+ bool ret = false;
BUG_ON(crt->base.type != INTEL_OUTPUT_ANALOG);
*/
if (!is_digital) {
DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n");
- return true;
+ ret = true;
+ } else {
+ DRM_DEBUG_KMS("CRT not detected via DDC:0x50 [EDID reports a digital panel]\n");
}
-
- DRM_DEBUG_KMS("CRT not detected via DDC:0x50 [EDID reports a digital panel]\n");
} else {
DRM_DEBUG_KMS("CRT not detected via DDC:0x50 [no valid EDID found]\n");
}
kfree(edid);
- return false;
+ return ret;
}
static enum drm_connector_status
i915_vma_pin_fence(vma);
}
+ i915_vma_get(vma);
err:
intel_runtime_pm_put(dev_priv);
return vma;
}
-void intel_unpin_fb_obj(struct drm_framebuffer *fb, unsigned int rotation)
+void intel_unpin_fb_vma(struct i915_vma *vma)
{
- struct drm_i915_gem_object *obj = intel_fb_obj(fb);
- struct i915_ggtt_view view;
- struct i915_vma *vma;
+ lockdep_assert_held(&vma->vm->dev->struct_mutex);
- WARN_ON(!mutex_is_locked(&obj->base.dev->struct_mutex));
-
- intel_fill_fb_ggtt_view(&view, fb, rotation);
- vma = i915_gem_object_to_ggtt(obj, &view);
+ if (WARN_ON_ONCE(!vma))
+ return;
i915_vma_unpin_fence(vma);
i915_gem_object_unpin_from_display_plane(vma);
+ i915_vma_put(vma);
}
static int intel_fb_pitch(const struct drm_framebuffer *fb, int plane,
* We only keep the x/y offsets, so push all of the
* gtt offset into the x/y offsets.
*/
- _intel_adjust_tile_offset(&x, &y, tile_size,
- tile_width, tile_height, pitch_tiles,
+ _intel_adjust_tile_offset(&x, &y,
+ tile_width, tile_height,
+ tile_size, pitch_tiles,
gtt_offset_rotated * tile_size, 0);
gtt_offset_rotated += rot_info->plane[i].width * rot_info->plane[i].height;
struct drm_device *dev = intel_crtc->base.dev;
struct drm_i915_private *dev_priv = to_i915(dev);
struct drm_crtc *c;
- struct intel_crtc *i;
struct drm_i915_gem_object *obj;
struct drm_plane *primary = intel_crtc->base.primary;
struct drm_plane_state *plane_state = primary->state;
* an fb with another CRTC instead
*/
for_each_crtc(dev, c) {
- i = to_intel_crtc(c);
+ struct intel_plane_state *state;
if (c == &intel_crtc->base)
continue;
- if (!i->active)
+ if (!to_intel_crtc(c)->active)
continue;
- fb = c->primary->fb;
- if (!fb)
+ state = to_intel_plane_state(c->primary->state);
+ if (!state->vma)
continue;
- obj = intel_fb_obj(fb);
- if (i915_gem_object_ggtt_offset(obj, NULL) == plane_config->base) {
+ if (intel_plane_ggtt_offset(state) == plane_config->base) {
+ fb = c->primary->fb;
drm_framebuffer_reference(fb);
goto valid_fb;
}
return;
valid_fb:
+ mutex_lock(&dev->struct_mutex);
+ intel_state->vma =
+ intel_pin_and_fence_fb_obj(fb, primary->state->rotation);
+ mutex_unlock(&dev->struct_mutex);
+ if (IS_ERR(intel_state->vma)) {
+ DRM_ERROR("failed to pin boot fb on pipe %d: %li\n",
+ intel_crtc->pipe, PTR_ERR(intel_state->vma));
+
+ intel_state->vma = NULL;
+ drm_framebuffer_unreference(fb);
+ return;
+ }
+
plane_state->src_x = 0;
plane_state->src_y = 0;
plane_state->src_w = fb->width << 16;
unsigned int rotation = plane_state->base.rotation;
int ret;
+ if (!plane_state->base.visible)
+ return 0;
+
/* Rotate src coordinates to match rotated GTT view */
if (drm_rotation_90_or_270(rotation))
drm_rect_rotate(&plane_state->base.src,
I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]);
if (INTEL_GEN(dev_priv) >= 4) {
I915_WRITE(DSPSURF(plane),
- intel_fb_gtt_offset(fb, rotation) +
+ intel_plane_ggtt_offset(plane_state) +
intel_crtc->dspaddr_offset);
I915_WRITE(DSPTILEOFF(plane), (y << 16) | x);
I915_WRITE(DSPLINOFF(plane), linear_offset);
} else {
I915_WRITE(DSPADDR(plane),
- intel_fb_gtt_offset(fb, rotation) +
+ intel_plane_ggtt_offset(plane_state) +
intel_crtc->dspaddr_offset);
}
POSTING_READ(reg);
I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]);
I915_WRITE(DSPSURF(plane),
- intel_fb_gtt_offset(fb, rotation) +
+ intel_plane_ggtt_offset(plane_state) +
intel_crtc->dspaddr_offset);
if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) {
I915_WRITE(DSPOFFSET(plane), (y << 16) | x);
}
}
-u32 intel_fb_gtt_offset(struct drm_framebuffer *fb,
- unsigned int rotation)
-{
- struct drm_i915_gem_object *obj = intel_fb_obj(fb);
- struct i915_ggtt_view view;
- struct i915_vma *vma;
-
- intel_fill_fb_ggtt_view(&view, fb, rotation);
-
- vma = i915_gem_object_to_ggtt(obj, &view);
- if (WARN(!vma, "ggtt vma for display object not found! (view=%u)\n",
- view.type))
- return -1;
-
- return i915_ggtt_offset(vma);
-}
-
static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id)
{
struct drm_device *dev = intel_crtc->base.dev;
}
I915_WRITE(PLANE_SURF(pipe, 0),
- intel_fb_gtt_offset(fb, rotation) + surf_addr);
+ intel_plane_ggtt_offset(plane_state) + surf_addr);
POSTING_READ(PLANE_SURF(pipe, 0));
}
}
state = drm_atomic_state_alloc(crtc->dev);
+ if (!state) {
+ DRM_DEBUG_KMS("failed to disable [CRTC:%d:%s], out of memory",
+ crtc->base.id, crtc->name);
+ return;
+ }
+
state->acquire_ctx = crtc->dev->mode_config.acquire_ctx;
/* Everything's already locked, -EDEADLK can't happen. */
}
old->restore_state = restore_state;
+ drm_atomic_state_put(state);
/* let the connector get through one full cycle before testing */
intel_wait_for_vblank(dev_priv, intel_crtc->pipe);
flush_work(&work->mmio_work);
mutex_lock(&dev->struct_mutex);
- intel_unpin_fb_obj(work->old_fb, primary->state->rotation);
+ intel_unpin_fb_vma(work->old_vma);
i915_gem_object_put(work->pending_flip_obj);
mutex_unlock(&dev->struct_mutex);
goto cleanup_pending;
}
- work->gtt_offset = intel_fb_gtt_offset(fb, primary->state->rotation);
- work->gtt_offset += intel_crtc->dspaddr_offset;
+ work->old_vma = to_intel_plane_state(primary->state)->vma;
+ to_intel_plane_state(primary->state)->vma = vma;
+
+ work->gtt_offset = i915_ggtt_offset(vma) + intel_crtc->dspaddr_offset;
work->rotation = crtc->primary->state->rotation;
/*
cleanup_request:
i915_add_request_no_flush(request);
cleanup_unpin:
- intel_unpin_fb_obj(fb, crtc->primary->state->rotation);
+ to_intel_plane_state(primary->state)->vma = work->old_vma;
+ intel_unpin_fb_vma(vma);
cleanup_pending:
atomic_dec(&intel_crtc->unpin_work_count);
unlock:
break;
case FENCE_FREE:
- drm_atomic_state_put(&state->base);
- break;
+ {
+ struct intel_atomic_helper *helper =
+ &to_i915(state->base.dev)->atomic_helper;
+
+ if (llist_add(&state->freed, &helper->free_list))
+ schedule_work(&helper->free_work);
+ break;
+ }
}
return NOTIFY_DONE;
DRM_DEBUG_KMS("failed to pin object\n");
return PTR_ERR(vma);
}
+
+ to_intel_plane_state(new_state)->vma = vma;
}
return 0;
intel_cleanup_plane_fb(struct drm_plane *plane,
struct drm_plane_state *old_state)
{
- struct drm_i915_private *dev_priv = to_i915(plane->dev);
- struct intel_plane_state *old_intel_state;
- struct drm_i915_gem_object *old_obj = intel_fb_obj(old_state->fb);
- struct drm_i915_gem_object *obj = intel_fb_obj(plane->state->fb);
-
- old_intel_state = to_intel_plane_state(old_state);
-
- if (!obj && !old_obj)
- return;
+ struct i915_vma *vma;
- if (old_obj && (plane->type != DRM_PLANE_TYPE_CURSOR ||
- !INTEL_INFO(dev_priv)->cursor_needs_physical))
- intel_unpin_fb_obj(old_state->fb, old_state->rotation);
+ /* Should only be called after a successful intel_prepare_plane_fb()! */
+ vma = fetch_and_zero(&to_intel_plane_state(old_state)->vma);
+ if (vma)
+ intel_unpin_fb_vma(vma);
}
int
if (!obj)
addr = 0;
else if (!INTEL_INFO(dev_priv)->cursor_needs_physical)
- addr = i915_gem_object_ggtt_offset(obj, NULL);
+ addr = intel_plane_ggtt_offset(state);
else
addr = obj->phys_handle->busaddr;
drm_modeset_acquire_fini(&ctx);
}
+static void intel_atomic_helper_free_state(struct work_struct *work)
+{
+ struct drm_i915_private *dev_priv =
+ container_of(work, typeof(*dev_priv), atomic_helper.free_work);
+ struct intel_atomic_state *state, *next;
+ struct llist_node *freed;
+
+ freed = llist_del_all(&dev_priv->atomic_helper.free_list);
+ llist_for_each_entry_safe(state, next, freed, freed)
+ drm_atomic_state_put(&state->base);
+}
+
int intel_modeset_init(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = to_i915(dev);
dev->mode_config.funcs = &intel_mode_funcs;
+ INIT_WORK(&dev_priv->atomic_helper.free_work,
+ intel_atomic_helper_free_state);
+
intel_init_quirks(dev);
intel_init_pm(dev_priv);
if (ret)
DRM_ERROR("Restoring old state failed with %i\n", ret);
- drm_atomic_state_put(state);
+ if (state)
+ drm_atomic_state_put(state);
}
void intel_modeset_gem_init(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = to_i915(dev);
- struct drm_crtc *c;
- struct drm_i915_gem_object *obj;
intel_init_gt_powersave(dev_priv);
intel_modeset_init_hw(dev);
intel_setup_overlay(dev_priv);
-
- /*
- * Make sure any fbs we allocated at startup are properly
- * pinned & fenced. When we do the allocation it's too early
- * for this.
- */
- for_each_crtc(dev, c) {
- struct i915_vma *vma;
-
- obj = intel_fb_obj(c->primary->fb);
- if (obj == NULL)
- continue;
-
- mutex_lock(&dev->struct_mutex);
- vma = intel_pin_and_fence_fb_obj(c->primary->fb,
- c->primary->state->rotation);
- mutex_unlock(&dev->struct_mutex);
- if (IS_ERR(vma)) {
- DRM_ERROR("failed to pin boot fb on pipe %d\n",
- to_intel_crtc(c)->pipe);
- drm_framebuffer_unreference(c->primary->fb);
- c->primary->fb = NULL;
- c->primary->crtc = c->primary->state->crtc = NULL;
- update_state_fb(c->primary);
- c->state->plane_mask &= ~(1 << drm_plane_index(c->primary));
- }
- }
}
int intel_connector_register(struct drm_connector *connector)
{
struct drm_i915_private *dev_priv = to_i915(dev);
+ flush_work(&dev_priv->atomic_helper.free_work);
+ WARN_ON(!llist_empty(&dev_priv->atomic_helper.free_list));
+
intel_disable_gt_powersave(dev_priv);
/*
struct skl_wm_values wm_results;
struct i915_sw_fence commit_ready;
+
+ struct llist_node freed;
};
struct intel_plane_state {
struct drm_plane_state base;
struct drm_rect clip;
+ struct i915_vma *vma;
struct {
u32 offset;
struct work_struct mmio_work;
struct drm_crtc *crtc;
+ struct i915_vma *old_vma;
struct drm_framebuffer *old_fb;
struct drm_i915_gem_object *pending_flip_obj;
struct drm_pending_vblank_event *event;
struct drm_modeset_acquire_ctx *ctx);
struct i915_vma *
intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb, unsigned int rotation);
-void intel_unpin_fb_obj(struct drm_framebuffer *fb, unsigned int rotation);
+void intel_unpin_fb_vma(struct i915_vma *vma);
struct drm_framebuffer *
__intel_framebuffer_create(struct drm_device *dev,
struct drm_mode_fb_cmd2 *mode_cmd,
int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state);
int skl_max_scale(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state);
-u32 intel_fb_gtt_offset(struct drm_framebuffer *fb, unsigned int rotation);
+static inline u32 intel_plane_ggtt_offset(const struct intel_plane_state *state)
+{
+ return i915_ggtt_offset(state->vma);
+}
u32 skl_plane_ctl_format(uint32_t pixel_format);
u32 skl_plane_ctl_tiling(uint64_t fb_modifier);
if (IS_I945GM(dev_priv))
fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */
fbc_ctl |= (cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT;
- fbc_ctl |= params->fb.fence_reg;
+ fbc_ctl |= params->vma->fence->id;
I915_WRITE(FBC_CONTROL, fbc_ctl);
}
else
dpfc_ctl |= DPFC_CTL_LIMIT_1X;
- if (params->fb.fence_reg != I915_FENCE_REG_NONE) {
- dpfc_ctl |= DPFC_CTL_FENCE_EN | params->fb.fence_reg;
+ if (params->vma->fence) {
+ dpfc_ctl |= DPFC_CTL_FENCE_EN | params->vma->fence->id;
I915_WRITE(DPFC_FENCE_YOFF, params->crtc.fence_y_offset);
} else {
I915_WRITE(DPFC_FENCE_YOFF, 0);
break;
}
- if (params->fb.fence_reg != I915_FENCE_REG_NONE) {
+ if (params->vma->fence) {
dpfc_ctl |= DPFC_CTL_FENCE_EN;
if (IS_GEN5(dev_priv))
- dpfc_ctl |= params->fb.fence_reg;
+ dpfc_ctl |= params->vma->fence->id;
if (IS_GEN6(dev_priv)) {
I915_WRITE(SNB_DPFC_CTL_SA,
- SNB_CPU_FENCE_ENABLE | params->fb.fence_reg);
+ SNB_CPU_FENCE_ENABLE |
+ params->vma->fence->id);
I915_WRITE(DPFC_CPU_FENCE_OFFSET,
params->crtc.fence_y_offset);
}
}
I915_WRITE(ILK_DPFC_FENCE_YOFF, params->crtc.fence_y_offset);
- I915_WRITE(ILK_FBC_RT_BASE, params->fb.ggtt_offset | ILK_FBC_RT_VALID);
+ I915_WRITE(ILK_FBC_RT_BASE,
+ i915_ggtt_offset(params->vma) | ILK_FBC_RT_VALID);
/* enable it... */
I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
break;
}
- if (params->fb.fence_reg != I915_FENCE_REG_NONE) {
+ if (params->vma->fence) {
dpfc_ctl |= IVB_DPFC_CTL_FENCE_EN;
I915_WRITE(SNB_DPFC_CTL_SA,
- SNB_CPU_FENCE_ENABLE | params->fb.fence_reg);
+ SNB_CPU_FENCE_ENABLE |
+ params->vma->fence->id);
I915_WRITE(DPFC_CPU_FENCE_OFFSET, params->crtc.fence_y_offset);
} else {
I915_WRITE(SNB_DPFC_CTL_SA,0);
return effective_w <= max_w && effective_h <= max_h;
}
-/* XXX replace me when we have VMA tracking for intel_plane_state */
-static int get_fence_id(struct drm_framebuffer *fb)
-{
- struct i915_vma *vma = i915_gem_object_to_ggtt(intel_fb_obj(fb), NULL);
-
- return vma && vma->fence ? vma->fence->id : I915_FENCE_REG_NONE;
-}
-
static void intel_fbc_update_state_cache(struct intel_crtc *crtc,
struct intel_crtc_state *crtc_state,
struct intel_plane_state *plane_state)
struct intel_fbc *fbc = &dev_priv->fbc;
struct intel_fbc_state_cache *cache = &fbc->state_cache;
struct drm_framebuffer *fb = plane_state->base.fb;
- struct drm_i915_gem_object *obj;
+
+ cache->vma = NULL;
cache->crtc.mode_flags = crtc_state->base.adjusted_mode.flags;
if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
if (!cache->plane.visible)
return;
- obj = intel_fb_obj(fb);
-
- /* FIXME: We lack the proper locking here, so only run this on the
- * platforms that need. */
- if (IS_GEN(dev_priv, 5, 6))
- cache->fb.ilk_ggtt_offset = i915_gem_object_ggtt_offset(obj, NULL);
cache->fb.pixel_format = fb->pixel_format;
cache->fb.stride = fb->pitches[0];
- cache->fb.fence_reg = get_fence_id(fb);
- cache->fb.tiling_mode = i915_gem_object_get_tiling(obj);
+
+ cache->vma = plane_state->vma;
}
static bool intel_fbc_can_activate(struct intel_crtc *crtc)
return false;
}
- if (!cache->plane.visible) {
+ if (!cache->vma) {
fbc->no_fbc_reason = "primary plane not visible";
return false;
}
* so have no fence associated with it) due to aperture constaints
* at the time of pinning.
*/
- if (cache->fb.tiling_mode != I915_TILING_X ||
- cache->fb.fence_reg == I915_FENCE_REG_NONE) {
+ if (!cache->vma->fence) {
fbc->no_fbc_reason = "framebuffer not tiled or fenced";
return false;
}
* zero. */
memset(params, 0, sizeof(*params));
+ params->vma = cache->vma;
+
params->crtc.pipe = crtc->pipe;
params->crtc.plane = crtc->plane;
params->crtc.fence_y_offset = get_crtc_fence_y_offset(crtc);
params->fb.pixel_format = cache->fb.pixel_format;
params->fb.stride = cache->fb.stride;
- params->fb.fence_reg = cache->fb.fence_reg;
params->cfb_size = intel_fbc_calculate_cfb_size(dev_priv, cache);
-
- params->fb.ggtt_offset = cache->fb.ilk_ggtt_offset;
}
static bool intel_fbc_reg_params_equal(struct intel_fbc_reg_params *params1,
out_destroy_fbi:
drm_fb_helper_release_fbi(helper);
out_unpin:
- intel_unpin_fb_obj(&ifbdev->fb->base, DRM_ROTATE_0);
+ intel_unpin_fb_vma(vma);
out_unlock:
mutex_unlock(&dev->struct_mutex);
return ret;
if (ifbdev->fb) {
mutex_lock(&ifbdev->helper.dev->struct_mutex);
- intel_unpin_fb_obj(&ifbdev->fb->base, DRM_ROTATE_0);
+ intel_unpin_fb_vma(ifbdev->vma);
mutex_unlock(&ifbdev->helper.dev->struct_mutex);
drm_framebuffer_remove(&ifbdev->fb->base);
{
struct intel_fbdev *ifbdev = to_i915(dev)->fbdev;
+ if (!ifbdev)
+ return;
+
ifbdev->cookie = async_schedule(intel_fbdev_initial_config, ifbdev);
}
uint32_t *batch,
uint32_t index)
{
- struct drm_i915_private *dev_priv = engine->i915;
uint32_t l3sqc4_flush = (0x40400000 | GEN8_LQSC_FLUSH_COHERENT_LINES);
- /*
- * WaDisableLSQCROPERFforOCL:kbl
- * This WA is implemented in skl_init_clock_gating() but since
- * this batch updates GEN8_L3SQCREG4 with default value we need to
- * set this bit here to retain the WA during flush.
- */
- if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_E0))
- l3sqc4_flush |= GEN8_LQSC_RO_PERF_DIS;
-
wa_ctx_emit(batch, index, (MI_STORE_REGISTER_MEM_GEN8 |
MI_SRM_LRM_GLOBAL_GTT));
wa_ctx_emit_reg(batch, index, GEN8_L3SQCREG4);
WA_SET_BIT_MASKED(HDC_CHICKEN0,
HDC_FENCE_DEST_SLM_DISABLE);
- /* GEN8_L3SQCREG4 has a dependency with WA batch so any new changes
- * involving this register should also be added to WA batch as required.
- */
- if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_E0))
- /* WaDisableLSQCROPERFforOCL:kbl */
- I915_WRITE(GEN8_L3SQCREG4, I915_READ(GEN8_L3SQCREG4) |
- GEN8_LQSC_RO_PERF_DIS);
-
/* WaToEnableHwFixForPushConstHWBug:kbl */
if (IS_KBL_REVID(dev_priv, KBL_REVID_C0, REVID_FOREVER))
WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2,
I915_WRITE(PLANE_CTL(pipe, plane), plane_ctl);
I915_WRITE(PLANE_SURF(pipe, plane),
- intel_fb_gtt_offset(fb, rotation) + surf_addr);
+ intel_plane_ggtt_offset(plane_state) + surf_addr);
POSTING_READ(PLANE_SURF(pipe, plane));
}
I915_WRITE(SPSIZE(pipe, plane), (crtc_h << 16) | crtc_w);
I915_WRITE(SPCNTR(pipe, plane), sprctl);
I915_WRITE(SPSURF(pipe, plane),
- intel_fb_gtt_offset(fb, rotation) + sprsurf_offset);
+ intel_plane_ggtt_offset(plane_state) + sprsurf_offset);
POSTING_READ(SPSURF(pipe, plane));
}
I915_WRITE(SPRSCALE(pipe), sprscale);
I915_WRITE(SPRCTL(pipe), sprctl);
I915_WRITE(SPRSURF(pipe),
- intel_fb_gtt_offset(fb, rotation) + sprsurf_offset);
+ intel_plane_ggtt_offset(plane_state) + sprsurf_offset);
POSTING_READ(SPRSURF(pipe));
}
I915_WRITE(DVSSCALE(pipe), dvsscale);
I915_WRITE(DVSCNTR(pipe), dvscntr);
I915_WRITE(DVSSURF(pipe),
- intel_fb_gtt_offset(fb, rotation) + dvssurf_offset);
+ intel_plane_ggtt_offset(plane_state) + dvssurf_offset);
POSTING_READ(DVSSURF(pipe));
}
struct drm_crtc_state *crtc_state;
struct drm_rect clip = { 0, };
+ if (!state->crtc)
+ return 0;
+
crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
if (IS_ERR(crtc_state))
return PTR_ERR(crtc_state);
* - TV Panel encoding via ENCT
*/
+/* HHI Registers */
+#define HHI_VDAC_CNTL0 0x2F4 /* 0xbd offset in data sheet */
+#define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */
+#define HHI_HDMI_PHY_CNTL0 0x3a0 /* 0xe8 offset in data sheet */
+
struct meson_cvbs_enci_mode meson_cvbs_enci_pal = {
.mode_tag = MESON_VENC_MODE_CVBS_PAL,
.hso_begin = 3,
void meson_venc_init(struct meson_drm *priv)
{
+ /* Disable CVBS VDAC */
+ regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0);
+ regmap_write(priv->hhi, HHI_VDAC_CNTL1, 8);
+
+ /* Power Down Dacs */
+ writel_relaxed(0xff, priv->io_base + _REG(VENC_VDAC_SETTING));
+
+ /* Disable HDMI PHY */
+ regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0);
+
+ /* Disable HDMI */
+ writel_bits_relaxed(0x3, 0,
+ priv->io_base + _REG(VPU_HDMI_SETTING));
+
/* Disable all encoders */
writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN));
writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN));
/* Disable CVBS VDAC */
regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0);
- regmap_write(priv->hhi, HHI_VDAC_CNTL1, 0);
+ regmap_write(priv->hhi, HHI_VDAC_CNTL1, 8);
}
static void meson_venc_cvbs_encoder_enable(struct drm_encoder *encoder)
void adreno_flush(struct msm_gpu *gpu)
{
struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
- uint32_t wptr = get_wptr(gpu->rb);
+ uint32_t wptr;
+
+ /*
+ * Mask wptr value that we calculate to fit in the HW range. This is
+ * to account for the possibility that the last command fit exactly into
+ * the ringbuffer and rb->next hasn't wrapped to zero yet
+ */
+ wptr = get_wptr(gpu->rb) & ((gpu->rb->size / 4) - 1);
/* ensure writes to ringbuffer have hit system memory: */
mb();
{
struct adreno_platform_config *config = pdev->dev.platform_data;
struct msm_gpu *gpu = &adreno_gpu->base;
- struct msm_mmu *mmu;
int ret;
adreno_gpu->funcs = funcs;
return ret;
}
- mmu = gpu->aspace->mmu;
- if (mmu) {
+ if (gpu->aspace && gpu->aspace->mmu) {
+ struct msm_mmu *mmu = gpu->aspace->mmu;
ret = mmu->funcs->attach(mmu, iommu_ports,
ARRAY_SIZE(iommu_ports));
if (ret)
static void mdp5_complete_commit(struct msm_kms *kms, struct drm_atomic_state *state)
{
- int i;
struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
- struct drm_plane *plane;
- struct drm_plane_state *plane_state;
-
- for_each_plane_in_state(state, plane, plane_state, i)
- mdp5_plane_complete_commit(plane, plane_state);
if (mdp5_kms->smp)
mdp5_smp_complete_commit(mdp5_kms->smp, &mdp5_kms->state->smp);
/* assigned by crtc blender */
enum mdp_mixer_stage_id stage;
-
- bool pending : 1;
};
#define to_mdp5_plane_state(x) \
container_of(x, struct mdp5_plane_state, base)
void mdp5_irq_domain_fini(struct mdp5_kms *mdp5_kms);
uint32_t mdp5_plane_get_flush(struct drm_plane *plane);
-void mdp5_plane_complete_commit(struct drm_plane *plane,
- struct drm_plane_state *state);
enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane);
struct drm_plane *mdp5_plane_init(struct drm_device *dev, bool primary);
drm_printf(p, "\tzpos=%u\n", pstate->zpos);
drm_printf(p, "\talpha=%u\n", pstate->alpha);
drm_printf(p, "\tstage=%s\n", stage2name(pstate->stage));
- drm_printf(p, "\tpending=%u\n", pstate->pending);
}
static void mdp5_plane_reset(struct drm_plane *plane)
if (mdp5_state && mdp5_state->base.fb)
drm_framebuffer_reference(mdp5_state->base.fb);
- mdp5_state->pending = false;
-
return &mdp5_state->base;
}
DBG("%s: check (%d -> %d)", plane->name,
plane_enabled(old_state), plane_enabled(state));
- /* We don't allow faster-than-vblank updates.. if we did add this
- * some day, we would need to disallow in cases where hwpipe
- * changes
- */
- if (WARN_ON(to_mdp5_plane_state(old_state)->pending))
- return -EBUSY;
-
max_width = config->hw->lm.max_width << 16;
max_height = config->hw->lm.max_height << 16;
struct drm_plane_state *old_state)
{
struct drm_plane_state *state = plane->state;
- struct mdp5_plane_state *mdp5_state = to_mdp5_plane_state(state);
DBG("%s: update", plane->name);
- mdp5_state->pending = true;
-
if (plane_enabled(state)) {
int ret;
return pstate->hwpipe->flush_mask;
}
-/* called after vsync in thread context */
-void mdp5_plane_complete_commit(struct drm_plane *plane,
- struct drm_plane_state *state)
-{
- struct mdp5_plane_state *pstate = to_mdp5_plane_state(plane->state);
-
- pstate->pending = false;
-}
-
/* initialize plane */
struct drm_plane *mdp5_plane_init(struct drm_device *dev, bool primary)
{
WARN_ON(!mutex_is_locked(&dev->struct_mutex));
for (id = 0; id < ARRAY_SIZE(msm_obj->domain); id++) {
+ if (!priv->aspace[id])
+ continue;
msm_gem_unmap_vma(priv->aspace[id],
&msm_obj->domain[id], msm_obj->sgt);
}
pagefault_disable();
}
- if (submit_bo.flags & ~MSM_SUBMIT_BO_FLAGS) {
+ if ((submit_bo.flags & ~MSM_SUBMIT_BO_FLAGS) ||
+ !(submit_bo.flags & MSM_SUBMIT_BO_FLAGS)) {
DRM_ERROR("invalid flags: %x\n", submit_bo.flags);
ret = -EINVAL;
goto out_unlock;
{
uint32_t i, last_offset = 0;
uint32_t *ptr;
- int ret;
+ int ret = 0;
if (offset % 4) {
DRM_ERROR("non-aligned cmdstream buffer: %u\n", offset);
ret = copy_from_user(&submit_reloc, userptr, sizeof(submit_reloc));
if (ret)
- return -EFAULT;
+ goto out;
if (submit_reloc.submit_offset % 4) {
DRM_ERROR("non-aligned reloc offset: %u\n",
submit_reloc.submit_offset);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
/* offset in dwords: */
if ((off >= (obj->base.size / 4)) ||
(off < last_offset)) {
DRM_ERROR("invalid offset %u at reloc %u\n", off, i);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
ret = submit_bo(submit, submit_reloc.reloc_idx, NULL, &iova, &valid);
if (ret)
- return ret;
+ goto out;
if (valid)
continue;
last_offset = off;
}
+out:
msm_gem_put_vaddr_locked(&obj->base);
- return 0;
+ return ret;
}
static void submit_cleanup(struct msm_gem_submit *submit)
struct msm_ringbuffer *ring;
int ret;
- size = ALIGN(size, 4); /* size should be dword aligned */
+ if (WARN_ON(!is_power_of_2(size)))
+ return ERR_PTR(-EINVAL);
ring = kzalloc(sizeof(*ring), GFP_KERNEL);
if (!ring) {
uint32_t mpllP;
pci_read_config_dword(pci_get_bus_and_slot(0, 3), 0x6c, &mpllP);
+ mpllP = (mpllP >> 8) & 0xf;
if (!mpllP)
mpllP = 4;
uint32_t clock;
pci_read_config_dword(pci_get_bus_and_slot(0, 5), 0x4c, &clock);
- return clock;
+ return clock / 1000;
}
ret = nouveau_hw_get_pllvals(dev, plltype, &pllvals);
return ret;
/* enable polling for external displays */
- drm_kms_helper_poll_enable(dev);
+ if (!dev->mode_config.poll_enabled)
+ drm_kms_helper_poll_enable(dev);
/* enable hotplug interrupts */
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
pci_set_master(pdev);
ret = nouveau_do_resume(drm_dev, true);
- drm_kms_helper_poll_enable(drm_dev);
+
+ if (!drm_dev->mode_config.poll_enabled)
+ drm_kms_helper_poll_enable(drm_dev);
+
/* do magic */
nvif_mask(&device->object, 0x088488, (1 << 25), (1 << 25));
vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_ON);
struct backlight_device *backlight;
struct list_head bl_connectors;
struct work_struct hpd_work;
+ struct work_struct fbcon_work;
+ int fbcon_new_state;
#ifdef CONFIG_ACPI
struct notifier_block acpi_nb;
#endif
.fb_probe = nouveau_fbcon_create,
};
+static void
+nouveau_fbcon_set_suspend_work(struct work_struct *work)
+{
+ struct nouveau_drm *drm = container_of(work, typeof(*drm), fbcon_work);
+ int state = READ_ONCE(drm->fbcon_new_state);
+
+ if (state == FBINFO_STATE_RUNNING)
+ pm_runtime_get_sync(drm->dev->dev);
+
+ console_lock();
+ if (state == FBINFO_STATE_RUNNING)
+ nouveau_fbcon_accel_restore(drm->dev);
+ drm_fb_helper_set_suspend(&drm->fbcon->helper, state);
+ if (state != FBINFO_STATE_RUNNING)
+ nouveau_fbcon_accel_save_disable(drm->dev);
+ console_unlock();
+
+ if (state == FBINFO_STATE_RUNNING) {
+ pm_runtime_mark_last_busy(drm->dev->dev);
+ pm_runtime_put_sync(drm->dev->dev);
+ }
+}
+
void
nouveau_fbcon_set_suspend(struct drm_device *dev, int state)
{
struct nouveau_drm *drm = nouveau_drm(dev);
- if (drm->fbcon) {
- console_lock();
- if (state == FBINFO_STATE_RUNNING)
- nouveau_fbcon_accel_restore(dev);
- drm_fb_helper_set_suspend(&drm->fbcon->helper, state);
- if (state != FBINFO_STATE_RUNNING)
- nouveau_fbcon_accel_save_disable(dev);
- console_unlock();
- }
+
+ if (!drm->fbcon)
+ return;
+
+ drm->fbcon_new_state = state;
+ /* Since runtime resume can happen as a result of a sysfs operation,
+ * it's possible we already have the console locked. So handle fbcon
+ * init/deinit from a seperate work thread
+ */
+ schedule_work(&drm->fbcon_work);
}
int
return -ENOMEM;
drm->fbcon = fbcon;
+ INIT_WORK(&drm->fbcon_work, nouveau_fbcon_set_suspend_work);
drm_fb_helper_prepare(dev, &fbcon->helper, &nouveau_fbcon_helper_funcs);
struct nouveau_bo *bo;
struct nouveau_bo *bo_gart;
u32 *suspend;
+ struct mutex mutex;
};
int nv84_fence_context_new(struct nouveau_channel *);
}
/* nouveau_led.c */
-#if IS_ENABLED(CONFIG_LEDS_CLASS)
+#if IS_REACHABLE(CONFIG_LEDS_CLASS)
int nouveau_led_init(struct drm_device *dev);
void nouveau_led_suspend(struct drm_device *dev);
void nouveau_led_resume(struct drm_device *dev);
if (!(ret = nvif_unpack(-ENOSYS, &data, &size, argv->v0, 0, 0, true))) {
/* block access to objects not created via this interface */
owner = argv->v0.owner;
- if (argv->v0.object == 0ULL)
+ if (argv->v0.object == 0ULL &&
+ argv->v0.type != NVIF_IOCTL_V0_DEL)
argv->v0.owner = NVDRM_OBJECT_ANY; /* except client */
else
argv->v0.owner = NVDRM_OBJECT_USIF;
}
}
+ for_each_crtc_in_state(state, crtc, crtc_state, i) {
+ if (crtc->state->event)
+ drm_crtc_vblank_get(crtc);
+ }
+
/* Update plane(s). */
for_each_plane_in_state(state, plane, plane_state, i) {
struct nv50_wndw_atom *asyw = nv50_wndw_atom(plane->state);
drm_crtc_send_vblank_event(crtc, crtc->state->event);
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
crtc->state->event = NULL;
+ drm_crtc_vblank_put(crtc);
}
}
struct nv84_fence_chan *fctx = chan->fence;
nouveau_bo_wr32(priv->bo, chan->chid * 16 / 4, fctx->base.sequence);
+ mutex_lock(&priv->mutex);
nouveau_bo_vma_del(priv->bo, &fctx->vma_gart);
nouveau_bo_vma_del(priv->bo, &fctx->vma);
+ mutex_unlock(&priv->mutex);
nouveau_fence_context_del(&fctx->base);
chan->fence = NULL;
nouveau_fence_context_free(&fctx->base);
fctx->base.sync32 = nv84_fence_sync32;
fctx->base.sequence = nv84_fence_read(chan);
+ mutex_lock(&priv->mutex);
ret = nouveau_bo_vma_add(priv->bo, cli->vm, &fctx->vma);
if (ret == 0) {
ret = nouveau_bo_vma_add(priv->bo_gart, cli->vm,
&fctx->vma_gart);
}
+ mutex_unlock(&priv->mutex);
if (ret)
nv84_fence_context_del(chan);
priv->base.context_base = dma_fence_context_alloc(priv->base.contexts);
priv->base.uevent = true;
+ mutex_init(&priv->mutex);
+
/* Use VRAM if there is any ; otherwise fallback to system memory */
domain = drm->device.info.ram_size != 0 ? TTM_PL_FLAG_VRAM :
/*
);
}
for (i = 0; i < size; i++)
- nvkm_wr32(device, 0x61c440 + soff, (i << 8) | args->v0.data[0]);
+ nvkm_wr32(device, 0x61c440 + soff, (i << 8) | args->v0.data[i]);
for (; i < 0x60; i++)
nvkm_wr32(device, 0x61c440 + soff, (i << 8));
nvkm_mask(device, 0x61c448 + soff, 0x80000003, 0x80000003);
case 0x94:
case 0x96:
case 0x98:
- case 0xaa:
- case 0xac:
return true;
default:
break;
* 2.46.0 - Add PFP_SYNC_ME support on evergreen
* 2.47.0 - Add UVD_NO_OP register support
* 2.48.0 - TA_CS_BC_BASE_ADDR allowed on SI
+ * 2.49.0 - DRM_RADEON_GEM_INFO ioctl returns correct vram_size/visible values
*/
#define KMS_DRIVER_MAJOR 2
-#define KMS_DRIVER_MINOR 48
+#define KMS_DRIVER_MINOR 49
#define KMS_DRIVER_PATCHLEVEL 0
int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags);
int radeon_driver_unload_kms(struct drm_device *dev);
radeon_pci_shutdown(struct pci_dev *pdev)
{
/* if we are running in a VM, make sure the device
- * torn down properly on reboot/shutdown.
- * unfortunately we can't detect certain
- * hypervisors so just do this all the time.
+ * torn down properly on reboot/shutdown
*/
- radeon_pci_remove(pdev);
+ if (radeon_device_is_virtual())
+ radeon_pci_remove(pdev);
}
static int radeon_pmops_suspend(struct device *dev)
man = &rdev->mman.bdev.man[TTM_PL_VRAM];
- args->vram_size = rdev->mc.real_vram_size;
- args->vram_visible = (u64)man->size << PAGE_SHIFT;
+ args->vram_size = (u64)man->size << PAGE_SHIFT;
+ args->vram_visible = rdev->mc.visible_vram_size;
args->vram_visible -= rdev->vram_pin_size;
args->gart_size = rdev->mc.gtt_size;
args->gart_size -= rdev->gart_pin_size;
MODULE_FIRMWARE("radeon/tahiti_mc.bin");
MODULE_FIRMWARE("radeon/tahiti_rlc.bin");
MODULE_FIRMWARE("radeon/tahiti_smc.bin");
-MODULE_FIRMWARE("radeon/tahiti_k_smc.bin");
MODULE_FIRMWARE("radeon/PITCAIRN_pfp.bin");
MODULE_FIRMWARE("radeon/PITCAIRN_me.bin");
MODULE_FIRMWARE("radeon/hainan_rlc.bin");
MODULE_FIRMWARE("radeon/hainan_smc.bin");
MODULE_FIRMWARE("radeon/hainan_k_smc.bin");
+MODULE_FIRMWARE("radeon/banks_k_2_smc.bin");
+
+MODULE_FIRMWARE("radeon/si58_mc.bin");
static u32 si_get_cu_active_bitmap(struct radeon_device *rdev, u32 se, u32 sh);
static void si_pcie_gen3_enable(struct radeon_device *rdev);
int err;
int new_fw = 0;
bool new_smc = false;
+ bool si58_fw = false;
+ bool banks2_fw = false;
DRM_DEBUG("\n");
switch (rdev->family) {
case CHIP_TAHITI:
chip_name = "TAHITI";
- /* XXX: figure out which Tahitis need the new ucode */
- if (0)
- new_smc = true;
new_chip_name = "tahiti";
pfp_req_size = SI_PFP_UCODE_SIZE * 4;
me_req_size = SI_PM4_UCODE_SIZE * 4;
break;
case CHIP_PITCAIRN:
chip_name = "PITCAIRN";
- if ((rdev->pdev->revision == 0x81) ||
- (rdev->pdev->device == 0x6810) ||
- (rdev->pdev->device == 0x6811) ||
- (rdev->pdev->device == 0x6816) ||
- (rdev->pdev->device == 0x6817) ||
- (rdev->pdev->device == 0x6806))
+ if ((rdev->pdev->revision == 0x81) &&
+ ((rdev->pdev->device == 0x6810) ||
+ (rdev->pdev->device == 0x6811)))
new_smc = true;
new_chip_name = "pitcairn";
pfp_req_size = SI_PFP_UCODE_SIZE * 4;
break;
case CHIP_VERDE:
chip_name = "VERDE";
- if ((rdev->pdev->revision == 0x81) ||
- (rdev->pdev->revision == 0x83) ||
- (rdev->pdev->revision == 0x87) ||
- (rdev->pdev->device == 0x6820) ||
- (rdev->pdev->device == 0x6821) ||
- (rdev->pdev->device == 0x6822) ||
- (rdev->pdev->device == 0x6823) ||
- (rdev->pdev->device == 0x682A) ||
- (rdev->pdev->device == 0x682B))
+ if (((rdev->pdev->device == 0x6820) &&
+ ((rdev->pdev->revision == 0x81) ||
+ (rdev->pdev->revision == 0x83))) ||
+ ((rdev->pdev->device == 0x6821) &&
+ ((rdev->pdev->revision == 0x83) ||
+ (rdev->pdev->revision == 0x87))) ||
+ ((rdev->pdev->revision == 0x87) &&
+ ((rdev->pdev->device == 0x6823) ||
+ (rdev->pdev->device == 0x682b))))
new_smc = true;
new_chip_name = "verde";
pfp_req_size = SI_PFP_UCODE_SIZE * 4;
break;
case CHIP_OLAND:
chip_name = "OLAND";
- if ((rdev->pdev->revision == 0xC7) ||
- (rdev->pdev->revision == 0x80) ||
- (rdev->pdev->revision == 0x81) ||
- (rdev->pdev->revision == 0x83) ||
- (rdev->pdev->revision == 0x87) ||
- (rdev->pdev->device == 0x6604) ||
- (rdev->pdev->device == 0x6605))
+ if (((rdev->pdev->revision == 0x81) &&
+ ((rdev->pdev->device == 0x6600) ||
+ (rdev->pdev->device == 0x6604) ||
+ (rdev->pdev->device == 0x6605) ||
+ (rdev->pdev->device == 0x6610))) ||
+ ((rdev->pdev->revision == 0x83) &&
+ (rdev->pdev->device == 0x6610)))
new_smc = true;
new_chip_name = "oland";
pfp_req_size = SI_PFP_UCODE_SIZE * 4;
break;
case CHIP_HAINAN:
chip_name = "HAINAN";
- if ((rdev->pdev->revision == 0x81) ||
- (rdev->pdev->revision == 0x83) ||
- (rdev->pdev->revision == 0xC3) ||
- (rdev->pdev->device == 0x6664) ||
- (rdev->pdev->device == 0x6665) ||
- (rdev->pdev->device == 0x6667))
+ if (((rdev->pdev->revision == 0x81) &&
+ (rdev->pdev->device == 0x6660)) ||
+ ((rdev->pdev->revision == 0x83) &&
+ ((rdev->pdev->device == 0x6660) ||
+ (rdev->pdev->device == 0x6663) ||
+ (rdev->pdev->device == 0x6665) ||
+ (rdev->pdev->device == 0x6667))))
new_smc = true;
+ else if ((rdev->pdev->revision == 0xc3) &&
+ (rdev->pdev->device == 0x6665))
+ banks2_fw = true;
new_chip_name = "hainan";
pfp_req_size = SI_PFP_UCODE_SIZE * 4;
me_req_size = SI_PM4_UCODE_SIZE * 4;
default: BUG();
}
+ /* this memory configuration requires special firmware */
+ if (((RREG32(MC_SEQ_MISC0) & 0xff000000) >> 24) == 0x58)
+ si58_fw = true;
+
DRM_INFO("Loading %s Microcode\n", new_chip_name);
snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", new_chip_name);
}
}
- snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", new_chip_name);
+ if (si58_fw)
+ snprintf(fw_name, sizeof(fw_name), "radeon/si58_mc.bin");
+ else
+ snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", new_chip_name);
err = request_firmware(&rdev->mc_fw, fw_name, rdev->dev);
if (err) {
snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc2.bin", chip_name);
}
}
- if (new_smc)
+ if (banks2_fw)
+ snprintf(fw_name, sizeof(fw_name), "radeon/banks_k_2_smc.bin");
+ else if (new_smc)
snprintf(fw_name, sizeof(fw_name), "radeon/%s_k_smc.bin", new_chip_name);
else
snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", new_chip_name);
(rdev->pdev->device == 0x6817) ||
(rdev->pdev->device == 0x6806))
max_mclk = 120000;
- } else if (rdev->family == CHIP_VERDE) {
- if ((rdev->pdev->revision == 0x81) ||
- (rdev->pdev->revision == 0x83) ||
- (rdev->pdev->revision == 0x87) ||
- (rdev->pdev->device == 0x6820) ||
- (rdev->pdev->device == 0x6821) ||
- (rdev->pdev->device == 0x6822) ||
- (rdev->pdev->device == 0x6823) ||
- (rdev->pdev->device == 0x682A) ||
- (rdev->pdev->device == 0x682B)) {
- max_sclk = 75000;
- max_mclk = 80000;
- }
- } else if (rdev->family == CHIP_OLAND) {
- if ((rdev->pdev->revision == 0xC7) ||
- (rdev->pdev->revision == 0x80) ||
- (rdev->pdev->revision == 0x81) ||
- (rdev->pdev->revision == 0x83) ||
- (rdev->pdev->revision == 0x87) ||
- (rdev->pdev->device == 0x6604) ||
- (rdev->pdev->device == 0x6605)) {
- max_sclk = 75000;
- max_mclk = 80000;
- }
} else if (rdev->family == CHIP_HAINAN) {
if ((rdev->pdev->revision == 0x81) ||
(rdev->pdev->revision == 0x83) ||
(rdev->pdev->device == 0x6665) ||
(rdev->pdev->device == 0x6667)) {
max_sclk = 75000;
- max_mclk = 80000;
}
}
/* Apply dpm quirks */
struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
struct drm_device *dev = crtc->dev;
struct tilcdc_drm_private *priv = dev->dev_private;
- uint32_t stat;
+ uint32_t stat, reg;
stat = tilcdc_read_irqstatus(dev);
tilcdc_clear_irqstatus(dev, stat);
dev_err_ratelimited(dev->dev, "%s(0x%08x): Sync lost",
__func__, stat);
tilcdc_crtc->frame_intact = false;
- if (tilcdc_crtc->sync_lost_count++ >
- SYNC_LOST_COUNT_LIMIT) {
- dev_err(dev->dev, "%s(0x%08x): Sync lost flood detected, recovering", __func__, stat);
- queue_work(system_wq, &tilcdc_crtc->recover_work);
- if (priv->rev == 1)
+ if (priv->rev == 1) {
+ reg = tilcdc_read(dev, LCDC_RASTER_CTRL_REG);
+ if (reg & LCDC_RASTER_ENABLE) {
tilcdc_clear(dev, LCDC_RASTER_CTRL_REG,
- LCDC_V1_SYNC_LOST_INT_ENA);
- else
+ LCDC_RASTER_ENABLE);
+ tilcdc_set(dev, LCDC_RASTER_CTRL_REG,
+ LCDC_RASTER_ENABLE);
+ }
+ } else {
+ if (tilcdc_crtc->sync_lost_count++ >
+ SYNC_LOST_COUNT_LIMIT) {
+ dev_err(dev->dev,
+ "%s(0x%08x): Sync lost flood detected, recovering",
+ __func__, stat);
+ queue_work(system_wq,
+ &tilcdc_crtc->recover_work);
tilcdc_write(dev, LCDC_INT_ENABLE_CLR_REG,
LCDC_SYNC_LOST);
- tilcdc_crtc->sync_lost_count = 0;
+ tilcdc_crtc->sync_lost_count = 0;
+ }
}
}
}
- __drm_atomic_helper_crtc_destroy_state(state);
+ drm_atomic_helper_crtc_destroy_state(crtc, state);
}
static const struct drm_crtc_funcs vc4_crtc_funcs = {
args->shader_rec_count);
struct vc4_bo *bo;
- if (uniforms_offset < shader_rec_offset ||
+ if (shader_rec_offset < args->bin_cl_size ||
+ uniforms_offset < shader_rec_offset ||
exec_size < uniforms_offset ||
args->shader_rec_count >= (UINT_MAX /
sizeof(struct vc4_shader_state)) ||
temp_size < exec_size) {
DRM_ERROR("overflow in exec arguments\n");
+ ret = -EINVAL;
goto fail;
}
}
ret = vc4_full_res_bounds_check(exec, *obj, surf);
- if (!ret)
+ if (ret)
return ret;
return 0;
info->fbops = &virtio_gpufb_ops;
info->pixmap.flags = FB_PIXMAP_SYSTEM;
- info->screen_base = obj->vmap;
+ info->screen_buffer = obj->vmap;
info->screen_size = obj->gem_base.size;
drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
drm_fb_helper_fill_var(info, &vfbdev->helper,
{ HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0002) },
{ HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0003) },
{ HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0004) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_PETZL, USB_DEVICE_ID_PETZL_HEADLAMP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_PHILIPS, USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_POWERCOM, USB_DEVICE_ID_POWERCOM_UPS) },
#if IS_ENABLED(CONFIG_MOUSE_SYNAPTICS_USB)
struct usb_interface *usbif = to_usb_interface(dev->parent);
struct usb_device *usbdev = interface_to_usbdev(usbif);
int brightness;
- char data[8];
+ char *data;
+
+ data = kmalloc(8, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0),
K90_REQUEST_STATUS,
USB_DIR_IN | USB_TYPE_VENDOR |
USB_RECIP_DEVICE, 0, 0, data, 8,
USB_CTRL_SET_TIMEOUT);
- if (ret < 0) {
+ if (ret < 5) {
dev_warn(dev, "Failed to get K90 initial state (error %d).\n",
ret);
- return -EIO;
+ ret = -EIO;
+ goto out;
}
brightness = data[4];
if (brightness < 0 || brightness > 3) {
dev_warn(dev,
"Read invalid backlight brightness: %02hhx.\n",
data[4]);
- return -EIO;
+ ret = -EIO;
+ goto out;
}
- return brightness;
+ ret = brightness;
+out:
+ kfree(data);
+
+ return ret;
}
static enum led_brightness k90_record_led_get(struct led_classdev *led_cdev)
struct usb_interface *usbif = to_usb_interface(dev->parent);
struct usb_device *usbdev = interface_to_usbdev(usbif);
const char *macro_mode;
- char data[8];
+ char *data;
+
+ data = kmalloc(2, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0),
K90_REQUEST_GET_MODE,
USB_DIR_IN | USB_TYPE_VENDOR |
USB_RECIP_DEVICE, 0, 0, data, 2,
USB_CTRL_SET_TIMEOUT);
- if (ret < 0) {
+ if (ret < 1) {
dev_warn(dev, "Failed to get K90 initial mode (error %d).\n",
ret);
- return -EIO;
+ ret = -EIO;
+ goto out;
}
switch (data[0]) {
default:
dev_warn(dev, "K90 in unknown mode: %02hhx.\n",
data[0]);
- return -EIO;
+ ret = -EIO;
+ goto out;
}
- return snprintf(buf, PAGE_SIZE, "%s\n", macro_mode);
+ ret = snprintf(buf, PAGE_SIZE, "%s\n", macro_mode);
+out:
+ kfree(data);
+
+ return ret;
}
static ssize_t k90_store_macro_mode(struct device *dev,
struct usb_interface *usbif = to_usb_interface(dev->parent);
struct usb_device *usbdev = interface_to_usbdev(usbif);
int current_profile;
- char data[8];
+ char *data;
+
+ data = kmalloc(8, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0),
K90_REQUEST_STATUS,
USB_DIR_IN | USB_TYPE_VENDOR |
USB_RECIP_DEVICE, 0, 0, data, 8,
USB_CTRL_SET_TIMEOUT);
- if (ret < 0) {
+ if (ret < 8) {
dev_warn(dev, "Failed to get K90 initial state (error %d).\n",
ret);
- return -EIO;
+ ret = -EIO;
+ goto out;
}
current_profile = data[7];
if (current_profile < 1 || current_profile > 3) {
dev_warn(dev, "Read invalid current profile: %02hhx.\n",
data[7]);
- return -EIO;
+ ret = -EIO;
+ goto out;
}
- return snprintf(buf, PAGE_SIZE, "%d\n", current_profile);
+ ret = snprintf(buf, PAGE_SIZE, "%d\n", current_profile);
+out:
+ kfree(data);
+
+ return ret;
}
static ssize_t k90_store_current_profile(struct device *dev,
atomic_t xfer_avail;
struct gpio_chip gc;
u8 *in_out_buffer;
- spinlock_t lock;
+ struct mutex lock;
struct gpio_desc *desc[8];
bool gpio_poll;
struct cp2112_device *dev = gpiochip_get_data(chip);
struct hid_device *hdev = dev->hdev;
u8 *buf = dev->in_out_buffer;
- unsigned long flags;
int ret;
- spin_lock_irqsave(&dev->lock, flags);
+ mutex_lock(&dev->lock);
ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf,
CP2112_GPIO_CONFIG_LENGTH, HID_FEATURE_REPORT,
ret = 0;
exit:
- spin_unlock_irqrestore(&dev->lock, flags);
- return ret <= 0 ? ret : -EIO;
+ mutex_unlock(&dev->lock);
+ return ret < 0 ? ret : -EIO;
}
static void cp2112_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
struct cp2112_device *dev = gpiochip_get_data(chip);
struct hid_device *hdev = dev->hdev;
u8 *buf = dev->in_out_buffer;
- unsigned long flags;
int ret;
- spin_lock_irqsave(&dev->lock, flags);
+ mutex_lock(&dev->lock);
buf[0] = CP2112_GPIO_SET;
buf[1] = value ? 0xff : 0;
if (ret < 0)
hid_err(hdev, "error setting GPIO values: %d\n", ret);
- spin_unlock_irqrestore(&dev->lock, flags);
+ mutex_unlock(&dev->lock);
}
static int cp2112_gpio_get_all(struct gpio_chip *chip)
struct cp2112_device *dev = gpiochip_get_data(chip);
struct hid_device *hdev = dev->hdev;
u8 *buf = dev->in_out_buffer;
- unsigned long flags;
int ret;
- spin_lock_irqsave(&dev->lock, flags);
+ mutex_lock(&dev->lock);
ret = hid_hw_raw_request(hdev, CP2112_GPIO_GET, buf,
CP2112_GPIO_GET_LENGTH, HID_FEATURE_REPORT,
ret = buf[1];
exit:
- spin_unlock_irqrestore(&dev->lock, flags);
+ mutex_unlock(&dev->lock);
return ret;
}
struct cp2112_device *dev = gpiochip_get_data(chip);
struct hid_device *hdev = dev->hdev;
u8 *buf = dev->in_out_buffer;
- unsigned long flags;
int ret;
- spin_lock_irqsave(&dev->lock, flags);
+ mutex_lock(&dev->lock);
ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf,
CP2112_GPIO_CONFIG_LENGTH, HID_FEATURE_REPORT,
goto fail;
}
- spin_unlock_irqrestore(&dev->lock, flags);
+ mutex_unlock(&dev->lock);
/*
* Set gpio value when output direction is already set,
return 0;
fail:
- spin_unlock_irqrestore(&dev->lock, flags);
+ mutex_unlock(&dev->lock);
return ret < 0 ? ret : -EIO;
}
if (!dev->in_out_buffer)
return -ENOMEM;
- spin_lock_init(&dev->lock);
+ mutex_init(&dev->lock);
ret = hid_parse(hdev);
if (ret) {
if (!(quirks & CP_RDESC_SWAPPED_MIN_MAX))
return rdesc;
+ if (*rsize < 4)
+ return rdesc;
+
for (i = 0; i < *rsize - 4; i++)
if (rdesc[i] == 0x29 && rdesc[i + 2] == 0x19) {
rdesc[i] = 0x19;
#define USB_VENDOR_ID_ALPS_JP 0x044E
#define HID_DEVICE_ID_ALPS_U1_DUAL 0x120B
+#define USB_VENDOR_ID_AMI 0x046b
+#define USB_DEVICE_ID_AMI_VIRT_KEYBOARD_AND_MOUSE 0xff10
+
#define USB_VENDOR_ID_ANTON 0x1130
#define USB_DEVICE_ID_ANTON_TOUCH_PAD 0x3101
#define USB_VENDOR_ID_PETALYNX 0x18b1
#define USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE 0x0037
+#define USB_VENDOR_ID_PETZL 0x2122
+#define USB_DEVICE_ID_PETZL_HEADLAMP 0x1234
+
#define USB_VENDOR_ID_PHILIPS 0x0471
#define USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE 0x0617
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG),
.driver_data = LG_NOGET | LG_FF4 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
- .driver_data = LG_FF2 },
+ .driver_data = LG_NOGET | LG_FF2 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940),
.driver_data = LG_FF3 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR),
if (ret)
goto out_unlock;
+ /*
+ * The HID over I2C specification states that if a DEVICE needs time
+ * after the PWR_ON request, it should utilise CLOCK stretching.
+ * However, it has been observered that the Windows driver provides a
+ * 1ms sleep between the PWR_ON and RESET requests and that some devices
+ * rely on this.
+ */
+ usleep_range(1000, 5000);
+
i2c_hid_dbg(ihid, "resetting...\n");
ret = i2c_hid_command(client, &hid_reset_cmd, NULL, 0);
{ USB_VENDOR_ID_AIREN, USB_DEVICE_ID_AIREN_SLIMPLUS, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_AKAI, USB_DEVICE_ID_AKAI_MPKMINI2, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_AKAI_09E8, USB_DEVICE_ID_AKAI_09E8_MIDIMIX, HID_QUIRK_NO_INIT_REPORTS },
+ { USB_VENDOR_ID_AMI, USB_DEVICE_ID_AMI_VIRT_KEYBOARD_AND_MOUSE, HID_QUIRK_ALWAYS_POLL },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
return retval;
}
+ if (wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH)
+ wacom_wac->shared->touch = hdev;
+ else if (wacom_wac->features.device_type & WACOM_DEVICETYPE_PEN)
+ wacom_wac->shared->pen = hdev;
+
out:
mutex_unlock(&wacom_udev_list_lock);
return retval;
if (error)
goto fail;
- error = wacom_add_shared_data(hdev);
- if (error)
- goto fail;
-
/*
* Bamboo Pad has a generic hid handling for the Pen, and we switch it
* into debug mode for the touch part.
wacom_update_name(wacom, wireless ? " (WL)" : "");
- if (wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH)
- wacom_wac->shared->touch = hdev;
- else if (wacom_wac->features.device_type & WACOM_DEVICETYPE_PEN)
- wacom_wac->shared->pen = hdev;
+ error = wacom_add_shared_data(hdev);
+ if (error)
+ goto fail;
if (!(features->device_type & WACOM_DEVICETYPE_WL_MONITOR) &&
(features->quirks & WACOM_QUIRK_BATTERY)) {
wacom->id[0] = STYLUS_DEVICE_ID;
}
- pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1));
- if (features->pressure_max > 255)
- pressure = (pressure << 1) | ((data[4] >> 6) & 1);
- pressure += (features->pressure_max + 1) / 2;
+ if (prox) {
+ pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1));
+ if (features->pressure_max > 255)
+ pressure = (pressure << 1) | ((data[4] >> 6) & 1);
+ pressure += (features->pressure_max + 1) / 2;
- input_report_abs(input, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14));
- input_report_abs(input, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14));
- input_report_abs(input, ABS_PRESSURE, pressure);
+ input_report_abs(input, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14));
+ input_report_abs(input, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14));
+ input_report_abs(input, ABS_PRESSURE, pressure);
- input_report_key(input, BTN_TOUCH, data[4] & 0x08);
- input_report_key(input, BTN_STYLUS, data[4] & 0x10);
- /* Only allow the stylus2 button to be reported for the pen tool. */
- input_report_key(input, BTN_STYLUS2, (wacom->tool[0] == BTN_TOOL_PEN) && (data[4] & 0x20));
+ input_report_key(input, BTN_TOUCH, data[4] & 0x08);
+ input_report_key(input, BTN_STYLUS, data[4] & 0x10);
+ /* Only allow the stylus2 button to be reported for the pen tool. */
+ input_report_key(input, BTN_STYLUS2, (wacom->tool[0] == BTN_TOOL_PEN) && (data[4] & 0x20));
+ }
if (!prox)
wacom->id[0] = 0;
wacom_report_events(hdev, report);
+ /*
+ * Non-input reports may be sent prior to the device being
+ * completely initialized. Since only their events need
+ * to be processed, exit after 'wacom_report_events' has
+ * been called to prevent potential crashes in the report-
+ * processing functions.
+ */
+ if (report->type != HID_INPUT_REPORT)
+ return;
+
if (WACOM_PAD_FIELD(field)) {
wacom_wac_pad_battery_report(hdev, report);
if (wacom->wacom_wac.pad_input)
return ret;
}
+ init_cached_read_index(channel);
next_read_location = hv_get_next_read_location(inring_info);
next_read_location = hv_copyfrom_ringbuffer(inring_info, &desc,
sizeof(desc),
goto err_clk_dis;
}
- ret = i2c_add_adapter(&id->adap);
- if (ret < 0)
- goto err_clk_dis;
-
/*
* Cadence I2C controller has a bug wherein it generates
* invalid read transaction after HW timeout in master receiver mode.
*/
cdns_i2c_writereg(CDNS_I2C_TIMEOUT_MAX, CDNS_I2C_TIME_OUT_OFFSET);
+ ret = i2c_add_adapter(&id->adap);
+ if (ret < 0)
+ goto err_clk_dis;
+
dev_info(&pdev->dev, "%u kHz mmio %08lx irq %d\n",
id->i2c_clk / 1000, (unsigned long)r_mem->start, id->irq);
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/slab.h>
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int lpi2c_imx_suspend(struct device *dev)
+{
+ pinctrl_pm_select_sleep_state(dev);
+
+ return 0;
+}
+
+static int lpi2c_imx_resume(struct device *dev)
+{
+ pinctrl_pm_select_default_state(dev);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(imx_lpi2c_pm, lpi2c_imx_suspend, lpi2c_imx_resume);
+
static struct platform_driver lpi2c_imx_driver = {
.probe = lpi2c_imx_probe,
.remove = lpi2c_imx_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = lpi2c_imx_of_match,
+ .pm = &imx_lpi2c_pm,
},
};
u8 command, int size, union i2c_smbus_data *data)
{
struct i2c_piix4_adapdata *adapdata = i2c_get_adapdata(adap);
+ unsigned short piix4_smba = adapdata->smba;
+ int retries = MAX_TIMEOUT;
+ int smbslvcnt;
u8 smba_en_lo;
u8 port;
int retval;
+ /* Request the SMBUS semaphore, avoid conflicts with the IMC */
+ smbslvcnt = inb_p(SMBSLVCNT);
+ do {
+ outb_p(smbslvcnt | 0x10, SMBSLVCNT);
+
+ /* Check the semaphore status */
+ smbslvcnt = inb_p(SMBSLVCNT);
+ if (smbslvcnt & 0x10)
+ break;
+
+ usleep_range(1000, 2000);
+ } while (--retries);
+ /* SMBus is still owned by the IMC, we give up */
+ if (!retries)
+ return -EBUSY;
+
mutex_lock(&piix4_mutex_sb800);
outb_p(piix4_port_sel_sb800, SB800_PIIX4_SMB_IDX);
mutex_unlock(&piix4_mutex_sb800);
+ /* Release the semaphore */
+ outb_p(smbslvcnt | 0x20, SMBSLVCNT);
+
return retval;
}
if (!client->irq) {
int irq = -ENOENT;
- if (dev->of_node) {
+ if (client->flags & I2C_CLIENT_HOST_NOTIFY) {
+ dev_dbg(dev, "Using Host Notify IRQ\n");
+ irq = i2c_smbus_host_notify_to_irq(client);
+ } else if (dev->of_node) {
irq = of_irq_get_byname(dev->of_node, "irq");
if (irq == -EINVAL || irq == -ENODATA)
irq = of_irq_get(dev->of_node, 0);
}
if (irq == -EPROBE_DEFER)
return irq;
- /*
- * ACPI and OF did not find any useful IRQ, try to see
- * if Host Notify can be used.
- */
- if (irq < 0) {
- dev_dbg(dev, "Using Host Notify IRQ\n");
- irq = i2c_smbus_host_notify_to_irq(client);
- }
+
if (irq < 0)
irq = 0;
if (i2c_check_addr_validity(addr, info.flags)) {
dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n",
- info.addr, node->full_name);
+ addr, node->full_name);
return ERR_PTR(-EINVAL);
}
info.of_node = of_node_get(node);
info.archdata = &dev_ad;
+ if (of_property_read_bool(node, "host-notify"))
+ info.flags |= I2C_CLIENT_HOST_NOTIFY;
+
if (of_get_property(node, "wakeup-source", NULL))
info.flags |= I2C_CLIENT_WAKE;
int ret;
if (!client || !slave_cb) {
- WARN(1, "insufficent data\n");
+ WARN(1, "insufficient data\n");
return -EINVAL;
}
unsigned long arg)
{
struct i2c_smbus_ioctl_data data_arg;
- union i2c_smbus_data temp;
+ union i2c_smbus_data temp = {};
int datasize, res;
if (copy_from_user(&data_arg,
config IIO_ST_ACCEL_3AXIS
tristate "STMicroelectronics accelerometers 3-Axis Driver"
depends on (I2C || SPI_MASTER) && SYSFS
+ depends on !SENSORS_LIS3_I2C
+ depends on !SENSORS_LIS3_SPI
select IIO_ST_SENSORS_CORE
select IIO_ST_ACCEL_I2C_3AXIS if (I2C)
select IIO_ST_ACCEL_SPI_3AXIS if (SPI_MASTER)
if (block_supported) {
indio_dev->modes |= INDIO_BUFFER_SOFTWARE;
indio_dev->info = &bmc150_accel_info_fifo;
- indio_dev->buffer->attrs = bmc150_accel_fifo_attributes;
+ iio_buffer_set_attrs(indio_dev->buffer,
+ bmc150_accel_fifo_attributes);
}
}
struct hid_sensor_hub_callbacks callbacks;
struct hid_sensor_common common_attributes;
struct hid_sensor_hub_attribute_info accel[ACCEL_3D_CHANNEL_MAX];
- u32 accel_val[ACCEL_3D_CHANNEL_MAX];
+ /* Reserve for 3 channels + padding + timestamp */
+ u32 accel_val[ACCEL_3D_CHANNEL_MAX + 3];
int scale_pre_decml;
int scale_post_decml;
int scale_precision;
int value_offset;
+ int64_t timestamp;
};
static const u32 accel_3d_addresses[ACCEL_3D_CHANNEL_MAX] = {
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_Z,
+ },
+ IIO_CHAN_SOFT_TIMESTAMP(3)
+};
+
+/* Channel definitions */
+static const struct iio_chan_spec gravity_channels[] = {
+ {
+ .type = IIO_GRAVITY,
+ .modified = 1,
+ .channel2 = IIO_MOD_X,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_HYSTERESIS),
+ .scan_index = CHANNEL_SCAN_INDEX_X,
+ }, {
+ .type = IIO_GRAVITY,
+ .modified = 1,
+ .channel2 = IIO_MOD_Y,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_HYSTERESIS),
+ .scan_index = CHANNEL_SCAN_INDEX_Y,
+ }, {
+ .type = IIO_GRAVITY,
+ .modified = 1,
+ .channel2 = IIO_MOD_Z,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_HYSTERESIS),
+ .scan_index = CHANNEL_SCAN_INDEX_Z,
}
};
int report_id = -1;
u32 address;
int ret_type;
+ struct hid_sensor_hub_device *hsdev =
+ accel_state->common_attributes.hsdev;
*val = 0;
*val2 = 0;
if (report_id >= 0)
*val = sensor_hub_input_attr_get_raw_value(
accel_state->common_attributes.hsdev,
- HID_USAGE_SENSOR_ACCEL_3D, address,
- report_id,
+ hsdev->usage, address, report_id,
SENSOR_HUB_SYNC);
else {
*val = 0;
};
/* Function to push data to buffer */
-static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data,
- int len)
+static void hid_sensor_push_data(struct iio_dev *indio_dev, void *data,
+ int len, int64_t timestamp)
{
dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
- iio_push_to_buffers(indio_dev, data);
+ iio_push_to_buffers_with_timestamp(indio_dev, data, timestamp);
}
/* Callback handler to send event after all samples are received and captured */
struct accel_3d_state *accel_state = iio_priv(indio_dev);
dev_dbg(&indio_dev->dev, "accel_3d_proc_event\n");
- if (atomic_read(&accel_state->common_attributes.data_ready))
+ if (atomic_read(&accel_state->common_attributes.data_ready)) {
+ if (!accel_state->timestamp)
+ accel_state->timestamp = iio_get_time_ns(indio_dev);
+
hid_sensor_push_data(indio_dev,
- accel_state->accel_val,
- sizeof(accel_state->accel_val));
+ accel_state->accel_val,
+ sizeof(accel_state->accel_val),
+ accel_state->timestamp);
+
+ accel_state->timestamp = 0;
+ }
return 0;
}
*(u32 *)raw_data;
ret = 0;
break;
+ case HID_USAGE_SENSOR_TIME_TIMESTAMP:
+ accel_state->timestamp =
+ hid_sensor_convert_timestamp(
+ &accel_state->common_attributes,
+ *(int64_t *)raw_data);
+ break;
default:
break;
}
st->accel[2].index, st->accel[2].report_id);
st->scale_precision = hid_sensor_format_scale(
- HID_USAGE_SENSOR_ACCEL_3D,
+ hsdev->usage,
&st->accel[CHANNEL_SCAN_INDEX_X],
&st->scale_pre_decml, &st->scale_post_decml);
static int hid_accel_3d_probe(struct platform_device *pdev)
{
int ret = 0;
- static const char *name = "accel_3d";
+ static const char *name;
struct iio_dev *indio_dev;
struct accel_3d_state *accel_state;
+ const struct iio_chan_spec *channel_spec;
+ int channel_size;
+
struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data;
indio_dev = devm_iio_device_alloc(&pdev->dev,
accel_state->common_attributes.hsdev = hsdev;
accel_state->common_attributes.pdev = pdev;
- ret = hid_sensor_parse_common_attributes(hsdev,
- HID_USAGE_SENSOR_ACCEL_3D,
+ if (hsdev->usage == HID_USAGE_SENSOR_ACCEL_3D) {
+ name = "accel_3d";
+ channel_spec = accel_3d_channels;
+ channel_size = sizeof(accel_3d_channels);
+ } else {
+ name = "gravity";
+ channel_spec = gravity_channels;
+ channel_size = sizeof(gravity_channels);
+ }
+ ret = hid_sensor_parse_common_attributes(hsdev, hsdev->usage,
&accel_state->common_attributes);
if (ret) {
dev_err(&pdev->dev, "failed to setup common attributes\n");
return ret;
}
+ indio_dev->channels = kmemdup(channel_spec, channel_size, GFP_KERNEL);
- indio_dev->channels = kmemdup(accel_3d_channels,
- sizeof(accel_3d_channels), GFP_KERNEL);
if (!indio_dev->channels) {
dev_err(&pdev->dev, "failed to duplicate channels\n");
return -ENOMEM;
}
-
ret = accel_3d_parse_report(pdev, hsdev,
- (struct iio_chan_spec *)indio_dev->channels,
- HID_USAGE_SENSOR_ACCEL_3D, accel_state);
+ (struct iio_chan_spec *)indio_dev->channels,
+ hsdev->usage, accel_state);
if (ret) {
dev_err(&pdev->dev, "failed to setup attributes\n");
goto error_free_dev_mem;
accel_state->callbacks.send_event = accel_3d_proc_event;
accel_state->callbacks.capture_sample = accel_3d_capture_sample;
accel_state->callbacks.pdev = pdev;
- ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_ACCEL_3D,
+ ret = sensor_hub_register_callback(hsdev, hsdev->usage,
&accel_state->callbacks);
if (ret < 0) {
dev_err(&pdev->dev, "callback reg failed\n");
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct accel_3d_state *accel_state = iio_priv(indio_dev);
- sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_ACCEL_3D);
+ sensor_hub_remove_callback(hsdev, hsdev->usage);
iio_device_unregister(indio_dev);
hid_sensor_remove_trigger(&accel_state->common_attributes);
iio_triggered_buffer_cleanup(indio_dev);
/* Format: HID-SENSOR-usage_id_in_hex_lowercase */
.name = "HID-SENSOR-200073",
},
+ { /* gravity sensor */
+ .name = "HID-SENSOR-20007b",
+ },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, hid_accel_3d_ids);
return -EINVAL;
}
-static int mma8452_get_odr_index(struct mma8452_data *data)
+static unsigned int mma8452_get_odr_index(struct mma8452_data *data)
{
return (data->ctrl_reg1 & MMA8452_CTRL_DR_MASK) >>
MMA8452_CTRL_DR_SHIFT;
};
/* Datasheet table: step time "Relationship with the ODR" (sample frequency) */
-static const int mma8452_transient_time_step_us[4][8] = {
+static const unsigned int mma8452_transient_time_step_us[4][8] = {
{ 1250, 2500, 5000, 10000, 20000, 20000, 20000, 20000 }, /* normal */
{ 1250, 2500, 5000, 10000, 20000, 80000, 80000, 80000 }, /* l p l n */
{ 1250, 2500, 2500, 2500, 2500, 2500, 2500, 2500 }, /* high res*/
#include <linux/iio/common/ssp_sensors.h>
#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
#include <linux/iio/kfifo_buf.h>
#include <linux/module.h>
#include <linux/platform_device.h>
platform_set_drvdata(pdev, indio_dev);
- ret = iio_device_register(indio_dev);
+ ret = devm_iio_device_register(&pdev->dev, indio_dev);
if (ret < 0)
return ret;
return 0;
}
-static int ssp_accel_remove(struct platform_device *pdev)
-{
- struct iio_dev *indio_dev = platform_get_drvdata(pdev);
-
- iio_device_unregister(indio_dev);
-
- return 0;
-}
-
static struct platform_driver ssp_accel_driver = {
.driver = {
.name = SSP_ACCEL_NAME,
},
.probe = ssp_accel_probe,
- .remove = ssp_accel_remove,
};
module_platform_driver(ssp_accel_driver);
#include <linux/types.h>
#include <linux/iio/common/st_sensors.h>
+enum st_accel_type {
+ LSM303DLH,
+ LSM303DLHC,
+ LIS3DH,
+ LSM330D,
+ LSM330DL,
+ LSM330DLC,
+ LIS331DLH,
+ LSM303DL,
+ LSM303DLM,
+ LSM330,
+ LSM303AGR,
+ LIS2DH12,
+ LIS3L02DQ,
+ LNG2DM,
+ ST_ACCEL_MAX,
+};
+
#define H3LIS331DL_DRIVER_NAME "h3lis331dl_accel"
#define LIS3LV02DL_ACCEL_DEV_NAME "lis3lv02dl_accel"
#define LSM303DLHC_ACCEL_DEV_NAME "lsm303dlhc_accel"
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#ifdef CONFIG_OF
static const struct of_device_id st_accel_of_match[] = {
+ {
+ /* An older compatible */
+ .compatible = "st,lis3lv02d",
+ .data = LIS3LV02DL_ACCEL_DEV_NAME,
+ },
{
.compatible = "st,lis3lv02dl-accel",
.data = LIS3LV02DL_ACCEL_DEV_NAME,
#define st_accel_of_match NULL
#endif
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id st_accel_acpi_match[] = {
+ {"SMO8A90", LNG2DM},
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, st_accel_acpi_match);
+#else
+#define st_accel_acpi_match NULL
+#endif
+
+static const struct i2c_device_id st_accel_id_table[] = {
+ { LSM303DLH_ACCEL_DEV_NAME, LSM303DLH },
+ { LSM303DLHC_ACCEL_DEV_NAME, LSM303DLHC },
+ { LIS3DH_ACCEL_DEV_NAME, LIS3DH },
+ { LSM330D_ACCEL_DEV_NAME, LSM330D },
+ { LSM330DL_ACCEL_DEV_NAME, LSM330DL },
+ { LSM330DLC_ACCEL_DEV_NAME, LSM330DLC },
+ { LIS331DLH_ACCEL_DEV_NAME, LIS331DLH },
+ { LSM303DL_ACCEL_DEV_NAME, LSM303DL },
+ { LSM303DLM_ACCEL_DEV_NAME, LSM303DLM },
+ { LSM330_ACCEL_DEV_NAME, LSM330 },
+ { LSM303AGR_ACCEL_DEV_NAME, LSM303AGR },
+ { LIS2DH12_ACCEL_DEV_NAME, LIS2DH12 },
+ { LIS3L02DQ_ACCEL_DEV_NAME, LIS3L02DQ },
+ { LNG2DM_ACCEL_DEV_NAME, LNG2DM },
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, st_accel_id_table);
+
static int st_accel_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct iio_dev *indio_dev;
struct st_sensor_data *adata;
- int err;
+ int ret;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*adata));
if (!indio_dev)
return -ENOMEM;
adata = iio_priv(indio_dev);
- st_sensors_of_i2c_probe(client, st_accel_of_match);
+
+ if (client->dev.of_node) {
+ st_sensors_of_i2c_probe(client, st_accel_of_match);
+ } else if (ACPI_HANDLE(&client->dev)) {
+ ret = st_sensors_match_acpi_device(&client->dev);
+ if ((ret < 0) || (ret >= ST_ACCEL_MAX))
+ return -ENODEV;
+
+ strncpy(client->name, st_accel_id_table[ret].name,
+ sizeof(client->name));
+ client->name[sizeof(client->name) - 1] = '\0';
+ } else if (!id)
+ return -ENODEV;
+
st_sensors_i2c_configure(indio_dev, client, adata);
- err = st_accel_common_probe(indio_dev);
- if (err < 0)
- return err;
+ ret = st_accel_common_probe(indio_dev);
+ if (ret < 0)
+ return ret;
return 0;
}
return 0;
}
-static const struct i2c_device_id st_accel_id_table[] = {
- { LSM303DLH_ACCEL_DEV_NAME },
- { LSM303DLHC_ACCEL_DEV_NAME },
- { LIS3DH_ACCEL_DEV_NAME },
- { LSM330D_ACCEL_DEV_NAME },
- { LSM330DL_ACCEL_DEV_NAME },
- { LSM330DLC_ACCEL_DEV_NAME },
- { LIS331DLH_ACCEL_DEV_NAME },
- { LSM303DL_ACCEL_DEV_NAME },
- { LSM303DLM_ACCEL_DEV_NAME },
- { LSM330_ACCEL_DEV_NAME },
- { LSM303AGR_ACCEL_DEV_NAME },
- { LIS2DH12_ACCEL_DEV_NAME },
- { LIS3L02DQ_ACCEL_DEV_NAME },
- { LNG2DM_ACCEL_DEV_NAME },
- {},
-};
-MODULE_DEVICE_TABLE(i2c, st_accel_id_table);
-
static struct i2c_driver st_accel_driver = {
.driver = {
.name = "st-accel-i2c",
.of_match_table = of_match_ptr(st_accel_of_match),
+ .acpi_match_table = ACPI_PTR(st_accel_acpi_match),
},
.probe = st_accel_i2c_probe,
.remove = st_accel_i2c_remove,
};
MODULE_DEVICE_TABLE(spi, st_accel_id_table);
+#ifdef CONFIG_OF
+static const struct of_device_id lis302dl_spi_dt_ids[] = {
+ { .compatible = "st,lis302dl-spi" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, lis302dl_spi_dt_ids);
+#endif
+
static struct spi_driver st_accel_driver = {
.driver = {
.name = "st-accel-spi",
+ .of_match_table = of_match_ptr(lis302dl_spi_dt_ids),
},
.probe = st_accel_spi_probe,
.remove = st_accel_spi_remove,
This driver can also be built as a module. If so, the module will be
called hi8435.
+config HX711
+ tristate "AVIA HX711 ADC for weight cells"
+ depends on GPIOLIB
+ help
+ If you say yes here you get support for AVIA HX711 ADC which is used
+ for weigh cells
+
+ This driver uses two GPIOs, one acts as the clock and controls the
+ channel selection and gain, the other one is used for the measurement
+ data
+
+ Currently the raw value is read from the chip and delivered.
+ To get an actual weight one needs to subtract the
+ zero offset and multiply by a scale factor.
+ This should be done in userspace.
+
+ This driver can also be built as a module. If so, the module will be
+ called hx711.
+
config INA2XX_ADC
tristate "Texas Instruments INA2xx Power Monitors IIO driver"
depends on I2C && !SENSORS_INA2XX
To compile this driver as a module, choose M here: the module will be
called max1027.
+config MAX11100
+ tristate "Maxim max11100 ADC driver"
+ depends on SPI_MASTER
+ help
+ Say yes here to build support for Maxim max11100 SPI ADC
+
+ To compile this driver as a module, choose M here: the module will be
+ called max11100.
+
config MAX1363
tristate "Maxim max1363 ADC driver"
depends on I2C
This driver can also be built as a module. If so, the module will be
called men_z188_adc.
+config MESON_SARADC
+ tristate "Amlogic Meson SAR ADC driver"
+ default ARCH_MESON
+ depends on OF && COMMON_CLK && (ARCH_MESON || COMPILE_TEST)
+ select REGMAP_MMIO
+ help
+ Say yes here to build support for the SAR ADC found in Amlogic Meson
+ SoCs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called meson_saradc.
+
config MXS_LRADC
tristate "Freescale i.MX23/i.MX28 LRADC"
depends on (ARCH_MXS || COMPILE_TEST) && HAS_IOMEM
To compile this driver as a module, choose M here: the module will
be called qcom-spmi-vadc.
+config RCAR_GYRO_ADC
+ tristate "Renesas R-Car GyroADC driver"
+ depends on ARCH_RCAR_GEN2 || (ARM && COMPILE_TEST)
+ help
+ Say yes here to build support for the GyroADC found in Renesas
+ R-Car Gen2 SoCs. This block is a simple SPI offload engine for
+ reading data out of attached compatible ADCs in a round-robin
+ fashion. Up to 4 or 8 ADC channels are supported by this block,
+ depending on which ADCs are attached.
+
+ To compile this driver as a module, choose M here: the
+ module will be called rcar-gyroadc.
+
config ROCKCHIP_SARADC
tristate "Rockchip SARADC driver"
depends on ARCH_ROCKCHIP || (ARM && COMPILE_TEST)
config STM32_ADC_CORE
tristate "STMicroelectronics STM32 adc core"
depends on ARCH_STM32 || COMPILE_TEST
+ depends on HAS_DMA
depends on OF
depends on REGULATOR
+ select IIO_BUFFER
+ select MFD_STM32_TIMERS
+ select IIO_STM32_TIMER_TRIGGER
+ select IIO_TRIGGERED_BUFFER
help
Select this option to enable the core driver for STMicroelectronics
STM32 analog-to-digital converter (ADC).
This driver can also be built as a module. If so, the module will be
called ti-ads1015.
+config TI_ADS7950
+ tristate "Texas Instruments ADS7950 ADC driver"
+ depends on SPI
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ help
+ Say yes here to build support for Texas Instruments ADS7950, ADS7951,
+ ADS7952, ADS7953, ADS7954, ADS7955, ADS7956, ADS7957, ADS7958, ADS7959.
+ ADS7960, ADS7961.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ti-ads7950.
+
config TI_ADS8688
tristate "Texas Instruments ADS8688"
depends on SPI && OF
To compile this driver as a module, choose M here: the module will be
called ti_am335x_adc.
+config TI_TLC4541
+ tristate "Texas Instruments TLC4541 ADC driver"
+ depends on SPI
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ help
+ Say yes here to build support for Texas Instruments TLC4541 / TLC3541
+ ADC chips.
+
+ This driver can also be built as a module. If so, the module will be
+ called ti-tlc4541.
+
config TWL4030_MADC
tristate "TWL4030 MADC (Monitoring A/D Converter)"
depends on TWL4030_CORE
obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
obj-$(CONFIG_FSL_MX25_ADC) += fsl-imx25-gcq.o
obj-$(CONFIG_HI8435) += hi8435.o
+obj-$(CONFIG_HX711) += hx711.o
obj-$(CONFIG_IMX7D_ADC) += imx7d_adc.o
obj-$(CONFIG_INA2XX_ADC) += ina2xx-adc.o
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
obj-$(CONFIG_LPC18XX_ADC) += lpc18xx_adc.o
obj-$(CONFIG_LTC2485) += ltc2485.o
obj-$(CONFIG_MAX1027) += max1027.o
+obj-$(CONFIG_MAX11100) += max11100.o
obj-$(CONFIG_MAX1363) += max1363.o
obj-$(CONFIG_MCP320X) += mcp320x.o
obj-$(CONFIG_MCP3422) += mcp3422.o
obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
+obj-$(CONFIG_MESON_SARADC) += meson_saradc.o
obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o
obj-$(CONFIG_NAU7802) += nau7802.o
obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o
obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o
+obj-$(CONFIG_RCAR_GYRO_ADC) += rcar-gyroadc.o
obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
obj-$(CONFIG_STX104) += stx104.o
obj-$(CONFIG_STM32_ADC_CORE) += stm32-adc-core.o
obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o
obj-$(CONFIG_TI_ADC161S626) += ti-adc161s626.o
obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o
+obj-$(CONFIG_TI_ADS7950) += ti-ads7950.o
obj-$(CONFIG_TI_ADS8688) += ti-ads8688.o
obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o
+obj-$(CONFIG_TI_TLC4541) += ti-tlc4541.o
obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o
obj-$(CONFIG_VF610_ADC) += vf610_adc.o
#include <linux/iio/driver.h>
#define AXP288_ADC_EN_MASK 0xF1
-#define AXP288_ADC_TS_PIN_GPADC 0xF2
-#define AXP288_ADC_TS_PIN_ON 0xF3
enum axp288_adc_id {
AXP288_ADC_TS,
return IIO_VAL_INT;
}
-static int axp288_adc_set_ts(struct regmap *regmap, unsigned int mode,
- unsigned long address)
-{
- /* channels other than GPADC do not need to switch TS pin */
- if (address != AXP288_GP_ADC_H)
- return 0;
-
- return regmap_write(regmap, AXP288_ADC_TS_PIN_CTRL, mode);
-}
-
static int axp288_adc_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
mutex_lock(&indio_dev->mlock);
switch (mask) {
case IIO_CHAN_INFO_RAW:
- if (axp288_adc_set_ts(info->regmap, AXP288_ADC_TS_PIN_GPADC,
- chan->address)) {
- dev_err(&indio_dev->dev, "GPADC mode\n");
- ret = -EINVAL;
- break;
- }
ret = axp288_adc_read_channel(val, chan->address, info->regmap);
- if (axp288_adc_set_ts(info->regmap, AXP288_ADC_TS_PIN_ON,
- chan->address))
- dev_err(&indio_dev->dev, "TS pin restore\n");
break;
default:
ret = -EINVAL;
return ret;
}
-static int axp288_adc_set_state(struct regmap *regmap)
-{
- /* ADC should be always enabled for internal FG to function */
- if (regmap_write(regmap, AXP288_ADC_TS_PIN_CTRL, AXP288_ADC_TS_PIN_ON))
- return -EIO;
-
- return regmap_write(regmap, AXP20X_ADC_EN1, AXP288_ADC_EN_MASK);
-}
-
static const struct iio_info axp288_adc_iio_info = {
.read_raw = &axp288_adc_read_raw,
.driver_module = THIS_MODULE,
* Set ADC to enabled state at all time, including system suspend.
* otherwise internal fuel gauge functionality may be affected.
*/
- ret = axp288_adc_set_state(axp20x->regmap);
+ ret = regmap_write(info->regmap, AXP20X_ADC_EN1, AXP288_ADC_EN_MASK);
if (ret) {
dev_err(&pdev->dev, "unable to enable ADC device\n");
return ret;
input_report_key(info->input, BTN_TOUCH, 1);
input_sync(info->input);
- msleep(1);
+ usleep_range(1000, 1100);
};
writel(0, ADC_V1_CLRINTPNDNUP(info->regs));
{ .compatible = "fsl,imx25-gcq", },
{ /* Sentinel */ }
};
+MODULE_DEVICE_TABLE(of, mx25_gcq_ids);
static struct platform_driver mx25_gcq_driver = {
.driver = {
--- /dev/null
+/*
+ * HX711: analog to digital converter for weight sensor module
+ *
+ * Copyright (c) 2016 Andreas Klinger <ak@it-klinger.de>
+ *
+ * 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/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/gpio/consumer.h>
+#include <linux/regulator/consumer.h>
+
+/* gain to pulse and scale conversion */
+#define HX711_GAIN_MAX 3
+
+struct hx711_gain_to_scale {
+ int gain;
+ int gain_pulse;
+ int scale;
+ int channel;
+};
+
+/*
+ * .scale depends on AVDD which in turn is known as soon as the regulator
+ * is available
+ * therefore we set .scale in hx711_probe()
+ *
+ * channel A in documentation is channel 0 in source code
+ * channel B in documentation is channel 1 in source code
+ */
+static struct hx711_gain_to_scale hx711_gain_to_scale[HX711_GAIN_MAX] = {
+ { 128, 1, 0, 0 },
+ { 32, 2, 0, 1 },
+ { 64, 3, 0, 0 }
+};
+
+static int hx711_get_gain_to_pulse(int gain)
+{
+ int i;
+
+ for (i = 0; i < HX711_GAIN_MAX; i++)
+ if (hx711_gain_to_scale[i].gain == gain)
+ return hx711_gain_to_scale[i].gain_pulse;
+ return 1;
+}
+
+static int hx711_get_gain_to_scale(int gain)
+{
+ int i;
+
+ for (i = 0; i < HX711_GAIN_MAX; i++)
+ if (hx711_gain_to_scale[i].gain == gain)
+ return hx711_gain_to_scale[i].scale;
+ return 0;
+}
+
+static int hx711_get_scale_to_gain(int scale)
+{
+ int i;
+
+ for (i = 0; i < HX711_GAIN_MAX; i++)
+ if (hx711_gain_to_scale[i].scale == scale)
+ return hx711_gain_to_scale[i].gain;
+ return -EINVAL;
+}
+
+struct hx711_data {
+ struct device *dev;
+ struct gpio_desc *gpiod_pd_sck;
+ struct gpio_desc *gpiod_dout;
+ struct regulator *reg_avdd;
+ int gain_set; /* gain set on device */
+ int gain_chan_a; /* gain for channel A */
+ struct mutex lock;
+};
+
+static int hx711_cycle(struct hx711_data *hx711_data)
+{
+ int val;
+
+ /*
+ * if preempted for more then 60us while PD_SCK is high:
+ * hx711 is going in reset
+ * ==> measuring is false
+ */
+ preempt_disable();
+ gpiod_set_value(hx711_data->gpiod_pd_sck, 1);
+ val = gpiod_get_value(hx711_data->gpiod_dout);
+ /*
+ * here we are not waiting for 0.2 us as suggested by the datasheet,
+ * because the oscilloscope showed in a test scenario
+ * at least 1.15 us for PD_SCK high (T3 in datasheet)
+ * and 0.56 us for PD_SCK low on TI Sitara with 800 MHz
+ */
+ gpiod_set_value(hx711_data->gpiod_pd_sck, 0);
+ preempt_enable();
+
+ return val;
+}
+
+static int hx711_read(struct hx711_data *hx711_data)
+{
+ int i, ret;
+ int value = 0;
+ int val = gpiod_get_value(hx711_data->gpiod_dout);
+
+ /* we double check if it's really down */
+ if (val)
+ return -EIO;
+
+ for (i = 0; i < 24; i++) {
+ value <<= 1;
+ ret = hx711_cycle(hx711_data);
+ if (ret)
+ value++;
+ }
+
+ value ^= 0x800000;
+
+ for (i = 0; i < hx711_get_gain_to_pulse(hx711_data->gain_set); i++)
+ hx711_cycle(hx711_data);
+
+ return value;
+}
+
+static int hx711_wait_for_ready(struct hx711_data *hx711_data)
+{
+ int i, val;
+
+ /*
+ * a maximum reset cycle time of 56 ms was measured.
+ * we round it up to 100 ms
+ */
+ for (i = 0; i < 100; i++) {
+ val = gpiod_get_value(hx711_data->gpiod_dout);
+ if (!val)
+ break;
+ /* sleep at least 1 ms */
+ msleep(1);
+ }
+ if (val)
+ return -EIO;
+
+ return 0;
+}
+
+static int hx711_reset(struct hx711_data *hx711_data)
+{
+ int ret;
+ int val = gpiod_get_value(hx711_data->gpiod_dout);
+
+ if (val) {
+ /*
+ * an examination with the oszilloscope indicated
+ * that the first value read after the reset is not stable
+ * if we reset too short;
+ * the shorter the reset cycle
+ * the less reliable the first value after reset is;
+ * there were no problems encountered with a value
+ * of 10 ms or higher
+ */
+ gpiod_set_value(hx711_data->gpiod_pd_sck, 1);
+ 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
+ */
+ ret = hx711_wait_for_ready(hx711_data);
+ if (ret)
+ return ret;
+ }
+
+ return val;
+}
+
+static int hx711_set_gain_for_channel(struct hx711_data *hx711_data, int chan)
+{
+ int ret;
+
+ if (chan == 0) {
+ if (hx711_data->gain_set == 32) {
+ hx711_data->gain_set = hx711_data->gain_chan_a;
+
+ ret = hx711_read(hx711_data);
+ if (ret < 0)
+ return ret;
+
+ ret = hx711_wait_for_ready(hx711_data);
+ if (ret)
+ return ret;
+ }
+ } else {
+ if (hx711_data->gain_set != 32) {
+ hx711_data->gain_set = 32;
+
+ ret = hx711_read(hx711_data);
+ if (ret < 0)
+ return ret;
+
+ ret = hx711_wait_for_ready(hx711_data);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int hx711_read_raw(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ int *val, int *val2, long mask)
+{
+ struct hx711_data *hx711_data = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ mutex_lock(&hx711_data->lock);
+
+ /*
+ * hx711_reset() must be called from here
+ * because it could be calling hx711_read() by itself
+ */
+ if (hx711_reset(hx711_data)) {
+ mutex_unlock(&hx711_data->lock);
+ dev_err(hx711_data->dev, "reset failed!");
+ return -EIO;
+ }
+
+ ret = hx711_set_gain_for_channel(hx711_data, chan->channel);
+ if (ret < 0) {
+ mutex_unlock(&hx711_data->lock);
+ return ret;
+ }
+
+ *val = hx711_read(hx711_data);
+
+ mutex_unlock(&hx711_data->lock);
+
+ if (*val < 0)
+ return *val;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = 0;
+ mutex_lock(&hx711_data->lock);
+
+ *val2 = hx711_get_gain_to_scale(hx711_data->gain_set);
+
+ mutex_unlock(&hx711_data->lock);
+
+ return IIO_VAL_INT_PLUS_NANO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int hx711_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val,
+ int val2,
+ long mask)
+{
+ struct hx711_data *hx711_data = iio_priv(indio_dev);
+ int ret;
+ int gain;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ /*
+ * a scale greater than 1 mV per LSB is not possible
+ * with the HX711, therefore val must be 0
+ */
+ if (val != 0)
+ return -EINVAL;
+
+ mutex_lock(&hx711_data->lock);
+
+ gain = hx711_get_scale_to_gain(val2);
+ if (gain < 0) {
+ mutex_unlock(&hx711_data->lock);
+ return gain;
+ }
+
+ if (gain != hx711_data->gain_set) {
+ hx711_data->gain_set = gain;
+ if (gain != 32)
+ hx711_data->gain_chan_a = gain;
+
+ ret = hx711_read(hx711_data);
+ if (ret < 0) {
+ mutex_unlock(&hx711_data->lock);
+ return ret;
+ }
+ }
+
+ mutex_unlock(&hx711_data->lock);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int hx711_write_raw_get_fmt(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ long mask)
+{
+ return IIO_VAL_INT_PLUS_NANO;
+}
+
+static ssize_t hx711_scale_available_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev_attr *iio_attr = to_iio_dev_attr(attr);
+ int channel = iio_attr->address;
+ int i, len = 0;
+
+ for (i = 0; i < HX711_GAIN_MAX; i++)
+ if (hx711_gain_to_scale[i].channel == channel)
+ len += sprintf(buf + len, "0.%09d ",
+ hx711_gain_to_scale[i].scale);
+
+ len += sprintf(buf + len, "\n");
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(in_voltage0_scale_available, S_IRUGO,
+ hx711_scale_available_show, NULL, 0);
+
+static IIO_DEVICE_ATTR(in_voltage1_scale_available, S_IRUGO,
+ hx711_scale_available_show, NULL, 1);
+
+static struct attribute *hx711_attributes[] = {
+ &iio_dev_attr_in_voltage0_scale_available.dev_attr.attr,
+ &iio_dev_attr_in_voltage1_scale_available.dev_attr.attr,
+ NULL,
+};
+
+static struct attribute_group hx711_attribute_group = {
+ .attrs = hx711_attributes,
+};
+
+static const struct iio_info hx711_iio_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = hx711_read_raw,
+ .write_raw = hx711_write_raw,
+ .write_raw_get_fmt = hx711_write_raw_get_fmt,
+ .attrs = &hx711_attribute_group,
+};
+
+static const struct iio_chan_spec hx711_chan_spec[] = {
+ {
+ .type = IIO_VOLTAGE,
+ .channel = 0,
+ .indexed = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+ },
+ {
+ .type = IIO_VOLTAGE,
+ .channel = 1,
+ .indexed = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+ },
+};
+
+static int hx711_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct hx711_data *hx711_data;
+ struct iio_dev *indio_dev;
+ int ret;
+ int i;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(struct hx711_data));
+ if (!indio_dev) {
+ dev_err(dev, "failed to allocate IIO device\n");
+ return -ENOMEM;
+ }
+
+ hx711_data = iio_priv(indio_dev);
+ hx711_data->dev = dev;
+
+ mutex_init(&hx711_data->lock);
+
+ /*
+ * PD_SCK stands for power down and serial clock input of HX711
+ * in the driver it is an output
+ */
+ hx711_data->gpiod_pd_sck = devm_gpiod_get(dev, "sck", GPIOD_OUT_LOW);
+ if (IS_ERR(hx711_data->gpiod_pd_sck)) {
+ dev_err(dev, "failed to get sck-gpiod: err=%ld\n",
+ PTR_ERR(hx711_data->gpiod_pd_sck));
+ return PTR_ERR(hx711_data->gpiod_pd_sck);
+ }
+
+ /*
+ * DOUT stands for serial data output of HX711
+ * for the driver it is an input
+ */
+ hx711_data->gpiod_dout = devm_gpiod_get(dev, "dout", GPIOD_IN);
+ if (IS_ERR(hx711_data->gpiod_dout)) {
+ dev_err(dev, "failed to get dout-gpiod: err=%ld\n",
+ PTR_ERR(hx711_data->gpiod_dout));
+ return PTR_ERR(hx711_data->gpiod_dout);
+ }
+
+ hx711_data->reg_avdd = devm_regulator_get(dev, "avdd");
+ if (IS_ERR(hx711_data->reg_avdd))
+ return PTR_ERR(hx711_data->reg_avdd);
+
+ ret = regulator_enable(hx711_data->reg_avdd);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * with
+ * full scale differential input range: AVDD / GAIN
+ * full scale output data: 2^24
+ * we can say:
+ * AVDD / GAIN = 2^24
+ * therefore:
+ * 1 LSB = AVDD / GAIN / 2^24
+ * AVDD is in uV, but we need 10^-9 mV
+ * approximately to fit into a 32 bit number:
+ * 1 LSB = (AVDD * 100) / GAIN / 1678 [10^-9 mV]
+ */
+ ret = regulator_get_voltage(hx711_data->reg_avdd);
+ if (ret < 0) {
+ regulator_disable(hx711_data->reg_avdd);
+ return ret;
+ }
+ /* we need 10^-9 mV */
+ ret *= 100;
+
+ for (i = 0; i < HX711_GAIN_MAX; i++)
+ hx711_gain_to_scale[i].scale =
+ ret / hx711_gain_to_scale[i].gain / 1678;
+
+ hx711_data->gain_set = 128;
+ hx711_data->gain_chan_a = 128;
+
+ platform_set_drvdata(pdev, indio_dev);
+
+ indio_dev->name = "hx711";
+ indio_dev->dev.parent = &pdev->dev;
+ indio_dev->info = &hx711_iio_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = hx711_chan_spec;
+ indio_dev->num_channels = ARRAY_SIZE(hx711_chan_spec);
+
+ ret = iio_device_register(indio_dev);
+ if (ret < 0) {
+ dev_err(dev, "Couldn't register the device\n");
+ regulator_disable(hx711_data->reg_avdd);
+ }
+
+ return ret;
+}
+
+static int hx711_remove(struct platform_device *pdev)
+{
+ struct hx711_data *hx711_data;
+ struct iio_dev *indio_dev;
+
+ indio_dev = platform_get_drvdata(pdev);
+ hx711_data = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+
+ regulator_disable(hx711_data->reg_avdd);
+
+ return 0;
+}
+
+static const struct of_device_id of_hx711_match[] = {
+ { .compatible = "avia,hx711", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, of_hx711_match);
+
+static struct platform_driver hx711_driver = {
+ .probe = hx711_probe,
+ .remove = hx711_remove,
+ .driver = {
+ .name = "hx711-gpio",
+ .of_match_table = of_hx711_match,
+ },
+};
+
+module_platform_driver(hx711_driver);
+
+MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>");
+MODULE_DESCRIPTION("HX711 bitbanging driver - ADC for weight cells");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:hx711-gpio");
+
#include <linux/delay.h>
#include <linux/i2c.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
#include <linux/iio/kfifo_buf.h>
#include <linux/iio/sysfs.h>
#include <linux/kthread.h>
--- /dev/null
+/*
+ * iio/adc/max11100.c
+ * Maxim max11100 ADC Driver with IIO interface
+ *
+ * Copyright (C) 2016-17 Renesas Electronics Corporation
+ * Copyright (C) 2016-17 Jacopo Mondi
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/driver.h>
+
+/*
+ * LSB is the ADC single digital step
+ * 1 LSB = (vref_mv / 2 ^ 16)
+ *
+ * LSB is used to calculate analog voltage value
+ * from the number of ADC steps count
+ *
+ * Ain = (count * LSB)
+ */
+#define MAX11100_LSB_DIV (1 << 16)
+
+struct max11100_state {
+ struct regulator *vref_reg;
+ struct spi_device *spi;
+
+ /*
+ * DMA (thus cache coherency maintenance) requires the
+ * transfer buffers to live in their own cache lines.
+ */
+ u8 buffer[3] ____cacheline_aligned;
+};
+
+static struct iio_chan_spec max11100_channels[] = {
+ { /* [0] */
+ .type = IIO_VOLTAGE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ },
+};
+
+static int max11100_read_single(struct iio_dev *indio_dev, int *val)
+{
+ int ret;
+ struct max11100_state *state = iio_priv(indio_dev);
+
+ ret = spi_read(state->spi, state->buffer, sizeof(state->buffer));
+ if (ret) {
+ dev_err(&indio_dev->dev, "SPI transfer failed\n");
+ return ret;
+ }
+
+ /* the first 8 bits sent out from ADC must be 0s */
+ if (state->buffer[0]) {
+ dev_err(&indio_dev->dev, "Invalid value: buffer[0] != 0\n");
+ return -EINVAL;
+ }
+
+ *val = (state->buffer[1] << 8) | state->buffer[2];
+
+ return 0;
+}
+
+static int max11100_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long info)
+{
+ int ret, vref_uv;
+ struct max11100_state *state = iio_priv(indio_dev);
+
+ switch (info) {
+ case IIO_CHAN_INFO_RAW:
+ ret = max11100_read_single(indio_dev, val);
+ if (ret)
+ return ret;
+
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ vref_uv = regulator_get_voltage(state->vref_reg);
+ if (vref_uv < 0)
+ /* dummy regulator "get_voltage" returns -EINVAL */
+ return -EINVAL;
+
+ *val = vref_uv / 1000;
+ *val2 = MAX11100_LSB_DIV;
+ return IIO_VAL_FRACTIONAL;
+ }
+
+ return -EINVAL;
+}
+
+static const struct iio_info max11100_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = max11100_read_raw,
+};
+
+static int max11100_probe(struct spi_device *spi)
+{
+ int ret;
+ struct iio_dev *indio_dev;
+ struct max11100_state *state;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*state));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ spi_set_drvdata(spi, indio_dev);
+
+ state = iio_priv(indio_dev);
+ state->spi = spi;
+
+ indio_dev->dev.parent = &spi->dev;
+ indio_dev->dev.of_node = spi->dev.of_node;
+ indio_dev->name = "max11100";
+ indio_dev->info = &max11100_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = max11100_channels,
+ indio_dev->num_channels = ARRAY_SIZE(max11100_channels),
+
+ state->vref_reg = devm_regulator_get(&spi->dev, "vref");
+ if (IS_ERR(state->vref_reg))
+ return PTR_ERR(state->vref_reg);
+
+ ret = regulator_enable(state->vref_reg);
+ if (ret)
+ return ret;
+
+ ret = iio_device_register(indio_dev);
+ if (ret)
+ goto disable_regulator;
+
+ return 0;
+
+disable_regulator:
+ regulator_disable(state->vref_reg);
+
+ return ret;
+}
+
+static int max11100_remove(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
+ struct max11100_state *state = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ regulator_disable(state->vref_reg);
+
+ return 0;
+}
+
+static const struct of_device_id max11100_ids[] = {
+ {.compatible = "maxim,max11100"},
+ { },
+};
+MODULE_DEVICE_TABLE(of, max11100_ids);
+
+static struct spi_driver max11100_driver = {
+ .driver = {
+ .name = "max11100",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(max11100_ids),
+ },
+ .probe = max11100_probe,
+ .remove = max11100_remove,
+};
+
+module_spi_driver(max11100_driver);
+
+MODULE_AUTHOR("Jacopo Mondi <jacopo@jmondi.org>");
+MODULE_DESCRIPTION("Maxim max11100 ADC Driver");
+MODULE_LICENSE("GPL v2");
MAX1363_COMPATIBLE("maxim,max11647", max11647),
{ /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, max1363_of_match);
#endif
static int max1363_probe(struct i2c_client *client,
--- /dev/null
+/*
+ * Amlogic Meson Successive Approximation Register (SAR) A/D Converter
+ *
+ * Copyright (C) 2017 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/iio/iio.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+#define MESON_SAR_ADC_REG0 0x00
+ #define MESON_SAR_ADC_REG0_PANEL_DETECT BIT(31)
+ #define MESON_SAR_ADC_REG0_BUSY_MASK GENMASK(30, 28)
+ #define MESON_SAR_ADC_REG0_DELTA_BUSY BIT(30)
+ #define MESON_SAR_ADC_REG0_AVG_BUSY BIT(29)
+ #define MESON_SAR_ADC_REG0_SAMPLE_BUSY BIT(28)
+ #define MESON_SAR_ADC_REG0_FIFO_FULL BIT(27)
+ #define MESON_SAR_ADC_REG0_FIFO_EMPTY BIT(26)
+ #define MESON_SAR_ADC_REG0_FIFO_COUNT_MASK GENMASK(25, 21)
+ #define MESON_SAR_ADC_REG0_ADC_BIAS_CTRL_MASK GENMASK(20, 19)
+ #define MESON_SAR_ADC_REG0_CURR_CHAN_ID_MASK GENMASK(18, 16)
+ #define MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL BIT(15)
+ #define MESON_SAR_ADC_REG0_SAMPLING_STOP BIT(14)
+ #define MESON_SAR_ADC_REG0_CHAN_DELTA_EN_MASK GENMASK(13, 12)
+ #define MESON_SAR_ADC_REG0_DETECT_IRQ_POL BIT(10)
+ #define MESON_SAR_ADC_REG0_DETECT_IRQ_EN BIT(9)
+ #define MESON_SAR_ADC_REG0_FIFO_CNT_IRQ_MASK GENMASK(8, 4)
+ #define MESON_SAR_ADC_REG0_FIFO_IRQ_EN BIT(3)
+ #define MESON_SAR_ADC_REG0_SAMPLING_START BIT(2)
+ #define MESON_SAR_ADC_REG0_CONTINUOUS_EN BIT(1)
+ #define MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE BIT(0)
+
+#define MESON_SAR_ADC_CHAN_LIST 0x04
+ #define MESON_SAR_ADC_CHAN_LIST_MAX_INDEX_MASK GENMASK(26, 24)
+ #define MESON_SAR_ADC_CHAN_LIST_ENTRY_MASK(_chan) \
+ (GENMASK(2, 0) << ((_chan) * 3))
+
+#define MESON_SAR_ADC_AVG_CNTL 0x08
+ #define MESON_SAR_ADC_AVG_CNTL_AVG_MODE_SHIFT(_chan) \
+ (16 + ((_chan) * 2))
+ #define MESON_SAR_ADC_AVG_CNTL_AVG_MODE_MASK(_chan) \
+ (GENMASK(17, 16) << ((_chan) * 2))
+ #define MESON_SAR_ADC_AVG_CNTL_NUM_SAMPLES_SHIFT(_chan) \
+ (0 + ((_chan) * 2))
+ #define MESON_SAR_ADC_AVG_CNTL_NUM_SAMPLES_MASK(_chan) \
+ (GENMASK(1, 0) << ((_chan) * 2))
+
+#define MESON_SAR_ADC_REG3 0x0c
+ #define MESON_SAR_ADC_REG3_CNTL_USE_SC_DLY BIT(31)
+ #define MESON_SAR_ADC_REG3_CLK_EN BIT(30)
+ #define MESON_SAR_ADC_REG3_BL30_INITIALIZED BIT(28)
+ #define MESON_SAR_ADC_REG3_CTRL_CONT_RING_COUNTER_EN BIT(27)
+ #define MESON_SAR_ADC_REG3_CTRL_SAMPLING_CLOCK_PHASE BIT(26)
+ #define MESON_SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK GENMASK(25, 23)
+ #define MESON_SAR_ADC_REG3_DETECT_EN BIT(22)
+ #define MESON_SAR_ADC_REG3_ADC_EN BIT(21)
+ #define MESON_SAR_ADC_REG3_PANEL_DETECT_COUNT_MASK GENMASK(20, 18)
+ #define MESON_SAR_ADC_REG3_PANEL_DETECT_FILTER_TB_MASK GENMASK(17, 16)
+ #define MESON_SAR_ADC_REG3_ADC_CLK_DIV_SHIFT 10
+ #define MESON_SAR_ADC_REG3_ADC_CLK_DIV_WIDTH 5
+ #define MESON_SAR_ADC_REG3_BLOCK_DLY_SEL_MASK GENMASK(9, 8)
+ #define MESON_SAR_ADC_REG3_BLOCK_DLY_MASK GENMASK(7, 0)
+
+#define MESON_SAR_ADC_DELAY 0x10
+ #define MESON_SAR_ADC_DELAY_INPUT_DLY_SEL_MASK GENMASK(25, 24)
+ #define MESON_SAR_ADC_DELAY_BL30_BUSY BIT(15)
+ #define MESON_SAR_ADC_DELAY_KERNEL_BUSY BIT(14)
+ #define MESON_SAR_ADC_DELAY_INPUT_DLY_CNT_MASK GENMASK(23, 16)
+ #define MESON_SAR_ADC_DELAY_SAMPLE_DLY_SEL_MASK GENMASK(9, 8)
+ #define MESON_SAR_ADC_DELAY_SAMPLE_DLY_CNT_MASK GENMASK(7, 0)
+
+#define MESON_SAR_ADC_LAST_RD 0x14
+ #define MESON_SAR_ADC_LAST_RD_LAST_CHANNEL1_MASK GENMASK(23, 16)
+ #define MESON_SAR_ADC_LAST_RD_LAST_CHANNEL0_MASK GENMASK(9, 0)
+
+#define MESON_SAR_ADC_FIFO_RD 0x18
+ #define MESON_SAR_ADC_FIFO_RD_CHAN_ID_MASK GENMASK(14, 12)
+ #define MESON_SAR_ADC_FIFO_RD_SAMPLE_VALUE_MASK GENMASK(11, 0)
+
+#define MESON_SAR_ADC_AUX_SW 0x1c
+ #define MESON_SAR_ADC_AUX_SW_MUX_SEL_CHAN_MASK(_chan) \
+ (GENMASK(10, 8) << (((_chan) - 2) * 2))
+ #define MESON_SAR_ADC_AUX_SW_VREF_P_MUX BIT(6)
+ #define MESON_SAR_ADC_AUX_SW_VREF_N_MUX BIT(5)
+ #define MESON_SAR_ADC_AUX_SW_MODE_SEL BIT(4)
+ #define MESON_SAR_ADC_AUX_SW_YP_DRIVE_SW BIT(3)
+ #define MESON_SAR_ADC_AUX_SW_XP_DRIVE_SW BIT(2)
+ #define MESON_SAR_ADC_AUX_SW_YM_DRIVE_SW BIT(1)
+ #define MESON_SAR_ADC_AUX_SW_XM_DRIVE_SW BIT(0)
+
+#define MESON_SAR_ADC_CHAN_10_SW 0x20
+ #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_MUX_SEL_MASK GENMASK(25, 23)
+ #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_VREF_P_MUX BIT(22)
+ #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_VREF_N_MUX BIT(21)
+ #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_MODE_SEL BIT(20)
+ #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_YP_DRIVE_SW BIT(19)
+ #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_XP_DRIVE_SW BIT(18)
+ #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_YM_DRIVE_SW BIT(17)
+ #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_XM_DRIVE_SW BIT(16)
+ #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_MUX_SEL_MASK GENMASK(9, 7)
+ #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_VREF_P_MUX BIT(6)
+ #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_VREF_N_MUX BIT(5)
+ #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_MODE_SEL BIT(4)
+ #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_YP_DRIVE_SW BIT(3)
+ #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_XP_DRIVE_SW BIT(2)
+ #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_YM_DRIVE_SW BIT(1)
+ #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_XM_DRIVE_SW BIT(0)
+
+#define MESON_SAR_ADC_DETECT_IDLE_SW 0x24
+ #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_SW_EN BIT(26)
+ #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_MUX_MASK GENMASK(25, 23)
+ #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_VREF_P_MUX BIT(22)
+ #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_VREF_N_MUX BIT(21)
+ #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_SEL BIT(20)
+ #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_YP_DRIVE_SW BIT(19)
+ #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_XP_DRIVE_SW BIT(18)
+ #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_YM_DRIVE_SW BIT(17)
+ #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_XM_DRIVE_SW BIT(16)
+ #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_MUX_SEL_MASK GENMASK(9, 7)
+ #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_VREF_P_MUX BIT(6)
+ #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_VREF_N_MUX BIT(5)
+ #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_SEL BIT(4)
+ #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_YP_DRIVE_SW BIT(3)
+ #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_XP_DRIVE_SW BIT(2)
+ #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_YM_DRIVE_SW BIT(1)
+ #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_XM_DRIVE_SW BIT(0)
+
+#define MESON_SAR_ADC_DELTA_10 0x28
+ #define MESON_SAR_ADC_DELTA_10_TEMP_SEL BIT(27)
+ #define MESON_SAR_ADC_DELTA_10_TS_REVE1 BIT(26)
+ #define MESON_SAR_ADC_DELTA_10_CHAN1_DELTA_VALUE_MASK GENMASK(25, 16)
+ #define MESON_SAR_ADC_DELTA_10_TS_REVE0 BIT(15)
+ #define MESON_SAR_ADC_DELTA_10_TS_C_SHIFT 11
+ #define MESON_SAR_ADC_DELTA_10_TS_C_MASK GENMASK(14, 11)
+ #define MESON_SAR_ADC_DELTA_10_TS_VBG_EN BIT(10)
+ #define MESON_SAR_ADC_DELTA_10_CHAN0_DELTA_VALUE_MASK GENMASK(9, 0)
+
+/*
+ * NOTE: registers from here are undocumented (the vendor Linux kernel driver
+ * and u-boot source served as reference). These only seem to be relevant on
+ * GXBB and newer.
+ */
+#define MESON_SAR_ADC_REG11 0x2c
+ #define MESON_SAR_ADC_REG11_BANDGAP_EN BIT(13)
+
+#define MESON_SAR_ADC_REG13 0x34
+ #define MESON_SAR_ADC_REG13_12BIT_CALIBRATION_MASK GENMASK(13, 8)
+
+#define MESON_SAR_ADC_MAX_FIFO_SIZE 32
+
+#define MESON_SAR_ADC_CHAN(_chan) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = _chan, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_AVERAGE_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .datasheet_name = "SAR_ADC_CH"#_chan, \
+}
+
+/*
+ * TODO: the hardware supports IIO_TEMP for channel 6 as well which is
+ * currently not supported by this driver.
+ */
+static const struct iio_chan_spec meson_sar_adc_iio_channels[] = {
+ MESON_SAR_ADC_CHAN(0),
+ MESON_SAR_ADC_CHAN(1),
+ MESON_SAR_ADC_CHAN(2),
+ MESON_SAR_ADC_CHAN(3),
+ MESON_SAR_ADC_CHAN(4),
+ MESON_SAR_ADC_CHAN(5),
+ MESON_SAR_ADC_CHAN(6),
+ MESON_SAR_ADC_CHAN(7),
+ IIO_CHAN_SOFT_TIMESTAMP(8),
+};
+
+enum meson_sar_adc_avg_mode {
+ NO_AVERAGING = 0x0,
+ MEAN_AVERAGING = 0x1,
+ MEDIAN_AVERAGING = 0x2,
+};
+
+enum meson_sar_adc_num_samples {
+ ONE_SAMPLE = 0x0,
+ TWO_SAMPLES = 0x1,
+ FOUR_SAMPLES = 0x2,
+ EIGHT_SAMPLES = 0x3,
+};
+
+enum meson_sar_adc_chan7_mux_sel {
+ CHAN7_MUX_VSS = 0x0,
+ CHAN7_MUX_VDD_DIV4 = 0x1,
+ CHAN7_MUX_VDD_DIV2 = 0x2,
+ CHAN7_MUX_VDD_MUL3_DIV4 = 0x3,
+ CHAN7_MUX_VDD = 0x4,
+ CHAN7_MUX_CH7_INPUT = 0x7,
+};
+
+struct meson_sar_adc_data {
+ unsigned int resolution;
+ const char *name;
+};
+
+struct meson_sar_adc_priv {
+ struct regmap *regmap;
+ struct regulator *vref;
+ const struct meson_sar_adc_data *data;
+ struct clk *clkin;
+ struct clk *core_clk;
+ struct clk *sana_clk;
+ struct clk *adc_sel_clk;
+ struct clk *adc_clk;
+ struct clk_gate clk_gate;
+ struct clk *adc_div_clk;
+ struct clk_divider clk_div;
+};
+
+static const struct regmap_config meson_sar_adc_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = MESON_SAR_ADC_REG13,
+};
+
+static unsigned int meson_sar_adc_get_fifo_count(struct iio_dev *indio_dev)
+{
+ struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
+ u32 regval;
+
+ regmap_read(priv->regmap, MESON_SAR_ADC_REG0, ®val);
+
+ return FIELD_GET(MESON_SAR_ADC_REG0_FIFO_COUNT_MASK, regval);
+}
+
+static int meson_sar_adc_wait_busy_clear(struct iio_dev *indio_dev)
+{
+ struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
+ int regval, timeout = 10000;
+
+ /*
+ * NOTE: we need a small delay before reading the status, otherwise
+ * the sample engine may not have started internally (which would
+ * seem to us that sampling is already finished).
+ */
+ do {
+ udelay(1);
+ regmap_read(priv->regmap, MESON_SAR_ADC_REG0, ®val);
+ } while (FIELD_GET(MESON_SAR_ADC_REG0_BUSY_MASK, regval) && timeout--);
+
+ if (timeout < 0)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int meson_sar_adc_read_raw_sample(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ int *val)
+{
+ struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
+ int ret, regval, fifo_chan, fifo_val, sum = 0, count = 0;
+
+ ret = meson_sar_adc_wait_busy_clear(indio_dev);
+ if (ret)
+ return ret;
+
+ while (meson_sar_adc_get_fifo_count(indio_dev) > 0 &&
+ count < MESON_SAR_ADC_MAX_FIFO_SIZE) {
+ regmap_read(priv->regmap, MESON_SAR_ADC_FIFO_RD, ®val);
+
+ fifo_chan = FIELD_GET(MESON_SAR_ADC_FIFO_RD_CHAN_ID_MASK,
+ regval);
+ if (fifo_chan != chan->channel)
+ continue;
+
+ fifo_val = FIELD_GET(MESON_SAR_ADC_FIFO_RD_SAMPLE_VALUE_MASK,
+ regval);
+ fifo_val &= (BIT(priv->data->resolution) - 1);
+
+ sum += fifo_val;
+ count++;
+ }
+
+ if (!count)
+ return -ENOENT;
+
+ *val = sum / count;
+
+ return 0;
+}
+
+static void meson_sar_adc_set_averaging(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum meson_sar_adc_avg_mode mode,
+ enum meson_sar_adc_num_samples samples)
+{
+ struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
+ int val, channel = chan->channel;
+
+ val = samples << MESON_SAR_ADC_AVG_CNTL_NUM_SAMPLES_SHIFT(channel);
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_AVG_CNTL,
+ MESON_SAR_ADC_AVG_CNTL_NUM_SAMPLES_MASK(channel),
+ val);
+
+ val = mode << MESON_SAR_ADC_AVG_CNTL_AVG_MODE_SHIFT(channel);
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_AVG_CNTL,
+ MESON_SAR_ADC_AVG_CNTL_AVG_MODE_MASK(channel), val);
+}
+
+static void meson_sar_adc_enable_channel(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan)
+{
+ struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
+ u32 regval;
+
+ /*
+ * the SAR ADC engine allows sampling multiple channels at the same
+ * time. to keep it simple we're only working with one *internal*
+ * channel, which starts counting at index 0 (which means: count = 1).
+ */
+ regval = FIELD_PREP(MESON_SAR_ADC_CHAN_LIST_MAX_INDEX_MASK, 0);
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_LIST,
+ MESON_SAR_ADC_CHAN_LIST_MAX_INDEX_MASK, regval);
+
+ /* map channel index 0 to the channel which we want to read */
+ regval = FIELD_PREP(MESON_SAR_ADC_CHAN_LIST_ENTRY_MASK(0),
+ chan->channel);
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_LIST,
+ MESON_SAR_ADC_CHAN_LIST_ENTRY_MASK(0), regval);
+
+ regval = FIELD_PREP(MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_MUX_MASK,
+ chan->channel);
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_DETECT_IDLE_SW,
+ MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_MUX_MASK,
+ regval);
+
+ regval = FIELD_PREP(MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_MUX_SEL_MASK,
+ chan->channel);
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_DETECT_IDLE_SW,
+ MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_MUX_SEL_MASK,
+ regval);
+
+ if (chan->channel == 6)
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10,
+ MESON_SAR_ADC_DELTA_10_TEMP_SEL, 0);
+}
+
+static void meson_sar_adc_set_chan7_mux(struct iio_dev *indio_dev,
+ enum meson_sar_adc_chan7_mux_sel sel)
+{
+ struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
+ u32 regval;
+
+ regval = FIELD_PREP(MESON_SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK, sel);
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3,
+ MESON_SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK, regval);
+
+ usleep_range(10, 20);
+}
+
+static void meson_sar_adc_start_sample_engine(struct iio_dev *indio_dev)
+{
+ struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
+
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
+ MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE,
+ MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE);
+
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
+ MESON_SAR_ADC_REG0_SAMPLING_START,
+ MESON_SAR_ADC_REG0_SAMPLING_START);
+}
+
+static void meson_sar_adc_stop_sample_engine(struct iio_dev *indio_dev)
+{
+ struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
+
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
+ MESON_SAR_ADC_REG0_SAMPLING_STOP,
+ MESON_SAR_ADC_REG0_SAMPLING_STOP);
+
+ /* wait until all modules are stopped */
+ meson_sar_adc_wait_busy_clear(indio_dev);
+
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
+ MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE, 0);
+}
+
+static int meson_sar_adc_lock(struct iio_dev *indio_dev)
+{
+ struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
+ int val, timeout = 10000;
+
+ mutex_lock(&indio_dev->mlock);
+
+ /* prevent BL30 from using the SAR ADC while we are using it */
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
+ MESON_SAR_ADC_DELAY_KERNEL_BUSY,
+ MESON_SAR_ADC_DELAY_KERNEL_BUSY);
+
+ /* wait until BL30 releases it's lock (so we can use the SAR ADC) */
+ do {
+ udelay(1);
+ regmap_read(priv->regmap, MESON_SAR_ADC_DELAY, &val);
+ } while (val & MESON_SAR_ADC_DELAY_BL30_BUSY && timeout--);
+
+ if (timeout < 0)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static void meson_sar_adc_unlock(struct iio_dev *indio_dev)
+{
+ struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
+
+ /* allow BL30 to use the SAR ADC again */
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
+ MESON_SAR_ADC_DELAY_KERNEL_BUSY, 0);
+
+ mutex_unlock(&indio_dev->mlock);
+}
+
+static void meson_sar_adc_clear_fifo(struct iio_dev *indio_dev)
+{
+ struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
+ int count;
+
+ for (count = 0; count < MESON_SAR_ADC_MAX_FIFO_SIZE; count++) {
+ if (!meson_sar_adc_get_fifo_count(indio_dev))
+ break;
+
+ regmap_read(priv->regmap, MESON_SAR_ADC_FIFO_RD, 0);
+ }
+}
+
+static int meson_sar_adc_get_sample(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum meson_sar_adc_avg_mode avg_mode,
+ enum meson_sar_adc_num_samples avg_samples,
+ int *val)
+{
+ int ret;
+
+ ret = meson_sar_adc_lock(indio_dev);
+ if (ret)
+ return ret;
+
+ /* clear the FIFO to make sure we're not reading old values */
+ meson_sar_adc_clear_fifo(indio_dev);
+
+ meson_sar_adc_set_averaging(indio_dev, chan, avg_mode, avg_samples);
+
+ meson_sar_adc_enable_channel(indio_dev, chan);
+
+ meson_sar_adc_start_sample_engine(indio_dev);
+ ret = meson_sar_adc_read_raw_sample(indio_dev, chan, val);
+ meson_sar_adc_stop_sample_engine(indio_dev);
+
+ meson_sar_adc_unlock(indio_dev);
+
+ if (ret) {
+ dev_warn(indio_dev->dev.parent,
+ "failed to read sample for channel %d: %d\n",
+ chan->channel, ret);
+ return ret;
+ }
+
+ return IIO_VAL_INT;
+}
+
+static int meson_sar_adc_iio_info_read_raw(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ int *val, int *val2, long mask)
+{
+ struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ return meson_sar_adc_get_sample(indio_dev, chan, NO_AVERAGING,
+ ONE_SAMPLE, val);
+ break;
+
+ case IIO_CHAN_INFO_AVERAGE_RAW:
+ return meson_sar_adc_get_sample(indio_dev, chan,
+ MEAN_AVERAGING, EIGHT_SAMPLES,
+ val);
+ break;
+
+ case IIO_CHAN_INFO_SCALE:
+ ret = regulator_get_voltage(priv->vref);
+ if (ret < 0) {
+ dev_err(indio_dev->dev.parent,
+ "failed to get vref voltage: %d\n", ret);
+ return ret;
+ }
+
+ *val = ret / 1000;
+ *val2 = priv->data->resolution;
+ return IIO_VAL_FRACTIONAL_LOG2;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int meson_sar_adc_clk_init(struct iio_dev *indio_dev,
+ void __iomem *base)
+{
+ struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
+ struct clk_init_data init;
+ const char *clk_parents[1];
+
+ init.name = devm_kasprintf(&indio_dev->dev, GFP_KERNEL, "%s#adc_div",
+ of_node_full_name(indio_dev->dev.of_node));
+ init.flags = 0;
+ init.ops = &clk_divider_ops;
+ clk_parents[0] = __clk_get_name(priv->clkin);
+ init.parent_names = clk_parents;
+ init.num_parents = 1;
+
+ priv->clk_div.reg = base + MESON_SAR_ADC_REG3;
+ priv->clk_div.shift = MESON_SAR_ADC_REG3_ADC_CLK_DIV_SHIFT;
+ priv->clk_div.width = MESON_SAR_ADC_REG3_ADC_CLK_DIV_WIDTH;
+ priv->clk_div.hw.init = &init;
+ priv->clk_div.flags = 0;
+
+ priv->adc_div_clk = devm_clk_register(&indio_dev->dev,
+ &priv->clk_div.hw);
+ if (WARN_ON(IS_ERR(priv->adc_div_clk)))
+ return PTR_ERR(priv->adc_div_clk);
+
+ init.name = devm_kasprintf(&indio_dev->dev, GFP_KERNEL, "%s#adc_en",
+ of_node_full_name(indio_dev->dev.of_node));
+ init.flags = CLK_SET_RATE_PARENT;
+ init.ops = &clk_gate_ops;
+ clk_parents[0] = __clk_get_name(priv->adc_div_clk);
+ init.parent_names = clk_parents;
+ init.num_parents = 1;
+
+ priv->clk_gate.reg = base + MESON_SAR_ADC_REG3;
+ priv->clk_gate.bit_idx = fls(MESON_SAR_ADC_REG3_CLK_EN);
+ priv->clk_gate.hw.init = &init;
+
+ priv->adc_clk = devm_clk_register(&indio_dev->dev, &priv->clk_gate.hw);
+ if (WARN_ON(IS_ERR(priv->adc_clk)))
+ return PTR_ERR(priv->adc_clk);
+
+ return 0;
+}
+
+static int meson_sar_adc_init(struct iio_dev *indio_dev)
+{
+ struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
+ int regval, ret;
+
+ /*
+ * make sure we start at CH7 input since the other muxes are only used
+ * for internal calibration.
+ */
+ meson_sar_adc_set_chan7_mux(indio_dev, CHAN7_MUX_CH7_INPUT);
+
+ /*
+ * leave sampling delay and the input clocks as configured by BL30 to
+ * make sure BL30 gets the values it expects when reading the
+ * temperature sensor.
+ */
+ regmap_read(priv->regmap, MESON_SAR_ADC_REG3, ®val);
+ if (regval & MESON_SAR_ADC_REG3_BL30_INITIALIZED)
+ return 0;
+
+ meson_sar_adc_stop_sample_engine(indio_dev);
+
+ /* update the channel 6 MUX to select the temperature sensor */
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
+ MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL,
+ MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL);
+
+ /* disable all channels by default */
+ regmap_write(priv->regmap, MESON_SAR_ADC_CHAN_LIST, 0x0);
+
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3,
+ MESON_SAR_ADC_REG3_CTRL_SAMPLING_CLOCK_PHASE, 0);
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3,
+ MESON_SAR_ADC_REG3_CNTL_USE_SC_DLY,
+ MESON_SAR_ADC_REG3_CNTL_USE_SC_DLY);
+
+ /* delay between two samples = (10+1) * 1uS */
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
+ MESON_SAR_ADC_DELAY_INPUT_DLY_CNT_MASK,
+ FIELD_PREP(MESON_SAR_ADC_DELAY_SAMPLE_DLY_CNT_MASK,
+ 10));
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
+ MESON_SAR_ADC_DELAY_SAMPLE_DLY_SEL_MASK,
+ FIELD_PREP(MESON_SAR_ADC_DELAY_SAMPLE_DLY_SEL_MASK,
+ 0));
+
+ /* delay between two samples = (10+1) * 1uS */
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
+ MESON_SAR_ADC_DELAY_INPUT_DLY_CNT_MASK,
+ FIELD_PREP(MESON_SAR_ADC_DELAY_INPUT_DLY_CNT_MASK,
+ 10));
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY,
+ MESON_SAR_ADC_DELAY_INPUT_DLY_SEL_MASK,
+ FIELD_PREP(MESON_SAR_ADC_DELAY_INPUT_DLY_SEL_MASK,
+ 1));
+
+ ret = clk_set_parent(priv->adc_sel_clk, priv->clkin);
+ if (ret) {
+ dev_err(indio_dev->dev.parent,
+ "failed to set adc parent to clkin\n");
+ return ret;
+ }
+
+ ret = clk_set_rate(priv->adc_clk, 1200000);
+ if (ret) {
+ dev_err(indio_dev->dev.parent,
+ "failed to set adc clock rate\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int meson_sar_adc_hw_enable(struct iio_dev *indio_dev)
+{
+ struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
+ int ret;
+
+ ret = meson_sar_adc_lock(indio_dev);
+ if (ret)
+ goto err_lock;
+
+ ret = regulator_enable(priv->vref);
+ if (ret < 0) {
+ dev_err(indio_dev->dev.parent,
+ "failed to enable vref regulator\n");
+ goto err_vref;
+ }
+
+ ret = clk_prepare_enable(priv->core_clk);
+ if (ret) {
+ dev_err(indio_dev->dev.parent, "failed to enable core clk\n");
+ goto err_core_clk;
+ }
+
+ ret = clk_prepare_enable(priv->sana_clk);
+ if (ret) {
+ dev_err(indio_dev->dev.parent, "failed to enable sana clk\n");
+ goto err_sana_clk;
+ }
+
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11,
+ MESON_SAR_ADC_REG11_BANDGAP_EN,
+ MESON_SAR_ADC_REG11_BANDGAP_EN);
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3,
+ MESON_SAR_ADC_REG3_ADC_EN,
+ MESON_SAR_ADC_REG3_ADC_EN);
+
+ udelay(5);
+
+ ret = clk_prepare_enable(priv->adc_clk);
+ if (ret) {
+ dev_err(indio_dev->dev.parent, "failed to enable adc clk\n");
+ goto err_adc_clk;
+ }
+
+ meson_sar_adc_unlock(indio_dev);
+
+ return 0;
+
+err_adc_clk:
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3,
+ MESON_SAR_ADC_REG3_ADC_EN, 0);
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11,
+ MESON_SAR_ADC_REG11_BANDGAP_EN, 0);
+ clk_disable_unprepare(priv->sana_clk);
+err_sana_clk:
+ clk_disable_unprepare(priv->core_clk);
+err_core_clk:
+ regulator_disable(priv->vref);
+err_vref:
+ meson_sar_adc_unlock(indio_dev);
+err_lock:
+ return ret;
+}
+
+static int meson_sar_adc_hw_disable(struct iio_dev *indio_dev)
+{
+ struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
+ int ret;
+
+ ret = meson_sar_adc_lock(indio_dev);
+ if (ret)
+ return ret;
+
+ clk_disable_unprepare(priv->adc_clk);
+
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3,
+ MESON_SAR_ADC_REG3_ADC_EN, 0);
+ regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11,
+ MESON_SAR_ADC_REG11_BANDGAP_EN, 0);
+
+ clk_disable_unprepare(priv->sana_clk);
+ clk_disable_unprepare(priv->core_clk);
+
+ regulator_disable(priv->vref);
+
+ meson_sar_adc_unlock(indio_dev);
+
+ return 0;
+}
+
+static const struct iio_info meson_sar_adc_iio_info = {
+ .read_raw = meson_sar_adc_iio_info_read_raw,
+ .driver_module = THIS_MODULE,
+};
+
+struct meson_sar_adc_data meson_sar_adc_gxbb_data = {
+ .resolution = 10,
+ .name = "meson-gxbb-saradc",
+};
+
+struct meson_sar_adc_data meson_sar_adc_gxl_data = {
+ .resolution = 12,
+ .name = "meson-gxl-saradc",
+};
+
+struct meson_sar_adc_data meson_sar_adc_gxm_data = {
+ .resolution = 12,
+ .name = "meson-gxm-saradc",
+};
+
+static const struct of_device_id meson_sar_adc_of_match[] = {
+ {
+ .compatible = "amlogic,meson-gxbb-saradc",
+ .data = &meson_sar_adc_gxbb_data,
+ }, {
+ .compatible = "amlogic,meson-gxl-saradc",
+ .data = &meson_sar_adc_gxl_data,
+ }, {
+ .compatible = "amlogic,meson-gxm-saradc",
+ .data = &meson_sar_adc_gxm_data,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, meson_sar_adc_of_match);
+
+static int meson_sar_adc_probe(struct platform_device *pdev)
+{
+ struct meson_sar_adc_priv *priv;
+ struct iio_dev *indio_dev;
+ struct resource *res;
+ void __iomem *base;
+ const struct of_device_id *match;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv));
+ if (!indio_dev) {
+ dev_err(&pdev->dev, "failed allocating iio device\n");
+ return -ENOMEM;
+ }
+
+ priv = iio_priv(indio_dev);
+
+ match = of_match_device(meson_sar_adc_of_match, &pdev->dev);
+ priv->data = match->data;
+
+ indio_dev->name = priv->data->name;
+ indio_dev->dev.parent = &pdev->dev;
+ indio_dev->dev.of_node = pdev->dev.of_node;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &meson_sar_adc_iio_info;
+
+ indio_dev->channels = meson_sar_adc_iio_channels;
+ indio_dev->num_channels = ARRAY_SIZE(meson_sar_adc_iio_channels);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ priv->regmap = devm_regmap_init_mmio(&pdev->dev, base,
+ &meson_sar_adc_regmap_config);
+ if (IS_ERR(priv->regmap))
+ return PTR_ERR(priv->regmap);
+
+ priv->clkin = devm_clk_get(&pdev->dev, "clkin");
+ if (IS_ERR(priv->clkin)) {
+ dev_err(&pdev->dev, "failed to get clkin\n");
+ return PTR_ERR(priv->clkin);
+ }
+
+ priv->core_clk = devm_clk_get(&pdev->dev, "core");
+ if (IS_ERR(priv->core_clk)) {
+ dev_err(&pdev->dev, "failed to get core clk\n");
+ return PTR_ERR(priv->core_clk);
+ }
+
+ priv->sana_clk = devm_clk_get(&pdev->dev, "sana");
+ if (IS_ERR(priv->sana_clk)) {
+ if (PTR_ERR(priv->sana_clk) == -ENOENT) {
+ priv->sana_clk = NULL;
+ } else {
+ dev_err(&pdev->dev, "failed to get sana clk\n");
+ return PTR_ERR(priv->sana_clk);
+ }
+ }
+
+ priv->adc_clk = devm_clk_get(&pdev->dev, "adc_clk");
+ if (IS_ERR(priv->adc_clk)) {
+ if (PTR_ERR(priv->adc_clk) == -ENOENT) {
+ priv->adc_clk = NULL;
+ } else {
+ dev_err(&pdev->dev, "failed to get adc clk\n");
+ return PTR_ERR(priv->adc_clk);
+ }
+ }
+
+ priv->adc_sel_clk = devm_clk_get(&pdev->dev, "adc_sel");
+ if (IS_ERR(priv->adc_sel_clk)) {
+ if (PTR_ERR(priv->adc_sel_clk) == -ENOENT) {
+ priv->adc_sel_clk = NULL;
+ } else {
+ dev_err(&pdev->dev, "failed to get adc_sel clk\n");
+ return PTR_ERR(priv->adc_sel_clk);
+ }
+ }
+
+ /* on pre-GXBB SoCs the SAR ADC itself provides the ADC clock: */
+ if (!priv->adc_clk) {
+ ret = meson_sar_adc_clk_init(indio_dev, base);
+ if (ret)
+ return ret;
+ }
+
+ priv->vref = devm_regulator_get(&pdev->dev, "vref");
+ if (IS_ERR(priv->vref)) {
+ dev_err(&pdev->dev, "failed to get vref regulator\n");
+ return PTR_ERR(priv->vref);
+ }
+
+ ret = meson_sar_adc_init(indio_dev);
+ if (ret)
+ goto err;
+
+ ret = meson_sar_adc_hw_enable(indio_dev);
+ if (ret)
+ goto err;
+
+ platform_set_drvdata(pdev, indio_dev);
+
+ ret = iio_device_register(indio_dev);
+ if (ret)
+ goto err_hw;
+
+ return 0;
+
+err_hw:
+ meson_sar_adc_hw_disable(indio_dev);
+err:
+ return ret;
+}
+
+static int meson_sar_adc_remove(struct platform_device *pdev)
+{
+ struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+
+ iio_device_unregister(indio_dev);
+
+ return meson_sar_adc_hw_disable(indio_dev);
+}
+
+static int __maybe_unused meson_sar_adc_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+
+ return meson_sar_adc_hw_disable(indio_dev);
+}
+
+static int __maybe_unused meson_sar_adc_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+
+ return meson_sar_adc_hw_enable(indio_dev);
+}
+
+static SIMPLE_DEV_PM_OPS(meson_sar_adc_pm_ops,
+ meson_sar_adc_suspend, meson_sar_adc_resume);
+
+static struct platform_driver meson_sar_adc_driver = {
+ .probe = meson_sar_adc_probe,
+ .remove = meson_sar_adc_remove,
+ .driver = {
+ .name = "meson-saradc",
+ .of_match_table = meson_sar_adc_of_match,
+ .pm = &meson_sar_adc_pm_ops,
+ },
+};
+
+module_platform_driver(meson_sar_adc_driver);
+
+MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
+MODULE_DESCRIPTION("Amlogic Meson SAR ADC driver");
+MODULE_LICENSE("GPL v2");
/*
- * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
#define VADC_MAX_ADC_CODE 0xa800
#define VADC_ABSOLUTE_RANGE_UV 625000
-#define VADC_RATIOMETRIC_RANGE_UV 1800000
+#define VADC_RATIOMETRIC_RANGE 1800
#define VADC_DEF_PRESCALING 0 /* 1:1 */
#define VADC_DEF_DECIMATION 0 /* 512 */
#define KELVINMIL_CELSIUSMIL 273150
+#define PMI_CHG_SCALE_1 -138890
+#define PMI_CHG_SCALE_2 391750000000LL
+
#define VADC_CHAN_MIN VADC_USBIN
#define VADC_CHAN_MAX VADC_LR_MUX3_BUF_PU1_PU2_XO_THERM
+/**
+ * struct vadc_map_pt - Map the graph representation for ADC channel
+ * @x: Represent the ADC digitized code.
+ * @y: Represent the physical data which can be temperature, voltage,
+ * resistance.
+ */
+struct vadc_map_pt {
+ s32 x;
+ s32 y;
+};
+
/*
* VADC_CALIB_ABSOLUTE: uses the 625mV and 1.25V as reference channels.
* VADC_CALIB_RATIOMETRIC: uses the reference voltage (1.8V) and GND for
* start of conversion.
* @avg_samples: ability to provide single result from the ADC
* that is an average of multiple measurements.
+ * @scale_fn: Represents the scaling function to convert voltage
+ * physical units desired by the client for the channel.
+ * Referenced from enum vadc_scale_fn_type.
*/
struct vadc_channel_prop {
unsigned int channel;
unsigned int prescale;
unsigned int hw_settle_time;
unsigned int avg_samples;
+ unsigned int scale_fn;
};
/**
struct mutex lock;
};
+/**
+ * struct vadc_scale_fn - Scaling function prototype
+ * @scale: Function pointer to one of the scaling functions
+ * which takes the adc properties, channel properties,
+ * and returns the physical result.
+ */
+struct vadc_scale_fn {
+ int (*scale)(struct vadc_priv *, const struct vadc_channel_prop *,
+ u16, int *);
+};
+
+/**
+ * enum vadc_scale_fn_type - Scaling function to convert ADC code to
+ * physical scaled units for the channel.
+ * SCALE_DEFAULT: Default scaling to convert raw adc code to voltage (uV).
+ * SCALE_THERM_100K_PULLUP: Returns temperature in millidegC.
+ * Uses a mapping table with 100K pullup.
+ * SCALE_PMIC_THERM: Returns result in milli degree's Centigrade.
+ * SCALE_XOTHERM: Returns XO thermistor voltage in millidegC.
+ * SCALE_PMI_CHG_TEMP: Conversion for PMI CHG temp
+ */
+enum vadc_scale_fn_type {
+ SCALE_DEFAULT = 0,
+ SCALE_THERM_100K_PULLUP,
+ SCALE_PMIC_THERM,
+ SCALE_XOTHERM,
+ SCALE_PMI_CHG_TEMP,
+};
+
static const struct vadc_prescale_ratio vadc_prescale_ratios[] = {
{.num = 1, .den = 1},
{.num = 1, .den = 3},
{.num = 1, .den = 10}
};
+/* Voltage to temperature */
+static const struct vadc_map_pt adcmap_100k_104ef_104fb[] = {
+ {1758, -40},
+ {1742, -35},
+ {1719, -30},
+ {1691, -25},
+ {1654, -20},
+ {1608, -15},
+ {1551, -10},
+ {1483, -5},
+ {1404, 0},
+ {1315, 5},
+ {1218, 10},
+ {1114, 15},
+ {1007, 20},
+ {900, 25},
+ {795, 30},
+ {696, 35},
+ {605, 40},
+ {522, 45},
+ {448, 50},
+ {383, 55},
+ {327, 60},
+ {278, 65},
+ {237, 70},
+ {202, 75},
+ {172, 80},
+ {146, 85},
+ {125, 90},
+ {107, 95},
+ {92, 100},
+ {79, 105},
+ {68, 110},
+ {59, 115},
+ {51, 120},
+ {44, 125}
+};
+
static int vadc_read(struct vadc_priv *vadc, u16 offset, u8 *data)
{
return regmap_bulk_read(vadc->regmap, vadc->base + offset, data, 1);
u16 read_1, read_2;
int ret;
- vadc->graph[VADC_CALIB_RATIOMETRIC].dx = VADC_RATIOMETRIC_RANGE_UV;
+ vadc->graph[VADC_CALIB_RATIOMETRIC].dx = VADC_RATIOMETRIC_RANGE;
vadc->graph[VADC_CALIB_ABSOLUTE].dx = VADC_ABSOLUTE_RANGE_UV;
prop = vadc_get_channel(vadc, VADC_REF_1250MV);
return ret;
}
-static s32 vadc_calibrate(struct vadc_priv *vadc,
- const struct vadc_channel_prop *prop, u16 adc_code)
+static int vadc_map_voltage_temp(const struct vadc_map_pt *pts,
+ u32 tablesize, s32 input, s64 *output)
+{
+ bool descending = 1;
+ u32 i = 0;
+
+ if (!pts)
+ return -EINVAL;
+
+ /* Check if table is descending or ascending */
+ if (tablesize > 1) {
+ if (pts[0].x < pts[1].x)
+ descending = 0;
+ }
+
+ while (i < tablesize) {
+ if ((descending) && (pts[i].x < input)) {
+ /* table entry is less than measured*/
+ /* value and table is descending, stop */
+ break;
+ } else if ((!descending) &&
+ (pts[i].x > input)) {
+ /* table entry is greater than measured*/
+ /*value and table is ascending, stop */
+ break;
+ }
+ i++;
+ }
+
+ if (i == 0) {
+ *output = pts[0].y;
+ } else if (i == tablesize) {
+ *output = pts[tablesize - 1].y;
+ } else {
+ /* result is between search_index and search_index-1 */
+ /* interpolate linearly */
+ *output = (((s32)((pts[i].y - pts[i - 1].y) *
+ (input - pts[i - 1].x)) /
+ (pts[i].x - pts[i - 1].x)) +
+ pts[i - 1].y);
+ }
+
+ return 0;
+}
+
+static void vadc_scale_calib(struct vadc_priv *vadc, u16 adc_code,
+ const struct vadc_channel_prop *prop,
+ s64 *scale_voltage)
+{
+ *scale_voltage = (adc_code -
+ vadc->graph[prop->calibration].gnd);
+ *scale_voltage *= vadc->graph[prop->calibration].dx;
+ *scale_voltage = div64_s64(*scale_voltage,
+ vadc->graph[prop->calibration].dy);
+ if (prop->calibration == VADC_CALIB_ABSOLUTE)
+ *scale_voltage +=
+ vadc->graph[prop->calibration].dx;
+
+ if (*scale_voltage < 0)
+ *scale_voltage = 0;
+}
+
+static int vadc_scale_volt(struct vadc_priv *vadc,
+ const struct vadc_channel_prop *prop, u16 adc_code,
+ int *result_uv)
{
const struct vadc_prescale_ratio *prescale;
- s64 voltage;
+ s64 voltage = 0, result = 0;
- voltage = adc_code - vadc->graph[prop->calibration].gnd;
- voltage *= vadc->graph[prop->calibration].dx;
- voltage = div64_s64(voltage, vadc->graph[prop->calibration].dy);
+ vadc_scale_calib(vadc, adc_code, prop, &voltage);
+
+ prescale = &vadc_prescale_ratios[prop->prescale];
+ voltage = voltage * prescale->den;
+ result = div64_s64(voltage, prescale->num);
+ *result_uv = result;
+
+ return 0;
+}
+
+static int vadc_scale_therm(struct vadc_priv *vadc,
+ const struct vadc_channel_prop *prop, u16 adc_code,
+ int *result_mdec)
+{
+ s64 voltage = 0, result = 0;
+
+ vadc_scale_calib(vadc, adc_code, prop, &voltage);
if (prop->calibration == VADC_CALIB_ABSOLUTE)
- voltage += vadc->graph[prop->calibration].dx;
+ voltage = div64_s64(voltage, 1000);
+
+ vadc_map_voltage_temp(adcmap_100k_104ef_104fb,
+ ARRAY_SIZE(adcmap_100k_104ef_104fb),
+ voltage, &result);
+ result *= 1000;
+ *result_mdec = result;
- if (voltage < 0)
+ return 0;
+}
+
+static int vadc_scale_die_temp(struct vadc_priv *vadc,
+ const struct vadc_channel_prop *prop,
+ u16 adc_code, int *result_mdec)
+{
+ const struct vadc_prescale_ratio *prescale;
+ s64 voltage = 0;
+ u64 temp; /* Temporary variable for do_div */
+
+ vadc_scale_calib(vadc, adc_code, prop, &voltage);
+
+ if (voltage > 0) {
+ prescale = &vadc_prescale_ratios[prop->prescale];
+ temp = voltage * prescale->den;
+ do_div(temp, prescale->num * 2);
+ voltage = temp;
+ } else {
voltage = 0;
+ }
- prescale = &vadc_prescale_ratios[prop->prescale];
+ voltage -= KELVINMIL_CELSIUSMIL;
+ *result_mdec = voltage;
+
+ return 0;
+}
+
+static int vadc_scale_chg_temp(struct vadc_priv *vadc,
+ const struct vadc_channel_prop *prop,
+ u16 adc_code, int *result_mdec)
+{
+ const struct vadc_prescale_ratio *prescale;
+ s64 voltage = 0, result = 0;
+ vadc_scale_calib(vadc, adc_code, prop, &voltage);
+
+ prescale = &vadc_prescale_ratios[prop->prescale];
voltage = voltage * prescale->den;
+ voltage = div64_s64(voltage, prescale->num);
+ voltage = ((PMI_CHG_SCALE_1) * (voltage * 2));
+ voltage = (voltage + PMI_CHG_SCALE_2);
+ result = div64_s64(voltage, 1000000);
+ *result_mdec = result;
- return div64_s64(voltage, prescale->num);
+ return 0;
}
static int vadc_decimation_from_dt(u32 value)
return __ffs64(value);
}
+static struct vadc_scale_fn scale_fn[] = {
+ [SCALE_DEFAULT] = {vadc_scale_volt},
+ [SCALE_THERM_100K_PULLUP] = {vadc_scale_therm},
+ [SCALE_PMIC_THERM] = {vadc_scale_die_temp},
+ [SCALE_XOTHERM] = {vadc_scale_therm},
+ [SCALE_PMI_CHG_TEMP] = {vadc_scale_chg_temp},
+};
+
static int vadc_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val, int *val2,
long mask)
if (ret)
break;
- *val = vadc_calibrate(vadc, prop, adc_code);
+ scale_fn[prop->scale_fn].scale(vadc, prop, adc_code, val);
- /* 2mV/K, return milli Celsius */
- *val /= 2;
- *val -= KELVINMIL_CELSIUSMIL;
return IIO_VAL_INT;
case IIO_CHAN_INFO_RAW:
prop = &vadc->chan_props[chan->address];
if (ret)
break;
- *val = vadc_calibrate(vadc, prop, adc_code);
+ *val = (int)adc_code;
return IIO_VAL_INT;
- case IIO_CHAN_INFO_SCALE:
- *val = 0;
- *val2 = 1000;
- return IIO_VAL_INT_PLUS_MICRO;
default:
ret = -EINVAL;
break;
unsigned int prescale_index;
enum iio_chan_type type;
long info_mask;
+ unsigned int scale_fn;
};
-#define VADC_CHAN(_dname, _type, _mask, _pre) \
+#define VADC_CHAN(_dname, _type, _mask, _pre, _scale) \
[VADC_##_dname] = { \
.datasheet_name = __stringify(_dname), \
.prescale_index = _pre, \
.type = _type, \
- .info_mask = _mask \
+ .info_mask = _mask, \
+ .scale_fn = _scale \
}, \
-#define VADC_CHAN_TEMP(_dname, _pre) \
- VADC_CHAN(_dname, IIO_TEMP, BIT(IIO_CHAN_INFO_PROCESSED), _pre) \
+#define VADC_NO_CHAN(_dname, _type, _mask, _pre) \
+ [VADC_##_dname] = { \
+ .datasheet_name = __stringify(_dname), \
+ .prescale_index = _pre, \
+ .type = _type, \
+ .info_mask = _mask \
+ },
-#define VADC_CHAN_VOLT(_dname, _pre) \
+#define VADC_CHAN_TEMP(_dname, _pre, _scale) \
+ VADC_CHAN(_dname, IIO_TEMP, \
+ BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_PROCESSED), \
+ _pre, _scale) \
+
+#define VADC_CHAN_VOLT(_dname, _pre, _scale) \
VADC_CHAN(_dname, IIO_VOLTAGE, \
- BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), \
+ BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_PROCESSED),\
+ _pre, _scale) \
+
+#define VADC_CHAN_NO_SCALE(_dname, _pre) \
+ VADC_NO_CHAN(_dname, IIO_VOLTAGE, \
+ BIT(IIO_CHAN_INFO_RAW), \
_pre) \
/*
* gaps in the array should be treated as reserved channels.
*/
static const struct vadc_channels vadc_chans[] = {
- VADC_CHAN_VOLT(USBIN, 4)
- VADC_CHAN_VOLT(DCIN, 4)
- VADC_CHAN_VOLT(VCHG_SNS, 3)
- VADC_CHAN_VOLT(SPARE1_03, 1)
- VADC_CHAN_VOLT(USB_ID_MV, 1)
- VADC_CHAN_VOLT(VCOIN, 1)
- VADC_CHAN_VOLT(VBAT_SNS, 1)
- VADC_CHAN_VOLT(VSYS, 1)
- VADC_CHAN_TEMP(DIE_TEMP, 0)
- VADC_CHAN_VOLT(REF_625MV, 0)
- VADC_CHAN_VOLT(REF_1250MV, 0)
- VADC_CHAN_VOLT(CHG_TEMP, 0)
- VADC_CHAN_VOLT(SPARE1, 0)
- VADC_CHAN_VOLT(SPARE2, 0)
- VADC_CHAN_VOLT(GND_REF, 0)
- VADC_CHAN_VOLT(VDD_VADC, 0)
-
- VADC_CHAN_VOLT(P_MUX1_1_1, 0)
- VADC_CHAN_VOLT(P_MUX2_1_1, 0)
- VADC_CHAN_VOLT(P_MUX3_1_1, 0)
- VADC_CHAN_VOLT(P_MUX4_1_1, 0)
- VADC_CHAN_VOLT(P_MUX5_1_1, 0)
- VADC_CHAN_VOLT(P_MUX6_1_1, 0)
- VADC_CHAN_VOLT(P_MUX7_1_1, 0)
- VADC_CHAN_VOLT(P_MUX8_1_1, 0)
- VADC_CHAN_VOLT(P_MUX9_1_1, 0)
- VADC_CHAN_VOLT(P_MUX10_1_1, 0)
- VADC_CHAN_VOLT(P_MUX11_1_1, 0)
- VADC_CHAN_VOLT(P_MUX12_1_1, 0)
- VADC_CHAN_VOLT(P_MUX13_1_1, 0)
- VADC_CHAN_VOLT(P_MUX14_1_1, 0)
- VADC_CHAN_VOLT(P_MUX15_1_1, 0)
- VADC_CHAN_VOLT(P_MUX16_1_1, 0)
-
- VADC_CHAN_VOLT(P_MUX1_1_3, 1)
- VADC_CHAN_VOLT(P_MUX2_1_3, 1)
- VADC_CHAN_VOLT(P_MUX3_1_3, 1)
- VADC_CHAN_VOLT(P_MUX4_1_3, 1)
- VADC_CHAN_VOLT(P_MUX5_1_3, 1)
- VADC_CHAN_VOLT(P_MUX6_1_3, 1)
- VADC_CHAN_VOLT(P_MUX7_1_3, 1)
- VADC_CHAN_VOLT(P_MUX8_1_3, 1)
- VADC_CHAN_VOLT(P_MUX9_1_3, 1)
- VADC_CHAN_VOLT(P_MUX10_1_3, 1)
- VADC_CHAN_VOLT(P_MUX11_1_3, 1)
- VADC_CHAN_VOLT(P_MUX12_1_3, 1)
- VADC_CHAN_VOLT(P_MUX13_1_3, 1)
- VADC_CHAN_VOLT(P_MUX14_1_3, 1)
- VADC_CHAN_VOLT(P_MUX15_1_3, 1)
- VADC_CHAN_VOLT(P_MUX16_1_3, 1)
-
- VADC_CHAN_VOLT(LR_MUX1_BAT_THERM, 0)
- VADC_CHAN_VOLT(LR_MUX2_BAT_ID, 0)
- VADC_CHAN_VOLT(LR_MUX3_XO_THERM, 0)
- VADC_CHAN_VOLT(LR_MUX4_AMUX_THM1, 0)
- VADC_CHAN_VOLT(LR_MUX5_AMUX_THM2, 0)
- VADC_CHAN_VOLT(LR_MUX6_AMUX_THM3, 0)
- VADC_CHAN_VOLT(LR_MUX7_HW_ID, 0)
- VADC_CHAN_VOLT(LR_MUX8_AMUX_THM4, 0)
- VADC_CHAN_VOLT(LR_MUX9_AMUX_THM5, 0)
- VADC_CHAN_VOLT(LR_MUX10_USB_ID, 0)
- VADC_CHAN_VOLT(AMUX_PU1, 0)
- VADC_CHAN_VOLT(AMUX_PU2, 0)
- VADC_CHAN_VOLT(LR_MUX3_BUF_XO_THERM, 0)
-
- VADC_CHAN_VOLT(LR_MUX1_PU1_BAT_THERM, 0)
- VADC_CHAN_VOLT(LR_MUX2_PU1_BAT_ID, 0)
- VADC_CHAN_VOLT(LR_MUX3_PU1_XO_THERM, 0)
- VADC_CHAN_VOLT(LR_MUX4_PU1_AMUX_THM1, 0)
- VADC_CHAN_VOLT(LR_MUX5_PU1_AMUX_THM2, 0)
- VADC_CHAN_VOLT(LR_MUX6_PU1_AMUX_THM3, 0)
- VADC_CHAN_VOLT(LR_MUX7_PU1_AMUX_HW_ID, 0)
- VADC_CHAN_VOLT(LR_MUX8_PU1_AMUX_THM4, 0)
- VADC_CHAN_VOLT(LR_MUX9_PU1_AMUX_THM5, 0)
- VADC_CHAN_VOLT(LR_MUX10_PU1_AMUX_USB_ID, 0)
- VADC_CHAN_VOLT(LR_MUX3_BUF_PU1_XO_THERM, 0)
-
- VADC_CHAN_VOLT(LR_MUX1_PU2_BAT_THERM, 0)
- VADC_CHAN_VOLT(LR_MUX2_PU2_BAT_ID, 0)
- VADC_CHAN_VOLT(LR_MUX3_PU2_XO_THERM, 0)
- VADC_CHAN_VOLT(LR_MUX4_PU2_AMUX_THM1, 0)
- VADC_CHAN_VOLT(LR_MUX5_PU2_AMUX_THM2, 0)
- VADC_CHAN_VOLT(LR_MUX6_PU2_AMUX_THM3, 0)
- VADC_CHAN_VOLT(LR_MUX7_PU2_AMUX_HW_ID, 0)
- VADC_CHAN_VOLT(LR_MUX8_PU2_AMUX_THM4, 0)
- VADC_CHAN_VOLT(LR_MUX9_PU2_AMUX_THM5, 0)
- VADC_CHAN_VOLT(LR_MUX10_PU2_AMUX_USB_ID, 0)
- VADC_CHAN_VOLT(LR_MUX3_BUF_PU2_XO_THERM, 0)
-
- VADC_CHAN_VOLT(LR_MUX1_PU1_PU2_BAT_THERM, 0)
- VADC_CHAN_VOLT(LR_MUX2_PU1_PU2_BAT_ID, 0)
- VADC_CHAN_VOLT(LR_MUX3_PU1_PU2_XO_THERM, 0)
- VADC_CHAN_VOLT(LR_MUX4_PU1_PU2_AMUX_THM1, 0)
- VADC_CHAN_VOLT(LR_MUX5_PU1_PU2_AMUX_THM2, 0)
- VADC_CHAN_VOLT(LR_MUX6_PU1_PU2_AMUX_THM3, 0)
- VADC_CHAN_VOLT(LR_MUX7_PU1_PU2_AMUX_HW_ID, 0)
- VADC_CHAN_VOLT(LR_MUX8_PU1_PU2_AMUX_THM4, 0)
- VADC_CHAN_VOLT(LR_MUX9_PU1_PU2_AMUX_THM5, 0)
- VADC_CHAN_VOLT(LR_MUX10_PU1_PU2_AMUX_USB_ID, 0)
- VADC_CHAN_VOLT(LR_MUX3_BUF_PU1_PU2_XO_THERM, 0)
+ VADC_CHAN_VOLT(USBIN, 4, SCALE_DEFAULT)
+ VADC_CHAN_VOLT(DCIN, 4, SCALE_DEFAULT)
+ VADC_CHAN_NO_SCALE(VCHG_SNS, 3)
+ VADC_CHAN_NO_SCALE(SPARE1_03, 1)
+ VADC_CHAN_NO_SCALE(USB_ID_MV, 1)
+ VADC_CHAN_VOLT(VCOIN, 1, SCALE_DEFAULT)
+ VADC_CHAN_NO_SCALE(VBAT_SNS, 1)
+ VADC_CHAN_VOLT(VSYS, 1, SCALE_DEFAULT)
+ VADC_CHAN_TEMP(DIE_TEMP, 0, SCALE_PMIC_THERM)
+ VADC_CHAN_VOLT(REF_625MV, 0, SCALE_DEFAULT)
+ VADC_CHAN_VOLT(REF_1250MV, 0, SCALE_DEFAULT)
+ VADC_CHAN_NO_SCALE(CHG_TEMP, 0)
+ VADC_CHAN_NO_SCALE(SPARE1, 0)
+ VADC_CHAN_TEMP(SPARE2, 0, SCALE_PMI_CHG_TEMP)
+ VADC_CHAN_VOLT(GND_REF, 0, SCALE_DEFAULT)
+ VADC_CHAN_VOLT(VDD_VADC, 0, SCALE_DEFAULT)
+
+ VADC_CHAN_NO_SCALE(P_MUX1_1_1, 0)
+ VADC_CHAN_NO_SCALE(P_MUX2_1_1, 0)
+ VADC_CHAN_NO_SCALE(P_MUX3_1_1, 0)
+ VADC_CHAN_NO_SCALE(P_MUX4_1_1, 0)
+ VADC_CHAN_NO_SCALE(P_MUX5_1_1, 0)
+ VADC_CHAN_NO_SCALE(P_MUX6_1_1, 0)
+ VADC_CHAN_NO_SCALE(P_MUX7_1_1, 0)
+ VADC_CHAN_NO_SCALE(P_MUX8_1_1, 0)
+ VADC_CHAN_NO_SCALE(P_MUX9_1_1, 0)
+ VADC_CHAN_NO_SCALE(P_MUX10_1_1, 0)
+ VADC_CHAN_NO_SCALE(P_MUX11_1_1, 0)
+ VADC_CHAN_NO_SCALE(P_MUX12_1_1, 0)
+ VADC_CHAN_NO_SCALE(P_MUX13_1_1, 0)
+ VADC_CHAN_NO_SCALE(P_MUX14_1_1, 0)
+ VADC_CHAN_NO_SCALE(P_MUX15_1_1, 0)
+ VADC_CHAN_NO_SCALE(P_MUX16_1_1, 0)
+
+ VADC_CHAN_NO_SCALE(P_MUX1_1_3, 1)
+ VADC_CHAN_NO_SCALE(P_MUX2_1_3, 1)
+ VADC_CHAN_NO_SCALE(P_MUX3_1_3, 1)
+ VADC_CHAN_NO_SCALE(P_MUX4_1_3, 1)
+ VADC_CHAN_NO_SCALE(P_MUX5_1_3, 1)
+ VADC_CHAN_NO_SCALE(P_MUX6_1_3, 1)
+ VADC_CHAN_NO_SCALE(P_MUX7_1_3, 1)
+ VADC_CHAN_NO_SCALE(P_MUX8_1_3, 1)
+ VADC_CHAN_NO_SCALE(P_MUX9_1_3, 1)
+ VADC_CHAN_NO_SCALE(P_MUX10_1_3, 1)
+ VADC_CHAN_NO_SCALE(P_MUX11_1_3, 1)
+ VADC_CHAN_NO_SCALE(P_MUX12_1_3, 1)
+ VADC_CHAN_NO_SCALE(P_MUX13_1_3, 1)
+ VADC_CHAN_NO_SCALE(P_MUX14_1_3, 1)
+ VADC_CHAN_NO_SCALE(P_MUX15_1_3, 1)
+ VADC_CHAN_NO_SCALE(P_MUX16_1_3, 1)
+
+ VADC_CHAN_NO_SCALE(LR_MUX1_BAT_THERM, 0)
+ VADC_CHAN_NO_SCALE(LR_MUX2_BAT_ID, 0)
+ VADC_CHAN_NO_SCALE(LR_MUX3_XO_THERM, 0)
+ VADC_CHAN_NO_SCALE(LR_MUX4_AMUX_THM1, 0)
+ VADC_CHAN_NO_SCALE(LR_MUX5_AMUX_THM2, 0)
+ VADC_CHAN_NO_SCALE(LR_MUX6_AMUX_THM3, 0)
+ VADC_CHAN_NO_SCALE(LR_MUX7_HW_ID, 0)
+ VADC_CHAN_NO_SCALE(LR_MUX8_AMUX_THM4, 0)
+ VADC_CHAN_NO_SCALE(LR_MUX9_AMUX_THM5, 0)
+ VADC_CHAN_NO_SCALE(LR_MUX10_USB_ID, 0)
+ VADC_CHAN_NO_SCALE(AMUX_PU1, 0)
+ VADC_CHAN_NO_SCALE(AMUX_PU2, 0)
+ VADC_CHAN_NO_SCALE(LR_MUX3_BUF_XO_THERM, 0)
+
+ VADC_CHAN_NO_SCALE(LR_MUX1_PU1_BAT_THERM, 0)
+ VADC_CHAN_NO_SCALE(LR_MUX2_PU1_BAT_ID, 0)
+ VADC_CHAN_NO_SCALE(LR_MUX3_PU1_XO_THERM, 0)
+ VADC_CHAN_TEMP(LR_MUX4_PU1_AMUX_THM1, 0, SCALE_THERM_100K_PULLUP)
+ VADC_CHAN_TEMP(LR_MUX5_PU1_AMUX_THM2, 0, SCALE_THERM_100K_PULLUP)
+ VADC_CHAN_TEMP(LR_MUX6_PU1_AMUX_THM3, 0, SCALE_THERM_100K_PULLUP)
+ VADC_CHAN_NO_SCALE(LR_MUX7_PU1_AMUX_HW_ID, 0)
+ VADC_CHAN_TEMP(LR_MUX8_PU1_AMUX_THM4, 0, SCALE_THERM_100K_PULLUP)
+ VADC_CHAN_TEMP(LR_MUX9_PU1_AMUX_THM5, 0, SCALE_THERM_100K_PULLUP)
+ VADC_CHAN_NO_SCALE(LR_MUX10_PU1_AMUX_USB_ID, 0)
+ VADC_CHAN_TEMP(LR_MUX3_BUF_PU1_XO_THERM, 0, SCALE_XOTHERM)
+
+ VADC_CHAN_NO_SCALE(LR_MUX1_PU2_BAT_THERM, 0)
+ VADC_CHAN_NO_SCALE(LR_MUX2_PU2_BAT_ID, 0)
+ VADC_CHAN_NO_SCALE(LR_MUX3_PU2_XO_THERM, 0)
+ VADC_CHAN_NO_SCALE(LR_MUX4_PU2_AMUX_THM1, 0)
+ VADC_CHAN_NO_SCALE(LR_MUX5_PU2_AMUX_THM2, 0)
+ VADC_CHAN_NO_SCALE(LR_MUX6_PU2_AMUX_THM3, 0)
+ VADC_CHAN_NO_SCALE(LR_MUX7_PU2_AMUX_HW_ID, 0)
+ VADC_CHAN_NO_SCALE(LR_MUX8_PU2_AMUX_THM4, 0)
+ VADC_CHAN_NO_SCALE(LR_MUX9_PU2_AMUX_THM5, 0)
+ VADC_CHAN_NO_SCALE(LR_MUX10_PU2_AMUX_USB_ID, 0)
+ VADC_CHAN_NO_SCALE(LR_MUX3_BUF_PU2_XO_THERM, 0)
+
+ VADC_CHAN_NO_SCALE(LR_MUX1_PU1_PU2_BAT_THERM, 0)
+ VADC_CHAN_NO_SCALE(LR_MUX2_PU1_PU2_BAT_ID, 0)
+ VADC_CHAN_NO_SCALE(LR_MUX3_PU1_PU2_XO_THERM, 0)
+ VADC_CHAN_NO_SCALE(LR_MUX4_PU1_PU2_AMUX_THM1, 0)
+ VADC_CHAN_NO_SCALE(LR_MUX5_PU1_PU2_AMUX_THM2, 0)
+ VADC_CHAN_NO_SCALE(LR_MUX6_PU1_PU2_AMUX_THM3, 0)
+ VADC_CHAN_NO_SCALE(LR_MUX7_PU1_PU2_AMUX_HW_ID, 0)
+ VADC_CHAN_NO_SCALE(LR_MUX8_PU1_PU2_AMUX_THM4, 0)
+ VADC_CHAN_NO_SCALE(LR_MUX9_PU1_PU2_AMUX_THM5, 0)
+ VADC_CHAN_NO_SCALE(LR_MUX10_PU1_PU2_AMUX_USB_ID, 0)
+ VADC_CHAN_NO_SCALE(LR_MUX3_BUF_PU1_PU2_XO_THERM, 0)
};
static int vadc_get_dt_channel_data(struct device *dev,
return ret;
}
+ prop.scale_fn = vadc_chans[prop.channel].scale_fn;
vadc->chan_props[index] = prop;
vadc_chan = &vadc_chans[prop.channel];
--- /dev/null
+/*
+ * Renesas R-Car GyroADC driver
+ *
+ * Copyright 2016 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * 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/platform_device.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of_platform.h>
+#include <linux/err.h>
+#include <linux/pm_runtime.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger.h>
+
+#define DRIVER_NAME "rcar-gyroadc"
+
+/* GyroADC registers. */
+#define RCAR_GYROADC_MODE_SELECT 0x00
+#define RCAR_GYROADC_MODE_SELECT_1_MB88101A 0x0
+#define RCAR_GYROADC_MODE_SELECT_2_ADCS7476 0x1
+#define RCAR_GYROADC_MODE_SELECT_3_MAX1162 0x3
+
+#define RCAR_GYROADC_START_STOP 0x04
+#define RCAR_GYROADC_START_STOP_START BIT(0)
+
+#define RCAR_GYROADC_CLOCK_LENGTH 0x08
+#define RCAR_GYROADC_1_25MS_LENGTH 0x0c
+
+#define RCAR_GYROADC_REALTIME_DATA(ch) (0x10 + ((ch) * 4))
+#define RCAR_GYROADC_100MS_ADDED_DATA(ch) (0x30 + ((ch) * 4))
+#define RCAR_GYROADC_10MS_AVG_DATA(ch) (0x50 + ((ch) * 4))
+
+#define RCAR_GYROADC_FIFO_STATUS 0x70
+#define RCAR_GYROADC_FIFO_STATUS_EMPTY(ch) BIT(0 + (4 * (ch)))
+#define RCAR_GYROADC_FIFO_STATUS_FULL(ch) BIT(1 + (4 * (ch)))
+#define RCAR_GYROADC_FIFO_STATUS_ERROR(ch) BIT(2 + (4 * (ch)))
+
+#define RCAR_GYROADC_INTR 0x74
+#define RCAR_GYROADC_INTR_INT BIT(0)
+
+#define RCAR_GYROADC_INTENR 0x78
+#define RCAR_GYROADC_INTENR_INTEN BIT(0)
+
+#define RCAR_GYROADC_SAMPLE_RATE 800 /* Hz */
+
+#define RCAR_GYROADC_RUNTIME_PM_DELAY_MS 2000
+
+enum rcar_gyroadc_model {
+ RCAR_GYROADC_MODEL_DEFAULT,
+ RCAR_GYROADC_MODEL_R8A7792,
+};
+
+struct rcar_gyroadc {
+ struct device *dev;
+ void __iomem *regs;
+ struct clk *iclk;
+ struct regulator *vref[8];
+ unsigned int num_channels;
+ enum rcar_gyroadc_model model;
+ unsigned int mode;
+ unsigned int sample_width;
+};
+
+static void rcar_gyroadc_hw_init(struct rcar_gyroadc *priv)
+{
+ const unsigned long clk_mhz = clk_get_rate(priv->iclk) / 1000000;
+ const unsigned long clk_mul =
+ (priv->mode == RCAR_GYROADC_MODE_SELECT_1_MB88101A) ? 10 : 5;
+ unsigned long clk_len = clk_mhz * clk_mul;
+
+ /*
+ * According to the R-Car Gen2 datasheet Rev. 1.01, Sept 08 2014,
+ * page 77-7, clock length must be even number. If it's odd number,
+ * add one.
+ */
+ if (clk_len & 1)
+ clk_len++;
+
+ /* Stop the GyroADC. */
+ writel(0, priv->regs + RCAR_GYROADC_START_STOP);
+
+ /* Disable IRQ on V2H. */
+ if (priv->model == RCAR_GYROADC_MODEL_R8A7792)
+ writel(0, priv->regs + RCAR_GYROADC_INTENR);
+
+ /* Set mode and timing. */
+ writel(priv->mode, priv->regs + RCAR_GYROADC_MODE_SELECT);
+ writel(clk_len, priv->regs + RCAR_GYROADC_CLOCK_LENGTH);
+ writel(clk_mhz * 1250, priv->regs + RCAR_GYROADC_1_25MS_LENGTH);
+}
+
+static void rcar_gyroadc_hw_start(struct rcar_gyroadc *priv)
+{
+ /* Start sampling. */
+ writel(RCAR_GYROADC_START_STOP_START,
+ priv->regs + RCAR_GYROADC_START_STOP);
+
+ /*
+ * Wait for the first conversion to complete. This is longer than
+ * the 1.25 mS in the datasheet because 1.25 mS is not enough for
+ * the hardware to deliver the first sample and the hardware does
+ * then return zeroes instead of valid data.
+ */
+ mdelay(3);
+}
+
+static void rcar_gyroadc_hw_stop(struct rcar_gyroadc *priv)
+{
+ /* Stop the GyroADC. */
+ writel(0, priv->regs + RCAR_GYROADC_START_STOP);
+}
+
+#define RCAR_GYROADC_CHAN(_idx) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = (_idx), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+}
+
+static const struct iio_chan_spec rcar_gyroadc_iio_channels_1[] = {
+ RCAR_GYROADC_CHAN(0),
+ RCAR_GYROADC_CHAN(1),
+ RCAR_GYROADC_CHAN(2),
+ RCAR_GYROADC_CHAN(3),
+};
+
+static const struct iio_chan_spec rcar_gyroadc_iio_channels_2[] = {
+ RCAR_GYROADC_CHAN(0),
+ RCAR_GYROADC_CHAN(1),
+ RCAR_GYROADC_CHAN(2),
+ RCAR_GYROADC_CHAN(3),
+ RCAR_GYROADC_CHAN(4),
+ RCAR_GYROADC_CHAN(5),
+ RCAR_GYROADC_CHAN(6),
+ RCAR_GYROADC_CHAN(7),
+};
+
+static const struct iio_chan_spec rcar_gyroadc_iio_channels_3[] = {
+ RCAR_GYROADC_CHAN(0),
+ RCAR_GYROADC_CHAN(1),
+ RCAR_GYROADC_CHAN(2),
+ RCAR_GYROADC_CHAN(3),
+ RCAR_GYROADC_CHAN(4),
+ RCAR_GYROADC_CHAN(5),
+ RCAR_GYROADC_CHAN(6),
+ RCAR_GYROADC_CHAN(7),
+};
+
+static int rcar_gyroadc_set_power(struct rcar_gyroadc *priv, bool on)
+{
+ struct device *dev = priv->dev;
+ int ret;
+
+ if (on) {
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0)
+ pm_runtime_put_noidle(dev);
+ } else {
+ pm_runtime_mark_last_busy(dev);
+ ret = pm_runtime_put_autosuspend(dev);
+ }
+
+ return ret;
+}
+
+static int rcar_gyroadc_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct rcar_gyroadc *priv = iio_priv(indio_dev);
+ struct regulator *consumer;
+ unsigned int datareg = RCAR_GYROADC_REALTIME_DATA(chan->channel);
+ unsigned int vref;
+ int ret;
+
+ /*
+ * MB88101 is special in that it has only single regulator for
+ * all four channels.
+ */
+ if (priv->mode == RCAR_GYROADC_MODE_SELECT_1_MB88101A)
+ consumer = priv->vref[0];
+ else
+ consumer = priv->vref[chan->channel];
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (chan->type != IIO_VOLTAGE)
+ return -EINVAL;
+
+ /* Channel not connected. */
+ if (!consumer)
+ return -EINVAL;
+
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
+
+ ret = rcar_gyroadc_set_power(priv, true);
+ if (ret < 0) {
+ iio_device_release_direct_mode(indio_dev);
+ return ret;
+ }
+
+ *val = readl(priv->regs + datareg);
+ *val &= BIT(priv->sample_width) - 1;
+
+ ret = rcar_gyroadc_set_power(priv, false);
+ iio_device_release_direct_mode(indio_dev);
+ if (ret < 0)
+ return ret;
+
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ /* Channel not connected. */
+ if (!consumer)
+ return -EINVAL;
+
+ vref = regulator_get_voltage(consumer);
+ *val = vref / 1000;
+ *val2 = 1 << priv->sample_width;
+
+ return IIO_VAL_FRACTIONAL;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *val = RCAR_GYROADC_SAMPLE_RATE;
+
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int rcar_gyroadc_reg_access(struct iio_dev *indio_dev,
+ unsigned int reg, unsigned int writeval,
+ unsigned int *readval)
+{
+ struct rcar_gyroadc *priv = iio_priv(indio_dev);
+ unsigned int maxreg = RCAR_GYROADC_FIFO_STATUS;
+
+ if (readval == NULL)
+ return -EINVAL;
+
+ if (reg % 4)
+ return -EINVAL;
+
+ /* Handle the V2H case with extra interrupt block. */
+ if (priv->model == RCAR_GYROADC_MODEL_R8A7792)
+ maxreg = RCAR_GYROADC_INTENR;
+
+ if (reg > maxreg)
+ return -EINVAL;
+
+ *readval = readl(priv->regs + reg);
+
+ return 0;
+}
+
+static const struct iio_info rcar_gyroadc_iio_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = rcar_gyroadc_read_raw,
+ .debugfs_reg_access = rcar_gyroadc_reg_access,
+};
+
+static const struct of_device_id rcar_gyroadc_match[] = {
+ {
+ /* R-Car compatible GyroADC */
+ .compatible = "renesas,rcar-gyroadc",
+ .data = (void *)RCAR_GYROADC_MODEL_DEFAULT,
+ }, {
+ /* R-Car V2H specialty with interrupt registers. */
+ .compatible = "renesas,r8a7792-gyroadc",
+ .data = (void *)RCAR_GYROADC_MODEL_R8A7792,
+ }, {
+ /* sentinel */
+ }
+};
+
+MODULE_DEVICE_TABLE(of, rcar_gyroadc_match);
+
+static const struct of_device_id rcar_gyroadc_child_match[] = {
+ /* Mode 1 ADCs */
+ {
+ .compatible = "fujitsu,mb88101a",
+ .data = (void *)RCAR_GYROADC_MODE_SELECT_1_MB88101A,
+ },
+ /* Mode 2 ADCs */
+ {
+ .compatible = "ti,adcs7476",
+ .data = (void *)RCAR_GYROADC_MODE_SELECT_2_ADCS7476,
+ }, {
+ .compatible = "ti,adc121",
+ .data = (void *)RCAR_GYROADC_MODE_SELECT_2_ADCS7476,
+ }, {
+ .compatible = "adi,ad7476",
+ .data = (void *)RCAR_GYROADC_MODE_SELECT_2_ADCS7476,
+ },
+ /* Mode 3 ADCs */
+ {
+ .compatible = "maxim,max1162",
+ .data = (void *)RCAR_GYROADC_MODE_SELECT_3_MAX1162,
+ }, {
+ .compatible = "maxim,max11100",
+ .data = (void *)RCAR_GYROADC_MODE_SELECT_3_MAX1162,
+ },
+ { /* sentinel */ }
+};
+
+static int rcar_gyroadc_parse_subdevs(struct iio_dev *indio_dev)
+{
+ const struct of_device_id *of_id;
+ const struct iio_chan_spec *channels;
+ struct rcar_gyroadc *priv = iio_priv(indio_dev);
+ struct device *dev = priv->dev;
+ struct device_node *np = dev->of_node;
+ struct device_node *child;
+ struct regulator *vref;
+ unsigned int reg;
+ unsigned int adcmode, childmode;
+ unsigned int sample_width;
+ unsigned int num_channels;
+ int ret, first = 1;
+
+ for_each_child_of_node(np, child) {
+ of_id = of_match_node(rcar_gyroadc_child_match, child);
+ if (!of_id) {
+ dev_err(dev, "Ignoring unsupported ADC \"%s\".",
+ child->name);
+ continue;
+ }
+
+ childmode = (unsigned int)of_id->data;
+ switch (childmode) {
+ case RCAR_GYROADC_MODE_SELECT_1_MB88101A:
+ sample_width = 12;
+ channels = rcar_gyroadc_iio_channels_1;
+ num_channels = ARRAY_SIZE(rcar_gyroadc_iio_channels_1);
+ break;
+ case RCAR_GYROADC_MODE_SELECT_2_ADCS7476:
+ sample_width = 15;
+ channels = rcar_gyroadc_iio_channels_2;
+ num_channels = ARRAY_SIZE(rcar_gyroadc_iio_channels_2);
+ break;
+ case RCAR_GYROADC_MODE_SELECT_3_MAX1162:
+ sample_width = 16;
+ channels = rcar_gyroadc_iio_channels_3;
+ num_channels = ARRAY_SIZE(rcar_gyroadc_iio_channels_3);
+ break;
+ }
+
+ /*
+ * MB88101 is special in that it's only a single chip taking
+ * up all the CHS lines. Thus, the DT binding is also special
+ * and has no reg property. If we run into such ADC, handle
+ * it here.
+ */
+ if (childmode == RCAR_GYROADC_MODE_SELECT_1_MB88101A) {
+ reg = 0;
+ } else {
+ ret = of_property_read_u32(child, "reg", ®);
+ if (ret) {
+ dev_err(dev,
+ "Failed to get child reg property of ADC \"%s\".\n",
+ child->name);
+ return ret;
+ }
+
+ /* Channel number is too high. */
+ if (reg >= num_channels) {
+ dev_err(dev,
+ "Only %i channels supported with %s, but reg = <%i>.\n",
+ num_channels, child->name, reg);
+ return ret;
+ }
+ }
+
+ /* Child node selected different mode than the rest. */
+ if (!first && (adcmode != childmode)) {
+ dev_err(dev,
+ "Channel %i uses different ADC mode than the rest.\n",
+ reg);
+ return ret;
+ }
+
+ /* Channel is valid, grab the regulator. */
+ dev->of_node = child;
+ vref = devm_regulator_get(dev, "vref");
+ dev->of_node = np;
+ if (IS_ERR(vref)) {
+ dev_dbg(dev, "Channel %i 'vref' supply not connected.\n",
+ reg);
+ return PTR_ERR(vref);
+ }
+
+ priv->vref[reg] = vref;
+
+ if (!first)
+ continue;
+
+ /* First child node which passed sanity tests. */
+ adcmode = childmode;
+ first = 0;
+
+ priv->num_channels = num_channels;
+ priv->mode = childmode;
+ priv->sample_width = sample_width;
+
+ indio_dev->channels = channels;
+ indio_dev->num_channels = num_channels;
+
+ /*
+ * MB88101 is special and we only have one such device
+ * attached to the GyroADC at a time, so if we found it,
+ * we can stop parsing here.
+ */
+ if (childmode == RCAR_GYROADC_MODE_SELECT_1_MB88101A)
+ break;
+ }
+
+ if (first) {
+ dev_err(dev, "No valid ADC channels found, aborting.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void rcar_gyroadc_deinit_supplies(struct iio_dev *indio_dev)
+{
+ struct rcar_gyroadc *priv = iio_priv(indio_dev);
+ unsigned int i;
+
+ for (i = 0; i < priv->num_channels; i++) {
+ if (!priv->vref[i])
+ continue;
+
+ regulator_disable(priv->vref[i]);
+ }
+}
+
+static int rcar_gyroadc_init_supplies(struct iio_dev *indio_dev)
+{
+ struct rcar_gyroadc *priv = iio_priv(indio_dev);
+ struct device *dev = priv->dev;
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < priv->num_channels; i++) {
+ if (!priv->vref[i])
+ continue;
+
+ ret = regulator_enable(priv->vref[i]);
+ if (ret) {
+ dev_err(dev, "Failed to enable regulator %i (ret=%i)\n",
+ i, ret);
+ goto err;
+ }
+ }
+
+ return 0;
+
+err:
+ rcar_gyroadc_deinit_supplies(indio_dev);
+ return ret;
+}
+
+static int rcar_gyroadc_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *of_id =
+ of_match_device(rcar_gyroadc_match, &pdev->dev);
+ struct device *dev = &pdev->dev;
+ struct rcar_gyroadc *priv;
+ struct iio_dev *indio_dev;
+ struct resource *mem;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
+ if (!indio_dev) {
+ dev_err(dev, "Failed to allocate IIO device.\n");
+ return -ENOMEM;
+ }
+
+ priv = iio_priv(indio_dev);
+ priv->dev = dev;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->regs = devm_ioremap_resource(dev, mem);
+ if (IS_ERR(priv->regs))
+ return PTR_ERR(priv->regs);
+
+ priv->iclk = devm_clk_get(dev, "if");
+ if (IS_ERR(priv->iclk)) {
+ ret = PTR_ERR(priv->iclk);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get IF clock (ret=%i)\n", ret);
+ return ret;
+ }
+
+ ret = rcar_gyroadc_parse_subdevs(indio_dev);
+ if (ret)
+ return ret;
+
+ ret = rcar_gyroadc_init_supplies(indio_dev);
+ if (ret)
+ return ret;
+
+ priv->model = (enum rcar_gyroadc_model)of_id->data;
+
+ platform_set_drvdata(pdev, indio_dev);
+
+ indio_dev->name = DRIVER_NAME;
+ indio_dev->dev.parent = dev;
+ indio_dev->dev.of_node = pdev->dev.of_node;
+ indio_dev->info = &rcar_gyroadc_iio_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = clk_prepare_enable(priv->iclk);
+ if (ret) {
+ dev_err(dev, "Could not prepare or enable the IF clock.\n");
+ goto err_clk_if_enable;
+ }
+
+ pm_runtime_set_autosuspend_delay(dev, RCAR_GYROADC_RUNTIME_PM_DELAY_MS);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_enable(dev);
+
+ pm_runtime_get_sync(dev);
+ rcar_gyroadc_hw_init(priv);
+ rcar_gyroadc_hw_start(priv);
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(dev, "Couldn't register IIO device.\n");
+ goto err_iio_device_register;
+ }
+
+ pm_runtime_put_sync(dev);
+
+ return 0;
+
+err_iio_device_register:
+ rcar_gyroadc_hw_stop(priv);
+ pm_runtime_put_sync(dev);
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+ clk_disable_unprepare(priv->iclk);
+err_clk_if_enable:
+ rcar_gyroadc_deinit_supplies(indio_dev);
+
+ return ret;
+}
+
+static int rcar_gyroadc_remove(struct platform_device *pdev)
+{
+ struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+ struct rcar_gyroadc *priv = iio_priv(indio_dev);
+ struct device *dev = priv->dev;
+
+ iio_device_unregister(indio_dev);
+ pm_runtime_get_sync(dev);
+ rcar_gyroadc_hw_stop(priv);
+ pm_runtime_put_sync(dev);
+ pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
+ clk_disable_unprepare(priv->iclk);
+ rcar_gyroadc_deinit_supplies(indio_dev);
+
+ return 0;
+}
+
+#if defined(CONFIG_PM)
+static int rcar_gyroadc_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct rcar_gyroadc *priv = iio_priv(indio_dev);
+
+ rcar_gyroadc_hw_stop(priv);
+
+ return 0;
+}
+
+static int rcar_gyroadc_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct rcar_gyroadc *priv = iio_priv(indio_dev);
+
+ rcar_gyroadc_hw_start(priv);
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops rcar_gyroadc_pm_ops = {
+ SET_RUNTIME_PM_OPS(rcar_gyroadc_suspend, rcar_gyroadc_resume, NULL)
+};
+
+static struct platform_driver rcar_gyroadc_driver = {
+ .probe = rcar_gyroadc_probe,
+ .remove = rcar_gyroadc_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .of_match_table = rcar_gyroadc_match,
+ .pm = &rcar_gyroadc_pm_ops,
+ },
+};
+
+module_platform_driver(rcar_gyroadc_driver);
+
+MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
+MODULE_DESCRIPTION("Renesas R-Car GyroADC driver");
+MODULE_LICENSE("GPL");
priv->common.base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(priv->common.base))
return PTR_ERR(priv->common.base);
+ priv->common.phys_base = res->start;
priv->vref = devm_regulator_get(&pdev->dev, "vref");
if (IS_ERR(priv->vref)) {
/**
* struct stm32_adc_common - stm32 ADC driver common data (for all instances)
* @base: control registers base cpu addr
+ * @phys_base: control registers base physical addr
* @vref_mv: vref voltage (mv)
*/
struct stm32_adc_common {
void __iomem *base;
+ phys_addr_t phys_base;
int vref_mv;
};
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/timer/stm32-timer-trigger.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
/* STM32F4_ADC_CR2 - bit fields */
#define STM32F4_SWSTART BIT(30)
+#define STM32F4_EXTEN_SHIFT 28
#define STM32F4_EXTEN_MASK GENMASK(29, 28)
+#define STM32F4_EXTSEL_SHIFT 24
+#define STM32F4_EXTSEL_MASK GENMASK(27, 24)
#define STM32F4_EOCS BIT(10)
+#define STM32F4_DDS BIT(9)
+#define STM32F4_DMA BIT(8)
#define STM32F4_ADON BIT(0)
-/* STM32F4_ADC_SQR1 - bit fields */
-#define STM32F4_L_SHIFT 20
-#define STM32F4_L_MASK GENMASK(23, 20)
-
-/* STM32F4_ADC_SQR3 - bit fields */
-#define STM32F4_SQ1_SHIFT 0
-#define STM32F4_SQ1_MASK GENMASK(4, 0)
-
+#define STM32_ADC_MAX_SQ 16 /* SQ1..SQ16 */
#define STM32_ADC_TIMEOUT_US 100000
#define STM32_ADC_TIMEOUT (msecs_to_jiffies(STM32_ADC_TIMEOUT_US / 1000))
+#define STM32_DMA_BUFFER_SIZE PAGE_SIZE
+
+/* External trigger enable */
+enum stm32_adc_exten {
+ STM32_EXTEN_SWTRIG,
+ STM32_EXTEN_HWTRIG_RISING_EDGE,
+ STM32_EXTEN_HWTRIG_FALLING_EDGE,
+ STM32_EXTEN_HWTRIG_BOTH_EDGES,
+};
+
+/* extsel - trigger mux selection value */
+enum stm32_adc_extsel {
+ STM32_EXT0,
+ STM32_EXT1,
+ STM32_EXT2,
+ STM32_EXT3,
+ STM32_EXT4,
+ STM32_EXT5,
+ STM32_EXT6,
+ STM32_EXT7,
+ STM32_EXT8,
+ STM32_EXT9,
+ STM32_EXT10,
+ STM32_EXT11,
+ STM32_EXT12,
+ STM32_EXT13,
+ STM32_EXT14,
+ STM32_EXT15,
+};
+
+/**
+ * struct stm32_adc_trig_info - ADC trigger info
+ * @name: name of the trigger, corresponding to its source
+ * @extsel: trigger selection
+ */
+struct stm32_adc_trig_info {
+ const char *name;
+ enum stm32_adc_extsel extsel;
+};
+
+/**
+ * stm32_adc_regs - stm32 ADC misc registers & bitfield desc
+ * @reg: register offset
+ * @mask: bitfield mask
+ * @shift: left shift
+ */
+struct stm32_adc_regs {
+ int reg;
+ int mask;
+ int shift;
+};
+
/**
* struct stm32_adc - private data of each ADC IIO instance
* @common: reference to ADC block common data
* @clk: clock for this adc instance
* @irq: interrupt for this adc instance
* @lock: spinlock
+ * @bufi: data buffer index
+ * @num_conv: expected number of scan conversions
+ * @trigger_polarity: external trigger polarity (e.g. exten)
+ * @dma_chan: dma channel
+ * @rx_buf: dma rx buffer cpu address
+ * @rx_dma_buf: dma rx buffer bus address
+ * @rx_buf_sz: dma rx buffer size
*/
struct stm32_adc {
struct stm32_adc_common *common;
u32 offset;
struct completion completion;
- u16 *buffer;
+ u16 buffer[STM32_ADC_MAX_SQ];
struct clk *clk;
int irq;
spinlock_t lock; /* interrupt lock */
+ unsigned int bufi;
+ unsigned int num_conv;
+ u32 trigger_polarity;
+ struct dma_chan *dma_chan;
+ u8 *rx_buf;
+ dma_addr_t rx_dma_buf;
+ unsigned int rx_buf_sz;
};
/**
{ IIO_VOLTAGE, 15, "in15" },
};
+/**
+ * stm32f4_sq - describe regular sequence registers
+ * - L: sequence len (register & bit field)
+ * - SQ1..SQ16: sequence entries (register & bit field)
+ */
+static const struct stm32_adc_regs stm32f4_sq[STM32_ADC_MAX_SQ + 1] = {
+ /* L: len bit field description to be kept as first element */
+ { STM32F4_ADC_SQR1, GENMASK(23, 20), 20 },
+ /* SQ1..SQ16 registers & bit fields (reg, mask, shift) */
+ { STM32F4_ADC_SQR3, GENMASK(4, 0), 0 },
+ { STM32F4_ADC_SQR3, GENMASK(9, 5), 5 },
+ { STM32F4_ADC_SQR3, GENMASK(14, 10), 10 },
+ { STM32F4_ADC_SQR3, GENMASK(19, 15), 15 },
+ { STM32F4_ADC_SQR3, GENMASK(24, 20), 20 },
+ { STM32F4_ADC_SQR3, GENMASK(29, 25), 25 },
+ { STM32F4_ADC_SQR2, GENMASK(4, 0), 0 },
+ { STM32F4_ADC_SQR2, GENMASK(9, 5), 5 },
+ { STM32F4_ADC_SQR2, GENMASK(14, 10), 10 },
+ { STM32F4_ADC_SQR2, GENMASK(19, 15), 15 },
+ { STM32F4_ADC_SQR2, GENMASK(24, 20), 20 },
+ { STM32F4_ADC_SQR2, GENMASK(29, 25), 25 },
+ { STM32F4_ADC_SQR1, GENMASK(4, 0), 0 },
+ { STM32F4_ADC_SQR1, GENMASK(9, 5), 5 },
+ { STM32F4_ADC_SQR1, GENMASK(14, 10), 10 },
+ { STM32F4_ADC_SQR1, GENMASK(19, 15), 15 },
+};
+
+/* STM32F4 external trigger sources for all instances */
+static struct stm32_adc_trig_info stm32f4_adc_trigs[] = {
+ { TIM1_CH1, STM32_EXT0 },
+ { TIM1_CH2, STM32_EXT1 },
+ { TIM1_CH3, STM32_EXT2 },
+ { TIM2_CH2, STM32_EXT3 },
+ { TIM2_CH3, STM32_EXT4 },
+ { TIM2_CH4, STM32_EXT5 },
+ { TIM2_TRGO, STM32_EXT6 },
+ { TIM3_CH1, STM32_EXT7 },
+ { TIM3_TRGO, STM32_EXT8 },
+ { TIM4_CH4, STM32_EXT9 },
+ { TIM5_CH1, STM32_EXT10 },
+ { TIM5_CH2, STM32_EXT11 },
+ { TIM5_CH3, STM32_EXT12 },
+ { TIM8_CH1, STM32_EXT13 },
+ { TIM8_TRGO, STM32_EXT14 },
+ {}, /* sentinel */
+};
+
/**
* STM32 ADC registers access routines
* @adc: stm32 adc instance
/**
* stm32_adc_start_conv() - Start conversions for regular channels.
* @adc: stm32 adc instance
+ * @dma: use dma to transfer conversion result
+ *
+ * Start conversions for regular channels.
+ * Also take care of normal or DMA mode. Circular DMA may be used for regular
+ * conversions, in IIO buffer modes. Otherwise, use ADC interrupt with direct
+ * DR read instead (e.g. read_raw, or triggered buffer mode without DMA).
*/
-static void stm32_adc_start_conv(struct stm32_adc *adc)
+static void stm32_adc_start_conv(struct stm32_adc *adc, bool dma)
{
stm32_adc_set_bits(adc, STM32F4_ADC_CR1, STM32F4_SCAN);
+
+ if (dma)
+ stm32_adc_set_bits(adc, STM32F4_ADC_CR2,
+ STM32F4_DMA | STM32F4_DDS);
+
stm32_adc_set_bits(adc, STM32F4_ADC_CR2, STM32F4_EOCS | STM32F4_ADON);
/* Wait for Power-up time (tSTAB from datasheet) */
stm32_adc_clr_bits(adc, STM32F4_ADC_SR, STM32F4_STRT);
stm32_adc_clr_bits(adc, STM32F4_ADC_CR1, STM32F4_SCAN);
- stm32_adc_clr_bits(adc, STM32F4_ADC_CR2, STM32F4_ADON);
+ stm32_adc_clr_bits(adc, STM32F4_ADC_CR2,
+ STM32F4_ADON | STM32F4_DMA | STM32F4_DDS);
+}
+
+/**
+ * stm32_adc_conf_scan_seq() - Build regular channels scan sequence
+ * @indio_dev: IIO device
+ * @scan_mask: channels to be converted
+ *
+ * Conversion sequence :
+ * Configure ADC scan sequence based on selected channels in scan_mask.
+ * Add channels to SQR registers, from scan_mask LSB to MSB, then
+ * program sequence len.
+ */
+static int stm32_adc_conf_scan_seq(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask)
+{
+ struct stm32_adc *adc = iio_priv(indio_dev);
+ const struct iio_chan_spec *chan;
+ u32 val, bit;
+ int i = 0;
+
+ for_each_set_bit(bit, scan_mask, indio_dev->masklength) {
+ chan = indio_dev->channels + bit;
+ /*
+ * Assign one channel per SQ entry in regular
+ * sequence, starting with SQ1.
+ */
+ i++;
+ if (i > STM32_ADC_MAX_SQ)
+ return -EINVAL;
+
+ dev_dbg(&indio_dev->dev, "%s chan %d to SQ%d\n",
+ __func__, chan->channel, i);
+
+ val = stm32_adc_readl(adc, stm32f4_sq[i].reg);
+ val &= ~stm32f4_sq[i].mask;
+ val |= chan->channel << stm32f4_sq[i].shift;
+ stm32_adc_writel(adc, stm32f4_sq[i].reg, val);
+ }
+
+ if (!i)
+ return -EINVAL;
+
+ /* Sequence len */
+ val = stm32_adc_readl(adc, stm32f4_sq[0].reg);
+ val &= ~stm32f4_sq[0].mask;
+ val |= ((i - 1) << stm32f4_sq[0].shift);
+ stm32_adc_writel(adc, stm32f4_sq[0].reg, val);
+
+ return 0;
+}
+
+/**
+ * stm32_adc_get_trig_extsel() - Get external trigger selection
+ * @trig: trigger
+ *
+ * Returns trigger extsel value, if trig matches, -EINVAL otherwise.
+ */
+static int stm32_adc_get_trig_extsel(struct iio_trigger *trig)
+{
+ int i;
+
+ /* lookup triggers registered by stm32 timer trigger driver */
+ for (i = 0; stm32f4_adc_trigs[i].name; i++) {
+ /**
+ * Checking both stm32 timer trigger type and trig name
+ * should be safe against arbitrary trigger names.
+ */
+ if (is_stm32_timer_trigger(trig) &&
+ !strcmp(stm32f4_adc_trigs[i].name, trig->name)) {
+ return stm32f4_adc_trigs[i].extsel;
+ }
+ }
+
+ return -EINVAL;
}
+/**
+ * stm32_adc_set_trig() - Set a regular trigger
+ * @indio_dev: IIO device
+ * @trig: IIO trigger
+ *
+ * Set trigger source/polarity (e.g. SW, or HW with polarity) :
+ * - if HW trigger disabled (e.g. trig == NULL, conversion launched by sw)
+ * - if HW trigger enabled, set source & polarity
+ */
+static int stm32_adc_set_trig(struct iio_dev *indio_dev,
+ struct iio_trigger *trig)
+{
+ struct stm32_adc *adc = iio_priv(indio_dev);
+ u32 val, extsel = 0, exten = STM32_EXTEN_SWTRIG;
+ unsigned long flags;
+ int ret;
+
+ if (trig) {
+ ret = stm32_adc_get_trig_extsel(trig);
+ if (ret < 0)
+ return ret;
+
+ /* set trigger source and polarity (default to rising edge) */
+ extsel = ret;
+ exten = adc->trigger_polarity + STM32_EXTEN_HWTRIG_RISING_EDGE;
+ }
+
+ spin_lock_irqsave(&adc->lock, flags);
+ val = stm32_adc_readl(adc, STM32F4_ADC_CR2);
+ val &= ~(STM32F4_EXTEN_MASK | STM32F4_EXTSEL_MASK);
+ val |= exten << STM32F4_EXTEN_SHIFT;
+ val |= extsel << STM32F4_EXTSEL_SHIFT;
+ stm32_adc_writel(adc, STM32F4_ADC_CR2, val);
+ spin_unlock_irqrestore(&adc->lock, flags);
+
+ return 0;
+}
+
+static int stm32_adc_set_trig_pol(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ unsigned int type)
+{
+ struct stm32_adc *adc = iio_priv(indio_dev);
+
+ adc->trigger_polarity = type;
+
+ return 0;
+}
+
+static int stm32_adc_get_trig_pol(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan)
+{
+ struct stm32_adc *adc = iio_priv(indio_dev);
+
+ return adc->trigger_polarity;
+}
+
+static const char * const stm32_trig_pol_items[] = {
+ "rising-edge", "falling-edge", "both-edges",
+};
+
+static const struct iio_enum stm32_adc_trig_pol = {
+ .items = stm32_trig_pol_items,
+ .num_items = ARRAY_SIZE(stm32_trig_pol_items),
+ .get = stm32_adc_get_trig_pol,
+ .set = stm32_adc_set_trig_pol,
+};
+
/**
* stm32_adc_single_conv() - Performs a single conversion
* @indio_dev: IIO device
struct stm32_adc *adc = iio_priv(indio_dev);
long timeout;
u32 val;
- u16 result;
int ret;
reinit_completion(&adc->completion);
- adc->buffer = &result;
+ adc->bufi = 0;
- /* Program chan number in regular sequence */
- val = stm32_adc_readl(adc, STM32F4_ADC_SQR3);
- val &= ~STM32F4_SQ1_MASK;
- val |= chan->channel << STM32F4_SQ1_SHIFT;
- stm32_adc_writel(adc, STM32F4_ADC_SQR3, val);
+ /* Program chan number in regular sequence (SQ1) */
+ val = stm32_adc_readl(adc, stm32f4_sq[1].reg);
+ val &= ~stm32f4_sq[1].mask;
+ val |= chan->channel << stm32f4_sq[1].shift;
+ stm32_adc_writel(adc, stm32f4_sq[1].reg, val);
/* Set regular sequence len (0 for 1 conversion) */
- stm32_adc_clr_bits(adc, STM32F4_ADC_SQR1, STM32F4_L_MASK);
+ stm32_adc_clr_bits(adc, stm32f4_sq[0].reg, stm32f4_sq[0].mask);
/* Trigger detection disabled (conversion can be launched in SW) */
stm32_adc_clr_bits(adc, STM32F4_ADC_CR2, STM32F4_EXTEN_MASK);
stm32_adc_conv_irq_enable(adc);
- stm32_adc_start_conv(adc);
+ stm32_adc_start_conv(adc, false);
timeout = wait_for_completion_interruptible_timeout(
&adc->completion, STM32_ADC_TIMEOUT);
} else if (timeout < 0) {
ret = timeout;
} else {
- *res = result;
+ *res = adc->buffer[0];
ret = IIO_VAL_INT;
}
static irqreturn_t stm32_adc_isr(int irq, void *data)
{
struct stm32_adc *adc = data;
+ struct iio_dev *indio_dev = iio_priv_to_dev(adc);
u32 status = stm32_adc_readl(adc, STM32F4_ADC_SR);
if (status & STM32F4_EOC) {
- *adc->buffer = stm32_adc_readw(adc, STM32F4_ADC_DR);
- complete(&adc->completion);
+ /* Reading DR also clears EOC status flag */
+ adc->buffer[adc->bufi] = stm32_adc_readw(adc, STM32F4_ADC_DR);
+ if (iio_buffer_enabled(indio_dev)) {
+ adc->bufi++;
+ if (adc->bufi >= adc->num_conv) {
+ stm32_adc_conv_irq_disable(adc);
+ iio_trigger_poll(indio_dev->trig);
+ }
+ } else {
+ complete(&adc->completion);
+ }
return IRQ_HANDLED;
}
return IRQ_NONE;
}
+/**
+ * stm32_adc_validate_trigger() - validate trigger for stm32 adc
+ * @indio_dev: IIO device
+ * @trig: new trigger
+ *
+ * Returns: 0 if trig matches one of the triggers registered by stm32 adc
+ * driver, -EINVAL otherwise.
+ */
+static int stm32_adc_validate_trigger(struct iio_dev *indio_dev,
+ struct iio_trigger *trig)
+{
+ return stm32_adc_get_trig_extsel(trig) < 0 ? -EINVAL : 0;
+}
+
+static int stm32_adc_set_watermark(struct iio_dev *indio_dev, unsigned int val)
+{
+ struct stm32_adc *adc = iio_priv(indio_dev);
+ unsigned int watermark = STM32_DMA_BUFFER_SIZE / 2;
+
+ /*
+ * dma cyclic transfers are used, buffer is split into two periods.
+ * There should be :
+ * - always one buffer (period) dma is working on
+ * - one buffer (period) driver can push with iio_trigger_poll().
+ */
+ watermark = min(watermark, val * (unsigned)(sizeof(u16)));
+ adc->rx_buf_sz = watermark * 2;
+
+ return 0;
+}
+
+static int stm32_adc_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask)
+{
+ struct stm32_adc *adc = iio_priv(indio_dev);
+ int ret;
+
+ adc->num_conv = bitmap_weight(scan_mask, indio_dev->masklength);
+
+ ret = stm32_adc_conf_scan_seq(indio_dev, scan_mask);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
static int stm32_adc_of_xlate(struct iio_dev *indio_dev,
const struct of_phandle_args *iiospec)
{
static const struct iio_info stm32_adc_iio_info = {
.read_raw = stm32_adc_read_raw,
+ .validate_trigger = stm32_adc_validate_trigger,
+ .hwfifo_set_watermark = stm32_adc_set_watermark,
+ .update_scan_mode = stm32_adc_update_scan_mode,
.debugfs_reg_access = stm32_adc_debugfs_reg_access,
.of_xlate = stm32_adc_of_xlate,
.driver_module = THIS_MODULE,
};
+static unsigned int stm32_adc_dma_residue(struct stm32_adc *adc)
+{
+ struct dma_tx_state state;
+ enum dma_status status;
+
+ status = dmaengine_tx_status(adc->dma_chan,
+ adc->dma_chan->cookie,
+ &state);
+ if (status == DMA_IN_PROGRESS) {
+ /* Residue is size in bytes from end of buffer */
+ unsigned int i = adc->rx_buf_sz - state.residue;
+ unsigned int size;
+
+ /* Return available bytes */
+ if (i >= adc->bufi)
+ size = i - adc->bufi;
+ else
+ size = adc->rx_buf_sz + i - adc->bufi;
+
+ return size;
+ }
+
+ return 0;
+}
+
+static void stm32_adc_dma_buffer_done(void *data)
+{
+ struct iio_dev *indio_dev = data;
+
+ iio_trigger_poll_chained(indio_dev->trig);
+}
+
+static int stm32_adc_dma_start(struct iio_dev *indio_dev)
+{
+ struct stm32_adc *adc = iio_priv(indio_dev);
+ struct dma_async_tx_descriptor *desc;
+ dma_cookie_t cookie;
+ int ret;
+
+ if (!adc->dma_chan)
+ return 0;
+
+ dev_dbg(&indio_dev->dev, "%s size=%d watermark=%d\n", __func__,
+ adc->rx_buf_sz, adc->rx_buf_sz / 2);
+
+ /* Prepare a DMA cyclic transaction */
+ desc = dmaengine_prep_dma_cyclic(adc->dma_chan,
+ adc->rx_dma_buf,
+ adc->rx_buf_sz, adc->rx_buf_sz / 2,
+ DMA_DEV_TO_MEM,
+ DMA_PREP_INTERRUPT);
+ if (!desc)
+ return -EBUSY;
+
+ desc->callback = stm32_adc_dma_buffer_done;
+ desc->callback_param = indio_dev;
+
+ cookie = dmaengine_submit(desc);
+ ret = dma_submit_error(cookie);
+ if (ret) {
+ dmaengine_terminate_all(adc->dma_chan);
+ return ret;
+ }
+
+ /* Issue pending DMA requests */
+ dma_async_issue_pending(adc->dma_chan);
+
+ return 0;
+}
+
+static int stm32_adc_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct stm32_adc *adc = iio_priv(indio_dev);
+ int ret;
+
+ ret = stm32_adc_set_trig(indio_dev, indio_dev->trig);
+ if (ret) {
+ dev_err(&indio_dev->dev, "Can't set trigger\n");
+ return ret;
+ }
+
+ ret = stm32_adc_dma_start(indio_dev);
+ if (ret) {
+ dev_err(&indio_dev->dev, "Can't start dma\n");
+ goto err_clr_trig;
+ }
+
+ ret = iio_triggered_buffer_postenable(indio_dev);
+ if (ret < 0)
+ goto err_stop_dma;
+
+ /* Reset adc buffer index */
+ adc->bufi = 0;
+
+ if (!adc->dma_chan)
+ stm32_adc_conv_irq_enable(adc);
+
+ stm32_adc_start_conv(adc, !!adc->dma_chan);
+
+ return 0;
+
+err_stop_dma:
+ if (adc->dma_chan)
+ dmaengine_terminate_all(adc->dma_chan);
+err_clr_trig:
+ stm32_adc_set_trig(indio_dev, NULL);
+
+ return ret;
+}
+
+static int stm32_adc_buffer_predisable(struct iio_dev *indio_dev)
+{
+ struct stm32_adc *adc = iio_priv(indio_dev);
+ int ret;
+
+ stm32_adc_stop_conv(adc);
+ if (!adc->dma_chan)
+ stm32_adc_conv_irq_disable(adc);
+
+ ret = iio_triggered_buffer_predisable(indio_dev);
+ if (ret < 0)
+ dev_err(&indio_dev->dev, "predisable failed\n");
+
+ if (adc->dma_chan)
+ dmaengine_terminate_all(adc->dma_chan);
+
+ if (stm32_adc_set_trig(indio_dev, NULL))
+ dev_err(&indio_dev->dev, "Can't clear trigger\n");
+
+ return ret;
+}
+
+static const struct iio_buffer_setup_ops stm32_adc_buffer_setup_ops = {
+ .postenable = &stm32_adc_buffer_postenable,
+ .predisable = &stm32_adc_buffer_predisable,
+};
+
+static irqreturn_t stm32_adc_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct stm32_adc *adc = iio_priv(indio_dev);
+
+ dev_dbg(&indio_dev->dev, "%s bufi=%d\n", __func__, adc->bufi);
+
+ if (!adc->dma_chan) {
+ /* reset buffer index */
+ adc->bufi = 0;
+ iio_push_to_buffers_with_timestamp(indio_dev, adc->buffer,
+ pf->timestamp);
+ } else {
+ int residue = stm32_adc_dma_residue(adc);
+
+ while (residue >= indio_dev->scan_bytes) {
+ u16 *buffer = (u16 *)&adc->rx_buf[adc->bufi];
+
+ iio_push_to_buffers_with_timestamp(indio_dev, buffer,
+ pf->timestamp);
+ residue -= indio_dev->scan_bytes;
+ adc->bufi += indio_dev->scan_bytes;
+ if (adc->bufi >= adc->rx_buf_sz)
+ adc->bufi = 0;
+ }
+ }
+
+ iio_trigger_notify_done(indio_dev->trig);
+
+ /* re-enable eoc irq */
+ if (!adc->dma_chan)
+ stm32_adc_conv_irq_enable(adc);
+
+ return IRQ_HANDLED;
+}
+
+static const struct iio_chan_spec_ext_info stm32_adc_ext_info[] = {
+ IIO_ENUM("trigger_polarity", IIO_SHARED_BY_ALL, &stm32_adc_trig_pol),
+ {
+ .name = "trigger_polarity_available",
+ .shared = IIO_SHARED_BY_ALL,
+ .read = iio_enum_available_read,
+ .private = (uintptr_t)&stm32_adc_trig_pol,
+ },
+ {},
+};
+
static void stm32_adc_chan_init_one(struct iio_dev *indio_dev,
struct iio_chan_spec *chan,
const struct stm32_adc_chan_spec *channel,
chan->scan_type.sign = 'u';
chan->scan_type.realbits = 12;
chan->scan_type.storagebits = 16;
+ chan->ext_info = stm32_adc_ext_info;
}
static int stm32_adc_chan_of_init(struct iio_dev *indio_dev)
return 0;
}
+static int stm32_adc_dma_request(struct iio_dev *indio_dev)
+{
+ struct stm32_adc *adc = iio_priv(indio_dev);
+ struct dma_slave_config config;
+ int ret;
+
+ adc->dma_chan = dma_request_slave_channel(&indio_dev->dev, "rx");
+ if (!adc->dma_chan)
+ return 0;
+
+ adc->rx_buf = dma_alloc_coherent(adc->dma_chan->device->dev,
+ STM32_DMA_BUFFER_SIZE,
+ &adc->rx_dma_buf, GFP_KERNEL);
+ if (!adc->rx_buf) {
+ ret = -ENOMEM;
+ goto err_release;
+ }
+
+ /* Configure DMA channel to read data register */
+ memset(&config, 0, sizeof(config));
+ config.src_addr = (dma_addr_t)adc->common->phys_base;
+ config.src_addr += adc->offset + STM32F4_ADC_DR;
+ config.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+
+ ret = dmaengine_slave_config(adc->dma_chan, &config);
+ if (ret)
+ goto err_free;
+
+ return 0;
+
+err_free:
+ dma_free_coherent(adc->dma_chan->device->dev, STM32_DMA_BUFFER_SIZE,
+ adc->rx_buf, adc->rx_dma_buf);
+err_release:
+ dma_release_channel(adc->dma_chan);
+
+ return ret;
+}
+
static int stm32_adc_probe(struct platform_device *pdev)
{
struct iio_dev *indio_dev;
if (ret < 0)
goto err_clk_disable;
+ ret = stm32_adc_dma_request(indio_dev);
+ if (ret < 0)
+ goto err_clk_disable;
+
+ ret = iio_triggered_buffer_setup(indio_dev,
+ &iio_pollfunc_store_time,
+ &stm32_adc_trigger_handler,
+ &stm32_adc_buffer_setup_ops);
+ if (ret) {
+ dev_err(&pdev->dev, "buffer setup failed\n");
+ goto err_dma_disable;
+ }
+
ret = iio_device_register(indio_dev);
if (ret) {
dev_err(&pdev->dev, "iio dev register failed\n");
- goto err_clk_disable;
+ goto err_buffer_cleanup;
}
return 0;
+err_buffer_cleanup:
+ iio_triggered_buffer_cleanup(indio_dev);
+
+err_dma_disable:
+ if (adc->dma_chan) {
+ dma_free_coherent(adc->dma_chan->device->dev,
+ STM32_DMA_BUFFER_SIZE,
+ adc->rx_buf, adc->rx_dma_buf);
+ dma_release_channel(adc->dma_chan);
+ }
err_clk_disable:
clk_disable_unprepare(adc->clk);
struct iio_dev *indio_dev = iio_priv_to_dev(adc);
iio_device_unregister(indio_dev);
+ iio_triggered_buffer_cleanup(indio_dev);
+ if (adc->dma_chan) {
+ dma_free_coherent(adc->dma_chan->device->dev,
+ STM32_DMA_BUFFER_SIZE,
+ adc->rx_buf, adc->rx_dma_buf);
+ dma_release_channel(adc->dma_chan);
+ }
clk_disable_unprepare(adc->clk);
return 0;
unsigned int out_state;
};
-/**
- * struct stx104_dev - STX104 device private data structure
- * @indio_dev: IIO device
- * @chip: instance of the gpio_chip
- */
-struct stx104_dev {
- struct iio_dev *indio_dev;
- struct gpio_chip *chip;
-};
-
static int stx104_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val, int *val2, long mask)
{
spin_unlock_irqrestore(&stx104gpio->lock, flags);
}
+#define STX104_NGPIO 8
+static const char *stx104_names[STX104_NGPIO] = {
+ "DIN0", "DIN1", "DIN2", "DIN3", "DOUT0", "DOUT1", "DOUT2", "DOUT3"
+};
+
+static void stx104_gpio_set_multiple(struct gpio_chip *chip,
+ unsigned long *mask, unsigned long *bits)
+{
+ struct stx104_gpio *const stx104gpio = gpiochip_get_data(chip);
+ unsigned long flags;
+
+ /* verify masked GPIO are output */
+ if (!(*mask & 0xF0))
+ return;
+
+ *mask >>= 4;
+ *bits >>= 4;
+
+ spin_lock_irqsave(&stx104gpio->lock, flags);
+
+ stx104gpio->out_state &= ~*mask;
+ stx104gpio->out_state |= *mask & *bits;
+ outb(stx104gpio->out_state, stx104gpio->base);
+
+ spin_unlock_irqrestore(&stx104gpio->lock, flags);
+}
+
static int stx104_probe(struct device *dev, unsigned int id)
{
struct iio_dev *indio_dev;
struct stx104_iio *priv;
struct stx104_gpio *stx104gpio;
- struct stx104_dev *stx104dev;
int err;
indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
if (!stx104gpio)
return -ENOMEM;
- stx104dev = devm_kzalloc(dev, sizeof(*stx104dev), GFP_KERNEL);
- if (!stx104dev)
- return -ENOMEM;
-
if (!devm_request_region(dev, base[id], STX104_EXTENT,
dev_name(dev))) {
dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
stx104gpio->chip.parent = dev;
stx104gpio->chip.owner = THIS_MODULE;
stx104gpio->chip.base = -1;
- stx104gpio->chip.ngpio = 8;
+ stx104gpio->chip.ngpio = STX104_NGPIO;
+ stx104gpio->chip.names = stx104_names;
stx104gpio->chip.get_direction = stx104_gpio_get_direction;
stx104gpio->chip.direction_input = stx104_gpio_direction_input;
stx104gpio->chip.direction_output = stx104_gpio_direction_output;
stx104gpio->chip.get = stx104_gpio_get;
stx104gpio->chip.set = stx104_gpio_set;
+ stx104gpio->chip.set_multiple = stx104_gpio_set_multiple;
stx104gpio->base = base[id] + 3;
stx104gpio->out_state = 0x0;
spin_lock_init(&stx104gpio->lock);
- stx104dev->indio_dev = indio_dev;
- stx104dev->chip = &stx104gpio->chip;
- dev_set_drvdata(dev, stx104dev);
-
- err = gpiochip_add_data(&stx104gpio->chip, stx104gpio);
+ err = devm_gpiochip_add_data(dev, &stx104gpio->chip, stx104gpio);
if (err) {
dev_err(dev, "GPIO registering failed (%d)\n", err);
return err;
}
- err = iio_device_register(indio_dev);
- if (err) {
- dev_err(dev, "IIO device registering failed (%d)\n", err);
- gpiochip_remove(&stx104gpio->chip);
- return err;
- }
-
- return 0;
-}
-
-static int stx104_remove(struct device *dev, unsigned int id)
-{
- struct stx104_dev *const stx104dev = dev_get_drvdata(dev);
-
- iio_device_unregister(stx104dev->indio_dev);
- gpiochip_remove(stx104dev->chip);
-
- return 0;
+ return devm_iio_device_register(dev, indio_dev);
}
static struct isa_driver stx104_driver = {
.driver = {
.name = "stx104"
},
- .remove = stx104_remove
};
module_isa_driver(stx104_driver, num_stx104);
.attrs = ads1115_attributes,
};
-static struct iio_info ads1015_info = {
+static const struct iio_info ads1015_info = {
.driver_module = THIS_MODULE,
.read_raw = ads1015_read_raw,
.write_raw = ads1015_write_raw,
.attrs = &ads1015_attribute_group,
};
-static struct iio_info ads1115_info = {
+static const struct iio_info ads1115_info = {
.driver_module = THIS_MODULE,
.read_raw = ads1015_read_raw,
.write_raw = ads1015_write_raw,
--- /dev/null
+/*
+ * Texas Instruments ADS7950 SPI ADC driver
+ *
+ * Copyright 2016 David Lechner <david@lechnology.com>
+ *
+ * Based on iio/ad7923.c:
+ * Copyright 2011 Analog Devices Inc
+ * Copyright 2012 CS Systemes d'Information
+ *
+ * And also on hwmon/ads79xx.c
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
+ * Nishanth Menon
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#define TI_ADS7950_CR_MANUAL BIT(12)
+#define TI_ADS7950_CR_WRITE BIT(11)
+#define TI_ADS7950_CR_CHAN(ch) ((ch) << 7)
+#define TI_ADS7950_CR_RANGE_5V BIT(6)
+
+#define TI_ADS7950_MAX_CHAN 16
+
+#define TI_ADS7950_TIMESTAMP_SIZE (sizeof(int64_t) / sizeof(__be16))
+
+/* val = value, dec = left shift, bits = number of bits of the mask */
+#define TI_ADS7950_EXTRACT(val, dec, bits) \
+ (((val) >> (dec)) & ((1 << (bits)) - 1))
+
+struct ti_ads7950_state {
+ struct spi_device *spi;
+ struct spi_transfer ring_xfer[TI_ADS7950_MAX_CHAN + 2];
+ struct spi_transfer scan_single_xfer[3];
+ struct spi_message ring_msg;
+ struct spi_message scan_single_msg;
+
+ struct regulator *reg;
+
+ unsigned int settings;
+
+ /*
+ * DMA (thus cache coherency maintenance) requires the
+ * transfer buffers to live in their own cache lines.
+ */
+ __be16 rx_buf[TI_ADS7950_MAX_CHAN + TI_ADS7950_TIMESTAMP_SIZE]
+ ____cacheline_aligned;
+ __be16 tx_buf[TI_ADS7950_MAX_CHAN];
+};
+
+struct ti_ads7950_chip_info {
+ const struct iio_chan_spec *channels;
+ unsigned int num_channels;
+};
+
+enum ti_ads7950_id {
+ TI_ADS7950,
+ TI_ADS7951,
+ TI_ADS7952,
+ TI_ADS7953,
+ TI_ADS7954,
+ TI_ADS7955,
+ TI_ADS7956,
+ TI_ADS7957,
+ TI_ADS7958,
+ TI_ADS7959,
+ TI_ADS7960,
+ TI_ADS7961,
+};
+
+#define TI_ADS7950_V_CHAN(index, bits) \
+{ \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = index, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .address = index, \
+ .datasheet_name = "CH##index", \
+ .scan_index = index, \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = bits, \
+ .storagebits = 16, \
+ .shift = 12 - (bits), \
+ .endianness = IIO_BE, \
+ }, \
+}
+
+#define DECLARE_TI_ADS7950_4_CHANNELS(name, bits) \
+const struct iio_chan_spec name ## _channels[] = { \
+ TI_ADS7950_V_CHAN(0, bits), \
+ TI_ADS7950_V_CHAN(1, bits), \
+ TI_ADS7950_V_CHAN(2, bits), \
+ TI_ADS7950_V_CHAN(3, bits), \
+ IIO_CHAN_SOFT_TIMESTAMP(4), \
+}
+
+#define DECLARE_TI_ADS7950_8_CHANNELS(name, bits) \
+const struct iio_chan_spec name ## _channels[] = { \
+ TI_ADS7950_V_CHAN(0, bits), \
+ TI_ADS7950_V_CHAN(1, bits), \
+ TI_ADS7950_V_CHAN(2, bits), \
+ TI_ADS7950_V_CHAN(3, bits), \
+ TI_ADS7950_V_CHAN(4, bits), \
+ TI_ADS7950_V_CHAN(5, bits), \
+ TI_ADS7950_V_CHAN(6, bits), \
+ TI_ADS7950_V_CHAN(7, bits), \
+ IIO_CHAN_SOFT_TIMESTAMP(8), \
+}
+
+#define DECLARE_TI_ADS7950_12_CHANNELS(name, bits) \
+const struct iio_chan_spec name ## _channels[] = { \
+ TI_ADS7950_V_CHAN(0, bits), \
+ TI_ADS7950_V_CHAN(1, bits), \
+ TI_ADS7950_V_CHAN(2, bits), \
+ TI_ADS7950_V_CHAN(3, bits), \
+ TI_ADS7950_V_CHAN(4, bits), \
+ TI_ADS7950_V_CHAN(5, bits), \
+ TI_ADS7950_V_CHAN(6, bits), \
+ TI_ADS7950_V_CHAN(7, bits), \
+ TI_ADS7950_V_CHAN(8, bits), \
+ TI_ADS7950_V_CHAN(9, bits), \
+ TI_ADS7950_V_CHAN(10, bits), \
+ TI_ADS7950_V_CHAN(11, bits), \
+ IIO_CHAN_SOFT_TIMESTAMP(12), \
+}
+
+#define DECLARE_TI_ADS7950_16_CHANNELS(name, bits) \
+const struct iio_chan_spec name ## _channels[] = { \
+ TI_ADS7950_V_CHAN(0, bits), \
+ TI_ADS7950_V_CHAN(1, bits), \
+ TI_ADS7950_V_CHAN(2, bits), \
+ TI_ADS7950_V_CHAN(3, bits), \
+ TI_ADS7950_V_CHAN(4, bits), \
+ TI_ADS7950_V_CHAN(5, bits), \
+ TI_ADS7950_V_CHAN(6, bits), \
+ TI_ADS7950_V_CHAN(7, bits), \
+ TI_ADS7950_V_CHAN(8, bits), \
+ TI_ADS7950_V_CHAN(9, bits), \
+ TI_ADS7950_V_CHAN(10, bits), \
+ TI_ADS7950_V_CHAN(11, bits), \
+ TI_ADS7950_V_CHAN(12, bits), \
+ TI_ADS7950_V_CHAN(13, bits), \
+ TI_ADS7950_V_CHAN(14, bits), \
+ TI_ADS7950_V_CHAN(15, bits), \
+ IIO_CHAN_SOFT_TIMESTAMP(16), \
+}
+
+static DECLARE_TI_ADS7950_4_CHANNELS(ti_ads7950, 12);
+static DECLARE_TI_ADS7950_8_CHANNELS(ti_ads7951, 12);
+static DECLARE_TI_ADS7950_12_CHANNELS(ti_ads7952, 12);
+static DECLARE_TI_ADS7950_16_CHANNELS(ti_ads7953, 12);
+static DECLARE_TI_ADS7950_4_CHANNELS(ti_ads7954, 10);
+static DECLARE_TI_ADS7950_8_CHANNELS(ti_ads7955, 10);
+static DECLARE_TI_ADS7950_12_CHANNELS(ti_ads7956, 10);
+static DECLARE_TI_ADS7950_16_CHANNELS(ti_ads7957, 10);
+static DECLARE_TI_ADS7950_4_CHANNELS(ti_ads7958, 8);
+static DECLARE_TI_ADS7950_8_CHANNELS(ti_ads7959, 8);
+static DECLARE_TI_ADS7950_12_CHANNELS(ti_ads7960, 8);
+static DECLARE_TI_ADS7950_16_CHANNELS(ti_ads7961, 8);
+
+static const struct ti_ads7950_chip_info ti_ads7950_chip_info[] = {
+ [TI_ADS7950] = {
+ .channels = ti_ads7950_channels,
+ .num_channels = ARRAY_SIZE(ti_ads7950_channels),
+ },
+ [TI_ADS7951] = {
+ .channels = ti_ads7951_channels,
+ .num_channels = ARRAY_SIZE(ti_ads7951_channels),
+ },
+ [TI_ADS7952] = {
+ .channels = ti_ads7952_channels,
+ .num_channels = ARRAY_SIZE(ti_ads7952_channels),
+ },
+ [TI_ADS7953] = {
+ .channels = ti_ads7953_channels,
+ .num_channels = ARRAY_SIZE(ti_ads7953_channels),
+ },
+ [TI_ADS7954] = {
+ .channels = ti_ads7954_channels,
+ .num_channels = ARRAY_SIZE(ti_ads7954_channels),
+ },
+ [TI_ADS7955] = {
+ .channels = ti_ads7955_channels,
+ .num_channels = ARRAY_SIZE(ti_ads7955_channels),
+ },
+ [TI_ADS7956] = {
+ .channels = ti_ads7956_channels,
+ .num_channels = ARRAY_SIZE(ti_ads7956_channels),
+ },
+ [TI_ADS7957] = {
+ .channels = ti_ads7957_channels,
+ .num_channels = ARRAY_SIZE(ti_ads7957_channels),
+ },
+ [TI_ADS7958] = {
+ .channels = ti_ads7958_channels,
+ .num_channels = ARRAY_SIZE(ti_ads7958_channels),
+ },
+ [TI_ADS7959] = {
+ .channels = ti_ads7959_channels,
+ .num_channels = ARRAY_SIZE(ti_ads7959_channels),
+ },
+ [TI_ADS7960] = {
+ .channels = ti_ads7960_channels,
+ .num_channels = ARRAY_SIZE(ti_ads7960_channels),
+ },
+ [TI_ADS7961] = {
+ .channels = ti_ads7961_channels,
+ .num_channels = ARRAY_SIZE(ti_ads7961_channels),
+ },
+};
+
+/*
+ * ti_ads7950_update_scan_mode() setup the spi transfer buffer for the new
+ * scan mask
+ */
+static int ti_ads7950_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *active_scan_mask)
+{
+ struct ti_ads7950_state *st = iio_priv(indio_dev);
+ int i, cmd, len;
+
+ len = 0;
+ for_each_set_bit(i, active_scan_mask, indio_dev->num_channels) {
+ cmd = TI_ADS7950_CR_WRITE | TI_ADS7950_CR_CHAN(i) | st->settings;
+ st->tx_buf[len++] = cpu_to_be16(cmd);
+ }
+
+ /* Data for the 1st channel is not returned until the 3rd transfer */
+ len += 2;
+ for (i = 0; i < len; i++) {
+ if ((i + 2) < len)
+ st->ring_xfer[i].tx_buf = &st->tx_buf[i];
+ if (i >= 2)
+ st->ring_xfer[i].rx_buf = &st->rx_buf[i - 2];
+ st->ring_xfer[i].len = 2;
+ st->ring_xfer[i].cs_change = 1;
+ }
+ /* make sure last transfer's cs_change is not set */
+ st->ring_xfer[len - 1].cs_change = 0;
+
+ spi_message_init_with_transfers(&st->ring_msg, st->ring_xfer, len);
+
+ return 0;
+}
+
+static irqreturn_t ti_ads7950_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct ti_ads7950_state *st = iio_priv(indio_dev);
+ int ret;
+
+ ret = spi_sync(st->spi, &st->ring_msg);
+ if (ret < 0)
+ goto out;
+
+ iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf,
+ iio_get_time_ns(indio_dev));
+
+out:
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static int ti_ads7950_scan_direct(struct ti_ads7950_state *st, unsigned int ch)
+{
+ int ret, cmd;
+
+ cmd = TI_ADS7950_CR_WRITE | TI_ADS7950_CR_CHAN(ch) | st->settings;
+ st->tx_buf[0] = cpu_to_be16(cmd);
+
+ ret = spi_sync(st->spi, &st->scan_single_msg);
+ if (ret)
+ return ret;
+
+ return be16_to_cpu(st->rx_buf[0]);
+}
+
+static int ti_ads7950_get_range(struct ti_ads7950_state *st)
+{
+ int vref;
+
+ vref = regulator_get_voltage(st->reg);
+ if (vref < 0)
+ return vref;
+
+ vref /= 1000;
+
+ if (st->settings & TI_ADS7950_CR_RANGE_5V)
+ vref *= 2;
+
+ return vref;
+}
+
+static int ti_ads7950_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long m)
+{
+ struct ti_ads7950_state *st = iio_priv(indio_dev);
+ int ret;
+
+ switch (m) {
+ case IIO_CHAN_INFO_RAW:
+
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret < 0)
+ return ret;
+
+ ret = ti_ads7950_scan_direct(st, chan->address);
+ iio_device_release_direct_mode(indio_dev);
+ if (ret < 0)
+ return ret;
+
+ if (chan->address != TI_ADS7950_EXTRACT(ret, 12, 4))
+ return -EIO;
+
+ *val = TI_ADS7950_EXTRACT(ret, chan->scan_type.shift,
+ chan->scan_type.realbits);
+
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ ret = ti_ads7950_get_range(st);
+ if (ret < 0)
+ return ret;
+
+ *val = ret;
+ *val2 = (1 << chan->scan_type.realbits) - 1;
+
+ return IIO_VAL_FRACTIONAL;
+ }
+
+ return -EINVAL;
+}
+
+static const struct iio_info ti_ads7950_info = {
+ .read_raw = &ti_ads7950_read_raw,
+ .update_scan_mode = ti_ads7950_update_scan_mode,
+ .driver_module = THIS_MODULE,
+};
+
+static int ti_ads7950_probe(struct spi_device *spi)
+{
+ struct ti_ads7950_state *st;
+ struct iio_dev *indio_dev;
+ const struct ti_ads7950_chip_info *info;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+
+ spi_set_drvdata(spi, indio_dev);
+
+ st->spi = spi;
+ st->settings = TI_ADS7950_CR_MANUAL | TI_ADS7950_CR_RANGE_5V;
+
+ info = &ti_ads7950_chip_info[spi_get_device_id(spi)->driver_data];
+
+ indio_dev->name = spi_get_device_id(spi)->name;
+ indio_dev->dev.parent = &spi->dev;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = info->channels;
+ indio_dev->num_channels = info->num_channels;
+ indio_dev->info = &ti_ads7950_info;
+
+ /*
+ * Setup default message. The sample is read at the end of the first
+ * transfer, then it takes one full cycle to convert the sample and one
+ * more cycle to send the value. The conversion process is driven by
+ * the SPI clock, which is why we have 3 transfers. The middle one is
+ * just dummy data sent while the chip is converting the sample that
+ * was read at the end of the first transfer.
+ */
+
+ st->scan_single_xfer[0].tx_buf = &st->tx_buf[0];
+ st->scan_single_xfer[0].len = 2;
+ st->scan_single_xfer[0].cs_change = 1;
+ st->scan_single_xfer[1].tx_buf = &st->tx_buf[0];
+ st->scan_single_xfer[1].len = 2;
+ st->scan_single_xfer[1].cs_change = 1;
+ st->scan_single_xfer[2].rx_buf = &st->rx_buf[0];
+ st->scan_single_xfer[2].len = 2;
+
+ spi_message_init_with_transfers(&st->scan_single_msg,
+ st->scan_single_xfer, 3);
+
+ st->reg = devm_regulator_get(&spi->dev, "vref");
+ if (IS_ERR(st->reg)) {
+ dev_err(&spi->dev, "Failed get get regulator \"vref\"\n");
+ return PTR_ERR(st->reg);
+ }
+
+ ret = regulator_enable(st->reg);
+ if (ret) {
+ dev_err(&spi->dev, "Failed to enable regulator \"vref\"\n");
+ return ret;
+ }
+
+ ret = iio_triggered_buffer_setup(indio_dev, NULL,
+ &ti_ads7950_trigger_handler, NULL);
+ if (ret) {
+ dev_err(&spi->dev, "Failed to setup triggered buffer\n");
+ goto error_disable_reg;
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(&spi->dev, "Failed to register iio device\n");
+ goto error_cleanup_ring;
+ }
+
+ return 0;
+
+error_cleanup_ring:
+ iio_triggered_buffer_cleanup(indio_dev);
+error_disable_reg:
+ regulator_disable(st->reg);
+
+ return ret;
+}
+
+static int ti_ads7950_remove(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
+ struct ti_ads7950_state *st = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ iio_triggered_buffer_cleanup(indio_dev);
+ regulator_disable(st->reg);
+
+ return 0;
+}
+
+static const struct spi_device_id ti_ads7950_id[] = {
+ { "ads7950", TI_ADS7950 },
+ { "ads7951", TI_ADS7951 },
+ { "ads7952", TI_ADS7952 },
+ { "ads7953", TI_ADS7953 },
+ { "ads7954", TI_ADS7954 },
+ { "ads7955", TI_ADS7955 },
+ { "ads7956", TI_ADS7956 },
+ { "ads7957", TI_ADS7957 },
+ { "ads7958", TI_ADS7958 },
+ { "ads7959", TI_ADS7959 },
+ { "ads7960", TI_ADS7960 },
+ { "ads7961", TI_ADS7961 },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, ti_ads7950_id);
+
+static struct spi_driver ti_ads7950_driver = {
+ .driver = {
+ .name = "ads7950",
+ },
+ .probe = ti_ads7950_probe,
+ .remove = ti_ads7950_remove,
+ .id_table = ti_ads7950_id,
+};
+module_spi_driver(ti_ads7950_driver);
+
+MODULE_AUTHOR("David Lechner <david@lechnology.com>");
+MODULE_DESCRIPTION("TI TI_ADS7950 ADC");
+MODULE_LICENSE("GPL v2");
--- /dev/null
+/*
+ * TI tlc4541 ADC Driver
+ *
+ * Copyright (C) 2017 Phil Reid
+ *
+ * Datasheets can be found here:
+ * http://www.ti.com/lit/gpn/tlc3541
+ * http://www.ti.com/lit/gpn/tlc4541
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * The tlc4541 requires 24 clock cycles to start a transfer.
+ * Conversion then takes 2.94us to complete before data is ready
+ * Data is returned MSB first.
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/sysfs.h>
+
+struct tlc4541_state {
+ struct spi_device *spi;
+ struct regulator *reg;
+ struct spi_transfer scan_single_xfer[3];
+ struct spi_message scan_single_msg;
+
+ /*
+ * DMA (thus cache coherency maintenance) requires the
+ * transfer buffers to live in their own cache lines.
+ * 2 bytes data + 6 bytes padding + 8 bytes timestamp when
+ * call iio_push_to_buffers_with_timestamp.
+ */
+ __be16 rx_buf[8] ____cacheline_aligned;
+};
+
+struct tlc4541_chip_info {
+ const struct iio_chan_spec *channels;
+ unsigned int num_channels;
+};
+
+enum tlc4541_id {
+ TLC3541,
+ TLC4541,
+};
+
+#define TLC4541_V_CHAN(bits, bitshift) { \
+ .type = IIO_VOLTAGE, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = (bits), \
+ .storagebits = 16, \
+ .shift = (bitshift), \
+ .endianness = IIO_BE, \
+ }, \
+ }
+
+#define DECLARE_TLC4541_CHANNELS(name, bits, bitshift) \
+const struct iio_chan_spec name ## _channels[] = { \
+ TLC4541_V_CHAN(bits, bitshift), \
+ IIO_CHAN_SOFT_TIMESTAMP(1), \
+}
+
+static DECLARE_TLC4541_CHANNELS(tlc3541, 14, 2);
+static DECLARE_TLC4541_CHANNELS(tlc4541, 16, 0);
+
+static const struct tlc4541_chip_info tlc4541_chip_info[] = {
+ [TLC3541] = {
+ .channels = tlc3541_channels,
+ .num_channels = ARRAY_SIZE(tlc3541_channels),
+ },
+ [TLC4541] = {
+ .channels = tlc4541_channels,
+ .num_channels = ARRAY_SIZE(tlc4541_channels),
+ },
+};
+
+static irqreturn_t tlc4541_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct tlc4541_state *st = iio_priv(indio_dev);
+ int ret;
+
+ ret = spi_sync(st->spi, &st->scan_single_msg);
+ if (ret < 0)
+ goto done;
+
+ iio_push_to_buffers_with_timestamp(indio_dev, st->rx_buf,
+ iio_get_time_ns(indio_dev));
+
+done:
+ iio_trigger_notify_done(indio_dev->trig);
+ return IRQ_HANDLED;
+}
+
+static int tlc4541_get_range(struct tlc4541_state *st)
+{
+ int vref;
+
+ vref = regulator_get_voltage(st->reg);
+ if (vref < 0)
+ return vref;
+
+ vref /= 1000;
+
+ return vref;
+}
+
+static int tlc4541_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val,
+ int *val2,
+ long m)
+{
+ int ret = 0;
+ struct tlc4541_state *st = iio_priv(indio_dev);
+
+ switch (m) {
+ case IIO_CHAN_INFO_RAW:
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
+ ret = spi_sync(st->spi, &st->scan_single_msg);
+ iio_device_release_direct_mode(indio_dev);
+ if (ret < 0)
+ return ret;
+ *val = be16_to_cpu(st->rx_buf[0]);
+ *val = *val >> chan->scan_type.shift;
+ *val &= GENMASK(chan->scan_type.realbits - 1, 0);
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ ret = tlc4541_get_range(st);
+ if (ret < 0)
+ return ret;
+ *val = ret;
+ *val2 = chan->scan_type.realbits;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ }
+ return -EINVAL;
+}
+
+static const struct iio_info tlc4541_info = {
+ .read_raw = &tlc4541_read_raw,
+ .driver_module = THIS_MODULE,
+};
+
+static int tlc4541_probe(struct spi_device *spi)
+{
+ struct tlc4541_state *st;
+ struct iio_dev *indio_dev;
+ const struct tlc4541_chip_info *info;
+ int ret;
+ int8_t device_init = 0;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (indio_dev == NULL)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+
+ spi_set_drvdata(spi, indio_dev);
+
+ st->spi = spi;
+
+ info = &tlc4541_chip_info[spi_get_device_id(spi)->driver_data];
+
+ indio_dev->name = spi_get_device_id(spi)->name;
+ indio_dev->dev.parent = &spi->dev;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->channels = info->channels;
+ indio_dev->num_channels = info->num_channels;
+ indio_dev->info = &tlc4541_info;
+
+ /* perform reset */
+ spi_write(spi, &device_init, 1);
+
+ /* Setup default message */
+ st->scan_single_xfer[0].rx_buf = &st->rx_buf[0];
+ st->scan_single_xfer[0].len = 3;
+ st->scan_single_xfer[1].delay_usecs = 3;
+ st->scan_single_xfer[2].rx_buf = &st->rx_buf[0];
+ st->scan_single_xfer[2].len = 2;
+
+ spi_message_init_with_transfers(&st->scan_single_msg,
+ st->scan_single_xfer, 3);
+
+ st->reg = devm_regulator_get(&spi->dev, "vref");
+ if (IS_ERR(st->reg))
+ return PTR_ERR(st->reg);
+
+ ret = regulator_enable(st->reg);
+ if (ret)
+ return ret;
+
+ ret = iio_triggered_buffer_setup(indio_dev, NULL,
+ &tlc4541_trigger_handler, NULL);
+ if (ret)
+ goto error_disable_reg;
+
+ ret = iio_device_register(indio_dev);
+ if (ret)
+ goto error_cleanup_buffer;
+
+ return 0;
+
+error_cleanup_buffer:
+ iio_triggered_buffer_cleanup(indio_dev);
+error_disable_reg:
+ regulator_disable(st->reg);
+
+ return ret;
+}
+
+static int tlc4541_remove(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev = spi_get_drvdata(spi);
+ struct tlc4541_state *st = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ iio_triggered_buffer_cleanup(indio_dev);
+ regulator_disable(st->reg);
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id tlc4541_dt_ids[] = {
+ { .compatible = "ti,tlc3541", },
+ { .compatible = "ti,tlc4541", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, tlc4541_dt_ids);
+#endif
+
+static const struct spi_device_id tlc4541_id[] = {
+ {"tlc3541", TLC3541},
+ {"tlc4541", TLC4541},
+ {}
+};
+MODULE_DEVICE_TABLE(spi, tlc4541_id);
+
+static struct spi_driver tlc4541_driver = {
+ .driver = {
+ .name = "tlc4541",
+ .of_match_table = of_match_ptr(tlc4541_dt_ids),
+ },
+ .probe = tlc4541_probe,
+ .remove = tlc4541_remove,
+ .id_table = tlc4541_id,
+};
+module_spi_driver(tlc4541_driver);
+
+MODULE_AUTHOR("Phil Reid <preid@electromag.com.au>");
+MODULE_DESCRIPTION("Texas Instruments TLC4541 ADC");
+MODULE_LICENSE("GPL v2");
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/export.h>
-#include <linux/iio/buffer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer_impl.h>
#include <linux/iio/consumer.h>
struct iio_cb_buffer {
#include <linux/workqueue.h>
#include <linux/kfifo.h>
#include <linux/mutex.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/buffer_impl.h>
#include <linux/sched.h>
#include <linux/poll.h>
{HID_USAGE_SENSOR_PRESSURE, 0, 100, 0},
{HID_USAGE_SENSOR_PRESSURE, HID_USAGE_SENSOR_UNITS_PASCAL, 0, 1000000},
+
+ {HID_USAGE_SENSOR_TIME_TIMESTAMP, 0, 1000000000, 0},
+ {HID_USAGE_SENSOR_TIME_TIMESTAMP, HID_USAGE_SENSOR_UNITS_MILLISECOND,
+ 1000000, 0},
};
static int pow_10(unsigned power)
}
EXPORT_SYMBOL(hid_sensor_format_scale);
+int64_t hid_sensor_convert_timestamp(struct hid_sensor_common *st,
+ int64_t raw_value)
+{
+ return st->timestamp_ns_scale * raw_value;
+}
+EXPORT_SYMBOL(hid_sensor_convert_timestamp);
+
static
int hid_sensor_get_reporting_interval(struct hid_sensor_hub_device *hsdev,
u32 usage_id,
struct hid_sensor_common *st)
{
+ struct hid_sensor_hub_attribute_info timestamp;
hid_sensor_get_reporting_interval(hsdev, usage_id, st);
HID_USAGE_SENSOR_PROP_SENSITIVITY_ABS,
&st->sensitivity);
- hid_dbg(hsdev->hdev, "common attributes: %x:%x, %x:%x, %x:%x %x:%x\n",
- st->poll.index, st->poll.report_id,
- st->report_state.index, st->report_state.report_id,
- st->power_state.index, st->power_state.report_id,
- st->sensitivity.index, st->sensitivity.report_id);
+ sensor_hub_input_get_attribute_info(hsdev,
+ HID_INPUT_REPORT, usage_id,
+ HID_USAGE_SENSOR_TIME_TIMESTAMP,
+ ×tamp);
+ if (timestamp.index >= 0 && timestamp.report_id) {
+ int val0, val1;
+
+ hid_sensor_format_scale(HID_USAGE_SENSOR_TIME_TIMESTAMP,
+ ×tamp, &val0, &val1);
+ st->timestamp_ns_scale = val0;
+ } else
+ st->timestamp_ns_scale = 1000000000;
+
+ hid_dbg(hsdev->hdev, "common attributes: %x:%x, %x:%x, %x:%x %x:%x %x:%x\n",
+ st->poll.index, st->poll.report_id,
+ st->report_state.index, st->report_state.report_id,
+ st->power_state.index, st->power_state.report_id,
+ st->sensitivity.index, st->sensitivity.report_id,
+ timestamp.index, timestamp.report_id);
return 0;
}
*/
#include <linux/iio/common/ssp_sensors.h>
+#include <linux/iio/buffer.h>
#include <linux/iio/kfifo_buf.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/iio/iio.h>
#include <linux/of_device.h>
+#include <linux/acpi.h>
#include <linux/iio/common/st_sensors_i2c.h>
EXPORT_SYMBOL(st_sensors_of_i2c_probe);
#endif
+#ifdef CONFIG_ACPI
+int st_sensors_match_acpi_device(struct device *dev)
+{
+ const struct acpi_device_id *acpi_id;
+ kernel_ulong_t driver_data = 0;
+
+ if (ACPI_HANDLE(dev)) {
+ acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev);
+ if (!acpi_id) {
+ dev_err(dev, "No driver data\n");
+ return -EINVAL;
+ }
+ driver_data = acpi_id->driver_data;
+ }
+ return driver_data;
+}
+EXPORT_SYMBOL(st_sensors_match_acpi_device);
+#endif
+
MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
MODULE_DESCRIPTION("STMicroelectronics ST-sensors i2c driver");
MODULE_LICENSE("GPL v2");
#include <linux/module.h>
#include <linux/of.h>
#include <linux/spi/spi.h>
+#include <linux/acpi.h>
#define AD5592R_GPIO_READBACK_EN BIT(10)
#define AD5592R_LDAC_READBACK_EN BIT(6)
};
MODULE_DEVICE_TABLE(of, ad5592r_of_match);
+static const struct acpi_device_id ad5592r_acpi_match[] = {
+ {"ADS5592", },
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, ad5592r_acpi_match);
+
static struct spi_driver ad5592r_spi_driver = {
.driver = {
.name = "ad5592r",
.of_match_table = of_match_ptr(ad5592r_of_match),
+ .acpi_match_table = ACPI_PTR(ad5592r_acpi_match),
},
.probe = ad5592r_spi_probe,
.remove = ad5592r_spi_remove,
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/acpi.h>
#define AD5593R_MODE_CONF (0 << 4)
#define AD5593R_MODE_DAC_WRITE (1 << 4)
};
MODULE_DEVICE_TABLE(of, ad5593r_of_match);
+static const struct acpi_device_id ad5593r_acpi_match[] = {
+ {"ADS5593", },
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, ad5593r_acpi_match);
+
static struct i2c_driver ad5593r_driver = {
.driver = {
.name = "ad5593r",
.of_match_table = of_match_ptr(ad5593r_of_match),
+ .acpi_match_table = ACPI_PTR(ad5593r_acpi_match),
},
.probe = ad5593r_i2c_probe,
.remove = ad5593r_i2c_remove,
iio_simple_dummy_events_register(struct iio_dev *indio_dev)
{
return 0;
-};
+}
static inline void
iio_simple_dummy_events_unregister(struct iio_dev *indio_dev)
-{ };
+{}
#endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS*/
static inline int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev)
{
return 0;
-};
+}
static inline
void iio_simple_dummy_unconfigure_buffer(struct iio_dev *indio_dev)
-{};
+{}
#endif /* CONFIG_IIO_SIMPLE_DUMMY_BUFFER */
#endif /* _IIO_SIMPLE_DUMMY_H_ */
#include <linux/iio/iio.h>
#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/buffer.h>
#include <linux/iio/kfifo_buf.h>
#include "iio_simple_dummy.h"
iio_device_attach_buffer(indio_dev, buffer);
- /* Enable timestamps by default */
- buffer->scan_timestamp = true;
-
/*
* Tell the core what device type specific functions should
* be run on either side of buffer capture enable / disable.
#include <linux/iio/common/ssp_sensors.h>
#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
#include <linux/iio/kfifo_buf.h>
#include <linux/module.h>
#include <linux/platform_device.h>
platform_set_drvdata(pdev, indio_dev);
- ret = iio_device_register(indio_dev);
+ ret = devm_iio_device_register(&pdev->dev, indio_dev);
if (ret < 0)
return ret;
return 0;
}
-static int ssp_gyro_remove(struct platform_device *pdev)
-{
- struct iio_dev *indio_dev = platform_get_drvdata(pdev);
-
- iio_device_unregister(indio_dev);
-
- return 0;
-}
-
static struct platform_driver ssp_gyro_driver = {
.driver = {
.name = SSP_GYROSCOPE_NAME,
},
.probe = ssp_gyro_probe,
- .remove = ssp_gyro_remove,
};
module_platform_driver(ssp_gyro_driver);
if (ret)
return ret;
- usleep_range(35000, 50000);
+ msleep(35);
return max30100_read_temp(data, val);
}
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include "hts221.h"
return hts221_probe(iio_dev);
}
+static const struct acpi_device_id hts221_acpi_match[] = {
+ {"SMO9100", 0},
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, hts221_acpi_match);
+
static const struct of_device_id hts221_i2c_of_match[] = {
{ .compatible = "st,hts221", },
{},
.driver = {
.name = "hts221_i2c",
.of_match_table = of_match_ptr(hts221_i2c_of_match),
+ .acpi_match_table = ACPI_PTR(hts221_acpi_match),
},
.probe = hts221_i2c_probe,
.id_table = hts221_i2c_id_table,
be called kmx61.
source "drivers/iio/imu/inv_mpu6050/Kconfig"
+source "drivers/iio/imu/st_lsm6dsx/Kconfig"
endmenu
obj-y += inv_mpu6050/
obj-$(CONFIG_KMX61) += kmx61.o
+
+obj-y += st_lsm6dsx/
__le16 sample;
enum bmi160_sensor_type t = bmi160_to_sensor(chan_type);
- reg = bmi160_regs[t].data + (axis - IIO_MOD_X) * sizeof(__le16);
+ reg = bmi160_regs[t].data + (axis - IIO_MOD_X) * sizeof(sample);
- ret = regmap_bulk_read(data->regmap, reg, &sample, sizeof(__le16));
+ ret = regmap_bulk_read(data->regmap, reg, &sample, sizeof(sample));
if (ret < 0)
return ret;
for_each_set_bit(i, indio_dev->active_scan_mask,
indio_dev->masklength) {
- ret = regmap_bulk_read(data->regmap, base + i * sizeof(__le16),
- &sample, sizeof(__le16));
+ ret = regmap_bulk_read(data->regmap, base + i * sizeof(sample),
+ &sample, sizeof(sample));
if (ret < 0)
goto done;
buf[j++] = sample;
* - 0x68 if SDO is pulled to GND
* - 0x69 if SDO is pulled to VDDIO
*/
-#include <linux/module.h>
+#include <linux/acpi.h>
#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of.h>
#include <linux/regmap.h>
-#include <linux/acpi.h>
#include "bmi160.h"
};
MODULE_DEVICE_TABLE(acpi, bmi160_acpi_match);
+#ifdef CONFIG_OF
+static const struct of_device_id bmi160_of_match[] = {
+ { .compatible = "bosch,bmi160" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, bmi160_of_match);
+#endif
+
static struct i2c_driver bmi160_i2c_driver = {
.driver = {
.name = "bmi160_i2c",
.acpi_match_table = ACPI_PTR(bmi160_acpi_match),
+ .of_match_table = of_match_ptr(bmi160_of_match),
},
.probe = bmi160_i2c_probe,
.remove = bmi160_i2c_remove,
* the GNU General Public License. See the file COPYING in the main
* directory of this archive for more details.
*/
+#include <linux/acpi.h>
#include <linux/module.h>
-#include <linux/spi/spi.h>
+#include <linux/of.h>
#include <linux/regmap.h>
-#include <linux/acpi.h>
+#include <linux/spi/spi.h>
#include "bmi160.h"
};
MODULE_DEVICE_TABLE(acpi, bmi160_acpi_match);
+#ifdef CONFIG_OF
+static const struct of_device_id bmi160_of_match[] = {
+ { .compatible = "bosch,bmi160" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, bmi160_of_match);
+#endif
+
static struct spi_driver bmi160_spi_driver = {
.probe = bmi160_spi_probe,
.remove = bmi160_spi_remove,
.id_table = bmi160_spi_id,
.driver = {
- .acpi_match_table = ACPI_PTR(bmi160_acpi_match),
- .name = "bmi160_spi",
+ .acpi_match_table = ACPI_PTR(bmi160_acpi_match),
+ .of_match_table = of_match_ptr(bmi160_of_match),
+ .name = "bmi160_spi",
},
};
module_spi_driver(bmi160_spi_driver);
--- /dev/null
+
+config IIO_ST_LSM6DSX
+ tristate "ST_LSM6DSx driver for STM 6-axis IMU MEMS sensors"
+ depends on (I2C || SPI)
+ select IIO_BUFFER
+ select IIO_KFIFO_BUF
+ select IIO_ST_LSM6DSX_I2C if (I2C)
+ select IIO_ST_LSM6DSX_SPI if (SPI_MASTER)
+ help
+ Say yes here to build support for STMicroelectronics LSM6DSx imu
+ sensor. Supported devices: lsm6ds3, lsm6dsm
+
+ To compile this driver as a module, choose M here: the module
+ will be called st_lsm6dsx.
+
+config IIO_ST_LSM6DSX_I2C
+ tristate
+ depends on IIO_ST_LSM6DSX
+
+config IIO_ST_LSM6DSX_SPI
+ tristate
+ depends on IIO_ST_LSM6DSX
--- /dev/null
+st_lsm6dsx-y := st_lsm6dsx_core.o st_lsm6dsx_buffer.o
+
+obj-$(CONFIG_IIO_ST_LSM6DSX) += st_lsm6dsx.o
+obj-$(CONFIG_IIO_ST_LSM6DSX_I2C) += st_lsm6dsx_i2c.o
+obj-$(CONFIG_IIO_ST_LSM6DSX_SPI) += st_lsm6dsx_spi.o
--- /dev/null
+/*
+ * STMicroelectronics st_lsm6dsx sensor driver
+ *
+ * Copyright 2016 STMicroelectronics Inc.
+ *
+ * Lorenzo Bianconi <lorenzo.bianconi@st.com>
+ * Denis Ciocca <denis.ciocca@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef ST_LSM6DSX_H
+#define ST_LSM6DSX_H
+
+#include <linux/device.h>
+
+#define ST_LSM6DS3_DEV_NAME "lsm6ds3"
+#define ST_LSM6DSM_DEV_NAME "lsm6dsm"
+
+enum st_lsm6dsx_hw_id {
+ ST_LSM6DS3_ID,
+ ST_LSM6DSM_ID,
+};
+
+#define ST_LSM6DSX_CHAN_SIZE 2
+#define ST_LSM6DSX_SAMPLE_SIZE 6
+#define ST_LSM6DSX_SAMPLE_DEPTH (ST_LSM6DSX_SAMPLE_SIZE / \
+ ST_LSM6DSX_CHAN_SIZE)
+
+#if defined(CONFIG_SPI_MASTER)
+#define ST_LSM6DSX_RX_MAX_LENGTH 256
+#define ST_LSM6DSX_TX_MAX_LENGTH 8
+
+struct st_lsm6dsx_transfer_buffer {
+ u8 rx_buf[ST_LSM6DSX_RX_MAX_LENGTH];
+ u8 tx_buf[ST_LSM6DSX_TX_MAX_LENGTH] ____cacheline_aligned;
+};
+#endif /* CONFIG_SPI_MASTER */
+
+struct st_lsm6dsx_transfer_function {
+ int (*read)(struct device *dev, u8 addr, int len, u8 *data);
+ int (*write)(struct device *dev, u8 addr, int len, u8 *data);
+};
+
+struct st_lsm6dsx_reg {
+ u8 addr;
+ u8 mask;
+};
+
+struct st_lsm6dsx_settings {
+ u8 wai;
+ u16 max_fifo_size;
+ enum st_lsm6dsx_hw_id id;
+};
+
+enum st_lsm6dsx_sensor_id {
+ ST_LSM6DSX_ID_ACC,
+ ST_LSM6DSX_ID_GYRO,
+ ST_LSM6DSX_ID_MAX,
+};
+
+enum st_lsm6dsx_fifo_mode {
+ ST_LSM6DSX_FIFO_BYPASS = 0x0,
+ ST_LSM6DSX_FIFO_CONT = 0x6,
+};
+
+/**
+ * struct st_lsm6dsx_sensor - ST IMU sensor instance
+ * @id: Sensor identifier.
+ * @hw: Pointer to instance of struct st_lsm6dsx_hw.
+ * @gain: Configured sensor sensitivity.
+ * @odr: Output data rate of the sensor [Hz].
+ * @watermark: Sensor watermark level.
+ * @sip: Number of samples in a given pattern.
+ * @decimator: FIFO decimation factor.
+ * @decimator_mask: Sensor mask for decimation register.
+ * @delta_ts: Delta time between two consecutive interrupts.
+ * @ts: Latest timestamp from the interrupt handler.
+ */
+struct st_lsm6dsx_sensor {
+ enum st_lsm6dsx_sensor_id id;
+ struct st_lsm6dsx_hw *hw;
+
+ u32 gain;
+ u16 odr;
+
+ u16 watermark;
+ u8 sip;
+ u8 decimator;
+ u8 decimator_mask;
+
+ s64 delta_ts;
+ s64 ts;
+};
+
+/**
+ * struct st_lsm6dsx_hw - ST IMU MEMS hw instance
+ * @dev: Pointer to instance of struct device (I2C or SPI).
+ * @irq: Device interrupt line (I2C or SPI).
+ * @lock: Mutex to protect read and write operations.
+ * @fifo_lock: Mutex to prevent concurrent access to the hw FIFO.
+ * @fifo_mode: FIFO operating mode supported by the device.
+ * @enable_mask: Enabled sensor bitmask.
+ * @sip: Total number of samples (acc/gyro) in a given pattern.
+ * @iio_devs: Pointers to acc/gyro iio_dev instances.
+ * @settings: Pointer to the specific sensor settings in use.
+ * @tf: Transfer function structure used by I/O operations.
+ * @tb: Transfer buffers used by SPI I/O operations.
+ */
+struct st_lsm6dsx_hw {
+ struct device *dev;
+ int irq;
+
+ struct mutex lock;
+ struct mutex fifo_lock;
+
+ enum st_lsm6dsx_fifo_mode fifo_mode;
+ u8 enable_mask;
+ u8 sip;
+
+ struct iio_dev *iio_devs[ST_LSM6DSX_ID_MAX];
+
+ const struct st_lsm6dsx_settings *settings;
+
+ const struct st_lsm6dsx_transfer_function *tf;
+#if defined(CONFIG_SPI_MASTER)
+ struct st_lsm6dsx_transfer_buffer tb;
+#endif /* CONFIG_SPI_MASTER */
+};
+
+int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,
+ const struct st_lsm6dsx_transfer_function *tf_ops);
+int st_lsm6dsx_sensor_enable(struct st_lsm6dsx_sensor *sensor);
+int st_lsm6dsx_sensor_disable(struct st_lsm6dsx_sensor *sensor);
+int st_lsm6dsx_fifo_setup(struct st_lsm6dsx_hw *hw);
+int st_lsm6dsx_write_with_mask(struct st_lsm6dsx_hw *hw, u8 addr, u8 mask,
+ u8 val);
+int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor,
+ u16 watermark);
+
+#endif /* ST_LSM6DSX_H */
--- /dev/null
+/*
+ * STMicroelectronics st_lsm6dsx FIFO buffer library driver
+ *
+ * LSM6DS3/LSM6DSM: The FIFO buffer can be configured to store data
+ * from gyroscope and accelerometer. Samples are queued without any tag
+ * according to a specific pattern based on 'FIFO data sets' (6 bytes each):
+ * - 1st data set is reserved for gyroscope data
+ * - 2nd data set is reserved for accelerometer data
+ * The FIFO pattern changes depending on the ODRs and decimation factors
+ * assigned to the FIFO data sets. The first sequence of data stored in FIFO
+ * buffer contains the data of all the enabled FIFO data sets
+ * (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.
+ * FIFO supported modes:
+ * - BYPASS: FIFO disabled
+ * - CONTINUOUS: FIFO enabled. When the buffer is full, the FIFO index
+ * restarts from the beginning and the oldest sample is overwritten
+ *
+ * Copyright 2016 STMicroelectronics Inc.
+ *
+ * Lorenzo Bianconi <lorenzo.bianconi@st.com>
+ * Denis Ciocca <denis.ciocca@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+#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>
+
+#include "st_lsm6dsx.h"
+
+#define ST_LSM6DSX_REG_FIFO_THL_ADDR 0x06
+#define ST_LSM6DSX_REG_FIFO_THH_ADDR 0x07
+#define ST_LSM6DSX_FIFO_TH_MASK GENMASK(11, 0)
+#define ST_LSM6DSX_REG_FIFO_DEC_GXL_ADDR 0x08
+#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)
+#define ST_LSM6DSX_REG_FIFO_DIFFL_ADDR 0x3a
+#define ST_LSM6DSX_FIFO_DIFF_MASK GENMASK(11, 0)
+#define ST_LSM6DSX_FIFO_EMPTY_MASK BIT(12)
+#define ST_LSM6DSX_REG_FIFO_OUTL_ADDR 0x3e
+
+#define ST_LSM6DSX_MAX_FIFO_ODR_VAL 0x08
+
+struct st_lsm6dsx_decimator_entry {
+ u8 decimator;
+ u8 val;
+};
+
+static const
+struct st_lsm6dsx_decimator_entry st_lsm6dsx_decimator_table[] = {
+ { 0, 0x0 },
+ { 1, 0x1 },
+ { 2, 0x2 },
+ { 3, 0x3 },
+ { 4, 0x4 },
+ { 8, 0x5 },
+ { 16, 0x6 },
+ { 32, 0x7 },
+};
+
+static int st_lsm6dsx_get_decimator_val(u8 val)
+{
+ const int max_size = ARRAY_SIZE(st_lsm6dsx_decimator_table);
+ int i;
+
+ for (i = 0; i < max_size; i++)
+ if (st_lsm6dsx_decimator_table[i].decimator == val)
+ break;
+
+ return i == max_size ? 0 : st_lsm6dsx_decimator_table[i].val;
+}
+
+static void st_lsm6dsx_get_max_min_odr(struct st_lsm6dsx_hw *hw,
+ u16 *max_odr, u16 *min_odr)
+{
+ struct st_lsm6dsx_sensor *sensor;
+ int i;
+
+ *max_odr = 0, *min_odr = ~0;
+ for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+ sensor = iio_priv(hw->iio_devs[i]);
+
+ if (!(hw->enable_mask & BIT(sensor->id)))
+ continue;
+
+ *max_odr = max_t(u16, *max_odr, sensor->odr);
+ *min_odr = min_t(u16, *min_odr, sensor->odr);
+ }
+}
+
+static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw)
+{
+ struct st_lsm6dsx_sensor *sensor;
+ u16 max_odr, min_odr, sip = 0;
+ int err, i;
+ u8 data;
+
+ st_lsm6dsx_get_max_min_odr(hw, &max_odr, &min_odr);
+
+ for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+ sensor = iio_priv(hw->iio_devs[i]);
+
+ /* update fifo decimators and sample in pattern */
+ if (hw->enable_mask & BIT(sensor->id)) {
+ sensor->sip = sensor->odr / min_odr;
+ sensor->decimator = max_odr / sensor->odr;
+ data = st_lsm6dsx_get_decimator_val(sensor->decimator);
+ } else {
+ sensor->sip = 0;
+ sensor->decimator = 0;
+ data = 0;
+ }
+
+ err = st_lsm6dsx_write_with_mask(hw,
+ ST_LSM6DSX_REG_FIFO_DEC_GXL_ADDR,
+ sensor->decimator_mask, data);
+ if (err < 0)
+ return err;
+
+ sip += sensor->sip;
+ }
+ hw->sip = sip;
+
+ return 0;
+}
+
+static int st_lsm6dsx_set_fifo_mode(struct st_lsm6dsx_hw *hw,
+ enum st_lsm6dsx_fifo_mode fifo_mode)
+{
+ u8 data;
+ int err;
+
+ switch (fifo_mode) {
+ case ST_LSM6DSX_FIFO_BYPASS:
+ data = fifo_mode;
+ break;
+ case ST_LSM6DSX_FIFO_CONT:
+ data = (ST_LSM6DSX_MAX_FIFO_ODR_VAL <<
+ __ffs(ST_LSM6DSX_FIFO_ODR_MASK)) | fifo_mode;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ err = hw->tf->write(hw->dev, ST_LSM6DSX_REG_FIFO_MODE_ADDR,
+ sizeof(data), &data);
+ if (err < 0)
+ return err;
+
+ hw->fifo_mode = fifo_mode;
+
+ return 0;
+}
+
+int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor, u16 watermark)
+{
+ u16 fifo_watermark = ~0, cur_watermark, sip = 0;
+ struct st_lsm6dsx_hw *hw = sensor->hw;
+ struct st_lsm6dsx_sensor *cur_sensor;
+ __le16 wdata;
+ int i, err;
+ u8 data;
+
+ for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+ cur_sensor = iio_priv(hw->iio_devs[i]);
+
+ if (!(hw->enable_mask & BIT(cur_sensor->id)))
+ continue;
+
+ cur_watermark = (cur_sensor == sensor) ? watermark
+ : cur_sensor->watermark;
+
+ fifo_watermark = min_t(u16, fifo_watermark, cur_watermark);
+ sip += cur_sensor->sip;
+ }
+
+ if (!sip)
+ return 0;
+
+ fifo_watermark = max_t(u16, fifo_watermark, sip);
+ fifo_watermark = (fifo_watermark / sip) * sip;
+ fifo_watermark = fifo_watermark * ST_LSM6DSX_SAMPLE_DEPTH;
+
+ mutex_lock(&hw->lock);
+
+ err = hw->tf->read(hw->dev, ST_LSM6DSX_REG_FIFO_THH_ADDR,
+ sizeof(data), &data);
+ if (err < 0)
+ goto out;
+
+ fifo_watermark = ((data & ~ST_LSM6DSX_FIFO_TH_MASK) << 8) |
+ (fifo_watermark & ST_LSM6DSX_FIFO_TH_MASK);
+
+ wdata = cpu_to_le16(fifo_watermark);
+ err = hw->tf->write(hw->dev, ST_LSM6DSX_REG_FIFO_THL_ADDR,
+ sizeof(wdata), (u8 *)&wdata);
+out:
+ mutex_unlock(&hw->lock);
+
+ return err < 0 ? err : 0;
+}
+
+/**
+ * st_lsm6dsx_read_fifo() - LSM6DS3-LSM6DSM read FIFO routine
+ * @hw: Pointer to instance of struct st_lsm6dsx_hw.
+ *
+ * Read samples from the hw FIFO and push them to IIO buffers.
+ *
+ * Return: Number of bytes read from the FIFO
+ */
+static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
+{
+ u16 fifo_len, pattern_len = hw->sip * ST_LSM6DSX_SAMPLE_SIZE;
+ int err, acc_sip, gyro_sip, read_len, samples, offset;
+ struct st_lsm6dsx_sensor *acc_sensor, *gyro_sensor;
+ s64 acc_ts, acc_delta_ts, gyro_ts, gyro_delta_ts;
+ u8 iio_buff[ALIGN(ST_LSM6DSX_SAMPLE_SIZE, sizeof(s64)) + sizeof(s64)];
+ u8 buff[pattern_len];
+ __le16 fifo_status;
+
+ err = hw->tf->read(hw->dev, ST_LSM6DSX_REG_FIFO_DIFFL_ADDR,
+ sizeof(fifo_status), (u8 *)&fifo_status);
+ if (err < 0)
+ return err;
+
+ if (fifo_status & cpu_to_le16(ST_LSM6DSX_FIFO_EMPTY_MASK))
+ return 0;
+
+ fifo_len = (le16_to_cpu(fifo_status) & ST_LSM6DSX_FIFO_DIFF_MASK) *
+ ST_LSM6DSX_CHAN_SIZE;
+ samples = fifo_len / ST_LSM6DSX_SAMPLE_SIZE;
+ fifo_len = (fifo_len / pattern_len) * pattern_len;
+
+ /*
+ * compute delta timestamp between two consecutive samples
+ * in order to estimate queueing time of data generated
+ * by the sensor
+ */
+ acc_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_ACC]);
+ acc_ts = acc_sensor->ts - acc_sensor->delta_ts;
+ acc_delta_ts = div_s64(acc_sensor->delta_ts * acc_sensor->decimator,
+ samples);
+
+ gyro_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_GYRO]);
+ gyro_ts = gyro_sensor->ts - gyro_sensor->delta_ts;
+ gyro_delta_ts = div_s64(gyro_sensor->delta_ts * gyro_sensor->decimator,
+ samples);
+
+ for (read_len = 0; read_len < fifo_len; read_len += pattern_len) {
+ err = hw->tf->read(hw->dev, ST_LSM6DSX_REG_FIFO_OUTL_ADDR,
+ sizeof(buff), buff);
+ if (err < 0)
+ return err;
+
+ /*
+ * Data are written to the FIFO with a specific pattern
+ * depending on the configured ODRs. The first sequence of data
+ * stored in FIFO contains the data of all enabled sensors
+ * (e.g. Gx, Gy, Gz, Ax, Ay, Az), then data are repeated
+ * depending on the value of the decimation factor set for each
+ * sensor.
+ *
+ * Supposing the FIFO is storing data from gyroscope and
+ * accelerometer at different ODRs:
+ * - gyroscope ODR = 208Hz, accelerometer ODR = 104Hz
+ * Since the gyroscope ODR is twice the accelerometer one, the
+ * following pattern is repeated every 9 samples:
+ * - Gx, Gy, Gz, Ax, Ay, Az, Gx, Gy, Gz
+ */
+ gyro_sip = gyro_sensor->sip;
+ acc_sip = acc_sensor->sip;
+ offset = 0;
+
+ while (acc_sip > 0 || gyro_sip > 0) {
+ if (gyro_sip-- > 0) {
+ memcpy(iio_buff, &buff[offset],
+ ST_LSM6DSX_SAMPLE_SIZE);
+ iio_push_to_buffers_with_timestamp(
+ hw->iio_devs[ST_LSM6DSX_ID_GYRO],
+ iio_buff, gyro_ts);
+ offset += ST_LSM6DSX_SAMPLE_SIZE;
+ gyro_ts += gyro_delta_ts;
+ }
+
+ if (acc_sip-- > 0) {
+ memcpy(iio_buff, &buff[offset],
+ ST_LSM6DSX_SAMPLE_SIZE);
+ iio_push_to_buffers_with_timestamp(
+ hw->iio_devs[ST_LSM6DSX_ID_ACC],
+ iio_buff, acc_ts);
+ offset += ST_LSM6DSX_SAMPLE_SIZE;
+ acc_ts += acc_delta_ts;
+ }
+ }
+ }
+
+ return read_len;
+}
+
+static int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw)
+{
+ int err;
+
+ mutex_lock(&hw->fifo_lock);
+
+ st_lsm6dsx_read_fifo(hw);
+ err = st_lsm6dsx_set_fifo_mode(hw, ST_LSM6DSX_FIFO_BYPASS);
+
+ mutex_unlock(&hw->fifo_lock);
+
+ return err;
+}
+
+static int st_lsm6dsx_update_fifo(struct iio_dev *iio_dev, bool enable)
+{
+ struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
+ struct st_lsm6dsx_hw *hw = sensor->hw;
+ int err;
+
+ if (hw->fifo_mode != ST_LSM6DSX_FIFO_BYPASS) {
+ err = st_lsm6dsx_flush_fifo(hw);
+ if (err < 0)
+ return err;
+ }
+
+ if (enable) {
+ err = st_lsm6dsx_sensor_enable(sensor);
+ if (err < 0)
+ return err;
+ } else {
+ err = st_lsm6dsx_sensor_disable(sensor);
+ if (err < 0)
+ return err;
+ }
+
+ err = st_lsm6dsx_update_decimators(hw);
+ if (err < 0)
+ return err;
+
+ err = st_lsm6dsx_update_watermark(sensor, sensor->watermark);
+ if (err < 0)
+ return err;
+
+ if (hw->enable_mask) {
+ err = st_lsm6dsx_set_fifo_mode(hw, ST_LSM6DSX_FIFO_CONT);
+ if (err < 0)
+ return err;
+
+ /*
+ * store enable buffer timestamp as reference to compute
+ * first delta timestamp
+ */
+ sensor->ts = iio_get_time_ns(iio_dev);
+ }
+
+ return 0;
+}
+
+static irqreturn_t st_lsm6dsx_handler_irq(int irq, void *private)
+{
+ struct st_lsm6dsx_hw *hw = (struct st_lsm6dsx_hw *)private;
+ struct st_lsm6dsx_sensor *sensor;
+ int i;
+
+ if (!hw->sip)
+ return IRQ_NONE;
+
+ for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+ sensor = iio_priv(hw->iio_devs[i]);
+
+ if (sensor->sip > 0) {
+ s64 timestamp;
+
+ timestamp = iio_get_time_ns(hw->iio_devs[i]);
+ sensor->delta_ts = timestamp - sensor->ts;
+ sensor->ts = timestamp;
+ }
+ }
+
+ return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t st_lsm6dsx_handler_thread(int irq, void *private)
+{
+ struct st_lsm6dsx_hw *hw = (struct st_lsm6dsx_hw *)private;
+ int count;
+
+ mutex_lock(&hw->fifo_lock);
+ count = st_lsm6dsx_read_fifo(hw);
+ mutex_unlock(&hw->fifo_lock);
+
+ return !count ? IRQ_NONE : IRQ_HANDLED;
+}
+
+static int st_lsm6dsx_buffer_preenable(struct iio_dev *iio_dev)
+{
+ return st_lsm6dsx_update_fifo(iio_dev, true);
+}
+
+static int st_lsm6dsx_buffer_postdisable(struct iio_dev *iio_dev)
+{
+ return st_lsm6dsx_update_fifo(iio_dev, false);
+}
+
+static const struct iio_buffer_setup_ops st_lsm6dsx_buffer_ops = {
+ .preenable = st_lsm6dsx_buffer_preenable,
+ .postdisable = st_lsm6dsx_buffer_postdisable,
+};
+
+int st_lsm6dsx_fifo_setup(struct st_lsm6dsx_hw *hw)
+{
+ struct iio_buffer *buffer;
+ unsigned long irq_type;
+ 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:
+ break;
+ default:
+ dev_info(hw->dev, "mode %lx unsupported\n", irq_type);
+ return -EINVAL;
+ }
+
+ 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;
+ }
+
+ for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+ buffer = devm_iio_kfifo_allocate(hw->dev);
+ if (!buffer)
+ return -ENOMEM;
+
+ iio_device_attach_buffer(hw->iio_devs[i], buffer);
+ hw->iio_devs[i]->modes |= INDIO_BUFFER_SOFTWARE;
+ hw->iio_devs[i]->setup_ops = &st_lsm6dsx_buffer_ops;
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+ * STMicroelectronics st_lsm6dsx sensor driver
+ *
+ * The ST LSM6DSx IMU MEMS series consists of 3D digital accelerometer
+ * and 3D digital gyroscope system-in-package with a digital I2C/SPI serial
+ * interface standard output.
+ * LSM6DSx IMU MEMS series has a dynamic user-selectable full-scale
+ * acceleration range of +-2/+-4/+-8/+-16 g and an angular rate range of
+ * +-125/+-245/+-500/+-1000/+-2000 dps
+ * LSM6DSx series has an integrated First-In-First-Out (FIFO) buffer
+ * allowing dynamic batching of sensor data.
+ *
+ * Supported sensors:
+ * - LSM6DS3:
+ * - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416
+ * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
+ * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
+ * - FIFO size: 8KB
+ *
+ * - LSM6DSM:
+ * - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416
+ * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
+ * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
+ * - FIFO size: 4KB
+ *
+ * Copyright 2016 STMicroelectronics Inc.
+ *
+ * Lorenzo Bianconi <lorenzo.bianconi@st.com>
+ * Denis Ciocca <denis.ciocca@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#include <linux/platform_data/st_sensors_pdata.h>
+
+#include "st_lsm6dsx.h"
+
+#define ST_LSM6DSX_REG_ACC_DEC_MASK GENMASK(2, 0)
+#define ST_LSM6DSX_REG_GYRO_DEC_MASK GENMASK(5, 3)
+#define ST_LSM6DSX_REG_INT1_ADDR 0x0d
+#define ST_LSM6DSX_REG_INT2_ADDR 0x0e
+#define ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK BIT(3)
+#define ST_LSM6DSX_REG_WHOAMI_ADDR 0x0f
+#define ST_LSM6DSX_REG_RESET_ADDR 0x12
+#define ST_LSM6DSX_REG_RESET_MASK BIT(0)
+#define ST_LSM6DSX_REG_BDU_ADDR 0x12
+#define ST_LSM6DSX_REG_BDU_MASK BIT(6)
+#define ST_LSM6DSX_REG_INT2_ON_INT1_ADDR 0x13
+#define ST_LSM6DSX_REG_INT2_ON_INT1_MASK BIT(5)
+#define ST_LSM6DSX_REG_ROUNDING_ADDR 0x16
+#define ST_LSM6DSX_REG_ROUNDING_MASK BIT(2)
+#define ST_LSM6DSX_REG_LIR_ADDR 0x58
+#define ST_LSM6DSX_REG_LIR_MASK BIT(0)
+
+#define ST_LSM6DSX_REG_ACC_ODR_ADDR 0x10
+#define ST_LSM6DSX_REG_ACC_ODR_MASK GENMASK(7, 4)
+#define ST_LSM6DSX_REG_ACC_FS_ADDR 0x10
+#define ST_LSM6DSX_REG_ACC_FS_MASK GENMASK(3, 2)
+#define ST_LSM6DSX_REG_ACC_OUT_X_L_ADDR 0x28
+#define ST_LSM6DSX_REG_ACC_OUT_Y_L_ADDR 0x2a
+#define ST_LSM6DSX_REG_ACC_OUT_Z_L_ADDR 0x2c
+
+#define ST_LSM6DSX_REG_GYRO_ODR_ADDR 0x11
+#define ST_LSM6DSX_REG_GYRO_ODR_MASK GENMASK(7, 4)
+#define ST_LSM6DSX_REG_GYRO_FS_ADDR 0x11
+#define ST_LSM6DSX_REG_GYRO_FS_MASK GENMASK(3, 2)
+#define ST_LSM6DSX_REG_GYRO_OUT_X_L_ADDR 0x22
+#define ST_LSM6DSX_REG_GYRO_OUT_Y_L_ADDR 0x24
+#define ST_LSM6DSX_REG_GYRO_OUT_Z_L_ADDR 0x26
+
+#define ST_LSM6DS3_WHOAMI 0x69
+#define ST_LSM6DSM_WHOAMI 0x6a
+
+#define ST_LSM6DS3_MAX_FIFO_SIZE 8192
+#define ST_LSM6DSM_MAX_FIFO_SIZE 4096
+
+#define ST_LSM6DSX_ACC_FS_2G_GAIN IIO_G_TO_M_S_2(61)
+#define ST_LSM6DSX_ACC_FS_4G_GAIN IIO_G_TO_M_S_2(122)
+#define ST_LSM6DSX_ACC_FS_8G_GAIN IIO_G_TO_M_S_2(244)
+#define ST_LSM6DSX_ACC_FS_16G_GAIN IIO_G_TO_M_S_2(488)
+
+#define ST_LSM6DSX_GYRO_FS_245_GAIN IIO_DEGREE_TO_RAD(8750)
+#define ST_LSM6DSX_GYRO_FS_500_GAIN IIO_DEGREE_TO_RAD(17500)
+#define ST_LSM6DSX_GYRO_FS_1000_GAIN IIO_DEGREE_TO_RAD(35000)
+#define ST_LSM6DSX_GYRO_FS_2000_GAIN IIO_DEGREE_TO_RAD(70000)
+
+struct st_lsm6dsx_odr {
+ u16 hz;
+ u8 val;
+};
+
+#define ST_LSM6DSX_ODR_LIST_SIZE 6
+struct st_lsm6dsx_odr_table_entry {
+ struct st_lsm6dsx_reg reg;
+ struct st_lsm6dsx_odr odr_avl[ST_LSM6DSX_ODR_LIST_SIZE];
+};
+
+static const struct st_lsm6dsx_odr_table_entry st_lsm6dsx_odr_table[] = {
+ [ST_LSM6DSX_ID_ACC] = {
+ .reg = {
+ .addr = ST_LSM6DSX_REG_ACC_ODR_ADDR,
+ .mask = ST_LSM6DSX_REG_ACC_ODR_MASK,
+ },
+ .odr_avl[0] = { 13, 0x01 },
+ .odr_avl[1] = { 26, 0x02 },
+ .odr_avl[2] = { 52, 0x03 },
+ .odr_avl[3] = { 104, 0x04 },
+ .odr_avl[4] = { 208, 0x05 },
+ .odr_avl[5] = { 416, 0x06 },
+ },
+ [ST_LSM6DSX_ID_GYRO] = {
+ .reg = {
+ .addr = ST_LSM6DSX_REG_GYRO_ODR_ADDR,
+ .mask = ST_LSM6DSX_REG_GYRO_ODR_MASK,
+ },
+ .odr_avl[0] = { 13, 0x01 },
+ .odr_avl[1] = { 26, 0x02 },
+ .odr_avl[2] = { 52, 0x03 },
+ .odr_avl[3] = { 104, 0x04 },
+ .odr_avl[4] = { 208, 0x05 },
+ .odr_avl[5] = { 416, 0x06 },
+ }
+};
+
+struct st_lsm6dsx_fs {
+ u32 gain;
+ u8 val;
+};
+
+#define ST_LSM6DSX_FS_LIST_SIZE 4
+struct st_lsm6dsx_fs_table_entry {
+ struct st_lsm6dsx_reg reg;
+ struct st_lsm6dsx_fs fs_avl[ST_LSM6DSX_FS_LIST_SIZE];
+};
+
+static const struct st_lsm6dsx_fs_table_entry st_lsm6dsx_fs_table[] = {
+ [ST_LSM6DSX_ID_ACC] = {
+ .reg = {
+ .addr = ST_LSM6DSX_REG_ACC_FS_ADDR,
+ .mask = ST_LSM6DSX_REG_ACC_FS_MASK,
+ },
+ .fs_avl[0] = { ST_LSM6DSX_ACC_FS_2G_GAIN, 0x0 },
+ .fs_avl[1] = { ST_LSM6DSX_ACC_FS_4G_GAIN, 0x2 },
+ .fs_avl[2] = { ST_LSM6DSX_ACC_FS_8G_GAIN, 0x3 },
+ .fs_avl[3] = { ST_LSM6DSX_ACC_FS_16G_GAIN, 0x1 },
+ },
+ [ST_LSM6DSX_ID_GYRO] = {
+ .reg = {
+ .addr = ST_LSM6DSX_REG_GYRO_FS_ADDR,
+ .mask = ST_LSM6DSX_REG_GYRO_FS_MASK,
+ },
+ .fs_avl[0] = { ST_LSM6DSX_GYRO_FS_245_GAIN, 0x0 },
+ .fs_avl[1] = { ST_LSM6DSX_GYRO_FS_500_GAIN, 0x1 },
+ .fs_avl[2] = { ST_LSM6DSX_GYRO_FS_1000_GAIN, 0x2 },
+ .fs_avl[3] = { ST_LSM6DSX_GYRO_FS_2000_GAIN, 0x3 },
+ }
+};
+
+static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
+ {
+ .wai = ST_LSM6DS3_WHOAMI,
+ .max_fifo_size = ST_LSM6DS3_MAX_FIFO_SIZE,
+ .id = ST_LSM6DS3_ID,
+ },
+ {
+ .wai = ST_LSM6DSM_WHOAMI,
+ .max_fifo_size = ST_LSM6DSM_MAX_FIFO_SIZE,
+ .id = ST_LSM6DSM_ID,
+ },
+};
+
+#define ST_LSM6DSX_CHANNEL(chan_type, addr, mod, scan_idx) \
+{ \
+ .type = chan_type, \
+ .address = addr, \
+ .modified = 1, \
+ .channel2 = mod, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ 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, \
+ }, \
+}
+
+static const struct iio_chan_spec st_lsm6dsx_acc_channels[] = {
+ ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_X_L_ADDR,
+ IIO_MOD_X, 0),
+ ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_Y_L_ADDR,
+ IIO_MOD_Y, 1),
+ ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_Z_L_ADDR,
+ IIO_MOD_Z, 2),
+ IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+static const struct iio_chan_spec st_lsm6dsx_gyro_channels[] = {
+ ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_X_L_ADDR,
+ IIO_MOD_X, 0),
+ ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_Y_L_ADDR,
+ IIO_MOD_Y, 1),
+ ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_Z_L_ADDR,
+ IIO_MOD_Z, 2),
+ IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+int st_lsm6dsx_write_with_mask(struct st_lsm6dsx_hw *hw, u8 addr, u8 mask,
+ u8 val)
+{
+ u8 data;
+ int err;
+
+ mutex_lock(&hw->lock);
+
+ err = hw->tf->read(hw->dev, addr, sizeof(data), &data);
+ if (err < 0) {
+ dev_err(hw->dev, "failed to read %02x register\n", addr);
+ goto out;
+ }
+
+ data = (data & ~mask) | ((val << __ffs(mask)) & mask);
+
+ err = hw->tf->write(hw->dev, addr, sizeof(data), &data);
+ if (err < 0)
+ dev_err(hw->dev, "failed to write %02x register\n", addr);
+
+out:
+ mutex_unlock(&hw->lock);
+
+ return err;
+}
+
+static int st_lsm6dsx_check_whoami(struct st_lsm6dsx_hw *hw, int id)
+{
+ int err, i;
+ u8 data;
+
+ for (i = 0; i < ARRAY_SIZE(st_lsm6dsx_sensor_settings); i++) {
+ if (id == st_lsm6dsx_sensor_settings[i].id)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(st_lsm6dsx_sensor_settings)) {
+ dev_err(hw->dev, "unsupported hw id [%02x]\n", id);
+ return -ENODEV;
+ }
+
+ err = hw->tf->read(hw->dev, ST_LSM6DSX_REG_WHOAMI_ADDR, sizeof(data),
+ &data);
+ if (err < 0) {
+ dev_err(hw->dev, "failed to read whoami register\n");
+ return err;
+ }
+
+ if (data != st_lsm6dsx_sensor_settings[i].wai) {
+ dev_err(hw->dev, "unsupported whoami [%02x]\n", data);
+ return -ENODEV;
+ }
+
+ hw->settings = &st_lsm6dsx_sensor_settings[i];
+
+ return 0;
+}
+
+static int st_lsm6dsx_set_full_scale(struct st_lsm6dsx_sensor *sensor,
+ u32 gain)
+{
+ enum st_lsm6dsx_sensor_id id = sensor->id;
+ int i, err;
+ u8 val;
+
+ for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++)
+ if (st_lsm6dsx_fs_table[id].fs_avl[i].gain == gain)
+ break;
+
+ if (i == ST_LSM6DSX_FS_LIST_SIZE)
+ return -EINVAL;
+
+ val = st_lsm6dsx_fs_table[id].fs_avl[i].val;
+ err = st_lsm6dsx_write_with_mask(sensor->hw,
+ st_lsm6dsx_fs_table[id].reg.addr,
+ st_lsm6dsx_fs_table[id].reg.mask,
+ val);
+ if (err < 0)
+ return err;
+
+ sensor->gain = gain;
+
+ return 0;
+}
+
+static int st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u16 odr)
+{
+ enum st_lsm6dsx_sensor_id id = sensor->id;
+ int i, err;
+ u8 val;
+
+ for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++)
+ if (st_lsm6dsx_odr_table[id].odr_avl[i].hz == odr)
+ break;
+
+ if (i == ST_LSM6DSX_ODR_LIST_SIZE)
+ return -EINVAL;
+
+ val = st_lsm6dsx_odr_table[id].odr_avl[i].val;
+ err = st_lsm6dsx_write_with_mask(sensor->hw,
+ st_lsm6dsx_odr_table[id].reg.addr,
+ st_lsm6dsx_odr_table[id].reg.mask,
+ val);
+ if (err < 0)
+ return err;
+
+ sensor->odr = odr;
+
+ return 0;
+}
+
+int st_lsm6dsx_sensor_enable(struct st_lsm6dsx_sensor *sensor)
+{
+ int err;
+
+ err = st_lsm6dsx_set_odr(sensor, sensor->odr);
+ if (err < 0)
+ return err;
+
+ sensor->hw->enable_mask |= BIT(sensor->id);
+
+ return 0;
+}
+
+int st_lsm6dsx_sensor_disable(struct st_lsm6dsx_sensor *sensor)
+{
+ enum st_lsm6dsx_sensor_id id = sensor->id;
+ int err;
+
+ err = st_lsm6dsx_write_with_mask(sensor->hw,
+ st_lsm6dsx_odr_table[id].reg.addr,
+ st_lsm6dsx_odr_table[id].reg.mask, 0);
+ if (err < 0)
+ return err;
+
+ sensor->hw->enable_mask &= ~BIT(id);
+
+ return 0;
+}
+
+static int st_lsm6dsx_read_oneshot(struct st_lsm6dsx_sensor *sensor,
+ u8 addr, int *val)
+{
+ int err, delay;
+ __le16 data;
+
+ err = st_lsm6dsx_sensor_enable(sensor);
+ if (err < 0)
+ return err;
+
+ delay = 1000000 / sensor->odr;
+ usleep_range(delay, 2 * delay);
+
+ err = sensor->hw->tf->read(sensor->hw->dev, addr, sizeof(data),
+ (u8 *)&data);
+ if (err < 0)
+ return err;
+
+ st_lsm6dsx_sensor_disable(sensor);
+
+ *val = (s16)data;
+
+ return IIO_VAL_INT;
+}
+
+static int st_lsm6dsx_read_raw(struct iio_dev *iio_dev,
+ struct iio_chan_spec const *ch,
+ int *val, int *val2, long mask)
+{
+ struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = iio_device_claim_direct_mode(iio_dev);
+ if (ret)
+ break;
+
+ ret = st_lsm6dsx_read_oneshot(sensor, ch->address, val);
+ iio_device_release_direct_mode(iio_dev);
+ break;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *val = sensor->odr;
+ ret = IIO_VAL_INT;
+ break;
+ case IIO_CHAN_INFO_SCALE:
+ *val = 0;
+ *val2 = sensor->gain;
+ ret = IIO_VAL_INT_PLUS_MICRO;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
+ int err;
+
+ err = iio_device_claim_direct_mode(iio_dev);
+ if (err)
+ return err;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ err = st_lsm6dsx_set_full_scale(sensor, val2);
+ break;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ err = st_lsm6dsx_set_odr(sensor, val);
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+
+ iio_device_release_direct_mode(iio_dev);
+
+ return err;
+}
+
+static int st_lsm6dsx_set_watermark(struct iio_dev *iio_dev, unsigned int val)
+{
+ struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
+ struct st_lsm6dsx_hw *hw = sensor->hw;
+ int err, max_fifo_len;
+
+ max_fifo_len = hw->settings->max_fifo_size / ST_LSM6DSX_SAMPLE_SIZE;
+ if (val < 1 || val > max_fifo_len)
+ return -EINVAL;
+
+ err = st_lsm6dsx_update_watermark(sensor, val);
+ if (err < 0)
+ return err;
+
+ sensor->watermark = val;
+
+ return 0;
+}
+
+static ssize_t
+st_lsm6dsx_sysfs_sampling_frequency_avail(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev));
+ enum st_lsm6dsx_sensor_id id = sensor->id;
+ int i, len = 0;
+
+ for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++)
+ len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
+ st_lsm6dsx_odr_table[id].odr_avl[i].hz);
+ buf[len - 1] = '\n';
+
+ return len;
+}
+
+static ssize_t st_lsm6dsx_sysfs_scale_avail(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev));
+ enum st_lsm6dsx_sensor_id id = sensor->id;
+ int i, len = 0;
+
+ for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++)
+ len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ",
+ st_lsm6dsx_fs_table[id].fs_avl[i].gain);
+ buf[len - 1] = '\n';
+
+ return len;
+}
+
+static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(st_lsm6dsx_sysfs_sampling_frequency_avail);
+static IIO_DEVICE_ATTR(in_accel_scale_available, 0444,
+ st_lsm6dsx_sysfs_scale_avail, NULL, 0);
+static IIO_DEVICE_ATTR(in_anglvel_scale_available, 0444,
+ st_lsm6dsx_sysfs_scale_avail, NULL, 0);
+
+static struct attribute *st_lsm6dsx_acc_attributes[] = {
+ &iio_dev_attr_sampling_frequency_available.dev_attr.attr,
+ &iio_dev_attr_in_accel_scale_available.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group st_lsm6dsx_acc_attribute_group = {
+ .attrs = st_lsm6dsx_acc_attributes,
+};
+
+static const struct iio_info st_lsm6dsx_acc_info = {
+ .driver_module = THIS_MODULE,
+ .attrs = &st_lsm6dsx_acc_attribute_group,
+ .read_raw = st_lsm6dsx_read_raw,
+ .write_raw = st_lsm6dsx_write_raw,
+ .hwfifo_set_watermark = st_lsm6dsx_set_watermark,
+};
+
+static struct attribute *st_lsm6dsx_gyro_attributes[] = {
+ &iio_dev_attr_sampling_frequency_available.dev_attr.attr,
+ &iio_dev_attr_in_anglvel_scale_available.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group st_lsm6dsx_gyro_attribute_group = {
+ .attrs = st_lsm6dsx_gyro_attributes,
+};
+
+static const struct iio_info st_lsm6dsx_gyro_info = {
+ .driver_module = THIS_MODULE,
+ .attrs = &st_lsm6dsx_gyro_attribute_group,
+ .read_raw = st_lsm6dsx_read_raw,
+ .write_raw = st_lsm6dsx_write_raw,
+ .hwfifo_set_watermark = st_lsm6dsx_set_watermark,
+};
+
+static const unsigned long st_lsm6dsx_available_scan_masks[] = {0x7, 0x0};
+
+static int st_lsm6dsx_of_get_drdy_pin(struct st_lsm6dsx_hw *hw, int *drdy_pin)
+{
+ struct device_node *np = hw->dev->of_node;
+ int err;
+
+ if (!np)
+ return -EINVAL;
+
+ err = of_property_read_u32(np, "st,drdy-int-pin", drdy_pin);
+ if (err == -ENODATA) {
+ /* if the property has not been specified use default value */
+ *drdy_pin = 1;
+ err = 0;
+ }
+
+ return err;
+}
+
+static int st_lsm6dsx_get_drdy_reg(struct st_lsm6dsx_hw *hw, u8 *drdy_reg)
+{
+ int err = 0, drdy_pin;
+
+ if (st_lsm6dsx_of_get_drdy_pin(hw, &drdy_pin) < 0) {
+ struct st_sensors_platform_data *pdata;
+ struct device *dev = hw->dev;
+
+ pdata = (struct st_sensors_platform_data *)dev->platform_data;
+ drdy_pin = pdata ? pdata->drdy_int_pin : 1;
+ }
+
+ switch (drdy_pin) {
+ case 1:
+ *drdy_reg = ST_LSM6DSX_REG_INT1_ADDR;
+ break;
+ case 2:
+ *drdy_reg = ST_LSM6DSX_REG_INT2_ADDR;
+ break;
+ default:
+ dev_err(hw->dev, "unsupported data ready pin\n");
+ err = -EINVAL;
+ break;
+ }
+
+ return err;
+}
+
+static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw)
+{
+ u8 data, drdy_int_reg;
+ int err;
+
+ data = ST_LSM6DSX_REG_RESET_MASK;
+ err = hw->tf->write(hw->dev, ST_LSM6DSX_REG_RESET_ADDR, sizeof(data),
+ &data);
+ if (err < 0)
+ return err;
+
+ msleep(200);
+
+ /* latch interrupts */
+ err = st_lsm6dsx_write_with_mask(hw, ST_LSM6DSX_REG_LIR_ADDR,
+ ST_LSM6DSX_REG_LIR_MASK, 1);
+ if (err < 0)
+ return err;
+
+ /* enable Block Data Update */
+ err = st_lsm6dsx_write_with_mask(hw, ST_LSM6DSX_REG_BDU_ADDR,
+ ST_LSM6DSX_REG_BDU_MASK, 1);
+ if (err < 0)
+ return err;
+
+ err = st_lsm6dsx_write_with_mask(hw, ST_LSM6DSX_REG_ROUNDING_ADDR,
+ ST_LSM6DSX_REG_ROUNDING_MASK, 1);
+ if (err < 0)
+ return err;
+
+ /* enable FIFO watermak interrupt */
+ err = st_lsm6dsx_get_drdy_reg(hw, &drdy_int_reg);
+ if (err < 0)
+ return err;
+
+ return st_lsm6dsx_write_with_mask(hw, drdy_int_reg,
+ ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK, 1);
+}
+
+static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw,
+ enum st_lsm6dsx_sensor_id id)
+{
+ struct st_lsm6dsx_sensor *sensor;
+ struct iio_dev *iio_dev;
+
+ iio_dev = devm_iio_device_alloc(hw->dev, sizeof(*sensor));
+ if (!iio_dev)
+ return NULL;
+
+ iio_dev->modes = INDIO_DIRECT_MODE;
+ iio_dev->dev.parent = hw->dev;
+ iio_dev->available_scan_masks = st_lsm6dsx_available_scan_masks;
+
+ sensor = iio_priv(iio_dev);
+ sensor->id = id;
+ sensor->hw = hw;
+ sensor->odr = st_lsm6dsx_odr_table[id].odr_avl[0].hz;
+ sensor->gain = st_lsm6dsx_fs_table[id].fs_avl[0].gain;
+ sensor->watermark = 1;
+
+ switch (id) {
+ case ST_LSM6DSX_ID_ACC:
+ iio_dev->channels = st_lsm6dsx_acc_channels;
+ iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_acc_channels);
+ iio_dev->name = "lsm6dsx_accel";
+ iio_dev->info = &st_lsm6dsx_acc_info;
+
+ sensor->decimator_mask = ST_LSM6DSX_REG_ACC_DEC_MASK;
+ break;
+ case ST_LSM6DSX_ID_GYRO:
+ iio_dev->channels = st_lsm6dsx_gyro_channels;
+ iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_gyro_channels);
+ iio_dev->name = "lsm6dsx_gyro";
+ iio_dev->info = &st_lsm6dsx_gyro_info;
+
+ sensor->decimator_mask = ST_LSM6DSX_REG_GYRO_DEC_MASK;
+ break;
+ default:
+ return NULL;
+ }
+
+ return iio_dev;
+}
+
+int st_lsm6dsx_probe(struct device *dev, int irq, int hw_id,
+ const struct st_lsm6dsx_transfer_function *tf_ops)
+{
+ struct st_lsm6dsx_hw *hw;
+ int i, err;
+
+ hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
+ if (!hw)
+ return -ENOMEM;
+
+ dev_set_drvdata(dev, (void *)hw);
+
+ mutex_init(&hw->lock);
+ mutex_init(&hw->fifo_lock);
+
+ hw->dev = dev;
+ hw->irq = irq;
+ hw->tf = tf_ops;
+
+ err = st_lsm6dsx_check_whoami(hw, hw_id);
+ if (err < 0)
+ return err;
+
+ for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+ hw->iio_devs[i] = st_lsm6dsx_alloc_iiodev(hw, i);
+ if (!hw->iio_devs[i])
+ return -ENOMEM;
+ }
+
+ err = st_lsm6dsx_init_device(hw);
+ if (err < 0)
+ return err;
+
+ if (hw->irq > 0) {
+ err = st_lsm6dsx_fifo_setup(hw);
+ if (err < 0)
+ return err;
+ }
+
+ for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+ err = devm_iio_device_register(hw->dev, hw->iio_devs[i]);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(st_lsm6dsx_probe);
+
+MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>");
+MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx driver");
+MODULE_LICENSE("GPL v2");
--- /dev/null
+/*
+ * STMicroelectronics st_lsm6dsx i2c driver
+ *
+ * Copyright 2016 STMicroelectronics Inc.
+ *
+ * Lorenzo Bianconi <lorenzo.bianconi@st.com>
+ * Denis Ciocca <denis.ciocca@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+
+#include "st_lsm6dsx.h"
+
+static int st_lsm6dsx_i2c_read(struct device *dev, u8 addr, int len, u8 *data)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct i2c_msg msg[2];
+
+ msg[0].addr = client->addr;
+ msg[0].flags = client->flags;
+ msg[0].len = 1;
+ msg[0].buf = &addr;
+
+ msg[1].addr = client->addr;
+ msg[1].flags = client->flags | I2C_M_RD;
+ msg[1].len = len;
+ msg[1].buf = data;
+
+ return i2c_transfer(client->adapter, msg, 2);
+}
+
+static int st_lsm6dsx_i2c_write(struct device *dev, u8 addr, int len, u8 *data)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct i2c_msg msg;
+ u8 send[len + 1];
+
+ send[0] = addr;
+ memcpy(&send[1], data, len * sizeof(u8));
+
+ msg.addr = client->addr;
+ msg.flags = client->flags;
+ msg.len = len + 1;
+ msg.buf = send;
+
+ return i2c_transfer(client->adapter, &msg, 1);
+}
+
+static const struct st_lsm6dsx_transfer_function st_lsm6dsx_transfer_fn = {
+ .read = st_lsm6dsx_i2c_read,
+ .write = st_lsm6dsx_i2c_write,
+};
+
+static int st_lsm6dsx_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ return st_lsm6dsx_probe(&client->dev, client->irq,
+ (int)id->driver_data,
+ &st_lsm6dsx_transfer_fn);
+}
+
+static const struct of_device_id st_lsm6dsx_i2c_of_match[] = {
+ {
+ .compatible = "st,lsm6ds3",
+ .data = (void *)ST_LSM6DS3_ID,
+ },
+ {
+ .compatible = "st,lsm6dsm",
+ .data = (void *)ST_LSM6DSM_ID,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match);
+
+static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = {
+ { ST_LSM6DS3_DEV_NAME, ST_LSM6DS3_ID },
+ { ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID },
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table);
+
+static struct i2c_driver st_lsm6dsx_driver = {
+ .driver = {
+ .name = "st_lsm6dsx_i2c",
+ .of_match_table = of_match_ptr(st_lsm6dsx_i2c_of_match),
+ },
+ .probe = st_lsm6dsx_i2c_probe,
+ .id_table = st_lsm6dsx_i2c_id_table,
+};
+module_i2c_driver(st_lsm6dsx_driver);
+
+MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>");
+MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx i2c driver");
+MODULE_LICENSE("GPL v2");
--- /dev/null
+/*
+ * STMicroelectronics st_lsm6dsx spi driver
+ *
+ * Copyright 2016 STMicroelectronics Inc.
+ *
+ * Lorenzo Bianconi <lorenzo.bianconi@st.com>
+ * Denis Ciocca <denis.ciocca@st.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+
+#include "st_lsm6dsx.h"
+
+#define SENSORS_SPI_READ BIT(7)
+
+static int st_lsm6dsx_spi_read(struct device *dev, u8 addr, int len,
+ u8 *data)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ struct st_lsm6dsx_hw *hw = spi_get_drvdata(spi);
+ int err;
+
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = hw->tb.tx_buf,
+ .bits_per_word = 8,
+ .len = 1,
+ },
+ {
+ .rx_buf = hw->tb.rx_buf,
+ .bits_per_word = 8,
+ .len = len,
+ }
+ };
+
+ hw->tb.tx_buf[0] = addr | SENSORS_SPI_READ;
+
+ err = spi_sync_transfer(spi, xfers, ARRAY_SIZE(xfers));
+ if (err < 0)
+ return err;
+
+ memcpy(data, hw->tb.rx_buf, len * sizeof(u8));
+
+ return len;
+}
+
+static int st_lsm6dsx_spi_write(struct device *dev, u8 addr, int len,
+ u8 *data)
+{
+ struct st_lsm6dsx_hw *hw;
+ struct spi_device *spi;
+
+ if (len >= ST_LSM6DSX_TX_MAX_LENGTH)
+ return -ENOMEM;
+
+ spi = to_spi_device(dev);
+ hw = spi_get_drvdata(spi);
+
+ hw->tb.tx_buf[0] = addr;
+ memcpy(&hw->tb.tx_buf[1], data, len);
+
+ return spi_write(spi, hw->tb.tx_buf, len + 1);
+}
+
+static const struct st_lsm6dsx_transfer_function st_lsm6dsx_transfer_fn = {
+ .read = st_lsm6dsx_spi_read,
+ .write = st_lsm6dsx_spi_write,
+};
+
+static int st_lsm6dsx_spi_probe(struct spi_device *spi)
+{
+ const struct spi_device_id *id = spi_get_device_id(spi);
+
+ return st_lsm6dsx_probe(&spi->dev, spi->irq,
+ (int)id->driver_data,
+ &st_lsm6dsx_transfer_fn);
+}
+
+static const struct of_device_id st_lsm6dsx_spi_of_match[] = {
+ {
+ .compatible = "st,lsm6ds3",
+ .data = (void *)ST_LSM6DS3_ID,
+ },
+ {
+ .compatible = "st,lsm6dsm",
+ .data = (void *)ST_LSM6DSM_ID,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match);
+
+static const struct spi_device_id st_lsm6dsx_spi_id_table[] = {
+ { ST_LSM6DS3_DEV_NAME, ST_LSM6DS3_ID },
+ { ST_LSM6DSM_DEV_NAME, ST_LSM6DSM_ID },
+ {},
+};
+MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table);
+
+static struct spi_driver st_lsm6dsx_driver = {
+ .driver = {
+ .name = "st_lsm6dsx_spi",
+ .of_match_table = of_match_ptr(st_lsm6dsx_spi_of_match),
+ },
+ .probe = st_lsm6dsx_spi_probe,
+ .id_table = st_lsm6dsx_spi_id_table,
+};
+module_spi_driver(st_lsm6dsx_driver);
+
+MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi@st.com>");
+MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx spi driver");
+MODULE_LICENSE("GPL v2");
#include "iio_core.h"
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
+#include <linux/iio/buffer_impl.h>
static const char * const iio_endian_prefix[] = {
[IIO_BE] = "be",
}
EXPORT_SYMBOL(iio_buffer_init);
+/**
+ * iio_buffer_set_attrs - Set buffer specific attributes
+ * @buffer: The buffer for which we are setting attributes
+ * @attrs: Pointer to a null terminated list of pointers to attributes
+ */
+void iio_buffer_set_attrs(struct iio_buffer *buffer,
+ const struct attribute **attrs)
+{
+ buffer->attrs = attrs;
+}
+EXPORT_SYMBOL_GPL(iio_buffer_set_attrs);
+
static ssize_t iio_show_scan_index(struct device *dev,
struct device_attribute *attr,
char *buf)
return 0;
}
+static int iio_scan_mask_query(struct iio_dev *indio_dev,
+ struct iio_buffer *buffer, int bit)
+{
+ if (bit > indio_dev->masklength)
+ return -EINVAL;
+
+ if (!buffer->scan_mask)
+ return 0;
+
+ /* Ensure return value is 0 or 1. */
+ return !!test_bit(bit, buffer->scan_mask);
+};
+
static ssize_t iio_scan_el_store(struct device *dev,
struct device_attribute *attr,
const char *buf,
return 0;
}
+/**
+ * struct iio_demux_table - table describing demux memcpy ops
+ * @from: index to copy from
+ * @to: index to copy to
+ * @length: how many bytes to copy
+ * @l: list head used for management
+ */
+struct iio_demux_table {
+ unsigned from;
+ unsigned to;
+ unsigned length;
+ struct list_head l;
+};
+
+static void iio_buffer_demux_free(struct iio_buffer *buffer)
+{
+ struct iio_demux_table *p, *q;
+ list_for_each_entry_safe(p, q, &buffer->demux_list, l) {
+ list_del(&p->l);
+ kfree(p);
+ }
+}
+
+static int iio_buffer_add_demux(struct iio_buffer *buffer,
+ struct iio_demux_table **p, unsigned int in_loc, unsigned int out_loc,
+ unsigned int length)
+{
+
+ if (*p && (*p)->from + (*p)->length == in_loc &&
+ (*p)->to + (*p)->length == out_loc) {
+ (*p)->length += length;
+ } else {
+ *p = kmalloc(sizeof(**p), GFP_KERNEL);
+ if (*p == NULL)
+ return -ENOMEM;
+ (*p)->from = in_loc;
+ (*p)->to = out_loc;
+ (*p)->length = length;
+ list_add_tail(&(*p)->l, &buffer->demux_list);
+ }
+
+ return 0;
+}
+
+static int iio_buffer_update_demux(struct iio_dev *indio_dev,
+ struct iio_buffer *buffer)
+{
+ int ret, in_ind = -1, out_ind, length;
+ unsigned in_loc = 0, out_loc = 0;
+ struct iio_demux_table *p = NULL;
+
+ /* Clear out any old demux */
+ iio_buffer_demux_free(buffer);
+ kfree(buffer->demux_bounce);
+ buffer->demux_bounce = NULL;
+
+ /* First work out which scan mode we will actually have */
+ if (bitmap_equal(indio_dev->active_scan_mask,
+ buffer->scan_mask,
+ indio_dev->masklength))
+ return 0;
+
+ /* Now we have the two masks, work from least sig and build up sizes */
+ for_each_set_bit(out_ind,
+ buffer->scan_mask,
+ indio_dev->masklength) {
+ in_ind = find_next_bit(indio_dev->active_scan_mask,
+ indio_dev->masklength,
+ in_ind + 1);
+ while (in_ind != out_ind) {
+ in_ind = find_next_bit(indio_dev->active_scan_mask,
+ indio_dev->masklength,
+ in_ind + 1);
+ length = iio_storage_bytes_for_si(indio_dev, in_ind);
+ /* Make sure we are aligned */
+ in_loc = roundup(in_loc, length) + length;
+ }
+ length = iio_storage_bytes_for_si(indio_dev, in_ind);
+ out_loc = roundup(out_loc, length);
+ in_loc = roundup(in_loc, length);
+ ret = iio_buffer_add_demux(buffer, &p, in_loc, out_loc, length);
+ if (ret)
+ goto error_clear_mux_table;
+ out_loc += length;
+ in_loc += length;
+ }
+ /* Relies on scan_timestamp being last */
+ if (buffer->scan_timestamp) {
+ length = iio_storage_bytes_for_timestamp(indio_dev);
+ out_loc = roundup(out_loc, length);
+ in_loc = roundup(in_loc, length);
+ ret = iio_buffer_add_demux(buffer, &p, in_loc, out_loc, length);
+ if (ret)
+ goto error_clear_mux_table;
+ out_loc += length;
+ in_loc += length;
+ }
+ buffer->demux_bounce = kzalloc(out_loc, GFP_KERNEL);
+ if (buffer->demux_bounce == NULL) {
+ ret = -ENOMEM;
+ goto error_clear_mux_table;
+ }
+ return 0;
+
+error_clear_mux_table:
+ iio_buffer_demux_free(buffer);
+
+ return ret;
+}
+
+static int iio_update_demux(struct iio_dev *indio_dev)
+{
+ struct iio_buffer *buffer;
+ int ret;
+
+ list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list) {
+ ret = iio_buffer_update_demux(indio_dev, buffer);
+ if (ret < 0)
+ goto error_clear_mux_table;
+ }
+ return 0;
+
+error_clear_mux_table:
+ list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list)
+ iio_buffer_demux_free(buffer);
+
+ return ret;
+}
+
static int iio_enable_buffers(struct iio_dev *indio_dev,
struct iio_device_config *config)
{
}
EXPORT_SYMBOL_GPL(iio_validate_scan_mask_onehot);
-int iio_scan_mask_query(struct iio_dev *indio_dev,
- struct iio_buffer *buffer, int bit)
-{
- if (bit > indio_dev->masklength)
- return -EINVAL;
-
- if (!buffer->scan_mask)
- return 0;
-
- /* Ensure return value is 0 or 1. */
- return !!test_bit(bit, buffer->scan_mask);
-};
-EXPORT_SYMBOL_GPL(iio_scan_mask_query);
-
-/**
- * struct iio_demux_table - table describing demux memcpy ops
- * @from: index to copy from
- * @to: index to copy to
- * @length: how many bytes to copy
- * @l: list head used for management
- */
-struct iio_demux_table {
- unsigned from;
- unsigned to;
- unsigned length;
- struct list_head l;
-};
-
static const void *iio_demux(struct iio_buffer *buffer,
const void *datain)
{
return 0;
}
-static void iio_buffer_demux_free(struct iio_buffer *buffer)
-{
- struct iio_demux_table *p, *q;
- list_for_each_entry_safe(p, q, &buffer->demux_list, l) {
- list_del(&p->l);
- kfree(p);
- }
-}
-
-
+/**
+ * iio_push_to_buffers() - push to a registered buffer.
+ * @indio_dev: iio_dev structure for device.
+ * @data: Full scan.
+ */
int iio_push_to_buffers(struct iio_dev *indio_dev, const void *data)
{
int ret;
}
EXPORT_SYMBOL_GPL(iio_push_to_buffers);
-static int iio_buffer_add_demux(struct iio_buffer *buffer,
- struct iio_demux_table **p, unsigned int in_loc, unsigned int out_loc,
- unsigned int length)
-{
-
- if (*p && (*p)->from + (*p)->length == in_loc &&
- (*p)->to + (*p)->length == out_loc) {
- (*p)->length += length;
- } else {
- *p = kmalloc(sizeof(**p), GFP_KERNEL);
- if (*p == NULL)
- return -ENOMEM;
- (*p)->from = in_loc;
- (*p)->to = out_loc;
- (*p)->length = length;
- list_add_tail(&(*p)->l, &buffer->demux_list);
- }
-
- return 0;
-}
-
-static int iio_buffer_update_demux(struct iio_dev *indio_dev,
- struct iio_buffer *buffer)
-{
- int ret, in_ind = -1, out_ind, length;
- unsigned in_loc = 0, out_loc = 0;
- struct iio_demux_table *p = NULL;
-
- /* Clear out any old demux */
- iio_buffer_demux_free(buffer);
- kfree(buffer->demux_bounce);
- buffer->demux_bounce = NULL;
-
- /* First work out which scan mode we will actually have */
- if (bitmap_equal(indio_dev->active_scan_mask,
- buffer->scan_mask,
- indio_dev->masklength))
- return 0;
-
- /* Now we have the two masks, work from least sig and build up sizes */
- for_each_set_bit(out_ind,
- buffer->scan_mask,
- indio_dev->masklength) {
- in_ind = find_next_bit(indio_dev->active_scan_mask,
- indio_dev->masklength,
- in_ind + 1);
- while (in_ind != out_ind) {
- in_ind = find_next_bit(indio_dev->active_scan_mask,
- indio_dev->masklength,
- in_ind + 1);
- length = iio_storage_bytes_for_si(indio_dev, in_ind);
- /* Make sure we are aligned */
- in_loc = roundup(in_loc, length) + length;
- }
- length = iio_storage_bytes_for_si(indio_dev, in_ind);
- out_loc = roundup(out_loc, length);
- in_loc = roundup(in_loc, length);
- ret = iio_buffer_add_demux(buffer, &p, in_loc, out_loc, length);
- if (ret)
- goto error_clear_mux_table;
- out_loc += length;
- in_loc += length;
- }
- /* Relies on scan_timestamp being last */
- if (buffer->scan_timestamp) {
- length = iio_storage_bytes_for_timestamp(indio_dev);
- out_loc = roundup(out_loc, length);
- in_loc = roundup(in_loc, length);
- ret = iio_buffer_add_demux(buffer, &p, in_loc, out_loc, length);
- if (ret)
- goto error_clear_mux_table;
- out_loc += length;
- in_loc += length;
- }
- buffer->demux_bounce = kzalloc(out_loc, GFP_KERNEL);
- if (buffer->demux_bounce == NULL) {
- ret = -ENOMEM;
- goto error_clear_mux_table;
- }
- return 0;
-
-error_clear_mux_table:
- iio_buffer_demux_free(buffer);
-
- return ret;
-}
-
-int iio_update_demux(struct iio_dev *indio_dev)
-{
- struct iio_buffer *buffer;
- int ret;
-
- list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list) {
- ret = iio_buffer_update_demux(indio_dev, buffer);
- if (ret < 0)
- goto error_clear_mux_table;
- }
- return 0;
-
-error_clear_mux_table:
- list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list)
- iio_buffer_demux_free(buffer);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(iio_update_demux);
-
/**
* iio_buffer_release() - Free a buffer's resources
* @ref: Pointer to the kref embedded in the iio_buffer struct
kref_put(&buffer->ref, iio_buffer_release);
}
EXPORT_SYMBOL_GPL(iio_buffer_put);
+
+/**
+ * iio_device_attach_buffer - Attach a buffer to a IIO device
+ * @indio_dev: The device the buffer should be attached to
+ * @buffer: The buffer to attach to the device
+ *
+ * This function attaches a buffer to a IIO device. The buffer stays attached to
+ * the device until the device is freed. The function should only be called at
+ * most once per device.
+ */
+void iio_device_attach_buffer(struct iio_dev *indio_dev,
+ struct iio_buffer *buffer)
+{
+ indio_dev->buffer = iio_buffer_get(buffer);
+}
+EXPORT_SYMBOL_GPL(iio_device_attach_buffer);
#include <linux/iio/sysfs.h>
#include <linux/iio/events.h>
#include <linux/iio/buffer.h>
+#include <linux/iio/buffer_impl.h>
/* IDA to assign each registered device a unique id */
static DEFINE_IDA(iio_ida);
[IIO_ELECTRICALCONDUCTIVITY] = "electricalconductivity",
[IIO_COUNT] = "count",
[IIO_INDEX] = "index",
+ [IIO_GRAVITY] = "gravity",
};
static const char * const iio_modifier_names[] = {
return NULL;
}
-static struct iio_trigger *iio_trigger_find_by_name(const char *name,
- size_t len)
+static struct iio_trigger *iio_trigger_acquire_by_name(const char *name)
{
struct iio_trigger *trig = NULL, *iter;
list_for_each_entry(iter, &iio_trigger_list, list)
if (sysfs_streq(iter->name, name)) {
trig = iter;
+ iio_trigger_get(trig);
break;
}
mutex_unlock(&iio_trigger_list_lock);
}
mutex_unlock(&indio_dev->mlock);
- trig = iio_trigger_find_by_name(buf, len);
- if (oldtrig == trig)
- return len;
+ trig = iio_trigger_acquire_by_name(buf);
+ if (oldtrig == trig) {
+ ret = len;
+ goto out_trigger_put;
+ }
if (trig && indio_dev->info->validate_trigger) {
ret = indio_dev->info->validate_trigger(indio_dev, trig);
if (ret)
- return ret;
+ goto out_trigger_put;
}
if (trig && trig->ops->validate_device) {
ret = trig->ops->validate_device(trig, indio_dev);
if (ret)
- return ret;
+ goto out_trigger_put;
}
indio_dev->trig = trig;
iio_trigger_put(oldtrig);
}
if (indio_dev->trig) {
- iio_trigger_get(indio_dev->trig);
if (indio_dev->modes & INDIO_EVENT_TRIGGERED)
iio_trigger_attach_poll_func(indio_dev->trig,
indio_dev->pollfunc_event);
}
return len;
+
+out_trigger_put:
+ iio_trigger_put(trig);
+ return ret;
}
static DEVICE_ATTR(current_trigger, S_IRUGO | S_IWUSR,
kfree(trig);
}
-static struct device_type iio_trig_type = {
+static const struct device_type iio_trig_type = {
.release = iio_trig_release,
.groups = iio_trig_dev_groups,
};
static struct iio_trigger *viio_trigger_alloc(const char *fmt, va_list vargs)
{
struct iio_trigger *trig;
+ int i;
+
trig = kzalloc(sizeof *trig, GFP_KERNEL);
- if (trig) {
- int i;
- trig->dev.type = &iio_trig_type;
- trig->dev.bus = &iio_bus_type;
- device_initialize(&trig->dev);
-
- mutex_init(&trig->pool_lock);
- trig->subirq_base
- = irq_alloc_descs(-1, 0,
- CONFIG_IIO_CONSUMERS_PER_TRIGGER,
- 0);
- if (trig->subirq_base < 0) {
- kfree(trig);
- return NULL;
- }
+ if (!trig)
+ return NULL;
- trig->name = kvasprintf(GFP_KERNEL, fmt, vargs);
- if (trig->name == NULL) {
- irq_free_descs(trig->subirq_base,
- CONFIG_IIO_CONSUMERS_PER_TRIGGER);
- kfree(trig);
- return NULL;
- }
- trig->subirq_chip.name = trig->name;
- trig->subirq_chip.irq_mask = &iio_trig_subirqmask;
- trig->subirq_chip.irq_unmask = &iio_trig_subirqunmask;
- for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++) {
- irq_set_chip(trig->subirq_base + i,
- &trig->subirq_chip);
- irq_set_handler(trig->subirq_base + i,
- &handle_simple_irq);
- irq_modify_status(trig->subirq_base + i,
- IRQ_NOREQUEST | IRQ_NOAUTOEN,
- IRQ_NOPROBE);
- }
- get_device(&trig->dev);
+ trig->dev.type = &iio_trig_type;
+ trig->dev.bus = &iio_bus_type;
+ device_initialize(&trig->dev);
+
+ mutex_init(&trig->pool_lock);
+ trig->subirq_base = irq_alloc_descs(-1, 0,
+ CONFIG_IIO_CONSUMERS_PER_TRIGGER,
+ 0);
+ if (trig->subirq_base < 0)
+ goto free_trig;
+
+ trig->name = kvasprintf(GFP_KERNEL, fmt, vargs);
+ if (trig->name == NULL)
+ goto free_descs;
+
+ trig->subirq_chip.name = trig->name;
+ trig->subirq_chip.irq_mask = &iio_trig_subirqmask;
+ trig->subirq_chip.irq_unmask = &iio_trig_subirqunmask;
+ for (i = 0; i < CONFIG_IIO_CONSUMERS_PER_TRIGGER; i++) {
+ irq_set_chip(trig->subirq_base + i, &trig->subirq_chip);
+ irq_set_handler(trig->subirq_base + i, &handle_simple_irq);
+ irq_modify_status(trig->subirq_base + i,
+ IRQ_NOREQUEST | IRQ_NOAUTOEN, IRQ_NOPROBE);
}
+ get_device(&trig->dev);
return trig;
+
+free_descs:
+ irq_free_descs(trig->subirq_base, CONFIG_IIO_CONSUMERS_PER_TRIGGER);
+free_trig:
+ kfree(trig);
+ return NULL;
}
struct iio_trigger *iio_trigger_alloc(const char *fmt, ...)
scale_type = iio_channel_read(chan, &scale_val, &scale_val2,
IIO_CHAN_INFO_SCALE);
- if (scale_type < 0)
- return scale_type;
+ if (scale_type < 0) {
+ /*
+ * Just pass raw values as processed if no scaling is
+ * available.
+ */
+ *processed = raw;
+ return 0;
+ }
switch (scale_type) {
case IIO_VAL_INT:
To compile this driver as a module, choose M here: the module will
be called cm3323.
+config CM3605
+ tristate "Capella CM3605 ambient light and proximity sensor"
+ depends on OF
+ help
+ Say Y here if you want to build a driver for Capella CM3605
+ ambient light and short range proximity sensor.
+
+ To compile this driver as a module, choose M here: the module will
+ be called cm3605.
+
config CM36651
depends on I2C
tristate "CM36651 driver"
obj-$(CONFIG_CM32181) += cm32181.o
obj-$(CONFIG_CM3232) += cm3232.o
obj-$(CONFIG_CM3323) += cm3323.o
+obj-$(CONFIG_CM3605) += cm3605.o
obj-$(CONFIG_CM36651) += cm36651.o
obj-$(CONFIG_GP2AP020A00F) += gp2ap020a00f.o
obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o
if (ret < 0)
dev_err(&chip->client->dev, "Error writing reg_cmd\n");
- return 0;
+ return ret;
}
/**
--- /dev/null
+/*
+ * CM3605 Ambient Light and Proximity Sensor
+ *
+ * Copyright (C) 2016 Linaro Ltd.
+ * Author: Linus Walleij <linus.walleij@linaro.org>
+ *
+ * This hardware was found in the very first Nexus One handset from Google/HTC
+ * and an early endavour into mobile light and proximity sensors.
+ */
+
+#include <linux/module.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/iio/consumer.h> /* To get our ADC channel */
+#include <linux/iio/types.h> /* To deal with our ADC channel */
+#include <linux/init.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/math64.h>
+#include <linux/pm.h>
+
+#define CM3605_PROX_CHANNEL 0
+#define CM3605_ALS_CHANNEL 1
+#define CM3605_AOUT_TYP_MAX_MV 1550
+/* It should not go above 1.650V according to the data sheet */
+#define CM3605_AOUT_MAX_MV 1650
+
+/**
+ * struct cm3605 - CM3605 state
+ * @dev: pointer to parent device
+ * @vdd: regulator controlling VDD
+ * @aset: sleep enable GPIO, high = sleep
+ * @aout: IIO ADC channel to convert the AOUT signal
+ * @als_max: maximum LUX detection (depends on RSET)
+ * @dir: proximity direction: start as FALLING
+ * @led: trigger for the infrared LED used by the proximity sensor
+ */
+struct cm3605 {
+ struct device *dev;
+ struct regulator *vdd;
+ struct gpio_desc *aset;
+ struct iio_channel *aout;
+ s32 als_max;
+ enum iio_event_direction dir;
+ struct led_trigger *led;
+};
+
+static irqreturn_t cm3605_prox_irq(int irq, void *d)
+{
+ struct iio_dev *indio_dev = d;
+ struct cm3605 *cm3605 = iio_priv(indio_dev);
+ u64 ev;
+
+ ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, CM3605_PROX_CHANNEL,
+ IIO_EV_TYPE_THRESH, cm3605->dir);
+ iio_push_event(indio_dev, ev, iio_get_time_ns(indio_dev));
+
+ /* Invert the edge for each event */
+ if (cm3605->dir == IIO_EV_DIR_RISING)
+ cm3605->dir = IIO_EV_DIR_FALLING;
+ else
+ cm3605->dir = IIO_EV_DIR_RISING;
+
+ return IRQ_HANDLED;
+}
+
+static int cm3605_get_lux(struct cm3605 *cm3605)
+{
+ int ret, res;
+ s64 lux;
+
+ ret = iio_read_channel_processed(cm3605->aout, &res);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(cm3605->dev, "read %d mV from ADC\n", res);
+
+ /*
+ * AOUT has an offset of ~30mV then linear at dark
+ * then goes from 2.54 up to 650 LUX yielding 1.55V
+ * (1550 mV) so scale the returned value to this interval
+ * using simple linear interpolation.
+ */
+ if (res < 30)
+ return 0;
+ if (res > CM3605_AOUT_MAX_MV)
+ dev_err(cm3605->dev, "device out of range\n");
+
+ /* Remove bias */
+ lux = res - 30;
+
+ /* Linear interpolation between 0 and ALS typ max */
+ lux *= cm3605->als_max;
+ lux = div64_s64(lux, CM3605_AOUT_TYP_MAX_MV);
+
+ return lux;
+}
+
+static int cm3605_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct cm3605 *cm3605 = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ switch (chan->type) {
+ case IIO_LIGHT:
+ ret = cm3605_get_lux(cm3605);
+ if (ret < 0)
+ return ret;
+ *val = ret;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info cm3605_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = cm3605_read_raw,
+};
+
+static const struct iio_event_spec cm3605_events[] = {
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_EITHER,
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE),
+ },
+};
+
+static const struct iio_chan_spec cm3605_channels[] = {
+ {
+ .type = IIO_PROXIMITY,
+ .event_spec = cm3605_events,
+ .num_event_specs = ARRAY_SIZE(cm3605_events),
+ },
+ {
+ .type = IIO_LIGHT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .channel = CM3605_ALS_CHANNEL,
+ },
+};
+
+static int cm3605_probe(struct platform_device *pdev)
+{
+ struct cm3605 *cm3605;
+ struct iio_dev *indio_dev;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ enum iio_chan_type ch_type;
+ u32 rset;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*cm3605));
+ if (!indio_dev)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, indio_dev);
+
+ cm3605 = iio_priv(indio_dev);
+ cm3605->dev = dev;
+ cm3605->dir = IIO_EV_DIR_FALLING;
+
+ ret = of_property_read_u32(np, "capella,aset-resistance-ohms", &rset);
+ if (ret) {
+ dev_info(dev, "no RSET specified, assuming 100K\n");
+ rset = 100000;
+ }
+ switch (rset) {
+ case 50000:
+ cm3605->als_max = 650;
+ break;
+ case 100000:
+ cm3605->als_max = 300;
+ break;
+ case 300000:
+ cm3605->als_max = 100;
+ break;
+ case 600000:
+ cm3605->als_max = 50;
+ break;
+ default:
+ dev_info(dev, "non-standard resistance\n");
+ return -EINVAL;
+ }
+
+ cm3605->aout = devm_iio_channel_get(dev, "aout");
+ if (IS_ERR(cm3605->aout)) {
+ if (PTR_ERR(cm3605->aout) == -ENODEV) {
+ dev_err(dev, "no ADC, deferring...\n");
+ return -EPROBE_DEFER;
+ }
+ dev_err(dev, "failed to get AOUT ADC channel\n");
+ return PTR_ERR(cm3605->aout);
+ }
+ ret = iio_get_channel_type(cm3605->aout, &ch_type);
+ if (ret < 0)
+ return ret;
+ if (ch_type != IIO_VOLTAGE) {
+ dev_err(dev, "wrong type of IIO channel specified for AOUT\n");
+ return -EINVAL;
+ }
+
+ cm3605->vdd = devm_regulator_get(dev, "vdd");
+ if (IS_ERR(cm3605->vdd)) {
+ dev_err(dev, "failed to get VDD regulator\n");
+ return PTR_ERR(cm3605->vdd);
+ }
+ ret = regulator_enable(cm3605->vdd);
+ if (ret) {
+ dev_err(dev, "failed to enable VDD regulator\n");
+ return ret;
+ }
+
+ cm3605->aset = devm_gpiod_get(dev, "aset", GPIOD_OUT_HIGH);
+ if (IS_ERR(cm3605->aset)) {
+ dev_err(dev, "no ASET GPIO\n");
+ ret = PTR_ERR(cm3605->aset);
+ goto out_disable_vdd;
+ }
+
+ ret = devm_request_threaded_irq(dev, platform_get_irq(pdev, 0),
+ cm3605_prox_irq, NULL, 0, "cm3605", indio_dev);
+ if (ret) {
+ dev_err(dev, "unable to request IRQ\n");
+ goto out_disable_aset;
+ }
+
+ /* Just name the trigger the same as the driver */
+ led_trigger_register_simple("cm3605", &cm3605->led);
+ led_trigger_event(cm3605->led, LED_FULL);
+
+ indio_dev->dev.parent = dev;
+ indio_dev->info = &cm3605_info;
+ indio_dev->name = "cm3605";
+ indio_dev->channels = cm3605_channels;
+ indio_dev->num_channels = ARRAY_SIZE(cm3605_channels);
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = iio_device_register(indio_dev);
+ if (ret)
+ goto out_remove_trigger;
+ dev_info(dev, "Capella Microsystems CM3605 enabled range 0..%d LUX\n",
+ cm3605->als_max);
+
+ return 0;
+
+out_remove_trigger:
+ led_trigger_event(cm3605->led, LED_OFF);
+ led_trigger_unregister_simple(cm3605->led);
+out_disable_aset:
+ gpiod_set_value_cansleep(cm3605->aset, 0);
+out_disable_vdd:
+ regulator_disable(cm3605->vdd);
+ return ret;
+}
+
+static int cm3605_remove(struct platform_device *pdev)
+{
+ struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+ struct cm3605 *cm3605 = iio_priv(indio_dev);
+
+ led_trigger_event(cm3605->led, LED_OFF);
+ led_trigger_unregister_simple(cm3605->led);
+ gpiod_set_value_cansleep(cm3605->aset, 0);
+ iio_device_unregister(indio_dev);
+ regulator_disable(cm3605->vdd);
+
+ return 0;
+}
+
+static int __maybe_unused cm3605_pm_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct cm3605 *cm3605 = iio_priv(indio_dev);
+
+ led_trigger_event(cm3605->led, LED_OFF);
+ regulator_disable(cm3605->vdd);
+
+ return 0;
+}
+
+static int __maybe_unused cm3605_pm_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct cm3605 *cm3605 = iio_priv(indio_dev);
+ int ret;
+
+ ret = regulator_enable(cm3605->vdd);
+ if (ret)
+ dev_err(dev, "failed to enable regulator in resume path\n");
+ led_trigger_event(cm3605->led, LED_FULL);
+
+ return 0;
+}
+
+static const struct dev_pm_ops cm3605_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(cm3605_pm_suspend,
+ cm3605_pm_resume)
+};
+
+static const struct of_device_id cm3605_of_match[] = {
+ {.compatible = "capella,cm3605"},
+ { },
+};
+MODULE_DEVICE_TABLE(of, cm3605_of_match);
+
+static struct platform_driver cm3605_driver = {
+ .driver = {
+ .name = "cm3605",
+ .of_match_table = cm3605_of_match,
+ .pm = &cm3605_dev_pm_ops,
+ },
+ .probe = cm3605_probe,
+ .remove = cm3605_remove,
+};
+module_platform_driver(cm3605_driver);
+
+MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
+MODULE_DESCRIPTION("CM3605 ambient light and proximity sensor driver");
+MODULE_LICENSE("GPL");
#include <linux/iio/triggered_buffer.h>
#include "../common/hid-sensors/hid-sensor-trigger.h"
-#define CHANNEL_SCAN_INDEX_ILLUM 0
+enum {
+ CHANNEL_SCAN_INDEX_INTENSITY = 0,
+ CHANNEL_SCAN_INDEX_ILLUM = 1,
+ CHANNEL_SCAN_INDEX_MAX
+};
struct als_state {
struct hid_sensor_hub_callbacks callbacks;
struct hid_sensor_common common_attributes;
struct hid_sensor_hub_attribute_info als_illum;
- u32 illum;
+ u32 illum[CHANNEL_SCAN_INDEX_MAX];
int scale_pre_decml;
int scale_post_decml;
int scale_precision;
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_SAMP_FREQ) |
BIT(IIO_CHAN_INFO_HYSTERESIS),
+ .scan_index = CHANNEL_SCAN_INDEX_INTENSITY,
+ },
+ {
+ .type = IIO_LIGHT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_HYSTERESIS),
.scan_index = CHANNEL_SCAN_INDEX_ILLUM,
}
};
switch (mask) {
case 0:
switch (chan->scan_index) {
+ case CHANNEL_SCAN_INDEX_INTENSITY:
case CHANNEL_SCAN_INDEX_ILLUM:
report_id = als_state->als_illum.report_id;
address =
struct iio_dev *indio_dev = platform_get_drvdata(priv);
struct als_state *als_state = iio_priv(indio_dev);
int ret = -EINVAL;
+ u32 sample_data = *(u32 *)raw_data;
switch (usage_id) {
case HID_USAGE_SENSOR_LIGHT_ILLUM:
- als_state->illum = *(u32 *)raw_data;
+ als_state->illum[CHANNEL_SCAN_INDEX_INTENSITY] = sample_data;
+ als_state->illum[CHANNEL_SCAN_INDEX_ILLUM] = sample_data;
ret = 0;
break;
default:
&st->als_illum);
if (ret < 0)
return ret;
+ als_adjust_channel_bit_mask(channels, CHANNEL_SCAN_INDEX_INTENSITY,
+ st->als_illum.size);
als_adjust_channel_bit_mask(channels, CHANNEL_SCAN_INDEX_ILLUM,
st->als_illum.size);
{ .compatible = "ti,opt3001" },
{ }
};
+MODULE_DEVICE_TABLE(of, opt3001_of_match);
static struct i2c_driver opt3001_driver = {
.probe = opt3001_probe,
if (val & AK8974_STATUS_DRDY)
return 0;
} while (--timeout);
- if (!timeout) {
- dev_err(&ak8974->i2c->dev,
- "timeout waiting for DRDY\n");
- return -ETIMEDOUT;
- }
- return 0;
+ dev_err(&ak8974->i2c->dev, "timeout waiting for DRDY\n");
+ return -ETIMEDOUT;
}
static int ak8974_getresult(struct ak8974 *ak8974, __le16 *result)
int val, int val2, long mask)
{
struct mag3110_data *data = iio_priv(indio_dev);
- int rate;
+ int rate, ret;
- if (iio_buffer_enabled(indio_dev))
- return -EBUSY;
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
switch (mask) {
case IIO_CHAN_INFO_SAMP_FREQ:
rate = mag3110_get_samp_freq_index(data, val, val2);
- if (rate < 0)
- return -EINVAL;
+ if (rate < 0) {
+ ret = -EINVAL;
+ break;
+ }
data->ctrl_reg1 &= ~MAG3110_CTRL_DR_MASK;
data->ctrl_reg1 |= rate << MAG3110_CTRL_DR_SHIFT;
- return i2c_smbus_write_byte_data(data->client,
+ ret = i2c_smbus_write_byte_data(data->client,
MAG3110_CTRL_REG1, data->ctrl_reg1);
+ break;
case IIO_CHAN_INFO_CALIBBIAS:
- if (val < -10000 || val > 10000)
- return -EINVAL;
- return i2c_smbus_write_word_swapped(data->client,
+ if (val < -10000 || val > 10000) {
+ ret = -EINVAL;
+ break;
+ }
+ ret = i2c_smbus_write_word_swapped(data->client,
MAG3110_OFF_X + 2 * chan->scan_index, val << 1);
+ break;
default:
- return -EINVAL;
+ ret = -EINVAL;
+ break;
}
+ iio_device_release_direct_mode(indio_dev);
+ return ret;
}
static irqreturn_t mag3110_trigger_handler(int irq, void *p)
To compile this driver as a module, choose M here: the
module will be called ds1803.
+config MAX5481
+ tristate "Maxim MAX5481-MAX5484 Digital Potentiometer driver"
+ depends on SPI
+ help
+ Say yes here to build support for the Maxim
+ MAX5481, MAX5482, MAX5483, MAX5484 digital potentiometer
+ chips.
+
+ To compile this driver as a module, choose M here: the
+ module will be called max5481.
+
config MAX5487
tristate "Maxim MAX5487/MAX5488/MAX5489 Digital Potentiometer driver"
depends on SPI
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_DS1803) += ds1803.o
+obj-$(CONFIG_MAX5481) += max5481.o
obj-$(CONFIG_MAX5487) += max5487.o
obj-$(CONFIG_MCP4131) += mcp4131.o
obj-$(CONFIG_MCP4531) += mcp4531.o
--- /dev/null
+/*
+ * Maxim Integrated MAX5481-MAX5484 digital potentiometer driver
+ * Copyright 2016 Rockwell Collins
+ *
+ * Datasheet:
+ * http://datasheets.maximintegrated.com/en/ds/MAX5481-MAX5484.pdf
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the gnu general public license version 2 as
+ * published by the free software foundation.
+ *
+ */
+
+#include <linux/acpi.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/spi/spi.h>
+
+/* write wiper reg */
+#define MAX5481_WRITE_WIPER (0 << 4)
+/* copy wiper reg to NV reg */
+#define MAX5481_COPY_AB_TO_NV (2 << 4)
+/* copy NV reg to wiper reg */
+#define MAX5481_COPY_NV_TO_AB (3 << 4)
+
+#define MAX5481_MAX_POS 1023
+
+enum max5481_variant {
+ max5481,
+ max5482,
+ max5483,
+ max5484,
+};
+
+struct max5481_cfg {
+ int kohms;
+};
+
+static const struct max5481_cfg max5481_cfg[] = {
+ [max5481] = { .kohms = 10, },
+ [max5482] = { .kohms = 50, },
+ [max5483] = { .kohms = 10, },
+ [max5484] = { .kohms = 50, },
+};
+
+struct max5481_data {
+ struct spi_device *spi;
+ const struct max5481_cfg *cfg;
+ u8 msg[3] ____cacheline_aligned;
+};
+
+#define MAX5481_CHANNEL { \
+ .type = IIO_RESISTANCE, \
+ .indexed = 1, \
+ .output = 1, \
+ .channel = 0, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+}
+
+static const struct iio_chan_spec max5481_channels[] = {
+ MAX5481_CHANNEL,
+};
+
+static int max5481_write_cmd(struct max5481_data *data, u8 cmd, u16 val)
+{
+ struct spi_device *spi = data->spi;
+
+ data->msg[0] = cmd;
+
+ switch (cmd) {
+ case MAX5481_WRITE_WIPER:
+ data->msg[1] = val >> 2;
+ data->msg[2] = (val & 0x3) << 6;
+ return spi_write(spi, data->msg, 3);
+
+ case MAX5481_COPY_AB_TO_NV:
+ case MAX5481_COPY_NV_TO_AB:
+ return spi_write(spi, data->msg, 1);
+
+ default:
+ return -EIO;
+ }
+}
+
+static int max5481_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct max5481_data *data = iio_priv(indio_dev);
+
+ if (mask != IIO_CHAN_INFO_SCALE)
+ return -EINVAL;
+
+ *val = 1000 * data->cfg->kohms;
+ *val2 = MAX5481_MAX_POS;
+
+ return IIO_VAL_FRACTIONAL;
+}
+
+static int max5481_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct max5481_data *data = iio_priv(indio_dev);
+
+ if (mask != IIO_CHAN_INFO_RAW)
+ return -EINVAL;
+
+ if (val < 0 || val > MAX5481_MAX_POS)
+ return -EINVAL;
+
+ return max5481_write_cmd(data, MAX5481_WRITE_WIPER, val);
+}
+
+static const struct iio_info max5481_info = {
+ .read_raw = max5481_read_raw,
+ .write_raw = max5481_write_raw,
+ .driver_module = THIS_MODULE,
+};
+
+#if defined(CONFIG_OF)
+static const struct of_device_id max5481_match[] = {
+ { .compatible = "maxim,max5481", .data = &max5481_cfg[max5481] },
+ { .compatible = "maxim,max5482", .data = &max5481_cfg[max5482] },
+ { .compatible = "maxim,max5483", .data = &max5481_cfg[max5483] },
+ { .compatible = "maxim,max5484", .data = &max5481_cfg[max5484] },
+ { }
+};
+MODULE_DEVICE_TABLE(of, max5481_match);
+#endif
+
+static int max5481_probe(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev;
+ struct max5481_data *data;
+ const struct spi_device_id *id = spi_get_device_id(spi);
+ const struct of_device_id *match;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ dev_set_drvdata(&spi->dev, indio_dev);
+ data = iio_priv(indio_dev);
+
+ data->spi = spi;
+
+ match = of_match_device(of_match_ptr(max5481_match), &spi->dev);
+ if (match)
+ data->cfg = of_device_get_match_data(&spi->dev);
+ else
+ data->cfg = &max5481_cfg[id->driver_data];
+
+ indio_dev->name = id->name;
+ indio_dev->dev.parent = &spi->dev;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ /* variant specific configuration */
+ indio_dev->info = &max5481_info;
+ indio_dev->channels = max5481_channels;
+ indio_dev->num_channels = ARRAY_SIZE(max5481_channels);
+
+ /* restore wiper from NV */
+ ret = max5481_write_cmd(data, MAX5481_COPY_NV_TO_AB, 0);
+ if (ret < 0)
+ return ret;
+
+ return iio_device_register(indio_dev);
+}
+
+static int max5481_remove(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev = dev_get_drvdata(&spi->dev);
+ struct max5481_data *data = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+
+ /* save wiper reg to NV reg */
+ return max5481_write_cmd(data, MAX5481_COPY_AB_TO_NV, 0);
+}
+
+static const struct spi_device_id max5481_id_table[] = {
+ { "max5481", max5481 },
+ { "max5482", max5482 },
+ { "max5483", max5483 },
+ { "max5484", max5484 },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, max5481_id_table);
+
+#if defined(CONFIG_ACPI)
+static const struct acpi_device_id max5481_acpi_match[] = {
+ { "max5481", max5481 },
+ { "max5482", max5482 },
+ { "max5483", max5483 },
+ { "max5484", max5484 },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, max5481_acpi_match);
+#endif
+
+static struct spi_driver max5481_driver = {
+ .driver = {
+ .name = "max5481",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(max5481_match),
+ .acpi_match_table = ACPI_PTR(max5481_acpi_match),
+ },
+ .probe = max5481_probe,
+ .remove = max5481_remove,
+ .id_table = max5481_id_table,
+};
+
+module_spi_driver(max5481_driver);
+
+MODULE_AUTHOR("Maury Anderson <maury.anderson@rockwellcollins.com>");
+MODULE_DESCRIPTION("max5481 SPI driver");
+MODULE_LICENSE("GPL v2");
MCP4531_COMPATIBLE("microchip,mcp4662-104", MCP466x_104),
{ /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, mcp4531_of_match);
#endif
static int mcp4531_probe(struct i2c_client *client,
depends on SPI_MASTER
select REGMAP
+config IIO_CROS_EC_BARO
+ tristate "ChromeOS EC Barometer Sensor"
+ depends on IIO_CROS_EC_SENSORS_CORE
+ help
+ Say yes here to build support for the Barometer sensor when
+ presented by the ChromeOS EC Sensor hub.
+
+ To compile this driver as a module, choose M here: the module
+ will be called cros_ec_baro.
+
config HID_SENSOR_PRESS
depends on HID_SENSOR_HUB
select IIO_BUFFER
bmp280-objs := bmp280-core.o bmp280-regmap.o
obj-$(CONFIG_BMP280_I2C) += bmp280-i2c.o
obj-$(CONFIG_BMP280_SPI) += bmp280-spi.o
+obj-$(CONFIG_IIO_CROS_EC_BARO) += cros_ec_baro.o
obj-$(CONFIG_HID_SENSOR_PRESS) += hid-sensor-press.o
obj-$(CONFIG_HP03) += hp03.o
obj-$(CONFIG_MPL115) += mpl115.o
struct bmp180_calib calib;
struct regulator *vddd;
struct regulator *vdda;
- unsigned int start_up_time; /* in milliseconds */
+ unsigned int start_up_time; /* in microseconds */
/* log of base 2 of oversampling rate */
u8 oversampling_press;
data->chip_info = &bmp180_chip_info;
data->oversampling_press = ilog2(8);
data->oversampling_temp = ilog2(1);
- data->start_up_time = 10;
+ data->start_up_time = 10000;
break;
case BMP280_CHIP_ID:
indio_dev->num_channels = 2;
data->chip_info = &bmp280_chip_info;
data->oversampling_press = ilog2(16);
data->oversampling_temp = ilog2(2);
- data->start_up_time = 2;
+ data->start_up_time = 2000;
break;
case BME280_CHIP_ID:
indio_dev->num_channels = 3;
data->oversampling_press = ilog2(16);
data->oversampling_humid = ilog2(16);
data->oversampling_temp = ilog2(2);
- data->start_up_time = 2;
+ data->start_up_time = 2000;
break;
default:
return -EINVAL;
goto out_disable_vddd;
}
/* Wait to make sure we started up properly */
- mdelay(data->start_up_time);
+ usleep_range(data->start_up_time, data->start_up_time + 100);
/* Bring chip out of reset if there is an assigned GPIO line */
gpiod = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
* Set autosuspend to two orders of magnitude larger than the
* start-up time.
*/
- pm_runtime_set_autosuspend_delay(dev, data->start_up_time *100);
+ pm_runtime_set_autosuspend_delay(dev, data->start_up_time / 10);
pm_runtime_use_autosuspend(dev);
pm_runtime_put(dev);
ret = regulator_enable(data->vdda);
if (ret)
return ret;
- msleep(data->start_up_time);
+ usleep_range(data->start_up_time, data->start_up_time + 100);
return data->chip_info->chip_config(data);
}
#endif /* CONFIG_PM */
--- /dev/null
+/*
+ * cros_ec_baro - Driver for barometer sensor behind CrosEC.
+ *
+ * Copyright (C) 2017 Google, Inc
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/kernel.h>
+#include <linux/mfd/cros_ec.h>
+#include <linux/mfd/cros_ec_commands.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+#include "../common/cros_ec_sensors/cros_ec_sensors_core.h"
+
+/*
+ * One channel for pressure, the other for timestamp.
+ */
+#define CROS_EC_BARO_MAX_CHANNELS (1 + 1)
+
+/* State data for ec_sensors iio driver. */
+struct cros_ec_baro_state {
+ /* Shared by all sensors */
+ struct cros_ec_sensors_core_state core;
+
+ struct iio_chan_spec channels[CROS_EC_BARO_MAX_CHANNELS];
+};
+
+static int cros_ec_baro_read(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct cros_ec_baro_state *st = iio_priv(indio_dev);
+ u16 data = 0;
+ int ret = IIO_VAL_INT;
+ int idx = chan->scan_index;
+
+ mutex_lock(&st->core.cmd_lock);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (cros_ec_sensors_read_cmd(indio_dev, 1 << idx,
+ (s16 *)&data) < 0)
+ ret = -EIO;
+ *val = data;
+ break;
+ case IIO_CHAN_INFO_SCALE:
+ st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_RANGE;
+ st->core.param.sensor_range.data = EC_MOTION_SENSE_NO_VALUE;
+
+ if (cros_ec_motion_send_host_cmd(&st->core, 0)) {
+ ret = -EIO;
+ break;
+ }
+ *val = st->core.resp->sensor_range.ret;
+
+ /* scale * in_pressure_raw --> kPa */
+ *val2 = 10 << CROS_EC_SENSOR_BITS;
+ ret = IIO_VAL_FRACTIONAL;
+ break;
+ default:
+ ret = cros_ec_sensors_core_read(&st->core, chan, val, val2,
+ mask);
+ break;
+ }
+
+ mutex_unlock(&st->core.cmd_lock);
+
+ return ret;
+}
+
+static int cros_ec_baro_write(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct cros_ec_baro_state *st = iio_priv(indio_dev);
+ int ret = 0;
+
+ mutex_lock(&st->core.cmd_lock);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ st->core.param.cmd = MOTIONSENSE_CMD_SENSOR_RANGE;
+ st->core.param.sensor_range.data = val;
+
+ /* Always roundup, so caller gets at least what it asks for. */
+ st->core.param.sensor_range.roundup = 1;
+
+ if (cros_ec_motion_send_host_cmd(&st->core, 0))
+ ret = -EIO;
+ break;
+ default:
+ ret = cros_ec_sensors_core_write(&st->core, chan, val, val2,
+ mask);
+ break;
+ }
+
+ mutex_unlock(&st->core.cmd_lock);
+
+ return ret;
+}
+
+static const struct iio_info cros_ec_baro_info = {
+ .read_raw = &cros_ec_baro_read,
+ .write_raw = &cros_ec_baro_write,
+ .driver_module = THIS_MODULE,
+};
+
+static int cros_ec_baro_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct cros_ec_dev *ec_dev = dev_get_drvdata(dev->parent);
+ struct cros_ec_device *ec_device;
+ struct iio_dev *indio_dev;
+ struct cros_ec_baro_state *state;
+ struct iio_chan_spec *channel;
+ int ret;
+
+ if (!ec_dev || !ec_dev->ec_dev) {
+ dev_warn(dev, "No CROS EC device found.\n");
+ return -EINVAL;
+ }
+ ec_device = ec_dev->ec_dev;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*state));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ ret = cros_ec_sensors_core_init(pdev, indio_dev, true);
+ if (ret)
+ return ret;
+
+ indio_dev->info = &cros_ec_baro_info;
+ state = iio_priv(indio_dev);
+ state->core.type = state->core.resp->info.type;
+ state->core.loc = state->core.resp->info.location;
+ channel = state->channels;
+ /* Common part */
+ channel->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
+ channel->info_mask_shared_by_all =
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_FREQUENCY);
+ channel->scan_type.realbits = CROS_EC_SENSOR_BITS;
+ channel->scan_type.storagebits = CROS_EC_SENSOR_BITS;
+ channel->scan_type.shift = 0;
+ channel->scan_index = 0;
+ channel->ext_info = cros_ec_sensors_ext_info;
+ channel->scan_type.sign = 'u';
+
+ state->core.calib[0] = 0;
+
+ /* Sensor specific */
+ switch (state->core.type) {
+ case MOTIONSENSE_TYPE_BARO:
+ channel->type = IIO_PRESSURE;
+ break;
+ default:
+ dev_warn(dev, "Unknown motion sensor\n");
+ return -EINVAL;
+ }
+
+ /* Timestamp */
+ channel++;
+ channel->type = IIO_TIMESTAMP;
+ channel->channel = -1;
+ channel->scan_index = 1;
+ channel->scan_type.sign = 's';
+ channel->scan_type.realbits = 64;
+ channel->scan_type.storagebits = 64;
+
+ indio_dev->channels = state->channels;
+ indio_dev->num_channels = CROS_EC_BARO_MAX_CHANNELS;
+
+ state->core.read_ec_sensors_data = cros_ec_sensors_read_cmd;
+
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
+ cros_ec_sensors_capture, NULL);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct platform_device_id cros_ec_baro_ids[] = {
+ {
+ .name = "cros-ec-baro",
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, cros_ec_baro_ids);
+
+static struct platform_driver cros_ec_baro_platform_driver = {
+ .driver = {
+ .name = "cros-ec-baro",
+ },
+ .probe = cros_ec_baro_probe,
+ .id_table = cros_ec_baro_ids,
+};
+module_platform_driver(cros_ec_baro_platform_driver);
+
+MODULE_DESCRIPTION("ChromeOS EC barometer sensor driver");
+MODULE_LICENSE("GPL v2");
{
struct ms5611_state *st = iio_priv(indio_dev);
const struct ms5611_osr *osr = NULL;
+ int ret;
if (mask != IIO_CHAN_INFO_OVERSAMPLING_RATIO)
return -EINVAL;
if (!osr)
return -EINVAL;
- mutex_lock(&st->lock);
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
- if (iio_buffer_enabled(indio_dev)) {
- mutex_unlock(&st->lock);
- return -EBUSY;
- }
+ mutex_lock(&st->lock);
if (chan->type == IIO_TEMP)
st->temp_osr = osr;
st->pressure_osr = osr;
mutex_unlock(&st->lock);
+ iio_device_release_direct_mode(indio_dev);
+
return 0;
}
#include <linux/types.h>
#include <linux/iio/common/st_sensors.h>
+enum st_press_type {
+ LPS001WP,
+ LPS25H,
+ LPS331AP,
+ LPS22HB,
+ ST_PRESS_MAX,
+};
+
#define LPS001WP_PRESS_DEV_NAME "lps001wp"
#define LPS25H_PRESS_DEV_NAME "lps25h"
#define LPS331AP_PRESS_DEV_NAME "lps331ap"
.address = ST_PRESS_1_OUT_XL_ADDR,
.scan_index = 0,
.scan_type = {
- .sign = 'u',
+ .sign = 's',
.realbits = 24,
.storagebits = 32,
.endianness = IIO_LE,
},
.info_mask_separate =
BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
},
{
.type = IIO_TEMP,
.address = ST_TEMP_1_OUT_L_ADDR,
.scan_index = 1,
.scan_type = {
- .sign = 'u',
+ .sign = 's',
.realbits = 16,
.storagebits = 16,
.endianness = IIO_LE,
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OFFSET),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
},
IIO_CHAN_SOFT_TIMESTAMP(2)
};
.address = ST_PRESS_LPS001WP_OUT_L_ADDR,
.scan_index = 0,
.scan_type = {
- .sign = 'u',
+ .sign = 's',
.realbits = 16,
.storagebits = 16,
.endianness = IIO_LE,
.address = ST_TEMP_LPS001WP_OUT_L_ADDR,
.scan_index = 1,
.scan_type = {
- .sign = 'u',
+ .sign = 's',
.realbits = 16,
.storagebits = 16,
.endianness = IIO_LE,
.address = ST_PRESS_1_OUT_XL_ADDR,
.scan_index = 0,
.scan_type = {
- .sign = 'u',
+ .sign = 's',
.realbits = 24,
.storagebits = 32,
.endianness = IIO_LE,
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#define st_press_of_match NULL
#endif
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id st_press_acpi_match[] = {
+ {"SNO9210", LPS22HB},
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, st_press_acpi_match);
+#else
+#define st_press_acpi_match NULL
+#endif
+
+static const struct i2c_device_id st_press_id_table[] = {
+ { LPS001WP_PRESS_DEV_NAME, LPS001WP },
+ { LPS25H_PRESS_DEV_NAME, LPS25H },
+ { LPS331AP_PRESS_DEV_NAME, LPS331AP },
+ { LPS22HB_PRESS_DEV_NAME, LPS22HB },
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, st_press_id_table);
+
static int st_press_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct iio_dev *indio_dev;
struct st_sensor_data *press_data;
- int err;
+ int ret;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*press_data));
if (!indio_dev)
return -ENOMEM;
press_data = iio_priv(indio_dev);
- st_sensors_of_i2c_probe(client, st_press_of_match);
+
+ if (client->dev.of_node) {
+ st_sensors_of_i2c_probe(client, st_press_of_match);
+ } else if (ACPI_HANDLE(&client->dev)) {
+ ret = st_sensors_match_acpi_device(&client->dev);
+ if ((ret < 0) || (ret >= ST_PRESS_MAX))
+ return -ENODEV;
+
+ strncpy(client->name, st_press_id_table[ret].name,
+ sizeof(client->name));
+ client->name[sizeof(client->name) - 1] = '\0';
+ } else if (!id)
+ return -ENODEV;
st_sensors_i2c_configure(indio_dev, client, press_data);
- err = st_press_common_probe(indio_dev);
- if (err < 0)
- return err;
+ ret = st_press_common_probe(indio_dev);
+ if (ret < 0)
+ return ret;
return 0;
}
return 0;
}
-static const struct i2c_device_id st_press_id_table[] = {
- { LPS001WP_PRESS_DEV_NAME },
- { LPS25H_PRESS_DEV_NAME },
- { LPS331AP_PRESS_DEV_NAME },
- {},
-};
-MODULE_DEVICE_TABLE(i2c, st_press_id_table);
-
static struct i2c_driver st_press_driver = {
.driver = {
.name = "st-press-i2c",
.of_match_table = of_match_ptr(st_press_of_match),
+ .acpi_match_table = ACPI_PTR(st_press_acpi_match),
},
.probe = st_press_i2c_probe,
.remove = st_press_i2c_remove,
endmenu
-menu "Proximity sensors"
+menu "Proximity and distance sensors"
config LIDAR_LITE_V2
tristate "PulsedLight LIDAR sensor"
To compile this driver as a module, choose M here: the
module will be called sx9500.
+config SRF08
+ tristate "Devantech SRF08 ultrasonic ranger sensor"
+ depends on I2C
+ help
+ Say Y here to build a driver for Devantech SRF08 ultrasonic
+ ranger sensor. This driver can be used to measure the distance
+ of objects.
+
+ To compile this driver as a module, choose M here: the
+ module will be called srf08.
+
endmenu
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AS3935) += as3935.o
obj-$(CONFIG_LIDAR_LITE_V2) += pulsedlight-lidar-lite-v2.o
+obj-$(CONFIG_SRF08) += srf08.o
obj-$(CONFIG_SX9500) += sx9500.o
static const struct i2c_device_id lidar_id[] = {
{"lidar-lite-v2", 0},
+ {"lidar-lite-v3", 0},
{ },
};
MODULE_DEVICE_TABLE(i2c, lidar_id);
static const struct of_device_id lidar_dt_ids[] = {
{ .compatible = "pulsedlight,lidar-lite-v2" },
+ { .compatible = "grmn,lidar-lite-v3" },
{ }
};
MODULE_DEVICE_TABLE(of, lidar_dt_ids);
--- /dev/null
+/*
+ * srf08.c - Support for Devantech SRF08 ultrasonic ranger
+ *
+ * Copyright (c) 2016 Andreas Klinger <ak@it-klinger.de>
+ *
+ * This file is subject to the terms and conditions of version 2 of
+ * the GNU General Public License. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * For details about the device see:
+ * http://www.robot-electronics.co.uk/htm/srf08tech.html
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/bitops.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+/* registers of SRF08 device */
+#define SRF08_WRITE_COMMAND 0x00 /* Command Register */
+#define SRF08_WRITE_MAX_GAIN 0x01 /* Max Gain Register: 0 .. 31 */
+#define SRF08_WRITE_RANGE 0x02 /* Range Register: 0 .. 255 */
+#define SRF08_READ_SW_REVISION 0x00 /* Software Revision */
+#define SRF08_READ_LIGHT 0x01 /* Light Sensor during last echo */
+#define SRF08_READ_ECHO_1_HIGH 0x02 /* Range of first echo received */
+#define SRF08_READ_ECHO_1_LOW 0x03 /* Range of first echo received */
+
+#define SRF08_CMD_RANGING_CM 0x51 /* Ranging Mode - Result in cm */
+
+#define SRF08_DEFAULT_GAIN 1025 /* default analogue value of Gain */
+#define SRF08_DEFAULT_RANGE 6020 /* default value of Range in mm */
+
+struct srf08_data {
+ struct i2c_client *client;
+ int sensitivity; /* Gain */
+ int range_mm; /* max. Range in mm */
+ struct mutex lock;
+};
+
+/*
+ * in the documentation one can read about the "Gain" of the device
+ * which is used here for amplifying the signal and filtering out unwanted
+ * ones.
+ * But with ADC's this term is already used differently and that's why it
+ * is called "Sensitivity" here.
+ */
+static const int srf08_sensitivity[] = {
+ 94, 97, 100, 103, 107, 110, 114, 118,
+ 123, 128, 133, 139, 145, 152, 159, 168,
+ 177, 187, 199, 212, 227, 245, 265, 288,
+ 317, 352, 395, 450, 524, 626, 777, 1025 };
+
+static int srf08_read_ranging(struct srf08_data *data)
+{
+ struct i2c_client *client = data->client;
+ int ret, i;
+ int waittime;
+
+ mutex_lock(&data->lock);
+
+ ret = i2c_smbus_write_byte_data(data->client,
+ SRF08_WRITE_COMMAND, SRF08_CMD_RANGING_CM);
+ if (ret < 0) {
+ dev_err(&client->dev, "write command - err: %d\n", ret);
+ mutex_unlock(&data->lock);
+ return ret;
+ }
+
+ /*
+ * we read here until a correct version number shows up as
+ * suggested by the documentation
+ *
+ * with an ultrasonic speed of 343 m/s and a roundtrip of it
+ * sleep the expected duration and try to read from the device
+ * if nothing useful is read try it in a shorter grid
+ *
+ * polling for not more than 20 ms should be enough
+ */
+ waittime = 1 + data->range_mm / 172;
+ msleep(waittime);
+ for (i = 0; i < 4; i++) {
+ ret = i2c_smbus_read_byte_data(data->client,
+ SRF08_READ_SW_REVISION);
+
+ /* check if a valid version number is read */
+ if (ret < 255 && ret > 0)
+ break;
+ msleep(5);
+ }
+
+ if (ret >= 255 || ret <= 0) {
+ dev_err(&client->dev, "device not ready\n");
+ mutex_unlock(&data->lock);
+ return -EIO;
+ }
+
+ ret = i2c_smbus_read_word_swapped(data->client,
+ SRF08_READ_ECHO_1_HIGH);
+ if (ret < 0) {
+ dev_err(&client->dev, "cannot read distance: ret=%d\n", ret);
+ mutex_unlock(&data->lock);
+ return ret;
+ }
+
+ mutex_unlock(&data->lock);
+
+ return ret;
+}
+
+static int srf08_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel, int *val,
+ int *val2, long mask)
+{
+ struct srf08_data *data = iio_priv(indio_dev);
+ int ret;
+
+ if (channel->type != IIO_DISTANCE)
+ return -EINVAL;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = srf08_read_ranging(data);
+ if (ret < 0)
+ return ret;
+ *val = ret;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ /* 1 LSB is 1 cm */
+ *val = 0;
+ *val2 = 10000;
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static ssize_t srf08_show_range_mm_available(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "[0.043 0.043 11.008]\n");
+}
+
+static IIO_DEVICE_ATTR(sensor_max_range_available, S_IRUGO,
+ srf08_show_range_mm_available, NULL, 0);
+
+static ssize_t srf08_show_range_mm(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct srf08_data *data = iio_priv(indio_dev);
+
+ return sprintf(buf, "%d.%03d\n", data->range_mm / 1000,
+ data->range_mm % 1000);
+}
+
+/*
+ * set the range of the sensor to an even multiple of 43 mm
+ * which corresponds to 1 LSB in the register
+ *
+ * register value corresponding range
+ * 0x00 43 mm
+ * 0x01 86 mm
+ * 0x02 129 mm
+ * ...
+ * 0xFF 11008 mm
+ */
+static ssize_t srf08_write_range_mm(struct srf08_data *data, unsigned int val)
+{
+ int ret;
+ struct i2c_client *client = data->client;
+ unsigned int mod;
+ u8 regval;
+
+ ret = val / 43 - 1;
+ mod = val % 43;
+
+ if (mod || (ret < 0) || (ret > 255))
+ return -EINVAL;
+
+ regval = ret;
+
+ mutex_lock(&data->lock);
+
+ ret = i2c_smbus_write_byte_data(client, SRF08_WRITE_RANGE, regval);
+ if (ret < 0) {
+ dev_err(&client->dev, "write_range - err: %d\n", ret);
+ mutex_unlock(&data->lock);
+ return ret;
+ }
+
+ data->range_mm = val;
+
+ mutex_unlock(&data->lock);
+
+ return 0;
+}
+
+static ssize_t srf08_store_range_mm(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct srf08_data *data = iio_priv(indio_dev);
+ int ret;
+ int integer, fract;
+
+ ret = iio_str_to_fixpoint(buf, 100, &integer, &fract);
+ if (ret)
+ return ret;
+
+ ret = srf08_write_range_mm(data, integer * 1000 + fract);
+ if (ret < 0)
+ return ret;
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(sensor_max_range, S_IRUGO | S_IWUSR,
+ srf08_show_range_mm, srf08_store_range_mm, 0);
+
+static ssize_t srf08_show_sensitivity_available(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int i, len = 0;
+
+ for (i = 0; i < ARRAY_SIZE(srf08_sensitivity); i++)
+ len += sprintf(buf + len, "%d ", srf08_sensitivity[i]);
+
+ len += sprintf(buf + len, "\n");
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(sensor_sensitivity_available, S_IRUGO,
+ srf08_show_sensitivity_available, NULL, 0);
+
+static ssize_t srf08_show_sensitivity(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct srf08_data *data = iio_priv(indio_dev);
+ int len;
+
+ len = sprintf(buf, "%d\n", data->sensitivity);
+
+ return len;
+}
+
+static ssize_t srf08_write_sensitivity(struct srf08_data *data,
+ unsigned int val)
+{
+ struct i2c_client *client = data->client;
+ int ret, i;
+ u8 regval;
+
+ for (i = 0; i < ARRAY_SIZE(srf08_sensitivity); i++)
+ if (val == srf08_sensitivity[i]) {
+ regval = i;
+ break;
+ }
+
+ if (i >= ARRAY_SIZE(srf08_sensitivity))
+ return -EINVAL;
+
+ mutex_lock(&data->lock);
+
+ ret = i2c_smbus_write_byte_data(client,
+ SRF08_WRITE_MAX_GAIN, regval);
+ if (ret < 0) {
+ dev_err(&client->dev, "write_sensitivity - err: %d\n", ret);
+ mutex_unlock(&data->lock);
+ return ret;
+ }
+
+ data->sensitivity = val;
+
+ mutex_unlock(&data->lock);
+
+ return 0;
+}
+
+static ssize_t srf08_store_sensitivity(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct srf08_data *data = iio_priv(indio_dev);
+ int ret;
+ unsigned int val;
+
+ ret = kstrtouint(buf, 10, &val);
+ if (ret)
+ return ret;
+
+ ret = srf08_write_sensitivity(data, val);
+ if (ret < 0)
+ return ret;
+
+ return len;
+}
+
+static IIO_DEVICE_ATTR(sensor_sensitivity, S_IRUGO | S_IWUSR,
+ srf08_show_sensitivity, srf08_store_sensitivity, 0);
+
+static struct attribute *srf08_attributes[] = {
+ &iio_dev_attr_sensor_max_range.dev_attr.attr,
+ &iio_dev_attr_sensor_max_range_available.dev_attr.attr,
+ &iio_dev_attr_sensor_sensitivity.dev_attr.attr,
+ &iio_dev_attr_sensor_sensitivity_available.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group srf08_attribute_group = {
+ .attrs = srf08_attributes,
+};
+
+static const struct iio_chan_spec srf08_channels[] = {
+ {
+ .type = IIO_DISTANCE,
+ .info_mask_separate =
+ BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ },
+};
+
+static const struct iio_info srf08_info = {
+ .read_raw = srf08_read_raw,
+ .attrs = &srf08_attribute_group,
+ .driver_module = THIS_MODULE,
+};
+
+static int srf08_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct iio_dev *indio_dev;
+ struct srf08_data *data;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_BYTE_DATA |
+ I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
+ I2C_FUNC_SMBUS_READ_WORD_DATA))
+ return -ENODEV;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ i2c_set_clientdata(client, indio_dev);
+ data->client = client;
+
+ indio_dev->name = "srf08";
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &srf08_info;
+ indio_dev->channels = srf08_channels;
+ indio_dev->num_channels = ARRAY_SIZE(srf08_channels);
+
+ mutex_init(&data->lock);
+
+ /*
+ * set default values of device here
+ * these register values cannot be read from the hardware
+ * therefore set driver specific default values
+ */
+ ret = srf08_write_range_mm(data, SRF08_DEFAULT_RANGE);
+ if (ret < 0)
+ return ret;
+
+ ret = srf08_write_sensitivity(data, SRF08_DEFAULT_GAIN);
+ if (ret < 0)
+ return ret;
+
+ return devm_iio_device_register(&client->dev, indio_dev);
+}
+
+static const struct i2c_device_id srf08_id[] = {
+ { "srf08", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, srf08_id);
+
+static struct i2c_driver srf08_driver = {
+ .driver = {
+ .name = "srf08",
+ },
+ .probe = srf08_probe,
+ .id_table = srf08_id,
+};
+module_i2c_driver(srf08_driver);
+
+MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>");
+MODULE_DESCRIPTION("Devantech SRF08 ultrasonic ranger driver");
+MODULE_LICENSE("GPL");
int *val, int *val2, long mask)
{
struct sx9500_data *data = iio_priv(indio_dev);
+ int ret;
switch (chan->type) {
case IIO_PROXIMITY:
switch (mask) {
case IIO_CHAN_INFO_RAW:
- if (iio_buffer_enabled(indio_dev))
- return -EBUSY;
- return sx9500_read_proximity(data, chan, val);
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
+ ret = sx9500_read_proximity(data, chan, val);
+ iio_device_release_direct_mode(indio_dev);
+ return ret;
case IIO_CHAN_INFO_SAMP_FREQ:
return sx9500_read_samp_freq(data, val, val2);
default:
This driver can also be built as a module. If so, the module will
be called tmp006.
+config TMP007
+ tristate "TMP007 infrared thermopile sensor with Integrated Math Engine"
+ depends on I2C
+ help
+ If you say yes here you get support for the Texas Instruments
+ TMP007 infrared thermopile sensor with Integrated Math Engine.
+
+ This driver can also be built as a module. If so, the module will
+ be called tmp007.
+
config TSYS01
tristate "Measurement Specialties TSYS01 temperature sensor using I2C bus connection"
depends on I2C
obj-$(CONFIG_MAXIM_THERMOCOUPLE) += maxim_thermocouple.o
obj-$(CONFIG_MLX90614) += mlx90614.o
obj-$(CONFIG_TMP006) += tmp006.o
+obj-$(CONFIG_TMP007) += tmp007.o
obj-$(CONFIG_TSYS01) += tsys01.o
obj-$(CONFIG_TSYS02D) += tsys02d.o
--- /dev/null
+/*
+ * tmp007.c - Support for TI TMP007 IR thermopile sensor with integrated math engine
+ *
+ * Copyright (c) 2017 Manivannan Sadhasivam <manivannanece23@gmail.com>
+ *
+ * This file is subject to the terms and conditions of version 2 of
+ * the GNU General Public License. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * Driver for the Texas Instruments I2C 16-bit IR thermopile sensor
+ *
+ * (7-bit I2C slave address (0x40 - 0x47), changeable via ADR pins)
+ *
+ * Note: This driver assumes that the sensor has been calibrated beforehand
+ *
+ * TODO: ALERT irq, limit threshold events
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/bitops.h>
+#include <linux/of.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define TMP007_TDIE 0x01
+#define TMP007_CONFIG 0x02
+#define TMP007_TOBJECT 0x03
+#define TMP007_STATUS 0x04
+#define TMP007_STATUS_MASK 0x05
+#define TMP007_MANUFACTURER_ID 0x1e
+#define TMP007_DEVICE_ID 0x1f
+
+#define TMP007_CONFIG_CONV_EN BIT(12)
+#define TMP007_CONFIG_COMP_EN BIT(5)
+#define TMP007_CONFIG_TC_EN BIT(6)
+#define TMP007_CONFIG_CR_MASK GENMASK(11, 9)
+#define TMP007_CONFIG_CR_SHIFT 9
+
+#define TMP007_STATUS_CONV_READY BIT(14)
+#define TMP007_STATUS_DATA_VALID BIT(9)
+
+#define TMP007_MANUFACTURER_MAGIC 0x5449
+#define TMP007_DEVICE_MAGIC 0x0078
+
+#define TMP007_TEMP_SHIFT 2
+
+struct tmp007_data {
+ struct i2c_client *client;
+ u16 config;
+};
+
+static const int tmp007_avgs[5][2] = { {4, 0}, {2, 0}, {1, 0},
+ {0, 500000}, {0, 250000} };
+
+static int tmp007_read_temperature(struct tmp007_data *data, u8 reg)
+{
+ s32 ret;
+ int tries = 50;
+
+ while (tries-- > 0) {
+ ret = i2c_smbus_read_word_swapped(data->client,
+ TMP007_STATUS);
+ if (ret < 0)
+ return ret;
+ if ((ret & TMP007_STATUS_CONV_READY) &&
+ !(ret & TMP007_STATUS_DATA_VALID))
+ break;
+ msleep(100);
+ }
+
+ if (tries < 0)
+ return -EIO;
+
+ return i2c_smbus_read_word_swapped(data->client, reg);
+}
+
+static int tmp007_powerdown(struct tmp007_data *data)
+{
+ return i2c_smbus_write_word_swapped(data->client, TMP007_CONFIG,
+ data->config & ~TMP007_CONFIG_CONV_EN);
+}
+
+static int tmp007_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel, int *val,
+ int *val2, long mask)
+{
+ struct tmp007_data *data = iio_priv(indio_dev);
+ s32 ret;
+ int conv_rate;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ switch (channel->channel2) {
+ case IIO_MOD_TEMP_AMBIENT: /* LSB: 0.03125 degree Celsius */
+ ret = i2c_smbus_read_word_swapped(data->client, TMP007_TDIE);
+ if (ret < 0)
+ return ret;
+ break;
+ case IIO_MOD_TEMP_OBJECT:
+ ret = tmp007_read_temperature(data, TMP007_TOBJECT);
+ if (ret < 0)
+ return ret;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ *val = sign_extend32(ret, 15) >> TMP007_TEMP_SHIFT;
+
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = 31;
+ *val2 = 250000;
+
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ conv_rate = (data->config & TMP007_CONFIG_CR_MASK)
+ >> TMP007_CONFIG_CR_SHIFT;
+ *val = tmp007_avgs[conv_rate][0];
+ *val2 = tmp007_avgs[conv_rate][1];
+
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int tmp007_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *channel, int val,
+ int val2, long mask)
+{
+ struct tmp007_data *data = iio_priv(indio_dev);
+ int i;
+ u16 tmp;
+
+ if (mask == IIO_CHAN_INFO_SAMP_FREQ) {
+ for (i = 0; i < ARRAY_SIZE(tmp007_avgs); i++) {
+ if ((val == tmp007_avgs[i][0]) &&
+ (val2 == tmp007_avgs[i][1])) {
+ tmp = data->config & ~TMP007_CONFIG_CR_MASK;
+ tmp |= (i << TMP007_CONFIG_CR_SHIFT);
+
+ return i2c_smbus_write_word_swapped(data->client,
+ TMP007_CONFIG,
+ data->config = tmp);
+ }
+ }
+ }
+
+ return -EINVAL;
+}
+
+static IIO_CONST_ATTR(sampling_frequency_available, "4 2 1 0.5 0.25");
+
+static struct attribute *tmp007_attributes[] = {
+ &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group tmp007_attribute_group = {
+ .attrs = tmp007_attributes,
+};
+
+static const struct iio_chan_spec tmp007_channels[] = {
+ {
+ .type = IIO_TEMP,
+ .modified = 1,
+ .channel2 = IIO_MOD_TEMP_AMBIENT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ },
+ {
+ .type = IIO_TEMP,
+ .modified = 1,
+ .channel2 = IIO_MOD_TEMP_OBJECT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ }
+};
+
+static const struct iio_info tmp007_info = {
+ .read_raw = tmp007_read_raw,
+ .write_raw = tmp007_write_raw,
+ .attrs = &tmp007_attribute_group,
+ .driver_module = THIS_MODULE,
+};
+
+static bool tmp007_identify(struct i2c_client *client)
+{
+ int manf_id, dev_id;
+
+ manf_id = i2c_smbus_read_word_swapped(client, TMP007_MANUFACTURER_ID);
+ if (manf_id < 0)
+ return false;
+
+ dev_id = i2c_smbus_read_word_swapped(client, TMP007_DEVICE_ID);
+ if (dev_id < 0)
+ return false;
+
+ return (manf_id == TMP007_MANUFACTURER_MAGIC && dev_id == TMP007_DEVICE_MAGIC);
+}
+
+static int tmp007_probe(struct i2c_client *client,
+ const struct i2c_device_id *tmp007_id)
+{
+ struct tmp007_data *data;
+ struct iio_dev *indio_dev;
+ int ret;
+ u16 status;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
+ return -EOPNOTSUPP;
+
+ if (!tmp007_identify(client)) {
+ dev_err(&client->dev, "TMP007 not found\n");
+ return -ENODEV;
+ }
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ i2c_set_clientdata(client, indio_dev);
+ data->client = client;
+
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->name = "tmp007";
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &tmp007_info;
+
+ indio_dev->channels = tmp007_channels;
+ indio_dev->num_channels = ARRAY_SIZE(tmp007_channels);
+
+ /*
+ * Set Configuration register:
+ * 1. Conversion ON
+ * 2. Comparator mode
+ * 3. Transient correction enable
+ */
+
+ ret = i2c_smbus_read_word_swapped(data->client, TMP007_CONFIG);
+ if (ret < 0)
+ return ret;
+
+ data->config = ret;
+ data->config |= (TMP007_CONFIG_CONV_EN | TMP007_CONFIG_COMP_EN | TMP007_CONFIG_TC_EN);
+
+ ret = i2c_smbus_write_word_swapped(data->client, TMP007_CONFIG,
+ data->config);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Set Status Mask register:
+ * 1. Conversion ready enable
+ * 2. Data valid enable
+ */
+
+ ret = i2c_smbus_read_word_swapped(data->client, TMP007_STATUS_MASK);
+ if (ret < 0)
+ goto error_powerdown;
+
+ status = ret;
+ status |= (TMP007_STATUS_CONV_READY | TMP007_STATUS_DATA_VALID);
+
+ ret = i2c_smbus_write_word_swapped(data->client, TMP007_STATUS_MASK, status);
+ if (ret < 0)
+ goto error_powerdown;
+
+ return iio_device_register(indio_dev);
+
+error_powerdown:
+ tmp007_powerdown(data);
+
+ return ret;
+}
+
+static int tmp007_remove(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct tmp007_data *data = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ tmp007_powerdown(data);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int tmp007_suspend(struct device *dev)
+{
+ struct tmp007_data *data = iio_priv(i2c_get_clientdata(
+ to_i2c_client(dev)));
+
+ return tmp007_powerdown(data);
+}
+
+static int tmp007_resume(struct device *dev)
+{
+ struct tmp007_data *data = iio_priv(i2c_get_clientdata(
+ to_i2c_client(dev)));
+
+ return i2c_smbus_write_word_swapped(data->client, TMP007_CONFIG,
+ data->config | TMP007_CONFIG_CONV_EN);
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(tmp007_pm_ops, tmp007_suspend, tmp007_resume);
+
+static const struct of_device_id tmp007_of_match[] = {
+ { .compatible = "ti,tmp007", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, tmp007_of_match);
+
+static const struct i2c_device_id tmp007_id[] = {
+ { "tmp007", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tmp007_id);
+
+static struct i2c_driver tmp007_driver = {
+ .driver = {
+ .name = "tmp007",
+ .of_match_table = of_match_ptr(tmp007_of_match),
+ .pm = &tmp007_pm_ops,
+ },
+ .probe = tmp007_probe,
+ .remove = tmp007_remove,
+ .id_table = tmp007_id,
+};
+module_i2c_driver(tmp007_driver);
+
+MODULE_AUTHOR("Manivannan Sadhasivam <manivannanece23@gmail.com>");
+MODULE_DESCRIPTION("TI TMP007 IR thermopile sensor driver");
+MODULE_LICENSE("GPL");
To compile this driver as a module, choose M here: the
module will be called iio-trig-interrupt.
+config IIO_STM32_TIMER_TRIGGER
+ tristate "STM32 Timer Trigger"
+ depends on (ARCH_STM32 && OF && MFD_STM32_TIMERS) || COMPILE_TEST
+ help
+ Select this option to enable STM32 Timer Trigger
+
+ To compile this driver as a module, choose M here: the
+ module will be called stm32-timer-trigger.
+
config IIO_TIGHTLOOP_TRIGGER
tristate "A kthread based hammering loop trigger"
depends on IIO_SW_TRIGGER
obj-$(CONFIG_IIO_HRTIMER_TRIGGER) += iio-trig-hrtimer.o
obj-$(CONFIG_IIO_INTERRUPT_TRIGGER) += iio-trig-interrupt.o
+obj-$(CONFIG_IIO_STM32_TIMER_TRIGGER) += stm32-timer-trigger.o
obj-$(CONFIG_IIO_SYSFS_TRIGGER) += iio-trig-sysfs.o
obj-$(CONFIG_IIO_TIGHTLOOP_TRIGGER) += iio-trig-loop.o
trig_info = kzalloc(sizeof(*trig_info), GFP_KERNEL);
if (!trig_info) {
ret = -ENOMEM;
- goto error_put_trigger;
+ goto error_free_trigger;
}
iio_trigger_set_drvdata(trig, trig_info);
trig_info->irq = irq;
free_irq(irq, trig);
error_free_trig_info:
kfree(trig_info);
-error_put_trigger:
- iio_trigger_put(trig);
+error_free_trigger:
+ iio_trigger_free(trig);
error_ret:
return ret;
}
iio_trigger_unregister(trig);
free_irq(trig_info->irq, trig);
kfree(trig_info);
- iio_trigger_put(trig);
+ iio_trigger_free(trig);
return 0;
}
return 0;
out2:
- iio_trigger_put(t->trig);
+ iio_trigger_free(t->trig);
free_t:
kfree(t);
out1:
--- /dev/null
+/*
+ * Copyright (C) STMicroelectronics 2016
+ *
+ * Author: Benjamin Gaignard <benjamin.gaignard@st.com>
+ *
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/timer/stm32-timer-trigger.h>
+#include <linux/iio/trigger.h>
+#include <linux/mfd/stm32-timers.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#define MAX_TRIGGERS 6
+
+/* List the triggers created by each timer */
+static const void *triggers_table[][MAX_TRIGGERS] = {
+ { TIM1_TRGO, TIM1_CH1, TIM1_CH2, TIM1_CH3, TIM1_CH4,},
+ { TIM2_TRGO, TIM2_CH1, TIM2_CH2, TIM2_CH3, TIM2_CH4,},
+ { TIM3_TRGO, TIM3_CH1, TIM3_CH2, TIM3_CH3, TIM3_CH4,},
+ { TIM4_TRGO, TIM4_CH1, TIM4_CH2, TIM4_CH3, TIM4_CH4,},
+ { TIM5_TRGO, TIM5_CH1, TIM5_CH2, TIM5_CH3, TIM5_CH4,},
+ { TIM6_TRGO,},
+ { TIM7_TRGO,},
+ { TIM8_TRGO, TIM8_CH1, TIM8_CH2, TIM8_CH3, TIM8_CH4,},
+ { TIM9_TRGO, TIM9_CH1, TIM9_CH2,},
+ { }, /* timer 10 */
+ { }, /* timer 11 */
+ { TIM12_TRGO, TIM12_CH1, TIM12_CH2,},
+};
+
+struct stm32_timer_trigger {
+ struct device *dev;
+ struct regmap *regmap;
+ struct clk *clk;
+ u32 max_arr;
+ const void *triggers;
+};
+
+static int stm32_timer_start(struct stm32_timer_trigger *priv,
+ unsigned int frequency)
+{
+ unsigned long long prd, div;
+ int prescaler = 0;
+ u32 ccer, cr1;
+
+ /* Period and prescaler values depends of clock rate */
+ div = (unsigned long long)clk_get_rate(priv->clk);
+
+ do_div(div, frequency);
+
+ prd = div;
+
+ /*
+ * Increase prescaler value until we get a result that fit
+ * with auto reload register maximum value.
+ */
+ while (div > priv->max_arr) {
+ prescaler++;
+ div = prd;
+ do_div(div, (prescaler + 1));
+ }
+ prd = div;
+
+ if (prescaler > MAX_TIM_PSC) {
+ dev_err(priv->dev, "prescaler exceeds the maximum value\n");
+ return -EINVAL;
+ }
+
+ /* Check if nobody else use the timer */
+ regmap_read(priv->regmap, TIM_CCER, &ccer);
+ if (ccer & TIM_CCER_CCXE)
+ return -EBUSY;
+
+ regmap_read(priv->regmap, TIM_CR1, &cr1);
+ if (!(cr1 & TIM_CR1_CEN))
+ clk_enable(priv->clk);
+
+ regmap_write(priv->regmap, TIM_PSC, prescaler);
+ regmap_write(priv->regmap, TIM_ARR, prd - 1);
+ regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, TIM_CR1_ARPE);
+
+ /* Force master mode to update mode */
+ regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS, 0x20);
+
+ /* Make sure that registers are updated */
+ regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG);
+
+ /* Enable controller */
+ regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, TIM_CR1_CEN);
+
+ return 0;
+}
+
+static void stm32_timer_stop(struct stm32_timer_trigger *priv)
+{
+ u32 ccer, cr1;
+
+ regmap_read(priv->regmap, TIM_CCER, &ccer);
+ if (ccer & TIM_CCER_CCXE)
+ return;
+
+ regmap_read(priv->regmap, TIM_CR1, &cr1);
+ if (cr1 & TIM_CR1_CEN)
+ clk_disable(priv->clk);
+
+ /* Stop timer */
+ regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0);
+ regmap_write(priv->regmap, TIM_PSC, 0);
+ regmap_write(priv->regmap, TIM_ARR, 0);
+
+ /* Make sure that registers are updated */
+ regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG);
+}
+
+static ssize_t stm32_tt_store_frequency(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct iio_trigger *trig = to_iio_trigger(dev);
+ struct stm32_timer_trigger *priv = iio_trigger_get_drvdata(trig);
+ unsigned int freq;
+ int ret;
+
+ ret = kstrtouint(buf, 10, &freq);
+ if (ret)
+ return ret;
+
+ if (freq == 0) {
+ stm32_timer_stop(priv);
+ } else {
+ ret = stm32_timer_start(priv, freq);
+ if (ret)
+ return ret;
+ }
+
+ return len;
+}
+
+static ssize_t stm32_tt_read_frequency(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct iio_trigger *trig = to_iio_trigger(dev);
+ struct stm32_timer_trigger *priv = iio_trigger_get_drvdata(trig);
+ u32 psc, arr, cr1;
+ unsigned long long freq = 0;
+
+ regmap_read(priv->regmap, TIM_CR1, &cr1);
+ regmap_read(priv->regmap, TIM_PSC, &psc);
+ regmap_read(priv->regmap, TIM_ARR, &arr);
+
+ if (psc && arr && (cr1 & TIM_CR1_CEN)) {
+ freq = (unsigned long long)clk_get_rate(priv->clk);
+ do_div(freq, psc);
+ do_div(freq, arr);
+ }
+
+ return sprintf(buf, "%d\n", (unsigned int)freq);
+}
+
+static IIO_DEV_ATTR_SAMP_FREQ(0660,
+ stm32_tt_read_frequency,
+ stm32_tt_store_frequency);
+
+static char *master_mode_table[] = {
+ "reset",
+ "enable",
+ "update",
+ "compare_pulse",
+ "OC1REF",
+ "OC2REF",
+ "OC3REF",
+ "OC4REF"
+};
+
+static ssize_t stm32_tt_show_master_mode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct stm32_timer_trigger *priv = iio_priv(indio_dev);
+ u32 cr2;
+
+ regmap_read(priv->regmap, TIM_CR2, &cr2);
+ cr2 = (cr2 & TIM_CR2_MMS) >> TIM_CR2_MMS_SHIFT;
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", master_mode_table[cr2]);
+}
+
+static ssize_t stm32_tt_store_master_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct stm32_timer_trigger *priv = iio_priv(indio_dev);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(master_mode_table); i++) {
+ if (!strncmp(master_mode_table[i], buf,
+ strlen(master_mode_table[i]))) {
+ regmap_update_bits(priv->regmap, TIM_CR2,
+ TIM_CR2_MMS, i << TIM_CR2_MMS_SHIFT);
+ /* Make sure that registers are updated */
+ regmap_update_bits(priv->regmap, TIM_EGR,
+ TIM_EGR_UG, TIM_EGR_UG);
+ return len;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static IIO_CONST_ATTR(master_mode_available,
+ "reset enable update compare_pulse OC1REF OC2REF OC3REF OC4REF");
+
+static IIO_DEVICE_ATTR(master_mode, 0660,
+ stm32_tt_show_master_mode,
+ stm32_tt_store_master_mode,
+ 0);
+
+static struct attribute *stm32_trigger_attrs[] = {
+ &iio_dev_attr_sampling_frequency.dev_attr.attr,
+ &iio_dev_attr_master_mode.dev_attr.attr,
+ &iio_const_attr_master_mode_available.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group stm32_trigger_attr_group = {
+ .attrs = stm32_trigger_attrs,
+};
+
+static const struct attribute_group *stm32_trigger_attr_groups[] = {
+ &stm32_trigger_attr_group,
+ NULL,
+};
+
+static const struct iio_trigger_ops timer_trigger_ops = {
+ .owner = THIS_MODULE,
+};
+
+static int stm32_setup_iio_triggers(struct stm32_timer_trigger *priv)
+{
+ int ret;
+ const char * const *cur = priv->triggers;
+
+ while (cur && *cur) {
+ struct iio_trigger *trig;
+
+ trig = devm_iio_trigger_alloc(priv->dev, "%s", *cur);
+ if (!trig)
+ return -ENOMEM;
+
+ trig->dev.parent = priv->dev->parent;
+ trig->ops = &timer_trigger_ops;
+
+ /*
+ * sampling frequency and master mode attributes
+ * should only be available on trgo trigger which
+ * is always the first in the list.
+ */
+ if (cur == priv->triggers)
+ trig->dev.groups = stm32_trigger_attr_groups;
+
+ iio_trigger_set_drvdata(trig, priv);
+
+ ret = devm_iio_trigger_register(priv->dev, trig);
+ if (ret)
+ return ret;
+ cur++;
+ }
+
+ return 0;
+}
+
+/**
+ * is_stm32_timer_trigger
+ * @trig: trigger to be checked
+ *
+ * return true if the trigger is a valid stm32 iio timer trigger
+ * either return false
+ */
+bool is_stm32_timer_trigger(struct iio_trigger *trig)
+{
+ return (trig->ops == &timer_trigger_ops);
+}
+EXPORT_SYMBOL(is_stm32_timer_trigger);
+
+static int stm32_timer_trigger_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct stm32_timer_trigger *priv;
+ struct stm32_timers *ddata = dev_get_drvdata(pdev->dev.parent);
+ unsigned int index;
+ int ret;
+
+ if (of_property_read_u32(dev->of_node, "reg", &index))
+ return -EINVAL;
+
+ if (index >= ARRAY_SIZE(triggers_table))
+ return -EINVAL;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = dev;
+ priv->regmap = ddata->regmap;
+ priv->clk = ddata->clk;
+ priv->max_arr = ddata->max_arr;
+ priv->triggers = triggers_table[index];
+
+ ret = stm32_setup_iio_triggers(priv);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, priv);
+
+ return 0;
+}
+
+static const struct of_device_id stm32_trig_of_match[] = {
+ { .compatible = "st,stm32-timer-trigger", },
+ { /* end node */ },
+};
+MODULE_DEVICE_TABLE(of, stm32_trig_of_match);
+
+static struct platform_driver stm32_timer_trigger_driver = {
+ .probe = stm32_timer_trigger_probe,
+ .driver = {
+ .name = "stm32-timer-trigger",
+ .of_match_table = stm32_trig_of_match,
+ },
+};
+module_platform_driver(stm32_timer_trigger_driver);
+
+MODULE_ALIAS("platform: stm32-timer-trigger");
+MODULE_DESCRIPTION("STMicroelectronics STM32 Timer Trigger driver");
+MODULE_LICENSE("GPL v2");
if (!src_addr || !src_addr->sa_family) {
src_addr = (struct sockaddr *) &id->route.addr.src_addr;
src_addr->sa_family = dst_addr->sa_family;
- if (dst_addr->sa_family == AF_INET6) {
+ if (IS_ENABLED(CONFIG_IPV6) &&
+ dst_addr->sa_family == AF_INET6) {
struct sockaddr_in6 *src_addr6 = (struct sockaddr_in6 *) src_addr;
struct sockaddr_in6 *dst_addr6 = (struct sockaddr_in6 *) dst_addr;
src_addr6->sin6_scope_id = dst_addr6->sin6_scope_id;
IB_ACCESS_REMOTE_ATOMIC | IB_ACCESS_MW_BIND));
if (access & IB_ACCESS_ON_DEMAND) {
+ put_pid(umem->pid);
ret = ib_umem_odp_get(context, umem);
if (ret) {
kfree(umem);
page_list = (struct page **) __get_free_page(GFP_KERNEL);
if (!page_list) {
+ put_pid(umem->pid);
kfree(umem);
return ERR_PTR(-ENOMEM);
}
memset(props, 0, sizeof(struct ib_port_attr));
props->max_mtu = IB_MTU_4096;
- if (netdev->mtu >= 4096)
- props->active_mtu = IB_MTU_4096;
- else if (netdev->mtu >= 2048)
- props->active_mtu = IB_MTU_2048;
- else if (netdev->mtu >= 1024)
- props->active_mtu = IB_MTU_1024;
- else if (netdev->mtu >= 512)
- props->active_mtu = IB_MTU_512;
- else
- props->active_mtu = IB_MTU_256;
+ props->active_mtu = ib_mtu_int_to_enum(netdev->mtu);
if (!netif_carrier_ok(netdev))
props->state = IB_PORT_DOWN;
skb_trim(skb, dlen);
mutex_lock(&ep->com.mutex);
- /* update RX credits */
- update_rx_credits(ep, dlen);
-
switch (ep->com.state) {
case MPA_REQ_SENT:
+ update_rx_credits(ep, dlen);
ep->rcv_seq += dlen;
disconnect = process_mpa_reply(ep, skb);
break;
case MPA_REQ_WAIT:
+ update_rx_credits(ep, dlen);
ep->rcv_seq += dlen;
disconnect = process_mpa_request(ep, skb);
break;
case FPDU_MODE: {
struct c4iw_qp_attributes attrs;
+
+ update_rx_credits(ep, dlen);
BUG_ON(!ep->com.qp);
if (status)
pr_err("%s Unexpected streaming data." \
goto skip_cqe;
}
+ /*
+ * Special cqe for drain WR completions...
+ */
+ if (CQE_OPCODE(hw_cqe) == C4IW_DRAIN_OPCODE) {
+ *cookie = CQE_DRAIN_COOKIE(hw_cqe);
+ *cqe = *hw_cqe;
+ goto skip_cqe;
+ }
+
/*
* Gotta tweak READ completions:
* 1) the cqe doesn't contain the sq_wptr from the wr.
c4iw_invalidate_mr(qhp->rhp,
CQE_WRID_FR_STAG(&cqe));
break;
+ case C4IW_DRAIN_OPCODE:
+ wc->opcode = IB_WC_SEND;
+ break;
default:
printk(KERN_ERR MOD "Unexpected opcode %d "
"in the CQE received for QPID=0x%0x\n",
}
}
out:
- if (wq) {
- if (unlikely(qhp->attr.state != C4IW_QP_STATE_RTS)) {
- if (t4_sq_empty(wq))
- complete(&qhp->sq_drained);
- if (t4_rq_empty(wq))
- complete(&qhp->rq_drained);
- }
+ if (wq)
spin_unlock(&qhp->lock);
- }
return ret;
}
}
}
+ rdev->free_workq = create_singlethread_workqueue("iw_cxgb4_free");
+ if (!rdev->free_workq) {
+ err = -ENOMEM;
+ goto err_free_status_page;
+ }
+
rdev->status_page->db_off = 0;
return 0;
+err_free_status_page:
+ free_page((unsigned long)rdev->status_page);
destroy_ocqp_pool:
c4iw_ocqp_pool_destroy(rdev);
destroy_rqtpool:
static void c4iw_rdev_close(struct c4iw_rdev *rdev)
{
+ destroy_workqueue(rdev->free_workq);
kfree(rdev->wr_log);
free_page((unsigned long)rdev->status_page);
c4iw_pblpool_destroy(rdev);
#include <linux/kref.h>
#include <linux/timer.h>
#include <linux/io.h>
+#include <linux/workqueue.h>
#include <asm/byteorder.h>
struct list_head qpids;
struct list_head cqids;
struct mutex lock;
+ struct kref kref;
};
enum c4iw_rdev_flags {
atomic_t wr_log_idx;
struct wr_log_entry *wr_log;
int wr_log_size;
+ struct workqueue_struct *free_workq;
};
static inline int c4iw_fatal_error(struct c4iw_rdev *rdev)
wait_queue_head_t wait;
struct timer_list timer;
int sq_sig_all;
- struct completion rq_drained;
- struct completion sq_drained;
+ struct work_struct free_work;
+ struct c4iw_ucontext *ucontext;
};
static inline struct c4iw_qp *to_c4iw_qp(struct ib_qp *ibqp)
u32 key;
spinlock_t mmap_lock;
struct list_head mmaps;
+ struct kref kref;
};
static inline struct c4iw_ucontext *to_c4iw_ucontext(struct ib_ucontext *c)
return container_of(c, struct c4iw_ucontext, ibucontext);
}
+void _c4iw_free_ucontext(struct kref *kref);
+
+static inline void c4iw_put_ucontext(struct c4iw_ucontext *ucontext)
+{
+ kref_put(&ucontext->kref, _c4iw_free_ucontext);
+}
+
+static inline void c4iw_get_ucontext(struct c4iw_ucontext *ucontext)
+{
+ kref_get(&ucontext->kref);
+}
+
struct c4iw_mm_entry {
struct list_head entry;
u64 addr;
return IB_QPS_ERR;
}
+#define C4IW_DRAIN_OPCODE FW_RI_SGE_EC_CR_RETURN
+
static inline u32 c4iw_ib_to_tpt_access(int a)
{
return (a & IB_ACCESS_REMOTE_WRITE ? FW_RI_MEM_ACCESS_REM_WRITE : 0) |
extern int db_fc_threshold;
extern int db_coalescing_threshold;
extern int use_dsgl;
-void c4iw_drain_rq(struct ib_qp *qp);
-void c4iw_drain_sq(struct ib_qp *qp);
void c4iw_invalidate_mr(struct c4iw_dev *rhp, u32 rkey);
#endif
return -ENOSYS;
}
-static int c4iw_dealloc_ucontext(struct ib_ucontext *context)
+void _c4iw_free_ucontext(struct kref *kref)
{
- struct c4iw_dev *rhp = to_c4iw_dev(context->device);
- struct c4iw_ucontext *ucontext = to_c4iw_ucontext(context);
+ struct c4iw_ucontext *ucontext;
+ struct c4iw_dev *rhp;
struct c4iw_mm_entry *mm, *tmp;
- PDBG("%s context %p\n", __func__, context);
+ ucontext = container_of(kref, struct c4iw_ucontext, kref);
+ rhp = to_c4iw_dev(ucontext->ibucontext.device);
+
+ PDBG("%s ucontext %p\n", __func__, ucontext);
list_for_each_entry_safe(mm, tmp, &ucontext->mmaps, entry)
kfree(mm);
c4iw_release_dev_ucontext(&rhp->rdev, &ucontext->uctx);
kfree(ucontext);
+}
+
+static int c4iw_dealloc_ucontext(struct ib_ucontext *context)
+{
+ struct c4iw_ucontext *ucontext = to_c4iw_ucontext(context);
+
+ PDBG("%s context %p\n", __func__, context);
+ c4iw_put_ucontext(ucontext);
return 0;
}
c4iw_init_dev_ucontext(&rhp->rdev, &context->uctx);
INIT_LIST_HEAD(&context->mmaps);
spin_lock_init(&context->mmap_lock);
+ kref_init(&context->kref);
if (udata->outlen < sizeof(uresp) - sizeof(uresp.reserved)) {
if (!warned++)
memset(props, 0, sizeof(struct ib_port_attr));
props->max_mtu = IB_MTU_4096;
- if (netdev->mtu >= 4096)
- props->active_mtu = IB_MTU_4096;
- else if (netdev->mtu >= 2048)
- props->active_mtu = IB_MTU_2048;
- else if (netdev->mtu >= 1024)
- props->active_mtu = IB_MTU_1024;
- else if (netdev->mtu >= 512)
- props->active_mtu = IB_MTU_512;
- else
- props->active_mtu = IB_MTU_256;
+ props->active_mtu = ib_mtu_int_to_enum(netdev->mtu);
if (!netif_carrier_ok(netdev))
props->state = IB_PORT_DOWN;
dev->ibdev.uverbs_abi_ver = C4IW_UVERBS_ABI_VERSION;
dev->ibdev.get_port_immutable = c4iw_port_immutable;
dev->ibdev.get_dev_fw_str = get_dev_fw_str;
- dev->ibdev.drain_sq = c4iw_drain_sq;
- dev->ibdev.drain_rq = c4iw_drain_rq;
dev->ibdev.iwcm = kmalloc(sizeof(struct iw_cm_verbs), GFP_KERNEL);
if (!dev->ibdev.iwcm)
return 0;
}
-static void _free_qp(struct kref *kref)
+static void free_qp_work(struct work_struct *work)
+{
+ struct c4iw_ucontext *ucontext;
+ struct c4iw_qp *qhp;
+ struct c4iw_dev *rhp;
+
+ qhp = container_of(work, struct c4iw_qp, free_work);
+ ucontext = qhp->ucontext;
+ rhp = qhp->rhp;
+
+ PDBG("%s qhp %p ucontext %p\n", __func__, qhp, ucontext);
+ destroy_qp(&rhp->rdev, &qhp->wq,
+ ucontext ? &ucontext->uctx : &rhp->rdev.uctx);
+
+ if (ucontext)
+ c4iw_put_ucontext(ucontext);
+ kfree(qhp);
+}
+
+static void queue_qp_free(struct kref *kref)
{
struct c4iw_qp *qhp;
qhp = container_of(kref, struct c4iw_qp, kref);
PDBG("%s qhp %p\n", __func__, qhp);
- kfree(qhp);
+ queue_work(qhp->rhp->rdev.free_workq, &qhp->free_work);
}
void c4iw_qp_add_ref(struct ib_qp *qp)
void c4iw_qp_rem_ref(struct ib_qp *qp)
{
PDBG("%s ib_qp %p\n", __func__, qp);
- kref_put(&to_c4iw_qp(qp)->kref, _free_qp);
+ kref_put(&to_c4iw_qp(qp)->kref, queue_qp_free);
}
static void add_to_fc_list(struct list_head *head, struct list_head *entry)
return 0;
}
+static void complete_sq_drain_wr(struct c4iw_qp *qhp, struct ib_send_wr *wr)
+{
+ struct t4_cqe cqe = {};
+ struct c4iw_cq *schp;
+ unsigned long flag;
+ struct t4_cq *cq;
+
+ schp = to_c4iw_cq(qhp->ibqp.send_cq);
+ cq = &schp->cq;
+
+ cqe.u.drain_cookie = wr->wr_id;
+ cqe.header = cpu_to_be32(CQE_STATUS_V(T4_ERR_SWFLUSH) |
+ CQE_OPCODE_V(C4IW_DRAIN_OPCODE) |
+ CQE_TYPE_V(1) |
+ CQE_SWCQE_V(1) |
+ CQE_QPID_V(qhp->wq.sq.qid));
+
+ spin_lock_irqsave(&schp->lock, flag);
+ cqe.bits_type_ts = cpu_to_be64(CQE_GENBIT_V((u64)cq->gen));
+ cq->sw_queue[cq->sw_pidx] = cqe;
+ t4_swcq_produce(cq);
+ spin_unlock_irqrestore(&schp->lock, flag);
+
+ spin_lock_irqsave(&schp->comp_handler_lock, flag);
+ (*schp->ibcq.comp_handler)(&schp->ibcq,
+ schp->ibcq.cq_context);
+ spin_unlock_irqrestore(&schp->comp_handler_lock, flag);
+}
+
+static void complete_rq_drain_wr(struct c4iw_qp *qhp, struct ib_recv_wr *wr)
+{
+ struct t4_cqe cqe = {};
+ struct c4iw_cq *rchp;
+ unsigned long flag;
+ struct t4_cq *cq;
+
+ rchp = to_c4iw_cq(qhp->ibqp.recv_cq);
+ cq = &rchp->cq;
+
+ cqe.u.drain_cookie = wr->wr_id;
+ cqe.header = cpu_to_be32(CQE_STATUS_V(T4_ERR_SWFLUSH) |
+ CQE_OPCODE_V(C4IW_DRAIN_OPCODE) |
+ CQE_TYPE_V(0) |
+ CQE_SWCQE_V(1) |
+ CQE_QPID_V(qhp->wq.sq.qid));
+
+ spin_lock_irqsave(&rchp->lock, flag);
+ cqe.bits_type_ts = cpu_to_be64(CQE_GENBIT_V((u64)cq->gen));
+ cq->sw_queue[cq->sw_pidx] = cqe;
+ t4_swcq_produce(cq);
+ spin_unlock_irqrestore(&rchp->lock, flag);
+
+ spin_lock_irqsave(&rchp->comp_handler_lock, flag);
+ (*rchp->ibcq.comp_handler)(&rchp->ibcq,
+ rchp->ibcq.cq_context);
+ spin_unlock_irqrestore(&rchp->comp_handler_lock, flag);
+}
+
int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
struct ib_send_wr **bad_wr)
{
spin_lock_irqsave(&qhp->lock, flag);
if (t4_wq_in_error(&qhp->wq)) {
spin_unlock_irqrestore(&qhp->lock, flag);
- *bad_wr = wr;
- return -EINVAL;
+ complete_sq_drain_wr(qhp, wr);
+ return err;
}
num_wrs = t4_sq_avail(&qhp->wq);
if (num_wrs == 0) {
spin_lock_irqsave(&qhp->lock, flag);
if (t4_wq_in_error(&qhp->wq)) {
spin_unlock_irqrestore(&qhp->lock, flag);
- *bad_wr = wr;
- return -EINVAL;
+ complete_rq_drain_wr(qhp, wr);
+ return err;
}
num_wrs = t4_rq_avail(&qhp->wq);
if (num_wrs == 0) {
}
break;
case C4IW_QP_STATE_CLOSING:
- if (!internal) {
+
+ /*
+ * Allow kernel users to move to ERROR for qp draining.
+ */
+ if (!internal && (qhp->ibqp.uobject || attrs->next_state !=
+ C4IW_QP_STATE_ERROR)) {
ret = -EINVAL;
goto out;
}
struct c4iw_dev *rhp;
struct c4iw_qp *qhp;
struct c4iw_qp_attributes attrs;
- struct c4iw_ucontext *ucontext;
qhp = to_c4iw_qp(ib_qp);
rhp = qhp->rhp;
spin_unlock_irq(&rhp->lock);
free_ird(rhp, qhp->attr.max_ird);
- ucontext = ib_qp->uobject ?
- to_c4iw_ucontext(ib_qp->uobject->context) : NULL;
- destroy_qp(&rhp->rdev, &qhp->wq,
- ucontext ? &ucontext->uctx : &rhp->rdev.uctx);
-
c4iw_qp_rem_ref(ib_qp);
PDBG("%s ib_qp %p qpid 0x%0x\n", __func__, ib_qp, qhp->wq.sq.qid);
qhp->attr.max_ird = 0;
qhp->sq_sig_all = attrs->sq_sig_type == IB_SIGNAL_ALL_WR;
spin_lock_init(&qhp->lock);
- init_completion(&qhp->sq_drained);
- init_completion(&qhp->rq_drained);
mutex_init(&qhp->mutex);
init_waitqueue_head(&qhp->wait);
kref_init(&qhp->kref);
+ INIT_WORK(&qhp->free_work, free_qp_work);
ret = insert_handle(rhp, &rhp->qpidr, qhp, qhp->wq.sq.qid);
if (ret)
ma_sync_key_mm->len = PAGE_SIZE;
insert_mmap(ucontext, ma_sync_key_mm);
}
+
+ c4iw_get_ucontext(ucontext);
+ qhp->ucontext = ucontext;
}
qhp->ibqp.qp_num = qhp->wq.sq.qid;
init_timer(&(qhp->timer));
init_attr->sq_sig_type = qhp->sq_sig_all ? IB_SIGNAL_ALL_WR : 0;
return 0;
}
-
-static void move_qp_to_err(struct c4iw_qp *qp)
-{
- struct c4iw_qp_attributes attrs = { .next_state = C4IW_QP_STATE_ERROR };
-
- (void)c4iw_modify_qp(qp->rhp, qp, C4IW_QP_ATTR_NEXT_STATE, &attrs, 1);
-}
-
-void c4iw_drain_sq(struct ib_qp *ibqp)
-{
- struct c4iw_qp *qp = to_c4iw_qp(ibqp);
- unsigned long flag;
- bool need_to_wait;
-
- move_qp_to_err(qp);
- spin_lock_irqsave(&qp->lock, flag);
- need_to_wait = !t4_sq_empty(&qp->wq);
- spin_unlock_irqrestore(&qp->lock, flag);
-
- if (need_to_wait)
- wait_for_completion(&qp->sq_drained);
-}
-
-void c4iw_drain_rq(struct ib_qp *ibqp)
-{
- struct c4iw_qp *qp = to_c4iw_qp(ibqp);
- unsigned long flag;
- bool need_to_wait;
-
- move_qp_to_err(qp);
- spin_lock_irqsave(&qp->lock, flag);
- need_to_wait = !t4_rq_empty(&qp->wq);
- spin_unlock_irqrestore(&qp->lock, flag);
-
- if (need_to_wait)
- wait_for_completion(&qp->rq_drained);
-}
__be32 wrid_hi;
__be32 wrid_low;
} gen;
+ u64 drain_cookie;
} u;
__be64 reserved;
__be64 bits_type_ts;
/* generic accessor macros */
#define CQE_WRID_HI(x) (be32_to_cpu((x)->u.gen.wrid_hi))
#define CQE_WRID_LOW(x) (be32_to_cpu((x)->u.gen.wrid_low))
+#define CQE_DRAIN_COOKIE(x) ((x)->u.drain_cookie)
/* macros for flit 3 of the cqe */
#define CQE_GENBIT_S 63
memset(props, 0, sizeof(*props));
props->max_mtu = IB_MTU_4096;
- if (netdev->mtu >= 4096)
- props->active_mtu = IB_MTU_4096;
- else if (netdev->mtu >= 2048)
- props->active_mtu = IB_MTU_2048;
- else if (netdev->mtu >= 1024)
- props->active_mtu = IB_MTU_1024;
- else if (netdev->mtu >= 512)
- props->active_mtu = IB_MTU_512;
- else
- props->active_mtu = IB_MTU_256;
+ props->active_mtu = ib_mtu_int_to_enum(netdev->mtu);
props->lid = 1;
if (netif_carrier_ok(iwdev->netdev))
memset(props, 0, sizeof(*props));
props->max_mtu = IB_MTU_4096;
-
- if (netdev->mtu >= 4096)
- props->active_mtu = IB_MTU_4096;
- else if (netdev->mtu >= 2048)
- props->active_mtu = IB_MTU_2048;
- else if (netdev->mtu >= 1024)
- props->active_mtu = IB_MTU_1024;
- else if (netdev->mtu >= 512)
- props->active_mtu = IB_MTU_512;
- else
- props->active_mtu = IB_MTU_256;
+ props->active_mtu = ib_mtu_int_to_enum(netdev->mtu);
props->lid = 1;
props->lmc = 0;
return 0;
}
-void qedr_unaffiliated_event(void *context,
- u8 event_code)
+void qedr_unaffiliated_event(void *context, u8 event_code)
{
pr_err("unaffiliated event not implemented yet\n");
}
if (device_create_file(&dev->ibdev.dev, qedr_attributes[i]))
goto sysfs_err;
+ if (!test_and_set_bit(QEDR_ENET_STATE_BIT, &dev->enet_state))
+ qedr_ib_dispatch_event(dev, QEDR_PORT, IB_EVENT_PORT_ACTIVE);
+
DP_DEBUG(dev, QEDR_MSG_INIT, "qedr driver loaded successfully\n");
return dev;
ib_dealloc_device(&dev->ibdev);
}
-static int qedr_close(struct qedr_dev *dev)
+static void qedr_close(struct qedr_dev *dev)
{
- qedr_ib_dispatch_event(dev, 1, IB_EVENT_PORT_ERR);
-
- return 0;
+ if (test_and_clear_bit(QEDR_ENET_STATE_BIT, &dev->enet_state))
+ qedr_ib_dispatch_event(dev, QEDR_PORT, IB_EVENT_PORT_ERR);
}
static void qedr_shutdown(struct qedr_dev *dev)
qedr_remove(dev);
}
+static void qedr_open(struct qedr_dev *dev)
+{
+ if (!test_and_set_bit(QEDR_ENET_STATE_BIT, &dev->enet_state))
+ qedr_ib_dispatch_event(dev, QEDR_PORT, IB_EVENT_PORT_ACTIVE);
+}
+
static void qedr_mac_address_change(struct qedr_dev *dev)
{
union ib_gid *sgid = &dev->sgid_tbl[0];
ether_addr_copy(dev->gsi_ll2_mac_address, dev->ndev->dev_addr);
- qedr_ib_dispatch_event(dev, 1, IB_EVENT_GID_CHANGE);
+ qedr_ib_dispatch_event(dev, QEDR_PORT, IB_EVENT_GID_CHANGE);
if (rc)
DP_ERR(dev, "Error updating mac filter\n");
{
switch (event) {
case QEDE_UP:
- qedr_ib_dispatch_event(dev, 1, IB_EVENT_PORT_ACTIVE);
+ qedr_open(dev);
break;
case QEDE_DOWN:
qedr_close(dev);
struct qed_rdma_events events;
};
+#define QEDR_ENET_STATE_BIT (0)
+
struct qedr_dev {
struct ib_device ibdev;
struct qed_dev *cdev;
struct qedr_cq *gsi_sqcq;
struct qedr_cq *gsi_rqcq;
struct qedr_qp *gsi_qp;
+
+ unsigned long enet_state;
};
#define QEDR_MAX_SQ_PBL (0x8000)
#define QEDR_ROCE_MAX_CNQ_SIZE (0x4000)
#define QEDR_MAX_PORT (1)
+#define QEDR_PORT (1)
#define QEDR_UVERBS(CMD_NAME) (1ull << IB_USER_VERBS_CMD_##CMD_NAME)
u16 icid;
- /* Lock to protect completion handler */
- spinlock_t comp_handler_lock;
-
/* Lock to protect multiplem CQ's */
spinlock_t cq_lock;
u8 arm_flags;
qedr_inc_sw_gsi_cons(&qp->sq);
spin_unlock_irqrestore(&qp->q_lock, flags);
- if (cq->ibcq.comp_handler) {
- spin_lock_irqsave(&cq->comp_handler_lock, flags);
+ if (cq->ibcq.comp_handler)
(*cq->ibcq.comp_handler) (&cq->ibcq, cq->ibcq.cq_context);
- spin_unlock_irqrestore(&cq->comp_handler_lock, flags);
- }
}
void qedr_ll2_rx_cb(void *_dev, struct qed_roce_ll2_packet *pkt,
spin_unlock_irqrestore(&qp->q_lock, flags);
- if (cq->ibcq.comp_handler) {
- spin_lock_irqsave(&cq->comp_handler_lock, flags);
+ if (cq->ibcq.comp_handler)
(*cq->ibcq.comp_handler) (&cq->ibcq, cq->ibcq.cq_context);
- spin_unlock_irqrestore(&cq->comp_handler_lock, flags);
- }
}
static void qedr_destroy_gsi_cq(struct qedr_dev *dev,
}
if (ether_addr_equal(udh.eth.smac_h, udh.eth.dmac_h))
- packet->tx_dest = QED_ROCE_LL2_TX_DEST_NW;
- else
packet->tx_dest = QED_ROCE_LL2_TX_DEST_LB;
+ else
+ packet->tx_dest = QED_ROCE_LL2_TX_DEST_NW;
packet->roce_mode = roce_mode;
memcpy(packet->header.vaddr, ud_header_buffer, header_size);
struct ib_ucontext *context, struct ib_udata *udata)
{
struct qedr_dev *dev = get_qedr_dev(ibdev);
- struct qedr_ucontext *uctx = NULL;
- struct qedr_alloc_pd_uresp uresp;
struct qedr_pd *pd;
u16 pd_id;
int rc;
if (!pd)
return ERR_PTR(-ENOMEM);
- dev->ops->rdma_alloc_pd(dev->rdma_ctx, &pd_id);
+ rc = dev->ops->rdma_alloc_pd(dev->rdma_ctx, &pd_id);
+ if (rc)
+ goto err;
- uresp.pd_id = pd_id;
pd->pd_id = pd_id;
if (udata && context) {
+ struct qedr_alloc_pd_uresp uresp;
+
+ uresp.pd_id = pd_id;
+
rc = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
- if (rc)
+ if (rc) {
DP_ERR(dev, "copy error pd_id=0x%x.\n", pd_id);
- uctx = get_qedr_ucontext(context);
- uctx->pd = pd;
- pd->uctx = uctx;
+ dev->ops->rdma_dealloc_pd(dev->rdma_ctx, pd_id);
+ goto err;
+ }
+
+ pd->uctx = get_qedr_ucontext(context);
+ pd->uctx->pd = pd;
}
return &pd->ibpd;
+
+err:
+ kfree(pd);
+ return ERR_PTR(rc);
}
int qedr_dealloc_pd(struct ib_pd *ibpd)
return ERR_PTR(-EFAULT);
}
-enum ib_qp_state qedr_get_ibqp_state(enum qed_roce_qp_state qp_state)
+static enum ib_qp_state qedr_get_ibqp_state(enum qed_roce_qp_state qp_state)
{
switch (qp_state) {
case QED_ROCE_QP_STATE_RESET:
return IB_QPS_ERR;
}
-enum qed_roce_qp_state qedr_get_state_from_ibqp(enum ib_qp_state qp_state)
+static enum qed_roce_qp_state qedr_get_state_from_ibqp(
+ enum ib_qp_state qp_state)
{
switch (qp_state) {
case IB_QPS_RESET:
int status = 0;
if (new_state == qp->state)
- return 1;
+ return 0;
switch (qp->state) {
case QED_ROCE_QP_STATE_RESET:
/* ERR->XXX */
switch (new_state) {
case QED_ROCE_QP_STATE_RESET:
+ if ((qp->rq.prod != qp->rq.cons) ||
+ (qp->sq.prod != qp->sq.cons)) {
+ DP_NOTICE(dev,
+ "Error->Reset with rq/sq not empty rq.prod=%x rq.cons=%x sq.prod=%x sq.cons=%x\n",
+ qp->rq.prod, qp->rq.cons, qp->sq.prod,
+ qp->sq.cons);
+ status = -EINVAL;
+ }
break;
default:
status = -EINVAL;
qp_params.sgid.dwords[2], qp_params.sgid.dwords[3]);
DP_DEBUG(dev, QEDR_MSG_QP, "remote_mac=[%pM]\n",
qp_params.remote_mac_addr);
-;
qp_params.mtu = qp->mtu;
qp_params.lb_indication = false;
qp_attr->qp_state = qedr_get_ibqp_state(params.state);
qp_attr->cur_qp_state = qedr_get_ibqp_state(params.state);
- qp_attr->path_mtu = iboe_get_mtu(params.mtu);
+ qp_attr->path_mtu = ib_mtu_int_to_enum(params.mtu);
qp_attr->path_mig_state = IB_MIG_MIGRATED;
qp_attr->rq_psn = params.rq_psn;
qp_attr->sq_psn = params.sq_psn;
qp_attr->cap.max_recv_wr = qp->rq.max_wr;
qp_attr->cap.max_send_sge = qp->sq.max_sges;
qp_attr->cap.max_recv_sge = qp->rq.max_sges;
- qp_attr->cap.max_inline_data = qp->max_inline_data;
+ qp_attr->cap.max_inline_data = ROCE_REQ_MAX_INLINE_DATA_SIZE;
qp_init_attr->cap = qp_attr->cap;
memcpy(&qp_attr->ah_attr.grh.dgid.raw[0], ¶ms.dgid.bytes[0],
return rc;
}
-struct qedr_mr *__qedr_alloc_mr(struct ib_pd *ibpd, int max_page_list_len)
+static struct qedr_mr *__qedr_alloc_mr(struct ib_pd *ibpd,
+ int max_page_list_len)
{
struct qedr_pd *pd = get_qedr_pd(ibpd);
struct qedr_dev *dev = get_qedr_dev(ibpd->device);
return 0;
}
-enum ib_wc_opcode qedr_ib_to_wc_opcode(enum ib_wr_opcode opcode)
+static enum ib_wc_opcode qedr_ib_to_wc_opcode(enum ib_wr_opcode opcode)
{
switch (opcode) {
case IB_WR_RDMA_WRITE:
}
}
-inline bool qedr_can_post_send(struct qedr_qp *qp, struct ib_send_wr *wr)
+static inline bool qedr_can_post_send(struct qedr_qp *qp, struct ib_send_wr *wr)
{
int wq_is_full, err_wr, pbl_is_full;
struct qedr_dev *dev = qp->dev;
return true;
}
-int __qedr_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
+static int __qedr_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
struct ib_send_wr **bad_wr)
{
struct qedr_dev *dev = get_qedr_dev(ibqp->device);
IB_WC_SUCCESS, 0);
break;
case RDMA_CQE_REQ_STS_WORK_REQUEST_FLUSHED_ERR:
- DP_ERR(dev,
- "Error: POLL CQ with RDMA_CQE_REQ_STS_WORK_REQUEST_FLUSHED_ERR. CQ icid=0x%x, QP icid=0x%x\n",
- cq->icid, qp->icid);
+ if (qp->state != QED_ROCE_QP_STATE_ERR)
+ DP_ERR(dev,
+ "Error: POLL CQ with RDMA_CQE_REQ_STS_WORK_REQUEST_FLUSHED_ERR. CQ icid=0x%x, QP icid=0x%x\n",
+ cq->icid, qp->icid);
cnt = process_req(dev, qp, cq, num_entries, wc, req->sq_cons,
IB_WC_WR_FLUSH_ERR, 1);
break;
if (ret) {
dev_err(&pdev->dev, "failed to allocate interrupts\n");
ret = -ENOMEM;
- goto err_netdevice;
+ goto err_free_cq_ring;
}
/* Allocate UAR table. */
err_free_intrs:
pvrdma_free_irq(dev);
pvrdma_disable_msi_all(dev);
-err_netdevice:
- unregister_netdevice_notifier(&dev->nb_netdev);
err_free_cq_ring:
pvrdma_page_dir_cleanup(dev, &dev->cq_pdir);
err_free_async_ring:
union pvrdma_cmd_resp rsp;
struct pvrdma_cmd_create_uc *cmd = &req.create_uc;
struct pvrdma_cmd_create_uc_resp *resp = &rsp.create_uc_resp;
- struct pvrdma_alloc_ucontext_resp uresp;
+ struct pvrdma_alloc_ucontext_resp uresp = {0};
int ret;
void *ptr;
}
spin_lock_bh(&dev_list_lock);
- list_add_tail(&rxe_dev_list, &rxe->list);
+ list_add_tail(&rxe->list, &rxe_dev_list);
spin_unlock_bh(&dev_list_lock);
return rxe;
}
del_timer_sync(&qp->rnr_nak_timer);
rxe_cleanup_task(&qp->req.task);
- if (qp_type(qp) == IB_QPT_RC)
- rxe_cleanup_task(&qp->comp.task);
+ rxe_cleanup_task(&qp->comp.task);
/* flush out any receive wr's or pending requests */
__rxe_do_task(&qp->req.task);
SHOST_DIX_GUARD_CRC);
}
- /*
- * Limit the sg_tablesize and max_sectors based on the device
- * max fastreg page list length.
- */
- shost->sg_tablesize = min_t(unsigned short, shost->sg_tablesize,
- ib_conn->device->ib_device->attrs.max_fast_reg_page_list_len);
-
if (iscsi_host_add(shost,
ib_conn->device->ib_device->dma_device)) {
mutex_unlock(&iser_conn->state_mutex);
max_fr_sectors = ((shost->sg_tablesize - 1) * PAGE_SIZE) >> 9;
shost->max_sectors = min(iser_max_sectors, max_fr_sectors);
+ iser_dbg("iser_conn %p, sg_tablesize %u, max_sectors %u\n",
+ iser_conn, shost->sg_tablesize,
+ shost->max_sectors);
+
if (cmds_max > max_cmds) {
iser_info("cmds_max changed from %u to %u\n",
cmds_max, max_cmds);
* @rx_descs: rx buffers array (cyclic buffer)
* @num_rx_descs: number of rx descriptors
* @scsi_sg_tablesize: scsi host sg_tablesize
- * @scsi_max_sectors: scsi host max sectors
*/
struct iser_conn {
struct ib_conn ib_conn;
struct iser_rx_desc *rx_descs;
u32 num_rx_descs;
unsigned short scsi_sg_tablesize;
- unsigned int scsi_max_sectors;
bool snd_w_inv;
};
sup_sg_tablesize = min_t(unsigned, ISCSI_ISER_MAX_SG_TABLESIZE,
device->ib_device->attrs.max_fast_reg_page_list_len);
- if (sg_tablesize > sup_sg_tablesize) {
- sg_tablesize = sup_sg_tablesize;
- iser_conn->scsi_max_sectors = sg_tablesize * SIZE_4K / 512;
- } else {
- iser_conn->scsi_max_sectors = max_sectors;
- }
-
- iser_conn->scsi_sg_tablesize = sg_tablesize;
-
- iser_dbg("iser_conn %p, sg_tablesize %u, max_sectors %u\n",
- iser_conn, iser_conn->scsi_sg_tablesize,
- iser_conn->scsi_max_sectors);
+ iser_conn->scsi_sg_tablesize = min(sg_tablesize, sup_sg_tablesize);
}
/**
struct srp_fr_desc *d;
struct ib_mr *mr;
int i, ret = -EINVAL;
+ enum ib_mr_type mr_type;
if (pool_size <= 0)
goto err;
spin_lock_init(&pool->lock);
INIT_LIST_HEAD(&pool->free_list);
+ if (device->attrs.device_cap_flags & IB_DEVICE_SG_GAPS_REG)
+ mr_type = IB_MR_TYPE_SG_GAPS;
+ else
+ mr_type = IB_MR_TYPE_MEM_REG;
+
for (i = 0, d = &pool->desc[0]; i < pool->size; i++, d++) {
- mr = ib_alloc_mr(pd, IB_MR_TYPE_MEM_REG,
- max_page_list_len);
+ mr = ib_alloc_mr(pd, mr_type, max_page_list_len);
if (IS_ERR(mr)) {
ret = PTR_ERR(mr);
if (ret == -ENOMEM)
indirect_sg_entries = cmd_sg_entries;
}
+ if (indirect_sg_entries > SG_MAX_SEGMENTS) {
+ pr_warn("Clamping indirect_sg_entries to %u\n",
+ SG_MAX_SEGMENTS);
+ indirect_sg_entries = SG_MAX_SEGMENTS;
+ }
+
srp_remove_wq = create_workqueue("srp_remove");
if (!srp_remove_wq) {
ret = -ENOMEM;
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/mm.h>
-#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/init.h>
input_dev->name = xpad->name;
input_dev->phys = xpad->phys;
usb_to_input_id(xpad->udev, &input_dev->id);
+
+ if (xpad->xtype == XTYPE_XBOX360W) {
+ /* x360w controllers and the receiver have different ids */
+ input_dev->id.product = 0x02a1;
+ }
+
input_dev->dev.parent = &xpad->intf->dev;
input_set_drvdata(input_dev, xpad);
MODULE_DEVICE_TABLE(i2c, adxl34x_id);
-#ifdef CONFIG_OF
static const struct of_device_id adxl34x_of_id[] = {
/*
* The ADXL346 is backward-compatible with the ADXL345. Differences are
};
MODULE_DEVICE_TABLE(of, adxl34x_of_id);
-#endif
static struct i2c_driver adxl34x_driver = {
.driver = {
.name = "adxl34x",
.pm = &adxl34x_i2c_pm,
- .of_match_table = of_match_ptr(adxl34x_of_id),
+ .of_match_table = adxl34x_of_id,
},
.probe = adxl34x_i2c_probe,
.remove = adxl34x_i2c_remove,
(_b[1] & 0x7F) \
)
-#define SS4_TS_Y_V2(_b) (s8)( \
+#define SS4_TS_Y_V2(_b) -(s8)( \
((_b[3] & 0x01) << 7) | \
(_b[2] & 0x7F) \
)
* after soft reset, we should wait for 1 ms
* before the device becomes operational
*/
-#define SOFT_RESET_DELAY_MS 3
+#define SOFT_RESET_DELAY_US 3000
/* and after hard reset, we should wait for max 500ms */
#define HARD_RESET_DELAY_MS 500
if (ret) {
dev_err(&client->dev, "Unable to reset device\n");
} else {
- msleep(SOFT_RESET_DELAY_MS);
+ usleep_range(SOFT_RESET_DELAY_US, SOFT_RESET_DELAY_US + 100);
ret = synaptics_i2c_config(client);
if (ret)
dev_err(&client->dev, "Unable to config device\n");
config RMI4_F03
bool "RMI4 Function 03 (PS2 Guest)"
- depends on RMI4_CORE && SERIO
+ depends on RMI4_CORE
+ depends on SERIO=y || RMI4_CORE=SERIO
help
Say Y here if you want to add support for RMI4 function 03.
data->enabled = true;
if (clear_wake && device_may_wakeup(rmi_dev->xport->dev)) {
retval = disable_irq_wake(irq);
- if (!retval)
+ if (retval)
dev_warn(&rmi_dev->dev,
"Failed to disable irq for wake: %d\n",
retval);
disable_irq(irq);
if (enable_wake && device_may_wakeup(rmi_dev->xport->dev)) {
retval = enable_irq_wake(irq);
- if (!retval)
+ if (retval)
dev_warn(&rmi_dev->dev,
"Failed to enable irq for wake: %d\n",
retval);
DMI_MATCH(DMI_PRODUCT_VERSION, "Rev 1"),
},
},
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "PEGATRON CORPORATION"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "C15B"),
+ },
+ },
{ }
};
case QUEUE_HEADER_NORMAL:
report_count = ts->buf[FW_HDR_COUNT];
- if (report_count > 3) {
+ if (report_count == 0 || report_count > 3) {
dev_err(&client->dev,
- "too large report count: %*ph\n",
+ "bad report count: %*ph\n",
HEADER_SIZE, ts->buf);
break;
}
}
platform_set_drvdata(wm->battery_dev, wm);
wm->battery_dev->dev.parent = dev;
- wm->battery_dev->dev.platform_data = pdata->batt_pdata;
+ wm->battery_dev->dev.platform_data = pdata ? pdata->batt_pdata : NULL;
ret = platform_device_add(wm->battery_dev);
if (ret < 0)
goto batt_reg_err;
((CAPI_MSG *) msg)->header.ncci = 0;
((CAPI_MSG *) msg)->info.facility_req.Selector = SELECTOR_LINE_INTERCONNECT;
((CAPI_MSG *) msg)->info.facility_req.structs[0] = 3;
- PUT_WORD(&(((CAPI_MSG *) msg)->info.facility_req.structs[1]), LI_REQ_SILENT_UPDATE);
+ ((CAPI_MSG *) msg)->info.facility_req.structs[1] = LI_REQ_SILENT_UPDATE & 0xff;
+ ((CAPI_MSG *) msg)->info.facility_req.structs[2] = LI_REQ_SILENT_UPDATE >> 8;
((CAPI_MSG *) msg)->info.facility_req.structs[3] = 0;
w = api_put(notify_plci->appl, (CAPI_MSG *) msg);
if (w != _QUEUE_FULL)
if (start_readonly && mddev->ro == 0)
mddev->ro = 2; /* read-only, but switch on first write */
+ /*
+ * NOTE: some pers->run(), for example r5l_recovery_log(), wakes
+ * up mddev->thread. It is important to initialize critical
+ * resources for mddev->thread BEFORE calling pers->run().
+ */
err = pers->run(mddev);
if (err)
pr_warn("md: pers->run() failed ...\n");
int is_new);
struct md_cluster_info;
+/* change UNSUPPORTED_MDDEV_FLAGS for each array type if new flag is added */
enum mddev_flags {
MD_ARRAY_FIRST_USE, /* First use of array, needs initialization */
MD_CLOSING, /* If set, we are closing the array, do not open
{
return mddev->cluster_info && mddev->bitmap_info.nodes > 1;
}
+
+/* clear unsupported mddev_flags */
+static inline void mddev_clear_unsupported_flags(struct mddev *mddev,
+ unsigned long unsupported_flags)
+{
+ mddev->flags &= ~unsupported_flags;
+}
#endif /* _MD_MD_H */
#include "raid0.h"
#include "raid5.h"
+#define UNSUPPORTED_MDDEV_FLAGS \
+ ((1L << MD_HAS_JOURNAL) | \
+ (1L << MD_JOURNAL_CLEAN) | \
+ (1L << MD_FAILFAST_SUPPORTED))
+
static int raid0_congested(struct mddev *mddev, int bits)
{
struct r0conf *conf = mddev->private;
mddev->delta_disks = -1;
/* make sure it will be not marked as dirty */
mddev->recovery_cp = MaxSector;
- clear_bit(MD_HAS_JOURNAL, &mddev->flags);
- clear_bit(MD_JOURNAL_CLEAN, &mddev->flags);
+ mddev_clear_unsupported_flags(mddev, UNSUPPORTED_MDDEV_FLAGS);
create_strip_zones(mddev, &priv_conf);
mddev->degraded = 0;
/* make sure it will be not marked as dirty */
mddev->recovery_cp = MaxSector;
- clear_bit(MD_FAILFAST_SUPPORTED, &mddev->flags);
+ mddev_clear_unsupported_flags(mddev, UNSUPPORTED_MDDEV_FLAGS);
create_strip_zones(mddev, &priv_conf);
return priv_conf;
mddev->raid_disks = 1;
/* make sure it will be not marked as dirty */
mddev->recovery_cp = MaxSector;
- clear_bit(MD_FAILFAST_SUPPORTED, &mddev->flags);
+ mddev_clear_unsupported_flags(mddev, UNSUPPORTED_MDDEV_FLAGS);
create_strip_zones(mddev, &priv_conf);
return priv_conf;
#include "raid1.h"
#include "bitmap.h"
+#define UNSUPPORTED_MDDEV_FLAGS \
+ ((1L << MD_HAS_JOURNAL) | \
+ (1L << MD_JOURNAL_CLEAN))
+
/*
* Number of guaranteed r1bios in case of extreme VM load:
*/
kfree(plug);
}
-static void raid1_make_request(struct mddev *mddev, struct bio * bio)
+static void raid1_read_request(struct mddev *mddev, struct bio *bio,
+ struct r1bio *r1_bio)
{
struct r1conf *conf = mddev->private;
struct raid1_info *mirror;
- struct r1bio *r1_bio;
struct bio *read_bio;
+ struct bitmap *bitmap = mddev->bitmap;
+ const int op = bio_op(bio);
+ const unsigned long do_sync = (bio->bi_opf & REQ_SYNC);
+ int sectors_handled;
+ int max_sectors;
+ int rdisk;
+
+ wait_barrier(conf, bio);
+
+read_again:
+ rdisk = read_balance(conf, r1_bio, &max_sectors);
+
+ if (rdisk < 0) {
+ /* couldn't find anywhere to read from */
+ raid_end_bio_io(r1_bio);
+ return;
+ }
+ mirror = conf->mirrors + rdisk;
+
+ if (test_bit(WriteMostly, &mirror->rdev->flags) &&
+ bitmap) {
+ /*
+ * Reading from a write-mostly device must take care not to
+ * over-take any writes that are 'behind'
+ */
+ raid1_log(mddev, "wait behind writes");
+ wait_event(bitmap->behind_wait,
+ atomic_read(&bitmap->behind_writes) == 0);
+ }
+ r1_bio->read_disk = rdisk;
+ r1_bio->start_next_window = 0;
+
+ read_bio = bio_clone_mddev(bio, GFP_NOIO, mddev);
+ bio_trim(read_bio, r1_bio->sector - bio->bi_iter.bi_sector,
+ max_sectors);
+
+ r1_bio->bios[rdisk] = read_bio;
+
+ read_bio->bi_iter.bi_sector = r1_bio->sector +
+ mirror->rdev->data_offset;
+ read_bio->bi_bdev = mirror->rdev->bdev;
+ read_bio->bi_end_io = raid1_end_read_request;
+ bio_set_op_attrs(read_bio, op, do_sync);
+ if (test_bit(FailFast, &mirror->rdev->flags) &&
+ test_bit(R1BIO_FailFast, &r1_bio->state))
+ read_bio->bi_opf |= MD_FAILFAST;
+ read_bio->bi_private = r1_bio;
+
+ if (mddev->gendisk)
+ trace_block_bio_remap(bdev_get_queue(read_bio->bi_bdev),
+ read_bio, disk_devt(mddev->gendisk),
+ r1_bio->sector);
+
+ if (max_sectors < r1_bio->sectors) {
+ /*
+ * could not read all from this device, so we will need another
+ * r1_bio.
+ */
+ sectors_handled = (r1_bio->sector + max_sectors
+ - bio->bi_iter.bi_sector);
+ r1_bio->sectors = max_sectors;
+ spin_lock_irq(&conf->device_lock);
+ if (bio->bi_phys_segments == 0)
+ bio->bi_phys_segments = 2;
+ else
+ bio->bi_phys_segments++;
+ spin_unlock_irq(&conf->device_lock);
+
+ /*
+ * Cannot call generic_make_request directly as that will be
+ * queued in __make_request and subsequent mempool_alloc might
+ * block waiting for it. So hand bio over to raid1d.
+ */
+ reschedule_retry(r1_bio);
+
+ r1_bio = mempool_alloc(conf->r1bio_pool, GFP_NOIO);
+
+ r1_bio->master_bio = bio;
+ r1_bio->sectors = bio_sectors(bio) - sectors_handled;
+ r1_bio->state = 0;
+ r1_bio->mddev = mddev;
+ r1_bio->sector = bio->bi_iter.bi_sector + sectors_handled;
+ goto read_again;
+ } else
+ generic_make_request(read_bio);
+}
+
+static void raid1_write_request(struct mddev *mddev, struct bio *bio,
+ struct r1bio *r1_bio)
+{
+ struct r1conf *conf = mddev->private;
int i, disks;
- struct bitmap *bitmap;
+ struct bitmap *bitmap = mddev->bitmap;
unsigned long flags;
const int op = bio_op(bio);
- const int rw = bio_data_dir(bio);
const unsigned long do_sync = (bio->bi_opf & REQ_SYNC);
const unsigned long do_flush_fua = (bio->bi_opf &
(REQ_PREFLUSH | REQ_FUA));
md_write_start(mddev, bio); /* wait on superblock update early */
- if (bio_data_dir(bio) == WRITE &&
- ((bio_end_sector(bio) > mddev->suspend_lo &&
+ if ((bio_end_sector(bio) > mddev->suspend_lo &&
bio->bi_iter.bi_sector < mddev->suspend_hi) ||
(mddev_is_clustered(mddev) &&
md_cluster_ops->area_resyncing(mddev, WRITE,
- bio->bi_iter.bi_sector, bio_end_sector(bio))))) {
- /* As the suspend_* range is controlled by
- * userspace, we want an interruptible
- * wait.
+ bio->bi_iter.bi_sector, bio_end_sector(bio)))) {
+
+ /*
+ * As the suspend_* range is controlled by userspace, we want
+ * an interruptible wait.
*/
DEFINE_WAIT(w);
for (;;) {
bio->bi_iter.bi_sector >= mddev->suspend_hi ||
(mddev_is_clustered(mddev) &&
!md_cluster_ops->area_resyncing(mddev, WRITE,
- bio->bi_iter.bi_sector, bio_end_sector(bio))))
+ bio->bi_iter.bi_sector,
+ bio_end_sector(bio))))
break;
schedule();
}
finish_wait(&conf->wait_barrier, &w);
}
-
start_next_window = wait_barrier(conf, bio);
- bitmap = mddev->bitmap;
-
- /*
- * make_request() can abort the operation when read-ahead is being
- * used and no empty request is available.
- *
- */
- r1_bio = mempool_alloc(conf->r1bio_pool, GFP_NOIO);
-
- r1_bio->master_bio = bio;
- r1_bio->sectors = bio_sectors(bio);
- r1_bio->state = 0;
- r1_bio->mddev = mddev;
- r1_bio->sector = bio->bi_iter.bi_sector;
-
- /* We might need to issue multiple reads to different
- * devices if there are bad blocks around, so we keep
- * track of the number of reads in bio->bi_phys_segments.
- * If this is 0, there is only one r1_bio and no locking
- * will be needed when requests complete. If it is
- * non-zero, then it is the number of not-completed requests.
- */
- bio->bi_phys_segments = 0;
- bio_clear_flag(bio, BIO_SEG_VALID);
-
- if (rw == READ) {
- /*
- * read balancing logic:
- */
- int rdisk;
-
-read_again:
- rdisk = read_balance(conf, r1_bio, &max_sectors);
-
- if (rdisk < 0) {
- /* couldn't find anywhere to read from */
- raid_end_bio_io(r1_bio);
- return;
- }
- mirror = conf->mirrors + rdisk;
-
- if (test_bit(WriteMostly, &mirror->rdev->flags) &&
- bitmap) {
- /* Reading from a write-mostly device must
- * take care not to over-take any writes
- * that are 'behind'
- */
- raid1_log(mddev, "wait behind writes");
- wait_event(bitmap->behind_wait,
- atomic_read(&bitmap->behind_writes) == 0);
- }
- r1_bio->read_disk = rdisk;
- r1_bio->start_next_window = 0;
-
- read_bio = bio_clone_mddev(bio, GFP_NOIO, mddev);
- bio_trim(read_bio, r1_bio->sector - bio->bi_iter.bi_sector,
- max_sectors);
-
- r1_bio->bios[rdisk] = read_bio;
-
- read_bio->bi_iter.bi_sector = r1_bio->sector +
- mirror->rdev->data_offset;
- read_bio->bi_bdev = mirror->rdev->bdev;
- read_bio->bi_end_io = raid1_end_read_request;
- bio_set_op_attrs(read_bio, op, do_sync);
- if (test_bit(FailFast, &mirror->rdev->flags) &&
- test_bit(R1BIO_FailFast, &r1_bio->state))
- read_bio->bi_opf |= MD_FAILFAST;
- read_bio->bi_private = r1_bio;
-
- if (mddev->gendisk)
- trace_block_bio_remap(bdev_get_queue(read_bio->bi_bdev),
- read_bio, disk_devt(mddev->gendisk),
- r1_bio->sector);
-
- if (max_sectors < r1_bio->sectors) {
- /* could not read all from this device, so we will
- * need another r1_bio.
- */
-
- sectors_handled = (r1_bio->sector + max_sectors
- - bio->bi_iter.bi_sector);
- r1_bio->sectors = max_sectors;
- spin_lock_irq(&conf->device_lock);
- if (bio->bi_phys_segments == 0)
- bio->bi_phys_segments = 2;
- else
- bio->bi_phys_segments++;
- spin_unlock_irq(&conf->device_lock);
- /* Cannot call generic_make_request directly
- * as that will be queued in __make_request
- * and subsequent mempool_alloc might block waiting
- * for it. So hand bio over to raid1d.
- */
- reschedule_retry(r1_bio);
-
- r1_bio = mempool_alloc(conf->r1bio_pool, GFP_NOIO);
-
- r1_bio->master_bio = bio;
- r1_bio->sectors = bio_sectors(bio) - sectors_handled;
- r1_bio->state = 0;
- r1_bio->mddev = mddev;
- r1_bio->sector = bio->bi_iter.bi_sector +
- sectors_handled;
- goto read_again;
- } else
- generic_make_request(read_bio);
- return;
- }
-
- /*
- * WRITE:
- */
if (conf->pending_count >= max_queued_requests) {
md_wakeup_thread(mddev->thread);
raid1_log(mddev, "wait queued");
int bad_sectors;
int is_bad;
- is_bad = is_badblock(rdev, r1_bio->sector,
- max_sectors,
+ is_bad = is_badblock(rdev, r1_bio->sector, max_sectors,
&first_bad, &bad_sectors);
if (is_bad < 0) {
/* mustn't write here until the bad block is
continue;
mbio = bio_clone_mddev(bio, GFP_NOIO, mddev);
- bio_trim(mbio, r1_bio->sector - bio->bi_iter.bi_sector, max_sectors);
+ bio_trim(mbio, r1_bio->sector - bio->bi_iter.bi_sector,
+ max_sectors);
if (first_clone) {
/* do behind I/O ?
wake_up(&conf->wait_barrier);
}
+static void raid1_make_request(struct mddev *mddev, struct bio *bio)
+{
+ struct r1conf *conf = mddev->private;
+ struct r1bio *r1_bio;
+
+ /*
+ * make_request() can abort the operation when read-ahead is being
+ * used and no empty request is available.
+ *
+ */
+ r1_bio = mempool_alloc(conf->r1bio_pool, GFP_NOIO);
+
+ r1_bio->master_bio = bio;
+ r1_bio->sectors = bio_sectors(bio);
+ r1_bio->state = 0;
+ r1_bio->mddev = mddev;
+ r1_bio->sector = bio->bi_iter.bi_sector;
+
+ /*
+ * We might need to issue multiple reads to different devices if there
+ * are bad blocks around, so we keep track of the number of reads in
+ * bio->bi_phys_segments. If this is 0, there is only one r1_bio and
+ * no locking will be needed when requests complete. If it is
+ * non-zero, then it is the number of not-completed requests.
+ */
+ bio->bi_phys_segments = 0;
+ bio_clear_flag(bio, BIO_SEG_VALID);
+
+ if (bio_data_dir(bio) == READ)
+ raid1_read_request(mddev, bio, r1_bio);
+ else
+ raid1_write_request(mddev, bio, r1_bio);
+}
+
static void raid1_status(struct seq_file *seq, struct mddev *mddev)
{
struct r1conf *conf = mddev->private;
if (!IS_ERR(conf)) {
/* Array must appear to be quiesced */
conf->array_frozen = 1;
- clear_bit(MD_HAS_JOURNAL, &mddev->flags);
- clear_bit(MD_JOURNAL_CLEAN, &mddev->flags);
+ mddev_clear_unsupported_flags(mddev,
+ UNSUPPORTED_MDDEV_FLAGS);
}
return conf;
}
kfree(plug);
}
-static void __make_request(struct mddev *mddev, struct bio *bio)
+static void raid10_read_request(struct mddev *mddev, struct bio *bio,
+ struct r10bio *r10_bio)
{
struct r10conf *conf = mddev->private;
- struct r10bio *r10_bio;
struct bio *read_bio;
+ const int op = bio_op(bio);
+ const unsigned long do_sync = (bio->bi_opf & REQ_SYNC);
+ int sectors_handled;
+ int max_sectors;
+ sector_t sectors;
+ struct md_rdev *rdev;
+ int slot;
+
+ /*
+ * Register the new request and wait if the reconstruction
+ * thread has put up a bar for new requests.
+ * Continue immediately if no resync is active currently.
+ */
+ wait_barrier(conf);
+
+ sectors = bio_sectors(bio);
+ while (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
+ bio->bi_iter.bi_sector < conf->reshape_progress &&
+ bio->bi_iter.bi_sector + sectors > conf->reshape_progress) {
+ /*
+ * IO spans the reshape position. Need to wait for reshape to
+ * pass
+ */
+ raid10_log(conf->mddev, "wait reshape");
+ allow_barrier(conf);
+ wait_event(conf->wait_barrier,
+ conf->reshape_progress <= bio->bi_iter.bi_sector ||
+ conf->reshape_progress >= bio->bi_iter.bi_sector +
+ sectors);
+ wait_barrier(conf);
+ }
+
+read_again:
+ rdev = read_balance(conf, r10_bio, &max_sectors);
+ if (!rdev) {
+ raid_end_bio_io(r10_bio);
+ return;
+ }
+ slot = r10_bio->read_slot;
+
+ read_bio = bio_clone_mddev(bio, GFP_NOIO, mddev);
+ bio_trim(read_bio, r10_bio->sector - bio->bi_iter.bi_sector,
+ max_sectors);
+
+ r10_bio->devs[slot].bio = read_bio;
+ r10_bio->devs[slot].rdev = rdev;
+
+ read_bio->bi_iter.bi_sector = r10_bio->devs[slot].addr +
+ choose_data_offset(r10_bio, rdev);
+ read_bio->bi_bdev = rdev->bdev;
+ read_bio->bi_end_io = raid10_end_read_request;
+ bio_set_op_attrs(read_bio, op, do_sync);
+ if (test_bit(FailFast, &rdev->flags) &&
+ test_bit(R10BIO_FailFast, &r10_bio->state))
+ read_bio->bi_opf |= MD_FAILFAST;
+ read_bio->bi_private = r10_bio;
+
+ if (mddev->gendisk)
+ trace_block_bio_remap(bdev_get_queue(read_bio->bi_bdev),
+ read_bio, disk_devt(mddev->gendisk),
+ r10_bio->sector);
+ if (max_sectors < r10_bio->sectors) {
+ /*
+ * Could not read all from this device, so we will need another
+ * r10_bio.
+ */
+ sectors_handled = (r10_bio->sector + max_sectors
+ - bio->bi_iter.bi_sector);
+ r10_bio->sectors = max_sectors;
+ spin_lock_irq(&conf->device_lock);
+ if (bio->bi_phys_segments == 0)
+ bio->bi_phys_segments = 2;
+ else
+ bio->bi_phys_segments++;
+ spin_unlock_irq(&conf->device_lock);
+ /*
+ * Cannot call generic_make_request directly as that will be
+ * queued in __generic_make_request and subsequent
+ * mempool_alloc might block waiting for it. so hand bio over
+ * to raid10d.
+ */
+ reschedule_retry(r10_bio);
+
+ r10_bio = mempool_alloc(conf->r10bio_pool, GFP_NOIO);
+
+ r10_bio->master_bio = bio;
+ r10_bio->sectors = bio_sectors(bio) - sectors_handled;
+ r10_bio->state = 0;
+ r10_bio->mddev = mddev;
+ r10_bio->sector = bio->bi_iter.bi_sector + sectors_handled;
+ goto read_again;
+ } else
+ generic_make_request(read_bio);
+ return;
+}
+
+static void raid10_write_request(struct mddev *mddev, struct bio *bio,
+ struct r10bio *r10_bio)
+{
+ struct r10conf *conf = mddev->private;
int i;
const int op = bio_op(bio);
- const int rw = bio_data_dir(bio);
const unsigned long do_sync = (bio->bi_opf & REQ_SYNC);
const unsigned long do_fua = (bio->bi_opf & REQ_FUA);
unsigned long flags;
struct md_rdev *blocked_rdev;
struct blk_plug_cb *cb;
struct raid10_plug_cb *plug = NULL;
+ sector_t sectors;
int sectors_handled;
int max_sectors;
- int sectors;
md_write_start(mddev, bio);
while (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
bio->bi_iter.bi_sector < conf->reshape_progress &&
bio->bi_iter.bi_sector + sectors > conf->reshape_progress) {
- /* IO spans the reshape position. Need to wait for
- * reshape to pass
+ /*
+ * IO spans the reshape position. Need to wait for reshape to
+ * pass
*/
raid10_log(conf->mddev, "wait reshape");
allow_barrier(conf);
sectors);
wait_barrier(conf);
}
+
if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
- bio_data_dir(bio) == WRITE &&
(mddev->reshape_backwards
? (bio->bi_iter.bi_sector < conf->reshape_safe &&
bio->bi_iter.bi_sector + sectors > conf->reshape_progress)
conf->reshape_safe = mddev->reshape_position;
}
- r10_bio = mempool_alloc(conf->r10bio_pool, GFP_NOIO);
-
- r10_bio->master_bio = bio;
- r10_bio->sectors = sectors;
-
- r10_bio->mddev = mddev;
- r10_bio->sector = bio->bi_iter.bi_sector;
- r10_bio->state = 0;
-
- /* We might need to issue multiple reads to different
- * devices if there are bad blocks around, so we keep
- * track of the number of reads in bio->bi_phys_segments.
- * If this is 0, there is only one r10_bio and no locking
- * will be needed when the request completes. If it is
- * non-zero, then it is the number of not-completed requests.
- */
- bio->bi_phys_segments = 0;
- bio_clear_flag(bio, BIO_SEG_VALID);
-
- if (rw == READ) {
- /*
- * read balancing logic:
- */
- struct md_rdev *rdev;
- int slot;
-
-read_again:
- rdev = read_balance(conf, r10_bio, &max_sectors);
- if (!rdev) {
- raid_end_bio_io(r10_bio);
- return;
- }
- slot = r10_bio->read_slot;
-
- read_bio = bio_clone_mddev(bio, GFP_NOIO, mddev);
- bio_trim(read_bio, r10_bio->sector - bio->bi_iter.bi_sector,
- max_sectors);
-
- r10_bio->devs[slot].bio = read_bio;
- r10_bio->devs[slot].rdev = rdev;
-
- read_bio->bi_iter.bi_sector = r10_bio->devs[slot].addr +
- choose_data_offset(r10_bio, rdev);
- read_bio->bi_bdev = rdev->bdev;
- read_bio->bi_end_io = raid10_end_read_request;
- bio_set_op_attrs(read_bio, op, do_sync);
- if (test_bit(FailFast, &rdev->flags) &&
- test_bit(R10BIO_FailFast, &r10_bio->state))
- read_bio->bi_opf |= MD_FAILFAST;
- read_bio->bi_private = r10_bio;
-
- if (mddev->gendisk)
- trace_block_bio_remap(bdev_get_queue(read_bio->bi_bdev),
- read_bio, disk_devt(mddev->gendisk),
- r10_bio->sector);
- if (max_sectors < r10_bio->sectors) {
- /* Could not read all from this device, so we will
- * need another r10_bio.
- */
- sectors_handled = (r10_bio->sector + max_sectors
- - bio->bi_iter.bi_sector);
- r10_bio->sectors = max_sectors;
- spin_lock_irq(&conf->device_lock);
- if (bio->bi_phys_segments == 0)
- bio->bi_phys_segments = 2;
- else
- bio->bi_phys_segments++;
- spin_unlock_irq(&conf->device_lock);
- /* Cannot call generic_make_request directly
- * as that will be queued in __generic_make_request
- * and subsequent mempool_alloc might block
- * waiting for it. so hand bio over to raid10d.
- */
- reschedule_retry(r10_bio);
-
- r10_bio = mempool_alloc(conf->r10bio_pool, GFP_NOIO);
-
- r10_bio->master_bio = bio;
- r10_bio->sectors = bio_sectors(bio) - sectors_handled;
- r10_bio->state = 0;
- r10_bio->mddev = mddev;
- r10_bio->sector = bio->bi_iter.bi_sector +
- sectors_handled;
- goto read_again;
- } else
- generic_make_request(read_bio);
- return;
- }
-
- /*
- * WRITE:
- */
if (conf->pending_count >= max_queued_requests) {
md_wakeup_thread(mddev->thread);
raid10_log(mddev, "wait queued");
int bad_sectors;
int is_bad;
- is_bad = is_badblock(rdev, dev_sector,
- max_sectors,
+ is_bad = is_badblock(rdev, dev_sector, max_sectors,
&first_bad, &bad_sectors);
if (is_bad < 0) {
/* Mustn't write here until the bad block
r10_bio->devs[i].bio = mbio;
mbio->bi_iter.bi_sector = (r10_bio->devs[i].addr+
- choose_data_offset(r10_bio,
- rdev));
+ choose_data_offset(r10_bio, rdev));
mbio->bi_bdev = rdev->bdev;
mbio->bi_end_io = raid10_end_write_request;
bio_set_op_attrs(mbio, op, do_sync | do_fua);
r10_bio->devs[i].repl_bio = mbio;
mbio->bi_iter.bi_sector = (r10_bio->devs[i].addr +
- choose_data_offset(
- r10_bio, rdev));
+ choose_data_offset(r10_bio, rdev));
mbio->bi_bdev = rdev->bdev;
mbio->bi_end_io = raid10_end_write_request;
bio_set_op_attrs(mbio, op, do_sync | do_fua);
one_write_done(r10_bio);
}
+static void __make_request(struct mddev *mddev, struct bio *bio)
+{
+ struct r10conf *conf = mddev->private;
+ struct r10bio *r10_bio;
+
+ r10_bio = mempool_alloc(conf->r10bio_pool, GFP_NOIO);
+
+ r10_bio->master_bio = bio;
+ r10_bio->sectors = bio_sectors(bio);
+
+ r10_bio->mddev = mddev;
+ r10_bio->sector = bio->bi_iter.bi_sector;
+ r10_bio->state = 0;
+
+ /*
+ * We might need to issue multiple reads to different devices if there
+ * are bad blocks around, so we keep track of the number of reads in
+ * bio->bi_phys_segments. If this is 0, there is only one r10_bio and
+ * no locking will be needed when the request completes. If it is
+ * non-zero, then it is the number of not-completed requests.
+ */
+ bio->bi_phys_segments = 0;
+ bio_clear_flag(bio, BIO_SEG_VALID);
+
+ if (bio_data_dir(bio) == READ)
+ raid10_read_request(mddev, bio, r10_bio);
+ else
+ raid10_write_request(mddev, bio, r10_bio);
+}
+
static void raid10_make_request(struct mddev *mddev, struct bio *bio)
{
struct r10conf *conf = mddev->private;
/* to submit async io_units, to fulfill ordering of flush */
struct work_struct deferred_io_work;
+ /* to disable write back during in degraded mode */
+ struct work_struct disable_writeback_work;
};
/*
r5l_do_submit_io(log, io);
}
+static void r5c_disable_writeback_async(struct work_struct *work)
+{
+ struct r5l_log *log = container_of(work, struct r5l_log,
+ disable_writeback_work);
+ struct mddev *mddev = log->rdev->mddev;
+
+ if (log->r5c_journal_mode == R5C_JOURNAL_MODE_WRITE_THROUGH)
+ return;
+ pr_info("md/raid:%s: Disabling writeback cache for degraded array.\n",
+ mdname(mddev));
+ mddev_suspend(mddev);
+ log->r5c_journal_mode = R5C_JOURNAL_MODE_WRITE_THROUGH;
+ mddev_resume(mddev);
+}
+
static void r5l_submit_current_io(struct r5l_log *log)
{
struct r5l_io_unit *io = log->current_io;
next_checkpoint = r5c_calculate_new_cp(conf);
spin_unlock_irq(&log->io_list_lock);
- BUG_ON(reclaimable < 0);
-
if (reclaimable == 0 || !write_super)
return;
static struct stripe_head *
r5c_recovery_alloc_stripe(struct r5conf *conf,
- sector_t stripe_sect,
- sector_t log_start)
+ sector_t stripe_sect)
{
struct stripe_head *sh;
return NULL; /* no more stripe available */
r5l_recovery_reset_stripe(sh);
- sh->log_start = log_start;
return sh;
}
stripe_sect);
if (!sh) {
- sh = r5c_recovery_alloc_stripe(conf, stripe_sect, ctx->pos);
+ sh = r5c_recovery_alloc_stripe(conf, stripe_sect);
/*
* cannot get stripe from raid5_get_active_stripe
* try replay some stripes
r5c_recovery_replay_stripes(
cached_stripe_list, ctx);
sh = r5c_recovery_alloc_stripe(
- conf, stripe_sect, ctx->pos);
+ conf, stripe_sect);
}
if (!sh) {
pr_debug("md/raid:%s: Increasing stripe cache size to %d to recovery data on journal.\n",
conf->min_nr_stripes * 2);
raid5_set_cache_size(mddev,
conf->min_nr_stripes * 2);
- sh = r5c_recovery_alloc_stripe(
- conf, stripe_sect, ctx->pos);
+ sh = r5c_recovery_alloc_stripe(conf,
+ stripe_sect);
}
if (!sh) {
pr_err("md/raid:%s: Cannot get enough stripes due to memory pressure. Recovery failed.\n",
if (!test_bit(STRIPE_R5C_CACHING, &sh->state) &&
test_bit(R5_Wantwrite, &sh->dev[sh->pd_idx].flags)) {
r5l_recovery_replay_one_stripe(conf, sh, ctx);
- sh->log_start = ctx->pos;
list_move_tail(&sh->lru, cached_stripe_list);
}
r5l_recovery_load_data(log, sh, ctx, payload,
set_bit(R5_UPTODATE, &dev->flags);
}
}
- list_add_tail(&sh->r5c, &log->stripe_in_journal_list);
- atomic_inc(&log->stripe_in_journal_count);
}
/*
r5c_recovery_rewrite_data_only_stripes(struct r5l_log *log,
struct r5l_recovery_ctx *ctx)
{
- struct stripe_head *sh, *next;
+ struct stripe_head *sh;
struct mddev *mddev = log->rdev->mddev;
struct page *page;
+ sector_t next_checkpoint = MaxSector;
page = alloc_page(GFP_KERNEL);
if (!page) {
return -ENOMEM;
}
- list_for_each_entry_safe(sh, next, &ctx->cached_list, lru) {
+ WARN_ON(list_empty(&ctx->cached_list));
+
+ list_for_each_entry(sh, &ctx->cached_list, lru) {
struct r5l_meta_block *mb;
int i;
int offset;
sync_page_io(log->rdev, ctx->pos, PAGE_SIZE, page,
REQ_OP_WRITE, REQ_FUA, false);
sh->log_start = ctx->pos;
+ list_add_tail(&sh->r5c, &log->stripe_in_journal_list);
+ atomic_inc(&log->stripe_in_journal_count);
ctx->pos = write_pos;
ctx->seq += 1;
+ next_checkpoint = sh->log_start;
+ }
+ log->next_checkpoint = next_checkpoint;
+ __free_page(page);
+ return 0;
+}
+
+static void r5c_recovery_flush_data_only_stripes(struct r5l_log *log,
+ struct r5l_recovery_ctx *ctx)
+{
+ struct mddev *mddev = log->rdev->mddev;
+ struct r5conf *conf = mddev->private;
+ struct stripe_head *sh, *next;
+
+ if (ctx->data_only_stripes == 0)
+ return;
+ log->r5c_journal_mode = R5C_JOURNAL_MODE_WRITE_BACK;
+
+ list_for_each_entry_safe(sh, next, &ctx->cached_list, lru) {
+ r5c_make_stripe_write_out(sh);
+ set_bit(STRIPE_HANDLE, &sh->state);
list_del_init(&sh->lru);
raid5_release_stripe(sh);
}
- __free_page(page);
- return 0;
+
+ md_wakeup_thread(conf->mddev->thread);
+ /* reuse conf->wait_for_quiescent in recovery */
+ wait_event(conf->wait_for_quiescent,
+ atomic_read(&conf->active_stripes) == 0);
+
+ log->r5c_journal_mode = R5C_JOURNAL_MODE_WRITE_THROUGH;
}
static int r5l_recovery_log(struct r5l_log *log)
struct r5l_recovery_ctx ctx;
int ret;
sector_t pos;
- struct stripe_head *sh;
ctx.pos = log->last_checkpoint;
ctx.seq = log->last_cp_seq;
pos = ctx.pos;
ctx.seq += 10000;
- if (ctx.data_only_stripes == 0) {
- log->next_checkpoint = ctx.pos;
- r5l_log_write_empty_meta_block(log, ctx.pos, ctx.seq++);
- ctx.pos = r5l_ring_add(log, ctx.pos, BLOCK_SECTORS);
- } else {
- sh = list_last_entry(&ctx.cached_list, struct stripe_head, lru);
- log->next_checkpoint = sh->log_start;
- }
if ((ctx.data_only_stripes == 0) && (ctx.data_parity_stripes == 0))
pr_debug("md/raid:%s: starting from clean shutdown\n",
mdname(mddev));
- else {
- pr_debug("md/raid:%s: recoverying %d data-only stripes and %d data-parity stripes\n",
+ else
+ pr_debug("md/raid:%s: recovering %d data-only stripes and %d data-parity stripes\n",
mdname(mddev), ctx.data_only_stripes,
ctx.data_parity_stripes);
- if (ctx.data_only_stripes > 0)
- if (r5c_recovery_rewrite_data_only_stripes(log, &ctx)) {
- pr_err("md/raid:%s: failed to rewrite stripes to journal\n",
- mdname(mddev));
- return -EIO;
- }
+ if (ctx.data_only_stripes == 0) {
+ log->next_checkpoint = ctx.pos;
+ r5l_log_write_empty_meta_block(log, ctx.pos, ctx.seq++);
+ ctx.pos = r5l_ring_add(log, ctx.pos, BLOCK_SECTORS);
+ } else if (r5c_recovery_rewrite_data_only_stripes(log, &ctx)) {
+ pr_err("md/raid:%s: failed to rewrite stripes to journal\n",
+ mdname(mddev));
+ return -EIO;
}
log->log_start = ctx.pos;
log->seq = ctx.seq;
log->last_checkpoint = pos;
r5l_write_super(log, pos);
+
+ r5c_recovery_flush_data_only_stripes(log, &ctx);
return 0;
}
val > R5C_JOURNAL_MODE_WRITE_BACK)
return -EINVAL;
+ if (raid5_calc_degraded(conf) > 0 &&
+ val == R5C_JOURNAL_MODE_WRITE_BACK)
+ return -EINVAL;
+
mddev_suspend(mddev);
conf->log->r5c_journal_mode = val;
mddev_resume(mddev);
set_bit(STRIPE_R5C_CACHING, &sh->state);
}
+ /*
+ * When run in degraded mode, array is set to write-through mode.
+ * This check helps drain pending write safely in the transition to
+ * write-through mode.
+ */
+ if (s->failed) {
+ r5c_make_stripe_write_out(sh);
+ return -EAGAIN;
+ }
+
for (i = disks; i--; ) {
dev = &sh->dev[i];
/* if non-overwrite, use writing-out phase */
struct page *p = sh->dev[i].orig_page;
sh->dev[i].orig_page = sh->dev[i].page;
+ clear_bit(R5_OrigPageUPTDODATE, &sh->dev[i].flags);
+
if (!using_disk_info_extra_page)
put_page(p);
}
if (do_wakeup)
wake_up(&conf->wait_for_overlap);
- if (conf->log->r5c_journal_mode == R5C_JOURNAL_MODE_WRITE_THROUGH)
- return;
-
spin_lock_irq(&conf->log->stripe_in_journal_lock);
list_del_init(&sh->r5c);
spin_unlock_irq(&conf->log->stripe_in_journal_lock);
return ret;
}
+void r5c_update_on_rdev_error(struct mddev *mddev)
+{
+ struct r5conf *conf = mddev->private;
+ struct r5l_log *log = conf->log;
+
+ if (!log)
+ return;
+
+ if (raid5_calc_degraded(conf) > 0 &&
+ conf->log->r5c_journal_mode == R5C_JOURNAL_MODE_WRITE_BACK)
+ schedule_work(&log->disable_writeback_work);
+}
+
int r5l_init_log(struct r5conf *conf, struct md_rdev *rdev)
{
struct request_queue *q = bdev_get_queue(rdev->bdev);
spin_lock_init(&log->no_space_stripes_lock);
INIT_WORK(&log->deferred_io_work, r5l_submit_io_async);
+ INIT_WORK(&log->disable_writeback_work, r5c_disable_writeback_async);
log->r5c_journal_mode = R5C_JOURNAL_MODE_WRITE_THROUGH;
INIT_LIST_HEAD(&log->stripe_in_journal_list);
spin_lock_init(&log->stripe_in_journal_lock);
atomic_set(&log->stripe_in_journal_count, 0);
+ rcu_assign_pointer(conf->log, log);
+
if (r5l_load_log(log))
goto error;
- rcu_assign_pointer(conf->log, log);
set_bit(MD_HAS_JOURNAL, &conf->mddev->flags);
return 0;
error:
+ rcu_assign_pointer(conf->log, NULL);
md_unregister_thread(&log->reclaim_thread);
reclaim_thread:
mempool_destroy(log->meta_pool);
void r5l_exit_log(struct r5l_log *log)
{
+ flush_work(&log->disable_writeback_work);
md_unregister_thread(&log->reclaim_thread);
mempool_destroy(log->meta_pool);
bioset_free(log->bs);
#include "raid0.h"
#include "bitmap.h"
+#define UNSUPPORTED_MDDEV_FLAGS (1L << MD_FAILFAST_SUPPORTED)
+
#define cpu_to_group(cpu) cpu_to_node(cpu)
#define ANY_GROUP NUMA_NO_NODE
* of the two sections, and some non-in_sync devices may
* be insync in the section most affected by failed devices.
*/
-static int calc_degraded(struct r5conf *conf)
+int raid5_calc_degraded(struct r5conf *conf)
{
int degraded, degraded2;
int i;
if (conf->mddev->reshape_position == MaxSector)
return conf->mddev->degraded > conf->max_degraded;
- degraded = calc_degraded(conf);
+ degraded = raid5_calc_degraded(conf);
if (degraded > conf->max_degraded)
return 1;
return 0;
if (test_bit(R5_SkipCopy, &sh->dev[i].flags))
WARN_ON(test_bit(R5_UPTODATE, &sh->dev[i].flags));
- sh->dev[i].vec.bv_page = sh->dev[i].page;
+
+ if (!op_is_write(op) &&
+ test_bit(R5_InJournal, &sh->dev[i].flags))
+ /*
+ * issuing read for a page in journal, this
+ * must be preparing for prexor in rmw; read
+ * the data into orig_page
+ */
+ sh->dev[i].vec.bv_page = sh->dev[i].orig_page;
+ else
+ sh->dev[i].vec.bv_page = sh->dev[i].page;
bi->bi_vcnt = 1;
bi->bi_io_vec[0].bv_len = STRIPE_SIZE;
bi->bi_io_vec[0].bv_offset = 0;
} else if (test_bit(R5_ReadNoMerge, &sh->dev[i].flags))
clear_bit(R5_ReadNoMerge, &sh->dev[i].flags);
+ if (test_bit(R5_InJournal, &sh->dev[i].flags))
+ /*
+ * end read for a page in journal, this
+ * must be preparing for prexor in rmw
+ */
+ set_bit(R5_OrigPageUPTDODATE, &sh->dev[i].flags);
+
if (atomic_read(&rdev->read_errors))
atomic_set(&rdev->read_errors, 0);
} else {
spin_lock_irqsave(&conf->device_lock, flags);
clear_bit(In_sync, &rdev->flags);
- mddev->degraded = calc_degraded(conf);
+ mddev->degraded = raid5_calc_degraded(conf);
spin_unlock_irqrestore(&conf->device_lock, flags);
set_bit(MD_RECOVERY_INTR, &mddev->recovery);
bdevname(rdev->bdev, b),
mdname(mddev),
conf->raid_disks - mddev->degraded);
+ r5c_update_on_rdev_error(mddev);
}
/*
return r_sector;
}
+/*
+ * There are cases where we want handle_stripe_dirtying() and
+ * schedule_reconstruction() to delay towrite to some dev of a stripe.
+ *
+ * This function checks whether we want to delay the towrite. Specifically,
+ * we delay the towrite when:
+ *
+ * 1. degraded stripe has a non-overwrite to the missing dev, AND this
+ * stripe has data in journal (for other devices).
+ *
+ * In this case, when reading data for the non-overwrite dev, it is
+ * necessary to handle complex rmw of write back cache (prexor with
+ * orig_page, and xor with page). To keep read path simple, we would
+ * like to flush data in journal to RAID disks first, so complex rmw
+ * is handled in the write patch (handle_stripe_dirtying).
+ *
+ */
+static inline bool delay_towrite(struct r5dev *dev,
+ struct stripe_head_state *s)
+{
+ return !test_bit(R5_OVERWRITE, &dev->flags) &&
+ !test_bit(R5_Insync, &dev->flags) && s->injournal;
+}
+
static void
schedule_reconstruction(struct stripe_head *sh, struct stripe_head_state *s,
int rcw, int expand)
for (i = disks; i--; ) {
struct r5dev *dev = &sh->dev[i];
- if (dev->towrite) {
+ if (dev->towrite && !delay_towrite(dev, s)) {
set_bit(R5_LOCKED, &dev->flags);
set_bit(R5_Wantdrain, &dev->flags);
if (!expand)
return rv;
}
-/* fetch_block - checks the given member device to see if its data needs
- * to be read or computed to satisfy a request.
- *
- * Returns 1 when no more member devices need to be checked, otherwise returns
- * 0 to tell the loop in handle_stripe_fill to continue
- */
-
static int need_this_block(struct stripe_head *sh, struct stripe_head_state *s,
int disk_idx, int disks)
{
return 0;
}
+/* fetch_block - checks the given member device to see if its data needs
+ * to be read or computed to satisfy a request.
+ *
+ * Returns 1 when no more member devices need to be checked, otherwise returns
+ * 0 to tell the loop in handle_stripe_fill to continue
+ */
static int fetch_block(struct stripe_head *sh, struct stripe_head_state *s,
int disk_idx, int disks)
{
* midst of changing due to a write
*/
if (!test_bit(STRIPE_COMPUTE_RUN, &sh->state) && !sh->check_state &&
- !sh->reconstruct_state)
+ !sh->reconstruct_state) {
+
+ /*
+ * For degraded stripe with data in journal, do not handle
+ * read requests yet, instead, flush the stripe to raid
+ * disks first, this avoids handling complex rmw of write
+ * back cache (prexor with orig_page, and then xor with
+ * page) in the read path
+ */
+ if (s->injournal && s->failed) {
+ if (test_bit(STRIPE_R5C_CACHING, &sh->state))
+ r5c_make_stripe_write_out(sh);
+ goto out;
+ }
+
for (i = disks; i--; )
if (fetch_block(sh, s, i, disks))
break;
+ }
+out:
set_bit(STRIPE_HANDLE, &sh->state);
}
break_stripe_batch_list(head_sh, STRIPE_EXPAND_SYNC_FLAGS);
}
+/*
+ * For RMW in write back cache, we need extra page in prexor to store the
+ * old data. This page is stored in dev->orig_page.
+ *
+ * This function checks whether we have data for prexor. The exact logic
+ * is:
+ * R5_UPTODATE && (!R5_InJournal || R5_OrigPageUPTDODATE)
+ */
+static inline bool uptodate_for_rmw(struct r5dev *dev)
+{
+ return (test_bit(R5_UPTODATE, &dev->flags)) &&
+ (!test_bit(R5_InJournal, &dev->flags) ||
+ test_bit(R5_OrigPageUPTDODATE, &dev->flags));
+}
+
static int handle_stripe_dirtying(struct r5conf *conf,
struct stripe_head *sh,
struct stripe_head_state *s,
} else for (i = disks; i--; ) {
/* would I have to read this buffer for read_modify_write */
struct r5dev *dev = &sh->dev[i];
- if ((dev->towrite || i == sh->pd_idx || i == sh->qd_idx ||
+ if (((dev->towrite && !delay_towrite(dev, s)) ||
+ i == sh->pd_idx || i == sh->qd_idx ||
test_bit(R5_InJournal, &dev->flags)) &&
!test_bit(R5_LOCKED, &dev->flags) &&
- !((test_bit(R5_UPTODATE, &dev->flags) &&
- (!test_bit(R5_InJournal, &dev->flags) ||
- dev->page != dev->orig_page)) ||
+ !(uptodate_for_rmw(dev) ||
test_bit(R5_Wantcompute, &dev->flags))) {
if (test_bit(R5_Insync, &dev->flags))
rmw++;
i != sh->pd_idx && i != sh->qd_idx &&
!test_bit(R5_LOCKED, &dev->flags) &&
!(test_bit(R5_UPTODATE, &dev->flags) ||
- test_bit(R5_InJournal, &dev->flags) ||
test_bit(R5_Wantcompute, &dev->flags))) {
if (test_bit(R5_Insync, &dev->flags))
rcw++;
for (i = disks; i--; ) {
struct r5dev *dev = &sh->dev[i];
- if ((dev->towrite ||
+ if (((dev->towrite && !delay_towrite(dev, s)) ||
i == sh->pd_idx || i == sh->qd_idx ||
test_bit(R5_InJournal, &dev->flags)) &&
!test_bit(R5_LOCKED, &dev->flags) &&
- !((test_bit(R5_UPTODATE, &dev->flags) &&
- (!test_bit(R5_InJournal, &dev->flags) ||
- dev->page != dev->orig_page)) ||
+ !(uptodate_for_rmw(dev) ||
test_bit(R5_Wantcompute, &dev->flags)) &&
test_bit(R5_Insync, &dev->flags)) {
if (test_bit(STRIPE_PREREAD_ACTIVE,
i != sh->pd_idx && i != sh->qd_idx &&
!test_bit(R5_LOCKED, &dev->flags) &&
!(test_bit(R5_UPTODATE, &dev->flags) ||
- test_bit(R5_InJournal, &dev->flags) ||
test_bit(R5_Wantcompute, &dev->flags))) {
rcw++;
if (test_bit(R5_Insync, &dev->flags) &&
/*
* 0 for a fully functional array, 1 or 2 for a degraded array.
*/
- mddev->degraded = calc_degraded(conf);
+ mddev->degraded = raid5_calc_degraded(conf);
if (has_failed(conf)) {
pr_crit("md/raid:%s: not enough operational devices (%d/%d failed)\n",
}
}
spin_lock_irqsave(&conf->device_lock, flags);
- mddev->degraded = calc_degraded(conf);
+ mddev->degraded = raid5_calc_degraded(conf);
spin_unlock_irqrestore(&conf->device_lock, flags);
print_raid5_conf(conf);
return count;
* pre and post number of devices.
*/
spin_lock_irqsave(&conf->device_lock, flags);
- mddev->degraded = calc_degraded(conf);
+ mddev->degraded = raid5_calc_degraded(conf);
spin_unlock_irqrestore(&conf->device_lock, flags);
}
mddev->raid_disks = conf->raid_disks;
} else {
int d;
spin_lock_irq(&conf->device_lock);
- mddev->degraded = calc_degraded(conf);
+ mddev->degraded = raid5_calc_degraded(conf);
spin_unlock_irq(&conf->device_lock);
for (d = conf->raid_disks ;
d < conf->raid_disks - mddev->delta_disks;
mddev->new_chunk_sectors = chunksect;
ret = setup_conf(mddev);
- if (!IS_ERR_VALUE(ret))
- clear_bit(MD_FAILFAST_SUPPORTED, &mddev->flags);
+ if (!IS_ERR(ret))
+ mddev_clear_unsupported_flags(mddev,
+ UNSUPPORTED_MDDEV_FLAGS);
return ret;
}
* data and parity being written are in the journal
* device
*/
+ R5_OrigPageUPTDODATE, /* with write back cache, we read old data into
+ * dev->orig_page for prexor. When this flag is
+ * set, orig_page contains latest data in the
+ * raid disk.
+ */
};
/*
extern struct stripe_head *
raid5_get_active_stripe(struct r5conf *conf, sector_t sector,
int previous, int noblock, int noquiesce);
+extern int raid5_calc_degraded(struct r5conf *conf);
extern int r5l_init_log(struct r5conf *conf, struct md_rdev *rdev);
extern void r5l_exit_log(struct r5l_log *log);
extern int r5l_write_stripe(struct r5l_log *log, struct stripe_head *head_sh);
extern void r5c_check_stripe_cache_usage(struct r5conf *conf);
extern void r5c_check_cached_full_stripe(struct r5conf *conf);
extern struct md_sysfs_entry r5c_journal_mode;
+extern void r5c_update_on_rdev_error(struct mddev *mddev);
#endif
#include "cec-priv.h"
-static int cec_report_features(struct cec_adapter *adap, unsigned int la_idx);
-static int cec_report_phys_addr(struct cec_adapter *adap, unsigned int la_idx);
+static void cec_fill_msg_report_features(struct cec_adapter *adap,
+ struct cec_msg *msg,
+ unsigned int la_idx);
/*
* 400 ms is the time it takes for one 16 byte message to be
/* Mark it as an error */
data->msg.tx_ts = ktime_get_ns();
- data->msg.tx_status = CEC_TX_STATUS_ERROR |
- CEC_TX_STATUS_MAX_RETRIES;
+ data->msg.tx_status |= CEC_TX_STATUS_ERROR |
+ CEC_TX_STATUS_MAX_RETRIES;
+ data->msg.tx_error_cnt++;
data->attempts = 0;
- data->msg.tx_error_cnt = 1;
/* Queue transmitted message for monitoring purposes */
cec_queue_msg_monitor(data->adap, &data->msg, 1);
[CEC_MSG_REQUEST_ARC_TERMINATION] = 2 | DIRECTED,
[CEC_MSG_TERMINATE_ARC] = 2 | DIRECTED,
[CEC_MSG_REQUEST_CURRENT_LATENCY] = 4 | BCAST,
- [CEC_MSG_REPORT_CURRENT_LATENCY] = 7 | BCAST,
+ [CEC_MSG_REPORT_CURRENT_LATENCY] = 6 | BCAST,
[CEC_MSG_CDC_MESSAGE] = 2 | BCAST,
};
for (i = 1; i < las->num_log_addrs; i++)
las->log_addr[i] = CEC_LOG_ADDR_INVALID;
}
+ for (i = las->num_log_addrs; i < CEC_MAX_LOG_ADDRS; i++)
+ las->log_addr[i] = CEC_LOG_ADDR_INVALID;
adap->is_configured = true;
adap->is_configuring = false;
cec_post_state_event(adap);
- mutex_unlock(&adap->lock);
+ /*
+ * Now post the Report Features and Report Physical Address broadcast
+ * messages. Note that these are non-blocking transmits, meaning that
+ * they are just queued up and once adap->lock is unlocked the main
+ * thread will kick in and start transmitting these.
+ *
+ * If after this function is done (but before one or more of these
+ * messages are actually transmitted) the CEC adapter is unconfigured,
+ * then any remaining messages will be dropped by the main thread.
+ */
for (i = 0; i < las->num_log_addrs; i++) {
+ struct cec_msg msg = {};
+
if (las->log_addr[i] == CEC_LOG_ADDR_INVALID ||
(las->flags & CEC_LOG_ADDRS_FL_CDC_ONLY))
continue;
- /*
- * Report Features must come first according
- * to CEC 2.0
- */
- if (las->log_addr[i] != CEC_LOG_ADDR_UNREGISTERED)
- cec_report_features(adap, i);
- cec_report_phys_addr(adap, i);
+ msg.msg[0] = (las->log_addr[i] << 4) | 0x0f;
+
+ /* Report Features must come first according to CEC 2.0 */
+ if (las->log_addr[i] != CEC_LOG_ADDR_UNREGISTERED &&
+ adap->log_addrs.cec_version >= CEC_OP_CEC_VERSION_2_0) {
+ cec_fill_msg_report_features(adap, &msg, i);
+ cec_transmit_msg_fh(adap, &msg, NULL, false);
+ }
+
+ /* Report Physical Address */
+ cec_msg_report_physical_addr(&msg, adap->phys_addr,
+ las->primary_device_type[i]);
+ dprintk(2, "config: la %d pa %x.%x.%x.%x\n",
+ las->log_addr[i],
+ cec_phys_addr_exp(adap->phys_addr));
+ cec_transmit_msg_fh(adap, &msg, NULL, false);
}
- for (i = las->num_log_addrs; i < CEC_MAX_LOG_ADDRS; i++)
- las->log_addr[i] = CEC_LOG_ADDR_INVALID;
- mutex_lock(&adap->lock);
adap->kthread_config = NULL;
- mutex_unlock(&adap->lock);
complete(&adap->config_completion);
+ mutex_unlock(&adap->lock);
return 0;
unconfigure:
/* High-level core CEC message handling */
-/* Transmit the Report Features message */
-static int cec_report_features(struct cec_adapter *adap, unsigned int la_idx)
+/* Fill in the Report Features message */
+static void cec_fill_msg_report_features(struct cec_adapter *adap,
+ struct cec_msg *msg,
+ unsigned int la_idx)
{
- struct cec_msg msg = { };
const struct cec_log_addrs *las = &adap->log_addrs;
const u8 *features = las->features[la_idx];
bool op_is_dev_features = false;
unsigned int idx;
- /* This is 2.0 and up only */
- if (adap->log_addrs.cec_version < CEC_OP_CEC_VERSION_2_0)
- return 0;
-
/* Report Features */
- msg.msg[0] = (las->log_addr[la_idx] << 4) | 0x0f;
- msg.len = 4;
- msg.msg[1] = CEC_MSG_REPORT_FEATURES;
- msg.msg[2] = adap->log_addrs.cec_version;
- msg.msg[3] = las->all_device_types[la_idx];
+ msg->msg[0] = (las->log_addr[la_idx] << 4) | 0x0f;
+ msg->len = 4;
+ msg->msg[1] = CEC_MSG_REPORT_FEATURES;
+ msg->msg[2] = adap->log_addrs.cec_version;
+ msg->msg[3] = las->all_device_types[la_idx];
/* Write RC Profiles first, then Device Features */
for (idx = 0; idx < ARRAY_SIZE(las->features[0]); idx++) {
- msg.msg[msg.len++] = features[idx];
+ msg->msg[msg->len++] = features[idx];
if ((features[idx] & CEC_OP_FEAT_EXT) == 0) {
if (op_is_dev_features)
break;
op_is_dev_features = true;
}
}
- return cec_transmit_msg(adap, &msg, false);
-}
-
-/* Transmit the Report Physical Address message */
-static int cec_report_phys_addr(struct cec_adapter *adap, unsigned int la_idx)
-{
- const struct cec_log_addrs *las = &adap->log_addrs;
- struct cec_msg msg = { };
-
- /* Report Physical Address */
- msg.msg[0] = (las->log_addr[la_idx] << 4) | 0x0f;
- cec_msg_report_physical_addr(&msg, adap->phys_addr,
- las->primary_device_type[la_idx]);
- dprintk(2, "config: la %d pa %x.%x.%x.%x\n",
- las->log_addr[la_idx],
- cec_phys_addr_exp(adap->phys_addr));
- return cec_transmit_msg(adap, &msg, false);
}
/* Transmit the Feature Abort message */
}
case CEC_MSG_GIVE_FEATURES:
- if (adap->log_addrs.cec_version >= CEC_OP_CEC_VERSION_2_0)
- return cec_report_features(adap, la_idx);
- return 0;
+ if (adap->log_addrs.cec_version < CEC_OP_CEC_VERSION_2_0)
+ return cec_feature_abort(adap, msg);
+ cec_fill_msg_report_features(adap, &tx_cec_msg, la_idx);
+ return cec_transmit_msg(adap, &tx_cec_msg, false);
default:
/*
skb_copy_from_linear_data(h->priv->ule_skb, dest_addr,
ETH_ALEN);
skb_pull(h->priv->ule_skb, ETH_ALEN);
+ } else {
+ /* dest_addr buffer is only valid if h->priv->ule_dbit == 0 */
+ eth_zero_addr(dest_addr);
}
/* Handle ULE Extension Headers. */
if (!h->priv->ule_bridged) {
skb_push(h->priv->ule_skb, ETH_HLEN);
h->ethh = (struct ethhdr *)h->priv->ule_skb->data;
- if (!h->priv->ule_dbit) {
- /*
- * dest_addr buffer is only valid if
- * h->priv->ule_dbit == 0
- */
- memcpy(h->ethh->h_dest, dest_addr, ETH_ALEN);
- eth_zero_addr(h->ethh->h_source);
- } else /* zeroize source and dest */
- memset(h->ethh, 0, ETH_ALEN * 2);
-
+ memcpy(h->ethh->h_dest, dest_addr, ETH_ALEN);
+ eth_zero_addr(h->ethh->h_source);
h->ethh->h_proto = htons(h->priv->ule_sndu_type);
}
/* else: skb is in correct state; nothing to do. */
config VIDEO_S5K4ECGX
tristate "Samsung S5K4ECGX sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+ select CRC32
---help---
This is a V4L2 sensor-level driver for Samsung S5K4ECGX 5M
camera sensor with an embedded SoC image signal processor.
* I2C Driver
*/
-#ifdef CONFIG_PM
-
-static int smiapp_suspend(struct device *dev)
+static int __maybe_unused smiapp_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct v4l2_subdev *subdev = i2c_get_clientdata(client);
return 0;
}
-static int smiapp_resume(struct device *dev)
+static int __maybe_unused smiapp_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct v4l2_subdev *subdev = i2c_get_clientdata(client);
return rval;
}
-#else
-
-#define smiapp_suspend NULL
-#define smiapp_resume NULL
-
-#endif /* CONFIG_PM */
-
static struct smiapp_hwconfig *smiapp_get_hwconfig(struct device *dev)
{
struct smiapp_hwconfig *hwcfg;
if (IS_ERR(sensor->xshutdown))
return PTR_ERR(sensor->xshutdown);
- pm_runtime_enable(&client->dev);
-
- rval = pm_runtime_get_sync(&client->dev);
- if (rval < 0) {
- rval = -ENODEV;
- goto out_power_off;
- }
+ rval = smiapp_power_on(&client->dev);
+ if (rval < 0)
+ return rval;
rval = smiapp_identify_module(sensor);
if (rval) {
if (rval < 0)
goto out_media_entity_cleanup;
+ pm_runtime_set_active(&client->dev);
+ pm_runtime_get_noresume(&client->dev);
+ pm_runtime_enable(&client->dev);
pm_runtime_set_autosuspend_delay(&client->dev, 1000);
pm_runtime_use_autosuspend(&client->dev);
pm_runtime_put_autosuspend(&client->dev);
smiapp_cleanup(sensor);
out_power_off:
- pm_runtime_put(&client->dev);
- pm_runtime_disable(&client->dev);
+ smiapp_power_off(&client->dev);
return rval;
}
v4l2_async_unregister_subdev(subdev);
- pm_runtime_suspend(&client->dev);
pm_runtime_disable(&client->dev);
+ if (!pm_runtime_status_suspended(&client->dev))
+ smiapp_power_off(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
for (i = 0; i < sensor->ssds_used; i++) {
v4l2_device_unregister_subdev(&sensor->ssds[i].sd);
tvp5150_write(sd, TVP5150_OP_MODE_CTL, opmode);
tvp5150_write(sd, TVP5150_VD_IN_SRC_SEL_1, input);
- /* Svideo should enable YCrCb output and disable GPCL output
- * For Composite and TV, it should be the reverse
+ /*
+ * Setup the FID/GLCO/VLK/HVLK and INTREQ/GPCL/VBLK output signals. For
+ * S-Video we output the vertical lock (VLK) signal on FID/GLCO/VLK/HVLK
+ * and set INTREQ/GPCL/VBLK to logic 0. For composite we output the
+ * field indicator (FID) signal on FID/GLCO/VLK/HVLK and set
+ * INTREQ/GPCL/VBLK to logic 1.
*/
val = tvp5150_read(sd, TVP5150_MISC_CTL);
if (val < 0) {
}
if (decoder->input == TVP5150_SVIDEO)
- val = (val & ~0x40) | 0x10;
+ val = (val & ~TVP5150_MISC_CTL_GPCL) | TVP5150_MISC_CTL_HVLK;
else
- val = (val & ~0x10) | 0x40;
+ val = (val & ~TVP5150_MISC_CTL_HVLK) | TVP5150_MISC_CTL_GPCL;
tvp5150_write(sd, TVP5150_MISC_CTL, val);
};
},{ /* Automatic offset and AGC enabled */
TVP5150_ANAL_CHL_CTL, 0x15
},{ /* Activate YCrCb output 0x9 or 0xd ? */
- TVP5150_MISC_CTL, 0x6f
+ TVP5150_MISC_CTL, TVP5150_MISC_CTL_GPCL |
+ TVP5150_MISC_CTL_INTREQ_OE |
+ TVP5150_MISC_CTL_YCBCR_OE |
+ TVP5150_MISC_CTL_SYNC_OE |
+ TVP5150_MISC_CTL_VBLANK |
+ TVP5150_MISC_CTL_CLOCK_OE,
},{ /* Activates video std autodetection for all standards */
TVP5150_AUTOSW_MSK, 0x0
},{ /* Default format: 0x47. For 4:2:2: 0x40 */
f = &format->format;
- tvp5150_reset(sd, 0);
-
f->width = decoder->rect.width;
f->height = decoder->rect.height / 2;
static int tvp5150_s_stream(struct v4l2_subdev *sd, int enable)
{
struct tvp5150 *decoder = to_tvp5150(sd);
- /* Output format: 8-bit ITU-R BT.656 with embedded syncs */
- int val = 0x09;
-
- /* Output format: 8-bit 4:2:2 YUV with discrete sync */
- if (decoder->mbus_type == V4L2_MBUS_PARALLEL)
- val = 0x0d;
+ int val;
- /* Initializes TVP5150 to its default values */
- /* # set PCLK (27MHz) */
- tvp5150_write(sd, TVP5150_CONF_SHARED_PIN, 0x00);
+ /* Enable or disable the video output signals. */
+ val = tvp5150_read(sd, TVP5150_MISC_CTL);
+ if (val < 0)
+ return val;
+
+ val &= ~(TVP5150_MISC_CTL_YCBCR_OE | TVP5150_MISC_CTL_SYNC_OE |
+ TVP5150_MISC_CTL_CLOCK_OE);
+
+ if (enable) {
+ /*
+ * Enable the YCbCr and clock outputs. In discrete sync mode
+ * (non-BT.656) additionally enable the the sync outputs.
+ */
+ val |= TVP5150_MISC_CTL_YCBCR_OE | TVP5150_MISC_CTL_CLOCK_OE;
+ if (decoder->mbus_type == V4L2_MBUS_PARALLEL)
+ val |= TVP5150_MISC_CTL_SYNC_OE;
+ }
- if (enable)
- tvp5150_write(sd, TVP5150_MISC_CTL, val);
- else
- tvp5150_write(sd, TVP5150_MISC_CTL, 0x00);
+ tvp5150_write(sd, TVP5150_MISC_CTL, val);
return 0;
}
res = core->hdl.error;
goto err;
}
- v4l2_ctrl_handler_setup(&core->hdl);
/* Default is no cropping */
core->rect.top = 0;
core->rect.left = 0;
core->rect.width = TVP5150_H_MAX;
+ tvp5150_reset(sd, 0); /* Calls v4l2_ctrl_handler_setup() */
+
res = v4l2_async_register_subdev(sd);
if (res < 0)
goto err;
#define TVP5150_ANAL_CHL_CTL 0x01 /* Analog channel controls */
#define TVP5150_OP_MODE_CTL 0x02 /* Operation mode controls */
#define TVP5150_MISC_CTL 0x03 /* Miscellaneous controls */
+#define TVP5150_MISC_CTL_VBLK_GPCL BIT(7)
+#define TVP5150_MISC_CTL_GPCL BIT(6)
+#define TVP5150_MISC_CTL_INTREQ_OE BIT(5)
+#define TVP5150_MISC_CTL_HVLK BIT(4)
+#define TVP5150_MISC_CTL_YCBCR_OE BIT(3)
+#define TVP5150_MISC_CTL_SYNC_OE BIT(2)
+#define TVP5150_MISC_CTL_VBLANK BIT(1)
+#define TVP5150_MISC_CTL_CLOCK_OE BIT(0)
+
#define TVP5150_AUTOSW_MSK 0x04 /* Autoswitch mask: TVP5150A / TVP5150AM */
/* Reserved 05h */
static void cobalt_free_msi(struct cobalt *cobalt, struct pci_dev *pci_dev)
{
free_irq(pci_dev->irq, (void *)cobalt);
-
- if (cobalt->msi_enabled)
- pci_disable_msi(pci_dev);
+ pci_free_irq_vectors(pci_dev);
}
static int cobalt_setup_pci(struct cobalt *cobalt, struct pci_dev *pci_dev,
from being generated. */
cobalt_set_interrupt(cobalt, false);
- if (pci_enable_msi_range(pci_dev, 1, 1) < 1) {
+ if (pci_alloc_irq_vectors(pci_dev, 1, 1, PCI_IRQ_MSI) < 1) {
cobalt_err("Could not enable MSI\n");
- cobalt->msi_enabled = false;
ret = -EIO;
goto err_release;
}
msi_config_show(cobalt, pci_dev);
- cobalt->msi_enabled = true;
/* Register IRQ */
if (request_irq(pci_dev->irq, cobalt_irq_handler, IRQF_SHARED,
u32 irq_none;
u32 irq_full_fifo;
- bool msi_enabled;
-
/* omnitek dma */
int dma_channels;
int first_fifo_channel;
u8 c; /* transaction counter, wraps around... */
u8 initialized; /* set to 1 if 0x15 has been sent */
u16 last_rc_key;
-
- unsigned char data[80];
};
static int tt3650_ci_msg(struct dvb_usb_device *d, u8 cmd, u8 *data,
unsigned int write_len, unsigned int read_len)
{
struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+ u8 *buf;
u8 id;
unsigned int rlen;
int ret;
return -EIO;
}
- mutex_lock(&state->ca_mutex);
+ buf = kmalloc(64, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
id = state->c++;
- state->data[0] = SYNC_BYTE_OUT;
- state->data[1] = id;
- state->data[2] = cmd;
- state->data[3] = write_len;
+ buf[0] = SYNC_BYTE_OUT;
+ buf[1] = id;
+ buf[2] = cmd;
+ buf[3] = write_len;
- memcpy(state->data + 4, data, write_len);
+ memcpy(buf + 4, data, write_len);
rlen = (read_len > 0) ? 64 : 0;
- ret = dvb_usb_generic_rw(d, state->data, 4 + write_len,
- state->data, rlen, /* delay_ms */ 0);
+ ret = dvb_usb_generic_rw(d, buf, 4 + write_len,
+ buf, rlen, /* delay_ms */ 0);
if (0 != ret)
goto failed;
ret = -EIO;
- if (SYNC_BYTE_IN != state->data[0] || id != state->data[1])
+ if (SYNC_BYTE_IN != buf[0] || id != buf[1])
goto failed;
- memcpy(data, state->data + 4, read_len);
+ memcpy(data, buf + 4, read_len);
- mutex_unlock(&state->ca_mutex);
+ kfree(buf);
return 0;
failed:
err("CI error %d; %02X %02X %02X -> %*ph.",
- ret, SYNC_BYTE_OUT, id, cmd, 3, state->data);
+ ret, SYNC_BYTE_OUT, id, cmd, 3, buf);
- mutex_unlock(&state->ca_mutex);
+ kfree(buf);
return ret;
}
u8 *rcv_buf, u8 rcv_len)
{
struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+ u8 *buf;
u8 id;
int ret;
- mutex_lock(&state->ca_mutex);
+ buf = kmalloc(64, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
id = state->c++;
ret = -EINVAL;
if (snd_len > 64 - 7 || rcv_len > 64 - 7)
goto failed;
- state->data[0] = SYNC_BYTE_OUT;
- state->data[1] = id;
- state->data[2] = PCTV_CMD_I2C;
- state->data[3] = snd_len + 3;
- state->data[4] = addr << 1;
- state->data[5] = snd_len;
- state->data[6] = rcv_len;
+ buf[0] = SYNC_BYTE_OUT;
+ buf[1] = id;
+ buf[2] = PCTV_CMD_I2C;
+ buf[3] = snd_len + 3;
+ buf[4] = addr << 1;
+ buf[5] = snd_len;
+ buf[6] = rcv_len;
- memcpy(state->data + 7, snd_buf, snd_len);
+ memcpy(buf + 7, snd_buf, snd_len);
- ret = dvb_usb_generic_rw(d, state->data, 7 + snd_len,
- state->data, /* rcv_len */ 64,
+ ret = dvb_usb_generic_rw(d, buf, 7 + snd_len,
+ buf, /* rcv_len */ 64,
/* delay_ms */ 0);
if (ret < 0)
goto failed;
/* TT USB protocol error. */
ret = -EIO;
- if (SYNC_BYTE_IN != state->data[0] || id != state->data[1])
+ if (SYNC_BYTE_IN != buf[0] || id != buf[1])
goto failed;
/* I2C device didn't respond as expected. */
ret = -EREMOTEIO;
- if (state->data[5] < snd_len || state->data[6] < rcv_len)
+ if (buf[5] < snd_len || buf[6] < rcv_len)
goto failed;
- memcpy(rcv_buf, state->data + 7, rcv_len);
- mutex_unlock(&state->ca_mutex);
+ memcpy(rcv_buf, buf + 7, rcv_len);
+ kfree(buf);
return rcv_len;
failed:
err("I2C error %d; %02X %02X %02X %02X %02X -> %*ph",
ret, SYNC_BYTE_OUT, id, addr << 1, snd_len, rcv_len,
- 7, state->data);
+ 7, buf);
- mutex_unlock(&state->ca_mutex);
+ kfree(buf);
return ret;
}
static int pctv452e_power_ctrl(struct dvb_usb_device *d, int i)
{
struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
- u8 *rx;
+ u8 *b0, *rx;
int ret;
info("%s: %d\n", __func__, i);
if (state->initialized)
return 0;
- rx = kmalloc(PCTV_ANSWER_LEN, GFP_KERNEL);
- if (!rx)
+ b0 = kmalloc(5 + PCTV_ANSWER_LEN, GFP_KERNEL);
+ if (!b0)
return -ENOMEM;
- mutex_lock(&state->ca_mutex);
+ rx = b0 + 5;
+
/* hmm where shoud this should go? */
ret = usb_set_interface(d->udev, 0, ISOC_INTERFACE_ALTERNATIVE);
if (ret != 0)
__func__, ret);
/* this is a one-time initialization, dont know where to put */
- state->data[0] = 0xaa;
- state->data[1] = state->c++;
- state->data[2] = PCTV_CMD_RESET;
- state->data[3] = 1;
- state->data[4] = 0;
+ b0[0] = 0xaa;
+ b0[1] = state->c++;
+ b0[2] = PCTV_CMD_RESET;
+ b0[3] = 1;
+ b0[4] = 0;
/* reset board */
- ret = dvb_usb_generic_rw(d, state->data, 5, rx, PCTV_ANSWER_LEN, 0);
+ ret = dvb_usb_generic_rw(d, b0, 5, rx, PCTV_ANSWER_LEN, 0);
if (ret)
goto ret;
- state->data[1] = state->c++;
- state->data[4] = 1;
+ b0[1] = state->c++;
+ b0[4] = 1;
/* reset board (again?) */
- ret = dvb_usb_generic_rw(d, state->data, 5, rx, PCTV_ANSWER_LEN, 0);
+ ret = dvb_usb_generic_rw(d, b0, 5, rx, PCTV_ANSWER_LEN, 0);
if (ret)
goto ret;
state->initialized = 1;
ret:
- mutex_unlock(&state->ca_mutex);
- kfree(rx);
+ kfree(b0);
return ret;
}
static int pctv452e_rc_query(struct dvb_usb_device *d)
{
struct pctv452e_state *state = (struct pctv452e_state *)d->priv;
+ u8 *b, *rx;
int ret, i;
u8 id;
- mutex_lock(&state->ca_mutex);
+ b = kmalloc(CMD_BUFFER_SIZE + PCTV_ANSWER_LEN, GFP_KERNEL);
+ if (!b)
+ return -ENOMEM;
+
+ rx = b + CMD_BUFFER_SIZE;
+
id = state->c++;
/* prepare command header */
- state->data[0] = SYNC_BYTE_OUT;
- state->data[1] = id;
- state->data[2] = PCTV_CMD_IR;
- state->data[3] = 0;
+ b[0] = SYNC_BYTE_OUT;
+ b[1] = id;
+ b[2] = PCTV_CMD_IR;
+ b[3] = 0;
/* send ir request */
- ret = dvb_usb_generic_rw(d, state->data, 4,
- state->data, PCTV_ANSWER_LEN, 0);
+ ret = dvb_usb_generic_rw(d, b, 4, rx, PCTV_ANSWER_LEN, 0);
if (ret != 0)
goto ret;
if (debug > 3) {
- info("%s: read: %2d: %*ph: ", __func__, ret, 3, state->data);
- for (i = 0; (i < state->data[3]) && ((i + 3) < PCTV_ANSWER_LEN); i++)
- info(" %02x", state->data[i + 3]);
+ info("%s: read: %2d: %*ph: ", __func__, ret, 3, rx);
+ for (i = 0; (i < rx[3]) && ((i+3) < PCTV_ANSWER_LEN); i++)
+ info(" %02x", rx[i+3]);
info("\n");
}
- if ((state->data[3] == 9) && (state->data[12] & 0x01)) {
+ if ((rx[3] == 9) && (rx[12] & 0x01)) {
/* got a "press" event */
- state->last_rc_key = RC_SCANCODE_RC5(state->data[7], state->data[6]);
+ state->last_rc_key = RC_SCANCODE_RC5(rx[7], rx[6]);
if (debug > 2)
info("%s: cmd=0x%02x sys=0x%02x\n",
- __func__, state->data[6], state->data[7]);
+ __func__, rx[6], rx[7]);
rc_keydown(d->rc_dev, RC_TYPE_RC5, state->last_rc_key, 0);
} else if (state->last_rc_key) {
state->last_rc_key = 0;
}
ret:
- mutex_unlock(&state->ca_mutex);
+ kfree(b);
return ret;
}
struct ms_id_register id_reg;
if (!(*mrq)) {
- memstick_init_req(&card->current_mrq, MS_TPC_READ_REG, NULL,
+ memstick_init_req(&card->current_mrq, MS_TPC_READ_REG, &id_reg,
sizeof(struct ms_id_register));
*mrq = &card->current_mrq;
return 0;
in various ST Microelectronics and ST-Ericsson embedded
Nomadik series.
+config MFD_STM32_TIMERS
+ tristate "Support for STM32 Timers"
+ depends on (ARCH_STM32 && OF) || COMPILE_TEST
+ select MFD_CORE
+ select REGMAP
+ select REGMAP_MMIO
+ help
+ Select this option to enable STM32 timers driver used
+ for PWM and IIO Timer. This driver allow to share the
+ registers between the others drivers.
+
menu "Multimedia Capabilities Port drivers"
depends on ARCH_SA1100
obj-$(CONFIG_MFD_ALTERA_A10SR) += altera-a10sr.o
obj-$(CONFIG_MFD_SUN4I_GPADC) += sun4i-gpadc.o
+
+obj-$(CONFIG_MFD_STM32_TIMERS) += stm32-timers.o
--- /dev/null
+/*
+ * Copyright (C) STMicroelectronics 2016
+ *
+ * Author: Benjamin Gaignard <benjamin.gaignard@st.com>
+ *
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#include <linux/mfd/stm32-timers.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/reset.h>
+
+static const struct regmap_config stm32_timers_regmap_cfg = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = sizeof(u32),
+ .max_register = 0x400,
+};
+
+static void stm32_timers_get_arr_size(struct stm32_timers *ddata)
+{
+ /*
+ * Only the available bits will be written so when readback
+ * we get the maximum value of auto reload register
+ */
+ regmap_write(ddata->regmap, TIM_ARR, ~0L);
+ regmap_read(ddata->regmap, TIM_ARR, &ddata->max_arr);
+ regmap_write(ddata->regmap, TIM_ARR, 0x0);
+}
+
+static int stm32_timers_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct stm32_timers *ddata;
+ struct resource *res;
+ void __iomem *mmio;
+
+ ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
+ if (!ddata)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mmio = devm_ioremap_resource(dev, res);
+ if (IS_ERR(mmio))
+ return PTR_ERR(mmio);
+
+ ddata->regmap = devm_regmap_init_mmio_clk(dev, "int", mmio,
+ &stm32_timers_regmap_cfg);
+ if (IS_ERR(ddata->regmap))
+ return PTR_ERR(ddata->regmap);
+
+ ddata->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(ddata->clk))
+ return PTR_ERR(ddata->clk);
+
+ stm32_timers_get_arr_size(ddata);
+
+ platform_set_drvdata(pdev, ddata);
+
+ return of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+}
+
+static const struct of_device_id stm32_timers_of_match[] = {
+ { .compatible = "st,stm32-timers", },
+ { /* end node */ },
+};
+MODULE_DEVICE_TABLE(of, stm32_timers_of_match);
+
+static struct platform_driver stm32_timers_driver = {
+ .probe = stm32_timers_probe,
+ .driver = {
+ .name = "stm32-timers",
+ .of_match_table = stm32_timers_of_match,
+ },
+};
+module_platform_driver(stm32_timers_driver);
+
+MODULE_DESCRIPTION("STMicroelectronics STM32 Timers");
+MODULE_LICENSE("GPL v2");
{
int ret;
+ if (!cldev->bus->hbm_f_os_supported)
+ return;
+
ret = mei_cldev_enable(cldev);
if (ret)
return;
dev->hbm_f_ev_supported);
pos += scnprintf(buf + pos, bufsz - pos, "\tFA: %01d\n",
dev->hbm_f_fa_supported);
+ pos += scnprintf(buf + pos, bufsz - pos, "\tOS: %01d\n",
+ dev->hbm_f_os_supported);
}
pos += scnprintf(buf + pos, bufsz - pos, "pg: %s, %s\n",
/* Fixed Address Client Support */
if (dev->version.major_version >= HBM_MAJOR_VERSION_FA)
dev->hbm_f_fa_supported = 1;
+
+ /* OS ver message Support */
+ if (dev->version.major_version >= HBM_MAJOR_VERSION_OS)
+ dev->hbm_f_os_supported = 1;
}
/**
#define HBM_MINOR_VERSION_FA 0
#define HBM_MAJOR_VERSION_FA 2
+/*
+ * MEI version with OS ver message support
+ */
+#define HBM_MINOR_VERSION_OS 0
+#define HBM_MAJOR_VERSION_OS 2
+
/* Host bus message command opcode */
#define MEI_HBM_CMD_OP_MSK 0x7f
/* Host bus message command RESPONSE */
* @hbm_f_ev_supported : hbm feature event notification
* @hbm_f_fa_supported : hbm feature fixed address client
* @hbm_f_ie_supported : hbm feature immediate reply to enum request
+ * @hbm_f_os_supported : hbm feature support OS ver message
*
* @me_clients_rwsem: rw lock over me_clients list
* @me_clients : list of FW clients
unsigned int hbm_f_ev_supported:1;
unsigned int hbm_f_fa_supported:1;
unsigned int hbm_f_ie_supported:1;
+ unsigned int hbm_f_os_supported:1;
struct rw_semaphore me_clients_rwsem;
struct list_head me_clients;
}
} while (busy);
- if (host->ops->card_busy && send_status)
- return mmc_switch_status(card);
-
return 0;
}
if (!use_busy_signal)
goto out;
- /* Switch to new timing before poll and check switch status. */
- if (timing)
- mmc_set_timing(host, timing);
-
/*If SPI or used HW busy detection above, then we don't need to poll. */
if (((host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp) ||
- mmc_host_is_spi(host)) {
- if (send_status)
- err = mmc_switch_status(card);
+ mmc_host_is_spi(host))
goto out_tim;
- }
/* Let's try to poll to find out when the command is completed. */
err = mmc_poll_for_busy(card, timeout_ms, send_status, retry_crc_err);
+ if (err)
+ goto out;
out_tim:
- if (err && timing)
- mmc_set_timing(host, old_timing);
+ /* Switch to new timing before check switch status. */
+ if (timing)
+ mmc_set_timing(host, timing);
+
+ if (send_status) {
+ err = mmc_switch_status(card);
+ if (err && timing)
+ mmc_set_timing(host, old_timing);
+ }
out:
mmc_retune_release(host);
if (!slot)
continue;
- if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER) {
+ if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER)
dw_mci_set_ios(slot->mmc, &slot->mmc->ios);
- dw_mci_setup_bus(slot, true);
- }
+
+ /* Force setup bus to guarantee available clock output */
+ dw_mci_setup_bus(slot, true);
}
/* Now that slots are all setup, we can enable card detect */
{
struct meson_host *host = dev_id;
struct mmc_request *mrq;
- struct mmc_command *cmd = host->cmd;
+ struct mmc_command *cmd;
u32 irq_en, status, raw_status;
irqreturn_t ret = IRQ_HANDLED;
if (WARN_ON(!host))
return IRQ_NONE;
+ cmd = host->cmd;
+
mrq = host->mrq;
if (WARN_ON(!mrq))
int ret = IRQ_HANDLED;
if (WARN_ON(!mrq))
- ret = IRQ_NONE;
+ return IRQ_NONE;
if (WARN_ON(!cmd))
- ret = IRQ_NONE;
+ return IRQ_NONE;
data = cmd->data;
if (data) {
cmd0 = BF_SSP(cmd->opcode, CMD0_CMD);
cmd1 = cmd->arg;
+ if (cmd->opcode == MMC_STOP_TRANSMISSION)
+ cmd0 |= BM_SSP_CMD0_APPEND_8CYC;
+
if (host->sdio_irq_en) {
ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK;
cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN | BM_SSP_CMD0_SLOW_CLKING_EN;
ssp->base + HW_SSP_BLOCK_SIZE);
}
- if ((cmd->opcode == MMC_STOP_TRANSMISSION) ||
- (cmd->opcode == SD_IO_RW_EXTENDED))
+ if (cmd->opcode == SD_IO_RW_EXTENDED)
cmd0 |= BM_SSP_CMD0_APPEND_8CYC;
cmd1 = cmd->arg;
/* Power on the SDHCI controller and its children */
acpi_device_fix_up_power(device);
list_for_each_entry(child, &device->children, node)
- acpi_device_fix_up_power(child);
+ if (child->status.present && child->status.enabled)
+ acpi_device_fix_up_power(child);
if (acpi_bus_get_status(device) || !device->status.present)
return -ENODEV;
if (intmask & SDHCI_INT_RETUNE)
mmc_retune_needed(host->mmc);
- if (intmask & SDHCI_INT_CARD_INT) {
+ if ((intmask & SDHCI_INT_CARD_INT) &&
+ (host->ier & SDHCI_INT_CARD_INT)) {
sdhci_enable_sdio_irq_nolock(host, false);
host->thread_isr |= SDHCI_INT_CARD_INT;
result = IRQ_WAKE_THREAD;
config MTD_NAND_OXNAS
tristate "NAND Flash support for Oxford Semiconductor SoC"
+ depends on HAS_IOMEM
help
This enables the NAND flash controller on Oxford Semiconductor SoCs.
Flexible Static Memory Controller (FSMC)
config MTD_NAND_XWAY
- tristate "Support for NAND on Lantiq XWAY SoC"
+ bool "Support for NAND on Lantiq XWAY SoC"
depends on LANTIQ && SOC_TYPE_XWAY
help
Enables support for NAND Flash chips on Lantiq XWAY SoCs. NAND is attached
init_completion(&host->comp_controller);
host->irq = platform_get_irq(pdev, 0);
- if ((host->irq < 0) || (host->irq >= NR_IRQS)) {
+ if (host->irq < 0) {
dev_err(&pdev->dev, "failed to get platform irq\n");
res = -EINVAL;
goto err_exit3;
if (IS_ERR(nfc->pbus_base))
return PTR_ERR(nfc->pbus_base);
+ writel_relaxed(MODE_RAW, nfc->pbus_base + PBUS_PAD_MODE);
+
clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(clk))
return PTR_ERR(clk);
- nfc->chan = dma_request_chan(&pdev->dev, "nfc_sbox");
+ nfc->chan = dma_request_chan(&pdev->dev, "rxtx");
if (IS_ERR(nfc->chan))
return PTR_ERR(nfc->chan);
{ .compatible = "lantiq,nand-xway" },
{},
};
-MODULE_DEVICE_TABLE(of, xway_nand_match);
static struct platform_driver xway_nand_driver = {
.probe = xway_nand_probe,
},
};
-module_platform_driver(xway_nand_driver);
-
-MODULE_LICENSE("GPL");
+builtin_platform_driver(xway_nand_driver);
*/
static int ipddp_create(struct ipddp_route *new_rt)
{
- struct ipddp_route *rt = kmalloc(sizeof(*rt), GFP_KERNEL);
+ struct ipddp_route *rt = kzalloc(sizeof(*rt), GFP_KERNEL);
if (rt == NULL)
return -ENOMEM;
dev->irq = pdev->irq;
priv->base = addr;
+ priv->device = &pdev->dev;
if (!c_can_pci_data->freq) {
dev_err(&pdev->dev, "no clock frequency defined\n");
netif_napi_add(ndev, &priv->napi, ti_hecc_rx_poll,
HECC_DEF_NAPI_WEIGHT);
- clk_enable(priv->clk);
+ err = clk_prepare_enable(priv->clk);
+ if (err) {
+ dev_err(&pdev->dev, "clk_prepare_enable() failed\n");
+ goto probe_exit_clk;
+ }
+
err = register_candev(ndev);
if (err) {
dev_err(&pdev->dev, "register_candev() failed\n");
struct ti_hecc_priv *priv = netdev_priv(ndev);
unregister_candev(ndev);
- clk_disable(priv->clk);
+ clk_disable_unprepare(priv->clk);
clk_put(priv->clk);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
iounmap(priv->base);
hecc_set_bit(priv, HECC_CANMC, HECC_CANMC_PDR);
priv->can.state = CAN_STATE_SLEEPING;
- clk_disable(priv->clk);
+ clk_disable_unprepare(priv->clk);
return 0;
}
{
struct net_device *dev = platform_get_drvdata(pdev);
struct ti_hecc_priv *priv = netdev_priv(dev);
+ int err;
- clk_enable(priv->clk);
+ err = clk_prepare_enable(priv->clk);
+ if (err)
+ return err;
hecc_clear_bit(priv, HECC_CANMC, HECC_CANMC_PDR);
priv->can.state = CAN_STATE_ERROR_ACTIVE;
if (addr == BRCM_PSEUDO_PHY_ADDR && priv->indir_phy_mask & BIT(addr))
return bcm_sf2_sw_indir_rw(priv, 1, addr, regnum, 0);
else
- return mdiobus_read(priv->master_mii_bus, addr, regnum);
+ return mdiobus_read_nested(priv->master_mii_bus, addr, regnum);
}
static int bcm_sf2_sw_mdio_write(struct mii_bus *bus, int addr, int regnum,
if (addr == BRCM_PSEUDO_PHY_ADDR && priv->indir_phy_mask & BIT(addr))
bcm_sf2_sw_indir_rw(priv, 0, addr, regnum, val);
else
- mdiobus_write(priv->master_mii_bus, addr, regnum, val);
+ mdiobus_write_nested(priv->master_mii_bus, addr, regnum, val);
return 0;
}
const char *reg_names[BCM_SF2_REGS_NUM] = BCM_SF2_REGS_NAME;
struct device_node *dn = pdev->dev.of_node;
struct b53_platform_data *pdata;
+ struct dsa_switch_ops *ops;
struct bcm_sf2_priv *priv;
struct b53_device *dev;
struct dsa_switch *ds;
if (!priv)
return -ENOMEM;
+ ops = devm_kzalloc(&pdev->dev, sizeof(*ops), GFP_KERNEL);
+ if (!ops)
+ return -ENOMEM;
+
dev = b53_switch_alloc(&pdev->dev, &bcm_sf2_io_ops, priv);
if (!dev)
return -ENOMEM;
ds = dev->ds;
/* Override the parts that are non-standard wrt. normal b53 devices */
+ memcpy(ops, ds->ops, sizeof(*ops));
+ ds->ops = ops;
ds->ops->get_tag_protocol = bcm_sf2_sw_get_tag_protocol;
ds->ops->setup = bcm_sf2_sw_setup;
ds->ops->get_phy_flags = bcm_sf2_sw_get_phy_flags;
if (skb == NULL)
break;
np->rx_info[i].mapping = pci_map_single(np->pci_dev, skb->data, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ if (pci_dma_mapping_error(np->pci_dev,
+ np->rx_info[i].mapping)) {
+ dev_kfree_skb(skb);
+ np->rx_info[i].skb = NULL;
+ break;
+ }
/* Grrr, we cannot offset to correctly align the IP header. */
np->rx_ring[i].rxaddr = cpu_to_dma(np->rx_info[i].mapping | RxDescValid);
}
{
struct netdev_private *np = netdev_priv(dev);
unsigned int entry;
+ unsigned int prev_tx;
u32 status;
- int i;
+ int i, j;
/*
* be cautious here, wrapping the queue has weird semantics
}
#endif /* ZEROCOPY && HAS_BROKEN_FIRMWARE */
+ prev_tx = np->cur_tx;
entry = np->cur_tx % TX_RING_SIZE;
for (i = 0; i < skb_num_frags(skb); i++) {
int wrap_ring = 0;
skb_frag_size(this_frag),
PCI_DMA_TODEVICE);
}
+ if (pci_dma_mapping_error(np->pci_dev,
+ np->tx_info[entry].mapping)) {
+ dev->stats.tx_dropped++;
+ goto err_out;
+ }
np->tx_ring[entry].addr = cpu_to_dma(np->tx_info[entry].mapping);
np->tx_ring[entry].status = cpu_to_le32(status);
netif_stop_queue(dev);
return NETDEV_TX_OK;
-}
+err_out:
+ entry = prev_tx % TX_RING_SIZE;
+ np->tx_info[entry].skb = NULL;
+ if (i > 0) {
+ pci_unmap_single(np->pci_dev,
+ np->tx_info[entry].mapping,
+ skb_first_frag_len(skb),
+ PCI_DMA_TODEVICE);
+ np->tx_info[entry].mapping = 0;
+ entry = (entry + np->tx_info[entry].used_slots) % TX_RING_SIZE;
+ for (j = 1; j < i; j++) {
+ pci_unmap_single(np->pci_dev,
+ np->tx_info[entry].mapping,
+ skb_frag_size(
+ &skb_shinfo(skb)->frags[j-1]),
+ PCI_DMA_TODEVICE);
+ entry++;
+ }
+ }
+ dev_kfree_skb_any(skb);
+ np->cur_tx = prev_tx;
+ return NETDEV_TX_OK;
+}
/* The interrupt handler does all of the Rx thread work and cleans up
after the Tx thread. */
break; /* Better luck next round. */
np->rx_info[entry].mapping =
pci_map_single(np->pci_dev, skb->data, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ if (pci_dma_mapping_error(np->pci_dev,
+ np->rx_info[entry].mapping)) {
+ dev_kfree_skb(skb);
+ np->rx_info[entry].skb = NULL;
+ break;
+ }
np->rx_ring[entry].rxaddr =
cpu_to_dma(np->rx_info[entry].mapping | RxDescValid);
}
#define PCS_V1_WINDOW_SELECT 0x03fc
#define PCS_V2_WINDOW_DEF 0x9060
#define PCS_V2_WINDOW_SELECT 0x9064
+#define PCS_V2_RV_WINDOW_DEF 0x1060
+#define PCS_V2_RV_WINDOW_SELECT 0x1064
/* PCS register entry bit positions and sizes */
#define PCS_V2_WINDOW_DEF_OFFSET_INDEX 6
offset = pdata->xpcs_window + (mmd_address & pdata->xpcs_window_mask);
spin_lock_irqsave(&pdata->xpcs_lock, flags);
- XPCS32_IOWRITE(pdata, PCS_V2_WINDOW_SELECT, index);
+ XPCS32_IOWRITE(pdata, pdata->xpcs_window_sel_reg, index);
mmd_data = XPCS16_IOREAD(pdata, offset);
spin_unlock_irqrestore(&pdata->xpcs_lock, flags);
offset = pdata->xpcs_window + (mmd_address & pdata->xpcs_window_mask);
spin_lock_irqsave(&pdata->xpcs_lock, flags);
- XPCS32_IOWRITE(pdata, PCS_V2_WINDOW_SELECT, index);
+ XPCS32_IOWRITE(pdata, pdata->xpcs_window_sel_reg, index);
XPCS16_IOWRITE(pdata, offset, mmd_data);
spin_unlock_irqrestore(&pdata->xpcs_lock, flags);
}
/* Flush Tx queues */
ret = xgbe_flush_tx_queues(pdata);
- if (ret)
+ if (ret) {
+ netdev_err(pdata->netdev, "error flushing TX queues\n");
return ret;
+ }
/*
* Initialize DMA related features
}
}
+isr_done:
/* If there is not a separate AN irq, handle it here */
if (pdata->dev_irq == pdata->an_irq)
pdata->phy_if.an_isr(irq, pdata);
if (pdata->vdata->i2c_support && (pdata->dev_irq == pdata->i2c_irq))
pdata->i2c_if.i2c_isr(irq, pdata);
-isr_done:
return IRQ_HANDLED;
}
DBGPR("-->xgbe_start\n");
- hw_if->init(pdata);
+ ret = hw_if->init(pdata);
+ if (ret)
+ return ret;
xgbe_napi_enable(pdata, 1);
struct xgbe_prv_data *pdata;
struct device *dev = &pdev->dev;
void __iomem * const *iomap_table;
+ struct pci_dev *rdev;
unsigned int ma_lo, ma_hi;
unsigned int reg;
int bar_mask;
if (netif_msg_probe(pdata))
dev_dbg(dev, "xpcs_regs = %p\n", pdata->xpcs_regs);
+ /* Set the PCS indirect addressing definition registers */
+ rdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0));
+ if (rdev &&
+ (rdev->vendor == PCI_VENDOR_ID_AMD) && (rdev->device == 0x15d0)) {
+ pdata->xpcs_window_def_reg = PCS_V2_RV_WINDOW_DEF;
+ pdata->xpcs_window_sel_reg = PCS_V2_RV_WINDOW_SELECT;
+ } else {
+ pdata->xpcs_window_def_reg = PCS_V2_WINDOW_DEF;
+ pdata->xpcs_window_sel_reg = PCS_V2_WINDOW_SELECT;
+ }
+ pci_dev_put(rdev);
+
/* Configure the PCS indirect addressing support */
- reg = XPCS32_IOREAD(pdata, PCS_V2_WINDOW_DEF);
+ reg = XPCS32_IOREAD(pdata, pdata->xpcs_window_def_reg);
pdata->xpcs_window = XPCS_GET_BITS(reg, PCS_V2_WINDOW_DEF, OFFSET);
pdata->xpcs_window <<= 6;
pdata->xpcs_window_size = XPCS_GET_BITS(reg, PCS_V2_WINDOW_DEF, SIZE);
/* XPCS indirect addressing lock */
spinlock_t xpcs_lock;
+ unsigned int xpcs_window_def_reg;
+ unsigned int xpcs_window_sel_reg;
unsigned int xpcs_window;
unsigned int xpcs_window_size;
unsigned int xpcs_window_mask;
return -ENOMEM;
}
- alx_reinit_rings(alx);
-
return 0;
}
if (alx->qnapi[0] && alx->qnapi[0]->rxq)
kfree(alx->qnapi[0]->rxq->bufs);
- if (!alx->descmem.virt)
+ if (alx->descmem.virt)
dma_free_coherent(&alx->hw.pdev->dev,
alx->descmem.size,
alx->descmem.virt,
alx_free_rings(alx);
alx_free_napis(alx);
alx_disable_advanced_intr(alx);
+ alx_init_intr(alx, false);
err = alx_alloc_napis(alx);
if (err)
if (err)
goto out_free_rings;
+ /* must be called after alx_request_irq because the chip stops working
+ * if we copy the dma addresses in alx_init_ring_ptrs twice when
+ * requesting msi-x interrupts failed
+ */
+ alx_reinit_rings(alx);
+
netif_set_real_num_tx_queues(alx->dev, alx->num_txq);
netif_set_real_num_rx_queues(alx->dev, alx->num_rxq);
priv->old_link = 0;
priv->old_duplex = -1;
priv->old_pause = -1;
+ } else {
+ phydev = NULL;
}
/* mask all interrupts and request them */
enet_dmac_writel(priv, priv->dma_chan_int_mask,
ENETDMAC_IRMASK, priv->tx_chan);
- if (priv->has_phy)
+ if (phydev)
phy_start(phydev);
else
bcm_enet_adjust_link(dev);
free_irq(dev->irq, dev);
out_phy_disconnect:
- if (priv->has_phy)
+ if (phydev)
phy_disconnect(phydev);
return ret;
unsigned int c_index, last_c_index, last_tx_cn, num_tx_cbs;
unsigned int pkts_compl = 0, bytes_compl = 0;
struct bcm_sysport_cb *cb;
- struct netdev_queue *txq;
u32 hw_ind;
- txq = netdev_get_tx_queue(ndev, ring->index);
-
/* Compute how many descriptors have been processed since last call */
hw_ind = tdma_readl(priv, TDMA_DESC_RING_PROD_CONS_INDEX(ring->index));
c_index = (hw_ind >> RING_CONS_INDEX_SHIFT) & RING_CONS_INDEX_MASK;
ring->c_index = c_index;
- if (netif_tx_queue_stopped(txq) && pkts_compl)
- netif_tx_wake_queue(txq);
-
netif_dbg(priv, tx_done, ndev,
"ring=%d c_index=%d pkts_compl=%d, bytes_compl=%d\n",
ring->index, ring->c_index, pkts_compl, bytes_compl);
static unsigned int bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv,
struct bcm_sysport_tx_ring *ring)
{
+ struct netdev_queue *txq;
unsigned int released;
unsigned long flags;
+ txq = netdev_get_tx_queue(priv->netdev, ring->index);
+
spin_lock_irqsave(&ring->lock, flags);
released = __bcm_sysport_tx_reclaim(priv, ring);
+ if (released)
+ netif_tx_wake_queue(txq);
+
spin_unlock_irqrestore(&ring->lock, flags);
return released;
}
+/* Locked version of the per-ring TX reclaim, but does not wake the queue */
+static void bcm_sysport_tx_clean(struct bcm_sysport_priv *priv,
+ struct bcm_sysport_tx_ring *ring)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ring->lock, flags);
+ __bcm_sysport_tx_reclaim(priv, ring);
+ spin_unlock_irqrestore(&ring->lock, flags);
+}
+
static int bcm_sysport_tx_poll(struct napi_struct *napi, int budget)
{
struct bcm_sysport_tx_ring *ring =
napi_disable(&ring->napi);
netif_napi_del(&ring->napi);
- bcm_sysport_tx_reclaim(priv, ring);
+ bcm_sysport_tx_clean(priv, ring);
kfree(ring->cbs);
ring->cbs = NULL;
{
#ifdef CONFIG_INET
struct tcphdr *th;
- int len, nw_off, tcp_opt_len;
+ int len, nw_off, tcp_opt_len = 0;
if (tcp_ts)
tcp_opt_len = 12;
if ((link_info->support_auto_speeds | diff) !=
link_info->support_auto_speeds) {
/* An advertised speed is no longer supported, so we need to
- * update the advertisement settings. See bnxt_reset() for
- * comments about the rtnl_lock() sequence below.
+ * update the advertisement settings. Caller holds RTNL
+ * so we can modify link settings.
*/
- clear_bit(BNXT_STATE_IN_SP_TASK, &bp->state);
- rtnl_lock();
link_info->advertising = link_info->support_auto_speeds;
- if (test_bit(BNXT_STATE_OPEN, &bp->state) &&
- (link_info->autoneg & BNXT_AUTONEG_SPEED))
+ if (link_info->autoneg & BNXT_AUTONEG_SPEED)
bnxt_hwrm_set_link_setting(bp, true, false);
- set_bit(BNXT_STATE_IN_SP_TASK, &bp->state);
- rtnl_unlock();
}
return 0;
}
mod_timer(&bp->timer, jiffies + bp->current_interval);
}
-/* Only called from bnxt_sp_task() */
-static void bnxt_reset(struct bnxt *bp, bool silent)
+static void bnxt_rtnl_lock_sp(struct bnxt *bp)
{
- /* bnxt_reset_task() calls bnxt_close_nic() which waits
- * for BNXT_STATE_IN_SP_TASK to clear.
- * If there is a parallel dev_close(), bnxt_close() may be holding
+ /* We are called from bnxt_sp_task which has BNXT_STATE_IN_SP_TASK
+ * set. If the device is being closed, bnxt_close() may be holding
* rtnl() and waiting for BNXT_STATE_IN_SP_TASK to clear. So we
* must clear BNXT_STATE_IN_SP_TASK before holding rtnl().
*/
clear_bit(BNXT_STATE_IN_SP_TASK, &bp->state);
rtnl_lock();
- if (test_bit(BNXT_STATE_OPEN, &bp->state))
- bnxt_reset_task(bp, silent);
+}
+
+static void bnxt_rtnl_unlock_sp(struct bnxt *bp)
+{
set_bit(BNXT_STATE_IN_SP_TASK, &bp->state);
rtnl_unlock();
}
+/* Only called from bnxt_sp_task() */
+static void bnxt_reset(struct bnxt *bp, bool silent)
+{
+ bnxt_rtnl_lock_sp(bp);
+ if (test_bit(BNXT_STATE_OPEN, &bp->state))
+ bnxt_reset_task(bp, silent);
+ bnxt_rtnl_unlock_sp(bp);
+}
+
static void bnxt_cfg_ntp_filters(struct bnxt *);
static void bnxt_sp_task(struct work_struct *work)
{
struct bnxt *bp = container_of(work, struct bnxt, sp_task);
- int rc;
set_bit(BNXT_STATE_IN_SP_TASK, &bp->state);
smp_mb__after_atomic();
if (test_and_clear_bit(BNXT_RX_NTP_FLTR_SP_EVENT, &bp->sp_event))
bnxt_cfg_ntp_filters(bp);
- if (test_and_clear_bit(BNXT_LINK_CHNG_SP_EVENT, &bp->sp_event)) {
- if (test_and_clear_bit(BNXT_LINK_SPEED_CHNG_SP_EVENT,
- &bp->sp_event))
- bnxt_hwrm_phy_qcaps(bp);
-
- rc = bnxt_update_link(bp, true);
- if (rc)
- netdev_err(bp->dev, "SP task can't update link (rc: %x)\n",
- rc);
- }
if (test_and_clear_bit(BNXT_HWRM_EXEC_FWD_REQ_SP_EVENT, &bp->sp_event))
bnxt_hwrm_exec_fwd_req(bp);
if (test_and_clear_bit(BNXT_VXLAN_ADD_PORT_SP_EVENT, &bp->sp_event)) {
bnxt_hwrm_tunnel_dst_port_free(
bp, TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_GENEVE);
}
+ if (test_and_clear_bit(BNXT_PERIODIC_STATS_SP_EVENT, &bp->sp_event))
+ bnxt_hwrm_port_qstats(bp);
+
+ /* These functions below will clear BNXT_STATE_IN_SP_TASK. They
+ * must be the last functions to be called before exiting.
+ */
+ if (test_and_clear_bit(BNXT_LINK_CHNG_SP_EVENT, &bp->sp_event)) {
+ int rc = 0;
+
+ if (test_and_clear_bit(BNXT_LINK_SPEED_CHNG_SP_EVENT,
+ &bp->sp_event))
+ bnxt_hwrm_phy_qcaps(bp);
+
+ bnxt_rtnl_lock_sp(bp);
+ if (test_bit(BNXT_STATE_OPEN, &bp->state))
+ rc = bnxt_update_link(bp, true);
+ bnxt_rtnl_unlock_sp(bp);
+ if (rc)
+ netdev_err(bp->dev, "SP task can't update link (rc: %x)\n",
+ rc);
+ }
+ if (test_and_clear_bit(BNXT_HWRM_PORT_MODULE_SP_EVENT, &bp->sp_event)) {
+ bnxt_rtnl_lock_sp(bp);
+ if (test_bit(BNXT_STATE_OPEN, &bp->state))
+ bnxt_get_port_module_status(bp);
+ bnxt_rtnl_unlock_sp(bp);
+ }
if (test_and_clear_bit(BNXT_RESET_TASK_SP_EVENT, &bp->sp_event))
bnxt_reset(bp, false);
if (test_and_clear_bit(BNXT_RESET_TASK_SILENT_SP_EVENT, &bp->sp_event))
bnxt_reset(bp, true);
- if (test_and_clear_bit(BNXT_HWRM_PORT_MODULE_SP_EVENT, &bp->sp_event))
- bnxt_get_port_module_status(bp);
-
- if (test_and_clear_bit(BNXT_PERIODIC_STATS_SP_EVENT, &bp->sp_event))
- bnxt_hwrm_port_qstats(bp);
-
smp_mb__before_atomic();
clear_bit(BNXT_STATE_IN_SP_TASK, &bp->state);
}
tg3_mem_rx_release(tp);
tg3_mem_tx_release(tp);
+ /* Protect tg3_get_stats64() from reading freed tp->hw_stats. */
+ tg3_full_lock(tp, 0);
if (tp->hw_stats) {
dma_free_coherent(&tp->pdev->dev, sizeof(struct tg3_hw_stats),
tp->hw_stats, tp->stats_mapping);
tp->hw_stats = NULL;
}
+ tg3_full_unlock(tp);
}
/*
#define DEFAULT_RX_RING_SIZE 512 /* must be power of 2 */
#define MIN_RX_RING_SIZE 64
#define MAX_RX_RING_SIZE 8192
-#define RX_RING_BYTES(bp) (sizeof(struct macb_dma_desc) \
+#define RX_RING_BYTES(bp) (macb_dma_desc_get_size(bp) \
* (bp)->rx_ring_size)
#define DEFAULT_TX_RING_SIZE 512 /* must be power of 2 */
#define MIN_TX_RING_SIZE 64
#define MAX_TX_RING_SIZE 4096
-#define TX_RING_BYTES(bp) (sizeof(struct macb_dma_desc) \
+#define TX_RING_BYTES(bp) (macb_dma_desc_get_size(bp) \
* (bp)->tx_ring_size)
/* level of occupied TX descriptors under which we wake up TX process */
*/
#define MACB_HALT_TIMEOUT 1230
+/* DMA buffer descriptor might be different size
+ * depends on hardware configuration.
+ */
+static unsigned int macb_dma_desc_get_size(struct macb *bp)
+{
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+ if (bp->hw_dma_cap == HW_DMA_CAP_64B)
+ return sizeof(struct macb_dma_desc) + sizeof(struct macb_dma_desc_64);
+#endif
+ return sizeof(struct macb_dma_desc);
+}
+
+static unsigned int macb_adj_dma_desc_idx(struct macb *bp, unsigned int idx)
+{
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+ /* Dma buffer descriptor is 4 words length (instead of 2 words)
+ * for 64b GEM.
+ */
+ if (bp->hw_dma_cap == HW_DMA_CAP_64B)
+ idx <<= 1;
+#endif
+ return idx;
+}
+
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+static struct macb_dma_desc_64 *macb_64b_desc(struct macb *bp, struct macb_dma_desc *desc)
+{
+ return (struct macb_dma_desc_64 *)((void *)desc + sizeof(struct macb_dma_desc));
+}
+#endif
+
/* Ring buffer accessors */
static unsigned int macb_tx_ring_wrap(struct macb *bp, unsigned int index)
{
static struct macb_dma_desc *macb_tx_desc(struct macb_queue *queue,
unsigned int index)
{
- return &queue->tx_ring[macb_tx_ring_wrap(queue->bp, index)];
+ index = macb_tx_ring_wrap(queue->bp, index);
+ index = macb_adj_dma_desc_idx(queue->bp, index);
+ return &queue->tx_ring[index];
}
static struct macb_tx_skb *macb_tx_skb(struct macb_queue *queue,
dma_addr_t offset;
offset = macb_tx_ring_wrap(queue->bp, index) *
- sizeof(struct macb_dma_desc);
+ macb_dma_desc_get_size(queue->bp);
return queue->tx_ring_dma + offset;
}
static struct macb_dma_desc *macb_rx_desc(struct macb *bp, unsigned int index)
{
- return &bp->rx_ring[macb_rx_ring_wrap(bp, index)];
+ index = macb_rx_ring_wrap(bp, index);
+ index = macb_adj_dma_desc_idx(bp, index);
+ return &bp->rx_ring[index];
}
static void *macb_rx_buffer(struct macb *bp, unsigned int index)
}
}
-static inline void macb_set_addr(struct macb_dma_desc *desc, dma_addr_t addr)
+static void macb_set_addr(struct macb *bp, struct macb_dma_desc *desc, dma_addr_t addr)
{
- desc->addr = (u32)addr;
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
- desc->addrh = (u32)(addr >> 32);
+ struct macb_dma_desc_64 *desc_64;
+
+ if (bp->hw_dma_cap == HW_DMA_CAP_64B) {
+ desc_64 = macb_64b_desc(bp, desc);
+ desc_64->addrh = upper_32_bits(addr);
+ }
#endif
+ desc->addr = lower_32_bits(addr);
+}
+
+static dma_addr_t macb_get_addr(struct macb *bp, struct macb_dma_desc *desc)
+{
+ dma_addr_t addr = 0;
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+ struct macb_dma_desc_64 *desc_64;
+
+ if (bp->hw_dma_cap == HW_DMA_CAP_64B) {
+ desc_64 = macb_64b_desc(bp, desc);
+ addr = ((u64)(desc_64->addrh) << 32);
+ }
+#endif
+ addr |= MACB_BF(RX_WADDR, MACB_BFEXT(RX_WADDR, desc->addr));
+ return addr;
}
static void macb_tx_error_task(struct work_struct *work)
/* Set end of TX queue */
desc = macb_tx_desc(queue, 0);
- macb_set_addr(desc, 0);
+ macb_set_addr(bp, desc, 0);
desc->ctrl = MACB_BIT(TX_USED);
/* Make descriptor updates visible to hardware */
wmb();
/* Reinitialize the TX desc queue */
- queue_writel(queue, TBQP, (u32)(queue->tx_ring_dma));
+ queue_writel(queue, TBQP, lower_32_bits(queue->tx_ring_dma));
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
- queue_writel(queue, TBQPH, (u32)(queue->tx_ring_dma >> 32));
+ if (bp->hw_dma_cap == HW_DMA_CAP_64B)
+ queue_writel(queue, TBQPH, upper_32_bits(queue->tx_ring_dma));
#endif
/* Make TX ring reflect state of hardware */
queue->tx_head = 0;
unsigned int entry;
struct sk_buff *skb;
dma_addr_t paddr;
+ struct macb_dma_desc *desc;
while (CIRC_SPACE(bp->rx_prepared_head, bp->rx_tail,
bp->rx_ring_size) > 0) {
rmb();
bp->rx_prepared_head++;
+ desc = macb_rx_desc(bp, entry);
if (!bp->rx_skbuff[entry]) {
/* allocate sk_buff for this free entry in ring */
if (entry == bp->rx_ring_size - 1)
paddr |= MACB_BIT(RX_WRAP);
- macb_set_addr(&(bp->rx_ring[entry]), paddr);
- bp->rx_ring[entry].ctrl = 0;
+ macb_set_addr(bp, desc, paddr);
+ desc->ctrl = 0;
/* properly align Ethernet header */
skb_reserve(skb, NET_IP_ALIGN);
} else {
- bp->rx_ring[entry].addr &= ~MACB_BIT(RX_USED);
- bp->rx_ring[entry].ctrl = 0;
+ desc->addr &= ~MACB_BIT(RX_USED);
+ desc->ctrl = 0;
}
}
bool rxused;
entry = macb_rx_ring_wrap(bp, bp->rx_tail);
- desc = &bp->rx_ring[entry];
+ desc = macb_rx_desc(bp, entry);
/* Make hw descriptor updates visible to CPU */
rmb();
rxused = (desc->addr & MACB_BIT(RX_USED)) ? true : false;
- addr = MACB_BF(RX_WADDR, MACB_BFEXT(RX_WADDR, desc->addr));
-#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
- addr |= ((u64)(desc->addrh) << 32);
-#endif
+ addr = macb_get_addr(bp, desc);
ctrl = desc->ctrl;
if (!rxused)
static inline void macb_init_rx_ring(struct macb *bp)
{
dma_addr_t addr;
+ struct macb_dma_desc *desc = NULL;
int i;
addr = bp->rx_buffers_dma;
for (i = 0; i < bp->rx_ring_size; i++) {
- bp->rx_ring[i].addr = addr;
- bp->rx_ring[i].ctrl = 0;
+ desc = macb_rx_desc(bp, i);
+ macb_set_addr(bp, desc, addr);
+ desc->ctrl = 0;
addr += bp->rx_buffer_size;
}
- bp->rx_ring[bp->rx_ring_size - 1].addr |= MACB_BIT(RX_WRAP);
+ desc->addr |= MACB_BIT(RX_WRAP);
bp->rx_tail = 0;
}
for (tail = bp->rx_tail; budget > 0; tail++) {
struct macb_dma_desc *desc = macb_rx_desc(bp, tail);
- u32 addr, ctrl;
+ u32 ctrl;
/* Make hw descriptor updates visible to CPU */
rmb();
- addr = desc->addr;
ctrl = desc->ctrl;
- if (!(addr & MACB_BIT(RX_USED)))
+ if (!(desc->addr & MACB_BIT(RX_USED)))
break;
if (ctrl & MACB_BIT(RX_SOF)) {
i = tx_head;
entry = macb_tx_ring_wrap(bp, i);
ctrl = MACB_BIT(TX_USED);
- desc = &queue->tx_ring[entry];
+ desc = macb_tx_desc(queue, entry);
desc->ctrl = ctrl;
if (lso_ctrl) {
i--;
entry = macb_tx_ring_wrap(bp, i);
tx_skb = &queue->tx_skb[entry];
- desc = &queue->tx_ring[entry];
+ desc = macb_tx_desc(queue, entry);
ctrl = (u32)tx_skb->size;
if (eof) {
ctrl |= MACB_BF(MSS_MFS, mss_mfs);
/* Set TX buffer descriptor */
- macb_set_addr(desc, tx_skb->mapping);
+ macb_set_addr(bp, desc, tx_skb->mapping);
/* desc->addr must be visible to hardware before clearing
* 'TX_USED' bit in desc->ctrl.
*/
if (!skb)
continue;
- desc = &bp->rx_ring[i];
- addr = MACB_BF(RX_WADDR, MACB_BFEXT(RX_WADDR, desc->addr));
-#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
- addr |= ((u64)(desc->addrh) << 32);
-#endif
+ desc = macb_rx_desc(bp, i);
+ addr = macb_get_addr(bp, desc);
+
dma_unmap_single(&bp->pdev->dev, addr, bp->rx_buffer_size,
DMA_FROM_DEVICE);
dev_kfree_skb_any(skb);
static void gem_init_rings(struct macb *bp)
{
struct macb_queue *queue;
+ struct macb_dma_desc *desc = NULL;
unsigned int q;
int i;
for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
for (i = 0; i < bp->tx_ring_size; i++) {
- queue->tx_ring[i].addr = 0;
- queue->tx_ring[i].ctrl = MACB_BIT(TX_USED);
+ desc = macb_tx_desc(queue, i);
+ macb_set_addr(bp, desc, 0);
+ desc->ctrl = MACB_BIT(TX_USED);
}
- queue->tx_ring[bp->tx_ring_size - 1].ctrl |= MACB_BIT(TX_WRAP);
+ desc->ctrl |= MACB_BIT(TX_WRAP);
queue->tx_head = 0;
queue->tx_tail = 0;
}
static void macb_init_rings(struct macb *bp)
{
int i;
+ struct macb_dma_desc *desc = NULL;
macb_init_rx_ring(bp);
for (i = 0; i < bp->tx_ring_size; i++) {
- bp->queues[0].tx_ring[i].addr = 0;
- bp->queues[0].tx_ring[i].ctrl = MACB_BIT(TX_USED);
+ desc = macb_tx_desc(&bp->queues[0], i);
+ macb_set_addr(bp, desc, 0);
+ desc->ctrl = MACB_BIT(TX_USED);
}
bp->queues[0].tx_head = 0;
bp->queues[0].tx_tail = 0;
- bp->queues[0].tx_ring[bp->tx_ring_size - 1].ctrl |= MACB_BIT(TX_WRAP);
+ desc->ctrl |= MACB_BIT(TX_WRAP);
}
static void macb_reset_hw(struct macb *bp)
dmacfg &= ~GEM_BIT(TXCOEN);
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
- dmacfg |= GEM_BIT(ADDR64);
+ if (bp->hw_dma_cap == HW_DMA_CAP_64B)
+ dmacfg |= GEM_BIT(ADDR64);
#endif
netdev_dbg(bp->dev, "Cadence configure DMA with 0x%08x\n",
dmacfg);
macb_configure_dma(bp);
/* Initialize TX and RX buffers */
- macb_writel(bp, RBQP, (u32)(bp->rx_ring_dma));
+ macb_writel(bp, RBQP, lower_32_bits(bp->rx_ring_dma));
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
- macb_writel(bp, RBQPH, (u32)(bp->rx_ring_dma >> 32));
+ if (bp->hw_dma_cap == HW_DMA_CAP_64B)
+ macb_writel(bp, RBQPH, upper_32_bits(bp->rx_ring_dma));
#endif
for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
- queue_writel(queue, TBQP, (u32)(queue->tx_ring_dma));
+ queue_writel(queue, TBQP, lower_32_bits(queue->tx_ring_dma));
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
- queue_writel(queue, TBQPH, (u32)(queue->tx_ring_dma >> 32));
+ if (bp->hw_dma_cap == HW_DMA_CAP_64B)
+ queue_writel(queue, TBQPH, upper_32_bits(queue->tx_ring_dma));
#endif
/* Enable interrupts */
queue->IMR = GEM_IMR(hw_q - 1);
queue->TBQP = GEM_TBQP(hw_q - 1);
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
- queue->TBQPH = GEM_TBQPH(hw_q -1);
+ if (bp->hw_dma_cap == HW_DMA_CAP_64B)
+ queue->TBQPH = GEM_TBQPH(hw_q - 1);
#endif
} else {
/* queue0 uses legacy registers */
queue->IMR = MACB_IMR;
queue->TBQP = MACB_TBQP;
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
- queue->TBQPH = MACB_TBQPH;
+ if (bp->hw_dma_cap == HW_DMA_CAP_64B)
+ queue->TBQPH = MACB_TBQPH;
#endif
}
static int at91ether_start(struct net_device *dev)
{
struct macb *lp = netdev_priv(dev);
+ struct macb_dma_desc *desc;
dma_addr_t addr;
u32 ctl;
int i;
lp->rx_ring = dma_alloc_coherent(&lp->pdev->dev,
(AT91ETHER_MAX_RX_DESCR *
- sizeof(struct macb_dma_desc)),
+ macb_dma_desc_get_size(lp)),
&lp->rx_ring_dma, GFP_KERNEL);
if (!lp->rx_ring)
return -ENOMEM;
if (!lp->rx_buffers) {
dma_free_coherent(&lp->pdev->dev,
AT91ETHER_MAX_RX_DESCR *
- sizeof(struct macb_dma_desc),
+ macb_dma_desc_get_size(lp),
lp->rx_ring, lp->rx_ring_dma);
lp->rx_ring = NULL;
return -ENOMEM;
addr = lp->rx_buffers_dma;
for (i = 0; i < AT91ETHER_MAX_RX_DESCR; i++) {
- lp->rx_ring[i].addr = addr;
- lp->rx_ring[i].ctrl = 0;
+ desc = macb_rx_desc(lp, i);
+ macb_set_addr(lp, desc, addr);
+ desc->ctrl = 0;
addr += AT91ETHER_MAX_RBUFF_SZ;
}
/* Set the Wrap bit on the last descriptor */
- lp->rx_ring[AT91ETHER_MAX_RX_DESCR - 1].addr |= MACB_BIT(RX_WRAP);
+ desc->addr |= MACB_BIT(RX_WRAP);
/* Reset buffer index */
lp->rx_tail = 0;
dma_free_coherent(&lp->pdev->dev,
AT91ETHER_MAX_RX_DESCR *
- sizeof(struct macb_dma_desc),
+ macb_dma_desc_get_size(lp),
lp->rx_ring, lp->rx_ring_dma);
lp->rx_ring = NULL;
static void at91ether_rx(struct net_device *dev)
{
struct macb *lp = netdev_priv(dev);
+ struct macb_dma_desc *desc;
unsigned char *p_recv;
struct sk_buff *skb;
unsigned int pktlen;
- while (lp->rx_ring[lp->rx_tail].addr & MACB_BIT(RX_USED)) {
+ desc = macb_rx_desc(lp, lp->rx_tail);
+ while (desc->addr & MACB_BIT(RX_USED)) {
p_recv = lp->rx_buffers + lp->rx_tail * AT91ETHER_MAX_RBUFF_SZ;
- pktlen = MACB_BF(RX_FRMLEN, lp->rx_ring[lp->rx_tail].ctrl);
+ pktlen = MACB_BF(RX_FRMLEN, desc->ctrl);
skb = netdev_alloc_skb(dev, pktlen + 2);
if (skb) {
skb_reserve(skb, 2);
lp->stats.rx_dropped++;
}
- if (lp->rx_ring[lp->rx_tail].ctrl & MACB_BIT(RX_MHASH_MATCH))
+ if (desc->ctrl & MACB_BIT(RX_MHASH_MATCH))
lp->stats.multicast++;
/* reset ownership bit */
- lp->rx_ring[lp->rx_tail].addr &= ~MACB_BIT(RX_USED);
+ desc->addr &= ~MACB_BIT(RX_USED);
/* wrap after last buffer */
if (lp->rx_tail == AT91ETHER_MAX_RX_DESCR - 1)
lp->rx_tail = 0;
else
lp->rx_tail++;
+
+ desc = macb_rx_desc(lp, lp->rx_tail);
}
}
device_init_wakeup(&pdev->dev, bp->wol & MACB_WOL_HAS_MAGIC_PACKET);
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
- if (GEM_BFEXT(DBWDEF, gem_readl(bp, DCFG1)) > GEM_DBW32)
+ if (GEM_BFEXT(DAW64, gem_readl(bp, DCFG6))) {
dma_set_mask(&pdev->dev, DMA_BIT_MASK(44));
+ bp->hw_dma_cap = HW_DMA_CAP_64B;
+ } else
+ bp->hw_dma_cap = HW_DMA_CAP_32B;
#endif
spin_lock_init(&bp->lock);
/* Bitfields in DCFG6. */
#define GEM_PBUF_LSO_OFFSET 27
#define GEM_PBUF_LSO_SIZE 1
+#define GEM_DAW64_OFFSET 23
+#define GEM_DAW64_SIZE 1
/* Constants for CLK */
#define MACB_CLK_DIV8 0
struct macb_dma_desc {
u32 addr;
u32 ctrl;
+};
+
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
- u32 addrh;
- u32 resvd;
-#endif
+enum macb_hw_dma_cap {
+ HW_DMA_CAP_32B,
+ HW_DMA_CAP_64B,
};
+struct macb_dma_desc_64 {
+ u32 addrh;
+ u32 resvd;
+};
+#endif
+
/* DMA descriptor bitfields */
#define MACB_RX_USED_OFFSET 0
#define MACB_RX_USED_SIZE 1
unsigned int jumbo_max_len;
u32 wol;
+
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+ enum macb_hw_dma_cap hw_dma_cap;
+#endif
};
static inline bool macb_is_gem(struct macb *bp)
struct bgx {
u8 bgx_id;
struct lmac lmac[MAX_LMAC_PER_BGX];
- int lmac_count;
+ u8 lmac_count;
u8 max_lmac;
+ u8 acpi_lmac_idx;
void __iomem *reg_base;
struct pci_dev *pdev;
bool is_dlm;
if (acpi_bus_get_device(handle, &adev))
goto out;
- acpi_get_mac_address(dev, adev, bgx->lmac[bgx->lmac_count].mac);
+ acpi_get_mac_address(dev, adev, bgx->lmac[bgx->acpi_lmac_idx].mac);
- SET_NETDEV_DEV(&bgx->lmac[bgx->lmac_count].netdev, dev);
+ SET_NETDEV_DEV(&bgx->lmac[bgx->acpi_lmac_idx].netdev, dev);
- bgx->lmac[bgx->lmac_count].lmacid = bgx->lmac_count;
+ bgx->lmac[bgx->acpi_lmac_idx].lmacid = bgx->acpi_lmac_idx;
+ bgx->acpi_lmac_idx++; /* move to next LMAC */
out:
- bgx->lmac_count++;
return AE_OK;
}
int speed = 2;
if (!xcv) {
- dev_err(&xcv->pdev->dev,
- "XCV init not done, probe may have failed\n");
+ pr_err("XCV init not done, probe may have failed\n");
return;
}
err:
mutex_unlock(&adapter->mcc_lock);
- if (status == MCC_STATUS_UNAUTHORIZED_REQUEST)
+ if (base_status(status) == MCC_STATUS_UNAUTHORIZED_REQUEST)
status = -EPERM;
return status;
/* Check if mac has already been added as part of uc-list */
for (i = 0; i < adapter->uc_macs; i++) {
- if (ether_addr_equal((u8 *)&adapter->uc_list[i * ETH_ALEN],
- mac)) {
+ if (ether_addr_equal(adapter->uc_list[i].mac, mac)) {
/* mac already added, skip addition */
adapter->pmac_id[0] = adapter->pmac_id[i + 1];
return 0;
if (ether_addr_equal(addr->sa_data, adapter->dev_mac))
return 0;
+ /* BE3 VFs without FILTMGMT privilege are not allowed to set its MAC
+ * address
+ */
+ if (BEx_chip(adapter) && be_virtfn(adapter) &&
+ !check_privilege(adapter, BE_PRIV_FILTMGMT))
+ return -EPERM;
+
/* if device is not running, copy MAC to netdev->dev_addr */
if (!netif_running(netdev))
goto done;
status = -EPERM;
goto err;
}
-done:
+
+ /* Remember currently programmed MAC */
ether_addr_copy(adapter->dev_mac, addr->sa_data);
+done:
ether_addr_copy(netdev->dev_addr, addr->sa_data);
dev_info(dev, "MAC address changed to %pM\n", addr->sa_data);
return 0;
static int be_uc_mac_add(struct be_adapter *adapter, int uc_idx)
{
- if (ether_addr_equal((u8 *)&adapter->uc_list[uc_idx * ETH_ALEN],
- adapter->dev_mac)) {
+ if (ether_addr_equal(adapter->uc_list[uc_idx].mac, adapter->dev_mac)) {
adapter->pmac_id[uc_idx + 1] = adapter->pmac_id[0];
return 0;
}
- return be_cmd_pmac_add(adapter,
- (u8 *)&adapter->uc_list[uc_idx * ETH_ALEN],
+ return be_cmd_pmac_add(adapter, adapter->uc_list[uc_idx].mac,
adapter->if_handle,
&adapter->pmac_id[uc_idx + 1], 0);
}
}
if (adapter->update_uc_list) {
- i = 1; /* First slot is claimed by the Primary MAC */
-
/* cache the uc-list in adapter array */
+ i = 0;
netdev_for_each_uc_addr(ha, netdev) {
ether_addr_copy(adapter->uc_list[i].mac, ha->addr);
i++;
static void be_disable_if_filters(struct be_adapter *adapter)
{
- be_dev_mac_del(adapter, adapter->pmac_id[0]);
+ /* Don't delete MAC on BE3 VFs without FILTMGMT privilege */
+ if (!BEx_chip(adapter) || !be_virtfn(adapter) ||
+ check_privilege(adapter, BE_PRIV_FILTMGMT)) {
+ be_dev_mac_del(adapter, adapter->pmac_id[0]);
+ eth_zero_addr(adapter->dev_mac);
+ }
+
be_clear_uc_list(adapter);
be_clear_mc_list(adapter);
if (status)
return status;
- /* For BE3 VFs, the PF programs the initial MAC address */
- if (!(BEx_chip(adapter) && be_virtfn(adapter))) {
+ /* Normally this condition usually true as the ->dev_mac is zeroed.
+ * But on BE3 VFs the initial MAC is pre-programmed by PF and
+ * subsequent be_dev_mac_add() can fail (after fresh boot)
+ */
+ if (!ether_addr_equal(adapter->dev_mac, adapter->netdev->dev_addr)) {
+ int old_pmac_id = -1;
+
+ /* Remember old programmed MAC if any - can happen on BE3 VF */
+ if (!is_zero_ether_addr(adapter->dev_mac))
+ old_pmac_id = adapter->pmac_id[0];
+
status = be_dev_mac_add(adapter, adapter->netdev->dev_addr);
if (status)
return status;
+
+ /* Delete the old programmed MAC as we successfully programmed
+ * a new MAC
+ */
+ if (old_pmac_id >= 0 && old_pmac_id != adapter->pmac_id[0])
+ be_dev_mac_del(adapter, old_pmac_id);
+
ether_addr_copy(adapter->dev_mac, adapter->netdev->dev_addr);
}
memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN);
memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN);
+
+ /* Initial MAC for BE3 VFs is already programmed by PF */
+ if (BEx_chip(adapter) && be_virtfn(adapter))
+ memcpy(adapter->dev_mac, mac, ETH_ALEN);
}
return 0;
if (!rxb->page)
continue;
- dma_unmap_single(rx_queue->dev, rxb->dma,
- PAGE_SIZE, DMA_FROM_DEVICE);
+ dma_unmap_page(rx_queue->dev, rxb->dma,
+ PAGE_SIZE, DMA_FROM_DEVICE);
__free_page(rxb->page);
rxb->page = NULL;
}
/* try reuse page */
- if (unlikely(page_count(page) != 1))
+ if (unlikely(page_count(page) != 1 || page_is_pfmemalloc(page)))
return false;
/* change offset to the other half */
netdev->netdev_ops = &ibmveth_netdev_ops;
netdev->ethtool_ops = &netdev_ethtool_ops;
SET_NETDEV_DEV(netdev, &dev->dev);
- netdev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM |
- NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
+ netdev->hw_features = NETIF_F_SG;
+ if (vio_get_attribute(dev, "ibm,illan-options", NULL) != NULL) {
+ netdev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+ NETIF_F_RXCSUM;
+ }
netdev->features |= netdev->hw_features;
PAGE_SIZE,
DMA_FROM_DEVICE,
DMA_ATTR_SKIP_CPU_SYNC);
- __page_frag_drain(buffer_info->page, 0,
- buffer_info->pagecnt_bias);
+ __page_frag_cache_drain(buffer_info->page,
+ buffer_info->pagecnt_bias);
buffer_info->page = NULL;
}
dma_unmap_page_attrs(rx_ring->dev, rx_buffer->dma,
PAGE_SIZE, DMA_FROM_DEVICE,
DMA_ATTR_SKIP_CPU_SYNC);
- __page_frag_drain(page, 0, rx_buffer->pagecnt_bias);
+ __page_frag_cache_drain(page, rx_buffer->pagecnt_bias);
}
/* clear contents of rx_buffer */
}
const struct of_device_id of_mtk_match[] = {
- { .compatible = "mediatek,mt7623-eth" },
+ { .compatible = "mediatek,mt2701-eth" },
{},
};
MODULE_DEVICE_TABLE(of, of_mtk_match);
return -ETIMEDOUT;
}
-static int mlx4_comm_internal_err(u32 slave_read)
+int mlx4_comm_internal_err(u32 slave_read)
{
return (u32)COMM_CHAN_EVENT_INTERNAL_ERR ==
(slave_read & (u32)COMM_CHAN_EVENT_INTERNAL_ERR) ? 1 : 0;
{
struct mlx4_cq *cq;
+ rcu_read_lock();
cq = radix_tree_lookup(&mlx4_priv(dev)->cq_table.tree,
cqn & (dev->caps.num_cqs - 1));
+ rcu_read_unlock();
+
if (!cq) {
mlx4_dbg(dev, "Completion event for bogus CQ %08x\n", cqn);
return;
}
+ /* Acessing the CQ outside of rcu_read_lock is safe, because
+ * the CQ is freed only after interrupt handling is completed.
+ */
++cq->arm_sn;
cq->comp(cq);
struct mlx4_cq_table *cq_table = &mlx4_priv(dev)->cq_table;
struct mlx4_cq *cq;
- spin_lock(&cq_table->lock);
-
+ rcu_read_lock();
cq = radix_tree_lookup(&cq_table->tree, cqn & (dev->caps.num_cqs - 1));
- if (cq)
- atomic_inc(&cq->refcount);
-
- spin_unlock(&cq_table->lock);
+ rcu_read_unlock();
if (!cq) {
- mlx4_warn(dev, "Async event for bogus CQ %08x\n", cqn);
+ mlx4_dbg(dev, "Async event for bogus CQ %08x\n", cqn);
return;
}
+ /* Acessing the CQ outside of rcu_read_lock is safe, because
+ * the CQ is freed only after interrupt handling is completed.
+ */
cq->event(cq, event_type);
-
- if (atomic_dec_and_test(&cq->refcount))
- complete(&cq->free);
}
static int mlx4_SW2HW_CQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
if (err)
return err;
- spin_lock_irq(&cq_table->lock);
+ spin_lock(&cq_table->lock);
err = radix_tree_insert(&cq_table->tree, cq->cqn, cq);
- spin_unlock_irq(&cq_table->lock);
+ spin_unlock(&cq_table->lock);
if (err)
goto err_icm;
return 0;
err_radix:
- spin_lock_irq(&cq_table->lock);
+ spin_lock(&cq_table->lock);
radix_tree_delete(&cq_table->tree, cq->cqn);
- spin_unlock_irq(&cq_table->lock);
+ spin_unlock(&cq_table->lock);
err_icm:
mlx4_cq_free_icm(dev, cq->cqn);
if (err)
mlx4_warn(dev, "HW2SW_CQ failed (%d) for CQN %06x\n", err, cq->cqn);
+ spin_lock(&cq_table->lock);
+ radix_tree_delete(&cq_table->tree, cq->cqn);
+ spin_unlock(&cq_table->lock);
+
synchronize_irq(priv->eq_table.eq[MLX4_CQ_TO_EQ_VECTOR(cq->vector)].irq);
if (priv->eq_table.eq[MLX4_CQ_TO_EQ_VECTOR(cq->vector)].irq !=
priv->eq_table.eq[MLX4_EQ_ASYNC].irq)
synchronize_irq(priv->eq_table.eq[MLX4_EQ_ASYNC].irq);
- spin_lock_irq(&cq_table->lock);
- radix_tree_delete(&cq_table->tree, cq->cqn);
- spin_unlock_irq(&cq_table->lock);
-
if (atomic_dec_and_test(&cq->refcount))
complete(&cq->free);
wait_for_completion(&cq->free);
{
struct mlx4_en_priv *priv = netdev_priv(dev);
- memset(channel, 0, sizeof(*channel));
-
channel->max_rx = MAX_RX_RINGS;
channel->max_tx = MLX4_EN_MAX_TX_RING_P_UP;
int xdp_count;
int err = 0;
- if (channel->other_count || channel->combined_count ||
- channel->tx_count > MLX4_EN_MAX_TX_RING_P_UP ||
- channel->rx_count > MAX_RX_RINGS ||
- !channel->tx_count || !channel->rx_count)
+ if (!channel->tx_count || !channel->rx_count)
return -EINVAL;
tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
/* Process all completions if exist to prevent
* the queues freezing if they are full
*/
- for (i = 0; i < priv->rx_ring_num; i++)
+ for (i = 0; i < priv->rx_ring_num; i++) {
+ local_bh_disable();
napi_schedule(&priv->rx_cq[i]->napi);
+ local_bh_enable();
+ }
netif_tx_start_all_queues(dev);
netif_device_attach(dev);
if (priv->tx_ring_num[TX_XDP] &&
!mlx4_en_check_xdp_mtu(dev, new_mtu))
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
dev->mtu = new_mtu;
break;
case MLX4_EVENT_TYPE_SRQ_LIMIT:
- mlx4_dbg(dev, "%s: MLX4_EVENT_TYPE_SRQ_LIMIT\n",
- __func__);
+ mlx4_dbg(dev, "%s: MLX4_EVENT_TYPE_SRQ_LIMIT. srq_no=0x%x, eq 0x%x\n",
+ __func__, be32_to_cpu(eqe->event.srq.srqn),
+ eq->eqn);
case MLX4_EVENT_TYPE_SRQ_CATAS_ERROR:
if (mlx4_is_master(dev)) {
/* forward only to slave owning the SRQ */
eq->eqn, eq->cons_index, ret);
break;
}
- mlx4_warn(dev, "%s: slave:%d, srq_no:0x%x, event: %02x(%02x)\n",
- __func__, slave,
- be32_to_cpu(eqe->event.srq.srqn),
- eqe->type, eqe->subtype);
+ if (eqe->type ==
+ MLX4_EVENT_TYPE_SRQ_CATAS_ERROR)
+ mlx4_warn(dev, "%s: slave:%d, srq_no:0x%x, event: %02x(%02x)\n",
+ __func__, slave,
+ be32_to_cpu(eqe->event.srq.srqn),
+ eqe->type, eqe->subtype);
if (!ret && slave != dev->caps.function) {
- mlx4_warn(dev, "%s: sending event %02x(%02x) to slave:%d\n",
- __func__, eqe->type,
- eqe->subtype, slave);
+ if (eqe->type ==
+ MLX4_EVENT_TYPE_SRQ_CATAS_ERROR)
+ mlx4_warn(dev, "%s: sending event %02x(%02x) to slave:%d\n",
+ __func__, eqe->type,
+ eqe->subtype, slave);
mlx4_slave_event(dev, slave, eqe);
break;
}
return;
mlx4_stop_catas_poll(dev);
+ if (dev->persist->interface_state & MLX4_INTERFACE_STATE_DELETION &&
+ mlx4_is_slave(dev)) {
+ /* In mlx4_remove_one on a VF */
+ u32 slave_read =
+ swab32(readl(&mlx4_priv(dev)->mfunc.comm->slave_read));
+
+ if (mlx4_comm_internal_err(slave_read)) {
+ mlx4_dbg(dev, "%s: comm channel is down, entering error state.\n",
+ __func__);
+ mlx4_enter_error_state(dev->persist);
+ }
+ }
mutex_lock(&intf_mutex);
list_for_each_entry(intf, &intf_list, list)
void mlx4_srq_event(struct mlx4_dev *dev, u32 srqn, int event_type);
void mlx4_enter_error_state(struct mlx4_dev_persistent *persist);
+int mlx4_comm_internal_err(u32 slave_read);
int mlx4_SENSE_PORT(struct mlx4_dev *dev, int port,
enum mlx4_port_type *type);
put_res(dev, slave, srqn, RES_SRQ);
qp->srq = srq;
}
+
+ /* Save param3 for dynamic changes from VST back to VGT */
+ qp->param3 = qpc->param3;
put_res(dev, slave, rcqn, RES_CQ);
put_res(dev, slave, mtt_base, RES_MTT);
res_end_move(dev, slave, RES_QP, qpn);
int qpn = vhcr->in_modifier & 0x7fffff;
struct res_qp *qp;
u8 orig_sched_queue;
- __be32 orig_param3 = qpc->param3;
u8 orig_vlan_control = qpc->pri_path.vlan_control;
u8 orig_fvl_rx = qpc->pri_path.fvl_rx;
u8 orig_pri_path_fl = qpc->pri_path.fl;
*/
if (!err) {
qp->sched_queue = orig_sched_queue;
- qp->param3 = orig_param3;
qp->vlan_control = orig_vlan_control;
qp->fvl_rx = orig_fvl_rx;
qp->pri_path_fl = orig_pri_path_fl;
if (cmd->cmdif_rev > CMD_IF_REV) {
dev_err(&dev->pdev->dev, "driver does not support command interface version. driver %d, firmware %d\n",
CMD_IF_REV, cmd->cmdif_rev);
- err = -ENOTSUPP;
+ err = -EOPNOTSUPP;
goto err_free_page;
}
int mlx5e_modify_rqs_vsd(struct mlx5e_priv *priv, bool vsd);
int mlx5e_redirect_rqt(struct mlx5e_priv *priv, u32 rqtn, int sz, int ix);
-void mlx5e_build_tir_ctx_hash(void *tirc, struct mlx5e_priv *priv);
+void mlx5e_build_indir_tir_ctx_hash(struct mlx5e_priv *priv, void *tirc,
+ enum mlx5e_traffic_types tt);
int mlx5e_open_locked(struct net_device *netdev);
int mlx5e_close_locked(struct net_device *netdev);
static inline int mlx5e_arfs_enable(struct mlx5e_priv *priv)
{
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
}
static inline int mlx5e_arfs_disable(struct mlx5e_priv *priv)
{
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
}
#else
int mlx5e_arfs_create_tables(struct mlx5e_priv *priv);
int i;
if (!MLX5_CAP_GEN(priv->mdev, ets))
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
ets->ets_cap = mlx5_max_tc(priv->mdev) + 1;
for (i = 0; i < ets->ets_cap; i++) {
int err;
if (!MLX5_CAP_GEN(priv->mdev, ets))
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
err = mlx5e_dbcnl_validate_ets(netdev, ets);
if (err)
struct mlx5_core_dev *mdev = priv->mdev;
struct ieee_ets ets;
struct ieee_pfc pfc;
- int err = -ENOTSUPP;
+ int err = -EOPNOTSUPP;
int i;
if (!MLX5_CAP_GEN(mdev, ets))
struct mlx5e_priv *priv = netdev_priv(netdev);
struct mlx5_core_dev *mdev = priv->mdev;
+ if (!MLX5_CAP_GEN(priv->mdev, ets)) {
+ netdev_err(netdev, "%s, ets is not supported\n", __func__);
+ return;
+ }
+
if (priority >= CEE_DCBX_MAX_PRIO) {
netdev_err(netdev,
"%s, priority is out of range\n", __func__);
struct ethtool_channels *ch)
{
struct mlx5e_priv *priv = netdev_priv(dev);
- int ncv = mlx5e_get_max_num_channels(priv->mdev);
unsigned int count = ch->combined_count;
bool arfs_enabled;
bool was_opened;
__func__);
return -EINVAL;
}
- if (ch->rx_count || ch->tx_count) {
- netdev_info(dev, "%s: separate rx/tx count not supported\n",
- __func__);
- return -EINVAL;
- }
- if (count > ncv) {
- netdev_info(dev, "%s: count (%d) > max (%d)\n",
- __func__, count, ncv);
- return -EINVAL;
- }
if (priv->params.num_channels == count)
return 0;
struct mlx5e_priv *priv = netdev_priv(netdev);
if (!MLX5_CAP_GEN(priv->mdev, cq_moderation))
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
coal->rx_coalesce_usecs = priv->params.rx_cq_moderation.usec;
coal->rx_max_coalesced_frames = priv->params.rx_cq_moderation.pkts;
int i;
if (!MLX5_CAP_GEN(mdev, cq_moderation))
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
mutex_lock(&priv->state_lock);
static void mlx5e_modify_tirs_hash(struct mlx5e_priv *priv, void *in, int inlen)
{
- struct mlx5_core_dev *mdev = priv->mdev;
void *tirc = MLX5_ADDR_OF(modify_tir_in, in, ctx);
- int i;
+ struct mlx5_core_dev *mdev = priv->mdev;
+ int ctxlen = MLX5_ST_SZ_BYTES(tirc);
+ int tt;
MLX5_SET(modify_tir_in, in, bitmask.hash, 1);
- mlx5e_build_tir_ctx_hash(tirc, priv);
- for (i = 0; i < MLX5E_NUM_INDIR_TIRS; i++)
- mlx5_core_modify_tir(mdev, priv->indir_tir[i].tirn, in, inlen);
+ for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++) {
+ memset(tirc, 0, ctxlen);
+ mlx5e_build_indir_tir_ctx_hash(priv, tirc, tt);
+ mlx5_core_modify_tir(mdev, priv->indir_tir[tt].tirn, in, inlen);
+ }
}
static int mlx5e_set_rxfh(struct net_device *dev, const u32 *indir,
{
struct mlx5e_priv *priv = netdev_priv(dev);
int inlen = MLX5_ST_SZ_BYTES(modify_tir_in);
+ bool hash_changed = false;
void *in;
if ((hfunc != ETH_RSS_HASH_NO_CHANGE) &&
mlx5e_redirect_rqt(priv, rqtn, MLX5E_INDIR_RQT_SIZE, 0);
}
- if (key)
+ if (hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ hfunc != priv->params.rss_hfunc) {
+ priv->params.rss_hfunc = hfunc;
+ hash_changed = true;
+ }
+
+ if (key) {
memcpy(priv->params.toeplitz_hash_key, key,
sizeof(priv->params.toeplitz_hash_key));
+ hash_changed = hash_changed ||
+ priv->params.rss_hfunc == ETH_RSS_HASH_TOP;
+ }
- if (hfunc != ETH_RSS_HASH_NO_CHANGE)
- priv->params.rss_hfunc = hfunc;
-
- mlx5e_modify_tirs_hash(priv, in, inlen);
+ if (hash_changed)
+ mlx5e_modify_tirs_hash(priv, in, inlen);
mutex_unlock(&priv->state_lock);
u32 mlx5_wol_mode;
if (!wol_supported)
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
if (wol->wolopts & ~wol_supported)
return -EINVAL;
if (rx_cq_period_mode == MLX5_CQ_PERIOD_MODE_START_FROM_CQE &&
!MLX5_CAP_GEN(mdev, cq_period_start_from_cqe))
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
if (!rx_mode_changed)
return 0;
bool reset;
if (!MLX5_CAP_GEN(mdev, cqe_compression))
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
if (enable && priv->tstamp.hwtstamp_config.rx_filter != HWTSTAMP_FILTER_NONE) {
netdev_err(netdev, "Can't enable cqe compression while timestamping is enabled.\n");
MLX5_FLOW_NAMESPACE_KERNEL);
if (!priv->fs.ns)
- return -EINVAL;
+ return -EOPNOTSUPP;
err = mlx5e_arfs_create_tables(priv);
if (err) {
ns = mlx5_get_flow_namespace(priv->mdev,
MLX5_FLOW_NAMESPACE_ETHTOOL);
if (!ns)
- return ERR_PTR(-ENOTSUPP);
+ return ERR_PTR(-EOPNOTSUPP);
table_size = min_t(u32, BIT(MLX5_CAP_FLOWTABLE(priv->mdev,
flow_table_properties_nic_receive.log_max_ft_size)),
MLX5_SET(tirc, tirc, lro_timeout_period_usecs, priv->params.lro_timeout);
}
-void mlx5e_build_tir_ctx_hash(void *tirc, struct mlx5e_priv *priv)
+void mlx5e_build_indir_tir_ctx_hash(struct mlx5e_priv *priv, void *tirc,
+ enum mlx5e_traffic_types tt)
{
+ void *hfso = MLX5_ADDR_OF(tirc, tirc, rx_hash_field_selector_outer);
+
+#define MLX5_HASH_IP (MLX5_HASH_FIELD_SEL_SRC_IP |\
+ MLX5_HASH_FIELD_SEL_DST_IP)
+
+#define MLX5_HASH_IP_L4PORTS (MLX5_HASH_FIELD_SEL_SRC_IP |\
+ MLX5_HASH_FIELD_SEL_DST_IP |\
+ MLX5_HASH_FIELD_SEL_L4_SPORT |\
+ MLX5_HASH_FIELD_SEL_L4_DPORT)
+
+#define MLX5_HASH_IP_IPSEC_SPI (MLX5_HASH_FIELD_SEL_SRC_IP |\
+ MLX5_HASH_FIELD_SEL_DST_IP |\
+ MLX5_HASH_FIELD_SEL_IPSEC_SPI)
+
MLX5_SET(tirc, tirc, rx_hash_fn,
mlx5e_rx_hash_fn(priv->params.rss_hfunc));
if (priv->params.rss_hfunc == ETH_RSS_HASH_TOP) {
MLX5_SET(tirc, tirc, rx_hash_symmetric, 1);
memcpy(rss_key, priv->params.toeplitz_hash_key, len);
}
+
+ switch (tt) {
+ case MLX5E_TT_IPV4_TCP:
+ MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+ MLX5_L3_PROT_TYPE_IPV4);
+ MLX5_SET(rx_hash_field_select, hfso, l4_prot_type,
+ MLX5_L4_PROT_TYPE_TCP);
+ MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+ MLX5_HASH_IP_L4PORTS);
+ break;
+
+ case MLX5E_TT_IPV6_TCP:
+ MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+ MLX5_L3_PROT_TYPE_IPV6);
+ MLX5_SET(rx_hash_field_select, hfso, l4_prot_type,
+ MLX5_L4_PROT_TYPE_TCP);
+ MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+ MLX5_HASH_IP_L4PORTS);
+ break;
+
+ case MLX5E_TT_IPV4_UDP:
+ MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+ MLX5_L3_PROT_TYPE_IPV4);
+ MLX5_SET(rx_hash_field_select, hfso, l4_prot_type,
+ MLX5_L4_PROT_TYPE_UDP);
+ MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+ MLX5_HASH_IP_L4PORTS);
+ break;
+
+ case MLX5E_TT_IPV6_UDP:
+ MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+ MLX5_L3_PROT_TYPE_IPV6);
+ MLX5_SET(rx_hash_field_select, hfso, l4_prot_type,
+ MLX5_L4_PROT_TYPE_UDP);
+ MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+ MLX5_HASH_IP_L4PORTS);
+ break;
+
+ case MLX5E_TT_IPV4_IPSEC_AH:
+ MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+ MLX5_L3_PROT_TYPE_IPV4);
+ MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+ MLX5_HASH_IP_IPSEC_SPI);
+ break;
+
+ case MLX5E_TT_IPV6_IPSEC_AH:
+ MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+ MLX5_L3_PROT_TYPE_IPV6);
+ MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+ MLX5_HASH_IP_IPSEC_SPI);
+ break;
+
+ case MLX5E_TT_IPV4_IPSEC_ESP:
+ MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+ MLX5_L3_PROT_TYPE_IPV4);
+ MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+ MLX5_HASH_IP_IPSEC_SPI);
+ break;
+
+ case MLX5E_TT_IPV6_IPSEC_ESP:
+ MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+ MLX5_L3_PROT_TYPE_IPV6);
+ MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+ MLX5_HASH_IP_IPSEC_SPI);
+ break;
+
+ case MLX5E_TT_IPV4:
+ MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+ MLX5_L3_PROT_TYPE_IPV4);
+ MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+ MLX5_HASH_IP);
+ break;
+
+ case MLX5E_TT_IPV6:
+ MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
+ MLX5_L3_PROT_TYPE_IPV6);
+ MLX5_SET(rx_hash_field_select, hfso, selected_fields,
+ MLX5_HASH_IP);
+ break;
+ default:
+ WARN_ONCE(true, "%s: bad traffic type!\n", __func__);
+ }
}
static int mlx5e_modify_tirs_lro(struct mlx5e_priv *priv)
static void mlx5e_build_indir_tir_ctx(struct mlx5e_priv *priv, u32 *tirc,
enum mlx5e_traffic_types tt)
{
- void *hfso = MLX5_ADDR_OF(tirc, tirc, rx_hash_field_selector_outer);
-
MLX5_SET(tirc, tirc, transport_domain, priv->mdev->mlx5e_res.td.tdn);
-#define MLX5_HASH_IP (MLX5_HASH_FIELD_SEL_SRC_IP |\
- MLX5_HASH_FIELD_SEL_DST_IP)
-
-#define MLX5_HASH_IP_L4PORTS (MLX5_HASH_FIELD_SEL_SRC_IP |\
- MLX5_HASH_FIELD_SEL_DST_IP |\
- MLX5_HASH_FIELD_SEL_L4_SPORT |\
- MLX5_HASH_FIELD_SEL_L4_DPORT)
-
-#define MLX5_HASH_IP_IPSEC_SPI (MLX5_HASH_FIELD_SEL_SRC_IP |\
- MLX5_HASH_FIELD_SEL_DST_IP |\
- MLX5_HASH_FIELD_SEL_IPSEC_SPI)
-
mlx5e_build_tir_ctx_lro(tirc, priv);
MLX5_SET(tirc, tirc, disp_type, MLX5_TIRC_DISP_TYPE_INDIRECT);
MLX5_SET(tirc, tirc, indirect_table, priv->indir_rqt.rqtn);
- mlx5e_build_tir_ctx_hash(tirc, priv);
-
- switch (tt) {
- case MLX5E_TT_IPV4_TCP:
- MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
- MLX5_L3_PROT_TYPE_IPV4);
- MLX5_SET(rx_hash_field_select, hfso, l4_prot_type,
- MLX5_L4_PROT_TYPE_TCP);
- MLX5_SET(rx_hash_field_select, hfso, selected_fields,
- MLX5_HASH_IP_L4PORTS);
- break;
-
- case MLX5E_TT_IPV6_TCP:
- MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
- MLX5_L3_PROT_TYPE_IPV6);
- MLX5_SET(rx_hash_field_select, hfso, l4_prot_type,
- MLX5_L4_PROT_TYPE_TCP);
- MLX5_SET(rx_hash_field_select, hfso, selected_fields,
- MLX5_HASH_IP_L4PORTS);
- break;
-
- case MLX5E_TT_IPV4_UDP:
- MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
- MLX5_L3_PROT_TYPE_IPV4);
- MLX5_SET(rx_hash_field_select, hfso, l4_prot_type,
- MLX5_L4_PROT_TYPE_UDP);
- MLX5_SET(rx_hash_field_select, hfso, selected_fields,
- MLX5_HASH_IP_L4PORTS);
- break;
-
- case MLX5E_TT_IPV6_UDP:
- MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
- MLX5_L3_PROT_TYPE_IPV6);
- MLX5_SET(rx_hash_field_select, hfso, l4_prot_type,
- MLX5_L4_PROT_TYPE_UDP);
- MLX5_SET(rx_hash_field_select, hfso, selected_fields,
- MLX5_HASH_IP_L4PORTS);
- break;
-
- case MLX5E_TT_IPV4_IPSEC_AH:
- MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
- MLX5_L3_PROT_TYPE_IPV4);
- MLX5_SET(rx_hash_field_select, hfso, selected_fields,
- MLX5_HASH_IP_IPSEC_SPI);
- break;
-
- case MLX5E_TT_IPV6_IPSEC_AH:
- MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
- MLX5_L3_PROT_TYPE_IPV6);
- MLX5_SET(rx_hash_field_select, hfso, selected_fields,
- MLX5_HASH_IP_IPSEC_SPI);
- break;
-
- case MLX5E_TT_IPV4_IPSEC_ESP:
- MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
- MLX5_L3_PROT_TYPE_IPV4);
- MLX5_SET(rx_hash_field_select, hfso, selected_fields,
- MLX5_HASH_IP_IPSEC_SPI);
- break;
-
- case MLX5E_TT_IPV6_IPSEC_ESP:
- MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
- MLX5_L3_PROT_TYPE_IPV6);
- MLX5_SET(rx_hash_field_select, hfso, selected_fields,
- MLX5_HASH_IP_IPSEC_SPI);
- break;
-
- case MLX5E_TT_IPV4:
- MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
- MLX5_L3_PROT_TYPE_IPV4);
- MLX5_SET(rx_hash_field_select, hfso, selected_fields,
- MLX5_HASH_IP);
- break;
-
- case MLX5E_TT_IPV6:
- MLX5_SET(rx_hash_field_select, hfso, l3_prot_type,
- MLX5_L3_PROT_TYPE_IPV6);
- MLX5_SET(rx_hash_field_select, hfso, selected_fields,
- MLX5_HASH_IP);
- break;
- default:
- WARN_ONCE(true,
- "mlx5e_build_indir_tir_ctx: bad traffic type!\n");
- }
+ mlx5e_build_indir_tir_ctx_hash(priv, tirc, tt);
}
static void mlx5e_build_direct_tir_ctx(struct mlx5e_priv *priv, u32 *tirc,
static int mlx5e_check_required_hca_cap(struct mlx5_core_dev *mdev)
{
if (MLX5_CAP_GEN(mdev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
if (!MLX5_CAP_GEN(mdev, eth_net_offloads) ||
!MLX5_CAP_GEN(mdev, nic_flow_table) ||
!MLX5_CAP_ETH(mdev, csum_cap) ||
< 3) {
mlx5_core_warn(mdev,
"Not creating net device, some required device capabilities are missing\n");
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
}
if (!MLX5_CAP_ETH(mdev, self_lb_en_modifiable))
mlx5_core_warn(mdev, "Self loop back prevention is not supported\n");
static void mlx5e_nic_cleanup(struct mlx5e_priv *priv)
{
- struct mlx5_core_dev *mdev = priv->mdev;
- struct mlx5_eswitch *esw = mdev->priv.eswitch;
-
mlx5e_vxlan_cleanup(priv);
- if (MLX5_CAP_GEN(mdev, vport_group_manager))
- mlx5_eswitch_unregister_vport_rep(esw, 0);
-
if (priv->xdp_prog)
bpf_prog_put(priv->xdp_prog);
}
static void mlx5e_nic_disable(struct mlx5e_priv *priv)
{
+ struct mlx5_core_dev *mdev = priv->mdev;
+ struct mlx5_eswitch *esw = mdev->priv.eswitch;
+
queue_work(priv->wq, &priv->set_rx_mode_work);
+ if (MLX5_CAP_GEN(mdev, vport_group_manager))
+ mlx5_eswitch_unregister_vport_rep(esw, 0);
mlx5e_disable_async_events(priv);
- mlx5_lag_remove(priv->mdev);
+ mlx5_lag_remove(mdev);
}
static const struct mlx5e_profile mlx5e_nic_profile = {
return false;
}
+ if (unlikely(page_is_pfmemalloc(dma_info->page)))
+ return false;
+
cache->page_cache[cache->tail] = *dma_info;
cache->tail = tail_next;
return true;
switch (am->tune_state) {
case MLX5E_AM_PARKING_ON_TOP:
case MLX5E_AM_PARKING_TIRED:
- WARN_ONCE(true, "mlx5e_am_on_top: PARKING\n");
return true;
case MLX5E_AM_GOING_RIGHT:
return (am->steps_left > 1) && (am->steps_right == 1);
switch (am->tune_state) {
case MLX5E_AM_PARKING_ON_TOP:
case MLX5E_AM_PARKING_TIRED:
- WARN_ONCE(true, "mlx5e_am_turn: PARKING\n");
break;
case MLX5E_AM_GOING_RIGHT:
am->tune_state = MLX5E_AM_GOING_LEFT;
switch (am->tune_state) {
case MLX5E_AM_PARKING_ON_TOP:
case MLX5E_AM_PARKING_TIRED:
- WARN_ONCE(true, "mlx5e_am_step: PARKING\n");
break;
case MLX5E_AM_GOING_RIGHT:
if (am->profile_ix == (MLX5E_PARAMS_AM_NUM_PROFILES - 1))
u32 delta_us = ktime_us_delta(end->time, start->time);
unsigned int npkts = end->pkt_ctr - start->pkt_ctr;
- if (!delta_us) {
- WARN_ONCE(true, "mlx5e_am_calc_stats: delta_us=0\n");
+ if (!delta_us)
return;
- }
curr_stats->ppms = (npkts * USEC_PER_MSEC) / delta_us;
curr_stats->epms = (MLX5E_AM_NEVENTS * USEC_PER_MSEC) / delta_us;
}
}
+/* we get here also when setting rule to the FW failed, etc. It means that the
+ * flow rule itself might not exist, but some offloading related to the actions
+ * should be cleaned.
+ */
static void mlx5e_tc_del_flow(struct mlx5e_priv *priv,
struct mlx5e_tc_flow *flow)
{
struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
struct mlx5_fc *counter = NULL;
- counter = mlx5_flow_rule_counter(flow->rule);
-
- mlx5_del_flow_rules(flow->rule);
+ if (!IS_ERR(flow->rule)) {
+ counter = mlx5_flow_rule_counter(flow->rule);
+ mlx5_del_flow_rules(flow->rule);
+ mlx5_fc_destroy(priv->mdev, counter);
+ }
if (esw && esw->mode == SRIOV_OFFLOADS) {
mlx5_eswitch_del_vlan_action(esw, flow->attr);
mlx5e_detach_encap(priv, flow);
}
- mlx5_fc_destroy(priv->mdev, counter);
-
if (!mlx5e_tc_num_filters(priv) && (priv->fs.tc.t)) {
mlx5_destroy_flow_table(priv->fs.tc.t);
priv->fs.tc.t = NULL;
void *headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
outer_headers);
+ struct flow_dissector_key_control *enc_control =
+ skb_flow_dissector_target(f->dissector,
+ FLOW_DISSECTOR_KEY_ENC_CONTROL,
+ f->key);
+
if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_PORTS)) {
struct flow_dissector_key_ports *key =
skb_flow_dissector_target(f->dissector,
/* Full udp dst port must be given */
if (memchr_inv(&mask->dst, 0xff, sizeof(mask->dst)))
- return -EOPNOTSUPP;
-
- /* udp src port isn't supported */
- if (memchr_inv(&mask->src, 0, sizeof(mask->src)))
- return -EOPNOTSUPP;
+ goto vxlan_match_offload_err;
if (mlx5e_vxlan_lookup_port(priv, be16_to_cpu(key->dst)) &&
MLX5_CAP_ESW(priv->mdev, vxlan_encap_decap))
parse_vxlan_attr(spec, f);
- else
+ else {
+ netdev_warn(priv->netdev,
+ "%d isn't an offloaded vxlan udp dport\n", be16_to_cpu(key->dst));
return -EOPNOTSUPP;
+ }
MLX5_SET(fte_match_set_lyr_2_4, headers_c,
udp_dport, ntohs(mask->dst));
MLX5_SET(fte_match_set_lyr_2_4, headers_v,
udp_dport, ntohs(key->dst));
+ MLX5_SET(fte_match_set_lyr_2_4, headers_c,
+ udp_sport, ntohs(mask->src));
+ MLX5_SET(fte_match_set_lyr_2_4, headers_v,
+ udp_sport, ntohs(key->src));
} else { /* udp dst port must be given */
- return -EOPNOTSUPP;
+vxlan_match_offload_err:
+ netdev_warn(priv->netdev,
+ "IP tunnel decap offload supported only for vxlan, must set UDP dport\n");
+ return -EOPNOTSUPP;
}
- if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS)) {
+ if (enc_control->addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
struct flow_dissector_key_ipv4_addrs *key =
skb_flow_dissector_target(f->dissector,
FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS,
MLX5_SET(fte_match_set_lyr_2_4, headers_v,
dst_ipv4_dst_ipv6.ipv4_layout.ipv4,
ntohl(key->dst));
- }
- MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, ethertype);
- MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, ETH_P_IP);
+ MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, ethertype);
+ MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, ETH_P_IP);
+ }
/* Enforce DMAC when offloading incoming tunneled flows.
* Flow counters require a match on the DMAC.
if (parse_tunnel_attr(priv, spec, f))
return -EOPNOTSUPP;
break;
+ case FLOW_DISSECTOR_KEY_IPV6_ADDRS:
+ netdev_warn(priv->netdev,
+ "IPv6 tunnel decap offload isn't supported\n");
default:
return -EOPNOTSUPP;
}
MLX5_SET(fte_match_set_lyr_2_4, headers_c, frag, 1);
MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag,
key->flags & FLOW_DIS_IS_FRAGMENT);
+
+ /* the HW doesn't need L3 inline to match on frag=no */
+ if (key->flags & FLOW_DIS_IS_FRAGMENT)
+ *min_inline = MLX5_INLINE_MODE_IP;
}
}
__be32 *saddr,
int *out_ttl)
{
+ struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
struct rtable *rt;
struct neighbour *n = NULL;
int ttl;
#if IS_ENABLED(CONFIG_INET)
+ int ret;
+
rt = ip_route_output_key(dev_net(mirred_dev), fl4);
- if (IS_ERR(rt)) {
- pr_warn("%s: no route to %pI4\n", __func__, &fl4->daddr);
- return -EOPNOTSUPP;
- }
+ ret = PTR_ERR_OR_ZERO(rt);
+ if (ret)
+ return ret;
#else
return -EOPNOTSUPP;
#endif
-
- if (!switchdev_port_same_parent_id(priv->netdev, rt->dst.dev)) {
- pr_warn("%s: Can't offload the flow, netdevices aren't on the same HW e-switch\n",
- __func__);
- ip_rt_put(rt);
- return -EOPNOTSUPP;
- }
+ /* if the egress device isn't on the same HW e-switch, we use the uplink */
+ if (!switchdev_port_same_parent_id(priv->netdev, rt->dst.dev))
+ *out_dev = mlx5_eswitch_get_uplink_netdev(esw);
+ else
+ *out_dev = rt->dst.dev;
ttl = ip4_dst_hoplimit(&rt->dst);
n = dst_neigh_lookup(&rt->dst, &fl4->daddr);
*out_n = n;
*saddr = fl4->saddr;
*out_ttl = ttl;
- *out_dev = rt->dst.dev;
return 0;
}
struct net_device **out_dev)
{
int max_encap_size = MLX5_CAP_ESW(priv->mdev, max_encap_header_size);
+ struct neighbour *n = NULL;
struct flowi4 fl4 = {};
- struct neighbour *n;
char *encap_header;
int encap_size;
__be32 saddr;
e->out_dev = *out_dev;
if (!(n->nud_state & NUD_VALID)) {
- err = -ENOTSUPP;
+ pr_warn("%s: can't offload, neighbour to %pI4 invalid\n", __func__, &fl4.daddr);
+ err = -EOPNOTSUPP;
goto out;
}
err = mlx5_encap_alloc(priv->mdev, e->tunnel_type,
encap_size, encap_header, &e->encap_id);
out:
+ if (err && n)
+ neigh_release(n);
kfree(encap_header);
return err;
}
int tunnel_type;
int err;
- /* udp dst port must be given */
+ /* udp dst port must be set */
if (!memchr_inv(&key->tp_dst, 0, sizeof(key->tp_dst)))
+ goto vxlan_encap_offload_err;
+
+ /* setting udp src port isn't supported */
+ if (memchr_inv(&key->tp_src, 0, sizeof(key->tp_src))) {
+vxlan_encap_offload_err:
+ netdev_warn(priv->netdev,
+ "must set udp dst port and not set udp src port\n");
return -EOPNOTSUPP;
+ }
if (mlx5e_vxlan_lookup_port(priv, be16_to_cpu(key->tp_dst)) &&
MLX5_CAP_ESW(priv->mdev, vxlan_encap_decap)) {
info.tun_id = tunnel_id_to_key32(key->tun_id);
tunnel_type = MLX5_HEADER_TYPE_VXLAN;
} else {
+ netdev_warn(priv->netdev,
+ "%d isn't an offloaded vxlan udp dport\n", be16_to_cpu(key->tp_dst));
return -EOPNOTSUPP;
}
case AF_INET:
info.daddr = key->u.ipv4.dst;
break;
+ case AF_INET6:
+ netdev_warn(priv->netdev,
+ "IPv6 tunnel encap offload isn't supported\n");
default:
return -EOPNOTSUPP;
}
if (IS_ERR(flow->rule)) {
err = PTR_ERR(flow->rule);
- goto err_free;
+ goto err_del_rule;
}
err = rhashtable_insert_fast(&tc->ht, &flow->node,
goto out;
err_del_rule:
- mlx5_del_flow_rules(flow->rule);
+ mlx5e_tc_del_flow(priv, flow);
err_free:
kfree(flow);
if (!MLX5_CAP_ESW(dev, vport_cvlan_strip) ||
!MLX5_CAP_ESW(dev, vport_cvlan_insert_if_not_exist))
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
esw_debug(dev, "Set Vport[%d] VLAN %d qos %d set=%x\n",
vport, vlan, qos, set_flags);
root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
if (!root_ns) {
esw_warn(dev, "Failed to get FDB flow namespace\n");
- return -ENOMEM;
+ return -EOPNOTSUPP;
}
flow_group_in = mlx5_vzalloc(inlen);
root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_ESW_EGRESS);
if (!root_ns) {
esw_warn(dev, "Failed to get E-Switch egress flow namespace\n");
- return -EIO;
+ return -EOPNOTSUPP;
}
flow_group_in = mlx5_vzalloc(inlen);
root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_ESW_INGRESS);
if (!root_ns) {
esw_warn(dev, "Failed to get E-Switch ingress flow namespace\n");
- return -EIO;
+ return -EOPNOTSUPP;
}
flow_group_in = mlx5_vzalloc(inlen);
if (!MLX5_CAP_GEN(esw->dev, eswitch_flow_table) ||
!MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, ft_support)) {
esw_warn(esw->dev, "E-Switch FDB is not supported, aborting ...\n");
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
}
if (!MLX5_CAP_ESW_INGRESS_ACL(esw->dev, ft_support))
return 0;
out_notsupp:
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
}
int mlx5_eswitch_add_vlan_action(struct mlx5_eswitch *esw,
root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
if (!root_ns) {
esw_warn(dev, "Failed to get FDB flow namespace\n");
+ err = -EOPNOTSUPP;
goto ns_err;
}
ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_OFFLOADS);
if (!ns) {
esw_warn(esw->dev, "Failed to get offloads flow namespace\n");
- return -ENOMEM;
+ return -EOPNOTSUPP;
}
ft_offloads = mlx5_create_flow_table(ns, 0, dev->priv.sriov.num_vfs + 2, 0, 0);
esw_warn(esw->dev, "Failed setting eswitch to offloads, err %d\n", err);
err1 = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_LEGACY);
if (err1)
- esw_warn(esw->dev, "Failed setting eswitch back to legacy, err %d\n", err);
+ esw_warn(esw->dev, "Failed setting eswitch back to legacy, err %d\n", err1);
}
if (esw->offloads.inline_mode == MLX5_INLINE_MODE_NONE) {
if (mlx5_eswitch_inline_mode_get(esw,
int vport;
int err;
+ /* disable PF RoCE so missed packets don't go through RoCE steering */
+ mlx5_dev_list_lock();
+ mlx5_remove_dev_by_protocol(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
+ mlx5_dev_list_unlock();
+
err = esw_create_offloads_fdb_table(esw, nvports);
if (err)
- return err;
+ goto create_fdb_err;
err = esw_create_offloads_table(esw);
if (err)
goto err_reps;
}
- /* disable PF RoCE so missed packets don't go through RoCE steering */
- mlx5_dev_list_lock();
- mlx5_remove_dev_by_protocol(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
- mlx5_dev_list_unlock();
-
return 0;
err_reps:
create_ft_err:
esw_destroy_offloads_fdb_table(esw);
+
+create_fdb_err:
+ /* enable back PF RoCE */
+ mlx5_dev_list_lock();
+ mlx5_add_dev_by_protocol(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
+ mlx5_dev_list_unlock();
+
return err;
}
{
int err, err1, num_vfs = esw->dev->priv.sriov.num_vfs;
- /* enable back PF RoCE */
- mlx5_dev_list_lock();
- mlx5_add_dev_by_protocol(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
- mlx5_dev_list_unlock();
-
mlx5_eswitch_disable_sriov(esw);
err = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_LEGACY);
if (err) {
esw_warn(esw->dev, "Failed setting eswitch back to offloads, err %d\n", err);
}
+ /* enable back PF RoCE */
+ mlx5_dev_list_lock();
+ mlx5_add_dev_by_protocol(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
+ mlx5_dev_list_unlock();
+
return err;
}
flow_table_properties_nic_receive.
flow_modify_en);
if (!atomic_mod_cap)
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
opmod = 1;
return mlx5_cmd_set_fte(dev, opmod, modify_mask, ft, group_id, fte);
struct mlx5_flow_table *ft;
ns = mlx5_get_flow_namespace(steering->dev, MLX5_FLOW_NAMESPACE_ANCHOR);
- if (!ns)
+ if (WARN_ON(!ns))
return -EINVAL;
ft = mlx5_create_flow_table(ns, ANCHOR_PRIO, ANCHOR_SIZE, ANCHOR_LEVEL, 0);
if (IS_ERR(ft)) {
return 0;
}
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
}
{
int err = 0;
- mlx5_drain_health_wq(dev);
+ if (cleanup)
+ mlx5_drain_health_wq(dev);
mutex_lock(&dev->intf_state_mutex);
if (test_bit(MLX5_INTERFACE_STATE_DOWN, &dev->intf_state)) {
mlx5_enter_error_state(dev);
mlx5_unload_one(dev, priv, false);
- /* In case of kernel call save the pci state */
+ /* In case of kernel call save the pci state and drain the health wq */
if (state) {
pci_save_state(pdev);
+ mlx5_drain_health_wq(dev);
mlx5_pci_disable_device(dev);
}
u32 out[MLX5_ST_SZ_DW(qtct_reg)];
if (!MLX5_CAP_GEN(mdev, ets))
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
return mlx5_core_access_reg(mdev, in, inlen, out, sizeof(out),
MLX5_REG_QETCR, 0, 1);
u32 in[MLX5_ST_SZ_DW(qtct_reg)];
if (!MLX5_CAP_GEN(mdev, ets))
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
memset(in, 0, sizeof(in));
return mlx5_core_access_reg(mdev, in, sizeof(in), out, outlen,
if (!MLX5_CAP_GEN(mdev, vport_group_manager))
return -EACCES;
if (!MLX5_CAP_ESW(mdev, nic_vport_node_guid_modify))
- return -ENOTSUPP;
+ return -EOPNOTSUPP;
in = mlx5_vzalloc(inlen);
if (!in)
/* pci_eqe_cmd_token
* Command completion event - token
*/
-MLXSW_ITEM32(pci, eqe, cmd_token, 0x08, 16, 16);
+MLXSW_ITEM32(pci, eqe, cmd_token, 0x00, 16, 16);
/* pci_eqe_cmd_status
* Command completion event - status
*/
-MLXSW_ITEM32(pci, eqe, cmd_status, 0x08, 0, 8);
+MLXSW_ITEM32(pci, eqe, cmd_status, 0x00, 0, 8);
/* pci_eqe_cmd_out_param_h
* Command completion event - output parameter - higher part
*/
-MLXSW_ITEM32(pci, eqe, cmd_out_param_h, 0x0C, 0, 32);
+MLXSW_ITEM32(pci, eqe, cmd_out_param_h, 0x04, 0, 32);
/* pci_eqe_cmd_out_param_l
* Command completion event - output parameter - lower part
*/
-MLXSW_ITEM32(pci, eqe, cmd_out_param_l, 0x10, 0, 32);
+MLXSW_ITEM32(pci, eqe, cmd_out_param_l, 0x08, 0, 32);
#endif
dev_kfree_skb_any(skb_orig);
return NETDEV_TX_OK;
}
+ dev_consume_skb_any(skb_orig);
}
if (eth_skb_pad(skb)) {
static int
mlxsw_sp_nexthop_group_mac_update(struct mlxsw_sp *mlxsw_sp,
- struct mlxsw_sp_nexthop_group *nh_grp)
+ struct mlxsw_sp_nexthop_group *nh_grp,
+ bool reallocate)
{
u32 adj_index = nh_grp->adj_index; /* base */
struct mlxsw_sp_nexthop *nh;
continue;
}
- if (nh->update) {
+ if (nh->update || reallocate) {
err = mlxsw_sp_nexthop_mac_update(mlxsw_sp,
adj_index, nh);
if (err)
/* Nothing was added or removed, so no need to reallocate. Just
* update MAC on existing adjacency indexes.
*/
- err = mlxsw_sp_nexthop_group_mac_update(mlxsw_sp, nh_grp);
+ err = mlxsw_sp_nexthop_group_mac_update(mlxsw_sp, nh_grp,
+ false);
if (err) {
dev_warn(mlxsw_sp->bus_info->dev, "Failed to update neigh MAC in adjacency table.\n");
goto set_trap;
nh_grp->adj_index_valid = 1;
nh_grp->adj_index = adj_index;
nh_grp->ecmp_size = ecmp_size;
- err = mlxsw_sp_nexthop_group_mac_update(mlxsw_sp, nh_grp);
+ err = mlxsw_sp_nexthop_group_mac_update(mlxsw_sp, nh_grp, true);
if (err) {
dev_warn(mlxsw_sp->bus_info->dev, "Failed to update neigh MAC in adjacency table.\n");
goto set_trap;
dev_kfree_skb_any(skb_orig);
return NETDEV_TX_OK;
}
+ dev_consume_skb_any(skb_orig);
}
mlxsw_sx_txhdr_construct(skb, &tx_info);
/* TX header is consumed by HW on the way so we shouldn't count its
list_del(&p_pkt->list_entry);
b_last_packet = list_empty(&p_tx->active_descq);
list_add_tail(&p_pkt->list_entry, &p_tx->free_descq);
- if (p_ll2_conn->conn_type == QED_LL2_TYPE_ISCSI_OOO) {
+ if (p_ll2_conn->conn.conn_type == QED_LL2_TYPE_ISCSI_OOO) {
struct qed_ooo_buffer *p_buffer;
p_buffer = (struct qed_ooo_buffer *)p_pkt->cookie;
b_last_frag =
p_tx->cur_completing_bd_idx == p_pkt->bd_used;
tx_frag = p_pkt->bds_set[0].tx_frag;
- if (p_ll2_conn->gsi_enable)
+ if (p_ll2_conn->conn.gsi_enable)
qed_ll2b_release_tx_gsi_packet(p_hwfn,
p_ll2_conn->
my_id,
spin_unlock_irqrestore(&p_tx->lock, flags);
tx_frag = p_pkt->bds_set[0].tx_frag;
- if (p_ll2_conn->gsi_enable)
+ if (p_ll2_conn->conn.gsi_enable)
qed_ll2b_complete_tx_gsi_packet(p_hwfn,
p_ll2_conn->my_id,
p_pkt->cookie,
list_move_tail(&p_pkt->list_entry, &p_rx->free_descq);
- if (p_ll2_conn->conn_type == QED_LL2_TYPE_ISCSI_OOO) {
+ if (p_ll2_conn->conn.conn_type == QED_LL2_TYPE_ISCSI_OOO) {
struct qed_ooo_buffer *p_buffer;
p_buffer = (struct qed_ooo_buffer *)p_pkt->cookie;
rc = qed_ll2_prepare_tx_packet(p_hwfn, p_ll2_conn->my_id, 1,
p_buffer->vlan, bd_flags,
l4_hdr_offset_w,
- p_ll2_conn->tx_dest, 0,
+ p_ll2_conn->conn.tx_dest, 0,
first_frag,
p_buffer->packet_length,
p_buffer, true);
u16 buf_idx;
int rc = 0;
- if (p_ll2_info->conn_type != QED_LL2_TYPE_ISCSI_OOO)
+ if (p_ll2_info->conn.conn_type != QED_LL2_TYPE_ISCSI_OOO)
return rc;
if (!rx_num_ooo_buffers)
qed_ll2_establish_connection_ooo(struct qed_hwfn *p_hwfn,
struct qed_ll2_info *p_ll2_conn)
{
- if (p_ll2_conn->conn_type != QED_LL2_TYPE_ISCSI_OOO)
+ if (p_ll2_conn->conn.conn_type != QED_LL2_TYPE_ISCSI_OOO)
return;
qed_ooo_release_all_isles(p_hwfn, p_hwfn->p_ooo_info);
{
struct qed_ooo_buffer *p_buffer;
- if (p_ll2_conn->conn_type != QED_LL2_TYPE_ISCSI_OOO)
+ if (p_ll2_conn->conn.conn_type != QED_LL2_TYPE_ISCSI_OOO)
return;
qed_ooo_release_all_isles(p_hwfn, p_hwfn->p_ooo_info);
{
struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev);
u8 *handle = &hwfn->pf_params.iscsi_pf_params.ll2_ooo_queue_id;
- struct qed_ll2_info *ll2_info;
+ struct qed_ll2_conn ll2_info;
int rc;
- ll2_info = kzalloc(sizeof(*ll2_info), GFP_KERNEL);
- if (!ll2_info)
- return -ENOMEM;
- ll2_info->conn_type = QED_LL2_TYPE_ISCSI_OOO;
- ll2_info->mtu = params->mtu;
- ll2_info->rx_drop_ttl0_flg = params->drop_ttl0_packets;
- ll2_info->rx_vlan_removal_en = params->rx_vlan_stripping;
- ll2_info->tx_tc = OOO_LB_TC;
- ll2_info->tx_dest = CORE_TX_DEST_LB;
-
- rc = qed_ll2_acquire_connection(hwfn, ll2_info,
+ ll2_info.conn_type = QED_LL2_TYPE_ISCSI_OOO;
+ ll2_info.mtu = params->mtu;
+ ll2_info.rx_drop_ttl0_flg = params->drop_ttl0_packets;
+ ll2_info.rx_vlan_removal_en = params->rx_vlan_stripping;
+ ll2_info.tx_tc = OOO_LB_TC;
+ ll2_info.tx_dest = CORE_TX_DEST_LB;
+
+ rc = qed_ll2_acquire_connection(hwfn, &ll2_info,
QED_LL2_RX_SIZE, QED_LL2_TX_SIZE,
handle);
- kfree(ll2_info);
if (rc) {
DP_INFO(cdev, "Failed to acquire LL2 OOO connection\n");
goto out;
struct qed_ll2_info *p_ll2_conn,
u8 action_on_error)
{
- enum qed_ll2_conn_type conn_type = p_ll2_conn->conn_type;
+ enum qed_ll2_conn_type conn_type = p_ll2_conn->conn.conn_type;
struct qed_ll2_rx_queue *p_rx = &p_ll2_conn->rx_queue;
struct core_rx_start_ramrod_data *p_ramrod = NULL;
struct qed_spq_entry *p_ent = NULL;
p_ramrod->sb_index = p_rx->rx_sb_index;
p_ramrod->complete_event_flg = 1;
- p_ramrod->mtu = cpu_to_le16(p_ll2_conn->mtu);
+ p_ramrod->mtu = cpu_to_le16(p_ll2_conn->conn.mtu);
DMA_REGPAIR_LE(p_ramrod->bd_base,
p_rx->rxq_chain.p_phys_addr);
cqe_pbl_size = (u16)qed_chain_get_page_cnt(&p_rx->rcq_chain);
DMA_REGPAIR_LE(p_ramrod->cqe_pbl_addr,
qed_chain_get_pbl_phys(&p_rx->rcq_chain));
- p_ramrod->drop_ttl0_flg = p_ll2_conn->rx_drop_ttl0_flg;
- p_ramrod->inner_vlan_removal_en = p_ll2_conn->rx_vlan_removal_en;
+ p_ramrod->drop_ttl0_flg = p_ll2_conn->conn.rx_drop_ttl0_flg;
+ p_ramrod->inner_vlan_removal_en = p_ll2_conn->conn.rx_vlan_removal_en;
p_ramrod->queue_id = p_ll2_conn->queue_id;
p_ramrod->main_func_queue = (conn_type == QED_LL2_TYPE_ISCSI_OOO) ? 0
: 1;
}
p_ramrod->action_on_error.error_type = action_on_error;
- p_ramrod->gsi_offload_flag = p_ll2_conn->gsi_enable;
+ p_ramrod->gsi_offload_flag = p_ll2_conn->conn.gsi_enable;
return qed_spq_post(p_hwfn, p_ent, NULL);
}
static int qed_sp_ll2_tx_queue_start(struct qed_hwfn *p_hwfn,
struct qed_ll2_info *p_ll2_conn)
{
- enum qed_ll2_conn_type conn_type = p_ll2_conn->conn_type;
+ enum qed_ll2_conn_type conn_type = p_ll2_conn->conn.conn_type;
struct qed_ll2_tx_queue *p_tx = &p_ll2_conn->tx_queue;
struct core_tx_start_ramrod_data *p_ramrod = NULL;
struct qed_spq_entry *p_ent = NULL;
if (!QED_LL2_TX_REGISTERED(p_ll2_conn))
return 0;
- if (p_ll2_conn->conn_type == QED_LL2_TYPE_ISCSI_OOO)
+ if (p_ll2_conn->conn.conn_type == QED_LL2_TYPE_ISCSI_OOO)
p_ll2_conn->tx_stats_en = 0;
else
p_ll2_conn->tx_stats_en = 1;
p_ramrod->sb_id = cpu_to_le16(qed_int_get_sp_sb_id(p_hwfn));
p_ramrod->sb_index = p_tx->tx_sb_index;
- p_ramrod->mtu = cpu_to_le16(p_ll2_conn->mtu);
+ p_ramrod->mtu = cpu_to_le16(p_ll2_conn->conn.mtu);
p_ramrod->stats_en = p_ll2_conn->tx_stats_en;
p_ramrod->stats_id = p_ll2_conn->tx_stats_id;
p_ramrod->pbl_size = cpu_to_le16(pbl_size);
memset(&pq_params, 0, sizeof(pq_params));
- pq_params.core.tc = p_ll2_conn->tx_tc;
+ pq_params.core.tc = p_ll2_conn->conn.tx_tc;
pq_id = qed_get_qm_pq(p_hwfn, PROTOCOLID_CORE, &pq_params);
p_ramrod->qm_pq_id = cpu_to_le16(pq_id);
DP_NOTICE(p_hwfn, "Unknown connection type: %d\n", conn_type);
}
- p_ramrod->gsi_offload_flag = p_ll2_conn->gsi_enable;
+ p_ramrod->gsi_offload_flag = p_ll2_conn->conn.gsi_enable;
return qed_spq_post(p_hwfn, p_ent, NULL);
}
DP_VERBOSE(p_hwfn, QED_MSG_LL2,
"Allocated LL2 Rxq [Type %08x] with 0x%08x buffers\n",
- p_ll2_info->conn_type, rx_num_desc);
+ p_ll2_info->conn.conn_type, rx_num_desc);
out:
return rc;
DP_VERBOSE(p_hwfn, QED_MSG_LL2,
"Allocated LL2 Txq [Type %08x] with 0x%08x buffers\n",
- p_ll2_info->conn_type, tx_num_desc);
+ p_ll2_info->conn.conn_type, tx_num_desc);
out:
if (rc)
}
int qed_ll2_acquire_connection(struct qed_hwfn *p_hwfn,
- struct qed_ll2_info *p_params,
+ struct qed_ll2_conn *p_params,
u16 rx_num_desc,
u16 tx_num_desc,
u8 *p_connection_handle)
if (!p_ll2_info)
return -EBUSY;
- p_ll2_info->conn_type = p_params->conn_type;
- p_ll2_info->mtu = p_params->mtu;
- p_ll2_info->rx_drop_ttl0_flg = p_params->rx_drop_ttl0_flg;
- p_ll2_info->rx_vlan_removal_en = p_params->rx_vlan_removal_en;
- p_ll2_info->tx_tc = p_params->tx_tc;
- p_ll2_info->tx_dest = p_params->tx_dest;
- p_ll2_info->ai_err_packet_too_big = p_params->ai_err_packet_too_big;
- p_ll2_info->ai_err_no_buf = p_params->ai_err_no_buf;
- p_ll2_info->gsi_enable = p_params->gsi_enable;
+ p_ll2_info->conn = *p_params;
rc = qed_ll2_acquire_connection_rx(p_hwfn, p_ll2_info, rx_num_desc);
if (rc)
SET_FIELD(action_on_error,
CORE_RX_ACTION_ON_ERROR_PACKET_TOO_BIG,
- p_ll2_conn->ai_err_packet_too_big);
+ p_ll2_conn->conn.ai_err_packet_too_big);
SET_FIELD(action_on_error,
- CORE_RX_ACTION_ON_ERROR_NO_BUFF, p_ll2_conn->ai_err_no_buf);
+ CORE_RX_ACTION_ON_ERROR_NO_BUFF, p_ll2_conn->conn.ai_err_no_buf);
return qed_sp_ll2_rx_queue_start(p_hwfn, p_ll2_conn, action_on_error);
}
"LL2 [q 0x%02x cid 0x%08x type 0x%08x] Tx Producer at [0x%04x] - set with a %04x bytes %02x BDs buffer at %08x:%08x\n",
p_ll2->queue_id,
p_ll2->cid,
- p_ll2->conn_type,
+ p_ll2->conn.conn_type,
prod_idx,
first_frag_len,
num_of_bds,
(NETIF_MSG_TX_QUEUED | QED_MSG_LL2),
"LL2 [q 0x%02x cid 0x%08x type 0x%08x] Doorbelled [producer 0x%04x]\n",
p_ll2_conn->queue_id,
- p_ll2_conn->cid, p_ll2_conn->conn_type, db_msg.spq_prod);
+ p_ll2_conn->cid, p_ll2_conn->conn.conn_type, db_msg.spq_prod);
}
int qed_ll2_prepare_tx_packet(struct qed_hwfn *p_hwfn,
qed_ll2_rxq_flush(p_hwfn, connection_handle);
}
- if (p_ll2_conn->conn_type == QED_LL2_TYPE_ISCSI_OOO)
+ if (p_ll2_conn->conn.conn_type == QED_LL2_TYPE_ISCSI_OOO)
qed_ooo_release_all_isles(p_hwfn, p_hwfn->p_ooo_info);
return rc;
static int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params)
{
- struct qed_ll2_info ll2_info;
+ struct qed_ll2_conn ll2_info;
struct qed_ll2_buffer *buffer, *tmp_buffer;
enum qed_ll2_conn_type conn_type;
struct qed_ptt *p_ptt;
/* Prepare the temporary ll2 information */
memset(&ll2_info, 0, sizeof(ll2_info));
+
ll2_info.conn_type = conn_type;
ll2_info.mtu = params->mtu;
ll2_info.rx_drop_ttl0_flg = params->drop_ttl0_packets;
}
ether_addr_copy(cdev->ll2_mac_address, params->ll2_mac_address);
-
return 0;
release_terminate_all:
bool b_completing_packet;
};
-struct qed_ll2_info {
- /* Lock protecting the state of LL2 */
- struct mutex mutex;
+struct qed_ll2_conn {
enum qed_ll2_conn_type conn_type;
- u32 cid;
- u8 my_id;
- u8 queue_id;
- u8 tx_stats_id;
- bool b_active;
u16 mtu;
u8 rx_drop_ttl0_flg;
u8 rx_vlan_removal_en;
enum core_tx_dest tx_dest;
enum core_error_handle ai_err_packet_too_big;
enum core_error_handle ai_err_no_buf;
+ u8 gsi_enable;
+};
+
+struct qed_ll2_info {
+ /* Lock protecting the state of LL2 */
+ struct mutex mutex;
+ struct qed_ll2_conn conn;
+ u32 cid;
+ u8 my_id;
+ u8 queue_id;
+ u8 tx_stats_id;
+ bool b_active;
u8 tx_stats_en;
struct qed_ll2_rx_queue rx_queue;
struct qed_ll2_tx_queue tx_queue;
- u8 gsi_enable;
};
/**
* @return 0 on success, failure otherwise
*/
int qed_ll2_acquire_connection(struct qed_hwfn *p_hwfn,
- struct qed_ll2_info *p_params,
+ struct qed_ll2_conn *p_params,
u16 rx_num_desc,
u16 tx_num_desc,
u8 *p_connection_handle);
{
struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev);
struct qed_roce_ll2_info *roce_ll2;
- struct qed_ll2_info ll2_params;
+ struct qed_ll2_conn ll2_params;
int rc;
if (!params) {
else
adpt->phydev = mdiobus_get_phy(mii_bus, phy_addr);
+ /* of_phy_find_device() claims a reference to the phydev,
+ * so we do that here manually as well. When the driver
+ * later unloads, it can unilaterally drop the reference
+ * without worrying about ACPI vs DT.
+ */
+ if (adpt->phydev)
+ get_device(&adpt->phydev->mdio.dev);
} else {
struct device_node *phy_np;
err_undo_napi:
netif_napi_del(&adpt->rx_q.napi);
err_undo_mdiobus:
- if (!has_acpi_companion(&pdev->dev))
- put_device(&adpt->phydev->mdio.dev);
+ put_device(&adpt->phydev->mdio.dev);
mdiobus_unregister(adpt->mii_bus);
err_undo_clocks:
emac_clks_teardown(adpt);
emac_clks_teardown(adpt);
- if (!has_acpi_companion(&pdev->dev))
- put_device(&adpt->phydev->mdio.dev);
+ put_device(&adpt->phydev->mdio.dev);
mdiobus_unregister(adpt->mii_bus);
free_netdev(netdev);
enum rtl_rx_desc_bit {
/* Rx private */
PID1 = (1 << 18), /* Protocol ID bit 1/2 */
- PID0 = (1 << 17), /* Protocol ID bit 2/2 */
+ PID0 = (1 << 17), /* Protocol ID bit 0/2 */
#define RxProtoUDP (PID1)
#define RxProtoTCP (PID0)
.get_mdio_data = ravb_get_mdio_data,
};
+/* Free TX skb function for AVB-IP */
+static int ravb_tx_free(struct net_device *ndev, int q, bool free_txed_only)
+{
+ struct ravb_private *priv = netdev_priv(ndev);
+ struct net_device_stats *stats = &priv->stats[q];
+ struct ravb_tx_desc *desc;
+ int free_num = 0;
+ int entry;
+ u32 size;
+
+ for (; priv->cur_tx[q] - priv->dirty_tx[q] > 0; priv->dirty_tx[q]++) {
+ bool txed;
+
+ entry = priv->dirty_tx[q] % (priv->num_tx_ring[q] *
+ NUM_TX_DESC);
+ desc = &priv->tx_ring[q][entry];
+ txed = desc->die_dt == DT_FEMPTY;
+ if (free_txed_only && !txed)
+ break;
+ /* Descriptor type must be checked before all other reads */
+ dma_rmb();
+ size = le16_to_cpu(desc->ds_tagl) & TX_DS;
+ /* Free the original skb. */
+ if (priv->tx_skb[q][entry / NUM_TX_DESC]) {
+ dma_unmap_single(ndev->dev.parent, le32_to_cpu(desc->dptr),
+ size, DMA_TO_DEVICE);
+ /* Last packet descriptor? */
+ if (entry % NUM_TX_DESC == NUM_TX_DESC - 1) {
+ entry /= NUM_TX_DESC;
+ dev_kfree_skb_any(priv->tx_skb[q][entry]);
+ priv->tx_skb[q][entry] = NULL;
+ if (txed)
+ stats->tx_packets++;
+ }
+ free_num++;
+ }
+ if (txed)
+ stats->tx_bytes += size;
+ desc->die_dt = DT_EEMPTY;
+ }
+ return free_num;
+}
+
/* Free skb's and DMA buffers for Ethernet AVB */
static void ravb_ring_free(struct net_device *ndev, int q)
{
kfree(priv->rx_skb[q]);
priv->rx_skb[q] = NULL;
- /* Free TX skb ringbuffer */
- if (priv->tx_skb[q]) {
- for (i = 0; i < priv->num_tx_ring[q]; i++)
- dev_kfree_skb(priv->tx_skb[q][i]);
- }
- kfree(priv->tx_skb[q]);
- priv->tx_skb[q] = NULL;
-
/* Free aligned TX buffers */
kfree(priv->tx_align[q]);
priv->tx_align[q] = NULL;
if (priv->rx_ring[q]) {
+ for (i = 0; i < priv->num_rx_ring[q]; i++) {
+ struct ravb_ex_rx_desc *desc = &priv->rx_ring[q][i];
+
+ if (!dma_mapping_error(ndev->dev.parent,
+ le32_to_cpu(desc->dptr)))
+ dma_unmap_single(ndev->dev.parent,
+ le32_to_cpu(desc->dptr),
+ PKT_BUF_SZ,
+ DMA_FROM_DEVICE);
+ }
ring_size = sizeof(struct ravb_ex_rx_desc) *
(priv->num_rx_ring[q] + 1);
dma_free_coherent(ndev->dev.parent, ring_size, priv->rx_ring[q],
}
if (priv->tx_ring[q]) {
+ ravb_tx_free(ndev, q, false);
+
ring_size = sizeof(struct ravb_tx_desc) *
(priv->num_tx_ring[q] * NUM_TX_DESC + 1);
dma_free_coherent(ndev->dev.parent, ring_size, priv->tx_ring[q],
priv->tx_desc_dma[q]);
priv->tx_ring[q] = NULL;
}
+
+ /* Free TX skb ringbuffer.
+ * SKBs are freed by ravb_tx_free() call above.
+ */
+ kfree(priv->tx_skb[q]);
+ priv->tx_skb[q] = NULL;
}
/* Format skb and descriptor buffer for Ethernet AVB */
return 0;
}
-/* Free TX skb function for AVB-IP */
-static int ravb_tx_free(struct net_device *ndev, int q)
-{
- struct ravb_private *priv = netdev_priv(ndev);
- struct net_device_stats *stats = &priv->stats[q];
- struct ravb_tx_desc *desc;
- int free_num = 0;
- int entry;
- u32 size;
-
- for (; priv->cur_tx[q] - priv->dirty_tx[q] > 0; priv->dirty_tx[q]++) {
- entry = priv->dirty_tx[q] % (priv->num_tx_ring[q] *
- NUM_TX_DESC);
- desc = &priv->tx_ring[q][entry];
- if (desc->die_dt != DT_FEMPTY)
- break;
- /* Descriptor type must be checked before all other reads */
- dma_rmb();
- size = le16_to_cpu(desc->ds_tagl) & TX_DS;
- /* Free the original skb. */
- if (priv->tx_skb[q][entry / NUM_TX_DESC]) {
- dma_unmap_single(ndev->dev.parent, le32_to_cpu(desc->dptr),
- size, DMA_TO_DEVICE);
- /* Last packet descriptor? */
- if (entry % NUM_TX_DESC == NUM_TX_DESC - 1) {
- entry /= NUM_TX_DESC;
- dev_kfree_skb_any(priv->tx_skb[q][entry]);
- priv->tx_skb[q][entry] = NULL;
- stats->tx_packets++;
- }
- free_num++;
- }
- stats->tx_bytes += size;
- desc->die_dt = DT_EEMPTY;
- }
- return free_num;
-}
-
static void ravb_get_tx_tstamp(struct net_device *ndev)
{
struct ravb_private *priv = netdev_priv(ndev);
spin_lock_irqsave(&priv->lock, flags);
/* Clear TX interrupt */
ravb_write(ndev, ~mask, TIS);
- ravb_tx_free(ndev, q);
+ ravb_tx_free(ndev, q, true);
netif_wake_subqueue(ndev, q);
mmiowb();
spin_unlock_irqrestore(&priv->lock, flags);
/* Receive error message handling */
priv->rx_over_errors = priv->stats[RAVB_BE].rx_over_errors;
priv->rx_over_errors += priv->stats[RAVB_NC].rx_over_errors;
- if (priv->rx_over_errors != ndev->stats.rx_over_errors) {
+ if (priv->rx_over_errors != ndev->stats.rx_over_errors)
ndev->stats.rx_over_errors = priv->rx_over_errors;
- netif_err(priv, rx_err, ndev, "Receive Descriptor Empty\n");
- }
- if (priv->rx_fifo_errors != ndev->stats.rx_fifo_errors) {
+ if (priv->rx_fifo_errors != ndev->stats.rx_fifo_errors)
ndev->stats.rx_fifo_errors = priv->rx_fifo_errors;
- netif_err(priv, rx_err, ndev, "Receive FIFO Overflow\n");
- }
out:
return budget - quota;
}
buffer = PTR_ALIGN(priv->tx_align[q], DPTR_ALIGN) +
entry / NUM_TX_DESC * DPTR_ALIGN;
len = PTR_ALIGN(skb->data, DPTR_ALIGN) - skb->data;
+ /* Zero length DMA descriptors are problematic as they seem to
+ * terminate DMA transfers. Avoid them by simply using a length of
+ * DPTR_ALIGN (4) when skb data is aligned to DPTR_ALIGN.
+ *
+ * As skb is guaranteed to have at least ETH_ZLEN (60) bytes of
+ * data by the call to skb_put_padto() above this is safe with
+ * respect to both the length of the first DMA descriptor (len)
+ * overflowing the available data and the length of the second DMA
+ * descriptor (skb->len - len) being negative.
+ */
+ if (len == 0)
+ len = DPTR_ALIGN;
+
memcpy(buffer, skb->data, len);
dma_addr = dma_map_single(ndev->dev.parent, buffer, len, DMA_TO_DEVICE);
if (dma_mapping_error(ndev->dev.parent, dma_addr))
priv->cur_tx[q] += NUM_TX_DESC;
if (priv->cur_tx[q] - priv->dirty_tx[q] >
- (priv->num_tx_ring[q] - 1) * NUM_TX_DESC && !ravb_tx_free(ndev, q))
+ (priv->num_tx_ring[q] - 1) * NUM_TX_DESC &&
+ !ravb_tx_free(ndev, q, true))
netif_stop_subqueue(ndev, q);
exit:
.rpadir_value = 2 << 16,
.no_trimd = 1,
.no_ade = 1,
+ .hw_crc = 1,
.tsu = 1,
.select_mii = 1,
.shift_rd0 = 1,
.ecsr_value = ECSR_ICD | ECSR_MPD,
.ecsipr_value = ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP,
- .eesipr_value = DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff,
+ .eesipr_value = DMAC_M_RFRMER | DMAC_M_ECI | 0x003f07ff,
.tx_check = EESR_TC1 | EESR_FTC,
.eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT |
.ecsr_value = ECSR_ICD | ECSR_MPD,
.ecsipr_value = ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP,
- .eesipr_value = DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff,
+ .eesipr_value = DMAC_M_RFRMER | DMAC_M_ECI | 0x003f07ff,
.tx_check = EESR_TC1 | EESR_FTC,
.eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT |
{
void __iomem *ioaddr = hw->pcsr;
u32 intr_status = readl(ioaddr + GMAC_INT_STATUS);
+ u32 intr_mask = readl(ioaddr + GMAC_INT_MASK);
int ret = 0;
+ /* Discard masked bits */
+ intr_status &= ~intr_mask;
+
/* Not used events (e.g. MMC interrupts) are not handled. */
if ((intr_status & GMAC_INT_STATUS_MMCTIS))
x->mmc_tx_irq_n++;
ndev->max_mtu = JUMBO_LEN;
else
ndev->max_mtu = SKB_MAX_HEAD(NET_SKB_PAD + NET_IP_ALIGN);
- if (priv->plat->maxmtu < ndev->max_mtu)
+ /* Will not overwrite ndev->max_mtu if plat->maxmtu > ndev->max_mtu
+ * as well as plat->maxmtu < ndev->min_mtu which is a invalid range.
+ */
+ if ((priv->plat->maxmtu < ndev->max_mtu) &&
+ (priv->plat->maxmtu >= ndev->min_mtu))
ndev->max_mtu = priv->plat->maxmtu;
+ else if (priv->plat->maxmtu < ndev->min_mtu)
+ dev_warn(priv->device,
+ "%s: warning: maxmtu having invalid value (%d)\n",
+ __func__, priv->plat->maxmtu);
if (flow_ctrl)
priv->flow_ctrl = FLOW_AUTO; /* RX/TX pause on */
*/
if ((priv->synopsys_id >= DWMAC_CORE_3_50) && (!priv->plat->riwt_off)) {
priv->use_riwt = 1;
- netdev_info(priv->dev, "Enable RX Mitigation via HW Watchdog Timer\n");
+ dev_info(priv->device,
+ "Enable RX Mitigation via HW Watchdog Timer\n");
}
netif_napi_add(ndev, &priv->napi, stmmac_poll, 64);
/* MDIO bus Registration */
ret = stmmac_mdio_register(ndev);
if (ret < 0) {
- netdev_err(priv->dev,
- "%s: MDIO bus (id: %d) registration failed",
- __func__, priv->plat->bus_id);
+ dev_err(priv->device,
+ "%s: MDIO bus (id: %d) registration failed",
+ __func__, priv->plat->bus_id);
goto error_mdio_register;
}
}
ret = register_netdev(ndev);
if (ret) {
- netdev_err(priv->dev, "%s: ERROR %i registering the device\n",
- __func__, ret);
+ dev_err(priv->device, "%s: ERROR %i registering the device\n",
+ __func__, ret);
goto error_netdev_register;
}
/* Set default value for unicast filter entries */
plat->unicast_filter_entries = 1;
+
+ /* Set the maxmtu to a default of JUMBO_LEN */
+ plat->maxmtu = JUMBO_LEN;
}
static int quark_default_data(struct plat_stmmacenet_data *plat,
/* Set default value for unicast filter entries */
plat->unicast_filter_entries = 1;
+ /* Set the maxmtu to a default of JUMBO_LEN */
+ plat->maxmtu = JUMBO_LEN;
+
return 0;
}
if (of_phy_is_fixed_link(np))
of_phy_deregister_fixed_link(np);
of_node_put(plat->phy_node);
+ of_node_put(plat->mdio_node);
}
#else
struct plat_stmmacenet_data *
goto fail_alloc;
}
-#warning FIXME: unhardcode gpio&reset bits
+ /* FIXME: unhardcode gpio&reset bits */
ar7_gpio_disable(26);
ar7_gpio_disable(27);
ar7_device_reset(AR7_RESET_BIT_CPMAC_LO);
struct socket *sock0;
struct socket *sock1u;
- struct net *net;
struct net_device *dev;
unsigned int hash_size;
netdev_dbg(gtp->dev, "encap_recv sk=%p\n", sk);
- xnet = !net_eq(gtp->net, dev_net(gtp->dev));
+ xnet = !net_eq(sock_net(sk), dev_net(gtp->dev));
switch (udp_sk(sk)->encap_type) {
case UDP_ENCAP_GTP0:
pktinfo.fl4.saddr, pktinfo.fl4.daddr,
pktinfo.iph->tos,
ip4_dst_hoplimit(&pktinfo.rt->dst),
- htons(IP_DF),
+ 0,
pktinfo.gtph_port, pktinfo.gtph_port,
true, false);
break;
static int gtp_hashtable_new(struct gtp_dev *gtp, int hsize);
static void gtp_hashtable_free(struct gtp_dev *gtp);
static int gtp_encap_enable(struct net_device *dev, struct gtp_dev *gtp,
- int fd_gtp0, int fd_gtp1, struct net *src_net);
+ int fd_gtp0, int fd_gtp1);
static int gtp_newlink(struct net *src_net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[])
fd0 = nla_get_u32(data[IFLA_GTP_FD0]);
fd1 = nla_get_u32(data[IFLA_GTP_FD1]);
- err = gtp_encap_enable(dev, gtp, fd0, fd1, src_net);
+ err = gtp_encap_enable(dev, gtp, fd0, fd1);
if (err < 0)
goto out_err;
}
static int gtp_encap_enable(struct net_device *dev, struct gtp_dev *gtp,
- int fd_gtp0, int fd_gtp1, struct net *src_net)
+ int fd_gtp0, int fd_gtp1)
{
struct udp_tunnel_sock_cfg tuncfg = {NULL};
struct socket *sock0, *sock1u;
gtp->sock0 = sock0;
gtp->sock1u = sock1u;
- gtp->net = src_net;
tuncfg.sk_user_data = gtp;
tuncfg.encap_rcv = gtp_encap_recv;
MODULE_AUTHOR("Harald Welte <hwelte@sysmocom.de>");
MODULE_DESCRIPTION("Interface driver for GTP encapsulated traffic");
MODULE_ALIAS_RTNL_LINK("gtp");
+MODULE_ALIAS_GENL_FAMILY("gtp");
ndev = hv_get_drvdata(device);
buffer = get_per_channel_state(channel);
+ /* commit_rd_index() -> hv_signal_on_read() needs this. */
+ init_cached_read_index(channel);
+
do {
desc = get_next_pkt_raw(channel);
if (desc != NULL) {
bufferlen = bytes_recvd;
}
+
+ init_cached_read_index(channel);
+
} while (1);
if (bufferlen > NETVSC_PACKET_SIZE)
* policy filters on the host). Deliver these via the VF
* interface in the guest.
*/
+ rcu_read_lock();
vf_netdev = rcu_dereference(net_device_ctx->vf_netdev);
if (vf_netdev && (vf_netdev->flags & IFF_UP))
net = vf_netdev;
skb = netvsc_alloc_recv_skb(net, packet, csum_info, *data, vlan_tci);
if (unlikely(!skb)) {
++net->stats.rx_dropped;
+ rcu_read_unlock();
return NVSP_STAT_FAIL;
}
* TODO - use NAPI?
*/
netif_rx(skb);
+ rcu_read_unlock();
return 0;
}
/* Reset */
if (gpio_is_valid(rstn)) {
udelay(1);
- gpio_set_value(rstn, 0);
+ gpio_set_value_cansleep(rstn, 0);
udelay(1);
- gpio_set_value(rstn, 1);
+ gpio_set_value_cansleep(rstn, 1);
usleep_range(120, 240);
}
{
struct usb_device *usb_dev = atusb->usb_dev;
int ret;
+ uint8_t *buffer;
uint8_t value;
+ buffer = kmalloc(1, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
dev_dbg(&usb_dev->dev, "atusb: reg = 0x%x\n", reg);
ret = atusb_control_msg(atusb, usb_rcvctrlpipe(usb_dev, 0),
ATUSB_REG_READ, ATUSB_REQ_FROM_DEV,
- 0, reg, &value, 1, 1000);
- return ret >= 0 ? value : ret;
+ 0, reg, buffer, 1, 1000);
+
+ if (ret >= 0) {
+ value = buffer[0];
+ kfree(buffer);
+ return value;
+ } else {
+ kfree(buffer);
+ return ret;
+ }
}
static int atusb_write_subreg(struct atusb *atusb, uint8_t reg, uint8_t mask,
atusb_set_frame_retries(struct ieee802154_hw *hw, s8 retries)
{
struct atusb *atusb = hw->priv;
- struct device *dev = &atusb->usb_dev->dev;
-
- if (atusb->fw_ver_maj == 0 && atusb->fw_ver_min < 3) {
- dev_info(dev, "Automatic frame retransmission is only available from "
- "firmware version 0.3. Please update if you want this feature.");
- return -EINVAL;
- }
return atusb_write_subreg(atusb, SR_MAX_FRAME_RETRIES, retries);
}
static int atusb_get_and_show_revision(struct atusb *atusb)
{
struct usb_device *usb_dev = atusb->usb_dev;
- unsigned char buffer[3];
+ unsigned char *buffer;
int ret;
+ buffer = kmalloc(3, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
/* Get a couple of the ATMega Firmware values */
ret = atusb_control_msg(atusb, usb_rcvctrlpipe(usb_dev, 0),
ATUSB_ID, ATUSB_REQ_FROM_DEV, 0, 0,
dev_info(&usb_dev->dev, "Please update to version 0.2 or newer");
}
+ kfree(buffer);
return ret;
}
static int atusb_get_and_show_build(struct atusb *atusb)
{
struct usb_device *usb_dev = atusb->usb_dev;
- char build[ATUSB_BUILD_SIZE + 1];
+ char *build;
int ret;
+ build = kmalloc(ATUSB_BUILD_SIZE + 1, GFP_KERNEL);
+ if (!build)
+ return -ENOMEM;
+
ret = atusb_control_msg(atusb, usb_rcvctrlpipe(usb_dev, 0),
ATUSB_BUILD, ATUSB_REQ_FROM_DEV, 0, 0,
build, ATUSB_BUILD_SIZE, 1000);
dev_info(&usb_dev->dev, "Firmware: build %s\n", build);
}
+ kfree(build);
return ret;
}
static int atusb_set_extended_addr(struct atusb *atusb)
{
struct usb_device *usb_dev = atusb->usb_dev;
- unsigned char buffer[IEEE802154_EXTENDED_ADDR_LEN];
+ unsigned char *buffer;
__le64 extended_addr;
u64 addr;
int ret;
return 0;
}
+ buffer = kmalloc(IEEE802154_EXTENDED_ADDR_LEN, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
/* Firmware is new enough so we fetch the address from EEPROM */
ret = atusb_control_msg(atusb, usb_rcvctrlpipe(usb_dev, 0),
ATUSB_EUI64_READ, ATUSB_REQ_FROM_DEV, 0, 0,
buffer, IEEE802154_EXTENDED_ADDR_LEN, 1000);
- if (ret < 0)
- dev_err(&usb_dev->dev, "failed to fetch extended address\n");
+ if (ret < 0) {
+ dev_err(&usb_dev->dev, "failed to fetch extended address, random address set\n");
+ ieee802154_random_extended_addr(&atusb->hw->phy->perm_extended_addr);
+ kfree(buffer);
+ return ret;
+ }
memcpy(&extended_addr, buffer, IEEE802154_EXTENDED_ADDR_LEN);
/* Check if read address is not empty and the unicast bit is set correctly */
&addr);
}
+ kfree(buffer);
return ret;
}
hw->parent = &usb_dev->dev;
hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_AFILT |
- IEEE802154_HW_PROMISCUOUS | IEEE802154_HW_CSMA_PARAMS |
- IEEE802154_HW_FRAME_RETRIES;
+ IEEE802154_HW_PROMISCUOUS | IEEE802154_HW_CSMA_PARAMS;
hw->phy->flags = WPAN_PHY_FLAG_TXPOWER | WPAN_PHY_FLAG_CCA_ED_LEVEL |
WPAN_PHY_FLAG_CCA_MODE;
atusb_get_and_show_build(atusb);
atusb_set_extended_addr(atusb);
+ if (atusb->fw_ver_maj >= 0 && atusb->fw_ver_min >= 3)
+ hw->flags |= IEEE802154_HW_FRAME_RETRIES;
+
ret = atusb_get_and_clear_error(atusb);
if (ret) {
dev_err(&atusb->usb_dev->dev,
return -EINVAL;
if (virtio_net_hdr_from_skb(skb, &vnet_hdr,
- macvtap_is_little_endian(q)))
+ macvtap_is_little_endian(q), true))
BUG();
if (copy_to_iter(&vnet_hdr, sizeof(vnet_hdr), iter) !=
config MESON_GXL_PHY
tristate "Amlogic Meson GXL Internal PHY"
+ depends on ARCH_MESON || COMPILE_TEST
---help---
Currently has a driver for the Amlogic Meson GXL Internal PHY
MODULE_AUTHOR("Maxime Bizon <mbizon@freebox.fr>");
MODULE_LICENSE("GPL");
+static int bcm63xx_config_intr(struct phy_device *phydev)
+{
+ int reg, err;
+
+ reg = phy_read(phydev, MII_BCM63XX_IR);
+ if (reg < 0)
+ return reg;
+
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+ reg &= ~MII_BCM63XX_IR_GMASK;
+ else
+ reg |= MII_BCM63XX_IR_GMASK;
+
+ err = phy_write(phydev, MII_BCM63XX_IR, reg);
+ return err;
+}
+
static int bcm63xx_config_init(struct phy_device *phydev)
{
int reg, err;
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
.ack_interrupt = bcm_phy_ack_intr,
- .config_intr = bcm_phy_config_intr,
+ .config_intr = bcm63xx_config_intr,
}, {
/* same phy as above, with just a different OUI */
.phy_id = 0x002bdc00,
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
.ack_interrupt = bcm_phy_ack_intr,
- .config_intr = bcm_phy_config_intr,
+ .config_intr = bcm63xx_config_intr,
} };
module_phy_driver(bcm63xx_driver);
#include <linux/phy.h>
#define TI_DP83848C_PHY_ID 0x20005ca0
+#define TI_DP83620_PHY_ID 0x20005ce0
#define NS_DP83848C_PHY_ID 0x20005c90
#define TLK10X_PHY_ID 0x2000a210
#define TI_DP83822_PHY_ID 0x2000a240
static struct mdio_device_id __maybe_unused dp83848_tbl[] = {
{ TI_DP83848C_PHY_ID, 0xfffffff0 },
{ NS_DP83848C_PHY_ID, 0xfffffff0 },
+ { TI_DP83620_PHY_ID, 0xfffffff0 },
{ TLK10X_PHY_ID, 0xfffffff0 },
{ TI_DP83822_PHY_ID, 0xfffffff0 },
{ }
static struct phy_driver dp83848_driver[] = {
DP83848_PHY_DRIVER(TI_DP83848C_PHY_ID, "TI DP83848C 10/100 Mbps PHY"),
DP83848_PHY_DRIVER(NS_DP83848C_PHY_ID, "NS DP83848C 10/100 Mbps PHY"),
+ DP83848_PHY_DRIVER(TI_DP83620_PHY_ID, "TI DP83620 10/100 Mbps PHY"),
DP83848_PHY_DRIVER(TLK10X_PHY_ID, "TI TLK10X 10/100 Mbps PHY"),
DP83848_PHY_DRIVER(TI_DP83822_PHY_ID, "TI DP83822 10/100 Mbps PHY"),
};
#define MII_DP83867_MICR 0x12
#define MII_DP83867_ISR 0x13
#define DP83867_CTRL 0x1f
+#define DP83867_CFG3 0x1e
/* Extended Registers */
#define DP83867_RGMIICTL 0x0032
micr_status |=
(MII_DP83867_MICR_AN_ERR_INT_EN |
MII_DP83867_MICR_SPEED_CHNG_INT_EN |
+ MII_DP83867_MICR_AUTONEG_COMP_INT_EN |
+ MII_DP83867_MICR_LINK_STS_CHNG_INT_EN |
MII_DP83867_MICR_DUP_MODE_CHNG_INT_EN |
MII_DP83867_MICR_SLEEP_MODE_CHNG_INT_EN);
ret = of_property_read_u32(of_node, "ti,rx-internal-delay",
&dp83867->rx_id_delay);
- if (ret)
+ if (ret &&
+ (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
+ phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID))
return ret;
ret = of_property_read_u32(of_node, "ti,tx-internal-delay",
&dp83867->tx_id_delay);
- if (ret)
+ if (ret &&
+ (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
+ phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID))
return ret;
return of_property_read_u32(of_node, "ti,fifo-depth",
}
}
+ /* Enable Interrupt output INT_OE in CFG3 register */
+ if (phy_interrupt_is_valid(phydev)) {
+ val = phy_read(phydev, DP83867_CFG3);
+ val |= BIT(7);
+ phy_write(phydev, DP83867_CFG3, val);
+ }
+
return 0;
}
int err;
/* Check the fiber mode first */
- if (phydev->supported & SUPPORTED_FIBRE) {
+ if (phydev->supported & SUPPORTED_FIBRE &&
+ phydev->interface != PHY_INTERFACE_MODE_SGMII) {
err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_FIBER);
if (err < 0)
goto error;
.ack_interrupt = &marvell_ack_interrupt,
.config_intr = &marvell_config_intr,
.did_interrupt = &m88e1121_did_interrupt,
+ .get_wol = &m88e1318_get_wol,
+ .set_wol = &m88e1318_set_wol,
.resume = &marvell_resume,
.suspend = &marvell_suspend,
.get_sset_count = marvell_get_sset_count,
.get_stats = kszphy_get_stats,
.suspend = genphy_suspend,
.resume = genphy_resume,
+}, {
+ .phy_id = PHY_ID_KSZ8795,
+ .phy_id_mask = MICREL_PHY_ID_MASK,
+ .name = "Micrel KSZ8795",
+ .features = PHY_BASIC_FEATURES,
+ .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
+ .config_init = kszphy_config_init,
+ .config_aneg = ksz8873mll_config_aneg,
+ .read_status = ksz8873mll_read_status,
+ .get_sset_count = kszphy_get_sset_count,
+ .get_strings = kszphy_get_strings,
+ .get_stats = kszphy_get_stats,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
} };
module_phy_driver(ksphy_driver);
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/phy.h>
+#include <linux/phy_led_triggers.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <linux/mdio.h>
* phy_trigger_machine - trigger the state machine to run
*
* @phydev: the phy_device struct
+ * @sync: indicate whether we should wait for the workqueue cancelation
*
* Description: There has been a change in state which requires that the
* state machine runs.
*/
-static void phy_trigger_machine(struct phy_device *phydev)
+static void phy_trigger_machine(struct phy_device *phydev, bool sync)
{
- cancel_delayed_work_sync(&phydev->state_queue);
+ if (sync)
+ cancel_delayed_work_sync(&phydev->state_queue);
+ else
+ cancel_delayed_work(&phydev->state_queue);
queue_delayed_work(system_power_efficient_wq, &phydev->state_queue, 0);
}
phydev->state = PHY_HALTED;
mutex_unlock(&phydev->lock);
- phy_trigger_machine(phydev);
+ phy_trigger_machine(phydev, false);
}
/**
}
/* reschedule state queue work to run as soon as possible */
- phy_trigger_machine(phydev);
+ phy_trigger_machine(phydev, true);
return;
ignore:
if (do_resume)
phy_resume(phydev);
- phy_trigger_machine(phydev);
+ phy_trigger_machine(phydev, true);
}
EXPORT_SYMBOL(phy_start);
if (old_link != phydev->link)
phydev->state = PHY_CHANGELINK;
}
+ /*
+ * Failsafe: check that nobody set phydev->link=0 between two
+ * poll cycles, otherwise we won't leave RUNNING state as long
+ * as link remains down.
+ */
+ if (!phydev->link && phydev->state == PHY_RUNNING) {
+ phydev->state = PHY_CHANGELINK;
+ phydev_err(phydev, "no link in PHY_RUNNING\n");
+ }
break;
case PHY_CHANGELINK:
err = phy_read_status(phydev);
*/
#include <linux/leds.h>
#include <linux/phy.h>
+#include <linux/phy_led_triggers.h>
#include <linux/netdevice.h>
static struct phy_led_trigger *phy_speed_to_led_trigger(struct phy_device *phy,
sizeof(struct phy_led_trigger) *
phy->phy_num_led_triggers,
GFP_KERNEL);
- if (!phy->phy_led_triggers)
- return -ENOMEM;
+ if (!phy->phy_led_triggers) {
+ err = -ENOMEM;
+ goto out_clear;
+ }
for (i = 0; i < phy->phy_num_led_triggers; i++) {
err = phy_led_trigger_register(phy, &phy->phy_led_triggers[i],
while (i--)
phy_led_trigger_unregister(&phy->phy_led_triggers[i]);
devm_kfree(&phy->mdio.dev, phy->phy_led_triggers);
+out_clear:
+ phy->phy_num_led_triggers = 0;
return err;
}
EXPORT_SYMBOL_GPL(phy_led_triggers_register);
return -EINVAL;
if (virtio_net_hdr_from_skb(skb, &gso,
- tun_is_little_endian(tun))) {
+ tun_is_little_endian(tun), true)) {
struct skb_shared_info *sinfo = skb_shinfo(skb);
pr_err("unexpected GSO type: "
"0x%x, gso_size %d, hdr_len %d\n",
#define SAMSUNG_VENDOR_ID 0x04e8
#define LENOVO_VENDOR_ID 0x17ef
#define NVIDIA_VENDOR_ID 0x0955
+#define HP_VENDOR_ID 0x03f0
static const struct usb_device_id products[] = {
/* BLACKLIST !!
.driver_info = 0,
},
+/* HP lt2523 (Novatel E371) - handled by qmi_wwan */
+{
+ USB_DEVICE_AND_INTERFACE_INFO(HP_VENDOR_ID, 0x421d, USB_CLASS_COMM,
+ USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
+ .driver_info = 0,
+},
+
/* AnyDATA ADU960S - handled by qmi_wwan */
{
USB_DEVICE_AND_INTERFACE_INFO(0x16d5, 0x650a, USB_CLASS_COMM,
USB_CDC_PROTO_NONE),
.driver_info = (unsigned long)&qmi_wwan_info,
},
+ { /* HP lt2523 (Novatel E371) */
+ USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0x421d,
+ USB_CLASS_COMM,
+ USB_CDC_SUBCLASS_ETHERNET,
+ USB_CDC_PROTO_NONE),
+ .driver_info = (unsigned long)&qmi_wwan_info,
+ },
{ /* HP lt4112 LTE/HSPA+ Gobi 4G Module (Huawei me906e) */
USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0x581d, USB_CLASS_VENDOR_SPEC, 1, 7),
.driver_info = (unsigned long)&qmi_wwan_info,
#define NETNEXT_VERSION "08"
/* Information for net */
-#define NET_VERSION "6"
+#define NET_VERSION "8"
#define DRIVER_VERSION "v1." NETNEXT_VERSION "." NET_VERSION
#define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>"
u8 checksum = CHECKSUM_NONE;
u32 opts2, opts3;
- if (tp->version == RTL_VER_01 || tp->version == RTL_VER_02)
+ if (!(tp->netdev->features & NETIF_F_RXCSUM))
goto return_result;
opts2 = le32_to_cpu(rx_desc->opts2);
napi_complete(napi);
if (!list_empty(&tp->rx_done))
napi_schedule(napi);
+ else if (!skb_queue_empty(&tp->tx_queue) &&
+ !list_empty(&tp->tx_free))
+ napi_schedule(napi);
}
return work_done;
if (!netif_carrier_ok(netdev)) {
tp->rtl_ops.enable(tp);
set_bit(RTL8152_SET_RX_MODE, &tp->flags);
+ netif_stop_queue(netdev);
napi_disable(&tp->napi);
netif_carrier_on(netdev);
rtl_start_rx(tp);
napi_enable(&tp->napi);
+ netif_wake_queue(netdev);
+ netif_info(tp, link, netdev, "carrier on\n");
}
} else {
if (netif_carrier_ok(netdev)) {
napi_disable(&tp->napi);
tp->rtl_ops.disable(tp);
napi_enable(&tp->napi);
+ netif_info(tp, link, netdev, "carrier off\n");
}
}
}
if (!netif_running(netdev))
return 0;
+ netif_stop_queue(netdev);
napi_disable(&tp->napi);
clear_bit(WORK_ENABLE, &tp->flags);
usb_kill_urb(tp->intr_urb);
cancel_delayed_work_sync(&tp->schedule);
if (netif_carrier_ok(netdev)) {
- netif_stop_queue(netdev);
mutex_lock(&tp->control);
tp->rtl_ops.disable(tp);
mutex_unlock(&tp->control);
if (netif_carrier_ok(netdev)) {
mutex_lock(&tp->control);
tp->rtl_ops.enable(tp);
+ rtl_start_rx(tp);
rtl8152_set_rx_mode(netdev);
mutex_unlock(&tp->control);
- netif_wake_queue(netdev);
}
napi_enable(&tp->napi);
+ netif_wake_queue(netdev);
+ usb_submit_urb(tp->intr_urb, GFP_KERNEL);
+
+ if (!list_empty(&tp->rx_done))
+ napi_schedule(&tp->napi);
return 0;
}
*/
if (!sw_linking && tp->rtl_ops.in_nway(tp))
return true;
+ else if (!skb_queue_empty(&tp->tx_queue))
+ return true;
else
return false;
}
-static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)
+static int rtl8152_rumtime_suspend(struct r8152 *tp)
{
- struct r8152 *tp = usb_get_intfdata(intf);
struct net_device *netdev = tp->netdev;
int ret = 0;
- mutex_lock(&tp->control);
+ set_bit(SELECTIVE_SUSPEND, &tp->flags);
+ smp_mb__after_atomic();
+
+ if (netif_running(netdev) && test_bit(WORK_ENABLE, &tp->flags)) {
+ u32 rcr = 0;
- if (PMSG_IS_AUTO(message)) {
- if (netif_running(netdev) && delay_autosuspend(tp)) {
+ if (delay_autosuspend(tp)) {
+ clear_bit(SELECTIVE_SUSPEND, &tp->flags);
+ smp_mb__after_atomic();
ret = -EBUSY;
goto out1;
}
- set_bit(SELECTIVE_SUSPEND, &tp->flags);
- } else {
- netif_device_detach(netdev);
+ if (netif_carrier_ok(netdev)) {
+ u32 ocp_data;
+
+ rcr = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
+ ocp_data = rcr & ~RCR_ACPT_ALL;
+ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
+ rxdy_gated_en(tp, true);
+ ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA,
+ PLA_OOB_CTRL);
+ if (!(ocp_data & RXFIFO_EMPTY)) {
+ rxdy_gated_en(tp, false);
+ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, rcr);
+ clear_bit(SELECTIVE_SUSPEND, &tp->flags);
+ smp_mb__after_atomic();
+ ret = -EBUSY;
+ goto out1;
+ }
+ }
+
+ clear_bit(WORK_ENABLE, &tp->flags);
+ usb_kill_urb(tp->intr_urb);
+
+ tp->rtl_ops.autosuspend_en(tp, true);
+
+ if (netif_carrier_ok(netdev)) {
+ napi_disable(&tp->napi);
+ rtl_stop_rx(tp);
+ rxdy_gated_en(tp, false);
+ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, rcr);
+ napi_enable(&tp->napi);
+ }
}
+out1:
+ return ret;
+}
+
+static int rtl8152_system_suspend(struct r8152 *tp)
+{
+ struct net_device *netdev = tp->netdev;
+ int ret = 0;
+
+ netif_device_detach(netdev);
+
if (netif_running(netdev) && test_bit(WORK_ENABLE, &tp->flags)) {
clear_bit(WORK_ENABLE, &tp->flags);
usb_kill_urb(tp->intr_urb);
napi_disable(&tp->napi);
- if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
- rtl_stop_rx(tp);
- tp->rtl_ops.autosuspend_en(tp, true);
- } else {
- cancel_delayed_work_sync(&tp->schedule);
- tp->rtl_ops.down(tp);
- }
+ cancel_delayed_work_sync(&tp->schedule);
+ tp->rtl_ops.down(tp);
napi_enable(&tp->napi);
}
-out1:
+
+ return ret;
+}
+
+static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct r8152 *tp = usb_get_intfdata(intf);
+ int ret;
+
+ mutex_lock(&tp->control);
+
+ if (PMSG_IS_AUTO(message))
+ ret = rtl8152_rumtime_suspend(tp);
+ else
+ ret = rtl8152_system_suspend(tp);
+
mutex_unlock(&tp->control);
return ret;
if (netif_running(tp->netdev) && tp->netdev->flags & IFF_UP) {
if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
tp->rtl_ops.autosuspend_en(tp, false);
- clear_bit(SELECTIVE_SUSPEND, &tp->flags);
napi_disable(&tp->napi);
set_bit(WORK_ENABLE, &tp->flags);
if (netif_carrier_ok(tp->netdev))
rtl_start_rx(tp);
napi_enable(&tp->napi);
+ clear_bit(SELECTIVE_SUSPEND, &tp->flags);
+ smp_mb__after_atomic();
+ if (!list_empty(&tp->rx_done))
+ napi_schedule(&tp->napi);
} else {
tp->rtl_ops.up(tp);
netif_carrier_off(tp->netdev);
NETIF_F_HIGHDMA | NETIF_F_FRAGLIST |
NETIF_F_IPV6_CSUM | NETIF_F_TSO6;
+ if (tp->version == RTL_VER_01) {
+ netdev->features &= ~NETIF_F_RXCSUM;
+ netdev->hw_features &= ~NETIF_F_RXCSUM;
+ }
+
netdev->ethtool_ops = &ops;
netif_set_gso_max_size(netdev, RTL_LIMITED_TSO_SIZE);
*/
DECLARE_EWMA(pkt_len, 1, 64)
+/* With mergeable buffers we align buffer address and use the low bits to
+ * encode its true size. Buffer size is up to 1 page so we need to align to
+ * square root of page size to ensure we reserve enough bits to encode the true
+ * size.
+ */
+#define MERGEABLE_BUFFER_MIN_ALIGN_SHIFT ((PAGE_SHIFT + 1) / 2)
+
/* Minimum alignment for mergeable packet buffers. */
-#define MERGEABLE_BUFFER_ALIGN max(L1_CACHE_BYTES, 256)
+#define MERGEABLE_BUFFER_ALIGN max(L1_CACHE_BYTES, \
+ 1 << MERGEABLE_BUFFER_MIN_ALIGN_SHIFT)
#define VIRTNET_DRIVER_VERSION "1.0.0"
hdr = skb_vnet_hdr(skb);
if (virtio_net_hdr_from_skb(skb, &hdr->hdr,
- virtio_is_little_endian(vi->vdev)))
+ virtio_is_little_endian(vi->vdev), false))
BUG();
if (vi->mergeable_rx_bufs)
u16 xdp_qp = 0, curr_qp;
int i, err;
+ if (prog && prog->xdp_adjust_head) {
+ netdev_warn(dev, "Does not support bpf_xdp_adjust_head()\n");
+ return -EOPNOTSUPP;
+ }
+
if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_TSO4) ||
virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_TSO6) ||
virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_ECN) ||
put_page(vi->rq[i].alloc_frag.page);
}
-static bool is_xdp_queue(struct virtnet_info *vi, int q)
+static bool is_xdp_raw_buffer_queue(struct virtnet_info *vi, int q)
{
+ /* For small receive mode always use kfree_skb variants */
+ if (!vi->mergeable_rx_bufs)
+ return false;
+
if (q < (vi->curr_queue_pairs - vi->xdp_queue_pairs))
return false;
else if (q < vi->curr_queue_pairs)
for (i = 0; i < vi->max_queue_pairs; i++) {
struct virtqueue *vq = vi->sq[i].vq;
while ((buf = virtqueue_detach_unused_buf(vq)) != NULL) {
- if (!is_xdp_queue(vi, i))
+ if (!is_xdp_raw_buffer_queue(vi, i))
dev_kfree_skb(buf);
else
put_page(virt_to_head_page(buf));
.flowi4_iif = LOOPBACK_IFINDEX,
.flowi4_tos = RT_TOS(ip4h->tos),
.flowi4_flags = FLOWI_FLAG_ANYSRC | FLOWI_FLAG_SKIP_NH_OIF,
+ .flowi4_proto = ip4h->protocol,
.daddr = ip4h->daddr,
+ .saddr = ip4h->saddr,
};
struct net *net = dev_net(vrf_dev);
struct rtable *rt;
return -EINVAL;
vrf->tb_id = nla_get_u32(data[IFLA_VRF_TABLE]);
+ if (vrf->tb_id == RT_TABLE_UNSPEC)
+ return -EINVAL;
dev->priv_flags |= IFF_L3MDEV_MASTER;
static struct rtable *vxlan_get_route(struct vxlan_dev *vxlan, struct net_device *dev,
struct vxlan_sock *sock4,
struct sk_buff *skb, int oif, u8 tos,
- __be32 daddr, __be32 *saddr,
+ __be32 daddr, __be32 *saddr, __be16 dport, __be16 sport,
struct dst_cache *dst_cache,
const struct ip_tunnel_info *info)
{
fl4.flowi4_proto = IPPROTO_UDP;
fl4.daddr = daddr;
fl4.saddr = *saddr;
+ fl4.fl4_dport = dport;
+ fl4.fl4_sport = sport;
rt = ip_route_output_key(vxlan->net, &fl4);
if (likely(!IS_ERR(rt))) {
__be32 label,
const struct in6_addr *daddr,
struct in6_addr *saddr,
+ __be16 dport, __be16 sport,
struct dst_cache *dst_cache,
const struct ip_tunnel_info *info)
{
fl6.flowlabel = ip6_make_flowinfo(RT_TOS(tos), label);
fl6.flowi6_mark = skb->mark;
fl6.flowi6_proto = IPPROTO_UDP;
+ fl6.fl6_dport = dport;
+ fl6.fl6_sport = sport;
err = ipv6_stub->ipv6_dst_lookup(vxlan->net,
sock6->sock->sk,
rdst ? rdst->remote_ifindex : 0, tos,
dst->sin.sin_addr.s_addr,
&src->sin.sin_addr.s_addr,
+ dst_port, src_port,
dst_cache, info);
if (IS_ERR(rt)) {
err = PTR_ERR(rt);
rdst ? rdst->remote_ifindex : 0, tos,
label, &dst->sin6.sin6_addr,
&src->sin6.sin6_addr,
+ dst_port, src_port,
dst_cache, info);
if (IS_ERR(ndst)) {
err = PTR_ERR(ndst);
= container_of(p, struct vxlan_fdb, hlist);
unsigned long timeout;
- if (f->state & NUD_PERMANENT)
+ if (f->state & (NUD_PERMANENT | NUD_NOARP))
continue;
timeout = f->used + vxlan->cfg.age_interval * HZ;
}
/* Purge the forwarding table */
-static void vxlan_flush(struct vxlan_dev *vxlan)
+static void vxlan_flush(struct vxlan_dev *vxlan, bool do_all)
{
unsigned int h;
hlist_for_each_safe(p, n, &vxlan->fdb_head[h]) {
struct vxlan_fdb *f
= container_of(p, struct vxlan_fdb, hlist);
+ if (!do_all && (f->state & (NUD_PERMANENT | NUD_NOARP)))
+ continue;
/* the all_zeros_mac entry is deleted at vxlan_uninit */
if (!is_zero_ether_addr(f->eth_addr))
vxlan_fdb_destroy(vxlan, f);
del_timer_sync(&vxlan->age_timer);
- vxlan_flush(vxlan);
+ vxlan_flush(vxlan, false);
vxlan_sock_release(vxlan);
return ret;
rt = vxlan_get_route(vxlan, dev, sock4, skb, 0, info->key.tos,
info->key.u.ipv4.dst,
- &info->key.u.ipv4.src, NULL, info);
+ &info->key.u.ipv4.src, dport, sport, NULL, info);
if (IS_ERR(rt))
return PTR_ERR(rt);
ip_rt_put(rt);
ndst = vxlan6_get_route(vxlan, dev, sock6, skb, 0, info->key.tos,
info->key.label, &info->key.u.ipv6.dst,
- &info->key.u.ipv6.src, NULL, info);
+ &info->key.u.ipv6.src, dport, sport, NULL, info);
if (IS_ERR(ndst))
return PTR_ERR(ndst);
dst_release(ndst);
memcpy(&vxlan->cfg, conf, sizeof(*conf));
if (!vxlan->cfg.dst_port) {
if (conf->flags & VXLAN_F_GPE)
- vxlan->cfg.dst_port = 4790; /* IANA assigned VXLAN-GPE port */
+ vxlan->cfg.dst_port = htons(4790); /* IANA VXLAN-GPE port */
else
vxlan->cfg.dst_port = default_port;
}
struct vxlan_dev *vxlan = netdev_priv(dev);
struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
+ vxlan_flush(vxlan, true);
+
spin_lock(&vn->sock_lock);
if (!hlist_unhashed(&vxlan->hlist))
hlist_del_rcu(&vxlan->hlist);
#define IWL8000_FW_PRE "iwlwifi-8000C-"
#define IWL8000_MODULE_FIRMWARE(api) \
- IWL8000_FW_PRE "-" __stringify(api) ".ucode"
+ IWL8000_FW_PRE __stringify(api) ".ucode"
#define IWL8265_FW_PRE "iwlwifi-8265-"
#define IWL8265_MODULE_FIRMWARE(api) \
.frame_limit = IWL_FRAME_LIMIT,
};
- /* Make sure reserved queue is still marked as such (or allocated) */
- mvm->queue_info[mvm_sta->reserved_queue].status =
- IWL_MVM_QUEUE_RESERVED;
+ /* Make sure reserved queue is still marked as such (if allocated) */
+ if (mvm_sta->reserved_queue != IEEE80211_INVAL_HW_QUEUE)
+ mvm->queue_info[mvm_sta->reserved_queue].status =
+ IWL_MVM_QUEUE_RESERVED;
for (i = 0; i <= IWL_MAX_TID_COUNT; i++) {
struct iwl_mvm_tid_data *tid_data = &mvm_sta->tid_data[i];
return;
IWL_DEBUG_TEMP(mvm, "Thermal zone device unregister\n");
- thermal_zone_device_unregister(mvm->tz_device.tzone);
- mvm->tz_device.tzone = NULL;
+ if (mvm->tz_device.tzone) {
+ thermal_zone_device_unregister(mvm->tz_device.tzone);
+ mvm->tz_device.tzone = NULL;
+ }
}
static void iwl_mvm_cooling_device_unregister(struct iwl_mvm *mvm)
return;
IWL_DEBUG_TEMP(mvm, "Cooling device unregister\n");
- thermal_cooling_device_unregister(mvm->cooling_dev.cdev);
- mvm->cooling_dev.cdev = NULL;
+ if (mvm->cooling_dev.cdev) {
+ thermal_cooling_device_unregister(mvm->cooling_dev.cdev);
+ mvm->cooling_dev.cdev = NULL;
+ }
}
#endif /* CONFIG_THERMAL */
/********************************************************************/
int orinoco_mic_init(struct orinoco_private *priv)
{
- priv->tx_tfm_mic = crypto_alloc_ahash("michael_mic", 0,
+ priv->tx_tfm_mic = crypto_alloc_shash("michael_mic", 0,
CRYPTO_ALG_ASYNC);
if (IS_ERR(priv->tx_tfm_mic)) {
printk(KERN_DEBUG "orinoco_mic_init: could not allocate "
return -ENOMEM;
}
- priv->rx_tfm_mic = crypto_alloc_ahash("michael_mic", 0,
+ priv->rx_tfm_mic = crypto_alloc_shash("michael_mic", 0,
CRYPTO_ALG_ASYNC);
if (IS_ERR(priv->rx_tfm_mic)) {
printk(KERN_DEBUG "orinoco_mic_init: could not allocate "
void orinoco_mic_free(struct orinoco_private *priv)
{
if (priv->tx_tfm_mic)
- crypto_free_ahash(priv->tx_tfm_mic);
+ crypto_free_shash(priv->tx_tfm_mic);
if (priv->rx_tfm_mic)
- crypto_free_ahash(priv->rx_tfm_mic);
+ crypto_free_shash(priv->rx_tfm_mic);
}
-int orinoco_mic(struct crypto_ahash *tfm_michael, u8 *key,
+int orinoco_mic(struct crypto_shash *tfm_michael, u8 *key,
u8 *da, u8 *sa, u8 priority,
u8 *data, size_t data_len, u8 *mic)
{
- AHASH_REQUEST_ON_STACK(req, tfm_michael);
- struct scatterlist sg[2];
+ SHASH_DESC_ON_STACK(desc, tfm_michael);
u8 hdr[ETH_HLEN + 2]; /* size of header + padding */
int err;
hdr[ETH_ALEN * 2 + 2] = 0;
hdr[ETH_ALEN * 2 + 3] = 0;
- /* Use scatter gather to MIC header and data in one go */
- sg_init_table(sg, 2);
- sg_set_buf(&sg[0], hdr, sizeof(hdr));
- sg_set_buf(&sg[1], data, data_len);
+ desc->tfm = tfm_michael;
+ desc->flags = 0;
- if (crypto_ahash_setkey(tfm_michael, key, MIC_KEYLEN))
- return -1;
+ err = crypto_shash_setkey(tfm_michael, key, MIC_KEYLEN);
+ if (err)
+ return err;
+
+ err = crypto_shash_init(desc);
+ if (err)
+ return err;
+
+ err = crypto_shash_update(desc, hdr, sizeof(hdr));
+ if (err)
+ return err;
+
+ err = crypto_shash_update(desc, data, data_len);
+ if (err)
+ return err;
+
+ err = crypto_shash_final(desc, mic);
+ shash_desc_zero(desc);
- ahash_request_set_tfm(req, tfm_michael);
- ahash_request_set_callback(req, 0, NULL, NULL);
- ahash_request_set_crypt(req, sg, mic, data_len + sizeof(hdr));
- err = crypto_ahash_digest(req);
- ahash_request_zero(req);
return err;
}
#define _ORINOCO_MIC_H_
#include <linux/types.h>
+#include <crypto/hash.h>
#define MICHAEL_MIC_LEN 8
int orinoco_mic_init(struct orinoco_private *priv);
void orinoco_mic_free(struct orinoco_private *priv);
-int orinoco_mic(struct crypto_ahash *tfm_michael, u8 *key,
+int orinoco_mic(struct crypto_shash *tfm_michael, u8 *key,
u8 *da, u8 *sa, u8 priority,
u8 *data, size_t data_len, u8 *mic);
u8 *wpa_ie;
int wpa_ie_len;
- struct crypto_ahash *rx_tfm_mic;
- struct crypto_ahash *tx_tfm_mic;
+ struct crypto_shash *rx_tfm_mic;
+ struct crypto_shash *tx_tfm_mic;
unsigned int wpa_enabled:1;
unsigned int tkip_cm_active:1;
return -ENOMEM;
}
rtlpriv = hw->priv;
+ rtlpriv->hw = hw;
rtlpriv->usb_data = kzalloc(RTL_USB_MAX_RX_COUNT * sizeof(u32),
GFP_KERNEL);
if (!rtlpriv->usb_data)
{
struct xenvif *vif = netdev_priv(dev);
struct xenvif_queue *queue = NULL;
- unsigned int num_queues = vif->num_queues;
unsigned long rx_bytes = 0;
unsigned long rx_packets = 0;
unsigned long tx_bytes = 0;
unsigned long tx_packets = 0;
unsigned int index;
+ spin_lock(&vif->lock);
if (vif->queues == NULL)
goto out;
/* Aggregate tx and rx stats from each queue */
- for (index = 0; index < num_queues; ++index) {
+ for (index = 0; index < vif->num_queues; ++index) {
queue = &vif->queues[index];
rx_bytes += queue->stats.rx_bytes;
rx_packets += queue->stats.rx_packets;
}
out:
+ spin_unlock(&vif->lock);
+
vif->dev->stats.rx_bytes = rx_bytes;
vif->dev->stats.rx_packets = rx_packets;
vif->dev->stats.tx_bytes = tx_bytes;
static void backend_disconnect(struct backend_info *be)
{
if (be->vif) {
+ unsigned int queue_index;
+
xen_unregister_watchers(be->vif);
#ifdef CONFIG_DEBUG_FS
xenvif_debugfs_delif(be->vif);
#endif /* CONFIG_DEBUG_FS */
xenvif_disconnect_data(be->vif);
+ for (queue_index = 0; queue_index < be->vif->num_queues; ++queue_index)
+ xenvif_deinit_queue(&be->vif->queues[queue_index]);
+
+ spin_lock(&be->vif->lock);
+ vfree(be->vif->queues);
+ be->vif->num_queues = 0;
+ be->vif->queues = NULL;
+ spin_unlock(&be->vif->lock);
+
xenvif_disconnect_ctrl(be->vif);
}
}
err:
if (be->vif->num_queues > 0)
xenvif_disconnect_data(be->vif); /* Clean up existing queues */
+ for (queue_index = 0; queue_index < be->vif->num_queues; ++queue_index)
+ xenvif_deinit_queue(&be->vif->queues[queue_index]);
vfree(be->vif->queues);
be->vif->queues = NULL;
be->vif->num_queues = 0;
queue->rx.req_prod_pvt = req_prod;
/* Not enough requests? Try again later. */
- if (req_prod - queue->rx.rsp_cons < NET_RX_SLOTS_MIN) {
+ if (req_prod - queue->rx.sring->req_prod < NET_RX_SLOTS_MIN) {
mod_timer(&queue->rx_refill_timer, jiffies + (HZ/10));
return;
}
{
resource_size_t allocated = 0, available = 0;
struct nd_region *nd_region = to_nd_region(dev->parent);
+ struct nd_namespace_common *ndns = to_ndns(dev);
struct nd_mapping *nd_mapping;
struct nvdimm_drvdata *ndd;
struct nd_label_id label_id;
u8 *uuid = NULL;
int rc, i;
- if (dev->driver || to_ndns(dev)->claim)
+ if (dev->driver || ndns->claim)
return -EBUSY;
if (is_namespace_pmem(dev)) {
nd_namespace_pmem_set_resource(nd_region, nspm,
val * nd_region->ndr_mappings);
- } else if (is_namespace_blk(dev)) {
- struct nd_namespace_blk *nsblk = to_nd_namespace_blk(dev);
-
- /*
- * Try to delete the namespace if we deleted all of its
- * allocation, this is not the seed device for the
- * region, and it is not actively claimed by a btt
- * instance.
- */
- if (val == 0 && nd_region->ns_seed != dev
- && !nsblk->common.claim)
- nd_device_unregister(dev, ND_ASYNC);
}
+ /*
+ * Try to delete the namespace if we deleted all of its
+ * allocation, this is not the seed device for the region, and
+ * it is not actively claimed by a btt instance.
+ */
+ if (val == 0 && nd_region->ns_seed != dev && !ndns->claim)
+ nd_device_unregister(dev, ND_ASYNC);
+
return rc;
}
rc = memcpy_from_pmem(mem + off, pmem_addr, len);
kunmap_atomic(mem);
- return rc;
+ if (rc)
+ return -EIO;
+ return 0;
}
static int pmem_do_bvec(struct pmem_device *pmem, struct page *page,
if (ret)
return ret;
- /* Checking for ctrl->tagset is a trick to avoid sleeping on module
- * load, since we only need the quirk on reset_controller. Notice
- * that the HGST device needs this delay only in firmware activation
- * procedure; unfortunately we have no (easy) way to verify this.
- */
- if ((ctrl->quirks & NVME_QUIRK_DELAY_BEFORE_CHK_RDY) && ctrl->tagset)
+ if (ctrl->quirks & NVME_QUIRK_DELAY_BEFORE_CHK_RDY)
msleep(NVME_QUIRK_DELAY_AMOUNT);
return nvme_wait_ready(ctrl, cap, false);
struct nvme_fc_fcp_op *op)
{
struct nvmefc_fcp_req *freq = &op->fcp_req;
- u32 map_len = nvme_map_len(rq);
enum dma_data_direction dir;
int ret;
freq->sg_cnt = 0;
- if (!map_len)
+ if (!blk_rq_payload_bytes(rq))
return 0;
freq->sg_table.sgl = freq->first_sgl;
- ret = sg_alloc_table_chained(&freq->sg_table, rq->nr_phys_segments,
- freq->sg_table.sgl);
+ ret = sg_alloc_table_chained(&freq->sg_table,
+ blk_rq_nr_phys_segments(rq), freq->sg_table.sgl);
if (ret)
return -ENOMEM;
op->nents = blk_rq_map_sg(rq->q, rq, freq->sg_table.sgl);
- WARN_ON(op->nents > rq->nr_phys_segments);
+ WARN_ON(op->nents > blk_rq_nr_phys_segments(rq));
dir = (rq_data_dir(rq) == WRITE) ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
freq->sg_cnt = fc_dma_map_sg(ctrl->lport->dev, freq->sg_table.sgl,
op->nents, dir);
if (ret)
return ret;
- data_len = nvme_map_len(rq);
+ data_len = blk_rq_payload_bytes(rq);
if (data_len)
io_dir = ((rq_data_dir(rq) == WRITE) ?
NVMEFC_FCP_WRITE : NVMEFC_FCP_READ);
return (sector >> (ns->lba_shift - 9));
}
-static inline unsigned nvme_map_len(struct request *rq)
-{
- if (req_op(rq) == REQ_OP_DISCARD)
- return sizeof(struct nvme_dsm_range);
- else
- return blk_rq_bytes(rq);
-}
-
static inline void nvme_cleanup_cmd(struct request *req)
{
if (req->rq_flags & RQF_SPECIAL_PAYLOAD) {
return (__le64 **)(iod->sg + blk_rq_nr_phys_segments(req));
}
-static int nvme_init_iod(struct request *rq, unsigned size,
- struct nvme_dev *dev)
+static int nvme_init_iod(struct request *rq, struct nvme_dev *dev)
{
struct nvme_iod *iod = blk_mq_rq_to_pdu(rq);
int nseg = blk_rq_nr_phys_segments(rq);
+ unsigned int size = blk_rq_payload_bytes(rq);
if (nseg > NVME_INT_PAGES || size > NVME_INT_BYTES(dev)) {
iod->sg = kmalloc(nvme_iod_alloc_size(dev, size, nseg), GFP_ATOMIC);
}
#endif
-static bool nvme_setup_prps(struct nvme_dev *dev, struct request *req,
- int total_len)
+static bool nvme_setup_prps(struct nvme_dev *dev, struct request *req)
{
struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
struct dma_pool *pool;
- int length = total_len;
+ int length = blk_rq_payload_bytes(req);
struct scatterlist *sg = iod->sg;
int dma_len = sg_dma_len(sg);
u64 dma_addr = sg_dma_address(sg);
}
static int nvme_map_data(struct nvme_dev *dev, struct request *req,
- unsigned size, struct nvme_command *cmnd)
+ struct nvme_command *cmnd)
{
struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
struct request_queue *q = req->q;
DMA_ATTR_NO_WARN))
goto out;
- if (!nvme_setup_prps(dev, req, size))
+ if (!nvme_setup_prps(dev, req))
goto out_unmap;
ret = BLK_MQ_RQ_QUEUE_ERROR;
struct nvme_dev *dev = nvmeq->dev;
struct request *req = bd->rq;
struct nvme_command cmnd;
- unsigned map_len;
int ret = BLK_MQ_RQ_QUEUE_OK;
/*
if (ret != BLK_MQ_RQ_QUEUE_OK)
return ret;
- map_len = nvme_map_len(req);
- ret = nvme_init_iod(req, map_len, dev);
+ ret = nvme_init_iod(req, dev);
if (ret != BLK_MQ_RQ_QUEUE_OK)
goto out_free_cmd;
if (blk_rq_nr_phys_segments(req))
- ret = nvme_map_data(dev, req, map_len, &cmnd);
+ ret = nvme_map_data(dev, req, &cmnd);
if (ret != BLK_MQ_RQ_QUEUE_OK)
goto out_cleanup_iod;
}
static int nvme_rdma_map_data(struct nvme_rdma_queue *queue,
- struct request *rq, unsigned int map_len,
- struct nvme_command *c)
+ struct request *rq, struct nvme_command *c)
{
struct nvme_rdma_request *req = blk_mq_rq_to_pdu(rq);
struct nvme_rdma_device *dev = queue->device;
}
if (count == 1) {
- if (rq_data_dir(rq) == WRITE &&
- map_len <= nvme_rdma_inline_data_size(queue) &&
- nvme_rdma_queue_idx(queue))
+ if (rq_data_dir(rq) == WRITE && nvme_rdma_queue_idx(queue) &&
+ blk_rq_payload_bytes(rq) <=
+ nvme_rdma_inline_data_size(queue))
return nvme_rdma_map_sg_inline(queue, req, c);
if (dev->pd->flags & IB_PD_UNSAFE_GLOBAL_RKEY)
struct request *rq)
{
if (unlikely(!test_bit(NVME_RDMA_Q_LIVE, &queue->flags))) {
- struct nvme_command *cmd = (struct nvme_command *)rq->cmd;
+ struct nvme_command *cmd = nvme_req(rq)->cmd;
if (rq->cmd_type != REQ_TYPE_DRV_PRIV ||
cmd->common.opcode != nvme_fabrics_command ||
struct nvme_command *c = sqe->data;
bool flush = false;
struct ib_device *dev;
- unsigned int map_len;
int ret;
WARN_ON_ONCE(rq->tag < 0);
blk_mq_start_request(rq);
- map_len = nvme_map_len(rq);
- ret = nvme_rdma_map_data(queue, rq, map_len, c);
+ ret = nvme_rdma_map_data(queue, rq, c);
if (ret < 0) {
dev_err(queue->ctrl->ctrl.device,
"Failed to map data (%d)\n", ret);
{
struct nvmet_subsys *subsys = to_subsys(item);
+ nvmet_subsys_del_ctrls(subsys);
nvmet_subsys_put(subsys);
}
pr_err("ctrl %d keep-alive timer (%d seconds) expired!\n",
ctrl->cntlid, ctrl->kato);
- ctrl->ops->delete_ctrl(ctrl);
+ nvmet_ctrl_fatal_error(ctrl);
}
static void nvmet_start_keep_alive_timer(struct nvmet_ctrl *ctrl)
list_del(&ctrl->subsys_entry);
mutex_unlock(&subsys->lock);
+ flush_work(&ctrl->async_event_work);
+ cancel_work_sync(&ctrl->fatal_err_work);
+
ida_simple_remove(&subsys->cntlid_ida, ctrl->cntlid);
nvmet_subsys_put(subsys);
kfree(subsys);
}
+void nvmet_subsys_del_ctrls(struct nvmet_subsys *subsys)
+{
+ struct nvmet_ctrl *ctrl;
+
+ mutex_lock(&subsys->lock);
+ list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry)
+ ctrl->ops->delete_ctrl(ctrl);
+ mutex_unlock(&subsys->lock);
+}
+
void nvmet_subsys_put(struct nvmet_subsys *subsys)
{
kref_put(&subsys->ref, nvmet_subsys_free);
(struct fcnvme_ls_disconnect_rqst *)iod->rqstbuf;
struct fcnvme_ls_disconnect_acc *acc =
(struct fcnvme_ls_disconnect_acc *)iod->rspbuf;
- struct nvmet_fc_tgt_queue *queue;
+ struct nvmet_fc_tgt_queue *queue = NULL;
struct nvmet_fc_tgt_assoc *assoc;
int ret = 0;
bool del_assoc = false;
assoc = nvmet_fc_find_target_assoc(tgtport,
be64_to_cpu(rqst->associd.association_id));
iod->assoc = assoc;
- if (!assoc)
+ if (assoc) {
+ if (rqst->discon_cmd.scope ==
+ FCNVME_DISCONN_CONNECTION) {
+ queue = nvmet_fc_find_target_queue(tgtport,
+ be64_to_cpu(
+ rqst->discon_cmd.id));
+ if (!queue) {
+ nvmet_fc_tgt_a_put(assoc);
+ ret = VERR_NO_CONN;
+ }
+ }
+ } else
ret = VERR_NO_ASSOC;
}
FCNVME_LS_DISCONNECT);
- if (rqst->discon_cmd.scope == FCNVME_DISCONN_CONNECTION) {
- queue = nvmet_fc_find_target_queue(tgtport,
- be64_to_cpu(rqst->discon_cmd.id));
- if (queue) {
- int qid = queue->qid;
+ /* are we to delete a Connection ID (queue) */
+ if (queue) {
+ int qid = queue->qid;
- nvmet_fc_delete_target_queue(queue);
+ nvmet_fc_delete_target_queue(queue);
- /* release the get taken by find_target_queue */
- nvmet_fc_tgt_q_put(queue);
+ /* release the get taken by find_target_queue */
+ nvmet_fc_tgt_q_put(queue);
- /* tear association down if io queue terminated */
- if (!qid)
- del_assoc = true;
- }
+ /* tear association down if io queue terminated */
+ if (!qid)
+ del_assoc = true;
}
/* release get taken in nvmet_fc_find_target_assoc */
struct nvmet_subsys *nvmet_subsys_alloc(const char *subsysnqn,
enum nvme_subsys_type type);
void nvmet_subsys_put(struct nvmet_subsys *subsys);
+void nvmet_subsys_del_ctrls(struct nvmet_subsys *subsys);
struct nvmet_ns *nvmet_find_namespace(struct nvmet_ctrl *ctrl, __le32 nsid);
void nvmet_put_namespace(struct nvmet_ns *ns);
{
struct ib_recv_wr *bad_wr;
+ ib_dma_sync_single_for_device(ndev->device,
+ cmd->sge[0].addr, cmd->sge[0].length,
+ DMA_FROM_DEVICE);
+
if (ndev->srq)
return ib_post_srq_recv(ndev->srq, &cmd->wr, &bad_wr);
return ib_post_recv(cmd->queue->cm_id->qp, &cmd->wr, &bad_wr);
first_wr = &rsp->send_wr;
nvmet_rdma_post_recv(rsp->queue->dev, rsp->cmd);
+
+ ib_dma_sync_single_for_device(rsp->queue->dev->device,
+ rsp->send_sge.addr, rsp->send_sge.length,
+ DMA_TO_DEVICE);
+
if (ib_post_send(cm_id->qp, first_wr, &bad_wr)) {
pr_err("sending cmd response failed\n");
nvmet_rdma_release_rsp(rsp);
cmd->n_rdma = 0;
cmd->req.port = queue->port;
+
+ ib_dma_sync_single_for_cpu(queue->dev->device,
+ cmd->cmd->sge[0].addr, cmd->cmd->sge[0].length,
+ DMA_FROM_DEVICE);
+ ib_dma_sync_single_for_cpu(queue->dev->device,
+ cmd->send_sge.addr, cmd->send_sge.length,
+ DMA_TO_DEVICE);
+
if (!nvmet_req_init(&cmd->req, &queue->nvme_cq,
&queue->nvme_sq, &nvmet_rdma_ops))
return;
p->irq = PARPORT_IRQ_NONE;
}
if (p->irq != PARPORT_IRQ_NONE) {
- printk(", irq %d", p->irq);
+ pr_cont(", irq %d", p->irq);
if (p->dma == PARPORT_DMA_AUTO) {
p->dma = PARPORT_DMA_NONE;
is mandatory (see above) */
p->dma = PARPORT_DMA_NONE;
- printk(" [");
-#define printmode(x) {if(p->modes&PARPORT_MODE_##x){printk("%s%s",f?",":"",#x);f++;}}
+ pr_cont(" [");
+#define printmode(x) {if(p->modes&PARPORT_MODE_##x){pr_cont("%s%s",f?",":"",#x);f++;}}
{
int f = 0;
printmode(PCSPP);
// printmode(DMA);
}
#undef printmode
- printk("]\n");
+ pr_cont("]\n");
if (p->irq != PARPORT_IRQ_NONE) {
if (request_irq (p->irq, parport_irq_handler,
rc = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "pci/xgene:online",
xgene_msi_hwirq_alloc, NULL);
- if (rc)
+ if (rc < 0)
goto err_cpuhp;
pci_xgene_online = rc;
rc = cpuhp_setup_state(CPUHP_PCI_XGENE_DEAD, "pci/xgene:dead", NULL,
{
u32 val;
- /* get iATU unroll support */
- pp->iatu_unroll_enabled = dw_pcie_iatu_unroll_enabled(pp);
- dev_dbg(pp->dev, "iATU unroll: %s\n",
- pp->iatu_unroll_enabled ? "enabled" : "disabled");
-
/* set the number of lanes */
val = dw_pcie_readl_rc(pp, PCIE_PORT_LINK_CONTROL);
val &= ~PORT_LINK_MODE_MASK;
* we should not program the ATU here.
*/
if (!pp->ops->rd_other_conf) {
+ /* get iATU unroll support */
+ pp->iatu_unroll_enabled = dw_pcie_iatu_unroll_enabled(pp);
+ dev_dbg(pp->dev, "iATU unroll: %s\n",
+ pp->iatu_unroll_enabled ? "enabled" : "disabled");
+
dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0,
PCIE_ATU_TYPE_MEM, pp->mem_base,
pp->mem_bus_addr, pp->mem_size);
link = kzalloc(sizeof(*link), GFP_KERNEL);
if (!link)
return NULL;
+
INIT_LIST_HEAD(&link->sibling);
INIT_LIST_HEAD(&link->children);
INIT_LIST_HEAD(&link->link);
link->pdev = pdev;
- if (pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT) {
+
+ /*
+ * Root Ports and PCI/PCI-X to PCIe Bridges are roots of PCIe
+ * hierarchies.
+ */
+ if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT ||
+ pci_pcie_type(pdev) == PCI_EXP_TYPE_PCIE_BRIDGE) {
+ link->root = link;
+ } else {
struct pcie_link_state *parent;
+
parent = pdev->bus->parent->self->link_state;
if (!parent) {
kfree(link);
return NULL;
}
+
link->parent = parent;
+ link->root = link->parent->root;
list_add(&link->link, &parent->children);
}
- /* Setup a pointer to the root port link */
- if (!link->parent)
- link->root = link;
- else
- link->root = link->parent->root;
list_add(&link->sibling, &link_list);
pdev->link_state = link;
pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
if (!pos)
return;
+
pdev->pcie_cap = pos;
pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, ®16);
pdev->pcie_flags_reg = reg16;
pdev->pcie_mpss = reg16 & PCI_EXP_DEVCAP_PAYLOAD;
/*
- * A Root Port is always the upstream end of a Link. No PCIe
- * component has two Links. Two Links are connected by a Switch
- * that has a Port on each Link and internal logic to connect the
- * two Ports.
+ * A Root Port or a PCI-to-PCIe bridge is always the upstream end
+ * of a Link. No PCIe component has two Links. Two Links are
+ * connected by a Switch that has a Port on each Link and internal
+ * logic to connect the two Ports.
*/
type = pci_pcie_type(pdev);
- if (type == PCI_EXP_TYPE_ROOT_PORT)
+ if (type == PCI_EXP_TYPE_ROOT_PORT ||
+ type == PCI_EXP_TYPE_PCIE_BRIDGE)
pdev->has_secondary_link = 1;
else if (type == PCI_EXP_TYPE_UPSTREAM ||
type == PCI_EXP_TYPE_DOWNSTREAM) {
BERLIN_PINCTRL_GROUP("SCRD0_CRD_PRES", 0xc, 0x3, 0x15,
BERLIN_PINCTRL_FUNCTION(0x0, "gpio"), /* GPIO20 */
BERLIN_PINCTRL_FUNCTION(0x1, "scrd0"), /* crd pres */
- BERLIN_PINCTRL_FUNCTION(0x1, "sd1a")), /* DAT3 */
+ BERLIN_PINCTRL_FUNCTION(0x3, "sd1a")), /* DAT3 */
BERLIN_PINCTRL_GROUP("SPI1_SS0n", 0xc, 0x3, 0x18,
BERLIN_PINCTRL_FUNCTION(0x0, "spi1"), /* SS0n */
BERLIN_PINCTRL_FUNCTION(0x1, "gpio"), /* GPIO37 */
int reg)
{
struct byt_community *comm = byt_get_community(vg, offset);
- u32 reg_offset = 0;
+ u32 reg_offset;
if (!comm)
return NULL;
offset -= comm->pin_base;
- if (reg == BYT_INT_STAT_REG)
+ switch (reg) {
+ case BYT_INT_STAT_REG:
reg_offset = (offset / 32) * 4;
- else
+ break;
+ case BYT_DEBOUNCE_REG:
+ reg_offset = 0;
+ break;
+ default:
reg_offset = comm->pad_map[offset] * 16;
+ break;
+ }
return comm->reg_base + reg_offset + reg;
}
enum pin_config_param param = pinconf_to_config_param(*config);
void __iomem *conf_reg = byt_gpio_reg(vg, offset, BYT_CONF0_REG);
void __iomem *val_reg = byt_gpio_reg(vg, offset, BYT_VAL_REG);
+ void __iomem *db_reg = byt_gpio_reg(vg, offset, BYT_DEBOUNCE_REG);
unsigned long flags;
u32 conf, pull, val, debounce;
u16 arg = 0;
return -EINVAL;
raw_spin_lock_irqsave(&vg->lock, flags);
- debounce = readl(byt_gpio_reg(vg, offset, BYT_DEBOUNCE_REG));
+ debounce = readl(db_reg);
raw_spin_unlock_irqrestore(&vg->lock, flags);
switch (debounce & BYT_DEBOUNCE_PULSE_MASK) {
unsigned int param, arg;
void __iomem *conf_reg = byt_gpio_reg(vg, offset, BYT_CONF0_REG);
void __iomem *val_reg = byt_gpio_reg(vg, offset, BYT_VAL_REG);
+ void __iomem *db_reg = byt_gpio_reg(vg, offset, BYT_DEBOUNCE_REG);
unsigned long flags;
u32 conf, val, debounce;
int i, ret = 0;
break;
case PIN_CONFIG_INPUT_DEBOUNCE:
- debounce = readl(byt_gpio_reg(vg, offset,
- BYT_DEBOUNCE_REG));
- conf &= ~BYT_DEBOUNCE_PULSE_MASK;
+ debounce = readl(db_reg);
+ debounce &= ~BYT_DEBOUNCE_PULSE_MASK;
+
+ if (arg)
+ conf |= BYT_DEBOUNCE_EN;
+ else
+ conf &= ~BYT_DEBOUNCE_EN;
switch (arg) {
case 375:
- conf |= BYT_DEBOUNCE_PULSE_375US;
+ debounce |= BYT_DEBOUNCE_PULSE_375US;
break;
case 750:
- conf |= BYT_DEBOUNCE_PULSE_750US;
+ debounce |= BYT_DEBOUNCE_PULSE_750US;
break;
case 1500:
- conf |= BYT_DEBOUNCE_PULSE_1500US;
+ debounce |= BYT_DEBOUNCE_PULSE_1500US;
break;
case 3000:
- conf |= BYT_DEBOUNCE_PULSE_3MS;
+ debounce |= BYT_DEBOUNCE_PULSE_3MS;
break;
case 6000:
- conf |= BYT_DEBOUNCE_PULSE_6MS;
+ debounce |= BYT_DEBOUNCE_PULSE_6MS;
break;
case 12000:
- conf |= BYT_DEBOUNCE_PULSE_12MS;
+ debounce |= BYT_DEBOUNCE_PULSE_12MS;
break;
case 24000:
- conf |= BYT_DEBOUNCE_PULSE_24MS;
+ debounce |= BYT_DEBOUNCE_PULSE_24MS;
break;
default:
- ret = -EINVAL;
+ if (arg)
+ ret = -EINVAL;
+ break;
}
+ if (!ret)
+ writel(debounce, db_reg);
break;
default:
ret = -ENOTSUPP;
continue;
}
+ raw_spin_lock(&vg->lock);
pending = readl(reg);
+ raw_spin_unlock(&vg->lock);
for_each_set_bit(pin, &pending, 32) {
virq = irq_find_mapping(vg->chip.irqdomain, base + pin);
generic_handle_irq(virq);
static void byt_gpio_irq_init_hw(struct byt_gpio *vg)
{
+ struct gpio_chip *gc = &vg->chip;
+ struct device *dev = &vg->pdev->dev;
void __iomem *reg;
u32 base, value;
int i;
}
value = readl(reg);
- if ((value & BYT_PIN_MUX) == byt_get_gpio_mux(vg, i) &&
- !(value & BYT_DIRECT_IRQ_EN)) {
+ if (value & BYT_DIRECT_IRQ_EN) {
+ clear_bit(i, gc->irq_valid_mask);
+ dev_dbg(dev, "excluding GPIO %d from IRQ domain\n", i);
+ } else if ((value & BYT_PIN_MUX) == byt_get_gpio_mux(vg, i)) {
byt_gpio_clear_triggering(vg, i);
- dev_dbg(&vg->pdev->dev, "disabling GPIO %d\n", i);
+ dev_dbg(dev, "disabling GPIO %d\n", i);
}
}
gc->can_sleep = false;
gc->parent = &vg->pdev->dev;
gc->ngpio = vg->soc_data->npins;
+ gc->irq_need_valid_mask = true;
#ifdef CONFIG_PM_SLEEP
vg->saved_context = devm_kcalloc(&vg->pdev->dev, gc->ngpio,
#define BXT_PAD_OWN 0x020
#define BXT_HOSTSW_OWN 0x080
-#define BXT_PADCFGLOCK 0x090
+#define BXT_PADCFGLOCK 0x060
#define BXT_GPI_IE 0x110
#define BXT_COMMUNITY(s, e) \
return 0;
}
+static void __intel_gpio_set_direction(void __iomem *padcfg0, bool input)
+{
+ u32 value;
+
+ value = readl(padcfg0);
+ if (input) {
+ value &= ~PADCFG0_GPIORXDIS;
+ value |= PADCFG0_GPIOTXDIS;
+ } else {
+ value &= ~PADCFG0_GPIOTXDIS;
+ value |= PADCFG0_GPIORXDIS;
+ }
+ writel(value, padcfg0);
+}
+
static int intel_gpio_request_enable(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
unsigned pin)
/* Disable SCI/SMI/NMI generation */
value &= ~(PADCFG0_GPIROUTIOXAPIC | PADCFG0_GPIROUTSCI);
value &= ~(PADCFG0_GPIROUTSMI | PADCFG0_GPIROUTNMI);
- /* Disable TX buffer and enable RX (this will be input) */
- value &= ~PADCFG0_GPIORXDIS;
- value |= PADCFG0_GPIOTXDIS;
writel(value, padcfg0);
+ /* Disable TX buffer and enable RX (this will be input) */
+ __intel_gpio_set_direction(padcfg0, true);
+
raw_spin_unlock_irqrestore(&pctrl->lock, flags);
return 0;
struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
void __iomem *padcfg0;
unsigned long flags;
- u32 value;
raw_spin_lock_irqsave(&pctrl->lock, flags);
padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0);
-
- value = readl(padcfg0);
- if (input)
- value |= PADCFG0_GPIOTXDIS;
- else
- value &= ~PADCFG0_GPIOTXDIS;
- writel(value, padcfg0);
+ __intel_gpio_set_direction(padcfg0, input);
raw_spin_unlock_irqrestore(&pctrl->lock, flags);
unsigned int i;
int ret;
+ if (!mrfld_buf_available(mp, pin))
+ return -ENOTSUPP;
+
for (i = 0; i < nconfigs; i++) {
switch (pinconf_to_config_param(configs[i])) {
case PIN_CONFIG_BIAS_DISABLE:
static const unsigned int uart_rx_ao_a_pins[] = { PIN(GPIOAO_1, 0) };
static const unsigned int uart_cts_ao_a_pins[] = { PIN(GPIOAO_2, 0) };
static const unsigned int uart_rts_ao_a_pins[] = { PIN(GPIOAO_3, 0) };
-static const unsigned int uart_tx_ao_b_pins[] = { PIN(GPIOAO_0, 0) };
-static const unsigned int uart_rx_ao_b_pins[] = { PIN(GPIOAO_1, 0),
- PIN(GPIOAO_5, 0) };
+static const unsigned int uart_tx_ao_b_pins[] = { PIN(GPIOAO_4, 0) };
+static const unsigned int uart_rx_ao_b_pins[] = { PIN(GPIOAO_5, 0) };
static const unsigned int uart_cts_ao_b_pins[] = { PIN(GPIOAO_2, 0) };
static const unsigned int uart_rts_ao_b_pins[] = { PIN(GPIOAO_3, 0) };
GPIO_GROUP(GPIOAO_13, 0),
/* bank AO */
- GROUP(uart_tx_ao_b, 0, 26),
+ GROUP(uart_tx_ao_b, 0, 24),
GROUP(uart_rx_ao_b, 0, 25),
GROUP(uart_tx_ao_a, 0, 12),
GROUP(uart_rx_ao_a, 0, 11),
static const unsigned int uart_rx_ao_a_pins[] = { PIN(GPIOAO_1, 0) };
static const unsigned int uart_cts_ao_a_pins[] = { PIN(GPIOAO_2, 0) };
static const unsigned int uart_rts_ao_a_pins[] = { PIN(GPIOAO_3, 0) };
-static const unsigned int uart_tx_ao_b_pins[] = { PIN(GPIOAO_0, 0) };
-static const unsigned int uart_rx_ao_b_pins[] = { PIN(GPIOAO_1, 0),
- PIN(GPIOAO_5, 0) };
+static const unsigned int uart_tx_ao_b_pins[] = { PIN(GPIOAO_4, 0) };
+static const unsigned int uart_rx_ao_b_pins[] = { PIN(GPIOAO_5, 0) };
static const unsigned int uart_cts_ao_b_pins[] = { PIN(GPIOAO_2, 0) };
static const unsigned int uart_rts_ao_b_pins[] = { PIN(GPIOAO_3, 0) };
GPIO_GROUP(GPIOAO_9, 0),
/* bank AO */
- GROUP(uart_tx_ao_b, 0, 26),
+ GROUP(uart_tx_ao_b, 0, 24),
GROUP(uart_rx_ao_b, 0, 25),
GROUP(uart_tx_ao_a, 0, 12),
GROUP(uart_rx_ao_a, 0, 11),
i = 128;
pin_num = AMD_GPIO_PINS_BANK2 + i;
break;
+ default:
+ return;
}
for (; i < pin_num; i++) {
val = arg / 10 - 1;
break;
case PIN_CONFIG_BIAS_DISABLE:
- val = 0;
- break;
+ continue;
case PIN_CONFIG_BIAS_PULL_UP:
if (arg == 0)
return -EINVAL;
0, 0, 0, 0};
static const unsigned ether_rmii_pins[] = {30, 31, 32, 33, 34, 35, 36, 37, 39,
41, 42, 45};
-static const int ether_rmii_muxvals[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
+static const int ether_rmii_muxvals[] = {0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1};
static const unsigned i2c0_pins[] = {63, 64};
static const int i2c0_muxvals[] = {0, 0};
static const unsigned i2c1_pins[] = {65, 66};
case MOTIONSENSE_TYPE_ACCEL:
sensor_cells[id].name = "cros-ec-accel";
break;
+ case MOTIONSENSE_TYPE_BARO:
+ sensor_cells[id].name = "cros-ec-baro";
+ break;
case MOTIONSENSE_TYPE_GYRO:
sensor_cells[id].name = "cros-ec-gyro";
break;
case 8:
case 7:
case 6:
+ case 1:
ideapad_input_report(priv, vpc_bit);
break;
case 5:
input_set_capability(input, EV_KEY, KEY_POWER);
- error = request_threaded_irq(irq, NULL, mfld_pb_isr, 0,
+ error = request_threaded_irq(irq, NULL, mfld_pb_isr, IRQF_ONESHOT,
DRIVER_NAME, input);
if (error) {
dev_err(&pdev->dev, "Unable to request irq %d for mfld power"
return 0;
fail_platform_mux_register:
- for (i--; i > 0 ; i--)
+ while (--i >= 0)
platform_device_unregister(priv->pdev_mux[i]);
platform_device_unregister(priv->pdev_i2c);
fail_alloc:
static int s3_wmi_check_platform_device(struct device *dev, void *data)
{
- struct acpi_device *adev, *ts_adev;
+ struct acpi_device *adev, *ts_adev = NULL;
acpi_handle handle;
acpi_status status;
return 0;
}
-#ifdef CONFIG_PM
-static int s3_wmi_resume(struct device *dev)
+static int __maybe_unused s3_wmi_resume(struct device *dev)
{
s3_wmi_send_lid_state();
return 0;
}
-#endif
static SIMPLE_DEV_PM_OPS(s3_wmi_pm, NULL, s3_wmi_resume);
static struct platform_driver s3_wmi_driver = {
To compile this driver as a module, choose M here: the module
will be called pwm-sti.
+config PWM_STM32
+ tristate "STMicroelectronics STM32 PWM"
+ depends on MFD_STM32_TIMERS || COMPILE_TEST
+ help
+ Generic PWM framework driver for STM32 SoCs.
+
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-stm32.
+
config PWM_STMPE
bool "STMPE expander PWM export"
depends on MFD_STMPE
obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o
obj-$(CONFIG_PWM_STI) += pwm-sti.o
+obj-$(CONFIG_PWM_STM32) += pwm-stm32.o
obj-$(CONFIG_PWM_STMPE) += pwm-stmpe.o
obj-$(CONFIG_PWM_SUN4I) += pwm-sun4i.o
obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o
--- /dev/null
+/*
+ * Copyright (C) STMicroelectronics 2016
+ *
+ * Author: Gerald Baeza <gerald.baeza@st.com>
+ *
+ * License terms: GNU General Public License (GPL), version 2
+ *
+ * Inspired by timer-stm32.c from Maxime Coquelin
+ * pwm-atmel.c from Bo Shen
+ */
+
+#include <linux/mfd/stm32-timers.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+
+#define CCMR_CHANNEL_SHIFT 8
+#define CCMR_CHANNEL_MASK 0xFF
+#define MAX_BREAKINPUT 2
+
+struct stm32_pwm {
+ struct pwm_chip chip;
+ struct device *dev;
+ struct clk *clk;
+ struct regmap *regmap;
+ u32 max_arr;
+ bool have_complementary_output;
+};
+
+struct stm32_breakinput {
+ u32 index;
+ u32 level;
+ u32 filter;
+};
+
+static inline struct stm32_pwm *to_stm32_pwm_dev(struct pwm_chip *chip)
+{
+ return container_of(chip, struct stm32_pwm, chip);
+}
+
+static u32 active_channels(struct stm32_pwm *dev)
+{
+ u32 ccer;
+
+ regmap_read(dev->regmap, TIM_CCER, &ccer);
+
+ return ccer & TIM_CCER_CCXE;
+}
+
+static int write_ccrx(struct stm32_pwm *dev, int ch, u32 value)
+{
+ switch (ch) {
+ case 0:
+ return regmap_write(dev->regmap, TIM_CCR1, value);
+ case 1:
+ return regmap_write(dev->regmap, TIM_CCR2, value);
+ case 2:
+ return regmap_write(dev->regmap, TIM_CCR3, value);
+ case 3:
+ return regmap_write(dev->regmap, TIM_CCR4, value);
+ }
+ return -EINVAL;
+}
+
+static int stm32_pwm_config(struct stm32_pwm *priv, int ch,
+ int duty_ns, int period_ns)
+{
+ unsigned long long prd, div, dty;
+ unsigned int prescaler = 0;
+ u32 ccmr, mask, shift;
+
+ /* Period and prescaler values depends on clock rate */
+ div = (unsigned long long)clk_get_rate(priv->clk) * period_ns;
+
+ do_div(div, NSEC_PER_SEC);
+ prd = div;
+
+ while (div > priv->max_arr) {
+ prescaler++;
+ div = prd;
+ do_div(div, prescaler + 1);
+ }
+
+ prd = div;
+
+ if (prescaler > MAX_TIM_PSC)
+ return -EINVAL;
+
+ /*
+ * All channels share the same prescaler and counter so when two
+ * channels are active at the same time we can't change them
+ */
+ if (active_channels(priv) & ~(1 << ch * 4)) {
+ u32 psc, arr;
+
+ regmap_read(priv->regmap, TIM_PSC, &psc);
+ regmap_read(priv->regmap, TIM_ARR, &arr);
+
+ if ((psc != prescaler) || (arr != prd - 1))
+ return -EBUSY;
+ }
+
+ regmap_write(priv->regmap, TIM_PSC, prescaler);
+ regmap_write(priv->regmap, TIM_ARR, prd - 1);
+ regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, TIM_CR1_ARPE);
+
+ /* Calculate the duty cycles */
+ dty = prd * duty_ns;
+ do_div(dty, period_ns);
+
+ write_ccrx(priv, ch, dty);
+
+ /* Configure output mode */
+ shift = (ch & 0x1) * CCMR_CHANNEL_SHIFT;
+ ccmr = (TIM_CCMR_PE | TIM_CCMR_M1) << shift;
+ mask = CCMR_CHANNEL_MASK << shift;
+
+ if (ch < 2)
+ regmap_update_bits(priv->regmap, TIM_CCMR1, mask, ccmr);
+ else
+ regmap_update_bits(priv->regmap, TIM_CCMR2, mask, ccmr);
+
+ regmap_update_bits(priv->regmap, TIM_BDTR,
+ TIM_BDTR_MOE | TIM_BDTR_AOE,
+ TIM_BDTR_MOE | TIM_BDTR_AOE);
+
+ return 0;
+}
+
+static int stm32_pwm_set_polarity(struct stm32_pwm *priv, int ch,
+ enum pwm_polarity polarity)
+{
+ u32 mask;
+
+ mask = TIM_CCER_CC1P << (ch * 4);
+ if (priv->have_complementary_output)
+ mask |= TIM_CCER_CC1NP << (ch * 4);
+
+ regmap_update_bits(priv->regmap, TIM_CCER, mask,
+ polarity == PWM_POLARITY_NORMAL ? 0 : mask);
+
+ return 0;
+}
+
+static int stm32_pwm_enable(struct stm32_pwm *priv, int ch)
+{
+ u32 mask;
+ int ret;
+
+ ret = clk_enable(priv->clk);
+ if (ret)
+ return ret;
+
+ /* Enable channel */
+ mask = TIM_CCER_CC1E << (ch * 4);
+ if (priv->have_complementary_output)
+ mask |= TIM_CCER_CC1NE << (ch * 4);
+
+ regmap_update_bits(priv->regmap, TIM_CCER, mask, mask);
+
+ /* Make sure that registers are updated */
+ regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG);
+
+ /* Enable controller */
+ regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, TIM_CR1_CEN);
+
+ return 0;
+}
+
+static void stm32_pwm_disable(struct stm32_pwm *priv, int ch)
+{
+ u32 mask;
+
+ /* Disable channel */
+ mask = TIM_CCER_CC1E << (ch * 4);
+ if (priv->have_complementary_output)
+ mask |= TIM_CCER_CC1NE << (ch * 4);
+
+ regmap_update_bits(priv->regmap, TIM_CCER, mask, 0);
+
+ /* When all channels are disabled, we can disable the controller */
+ if (!active_channels(priv))
+ regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0);
+
+ clk_disable(priv->clk);
+}
+
+static int stm32_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+ struct pwm_state *state)
+{
+ bool enabled;
+ struct stm32_pwm *priv = to_stm32_pwm_dev(chip);
+ int ret;
+
+ enabled = pwm->state.enabled;
+
+ if (enabled && !state->enabled) {
+ stm32_pwm_disable(priv, pwm->hwpwm);
+ return 0;
+ }
+
+ if (state->polarity != pwm->state.polarity)
+ stm32_pwm_set_polarity(priv, pwm->hwpwm, state->polarity);
+
+ ret = stm32_pwm_config(priv, pwm->hwpwm,
+ state->duty_cycle, state->period);
+ if (ret)
+ return ret;
+
+ if (!enabled && state->enabled)
+ ret = stm32_pwm_enable(priv, pwm->hwpwm);
+
+ return ret;
+}
+
+static const struct pwm_ops stm32pwm_ops = {
+ .owner = THIS_MODULE,
+ .apply = stm32_pwm_apply,
+};
+
+static int stm32_pwm_set_breakinput(struct stm32_pwm *priv,
+ int index, int level, int filter)
+{
+ u32 bke = (index == 0) ? TIM_BDTR_BKE : TIM_BDTR_BK2E;
+ int shift = (index == 0) ? TIM_BDTR_BKF_SHIFT : TIM_BDTR_BK2F_SHIFT;
+ u32 mask = (index == 0) ? TIM_BDTR_BKE | TIM_BDTR_BKP | TIM_BDTR_BKF
+ : TIM_BDTR_BK2E | TIM_BDTR_BK2P | TIM_BDTR_BK2F;
+ u32 bdtr = bke;
+
+ /*
+ * The both bits could be set since only one will be wrote
+ * due to mask value.
+ */
+ if (level)
+ bdtr |= TIM_BDTR_BKP | TIM_BDTR_BK2P;
+
+ bdtr |= (filter & TIM_BDTR_BKF_MASK) << shift;
+
+ regmap_update_bits(priv->regmap, TIM_BDTR, mask, bdtr);
+
+ regmap_read(priv->regmap, TIM_BDTR, &bdtr);
+
+ return (bdtr & bke) ? 0 : -EINVAL;
+}
+
+static int stm32_pwm_apply_breakinputs(struct stm32_pwm *priv,
+ struct device_node *np)
+{
+ struct stm32_breakinput breakinput[MAX_BREAKINPUT];
+ int nb, ret, i, array_size;
+
+ nb = of_property_count_elems_of_size(np, "st,breakinput",
+ sizeof(struct stm32_breakinput));
+
+ /*
+ * Because "st,breakinput" parameter is optional do not make probe
+ * failed if it doesn't exist.
+ */
+ if (nb <= 0)
+ return 0;
+
+ if (nb > MAX_BREAKINPUT)
+ return -EINVAL;
+
+ array_size = nb * sizeof(struct stm32_breakinput) / sizeof(u32);
+ ret = of_property_read_u32_array(np, "st,breakinput",
+ (u32 *)breakinput, array_size);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < nb && !ret; i++) {
+ ret = stm32_pwm_set_breakinput(priv,
+ breakinput[i].index,
+ breakinput[i].level,
+ breakinput[i].filter);
+ }
+
+ return ret;
+}
+
+static void stm32_pwm_detect_complementary(struct stm32_pwm *priv)
+{
+ u32 ccer;
+
+ /*
+ * If complementary bit doesn't exist writing 1 will have no
+ * effect so we can detect it.
+ */
+ regmap_update_bits(priv->regmap,
+ TIM_CCER, TIM_CCER_CC1NE, TIM_CCER_CC1NE);
+ regmap_read(priv->regmap, TIM_CCER, &ccer);
+ regmap_update_bits(priv->regmap, TIM_CCER, TIM_CCER_CC1NE, 0);
+
+ priv->have_complementary_output = (ccer != 0);
+}
+
+static int stm32_pwm_detect_channels(struct stm32_pwm *priv)
+{
+ u32 ccer;
+ int npwm = 0;
+
+ /*
+ * If channels enable bits don't exist writing 1 will have no
+ * effect so we can detect and count them.
+ */
+ regmap_update_bits(priv->regmap,
+ TIM_CCER, TIM_CCER_CCXE, TIM_CCER_CCXE);
+ regmap_read(priv->regmap, TIM_CCER, &ccer);
+ regmap_update_bits(priv->regmap, TIM_CCER, TIM_CCER_CCXE, 0);
+
+ if (ccer & TIM_CCER_CC1E)
+ npwm++;
+
+ if (ccer & TIM_CCER_CC2E)
+ npwm++;
+
+ if (ccer & TIM_CCER_CC3E)
+ npwm++;
+
+ if (ccer & TIM_CCER_CC4E)
+ npwm++;
+
+ return npwm;
+}
+
+static int stm32_pwm_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct stm32_timers *ddata = dev_get_drvdata(pdev->dev.parent);
+ struct stm32_pwm *priv;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->regmap = ddata->regmap;
+ priv->clk = ddata->clk;
+ priv->max_arr = ddata->max_arr;
+
+ if (!priv->regmap || !priv->clk)
+ return -EINVAL;
+
+ ret = stm32_pwm_apply_breakinputs(priv, np);
+ if (ret)
+ return ret;
+
+ stm32_pwm_detect_complementary(priv);
+
+ priv->chip.base = -1;
+ priv->chip.dev = dev;
+ priv->chip.ops = &stm32pwm_ops;
+ priv->chip.npwm = stm32_pwm_detect_channels(priv);
+
+ ret = pwmchip_add(&priv->chip);
+ if (ret < 0)
+ return ret;
+
+ platform_set_drvdata(pdev, priv);
+
+ return 0;
+}
+
+static int stm32_pwm_remove(struct platform_device *pdev)
+{
+ struct stm32_pwm *priv = platform_get_drvdata(pdev);
+ unsigned int i;
+
+ for (i = 0; i < priv->chip.npwm; i++)
+ pwm_disable(&priv->chip.pwms[i]);
+
+ pwmchip_remove(&priv->chip);
+
+ return 0;
+}
+
+static const struct of_device_id stm32_pwm_of_match[] = {
+ { .compatible = "st,stm32-pwm", },
+ { /* end node */ },
+};
+MODULE_DEVICE_TABLE(of, stm32_pwm_of_match);
+
+static struct platform_driver stm32_pwm_driver = {
+ .probe = stm32_pwm_probe,
+ .remove = stm32_pwm_remove,
+ .driver = {
+ .name = "stm32-pwm",
+ .of_match_table = stm32_pwm_of_match,
+ },
+};
+module_platform_driver(stm32_pwm_driver);
+
+MODULE_ALIAS("platform:stm32-pwm");
+MODULE_DESCRIPTION("STMicroelectronics STM32 PWM driver");
+MODULE_LICENSE("GPL v2");
64, AXP806_DCDCD_V_CTRL, 0x3f, AXP806_PWR_OUT_CTRL1,
BIT(3)),
AXP_DESC(AXP806, DCDCE, "dcdce", "vine", 1100, 3400, 100,
- AXP806_DCDCB_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(4)),
+ AXP806_DCDCE_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(4)),
AXP_DESC(AXP806, ALDO1, "aldo1", "aldoin", 700, 3300, 100,
AXP806_ALDO1_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(5)),
AXP_DESC(AXP806, ALDO2, "aldo2", "aldoin", 700, 3400, 100,
#include <linux/of_gpio.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/machine.h>
-#include <linux/acpi.h>
-#include <linux/property.h>
-#include <linux/gpio/consumer.h>
struct fixed_voltage_data {
struct regulator_desc desc;
return config;
}
-/**
- * acpi_get_fixed_voltage_config - extract fixed_voltage_config structure info
- * @dev: device requesting for fixed_voltage_config
- * @desc: regulator description
- *
- * Populates fixed_voltage_config structure by extracting data through ACPI
- * interface, returns a pointer to the populated structure of NULL if memory
- * alloc fails.
- */
-static struct fixed_voltage_config *
-acpi_get_fixed_voltage_config(struct device *dev,
- const struct regulator_desc *desc)
-{
- struct fixed_voltage_config *config;
- const char *supply_name;
- struct gpio_desc *gpiod;
- int ret;
-
- config = devm_kzalloc(dev, sizeof(*config), GFP_KERNEL);
- if (!config)
- return ERR_PTR(-ENOMEM);
-
- ret = device_property_read_string(dev, "supply-name", &supply_name);
- if (!ret)
- config->supply_name = supply_name;
-
- gpiod = gpiod_get(dev, "gpio", GPIOD_ASIS);
- if (IS_ERR(gpiod))
- return ERR_PTR(-ENODEV);
-
- config->gpio = desc_to_gpio(gpiod);
- config->enable_high = device_property_read_bool(dev,
- "enable-active-high");
- gpiod_put(gpiod);
-
- return config;
-}
-
static struct regulator_ops fixed_voltage_ops = {
};
&drvdata->desc);
if (IS_ERR(config))
return PTR_ERR(config);
- } else if (ACPI_HANDLE(&pdev->dev)) {
- config = acpi_get_fixed_voltage_config(&pdev->dev,
- &drvdata->desc);
- if (IS_ERR(config))
- return PTR_ERR(config);
} else {
config = dev_get_platdata(&pdev->dev);
}
vsel = 62;
else if ((min_uV > 1800000) && (min_uV <= 1900000))
vsel = 61;
- else if ((min_uV > 1350000) && (min_uV <= 1800000))
+ else if ((min_uV > 1500000) && (min_uV <= 1800000))
vsel = 60;
else if ((min_uV > 1350000) && (min_uV <= 1500000))
vsel = 59;
goto unwind_vring_allocations;
}
- /* track the rvdevs list reference */
- kref_get(&rvdev->refcount);
-
list_add_tail(&rvdev->node, &rproc->rvdevs);
rproc_add_subdev(rproc, &rvdev->subdev,
/*
* Create a copy of the resource table. When a virtio device starts
* and calls vring_new_virtqueue() the address of the allocated vring
- * will be stored in the table_ptr. Before the device is started,
- * table_ptr will be copied into device memory.
+ * will be stored in the cached_table. Before the device is started,
+ * cached_table will be copied into device memory.
*/
- rproc->table_ptr = kmemdup(table, tablesz, GFP_KERNEL);
- if (!rproc->table_ptr)
+ rproc->cached_table = kmemdup(table, tablesz, GFP_KERNEL);
+ if (!rproc->cached_table)
goto clean_up;
+ rproc->table_ptr = rproc->cached_table;
+
/* reset max_notifyid */
rproc->max_notifyid = -1;
}
/*
- * The starting device has been given the rproc->table_ptr as the
+ * The starting device has been given the rproc->cached_table as the
* resource table. The address of the vring along with the other
- * allocated resources (carveouts etc) is stored in table_ptr.
+ * allocated resources (carveouts etc) is stored in cached_table.
* In order to pass this information to the remote device we must copy
* this information to device memory. We also update the table_ptr so
* that any subsequent changes will be applied to the loaded version.
*/
loaded_table = rproc_find_loaded_rsc_table(rproc, fw);
- if (loaded_table)
- memcpy(loaded_table, rproc->table_ptr, tablesz);
+ if (loaded_table) {
+ memcpy(loaded_table, rproc->cached_table, tablesz);
+ rproc->table_ptr = loaded_table;
+ }
/* power up the remote processor */
ret = rproc->ops->start(rproc);
clean_up_resources:
rproc_resource_cleanup(rproc);
clean_up:
- kfree(rproc->table_ptr);
+ kfree(rproc->cached_table);
+ rproc->cached_table = NULL;
rproc->table_ptr = NULL;
rproc_disable_iommu(rproc);
rproc_disable_iommu(rproc);
/* Free the copy of the resource table */
- kfree(rproc->table_ptr);
+ kfree(rproc->cached_table);
+ rproc->cached_table = NULL;
rproc->table_ptr = NULL;
/* if in crash state, unlock crash handler */
struct device *dev = &rpdev->dev;
int ret;
- dev_set_name(&rpdev->dev, "%s:%s",
- dev_name(dev->parent), rpdev->id.name);
+ dev_set_name(&rpdev->dev, "%s.%s.%d.%d", dev_name(dev->parent),
+ rpdev->id.name, rpdev->src, rpdev->dst);
rpdev->dev.bus = &rpmsg_bus;
rpdev->dev.release = rpmsg_release_device;
will be called rtc-mpc5121.
config RTC_DRV_JZ4740
- bool "Ingenic JZ4740 SoC"
+ tristate "Ingenic JZ4740 SoC"
depends on MACH_INGENIC || COMPILE_TEST
help
If you say yes here you get support for the Ingenic JZ47xx SoCs RTC
controllers.
+ This driver can also be buillt as a module. If so, the module
+ will be called rtc-jz4740.
+
config RTC_DRV_LPC24XX
tristate "NXP RTC for LPC178x/18xx/408x/43xx"
depends on ARCH_LPC18XX || COMPILE_TEST
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/reboot.h>
JZ_REG_RTC_RESET_COUNTER, reset_counter_ticks);
jz4740_rtc_poweroff(dev_for_power_off);
- machine_halt();
+ kernel_halt();
}
static const struct of_device_id jz4740_rtc_of_match[] = {
{ .compatible = "ingenic,jz4780-rtc", .data = (void *)ID_JZ4780 },
{},
};
+MODULE_DEVICE_TABLE(of, jz4740_rtc_of_match);
static int jz4740_rtc_probe(struct platform_device *pdev)
{
{ "jz4780-rtc", ID_JZ4780 },
{}
};
+MODULE_DEVICE_TABLE(platform, jz4740_rtc_ids);
static struct platform_driver jz4740_rtc_driver = {
.probe = jz4740_rtc_probe,
.id_table = jz4740_rtc_ids,
};
-builtin_platform_driver(jz4740_rtc_driver);
+module_platform_driver(jz4740_rtc_driver);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("RTC driver for the JZ4740 SoC\n");
+MODULE_ALIAS("platform:jz4740-rtc");
#define CCW_CMD_WRITE_CONF 0x21
#define CCW_CMD_WRITE_STATUS 0x31
#define CCW_CMD_READ_VQ_CONF 0x32
+#define CCW_CMD_READ_STATUS 0x72
#define CCW_CMD_SET_IND_ADAPTER 0x73
#define CCW_CMD_SET_VIRTIO_REV 0x83
#define VIRTIO_CCW_DOING_SET_CONF_IND 0x04000000
#define VIRTIO_CCW_DOING_SET_IND_ADAPTER 0x08000000
#define VIRTIO_CCW_DOING_SET_VIRTIO_REV 0x10000000
+#define VIRTIO_CCW_DOING_READ_STATUS 0x20000000
#define VIRTIO_CCW_INTPARM_MASK 0xffff0000
static struct virtio_ccw_device *to_vc_device(struct virtio_device *vdev)
* This may happen on device detach.
*/
if (ret && (ret != -ENODEV))
- dev_warn(&vq->vdev->dev, "Error %d while deleting queue %d",
+ dev_warn(&vq->vdev->dev, "Error %d while deleting queue %d\n",
ret, index);
vring_del_virtqueue(vq);
static u8 virtio_ccw_get_status(struct virtio_device *vdev)
{
struct virtio_ccw_device *vcdev = to_vc_device(vdev);
+ u8 old_status = *vcdev->status;
+ struct ccw1 *ccw;
+
+ if (vcdev->revision < 1)
+ return *vcdev->status;
+
+ ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
+ if (!ccw)
+ return old_status;
+
+ ccw->cmd_code = CCW_CMD_READ_STATUS;
+ ccw->flags = 0;
+ ccw->count = sizeof(*vcdev->status);
+ ccw->cda = (__u32)(unsigned long)vcdev->status;
+ ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_STATUS);
+/*
+ * If the channel program failed (should only happen if the device
+ * was hotunplugged, and then we clean up via the machine check
+ * handler anyway), vcdev->status was not overwritten and we just
+ * return the old status, which is fine.
+*/
+ kfree(ccw);
return *vcdev->status;
}
kfree(ccw);
}
-static struct virtio_config_ops virtio_ccw_config_ops = {
+static const struct virtio_config_ops virtio_ccw_config_ops = {
.get_features = virtio_ccw_get_features,
.finalize_features = virtio_ccw_finalize_features,
.get = virtio_ccw_get_config,
case VIRTIO_CCW_DOING_READ_CONFIG:
case VIRTIO_CCW_DOING_WRITE_CONFIG:
case VIRTIO_CCW_DOING_WRITE_STATUS:
+ case VIRTIO_CCW_DOING_READ_STATUS:
case VIRTIO_CCW_DOING_SET_VQ:
case VIRTIO_CCW_DOING_SET_IND:
case VIRTIO_CCW_DOING_SET_CONF_IND:
u32 bfi_image_cb_size, bfi_image_ct_size, bfi_image_ct2_size;
u32 *bfi_image_cb, *bfi_image_ct, *bfi_image_ct2;
-#define BFAD_FW_FILE_CB "cbfw-3.2.3.0.bin"
-#define BFAD_FW_FILE_CT "ctfw-3.2.3.0.bin"
-#define BFAD_FW_FILE_CT2 "ct2fw-3.2.3.0.bin"
+#define BFAD_FW_FILE_CB "cbfw-3.2.5.1.bin"
+#define BFAD_FW_FILE_CT "ctfw-3.2.5.1.bin"
+#define BFAD_FW_FILE_CT2 "ct2fw-3.2.5.1.bin"
static u32 *bfad_load_fwimg(struct pci_dev *pdev);
static void bfad_free_fwimg(void);
struct bfad_fcxp *drv_fcxp;
struct bfa_fcs_lport_s *fcs_port;
struct bfa_fcs_rport_s *fcs_rport;
- struct fc_bsg_request *bsg_request = bsg_request;
+ struct fc_bsg_request *bsg_request = job->request;
struct fc_bsg_reply *bsg_reply = job->reply;
uint32_t command_type = bsg_request->msgcode;
unsigned long flags;
#ifdef BFA_DRIVER_VERSION
#define BFAD_DRIVER_VERSION BFA_DRIVER_VERSION
#else
-#define BFAD_DRIVER_VERSION "3.2.25.0"
+#define BFAD_DRIVER_VERSION "3.2.25.1"
#endif
#define BFAD_PROTO_NAME FCPI_NAME
struct completion *remove_wait; /* device remove thread blocks */
atomic_t in_flight; /* io counter */
+ bool internal_reset_inprogress;
u32 _reserved; /* fill hole */
unsigned long state_flags; /* protected by host lock */
enum fnic_state state;
unsigned long wait_host_tmo;
struct Scsi_Host *shost = sc->device->host;
struct fc_lport *lp = shost_priv(shost);
+ struct fnic *fnic = lport_priv(lp);
+ unsigned long flags;
+
+ spin_lock_irqsave(&fnic->fnic_lock, flags);
+ if (fnic->internal_reset_inprogress == 0) {
+ fnic->internal_reset_inprogress = 1;
+ } else {
+ spin_unlock_irqrestore(&fnic->fnic_lock, flags);
+ FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host,
+ "host reset in progress skipping another host reset\n");
+ return SUCCESS;
+ }
+ spin_unlock_irqrestore(&fnic->fnic_lock, flags);
/*
* If fnic_reset is successful, wait for fabric login to complete
}
}
+ spin_lock_irqsave(&fnic->fnic_lock, flags);
+ fnic->internal_reset_inprogress = 0;
+ spin_unlock_irqrestore(&fnic->fnic_lock, flags);
return ret;
}
#define INITIAL_SRP_LIMIT 800
#define DEFAULT_MAX_SECTORS 256
+#define MAX_TXU 1024 * 1024
static uint max_vdma_size = MAX_H_COPY_RDMA;
}
info = dma_alloc_coherent(&vscsi->dma_dev->dev, sizeof(*info), &token,
- GFP_KERNEL);
+ GFP_ATOMIC);
if (!info) {
dev_err(&vscsi->dev, "bad dma_alloc_coherent %p\n",
iue->target);
info->mad_version = cpu_to_be32(MAD_VERSION_1);
info->os_type = cpu_to_be32(LINUX);
memset(&info->port_max_txu[0], 0, sizeof(info->port_max_txu));
- info->port_max_txu[0] = cpu_to_be32(128 * PAGE_SIZE);
+ info->port_max_txu[0] = cpu_to_be32(MAX_TXU);
dma_wmb();
rc = h_copy_rdma(sizeof(*info), vscsi->dds.window[LOCAL].liobn,
}
cap = dma_alloc_coherent(&vscsi->dma_dev->dev, olen, &token,
- GFP_KERNEL);
+ GFP_ATOMIC);
if (!cap) {
dev_err(&vscsi->dev, "bad dma_alloc_coherent %p\n",
iue->target);
1, 1);
if (rc) {
pr_err("srp_transfer_data() failed: %d\n", rc);
- return -EAGAIN;
+ return -EIO;
}
/*
* We now tell TCM to add this WRITE CDB directly into the TCM storage
} else {
buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2;
lpfc_els_free_data(phba, buf_ptr1);
+ elsiocb->context2 = NULL;
}
}
if (elsiocb->context3) {
buf_ptr = (struct lpfc_dmabuf *) elsiocb->context3;
lpfc_els_free_bpl(phba, buf_ptr);
+ elsiocb->context3 = NULL;
}
lpfc_sli_release_iocbq(phba, elsiocb);
return 0;
free_vfi_bmask:
kfree(phba->sli4_hba.vfi_bmask);
+ phba->sli4_hba.vfi_bmask = NULL;
free_xri_ids:
kfree(phba->sli4_hba.xri_ids);
+ phba->sli4_hba.xri_ids = NULL;
free_xri_bmask:
kfree(phba->sli4_hba.xri_bmask);
+ phba->sli4_hba.xri_bmask = NULL;
free_vpi_ids:
kfree(phba->vpi_ids);
+ phba->vpi_ids = NULL;
free_vpi_bmask:
kfree(phba->vpi_bmask);
+ phba->vpi_bmask = NULL;
free_rpi_ids:
kfree(phba->sli4_hba.rpi_ids);
+ phba->sli4_hba.rpi_ids = NULL;
free_rpi_bmask:
kfree(phba->sli4_hba.rpi_bmask);
+ phba->sli4_hba.rpi_bmask = NULL;
err_exit:
return rc;
}
* @eedp_enable: eedp support enable bit
* @eedp_type: 0(type_1), 1(type_2), 2(type_3)
* @eedp_block_length: block size
+ * @ata_command_pending: SATL passthrough outstanding for device
*/
struct MPT3SAS_DEVICE {
struct MPT3SAS_TARGET *sas_target;
u8 ignore_delay_remove;
/* Iopriority Command Handling */
u8 ncq_prio_enable;
+ /*
+ * Bug workaround for SATL handling: the mpt2/3sas firmware
+ * doesn't return BUSY or TASK_SET_FULL for subsequent
+ * commands while a SATL pass through is in operation as the
+ * spec requires, it simply does nothing with them until the
+ * pass through completes, causing them possibly to timeout if
+ * the passthrough is a long executing command (like format or
+ * secure erase). This variable allows us to do the right
+ * thing while a SATL command is pending.
+ */
+ unsigned long ata_command_pending;
};
}
}
-static inline bool ata_12_16_cmd(struct scsi_cmnd *scmd)
+static int _scsih_set_satl_pending(struct scsi_cmnd *scmd, bool pending)
{
- return (scmd->cmnd[0] == ATA_12 || scmd->cmnd[0] == ATA_16);
+ struct MPT3SAS_DEVICE *priv = scmd->device->hostdata;
+
+ if (scmd->cmnd[0] != ATA_12 && scmd->cmnd[0] != ATA_16)
+ return 0;
+
+ if (pending)
+ return test_and_set_bit(0, &priv->ata_command_pending);
+
+ clear_bit(0, &priv->ata_command_pending);
+ return 0;
}
/**
if (!scmd)
continue;
count++;
- if (ata_12_16_cmd(scmd))
- scsi_internal_device_unblock(scmd->device,
- SDEV_RUNNING);
+ _scsih_set_satl_pending(scmd, false);
mpt3sas_base_free_smid(ioc, smid);
scsi_dma_unmap(scmd);
if (ioc->pci_error_recovery)
if (ioc->logging_level & MPT_DEBUG_SCSI)
scsi_print_command(scmd);
- /*
- * Lock the device for any subsequent command until command is
- * done.
- */
- if (ata_12_16_cmd(scmd))
- scsi_internal_device_block(scmd->device);
-
sas_device_priv_data = scmd->device->hostdata;
if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
scmd->result = DID_NO_CONNECT << 16;
return 0;
}
+ /*
+ * Bug work around for firmware SATL handling. The loop
+ * is based on atomic operations and ensures consistency
+ * since we're lockless at this point
+ */
+ do {
+ if (test_bit(0, &sas_device_priv_data->ata_command_pending)) {
+ scmd->result = SAM_STAT_BUSY;
+ scmd->scsi_done(scmd);
+ return 0;
+ }
+ } while (_scsih_set_satl_pending(scmd, true));
+
sas_target_priv_data = sas_device_priv_data->sas_target;
/* invalid device handle */
if (scmd == NULL)
return 1;
- if (ata_12_16_cmd(scmd))
- scsi_internal_device_unblock(scmd->device, SDEV_RUNNING);
+ _scsih_set_satl_pending(scmd, false);
mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
config QEDI
tristate "QLogic QEDI 25/40/100Gb iSCSI Initiator Driver Support"
- depends on PCI && SCSI
+ depends on PCI && SCSI && UIO
depends on QED
select SCSI_ISCSI_ATTRS
select QED_LL2
struct qla_hw_data *ha = vha->hw;
ssize_t rval = 0;
+ mutex_lock(&ha->optrom_mutex);
+
if (ha->optrom_state != QLA_SREADING)
- return 0;
+ goto out;
- mutex_lock(&ha->optrom_mutex);
rval = memory_read_from_buffer(buf, count, &off, ha->optrom_buffer,
ha->optrom_region_size);
+
+out:
mutex_unlock(&ha->optrom_mutex);
return rval;
struct device, kobj)));
struct qla_hw_data *ha = vha->hw;
- if (ha->optrom_state != QLA_SWRITING)
+ mutex_lock(&ha->optrom_mutex);
+
+ if (ha->optrom_state != QLA_SWRITING) {
+ mutex_unlock(&ha->optrom_mutex);
return -EINVAL;
- if (off > ha->optrom_region_size)
+ }
+ if (off > ha->optrom_region_size) {
+ mutex_unlock(&ha->optrom_mutex);
return -ERANGE;
+ }
if (off + count > ha->optrom_region_size)
count = ha->optrom_region_size - off;
- mutex_lock(&ha->optrom_mutex);
memcpy(&ha->optrom_buffer[off], buf, count);
mutex_unlock(&ha->optrom_mutex);
struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
struct device, kobj)));
int type;
- int rval = 0;
port_id_t did;
type = simple_strtol(buf, NULL, 10);
ql_log(ql_log_info, vha, 0x70e4, "%s: %d\n", __func__, type);
- rval = qla24xx_els_dcmd_iocb(vha, ELS_DCMD_LOGO, did);
+ qla24xx_els_dcmd_iocb(vha, ELS_DCMD_LOGO, did);
return count;
}
struct atio {
uint8_t entry_type; /* Entry type. */
uint8_t entry_count; /* Entry count. */
- uint8_t data[58];
+ __le16 attr_n_length;
+ uint8_t data[56];
uint32_t signature;
#define ATIO_PROCESSED 0xDEADDEAD /* Signature */
};
#define QLA_MSIX_FW_MODE(m) (((m) & (BIT_7|BIT_8|BIT_9)) >> 7)
#define QLA_MSIX_FW_MODE_1(m) (QLA_MSIX_FW_MODE(m) == 1)
-#define QLA_MSIX_DEFAULT 0x00
+#define QLA_BASE_VECTORS 2 /* default + RSP */
#define QLA_MSIX_RSP_Q 0x01
#define QLA_ATIO_VECTOR 0x02
#define QLA_MSIX_QPAIR_MULTIQ_RSP_Q 0x03
uint16_t entry;
char name[30];
void *handle;
- struct irq_affinity_notify irq_notify;
int cpuid;
};
/* Wait for soft-reset to complete. */
RD_REG_DWORD(®->ctrl_status);
- for (cnt = 0; cnt < 6000000; cnt++) {
+ for (cnt = 0; cnt < 60; cnt++) {
barrier();
if ((RD_REG_DWORD(®->ctrl_status) &
CSRX_ISP_SOFT_RESET) == 0)
RD_REG_DWORD(®->hccr);
RD_REG_WORD(®->mailbox0);
- for (cnt = 6000000; RD_REG_WORD(®->mailbox0) != 0 &&
+ for (cnt = 60; RD_REG_WORD(®->mailbox0) != 0 &&
rval == QLA_SUCCESS; cnt--) {
barrier();
if (cnt)
static void qla2x00_status_cont_entry(struct rsp_que *, sts_cont_entry_t *);
static void qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *,
sts_entry_t *);
-static void qla_irq_affinity_notify(struct irq_affinity_notify *,
- const cpumask_t *);
-static void qla_irq_affinity_release(struct kref *);
-
/**
* qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200.
if (pkt->entry_status & RF_BUSY)
res = DID_BUS_BUSY << 16;
+ if (pkt->entry_type == NOTIFY_ACK_TYPE &&
+ pkt->handle == QLA_TGT_SKIP_HANDLE)
+ return;
+
sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
if (sp) {
sp->done(ha, sp, res);
if (!vha->flags.online)
return;
- if (rsp->msix && rsp->msix->cpuid != smp_processor_id()) {
- /* if kernel does not notify qla of IRQ's CPU change,
- * then set it here.
- */
- rsp->msix->cpuid = smp_processor_id();
- ha->tgt.rspq_vector_cpuid = rsp->msix->cpuid;
- }
-
while (rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
pkt = (struct sts_entry_24xx *)rsp->ring_ptr;
static int
qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
{
-#define MIN_MSIX_COUNT 2
int i, ret;
struct qla_msix_entry *qentry;
scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
+ struct irq_affinity desc = {
+ .pre_vectors = QLA_BASE_VECTORS,
+ };
+
+ if (QLA_TGT_MODE_ENABLED() && IS_ATIO_MSIX_CAPABLE(ha))
+ desc.pre_vectors++;
+
+ ret = pci_alloc_irq_vectors_affinity(ha->pdev, QLA_BASE_VECTORS,
+ ha->msix_count, PCI_IRQ_MSIX | PCI_IRQ_AFFINITY,
+ &desc);
- ret = pci_alloc_irq_vectors(ha->pdev, MIN_MSIX_COUNT, ha->msix_count,
- PCI_IRQ_MSIX | PCI_IRQ_AFFINITY);
if (ret < 0) {
ql_log(ql_log_fatal, vha, 0x00c7,
"MSI-X: Failed to enable support, "
qentry->have_irq = 0;
qentry->in_use = 0;
qentry->handle = NULL;
- qentry->irq_notify.notify = qla_irq_affinity_notify;
- qentry->irq_notify.release = qla_irq_affinity_release;
- qentry->cpuid = -1;
}
/* Enable MSI-X vectors for the base queue */
- for (i = 0; i < (QLA_MSIX_RSP_Q + 1); i++) {
+ for (i = 0; i < QLA_BASE_VECTORS; i++) {
qentry = &ha->msix_entries[i];
qentry->handle = rsp;
rsp->msix = qentry;
goto msix_register_fail;
qentry->have_irq = 1;
qentry->in_use = 1;
-
- /* Register for CPU affinity notification. */
- irq_set_affinity_notifier(qentry->vector, &qentry->irq_notify);
-
- /* Schedule work (ie. trigger a notification) to read cpu
- * mask for this specific irq.
- * kref_get is required because
- * irq_affinity_notify() will do
- * kref_put().
- */
- kref_get(&qentry->irq_notify.kref);
- schedule_work(&qentry->irq_notify.work);
}
/*
msix->handle = qpair;
return ret;
}
-
-
-/* irq_set_affinity/irqbalance will trigger notification of cpu mask update */
-static void qla_irq_affinity_notify(struct irq_affinity_notify *notify,
- const cpumask_t *mask)
-{
- struct qla_msix_entry *e =
- container_of(notify, struct qla_msix_entry, irq_notify);
- struct qla_hw_data *ha;
- struct scsi_qla_host *base_vha;
- struct rsp_que *rsp = e->handle;
-
- /* user is recommended to set mask to just 1 cpu */
- e->cpuid = cpumask_first(mask);
-
- ha = rsp->hw;
- base_vha = pci_get_drvdata(ha->pdev);
-
- ql_dbg(ql_dbg_init, base_vha, 0xffff,
- "%s: host %ld : vector %d cpu %d \n", __func__,
- base_vha->host_no, e->vector, e->cpuid);
-
- if (e->have_irq) {
- if ((IS_QLA83XX(ha) || IS_QLA27XX(ha)) &&
- (e->entry == QLA83XX_RSPQ_MSIX_ENTRY_NUMBER)) {
- ha->tgt.rspq_vector_cpuid = e->cpuid;
- ql_dbg(ql_dbg_init, base_vha, 0xffff,
- "%s: host%ld: rspq vector %d cpu %d runtime change\n",
- __func__, base_vha->host_no, e->vector, e->cpuid);
- }
- }
-}
-
-static void qla_irq_affinity_release(struct kref *ref)
-{
- struct irq_affinity_notify *notify =
- container_of(ref, struct irq_affinity_notify, kref);
- struct qla_msix_entry *e =
- container_of(notify, struct qla_msix_entry, irq_notify);
- struct rsp_que *rsp = e->handle;
- struct scsi_qla_host *base_vha = pci_get_drvdata(rsp->hw->pdev);
-
- ql_dbg(ql_dbg_init, base_vha, 0xffff,
- "%s: host%ld: vector %d cpu %d\n", __func__,
- base_vha->host_no, e->vector, e->cpuid);
-}
#include <linux/delay.h>
#include <linux/gfp.h>
-struct rom_cmd {
+static struct rom_cmd {
uint16_t cmd;
} rom_cmds[] = {
{ MBC_LOAD_RAM },
return QLA_FUNCTION_TIMEOUT;
}
- /* if PCI error, then avoid mbx processing.*/
- if (test_bit(PCI_ERR, &base_vha->dpc_flags)) {
+ /* if PCI error, then avoid mbx processing.*/
+ if (test_bit(PCI_ERR, &base_vha->dpc_flags)) {
ql_log(ql_log_warn, vha, 0x1191,
"PCI error, exiting.\n");
return QLA_FUNCTION_TIMEOUT;
- }
+ }
reg = ha->iobase;
io_lock_on = base_vha->flags.init_done;
}
} else {
- uint16_t mb0;
- uint32_t ictrl;
+ uint16_t mb[8];
+ uint32_t ictrl, host_status, hccr;
uint16_t w;
if (IS_FWI2_CAPABLE(ha)) {
- mb0 = RD_REG_WORD(®->isp24.mailbox0);
+ mb[0] = RD_REG_WORD(®->isp24.mailbox0);
+ mb[1] = RD_REG_WORD(®->isp24.mailbox1);
+ mb[2] = RD_REG_WORD(®->isp24.mailbox2);
+ mb[3] = RD_REG_WORD(®->isp24.mailbox3);
+ mb[7] = RD_REG_WORD(®->isp24.mailbox7);
ictrl = RD_REG_DWORD(®->isp24.ictrl);
+ host_status = RD_REG_DWORD(®->isp24.host_status);
+ hccr = RD_REG_DWORD(®->isp24.hccr);
+
+ ql_log(ql_log_warn, vha, 0x1119,
+ "MBX Command timeout for cmd %x, iocontrol=%x jiffies=%lx "
+ "mb[0-3]=[0x%x 0x%x 0x%x 0x%x] mb7 0x%x host_status 0x%x hccr 0x%x\n",
+ command, ictrl, jiffies, mb[0], mb[1], mb[2], mb[3],
+ mb[7], host_status, hccr);
+
} else {
- mb0 = RD_MAILBOX_REG(ha, ®->isp, 0);
+ mb[0] = RD_MAILBOX_REG(ha, ®->isp, 0);
ictrl = RD_REG_WORD(®->isp.ictrl);
+ ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1119,
+ "MBX Command timeout for cmd %x, iocontrol=%x jiffies=%lx "
+ "mb[0]=0x%x\n", command, ictrl, jiffies, mb[0]);
}
- ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1119,
- "MBX Command timeout for cmd %x, iocontrol=%x jiffies=%lx "
- "mb[0]=0x%x\n", command, ictrl, jiffies, mb0);
ql_dump_regs(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1019);
/* Capture FW dump only, if PCI device active */
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
struct qla_hw_data *ha = vha->hw;
- int configured_count;
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x111a,
"Entered %s.\n", __func__);
/*EMPTY*/
ql_dbg(ql_dbg_mbx, vha, 0x111b, "Failed=%x.\n", rval);
} else {
- configured_count = mcp->mb[11];
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x118c,
"Done %s.\n", __func__);
}
(crb_addr_xform[QLA82XX_HW_PX_MAP_CRB_##name] = \
QLA82XX_HW_CRB_HUB_AGT_ADR_##name << 20)
+const int MD_MIU_TEST_AGT_RDDATA[] = {
+ 0x410000A8, 0x410000AC,
+ 0x410000B8, 0x410000BC
+};
+
static void qla82xx_crb_addr_transform_setup(void)
{
qla82xx_crb_addr_transform(XDMA);
#define MD_MIU_TEST_AGT_ADDR_LO 0x41000094
#define MD_MIU_TEST_AGT_ADDR_HI 0x41000098
-static const int MD_MIU_TEST_AGT_RDDATA[] = { 0x410000A8, 0x410000AC,
- 0x410000B8, 0x410000BC };
+extern const int MD_MIU_TEST_AGT_RDDATA[4];
#define CRB_NIU_XG_PAUSE_CTL_P0 0x1
#define CRB_NIU_XG_PAUSE_CTL_P1 0x8
#define TIMEOUT_100_MS 100
+static const uint32_t qla8044_reg_tbl[] = {
+ QLA8044_PEG_HALT_STATUS1,
+ QLA8044_PEG_HALT_STATUS2,
+ QLA8044_PEG_ALIVE_COUNTER,
+ QLA8044_CRB_DRV_ACTIVE,
+ QLA8044_CRB_DEV_STATE,
+ QLA8044_CRB_DRV_STATE,
+ QLA8044_CRB_DRV_SCRATCH,
+ QLA8044_CRB_DEV_PART_INFO1,
+ QLA8044_CRB_IDC_VER_MAJOR,
+ QLA8044_FW_VER_MAJOR,
+ QLA8044_FW_VER_MINOR,
+ QLA8044_FW_VER_SUB,
+ QLA8044_CMDPEG_STATE,
+ QLA8044_ASIC_TEMP,
+};
+
/* 8044 Flash Read/Write functions */
uint32_t
qla8044_rd_reg(struct qla_hw_data *ha, ulong addr)
#define CRB_CMDPEG_CHECK_RETRY_COUNT 60
#define CRB_CMDPEG_CHECK_DELAY 500
-static const uint32_t qla8044_reg_tbl[] = {
- QLA8044_PEG_HALT_STATUS1,
- QLA8044_PEG_HALT_STATUS2,
- QLA8044_PEG_ALIVE_COUNTER,
- QLA8044_CRB_DRV_ACTIVE,
- QLA8044_CRB_DEV_STATE,
- QLA8044_CRB_DRV_STATE,
- QLA8044_CRB_DRV_SCRATCH,
- QLA8044_CRB_DEV_PART_INFO1,
- QLA8044_CRB_IDC_VER_MAJOR,
- QLA8044_FW_VER_MAJOR,
- QLA8044_FW_VER_MINOR,
- QLA8044_FW_VER_SUB,
- QLA8044_CMDPEG_STATE,
- QLA8044_ASIC_TEMP,
-};
-
/* MiniDump Structures */
/* Driver_code is for driver to write some info about the entry
continue;
rsp = ha->rsp_q_map[cnt];
- clear_bit(cnt, ha->req_qid_map);
+ clear_bit(cnt, ha->rsp_qid_map);
ha->rsp_q_map[cnt] = NULL;
spin_unlock_irqrestore(&ha->hardware_lock, flags);
qla2x00_free_rsp_que(ha, rsp);
sizeof(struct ct6_dsd), 0,
SLAB_HWCACHE_ALIGN, NULL);
if (!ctx_cachep)
- goto fail_free_gid_list;
+ goto fail_free_srb_mempool;
}
ha->ctx_mempool = mempool_create_slab_pool(SRB_MIN_REQ,
ctx_cachep);
ha->loop_id_map = kzalloc(BITS_TO_LONGS(LOOPID_MAP_SIZE) * sizeof(long),
GFP_KERNEL);
if (!ha->loop_id_map)
- goto fail_async_pd;
+ goto fail_loop_id_map;
else {
qla2x00_set_reserved_loop_ids(ha);
ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0123,
return 0;
+fail_loop_id_map:
+ dma_pool_free(ha->s_dma_pool, ha->async_pd, ha->async_pd_dma);
fail_async_pd:
dma_pool_free(ha->s_dma_pool, ha->ex_init_cb, ha->ex_init_cb_dma);
fail_ex_init_cb:
dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma);
ha->ms_iocb = NULL;
ha->ms_iocb_dma = 0;
+
+ if (ha->sns_cmd)
+ dma_free_coherent(&ha->pdev->dev, sizeof(struct sns_cmd_pkt),
+ ha->sns_cmd, ha->sns_cmd_dma);
fail_dma_pool:
if (IS_QLA82XX(ha) || ql2xenabledif) {
dma_pool_destroy(ha->fcp_cmnd_dma_pool);
kfree(ha->nvram);
ha->nvram = NULL;
fail_free_ctx_mempool:
- mempool_destroy(ha->ctx_mempool);
+ if (ha->ctx_mempool)
+ mempool_destroy(ha->ctx_mempool);
ha->ctx_mempool = NULL;
fail_free_srb_mempool:
- mempool_destroy(ha->srb_mempool);
+ if (ha->srb_mempool)
+ mempool_destroy(ha->srb_mempool);
ha->srb_mempool = NULL;
fail_free_gid_list:
dma_free_coherent(&ha->pdev->dev, qla2x00_gid_list_size(ha),
{
struct qla_hw_data *ha = vha->hw;
struct qla_tgt_sess *sess = NULL;
- uint32_t unpacked_lun, lun = 0;
uint16_t loop_id;
int res = 0;
struct imm_ntfy_from_isp *n = (struct imm_ntfy_from_isp *)iocb;
- struct atio_from_isp *a = (struct atio_from_isp *)iocb;
unsigned long flags;
loop_id = le16_to_cpu(n->u.isp24.nport_handle);
"loop_id %d)\n", vha->host_no, sess, sess->port_name,
mcmd, loop_id);
- lun = a->u.isp24.fcp_cmnd.lun;
- unpacked_lun = scsilun_to_int((struct scsi_lun *)&lun);
-
- return qlt_issue_task_mgmt(sess, unpacked_lun, mcmd,
- iocb, QLA24XX_MGMT_SEND_NACK);
+ return qlt_issue_task_mgmt(sess, 0, mcmd, iocb, QLA24XX_MGMT_SEND_NACK);
}
/* ha->tgt.sess_lock supposed to be held on entry */
pkt->entry_type = NOTIFY_ACK_TYPE;
pkt->entry_count = 1;
- pkt->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK;
+ pkt->handle = QLA_TGT_SKIP_HANDLE;
nack = (struct nack_to_isp *)pkt;
nack->ox_id = ntfy->ox_id;
#if 0 /* Todo */
if (rc == -ENOMEM)
qlt_alloc_qfull_cmd(vha, imm, 0, 0);
+#else
+ if (rc) {
+ }
#endif
goto done;
}
if (!vha->flags.online)
return;
- while (ha->tgt.atio_ring_ptr->signature != ATIO_PROCESSED) {
+ while ((ha->tgt.atio_ring_ptr->signature != ATIO_PROCESSED) ||
+ fcpcmd_is_corrupted(ha->tgt.atio_ring_ptr)) {
pkt = (struct atio_from_isp *)ha->tgt.atio_ring_ptr;
cnt = pkt->u.raw.entry_count;
- qlt_24xx_atio_pkt_all_vps(vha, (struct atio_from_isp *)pkt,
- ha_locked);
+ if (unlikely(fcpcmd_is_corrupted(ha->tgt.atio_ring_ptr))) {
+ /*
+ * This packet is corrupted. The header + payload
+ * can not be trusted. There is no point in passing
+ * it further up.
+ */
+ ql_log(ql_log_warn, vha, 0xffff,
+ "corrupted fcp frame SID[%3phN] OXID[%04x] EXCG[%x] %64phN\n",
+ pkt->u.isp24.fcp_hdr.s_id,
+ be16_to_cpu(pkt->u.isp24.fcp_hdr.ox_id),
+ le32_to_cpu(pkt->u.isp24.exchange_addr), pkt);
+
+ adjust_corrupted_atio(pkt);
+ qlt_send_term_exchange(vha, NULL, pkt, ha_locked, 0);
+ } else {
+ qlt_24xx_atio_pkt_all_vps(vha,
+ (struct atio_from_isp *)pkt, ha_locked);
+ }
for (i = 0; i < cnt; i++) {
ha->tgt.atio_ring_index++;
/* Disable Full Login after LIP */
nv->host_p &= cpu_to_le32(~BIT_10);
+
+ /*
+ * clear BIT 15 explicitly as we have seen at least
+ * a couple of instances where this was set and this
+ * was causing the firmware to not be initialized.
+ */
+ nv->firmware_options_1 &= cpu_to_le32(~BIT_15);
/* Enable target PRLI control */
nv->firmware_options_2 |= cpu_to_le32(BIT_14);
} else {
return;
}
- /* out-of-order frames reassembly */
- nv->firmware_options_3 |= BIT_6|BIT_9;
-
if (ha->tgt.enable_class_2) {
if (vha->flags.init_done)
fc_host_supported_classes(vha->host) =
/* Disable ini mode, if requested */
if (!qla_ini_mode_enabled(vha))
nv->firmware_options_1 |= cpu_to_le32(BIT_5);
-
/* Disable Full Login after LIP */
nv->firmware_options_1 &= cpu_to_le32(~BIT_13);
/* Enable initial LIP */
nv->firmware_options_1 &= cpu_to_le32(~BIT_9);
+ /*
+ * clear BIT 15 explicitly as we have seen at
+ * least a couple of instances where this was set
+ * and this was causing the firmware to not be
+ * initialized.
+ */
+ nv->firmware_options_1 &= cpu_to_le32(~BIT_15);
if (ql2xtgt_tape_enable)
/* Enable FC tape support */
nv->firmware_options_2 |= cpu_to_le32(BIT_12);
return;
}
- /* out-of-order frames reassembly */
- nv->firmware_options_3 |= BIT_6|BIT_9;
-
if (ha->tgt.enable_class_2) {
if (vha->flags.init_done)
fc_host_supported_classes(vha->host) =
struct {
uint8_t entry_type; /* Entry type. */
uint8_t entry_count; /* Entry count. */
- uint8_t data[58];
+ __le16 attr_n_length;
+#define FCP_CMD_LENGTH_MASK 0x0fff
+#define FCP_CMD_LENGTH_MIN 0x38
+ uint8_t data[56];
uint32_t signature;
#define ATIO_PROCESSED 0xDEADDEAD /* Signature */
} raw;
} u;
} __packed;
+static inline int fcpcmd_is_corrupted(struct atio *atio)
+{
+ if (atio->entry_type == ATIO_TYPE7 &&
+ (le16_to_cpu(atio->attr_n_length & FCP_CMD_LENGTH_MASK) <
+ FCP_CMD_LENGTH_MIN))
+ return 1;
+ else
+ return 0;
+}
+
+/* adjust corrupted atio so we won't trip over the same entry again. */
+static inline void adjust_corrupted_atio(struct atio_from_isp *atio)
+{
+ atio->u.raw.attr_n_length = cpu_to_le16(FCP_CMD_LENGTH_MIN);
+ atio->u.isp24.fcp_cmnd.add_cdb_len = 0;
+}
+
#define CTIO_TYPE7 0x12 /* Continue target I/O entry (for 24xx) */
/*
count++;
}
}
+ } else if (QLA_TGT_MODE_ENABLED() &&
+ ent->t263.queue_type == T263_QUEUE_TYPE_ATIO) {
+ struct qla_hw_data *ha = vha->hw;
+ struct atio *atr = ha->tgt.atio_ring;
+
+ if (atr || !buf) {
+ length = ha->tgt.atio_q_length;
+ qla27xx_insert16(0, buf, len);
+ qla27xx_insert16(length, buf, len);
+ qla27xx_insertbuf(atr, length * sizeof(*atr), buf, len);
+ count++;
+ }
} else {
ql_dbg(ql_dbg_misc, vha, 0xd026,
"%s: unknown queue %x\n", __func__, ent->t263.queue_type);
count++;
}
}
+ } else if (QLA_TGT_MODE_ENABLED() &&
+ ent->t274.queue_type == T274_QUEUE_TYPE_ATIO_SHAD) {
+ struct qla_hw_data *ha = vha->hw;
+ struct atio *atr = ha->tgt.atio_ring_ptr;
+
+ if (atr || !buf) {
+ qla27xx_insert16(0, buf, len);
+ qla27xx_insert16(1, buf, len);
+ qla27xx_insert32(ha->tgt.atio_q_in ?
+ readl(ha->tgt.atio_q_in) : 0, buf, len);
+ count++;
+ }
} else {
ql_dbg(ql_dbg_misc, vha, 0xd02f,
"%s: unknown queue %x\n", __func__, ent->t274.queue_type);
{
return sprintf(page,
"TCM QLOGIC QLA2XXX NPIV capable fabric module %s on %s/%s on "
- UTS_RELEASE"\n", TCM_QLA2XXX_VERSION, utsname()->sysname,
+ UTS_RELEASE"\n", QLA2XXX_VERSION, utsname()->sysname,
utsname()->machine);
}
int ret;
pr_debug("TCM QLOGIC QLA2XXX fabric module %s on %s/%s on "
- UTS_RELEASE"\n", TCM_QLA2XXX_VERSION, utsname()->sysname,
+ UTS_RELEASE"\n", QLA2XXX_VERSION, utsname()->sysname,
utsname()->machine);
ret = target_register_template(&tcm_qla2xxx_ops);
#include <target/target_core_base.h>
#include <linux/btree.h>
-#define TCM_QLA2XXX_VERSION "v0.1"
/* length of ASCII WWPNs including pad */
#define TCM_QLA2XXX_NAMELEN 32
/*
count = blk_rq_map_sg(req->q, req, sdb->table.sgl);
BUG_ON(count > sdb->table.nents);
sdb->table.nents = count;
- sdb->length = blk_rq_bytes(req);
+ sdb->length = blk_rq_payload_bytes(req);
return BLKPREP_OK;
}
* request queue.
*/
if (q->mq_ops) {
- blk_mq_stop_hw_queues(q);
+ blk_mq_quiesce_queue(q);
} else {
spin_lock_irqsave(q->queue_lock, flags);
blk_stop_queue(q);
cmd->allowed = SD_MAX_RETRIES;
/*
- * For WRITE_SAME the data transferred in the DATA IN buffer is
+ * For WRITE SAME the data transferred via the DATA OUT buffer is
* different from the amount of data actually written to the target.
*
- * We set up __data_len to the amount of data transferred from the
- * DATA IN buffer so that blk_rq_map_sg set up the proper S/G list
+ * We set up __data_len to the amount of data transferred via the
+ * DATA OUT buffer so that blk_rq_map_sg sets up the proper S/G list
* to transfer a single sector of data first, but then reset it to
* the amount of data to be written right after so that the I/O path
* knows how much to actually write.
if (sdp->broken_fua) {
sd_first_printk(KERN_NOTICE, sdkp, "Disabling FUA\n");
sdkp->DPOFUA = 0;
- } else if (sdkp->DPOFUA && !sdkp->device->use_10_for_rw) {
+ } else if (sdkp->DPOFUA && !sdkp->device->use_10_for_rw &&
+ !sdkp->device->use_16_for_rw) {
sd_first_printk(KERN_NOTICE, sdkp,
"Uses READ/WRITE(6), disabling FUA\n");
sdkp->DPOFUA = 0;
queue_flag_clear_unlocked(QUEUE_FLAG_ADD_RANDOM, q);
}
- sdkp->zoned = (buffer[8] >> 4) & 3;
- if (sdkp->zoned == 1)
- q->limits.zoned = BLK_ZONED_HA;
- else if (sdkp->device->type == TYPE_ZBC)
+ if (sdkp->device->type == TYPE_ZBC) {
+ /* Host-managed */
q->limits.zoned = BLK_ZONED_HM;
- else
- q->limits.zoned = BLK_ZONED_NONE;
+ } else {
+ sdkp->zoned = (buffer[8] >> 4) & 3;
+ if (sdkp->zoned == 1)
+ /* Host-aware */
+ q->limits.zoned = BLK_ZONED_HA;
+ else
+ /*
+ * Treat drive-managed devices as
+ * regular block devices.
+ */
+ q->limits.zoned = BLK_ZONED_NONE;
+ }
if (blk_queue_is_zoned(q) && sdkp->first_scan)
sd_printk(KERN_NOTICE, sdkp, "Host-%s zoned block device\n",
q->limits.zoned == BLK_ZONED_HM ? "managed" : "aware");
ses_enclosure_data_process(edev, to_scsi_device(edev->edev.parent), 0);
- if (scsi_is_sas_rphy(&sdev->sdev_gendev))
+ if (scsi_is_sas_rphy(sdev->sdev_target->dev.parent))
efd.addr = sas_get_address(sdev);
if (efd.addr) {
if (!pool) {
SNIC_HOST_ERR(shost, "dflt sgl pool creation failed\n");
+ ret = -ENOMEM;
goto err_free_res;
}
if (!pool) {
SNIC_HOST_ERR(shost, "max sgl pool creation failed\n");
+ ret = -ENOMEM;
goto err_free_dflt_sgl_pool;
}
if (!pool) {
SNIC_HOST_ERR(shost, "snic tmreq info pool creation failed.\n");
+ ret = -ENOMEM;
goto err_free_max_sgl_pool;
}
{
struct Scsi_Host *shost = virtio_scsi_host(vscsi->vdev);
struct virtio_scsi_cmd *cmd = scsi_cmd_priv(sc);
+ unsigned long flags;
int req_size;
+ int ret;
BUG_ON(scsi_sg_count(sc) > shost->sg_tablesize);
req_size = sizeof(cmd->req.cmd);
}
- if (virtscsi_kick_cmd(req_vq, cmd, req_size, sizeof(cmd->resp.cmd)) != 0)
+ ret = virtscsi_kick_cmd(req_vq, cmd, req_size, sizeof(cmd->resp.cmd));
+ if (ret == -EIO) {
+ cmd->resp.cmd.response = VIRTIO_SCSI_S_BAD_TARGET;
+ spin_lock_irqsave(&req_vq->vq_lock, flags);
+ virtscsi_complete_cmd(vscsi, cmd);
+ spin_unlock_irqrestore(&req_vq->vq_lock, flags);
+ } else if (ret != 0) {
return SCSI_MLQUEUE_HOST_BUSY;
+ }
return 0;
}
if (IS_ERR(task)) {
dev_err(dev, "can't create rproc_boot thread\n");
+ ret = PTR_ERR(task);
goto err_put_rproc;
}
config SPI_FSL_DSPI
tristate "Freescale DSPI controller"
select REGMAP_MMIO
+ depends on HAS_DMA
depends on SOC_VF610 || SOC_LS1021A || ARCH_LAYERSCAPE || COMPILE_TEST
help
This enables support for the Freescale DSPI controller in master
struct spi_master *master;
struct a3700_spi *spi;
u32 num_cs = 0;
- int ret = 0;
+ int irq, ret = 0;
master = spi_alloc_master(dev, sizeof(*spi));
if (!master) {
master->unprepare_message = a3700_spi_unprepare_message;
master->set_cs = a3700_spi_set_cs;
master->flags = SPI_MASTER_HALF_DUPLEX;
- master->mode_bits |= (SPI_RX_DUAL | SPI_RX_DUAL |
+ master->mode_bits |= (SPI_RX_DUAL | SPI_TX_DUAL |
SPI_RX_QUAD | SPI_TX_QUAD);
platform_set_drvdata(pdev, master);
goto error;
}
- spi->irq = platform_get_irq(pdev, 0);
- if (spi->irq < 0) {
- dev_err(dev, "could not get irq: %d\n", spi->irq);
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dev, "could not get irq: %d\n", irq);
ret = -ENXIO;
goto error;
}
+ spi->irq = irq;
init_completion(&spi->done);
SPI_ENGINE_VERSION_MAJOR(version),
SPI_ENGINE_VERSION_MINOR(version),
SPI_ENGINE_VERSION_PATCH(version));
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_put_master;
}
spi_engine->clk = devm_clk_get(&pdev->dev, "s_axi_aclk");
buf = t->rx_buf;
t->rx_dma = dma_map_single(&spi->dev, buf,
t->len, DMA_FROM_DEVICE);
- if (!t->rx_dma) {
+ if (dma_mapping_error(&spi->dev, !t->rx_dma)) {
ret = -EFAULT;
goto err_rx_map;
}
buf = (void *)t->tx_buf;
t->tx_dma = dma_map_single(&spi->dev, buf,
t->len, DMA_TO_DEVICE);
- if (!t->tx_dma) {
+ if (dma_mapping_error(&spi->dev, t->tx_dma)) {
ret = -EFAULT;
goto err_tx_map;
}
static void mid_spi_dma_stop(struct dw_spi *dws)
{
if (test_bit(TX_BUSY, &dws->dma_chan_busy)) {
- dmaengine_terminate_all(dws->txchan);
+ dmaengine_terminate_sync(dws->txchan);
clear_bit(TX_BUSY, &dws->dma_chan_busy);
}
if (test_bit(RX_BUSY, &dws->dma_chan_busy)) {
- dmaengine_terminate_all(dws->rxchan);
+ dmaengine_terminate_sync(dws->rxchan);
clear_bit(RX_BUSY, &dws->dma_chan_busy);
}
}
static int dw_spi_debugfs_init(struct dw_spi *dws)
{
- dws->debugfs = debugfs_create_dir("dw_spi", NULL);
+ char name[128];
+
+ snprintf(name, 128, "dw_spi-%s", dev_name(&dws->master->dev));
+ dws->debugfs = debugfs_create_dir(name, NULL);
if (!dws->debugfs)
return -ENOMEM;
pxa2xx_spi_write(drv_data, SSCR1, tmp);
tmp = SSCR0_SCR(2) | SSCR0_Motorola | SSCR0_DataSize(8);
pxa2xx_spi_write(drv_data, SSCR0, tmp);
+ break;
default:
tmp = SSCR1_RxTresh(RX_THRESH_DFLT) |
SSCR1_TxTresh(TX_THRESH_DFLT);
};
static const struct of_device_id sh_msiof_match[] = {
- { .compatible = "renesas,sh-msiof", .data = &sh_data },
{ .compatible = "renesas,sh-mobile-msiof", .data = &sh_data },
{ .compatible = "renesas,msiof-r8a7790", .data = &r8a779x_data },
{ .compatible = "renesas,msiof-r8a7791", .data = &r8a779x_data },
{ .compatible = "renesas,msiof-r8a7792", .data = &r8a779x_data },
{ .compatible = "renesas,msiof-r8a7793", .data = &r8a779x_data },
{ .compatible = "renesas,msiof-r8a7794", .data = &r8a779x_data },
+ { .compatible = "renesas,rcar-gen2-msiof", .data = &r8a779x_data },
{ .compatible = "renesas,msiof-r8a7796", .data = &r8a779x_data },
+ { .compatible = "renesas,rcar-gen3-msiof", .data = &r8a779x_data },
+ { .compatible = "renesas,sh-msiof", .data = &sh_data }, /* Deprecated */
{},
};
MODULE_DEVICE_TABLE(of, sh_msiof_match);
source "drivers/staging/most/Kconfig"
-source "drivers/staging/i4l/Kconfig"
-
source "drivers/staging/ks7010/Kconfig"
source "drivers/staging/greybus/Kconfig"
source "drivers/staging/vc04_services/Kconfig"
+source "drivers/staging/bcm2835-audio/Kconfig"
+
endif # STAGING
obj-$(CONFIG_FSL_MC_BUS) += fsl-mc/
obj-$(CONFIG_WILC1000) += wilc1000/
obj-$(CONFIG_MOST) += most/
-obj-$(CONFIG_ISDN_I4L) += i4l/
obj-$(CONFIG_KS7010) += ks7010/
obj-$(CONFIG_GREYBUS) += greybus/
obj-$(CONFIG_BCM2835_VCHIQ) += vc04_services/
+obj-$(CONFIG_SND_BCM2835) += bcm2835-audio/
+
struct ion_handle *handle;
mutex_lock(&client->lock);
- handle = ion_handle_get_by_id_nolock(client, data.handle.handle);
+ handle = ion_handle_get_by_id_nolock(client,
+ data.handle.handle);
if (IS_ERR(handle)) {
mutex_unlock(&client->lock);
return PTR_ERR(handle);
#include "ion.h"
#include "ion_priv.h"
-#define ION_CMA_ALLOCATE_FAILED -1
-
struct ion_cma_heap {
struct ion_heap heap;
struct device *dev;
info = kzalloc(sizeof(struct ion_cma_buffer_info), GFP_KERNEL);
if (!info)
- return ION_CMA_ALLOCATE_FAILED;
+ return -ENOMEM;
info->cpu_addr = dma_alloc_coherent(dev, len, &(info->handle),
GFP_HIGHUSER | __GFP_ZERO);
dma_free_coherent(dev, len, info->cpu_addr, info->handle);
err:
kfree(info);
- return ION_CMA_ALLOCATE_FAILED;
+ return -ENOMEM;
}
static void ion_cma_free(struct ion_buffer *buffer)
static void rmem_ion_device_release(struct reserved_mem *rmem,
struct device *dev)
{
- return;
}
static const struct reserved_mem_ops rmem_dma_ops = {
* handle, used for debugging
* @pid: pid of last client to reference this buffer in a
* handle, used for debugging
-*/
+ */
struct ion_buffer {
struct kref ref;
union {
* some helpers for common operations on buffers using the sg_table
* and vaddr fields
*/
-void *ion_heap_map_kernel(struct ion_heap *, struct ion_buffer *);
-void ion_heap_unmap_kernel(struct ion_heap *, struct ion_buffer *);
-int ion_heap_map_user(struct ion_heap *, struct ion_buffer *,
- struct vm_area_struct *);
+void *ion_heap_map_kernel(struct ion_heap *heap, struct ion_buffer *buffer);
+void ion_heap_unmap_kernel(struct ion_heap *heap, struct ion_buffer *buffer);
+int ion_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer,
+ struct vm_area_struct *vma);
int ion_heap_buffer_zero(struct ion_buffer *buffer);
int ion_heap_pages_zero(struct page *page, size_t size, pgprot_t pgprot);
* heaps as appropriate.
*/
-struct ion_heap *ion_heap_create(struct ion_platform_heap *);
-void ion_heap_destroy(struct ion_heap *);
-struct ion_heap *ion_system_heap_create(struct ion_platform_heap *);
-void ion_system_heap_destroy(struct ion_heap *);
+struct ion_heap *ion_heap_create(struct ion_platform_heap *heap_data);
+void ion_heap_destroy(struct ion_heap *heap);
+struct ion_heap *ion_system_heap_create(struct ion_platform_heap *unused);
+void ion_system_heap_destroy(struct ion_heap *heap);
-struct ion_heap *ion_system_contig_heap_create(struct ion_platform_heap *);
-void ion_system_contig_heap_destroy(struct ion_heap *);
+struct ion_heap *ion_system_contig_heap_create(struct ion_platform_heap *heap);
+void ion_system_contig_heap_destroy(struct ion_heap *heap);
-struct ion_heap *ion_carveout_heap_create(struct ion_platform_heap *);
-void ion_carveout_heap_destroy(struct ion_heap *);
+struct ion_heap *ion_carveout_heap_create(struct ion_platform_heap *heap_data);
+void ion_carveout_heap_destroy(struct ion_heap *heap);
-struct ion_heap *ion_chunk_heap_create(struct ion_platform_heap *);
-void ion_chunk_heap_destroy(struct ion_heap *);
-struct ion_heap *ion_cma_heap_create(struct ion_platform_heap *);
-void ion_cma_heap_destroy(struct ion_heap *);
+struct ion_heap *ion_chunk_heap_create(struct ion_platform_heap *heap_data);
+void ion_chunk_heap_destroy(struct ion_heap *heap);
+struct ion_heap *ion_cma_heap_create(struct ion_platform_heap *data);
+void ion_cma_heap_destroy(struct ion_heap *heap);
/**
* functions for creating and destroying a heap pool -- allows you
struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order,
bool cached);
-void ion_page_pool_destroy(struct ion_page_pool *);
-struct page *ion_page_pool_alloc(struct ion_page_pool *);
-void ion_page_pool_free(struct ion_page_pool *, struct page *);
+void ion_page_pool_destroy(struct ion_page_pool *pool);
+struct page *ion_page_pool_alloc(struct ion_page_pool *pool);
+void ion_page_pool_free(struct ion_page_pool *pool, struct page *page);
/** ion_page_pool_shrink - shrinks the size of the memory cached in the pool
* @pool: the pool
--- /dev/null
+config SND_BCM2835
+ tristate "BCM2835 ALSA driver"
+ depends on ARCH_BCM2835 && BCM2835_VCHIQ && SND
+ select SND_PCM
+ help
+ Say Y or M if you want to support BCM2835 Alsa pcm card driver
+
--- /dev/null
+obj-$(CONFIG_SND_BCM2835) += snd-bcm2835.o
+snd-bcm2835-objs := bcm2835.o bcm2835-ctl.o bcm2835-pcm.o bcm2835-vchiq.o
+
+ccflags-y += -Idrivers/staging/vc04_services -D__VCCOREVER__=0x04000000
+
--- /dev/null
+*****************************************************************************
+* *
+* TODO: BCM2835-AUDIO *
+* *
+*****************************************************************************
+
+
+1) Document the device tree node
+
+The downstream tree(the tree that the driver was imported from) at
+http://www.github.com/raspberrypi/linux uses this node:
+
+audio: audio {
+ compatible = "brcm,bcm2835-audio";
+ brcm,pwm-channels = <8>;
+};
+
+Since the driver requires the use of VCHIQ, it may be useful to have a link
+in the device tree to the VCHIQ driver.
+
+2) Gracefully handle the case where VCHIQ is missing from the device tree or
+it has not been initialized yet.
+
+3) Review error handling and remove duplicate code.
+
+4) Cleanup the logging mechanism. The driver should probably be using the
+standard kernel logging mechanisms such as dev_info, dev_dbg, and friends.
+
+5) Fix the remaining checkpatch.pl errors and warnings.
--- /dev/null
+/*****************************************************************************
+ * Copyright 2011 Broadcom Corporation. All rights reserved.
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2, available at
+ * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+ *
+ * Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a
+ * license other than the GPL, without Broadcom's express prior written
+ * consent.
+ *****************************************************************************/
+
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/moduleparam.h>
+#include <linux/sched.h>
+
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/rawmidi.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/asoundef.h>
+
+#include "bcm2835.h"
+
+/* volume maximum and minimum in terms of 0.01dB */
+#define CTRL_VOL_MAX 400
+#define CTRL_VOL_MIN -10239 /* originally -10240 */
+
+static int snd_bcm2835_ctl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ audio_info(" ... IN\n");
+ if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = CTRL_VOL_MIN;
+ uinfo->value.integer.max = CTRL_VOL_MAX; /* 2303 */
+ } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = AUDIO_DEST_MAX - 1;
+ }
+ audio_info(" ... OUT\n");
+ return 0;
+}
+
+/* toggles mute on or off depending on the value of nmute, and returns
+ * 1 if the mute value was changed, otherwise 0
+ */
+static int toggle_mute(struct bcm2835_chip *chip, int nmute)
+{
+ /* if settings are ok, just return 0 */
+ if (chip->mute == nmute)
+ return 0;
+
+ /* if the sound is muted then we need to unmute */
+ if (chip->mute == CTRL_VOL_MUTE) {
+ chip->volume = chip->old_volume; /* copy the old volume back */
+ audio_info("Unmuting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
+ } else /* otherwise we mute */ {
+ chip->old_volume = chip->volume;
+ chip->volume = 26214; /* set volume to minimum level AKA mute */
+ audio_info("Muting, old_volume = %d, volume = %d ...\n", chip->old_volume, chip->volume);
+ }
+
+ chip->mute = nmute;
+ return 1;
+}
+
+static int snd_bcm2835_ctl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
+
+ if (mutex_lock_interruptible(&chip->audio_mutex))
+ return -EINTR;
+
+ BUG_ON(!chip && !(chip->avail_substreams & AVAIL_SUBSTREAMS_MASK));
+
+ if (kcontrol->private_value == PCM_PLAYBACK_VOLUME)
+ ucontrol->value.integer.value[0] = chip2alsa(chip->volume);
+ else if (kcontrol->private_value == PCM_PLAYBACK_MUTE)
+ ucontrol->value.integer.value[0] = chip->mute;
+ else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE)
+ ucontrol->value.integer.value[0] = chip->dest;
+
+ mutex_unlock(&chip->audio_mutex);
+ return 0;
+}
+
+static int snd_bcm2835_ctl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
+ int changed = 0;
+
+ if (mutex_lock_interruptible(&chip->audio_mutex))
+ return -EINTR;
+
+ if (kcontrol->private_value == PCM_PLAYBACK_VOLUME) {
+ audio_info("Volume change attempted.. volume = %d new_volume = %d\n", chip->volume, (int) ucontrol->value.integer.value[0]);
+ if (chip->mute == CTRL_VOL_MUTE) {
+ /* changed = toggle_mute(chip, CTRL_VOL_UNMUTE); */
+ changed = 1; /* should return 0 to signify no change but the mixer takes this as the opposite sign (no idea why) */
+ goto unlock;
+ }
+ if (changed
+ || (ucontrol->value.integer.value[0] != chip2alsa(chip->volume))) {
+
+ chip->volume = alsa2chip(ucontrol->value.integer.value[0]);
+ changed = 1;
+ }
+
+ } else if (kcontrol->private_value == PCM_PLAYBACK_MUTE) {
+ /* Now implemented */
+ audio_info(" Mute attempted\n");
+ changed = toggle_mute(chip, ucontrol->value.integer.value[0]);
+
+ } else if (kcontrol->private_value == PCM_PLAYBACK_DEVICE) {
+ if (ucontrol->value.integer.value[0] != chip->dest) {
+ chip->dest = ucontrol->value.integer.value[0];
+ changed = 1;
+ }
+ }
+
+ if (changed) {
+ if (bcm2835_audio_set_ctls(chip))
+ printk(KERN_ERR "Failed to set ALSA controls..\n");
+ }
+
+unlock:
+ mutex_unlock(&chip->audio_mutex);
+ return changed;
+}
+
+static DECLARE_TLV_DB_SCALE(snd_bcm2835_db_scale, CTRL_VOL_MIN, 1, 1);
+
+static struct snd_kcontrol_new snd_bcm2835_ctl[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "PCM Playback Volume",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+ .private_value = PCM_PLAYBACK_VOLUME,
+ .info = snd_bcm2835_ctl_info,
+ .get = snd_bcm2835_ctl_get,
+ .put = snd_bcm2835_ctl_put,
+ .count = 1,
+ .tlv = {.p = snd_bcm2835_db_scale}
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "PCM Playback Switch",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .private_value = PCM_PLAYBACK_MUTE,
+ .info = snd_bcm2835_ctl_info,
+ .get = snd_bcm2835_ctl_get,
+ .put = snd_bcm2835_ctl_put,
+ .count = 1,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "PCM Playback Route",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .private_value = PCM_PLAYBACK_DEVICE,
+ .info = snd_bcm2835_ctl_info,
+ .get = snd_bcm2835_ctl_get,
+ .put = snd_bcm2835_ctl_put,
+ .count = 1,
+ },
+};
+
+static int snd_bcm2835_spdif_default_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+ uinfo->count = 1;
+ return 0;
+}
+
+static int snd_bcm2835_spdif_default_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
+ int i;
+
+ if (mutex_lock_interruptible(&chip->audio_mutex))
+ return -EINTR;
+
+ for (i = 0; i < 4; i++)
+ ucontrol->value.iec958.status[i] =
+ (chip->spdif_status >> (i * 8)) && 0xff;
+
+ mutex_unlock(&chip->audio_mutex);
+ return 0;
+}
+
+static int snd_bcm2835_spdif_default_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
+ unsigned int val = 0;
+ int i, change;
+
+ if (mutex_lock_interruptible(&chip->audio_mutex))
+ return -EINTR;
+
+ for (i = 0; i < 4; i++)
+ val |= (unsigned int) ucontrol->value.iec958.status[i] << (i * 8);
+
+ change = val != chip->spdif_status;
+ chip->spdif_status = val;
+
+ mutex_unlock(&chip->audio_mutex);
+ return change;
+}
+
+static int snd_bcm2835_spdif_mask_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+ uinfo->count = 1;
+ return 0;
+}
+
+static int snd_bcm2835_spdif_mask_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ /* bcm2835 supports only consumer mode and sets all other format flags
+ * automatically. So the only thing left is signalling non-audio
+ * content */
+ ucontrol->value.iec958.status[0] = IEC958_AES0_NONAUDIO;
+ return 0;
+}
+
+static int snd_bcm2835_spdif_stream_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+ uinfo->count = 1;
+ return 0;
+}
+
+static int snd_bcm2835_spdif_stream_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
+ int i;
+
+ if (mutex_lock_interruptible(&chip->audio_mutex))
+ return -EINTR;
+
+ for (i = 0; i < 4; i++)
+ ucontrol->value.iec958.status[i] =
+ (chip->spdif_status >> (i * 8)) & 0xff;
+
+ mutex_unlock(&chip->audio_mutex);
+ return 0;
+}
+
+static int snd_bcm2835_spdif_stream_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct bcm2835_chip *chip = snd_kcontrol_chip(kcontrol);
+ unsigned int val = 0;
+ int i, change;
+
+ if (mutex_lock_interruptible(&chip->audio_mutex))
+ return -EINTR;
+
+ for (i = 0; i < 4; i++)
+ val |= (unsigned int) ucontrol->value.iec958.status[i] << (i * 8);
+ change = val != chip->spdif_status;
+ chip->spdif_status = val;
+
+ mutex_unlock(&chip->audio_mutex);
+ return change;
+}
+
+static struct snd_kcontrol_new snd_bcm2835_spdif[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
+ .info = snd_bcm2835_spdif_default_info,
+ .get = snd_bcm2835_spdif_default_get,
+ .put = snd_bcm2835_spdif_default_put
+ },
+ {
+ .access = SNDRV_CTL_ELEM_ACCESS_READ,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
+ .info = snd_bcm2835_spdif_mask_info,
+ .get = snd_bcm2835_spdif_mask_get,
+ },
+ {
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_INACTIVE,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM),
+ .info = snd_bcm2835_spdif_stream_info,
+ .get = snd_bcm2835_spdif_stream_get,
+ .put = snd_bcm2835_spdif_stream_put,
+ },
+};
+
+int snd_bcm2835_new_ctl(struct bcm2835_chip *chip)
+{
+ int err;
+ unsigned int idx;
+
+ strcpy(chip->card->mixername, "Broadcom Mixer");
+ for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_ctl); idx++) {
+ err = snd_ctl_add(chip->card,
+ snd_ctl_new1(&snd_bcm2835_ctl[idx], chip));
+ if (err < 0)
+ return err;
+ }
+ for (idx = 0; idx < ARRAY_SIZE(snd_bcm2835_spdif); idx++) {
+ err = snd_ctl_add(chip->card,
+ snd_ctl_new1(&snd_bcm2835_spdif[idx], chip));
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
--- /dev/null
+/*****************************************************************************
+ * Copyright 2011 Broadcom Corporation. All rights reserved.
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2, available at
+ * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+ *
+ * Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a
+ * license other than the GPL, without Broadcom's express prior written
+ * consent.
+ *****************************************************************************/
+
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+
+#include <sound/asoundef.h>
+
+#include "bcm2835.h"
+
+/* hardware definition */
+static struct snd_pcm_hardware snd_bcm2835_playback_hw = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
+ .formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ .channels_min = 1,
+ .channels_max = 2,
+ .buffer_bytes_max = 128 * 1024,
+ .period_bytes_min = 1 * 1024,
+ .period_bytes_max = 128 * 1024,
+ .periods_min = 1,
+ .periods_max = 128,
+};
+
+static struct snd_pcm_hardware snd_bcm2835_playback_spdif_hw = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000,
+ .rate_min = 44100,
+ .rate_max = 48000,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 128 * 1024,
+ .period_bytes_min = 1 * 1024,
+ .period_bytes_max = 128 * 1024,
+ .periods_min = 1,
+ .periods_max = 128,
+};
+
+static void snd_bcm2835_playback_free(struct snd_pcm_runtime *runtime)
+{
+ audio_info("Freeing up alsa stream here ..\n");
+ if (runtime->private_data)
+ kfree(runtime->private_data);
+ runtime->private_data = NULL;
+}
+
+void bcm2835_playback_fifo(struct bcm2835_alsa_stream *alsa_stream)
+{
+ unsigned int consumed = 0;
+ int new_period = 0;
+
+ audio_info(" .. IN\n");
+
+ audio_info("alsa_stream=%p substream=%p\n", alsa_stream,
+ alsa_stream ? alsa_stream->substream : 0);
+
+ if (alsa_stream->open)
+ consumed = bcm2835_audio_retrieve_buffers(alsa_stream);
+
+ /* We get called only if playback was triggered, So, the number of buffers we retrieve in
+ * each iteration are the buffers that have been played out already
+ */
+
+ if (alsa_stream->period_size) {
+ if ((alsa_stream->pos / alsa_stream->period_size) !=
+ ((alsa_stream->pos + consumed) / alsa_stream->period_size))
+ new_period = 1;
+ }
+ audio_debug("updating pos cur: %d + %d max:%d period_bytes:%d, hw_ptr: %d new_period:%d\n",
+ alsa_stream->pos,
+ consumed,
+ alsa_stream->buffer_size,
+ (int) (alsa_stream->period_size * alsa_stream->substream->runtime->periods),
+ frames_to_bytes(alsa_stream->substream->runtime, alsa_stream->substream->runtime->status->hw_ptr),
+ new_period);
+ if (alsa_stream->buffer_size) {
+ alsa_stream->pos += consumed &~(1 << 30);
+ alsa_stream->pos %= alsa_stream->buffer_size;
+ }
+
+ if (alsa_stream->substream) {
+ if (new_period)
+ snd_pcm_period_elapsed(alsa_stream->substream);
+ } else {
+ audio_warning(" unexpected NULL substream\n");
+ }
+ audio_info(" .. OUT\n");
+}
+
+/* open callback */
+static int snd_bcm2835_playback_open_generic(
+ struct snd_pcm_substream *substream, int spdif)
+{
+ struct bcm2835_chip *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct bcm2835_alsa_stream *alsa_stream;
+ int idx;
+ int err;
+
+ audio_info(" .. IN (%d)\n", substream->number);
+
+ if (mutex_lock_interruptible(&chip->audio_mutex)) {
+ audio_error("Interrupted whilst waiting for lock\n");
+ return -EINTR;
+ }
+ audio_info("Alsa open (%d)\n", substream->number);
+ idx = substream->number;
+
+ if (spdif && chip->opened) {
+ err = -EBUSY;
+ goto out;
+ } else if (!spdif && (chip->opened & (1 << idx))) {
+ err = -EBUSY;
+ goto out;
+ }
+ if (idx >= MAX_SUBSTREAMS) {
+ audio_error
+ ("substream(%d) device doesn't exist max(%d) substreams allowed\n",
+ idx, MAX_SUBSTREAMS);
+ err = -ENODEV;
+ goto out;
+ }
+
+ /* Check if we are ready */
+ if (!(chip->avail_substreams & (1 << idx))) {
+ /* We are not ready yet */
+ audio_error("substream(%d) device is not ready yet\n", idx);
+ err = -EAGAIN;
+ goto out;
+ }
+
+ alsa_stream = kzalloc(sizeof(*alsa_stream), GFP_KERNEL);
+ if (!alsa_stream) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ /* Initialise alsa_stream */
+ alsa_stream->chip = chip;
+ alsa_stream->substream = substream;
+ alsa_stream->idx = idx;
+
+ sema_init(&alsa_stream->buffers_update_sem, 0);
+ sema_init(&alsa_stream->control_sem, 0);
+ spin_lock_init(&alsa_stream->lock);
+
+ err = bcm2835_audio_open(alsa_stream);
+ if (err) {
+ kfree(alsa_stream);
+ goto out;
+ }
+ runtime->private_data = alsa_stream;
+ runtime->private_free = snd_bcm2835_playback_free;
+ if (spdif) {
+ runtime->hw = snd_bcm2835_playback_spdif_hw;
+ } else {
+ /* clear spdif status, as we are not in spdif mode */
+ chip->spdif_status = 0;
+ runtime->hw = snd_bcm2835_playback_hw;
+ }
+ /* minimum 16 bytes alignment (for vchiq bulk transfers) */
+ snd_pcm_hw_constraint_step(runtime,
+ 0,
+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+ 16);
+
+ chip->alsa_stream[idx] = alsa_stream;
+
+ chip->opened |= (1 << idx);
+ alsa_stream->open = 1;
+ alsa_stream->draining = 1;
+
+out:
+ mutex_unlock(&chip->audio_mutex);
+
+ audio_info(" .. OUT =%d\n", err);
+
+ return err;
+}
+
+static int snd_bcm2835_playback_open(struct snd_pcm_substream *substream)
+{
+ return snd_bcm2835_playback_open_generic(substream, 0);
+}
+
+static int snd_bcm2835_playback_spdif_open(struct snd_pcm_substream *substream)
+{
+ return snd_bcm2835_playback_open_generic(substream, 1);
+}
+
+/* close callback */
+static int snd_bcm2835_playback_close(struct snd_pcm_substream *substream)
+{
+ /* the hardware-specific codes will be here */
+
+ struct bcm2835_chip *chip;
+ struct snd_pcm_runtime *runtime;
+ struct bcm2835_alsa_stream *alsa_stream;
+
+ audio_info(" .. IN\n");
+
+ chip = snd_pcm_substream_chip(substream);
+ if (mutex_lock_interruptible(&chip->audio_mutex)) {
+ audio_error("Interrupted whilst waiting for lock\n");
+ return -EINTR;
+ }
+ runtime = substream->runtime;
+ alsa_stream = runtime->private_data;
+
+ audio_info("Alsa close\n");
+
+ /*
+ * Call stop if it's still running. This happens when app
+ * is force killed and we don't get a stop trigger.
+ */
+ if (alsa_stream->running) {
+ int err;
+ err = bcm2835_audio_stop(alsa_stream);
+ alsa_stream->running = 0;
+ if (err)
+ audio_error(" Failed to STOP alsa device\n");
+ }
+
+ alsa_stream->period_size = 0;
+ alsa_stream->buffer_size = 0;
+
+ if (alsa_stream->open) {
+ alsa_stream->open = 0;
+ bcm2835_audio_close(alsa_stream);
+ }
+ if (alsa_stream->chip)
+ alsa_stream->chip->alsa_stream[alsa_stream->idx] = NULL;
+ /*
+ * Do not free up alsa_stream here, it will be freed up by
+ * runtime->private_free callback we registered in *_open above
+ */
+
+ chip->opened &= ~(1 << substream->number);
+
+ mutex_unlock(&chip->audio_mutex);
+ audio_info(" .. OUT\n");
+
+ return 0;
+}
+
+/* hw_params callback */
+static int snd_bcm2835_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
+ int err;
+
+ audio_info(" .. IN\n");
+
+ err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+ if (err < 0) {
+ audio_error
+ (" pcm_lib_malloc failed to allocated pages for buffers\n");
+ return err;
+ }
+
+ alsa_stream->channels = params_channels(params);
+ alsa_stream->params_rate = params_rate(params);
+ alsa_stream->pcm_format_width = snd_pcm_format_width(params_format(params));
+ audio_info(" .. OUT\n");
+
+ return err;
+}
+
+/* hw_free callback */
+static int snd_bcm2835_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ audio_info(" .. IN\n");
+ return snd_pcm_lib_free_pages(substream);
+}
+
+/* prepare callback */
+static int snd_bcm2835_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ struct bcm2835_chip *chip = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
+ int channels;
+ int err;
+
+ audio_info(" .. IN\n");
+
+ if (mutex_lock_interruptible(&chip->audio_mutex))
+ return -EINTR;
+
+ /* notify the vchiq that it should enter spdif passthrough mode by
+ * setting channels=0 (see
+ * https://github.com/raspberrypi/linux/issues/528) */
+ if (chip->spdif_status & IEC958_AES0_NONAUDIO)
+ channels = 0;
+ else
+ channels = alsa_stream->channels;
+
+ err = bcm2835_audio_set_params(alsa_stream, channels,
+ alsa_stream->params_rate,
+ alsa_stream->pcm_format_width);
+ if (err < 0) {
+ audio_error(" error setting hw params\n");
+ }
+
+ bcm2835_audio_setup(alsa_stream);
+
+ /* in preparation of the stream, set the controls (volume level) of the stream */
+ bcm2835_audio_set_ctls(alsa_stream->chip);
+
+
+ memset(&alsa_stream->pcm_indirect, 0, sizeof(alsa_stream->pcm_indirect));
+
+ alsa_stream->pcm_indirect.hw_buffer_size =
+ alsa_stream->pcm_indirect.sw_buffer_size =
+ snd_pcm_lib_buffer_bytes(substream);
+
+ alsa_stream->buffer_size = snd_pcm_lib_buffer_bytes(substream);
+ alsa_stream->period_size = snd_pcm_lib_period_bytes(substream);
+ alsa_stream->pos = 0;
+
+ audio_debug("buffer_size=%d, period_size=%d pos=%d frame_bits=%d\n",
+ alsa_stream->buffer_size, alsa_stream->period_size,
+ alsa_stream->pos, runtime->frame_bits);
+
+ mutex_unlock(&chip->audio_mutex);
+ audio_info(" .. OUT\n");
+ return 0;
+}
+
+static void snd_bcm2835_pcm_transfer(struct snd_pcm_substream *substream,
+ struct snd_pcm_indirect *rec, size_t bytes)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
+ void *src = (void *) (substream->runtime->dma_area + rec->sw_data);
+ int err;
+
+ err = bcm2835_audio_write(alsa_stream, bytes, src);
+ if (err)
+ audio_error(" Failed to transfer to alsa device (%d)\n", err);
+
+}
+
+static int snd_bcm2835_pcm_ack(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
+ struct snd_pcm_indirect *pcm_indirect = &alsa_stream->pcm_indirect;
+
+ pcm_indirect->hw_queue_size = runtime->hw.buffer_bytes_max;
+ snd_pcm_indirect_playback_transfer(substream, pcm_indirect,
+ snd_bcm2835_pcm_transfer);
+ return 0;
+}
+
+/* trigger callback */
+static int snd_bcm2835_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
+ int err = 0;
+
+ audio_info(" .. IN\n");
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ audio_debug("bcm2835_AUDIO_TRIGGER_START running=%d\n",
+ alsa_stream->running);
+ if (!alsa_stream->running) {
+ err = bcm2835_audio_start(alsa_stream);
+ if (!err) {
+ alsa_stream->pcm_indirect.hw_io =
+ alsa_stream->pcm_indirect.hw_data =
+ bytes_to_frames(runtime,
+ alsa_stream->pos);
+ substream->ops->ack(substream);
+ alsa_stream->running = 1;
+ alsa_stream->draining = 1;
+ } else {
+ audio_error(" Failed to START alsa device (%d)\n", err);
+ }
+ }
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ audio_debug
+ ("bcm2835_AUDIO_TRIGGER_STOP running=%d draining=%d\n",
+ alsa_stream->running, runtime->status->state == SNDRV_PCM_STATE_DRAINING);
+ if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
+ audio_info("DRAINING\n");
+ alsa_stream->draining = 1;
+ } else {
+ audio_info("DROPPING\n");
+ alsa_stream->draining = 0;
+ }
+ if (alsa_stream->running) {
+ err = bcm2835_audio_stop(alsa_stream);
+ if (err != 0)
+ audio_error(" Failed to STOP alsa device (%d)\n", err);
+ alsa_stream->running = 0;
+ }
+ break;
+ default:
+ err = -EINVAL;
+ }
+
+ audio_info(" .. OUT\n");
+ return err;
+}
+
+/* pointer callback */
+static snd_pcm_uframes_t
+snd_bcm2835_pcm_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct bcm2835_alsa_stream *alsa_stream = runtime->private_data;
+
+ audio_info(" .. IN\n");
+
+ audio_debug("pcm_pointer... (%d) hwptr=%d appl=%d pos=%d\n", 0,
+ frames_to_bytes(runtime, runtime->status->hw_ptr),
+ frames_to_bytes(runtime, runtime->control->appl_ptr),
+ alsa_stream->pos);
+
+ audio_info(" .. OUT\n");
+ return snd_pcm_indirect_playback_pointer(substream,
+ &alsa_stream->pcm_indirect,
+ alsa_stream->pos);
+}
+
+static int snd_bcm2835_pcm_lib_ioctl(struct snd_pcm_substream *substream,
+ unsigned int cmd, void *arg)
+{
+ int ret = snd_pcm_lib_ioctl(substream, cmd, arg);
+ audio_info(" .. substream=%p, cmd=%d, arg=%p (%x) ret=%d\n", substream,
+ cmd, arg, arg ? *(unsigned *) arg : 0, ret);
+ return ret;
+}
+
+/* operators */
+static struct snd_pcm_ops snd_bcm2835_playback_ops = {
+ .open = snd_bcm2835_playback_open,
+ .close = snd_bcm2835_playback_close,
+ .ioctl = snd_bcm2835_pcm_lib_ioctl,
+ .hw_params = snd_bcm2835_pcm_hw_params,
+ .hw_free = snd_bcm2835_pcm_hw_free,
+ .prepare = snd_bcm2835_pcm_prepare,
+ .trigger = snd_bcm2835_pcm_trigger,
+ .pointer = snd_bcm2835_pcm_pointer,
+ .ack = snd_bcm2835_pcm_ack,
+};
+
+static struct snd_pcm_ops snd_bcm2835_playback_spdif_ops = {
+ .open = snd_bcm2835_playback_spdif_open,
+ .close = snd_bcm2835_playback_close,
+ .ioctl = snd_bcm2835_pcm_lib_ioctl,
+ .hw_params = snd_bcm2835_pcm_hw_params,
+ .hw_free = snd_bcm2835_pcm_hw_free,
+ .prepare = snd_bcm2835_pcm_prepare,
+ .trigger = snd_bcm2835_pcm_trigger,
+ .pointer = snd_bcm2835_pcm_pointer,
+ .ack = snd_bcm2835_pcm_ack,
+};
+
+/* create a pcm device */
+int snd_bcm2835_new_pcm(struct bcm2835_chip *chip)
+{
+ struct snd_pcm *pcm;
+ int err;
+
+ audio_info(" .. IN\n");
+ mutex_init(&chip->audio_mutex);
+ if (mutex_lock_interruptible(&chip->audio_mutex)) {
+ audio_error("Interrupted whilst waiting for lock\n");
+ return -EINTR;
+ }
+ err = snd_pcm_new(chip->card, "bcm2835 ALSA", 0, MAX_SUBSTREAMS, 0, &pcm);
+ if (err < 0)
+ goto out;
+ pcm->private_data = chip;
+ strcpy(pcm->name, "bcm2835 ALSA");
+ chip->pcm = pcm;
+ chip->dest = AUDIO_DEST_AUTO;
+ chip->volume = alsa2chip(0);
+ chip->mute = CTRL_VOL_UNMUTE; /*disable mute on startup */
+ /* set operators */
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ &snd_bcm2835_playback_ops);
+
+ /* pre-allocation of buffers */
+ /* NOTE: this may fail */
+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
+ snd_dma_continuous_data(GFP_KERNEL),
+ snd_bcm2835_playback_hw.buffer_bytes_max,
+ snd_bcm2835_playback_hw.buffer_bytes_max);
+
+
+out:
+ mutex_unlock(&chip->audio_mutex);
+ audio_info(" .. OUT\n");
+
+ return 0;
+}
+
+int snd_bcm2835_new_spdif_pcm(struct bcm2835_chip *chip)
+{
+ struct snd_pcm *pcm;
+ int err;
+
+ audio_info(" .. IN\n");
+ if (mutex_lock_interruptible(&chip->audio_mutex)) {
+ audio_error("Interrupted whilst waiting for lock\n");
+ return -EINTR;
+ }
+ err = snd_pcm_new(chip->card, "bcm2835 ALSA", 1, 1, 0, &pcm);
+ if (err < 0)
+ goto out;
+
+ pcm->private_data = chip;
+ strcpy(pcm->name, "bcm2835 IEC958/HDMI");
+ chip->pcm_spdif = pcm;
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+ &snd_bcm2835_playback_spdif_ops);
+
+ /* pre-allocation of buffers */
+ /* NOTE: this may fail */
+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
+ snd_dma_continuous_data(GFP_KERNEL),
+ snd_bcm2835_playback_spdif_hw.buffer_bytes_max, snd_bcm2835_playback_spdif_hw.buffer_bytes_max);
+out:
+ mutex_unlock(&chip->audio_mutex);
+ audio_info(" .. OUT\n");
+
+ return 0;
+}
--- /dev/null
+/*****************************************************************************
+ * Copyright 2011 Broadcom Corporation. All rights reserved.
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2, available at
+ * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+ *
+ * Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a
+ * license other than the GPL, without Broadcom's express prior written
+ * consent.
+ *****************************************************************************/
+
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/mm.h>
+#include <linux/syscalls.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/atomic.h>
+#include <linux/module.h>
+#include <linux/completion.h>
+
+#include "bcm2835.h"
+
+/* ---- Include Files -------------------------------------------------------- */
+
+#include "interface/vchi/vchi.h"
+#include "vc_vchi_audioserv_defs.h"
+
+/* ---- Private Constants and Types ------------------------------------------ */
+
+#define BCM2835_AUDIO_STOP 0
+#define BCM2835_AUDIO_START 1
+#define BCM2835_AUDIO_WRITE 2
+
+/* Logging macros (for remapping to other logging mechanisms, i.e., printf) */
+#ifdef AUDIO_DEBUG_ENABLE
+#define LOG_ERR(fmt, arg...) pr_err("%s:%d " fmt, __func__, __LINE__, ##arg)
+#define LOG_WARN(fmt, arg...) pr_info("%s:%d " fmt, __func__, __LINE__, ##arg)
+#define LOG_INFO(fmt, arg...) pr_info("%s:%d " fmt, __func__, __LINE__, ##arg)
+#define LOG_DBG(fmt, arg...) pr_info("%s:%d " fmt, __func__, __LINE__, ##arg)
+#else
+#define LOG_ERR(fmt, arg...) pr_err("%s:%d " fmt, __func__, __LINE__, ##arg)
+#define LOG_WARN(fmt, arg...) no_printk(fmt, ##arg)
+#define LOG_INFO(fmt, arg...) no_printk(fmt, ##arg)
+#define LOG_DBG(fmt, arg...) no_printk(fmt, ##arg)
+#endif
+
+struct bcm2835_audio_instance {
+ unsigned int num_connections;
+ VCHI_SERVICE_HANDLE_T vchi_handle[VCHI_MAX_NUM_CONNECTIONS];
+ struct completion msg_avail_comp;
+ struct mutex vchi_mutex;
+ struct bcm2835_alsa_stream *alsa_stream;
+ int result;
+ short peer_version;
+};
+
+static bool force_bulk;
+
+/* ---- Private Variables ---------------------------------------------------- */
+
+/* ---- Private Function Prototypes ------------------------------------------ */
+
+/* ---- Private Functions ---------------------------------------------------- */
+
+static int bcm2835_audio_stop_worker(struct bcm2835_alsa_stream *alsa_stream);
+static int bcm2835_audio_start_worker(struct bcm2835_alsa_stream *alsa_stream);
+static int bcm2835_audio_write_worker(struct bcm2835_alsa_stream *alsa_stream,
+ unsigned int count, void *src);
+
+
+// Routine to send a message across a service
+
+static int
+bcm2835_vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,
+ void *data,
+ unsigned int size)
+{
+ return vchi_queue_kernel_message(handle,
+ data,
+ size);
+}
+
+static const u32 BCM2835_AUDIO_WRITE_COOKIE1 = ('B' << 24 | 'C' << 16 |
+ 'M' << 8 | 'A');
+static const u32 BCM2835_AUDIO_WRITE_COOKIE2 = ('D' << 24 | 'A' << 16 |
+ 'T' << 8 | 'A');
+
+struct bcm2835_audio_work {
+ struct work_struct my_work;
+ struct bcm2835_alsa_stream *alsa_stream;
+ int cmd;
+ void *src;
+ unsigned int count;
+};
+
+static void my_wq_function(struct work_struct *work)
+{
+ struct bcm2835_audio_work *w =
+ container_of(work, struct bcm2835_audio_work, my_work);
+ int ret = -9;
+ LOG_DBG(" .. IN %p:%d\n", w->alsa_stream, w->cmd);
+ switch (w->cmd) {
+ case BCM2835_AUDIO_START:
+ ret = bcm2835_audio_start_worker(w->alsa_stream);
+ break;
+ case BCM2835_AUDIO_STOP:
+ ret = bcm2835_audio_stop_worker(w->alsa_stream);
+ break;
+ case BCM2835_AUDIO_WRITE:
+ ret = bcm2835_audio_write_worker(w->alsa_stream, w->count,
+ w->src);
+ break;
+ default:
+ LOG_ERR(" Unexpected work: %p:%d\n", w->alsa_stream, w->cmd);
+ break;
+ }
+ kfree((void *) work);
+ LOG_DBG(" .. OUT %d\n", ret);
+}
+
+int bcm2835_audio_start(struct bcm2835_alsa_stream *alsa_stream)
+{
+ int ret = -1;
+ LOG_DBG(" .. IN\n");
+ if (alsa_stream->my_wq) {
+ struct bcm2835_audio_work *work =
+ kmalloc(sizeof(struct bcm2835_audio_work *), GFP_ATOMIC);
+ /*--- Queue some work (item 1) ---*/
+ if (work) {
+ INIT_WORK(&work->my_work, my_wq_function);
+ work->alsa_stream = alsa_stream;
+ work->cmd = BCM2835_AUDIO_START;
+ if (queue_work(alsa_stream->my_wq, &work->my_work))
+ ret = 0;
+ } else
+ LOG_ERR(" .. Error: NULL work kmalloc\n");
+ }
+ LOG_DBG(" .. OUT %d\n", ret);
+ return ret;
+}
+
+int bcm2835_audio_stop(struct bcm2835_alsa_stream *alsa_stream)
+{
+ int ret = -1;
+ LOG_DBG(" .. IN\n");
+ if (alsa_stream->my_wq) {
+ struct bcm2835_audio_work *work =
+ kmalloc(sizeof(struct bcm2835_audio_work *), GFP_ATOMIC);
+ /*--- Queue some work (item 1) ---*/
+ if (work) {
+ INIT_WORK(&work->my_work, my_wq_function);
+ work->alsa_stream = alsa_stream;
+ work->cmd = BCM2835_AUDIO_STOP;
+ if (queue_work(alsa_stream->my_wq, &work->my_work))
+ ret = 0;
+ } else
+ LOG_ERR(" .. Error: NULL work kmalloc\n");
+ }
+ LOG_DBG(" .. OUT %d\n", ret);
+ return ret;
+}
+
+int bcm2835_audio_write(struct bcm2835_alsa_stream *alsa_stream,
+ unsigned int count, void *src)
+{
+ int ret = -1;
+ LOG_DBG(" .. IN\n");
+ if (alsa_stream->my_wq) {
+ struct bcm2835_audio_work *work =
+ kmalloc(sizeof(struct bcm2835_audio_work *), GFP_ATOMIC);
+ /*--- Queue some work (item 1) ---*/
+ if (work) {
+ INIT_WORK(&work->my_work, my_wq_function);
+ work->alsa_stream = alsa_stream;
+ work->cmd = BCM2835_AUDIO_WRITE;
+ work->src = src;
+ work->count = count;
+ if (queue_work(alsa_stream->my_wq, &work->my_work))
+ ret = 0;
+ } else
+ LOG_ERR(" .. Error: NULL work kmalloc\n");
+ }
+ LOG_DBG(" .. OUT %d\n", ret);
+ return ret;
+}
+
+static void my_workqueue_init(struct bcm2835_alsa_stream *alsa_stream)
+{
+ alsa_stream->my_wq = alloc_workqueue("my_queue", WQ_HIGHPRI, 1);
+ return;
+}
+
+static void my_workqueue_quit(struct bcm2835_alsa_stream *alsa_stream)
+{
+ if (alsa_stream->my_wq) {
+ flush_workqueue(alsa_stream->my_wq);
+ destroy_workqueue(alsa_stream->my_wq);
+ alsa_stream->my_wq = NULL;
+ }
+ return;
+}
+
+static void audio_vchi_callback(void *param,
+ const VCHI_CALLBACK_REASON_T reason,
+ void *msg_handle)
+{
+ struct bcm2835_audio_instance *instance = param;
+ int status;
+ int msg_len;
+ struct vc_audio_msg m;
+ LOG_DBG(" .. IN instance=%p, handle=%p, alsa=%p, reason=%d, handle=%p\n",
+ instance, instance ? instance->vchi_handle[0] : NULL, instance ? instance->alsa_stream : NULL, reason, msg_handle);
+
+ if (reason != VCHI_CALLBACK_MSG_AVAILABLE) {
+ return;
+ }
+ if (!instance) {
+ LOG_ERR(" .. instance is null\n");
+ BUG();
+ return;
+ }
+ if (!instance->vchi_handle[0]) {
+ LOG_ERR(" .. instance->vchi_handle[0] is null\n");
+ BUG();
+ return;
+ }
+ status = vchi_msg_dequeue(instance->vchi_handle[0],
+ &m, sizeof(m), &msg_len, VCHI_FLAGS_NONE);
+ if (m.type == VC_AUDIO_MSG_TYPE_RESULT) {
+ LOG_DBG(" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_RESULT, success=%d\n",
+ instance, m.u.result.success);
+ instance->result = m.u.result.success;
+ complete(&instance->msg_avail_comp);
+ } else if (m.type == VC_AUDIO_MSG_TYPE_COMPLETE) {
+ struct bcm2835_alsa_stream *alsa_stream = instance->alsa_stream;
+ LOG_DBG(" .. instance=%p, m.type=VC_AUDIO_MSG_TYPE_COMPLETE, complete=%d\n",
+ instance, m.u.complete.count);
+ if (m.u.complete.cookie1 != BCM2835_AUDIO_WRITE_COOKIE1 ||
+ m.u.complete.cookie2 != BCM2835_AUDIO_WRITE_COOKIE2)
+ LOG_ERR(" .. response is corrupt\n");
+ else if (alsa_stream) {
+ atomic_add(m.u.complete.count,
+ &alsa_stream->retrieved);
+ bcm2835_playback_fifo(alsa_stream);
+ } else {
+ LOG_ERR(" .. unexpected alsa_stream=%p\n",
+ alsa_stream);
+ }
+ } else {
+ LOG_ERR(" .. unexpected m.type=%d\n", m.type);
+ }
+ LOG_DBG(" .. OUT\n");
+}
+
+static struct bcm2835_audio_instance *
+vc_vchi_audio_init(VCHI_INSTANCE_T vchi_instance,
+ VCHI_CONNECTION_T **vchi_connections,
+ unsigned int num_connections)
+{
+ unsigned int i;
+ struct bcm2835_audio_instance *instance;
+ int status;
+
+ LOG_DBG("%s: start", __func__);
+
+ if (num_connections > VCHI_MAX_NUM_CONNECTIONS) {
+ LOG_ERR("%s: unsupported number of connections %u (max=%u)\n",
+ __func__, num_connections, VCHI_MAX_NUM_CONNECTIONS);
+
+ return NULL;
+ }
+ /* Allocate memory for this instance */
+ instance = kmalloc(sizeof(*instance), GFP_KERNEL);
+ if (!instance)
+ return NULL;
+
+ memset(instance, 0, sizeof(*instance));
+ instance->num_connections = num_connections;
+
+ /* Create a lock for exclusive, serialized VCHI connection access */
+ mutex_init(&instance->vchi_mutex);
+ /* Open the VCHI service connections */
+ for (i = 0; i < num_connections; i++) {
+ SERVICE_CREATION_T params = {
+ VCHI_VERSION_EX(VC_AUDIOSERV_VER, VC_AUDIOSERV_MIN_VER),
+ VC_AUDIO_SERVER_NAME, // 4cc service code
+ vchi_connections[i], // passed in fn pointers
+ 0, // rx fifo size (unused)
+ 0, // tx fifo size (unused)
+ audio_vchi_callback, // service callback
+ instance, // service callback parameter
+ 1, //TODO: remove VCOS_FALSE, // unaligned bulk recieves
+ 1, //TODO: remove VCOS_FALSE, // unaligned bulk transmits
+ 0 // want crc check on bulk transfers
+ };
+
+ LOG_DBG("%s: about to open %i\n", __func__, i);
+ status = vchi_service_open(vchi_instance, ¶ms,
+ &instance->vchi_handle[i]);
+ LOG_DBG("%s: opened %i: %p=%d\n", __func__, i, instance->vchi_handle[i], status);
+ if (status) {
+ LOG_ERR("%s: failed to open VCHI service connection (status=%d)\n",
+ __func__, status);
+
+ goto err_close_services;
+ }
+ /* Finished with the service for now */
+ vchi_service_release(instance->vchi_handle[i]);
+ }
+
+ LOG_DBG("%s: okay\n", __func__);
+ return instance;
+
+err_close_services:
+ for (i = 0; i < instance->num_connections; i++) {
+ LOG_ERR("%s: closing %i: %p\n", __func__, i, instance->vchi_handle[i]);
+ if (instance->vchi_handle[i])
+ vchi_service_close(instance->vchi_handle[i]);
+ }
+
+ kfree(instance);
+ LOG_ERR("%s: error\n", __func__);
+
+ return NULL;
+}
+
+static int vc_vchi_audio_deinit(struct bcm2835_audio_instance *instance)
+{
+ unsigned int i;
+
+ LOG_DBG(" .. IN\n");
+
+ if (!instance) {
+ LOG_ERR("%s: invalid handle %p\n", __func__, instance);
+
+ return -1;
+ }
+
+ LOG_DBG(" .. about to lock (%d)\n", instance->num_connections);
+ if (mutex_lock_interruptible(&instance->vchi_mutex)) {
+ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
+ instance->num_connections);
+ return -EINTR;
+ }
+
+ /* Close all VCHI service connections */
+ for (i = 0; i < instance->num_connections; i++) {
+ int status;
+ LOG_DBG(" .. %i:closing %p\n", i, instance->vchi_handle[i]);
+ vchi_service_use(instance->vchi_handle[i]);
+
+ status = vchi_service_close(instance->vchi_handle[i]);
+ if (status) {
+ LOG_DBG("%s: failed to close VCHI service connection (status=%d)\n",
+ __func__, status);
+ }
+ }
+
+ mutex_unlock(&instance->vchi_mutex);
+
+ kfree(instance);
+
+ LOG_DBG(" .. OUT\n");
+
+ return 0;
+}
+
+static int bcm2835_audio_open_connection(struct bcm2835_alsa_stream *alsa_stream)
+{
+ static VCHI_INSTANCE_T vchi_instance;
+ static VCHI_CONNECTION_T *vchi_connection;
+ static int initted;
+ struct bcm2835_audio_instance *instance =
+ (struct bcm2835_audio_instance *)alsa_stream->instance;
+ int ret;
+ LOG_DBG(" .. IN\n");
+
+ LOG_INFO("%s: start\n", __func__);
+ BUG_ON(instance);
+ if (instance) {
+ LOG_ERR("%s: VCHI instance already open (%p)\n",
+ __func__, instance);
+ instance->alsa_stream = alsa_stream;
+ alsa_stream->instance = instance;
+ ret = 0; // xxx todo -1;
+ goto err_free_mem;
+ }
+
+ /* Initialize and create a VCHI connection */
+ if (!initted) {
+ ret = vchi_initialise(&vchi_instance);
+ if (ret) {
+ LOG_ERR("%s: failed to initialise VCHI instance (ret=%d)\n",
+ __func__, ret);
+
+ ret = -EIO;
+ goto err_free_mem;
+ }
+ ret = vchi_connect(NULL, 0, vchi_instance);
+ if (ret) {
+ LOG_ERR("%s: failed to connect VCHI instance (ret=%d)\n",
+ __func__, ret);
+
+ ret = -EIO;
+ goto err_free_mem;
+ }
+ initted = 1;
+ }
+
+ /* Initialize an instance of the audio service */
+ instance = vc_vchi_audio_init(vchi_instance, &vchi_connection, 1);
+
+ if (!instance) {
+ LOG_ERR("%s: failed to initialize audio service\n", __func__);
+
+ ret = -EPERM;
+ goto err_free_mem;
+ }
+
+ instance->alsa_stream = alsa_stream;
+ alsa_stream->instance = instance;
+
+ LOG_DBG(" success !\n");
+ ret = 0;
+err_free_mem:
+ LOG_DBG(" .. OUT\n");
+
+ return ret;
+}
+
+int bcm2835_audio_open(struct bcm2835_alsa_stream *alsa_stream)
+{
+ struct bcm2835_audio_instance *instance;
+ struct vc_audio_msg m;
+ int status;
+ int ret;
+ LOG_DBG(" .. IN\n");
+
+ my_workqueue_init(alsa_stream);
+
+ ret = bcm2835_audio_open_connection(alsa_stream);
+ if (ret) {
+ ret = -1;
+ goto exit;
+ }
+ instance = alsa_stream->instance;
+ LOG_DBG(" instance (%p)\n", instance);
+
+ if (mutex_lock_interruptible(&instance->vchi_mutex)) {
+ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n", instance->num_connections);
+ return -EINTR;
+ }
+ vchi_service_use(instance->vchi_handle[0]);
+
+ m.type = VC_AUDIO_MSG_TYPE_OPEN;
+
+ /* Send the message to the videocore */
+ status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
+ &m, sizeof(m));
+
+ if (status) {
+ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
+ __func__, status);
+
+ ret = -1;
+ goto unlock;
+ }
+
+ ret = 0;
+
+unlock:
+ vchi_service_release(instance->vchi_handle[0]);
+ mutex_unlock(&instance->vchi_mutex);
+exit:
+ LOG_DBG(" .. OUT\n");
+ return ret;
+}
+
+static int bcm2835_audio_set_ctls_chan(struct bcm2835_alsa_stream *alsa_stream,
+ struct bcm2835_chip *chip)
+{
+ struct vc_audio_msg m;
+ struct bcm2835_audio_instance *instance = alsa_stream->instance;
+ int status;
+ int ret;
+ LOG_DBG(" .. IN\n");
+
+ LOG_INFO(" Setting ALSA dest(%d), volume(%d)\n",
+ chip->dest, chip->volume);
+
+ if (mutex_lock_interruptible(&instance->vchi_mutex)) {
+ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
+ instance->num_connections);
+ return -EINTR;
+ }
+ vchi_service_use(instance->vchi_handle[0]);
+
+ instance->result = -1;
+
+ m.type = VC_AUDIO_MSG_TYPE_CONTROL;
+ m.u.control.dest = chip->dest;
+ m.u.control.volume = chip->volume;
+
+ /* Create the message available completion */
+ init_completion(&instance->msg_avail_comp);
+
+ /* Send the message to the videocore */
+ status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
+ &m, sizeof(m));
+
+ if (status) {
+ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
+ __func__, status);
+
+ ret = -1;
+ goto unlock;
+ }
+
+ /* We are expecting a reply from the videocore */
+ wait_for_completion(&instance->msg_avail_comp);
+
+ if (instance->result) {
+ LOG_ERR("%s: result=%d\n", __func__, instance->result);
+
+ ret = -1;
+ goto unlock;
+ }
+
+ ret = 0;
+
+unlock:
+ vchi_service_release(instance->vchi_handle[0]);
+ mutex_unlock(&instance->vchi_mutex);
+
+ LOG_DBG(" .. OUT\n");
+ return ret;
+}
+
+int bcm2835_audio_set_ctls(struct bcm2835_chip *chip)
+{
+ int i;
+ int ret = 0;
+ LOG_DBG(" .. IN\n");
+ LOG_DBG(" Setting ALSA dest(%d), volume(%d)\n", chip->dest, chip->volume);
+
+ /* change ctls for all substreams */
+ for (i = 0; i < MAX_SUBSTREAMS; i++) {
+ if (chip->avail_substreams & (1 << i)) {
+ if (!chip->alsa_stream[i]) {
+ LOG_DBG(" No ALSA stream available?! %i:%p (%x)\n", i, chip->alsa_stream[i], chip->avail_substreams);
+ ret = 0;
+ } else if (bcm2835_audio_set_ctls_chan(chip->alsa_stream[i], chip) != 0) {
+ LOG_ERR("Couldn't set the controls for stream %d\n", i);
+ ret = -1;
+ } else LOG_DBG(" Controls set for stream %d\n", i);
+ }
+ }
+ LOG_DBG(" .. OUT ret=%d\n", ret);
+ return ret;
+}
+
+int bcm2835_audio_set_params(struct bcm2835_alsa_stream *alsa_stream,
+ unsigned int channels, unsigned int samplerate,
+ unsigned int bps)
+{
+ struct vc_audio_msg m;
+ struct bcm2835_audio_instance *instance = alsa_stream->instance;
+ int status;
+ int ret;
+ LOG_DBG(" .. IN\n");
+
+ LOG_INFO(" Setting ALSA channels(%d), samplerate(%d), bits-per-sample(%d)\n",
+ channels, samplerate, bps);
+
+ /* resend ctls - alsa_stream may not have been open when first send */
+ ret = bcm2835_audio_set_ctls_chan(alsa_stream, alsa_stream->chip);
+ if (ret) {
+ LOG_ERR(" Alsa controls not supported\n");
+ return -EINVAL;
+ }
+
+ if (mutex_lock_interruptible(&instance->vchi_mutex)) {
+ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n", instance->num_connections);
+ return -EINTR;
+ }
+ vchi_service_use(instance->vchi_handle[0]);
+
+ instance->result = -1;
+
+ m.type = VC_AUDIO_MSG_TYPE_CONFIG;
+ m.u.config.channels = channels;
+ m.u.config.samplerate = samplerate;
+ m.u.config.bps = bps;
+
+ /* Create the message available completion */
+ init_completion(&instance->msg_avail_comp);
+
+ /* Send the message to the videocore */
+ status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
+ &m, sizeof(m));
+
+ if (status) {
+ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
+ __func__, status);
+
+ ret = -1;
+ goto unlock;
+ }
+
+ /* We are expecting a reply from the videocore */
+ wait_for_completion(&instance->msg_avail_comp);
+
+ if (instance->result) {
+ LOG_ERR("%s: result=%d", __func__, instance->result);
+
+ ret = -1;
+ goto unlock;
+ }
+
+ ret = 0;
+
+unlock:
+ vchi_service_release(instance->vchi_handle[0]);
+ mutex_unlock(&instance->vchi_mutex);
+
+ LOG_DBG(" .. OUT\n");
+ return ret;
+}
+
+int bcm2835_audio_setup(struct bcm2835_alsa_stream *alsa_stream)
+{
+ LOG_DBG(" .. IN\n");
+
+ LOG_DBG(" .. OUT\n");
+
+ return 0;
+}
+
+static int bcm2835_audio_start_worker(struct bcm2835_alsa_stream *alsa_stream)
+{
+ struct vc_audio_msg m;
+ struct bcm2835_audio_instance *instance = alsa_stream->instance;
+ int status;
+ int ret;
+ LOG_DBG(" .. IN\n");
+
+ if (mutex_lock_interruptible(&instance->vchi_mutex)) {
+ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
+ instance->num_connections);
+ return -EINTR;
+ }
+ vchi_service_use(instance->vchi_handle[0]);
+
+ m.type = VC_AUDIO_MSG_TYPE_START;
+
+ /* Send the message to the videocore */
+ status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
+ &m, sizeof(m));
+
+ if (status) {
+ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
+ __func__, status);
+
+ ret = -1;
+ goto unlock;
+ }
+
+ ret = 0;
+
+unlock:
+ vchi_service_release(instance->vchi_handle[0]);
+ mutex_unlock(&instance->vchi_mutex);
+ LOG_DBG(" .. OUT\n");
+ return ret;
+}
+
+static int bcm2835_audio_stop_worker(struct bcm2835_alsa_stream *alsa_stream)
+{
+ struct vc_audio_msg m;
+ struct bcm2835_audio_instance *instance = alsa_stream->instance;
+ int status;
+ int ret;
+ LOG_DBG(" .. IN\n");
+
+ if (mutex_lock_interruptible(&instance->vchi_mutex)) {
+ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
+ instance->num_connections);
+ return -EINTR;
+ }
+ vchi_service_use(instance->vchi_handle[0]);
+
+ m.type = VC_AUDIO_MSG_TYPE_STOP;
+ m.u.stop.draining = alsa_stream->draining;
+
+ /* Send the message to the videocore */
+ status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
+ &m, sizeof(m));
+
+ if (status) {
+ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
+ __func__, status);
+
+ ret = -1;
+ goto unlock;
+ }
+
+ ret = 0;
+
+unlock:
+ vchi_service_release(instance->vchi_handle[0]);
+ mutex_unlock(&instance->vchi_mutex);
+ LOG_DBG(" .. OUT\n");
+ return ret;
+}
+
+int bcm2835_audio_close(struct bcm2835_alsa_stream *alsa_stream)
+{
+ struct vc_audio_msg m;
+ struct bcm2835_audio_instance *instance = alsa_stream->instance;
+ int status;
+ int ret;
+ LOG_DBG(" .. IN\n");
+
+ my_workqueue_quit(alsa_stream);
+
+ if (mutex_lock_interruptible(&instance->vchi_mutex)) {
+ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
+ instance->num_connections);
+ return -EINTR;
+ }
+ vchi_service_use(instance->vchi_handle[0]);
+
+ m.type = VC_AUDIO_MSG_TYPE_CLOSE;
+
+ /* Create the message available completion */
+ init_completion(&instance->msg_avail_comp);
+
+ /* Send the message to the videocore */
+ status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
+ &m, sizeof(m));
+
+ if (status) {
+ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
+ __func__, status);
+ ret = -1;
+ goto unlock;
+ }
+
+ /* We are expecting a reply from the videocore */
+ wait_for_completion(&instance->msg_avail_comp);
+
+ if (instance->result) {
+ LOG_ERR("%s: failed result (result=%d)\n",
+ __func__, instance->result);
+
+ ret = -1;
+ goto unlock;
+ }
+
+ ret = 0;
+
+unlock:
+ vchi_service_release(instance->vchi_handle[0]);
+ mutex_unlock(&instance->vchi_mutex);
+
+ /* Stop the audio service */
+ vc_vchi_audio_deinit(instance);
+ alsa_stream->instance = NULL;
+
+ LOG_DBG(" .. OUT\n");
+ return ret;
+}
+
+static int bcm2835_audio_write_worker(struct bcm2835_alsa_stream *alsa_stream,
+ unsigned int count, void *src)
+{
+ struct vc_audio_msg m;
+ struct bcm2835_audio_instance *instance = alsa_stream->instance;
+ int status;
+ int ret;
+
+ LOG_DBG(" .. IN\n");
+
+ LOG_INFO(" Writing %d bytes from %p\n", count, src);
+
+ if (mutex_lock_interruptible(&instance->vchi_mutex)) {
+ LOG_DBG("Interrupted whilst waiting for lock on (%d)\n",
+ instance->num_connections);
+ return -EINTR;
+ }
+ vchi_service_use(instance->vchi_handle[0]);
+
+ if (instance->peer_version == 0 && vchi_get_peer_version(instance->vchi_handle[0], &instance->peer_version) == 0) {
+ LOG_DBG("%s: client version %d connected\n", __func__, instance->peer_version);
+ }
+ m.type = VC_AUDIO_MSG_TYPE_WRITE;
+ m.u.write.count = count;
+ // old version uses bulk, new version uses control
+ m.u.write.max_packet = instance->peer_version < 2 || force_bulk ? 0 : 4000;
+ m.u.write.cookie1 = BCM2835_AUDIO_WRITE_COOKIE1;
+ m.u.write.cookie2 = BCM2835_AUDIO_WRITE_COOKIE2;
+ m.u.write.silence = src == NULL;
+
+ /* Send the message to the videocore */
+ status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
+ &m, sizeof(m));
+
+ if (status) {
+ LOG_ERR("%s: failed on vchi_msg_queue (status=%d)\n",
+ __func__, status);
+
+ ret = -1;
+ goto unlock;
+ }
+ if (!m.u.write.silence) {
+ if (!m.u.write.max_packet) {
+ /* Send the message to the videocore */
+ status = vchi_bulk_queue_transmit(instance->vchi_handle[0],
+ src, count,
+ 0 *
+ VCHI_FLAGS_BLOCK_UNTIL_QUEUED
+ +
+ 1 *
+ VCHI_FLAGS_BLOCK_UNTIL_DATA_READ,
+ NULL);
+ } else {
+ while (count > 0) {
+ int bytes = min((int) m.u.write.max_packet, (int) count);
+ status = bcm2835_vchi_msg_queue(instance->vchi_handle[0],
+ src, bytes);
+ src = (char *)src + bytes;
+ count -= bytes;
+ }
+ }
+ if (status) {
+ LOG_ERR("%s: failed on vchi_bulk_queue_transmit (status=%d)\n",
+ __func__, status);
+
+ ret = -1;
+ goto unlock;
+ }
+ }
+ ret = 0;
+
+unlock:
+ vchi_service_release(instance->vchi_handle[0]);
+ mutex_unlock(&instance->vchi_mutex);
+ LOG_DBG(" .. OUT\n");
+ return ret;
+}
+
+/**
+ * Returns all buffers from arm->vc
+ */
+void bcm2835_audio_flush_buffers(struct bcm2835_alsa_stream *alsa_stream)
+{
+ LOG_DBG(" .. IN\n");
+ LOG_DBG(" .. OUT\n");
+ return;
+}
+
+/**
+ * Forces VC to flush(drop) its filled playback buffers and
+ * return them the us. (VC->ARM)
+ */
+void bcm2835_audio_flush_playback_buffers(struct bcm2835_alsa_stream *alsa_stream)
+{
+ LOG_DBG(" .. IN\n");
+ LOG_DBG(" .. OUT\n");
+}
+
+unsigned int bcm2835_audio_retrieve_buffers(struct bcm2835_alsa_stream *alsa_stream)
+{
+ unsigned int count = atomic_read(&alsa_stream->retrieved);
+ atomic_sub(count, &alsa_stream->retrieved);
+ return count;
+}
+
+module_param(force_bulk, bool, 0444);
+MODULE_PARM_DESC(force_bulk, "Force use of vchiq bulk for audio");
--- /dev/null
+/*****************************************************************************
+ * Copyright 2011 Broadcom Corporation. All rights reserved.
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2, available at
+ * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+ *
+ * Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a
+ * license other than the GPL, without Broadcom's express prior written
+ * consent.
+ *****************************************************************************/
+
+#include <linux/platform_device.h>
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/of.h>
+
+#include "bcm2835.h"
+
+/* HACKY global pointers needed for successive probes to work : ssp
+ * But compared against the changes we will have to do in VC audio_ipc code
+ * to export 8 audio_ipc devices as a single IPC device and then monitor all
+ * four devices in a thread, this gets things done quickly and should be easier
+ * to debug if we run into issues
+ */
+
+static struct snd_card *g_card;
+static struct bcm2835_chip *g_chip;
+
+static int snd_bcm2835_free(struct bcm2835_chip *chip)
+{
+ kfree(chip);
+ return 0;
+}
+
+/* component-destructor
+ * (see "Management of Cards and Components")
+ */
+static int snd_bcm2835_dev_free(struct snd_device *device)
+{
+ return snd_bcm2835_free(device->device_data);
+}
+
+/* chip-specific constructor
+ * (see "Management of Cards and Components")
+ */
+static int snd_bcm2835_create(struct snd_card *card,
+ struct platform_device *pdev,
+ struct bcm2835_chip **rchip)
+{
+ struct bcm2835_chip *chip;
+ int err;
+ static struct snd_device_ops ops = {
+ .dev_free = snd_bcm2835_dev_free,
+ };
+
+ *rchip = NULL;
+
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->card = card;
+
+ err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
+ if (err < 0) {
+ snd_bcm2835_free(chip);
+ return err;
+ }
+
+ *rchip = chip;
+ return 0;
+}
+
+static int snd_bcm2835_alsa_probe_dt(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct bcm2835_chip *chip;
+ struct snd_card *card;
+ u32 numchans;
+ int err, i;
+
+ err = of_property_read_u32(dev->of_node, "brcm,pwm-channels",
+ &numchans);
+ if (err) {
+ dev_err(dev, "Failed to get DT property 'brcm,pwm-channels'");
+ return err;
+ }
+
+ if (numchans == 0 || numchans > MAX_SUBSTREAMS) {
+ numchans = MAX_SUBSTREAMS;
+ dev_warn(dev, "Illegal 'brcm,pwm-channels' value, will use %u\n",
+ numchans);
+ }
+
+ err = snd_card_new(&pdev->dev, -1, NULL, THIS_MODULE, 0, &card);
+ if (err) {
+ dev_err(dev, "Failed to create soundcard structure\n");
+ return err;
+ }
+
+ snd_card_set_dev(card, dev);
+ strcpy(card->driver, "bcm2835");
+ strcpy(card->shortname, "bcm2835 ALSA");
+ sprintf(card->longname, "%s", card->shortname);
+
+ err = snd_bcm2835_create(card, pdev, &chip);
+ if (err < 0) {
+ dev_err(dev, "Failed to create bcm2835 chip\n");
+ goto err_free;
+ }
+
+ err = snd_bcm2835_new_pcm(chip);
+ if (err < 0) {
+ dev_err(dev, "Failed to create new bcm2835 pcm device\n");
+ goto err_free;
+ }
+
+ err = snd_bcm2835_new_spdif_pcm(chip);
+ if (err < 0) {
+ dev_err(dev, "Failed to create new bcm2835 spdif pcm device\n");
+ goto err_free;
+ }
+
+ err = snd_bcm2835_new_ctl(chip);
+ if (err < 0) {
+ dev_err(dev, "Failed to create new bcm2835 ctl\n");
+ goto err_free;
+ }
+
+ for (i = 0; i < numchans; i++) {
+ chip->avail_substreams |= (1 << i);
+ chip->pdev[i] = pdev;
+ }
+
+ err = snd_card_register(card);
+ if (err) {
+ dev_err(dev, "Failed to register bcm2835 ALSA card\n");
+ goto err_free;
+ }
+
+ g_card = card;
+ g_chip = chip;
+ platform_set_drvdata(pdev, card);
+ audio_info("bcm2835 ALSA card created with %u channels\n", numchans);
+
+ return 0;
+
+err_free:
+ snd_card_free(card);
+
+ return err;
+}
+
+static int snd_bcm2835_alsa_remove(struct platform_device *pdev)
+{
+ int idx;
+ void *drv_data;
+
+ drv_data = platform_get_drvdata(pdev);
+
+ if (drv_data == (void *)g_card) {
+ /* This is the card device */
+ snd_card_free((struct snd_card *)drv_data);
+ g_card = NULL;
+ g_chip = NULL;
+ } else {
+ idx = (int)(long)drv_data;
+ if (g_card) {
+ BUG_ON(!g_chip);
+ /* We pass chip device numbers in audio ipc devices
+ * other than the one we registered our card with
+ */
+ idx = (int)(long)drv_data;
+ BUG_ON(!idx || idx > MAX_SUBSTREAMS);
+ g_chip->avail_substreams &= ~(1 << idx);
+ /* There should be atleast one substream registered
+ * after we are done here, as it wil be removed when
+ * the *remove* is called for the card device
+ */
+ BUG_ON(!g_chip->avail_substreams);
+ }
+ }
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int snd_bcm2835_alsa_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ return 0;
+}
+
+static int snd_bcm2835_alsa_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+
+#endif
+
+static const struct of_device_id snd_bcm2835_of_match_table[] = {
+ { .compatible = "brcm,bcm2835-audio",},
+ {},
+};
+MODULE_DEVICE_TABLE(of, snd_bcm2835_of_match_table);
+
+static struct platform_driver bcm2835_alsa0_driver = {
+ .probe = snd_bcm2835_alsa_probe_dt,
+ .remove = snd_bcm2835_alsa_remove,
+#ifdef CONFIG_PM
+ .suspend = snd_bcm2835_alsa_suspend,
+ .resume = snd_bcm2835_alsa_resume,
+#endif
+ .driver = {
+ .name = "bcm2835_AUD0",
+ .owner = THIS_MODULE,
+ .of_match_table = snd_bcm2835_of_match_table,
+ },
+};
+
+static int bcm2835_alsa_device_init(void)
+{
+ int retval;
+
+ retval = platform_driver_register(&bcm2835_alsa0_driver);
+ if (retval)
+ pr_err("Error registering bcm2835_alsa0_driver %d .\n", retval);
+
+ return retval;
+}
+
+static void bcm2835_alsa_device_exit(void)
+{
+ platform_driver_unregister(&bcm2835_alsa0_driver);
+}
+
+late_initcall(bcm2835_alsa_device_init);
+module_exit(bcm2835_alsa_device_exit);
+
+MODULE_AUTHOR("Dom Cobley");
+MODULE_DESCRIPTION("Alsa driver for BCM2835 chip");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*****************************************************************************
+ * Copyright 2011 Broadcom Corporation. All rights reserved.
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2, available at
+ * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+ *
+ * Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a
+ * license other than the GPL, without Broadcom's express prior written
+ * consent.
+ *****************************************************************************/
+
+#ifndef __SOUND_ARM_BCM2835_H
+#define __SOUND_ARM_BCM2835_H
+
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/pcm-indirect.h>
+#include <linux/workqueue.h>
+
+/*
+#define AUDIO_DEBUG_ENABLE
+#define AUDIO_VERBOSE_DEBUG_ENABLE
+ */
+
+/* Debug macros */
+
+#ifdef AUDIO_DEBUG_ENABLE
+#ifdef AUDIO_VERBOSE_DEBUG_ENABLE
+
+#define audio_debug(fmt, arg...) \
+ printk(KERN_INFO"%s:%d " fmt, __func__, __LINE__, ##arg)
+
+#define audio_info(fmt, arg...) \
+ printk(KERN_INFO"%s:%d " fmt, __func__, __LINE__, ##arg)
+
+#else
+
+#define audio_debug(fmt, arg...)
+
+#define audio_info(fmt, arg...)
+
+#endif /* AUDIO_VERBOSE_DEBUG_ENABLE */
+
+#else
+
+#define audio_debug(fmt, arg...)
+
+#define audio_info(fmt, arg...)
+
+#endif /* AUDIO_DEBUG_ENABLE */
+
+#define audio_error(fmt, arg...) \
+ printk(KERN_ERR"%s:%d " fmt, __func__, __LINE__, ##arg)
+
+#define audio_warning(fmt, arg...) \
+ printk(KERN_WARNING"%s:%d " fmt, __func__, __LINE__, ##arg)
+
+#define audio_alert(fmt, arg...) \
+ printk(KERN_ALERT"%s:%d " fmt, __func__, __LINE__, ##arg)
+
+#define MAX_SUBSTREAMS (8)
+#define AVAIL_SUBSTREAMS_MASK (0xff)
+
+enum {
+ CTRL_VOL_MUTE,
+ CTRL_VOL_UNMUTE
+};
+
+/* macros for alsa2chip and chip2alsa, instead of functions */
+
+#define alsa2chip(vol) (uint)(-((vol << 8) / 100)) /* convert alsa to chip volume (defined as macro rather than function call) */
+#define chip2alsa(vol) -((vol * 100) >> 8) /* convert chip to alsa volume */
+
+/* Some constants for values .. */
+enum snd_bcm2835_route {
+ AUDIO_DEST_AUTO = 0,
+ AUDIO_DEST_HEADPHONES = 1,
+ AUDIO_DEST_HDMI = 2,
+ AUDIO_DEST_MAX,
+};
+
+enum snd_bcm2835_ctrl {
+ PCM_PLAYBACK_VOLUME,
+ PCM_PLAYBACK_MUTE,
+ PCM_PLAYBACK_DEVICE,
+};
+
+/* definition of the chip-specific record */
+struct bcm2835_chip {
+ struct snd_card *card;
+ struct snd_pcm *pcm;
+ struct snd_pcm *pcm_spdif;
+ /* Bitmat for valid reg_base and irq numbers */
+ unsigned int avail_substreams;
+ struct platform_device *pdev[MAX_SUBSTREAMS];
+ struct bcm2835_alsa_stream *alsa_stream[MAX_SUBSTREAMS];
+
+ int volume;
+ int old_volume; /* stores the volume value whist muted */
+ int dest;
+ int mute;
+
+ unsigned int opened;
+ unsigned int spdif_status;
+ struct mutex audio_mutex;
+};
+
+struct bcm2835_alsa_stream {
+ struct bcm2835_chip *chip;
+ struct snd_pcm_substream *substream;
+ struct snd_pcm_indirect pcm_indirect;
+
+ struct semaphore buffers_update_sem;
+ struct semaphore control_sem;
+ spinlock_t lock;
+ volatile unsigned int control;
+ volatile unsigned int status;
+
+ int open;
+ int running;
+ int draining;
+
+ int channels;
+ int params_rate;
+ int pcm_format_width;
+
+ unsigned int pos;
+ unsigned int buffer_size;
+ unsigned int period_size;
+
+ atomic_t retrieved;
+ struct bcm2835_audio_instance *instance;
+ struct workqueue_struct *my_wq;
+ int idx;
+};
+
+int snd_bcm2835_new_ctl(struct bcm2835_chip *chip);
+int snd_bcm2835_new_pcm(struct bcm2835_chip *chip);
+int snd_bcm2835_new_spdif_pcm(struct bcm2835_chip *chip);
+
+int bcm2835_audio_open(struct bcm2835_alsa_stream *alsa_stream);
+int bcm2835_audio_close(struct bcm2835_alsa_stream *alsa_stream);
+int bcm2835_audio_set_params(struct bcm2835_alsa_stream *alsa_stream,
+ unsigned int channels, unsigned int samplerate,
+ unsigned int bps);
+int bcm2835_audio_setup(struct bcm2835_alsa_stream *alsa_stream);
+int bcm2835_audio_start(struct bcm2835_alsa_stream *alsa_stream);
+int bcm2835_audio_stop(struct bcm2835_alsa_stream *alsa_stream);
+int bcm2835_audio_set_ctls(struct bcm2835_chip *chip);
+int bcm2835_audio_write(struct bcm2835_alsa_stream *alsa_stream,
+ unsigned int count,
+ void *src);
+void bcm2835_playback_fifo(struct bcm2835_alsa_stream *alsa_stream);
+unsigned int bcm2835_audio_retrieve_buffers(struct bcm2835_alsa_stream *alsa_stream);
+void bcm2835_audio_flush_buffers(struct bcm2835_alsa_stream *alsa_stream);
+void bcm2835_audio_flush_playback_buffers(struct bcm2835_alsa_stream *alsa_stream);
+
+#endif /* __SOUND_ARM_BCM2835_H */
--- /dev/null
+/*****************************************************************************
+ * Copyright 2011 Broadcom Corporation. All rights reserved.
+ *
+ * Unless you and Broadcom execute a separate written software license
+ * agreement governing use of this software, this software is licensed to you
+ * under the terms of the GNU General Public License version 2, available at
+ * http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
+ *
+ * Notwithstanding the above, under no circumstances may you combine this
+ * software in any way with any other Broadcom software provided under a
+ * license other than the GPL, without Broadcom's express prior written
+ * consent.
+ *****************************************************************************/
+
+#ifndef _VC_AUDIO_DEFS_H_
+#define _VC_AUDIO_DEFS_H_
+
+#define VC_AUDIOSERV_MIN_VER 1
+#define VC_AUDIOSERV_VER 2
+
+/* FourCC code used for VCHI connection */
+#define VC_AUDIO_SERVER_NAME MAKE_FOURCC("AUDS")
+
+/* Maximum message length */
+#define VC_AUDIO_MAX_MSG_LEN (sizeof(VC_AUDIO_MSG_T))
+
+/*
+ * List of screens that are currently supported
+ * All message types supported for HOST->VC direction
+ */
+
+enum vc_audio_msg_type {
+ VC_AUDIO_MSG_TYPE_RESULT, // Generic result
+ VC_AUDIO_MSG_TYPE_COMPLETE, // Generic result
+ VC_AUDIO_MSG_TYPE_CONFIG, // Configure audio
+ VC_AUDIO_MSG_TYPE_CONTROL, // Configure audio
+ VC_AUDIO_MSG_TYPE_OPEN, // Configure audio
+ VC_AUDIO_MSG_TYPE_CLOSE, // Configure audio
+ VC_AUDIO_MSG_TYPE_START, // Configure audio
+ VC_AUDIO_MSG_TYPE_STOP, // Configure audio
+ VC_AUDIO_MSG_TYPE_WRITE, // Configure audio
+ VC_AUDIO_MSG_TYPE_MAX
+};
+
+/* configure the audio */
+
+struct vc_audio_config {
+ u32 channels;
+ u32 samplerate;
+ u32 bps;
+};
+
+struct vc_audio_control {
+ u32 volume;
+ u32 dest;
+};
+
+struct vc_audio_open {
+ u32 dummy;
+};
+
+struct vc_audio_close {
+ u32 dummy;
+};
+
+struct vc_audio_start {
+ u32 dummy;
+};
+
+struct vc_audio_stop {
+ u32 draining;
+};
+
+/* configure the write audio samples */
+struct vc_audio_write {
+ u32 count; // in bytes
+ u32 cookie1;
+ u32 cookie2;
+ s16 silence;
+ s16 max_packet;
+};
+
+/* Generic result for a request (VC->HOST) */
+struct vc_audio_result {
+ s32 success; // Success value
+};
+
+/* Generic result for a request (VC->HOST) */
+struct vc_audio_complete {
+ s32 count; // Success value
+ u32 cookie1;
+ u32 cookie2;
+};
+
+/* Message header for all messages in HOST->VC direction */
+struct vc_audio_msg {
+ s32 type; /* Message type (VC_AUDIO_MSG_TYPE) */
+ union {
+ struct vc_audio_config config;
+ struct vc_audio_control control;
+ struct vc_audio_open open;
+ struct vc_audio_close close;
+ struct vc_audio_start start;
+ struct vc_audio_stop stop;
+ struct vc_audio_write write;
+ struct vc_audio_result result;
+ struct vc_audio_complete complete;
+ } u;
+};
+
+#endif /* _VC_AUDIO_DEFS_H_ */
select COMEDI_NI_TIOCMD
---help---
Enable support for National Instruments PCI-6601 (ni_660x), PCI-6602,
- PXI-6602, PXI-6608 and PXI-6624.
+ PXI-6602, PXI-6608, PCI-6624, and PXI-6624.
To compile this driver as a module, choose M here: the module will be
called ni_660x.
PCI-MIO-16E-4, PCI-6014, PCI-6040E, PXI-6040E, PCI-6030E, PCI-6031E,
PCI-6032E, PCI-6033E, PCI-6071E, PCI-6023E, PCI-6024E, PCI-6025E,
PXI-6025E, PCI-6034E, PCI-6035E, PCI-6052E, PCI-6110, PCI-6111,
- PCI-6220, PCI-6221, PCI-6224, PXI-6224, PCI-6225, PXI-6225, PCI-6229,
- PCI-6250, PCI-6251, PCIe-6251, PCI-6254, PCI-6259, PCIe-6259,
- PCI-6280, PCI-6281, PXI-6281, PCI-6284, PCI-6289, PCI-6711, PXI-6711,
+ PCI-6220, PXI-6220, PCI-6221, PXI-6221, PCI-6224, PXI-6224, PCI-6225,
+ PXI-6225, PCI-6229, PXI-6229, PCI-6250, PXI-6250, PCI-6251, PXI-6251,
+ PCIe-6251, PXIe-6251, PCI-6254, PXI-6254, PCI-6259, PXI-6259,
+ PCIe-6259, PXIe-6259, PCI-6280, PXI-6280, PCI-6281, PXI-6281,
+ PCI-6284, PXI-6284, PCI-6289, PXI-6289, PCI-6711, PXI-6711,
PCI-6713, PXI-6713, PXI-6071E, PCI-6070E, PXI-6070E, PXI-6052E,
PCI-6036E, PCI-6731, PCI-6733, PXI-6733, PCI-6143, PXI-6143
#ifdef CONFIG_COMPAT
struct file;
-long comedi_compat_ioctl(struct file *, unsigned int cmd, unsigned long arg);
+long comedi_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg);
#else /* CONFIG_COMPAT */
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/slab.h>
-#include <linux/kmod.h>
#include <linux/poll.h>
-#include <linux/init.h>
#include <linux/device.h>
-#include <linux/vmalloc.h>
#include <linux/fs.h>
#include "comedidev.h"
#include <linux/cdev.h>
-#include <linux/stat.h>
#include <linux/io.h>
#include <linux/uaccess.h>
comedi_class->dev_groups = comedi_dev_groups;
- /* XXX requires /proc interface */
- comedi_proc_init();
-
/* create devices files for legacy/manual use */
for (i = 0; i < comedi_num_legacy_minors; i++) {
struct comedi_device *dev;
mutex_unlock(&dev->mutex);
}
+ /* XXX requires /proc interface */
+ comedi_proc_init();
+
return 0;
}
module_init(comedi_init);
extern struct comedi_driver *comedi_drivers;
extern struct mutex comedi_drivers_list_lock;
-int insn_inval(struct comedi_device *, struct comedi_subdevice *,
- struct comedi_insn *, unsigned int *);
+int insn_inval(struct comedi_device *dev, struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data);
-void comedi_device_detach(struct comedi_device *);
-int comedi_device_attach(struct comedi_device *, struct comedi_devconfig *);
+void comedi_device_detach(struct comedi_device *dev);
+int comedi_device_attach(struct comedi_device *dev,
+ struct comedi_devconfig *it);
#ifdef CONFIG_PROC_FS
#define PCI_VENDOR_ID_RTD 0x1435
#define PCI_VENDOR_ID_HUMUSOFT 0x186c
-struct pci_dev *comedi_to_pci_dev(struct comedi_device *);
+struct pci_dev *comedi_to_pci_dev(struct comedi_device *dev);
-int comedi_pci_enable(struct comedi_device *);
-void comedi_pci_disable(struct comedi_device *);
-void comedi_pci_detach(struct comedi_device *);
+int comedi_pci_enable(struct comedi_device *dev);
+void comedi_pci_disable(struct comedi_device *dev);
+void comedi_pci_detach(struct comedi_device *dev);
-int comedi_pci_auto_config(struct pci_dev *, struct comedi_driver *,
+int comedi_pci_auto_config(struct pci_dev *pcidev, struct comedi_driver *driver,
unsigned long context);
-void comedi_pci_auto_unconfig(struct pci_dev *);
+void comedi_pci_auto_unconfig(struct pci_dev *pcidev);
-int comedi_pci_driver_register(struct comedi_driver *, struct pci_driver *);
-void comedi_pci_driver_unregister(struct comedi_driver *, struct pci_driver *);
+int comedi_pci_driver_register(struct comedi_driver *comedi_driver,
+ struct pci_driver *pci_driver);
+void comedi_pci_driver_unregister(struct comedi_driver *comedi_driver,
+ struct pci_driver *pci_driver);
/**
* module_comedi_pci_driver() - Helper macro for registering a comedi PCI driver
* or a negative error number from pcmcia_enable_device() if it fails.
*/
int comedi_pcmcia_enable(struct comedi_device *dev,
- int (*conf_check)(struct pcmcia_device *, void *))
+ int (*conf_check)(struct pcmcia_device *p_dev,
+ void *priv_data))
{
struct pcmcia_device *link = comedi_to_pcmcia_dev(dev);
int ret;
#include "comedidev.h"
-struct pcmcia_device *comedi_to_pcmcia_dev(struct comedi_device *);
+struct pcmcia_device *comedi_to_pcmcia_dev(struct comedi_device *dev);
-int comedi_pcmcia_enable(struct comedi_device *,
- int (*conf_check)(struct pcmcia_device *, void *));
-void comedi_pcmcia_disable(struct comedi_device *);
+int comedi_pcmcia_enable(struct comedi_device *dev,
+ int (*conf_check)(struct pcmcia_device *p_dev,
+ void *priv_data));
+void comedi_pcmcia_disable(struct comedi_device *dev);
-int comedi_pcmcia_auto_config(struct pcmcia_device *, struct comedi_driver *);
-void comedi_pcmcia_auto_unconfig(struct pcmcia_device *);
+int comedi_pcmcia_auto_config(struct pcmcia_device *link,
+ struct comedi_driver *driver);
+void comedi_pcmcia_auto_unconfig(struct pcmcia_device *link);
-int comedi_pcmcia_driver_register(struct comedi_driver *,
- struct pcmcia_driver *);
-void comedi_pcmcia_driver_unregister(struct comedi_driver *,
- struct pcmcia_driver *);
+int comedi_pcmcia_driver_register(struct comedi_driver *comedi_driver,
+ struct pcmcia_driver *pcmcia_driver);
+void comedi_pcmcia_driver_unregister(struct comedi_driver *comedi_driver,
+ struct pcmcia_driver *pcmcia_driver);
/**
* module_comedi_pcmcia_driver() - Helper macro for registering a comedi
#include "comedidev.h"
-struct usb_interface *comedi_to_usb_interface(struct comedi_device *);
-struct usb_device *comedi_to_usb_dev(struct comedi_device *);
+struct usb_interface *comedi_to_usb_interface(struct comedi_device *dev);
+struct usb_device *comedi_to_usb_dev(struct comedi_device *dev);
-int comedi_usb_auto_config(struct usb_interface *, struct comedi_driver *,
- unsigned long context);
-void comedi_usb_auto_unconfig(struct usb_interface *);
+int comedi_usb_auto_config(struct usb_interface *intf,
+ struct comedi_driver *driver, unsigned long context);
+void comedi_usb_auto_unconfig(struct usb_interface *intf);
-int comedi_usb_driver_register(struct comedi_driver *, struct usb_driver *);
-void comedi_usb_driver_unregister(struct comedi_driver *, struct usb_driver *);
+int comedi_usb_driver_register(struct comedi_driver *comedi_driver,
+ struct usb_driver *usb_driver);
+void comedi_usb_driver_unregister(struct comedi_driver *comedi_driver,
+ struct usb_driver *usb_driver);
/**
* module_comedi_usb_driver() - Helper macro for registering a comedi USB driver
#define range_digital range_unipolar5
-#if __GNUC__ >= 3
-#define GCC_ZERO_LENGTH_ARRAY
-#else
-#define GCC_ZERO_LENGTH_ARRAY 0
-#endif
-
/**
* struct comedi_lrange - Describes a COMEDI range table
* @length: Number of entries in the range table.
*/
struct comedi_lrange {
int length;
- struct comedi_krange range[GCC_ZERO_LENGTH_ARRAY];
+ struct comedi_krange range[];
};
/**
#define COMEDI_TIMEOUT_MS 1000
-int comedi_timeout(struct comedi_device *, struct comedi_subdevice *,
- struct comedi_insn *,
- int (*cb)(struct comedi_device *, struct comedi_subdevice *,
- struct comedi_insn *, unsigned long context),
+int comedi_timeout(struct comedi_device *dev, struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ int (*cb)(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned long context),
unsigned long context);
unsigned int comedi_handle_events(struct comedi_device *dev,
struct comedi_subdevice *s);
-int comedi_dio_insn_config(struct comedi_device *, struct comedi_subdevice *,
- struct comedi_insn *, unsigned int *data,
+int comedi_dio_insn_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data,
unsigned int mask);
-unsigned int comedi_dio_update_state(struct comedi_subdevice *,
+unsigned int comedi_dio_update_state(struct comedi_subdevice *s,
unsigned int *data);
unsigned int comedi_bytes_per_scan(struct comedi_subdevice *s);
unsigned int comedi_nscans_left(struct comedi_subdevice *s,
void comedi_inc_scan_progress(struct comedi_subdevice *s,
unsigned int num_bytes);
-void *comedi_alloc_devpriv(struct comedi_device *, size_t);
-int comedi_alloc_subdevices(struct comedi_device *, int);
-int comedi_alloc_subdev_readback(struct comedi_subdevice *);
+void *comedi_alloc_devpriv(struct comedi_device *dev, size_t size);
+int comedi_alloc_subdevices(struct comedi_device *dev, int num_subdevices);
+int comedi_alloc_subdev_readback(struct comedi_subdevice *s);
-int comedi_readback_insn_read(struct comedi_device *, struct comedi_subdevice *,
- struct comedi_insn *, unsigned int *data);
+int comedi_readback_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data);
-int comedi_load_firmware(struct comedi_device *, struct device *,
+int comedi_load_firmware(struct comedi_device *dev, struct device *hw_dev,
const char *name,
- int (*cb)(struct comedi_device *,
+ int (*cb)(struct comedi_device *dev,
const u8 *data, size_t size,
unsigned long context),
unsigned long context);
-int __comedi_request_region(struct comedi_device *,
+int __comedi_request_region(struct comedi_device *dev,
unsigned long start, unsigned long len);
-int comedi_request_region(struct comedi_device *,
+int comedi_request_region(struct comedi_device *dev,
unsigned long start, unsigned long len);
-void comedi_legacy_detach(struct comedi_device *);
+void comedi_legacy_detach(struct comedi_device *dev);
-int comedi_auto_config(struct device *, struct comedi_driver *,
- unsigned long context);
-void comedi_auto_unconfig(struct device *);
+int comedi_auto_config(struct device *hardware_device,
+ struct comedi_driver *driver, unsigned long context);
+void comedi_auto_unconfig(struct device *hardware_device);
-int comedi_driver_register(struct comedi_driver *);
-void comedi_driver_unregister(struct comedi_driver *);
+int comedi_driver_register(struct comedi_driver *driver);
+void comedi_driver_unregister(struct comedi_driver *driver);
/**
* module_comedi_driver() - Helper macro for registering a comedi driver
struct comedi_subdevice;
void addi_watchdog_reset(unsigned long iobase);
-int addi_watchdog_init(struct comedi_subdevice *, unsigned long iobase);
+int addi_watchdog_init(struct comedi_subdevice *s, unsigned long iobase);
#endif
EXT_START_TRIG_BNC_BIT = 0x2000,
};
-static inline uint16_t analog_trig_low_threshold_bits(uint16_t threshold)
+static inline u16 analog_trig_low_threshold_bits(u16 threshold)
{
return threshold & 0xfff;
}
ADC_MODE_MASK = 0xf000,
};
-static inline uint16_t adc_lo_chan_4020_bits(unsigned int channel)
+static inline u16 adc_lo_chan_4020_bits(unsigned int channel)
{
return (channel & 0x3) << 8;
};
-static inline uint16_t adc_hi_chan_4020_bits(unsigned int channel)
+static inline u16 adc_hi_chan_4020_bits(unsigned int channel)
{
return (channel & 0x3) << 10;
};
-static inline uint16_t adc_mode_bits(unsigned int mode)
+static inline u16 adc_mode_bits(unsigned int mode)
{
return (mode & 0xf) << 12;
};
* 7 : dac channel 1
*/
-static inline uint16_t adc_src_bits(unsigned int source)
+static inline u16 adc_src_bits(unsigned int source)
{
return (source & 0xf) << 3;
};
-static inline uint16_t adc_convert_chan_4020_bits(unsigned int channel)
+static inline u16 adc_convert_chan_4020_bits(unsigned int channel)
{
return (channel & 0x3) << 8;
};
QUEUE_EOSCAN_BIT = 0x8000, /* queue end of scan */
};
-static inline uint16_t adc_chan_bits(unsigned int channel)
+static inline u16 adc_chan_bits(unsigned int channel)
{
return channel & 0x3f;
};
ADC_STOP_BIT = 0x200,
};
-static inline uint16_t pipe_full_bits(uint16_t hw_status_bits)
+static inline u16 pipe_full_bits(u16 hw_status_bits)
{
return (hw_status_bits >> 10) & 0x3;
};
-static inline unsigned int dma_chain_flag_bits(uint16_t prepost_bits)
+static inline unsigned int dma_chain_flag_bits(u16 prepost_bits)
{
return (prepost_bits >> 6) & 0x3;
}
-static inline unsigned int adc_upper_read_ptr_code(uint16_t prepost_bits)
+static inline unsigned int adc_upper_read_ptr_code(u16 prepost_bits)
{
return (prepost_bits >> 12) & 0x3;
}
-static inline unsigned int adc_upper_write_ptr_code(uint16_t prepost_bits)
+static inline unsigned int adc_upper_write_ptr_code(u16 prepost_bits)
{
return (prepost_bits >> 14) & 0x3;
}
BNC_TRIG_THRESHOLD_0V_BIT = 0x80,
};
-static inline uint8_t adc_src_4020_bits(unsigned int source)
+static inline u8 adc_src_4020_bits(unsigned int source)
{
return (source << 4) & ADC_SRC_4020_MASK;
};
-static inline uint8_t attenuate_bit(unsigned int channel)
+static inline u8 attenuate_bit(unsigned int channel)
{
/* attenuate channel (+-5V input range) */
return 1 << (channel & 0x3);
}
};
-static const uint8_t ai_range_code_64xx[8] = {
+static const u8 ai_range_code_64xx[8] = {
0x0, 0x1, 0x2, 0x3, /* bipolar 10, 5, 2,5, 1.25 */
0x8, 0x9, 0xa, 0xb /* unipolar 10, 5, 2.5, 1.25 */
};
}
};
-static const uint8_t ai_range_code_64_mx[7] = {
+static const u8 ai_range_code_64_mx[7] = {
0x0, 0x1, 0x2, 0x3, /* bipolar 5, 2.5, 1.25, 0.625 */
0x9, 0xa, 0xb /* unipolar 5, 2.5, 1.25 */
};
}
};
-static const uint8_t ai_range_code_60xx[4] = {
+static const u8 ai_range_code_60xx[4] = {
0x0, 0x1, 0x4, 0x7 /* bipolar 10, 5, 0.5, 0.05 */
};
}
};
-static const uint8_t ai_range_code_6030[14] = {
+static const u8 ai_range_code_6030[14] = {
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, /* bip 10, 5, 2, 1, 0.5, 0.2, 0.1 */
0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* uni 10, 5, 2, 1, 0.5, 0.2, 0.1 */
};
}
};
-static const uint8_t ai_range_code_6052[15] = {
+static const u8 ai_range_code_6052[15] = {
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, /* bipolar 10 ... 0.05 */
0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* unipolar 10 ... 0.1 */
};
unsigned int num_segments;
unsigned int max_segment_length;
unsigned int sample_packing_ratio;
- uint16_t fifo_size_reg_mask;
+ u16 fifo_size_reg_mask;
};
enum pcidas64_boardid {
int ai_bits; /* analog input resolution */
int ai_speed; /* fastest conversion period in ns */
const struct comedi_lrange *ai_range_table;
- const uint8_t *ai_range_code;
+ const u8 *ai_range_code;
int ao_nchan; /* number of analog out channels */
int ao_bits; /* analog output resolution */
int ao_scan_speed; /* analog output scan speed */
void __iomem *plx9080_iobase;
void __iomem *main_iobase;
/* local address (used by dma controller) */
- uint32_t local0_iobase;
- uint32_t local1_iobase;
+ u32 local0_iobase;
+ u32 local1_iobase;
/* dma buffers for analog input */
- uint16_t *ai_buffer[MAX_AI_DMA_RING_COUNT];
+ u16 *ai_buffer[MAX_AI_DMA_RING_COUNT];
/* physical addresses of ai dma buffers */
dma_addr_t ai_buffer_bus_addr[MAX_AI_DMA_RING_COUNT];
/*
*/
unsigned int ai_dma_index;
/* dma buffers for analog output */
- uint16_t *ao_buffer[AO_DMA_RING_COUNT];
+ u16 *ao_buffer[AO_DMA_RING_COUNT];
/* physical addresses of ao dma buffers */
dma_addr_t ao_buffer_bus_addr[AO_DMA_RING_COUNT];
struct plx_dma_desc *ao_dma_desc;
/* last bits sent to INTR_ENABLE_REG register */
unsigned int intr_enable_bits;
/* last bits sent to ADC_CONTROL1_REG register */
- uint16_t adc_control1_bits;
+ u16 adc_control1_bits;
/* last bits sent to FIFO_SIZE_REG register */
- uint16_t fifo_size_bits;
+ u16 fifo_size_bits;
/* last bits sent to HW_CONFIG_REG register */
- uint16_t hw_config_bits;
- uint16_t dac_control1_bits;
+ u16 hw_config_bits;
+ u16 dac_control1_bits;
/* last bits written to plx9080 control register */
- uint32_t plx_control_bits;
+ u32 plx_control_bits;
/* last bits written to plx interrupt control and status register */
- uint32_t plx_intcsr_bits;
+ u32 plx_intcsr_bits;
/* index of calibration source readable through ai ch0 */
int calibration_source;
/* bits written to i2c calibration/range register */
- uint8_t i2c_cal_range_bits;
+ u8 i2c_cal_range_bits;
/* configure digital triggers to trigger on falling edge */
unsigned int ext_trig_falling;
short ai_cmd_running;
}
static unsigned int hw_revision(const struct comedi_device *dev,
- uint16_t hw_status_bits)
+ u16 hw_status_bits)
{
const struct pcidas64_board *board = dev->board_ptr;
}
static void set_dac_range_bits(struct comedi_device *dev,
- uint16_t *bits, unsigned int channel,
+ u16 *bits, unsigned int channel,
unsigned int range)
{
const struct pcidas64_board *board = dev->board_ptr;
{
const struct pcidas64_board *board = dev->board_ptr;
struct pcidas64_private *devpriv = dev->private;
- uint32_t bits;
+ u32 bits;
unsigned long flags;
bits = EN_ADC_OVERRUN_BIT | EN_ADC_DONE_INTR_BIT |
{
const struct pcidas64_board *board = dev->board_ptr;
struct pcidas64_private *devpriv = dev->private;
- uint32_t bits;
+ u32 bits;
void __iomem *plx_iobase = devpriv->plx9080_iobase;
devpriv->plx_control_bits =
static const int increment_size = 0x100;
const struct hw_fifo_info *const fifo = board->ai_fifo;
unsigned int num_increments;
- uint16_t bits;
+ u16 bits;
if (num_entries < increment_size)
num_entries = increment_size;
{
const struct pcidas64_board *board = dev->board_ptr;
struct pcidas64_private *devpriv = dev->private;
- uint16_t bits;
+ u16 bits;
unsigned long flags;
spin_lock_irqsave(&dev->spinlock, flags);
}
}
-static void i2c_write_byte(struct comedi_device *dev, uint8_t byte)
+static void i2c_write_byte(struct comedi_device *dev, u8 byte)
{
- uint8_t bit;
+ u8 bit;
unsigned int num_bits = 8;
for (bit = 1 << (num_bits - 1); bit; bit >>= 1) {
}
static void i2c_write(struct comedi_device *dev, unsigned int address,
- const uint8_t *data, unsigned int length)
+ const u8 *data, unsigned int length)
{
struct pcidas64_private *devpriv = dev->private;
unsigned int i;
- uint8_t bitstream;
+ u8 bitstream;
static const int read_bit = 0x1;
/*
/* set start channel, and rest of settings */
writew(bits, devpriv->main_iobase + ADC_QUEUE_LOAD_REG);
} else {
- uint8_t old_cal_range_bits = devpriv->i2c_cal_range_bits;
+ u8 old_cal_range_bits = devpriv->i2c_cal_range_bits;
devpriv->i2c_cal_range_bits &= ~ADC_SRC_4020_MASK;
if (insn->chanspec & CR_ALT_SOURCE) {
* as it is very slow
*/
if (old_cal_range_bits != devpriv->i2c_cal_range_bits) {
- uint8_t i2c_data = devpriv->i2c_cal_range_bits;
+ u8 i2c_data = devpriv->i2c_cal_range_bits;
i2c_write(dev, RANGE_CAL_I2C_ADDR, &i2c_data,
sizeof(i2c_data));
num_samples = devpriv->ai_fifo_segment_length *
board->ai_fifo->sample_packing_ratio;
- if (num_samples > DMA_BUFFER_SIZE / sizeof(uint16_t))
- num_samples = DMA_BUFFER_SIZE / sizeof(uint16_t);
+ if (num_samples > DMA_BUFFER_SIZE / sizeof(u16))
+ num_samples = DMA_BUFFER_SIZE / sizeof(u16);
return num_samples;
}
-static uint32_t ai_convert_counter_6xxx(const struct comedi_device *dev,
+static u32 ai_convert_counter_6xxx(const struct comedi_device *dev,
const struct comedi_cmd *cmd)
{
/* supposed to load counter with desired divisor minus 3 */
return cmd->convert_arg / TIMER_BASE - 3;
}
-static uint32_t ai_scan_counter_6xxx(struct comedi_device *dev,
+static u32 ai_scan_counter_6xxx(struct comedi_device *dev,
struct comedi_cmd *cmd)
{
- uint32_t count;
+ u32 count;
/* figure out how long we need to delay at end of scan */
switch (cmd->scan_begin_src) {
return count - 3;
}
-static uint32_t ai_convert_counter_4020(struct comedi_device *dev,
+static u32 ai_convert_counter_4020(struct comedi_device *dev,
struct comedi_cmd *cmd)
{
struct pcidas64_private *devpriv = dev->private;
{
const struct pcidas64_board *board = dev->board_ptr;
struct pcidas64_private *devpriv = dev->private;
- uint32_t convert_counter = 0, scan_counter = 0;
+ u32 convert_counter = 0, scan_counter = 0;
check_adc_timing(dev, cmd);
* as it is very slow
*/
if (old_cal_range_bits != devpriv->i2c_cal_range_bits) {
- uint8_t i2c_data = devpriv->i2c_cal_range_bits;
+ u8 i2c_data = devpriv->i2c_cal_range_bits;
i2c_write(dev, RANGE_CAL_I2C_ADDR, &i2c_data,
sizeof(i2c_data));
struct pcidas64_private *devpriv = dev->private;
struct comedi_async *async = s->async;
struct comedi_cmd *cmd = &async->cmd;
- uint32_t bits;
+ u32 bits;
unsigned int i;
unsigned long flags;
int retval;
for (i = 0; i < ai_dma_ring_count(board); i++)
devpriv->ai_dma_desc[i].transfer_size =
cpu_to_le32(dma_transfer_size(dev) *
- sizeof(uint16_t));
+ sizeof(u16));
/* give location of first dma descriptor */
load_first_dma_descriptor(dev, 1,
struct pcidas64_private *devpriv = dev->private;
struct comedi_subdevice *s = dev->read_subdev;
unsigned int i;
- uint16_t prepost_bits;
+ u16 prepost_bits;
int read_segment, read_index, write_segment, write_index;
int num_samples;
struct comedi_subdevice *s = dev->read_subdev;
unsigned int nsamples;
unsigned int i;
- uint32_t fifo_data;
+ u32 fifo_data;
int write_code =
readw(devpriv->main_iobase + ADC_WRITE_PNTR_REG) & 0x7fff;
int read_code =
const struct pcidas64_board *board = dev->board_ptr;
struct pcidas64_private *devpriv = dev->private;
struct comedi_subdevice *s = dev->read_subdev;
- uint32_t next_transfer_addr;
+ u32 next_transfer_addr;
int j;
int num_samples = 0;
void __iomem *pci_addr_reg;
struct comedi_subdevice *s = dev->read_subdev;
struct comedi_async *async = s->async;
struct comedi_cmd *cmd = &async->cmd;
- uint8_t dma1_status;
+ u8 dma1_status;
unsigned long flags;
/* check for fifo overrun */
struct comedi_subdevice *s = dev->write_subdev;
struct comedi_async *async;
struct comedi_cmd *cmd;
- uint8_t dma0_status;
+ u8 dma0_status;
unsigned long flags;
/* board might not support ao, in which case write_subdev is NULL */
struct comedi_device *dev = d;
struct pcidas64_private *devpriv = dev->private;
unsigned short status;
- uint32_t plx_status;
- uint32_t plx_bits;
+ u32 plx_status;
+ u32 plx_bits;
plx_status = readl(devpriv->plx9080_iobase + PLX_REG_INTCSR);
status = readw(devpriv->main_iobase + HW_STATUS_REG);
const struct comedi_cmd *cmd)
{
struct pcidas64_private *devpriv = dev->private;
- uint16_t bits;
+ u16 bits;
unsigned int first_channel, last_channel;
first_channel = CR_CHAN(cmd->chanlist[0]);
*/
static int caldac_8800_write(struct comedi_device *dev, unsigned int address,
- uint8_t value)
+ u8 value)
{
struct pcidas64_private *devpriv = dev->private;
static const int num_caldac_channels = 8;
static int caldac_i2c_write(struct comedi_device *dev,
unsigned int caldac_channel, unsigned int value)
{
- uint8_t serial_bytes[3];
- uint8_t i2c_addr;
+ u8 serial_bytes[3];
+ u8 i2c_addr;
enum pointer_bits {
/* manual has gain and offset bits switched */
OFFSET_0_2 = 0x1,
return insn->n;
}
-static uint16_t read_eeprom(struct comedi_device *dev, uint8_t address)
+static u16 read_eeprom(struct comedi_device *dev, u8 address)
{
struct pcidas64_private *devpriv = dev->private;
static const int bitstream_length = 11;
unsigned int bit;
void __iomem * const plx_control_addr =
devpriv->plx9080_iobase + PLX_REG_CNTRL;
- uint16_t value;
+ u16 value;
static const int value_length = 16;
static const int eeprom_udelay = 1;
s->do_cmdtest = ai_cmdtest;
s->cancel = ai_cancel;
if (board->layout == LAYOUT_4020) {
- uint8_t data;
+ u8 data;
/*
* set adc to read from inputs
* (not internal calibration sources)
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
const struct pcidas64_board *board = NULL;
struct pcidas64_private *devpriv;
- uint32_t local_range, local_decode;
+ u32 local_range, local_decode;
int retval;
if (context < ARRAY_SIZE(pcidas64_boards))
PLX_LASRR_MEM_MASK;
local_decode = readl(devpriv->plx9080_iobase + PLX_REG_LAS0BA) &
local_range & PLX_LASBA_MEM_MASK;
- devpriv->local0_iobase = ((uint32_t)devpriv->main_phys_iobase &
+ devpriv->local0_iobase = ((u32)devpriv->main_phys_iobase &
~local_range) | local_decode;
local_range = readl(devpriv->plx9080_iobase + PLX_REG_LAS1RR) &
PLX_LASRR_MEM_MASK;
local_decode = readl(devpriv->plx9080_iobase + PLX_REG_LAS1BA) &
local_range & PLX_LASBA_MEM_MASK;
- devpriv->local1_iobase = ((uint32_t)devpriv->dio_counter_phys_iobase &
+ devpriv->local1_iobase = ((u32)devpriv->dio_counter_phys_iobase &
~local_range) | local_decode;
retval = alloc_and_init_dma_members(dev);
unsigned int gate_src[3];
bool busy[3];
- int (*insn_config)(struct comedi_device *, struct comedi_subdevice *s,
- struct comedi_insn *, unsigned int *data);
+ int (*insn_config)(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data);
};
-unsigned int comedi_8254_status(struct comedi_8254 *, unsigned int counter);
-unsigned int comedi_8254_read(struct comedi_8254 *, unsigned int counter);
-void comedi_8254_write(struct comedi_8254 *,
+unsigned int comedi_8254_status(struct comedi_8254 *i8254,
+ unsigned int counter);
+unsigned int comedi_8254_read(struct comedi_8254 *i8254, unsigned int counter);
+void comedi_8254_write(struct comedi_8254 *i8254,
unsigned int counter, unsigned int val);
-int comedi_8254_set_mode(struct comedi_8254 *,
+int comedi_8254_set_mode(struct comedi_8254 *i8254,
unsigned int counter, unsigned int mode);
-int comedi_8254_load(struct comedi_8254 *,
+int comedi_8254_load(struct comedi_8254 *i8254,
unsigned int counter, unsigned int val, unsigned int mode);
-void comedi_8254_pacer_enable(struct comedi_8254 *,
+void comedi_8254_pacer_enable(struct comedi_8254 *i8254,
unsigned int counter1, unsigned int counter2,
bool enable);
-void comedi_8254_update_divisors(struct comedi_8254 *);
-void comedi_8254_cascade_ns_to_timer(struct comedi_8254 *,
+void comedi_8254_update_divisors(struct comedi_8254 *i8254);
+void comedi_8254_cascade_ns_to_timer(struct comedi_8254 *i8254,
unsigned int *nanosec, unsigned int flags);
-void comedi_8254_ns_to_timer(struct comedi_8254 *,
+void comedi_8254_ns_to_timer(struct comedi_8254 *i8254,
unsigned int *nanosec, unsigned int flags);
-void comedi_8254_set_busy(struct comedi_8254 *,
+void comedi_8254_set_busy(struct comedi_8254 *i8254,
unsigned int counter, bool busy);
-void comedi_8254_subdevice_init(struct comedi_subdevice *,
- struct comedi_8254 *);
+void comedi_8254_subdevice_init(struct comedi_subdevice *s,
+ struct comedi_8254 *i8254);
struct comedi_8254 *comedi_8254_init(unsigned long iobase,
unsigned int osc_base,
#if IS_ENABLED(CONFIG_ISA_DMA_API)
-void comedi_isadma_program(struct comedi_isadma_desc *);
+void comedi_isadma_program(struct comedi_isadma_desc *desc);
unsigned int comedi_isadma_disable(unsigned int dma_chan);
unsigned int comedi_isadma_disable_on_sample(unsigned int dma_chan,
unsigned int size);
-unsigned int comedi_isadma_poll(struct comedi_isadma *);
-void comedi_isadma_set_mode(struct comedi_isadma_desc *, char dma_dir);
+unsigned int comedi_isadma_poll(struct comedi_isadma *dma);
+void comedi_isadma_set_mode(struct comedi_isadma_desc *desc, char dma_dir);
-struct comedi_isadma *comedi_isadma_alloc(struct comedi_device *,
+struct comedi_isadma *comedi_isadma_alloc(struct comedi_device *dev,
int n_desc, unsigned int dma_chan1,
unsigned int dma_chan2,
unsigned int maxsize, char dma_dir);
-void comedi_isadma_free(struct comedi_isadma *);
+void comedi_isadma_free(struct comedi_isadma *dma);
#else /* !IS_ENABLED(CONFIG_ISA_DMA_API) */
#include "../comedi_pci.h"
#include "8255.h"
+#include "plx9080.h"
-#define DAQBOARD2000_FIRMWARE "daqboard2000_firmware.bin"
+#define DB2K_FIRMWARE "daqboard2000_firmware.bin"
-#define DAQBOARD2000_SUBSYSTEM_IDS2 0x0002 /* Daqboard/2000 - 2 Dacs */
-#define DAQBOARD2000_SUBSYSTEM_IDS4 0x0004 /* Daqboard/2000 - 4 Dacs */
-
-/* Initialization bits for the Serial EEPROM Control Register */
-#define DB2K_SECR_PROG_PIN_HI 0x8001767e
-#define DB2K_SECR_PROG_PIN_LO 0x8000767e
-#define DB2K_SECR_LOCAL_BUS_HI 0xc000767e
-#define DB2K_SECR_LOCAL_BUS_LO 0x8000767e
-#define DB2K_SECR_RELOAD_HI 0xa000767e
-#define DB2K_SECR_RELOAD_LO 0x8000767e
-
-/* SECR status bits */
-#define DAQBOARD2000_EEPROM_PRESENT 0x10000000
-
-/* CPLD status bits */
-#define DAQBOARD2000_CPLD_INIT 0x0002
-#define DAQBOARD2000_CPLD_DONE 0x0004
-
-static const struct comedi_lrange range_daqboard2000_ai = {
+static const struct comedi_lrange db2k_ai_range = {
13, {
BIP_RANGE(10),
BIP_RANGE(5),
#define DB2K_REG_TRIG_DACS 0xbc /* u16 */
#define DB2K_REG_DIO_P2_EXP_IO_16_BIT(x) (0xc0 + (x) * 2) /* s16 */
+/* CPLD registers */
+#define DB2K_REG_CPLD_STATUS 0x1000 /* u16 (r) */
+#define DB2K_REG_CPLD_WDATA 0x1000 /* u16 (w) */
+
/* Scan Sequencer programming */
#define DB2K_ACQ_CONTROL_SEQ_START_SCAN_LIST 0x0011
#define DB2K_ACQ_CONTROL_SEQ_STOP_SCAN_LIST 0x0010
#define DB2K_REF_DACS_SELECT_POS_REF 0x0100
#define DB2K_REF_DACS_SELECT_NEG_REF 0x0000
-struct daq200_boardtype {
+/* CPLD status bits */
+#define DB2K_CPLD_STATUS_INIT 0x0002
+#define DB2K_CPLD_STATUS_TXREADY 0x0004
+#define DB2K_CPLD_VERSION_MASK 0xf000
+/* "New CPLD" signature. */
+#define DB2K_CPLD_VERSION_NEW 0x5000
+
+enum db2k_boardid {
+ BOARD_DAQBOARD2000,
+ BOARD_DAQBOARD2001
+};
+
+struct db2k_boardtype {
const char *name;
- int id;
+ bool has_2_ao:1; /* false: 4 AO chans; true: 2 AO chans */
};
-static const struct daq200_boardtype boardtypes[] = {
- {"ids2", DAQBOARD2000_SUBSYSTEM_IDS2},
- {"ids4", DAQBOARD2000_SUBSYSTEM_IDS4},
+static const struct db2k_boardtype db2k_boardtypes[] = {
+ [BOARD_DAQBOARD2000] = {
+ .name = "daqboard2000",
+ .has_2_ao = true,
+ },
+ [BOARD_DAQBOARD2001] = {
+ .name = "daqboard2001",
+ },
};
-struct daqboard2000_private {
- enum {
- card_daqboard_2000
- } card;
+struct db2k_private {
void __iomem *plx;
};
-static void daqboard2000_write_acq_scan_list_entry(struct comedi_device *dev,
- u16 entry)
+static void db2k_write_acq_scan_list_entry(struct comedi_device *dev, u16 entry)
{
writew(entry & 0x00ff, dev->mmio + DB2K_REG_ACQ_SCAN_LIST_FIFO);
writew((entry >> 8) & 0x00ff,
dev->mmio + DB2K_REG_ACQ_SCAN_LIST_FIFO);
}
-static void daqboard2000_setup_sampling(struct comedi_device *dev, int chan,
- int gain)
+static void db2k_setup_sampling(struct comedi_device *dev, int chan, int gain)
{
u16 word0, word1, word2, word3;
/* These should be read from EEPROM */
word2 |= 0x0800; /* offset */
word3 |= 0xc000; /* gain */
- daqboard2000_write_acq_scan_list_entry(dev, word0);
- daqboard2000_write_acq_scan_list_entry(dev, word1);
- daqboard2000_write_acq_scan_list_entry(dev, word2);
- daqboard2000_write_acq_scan_list_entry(dev, word3);
+ db2k_write_acq_scan_list_entry(dev, word0);
+ db2k_write_acq_scan_list_entry(dev, word1);
+ db2k_write_acq_scan_list_entry(dev, word2);
+ db2k_write_acq_scan_list_entry(dev, word3);
}
-static int daqboard2000_ai_status(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned long context)
+static int db2k_ai_status(struct comedi_device *dev, struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned long context)
{
unsigned int status;
return -EBUSY;
}
-static int daqboard2000_ai_insn_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static int db2k_ai_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
{
int gain, chan;
int ret;
* forced to fix it. --ds
*/
for (i = 0; i < insn->n; i++) {
- daqboard2000_setup_sampling(dev, chan, gain);
+ db2k_setup_sampling(dev, chan, gain);
/* Enable reading from the scanlist FIFO */
writew(DB2K_ACQ_CONTROL_SEQ_START_SCAN_LIST,
dev->mmio + DB2K_REG_ACQ_CONTROL);
- ret = comedi_timeout(dev, s, insn, daqboard2000_ai_status,
+ ret = comedi_timeout(dev, s, insn, db2k_ai_status,
DB2K_ACQ_STATUS_CONFIG_PIPE_FULL);
if (ret)
return ret;
writew(DB2K_ACQ_CONTROL_ADC_PACER_ENABLE,
dev->mmio + DB2K_REG_ACQ_CONTROL);
- ret = comedi_timeout(dev, s, insn, daqboard2000_ai_status,
+ ret = comedi_timeout(dev, s, insn, db2k_ai_status,
DB2K_ACQ_STATUS_LOGIC_SCANNING);
if (ret)
return ret;
ret =
- comedi_timeout(dev, s, insn, daqboard2000_ai_status,
+ comedi_timeout(dev, s, insn, db2k_ai_status,
DB2K_ACQ_STATUS_RESULTS_FIFO_HAS_DATA);
if (ret)
return ret;
return i;
}
-static int daqboard2000_ao_eoc(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned long context)
+static int db2k_ao_eoc(struct comedi_device *dev, struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned long context)
{
unsigned int chan = CR_CHAN(insn->chanspec);
unsigned int status;
return -EBUSY;
}
-static int daqboard2000_ao_insn_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static int db2k_ao_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
{
unsigned int chan = CR_CHAN(insn->chanspec);
int i;
writew(val, dev->mmio + DB2K_REG_DAC_SETTING(chan));
- ret = comedi_timeout(dev, s, insn, daqboard2000_ao_eoc, 0);
+ ret = comedi_timeout(dev, s, insn, db2k_ao_eoc, 0);
if (ret)
return ret;
return insn->n;
}
-static void daqboard2000_reset_local_bus(struct comedi_device *dev)
+static void db2k_reset_local_bus(struct comedi_device *dev)
{
- struct daqboard2000_private *devpriv = dev->private;
+ struct db2k_private *devpriv = dev->private;
+ u32 cntrl;
- writel(DB2K_SECR_LOCAL_BUS_HI, devpriv->plx + 0x6c);
+ cntrl = readl(devpriv->plx + PLX_REG_CNTRL);
+ cntrl |= PLX_CNTRL_RESET;
+ writel(cntrl, devpriv->plx + PLX_REG_CNTRL);
mdelay(10);
- writel(DB2K_SECR_LOCAL_BUS_LO, devpriv->plx + 0x6c);
+ cntrl &= ~PLX_CNTRL_RESET;
+ writel(cntrl, devpriv->plx + PLX_REG_CNTRL);
mdelay(10);
}
-static void daqboard2000_reload_plx(struct comedi_device *dev)
+static void db2k_reload_plx(struct comedi_device *dev)
{
- struct daqboard2000_private *devpriv = dev->private;
+ struct db2k_private *devpriv = dev->private;
+ u32 cntrl;
- writel(DB2K_SECR_RELOAD_LO, devpriv->plx + 0x6c);
+ cntrl = readl(devpriv->plx + PLX_REG_CNTRL);
+ cntrl &= ~PLX_CNTRL_EERELOAD;
+ writel(cntrl, devpriv->plx + PLX_REG_CNTRL);
mdelay(10);
- writel(DB2K_SECR_RELOAD_HI, devpriv->plx + 0x6c);
+ cntrl |= PLX_CNTRL_EERELOAD;
+ writel(cntrl, devpriv->plx + PLX_REG_CNTRL);
mdelay(10);
- writel(DB2K_SECR_RELOAD_LO, devpriv->plx + 0x6c);
+ cntrl &= ~PLX_CNTRL_EERELOAD;
+ writel(cntrl, devpriv->plx + PLX_REG_CNTRL);
mdelay(10);
}
-static void daqboard2000_pulse_prog_pin(struct comedi_device *dev)
+static void db2k_pulse_prog_pin(struct comedi_device *dev)
{
- struct daqboard2000_private *devpriv = dev->private;
+ struct db2k_private *devpriv = dev->private;
+ u32 cntrl;
- writel(DB2K_SECR_PROG_PIN_HI, devpriv->plx + 0x6c);
+ cntrl = readl(devpriv->plx + PLX_REG_CNTRL);
+ cntrl |= PLX_CNTRL_USERO;
+ writel(cntrl, devpriv->plx + PLX_REG_CNTRL);
mdelay(10);
- writel(DB2K_SECR_PROG_PIN_LO, devpriv->plx + 0x6c);
+ cntrl &= ~PLX_CNTRL_USERO;
+ writel(cntrl, devpriv->plx + PLX_REG_CNTRL);
mdelay(10); /* Not in the original code, but I like symmetry... */
}
-static int daqboard2000_poll_cpld(struct comedi_device *dev, int mask)
+static int db2k_wait_cpld_init(struct comedi_device *dev)
{
- int result = 0;
+ int result = -ETIMEDOUT;
int i;
- int cpld;
+ u16 cpld;
/* timeout after 50 tries -> 5ms */
for (i = 0; i < 50; i++) {
- cpld = readw(dev->mmio + 0x1000);
- if ((cpld & mask) == mask) {
- result = 1;
+ cpld = readw(dev->mmio + DB2K_REG_CPLD_STATUS);
+ if (cpld & DB2K_CPLD_STATUS_INIT) {
+ result = 0;
break;
}
usleep_range(100, 1000);
return result;
}
-static int daqboard2000_write_cpld(struct comedi_device *dev, int data)
+static int db2k_wait_cpld_txready(struct comedi_device *dev)
+{
+ int i;
+
+ for (i = 0; i < 100; i++) {
+ if (readw(dev->mmio + DB2K_REG_CPLD_STATUS) &
+ DB2K_CPLD_STATUS_TXREADY) {
+ return 0;
+ }
+ udelay(1);
+ }
+ return -ETIMEDOUT;
+}
+
+static int db2k_write_cpld(struct comedi_device *dev, u16 data, bool new_cpld)
{
int result = 0;
- usleep_range(10, 20);
- writew(data, dev->mmio + 0x1000);
- if ((readw(dev->mmio + 0x1000) & DAQBOARD2000_CPLD_INIT) ==
- DAQBOARD2000_CPLD_INIT) {
- result = 1;
+ if (new_cpld) {
+ result = db2k_wait_cpld_txready(dev);
+ if (result)
+ return result;
+ } else {
+ usleep_range(10, 20);
}
+ writew(data, dev->mmio + DB2K_REG_CPLD_WDATA);
+ if (!(readw(dev->mmio + DB2K_REG_CPLD_STATUS) & DB2K_CPLD_STATUS_INIT))
+ result = -EIO;
+
return result;
}
-static int daqboard2000_load_firmware(struct comedi_device *dev,
- const u8 *cpld_array, size_t len,
- unsigned long context)
+static int db2k_wait_fpga_programmed(struct comedi_device *dev)
+{
+ struct db2k_private *devpriv = dev->private;
+ int i;
+
+ /* Time out after 200 tries -> 20ms */
+ for (i = 0; i < 200; i++) {
+ u32 cntrl = readl(devpriv->plx + PLX_REG_CNTRL);
+ /* General Purpose Input (USERI) set on FPGA "DONE". */
+ if (cntrl & PLX_CNTRL_USERI)
+ return 0;
+
+ usleep_range(100, 1000);
+ }
+ return -ETIMEDOUT;
+}
+
+static int db2k_load_firmware(struct comedi_device *dev, const u8 *cpld_array,
+ size_t len, unsigned long context)
{
- struct daqboard2000_private *devpriv = dev->private;
+ struct db2k_private *devpriv = dev->private;
int result = -EIO;
- /* Read the serial EEPROM control register */
- int secr;
+ u32 cntrl;
int retry;
size_t i;
+ bool new_cpld;
+
+ /* Look for FPGA start sequence in firmware. */
+ for (i = 0; i + 1 < len; i++) {
+ if (cpld_array[i] == 0xff && cpld_array[i + 1] == 0x20)
+ break;
+ }
+ if (i + 1 >= len) {
+ dev_err(dev->class_dev, "bad firmware - no start sequence\n");
+ return -EINVAL;
+ }
+ /* Check length is even. */
+ if ((len - i) & 1) {
+ dev_err(dev->class_dev,
+ "bad firmware - odd length (%zu = %zu - %zu)\n",
+ len - i, len, i);
+ return -EINVAL;
+ }
+ /* Strip firmware header. */
+ cpld_array += i;
+ len -= i;
/* Check to make sure the serial eeprom is present on the board */
- secr = readl(devpriv->plx + 0x6c);
- if (!(secr & DAQBOARD2000_EEPROM_PRESENT))
+ cntrl = readl(devpriv->plx + PLX_REG_CNTRL);
+ if (!(cntrl & PLX_CNTRL_EEPRESENT))
return -EIO;
for (retry = 0; retry < 3; retry++) {
- daqboard2000_reset_local_bus(dev);
- daqboard2000_reload_plx(dev);
- daqboard2000_pulse_prog_pin(dev);
- if (daqboard2000_poll_cpld(dev, DAQBOARD2000_CPLD_INIT)) {
- for (i = 0; i < len; i++) {
- if (cpld_array[i] == 0xff &&
- cpld_array[i + 1] == 0x20)
- break;
- }
- for (; i < len; i += 2) {
- int data =
- (cpld_array[i] << 8) + cpld_array[i + 1];
- if (!daqboard2000_write_cpld(dev, data))
- break;
- }
- if (i >= len) {
- daqboard2000_reset_local_bus(dev);
- daqboard2000_reload_plx(dev);
- result = 0;
+ db2k_reset_local_bus(dev);
+ db2k_reload_plx(dev);
+ db2k_pulse_prog_pin(dev);
+ result = db2k_wait_cpld_init(dev);
+ if (result)
+ continue;
+
+ new_cpld = (readw(dev->mmio + DB2K_REG_CPLD_STATUS) &
+ DB2K_CPLD_VERSION_MASK) == DB2K_CPLD_VERSION_NEW;
+ for (; i < len; i += 2) {
+ u16 data = (cpld_array[i] << 8) + cpld_array[i + 1];
+
+ result = db2k_write_cpld(dev, data, new_cpld);
+ if (result)
break;
- }
+ }
+ if (result == 0)
+ result = db2k_wait_fpga_programmed(dev);
+ if (result == 0) {
+ db2k_reset_local_bus(dev);
+ db2k_reload_plx(dev);
+ break;
}
}
return result;
}
-static void daqboard2000_adc_stop_dma_transfer(struct comedi_device *dev)
+static void db2k_adc_stop_dma_transfer(struct comedi_device *dev)
{
}
-static void daqboard2000_adc_disarm(struct comedi_device *dev)
+static void db2k_adc_disarm(struct comedi_device *dev)
{
/* Disable hardware triggers */
udelay(2);
dev->mmio + DB2K_REG_ACQ_CONTROL);
/* Stop the input dma (abort channel 1) */
- daqboard2000_adc_stop_dma_transfer(dev);
+ db2k_adc_stop_dma_transfer(dev);
}
-static void daqboard2000_activate_reference_dacs(struct comedi_device *dev)
+static void db2k_activate_reference_dacs(struct comedi_device *dev)
{
unsigned int val;
int timeout;
}
}
-static void daqboard2000_initialize_ctrs(struct comedi_device *dev)
+static void db2k_initialize_ctrs(struct comedi_device *dev)
{
}
-static void daqboard2000_initialize_tmrs(struct comedi_device *dev)
+static void db2k_initialize_tmrs(struct comedi_device *dev)
{
}
-static void daqboard2000_dac_disarm(struct comedi_device *dev)
+static void db2k_dac_disarm(struct comedi_device *dev)
{
}
-static void daqboard2000_initialize_adc(struct comedi_device *dev)
+static void db2k_initialize_adc(struct comedi_device *dev)
{
- daqboard2000_adc_disarm(dev);
- daqboard2000_activate_reference_dacs(dev);
- daqboard2000_initialize_ctrs(dev);
- daqboard2000_initialize_tmrs(dev);
+ db2k_adc_disarm(dev);
+ db2k_activate_reference_dacs(dev);
+ db2k_initialize_ctrs(dev);
+ db2k_initialize_tmrs(dev);
}
-static void daqboard2000_initialize_dac(struct comedi_device *dev)
+static void db2k_initialize_dac(struct comedi_device *dev)
{
- daqboard2000_dac_disarm(dev);
+ db2k_dac_disarm(dev);
}
-static int daqboard2000_8255_cb(struct comedi_device *dev,
- int dir, int port, int data,
- unsigned long iobase)
+static int db2k_8255_cb(struct comedi_device *dev, int dir, int port, int data,
+ unsigned long iobase)
{
if (dir) {
writew(data, dev->mmio + iobase + port * 2);
return readw(dev->mmio + iobase + port * 2);
}
-static const void *daqboard2000_find_boardinfo(struct comedi_device *dev,
- struct pci_dev *pcidev)
-{
- const struct daq200_boardtype *board;
- int i;
-
- if (pcidev->subsystem_vendor != PCI_VENDOR_ID_IOTECH)
- return NULL;
-
- for (i = 0; i < ARRAY_SIZE(boardtypes); i++) {
- board = &boardtypes[i];
- if (pcidev->subsystem_device == board->id)
- return board;
- }
- return NULL;
-}
-
-static int daqboard2000_auto_attach(struct comedi_device *dev,
- unsigned long context_unused)
+static int db2k_auto_attach(struct comedi_device *dev, unsigned long context)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- const struct daq200_boardtype *board;
- struct daqboard2000_private *devpriv;
+ const struct db2k_boardtype *board;
+ struct db2k_private *devpriv;
struct comedi_subdevice *s;
int result;
- board = daqboard2000_find_boardinfo(dev, pcidev);
- if (!board)
+ if (context >= ARRAY_SIZE(db2k_boardtypes))
+ return -ENODEV;
+ board = &db2k_boardtypes[context];
+ if (!board->name)
return -ENODEV;
dev->board_ptr = board;
dev->board_name = board->name;
if (result)
return result;
- readl(devpriv->plx + 0x6c);
-
result = comedi_load_firmware(dev, &comedi_to_pci_dev(dev)->dev,
- DAQBOARD2000_FIRMWARE,
- daqboard2000_load_firmware, 0);
+ DB2K_FIRMWARE, db2k_load_firmware, 0);
if (result < 0)
return result;
- daqboard2000_initialize_adc(dev);
- daqboard2000_initialize_dac(dev);
+ db2k_initialize_adc(dev);
+ db2k_initialize_dac(dev);
s = &dev->subdevices[0];
/* ai subdevice */
s->subdev_flags = SDF_READABLE | SDF_GROUND;
s->n_chan = 24;
s->maxdata = 0xffff;
- s->insn_read = daqboard2000_ai_insn_read;
- s->range_table = &range_daqboard2000_ai;
+ s->insn_read = db2k_ai_insn_read;
+ s->range_table = &db2k_ai_range;
s = &dev->subdevices[1];
/* ao subdevice */
s->type = COMEDI_SUBD_AO;
s->subdev_flags = SDF_WRITABLE;
- s->n_chan = 2;
+ s->n_chan = board->has_2_ao ? 2 : 4;
s->maxdata = 0xffff;
- s->insn_write = daqboard2000_ao_insn_write;
+ s->insn_write = db2k_ao_insn_write;
s->range_table = &range_bipolar10;
result = comedi_alloc_subdev_readback(s);
return result;
s = &dev->subdevices[2];
- return subdev_8255_init(dev, s, daqboard2000_8255_cb,
+ return subdev_8255_init(dev, s, db2k_8255_cb,
DB2K_REG_DIO_P2_EXP_IO_8_BIT);
}
-static void daqboard2000_detach(struct comedi_device *dev)
+static void db2k_detach(struct comedi_device *dev)
{
- struct daqboard2000_private *devpriv = dev->private;
+ struct db2k_private *devpriv = dev->private;
if (devpriv && devpriv->plx)
iounmap(devpriv->plx);
comedi_pci_detach(dev);
}
-static struct comedi_driver daqboard2000_driver = {
+static struct comedi_driver db2k_driver = {
.driver_name = "daqboard2000",
.module = THIS_MODULE,
- .auto_attach = daqboard2000_auto_attach,
- .detach = daqboard2000_detach,
+ .auto_attach = db2k_auto_attach,
+ .detach = db2k_detach,
};
-static int daqboard2000_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *id)
+static int db2k_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
- return comedi_pci_auto_config(dev, &daqboard2000_driver,
- id->driver_data);
+ return comedi_pci_auto_config(dev, &db2k_driver, id->driver_data);
}
-static const struct pci_device_id daqboard2000_pci_table[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_IOTECH, 0x0409) },
+static const struct pci_device_id db2k_pci_table[] = {
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_IOTECH, 0x0409, PCI_VENDOR_ID_IOTECH,
+ 0x0002), .driver_data = BOARD_DAQBOARD2000, },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_IOTECH, 0x0409, PCI_VENDOR_ID_IOTECH,
+ 0x0004), .driver_data = BOARD_DAQBOARD2001, },
{ 0 }
};
-MODULE_DEVICE_TABLE(pci, daqboard2000_pci_table);
+MODULE_DEVICE_TABLE(pci, db2k_pci_table);
-static struct pci_driver daqboard2000_pci_driver = {
+static struct pci_driver db2k_pci_driver = {
.name = "daqboard2000",
- .id_table = daqboard2000_pci_table,
- .probe = daqboard2000_pci_probe,
+ .id_table = db2k_pci_table,
+ .probe = db2k_pci_probe,
.remove = comedi_pci_auto_unconfig,
};
-module_comedi_pci_driver(daqboard2000_driver, daqboard2000_pci_driver);
+module_comedi_pci_driver(db2k_driver, db2k_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
-MODULE_FIRMWARE(DAQBOARD2000_FIRMWARE);
+MODULE_FIRMWARE(DB2K_FIRMWARE);
spinlock_t lock;
};
-u32 mite_bytes_in_transit(struct mite_channel *);
+u32 mite_bytes_in_transit(struct mite_channel *mite_chan);
-void mite_sync_dma(struct mite_channel *, struct comedi_subdevice *);
-void mite_ack_linkc(struct mite_channel *, struct comedi_subdevice *s,
+void mite_sync_dma(struct mite_channel *mite_chan, struct comedi_subdevice *s);
+void mite_ack_linkc(struct mite_channel *mite_chan, struct comedi_subdevice *s,
bool sync);
-int mite_done(struct mite_channel *);
+int mite_done(struct mite_channel *mite_chan);
-void mite_dma_arm(struct mite_channel *);
-void mite_dma_disarm(struct mite_channel *);
+void mite_dma_arm(struct mite_channel *mite_chan);
+void mite_dma_disarm(struct mite_channel *mite_chan);
-void mite_prep_dma(struct mite_channel *,
+void mite_prep_dma(struct mite_channel *mite_chan,
unsigned int num_device_bits, unsigned int num_memory_bits);
-struct mite_channel *mite_request_channel_in_range(struct mite *,
- struct mite_ring *,
+struct mite_channel *mite_request_channel_in_range(struct mite *mite,
+ struct mite_ring *ring,
unsigned int min_channel,
unsigned int max_channel);
-struct mite_channel *mite_request_channel(struct mite *, struct mite_ring *);
-void mite_release_channel(struct mite_channel *);
+struct mite_channel *mite_request_channel(struct mite *mite,
+ struct mite_ring *ring);
+void mite_release_channel(struct mite_channel *mite_chan);
-int mite_init_ring_descriptors(struct mite_ring *, struct comedi_subdevice *,
- unsigned int nbytes);
-int mite_buf_change(struct mite_ring *, struct comedi_subdevice *);
+int mite_init_ring_descriptors(struct mite_ring *ring,
+ struct comedi_subdevice *s, unsigned int nbytes);
+int mite_buf_change(struct mite_ring *ring, struct comedi_subdevice *s);
-struct mite_ring *mite_alloc_ring(struct mite *);
-void mite_free_ring(struct mite_ring *);
+struct mite_ring *mite_alloc_ring(struct mite *mite);
+void mite_free_ring(struct mite_ring *ring);
-struct mite *mite_attach(struct comedi_device *, bool use_win1);
-void mite_detach(struct mite *);
+struct mite *mite_attach(struct comedi_device *dev, bool use_win1);
+void mite_detach(struct mite *mite);
/*
* Mite registers (used outside of the mite driver)
* Driver: ni_660x
* Description: National Instruments 660x counter/timer boards
* Devices: [National Instruments] PCI-6601 (ni_660x), PCI-6602, PXI-6602,
- * PXI-6608, PXI-6624
+ * PXI-6608, PCI-6624, PXI-6624
* Author: J.P. Mellor <jpmellor@rose-hulman.edu>,
* Herman.Bruyninckx@mech.kuleuven.ac.be,
* Wim.Meeussen@mech.kuleuven.ac.be,
* Klaas.Gadeyne@mech.kuleuven.ac.be,
* Frank Mori Hess <fmhess@users.sourceforge.net>
- * Updated: Fri, 15 Mar 2013 10:47:56 +0000
+ * Updated: Mon, 16 Jan 2017 14:00:43 +0000
* Status: experimental
*
* Encoders work. PulseGeneration (both single pulse and pulse train)
BOARD_PCI6602,
BOARD_PXI6602,
BOARD_PXI6608,
+ BOARD_PCI6624,
BOARD_PXI6624
};
.name = "PXI-6608",
.n_chips = 2,
},
+ [BOARD_PCI6624] = {
+ .name = "PCI-6624",
+ .n_chips = 2,
+ },
[BOARD_PXI6624] = {
.name = "PXI-6624",
.n_chips = 2,
{ PCI_VDEVICE(NI, 0x1360), BOARD_PXI6602 },
{ PCI_VDEVICE(NI, 0x2c60), BOARD_PCI6601 },
{ PCI_VDEVICE(NI, 0x2cc0), BOARD_PXI6608 },
+ { PCI_VDEVICE(NI, 0x1e30), BOARD_PCI6624 },
{ PCI_VDEVICE(NI, 0x1e40), BOARD_PXI6624 },
{ 0 }
};
/* ripped from mite.h and mite_setup2() to avoid mite dependency */
#define MITE_IODWBSR 0xc0 /* IO Device Window Base Size Register */
-#define WENAB (1 << 7) /* window enable */
+#define WENAB BIT(7) /* window enable */
static int ni_670x_mite_init(struct pci_dev *pcidev)
{
#define ATAO_CFG2_REG 0x02
#define ATAO_CFG2_CALLD_NOP (0 << 14)
#define ATAO_CFG2_CALLD(x) ((((x) >> 3) + 1) << 14)
-#define ATAO_CFG2_FFRTEN (1 << 13)
+#define ATAO_CFG2_FFRTEN BIT(13)
#define ATAO_CFG2_DACS(x) (1 << (((x) / 2) + 8))
#define ATAO_CFG2_LDAC(x) (1 << (((x) / 2) + 3))
-#define ATAO_CFG2_PROMEN (1 << 2)
-#define ATAO_CFG2_SCLK (1 << 1)
-#define ATAO_CFG2_SDATA (1 << 0)
+#define ATAO_CFG2_PROMEN BIT(2)
+#define ATAO_CFG2_SCLK BIT(1)
+#define ATAO_CFG2_SDATA BIT(0)
#define ATAO_CFG3_REG 0x04
-#define ATAO_CFG3_DMAMODE (1 << 6)
-#define ATAO_CFG3_CLKOUT (1 << 5)
-#define ATAO_CFG3_RCLKEN (1 << 4)
-#define ATAO_CFG3_DOUTEN2 (1 << 3)
-#define ATAO_CFG3_DOUTEN1 (1 << 2)
-#define ATAO_CFG3_EN2_5V (1 << 1)
-#define ATAO_CFG3_SCANEN (1 << 0)
+#define ATAO_CFG3_DMAMODE BIT(6)
+#define ATAO_CFG3_CLKOUT BIT(5)
+#define ATAO_CFG3_RCLKEN BIT(4)
+#define ATAO_CFG3_DOUTEN2 BIT(3)
+#define ATAO_CFG3_DOUTEN1 BIT(2)
+#define ATAO_CFG3_EN2_5V BIT(1)
+#define ATAO_CFG3_SCANEN BIT(0)
#define ATAO_82C53_BASE 0x06
#define ATAO_CFG1_REG 0x0a
-#define ATAO_CFG1_EXTINT2EN (1 << 15)
-#define ATAO_CFG1_EXTINT1EN (1 << 14)
-#define ATAO_CFG1_CNTINT2EN (1 << 13)
-#define ATAO_CFG1_CNTINT1EN (1 << 12)
-#define ATAO_CFG1_TCINTEN (1 << 11)
-#define ATAO_CFG1_CNT1SRC (1 << 10)
-#define ATAO_CFG1_CNT2SRC (1 << 9)
-#define ATAO_CFG1_FIFOEN (1 << 8)
-#define ATAO_CFG1_GRP2WR (1 << 7)
-#define ATAO_CFG1_EXTUPDEN (1 << 6)
-#define ATAO_CFG1_DMARQ (1 << 5)
-#define ATAO_CFG1_DMAEN (1 << 4)
+#define ATAO_CFG1_EXTINT2EN BIT(15)
+#define ATAO_CFG1_EXTINT1EN BIT(14)
+#define ATAO_CFG1_CNTINT2EN BIT(13)
+#define ATAO_CFG1_CNTINT1EN BIT(12)
+#define ATAO_CFG1_TCINTEN BIT(11)
+#define ATAO_CFG1_CNT1SRC BIT(10)
+#define ATAO_CFG1_CNT2SRC BIT(9)
+#define ATAO_CFG1_FIFOEN BIT(8)
+#define ATAO_CFG1_GRP2WR BIT(7)
+#define ATAO_CFG1_EXTUPDEN BIT(6)
+#define ATAO_CFG1_DMARQ BIT(5)
+#define ATAO_CFG1_DMAEN BIT(4)
#define ATAO_CFG1_CH(x) (((x) & 0xf) << 0)
#define ATAO_STATUS_REG 0x0a
-#define ATAO_STATUS_FH (1 << 6)
-#define ATAO_STATUS_FE (1 << 5)
-#define ATAO_STATUS_FF (1 << 4)
-#define ATAO_STATUS_INT2 (1 << 3)
-#define ATAO_STATUS_INT1 (1 << 2)
-#define ATAO_STATUS_TCINT (1 << 1)
-#define ATAO_STATUS_PROMOUT (1 << 0)
+#define ATAO_STATUS_FH BIT(6)
+#define ATAO_STATUS_FE BIT(5)
+#define ATAO_STATUS_FF BIT(4)
+#define ATAO_STATUS_INT2 BIT(3)
+#define ATAO_STATUS_INT1 BIT(2)
+#define ATAO_STATUS_TCINT BIT(1)
+#define ATAO_STATUS_PROMOUT BIT(0)
#define ATAO_FIFO_WRITE_REG 0x0c
#define ATAO_FIFO_CLEAR_REG 0x0c
#define ATAO_AO_REG(x) (0x0c + ((x) * 2))
#define ATAO_2_INT1CLR_REG 0x02
#define ATAO_2_INT2CLR_REG 0x04
#define ATAO_2_RTSISHFT_REG 0x06
-#define ATAO_2_RTSISHFT_RSI (1 << 0)
+#define ATAO_2_RTSISHFT_RSI BIT(0)
#define ATAO_2_RTSISTRB_REG 0x07
struct atao_board {
* function pointers so we can use inb/outb or readb/writeb as
* appropriate
*/
- unsigned int (*read_byte)(struct comedi_device *, unsigned long reg);
- void (*write_byte)(struct comedi_device *,
+ unsigned int (*read_byte)(struct comedi_device *dev, unsigned long reg);
+ void (*write_byte)(struct comedi_device *dev,
unsigned int byte, unsigned long reg);
};
* PCI-MIO-16XE-10, PXI-6030E, PCI-MIO-16E-1, PCI-MIO-16E-4, PCI-6014,
* PCI-6040E, PXI-6040E, PCI-6030E, PCI-6031E, PCI-6032E, PCI-6033E,
* PCI-6071E, PCI-6023E, PCI-6024E, PCI-6025E, PXI-6025E, PCI-6034E,
- * PCI-6035E, PCI-6052E,
- * PCI-6110, PCI-6111, PCI-6220, PCI-6221, PCI-6224, PXI-6224,
- * PCI-6225, PXI-6225, PCI-6229, PCI-6250,
- * PCI-6251, PXI-6251, PCIe-6251, PXIe-6251,
- * PCI-6254, PCI-6259, PCIe-6259,
- * PCI-6280, PCI-6281, PXI-6281, PCI-6284, PCI-6289,
- * PCI-6711, PXI-6711, PCI-6713, PXI-6713,
- * PXI-6071E, PCI-6070E, PXI-6070E,
+ * PCI-6035E, PCI-6052E, PCI-6110, PCI-6111, PCI-6220, PXI-6220,
+ * PCI-6221, PXI-6221, PCI-6224, PXI-6224, PCI-6225, PXI-6225,
+ * PCI-6229, PXI-6229, PCI-6250, PXI-6250, PCI-6251, PXI-6251,
+ * PCIe-6251, PXIe-6251, PCI-6254, PXI-6254, PCI-6259, PXI-6259,
+ * PCIe-6259, PXIe-6259, PCI-6280, PXI-6280, PCI-6281, PXI-6281,
+ * PCI-6284, PXI-6284, PCI-6289, PXI-6289, PCI-6711, PXI-6711,
+ * PCI-6713, PXI-6713, PXI-6071E, PCI-6070E, PXI-6070E,
* PXI-6052E, PCI-6036E, PCI-6731, PCI-6733, PXI-6733,
* PCI-6143, PXI-6143
- * Updated: Mon, 09 Jan 2012 14:52:48 +0000
+ * Updated: Mon, 16 Jan 2017 12:56:04 +0000
*
* These boards are almost identical to the AT-MIO E series, except that
* they use the PCI bus instead of ISA (i.e., AT). See the notes for the
BOARD_PXI6031E,
BOARD_PCI6036E,
BOARD_PCI6220,
+ BOARD_PXI6220,
BOARD_PCI6221,
BOARD_PCI6221_37PIN,
+ BOARD_PXI6221,
BOARD_PCI6224,
BOARD_PXI6224,
BOARD_PCI6225,
BOARD_PXI6225,
BOARD_PCI6229,
+ BOARD_PXI6229,
BOARD_PCI6250,
+ BOARD_PXI6250,
BOARD_PCI6251,
BOARD_PXI6251,
BOARD_PCIE6251,
BOARD_PXIE6251,
BOARD_PCI6254,
+ BOARD_PXI6254,
BOARD_PCI6259,
+ BOARD_PXI6259,
BOARD_PCIE6259,
+ BOARD_PXIE6259,
BOARD_PCI6280,
+ BOARD_PXI6280,
BOARD_PCI6281,
BOARD_PXI6281,
BOARD_PCI6284,
+ BOARD_PXI6284,
BOARD_PCI6289,
+ BOARD_PXI6289,
BOARD_PCI6143,
BOARD_PXI6143,
};
.reg_type = ni_reg_622x,
.caldac = { caldac_none },
},
+ [BOARD_PXI6220] = {
+ .name = "pxi-6220",
+ .n_adchan = 16,
+ .ai_maxdata = 0xffff,
+ .ai_fifo_depth = 512, /* FIXME: guess */
+ .gainlkup = ai_gain_622x,
+ .ai_speed = 4000,
+ .reg_type = ni_reg_622x,
+ .caldac = { caldac_none },
+ },
[BOARD_PCI6221] = {
.name = "pci-6221",
.n_adchan = 16,
.ao_speed = 1200,
.caldac = { caldac_none },
},
+ [BOARD_PXI6221] = {
+ .name = "pxi-6221",
+ .n_adchan = 16,
+ .ai_maxdata = 0xffff,
+ .ai_fifo_depth = 4095,
+ .gainlkup = ai_gain_622x,
+ .ai_speed = 4000,
+ .n_aochan = 2,
+ .ao_maxdata = 0xffff,
+ .ao_fifo_depth = 8191,
+ .ao_range_table = &range_bipolar10,
+ .reg_type = ni_reg_622x,
+ .ao_speed = 1200,
+ .caldac = { caldac_none },
+ },
[BOARD_PCI6224] = {
.name = "pci-6224",
.n_adchan = 32,
.has_32dio_chan = 1,
.caldac = { caldac_none },
},
+ [BOARD_PXI6229] = {
+ .name = "pxi-6229",
+ .n_adchan = 32,
+ .ai_maxdata = 0xffff,
+ .ai_fifo_depth = 4095,
+ .gainlkup = ai_gain_622x,
+ .ai_speed = 4000,
+ .n_aochan = 4,
+ .ao_maxdata = 0xffff,
+ .ao_fifo_depth = 8191,
+ .ao_range_table = &range_bipolar10,
+ .reg_type = ni_reg_622x,
+ .ao_speed = 1200,
+ .has_32dio_chan = 1,
+ .caldac = { caldac_none },
+ },
[BOARD_PCI6250] = {
.name = "pci-6250",
.n_adchan = 16,
.reg_type = ni_reg_625x,
.caldac = { caldac_none },
},
+ [BOARD_PXI6250] = {
+ .name = "pxi-6250",
+ .n_adchan = 16,
+ .ai_maxdata = 0xffff,
+ .ai_fifo_depth = 4095,
+ .gainlkup = ai_gain_628x,
+ .ai_speed = 800,
+ .reg_type = ni_reg_625x,
+ .caldac = { caldac_none },
+ },
[BOARD_PCI6251] = {
.name = "pci-6251",
.n_adchan = 16,
.has_32dio_chan = 1,
.caldac = { caldac_none },
},
+ [BOARD_PXI6254] = {
+ .name = "pxi-6254",
+ .n_adchan = 32,
+ .ai_maxdata = 0xffff,
+ .ai_fifo_depth = 4095,
+ .gainlkup = ai_gain_628x,
+ .ai_speed = 800,
+ .reg_type = ni_reg_625x,
+ .has_32dio_chan = 1,
+ .caldac = { caldac_none },
+ },
[BOARD_PCI6259] = {
.name = "pci-6259",
.n_adchan = 32,
.has_32dio_chan = 1,
.caldac = { caldac_none },
},
+ [BOARD_PXI6259] = {
+ .name = "pxi-6259",
+ .n_adchan = 32,
+ .ai_maxdata = 0xffff,
+ .ai_fifo_depth = 4095,
+ .gainlkup = ai_gain_628x,
+ .ai_speed = 800,
+ .n_aochan = 4,
+ .ao_maxdata = 0xffff,
+ .ao_fifo_depth = 8191,
+ .ao_range_table = &range_ni_M_625x_ao,
+ .reg_type = ni_reg_625x,
+ .ao_speed = 350,
+ .has_32dio_chan = 1,
+ .caldac = { caldac_none },
+ },
[BOARD_PCIE6259] = {
.name = "pcie-6259",
.n_adchan = 32,
.has_32dio_chan = 1,
.caldac = { caldac_none },
},
+ [BOARD_PXIE6259] = {
+ .name = "pxie-6259",
+ .n_adchan = 32,
+ .ai_maxdata = 0xffff,
+ .ai_fifo_depth = 4095,
+ .gainlkup = ai_gain_628x,
+ .ai_speed = 800,
+ .n_aochan = 4,
+ .ao_maxdata = 0xffff,
+ .ao_fifo_depth = 8191,
+ .ao_range_table = &range_ni_M_625x_ao,
+ .reg_type = ni_reg_625x,
+ .ao_speed = 350,
+ .has_32dio_chan = 1,
+ .caldac = { caldac_none },
+ },
[BOARD_PCI6280] = {
.name = "pci-6280",
.n_adchan = 16,
.reg_type = ni_reg_628x,
.caldac = { caldac_none },
},
+ [BOARD_PXI6280] = {
+ .name = "pxi-6280",
+ .n_adchan = 16,
+ .ai_maxdata = 0x3ffff,
+ .ai_fifo_depth = 2047,
+ .gainlkup = ai_gain_628x,
+ .ai_speed = 1600,
+ .ao_fifo_depth = 8191,
+ .reg_type = ni_reg_628x,
+ .caldac = { caldac_none },
+ },
[BOARD_PCI6281] = {
.name = "pci-6281",
.n_adchan = 16,
.has_32dio_chan = 1,
.caldac = { caldac_none },
},
+ [BOARD_PXI6284] = {
+ .name = "pxi-6284",
+ .n_adchan = 32,
+ .ai_maxdata = 0x3ffff,
+ .ai_fifo_depth = 2047,
+ .gainlkup = ai_gain_628x,
+ .ai_speed = 1600,
+ .reg_type = ni_reg_628x,
+ .has_32dio_chan = 1,
+ .caldac = { caldac_none },
+ },
[BOARD_PCI6289] = {
.name = "pci-6289",
.n_adchan = 32,
.has_32dio_chan = 1,
.caldac = { caldac_none },
},
+ [BOARD_PXI6289] = {
+ .name = "pxi-6289",
+ .n_adchan = 32,
+ .ai_maxdata = 0x3ffff,
+ .ai_fifo_depth = 2047,
+ .gainlkup = ai_gain_628x,
+ .ai_speed = 1600,
+ .n_aochan = 4,
+ .ao_maxdata = 0xffff,
+ .ao_fifo_depth = 8191,
+ .ao_range_table = &range_ni_M_628x_ao,
+ .reg_type = ni_reg_628x,
+ .ao_speed = 350,
+ .has_32dio_chan = 1,
+ .caldac = { caldac_none },
+ },
[BOARD_PCI6143] = {
.name = "pci-6143",
.n_adchan = 8,
{ PCI_VDEVICE(NI, 0x70aa), BOARD_PCI6229 },
{ PCI_VDEVICE(NI, 0x70ab), BOARD_PCI6259 },
{ PCI_VDEVICE(NI, 0x70ac), BOARD_PCI6289 },
+ { PCI_VDEVICE(NI, 0x70ad), BOARD_PXI6251 },
+ { PCI_VDEVICE(NI, 0x70ae), BOARD_PXI6220 },
{ PCI_VDEVICE(NI, 0x70af), BOARD_PCI6221 },
{ PCI_VDEVICE(NI, 0x70b0), BOARD_PCI6220 },
+ { PCI_VDEVICE(NI, 0x70b1), BOARD_PXI6229 },
+ { PCI_VDEVICE(NI, 0x70b2), BOARD_PXI6259 },
+ { PCI_VDEVICE(NI, 0x70b3), BOARD_PXI6289 },
{ PCI_VDEVICE(NI, 0x70b4), BOARD_PCI6250 },
+ { PCI_VDEVICE(NI, 0x70b5), BOARD_PXI6221 },
{ PCI_VDEVICE(NI, 0x70b6), BOARD_PCI6280 },
{ PCI_VDEVICE(NI, 0x70b7), BOARD_PCI6254 },
{ PCI_VDEVICE(NI, 0x70b8), BOARD_PCI6251 },
+ { PCI_VDEVICE(NI, 0x70b9), BOARD_PXI6250 },
+ { PCI_VDEVICE(NI, 0x70ba), BOARD_PXI6254 },
+ { PCI_VDEVICE(NI, 0x70bb), BOARD_PXI6280 },
{ PCI_VDEVICE(NI, 0x70bc), BOARD_PCI6284 },
{ PCI_VDEVICE(NI, 0x70bd), BOARD_PCI6281 },
+ { PCI_VDEVICE(NI, 0x70be), BOARD_PXI6284 },
{ PCI_VDEVICE(NI, 0x70bf), BOARD_PXI6281 },
{ PCI_VDEVICE(NI, 0x70c0), BOARD_PCI6143 },
{ PCI_VDEVICE(NI, 0x70f2), BOARD_PCI6224 },
{ PCI_VDEVICE(NI, 0x710d), BOARD_PXI6143 },
{ PCI_VDEVICE(NI, 0x716c), BOARD_PCI6225 },
{ PCI_VDEVICE(NI, 0x716d), BOARD_PXI6225 },
+ { PCI_VDEVICE(NI, 0x717d), BOARD_PCIE6251 },
{ PCI_VDEVICE(NI, 0x717f), BOARD_PCIE6259 },
{ PCI_VDEVICE(NI, 0x71bc), BOARD_PCI6221_37PIN },
- { PCI_VDEVICE(NI, 0x717d), BOARD_PCIE6251 },
{ PCI_VDEVICE(NI, 0x72e8), BOARD_PXIE6251 },
- { PCI_VDEVICE(NI, 0x70ad), BOARD_PXI6251 },
+ { PCI_VDEVICE(NI, 0x72e9), BOARD_PXIE6259 },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, ni_pcimio_pci_table);
struct ni_gpct_device {
struct comedi_device *dev;
- void (*write)(struct ni_gpct *, unsigned int value,
+ void (*write)(struct ni_gpct *counter, unsigned int value,
enum ni_gpct_register);
- unsigned int (*read)(struct ni_gpct *, enum ni_gpct_register);
+ unsigned int (*read)(struct ni_gpct *counter, enum ni_gpct_register);
enum ni_gpct_variant variant;
struct ni_gpct *counters;
unsigned int num_counters;
};
struct ni_gpct_device *
-ni_gpct_device_construct(struct comedi_device *,
- void (*write)(struct ni_gpct *,
+ni_gpct_device_construct(struct comedi_device *dev,
+ void (*write)(struct ni_gpct *counter,
unsigned int value,
enum ni_gpct_register),
- unsigned int (*read)(struct ni_gpct *,
+ unsigned int (*read)(struct ni_gpct *counter,
enum ni_gpct_register),
enum ni_gpct_variant,
unsigned int num_counters);
-void ni_gpct_device_destroy(struct ni_gpct_device *);
-void ni_tio_init_counter(struct ni_gpct *);
-int ni_tio_insn_read(struct comedi_device *, struct comedi_subdevice *,
- struct comedi_insn *, unsigned int *data);
-int ni_tio_insn_config(struct comedi_device *, struct comedi_subdevice *,
- struct comedi_insn *, unsigned int *data);
-int ni_tio_insn_write(struct comedi_device *, struct comedi_subdevice *,
- struct comedi_insn *, unsigned int *data);
-int ni_tio_cmd(struct comedi_device *, struct comedi_subdevice *);
-int ni_tio_cmdtest(struct comedi_device *, struct comedi_subdevice *,
- struct comedi_cmd *);
-int ni_tio_cancel(struct ni_gpct *);
-void ni_tio_handle_interrupt(struct ni_gpct *, struct comedi_subdevice *);
-void ni_tio_set_mite_channel(struct ni_gpct *, struct mite_channel *);
-void ni_tio_acknowledge(struct ni_gpct *);
+void ni_gpct_device_destroy(struct ni_gpct_device *counter_dev);
+void ni_tio_init_counter(struct ni_gpct *counter);
+int ni_tio_insn_read(struct comedi_device *dev, struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data);
+int ni_tio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data);
+int ni_tio_insn_write(struct comedi_device *dev, struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data);
+int ni_tio_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
+int ni_tio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
+ struct comedi_cmd *cmd);
+int ni_tio_cancel(struct ni_gpct *counter);
+void ni_tio_handle_interrupt(struct ni_gpct *counter,
+ struct comedi_subdevice *s);
+void ni_tio_set_mite_channel(struct ni_gpct *counter,
+ struct mite_channel *mite_chan);
+void ni_tio_acknowledge(struct ni_gpct *counter);
#endif /* _COMEDI_NI_TIO_H */
#define GI_TC_INTERRUPT_ENABLE(x) (((x) % 2) ? BIT(9) : BIT(6))
#define GI_GATE_INTERRUPT_ENABLE(x) (((x) % 2) ? BIT(10) : BIT(8))
-void ni_tio_write(struct ni_gpct *, unsigned int value, enum ni_gpct_register);
-unsigned int ni_tio_read(struct ni_gpct *, enum ni_gpct_register);
+void ni_tio_write(struct ni_gpct *counter, unsigned int value,
+ enum ni_gpct_register);
+unsigned int ni_tio_read(struct ni_gpct *counter, enum ni_gpct_register);
static inline bool
ni_tio_counting_mode_registers_present(const struct ni_gpct_device *counter_dev)
return counter_dev->variant != ni_gpct_variant_e_series;
}
-void ni_tio_set_bits(struct ni_gpct *, enum ni_gpct_register reg,
+void ni_tio_set_bits(struct ni_gpct *counter, enum ni_gpct_register reg,
unsigned int mask, unsigned int value);
-unsigned int ni_tio_get_soft_copy(const struct ni_gpct *,
+unsigned int ni_tio_get_soft_copy(const struct ni_gpct *counter,
enum ni_gpct_register reg);
-int ni_tio_arm(struct ni_gpct *, bool arm, unsigned int start_trigger);
-int ni_tio_set_gate_src(struct ni_gpct *, unsigned int gate, unsigned int src);
+int ni_tio_arm(struct ni_gpct *counter, bool arm, unsigned int start_trigger);
+int ni_tio_set_gate_src(struct ni_gpct *counter, unsigned int gate,
+ unsigned int src);
#endif /* _COMEDI_NI_TIO_INTERNAL_H */
}
static const struct file_operations comedi_proc_fops = {
+ .owner = THIS_MODULE,
.open = comedi_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
-void comedi_proc_init(void)
+void __init comedi_proc_init(void)
{
- proc_create("comedi", 0644, NULL, &comedi_proc_fops);
+ if (!proc_create("comedi", 0444, NULL, &comedi_proc_fops))
+ pr_warn("comedi: unable to create proc entry\n");
}
void comedi_proc_cleanup(void)
-* checkpatch fixes
* remove unnecessary comments
* remove unnecessary error messages. Example kzalloc() has its
own error message. Adding an extra one is useless.
* use goto statements for error handling when appropriate
* there is a lot of unnecessary code in the driver. It was
- originally a standalone driver. Remove uneeded code.
+ originally a standalone driver. Remove unneeded code.
Please send patches to Greg Kroah-Hartman <greg@kroah.com> and
Cc: Lidza Louina <lidza.louina@gmail.com>
/*-------------------------------------------------------------------------*/
/* Endpoint 0 OUT Transfer (PIO) */
-static int EP0_out_PIO(struct nbu2ss_udc *udc, u8 *pBuf, u32 length)
+static int ep0_out_pio(struct nbu2ss_udc *udc, u8 *buf, u32 length)
{
u32 i;
- int nret = 0;
- u32 iWordLength = 0;
- union usb_reg_access *pBuf32 = (union usb_reg_access *)pBuf;
+ u32 numreads = length / sizeof(u32);
+ union usb_reg_access *buf32 = (union usb_reg_access *)buf;
- /*------------------------------------------------------------*/
- /* Read Length */
- iWordLength = length / sizeof(u32);
+ if (!numreads)
+ return 0;
- /*------------------------------------------------------------*/
/* PIO Read */
- if (iWordLength) {
- for (i = 0; i < iWordLength; i++) {
- pBuf32->dw = _nbu2ss_readl(&udc->p_regs->EP0_READ);
- pBuf32++;
- }
- nret = iWordLength * sizeof(u32);
+ for (i = 0; i < numreads; i++) {
+ buf32->dw = _nbu2ss_readl(&udc->p_regs->EP0_READ);
+ buf32++;
}
- return nret;
+ return numreads * sizeof(u32);
}
/*-------------------------------------------------------------------------*/
pBuffer = (u8 *)req->req.buf;
pBuffer += req->req.actual;
- result = EP0_out_PIO(udc, pBuffer
+ result = ep0_out_pio(udc, pBuffer
, min(iRemainSize, iRecvLength));
if (result < 0)
return result;
};
/*-------------------------------------------------------------------------*/
-static void __init nbu2ss_drv_ep_init(struct nbu2ss_udc *udc)
+static void nbu2ss_drv_ep_init(struct nbu2ss_udc *udc)
{
int i;
/*-------------------------------------------------------------------------*/
/* platform_driver */
-static int __init nbu2ss_drv_contest_init(
+static int nbu2ss_drv_contest_init(
struct platform_device *pdev,
struct nbu2ss_udc *udc)
{
buf[i] = (u8)va_arg(args, unsigned int);
va_end(args);
- fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par,
- par->info->device, u8, buf, len, "%s: ", __func__);
- }
+ fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par, par->info->device,
+ u8, buf, len, "%s: ", __func__);
+}
va_start(args, len);
static void
construct_line_bitmap(struct fbtft_par *par, u8 *dest, signed short *src,
- int xs, int xe, int y)
+ int xs, int xe, int y)
{
int x, i;
/* left half of display */
if (addr_win.xs < par->info->var.xres / 2) {
construct_line_bitmap(par, buf, convert_buf,
- addr_win.xs, par->info->var.xres / 2, y);
+ addr_win.xs,
+ par->info->var.xres / 2, y);
len = par->info->var.xres / 2 - addr_win.xs;
/* right half of display */
if (addr_win.xe >= par->info->var.xres / 2) {
construct_line_bitmap(par, buf,
- convert_buf, par->info->var.xres / 2,
- addr_win.xe + 1, y);
+ convert_buf,
+ par->info->var.xres / 2,
+ addr_win.xe + 1, y);
len = addr_win.xe + 1 - par->info->var.xres / 2;
static int write(struct fbtft_par *par, void *buf, size_t len)
{
fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
- "%s(len=%d): ", __func__, len);
+ "%s(len=%d): ", __func__, len);
gpio_set_value(par->RW, 0); /* set write mode */
"3 3 17 8 4 7 05 7 6 0 3 1 6 0 0 "
static bool emulate;
-module_param(emulate, bool, 0);
+module_param(emulate, bool, 0000);
MODULE_PARM_DESC(emulate, "Force emulation in 9-bit mode");
static int init_display(struct fbtft_par *par)
* ON0 ON1 CN0 CN1 CN2 CN3 CN4 MN0 MN1 MN2 MN3 MN4 MN5 XXXX GC
*/
#define CURVE(num, idx) curves[num * par->gamma.num_values + idx]
-static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+static int set_gamma(struct fbtft_par *par, u32 *curves)
{
unsigned long mask[] = {
0x0f, 0x0f, 0x1f, 0x0f, 0x0f, 0x0f, 0x1f, 0x07, 0x07, 0x07,
* VRN0 VRN1 VRN2 VRN3 VRN4 VRN5 PRN0 PRN1 PKN0 PKN1 PKN2 PKN3 PKN4 CGM
*/
#define CURVE(num, idx) curves[num * par->gamma.num_values + idx]
-static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+static int set_gamma(struct fbtft_par *par, u32 *curves)
{
unsigned long mask[] = {
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x7f, 0x7f, 0x1f, 0x1f,
}
/* gamma string format: */
-static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+static int set_gamma(struct fbtft_par *par, u32 *curves)
{
write_reg(par, 0xE0,
curves[0], curves[1], curves[2], curves[3],
#ifdef GAMMA_ADJ
#define CURVE(num, idx) curves[num * par->gamma.num_values + idx]
-static int gamma_adj(struct fbtft_par *par, unsigned long *curves)
+static int gamma_adj(struct fbtft_par *par, u32 *curves)
{
unsigned long mask[] = {
0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
* VRN0 VRN1 RN0 RN1 KN0 KN1 KN2 KN3 KN4 KN5
*/
#define CURVE(num, idx) curves[num * par->gamma.num_values + idx]
-static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+static int set_gamma(struct fbtft_par *par, u32 *curves)
{
unsigned long mask[] = {
0x1f, 0x1f, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
* VRN0 VRN1 RN0 RN1 KN0 KN1 KN2 KN3 KN4 KN5
*/
#define CURVE(num, idx) curves[num * par->gamma.num_values + idx]
-static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+static int set_gamma(struct fbtft_par *par, u32 *curves)
{
unsigned long mask[] = {
0x1f, 0x1f, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
* Negative: Par1 Par2 [...] Par15
*/
#define CURVE(num, idx) curves[num * par->gamma.num_values + idx]
-static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+static int set_gamma(struct fbtft_par *par, u32 *curves)
{
int i;
#define DEFAULT_GAMMA "40" /* gamma controls the contrast in this driver */
static unsigned int tc;
-module_param(tc, uint, 0);
+module_param(tc, uint, 0000);
MODULE_PARM_DESC(tc, "TC[1:0] Temperature coefficient: 0-3 (default: 0)");
static unsigned int bs = 4;
-module_param(bs, uint, 0);
+module_param(bs, uint, 0000);
MODULE_PARM_DESC(bs, "BS[2:0] Bias voltage level: 0-7 (default: 4)");
static int init_display(struct fbtft_par *par)
return ret;
}
-static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+static int set_gamma(struct fbtft_par *par, u32 *curves)
{
/* apply mask */
curves[0] &= 0x7F;
struct spi_message m;
fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
- "%s(len=%d): ", __func__, len);
+ "%s(len=%d): ", __func__, len);
if (!par->spi) {
dev_err(par->info->device,
}
spi_message_init(&m);
- if (par->txbuf.dma && buf == par->txbuf.buf) {
- t.tx_dma = par->txbuf.dma;
- m.is_dma_mapped = 1;
- }
spi_message_add_tail(&t, &m);
return spi_sync(par->spi, &m);
}
gpio_set_value(par->gpio.dc, 1);
fbtft_par_dbg(DEBUG_INIT_DISPLAY, par,
- "%s()\n", __func__);
+ "%s()\n", __func__);
fbtft_par_dbg(DEBUG_INIT_DISPLAY, par,
- "display size %dx%d\n",
+ "display size %dx%d\n",
par->info->var.xres,
par->info->var.yres);
buf[i] = (u8)va_arg(args, unsigned int);
va_end(args);
fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par, par->info->device,
- u8, buf, len, "%s: ", __func__);
+ u8, buf, len, "%s: ", __func__);
}
va_start(args, len);
size_t startbyte_size = 0;
fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s(offset=%zu, len=%zu)\n",
- __func__, offset, len);
+ __func__, offset, len);
remain = len / 2;
vmem16 = (u16 *)(par->info->screen_buffer + offset);
* PKN0 PKN1 PKN2 PKN3 PKN4 PKN5 PKN6 PKN7 PRN8 PRN9 PRN10 PRN11 VRN0 VRN1
*/
#define CURVE(num, idx) curves[num * par->gamma.num_values + idx]
-static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+static int set_gamma(struct fbtft_par *par, u32 *curves)
{
unsigned long mask[] = {
0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f,
"02 03 2 5 7 5 4 2 4 2"
static unsigned int reg11 = 0x6040;
-module_param(reg11, uint, 0);
+module_param(reg11, uint, 0000);
MODULE_PARM_DESC(reg11, "Register 11h value");
static int init_display(struct fbtft_par *par)
* VRN0 VRN1 PRN0 PRN1 PKN0 PKN1 PKN2 PKN3 PKN4 PKN5
*/
#define CURVE(num, idx) curves[num * par->gamma.num_values + idx]
-static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+static int set_gamma(struct fbtft_par *par, u32 *curves)
{
unsigned long mask[] = {
0x1f, 0x1f, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
}
/* Gamma is used to control Contrast */
-static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+static int set_gamma(struct fbtft_par *par, u32 *curves)
{
curves[0] &= 0xFF;
/* Set Contrast Control for BANK0 */
write_reg(par, 0xA8);
if (par->info->var.yres == 64)
write_reg(par, 0x3F);
+ else if (par->info->var.yres == 48)
+ write_reg(par, 0x2F);
else
write_reg(par, 0x1F);
/* Vertical addressing mode */
write_reg(par, 0x01);
- /*Set Segment Re-map */
+ /* Set Segment Re-map */
/* column address 127 is mapped to SEG0 */
write_reg(par, 0xA0 | 0x1);
if (par->info->var.yres == 64)
/* A[4]=1b, Alternative COM pin configuration */
write_reg(par, 0x12);
+ else if (par->info->var.yres == 48)
+ /* A[4]=1b, Alternative COM pin configuration */
+ write_reg(par, 0x12);
else
/* A[4]=0b, Sequential COM pin configuration */
write_reg(par, 0x02);
return 0;
}
+static void set_addr_win_64x48(struct fbtft_par *par)
+{
+ /* Set Column Address */
+ write_reg(par, 0x21);
+ write_reg(par, 0x20);
+ write_reg(par, 0x5F);
+
+ /* Set Page Address */
+ write_reg(par, 0x22);
+ write_reg(par, 0x0);
+ write_reg(par, 0x5);
+}
+
static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
{
/* Set Lower Column Start Address for Page Addressing Mode */
write_reg(par, 0x10 | 0x0);
/* Set Display Start Line */
write_reg(par, 0x40 | 0x0);
+
+ if (par->info->var.xres == 64 && par->info->var.yres == 48)
+ set_addr_win_64x48(par);
}
static int blank(struct fbtft_par *par, bool on)
{
fbtft_par_dbg(DEBUG_BLANK, par, "%s(blank=%s)\n",
- __func__, on ? "true" : "false");
+ __func__, on ? "true" : "false");
if (on)
write_reg(par, 0xAE);
}
/* Gamma is used to control Contrast */
-static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+static int set_gamma(struct fbtft_par *par, u32 *curves)
{
/* apply mask */
curves[0] &= 0xFF;
static int write_vmem(struct fbtft_par *par, size_t offset, size_t len)
{
u16 *vmem16 = (u16 *)par->info->screen_buffer;
+ u32 xres = par->info->var.xres;
+ u32 yres = par->info->var.yres;
u8 *buf = par->txbuf.buf;
int x, y, i;
int ret = 0;
- for (x = 0; x < par->info->var.xres; x++) {
- for (y = 0; y < par->info->var.yres/8; y++) {
+ for (x = 0; x < xres; x++) {
+ for (y = 0; y < yres / 8; y++) {
*buf = 0x00;
for (i = 0; i < 8; i++)
- *buf |= (vmem16[(y * 8 + i) *
- par->info->var.xres + x] ?
- 1 : 0) << i;
+ *buf |= (vmem16[(y * 8 + i) * xres + x] ? 1 : 0) << i;
buf++;
}
}
/* Write data */
gpio_set_value(par->gpio.dc, 1);
- ret = par->fbtftops.write(par, par->txbuf.buf,
- par->info->var.xres * par->info->var.yres /
- 8);
+ ret = par->fbtftops.write(par, par->txbuf.buf, xres * yres / 8);
if (ret < 0)
dev_err(par->info->device, "write failed and returned: %d\n",
ret);
* 0 = Setting of GS1 < Setting of GS2 < Setting of GS3.....<
* Setting of GS14 < Setting of GS15
*/
-static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+static int set_gamma(struct fbtft_par *par, u32 *curves)
{
int i;
* Setting of GS63 has to be > Setting of GS62 +1
*
*/
-static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+static int set_gamma(struct fbtft_par *par, u32 *curves)
{
unsigned long tmp[GAMMA_NUM * GAMMA_LEN];
int i, acc = 0;
}
write_reg(par, 0xB8,
- tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7],
- tmp[8], tmp[9], tmp[10], tmp[11], tmp[12], tmp[13], tmp[14], tmp[15],
- tmp[16], tmp[17], tmp[18], tmp[19], tmp[20], tmp[21], tmp[22], tmp[23],
- tmp[24], tmp[25], tmp[26], tmp[27], tmp[28], tmp[29], tmp[30], tmp[31],
- tmp[32], tmp[33], tmp[34], tmp[35], tmp[36], tmp[37], tmp[38], tmp[39],
- tmp[40], tmp[41], tmp[42], tmp[43], tmp[44], tmp[45], tmp[46], tmp[47],
- tmp[48], tmp[49], tmp[50], tmp[51], tmp[52], tmp[53], tmp[54], tmp[55],
- tmp[56], tmp[57], tmp[58], tmp[59], tmp[60], tmp[61], tmp[62]);
+ tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6],
+ tmp[7], tmp[8], tmp[9], tmp[10], tmp[11], tmp[12], tmp[13],
+ tmp[14], tmp[15], tmp[16], tmp[17], tmp[18], tmp[19], tmp[20],
+ tmp[21], tmp[22], tmp[23], tmp[24], tmp[25], tmp[26], tmp[27],
+ tmp[28], tmp[29], tmp[30], tmp[31], tmp[32], tmp[33], tmp[34],
+ tmp[35], tmp[36], tmp[37], tmp[38], tmp[39], tmp[40], tmp[41],
+ tmp[42], tmp[43], tmp[44], tmp[45], tmp[46], tmp[47], tmp[48],
+ tmp[49], tmp[50], tmp[51], tmp[52], tmp[53], tmp[54], tmp[55],
+ tmp[56], tmp[57], tmp[58], tmp[59], tmp[60], tmp[61],
+ tmp[62]);
return 0;
}
static int blank(struct fbtft_par *par, bool on)
{
fbtft_par_dbg(DEBUG_BLANK, par, "%s(blank=%s)\n",
- __func__, on ? "true" : "false");
+ __func__, on ? "true" : "false");
if (on)
write_reg(par, 0xAE);
else
if (par->fbtftops.init_display != init_display) {
/* don't risk messing up register A0h */
fbtft_par_dbg(DEBUG_INIT_DISPLAY, par,
- "%s: skipping since custom init_display() is used\n",
- __func__);
+ "%s: skipping since custom init_display() is used\n",
+ __func__);
return 0;
}
* Setting of GS63 has to be > Setting of GS62 +1
*
*/
-static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+static int set_gamma(struct fbtft_par *par, u32 *curves)
{
unsigned long tmp[GAMMA_NUM * GAMMA_LEN];
int i, acc = 0;
* VRF0N VOS0N PK0N PK1N PK2N PK3N PK4N PK5N PK6N PK7N PK8N PK9N SELV0N SELV1N SELV62N SELV63N
*/
#define CURVE(num, idx) curves[num * par->gamma.num_values + idx]
-static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+static int set_gamma(struct fbtft_par *par, u32 *curves)
{
int i, j;
*
* Return: 0 on success, < 0 if error occurred.
*/
-static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+static int set_gamma(struct fbtft_par *par, u32 *curves)
{
int i;
int j;
#define DEFAULT_GAMMA "40"
static unsigned int bs = 4;
-module_param(bs, uint, 0);
+module_param(bs, uint, 0000);
MODULE_PARM_DESC(bs, "BS[2:0] Bias voltage level: 0-7 (default: 4)");
static int init_display(struct fbtft_par *par)
return ret;
}
-static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+static int set_gamma(struct fbtft_par *par, u32 *curves)
{
/* apply mask */
curves[0] &= 0x7F;
/* BR -> actual ratio: 0-3 -> 5, 10, 11, 13 */
static unsigned int ratio = 2;
-module_param(ratio, uint, 0);
+module_param(ratio, uint, 0000);
MODULE_PARM_DESC(ratio, "BR[1:0] Bias voltage ratio: 0-3 (default: 2)");
static unsigned int gain = 3;
-module_param(gain, uint, 0);
+module_param(gain, uint, 0000);
MODULE_PARM_DESC(gain, "GN[1:0] Bias voltage gain: 0-3 (default: 3)");
static unsigned int pot = 16;
-module_param(pot, uint, 0);
+module_param(pot, uint, 0000);
MODULE_PARM_DESC(pot, "PM[6:0] Bias voltage pot.: 0-63 (default: 16)");
/* TC -> % compensation per deg C: 0-3 -> -.05, -.10, -.015, -.20 */
static unsigned int temp;
-module_param(temp, uint, 0);
+module_param(temp, uint, 0000);
MODULE_PARM_DESC(temp, "TC[1:0] Temperature compensation: 0-3 (default: 0)");
/* PC[1:0] -> LCD capacitance: 0-3 -> <20nF, 20-28 nF, 29-40 nF, 40-56 nF */
static unsigned int load = 1;
-module_param(load, uint, 0);
+module_param(load, uint, 0000);
MODULE_PARM_DESC(load, "PC[1:0] Panel Loading: 0-3 (default: 1)");
/* PC[3:2] -> V_LCD: 0, 1, 3 -> ext., int. with ratio = 5, int. standard */
static unsigned int pump = 3;
-module_param(pump, uint, 0);
+module_param(pump, uint, 0000);
MODULE_PARM_DESC(pump, "PC[3:2] Pump control: 0,1,3 (default: 3)");
static int init_display(struct fbtft_par *par)
#define COLOR_RGB565 16
static short mode = 565;
-module_param(mode, short, 0);
+module_param(mode, short, 0000);
MODULE_PARM_DESC(mode, "RGB color transfer mode: 332, 565 (default)");
static void write_reg8_bus8(struct fbtft_par *par, int len, ...)
#include <linux/backlight.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
-#include <linux/dma-mapping.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <video/mipi_display.h>
#include "internal.h"
static unsigned long debug;
-module_param(debug, ulong, 0);
+module_param(debug, ulong, 0000);
MODULE_PARM_DESC(debug, "override device debug level");
-#ifdef CONFIG_HAS_DMA
-static bool dma = true;
-module_param(dma, bool, 0);
-MODULE_PARM_DESC(dma, "Use DMA buffer");
-#endif
-
void fbtft_dbg_hex(const struct device *dev, int groupsize,
void *buf, size_t len, const char *fmt, ...)
{
if (par->gpio.reset == -1)
return;
fbtft_par_dbg(DEBUG_RESET, par, "%s()\n", __func__);
- gpio_set_value(par->gpio.reset, 0);
- udelay(20);
- gpio_set_value(par->gpio.reset, 1);
- mdelay(120);
+ gpio_set_value_cansleep(par->gpio.reset, 0);
+ usleep_range(20, 40);
+ gpio_set_value_cansleep(par->gpio.reset, 1);
+ msleep(120);
}
static void fbtft_update_display(struct fbtft_par *par, unsigned int start_line,
int vmem_size, i;
s16 *init_sequence = display->init_sequence;
char *gamma = display->gamma;
- unsigned long *gamma_curves = NULL;
+ u32 *gamma_curves = NULL;
/* sanity check */
if (display->gamma_num * display->gamma_len >
#endif
if (txbuflen > 0) {
-#ifdef CONFIG_HAS_DMA
- if (dma) {
- dev->coherent_dma_mask = ~0;
- txbuf = dmam_alloc_coherent(dev, txbuflen,
- &par->txbuf.dma, GFP_DMA);
- } else
-#endif
- {
- txbuf = devm_kzalloc(par->info->device,
- txbuflen, GFP_KERNEL);
- }
+ txbuf = devm_kzalloc(par->info->device, txbuflen, GFP_KERNEL);
if (!txbuf)
goto alloc_fail;
par->txbuf.buf = txbuf;
fbtft_sysfs_init(par);
if (par->txbuf.buf)
- sprintf(text1, ", %zu KiB %sbuffer memory",
- par->txbuf.len >> 10, par->txbuf.dma ? "DMA " : "");
+ sprintf(text1, ", %zu KiB buffer memory", par->txbuf.len >> 10);
if (spi)
sprintf(text2, ", spi%d.%d at %d MHz", spi->master->bus_num,
spi->chip_select, spi->max_speed_hz / 1000000);
}
spi_message_init(&m);
- if (par->txbuf.dma && buf == par->txbuf.buf) {
- t.tx_dma = par->txbuf.dma;
- m.is_dma_mapped = 1;
- }
spi_message_add_tail(&t, &m);
return spi_sync(par->spi, &m);
}
static int get_next_ulong(char **str_p, unsigned long *val, char *sep, int base)
{
char *p_val;
- int ret;
if (!str_p || !(*str_p))
return -EINVAL;
if (!p_val)
return -EINVAL;
- ret = kstrtoul(p_val, base, val);
- if (ret)
- return -EINVAL;
-
- return 0;
+ return kstrtoul(p_val, base, val);
}
-int fbtft_gamma_parse_str(struct fbtft_par *par, unsigned long *curves,
+int fbtft_gamma_parse_str(struct fbtft_par *par, u32 *curves,
const char *str, int size)
{
char *str_p, *curve_p = NULL;
}
static ssize_t
-sprintf_gamma(struct fbtft_par *par, unsigned long *curves, char *buf)
+sprintf_gamma(struct fbtft_par *par, u32 *curves, char *buf)
{
ssize_t len = 0;
unsigned int i, j;
for (i = 0; i < par->gamma.num_curves; i++) {
for (j = 0; j < par->gamma.num_values; j++)
len += scnprintf(&buf[len], PAGE_SIZE,
- "%04lx ", curves[i * par->gamma.num_values + j]);
+ "%04x ", curves[i * par->gamma.num_values + j]);
buf[len - 1] = '\n';
}
mutex_unlock(&par->gamma.lock);
{
struct fb_info *fb_info = dev_get_drvdata(device);
struct fbtft_par *par = fb_info->par;
- unsigned long tmp_curves[FBTFT_GAMMA_MAX_VALUES_TOTAL];
+ u32 tmp_curves[FBTFT_GAMMA_MAX_VALUES_TOTAL];
int ret;
ret = fbtft_gamma_parse_str(par, tmp_curves, buf, count);
void (*unregister_backlight)(struct fbtft_par *par);
int (*set_var)(struct fbtft_par *par);
- int (*set_gamma)(struct fbtft_par *par, unsigned long *curves);
+ int (*set_gamma)(struct fbtft_par *par, u32 *curves);
};
/**
u32 pseudo_palette[16];
struct {
void *buf;
- dma_addr_t dma;
size_t len;
} txbuf;
u8 *buf;
s16 *init_sequence;
struct {
struct mutex lock;
- unsigned long *curves;
+ u32 *curves;
int num_values;
int num_curves;
} gamma;
static struct platform_device *p_device;
static char *name;
-module_param(name, charp, 0);
+module_param(name, charp, 0000);
MODULE_PARM_DESC(name, "Devicename (required). name=list => list all supported devices.");
static unsigned int rotate;
-module_param(rotate, uint, 0);
+module_param(rotate, uint, 0000);
MODULE_PARM_DESC(rotate,
"Angle to rotate display counter clockwise: 0, 90, 180, 270");
static unsigned int busnum;
-module_param(busnum, uint, 0);
+module_param(busnum, uint, 0000);
MODULE_PARM_DESC(busnum, "SPI bus number (default=0)");
static unsigned int cs;
-module_param(cs, uint, 0);
+module_param(cs, uint, 0000);
MODULE_PARM_DESC(cs, "SPI chip select (default=0)");
static unsigned int speed;
-module_param(speed, uint, 0);
+module_param(speed, uint, 0000);
MODULE_PARM_DESC(speed, "SPI speed (override device default)");
static int mode = -1;
-module_param(mode, int, 0);
+module_param(mode, int, 0000);
MODULE_PARM_DESC(mode, "SPI mode (override device default)");
static char *gpios;
-module_param(gpios, charp, 0);
+module_param(gpios, charp, 0000);
MODULE_PARM_DESC(gpios,
"List of gpios. Comma separated with the form: reset:23,dc:24 (when overriding the default, all gpios must be specified)");
static unsigned int fps;
-module_param(fps, uint, 0);
+module_param(fps, uint, 0000);
MODULE_PARM_DESC(fps, "Frames per second (override driver default)");
static char *gamma;
-module_param(gamma, charp, 0);
+module_param(gamma, charp, 0000);
MODULE_PARM_DESC(gamma,
"String representation of Gamma Curve(s). Driver specific.");
static int txbuflen;
-module_param(txbuflen, int, 0);
+module_param(txbuflen, int, 0000);
MODULE_PARM_DESC(txbuflen, "txbuflen (override driver default)");
static int bgr = -1;
-module_param(bgr, int, 0);
+module_param(bgr, int, 0000);
MODULE_PARM_DESC(bgr,
"BGR bit (supported by some drivers).");
static unsigned int startbyte;
-module_param(startbyte, uint, 0);
+module_param(startbyte, uint, 0000);
MODULE_PARM_DESC(startbyte, "Sets the Start byte used by some SPI displays.");
static bool custom;
-module_param(custom, bool, 0);
+module_param(custom, bool, 0000);
MODULE_PARM_DESC(custom, "Add a custom display device. Use speed= argument to make it a SPI device, else platform_device");
static unsigned int width;
-module_param(width, uint, 0);
+module_param(width, uint, 0000);
MODULE_PARM_DESC(width, "Display width, used with the custom argument");
static unsigned int height;
-module_param(height, uint, 0);
+module_param(height, uint, 0000);
MODULE_PARM_DESC(height, "Display height, used with the custom argument");
static unsigned int buswidth = 8;
-module_param(buswidth, uint, 0);
+module_param(buswidth, uint, 0000);
MODULE_PARM_DESC(buswidth, "Display bus width, used with the custom argument");
static s16 init[FBTFT_MAX_INIT_SEQUENCE];
static int init_num;
-module_param_array(init, short, &init_num, 0);
+module_param_array(init, short, &init_num, 0000);
MODULE_PARM_DESC(init, "Init sequence, used with the custom argument");
static unsigned long debug;
-module_param(debug, ulong, 0);
+module_param(debug, ulong, 0000);
MODULE_PARM_DESC(debug,
"level: 0-7 (the remaining 29 bits is for advanced usage)");
static unsigned int verbose = 3;
-module_param(verbose, uint, 0);
+module_param(verbose, uint, 0000);
MODULE_PARM_DESC(verbose,
"0 silent, >0 show gpios, >1 show devices, >2 show devices before (default=3)");
#define DRVNAME "flexfb"
static char *chip;
-module_param(chip, charp, 0);
+module_param(chip, charp, 0000);
MODULE_PARM_DESC(chip, "LCD controller");
static unsigned int width;
-module_param(width, uint, 0);
+module_param(width, uint, 0000);
MODULE_PARM_DESC(width, "Display width");
static unsigned int height;
-module_param(height, uint, 0);
+module_param(height, uint, 0000);
MODULE_PARM_DESC(height, "Display height");
static s16 init[512];
static int init_num;
-module_param_array(init, short, &init_num, 0);
+module_param_array(init, short, &init_num, 0000);
MODULE_PARM_DESC(init, "Init sequence");
static unsigned int setaddrwin;
-module_param(setaddrwin, uint, 0);
+module_param(setaddrwin, uint, 0000);
MODULE_PARM_DESC(setaddrwin, "Which set_addr_win() implementation to use");
static unsigned int buswidth = 8;
-module_param(buswidth, uint, 0);
+module_param(buswidth, uint, 0000);
MODULE_PARM_DESC(buswidth, "Width of databus (default: 8)");
static unsigned int regwidth = 8;
-module_param(regwidth, uint, 0);
+module_param(regwidth, uint, 0000);
MODULE_PARM_DESC(regwidth, "Width of controller register (default: 8)");
static bool nobacklight;
-module_param(nobacklight, bool, 0);
+module_param(nobacklight, bool, 0000);
MODULE_PARM_DESC(nobacklight, "Turn off backlight functionality.");
static bool latched;
-module_param(latched, bool, 0);
+module_param(latched, bool, 0000);
MODULE_PARM_DESC(latched, "Use with latched 16-bit databus");
static s16 *initp;
.init_seq = ili9225_init,
.init_seq_sz = ARRAY_SIZE(ili9225_init),
},
- {
- .name = "ili9225",
- .width = 176,
- .height = 220,
- .regwidth = 16,
- .init_seq = ili9225_init,
- .init_seq_sz = ARRAY_SIZE(ili9225_init),
- },
- {
- .name = "ili9225",
- .width = 176,
- .height = 220,
- .regwidth = 16,
- .init_seq = ili9225_init,
- .init_seq_sz = ARRAY_SIZE(ili9225_init),
- },
{
.name = "ili9320",
.width = 240,
void fbtft_sysfs_init(struct fbtft_par *par);
void fbtft_sysfs_exit(struct fbtft_par *par);
void fbtft_expand_debug_value(unsigned long *debug);
-int fbtft_gamma_parse_str(struct fbtft_par *par, unsigned long *curves,
+int fbtft_gamma_parse_str(struct fbtft_par *par, u32 *curves,
const char *str, int size);
#endif /* __LINUX_FBTFT_INTERNAL_H */
/* Command IDs */
#define DPBP_CMDID_CLOSE DPBP_CMD(0x800)
#define DPBP_CMDID_OPEN DPBP_CMD(0x804)
-#define DPBP_CMDID_CREATE DPBP_CMD(0x904)
-#define DPBP_CMDID_DESTROY DPBP_CMD(0x984)
#define DPBP_CMDID_GET_API_VERSION DPBP_CMD(0xa04)
#define DPBP_CMDID_ENABLE DPBP_CMD(0x002)
#define DPBP_CMDID_RESET DPBP_CMD(0x005)
#define DPBP_CMDID_IS_ENABLED DPBP_CMD(0x006)
-#define DPBP_CMDID_SET_IRQ DPBP_CMD(0x010)
-#define DPBP_CMDID_GET_IRQ DPBP_CMD(0x011)
-#define DPBP_CMDID_SET_IRQ_ENABLE DPBP_CMD(0x012)
-#define DPBP_CMDID_GET_IRQ_ENABLE DPBP_CMD(0x013)
-#define DPBP_CMDID_SET_IRQ_MASK DPBP_CMD(0x014)
-#define DPBP_CMDID_GET_IRQ_MASK DPBP_CMD(0x015)
-#define DPBP_CMDID_GET_IRQ_STATUS DPBP_CMD(0x016)
-#define DPBP_CMDID_CLEAR_IRQ_STATUS DPBP_CMD(0x017)
-
-#define DPBP_CMDID_SET_NOTIFICATIONS DPBP_CMD(0x01b0)
-#define DPBP_CMDID_GET_NOTIFICATIONS DPBP_CMD(0x01b1)
-
struct dpbp_cmd_open {
__le32 dpbp_id;
};
u8 enabled;
};
-struct dpbp_cmd_set_irq {
- /* cmd word 0 */
- u8 irq_index;
- u8 pad[3];
- __le32 irq_val;
- /* cmd word 1 */
- __le64 irq_addr;
- /* cmd word 2 */
- __le32 irq_num;
-};
-
-struct dpbp_cmd_get_irq {
- __le32 pad;
- u8 irq_index;
-};
-
-struct dpbp_rsp_get_irq {
- /* response word 0 */
- __le32 irq_val;
- __le32 pad;
- /* response word 1 */
- __le64 irq_addr;
- /* response word 2 */
- __le32 irq_num;
- __le32 type;
-};
-
-struct dpbp_cmd_set_irq_enable {
- u8 enable;
- u8 pad[3];
- u8 irq_index;
-};
-
-struct dpbp_cmd_get_irq_enable {
- __le32 pad;
- u8 irq_index;
-};
-
-struct dpbp_rsp_get_irq_enable {
- u8 enabled;
-};
-
-struct dpbp_cmd_set_irq_mask {
- __le32 mask;
- u8 irq_index;
-};
-
-struct dpbp_cmd_get_irq_mask {
- __le32 pad;
- u8 irq_index;
-};
-
-struct dpbp_rsp_get_irq_mask {
- __le32 mask;
-};
-
-struct dpbp_cmd_get_irq_status {
- __le32 status;
- u8 irq_index;
-};
-
-struct dpbp_rsp_get_irq_status {
- __le32 status;
-};
-
-struct dpbp_cmd_clear_irq_status {
- __le32 status;
- u8 irq_index;
-};
-
struct dpbp_rsp_get_attributes {
/* response word 0 */
__le16 pad;
__le16 version_minor;
};
-struct dpbp_cmd_set_notifications {
- /* cmd word 0 */
- __le32 depletion_entry;
- __le32 depletion_exit;
- /* cmd word 1 */
- __le32 surplus_entry;
- __le32 surplus_exit;
- /* cmd word 2 */
- __le16 options;
- __le16 pad[3];
- /* cmd word 3 */
- __le64 message_ctx;
- /* cmd word 4 */
- __le64 message_iova;
-};
-
-struct dpbp_rsp_get_notifications {
- /* response word 0 */
- __le32 depletion_entry;
- __le32 depletion_exit;
- /* response word 1 */
- __le32 surplus_entry;
- __le32 surplus_exit;
- /* response word 2 */
- __le16 options;
- __le16 pad[3];
- /* response word 3 */
- __le64 message_ctx;
- /* response word 4 */
- __le64 message_iova;
-};
-
#endif /* _FSL_DPBP_CMD_H */
}
EXPORT_SYMBOL(dpbp_close);
-/**
- * dpbp_create() - Create the DPBP object.
- * @mc_io: Pointer to MC portal's I/O object
- * @dprc_token: Parent container token; '0' for default container
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @cfg: Configuration structure
- * @obj_id: Returned object id; use in subsequent API calls
- *
- * Create the DPBP object, allocate required resources and
- * perform required initialization.
- *
- * This function accepts an authentication token of a parent
- * container that this object should be assigned to and returns
- * an object id. This object_id will be used in all subsequent calls to
- * this specific object.
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dpbp_create(struct fsl_mc_io *mc_io,
- u16 dprc_token,
- u32 cmd_flags,
- const struct dpbp_cfg *cfg,
- u32 *obj_id)
-{
- struct mc_command cmd = { 0 };
- int err;
-
- (void)(cfg); /* unused */
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPBP_CMDID_CREATE,
- cmd_flags, dprc_token);
-
- /* send command to mc*/
- err = mc_send_command(mc_io, &cmd);
- if (err)
- return err;
-
- /* retrieve response parameters */
- *obj_id = mc_cmd_read_object_id(&cmd);
-
- return 0;
-}
-
-/**
- * dpbp_destroy() - Destroy the DPBP object and release all its resources.
- * @mc_io: Pointer to MC portal's I/O object
- * @dprc_token: Parent container token; '0' for default container
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @obj_id: ID of DPBP object
- *
- * Return: '0' on Success; error code otherwise.
- */
-int dpbp_destroy(struct fsl_mc_io *mc_io,
- u16 dprc_token,
- u32 cmd_flags,
- u32 obj_id)
-{
- struct dpbp_cmd_destroy *cmd_params;
- struct mc_command cmd = { 0 };
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPBP_CMDID_DESTROY,
- cmd_flags, dprc_token);
- cmd_params = (struct dpbp_cmd_destroy *)cmd.params;
- cmd_params->object_id = cpu_to_le32(obj_id);
-
- /* send command to mc*/
- return mc_send_command(mc_io, &cmd);
-}
-
/**
* dpbp_enable() - Enable the DPBP.
* @mc_io: Pointer to MC portal's I/O object
return 0;
}
+EXPORT_SYMBOL(dpbp_is_enabled);
/**
* dpbp_reset() - Reset the DPBP, returns the object to initial state.
/* send command to mc*/
return mc_send_command(mc_io, &cmd);
}
-
-/**
- * dpbp_set_irq() - Set IRQ information for the DPBP to trigger an interrupt.
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPBP object
- * @irq_index: Identifies the interrupt index to configure
- * @irq_cfg: IRQ configuration
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dpbp_set_irq(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- struct dpbp_irq_cfg *irq_cfg)
-{
- struct mc_command cmd = { 0 };
- struct dpbp_cmd_set_irq *cmd_params;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPBP_CMDID_SET_IRQ,
- cmd_flags, token);
- cmd_params = (struct dpbp_cmd_set_irq *)cmd.params;
- cmd_params->irq_index = irq_index;
- cmd_params->irq_val = cpu_to_le32(irq_cfg->val);
- cmd_params->irq_addr = cpu_to_le64(irq_cfg->addr);
- cmd_params->irq_num = cpu_to_le32(irq_cfg->irq_num);
-
- /* send command to mc*/
- return mc_send_command(mc_io, &cmd);
-}
-
-/**
- * dpbp_get_irq() - Get IRQ information from the DPBP.
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPBP object
- * @irq_index: The interrupt index to configure
- * @type: Interrupt type: 0 represents message interrupt
- * type (both irq_addr and irq_val are valid)
- * @irq_cfg: IRQ attributes
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dpbp_get_irq(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- int *type,
- struct dpbp_irq_cfg *irq_cfg)
-{
- struct mc_command cmd = { 0 };
- struct dpbp_cmd_get_irq *cmd_params;
- struct dpbp_rsp_get_irq *rsp_params;
- int err;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPBP_CMDID_GET_IRQ,
- cmd_flags, token);
- cmd_params = (struct dpbp_cmd_get_irq *)cmd.params;
- cmd_params->irq_index = irq_index;
-
- /* send command to mc*/
- err = mc_send_command(mc_io, &cmd);
- if (err)
- return err;
-
- /* retrieve response parameters */
- rsp_params = (struct dpbp_rsp_get_irq *)cmd.params;
- irq_cfg->val = le32_to_cpu(rsp_params->irq_val);
- irq_cfg->addr = le64_to_cpu(rsp_params->irq_addr);
- irq_cfg->irq_num = le32_to_cpu(rsp_params->irq_num);
- *type = le32_to_cpu(rsp_params->type);
-
- return 0;
-}
-
-/**
- * dpbp_set_irq_enable() - Set overall interrupt state.
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPBP object
- * @irq_index: The interrupt index to configure
- * @en: Interrupt state - enable = 1, disable = 0
- *
- * Allows GPP software to control when interrupts are generated.
- * Each interrupt can have up to 32 causes. The enable/disable control's the
- * overall interrupt state. if the interrupt is disabled no causes will cause
- * an interrupt.
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dpbp_set_irq_enable(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- u8 en)
-{
- struct mc_command cmd = { 0 };
- struct dpbp_cmd_set_irq_enable *cmd_params;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPBP_CMDID_SET_IRQ_ENABLE,
- cmd_flags, token);
- cmd_params = (struct dpbp_cmd_set_irq_enable *)cmd.params;
- cmd_params->enable = en & DPBP_ENABLE;
- cmd_params->irq_index = irq_index;
-
- /* send command to mc*/
- return mc_send_command(mc_io, &cmd);
-}
-
-/**
- * dpbp_get_irq_enable() - Get overall interrupt state
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPBP object
- * @irq_index: The interrupt index to configure
- * @en: Returned interrupt state - enable = 1, disable = 0
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dpbp_get_irq_enable(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- u8 *en)
-{
- struct mc_command cmd = { 0 };
- struct dpbp_cmd_get_irq_enable *cmd_params;
- struct dpbp_rsp_get_irq_enable *rsp_params;
- int err;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPBP_CMDID_GET_IRQ_ENABLE,
- cmd_flags, token);
- cmd_params = (struct dpbp_cmd_get_irq_enable *)cmd.params;
- cmd_params->irq_index = irq_index;
-
- /* send command to mc*/
- err = mc_send_command(mc_io, &cmd);
- if (err)
- return err;
-
- /* retrieve response parameters */
- rsp_params = (struct dpbp_rsp_get_irq_enable *)cmd.params;
- *en = rsp_params->enabled & DPBP_ENABLE;
- return 0;
-}
-
-/**
- * dpbp_set_irq_mask() - Set interrupt mask.
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPBP object
- * @irq_index: The interrupt index to configure
- * @mask: Event mask to trigger interrupt;
- * each bit:
- * 0 = ignore event
- * 1 = consider event for asserting IRQ
- *
- * Every interrupt can have up to 32 causes and the interrupt model supports
- * masking/unmasking each cause independently
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dpbp_set_irq_mask(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- u32 mask)
-{
- struct mc_command cmd = { 0 };
- struct dpbp_cmd_set_irq_mask *cmd_params;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPBP_CMDID_SET_IRQ_MASK,
- cmd_flags, token);
- cmd_params = (struct dpbp_cmd_set_irq_mask *)cmd.params;
- cmd_params->mask = cpu_to_le32(mask);
- cmd_params->irq_index = irq_index;
-
- /* send command to mc*/
- return mc_send_command(mc_io, &cmd);
-}
-
-/**
- * dpbp_get_irq_mask() - Get interrupt mask.
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPBP object
- * @irq_index: The interrupt index to configure
- * @mask: Returned event mask to trigger interrupt
- *
- * Every interrupt can have up to 32 causes and the interrupt model supports
- * masking/unmasking each cause independently
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dpbp_get_irq_mask(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- u32 *mask)
-{
- struct mc_command cmd = { 0 };
- struct dpbp_cmd_get_irq_mask *cmd_params;
- struct dpbp_rsp_get_irq_mask *rsp_params;
- int err;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPBP_CMDID_GET_IRQ_MASK,
- cmd_flags, token);
- cmd_params = (struct dpbp_cmd_get_irq_mask *)cmd.params;
- cmd_params->irq_index = irq_index;
-
- /* send command to mc*/
- err = mc_send_command(mc_io, &cmd);
- if (err)
- return err;
-
- /* retrieve response parameters */
- rsp_params = (struct dpbp_rsp_get_irq_mask *)cmd.params;
- *mask = le32_to_cpu(rsp_params->mask);
-
- return 0;
-}
-
-/**
- * dpbp_get_irq_status() - Get the current status of any pending interrupts.
- *
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPBP object
- * @irq_index: The interrupt index to configure
- * @status: Returned interrupts status - one bit per cause:
- * 0 = no interrupt pending
- * 1 = interrupt pending
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dpbp_get_irq_status(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- u32 *status)
-{
- struct mc_command cmd = { 0 };
- struct dpbp_cmd_get_irq_status *cmd_params;
- struct dpbp_rsp_get_irq_status *rsp_params;
- int err;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPBP_CMDID_GET_IRQ_STATUS,
- cmd_flags, token);
- cmd_params = (struct dpbp_cmd_get_irq_status *)cmd.params;
- cmd_params->status = cpu_to_le32(*status);
- cmd_params->irq_index = irq_index;
-
- /* send command to mc*/
- err = mc_send_command(mc_io, &cmd);
- if (err)
- return err;
-
- /* retrieve response parameters */
- rsp_params = (struct dpbp_rsp_get_irq_status *)cmd.params;
- *status = le32_to_cpu(rsp_params->status);
-
- return 0;
-}
-
-/**
- * dpbp_clear_irq_status() - Clear a pending interrupt's status
- *
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPBP object
- * @irq_index: The interrupt index to configure
- * @status: Bits to clear (W1C) - one bit per cause:
- * 0 = don't change
- * 1 = clear status bit
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dpbp_clear_irq_status(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- u32 status)
-{
- struct mc_command cmd = { 0 };
- struct dpbp_cmd_clear_irq_status *cmd_params;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPBP_CMDID_CLEAR_IRQ_STATUS,
- cmd_flags, token);
- cmd_params = (struct dpbp_cmd_clear_irq_status *)cmd.params;
- cmd_params->status = cpu_to_le32(status);
- cmd_params->irq_index = irq_index;
-
- /* send command to mc*/
- return mc_send_command(mc_io, &cmd);
-}
+EXPORT_SYMBOL(dpbp_reset);
/**
* dpbp_get_attributes - Retrieve DPBP attributes.
}
EXPORT_SYMBOL(dpbp_get_attributes);
-/**
- * dpbp_set_notifications() - Set notifications towards software
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPBP object
- * @cfg: notifications configuration
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dpbp_set_notifications(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- struct dpbp_notification_cfg *cfg)
-{
- struct mc_command cmd = { 0 };
- struct dpbp_cmd_set_notifications *cmd_params;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPBP_CMDID_SET_NOTIFICATIONS,
- cmd_flags, token);
- cmd_params = (struct dpbp_cmd_set_notifications *)cmd.params;
- cmd_params->depletion_entry = cpu_to_le32(cfg->depletion_entry);
- cmd_params->depletion_exit = cpu_to_le32(cfg->depletion_exit);
- cmd_params->surplus_entry = cpu_to_le32(cfg->surplus_entry);
- cmd_params->surplus_exit = cpu_to_le32(cfg->surplus_exit);
- cmd_params->options = cpu_to_le16(cfg->options);
- cmd_params->message_ctx = cpu_to_le64(cfg->message_ctx);
- cmd_params->message_iova = cpu_to_le64(cfg->message_iova);
-
- /* send command to mc*/
- return mc_send_command(mc_io, &cmd);
-}
-
-/**
- * dpbp_get_notifications() - Get the notifications configuration
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPBP object
- * @cfg: notifications configuration
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dpbp_get_notifications(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- struct dpbp_notification_cfg *cfg)
-{
- struct mc_command cmd = { 0 };
- struct dpbp_rsp_get_notifications *rsp_params;
- int err;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPBP_CMDID_GET_NOTIFICATIONS,
- cmd_flags,
- token);
-
- /* send command to mc*/
- err = mc_send_command(mc_io, &cmd);
- if (err)
- return err;
-
- /* retrieve response parameters */
- rsp_params = (struct dpbp_rsp_get_notifications *)cmd.params;
- cfg->depletion_entry = le32_to_cpu(rsp_params->depletion_entry);
- cfg->depletion_exit = le32_to_cpu(rsp_params->depletion_exit);
- cfg->surplus_entry = le32_to_cpu(rsp_params->surplus_entry);
- cfg->surplus_exit = le32_to_cpu(rsp_params->surplus_exit);
- cfg->options = le16_to_cpu(rsp_params->options);
- cfg->message_ctx = le64_to_cpu(rsp_params->message_ctx);
- cfg->message_iova = le64_to_cpu(rsp_params->message_iova);
-
- return 0;
-}
-
/**
* dpbp_get_api_version - Get Data Path Buffer Pool API version
* @mc_io: Pointer to Mc portal's I/O object
return 0;
}
+EXPORT_SYMBOL(dpbp_get_api_version);
/* Command IDs */
#define DPMCP_CMDID_CLOSE DPMCP_CMD(0x800)
#define DPMCP_CMDID_OPEN DPMCP_CMD(0x80b)
-#define DPMCP_CMDID_CREATE DPMCP_CMD(0x90b)
-#define DPMCP_CMDID_DESTROY DPMCP_CMD(0x98b)
#define DPMCP_CMDID_GET_API_VERSION DPMCP_CMD(0xa0b)
-#define DPMCP_CMDID_GET_ATTR DPMCP_CMD(0x004)
#define DPMCP_CMDID_RESET DPMCP_CMD(0x005)
-#define DPMCP_CMDID_SET_IRQ DPMCP_CMD(0x010)
-#define DPMCP_CMDID_GET_IRQ DPMCP_CMD(0x011)
-#define DPMCP_CMDID_SET_IRQ_ENABLE DPMCP_CMD(0x012)
-#define DPMCP_CMDID_GET_IRQ_ENABLE DPMCP_CMD(0x013)
-#define DPMCP_CMDID_SET_IRQ_MASK DPMCP_CMD(0x014)
-#define DPMCP_CMDID_GET_IRQ_MASK DPMCP_CMD(0x015)
-#define DPMCP_CMDID_GET_IRQ_STATUS DPMCP_CMD(0x016)
-
struct dpmcp_cmd_open {
__le32 dpmcp_id;
};
-struct dpmcp_cmd_create {
- __le32 portal_id;
-};
-
-struct dpmcp_cmd_destroy {
- __le32 object_id;
-};
-
-struct dpmcp_cmd_set_irq {
- /* cmd word 0 */
- u8 irq_index;
- u8 pad[3];
- __le32 irq_val;
- /* cmd word 1 */
- __le64 irq_addr;
- /* cmd word 2 */
- __le32 irq_num;
-};
-
-struct dpmcp_cmd_get_irq {
- __le32 pad;
- u8 irq_index;
-};
-
-struct dpmcp_rsp_get_irq {
- /* cmd word 0 */
- __le32 irq_val;
- __le32 pad;
- /* cmd word 1 */
- __le64 irq_paddr;
- /* cmd word 2 */
- __le32 irq_num;
- __le32 type;
-};
-
-#define DPMCP_ENABLE 0x1
-
-struct dpmcp_cmd_set_irq_enable {
- u8 enable;
- u8 pad[3];
- u8 irq_index;
-};
-
-struct dpmcp_cmd_get_irq_enable {
- __le32 pad;
- u8 irq_index;
-};
-
-struct dpmcp_rsp_get_irq_enable {
- u8 enabled;
-};
-
-struct dpmcp_cmd_set_irq_mask {
- __le32 mask;
- u8 irq_index;
-};
-
-struct dpmcp_cmd_get_irq_mask {
- __le32 pad;
- u8 irq_index;
-};
-
-struct dpmcp_rsp_get_irq_mask {
- __le32 mask;
-};
-
-struct dpmcp_cmd_get_irq_status {
- __le32 status;
- u8 irq_index;
-};
-
-struct dpmcp_rsp_get_irq_status {
- __le32 status;
-};
-
-struct dpmcp_rsp_get_attributes {
- /* response word 0 */
- __le32 pad;
- __le32 id;
- /* response word 1 */
- __le16 version_major;
- __le16 version_minor;
-};
-
#endif /* _FSL_DPMCP_CMD_H */
return mc_send_command(mc_io, &cmd);
}
-/**
- * dpmcp_create() - Create the DPMCP object.
- * @mc_io: Pointer to MC portal's I/O object
- * @dprc_token: Parent container token; '0' for default container
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @cfg: Configuration structure
- * @obj_id: Returned object id; use in subsequent API calls
- *
- * Create the DPMCP object, allocate required resources and
- * perform required initialization.
- *
- * The object can be created either by declaring it in the
- * DPL file, or by calling this function.
-
- * This function accepts an authentication token of a parent
- * container that this object should be assigned to and returns
- * an object id. This object_id will be used in all subsequent calls to
- * this specific object.
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dpmcp_create(struct fsl_mc_io *mc_io,
- u16 dprc_token,
- u32 cmd_flags,
- const struct dpmcp_cfg *cfg,
- u32 *obj_id)
-{
- struct mc_command cmd = { 0 };
- struct dpmcp_cmd_create *cmd_params;
-
- int err;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPMCP_CMDID_CREATE,
- cmd_flags, dprc_token);
- cmd_params = (struct dpmcp_cmd_create *)cmd.params;
- cmd_params->portal_id = cpu_to_le32(cfg->portal_id);
-
- /* send command to mc*/
- err = mc_send_command(mc_io, &cmd);
- if (err)
- return err;
-
- /* retrieve response parameters */
- *obj_id = mc_cmd_read_object_id(&cmd);
-
- return 0;
-}
-
-/**
- * dpmcp_destroy() - Destroy the DPMCP object and release all its resources.
- * @mc_io: Pointer to MC portal's I/O object
- * @dprc_token: Parent container token; '0' for default container
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @obj_id: ID of DPMCP object
- *
- * Return: '0' on Success; error code otherwise.
- */
-int dpmcp_destroy(struct fsl_mc_io *mc_io,
- u16 dprc_token,
- u32 cmd_flags,
- u32 obj_id)
-{
- struct mc_command cmd = { 0 };
- struct dpmcp_cmd_destroy *cmd_params;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPMCP_CMDID_DESTROY,
- cmd_flags, dprc_token);
- cmd_params = (struct dpmcp_cmd_destroy *)cmd.params;
- cmd_params->object_id = cpu_to_le32(obj_id);
-
- /* send command to mc*/
- return mc_send_command(mc_io, &cmd);
-}
-
/**
* dpmcp_reset() - Reset the DPMCP, returns the object to initial state.
* @mc_io: Pointer to MC portal's I/O object
return mc_send_command(mc_io, &cmd);
}
-/**
- * dpmcp_set_irq() - Set IRQ information for the DPMCP to trigger an interrupt.
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPMCP object
- * @irq_index: Identifies the interrupt index to configure
- * @irq_cfg: IRQ configuration
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dpmcp_set_irq(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- struct dpmcp_irq_cfg *irq_cfg)
-{
- struct mc_command cmd = { 0 };
- struct dpmcp_cmd_set_irq *cmd_params;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPMCP_CMDID_SET_IRQ,
- cmd_flags, token);
- cmd_params = (struct dpmcp_cmd_set_irq *)cmd.params;
- cmd_params->irq_index = irq_index;
- cmd_params->irq_val = cpu_to_le32(irq_cfg->val);
- cmd_params->irq_addr = cpu_to_le64(irq_cfg->paddr);
- cmd_params->irq_num = cpu_to_le32(irq_cfg->irq_num);
-
- /* send command to mc*/
- return mc_send_command(mc_io, &cmd);
-}
-
-/**
- * dpmcp_get_irq() - Get IRQ information from the DPMCP.
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPMCP object
- * @irq_index: The interrupt index to configure
- * @type: Interrupt type: 0 represents message interrupt
- * type (both irq_addr and irq_val are valid)
- * @irq_cfg: IRQ attributes
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dpmcp_get_irq(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- int *type,
- struct dpmcp_irq_cfg *irq_cfg)
-{
- struct mc_command cmd = { 0 };
- struct dpmcp_cmd_get_irq *cmd_params;
- struct dpmcp_rsp_get_irq *rsp_params;
- int err;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPMCP_CMDID_GET_IRQ,
- cmd_flags, token);
- cmd_params = (struct dpmcp_cmd_get_irq *)cmd.params;
- cmd_params->irq_index = irq_index;
-
- /* send command to mc*/
- err = mc_send_command(mc_io, &cmd);
- if (err)
- return err;
-
- /* retrieve response parameters */
- rsp_params = (struct dpmcp_rsp_get_irq *)cmd.params;
- irq_cfg->val = le32_to_cpu(rsp_params->irq_val);
- irq_cfg->paddr = le64_to_cpu(rsp_params->irq_paddr);
- irq_cfg->irq_num = le32_to_cpu(rsp_params->irq_num);
- *type = le32_to_cpu(rsp_params->type);
- return 0;
-}
-
-/**
- * dpmcp_set_irq_enable() - Set overall interrupt state.
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPMCP object
- * @irq_index: The interrupt index to configure
- * @en: Interrupt state - enable = 1, disable = 0
- *
- * Allows GPP software to control when interrupts are generated.
- * Each interrupt can have up to 32 causes. The enable/disable control's the
- * overall interrupt state. if the interrupt is disabled no causes will cause
- * an interrupt.
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dpmcp_set_irq_enable(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- u8 en)
-{
- struct mc_command cmd = { 0 };
- struct dpmcp_cmd_set_irq_enable *cmd_params;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPMCP_CMDID_SET_IRQ_ENABLE,
- cmd_flags, token);
- cmd_params = (struct dpmcp_cmd_set_irq_enable *)cmd.params;
- cmd_params->enable = en & DPMCP_ENABLE;
- cmd_params->irq_index = irq_index;
-
- /* send command to mc*/
- return mc_send_command(mc_io, &cmd);
-}
-
-/**
- * dpmcp_get_irq_enable() - Get overall interrupt state
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPMCP object
- * @irq_index: The interrupt index to configure
- * @en: Returned interrupt state - enable = 1, disable = 0
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dpmcp_get_irq_enable(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- u8 *en)
-{
- struct mc_command cmd = { 0 };
- struct dpmcp_cmd_get_irq_enable *cmd_params;
- struct dpmcp_rsp_get_irq_enable *rsp_params;
- int err;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPMCP_CMDID_GET_IRQ_ENABLE,
- cmd_flags, token);
- cmd_params = (struct dpmcp_cmd_get_irq_enable *)cmd.params;
- cmd_params->irq_index = irq_index;
-
- /* send command to mc*/
- err = mc_send_command(mc_io, &cmd);
- if (err)
- return err;
-
- /* retrieve response parameters */
- rsp_params = (struct dpmcp_rsp_get_irq_enable *)cmd.params;
- *en = rsp_params->enabled & DPMCP_ENABLE;
- return 0;
-}
-
-/**
- * dpmcp_set_irq_mask() - Set interrupt mask.
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPMCP object
- * @irq_index: The interrupt index to configure
- * @mask: Event mask to trigger interrupt;
- * each bit:
- * 0 = ignore event
- * 1 = consider event for asserting IRQ
- *
- * Every interrupt can have up to 32 causes and the interrupt model supports
- * masking/unmasking each cause independently
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dpmcp_set_irq_mask(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- u32 mask)
-{
- struct mc_command cmd = { 0 };
- struct dpmcp_cmd_set_irq_mask *cmd_params;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPMCP_CMDID_SET_IRQ_MASK,
- cmd_flags, token);
- cmd_params = (struct dpmcp_cmd_set_irq_mask *)cmd.params;
- cmd_params->mask = cpu_to_le32(mask);
- cmd_params->irq_index = irq_index;
-
- /* send command to mc*/
- return mc_send_command(mc_io, &cmd);
-}
-
-/**
- * dpmcp_get_irq_mask() - Get interrupt mask.
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPMCP object
- * @irq_index: The interrupt index to configure
- * @mask: Returned event mask to trigger interrupt
- *
- * Every interrupt can have up to 32 causes and the interrupt model supports
- * masking/unmasking each cause independently
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dpmcp_get_irq_mask(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- u32 *mask)
-{
- struct mc_command cmd = { 0 };
- struct dpmcp_cmd_get_irq_mask *cmd_params;
- struct dpmcp_rsp_get_irq_mask *rsp_params;
-
- int err;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPMCP_CMDID_GET_IRQ_MASK,
- cmd_flags, token);
- cmd_params = (struct dpmcp_cmd_get_irq_mask *)cmd.params;
- cmd_params->irq_index = irq_index;
-
- /* send command to mc*/
- err = mc_send_command(mc_io, &cmd);
- if (err)
- return err;
-
- /* retrieve response parameters */
- rsp_params = (struct dpmcp_rsp_get_irq_mask *)cmd.params;
- *mask = le32_to_cpu(rsp_params->mask);
-
- return 0;
-}
-
-/**
- * dpmcp_get_irq_status() - Get the current status of any pending interrupts.
- *
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPMCP object
- * @irq_index: The interrupt index to configure
- * @status: Returned interrupts status - one bit per cause:
- * 0 = no interrupt pending
- * 1 = interrupt pending
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dpmcp_get_irq_status(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- u32 *status)
-{
- struct mc_command cmd = { 0 };
- struct dpmcp_cmd_get_irq_status *cmd_params;
- struct dpmcp_rsp_get_irq_status *rsp_params;
- int err;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPMCP_CMDID_GET_IRQ_STATUS,
- cmd_flags, token);
- cmd_params = (struct dpmcp_cmd_get_irq_status *)cmd.params;
- cmd_params->status = cpu_to_le32(*status);
- cmd_params->irq_index = irq_index;
-
- /* send command to mc*/
- err = mc_send_command(mc_io, &cmd);
- if (err)
- return err;
-
- /* retrieve response parameters */
- rsp_params = (struct dpmcp_rsp_get_irq_status *)cmd.params;
- *status = le32_to_cpu(rsp_params->status);
-
- return 0;
-}
-
-/**
- * dpmcp_get_attributes - Retrieve DPMCP attributes.
- *
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPMCP object
- * @attr: Returned object's attributes
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dpmcp_get_attributes(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- struct dpmcp_attr *attr)
-{
- struct mc_command cmd = { 0 };
- struct dpmcp_rsp_get_attributes *rsp_params;
- int err;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPMCP_CMDID_GET_ATTR,
- cmd_flags, token);
-
- /* send command to mc*/
- err = mc_send_command(mc_io, &cmd);
- if (err)
- return err;
-
- /* retrieve response parameters */
- rsp_params = (struct dpmcp_rsp_get_attributes *)cmd.params;
- attr->id = le32_to_cpu(rsp_params->id);
-
- return 0;
-}
-
/**
* dpmcp_get_api_version - Get Data Path Management Command Portal API version
* @mc_io: Pointer to Mc portal's I/O object
int dpmcp_id,
u16 *token);
-/* Get portal ID from pool */
-#define DPMCP_GET_PORTAL_ID_FROM_POOL (-1)
-
int dpmcp_close(struct fsl_mc_io *mc_io,
u32 cmd_flags,
u16 token);
-/**
- * struct dpmcp_cfg - Structure representing DPMCP configuration
- * @portal_id: Portal ID; 'DPMCP_GET_PORTAL_ID_FROM_POOL' to get the portal ID
- * from pool
- */
-struct dpmcp_cfg {
- int portal_id;
-};
-
-int dpmcp_create(struct fsl_mc_io *mc_io,
- u16 dprc_token,
- u32 cmd_flags,
- const struct dpmcp_cfg *cfg,
- u32 *obj_id);
-
-int dpmcp_destroy(struct fsl_mc_io *mc_io,
- u16 dprc_token,
- u32 cmd_flags,
- u32 obj_id);
+int dpmcp_get_api_version(struct fsl_mc_io *mc_io,
+ u32 cmd_flags,
+ u16 *major_ver,
+ u16 *minor_ver);
int dpmcp_reset(struct fsl_mc_io *mc_io,
u32 cmd_flags,
u16 token);
-/* IRQ */
-/* IRQ Index */
-#define DPMCP_IRQ_INDEX 0
-/* irq event - Indicates that the link state changed */
-#define DPMCP_IRQ_EVENT_CMD_DONE 0x00000001
-
-/**
- * struct dpmcp_irq_cfg - IRQ configuration
- * @paddr: Address that must be written to signal a message-based interrupt
- * @val: Value to write into irq_addr address
- * @irq_num: A user defined number associated with this IRQ
- */
-struct dpmcp_irq_cfg {
- u64 paddr;
- u32 val;
- int irq_num;
-};
-
-int dpmcp_set_irq(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- struct dpmcp_irq_cfg *irq_cfg);
-
-int dpmcp_get_irq(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- int *type,
- struct dpmcp_irq_cfg *irq_cfg);
-
-int dpmcp_set_irq_enable(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- u8 en);
-
-int dpmcp_get_irq_enable(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- u8 *en);
-
-int dpmcp_set_irq_mask(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- u32 mask);
-
-int dpmcp_get_irq_mask(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- u32 *mask);
-
-int dpmcp_get_irq_status(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- u32 *status);
-
-/**
- * struct dpmcp_attr - Structure representing DPMCP attributes
- * @id: DPMCP object ID
- */
-struct dpmcp_attr {
- int id;
-};
-
-int dpmcp_get_attributes(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- struct dpmcp_attr *attr);
-
#endif /* __FSL_DPMCP_H */
/* Command IDs */
#define DPRC_CMDID_CLOSE DPRC_CMD(0x800)
#define DPRC_CMDID_OPEN DPRC_CMD(0x805)
-#define DPRC_CMDID_CREATE DPRC_CMD(0x905)
#define DPRC_CMDID_GET_API_VERSION DPRC_CMD(0xa05)
#define DPRC_CMDID_GET_ATTR DPRC_CMD(0x004)
-#define DPRC_CMDID_RESET_CONT DPRC_CMD(0x005)
#define DPRC_CMDID_SET_IRQ DPRC_CMD(0x010)
#define DPRC_CMDID_GET_IRQ DPRC_CMD(0x011)
#define DPRC_CMDID_GET_IRQ_STATUS DPRC_CMD(0x016)
#define DPRC_CMDID_CLEAR_IRQ_STATUS DPRC_CMD(0x017)
-#define DPRC_CMDID_CREATE_CONT DPRC_CMD(0x151)
-#define DPRC_CMDID_DESTROY_CONT DPRC_CMD(0x152)
#define DPRC_CMDID_GET_CONT_ID DPRC_CMD(0x830)
-#define DPRC_CMDID_SET_RES_QUOTA DPRC_CMD(0x155)
-#define DPRC_CMDID_GET_RES_QUOTA DPRC_CMD(0x156)
-#define DPRC_CMDID_ASSIGN DPRC_CMD(0x157)
-#define DPRC_CMDID_UNASSIGN DPRC_CMD(0x158)
#define DPRC_CMDID_GET_OBJ_COUNT DPRC_CMD(0x159)
#define DPRC_CMDID_GET_OBJ DPRC_CMD(0x15A)
#define DPRC_CMDID_GET_RES_COUNT DPRC_CMD(0x15B)
-#define DPRC_CMDID_GET_RES_IDS DPRC_CMD(0x15C)
#define DPRC_CMDID_GET_OBJ_REG DPRC_CMD(0x15E)
#define DPRC_CMDID_SET_OBJ_IRQ DPRC_CMD(0x15F)
#define DPRC_CMDID_GET_OBJ_IRQ DPRC_CMD(0x160)
-#define DPRC_CMDID_SET_OBJ_LABEL DPRC_CMD(0x161)
-#define DPRC_CMDID_GET_OBJ_DESC DPRC_CMD(0x162)
-
-#define DPRC_CMDID_CONNECT DPRC_CMD(0x167)
-#define DPRC_CMDID_DISCONNECT DPRC_CMD(0x168)
-#define DPRC_CMDID_GET_POOL DPRC_CMD(0x169)
-#define DPRC_CMDID_GET_POOL_COUNT DPRC_CMD(0x16A)
-
-#define DPRC_CMDID_GET_CONNECTION DPRC_CMD(0x16C)
struct dprc_cmd_open {
__le32 container_id;
child_dev = fsl_mc_device_lookup(obj_desc, mc_bus_dev);
if (child_dev) {
check_plugged_state_change(child_dev, obj_desc);
+ put_device(&child_dev->dev);
continue;
}
}
EXPORT_SYMBOL(dprc_close);
-/**
- * dprc_create_container() - Create child container
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPRC object
- * @cfg: Child container configuration
- * @child_container_id: Returned child container ID
- * @child_portal_offset: Returned child portal offset from MC portal base
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dprc_create_container(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- struct dprc_cfg *cfg,
- int *child_container_id,
- u64 *child_portal_offset)
-{
- struct mc_command cmd = { 0 };
- struct dprc_cmd_create_container *cmd_params;
- struct dprc_rsp_create_container *rsp_params;
- int err;
-
- /* prepare command */
- cmd_params = (struct dprc_cmd_create_container *)cmd.params;
- cmd_params->options = cpu_to_le32(cfg->options);
- cmd_params->icid = cpu_to_le16(cfg->icid);
- cmd_params->portal_id = cpu_to_le32(cfg->portal_id);
- strncpy(cmd_params->label, cfg->label, 16);
- cmd_params->label[15] = '\0';
-
- cmd.header = mc_encode_cmd_header(DPRC_CMDID_CREATE_CONT,
- cmd_flags, token);
-
- /* send command to mc*/
- err = mc_send_command(mc_io, &cmd);
- if (err)
- return err;
-
- /* retrieve response parameters */
- rsp_params = (struct dprc_rsp_create_container *)cmd.params;
- *child_container_id = le32_to_cpu(rsp_params->child_container_id);
- *child_portal_offset = le64_to_cpu(rsp_params->child_portal_addr);
-
- return 0;
-}
-
-/**
- * dprc_destroy_container() - Destroy child container.
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPRC object
- * @child_container_id: ID of the container to destroy
- *
- * This function terminates the child container, so following this call the
- * child container ID becomes invalid.
- *
- * Notes:
- * - All resources and objects of the destroyed container are returned to the
- * parent container or destroyed if were created be the destroyed container.
- * - This function destroy all the child containers of the specified
- * container prior to destroying the container itself.
- *
- * warning: Only the parent container is allowed to destroy a child policy
- * Container 0 can't be destroyed
- *
- * Return: '0' on Success; Error code otherwise.
- *
- */
-int dprc_destroy_container(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- int child_container_id)
-{
- struct mc_command cmd = { 0 };
- struct dprc_cmd_destroy_container *cmd_params;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPRC_CMDID_DESTROY_CONT,
- cmd_flags, token);
- cmd_params = (struct dprc_cmd_destroy_container *)cmd.params;
- cmd_params->child_container_id = cpu_to_le32(child_container_id);
-
- /* send command to mc*/
- return mc_send_command(mc_io, &cmd);
-}
-
-/**
- * dprc_reset_container - Reset child container.
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPRC object
- * @child_container_id: ID of the container to reset
- *
- * In case a software context crashes or becomes non-responsive, the parent
- * may wish to reset its resources container before the software context is
- * restarted.
- *
- * This routine informs all objects assigned to the child container that the
- * container is being reset, so they may perform any cleanup operations that are
- * needed. All objects handles that were owned by the child container shall be
- * closed.
- *
- * Note that such request may be submitted even if the child software context
- * has not crashed, but the resulting object cleanup operations will not be
- * aware of that.
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dprc_reset_container(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- int child_container_id)
-{
- struct mc_command cmd = { 0 };
- struct dprc_cmd_reset_container *cmd_params;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPRC_CMDID_RESET_CONT,
- cmd_flags, token);
- cmd_params = (struct dprc_cmd_reset_container *)cmd.params;
- cmd_params->child_container_id = cpu_to_le32(child_container_id);
-
- /* send command to mc*/
- return mc_send_command(mc_io, &cmd);
-}
-
/**
* dprc_get_irq() - Get IRQ information from the DPRC.
* @mc_io: Pointer to MC portal's I/O object
return 0;
}
-/**
- * dprc_set_res_quota() - Set allocation policy for a specific resource/object
- * type in a child container
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPRC object
- * @child_container_id: ID of the child container
- * @type: Resource/object type
- * @quota: Sets the maximum number of resources of the selected type
- * that the child container is allowed to allocate from its parent;
- * when quota is set to -1, the policy is the same as container's
- * general policy.
- *
- * Allocation policy determines whether or not a container may allocate
- * resources from its parent. Each container has a 'global' allocation policy
- * that is set when the container is created.
- *
- * This function sets allocation policy for a specific resource type.
- * The default policy for all resource types matches the container's 'global'
- * allocation policy.
- *
- * Return: '0' on Success; Error code otherwise.
- *
- * @warning Only the parent container is allowed to change a child policy.
- */
-int dprc_set_res_quota(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- int child_container_id,
- char *type,
- u16 quota)
-{
- struct mc_command cmd = { 0 };
- struct dprc_cmd_set_res_quota *cmd_params;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPRC_CMDID_SET_RES_QUOTA,
- cmd_flags, token);
- cmd_params = (struct dprc_cmd_set_res_quota *)cmd.params;
- cmd_params->child_container_id = cpu_to_le32(child_container_id);
- cmd_params->quota = cpu_to_le16(quota);
- strncpy(cmd_params->type, type, 16);
- cmd_params->type[15] = '\0';
-
- /* send command to mc*/
- return mc_send_command(mc_io, &cmd);
-}
-
-/**
- * dprc_get_res_quota() - Gets the allocation policy of a specific
- * resource/object type in a child container
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPRC object
- * @child_container_id; ID of the child container
- * @type: resource/object type
- * @quota: Returnes the maximum number of resources of the selected type
- * that the child container is allowed to allocate from the parent;
- * when quota is set to -1, the policy is the same as container's
- * general policy.
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dprc_get_res_quota(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- int child_container_id,
- char *type,
- u16 *quota)
-{
- struct mc_command cmd = { 0 };
- struct dprc_cmd_get_res_quota *cmd_params;
- struct dprc_rsp_get_res_quota *rsp_params;
- int err;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_RES_QUOTA,
- cmd_flags, token);
- cmd_params = (struct dprc_cmd_get_res_quota *)cmd.params;
- cmd_params->child_container_id = cpu_to_le32(child_container_id);
- strncpy(cmd_params->type, type, 16);
- cmd_params->type[15] = '\0';
-
- /* send command to mc*/
- err = mc_send_command(mc_io, &cmd);
- if (err)
- return err;
-
- /* retrieve response parameters */
- rsp_params = (struct dprc_rsp_get_res_quota *)cmd.params;
- *quota = le16_to_cpu(rsp_params->quota);
-
- return 0;
-}
-
-/**
- * dprc_assign() - Assigns objects or resource to a child container.
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPRC object
- * @container_id: ID of the child container
- * @res_req: Describes the type and amount of resources to
- * assign to the given container
- *
- * Assignment is usually done by a parent (this DPRC) to one of its child
- * containers.
- *
- * According to the DPRC allocation policy, the assigned resources may be taken
- * (allocated) from the container's ancestors, if not enough resources are
- * available in the container itself.
- *
- * The type of assignment depends on the dprc_res_req options, as follows:
- * - DPRC_RES_REQ_OPT_EXPLICIT: indicates that assigned resources should have
- * the explicit base ID specified at the id_base_align field of res_req.
- * - DPRC_RES_REQ_OPT_ALIGNED: indicates that the assigned resources should be
- * aligned to the value given at id_base_align field of res_req.
- * - DPRC_RES_REQ_OPT_PLUGGED: Relevant only for object assignment,
- * and indicates that the object must be set to the plugged state.
- *
- * A container may use this function with its own ID in order to change a
- * object state to plugged or unplugged.
- *
- * If IRQ information has been set in the child DPRC, it will signal an
- * interrupt following every change in its object assignment.
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dprc_assign(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- int container_id,
- struct dprc_res_req *res_req)
-{
- struct mc_command cmd = { 0 };
- struct dprc_cmd_assign *cmd_params;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPRC_CMDID_ASSIGN,
- cmd_flags, token);
- cmd_params = (struct dprc_cmd_assign *)cmd.params;
- cmd_params->container_id = cpu_to_le32(container_id);
- cmd_params->options = cpu_to_le32(res_req->options);
- cmd_params->num = cpu_to_le32(res_req->num);
- cmd_params->id_base_align = cpu_to_le32(res_req->id_base_align);
- strncpy(cmd_params->type, res_req->type, 16);
- cmd_params->type[15] = '\0';
-
- /* send command to mc*/
- return mc_send_command(mc_io, &cmd);
-}
-
-/**
- * dprc_unassign() - Un-assigns objects or resources from a child container
- * and moves them into this (parent) DPRC.
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPRC object
- * @child_container_id: ID of the child container
- * @res_req: Describes the type and amount of resources to un-assign from
- * the child container
- *
- * Un-assignment of objects can succeed only if the object is not in the
- * plugged or opened state.
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dprc_unassign(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- int child_container_id,
- struct dprc_res_req *res_req)
-{
- struct mc_command cmd = { 0 };
- struct dprc_cmd_unassign *cmd_params;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPRC_CMDID_UNASSIGN,
- cmd_flags,
- token);
- cmd_params = (struct dprc_cmd_unassign *)cmd.params;
- cmd_params->child_container_id = cpu_to_le32(child_container_id);
- cmd_params->options = cpu_to_le32(res_req->options);
- cmd_params->num = cpu_to_le32(res_req->num);
- cmd_params->id_base_align = cpu_to_le32(res_req->id_base_align);
- strncpy(cmd_params->type, res_req->type, 16);
- cmd_params->type[15] = '\0';
-
- /* send command to mc*/
- return mc_send_command(mc_io, &cmd);
-}
-
-/**
- * dprc_get_pool_count() - Get the number of dprc's pools
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @mc_io: Pointer to MC portal's I/O object
- * @token: Token of DPRC object
- * @pool_count: Returned number of resource pools in the dprc
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dprc_get_pool_count(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- int *pool_count)
-{
- struct mc_command cmd = { 0 };
- struct dprc_rsp_get_pool_count *rsp_params;
- int err;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_POOL_COUNT,
- cmd_flags, token);
-
- /* send command to mc*/
- err = mc_send_command(mc_io, &cmd);
- if (err)
- return err;
-
- /* retrieve response parameters */
- rsp_params = (struct dprc_rsp_get_pool_count *)cmd.params;
- *pool_count = le32_to_cpu(rsp_params->pool_count);
-
- return 0;
-}
-
-/**
- * dprc_get_pool() - Get the type (string) of a certain dprc's pool
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPRC object
- * @pool_index; Index of the pool to be queried (< pool_count)
- * @type: The type of the pool
- *
- * The pool types retrieved one by one by incrementing
- * pool_index up to (not including) the value of pool_count returned
- * from dprc_get_pool_count(). dprc_get_pool_count() must
- * be called prior to dprc_get_pool().
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dprc_get_pool(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- int pool_index,
- char *type)
-{
- struct mc_command cmd = { 0 };
- struct dprc_cmd_get_pool *cmd_params;
- struct dprc_rsp_get_pool *rsp_params;
- int err;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_POOL,
- cmd_flags,
- token);
- cmd_params = (struct dprc_cmd_get_pool *)cmd.params;
- cmd_params->pool_index = cpu_to_le32(pool_index);
-
- /* send command to mc*/
- err = mc_send_command(mc_io, &cmd);
- if (err)
- return err;
-
- /* retrieve response parameters */
- rsp_params = (struct dprc_rsp_get_pool *)cmd.params;
- strncpy(type, rsp_params->type, 16);
- type[15] = '\0';
-
- return 0;
-}
-
/**
* dprc_get_obj_count() - Obtains the number of objects in the DPRC
* @mc_io: Pointer to MC portal's I/O object
}
EXPORT_SYMBOL(dprc_get_obj);
-/**
- * dprc_get_obj_desc() - Get object descriptor.
- *
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPRC object
- * @obj_type: The type of the object to get its descriptor.
- * @obj_id: The id of the object to get its descriptor
- * @obj_desc: The returned descriptor to fill and return to the user
- *
- * Return: '0' on Success; Error code otherwise.
- *
- */
-int dprc_get_obj_desc(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- char *obj_type,
- int obj_id,
- struct dprc_obj_desc *obj_desc)
-{
- struct mc_command cmd = { 0 };
- struct dprc_cmd_get_obj_desc *cmd_params;
- struct dprc_rsp_get_obj_desc *rsp_params;
- int err;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_DESC,
- cmd_flags,
- token);
- cmd_params = (struct dprc_cmd_get_obj_desc *)cmd.params;
- cmd_params->obj_id = cpu_to_le32(obj_id);
- strncpy(cmd_params->type, obj_type, 16);
- cmd_params->type[15] = '\0';
-
- /* send command to mc*/
- err = mc_send_command(mc_io, &cmd);
- if (err)
- return err;
-
- /* retrieve response parameters */
- rsp_params = (struct dprc_rsp_get_obj_desc *)cmd.params;
- obj_desc->id = le32_to_cpu(rsp_params->id);
- obj_desc->vendor = le16_to_cpu(rsp_params->vendor);
- obj_desc->irq_count = rsp_params->irq_count;
- obj_desc->region_count = rsp_params->region_count;
- obj_desc->state = le32_to_cpu(rsp_params->state);
- obj_desc->ver_major = le16_to_cpu(rsp_params->version_major);
- obj_desc->ver_minor = le16_to_cpu(rsp_params->version_minor);
- obj_desc->flags = le16_to_cpu(rsp_params->flags);
- strncpy(obj_desc->type, rsp_params->type, 16);
- obj_desc->type[15] = '\0';
- strncpy(obj_desc->label, rsp_params->label, 16);
- obj_desc->label[15] = '\0';
-
- return 0;
-}
-EXPORT_SYMBOL(dprc_get_obj_desc);
-
/**
* dprc_set_obj_irq() - Set IRQ information for object to trigger an interrupt.
* @mc_io: Pointer to MC portal's I/O object
}
EXPORT_SYMBOL(dprc_get_res_count);
-/**
- * dprc_get_res_ids() - Obtains IDs of free resources in the container
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPRC object
- * @type: pool type
- * @range_desc: range descriptor
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dprc_get_res_ids(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- char *type,
- struct dprc_res_ids_range_desc *range_desc)
-{
- struct mc_command cmd = { 0 };
- struct dprc_cmd_get_res_ids *cmd_params;
- struct dprc_rsp_get_res_ids *rsp_params;
- int err;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_RES_IDS,
- cmd_flags, token);
- cmd_params = (struct dprc_cmd_get_res_ids *)cmd.params;
- cmd_params->iter_status = range_desc->iter_status;
- cmd_params->base_id = cpu_to_le32(range_desc->base_id);
- cmd_params->last_id = cpu_to_le32(range_desc->last_id);
- strncpy(cmd_params->type, type, 16);
- cmd_params->type[15] = '\0';
-
- /* send command to mc*/
- err = mc_send_command(mc_io, &cmd);
- if (err)
- return err;
-
- /* retrieve response parameters */
- rsp_params = (struct dprc_rsp_get_res_ids *)cmd.params;
- range_desc->iter_status = rsp_params->iter_status;
- range_desc->base_id = le32_to_cpu(rsp_params->base_id);
- range_desc->last_id = le32_to_cpu(rsp_params->last_id);
-
- return 0;
-}
-EXPORT_SYMBOL(dprc_get_res_ids);
-
/**
* dprc_get_obj_region() - Get region information for a specified object.
* @mc_io: Pointer to MC portal's I/O object
}
EXPORT_SYMBOL(dprc_get_obj_region);
-/**
- * dprc_set_obj_label() - Set object label.
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPRC object
- * @obj_type: Object's type
- * @obj_id: Object's ID
- * @label: The required label. The maximum length is 16 chars.
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dprc_set_obj_label(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- char *obj_type,
- int obj_id,
- char *label)
-{
- struct mc_command cmd = { 0 };
- struct dprc_cmd_set_obj_label *cmd_params;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPRC_CMDID_SET_OBJ_LABEL,
- cmd_flags,
- token);
- cmd_params = (struct dprc_cmd_set_obj_label *)cmd.params;
- cmd_params->obj_id = cpu_to_le32(obj_id);
- strncpy(cmd_params->label, label, 16);
- cmd_params->label[15] = '\0';
- strncpy(cmd_params->obj_type, obj_type, 16);
- cmd_params->obj_type[15] = '\0';
-
- /* send command to mc*/
- return mc_send_command(mc_io, &cmd);
-}
-EXPORT_SYMBOL(dprc_set_obj_label);
-
-/**
- * dprc_connect() - Connect two endpoints to create a network link between them
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPRC object
- * @endpoint1: Endpoint 1 configuration parameters
- * @endpoint2: Endpoint 2 configuration parameters
- * @cfg: Connection configuration. The connection configuration is ignored for
- * connections made to DPMAC objects, where rate is retrieved from the
- * MAC configuration.
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dprc_connect(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- const struct dprc_endpoint *endpoint1,
- const struct dprc_endpoint *endpoint2,
- const struct dprc_connection_cfg *cfg)
-{
- struct mc_command cmd = { 0 };
- struct dprc_cmd_connect *cmd_params;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPRC_CMDID_CONNECT,
- cmd_flags,
- token);
- cmd_params = (struct dprc_cmd_connect *)cmd.params;
- cmd_params->ep1_id = cpu_to_le32(endpoint1->id);
- cmd_params->ep1_interface_id = cpu_to_le32(endpoint1->if_id);
- cmd_params->ep2_id = cpu_to_le32(endpoint2->id);
- cmd_params->ep2_interface_id = cpu_to_le32(endpoint2->if_id);
- strncpy(cmd_params->ep1_type, endpoint1->type, 16);
- cmd_params->ep1_type[15] = '\0';
- cmd_params->max_rate = cpu_to_le32(cfg->max_rate);
- cmd_params->committed_rate = cpu_to_le32(cfg->committed_rate);
- strncpy(cmd_params->ep2_type, endpoint2->type, 16);
- cmd_params->ep2_type[15] = '\0';
-
- /* send command to mc*/
- return mc_send_command(mc_io, &cmd);
-}
-
-/**
- * dprc_disconnect() - Disconnect one endpoint to remove its network connection
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPRC object
- * @endpoint: Endpoint configuration parameters
- *
- * Return: '0' on Success; Error code otherwise.
- */
-int dprc_disconnect(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- const struct dprc_endpoint *endpoint)
-{
- struct mc_command cmd = { 0 };
- struct dprc_cmd_disconnect *cmd_params;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPRC_CMDID_DISCONNECT,
- cmd_flags,
- token);
- cmd_params = (struct dprc_cmd_disconnect *)cmd.params;
- cmd_params->id = cpu_to_le32(endpoint->id);
- cmd_params->interface_id = cpu_to_le32(endpoint->if_id);
- strncpy(cmd_params->type, endpoint->type, 16);
- cmd_params->type[15] = '\0';
-
- /* send command to mc*/
- return mc_send_command(mc_io, &cmd);
-}
-
-/**
- * dprc_get_connection() - Get connected endpoint and link status if connection
- * exists.
- * @mc_io: Pointer to MC portal's I/O object
- * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
- * @token: Token of DPRC object
- * @endpoint1: Endpoint 1 configuration parameters
- * @endpoint2: Returned endpoint 2 configuration parameters
- * @state: Returned link state:
- * 1 - link is up;
- * 0 - link is down;
- * -1 - no connection (endpoint2 information is irrelevant)
- *
- * Return: '0' on Success; -ENAVAIL if connection does not exist.
- */
-int dprc_get_connection(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- const struct dprc_endpoint *endpoint1,
- struct dprc_endpoint *endpoint2,
- int *state)
-{
- struct mc_command cmd = { 0 };
- struct dprc_cmd_get_connection *cmd_params;
- struct dprc_rsp_get_connection *rsp_params;
- int err;
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_CONNECTION,
- cmd_flags,
- token);
- cmd_params = (struct dprc_cmd_get_connection *)cmd.params;
- cmd_params->ep1_id = cpu_to_le32(endpoint1->id);
- cmd_params->ep1_interface_id = cpu_to_le32(endpoint1->if_id);
- strncpy(cmd_params->ep1_type, endpoint1->type, 16);
- cmd_params->ep1_type[15] = '\0';
-
- /* send command to mc*/
- err = mc_send_command(mc_io, &cmd);
- if (err)
- return err;
-
- /* retrieve response parameters */
- rsp_params = (struct dprc_rsp_get_connection *)cmd.params;
- endpoint2->id = le32_to_cpu(rsp_params->ep2_id);
- endpoint2->if_id = le32_to_cpu(rsp_params->ep2_interface_id);
- strncpy(endpoint2->type, rsp_params->ep2_type, 16);
- endpoint2->type[15] = '\0';
- *state = le32_to_cpu(rsp_params->state);
-
- return 0;
-}
-
/**
* dprc_get_api_version - Get Data Path Resource Container API version
* @mc_io: Pointer to Mc portal's I/O object
#include "fsl-mc-private.h"
#include "dprc-cmd.h"
-static struct kmem_cache *mc_dev_cache;
-
/**
* Default DMA mask for devices on a fsl-mc bus
*/
struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(drv);
bool found = false;
- if (WARN_ON(!fsl_mc_bus_exists()))
- goto out;
-
if (!mc_drv->match_id_table)
goto out;
};
EXPORT_SYMBOL_GPL(fsl_mc_bus_type);
-static atomic_t root_dprc_count = ATOMIC_INIT(0);
-
static int fsl_mc_driver_probe(struct device *dev)
{
struct fsl_mc_driver *mc_drv;
}
EXPORT_SYMBOL_GPL(fsl_mc_driver_unregister);
-/**
- * fsl_mc_bus_exists - check if a root dprc exists
- */
-bool fsl_mc_bus_exists(void)
-{
- return atomic_read(&root_dprc_count) > 0;
-}
-EXPORT_SYMBOL_GPL(fsl_mc_bus_exists);
-
/**
* fsl_mc_get_root_dprc - function to traverse to the root dprc
*/
return dev == root_dprc_dev;
}
+static void fsl_mc_device_release(struct device *dev)
+{
+ struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
+ struct fsl_mc_bus *mc_bus = NULL;
+
+ kfree(mc_dev->regions);
+
+ if (strcmp(mc_dev->obj_desc.type, "dprc") == 0)
+ mc_bus = to_fsl_mc_bus(mc_dev);
+
+ if (mc_bus)
+ kfree(mc_bus);
+ else
+ kfree(mc_dev);
+}
+
/**
* Add a newly discovered fsl-mc device to be visible in Linux
*/
/*
* Allocate an MC bus device object:
*/
- mc_bus = devm_kzalloc(parent_dev, sizeof(*mc_bus), GFP_KERNEL);
+ mc_bus = kzalloc(sizeof(*mc_bus), GFP_KERNEL);
if (!mc_bus)
return -ENOMEM;
/*
* Allocate a regular fsl_mc_device object:
*/
- mc_dev = kmem_cache_zalloc(mc_dev_cache, GFP_KERNEL);
+ mc_dev = kzalloc(sizeof(*mc_dev), GFP_KERNEL);
if (!mc_dev)
return -ENOMEM;
}
device_initialize(&mc_dev->dev);
mc_dev->dev.parent = parent_dev;
mc_dev->dev.bus = &fsl_mc_bus_type;
+ mc_dev->dev.release = fsl_mc_device_release;
dev_set_name(&mc_dev->dev, "%s.%d", obj_desc->type, obj_desc->id);
if (strcmp(obj_desc->type, "dprc") == 0) {
}
mc_io2 = mc_io;
-
- atomic_inc(&root_dprc_count);
}
error = get_dprc_icid(mc_io2, obj_desc->id, &mc_dev->icid);
goto error_cleanup_dev;
}
- (void)get_device(&mc_dev->dev);
dev_dbg(parent_dev, "added %s\n", dev_name(&mc_dev->dev));
*new_mc_dev = mc_dev;
error_cleanup_dev:
kfree(mc_dev->regions);
if (mc_bus)
- devm_kfree(parent_dev, mc_bus);
+ kfree(mc_bus);
else
- kmem_cache_free(mc_dev_cache, mc_dev);
+ kfree(mc_dev);
return error;
}
*/
void fsl_mc_device_remove(struct fsl_mc_device *mc_dev)
{
- struct fsl_mc_bus *mc_bus = NULL;
-
- kfree(mc_dev->regions);
-
/*
* The device-specific remove callback will get invoked by device_del()
*/
device_del(&mc_dev->dev);
put_device(&mc_dev->dev);
-
- if (strcmp(mc_dev->obj_desc.type, "dprc") == 0) {
- mc_bus = to_fsl_mc_bus(mc_dev);
-
- if (fsl_mc_is_root_dprc(&mc_dev->dev)) {
- if (atomic_read(&root_dprc_count) > 0)
- atomic_dec(&root_dprc_count);
- else
- WARN_ON(1);
- }
- }
-
- if (mc_bus)
- devm_kfree(mc_dev->dev.parent, mc_bus);
- else
- kmem_cache_free(mc_dev_cache, mc_dev);
}
EXPORT_SYMBOL_GPL(fsl_mc_device_remove);
error = dprc_get_container_id(mc_io, 0, &container_id);
if (error < 0) {
dev_err(&pdev->dev,
- "dpmng_get_container_id() failed: %d\n", error);
+ "dprc_get_container_id() failed: %d\n", error);
goto error_cleanup_mc_io;
}
{
int error;
- mc_dev_cache = kmem_cache_create("fsl_mc_device",
- sizeof(struct fsl_mc_device), 0, 0,
- NULL);
- if (!mc_dev_cache) {
- pr_err("Could not create fsl_mc_device cache\n");
- return -ENOMEM;
- }
-
error = bus_register(&fsl_mc_bus_type);
if (error < 0) {
pr_err("bus type registration failed: %d\n", error);
bus_unregister(&fsl_mc_bus_type);
error_cleanup_cache:
- kmem_cache_destroy(mc_dev_cache);
return error;
}
postcore_initcall(fsl_mc_bus_driver_init);
u32 cmd_flags,
u16 token);
-/**
- * struct dpbp_cfg - Structure representing DPBP configuration
- * @options: place holder
- */
-struct dpbp_cfg {
- u32 options;
-};
-
-int dpbp_create(struct fsl_mc_io *mc_io,
- u16 dprc_token,
- u32 cmd_flags,
- const struct dpbp_cfg *cfg,
- u32 *obj_id);
-
-int dpbp_destroy(struct fsl_mc_io *mc_io,
- u16 dprc_token,
- u32 cmd_flags,
- u32 obj_id);
-
int dpbp_enable(struct fsl_mc_io *mc_io,
u32 cmd_flags,
u16 token);
u32 cmd_flags,
u16 token);
-/**
- * struct dpbp_irq_cfg - IRQ configuration
- * @addr: Address that must be written to signal a message-based interrupt
- * @val: Value to write into irq_addr address
- * @irq_num: A user defined number associated with this IRQ
- */
-struct dpbp_irq_cfg {
- u64 addr;
- u32 val;
- int irq_num;
-};
-
-int dpbp_set_irq(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- struct dpbp_irq_cfg *irq_cfg);
-
-int dpbp_get_irq(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- int *type,
- struct dpbp_irq_cfg *irq_cfg);
-
-int dpbp_set_irq_enable(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- u8 en);
-
-int dpbp_get_irq_enable(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- u8 *en);
-
-int dpbp_set_irq_mask(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- u32 mask);
-
-int dpbp_get_irq_mask(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- u32 *mask);
-
-int dpbp_get_irq_status(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- u32 *status);
-
-int dpbp_clear_irq_status(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- u8 irq_index,
- u32 status);
-
/**
* struct dpbp_attr - Structure representing DPBP attributes
* @id: DPBP object ID
u16 token,
struct dpbp_attr *attr);
-/**
- * DPBP notifications options
- */
-
-/**
- * BPSCN write will attempt to allocate into a cache (coherent write)
- */
-#define DPBP_NOTIF_OPT_COHERENT_WRITE 0x00000001
-
-/**
- * struct dpbp_notification_cfg - Structure representing DPBP notifications
- * towards software
- * @depletion_entry: below this threshold the pool is "depleted";
- * set it to '0' to disable it
- * @depletion_exit: greater than or equal to this threshold the pool exit its
- * "depleted" state
- * @surplus_entry: above this threshold the pool is in "surplus" state;
- * set it to '0' to disable it
- * @surplus_exit: less than or equal to this threshold the pool exit its
- * "surplus" state
- * @message_iova: MUST be given if either 'depletion_entry' or 'surplus_entry'
- * is not '0' (enable); I/O virtual address (must be in DMA-able memory),
- * must be 16B aligned.
- * @message_ctx: The context that will be part of the BPSCN message and will
- * be written to 'message_iova'
- * @options: Mask of available options; use 'DPBP_NOTIF_OPT_<X>' values
- */
-struct dpbp_notification_cfg {
- u32 depletion_entry;
- u32 depletion_exit;
- u32 surplus_entry;
- u32 surplus_exit;
- u64 message_iova;
- u64 message_ctx;
- u16 options;
-};
-
-int dpbp_set_notifications(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- struct dpbp_notification_cfg *cfg);
-
-int dpbp_get_notifications(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- struct dpbp_notification_cfg *cfg);
-
int dpbp_get_api_version(struct fsl_mc_io *mc_io,
u32 cmd_flags,
u16 *major_ver,
u16 *minor_ver);
-/** @} */
-
#endif /* __FSL_DPBP_H */
u32 cmd_flags,
struct mc_version *mc_ver_info);
-int dpmng_get_container_id(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- int *container_id);
-
#endif /* __FSL_DPMNG_H */
struct fsl_mc_io;
-/**
- * Set this value as the icid value in dprc_cfg structure when creating a
- * container, in case the ICID is not selected by the user and should be
- * allocated by the DPRC from the pool of ICIDs.
- */
-#define DPRC_GET_ICID_FROM_POOL (u16)(~(0))
-
-/**
- * Set this value as the portal_id value in dprc_cfg structure when creating a
- * container, in case the portal ID is not specifically selected by the
- * user and should be allocated by the DPRC from the pool of portal ids.
- */
-#define DPRC_GET_PORTAL_ID_FROM_POOL (int)(~(0))
-
int dprc_open(struct fsl_mc_io *mc_io,
u32 cmd_flags,
int container_id,
u32 cmd_flags,
u16 token);
-/**
- * Container general options
- *
- * These options may be selected at container creation by the container creator
- * and can be retrieved using dprc_get_attributes()
- */
-
-/*
- * Spawn Policy Option allowed - Indicates that the new container is allowed
- * to spawn and have its own child containers.
- */
-#define DPRC_CFG_OPT_SPAWN_ALLOWED 0x00000001
-
-/*
- * General Container allocation policy - Indicates that the new container is
- * allowed to allocate requested resources from its parent container; if not
- * set, the container is only allowed to use resources in its own pools; Note
- * that this is a container's global policy, but the parent container may
- * override it and set specific quota per resource type.
- */
-#define DPRC_CFG_OPT_ALLOC_ALLOWED 0x00000002
-
-/*
- * Object initialization allowed - software context associated with this
- * container is allowed to invoke object initialization operations.
- */
-#define DPRC_CFG_OPT_OBJ_CREATE_ALLOWED 0x00000004
-
-/*
- * Topology change allowed - software context associated with this
- * container is allowed to invoke topology operations, such as attach/detach
- * of network objects.
- */
-#define DPRC_CFG_OPT_TOPOLOGY_CHANGES_ALLOWED 0x00000008
-
-/* AIOP - Indicates that container belongs to AIOP. */
-#define DPRC_CFG_OPT_AIOP 0x00000020
-
-/* IRQ Config - Indicates that the container allowed to configure its IRQs. */
-#define DPRC_CFG_OPT_IRQ_CFG_ALLOWED 0x00000040
-
-/**
- * struct dprc_cfg - Container configuration options
- * @icid: Container's ICID; if set to 'DPRC_GET_ICID_FROM_POOL', a free
- * ICID value is allocated by the DPRC
- * @portal_id: Portal ID; if set to 'DPRC_GET_PORTAL_ID_FROM_POOL', a free
- * portal ID is allocated by the DPRC
- * @options: Combination of 'DPRC_CFG_OPT_<X>' options
- * @label: Object's label
- */
-struct dprc_cfg {
- u16 icid;
- int portal_id;
- u64 options;
- char label[16];
-};
-
-int dprc_create_container(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- struct dprc_cfg *cfg,
- int *child_container_id,
- u64 *child_portal_offset);
-
-int dprc_destroy_container(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- int child_container_id);
-
-int dprc_reset_container(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- int child_container_id);
/* IRQ */
u16 token,
struct dprc_attributes *attributes);
-int dprc_set_res_quota(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- int child_container_id,
- char *type,
- u16 quota);
-
-int dprc_get_res_quota(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- int child_container_id,
- char *type,
- u16 *quota);
-
-/* Resource request options */
-
-/*
- * Explicit resource ID request - The requested objects/resources
- * are explicit and sequential (in case of resources).
- * The base ID is given at res_req at base_align field
- */
-#define DPRC_RES_REQ_OPT_EXPLICIT 0x00000001
-
-/*
- * Aligned resources request - Relevant only for resources
- * request (and not objects). Indicates that resources base ID should be
- * sequential and aligned to the value given at dprc_res_req base_align field
- */
-#define DPRC_RES_REQ_OPT_ALIGNED 0x00000002
-
-/*
- * Plugged Flag - Relevant only for object assignment request.
- * Indicates that after all objects assigned. An interrupt will be invoked at
- * the relevant GPP. The assigned object will be marked as plugged.
- * plugged objects can't be assigned from their container
- */
-#define DPRC_RES_REQ_OPT_PLUGGED 0x00000004
-
-/**
- * struct dprc_res_req - Resource request descriptor, to be used in assignment
- * or un-assignment of resources and objects.
- * @type: Resource/object type: Represent as a NULL terminated string.
- * This string may received by using dprc_get_pool() to get resource
- * type and dprc_get_obj() to get object type;
- * Note: it is not possible to assign/un-assign DPRC objects
- * @num: Number of resources
- * @options: Request options: combination of DPRC_RES_REQ_OPT_ options
- * @id_base_align: In case of explicit assignment (DPRC_RES_REQ_OPT_EXPLICIT
- * is set at option), this field represents the required base ID
- * for resource allocation; In case of aligned assignment
- * (DPRC_RES_REQ_OPT_ALIGNED is set at option), this field
- * indicates the required alignment for the resource ID(s) -
- * use 0 if there is no alignment or explicit ID requirements
- */
-struct dprc_res_req {
- char type[16];
- u32 num;
- u32 options;
- int id_base_align;
-};
-
-int dprc_assign(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- int container_id,
- struct dprc_res_req *res_req);
-
-int dprc_unassign(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- int child_container_id,
- struct dprc_res_req *res_req);
-
-int dprc_get_pool_count(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- int *pool_count);
-
-int dprc_get_pool(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- int pool_index,
- char *type);
-
int dprc_get_obj_count(struct fsl_mc_io *mc_io,
u32 cmd_flags,
u16 token,
DPRC_ITER_STATUS_LAST = 2
};
-/**
- * struct dprc_res_ids_range_desc - Resource ID range descriptor
- * @base_id: Base resource ID of this range
- * @last_id: Last resource ID of this range
- * @iter_status: Iteration status - should be set to DPRC_ITER_STATUS_FIRST at
- * first iteration; while the returned marker is DPRC_ITER_STATUS_MORE,
- * additional iterations are needed, until the returned marker is
- * DPRC_ITER_STATUS_LAST
- */
-struct dprc_res_ids_range_desc {
- int base_id;
- int last_id;
- enum dprc_iter_status iter_status;
-};
-
-int dprc_get_res_ids(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- char *type,
- struct dprc_res_ids_range_desc *range_desc);
-
/* Region flags */
/* Cacheable - Indicates that region should be mapped as cacheable */
#define DPRC_REGION_CACHEABLE 0x00000001
u8 region_index,
struct dprc_region_desc *region_desc);
-int dprc_set_obj_label(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- char *obj_type,
- int obj_id,
- char *label);
-
-/**
- * struct dprc_endpoint - Endpoint description for link connect/disconnect
- * operations
- * @type: Endpoint object type: NULL terminated string
- * @id: Endpoint object ID
- * @if_id: Interface ID; should be set for endpoints with multiple
- * interfaces ("dpsw", "dpdmux"); for others, always set to 0
- */
-struct dprc_endpoint {
- char type[16];
- int id;
- int if_id;
-};
-
-/**
- * struct dprc_connection_cfg - Connection configuration.
- * Used for virtual connections only
- * @committed_rate: Committed rate (Mbits/s)
- * @max_rate: Maximum rate (Mbits/s)
- */
-struct dprc_connection_cfg {
- u32 committed_rate;
- u32 max_rate;
-};
-
-int dprc_connect(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- const struct dprc_endpoint *endpoint1,
- const struct dprc_endpoint *endpoint2,
- const struct dprc_connection_cfg *cfg);
-
-int dprc_disconnect(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- const struct dprc_endpoint *endpoint);
-
-int dprc_get_connection(struct fsl_mc_io *mc_io,
- u32 cmd_flags,
- u16 token,
- const struct dprc_endpoint *endpoint1,
- struct dprc_endpoint *endpoint2,
- int *state);
-
int dprc_get_api_version(struct fsl_mc_io *mc_io,
u32 cmd_flags,
u16 *major_ver,
ed->dev_ed = ENDIANNESS_LITTLE;
}
-u16 gdm_cpu_to_dev16(struct gdm_endian *ed, u16 x)
+__dev16 gdm_cpu_to_dev16(struct gdm_endian *ed, u16 x)
{
if (ed->dev_ed == ENDIANNESS_LITTLE)
- return cpu_to_le16(x);
+ return (__force __dev16)cpu_to_le16(x);
else
- return cpu_to_be16(x);
+ return (__force __dev16)cpu_to_be16(x);
}
-u16 gdm_dev16_to_cpu(struct gdm_endian *ed, u16 x)
+u16 gdm_dev16_to_cpu(struct gdm_endian *ed, __dev16 x)
{
if (ed->dev_ed == ENDIANNESS_LITTLE)
- return le16_to_cpu(x);
+ return le16_to_cpu((__force __le16)x);
else
- return be16_to_cpu(x);
+ return be16_to_cpu((__force __be16)x);
}
-u32 gdm_cpu_to_dev32(struct gdm_endian *ed, u32 x)
+__dev32 gdm_cpu_to_dev32(struct gdm_endian *ed, u32 x)
{
if (ed->dev_ed == ENDIANNESS_LITTLE)
- return cpu_to_le32(x);
+ return (__force __dev32)cpu_to_le32(x);
else
- return cpu_to_be32(x);
+ return (__force __dev32)cpu_to_be32(x);
}
-u32 gdm_dev32_to_cpu(struct gdm_endian *ed, u32 x)
+u32 gdm_dev32_to_cpu(struct gdm_endian *ed, __dev32 x)
{
if (ed->dev_ed == ENDIANNESS_LITTLE)
- return le32_to_cpu(x);
+ return le32_to_cpu((__force __le32)x);
else
- return be32_to_cpu(x);
+ return be32_to_cpu((__force __be32)x);
}
#include <linux/types.h>
+/*
+ * For data in "device-endian" byte order (device endianness is model
+ * dependent). Analogous to __leXX or __beXX.
+ */
+typedef __u32 __bitwise __dev32;
+typedef __u16 __bitwise __dev16;
+
enum {
ENDIANNESS_MIN = 0,
ENDIANNESS_UNKNOWN,
};
void gdm_set_endian(struct gdm_endian *ed, u8 dev_endian);
-u16 gdm_cpu_to_dev16(struct gdm_endian *ed, u16 x);
-u16 gdm_dev16_to_cpu(struct gdm_endian *ed, u16 x);
-u32 gdm_cpu_to_dev32(struct gdm_endian *ed, u32 x);
-u32 gdm_dev32_to_cpu(struct gdm_endian *ed, u32 x);
+__dev16 gdm_cpu_to_dev16(struct gdm_endian *ed, u16 x);
+u16 gdm_dev16_to_cpu(struct gdm_endian *ed, __dev16 x);
+__dev32 gdm_cpu_to_dev32(struct gdm_endian *ed, u32 x);
+u32 gdm_dev32_to_cpu(struct gdm_endian *ed, __dev32 x);
#endif /*__GDM_ENDIAN_H__*/
memset(&pseudo_header, 0, sizeof(pseudo_header));
memcpy(&pseudo_header.ph.ph_src, &ipv6->saddr.in6_u.u6_addr8, 16);
memcpy(&pseudo_header.ph.ph_dst, &ipv6->daddr.in6_u.u6_addr8, 16);
- pseudo_header.ph.ph_len = ipv6->payload_len;
+ pseudo_header.ph.ph_len = be16_to_cpu(ipv6->payload_len);
pseudo_header.ph.ph_nxt = ipv6->nexthdr;
w = (u16 *)&pseudo_header;
}
}
-static u8 find_dev_index(u32 nic_type)
+static int find_dev_index(u32 nic_type)
{
u8 index;
index = (u8)(nic_type & 0x0000000f);
- if (index > MAX_NIC_TYPE)
- index = 0;
+ if (index >= MAX_NIC_TYPE)
+ return -EINVAL;
return index;
}
struct net_device *dev;
struct multi_sdu *multi_sdu = (struct multi_sdu *)buf;
struct sdu *sdu = NULL;
+ struct gdm_endian *endian = phy_dev->get_endian(phy_dev->priv_dev);
u8 *data = (u8 *)multi_sdu->data;
u16 i = 0;
u16 num_packet;
u16 hci_len;
u16 cmd_evt;
u32 nic_type;
- u8 index;
+ int index;
- hci_len = gdm_dev16_to_cpu(phy_dev->get_endian(phy_dev->priv_dev),
- multi_sdu->len);
- num_packet = gdm_dev16_to_cpu(phy_dev->get_endian(phy_dev->priv_dev),
- multi_sdu->num_packet);
+ hci_len = gdm_dev16_to_cpu(endian, multi_sdu->len);
+ num_packet = gdm_dev16_to_cpu(endian, multi_sdu->num_packet);
for (i = 0; i < num_packet; i++) {
sdu = (struct sdu *)data;
- cmd_evt = gdm_dev16_to_cpu(phy_dev->
- get_endian(phy_dev->priv_dev), sdu->cmd_evt);
- hci_len = gdm_dev16_to_cpu(phy_dev->
- get_endian(phy_dev->priv_dev), sdu->len);
- nic_type = gdm_dev32_to_cpu(phy_dev->
- get_endian(phy_dev->priv_dev), sdu->nic_type);
+ cmd_evt = gdm_dev16_to_cpu(endian, sdu->cmd_evt);
+ hci_len = gdm_dev16_to_cpu(endian, sdu->len);
+ nic_type = gdm_dev32_to_cpu(endian, sdu->nic_type);
if (cmd_evt != LTE_RX_SDU) {
pr_err("rx sdu wrong hci %04x\n", cmd_evt);
}
index = find_dev_index(nic_type);
- if (index < MAX_NIC_TYPE) {
- dev = phy_dev->dev[index];
- gdm_lte_netif_rx(dev, (char *)sdu->data,
- (int)(hci_len - 12), nic_type);
- } else {
+ if (index < 0) {
pr_err("rx sdu invalid nic_type :%x\n", nic_type);
+ return;
}
+ dev = phy_dev->dev[index];
+ gdm_lte_netif_rx(dev, (char *)sdu->data,
+ (int)(hci_len - 12), nic_type);
data += ((hci_len + 3) & 0xfffc) + HCI_HEADER_SIZE;
}
{
struct hci_packet *hci = (struct hci_packet *)buf;
struct hci_pdn_table_ind *pdn_table = (struct hci_pdn_table_ind *)buf;
+ struct gdm_endian *endian = phy_dev->get_endian(phy_dev->priv_dev);
struct sdu *sdu;
struct net_device *dev;
int ret = 0;
u16 cmd_evt;
u32 nic_type;
- u8 index;
+ int index;
if (!len)
return ret;
- cmd_evt = gdm_dev16_to_cpu(phy_dev->get_endian(phy_dev->priv_dev),
- hci->cmd_evt);
+ cmd_evt = gdm_dev16_to_cpu(endian, hci->cmd_evt);
dev = phy_dev->dev[0];
if (!dev)
switch (cmd_evt) {
case LTE_RX_SDU:
sdu = (struct sdu *)hci->data;
- nic_type = gdm_dev32_to_cpu(phy_dev->
- get_endian(phy_dev->priv_dev), sdu->nic_type);
+ nic_type = gdm_dev32_to_cpu(endian, sdu->nic_type);
index = find_dev_index(nic_type);
+ if (index < 0)
+ return index;
dev = phy_dev->dev[index];
gdm_lte_netif_rx(dev, hci->data, len, nic_type);
break;
break;
case LTE_PDN_TABLE_IND:
pdn_table = (struct hci_pdn_table_ind *)buf;
- nic_type = gdm_dev32_to_cpu(phy_dev->
- get_endian(phy_dev->priv_dev),
- pdn_table->nic_type);
+ nic_type = gdm_dev32_to_cpu(endian, pdn_table->nic_type);
index = find_dev_index(nic_type);
+ if (index < 0)
+ return index;
dev = phy_dev->dev[index];
gdm_lte_pdn_table(dev, buf, len);
/* Fall through */
#define NIC_TYPE_F_VLAN 0x00100000
struct hci_packet {
- u16 cmd_evt;
- u16 len;
+ __dev16 cmd_evt;
+ __dev16 len;
u8 data[0];
} __packed;
} __packed;
struct sdu_header {
- u16 cmd_evt;
- u16 len;
- u32 dftEpsId;
- u32 bearer_ID;
- u32 nic_type;
+ __dev16 cmd_evt;
+ __dev16 len;
+ __dev32 dftEpsId;
+ __dev32 bearer_ID;
+ __dev32 nic_type;
} __packed;
struct sdu {
- u16 cmd_evt;
- u16 len;
- u32 dft_eps_ID;
- u32 bearer_ID;
- u32 nic_type;
+ __dev16 cmd_evt;
+ __dev16 len;
+ __dev32 dft_eps_ID;
+ __dev32 bearer_ID;
+ __dev32 nic_type;
u8 data[0];
} __packed;
struct multi_sdu {
- u16 cmd_evt;
- u16 len;
- u16 num_packet;
- u16 reserved;
+ __dev16 cmd_evt;
+ __dev16 len;
+ __dev16 num_packet;
+ __dev16 reserved;
u8 data[0];
} __packed;
struct hci_pdn_table_ind {
- u16 cmd_evt;
- u16 len;
+ __dev16 cmd_evt;
+ __dev16 len;
u8 activate;
- u32 dft_eps_id;
- u32 nic_type;
+ __dev32 dft_eps_id;
+ __dev32 nic_type;
u8 pdn_type;
u8 ipv4_addr[4];
u8 ipv6_intf_id[8];
} __packed;
struct hci_connect_ind {
- u16 cmd_evt;
- u16 len;
- u32 connect;
+ __dev16 cmd_evt;
+ __dev16 len;
+ __dev32 connect;
} __packed;
#endif /* _HCI_PACKET_H_ */
control.o \
svc.o \
svc_watchdog.o \
- operation.o \
- timesync.o \
- timesync_platform.o
+ operation.o
obj-$(CONFIG_GREYBUS) += greybus.o
return 0;
}
-static int arche_apb_ctrl_suspend(struct device *dev)
+static int __maybe_unused arche_apb_ctrl_suspend(struct device *dev)
{
/*
* If timing profile permits, we may shutdown bridge
return 0;
}
-static int arche_apb_ctrl_resume(struct device *dev)
+static int __maybe_unused arche_apb_ctrl_resume(struct device *dev)
{
/*
* Atleast for ES2 we have to meet the delay requirement between
#ifndef __ARCHE_PLATFORM_H
#define __ARCHE_PLATFORM_H
-#include "timesync.h"
-
enum arche_platform_state {
ARCHE_PLATFORM_STATE_OFF,
ARCHE_PLATFORM_STATE_ACTIVE,
gb_pm_runtime_put_noidle(bundle);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ sig_bits = dai->driver->playback.sig_bits;
+ else
+ sig_bits = dai->driver->capture.sig_bits;
+
params->state = GBAUDIO_CODEC_HWPARAMS;
params->format = format;
params->rate = rate;
.rate_min = 48000,
.channels_min = 1,
.channels_max = 2,
+ .sig_bits = 16,
},
.capture = {
.stream_name = "I2S 0 Capture",
.rate_min = 48000,
.channels_min = 1,
.channels_max = 2,
+ .sig_bits = 16,
},
.ops = &gbcodec_dai_ops,
},
return 0;
}
-static u8 gbcodec_reg[GBCODEC_REG_COUNT] = {
- [GBCODEC_CTL_REG] = GBCODEC_CTL_REG_DEFAULT,
- [GBCODEC_MUTE_REG] = GBCODEC_MUTE_REG_DEFAULT,
- [GBCODEC_PB_LVOL_REG] = GBCODEC_PB_VOL_REG_DEFAULT,
- [GBCODEC_PB_RVOL_REG] = GBCODEC_PB_VOL_REG_DEFAULT,
- [GBCODEC_CAP_LVOL_REG] = GBCODEC_CAP_VOL_REG_DEFAULT,
- [GBCODEC_CAP_RVOL_REG] = GBCODEC_CAP_VOL_REG_DEFAULT,
- [GBCODEC_APB1_MUX_REG] = GBCODEC_APB1_MUX_REG_DEFAULT,
- [GBCODEC_APB2_MUX_REG] = GBCODEC_APB2_MUX_REG_DEFAULT,
-};
-
static int gbcodec_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
- int ret = 0;
-
- if (reg == SND_SOC_NOPM)
- return 0;
-
- BUG_ON(reg >= GBCODEC_REG_COUNT);
-
- gbcodec_reg[reg] = value;
- dev_dbg(codec->dev, "reg[%d] = 0x%x\n", reg, value);
-
- return ret;
+ return 0;
}
static unsigned int gbcodec_read(struct snd_soc_codec *codec,
unsigned int reg)
{
- unsigned int val = 0;
-
- if (reg == SND_SOC_NOPM)
- return 0;
-
- BUG_ON(reg >= GBCODEC_REG_COUNT);
-
- val = gbcodec_reg[reg];
- dev_dbg(codec->dev, "reg[%d] = 0x%x\n", reg, val);
-
- return val;
+ return 0;
}
static struct snd_soc_codec_driver soc_codec_dev_gbaudio = {
.read = gbcodec_read,
.write = gbcodec_write,
- .reg_cache_size = GBCODEC_REG_COUNT,
- .reg_cache_default = gbcodec_reg_defaults,
- .reg_word_size = 1,
-
.idle_bias_off = true,
.ignore_pmdown_time = 1,
};
NUM_CODEC_DAIS,
};
-enum gbcodec_reg_index {
- GBCODEC_CTL_REG,
- GBCODEC_MUTE_REG,
- GBCODEC_PB_LVOL_REG,
- GBCODEC_PB_RVOL_REG,
- GBCODEC_CAP_LVOL_REG,
- GBCODEC_CAP_RVOL_REG,
- GBCODEC_APB1_MUX_REG,
- GBCODEC_APB2_MUX_REG,
- GBCODEC_REG_COUNT
-};
-
/* device_type should be same as defined in audio.h (Android media layer) */
enum {
GBAUDIO_DEVICE_NONE = 0x0,
GBAUDIO_DEVICE_IN_WIRED_HEADSET = GBAUDIO_DEVICE_BIT_IN | 0x10,
};
-/* bit 0-SPK, 1-HP, 2-DAC,
- * 4-MIC, 5-HSMIC, 6-MIC2
- */
-#define GBCODEC_CTL_REG_DEFAULT 0x00
-
-/* bit 0,1 - APB1-PB-L/R
- * bit 2,3 - APB2-PB-L/R
- * bit 4,5 - APB1-Cap-L/R
- * bit 6,7 - APB2-Cap-L/R
- */
-#define GBCODEC_MUTE_REG_DEFAULT 0x00
-
-/* 0-127 steps */
-#define GBCODEC_PB_VOL_REG_DEFAULT 0x00
-#define GBCODEC_CAP_VOL_REG_DEFAULT 0x00
-
-/* bit 0,1,2 - PB stereo, left, right
- * bit 8,9,10 - Cap stereo, left, right
- */
-#define GBCODEC_APB1_MUX_REG_DEFAULT 0x00
-#define GBCODEC_APB2_MUX_REG_DEFAULT 0x00
-
#define GBCODEC_JACK_MASK 0x0000FFFF
#define GBCODEC_JACK_BUTTON_MASK 0xFFFF0000
-static const u8 gbcodec_reg_defaults[GBCODEC_REG_COUNT] = {
- GBCODEC_CTL_REG_DEFAULT,
- GBCODEC_MUTE_REG_DEFAULT,
- GBCODEC_PB_VOL_REG_DEFAULT,
- GBCODEC_PB_VOL_REG_DEFAULT,
- GBCODEC_CAP_VOL_REG_DEFAULT,
- GBCODEC_CAP_VOL_REG_DEFAULT,
- GBCODEC_APB1_MUX_REG_DEFAULT,
- GBCODEC_APB2_MUX_REG_DEFAULT,
-};
-
enum gbaudio_codec_state {
GBAUDIO_CODEC_SHUTDOWN = 0,
GBAUDIO_CODEC_STARTUP,
/* to maintain runtime stream params for each DAI */
struct list_head dai_list;
struct mutex lock;
- u8 reg[GBCODEC_REG_COUNT];
};
struct gbaudio_widget {
EXPORT_SYMBOL_GPL(gb_audio_gb_disable_widget);
int gb_audio_gb_get_pcm(struct gb_connection *connection, u16 data_cport,
- uint32_t *format, uint32_t *rate, u8 *channels,
+ u32 *format, u32 *rate, u8 *channels,
u8 *sig_bits)
{
struct gb_audio_get_pcm_request req;
EXPORT_SYMBOL_GPL(gb_audio_gb_get_pcm);
int gb_audio_gb_set_pcm(struct gb_connection *connection, u16 data_cport,
- uint32_t format, uint32_t rate, u8 channels,
+ u32 format, u32 rate, u8 channels,
u8 sig_bits)
{
struct gb_audio_set_pcm_request req;
struct gb_audio_streaming_event_request *req)
{
dev_warn(module->dev, "Audio Event received: cport: %u, event: %u\n",
- req->data_cport, req->event);
+ le16_to_cpu(req->data_cport), req->event);
return 0;
}
{
const char **strings;
int i;
+ unsigned int items;
__u8 *data;
- strings = devm_kzalloc(gb->dev, sizeof(char *) * gbenum->items,
- GFP_KERNEL);
+ items = le32_to_cpu(gbenum->items);
+ strings = devm_kzalloc(gb->dev, sizeof(char *) * items, GFP_KERNEL);
data = gbenum->names;
- for (i = 0; i < gbenum->items; i++) {
+ for (i = 0; i < items; i++) {
strings[i] = (const char *)data;
while (*data != '\0')
data++;
switch (info->type) {
case GB_AUDIO_CTL_ELEM_TYPE_BOOLEAN:
case GB_AUDIO_CTL_ELEM_TYPE_INTEGER:
- uinfo->value.integer.min = info->value.integer.min;
- uinfo->value.integer.max = info->value.integer.max;
+ uinfo->value.integer.min = le32_to_cpu(info->value.integer.min);
+ uinfo->value.integer.max = le32_to_cpu(info->value.integer.max);
break;
case GB_AUDIO_CTL_ELEM_TYPE_ENUMERATED:
- max = info->value.enumerated.items;
+ max = le32_to_cpu(info->value.enumerated.items);
uinfo->value.enumerated.items = max;
if (uinfo->value.enumerated.item > max - 1)
uinfo->value.enumerated.item = max - 1;
case GB_AUDIO_CTL_ELEM_TYPE_BOOLEAN:
case GB_AUDIO_CTL_ELEM_TYPE_INTEGER:
ucontrol->value.integer.value[0] =
- gbvalue.value.integer_value[0];
+ le32_to_cpu(gbvalue.value.integer_value[0]);
if (data->vcount == 2)
ucontrol->value.integer.value[1] =
- gbvalue.value.integer_value[1];
+ le32_to_cpu(gbvalue.value.integer_value[1]);
break;
case GB_AUDIO_CTL_ELEM_TYPE_ENUMERATED:
ucontrol->value.enumerated.item[0] =
- gbvalue.value.enumerated_item[0];
+ le32_to_cpu(gbvalue.value.enumerated_item[0]);
if (data->vcount == 2)
ucontrol->value.enumerated.item[1] =
- gbvalue.value.enumerated_item[1];
+ le32_to_cpu(gbvalue.value.enumerated_item[1]);
break;
default:
dev_err(codec->dev, "Invalid type: %d for %s:kcontrol\n",
case GB_AUDIO_CTL_ELEM_TYPE_BOOLEAN:
case GB_AUDIO_CTL_ELEM_TYPE_INTEGER:
gbvalue.value.integer_value[0] =
- ucontrol->value.integer.value[0];
+ cpu_to_le32(ucontrol->value.integer.value[0]);
if (data->vcount == 2)
gbvalue.value.integer_value[1] =
- ucontrol->value.integer.value[1];
+ cpu_to_le32(ucontrol->value.integer.value[1]);
break;
case GB_AUDIO_CTL_ELEM_TYPE_ENUMERATED:
gbvalue.value.enumerated_item[0] =
- ucontrol->value.enumerated.item[0];
+ cpu_to_le32(ucontrol->value.enumerated.item[0]);
if (data->vcount == 2)
gbvalue.value.enumerated_item[1] =
- ucontrol->value.enumerated.item[1];
+ cpu_to_le32(ucontrol->value.enumerated.item[1]);
break;
default:
dev_err(codec->dev, "Invalid type: %d for %s:kcontrol\n",
info = (struct gb_audio_ctl_elem_info *)data->info;
/* update uinfo */
- platform_max = info->value.integer.max;
- platform_min = info->value.integer.min;
+ platform_max = le32_to_cpu(info->value.integer.max);
+ platform_min = le32_to_cpu(info->value.integer.min);
if (platform_max == 1 &&
!strnstr(kcontrol->id.name, " Volume", NAME_SIZE))
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = data->vcount;
- uinfo->value.integer.min = 0;
- if (info->value.integer.min < 0 &&
- (uinfo->type == SNDRV_CTL_ELEM_TYPE_INTEGER))
- uinfo->value.integer.max = platform_max - platform_min;
- else
- uinfo->value.integer.max = platform_max;
+ uinfo->value.integer.min = platform_min;
+ uinfo->value.integer.max = platform_max;
return 0;
}
return ret;
}
/* update ucontrol */
- ucontrol->value.integer.value[0] = gbvalue.value.integer_value[0];
+ ucontrol->value.integer.value[0] =
+ le32_to_cpu(gbvalue.value.integer_value[0]);
return ret;
}
"GB: Control '%s' is stereo, which is not supported\n",
kcontrol->id.name);
- max = info->value.integer.max;
+ max = le32_to_cpu(info->value.integer.max);
mask = (1 << fls(max)) - 1;
val = ucontrol->value.integer.value[0] & mask;
connect = !!val;
connect);
}
gbvalue.value.integer_value[0] =
- ucontrol->value.integer.value[0];
+ cpu_to_le32(ucontrol->value.integer.value[0]);
ret = gb_pm_runtime_get_sync(bundle);
if (ret)
return ret;
}
- ucontrol->value.enumerated.item[0] = gbvalue.value.enumerated_item[0];
+ ucontrol->value.enumerated.item[0] =
+ le32_to_cpu(gbvalue.value.enumerated_item[0]);
if (e->shift_l != e->shift_r)
ucontrol->value.enumerated.item[1] =
- gbvalue.value.enumerated_item[1];
+ le32_to_cpu(gbvalue.value.enumerated_item[1]);
return 0;
}
if (ucontrol->value.enumerated.item[0] > e->max - 1)
return -EINVAL;
- gbvalue.value.enumerated_item[0] = ucontrol->value.enumerated.item[0];
+ gbvalue.value.enumerated_item[0] =
+ cpu_to_le32(ucontrol->value.enumerated.item[0]);
if (e->shift_l != e->shift_r) {
if (ucontrol->value.enumerated.item[1] > e->max - 1)
return -EINVAL;
gbvalue.value.enumerated_item[1] =
- ucontrol->value.enumerated.item[1];
+ cpu_to_le32(ucontrol->value.enumerated.item[1]);
}
bundle = to_gb_bundle(module->dev);
gb_enum = &ctl->info.value.enumerated;
/* since count=1, and reg is dummy */
- gbe->max = gb_enum->items;
+ gbe->max = le32_to_cpu(gb_enum->items);
gbe->texts = gb_generate_enum_strings(gb, gb_enum);
/* debug enum info */
- dev_dbg(gb->dev, "Max:%d, name_length:%d\n", gb_enum->items,
- gb_enum->names_length);
- for (i = 0; i < gb_enum->items; i++)
+ dev_dbg(gb->dev, "Max:%d, name_length:%d\n", gbe->max,
+ le16_to_cpu(gb_enum->names_length));
+ for (i = 0; i < gbe->max; i++)
dev_dbg(gb->dev, "src[%d]: %s\n", i, gbe->texts[i]);
*kctl = (struct snd_kcontrol_new)
if (!ctldata)
return -ENOMEM;
ctldata->ctl_id = ctl->id;
- ctldata->data_cport = ctl->data_cport;
+ ctldata->data_cport = le16_to_cpu(ctl->data_cport);
ctldata->access = ctl->access;
ctldata->vcount = ctl->count_values;
ctldata->info = &ctl->info;
gb_enum = &ctl->info.value.enumerated;
/* since count=1, and reg is dummy */
- gbe->max = gb_enum->items;
+ gbe->max = le32_to_cpu(gb_enum->items);
gbe->texts = gb_generate_enum_strings(gb, gb_enum);
/* debug enum info */
- dev_dbg(gb->dev, "Max:%d, name_length:%d\n", gb_enum->items,
- gb_enum->names_length);
- for (i = 0; i < gb_enum->items; i++)
+ dev_dbg(gb->dev, "Max:%d, name_length:%d\n", gbe->max,
+ le16_to_cpu(gb_enum->names_length));
+ for (i = 0; i < gbe->max; i++)
dev_dbg(gb->dev, "src[%d]: %s\n", i, gbe->texts[i]);
*kctl = (struct snd_kcontrol_new)
if (!ctldata)
return -ENOMEM;
ctldata->ctl_id = ctl->id;
- ctldata->data_cport = ctl->data_cport;
+ ctldata->data_cport = le16_to_cpu(ctl->data_cport);
ctldata->access = ctl->access;
ctldata->vcount = ctl->count_values;
ctldata->info = &ctl->info;
csize = offsetof(struct gb_audio_control, info);
csize += offsetof(struct gb_audio_ctl_elem_info, value);
csize += offsetof(struct gb_audio_enumerated, names);
- csize += gbenum->names_length;
+ csize += le16_to_cpu(gbenum->names_length);
control->texts = (const char * const *)
gb_generate_enum_strings(module, gbenum);
- control->items = gbenum->items;
+ control->items = le32_to_cpu(gbenum->items);
} else {
csize = sizeof(struct gb_audio_control);
}
csize = offsetof(struct gb_audio_control, info);
csize += offsetof(struct gb_audio_ctl_elem_info, value);
csize += offsetof(struct gb_audio_enumerated, names);
- csize += gbenum->names_length;
+ csize += le16_to_cpu(gbenum->names_length);
control->texts = (const char * const *)
gb_generate_enum_strings(module, gbenum);
- control->items = gbenum->items;
+ control->items = le32_to_cpu(gbenum->items);
} else {
csize = sizeof(struct gb_audio_control);
}
goto error;
}
dev_dbg(module->dev, "Route {%s, %s, %s}\n", dapm_routes->sink,
- (dapm_routes->control) ? dapm_routes->control:"NULL",
+ (dapm_routes->control) ? dapm_routes->control : "NULL",
dapm_routes->source);
dapm_routes++;
curr++;
/* update block offset */
module->dai_offset = (unsigned long)&tplg_data->data;
- module->control_offset = module->dai_offset + tplg_data->size_dais;
+ module->control_offset = module->dai_offset +
+ le32_to_cpu(tplg_data->size_dais);
module->widget_offset = module->control_offset +
- tplg_data->size_controls;
+ le32_to_cpu(tplg_data->size_controls);
module->route_offset = module->widget_offset +
- tplg_data->size_widgets;
+ le32_to_cpu(tplg_data->size_widgets);
dev_dbg(module->dev, "DAI offset is 0x%lx\n", module->dai_offset);
dev_dbg(module->dev, "control offset is %lx\n",
struct gb_audio_control *controls;
struct gb_audio_widget *widgets;
struct gb_audio_route *routes;
+ unsigned int jack_type;
if (!tplg_data)
return -EINVAL;
dev_dbg(module->dev, "Route parsing finished\n");
/* parse jack capabilities */
- if (tplg_data->jack_type) {
- module->jack_mask = tplg_data->jack_type & GBCODEC_JACK_MASK;
- module->button_mask = tplg_data->jack_type &
- GBCODEC_JACK_BUTTON_MASK;
+ jack_type = le32_to_cpu(tplg_data->jack_type);
+ if (jack_type) {
+ module->jack_mask = jack_type & GBCODEC_JACK_MASK;
+ module->button_mask = jack_type & GBCODEC_JACK_BUTTON_MASK;
}
return ret;
#include "greybus_authentication.h"
#include "firmware.h"
-#include "greybus.h"
#define CAP_TIMEOUT_MS 1000
static const struct gb_camera_debugfs_entry gb_camera_debugfs_entries[] = {
{
.name = "capabilities",
- .mask = S_IFREG | S_IRUGO,
+ .mask = S_IFREG | 0444,
.buffer = GB_CAMERA_DEBUGFS_BUFFER_CAPABILITIES,
.execute = gb_camera_debugfs_capabilities,
}, {
.name = "configure_streams",
- .mask = S_IFREG | S_IRUGO | S_IWUGO,
+ .mask = S_IFREG | 0666,
.buffer = GB_CAMERA_DEBUGFS_BUFFER_STREAMS,
.execute = gb_camera_debugfs_configure_streams,
}, {
.name = "capture",
- .mask = S_IFREG | S_IRUGO | S_IWUGO,
+ .mask = S_IFREG | 0666,
.buffer = GB_CAMERA_DEBUGFS_BUFFER_CAPTURE,
.execute = gb_camera_debugfs_capture,
}, {
.name = "flush",
- .mask = S_IFREG | S_IRUGO | S_IWUGO,
+ .mask = S_IFREG | 0666,
.buffer = GB_CAMERA_DEBUGFS_BUFFER_FLUSH,
.execute = gb_camera_debugfs_flush,
},
ssize_t ret;
/* For read-only entries the operation is triggered by a read. */
- if (!(op->mask & S_IWUGO)) {
+ if (!(op->mask & 0222)) {
ret = op->execute(gcam, NULL, 0);
if (ret < 0)
return ret;
size_t peer_space;
int ret;
+ if (!hd->driver->cport_quiesce)
+ return 0;
+
peer_space = sizeof(struct gb_operation_msg_hdr) +
sizeof(struct gb_cport_shutdown_request);
struct gb_host_device *hd = connection->hd;
int ret;
+ if (!hd->driver->cport_clear)
+ return 0;
+
ret = hd->driver->cport_clear(hd, connection->hd_cport_id);
if (ret) {
dev_err(&hd->dev, "%s: failed to clear host cport: %d\n",
return ret;
}
-int gb_control_timesync_enable(struct gb_control *control, u8 count,
- u64 frame_time, u32 strobe_delay, u32 refclk)
-{
- struct gb_control_timesync_enable_request request;
-
- request.count = count;
- request.frame_time = cpu_to_le64(frame_time);
- request.strobe_delay = cpu_to_le32(strobe_delay);
- request.refclk = cpu_to_le32(refclk);
- return gb_operation_sync(control->connection,
- GB_CONTROL_TYPE_TIMESYNC_ENABLE, &request,
- sizeof(request), NULL, 0);
-}
-
-int gb_control_timesync_disable(struct gb_control *control)
-{
- return gb_operation_sync(control->connection,
- GB_CONTROL_TYPE_TIMESYNC_DISABLE, NULL, 0,
- NULL, 0);
-}
-
-int gb_control_timesync_get_last_event(struct gb_control *control,
- u64 *frame_time)
-{
- struct gb_control_timesync_get_last_event_response response;
- int ret;
-
- ret = gb_operation_sync(control->connection,
- GB_CONTROL_TYPE_TIMESYNC_GET_LAST_EVENT,
- NULL, 0, &response, sizeof(response));
- if (!ret)
- *frame_time = le64_to_cpu(response.frame_time);
- return ret;
-}
-
-int gb_control_timesync_authoritative(struct gb_control *control,
- u64 *frame_time)
-{
- struct gb_control_timesync_authoritative_request request;
- int i;
-
- for (i = 0; i < GB_TIMESYNC_MAX_STROBES; i++)
- request.frame_time[i] = cpu_to_le64(frame_time[i]);
-
- return gb_operation_sync(control->connection,
- GB_CONTROL_TYPE_TIMESYNC_AUTHORITATIVE,
- &request, sizeof(request),
- NULL, 0);
-}
-
static int gb_control_bundle_pm_status_map(u8 status)
{
switch (status) {
int gb_control_get_manifest_size_operation(struct gb_interface *intf);
int gb_control_get_manifest_operation(struct gb_interface *intf, void *manifest,
size_t size);
-int gb_control_timesync_enable(struct gb_control *control, u8 count,
- u64 frame_time, u32 strobe_delay, u32 refclk);
-int gb_control_timesync_disable(struct gb_control *control);
-int gb_control_timesync_get_last_event(struct gb_control *control,
- u64 *frame_time);
-int gb_control_timesync_authoritative(struct gb_control *control,
- u64 *frame_time);
int gb_control_bundle_suspend(struct gb_control *control, u8 bundle_id);
int gb_control_bundle_resume(struct gb_control *control, u8 bundle_id);
int gb_control_bundle_deactivate(struct gb_control *control, u8 bundle_id);
return retval;
}
- gb_timesync_schedule_synchronous(bundle->intf);
-
pm_runtime_put(&bundle->intf->dev);
return 0;
pr_err("gb_operation_init failed (%d)\n", retval);
goto error_operation;
}
-
- retval = gb_timesync_init();
- if (retval) {
- pr_err("gb_timesync_init failed\n");
- goto error_timesync;
- }
return 0; /* Success */
-error_timesync:
- gb_operation_exit();
error_operation:
gb_hd_exit();
error_hd:
static void __exit gb_exit(void)
{
- gb_timesync_exit();
gb_operation_exit();
gb_hd_exit();
bus_unregister(&greybus_bus_type);
struct list_head arpcs;
};
-/**
- * timesync_enable_request - Enable timesync in an APBridge
- * @count: number of TimeSync Pulses to expect
- * @frame_time: the initial FrameTime at the first TimeSync Pulse
- * @strobe_delay: the expected delay in microseconds between each TimeSync Pulse
- * @refclk: The AP mandated reference clock to run FrameTime at
- */
-struct timesync_enable_request {
- __u8 count;
- __le64 frame_time;
- __le32 strobe_delay;
- __le32 refclk;
-} __packed;
-
-/**
- * timesync_authoritative_request - Transmit authoritative FrameTime to APBridge
- * @frame_time: An array of authoritative FrameTimes provided by the SVC
- * and relayed to the APBridge by the AP
- */
-struct timesync_authoritative_request {
- __le64 frame_time[GB_TIMESYNC_MAX_STROBES];
-} __packed;
-
struct arpc {
struct list_head list;
struct arpc_request_message *req;
return retval;
}
-static int timesync_enable(struct gb_host_device *hd, u8 count,
- u64 frame_time, u32 strobe_delay, u32 refclk)
-{
- int retval;
- struct es2_ap_dev *es2 = hd_to_es2(hd);
- struct usb_device *udev = es2->usb_dev;
- struct gb_control_timesync_enable_request *request;
-
- request = kzalloc(sizeof(*request), GFP_KERNEL);
- if (!request)
- return -ENOMEM;
-
- request->count = count;
- request->frame_time = cpu_to_le64(frame_time);
- request->strobe_delay = cpu_to_le32(strobe_delay);
- request->refclk = cpu_to_le32(refclk);
- retval = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
- GB_APB_REQUEST_TIMESYNC_ENABLE,
- USB_DIR_OUT | USB_TYPE_VENDOR |
- USB_RECIP_INTERFACE, 0, 0, request,
- sizeof(*request), ES2_USB_CTRL_TIMEOUT);
- if (retval < 0)
- dev_err(&udev->dev, "Cannot enable timesync %d\n", retval);
-
- kfree(request);
- return retval;
-}
-
-static int timesync_disable(struct gb_host_device *hd)
-{
- int retval;
- struct es2_ap_dev *es2 = hd_to_es2(hd);
- struct usb_device *udev = es2->usb_dev;
-
- retval = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
- GB_APB_REQUEST_TIMESYNC_DISABLE,
- USB_DIR_OUT | USB_TYPE_VENDOR |
- USB_RECIP_INTERFACE, 0, 0, NULL,
- 0, ES2_USB_CTRL_TIMEOUT);
- if (retval < 0)
- dev_err(&udev->dev, "Cannot disable timesync %d\n", retval);
-
- return retval;
-}
-
-static int timesync_authoritative(struct gb_host_device *hd, u64 *frame_time)
-{
- int retval, i;
- struct es2_ap_dev *es2 = hd_to_es2(hd);
- struct usb_device *udev = es2->usb_dev;
- struct timesync_authoritative_request *request;
-
- request = kzalloc(sizeof(*request), GFP_KERNEL);
- if (!request)
- return -ENOMEM;
-
- for (i = 0; i < GB_TIMESYNC_MAX_STROBES; i++)
- request->frame_time[i] = cpu_to_le64(frame_time[i]);
-
- retval = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
- GB_APB_REQUEST_TIMESYNC_AUTHORITATIVE,
- USB_DIR_OUT | USB_TYPE_VENDOR |
- USB_RECIP_INTERFACE, 0, 0, request,
- sizeof(*request), ES2_USB_CTRL_TIMEOUT);
- if (retval < 0)
- dev_err(&udev->dev, "Cannot timesync authoritative out %d\n", retval);
-
- kfree(request);
- return retval;
-}
-
-static int timesync_get_last_event(struct gb_host_device *hd, u64 *frame_time)
-{
- int retval;
- struct es2_ap_dev *es2 = hd_to_es2(hd);
- struct usb_device *udev = es2->usb_dev;
- __le64 *response_frame_time;
-
- response_frame_time = kzalloc(sizeof(*response_frame_time), GFP_KERNEL);
- if (!response_frame_time)
- return -ENOMEM;
-
- retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
- GB_APB_REQUEST_TIMESYNC_GET_LAST_EVENT,
- USB_DIR_IN | USB_TYPE_VENDOR |
- USB_RECIP_INTERFACE, 0, 0, response_frame_time,
- sizeof(*response_frame_time),
- ES2_USB_CTRL_TIMEOUT);
-
- if (retval != sizeof(*response_frame_time)) {
- dev_err(&udev->dev, "Cannot get last TimeSync event: %d\n",
- retval);
-
- if (retval >= 0)
- retval = -EIO;
-
- goto out;
- }
- *frame_time = le64_to_cpu(*response_frame_time);
- retval = 0;
-out:
- kfree(response_frame_time);
- return retval;
-}
-
static struct gb_hd_driver es2_driver = {
.hd_priv_size = sizeof(struct es2_ap_dev),
.message_send = message_send,
.latency_tag_enable = latency_tag_enable,
.latency_tag_disable = latency_tag_disable,
.output = output,
- .timesync_enable = timesync_enable,
- .timesync_disable = timesync_disable,
- .timesync_authoritative = timesync_authoritative,
- .timesync_get_last_event = timesync_get_last_event,
};
/* Common function to report consistent warnings based on URB status */
return 0;
}
-static int gb_gpio_request(struct gpio_chip *chip, unsigned offset)
+static int gb_gpio_request(struct gpio_chip *chip, unsigned int offset)
{
struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip);
return gb_gpio_activate_operation(ggc, (u8)offset);
}
-static void gb_gpio_free(struct gpio_chip *chip, unsigned offset)
+static void gb_gpio_free(struct gpio_chip *chip, unsigned int offset)
{
struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip);
gb_gpio_deactivate_operation(ggc, (u8)offset);
}
-static int gb_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+static int gb_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
{
struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip);
u8 which;
return ggc->lines[which].direction ? 1 : 0;
}
-static int gb_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+static int gb_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
{
struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip);
return gb_gpio_direction_in_operation(ggc, (u8)offset);
}
-static int gb_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
- int value)
+static int gb_gpio_direction_output(struct gpio_chip *chip, unsigned int offset,
+ int value)
{
struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip);
return gb_gpio_direction_out_operation(ggc, (u8)offset, !!value);
}
-static int gb_gpio_get(struct gpio_chip *chip, unsigned offset)
+static int gb_gpio_get(struct gpio_chip *chip, unsigned int offset)
{
struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip);
u8 which;
return ggc->lines[which].value;
}
-static void gb_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+static void gb_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
{
struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip);
gb_gpio_set_value_operation(ggc, (u8)offset, !!value);
}
-static int gb_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
- unsigned debounce)
+static int gb_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset,
+ unsigned int debounce)
{
struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip);
u16 usec;
{
struct gb_gpio_controller *ggc;
unsigned int offset;
- unsigned irq_base;
+ unsigned int irq_base;
if (!chip || !irqchip)
return -EINVAL;
return 0;
}
-static int gb_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+static int gb_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
{
struct gb_gpio_controller *ggc = gpio_chip_to_gb_gpio_controller(chip);
#include "bundle.h"
#include "connection.h"
#include "operation.h"
-#include "timesync.h"
/* Matches up with the Greybus Protocol specification document */
#define GREYBUS_VERSION_MAJOR 0x00
} __packed;
/* Control protocol [dis]connected response has no payload */
-#define GB_TIMESYNC_MAX_STROBES 0x04
-
-struct gb_control_timesync_enable_request {
- __u8 count;
- __le64 frame_time;
- __le32 strobe_delay;
- __le32 refclk;
-} __packed;
-/* timesync enable response has no payload */
-
-struct gb_control_timesync_authoritative_request {
- __le64 frame_time[GB_TIMESYNC_MAX_STROBES];
-} __packed;
-/* timesync authoritative response has no payload */
-
-/* timesync get_last_event_request has no payload */
-struct gb_control_timesync_get_last_event_response {
- __le64 frame_time;
-} __packed;
-
/*
* All Bundle power management operations use the same request and response
* layout and status codes.
#define GB_SVC_INTF_UNIPRO_NOT_OFF 0x03
} __packed;
-struct gb_svc_timesync_enable_request {
- __u8 count;
- __le64 frame_time;
- __le32 strobe_delay;
- __le32 refclk;
-} __packed;
-/* timesync enable response has no payload */
-
-/* timesync authoritative request has no payload */
-struct gb_svc_timesync_authoritative_response {
- __le64 frame_time[GB_TIMESYNC_MAX_STROBES];
-};
-
-struct gb_svc_timesync_wake_pins_acquire_request {
- __le32 strobe_mask;
-};
-
-/* timesync wake pins acquire response has no payload */
-
-/* timesync wake pins release request has no payload */
-/* timesync wake pins release response has no payload */
-
-/* timesync svc ping request has no payload */
-struct gb_svc_timesync_ping_response {
- __le64 frame_time;
-} __packed;
-
#define GB_SVC_UNIPRO_FAST_MODE 0x01
#define GB_SVC_UNIPRO_SLOW_MODE 0x02
#define GB_SVC_UNIPRO_FAST_AUTO_MODE 0x04
#undef DEFINE_HD_EVENT
-/*
- * Occurs on a TimeSync synchronization event or a TimeSync ping event.
- */
-TRACE_EVENT(gb_timesync_irq,
-
- TP_PROTO(u8 ping, u8 strobe, u8 count, u64 frame_time),
-
- TP_ARGS(ping, strobe, count, frame_time),
-
- TP_STRUCT__entry(
- __field(u8, ping)
- __field(u8, strobe)
- __field(u8, count)
- __field(u64, frame_time)
- ),
-
- TP_fast_assign(
- __entry->ping = ping;
- __entry->strobe = strobe;
- __entry->count = count;
- __entry->frame_time = frame_time;
- ),
-
- TP_printk("%s %d/%d frame-time %llu\n",
- __entry->ping ? "ping" : "strobe", __entry->strobe,
- __entry->count, __entry->frame_time)
-);
-
#endif /* _TRACE_GREYBUS_H */
/* This part must be outside protection */
int (*latency_tag_disable)(struct gb_host_device *hd, u16 cport_id);
int (*output)(struct gb_host_device *hd, void *req, u16 size, u8 cmd,
bool async);
- int (*timesync_enable)(struct gb_host_device *hd, u8 count,
- u64 frame_time, u32 strobe_delay, u32 refclk);
- int (*timesync_disable)(struct gb_host_device *hd);
- int (*timesync_authoritative)(struct gb_host_device *hd,
- u64 *frame_time);
- int (*timesync_get_last_event)(struct gb_host_device *hd,
- u64 *frame_time);
};
struct gb_host_device {
static int gb_interface_suspend(struct device *dev)
{
struct gb_interface *intf = to_gb_interface(dev);
- int ret, timesync_ret;
+ int ret;
ret = gb_control_interface_suspend_prepare(intf->control);
if (ret)
return ret;
- gb_timesync_interface_remove(intf);
-
ret = gb_control_suspend(intf->control);
if (ret)
goto err_hibernate_abort;
err_hibernate_abort:
gb_control_interface_hibernate_abort(intf->control);
- timesync_ret = gb_timesync_interface_add(intf);
- if (timesync_ret) {
- dev_err(dev, "failed to add to timesync: %d\n", timesync_ret);
- return timesync_ret;
- }
-
return ret;
}
if (ret)
return ret;
- ret = gb_timesync_interface_add(intf);
- if (ret) {
- dev_err(dev, "failed to add to timesync: %d\n", ret);
- return ret;
- }
-
- ret = gb_timesync_schedule_synchronous(intf);
- if (ret) {
- dev_err(dev, "failed to synchronize FrameTime: %d\n", ret);
- return ret;
- }
-
return 0;
}
if (ret)
goto err_destroy_bundles;
- ret = gb_timesync_interface_add(intf);
- if (ret) {
- dev_err(&intf->dev, "failed to add to timesync: %d\n", ret);
- goto err_destroy_bundles;
- }
-
/* Register the control device and any bundles */
ret = gb_control_add(intf->control);
if (ret)
- goto err_remove_timesync;
+ goto err_destroy_bundles;
pm_runtime_use_autosuspend(&intf->dev);
pm_runtime_get_noresume(&intf->dev);
return 0;
-err_remove_timesync:
- gb_timesync_interface_remove(intf);
err_destroy_bundles:
list_for_each_entry_safe(bundle, tmp, &intf->bundles, links)
gb_bundle_destroy(bundle);
gb_control_interface_deactivate_prepare(intf->control);
gb_control_del(intf->control);
- gb_timesync_interface_remove(intf);
gb_control_disable(intf->control);
gb_control_put(intf->control);
intf->control = NULL;
pm_runtime_put_noidle(&intf->dev);
}
-/* Enable TimeSync on an Interface control connection. */
-int gb_interface_timesync_enable(struct gb_interface *intf, u8 count,
- u64 frame_time, u32 strobe_delay, u32 refclk)
-{
- return gb_control_timesync_enable(intf->control, count,
- frame_time, strobe_delay,
- refclk);
-}
-
-/* Disable TimeSync on an Interface control connection. */
-int gb_interface_timesync_disable(struct gb_interface *intf)
-{
- return gb_control_timesync_disable(intf->control);
-}
-
-/* Transmit the Authoritative FrameTime via an Interface control connection. */
-int gb_interface_timesync_authoritative(struct gb_interface *intf,
- u64 *frame_time)
-{
- return gb_control_timesync_authoritative(intf->control,
- frame_time);
-}
-
/* Register an interface. */
int gb_interface_add(struct gb_interface *intf)
{
void gb_interface_deactivate(struct gb_interface *intf);
int gb_interface_enable(struct gb_interface *intf);
void gb_interface_disable(struct gb_interface *intf);
-int gb_interface_timesync_enable(struct gb_interface *intf, u8 count,
- u64 frame_time, u32 strobe_delay, u32 refclk);
-int gb_interface_timesync_authoritative(struct gb_interface *intf,
- u64 *frame_time);
-int gb_interface_timesync_disable(struct gb_interface *intf);
int gb_interface_add(struct gb_interface *intf);
void gb_interface_del(struct gb_interface *intf);
void gb_interface_put(struct gb_interface *intf);
}
receive = op->request->payload;
len = le16_to_cpu(receive->len);
- if (len != (int)(op->request->payload_size - sizeof(*receive))) {
- dev_err(dev, "log request wrong size %d vs %d\n", len,
- (int)(op->request->payload_size - sizeof(*receive)));
+ if (len != (op->request->payload_size - sizeof(*receive))) {
+ dev_err(dev, "log request wrong size %d vs %zu\n", len,
+ (op->request->payload_size - sizeof(*receive)));
return -EINVAL;
}
if (len == 0) {
#define GB_LOOPBACK_FIFO_DEFAULT 8192
-static unsigned kfifo_depth = GB_LOOPBACK_FIFO_DEFAULT;
+static unsigned int kfifo_depth = GB_LOOPBACK_FIFO_DEFAULT;
module_param(kfifo_depth, uint, 0444);
/* Maximum size of any one send data buffer we support */
mutex_lock(&gb->mutex);
ret = gb_operation_request_send(operation,
gb_loopback_async_operation_callback,
+ 0,
GFP_KERNEL);
if (ret)
goto error;
/* Optionally terminate */
if (gb->send_count == gb->iteration_max) {
+ mutex_unlock(&gb->mutex);
+
+ /* Wait for synchronous and asynchronus completion */
+ gb_loopback_async_wait_all(gb);
+
+ /* Mark complete unless user-space has poked us */
+ mutex_lock(&gb->mutex);
if (gb->iteration_count == gb->iteration_max) {
gb->type = 0;
gb->send_count = 0;
sysfs_notify(&gb->dev->kobj, NULL,
"iteration_count");
+ dev_dbg(&bundle->dev, "load test complete\n");
+ } else {
+ dev_dbg(&bundle->dev,
+ "continuing on with new test set\n");
}
mutex_unlock(&gb->mutex);
continue;
/* Else operations to perform */
if (gb->async) {
- if (type == GB_LOOPBACK_TYPE_PING) {
+ if (type == GB_LOOPBACK_TYPE_PING)
error = gb_loopback_async_ping(gb);
- } else if (type == GB_LOOPBACK_TYPE_TRANSFER) {
+ else if (type == GB_LOOPBACK_TYPE_TRANSFER)
error = gb_loopback_async_transfer(gb, size);
- } else if (type == GB_LOOPBACK_TYPE_SINK) {
+ else if (type == GB_LOOPBACK_TYPE_SINK)
error = gb_loopback_async_sink(gb, size);
- }
if (error)
gb->error++;
gb_loopback_calculate_stats(gb, !!error);
}
gb->send_count++;
- if (us_wait)
- udelay(us_wait);
+
+ if (us_wait) {
+ if (us_wait < 20000)
+ usleep_range(us_wait, us_wait + 100);
+ else
+ msleep(us_wait / 1000);
+ }
}
gb_pm_runtime_put_autosuspend(bundle);
static void gb_operation_work(struct work_struct *work)
{
struct gb_operation *operation;
+ int ret;
operation = container_of(work, struct gb_operation, work);
- if (gb_operation_is_incoming(operation))
+ if (gb_operation_is_incoming(operation)) {
gb_operation_request_handle(operation);
- else
+ } else {
+ ret = del_timer_sync(&operation->timer);
+ if (!ret) {
+ /* Cancel request message if scheduled by timeout. */
+ if (gb_operation_result(operation) == -ETIMEDOUT)
+ gb_message_cancel(operation->request);
+ }
+
operation->callback(operation);
+ }
gb_operation_put_active(operation);
gb_operation_put(operation);
}
+static void gb_operation_timeout(unsigned long arg)
+{
+ struct gb_operation *operation = (void *)arg;
+
+ if (gb_operation_result_set(operation, -ETIMEDOUT)) {
+ /*
+ * A stuck request message will be cancelled from the
+ * workqueue.
+ */
+ queue_work(gb_operation_completion_wq, &operation->work);
+ }
+}
+
static void gb_operation_message_init(struct gb_host_device *hd,
struct gb_message *message, u16 operation_id,
size_t payload_size, u8 type)
gfp_flags)) {
goto err_request;
}
+
+ setup_timer(&operation->timer, gb_operation_timeout,
+ (unsigned long)operation);
}
operation->flags = op_flags;
* gb_operation_request_send() - send an operation request message
* @operation: the operation to initiate
* @callback: the operation completion callback
+ * @timeout: operation timeout in milliseconds, or zero for no timeout
* @gfp: the memory flags to use for any allocations
*
* The caller has filled in any payload so the request message is ready to go.
*/
int gb_operation_request_send(struct gb_operation *operation,
gb_operation_callback callback,
+ unsigned int timeout,
gfp_t gfp)
{
struct gb_connection *connection = operation->connection;
if (ret)
goto err_put_active;
+ if (timeout) {
+ operation->timer.expires = jiffies + msecs_to_jiffies(timeout);
+ add_timer(&operation->timer);
+ }
+
return 0;
err_put_active:
unsigned int timeout)
{
int ret;
- unsigned long timeout_jiffies;
ret = gb_operation_request_send(operation, gb_operation_sync_callback,
- GFP_KERNEL);
+ timeout, GFP_KERNEL);
if (ret)
return ret;
- if (timeout)
- timeout_jiffies = msecs_to_jiffies(timeout);
- else
- timeout_jiffies = MAX_SCHEDULE_TIMEOUT;
-
- ret = wait_for_completion_interruptible_timeout(&operation->completion,
- timeout_jiffies);
+ ret = wait_for_completion_interruptible(&operation->completion);
if (ret < 0) {
/* Cancel the operation if interrupted */
gb_operation_cancel(operation, -ECANCELED);
- } else if (ret == 0) {
- /* Cancel the operation if op timed out */
- gb_operation_cancel(operation, -ETIMEDOUT);
}
return gb_operation_result(operation);
struct work_struct work;
gb_operation_callback callback;
struct completion completion;
+ struct timer_list timer;
struct kref kref;
atomic_t waiters;
int gb_operation_request_send(struct gb_operation *operation,
gb_operation_callback callback,
+ unsigned int timeout,
gfp_t gfp);
int gb_operation_request_send_sync_timeout(struct gb_operation *operation,
unsigned int timeout);
static inline bool single_op(struct mmc_command *cmd)
{
- uint32_t opcode = cmd->opcode;
+ u32 opcode = cmd->opcode;
return opcode == MMC_WRITE_BLOCK ||
opcode == MMC_READ_SINGLE_BLOCK;
}
}
-int gb_svc_timesync_enable(struct gb_svc *svc, u8 count, u64 frame_time,
- u32 strobe_delay, u32 refclk)
-{
- struct gb_connection *connection = svc->connection;
- struct gb_svc_timesync_enable_request request;
-
- request.count = count;
- request.frame_time = cpu_to_le64(frame_time);
- request.strobe_delay = cpu_to_le32(strobe_delay);
- request.refclk = cpu_to_le32(refclk);
- return gb_operation_sync(connection,
- GB_SVC_TYPE_TIMESYNC_ENABLE,
- &request, sizeof(request), NULL, 0);
-}
-
-int gb_svc_timesync_disable(struct gb_svc *svc)
-{
- struct gb_connection *connection = svc->connection;
-
- return gb_operation_sync(connection,
- GB_SVC_TYPE_TIMESYNC_DISABLE,
- NULL, 0, NULL, 0);
-}
-
-int gb_svc_timesync_authoritative(struct gb_svc *svc, u64 *frame_time)
-{
- struct gb_connection *connection = svc->connection;
- struct gb_svc_timesync_authoritative_response response;
- int ret, i;
-
- ret = gb_operation_sync(connection,
- GB_SVC_TYPE_TIMESYNC_AUTHORITATIVE, NULL, 0,
- &response, sizeof(response));
- if (ret < 0)
- return ret;
-
- for (i = 0; i < GB_TIMESYNC_MAX_STROBES; i++)
- frame_time[i] = le64_to_cpu(response.frame_time[i]);
- return 0;
-}
-
-int gb_svc_timesync_ping(struct gb_svc *svc, u64 *frame_time)
-{
- struct gb_connection *connection = svc->connection;
- struct gb_svc_timesync_ping_response response;
- int ret;
-
- ret = gb_operation_sync(connection,
- GB_SVC_TYPE_TIMESYNC_PING,
- NULL, 0,
- &response, sizeof(response));
- if (ret < 0)
- return ret;
-
- *frame_time = le64_to_cpu(response.frame_time);
- return 0;
-}
-
-int gb_svc_timesync_wake_pins_acquire(struct gb_svc *svc, u32 strobe_mask)
-{
- struct gb_connection *connection = svc->connection;
- struct gb_svc_timesync_wake_pins_acquire_request request;
-
- request.strobe_mask = cpu_to_le32(strobe_mask);
- return gb_operation_sync(connection,
- GB_SVC_TYPE_TIMESYNC_WAKE_PINS_ACQUIRE,
- &request, sizeof(request),
- NULL, 0);
-}
-
-int gb_svc_timesync_wake_pins_release(struct gb_svc *svc)
-{
- struct gb_connection *connection = svc->connection;
-
- return gb_operation_sync(connection,
- GB_SVC_TYPE_TIMESYNC_WAKE_PINS_RELEASE,
- NULL, 0, NULL, 0);
-}
-
/* Creates bi-directional routes between the devices */
int gb_svc_route_create(struct gb_svc *svc, u8 intf1_id, u8 dev1_id,
u8 intf2_id, u8 dev2_id)
gb_svc_debugfs_init(svc);
- ret = gb_timesync_svc_add(svc);
- if (ret) {
- dev_err(&svc->dev, "failed to add SVC to timesync: %d\n", ret);
- gb_svc_debugfs_exit(svc);
- goto err_unregister_device;
- }
-
return gb_svc_queue_deferred_request(op);
err_unregister_device:
* The SVC device may have been registered from the request handler.
*/
if (device_is_registered(&svc->dev)) {
- gb_timesync_svc_remove(svc);
gb_svc_debugfs_exit(svc);
gb_svc_watchdog_destroy(svc);
device_del(&svc->dev);
bool gb_svc_watchdog_enabled(struct gb_svc *svc);
int gb_svc_watchdog_enable(struct gb_svc *svc);
int gb_svc_watchdog_disable(struct gb_svc *svc);
-int gb_svc_timesync_enable(struct gb_svc *svc, u8 count, u64 frame_time,
- u32 strobe_delay, u32 refclk);
-int gb_svc_timesync_disable(struct gb_svc *svc);
-int gb_svc_timesync_authoritative(struct gb_svc *svc, u64 *frame_time);
-int gb_svc_timesync_ping(struct gb_svc *svc, u64 *frame_time);
-int gb_svc_timesync_wake_pins_acquire(struct gb_svc *svc, u32 strobe_mask);
-int gb_svc_timesync_wake_pins_release(struct gb_svc *svc);
int gb_svc_protocol_init(void);
void gb_svc_protocol_exit(void);
#include <linux/workqueue.h>
#include "greybus.h"
-#define SVC_WATCHDOG_PERIOD (2*HZ)
+#define SVC_WATCHDOG_PERIOD (2 * HZ)
struct gb_svc_watchdog {
struct delayed_work work;
NULL,
};
- printk(KERN_ERR "svc_watchdog: calling \"%s %s\" to reset greybus network!\n",
+ pr_err("svc_watchdog: calling \"%s %s\" to reset greybus network!\n",
argv[0], argv[1]);
call_usermodehelper(start_path, argv, envp, UMH_WAIT_EXEC);
}
+++ /dev/null
-/*
- * TimeSync API driver.
- *
- * Copyright 2016 Google Inc.
- * Copyright 2016 Linaro Ltd.
- *
- * Released under the GPLv2 only.
- */
-#include <linux/debugfs.h>
-#include <linux/hrtimer.h>
-#include "greybus.h"
-#include "timesync.h"
-#include "greybus_trace.h"
-
-/*
- * Minimum inter-strobe value of one millisecond is chosen because it
- * just-about fits the common definition of a jiffy.
- *
- * Maximum value OTOH is constrained by the number of bits the SVC can fit
- * into a 16 bit up-counter. The SVC configures the timer in microseconds
- * so the maximum allowable value is 65535 microseconds. We clip that value
- * to 10000 microseconds for the sake of using nice round base 10 numbers
- * and since right-now there's no imaginable use-case requiring anything
- * other than a one millisecond inter-strobe time, let alone something
- * higher than ten milliseconds.
- */
-#define GB_TIMESYNC_STROBE_DELAY_US 1000
-#define GB_TIMESYNC_DEFAULT_OFFSET_US 1000
-
-/* Work queue timers long, short and SVC strobe timeout */
-#define GB_TIMESYNC_DELAYED_WORK_LONG msecs_to_jiffies(10)
-#define GB_TIMESYNC_DELAYED_WORK_SHORT msecs_to_jiffies(1)
-#define GB_TIMESYNC_MAX_WAIT_SVC msecs_to_jiffies(5000)
-#define GB_TIMESYNC_KTIME_UPDATE msecs_to_jiffies(1000)
-#define GB_TIMESYNC_MAX_KTIME_CONVERSION 15
-
-/* Maximum number of times we'll retry a failed synchronous sync */
-#define GB_TIMESYNC_MAX_RETRIES 5
-
-/* Reported nanoseconds/femtoseconds per clock */
-static u64 gb_timesync_ns_per_clock;
-static u64 gb_timesync_fs_per_clock;
-
-/* Maximum difference we will accept converting FrameTime to ktime */
-static u32 gb_timesync_max_ktime_diff;
-
-/* Reported clock rate */
-static unsigned long gb_timesync_clock_rate;
-
-/* Workqueue */
-static void gb_timesync_worker(struct work_struct *work);
-
-/* List of SVCs with one FrameTime per SVC */
-static LIST_HEAD(gb_timesync_svc_list);
-
-/* Synchronize parallel contexts accessing a valid timesync_svc pointer */
-static DEFINE_MUTEX(gb_timesync_svc_list_mutex);
-
-/* Structure to convert from FrameTime to timespec/ktime */
-struct gb_timesync_frame_time_data {
- u64 frame_time;
- struct timespec ts;
-};
-
-struct gb_timesync_svc {
- struct list_head list;
- struct list_head interface_list;
- struct gb_svc *svc;
- struct gb_timesync_host_device *timesync_hd;
-
- spinlock_t spinlock; /* Per SVC spinlock to sync with ISR */
- struct mutex mutex; /* Per SVC mutex for regular synchronization */
-
- struct dentry *frame_time_dentry;
- struct dentry *frame_ktime_dentry;
- struct workqueue_struct *work_queue;
- wait_queue_head_t wait_queue;
- struct delayed_work delayed_work;
- struct timer_list ktime_timer;
-
- /* The current local FrameTime */
- u64 frame_time_offset;
- struct gb_timesync_frame_time_data strobe_data[GB_TIMESYNC_MAX_STROBES];
- struct gb_timesync_frame_time_data ktime_data;
-
- /* The SVC FrameTime and relative AP FrameTime @ last TIMESYNC_PING */
- u64 svc_ping_frame_time;
- u64 ap_ping_frame_time;
-
- /* Transitory settings */
- u32 strobe_mask;
- bool offset_down;
- bool print_ping;
- bool capture_ping;
- int strobe;
-
- /* Current state */
- int state;
-};
-
-struct gb_timesync_host_device {
- struct list_head list;
- struct gb_host_device *hd;
- u64 ping_frame_time;
-};
-
-struct gb_timesync_interface {
- struct list_head list;
- struct gb_interface *interface;
- u64 ping_frame_time;
-};
-
-enum gb_timesync_state {
- GB_TIMESYNC_STATE_INVALID = 0,
- GB_TIMESYNC_STATE_INACTIVE = 1,
- GB_TIMESYNC_STATE_INIT = 2,
- GB_TIMESYNC_STATE_WAIT_SVC = 3,
- GB_TIMESYNC_STATE_AUTHORITATIVE = 4,
- GB_TIMESYNC_STATE_PING = 5,
- GB_TIMESYNC_STATE_ACTIVE = 6,
-};
-
-static void gb_timesync_ktime_timer_fn(unsigned long data);
-
-static u64 gb_timesync_adjust_count(struct gb_timesync_svc *timesync_svc,
- u64 counts)
-{
- if (timesync_svc->offset_down)
- return counts - timesync_svc->frame_time_offset;
- else
- return counts + timesync_svc->frame_time_offset;
-}
-
-/*
- * This function provides the authoritative FrameTime to a calling function. It
- * is designed to be lockless and should remain that way the caller is assumed
- * to be state-aware.
- */
-static u64 __gb_timesync_get_frame_time(struct gb_timesync_svc *timesync_svc)
-{
- u64 clocks = gb_timesync_platform_get_counter();
-
- return gb_timesync_adjust_count(timesync_svc, clocks);
-}
-
-static void gb_timesync_schedule_svc_timeout(struct gb_timesync_svc
- *timesync_svc)
-{
- queue_delayed_work(timesync_svc->work_queue,
- ×ync_svc->delayed_work,
- GB_TIMESYNC_MAX_WAIT_SVC);
-}
-
-static void gb_timesync_set_state(struct gb_timesync_svc *timesync_svc,
- int state)
-{
- switch (state) {
- case GB_TIMESYNC_STATE_INVALID:
- timesync_svc->state = state;
- wake_up(×ync_svc->wait_queue);
- break;
- case GB_TIMESYNC_STATE_INACTIVE:
- timesync_svc->state = state;
- wake_up(×ync_svc->wait_queue);
- break;
- case GB_TIMESYNC_STATE_INIT:
- if (timesync_svc->state != GB_TIMESYNC_STATE_INVALID) {
- timesync_svc->strobe = 0;
- timesync_svc->frame_time_offset = 0;
- timesync_svc->state = state;
- cancel_delayed_work(×ync_svc->delayed_work);
- queue_delayed_work(timesync_svc->work_queue,
- ×ync_svc->delayed_work,
- GB_TIMESYNC_DELAYED_WORK_LONG);
- }
- break;
- case GB_TIMESYNC_STATE_WAIT_SVC:
- if (timesync_svc->state == GB_TIMESYNC_STATE_INIT)
- timesync_svc->state = state;
- break;
- case GB_TIMESYNC_STATE_AUTHORITATIVE:
- if (timesync_svc->state == GB_TIMESYNC_STATE_WAIT_SVC) {
- timesync_svc->state = state;
- cancel_delayed_work(×ync_svc->delayed_work);
- queue_delayed_work(timesync_svc->work_queue,
- ×ync_svc->delayed_work, 0);
- }
- break;
- case GB_TIMESYNC_STATE_PING:
- if (timesync_svc->state == GB_TIMESYNC_STATE_ACTIVE) {
- timesync_svc->state = state;
- queue_delayed_work(timesync_svc->work_queue,
- ×ync_svc->delayed_work,
- GB_TIMESYNC_DELAYED_WORK_SHORT);
- }
- break;
- case GB_TIMESYNC_STATE_ACTIVE:
- if (timesync_svc->state == GB_TIMESYNC_STATE_AUTHORITATIVE ||
- timesync_svc->state == GB_TIMESYNC_STATE_PING) {
- timesync_svc->state = state;
- wake_up(×ync_svc->wait_queue);
- }
- break;
- }
-
- if (WARN_ON(timesync_svc->state != state)) {
- pr_err("Invalid state transition %d=>%d\n",
- timesync_svc->state, state);
- }
-}
-
-static void gb_timesync_set_state_atomic(struct gb_timesync_svc *timesync_svc,
- int state)
-{
- unsigned long flags;
-
- spin_lock_irqsave(×ync_svc->spinlock, flags);
- gb_timesync_set_state(timesync_svc, state);
- spin_unlock_irqrestore(×ync_svc->spinlock, flags);
-}
-
-static u64 gb_timesync_diff(u64 x, u64 y)
-{
- if (x > y)
- return x - y;
- else
- return y - x;
-}
-
-static void gb_timesync_adjust_to_svc(struct gb_timesync_svc *svc,
- u64 svc_frame_time, u64 ap_frame_time)
-{
- if (svc_frame_time > ap_frame_time) {
- svc->frame_time_offset = svc_frame_time - ap_frame_time;
- svc->offset_down = false;
- } else {
- svc->frame_time_offset = ap_frame_time - svc_frame_time;
- svc->offset_down = true;
- }
-}
-
-/*
- * Associate a FrameTime with a ktime timestamp represented as struct timespec
- * Requires the calling context to hold timesync_svc->mutex
- */
-static void gb_timesync_store_ktime(struct gb_timesync_svc *timesync_svc,
- struct timespec ts, u64 frame_time)
-{
- timesync_svc->ktime_data.ts = ts;
- timesync_svc->ktime_data.frame_time = frame_time;
-}
-
-/*
- * Find the two pulses that best-match our expected inter-strobe gap and
- * then calculate the difference between the SVC time at the second pulse
- * to the local time at the second pulse.
- */
-static void gb_timesync_collate_frame_time(struct gb_timesync_svc *timesync_svc,
- u64 *frame_time)
-{
- int i = 0;
- u64 delta, ap_frame_time;
- u64 strobe_delay_ns = GB_TIMESYNC_STROBE_DELAY_US * NSEC_PER_USEC;
- u64 least = 0;
-
- for (i = 1; i < GB_TIMESYNC_MAX_STROBES; i++) {
- delta = timesync_svc->strobe_data[i].frame_time -
- timesync_svc->strobe_data[i - 1].frame_time;
- delta *= gb_timesync_ns_per_clock;
- delta = gb_timesync_diff(delta, strobe_delay_ns);
-
- if (!least || delta < least) {
- least = delta;
- gb_timesync_adjust_to_svc(timesync_svc, frame_time[i],
- timesync_svc->strobe_data[i].frame_time);
-
- ap_frame_time = timesync_svc->strobe_data[i].frame_time;
- ap_frame_time = gb_timesync_adjust_count(timesync_svc,
- ap_frame_time);
- gb_timesync_store_ktime(timesync_svc,
- timesync_svc->strobe_data[i].ts,
- ap_frame_time);
-
- pr_debug("adjust %s local %llu svc %llu delta %llu\n",
- timesync_svc->offset_down ? "down" : "up",
- timesync_svc->strobe_data[i].frame_time,
- frame_time[i], delta);
- }
- }
-}
-
-static void gb_timesync_teardown(struct gb_timesync_svc *timesync_svc)
-{
- struct gb_timesync_interface *timesync_interface;
- struct gb_svc *svc = timesync_svc->svc;
- struct gb_interface *interface;
- struct gb_host_device *hd;
- int ret;
-
- list_for_each_entry(timesync_interface,
- ×ync_svc->interface_list, list) {
- interface = timesync_interface->interface;
- ret = gb_interface_timesync_disable(interface);
- if (ret) {
- dev_err(&interface->dev,
- "interface timesync_disable %d\n", ret);
- }
- }
-
- hd = timesync_svc->timesync_hd->hd;
- ret = hd->driver->timesync_disable(hd);
- if (ret < 0) {
- dev_err(&hd->dev, "host timesync_disable %d\n",
- ret);
- }
-
- gb_svc_timesync_wake_pins_release(svc);
- gb_svc_timesync_disable(svc);
- gb_timesync_platform_unlock_bus();
-
- gb_timesync_set_state_atomic(timesync_svc, GB_TIMESYNC_STATE_INACTIVE);
-}
-
-static void gb_timesync_platform_lock_bus_fail(struct gb_timesync_svc
- *timesync_svc, int ret)
-{
- if (ret == -EAGAIN) {
- gb_timesync_set_state(timesync_svc, timesync_svc->state);
- } else {
- pr_err("Failed to lock timesync bus %d\n", ret);
- gb_timesync_set_state(timesync_svc, GB_TIMESYNC_STATE_INACTIVE);
- }
-}
-
-static void gb_timesync_enable(struct gb_timesync_svc *timesync_svc)
-{
- struct gb_svc *svc = timesync_svc->svc;
- struct gb_host_device *hd;
- struct gb_timesync_interface *timesync_interface;
- struct gb_interface *interface;
- u64 init_frame_time;
- unsigned long clock_rate = gb_timesync_clock_rate;
- int ret;
-
- /*
- * Get access to the wake pins in the AP and SVC
- * Release these pins either in gb_timesync_teardown() or in
- * gb_timesync_authoritative()
- */
- ret = gb_timesync_platform_lock_bus(timesync_svc);
- if (ret < 0) {
- gb_timesync_platform_lock_bus_fail(timesync_svc, ret);
- return;
- }
- ret = gb_svc_timesync_wake_pins_acquire(svc, timesync_svc->strobe_mask);
- if (ret) {
- dev_err(&svc->dev,
- "gb_svc_timesync_wake_pins_acquire %d\n", ret);
- gb_timesync_teardown(timesync_svc);
- return;
- }
-
- /* Choose an initial time in the future */
- init_frame_time = __gb_timesync_get_frame_time(timesync_svc) + 100000UL;
-
- /* Send enable command to all relevant participants */
- list_for_each_entry(timesync_interface, ×ync_svc->interface_list,
- list) {
- interface = timesync_interface->interface;
- ret = gb_interface_timesync_enable(interface,
- GB_TIMESYNC_MAX_STROBES,
- init_frame_time,
- GB_TIMESYNC_STROBE_DELAY_US,
- clock_rate);
- if (ret) {
- dev_err(&interface->dev,
- "interface timesync_enable %d\n", ret);
- }
- }
-
- hd = timesync_svc->timesync_hd->hd;
- ret = hd->driver->timesync_enable(hd, GB_TIMESYNC_MAX_STROBES,
- init_frame_time,
- GB_TIMESYNC_STROBE_DELAY_US,
- clock_rate);
- if (ret < 0) {
- dev_err(&hd->dev, "host timesync_enable %d\n",
- ret);
- }
-
- gb_timesync_set_state_atomic(timesync_svc, GB_TIMESYNC_STATE_WAIT_SVC);
- ret = gb_svc_timesync_enable(svc, GB_TIMESYNC_MAX_STROBES,
- init_frame_time,
- GB_TIMESYNC_STROBE_DELAY_US,
- clock_rate);
- if (ret) {
- dev_err(&svc->dev,
- "gb_svc_timesync_enable %d\n", ret);
- gb_timesync_teardown(timesync_svc);
- return;
- }
-
- /* Schedule a timeout waiting for SVC to complete strobing */
- gb_timesync_schedule_svc_timeout(timesync_svc);
-}
-
-static void gb_timesync_authoritative(struct gb_timesync_svc *timesync_svc)
-{
- struct gb_svc *svc = timesync_svc->svc;
- struct gb_host_device *hd;
- struct gb_timesync_interface *timesync_interface;
- struct gb_interface *interface;
- u64 svc_frame_time[GB_TIMESYNC_MAX_STROBES];
- int ret;
-
- /* Get authoritative time from SVC and adjust local clock */
- ret = gb_svc_timesync_authoritative(svc, svc_frame_time);
- if (ret) {
- dev_err(&svc->dev,
- "gb_svc_timesync_authoritative %d\n", ret);
- gb_timesync_teardown(timesync_svc);
- return;
- }
- gb_timesync_collate_frame_time(timesync_svc, svc_frame_time);
-
- /* Transmit authoritative time to downstream slaves */
- hd = timesync_svc->timesync_hd->hd;
- ret = hd->driver->timesync_authoritative(hd, svc_frame_time);
- if (ret < 0)
- dev_err(&hd->dev, "host timesync_authoritative %d\n", ret);
-
- list_for_each_entry(timesync_interface,
- ×ync_svc->interface_list, list) {
- interface = timesync_interface->interface;
- ret = gb_interface_timesync_authoritative(
- interface,
- svc_frame_time);
- if (ret) {
- dev_err(&interface->dev,
- "interface timesync_authoritative %d\n", ret);
- }
- }
-
- /* Release wake pins */
- gb_svc_timesync_wake_pins_release(svc);
- gb_timesync_platform_unlock_bus();
-
- /* Transition to state ACTIVE */
- gb_timesync_set_state_atomic(timesync_svc, GB_TIMESYNC_STATE_ACTIVE);
-
- /* Schedule a ping to verify the synchronized system time */
- timesync_svc->print_ping = true;
- gb_timesync_set_state_atomic(timesync_svc, GB_TIMESYNC_STATE_PING);
-}
-
-static int __gb_timesync_get_status(struct gb_timesync_svc *timesync_svc)
-{
- int ret = -EINVAL;
-
- switch (timesync_svc->state) {
- case GB_TIMESYNC_STATE_INVALID:
- case GB_TIMESYNC_STATE_INACTIVE:
- ret = -ENODEV;
- break;
- case GB_TIMESYNC_STATE_INIT:
- case GB_TIMESYNC_STATE_WAIT_SVC:
- case GB_TIMESYNC_STATE_AUTHORITATIVE:
- ret = -EAGAIN;
- break;
- case GB_TIMESYNC_STATE_PING:
- case GB_TIMESYNC_STATE_ACTIVE:
- ret = 0;
- break;
- }
- return ret;
-}
-
-/*
- * This routine takes a FrameTime and derives the difference with-respect
- * to a reference FrameTime/ktime pair. It then returns the calculated
- * ktime based on the difference between the supplied FrameTime and
- * the reference FrameTime.
- *
- * The time difference is calculated to six decimal places. Taking 19.2MHz
- * as an example this means we have 52.083333~ nanoseconds per clock or
- * 52083333~ femtoseconds per clock.
- *
- * Naively taking the count difference and converting to
- * seconds/nanoseconds would quickly see the 0.0833 component produce
- * noticeable errors. For example a time difference of one second would
- * loose 19200000 * 0.08333x nanoseconds or 1.59 seconds.
- *
- * In contrast calculating in femtoseconds the same example of 19200000 *
- * 0.000000083333x nanoseconds per count of error is just 1.59 nanoseconds!
- *
- * Continuing the example of 19.2 MHz we cap the maximum error difference
- * at a worst-case 0.3 microseconds over a potential calculation window of
- * abount 15 seconds, meaning you can convert a FrameTime that is <= 15
- * seconds older/younger than the reference time with a maximum error of
- * 0.2385 useconds. Note 19.2MHz is an example frequency not a requirement.
- */
-static int gb_timesync_to_timespec(struct gb_timesync_svc *timesync_svc,
- u64 frame_time, struct timespec *ts)
-{
- unsigned long flags;
- u64 delta_fs, counts, sec, nsec;
- bool add;
- int ret = 0;
-
- memset(ts, 0x00, sizeof(*ts));
- mutex_lock(×ync_svc->mutex);
- spin_lock_irqsave(×ync_svc->spinlock, flags);
-
- ret = __gb_timesync_get_status(timesync_svc);
- if (ret)
- goto done;
-
- /* Support calculating ktime upwards or downwards from the reference */
- if (frame_time < timesync_svc->ktime_data.frame_time) {
- add = false;
- counts = timesync_svc->ktime_data.frame_time - frame_time;
- } else {
- add = true;
- counts = frame_time - timesync_svc->ktime_data.frame_time;
- }
-
- /* Enforce the .23 of a usecond boundary @ 19.2MHz */
- if (counts > gb_timesync_max_ktime_diff) {
- ret = -EINVAL;
- goto done;
- }
-
- /* Determine the time difference in femtoseconds */
- delta_fs = counts * gb_timesync_fs_per_clock;
-
- /* Convert to seconds */
- sec = delta_fs;
- do_div(sec, NSEC_PER_SEC);
- do_div(sec, 1000000UL);
-
- /* Get the nanosecond remainder */
- nsec = do_div(delta_fs, sec);
- do_div(nsec, 1000000UL);
-
- if (add) {
- /* Add the calculated offset - overflow nanoseconds upwards */
- ts->tv_sec = timesync_svc->ktime_data.ts.tv_sec + sec;
- ts->tv_nsec = timesync_svc->ktime_data.ts.tv_nsec + nsec;
- if (ts->tv_nsec >= NSEC_PER_SEC) {
- ts->tv_sec++;
- ts->tv_nsec -= NSEC_PER_SEC;
- }
- } else {
- /* Subtract the difference over/underflow as necessary */
- if (nsec > timesync_svc->ktime_data.ts.tv_nsec) {
- sec++;
- nsec = nsec + timesync_svc->ktime_data.ts.tv_nsec;
- nsec = do_div(nsec, NSEC_PER_SEC);
- } else {
- nsec = timesync_svc->ktime_data.ts.tv_nsec - nsec;
- }
- /* Cannot return a negative second value */
- if (sec > timesync_svc->ktime_data.ts.tv_sec) {
- ret = -EINVAL;
- goto done;
- }
- ts->tv_sec = timesync_svc->ktime_data.ts.tv_sec - sec;
- ts->tv_nsec = nsec;
- }
-done:
- spin_unlock_irqrestore(×ync_svc->spinlock, flags);
- mutex_unlock(×ync_svc->mutex);
- return ret;
-}
-
-static size_t gb_timesync_log_frame_time(struct gb_timesync_svc *timesync_svc,
- char *buf, size_t buflen)
-{
- struct gb_svc *svc = timesync_svc->svc;
- struct gb_host_device *hd;
- struct gb_timesync_interface *timesync_interface;
- struct gb_interface *interface;
- unsigned int len;
- size_t off;
-
- /* AP/SVC */
- off = snprintf(buf, buflen, "%s frametime: ap=%llu %s=%llu ",
- greybus_bus_type.name,
- timesync_svc->ap_ping_frame_time, dev_name(&svc->dev),
- timesync_svc->svc_ping_frame_time);
- len = buflen - off;
-
- /* APB/GPB */
- if (len < buflen) {
- hd = timesync_svc->timesync_hd->hd;
- off += snprintf(&buf[off], len, "%s=%llu ", dev_name(&hd->dev),
- timesync_svc->timesync_hd->ping_frame_time);
- len = buflen - off;
- }
-
- list_for_each_entry(timesync_interface,
- ×ync_svc->interface_list, list) {
- if (len < buflen) {
- interface = timesync_interface->interface;
- off += snprintf(&buf[off], len, "%s=%llu ",
- dev_name(&interface->dev),
- timesync_interface->ping_frame_time);
- len = buflen - off;
- }
- }
- if (len < buflen)
- off += snprintf(&buf[off], len, "\n");
- return off;
-}
-
-static size_t gb_timesync_log_frame_ktime(struct gb_timesync_svc *timesync_svc,
- char *buf, size_t buflen)
-{
- struct gb_svc *svc = timesync_svc->svc;
- struct gb_host_device *hd;
- struct gb_timesync_interface *timesync_interface;
- struct gb_interface *interface;
- struct timespec ts;
- unsigned int len;
- size_t off;
-
- /* AP */
- gb_timesync_to_timespec(timesync_svc, timesync_svc->ap_ping_frame_time,
- &ts);
- off = snprintf(buf, buflen, "%s frametime: ap=%lu.%lu ",
- greybus_bus_type.name, ts.tv_sec, ts.tv_nsec);
- len = buflen - off;
- if (len >= buflen)
- goto done;
-
- /* SVC */
- gb_timesync_to_timespec(timesync_svc, timesync_svc->svc_ping_frame_time,
- &ts);
- off += snprintf(&buf[off], len, "%s=%lu.%lu ", dev_name(&svc->dev),
- ts.tv_sec, ts.tv_nsec);
- len = buflen - off;
- if (len >= buflen)
- goto done;
-
- /* APB/GPB */
- hd = timesync_svc->timesync_hd->hd;
- gb_timesync_to_timespec(timesync_svc,
- timesync_svc->timesync_hd->ping_frame_time,
- &ts);
- off += snprintf(&buf[off], len, "%s=%lu.%lu ",
- dev_name(&hd->dev),
- ts.tv_sec, ts.tv_nsec);
- len = buflen - off;
- if (len >= buflen)
- goto done;
-
- list_for_each_entry(timesync_interface,
- ×ync_svc->interface_list, list) {
- interface = timesync_interface->interface;
- gb_timesync_to_timespec(timesync_svc,
- timesync_interface->ping_frame_time,
- &ts);
- off += snprintf(&buf[off], len, "%s=%lu.%lu ",
- dev_name(&interface->dev),
- ts.tv_sec, ts.tv_nsec);
- len = buflen - off;
- if (len >= buflen)
- goto done;
- }
- off += snprintf(&buf[off], len, "\n");
-done:
- return off;
-}
-
-/*
- * Send an SVC initiated wake 'ping' to each TimeSync participant.
- * Get the FrameTime from each participant associated with the wake
- * ping.
- */
-static void gb_timesync_ping(struct gb_timesync_svc *timesync_svc)
-{
- struct gb_svc *svc = timesync_svc->svc;
- struct gb_host_device *hd;
- struct gb_timesync_interface *timesync_interface;
- struct gb_control *control;
- u64 *ping_frame_time;
- int ret;
-
- /* Get access to the wake pins in the AP and SVC */
- ret = gb_timesync_platform_lock_bus(timesync_svc);
- if (ret < 0) {
- gb_timesync_platform_lock_bus_fail(timesync_svc, ret);
- return;
- }
- ret = gb_svc_timesync_wake_pins_acquire(svc, timesync_svc->strobe_mask);
- if (ret) {
- dev_err(&svc->dev,
- "gb_svc_timesync_wake_pins_acquire %d\n", ret);
- gb_timesync_teardown(timesync_svc);
- return;
- }
-
- /* Have SVC generate a timesync ping */
- timesync_svc->capture_ping = true;
- timesync_svc->svc_ping_frame_time = 0;
- ret = gb_svc_timesync_ping(svc, ×ync_svc->svc_ping_frame_time);
- timesync_svc->capture_ping = false;
- if (ret) {
- dev_err(&svc->dev,
- "gb_svc_timesync_ping %d\n", ret);
- gb_timesync_teardown(timesync_svc);
- return;
- }
-
- /* Get the ping FrameTime from each APB/GPB */
- hd = timesync_svc->timesync_hd->hd;
- timesync_svc->timesync_hd->ping_frame_time = 0;
- ret = hd->driver->timesync_get_last_event(hd,
- ×ync_svc->timesync_hd->ping_frame_time);
- if (ret)
- dev_err(&hd->dev, "host timesync_get_last_event %d\n", ret);
-
- list_for_each_entry(timesync_interface,
- ×ync_svc->interface_list, list) {
- control = timesync_interface->interface->control;
- timesync_interface->ping_frame_time = 0;
- ping_frame_time = ×ync_interface->ping_frame_time;
- ret = gb_control_timesync_get_last_event(control,
- ping_frame_time);
- if (ret) {
- dev_err(×ync_interface->interface->dev,
- "gb_control_timesync_get_last_event %d\n", ret);
- }
- }
-
- /* Ping success - move to timesync active */
- gb_svc_timesync_wake_pins_release(svc);
- gb_timesync_platform_unlock_bus();
- gb_timesync_set_state_atomic(timesync_svc, GB_TIMESYNC_STATE_ACTIVE);
-}
-
-static void gb_timesync_log_ping_time(struct gb_timesync_svc *timesync_svc)
-{
- char *buf;
-
- if (!timesync_svc->print_ping)
- return;
-
- buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
- if (buf) {
- gb_timesync_log_frame_time(timesync_svc, buf, PAGE_SIZE);
- dev_dbg(×ync_svc->svc->dev, "%s", buf);
- kfree(buf);
- }
-}
-
-/*
- * Perform the actual work of scheduled TimeSync logic.
- */
-static void gb_timesync_worker(struct work_struct *work)
-{
- struct delayed_work *delayed_work = to_delayed_work(work);
- struct gb_timesync_svc *timesync_svc =
- container_of(delayed_work, struct gb_timesync_svc, delayed_work);
-
- mutex_lock(×ync_svc->mutex);
-
- switch (timesync_svc->state) {
- case GB_TIMESYNC_STATE_INIT:
- gb_timesync_enable(timesync_svc);
- break;
-
- case GB_TIMESYNC_STATE_WAIT_SVC:
- dev_err(×ync_svc->svc->dev,
- "timeout SVC strobe completion %d/%d\n",
- timesync_svc->strobe, GB_TIMESYNC_MAX_STROBES);
- gb_timesync_teardown(timesync_svc);
- break;
-
- case GB_TIMESYNC_STATE_AUTHORITATIVE:
- gb_timesync_authoritative(timesync_svc);
- break;
-
- case GB_TIMESYNC_STATE_PING:
- gb_timesync_ping(timesync_svc);
- gb_timesync_log_ping_time(timesync_svc);
- break;
-
- default:
- pr_err("Invalid state %d for delayed work\n",
- timesync_svc->state);
- break;
- }
-
- mutex_unlock(×ync_svc->mutex);
-}
-
-/*
- * Schedule a new TimeSync INIT or PING operation serialized w/r to
- * gb_timesync_worker().
- */
-static int gb_timesync_schedule(struct gb_timesync_svc *timesync_svc, int state)
-{
- int ret = 0;
-
- if (state != GB_TIMESYNC_STATE_INIT && state != GB_TIMESYNC_STATE_PING)
- return -EINVAL;
-
- mutex_lock(×ync_svc->mutex);
- if (timesync_svc->state != GB_TIMESYNC_STATE_INVALID)
- gb_timesync_set_state_atomic(timesync_svc, state);
- else
- ret = -ENODEV;
-
- mutex_unlock(×ync_svc->mutex);
- return ret;
-}
-
-static int __gb_timesync_schedule_synchronous(
- struct gb_timesync_svc *timesync_svc, int state)
-{
- unsigned long flags;
- int ret;
-
- ret = gb_timesync_schedule(timesync_svc, state);
- if (ret)
- return ret;
-
- ret = wait_event_interruptible(timesync_svc->wait_queue,
- (timesync_svc->state == GB_TIMESYNC_STATE_ACTIVE ||
- timesync_svc->state == GB_TIMESYNC_STATE_INACTIVE ||
- timesync_svc->state == GB_TIMESYNC_STATE_INVALID));
- if (ret)
- return ret;
-
- mutex_lock(×ync_svc->mutex);
- spin_lock_irqsave(×ync_svc->spinlock, flags);
-
- ret = __gb_timesync_get_status(timesync_svc);
-
- spin_unlock_irqrestore(×ync_svc->spinlock, flags);
- mutex_unlock(×ync_svc->mutex);
-
- return ret;
-}
-
-static struct gb_timesync_svc *gb_timesync_find_timesync_svc(
- struct gb_host_device *hd)
-{
- struct gb_timesync_svc *timesync_svc;
-
- list_for_each_entry(timesync_svc, &gb_timesync_svc_list, list) {
- if (timesync_svc->svc == hd->svc)
- return timesync_svc;
- }
- return NULL;
-}
-
-static struct gb_timesync_interface *gb_timesync_find_timesync_interface(
- struct gb_timesync_svc *timesync_svc,
- struct gb_interface *interface)
-{
- struct gb_timesync_interface *timesync_interface;
-
- list_for_each_entry(timesync_interface, ×ync_svc->interface_list, list) {
- if (timesync_interface->interface == interface)
- return timesync_interface;
- }
- return NULL;
-}
-
-int gb_timesync_schedule_synchronous(struct gb_interface *interface)
-{
- int ret;
- struct gb_timesync_svc *timesync_svc;
- int retries;
-
- if (!(interface->features & GREYBUS_INTERFACE_FEATURE_TIMESYNC))
- return 0;
-
- mutex_lock(&gb_timesync_svc_list_mutex);
- for (retries = 0; retries < GB_TIMESYNC_MAX_RETRIES; retries++) {
- timesync_svc = gb_timesync_find_timesync_svc(interface->hd);
- if (!timesync_svc) {
- ret = -ENODEV;
- goto done;
- }
-
- ret = __gb_timesync_schedule_synchronous(timesync_svc,
- GB_TIMESYNC_STATE_INIT);
- if (!ret)
- break;
- }
- if (ret && retries == GB_TIMESYNC_MAX_RETRIES)
- ret = -ETIMEDOUT;
-done:
- mutex_unlock(&gb_timesync_svc_list_mutex);
- return ret;
-}
-EXPORT_SYMBOL_GPL(gb_timesync_schedule_synchronous);
-
-void gb_timesync_schedule_asynchronous(struct gb_interface *interface)
-{
- struct gb_timesync_svc *timesync_svc;
-
- if (!(interface->features & GREYBUS_INTERFACE_FEATURE_TIMESYNC))
- return;
-
- mutex_lock(&gb_timesync_svc_list_mutex);
- timesync_svc = gb_timesync_find_timesync_svc(interface->hd);
- if (!timesync_svc)
- goto done;
-
- gb_timesync_schedule(timesync_svc, GB_TIMESYNC_STATE_INIT);
-done:
- mutex_unlock(&gb_timesync_svc_list_mutex);
- return;
-}
-EXPORT_SYMBOL_GPL(gb_timesync_schedule_asynchronous);
-
-static ssize_t gb_timesync_ping_read(struct file *file, char __user *ubuf,
- size_t len, loff_t *offset, bool ktime)
-{
- struct gb_timesync_svc *timesync_svc = file_inode(file)->i_private;
- char *buf;
- ssize_t ret = 0;
-
- mutex_lock(&gb_timesync_svc_list_mutex);
- mutex_lock(×ync_svc->mutex);
- if (list_empty(×ync_svc->interface_list))
- ret = -ENODEV;
- timesync_svc->print_ping = false;
- mutex_unlock(×ync_svc->mutex);
- if (ret)
- goto done;
-
- ret = __gb_timesync_schedule_synchronous(timesync_svc,
- GB_TIMESYNC_STATE_PING);
- if (ret)
- goto done;
-
- buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
- if (!buf) {
- ret = -ENOMEM;
- goto done;
- }
-
- if (ktime)
- ret = gb_timesync_log_frame_ktime(timesync_svc, buf, PAGE_SIZE);
- else
- ret = gb_timesync_log_frame_time(timesync_svc, buf, PAGE_SIZE);
- if (ret > 0)
- ret = simple_read_from_buffer(ubuf, len, offset, buf, ret);
- kfree(buf);
-done:
- mutex_unlock(&gb_timesync_svc_list_mutex);
- return ret;
-}
-
-static ssize_t gb_timesync_ping_read_frame_time(struct file *file,
- char __user *buf,
- size_t len, loff_t *offset)
-{
- return gb_timesync_ping_read(file, buf, len, offset, false);
-}
-
-static ssize_t gb_timesync_ping_read_frame_ktime(struct file *file,
- char __user *buf,
- size_t len, loff_t *offset)
-{
- return gb_timesync_ping_read(file, buf, len, offset, true);
-}
-
-static const struct file_operations gb_timesync_debugfs_frame_time_ops = {
- .read = gb_timesync_ping_read_frame_time,
-};
-
-static const struct file_operations gb_timesync_debugfs_frame_ktime_ops = {
- .read = gb_timesync_ping_read_frame_ktime,
-};
-
-static int gb_timesync_hd_add(struct gb_timesync_svc *timesync_svc,
- struct gb_host_device *hd)
-{
- struct gb_timesync_host_device *timesync_hd;
-
- timesync_hd = kzalloc(sizeof(*timesync_hd), GFP_KERNEL);
- if (!timesync_hd)
- return -ENOMEM;
-
- WARN_ON(timesync_svc->timesync_hd);
- timesync_hd->hd = hd;
- timesync_svc->timesync_hd = timesync_hd;
-
- return 0;
-}
-
-static void gb_timesync_hd_remove(struct gb_timesync_svc *timesync_svc,
- struct gb_host_device *hd)
-{
- if (timesync_svc->timesync_hd->hd == hd) {
- kfree(timesync_svc->timesync_hd);
- timesync_svc->timesync_hd = NULL;
- return;
- }
- WARN_ON(1);
-}
-
-int gb_timesync_svc_add(struct gb_svc *svc)
-{
- struct gb_timesync_svc *timesync_svc;
- int ret;
-
- timesync_svc = kzalloc(sizeof(*timesync_svc), GFP_KERNEL);
- if (!timesync_svc)
- return -ENOMEM;
-
- timesync_svc->work_queue =
- create_singlethread_workqueue("gb-timesync-work_queue");
-
- if (!timesync_svc->work_queue) {
- kfree(timesync_svc);
- return -ENOMEM;
- }
-
- mutex_lock(&gb_timesync_svc_list_mutex);
- INIT_LIST_HEAD(×ync_svc->interface_list);
- INIT_DELAYED_WORK(×ync_svc->delayed_work, gb_timesync_worker);
- mutex_init(×ync_svc->mutex);
- spin_lock_init(×ync_svc->spinlock);
- init_waitqueue_head(×ync_svc->wait_queue);
-
- timesync_svc->svc = svc;
- timesync_svc->frame_time_offset = 0;
- timesync_svc->capture_ping = false;
- gb_timesync_set_state_atomic(timesync_svc, GB_TIMESYNC_STATE_INACTIVE);
-
- timesync_svc->frame_time_dentry =
- debugfs_create_file("frame-time", S_IRUGO, svc->debugfs_dentry,
- timesync_svc,
- &gb_timesync_debugfs_frame_time_ops);
- timesync_svc->frame_ktime_dentry =
- debugfs_create_file("frame-ktime", S_IRUGO, svc->debugfs_dentry,
- timesync_svc,
- &gb_timesync_debugfs_frame_ktime_ops);
-
- list_add(×ync_svc->list, &gb_timesync_svc_list);
- ret = gb_timesync_hd_add(timesync_svc, svc->hd);
- if (ret) {
- list_del(×ync_svc->list);
- debugfs_remove(timesync_svc->frame_ktime_dentry);
- debugfs_remove(timesync_svc->frame_time_dentry);
- destroy_workqueue(timesync_svc->work_queue);
- kfree(timesync_svc);
- goto done;
- }
-
- init_timer(×ync_svc->ktime_timer);
- timesync_svc->ktime_timer.function = gb_timesync_ktime_timer_fn;
- timesync_svc->ktime_timer.expires = jiffies + GB_TIMESYNC_KTIME_UPDATE;
- timesync_svc->ktime_timer.data = (unsigned long)timesync_svc;
- add_timer(×ync_svc->ktime_timer);
-done:
- mutex_unlock(&gb_timesync_svc_list_mutex);
- return ret;
-}
-EXPORT_SYMBOL_GPL(gb_timesync_svc_add);
-
-void gb_timesync_svc_remove(struct gb_svc *svc)
-{
- struct gb_timesync_svc *timesync_svc;
- struct gb_timesync_interface *timesync_interface;
- struct gb_timesync_interface *next;
-
- mutex_lock(&gb_timesync_svc_list_mutex);
- timesync_svc = gb_timesync_find_timesync_svc(svc->hd);
- if (!timesync_svc)
- goto done;
-
- cancel_delayed_work_sync(×ync_svc->delayed_work);
-
- mutex_lock(×ync_svc->mutex);
-
- gb_timesync_set_state_atomic(timesync_svc, GB_TIMESYNC_STATE_INVALID);
- del_timer_sync(×ync_svc->ktime_timer);
- gb_timesync_teardown(timesync_svc);
-
- gb_timesync_hd_remove(timesync_svc, svc->hd);
- list_for_each_entry_safe(timesync_interface, next,
- ×ync_svc->interface_list, list) {
- list_del(×ync_interface->list);
- kfree(timesync_interface);
- }
- debugfs_remove(timesync_svc->frame_ktime_dentry);
- debugfs_remove(timesync_svc->frame_time_dentry);
- destroy_workqueue(timesync_svc->work_queue);
- list_del(×ync_svc->list);
-
- mutex_unlock(×ync_svc->mutex);
-
- kfree(timesync_svc);
-done:
- mutex_unlock(&gb_timesync_svc_list_mutex);
-}
-EXPORT_SYMBOL_GPL(gb_timesync_svc_remove);
-
-/*
- * Add a Greybus Interface to the set of TimeSync Interfaces.
- */
-int gb_timesync_interface_add(struct gb_interface *interface)
-{
- struct gb_timesync_svc *timesync_svc;
- struct gb_timesync_interface *timesync_interface;
- int ret = 0;
-
- if (!(interface->features & GREYBUS_INTERFACE_FEATURE_TIMESYNC))
- return 0;
-
- mutex_lock(&gb_timesync_svc_list_mutex);
- timesync_svc = gb_timesync_find_timesync_svc(interface->hd);
- if (!timesync_svc) {
- ret = -ENODEV;
- goto done;
- }
-
- timesync_interface = kzalloc(sizeof(*timesync_interface), GFP_KERNEL);
- if (!timesync_interface) {
- ret = -ENOMEM;
- goto done;
- }
-
- mutex_lock(×ync_svc->mutex);
- timesync_interface->interface = interface;
- list_add(×ync_interface->list, ×ync_svc->interface_list);
- timesync_svc->strobe_mask |= 1 << interface->interface_id;
- mutex_unlock(×ync_svc->mutex);
-
-done:
- mutex_unlock(&gb_timesync_svc_list_mutex);
- return ret;
-}
-EXPORT_SYMBOL_GPL(gb_timesync_interface_add);
-
-/*
- * Remove a Greybus Interface from the set of TimeSync Interfaces.
- */
-void gb_timesync_interface_remove(struct gb_interface *interface)
-{
- struct gb_timesync_svc *timesync_svc;
- struct gb_timesync_interface *timesync_interface;
-
- if (!(interface->features & GREYBUS_INTERFACE_FEATURE_TIMESYNC))
- return;
-
- mutex_lock(&gb_timesync_svc_list_mutex);
- timesync_svc = gb_timesync_find_timesync_svc(interface->hd);
- if (!timesync_svc)
- goto done;
-
- timesync_interface = gb_timesync_find_timesync_interface(timesync_svc,
- interface);
- if (!timesync_interface)
- goto done;
-
- mutex_lock(×ync_svc->mutex);
- timesync_svc->strobe_mask &= ~(1 << interface->interface_id);
- list_del(×ync_interface->list);
- kfree(timesync_interface);
- mutex_unlock(×ync_svc->mutex);
-done:
- mutex_unlock(&gb_timesync_svc_list_mutex);
-}
-EXPORT_SYMBOL_GPL(gb_timesync_interface_remove);
-
-/*
- * Give the authoritative FrameTime to the calling function. Returns zero if we
- * are not in GB_TIMESYNC_STATE_ACTIVE.
- */
-static u64 gb_timesync_get_frame_time(struct gb_timesync_svc *timesync_svc)
-{
- unsigned long flags;
- u64 ret;
-
- spin_lock_irqsave(×ync_svc->spinlock, flags);
- if (timesync_svc->state == GB_TIMESYNC_STATE_ACTIVE)
- ret = __gb_timesync_get_frame_time(timesync_svc);
- else
- ret = 0;
- spin_unlock_irqrestore(×ync_svc->spinlock, flags);
- return ret;
-}
-
-u64 gb_timesync_get_frame_time_by_interface(struct gb_interface *interface)
-{
- struct gb_timesync_svc *timesync_svc;
- u64 ret = 0;
-
- mutex_lock(&gb_timesync_svc_list_mutex);
- timesync_svc = gb_timesync_find_timesync_svc(interface->hd);
- if (!timesync_svc)
- goto done;
-
- ret = gb_timesync_get_frame_time(timesync_svc);
-done:
- mutex_unlock(&gb_timesync_svc_list_mutex);
- return ret;
-}
-EXPORT_SYMBOL_GPL(gb_timesync_get_frame_time_by_interface);
-
-u64 gb_timesync_get_frame_time_by_svc(struct gb_svc *svc)
-{
- struct gb_timesync_svc *timesync_svc;
- u64 ret = 0;
-
- mutex_lock(&gb_timesync_svc_list_mutex);
- timesync_svc = gb_timesync_find_timesync_svc(svc->hd);
- if (!timesync_svc)
- goto done;
-
- ret = gb_timesync_get_frame_time(timesync_svc);
-done:
- mutex_unlock(&gb_timesync_svc_list_mutex);
- return ret;
-}
-EXPORT_SYMBOL_GPL(gb_timesync_get_frame_time_by_svc);
-
-/* Incrementally updates the conversion base from FrameTime to ktime */
-static void gb_timesync_ktime_timer_fn(unsigned long data)
-{
- struct gb_timesync_svc *timesync_svc =
- (struct gb_timesync_svc *)data;
- unsigned long flags;
- u64 frame_time;
- struct timespec ts;
-
- spin_lock_irqsave(×ync_svc->spinlock, flags);
-
- if (timesync_svc->state != GB_TIMESYNC_STATE_ACTIVE)
- goto done;
-
- ktime_get_ts(&ts);
- frame_time = __gb_timesync_get_frame_time(timesync_svc);
- gb_timesync_store_ktime(timesync_svc, ts, frame_time);
-
-done:
- spin_unlock_irqrestore(×ync_svc->spinlock, flags);
- mod_timer(×ync_svc->ktime_timer,
- jiffies + GB_TIMESYNC_KTIME_UPDATE);
-}
-
-int gb_timesync_to_timespec_by_svc(struct gb_svc *svc, u64 frame_time,
- struct timespec *ts)
-{
- struct gb_timesync_svc *timesync_svc;
- int ret = 0;
-
- mutex_lock(&gb_timesync_svc_list_mutex);
- timesync_svc = gb_timesync_find_timesync_svc(svc->hd);
- if (!timesync_svc) {
- ret = -ENODEV;
- goto done;
- }
- ret = gb_timesync_to_timespec(timesync_svc, frame_time, ts);
-done:
- mutex_unlock(&gb_timesync_svc_list_mutex);
- return ret;
-}
-EXPORT_SYMBOL_GPL(gb_timesync_to_timespec_by_svc);
-
-int gb_timesync_to_timespec_by_interface(struct gb_interface *interface,
- u64 frame_time, struct timespec *ts)
-{
- struct gb_timesync_svc *timesync_svc;
- int ret = 0;
-
- mutex_lock(&gb_timesync_svc_list_mutex);
- timesync_svc = gb_timesync_find_timesync_svc(interface->hd);
- if (!timesync_svc) {
- ret = -ENODEV;
- goto done;
- }
-
- ret = gb_timesync_to_timespec(timesync_svc, frame_time, ts);
-done:
- mutex_unlock(&gb_timesync_svc_list_mutex);
- return ret;
-}
-EXPORT_SYMBOL_GPL(gb_timesync_to_timespec_by_interface);
-
-void gb_timesync_irq(struct gb_timesync_svc *timesync_svc)
-{
- unsigned long flags;
- u64 strobe_time;
- bool strobe_is_ping = true;
- struct timespec ts;
-
- ktime_get_ts(&ts);
- strobe_time = __gb_timesync_get_frame_time(timesync_svc);
-
- spin_lock_irqsave(×ync_svc->spinlock, flags);
-
- if (timesync_svc->state == GB_TIMESYNC_STATE_PING) {
- if (!timesync_svc->capture_ping)
- goto done_nolog;
- timesync_svc->ap_ping_frame_time = strobe_time;
- goto done_log;
- } else if (timesync_svc->state != GB_TIMESYNC_STATE_WAIT_SVC) {
- goto done_nolog;
- }
-
- timesync_svc->strobe_data[timesync_svc->strobe].frame_time = strobe_time;
- timesync_svc->strobe_data[timesync_svc->strobe].ts = ts;
-
- if (++timesync_svc->strobe == GB_TIMESYNC_MAX_STROBES) {
- gb_timesync_set_state(timesync_svc,
- GB_TIMESYNC_STATE_AUTHORITATIVE);
- }
- strobe_is_ping = false;
-done_log:
- trace_gb_timesync_irq(strobe_is_ping, timesync_svc->strobe,
- GB_TIMESYNC_MAX_STROBES, strobe_time);
-done_nolog:
- spin_unlock_irqrestore(×ync_svc->spinlock, flags);
-}
-EXPORT_SYMBOL(gb_timesync_irq);
-
-int __init gb_timesync_init(void)
-{
- int ret = 0;
-
- ret = gb_timesync_platform_init();
- if (ret) {
- pr_err("timesync platform init fail!\n");
- return ret;
- }
-
- gb_timesync_clock_rate = gb_timesync_platform_get_clock_rate();
-
- /* Calculate nanoseconds and femtoseconds per clock */
- gb_timesync_fs_per_clock = FSEC_PER_SEC;
- do_div(gb_timesync_fs_per_clock, gb_timesync_clock_rate);
- gb_timesync_ns_per_clock = NSEC_PER_SEC;
- do_div(gb_timesync_ns_per_clock, gb_timesync_clock_rate);
-
- /* Calculate the maximum number of clocks we will convert to ktime */
- gb_timesync_max_ktime_diff =
- GB_TIMESYNC_MAX_KTIME_CONVERSION * gb_timesync_clock_rate;
-
- pr_info("Time-Sync @ %lu Hz max ktime conversion +/- %d seconds\n",
- gb_timesync_clock_rate, GB_TIMESYNC_MAX_KTIME_CONVERSION);
- return 0;
-}
-
-void gb_timesync_exit(void)
-{
- gb_timesync_platform_exit();
-}
+++ /dev/null
-/*
- * TimeSync API driver.
- *
- * Copyright 2016 Google Inc.
- * Copyright 2016 Linaro Ltd.
- *
- * Released under the GPLv2 only.
- */
-
-#ifndef __TIMESYNC_H
-#define __TIMESYNC_H
-
-struct gb_svc;
-struct gb_interface;
-struct gb_timesync_svc;
-
-/* Platform */
-u64 gb_timesync_platform_get_counter(void);
-u32 gb_timesync_platform_get_clock_rate(void);
-int gb_timesync_platform_lock_bus(struct gb_timesync_svc *pdata);
-void gb_timesync_platform_unlock_bus(void);
-
-int gb_timesync_platform_init(void);
-void gb_timesync_platform_exit(void);
-
-/* Core API */
-int gb_timesync_interface_add(struct gb_interface *interface);
-void gb_timesync_interface_remove(struct gb_interface *interface);
-int gb_timesync_svc_add(struct gb_svc *svc);
-void gb_timesync_svc_remove(struct gb_svc *svc);
-
-u64 gb_timesync_get_frame_time_by_interface(struct gb_interface *interface);
-u64 gb_timesync_get_frame_time_by_svc(struct gb_svc *svc);
-int gb_timesync_to_timespec_by_svc(struct gb_svc *svc, u64 frame_time,
- struct timespec *ts);
-int gb_timesync_to_timespec_by_interface(struct gb_interface *interface,
- u64 frame_time, struct timespec *ts);
-
-int gb_timesync_schedule_synchronous(struct gb_interface *intf);
-void gb_timesync_schedule_asynchronous(struct gb_interface *intf);
-void gb_timesync_irq(struct gb_timesync_svc *timesync_svc);
-int gb_timesync_init(void);
-void gb_timesync_exit(void);
-
-#endif /* __TIMESYNC_H */
+++ /dev/null
-/*
- * TimeSync API driver.
- *
- * Copyright 2016 Google Inc.
- * Copyright 2016 Linaro Ltd.
- *
- * Released under the GPLv2 only.
- *
- * This code reads directly from an ARMv7 memory-mapped timer that lives in
- * MMIO space. Since this counter lives inside of MMIO space its shared between
- * cores and that means we don't have to worry about issues like TSC on x86
- * where each time-stamp-counter (TSC) is local to a particular core.
- *
- * Register-level access code is based on
- * drivers/clocksource/arm_arch_timer.c
- */
-#include <linux/cpufreq.h>
-#include <linux/of_platform.h>
-
-#include "greybus.h"
-#include "arche_platform.h"
-
-#define DEFAULT_FRAMETIME_CLOCK_HZ 19200000
-
-static u32 gb_timesync_clock_frequency;
-int (*arche_platform_change_state_cb)(enum arche_platform_state state,
- struct gb_timesync_svc *pdata);
-EXPORT_SYMBOL_GPL(arche_platform_change_state_cb);
-
-u64 gb_timesync_platform_get_counter(void)
-{
- return (u64)get_cycles();
-}
-
-u32 gb_timesync_platform_get_clock_rate(void)
-{
- if (unlikely(!gb_timesync_clock_frequency)) {
- gb_timesync_clock_frequency = cpufreq_get(0);
- if (!gb_timesync_clock_frequency)
- gb_timesync_clock_frequency = DEFAULT_FRAMETIME_CLOCK_HZ;
- }
-
- return gb_timesync_clock_frequency;
-}
-
-int gb_timesync_platform_lock_bus(struct gb_timesync_svc *pdata)
-{
- return arche_platform_change_state_cb(ARCHE_PLATFORM_STATE_TIME_SYNC,
- pdata);
-}
-
-void gb_timesync_platform_unlock_bus(void)
-{
- arche_platform_change_state_cb(ARCHE_PLATFORM_STATE_ACTIVE, NULL);
-}
-
-static const struct of_device_id arch_timer_of_match[] = {
- { .compatible = "google,greybus-frame-time-counter", },
- {},
-};
-
-int __init gb_timesync_platform_init(void)
-{
- struct device_node *np;
-
- np = of_find_matching_node(NULL, arch_timer_of_match);
- if (!np) {
- /* Tolerate not finding to allow BBB etc to continue */
- pr_warn("Unable to find a compatible ARMv7 timer\n");
- return 0;
- }
-
- if (of_property_read_u32(np, "clock-frequency",
- &gb_timesync_clock_frequency)) {
- pr_err("Unable to find timer clock-frequency\n");
- return -ENODEV;
- }
-
- return 0;
-}
-
-void gb_timesync_platform_exit(void) {}
GET_AVG(apbridge_unipro_latency_avg);
GET_AVG(gbphy_firmware_latency_avg);
-void abort()
+void abort(void)
{
_exit(1);
}
int fd, i, len, ret;
struct tm tm;
time_t local_time;
- mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
char file_name[MAX_SYSFS_PATH];
char data[CSV_MAX_LINE];
snprintf(file_name, sizeof(file_name), "%s_%d_%d.csv",
t->test_name, t->size, t->iteration_max);
- fd = open(file_name, O_WRONLY | O_CREAT | O_APPEND, mode);
+ fd = open(file_name, O_WRONLY | O_CREAT | O_APPEND, 0644);
if (fd < 0) {
fprintf(stderr, "unable to open %s for appendation\n", file_name);
abort();
struct serial_struct tmp;
memset(&tmp, 0, sizeof(tmp));
- tmp.flags = ASYNC_LOW_LATENCY | ASYNC_SKIP_TEST;
tmp.type = PORT_16550A;
tmp.line = gb_tty->minor;
tmp.xmit_fifo_size = 16;
+++ /dev/null
-$Id: README.act2000,v 1.3 2000/08/06 09:22:51 armin Exp $
-
-This document describes the ACT2000 driver for the
-IBM Active 2000 ISDN card.
-
-There are 3 Types of this card available. A ISA-, MCA-, and PCMCIA-Bus
-Version. Currently, only the ISA-Bus version of the card is supported.
-However MCA and PCMCIA will follow soon.
-
-The ISA-Bus Version uses 8 IO-ports. The base port address has to be set
-manually using the DIP switches.
-
-Setting up the DIP switches for the IBM Active 2000 ISDN card:
-
- Note: S5 and S6 always set off!
-
- S1 S2 S3 S4 Base-port
- on on on on 0x0200 (Factory default)
- off on on on 0x0240
- on off on on 0x0280
- off off on on 0x02c0
- on on off on 0x0300
- off on off on 0x0340
- on off off on 0x0380
- on on on off 0xcfe0
- off on on off 0xcfa0
- on off on off 0xcf60
- off off on off 0xcf20
- on on off off 0xcee0
- off on off off 0xcea0
- on off off off 0xce60
- off off off off Card disabled
-
-IRQ is configured by software. Possible values are:
-
- 3, 5, 7, 10, 11, 12, 15 and none (polled mode)
-
-
-The ACT2000 driver may either be built into the kernel or as a module.
-Initialization depends on how the driver is built:
-
-Driver built into the kernel:
-
- The ACT2000 driver can be configured using the commandline-feature while
- loading the kernel with LILO or LOADLIN. It accepts the following syntax:
-
- act2000=b,p,i[,idstring]
-
- where
-
- b = Bus-Type (1=ISA, 2=MCA, 3=PCMCIA)
- p = portbase (-1 means autoprobe)
- i = Interrupt (-1 means use next free IRQ, 0 means polled mode)
-
- The idstring is an arbitrary string used for referencing the card
- by the actctrl tool later.
-
- Defaults used, when no parameters given at all:
-
- 1,-1,-1,""
-
- which means: Autoprobe for an ISA card, use next free IRQ, let the
- ISDN linklevel fill the IdString (usually "line0" for the first card).
-
- If you like to use more than one card, you can use the program
- "actctrl" from the utility-package to configure additional cards.
-
- Using the "actctrl"-utility, portbase and irq can also be changed
- during runtime. The D-channel protocol is configured by the "dproto"
- option of the "actctrl"-utility after loading the firmware into the
- card's memory using the "actctrl"-utility.
-
-Driver built as module:
-
- The module act2000.o can be configured during modprobe (insmod) by
- appending its parameters to the modprobe resp. insmod commandline.
- The following syntax is accepted:
-
- act_bus=b act_port=p act_irq=i act_id=idstring
-
- where b, p, i and idstring have the same meanings as the parameters
- described for the builtin version above.
-
- Using the "actctrl"-utility, the same features apply to the modularized
- version as to the kernel-builtin one. (i.e. loading of firmware and
- configuring the D-channel protocol)
-
-Loading the firmware into the card:
-
- The firmware is supplied together with the isdn4k-utils package. It
- can be found in the subdirectory act2000/firmware/
-
- Assuming you have installed the utility-package correctly, the firmware
- will be downloaded into the card using the following command:
-
- actctrl -d idstring load /etc/isdn/bip11.btl
-
- where idstring is the Name of the card, given during insmod-time or
- (for kernel-builtin driver) on the kernel commandline. If only one
- ISDN card is used, the -d isdstrin may be omitted.
-
- For further documentation (adding more IBM Active 2000 cards), refer to
- the manpage actctrl.8 which is included in the isdn4k-utils package.
-
+++ /dev/null
-$Id: README.icn,v 1.7 2000/08/06 09:22:51 armin Exp $
-
-You can get the ICN-ISDN-card from:
-
-Thinking Objects Software GmbH
-Versbacher Röthe 159
-97078 Würzburg
-Tel: +49 931 2877950
-Fax: +49 931 2877951
-
-email info@think.de
-WWW http:/www.think.de
-
-
-The card communicates with the PC by two interfaces:
- 1. A range of 4 successive port-addresses, whose base address can be
- configured with the switches.
- 2. A memory window with 16KB-256KB size, which can be setup in 16k steps
- over the whole range of 16MB. Isdn4linux only uses a 16k window.
- The base address of the window can be configured when loading
- the lowlevel-module (see README). If using more than one card,
- all cards are mapped to the same window and activated as needed.
-
-Setting up the IO-address dipswitches for the ICN-ISDN-card:
-
- Two types of cards exist, one with dip-switches and one with
- hook-switches.
-
- 1. Setting for the card with hook-switches:
-
- (0 = switch closed, 1 = switch open)
-
- S3 S2 S1 Base-address
- 0 0 0 0x300
- 0 0 1 0x310
- 0 1 0 0x320 (Default for isdn4linux)
- 0 1 1 0x330
- 1 0 0 0x340
- 1 0 1 0x350
- 1 1 0 0x360
- 1 1 1 NOT ALLOWED!
-
- 2. Setting for the card with dip-switches:
-
- (0 = switch closed, 1 = switch open)
-
- S1 S2 S3 S4 Base-Address
- 0 0 0 0 0x300
- 0 0 0 1 0x310
- 0 0 1 0 0x320 (Default for isdn4linux)
- 0 0 1 1 0x330
- 0 1 0 0 0x340
- 0 1 0 1 0x350
- 0 1 1 0 0x360
- 0 1 1 1 NOT ALLOWED!
- 1 0 0 0 0x308
- 1 0 0 1 0x318
- 1 0 1 0 0x328
- 1 0 1 1 0x338
- 1 1 0 0 0x348
- 1 1 0 1 0x358
- 1 1 1 0 0x368
- 1 1 1 1 NOT ALLOWED!
-
-The ICN driver may be built into the kernel or as a module. Initialization
-depends on how the driver is built:
-
-Driver built into the kernel:
-
- The ICN driver can be configured using the commandline-feature while
- loading the kernel with LILO or LOADLIN. It accepts the following syntax:
-
- icn=p,m[,idstring1[,idstring2]]
-
- where
-
- p = portbase (default: 0x320)
- m = shared memory (default: 0xd0000)
-
- When using the ICN double card (4B), you MUST define TWO idstrings.
- idstring must start with a character! There is no way for the driver
- to distinguish between a 2B and 4B type card. Therefore, by supplying
- TWO idstrings, you tell the driver that you have a 4B installed.
-
- If you like to use more than one card, you can use the program
- "icnctrl" from the utility-package to configure additional cards.
- You need to configure shared memory only once, since the icn-driver
- maps all cards into the same address-space.
-
- Using the "icnctrl"-utility, portbase and shared memory can also be
- changed during runtime.
-
- The D-channel protocol is configured by loading different firmware
- into the card's memory using the "icnctrl"-utility.
-
-
-Driver built as module:
-
- The module icn.o can be configured during "insmod'ing" it by
- appending its parameters to the insmod-commandline. The following
- syntax is accepted:
-
- portbase=p membase=m icn_id=idstring [icn_id2=idstring2]
-
- where p, m, idstring1 and idstring2 have the same meanings as the
- parameters described for the kernel-version above.
-
- When using the ICN double card (4B), you MUST define TWO idstrings.
- idstring must start with a character! There is no way for the driver
- to distinguish between a 2B and 4B type card. Therefore, by supplying
- TWO idstrings, you tell the driver that you have a 4B installed.
-
- Using the "icnctrl"-utility, the same features apply to the modularized
- version like to the kernel-builtin one.
-
- The D-channel protocol is configured by loading different firmware
- into the card's memory using the "icnctrl"-utility.
-
-Loading the firmware into the card:
-
- The firmware is supplied together with the isdn4k-utils package. It
- can be found in the subdirectory icnctrl/firmware/
-
- There are 3 files:
-
- loadpg.bin - Image of the bootstrap loader.
- pc_1t_ca.bin - Image of firmware for german 1TR6 protocol.
- pc_eu_ca.bin - Image if firmware for EDSS1 (Euro-ISDN) protocol.
-
- Assuming you have installed the utility-package correctly, the firmware
- will be downloaded into the 2B-card using the following command:
-
- icnctrl -d Idstring load /etc/isdn/loadpg.bin /etc/isdn/pc_XX_ca.bin
-
- where XX is either "1t" or "eu", depending on the D-Channel protocol
- used on your S0-bus and Idstring is the Name of the card, given during
- insmod-time or (for kernel-builtin driver) on the kernel commandline.
-
- To load a 4B-card, the same command is used, except a second firmware
- file is appended to the commandline of icnctrl.
-
- -> After downloading firmware, the two LEDs at the back cover of the card
- (ICN-4B: 4 LEDs) must be blinking intermittently now. If a connection
- is up, the corresponding led is lit continuously.
-
- For further documentation (adding more ICN-cards), refer to the manpage
- icnctrl.8 which is included in the isdn4k-utils package.
-
+++ /dev/null
-------------------------------------------------------------------------------
- README file for the PCBIT-D Device Driver.
-------------------------------------------------------------------------------
-
-The PCBIT is a Euro ISDN adapter manufactured in Portugal by Octal and
-developed in cooperation with Portugal Telecom and Inesc.
-The driver interfaces with the standard kernel isdn facilities
-originally developed by Fritz Elfert in the isdn4linux project.
-
-The common versions of the pcbit board require a firmware that is
-distributed (and copyrighted) by the manufacturer. To load this
-firmware you need "pcbitctl" available on the standard isdn4k-utils
-package or in the pcbit package available in:
-
-ftp://ftp.di.fc.ul.pt/pub/systems/Linux/isdn
-
-Known Limitations:
-
-- The board reset procedure is at the moment incorrect and will only
-allow you to load the firmware after a hard reset.
-
-- Only HDLC in B-channels is supported at the moment. There is no
-current support for X.25 in B or D channels nor LAPD in B
-channels. The main reason is that these two other protocol modes have,
-to my knowledge, very little use. If you want to see them implemented
-*do* send me a mail.
-
-- The driver often triggers errors in the board that I and the
-manufacturer believe to be caused by bugs in the firmware. The current
-version includes several procedures for error recovery that should
-allow normal operation. Plans for the future include cooperation with
-the manufacturer in order to solve this problem.
-
-Information/hints/help can be obtained in the linux isdn
-mailing list (isdn4linux@listserv.isdn4linux.de) or directly from me.
-
-regards,
- Pedro.
-
-<roque@di.fc.ul.pt>
+++ /dev/null
-Welcome to Beta Release 2 of the combination ISDN driver for SpellCaster's
-ISA ISDN adapters. Please note this release 2 includes support for the
-DataCommute/BRI and TeleCommute/BRI adapters only and any other use is
-guaranteed to fail. If you have a DataCommute/PRI installed in the test
-computer, we recommend removing it as it will be detected but will not
-be usable. To see what we have done to Beta Release 2, see section 3.
-
-Speaking of guarantees, THIS IS BETA SOFTWARE and as such contains
-bugs and defects either known or unknown. Use this software at your own
-risk. There is NO SUPPORT for this software. Some help may be available
-through the web site or the mailing list but such support is totally at
-our own option and without warranty. If you choose to assume all and
-total risk by using this driver, we encourage you to join the beta
-mailing list.
-
-To join the Linux beta mailing list, send a message to:
-majordomo@spellcast.com with the words "subscribe linux-beta" as the only
-contents of the message. Do not include a signature. If you choose to
-remove yourself from this list at a later date, send another message to
-the same address with the words "unsubscribe linux-beta" as its only
-contents.
-
-TABLE OF CONTENTS
------------------
- 1. Introduction
- 1.1 What is ISDN4Linux?
- 1.2 What is different between this driver and previous drivers?
- 1.3 How do I setup my system with the correct software to use
- this driver release?
-
- 2. Basic Operations
- 2.1 Unpacking and installing the driver
- 2.2 Read the man pages!!!
- 2.3 Installing the driver
- 2.4 Removing the driver
- 2.5 What to do if it doesn't load
- 2.6 How to setup ISDN4Linux with the driver
-
- 3. Beta Change Summaries and Miscellaneous Notes
-
-1. Introduction
----------------
-
-The revision 2 Linux driver for SpellCaster ISA ISDN adapters is built
-upon ISDN4Linux available separately or as included in Linux 2.0 and later.
-The driver will support a maximum of 4 adapters in any one system of any
-type including DataCommute/BRI, DataCommute/PRI and TeleCommute/BRI for a
-maximum of 92 channels for host. The driver is supplied as a module in
-source form and needs to be complied before it can be used. It has been
-tested on Linux 2.0.20.
-
-1.1 What Is ISDN4Linux
-
-ISDN4Linux is a driver and set of tools used to access and use ISDN devices
-on a Linux platform in a common and standard way. It supports HDLC and PPP
-protocols and offers channel bundling and MLPPP support. To use ISDN4Linux
-you need to configure your kernel for ISDN support and get the ISDN4Linux
-tool kit from our web site.
-
-ISDN4Linux creates a channel pool from all of the available ISDN channels
-and therefore can function across adapters. When an ISDN4Linux compliant
-driver (such as ours) is loaded, all of the channels go into a pool and
-are used on a first-come first-served basis. In addition, individual
-channels can be specifically bound to particular interfaces.
-
-1.2 What is different between this driver and previous drivers?
-
-The revision 2 driver besides adopting the ISDN4Linux architecture has many
-subtle and not so subtle functional differences from previous releases. These
-include:
- - More efficient shared memory management combined with a simpler
- configuration. All adapters now use only 16Kbytes of shared RAM
- versus between 16K and 64K. New methods for using the shared RAM
- allow us to utilize all of the available RAM on the adapter through
- only one 16K page.
- - Better detection of available upper memory. The probing routines
- have been improved to better detect available shared RAM pages and
- used pages are now locked.
- - Decreased loading time and a wider range of I/O ports probed.
- We have significantly reduced the amount of time it takes to load
- the driver and at the same time doubled the number of I/O ports
- probed increasing the likelihood of finding an adapter.
- - We now support all ISA adapter models with a single driver instead
- of separate drivers for each model. The revision 2 driver supports
- the DataCommute/BRI, DataCommute/PRI and TeleCommute/BRI in any
- combination up to a maximum of four adapters per system.
- - On board PPP protocol support has been removed in favour of the
- sync-PPP support used in ISDN4Linux. This means more control of
- the protocol parameters, faster negotiation time and a more
- familiar interface.
-
-1.3 How do I setup my system with the correct software to use
- this driver release?
-
-Before you can compile, install and use the SpellCaster ISA ISDN driver, you
-must ensure that the following software is installed, configured and running:
-
- - Linux kernel 2.0.20 or later with the required init and ps
- versions. Please see your distribution vendor for the correct
- utility packages. The latest kernel is available from
- ftp://sunsite.unc.edu/pub/Linux/kernel/v2.0/
-
- - The latest modules package (modules-2.0.0.tar.gz) from
- ftp://sunsite.unc.edu/pub/Linux/kernel/modules-2.0.0.tar.gz
-
- - The ISDN4Linux tools available from
- ftp://ftp.franken.de/pub/isdn4linux/v2.0/isdn4k-utils-2.0.tar.gz
- This package may fail to compile for you so you can alternatively
- get a pre-compiled version from
- ftp://ftp.spellcast.com/pub/drivers/isdn4linux/isdn4k-bin-2.0.tar.gz
-
-
-2. Basic Operations
--------------------
-
-2.1 Unpacking and installing the driver
-
- 1. As root, create a directory in a convenient place. We suggest
- /usr/src/spellcaster.
-
- 2. Unpack the archive with :
- tar xzf sc-n.nn.tar.gz -C /usr/src/spellcaster
-
- 3. Change directory to /usr/src/spellcaster
-
- 4. Read the README and RELNOTES files.
-
- 5. Run 'make' and if all goes well, run 'make install'.
-
-2.2 Read the man pages!!!
-
-Make sure you read the scctrl(8) and sc(4) manual pages before continuing
-any further. Type 'man 8 scctrl' and 'man 4 sc'.
-
-2.3 Installing the driver
-
-To install the driver, type '/sbin/insmod sc' as root. sc(4) details options
-you can specify but you shouldn't need to use any unless this doesn't work.
-
-Make sure the driver loaded and detected all of the adapters by typing
-'dmesg'.
-
-The driver can be configured so that it is loaded upon startup. To do this,
-edit the file "/etc/modules/'uname -f'/'uname -v'" and insert the driver name
-"sc" into this file.
-
-2.4 Removing the driver
-
-To remove the driver, delete any interfaces that may exist (see isdnctrl(8)
-for more on this) and then type '/sbin/rmmod sc'.
-
-2.5 What to do if it doesn't load
-
-If, when you try to install the driver, you get a message mentioning
-'register_isdn' then you do not have the ISDN4Linux system installed. Please
-make sure that ISDN support is configured in the kernel.
-
-If you get a message that says 'initialization of sc failed', then the
-driver failed to detect an adapter or failed to find resources needed such
-as a free IRQ line or shared memory segment. If you are sure there are free
-resources available, use the insmod options detailed in sc(4) to override
-the probing function.
-
-Upon testing, the following problem was noted, the driver would load without
-problems, but the board would not respond beyond that point. When a check was
-done with 'cat /proc/interrupts' the interrupt count for sc was 0. In the event
-of this problem, change the BIOS settings so that the interrupts in question are
-reserved for ISA use only.
-
-
-2.6 How to setup ISDN4Linux with the driver
-
-There are three main configurations which you can use with the driver:
-
-A) Basic HDLC connection
-B) PPP connection
-C) MLPPP connection
-
-It should be mentioned here that you may also use a tty connection if you
-desire. The Documentation directory of the isdn4linux subsystem offers good
-documentation on this feature.
-
-A) 10 steps to the establishment of a basic HDLC connection
------------------------------------------------------------
-
-- please open the isdn-hdlc file in the examples directory and follow along...
-
- This file is a script used to configure a BRI ISDN TA to establish a
- basic HDLC connection between its two channels. Two network
- interfaces are created and two routes added between the channels.
-
- i) using the isdnctrl utility, add an interface with "addif" and
- name it "isdn0"
- ii) add the outgoing and inbound telephone numbers
- iii) set the Layer 2 protocol to hdlc
- iv) set the eaz of the interface to be the phone number of that
- specific channel
- v) to turn the callback features off, set the callback to "off" and
- the callback delay (cbdelay) to 0.
- vi) the hangup timeout can be set to a specified number of seconds
- vii) the hangup upon incoming call can be set on or off
- viii) use the ifconfig command to bring up the network interface with
- a specific IP address and point to point address
- ix) add a route to the IP address through the isdn0 interface
- x) a ping should result in the establishment of the connection
-
-
-B) Establishment of a PPP connection
-------------------------------------
-
-- please open the isdn-ppp file in the examples directory and follow along...
-
- This file is a script used to configure a BRI ISDN TA to establish a
- PPP connection between the two channels. The file is almost
- identical to the HDLC connection example except that the packet
- encapsulation type has to be set.
-
- use the same procedure as in the HDLC connection from steps i) to
- iii) then, after the Layer 2 protocol is set, set the encapsulation
- "encap" to syncppp. With this done, the rest of the steps, iv) to x)
- can be followed from above.
-
- Then, the ipppd (ippp daemon) must be setup:
-
- xi) use the ipppd function found in /sbin/ipppd to set the following:
- xii) take out (minus) VJ compression and bsd compression
- xiii) set the mru size to 2000
- xiv) link the two /dev interfaces to the daemon
-
-NOTE: A "*" in the inbound telephone number specifies that a call can be
-accepted on any number.
-
-C) Establishment of a MLPPP connection
---------------------------------------
-
-- please open the isdn-mppp file in the examples directory and follow along...
-
- This file is a script used to configure a BRI ISDN TA to accept a
- Multi Link PPP connection.
-
- i) using the isdnctrl utility, add an interface with "addif" and
- name it "ippp0"
- ii) add the inbound telephone number
- iii) set the Layer 2 protocol to hdlc and the Layer 3 protocol to
- trans (transparent)
- iv) set the packet encapsulation to syncppp
- v) set the eaz of the interface to be the phone number of that
- specific channel
- vi) to turn the callback features off, set the callback to "off" and
- the callback delay (cbdelay) to 0.
- vi) the hangup timeout can be set to a specified number of seconds
- vii) the hangup upon incoming call can be set on or off
- viii) add a slave interface and name it "ippp32" for example
- ix) set the similar parameters for the ippp32 interface
- x) use the ifconfig command to bring-up the ippp0 interface with a
- specific IP address and point to point address
- xi) add a route to the IP address through the ippp0 interface
- xii) use the ipppd function found in /sbin/ipppd to set the following:
- xiii) take out (minus) bsd compression
- xiv) set the mru size to 2000
- xv) add (+) the multi-link function "+mp"
- xvi) link the two /dev interfaces to the daemon
-
-NOTE: To use the MLPPP connection to dial OUT to a MLPPP connection, change
-the inbound telephone numbers to the outgoing telephone numbers of the MLPPP
-host.
-
-
-3. Beta Change Summaries and Miscellaneous Notes
-------------------------------------------------
-When using the "scctrl" utility to upload firmware revisions on the board,
-please note that the byte count displayed at the end of the operation may be
-different from the total number of bytes in the "dcbfwn.nn.sr" file. Please
-disregard the displayed byte count.
-
-It was noted that in Beta Release 1, the module would fail to load and result
-in a segmentation fault when 'insmod'ed. This problem was created when one of
-the isdn4linux parameters, (isdn_ctrl, data field) was filled in. In some
-cases, this data field was NULL, and was left unchecked, so when it was
-referenced... segv. The bug has been fixed around line 63-68 of event.c.
-
+++ /dev/null
-#
-# Old ISDN4Linux config
-#
-menu "Old ISDN4Linux (deprecated)"
- depends on ISDN_I4L
-
-source "drivers/staging/i4l/icn/Kconfig"
-
-source "drivers/staging/i4l/pcbit/Kconfig"
-
-source "drivers/staging/i4l/act2000/Kconfig"
-
-endmenu
+++ /dev/null
-# Makefile for the old ISDN I4L subsystem and device drivers.
-
-obj-$(CONFIG_ISDN_DRV_ICN) += icn/
-obj-$(CONFIG_ISDN_DRV_PCBIT) += pcbit/
-obj-$(CONFIG_ISDN_DRV_ACT2000) += act2000/
+++ /dev/null
-* The icn, pcbit and act2000 drivers are dead, remove them in 2017
- after another longterm kernel has been released, just in the
- unlikely case someone still has this hardware.
+++ /dev/null
-config ISDN_DRV_ACT2000
- tristate "IBM Active 2000 support"
- depends on ISA
- help
- Say Y here if you have an IBM Active 2000 ISDN card. In order to use
- this card, additional firmware is necessary, which has to be loaded
- into the card using a utility which is part of the latest
- isdn4k-utils package. Please read the file
- <file:Documentation/isdn/README.act2000> for more information.
+++ /dev/null
-# Makefile for the act2000 ISDN device driver
-
-# Each configuration option enables a list of files.
-
-obj-$(CONFIG_ISDN_DRV_ACT2000) += act2000.o
-
-# Multipart objects.
-
-act2000-y := module.o capi.o act2000_isa.o
+++ /dev/null
-/* $Id: act2000.h,v 1.8.6.3 2001/09/23 22:24:32 kai Exp $
- *
- * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
- *
- * Author Fritz Elfert
- * Copyright by Fritz Elfert <fritz@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * Thanks to Friedemann Baitinger and IBM Germany
- *
- */
-
-#ifndef act2000_h
-#define act2000_h
-
-#include <linux/compiler.h>
-
-#define ACT2000_IOCTL_SETPORT 1
-#define ACT2000_IOCTL_GETPORT 2
-#define ACT2000_IOCTL_SETIRQ 3
-#define ACT2000_IOCTL_GETIRQ 4
-#define ACT2000_IOCTL_SETBUS 5
-#define ACT2000_IOCTL_GETBUS 6
-#define ACT2000_IOCTL_SETPROTO 7
-#define ACT2000_IOCTL_GETPROTO 8
-#define ACT2000_IOCTL_SETMSN 9
-#define ACT2000_IOCTL_GETMSN 10
-#define ACT2000_IOCTL_LOADBOOT 11
-#define ACT2000_IOCTL_ADDCARD 12
-
-#define ACT2000_IOCTL_TEST 98
-#define ACT2000_IOCTL_DEBUGVAR 99
-
-#define ACT2000_BUS_ISA 1
-#define ACT2000_BUS_MCA 2
-#define ACT2000_BUS_PCMCIA 3
-
-/* Struct for adding new cards */
-typedef struct act2000_cdef {
- int bus;
- int port;
- int irq;
- char id[10];
-} act2000_cdef;
-
-/* Struct for downloading firmware */
-typedef struct act2000_ddef {
- int length; /* Length of code */
- char __user *buffer; /* Ptr. to code */
-} act2000_ddef;
-
-typedef struct act2000_fwid {
- char isdn[4];
- char revlen[2];
- char revision[504];
-} act2000_fwid;
-
-#if defined(__KERNEL__) || defined(__DEBUGVAR__)
-
-#ifdef __KERNEL__
-/* Kernel includes */
-
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/workqueue.h>
-#include <linux/interrupt.h>
-#include <linux/skbuff.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/major.h>
-#include <asm/io.h>
-#include <linux/kernel.h>
-#include <linux/signal.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/ioport.h>
-#include <linux/timer.h>
-#include <linux/wait.h>
-#include <linux/delay.h>
-#include <linux/ctype.h>
-#include <linux/isdnif.h>
-
-#endif /* __KERNEL__ */
-
-#define ACT2000_PORTLEN 8
-
-#define ACT2000_FLAGS_RUNNING 1 /* Cards driver activated */
-#define ACT2000_FLAGS_PVALID 2 /* Cards port is valid */
-#define ACT2000_FLAGS_IVALID 4 /* Cards irq is valid */
-#define ACT2000_FLAGS_LOADED 8 /* Firmware loaded */
-
-#define ACT2000_BCH 2 /* # of channels per card */
-
-/* D-Channel states */
-#define ACT2000_STATE_NULL 0
-#define ACT2000_STATE_ICALL 1
-#define ACT2000_STATE_OCALL 2
-#define ACT2000_STATE_IWAIT 3
-#define ACT2000_STATE_OWAIT 4
-#define ACT2000_STATE_IBWAIT 5
-#define ACT2000_STATE_OBWAIT 6
-#define ACT2000_STATE_BWAIT 7
-#define ACT2000_STATE_BHWAIT 8
-#define ACT2000_STATE_BHWAIT2 9
-#define ACT2000_STATE_DHWAIT 10
-#define ACT2000_STATE_DHWAIT2 11
-#define ACT2000_STATE_BSETUP 12
-#define ACT2000_STATE_ACTIVE 13
-
-#define ACT2000_MAX_QUEUED 8000 /* 2 * maxbuff */
-
-#define ACT2000_LOCK_TX 0
-#define ACT2000_LOCK_RX 1
-
-typedef struct act2000_chan {
- unsigned short callref; /* Call Reference */
- unsigned short fsm_state; /* Current D-Channel state */
- unsigned short eazmask; /* EAZ-Mask for this Channel */
- short queued; /* User-Data Bytes in TX queue */
- unsigned short plci;
- unsigned short ncci;
- unsigned char l2prot; /* Layer 2 protocol */
- unsigned char l3prot; /* Layer 3 protocol */
-} act2000_chan;
-
-typedef struct msn_entry {
- char eaz;
- char msn[16];
- struct msn_entry *next;
-} msn_entry;
-
-typedef struct irq_data_isa {
- __u8 *rcvptr;
- __u16 rcvidx;
- __u16 rcvlen;
- struct sk_buff *rcvskb;
- __u8 rcvignore;
- __u8 rcvhdr[8];
-} irq_data_isa;
-
-typedef union act2000_irq_data {
- irq_data_isa isa;
-} act2000_irq_data;
-
-/*
- * Per card driver data
- */
-typedef struct act2000_card {
- unsigned short port; /* Base-port-address */
- unsigned short irq; /* Interrupt */
- u_char ptype; /* Protocol type (1TR6 or Euro) */
- u_char bus; /* Cardtype (ISA, MCA, PCMCIA) */
- struct act2000_card *next; /* Pointer to next device struct */
- spinlock_t lock; /* protect critical operations */
- int myid; /* Driver-Nr. assigned by linklevel */
- unsigned long flags; /* Statusflags */
- unsigned long ilock; /* Semaphores for IRQ-Routines */
- struct sk_buff_head rcvq; /* Receive-Message queue */
- struct sk_buff_head sndq; /* Send-Message queue */
- struct sk_buff_head ackq; /* Data-Ack-Message queue */
- u_char *ack_msg; /* Ptr to User Data in User skb */
- __u16 need_b3ack; /* Flag: Need ACK for current skb */
- struct sk_buff *sbuf; /* skb which is currently sent */
- struct timer_list ptimer; /* Poll timer */
- struct work_struct snd_tq; /* Task struct for xmit bh */
- struct work_struct rcv_tq; /* Task struct for rcv bh */
- struct work_struct poll_tq; /* Task struct for polled rcv bh */
- msn_entry *msn_list;
- unsigned short msgnum; /* Message number for sending */
- spinlock_t mnlock; /* lock for msgnum */
- act2000_chan bch[ACT2000_BCH]; /* B-Channel status/control */
- char status_buf[256]; /* Buffer for status messages */
- char *status_buf_read;
- char *status_buf_write;
- char *status_buf_end;
- act2000_irq_data idat; /* Data used for IRQ handler */
- isdn_if interface; /* Interface to upper layer */
- char regname[35]; /* Name used for request_region */
-} act2000_card;
-
-static inline void act2000_schedule_tx(act2000_card *card)
-{
- schedule_work(&card->snd_tq);
-}
-
-static inline void act2000_schedule_rx(act2000_card *card)
-{
- schedule_work(&card->rcv_tq);
-}
-
-static inline void act2000_schedule_poll(act2000_card *card)
-{
- schedule_work(&card->poll_tq);
-}
-
-extern char *act2000_find_eaz(act2000_card *, char);
-
-#endif /* defined(__KERNEL__) || defined(__DEBUGVAR__) */
-#endif /* act2000_h */
+++ /dev/null
-/* $Id: act2000_isa.c,v 1.11.6.3 2001/09/23 22:24:32 kai Exp $
- *
- * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version).
- *
- * Author Fritz Elfert
- * Copyright by Fritz Elfert <fritz@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * Thanks to Friedemann Baitinger and IBM Germany
- *
- */
-
-#include "act2000.h"
-#include "act2000_isa.h"
-#include "capi.h"
-
-/*
- * Reset Controller, then try to read the Card's signature.
- + Return:
- * 1 = Signature found.
- * 0 = Signature not found.
- */
-static int
-act2000_isa_reset(unsigned short portbase)
-{
- unsigned char reg;
- int i;
- int found;
- int serial = 0;
-
- found = 0;
- reg = inb(portbase + ISA_COR);
- if (reg != 0xff) {
- outb(reg | ISA_COR_RESET, portbase + ISA_COR);
- mdelay(10);
- outb(reg, portbase + ISA_COR);
- mdelay(10);
-
- for (i = 0; i < 16; i++) {
- if (inb(portbase + ISA_ISR) & ISA_ISR_SERIAL)
- serial |= 0x10000;
- serial >>= 1;
- }
- if (serial == ISA_SER_ID)
- found++;
- }
- return found;
-}
-
-int
-act2000_isa_detect(unsigned short portbase)
-{
- int ret = 0;
-
- if (request_region(portbase, ACT2000_PORTLEN, "act2000isa")) {
- ret = act2000_isa_reset(portbase);
- release_region(portbase, ISA_REGION);
- }
- return ret;
-}
-
-static irqreturn_t
-act2000_isa_interrupt(int dummy, void *dev_id)
-{
- act2000_card *card = dev_id;
- u_char istatus;
-
- istatus = (inb(ISA_PORT_ISR) & 0x07);
- if (istatus & ISA_ISR_OUT) {
- /* RX fifo has data */
- istatus &= ISA_ISR_OUT_MASK;
- outb(0, ISA_PORT_SIS);
- act2000_isa_receive(card);
- outb(ISA_SIS_INT, ISA_PORT_SIS);
- }
- if (istatus & ISA_ISR_ERR) {
- /* Error Interrupt */
- istatus &= ISA_ISR_ERR_MASK;
- printk(KERN_WARNING "act2000: errIRQ\n");
- }
- if (istatus)
- printk(KERN_DEBUG "act2000: ?IRQ %d %02x\n", card->irq, istatus);
- return IRQ_HANDLED;
-}
-
-static void
-act2000_isa_select_irq(act2000_card *card)
-{
- unsigned char reg;
-
- reg = (inb(ISA_PORT_COR) & ~ISA_COR_IRQOFF) | ISA_COR_PERR;
- switch (card->irq) {
- case 3:
- reg = ISA_COR_IRQ03;
- break;
- case 5:
- reg = ISA_COR_IRQ05;
- break;
- case 7:
- reg = ISA_COR_IRQ07;
- break;
- case 10:
- reg = ISA_COR_IRQ10;
- break;
- case 11:
- reg = ISA_COR_IRQ11;
- break;
- case 12:
- reg = ISA_COR_IRQ12;
- break;
- case 15:
- reg = ISA_COR_IRQ15;
- break;
- }
- outb(reg, ISA_PORT_COR);
-}
-
-static void
-act2000_isa_enable_irq(act2000_card *card)
-{
- act2000_isa_select_irq(card);
- /* Enable READ irq */
- outb(ISA_SIS_INT, ISA_PORT_SIS);
-}
-
-/*
- * Install interrupt handler, enable irq on card.
- * If irq is -1, choose next free irq, else irq is given explicitly.
- */
-int
-act2000_isa_config_irq(act2000_card *card, short irq)
-{
- int old_irq;
-
- if (card->flags & ACT2000_FLAGS_IVALID)
- free_irq(card->irq, card);
-
- card->flags &= ~ACT2000_FLAGS_IVALID;
- outb(ISA_COR_IRQOFF, ISA_PORT_COR);
- if (!irq)
- return 0;
-
- old_irq = card->irq;
- card->irq = irq;
- if (request_irq(irq, &act2000_isa_interrupt, 0, card->regname, card)) {
- card->irq = old_irq;
- card->flags |= ACT2000_FLAGS_IVALID;
- printk(KERN_WARNING
- "act2000: Could not request irq %d\n", irq);
- return -EBUSY;
- } else {
- act2000_isa_select_irq(card);
- /* Disable READ and WRITE irq */
- outb(0, ISA_PORT_SIS);
- outb(0, ISA_PORT_SOS);
- }
- return 0;
-}
-
-int
-act2000_isa_config_port(act2000_card *card, unsigned short portbase)
-{
- if (card->flags & ACT2000_FLAGS_PVALID) {
- release_region(card->port, ISA_REGION);
- card->flags &= ~ACT2000_FLAGS_PVALID;
- }
- if (!request_region(portbase, ACT2000_PORTLEN, card->regname))
- return -EBUSY;
- else {
- card->port = portbase;
- card->flags |= ACT2000_FLAGS_PVALID;
- return 0;
- }
-}
-
-/*
- * Release resources, used by an adaptor.
- */
-void
-act2000_isa_release(act2000_card *card)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&card->lock, flags);
- if (card->flags & ACT2000_FLAGS_IVALID)
- free_irq(card->irq, card);
-
- card->flags &= ~ACT2000_FLAGS_IVALID;
- if (card->flags & ACT2000_FLAGS_PVALID)
- release_region(card->port, ISA_REGION);
- card->flags &= ~ACT2000_FLAGS_PVALID;
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-static int
-act2000_isa_writeb(act2000_card *card, u_char data)
-{
- u_char timeout = 40;
-
- while (timeout) {
- if (inb(ISA_PORT_SOS) & ISA_SOS_READY) {
- outb(data, ISA_PORT_SDO);
- return 0;
- } else {
- timeout--;
- udelay(10);
- }
- }
- return 1;
-}
-
-static int
-act2000_isa_readb(act2000_card *card, u_char *data)
-{
- u_char timeout = 40;
-
- while (timeout) {
- if (inb(ISA_PORT_SIS) & ISA_SIS_READY) {
- *data = inb(ISA_PORT_SDI);
- return 0;
- } else {
- timeout--;
- udelay(10);
- }
- }
- return 1;
-}
-
-void
-act2000_isa_receive(act2000_card *card)
-{
- u_char c;
-
- if (test_and_set_bit(ACT2000_LOCK_RX, (void *)&card->ilock) != 0)
- return;
- while (!act2000_isa_readb(card, &c)) {
- if (card->idat.isa.rcvidx < 8) {
- card->idat.isa.rcvhdr[card->idat.isa.rcvidx++] = c;
- if (card->idat.isa.rcvidx == 8) {
- int valid = actcapi_chkhdr(card, (actcapi_msghdr *)&card->idat.isa.rcvhdr);
-
- if (valid) {
- card->idat.isa.rcvlen = ((actcapi_msghdr *)&card->idat.isa.rcvhdr)->len;
- card->idat.isa.rcvskb = dev_alloc_skb(card->idat.isa.rcvlen);
- if (!card->idat.isa.rcvskb) {
- card->idat.isa.rcvignore = 1;
- printk(KERN_WARNING
- "act2000_isa_receive: no memory\n");
- test_and_clear_bit(ACT2000_LOCK_RX, (void *)&card->ilock);
- return;
- }
- memcpy(skb_put(card->idat.isa.rcvskb, 8), card->idat.isa.rcvhdr, 8);
- card->idat.isa.rcvptr = skb_put(card->idat.isa.rcvskb, card->idat.isa.rcvlen - 8);
- } else {
- card->idat.isa.rcvidx = 0;
- printk(KERN_WARNING
- "act2000_isa_receive: Invalid CAPI msg\n");
- {
- int i; __u8 *p; __u8 *t; __u8 tmp[30];
-
- for (i = 0, p = (__u8 *)&card->idat.isa.rcvhdr, t = tmp; i < 8; i++)
- t += sprintf(t, "%02x ", *(p++));
- printk(KERN_WARNING "act2000_isa_receive: %s\n", tmp);
- }
- }
- }
- } else {
- if (!card->idat.isa.rcvignore)
- *card->idat.isa.rcvptr++ = c;
- if (++card->idat.isa.rcvidx >= card->idat.isa.rcvlen) {
- if (!card->idat.isa.rcvignore) {
- skb_queue_tail(&card->rcvq, card->idat.isa.rcvskb);
- act2000_schedule_rx(card);
- }
- card->idat.isa.rcvidx = 0;
- card->idat.isa.rcvlen = 8;
- card->idat.isa.rcvignore = 0;
- card->idat.isa.rcvskb = NULL;
- card->idat.isa.rcvptr = card->idat.isa.rcvhdr;
- }
- }
- }
- if (!(card->flags & ACT2000_FLAGS_IVALID)) {
- /* In polling mode, schedule myself */
- if ((card->idat.isa.rcvidx) &&
- (card->idat.isa.rcvignore ||
- (card->idat.isa.rcvidx < card->idat.isa.rcvlen)))
- act2000_schedule_poll(card);
- }
- test_and_clear_bit(ACT2000_LOCK_RX, (void *)&card->ilock);
-}
-
-void
-act2000_isa_send(act2000_card *card)
-{
- unsigned long flags;
- struct sk_buff *skb;
- actcapi_msg *msg;
- int l;
-
- if (test_and_set_bit(ACT2000_LOCK_TX, (void *)&card->ilock) != 0)
- return;
- while (1) {
- spin_lock_irqsave(&card->lock, flags);
- if (!(card->sbuf)) {
- card->sbuf = skb_dequeue(&card->sndq);
- if (card->sbuf) {
- card->ack_msg = card->sbuf->data;
- msg = (actcapi_msg *)card->sbuf->data;
- if ((msg->hdr.cmd.cmd == 0x86) &&
- (msg->hdr.cmd.subcmd == 0)) {
- /* Save flags in message */
- card->need_b3ack = msg->msg.data_b3_req.flags;
- msg->msg.data_b3_req.flags = 0;
- }
- }
- }
- spin_unlock_irqrestore(&card->lock, flags);
- if (!(card->sbuf)) {
- /* No more data to send */
- test_and_clear_bit(ACT2000_LOCK_TX, (void *)&card->ilock);
- return;
- }
- skb = card->sbuf;
- l = 0;
- while (skb->len) {
- if (act2000_isa_writeb(card, *(skb->data))) {
- /* Fifo is full, but more data to send */
- test_and_clear_bit(ACT2000_LOCK_TX, (void *)&card->ilock);
- /* Schedule myself */
- act2000_schedule_tx(card);
- return;
- }
- skb_pull(skb, 1);
- l++;
- }
- msg = (actcapi_msg *)card->ack_msg;
- if ((msg->hdr.cmd.cmd == 0x86) &&
- (msg->hdr.cmd.subcmd == 0)) {
- /*
- * If it's user data, reset data-ptr
- * and put skb into ackq.
- */
- skb->data = card->ack_msg;
- /* Restore flags in message */
- msg->msg.data_b3_req.flags = card->need_b3ack;
- skb_queue_tail(&card->ackq, skb);
- } else
- dev_kfree_skb(skb);
- card->sbuf = NULL;
- }
-}
-
-/*
- * Get firmware ID, check for 'ISDN' signature.
- */
-static int
-act2000_isa_getid(act2000_card *card)
-{
- act2000_fwid fid;
- u_char *p = (u_char *)&fid;
- int count = 0;
-
- while (1) {
- if (count > 510)
- return -EPROTO;
- if (act2000_isa_readb(card, p++))
- break;
- count++;
- }
- if (count <= 20) {
- printk(KERN_WARNING "act2000: No Firmware-ID!\n");
- return -ETIME;
- }
- *p = '\0';
- fid.revlen[0] = '\0';
- if (strcmp(fid.isdn, "ISDN")) {
- printk(KERN_WARNING "act2000: Wrong Firmware-ID!\n");
- return -EPROTO;
- }
- p = strchr(fid.revision, '\n');
- if (p)
- *p = '\0';
- printk(KERN_INFO "act2000: Firmware-ID: %s\n", fid.revision);
- if (card->flags & ACT2000_FLAGS_IVALID) {
- printk(KERN_DEBUG "Enabling Interrupts ...\n");
- act2000_isa_enable_irq(card);
- }
- return 0;
-}
-
-/*
- * Download microcode into card, check Firmware signature.
- */
-int
-act2000_isa_download(act2000_card *card, act2000_ddef __user *cb)
-{
- unsigned int length;
- int l;
- int c;
- u_char *b;
- u_char __user *p;
- u_char *buf;
- act2000_ddef cblock;
-
- if (!act2000_isa_reset(card->port))
- return -ENXIO;
- msleep_interruptible(500);
- if (copy_from_user(&cblock, cb, sizeof(cblock)))
- return -EFAULT;
- length = cblock.length;
- p = cblock.buffer;
- if (!access_ok(VERIFY_READ, p, length))
- return -EFAULT;
- buf = kmalloc(1024, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
- while (length) {
- l = (length > 1024) ? 1024 : length;
- c = 0;
- b = buf;
- if (copy_from_user(buf, p, l)) {
- kfree(buf);
- return -EFAULT;
- }
- while (c < l) {
- if (act2000_isa_writeb(card, *b++)) {
- printk(KERN_WARNING
- "act2000: loader timed out"
- " len=%d c=%d\n", length, c);
- kfree(buf);
- return -ETIME;
- }
- c++;
- }
- length -= l;
- p += l;
- }
- kfree(buf);
- msleep_interruptible(500);
- return act2000_isa_getid(card);
-}
+++ /dev/null
-/* $Id: act2000_isa.h,v 1.4.6.1 2001/09/23 22:24:32 kai Exp $
- *
- * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000 (ISA-Version).
- *
- * Author Fritz Elfert
- * Copyright by Fritz Elfert <fritz@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * Thanks to Friedemann Baitinger and IBM Germany
- *
- */
-
-#ifndef act2000_isa_h
-#define act2000_isa_h
-
-#define ISA_POLL_LOOP 40 /* Try to read-write before give up */
-
-typedef enum {
- INT_NO_CHANGE = 0, /* Do not change the Mask */
- INT_ON = 1, /* Set to Enable */
- INT_OFF = 2, /* Set to Disable */
-} ISA_INT_T;
-
-/**************************************************************************/
-/* Configuration Register COR (RW) */
-/**************************************************************************/
-/* 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 */
-/* Soft Res| IRQM | IRQ Select | N/A | WAIT |Proc err */
-/**************************************************************************/
-#define ISA_COR 0 /* Offset for ISA config register */
-#define ISA_COR_PERR 0x01 /* Processor Error Enabled */
-#define ISA_COR_WS 0x02 /* Insert Wait State if 1 */
-#define ISA_COR_IRQOFF 0x38 /* No Interrupt */
-#define ISA_COR_IRQ07 0x30 /* IRQ 7 Enable */
-#define ISA_COR_IRQ05 0x28 /* IRQ 5 Enable */
-#define ISA_COR_IRQ03 0x20 /* IRQ 3 Enable */
-#define ISA_COR_IRQ10 0x18 /* IRQ 10 Enable */
-#define ISA_COR_IRQ11 0x10 /* IRQ 11 Enable */
-#define ISA_COR_IRQ12 0x08 /* IRQ 12 Enable */
-#define ISA_COR_IRQ15 0x00 /* IRQ 15 Enable */
-#define ISA_COR_IRQPULSE 0x40 /* 0 = Level 1 = Pulse Interrupt */
-#define ISA_COR_RESET 0x80 /* Soft Reset for Transputer */
-
-/**************************************************************************/
-/* Interrupt Source Register ISR (RO) */
-/**************************************************************************/
-/* 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 */
-/* N/A | N/A | N/A |Err sig |Ser ID |IN Intr |Out Intr| Error */
-/**************************************************************************/
-#define ISA_ISR 1 /* Offset for Interrupt Register */
-#define ISA_ISR_ERR 0x01 /* Error Interrupt */
-#define ISA_ISR_OUT 0x02 /* Output Interrupt */
-#define ISA_ISR_INP 0x04 /* Input Interrupt */
-#define ISA_ISR_SERIAL 0x08 /* Read out Serial ID after Reset */
-#define ISA_ISR_ERRSIG 0x10 /* Error Signal Input */
-#define ISA_ISR_ERR_MASK 0xfe /* Mask Error Interrupt */
-#define ISA_ISR_OUT_MASK 0xfd /* Mask Output Interrupt */
-#define ISA_ISR_INP_MASK 0xfb /* Mask Input Interrupt */
-
-/* Signature delivered after Reset at ISA_ISR_SERIAL (LSB first) */
-#define ISA_SER_ID 0x0201 /* ID for ISA Card */
-
-/**************************************************************************/
-/* EEPROM Register EPR (RW) */
-/**************************************************************************/
-/* 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 */
-/* N/A | N/A | N/A |ROM Hold| ROM CS |ROM CLK | ROM IN |ROM Out */
-/**************************************************************************/
-#define ISA_EPR 2 /* Offset for this Register */
-#define ISA_EPR_OUT 0x01 /* Rome Register Out (RO) */
-#define ISA_EPR_IN 0x02 /* Rom Register In (WR) */
-#define ISA_EPR_CLK 0x04 /* Rom Clock (WR) */
-#define ISA_EPR_CS 0x08 /* Rom Cip Select (WR) */
-#define ISA_EPR_HOLD 0x10 /* Rom Hold Signal (WR) */
-
-/**************************************************************************/
-/* EEPROM enable Register EER (unused) */
-/**************************************************************************/
-#define ISA_EER 3 /* Offset for this Register */
-
-/**************************************************************************/
-/* SLC Data Input SDI (RO) */
-/**************************************************************************/
-#define ISA_SDI 4 /* Offset for this Register */
-
-/**************************************************************************/
-/* SLC Data Output SDO (WO) */
-/**************************************************************************/
-#define ISA_SDO 5 /* Offset for this Register */
-
-/**************************************************************************/
-/* IMS C011 Mode 2 Input Status Register for INMOS CPU SIS (RW) */
-/**************************************************************************/
-/* 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 */
-/* N/A | N/A | N/A | N/A | N/A | N/A |Int Ena |Data Pre */
-/**************************************************************************/
-#define ISA_SIS 6 /* Offset for this Register */
-#define ISA_SIS_READY 0x01 /* If 1 : data is available */
-#define ISA_SIS_INT 0x02 /* Enable Interrupt for READ */
-
-/**************************************************************************/
-/* IMS C011 Mode 2 Output Status Register from INMOS CPU SOS (RW) */
-/**************************************************************************/
-/* 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 */
-/* N/A | N/A | N/A | N/A | N/A | N/A |Int Ena |Out Rdy */
-/**************************************************************************/
-#define ISA_SOS 7 /* Offset for this Register */
-#define ISA_SOS_READY 0x01 /* If 1 : we can write Data */
-#define ISA_SOS_INT 0x02 /* Enable Interrupt for WRITE */
-
-#define ISA_REGION 8 /* Number of Registers */
-
-
-/* Macros for accessing ports */
-#define ISA_PORT_COR (card->port + ISA_COR)
-#define ISA_PORT_ISR (card->port + ISA_ISR)
-#define ISA_PORT_EPR (card->port + ISA_EPR)
-#define ISA_PORT_EER (card->port + ISA_EER)
-#define ISA_PORT_SDI (card->port + ISA_SDI)
-#define ISA_PORT_SDO (card->port + ISA_SDO)
-#define ISA_PORT_SIS (card->port + ISA_SIS)
-#define ISA_PORT_SOS (card->port + ISA_SOS)
-
-/* Prototypes */
-
-extern int act2000_isa_detect(unsigned short portbase);
-extern int act2000_isa_config_irq(act2000_card *card, short irq);
-extern int act2000_isa_config_port(act2000_card *card, unsigned short portbase);
-extern int act2000_isa_download(act2000_card *card, act2000_ddef __user *cb);
-extern void act2000_isa_release(act2000_card *card);
-extern void act2000_isa_receive(act2000_card *card);
-extern void act2000_isa_send(act2000_card *card);
-
-#endif /* act2000_isa_h */
+++ /dev/null
-/* $Id: capi.c,v 1.9.6.2 2001/09/23 22:24:32 kai Exp $
- *
- * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
- * CAPI encoder/decoder
- *
- * Author Fritz Elfert
- * Copyright by Fritz Elfert <fritz@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * Thanks to Friedemann Baitinger and IBM Germany
- *
- */
-
-#include "act2000.h"
-#include "capi.h"
-
-static actcapi_msgdsc valid_msg[] = {
- {{ 0x86, 0x02}, "DATA_B3_IND"}, /* DATA_B3_IND/CONF must be first because of speed!!! */
- {{ 0x86, 0x01}, "DATA_B3_CONF"},
- {{ 0x02, 0x01}, "CONNECT_CONF"},
- {{ 0x02, 0x02}, "CONNECT_IND"},
- {{ 0x09, 0x01}, "CONNECT_INFO_CONF"},
- {{ 0x03, 0x02}, "CONNECT_ACTIVE_IND"},
- {{ 0x04, 0x01}, "DISCONNECT_CONF"},
- {{ 0x04, 0x02}, "DISCONNECT_IND"},
- {{ 0x05, 0x01}, "LISTEN_CONF"},
- {{ 0x06, 0x01}, "GET_PARAMS_CONF"},
- {{ 0x07, 0x01}, "INFO_CONF"},
- {{ 0x07, 0x02}, "INFO_IND"},
- {{ 0x08, 0x01}, "DATA_CONF"},
- {{ 0x08, 0x02}, "DATA_IND"},
- {{ 0x40, 0x01}, "SELECT_B2_PROTOCOL_CONF"},
- {{ 0x80, 0x01}, "SELECT_B3_PROTOCOL_CONF"},
- {{ 0x81, 0x01}, "LISTEN_B3_CONF"},
- {{ 0x82, 0x01}, "CONNECT_B3_CONF"},
- {{ 0x82, 0x02}, "CONNECT_B3_IND"},
- {{ 0x83, 0x02}, "CONNECT_B3_ACTIVE_IND"},
- {{ 0x84, 0x01}, "DISCONNECT_B3_CONF"},
- {{ 0x84, 0x02}, "DISCONNECT_B3_IND"},
- {{ 0x85, 0x01}, "GET_B3_PARAMS_CONF"},
- {{ 0x01, 0x01}, "RESET_B3_CONF"},
- {{ 0x01, 0x02}, "RESET_B3_IND"},
- /* {{ 0x87, 0x02, "HANDSET_IND"}, not implemented */
- {{ 0xff, 0x01}, "MANUFACTURER_CONF"},
- {{ 0xff, 0x02}, "MANUFACTURER_IND"},
-#ifdef DEBUG_MSG
- /* Requests */
- {{ 0x01, 0x00}, "RESET_B3_REQ"},
- {{ 0x02, 0x00}, "CONNECT_REQ"},
- {{ 0x04, 0x00}, "DISCONNECT_REQ"},
- {{ 0x05, 0x00}, "LISTEN_REQ"},
- {{ 0x06, 0x00}, "GET_PARAMS_REQ"},
- {{ 0x07, 0x00}, "INFO_REQ"},
- {{ 0x08, 0x00}, "DATA_REQ"},
- {{ 0x09, 0x00}, "CONNECT_INFO_REQ"},
- {{ 0x40, 0x00}, "SELECT_B2_PROTOCOL_REQ"},
- {{ 0x80, 0x00}, "SELECT_B3_PROTOCOL_REQ"},
- {{ 0x81, 0x00}, "LISTEN_B3_REQ"},
- {{ 0x82, 0x00}, "CONNECT_B3_REQ"},
- {{ 0x84, 0x00}, "DISCONNECT_B3_REQ"},
- {{ 0x85, 0x00}, "GET_B3_PARAMS_REQ"},
- {{ 0x86, 0x00}, "DATA_B3_REQ"},
- {{ 0xff, 0x00}, "MANUFACTURER_REQ"},
- /* Responses */
- {{ 0x01, 0x03}, "RESET_B3_RESP"},
- {{ 0x02, 0x03}, "CONNECT_RESP"},
- {{ 0x03, 0x03}, "CONNECT_ACTIVE_RESP"},
- {{ 0x04, 0x03}, "DISCONNECT_RESP"},
- {{ 0x07, 0x03}, "INFO_RESP"},
- {{ 0x08, 0x03}, "DATA_RESP"},
- {{ 0x82, 0x03}, "CONNECT_B3_RESP"},
- {{ 0x83, 0x03}, "CONNECT_B3_ACTIVE_RESP"},
- {{ 0x84, 0x03}, "DISCONNECT_B3_RESP"},
- {{ 0x86, 0x03}, "DATA_B3_RESP"},
- {{ 0xff, 0x03}, "MANUFACTURER_RESP"},
-#endif
- {{ 0x00, 0x00}, NULL},
-};
-#define num_valid_imsg 27 /* MANUFACTURER_IND */
-
-/*
- * Check for a valid incoming CAPI message.
- * Return:
- * 0 = Invalid message
- * 1 = Valid message, no B-Channel-data
- * 2 = Valid message, B-Channel-data
- */
-int
-actcapi_chkhdr(act2000_card *card, actcapi_msghdr *hdr)
-{
- int i;
-
- if (hdr->applicationID != 1)
- return 0;
- if (hdr->len < 9)
- return 0;
- for (i = 0; i < num_valid_imsg; i++)
- if ((hdr->cmd.cmd == valid_msg[i].cmd.cmd) &&
- (hdr->cmd.subcmd == valid_msg[i].cmd.subcmd)) {
- return i ? 1 : 2;
- }
- return 0;
-}
-
-#define ACTCAPI_MKHDR(l, c, s) { \
- skb = alloc_skb(l + 8, GFP_ATOMIC); \
- if (skb) { \
- m = (actcapi_msg *)skb_put(skb, l + 8); \
- m->hdr.len = l + 8; \
- m->hdr.applicationID = 1; \
- m->hdr.cmd.cmd = c; \
- m->hdr.cmd.subcmd = s; \
- m->hdr.msgnum = actcapi_nextsmsg(card); \
- } else { \
- m = NULL; \
- } \
- }
-
-#define ACTCAPI_CHKSKB if (!skb) { \
- printk(KERN_WARNING "actcapi: alloc_skb failed\n"); \
- return; \
- }
-
-#define ACTCAPI_QUEUE_TX { \
- actcapi_debug_msg(skb, 1); \
- skb_queue_tail(&card->sndq, skb); \
- act2000_schedule_tx(card); \
- }
-
-int
-actcapi_listen_req(act2000_card *card)
-{
- __u16 eazmask = 0;
- int i;
- actcapi_msg *m;
- struct sk_buff *skb;
-
- for (i = 0; i < ACT2000_BCH; i++)
- eazmask |= card->bch[i].eazmask;
- ACTCAPI_MKHDR(9, 0x05, 0x00);
- if (!skb) {
- printk(KERN_WARNING "actcapi: alloc_skb failed\n");
- return -ENOMEM;
- }
- m->msg.listen_req.controller = 0;
- m->msg.listen_req.infomask = 0x3f; /* All information */
- m->msg.listen_req.eazmask = eazmask;
- m->msg.listen_req.simask = (eazmask) ? 0x86 : 0; /* All SI's */
- ACTCAPI_QUEUE_TX;
- return 0;
-}
-
-int
-actcapi_connect_req(act2000_card *card, act2000_chan *chan, char *phone,
- char eaz, int si1, int si2)
-{
- actcapi_msg *m;
- struct sk_buff *skb;
-
- ACTCAPI_MKHDR((11 + strlen(phone)), 0x02, 0x00);
- if (!skb) {
- printk(KERN_WARNING "actcapi: alloc_skb failed\n");
- chan->fsm_state = ACT2000_STATE_NULL;
- return -ENOMEM;
- }
- m->msg.connect_req.controller = 0;
- m->msg.connect_req.bchan = 0x83;
- m->msg.connect_req.infomask = 0x3f;
- m->msg.connect_req.si1 = si1;
- m->msg.connect_req.si2 = si2;
- m->msg.connect_req.eaz = eaz ? eaz : '0';
- m->msg.connect_req.addr.len = strlen(phone) + 1;
- m->msg.connect_req.addr.tnp = 0x81;
- memcpy(m->msg.connect_req.addr.num, phone, strlen(phone));
- chan->callref = m->hdr.msgnum;
- ACTCAPI_QUEUE_TX;
- return 0;
-}
-
-static void
-actcapi_connect_b3_req(act2000_card *card, act2000_chan *chan)
-{
- actcapi_msg *m;
- struct sk_buff *skb;
-
- ACTCAPI_MKHDR(17, 0x82, 0x00);
- ACTCAPI_CHKSKB;
- m->msg.connect_b3_req.plci = chan->plci;
- memset(&m->msg.connect_b3_req.ncpi, 0,
- sizeof(m->msg.connect_b3_req.ncpi));
- m->msg.connect_b3_req.ncpi.len = 13;
- m->msg.connect_b3_req.ncpi.modulo = 8;
- ACTCAPI_QUEUE_TX;
-}
-
-/*
- * Set net type (1TR6) or (EDSS1)
- */
-int
-actcapi_manufacturer_req_net(act2000_card *card)
-{
- actcapi_msg *m;
- struct sk_buff *skb;
-
- ACTCAPI_MKHDR(5, 0xff, 0x00);
- if (!skb) {
- printk(KERN_WARNING "actcapi: alloc_skb failed\n");
- return -ENOMEM;
- }
- m->msg.manufacturer_req_net.manuf_msg = 0x11;
- m->msg.manufacturer_req_net.controller = 1;
- m->msg.manufacturer_req_net.nettype = (card->ptype == ISDN_PTYPE_EURO) ? 1 : 0;
- ACTCAPI_QUEUE_TX;
- printk(KERN_INFO "act2000 %s: D-channel protocol now %s\n",
- card->interface.id, (card->ptype == ISDN_PTYPE_EURO) ? "euro" : "1tr6");
- card->interface.features &=
- ~(ISDN_FEATURE_P_UNKNOWN | ISDN_FEATURE_P_EURO | ISDN_FEATURE_P_1TR6);
- card->interface.features |=
- ((card->ptype == ISDN_PTYPE_EURO) ? ISDN_FEATURE_P_EURO : ISDN_FEATURE_P_1TR6);
- return 0;
-}
-
-/*
- * Switch V.42 on or off
- */
-#if 0
-int
-actcapi_manufacturer_req_v42(act2000_card *card, ulong arg)
-{
- actcapi_msg *m;
- struct sk_buff *skb;
-
- ACTCAPI_MKHDR(8, 0xff, 0x00);
- if (!skb) {
-
- printk(KERN_WARNING "actcapi: alloc_skb failed\n");
- return -ENOMEM;
- }
- m->msg.manufacturer_req_v42.manuf_msg = 0x10;
- m->msg.manufacturer_req_v42.controller = 0;
- m->msg.manufacturer_req_v42.v42control = (arg ? 1 : 0);
- ACTCAPI_QUEUE_TX;
- return 0;
-}
-#endif /* 0 */
-
-/*
- * Set error-handler
- */
-int
-actcapi_manufacturer_req_errh(act2000_card *card)
-{
- actcapi_msg *m;
- struct sk_buff *skb;
-
- ACTCAPI_MKHDR(4, 0xff, 0x00);
- if (!skb) {
-
- printk(KERN_WARNING "actcapi: alloc_skb failed\n");
- return -ENOMEM;
- }
- m->msg.manufacturer_req_err.manuf_msg = 0x03;
- m->msg.manufacturer_req_err.controller = 0;
- ACTCAPI_QUEUE_TX;
- return 0;
-}
-
-/*
- * Set MSN-Mapping.
- */
-int
-actcapi_manufacturer_req_msn(act2000_card *card)
-{
- msn_entry *p = card->msn_list;
- actcapi_msg *m;
- struct sk_buff *skb;
- int len;
-
- while (p) {
- int i;
-
- len = strlen(p->msn);
- for (i = 0; i < 2; i++) {
- ACTCAPI_MKHDR(6 + len, 0xff, 0x00);
- if (!skb) {
- printk(KERN_WARNING "actcapi: alloc_skb failed\n");
- return -ENOMEM;
- }
- m->msg.manufacturer_req_msn.manuf_msg = 0x13 + i;
- m->msg.manufacturer_req_msn.controller = 0;
- m->msg.manufacturer_req_msn.msnmap.eaz = p->eaz;
- m->msg.manufacturer_req_msn.msnmap.len = len;
- memcpy(m->msg.manufacturer_req_msn.msnmap.msn, p->msn, len);
- ACTCAPI_QUEUE_TX;
- }
- p = p->next;
- }
- return 0;
-}
-
-void
-actcapi_select_b2_protocol_req(act2000_card *card, act2000_chan *chan)
-{
- actcapi_msg *m;
- struct sk_buff *skb;
-
- ACTCAPI_MKHDR(10, 0x40, 0x00);
- ACTCAPI_CHKSKB;
- m->msg.select_b2_protocol_req.plci = chan->plci;
- memset(&m->msg.select_b2_protocol_req.dlpd, 0,
- sizeof(m->msg.select_b2_protocol_req.dlpd));
- m->msg.select_b2_protocol_req.dlpd.len = 6;
- switch (chan->l2prot) {
- case ISDN_PROTO_L2_TRANS:
- m->msg.select_b2_protocol_req.protocol = 0x03;
- m->msg.select_b2_protocol_req.dlpd.dlen = 4000;
- break;
- case ISDN_PROTO_L2_HDLC:
- m->msg.select_b2_protocol_req.protocol = 0x02;
- m->msg.select_b2_protocol_req.dlpd.dlen = 4000;
- break;
- case ISDN_PROTO_L2_X75I:
- case ISDN_PROTO_L2_X75UI:
- case ISDN_PROTO_L2_X75BUI:
- m->msg.select_b2_protocol_req.protocol = 0x01;
- m->msg.select_b2_protocol_req.dlpd.dlen = 4000;
- m->msg.select_b2_protocol_req.dlpd.laa = 3;
- m->msg.select_b2_protocol_req.dlpd.lab = 1;
- m->msg.select_b2_protocol_req.dlpd.win = 7;
- m->msg.select_b2_protocol_req.dlpd.modulo = 8;
- break;
- }
- ACTCAPI_QUEUE_TX;
-}
-
-static void
-actcapi_select_b3_protocol_req(act2000_card *card, act2000_chan *chan)
-{
- actcapi_msg *m;
- struct sk_buff *skb;
-
- ACTCAPI_MKHDR(17, 0x80, 0x00);
- ACTCAPI_CHKSKB;
- m->msg.select_b3_protocol_req.plci = chan->plci;
- memset(&m->msg.select_b3_protocol_req.ncpd, 0,
- sizeof(m->msg.select_b3_protocol_req.ncpd));
- switch (chan->l3prot) {
- case ISDN_PROTO_L3_TRANS:
- m->msg.select_b3_protocol_req.protocol = 0x04;
- m->msg.select_b3_protocol_req.ncpd.len = 13;
- m->msg.select_b3_protocol_req.ncpd.modulo = 8;
- break;
- }
- ACTCAPI_QUEUE_TX;
-}
-
-static void
-actcapi_listen_b3_req(act2000_card *card, act2000_chan *chan)
-{
- actcapi_msg *m;
- struct sk_buff *skb;
-
- ACTCAPI_MKHDR(2, 0x81, 0x00);
- ACTCAPI_CHKSKB;
- m->msg.listen_b3_req.plci = chan->plci;
- ACTCAPI_QUEUE_TX;
-}
-
-static void
-actcapi_disconnect_req(act2000_card *card, act2000_chan *chan)
-{
- actcapi_msg *m;
- struct sk_buff *skb;
-
- ACTCAPI_MKHDR(3, 0x04, 0x00);
- ACTCAPI_CHKSKB;
- m->msg.disconnect_req.plci = chan->plci;
- m->msg.disconnect_req.cause = 0;
- ACTCAPI_QUEUE_TX;
-}
-
-void
-actcapi_disconnect_b3_req(act2000_card *card, act2000_chan *chan)
-{
- actcapi_msg *m;
- struct sk_buff *skb;
-
- ACTCAPI_MKHDR(17, 0x84, 0x00);
- ACTCAPI_CHKSKB;
- m->msg.disconnect_b3_req.ncci = chan->ncci;
- memset(&m->msg.disconnect_b3_req.ncpi, 0,
- sizeof(m->msg.disconnect_b3_req.ncpi));
- m->msg.disconnect_b3_req.ncpi.len = 13;
- m->msg.disconnect_b3_req.ncpi.modulo = 8;
- chan->fsm_state = ACT2000_STATE_BHWAIT;
- ACTCAPI_QUEUE_TX;
-}
-
-void
-actcapi_connect_resp(act2000_card *card, act2000_chan *chan, __u8 cause)
-{
- actcapi_msg *m;
- struct sk_buff *skb;
-
- ACTCAPI_MKHDR(3, 0x02, 0x03);
- ACTCAPI_CHKSKB;
- m->msg.connect_resp.plci = chan->plci;
- m->msg.connect_resp.rejectcause = cause;
- if (cause) {
- chan->fsm_state = ACT2000_STATE_NULL;
- chan->plci = 0x8000;
- } else
- chan->fsm_state = ACT2000_STATE_IWAIT;
- ACTCAPI_QUEUE_TX;
-}
-
-static void
-actcapi_connect_active_resp(act2000_card *card, act2000_chan *chan)
-{
- actcapi_msg *m;
- struct sk_buff *skb;
-
- ACTCAPI_MKHDR(2, 0x03, 0x03);
- ACTCAPI_CHKSKB;
- m->msg.connect_resp.plci = chan->plci;
- if (chan->fsm_state == ACT2000_STATE_IWAIT)
- chan->fsm_state = ACT2000_STATE_IBWAIT;
- ACTCAPI_QUEUE_TX;
-}
-
-static void
-actcapi_connect_b3_resp(act2000_card *card, act2000_chan *chan, __u8 rejectcause)
-{
- actcapi_msg *m;
- struct sk_buff *skb;
-
- ACTCAPI_MKHDR((rejectcause ? 3 : 17), 0x82, 0x03);
- ACTCAPI_CHKSKB;
- m->msg.connect_b3_resp.ncci = chan->ncci;
- m->msg.connect_b3_resp.rejectcause = rejectcause;
- if (!rejectcause) {
- memset(&m->msg.connect_b3_resp.ncpi, 0,
- sizeof(m->msg.connect_b3_resp.ncpi));
- m->msg.connect_b3_resp.ncpi.len = 13;
- m->msg.connect_b3_resp.ncpi.modulo = 8;
- chan->fsm_state = ACT2000_STATE_BWAIT;
- }
- ACTCAPI_QUEUE_TX;
-}
-
-static void
-actcapi_connect_b3_active_resp(act2000_card *card, act2000_chan *chan)
-{
- actcapi_msg *m;
- struct sk_buff *skb;
-
- ACTCAPI_MKHDR(2, 0x83, 0x03);
- ACTCAPI_CHKSKB;
- m->msg.connect_b3_active_resp.ncci = chan->ncci;
- chan->fsm_state = ACT2000_STATE_ACTIVE;
- ACTCAPI_QUEUE_TX;
-}
-
-static void
-actcapi_info_resp(act2000_card *card, act2000_chan *chan)
-{
- actcapi_msg *m;
- struct sk_buff *skb;
-
- ACTCAPI_MKHDR(2, 0x07, 0x03);
- ACTCAPI_CHKSKB;
- m->msg.info_resp.plci = chan->plci;
- ACTCAPI_QUEUE_TX;
-}
-
-static void
-actcapi_disconnect_b3_resp(act2000_card *card, act2000_chan *chan)
-{
- actcapi_msg *m;
- struct sk_buff *skb;
-
- ACTCAPI_MKHDR(2, 0x84, 0x03);
- ACTCAPI_CHKSKB;
- m->msg.disconnect_b3_resp.ncci = chan->ncci;
- chan->ncci = 0x8000;
- chan->queued = 0;
- ACTCAPI_QUEUE_TX;
-}
-
-static void
-actcapi_disconnect_resp(act2000_card *card, act2000_chan *chan)
-{
- actcapi_msg *m;
- struct sk_buff *skb;
-
- ACTCAPI_MKHDR(2, 0x04, 0x03);
- ACTCAPI_CHKSKB;
- m->msg.disconnect_resp.plci = chan->plci;
- chan->plci = 0x8000;
- ACTCAPI_QUEUE_TX;
-}
-
-static int
-new_plci(act2000_card *card, __u16 plci)
-{
- int i;
-
- for (i = 0; i < ACT2000_BCH; i++)
- if (card->bch[i].plci == 0x8000) {
- card->bch[i].plci = plci;
- return i;
- }
- return -1;
-}
-
-static int
-find_plci(act2000_card *card, __u16 plci)
-{
- int i;
-
- for (i = 0; i < ACT2000_BCH; i++)
- if (card->bch[i].plci == plci)
- return i;
- return -1;
-}
-
-static int
-find_ncci(act2000_card *card, __u16 ncci)
-{
- int i;
-
- for (i = 0; i < ACT2000_BCH; i++)
- if (card->bch[i].ncci == ncci)
- return i;
- return -1;
-}
-
-static int
-find_dialing(act2000_card *card, __u16 callref)
-{
- int i;
-
- for (i = 0; i < ACT2000_BCH; i++)
- if ((card->bch[i].callref == callref) &&
- (card->bch[i].fsm_state == ACT2000_STATE_OCALL))
- return i;
- return -1;
-}
-
-static int
-actcapi_data_b3_ind(act2000_card *card, struct sk_buff *skb) {
- __u16 plci;
- __u16 ncci;
- __u8 blocknr;
- int chan;
- actcapi_msg *msg = (actcapi_msg *)skb->data;
-
- EVAL_NCCI(msg->msg.data_b3_ind.fakencci, plci, ncci);
- chan = find_ncci(card, ncci);
- if (chan < 0)
- return 0;
- if (card->bch[chan].fsm_state != ACT2000_STATE_ACTIVE)
- return 0;
- if (card->bch[chan].plci != plci)
- return 0;
- blocknr = msg->msg.data_b3_ind.blocknr;
- skb_pull(skb, 19);
- card->interface.rcvcallb_skb(card->myid, chan, skb);
- if (!(skb = alloc_skb(11, GFP_ATOMIC))) {
- printk(KERN_WARNING "actcapi: alloc_skb failed\n");
- return 1;
- }
- msg = (actcapi_msg *)skb_put(skb, 11);
- msg->hdr.len = 11;
- msg->hdr.applicationID = 1;
- msg->hdr.cmd.cmd = 0x86;
- msg->hdr.cmd.subcmd = 0x03;
- msg->hdr.msgnum = actcapi_nextsmsg(card);
- msg->msg.data_b3_resp.ncci = ncci;
- msg->msg.data_b3_resp.blocknr = blocknr;
- ACTCAPI_QUEUE_TX;
- return 1;
-}
-
-/*
- * Walk over ackq, unlink DATA_B3_REQ from it, if
- * ncci and blocknr are matching.
- * Decrement queued-bytes counter.
- */
-static int
-handle_ack(act2000_card *card, act2000_chan *chan, __u8 blocknr) {
- unsigned long flags;
- struct sk_buff *skb;
- struct sk_buff *tmp;
- struct actcapi_msg *m;
- int ret = 0;
-
- spin_lock_irqsave(&card->lock, flags);
- skb = skb_peek(&card->ackq);
- spin_unlock_irqrestore(&card->lock, flags);
- if (!skb) {
- printk(KERN_WARNING "act2000: handle_ack nothing found!\n");
- return 0;
- }
- tmp = skb;
- while (1) {
- m = (actcapi_msg *)tmp->data;
- if ((((m->msg.data_b3_req.fakencci >> 8) & 0xff) == chan->ncci) &&
- (m->msg.data_b3_req.blocknr == blocknr)) {
- /* found corresponding DATA_B3_REQ */
- skb_unlink(tmp, &card->ackq);
- chan->queued -= m->msg.data_b3_req.datalen;
- if (m->msg.data_b3_req.flags)
- ret = m->msg.data_b3_req.datalen;
- dev_kfree_skb(tmp);
- if (chan->queued < 0)
- chan->queued = 0;
- return ret;
- }
- spin_lock_irqsave(&card->lock, flags);
- tmp = skb_peek((struct sk_buff_head *)tmp);
- spin_unlock_irqrestore(&card->lock, flags);
- if ((tmp == skb) || !tmp) {
- /* reached end of queue */
- printk(KERN_WARNING "act2000: handle_ack nothing found!\n");
- return 0;
- }
- }
-}
-
-void
-actcapi_dispatch(struct work_struct *work)
-{
- struct act2000_card *card =
- container_of(work, struct act2000_card, rcv_tq);
- struct sk_buff *skb;
- actcapi_msg *msg;
- __u16 ccmd;
- int chan;
- int len;
- act2000_chan *ctmp;
- isdn_ctrl cmd;
- char tmp[170];
-
- while ((skb = skb_dequeue(&card->rcvq))) {
- actcapi_debug_msg(skb, 0);
- msg = (actcapi_msg *)skb->data;
- ccmd = ((msg->hdr.cmd.cmd << 8) | msg->hdr.cmd.subcmd);
- switch (ccmd) {
- case 0x8602:
- /* DATA_B3_IND */
- if (actcapi_data_b3_ind(card, skb))
- return;
- break;
- case 0x8601:
- /* DATA_B3_CONF */
- chan = find_ncci(card, msg->msg.data_b3_conf.ncci);
- if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_ACTIVE)) {
- if (msg->msg.data_b3_conf.info != 0)
- printk(KERN_WARNING "act2000: DATA_B3_CONF: %04x\n",
- msg->msg.data_b3_conf.info);
- len = handle_ack(card, &card->bch[chan],
- msg->msg.data_b3_conf.blocknr);
- if (len) {
- cmd.driver = card->myid;
- cmd.command = ISDN_STAT_BSENT;
- cmd.arg = chan;
- cmd.parm.length = len;
- card->interface.statcallb(&cmd);
- }
- }
- break;
- case 0x0201:
- /* CONNECT_CONF */
- chan = find_dialing(card, msg->hdr.msgnum);
- if (chan >= 0) {
- if (msg->msg.connect_conf.info) {
- card->bch[chan].fsm_state = ACT2000_STATE_NULL;
- cmd.driver = card->myid;
- cmd.command = ISDN_STAT_DHUP;
- cmd.arg = chan;
- card->interface.statcallb(&cmd);
- } else {
- card->bch[chan].fsm_state = ACT2000_STATE_OWAIT;
- card->bch[chan].plci = msg->msg.connect_conf.plci;
- }
- }
- break;
- case 0x0202:
- /* CONNECT_IND */
- chan = new_plci(card, msg->msg.connect_ind.plci);
- if (chan < 0) {
- ctmp = (act2000_chan *)tmp;
- ctmp->plci = msg->msg.connect_ind.plci;
- actcapi_connect_resp(card, ctmp, 0x11); /* All Card-Cannels busy */
- } else {
- card->bch[chan].fsm_state = ACT2000_STATE_ICALL;
- cmd.driver = card->myid;
- cmd.command = ISDN_STAT_ICALL;
- cmd.arg = chan;
- cmd.parm.setup.si1 = msg->msg.connect_ind.si1;
- cmd.parm.setup.si2 = msg->msg.connect_ind.si2;
- if (card->ptype == ISDN_PTYPE_EURO)
- strcpy(cmd.parm.setup.eazmsn,
- act2000_find_eaz(card, msg->msg.connect_ind.eaz));
- else {
- cmd.parm.setup.eazmsn[0] = msg->msg.connect_ind.eaz;
- cmd.parm.setup.eazmsn[1] = 0;
- }
- memset(cmd.parm.setup.phone, 0, sizeof(cmd.parm.setup.phone));
- memcpy(cmd.parm.setup.phone, msg->msg.connect_ind.addr.num,
- msg->msg.connect_ind.addr.len - 1);
- cmd.parm.setup.plan = msg->msg.connect_ind.addr.tnp;
- cmd.parm.setup.screen = 0;
- if (card->interface.statcallb(&cmd) == 2)
- actcapi_connect_resp(card, &card->bch[chan], 0x15); /* Reject Call */
- }
- break;
- case 0x0302:
- /* CONNECT_ACTIVE_IND */
- chan = find_plci(card, msg->msg.connect_active_ind.plci);
- if (chan >= 0)
- switch (card->bch[chan].fsm_state) {
- case ACT2000_STATE_IWAIT:
- actcapi_connect_active_resp(card, &card->bch[chan]);
- break;
- case ACT2000_STATE_OWAIT:
- actcapi_connect_active_resp(card, &card->bch[chan]);
- actcapi_select_b2_protocol_req(card, &card->bch[chan]);
- break;
- }
- break;
- case 0x8202:
- /* CONNECT_B3_IND */
- chan = find_plci(card, msg->msg.connect_b3_ind.plci);
- if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_IBWAIT)) {
- card->bch[chan].ncci = msg->msg.connect_b3_ind.ncci;
- actcapi_connect_b3_resp(card, &card->bch[chan], 0);
- } else {
- ctmp = (act2000_chan *)tmp;
- ctmp->ncci = msg->msg.connect_b3_ind.ncci;
- actcapi_connect_b3_resp(card, ctmp, 0x11); /* All Card-Cannels busy */
- }
- break;
- case 0x8302:
- /* CONNECT_B3_ACTIVE_IND */
- chan = find_ncci(card, msg->msg.connect_b3_active_ind.ncci);
- if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_BWAIT)) {
- actcapi_connect_b3_active_resp(card, &card->bch[chan]);
- cmd.driver = card->myid;
- cmd.command = ISDN_STAT_BCONN;
- cmd.arg = chan;
- card->interface.statcallb(&cmd);
- }
- break;
- case 0x8402:
- /* DISCONNECT_B3_IND */
- chan = find_ncci(card, msg->msg.disconnect_b3_ind.ncci);
- if (chan >= 0) {
- ctmp = &card->bch[chan];
- actcapi_disconnect_b3_resp(card, ctmp);
- switch (ctmp->fsm_state) {
- case ACT2000_STATE_ACTIVE:
- ctmp->fsm_state = ACT2000_STATE_DHWAIT2;
- cmd.driver = card->myid;
- cmd.command = ISDN_STAT_BHUP;
- cmd.arg = chan;
- card->interface.statcallb(&cmd);
- break;
- case ACT2000_STATE_BHWAIT2:
- actcapi_disconnect_req(card, ctmp);
- ctmp->fsm_state = ACT2000_STATE_DHWAIT;
- cmd.driver = card->myid;
- cmd.command = ISDN_STAT_BHUP;
- cmd.arg = chan;
- card->interface.statcallb(&cmd);
- break;
- }
- }
- break;
- case 0x0402:
- /* DISCONNECT_IND */
- chan = find_plci(card, msg->msg.disconnect_ind.plci);
- if (chan >= 0) {
- ctmp = &card->bch[chan];
- actcapi_disconnect_resp(card, ctmp);
- ctmp->fsm_state = ACT2000_STATE_NULL;
- cmd.driver = card->myid;
- cmd.command = ISDN_STAT_DHUP;
- cmd.arg = chan;
- card->interface.statcallb(&cmd);
- } else {
- ctmp = (act2000_chan *)tmp;
- ctmp->plci = msg->msg.disconnect_ind.plci;
- actcapi_disconnect_resp(card, ctmp);
- }
- break;
- case 0x4001:
- /* SELECT_B2_PROTOCOL_CONF */
- chan = find_plci(card, msg->msg.select_b2_protocol_conf.plci);
- if (chan >= 0)
- switch (card->bch[chan].fsm_state) {
- case ACT2000_STATE_ICALL:
- case ACT2000_STATE_OWAIT:
- ctmp = &card->bch[chan];
- if (msg->msg.select_b2_protocol_conf.info == 0)
- actcapi_select_b3_protocol_req(card, ctmp);
- else {
- ctmp->fsm_state = ACT2000_STATE_NULL;
- cmd.driver = card->myid;
- cmd.command = ISDN_STAT_DHUP;
- cmd.arg = chan;
- card->interface.statcallb(&cmd);
- }
- break;
- }
- break;
- case 0x8001:
- /* SELECT_B3_PROTOCOL_CONF */
- chan = find_plci(card, msg->msg.select_b3_protocol_conf.plci);
- if (chan >= 0)
- switch (card->bch[chan].fsm_state) {
- case ACT2000_STATE_ICALL:
- case ACT2000_STATE_OWAIT:
- ctmp = &card->bch[chan];
- if (msg->msg.select_b3_protocol_conf.info == 0)
- actcapi_listen_b3_req(card, ctmp);
- else {
- ctmp->fsm_state = ACT2000_STATE_NULL;
- cmd.driver = card->myid;
- cmd.command = ISDN_STAT_DHUP;
- cmd.arg = chan;
- card->interface.statcallb(&cmd);
- }
- }
- break;
- case 0x8101:
- /* LISTEN_B3_CONF */
- chan = find_plci(card, msg->msg.listen_b3_conf.plci);
- if (chan >= 0)
- switch (card->bch[chan].fsm_state) {
- case ACT2000_STATE_ICALL:
- ctmp = &card->bch[chan];
- if (msg->msg.listen_b3_conf.info == 0)
- actcapi_connect_resp(card, ctmp, 0);
- else {
- ctmp->fsm_state = ACT2000_STATE_NULL;
- cmd.driver = card->myid;
- cmd.command = ISDN_STAT_DHUP;
- cmd.arg = chan;
- card->interface.statcallb(&cmd);
- }
- break;
- case ACT2000_STATE_OWAIT:
- ctmp = &card->bch[chan];
- if (msg->msg.listen_b3_conf.info == 0) {
- actcapi_connect_b3_req(card, ctmp);
- ctmp->fsm_state = ACT2000_STATE_OBWAIT;
- cmd.driver = card->myid;
- cmd.command = ISDN_STAT_DCONN;
- cmd.arg = chan;
- card->interface.statcallb(&cmd);
- } else {
- ctmp->fsm_state = ACT2000_STATE_NULL;
- cmd.driver = card->myid;
- cmd.command = ISDN_STAT_DHUP;
- cmd.arg = chan;
- card->interface.statcallb(&cmd);
- }
- break;
- }
- break;
- case 0x8201:
- /* CONNECT_B3_CONF */
- chan = find_plci(card, msg->msg.connect_b3_conf.plci);
- if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_OBWAIT)) {
- ctmp = &card->bch[chan];
- if (msg->msg.connect_b3_conf.info) {
- ctmp->fsm_state = ACT2000_STATE_NULL;
- cmd.driver = card->myid;
- cmd.command = ISDN_STAT_DHUP;
- cmd.arg = chan;
- card->interface.statcallb(&cmd);
- } else {
- ctmp->ncci = msg->msg.connect_b3_conf.ncci;
- ctmp->fsm_state = ACT2000_STATE_BWAIT;
- }
- }
- break;
- case 0x8401:
- /* DISCONNECT_B3_CONF */
- chan = find_ncci(card, msg->msg.disconnect_b3_conf.ncci);
- if ((chan >= 0) && (card->bch[chan].fsm_state == ACT2000_STATE_BHWAIT))
- card->bch[chan].fsm_state = ACT2000_STATE_BHWAIT2;
- break;
- case 0x0702:
- /* INFO_IND */
- chan = find_plci(card, msg->msg.info_ind.plci);
- if (chan >= 0)
- /* TODO: Eval Charging info / cause */
- actcapi_info_resp(card, &card->bch[chan]);
- break;
- case 0x0401:
- /* LISTEN_CONF */
- case 0x0501:
- /* LISTEN_CONF */
- case 0xff01:
- /* MANUFACTURER_CONF */
- break;
- case 0xff02:
- /* MANUFACTURER_IND */
- if (msg->msg.manuf_msg == 3) {
- memset(tmp, 0, sizeof(tmp));
- strncpy(tmp,
- &msg->msg.manufacturer_ind_err.errstring,
- msg->hdr.len - 16);
- if (msg->msg.manufacturer_ind_err.errcode)
- printk(KERN_WARNING "act2000: %s\n", tmp);
- else {
- printk(KERN_DEBUG "act2000: %s\n", tmp);
- if ((!strncmp(tmp, "INFO: Trace buffer con", 22)) ||
- (!strncmp(tmp, "INFO: Compile Date/Tim", 22))) {
- card->flags |= ACT2000_FLAGS_RUNNING;
- cmd.command = ISDN_STAT_RUN;
- cmd.driver = card->myid;
- cmd.arg = 0;
- actcapi_manufacturer_req_net(card);
- actcapi_manufacturer_req_msn(card);
- actcapi_listen_req(card);
- card->interface.statcallb(&cmd);
- }
- }
- }
- break;
- default:
- printk(KERN_WARNING "act2000: UNHANDLED Message %04x\n", ccmd);
- break;
- }
- dev_kfree_skb(skb);
- }
-}
-
-#ifdef DEBUG_MSG
-static void
-actcapi_debug_caddr(actcapi_addr *addr)
-{
- char tmp[30];
-
- printk(KERN_DEBUG " Alen = %d\n", addr->len);
- if (addr->len > 0)
- printk(KERN_DEBUG " Atnp = 0x%02x\n", addr->tnp);
- if (addr->len > 1) {
- memset(tmp, 0, 30);
- memcpy(tmp, addr->num, addr->len - 1);
- printk(KERN_DEBUG " Anum = '%s'\n", tmp);
- }
-}
-
-static void
-actcapi_debug_ncpi(actcapi_ncpi *ncpi)
-{
- printk(KERN_DEBUG " ncpi.len = %d\n", ncpi->len);
- if (ncpi->len >= 2)
- printk(KERN_DEBUG " ncpi.lic = 0x%04x\n", ncpi->lic);
- if (ncpi->len >= 4)
- printk(KERN_DEBUG " ncpi.hic = 0x%04x\n", ncpi->hic);
- if (ncpi->len >= 6)
- printk(KERN_DEBUG " ncpi.ltc = 0x%04x\n", ncpi->ltc);
- if (ncpi->len >= 8)
- printk(KERN_DEBUG " ncpi.htc = 0x%04x\n", ncpi->htc);
- if (ncpi->len >= 10)
- printk(KERN_DEBUG " ncpi.loc = 0x%04x\n", ncpi->loc);
- if (ncpi->len >= 12)
- printk(KERN_DEBUG " ncpi.hoc = 0x%04x\n", ncpi->hoc);
- if (ncpi->len >= 13)
- printk(KERN_DEBUG " ncpi.mod = %d\n", ncpi->modulo);
-}
-
-static void
-actcapi_debug_dlpd(actcapi_dlpd *dlpd)
-{
- printk(KERN_DEBUG " dlpd.len = %d\n", dlpd->len);
- if (dlpd->len >= 2)
- printk(KERN_DEBUG " dlpd.dlen = 0x%04x\n", dlpd->dlen);
- if (dlpd->len >= 3)
- printk(KERN_DEBUG " dlpd.laa = 0x%02x\n", dlpd->laa);
- if (dlpd->len >= 4)
- printk(KERN_DEBUG " dlpd.lab = 0x%02x\n", dlpd->lab);
- if (dlpd->len >= 5)
- printk(KERN_DEBUG " dlpd.modulo = %d\n", dlpd->modulo);
- if (dlpd->len >= 6)
- printk(KERN_DEBUG " dlpd.win = %d\n", dlpd->win);
-}
-
-#ifdef DEBUG_DUMP_SKB
-static void dump_skb(struct sk_buff *skb)
-{
- char tmp[80];
- char *p = skb->data;
- char *t = tmp;
- int i;
-
- for (i = 0; i < skb->len; i++) {
- t += sprintf(t, "%02x ", *p++ & 0xff);
- if ((i & 0x0f) == 8) {
- printk(KERN_DEBUG "dump: %s\n", tmp);
- t = tmp;
- }
- }
- if (i & 0x07)
- printk(KERN_DEBUG "dump: %s\n", tmp);
-}
-#endif
-
-void
-actcapi_debug_msg(struct sk_buff *skb, int direction)
-{
- actcapi_msg *msg = (actcapi_msg *)skb->data;
- char *descr;
- int i;
- char tmp[170];
-
-#ifndef DEBUG_DATA_MSG
- if (msg->hdr.cmd.cmd == 0x86)
- return;
-#endif
- descr = "INVALID";
-#ifdef DEBUG_DUMP_SKB
- dump_skb(skb);
-#endif
- for (i = 0; i < ARRAY_SIZE(valid_msg); i++)
- if ((msg->hdr.cmd.cmd == valid_msg[i].cmd.cmd) &&
- (msg->hdr.cmd.subcmd == valid_msg[i].cmd.subcmd)) {
- descr = valid_msg[i].description;
- break;
- }
- printk(KERN_DEBUG "%s %s msg\n", direction ? "Outgoing" : "Incoming", descr);
- printk(KERN_DEBUG " ApplID = %d\n", msg->hdr.applicationID);
- printk(KERN_DEBUG " Len = %d\n", msg->hdr.len);
- printk(KERN_DEBUG " MsgNum = 0x%04x\n", msg->hdr.msgnum);
- printk(KERN_DEBUG " Cmd = 0x%02x\n", msg->hdr.cmd.cmd);
- printk(KERN_DEBUG " SubCmd = 0x%02x\n", msg->hdr.cmd.subcmd);
- switch (i) {
- case 0:
- /* DATA B3 IND */
- printk(KERN_DEBUG " BLOCK = 0x%02x\n",
- msg->msg.data_b3_ind.blocknr);
- break;
- case 2:
- /* CONNECT CONF */
- printk(KERN_DEBUG " PLCI = 0x%04x\n",
- msg->msg.connect_conf.plci);
- printk(KERN_DEBUG " Info = 0x%04x\n",
- msg->msg.connect_conf.info);
- break;
- case 3:
- /* CONNECT IND */
- printk(KERN_DEBUG " PLCI = 0x%04x\n",
- msg->msg.connect_ind.plci);
- printk(KERN_DEBUG " Contr = %d\n",
- msg->msg.connect_ind.controller);
- printk(KERN_DEBUG " SI1 = %d\n",
- msg->msg.connect_ind.si1);
- printk(KERN_DEBUG " SI2 = %d\n",
- msg->msg.connect_ind.si2);
- printk(KERN_DEBUG " EAZ = '%c'\n",
- msg->msg.connect_ind.eaz);
- actcapi_debug_caddr(&msg->msg.connect_ind.addr);
- break;
- case 5:
- /* CONNECT ACTIVE IND */
- printk(KERN_DEBUG " PLCI = 0x%04x\n",
- msg->msg.connect_active_ind.plci);
- actcapi_debug_caddr(&msg->msg.connect_active_ind.addr);
- break;
- case 8:
- /* LISTEN CONF */
- printk(KERN_DEBUG " Contr = %d\n",
- msg->msg.listen_conf.controller);
- printk(KERN_DEBUG " Info = 0x%04x\n",
- msg->msg.listen_conf.info);
- break;
- case 11:
- /* INFO IND */
- printk(KERN_DEBUG " PLCI = 0x%04x\n",
- msg->msg.info_ind.plci);
- printk(KERN_DEBUG " Imsk = 0x%04x\n",
- msg->msg.info_ind.nr.mask);
- if (msg->hdr.len > 12) {
- int l = msg->hdr.len - 12;
- int j;
- char *p = tmp;
-
- for (j = 0; j < l; j++)
- p += sprintf(p, "%02x ", msg->msg.info_ind.el.display[j]);
- printk(KERN_DEBUG " D = '%s'\n", tmp);
- }
- break;
- case 14:
- /* SELECT B2 PROTOCOL CONF */
- printk(KERN_DEBUG " PLCI = 0x%04x\n",
- msg->msg.select_b2_protocol_conf.plci);
- printk(KERN_DEBUG " Info = 0x%04x\n",
- msg->msg.select_b2_protocol_conf.info);
- break;
- case 15:
- /* SELECT B3 PROTOCOL CONF */
- printk(KERN_DEBUG " PLCI = 0x%04x\n",
- msg->msg.select_b3_protocol_conf.plci);
- printk(KERN_DEBUG " Info = 0x%04x\n",
- msg->msg.select_b3_protocol_conf.info);
- break;
- case 16:
- /* LISTEN B3 CONF */
- printk(KERN_DEBUG " PLCI = 0x%04x\n",
- msg->msg.listen_b3_conf.plci);
- printk(KERN_DEBUG " Info = 0x%04x\n",
- msg->msg.listen_b3_conf.info);
- break;
- case 18:
- /* CONNECT B3 IND */
- printk(KERN_DEBUG " NCCI = 0x%04x\n",
- msg->msg.connect_b3_ind.ncci);
- printk(KERN_DEBUG " PLCI = 0x%04x\n",
- msg->msg.connect_b3_ind.plci);
- actcapi_debug_ncpi(&msg->msg.connect_b3_ind.ncpi);
- break;
- case 19:
- /* CONNECT B3 ACTIVE IND */
- printk(KERN_DEBUG " NCCI = 0x%04x\n",
- msg->msg.connect_b3_active_ind.ncci);
- actcapi_debug_ncpi(&msg->msg.connect_b3_active_ind.ncpi);
- break;
- case 26:
- /* MANUFACTURER IND */
- printk(KERN_DEBUG " Mmsg = 0x%02x\n",
- msg->msg.manufacturer_ind_err.manuf_msg);
- switch (msg->msg.manufacturer_ind_err.manuf_msg) {
- case 3:
- printk(KERN_DEBUG " Contr = %d\n",
- msg->msg.manufacturer_ind_err.controller);
- printk(KERN_DEBUG " Code = 0x%08x\n",
- msg->msg.manufacturer_ind_err.errcode);
- memset(tmp, 0, sizeof(tmp));
- strncpy(tmp, &msg->msg.manufacturer_ind_err.errstring,
- msg->hdr.len - 16);
- printk(KERN_DEBUG " Emsg = '%s'\n", tmp);
- break;
- }
- break;
- case 30:
- /* LISTEN REQ */
- printk(KERN_DEBUG " Imsk = 0x%08x\n",
- msg->msg.listen_req.infomask);
- printk(KERN_DEBUG " Emsk = 0x%04x\n",
- msg->msg.listen_req.eazmask);
- printk(KERN_DEBUG " Smsk = 0x%04x\n",
- msg->msg.listen_req.simask);
- break;
- case 35:
- /* SELECT_B2_PROTOCOL_REQ */
- printk(KERN_DEBUG " PLCI = 0x%04x\n",
- msg->msg.select_b2_protocol_req.plci);
- printk(KERN_DEBUG " prot = 0x%02x\n",
- msg->msg.select_b2_protocol_req.protocol);
- if (msg->hdr.len >= 11)
- printk(KERN_DEBUG "No dlpd\n");
- else
- actcapi_debug_dlpd(&msg->msg.select_b2_protocol_req.dlpd);
- break;
- case 44:
- /* CONNECT RESP */
- printk(KERN_DEBUG " PLCI = 0x%04x\n",
- msg->msg.connect_resp.plci);
- printk(KERN_DEBUG " CAUSE = 0x%02x\n",
- msg->msg.connect_resp.rejectcause);
- break;
- case 45:
- /* CONNECT ACTIVE RESP */
- printk(KERN_DEBUG " PLCI = 0x%04x\n",
- msg->msg.connect_active_resp.plci);
- break;
- }
-}
-#endif
+++ /dev/null
-/* $Id: capi.h,v 1.6.6.2 2001/09/23 22:24:32 kai Exp $
- *
- * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
- *
- * Author Fritz Elfert
- * Copyright by Fritz Elfert <fritz@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * Thanks to Friedemann Baitinger and IBM Germany
- *
- */
-
-#ifndef CAPI_H
-#define CAPI_H
-
-/* Command-part of a CAPI message */
-typedef struct actcapi_msgcmd {
- __u8 cmd;
- __u8 subcmd;
-} actcapi_msgcmd;
-
-/* CAPI message header */
-typedef struct actcapi_msghdr {
- __u16 len;
- __u16 applicationID;
- actcapi_msgcmd cmd;
- __u16 msgnum;
-} actcapi_msghdr;
-
-/* CAPI message description (for debugging) */
-typedef struct actcapi_msgdsc {
- actcapi_msgcmd cmd;
- char *description;
-} actcapi_msgdsc;
-
-/* CAPI Address */
-typedef struct actcapi_addr {
- __u8 len; /* Length of element */
- __u8 tnp; /* Type/Numbering Plan */
- __u8 num[20]; /* Caller ID */
-} actcapi_addr;
-
-/* CAPI INFO element mask */
-typedef union actcapi_infonr { /* info number */
- __u16 mask; /* info-mask field */
- struct bmask { /* bit definitions */
- unsigned codes:3; /* code set */
- unsigned rsvd:5; /* reserved */
- unsigned svind:1; /* single, variable length ind. */
- unsigned wtype:7; /* W-element type */
- } bmask;
-} actcapi_infonr;
-
-/* CAPI INFO element */
-typedef union actcapi_infoel { /* info element */
- __u8 len; /* length of info element */
- __u8 display[40]; /* display contents */
- __u8 uuinfo[40]; /* User-user info field */
- struct cause { /* Cause information */
- unsigned ext2:1; /* extension */
- unsigned cod:2; /* coding standard */
- unsigned spare:1; /* spare */
- unsigned loc:4; /* location */
- unsigned ext1:1; /* extension */
- unsigned cval:7; /* Cause value */
- } cause;
- struct charge { /* Charging information */
- __u8 toc; /* type of charging info */
- __u8 unit[10]; /* charging units */
- } charge;
- __u8 date[20]; /* date fields */
- __u8 stat; /* state of remote party */
-} actcapi_infoel;
-
-/* Message for EAZ<->MSN Mapping */
-typedef struct actcapi_msn {
- __u8 eaz;
- __u8 len; /* Length of MSN */
- __u8 msn[15];
-} __attribute__((packed)) actcapi_msn;
-
-typedef struct actcapi_dlpd {
- __u8 len; /* Length of structure */
- __u16 dlen; /* Data Length */
- __u8 laa; /* Link Address A */
- __u8 lab; /* Link Address B */
- __u8 modulo; /* Modulo Mode */
- __u8 win; /* Window size */
- __u8 xid[100]; /* XID Information */
-} __attribute__((packed)) actcapi_dlpd;
-
-typedef struct actcapi_ncpd {
- __u8 len; /* Length of structure */
- __u16 lic;
- __u16 hic;
- __u16 ltc;
- __u16 htc;
- __u16 loc;
- __u16 hoc;
- __u8 modulo;
-} __attribute__((packed)) actcapi_ncpd;
-#define actcapi_ncpi actcapi_ncpd
-
-/*
- * Layout of NCCI field in a B3 DATA CAPI message is different from
- * standard at act2000:
- *
- * Bit 0-4 = PLCI
- * Bit 5-7 = Controller
- * Bit 8-15 = NCCI
- */
-#define MAKE_NCCI(plci, contr, ncci) \
- ((plci & 0x1f) | ((contr & 0x7) << 5) | ((ncci & 0xff) << 8))
-
-#define EVAL_NCCI(fakencci, plci, ncci) { \
- plci = fakencci & 0x1f; \
- ncci = (fakencci >> 8) & 0xff; \
- }
-
-/*
- * Layout of PLCI field in a B3 DATA CAPI message is different from
- * standard at act2000:
- *
- * Bit 0-4 = PLCI
- * Bit 5-7 = Controller
- * Bit 8-15 = reserved (must be 0)
- */
-
-typedef struct actcapi_msg {
- actcapi_msghdr hdr;
- union {
- __u16 manuf_msg;
- struct manufacturer_req_net {
- __u16 manuf_msg;
- __u16 controller;
- __u8 nettype;
- } manufacturer_req_net;
- struct manufacturer_req_v42 {
- __u16 manuf_msg;
- __u16 controller;
- __u32 v42control;
- } manufacturer_req_v42;
- struct manufacturer_conf_v42 {
- __u16 manuf_msg;
- __u16 controller;
- } manufacturer_conf_v42;
- struct manufacturer_req_err {
- __u16 manuf_msg;
- __u16 controller;
- } manufacturer_req_err;
- struct manufacturer_ind_err {
- __u16 manuf_msg;
- __u16 controller;
- __u32 errcode;
- __u8 errstring; /* actually up to 160 */
- } manufacturer_ind_err;
- struct manufacturer_req_msn {
- __u16 manuf_msg;
- __u16 controller;
- actcapi_msn msnmap;
- } __attribute ((packed)) manufacturer_req_msn;
- /* TODO: TraceInit-req/conf/ind/resp and
- * TraceDump-req/conf/ind/resp
- */
- struct connect_req {
- __u8 controller;
- __u8 bchan;
- __u32 infomask;
- __u8 si1;
- __u8 si2;
- __u8 eaz;
- actcapi_addr addr;
- } __attribute__ ((packed)) connect_req;
- struct connect_conf {
- __u16 plci;
- __u16 info;
- } connect_conf;
- struct connect_ind {
- __u16 plci;
- __u8 controller;
- __u8 si1;
- __u8 si2;
- __u8 eaz;
- actcapi_addr addr;
- } __attribute__ ((packed)) connect_ind;
- struct connect_resp {
- __u16 plci;
- __u8 rejectcause;
- } connect_resp;
- struct connect_active_ind {
- __u16 plci;
- actcapi_addr addr;
- } __attribute__ ((packed)) connect_active_ind;
- struct connect_active_resp {
- __u16 plci;
- } connect_active_resp;
- struct connect_b3_req {
- __u16 plci;
- actcapi_ncpi ncpi;
- } __attribute__ ((packed)) connect_b3_req;
- struct connect_b3_conf {
- __u16 plci;
- __u16 ncci;
- __u16 info;
- } connect_b3_conf;
- struct connect_b3_ind {
- __u16 ncci;
- __u16 plci;
- actcapi_ncpi ncpi;
- } __attribute__ ((packed)) connect_b3_ind;
- struct connect_b3_resp {
- __u16 ncci;
- __u8 rejectcause;
- actcapi_ncpi ncpi;
- } __attribute__ ((packed)) connect_b3_resp;
- struct disconnect_req {
- __u16 plci;
- __u8 cause;
- } disconnect_req;
- struct disconnect_conf {
- __u16 plci;
- __u16 info;
- } disconnect_conf;
- struct disconnect_ind {
- __u16 plci;
- __u16 info;
- } disconnect_ind;
- struct disconnect_resp {
- __u16 plci;
- } disconnect_resp;
- struct connect_b3_active_ind {
- __u16 ncci;
- actcapi_ncpi ncpi;
- } __attribute__ ((packed)) connect_b3_active_ind;
- struct connect_b3_active_resp {
- __u16 ncci;
- } connect_b3_active_resp;
- struct disconnect_b3_req {
- __u16 ncci;
- actcapi_ncpi ncpi;
- } __attribute__ ((packed)) disconnect_b3_req;
- struct disconnect_b3_conf {
- __u16 ncci;
- __u16 info;
- } disconnect_b3_conf;
- struct disconnect_b3_ind {
- __u16 ncci;
- __u16 info;
- actcapi_ncpi ncpi;
- } __attribute__ ((packed)) disconnect_b3_ind;
- struct disconnect_b3_resp {
- __u16 ncci;
- } disconnect_b3_resp;
- struct info_ind {
- __u16 plci;
- actcapi_infonr nr;
- actcapi_infoel el;
- } __attribute__ ((packed)) info_ind;
- struct info_resp {
- __u16 plci;
- } info_resp;
- struct listen_b3_req {
- __u16 plci;
- } listen_b3_req;
- struct listen_b3_conf {
- __u16 plci;
- __u16 info;
- } listen_b3_conf;
- struct select_b2_protocol_req {
- __u16 plci;
- __u8 protocol;
- actcapi_dlpd dlpd;
- } __attribute__ ((packed)) select_b2_protocol_req;
- struct select_b2_protocol_conf {
- __u16 plci;
- __u16 info;
- } select_b2_protocol_conf;
- struct select_b3_protocol_req {
- __u16 plci;
- __u8 protocol;
- actcapi_ncpd ncpd;
- } __attribute__ ((packed)) select_b3_protocol_req;
- struct select_b3_protocol_conf {
- __u16 plci;
- __u16 info;
- } select_b3_protocol_conf;
- struct listen_req {
- __u8 controller;
- __u32 infomask;
- __u16 eazmask;
- __u16 simask;
- } __attribute__ ((packed)) listen_req;
- struct listen_conf {
- __u8 controller;
- __u16 info;
- } __attribute__ ((packed)) listen_conf;
- struct data_b3_req {
- __u16 fakencci;
- __u16 datalen;
- __u32 unused;
- __u8 blocknr;
- __u16 flags;
- } __attribute ((packed)) data_b3_req;
- struct data_b3_ind {
- __u16 fakencci;
- __u16 datalen;
- __u32 unused;
- __u8 blocknr;
- __u16 flags;
- } __attribute__ ((packed)) data_b3_ind;
- struct data_b3_resp {
- __u16 ncci;
- __u8 blocknr;
- } __attribute__ ((packed)) data_b3_resp;
- struct data_b3_conf {
- __u16 ncci;
- __u8 blocknr;
- __u16 info;
- } __attribute__ ((packed)) data_b3_conf;
- } msg;
-} __attribute__ ((packed)) actcapi_msg;
-
-static inline unsigned short
-actcapi_nextsmsg(act2000_card *card)
-{
- unsigned long flags;
- unsigned short n;
-
- spin_lock_irqsave(&card->mnlock, flags);
- n = card->msgnum;
- card->msgnum++;
- card->msgnum &= 0x7fff;
- spin_unlock_irqrestore(&card->mnlock, flags);
- return n;
-}
-#define DEBUG_MSG
-#undef DEBUG_DATA_MSG
-#undef DEBUG_DUMP_SKB
-
-extern int actcapi_chkhdr(act2000_card *, actcapi_msghdr *);
-extern int actcapi_listen_req(act2000_card *);
-extern int actcapi_manufacturer_req_net(act2000_card *);
-extern int actcapi_manufacturer_req_errh(act2000_card *);
-extern int actcapi_manufacturer_req_msn(act2000_card *);
-extern int actcapi_connect_req(act2000_card *, act2000_chan *, char *, char, int, int);
-extern void actcapi_select_b2_protocol_req(act2000_card *, act2000_chan *);
-extern void actcapi_disconnect_b3_req(act2000_card *, act2000_chan *);
-extern void actcapi_connect_resp(act2000_card *, act2000_chan *, __u8);
-extern void actcapi_dispatch(struct work_struct *);
-#ifdef DEBUG_MSG
-extern void actcapi_debug_msg(struct sk_buff *skb, int);
-#else
-#define actcapi_debug_msg(skb, len)
-#endif
-#endif
+++ /dev/null
-/* $Id: module.c,v 1.14.6.4 2001/09/23 22:24:32 kai Exp $
- *
- * ISDN lowlevel-module for the IBM ISDN-S0 Active 2000.
- *
- * Author Fritz Elfert
- * Copyright by Fritz Elfert <fritz@isdn4linux.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * Thanks to Friedemann Baitinger and IBM Germany
- *
- */
-
-#include "act2000.h"
-#include "act2000_isa.h"
-#include "capi.h"
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-
-static unsigned short act2000_isa_ports[] = {
- 0x0200, 0x0240, 0x0280, 0x02c0, 0x0300, 0x0340, 0x0380,
- 0xcfe0, 0xcfa0, 0xcf60, 0xcf20, 0xcee0, 0xcea0, 0xce60,
-};
-
-static act2000_card *cards = (act2000_card *) NULL;
-
-/* Parameters to be set by insmod */
-static int act_bus;
-static int act_port = -1; /* -1 = Autoprobe */
-static int act_irq = -1;
-static char *act_id = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
-
-MODULE_DESCRIPTION("ISDN4Linux: Driver for IBM Active 2000 ISDN card");
-MODULE_AUTHOR("Fritz Elfert");
-MODULE_LICENSE("GPL");
-MODULE_PARM_DESC(act_bus, "BusType of first card, 1=ISA, 2=MCA, 3=PCMCIA, currently only ISA");
-MODULE_PARM_DESC(act_port, "Base port address of first card");
-MODULE_PARM_DESC(act_irq, "IRQ of first card");
-MODULE_PARM_DESC(act_id, "ID-String of first card");
-module_param(act_bus, int, 0);
-module_param(act_port, int, 0);
-module_param(act_irq, int, 0);
-module_param(act_id, charp, 0);
-
-static int act2000_addcard(int, int, int, char *);
-
-static act2000_chan *
-find_channel(act2000_card *card, int channel)
-{
- if ((channel >= 0) && (channel < ACT2000_BCH))
- return &(card->bch[channel]);
- printk(KERN_WARNING "act2000: Invalid channel %d\n", channel);
- return NULL;
-}
-
-/*
- * Free MSN list
- */
-static void
-act2000_clear_msn(act2000_card *card)
-{
- struct msn_entry *p = card->msn_list;
- struct msn_entry *q;
- unsigned long flags;
-
- spin_lock_irqsave(&card->lock, flags);
- card->msn_list = NULL;
- spin_unlock_irqrestore(&card->lock, flags);
- while (p) {
- q = p->next;
- kfree(p);
- p = q;
- }
-}
-
-/*
- * Find an MSN entry in the list.
- * If ia5 != 0, return IA5-encoded EAZ, else
- * return a bitmask with corresponding bit set.
- */
-static __u16
-act2000_find_msn(act2000_card *card, char *msn, int ia5)
-{
- struct msn_entry *p = card->msn_list;
- __u8 eaz = '0';
-
- while (p) {
- if (!strcmp(p->msn, msn)) {
- eaz = p->eaz;
- break;
- }
- p = p->next;
- }
- if (!ia5)
- return 1 << (eaz - '0');
- else
- return eaz;
-}
-
-/*
- * Find an EAZ entry in the list.
- * return a string with corresponding msn.
- */
-char *
-act2000_find_eaz(act2000_card *card, char eaz)
-{
- struct msn_entry *p = card->msn_list;
-
- while (p) {
- if (p->eaz == eaz)
- return p->msn;
- p = p->next;
- }
- return "\0";
-}
-
-/*
- * Add or delete an MSN to the MSN list
- *
- * First character of msneaz is EAZ, rest is MSN.
- * If length of eazmsn is 1, delete that entry.
- */
-static int
-act2000_set_msn(act2000_card *card, char *eazmsn)
-{
- struct msn_entry *p = card->msn_list;
- struct msn_entry *q = NULL;
- unsigned long flags;
- int i;
-
- if (!strlen(eazmsn))
- return 0;
- if (strlen(eazmsn) > 16)
- return -EINVAL;
- for (i = 0; i < strlen(eazmsn); i++)
- if (!isdigit(eazmsn[i]))
- return -EINVAL;
- if (strlen(eazmsn) == 1) {
- /* Delete a single MSN */
- while (p) {
- if (p->eaz == eazmsn[0]) {
- spin_lock_irqsave(&card->lock, flags);
- if (q)
- q->next = p->next;
- else
- card->msn_list = p->next;
- spin_unlock_irqrestore(&card->lock, flags);
- kfree(p);
- printk(KERN_DEBUG
- "Mapping for EAZ %c deleted\n",
- eazmsn[0]);
- return 0;
- }
- q = p;
- p = p->next;
- }
- return 0;
- }
- /* Add a single MSN */
- while (p) {
- /* Found in list, replace MSN */
- if (p->eaz == eazmsn[0]) {
- spin_lock_irqsave(&card->lock, flags);
- strcpy(p->msn, &eazmsn[1]);
- spin_unlock_irqrestore(&card->lock, flags);
- printk(KERN_DEBUG
- "Mapping for EAZ %c changed to %s\n",
- eazmsn[0],
- &eazmsn[1]);
- return 0;
- }
- p = p->next;
- }
- /* Not found in list, add new entry */
- p = kmalloc(sizeof(msn_entry), GFP_KERNEL);
- if (!p)
- return -ENOMEM;
- p->eaz = eazmsn[0];
- strcpy(p->msn, &eazmsn[1]);
- p->next = card->msn_list;
- spin_lock_irqsave(&card->lock, flags);
- card->msn_list = p;
- spin_unlock_irqrestore(&card->lock, flags);
- printk(KERN_DEBUG
- "Mapping %c -> %s added\n",
- eazmsn[0],
- &eazmsn[1]);
- return 0;
-}
-
-static void
-act2000_transmit(struct work_struct *work)
-{
- struct act2000_card *card =
- container_of(work, struct act2000_card, snd_tq);
-
- switch (card->bus) {
- case ACT2000_BUS_ISA:
- act2000_isa_send(card);
- break;
- case ACT2000_BUS_PCMCIA:
- case ACT2000_BUS_MCA:
- default:
- printk(KERN_WARNING
- "act2000_transmit: Illegal bustype %d\n", card->bus);
- }
-}
-
-static void
-act2000_receive(struct work_struct *work)
-{
- struct act2000_card *card =
- container_of(work, struct act2000_card, poll_tq);
-
- switch (card->bus) {
- case ACT2000_BUS_ISA:
- act2000_isa_receive(card);
- break;
- case ACT2000_BUS_PCMCIA:
- case ACT2000_BUS_MCA:
- default:
- printk(KERN_WARNING
- "act2000_receive: Illegal bustype %d\n", card->bus);
- }
-}
-
-static void
-act2000_poll(unsigned long data)
-{
- act2000_card *card = (act2000_card *)data;
- unsigned long flags;
-
- act2000_receive(&card->poll_tq);
- spin_lock_irqsave(&card->lock, flags);
- mod_timer(&card->ptimer, jiffies + 3);
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-static int
-act2000_command(act2000_card *card, isdn_ctrl *c)
-{
- ulong a;
- act2000_chan *chan;
- act2000_cdef cdef;
- isdn_ctrl cmd;
- char tmp[17];
- int ret;
- unsigned long flags;
- void __user *arg;
-
- switch (c->command) {
- case ISDN_CMD_IOCTL:
- memcpy(&a, c->parm.num, sizeof(ulong));
- arg = (void __user *)a;
- switch (c->arg) {
- case ACT2000_IOCTL_LOADBOOT:
- switch (card->bus) {
- case ACT2000_BUS_ISA:
- ret = act2000_isa_download(card,
- arg);
- if (!ret) {
- card->flags |= ACT2000_FLAGS_LOADED;
- if (!(card->flags & ACT2000_FLAGS_IVALID)) {
- card->ptimer.expires = jiffies + 3;
- card->ptimer.function = act2000_poll;
- card->ptimer.data = (unsigned long)card;
- add_timer(&card->ptimer);
- }
- actcapi_manufacturer_req_errh(card);
- }
- break;
- default:
- printk(KERN_WARNING
- "act2000: Illegal BUS type %d\n",
- card->bus);
- ret = -EIO;
- }
- return ret;
- case ACT2000_IOCTL_SETPROTO:
- card->ptype = a ? ISDN_PTYPE_EURO : ISDN_PTYPE_1TR6;
- if (!(card->flags & ACT2000_FLAGS_RUNNING))
- return 0;
- actcapi_manufacturer_req_net(card);
- return 0;
- case ACT2000_IOCTL_SETMSN:
- if (copy_from_user(tmp, arg,
- sizeof(tmp)))
- return -EFAULT;
- ret = act2000_set_msn(card, tmp);
- if (ret)
- return ret;
- if (card->flags & ACT2000_FLAGS_RUNNING)
- return actcapi_manufacturer_req_msn(card);
- return 0;
- case ACT2000_IOCTL_ADDCARD:
- if (copy_from_user(&cdef, arg,
- sizeof(cdef)))
- return -EFAULT;
- if (act2000_addcard(cdef.bus, cdef.port, cdef.irq, cdef.id))
- return -EIO;
- return 0;
- case ACT2000_IOCTL_TEST:
- if (!(card->flags & ACT2000_FLAGS_RUNNING))
- return -ENODEV;
- return 0;
- default:
- return -EINVAL;
- }
- break;
- case ISDN_CMD_DIAL:
- if (!(card->flags & ACT2000_FLAGS_RUNNING))
- return -ENODEV;
- if (!(chan = find_channel(card, c->arg & 0x0f)))
- break;
- spin_lock_irqsave(&card->lock, flags);
- if (chan->fsm_state != ACT2000_STATE_NULL) {
- spin_unlock_irqrestore(&card->lock, flags);
- printk(KERN_WARNING "Dial on channel with state %d\n",
- chan->fsm_state);
- return -EBUSY;
- }
- if (card->ptype == ISDN_PTYPE_EURO)
- tmp[0] = act2000_find_msn(card, c->parm.setup.eazmsn, 1);
- else
- tmp[0] = c->parm.setup.eazmsn[0];
- chan->fsm_state = ACT2000_STATE_OCALL;
- chan->callref = 0xffff;
- spin_unlock_irqrestore(&card->lock, flags);
- ret = actcapi_connect_req(card, chan, c->parm.setup.phone,
- tmp[0], c->parm.setup.si1,
- c->parm.setup.si2);
- if (ret) {
- cmd.driver = card->myid;
- cmd.command = ISDN_STAT_DHUP;
- cmd.arg &= 0x0f;
- card->interface.statcallb(&cmd);
- }
- return ret;
- case ISDN_CMD_ACCEPTD:
- if (!(card->flags & ACT2000_FLAGS_RUNNING))
- return -ENODEV;
- if (!(chan = find_channel(card, c->arg & 0x0f)))
- break;
- if (chan->fsm_state == ACT2000_STATE_ICALL)
- actcapi_select_b2_protocol_req(card, chan);
- return 0;
- case ISDN_CMD_ACCEPTB:
- if (!(card->flags & ACT2000_FLAGS_RUNNING))
- return -ENODEV;
- return 0;
- case ISDN_CMD_HANGUP:
- if (!(card->flags & ACT2000_FLAGS_RUNNING))
- return -ENODEV;
- if (!(chan = find_channel(card, c->arg & 0x0f)))
- break;
- switch (chan->fsm_state) {
- case ACT2000_STATE_ICALL:
- case ACT2000_STATE_BSETUP:
- actcapi_connect_resp(card, chan, 0x15);
- break;
- case ACT2000_STATE_ACTIVE:
- actcapi_disconnect_b3_req(card, chan);
- break;
- }
- return 0;
- case ISDN_CMD_SETEAZ:
- if (!(card->flags & ACT2000_FLAGS_RUNNING))
- return -ENODEV;
- if (!(chan = find_channel(card, c->arg & 0x0f)))
- break;
- if (strlen(c->parm.num)) {
- if (card->ptype == ISDN_PTYPE_EURO) {
- chan->eazmask = act2000_find_msn(card, c->parm.num, 0);
- }
- if (card->ptype == ISDN_PTYPE_1TR6) {
- int i;
-
- chan->eazmask = 0;
- for (i = 0; i < strlen(c->parm.num); i++)
- if (isdigit(c->parm.num[i]))
- chan->eazmask |= (1 << (c->parm.num[i] - '0'));
- }
- } else
- chan->eazmask = 0x3ff;
- actcapi_listen_req(card);
- return 0;
- case ISDN_CMD_CLREAZ:
- if (!(card->flags & ACT2000_FLAGS_RUNNING))
- return -ENODEV;
- if (!(chan = find_channel(card, c->arg & 0x0f)))
- break;
- chan->eazmask = 0;
- actcapi_listen_req(card);
- return 0;
- case ISDN_CMD_SETL2:
- if (!(card->flags & ACT2000_FLAGS_RUNNING))
- return -ENODEV;
- if (!(chan = find_channel(card, c->arg & 0x0f)))
- break;
- chan->l2prot = (c->arg >> 8);
- return 0;
- case ISDN_CMD_SETL3:
- if (!(card->flags & ACT2000_FLAGS_RUNNING))
- return -ENODEV;
- if ((c->arg >> 8) != ISDN_PROTO_L3_TRANS) {
- printk(KERN_WARNING "L3 protocol unknown\n");
- return -1;
- }
- if (!(chan = find_channel(card, c->arg & 0x0f)))
- break;
- chan->l3prot = (c->arg >> 8);
- return 0;
- }
-
- return -EINVAL;
-}
-
-static int
-act2000_sendbuf(act2000_card *card, int channel, int ack, struct sk_buff *skb)
-{
- struct sk_buff *xmit_skb;
- int len;
- act2000_chan *chan;
- actcapi_msg *msg;
-
- if (!(chan = find_channel(card, channel)))
- return -1;
- if (chan->fsm_state != ACT2000_STATE_ACTIVE)
- return -1;
- len = skb->len;
- if ((chan->queued + len) >= ACT2000_MAX_QUEUED)
- return 0;
- if (!len)
- return 0;
- if (skb_headroom(skb) < 19) {
- printk(KERN_WARNING "act2000_sendbuf: Headroom only %d\n",
- skb_headroom(skb));
- xmit_skb = alloc_skb(len + 19, GFP_ATOMIC);
- if (!xmit_skb) {
- printk(KERN_WARNING "act2000_sendbuf: Out of memory\n");
- return 0;
- }
- skb_reserve(xmit_skb, 19);
- skb_copy_from_linear_data(skb, skb_put(xmit_skb, len), len);
- } else {
- xmit_skb = skb_clone(skb, GFP_ATOMIC);
- if (!xmit_skb) {
- printk(KERN_WARNING "act2000_sendbuf: Out of memory\n");
- return 0;
- }
- }
- dev_kfree_skb(skb);
- msg = (actcapi_msg *)skb_push(xmit_skb, 19);
- msg->hdr.len = 19 + len;
- msg->hdr.applicationID = 1;
- msg->hdr.cmd.cmd = 0x86;
- msg->hdr.cmd.subcmd = 0x00;
- msg->hdr.msgnum = actcapi_nextsmsg(card);
- msg->msg.data_b3_req.datalen = len;
- msg->msg.data_b3_req.blocknr = (msg->hdr.msgnum & 0xff);
- msg->msg.data_b3_req.fakencci = MAKE_NCCI(chan->plci, 0, chan->ncci);
- msg->msg.data_b3_req.flags = ack; /* Will be set to 0 on actual sending */
- actcapi_debug_msg(xmit_skb, 1);
- chan->queued += len;
- skb_queue_tail(&card->sndq, xmit_skb);
- act2000_schedule_tx(card);
- return len;
-}
-
-
-/* Read the Status-replies from the Interface */
-static int
-act2000_readstatus(u_char __user *buf, int len, act2000_card *card)
-{
- int count;
- u_char __user *p;
-
- for (p = buf, count = 0; count < len; p++, count++) {
- if (card->status_buf_read == card->status_buf_write)
- return count;
- put_user(*card->status_buf_read++, p);
- if (card->status_buf_read > card->status_buf_end)
- card->status_buf_read = card->status_buf;
- }
- return count;
-}
-
-/*
- * Find card with given driverId
- */
-static inline act2000_card *
-act2000_findcard(int driverid)
-{
- act2000_card *p = cards;
-
- while (p) {
- if (p->myid == driverid)
- return p;
- p = p->next;
- }
- return (act2000_card *) 0;
-}
-
-/*
- * Wrapper functions for interface to linklevel
- */
-static int
-if_command(isdn_ctrl *c)
-{
- act2000_card *card = act2000_findcard(c->driver);
-
- if (card)
- return act2000_command(card, c);
- printk(KERN_ERR
- "act2000: if_command %d called with invalid driverId %d!\n",
- c->command, c->driver);
- return -ENODEV;
-}
-
-static int
-if_writecmd(const u_char __user *buf, int len, int id, int channel)
-{
- act2000_card *card = act2000_findcard(id);
-
- if (card) {
- if (!(card->flags & ACT2000_FLAGS_RUNNING))
- return -ENODEV;
- return len;
- }
- printk(KERN_ERR
- "act2000: if_writecmd called with invalid driverId!\n");
- return -ENODEV;
-}
-
-static int
-if_readstatus(u_char __user *buf, int len, int id, int channel)
-{
- act2000_card *card = act2000_findcard(id);
-
- if (card) {
- if (!(card->flags & ACT2000_FLAGS_RUNNING))
- return -ENODEV;
- return act2000_readstatus(buf, len, card);
- }
- printk(KERN_ERR
- "act2000: if_readstatus called with invalid driverId!\n");
- return -ENODEV;
-}
-
-static int
-if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
-{
- act2000_card *card = act2000_findcard(id);
-
- if (card) {
- if (!(card->flags & ACT2000_FLAGS_RUNNING))
- return -ENODEV;
- return act2000_sendbuf(card, channel, ack, skb);
- }
- printk(KERN_ERR
- "act2000: if_sendbuf called with invalid driverId!\n");
- return -ENODEV;
-}
-
-
-/*
- * Allocate a new card-struct, initialize it
- * link it into cards-list.
- */
-static void
-act2000_alloccard(int bus, int port, int irq, char *id)
-{
- int i;
- act2000_card *card;
-
- if (!(card = kzalloc(sizeof(act2000_card), GFP_KERNEL))) {
- printk(KERN_WARNING
- "act2000: (%s) Could not allocate card-struct.\n", id);
- return;
- }
- spin_lock_init(&card->lock);
- spin_lock_init(&card->mnlock);
- skb_queue_head_init(&card->sndq);
- skb_queue_head_init(&card->rcvq);
- skb_queue_head_init(&card->ackq);
- INIT_WORK(&card->snd_tq, act2000_transmit);
- INIT_WORK(&card->rcv_tq, actcapi_dispatch);
- INIT_WORK(&card->poll_tq, act2000_receive);
- init_timer(&card->ptimer);
- card->interface.owner = THIS_MODULE;
- card->interface.channels = ACT2000_BCH;
- card->interface.maxbufsize = 4000;
- card->interface.command = if_command;
- card->interface.writebuf_skb = if_sendbuf;
- card->interface.writecmd = if_writecmd;
- card->interface.readstat = if_readstatus;
- card->interface.features =
- ISDN_FEATURE_L2_X75I |
- ISDN_FEATURE_L2_HDLC |
- ISDN_FEATURE_L3_TRANS |
- ISDN_FEATURE_P_UNKNOWN;
- card->interface.hl_hdrlen = 20;
- card->ptype = ISDN_PTYPE_EURO;
- strlcpy(card->interface.id, id, sizeof(card->interface.id));
- for (i = 0; i < ACT2000_BCH; i++) {
- card->bch[i].plci = 0x8000;
- card->bch[i].ncci = 0x8000;
- card->bch[i].l2prot = ISDN_PROTO_L2_X75I;
- card->bch[i].l3prot = ISDN_PROTO_L3_TRANS;
- }
- card->myid = -1;
- card->bus = bus;
- card->port = port;
- card->irq = irq;
- card->next = cards;
- cards = card;
-}
-
-/*
- * register card at linklevel
- */
-static int
-act2000_registercard(act2000_card *card)
-{
- switch (card->bus) {
- case ACT2000_BUS_ISA:
- break;
- case ACT2000_BUS_MCA:
- case ACT2000_BUS_PCMCIA:
- default:
- printk(KERN_WARNING
- "act2000: Illegal BUS type %d\n",
- card->bus);
- return -1;
- }
- if (!register_isdn(&card->interface)) {
- printk(KERN_WARNING
- "act2000: Unable to register %s\n",
- card->interface.id);
- return -1;
- }
- card->myid = card->interface.channels;
- sprintf(card->regname, "act2000-isdn (%s)", card->interface.id);
- return 0;
-}
-
-static void
-unregister_card(act2000_card *card)
-{
- isdn_ctrl cmd;
-
- cmd.command = ISDN_STAT_UNLOAD;
- cmd.driver = card->myid;
- card->interface.statcallb(&cmd);
- switch (card->bus) {
- case ACT2000_BUS_ISA:
- act2000_isa_release(card);
- break;
- case ACT2000_BUS_MCA:
- case ACT2000_BUS_PCMCIA:
- default:
- printk(KERN_WARNING
- "act2000: Invalid BUS type %d\n",
- card->bus);
- break;
- }
-}
-
-static int
-act2000_addcard(int bus, int port, int irq, char *id)
-{
- act2000_card *p;
- act2000_card *q = NULL;
- int initialized;
- int added = 0;
- int failed = 0;
- int i;
-
- if (!bus)
- bus = ACT2000_BUS_ISA;
- if (port != -1) {
- /* Port defined, do fixed setup */
- act2000_alloccard(bus, port, irq, id);
- } else {
- /* No port defined, perform autoprobing.
- * This may result in more than one card detected.
- */
- switch (bus) {
- case ACT2000_BUS_ISA:
- for (i = 0; i < ARRAY_SIZE(act2000_isa_ports); i++)
- if (act2000_isa_detect(act2000_isa_ports[i])) {
- printk(KERN_INFO "act2000: Detected "
- "ISA card at port 0x%x\n",
- act2000_isa_ports[i]);
- act2000_alloccard(bus,
- act2000_isa_ports[i], irq, id);
- }
- break;
- case ACT2000_BUS_MCA:
- case ACT2000_BUS_PCMCIA:
- default:
- printk(KERN_WARNING
- "act2000: addcard: Invalid BUS type %d\n", bus);
- }
- }
- if (!cards)
- return 1;
- p = cards;
- while (p) {
- initialized = 0;
- if (!p->interface.statcallb) {
- /* Not yet registered.
- * Try to register and activate it.
- */
- added++;
- switch (p->bus) {
- case ACT2000_BUS_ISA:
- if (act2000_isa_detect(p->port)) {
- if (act2000_registercard(p))
- break;
- if (act2000_isa_config_port(p, p->port)) {
- printk(KERN_WARNING
- "act2000: Could not request port 0x%04x\n",
- p->port);
- unregister_card(p);
- p->interface.statcallb = NULL;
- break;
- }
- if (act2000_isa_config_irq(p, p->irq)) {
- printk(KERN_INFO
- "act2000: No IRQ available, fallback to polling\n");
- /* Fall back to polled operation */
- p->irq = 0;
- }
- printk(KERN_INFO
- "act2000: ISA"
- "-type card at port "
- "0x%04x ",
- p->port);
- if (p->irq)
- printk("irq %d\n", p->irq);
- else
- printk("polled\n");
- initialized = 1;
- }
- break;
- case ACT2000_BUS_MCA:
- case ACT2000_BUS_PCMCIA:
- default:
- printk(KERN_WARNING
- "act2000: addcard: Invalid BUS type %d\n",
- p->bus);
- }
- } else
- /* Card already initialized */
- initialized = 1;
- if (initialized) {
- /* Init OK, next card ... */
- q = p;
- p = p->next;
- } else {
- /* Init failed, remove card from list, free memory */
- printk(KERN_WARNING
- "act2000: Initialization of %s failed\n",
- p->interface.id);
- if (q) {
- q->next = p->next;
- kfree(p);
- p = q->next;
- } else {
- cards = p->next;
- kfree(p);
- p = cards;
- }
- failed++;
- }
- }
- return added - failed;
-}
-
-#define DRIVERNAME "IBM Active 2000 ISDN driver"
-
-static int __init act2000_init(void)
-{
- printk(KERN_INFO "%s\n", DRIVERNAME);
- if (!cards)
- act2000_addcard(act_bus, act_port, act_irq, act_id);
- if (!cards)
- printk(KERN_INFO "act2000: No cards defined yet\n");
- return 0;
-}
-
-static void __exit act2000_exit(void)
-{
- act2000_card *card = cards;
- act2000_card *last;
-
- while (card) {
- unregister_card(card);
- del_timer_sync(&card->ptimer);
- card = card->next;
- }
- card = cards;
- while (card) {
- last = card;
- card = card->next;
- act2000_clear_msn(last);
- kfree(last);
- }
- printk(KERN_INFO "%s unloaded\n", DRIVERNAME);
-}
-
-module_init(act2000_init);
-module_exit(act2000_exit);
+++ /dev/null
-config ISDN_DRV_ICN
- tristate "ICN 2B and 4B support"
- depends on ISA
- help
- This enables support for two kinds of ISDN-cards made by a German
- company called ICN. 2B is the standard version for a single ISDN
- line with two B-channels, 4B supports two ISDN lines. For running
- this card, additional firmware is necessary, which has to be
- downloaded into the card using a utility which is distributed
- separately. See <file:Documentation/isdn/README> and
- <file:Documentation/isdn/README.icn> for more
- information.
+++ /dev/null
-# Makefile for the icn ISDN device driver
-
-# Each configuration option enables a list of files.
-
-obj-$(CONFIG_ISDN_DRV_ICN) += icn.o
+++ /dev/null
-/* $Id: icn.c,v 1.65.6.8 2001/09/23 22:24:55 kai Exp $
- *
- * ISDN low-level module for the ICN active ISDN-Card.
- *
- * Copyright 1994,95,96 by Fritz Elfert (fritz@isdn4linux.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include "icn.h"
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-
-static int portbase = ICN_BASEADDR;
-static unsigned long membase = ICN_MEMADDR;
-static char *icn_id = "\0";
-static char *icn_id2 = "\0";
-
-MODULE_DESCRIPTION("ISDN4Linux: Driver for ICN active ISDN card");
-MODULE_AUTHOR("Fritz Elfert");
-MODULE_LICENSE("GPL");
-module_param(portbase, int, 0);
-MODULE_PARM_DESC(portbase, "Port address of first card");
-module_param(membase, ulong, 0);
-MODULE_PARM_DESC(membase, "Shared memory address of all cards");
-module_param(icn_id, charp, 0);
-MODULE_PARM_DESC(icn_id, "ID-String of first card");
-module_param(icn_id2, charp, 0);
-MODULE_PARM_DESC(icn_id2, "ID-String of first card, second S0 (4B only)");
-
-/*
- * Verbose bootcode- and protocol-downloading.
- */
-#undef BOOT_DEBUG
-
-/*
- * Verbose Shmem-Mapping.
- */
-#undef MAP_DEBUG
-
-static char
-*revision = "$Revision: 1.65.6.8 $";
-
-static int icn_addcard(int, char *, char *);
-
-/*
- * Free send-queue completely.
- * Parameter:
- * card = pointer to card struct
- * channel = channel number
- */
-static void
-icn_free_queue(icn_card *card, int channel)
-{
- struct sk_buff_head *queue = &card->spqueue[channel];
- struct sk_buff *skb;
-
- skb_queue_purge(queue);
- card->xlen[channel] = 0;
- card->sndcount[channel] = 0;
- skb = card->xskb[channel];
- if (skb) {
- card->xskb[channel] = NULL;
- dev_kfree_skb(skb);
- }
-}
-
-/* Put a value into a shift-register, highest bit first.
- * Parameters:
- * port = port for output (bit 0 is significant)
- * val = value to be output
- * firstbit = Bit-Number of highest bit
- * bitcount = Number of bits to output
- */
-static inline void
-icn_shiftout(unsigned short port,
- unsigned long val,
- int firstbit,
- int bitcount)
-{
- register u_char s;
- register u_char c;
-
- for (s = firstbit, c = bitcount; c > 0; s--, c--)
- OUTB_P((u_char)((val >> s) & 1) ? 0xff : 0, port);
-}
-
-/*
- * disable a cards shared memory
- */
-static inline void
-icn_disable_ram(icn_card *card)
-{
- OUTB_P(0, ICN_MAPRAM);
-}
-
-/*
- * enable a cards shared memory
- */
-static inline void
-icn_enable_ram(icn_card *card)
-{
- OUTB_P(0xff, ICN_MAPRAM);
-}
-
-/*
- * Map a cards channel0 (Bank0/Bank8) or channel1 (Bank4/Bank12)
- *
- * must called with holding the devlock
- */
-static inline void
-icn_map_channel(icn_card *card, int channel)
-{
-#ifdef MAP_DEBUG
- printk(KERN_DEBUG "icn_map_channel %d %d\n", dev.channel, channel);
-#endif
- if ((channel == dev.channel) && (card == dev.mcard))
- return;
- if (dev.mcard)
- icn_disable_ram(dev.mcard);
- icn_shiftout(ICN_BANK, chan2bank[channel], 3, 4); /* Select Bank */
- icn_enable_ram(card);
- dev.mcard = card;
- dev.channel = channel;
-#ifdef MAP_DEBUG
- printk(KERN_DEBUG "icn_map_channel done\n");
-#endif
-}
-
-/*
- * Lock a cards channel.
- * Return 0 if requested card/channel is unmapped (failure).
- * Return 1 on success.
- *
- * must called with holding the devlock
- */
-static inline int
-icn_lock_channel(icn_card *card, int channel)
-{
- register int retval;
-
-#ifdef MAP_DEBUG
- printk(KERN_DEBUG "icn_lock_channel %d\n", channel);
-#endif
- if ((dev.channel == channel) && (card == dev.mcard)) {
- dev.chanlock++;
- retval = 1;
-#ifdef MAP_DEBUG
- printk(KERN_DEBUG "icn_lock_channel %d OK\n", channel);
-#endif
- } else {
- retval = 0;
-#ifdef MAP_DEBUG
- printk(KERN_DEBUG "icn_lock_channel %d FAILED, dc=%d\n", channel, dev.channel);
-#endif
- }
- return retval;
-}
-
-/*
- * Release current card/channel lock
- *
- * must called with holding the devlock
- */
-static inline void
-__icn_release_channel(void)
-{
-#ifdef MAP_DEBUG
- printk(KERN_DEBUG "icn_release_channel l=%d\n", dev.chanlock);
-#endif
- if (dev.chanlock > 0)
- dev.chanlock--;
-}
-
-/*
- * Release current card/channel lock
- */
-static inline void
-icn_release_channel(void)
-{
- ulong flags;
-
- spin_lock_irqsave(&dev.devlock, flags);
- __icn_release_channel();
- spin_unlock_irqrestore(&dev.devlock, flags);
-}
-
-/*
- * Try to map and lock a cards channel.
- * Return 1 on success, 0 on failure.
- */
-static inline int
-icn_trymaplock_channel(icn_card *card, int channel)
-{
- ulong flags;
-
-#ifdef MAP_DEBUG
- printk(KERN_DEBUG "trymaplock c=%d dc=%d l=%d\n", channel, dev.channel,
- dev.chanlock);
-#endif
- spin_lock_irqsave(&dev.devlock, flags);
- if ((!dev.chanlock) ||
- ((dev.channel == channel) && (dev.mcard == card))) {
- dev.chanlock++;
- icn_map_channel(card, channel);
- spin_unlock_irqrestore(&dev.devlock, flags);
-#ifdef MAP_DEBUG
- printk(KERN_DEBUG "trymaplock %d OK\n", channel);
-#endif
- return 1;
- }
- spin_unlock_irqrestore(&dev.devlock, flags);
-#ifdef MAP_DEBUG
- printk(KERN_DEBUG "trymaplock %d FAILED\n", channel);
-#endif
- return 0;
-}
-
-/*
- * Release current card/channel lock,
- * then map same or other channel without locking.
- */
-static inline void
-icn_maprelease_channel(icn_card *card, int channel)
-{
- ulong flags;
-
-#ifdef MAP_DEBUG
- printk(KERN_DEBUG "map_release c=%d l=%d\n", channel, dev.chanlock);
-#endif
- spin_lock_irqsave(&dev.devlock, flags);
- if (dev.chanlock > 0)
- dev.chanlock--;
- if (!dev.chanlock)
- icn_map_channel(card, channel);
- spin_unlock_irqrestore(&dev.devlock, flags);
-}
-
-/* Get Data from the B-Channel, assemble fragmented packets and put them
- * into receive-queue. Wake up any B-Channel-reading processes.
- * This routine is called via timer-callback from icn_pollbchan().
- */
-
-static void
-icn_pollbchan_receive(int channel, icn_card *card)
-{
- int mch = channel + ((card->secondhalf) ? 2 : 0);
- int eflag;
- int cnt;
- struct sk_buff *skb;
-
- if (icn_trymaplock_channel(card, mch)) {
- while (rbavl) {
- cnt = readb(&rbuf_l);
- if ((card->rcvidx[channel] + cnt) > 4000) {
- printk(KERN_WARNING
- "icn: (%s) bogus packet on ch%d, dropping.\n",
- CID,
- channel + 1);
- card->rcvidx[channel] = 0;
- eflag = 0;
- } else {
- memcpy_fromio(&card->rcvbuf[channel][card->rcvidx[channel]],
- &rbuf_d, cnt);
- card->rcvidx[channel] += cnt;
- eflag = readb(&rbuf_f);
- }
- rbnext;
- icn_maprelease_channel(card, mch & 2);
- if (!eflag) {
- cnt = card->rcvidx[channel];
- if (cnt) {
- skb = dev_alloc_skb(cnt);
- if (!skb) {
- printk(KERN_WARNING "icn: receive out of memory\n");
- break;
- }
- memcpy(skb_put(skb, cnt), card->rcvbuf[channel], cnt);
- card->rcvidx[channel] = 0;
- card->interface.rcvcallb_skb(card->myid, channel, skb);
- }
- }
- if (!icn_trymaplock_channel(card, mch))
- break;
- }
- icn_maprelease_channel(card, mch & 2);
- }
-}
-
-/* Send data-packet to B-Channel, split it up into fragments of
- * ICN_FRAGSIZE length. If last fragment is sent out, signal
- * success to upper layers via statcallb with ISDN_STAT_BSENT argument.
- * This routine is called via timer-callback from icn_pollbchan() or
- * directly from icn_sendbuf().
- */
-
-static void
-icn_pollbchan_send(int channel, icn_card *card)
-{
- int mch = channel + ((card->secondhalf) ? 2 : 0);
- int cnt;
- unsigned long flags;
- struct sk_buff *skb;
- isdn_ctrl cmd;
-
- if (!(card->sndcount[channel] || card->xskb[channel] ||
- !skb_queue_empty(&card->spqueue[channel])))
- return;
- if (icn_trymaplock_channel(card, mch)) {
- while (sbfree &&
- (card->sndcount[channel] ||
- !skb_queue_empty(&card->spqueue[channel]) ||
- card->xskb[channel])) {
- spin_lock_irqsave(&card->lock, flags);
- if (card->xmit_lock[channel]) {
- spin_unlock_irqrestore(&card->lock, flags);
- break;
- }
- card->xmit_lock[channel]++;
- spin_unlock_irqrestore(&card->lock, flags);
- skb = card->xskb[channel];
- if (!skb) {
- skb = skb_dequeue(&card->spqueue[channel]);
- if (skb) {
- /* Pop ACK-flag off skb.
- * Store length to xlen.
- */
- if (*(skb_pull(skb, 1)))
- card->xlen[channel] = skb->len;
- else
- card->xlen[channel] = 0;
- }
- }
- if (!skb)
- break;
- if (skb->len > ICN_FRAGSIZE) {
- writeb(0xff, &sbuf_f);
- cnt = ICN_FRAGSIZE;
- } else {
- writeb(0x0, &sbuf_f);
- cnt = skb->len;
- }
- writeb(cnt, &sbuf_l);
- memcpy_toio(&sbuf_d, skb->data, cnt);
- skb_pull(skb, cnt);
- sbnext; /* switch to next buffer */
- icn_maprelease_channel(card, mch & 2);
- spin_lock_irqsave(&card->lock, flags);
- card->sndcount[channel] -= cnt;
- if (!skb->len) {
- if (card->xskb[channel])
- card->xskb[channel] = NULL;
- card->xmit_lock[channel] = 0;
- spin_unlock_irqrestore(&card->lock, flags);
- dev_kfree_skb(skb);
- if (card->xlen[channel]) {
- cmd.command = ISDN_STAT_BSENT;
- cmd.driver = card->myid;
- cmd.arg = channel;
- cmd.parm.length = card->xlen[channel];
- card->interface.statcallb(&cmd);
- }
- } else {
- card->xskb[channel] = skb;
- card->xmit_lock[channel] = 0;
- spin_unlock_irqrestore(&card->lock, flags);
- }
- if (!icn_trymaplock_channel(card, mch))
- break;
- }
- icn_maprelease_channel(card, mch & 2);
- }
-}
-
-/* Send/Receive Data to/from the B-Channel.
- * This routine is called via timer-callback.
- * It schedules itself while any B-Channel is open.
- */
-
-static void
-icn_pollbchan(unsigned long data)
-{
- icn_card *card = (icn_card *)data;
- unsigned long flags;
-
- if (card->flags & ICN_FLAGS_B1ACTIVE) {
- icn_pollbchan_receive(0, card);
- icn_pollbchan_send(0, card);
- }
- if (card->flags & ICN_FLAGS_B2ACTIVE) {
- icn_pollbchan_receive(1, card);
- icn_pollbchan_send(1, card);
- }
- if (card->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE)) {
- /* schedule b-channel polling again */
- spin_lock_irqsave(&card->lock, flags);
- mod_timer(&card->rb_timer, jiffies + ICN_TIMER_BCREAD);
- card->flags |= ICN_FLAGS_RBTIMER;
- spin_unlock_irqrestore(&card->lock, flags);
- } else
- card->flags &= ~ICN_FLAGS_RBTIMER;
-}
-
-typedef struct icn_stat {
- char *statstr;
- int command;
- int action;
-} icn_stat;
-/* *INDENT-OFF* */
-static icn_stat icn_stat_table[] = {
- {"BCON_", ISDN_STAT_BCONN, 1}, /* B-Channel connected */
- {"BDIS_", ISDN_STAT_BHUP, 2}, /* B-Channel disconnected */
- /*
- ** add d-channel connect and disconnect support to link-level
- */
- {"DCON_", ISDN_STAT_DCONN, 10}, /* D-Channel connected */
- {"DDIS_", ISDN_STAT_DHUP, 11}, /* D-Channel disconnected */
- {"DCAL_I", ISDN_STAT_ICALL, 3}, /* Incoming call dialup-line */
- {"DSCA_I", ISDN_STAT_ICALL, 3}, /* Incoming call 1TR6-SPV */
- {"FCALL", ISDN_STAT_ICALL, 4}, /* Leased line connection up */
- {"CIF", ISDN_STAT_CINF, 5}, /* Charge-info, 1TR6-type */
- {"AOC", ISDN_STAT_CINF, 6}, /* Charge-info, DSS1-type */
- {"CAU", ISDN_STAT_CAUSE, 7}, /* Cause code */
- {"TEI OK", ISDN_STAT_RUN, 0}, /* Card connected to wallplug */
- {"E_L1: ACT FAIL", ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */
- {"E_L2: DATA LIN", ISDN_STAT_BHUP, 8}, /* Layer-2 data link lost */
- {"E_L1: ACTIVATION FAILED",
- ISDN_STAT_BHUP, 8}, /* Layer-1 activation failed */
- {NULL, 0, -1}
-};
-/* *INDENT-ON* */
-
-
-/*
- * Check Statusqueue-Pointer from isdn-cards.
- * If there are new status-replies from the interface, check
- * them against B-Channel-connects/disconnects and set flags accordingly.
- * Wake-Up any processes, who are reading the status-device.
- * If there are B-Channels open, initiate a timer-callback to
- * icn_pollbchan().
- * This routine is called periodically via timer.
- */
-
-static void
-icn_parse_status(u_char *status, int channel, icn_card *card)
-{
- icn_stat *s = icn_stat_table;
- int action = -1;
- unsigned long flags;
- isdn_ctrl cmd;
-
- while (s->statstr) {
- if (!strncmp(status, s->statstr, strlen(s->statstr))) {
- cmd.command = s->command;
- action = s->action;
- break;
- }
- s++;
- }
- if (action == -1)
- return;
- cmd.driver = card->myid;
- cmd.arg = channel;
- switch (action) {
- case 11:
- spin_lock_irqsave(&card->lock, flags);
- icn_free_queue(card, channel);
- card->rcvidx[channel] = 0;
-
- if (card->flags &
- ((channel) ? ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE)) {
- isdn_ctrl ncmd;
-
- card->flags &= ~((channel) ?
- ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE);
-
- memset(&ncmd, 0, sizeof(ncmd));
-
- ncmd.driver = card->myid;
- ncmd.arg = channel;
- ncmd.command = ISDN_STAT_BHUP;
- spin_unlock_irqrestore(&card->lock, flags);
- card->interface.statcallb(&cmd);
- } else
- spin_unlock_irqrestore(&card->lock, flags);
- break;
- case 1:
- spin_lock_irqsave(&card->lock, flags);
- icn_free_queue(card, channel);
- card->flags |= (channel) ?
- ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE;
- spin_unlock_irqrestore(&card->lock, flags);
- break;
- case 2:
- spin_lock_irqsave(&card->lock, flags);
- card->flags &= ~((channel) ?
- ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE);
- icn_free_queue(card, channel);
- card->rcvidx[channel] = 0;
- spin_unlock_irqrestore(&card->lock, flags);
- break;
- case 3:
- {
- char *t = status + 6;
- char *s = strchr(t, ',');
-
- *s++ = '\0';
- strlcpy(cmd.parm.setup.phone, t,
- sizeof(cmd.parm.setup.phone));
- s = strchr(t = s, ',');
- *s++ = '\0';
- if (!strlen(t))
- cmd.parm.setup.si1 = 0;
- else
- cmd.parm.setup.si1 =
- simple_strtoul(t, NULL, 10);
- s = strchr(t = s, ',');
- *s++ = '\0';
- if (!strlen(t))
- cmd.parm.setup.si2 = 0;
- else
- cmd.parm.setup.si2 =
- simple_strtoul(t, NULL, 10);
- strlcpy(cmd.parm.setup.eazmsn, s,
- sizeof(cmd.parm.setup.eazmsn));
- }
- cmd.parm.setup.plan = 0;
- cmd.parm.setup.screen = 0;
- break;
- case 4:
- sprintf(cmd.parm.setup.phone, "LEASED%d", card->myid);
- sprintf(cmd.parm.setup.eazmsn, "%d", channel + 1);
- cmd.parm.setup.si1 = 7;
- cmd.parm.setup.si2 = 0;
- cmd.parm.setup.plan = 0;
- cmd.parm.setup.screen = 0;
- break;
- case 5:
- strlcpy(cmd.parm.num, status + 3, sizeof(cmd.parm.num));
- break;
- case 6:
- snprintf(cmd.parm.num, sizeof(cmd.parm.num), "%d",
- (int)simple_strtoul(status + 7, NULL, 16));
- break;
- case 7:
- status += 3;
- if (strlen(status) == 4)
- snprintf(cmd.parm.num, sizeof(cmd.parm.num), "%s%c%c",
- status + 2, *status, *(status + 1));
- else
- strlcpy(cmd.parm.num, status + 1, sizeof(cmd.parm.num));
- break;
- case 8:
- spin_lock_irqsave(&card->lock, flags);
- card->flags &= ~ICN_FLAGS_B1ACTIVE;
- icn_free_queue(card, 0);
- card->rcvidx[0] = 0;
- spin_unlock_irqrestore(&card->lock, flags);
- cmd.arg = 0;
- cmd.driver = card->myid;
- card->interface.statcallb(&cmd);
- cmd.command = ISDN_STAT_DHUP;
- cmd.arg = 0;
- cmd.driver = card->myid;
- card->interface.statcallb(&cmd);
- cmd.command = ISDN_STAT_BHUP;
- spin_lock_irqsave(&card->lock, flags);
- card->flags &= ~ICN_FLAGS_B2ACTIVE;
- icn_free_queue(card, 1);
- card->rcvidx[1] = 0;
- spin_unlock_irqrestore(&card->lock, flags);
- cmd.arg = 1;
- cmd.driver = card->myid;
- card->interface.statcallb(&cmd);
- cmd.command = ISDN_STAT_DHUP;
- cmd.arg = 1;
- cmd.driver = card->myid;
- break;
- }
- card->interface.statcallb(&cmd);
- return;
-}
-
-static void
-icn_putmsg(icn_card *card, unsigned char c)
-{
- ulong flags;
-
- spin_lock_irqsave(&card->lock, flags);
- *card->msg_buf_write++ = (c == 0xff) ? '\n' : c;
- if (card->msg_buf_write == card->msg_buf_read) {
- if (++card->msg_buf_read > card->msg_buf_end)
- card->msg_buf_read = card->msg_buf;
- }
- if (card->msg_buf_write > card->msg_buf_end)
- card->msg_buf_write = card->msg_buf;
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-static void
-icn_polldchan(unsigned long data)
-{
- icn_card *card = (icn_card *)data;
- int mch = card->secondhalf ? 2 : 0;
- int avail = 0;
- int left;
- u_char c;
- int ch;
- unsigned long flags;
- int i;
- u_char *p;
- isdn_ctrl cmd;
-
- if (icn_trymaplock_channel(card, mch)) {
- avail = msg_avail;
- for (left = avail, i = readb(&msg_o); left > 0; i++, left--) {
- c = readb(&dev.shmem->comm_buffers.iopc_buf[i & 0xff]);
- icn_putmsg(card, c);
- if (c == 0xff) {
- card->imsg[card->iptr] = 0;
- card->iptr = 0;
- if (card->imsg[0] == '0' && card->imsg[1] >= '0' &&
- card->imsg[1] <= '2' && card->imsg[2] == ';') {
- ch = (card->imsg[1] - '0') - 1;
- p = &card->imsg[3];
- icn_parse_status(p, ch, card);
- } else {
- p = card->imsg;
- if (!strncmp(p, "DRV1.", 5)) {
- u_char vstr[10];
- u_char *q = vstr;
-
- printk(KERN_INFO "icn: (%s) %s\n", CID, p);
- if (!strncmp(p + 7, "TC", 2)) {
- card->ptype = ISDN_PTYPE_1TR6;
- card->interface.features |= ISDN_FEATURE_P_1TR6;
- printk(KERN_INFO
- "icn: (%s) 1TR6-Protocol loaded and running\n", CID);
- }
- if (!strncmp(p + 7, "EC", 2)) {
- card->ptype = ISDN_PTYPE_EURO;
- card->interface.features |= ISDN_FEATURE_P_EURO;
- printk(KERN_INFO
- "icn: (%s) Euro-Protocol loaded and running\n", CID);
- }
- p = strstr(card->imsg, "BRV") + 3;
- while (*p) {
- if (*p >= '0' && *p <= '9')
- *q++ = *p;
- p++;
- }
- *q = '\0';
- strcat(vstr, "000");
- vstr[3] = '\0';
- card->fw_rev = (int)simple_strtoul(vstr, NULL, 10);
- continue;
- }
- }
- } else {
- card->imsg[card->iptr] = c;
- if (card->iptr < 59)
- card->iptr++;
- }
- }
- writeb((readb(&msg_o) + avail) & 0xff, &msg_o);
- icn_release_channel();
- }
- if (avail) {
- cmd.command = ISDN_STAT_STAVAIL;
- cmd.driver = card->myid;
- cmd.arg = avail;
- card->interface.statcallb(&cmd);
- }
- spin_lock_irqsave(&card->lock, flags);
- if (card->flags & (ICN_FLAGS_B1ACTIVE | ICN_FLAGS_B2ACTIVE))
- if (!(card->flags & ICN_FLAGS_RBTIMER)) {
- /* schedule b-channel polling */
- card->flags |= ICN_FLAGS_RBTIMER;
- del_timer(&card->rb_timer);
- card->rb_timer.function = icn_pollbchan;
- card->rb_timer.data = (unsigned long)card;
- card->rb_timer.expires = jiffies + ICN_TIMER_BCREAD;
- add_timer(&card->rb_timer);
- }
- /* schedule again */
- mod_timer(&card->st_timer, jiffies + ICN_TIMER_DCREAD);
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-/* Append a packet to the transmit buffer-queue.
- * Parameters:
- * channel = Number of B-channel
- * skb = pointer to sk_buff
- * card = pointer to card-struct
- * Return:
- * Number of bytes transferred, -E??? on error
- */
-
-static int
-icn_sendbuf(int channel, int ack, struct sk_buff *skb, icn_card *card)
-{
- int len = skb->len;
- unsigned long flags;
- struct sk_buff *nskb;
-
- if (len > 4000) {
- printk(KERN_WARNING
- "icn: Send packet too large\n");
- return -EINVAL;
- }
- if (len) {
- if (!(card->flags & (channel) ? ICN_FLAGS_B2ACTIVE : ICN_FLAGS_B1ACTIVE))
- return 0;
- if (card->sndcount[channel] > ICN_MAX_SQUEUE)
- return 0;
- /* TODO test headroom or use skb->nb to flag ACK */
- nskb = skb_clone(skb, GFP_ATOMIC);
- if (nskb) {
- /* Push ACK flag as one
- * byte in front of data.
- */
- *(skb_push(nskb, 1)) = ack ? 1 : 0;
- skb_queue_tail(&card->spqueue[channel], nskb);
- dev_kfree_skb(skb);
- } else
- len = 0;
- spin_lock_irqsave(&card->lock, flags);
- card->sndcount[channel] += len;
- spin_unlock_irqrestore(&card->lock, flags);
- }
- return len;
-}
-
-/*
- * Check card's status after starting the bootstrap loader.
- * On entry, the card's shared memory has already to be mapped.
- * Return:
- * 0 on success (Boot loader ready)
- * -EIO on failure (timeout)
- */
-static int
-icn_check_loader(int cardnumber)
-{
- int timer = 0;
-
- while (1) {
-#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Loader %d ?\n", cardnumber);
-#endif
- if (readb(&dev.shmem->data_control.scns) ||
- readb(&dev.shmem->data_control.scnr)) {
- if (timer++ > 5) {
- printk(KERN_WARNING
- "icn: Boot-Loader %d timed out.\n",
- cardnumber);
- icn_release_channel();
- return -EIO;
- }
-#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Loader %d TO?\n", cardnumber);
-#endif
- msleep_interruptible(ICN_BOOT_TIMEOUT1);
- } else {
-#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Loader %d OK\n", cardnumber);
-#endif
- icn_release_channel();
- return 0;
- }
- }
-}
-
-/* Load the boot-code into the interface-card's memory and start it.
- * Always called from user-process.
- *
- * Parameters:
- * buffer = pointer to packet
- * Return:
- * 0 if successfully loaded
- */
-
-#ifdef BOOT_DEBUG
-#define SLEEP(sec) { \
- int slsec = sec; \
- printk(KERN_DEBUG "SLEEP(%d)\n", slsec); \
- while (slsec) { \
- msleep_interruptible(1000); \
- slsec--; \
- } \
- }
-#else
-#define SLEEP(sec)
-#endif
-
-static int
-icn_loadboot(u_char __user *buffer, icn_card *card)
-{
- int ret;
- u_char *codebuf;
- unsigned long flags;
-
-#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "icn_loadboot called, buffaddr=%08lx\n", (ulong)buffer);
-#endif
- codebuf = memdup_user(buffer, ICN_CODE_STAGE1);
- if (IS_ERR(codebuf))
- return PTR_ERR(codebuf);
-
- if (!card->rvalid) {
- if (!request_region(card->port, ICN_PORTLEN, card->regname)) {
- printk(KERN_WARNING
- "icn: (%s) ports 0x%03x-0x%03x in use.\n",
- CID,
- card->port,
- card->port + ICN_PORTLEN);
- ret = -EBUSY;
- goto out_kfree;
- }
- card->rvalid = 1;
- if (card->doubleS0)
- card->other->rvalid = 1;
- }
- if (!dev.mvalid) {
- if (!request_mem_region(dev.memaddr, 0x4000, "icn-isdn (all cards)")) {
- printk(KERN_WARNING
- "icn: memory at 0x%08lx in use.\n", dev.memaddr);
- ret = -EBUSY;
- goto out_kfree;
- }
- dev.shmem = ioremap(dev.memaddr, 0x4000);
- dev.mvalid = 1;
- }
- OUTB_P(0, ICN_RUN); /* Reset Controller */
- OUTB_P(0, ICN_MAPRAM); /* Disable RAM */
- icn_shiftout(ICN_CFG, 0x0f, 3, 4); /* Windowsize= 16k */
- icn_shiftout(ICN_CFG, dev.memaddr, 23, 10); /* Set RAM-Addr. */
-#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "shmem=%08lx\n", dev.memaddr);
-#endif
- SLEEP(1);
-#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Map Bank 0\n");
-#endif
- spin_lock_irqsave(&dev.devlock, flags);
- icn_map_channel(card, 0); /* Select Bank 0 */
- icn_lock_channel(card, 0); /* Lock Bank 0 */
- spin_unlock_irqrestore(&dev.devlock, flags);
- SLEEP(1);
- memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1); /* Copy code */
-#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Bootloader transferred\n");
-#endif
- if (card->doubleS0) {
- SLEEP(1);
-#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Map Bank 8\n");
-#endif
- spin_lock_irqsave(&dev.devlock, flags);
- __icn_release_channel();
- icn_map_channel(card, 2); /* Select Bank 8 */
- icn_lock_channel(card, 2); /* Lock Bank 8 */
- spin_unlock_irqrestore(&dev.devlock, flags);
- SLEEP(1);
- memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1); /* Copy code */
-#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Bootloader transferred\n");
-#endif
- }
- SLEEP(1);
- OUTB_P(0xff, ICN_RUN); /* Start Boot-Code */
- ret = icn_check_loader(card->doubleS0 ? 2 : 1);
- if (ret)
- goto out_kfree;
- if (!card->doubleS0) {
- ret = 0;
- goto out_kfree;
- }
- /* reached only, if we have a Double-S0-Card */
-#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Map Bank 0\n");
-#endif
- spin_lock_irqsave(&dev.devlock, flags);
- icn_map_channel(card, 0); /* Select Bank 0 */
- icn_lock_channel(card, 0); /* Lock Bank 0 */
- spin_unlock_irqrestore(&dev.devlock, flags);
- SLEEP(1);
- ret = (icn_check_loader(1));
-
-out_kfree:
- kfree(codebuf);
- return ret;
-}
-
-static int
-icn_loadproto(u_char __user *buffer, icn_card *card)
-{
- register u_char __user *p = buffer;
- u_char codebuf[256];
- uint left = ICN_CODE_STAGE2;
- uint cnt;
- int timer;
- unsigned long flags;
-
-#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "icn_loadproto called\n");
-#endif
- if (!access_ok(VERIFY_READ, buffer, ICN_CODE_STAGE2))
- return -EFAULT;
- timer = 0;
- spin_lock_irqsave(&dev.devlock, flags);
- if (card->secondhalf) {
- icn_map_channel(card, 2);
- icn_lock_channel(card, 2);
- } else {
- icn_map_channel(card, 0);
- icn_lock_channel(card, 0);
- }
- spin_unlock_irqrestore(&dev.devlock, flags);
- while (left) {
- if (sbfree) { /* If there is a free buffer... */
- cnt = left;
- if (cnt > 256)
- cnt = 256;
- if (copy_from_user(codebuf, p, cnt)) {
- icn_maprelease_channel(card, 0);
- return -EFAULT;
- }
- memcpy_toio(&sbuf_l, codebuf, cnt); /* copy data */
- sbnext; /* switch to next buffer */
- p += cnt;
- left -= cnt;
- timer = 0;
- } else {
-#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "boot 2 !sbfree\n");
-#endif
- if (timer++ > 5) {
- icn_maprelease_channel(card, 0);
- return -EIO;
- }
- schedule_timeout_interruptible(10);
- }
- }
- writeb(0x20, &sbuf_n);
- timer = 0;
- while (1) {
- if (readb(&cmd_o) || readb(&cmd_i)) {
-#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Proto?\n");
-#endif
- if (timer++ > 5) {
- printk(KERN_WARNING
- "icn: (%s) Protocol timed out.\n",
- CID);
-#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Proto TO!\n");
-#endif
- icn_maprelease_channel(card, 0);
- return -EIO;
- }
-#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Proto TO?\n");
-#endif
- msleep_interruptible(ICN_BOOT_TIMEOUT1);
- } else {
- if ((card->secondhalf) || (!card->doubleS0)) {
-#ifdef BOOT_DEBUG
- printk(KERN_DEBUG "Proto loaded, install poll-timer %d\n",
- card->secondhalf);
-#endif
- spin_lock_irqsave(&card->lock, flags);
- setup_timer(&card->st_timer, icn_polldchan,
- (unsigned long)card);
- mod_timer(&card->st_timer,
- jiffies + ICN_TIMER_DCREAD);
- card->flags |= ICN_FLAGS_RUNNING;
- if (card->doubleS0) {
- setup_timer(&card->other->st_timer,
- icn_polldchan,
- (unsigned long)card->other);
- mod_timer(&card->other->st_timer,
- jiffies + ICN_TIMER_DCREAD);
- card->other->flags |= ICN_FLAGS_RUNNING;
- }
- spin_unlock_irqrestore(&card->lock, flags);
- }
- icn_maprelease_channel(card, 0);
- return 0;
- }
- }
-}
-
-/* Read the Status-replies from the Interface */
-static int
-icn_readstatus(u_char __user *buf, int len, icn_card *card)
-{
- int count;
- u_char __user *p;
-
- for (p = buf, count = 0; count < len; p++, count++) {
- if (card->msg_buf_read == card->msg_buf_write)
- return count;
- if (put_user(*card->msg_buf_read++, p))
- return -EFAULT;
- if (card->msg_buf_read > card->msg_buf_end)
- card->msg_buf_read = card->msg_buf;
- }
- return count;
-}
-
-/* Put command-strings into the command-queue of the Interface */
-static int
-icn_writecmd(const u_char __user *ubuf, const u_char *kbuf, int len,
- int user, icn_card *card)
-{
- int mch = card->secondhalf ? 2 : 0;
- int pp;
- int i;
- int count;
- int xcount;
- int ocount;
- int loop;
- unsigned long flags;
- int lastmap_channel;
- struct icn_card *lastmap_card;
- u_char *p;
- isdn_ctrl cmd;
- u_char msg[0x100];
-
- ocount = 1;
- xcount = loop = 0;
- while (len) {
- count = cmd_free;
- if (count > len)
- count = len;
- if (user) {
- if (copy_from_user(msg, ubuf, count))
- return -EFAULT;
- } else
- memcpy(msg, kbuf, count);
-
- spin_lock_irqsave(&dev.devlock, flags);
- lastmap_card = dev.mcard;
- lastmap_channel = dev.channel;
- icn_map_channel(card, mch);
-
- icn_putmsg(card, '>');
- for (p = msg, pp = readb(&cmd_i), i = count; i > 0; i--, p++, pp
- ++) {
- writeb((*p == '\n') ? 0xff : *p,
- &dev.shmem->comm_buffers.pcio_buf[pp & 0xff]);
- len--;
- xcount++;
- icn_putmsg(card, *p);
- if ((*p == '\n') && (i > 1)) {
- icn_putmsg(card, '>');
- ocount++;
- }
- ocount++;
- }
- writeb((readb(&cmd_i) + count) & 0xff, &cmd_i);
- if (lastmap_card)
- icn_map_channel(lastmap_card, lastmap_channel);
- spin_unlock_irqrestore(&dev.devlock, flags);
- if (len) {
- mdelay(1);
- if (loop++ > 20)
- break;
- } else
- break;
- }
- if (len && (!user))
- printk(KERN_WARNING "icn: writemsg incomplete!\n");
- cmd.command = ISDN_STAT_STAVAIL;
- cmd.driver = card->myid;
- cmd.arg = ocount;
- card->interface.statcallb(&cmd);
- return xcount;
-}
-
-/*
- * Delete card's pending timers, send STOP to linklevel
- */
-static void
-icn_stopcard(icn_card *card)
-{
- unsigned long flags;
- isdn_ctrl cmd;
-
- spin_lock_irqsave(&card->lock, flags);
- if (card->flags & ICN_FLAGS_RUNNING) {
- card->flags &= ~ICN_FLAGS_RUNNING;
- del_timer(&card->st_timer);
- del_timer(&card->rb_timer);
- spin_unlock_irqrestore(&card->lock, flags);
- cmd.command = ISDN_STAT_STOP;
- cmd.driver = card->myid;
- card->interface.statcallb(&cmd);
- if (card->doubleS0)
- icn_stopcard(card->other);
- } else
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-static void
-icn_stopallcards(void)
-{
- icn_card *p = cards;
-
- while (p) {
- icn_stopcard(p);
- p = p->next;
- }
-}
-
-/*
- * Unmap all cards, because some of them may be mapped accidetly during
- * autoprobing of some network drivers (SMC-driver?)
- */
-static void
-icn_disable_cards(void)
-{
- icn_card *card = cards;
-
- while (card) {
- if (!request_region(card->port, ICN_PORTLEN, "icn-isdn")) {
- printk(KERN_WARNING
- "icn: (%s) ports 0x%03x-0x%03x in use.\n",
- CID,
- card->port,
- card->port + ICN_PORTLEN);
- } else {
- OUTB_P(0, ICN_RUN); /* Reset Controller */
- OUTB_P(0, ICN_MAPRAM); /* Disable RAM */
- release_region(card->port, ICN_PORTLEN);
- }
- card = card->next;
- }
-}
-
-static int
-icn_command(isdn_ctrl *c, icn_card *card)
-{
- ulong a;
- ulong flags;
- int i;
- char cbuf[80];
- isdn_ctrl cmd;
- icn_cdef cdef;
- char __user *arg;
-
- switch (c->command) {
- case ISDN_CMD_IOCTL:
- memcpy(&a, c->parm.num, sizeof(ulong));
- arg = (char __user *)a;
- switch (c->arg) {
- case ICN_IOCTL_SETMMIO:
- if (dev.memaddr != (a & 0x0ffc000)) {
- if (!request_mem_region(a & 0x0ffc000, 0x4000, "icn-isdn (all cards)")) {
- printk(KERN_WARNING
- "icn: memory at 0x%08lx in use.\n",
- a & 0x0ffc000);
- return -EINVAL;
- }
- release_mem_region(a & 0x0ffc000, 0x4000);
- icn_stopallcards();
- spin_lock_irqsave(&card->lock, flags);
- if (dev.mvalid) {
- iounmap(dev.shmem);
- release_mem_region(dev.memaddr, 0x4000);
- }
- dev.mvalid = 0;
- dev.memaddr = a & 0x0ffc000;
- spin_unlock_irqrestore(&card->lock, flags);
- printk(KERN_INFO
- "icn: (%s) mmio set to 0x%08lx\n",
- CID,
- dev.memaddr);
- }
- break;
- case ICN_IOCTL_GETMMIO:
- return (long)dev.memaddr;
- case ICN_IOCTL_SETPORT:
- if (a == 0x300 || a == 0x310 || a == 0x320 || a == 0x330
- || a == 0x340 || a == 0x350 || a == 0x360 ||
- a == 0x308 || a == 0x318 || a == 0x328 || a == 0x338
- || a == 0x348 || a == 0x358 || a == 0x368) {
- if (card->port != (unsigned short)a) {
- if (!request_region((unsigned short)a, ICN_PORTLEN, "icn-isdn")) {
- printk(KERN_WARNING
- "icn: (%s) ports 0x%03x-0x%03x in use.\n",
- CID, (int)a, (int)a + ICN_PORTLEN);
- return -EINVAL;
- }
- release_region((unsigned short)a, ICN_PORTLEN);
- icn_stopcard(card);
- spin_lock_irqsave(&card->lock, flags);
- if (card->rvalid)
- release_region(card->port, ICN_PORTLEN);
- card->port = (unsigned short)a;
- card->rvalid = 0;
- if (card->doubleS0) {
- card->other->port = (unsigned short)a;
- card->other->rvalid = 0;
- }
- spin_unlock_irqrestore(&card->lock, flags);
- printk(KERN_INFO
- "icn: (%s) port set to 0x%03x\n",
- CID, card->port);
- }
- } else
- return -EINVAL;
- break;
- case ICN_IOCTL_GETPORT:
- return (int)card->port;
- case ICN_IOCTL_GETDOUBLE:
- return (int)card->doubleS0;
- case ICN_IOCTL_DEBUGVAR:
- if (copy_to_user(arg,
- &card,
- sizeof(ulong)))
- return -EFAULT;
- a += sizeof(ulong);
- {
- ulong l = (ulong)&dev;
- if (copy_to_user(arg,
- &l,
- sizeof(ulong)))
- return -EFAULT;
- }
- return 0;
- case ICN_IOCTL_LOADBOOT:
- if (dev.firstload) {
- icn_disable_cards();
- dev.firstload = 0;
- }
- icn_stopcard(card);
- return icn_loadboot(arg, card);
- case ICN_IOCTL_LOADPROTO:
- icn_stopcard(card);
- i = (icn_loadproto(arg, card));
- if (i)
- return i;
- if (card->doubleS0)
- i = icn_loadproto(arg + ICN_CODE_STAGE2, card->other);
- return i;
- break;
- case ICN_IOCTL_ADDCARD:
- if (!dev.firstload)
- return -EBUSY;
- if (copy_from_user(&cdef,
- arg,
- sizeof(cdef)))
- return -EFAULT;
- return icn_addcard(cdef.port, cdef.id1, cdef.id2);
- break;
- case ICN_IOCTL_LEASEDCFG:
- if (a) {
- if (!card->leased) {
- card->leased = 1;
- while (card->ptype == ISDN_PTYPE_UNKNOWN)
- msleep_interruptible(ICN_BOOT_TIMEOUT1);
- msleep_interruptible(ICN_BOOT_TIMEOUT1);
- sprintf(cbuf, "00;FV2ON\n01;EAZ%c\n02;EAZ%c\n",
- (a & 1) ? '1' : 'C', (a & 2) ? '2' : 'C');
- i = icn_writecmd(NULL, cbuf,
- strlen(cbuf),
- 0, card);
- printk(KERN_INFO
- "icn: (%s) Leased-line mode enabled\n",
- CID);
- cmd.command = ISDN_STAT_RUN;
- cmd.driver = card->myid;
- cmd.arg = 0;
- card->interface.statcallb(&cmd);
- }
- } else {
- if (card->leased) {
- card->leased = 0;
- sprintf(cbuf, "00;FV2OFF\n");
- i = icn_writecmd(NULL, cbuf,
- strlen(cbuf),
- 0, card);
- printk(KERN_INFO
- "icn: (%s) Leased-line mode disabled\n",
- CID);
- cmd.command = ISDN_STAT_RUN;
- cmd.driver = card->myid;
- cmd.arg = 0;
- card->interface.statcallb(&cmd);
- }
- }
- return 0;
- default:
- return -EINVAL;
- }
- break;
- case ISDN_CMD_DIAL:
- if (!(card->flags & ICN_FLAGS_RUNNING))
- return -ENODEV;
- if (card->leased)
- break;
- if ((c->arg & 255) < ICN_BCH) {
- char *p;
- char dcode[4];
-
- a = c->arg;
- p = c->parm.setup.phone;
- if (*p == 's' || *p == 'S') {
- /* Dial for SPV */
- p++;
- strcpy(dcode, "SCA");
- } else
- /* Normal Dial */
- strcpy(dcode, "CAL");
- snprintf(cbuf, sizeof(cbuf),
- "%02d;D%s_R%s,%02d,%02d,%s\n", (int)(a + 1),
- dcode, p, c->parm.setup.si1,
- c->parm.setup.si2, c->parm.setup.eazmsn);
- i = icn_writecmd(NULL, cbuf, strlen(cbuf), 0, card);
- }
- break;
- case ISDN_CMD_ACCEPTD:
- if (!(card->flags & ICN_FLAGS_RUNNING))
- return -ENODEV;
- if (c->arg < ICN_BCH) {
- a = c->arg + 1;
- if (card->fw_rev >= 300) {
- switch (card->l2_proto[a - 1]) {
- case ISDN_PROTO_L2_X75I:
- sprintf(cbuf, "%02d;BX75\n", (int)a);
- break;
- case ISDN_PROTO_L2_HDLC:
- sprintf(cbuf, "%02d;BTRA\n", (int)a);
- break;
- }
- i = icn_writecmd(NULL, cbuf,
- strlen(cbuf), 0,
- card);
- }
- sprintf(cbuf, "%02d;DCON_R\n", (int)a);
- i = icn_writecmd(NULL, cbuf, strlen(cbuf), 0, card);
- }
- break;
- case ISDN_CMD_ACCEPTB:
- if (!(card->flags & ICN_FLAGS_RUNNING))
- return -ENODEV;
- if (c->arg < ICN_BCH) {
- a = c->arg + 1;
- if (card->fw_rev >= 300)
- switch (card->l2_proto[a - 1]) {
- case ISDN_PROTO_L2_X75I:
- sprintf(cbuf, "%02d;BCON_R,BX75\n", (int)a);
- break;
- case ISDN_PROTO_L2_HDLC:
- sprintf(cbuf, "%02d;BCON_R,BTRA\n", (int)a);
- break;
- } else
- sprintf(cbuf, "%02d;BCON_R\n", (int)a);
- i = icn_writecmd(NULL, cbuf, strlen(cbuf), 0, card);
- }
- break;
- case ISDN_CMD_HANGUP:
- if (!(card->flags & ICN_FLAGS_RUNNING))
- return -ENODEV;
- if (c->arg < ICN_BCH) {
- a = c->arg + 1;
- sprintf(cbuf, "%02d;BDIS_R\n%02d;DDIS_R\n", (int)a, (int)a);
- i = icn_writecmd(NULL, cbuf, strlen(cbuf), 0, card);
- }
- break;
- case ISDN_CMD_SETEAZ:
- if (!(card->flags & ICN_FLAGS_RUNNING))
- return -ENODEV;
- if (card->leased)
- break;
- if (c->arg < ICN_BCH) {
- a = c->arg + 1;
- if (card->ptype == ISDN_PTYPE_EURO) {
- sprintf(cbuf, "%02d;MS%s%s\n", (int)a,
- c->parm.num[0] ? "N" : "ALL", c->parm.num);
- } else
- sprintf(cbuf, "%02d;EAZ%s\n", (int)a,
- c->parm.num[0] ? (char *)(c->parm.num) : "0123456789");
- i = icn_writecmd(NULL, cbuf, strlen(cbuf), 0, card);
- }
- break;
- case ISDN_CMD_CLREAZ:
- if (!(card->flags & ICN_FLAGS_RUNNING))
- return -ENODEV;
- if (card->leased)
- break;
- if (c->arg < ICN_BCH) {
- a = c->arg + 1;
- if (card->ptype == ISDN_PTYPE_EURO)
- sprintf(cbuf, "%02d;MSNC\n", (int)a);
- else
- sprintf(cbuf, "%02d;EAZC\n", (int)a);
- i = icn_writecmd(NULL, cbuf, strlen(cbuf), 0, card);
- }
- break;
- case ISDN_CMD_SETL2:
- if (!(card->flags & ICN_FLAGS_RUNNING))
- return -ENODEV;
- if ((c->arg & 255) < ICN_BCH) {
- a = c->arg;
- switch (a >> 8) {
- case ISDN_PROTO_L2_X75I:
- sprintf(cbuf, "%02d;BX75\n", (int)(a & 255) + 1);
- break;
- case ISDN_PROTO_L2_HDLC:
- sprintf(cbuf, "%02d;BTRA\n", (int)(a & 255) + 1);
- break;
- default:
- return -EINVAL;
- }
- i = icn_writecmd(NULL, cbuf, strlen(cbuf), 0, card);
- card->l2_proto[a & 255] = (a >> 8);
- }
- break;
- case ISDN_CMD_SETL3:
- if (!(card->flags & ICN_FLAGS_RUNNING))
- return -ENODEV;
- return 0;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-/*
- * Find card with given driverId
- */
-static inline icn_card *
-icn_findcard(int driverid)
-{
- icn_card *p = cards;
-
- while (p) {
- if (p->myid == driverid)
- return p;
- p = p->next;
- }
- return (icn_card *)0;
-}
-
-/*
- * Wrapper functions for interface to linklevel
- */
-static int
-if_command(isdn_ctrl *c)
-{
- icn_card *card = icn_findcard(c->driver);
-
- if (card)
- return icn_command(c, card);
- printk(KERN_ERR
- "icn: if_command %d called with invalid driverId %d!\n",
- c->command, c->driver);
- return -ENODEV;
-}
-
-static int
-if_writecmd(const u_char __user *buf, int len, int id, int channel)
-{
- icn_card *card = icn_findcard(id);
-
- if (card) {
- if (!(card->flags & ICN_FLAGS_RUNNING))
- return -ENODEV;
- return icn_writecmd(buf, NULL, len, 1, card);
- }
- printk(KERN_ERR
- "icn: if_writecmd called with invalid driverId!\n");
- return -ENODEV;
-}
-
-static int
-if_readstatus(u_char __user *buf, int len, int id, int channel)
-{
- icn_card *card = icn_findcard(id);
-
- if (card) {
- if (!(card->flags & ICN_FLAGS_RUNNING))
- return -ENODEV;
- return icn_readstatus(buf, len, card);
- }
- printk(KERN_ERR
- "icn: if_readstatus called with invalid driverId!\n");
- return -ENODEV;
-}
-
-static int
-if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
-{
- icn_card *card = icn_findcard(id);
-
- if (card) {
- if (!(card->flags & ICN_FLAGS_RUNNING))
- return -ENODEV;
- return icn_sendbuf(channel, ack, skb, card);
- }
- printk(KERN_ERR
- "icn: if_sendbuf called with invalid driverId!\n");
- return -ENODEV;
-}
-
-/*
- * Allocate a new card-struct, initialize it
- * link it into cards-list and register it at linklevel.
- */
-static icn_card *
-icn_initcard(int port, char *id)
-{
- icn_card *card;
- int i;
-
- card = kzalloc(sizeof(icn_card), GFP_KERNEL);
- if (!card) {
- printk(KERN_WARNING
- "icn: (%s) Could not allocate card-struct.\n", id);
- return (icn_card *)0;
- }
- spin_lock_init(&card->lock);
- card->port = port;
- card->interface.owner = THIS_MODULE;
- card->interface.hl_hdrlen = 1;
- card->interface.channels = ICN_BCH;
- card->interface.maxbufsize = 4000;
- card->interface.command = if_command;
- card->interface.writebuf_skb = if_sendbuf;
- card->interface.writecmd = if_writecmd;
- card->interface.readstat = if_readstatus;
- card->interface.features = ISDN_FEATURE_L2_X75I |
- ISDN_FEATURE_L2_HDLC |
- ISDN_FEATURE_L3_TRANS |
- ISDN_FEATURE_P_UNKNOWN;
- card->ptype = ISDN_PTYPE_UNKNOWN;
- strlcpy(card->interface.id, id, sizeof(card->interface.id));
- card->msg_buf_write = card->msg_buf;
- card->msg_buf_read = card->msg_buf;
- card->msg_buf_end = &card->msg_buf[sizeof(card->msg_buf) - 1];
- for (i = 0; i < ICN_BCH; i++) {
- card->l2_proto[i] = ISDN_PROTO_L2_X75I;
- skb_queue_head_init(&card->spqueue[i]);
- }
- card->next = cards;
- cards = card;
- if (!register_isdn(&card->interface)) {
- cards = cards->next;
- printk(KERN_WARNING
- "icn: Unable to register %s\n", id);
- kfree(card);
- return (icn_card *)0;
- }
- card->myid = card->interface.channels;
- sprintf(card->regname, "icn-isdn (%s)", card->interface.id);
- return card;
-}
-
-static int
-icn_addcard(int port, char *id1, char *id2)
-{
- icn_card *card;
- icn_card *card2;
-
- card = icn_initcard(port, id1);
- if (!card)
- return -EIO;
- if (!strlen(id2)) {
- printk(KERN_INFO
- "icn: (%s) ICN-2B, port 0x%x added\n",
- card->interface.id, port);
- return 0;
- }
- card2 = icn_initcard(port, id2);
- if (!card2) {
- printk(KERN_INFO
- "icn: (%s) half ICN-4B, port 0x%x added\n", id2, port);
- return 0;
- }
- card->doubleS0 = 1;
- card->secondhalf = 0;
- card->other = card2;
- card2->doubleS0 = 1;
- card2->secondhalf = 1;
- card2->other = card;
- printk(KERN_INFO
- "icn: (%s and %s) ICN-4B, port 0x%x added\n",
- card->interface.id, card2->interface.id, port);
- return 0;
-}
-
-#ifndef MODULE
-static int __init
-icn_setup(char *line)
-{
- char *p, *str;
- int ints[3];
- static char sid[20];
- static char sid2[20];
-
- str = get_options(line, 2, ints);
- if (ints[0])
- portbase = ints[1];
- if (ints[0] > 1)
- membase = (unsigned long)ints[2];
- if (str && *str) {
- strlcpy(sid, str, sizeof(sid));
- icn_id = sid;
- p = strchr(sid, ',');
- if (p) {
- *p++ = 0;
- strcpy(sid2, p);
- icn_id2 = sid2;
- }
- }
- return 1;
-}
-__setup("icn=", icn_setup);
-#endif /* MODULE */
-
-static int __init icn_init(void)
-{
- char *p;
- char rev[21];
-
- memset(&dev, 0, sizeof(icn_dev));
- dev.memaddr = (membase & 0x0ffc000);
- dev.channel = -1;
- dev.mcard = NULL;
- dev.firstload = 1;
- spin_lock_init(&dev.devlock);
-
- p = strchr(revision, ':');
- if (p) {
- strncpy(rev, p + 1, 20);
- rev[20] = '\0';
- p = strchr(rev, '$');
- if (p)
- *p = 0;
- } else
- strcpy(rev, " ??? ");
- printk(KERN_NOTICE "ICN-ISDN-driver Rev%smem=0x%08lx\n", rev,
- dev.memaddr);
- return icn_addcard(portbase, icn_id, icn_id2);
-}
-
-static void __exit icn_exit(void)
-{
- isdn_ctrl cmd;
- icn_card *card = cards;
- icn_card *last, *tmpcard;
- int i;
- unsigned long flags;
-
- icn_stopallcards();
- while (card) {
- cmd.command = ISDN_STAT_UNLOAD;
- cmd.driver = card->myid;
- card->interface.statcallb(&cmd);
- spin_lock_irqsave(&card->lock, flags);
- if (card->rvalid) {
- OUTB_P(0, ICN_RUN); /* Reset Controller */
- OUTB_P(0, ICN_MAPRAM); /* Disable RAM */
- if (card->secondhalf || (!card->doubleS0)) {
- release_region(card->port, ICN_PORTLEN);
- card->rvalid = 0;
- }
- for (i = 0; i < ICN_BCH; i++)
- icn_free_queue(card, i);
- }
- tmpcard = card->next;
- spin_unlock_irqrestore(&card->lock, flags);
- card = tmpcard;
- }
- card = cards;
- cards = NULL;
- while (card) {
- last = card;
- card = card->next;
- kfree(last);
- }
- if (dev.mvalid) {
- iounmap(dev.shmem);
- release_mem_region(dev.memaddr, 0x4000);
- }
- printk(KERN_NOTICE "ICN-ISDN-driver unloaded\n");
-}
-
-module_init(icn_init);
-module_exit(icn_exit);
+++ /dev/null
-/* $Id: icn.h,v 1.30.6.5 2001/09/23 22:24:55 kai Exp $
- *
- * ISDN lowlevel-module for the ICN active ISDN-Card.
- *
- * Copyright 1994 by Fritz Elfert (fritz@isdn4linux.de)
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#ifndef icn_h
-#define icn_h
-
-#define ICN_IOCTL_SETMMIO 0
-#define ICN_IOCTL_GETMMIO 1
-#define ICN_IOCTL_SETPORT 2
-#define ICN_IOCTL_GETPORT 3
-#define ICN_IOCTL_LOADBOOT 4
-#define ICN_IOCTL_LOADPROTO 5
-#define ICN_IOCTL_LEASEDCFG 6
-#define ICN_IOCTL_GETDOUBLE 7
-#define ICN_IOCTL_DEBUGVAR 8
-#define ICN_IOCTL_ADDCARD 9
-
-/* Struct for adding new cards */
-typedef struct icn_cdef {
- int port;
- char id1[10];
- char id2[10];
-} icn_cdef;
-
-#if defined(__KERNEL__) || defined(__DEBUGVAR__)
-
-#ifdef __KERNEL__
-/* Kernel includes */
-
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/major.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/signal.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/ioport.h>
-#include <linux/timer.h>
-#include <linux/wait.h>
-#include <linux/delay.h>
-#include <linux/isdnif.h>
-
-#endif /* __KERNEL__ */
-
-/* some useful macros for debugging */
-#ifdef ICN_DEBUG_PORT
-#define OUTB_P(v, p) {pr_debug("icn: outb_p(0x%02x,0x%03x)\n", v, p); outb_p(v, p);}
-#else
-#define OUTB_P outb
-#endif
-
-/* Defaults for Port-Address and shared-memory */
-#define ICN_BASEADDR 0x320
-#define ICN_PORTLEN (0x04)
-#define ICN_MEMADDR 0x0d0000
-
-#define ICN_FLAGS_B1ACTIVE 1 /* B-Channel-1 is open */
-#define ICN_FLAGS_B2ACTIVE 2 /* B-Channel-2 is open */
-#define ICN_FLAGS_RUNNING 4 /* Cards driver activated */
-#define ICN_FLAGS_RBTIMER 8 /* cyclic scheduling of B-Channel-poll */
-
-#define ICN_BOOT_TIMEOUT1 1000 /* Delay for Boot-download (msecs) */
-
-#define ICN_TIMER_BCREAD (HZ / 100) /* B-Channel poll-cycle */
-#define ICN_TIMER_DCREAD (HZ / 2) /* D-Channel poll-cycle */
-
-#define ICN_CODE_STAGE1 4096 /* Size of bootcode */
-#define ICN_CODE_STAGE2 65536 /* Size of protocol-code */
-
-#define ICN_MAX_SQUEUE 8000 /* Max. outstanding send-data (2* hw-buf.) */
-#define ICN_FRAGSIZE (250) /* Max. size of send-fragments */
-#define ICN_BCH 2 /* Number of supported channels per card */
-
-/* type-definitions for accessing the mmap-io-areas */
-
-#define SHM_DCTL_OFFSET (0) /* Offset to data-controlstructures in shm */
-#define SHM_CCTL_OFFSET (0x1d2) /* Offset to comm-controlstructures in shm */
-#define SHM_CBUF_OFFSET (0x200) /* Offset to comm-buffers in shm */
-#define SHM_DBUF_OFFSET (0x2000) /* Offset to data-buffers in shm */
-
-/*
- * Layout of card's data buffers
- */
-typedef struct {
- unsigned char length; /* Bytecount of fragment (max 250) */
- unsigned char endflag; /* 0=last frag., 0xff=frag. continued */
- unsigned char data[ICN_FRAGSIZE]; /* The data */
- /* Fill to 256 bytes */
- char unused[0x100 - ICN_FRAGSIZE - 2];
-} frag_buf;
-
-/*
- * Layout of card's shared memory
- */
-typedef union {
- struct {
- unsigned char scns; /* Index to free SendFrag. */
- unsigned char scnr; /* Index to active SendFrag READONLY */
- unsigned char ecns; /* Index to free RcvFrag. READONLY */
- unsigned char ecnr; /* Index to valid RcvFrag */
- char unused[6];
- unsigned short fuell1; /* Internal Buf Bytecount */
- } data_control;
- struct {
- char unused[SHM_CCTL_OFFSET];
- unsigned char iopc_i; /* Read-Ptr Status-Queue READONLY */
- unsigned char iopc_o; /* Write-Ptr Status-Queue */
- unsigned char pcio_i; /* Write-Ptr Command-Queue */
- unsigned char pcio_o; /* Read-Ptr Command Queue READONLY */
- } comm_control;
- struct {
- char unused[SHM_CBUF_OFFSET];
- unsigned char pcio_buf[0x100]; /* Ring-Buffer Command-Queue */
- unsigned char iopc_buf[0x100]; /* Ring-Buffer Status-Queue */
- } comm_buffers;
- struct {
- char unused[SHM_DBUF_OFFSET];
- frag_buf receive_buf[0x10];
- frag_buf send_buf[0x10];
- } data_buffers;
-} icn_shmem;
-
-/*
- * Per card driver data
- */
-typedef struct icn_card {
- struct icn_card *next; /* Pointer to next device struct */
- struct icn_card *other; /* Pointer to other card for ICN4B */
- unsigned short port; /* Base-port-address */
- int myid; /* Driver-Nr. assigned by linklevel */
- int rvalid; /* IO-portregion has been requested */
- int leased; /* Flag: This Adapter is connected */
- /* to a leased line */
- unsigned short flags; /* Statusflags */
- int doubleS0; /* Flag: ICN4B */
- int secondhalf; /* Flag: Second half of a doubleS0 */
- int fw_rev; /* Firmware revision loaded */
- int ptype; /* Protocol type (1TR6 or Euro) */
- struct timer_list st_timer; /* Timer for Status-Polls */
- struct timer_list rb_timer; /* Timer for B-Channel-Polls */
- u_char rcvbuf[ICN_BCH][4096]; /* B-Channel-Receive-Buffers */
- int rcvidx[ICN_BCH]; /* Index for above buffers */
- int l2_proto[ICN_BCH]; /* Current layer-2-protocol */
- isdn_if interface; /* Interface to upper layer */
- int iptr; /* Index to imsg-buffer */
- char imsg[60]; /* Internal buf for status-parsing */
- char msg_buf[2048]; /* Buffer for status-messages */
- char *msg_buf_write; /* Writepointer for statusbuffer */
- char *msg_buf_read; /* Readpointer for statusbuffer */
- char *msg_buf_end; /* Pointer to end of statusbuffer */
- int sndcount[ICN_BCH]; /* Byte-counters for B-Ch.-send */
- int xlen[ICN_BCH]; /* Byte-counters/Flags for sent-ACK */
- struct sk_buff *xskb[ICN_BCH]; /* Current transmitted skb */
- struct sk_buff_head spqueue[ICN_BCH]; /* Sendqueue */
- char regname[35]; /* Name used for request_region */
- u_char xmit_lock[ICN_BCH]; /* Semaphore for pollbchan_send()*/
- spinlock_t lock; /* protect critical operations */
-} icn_card;
-
-/*
- * Main driver data
- */
-typedef struct icn_dev {
- spinlock_t devlock; /* spinlock to protect this struct */
- unsigned long memaddr; /* Address of memory mapped buffers */
- icn_shmem __iomem *shmem; /* Pointer to memory-mapped-buffers */
- int mvalid; /* IO-shmem has been requested */
- int channel; /* Currently mapped channel */
- struct icn_card *mcard; /* Currently mapped card */
- int chanlock; /* Semaphore for channel-mapping */
- int firstload; /* Flag: firmware never loaded */
-} icn_dev;
-
-typedef icn_dev *icn_devptr;
-
-#ifdef __KERNEL__
-
-static icn_card *cards = (icn_card *) 0;
-static u_char chan2bank[] = {0, 4, 8, 12}; /* for icn_map_channel() */
-
-static icn_dev dev;
-
-#endif /* __KERNEL__ */
-
-/* Utility-Macros */
-
-/* Macros for accessing ports */
-#define ICN_CFG (card->port)
-#define ICN_MAPRAM (card->port + 1)
-#define ICN_RUN (card->port + 2)
-#define ICN_BANK (card->port + 3)
-
-/* Return true, if there is a free transmit-buffer */
-#define sbfree (((readb(&dev.shmem->data_control.scns) + 1) & 0xf) != \
- readb(&dev.shmem->data_control.scnr))
-
-/* Switch to next transmit-buffer */
-#define sbnext (writeb((readb(&dev.shmem->data_control.scns) + 1) & 0xf, \
- &dev.shmem->data_control.scns))
-
-/* Shortcuts for transmit-buffer-access */
-#define sbuf_n dev.shmem->data_control.scns
-#define sbuf_d dev.shmem->data_buffers.send_buf[readb(&sbuf_n)].data
-#define sbuf_l dev.shmem->data_buffers.send_buf[readb(&sbuf_n)].length
-#define sbuf_f dev.shmem->data_buffers.send_buf[readb(&sbuf_n)].endflag
-
-/* Return true, if there is receive-data is available */
-#define rbavl (readb(&dev.shmem->data_control.ecnr) != \
- readb(&dev.shmem->data_control.ecns))
-
-/* Switch to next receive-buffer */
-#define rbnext (writeb((readb(&dev.shmem->data_control.ecnr) + 1) & 0xf, \
- &dev.shmem->data_control.ecnr))
-
-/* Shortcuts for receive-buffer-access */
-#define rbuf_n dev.shmem->data_control.ecnr
-#define rbuf_d dev.shmem->data_buffers.receive_buf[readb(&rbuf_n)].data
-#define rbuf_l dev.shmem->data_buffers.receive_buf[readb(&rbuf_n)].length
-#define rbuf_f dev.shmem->data_buffers.receive_buf[readb(&rbuf_n)].endflag
-
-/* Shortcuts for command-buffer-access */
-#define cmd_o (dev.shmem->comm_control.pcio_o)
-#define cmd_i (dev.shmem->comm_control.pcio_i)
-
-/* Return free space in command-buffer */
-#define cmd_free ((readb(&cmd_i) >= readb(&cmd_o)) ? \
- 0x100 - readb(&cmd_i) + readb(&cmd_o) : \
- readb(&cmd_o) - readb(&cmd_i))
-
-/* Shortcuts for message-buffer-access */
-#define msg_o (dev.shmem->comm_control.iopc_o)
-#define msg_i (dev.shmem->comm_control.iopc_i)
-
-/* Return length of Message, if avail. */
-#define msg_avail ((readb(&msg_o) > readb(&msg_i)) ? \
- 0x100 - readb(&msg_o) + readb(&msg_i) : \
- readb(&msg_i) - readb(&msg_o))
-
-#define CID (card->interface.id)
-
-#endif /* defined(__KERNEL__) || defined(__DEBUGVAR__) */
-#endif /* icn_h */
+++ /dev/null
-config ISDN_DRV_PCBIT
- tristate "PCBIT-D support"
- depends on ISA && (BROKEN || X86)
- help
- This enables support for the PCBIT ISDN-card. This card is
- manufactured in Portugal by Octal. For running this card,
- additional firmware is necessary, which has to be downloaded into
- the card using a utility which is distributed separately. See
- <file:Documentation/isdn/README> and
- <file:Documentation/isdn/README.pcbit> for more information.
+++ /dev/null
-# Makefile for the pcbit ISDN device driver
-
-# Each configuration option enables a list of files.
-
-obj-$(CONFIG_ISDN_DRV_PCBIT) += pcbit.o
-
-# Multipart objects.
-
-pcbit-y := module.o edss1.o drv.o layer2.o capi.o callbacks.o
+++ /dev/null
-/*
- * Callbacks for the FSM
- *
- * Copyright (C) 1996 Universidade de Lisboa
- *
- * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
- *
- * This software may be used and distributed according to the terms of
- * the GNU General Public License, incorporated herein by reference.
- */
-
-/*
- * Fix: 19981230 - Carlos Morgado <chbm@techie.com>
- * Port of Nelson Escravana's <nelson.escravana@usa.net> fix to CalledPN
- * NULL pointer dereference in cb_in_1 (originally fixed in 2.0)
- */
-
-#include <linux/string.h>
-#include <linux/kernel.h>
-
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/skbuff.h>
-
-#include <linux/io.h>
-
-#include <linux/isdnif.h>
-
-#include "pcbit.h"
-#include "layer2.h"
-#include "edss1.h"
-#include "callbacks.h"
-#include "capi.h"
-
-ushort last_ref_num = 1;
-
-/*
- * send_conn_req
- *
- */
-
-void cb_out_1(struct pcbit_dev *dev, struct pcbit_chan *chan,
- struct callb_data *cbdata)
-{
- struct sk_buff *skb;
- int len;
- ushort refnum;
-
-
-#ifdef DEBUG
- printk(KERN_DEBUG "Called Party Number: %s\n",
- cbdata->data.setup.CalledPN);
-#endif
- /*
- * hdr - kmalloc in capi_conn_req
- * - kfree when msg has been sent
- */
-
- if ((len = capi_conn_req(cbdata->data.setup.CalledPN, &skb,
- chan->proto)) < 0)
- {
- printk("capi_conn_req failed\n");
- return;
- }
-
-
- refnum = last_ref_num++ & 0x7fffU;
-
- chan->callref = 0;
- chan->layer2link = 0;
- chan->snum = 0;
- chan->s_refnum = refnum;
-
- pcbit_l2_write(dev, MSG_CONN_REQ, refnum, skb, len);
-}
-
-/*
- * rcv CONNECT
- * will go into ACTIVE state
- * send CONN_ACTIVE_RESP
- * send Select protocol request
- */
-
-void cb_out_2(struct pcbit_dev *dev, struct pcbit_chan *chan,
- struct callb_data *data)
-{
- isdn_ctrl ictl;
- struct sk_buff *skb;
- int len;
- ushort refnum;
-
- if ((len = capi_conn_active_resp(chan, &skb)) < 0)
- {
- printk("capi_conn_active_req failed\n");
- return;
- }
-
- refnum = last_ref_num++ & 0x7fffU;
- chan->s_refnum = refnum;
-
- pcbit_l2_write(dev, MSG_CONN_ACTV_RESP, refnum, skb, len);
-
-
- ictl.command = ISDN_STAT_DCONN;
- ictl.driver = dev->id;
- ictl.arg = chan->id;
- dev->dev_if->statcallb(&ictl);
-
- /* ACTIVE D-channel */
-
- /* Select protocol */
-
- if ((len = capi_select_proto_req(chan, &skb, 1 /*outgoing*/)) < 0) {
- printk("capi_select_proto_req failed\n");
- return;
- }
-
- refnum = last_ref_num++ & 0x7fffU;
- chan->s_refnum = refnum;
-
- pcbit_l2_write(dev, MSG_SELP_REQ, refnum, skb, len);
-}
-
-
-/*
- * Incoming call received
- * inform user
- */
-
-void cb_in_1(struct pcbit_dev *dev, struct pcbit_chan *chan,
- struct callb_data *cbdata)
-{
- isdn_ctrl ictl;
- unsigned short refnum;
- struct sk_buff *skb;
- int len;
-
-
- ictl.command = ISDN_STAT_ICALL;
- ictl.driver = dev->id;
- ictl.arg = chan->id;
-
- /*
- * ictl.num >= strlen() + strlen() + 5
- */
-
- if (cbdata->data.setup.CallingPN == NULL) {
- printk(KERN_DEBUG "NULL CallingPN to phone; using 0\n");
- strcpy(ictl.parm.setup.phone, "0");
- }
- else {
- strcpy(ictl.parm.setup.phone, cbdata->data.setup.CallingPN);
- }
- if (cbdata->data.setup.CalledPN == NULL) {
- printk(KERN_DEBUG "NULL CalledPN to eazmsn; using 0\n");
- strcpy(ictl.parm.setup.eazmsn, "0");
- }
- else {
- strcpy(ictl.parm.setup.eazmsn, cbdata->data.setup.CalledPN);
- }
- ictl.parm.setup.si1 = 7;
- ictl.parm.setup.si2 = 0;
- ictl.parm.setup.plan = 0;
- ictl.parm.setup.screen = 0;
-
-#ifdef DEBUG
- printk(KERN_DEBUG "statstr: %s\n", ictl.num);
-#endif
-
- dev->dev_if->statcallb(&ictl);
-
-
- if ((len = capi_conn_resp(chan, &skb)) < 0) {
- printk(KERN_DEBUG "capi_conn_resp failed\n");
- return;
- }
-
- refnum = last_ref_num++ & 0x7fffU;
- chan->s_refnum = refnum;
-
- pcbit_l2_write(dev, MSG_CONN_RESP, refnum, skb, len);
-}
-
-/*
- * user has replied
- * open the channel
- * send CONNECT message CONNECT_ACTIVE_REQ in CAPI
- */
-
-void cb_in_2(struct pcbit_dev *dev, struct pcbit_chan *chan,
- struct callb_data *data)
-{
- unsigned short refnum;
- struct sk_buff *skb;
- int len;
-
- if ((len = capi_conn_active_req(chan, &skb)) < 0) {
- printk(KERN_DEBUG "capi_conn_active_req failed\n");
- return;
- }
-
-
- refnum = last_ref_num++ & 0x7fffU;
- chan->s_refnum = refnum;
-
- printk(KERN_DEBUG "sending MSG_CONN_ACTV_REQ\n");
- pcbit_l2_write(dev, MSG_CONN_ACTV_REQ, refnum, skb, len);
-}
-
-/*
- * CONN_ACK arrived
- * start b-proto selection
- *
- */
-
-void cb_in_3(struct pcbit_dev *dev, struct pcbit_chan *chan,
- struct callb_data *data)
-{
- unsigned short refnum;
- struct sk_buff *skb;
- int len;
-
- if ((len = capi_select_proto_req(chan, &skb, 0 /*incoming*/)) < 0)
- {
- printk("capi_select_proto_req failed\n");
- return;
- }
-
- refnum = last_ref_num++ & 0x7fffU;
- chan->s_refnum = refnum;
-
- pcbit_l2_write(dev, MSG_SELP_REQ, refnum, skb, len);
-
-}
-
-
-/*
- * Received disconnect ind on active state
- * send disconnect resp
- * send msg to user
- */
-void cb_disc_1(struct pcbit_dev *dev, struct pcbit_chan *chan,
- struct callb_data *data)
-{
- struct sk_buff *skb;
- int len;
- ushort refnum;
- isdn_ctrl ictl;
-
- if ((len = capi_disc_resp(chan, &skb)) < 0) {
- printk("capi_disc_resp failed\n");
- return;
- }
-
- refnum = last_ref_num++ & 0x7fffU;
- chan->s_refnum = refnum;
-
- pcbit_l2_write(dev, MSG_DISC_RESP, refnum, skb, len);
-
- ictl.command = ISDN_STAT_BHUP;
- ictl.driver = dev->id;
- ictl.arg = chan->id;
- dev->dev_if->statcallb(&ictl);
-}
-
-
-/*
- * User HANGUP on active/call proceeding state
- * send disc.req
- */
-void cb_disc_2(struct pcbit_dev *dev, struct pcbit_chan *chan,
- struct callb_data *data)
-{
- struct sk_buff *skb;
- int len;
- ushort refnum;
-
- if ((len = capi_disc_req(chan->callref, &skb, CAUSE_NORMAL)) < 0)
- {
- printk("capi_disc_req failed\n");
- return;
- }
-
- refnum = last_ref_num++ & 0x7fffU;
- chan->s_refnum = refnum;
-
- pcbit_l2_write(dev, MSG_DISC_REQ, refnum, skb, len);
-}
-
-/*
- * Disc confirm received send BHUP
- * Problem: when the HL driver sends the disc req itself
- * LL receives BHUP
- */
-void cb_disc_3(struct pcbit_dev *dev, struct pcbit_chan *chan,
- struct callb_data *data)
-{
- isdn_ctrl ictl;
-
- ictl.command = ISDN_STAT_BHUP;
- ictl.driver = dev->id;
- ictl.arg = chan->id;
- dev->dev_if->statcallb(&ictl);
-}
-
-void cb_notdone(struct pcbit_dev *dev, struct pcbit_chan *chan,
- struct callb_data *data)
-{
-}
-
-/*
- * send activate b-chan protocol
- */
-void cb_selp_1(struct pcbit_dev *dev, struct pcbit_chan *chan,
- struct callb_data *data)
-{
- struct sk_buff *skb;
- int len;
- ushort refnum;
-
- if ((len = capi_activate_transp_req(chan, &skb)) < 0)
- {
- printk("capi_conn_activate_transp_req failed\n");
- return;
- }
-
- refnum = last_ref_num++ & 0x7fffU;
- chan->s_refnum = refnum;
-
- pcbit_l2_write(dev, MSG_ACT_TRANSP_REQ, refnum, skb, len);
-}
-
-/*
- * Inform User that the B-channel is available
- */
-void cb_open(struct pcbit_dev *dev, struct pcbit_chan *chan,
- struct callb_data *data)
-{
- isdn_ctrl ictl;
-
- ictl.command = ISDN_STAT_BCONN;
- ictl.driver = dev->id;
- ictl.arg = chan->id;
- dev->dev_if->statcallb(&ictl);
-}
+++ /dev/null
-/*
- * Callbacks prototypes for FSM
- *
- * Copyright (C) 1996 Universidade de Lisboa
- *
- * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
- *
- * This software may be used and distributed according to the terms of
- * the GNU General Public License, incorporated herein by reference.
- */
-
-#ifndef CALLBACKS_H
-#define CALLBACKS_H
-
-
-extern void cb_out_1(struct pcbit_dev *dev, struct pcbit_chan *chan,
- struct callb_data *data);
-
-extern void cb_out_2(struct pcbit_dev *dev, struct pcbit_chan *chan,
- struct callb_data *data);
-
-extern void cb_in_1(struct pcbit_dev *dev, struct pcbit_chan *chan,
- struct callb_data *data);
-extern void cb_in_2(struct pcbit_dev *dev, struct pcbit_chan *chan,
- struct callb_data *data);
-extern void cb_in_3(struct pcbit_dev *dev, struct pcbit_chan *chan,
- struct callb_data *data);
-
-extern void cb_disc_1(struct pcbit_dev *dev, struct pcbit_chan *chan,
- struct callb_data *data);
-extern void cb_disc_2(struct pcbit_dev *dev, struct pcbit_chan *chan,
- struct callb_data *data);
-extern void cb_disc_3(struct pcbit_dev *dev, struct pcbit_chan *chan,
- struct callb_data *data);
-
-extern void cb_notdone(struct pcbit_dev *dev, struct pcbit_chan *chan,
- struct callb_data *data);
-
-extern void cb_selp_1(struct pcbit_dev *dev, struct pcbit_chan *chan,
- struct callb_data *data);
-extern void cb_open(struct pcbit_dev *dev, struct pcbit_chan *chan,
- struct callb_data *data);
-
-#endif
+++ /dev/null
-/*
- * CAPI encoder/decoder for
- * Portugal Telecom CAPI 2.0
- *
- * Copyright (C) 1996 Universidade de Lisboa
- *
- * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
- *
- * This software may be used and distributed according to the terms of
- * the GNU General Public License, incorporated herein by reference.
- *
- * Not compatible with the AVM Gmbh. CAPI 2.0
- *
- */
-
-/*
- * Documentation:
- * - "Common ISDN API - Perfil Português - Versão 2.1",
- * Telecom Portugal, Fev 1992.
- * - "Common ISDN API - Especificação de protocolos para
- * acesso aos canais B", Inesc, Jan 1994.
- */
-
-/*
- * TODO: better decoding of Information Elements
- * for debug purposes mainly
- * encode our number in CallerPN and ConnectedPN
- */
-
-#include <linux/kernel.h>
-
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-
-#include <linux/skbuff.h>
-
-#include <linux/io.h>
-#include <linux/string.h>
-
-#include <linux/isdnif.h>
-
-#include "pcbit.h"
-#include "edss1.h"
-#include "capi.h"
-
-
-/*
- * Encoding of CAPI messages
- *
- */
-
-int capi_conn_req(const char *calledPN, struct sk_buff **skb, int proto)
-{
- ushort len;
-
- /*
- * length
- * AppInfoMask - 2
- * BC0 - 3
- * BC1 - 1
- * Chan - 2
- * Keypad - 1
- * CPN - 1
- * CPSA - 1
- * CalledPN - 2 + strlen
- * CalledPSA - 1
- * rest... - 4
- * ----------------
- * Total 18 + strlen
- */
-
- len = 18 + strlen(calledPN);
-
- if (proto == ISDN_PROTO_L2_TRANS)
- len++;
-
- if ((*skb = dev_alloc_skb(len)) == NULL) {
-
- printk(KERN_WARNING "capi_conn_req: alloc_skb failed\n");
- return -1;
- }
-
- /* InfoElmMask */
- *((ushort *)skb_put(*skb, 2)) = AppInfoMask;
-
- if (proto == ISDN_PROTO_L2_TRANS)
- {
- /* Bearer Capability - Mandatory*/
- *(skb_put(*skb, 1)) = 3; /* BC0.Length */
- *(skb_put(*skb, 1)) = 0x80; /* Speech */
- *(skb_put(*skb, 1)) = 0x10; /* Circuit Mode */
- *(skb_put(*skb, 1)) = 0x23; /* A-law */
- } else {
- /* Bearer Capability - Mandatory*/
- *(skb_put(*skb, 1)) = 2; /* BC0.Length */
- *(skb_put(*skb, 1)) = 0x88; /* Digital Information */
- *(skb_put(*skb, 1)) = 0x90; /* BC0.Octect4 */
- }
-
- /* Bearer Capability - Optional*/
- *(skb_put(*skb, 1)) = 0; /* BC1.Length = 0 */
-
- *(skb_put(*skb, 1)) = 1; /* ChannelID.Length = 1 */
- *(skb_put(*skb, 1)) = 0x83; /* Basic Interface - Any Channel */
-
- *(skb_put(*skb, 1)) = 0; /* Keypad.Length = 0 */
-
-
- *(skb_put(*skb, 1)) = 0; /* CallingPN.Length = 0 */
- *(skb_put(*skb, 1)) = 0; /* CallingPSA.Length = 0 */
-
- /* Called Party Number */
- *(skb_put(*skb, 1)) = strlen(calledPN) + 1;
- *(skb_put(*skb, 1)) = 0x81;
- memcpy(skb_put(*skb, strlen(calledPN)), calledPN, strlen(calledPN));
-
- /* '#' */
-
- *(skb_put(*skb, 1)) = 0; /* CalledPSA.Length = 0 */
-
- /* LLC.Length = 0; */
- /* HLC0.Length = 0; */
- /* HLC1.Length = 0; */
- /* UTUS.Length = 0; */
- memset(skb_put(*skb, 4), 0, 4);
-
- return len;
-}
-
-int capi_conn_resp(struct pcbit_chan *chan, struct sk_buff **skb)
-{
-
- if ((*skb = dev_alloc_skb(5)) == NULL) {
-
- printk(KERN_WARNING "capi_conn_resp: alloc_skb failed\n");
- return -1;
- }
-
- *((ushort *)skb_put(*skb, 2)) = chan->callref;
- *(skb_put(*skb, 1)) = 0x01; /* ACCEPT_CALL */
- *(skb_put(*skb, 1)) = 0;
- *(skb_put(*skb, 1)) = 0;
-
- return 5;
-}
-
-int capi_conn_active_req(struct pcbit_chan *chan, struct sk_buff **skb)
-{
- /*
- * 8 bytes
- */
-
- if ((*skb = dev_alloc_skb(8)) == NULL) {
-
- printk(KERN_WARNING "capi_conn_active_req: alloc_skb failed\n");
- return -1;
- }
-
- *((ushort *)skb_put(*skb, 2)) = chan->callref;
-
-#ifdef DEBUG
- printk(KERN_DEBUG "Call Reference: %04x\n", chan->callref);
-#endif
-
- *(skb_put(*skb, 1)) = 0; /* BC.Length = 0; */
- *(skb_put(*skb, 1)) = 0; /* ConnectedPN.Length = 0 */
- *(skb_put(*skb, 1)) = 0; /* PSA.Length */
- *(skb_put(*skb, 1)) = 0; /* LLC.Length = 0; */
- *(skb_put(*skb, 1)) = 0; /* HLC.Length = 0; */
- *(skb_put(*skb, 1)) = 0; /* UTUS.Length = 0; */
-
- return 8;
-}
-
-int capi_conn_active_resp(struct pcbit_chan *chan, struct sk_buff **skb)
-{
- /*
- * 2 bytes
- */
-
- if ((*skb = dev_alloc_skb(2)) == NULL) {
-
- printk(KERN_WARNING "capi_conn_active_resp: alloc_skb failed\n");
- return -1;
- }
-
- *((ushort *)skb_put(*skb, 2)) = chan->callref;
-
- return 2;
-}
-
-
-int capi_select_proto_req(struct pcbit_chan *chan, struct sk_buff **skb,
- int outgoing)
-{
-
- /*
- * 18 bytes
- */
-
- if ((*skb = dev_alloc_skb(18)) == NULL) {
-
- printk(KERN_WARNING "capi_select_proto_req: alloc_skb failed\n");
- return -1;
- }
-
- *((ushort *)skb_put(*skb, 2)) = chan->callref;
-
- /* Layer2 protocol */
-
- switch (chan->proto) {
- case ISDN_PROTO_L2_X75I:
- *(skb_put(*skb, 1)) = 0x05; /* LAPB */
- break;
- case ISDN_PROTO_L2_HDLC:
- *(skb_put(*skb, 1)) = 0x02;
- break;
- case ISDN_PROTO_L2_TRANS:
- /*
- * Voice (a-law)
- */
- *(skb_put(*skb, 1)) = 0x06;
- break;
- default:
-#ifdef DEBUG
- printk(KERN_DEBUG "Transparent\n");
-#endif
- *(skb_put(*skb, 1)) = 0x03;
- break;
- }
-
- *(skb_put(*skb, 1)) = (outgoing ? 0x02 : 0x42); /* Don't ask */
- *(skb_put(*skb, 1)) = 0x00;
-
- *((ushort *) skb_put(*skb, 2)) = MRU;
-
-
- *(skb_put(*skb, 1)) = 0x08; /* Modulo */
- *(skb_put(*skb, 1)) = 0x07; /* Max Window */
-
- *(skb_put(*skb, 1)) = 0x01; /* No Layer3 Protocol */
-
- /*
- * 2 - layer3 MTU [10]
- * - Modulo [12]
- * - Window
- * - layer1 proto [14]
- * - bitrate
- * - sub-channel [16]
- * - layer1dataformat [17]
- */
-
- memset(skb_put(*skb, 8), 0, 8);
-
- return 18;
-}
-
-
-int capi_activate_transp_req(struct pcbit_chan *chan, struct sk_buff **skb)
-{
-
- if ((*skb = dev_alloc_skb(7)) == NULL) {
-
- printk(KERN_WARNING "capi_activate_transp_req: alloc_skb failed\n");
- return -1;
- }
-
- *((ushort *)skb_put(*skb, 2)) = chan->callref;
-
-
- *(skb_put(*skb, 1)) = chan->layer2link; /* Layer2 id */
- *(skb_put(*skb, 1)) = 0x00; /* Transmit by default */
-
- *((ushort *) skb_put(*skb, 2)) = MRU;
-
- *(skb_put(*skb, 1)) = 0x01; /* Enables reception*/
-
- return 7;
-}
-
-int capi_tdata_req(struct pcbit_chan *chan, struct sk_buff *skb)
-{
- ushort data_len;
-
-
- /*
- * callref - 2
- * layer2link - 1
- * wBlockLength - 2
- * data - 4
- * sernum - 1
- */
-
- data_len = skb->len;
-
- if (skb_headroom(skb) < 10)
- {
- printk(KERN_CRIT "No headspace (%u) on headroom %p for capi header\n", skb_headroom(skb), skb);
- }
- else
- {
- skb_push(skb, 10);
- }
-
- *((u16 *) (skb->data)) = chan->callref;
- skb->data[2] = chan->layer2link;
- *((u16 *) (skb->data + 3)) = data_len;
-
- chan->s_refnum = (chan->s_refnum + 1) % 8;
- *((u32 *) (skb->data + 5)) = chan->s_refnum;
-
- skb->data[9] = 0; /* HDLC frame number */
-
- return 10;
-}
-
-int capi_tdata_resp(struct pcbit_chan *chan, struct sk_buff **skb)
-
-{
- if ((*skb = dev_alloc_skb(4)) == NULL) {
-
- printk(KERN_WARNING "capi_tdata_resp: alloc_skb failed\n");
- return -1;
- }
-
- *((ushort *)skb_put(*skb, 2)) = chan->callref;
-
- *(skb_put(*skb, 1)) = chan->layer2link;
- *(skb_put(*skb, 1)) = chan->r_refnum;
-
- return (*skb)->len;
-}
-
-int capi_disc_req(ushort callref, struct sk_buff **skb, u_char cause)
-{
-
- if ((*skb = dev_alloc_skb(6)) == NULL) {
-
- printk(KERN_WARNING "capi_disc_req: alloc_skb failed\n");
- return -1;
- }
-
- *((ushort *)skb_put(*skb, 2)) = callref;
-
- *(skb_put(*skb, 1)) = 2; /* Cause.Length = 2; */
- *(skb_put(*skb, 1)) = 0x80;
- *(skb_put(*skb, 1)) = 0x80 | cause;
-
- /*
- * Change it: we should send 'Sic transit gloria Mundi' here ;-)
- */
-
- *(skb_put(*skb, 1)) = 0; /* UTUS.Length = 0; */
-
- return 6;
-}
-
-int capi_disc_resp(struct pcbit_chan *chan, struct sk_buff **skb)
-{
- if ((*skb = dev_alloc_skb(2)) == NULL) {
-
- printk(KERN_WARNING "capi_disc_resp: alloc_skb failed\n");
- return -1;
- }
-
- *((ushort *)skb_put(*skb, 2)) = chan->callref;
-
- return 2;
-}
-
-
-/*
- * Decoding of CAPI messages
- *
- */
-
-int capi_decode_conn_ind(struct pcbit_chan *chan,
- struct sk_buff *skb,
- struct callb_data *info)
-{
- int CIlen, len;
-
- /* Call Reference [CAPI] */
- chan->callref = *((ushort *)skb->data);
- skb_pull(skb, 2);
-
-#ifdef DEBUG
- printk(KERN_DEBUG "Call Reference: %04x\n", chan->callref);
-#endif
-
- /* Channel Identification */
-
- /* Expect
- Len = 1
- Octect 3 = 0100 10CC - [ 7 Basic, 4 , 2-1 chan ]
- */
-
- CIlen = skb->data[0];
-#ifdef DEBUG
- if (CIlen == 1) {
-
- if (((skb->data[1]) & 0xFC) == 0x48)
- printk(KERN_DEBUG "decode_conn_ind: chan ok\n");
- printk(KERN_DEBUG "phyChan = %d\n", skb->data[1] & 0x03);
- }
- else
- printk(KERN_DEBUG "conn_ind: CIlen = %d\n", CIlen);
-#endif
- skb_pull(skb, CIlen + 1);
-
- /* Calling Party Number */
- /* An "additional service" as far as Portugal Telecom is concerned */
-
- len = skb->data[0];
-
- if (len > 0) {
- int count = 1;
-
-#ifdef DEBUG
- printk(KERN_DEBUG "CPN: Octect 3 %02x\n", skb->data[1]);
-#endif
- if ((skb->data[1] & 0x80) == 0)
- count = 2;
-
- if (!(info->data.setup.CallingPN = kmalloc(len - count + 1, GFP_ATOMIC)))
- return -1;
-
- skb_copy_from_linear_data_offset(skb, count + 1,
- info->data.setup.CallingPN,
- len - count);
- info->data.setup.CallingPN[len - count] = 0;
-
- }
- else {
- info->data.setup.CallingPN = NULL;
- printk(KERN_DEBUG "NULL CallingPN\n");
- }
-
- skb_pull(skb, len + 1);
-
- /* Calling Party Subaddress */
- skb_pull(skb, skb->data[0] + 1);
-
- /* Called Party Number */
-
- len = skb->data[0];
-
- if (len > 0) {
- int count = 1;
-
- if ((skb->data[1] & 0x80) == 0)
- count = 2;
-
- if (!(info->data.setup.CalledPN = kmalloc(len - count + 1, GFP_ATOMIC)))
- return -1;
-
- skb_copy_from_linear_data_offset(skb, count + 1,
- info->data.setup.CalledPN,
- len - count);
- info->data.setup.CalledPN[len - count] = 0;
-
- }
- else {
- info->data.setup.CalledPN = NULL;
- printk(KERN_DEBUG "NULL CalledPN\n");
- }
-
- skb_pull(skb, len + 1);
-
- /* Called Party Subaddress */
- skb_pull(skb, skb->data[0] + 1);
-
- /* LLC */
- skb_pull(skb, skb->data[0] + 1);
-
- /* HLC */
- skb_pull(skb, skb->data[0] + 1);
-
- /* U2U */
- skb_pull(skb, skb->data[0] + 1);
-
- return 0;
-}
-
-/*
- * returns errcode
- */
-
-int capi_decode_conn_conf(struct pcbit_chan *chan, struct sk_buff *skb,
- int *complete)
-{
- int errcode;
-
- chan->callref = *((ushort *)skb->data); /* Update CallReference */
- skb_pull(skb, 2);
-
- errcode = *((ushort *) skb->data); /* read errcode */
- skb_pull(skb, 2);
-
- *complete = *(skb->data);
- skb_pull(skb, 1);
-
- /* FIX ME */
- /* This is actually a firmware bug */
- if (!*complete)
- {
- printk(KERN_DEBUG "complete=%02x\n", *complete);
- *complete = 1;
- }
-
-
- /* Optional Bearer Capability */
- skb_pull(skb, *(skb->data) + 1);
-
- /* Channel Identification */
- skb_pull(skb, *(skb->data) + 1);
-
- /* High Layer Compatibility follows */
- skb_pull(skb, *(skb->data) + 1);
-
- return errcode;
-}
-
-int capi_decode_conn_actv_ind(struct pcbit_chan *chan, struct sk_buff *skb)
-{
- ushort len;
-#ifdef DEBUG
- char str[32];
-#endif
-
- /* Yet Another Bearer Capability */
- skb_pull(skb, *(skb->data) + 1);
-
-
- /* Connected Party Number */
- len = *(skb->data);
-
-#ifdef DEBUG
- if (len > 1 && len < 31) {
- skb_copy_from_linear_data_offset(skb, 2, str, len - 1);
- str[len] = 0;
- printk(KERN_DEBUG "Connected Party Number: %s\n", str);
- }
- else
- printk(KERN_DEBUG "actv_ind CPN len = %d\n", len);
-#endif
-
- skb_pull(skb, len + 1);
-
- /* Connected Subaddress */
- skb_pull(skb, *(skb->data) + 1);
-
- /* Low Layer Capability */
- skb_pull(skb, *(skb->data) + 1);
-
- /* High Layer Capability */
- skb_pull(skb, *(skb->data) + 1);
-
- return 0;
-}
-
-int capi_decode_conn_actv_conf(struct pcbit_chan *chan, struct sk_buff *skb)
-{
- ushort errcode;
-
- errcode = *((ushort *)skb->data);
- skb_pull(skb, 2);
-
- /* Channel Identification
- skb_pull(skb, skb->data[0] + 1);
- */
- return errcode;
-}
-
-
-int capi_decode_sel_proto_conf(struct pcbit_chan *chan, struct sk_buff *skb)
-{
- ushort errcode;
-
- chan->layer2link = *(skb->data);
- skb_pull(skb, 1);
-
- errcode = *((ushort *)skb->data);
- skb_pull(skb, 2);
-
- return errcode;
-}
-
-int capi_decode_actv_trans_conf(struct pcbit_chan *chan, struct sk_buff *skb)
-{
- ushort errcode;
-
- if (chan->layer2link != *(skb->data))
- printk("capi_decode_actv_trans_conf: layer2link doesn't match\n");
-
- skb_pull(skb, 1);
-
- errcode = *((ushort *)skb->data);
- skb_pull(skb, 2);
-
- return errcode;
-}
-
-int capi_decode_disc_ind(struct pcbit_chan *chan, struct sk_buff *skb)
-{
- ushort len;
-#ifdef DEBUG
- int i;
-#endif
- /* Cause */
-
- len = *(skb->data);
- skb_pull(skb, 1);
-
-#ifdef DEBUG
-
- for (i = 0; i < len; i++)
- printk(KERN_DEBUG "Cause Octect %d: %02x\n", i + 3,
- *(skb->data + i));
-#endif
-
- skb_pull(skb, len);
-
- return 0;
-}
-
-#ifdef DEBUG
-int capi_decode_debug_188(u_char *hdr, ushort hdrlen)
-{
- char str[64];
- int len;
-
- len = hdr[0];
-
- if (len < 64 && len == hdrlen - 1) {
- memcpy(str, hdr + 1, hdrlen - 1);
- str[hdrlen - 1] = 0;
- printk("%s\n", str);
- }
- else
- printk("debug message incorrect\n");
-
- return 0;
-}
-#endif
+++ /dev/null
-/*
- * CAPI encode/decode prototypes and defines
- *
- * Copyright (C) 1996 Universidade de Lisboa
- *
- * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
- *
- * This software may be used and distributed according to the terms of
- * the GNU General Public License, incorporated herein by reference.
- */
-
-#ifndef CAPI_H
-#define CAPI_H
-
-
-#define REQ_CAUSE 0x01
-#define REQ_DISPLAY 0x04
-#define REQ_USER_TO_USER 0x08
-
-#define AppInfoMask (REQ_CAUSE | REQ_DISPLAY | REQ_USER_TO_USER)
-
-/* Connection Setup */
-extern int capi_conn_req(const char *calledPN, struct sk_buff **buf,
- int proto);
-extern int capi_decode_conn_conf(struct pcbit_chan *chan, struct sk_buff *skb,
- int *complete);
-
-extern int capi_decode_conn_ind(struct pcbit_chan *chan, struct sk_buff *skb,
- struct callb_data *info);
-extern int capi_conn_resp(struct pcbit_chan *chan, struct sk_buff **skb);
-
-extern int capi_conn_active_req(struct pcbit_chan *chan, struct sk_buff **skb);
-extern int capi_decode_conn_actv_conf(struct pcbit_chan *chan,
- struct sk_buff *skb);
-
-extern int capi_decode_conn_actv_ind(struct pcbit_chan *chan,
- struct sk_buff *skb);
-extern int capi_conn_active_resp(struct pcbit_chan *chan,
- struct sk_buff **skb);
-
-/* Data */
-extern int capi_select_proto_req(struct pcbit_chan *chan, struct sk_buff **skb,
- int outgoing);
-extern int capi_decode_sel_proto_conf(struct pcbit_chan *chan,
- struct sk_buff *skb);
-
-extern int capi_activate_transp_req(struct pcbit_chan *chan,
- struct sk_buff **skb);
-extern int capi_decode_actv_trans_conf(struct pcbit_chan *chan,
- struct sk_buff *skb);
-
-extern int capi_tdata_req(struct pcbit_chan *chan, struct sk_buff *skb);
-extern int capi_tdata_resp(struct pcbit_chan *chan, struct sk_buff **skb);
-
-/* Connection Termination */
-extern int capi_disc_req(ushort callref, struct sk_buff **skb, u_char cause);
-
-extern int capi_decode_disc_ind(struct pcbit_chan *chan, struct sk_buff *skb);
-extern int capi_disc_resp(struct pcbit_chan *chan, struct sk_buff **skb);
-
-#ifdef DEBUG
-extern int capi_decode_debug_188(u_char *hdr, ushort hdrlen);
-#endif
-
-static inline struct pcbit_chan *
-capi_channel(struct pcbit_dev *dev, struct sk_buff *skb)
-{
- ushort callref;
-
- callref = *((ushort *)skb->data);
- skb_pull(skb, 2);
-
- if (dev->b1->callref == callref)
- return dev->b1;
- else if (dev->b2->callref == callref)
- return dev->b2;
-
- return NULL;
-}
-
-#endif
+++ /dev/null
-/*
- * PCBIT-D interface with isdn4linux
- *
- * Copyright (C) 1996 Universidade de Lisboa
- *
- * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
- *
- * This software may be used and distributed according to the terms of
- * the GNU General Public License, incorporated herein by reference.
- */
-
-/*
- * Fixes:
- *
- * Nuno Grilo <l38486@alfa.ist.utl.pt>
- * fixed msn_list NULL pointer dereference.
- *
- */
-
-#include <linux/module.h>
-
-
-#include <linux/kernel.h>
-
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/skbuff.h>
-
-#include <linux/isdnif.h>
-#include <linux/string.h>
-#include <linux/io.h>
-#include <linux/ioport.h>
-
-#include "pcbit.h"
-#include "edss1.h"
-#include "layer2.h"
-#include "capi.h"
-
-
-extern ushort last_ref_num;
-
-static int pcbit_ioctl(isdn_ctrl *ctl);
-
-static char *pcbit_devname[MAX_PCBIT_CARDS] = {
- "pcbit0",
- "pcbit1",
- "pcbit2",
- "pcbit3"
-};
-
-/*
- * prototypes
- */
-
-static int pcbit_command(isdn_ctrl *ctl);
-static int pcbit_stat(u_char __user *buf, int len, int, int);
-static int pcbit_xmit(int driver, int chan, int ack, struct sk_buff *skb);
-static int pcbit_writecmd(const u_char __user *, int, int, int);
-
-static int set_protocol_running(struct pcbit_dev *dev);
-
-static void pcbit_clear_msn(struct pcbit_dev *dev);
-static void pcbit_set_msn(struct pcbit_dev *dev, char *list);
-static int pcbit_check_msn(struct pcbit_dev *dev, char *msn);
-
-
-int pcbit_init_dev(int board, int mem_base, int irq)
-{
- struct pcbit_dev *dev;
- isdn_if *dev_if;
-
- if ((dev = kzalloc(sizeof(struct pcbit_dev), GFP_KERNEL)) == NULL)
- {
- printk("pcbit_init: couldn't malloc pcbit_dev struct\n");
- return -ENOMEM;
- }
-
- dev_pcbit[board] = dev;
- init_waitqueue_head(&dev->set_running_wq);
- spin_lock_init(&dev->lock);
-
- if (mem_base >= 0xA0000 && mem_base <= 0xFFFFF) {
- dev->ph_mem = mem_base;
- if (!request_mem_region(dev->ph_mem, 4096, "PCBIT mem")) {
- printk(KERN_WARNING
- "PCBIT: memory region %lx-%lx already in use\n",
- dev->ph_mem, dev->ph_mem + 4096);
- kfree(dev);
- dev_pcbit[board] = NULL;
- return -EACCES;
- }
- dev->sh_mem = ioremap(dev->ph_mem, 4096);
- }
- else
- {
- printk("memory address invalid");
- kfree(dev);
- dev_pcbit[board] = NULL;
- return -EACCES;
- }
-
- dev->b1 = kzalloc(sizeof(struct pcbit_chan), GFP_KERNEL);
- if (!dev->b1) {
- printk("pcbit_init: couldn't malloc pcbit_chan struct\n");
- iounmap(dev->sh_mem);
- release_mem_region(dev->ph_mem, 4096);
- kfree(dev);
- return -ENOMEM;
- }
-
- dev->b2 = kzalloc(sizeof(struct pcbit_chan), GFP_KERNEL);
- if (!dev->b2) {
- printk("pcbit_init: couldn't malloc pcbit_chan struct\n");
- kfree(dev->b1);
- iounmap(dev->sh_mem);
- release_mem_region(dev->ph_mem, 4096);
- kfree(dev);
- return -ENOMEM;
- }
-
- dev->b2->id = 1;
-
- INIT_WORK(&dev->qdelivery, pcbit_deliver);
-
- /*
- * interrupts
- */
-
- if (request_irq(irq, &pcbit_irq_handler, 0, pcbit_devname[board], dev) != 0)
- {
- kfree(dev->b1);
- kfree(dev->b2);
- iounmap(dev->sh_mem);
- release_mem_region(dev->ph_mem, 4096);
- kfree(dev);
- dev_pcbit[board] = NULL;
- return -EIO;
- }
-
- dev->irq = irq;
-
- /* next frame to be received */
- dev->rcv_seq = 0;
- dev->send_seq = 0;
- dev->unack_seq = 0;
-
- dev->hl_hdrlen = 16;
-
- dev_if = kmalloc(sizeof(isdn_if), GFP_KERNEL);
-
- if (!dev_if) {
- free_irq(irq, dev);
- kfree(dev->b1);
- kfree(dev->b2);
- iounmap(dev->sh_mem);
- release_mem_region(dev->ph_mem, 4096);
- kfree(dev);
- dev_pcbit[board] = NULL;
- return -EIO;
- }
-
- dev->dev_if = dev_if;
-
- dev_if->owner = THIS_MODULE;
-
- dev_if->channels = 2;
-
- dev_if->features = (ISDN_FEATURE_P_EURO | ISDN_FEATURE_L3_TRANS |
- ISDN_FEATURE_L2_HDLC | ISDN_FEATURE_L2_TRANS);
-
- dev_if->writebuf_skb = pcbit_xmit;
- dev_if->hl_hdrlen = 16;
-
- dev_if->maxbufsize = MAXBUFSIZE;
- dev_if->command = pcbit_command;
-
- dev_if->writecmd = pcbit_writecmd;
- dev_if->readstat = pcbit_stat;
-
-
- strcpy(dev_if->id, pcbit_devname[board]);
-
- if (!register_isdn(dev_if)) {
- free_irq(irq, dev);
- kfree(dev->b1);
- kfree(dev->b2);
- iounmap(dev->sh_mem);
- release_mem_region(dev->ph_mem, 4096);
- kfree(dev);
- dev_pcbit[board] = NULL;
- return -EIO;
- }
-
- dev->id = dev_if->channels;
-
-
- dev->l2_state = L2_DOWN;
- dev->free = 511;
-
- /*
- * set_protocol_running(dev);
- */
-
- return 0;
-}
-
-#ifdef MODULE
-void pcbit_terminate(int board)
-{
- struct pcbit_dev *dev;
-
- dev = dev_pcbit[board];
-
- if (dev) {
- /* unregister_isdn(dev->dev_if); */
- free_irq(dev->irq, dev);
- pcbit_clear_msn(dev);
- kfree(dev->dev_if);
- if (dev->b1->fsm_timer.function)
- del_timer(&dev->b1->fsm_timer);
- if (dev->b2->fsm_timer.function)
- del_timer(&dev->b2->fsm_timer);
- kfree(dev->b1);
- kfree(dev->b2);
- iounmap(dev->sh_mem);
- release_mem_region(dev->ph_mem, 4096);
- kfree(dev);
- }
-}
-#endif
-
-static int pcbit_command(isdn_ctrl *ctl)
-{
- struct pcbit_dev *dev;
- struct pcbit_chan *chan;
- struct callb_data info;
-
- dev = finddev(ctl->driver);
-
- if (!dev)
- {
- printk("pcbit_command: unknown device\n");
- return -1;
- }
-
- chan = (ctl->arg & 0x0F) ? dev->b2 : dev->b1;
-
-
- switch (ctl->command) {
- case ISDN_CMD_IOCTL:
- return pcbit_ioctl(ctl);
- break;
- case ISDN_CMD_DIAL:
- info.type = EV_USR_SETUP_REQ;
- info.data.setup.CalledPN = (char *) &ctl->parm.setup.phone;
- pcbit_fsm_event(dev, chan, EV_USR_SETUP_REQ, &info);
- break;
- case ISDN_CMD_ACCEPTD:
- pcbit_fsm_event(dev, chan, EV_USR_SETUP_RESP, NULL);
- break;
- case ISDN_CMD_ACCEPTB:
- printk("ISDN_CMD_ACCEPTB - not really needed\n");
- break;
- case ISDN_CMD_HANGUP:
- pcbit_fsm_event(dev, chan, EV_USR_RELEASE_REQ, NULL);
- break;
- case ISDN_CMD_SETL2:
- chan->proto = (ctl->arg >> 8);
- break;
- case ISDN_CMD_CLREAZ:
- pcbit_clear_msn(dev);
- break;
- case ISDN_CMD_SETEAZ:
- pcbit_set_msn(dev, ctl->parm.num);
- break;
- case ISDN_CMD_SETL3:
- if ((ctl->arg >> 8) != ISDN_PROTO_L3_TRANS)
- printk(KERN_DEBUG "L3 protocol unknown\n");
- break;
- default:
- printk(KERN_DEBUG "pcbit_command: unknown command\n");
- break;
- }
-
- return 0;
-}
-
-/*
- * Another Hack :-(
- * on some conditions the board stops sending TDATA_CONFs
- * let's see if we can turn around the problem
- */
-
-#ifdef BLOCK_TIMER
-static void pcbit_block_timer(unsigned long data)
-{
- struct pcbit_chan *chan;
- struct pcbit_dev *dev;
- isdn_ctrl ictl;
-
- chan = (struct pcbit_chan *)data;
-
- dev = chan2dev(chan);
-
- if (dev == NULL) {
- printk(KERN_DEBUG "pcbit: chan2dev failed\n");
- return;
- }
-
- del_timer(&chan->block_timer);
- chan->block_timer.function = NULL;
-
-#ifdef DEBUG
- printk(KERN_DEBUG "pcbit_block_timer\n");
-#endif
- chan->queued = 0;
- ictl.driver = dev->id;
- ictl.command = ISDN_STAT_BSENT;
- ictl.arg = chan->id;
- dev->dev_if->statcallb(&ictl);
-}
-#endif
-
-static int pcbit_xmit(int driver, int chnum, int ack, struct sk_buff *skb)
-{
- ushort hdrlen;
- int refnum, len;
- struct pcbit_chan *chan;
- struct pcbit_dev *dev;
-
- dev = finddev(driver);
- if (dev == NULL)
- {
- printk("finddev returned NULL");
- return -1;
- }
-
- chan = chnum ? dev->b2 : dev->b1;
-
-
- if (chan->fsm_state != ST_ACTIVE)
- return -1;
-
- if (chan->queued >= MAX_QUEUED)
- {
-#ifdef DEBUG_QUEUE
- printk(KERN_DEBUG
- "pcbit: %d packets already in queue - write fails\n",
- chan->queued);
-#endif
- /*
- * packet stays on the head of the device queue
- * since dev_start_xmit will fail
- * see net/core/dev.c
- */
-#ifdef BLOCK_TIMER
- if (chan->block_timer.function == NULL) {
- setup_timer(&chan->block_timer, &pcbit_block_timer,
- (long)chan);
- mod_timer(&chan->block_timer, jiffies + 1 * HZ);
- }
-#endif
- return 0;
- }
-
-
- chan->queued++;
-
- len = skb->len;
-
- hdrlen = capi_tdata_req(chan, skb);
-
- refnum = last_ref_num++ & 0x7fffU;
- chan->s_refnum = refnum;
-
- pcbit_l2_write(dev, MSG_TDATA_REQ, refnum, skb, hdrlen);
-
- return len;
-}
-
-static int pcbit_writecmd(const u_char __user *buf, int len, int driver, int channel)
-{
- struct pcbit_dev *dev;
- int i, j;
- const u_char *loadbuf;
- u_char *ptr = NULL;
- u_char *cbuf;
-
- int errstat;
-
- dev = finddev(driver);
-
- if (!dev)
- {
- printk("pcbit_writecmd: couldn't find device");
- return -ENODEV;
- }
-
- switch (dev->l2_state) {
- case L2_LWMODE:
- /* check (size <= rdp_size); write buf into board */
- if (len < 0 || len > BANK4 + 1 || len > 1024)
- {
- printk("pcbit_writecmd: invalid length %d\n", len);
- return -EINVAL;
- }
-
- cbuf = memdup_user(buf, len);
- if (IS_ERR(cbuf))
- return PTR_ERR(cbuf);
-
- memcpy_toio(dev->sh_mem, cbuf, len);
- kfree(cbuf);
- return len;
- case L2_FWMODE:
- /* this is the hard part */
- /* dumb board */
- /* get it into kernel space */
- if ((ptr = kmalloc(len, GFP_KERNEL)) == NULL)
- return -ENOMEM;
- if (copy_from_user(ptr, buf, len)) {
- kfree(ptr);
- return -EFAULT;
- }
- loadbuf = ptr;
-
- errstat = 0;
-
- for (i = 0; i < len; i++)
- {
- for (j = 0; j < LOAD_RETRY; j++)
- if (!(readb(dev->sh_mem + dev->loadptr)))
- break;
-
- if (j == LOAD_RETRY)
- {
- errstat = -ETIME;
- printk("TIMEOUT i=%d\n", i);
- break;
- }
- writeb(loadbuf[i], dev->sh_mem + dev->loadptr + 1);
- writeb(0x01, dev->sh_mem + dev->loadptr);
-
- dev->loadptr += 2;
- if (dev->loadptr > LOAD_ZONE_END)
- dev->loadptr = LOAD_ZONE_START;
- }
- kfree(ptr);
-
- return errstat ? errstat : len;
- default:
- return -EBUSY;
- }
-}
-
-/*
- * demultiplexing of messages
- *
- */
-
-void pcbit_l3_receive(struct pcbit_dev *dev, ulong msg,
- struct sk_buff *skb,
- ushort hdr_len, ushort refnum)
-{
- struct pcbit_chan *chan;
- struct sk_buff *skb2;
- unsigned short len;
- struct callb_data cbdata;
- int complete, err;
- isdn_ctrl ictl;
-
- switch (msg) {
-
- case MSG_TDATA_IND:
- if (!(chan = capi_channel(dev, skb))) {
- printk(KERN_WARNING
- "CAPI header: unknown channel id\n");
- break;
- }
- chan->r_refnum = skb->data[7];
- skb_pull(skb, 8);
-
- dev->dev_if->rcvcallb_skb(dev->id, chan->id, skb);
-
- if (capi_tdata_resp(chan, &skb2) > 0)
- pcbit_l2_write(dev, MSG_TDATA_RESP, refnum,
- skb2, skb2->len);
- return;
- break;
- case MSG_TDATA_CONF:
- if (!(chan = capi_channel(dev, skb))) {
- printk(KERN_WARNING
- "CAPI header: unknown channel id\n");
- break;
- }
-
-#ifdef DEBUG
- if ((*((ushort *)(skb->data + 2))) != 0) {
- printk(KERN_DEBUG "TDATA_CONF error\n");
- }
-#endif
-#ifdef BLOCK_TIMER
- if (chan->queued == MAX_QUEUED) {
- del_timer(&chan->block_timer);
- chan->block_timer.function = NULL;
- }
-
-#endif
- chan->queued--;
-
- ictl.driver = dev->id;
- ictl.command = ISDN_STAT_BSENT;
- ictl.arg = chan->id;
- dev->dev_if->statcallb(&ictl);
- break;
-
- case MSG_CONN_IND:
- /*
- * channel: 1st not used will do
- * if both are used we're in trouble
- */
-
- if (!dev->b1->fsm_state)
- chan = dev->b1;
- else if (!dev->b2->fsm_state)
- chan = dev->b2;
- else {
- printk(KERN_INFO
- "Incoming connection: no channels available");
-
- if ((len = capi_disc_req(*(ushort *)(skb->data), &skb2, CAUSE_NOCHAN)) > 0)
- pcbit_l2_write(dev, MSG_DISC_REQ, refnum, skb2, len);
- break;
- }
-
- cbdata.data.setup.CalledPN = NULL;
- cbdata.data.setup.CallingPN = NULL;
-
- capi_decode_conn_ind(chan, skb, &cbdata);
- cbdata.type = EV_NET_SETUP;
-
- pcbit_fsm_event(dev, chan, EV_NET_SETUP, NULL);
-
- if (pcbit_check_msn(dev, cbdata.data.setup.CallingPN))
- pcbit_fsm_event(dev, chan, EV_USR_PROCED_REQ, &cbdata);
- else
- pcbit_fsm_event(dev, chan, EV_USR_RELEASE_REQ, NULL);
-
- kfree(cbdata.data.setup.CalledPN);
- kfree(cbdata.data.setup.CallingPN);
- break;
-
- case MSG_CONN_CONF:
- /*
- * We should be able to find the channel by the message
- * reference number. The current version of the firmware
- * doesn't sent the ref number correctly.
- */
-#ifdef DEBUG
- printk(KERN_DEBUG "refnum=%04x b1=%04x b2=%04x\n", refnum,
- dev->b1->s_refnum,
- dev->b2->s_refnum);
-#endif
- /* We just try to find a channel in the right state */
-
- if (dev->b1->fsm_state == ST_CALL_INIT)
- chan = dev->b1;
- else {
- if (dev->b2->s_refnum == ST_CALL_INIT)
- chan = dev->b2;
- else {
- chan = NULL;
- printk(KERN_WARNING "Connection Confirm - no channel in Call Init state\n");
- break;
- }
- }
- if (capi_decode_conn_conf(chan, skb, &complete)) {
- printk(KERN_DEBUG "conn_conf indicates error\n");
- pcbit_fsm_event(dev, chan, EV_ERROR, NULL);
- }
- else
- if (complete)
- pcbit_fsm_event(dev, chan, EV_NET_CALL_PROC, NULL);
- else
- pcbit_fsm_event(dev, chan, EV_NET_SETUP_ACK, NULL);
- break;
- case MSG_CONN_ACTV_IND:
-
- if (!(chan = capi_channel(dev, skb))) {
- printk(KERN_WARNING
- "CAPI header: unknown channel id\n");
- break;
- }
-
- if (capi_decode_conn_actv_ind(chan, skb)) {
- printk("error in capi_decode_conn_actv_ind\n");
- /* pcbit_fsm_event(dev, chan, EV_ERROR, NULL); */
- break;
- }
- chan->r_refnum = refnum;
- pcbit_fsm_event(dev, chan, EV_NET_CONN, NULL);
- break;
- case MSG_CONN_ACTV_CONF:
-
- if (!(chan = capi_channel(dev, skb))) {
- printk(KERN_WARNING
- "CAPI header: unknown channel id\n");
- break;
- }
-
- if (capi_decode_conn_actv_conf(chan, skb) == 0)
- pcbit_fsm_event(dev, chan, EV_NET_CONN_ACK, NULL);
-
- else
- printk(KERN_DEBUG "decode_conn_actv_conf failed\n");
- break;
-
- case MSG_SELP_CONF:
-
- if (!(chan = capi_channel(dev, skb))) {
- printk(KERN_WARNING
- "CAPI header: unknown channel id\n");
- break;
- }
-
- if (!(err = capi_decode_sel_proto_conf(chan, skb)))
- pcbit_fsm_event(dev, chan, EV_NET_SELP_RESP, NULL);
- else {
- /* Error */
- printk("error %d - capi_decode_sel_proto_conf\n", err);
- }
- break;
- case MSG_ACT_TRANSP_CONF:
- if (!(chan = capi_channel(dev, skb))) {
- printk(KERN_WARNING
- "CAPI header: unknown channel id\n");
- break;
- }
-
- if (!capi_decode_actv_trans_conf(chan, skb))
- pcbit_fsm_event(dev, chan, EV_NET_ACTV_RESP, NULL);
- break;
-
- case MSG_DISC_IND:
-
- if (!(chan = capi_channel(dev, skb))) {
- printk(KERN_WARNING
- "CAPI header: unknown channel id\n");
- break;
- }
-
- if (!capi_decode_disc_ind(chan, skb))
- pcbit_fsm_event(dev, chan, EV_NET_DISC, NULL);
- else
- printk(KERN_WARNING "capi_decode_disc_ind - error\n");
- break;
- case MSG_DISC_CONF:
- if (!(chan = capi_channel(dev, skb))) {
- printk(KERN_WARNING
- "CAPI header: unknown channel id\n");
- break;
- }
-
- if (!capi_decode_disc_ind(chan, skb))
- pcbit_fsm_event(dev, chan, EV_NET_RELEASE, NULL);
- else
- printk(KERN_WARNING "capi_decode_disc_conf - error\n");
- break;
- case MSG_INFO_IND:
-#ifdef DEBUG
- printk(KERN_DEBUG "received Info Indication - discarded\n");
-#endif
- break;
-#ifdef DEBUG
- case MSG_DEBUG_188:
- capi_decode_debug_188(skb->data, skb->len);
- break;
-
- default:
- printk(KERN_DEBUG "pcbit_l3_receive: unknown message %08lx\n",
- msg);
- break;
-#endif
- }
-
- kfree_skb(skb);
-
-}
-
-/*
- * Single statbuf
- * should be a statbuf per device
- */
-
-static char statbuf[STATBUF_LEN];
-static int stat_st;
-static int stat_end;
-
-static int pcbit_stat(u_char __user *buf, int len, int driver, int channel)
-{
- int stat_count;
- stat_count = stat_end - stat_st;
-
- if (stat_count < 0)
- stat_count = STATBUF_LEN - stat_st + stat_end;
-
- /* FIXME: should we sleep and wait for more cookies ? */
- if (len > stat_count)
- len = stat_count;
-
- if (stat_st < stat_end)
- {
- if (copy_to_user(buf, statbuf + stat_st, len))
- return -EFAULT;
- stat_st += len;
- }
- else
- {
- if (len > STATBUF_LEN - stat_st)
- {
- if (copy_to_user(buf, statbuf + stat_st,
- STATBUF_LEN - stat_st))
- return -EFAULT;
- if (copy_to_user(buf, statbuf,
- len - (STATBUF_LEN - stat_st)))
- return -EFAULT;
-
- stat_st = len - (STATBUF_LEN - stat_st);
- }
- else
- {
- if (copy_to_user(buf, statbuf + stat_st, len))
- return -EFAULT;
-
- stat_st += len;
-
- if (stat_st == STATBUF_LEN)
- stat_st = 0;
- }
- }
-
- if (stat_st == stat_end)
- stat_st = stat_end = 0;
-
- return len;
-}
-
-static void pcbit_logstat(struct pcbit_dev *dev, char *str)
-{
- int i;
- isdn_ctrl ictl;
-
- for (i = stat_end; i < strlen(str); i++)
- {
- statbuf[i] = str[i];
- stat_end = (stat_end + 1) % STATBUF_LEN;
- if (stat_end == stat_st)
- stat_st = (stat_st + 1) % STATBUF_LEN;
- }
-
- ictl.command = ISDN_STAT_STAVAIL;
- ictl.driver = dev->id;
- ictl.arg = strlen(str);
- dev->dev_if->statcallb(&ictl);
-}
-
-void pcbit_state_change(struct pcbit_dev *dev, struct pcbit_chan *chan,
- unsigned short i, unsigned short ev, unsigned short f)
-{
- char buf[256];
-
- sprintf(buf, "change on device: %d channel:%d\n%s -> %s -> %s\n",
- dev->id, chan->id,
- isdn_state_table[i], strisdnevent(ev), isdn_state_table[f]
- );
-
-#ifdef DEBUG
- printk("%s", buf);
-#endif
-
- pcbit_logstat(dev, buf);
-}
-
-static void set_running_timeout(unsigned long ptr)
-{
- struct pcbit_dev *dev;
-
-#ifdef DEBUG
- printk(KERN_DEBUG "set_running_timeout\n");
-#endif
- dev = (struct pcbit_dev *) ptr;
-
- dev->l2_state = L2_DOWN;
- wake_up_interruptible(&dev->set_running_wq);
-}
-
-static int set_protocol_running(struct pcbit_dev *dev)
-{
- isdn_ctrl ctl;
-
- setup_timer(&dev->set_running_timer, &set_running_timeout, (ulong)dev);
-
- /* kick it */
-
- dev->l2_state = L2_STARTING;
-
- writeb((0x80U | ((dev->rcv_seq & 0x07) << 3) | (dev->send_seq & 0x07)),
- dev->sh_mem + BANK4);
-
- mod_timer(&dev->set_running_timer, jiffies + SET_RUN_TIMEOUT);
-
- wait_event(dev->set_running_wq, dev->l2_state == L2_RUNNING ||
- dev->l2_state == L2_DOWN);
-
- del_timer(&dev->set_running_timer);
-
- if (dev->l2_state == L2_RUNNING)
- {
- printk(KERN_DEBUG "pcbit: running\n");
-
- dev->unack_seq = dev->send_seq;
-
- dev->writeptr = dev->sh_mem;
- dev->readptr = dev->sh_mem + BANK2;
-
- /* tell the good news to the upper layer */
- ctl.driver = dev->id;
- ctl.command = ISDN_STAT_RUN;
-
- dev->dev_if->statcallb(&ctl);
- }
- else
- {
- printk(KERN_DEBUG "pcbit: initialization failed\n");
- printk(KERN_DEBUG "pcbit: firmware not loaded\n");
-
-#ifdef DEBUG
- printk(KERN_DEBUG "Bank3 = %02x\n",
- readb(dev->sh_mem + BANK3));
-#endif
- writeb(0x40, dev->sh_mem + BANK4);
-
- /* warn the upper layer */
- ctl.driver = dev->id;
- ctl.command = ISDN_STAT_STOP;
-
- dev->dev_if->statcallb(&ctl);
-
- return -EL2HLT; /* Level 2 halted */
- }
-
- return 0;
-}
-
-static int pcbit_ioctl(isdn_ctrl *ctl)
-{
- struct pcbit_dev *dev;
- struct pcbit_ioctl *cmd;
-
- dev = finddev(ctl->driver);
-
- if (!dev)
- {
- printk(KERN_DEBUG "pcbit_ioctl: unknown device\n");
- return -ENODEV;
- }
-
- cmd = (struct pcbit_ioctl *) ctl->parm.num;
-
- switch (ctl->arg) {
- case PCBIT_IOCTL_GETSTAT:
- cmd->info.l2_status = dev->l2_state;
- break;
-
- case PCBIT_IOCTL_STRLOAD:
- if (dev->l2_state == L2_RUNNING)
- return -EBUSY;
-
- dev->unack_seq = dev->send_seq = dev->rcv_seq = 0;
-
- dev->writeptr = dev->sh_mem;
- dev->readptr = dev->sh_mem + BANK2;
-
- dev->l2_state = L2_LOADING;
- break;
-
- case PCBIT_IOCTL_LWMODE:
- if (dev->l2_state != L2_LOADING)
- return -EINVAL;
-
- dev->l2_state = L2_LWMODE;
- break;
-
- case PCBIT_IOCTL_FWMODE:
- if (dev->l2_state == L2_RUNNING)
- return -EBUSY;
- dev->loadptr = LOAD_ZONE_START;
- dev->l2_state = L2_FWMODE;
-
- break;
- case PCBIT_IOCTL_ENDLOAD:
- if (dev->l2_state == L2_RUNNING)
- return -EBUSY;
- dev->l2_state = L2_DOWN;
- break;
-
- case PCBIT_IOCTL_SETBYTE:
- if (dev->l2_state == L2_RUNNING)
- return -EBUSY;
-
- /* check addr */
- if (cmd->info.rdp_byte.addr > BANK4)
- return -EFAULT;
-
- writeb(cmd->info.rdp_byte.value, dev->sh_mem + cmd->info.rdp_byte.addr);
- break;
- case PCBIT_IOCTL_GETBYTE:
- if (dev->l2_state == L2_RUNNING)
- return -EBUSY;
-
- /* check addr */
-
- if (cmd->info.rdp_byte.addr > BANK4)
- {
- printk("getbyte: invalid addr %04x\n", cmd->info.rdp_byte.addr);
- return -EFAULT;
- }
-
- cmd->info.rdp_byte.value = readb(dev->sh_mem + cmd->info.rdp_byte.addr);
- break;
- case PCBIT_IOCTL_RUNNING:
- if (dev->l2_state == L2_RUNNING)
- return -EBUSY;
- return set_protocol_running(dev);
- break;
- case PCBIT_IOCTL_WATCH188:
- if (dev->l2_state != L2_LOADING)
- return -EINVAL;
- pcbit_l2_write(dev, MSG_WATCH188, 0x0001, NULL, 0);
- break;
- case PCBIT_IOCTL_PING188:
- if (dev->l2_state != L2_LOADING)
- return -EINVAL;
- pcbit_l2_write(dev, MSG_PING188_REQ, 0x0001, NULL, 0);
- break;
- case PCBIT_IOCTL_APION:
- if (dev->l2_state != L2_LOADING)
- return -EINVAL;
- pcbit_l2_write(dev, MSG_API_ON, 0x0001, NULL, 0);
- break;
- case PCBIT_IOCTL_STOP:
- dev->l2_state = L2_DOWN;
- writeb(0x40, dev->sh_mem + BANK4);
- dev->rcv_seq = 0;
- dev->send_seq = 0;
- dev->unack_seq = 0;
- break;
- default:
- printk("error: unknown ioctl\n");
- break;
- }
- return 0;
-}
-
-/*
- * MSN list handling
- *
- * if null reject all calls
- * if first entry has null MSN accept all calls
- */
-
-static void pcbit_clear_msn(struct pcbit_dev *dev)
-{
- struct msn_entry *ptr, *back;
-
- for (ptr = dev->msn_list; ptr;)
- {
- back = ptr->next;
- kfree(ptr);
- ptr = back;
- }
-
- dev->msn_list = NULL;
-}
-
-static void pcbit_set_msn(struct pcbit_dev *dev, char *list)
-{
- struct msn_entry *ptr;
- struct msn_entry *back = NULL;
- char *cp, *sp;
- int len;
-
- if (strlen(list) == 0) {
- ptr = kmalloc(sizeof(struct msn_entry), GFP_ATOMIC);
- if (!ptr) {
- printk(KERN_WARNING "kmalloc failed\n");
- return;
- }
-
- ptr->msn = NULL;
-
- ptr->next = dev->msn_list;
- dev->msn_list = ptr;
-
- return;
- }
-
- if (dev->msn_list)
- for (back = dev->msn_list; back->next; back = back->next);
-
- sp = list;
-
- do {
- cp = strchr(sp, ',');
- if (cp)
- len = cp - sp;
- else
- len = strlen(sp);
-
- ptr = kmalloc(sizeof(struct msn_entry), GFP_ATOMIC);
-
- if (!ptr) {
- printk(KERN_WARNING "kmalloc failed\n");
- return;
- }
- ptr->next = NULL;
-
- ptr->msn = kmalloc(len + 1, GFP_ATOMIC);
- if (!ptr->msn) {
- printk(KERN_WARNING "kmalloc failed\n");
- kfree(ptr);
- return;
- }
-
- memcpy(ptr->msn, sp, len);
- ptr->msn[len] = 0;
-
-#ifdef DEBUG
- printk(KERN_DEBUG "msn: %s\n", ptr->msn);
-#endif
- if (dev->msn_list == NULL)
- dev->msn_list = ptr;
- else
- back->next = ptr;
- back = ptr;
- sp += len;
- } while (cp);
-}
-
-/*
- * check if we do signal or reject an incoming call
- */
-static int pcbit_check_msn(struct pcbit_dev *dev, char *msn)
-{
- struct msn_entry *ptr;
-
- for (ptr = dev->msn_list; ptr; ptr = ptr->next) {
-
- if (ptr->msn == NULL)
- return 1;
-
- if (strcmp(ptr->msn, msn) == 0)
- return 1;
- }
-
- return 0;
-}
+++ /dev/null
-/*
- * DSS.1 Finite State Machine
- * base: ITU-T Rec Q.931
- *
- * Copyright (C) 1996 Universidade de Lisboa
- *
- * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
- *
- * This software may be used and distributed according to the terms of
- * the GNU General Public License, incorporated herein by reference.
- */
-
-/*
- * TODO: complete the FSM
- * move state/event descriptions to a user space logger
- */
-
-#include <linux/string.h>
-#include <linux/kernel.h>
-
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/skbuff.h>
-
-#include <linux/timer.h>
-#include <linux/io.h>
-
-#include <linux/isdnif.h>
-
-#include "pcbit.h"
-#include "edss1.h"
-#include "layer2.h"
-#include "callbacks.h"
-
-
-const char * const isdn_state_table[] = {
- "Closed",
- "Call initiated",
- "Overlap sending",
- "Outgoing call proceeding",
- "NOT DEFINED",
- "Call delivered",
- "Call present",
- "Call received",
- "Connect request",
- "Incoming call proceeding",
- "Active",
- "Disconnect request",
- "Disconnect indication",
- "NOT DEFINED",
- "NOT DEFINED",
- "Suspend request",
- "NOT DEFINED",
- "Resume request",
- "NOT DEFINED",
- "Release Request",
- "NOT DEFINED",
- "NOT DEFINED",
- "NOT DEFINED",
- "NOT DEFINED",
- "NOT DEFINED",
- "Overlap receiving",
- "Select protocol on B-Channel",
- "Activate B-channel protocol"
-};
-
-#ifdef DEBUG_ERRS
-static
-struct CauseValue {
- byte nr;
- char *descr;
-} cvlist[] = {
- {0x01, "Unallocated (unassigned) number"},
- {0x02, "No route to specified transit network"},
- {0x03, "No route to destination"},
- {0x04, "Send special information tone"},
- {0x05, "Misdialled trunk prefix"},
- {0x06, "Channel unacceptable"},
- {0x07, "Channel awarded and being delivered in an established channel"},
- {0x08, "Preemption"},
- {0x09, "Preemption - circuit reserved for reuse"},
- {0x10, "Normal call clearing"},
- {0x11, "User busy"},
- {0x12, "No user responding"},
- {0x13, "No answer from user (user alerted)"},
- {0x14, "Subscriber absent"},
- {0x15, "Call rejected"},
- {0x16, "Number changed"},
- {0x1a, "non-selected user clearing"},
- {0x1b, "Destination out of order"},
- {0x1c, "Invalid number format (address incomplete)"},
- {0x1d, "Facility rejected"},
- {0x1e, "Response to Status enquiry"},
- {0x1f, "Normal, unspecified"},
- {0x22, "No circuit/channel available"},
- {0x26, "Network out of order"},
- {0x27, "Permanent frame mode connection out-of-service"},
- {0x28, "Permanent frame mode connection operational"},
- {0x29, "Temporary failure"},
- {0x2a, "Switching equipment congestion"},
- {0x2b, "Access information discarded"},
- {0x2c, "Requested circuit/channel not available"},
- {0x2e, "Precedence call blocked"},
- {0x2f, "Resource unavailable, unspecified"},
- {0x31, "Quality of service unavailable"},
- {0x32, "Requested facility not subscribed"},
- {0x35, "Outgoing calls barred within CUG"},
- {0x37, "Incoming calls barred within CUG"},
- {0x39, "Bearer capability not authorized"},
- {0x3a, "Bearer capability not presently available"},
- {0x3e, "Inconsistency in designated outgoing access information and subscriber class"},
- {0x3f, "Service or option not available, unspecified"},
- {0x41, "Bearer capability not implemented"},
- {0x42, "Channel type not implemented"},
- {0x43, "Requested facility not implemented"},
- {0x44, "Only restricted digital information bearer capability is available"},
- {0x4f, "Service or option not implemented"},
- {0x51, "Invalid call reference value"},
- {0x52, "Identified channel does not exist"},
- {0x53, "A suspended call exists, but this call identity does not"},
- {0x54, "Call identity in use"},
- {0x55, "No call suspended"},
- {0x56, "Call having the requested call identity has been cleared"},
- {0x57, "User not member of CUG"},
- {0x58, "Incompatible destination"},
- {0x5a, "Non-existent CUG"},
- {0x5b, "Invalid transit network selection"},
- {0x5f, "Invalid message, unspecified"},
- {0x60, "Mandatory information element is missing"},
- {0x61, "Message type non-existent or not implemented"},
- {0x62, "Message not compatible with call state or message type non-existent or not implemented"},
- {0x63, "Information element/parameter non-existent or not implemented"},
- {0x64, "Invalid information element contents"},
- {0x65, "Message not compatible with call state"},
- {0x66, "Recovery on timer expiry"},
- {0x67, "Parameter non-existent or not implemented - passed on"},
- {0x6e, "Message with unrecognized parameter discarded"},
- {0x6f, "Protocol error, unspecified"},
- {0x7f, "Interworking, unspecified"}
-};
-
-#endif
-
-static struct isdn_event_desc {
- unsigned short ev;
- char *desc;
-} isdn_event_table[] = {
- {EV_USR_SETUP_REQ, "CC->L3: Setup Request"},
- {EV_USR_SETUP_RESP, "CC->L3: Setup Response"},
- {EV_USR_PROCED_REQ, "CC->L3: Proceeding Request"},
- {EV_USR_RELEASE_REQ, "CC->L3: Release Request"},
-
- {EV_NET_SETUP, "NET->TE: setup "},
- {EV_NET_CALL_PROC, "NET->TE: call proceeding"},
- {EV_NET_SETUP_ACK, "NET->TE: setup acknowledge (more info needed)"},
- {EV_NET_CONN, "NET->TE: connect"},
- {EV_NET_CONN_ACK, "NET->TE: connect acknowledge"},
- {EV_NET_DISC, "NET->TE: disconnect indication"},
- {EV_NET_RELEASE, "NET->TE: release"},
- {EV_NET_RELEASE_COMP, "NET->TE: release complete"},
- {EV_NET_SELP_RESP, "Board: Select B-channel protocol ack"},
- {EV_NET_ACTV_RESP, "Board: Activate B-channel protocol ack"},
- {EV_TIMER, "Timeout"},
- {0, "NULL"}
-};
-
-char *strisdnevent(ushort ev)
-{
- struct isdn_event_desc *entry;
-
- for (entry = isdn_event_table; entry->ev; entry++)
- if (entry->ev == ev)
- break;
-
- return entry->desc;
-}
-
-/*
- * Euro ISDN finite state machine
- */
-
-static struct fsm_timer_entry fsm_timers[] = {
- {ST_CALL_PROC, 10},
- {ST_DISC_REQ, 2},
- {ST_ACTIVE_SELP, 5},
- {ST_ACTIVE_ACTV, 5},
- {ST_INCM_PROC, 10},
- {ST_CONN_REQ, 2},
- {0xff, 0}
-};
-
-static struct fsm_entry fsm_table[] = {
-/* Connect Phase */
- /* Outgoing */
- {ST_NULL, ST_CALL_INIT, EV_USR_SETUP_REQ, cb_out_1},
-
- {ST_CALL_INIT, ST_OVER_SEND, EV_NET_SETUP_ACK, cb_notdone},
- {ST_CALL_INIT, ST_CALL_PROC, EV_NET_CALL_PROC, NULL},
- {ST_CALL_INIT, ST_NULL, EV_NET_DISC, cb_out_2},
-
- {ST_CALL_PROC, ST_ACTIVE_SELP, EV_NET_CONN, cb_out_2},
- {ST_CALL_PROC, ST_NULL, EV_NET_DISC, cb_disc_1},
- {ST_CALL_PROC, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
-
- /* Incoming */
- {ST_NULL, ST_CALL_PRES, EV_NET_SETUP, NULL},
-
- {ST_CALL_PRES, ST_INCM_PROC, EV_USR_PROCED_REQ, cb_in_1},
- {ST_CALL_PRES, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
-
- {ST_INCM_PROC, ST_CONN_REQ, EV_USR_SETUP_RESP, cb_in_2},
- {ST_INCM_PROC, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
-
- {ST_CONN_REQ, ST_ACTIVE_SELP, EV_NET_CONN_ACK, cb_in_3},
-
- /* Active */
- {ST_ACTIVE, ST_NULL, EV_NET_DISC, cb_disc_1},
- {ST_ACTIVE, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
- {ST_ACTIVE, ST_NULL, EV_NET_RELEASE, cb_disc_3},
-
- /* Disconnect */
-
- {ST_DISC_REQ, ST_NULL, EV_NET_DISC, cb_disc_1},
- {ST_DISC_REQ, ST_NULL, EV_NET_RELEASE, cb_disc_3},
-
- /* protocol selection */
- {ST_ACTIVE_SELP, ST_ACTIVE_ACTV, EV_NET_SELP_RESP, cb_selp_1},
- {ST_ACTIVE_SELP, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
-
- {ST_ACTIVE_ACTV, ST_ACTIVE, EV_NET_ACTV_RESP, cb_open},
- {ST_ACTIVE_ACTV, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
-
- /* Timers */
- {ST_CALL_PROC, ST_DISC_REQ, EV_TIMER, cb_disc_2},
- {ST_DISC_REQ, ST_NULL, EV_TIMER, cb_disc_3},
- {ST_ACTIVE_SELP, ST_DISC_REQ, EV_TIMER, cb_disc_2},
- {ST_ACTIVE_ACTV, ST_DISC_REQ, EV_TIMER, cb_disc_2},
- {ST_INCM_PROC, ST_DISC_REQ, EV_TIMER, cb_disc_2},
- {ST_CONN_REQ, ST_CONN_REQ, EV_TIMER, cb_in_2},
-
- {0xff, 0, 0, NULL}
-};
-
-
-static void pcbit_fsm_timer(unsigned long data)
-{
- struct pcbit_dev *dev;
- struct pcbit_chan *chan;
-
- chan = (struct pcbit_chan *) data;
-
- del_timer(&chan->fsm_timer);
- chan->fsm_timer.function = NULL;
-
- dev = chan2dev(chan);
-
- if (!dev) {
- printk(KERN_WARNING "pcbit: timer for unknown device\n");
- return;
- }
-
- pcbit_fsm_event(dev, chan, EV_TIMER, NULL);
-}
-
-
-void pcbit_fsm_event(struct pcbit_dev *dev, struct pcbit_chan *chan,
- unsigned short event, struct callb_data *data)
-{
- struct fsm_entry *action;
- struct fsm_timer_entry *tentry;
- unsigned long flags;
-
- spin_lock_irqsave(&dev->lock, flags);
-
- for (action = fsm_table; action->init != 0xff; action++)
- if (action->init == chan->fsm_state && action->event == event)
- break;
-
- if (action->init == 0xff) {
-
- spin_unlock_irqrestore(&dev->lock, flags);
- printk(KERN_DEBUG "fsm error: event %x on state %x\n",
- event, chan->fsm_state);
- return;
- }
-
- if (chan->fsm_timer.function) {
- del_timer(&chan->fsm_timer);
- chan->fsm_timer.function = NULL;
- }
-
- chan->fsm_state = action->final;
-
- pcbit_state_change(dev, chan, action->init, event, action->final);
-
- for (tentry = fsm_timers; tentry->init != 0xff; tentry++)
- if (tentry->init == chan->fsm_state)
- break;
-
- if (tentry->init != 0xff) {
- setup_timer(&chan->fsm_timer, &pcbit_fsm_timer, (ulong)chan);
- mod_timer(&chan->fsm_timer, jiffies + tentry->timeout * HZ);
- }
-
- spin_unlock_irqrestore(&dev->lock, flags);
-
- if (action->callb)
- action->callb(dev, chan, data);
-
-}
+++ /dev/null
-/*
- * DSS.1 module definitions
- *
- * Copyright (C) 1996 Universidade de Lisboa
- *
- * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
- *
- * This software may be used and distributed according to the terms of
- * the GNU General Public License, incorporated herein by reference.
- */
-
-#ifndef EDSS1_H
-#define EDSS1_H
-
-/* ISDN states */
-
-#define ST_NULL 0
-#define ST_CALL_INIT 1 /* Call initiated */
-#define ST_OVER_SEND 2 /* Overlap sending - Requests More Info 4 call */
-#define ST_CALL_PROC 3 /* Call Proceeding */
-#define ST_CALL_DELV 4
-#define ST_CALL_PRES 6 /* Call Present - Received CONN.IND */
-#define ST_CALL_RECV 7 /* Alerting sent */
-#define ST_CONN_REQ 8 /* Answered - waiting 4 CONN.CONF */
-#define ST_INCM_PROC 9
-#define ST_ACTIVE 10
-#define ST_DISC_REQ 11
-#define ST_DISC_IND 12
-#define ST_SUSP_REQ 15
-#define ST_RESM_REQ 17
-#define ST_RELS_REQ 19
-#define ST_OVER_RECV 25
-
-#define ST_ACTIVE_SELP 26 /* Select protocol on B-Channel */
-#define ST_ACTIVE_ACTV 27 /* Activate B-channel protocol */
-
-#define MAX_STATE ST_ACTIVE_ACTV
-
-#define EV_NULL 0
-#define EV_USR_SETUP_REQ 1
-#define EV_USR_SETUP_RESP 2
-#define EV_USR_PROCED_REQ 3
-#define EV_USR_RELEASE_REQ 4
-#define EV_USR_REJECT_REQ 4
-
-#define EV_NET_SETUP 16
-#define EV_NET_CALL_PROC 17
-#define EV_NET_SETUP_ACK 18
-#define EV_NET_CONN 19
-#define EV_NET_CONN_ACK 20
-
-#define EV_NET_SELP_RESP 21
-#define EV_NET_ACTV_RESP 22
-
-#define EV_NET_DISC 23
-#define EV_NET_RELEASE 24
-#define EV_NET_RELEASE_COMP 25
-
-#define EV_TIMER 26
-#define EV_ERROR 32
-
-/*
- * Cause values
- * only the ones we use
- */
-
-#define CAUSE_NORMAL 0x10U
-#define CAUSE_NOCHAN 0x22U
-
-struct callb_data {
- unsigned short type;
- union {
- struct ConnInfo {
- char *CalledPN;
- char *CallingPN;
- } setup;
- unsigned short cause;
- } data;
-};
-
-struct fsm_entry {
- unsigned short init;
- unsigned short final;
- unsigned short event;
- void (*callb)(struct pcbit_dev *, struct pcbit_chan *, struct callb_data*);
-};
-
-struct fsm_timer_entry {
- unsigned short init;
- unsigned long timeout; /* in seconds */
-};
-
-extern const char * const isdn_state_table[];
-
-void pcbit_fsm_event(struct pcbit_dev *, struct pcbit_chan *,
- unsigned short event, struct callb_data *);
-char *strisdnevent(ushort ev);
-
-#endif
+++ /dev/null
-/*
- * PCBIT-D low-layer interface
- *
- * Copyright (C) 1996 Universidade de Lisboa
- *
- * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
- *
- * This software may be used and distributed according to the terms of
- * the GNU General Public License, incorporated herein by reference.
- */
-
-/*
- * 19991203 - Fernando Carvalho - takion@superbofh.org
- * Hacked to compile with egcs and run with current version of isdn modules
- */
-
-/*
- * Based on documentation provided by Inesc:
- * - "Interface com bus do PC para o PCBIT e PCBIT-D", Inesc, Jan 93
- */
-
-/*
- * TODO: better handling of errors
- * re-write/remove debug printks
- */
-
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/workqueue.h>
-#include <linux/mm.h>
-#include <linux/skbuff.h>
-
-#include <linux/isdnif.h>
-
-#include <linux/io.h>
-
-
-#include "pcbit.h"
-#include "layer2.h"
-#include "edss1.h"
-
-#undef DEBUG_FRAG
-
-
-/*
- * Prototypes
- */
-
-static void pcbit_transmit(struct pcbit_dev *dev);
-
-static void pcbit_recv_ack(struct pcbit_dev *dev, unsigned char ack);
-
-static void pcbit_l2_error(struct pcbit_dev *dev);
-static void pcbit_l2_active_conf(struct pcbit_dev *dev, u_char info);
-static void pcbit_l2_err_recover(unsigned long data);
-
-static void pcbit_firmware_bug(struct pcbit_dev *dev);
-
-static __inline__ void
-pcbit_sched_delivery(struct pcbit_dev *dev)
-{
- schedule_work(&dev->qdelivery);
-}
-
-
-/*
- * Called from layer3
- */
-
-int
-pcbit_l2_write(struct pcbit_dev *dev, ulong msg, ushort refnum,
- struct sk_buff *skb, unsigned short hdr_len)
-{
- struct frame_buf *frame,
- *ptr;
- unsigned long flags;
-
- if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) {
- dev_kfree_skb(skb);
- return -1;
- }
- if ((frame = kmalloc(sizeof(struct frame_buf),
- GFP_ATOMIC)) == NULL) {
- dev_kfree_skb(skb);
- return -1;
- }
- frame->msg = msg;
- frame->refnum = refnum;
- frame->copied = 0;
- frame->hdr_len = hdr_len;
-
- if (skb)
- frame->dt_len = skb->len - hdr_len;
- else
- frame->dt_len = 0;
-
- frame->skb = skb;
-
- frame->next = NULL;
-
- spin_lock_irqsave(&dev->lock, flags);
-
- if (dev->write_queue == NULL) {
- dev->write_queue = frame;
- spin_unlock_irqrestore(&dev->lock, flags);
- pcbit_transmit(dev);
- } else {
- for (ptr = dev->write_queue; ptr->next; ptr = ptr->next);
- ptr->next = frame;
-
- spin_unlock_irqrestore(&dev->lock, flags);
- }
- return 0;
-}
-
-static __inline__ void
-pcbit_tx_update(struct pcbit_dev *dev, ushort len)
-{
- u_char info;
-
- dev->send_seq = (dev->send_seq + 1) % 8;
-
- dev->fsize[dev->send_seq] = len;
- info = 0;
- info |= dev->rcv_seq << 3;
- info |= dev->send_seq;
-
- writeb(info, dev->sh_mem + BANK4);
-
-}
-
-/*
- * called by interrupt service routine or by write_2
- */
-
-static void
-pcbit_transmit(struct pcbit_dev *dev)
-{
- struct frame_buf *frame = NULL;
- unsigned char unacked;
- int flen; /* fragment frame length including all headers */
- int free;
- int count,
- cp_len;
- unsigned long flags;
- unsigned short tt;
-
- if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING)
- return;
-
- unacked = (dev->send_seq + (8 - dev->unack_seq)) & 0x07;
-
- spin_lock_irqsave(&dev->lock, flags);
-
- if (dev->free > 16 && dev->write_queue && unacked < 7) {
-
- if (!dev->w_busy)
- dev->w_busy = 1;
- else {
- spin_unlock_irqrestore(&dev->lock, flags);
- return;
- }
-
-
- frame = dev->write_queue;
- free = dev->free;
-
- spin_unlock_irqrestore(&dev->lock, flags);
-
- if (frame->copied == 0) {
-
- /* Type 0 frame */
-
- ulong msg;
-
- if (frame->skb)
- flen = FRAME_HDR_LEN + PREHDR_LEN + frame->skb->len;
- else
- flen = FRAME_HDR_LEN + PREHDR_LEN;
-
- if (flen > free)
- flen = free;
-
- msg = frame->msg;
-
- /*
- * Board level 2 header
- */
-
- pcbit_writew(dev, flen - FRAME_HDR_LEN);
-
- pcbit_writeb(dev, GET_MSG_CPU(msg));
-
- pcbit_writeb(dev, GET_MSG_PROC(msg));
-
- /* TH */
- pcbit_writew(dev, frame->hdr_len + PREHDR_LEN);
-
- /* TD */
- pcbit_writew(dev, frame->dt_len);
-
-
- /*
- * Board level 3 fixed-header
- */
-
- /* LEN = TH */
- pcbit_writew(dev, frame->hdr_len + PREHDR_LEN);
-
- /* XX */
- pcbit_writew(dev, 0);
-
- /* C + S */
- pcbit_writeb(dev, GET_MSG_CMD(msg));
- pcbit_writeb(dev, GET_MSG_SCMD(msg));
-
- /* NUM */
- pcbit_writew(dev, frame->refnum);
-
- count = FRAME_HDR_LEN + PREHDR_LEN;
- } else {
- /* Type 1 frame */
-
- flen = 2 + (frame->skb->len - frame->copied);
-
- if (flen > free)
- flen = free;
-
- /* TT */
- tt = ((ushort) (flen - 2)) | 0x8000U; /* Type 1 */
- pcbit_writew(dev, tt);
-
- count = 2;
- }
-
- if (frame->skb) {
- cp_len = frame->skb->len - frame->copied;
- if (cp_len > flen - count)
- cp_len = flen - count;
-
- memcpy_topcbit(dev, frame->skb->data + frame->copied,
- cp_len);
- frame->copied += cp_len;
- }
- /* bookkeeping */
- dev->free -= flen;
- pcbit_tx_update(dev, flen);
-
- spin_lock_irqsave(&dev->lock, flags);
-
- if (frame->skb == NULL || frame->copied == frame->skb->len) {
-
- dev->write_queue = frame->next;
-
- if (frame->skb != NULL) {
- /* free frame */
- dev_kfree_skb(frame->skb);
- }
- kfree(frame);
- }
- dev->w_busy = 0;
- spin_unlock_irqrestore(&dev->lock, flags);
- } else {
- spin_unlock_irqrestore(&dev->lock, flags);
-#ifdef DEBUG
- printk(KERN_DEBUG "unacked %d free %d write_queue %s\n",
- unacked, dev->free, dev->write_queue ? "not empty" :
- "empty");
-#endif
- }
-}
-
-
-/*
- * deliver a queued frame to the upper layer
- */
-
-void
-pcbit_deliver(struct work_struct *work)
-{
- struct frame_buf *frame;
- unsigned long flags, msg;
- struct pcbit_dev *dev =
- container_of(work, struct pcbit_dev, qdelivery);
-
- spin_lock_irqsave(&dev->lock, flags);
-
- while ((frame = dev->read_queue)) {
- dev->read_queue = frame->next;
- spin_unlock_irqrestore(&dev->lock, flags);
-
- msg = 0;
- SET_MSG_CPU(msg, 0);
- SET_MSG_PROC(msg, 0);
- SET_MSG_CMD(msg, frame->skb->data[2]);
- SET_MSG_SCMD(msg, frame->skb->data[3]);
-
- frame->refnum = *((ushort *)frame->skb->data + 4);
- frame->msg = *((ulong *)&msg);
-
- skb_pull(frame->skb, 6);
-
- pcbit_l3_receive(dev, frame->msg, frame->skb, frame->hdr_len,
- frame->refnum);
-
- kfree(frame);
-
- spin_lock_irqsave(&dev->lock, flags);
- }
-
- spin_unlock_irqrestore(&dev->lock, flags);
-}
-
-/*
- * Reads BANK 2 & Reassembles
- */
-
-static void
-pcbit_receive(struct pcbit_dev *dev)
-{
- unsigned short tt;
- u_char cpu,
- proc;
- struct frame_buf *frame = NULL;
- unsigned long flags;
- u_char type1;
-
- if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING)
- return;
-
- tt = pcbit_readw(dev);
-
- if ((tt & 0x7fffU) > 511) {
- printk(KERN_INFO "pcbit: invalid frame length -> TT=%04x\n",
- tt);
- pcbit_l2_error(dev);
- return;
- }
- if (!(tt & 0x8000U)) { /* Type 0 */
- type1 = 0;
-
- if (dev->read_frame) {
- printk(KERN_DEBUG "pcbit_receive: Type 0 frame and read_frame != NULL\n");
- /* discard previous queued frame */
- kfree_skb(dev->read_frame->skb);
- kfree(dev->read_frame);
- dev->read_frame = NULL;
- }
- frame = kzalloc(sizeof(struct frame_buf), GFP_ATOMIC);
-
- if (frame == NULL) {
- printk(KERN_WARNING "kmalloc failed\n");
- return;
- }
-
- cpu = pcbit_readb(dev);
- proc = pcbit_readb(dev);
-
-
- if (cpu != 0x06 && cpu != 0x02) {
- printk(KERN_DEBUG "pcbit: invalid cpu value\n");
- kfree(frame);
- pcbit_l2_error(dev);
- return;
- }
- /*
- * we discard cpu & proc on receiving
- * but we read it to update the pointer
- */
-
- frame->hdr_len = pcbit_readw(dev);
- frame->dt_len = pcbit_readw(dev);
-
- /*
- * 0 sized packet
- * I don't know if they are an error or not...
- * But they are very frequent
- * Not documented
- */
-
- if (frame->hdr_len == 0) {
- kfree(frame);
-#ifdef DEBUG
- printk(KERN_DEBUG "0 sized frame\n");
-#endif
- pcbit_firmware_bug(dev);
- return;
- }
- /* sanity check the length values */
- if (frame->hdr_len > 1024 || frame->dt_len > 2048) {
-#ifdef DEBUG
- printk(KERN_DEBUG "length problem: ");
- printk(KERN_DEBUG "TH=%04x TD=%04x\n",
- frame->hdr_len,
- frame->dt_len);
-#endif
- pcbit_l2_error(dev);
- kfree(frame);
- return;
- }
- /* minimum frame read */
-
- frame->skb = dev_alloc_skb(frame->hdr_len + frame->dt_len +
- ((frame->hdr_len + 15) & ~15));
-
- if (!frame->skb) {
- printk(KERN_DEBUG "pcbit_receive: out of memory\n");
- kfree(frame);
- return;
- }
- /* 16 byte alignment for IP */
- if (frame->dt_len)
- skb_reserve(frame->skb, (frame->hdr_len + 15) & ~15);
-
- } else {
- /* Type 1 */
- type1 = 1;
- tt &= 0x7fffU;
-
- if (!(frame = dev->read_frame)) {
- printk("Type 1 frame and no frame queued\n");
- /* usually after an error: toss frame */
- dev->readptr += tt;
- if (dev->readptr > dev->sh_mem + BANK2 + BANKLEN)
- dev->readptr -= BANKLEN;
- return;
-
- }
- }
-
- memcpy_frompcbit(dev, skb_put(frame->skb, tt), tt);
-
- frame->copied += tt;
- spin_lock_irqsave(&dev->lock, flags);
- if (frame->copied == frame->hdr_len + frame->dt_len) {
-
- if (type1) {
- dev->read_frame = NULL;
- }
- if (dev->read_queue) {
- struct frame_buf *ptr;
- for (ptr = dev->read_queue; ptr->next; ptr = ptr->next);
- ptr->next = frame;
- } else
- dev->read_queue = frame;
-
- } else {
- dev->read_frame = frame;
- }
- spin_unlock_irqrestore(&dev->lock, flags);
-}
-
-/*
- * The board sends 0 sized frames
- * They are TDATA_CONFs that get messed up somehow
- * gotta send a fake acknowledgment to the upper layer somehow
- */
-
-static __inline__ void
-pcbit_fake_conf(struct pcbit_dev *dev, struct pcbit_chan *chan)
-{
- isdn_ctrl ictl;
-
- if (chan->queued) {
- chan->queued--;
-
- ictl.driver = dev->id;
- ictl.command = ISDN_STAT_BSENT;
- ictl.arg = chan->id;
- dev->dev_if->statcallb(&ictl);
- }
-}
-
-static void
-pcbit_firmware_bug(struct pcbit_dev *dev)
-{
- struct pcbit_chan *chan;
-
- chan = dev->b1;
-
- if (chan->fsm_state == ST_ACTIVE) {
- pcbit_fake_conf(dev, chan);
- }
- chan = dev->b2;
-
- if (chan->fsm_state == ST_ACTIVE) {
- pcbit_fake_conf(dev, chan);
- }
-}
-
-irqreturn_t
-pcbit_irq_handler(int interrupt, void *devptr)
-{
- struct pcbit_dev *dev;
- u_char info,
- ack_seq,
- read_seq;
-
- dev = (struct pcbit_dev *) devptr;
-
- if (!dev) {
- printk(KERN_WARNING "pcbit_irq_handler: wrong device\n");
- return IRQ_NONE;
- }
- if (dev->interrupt) {
- printk(KERN_DEBUG "pcbit: reentering interrupt handler\n");
- return IRQ_HANDLED;
- }
- dev->interrupt = 1;
-
- info = readb(dev->sh_mem + BANK3);
-
- if (dev->l2_state == L2_STARTING || dev->l2_state == L2_ERROR) {
- pcbit_l2_active_conf(dev, info);
- dev->interrupt = 0;
- return IRQ_HANDLED;
- }
- if (info & 0x40U) { /* E bit set */
-#ifdef DEBUG
- printk(KERN_DEBUG "pcbit_irq_handler: E bit on\n");
-#endif
- pcbit_l2_error(dev);
- dev->interrupt = 0;
- return IRQ_HANDLED;
- }
- if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) {
- dev->interrupt = 0;
- return IRQ_HANDLED;
- }
- ack_seq = (info >> 3) & 0x07U;
- read_seq = (info & 0x07U);
-
- dev->interrupt = 0;
-
- if (read_seq != dev->rcv_seq) {
- while (read_seq != dev->rcv_seq) {
- pcbit_receive(dev);
- dev->rcv_seq = (dev->rcv_seq + 1) % 8;
- }
- pcbit_sched_delivery(dev);
- }
- if (ack_seq != dev->unack_seq) {
- pcbit_recv_ack(dev, ack_seq);
- }
- info = dev->rcv_seq << 3;
- info |= dev->send_seq;
-
- writeb(info, dev->sh_mem + BANK4);
- return IRQ_HANDLED;
-}
-
-
-static void
-pcbit_l2_active_conf(struct pcbit_dev *dev, u_char info)
-{
- u_char state;
-
- state = dev->l2_state;
-
-#ifdef DEBUG
- printk(KERN_DEBUG "layer2_active_confirm\n");
-#endif
-
-
- if (info & 0x80U) {
- dev->rcv_seq = info & 0x07U;
- dev->l2_state = L2_RUNNING;
- } else
- dev->l2_state = L2_DOWN;
-
- if (state == L2_STARTING)
- wake_up_interruptible(&dev->set_running_wq);
-
- if (state == L2_ERROR && dev->l2_state == L2_RUNNING) {
- pcbit_transmit(dev);
- }
-}
-
-static void
-pcbit_l2_err_recover(unsigned long data)
-{
-
- struct pcbit_dev *dev;
- struct frame_buf *frame;
-
- dev = (struct pcbit_dev *) data;
-
- del_timer(&dev->error_recover_timer);
- if (dev->w_busy || dev->r_busy) {
- init_timer(&dev->error_recover_timer);
- dev->error_recover_timer.expires = jiffies + ERRTIME;
- add_timer(&dev->error_recover_timer);
- return;
- }
- dev->w_busy = dev->r_busy = 1;
-
- if (dev->read_frame) {
- kfree_skb(dev->read_frame->skb);
- kfree(dev->read_frame);
- dev->read_frame = NULL;
- }
- if (dev->write_queue) {
- frame = dev->write_queue;
-#ifdef FREE_ON_ERROR
- dev->write_queue = dev->write_queue->next;
-
- if (frame->skb) {
- dev_kfree_skb(frame->skb);
- }
- kfree(frame);
-#else
- frame->copied = 0;
-#endif
- }
- dev->rcv_seq = dev->send_seq = dev->unack_seq = 0;
- dev->free = 511;
- dev->l2_state = L2_ERROR;
-
- /* this is an hack... */
- pcbit_firmware_bug(dev);
-
- dev->writeptr = dev->sh_mem;
- dev->readptr = dev->sh_mem + BANK2;
-
- writeb((0x80U | ((dev->rcv_seq & 0x07) << 3) | (dev->send_seq & 0x07)),
- dev->sh_mem + BANK4);
- dev->w_busy = dev->r_busy = 0;
-
-}
-
-static void
-pcbit_l2_error(struct pcbit_dev *dev)
-{
- if (dev->l2_state == L2_RUNNING) {
-
- printk(KERN_INFO "pcbit: layer 2 error\n");
-
-#ifdef DEBUG
- log_state(dev);
-#endif
-
- dev->l2_state = L2_DOWN;
-
- setup_timer(&dev->error_recover_timer, &pcbit_l2_err_recover,
- (ulong)dev);
- mod_timer(&dev->error_recover_timer, jiffies + ERRTIME);
- }
-}
-
-/*
- * Description:
- * if board acks frames
- * update dev->free
- * call pcbit_transmit to write possible queued frames
- */
-
-static void
-pcbit_recv_ack(struct pcbit_dev *dev, unsigned char ack)
-{
- int i,
- count;
- int unacked;
-
- unacked = (dev->send_seq + (8 - dev->unack_seq)) & 0x07;
-
- /* dev->unack_seq < ack <= dev->send_seq; */
-
- if (unacked) {
-
- if (dev->send_seq > dev->unack_seq) {
- if (ack <= dev->unack_seq || ack > dev->send_seq) {
- printk(KERN_DEBUG
- "layer 2 ack unacceptable - dev %d",
- dev->id);
-
- pcbit_l2_error(dev);
- } else if (ack > dev->send_seq && ack <= dev->unack_seq) {
- printk(KERN_DEBUG
- "layer 2 ack unacceptable - dev %d",
- dev->id);
- pcbit_l2_error(dev);
- }
- }
- /* ack is acceptable */
-
-
- i = dev->unack_seq;
-
- do {
- dev->unack_seq = i = (i + 1) % 8;
- dev->free += dev->fsize[i];
- } while (i != ack);
-
- count = 0;
- while (count < 7 && dev->write_queue) {
- u8 lsend_seq = dev->send_seq;
-
- pcbit_transmit(dev);
-
- if (dev->send_seq == lsend_seq)
- break;
- count++;
- }
- } else
- printk(KERN_DEBUG "recv_ack: unacked = 0\n");
-}
+++ /dev/null
-/*
- * PCBIT-D low-layer interface definitions
- *
- * Copyright (C) 1996 Universidade de Lisboa
- *
- * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
- *
- * This software may be used and distributed according to the terms of
- * the GNU General Public License, incorporated herein by reference.
- */
-
-/*
- * 19991203 - Fernando Carvalho - takion@superbofh.org
- * Hacked to compile with egcs and run with current version of isdn modules
- */
-
-#ifndef LAYER2_H
-#define LAYER2_H
-
-#include <linux/interrupt.h>
-
-#include <asm/byteorder.h>
-
-#define BANK1 0x0000U /* PC -> Board */
-#define BANK2 0x01ffU /* Board -> PC */
-#define BANK3 0x03feU /* Att Board */
-#define BANK4 0x03ffU /* Att PC */
-
-#define BANKLEN 0x01FFU
-
-#define LOAD_ZONE_START 0x03f8U
-#define LOAD_ZONE_END 0x03fdU
-
-#define LOAD_RETRY 18000000
-
-
-
-/* TAM - XX - C - S - NUM */
-#define PREHDR_LEN 8
-/* TT - M - I - TH - TD */
-#define FRAME_HDR_LEN 8
-
-#define MSG_CONN_REQ 0x08000100
-#define MSG_CONN_CONF 0x00000101
-#define MSG_CONN_IND 0x00000102
-#define MSG_CONN_RESP 0x08000103
-
-#define MSG_CONN_ACTV_REQ 0x08000300
-#define MSG_CONN_ACTV_CONF 0x00000301
-#define MSG_CONN_ACTV_IND 0x00000302
-#define MSG_CONN_ACTV_RESP 0x08000303
-
-#define MSG_DISC_REQ 0x08000400
-#define MSG_DISC_CONF 0x00000401
-#define MSG_DISC_IND 0x00000402
-#define MSG_DISC_RESP 0x08000403
-
-#define MSG_TDATA_REQ 0x0908E200
-#define MSG_TDATA_CONF 0x0000E201
-#define MSG_TDATA_IND 0x0000E202
-#define MSG_TDATA_RESP 0x0908E203
-
-#define MSG_SELP_REQ 0x09004000
-#define MSG_SELP_CONF 0x00004001
-
-#define MSG_ACT_TRANSP_REQ 0x0908E000
-#define MSG_ACT_TRANSP_CONF 0x0000E001
-
-#define MSG_STPROT_REQ 0x09004100
-#define MSG_STPROT_CONF 0x00004101
-
-#define MSG_PING188_REQ 0x09030500
-#define MSG_PING188_CONF 0x000005bc
-
-#define MSG_WATCH188 0x09030400
-
-#define MSG_API_ON 0x08020102
-#define MSG_POOL_PCBIT 0x08020400
-#define MSG_POOL_PCBIT_CONF 0x00000401
-
-#define MSG_INFO_IND 0x00002602
-#define MSG_INFO_RESP 0x08002603
-
-#define MSG_DEBUG_188 0x0000ff00
-
-/*
-
- long 4 3 2 1
- Intel 1 2 3 4
-*/
-
-#ifdef __LITTLE_ENDIAN
-#define SET_MSG_SCMD(msg, ch) (msg = (msg & 0xffffff00) | (((ch) & 0xff)))
-#define SET_MSG_CMD(msg, ch) (msg = (msg & 0xffff00ff) | (((ch) & 0xff) << 8))
-#define SET_MSG_PROC(msg, ch) (msg = (msg & 0xff00ffff) | (((ch) & 0xff) << 16))
-#define SET_MSG_CPU(msg, ch) (msg = (msg & 0x00ffffff) | (((ch) & 0xff) << 24))
-
-#define GET_MSG_SCMD(msg) ((msg) & 0xFF)
-#define GET_MSG_CMD(msg) ((msg) >> 8 & 0xFF)
-#define GET_MSG_PROC(msg) ((msg) >> 16 & 0xFF)
-#define GET_MSG_CPU(msg) ((msg) >> 24)
-
-#else
-#error "Non-Intel CPU"
-#endif
-
-#define MAX_QUEUED 7
-
-#define SCHED_READ 0x01
-#define SCHED_WRITE 0x02
-
-#define SET_RUN_TIMEOUT (2 * HZ) /* 2 seconds */
-
-struct frame_buf {
- ulong msg;
- unsigned int refnum;
- unsigned int dt_len;
- unsigned int hdr_len;
- struct sk_buff *skb;
- unsigned int copied;
- struct frame_buf *next;
-};
-
-extern int pcbit_l2_write(struct pcbit_dev *dev, ulong msg, ushort refnum,
- struct sk_buff *skb, unsigned short hdr_len);
-
-extern irqreturn_t pcbit_irq_handler(int interrupt, void *);
-
-extern struct pcbit_dev *dev_pcbit[MAX_PCBIT_CARDS];
-
-#ifdef DEBUG
-static __inline__ void log_state(struct pcbit_dev *dev) {
- printk(KERN_DEBUG "writeptr = %ld\n",
- (ulong) (dev->writeptr - dev->sh_mem));
- printk(KERN_DEBUG "readptr = %ld\n",
- (ulong) (dev->readptr - (dev->sh_mem + BANK2)));
- printk(KERN_DEBUG "{rcv_seq=%01x, send_seq=%01x, unack_seq=%01x}\n",
- dev->rcv_seq, dev->send_seq, dev->unack_seq);
-}
-#endif
-
-static __inline__ struct pcbit_dev *chan2dev(struct pcbit_chan *chan)
-{
- struct pcbit_dev *dev;
- int i;
-
-
- for (i = 0; i < MAX_PCBIT_CARDS; i++)
- if ((dev = dev_pcbit[i]))
- if (dev->b1 == chan || dev->b2 == chan)
- return dev;
- return NULL;
-
-}
-
-static __inline__ struct pcbit_dev *finddev(int id)
-{
- struct pcbit_dev *dev;
- int i;
-
- for (i = 0; i < MAX_PCBIT_CARDS; i++)
- if ((dev = dev_pcbit[i]))
- if (dev->id == id)
- return dev;
- return NULL;
-}
-
-
-/*
- * Support routines for reading and writing in the board
- */
-
-static __inline__ void pcbit_writeb(struct pcbit_dev *dev, unsigned char dt)
-{
- writeb(dt, dev->writeptr++);
- if (dev->writeptr == dev->sh_mem + BANKLEN)
- dev->writeptr = dev->sh_mem;
-}
-
-static __inline__ void pcbit_writew(struct pcbit_dev *dev, unsigned short dt)
-{
- int dist;
-
- dist = BANKLEN - (dev->writeptr - dev->sh_mem);
- switch (dist) {
- case 2:
- writew(dt, dev->writeptr);
- dev->writeptr = dev->sh_mem;
- break;
- case 1:
- writeb((u_char) (dt & 0x00ffU), dev->writeptr);
- dev->writeptr = dev->sh_mem;
- writeb((u_char) (dt >> 8), dev->writeptr++);
- break;
- default:
- writew(dt, dev->writeptr);
- dev->writeptr += 2;
- break;
- };
-}
-
-static __inline__ void memcpy_topcbit(struct pcbit_dev *dev, u_char *data,
- int len)
-{
- int diff;
-
- diff = len - (BANKLEN - (dev->writeptr - dev->sh_mem));
-
- if (diff > 0)
- {
- memcpy_toio(dev->writeptr, data, len - diff);
- memcpy_toio(dev->sh_mem, data + (len - diff), diff);
- dev->writeptr = dev->sh_mem + diff;
- }
- else
- {
- memcpy_toio(dev->writeptr, data, len);
-
- dev->writeptr += len;
- if (diff == 0)
- dev->writeptr = dev->sh_mem;
- }
-}
-
-static __inline__ unsigned char pcbit_readb(struct pcbit_dev *dev)
-{
- unsigned char val;
-
- val = readb(dev->readptr++);
- if (dev->readptr == dev->sh_mem + BANK2 + BANKLEN)
- dev->readptr = dev->sh_mem + BANK2;
-
- return val;
-}
-
-static __inline__ unsigned short pcbit_readw(struct pcbit_dev *dev)
-{
- int dist;
- unsigned short val;
-
- dist = BANKLEN - (dev->readptr - (dev->sh_mem + BANK2));
- switch (dist) {
- case 2:
- val = readw(dev->readptr);
- dev->readptr = dev->sh_mem + BANK2;
- break;
- case 1:
- val = readb(dev->readptr);
- dev->readptr = dev->sh_mem + BANK2;
- val = (readb(dev->readptr++) << 8) | val;
- break;
- default:
- val = readw(dev->readptr);
- dev->readptr += 2;
- break;
- };
- return val;
-}
-
-static __inline__ void memcpy_frompcbit(struct pcbit_dev *dev, u_char *data, int len)
-{
- int diff;
-
- diff = len - (BANKLEN - (dev->readptr - (dev->sh_mem + BANK2)));
- if (diff > 0)
- {
- memcpy_fromio(data, dev->readptr, len - diff);
- memcpy_fromio(data + (len - diff), dev->sh_mem + BANK2 , diff);
- dev->readptr = dev->sh_mem + BANK2 + diff;
- }
- else
- {
- memcpy_fromio(data, dev->readptr, len);
- dev->readptr += len;
- if (diff == 0)
- dev->readptr = dev->sh_mem + BANK2;
- }
-}
-
-
-#endif
+++ /dev/null
-/*
- * PCBIT-D module support
- *
- * Copyright (C) 1996 Universidade de Lisboa
- *
- * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
- *
- * This software may be used and distributed according to the terms of
- * the GNU General Public License, incorporated herein by reference.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/skbuff.h>
-
-#include <linux/isdnif.h>
-#include "pcbit.h"
-
-MODULE_DESCRIPTION("ISDN4Linux: Driver for PCBIT-T card");
-MODULE_AUTHOR("Pedro Roque Marques");
-MODULE_LICENSE("GPL");
-
-static int mem[MAX_PCBIT_CARDS];
-static int irq[MAX_PCBIT_CARDS];
-
-module_param_array(mem, int, NULL, 0);
-module_param_array(irq, int, NULL, 0);
-
-static int num_boards;
-struct pcbit_dev *dev_pcbit[MAX_PCBIT_CARDS];
-
-static int __init pcbit_init(void)
-{
- int board;
-
- num_boards = 0;
-
- printk(KERN_NOTICE
- "PCBIT-D device driver v 0.5-fjpc0 19991204 - "
- "Copyright (C) 1996 Universidade de Lisboa\n");
-
- if (mem[0] || irq[0])
- {
- for (board = 0; board < MAX_PCBIT_CARDS && mem[board] && irq[board]; board++)
- {
- if (!mem[board])
- mem[board] = 0xD0000;
- if (!irq[board])
- irq[board] = 5;
-
- if (pcbit_init_dev(board, mem[board], irq[board]) == 0)
- num_boards++;
-
- else
- {
- printk(KERN_WARNING
- "pcbit_init failed for dev %d",
- board + 1);
- return -EIO;
- }
- }
- }
-
- /* Hardcoded default settings detection */
-
- if (!num_boards)
- {
- printk(KERN_INFO
- "Trying to detect board using default settings\n");
- if (pcbit_init_dev(0, 0xD0000, 5) == 0)
- num_boards++;
- else
- return -EIO;
- }
- return 0;
-}
-
-static void __exit pcbit_exit(void)
-{
-#ifdef MODULE
- int board;
-
- for (board = 0; board < num_boards; board++)
- pcbit_terminate(board);
- printk(KERN_NOTICE
- "PCBIT-D module unloaded\n");
-#endif
-}
-
-#ifndef MODULE
-#define MAX_PARA (MAX_PCBIT_CARDS * 2)
-static int __init pcbit_setup(char *line)
-{
- int i, j, argc;
- char *str;
- int ints[MAX_PARA + 1];
-
- str = get_options(line, MAX_PARA, ints);
- argc = ints[0];
- i = 0;
- j = 1;
-
- while (argc && (i < MAX_PCBIT_CARDS)) {
-
- if (argc) {
- mem[i] = ints[j];
- j++; argc--;
- }
-
- if (argc) {
- irq[i] = ints[j];
- j++; argc--;
- }
-
- i++;
- }
- return (1);
-}
-__setup("pcbit=", pcbit_setup);
-#endif
-
-module_init(pcbit_init);
-module_exit(pcbit_exit);
+++ /dev/null
-/*
- * PCBIT-D device driver definitions
- *
- * Copyright (C) 1996 Universidade de Lisboa
- *
- * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
- *
- * This software may be used and distributed according to the terms of
- * the GNU General Public License, incorporated herein by reference.
- */
-
-#ifndef PCBIT_H
-#define PCBIT_H
-
-#include <linux/workqueue.h>
-
-#define MAX_PCBIT_CARDS 4
-
-
-#define BLOCK_TIMER
-
-#ifdef __KERNEL__
-
-struct pcbit_chan {
- unsigned short id;
- unsigned short callref; /* Call Reference */
- unsigned char proto; /* layer2protocol */
- unsigned char queued; /* unacked data messages */
- unsigned char layer2link; /* used in TData */
- unsigned char snum; /* used in TData */
- unsigned short s_refnum;
- unsigned short r_refnum;
- unsigned short fsm_state;
- struct timer_list fsm_timer;
-#ifdef BLOCK_TIMER
- struct timer_list block_timer;
-#endif
-};
-
-struct msn_entry {
- char *msn;
- struct msn_entry *next;
-};
-
-struct pcbit_dev {
- /* board */
-
- volatile unsigned char __iomem *sh_mem; /* RDP address */
- unsigned long ph_mem;
- unsigned int irq;
- unsigned int id;
- unsigned int interrupt; /* set during interrupt
- processing */
- spinlock_t lock;
- /* isdn4linux */
-
- struct msn_entry *msn_list; /* ISDN address list */
-
- isdn_if *dev_if;
-
- ushort ll_hdrlen;
- ushort hl_hdrlen;
-
- /* link layer */
- unsigned char l2_state;
-
- struct frame_buf *read_queue;
- struct frame_buf *read_frame;
- struct frame_buf *write_queue;
-
- /* Protocol start */
- wait_queue_head_t set_running_wq;
- struct timer_list set_running_timer;
-
- struct timer_list error_recover_timer;
-
- struct work_struct qdelivery;
-
- u_char w_busy;
- u_char r_busy;
-
- volatile unsigned char __iomem *readptr;
- volatile unsigned char __iomem *writeptr;
-
- ushort loadptr;
-
- unsigned short fsize[8]; /* sent layer2 frames size */
-
- unsigned char send_seq;
- unsigned char rcv_seq;
- unsigned char unack_seq;
-
- unsigned short free;
-
- /* channels */
-
- struct pcbit_chan *b1;
- struct pcbit_chan *b2;
-};
-
-#define STATS_TIMER (10 * HZ)
-#define ERRTIME (HZ / 10)
-
-/* MRU */
-#define MAXBUFSIZE 1534
-#define MRU MAXBUFSIZE
-
-#define STATBUF_LEN 2048
-/*
- *
- */
-
-#endif /* __KERNEL__ */
-
-/* isdn_ctrl only allows a long sized argument */
-
-struct pcbit_ioctl {
- union {
- struct byte_op {
- ushort addr;
- ushort value;
- } rdp_byte;
- unsigned long l2_status;
- } info;
-};
-
-
-
-#define PCBIT_IOCTL_GETSTAT 0x01 /* layer2 status */
-#define PCBIT_IOCTL_LWMODE 0x02 /* linear write mode */
-#define PCBIT_IOCTL_STRLOAD 0x03 /* start load mode */
-#define PCBIT_IOCTL_ENDLOAD 0x04 /* end load mode */
-#define PCBIT_IOCTL_SETBYTE 0x05 /* set byte */
-#define PCBIT_IOCTL_GETBYTE 0x06 /* get byte */
-#define PCBIT_IOCTL_RUNNING 0x07 /* set protocol running */
-#define PCBIT_IOCTL_WATCH188 0x08 /* set watch 188 */
-#define PCBIT_IOCTL_PING188 0x09 /* ping 188 */
-#define PCBIT_IOCTL_FWMODE 0x0A /* firmware write mode */
-#define PCBIT_IOCTL_STOP 0x0B /* stop protocol */
-#define PCBIT_IOCTL_APION 0x0C /* issue API_ON */
-
-#ifndef __KERNEL__
-
-#define PCBIT_GETSTAT (PCBIT_IOCTL_GETSTAT + IIOCDRVCTL)
-#define PCBIT_LWMODE (PCBIT_IOCTL_LWMODE + IIOCDRVCTL)
-#define PCBIT_STRLOAD (PCBIT_IOCTL_STRLOAD + IIOCDRVCTL)
-#define PCBIT_ENDLOAD (PCBIT_IOCTL_ENDLOAD + IIOCDRVCTL)
-#define PCBIT_SETBYTE (PCBIT_IOCTL_SETBYTE + IIOCDRVCTL)
-#define PCBIT_GETBYTE (PCBIT_IOCTL_GETBYTE + IIOCDRVCTL)
-#define PCBIT_RUNNING (PCBIT_IOCTL_RUNNING + IIOCDRVCTL)
-#define PCBIT_WATCH188 (PCBIT_IOCTL_WATCH188 + IIOCDRVCTL)
-#define PCBIT_PING188 (PCBIT_IOCTL_PING188 + IIOCDRVCTL)
-#define PCBIT_FWMODE (PCBIT_IOCTL_FWMODE + IIOCDRVCTL)
-#define PCBIT_STOP (PCBIT_IOCTL_STOP + IIOCDRVCTL)
-#define PCBIT_APION (PCBIT_IOCTL_APION + IIOCDRVCTL)
-
-#define MAXSUPERLINE 3000
-
-#endif
-
-#define L2_DOWN 0
-#define L2_LOADING 1
-#define L2_LWMODE 2
-#define L2_FWMODE 3
-#define L2_STARTING 4
-#define L2_RUNNING 5
-#define L2_ERROR 6
-
-void pcbit_deliver(struct work_struct *work);
-int pcbit_init_dev(int board, int mem_base, int irq);
-void pcbit_terminate(int board);
-void pcbit_l3_receive(struct pcbit_dev *dev, ulong msg, struct sk_buff *skb,
- ushort hdr_len, ushort refnum);
-void pcbit_state_change(struct pcbit_dev *dev, struct pcbit_chan *chan,
- unsigned short i, unsigned short ev, unsigned short f);
-
-#endif
/*
- * ADIS16201 Programmable Digital Vibration Sensor driver
+ * ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer
*
* Copyright 2010 Analog Devices Inc.
*
module_spi_driver(adis16201_driver);
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
-MODULE_DESCRIPTION("Analog Devices ADIS16201 Programmable Digital Vibration Sensor driver");
+MODULE_DESCRIPTION("Analog Devices ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("spi:adis16201");
/*
- * ADIS16203 Programmable Digital Vibration Sensor driver
+ * ADIS16203 Programmable 360 Degrees Inclinometer
*
- * Copyright 2030 Analog Devices Inc.
+ * Copyright 2010 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
module_spi_driver(adis16203_driver);
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
-MODULE_DESCRIPTION("Analog Devices ADIS16203 Programmable Digital Vibration Sensor driver");
+MODULE_DESCRIPTION("Analog Devices ADIS16203 Programmable 360 Degrees Inclinometer");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("spi:adis16203");
/*
- * ADIS16209 Programmable Digital Vibration Sensor driver
+ * ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer
*
* Copyright 2010 Analog Devices Inc.
*
module_spi_driver(adis16209_driver);
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
-MODULE_DESCRIPTION("Analog Devices ADIS16209 Digital Vibration Sensor driver");
+MODULE_DESCRIPTION("Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("spi:adis16209");
#include "ad7606.h"
+/* Scales are computed as 2.5/2**16 and 5/2**16 respectively */
+static const unsigned int scale_avail[2][2] = {
+ {0, 38147}, {0, 76294}
+};
+
static int ad7606_reset(struct ad7606_state *st)
{
if (st->gpio_reset) {
*val = (short)ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
- *val = st->range * 2;
- *val2 = st->chip_info->channels[0].scan_type.realbits;
- return IIO_VAL_FRACTIONAL_LOG2;
+ *val = scale_avail[st->range][0];
+ *val2 = scale_avail[st->range][1];
+ return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
*val = st->oversampling;
return IIO_VAL_INT;
return -EINVAL;
}
-static ssize_t ad7606_show_range(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct ad7606_state *st = iio_priv(indio_dev);
-
- return sprintf(buf, "%u\n", st->range);
-}
-
-static ssize_t ad7606_store_range(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t in_voltage_scale_available_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct ad7606_state *st = iio_priv(indio_dev);
- unsigned long lval;
- int ret;
-
- ret = kstrtoul(buf, 10, &lval);
- if (ret)
- return ret;
+ int i, len = 0;
- if (!(lval == 5000 || lval == 10000))
- return -EINVAL;
+ for (i = 0; i < ARRAY_SIZE(scale_avail); i++)
+ len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%06u ",
+ scale_avail[i][0], scale_avail[i][1]);
- mutex_lock(&indio_dev->mlock);
- gpiod_set_value(st->gpio_range, lval == 10000);
- st->range = lval;
- mutex_unlock(&indio_dev->mlock);
+ buf[len - 1] = '\n';
- return count;
+ return len;
}
-static IIO_DEVICE_ATTR(in_voltage_range, S_IRUGO | S_IWUSR,
- ad7606_show_range, ad7606_store_range, 0);
-static IIO_CONST_ATTR(in_voltage_range_available, "5000 10000");
+static IIO_DEVICE_ATTR_RO(in_voltage_scale_available, 0);
static int ad7606_oversampling_get_index(unsigned int val)
{
{
struct ad7606_state *st = iio_priv(indio_dev);
int values[3];
- int ret;
+ int ret, i;
switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ ret = -EINVAL;
+ mutex_lock(&indio_dev->mlock);
+ for (i = 0; i < ARRAY_SIZE(scale_avail); i++)
+ if (val2 == scale_avail[i][1]) {
+ gpiod_set_value(st->gpio_range, i);
+ st->range = i;
+
+ ret = 0;
+ break;
+ }
+ mutex_unlock(&indio_dev->mlock);
+
+ return ret;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
if (val2)
return -EINVAL;
static IIO_CONST_ATTR(oversampling_ratio_available, "1 2 4 8 16 32 64");
static struct attribute *ad7606_attributes_os_and_range[] = {
- &iio_dev_attr_in_voltage_range.dev_attr.attr,
- &iio_const_attr_in_voltage_range_available.dev_attr.attr,
+ &iio_dev_attr_in_voltage_scale_available.dev_attr.attr,
&iio_const_attr_oversampling_ratio_available.dev_attr.attr,
NULL,
};
};
static struct attribute *ad7606_attributes_range[] = {
- &iio_dev_attr_in_voltage_range.dev_attr.attr,
- &iio_const_attr_in_voltage_range_available.dev_attr.attr,
+ &iio_dev_attr_in_voltage_scale_available.dev_attr.attr,
NULL,
};
static const struct iio_info ad7606_info_range = {
.driver_module = THIS_MODULE,
.read_raw = &ad7606_read_raw,
+ .write_raw = &ad7606_write_raw,
.attrs = &ad7606_attribute_group_range,
};
st->dev = dev;
st->bops = bops;
st->base_address = base_address;
- st->range = 5000;
+ /* tied to logic low, analog input range is +/- 5V */
+ st->range = 0;
st->oversampling = 1;
INIT_WORK(&st->poll_work, &ad7606_poll_bh_to_ring);
struct ad7606_state *st = iio_priv(indio_dev);
if (st->gpio_standby) {
- gpiod_set_value(st->gpio_range, st->range == 10000);
+ gpiod_set_value(st->gpio_range, st->range);
gpiod_set_value(st->gpio_standby, 1);
ad7606_reset(st);
}
return len;
}
-static IIO_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR,
+static IIO_DEVICE_ATTR(mode, 0644,
ad7816_show_mode,
ad7816_store_mode,
0);
return sprintf(buf, "full\npower-save\n");
}
-static IIO_DEVICE_ATTR(available_modes, S_IRUGO, ad7816_show_available_modes,
+static IIO_DEVICE_ATTR(available_modes, 0444, ad7816_show_available_modes,
NULL, 0);
static ssize_t ad7816_show_channel(struct device *dev,
return len;
}
-static IIO_DEVICE_ATTR(channel, S_IRUGO | S_IWUSR,
+static IIO_DEVICE_ATTR(channel, 0644,
ad7816_show_channel,
ad7816_store_channel,
0);
return sprintf(buf, "%u\n", data);
}
-static IIO_DEVICE_ATTR(value, S_IRUGO, ad7816_show_value, NULL, 0);
+static IIO_DEVICE_ATTR(value, 0444, ad7816_show_value, NULL, 0);
static struct attribute *ad7816_attributes[] = {
&iio_dev_attr_available_modes.dev_attr.attr,
return len;
}
-static IIO_DEVICE_ATTR(oti, S_IRUGO | S_IWUSR,
+static IIO_DEVICE_ATTR(oti, 0644,
ad7816_show_oti, ad7816_set_oti, 0);
static struct attribute *ad7816_event_attributes[] = {
*/
static int adt7316_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+ const struct i2c_device_id *id)
{
struct adt7316_bus bus = {
.client = client,
chip->dac_bits = 12;
else if (chip->id == ID_ADT7317 || chip->id == ID_ADT7517)
chip->dac_bits = 10;
- } else
+ } else {
config3 = chip->config3 & (~ADT7316_DA_HIGH_RESOLUTION);
+ }
ret = chip->bus.write(chip->bus.client, ADT7316_CONFIG3, config3);
if (ret)
error_ret:
mutex_unlock(&chip->state_lock);
- return 0;
+ return ret;
}
static int ad7150_read_event_value(struct iio_dev *indio_dev,
#define AD7150_TIMEOUT(chan, type, dir, ev_type, ev_dir) \
IIO_DEVICE_ATTR(in_capacitance##chan##_##type##_##dir##_timeout, \
- S_IRUGO | S_IWUSR, \
+ 0644, \
&ad7150_show_timeout, \
&ad7150_store_timeout, \
IIO_UNMOD_EVENT_CODE(IIO_CAPACITANCE, \
if (client->irq) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
- NULL,
- &ad7150_event_handler,
- IRQF_TRIGGER_RISING |
- IRQF_TRIGGER_FALLING |
- IRQF_ONESHOT,
- "ad7150_irq1",
- indio_dev);
+ NULL,
+ &ad7150_event_handler,
+ IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING |
+ IRQF_ONESHOT,
+ "ad7150_irq1",
+ indio_dev);
if (ret)
return ret;
}
if (client->dev.platform_data) {
ret = devm_request_threaded_irq(&client->dev, *(unsigned int *)
- client->dev.platform_data,
- NULL,
- &ad7150_event_handler,
- IRQF_TRIGGER_RISING |
- IRQF_TRIGGER_FALLING |
- IRQF_ONESHOT,
- "ad7150_irq2",
- indio_dev);
+ client->dev.platform_data,
+ NULL,
+ &ad7150_event_handler,
+ IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING |
+ IRQF_ONESHOT,
+ "ad7150_irq2",
+ indio_dev);
if (ret)
return ret;
}
#include <linux/iio/kfifo_buf.h>
/* AD5933/AD5934 Registers */
-#define AD5933_REG_CONTROL_HB 0x80 /* R/W, 2 bytes */
-#define AD5933_REG_CONTROL_LB 0x81 /* R/W, 2 bytes */
+#define AD5933_REG_CONTROL_HB 0x80 /* R/W, 1 byte */
+#define AD5933_REG_CONTROL_LB 0x81 /* R/W, 1 byte */
#define AD5933_REG_FREQ_START 0x82 /* R/W, 3 bytes */
#define AD5933_REG_FREQ_INC 0x85 /* R/W, 3 bytes */
#define AD5933_REG_INC_NUM 0x88 /* R/W, 2 bytes, 9 bit */
#include <linux/regmap.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
+#include <linux/pm_runtime.h>
-#define ISL29028_CONV_TIME_MS 100
+#define ISL29028_CONV_TIME_MS 100
-#define ISL29028_REG_CONFIGURE 0x01
+#define ISL29028_REG_CONFIGURE 0x01
-#define ISL29028_CONF_ALS_IR_MODE_ALS 0
-#define ISL29028_CONF_ALS_IR_MODE_IR BIT(0)
-#define ISL29028_CONF_ALS_IR_MODE_MASK BIT(0)
+#define ISL29028_CONF_ALS_IR_MODE_ALS 0
+#define ISL29028_CONF_ALS_IR_MODE_IR BIT(0)
+#define ISL29028_CONF_ALS_IR_MODE_MASK BIT(0)
-#define ISL29028_CONF_ALS_RANGE_LOW_LUX 0
+#define ISL29028_CONF_ALS_RANGE_LOW_LUX 0
#define ISL29028_CONF_ALS_RANGE_HIGH_LUX BIT(1)
-#define ISL29028_CONF_ALS_RANGE_MASK BIT(1)
+#define ISL29028_CONF_ALS_RANGE_MASK BIT(1)
-#define ISL29028_CONF_ALS_DIS 0
-#define ISL29028_CONF_ALS_EN BIT(2)
-#define ISL29028_CONF_ALS_EN_MASK BIT(2)
+#define ISL29028_CONF_ALS_DIS 0
+#define ISL29028_CONF_ALS_EN BIT(2)
+#define ISL29028_CONF_ALS_EN_MASK BIT(2)
-#define ISL29028_CONF_PROX_SLP_SH 4
-#define ISL29028_CONF_PROX_SLP_MASK (7 << ISL29028_CONF_PROX_SLP_SH)
+#define ISL29028_CONF_PROX_SLP_SH 4
+#define ISL29028_CONF_PROX_SLP_MASK (7 << ISL29028_CONF_PROX_SLP_SH)
-#define ISL29028_CONF_PROX_EN BIT(7)
-#define ISL29028_CONF_PROX_EN_MASK BIT(7)
+#define ISL29028_CONF_PROX_EN BIT(7)
+#define ISL29028_CONF_PROX_EN_MASK BIT(7)
-#define ISL29028_REG_INTERRUPT 0x02
+#define ISL29028_REG_INTERRUPT 0x02
-#define ISL29028_REG_PROX_DATA 0x08
-#define ISL29028_REG_ALSIR_L 0x09
-#define ISL29028_REG_ALSIR_U 0x0A
+#define ISL29028_REG_PROX_DATA 0x08
+#define ISL29028_REG_ALSIR_L 0x09
+#define ISL29028_REG_ALSIR_U 0x0A
-#define ISL29028_REG_TEST1_MODE 0x0E
-#define ISL29028_REG_TEST2_MODE 0x0F
+#define ISL29028_REG_TEST1_MODE 0x0E
+#define ISL29028_REG_TEST2_MODE 0x0F
-#define ISL29028_NUM_REGS (ISL29028_REG_TEST2_MODE + 1)
+#define ISL29028_NUM_REGS (ISL29028_REG_TEST2_MODE + 1)
+
+#define ISL29028_POWER_OFF_DELAY_MS 2000
enum isl29028_als_ir_mode {
ISL29028_MODE_NONE = 0,
};
struct isl29028_chip {
- struct mutex lock;
- struct regmap *regmap;
-
- unsigned int prox_sampling;
- bool enable_prox;
-
- int lux_scale;
+ struct mutex lock;
+ struct regmap *regmap;
+ unsigned int prox_sampling;
+ bool enable_prox;
+ int lux_scale;
enum isl29028_als_ir_mode als_ir_mode;
};
static int isl29028_set_proxim_sampling(struct isl29028_chip *chip,
unsigned int sampling)
{
+ struct device *dev = regmap_get_device(chip->regmap);
static unsigned int prox_period[] = {800, 400, 200, 100, 75, 50, 12, 0};
- int sel;
unsigned int period = DIV_ROUND_UP(1000, sampling);
+ int sel, ret;
for (sel = 0; sel < ARRAY_SIZE(prox_period); ++sel) {
if (period >= prox_period[sel])
break;
}
- return regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
- ISL29028_CONF_PROX_SLP_MASK,
- sel << ISL29028_CONF_PROX_SLP_SH);
+
+ ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
+ ISL29028_CONF_PROX_SLP_MASK,
+ sel << ISL29028_CONF_PROX_SLP_SH);
+
+ if (ret < 0) {
+ dev_err(dev, "%s(): Error %d setting the proximity sampling\n",
+ __func__, ret);
+ return ret;
+ }
+
+ chip->prox_sampling = sampling;
+
+ return ret;
}
-static int isl29028_enable_proximity(struct isl29028_chip *chip, bool enable)
+static int isl29028_enable_proximity(struct isl29028_chip *chip)
{
int ret;
- int val = 0;
- if (enable)
- val = ISL29028_CONF_PROX_EN;
+ ret = isl29028_set_proxim_sampling(chip, chip->prox_sampling);
+ if (ret < 0)
+ return ret;
+
ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
- ISL29028_CONF_PROX_EN_MASK, val);
+ ISL29028_CONF_PROX_EN_MASK,
+ ISL29028_CONF_PROX_EN);
if (ret < 0)
return ret;
/* Wait for conversion to be complete for first sample */
mdelay(DIV_ROUND_UP(1000, chip->prox_sampling));
+
return 0;
}
static int isl29028_set_als_scale(struct isl29028_chip *chip, int lux_scale)
{
+ struct device *dev = regmap_get_device(chip->regmap);
int val = (lux_scale == 2000) ? ISL29028_CONF_ALS_RANGE_HIGH_LUX :
ISL29028_CONF_ALS_RANGE_LOW_LUX;
+ int ret;
- return regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
- ISL29028_CONF_ALS_RANGE_MASK, val);
+ ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
+ ISL29028_CONF_ALS_RANGE_MASK, val);
+ if (ret < 0) {
+ dev_err(dev, "%s(): Error %d setting the ALS scale\n", __func__,
+ ret);
+ return ret;
+ }
+
+ chip->lux_scale = lux_scale;
+
+ return ret;
}
static int isl29028_set_als_ir_mode(struct isl29028_chip *chip,
enum isl29028_als_ir_mode mode)
{
- int ret = 0;
+ int ret;
+
+ if (chip->als_ir_mode == mode)
+ return 0;
+
+ ret = isl29028_set_als_scale(chip, chip->lux_scale);
+ if (ret < 0)
+ return ret;
switch (mode) {
case ISL29028_MODE_ALS:
ISL29028_CONF_ALS_RANGE_MASK,
ISL29028_CONF_ALS_RANGE_HIGH_LUX);
break;
-
case ISL29028_MODE_IR:
ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
ISL29028_CONF_ALS_IR_MODE_MASK,
ISL29028_CONF_ALS_IR_MODE_IR);
break;
-
case ISL29028_MODE_NONE:
return regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
- ISL29028_CONF_ALS_EN_MASK, ISL29028_CONF_ALS_DIS);
+ ISL29028_CONF_ALS_EN_MASK,
+ ISL29028_CONF_ALS_DIS);
}
if (ret < 0)
/* Need to wait for conversion time if ALS/IR mode enabled */
mdelay(ISL29028_CONV_TIME_MS);
+
+ chip->als_ir_mode = mode;
+
return 0;
}
ret = regmap_read(chip->regmap, ISL29028_REG_ALSIR_L, &lsb);
if (ret < 0) {
dev_err(dev,
- "Error in reading register ALSIR_L err %d\n", ret);
+ "%s(): Error %d reading register ALSIR_L\n",
+ __func__, ret);
return ret;
}
ret = regmap_read(chip->regmap, ISL29028_REG_ALSIR_U, &msb);
if (ret < 0) {
dev_err(dev,
- "Error in reading register ALSIR_U err %d\n", ret);
+ "%s(): Error %d reading register ALSIR_U\n",
+ __func__, ret);
return ret;
}
*als_ir = ((msb & 0xF) << 8) | (lsb & 0xFF);
+
return 0;
}
unsigned int data;
int ret;
+ if (!chip->enable_prox) {
+ ret = isl29028_enable_proximity(chip);
+ if (ret < 0)
+ return ret;
+
+ chip->enable_prox = true;
+ }
+
ret = regmap_read(chip->regmap, ISL29028_REG_PROX_DATA, &data);
if (ret < 0) {
- dev_err(dev, "Error in reading register %d, error %d\n",
- ISL29028_REG_PROX_DATA, ret);
+ dev_err(dev, "%s(): Error %d reading register PROX_DATA\n",
+ __func__, ret);
return ret;
}
- *prox = data;
- return 0;
-}
-static int isl29028_proxim_get(struct isl29028_chip *chip, int *prox_data)
-{
- int ret;
+ *prox = data;
- if (!chip->enable_prox) {
- ret = isl29028_enable_proximity(chip, true);
- if (ret < 0)
- return ret;
- chip->enable_prox = true;
- }
- return isl29028_read_proxim(chip, prox_data);
+ return 0;
}
static int isl29028_als_get(struct isl29028_chip *chip, int *als_data)
int ret;
int als_ir_data;
- if (chip->als_ir_mode != ISL29028_MODE_ALS) {
- ret = isl29028_set_als_ir_mode(chip, ISL29028_MODE_ALS);
- if (ret < 0) {
- dev_err(dev,
- "Error in enabling ALS mode err %d\n", ret);
- return ret;
- }
- chip->als_ir_mode = ISL29028_MODE_ALS;
+ ret = isl29028_set_als_ir_mode(chip, ISL29028_MODE_ALS);
+ if (ret < 0) {
+ dev_err(dev, "%s(): Error %d enabling ALS mode\n", __func__,
+ ret);
+ return ret;
}
ret = isl29028_read_als_ir(chip, &als_ir_data);
als_ir_data = (als_ir_data * 49) / 100;
*als_data = als_ir_data;
+
return 0;
}
struct device *dev = regmap_get_device(chip->regmap);
int ret;
- if (chip->als_ir_mode != ISL29028_MODE_IR) {
- ret = isl29028_set_als_ir_mode(chip, ISL29028_MODE_IR);
- if (ret < 0) {
- dev_err(dev,
- "Error in enabling IR mode err %d\n", ret);
- return ret;
- }
- chip->als_ir_mode = ISL29028_MODE_IR;
+ ret = isl29028_set_als_ir_mode(chip, ISL29028_MODE_IR);
+ if (ret < 0) {
+ dev_err(dev, "%s(): Error %d enabling IR mode\n", __func__,
+ ret);
+ return ret;
}
+
return isl29028_read_als_ir(chip, ir_data);
}
+static int isl29028_set_pm_runtime_busy(struct isl29028_chip *chip, bool on)
+{
+ struct device *dev = regmap_get_device(chip->regmap);
+ int ret;
+
+ if (on) {
+ ret = pm_runtime_get_sync(dev);
+ if (ret < 0)
+ pm_runtime_put_noidle(dev);
+ } else {
+ pm_runtime_mark_last_busy(dev);
+ ret = pm_runtime_put_autosuspend(dev);
+ }
+
+ return ret;
+}
+
/* Channel IO */
static int isl29028_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
{
struct isl29028_chip *chip = iio_priv(indio_dev);
struct device *dev = regmap_get_device(chip->regmap);
- int ret = -EINVAL;
+ int ret;
+
+ ret = isl29028_set_pm_runtime_busy(chip, true);
+ if (ret < 0)
+ return ret;
mutex_lock(&chip->lock);
+
+ ret = -EINVAL;
switch (chan->type) {
case IIO_PROXIMITY:
if (mask != IIO_CHAN_INFO_SAMP_FREQ) {
dev_err(dev,
- "proximity: mask value 0x%08lx not supported\n",
- mask);
+ "%s(): proximity: Mask value 0x%08lx is not supported\n",
+ __func__, mask);
break;
}
+
if (val < 1 || val > 100) {
dev_err(dev,
- "Samp_freq %d is not in range[1:100]\n", val);
+ "%s(): proximity: Sampling frequency %d is not in the range [1:100]\n",
+ __func__, val);
break;
}
+
ret = isl29028_set_proxim_sampling(chip, val);
- if (ret < 0) {
- dev_err(dev,
- "Setting proximity samp_freq fail, err %d\n",
- ret);
- break;
- }
- chip->prox_sampling = val;
break;
-
case IIO_LIGHT:
if (mask != IIO_CHAN_INFO_SCALE) {
dev_err(dev,
- "light: mask value 0x%08lx not supported\n",
- mask);
+ "%s(): light: Mask value 0x%08lx is not supported\n",
+ __func__, mask);
break;
}
- if ((val != 125) && (val != 2000)) {
+
+ if (val != 125 && val != 2000) {
dev_err(dev,
- "lux scale %d is invalid [125, 2000]\n", val);
+ "%s(): light: Lux scale %d is not in the set {125, 2000}\n",
+ __func__, val);
break;
}
+
ret = isl29028_set_als_scale(chip, val);
- if (ret < 0) {
- dev_err(dev,
- "Setting lux scale fail with error %d\n", ret);
- break;
- }
- chip->lux_scale = val;
break;
-
default:
- dev_err(dev, "Unsupported channel type\n");
+ dev_err(dev, "%s(): Unsupported channel type %x\n",
+ __func__, chan->type);
break;
}
+
mutex_unlock(&chip->lock);
+
+ if (ret < 0)
+ return ret;
+
+ ret = isl29028_set_pm_runtime_busy(chip, false);
+ if (ret < 0)
+ return ret;
+
return ret;
}
{
struct isl29028_chip *chip = iio_priv(indio_dev);
struct device *dev = regmap_get_device(chip->regmap);
- int ret = -EINVAL;
+ int ret, pm_ret;
+
+ ret = isl29028_set_pm_runtime_busy(chip, true);
+ if (ret < 0)
+ return ret;
mutex_lock(&chip->lock);
+
+ ret = -EINVAL;
switch (mask) {
case IIO_CHAN_INFO_RAW:
case IIO_CHAN_INFO_PROCESSED:
ret = isl29028_ir_get(chip, val);
break;
case IIO_PROXIMITY:
- ret = isl29028_proxim_get(chip, val);
+ ret = isl29028_read_proxim(chip, val);
break;
default:
break;
}
+
if (ret < 0)
break;
+
ret = IIO_VAL_INT;
break;
-
case IIO_CHAN_INFO_SAMP_FREQ:
if (chan->type != IIO_PROXIMITY)
break;
+
*val = chip->prox_sampling;
ret = IIO_VAL_INT;
break;
-
case IIO_CHAN_INFO_SCALE:
if (chan->type != IIO_LIGHT)
break;
*val = chip->lux_scale;
ret = IIO_VAL_INT;
break;
-
default:
- dev_err(dev, "mask value 0x%08lx not supported\n", mask);
+ dev_err(dev, "%s(): mask value 0x%08lx is not supported\n",
+ __func__, mask);
break;
}
+
mutex_unlock(&chip->lock);
+
+ if (ret < 0)
+ return ret;
+
+ /**
+ * Preserve the ret variable if the call to
+ * isl29028_set_pm_runtime_busy() is successful so the reading
+ * (if applicable) is returned to user space.
+ */
+ pm_ret = isl29028_set_pm_runtime_busy(chip, false);
+ if (pm_ret < 0)
+ return pm_ret;
+
return ret;
}
"1 3 5 10 13 20 83 100");
static IIO_CONST_ATTR(in_illuminance_scale_available, "125 2000");
-#define ISL29028_DEV_ATTR(name) (&iio_dev_attr_##name.dev_attr.attr)
#define ISL29028_CONST_ATTR(name) (&iio_const_attr_##name.dev_attr.attr)
static struct attribute *isl29028_attributes[] = {
ISL29028_CONST_ATTR(in_proximity_sampling_frequency_available),
.write_raw = isl29028_write_raw,
};
-static int isl29028_chip_init(struct isl29028_chip *chip)
+static int isl29028_clear_configure_reg(struct isl29028_chip *chip)
{
struct device *dev = regmap_get_device(chip->regmap);
int ret;
- chip->enable_prox = false;
- chip->prox_sampling = 20;
- chip->lux_scale = 2000;
- chip->als_ir_mode = ISL29028_MODE_NONE;
-
- ret = regmap_write(chip->regmap, ISL29028_REG_TEST1_MODE, 0x0);
- if (ret < 0) {
- dev_err(dev, "%s(): write to reg %d failed, err = %d\n",
- __func__, ISL29028_REG_TEST1_MODE, ret);
- return ret;
- }
- ret = regmap_write(chip->regmap, ISL29028_REG_TEST2_MODE, 0x0);
- if (ret < 0) {
- dev_err(dev, "%s(): write to reg %d failed, err = %d\n",
- __func__, ISL29028_REG_TEST2_MODE, ret);
- return ret;
- }
-
ret = regmap_write(chip->regmap, ISL29028_REG_CONFIGURE, 0x0);
- if (ret < 0) {
- dev_err(dev, "%s(): write to reg %d failed, err = %d\n",
- __func__, ISL29028_REG_CONFIGURE, ret);
- return ret;
- }
+ if (ret < 0)
+ dev_err(dev, "%s(): Error %d clearing the CONFIGURE register\n",
+ __func__, ret);
- ret = isl29028_set_proxim_sampling(chip, chip->prox_sampling);
- if (ret < 0) {
- dev_err(dev, "setting the proximity, err = %d\n", ret);
- return ret;
- }
+ chip->als_ir_mode = ISL29028_MODE_NONE;
+ chip->enable_prox = false;
- ret = isl29028_set_als_scale(chip, chip->lux_scale);
- if (ret < 0)
- dev_err(dev, "setting als scale failed, err = %d\n", ret);
return ret;
}
int ret;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
- if (!indio_dev) {
- dev_err(&client->dev, "iio allocation fails\n");
+ if (!indio_dev)
return -ENOMEM;
- }
chip = iio_priv(indio_dev);
chip->regmap = devm_regmap_init_i2c(client, &isl29028_regmap_config);
if (IS_ERR(chip->regmap)) {
ret = PTR_ERR(chip->regmap);
- dev_err(&client->dev, "regmap initialization failed: %d\n",
- ret);
+ dev_err(&client->dev, "%s: Error %d initializing regmap\n",
+ __func__, ret);
return ret;
}
- ret = isl29028_chip_init(chip);
+ chip->enable_prox = false;
+ chip->prox_sampling = 20;
+ chip->lux_scale = 2000;
+
+ ret = regmap_write(chip->regmap, ISL29028_REG_TEST1_MODE, 0x0);
if (ret < 0) {
- dev_err(&client->dev, "chip initialization failed: %d\n", ret);
+ dev_err(&client->dev,
+ "%s(): Error %d writing to TEST1_MODE register\n",
+ __func__, ret);
return ret;
}
+ ret = regmap_write(chip->regmap, ISL29028_REG_TEST2_MODE, 0x0);
+ if (ret < 0) {
+ dev_err(&client->dev,
+ "%s(): Error %d writing to TEST2_MODE register\n",
+ __func__, ret);
+ return ret;
+ }
+
+ ret = isl29028_clear_configure_reg(chip);
+ if (ret < 0)
+ return ret;
+
indio_dev->info = &isl29028_info;
indio_dev->channels = isl29028_channels;
indio_dev->num_channels = ARRAY_SIZE(isl29028_channels);
indio_dev->name = id->name;
indio_dev->dev.parent = &client->dev;
indio_dev->modes = INDIO_DIRECT_MODE;
+
+ pm_runtime_enable(&client->dev);
+ pm_runtime_set_autosuspend_delay(&client->dev,
+ ISL29028_POWER_OFF_DELAY_MS);
+ pm_runtime_use_autosuspend(&client->dev);
+
ret = devm_iio_device_register(indio_dev->dev.parent, indio_dev);
if (ret < 0) {
dev_err(&client->dev,
- "iio registration fails with error %d\n",
- ret);
+ "%s(): iio registration failed with error %d\n",
+ __func__, ret);
return ret;
}
+
return 0;
}
+static int isl29028_remove(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct isl29028_chip *chip = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+
+ pm_runtime_disable(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+ pm_runtime_put_noidle(&client->dev);
+
+ return isl29028_clear_configure_reg(chip);
+}
+
+static int __maybe_unused isl29028_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct isl29028_chip *chip = iio_priv(indio_dev);
+ int ret;
+
+ mutex_lock(&chip->lock);
+
+ ret = isl29028_clear_configure_reg(chip);
+
+ mutex_unlock(&chip->lock);
+
+ return ret;
+}
+
+static int __maybe_unused isl29028_resume(struct device *dev)
+{
+ /**
+ * The specific component (ALS/IR or proximity) will enable itself as
+ * needed the next time that the user requests a reading. This is done
+ * above in isl29028_set_als_ir_mode() and isl29028_enable_proximity().
+ */
+ return 0;
+}
+
+static const struct dev_pm_ops isl29028_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(isl29028_suspend, isl29028_resume)
+ SET_RUNTIME_PM_OPS(isl29028_suspend, isl29028_resume, NULL)
+};
+
static const struct i2c_device_id isl29028_id[] = {
{"isl29028", 0},
{}
static struct i2c_driver isl29028_driver = {
.driver = {
.name = "isl29028",
+ .pm = &isl29028_pm_ops,
.of_match_table = isl29028_of_match,
},
.probe = isl29028_probe,
+ .remove = isl29028_remove,
.id_table = isl29028_id,
};
}
ade7753_reset(dev);
- msleep(ADE7753_STARTUP_DELAY);
+ usleep_range(ADE7753_STARTUP_DELAY, ADE7753_STARTUP_DELAY + 100);
err_ret:
return ret;
#define ADE7753_MAX_TX 4
#define ADE7753_MAX_RX 4
-#define ADE7753_STARTUP_DELAY 1
+#define ADE7753_STARTUP_DELAY 1000
#define ADE7753_SPI_SLOW (u32)(300 * 1000)
#define ADE7753_SPI_BURST (u32)(1000 * 1000)
}
ade7754_reset(dev);
- msleep(ADE7754_STARTUP_DELAY);
+ usleep_range(ADE7754_STARTUP_DELAY, ADE7754_STARTUP_DELAY + 100);
err_ret:
return ret;
#define ADE7754_MAX_TX 4
#define ADE7754_MAX_RX 4
-#define ADE7754_STARTUP_DELAY 1
+#define ADE7754_STARTUP_DELAY 1000
#define ADE7754_SPI_SLOW (u32)(300 * 1000)
#define ADE7754_SPI_BURST (u32)(1000 * 1000)
#define ADE7758_MAX_TX 8
#define ADE7758_MAX_RX 4
-#define ADE7758_STARTUP_DELAY 1
+#define ADE7758_STARTUP_DELAY 1000
#define AD7758_NUM_WAVSEL 5
#define AD7758_NUM_PHSEL 3
}
ade7758_reset(dev);
- msleep(ADE7758_STARTUP_DELAY);
+ usleep_range(ADE7758_STARTUP_DELAY, ADE7758_STARTUP_DELAY + 100);
err_ret:
return ret;
#include <asm/unaligned.h>
#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
#include <linux/iio/kfifo_buf.h>
#include <linux/iio/trigger_consumer.h>
#include "ade7758.h"
}
ade7759_reset(dev);
- msleep(ADE7759_STARTUP_DELAY);
+ usleep_range(ADE7759_STARTUP_DELAY, ADE7759_STARTUP_DELAY + 100);
err_ret:
return ret;
#define ADE7759_MAX_TX 6
#define ADE7759_MAX_RX 6
-#define ADE7759_STARTUP_DELAY 1
+#define ADE7759_STARTUP_DELAY 1000
#define ADE7759_SPI_SLOW (u32)(300 * 1000)
#define ADE7759_SPI_BURST (u32)(1000 * 1000)
}
ade7854_reset(dev);
- msleep(ADE7854_STARTUP_DELAY);
+ usleep_range(ADE7854_STARTUP_DELAY, ADE7854_STARTUP_DELAY + 100);
err_ret:
return ret;
#define ADE7854_MAX_TX 7
#define ADE7854_MAX_RX 7
-#define ADE7854_STARTUP_DELAY 1
+#define ADE7854_STARTUP_DELAY 1000
#define ADE7854_SPI_SLOW (u32)(300 * 1000)
#define ADE7854_SPI_BURST (u32)(1000 * 1000)
return sprintf(buf, "%lu\n", val);
}
-static DEVICE_ATTR(frequency, S_IRUGO | S_IWUSR, iio_bfin_tmr_frequency_show,
+static DEVICE_ATTR(frequency, 0644, iio_bfin_tmr_frequency_show,
iio_bfin_tmr_frequency_store);
static struct attribute *iio_bfin_tmr_trigger_attrs[] = {
out1:
iio_trigger_unregister(st->trig);
out:
- iio_trigger_put(st->trig);
+ iio_trigger_free(st->trig);
return ret;
}
peripheral_free(st->t->pin);
free_irq(st->irq, st);
iio_trigger_unregister(st->trig);
- iio_trigger_put(st->trig);
+ iio_trigger_free(st->trig);
return 0;
}
/* AHB Data Window 0x010000-0x01FFFF */
#define DATA_WINDOW 0x010000
-#define WINDOW_SIZE 64*1024
+#define WINDOW_SIZE (64 * 1024)
#define KS7010_IRAM_ADDRESS 0x06000000
-/*
+/*
* struct define
*/
struct hw_info_t {
/* Operational parameters that usually are not changed. */
/* Time in jiffies before concluding the transmitter is hung. */
#define TX_TIMEOUT (3*HZ)
-static const unsigned char dummy_addr[] =
- { 0x00, 0x0b, 0xe3, 0x00, 0x00, 0x00 };
+static const unsigned char dummy_addr[] = {
+ 0x00, 0x0b, 0xe3, 0x00, 0x00, 0x00
+};
static const struct net_device_ops ks_wlan_netdev_ops = {
.ndo_start_xmit = ks_wlan_start_xmit,
};
static struct cfs_crypto_hash_type hash_types[] = {
- [CFS_HASH_ALG_NULL] = { "null", 0, 0 },
- [CFS_HASH_ALG_ADLER32] = { "adler32", 1, 4 },
- [CFS_HASH_ALG_CRC32] = { "crc32", ~0, 4 },
- [CFS_HASH_ALG_CRC32C] = { "crc32c", ~0, 4 },
- [CFS_HASH_ALG_MD5] = { "md5", 0, 16 },
- [CFS_HASH_ALG_SHA1] = { "sha1", 0, 20 },
- [CFS_HASH_ALG_SHA256] = { "sha256", 0, 32 },
- [CFS_HASH_ALG_SHA384] = { "sha384", 0, 48 },
- [CFS_HASH_ALG_SHA512] = { "sha512", 0, 64 },
- [CFS_HASH_ALG_MAX] = { NULL, 0, 64 },
+ [CFS_HASH_ALG_NULL] = {
+ .cht_name = "null",
+ .cht_key = 0,
+ .cht_size = 0
+ },
+ [CFS_HASH_ALG_ADLER32] = {
+ .cht_name = "adler32",
+ .cht_key = 1,
+ .cht_size = 4
+ },
+ [CFS_HASH_ALG_CRC32] = {
+ .cht_name = "crc32",
+ .cht_key = ~0,
+ .cht_size = 4
+ },
+ [CFS_HASH_ALG_CRC32C] = {
+ .cht_name = "crc32c",
+ .cht_key = ~0,
+ .cht_size = 4
+ },
+ [CFS_HASH_ALG_MD5] = {
+ .cht_name = "md5",
+ .cht_key = 0,
+ .cht_size = 16
+ },
+ [CFS_HASH_ALG_SHA1] = {
+ .cht_name = "sha1",
+ .cht_key = 0,
+ .cht_size = 20
+ },
+ [CFS_HASH_ALG_SHA256] = {
+ .cht_name = "sha256",
+ .cht_key = 0,
+ .cht_size = 32
+ },
+ [CFS_HASH_ALG_SHA384] = {
+ .cht_name = "sha384",
+ .cht_key = 0,
+ .cht_size = 48
+ },
+ [CFS_HASH_ALG_SHA512] = {
+ .cht_name = "sha512",
+ .cht_key = 0,
+ .cht_size = 64
+ },
+ [CFS_HASH_ALG_MAX] = {
+ .cht_name = NULL,
+ .cht_key = 0,
+ .cht_size = 64
+ },
};
/* Maximum size of hash_types[].cht_size */
#define CFS_ALLOC_PTR(ptr) LIBCFS_ALLOC(ptr, sizeof(*(ptr)))
#define CFS_FREE_PTR(ptr) LIBCFS_FREE(ptr, sizeof(*(ptr)))
-/** Compile-time assertion.
- *
- * Check an invariant described by a constant expression at compile time by
- * forcing a compiler error if it does not hold. \a cond must be a constant
- * expression as defined by the ISO C Standard:
- *
- * 6.8.4.2 The switch statement
- * ....
- * [#3] The expression of each case label shall be an integer
- * constant expression and no two of the case constant
- * expressions in the same switch statement shall have the same
- * value after conversion...
- *
- */
-#define CLASSERT(cond) do {switch (42) {case (cond): case 0: break; } } while (0)
-
/* max value for numeric network address */
#define MAX_NUMERIC_VALUE 0xffffffff
#include <linux/capability.h>
-/* long integer with size equal to pointer */
-typedef unsigned long ulong_ptr_t;
-typedef long long_ptr_t;
-
#ifndef WITH_WATCHDOG
#define WITH_WATCHDOG
#endif
return route->lr_downis == 0;
}
-static inline int lnet_is_wire_handle_none(lnet_handle_wire_t *wh)
+static inline int lnet_is_wire_handle_none(struct lnet_handle_wire *wh)
{
return (wh->wh_interface_cookie == LNET_WIRE_HANDLE_COOKIE_NONE &&
wh->wh_object_cookie == LNET_WIRE_HANDLE_COOKIE_NONE);
}
static inline lnet_libmd_t *
-lnet_wire_handle2md(lnet_handle_wire_t *wh)
+lnet_wire_handle2md(struct lnet_handle_wire *wh)
{
/* ALWAYS called with resource lock held */
lnet_libhandle_t *lh;
void lnet_portals_destroy(void);
/* message functions */
-int lnet_parse(lnet_ni_t *ni, lnet_hdr_t *hdr,
+int lnet_parse(lnet_ni_t *ni, struct lnet_hdr *hdr,
lnet_nid_t fromnid, void *private, int rdma_req);
int lnet_parse_local(lnet_ni_t *ni, lnet_msg_t *msg);
int lnet_parse_forward_locked(lnet_ni_t *ni, lnet_msg_t *msg);
int lnet_msg_containers_create(void);
char *lnet_msgtyp2str(int type);
-void lnet_print_hdr(lnet_hdr_t *hdr);
+void lnet_print_hdr(struct lnet_hdr *hdr);
int lnet_fail_nid(lnet_nid_t nid, unsigned int threshold);
/** \addtogroup lnet_fault_simulation @{ */
int lnet_fault_init(void);
void lnet_fault_fini(void);
-bool lnet_drop_rule_match(lnet_hdr_t *hdr);
+bool lnet_drop_rule_match(struct lnet_hdr *hdr);
int lnet_delay_rule_add(struct lnet_fault_attr *attr);
int lnet_delay_rule_del(lnet_nid_t src, lnet_nid_t dst, bool shutdown);
struct lnet_fault_stat *stat);
void lnet_delay_rule_reset(void);
void lnet_delay_rule_check(void);
-bool lnet_delay_rule_match_locked(lnet_hdr_t *hdr, struct lnet_msg *msg);
+bool lnet_delay_rule_match_locked(struct lnet_hdr *hdr, struct lnet_msg *msg);
/** @} lnet_fault_simulation */
int lnet_router_checker_start(void);
void lnet_router_checker_stop(void);
void lnet_router_ni_update_locked(lnet_peer_t *gw, __u32 net);
-void lnet_swap_pinginfo(lnet_ping_info_t *info);
+void lnet_swap_pinginfo(struct lnet_ping_info *info);
int lnet_parse_ip2nets(char **networksp, char *ip2nets);
int lnet_parse_routes(char *route_str, int *im_a_router);
lnet_kiov_t *msg_kiov;
lnet_event_t msg_ev;
- lnet_hdr_t msg_hdr;
+ struct lnet_hdr msg_hdr;
} lnet_msg_t;
typedef struct lnet_libhandle {
struct lnet_tx_queue **ni_tx_queues; /* percpt TX queues */
int **ni_refs; /* percpt reference count */
time64_t ni_last_alive;/* when I was last alive */
- lnet_ni_status_t *ni_status; /* my health status */
+ struct lnet_ni_status *ni_status; /* my health status */
/* per NI LND tunables */
struct lnet_ioctl_config_lnd_tunables *ni_lnd_tunables;
/* equivalent interfaces to use */
/* router checker data, per router */
#define LNET_MAX_RTR_NIS 16
-#define LNET_PINGINFO_SIZE offsetof(lnet_ping_info_t, pi_ni[LNET_MAX_RTR_NIS])
+#define LNET_PINGINFO_SIZE offsetof(struct lnet_ping_info, pi_ni[LNET_MAX_RTR_NIS])
typedef struct {
/* chain on the_lnet.ln_zombie_rcd or ln_deathrow_rcd */
struct list_head rcd_list;
lnet_handle_md_t rcd_mdh; /* ping buffer MD */
struct lnet_peer *rcd_gateway; /* reference to gateway */
- lnet_ping_info_t *rcd_pinginfo; /* ping buffer */
+ struct lnet_ping_info *rcd_pinginfo; /* ping buffer */
} lnet_rc_data_t;
typedef struct lnet_peer {
lnet_handle_md_t ln_ping_target_md;
lnet_handle_eq_t ln_ping_target_eq;
- lnet_ping_info_t *ln_ping_info;
+ struct lnet_ping_info *ln_ping_info;
/* router checker startup/shutdown state */
int ln_rc_state;
#define LSTIO_BATCH_QUERY 0xC27 /* query batch status */
#define LSTIO_STAT_QUERY 0xC30 /* get stats */
-typedef struct {
+struct lst_sid {
lnet_nid_t ses_nid; /* nid of console node */
__u64 ses_stamp; /* time stamp */
-} lst_sid_t; /*** session id */
+}; /*** session id */
-extern lst_sid_t LST_INVALID_SID;
+extern struct lst_sid LST_INVALID_SID;
-typedef struct {
+struct lst_bid {
__u64 bat_id; /* unique id in session */
-} lst_bid_t; /*** batch id (group of tests) */
+}; /*** batch id (group of tests) */
/* Status of test node */
#define LST_NODE_ACTIVE 0x1 /* node in this session */
#define LST_NODE_DOWN 0x4 /* node is down */
#define LST_NODE_UNKNOWN 0x8 /* node not in session */
-typedef struct {
+struct lstcon_node_ent {
lnet_process_id_t nde_id; /* id of node */
int nde_state; /* state of node */
-} lstcon_node_ent_t; /*** node entry, for list_group command */
+}; /*** node entry, for list_group command */
-typedef struct {
+struct lstcon_ndlist_ent {
int nle_nnode; /* # of nodes */
int nle_nactive; /* # of active nodes */
int nle_nbusy; /* # of busy nodes */
int nle_ndown; /* # of down nodes */
int nle_nunknown; /* # of unknown nodes */
-} lstcon_ndlist_ent_t; /*** node_list entry, for list_batch command */
+}; /*** node_list entry, for list_batch command */
-typedef struct {
+struct lstcon_test_ent {
int tse_type; /* test type */
int tse_loop; /* loop count */
int tse_concur; /* concurrency of test */
-} lstcon_test_ent_t; /*** test summary entry, for
+}; /*** test summary entry, for
*** list_batch command */
-typedef struct {
+struct lstcon_batch_ent {
int bae_state; /* batch status */
int bae_timeout; /* batch timeout */
int bae_ntest; /* # of tests in the batch */
-} lstcon_batch_ent_t; /*** batch summary entry, for
+}; /*** batch summary entry, for
*** list_batch command */
-typedef struct {
- lstcon_ndlist_ent_t tbe_cli_nle; /* client (group) node_list
+struct lstcon_test_batch_ent {
+ struct lstcon_ndlist_ent tbe_cli_nle; /* client (group) node_list
* entry */
- lstcon_ndlist_ent_t tbe_srv_nle; /* server (group) node_list
+ struct lstcon_ndlist_ent tbe_srv_nle; /* server (group) node_list
* entry */
union {
- lstcon_test_ent_t tbe_test; /* test entry */
- lstcon_batch_ent_t tbe_batch; /* batch entry */
+ struct lstcon_test_ent tbe_test; /* test entry */
+ struct lstcon_batch_ent tbe_batch;/* batch entry */
} u;
-} lstcon_test_batch_ent_t; /*** test/batch verbose information entry,
+}; /*** test/batch verbose information entry,
*** for list_batch command */
-typedef struct {
+struct lstcon_rpc_ent {
struct list_head rpe_link; /* link chain */
lnet_process_id_t rpe_peer; /* peer's id */
struct timeval rpe_stamp; /* time stamp of RPC */
int rpe_state; /* peer's state */
int rpe_rpc_errno; /* RPC errno */
- lst_sid_t rpe_sid; /* peer's session id */
+ struct lst_sid rpe_sid; /* peer's session id */
int rpe_fwk_errno; /* framework errno */
int rpe_priv[4]; /* private data */
char rpe_payload[0]; /* private reply payload */
-} lstcon_rpc_ent_t;
+};
-typedef struct {
+struct lstcon_trans_stat {
int trs_rpc_stat[4]; /* RPCs stat (0: total
1: failed
2: finished
int trs_fwk_stat[8]; /* framework stat */
int trs_fwk_errno; /* errno of the first remote error */
void *trs_fwk_private; /* private framework stat */
-} lstcon_trans_stat_t;
+};
static inline int
-lstcon_rpc_stat_total(lstcon_trans_stat_t *stat, int inc)
+lstcon_rpc_stat_total(struct lstcon_trans_stat *stat, int inc)
{
return inc ? ++stat->trs_rpc_stat[0] : stat->trs_rpc_stat[0];
}
static inline int
-lstcon_rpc_stat_success(lstcon_trans_stat_t *stat, int inc)
+lstcon_rpc_stat_success(struct lstcon_trans_stat *stat, int inc)
{
return inc ? ++stat->trs_rpc_stat[1] : stat->trs_rpc_stat[1];
}
static inline int
-lstcon_rpc_stat_failure(lstcon_trans_stat_t *stat, int inc)
+lstcon_rpc_stat_failure(struct lstcon_trans_stat *stat, int inc)
{
return inc ? ++stat->trs_rpc_stat[2] : stat->trs_rpc_stat[2];
}
static inline int
-lstcon_sesop_stat_success(lstcon_trans_stat_t *stat, int inc)
+lstcon_sesop_stat_success(struct lstcon_trans_stat *stat, int inc)
{
return inc ? ++stat->trs_fwk_stat[0] : stat->trs_fwk_stat[0];
}
static inline int
-lstcon_sesop_stat_failure(lstcon_trans_stat_t *stat, int inc)
+lstcon_sesop_stat_failure(struct lstcon_trans_stat *stat, int inc)
{
return inc ? ++stat->trs_fwk_stat[1] : stat->trs_fwk_stat[1];
}
static inline int
-lstcon_sesqry_stat_active(lstcon_trans_stat_t *stat, int inc)
+lstcon_sesqry_stat_active(struct lstcon_trans_stat *stat, int inc)
{
return inc ? ++stat->trs_fwk_stat[0] : stat->trs_fwk_stat[0];
}
static inline int
-lstcon_sesqry_stat_busy(lstcon_trans_stat_t *stat, int inc)
+lstcon_sesqry_stat_busy(struct lstcon_trans_stat *stat, int inc)
{
return inc ? ++stat->trs_fwk_stat[1] : stat->trs_fwk_stat[1];
}
static inline int
-lstcon_sesqry_stat_unknown(lstcon_trans_stat_t *stat, int inc)
+lstcon_sesqry_stat_unknown(struct lstcon_trans_stat *stat, int inc)
{
return inc ? ++stat->trs_fwk_stat[2] : stat->trs_fwk_stat[2];
}
static inline int
-lstcon_tsbop_stat_success(lstcon_trans_stat_t *stat, int inc)
+lstcon_tsbop_stat_success(struct lstcon_trans_stat *stat, int inc)
{
return inc ? ++stat->trs_fwk_stat[0] : stat->trs_fwk_stat[0];
}
static inline int
-lstcon_tsbop_stat_failure(lstcon_trans_stat_t *stat, int inc)
+lstcon_tsbop_stat_failure(struct lstcon_trans_stat *stat, int inc)
{
return inc ? ++stat->trs_fwk_stat[1] : stat->trs_fwk_stat[1];
}
static inline int
-lstcon_tsbqry_stat_idle(lstcon_trans_stat_t *stat, int inc)
+lstcon_tsbqry_stat_idle(struct lstcon_trans_stat *stat, int inc)
{
return inc ? ++stat->trs_fwk_stat[0] : stat->trs_fwk_stat[0];
}
static inline int
-lstcon_tsbqry_stat_run(lstcon_trans_stat_t *stat, int inc)
+lstcon_tsbqry_stat_run(struct lstcon_trans_stat *stat, int inc)
{
return inc ? ++stat->trs_fwk_stat[1] : stat->trs_fwk_stat[1];
}
static inline int
-lstcon_tsbqry_stat_failure(lstcon_trans_stat_t *stat, int inc)
+lstcon_tsbqry_stat_failure(struct lstcon_trans_stat *stat, int inc)
{
return inc ? ++stat->trs_fwk_stat[2] : stat->trs_fwk_stat[2];
}
static inline int
-lstcon_statqry_stat_success(lstcon_trans_stat_t *stat, int inc)
+lstcon_statqry_stat_success(struct lstcon_trans_stat *stat, int inc)
{
return inc ? ++stat->trs_fwk_stat[0] : stat->trs_fwk_stat[0];
}
static inline int
-lstcon_statqry_stat_failure(lstcon_trans_stat_t *stat, int inc)
+lstcon_statqry_stat_failure(struct lstcon_trans_stat *stat, int inc)
{
return inc ? ++stat->trs_fwk_stat[1] : stat->trs_fwk_stat[1];
}
/* create a session */
-typedef struct {
+struct lstio_session_new_args {
int lstio_ses_key; /* IN: local key */
int lstio_ses_timeout; /* IN: session timeout */
int lstio_ses_force; /* IN: force create ? */
/** IN: session features */
unsigned int lstio_ses_feats;
- lst_sid_t __user *lstio_ses_idp; /* OUT: session id */
+ struct lst_sid __user *lstio_ses_idp; /* OUT: session id */
int lstio_ses_nmlen; /* IN: name length */
char __user *lstio_ses_namep; /* IN: session name */
-} lstio_session_new_args_t;
+};
/* query current session */
-typedef struct {
- lst_sid_t __user *lstio_ses_idp; /* OUT: session id */
+struct lstio_session_info_args {
+ struct lst_sid __user *lstio_ses_idp; /* OUT: session id */
int __user *lstio_ses_keyp; /* OUT: local key */
/** OUT: session features */
unsigned int __user *lstio_ses_featp;
- lstcon_ndlist_ent_t __user *lstio_ses_ndinfo; /* OUT: */
+ struct lstcon_ndlist_ent __user *lstio_ses_ndinfo;/* OUT: */
int lstio_ses_nmlen; /* IN: name length */
char __user *lstio_ses_namep; /* OUT: session name */
-} lstio_session_info_args_t;
+};
/* delete a session */
-typedef struct {
+struct lstio_session_end_args {
int lstio_ses_key; /* IN: session key */
-} lstio_session_end_args_t;
+};
#define LST_OPC_SESSION 1
#define LST_OPC_GROUP 2
#define LST_OPC_BATCHCLI 4
#define LST_OPC_BATCHSRV 5
-typedef struct {
+struct lstio_debug_args {
int lstio_dbg_key; /* IN: session key */
int lstio_dbg_type; /* IN: debug
session|batch|
nodes */
struct list_head __user *lstio_dbg_resultp; /* OUT: list head of
result buffer */
-} lstio_debug_args_t;
+};
-typedef struct {
+struct lstio_group_add_args {
int lstio_grp_key; /* IN: session key */
int lstio_grp_nmlen; /* IN: name length */
char __user *lstio_grp_namep; /* IN: group name */
-} lstio_group_add_args_t;
+};
-typedef struct {
+struct lstio_group_del_args {
int lstio_grp_key; /* IN: session key */
int lstio_grp_nmlen; /* IN: name length */
char __user *lstio_grp_namep; /* IN: group name */
-} lstio_group_del_args_t;
+};
#define LST_GROUP_CLEAN 1 /* remove inactive nodes in the group */
#define LST_GROUP_REFRESH 2 /* refresh inactive nodes
* in the group */
#define LST_GROUP_RMND 3 /* delete nodes from the group */
-typedef struct {
+struct lstio_group_update_args {
int lstio_grp_key; /* IN: session key */
int lstio_grp_opc; /* IN: OPC */
int lstio_grp_args; /* IN: arguments */
lnet_process_id_t __user *lstio_grp_idsp; /* IN: array of nodes */
struct list_head __user *lstio_grp_resultp; /* OUT: list head of
result buffer */
-} lstio_group_update_args_t;
+};
-typedef struct {
+struct lstio_group_nodes_args {
int lstio_grp_key; /* IN: session key */
int lstio_grp_nmlen; /* IN: name length */
char __user *lstio_grp_namep; /* IN: group name */
lnet_process_id_t __user *lstio_grp_idsp; /* IN: nodes */
struct list_head __user *lstio_grp_resultp; /* OUT: list head of
result buffer */
-} lstio_group_nodes_args_t;
+};
-typedef struct {
+struct lstio_group_list_args {
int lstio_grp_key; /* IN: session key */
int lstio_grp_idx; /* IN: group idx */
int lstio_grp_nmlen; /* IN: name len */
char __user *lstio_grp_namep; /* OUT: name */
-} lstio_group_list_args_t;
+};
-typedef struct {
+struct lstio_group_info_args {
int lstio_grp_key; /* IN: session key */
int lstio_grp_nmlen; /* IN: name len */
char __user *lstio_grp_namep; /* IN: name */
- lstcon_ndlist_ent_t __user *lstio_grp_entp; /* OUT: description of
- group */
+ struct lstcon_ndlist_ent __user *lstio_grp_entp;/* OUT: description of
+ group */
int __user *lstio_grp_idxp; /* IN/OUT: node index */
int __user *lstio_grp_ndentp; /* IN/OUT: # of nodent */
- lstcon_node_ent_t __user *lstio_grp_dentsp; /* OUT: nodent array */
-} lstio_group_info_args_t;
+ struct lstcon_node_ent __user *lstio_grp_dentsp;/* OUT: nodent array */
+};
#define LST_DEFAULT_BATCH "batch" /* default batch name */
-typedef struct {
+struct lstio_batch_add_args {
int lstio_bat_key; /* IN: session key */
int lstio_bat_nmlen; /* IN: name length */
char __user *lstio_bat_namep; /* IN: batch name */
-} lstio_batch_add_args_t;
+};
-typedef struct {
+struct lstio_batch_del_args {
int lstio_bat_key; /* IN: session key */
int lstio_bat_nmlen; /* IN: name length */
char __user *lstio_bat_namep; /* IN: batch name */
-} lstio_batch_del_args_t;
+};
-typedef struct {
+struct lstio_batch_run_args {
int lstio_bat_key; /* IN: session key */
int lstio_bat_timeout; /* IN: timeout for
the batch */
char __user *lstio_bat_namep; /* IN: batch name */
struct list_head __user *lstio_bat_resultp; /* OUT: list head of
result buffer */
-} lstio_batch_run_args_t;
+};
-typedef struct {
+struct lstio_batch_stop_args {
int lstio_bat_key; /* IN: session key */
int lstio_bat_force; /* IN: abort unfinished
test RPC */
char __user *lstio_bat_namep; /* IN: batch name */
struct list_head __user *lstio_bat_resultp; /* OUT: list head of
result buffer */
-} lstio_batch_stop_args_t;
+};
-typedef struct {
+struct lstio_batch_query_args {
int lstio_bat_key; /* IN: session key */
int lstio_bat_testidx; /* IN: test index */
int lstio_bat_client; /* IN: we testing
char __user *lstio_bat_namep; /* IN: batch name */
struct list_head __user *lstio_bat_resultp; /* OUT: list head of
result buffer */
-} lstio_batch_query_args_t;
+};
-typedef struct {
+struct lstio_batch_list_args {
int lstio_bat_key; /* IN: session key */
int lstio_bat_idx; /* IN: index */
int lstio_bat_nmlen; /* IN: name length */
char __user *lstio_bat_namep; /* IN: batch name */
-} lstio_batch_list_args_t;
+};
-typedef struct {
+struct lstio_batch_info_args {
int lstio_bat_key; /* IN: session key */
int lstio_bat_nmlen; /* IN: name length */
char __user *lstio_bat_namep; /* IN: name */
int lstio_bat_server; /* IN: query server
or not */
int lstio_bat_testidx; /* IN: test index */
- lstcon_test_batch_ent_t __user *lstio_bat_entp; /* OUT: batch ent */
+ struct lstcon_test_batch_ent __user *lstio_bat_entp;/* OUT: batch ent */
int __user *lstio_bat_idxp; /* IN/OUT: index of node */
int __user *lstio_bat_ndentp; /* IN/OUT: # of nodent */
- lstcon_node_ent_t __user *lstio_bat_dentsp; /* array of nodent */
-} lstio_batch_info_args_t;
+ struct lstcon_node_ent __user *lstio_bat_dentsp;/* array of nodent */
+};
/* add stat in session */
-typedef struct {
+struct lstio_stat_args {
int lstio_sta_key; /* IN: session key */
int lstio_sta_timeout; /* IN: timeout for
stat request */
lnet_process_id_t __user *lstio_sta_idsp; /* IN: pid */
struct list_head __user *lstio_sta_resultp; /* OUT: list head of
result buffer */
-} lstio_stat_args_t;
+};
-typedef enum {
+enum lst_test_type {
LST_TEST_BULK = 1,
LST_TEST_PING = 2
-} lst_test_type_t;
+};
/* create a test in a batch */
#define LST_MAX_CONCUR 1024 /* Max concurrency of test */
-typedef struct {
+struct lstio_test_args {
int lstio_tes_key; /* IN: session key */
int lstio_tes_bat_nmlen; /* IN: batch name len */
char __user *lstio_tes_bat_name; /* IN: batch name */
value */
struct list_head __user *lstio_tes_resultp;/* OUT: list head of
result buffer */
-} lstio_test_args_t;
+};
-typedef enum {
+enum lst_brw_type {
LST_BRW_READ = 1,
LST_BRW_WRITE = 2
-} lst_brw_type_t;
+};
-typedef enum {
+enum lst_brw_flags {
LST_BRW_CHECK_NONE = 1,
LST_BRW_CHECK_SIMPLE = 2,
LST_BRW_CHECK_FULL = 3
-} lst_brw_flags_t;
+};
-typedef struct {
+struct lst_test_bulk_param {
int blk_opc; /* bulk operation code */
int blk_size; /* size (bytes) */
int blk_time; /* time of running the test*/
int blk_flags; /* reserved flags */
int blk_cli_off; /* bulk offset on client */
int blk_srv_off; /* reserved: bulk offset on server */
-} lst_test_bulk_param_t;
+};
-typedef struct {
+struct lst_test_ping_param {
int png_size; /* size of ping message */
int png_time; /* time */
int png_loop; /* loop */
int png_flags; /* reserved flags */
-} lst_test_ping_param_t;
+};
-typedef struct {
+struct srpc_counters {
__u32 errors;
__u32 rpcs_sent;
__u32 rpcs_rcvd;
__u32 rpcs_expired;
__u64 bulk_get;
__u64 bulk_put;
-} WIRE_ATTR srpc_counters_t;
+} WIRE_ATTR;
-typedef struct {
+struct sfw_counters {
/** milliseconds since current session started */
__u32 running_ms;
__u32 active_batches;
__u32 zombie_sessions;
__u32 brw_errors;
__u32 ping_errors;
-} WIRE_ATTR sfw_counters_t;
+} WIRE_ATTR;
#endif
} WIRE_ATTR ksock_hello_msg_t;
typedef struct {
- lnet_hdr_t ksnm_hdr; /* lnet hdr */
+ struct lnet_hdr ksnm_hdr; /* lnet hdr */
/*
* ksnm_payload is removed because of winnt compiler's limitation:
} WIRE_ATTR ksm_u;
} WIRE_ATTR ksock_msg_t;
-static inline void
-socklnd_init_msg(ksock_msg_t *msg, int type)
-{
- msg->ksm_csum = 0;
- msg->ksm_type = type;
- msg->ksm_zc_cookies[0] = 0;
- msg->ksm_zc_cookies[1] = 0;
-}
-
#define KSOCK_MSG_NOOP 0xC0 /* ksm_u empty */
#define KSOCK_MSG_LNET 0xC1 /* lnet msg */
#define WIRE_ATTR __packed
/* Packed version of lnet_process_id_t to transfer via network */
-typedef struct {
+struct lnet_process_id_packed {
/* node id / process id */
lnet_nid_t nid;
lnet_pid_t pid;
-} WIRE_ATTR lnet_process_id_packed_t;
+} WIRE_ATTR;
/*
* The wire handle's interface cookie only matches one network interface in
* reboots). The object cookie only matches one object on that interface
* during that object's lifetime (i.e. no cookie re-use).
*/
-typedef struct {
+struct lnet_handle_wire {
__u64 wh_interface_cookie;
__u64 wh_object_cookie;
-} WIRE_ATTR lnet_handle_wire_t;
+} WIRE_ATTR;
typedef enum {
LNET_MSG_ACK = 0,
* wire structs MUST be fixed size and the smaller types are placed at the
* end.
*/
-typedef struct lnet_ack {
- lnet_handle_wire_t dst_wmd;
+struct lnet_ack {
+ struct lnet_handle_wire dst_wmd;
__u64 match_bits;
__u32 mlength;
-} WIRE_ATTR lnet_ack_t;
+} WIRE_ATTR;
-typedef struct lnet_put {
- lnet_handle_wire_t ack_wmd;
+struct lnet_put {
+ struct lnet_handle_wire ack_wmd;
__u64 match_bits;
__u64 hdr_data;
__u32 ptl_index;
__u32 offset;
-} WIRE_ATTR lnet_put_t;
+} WIRE_ATTR;
-typedef struct lnet_get {
- lnet_handle_wire_t return_wmd;
+struct lnet_get {
+ struct lnet_handle_wire return_wmd;
__u64 match_bits;
__u32 ptl_index;
__u32 src_offset;
__u32 sink_length;
-} WIRE_ATTR lnet_get_t;
+} WIRE_ATTR;
-typedef struct lnet_reply {
- lnet_handle_wire_t dst_wmd;
-} WIRE_ATTR lnet_reply_t;
+struct lnet_reply {
+ struct lnet_handle_wire dst_wmd;
+} WIRE_ATTR;
-typedef struct lnet_hello {
+struct lnet_hello {
__u64 incarnation;
__u32 type;
-} WIRE_ATTR lnet_hello_t;
+} WIRE_ATTR;
-typedef struct {
+struct lnet_hdr {
lnet_nid_t dest_nid;
lnet_nid_t src_nid;
lnet_pid_t dest_pid;
__u32 payload_length; /* payload data to follow */
/*<------__u64 aligned------->*/
union {
- lnet_ack_t ack;
- lnet_put_t put;
- lnet_get_t get;
- lnet_reply_t reply;
- lnet_hello_t hello;
+ struct lnet_ack ack;
+ struct lnet_put put;
+ struct lnet_get get;
+ struct lnet_reply reply;
+ struct lnet_hello hello;
} msg;
-} WIRE_ATTR lnet_hdr_t;
+} WIRE_ATTR;
/*
* A HELLO message contains a magic number and protocol version
* This is for use by byte-stream LNDs (e.g. TCP/IP) to check the peer is
* running the same protocol and to find out its NID. These LNDs should
* exchange HELLO messages when a connection is first established. Individual
- * LNDs can put whatever else they fancy in lnet_hdr_t::msg.
+ * LNDs can put whatever else they fancy in struct lnet_hdr::msg.
*/
-typedef struct {
+struct lnet_magicversion {
__u32 magic; /* LNET_PROTO_TCP_MAGIC */
__u16 version_major; /* increment on incompatible change */
__u16 version_minor; /* increment on compatible change */
-} WIRE_ATTR lnet_magicversion_t;
+} WIRE_ATTR;
/* PROTO MAGIC for LNDs */
#define LNET_PROTO_IB_MAGIC 0x0be91b91
#define LNET_PROTO_TCP_VERSION_MINOR 0
/* Acceptor connection request */
-typedef struct {
+struct lnet_acceptor_connreq {
__u32 acr_magic; /* PTL_ACCEPTOR_PROTO_MAGIC */
__u32 acr_version; /* protocol version */
__u64 acr_nid; /* target NID */
-} WIRE_ATTR lnet_acceptor_connreq_t;
+} WIRE_ATTR;
#define LNET_PROTO_ACCEPTOR_VERSION 1
-typedef struct {
+struct lnet_ni_status {
lnet_nid_t ns_nid;
__u32 ns_status;
__u32 ns_unused;
-} WIRE_ATTR lnet_ni_status_t;
+} WIRE_ATTR;
-typedef struct {
+struct lnet_ping_info {
__u32 pi_magic;
__u32 pi_features;
lnet_pid_t pi_pid;
__u32 pi_nnis;
- lnet_ni_status_t pi_ni[0];
-} WIRE_ATTR lnet_ping_info_t;
+ struct lnet_ni_status pi_ni[0];
+} WIRE_ATTR;
typedef struct lnet_counters {
__u32 msgs_alloc;
if (flip) {
/* leave magic unflipped as a clue to peer endianness */
msg->ibm_version = version;
- CLASSERT(sizeof(msg->ibm_type) == 1);
- CLASSERT(sizeof(msg->ibm_credits) == 1);
+ BUILD_BUG_ON(sizeof(msg->ibm_type) != 1);
+ BUILD_BUG_ON(sizeof(msg->ibm_credits) != 1);
msg->ibm_nob = msg_nob;
__swab64s(&msg->ibm_srcnid);
__swab64s(&msg->ibm_srcstamp);
dev = net->ibn_dev;
/* pre-mapped messages are not bigger than 1 page */
- CLASSERT(IBLND_MSG_SIZE <= PAGE_SIZE);
+ BUILD_BUG_ON(IBLND_MSG_SIZE > PAGE_SIZE);
/* No fancy arithmetic when we do the buffer calculations */
- CLASSERT(!(PAGE_SIZE % IBLND_MSG_SIZE));
+ BUILD_BUG_ON(PAGE_SIZE % IBLND_MSG_SIZE);
tpo->tpo_hdev = kiblnd_current_hdev(dev);
if (ni->ni_interfaces[0]) {
/* Use the IPoIB interface specified in 'networks=' */
- CLASSERT(LNET_MAX_INTERFACES > 1);
+ BUILD_BUG_ON(LNET_MAX_INTERFACES <= 1);
if (ni->ni_interfaces[1]) {
CERROR("Multiple interfaces not supported\n");
goto failed;
static int __init ko2iblnd_init(void)
{
- CLASSERT(sizeof(struct kib_msg) <= IBLND_MSG_SIZE);
- CLASSERT(offsetof(struct kib_msg,
+ BUILD_BUG_ON(sizeof(struct kib_msg) > IBLND_MSG_SIZE);
+ BUILD_BUG_ON(!offsetof(struct kib_msg,
ibm_u.get.ibgm_rd.rd_frags[IBLND_MAX_RDMA_FRAGS])
<= IBLND_MSG_SIZE);
- CLASSERT(offsetof(struct kib_msg,
+ BUILD_BUG_ON(!offsetof(struct kib_msg,
ibm_u.putack.ibpam_rd.rd_frags[IBLND_MAX_RDMA_FRAGS])
<= IBLND_MSG_SIZE);
} WIRE_ATTR;
struct kib_immediate_msg {
- lnet_hdr_t ibim_hdr; /* portals header */
+ struct lnet_hdr ibim_hdr; /* portals header */
char ibim_payload[0]; /* piggy-backed payload */
} WIRE_ATTR;
} WIRE_ATTR;
struct kib_putreq_msg {
- lnet_hdr_t ibprm_hdr; /* portals header */
+ struct lnet_hdr ibprm_hdr; /* portals header */
__u64 ibprm_cookie; /* opaque completion cookie */
} WIRE_ATTR;
} WIRE_ATTR;
struct kib_get_msg {
- lnet_hdr_t ibgm_hdr; /* portals header */
+ struct lnet_hdr ibgm_hdr; /* portals header */
__u64 ibgm_cookie; /* opaque completion cookie */
struct kib_rdma_desc ibgm_rd; /* rdma descriptor */
} WIRE_ATTR;
int
kiblnd_send(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg)
{
- lnet_hdr_t *hdr = &lntmsg->msg_hdr;
+ struct lnet_hdr *hdr = &lntmsg->msg_hdr;
int type = lntmsg->msg_type;
lnet_process_id_t target = lntmsg->msg_target;
int target_is_router = lntmsg->msg_target_is_router;
rc = cfs_cpt_bind(lnet_cpt_table(), sched->ibs_cpt);
if (rc) {
- CWARN("Failed to bind on CPT %d, please verify whether all CPUs are healthy and reload modules if necessary, otherwise your system might under risk of low performance\n",
+ CWARN("Unable to bind on CPU partition %d, please verify whether all CPUs are healthy and reload modules if necessary, otherwise your system might under risk of low performance\n",
sched->ibs_cpt);
}
write_unlock_bh(global_lock);
if (!conn->ksnc_proto) {
- conn->ksnc_proto = &ksocknal_protocol_v3x;
+ conn->ksnc_proto = &ksocknal_protocol_v3x;
#if SOCKNAL_VERSION_DEBUG
- if (*ksocknal_tunables.ksnd_protocol == 2)
- conn->ksnc_proto = &ksocknal_protocol_v2x;
- else if (*ksocknal_tunables.ksnd_protocol == 1)
- conn->ksnc_proto = &ksocknal_protocol_v1x;
+ if (*ksocknal_tunables.ksnd_protocol == 2)
+ conn->ksnc_proto = &ksocknal_protocol_v2x;
+ else if (*ksocknal_tunables.ksnd_protocol == 1)
+ conn->ksnc_proto = &ksocknal_protocol_v1x;
#endif
}
snprintf(name, sizeof(name), "socknal_cd%02d", i);
rc = ksocknal_thread_start(ksocknal_connd,
- (void *)((ulong_ptr_t)i), name);
+ (void *)((uintptr_t)i), name);
if (rc) {
spin_lock_bh(&ksocknal_data.ksnd_connd_lock);
ksocknal_data.ksnd_connd_starting--;
int rc;
/* check ksnr_connected/connecting field large enough */
- CLASSERT(SOCKLND_CONN_NTYPES <= 4);
- CLASSERT(SOCKLND_CONN_ACK == SOCKLND_CONN_BULK_IN);
+ BUILD_BUG_ON(SOCKLND_CONN_NTYPES > 4);
+ BUILD_BUG_ON(SOCKLND_CONN_ACK != SOCKLND_CONN_BULK_IN);
/* initialize the_ksocklnd */
the_ksocklnd.lnd_type = SOCKLND;
* V2.x message takes the
* whole struct
* V1.x message is a bare
- * lnet_hdr_t, it's stored in
+ * struct lnet_hdr, it's stored in
* ksnc_msg.ksm_u.lnetmsg
*/
/* WRITER */
tx->tx_niov = 1;
tx->tx_nonblk = nonblk;
- socklnd_init_msg(&tx->tx_msg, KSOCK_MSG_NOOP);
+ tx->tx_msg.ksm_csum = 0;
+ tx->tx_msg.ksm_type = KSOCK_MSG_NOOP;
+ tx->tx_msg.ksm_zc_cookies[0] = 0;
tx->tx_msg.ksm_zc_cookies[1] = cookie;
return tx;
tx->tx_zc_capable = 1;
}
- socklnd_init_msg(&tx->tx_msg, KSOCK_MSG_LNET);
+ tx->tx_msg.ksm_csum = 0;
+ tx->tx_msg.ksm_type = KSOCK_MSG_LNET;
+ tx->tx_msg.ksm_zc_cookies[0] = 0;
+ tx->tx_msg.ksm_zc_cookies[1] = 0;
/* The first fragment will be set later in pro_pack */
rc = ksocknal_launch_packet(ni, tx, target);
break;
case KSOCK_PROTO_V1:
- /* Receiving bare lnet_hdr_t */
+ /* Receiving bare struct lnet_hdr */
conn->ksnc_rx_state = SOCKNAL_RX_LNET_HEADER;
- conn->ksnc_rx_nob_wanted = sizeof(lnet_hdr_t);
- conn->ksnc_rx_nob_left = sizeof(lnet_hdr_t);
+ conn->ksnc_rx_nob_wanted = sizeof(struct lnet_hdr);
+ conn->ksnc_rx_nob_left = sizeof(struct lnet_hdr);
conn->ksnc_rx_iov = (struct kvec *)&conn->ksnc_rx_iov_space;
conn->ksnc_rx_iov[0].iov_base = &conn->ksnc_msg.ksm_u.lnetmsg;
- conn->ksnc_rx_iov[0].iov_len = sizeof(lnet_hdr_t);
+ conn->ksnc_rx_iov[0].iov_len = sizeof(struct lnet_hdr);
break;
default:
static int
ksocknal_process_receive(struct ksock_conn *conn)
{
- lnet_hdr_t *lhdr;
+ struct lnet_hdr *lhdr;
lnet_process_id_t *id;
int rc;
rc = cfs_cpt_bind(lnet_cpt_table(), info->ksi_cpt);
if (rc) {
- CERROR("Can't set CPT affinity to %d: %d\n",
- info->ksi_cpt, rc);
+ CWARN("Can't set CPU partition affinity to %d: %d\n",
+ info->ksi_cpt, rc);
}
spin_lock_bh(&sched->kss_lock);
}
if (hello->kshm_magic == le32_to_cpu(LNET_PROTO_TCP_MAGIC)) {
- lnet_magicversion_t *hmv = (lnet_magicversion_t *)hello;
+ struct lnet_magicversion *hmv = (struct lnet_magicversion *)hello;
- CLASSERT(sizeof(lnet_magicversion_t) ==
+ BUILD_BUG_ON(sizeof(struct lnet_magicversion) !=
offsetof(ksock_hello_msg_t, kshm_src_nid));
if (hmv->version_major == cpu_to_le16(KSOCK_PROTO_V1_MAJOR) &&
list_for_each_entry(peer, peers, ksnp_list) {
unsigned long deadline = 0;
+ struct ksock_tx *tx_stale;
int resid = 0;
int n = 0;
if (list_empty(&peer->ksnp_zc_req_list))
continue;
+ tx_stale = NULL;
spin_lock(&peer->ksnp_lock);
list_for_each_entry(tx, &peer->ksnp_zc_req_list, tx_zc_list) {
if (!cfs_time_aftereq(cfs_time_current(),
/* ignore the TX if connection is being closed */
if (tx->tx_conn->ksnc_closing)
continue;
+ if (!tx_stale)
+ tx_stale = tx;
n++;
}
- if (!n) {
+ if (!tx_stale) {
spin_unlock(&peer->ksnp_lock);
continue;
}
- tx = list_entry(peer->ksnp_zc_req_list.next,
- struct ksock_tx, tx_zc_list);
- deadline = tx->tx_deadline;
- resid = tx->tx_resid;
- conn = tx->tx_conn;
+ deadline = tx_stale->tx_deadline;
+ resid = tx_stale->tx_resid;
+ conn = tx_stale->tx_conn;
ksocknal_conn_addref(conn);
spin_unlock(&peer->ksnp_lock);
read_unlock(&ksocknal_data.ksnd_global_lock);
CERROR("Total %d stale ZC_REQs for peer %s detected; the oldest(%p) timed out %ld secs ago, resid: %d, wmem: %d\n",
- n, libcfs_nid2str(peer->ksnp_id.nid), tx,
+ n, libcfs_nid2str(peer->ksnp_id.nid), tx_stale,
cfs_duration_sec(cfs_time_current() - deadline),
resid, conn->ksnc_sock->sk->sk_wmem_queued);
} else {
nob = tx->tx_lnetmsg->msg_len +
((conn->ksnc_proto == &ksocknal_protocol_v1x) ?
- sizeof(lnet_hdr_t) : sizeof(ksock_msg_t));
+ sizeof(struct lnet_hdr) : sizeof(ksock_msg_t));
}
/* default checking for typed connection */
ksocknal_send_hello_v1(struct ksock_conn *conn, ksock_hello_msg_t *hello)
{
struct socket *sock = conn->ksnc_sock;
- lnet_hdr_t *hdr;
- lnet_magicversion_t *hmv;
+ struct lnet_hdr *hdr;
+ struct lnet_magicversion *hmv;
int rc;
int i;
- CLASSERT(sizeof(lnet_magicversion_t) == offsetof(lnet_hdr_t, src_nid));
+ BUILD_BUG_ON(sizeof(struct lnet_magicversion) != offsetof(struct lnet_hdr, src_nid));
LIBCFS_ALLOC(hdr, sizeof(*hdr));
if (!hdr) {
- CERROR("Can't allocate lnet_hdr_t\n");
+ CERROR("Can't allocate struct lnet_hdr\n");
return -ENOMEM;
}
- hmv = (lnet_magicversion_t *)&hdr->dest_nid;
+ hmv = (struct lnet_magicversion *)&hdr->dest_nid;
/*
- * Re-organize V2.x message header to V1.x (lnet_hdr_t)
+ * Re-organize V2.x message header to V1.x (struct lnet_hdr)
* header and send out
*/
hmv->magic = cpu_to_le32(LNET_PROTO_TCP_MAGIC);
int timeout)
{
struct socket *sock = conn->ksnc_sock;
- lnet_hdr_t *hdr;
+ struct lnet_hdr *hdr;
int rc;
int i;
LIBCFS_ALLOC(hdr, sizeof(*hdr));
if (!hdr) {
- CERROR("Can't allocate lnet_hdr_t\n");
+ CERROR("Can't allocate struct lnet_hdr\n");
return -ENOMEM;
}
rc = lnet_sock_read(sock, &hdr->src_nid,
- sizeof(*hdr) - offsetof(lnet_hdr_t, src_nid),
+ sizeof(*hdr) - offsetof(struct lnet_hdr, src_nid),
timeout);
if (rc) {
CERROR("Error %d reading rest of HELLO hdr from %pI4h\n",
LASSERT(tx->tx_lnetmsg);
tx->tx_iov[0].iov_base = &tx->tx_lnetmsg->msg_hdr;
- tx->tx_iov[0].iov_len = sizeof(lnet_hdr_t);
+ tx->tx_iov[0].iov_len = sizeof(struct lnet_hdr);
- tx->tx_nob = tx->tx_lnetmsg->msg_len + sizeof(lnet_hdr_t);
- tx->tx_resid = tx->tx_lnetmsg->msg_len + sizeof(lnet_hdr_t);
+ tx->tx_nob = tx->tx_lnetmsg->msg_len + sizeof(struct lnet_hdr);
+ tx->tx_resid = tx->tx_lnetmsg->msg_len + sizeof(struct lnet_hdr);
}
static void
last_dump_time = current_time;
snprintf(debug_file_name, sizeof(debug_file_name) - 1,
"%s.%lld.%ld", libcfs_debug_file_path_arr,
- (s64)current_time, (long_ptr_t)arg);
+ (s64)current_time, (long)arg);
pr_alert("LustreError: dumping log to %s\n", debug_file_name);
cfs_tracefile_dump_all_pages(debug_file_name);
libcfs_run_debug_log_upcall(debug_file_name);
struct cfs_hash *hs;
int len;
- CLASSERT(CFS_HASH_THETA_BITS < 15);
+ BUILD_BUG_ON(CFS_HASH_THETA_BITS >= 15);
LASSERT(name);
LASSERT(ops->hs_key);
*
* NB: If user specified cpu_pattern, cpu_npartitions will be ignored
*/
-static char *cpu_pattern = "";
+static char *cpu_pattern = "N";
module_param(cpu_pattern, charp, 0444);
MODULE_PARM_DESC(cpu_pattern, "CPU partitions pattern");
ret = -EINVAL;
if (*cpu_pattern) {
- cfs_cpt_table = cfs_cpt_table_create_pattern(cpu_pattern);
+ char *cpu_pattern_dup = kstrdup(cpu_pattern, GFP_KERNEL);
+
+ if (!cpu_pattern_dup) {
+ CERROR("Failed to duplicate cpu_pattern\n");
+ goto failed;
+ }
+
+ cfs_cpt_table = cfs_cpt_table_create_pattern(cpu_pattern_dup);
+ kfree(cpu_pattern_dup);
if (!cfs_cpt_table) {
CERROR("Failed to create cptab from pattern %s\n",
cpu_pattern);
}
spin_unlock(&cpt_data.cpt_lock);
- LCONSOLE(0, "HW CPU cores: %d, npartitions: %d\n",
- num_online_cpus(), cfs_cpt_number(cfs_cpt_table));
+ LCONSOLE(0, "HW nodes: %d, HW CPU cores: %d, npartitions: %d\n",
+ num_online_nodes(), num_online_cpus(),
+ cfs_cpt_number(cfs_cpt_table));
return 0;
failed:
const struct libcfs_ioctl_hdr __user *uhdr)
{
struct libcfs_ioctl_hdr hdr;
- int err = 0;
+ int err;
if (copy_from_user(&hdr, uhdr, sizeof(hdr)))
return -EFAULT;
return -ENOMEM;
if (copy_from_user(*hdr_pp, uhdr, hdr.ioc_len)) {
- LIBCFS_FREE(*hdr_pp, hdr.ioc_len);
err = -EFAULT;
+ goto free;
}
+
+ if ((*hdr_pp)->ioc_version != hdr.ioc_version ||
+ (*hdr_pp)->ioc_len != hdr.ioc_len) {
+ err = -EINVAL;
+ goto free;
+ }
+
+ return 0;
+
+free:
+ LIBCFS_FREE(*hdr_pp, hdr.ioc_len);
return err;
}
static const struct file_operations *lnet_debugfs_fops_select(umode_t mode)
{
- if (!(mode & S_IWUGO))
+ if (!(mode & 0222))
return &lnet_debugfs_file_operations_ro;
- if (!(mode & S_IRUGO))
+ if (!(mode & 0444))
return &lnet_debugfs_file_operations_wo;
return &lnet_debugfs_file_operations_rw;
/* CPT affinity scheduler? */
if (sched->ws_cptab)
if (cfs_cpt_bind(sched->ws_cptab, sched->ws_cpt))
- CWARN("Failed to bind %s on CPT %d\n",
+ CWARN("Unable to bind %s on CPU partition %d\n",
sched->ws_name, sched->ws_cpt);
spin_lock(&cfs_wi_data.wi_glock);
lnet_connect(struct socket **sockp, lnet_nid_t peer_nid,
__u32 local_ip, __u32 peer_ip, int peer_port)
{
- lnet_acceptor_connreq_t cr;
+ struct lnet_acceptor_connreq cr;
struct socket *sock;
int rc;
int port;
int fatal;
- CLASSERT(sizeof(cr) <= 16); /* not too big to be on the stack */
+ BUILD_BUG_ON(sizeof(cr) > 16); /* too big to be on the stack */
for (port = LNET_ACCEPTOR_MAX_RESERVED_PORT;
port >= LNET_ACCEPTOR_MIN_RESERVED_PORT;
continue;
}
- CLASSERT(LNET_PROTO_ACCEPTOR_VERSION == 1);
+ BUILD_BUG_ON(LNET_PROTO_ACCEPTOR_VERSION != 1);
cr.acr_magic = LNET_PROTO_ACCEPTOR_MAGIC;
cr.acr_version = LNET_PROTO_ACCEPTOR_VERSION;
static int
lnet_accept(struct socket *sock, __u32 magic)
{
- lnet_acceptor_connreq_t cr;
+ struct lnet_acceptor_connreq cr;
__u32 peer_ip;
int peer_port;
int rc;
rc = lnet_sock_read(sock, &cr.acr_nid,
sizeof(cr) -
- offsetof(lnet_acceptor_connreq_t, acr_nid),
+ offsetof(struct lnet_acceptor_connreq, acr_nid),
accept_timeout);
if (rc) {
CERROR("Error %d reading connection request from %pI4h\n",
__u32 magic;
__u32 peer_ip;
int peer_port;
- int secure = (int)((long_ptr_t)arg);
+ int secure = (int)((long)arg);
LASSERT(!lnet_acceptor_state.pta_sock);
if (!lnet_count_acceptor_nis()) /* not required */
return 0;
- task = kthread_run(lnet_acceptor, (void *)(ulong_ptr_t)secure,
+ task = kthread_run(lnet_acceptor, (void *)(uintptr_t)secure,
"acceptor_%03ld", secure);
if (IS_ERR(task)) {
rc2 = PTR_ERR(task);
*/
/* Constants... */
- CLASSERT(LNET_PROTO_TCP_MAGIC == 0xeebc0ded);
- CLASSERT(LNET_PROTO_TCP_VERSION_MAJOR == 1);
- CLASSERT(LNET_PROTO_TCP_VERSION_MINOR == 0);
- CLASSERT(LNET_MSG_ACK == 0);
- CLASSERT(LNET_MSG_PUT == 1);
- CLASSERT(LNET_MSG_GET == 2);
- CLASSERT(LNET_MSG_REPLY == 3);
- CLASSERT(LNET_MSG_HELLO == 4);
+ BUILD_BUG_ON(LNET_PROTO_TCP_MAGIC != 0xeebc0ded);
+ BUILD_BUG_ON(LNET_PROTO_TCP_VERSION_MAJOR != 1);
+ BUILD_BUG_ON(LNET_PROTO_TCP_VERSION_MINOR != 0);
+ BUILD_BUG_ON(LNET_MSG_ACK != 0);
+ BUILD_BUG_ON(LNET_MSG_PUT != 1);
+ BUILD_BUG_ON(LNET_MSG_GET != 2);
+ BUILD_BUG_ON(LNET_MSG_REPLY != 3);
+ BUILD_BUG_ON(LNET_MSG_HELLO != 4);
/* Checks for struct ptl_handle_wire_t */
- CLASSERT((int)sizeof(lnet_handle_wire_t) == 16);
- CLASSERT((int)offsetof(lnet_handle_wire_t, wh_interface_cookie) == 0);
- CLASSERT((int)sizeof(((lnet_handle_wire_t *)0)->wh_interface_cookie) == 8);
- CLASSERT((int)offsetof(lnet_handle_wire_t, wh_object_cookie) == 8);
- CLASSERT((int)sizeof(((lnet_handle_wire_t *)0)->wh_object_cookie) == 8);
-
- /* Checks for struct lnet_magicversion_t */
- CLASSERT((int)sizeof(lnet_magicversion_t) == 8);
- CLASSERT((int)offsetof(lnet_magicversion_t, magic) == 0);
- CLASSERT((int)sizeof(((lnet_magicversion_t *)0)->magic) == 4);
- CLASSERT((int)offsetof(lnet_magicversion_t, version_major) == 4);
- CLASSERT((int)sizeof(((lnet_magicversion_t *)0)->version_major) == 2);
- CLASSERT((int)offsetof(lnet_magicversion_t, version_minor) == 6);
- CLASSERT((int)sizeof(((lnet_magicversion_t *)0)->version_minor) == 2);
-
- /* Checks for struct lnet_hdr_t */
- CLASSERT((int)sizeof(lnet_hdr_t) == 72);
- CLASSERT((int)offsetof(lnet_hdr_t, dest_nid) == 0);
- CLASSERT((int)sizeof(((lnet_hdr_t *)0)->dest_nid) == 8);
- CLASSERT((int)offsetof(lnet_hdr_t, src_nid) == 8);
- CLASSERT((int)sizeof(((lnet_hdr_t *)0)->src_nid) == 8);
- CLASSERT((int)offsetof(lnet_hdr_t, dest_pid) == 16);
- CLASSERT((int)sizeof(((lnet_hdr_t *)0)->dest_pid) == 4);
- CLASSERT((int)offsetof(lnet_hdr_t, src_pid) == 20);
- CLASSERT((int)sizeof(((lnet_hdr_t *)0)->src_pid) == 4);
- CLASSERT((int)offsetof(lnet_hdr_t, type) == 24);
- CLASSERT((int)sizeof(((lnet_hdr_t *)0)->type) == 4);
- CLASSERT((int)offsetof(lnet_hdr_t, payload_length) == 28);
- CLASSERT((int)sizeof(((lnet_hdr_t *)0)->payload_length) == 4);
- CLASSERT((int)offsetof(lnet_hdr_t, msg) == 32);
- CLASSERT((int)sizeof(((lnet_hdr_t *)0)->msg) == 40);
+ BUILD_BUG_ON((int)sizeof(struct lnet_handle_wire) != 16);
+ BUILD_BUG_ON((int)offsetof(struct lnet_handle_wire, wh_interface_cookie) != 0);
+ BUILD_BUG_ON((int)sizeof(((struct lnet_handle_wire *)0)->wh_interface_cookie) != 8);
+ BUILD_BUG_ON((int)offsetof(struct lnet_handle_wire, wh_object_cookie) != 8);
+ BUILD_BUG_ON((int)sizeof(((struct lnet_handle_wire *)0)->wh_object_cookie) != 8);
+
+ /* Checks for struct struct lnet_magicversion */
+ BUILD_BUG_ON((int)sizeof(struct lnet_magicversion) != 8);
+ BUILD_BUG_ON((int)offsetof(struct lnet_magicversion, magic) != 0);
+ BUILD_BUG_ON((int)sizeof(((struct lnet_magicversion *)0)->magic) != 4);
+ BUILD_BUG_ON((int)offsetof(struct lnet_magicversion, version_major) != 4);
+ BUILD_BUG_ON((int)sizeof(((struct lnet_magicversion *)0)->version_major) != 2);
+ BUILD_BUG_ON((int)offsetof(struct lnet_magicversion, version_minor) != 6);
+ BUILD_BUG_ON((int)sizeof(((struct lnet_magicversion *)0)->version_minor) != 2);
+
+ /* Checks for struct struct lnet_hdr */
+ BUILD_BUG_ON((int)sizeof(struct lnet_hdr) != 72);
+ BUILD_BUG_ON((int)offsetof(struct lnet_hdr, dest_nid) != 0);
+ BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->dest_nid) != 8);
+ BUILD_BUG_ON((int)offsetof(struct lnet_hdr, src_nid) != 8);
+ BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->src_nid) != 8);
+ BUILD_BUG_ON((int)offsetof(struct lnet_hdr, dest_pid) != 16);
+ BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->dest_pid) != 4);
+ BUILD_BUG_ON((int)offsetof(struct lnet_hdr, src_pid) != 20);
+ BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->src_pid) != 4);
+ BUILD_BUG_ON((int)offsetof(struct lnet_hdr, type) != 24);
+ BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->type) != 4);
+ BUILD_BUG_ON((int)offsetof(struct lnet_hdr, payload_length) != 28);
+ BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->payload_length) != 4);
+ BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg) != 32);
+ BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg) != 40);
/* Ack */
- CLASSERT((int)offsetof(lnet_hdr_t, msg.ack.dst_wmd) == 32);
- CLASSERT((int)sizeof(((lnet_hdr_t *)0)->msg.ack.dst_wmd) == 16);
- CLASSERT((int)offsetof(lnet_hdr_t, msg.ack.match_bits) == 48);
- CLASSERT((int)sizeof(((lnet_hdr_t *)0)->msg.ack.match_bits) == 8);
- CLASSERT((int)offsetof(lnet_hdr_t, msg.ack.mlength) == 56);
- CLASSERT((int)sizeof(((lnet_hdr_t *)0)->msg.ack.mlength) == 4);
+ BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.ack.dst_wmd) != 32);
+ BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.ack.dst_wmd) != 16);
+ BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.ack.match_bits) != 48);
+ BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.ack.match_bits) != 8);
+ BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.ack.mlength) != 56);
+ BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.ack.mlength) != 4);
/* Put */
- CLASSERT((int)offsetof(lnet_hdr_t, msg.put.ack_wmd) == 32);
- CLASSERT((int)sizeof(((lnet_hdr_t *)0)->msg.put.ack_wmd) == 16);
- CLASSERT((int)offsetof(lnet_hdr_t, msg.put.match_bits) == 48);
- CLASSERT((int)sizeof(((lnet_hdr_t *)0)->msg.put.match_bits) == 8);
- CLASSERT((int)offsetof(lnet_hdr_t, msg.put.hdr_data) == 56);
- CLASSERT((int)sizeof(((lnet_hdr_t *)0)->msg.put.hdr_data) == 8);
- CLASSERT((int)offsetof(lnet_hdr_t, msg.put.ptl_index) == 64);
- CLASSERT((int)sizeof(((lnet_hdr_t *)0)->msg.put.ptl_index) == 4);
- CLASSERT((int)offsetof(lnet_hdr_t, msg.put.offset) == 68);
- CLASSERT((int)sizeof(((lnet_hdr_t *)0)->msg.put.offset) == 4);
+ BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.put.ack_wmd) != 32);
+ BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.put.ack_wmd) != 16);
+ BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.put.match_bits) != 48);
+ BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.put.match_bits) != 8);
+ BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.put.hdr_data) != 56);
+ BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.put.hdr_data) != 8);
+ BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.put.ptl_index) != 64);
+ BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.put.ptl_index) != 4);
+ BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.put.offset) != 68);
+ BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.put.offset) != 4);
/* Get */
- CLASSERT((int)offsetof(lnet_hdr_t, msg.get.return_wmd) == 32);
- CLASSERT((int)sizeof(((lnet_hdr_t *)0)->msg.get.return_wmd) == 16);
- CLASSERT((int)offsetof(lnet_hdr_t, msg.get.match_bits) == 48);
- CLASSERT((int)sizeof(((lnet_hdr_t *)0)->msg.get.match_bits) == 8);
- CLASSERT((int)offsetof(lnet_hdr_t, msg.get.ptl_index) == 56);
- CLASSERT((int)sizeof(((lnet_hdr_t *)0)->msg.get.ptl_index) == 4);
- CLASSERT((int)offsetof(lnet_hdr_t, msg.get.src_offset) == 60);
- CLASSERT((int)sizeof(((lnet_hdr_t *)0)->msg.get.src_offset) == 4);
- CLASSERT((int)offsetof(lnet_hdr_t, msg.get.sink_length) == 64);
- CLASSERT((int)sizeof(((lnet_hdr_t *)0)->msg.get.sink_length) == 4);
+ BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.get.return_wmd) != 32);
+ BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.get.return_wmd) != 16);
+ BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.get.match_bits) != 48);
+ BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.get.match_bits) != 8);
+ BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.get.ptl_index) != 56);
+ BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.get.ptl_index) != 4);
+ BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.get.src_offset) != 60);
+ BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.get.src_offset) != 4);
+ BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.get.sink_length) != 64);
+ BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.get.sink_length) != 4);
/* Reply */
- CLASSERT((int)offsetof(lnet_hdr_t, msg.reply.dst_wmd) == 32);
- CLASSERT((int)sizeof(((lnet_hdr_t *)0)->msg.reply.dst_wmd) == 16);
+ BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.reply.dst_wmd) != 32);
+ BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.reply.dst_wmd) != 16);
/* Hello */
- CLASSERT((int)offsetof(lnet_hdr_t, msg.hello.incarnation) == 32);
- CLASSERT((int)sizeof(((lnet_hdr_t *)0)->msg.hello.incarnation) == 8);
- CLASSERT((int)offsetof(lnet_hdr_t, msg.hello.type) == 40);
- CLASSERT((int)sizeof(((lnet_hdr_t *)0)->msg.hello.type) == 4);
+ BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.hello.incarnation) != 32);
+ BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.hello.incarnation) != 8);
+ BUILD_BUG_ON((int)offsetof(struct lnet_hdr, msg.hello.type) != 40);
+ BUILD_BUG_ON((int)sizeof(((struct lnet_hdr *)0)->msg.hello.type) != 4);
}
static lnd_t *
return count;
}
-static lnet_ping_info_t *
+static struct lnet_ping_info *
lnet_ping_info_create(int num_ni)
{
- lnet_ping_info_t *ping_info;
+ struct lnet_ping_info *ping_info;
unsigned int infosz;
- infosz = offsetof(lnet_ping_info_t, pi_ni[num_ni]);
+ infosz = offsetof(struct lnet_ping_info, pi_ni[num_ni]);
LIBCFS_ALLOC(ping_info, infosz);
if (!ping_info) {
CERROR("Can't allocate ping info[%d]\n", num_ni);
}
static inline void
-lnet_ping_info_free(lnet_ping_info_t *pinfo)
+lnet_ping_info_free(struct lnet_ping_info *pinfo)
{
LIBCFS_FREE(pinfo,
- offsetof(lnet_ping_info_t,
+ offsetof(struct lnet_ping_info,
pi_ni[pinfo->pi_nnis]));
}
static void
lnet_ping_event_handler(lnet_event_t *event)
{
- lnet_ping_info_t *pinfo = event->md.user_ptr;
+ struct lnet_ping_info *pinfo = event->md.user_ptr;
if (event->unlinked)
pinfo->pi_features = LNET_PING_FEAT_INVAL;
}
static int
-lnet_ping_info_setup(lnet_ping_info_t **ppinfo, lnet_handle_md_t *md_handle,
+lnet_ping_info_setup(struct lnet_ping_info **ppinfo, lnet_handle_md_t *md_handle,
int ni_count, bool set_eq)
{
lnet_process_id_t id = {LNET_NID_ANY, LNET_PID_ANY};
/* initialize md content */
md.start = *ppinfo;
- md.length = offsetof(lnet_ping_info_t,
+ md.length = offsetof(struct lnet_ping_info,
pi_ni[(*ppinfo)->pi_nnis]);
md.threshold = LNET_MD_THRESH_INF;
md.max_size = 0;
}
static void
-lnet_ping_md_unlink(lnet_ping_info_t *pinfo, lnet_handle_md_t *md_handle)
+lnet_ping_md_unlink(struct lnet_ping_info *pinfo, lnet_handle_md_t *md_handle)
{
sigset_t blocked = cfs_block_allsigs();
}
static void
-lnet_ping_info_install_locked(lnet_ping_info_t *ping_info)
+lnet_ping_info_install_locked(struct lnet_ping_info *ping_info)
{
- lnet_ni_status_t *ns;
+ struct lnet_ni_status *ns;
lnet_ni_t *ni;
int i = 0;
}
static void
-lnet_ping_target_update(lnet_ping_info_t *pinfo, lnet_handle_md_t md_handle)
+lnet_ping_target_update(struct lnet_ping_info *pinfo, lnet_handle_md_t md_handle)
{
- lnet_ping_info_t *old_pinfo = NULL;
+ struct lnet_ping_info *old_pinfo = NULL;
lnet_handle_md_t old_md;
/* switch the NIs to point to the new ping info created */
int im_a_router = 0;
int rc;
int ni_count;
- lnet_ping_info_t *pinfo;
+ struct lnet_ping_info *pinfo;
lnet_handle_md_t md_handle;
struct list_head net_head;
lnet_dyn_add_ni(lnet_pid_t requested_pid, struct lnet_ioctl_config_data *conf)
{
char *nets = conf->cfg_config_u.cfg_net.net_intf;
- lnet_ping_info_t *pinfo;
+ struct lnet_ping_info *pinfo;
lnet_handle_md_t md_handle;
struct lnet_ni *ni;
struct list_head net_head;
lnet_dyn_del_ni(__u32 net)
{
lnet_ni_t *ni;
- lnet_ping_info_t *pinfo;
+ struct lnet_ping_info *pinfo;
lnet_handle_md_t md_handle;
int rc;
int replied = 0;
const int a_long_time = 60000; /* mS */
int infosz;
- lnet_ping_info_t *info;
+ struct lnet_ping_info *info;
lnet_process_id_t tmpid;
int i;
int nob;
int rc2;
sigset_t blocked;
- infosz = offsetof(lnet_ping_info_t, pi_ni[n_ids]);
+ infosz = offsetof(struct lnet_ping_info, pi_ni[n_ids]);
if (n_ids <= 0 ||
id.nid == LNET_NID_ANY ||
goto out_1;
}
- if (nob < offsetof(lnet_ping_info_t, pi_ni[0])) {
+ if (nob < offsetof(struct lnet_ping_info, pi_ni[0])) {
CERROR("%s: Short reply %d(%d min)\n", libcfs_id2str(id),
- nob, (int)offsetof(lnet_ping_info_t, pi_ni[0]));
+ nob, (int)offsetof(struct lnet_ping_info, pi_ni[0]));
goto out_1;
}
if (info->pi_nnis < n_ids)
n_ids = info->pi_nnis;
- if (nob < offsetof(lnet_ping_info_t, pi_ni[n_ids])) {
+ if (nob < offsetof(struct lnet_ping_info, pi_ni[n_ids])) {
CERROR("%s: Short reply %d(%d expected)\n", libcfs_id2str(id),
- nob, (int)offsetof(lnet_ping_info_t, pi_ni[n_ids]));
+ nob, (int)offsetof(struct lnet_ping_info, pi_ni[n_ids]));
goto out_1;
}
!list_empty(&lp->lp_txq));
msg->msg_peertxcredit = 1;
- lp->lp_txqnob += msg->msg_len + sizeof(lnet_hdr_t);
+ lp->lp_txqnob += msg->msg_len + sizeof(struct lnet_hdr);
lp->lp_txcredits--;
if (lp->lp_txcredits < lp->lp_mintxcredits)
LASSERT((txpeer->lp_txcredits < 0) ==
!list_empty(&txpeer->lp_txq));
- txpeer->lp_txqnob -= msg->msg_len + sizeof(lnet_hdr_t);
+ txpeer->lp_txqnob -= msg->msg_len + sizeof(struct lnet_hdr);
LASSERT(txpeer->lp_txqnob >= 0);
txpeer->lp_txcredits++;
static void
lnet_recv_put(lnet_ni_t *ni, lnet_msg_t *msg)
{
- lnet_hdr_t *hdr = &msg->msg_hdr;
+ struct lnet_hdr *hdr = &msg->msg_hdr;
if (msg->msg_wanted)
lnet_setpayloadbuffer(msg);
static int
lnet_parse_put(lnet_ni_t *ni, lnet_msg_t *msg)
{
- lnet_hdr_t *hdr = &msg->msg_hdr;
+ struct lnet_hdr *hdr = &msg->msg_hdr;
struct lnet_match_info info;
bool ready_delay;
int rc;
lnet_parse_get(lnet_ni_t *ni, lnet_msg_t *msg, int rdma_get)
{
struct lnet_match_info info;
- lnet_hdr_t *hdr = &msg->msg_hdr;
- lnet_handle_wire_t reply_wmd;
+ struct lnet_hdr *hdr = &msg->msg_hdr;
+ struct lnet_handle_wire reply_wmd;
int rc;
/* Convert get fields to host byte order */
lnet_parse_reply(lnet_ni_t *ni, lnet_msg_t *msg)
{
void *private = msg->msg_private;
- lnet_hdr_t *hdr = &msg->msg_hdr;
+ struct lnet_hdr *hdr = &msg->msg_hdr;
lnet_process_id_t src = {0};
lnet_libmd_t *md;
int rlength;
static int
lnet_parse_ack(lnet_ni_t *ni, lnet_msg_t *msg)
{
- lnet_hdr_t *hdr = &msg->msg_hdr;
+ struct lnet_hdr *hdr = &msg->msg_hdr;
lnet_process_id_t src = {0};
lnet_libmd_t *md;
int cpt;
}
void
-lnet_print_hdr(lnet_hdr_t *hdr)
+lnet_print_hdr(struct lnet_hdr *hdr)
{
lnet_process_id_t src = {0};
lnet_process_id_t dst = {0};
}
int
-lnet_parse(lnet_ni_t *ni, lnet_hdr_t *hdr, lnet_nid_t from_nid,
+lnet_parse(lnet_ni_t *ni, struct lnet_hdr *hdr, lnet_nid_t from_nid,
void *private, int rdma_req)
{
int rc = 0;
void
lnet_build_msg_event(lnet_msg_t *msg, lnet_event_kind_t ev_type)
{
- lnet_hdr_t *hdr = &msg->msg_hdr;
+ struct lnet_hdr *hdr = &msg->msg_hdr;
lnet_event_t *ev = &msg->msg_ev;
LASSERT(!msg->msg_routing);
static int
lnet_complete_msg_locked(lnet_msg_t *msg, int cpt)
{
- lnet_handle_wire_t ack_wmd;
+ struct lnet_handle_wire ack_wmd;
int rc;
int status = msg->msg_ev.status;
again:
list_for_each_entry_safe(msg, tmp, head, msg_list) {
struct lnet_match_info info;
- lnet_hdr_t *hdr;
+ struct lnet_hdr *hdr;
int rc;
LASSERT(msg->msg_rx_delayed || head == &ptl->ptl_msg_stealing);
return -EINVAL;
}
- CLASSERT(sizeof(ifr.ifr_name) >= IFNAMSIZ);
+ BUILD_BUG_ON(sizeof(ifr.ifr_name) < IFNAMSIZ);
if (strlen(name) > sizeof(ifr.ifr_name) - 1)
return -E2BIG;
* Check if message from \a src to \a dst can match any existed drop rule
*/
bool
-lnet_drop_rule_match(lnet_hdr_t *hdr)
+lnet_drop_rule_match(struct lnet_hdr *hdr)
{
struct lnet_drop_rule *rule;
lnet_nid_t src = le64_to_cpu(hdr->src_nid);
* will be delayed if there is a match.
*/
bool
-lnet_delay_rule_match_locked(lnet_hdr_t *hdr, struct lnet_msg *msg)
+lnet_delay_rule_match_locked(struct lnet_hdr *hdr, struct lnet_msg *msg)
{
struct lnet_delay_rule *rule;
lnet_nid_t src = le64_to_cpu(hdr->src_nid);
int
lnet_fault_init(void)
{
- CLASSERT(LNET_PUT_BIT == 1 << LNET_MSG_PUT);
- CLASSERT(LNET_ACK_BIT == 1 << LNET_MSG_ACK);
- CLASSERT(LNET_GET_BIT == 1 << LNET_MSG_GET);
- CLASSERT(LNET_REPLY_BIT == 1 << LNET_MSG_REPLY);
+ BUILD_BUG_ON(LNET_PUT_BIT != 1 << LNET_MSG_PUT);
+ BUILD_BUG_ON(LNET_ACK_BIT != 1 << LNET_MSG_ACK);
+ BUILD_BUG_ON(LNET_GET_BIT != 1 << LNET_MSG_GET);
+ BUILD_BUG_ON(LNET_REPLY_BIT != 1 << LNET_MSG_REPLY);
mutex_init(&delay_dd.dd_mutex);
spin_lock_init(&delay_dd.dd_lock);
}
void
-lnet_swap_pinginfo(lnet_ping_info_t *info)
+lnet_swap_pinginfo(struct lnet_ping_info *info)
{
int i;
- lnet_ni_status_t *stat;
+ struct lnet_ni_status *stat;
__swab32s(&info->pi_magic);
__swab32s(&info->pi_features);
static void
lnet_parse_rc_info(lnet_rc_data_t *rcd)
{
- lnet_ping_info_t *info = rcd->rcd_pinginfo;
+ struct lnet_ping_info *info = rcd->rcd_pinginfo;
struct lnet_peer *gw = rcd->rcd_gateway;
lnet_route_t *rte;
}
for (i = 0; i < info->pi_nnis && i < LNET_MAX_RTR_NIS; i++) {
- lnet_ni_status_t *stat = &info->pi_ni[i];
+ struct lnet_ni_status *stat = &info->pi_ni[i];
lnet_nid_t nid = stat->ns_nid;
if (nid == LNET_NID_ANY) {
lnet_create_rc_data_locked(lnet_peer_t *gateway)
{
lnet_rc_data_t *rcd = NULL;
- lnet_ping_info_t *pi;
+ struct lnet_ping_info *pi;
lnet_md_t md;
int rc;
int i;
int ver;
int off;
- CLASSERT(sizeof(loff_t) >= 4);
+ BUILD_BUG_ON(sizeof(loff_t) < 4);
off = LNET_PROC_HOFF_GET(*ppos);
ver = LNET_PROC_VER_GET(*ppos);
int rc = 0;
int len;
- CLASSERT(LNET_PROC_HASH_BITS >= LNET_PEER_HASH_BITS);
+ BUILD_BUG_ON(LNET_PROC_HASH_BITS < LNET_PEER_HASH_BITS);
LASSERT(!write);
if (!*lenp)
return 0;
}
-int brw_inject_one_error(void)
+static int brw_inject_one_error(void)
{
struct timespec64 ts;
#include "console.h"
static int
-lst_session_new_ioctl(lstio_session_new_args_t *args)
+lst_session_new_ioctl(struct lstio_session_new_args *args)
{
char *name;
int rc;
}
static int
-lst_session_end_ioctl(lstio_session_end_args_t *args)
+lst_session_end_ioctl(struct lstio_session_end_args *args)
{
if (args->lstio_ses_key != console_session.ses_key)
return -EACCES;
}
static int
-lst_session_info_ioctl(lstio_session_info_args_t *args)
+lst_session_info_ioctl(struct lstio_session_info_args *args)
{
/* no checking of key */
}
static int
-lst_debug_ioctl(lstio_debug_args_t *args)
+lst_debug_ioctl(struct lstio_debug_args *args)
{
char *name = NULL;
int client = 1;
}
static int
-lst_group_add_ioctl(lstio_group_add_args_t *args)
+lst_group_add_ioctl(struct lstio_group_add_args *args)
{
char *name;
int rc;
}
static int
-lst_group_del_ioctl(lstio_group_del_args_t *args)
+lst_group_del_ioctl(struct lstio_group_del_args *args)
{
int rc;
char *name;
}
static int
-lst_group_update_ioctl(lstio_group_update_args_t *args)
+lst_group_update_ioctl(struct lstio_group_update_args *args)
{
int rc;
char *name;
}
static int
-lst_nodes_add_ioctl(lstio_group_nodes_args_t *args)
+lst_nodes_add_ioctl(struct lstio_group_nodes_args *args)
{
unsigned int feats;
int rc;
}
static int
-lst_group_list_ioctl(lstio_group_list_args_t *args)
+lst_group_list_ioctl(struct lstio_group_list_args *args)
{
if (args->lstio_grp_key != console_session.ses_key)
return -EACCES;
}
static int
-lst_group_info_ioctl(lstio_group_info_args_t *args)
+lst_group_info_ioctl(struct lstio_group_info_args *args)
{
char *name;
int ndent;
}
static int
-lst_batch_add_ioctl(lstio_batch_add_args_t *args)
+lst_batch_add_ioctl(struct lstio_batch_add_args *args)
{
int rc;
char *name;
}
static int
-lst_batch_run_ioctl(lstio_batch_run_args_t *args)
+lst_batch_run_ioctl(struct lstio_batch_run_args *args)
{
int rc;
char *name;
}
static int
-lst_batch_stop_ioctl(lstio_batch_stop_args_t *args)
+lst_batch_stop_ioctl(struct lstio_batch_stop_args *args)
{
int rc;
char *name;
}
static int
-lst_batch_query_ioctl(lstio_batch_query_args_t *args)
+lst_batch_query_ioctl(struct lstio_batch_query_args *args)
{
char *name;
int rc;
}
static int
-lst_batch_list_ioctl(lstio_batch_list_args_t *args)
+lst_batch_list_ioctl(struct lstio_batch_list_args *args)
{
if (args->lstio_bat_key != console_session.ses_key)
return -EACCES;
}
static int
-lst_batch_info_ioctl(lstio_batch_info_args_t *args)
+lst_batch_info_ioctl(struct lstio_batch_info_args *args)
{
char *name;
int rc;
}
static int
-lst_stat_query_ioctl(lstio_stat_args_t *args)
+lst_stat_query_ioctl(struct lstio_stat_args *args)
{
int rc;
char *name = NULL;
return rc;
}
-static int lst_test_add_ioctl(lstio_test_args_t *args)
+static int lst_test_add_ioctl(struct lstio_test_args *args)
{
char *batch_name;
char *src_name = NULL;
goto out;
}
- memset(&console_session.ses_trans_stat, 0, sizeof(lstcon_trans_stat_t));
+ memset(&console_session.ses_trans_stat, 0, sizeof(struct lstcon_trans_stat));
switch (opc) {
case LSTIO_SESSION_NEW:
- rc = lst_session_new_ioctl((lstio_session_new_args_t *)buf);
+ rc = lst_session_new_ioctl((struct lstio_session_new_args *)buf);
break;
case LSTIO_SESSION_END:
- rc = lst_session_end_ioctl((lstio_session_end_args_t *)buf);
+ rc = lst_session_end_ioctl((struct lstio_session_end_args *)buf);
break;
case LSTIO_SESSION_INFO:
- rc = lst_session_info_ioctl((lstio_session_info_args_t *)buf);
+ rc = lst_session_info_ioctl((struct lstio_session_info_args *)buf);
break;
case LSTIO_DEBUG:
- rc = lst_debug_ioctl((lstio_debug_args_t *)buf);
+ rc = lst_debug_ioctl((struct lstio_debug_args *)buf);
break;
case LSTIO_GROUP_ADD:
- rc = lst_group_add_ioctl((lstio_group_add_args_t *)buf);
+ rc = lst_group_add_ioctl((struct lstio_group_add_args *)buf);
break;
case LSTIO_GROUP_DEL:
- rc = lst_group_del_ioctl((lstio_group_del_args_t *)buf);
+ rc = lst_group_del_ioctl((struct lstio_group_del_args *)buf);
break;
case LSTIO_GROUP_UPDATE:
- rc = lst_group_update_ioctl((lstio_group_update_args_t *)buf);
+ rc = lst_group_update_ioctl((struct lstio_group_update_args *)buf);
break;
case LSTIO_NODES_ADD:
- rc = lst_nodes_add_ioctl((lstio_group_nodes_args_t *)buf);
+ rc = lst_nodes_add_ioctl((struct lstio_group_nodes_args *)buf);
break;
case LSTIO_GROUP_LIST:
- rc = lst_group_list_ioctl((lstio_group_list_args_t *)buf);
+ rc = lst_group_list_ioctl((struct lstio_group_list_args *)buf);
break;
case LSTIO_GROUP_INFO:
- rc = lst_group_info_ioctl((lstio_group_info_args_t *)buf);
+ rc = lst_group_info_ioctl((struct lstio_group_info_args *)buf);
break;
case LSTIO_BATCH_ADD:
- rc = lst_batch_add_ioctl((lstio_batch_add_args_t *)buf);
+ rc = lst_batch_add_ioctl((struct lstio_batch_add_args *)buf);
break;
case LSTIO_BATCH_START:
- rc = lst_batch_run_ioctl((lstio_batch_run_args_t *)buf);
+ rc = lst_batch_run_ioctl((struct lstio_batch_run_args *)buf);
break;
case LSTIO_BATCH_STOP:
- rc = lst_batch_stop_ioctl((lstio_batch_stop_args_t *)buf);
+ rc = lst_batch_stop_ioctl((struct lstio_batch_stop_args *)buf);
break;
case LSTIO_BATCH_QUERY:
- rc = lst_batch_query_ioctl((lstio_batch_query_args_t *)buf);
+ rc = lst_batch_query_ioctl((struct lstio_batch_query_args *)buf);
break;
case LSTIO_BATCH_LIST:
- rc = lst_batch_list_ioctl((lstio_batch_list_args_t *)buf);
+ rc = lst_batch_list_ioctl((struct lstio_batch_list_args *)buf);
break;
case LSTIO_BATCH_INFO:
- rc = lst_batch_info_ioctl((lstio_batch_info_args_t *)buf);
+ rc = lst_batch_info_ioctl((struct lstio_batch_info_args *)buf);
break;
case LSTIO_TEST_ADD:
- rc = lst_test_add_ioctl((lstio_test_args_t *)buf);
+ rc = lst_test_add_ioctl((struct lstio_test_args *)buf);
break;
case LSTIO_STAT_QUERY:
- rc = lst_stat_query_ioctl((lstio_stat_args_t *)buf);
+ rc = lst_stat_query_ioctl((struct lstio_stat_args *)buf);
break;
default:
rc = -EINVAL;
}
if (copy_to_user(data->ioc_pbuf2, &console_session.ses_trans_stat,
- sizeof(lstcon_trans_stat_t)))
+ sizeof(struct lstcon_trans_stat)))
rc = -EFAULT;
out:
mutex_unlock(&console_session.ses_mutex);
#include "console.h"
void lstcon_rpc_stat_reply(struct lstcon_rpc_trans *, struct srpc_msg *,
- struct lstcon_node *, lstcon_trans_stat_t *);
+ struct lstcon_node *, struct lstcon_trans_stat *);
static void
lstcon_rpc_done(struct srpc_client_rpc *rpc)
}
void
-lstcon_rpc_trans_stat(struct lstcon_rpc_trans *trans, lstcon_trans_stat_t *stat)
+lstcon_rpc_trans_stat(struct lstcon_rpc_trans *trans, struct lstcon_trans_stat *stat)
{
struct lstcon_rpc *crpc;
struct srpc_msg *rep;
{
struct list_head tmp;
struct list_head __user *next;
- lstcon_rpc_ent_t *ent;
+ struct lstcon_rpc_ent *ent;
struct srpc_generic_reply *rep;
struct lstcon_rpc *crpc;
struct srpc_msg *msg;
next = tmp.next;
- ent = list_entry(next, lstcon_rpc_ent_t, rpe_link);
+ ent = list_entry(next, struct lstcon_rpc_ent, rpe_link);
LASSERT(crpc->crp_stamp);
/* RPC is done */
rep = (struct srpc_generic_reply *)&msg->msg_body.reply;
- if (copy_to_user(&ent->rpe_sid, &rep->sid, sizeof(lst_sid_t)) ||
+ if (copy_to_user(&ent->rpe_sid, &rep->sid, sizeof(rep->sid)) ||
copy_to_user(&ent->rpe_fwk_errno, &rep->status,
sizeof(rep->status)))
return -EFAULT;
return 0;
}
-static lnet_process_id_packed_t *
+static struct lnet_process_id_packed *
lstcon_next_id(int idx, int nkiov, lnet_kiov_t *kiov)
{
- lnet_process_id_packed_t *pid;
+ struct lnet_process_id_packed *pid;
int i;
i = idx / SFW_ID_PER_PAGE;
LASSERT(i < nkiov);
- pid = (lnet_process_id_packed_t *)page_address(kiov[i].bv_page);
+ pid = (struct lnet_process_id_packed *)page_address(kiov[i].bv_page);
return &pid[idx % SFW_ID_PER_PAGE];
}
lstcon_dstnodes_prep(struct lstcon_group *grp, int idx,
int dist, int span, int nkiov, lnet_kiov_t *kiov)
{
- lnet_process_id_packed_t *pid;
+ struct lnet_process_id_packed *pid;
struct lstcon_ndlink *ndl;
struct lstcon_node *nd;
int start;
}
static int
-lstcon_pingrpc_prep(lst_test_ping_param_t *param, struct srpc_test_reqst *req)
+lstcon_pingrpc_prep(struct lst_test_ping_param *param, struct srpc_test_reqst *req)
{
struct test_ping_req *prq = &req->tsr_u.ping;
}
static int
-lstcon_bulkrpc_v0_prep(lst_test_bulk_param_t *param,
+lstcon_bulkrpc_v0_prep(struct lst_test_bulk_param *param,
struct srpc_test_reqst *req)
{
struct test_bulk_req *brq = &req->tsr_u.bulk_v0;
}
static int
-lstcon_bulkrpc_v1_prep(lst_test_bulk_param_t *param, bool is_client,
+lstcon_bulkrpc_v1_prep(struct lst_test_bulk_param *param, bool is_client,
struct srpc_test_reqst *req)
{
struct test_bulk_req_v1 *brq = &req->tsr_u.bulk_v1;
npg = sfw_id_pages(test->tes_span);
nob = !(feats & LST_FEAT_BULK_LEN) ?
npg * PAGE_SIZE :
- sizeof(lnet_process_id_packed_t) * test->tes_span;
+ sizeof(struct lnet_process_id_packed) * test->tes_span;
}
rc = lstcon_rpc_prep(nd, SRPC_SERVICE_TEST, feats, npg, nob, crpc);
switch (test->tes_type) {
case LST_TEST_PING:
trq->tsr_service = SRPC_SERVICE_PING;
- rc = lstcon_pingrpc_prep((lst_test_ping_param_t *)
+ rc = lstcon_pingrpc_prep((struct lst_test_ping_param *)
&test->tes_param[0], trq);
break;
case LST_TEST_BULK:
trq->tsr_service = SRPC_SERVICE_BRW;
if (!(feats & LST_FEAT_BULK_LEN)) {
- rc = lstcon_bulkrpc_v0_prep((lst_test_bulk_param_t *)
+ rc = lstcon_bulkrpc_v0_prep((struct lst_test_bulk_param *)
&test->tes_param[0], trq);
} else {
- rc = lstcon_bulkrpc_v1_prep((lst_test_bulk_param_t *)
+ rc = lstcon_bulkrpc_v1_prep((struct lst_test_bulk_param *)
&test->tes_param[0],
trq->tsr_is_client, trq);
}
void
lstcon_rpc_stat_reply(struct lstcon_rpc_trans *trans, struct srpc_msg *msg,
- struct lstcon_node *nd, lstcon_trans_stat_t *stat)
+ struct lstcon_node *nd, struct lstcon_trans_stat *stat)
{
struct srpc_rmsn_reply *rmsn_rep;
struct srpc_debug_reply *dbg_rep;
lstcon_rpc_trans_stat(console_session.ses_ping, lstcon_trans_stat());
lstcon_rpc_trans_destroy(console_session.ses_ping);
- memset(lstcon_trans_stat(), 0, sizeof(lstcon_trans_stat_t));
+ memset(lstcon_trans_stat(), 0, sizeof(struct lstcon_trans_stat));
console_session.ses_ping = NULL;
}
typedef int (*lstcon_rpc_cond_func_t)(int, struct lstcon_node *, void *);
typedef int (*lstcon_rpc_readent_func_t)(int, struct srpc_msg *,
- lstcon_rpc_ent_t __user *);
+ struct lstcon_rpc_ent __user *);
int lstcon_sesrpc_prep(struct lstcon_node *nd, int transop,
unsigned int version, struct lstcon_rpc **crpc);
void *arg, lstcon_rpc_cond_func_t condition,
struct lstcon_rpc_trans **transpp);
void lstcon_rpc_trans_stat(struct lstcon_rpc_trans *trans,
- lstcon_trans_stat_t *stat);
+ struct lstcon_trans_stat *stat);
int lstcon_rpc_trans_interpreter(struct lstcon_rpc_trans *trans,
struct list_head __user *head_up,
lstcon_rpc_readent_func_t readent);
static int
lstcon_sesrpc_readent(int transop, struct srpc_msg *msg,
- lstcon_rpc_ent_t __user *ent_up)
+ struct lstcon_rpc_ent __user *ent_up)
{
struct srpc_debug_reply *rep;
static int
lstcon_nodes_getent(struct list_head *head, int *index_p,
- int *count_p, lstcon_node_ent_t __user *dents_up)
+ int *count_p, struct lstcon_node_ent __user *dents_up)
{
struct lstcon_ndlink *ndl;
struct lstcon_node *nd;
}
int
-lstcon_group_info(char *name, lstcon_ndlist_ent_t __user *gents_p,
+lstcon_group_info(char *name, struct lstcon_ndlist_ent __user *gents_p,
int *index_p, int *count_p,
- lstcon_node_ent_t __user *dents_up)
+ struct lstcon_node_ent __user *dents_up)
{
- lstcon_ndlist_ent_t *gentp;
+ struct lstcon_ndlist_ent *gentp;
struct lstcon_group *grp;
struct lstcon_ndlink *ndl;
int rc;
}
/* non-verbose query */
- LIBCFS_ALLOC(gentp, sizeof(lstcon_ndlist_ent_t));
+ LIBCFS_ALLOC(gentp, sizeof(struct lstcon_ndlist_ent));
if (!gentp) {
CERROR("Can't allocate ndlist_ent\n");
lstcon_group_decref(grp);
LST_NODE_STATE_COUNTER(ndl->ndl_node, gentp);
rc = copy_to_user(gents_p, gentp,
- sizeof(lstcon_ndlist_ent_t)) ? -EFAULT : 0;
+ sizeof(struct lstcon_ndlist_ent)) ? -EFAULT : 0;
- LIBCFS_FREE(gentp, sizeof(lstcon_ndlist_ent_t));
+ LIBCFS_FREE(gentp, sizeof(struct lstcon_ndlist_ent));
lstcon_group_decref(grp);
}
int
-lstcon_batch_info(char *name, lstcon_test_batch_ent_t __user *ent_up,
+lstcon_batch_info(char *name, struct lstcon_test_batch_ent __user *ent_up,
int server, int testidx, int *index_p, int *ndent_p,
- lstcon_node_ent_t __user *dents_up)
+ struct lstcon_node_ent __user *dents_up)
{
- lstcon_test_batch_ent_t *entp;
+ struct lstcon_test_batch_ent *entp;
struct list_head *clilst;
struct list_head *srvlst;
struct lstcon_test *test = NULL;
}
/* non-verbose query */
- LIBCFS_ALLOC(entp, sizeof(lstcon_test_batch_ent_t));
+ LIBCFS_ALLOC(entp, sizeof(struct lstcon_test_batch_ent));
if (!entp)
return -ENOMEM;
LST_NODE_STATE_COUNTER(ndl->ndl_node, &entp->tbe_srv_nle);
rc = copy_to_user(ent_up, entp,
- sizeof(lstcon_test_batch_ent_t)) ? -EFAULT : 0;
+ sizeof(struct lstcon_test_batch_ent)) ? -EFAULT : 0;
- LIBCFS_FREE(entp, sizeof(lstcon_test_batch_ent_t));
+ LIBCFS_FREE(entp, sizeof(struct lstcon_test_batch_ent));
return rc;
}
static int
lstcon_tsbrpc_readent(int transop, struct srpc_msg *msg,
- lstcon_rpc_ent_t __user *ent_up)
+ struct lstcon_rpc_ent __user *ent_up)
{
struct srpc_batch_reply *rep = &msg->msg_body.bat_reply;
static int
lstcon_statrpc_readent(int transop, struct srpc_msg *msg,
- lstcon_rpc_ent_t __user *ent_up)
+ struct lstcon_rpc_ent __user *ent_up)
{
struct srpc_stat_reply *rep = &msg->msg_body.stat_reply;
- sfw_counters_t __user *sfwk_stat;
- srpc_counters_t __user *srpc_stat;
+ struct sfw_counters __user *sfwk_stat;
+ struct srpc_counters __user *srpc_stat;
lnet_counters_t __user *lnet_stat;
if (rep->str_status)
return 0;
- sfwk_stat = (sfw_counters_t __user *)&ent_up->rpe_payload[0];
- srpc_stat = (srpc_counters_t __user *)(sfwk_stat + 1);
+ sfwk_stat = (struct sfw_counters __user *)&ent_up->rpe_payload[0];
+ srpc_stat = (struct srpc_counters __user *)(sfwk_stat + 1);
lnet_stat = (lnet_counters_t __user *)(srpc_stat + 1);
if (copy_to_user(sfwk_stat, &rep->str_fw, sizeof(*sfwk_stat)) ||
}
int
-lstcon_session_match(lst_sid_t sid)
+lstcon_session_match(struct lst_sid sid)
{
return (console_session.ses_id.ses_nid == sid.ses_nid &&
console_session.ses_id.ses_stamp == sid.ses_stamp) ? 1 : 0;
}
static void
-lstcon_new_session_id(lst_sid_t *sid)
+lstcon_new_session_id(struct lst_sid *sid)
{
lnet_process_id_t id;
int
lstcon_session_new(char *name, int key, unsigned int feats,
- int timeout, int force, lst_sid_t __user *sid_up)
+ int timeout, int force, struct lst_sid __user *sid_up)
{
int rc = 0;
int i;
}
if (!copy_to_user(sid_up, &console_session.ses_id,
- sizeof(lst_sid_t)))
+ sizeof(struct lst_sid)))
return rc;
lstcon_session_end();
}
int
-lstcon_session_info(lst_sid_t __user *sid_up, int __user *key_up,
+lstcon_session_info(struct lst_sid __user *sid_up, int __user *key_up,
unsigned __user *featp,
- lstcon_ndlist_ent_t __user *ndinfo_up,
+ struct lstcon_ndlist_ent __user *ndinfo_up,
char __user *name_up, int len)
{
- lstcon_ndlist_ent_t *entp;
+ struct lstcon_ndlist_ent *entp;
struct lstcon_ndlink *ndl;
int rc = 0;
LST_NODE_STATE_COUNTER(ndl->ndl_node, entp);
if (copy_to_user(sid_up, &console_session.ses_id,
- sizeof(lst_sid_t)) ||
+ sizeof(*sid_up)) ||
copy_to_user(key_up, &console_session.ses_key,
sizeof(*key_up)) ||
copy_to_user(featp, &console_session.ses_features,
#define LST_BATCH_RUNNING 0xB1 /* running batch */
struct lstcon_tsb_hdr {
- lst_bid_t tsb_id; /* batch ID */
+ struct lst_bid tsb_id; /* batch ID */
int tsb_index; /* test index */
};
struct lstcon_session {
struct mutex ses_mutex; /* only 1 thread in session */
- lst_sid_t ses_id; /* global session id */
+ struct lst_sid ses_id; /* global session id */
int ses_key; /* local session key */
int ses_state; /* state of session */
int ses_timeout; /* timeout in seconds */
char ses_name[LST_NAME_SIZE];/* session name */
struct lstcon_rpc_trans *ses_ping; /* session pinger */
struct stt_timer ses_ping_timer; /* timer for pinger */
- lstcon_trans_stat_t ses_trans_stat; /* transaction stats */
+ struct lstcon_trans_stat ses_trans_stat; /* transaction stats */
struct list_head ses_trans_list; /* global list of transaction */
struct list_head ses_grp_list; /* global list of groups */
extern struct lstcon_session console_session;
-static inline lstcon_trans_stat_t *
+static inline struct lstcon_trans_stat *
lstcon_trans_stat(void)
{
return &console_session.ses_trans_stat;
int lstcon_ioctl_entry(unsigned int cmd, struct libcfs_ioctl_hdr *hdr);
int lstcon_console_init(void);
int lstcon_console_fini(void);
-int lstcon_session_match(lst_sid_t sid);
+int lstcon_session_match(struct lst_sid sid);
int lstcon_session_new(char *name, int key, unsigned int version,
- int timeout, int flags, lst_sid_t __user *sid_up);
-int lstcon_session_info(lst_sid_t __user *sid_up, int __user *key,
- unsigned __user *verp, lstcon_ndlist_ent_t __user *entp,
+ int timeout, int flags, struct lst_sid __user *sid_up);
+int lstcon_session_info(struct lst_sid __user *sid_up, int __user *key,
+ unsigned __user *verp, struct lstcon_ndlist_ent __user *entp,
char __user *name_up, int len);
int lstcon_session_end(void);
int lstcon_session_debug(int timeout, struct list_head __user *result_up);
unsigned int *featp, struct list_head __user *result_up);
int lstcon_nodes_remove(char *name, int nnd, lnet_process_id_t __user *nds_up,
struct list_head __user *result_up);
-int lstcon_group_info(char *name, lstcon_ndlist_ent_t __user *gent_up,
+int lstcon_group_info(char *name, struct lstcon_ndlist_ent __user *gent_up,
int *index_p, int *ndent_p,
- lstcon_node_ent_t __user *ndents_up);
+ struct lstcon_node_ent __user *ndents_up);
int lstcon_group_list(int idx, int len, char __user *name_up);
int lstcon_batch_add(char *name);
int lstcon_batch_run(char *name, int timeout,
struct list_head __user *result_up);
int lstcon_batch_del(char *name);
int lstcon_batch_list(int idx, int namelen, char __user *name_up);
-int lstcon_batch_info(char *name, lstcon_test_batch_ent_t __user *ent_up,
+int lstcon_batch_info(char *name, struct lstcon_test_batch_ent __user *ent_up,
int server, int testidx, int *index_p,
- int *ndent_p, lstcon_node_ent_t __user *dents_up);
+ int *ndent_p, struct lstcon_node_ent __user *dents_up);
int lstcon_group_stat(char *grp_name, int timeout,
struct list_head __user *result_up);
int lstcon_nodes_stat(int count, lnet_process_id_t __user *ids_up,
#include "selftest.h"
-lst_sid_t LST_INVALID_SID = {LNET_NID_ANY, -1};
+struct lst_sid LST_INVALID_SID = {LNET_NID_ANY, -1};
static int session_timeout = 100;
module_param(session_timeout, int, 0444);
}
static inline void
-sfw_init_session(struct sfw_session *sn, lst_sid_t sid,
+sfw_init_session(struct sfw_session *sn, struct lst_sid sid,
unsigned int features, const char *name)
{
struct stt_timer *timer = &sn->sn_timer;
}
static struct sfw_batch *
-sfw_find_batch(lst_bid_t bid)
+sfw_find_batch(struct lst_bid bid)
{
struct sfw_session *sn = sfw_data.fw_session;
struct sfw_batch *bat;
}
static struct sfw_batch *
-sfw_bid2batch(lst_bid_t bid)
+sfw_bid2batch(struct lst_bid bid)
{
struct sfw_session *sn = sfw_data.fw_session;
struct sfw_batch *bat;
sfw_get_stats(struct srpc_stat_reqst *request, struct srpc_stat_reply *reply)
{
struct sfw_session *sn = sfw_data.fw_session;
- sfw_counters_t *cnt = &reply->str_fw;
+ struct sfw_counters *cnt = &reply->str_fw;
struct sfw_batch *bat;
reply->str_sid = !sn ? LST_INVALID_SID : sn->sn_id;
LASSERT(bk);
LASSERT(bk->bk_niov * SFW_ID_PER_PAGE >= (unsigned int)ndest);
LASSERT((unsigned int)bk->bk_len >=
- sizeof(lnet_process_id_packed_t) * ndest);
+ sizeof(struct lnet_process_id_packed) * ndest);
sfw_unpack_addtest_req(msg);
memcpy(&tsi->tsi_u, &req->tsr_u, sizeof(tsi->tsi_u));
for (i = 0; i < ndest; i++) {
- lnet_process_id_packed_t *dests;
- lnet_process_id_packed_t id;
+ struct lnet_process_id_packed *dests;
+ struct lnet_process_id_packed id;
int j;
dests = page_address(bk->bk_iovs[i / SFW_ID_PER_PAGE].bv_page);
len = npg * PAGE_SIZE;
} else {
- len = sizeof(lnet_process_id_packed_t) *
+ len = sizeof(struct lnet_process_id_packed) *
request->tsr_ndest;
}
rc = cfs_wi_sched_create("lst_t", lnet_cpt_table(), i,
nthrs, &lst_sched_test[i]);
if (rc) {
- CERROR("Failed to create CPT affinity WI scheduler %d for LST\n", i);
+ CWARN("Failed to create CPU partition affinity WI scheduler %d for LST\n",
+ i);
goto error;
}
}
struct srpc_service *rpc_services[SRPC_SERVICE_MAX_ID + 1];
lnet_handle_eq_t rpc_lnet_eq; /* _the_ LNet event queue */
enum srpc_state rpc_state;
- srpc_counters_t rpc_counters;
+ struct srpc_counters rpc_counters;
__u64 rpc_matchbits; /* matchbits counter */
} srpc_data;
/* forward ref's */
int srpc_handle_rpc(struct swi_workitem *wi);
-void srpc_get_counters(srpc_counters_t *cnt)
+void srpc_get_counters(struct srpc_counters *cnt)
{
spin_lock(&srpc_data.rpc_glock);
*cnt = srpc_data.rpc_counters;
spin_unlock(&srpc_data.rpc_glock);
}
-void srpc_set_counters(const srpc_counters_t *cnt)
+void srpc_set_counters(const struct srpc_counters *cnt)
{
spin_lock(&srpc_data.rpc_glock);
srpc_data.rpc_counters = *cnt;
struct srpc_generic_reply {
__u32 status;
- lst_sid_t sid;
+ struct lst_sid sid;
} WIRE_ATTR;
/* FRAMEWORK RPCs */
struct srpc_mksn_reqst {
__u64 mksn_rpyid; /* reply buffer matchbits */
- lst_sid_t mksn_sid; /* session id */
+ struct lst_sid mksn_sid; /* session id */
__u32 mksn_force; /* use brute force */
char mksn_name[LST_NAME_SIZE];
} WIRE_ATTR; /* make session request */
struct srpc_mksn_reply {
__u32 mksn_status; /* session status */
- lst_sid_t mksn_sid; /* session id */
+ struct lst_sid mksn_sid; /* session id */
__u32 mksn_timeout; /* session timeout */
char mksn_name[LST_NAME_SIZE];
} WIRE_ATTR; /* make session reply */
struct srpc_rmsn_reqst {
__u64 rmsn_rpyid; /* reply buffer matchbits */
- lst_sid_t rmsn_sid; /* session id */
+ struct lst_sid rmsn_sid; /* session id */
} WIRE_ATTR; /* remove session request */
struct srpc_rmsn_reply {
__u32 rmsn_status;
- lst_sid_t rmsn_sid; /* session id */
+ struct lst_sid rmsn_sid; /* session id */
} WIRE_ATTR; /* remove session reply */
struct srpc_join_reqst {
__u64 join_rpyid; /* reply buffer matchbits */
- lst_sid_t join_sid; /* session id to join */
+ struct lst_sid join_sid; /* session id to join */
char join_group[LST_NAME_SIZE]; /* group name */
} WIRE_ATTR;
struct srpc_join_reply {
__u32 join_status; /* returned status */
- lst_sid_t join_sid; /* session id */
+ struct lst_sid join_sid; /* session id */
__u32 join_timeout; /* # seconds' inactivity to
* expire
*/
struct srpc_debug_reqst {
__u64 dbg_rpyid; /* reply buffer matchbits */
- lst_sid_t dbg_sid; /* session id */
+ struct lst_sid dbg_sid; /* session id */
__u32 dbg_flags; /* bitmap of debug */
} WIRE_ATTR;
struct srpc_debug_reply {
__u32 dbg_status; /* returned code */
- lst_sid_t dbg_sid; /* session id */
+ struct lst_sid dbg_sid; /* session id */
__u32 dbg_timeout; /* session timeout */
__u32 dbg_nbatch; /* # of batches in the node */
char dbg_name[LST_NAME_SIZE]; /* session name */
struct srpc_batch_reqst {
__u64 bar_rpyid; /* reply buffer matchbits */
- lst_sid_t bar_sid; /* session id */
- lst_bid_t bar_bid; /* batch id */
+ struct lst_sid bar_sid; /* session id */
+ struct lst_bid bar_bid; /* batch id */
__u32 bar_opc; /* create/start/stop batch */
__u32 bar_testidx; /* index of test */
__u32 bar_arg; /* parameters */
struct srpc_batch_reply {
__u32 bar_status; /* status of request */
- lst_sid_t bar_sid; /* session id */
+ struct lst_sid bar_sid; /* session id */
__u32 bar_active; /* # of active tests in batch/test */
__u32 bar_time; /* remained time */
} WIRE_ATTR;
struct srpc_stat_reqst {
__u64 str_rpyid; /* reply buffer matchbits */
- lst_sid_t str_sid; /* session id */
+ struct lst_sid str_sid; /* session id */
__u32 str_type; /* type of stat */
} WIRE_ATTR;
struct srpc_stat_reply {
__u32 str_status;
- lst_sid_t str_sid;
- sfw_counters_t str_fw;
- srpc_counters_t str_rpc;
+ struct lst_sid str_sid;
+ struct sfw_counters str_fw;
+ struct srpc_counters str_rpc;
lnet_counters_t str_lnet;
} WIRE_ATTR;
struct srpc_test_reqst {
__u64 tsr_rpyid; /* reply buffer matchbits */
__u64 tsr_bulkid; /* bulk buffer matchbits */
- lst_sid_t tsr_sid; /* session id */
- lst_bid_t tsr_bid; /* batch id */
+ struct lst_sid tsr_sid; /* session id */
+ struct lst_bid tsr_bid; /* batch id */
__u32 tsr_service; /* test type: bulk|ping|... */
__u32 tsr_loop; /* test client loop count or
* # server buffers needed
struct srpc_test_reply {
__u32 tsr_status; /* returned code */
- lst_sid_t tsr_sid;
+ struct lst_sid tsr_sid;
} WIRE_ATTR;
/* TEST RPCs */
struct sfw_session {
struct list_head sn_list; /* chain on fw_zombie_sessions */
- lst_sid_t sn_id; /* unique identifier */
+ struct lst_sid sn_id; /* unique identifier */
unsigned int sn_timeout; /* # seconds' inactivity to expire */
int sn_timer_active;
unsigned int sn_features;
struct sfw_batch {
struct list_head bat_list; /* chain on sn_batches */
- lst_bid_t bat_id; /* batch id */
+ struct lst_bid bat_id; /* batch id */
int bat_error; /* error code of batch */
struct sfw_session *bat_session; /* batch's session */
atomic_t bat_nactive; /* # of active tests */
* pages are not used
*/
#define SFW_MAX_CONCUR LST_MAX_CONCUR
-#define SFW_ID_PER_PAGE (PAGE_SIZE / sizeof(lnet_process_id_packed_t))
+#define SFW_ID_PER_PAGE (PAGE_SIZE / sizeof(struct lnet_process_id_packed))
#define SFW_MAX_NDESTS (LNET_MAX_IOV * SFW_ID_PER_PAGE)
#define sfw_id_pages(n) (((n) + SFW_ID_PER_PAGE - 1) / SFW_ID_PER_PAGE)
int srpc_finish_service(struct srpc_service *sv);
int srpc_service_add_buffers(struct srpc_service *sv, int nbuffer);
void srpc_service_remove_buffers(struct srpc_service *sv, int nbuffer);
-void srpc_get_counters(srpc_counters_t *cnt);
-void srpc_set_counters(const srpc_counters_t *cnt);
+void srpc_get_counters(struct srpc_counters *cnt);
+void srpc_set_counters(const struct srpc_counters *cnt);
extern struct cfs_wi_sched *lst_sched_serial;
extern struct cfs_wi_sched **lst_sched_test;
* FID_SEQ_START + 2 is for .lustre directory and its objects
*/
const struct lu_seq_range LUSTRE_SEQ_SPACE_RANGE = {
- FID_SEQ_NORMAL,
- (__u64)~0ULL
+ .lsr_start = FID_SEQ_NORMAL,
+ .lsr_end = (__u64)~0ULL,
};
/* Zero range, used for init and other purposes. */
const struct lu_seq_range LUSTRE_SEQ_ZERO_RANGE = {
- 0,
- 0
+ .lsr_start = 0,
};
/* Lustre Big Fs Lock fid. */
LPROC_SEQ_FOPS_RO(ldebugfs_fid_fid);
struct lprocfs_vars seq_client_debugfs_list[] = {
- { "space", &ldebugfs_fid_space_fops },
- { "width", &ldebugfs_fid_width_fops },
- { "server", &ldebugfs_fid_server_fops },
- { "fid", &ldebugfs_fid_fid_fops },
+ { .name = "space",
+ .fops = &ldebugfs_fid_space_fops },
+ { .name = "width",
+ .fops = &ldebugfs_fid_width_fops },
+ { .name = "server",
+ .fops = &ldebugfs_fid_server_fops },
+ { .name = "fid",
+ .fops = &ldebugfs_fid_fid_fops },
{ NULL }
};
size_t cl_size;
/** Layout generation. */
u32 cl_layout_gen;
- /**
- * True if this is a released file.
- * Temporarily added for released file truncate in ll_setattr_raw().
- * It will be removed later. -Jinshan
- */
- bool cl_is_released;
};
/**
* cra_end is included.
*/
pgoff_t cra_end;
+ /* optimal RPC size for this read, by pages */
+ unsigned long cra_rpc_size;
/*
- * Release routine. If readahead holds resources underneath, this
+ * Release callback. If readahead holds resources underneath, this
* function should be called to release it.
*/
void (*cra_release)(const struct lu_env *env, void *cbdata);
do { \
typeof(foo_io) __foo_io = (foo_io); \
\
- CLASSERT(offsetof(typeof(*__foo_io), base) == 0); \
+ BUILD_BUG_ON(offsetof(typeof(*__foo_io), base) != 0); \
memset(&__foo_io->base + 1, 0, \
sizeof(*__foo_io) - sizeof(__foo_io->base)); \
} while (0)
#ifndef _INTERVAL_H__
#define _INTERVAL_H__
-#include "../../include/linux/libcfs/libcfs.h" /* LASSERT. */
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
struct interval_node {
struct interval_node *in_left;
return node->in_extent.end;
}
-static inline void interval_set(struct interval_node *node,
- __u64 start, __u64 end)
+static inline int interval_set(struct interval_node *node,
+ __u64 start, __u64 end)
{
- LASSERT(start <= end);
+ if (start > end)
+ return -ERANGE;
node->in_extent.start = start;
node->in_extent.end = end;
node->in_max_high = end;
+ return 0;
}
/*
#define __LUSTRE_LU_OBJECT_H
#include <stdarg.h>
+#include <linux/percpu_counter.h>
#include "../../include/linux/libcfs/libcfs.h"
#include "lustre/lustre_idl.h"
#include "lu_ref.h"
LU_SS_CACHE_RACE,
LU_SS_CACHE_DEATH_RACE,
LU_SS_LRU_PURGED,
- LU_SS_LRU_LEN, /* # of objects in lsb_lru lists */
LU_SS_LAST_STAT
};
* XXX: a hack! fld has to find md_site via site, remove when possible
*/
struct seq_server_site *ld_seq_site;
+ /**
+ * Number of objects in lsb_lru_lists - used for shrinking
+ */
+ struct percpu_counter ls_lru_len_counter;
};
static inline struct lu_site_bkt_data *
void lu_object_put(const struct lu_env *env, struct lu_object *o);
void lu_object_unhash(const struct lu_env *env, struct lu_object *o);
+int lu_site_purge_objects(const struct lu_env *env, struct lu_site *s, int nr,
+ bool canblock);
-int lu_site_purge(const struct lu_env *env, struct lu_site *s, int nr);
+static inline int lu_site_purge(const struct lu_env *env, struct lu_site *s,
+ int nr)
+{
+ return lu_site_purge_objects(env, s, nr, true);
+}
void lu_site_print(const struct lu_env *env, struct lu_site *s, void *cookie,
lu_printer_t printer);
{ \
type *value; \
\
- CLASSERT(PAGE_SIZE >= sizeof(*value)); \
+ BUILD_BUG_ON(PAGE_SIZE < sizeof(*value)); \
\
value = kzalloc(sizeof(*value), GFP_NOFS); \
if (!value) \
int lu_buf_check_and_grow(struct lu_buf *buf, size_t len);
struct lu_buf *lu_buf_check_and_alloc(struct lu_buf *buf, size_t len);
+extern __u32 lu_context_tags_default;
+extern __u32 lu_session_tags_default;
+
/** @} lu */
#endif /* __LUSTRE_LU_OBJECT_H */
#define o_cksum o_nlink
#define o_grant_used o_data_version
-static inline void lustre_set_wire_obdo(const struct obd_connect_data *ocd,
- struct obdo *wobdo,
- const struct obdo *lobdo)
-{
- *wobdo = *lobdo;
- wobdo->o_flags &= ~OBD_FL_LOCAL_MASK;
- if (!ocd)
- return;
-
- if (unlikely(!(ocd->ocd_connect_flags & OBD_CONNECT_FID)) &&
- fid_seq_is_echo(ostid_seq(&lobdo->o_oi))) {
- /* Currently OBD_FL_OSTID will only be used when 2.4 echo
- * client communicate with pre-2.4 server
- */
- wobdo->o_oi.oi.oi_id = fid_oid(&lobdo->o_oi.oi_fid);
- wobdo->o_oi.oi.oi_seq = fid_seq(&lobdo->o_oi.oi_fid);
- }
-}
-
-static inline void lustre_get_wire_obdo(const struct obd_connect_data *ocd,
- struct obdo *lobdo,
- const struct obdo *wobdo)
-{
- __u32 local_flags = 0;
-
- if (lobdo->o_valid & OBD_MD_FLFLAGS)
- local_flags = lobdo->o_flags & OBD_FL_LOCAL_MASK;
-
- *lobdo = *wobdo;
- if (local_flags != 0) {
- lobdo->o_valid |= OBD_MD_FLFLAGS;
- lobdo->o_flags &= ~OBD_FL_LOCAL_MASK;
- lobdo->o_flags |= local_flags;
- }
- if (!ocd)
- return;
-
- if (unlikely(!(ocd->ocd_connect_flags & OBD_CONNECT_FID)) &&
- fid_seq_is_echo(wobdo->o_oi.oi.oi_seq)) {
- /* see above */
- lobdo->o_oi.oi_fid.f_seq = wobdo->o_oi.oi.oi_seq;
- lobdo->o_oi.oi_fid.f_oid = wobdo->o_oi.oi.oi_id;
- lobdo->o_oi.oi_fid.f_ver = 0;
- }
-}
-
/* request structure for OST's */
struct ost_body {
struct obdo oa;
* \retval buffer
*/
static inline char *hai_dump_data_field(struct hsm_action_item *hai,
- char *buffer, int len)
+ char *buffer, size_t len)
{
- int i, sz, data_len;
+ int i, data_len;
char *ptr;
ptr = buffer;
- sz = len;
data_len = hai->hai_len - sizeof(*hai);
- for (i = 0 ; (i < data_len) && (sz > 0) ; i++) {
- int cnt;
-
- cnt = snprintf(ptr, sz, "%.2X",
- (unsigned char)hai->hai_data[i]);
- ptr += cnt;
- sz -= cnt;
+ for (i = 0; (i < data_len) && (len > 2); i++) {
+ snprintf(ptr, 3, "%02X", (unsigned char)hai->hai_data[i]);
+ ptr += 2;
+ len -= 2;
}
+
*ptr = '\0';
+
return buffer;
}
union ptlrpc_async_args {
/**
* Scratchpad for passing args to completion interpreter. Users
- * cast to the struct of their choosing, and CLASSERT that this is
- * big enough. For _tons_ of context, kmalloc a struct and store
+ * cast to the struct of their choosing, and BUILD_BUG_ON oversized
+ * arguments. For _tons_ of context, kmalloc a struct and store
* a pointer to it here. The pointer_arg ensures this struct is at
* least big enough for that.
*/
* Thread name used in kthread_run()
*/
char pc_name[16];
- /**
- * Environment for request interpreters to run in.
- */
- struct lu_env pc_env;
/**
* CPT the thread is bound on.
*/
--- /dev/null
+/*
+ * GPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see
+ * http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * GPL HEADER END
+ */
+/*
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright (c) 2011, 2014, Intel Corporation.
+ *
+ * Copyright 2015 Cray Inc, all rights reserved.
+ * Author: Ben Evans.
+ *
+ * Define obdo associated functions
+ * obdo: OBject Device o...
+ */
+
+#ifndef _LUSTRE_OBDO_H_
+#define _LUSTRE_OBDO_H_
+
+#include "lustre/lustre_idl.h"
+
+/**
+ * Create an obdo to send over the wire
+ */
+void lustre_set_wire_obdo(const struct obd_connect_data *ocd,
+ struct obdo *wobdo,
+ const struct obdo *lobdo);
+
+/**
+ * Create a local obdo from a wire based odbo
+ */
+void lustre_get_wire_obdo(const struct obd_connect_data *ocd,
+ struct obdo *lobdo,
+ const struct obdo *wobdo);
+
+#endif
#ifndef _LUSTRE_REQ_LAYOUT_H__
#define _LUSTRE_REQ_LAYOUT_H__
+#include <linux/types.h>
+
/** \defgroup req_layout req_layout
*
* @{
__u32 rc_area[RCL_NR][REQ_MAX_FIELD_NR];
};
-#if !defined(__REQ_LAYOUT_USER__)
-
-/* struct ptlrpc_request, lustre_msg* */
-#include "lustre_net.h"
-
void req_capsule_init(struct req_capsule *pill, struct ptlrpc_request *req,
enum req_location location);
void req_capsule_fini(struct req_capsule *pill);
int req_layout_init(void);
void req_layout_fini(void);
-/* __REQ_LAYOUT_USER__ */
-#endif
-
extern struct req_format RQF_OBD_PING;
extern struct req_format RQF_OBD_SET_INFO;
extern struct req_format RQF_SEC_CTX;
#include "lustre_fld.h"
#include "lustre_handles.h"
#include "lustre_intent.h"
+#include "cl_object.h"
#define MAX_OBD_DEVICES 8192
struct lov_stripe_md;
struct obd_info;
+int lov_read_and_clear_async_rc(struct cl_object *clob);
+
typedef int (*obd_enqueue_update_f)(void *cookie, int rc);
/* obd info for a particular level (lov, osc). */
* the transaction has NOT yet committed.
*/
atomic_long_t cl_unstable_count;
+ /** Link to osc_shrinker_list */
+ struct list_head cl_shrink_list;
/* number of in flight destroy rpcs is limited to max_rpcs_in_flight */
atomic_t cl_destroy_in_flight;
unsigned long ltd_active:1; /* target up for requests */
};
-enum placement_policy {
- PLACEMENT_CHAR_POLICY = 0,
- PLACEMENT_NID_POLICY = 1,
- PLACEMENT_INVAL_POLICY = 2,
- PLACEMENT_MAX_POLICY
-};
-
struct lmv_obd {
int refcount;
struct lu_client_fld lmv_fld;
spinlock_t lmv_lock;
- enum placement_policy lmv_placement;
struct lmv_desc desc;
struct obd_uuid cluuid;
struct obd_export *exp;
* Events signalled through obd_notify() upcall-chain.
*/
enum obd_notify_event {
- /* target added */
- OBD_NOTIFY_CREATE,
/* Device connect start */
OBD_NOTIFY_CONNECT,
/* Device activated */
OBD_NOTIFY_ACTIVE,
/* Device deactivated */
OBD_NOTIFY_INACTIVE,
- /* Device disconnected */
- OBD_NOTIFY_DISCON,
/* Connect data for import were changed */
OBD_NOTIFY_OCD,
/* Sync request */
struct lookup_intent mi_it;
struct lustre_handle mi_lockh;
struct inode *mi_dir;
+ struct ldlm_enqueue_info mi_einfo;
int (*mi_cb)(struct ptlrpc_request *req,
struct md_enqueue_info *minfo, int rc);
void *mi_cbdata;
struct md_open_data *och_mod;
struct lustre_handle och_lease_handle; /* open lock for lease */
__u32 och_magic;
- int och_flags;
+ fmode_t och_flags;
};
#define OBD_CLIENT_HANDLE_MAGIC 0xd15ea5ed
struct lu_fid *fid);
int (*intent_getattr_async)(struct obd_export *,
- struct md_enqueue_info *,
- struct ldlm_enqueue_info *);
+ struct md_enqueue_info *);
int (*revalidate_lock)(struct obd_export *, struct lookup_intent *,
struct lu_fid *, __u64 *bits);
}
static inline int md_intent_getattr_async(struct obd_export *exp,
- struct md_enqueue_info *minfo,
- struct ldlm_enqueue_info *einfo)
+ struct md_enqueue_info *minfo)
{
int rc;
EXP_CHECK_MD_OP(exp, intent_getattr_async);
EXP_MD_COUNTER_INCREMENT(exp, intent_getattr_async);
- rc = MDP(exp->exp_obd, intent_getattr_async)(exp, minfo, einfo);
+ rc = MDP(exp->exp_obd, intent_getattr_async)(exp, minfo);
return rc;
}
struct interval_node *found, **root;
struct ldlm_interval *node;
struct ldlm_extent *extent;
- int idx;
+ int idx, rc;
LASSERT(lock->l_granted_mode == lock->l_req_mode);
/* node extent initialize */
extent = &lock->l_policy_data.l_extent;
- interval_set(&node->li_node, extent->start, extent->end);
+ rc = interval_set(&node->li_node, extent->start, extent->end);
+ LASSERT(!rc);
root = &res->lr_itree[idx].lit_root;
found = interval_insert(&node->li_node, root);
void ldlm_extent_policy_wire_to_local(const union ldlm_wire_policy_data *wpolicy,
union ldlm_policy_data *lpolicy)
{
- memset(lpolicy, 0, sizeof(*lpolicy));
lpolicy->l_extent.start = wpolicy->l_extent.start;
lpolicy->l_extent.end = wpolicy->l_extent.end;
lpolicy->l_extent.gid = wpolicy->l_extent.gid;
int added = (mode == LCK_NL);
int overlaps = 0;
int splitted = 0;
- const struct ldlm_callback_suite null_cbs = { NULL };
+ const struct ldlm_callback_suite null_cbs = { };
CDEBUG(D_DLMTRACE,
"flags %#llx owner %llu pid %u mode %u start %llu end %llu\n",
void ldlm_flock_policy_wire_to_local(const union ldlm_wire_policy_data *wpolicy,
union ldlm_policy_data *lpolicy)
{
- memset(lpolicy, 0, sizeof(*lpolicy));
lpolicy->l_flock.start = wpolicy->l_flock.lfw_start;
lpolicy->l_flock.end = wpolicy->l_flock.lfw_end;
lpolicy->l_flock.pid = wpolicy->l_flock.lfw_pid;
void ldlm_ibits_policy_wire_to_local(const union ldlm_wire_policy_data *wpolicy,
union ldlm_policy_data *lpolicy)
{
- memset(lpolicy, 0, sizeof(*lpolicy));
lpolicy->l_inodebits.bits = wpolicy->l_inodebits.bits;
}
INIT_LIST_HEAD(&cli->cl_lru_list);
spin_lock_init(&cli->cl_lru_list_lock);
atomic_long_set(&cli->cl_unstable_count, 0);
+ INIT_LIST_HEAD(&cli->cl_shrink_list);
init_waitqueue_head(&cli->cl_destroy_waitq);
atomic_set(&cli->cl_destroy_in_flight, 0);
cli->cl_supp_cksum_types = OBD_CKSUM_CRC32;
atomic_set(&cli->cl_resends, OSC_DEFAULT_RESENDS);
- /* This value may be reduced at connect time in
- * ptlrpc_connect_interpret() . We initialize it to only
- * 1MB until we know what the performance looks like.
- * In the future this should likely be increased. LU-1431
+ /*
+ * Set it to possible maximum size. It may be reduced by ocd_brw_size
+ * from OFD after connecting.
*/
- cli->cl_max_pages_per_rpc = min_t(int, PTLRPC_MAX_BRW_PAGES,
- LNET_MTU >> PAGE_SHIFT);
+ cli->cl_max_pages_per_rpc = PTLRPC_MAX_BRW_PAGES;
/*
* set cl_chunkbits default value to PAGE_CACHE_SHIFT,
rc = ptlrpc_connect_import(imp);
if (rc != 0) {
+ if (data && is_mdc)
+ data->ocd_connect_flags &= ~OBD_CONNECT_MULTIMODRPCS;
LASSERT(imp->imp_state == LUSTRE_IMP_DISCON);
goto out_ldlm;
}
if (!lock)
return NULL;
+ if (lock->l_export && lock->l_export->exp_failed) {
+ CDEBUG(D_INFO, "lock export failed: lock %p, exp %p\n",
+ lock, lock->l_export);
+ LDLM_LOCK_PUT(lock);
+ return NULL;
+ }
+
/* It's unlikely but possible that someone marked the lock as
* destroyed after we did handle2object on it
*/
if (!data->lmd_unref && LDLM_HAVE_MASK(lock, GONE))
return INTERVAL_ITER_CONT;
- if ((data->lmd_flags & LDLM_FL_LOCAL_ONLY) &&
- !ldlm_is_local(lock))
+ if (!equi(data->lmd_flags & LDLM_FL_LOCAL_ONLY, ldlm_is_local(lock)))
return INTERVAL_ITER_CONT;
if (data->lmd_flags & LDLM_FL_TEST_LOCK) {
return INTERVAL_ITER_STOP;
}
-static unsigned int itree_overlap_cb(struct interval_node *in, void *args)
+static enum interval_iter itree_overlap_cb(struct interval_node *in, void *args)
{
struct ldlm_interval *node = to_ldlm_interval(in);
struct lock_match_data *data = args;
LDLM_DEBUG(lock, "replaying lock:");
atomic_inc(&req->rq_import->imp_replay_inflight);
- CLASSERT(sizeof(*aa) <= sizeof(req->rq_async_args));
+ BUILD_BUG_ON(sizeof(*aa) > sizeof(req->rq_async_args));
aa = ptlrpc_req_async_args(req);
aa->lock_handle = body->lock_handle[0];
req->rq_interpret_reply = (ptlrpc_interpterer_t)replay_lock_interpret;
struct ldlm_lock *lock;
unsigned int granted = 0;
- CLASSERT(RES_NAME_SIZE == 4);
+ BUILD_BUG_ON(RES_NAME_SIZE != 4);
if (!((libcfs_debug | D_ERROR) & level))
return;
return 1;
/*
- * if open&create is set, talk to MDS to make sure file is created if
- * necessary, because we can't do this in ->open() later since that's
- * called on an inode. return 0 here to let lookup to handle this.
+ * VFS warns us that this is the second go around and previous
+ * operation failed (most likely open|creat), so this time
+ * we better talk to the server via the lookup path by name,
+ * not by fid.
*/
- if ((lookup_flags & (LOOKUP_OPEN | LOOKUP_CREATE)) ==
- (LOOKUP_OPEN | LOOKUP_CREATE))
+ if (lookup_flags & LOOKUP_REVAL)
return 0;
- if (lookup_flags & (LOOKUP_PARENT | LOOKUP_OPEN | LOOKUP_CREATE))
- return 1;
-
if (!dentry_may_statahead(dir, dentry))
return 1;
if (!IS_POSIXACL(parent) || !exp_connect_umask(ll_i2mdexp(parent)))
mode &= ~current_umask();
- mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR;
+ mode = (mode & (0777 | S_ISVTX)) | S_IFDIR;
op_data = ll_prep_md_op_data(NULL, parent, NULL, dirname,
strlen(dirname), mode, LUSTRE_OPC_MKDIR,
lump);
rc = md_setattr(sbi->ll_md_exp, op_data, lump, lum_size, &req);
ll_finish_md_op_data(op_data);
ptlrpc_req_finished(req);
- if (rc) {
- if (rc != -EPERM && rc != -EACCES)
- CERROR("mdc_setattr fails: rc = %d\n", rc);
- }
+ if (rc)
+ return rc;
- /* In the following we use the fact that LOV_USER_MAGIC_V1 and
+#if OBD_OCD_VERSION(2, 13, 53, 0) > LUSTRE_VERSION_CODE
+ /*
+ * 2.9 server has stored filesystem default stripe in ROOT xattr,
+ * and it's stored into system config for backward compatibility.
+ *
+ * In the following we use the fact that LOV_USER_MAGIC_V1 and
* LOV_USER_MAGIC_V3 have the same initial fields so we do not
* need to make the distinction between the 2 versions
*/
end:
kfree(param);
}
+#endif
return rc;
}
enum mds_op_bias bias,
void *data)
{
- struct obd_export *exp = ll_i2mdexp(inode);
+ const struct ll_inode_info *lli = ll_i2info(inode);
struct md_op_data *op_data;
struct ptlrpc_request *req = NULL;
- struct obd_device *obd = class_exp2obd(exp);
int rc;
- if (!obd) {
- /*
- * XXX: in case of LMV, is this correct to access
- * ->exp_handle?
- */
- CERROR("Invalid MDC connection handle %#llx\n",
- ll_i2mdexp(inode)->exp_handle.h_cookie);
+ if (!class_exp2obd(md_exp)) {
+ CERROR("%s: invalid MDC connection handle closing " DFID "\n",
+ ll_get_fsname(inode->i_sb, NULL, 0),
+ PFID(&lli->lli_fid));
rc = 0;
goto out;
}
op_data = kzalloc(sizeof(*op_data), GFP_NOFS);
+ /*
+ * We leak openhandle and request here on error, but not much to be
+ * done in OOM case since app won't retry close on error either.
+ */
if (!op_data) {
- /* XXX We leak openhandle and request here. */
rc = -ENOMEM;
goto out;
}
}
rc = md_close(md_exp, op_data, och->och_mod, &req);
- if (rc) {
- CERROR("%s: inode "DFID" mdc close failed: rc = %d\n",
- ll_i2mdexp(inode)->exp_obd->obd_name,
- PFID(ll_inode2fid(inode)), rc);
+ if (rc && rc != -EINTR) {
+ CERROR("%s: inode " DFID " mdc close failed: rc = %d\n",
+ md_exp->exp_obd->obd_name, PFID(&lli->lli_fid), rc);
}
if (op_data->op_bias & (MDS_HSM_RELEASE | MDS_CLOSE_LAYOUT_SWAP) &&
och->och_fh.cookie = DEAD_HANDLE_MAGIC;
kfree(och);
- if (req) /* This is close request */
- ptlrpc_req_finished(req);
+ ptlrpc_req_finished(req);
return rc;
}
ptlrpc_req_finished(req);
ll_intent_drop_lock(itp);
+ /*
+ * We did open by fid, but by the time we got to the server,
+ * the object disappeared. If this is a create, we cannot really
+ * tell the userspace that the file it was trying to create
+ * does not exist. Instead let's return -ESTALE, and the VFS will
+ * retry the create with LOOKUP_REVAL that we are going to catch
+ * in ll_revalidate_dentry() and use lookup then.
+ */
+ if (rc == -ENOENT && itp->it_op & IT_CREAT)
+ rc = -ESTALE;
+
return rc;
}
return false;
}
-void ll_io_init(struct cl_io *io, const struct file *file, int write)
+static void ll_io_init(struct cl_io *io, const struct file *file, int write)
{
struct inode *inode = file_inode(file);
return rc;
}
-static int ll_hsm_state_set(struct inode *inode, struct hsm_state_set *hss)
+int ll_hsm_state_set(struct inode *inode, struct hsm_state_set *hss)
{
struct md_op_data *op_data;
int rc;
goto free_hss;
}
- attr->ia_mode = hui->hui_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
+ attr->ia_mode = hui->hui_mode & 0777;
attr->ia_mode |= S_IFREG;
attr->ia_uid = make_kuid(&init_user_ns, hui->hui_uid);
attr->ia_gid = make_kgid(&init_user_ns, hui->hui_gid);
io = vvp_env_thread_io(env);
io->ci_obj = obj;
+ io->ci_verify_layout = 1;
io->u.ci_setattr.sa_attr.lvb_atime = LTIME_S(attr->ia_atime);
io->u.ci_setattr.sa_attr.lvb_mtime = LTIME_S(attr->ia_mtime);
cl_io_fini(env, io);
if (unlikely(io->ci_need_restart))
goto again;
- /* HSM import case: file is released, cannot be restored
- * no need to fail except if restore registration failed
- * with -ENODATA
- */
- if (result == -ENODATA && io->ci_restore_needed &&
- io->ci_result != -ENODATA)
- result = 0;
+
cl_env_put(env, &refcheck);
return result;
}
* future).
*
*/
+#define DEBUG_SUBSYSTEM S_LLITE
#include "../include/obd_class.h"
#include "../include/obd_support.h"
#include "../include/obd.h"
io = vvp_env_thread_io(env);
io->ci_obj = obj;
- io->ci_ignore_layout = 1;
rc = cl_io_init(env, io, CIT_MISC, io->ci_obj);
if (rc != 0) {
return container_of(inode, struct ll_inode_info, lli_vfs_inode);
}
-/* default to about 40meg of readahead on a given system. That much tied
- * up in 512k readahead requests serviced at 40ms each is about 1GB/s.
- */
-#define SBI_DEFAULT_READAHEAD_MAX (40UL << (20 - PAGE_SHIFT))
+/* default to about 64M of readahead on a given system. */
+#define SBI_DEFAULT_READAHEAD_MAX (64UL << (20 - PAGE_SHIFT))
/* default to read-ahead full files smaller than 2MB on the second read */
#define SBI_DEFAULT_READAHEAD_WHOLE_MAX (2UL << (20 - PAGE_SHIFT))
struct ra_io_arg {
unsigned long ria_start; /* start offset of read-ahead*/
unsigned long ria_end; /* end offset of read-ahead*/
+ unsigned long ria_reserved; /* reserved pages for read-ahead */
+ unsigned long ria_end_min; /* minimum end to cover current read */
+ bool ria_eof; /* reach end of file */
/* If stride read pattern is detected, ria_stoff means where
* stride read is started. Note: for normal read-ahead, the
* value here is meaningless, and also it will not be accessed
*/
/* root squash */
struct root_squash_info ll_squash;
+ struct path ll_mnt;
__kernel_fsid_t ll_fsid;
struct kobject ll_kobj; /* sysfs object */
* PTLRPC_MAX_BRW_PAGES chunks up to ->ra_max_pages.
*/
unsigned long ras_window_start, ras_window_len;
+ /*
+ * Optimal RPC size. It decides how many pages will be sent
+ * for each read-ahead.
+ */
+ unsigned long ras_rpc_size;
/*
* Where next read-ahead should start at. This lies within read-ahead
* window. Read-ahead window is read in pieces rather than at once
int ll_fid2path(struct inode *inode, void __user *arg);
int ll_data_version(struct inode *inode, __u64 *data_version, int flags);
int ll_hsm_release(struct inode *inode);
+int ll_hsm_state_set(struct inode *inode, struct hsm_state_set *hss);
/* llite/dcache.c */
sbi->ll_flags |= LL_SBI_CHECKSUM;
sbi->ll_flags |= LL_SBI_LRU_RESIZE;
+ sbi->ll_flags |= LL_SBI_LAZYSTATFS;
for (i = 0; i <= LL_PROCESS_HIST_MAX; i++) {
spin_lock_init(&sbi->ll_rw_extents_info.pp_extents[i].
sb->s_magic = LL_SUPER_MAGIC;
sb->s_maxbytes = MAX_LFS_FILESIZE;
sbi->ll_namelen = osfs->os_namelen;
+ sbi->ll_mnt.mnt = current->fs->root.mnt;
if ((sbi->ll_flags & LL_SBI_USER_XATTR) &&
!(data->ocd_connect_flags & OBD_CONNECT_XATTR)) {
* cache is not cleared yet.
*/
op_data->op_attr.ia_valid &= ~(TIMES_SET_FLAGS | ATTR_SIZE);
+ if (S_ISREG(inode->i_mode))
+ inode_lock(inode);
rc = simple_setattr(dentry, &op_data->op_attr);
+ if (S_ISREG(inode->i_mode))
+ inode_unlock(inode);
op_data->op_attr.ia_valid = ia_valid;
rc = ll_update_inode(inode, &md);
struct inode *inode = d_inode(dentry);
struct ll_inode_info *lli = ll_i2info(inode);
struct md_op_data *op_data = NULL;
- bool file_is_released = false;
int rc = 0;
CDEBUG(D_VFSTRACE, "%s: setattr inode "DFID"(%p) from %llu to %llu, valid %x, hsm_import %d\n",
LTIME_S(attr->ia_mtime), LTIME_S(attr->ia_ctime),
(s64)ktime_get_real_seconds());
- /* We always do an MDS RPC, even if we're only changing the size;
- * only the MDS knows whether truncate() should fail with -ETXTBUSY
- */
-
- op_data = kzalloc(sizeof(*op_data), GFP_NOFS);
- if (!op_data)
- return -ENOMEM;
-
- if (!S_ISDIR(inode->i_mode))
+ if (S_ISREG(inode->i_mode))
inode_unlock(inode);
- /* truncate on a released file must failed with -ENODATA,
- * so size must not be set on MDS for released file
- * but other attributes must be set
+ /*
+ * We always do an MDS RPC, even if we're only changing the size;
+ * only the MDS knows whether truncate() should fail with -ETXTBUSY
*/
- if (S_ISREG(inode->i_mode)) {
- struct cl_layout cl = {
- .cl_is_released = false,
- };
- struct lu_env *env;
- int refcheck;
- __u32 gen;
+ op_data = kzalloc(sizeof(*op_data), GFP_NOFS);
+ if (!op_data) {
+ rc = -ENOMEM;
+ goto out;
+ }
- rc = ll_layout_refresh(inode, &gen);
- if (rc < 0)
- goto out;
+ op_data->op_attr = *attr;
+ if (!hsm_import && attr->ia_valid & ATTR_SIZE) {
/*
- * XXX: the only place we need to know the layout type,
- * this will be removed by a later patch. -Jinshan
+ * If we are changing file size, file content is
+ * modified, flag it.
*/
- env = cl_env_get(&refcheck);
- if (IS_ERR(env)) {
- rc = PTR_ERR(env);
- goto out;
- }
-
- rc = cl_object_layout_get(env, lli->lli_clob, &cl);
- cl_env_put(env, &refcheck);
- if (rc < 0)
- goto out;
-
- file_is_released = cl.cl_is_released;
-
- if (!hsm_import && attr->ia_valid & ATTR_SIZE) {
- if (file_is_released) {
- rc = ll_layout_restore(inode, 0, attr->ia_size);
- if (rc < 0)
- goto out;
-
- file_is_released = false;
- ll_layout_refresh(inode, &gen);
- }
-
- /*
- * If we are changing file size, file content is
- * modified, flag it.
- */
- attr->ia_valid |= MDS_OPEN_OWNEROVERRIDE;
- op_data->op_bias |= MDS_DATA_MODIFIED;
- }
+ attr->ia_valid |= MDS_OPEN_OWNEROVERRIDE;
+ op_data->op_bias |= MDS_DATA_MODIFIED;
}
- memcpy(&op_data->op_attr, attr, sizeof(*attr));
-
rc = ll_md_setattr(dentry, op_data);
if (rc)
goto out;
- if (!S_ISREG(inode->i_mode) || file_is_released) {
+ if (!S_ISREG(inode->i_mode) || hsm_import) {
rc = 0;
goto out;
}
*/
rc = cl_setattr_ost(ll_i2info(inode)->lli_clob, attr, 0);
}
+
+ /*
+ * If the file was restored, it needs to set dirty flag.
+ *
+ * We've already sent MDS_DATA_MODIFIED flag in
+ * ll_md_setattr() for truncate. However, the MDT refuses to
+ * set the HS_DIRTY flag on released files, so we have to set
+ * it again if the file has been restored. Please check how
+ * LLIF_DATA_MODIFIED is set in vvp_io_setattr_fini().
+ *
+ * Please notice that if the file is not released, the previous
+ * MDS_DATA_MODIFIED has taken effect and usually
+ * LLIF_DATA_MODIFIED is not set(see vvp_io_setattr_fini()).
+ * This way we can save an RPC for common open + trunc
+ * operation.
+ */
+ if (test_and_clear_bit(LLIF_DATA_MODIFIED, &lli->lli_flags)) {
+ struct hsm_state_set hss = {
+ .hss_valid = HSS_SETMASK,
+ .hss_setmask = HS_DIRTY,
+ };
+ int rc2;
+
+ rc2 = ll_hsm_state_set(inode, &hss);
+ if (rc2 < 0)
+ CERROR(DFID "HSM set dirty failed: rc2 = %d\n",
+ PFID(ll_inode2fid(inode)), rc2);
+ }
+
out:
if (op_data)
ll_finish_md_op_data(op_data);
- if (!S_ISDIR(inode->i_mode)) {
+ if (S_ISREG(inode->i_mode)) {
inode_lock(inode);
if ((attr->ia_valid & ATTR_SIZE) && !hsm_import)
inode_dio_wait(inode);
if (((attr->ia_valid & (ATTR_MODE | ATTR_FORCE | ATTR_SIZE)) ==
(ATTR_SIZE | ATTR_MODE)) &&
(((mode & S_ISUID) && !(attr->ia_mode & S_ISUID)) ||
- (((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) &&
+ (((mode & (S_ISGID | 0010)) == (S_ISGID | 0010)) &&
!(attr->ia_mode & S_ISGID))))
attr->ia_valid |= ATTR_FORCE;
attr->ia_valid |= ATTR_KILL_SUID;
if ((attr->ia_valid & ATTR_MODE) &&
- ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) &&
+ ((mode & (S_ISGID | 0010)) == (S_ISGID | 0010)) &&
!(attr->ia_mode & S_ISGID) &&
!(attr->ia_valid & ATTR_KILL_SGID))
attr->ia_valid |= ATTR_KILL_SGID;
struct ll_sb_info *sbi = ll_s2sbi(sb);
struct obd_device *obd;
struct obd_ioctl_data *ioc_data;
+ wait_queue_head_t waitq;
+ struct l_wait_info lwi;
CDEBUG(D_VFSTRACE, "VFS Op: superblock %p count %d active %d\n", sb,
sb->s_count, atomic_read(&sb->s_active));
}
/* Really, we'd like to wait until there are no requests outstanding,
- * and then continue. For now, we just invalidate the requests,
- * schedule() and sleep one second if needed, and hope.
+ * and then continue. For now, we just periodically checking for vfs
+ * to decrement mnt_cnt and hope to finish it within 10sec.
*/
+ init_waitqueue_head(&waitq);
+ lwi = LWI_TIMEOUT_INTERVAL(cfs_time_seconds(10),
+ cfs_time_seconds(1), NULL, NULL);
+ l_wait_event(waitq, may_umount(sbi->ll_mnt.mnt), &lwi);
+
schedule();
}
}
LPROC_SEQ_FOPS(ll_unstable_stats);
-static ssize_t root_squash_show(struct kobject *kobj, struct attribute *attr,
- char *buf)
+static int ll_root_squash_seq_show(struct seq_file *m, void *v)
{
- struct ll_sb_info *sbi = container_of(kobj, struct ll_sb_info,
- ll_kobj);
+ struct super_block *sb = m->private;
+ struct ll_sb_info *sbi = ll_s2sbi(sb);
struct root_squash_info *squash = &sbi->ll_squash;
- return sprintf(buf, "%u:%u\n", squash->rsi_uid, squash->rsi_gid);
+ seq_printf(m, "%u:%u\n", squash->rsi_uid, squash->rsi_gid);
+ return 0;
}
-static ssize_t root_squash_store(struct kobject *kobj, struct attribute *attr,
- const char *buffer, size_t count)
+static ssize_t ll_root_squash_seq_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *off)
{
- struct ll_sb_info *sbi = container_of(kobj, struct ll_sb_info,
- ll_kobj);
+ struct seq_file *m = file->private_data;
+ struct super_block *sb = m->private;
+ struct ll_sb_info *sbi = ll_s2sbi(sb);
struct root_squash_info *squash = &sbi->ll_squash;
return lprocfs_wr_root_squash(buffer, count, squash,
- ll_get_fsname(sbi->ll_sb, NULL, 0));
+ ll_get_fsname(sb, NULL, 0));
}
-LUSTRE_RW_ATTR(root_squash);
+LPROC_SEQ_FOPS(ll_root_squash);
static int ll_nosquash_nids_seq_show(struct seq_file *m, void *v)
{
{ "statahead_stats", &ll_statahead_stats_fops, NULL, 0 },
{ "unstable_stats", &ll_unstable_stats_fops, NULL },
{ "sbi_flags", &ll_sbi_flags_fops, NULL, 0 },
+ { .name = "root_squash",
+ .fops = &ll_root_squash_fops },
{ .name = "nosquash_nids",
.fops = &ll_nosquash_nids_fops },
{ NULL }
&lustre_attr_max_easize.attr,
&lustre_attr_default_easize.attr,
&lustre_attr_xattr_cache.attr,
- &lustre_attr_root_squash.attr,
NULL,
};
return rc;
}
-/* ll_unlink() doesn't update the inode with the new link count.
- * Instead, ll_ddelete() and ll_d_iput() will update it based upon if there
- * is any lock existing. They will recycle dentries and inodes based upon locks
- * too. b=20433
- */
static int ll_unlink(struct inode *dir, struct dentry *dchild)
{
struct ptlrpc_request *request = NULL;
if (!IS_POSIXACL(dir) || !exp_connect_umask(ll_i2mdexp(dir)))
mode &= ~current_umask();
- mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR;
+ mode = (mode & (0777 | S_ISVTX)) | S_IFDIR;
err = ll_new_node(dir, dentry, NULL, mode, 0, LUSTRE_OPC_MKDIR);
if (!err)
CDEBUG(D_VFSTRACE, "VFS Op:name=%pd, dir="DFID"(%p),target=%.*s\n",
dentry, PFID(ll_inode2fid(dir)), dir, 3000, oldname);
- err = ll_new_node(dir, dentry, oldname, S_IFLNK | S_IRWXUGO,
+ err = ll_new_node(dir, dentry, oldname, S_IFLNK | 0777,
0, LUSTRE_OPC_SYMLINK);
if (!err)
* Pre: Caller should have allocated the range lock node.
* Post: The range lock node is meant to cover [start, end] region
*/
-void range_lock_init(struct range_lock *lock, __u64 start, __u64 end)
+int range_lock_init(struct range_lock *lock, __u64 start, __u64 end)
{
+ int rc;
+
memset(&lock->rl_node, 0, sizeof(lock->rl_node));
if (end != LUSTRE_EOF)
end >>= PAGE_SHIFT;
- interval_set(&lock->rl_node, start >> PAGE_SHIFT, end);
+ rc = interval_set(&lock->rl_node, start >> PAGE_SHIFT, end);
+ if (rc)
+ return rc;
+
INIT_LIST_HEAD(&lock->rl_next_lock);
lock->rl_task = NULL;
lock->rl_lock_count = 0;
lock->rl_blocking_ranges = 0;
lock->rl_sequence = 0;
+ return rc;
}
static inline struct range_lock *next_lock(struct range_lock *lock)
};
void range_lock_tree_init(struct range_lock_tree *tree);
-void range_lock_init(struct range_lock *lock, __u64 start, __u64 end);
+int range_lock_init(struct range_lock *lock, __u64 start, __u64 end);
int range_lock(struct range_lock_tree *tree, struct range_lock *lock);
void range_unlock(struct range_lock_tree *tree, struct range_lock *lock);
#endif
goto out;
}
- /* If the non-strided (ria_pages == 0) readahead window
- * (ria_start + ret) has grown across an RPC boundary, then trim
- * readahead size by the amount beyond the RPC so it ends on an
- * RPC boundary. If the readahead window is already ending on
- * an RPC boundary (beyond_rpc == 0), or smaller than a full
- * RPC (beyond_rpc < ret) the readahead size is unchanged.
- * The (beyond_rpc != 0) check is skipped since the conditional
- * branch is more expensive than subtracting zero from the result.
- *
- * Strided read is left unaligned to avoid small fragments beyond
- * the RPC boundary from needing an extra read RPC.
- */
- if (ria->ria_pages == 0) {
- long beyond_rpc = (ria->ria_start + ret) % PTLRPC_MAX_BRW_PAGES;
-
- if (/* beyond_rpc != 0 && */ beyond_rpc < ret)
- ret -= beyond_rpc;
- }
-
if (atomic_add_return(ret, &ra->ra_cur_pages) > ra->ra_max_pages) {
atomic_sub(ret, &ra->ra_cur_pages);
ret = 0;
#define RAS_CDEBUG(ras) \
CDEBUG(D_READA, \
- "lrp %lu cr %lu cp %lu ws %lu wl %lu nra %lu r %lu ri %lu" \
- "csr %lu sf %lu sp %lu sl %lu\n", \
+ "lrp %lu cr %lu cp %lu ws %lu wl %lu nra %lu rpc %lu " \
+ "r %lu ri %lu csr %lu sf %lu sp %lu sl %lu\n", \
ras->ras_last_readpage, ras->ras_consecutive_requests, \
ras->ras_consecutive_pages, ras->ras_window_start, \
ras->ras_window_len, ras->ras_next_readahead, \
+ ras->ras_rpc_size, \
ras->ras_requests, ras->ras_request_index, \
ras->ras_consecutive_stride_requests, ras->ras_stride_offset, \
ras->ras_stride_pages, ras->ras_stride_length)
ria->ria_start, ria->ria_end, ria->ria_stoff, ria->ria_length,\
ria->ria_pages)
-/* Limit this to the blocksize instead of PTLRPC_BRW_MAX_SIZE, since we don't
- * know what the actual RPC size is. If this needs to change, it makes more
- * sense to tune the i_blkbits value for the file based on the OSTs it is
- * striped over, rather than having a constant value for all files here.
- */
-
-/* RAS_INCREASE_STEP should be (1UL << (inode->i_blkbits - PAGE_SHIFT)).
- * Temporarily set RAS_INCREASE_STEP to 1MB. After 4MB RPC is enabled
- * by default, this should be adjusted corresponding with max_read_ahead_mb
- * and max_read_ahead_per_file_mb otherwise the readahead budget can be used
- * up quickly which will affect read performance significantly. See LU-2816
- */
-#define RAS_INCREASE_STEP(inode) (ONE_MB_BRW_SIZE >> PAGE_SHIFT)
-
static inline int stride_io_mode(struct ll_readahead_state *ras)
{
return ras->ras_consecutive_stride_requests > 1;
length);
}
+static unsigned long ras_align(struct ll_readahead_state *ras,
+ unsigned long index,
+ unsigned long *remainder)
+{
+ unsigned long rem = index % ras->ras_rpc_size;
+
+ if (remainder)
+ *remainder = rem;
+ return index - rem;
+}
+
/*Check whether the index is in the defined ra-window */
static int ras_inside_ra_window(unsigned long idx, struct ra_io_arg *ria)
{
ria->ria_length < ria->ria_pages);
}
-static int ll_read_ahead_pages(const struct lu_env *env,
- struct cl_io *io, struct cl_page_list *queue,
- struct ra_io_arg *ria,
- unsigned long *reserved_pages,
- pgoff_t *ra_end)
+static unsigned long
+ll_read_ahead_pages(const struct lu_env *env, struct cl_io *io,
+ struct cl_page_list *queue, struct ll_readahead_state *ras,
+ struct ra_io_arg *ria)
{
struct cl_read_ahead ra = { 0 };
- int rc, count = 0;
+ unsigned long ra_end = 0;
bool stride_ria;
pgoff_t page_idx;
+ int rc;
LASSERT(ria);
RIA_DEBUG(ria);
stride_ria = ria->ria_length > ria->ria_pages && ria->ria_pages > 0;
for (page_idx = ria->ria_start;
- page_idx <= ria->ria_end && *reserved_pages > 0; page_idx++) {
+ page_idx <= ria->ria_end && ria->ria_reserved > 0; page_idx++) {
if (ras_inside_ra_window(page_idx, ria)) {
if (!ra.cra_end || ra.cra_end < page_idx) {
+ unsigned long end;
+
cl_read_ahead_release(env, &ra);
rc = cl_io_read_ahead(env, io, page_idx, &ra);
if (rc < 0)
break;
+ CDEBUG(D_READA, "idx: %lu, ra: %lu, rpc: %lu\n",
+ page_idx, ra.cra_end, ra.cra_rpc_size);
LASSERTF(ra.cra_end >= page_idx,
"object: %p, indcies %lu / %lu\n",
io->ci_obj, ra.cra_end, page_idx);
+ /*
+ * update read ahead RPC size.
+ * NB: it's racy but doesn't matter
+ */
+ if (ras->ras_rpc_size > ra.cra_rpc_size &&
+ ra.cra_rpc_size > 0)
+ ras->ras_rpc_size = ra.cra_rpc_size;
+ /* trim it to align with optimal RPC size */
+ end = ras_align(ras, ria->ria_end + 1, NULL);
+ if (end > 0 && !ria->ria_eof)
+ ria->ria_end = end - 1;
+ if (ria->ria_end < ria->ria_end_min)
+ ria->ria_end = ria->ria_end_min;
+ if (ria->ria_end > ra.cra_end)
+ ria->ria_end = ra.cra_end;
}
- /* If the page is inside the read-ahead window*/
+ /* If the page is inside the read-ahead window */
rc = ll_read_ahead_page(env, io, queue, page_idx);
- if (!rc) {
- (*reserved_pages)--;
- count++;
- }
+ if (rc < 0)
+ break;
+
+ ra_end = page_idx;
+ if (!rc)
+ ria->ria_reserved--;
} else if (stride_ria) {
/* If it is not in the read-ahead window, and it is
* read-ahead mode, then check whether it should skip
}
cl_read_ahead_release(env, &ra);
- *ra_end = page_idx;
- return count;
+ return ra_end;
}
static int ll_readahead(const struct lu_env *env, struct cl_io *io,
struct vvp_io *vio = vvp_env_io(env);
struct ll_thread_info *lti = ll_env_info(env);
struct cl_attr *attr = vvp_env_thread_attr(env);
- unsigned long len, mlen = 0, reserved;
+ unsigned long len, mlen = 0;
pgoff_t ra_end, start = 0, end = 0;
struct inode *inode;
struct ra_io_arg *ria = <i->lti_ria;
end < vio->vui_ra_start + vio->vui_ra_count - 1)
end = vio->vui_ra_start + vio->vui_ra_count - 1;
- if (end != 0) {
- unsigned long rpc_boundary;
- /*
- * Align RA window to an optimal boundary.
- *
- * XXX This would be better to align to cl_max_pages_per_rpc
- * instead of PTLRPC_MAX_BRW_PAGES, because the RPC size may
- * be aligned to the RAID stripe size in the future and that
- * is more important than the RPC size.
- */
- /* Note: we only trim the RPC, instead of extending the RPC
- * to the boundary, so to avoid reading too much pages during
- * random reading.
- */
- rpc_boundary = (end + 1) & (~(PTLRPC_MAX_BRW_PAGES - 1));
- if (rpc_boundary > 0)
- rpc_boundary--;
-
- if (rpc_boundary > start)
- end = rpc_boundary;
+ if (end) {
+ unsigned long end_index;
/* Truncate RA window to end of file */
- end = min(end, (unsigned long)((kms - 1) >> PAGE_SHIFT));
+ end_index = (unsigned long)((kms - 1) >> PAGE_SHIFT);
+ if (end_index <= end) {
+ end = end_index;
+ ria->ria_eof = true;
+ }
ras->ras_next_readahead = max(end, end + 1);
RAS_CDEBUG(ras);
/* at least to extend the readahead window to cover current read */
if (!hit && vio->vui_ra_valid &&
vio->vui_ra_start + vio->vui_ra_count > ria->ria_start) {
+ unsigned long remainder;
+
/* to the end of current read window. */
mlen = vio->vui_ra_start + vio->vui_ra_count - ria->ria_start;
/* trim to RPC boundary */
- start = ria->ria_start & (PTLRPC_MAX_BRW_PAGES - 1);
- mlen = min(mlen, PTLRPC_MAX_BRW_PAGES - start);
+ ras_align(ras, ria->ria_start, &remainder);
+ mlen = min(mlen, ras->ras_rpc_size - remainder);
+ ria->ria_end_min = ria->ria_start + mlen;
}
- reserved = ll_ra_count_get(ll_i2sbi(inode), ria, len, mlen);
- if (reserved < len)
+ ria->ria_reserved = ll_ra_count_get(ll_i2sbi(inode), ria, len, mlen);
+ if (ria->ria_reserved < len)
ll_ra_stats_inc(inode, RA_STAT_MAX_IN_FLIGHT);
CDEBUG(D_READA, "reserved pages %lu/%lu/%lu, ra_cur %d, ra_max %lu\n",
- reserved, len, mlen,
+ ria->ria_reserved, len, mlen,
atomic_read(&ll_i2sbi(inode)->ll_ra_info.ra_cur_pages),
ll_i2sbi(inode)->ll_ra_info.ra_max_pages);
- ret = ll_read_ahead_pages(env, io, queue, ria, &reserved, &ra_end);
+ ra_end = ll_read_ahead_pages(env, io, queue, ras, ria);
- if (reserved != 0)
- ll_ra_count_put(ll_i2sbi(inode), reserved);
+ if (ria->ria_reserved)
+ ll_ra_count_put(ll_i2sbi(inode), ria->ria_reserved);
- if (ra_end == end + 1 && ra_end == (kms >> PAGE_SHIFT))
+ if (ra_end == end && ra_end == (kms >> PAGE_SHIFT))
ll_ra_stats_inc(inode, RA_STAT_EOF);
/* if we didn't get to the end of the region we reserved from
CDEBUG(D_READA, "ra_end = %lu end = %lu stride end = %lu pages = %d\n",
ra_end, end, ria->ria_end, ret);
- if (ra_end != end + 1) {
+ if (ra_end > 0 && ra_end != end) {
ll_ra_stats_inc(inode, RA_STAT_FAILED_REACH_END);
spin_lock(&ras->ras_lock);
- if (ra_end < ras->ras_next_readahead &&
+ if (ra_end <= ras->ras_next_readahead &&
index_in_window(ra_end, ras->ras_window_start, 0,
ras->ras_window_len)) {
- ras->ras_next_readahead = ra_end;
+ ras->ras_next_readahead = ra_end + 1;
RAS_CDEBUG(ras);
}
spin_unlock(&ras->ras_lock);
static void ras_set_start(struct inode *inode, struct ll_readahead_state *ras,
unsigned long index)
{
- ras->ras_window_start = index & (~(RAS_INCREASE_STEP(inode) - 1));
+ ras->ras_window_start = ras_align(ras, index, NULL);
}
/* called with the ras_lock held or from places where it doesn't matter */
void ll_readahead_init(struct inode *inode, struct ll_readahead_state *ras)
{
spin_lock_init(&ras->ras_lock);
+ ras->ras_rpc_size = PTLRPC_MAX_BRW_PAGES;
ras_reset(inode, ras, 0);
ras->ras_requests = 0;
}
* but current clio architecture does not support retrieve such
* information from lower layer. FIXME later
*/
- if (stride_io_mode(ras))
- ras_stride_increase_window(ras, ra, RAS_INCREASE_STEP(inode));
- else
- ras->ras_window_len = min(ras->ras_window_len +
- RAS_INCREASE_STEP(inode),
- ra->ra_max_pages_per_file);
+ if (stride_io_mode(ras)) {
+ ras_stride_increase_window(ras, ra, ras->ras_rpc_size);
+ } else {
+ unsigned long wlen;
+
+ wlen = min(ras->ras_window_len + ras->ras_rpc_size,
+ ra->ra_max_pages_per_file);
+ ras->ras_window_len = ras_align(ras, wlen, NULL);
+ }
}
static void ras_update(struct ll_sb_info *sbi, struct inode *inode,
spin_lock(&ras->ras_lock);
+ if (!hit)
+ CDEBUG(D_READA, DFID " pages at %lu miss.\n",
+ PFID(ll_inode2fid(inode)), index);
+
ll_ra_stats_inc_sbi(sbi, hit ? RA_STAT_HIT : RA_STAT_MISS);
/* reset the read-ahead window in two cases. First when the app seeks
* instead of ras_window_start, which is RPC aligned
*/
ras->ras_next_readahead = max(index, ras->ras_next_readahead);
+ ras->ras_window_start = max(ras->ras_stride_offset,
+ ras->ras_window_start);
} else {
if (ras->ras_next_readahead < ras->ras_window_start)
ras->ras_next_readahead = ras->ras_window_start;
*/
ras->ras_next_readahead = max(index, ras->ras_next_readahead);
ras->ras_stride_offset = index;
- ras->ras_window_len = RAS_INCREASE_STEP(inode);
+ ras->ras_window_start = max(index, ras->ras_window_start);
}
/* The initial ras_window_len is set to the request size. To avoid
struct cl_2queue *queue = &io->ci_queue;
struct ll_sb_info *sbi = ll_i2sbi(inode);
struct vvp_page *vpg;
+ bool uptodate;
int rc = 0;
vpg = cl2vvp_page(cl_object_page_slice(page->cp_obj, page));
+ uptodate = vpg->vpg_defer_uptodate;
+
if (sbi->ll_ra_info.ra_max_pages_per_file > 0 &&
sbi->ll_ra_info.ra_max_pages > 0) {
struct vvp_io *vio = vvp_env_io(env);
enum ras_update_flags flags = 0;
- if (vpg->vpg_defer_uptodate)
+ if (uptodate)
flags |= LL_RAS_HIT;
if (!vio->vui_ra_valid)
flags |= LL_RAS_MMAP;
ras_update(sbi, inode, ras, vvp_index(vpg), flags);
}
- if (vpg->vpg_defer_uptodate) {
+ cl_2queue_init(queue);
+ if (uptodate) {
vpg->vpg_ra_used = 1;
cl_page_export(env, page, 1);
+ cl_page_disown(env, io, page);
+ } else {
+ cl_page_list_add(&queue->c2_qin, page);
}
- cl_2queue_init(queue);
- /*
- * Add page into the queue even when it is marked uptodate above.
- * this will unlock it automatically as part of cl_page_list_disown().
- */
- cl_page_list_add(&queue->c2_qin, page);
if (sbi->ll_ra_info.ra_max_pages_per_file > 0 &&
sbi->ll_ra_info.ra_max_pages > 0) {
int rc2;
rc2 = ll_readahead(env, io, &queue->c2_qin, ras,
- vpg->vpg_defer_uptodate);
+ uptodate);
CDEBUG(D_READA, DFID "%d pages read ahead at %lu\n",
PFID(ll_inode2fid(inode)), rc2, vvp_index(vpg));
}
ssize_t tot_bytes = 0, result = 0;
long size = MAX_DIO_SIZE;
+ /* Check EOF by ourselves */
+ if (iov_iter_rw(iter) == READ && file_offset >= i_size_read(inode))
+ return 0;
+
/* FIXME: io smaller than PAGE_SIZE is broken on ia64 ??? */
if ((file_offset & ~PAGE_MASK) || (count & ~PAGE_MASK))
return -EINVAL;
struct inode *se_inode;
/* entry name */
struct qstr se_qstr;
+ /* entry fid */
+ struct lu_fid se_fid;
};
static unsigned int sai_generation;
/* allocate sa_entry and hash it to allow scanner process to find it */
static struct sa_entry *
sa_alloc(struct dentry *parent, struct ll_statahead_info *sai, __u64 index,
- const char *name, int len)
+ const char *name, int len, const struct lu_fid *fid)
{
struct ll_inode_info *lli;
struct sa_entry *entry;
entry->se_qstr.hash = full_name_hash(parent, name, len);
entry->se_qstr.len = len;
entry->se_qstr.name = dname;
+ entry->se_fid = *fid;
lli = ll_i2info(sai->sai_dentry->d_inode);
spin_lock(&lli->lli_sa_lock);
}
child = entry->se_inode;
- if (!child) {
- /*
- * lookup.
- */
- LASSERT(fid_is_zero(&minfo->mi_data.op_fid2));
-
- /* XXX: No fid in reply, this is probably cross-ref case.
- * SA can't handle it yet.
- */
- if (body->mbo_valid & OBD_MD_MDS) {
- rc = -EAGAIN;
- goto out;
- }
- } else {
- /*
- * revalidate.
- */
- /* unlinked and re-created with the same name */
+ if (child) {
+ /* revalidate; unlinked and re-created with the same name */
if (unlikely(!lu_fid_eq(&minfo->mi_data.op_fid2, &body->mbo_fid1))) {
entry->se_inode = NULL;
iput(child);
}
/* finish async stat RPC arguments */
-static void sa_fini_data(struct md_enqueue_info *minfo,
- struct ldlm_enqueue_info *einfo)
+static void sa_fini_data(struct md_enqueue_info *minfo)
{
- LASSERT(minfo && einfo);
iput(minfo->mi_dir);
kfree(minfo);
- kfree(einfo);
}
/**
* prepare arguments for async stat RPC.
*/
-static int sa_prep_data(struct inode *dir, struct inode *child,
- struct sa_entry *entry, struct md_enqueue_info **pmi,
- struct ldlm_enqueue_info **pei)
+static struct md_enqueue_info *
+sa_prep_data(struct inode *dir, struct inode *child, struct sa_entry *entry)
{
- const struct qstr *qstr = &entry->se_qstr;
struct md_enqueue_info *minfo;
struct ldlm_enqueue_info *einfo;
struct md_op_data *op_data;
- einfo = kzalloc(sizeof(*einfo), GFP_NOFS);
- if (!einfo)
- return -ENOMEM;
-
minfo = kzalloc(sizeof(*minfo), GFP_NOFS);
- if (!minfo) {
- kfree(einfo);
- return -ENOMEM;
- }
+ if (!minfo)
+ return ERR_PTR(-ENOMEM);
- op_data = ll_prep_md_op_data(&minfo->mi_data, dir, child, qstr->name,
- qstr->len, 0, LUSTRE_OPC_ANY, NULL);
+ op_data = ll_prep_md_op_data(&minfo->mi_data, dir, child, NULL, 0, 0,
+ LUSTRE_OPC_ANY, NULL);
if (IS_ERR(op_data)) {
- kfree(einfo);
kfree(minfo);
- return PTR_ERR(op_data);
+ return (struct md_enqueue_info *)op_data;
}
+ if (!child)
+ op_data->op_fid2 = entry->se_fid;
+
minfo->mi_it.it_op = IT_GETATTR;
minfo->mi_dir = igrab(dir);
minfo->mi_cb = ll_statahead_interpret;
minfo->mi_cbdata = entry;
+ einfo = &minfo->mi_einfo;
einfo->ei_type = LDLM_IBITS;
einfo->ei_mode = it_to_lock_mode(&minfo->mi_it);
einfo->ei_cb_bl = ll_md_blocking_ast;
einfo->ei_cb_gl = NULL;
einfo->ei_cbdata = NULL;
- *pmi = minfo;
- *pei = einfo;
-
- return 0;
+ return minfo;
}
/* async stat for file not found in dcache */
static int sa_lookup(struct inode *dir, struct sa_entry *entry)
{
struct md_enqueue_info *minfo;
- struct ldlm_enqueue_info *einfo;
int rc;
- rc = sa_prep_data(dir, NULL, entry, &minfo, &einfo);
- if (rc)
- return rc;
+ minfo = sa_prep_data(dir, NULL, entry);
+ if (IS_ERR(minfo))
+ return PTR_ERR(minfo);
- rc = md_intent_getattr_async(ll_i2mdexp(dir), minfo, einfo);
+ rc = md_intent_getattr_async(ll_i2mdexp(dir), minfo);
if (rc)
- sa_fini_data(minfo, einfo);
+ sa_fini_data(minfo);
return rc;
}
struct lookup_intent it = { .it_op = IT_GETATTR,
.it_lock_handle = 0 };
struct md_enqueue_info *minfo;
- struct ldlm_enqueue_info *einfo;
int rc;
if (unlikely(!inode))
return 1;
}
- rc = sa_prep_data(dir, inode, entry, &minfo, &einfo);
- if (rc) {
+ minfo = sa_prep_data(dir, inode, entry);
+ if (IS_ERR(minfo)) {
entry->se_inode = NULL;
iput(inode);
- return rc;
+ return PTR_ERR(minfo);
}
- rc = md_intent_getattr_async(ll_i2mdexp(dir), minfo, einfo);
+ rc = md_intent_getattr_async(ll_i2mdexp(dir), minfo);
if (rc) {
entry->se_inode = NULL;
iput(inode);
- sa_fini_data(minfo, einfo);
+ sa_fini_data(minfo);
}
return rc;
}
/* async stat for file with @name */
-static void sa_statahead(struct dentry *parent, const char *name, int len)
+static void sa_statahead(struct dentry *parent, const char *name, int len,
+ const struct lu_fid *fid)
{
struct inode *dir = d_inode(parent);
struct ll_inode_info *lli = ll_i2info(dir);
struct sa_entry *entry;
int rc;
- entry = sa_alloc(parent, sai, sai->sai_index, name, len);
+ entry = sa_alloc(parent, sai, sai->sai_index, name, len, fid);
if (IS_ERR(entry))
return;
for (ent = lu_dirent_start(dp);
ent && thread_is_running(sa_thread) && !sa_low_hit(sai);
ent = lu_dirent_next(ent)) {
+ struct lu_fid fid;
__u64 hash;
int namelen;
char *name;
if (unlikely(++first == 1))
continue;
+ fid_le_to_cpu(&fid, &ent->lde_fid);
+
/* wait for spare statahead window */
do {
l_wait_event(sa_thread->t_ctl_waitq,
} while (sa_sent_full(sai) &&
thread_is_running(sa_thread));
- sa_statahead(parent, name, namelen);
+ sa_statahead(parent, name, namelen, &fid);
}
pos = le64_to_cpu(dp->ldp_hash_end);
struct timespec64 ts;
int i, rc, seed[2];
- CLASSERT(sizeof(LUSTRE_VOLATILE_HDR) == LUSTRE_VOLATILE_HDR_LEN + 1);
+ BUILD_BUG_ON(sizeof(LUSTRE_VOLATILE_HDR) != LUSTRE_VOLATILE_HDR_LEN + 1);
/* print an address of _any_ initialized kernel symbol from this
* module, to allow debugging with gdb that doesn't support data
static void vvp_pgcache_id_unpack(loff_t pos, struct vvp_pgcache_id *id)
{
- CLASSERT(sizeof(pos) == sizeof(__u64));
+ BUILD_BUG_ON(sizeof(pos) != sizeof(__u64));
id->vpi_index = pos & 0xffffffff;
id->vpi_depth = (pos >> PGC_DEPTH_SHIFT) & 0xf;
# define CLOBINVRNT(env, clob, expr) \
((void)sizeof(env), (void)sizeof(clob), (void)sizeof(!!(expr)))
-int lov_read_and_clear_async_rc(struct cl_object *clob);
-
int vvp_io_init(const struct lu_env *env, struct cl_object *obj,
struct cl_io *io);
int vvp_io_write_commit(const struct lu_env *env, struct cl_io *io);
io->ci_ignore_layout, io->ci_verify_layout,
vio->vui_layout_gen, io->ci_restore_needed);
- if (io->ci_restore_needed == 1) {
+ if (io->ci_restore_needed) {
int rc;
/* file was detected release, we need to restore it
static void vvp_io_setattr_fini(const struct lu_env *env,
const struct cl_io_slice *ios)
{
+ bool restore_needed = ios->cis_io->ci_restore_needed;
+ struct inode *inode = vvp_object_inode(ios->cis_obj);
+
vvp_io_fini(env, ios);
+
+ if (restore_needed && !ios->cis_io->ci_restore_needed) {
+ /* restore finished, set data modified flag for HSM */
+ set_bit(LLIF_DATA_MODIFIED, &(ll_i2info(inode))->lli_flags);
+ }
}
static int vvp_io_read_start(const struct lu_env *env,
io->ci_lockreq = CILR_MANDATORY;
}
- /* ignore layout change for generic CIT_MISC but not for glimpse.
- * io context for glimpse must set ci_verify_layout to true,
- * see cl_glimpse_size0() for details.
- */
- if (io->ci_type == CIT_MISC && !io->ci_verify_layout)
- io->ci_ignore_layout = 1;
-
/* Enqueue layout lock and get layout version. We need to do this
* even for operations requiring to open file, such as read and write,
* because it might not grant layout lock in IT_OPEN.
* This takes inode as a separate argument, because inode on which error is to
* be set can be different from \a vmpage inode in case of direct-io.
*/
-static void vvp_vmpage_error(struct inode *inode, struct page *vmpage, int ioret)
+static void vvp_vmpage_error(struct inode *inode, struct page *vmpage,
+ int ioret)
{
struct vvp_object *obj = cl_inode2vvp(inode);
(!strcmp(name, "ima") || !strcmp(name, "evm")))
return -EOPNOTSUPP;
+ /*
+ * In user.* namespace, only regular files and directories can have
+ * extended attributes.
+ */
+ if (handler->flags == XATTR_USER_T) {
+ if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode))
+ return -EPERM;
+ }
+
sprintf(fullname, "%s%s\n", handler->prefix, name);
rc = md_setxattr(sbi->ll_md_exp, ll_inode2fid(inode),
valid, fullname, pv, size, 0, flags,
/* refresh slave from server */
body = req_capsule_server_get(&req->rq_pill,
&RMF_MDT_BODY);
- LASSERT(body);
-
- if (unlikely(body->mbo_nlink < 2)) {
- /*
- * If this is bad stripe, most likely due
- * to the race between close(unlink) and
- * getattr, let's return -EONENT, so llite
- * will revalidate the dentry see
- * ll_inode_revalidate_fini()
- */
- CDEBUG(D_INODE, "%s: nlink %d < 2 corrupt stripe %d "DFID":" DFID"\n",
- obd->obd_name, body->mbo_nlink, i,
- PFID(&lsm->lsm_md_oinfo[i].lmo_fid),
- PFID(&lsm->lsm_md_oinfo[0].lmo_fid));
-
+ if (!body) {
if (it.it_lock_mode && lockh) {
ldlm_lock_decref(lockh, it.it_lock_mode);
it.it_lock_mode = 0;
*/
obd->obd_self_export->exp_connect_data = *conn_data;
}
-#if 0
- else if (ev == OBD_NOTIFY_DISCON) {
- /*
- * For disconnect event, flush fld cache for failout MDS case.
- */
- fld_client_flush(&lmv->lmv_fld);
- }
-#endif
+
/*
* Pass the notification up the chain.
*/
/* count how many requests must be sent to the given target */
for (i = 0; i < hur->hur_request.hr_itemcount; i++) {
curr_tgt = lmv_find_target(lmv, &hur->hur_user_item[i].hui_fid);
+ if (IS_ERR(curr_tgt))
+ return PTR_ERR(curr_tgt);
if (obd_uuid_equals(&curr_tgt->ltd_uuid, &tgt_mds->ltd_uuid))
nr++;
}
return nr;
}
-static void lmv_hsm_req_build(struct lmv_obd *lmv,
- struct hsm_user_request *hur_in,
- const struct lmv_tgt_desc *tgt_mds,
- struct hsm_user_request *hur_out)
+static int lmv_hsm_req_build(struct lmv_obd *lmv,
+ struct hsm_user_request *hur_in,
+ const struct lmv_tgt_desc *tgt_mds,
+ struct hsm_user_request *hur_out)
{
int i, nr_out;
struct lmv_tgt_desc *curr_tgt;
for (i = 0; i < hur_in->hur_request.hr_itemcount; i++) {
curr_tgt = lmv_find_target(lmv,
&hur_in->hur_user_item[i].hui_fid);
+ if (IS_ERR(curr_tgt))
+ return PTR_ERR(curr_tgt);
if (obd_uuid_equals(&curr_tgt->ltd_uuid, &tgt_mds->ltd_uuid)) {
hur_out->hur_user_item[nr_out] =
hur_in->hur_user_item[i];
hur_out->hur_request.hr_itemcount = nr_out;
memcpy(hur_data(hur_out), hur_data(hur_in),
hur_in->hur_request.hr_data_len);
+
+ return 0;
}
static int lmv_hsm_ct_unregister(struct lmv_obd *lmv, unsigned int cmd, int len,
struct lustre_kernelcomm *lk,
void __user *uarg)
{
- int rc = 0;
__u32 i;
/* unregister request (call from llapi_hsm_copytool_fini) */
* Unreached coordinators will get EPIPE on next requests
* and will unregister automatically.
*/
- rc = libcfs_kkuc_group_rem(lk->lk_uid, lk->lk_group);
-
- return rc;
+ return libcfs_kkuc_group_rem(lk->lk_uid, lk->lk_group);
}
static int lmv_hsm_ct_register(struct lmv_obd *lmv, unsigned int cmd, int len,
} else {
/* split fid list to their respective MDS */
for (i = 0; i < count; i++) {
- unsigned int nr, reqlen;
- int rc1;
struct hsm_user_request *req;
+ size_t reqlen;
+ int nr, rc1;
tgt = lmv->tgts[i];
if (!tgt || !tgt->ltd_exp)
continue;
nr = lmv_hsm_req_count(lmv, hur, tgt);
+ if (nr < 0)
+ return nr;
if (nr == 0) /* nothing for this MDS */
continue;
if (!req)
return -ENOMEM;
- lmv_hsm_req_build(lmv, hur, tgt, req);
+ rc1 = lmv_hsm_req_build(lmv, hur, tgt, req);
+ if (rc1 < 0)
+ goto hsm_req_err;
rc1 = obd_iocontrol(cmd, tgt->ltd_exp, reqlen,
req, uarg);
+hsm_req_err:
if (rc1 != 0 && rc == 0)
rc = rc1;
kvfree(req);
lmv->desc.ld_active_tgt_count = 0;
lmv->max_def_easize = 0;
lmv->max_easize = 0;
- lmv->lmv_placement = PLACEMENT_CHAR_POLICY;
spin_lock_init(&lmv->lmv_lock);
mutex_init(&lmv->lmv_init_mutex);
if (rc)
return rc;
- rc = md_getstatus(lmv->tgts[0]->ltd_exp, fid);
- return rc;
+ return md_getstatus(lmv->tgts[0]->ltd_exp, fid);
}
static int lmv_getxattr(struct obd_export *exp, const struct lu_fid *fid,
if (IS_ERR(tgt))
return PTR_ERR(tgt);
- rc = md_getxattr(tgt->ltd_exp, fid, valid, name, input,
+ return md_getxattr(tgt->ltd_exp, fid, valid, name, input,
input_size, output_size, flags, request);
-
- return rc;
}
static int lmv_setxattr(struct obd_export *exp, const struct lu_fid *fid,
if (IS_ERR(tgt))
return PTR_ERR(tgt);
- rc = md_setxattr(tgt->ltd_exp, fid, valid, name, input,
+ return md_setxattr(tgt->ltd_exp, fid, valid, name, input,
input_size, output_size, flags, suppgid,
request);
-
- return rc;
}
static int lmv_getattr(struct obd_export *exp, struct md_op_data *op_data,
return 0;
}
- rc = md_getattr(tgt->ltd_exp, op_data, request);
-
- return rc;
+ return md_getattr(tgt->ltd_exp, op_data, request);
}
static int lmv_null_inode(struct obd_export *exp, const struct lu_fid *fid)
return PTR_ERR(tgt);
CDEBUG(D_INODE, "CLOSE "DFID"\n", PFID(&op_data->op_fid1));
- rc = md_close(tgt->ltd_exp, op_data, mod, request);
- return rc;
+ return md_close(tgt->ltd_exp, op_data, mod, request);
}
/**
CDEBUG(D_INODE, "ENQUEUE '%s' on " DFID " -> mds #%u\n",
LL_IT2STR(it), PFID(&op_data->op_fid1), tgt->ltd_idx);
- rc = md_enqueue(tgt->ltd_exp, einfo, policy, it, op_data, lockh,
+ return md_enqueue(tgt->ltd_exp, einfo, policy, it, op_data, lockh,
extra_lock_flags);
-
- return rc;
}
static int
if (rc != 0)
return rc;
- rc = md_link(tgt->ltd_exp, op_data, request);
-
- return rc;
+ return md_link(tgt->ltd_exp, op_data, request);
}
static int lmv_rename(struct obd_export *exp, struct md_op_data *op_data,
if (IS_ERR(tgt))
return PTR_ERR(tgt);
- rc = md_sync(tgt->ltd_exp, fid, request);
- return rc;
+ return md_sync(tgt->ltd_exp, fid, request);
}
/**
return rc;
if (unlikely(lsm)) {
- rc = lmv_read_striped_page(exp, op_data, cb_op, offset, ppage);
- return rc;
+ return lmv_read_striped_page(exp, op_data, cb_op, offset, ppage);
}
tgt = lmv_find_target(lmv, &op_data->op_fid1);
if (IS_ERR(tgt))
return PTR_ERR(tgt);
- rc = md_read_page(tgt->ltd_exp, op_data, cb_op, offset, ppage);
-
- return rc;
+ return md_read_page(tgt->ltd_exp, op_data, cb_op, offset, ppage);
}
/**
{
struct lmv_obd *lmv = &exp->exp_obd->u.lmv;
struct lmv_tgt_desc *tgt = lmv->tgts[0];
- int rc;
if (!tgt || !tgt->ltd_exp)
return -EINVAL;
- rc = md_set_lock_data(tgt->ltd_exp, lockh, data, bits);
- return rc;
+ return md_set_lock_data(tgt->ltd_exp, lockh, data, bits);
}
static enum ldlm_mode lmv_lock_match(struct obd_export *exp, __u64 flags,
}
static int lmv_intent_getattr_async(struct obd_export *exp,
- struct md_enqueue_info *minfo,
- struct ldlm_enqueue_info *einfo)
+ struct md_enqueue_info *minfo)
{
struct md_op_data *op_data = &minfo->mi_data;
struct obd_device *obd = exp->exp_obd;
struct lmv_obd *lmv = &obd->u.lmv;
- struct lmv_tgt_desc *tgt = NULL;
+ struct lmv_tgt_desc *ptgt = NULL;
+ struct lmv_tgt_desc *ctgt = NULL;
int rc;
+ if (!fid_is_sane(&op_data->op_fid2))
+ return -EINVAL;
+
rc = lmv_check_connect(obd);
if (rc)
return rc;
- tgt = lmv_locate_mds(lmv, op_data, &op_data->op_fid1);
- if (IS_ERR(tgt))
- return PTR_ERR(tgt);
+ ptgt = lmv_locate_mds(lmv, op_data, &op_data->op_fid1);
+ if (IS_ERR(ptgt))
+ return PTR_ERR(ptgt);
- rc = md_intent_getattr_async(tgt->ltd_exp, minfo, einfo);
- return rc;
+ ctgt = lmv_locate_mds(lmv, op_data, &op_data->op_fid2);
+ if (IS_ERR(ctgt))
+ return PTR_ERR(ctgt);
+
+ /*
+ * if child is on remote MDT, we need 2 async RPCs to fetch both LOOKUP
+ * lock on parent, and UPDATE lock on child MDT, which makes all
+ * complicated. Considering remote dir is rare case, and not supporting
+ * it in statahead won't cause any issue, drop its support for now.
+ */
+ if (ptgt != ctgt)
+ return -ENOTSUPP;
+
+ return md_intent_getattr_async(ptgt->ltd_exp, minfo);
}
static int lmv_revalidate_lock(struct obd_export *exp, struct lookup_intent *it,
if (IS_ERR(tgt))
return PTR_ERR(tgt);
- rc = md_revalidate_lock(tgt->ltd_exp, it, fid, bits);
- return rc;
+ return md_revalidate_lock(tgt->ltd_exp, it, fid, bits);
}
static int
}
if (oqctl->qc_cmd != Q_GETOQUOTA) {
- rc = obd_quotactl(tgt->ltd_exp, oqctl);
- return rc;
+ return obd_quotactl(tgt->ltd_exp, oqctl);
}
for (i = 0; i < lmv->desc.ld_tgt_count; i++) {
static int __init lmv_init(void)
{
struct lprocfs_static_vars lvars;
- int rc;
lprocfs_lmv_init_vars(&lvars);
- rc = class_register_type(&lmv_obd_ops, &lmv_md_ops,
+ return class_register_type(&lmv_obd_ops, &lmv_md_ops,
LUSTRE_LMV_NAME, NULL);
- return rc;
}
static void lmv_exit(void)
}
LUSTRE_RO_ATTR(numobd);
-static const char *placement_name[] = {
- [PLACEMENT_CHAR_POLICY] = "CHAR",
- [PLACEMENT_NID_POLICY] = "NID",
- [PLACEMENT_INVAL_POLICY] = "INVAL"
-};
-
-static enum placement_policy placement_name2policy(char *name, int len)
-{
- int i;
-
- for (i = 0; i < PLACEMENT_MAX_POLICY; i++) {
- if (!strncmp(placement_name[i], name, len))
- return i;
- }
- return PLACEMENT_INVAL_POLICY;
-}
-
-static const char *placement_policy2name(enum placement_policy placement)
-{
- LASSERT(placement < PLACEMENT_MAX_POLICY);
- return placement_name[placement];
-}
-
-static ssize_t placement_show(struct kobject *kobj, struct attribute *attr,
- char *buf)
-{
- struct obd_device *dev = container_of(kobj, struct obd_device,
- obd_kobj);
- struct lmv_obd *lmv;
-
- lmv = &dev->u.lmv;
- return sprintf(buf, "%s\n", placement_policy2name(lmv->lmv_placement));
-}
-
-#define MAX_POLICY_STRING_SIZE 64
-
-static ssize_t placement_store(struct kobject *kobj, struct attribute *attr,
- const char *buffer,
- size_t count)
-{
- struct obd_device *dev = container_of(kobj, struct obd_device,
- obd_kobj);
- char dummy[MAX_POLICY_STRING_SIZE + 1];
- enum placement_policy policy;
- struct lmv_obd *lmv = &dev->u.lmv;
-
- memcpy(dummy, buffer, MAX_POLICY_STRING_SIZE);
-
- if (count > MAX_POLICY_STRING_SIZE)
- count = MAX_POLICY_STRING_SIZE;
-
- if (dummy[count - 1] == '\n')
- count--;
- dummy[count] = '\0';
-
- policy = placement_name2policy(dummy, count);
- if (policy != PLACEMENT_INVAL_POLICY) {
- spin_lock(&lmv->lmv_lock);
- lmv->lmv_placement = policy;
- spin_unlock(&lmv->lmv_lock);
- } else {
- return -EINVAL;
- }
- return count;
-}
-LUSTRE_RW_ATTR(placement);
-
static ssize_t activeobd_show(struct kobject *kobj, struct attribute *attr,
char *buf)
{
struct obd_device *dev = p->private;
struct lmv_obd *lmv = &dev->u.lmv;
- return (*pos >= lmv->desc.ld_tgt_count) ? NULL : lmv->tgts[*pos];
+ while (*pos < lmv->tgts_size) {
+ if (lmv->tgts[*pos])
+ return lmv->tgts[*pos];
+ ++*pos;
+ }
+
+ return NULL;
}
static void lmv_tgt_seq_stop(struct seq_file *p, void *v)
{
struct obd_device *dev = p->private;
struct lmv_obd *lmv = &dev->u.lmv;
+
++*pos;
- return (*pos >= lmv->desc.ld_tgt_count) ? NULL : lmv->tgts[*pos];
+ while (*pos < lmv->tgts_size) {
+ if (lmv->tgts[*pos])
+ return lmv->tgts[*pos];
+ ++*pos;
+ }
+
+ return NULL;
}
static int lmv_tgt_seq_show(struct seq_file *p, void *v)
static struct attribute *lmv_attrs[] = {
&lustre_attr_activeobd.attr,
&lustre_attr_numobd.attr,
- &lustre_attr_placement.attr,
NULL,
};
* - in setattr, for truncate
*/
/* the truncate is for size > 0 so triggers a restore */
- if (cl_io_is_trunc(io))
+ if (cl_io_is_trunc(io)) {
io->ci_restore_needed = 1;
- result = -ENODATA;
+ result = -ENODATA;
+ } else {
+ result = 1;
+ }
break;
case CIT_READ:
case CIT_WRITE:
struct lov_layout_raid0 *r0 = lov_r0(loo);
struct lov_lock *lovlck;
+ CDEBUG(D_INODE, "%p: lock/io FID " DFID "/" DFID ", lock/io clobj %p/%p\n",
+ loo, PFID(lu_object_fid(lov2lu(loo))),
+ PFID(lu_object_fid(&obj->co_lu)),
+ lov2cl(loo), obj);
+
file_start = cl_offset(lov2cl(loo), lock->cll_descr.cld_start);
file_end = cl_offset(lov2cl(loo), lock->cll_descr.cld_end + 1) - 1;
CDEBUG(D_CONFIG, "idx=%d ltd_gen=%d ld_tgt_count=%d\n",
index, tgt->ltd_gen, lov->desc.ld_tgt_count);
- rc = obd_notify(obd, tgt_obd, OBD_NOTIFY_CREATE, &index);
-
if (lov->lov_connects == 0) {
/* lov_connect hasn't been called yet. We'll do the
* lov_connect_obd on this target when that fn first runs,
if (result != 0)
goto out;
+ if (!dev->ld_target[ost_idx]) {
+ CERROR("%s: OST %04x is not initialized\n",
+ lov2obd(dev->ld_lov)->obd_name, ost_idx);
+ result = -EIO;
+ goto out;
+ }
+
subdev = lovsub2cl_dev(dev->ld_target[ost_idx]);
subconf->u.coc_oinfo = oinfo;
LASSERTF(subdev, "not init ost %d\n", ost_idx);
static inline void lov_conf_freeze(struct lov_object *lov)
{
+ CDEBUG(D_INODE, "To take share lov(%p) owner %p/%p\n",
+ lov, lov->lo_owner, current);
if (lov->lo_owner != current)
down_read(&lov->lo_type_guard);
}
static inline void lov_conf_thaw(struct lov_object *lov)
{
+ CDEBUG(D_INODE, "To release share lov(%p) owner %p/%p\n",
+ lov, lov->lo_owner, current);
if (lov->lo_owner != current)
up_read(&lov->lo_type_guard);
}
down_write(&lov->lo_type_guard);
LASSERT(!lov->lo_owner);
lov->lo_owner = current;
+ CDEBUG(D_INODE, "Took exclusive lov(%p) owner %p\n",
+ lov, lov->lo_owner);
}
static void lov_conf_unlock(struct lov_object *lov)
{
+ CDEBUG(D_INODE, "To release exclusive lov(%p) owner %p\n",
+ lov, lov->lo_owner);
lov->lo_owner = NULL;
up_write(&lov->lo_type_guard);
}
struct lov_object *lov, struct lov_stripe_md *lsm,
const struct cl_object_conf *conf)
{
+ struct lov_device *lov_dev = lov_object_dev(lov);
enum lov_layout_type llt = lov_type(lsm);
union lov_layout_state *state = &lov->u;
const struct lov_layout_operations *old_ops;
LASSERT(!atomic_read(&lov->lo_active_ios));
+ CDEBUG(D_INODE, DFID "Apply new layout lov %p, type %d\n",
+ PFID(lu_object_fid(lov2lu(lov))), lov, llt);
+
lov->lo_type = LLT_EMPTY;
/* page bufsize fixup */
cl_object_header(&lov->lo_cl)->coh_page_bufsize -=
lov_page_slice_fixup(lov, NULL);
- rc = new_ops->llo_init(env, lov_object_dev(lov), lov, lsm, conf, state);
+ rc = new_ops->llo_init(env, lov_dev, lov, lsm, conf, state);
if (rc) {
+ struct obd_device *obd = lov2obd(lov_dev->ld_lov);
+
+ CERROR("%s: cannot apply new layout on " DFID " : rc = %d\n",
+ obd->obd_name, PFID(lu_object_fid(lov2lu(lov))), rc);
new_ops->llo_delete(env, lov, state);
new_ops->llo_fini(env, lov, state);
/* this file becomes an EMPTY file. */
struct cl_io *io)
{
CL_IO_SLICE_CLEAN(lov_env_io(env), lis_cl);
+
+ CDEBUG(D_INODE, DFID "io %p type %d ignore/verify layout %d/%d\n",
+ PFID(lu_object_fid(&obj->co_lu)), io, io->ci_type,
+ io->ci_ignore_layout, io->ci_verify_layout);
+
return LOV_2DISPATCH_MAYLOCK(cl2lov(obj), llo_io_init,
!io->ci_ignore_layout, env, obj, io);
}
if (!lsm) {
cl->cl_size = 0;
cl->cl_layout_gen = CL_LAYOUT_GEN_EMPTY;
- cl->cl_is_released = false;
-
return 0;
}
cl->cl_size = lov_mds_md_size(lsm->lsm_stripe_count, lsm->lsm_magic);
cl->cl_layout_gen = lsm->lsm_layout_gen;
- cl->cl_is_released = lsm_is_released(lsm);
rc = lov_lsm_pack(lsm, buf->lb_buf, buf->lb_len);
lov_lsm_put(lsm);
lmmv1->lmm_layout_gen = cpu_to_le16(lsm->lsm_layout_gen);
if (lsm->lsm_magic == LOV_MAGIC_V3) {
- CLASSERT(sizeof(lsm->lsm_pool_name) ==
+ BUILD_BUG_ON(sizeof(lsm->lsm_pool_name) !=
sizeof(lmmv3->lmm_pool_name));
strlcpy(lmmv3->lmm_pool_name, lsm->lsm_pool_name,
sizeof(lmmv3->lmm_pool_name));
return rc;
}
-struct lov_stripe_md *lov_lsm_alloc(u16 stripe_count, u32 pattern, u32 magic)
+static struct lov_stripe_md *lov_lsm_alloc(u16 stripe_count, u32 pattern,
+ u32 magic)
{
struct lov_stripe_md *lsm;
unsigned int i;
/* FIXME: Bug 1185 - copy fields properly when structs change */
/* struct lov_user_md_v3 and struct lov_mds_md_v3 must be the same */
- CLASSERT(sizeof(lum) == sizeof(struct lov_mds_md_v3));
- CLASSERT(sizeof(lum.lmm_objects[0]) == sizeof(lmmk->lmm_objects[0]));
+ BUILD_BUG_ON(sizeof(lum) != sizeof(struct lov_mds_md_v3));
+ BUILD_BUG_ON(sizeof(lum.lmm_objects[0]) != sizeof(lmmk->lmm_objects[0]));
if (cpu_to_le32(LOV_MAGIC) != LOV_MAGIC &&
(lmmk->lmm_magic == cpu_to_le32(LOV_MAGIC_V1) ||
continue;
}
- if (!lov->lov_tgts[i]->ltd_active)
- lov_check_and_wait_active(lov, i);
-
/* skip targets that have been explicitly disabled by the
* administrator
*/
continue;
}
+ if (!lov->lov_tgts[i]->ltd_active)
+ lov_check_and_wait_active(lov, i);
+
req = kzalloc(sizeof(*req), GFP_NOFS);
if (!req) {
rc = -ENOMEM;
struct lu_fid *fid, __u64 *bits);
int mdc_intent_getattr_async(struct obd_export *exp,
- struct md_enqueue_info *minfo,
- struct ldlm_enqueue_info *einfo);
+ struct md_enqueue_info *minfo);
enum ldlm_mode mdc_lock_match(struct obd_export *exp, __u64 flags,
const struct lu_fid *fid, enum ldlm_type type,
char *tmp;
__u64 flags;
- CLASSERT(sizeof(struct mdt_rec_reint) == sizeof(struct mdt_rec_create));
+ BUILD_BUG_ON(sizeof(struct mdt_rec_reint) != sizeof(struct mdt_rec_create));
rec = req_capsule_client_get(&req->rq_pill, &RMF_REC_REINT);
rec->cr_opcode = REINT_CREATE;
char *tmp;
__u64 cr_flags;
- CLASSERT(sizeof(struct mdt_rec_reint) == sizeof(struct mdt_rec_create));
+ BUILD_BUG_ON(sizeof(struct mdt_rec_reint) != sizeof(struct mdt_rec_create));
rec = req_capsule_client_get(&req->rq_pill, &RMF_REC_REINT);
/* XXX do something about time, uid, gid */
struct mdt_rec_setattr *rec;
struct lov_user_md *lum = NULL;
- CLASSERT(sizeof(struct mdt_rec_reint) ==
+ BUILD_BUG_ON(sizeof(struct mdt_rec_reint) !=
sizeof(struct mdt_rec_setattr));
rec = req_capsule_client_get(&req->rq_pill, &RMF_REC_REINT);
mdc_setattr_pack_rec(rec, op_data);
{
struct mdt_rec_unlink *rec;
- CLASSERT(sizeof(struct mdt_rec_reint) == sizeof(struct mdt_rec_unlink));
+ BUILD_BUG_ON(sizeof(struct mdt_rec_reint) != sizeof(struct mdt_rec_unlink));
rec = req_capsule_client_get(&req->rq_pill, &RMF_REC_REINT);
rec->ul_opcode = op_data->op_cli_flags & CLI_RM_ENTRY ?
{
struct mdt_rec_link *rec;
- CLASSERT(sizeof(struct mdt_rec_reint) == sizeof(struct mdt_rec_link));
+ BUILD_BUG_ON(sizeof(struct mdt_rec_reint) != sizeof(struct mdt_rec_link));
rec = req_capsule_client_get(&req->rq_pill, &RMF_REC_REINT);
rec->lk_opcode = REINT_LINK;
{
struct mdt_rec_rename *rec;
- CLASSERT(sizeof(struct mdt_rec_reint) == sizeof(struct mdt_rec_rename));
+ BUILD_BUG_ON(sizeof(struct mdt_rec_reint) != sizeof(struct mdt_rec_rename));
rec = req_capsule_client_get(&req->rq_pill, &RMF_REC_REINT);
/* XXX do something about time, uid, gid */
struct mdc_getattr_args {
struct obd_export *ga_exp;
struct md_enqueue_info *ga_minfo;
- struct ldlm_enqueue_info *ga_einfo;
};
int it_open_error(int phase, struct lookup_intent *it)
LASSERT(!policy);
saved_flags |= LDLM_FL_HAS_INTENT;
- if (it->it_op & (IT_OPEN | IT_UNLINK | IT_GETATTR | IT_READDIR))
+ if (it->it_op & (IT_UNLINK | IT_GETATTR | IT_READDIR))
policy = &update_policy;
else if (it->it_op & IT_LAYOUT)
policy = &layout_policy;
struct mdc_getattr_args *ga = args;
struct obd_export *exp = ga->ga_exp;
struct md_enqueue_info *minfo = ga->ga_minfo;
- struct ldlm_enqueue_info *einfo = ga->ga_einfo;
+ struct ldlm_enqueue_info *einfo = &minfo->mi_einfo;
struct lookup_intent *it;
struct lustre_handle *lockh;
struct obd_device *obddev;
rc = mdc_finish_intent_lock(exp, req, &minfo->mi_data, it, lockh);
out:
- kfree(einfo);
minfo->mi_cb(req, minfo, rc);
return 0;
}
int mdc_intent_getattr_async(struct obd_export *exp,
- struct md_enqueue_info *minfo,
- struct ldlm_enqueue_info *einfo)
+ struct md_enqueue_info *minfo)
{
struct md_op_data *op_data = &minfo->mi_data;
struct lookup_intent *it = &minfo->mi_it;
struct mdc_getattr_args *ga;
struct obd_device *obddev = class_exp2obd(exp);
struct ldlm_res_id res_id;
- /*XXX: Both MDS_INODELOCK_LOOKUP and MDS_INODELOCK_UPDATE are needed
- * for statahead currently. Consider CMD in future, such two bits
- * maybe managed by different MDS, should be adjusted then.
- */
union ldlm_policy_data policy = {
.l_inodebits = { MDS_INODELOCK_LOOKUP | MDS_INODELOCK_UPDATE }
};
return rc;
}
- rc = ldlm_cli_enqueue(exp, &req, einfo, &res_id, &policy, &flags, NULL,
- 0, LVB_T_NONE, &minfo->mi_lockh, 1);
+ rc = ldlm_cli_enqueue(exp, &req, &minfo->mi_einfo, &res_id, &policy,
+ &flags, NULL, 0, LVB_T_NONE, &minfo->mi_lockh, 1);
if (rc < 0) {
obd_put_request_slot(&obddev->u.cli);
ptlrpc_req_finished(req);
return rc;
}
- CLASSERT(sizeof(*ga) <= sizeof(req->rq_async_args));
+ BUILD_BUG_ON(sizeof(*ga) > sizeof(req->rq_async_args));
ga = ptlrpc_req_async_args(req);
ga->ga_exp = exp;
ga->ga_minfo = minfo;
- ga->ga_einfo = einfo;
req->rq_interpret_reply = mdc_intent_getattr_async_interpret;
ptlrpcd_add_req(req);
if (opcode == MDS_REINT) {
struct mdt_rec_setxattr *rec;
- CLASSERT(sizeof(struct mdt_rec_setxattr) ==
+ BUILD_BUG_ON(sizeof(struct mdt_rec_setxattr) !=
sizeof(struct mdt_rec_reint));
rec = req_capsule_client_get(&req->rq_pill, &RMF_REC_REINT);
rec->sx_opcode = REINT_SETXATTR;
rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, MDS_CLOSE);
if (rc) {
ptlrpc_request_free(req);
+ req = NULL;
goto out;
}
LASSERT(imp->imp_obd == obd);
switch (event) {
- case IMP_EVENT_DISCON: {
-#if 0
- /* XXX Pass event up to OBDs stack. used only for FLD now */
- rc = obd_notify_observer(obd, obd, OBD_NOTIFY_DISCON, NULL);
-#endif
- break;
- }
case IMP_EVENT_INACTIVE: {
struct client_obd *cli = &obd->u.cli;
/*
case IMP_EVENT_OCD:
rc = obd_notify_observer(obd, obd, OBD_NOTIFY_OCD, NULL);
break;
+ case IMP_EVENT_DISCON:
case IMP_EVENT_DEACTIVATE:
case IMP_EVENT_ACTIVATE:
break;
if (cld->cld_recover)
config_log_put(cld->cld_recover);
- if (cld->cld_sptlrpc)
- config_log_put(cld->cld_sptlrpc);
if (cld->cld_params)
config_log_put(cld->cld_params);
+ if (cld->cld_sptlrpc)
+ config_log_put(cld->cld_sptlrpc);
if (cld_is_sptlrpc(cld))
sptlrpc_conf_log_stop(cld->cld_logname);
/* instance may be NULL, should check name */
if (strcmp(logname, cld->cld_logname) == 0) {
found = cld;
+ config_log_get(found);
break;
}
}
- if (found) {
- atomic_inc(&found->cld_refcount);
- LASSERT(found->cld_stopping == 0 || cld_is_sptlrpc(found) == 0);
- }
spin_unlock(&config_list_lock);
return found;
}
if (!cld)
return ERR_PTR(-ENOMEM);
+ rc = mgc_logname2resid(logname, &cld->cld_resid, type);
+ if (rc) {
+ kfree(cld);
+ return ERR_PTR(rc);
+ }
+
strcpy(cld->cld_logname, logname);
if (cfg)
cld->cld_cfg = *cfg;
cld->cld_cfg.cfg_obdname = obd->obd_name;
}
- rc = mgc_logname2resid(logname, &cld->cld_resid, type);
-
spin_lock(&config_list_lock);
list_add(&cld->cld_list_chain, &config_llog_list);
spin_unlock(&config_list_lock);
- if (rc) {
- config_log_put(cld);
- return ERR_PTR(rc);
- }
-
if (cld_is_sptlrpc(cld)) {
rc = mgc_process_log(obd, cld);
if (rc && rc != -ENOENT)
* We have one active log per "mount" - client instance or servername.
* Each instance may be at a different point in the log.
*/
-static int config_log_add(struct obd_device *obd, char *logname,
- struct config_llog_instance *cfg,
- struct super_block *sb)
+static struct config_llog_data *
+config_log_add(struct obd_device *obd, char *logname,
+ struct config_llog_instance *cfg, struct super_block *sb)
{
struct lustre_sb_info *lsi = s2lsi(sb);
struct config_llog_data *cld;
struct config_llog_data *sptlrpc_cld;
struct config_llog_data *params_cld;
+ bool locked = false;
char seclogname[32];
char *ptr;
int rc;
ptr = strrchr(logname, '-');
if (!ptr || ptr - logname > 8) {
CERROR("logname %s is too long\n", logname);
- return -EINVAL;
+ return ERR_PTR(-EINVAL);
}
memcpy(seclogname, logname, ptr - logname);
rc = PTR_ERR(params_cld);
CERROR("%s: can't create params log: rc = %d\n",
obd->obd_name, rc);
- goto out_err1;
+ goto out_sptlrpc;
}
cld = do_config_log_add(obd, logname, CONFIG_T_CONFIG, cfg, sb);
if (IS_ERR(cld)) {
CERROR("can't create log: %s\n", logname);
rc = PTR_ERR(cld);
- goto out_err2;
+ goto out_params;
}
cld->cld_sptlrpc = sptlrpc_cld;
CERROR("%s: sptlrpc log name not correct, %s: rc = %d\n",
obd->obd_name, seclogname, -EINVAL);
config_log_put(cld);
- return -EINVAL;
+ rc = -EINVAL;
+ goto out_cld;
}
recover_cld = config_recover_log_add(obd, seclogname, cfg, sb);
if (IS_ERR(recover_cld)) {
rc = PTR_ERR(recover_cld);
- goto out_err3;
+ goto out_cld;
}
+
+ mutex_lock(&cld->cld_lock);
+ locked = true;
cld->cld_recover = recover_cld;
}
- return 0;
+ if (!locked)
+ mutex_lock(&cld->cld_lock);
+ cld->cld_params = params_cld;
+ cld->cld_sptlrpc = sptlrpc_cld;
+ mutex_unlock(&cld->cld_lock);
+
+ return cld;
-out_err3:
+out_cld:
config_log_put(cld);
-out_err2:
+out_params:
config_log_put(params_cld);
-out_err1:
+out_sptlrpc:
config_log_put(sptlrpc_cld);
out_err:
- return rc;
+ return ERR_PTR(rc);
}
static DEFINE_MUTEX(llog_process_lock);
+static inline void config_mark_cld_stop(struct config_llog_data *cld)
+{
+ mutex_lock(&cld->cld_lock);
+ spin_lock(&config_list_lock);
+ cld->cld_stopping = 1;
+ spin_unlock(&config_list_lock);
+ mutex_unlock(&cld->cld_lock);
+}
+
/** Stop watching for updates on this log.
*/
static int config_log_end(char *logname, struct config_llog_instance *cfg)
return rc;
}
+ spin_lock(&config_list_lock);
cld->cld_stopping = 1;
+ spin_unlock(&config_list_lock);
cld_recover = cld->cld_recover;
cld->cld_recover = NULL;
+
+ cld_params = cld->cld_params;
+ cld->cld_params = NULL;
+ cld_sptlrpc = cld->cld_sptlrpc;
+ cld->cld_sptlrpc = NULL;
mutex_unlock(&cld->cld_lock);
if (cld_recover) {
- mutex_lock(&cld_recover->cld_lock);
- cld_recover->cld_stopping = 1;
- mutex_unlock(&cld_recover->cld_lock);
+ config_mark_cld_stop(cld_recover);
config_log_put(cld_recover);
}
- spin_lock(&config_list_lock);
- cld_sptlrpc = cld->cld_sptlrpc;
- cld->cld_sptlrpc = NULL;
- cld_params = cld->cld_params;
- cld->cld_params = NULL;
- spin_unlock(&config_list_lock);
-
- if (cld_sptlrpc)
- config_log_put(cld_sptlrpc);
-
if (cld_params) {
- mutex_lock(&cld_params->cld_lock);
- cld_params->cld_stopping = 1;
- mutex_unlock(&cld_params->cld_lock);
+ config_mark_cld_stop(cld_params);
config_log_put(cld_params);
}
+ if (cld_sptlrpc)
+ config_log_put(cld_sptlrpc);
+
/* drop the ref from the find */
config_log_put(cld);
/* drop the start ref */
/* Keep trying failed locks periodically */
spin_lock(&config_list_lock);
rq_state |= RQ_RUNNING;
- while (1) {
+ while (!(rq_state & RQ_STOP)) {
struct l_wait_info lwi;
struct config_llog_data *cld, *cld_prev;
int rand = cfs_rand() & MGC_TIMEOUT_RAND_CENTISEC;
- int stopped = !!(rq_state & RQ_STOP);
int to;
/* Any new or requeued lostlocks will change the state */
spin_lock(&config_list_lock);
rq_state &= ~RQ_PRECLEANUP;
list_for_each_entry(cld, &config_llog_list, cld_list_chain) {
- if (!cld->cld_lostlock)
+ if (!cld->cld_lostlock || cld->cld_stopping)
continue;
+ /*
+ * hold reference to avoid being freed during
+ * subsequent processing.
+ */
+ config_log_get(cld);
+ cld->cld_lostlock = 0;
spin_unlock(&config_list_lock);
- LASSERT(atomic_read(&cld->cld_refcount) > 0);
-
- /* Whether we enqueued again or not in mgc_process_log,
- * we're done with the ref from the old enqueue
- */
if (cld_prev)
config_log_put(cld_prev);
cld_prev = cld;
- cld->cld_lostlock = 0;
- if (likely(!stopped))
+ if (likely(!(rq_state & RQ_STOP))) {
do_requeue(cld);
-
- spin_lock(&config_list_lock);
+ spin_lock(&config_list_lock);
+ } else {
+ spin_lock(&config_list_lock);
+ break;
+ }
}
spin_unlock(&config_list_lock);
if (cld_prev)
config_log_put(cld_prev);
- /* break after scanning the list so that we can drop
- * refcount to losing lock clds
- */
- if (unlikely(stopped)) {
- spin_lock(&config_list_lock);
- break;
- }
-
/* Wait a bit to see if anyone else needs a requeue */
lwi = (struct l_wait_info) { 0 };
l_wait_event(rq_waitq, rq_state & (RQ_NOW | RQ_STOP),
&lwi);
spin_lock(&config_list_lock);
}
+
/* spinlock and while guarantee RQ_NOW and RQ_LATER are not set */
rq_state &= ~RQ_RUNNING;
spin_unlock(&config_list_lock);
*/
static void mgc_requeue_add(struct config_llog_data *cld)
{
+ bool wakeup = false;
+
CDEBUG(D_INFO, "log %s: requeue (r=%d sp=%d st=%x)\n",
cld->cld_logname, atomic_read(&cld->cld_refcount),
cld->cld_stopping, rq_state);
LASSERT(atomic_read(&cld->cld_refcount) > 0);
mutex_lock(&cld->cld_lock);
- if (cld->cld_stopping || cld->cld_lostlock) {
- mutex_unlock(&cld->cld_lock);
- return;
- }
- /* this refcount will be released in mgc_requeue_thread. */
- config_log_get(cld);
- cld->cld_lostlock = 1;
- mutex_unlock(&cld->cld_lock);
-
- /* Hold lock for rq_state */
spin_lock(&config_list_lock);
- if (rq_state & RQ_STOP) {
- spin_unlock(&config_list_lock);
- cld->cld_lostlock = 0;
- config_log_put(cld);
- } else {
+ if (!(rq_state & RQ_STOP) && !cld->cld_stopping && !cld->cld_lostlock) {
+ cld->cld_lostlock = 1;
rq_state |= RQ_NOW;
- spin_unlock(&config_list_lock);
- wake_up(&rq_waitq);
+ wakeup = true;
}
+ spin_unlock(&config_list_lock);
+ mutex_unlock(&cld->cld_lock);
+ if (wakeup)
+ wake_up(&rq_waitq);
}
static int mgc_llog_init(const struct lu_env *env, struct obd_device *obd)
/* held at mgc_process_log(). */
LASSERT(atomic_read(&cld->cld_refcount) > 0);
+
+ lock->l_ast_data = NULL;
/* Are we done with this log? */
if (cld->cld_stopping) {
CDEBUG(D_MGC, "log %s: stopping, won't requeue\n",
goto restart;
} else {
mutex_lock(&cld->cld_lock);
+ spin_lock(&config_list_lock);
cld->cld_lostlock = 1;
+ spin_unlock(&config_list_lock);
}
} else {
/* mark cld_lostlock so that it will requeue
* after MGC becomes available.
*/
+ spin_lock(&config_list_lock);
cld->cld_lostlock = 1;
+ spin_unlock(&config_list_lock);
}
- /* Get extra reference, it will be put in requeue thread */
- config_log_get(cld);
}
if (cld_is_recover(cld)) {
CERROR("%s: recover log %s failed: rc = %d not fatal.\n",
mgc->obd_name, cld->cld_logname, rc);
rc = 0;
+ spin_lock(&config_list_lock);
cld->cld_lostlock = 1;
+ spin_unlock(&config_list_lock);
}
}
} else {
cfg->cfg_last_idx);
/* We're only called through here on the initial mount */
- rc = config_log_add(obd, logname, cfg, sb);
- if (rc)
- break;
- cld = config_log_find(logname, cfg);
- if (!cld) {
- rc = -ENOENT;
+ cld = config_log_add(obd, logname, cfg, sb);
+ if (IS_ERR(cld)) {
+ rc = PTR_ERR(cld);
break;
}
imp_connect_data, IMP_RECOV)) {
rc = mgc_process_log(obd, cld->cld_recover);
} else {
- struct config_llog_data *cir = cld->cld_recover;
+ struct config_llog_data *cir;
+ mutex_lock(&cld->cld_lock);
+ cir = cld->cld_recover;
cld->cld_recover = NULL;
+ mutex_unlock(&cld->cld_lock);
config_log_put(cir);
}
+
if (rc)
CERROR("Cannot process recover llog %d\n", rc);
}
"%s: can't process params llog: rc = %d\n",
obd->obd_name, rc);
}
- config_log_put(cld);
break;
}
LASSERT(atomic_read(&anchor->csi_sync_nr) == 0);
/* wait until cl_sync_io_note() has done wakeup */
- while (unlikely(atomic_read(&anchor->csi_barrier) != 0)) {
+ while (unlikely(atomic_read(&anchor->csi_barrier) != 0))
cpu_relax();
- }
+
return rc;
}
#include <linux/list.h>
#include "../../include/linux/libcfs/libcfs_hash.h" /* for cfs_hash stuff */
#include "../include/cl_object.h"
+#include "../include/lu_object.h"
#include "cl_internal.h"
static struct kmem_cache *cl_env_kmem;
/** Lock class of cl_object_header::coh_attr_guard */
static struct lock_class_key cl_attr_guard_class;
-extern __u32 lu_context_tags_default;
-extern __u32 lu_session_tags_default;
/**
* Initialize cl_object_header.
*/
LU_CACHE_PERCENT_DEFAULT = 20
};
-#define LU_CACHE_NR_MAX_ADJUST 128
+#define LU_CACHE_NR_MAX_ADJUST 512
#define LU_CACHE_NR_UNLIMITED -1
#define LU_CACHE_NR_DEFAULT LU_CACHE_NR_UNLIMITED
#define LU_CACHE_NR_LDISKFS_LIMIT LU_CACHE_NR_UNLIMITED
LASSERT(list_empty(&top->loh_lru));
list_add_tail(&top->loh_lru, &bkt->lsb_lru);
bkt->lsb_lru_len++;
- lprocfs_counter_incr(site->ls_stats, LU_SS_LRU_LEN);
+ percpu_counter_inc(&site->ls_lru_len_counter);
CDEBUG(D_INODE, "Add %p to site lru. hash: %p, bkt: %p, lru_len: %ld\n",
o, site->ls_obj_hash, bkt, bkt->lsb_lru_len);
cfs_hash_bd_unlock(site->ls_obj_hash, &bd, 1);
list_del_init(&top->loh_lru);
bkt = cfs_hash_bd_extra_get(obj_hash, &bd);
bkt->lsb_lru_len--;
- lprocfs_counter_decr(site->ls_stats, LU_SS_LRU_LEN);
+ percpu_counter_dec(&site->ls_lru_len_counter);
}
cfs_hash_bd_del_locked(obj_hash, &bd, &top->loh_hash);
cfs_hash_bd_unlock(obj_hash, &bd, 1);
/**
* Free \a nr objects from the cold end of the site LRU list.
+ * if canblock is false, then don't block awaiting for another
+ * instance of lu_site_purge() to complete
*/
-int lu_site_purge(const struct lu_env *env, struct lu_site *s, int nr)
+int lu_site_purge_objects(const struct lu_env *env, struct lu_site *s,
+ int nr, bool canblock)
{
struct lu_object_header *h;
struct lu_object_header *temp;
* It doesn't make any sense to make purge threads parallel, that can
* only bring troubles to us. See LU-5331.
*/
- mutex_lock(&s->ls_purge_mutex);
+ if (canblock)
+ mutex_lock(&s->ls_purge_mutex);
+ else if (!mutex_trylock(&s->ls_purge_mutex))
+ goto out;
+
did_sth = 0;
cfs_hash_for_each_bucket(s->ls_obj_hash, &bd, i) {
if (i < start)
&bd2, &h->loh_hash);
list_move(&h->loh_lru, &dispose);
bkt->lsb_lru_len--;
- lprocfs_counter_decr(s->ls_stats, LU_SS_LRU_LEN);
+ percpu_counter_dec(&s->ls_lru_len_counter);
if (did_sth == 0)
did_sth = 1;
}
/* race on s->ls_purge_start, but nobody cares */
s->ls_purge_start = i % CFS_HASH_NBKT(s->ls_obj_hash);
-
+out:
return nr;
}
-EXPORT_SYMBOL(lu_site_purge);
+EXPORT_SYMBOL(lu_site_purge_objects);
/*
* Object printing.
if (!list_empty(&h->loh_lru)) {
list_del_init(&h->loh_lru);
bkt->lsb_lru_len--;
- lprocfs_counter_decr(s->ls_stats, LU_SS_LRU_LEN);
+ percpu_counter_dec(&s->ls_lru_len_counter);
}
return lu_object_top(h);
}
size = cfs_hash_size_get(dev->ld_site->ls_obj_hash);
nr = (__u64)lu_cache_nr;
- if (size > nr)
- lu_site_purge(env, dev->ld_site,
- min_t(__u64, size - nr, LU_CACHE_NR_MAX_ADJUST));
+ if (size <= nr)
+ return;
+
+ lu_site_purge_objects(env, dev->ld_site,
+ min_t(__u64, size - nr, LU_CACHE_NR_MAX_ADJUST),
+ false);
}
static struct lu_object *lu_object_new(const struct lu_env *env,
* Global list of all sites on this node
*/
static LIST_HEAD(lu_sites);
-static DEFINE_MUTEX(lu_sites_guard);
+static DECLARE_RWSEM(lu_sites_guard);
/**
* Global environment used by site shrinker.
unsigned long bits;
unsigned long i;
char name[16];
+ int rc;
memset(s, 0, sizeof(*s));
mutex_init(&s->ls_purge_mutex);
+
+ rc = percpu_counter_init(&s->ls_lru_len_counter, 0, GFP_NOFS);
+ if (rc)
+ return -ENOMEM;
+
snprintf(name, sizeof(name), "lu_site_%s", top->ld_type->ldt_name);
for (bits = lu_htable_order(top); bits >= LU_SITE_BITS_MIN; bits--) {
s->ls_obj_hash = cfs_hash_create(name, bits, bits,
0, "cache_death_race", "cache_death_race");
lprocfs_counter_init(s->ls_stats, LU_SS_LRU_PURGED,
0, "lru_purged", "lru_purged");
- /*
- * Unlike other counters, lru_len can be decremented so
- * need lc_sum instead of just lc_count
- */
- lprocfs_counter_init(s->ls_stats, LU_SS_LRU_LEN,
- LPROCFS_CNTR_AVGMINMAX, "lru_len", "lru_len");
INIT_LIST_HEAD(&s->ls_linkage);
s->ls_top_dev = top;
*/
void lu_site_fini(struct lu_site *s)
{
- mutex_lock(&lu_sites_guard);
+ down_write(&lu_sites_guard);
list_del_init(&s->ls_linkage);
- mutex_unlock(&lu_sites_guard);
+ up_write(&lu_sites_guard);
+
+ percpu_counter_destroy(&s->ls_lru_len_counter);
if (s->ls_obj_hash) {
cfs_hash_putref(s->ls_obj_hash);
{
int result;
- mutex_lock(&lu_sites_guard);
+ down_write(&lu_sites_guard);
result = lu_context_refill(&lu_shrink_env.le_ctx);
if (result == 0)
list_add(&s->ls_linkage, &lu_sites);
- mutex_unlock(&lu_sites_guard);
+ up_write(&lu_sites_guard);
return result;
}
EXPORT_SYMBOL(lu_site_init_finish);
}
/*
- * lu_cache_shrink_count returns the number of cached objects that are
- * candidates to be freed by shrink_slab(). A counter, which tracks
- * the number of items in the site's lru, is maintained in the per cpu
- * stats of each site. The counter is incremented when an object is added
- * to a site's lru and decremented when one is removed. The number of
- * free-able objects is the sum of all per cpu counters for all sites.
+ * lu_cache_shrink_count() returns an approximate number of cached objects
+ * that can be freed by shrink_slab(). A counter, which tracks the
+ * number of items in the site's lru, is maintained in a percpu_counter
+ * for each site. The percpu values are incremented and decremented as
+ * objects are added or removed from the lru. The percpu values are summed
+ * and saved whenever a percpu value exceeds a threshold. Thus the saved,
+ * summed value at any given time may not accurately reflect the current
+ * lru length. But this value is sufficiently accurate for the needs of
+ * a shrinker.
*
* Using a per cpu counter is a compromise solution to concurrent access:
* lu_object_put() can update the counter without locking the site and
if (!(sc->gfp_mask & __GFP_FS))
return 0;
- mutex_lock(&lu_sites_guard);
- list_for_each_entry_safe(s, tmp, &lu_sites, ls_linkage) {
- cached += ls_stats_read(s->ls_stats, LU_SS_LRU_LEN);
- }
- mutex_unlock(&lu_sites_guard);
+ down_read(&lu_sites_guard);
+ list_for_each_entry_safe(s, tmp, &lu_sites, ls_linkage)
+ cached += percpu_counter_read_positive(&s->ls_lru_len_counter);
+ up_read(&lu_sites_guard);
cached = (cached / 100) * sysctl_vfs_cache_pressure;
CDEBUG(D_INODE, "%ld objects cached, cache pressure %d\n",
*/
return SHRINK_STOP;
- mutex_lock(&lu_sites_guard);
+ down_write(&lu_sites_guard);
list_for_each_entry_safe(s, tmp, &lu_sites, ls_linkage) {
freed = lu_site_purge(&lu_shrink_env, s, remain);
remain -= freed;
list_move_tail(&s->ls_linkage, &splice);
}
list_splice(&splice, lu_sites.prev);
- mutex_unlock(&lu_sites_guard);
+ up_write(&lu_sites_guard);
return sc->nr_to_scan - remain;
}
* conservatively. This should not be too bad, because this
* environment is global.
*/
- mutex_lock(&lu_sites_guard);
+ down_write(&lu_sites_guard);
result = lu_env_init(&lu_shrink_env, LCT_SHRINKER);
- mutex_unlock(&lu_sites_guard);
+ up_write(&lu_sites_guard);
if (result != 0)
return result;
* Tear shrinker environment down _after_ de-registering
* lu_global_key, because the latter has a value in the former.
*/
- mutex_lock(&lu_sites_guard);
+ down_write(&lu_sites_guard);
lu_env_fini(&lu_shrink_env);
- mutex_unlock(&lu_sites_guard);
+ up_write(&lu_sites_guard);
lu_ref_global_fini();
}
struct lprocfs_counter ret;
lprocfs_stats_collect(stats, idx, &ret);
- if (idx == LU_SS_LRU_LEN)
- /*
- * protect against counter on cpu A being decremented
- * before counter is incremented on cpu B; unlikely
- */
- return (__u32)((ret.lc_sum > 0) ? ret.lc_sum : 0);
-
return (__u32)ret.lc_count;
}
memset(&stats, 0, sizeof(stats));
lu_site_stats_get(s->ls_obj_hash, &stats, 1);
- seq_printf(m, "%d/%d %d/%ld %d %d %d %d %d %d %d %d\n",
+ seq_printf(m, "%d/%d %d/%ld %d %d %d %d %d %d %d\n",
stats.lss_busy,
stats.lss_total,
stats.lss_populated,
ls_stats_read(s->ls_stats, LU_SS_CACHE_MISS),
ls_stats_read(s->ls_stats, LU_SS_CACHE_RACE),
ls_stats_read(s->ls_stats, LU_SS_CACHE_DEATH_RACE),
- ls_stats_read(s->ls_stats, LU_SS_LRU_PURGED),
- ls_stats_read(s->ls_stats, LU_SS_LRU_LEN));
+ ls_stats_read(s->ls_stats, LU_SS_LRU_PURGED));
return 0;
}
EXPORT_SYMBOL(lu_site_stats_print);
*/
static int lmd_parse(char *options, struct lustre_mount_data *lmd)
{
- char *s1, *s2, *s3, *devname = NULL;
+ char *s1, *s2, *devname = NULL;
struct lustre_mount_data *raw = (struct lustre_mount_data *)options;
int rc = 0;
while (*s1) {
int clear = 0;
int time_min = OBD_RECOVERY_TIME_MIN;
+ char *s3;
/* Skip whitespace and extra commas */
while (*s1 == ' ' || *s1 == ',')
#include "../include/obd_class.h"
#include "../include/lustre/lustre_idl.h"
+#include "../include/lustre_obdo.h"
void obdo_set_parent_fid(struct obdo *dst, const struct lu_fid *parent)
{
ioobj->ioo_max_brw = 0;
}
EXPORT_SYMBOL(obdo_to_ioobj);
+
+/**
+ * Create an obdo to send over the wire
+ */
+void lustre_set_wire_obdo(const struct obd_connect_data *ocd,
+ struct obdo *wobdo, const struct obdo *lobdo)
+{
+ *wobdo = *lobdo;
+ wobdo->o_flags &= ~OBD_FL_LOCAL_MASK;
+ if (!ocd)
+ return;
+
+ if (unlikely(!(ocd->ocd_connect_flags & OBD_CONNECT_FID)) &&
+ fid_seq_is_echo(ostid_seq(&lobdo->o_oi))) {
+ /*
+ * Currently OBD_FL_OSTID will only be used when 2.4 echo
+ * client communicate with pre-2.4 server
+ */
+ wobdo->o_oi.oi.oi_id = fid_oid(&lobdo->o_oi.oi_fid);
+ wobdo->o_oi.oi.oi_seq = fid_seq(&lobdo->o_oi.oi_fid);
+ }
+}
+EXPORT_SYMBOL(lustre_set_wire_obdo);
+
+/**
+ * Create a local obdo from a wire based odbo
+ */
+void lustre_get_wire_obdo(const struct obd_connect_data *ocd,
+ struct obdo *lobdo, const struct obdo *wobdo)
+{
+ u32 local_flags = 0;
+
+ if (lobdo->o_valid & OBD_MD_FLFLAGS)
+ local_flags = lobdo->o_flags & OBD_FL_LOCAL_MASK;
+
+ *lobdo = *wobdo;
+ if (local_flags) {
+ lobdo->o_valid |= OBD_MD_FLFLAGS;
+ lobdo->o_flags &= ~OBD_FL_LOCAL_MASK;
+ lobdo->o_flags |= local_flags;
+ }
+ if (!ocd)
+ return;
+
+ if (unlikely(!(ocd->ocd_connect_flags & OBD_CONNECT_FID)) &&
+ fid_seq_is_echo(wobdo->o_oi.oi.oi_seq)) {
+ /* see above */
+ lobdo->o_oi.oi_fid.f_seq = wobdo->o_oi.oi.oi_seq;
+ lobdo->o_oi.oi_fid.f_oid = wobdo->o_oi.oi.oi_id;
+ lobdo->o_oi.oi_fid.f_ver = 0;
+ }
+}
+EXPORT_SYMBOL(lustre_get_wire_obdo);
static inline struct osc_extent *rb_extent(struct rb_node *n)
{
- if (!n)
- return NULL;
-
- return container_of(n, struct osc_extent, oe_node);
+ return rb_entry_safe(n, struct osc_extent, oe_node);
}
static inline struct osc_extent *next_extent(struct osc_extent *ext)
goto out;
}
- if (ext->oe_dlmlock) {
+ if (ext->oe_dlmlock && !ldlm_is_failed(ext->oe_dlmlock)) {
struct ldlm_extent *extent;
extent = &ext->oe_dlmlock->l_policy_data.l_extent;
env = cl_env_get(&refcheck);
io = &osc_env_info(env)->oti_io;
io->ci_obj = cl_object_top(osc2cl(obj));
+ io->ci_ignore_layout = 1;
rc = cl_io_init(env, io, CIT_MISC, io->ci_obj);
if (rc < 0)
goto out;
oap, osc, rc);
}
+struct extent_rpc_data {
+ struct list_head *erd_rpc_list;
+ unsigned int erd_page_count;
+ unsigned int erd_max_pages;
+ unsigned int erd_max_chunks;
+};
+
+static inline unsigned osc_extent_chunks(const struct osc_extent *ext)
+{
+ struct client_obd *cli = osc_cli(ext->oe_obj);
+ unsigned ppc_bits = cli->cl_chunkbits - PAGE_SHIFT;
+
+ return (ext->oe_end >> ppc_bits) - (ext->oe_start >> ppc_bits) + 1;
+}
+
/**
* Try to add extent to one RPC. We need to think about the following things:
* - # of pages must not be over max_pages_per_rpc
* - extent must be compatible with previous ones
*/
static int try_to_add_extent_for_io(struct client_obd *cli,
- struct osc_extent *ext, struct list_head *rpclist,
- unsigned int *pc, unsigned int *max_pages)
+ struct osc_extent *ext,
+ struct extent_rpc_data *data)
{
struct osc_extent *tmp;
+ unsigned int chunk_count;
struct osc_async_page *oap = list_first_entry(&ext->oe_pages,
struct osc_async_page,
oap_pending_item);
EASSERT((ext->oe_state == OES_CACHE || ext->oe_state == OES_LOCK_DONE),
ext);
- *max_pages = max(ext->oe_mppr, *max_pages);
- if (*pc + ext->oe_nr_pages > *max_pages)
+ chunk_count = osc_extent_chunks(ext);
+ if (chunk_count > data->erd_max_chunks)
+ return 0;
+
+ data->erd_max_pages = max(ext->oe_mppr, data->erd_max_pages);
+ if (data->erd_page_count + ext->oe_nr_pages > data->erd_max_pages)
return 0;
- list_for_each_entry(tmp, rpclist, oe_link) {
+ list_for_each_entry(tmp, data->erd_rpc_list, oe_link) {
struct osc_async_page *oap2;
oap2 = list_first_entry(&tmp->oe_pages, struct osc_async_page,
oap_pending_item);
EASSERT(tmp->oe_owner == current, tmp);
if (oap2cl_page(oap)->cp_type != oap2cl_page(oap2)->cp_type) {
- CDEBUG(D_CACHE, "Do not permit different type of IO"
- " for a same RPC\n");
+ CDEBUG(D_CACHE, "Do not permit different type of IO in one RPC\n");
return 0;
}
break;
}
- *pc += ext->oe_nr_pages;
- list_move_tail(&ext->oe_link, rpclist);
+ data->erd_max_chunks -= chunk_count;
+ data->erd_page_count += ext->oe_nr_pages;
+ list_move_tail(&ext->oe_link, data->erd_rpc_list);
ext->oe_owner = current;
return 1;
}
+static inline unsigned osc_max_write_chunks(const struct client_obd *cli)
+{
+ /*
+ * LU-8135:
+ *
+ * The maximum size of a single transaction is about 64MB in ZFS.
+ * #define DMU_MAX_ACCESS (64 * 1024 * 1024)
+ *
+ * Since ZFS is a copy-on-write file system, a single dirty page in
+ * a chunk will result in the rewrite of the whole chunk, therefore
+ * an RPC shouldn't be allowed to contain too many chunks otherwise
+ * it will make transaction size much bigger than 64MB, especially
+ * with big block size for ZFS.
+ *
+ * This piece of code is to make sure that OSC won't send write RPCs
+ * with too many chunks. The maximum chunk size that an RPC can cover
+ * is set to PTLRPC_MAX_BRW_SIZE, which is defined to 16MB. Ideally
+ * OST should tell the client what the biggest transaction size is,
+ * but it's good enough for now.
+ *
+ * This limitation doesn't apply to ldiskfs, which allows as many
+ * chunks in one RPC as we want. However, it won't have any benefits
+ * to have too many discontiguous pages in one RPC. Therefore, it
+ * can only have 256 chunks at most in one RPC.
+ */
+ return min(PTLRPC_MAX_BRW_SIZE >> cli->cl_chunkbits, 256);
+}
+
/**
* In order to prevent multiple ptlrpcd from breaking contiguous extents,
* get_write_extent() takes all appropriate extents in atomic.
struct client_obd *cli = osc_cli(obj);
struct osc_extent *ext;
struct osc_extent *temp;
- unsigned int page_count = 0;
- unsigned int max_pages = cli->cl_max_pages_per_rpc;
+ struct extent_rpc_data data = {
+ .erd_rpc_list = rpclist,
+ .erd_page_count = 0,
+ .erd_max_pages = cli->cl_max_pages_per_rpc,
+ .erd_max_chunks = osc_max_write_chunks(cli),
+ };
LASSERT(osc_object_is_locked(obj));
list_for_each_entry_safe(ext, temp, &obj->oo_hp_exts, oe_link) {
LASSERT(ext->oe_state == OES_CACHE);
- if (!try_to_add_extent_for_io(cli, ext, rpclist, &page_count,
- &max_pages))
- return page_count;
- EASSERT(ext->oe_nr_pages <= max_pages, ext);
+ if (!try_to_add_extent_for_io(cli, ext, &data))
+ return data.erd_page_count;
+ EASSERT(ext->oe_nr_pages <= data.erd_max_pages, ext);
}
- if (page_count == max_pages)
- return page_count;
+ if (data.erd_page_count == data.erd_max_pages)
+ return data.erd_page_count;
while (!list_empty(&obj->oo_urgent_exts)) {
ext = list_entry(obj->oo_urgent_exts.next,
struct osc_extent, oe_link);
- if (!try_to_add_extent_for_io(cli, ext, rpclist, &page_count,
- &max_pages))
- return page_count;
+ if (!try_to_add_extent_for_io(cli, ext, &data))
+ return data.erd_page_count;
if (!ext->oe_intree)
continue;
ext->oe_owner))
continue;
- if (!try_to_add_extent_for_io(cli, ext, rpclist,
- &page_count, &max_pages))
- return page_count;
+ if (!try_to_add_extent_for_io(cli, ext, &data))
+ return data.erd_page_count;
}
}
- if (page_count == max_pages)
- return page_count;
+ if (data.erd_page_count == data.erd_max_pages)
+ return data.erd_page_count;
ext = first_extent(obj);
while (ext) {
continue;
}
- if (!try_to_add_extent_for_io(cli, ext, rpclist, &page_count,
- &max_pages))
- return page_count;
+ if (!try_to_add_extent_for_io(cli, ext, &data))
+ return data.erd_page_count;
ext = next_extent(ext);
}
- return page_count;
+ return data.erd_page_count;
}
static int
struct osc_extent *ext;
struct osc_extent *next;
LIST_HEAD(rpclist);
- unsigned int page_count = 0;
- unsigned int max_pages = cli->cl_max_pages_per_rpc;
+ struct extent_rpc_data data = {
+ .erd_rpc_list = &rpclist,
+ .erd_page_count = 0,
+ .erd_max_pages = cli->cl_max_pages_per_rpc,
+ .erd_max_chunks = UINT_MAX,
+ };
int rc = 0;
LASSERT(osc_object_is_locked(osc));
list_for_each_entry_safe(ext, next, &osc->oo_reading_exts, oe_link) {
EASSERT(ext->oe_state == OES_LOCK_DONE, ext);
- if (!try_to_add_extent_for_io(cli, ext, &rpclist, &page_count,
- &max_pages))
+ if (!try_to_add_extent_for_io(cli, ext, &data))
break;
osc_extent_state_set(ext, OES_RPC);
- EASSERT(ext->oe_nr_pages <= max_pages, ext);
+ EASSERT(ext->oe_nr_pages <= data.erd_max_pages, ext);
}
- LASSERT(page_count <= max_pages);
+ LASSERT(data.erd_page_count <= data.erd_max_pages);
- osc_update_pending(osc, OBD_BRW_READ, -page_count);
+ osc_update_pending(osc, OBD_BRW_READ, -data.erd_page_count);
if (!list_empty(&rpclist)) {
osc_object_unlock(osc);
- LASSERT(page_count > 0);
rc = osc_build_rpc(env, cli, &rpclist, OBD_BRW_READ);
LASSERT(list_empty(&rpclist));
/**
* Called by osc_io_setattr_start() to freeze and destroy covering extents.
*/
-int osc_cache_truncate_start(const struct lu_env *env, struct osc_io *oio,
- struct osc_object *obj, __u64 size)
+int osc_cache_truncate_start(const struct lu_env *env, struct osc_object *obj,
+ u64 size, struct osc_extent **extp)
{
struct client_obd *cli = osc_cli(obj);
struct osc_extent *ext;
/* we need to hold this extent in OES_TRUNC state so
* that no writeback will happen. This is to avoid
* BUG 17397.
+ * Only partial truncate can reach here, if @size is
+ * not zero, the caller should provide a valid @extp.
*/
- LASSERT(!oio->oi_trunc);
- oio->oi_trunc = osc_extent_get(ext);
+ LASSERT(!*extp);
+ *extp = osc_extent_get(ext);
OSC_EXTENT_DUMP(D_CACHE, ext,
"trunc at %llu\n", size);
}
/**
* Called after osc_io_setattr_end to add oio->oi_trunc back to cache.
*/
-void osc_cache_truncate_end(const struct lu_env *env, struct osc_io *oio,
- struct osc_object *obj)
+void osc_cache_truncate_end(const struct lu_env *env, struct osc_extent *ext)
{
- struct osc_extent *ext = oio->oi_trunc;
-
- oio->oi_trunc = NULL;
if (ext) {
+ struct osc_object *obj = ext->oe_obj;
bool unplug = false;
EASSERT(ext->oe_nr_pages > 0, ext);
/* page is top page. */
info->oti_next_index = osc_index(ops) + 1;
if (cl_page_own(env, io, page) == 0) {
- KLASSERT(ergo(page->cp_type == CPT_CACHEABLE,
- !PageDirty(cl_page_vmpage(page))));
+ if (page->cp_type == CPT_CACHEABLE &&
+ PageDirty(cl_page_vmpage(page)))
+ CL_PAGE_DEBUG(D_ERROR, env, page,
+ "discard dirty page?\n");
/* discard the page */
cl_page_discard(env, io, page);
/* Protect osc_lock this osc_object has */
spinlock_t oo_ol_spin;
struct list_head oo_ol_list;
+
+ /** number of active IOs of this object */
+ atomic_t oo_nr_ios;
+ wait_queue_head_t oo_io_waitq;
};
static inline void osc_object_lock(struct osc_object *obj)
struct osc_page *ops);
int osc_queue_sync_pages(const struct lu_env *env, struct osc_object *obj,
struct list_head *list, int cmd, int brw_flags);
-int osc_cache_truncate_start(const struct lu_env *env, struct osc_io *oio,
- struct osc_object *obj, __u64 size);
-void osc_cache_truncate_end(const struct lu_env *env, struct osc_io *oio,
- struct osc_object *obj);
+int osc_cache_truncate_start(const struct lu_env *env, struct osc_object *obj,
+ u64 size, struct osc_extent **extp);
+void osc_cache_truncate_end(const struct lu_env *env, struct osc_extent *ext);
int osc_cache_writeback_range(const struct lu_env *env, struct osc_object *obj,
pgoff_t start, pgoff_t end, int hp, int discard);
int osc_cache_wait_range(const struct lu_env *env, struct osc_object *obj,
struct ptlrpc_request_set *rqset, int async, int agl);
int osc_match_base(struct obd_export *exp, struct ldlm_res_id *res_id,
- __u32 type, union ldlm_policy_data *policy, __u32 mode,
- __u64 *flags, void *data, struct lustre_handle *lockh,
- int unref);
+ enum ldlm_type type, union ldlm_policy_data *policy,
+ enum ldlm_mode mode, __u64 *flags, void *data,
+ struct lustre_handle *lockh, int unref);
int osc_setattr_async(struct obd_export *exp, struct obdo *oa,
obd_enqueue_update_f upcall, void *cookie,
return container_of0(d->obd_lu_dev, struct osc_device, od_cl.cd_lu_dev);
}
+extern struct lu_kmem_descr osc_caches[];
+
extern struct kmem_cache *osc_quota_kmem;
struct osc_quota_info {
/** linkage for quota hash table */
struct osc_object *obj, pgoff_t index,
enum osc_dap_flags flags);
+int osc_object_invalidate(const struct lu_env *env, struct osc_object *osc);
+
+/** osc shrink list to link all osc client obd */
+extern struct list_head osc_shrink_list;
+/** spin lock to protect osc_shrink_list */
+extern spinlock_t osc_shrink_lock;
+unsigned long osc_cache_shrink_count(struct shrinker *sk,
+ struct shrink_control *sc);
+unsigned long osc_cache_shrink_scan(struct shrinker *sk,
+ struct shrink_control *sc);
+
#endif /* OSC_INTERNAL_H */
#define DEBUG_SUBSYSTEM S_OSC
+#include "../include/lustre_obdo.h"
+
#include "osc_cl_internal.h"
/** \addtogroup osc
ldlm_lock_decref(&lockh, dlmlock->l_req_mode);
}
+ ra->cra_rpc_size = osc_cli(osc)->cl_max_pages_per_rpc;
ra->cra_end = cl_index(osc2cl(osc),
dlmlock->l_policy_data.l_extent.end);
ra->cra_release = osc_read_ahead_release;
LASSERT(qin->pl_nr > 0);
- CDEBUG(D_CACHE, "%d %d\n", qin->pl_nr, crt);
+ CDEBUG(D_CACHE | D_READA, "%d %d\n", qin->pl_nr, crt);
osc = cl2osc(ios->cis_obj);
cli = osc_cli(osc);
if (queued > 0)
result = osc_queue_sync_pages(env, osc, &list, cmd, brw_flags);
+ /* Update c/mtime for sync write. LU-7310 */
+ if (qout->pl_nr > 0 && !result) {
+ struct cl_attr *attr = &osc_env_info(env)->oti_attr;
+ struct cl_object *obj = ios->cis_obj;
+
+ cl_object_attr_lock(obj);
+ attr->cat_mtime = LTIME_S(CURRENT_TIME);
+ attr->cat_ctime = attr->cat_mtime;
+ cl_object_attr_update(env, obj, attr, CAT_MTIME | CAT_CTIME);
+ cl_object_attr_unlock(obj);
+ }
+
CDEBUG(D_INFO, "%d/%d %d\n", qin->pl_nr, qout->pl_nr, result);
return qout->pl_nr > 0 ? 0 : result;
}
return result;
}
-static int osc_io_rw_iter_init(const struct lu_env *env,
- const struct cl_io_slice *ios)
+static int osc_io_iter_init(const struct lu_env *env,
+ const struct cl_io_slice *ios)
+{
+ struct osc_object *osc = cl2osc(ios->cis_obj);
+ struct obd_import *imp = osc_cli(osc)->cl_import;
+ int rc = -EIO;
+
+ spin_lock(&imp->imp_lock);
+ if (likely(!imp->imp_invalid)) {
+ atomic_inc(&osc->oo_nr_ios);
+ rc = 0;
+ }
+ spin_unlock(&imp->imp_lock);
+
+ return rc;
+}
+
+static int osc_io_write_iter_init(const struct lu_env *env,
+ const struct cl_io_slice *ios)
{
struct cl_io *io = ios->cis_io;
struct osc_io *oio = osc_env_io(env);
unsigned long max_pages;
if (cl_io_is_append(io))
- return 0;
+ return osc_io_iter_init(env, ios);
npages = io->u.ci_rw.crw_count >> PAGE_SHIFT;
if (io->u.ci_rw.crw_pos & ~PAGE_MASK)
(void)ptlrpcd_queue_work(cli->cl_lru_work);
}
- return 0;
+ return osc_io_iter_init(env, ios);
}
-static void osc_io_rw_iter_fini(const struct lu_env *env,
- const struct cl_io_slice *ios)
+static void osc_io_iter_fini(const struct lu_env *env,
+ const struct cl_io_slice *ios)
+{
+ struct osc_object *osc = cl2osc(ios->cis_obj);
+
+ LASSERT(atomic_read(&osc->oo_nr_ios) > 0);
+ if (atomic_dec_and_test(&osc->oo_nr_ios))
+ wake_up_all(&osc->oo_io_waitq);
+}
+
+static void osc_io_write_iter_fini(const struct lu_env *env,
+ const struct cl_io_slice *ios)
{
struct osc_io *oio = osc_env_io(env);
struct osc_object *osc = cl2osc(ios->cis_obj);
oio->oi_lru_reserved = 0;
}
oio->oi_write_osclock = NULL;
+
+ osc_io_iter_fini(env, ios);
}
static int osc_io_fault_start(const struct lu_env *env,
/* truncate cache dirty pages first */
if (cl_io_is_trunc(io))
- result = osc_cache_truncate_start(env, oio, cl2osc(obj), size);
+ result = osc_cache_truncate_start(env, cl2osc(obj), size,
+ &oio->oi_trunc);
if (result == 0 && oio->oi_lockless == 0) {
cl_object_attr_lock(obj);
__u64 size = io->u.ci_setattr.sa_attr.lvb_size;
osc_trunc_check(env, io, oio, size);
- if (oio->oi_trunc) {
- osc_cache_truncate_end(env, oio, cl2osc(obj));
- oio->oi_trunc = NULL;
- }
+ osc_cache_truncate_end(env, oio->oi_trunc);
+ oio->oi_trunc = NULL;
}
}
ptlrpc_request_set_replen(req);
req->rq_interpret_reply = osc_data_version_interpret;
- CLASSERT(sizeof(*dva) <= sizeof(req->rq_async_args));
+ BUILD_BUG_ON(sizeof(*dva) > sizeof(req->rq_async_args));
dva = ptlrpc_req_async_args(req);
dva->dva_oio = oio;
static const struct cl_io_operations osc_io_ops = {
.op = {
[CIT_READ] = {
+ .cio_iter_init = osc_io_iter_init,
+ .cio_iter_fini = osc_io_iter_fini,
.cio_start = osc_io_read_start,
.cio_fini = osc_io_fini
},
[CIT_WRITE] = {
- .cio_iter_init = osc_io_rw_iter_init,
- .cio_iter_fini = osc_io_rw_iter_fini,
+ .cio_iter_init = osc_io_write_iter_init,
+ .cio_iter_fini = osc_io_write_iter_fini,
.cio_start = osc_io_write_start,
.cio_end = osc_io_end,
.cio_fini = osc_io_fini
},
[CIT_SETATTR] = {
+ .cio_iter_init = osc_io_iter_init,
+ .cio_iter_fini = osc_io_iter_fini,
.cio_start = osc_io_setattr_start,
.cio_end = osc_io_setattr_end
},
.cio_end = osc_io_data_version_end,
},
[CIT_FAULT] = {
+ .cio_iter_init = osc_io_iter_init,
+ .cio_iter_fini = osc_io_iter_fini,
.cio_start = osc_io_fault_start,
.cio_end = osc_io_end,
.cio_fini = osc_io_fini
INIT_LIST_HEAD(&osc->oo_write_item);
INIT_LIST_HEAD(&osc->oo_read_item);
+ atomic_set(&osc->oo_nr_ios, 0);
+ init_waitqueue_head(&osc->oo_io_waitq);
+
osc->oo_root.rb_node = NULL;
INIT_LIST_HEAD(&osc->oo_hp_exts);
INIT_LIST_HEAD(&osc->oo_urgent_exts);
LASSERT(atomic_read(&osc->oo_nr_reads) == 0);
LASSERT(atomic_read(&osc->oo_nr_writes) == 0);
LASSERT(list_empty(&osc->oo_ol_list));
+ LASSERT(!atomic_read(&osc->oo_nr_ios));
lu_object_fini(obj);
kmem_cache_free(osc_object_kmem, osc);
return obj;
}
+int osc_object_invalidate(const struct lu_env *env, struct osc_object *osc)
+{
+ struct l_wait_info lwi = { 0 };
+
+ CDEBUG(D_INODE, "Invalidate osc object: %p, # of active IOs: %d\n",
+ osc, atomic_read(&osc->oo_nr_ios));
+
+ l_wait_event(osc->oo_io_waitq, !atomic_read(&osc->oo_nr_ios), &lwi);
+
+ /* Discard all pages of this object. */
+ osc_cache_truncate_start(env, osc, 0, NULL);
+
+ return 0;
+}
+
/** @} osc */
return lru_shrink_min(cli);
} else {
time64_t duration = ktime_get_real_seconds();
+ long timediff;
/* knock out pages by duration of no IO activity */
duration -= cli->cl_lru_last_used;
- duration >>= 6; /* approximately 1 minute */
- if (duration > 0 &&
- pages >= div64_s64((s64)budget, duration))
+ /*
+ * The difference shouldn't be more than 70 years
+ * so we can safely case to a long. Round to
+ * approximately 1 minute.
+ */
+ timediff = (long)(duration >> 6);
+ if (timediff > 0 && pages >= budget / timediff)
return lru_shrink_min(cli);
}
return 0;
cli->cl_max_rpcs_in_flight;
}
+/**
+ * Return how many LRU pages in the cache of all OSC devices
+ *
+ * Return: return # of cached LRU pages times reclaimation tendency
+ * SHRINK_STOP if it cannot do any scanning in this time
+ */
+unsigned long osc_cache_shrink_count(struct shrinker *sk,
+ struct shrink_control *sc)
+{
+ struct client_obd *cli;
+ unsigned long cached = 0;
+
+ spin_lock(&osc_shrink_lock);
+ list_for_each_entry(cli, &osc_shrink_list, cl_shrink_list)
+ cached += atomic_long_read(&cli->cl_lru_in_list);
+ spin_unlock(&osc_shrink_lock);
+
+ return (cached * sysctl_vfs_cache_pressure) / 100;
+}
+
+/**
+ * Scan and try to reclaim sc->nr_to_scan cached LRU pages
+ *
+ * Return: number of cached LRU pages reclaimed
+ * SHRINK_STOP if it cannot do any scanning in this time
+ *
+ * Linux kernel will loop calling this shrinker scan routine with
+ * sc->nr_to_scan = SHRINK_BATCH(128 for now) until kernel got enough memory.
+ *
+ * If sc->nr_to_scan is 0, the VM is querying the cache size, we don't need
+ * to scan and try to reclaim LRU pages, just return 0 and
+ * osc_cache_shrink_count() will report the LRU page number.
+ */
+unsigned long osc_cache_shrink_scan(struct shrinker *sk,
+ struct shrink_control *sc)
+{
+ struct client_obd *stop_anchor = NULL;
+ struct client_obd *cli;
+ struct lu_env *env;
+ long shrank = 0;
+ int refcheck;
+ int rc;
+
+ if (!sc->nr_to_scan)
+ return 0;
+
+ if (!(sc->gfp_mask & __GFP_FS))
+ return SHRINK_STOP;
+
+ env = cl_env_get(&refcheck);
+ if (IS_ERR(env))
+ return SHRINK_STOP;
+
+ spin_lock(&osc_shrink_lock);
+ while (!list_empty(&osc_shrink_list)) {
+ cli = list_entry(osc_shrink_list.next, struct client_obd,
+ cl_shrink_list);
+
+ if (!stop_anchor)
+ stop_anchor = cli;
+ else if (cli == stop_anchor)
+ break;
+
+ list_move_tail(&cli->cl_shrink_list, &osc_shrink_list);
+ spin_unlock(&osc_shrink_lock);
+
+ /* shrink no more than max_pages_per_rpc for an OSC */
+ rc = osc_lru_shrink(env, cli, (sc->nr_to_scan - shrank) >
+ cli->cl_max_pages_per_rpc ?
+ cli->cl_max_pages_per_rpc :
+ sc->nr_to_scan - shrank, true);
+ if (rc > 0)
+ shrank += rc;
+
+ if (shrank >= sc->nr_to_scan)
+ goto out;
+
+ spin_lock(&osc_shrink_lock);
+ }
+ spin_unlock(&osc_shrink_lock);
+
+out:
+ cl_env_put(env, &refcheck);
+
+ return shrank;
+}
+
/** @} osc */
#include "../include/lprocfs_status.h"
#include "../include/lustre/lustre_ioctl.h"
#include "../include/lustre_debug.h"
+#include "../include/lustre_obdo.h"
#include "../include/lustre_param.h"
#include "../include/lustre_fid.h"
#include "../include/obd_class.h"
req->rq_interpret_reply =
(ptlrpc_interpterer_t)osc_setattr_interpret;
- CLASSERT(sizeof(*sa) <= sizeof(req->rq_async_args));
+ BUILD_BUG_ON(sizeof(*sa) > sizeof(req->rq_async_args));
sa = ptlrpc_req_async_args(req);
sa->sa_oa = oa;
sa->sa_upcall = upcall;
ptlrpc_request_set_replen(req);
req->rq_interpret_reply = (ptlrpc_interpterer_t)osc_setattr_interpret;
- CLASSERT(sizeof(*sa) <= sizeof(req->rq_async_args));
+ BUILD_BUG_ON(sizeof(*sa) > sizeof(req->rq_async_args));
sa = ptlrpc_req_async_args(req);
sa->sa_oa = oa;
sa->sa_upcall = upcall;
ptlrpc_request_set_replen(req);
req->rq_interpret_reply = osc_sync_interpret;
- CLASSERT(sizeof(*fa) <= sizeof(req->rq_async_args));
+ BUILD_BUG_ON(sizeof(*fa) > sizeof(req->rq_async_args));
fa = ptlrpc_req_async_args(req);
fa->fa_obj = obj;
fa->fa_oa = oa;
}
ptlrpc_request_set_replen(req);
- CLASSERT(sizeof(*aa) <= sizeof(req->rq_async_args));
+ BUILD_BUG_ON(sizeof(*aa) > sizeof(req->rq_async_args));
aa = ptlrpc_req_async_args(req);
aa->aa_oa = oa;
aa->aa_requested_nob = requested_nob;
cl_req_attr_set(env, osc2cl(obj), crattr);
lustre_msg_set_jobid(req->rq_reqmsg, crattr->cra_jobid);
- CLASSERT(sizeof(*aa) <= sizeof(req->rq_async_args));
+ BUILD_BUG_ON(sizeof(*aa) > sizeof(req->rq_async_args));
aa = ptlrpc_req_async_args(req);
INIT_LIST_HEAD(&aa->aa_oaps);
list_splice_init(&rpc_list, &aa->aa_oaps);
if (!rc) {
struct osc_enqueue_args *aa;
- CLASSERT(sizeof(*aa) <= sizeof(req->rq_async_args));
+ BUILD_BUG_ON(sizeof(*aa) > sizeof(req->rq_async_args));
aa = ptlrpc_req_async_args(req);
aa->oa_exp = exp;
aa->oa_mode = einfo->ei_mode;
}
req->rq_interpret_reply = (ptlrpc_interpterer_t)osc_statfs_interpret;
- CLASSERT(sizeof(*aa) <= sizeof(req->rq_async_args));
+ BUILD_BUG_ON(sizeof(*aa) > sizeof(req->rq_async_args));
aa = ptlrpc_req_async_args(req);
aa->aa_oi = oinfo;
struct osc_brw_async_args *aa;
struct obdo *oa;
- CLASSERT(sizeof(*aa) <= sizeof(req->rq_async_args));
+ BUILD_BUG_ON(sizeof(*aa) > sizeof(req->rq_async_args));
aa = ptlrpc_req_async_args(req);
oa = kmem_cache_zalloc(obdo_cachep, GFP_NOFS);
if (!oa) {
return rc;
}
+static int osc_ldlm_resource_invalidate(struct cfs_hash *hs,
+ struct cfs_hash_bd *bd,
+ struct hlist_node *hnode, void *arg)
+{
+ struct ldlm_resource *res = cfs_hash_object(hs, hnode);
+ struct osc_object *osc = NULL;
+ struct lu_env *env = arg;
+ struct ldlm_lock *lock;
+
+ lock_res(res);
+ list_for_each_entry(lock, &res->lr_granted, l_res_link) {
+ if (lock->l_ast_data && !osc) {
+ osc = lock->l_ast_data;
+ cl_object_get(osc2cl(osc));
+ }
+ lock->l_ast_data = NULL;
+ }
+ unlock_res(res);
+
+ if (osc) {
+ osc_object_invalidate(env, osc);
+ cl_object_put(env, osc2cl(osc));
+ }
+
+ return 0;
+}
+
static int osc_import_event(struct obd_device *obd,
struct obd_import *imp,
enum obd_import_event event)
struct lu_env *env;
int refcheck;
+ ldlm_namespace_cleanup(ns, LDLM_FL_LOCAL_ONLY);
+
env = cl_env_get(&refcheck);
if (!IS_ERR(env)) {
- /* Reset grants */
- cli = &obd->u.cli;
- /* all pages go to failing rpcs due to the invalid
- * import
- */
- osc_io_unplug(env, cli, NULL);
+ osc_io_unplug(env, &obd->u.cli, NULL);
- ldlm_namespace_cleanup(ns, LDLM_FL_LOCAL_ONLY);
+ cfs_hash_for_each_nolock(ns->ns_rs_hash,
+ osc_ldlm_resource_invalidate,
+ env, 0);
cl_env_put(env, &refcheck);
+
+ ldlm_namespace_cleanup(ns, LDLM_FL_LOCAL_ONLY);
} else {
rc = PTR_ERR(env);
}
INIT_LIST_HEAD(&cli->cl_grant_shrink_list);
ns_register_cancel(obd->obd_namespace, osc_cancel_weight);
+
+ spin_lock(&osc_shrink_lock);
+ list_add_tail(&cli->cl_shrink_list, &osc_shrink_list);
+ spin_unlock(&osc_shrink_lock);
+
return rc;
out_ptlrpcd_work:
struct client_obd *cli = &obd->u.cli;
int rc;
+ spin_lock(&osc_shrink_lock);
+ list_del(&cli->cl_shrink_list);
+ spin_unlock(&osc_shrink_lock);
+
/* lru cleanup */
if (cli->cl_cache) {
LASSERT(atomic_read(&cli->cl_cache->ccc_users) > 0);
.quotactl = osc_quotactl,
};
-extern struct lu_kmem_descr osc_caches[];
+struct list_head osc_shrink_list = LIST_HEAD_INIT(osc_shrink_list);
+DEFINE_SPINLOCK(osc_shrink_lock);
+
+static struct shrinker osc_cache_shrinker = {
+ .count_objects = osc_cache_shrink_count,
+ .scan_objects = osc_cache_shrink_scan,
+ .seeks = DEFAULT_SEEKS,
+};
static int __init osc_init(void)
{
if (rc)
goto out_kmem;
+ register_shrinker(&osc_cache_shrinker);
+
/* This is obviously too much memory, only prevent overflow here */
if (osc_reqpool_mem_max >= 1 << 12 || osc_reqpool_mem_max == 0) {
rc = -EINVAL;
static void /*__exit*/ osc_exit(void)
{
+ unregister_shrinker(&osc_cache_shrinker);
class_unregister_type(LUSTRE_OSC_NAME);
lu_kmem_fini(osc_caches);
ptlrpc_free_rq_pool(osc_rq_pool);
if (atomic_read(&imp->imp_inval_count) != 0) {
DEBUG_REQ(D_ERROR, req, "invalidate in flight");
*status = -EIO;
- } else if (imp->imp_dlm_fake || req->rq_no_delay) {
+ } else if (req->rq_no_delay) {
*status = -EWOULDBLOCK;
} else if (req->rq_allow_replay &&
(imp->imp_state == LUSTRE_IMP_REPLAY ||
list_for_each_entry_safe(req, saved, &imp->imp_committed_list,
rq_replay_list) {
LASSERT(req->rq_transno != 0);
- if (req->rq_import_generation < imp->imp_generation) {
- DEBUG_REQ(D_RPCTRACE, req, "free stale open request");
- ptlrpc_free_request(req);
- } else if (!req->rq_replay) {
- DEBUG_REQ(D_RPCTRACE, req, "free closed open request");
+ if (req->rq_import_generation < imp->imp_generation ||
+ !req->rq_replay) {
+ DEBUG_REQ(D_RPCTRACE, req, "free %s open request",
+ req->rq_import_generation <
+ imp->imp_generation ? "stale" : "closed");
+
+ if (imp->imp_replay_cursor == &req->rq_replay_list)
+ imp->imp_replay_cursor =
+ req->rq_replay_list.next;
+
ptlrpc_free_request(req);
}
}
}
/* Always need to be aligned to a power-of-two for multi-bulk BRW */
- CLASSERT(((PTLRPC_BULK_OPS_COUNT - 1) & PTLRPC_BULK_OPS_COUNT) == 0);
+ BUILD_BUG_ON(((PTLRPC_BULK_OPS_COUNT - 1) & PTLRPC_BULK_OPS_COUNT) != 0);
ptlrpc_last_xid &= PTLRPC_BULK_OPS_MASK;
}
req->rq_mbits = ptlrpc_next_xid();
} else {
/* old version transfers rq_xid to peer as matchbits */
- req->rq_mbits = ptlrpc_next_xid();
- req->rq_xid = req->rq_mbits;
+ spin_lock(&req->rq_import->imp_lock);
+ list_del_init(&req->rq_unreplied_list);
+ ptlrpc_assign_next_xid_nolock(req);
+ req->rq_mbits = req->rq_xid;
+ spin_unlock(&req->rq_import->imp_lock);
}
CDEBUG(D_HA, "resend bulk old x%llu new x%llu\n",
req->rq_no_resend = 1;
req->rq_pill.rc_fmt = (void *)&worker_format;
- CLASSERT(sizeof(*args) <= sizeof(req->rq_async_args));
+ BUILD_BUG_ON(sizeof(*args) > sizeof(req->rq_async_args));
args = ptlrpc_req_async_args(req);
args->cb = cb;
args->cbdata = cbdata;
* then we hope there will be less RPCs per bucket at some
* point, and sequence will catch up again
*/
- svcpt->scp_hist_seq += (1U << REQS_SEQ_SHIFT(svcpt));
+ svcpt->scp_hist_seq += (1ULL << REQS_SEQ_SHIFT(svcpt));
new_seq = svcpt->scp_hist_seq;
}
rs->rs_on_net = 0;
if (!rs->rs_no_ack ||
rs->rs_transno <=
- rs->rs_export->exp_obd->obd_last_committed)
+ rs->rs_export->exp_obd->obd_last_committed ||
+ list_empty(&rs->rs_obd_list))
ptlrpc_schedule_difficult_reply(rs);
spin_unlock(&rs->rs_lock);
ptlrpc_request_set_replen(request);
request->rq_interpret_reply = ptlrpc_connect_interpret;
- CLASSERT(sizeof(*aa) <= sizeof(request->rq_async_args));
+ BUILD_BUG_ON(sizeof(*aa) > sizeof(request->rq_async_args));
aa = ptlrpc_req_async_args(request);
memset(aa, 0, sizeof(*aa));
* of the format that the request conforms to.
*/
-#if !defined(__REQ_LAYOUT_USER__)
-
#define DEBUG_SUBSYSTEM S_RPC
#include <linux/module.h>
#include "../include/obd.h"
#include "../include/obd_support.h"
-/* __REQ_LAYOUT_USER__ */
-#endif
/* struct ptlrpc_request, lustre_msg* */
#include "../include/lustre_req_layout.h"
#include "../include/lustre_acl.h"
DEFINE_REQ_FMT0("FLD_QUERY", fld_query_client, fld_query_server);
EXPORT_SYMBOL(RQF_FLD_QUERY);
+/*
+ * The 'fld_read_server' uses 'RMF_GENERIC_DATA' to hold the 'FLD_QUERY'
+ * RPC reply that is composed of 'struct lu_seq_range_array'. But there
+ * is not registered swabber function for 'RMF_GENERIC_DATA'. So the RPC
+ * peers need to handle the RPC reply with fixed little-endian format.
+ *
+ * In theory, we can define new structure with some swabber registered to
+ * handle the 'FLD_QUERY' RPC reply result automatically. But from the
+ * implementation view, it is not easy to be done within current "struct
+ * req_msg_field" framework. Because the sequence range array in the RPC
+ * reply is not fixed length, instead, its length depends on 'lu_seq_range'
+ * count, that is unknown when prepare the RPC buffer. Generally, for such
+ * flexible length RPC usage, there will be a field in the RPC layout to
+ * indicate the data length. But for the 'FLD_READ' RPC, we have no way to
+ * do that unless we add new length filed that will broken the on-wire RPC
+ * protocol and cause interoperability trouble with old peer.
+ */
struct req_format RQF_FLD_READ =
DEFINE_REQ_FMT0("FLD_READ", fld_read_client, fld_read_server);
EXPORT_SYMBOL(RQF_FLD_READ);
ost_get_fiemap_server);
EXPORT_SYMBOL(RQF_OST_GET_INFO_FIEMAP);
-#if !defined(__REQ_LAYOUT_USER__)
-
/* Convenience macro */
#define FMT_FIELD(fmt, i, j) (fmt)->rf_fields[(i)].d[(j)]
1);
}
EXPORT_SYMBOL(req_capsule_shrink);
-
-/* __REQ_LAYOUT_USER__ */
-#endif
*/
spin_lock(&imp->imp_lock);
ptlrpc_assign_next_xid_nolock(request);
- request->rq_mbits = request->rq_xid;
min_xid = ptlrpc_known_replied_xid(imp);
spin_unlock(&imp->imp_lock);
lustre_msg_set_last_xid(request->rq_reqmsg, min_xid);
DEBUG_REQ(D_RPCTRACE, request, "Allocating new xid for resend on EINPROGRESS");
- } else if (request->rq_bulk) {
+ }
+
+ if (request->rq_bulk) {
ptlrpc_set_bulk_mbits(request);
lustre_msg_set_mbits(request->rq_reqmsg, request->rq_mbits);
}
return rc;
}
-/* ptlrpc/nrs_fifo.c */
-extern struct ptlrpc_nrs_pol_conf nrs_conf_fifo;
-
/**
* Adds all policies that ship with the ptlrpc module, to NRS core's list of
* policies \e nrs_core.nrs_policies.
default:
LASSERTF(0, "incorrect message magic: %08x\n", msg->lm_magic);
}
+ return 0;
}
EXPORT_SYMBOL(lustre_shrink_msg);
__swab32s(&m->lm_repsize);
__swab32s(&m->lm_cksum);
__swab32s(&m->lm_flags);
- CLASSERT(offsetof(typeof(*m), lm_padding_2) != 0);
- CLASSERT(offsetof(typeof(*m), lm_padding_3) != 0);
+ BUILD_BUG_ON(offsetof(typeof(*m), lm_padding_2) == 0);
+ BUILD_BUG_ON(offsetof(typeof(*m), lm_padding_3) == 0);
}
required_len = lustre_msg_hdr_size_v2(m->lm_bufcount);
__swab64s(&b->pb_pre_versions[2]);
__swab64s(&b->pb_pre_versions[3]);
__swab64s(&b->pb_mbits);
- CLASSERT(offsetof(typeof(*b), pb_padding0) != 0);
- CLASSERT(offsetof(typeof(*b), pb_padding1) != 0);
- CLASSERT(offsetof(typeof(*b), pb_padding64_0) != 0);
- CLASSERT(offsetof(typeof(*b), pb_padding64_1) != 0);
- CLASSERT(offsetof(typeof(*b), pb_padding64_2) != 0);
+ BUILD_BUG_ON(offsetof(typeof(*b), pb_padding0) == 0);
+ BUILD_BUG_ON(offsetof(typeof(*b), pb_padding1) == 0);
+ BUILD_BUG_ON(offsetof(typeof(*b), pb_padding64_0) == 0);
+ BUILD_BUG_ON(offsetof(typeof(*b), pb_padding64_1) == 0);
+ BUILD_BUG_ON(offsetof(typeof(*b), pb_padding64_2) == 0);
/* While we need to maintain compatibility between
* clients and servers without ptlrpc_body_v2 (< 2.3)
* do not swab any fields beyond pb_jobid, as we are
* using this swab function for both ptlrpc_body
* and ptlrpc_body_v2.
*/
- CLASSERT(offsetof(typeof(*b), pb_jobid) != 0);
+ BUILD_BUG_ON(offsetof(typeof(*b), pb_jobid) == 0);
}
void lustre_swab_connect(struct obd_connect_data *ocd)
__swab64s(&ocd->ocd_maxbytes);
if (ocd->ocd_connect_flags & OBD_CONNECT_MULTIMODRPCS)
__swab16s(&ocd->ocd_maxmodrpcs);
- CLASSERT(offsetof(typeof(*ocd), padding0));
- CLASSERT(offsetof(typeof(*ocd), padding1) != 0);
+ BUILD_BUG_ON(!offsetof(typeof(*ocd), padding0));
+ BUILD_BUG_ON(offsetof(typeof(*ocd), padding1) == 0);
if (ocd->ocd_connect_flags & OBD_CONNECT_FLAGS2)
__swab64s(&ocd->ocd_connect_flags2);
- CLASSERT(offsetof(typeof(*ocd), padding3) != 0);
- CLASSERT(offsetof(typeof(*ocd), padding4) != 0);
- CLASSERT(offsetof(typeof(*ocd), padding5) != 0);
- CLASSERT(offsetof(typeof(*ocd), padding6) != 0);
- CLASSERT(offsetof(typeof(*ocd), padding7) != 0);
- CLASSERT(offsetof(typeof(*ocd), padding8) != 0);
- CLASSERT(offsetof(typeof(*ocd), padding9) != 0);
- CLASSERT(offsetof(typeof(*ocd), paddingA) != 0);
- CLASSERT(offsetof(typeof(*ocd), paddingB) != 0);
- CLASSERT(offsetof(typeof(*ocd), paddingC) != 0);
- CLASSERT(offsetof(typeof(*ocd), paddingD) != 0);
- CLASSERT(offsetof(typeof(*ocd), paddingE) != 0);
- CLASSERT(offsetof(typeof(*ocd), paddingF) != 0);
+ BUILD_BUG_ON(offsetof(typeof(*ocd), padding3) == 0);
+ BUILD_BUG_ON(offsetof(typeof(*ocd), padding4) == 0);
+ BUILD_BUG_ON(offsetof(typeof(*ocd), padding5) == 0);
+ BUILD_BUG_ON(offsetof(typeof(*ocd), padding6) == 0);
+ BUILD_BUG_ON(offsetof(typeof(*ocd), padding7) == 0);
+ BUILD_BUG_ON(offsetof(typeof(*ocd), padding8) == 0);
+ BUILD_BUG_ON(offsetof(typeof(*ocd), padding9) == 0);
+ BUILD_BUG_ON(offsetof(typeof(*ocd), paddingA) == 0);
+ BUILD_BUG_ON(offsetof(typeof(*ocd), paddingB) == 0);
+ BUILD_BUG_ON(offsetof(typeof(*ocd), paddingC) == 0);
+ BUILD_BUG_ON(offsetof(typeof(*ocd), paddingD) == 0);
+ BUILD_BUG_ON(offsetof(typeof(*ocd), paddingE) == 0);
+ BUILD_BUG_ON(offsetof(typeof(*ocd), paddingF) == 0);
}
static void lustre_swab_obdo(struct obdo *o)
__swab32s(&o->o_uid_h);
__swab32s(&o->o_gid_h);
__swab64s(&o->o_data_version);
- CLASSERT(offsetof(typeof(*o), o_padding_4) != 0);
- CLASSERT(offsetof(typeof(*o), o_padding_5) != 0);
- CLASSERT(offsetof(typeof(*o), o_padding_6) != 0);
+ BUILD_BUG_ON(offsetof(typeof(*o), o_padding_4) == 0);
+ BUILD_BUG_ON(offsetof(typeof(*o), o_padding_5) == 0);
+ BUILD_BUG_ON(offsetof(typeof(*o), o_padding_6) == 0);
}
void lustre_swab_obd_statfs(struct obd_statfs *os)
__swab32s(&os->os_namelen);
__swab64s(&os->os_maxbytes);
__swab32s(&os->os_state);
- CLASSERT(offsetof(typeof(*os), os_fprecreated) != 0);
- CLASSERT(offsetof(typeof(*os), os_spare2) != 0);
- CLASSERT(offsetof(typeof(*os), os_spare3) != 0);
- CLASSERT(offsetof(typeof(*os), os_spare4) != 0);
- CLASSERT(offsetof(typeof(*os), os_spare5) != 0);
- CLASSERT(offsetof(typeof(*os), os_spare6) != 0);
- CLASSERT(offsetof(typeof(*os), os_spare7) != 0);
- CLASSERT(offsetof(typeof(*os), os_spare8) != 0);
- CLASSERT(offsetof(typeof(*os), os_spare9) != 0);
+ BUILD_BUG_ON(offsetof(typeof(*os), os_fprecreated) == 0);
+ BUILD_BUG_ON(offsetof(typeof(*os), os_spare2) == 0);
+ BUILD_BUG_ON(offsetof(typeof(*os), os_spare3) == 0);
+ BUILD_BUG_ON(offsetof(typeof(*os), os_spare4) == 0);
+ BUILD_BUG_ON(offsetof(typeof(*os), os_spare5) == 0);
+ BUILD_BUG_ON(offsetof(typeof(*os), os_spare6) == 0);
+ BUILD_BUG_ON(offsetof(typeof(*os), os_spare7) == 0);
+ BUILD_BUG_ON(offsetof(typeof(*os), os_spare8) == 0);
+ BUILD_BUG_ON(offsetof(typeof(*os), os_spare9) == 0);
}
void lustre_swab_obd_ioobj(struct obd_ioobj *ioo)
__swab64s(&desc->lquota_desc.gl_hardlimit);
__swab64s(&desc->lquota_desc.gl_softlimit);
__swab64s(&desc->lquota_desc.gl_time);
- CLASSERT(offsetof(typeof(desc->lquota_desc), gl_pad2) != 0);
+ BUILD_BUG_ON(offsetof(typeof(desc->lquota_desc), gl_pad2) == 0);
}
void lustre_swab_ost_lvb_v1(struct ost_lvb_v1 *lvb)
__swab32s(&b->mbo_flags);
__swab32s(&b->mbo_rdev);
__swab32s(&b->mbo_nlink);
- CLASSERT(offsetof(typeof(*b), mbo_unused2) != 0);
+ BUILD_BUG_ON(offsetof(typeof(*b), mbo_unused2) == 0);
__swab32s(&b->mbo_suppgid);
__swab32s(&b->mbo_eadatasize);
__swab32s(&b->mbo_aclsize);
__swab32s(&b->mbo_max_mdsize);
- CLASSERT(offsetof(typeof(*b), mbo_unused3));
+ BUILD_BUG_ON(!offsetof(typeof(*b), mbo_unused3));
__swab32s(&b->mbo_uid_h);
__swab32s(&b->mbo_gid_h);
- CLASSERT(offsetof(typeof(*b), mbo_padding_5) != 0);
+ BUILD_BUG_ON(offsetof(typeof(*b), mbo_padding_5) == 0);
}
void lustre_swab_mdt_ioepoch(struct mdt_ioepoch *b)
{
/* handle is opaque */
/* mio_handle is opaque */
- CLASSERT(offsetof(typeof(*b), mio_unused1));
- CLASSERT(offsetof(typeof(*b), mio_unused2));
- CLASSERT(offsetof(typeof(*b), mio_padding));
+ BUILD_BUG_ON(!offsetof(typeof(*b), mio_unused1));
+ BUILD_BUG_ON(!offsetof(typeof(*b), mio_unused2));
+ BUILD_BUG_ON(!offsetof(typeof(*b), mio_padding));
}
void lustre_swab_mgs_target_info(struct mgs_target_info *mti)
__swab32s(&mti->mti_flags);
__swab32s(&mti->mti_instance);
__swab32s(&mti->mti_nid_count);
- CLASSERT(sizeof(lnet_nid_t) == sizeof(__u64));
+ BUILD_BUG_ON(sizeof(lnet_nid_t) != sizeof(__u64));
for (i = 0; i < MTI_NIDS_MAX; i++)
__swab64s(&mti->mti_nids[i]);
}
/* mne_nid_(count|type) must be one byte size because we're gonna
* access it w/o swapping. */
- CLASSERT(sizeof(entry->mne_nid_count) == sizeof(__u8));
- CLASSERT(sizeof(entry->mne_nid_type) == sizeof(__u8));
+ BUILD_BUG_ON(sizeof(entry->mne_nid_count) != sizeof(__u8));
+ BUILD_BUG_ON(sizeof(entry->mne_nid_type) != sizeof(__u8));
/* remove this assertion if ipv6 is supported. */
LASSERT(entry->mne_nid_type == 0);
for (i = 0; i < entry->mne_nid_count; i++) {
- CLASSERT(sizeof(lnet_nid_t) == sizeof(__u64));
+ BUILD_BUG_ON(sizeof(lnet_nid_t) != sizeof(__u64));
__swab64s(&entry->u.nids[i]);
}
}
__swab64s(&b->dqb_btime);
__swab64s(&b->dqb_itime);
__swab32s(&b->dqb_valid);
- CLASSERT(offsetof(typeof(*b), dqb_padding) != 0);
+ BUILD_BUG_ON(offsetof(typeof(*b), dqb_padding) == 0);
}
void lustre_swab_obd_quotactl(struct obd_quotactl *q)
__swab32s(&rr->rr_flags_h);
__swab32s(&rr->rr_umask);
- CLASSERT(offsetof(typeof(*rr), rr_padding_4) != 0);
+ BUILD_BUG_ON(offsetof(typeof(*rr), rr_padding_4) == 0);
};
void lustre_swab_lov_desc(struct lov_desc *ld)
__swab32s(&lum->lum_stripe_offset);
__swab32s(&lum->lum_hash_type);
__swab32s(&lum->lum_type);
- CLASSERT(offsetof(typeof(*lum), lum_padding1));
+ BUILD_BUG_ON(!offsetof(typeof(*lum), lum_padding1));
}
EXPORT_SYMBOL(lustre_swab_lmv_user_md);
static void lustre_swab_ldlm_resource_desc(struct ldlm_resource_desc *r)
{
__swab32s(&r->lr_type);
- CLASSERT(offsetof(typeof(*r), lr_padding) != 0);
+ BUILD_BUG_ON(offsetof(typeof(*r), lr_padding) == 0);
lustre_swab_ldlm_res_id(&r->lr_name);
}
void lustre_swab_ldlm_reply(struct ldlm_reply *r)
{
__swab32s(&r->lock_flags);
- CLASSERT(offsetof(typeof(*r), lock_padding) != 0);
+ BUILD_BUG_ON(offsetof(typeof(*r), lock_padding) == 0);
lustre_swab_ldlm_lock_desc(&r->lock_desc);
/* lock_handle opaque */
__swab64s(&r->lock_policy_res1);
{
int offset = mdidx * LNET_MAX_IOV;
- CLASSERT(PTLRPC_MAX_BRW_PAGES < LI_POISON);
+ BUILD_BUG_ON(PTLRPC_MAX_BRW_PAGES >= LI_POISON);
LASSERT(mdidx < desc->bd_md_max_brw);
LASSERT(desc->bd_iov_count <= PTLRPC_MAX_BRW_PAGES);
sizeof(NRS_LPROCFS_QUANTUM_NAME_REG __stringify(LPROCFS_NRS_QUANTUM_MAX) " " \
NRS_LPROCFS_QUANTUM_NAME_HP __stringify(LPROCFS_NRS_QUANTUM_MAX))
+/* ptlrpc/nrs_fifo.c */
+extern struct ptlrpc_nrs_pol_conf nrs_conf_fifo;
+
/* recovd_thread.c */
int ptlrpc_expire_one_request(struct ptlrpc_request *req, int async_unlink);
*/
static int max_ptlrpcds;
module_param(max_ptlrpcds, int, 0644);
-MODULE_PARM_DESC(max_ptlrpcds, "Max ptlrpcd thread count to be started.");
+MODULE_PARM_DESC(max_ptlrpcds,
+ "Max ptlrpcd thread count to be started (obsolete).");
/*
* ptlrpcd_bind_policy is obsolete, but retained to ensure that
static int ptlrpcd_per_cpt_max;
module_param(ptlrpcd_per_cpt_max, int, 0644);
MODULE_PARM_DESC(ptlrpcd_per_cpt_max,
- "Max ptlrpcd thread count to be started per cpt.");
+ "Max ptlrpcd thread count to be started per CPT.");
/*
* ptlrpcd_partner_group_size: The desired number of threads in each
return 0;
}
- /*
- * So far only "client" ptlrpcd uses an environment. In the future,
- * ptlrpcd thread (or a thread-set) has to be given an argument,
- * describing its "scope".
- */
- rc = lu_context_init(&pc->pc_env.le_ctx, LCT_CL_THREAD | LCT_REMEMBER);
- if (rc != 0)
- goto out;
-
task = kthread_run(ptlrpcd, pc, "%s", pc->pc_name);
if (IS_ERR(task)) {
rc = PTR_ERR(task);
spin_unlock(&pc->pc_lock);
ptlrpc_set_destroy(set);
}
- lu_context_fini(&pc->pc_env.le_ctx);
-
-out:
clear_bit(LIOD_START, &pc->pc_flags);
return rc;
}
}
wait_for_completion(&pc->pc_finishing);
- lu_context_fini(&pc->pc_env.le_ctx);
spin_lock(&pc->pc_lock);
pc->pc_set = NULL;
imp->imp_last_transno_checked = 0;
ptlrpc_free_committed(imp);
last_transno = imp->imp_last_replay_transno;
- spin_unlock(&imp->imp_lock);
CDEBUG(D_HA, "import %p from %s committed %llu last %llu\n",
imp, obd2cli_tgt(imp->imp_obd),
imp->imp_peer_committed_transno, last_transno);
- /* Do I need to hold a lock across this iteration? We shouldn't be
- * racing with any additions to the list, because we're in recovery
- * and are therefore not processing additional requests to add. Calls
- * to ptlrpc_free_committed might commit requests, but nothing "newer"
- * than the one we're replaying (it can't be committed until it's
- * replayed, and we're doing that here). l_f_e_safe protects against
- * problems with the current request being committed, in the unlikely
- * event of that race. So, in conclusion, I think that it's safe to
- * perform this list-walk without the imp_lock held.
- *
- * But, the {mdc,osc}_replay_open callbacks both iterate
- * request lists, and have comments saying they assume the
- * imp_lock is being held by ptlrpc_replay, but it's not. it's
- * just a little race...
- */
-
/* Replay all the committed open requests on committed_list first */
if (!list_empty(&imp->imp_committed_list)) {
tmp = imp->imp_committed_list.prev;
/* The last request on committed_list hasn't been replayed */
if (req->rq_transno > last_transno) {
- /* Since the imp_committed_list is immutable before
- * all of it's requests being replayed, it's safe to
- * use a cursor to accelerate the search
- */
if (!imp->imp_resend_replay ||
imp->imp_replay_cursor == &imp->imp_committed_list)
imp->imp_replay_cursor = imp->imp_replay_cursor->next;
break;
req = NULL;
+ LASSERT(!list_empty(imp->imp_replay_cursor));
imp->imp_replay_cursor =
imp->imp_replay_cursor->next;
}
if (req && imp->imp_resend_replay)
lustre_msg_add_flags(req->rq_reqmsg, MSG_RESENT);
- spin_lock(&imp->imp_lock);
/* The resend replay request may have been removed from the
* unreplied list.
*/
}
spin_unlock(&imp->imp_lock);
+ OBD_FAIL_TIMEOUT(OBD_FAIL_LDLM_ENQUEUE_OLD_EXPORT, 2);
return 0;
}
*/
if (req->rq_ops->hpreq_check) {
rc = req->rq_ops->hpreq_check(req);
- /**
- * XXX: Out of all current
- * ptlrpc_hpreq_ops::hpreq_check(), only
- * ldlm_cancel_hpreq_check() can return an error code;
- * other functions assert in similar places, which seems
- * odd. What also does not seem right is that handlers
- * for those RPCs do not assert on the same checks, but
- * rather handle the error cases. e.g. see
- * ost_rw_hpreq_check(), and ost_brw_read(),
- * ost_brw_write().
+ if (rc == -ESTALE) {
+ req->rq_status = rc;
+ ptlrpc_error(req);
+ }
+ /** can only return error,
+ * 0 for normal request,
+ * or 1 for high priority request
*/
- if (rc < 0)
- return rc;
- LASSERT(rc == 0 || rc == 1);
+ LASSERT(rc <= 1);
}
spin_lock_bh(&req->rq_export->exp_rpc_lock);
MDS_DIR_END_OFF);
LASSERTF(DEAD_HANDLE_MAGIC == 0xdeadbeefcafebabeULL, "found 0x%.16llxULL\n",
DEAD_HANDLE_MAGIC);
- CLASSERT(MTI_NAME_MAXLEN == 64);
+ BUILD_BUG_ON(MTI_NAME_MAXLEN != 64);
LASSERTF(OST_REPLY == 0, "found %lld\n",
(long long)OST_REPLY);
LASSERTF(OST_GETATTR == 1, "found %lld\n",
(long long)LCK_MAXMODE);
LASSERTF(LCK_MODE_NUM == 8, "found %lld\n",
(long long)LCK_MODE_NUM);
- CLASSERT(LDLM_PLAIN == 10);
- CLASSERT(LDLM_EXTENT == 11);
- CLASSERT(LDLM_FLOCK == 12);
- CLASSERT(LDLM_IBITS == 13);
- CLASSERT(LDLM_MAX_TYPE == 14);
- CLASSERT(LUSTRE_RES_ID_SEQ_OFF == 0);
- CLASSERT(LUSTRE_RES_ID_VER_OID_OFF == 1);
- CLASSERT(LUSTRE_RES_ID_QUOTA_SEQ_OFF == 2);
- CLASSERT(LUSTRE_RES_ID_QUOTA_VER_OID_OFF == 3);
- CLASSERT(LUSTRE_RES_ID_HSH_OFF == 3);
+ BUILD_BUG_ON(LDLM_PLAIN != 10);
+ BUILD_BUG_ON(LDLM_EXTENT != 11);
+ BUILD_BUG_ON(LDLM_FLOCK != 12);
+ BUILD_BUG_ON(LDLM_IBITS != 13);
+ BUILD_BUG_ON(LDLM_MAX_TYPE != 14);
+ BUILD_BUG_ON(LUSTRE_RES_ID_SEQ_OFF != 0);
+ BUILD_BUG_ON(LUSTRE_RES_ID_VER_OID_OFF != 1);
+ BUILD_BUG_ON(LUSTRE_RES_ID_QUOTA_SEQ_OFF != 2);
+ BUILD_BUG_ON(LUSTRE_RES_ID_QUOTA_VER_OID_OFF != 3);
+ BUILD_BUG_ON(LUSTRE_RES_ID_HSH_OFF != 3);
LASSERTF(OBD_PING == 400, "found %lld\n",
(long long)OBD_PING);
LASSERTF(OBD_LOG_CANCEL == 401, "found %lld\n",
(long long)(int)offsetof(struct ptlrpc_body_v3, pb_slv));
LASSERTF((int)sizeof(((struct ptlrpc_body_v3 *)0)->pb_slv) == 8, "found %lld\n",
(long long)(int)sizeof(((struct ptlrpc_body_v3 *)0)->pb_slv));
- CLASSERT(PTLRPC_NUM_VERSIONS == 4);
+ BUILD_BUG_ON(PTLRPC_NUM_VERSIONS != 4);
LASSERTF((int)offsetof(struct ptlrpc_body_v3, pb_pre_versions) == 88, "found %lld\n",
(long long)(int)offsetof(struct ptlrpc_body_v3, pb_pre_versions));
LASSERTF((int)sizeof(((struct ptlrpc_body_v3 *)0)->pb_pre_versions) == 32, "found %lld\n",
(long long)(int)offsetof(struct ptlrpc_body_v3, pb_padding64_2));
LASSERTF((int)sizeof(((struct ptlrpc_body_v3 *)0)->pb_padding64_2) == 8, "found %lld\n",
(long long)(int)sizeof(((struct ptlrpc_body_v3 *)0)->pb_padding64_2));
- CLASSERT(LUSTRE_JOBID_SIZE == 32);
+ BUILD_BUG_ON(LUSTRE_JOBID_SIZE != 32);
LASSERTF((int)offsetof(struct ptlrpc_body_v3, pb_jobid) == 152, "found %lld\n",
(long long)(int)offsetof(struct ptlrpc_body_v3, pb_jobid));
LASSERTF((int)sizeof(((struct ptlrpc_body_v3 *)0)->pb_jobid) == 32, "found %lld\n",
OBD_MD_FLGETATTRLOCK);
LASSERTF(OBD_MD_FLDATAVERSION == (0x0010000000000000ULL), "found 0x%.16llxULL\n",
OBD_MD_FLDATAVERSION);
- CLASSERT(OBD_FL_INLINEDATA == 0x00000001);
- CLASSERT(OBD_FL_OBDMDEXISTS == 0x00000002);
- CLASSERT(OBD_FL_DELORPHAN == 0x00000004);
- CLASSERT(OBD_FL_NORPC == 0x00000008);
- CLASSERT(OBD_FL_IDONLY == 0x00000010);
- CLASSERT(OBD_FL_RECREATE_OBJS == 0x00000020);
- CLASSERT(OBD_FL_DEBUG_CHECK == 0x00000040);
- CLASSERT(OBD_FL_NO_USRQUOTA == 0x00000100);
- CLASSERT(OBD_FL_NO_GRPQUOTA == 0x00000200);
- CLASSERT(OBD_FL_CREATE_CROW == 0x00000400);
- CLASSERT(OBD_FL_SRVLOCK == 0x00000800);
- CLASSERT(OBD_FL_CKSUM_CRC32 == 0x00001000);
- CLASSERT(OBD_FL_CKSUM_ADLER == 0x00002000);
- CLASSERT(OBD_FL_CKSUM_CRC32C == 0x00004000);
- CLASSERT(OBD_FL_CKSUM_RSVD2 == 0x00008000);
- CLASSERT(OBD_FL_CKSUM_RSVD3 == 0x00010000);
- CLASSERT(OBD_FL_SHRINK_GRANT == 0x00020000);
- CLASSERT(OBD_FL_MMAP == 0x00040000);
- CLASSERT(OBD_FL_RECOV_RESEND == 0x00080000);
- CLASSERT(OBD_FL_NOSPC_BLK == 0x00100000);
- CLASSERT(OBD_FL_LOCAL_MASK == 0xf0000000);
+ BUILD_BUG_ON(OBD_FL_INLINEDATA != 0x00000001);
+ BUILD_BUG_ON(OBD_FL_OBDMDEXISTS != 0x00000002);
+ BUILD_BUG_ON(OBD_FL_DELORPHAN != 0x00000004);
+ BUILD_BUG_ON(OBD_FL_NORPC != 0x00000008);
+ BUILD_BUG_ON(OBD_FL_IDONLY != 0x00000010);
+ BUILD_BUG_ON(OBD_FL_RECREATE_OBJS != 0x00000020);
+ BUILD_BUG_ON(OBD_FL_DEBUG_CHECK != 0x00000040);
+ BUILD_BUG_ON(OBD_FL_NO_USRQUOTA != 0x00000100);
+ BUILD_BUG_ON(OBD_FL_NO_GRPQUOTA != 0x00000200);
+ BUILD_BUG_ON(OBD_FL_CREATE_CROW != 0x00000400);
+ BUILD_BUG_ON(OBD_FL_SRVLOCK != 0x00000800);
+ BUILD_BUG_ON(OBD_FL_CKSUM_CRC32 != 0x00001000);
+ BUILD_BUG_ON(OBD_FL_CKSUM_ADLER != 0x00002000);
+ BUILD_BUG_ON(OBD_FL_CKSUM_CRC32C != 0x00004000);
+ BUILD_BUG_ON(OBD_FL_CKSUM_RSVD2 != 0x00008000);
+ BUILD_BUG_ON(OBD_FL_CKSUM_RSVD3 != 0x00010000);
+ BUILD_BUG_ON(OBD_FL_SHRINK_GRANT != 0x00020000);
+ BUILD_BUG_ON(OBD_FL_MMAP != 0x00040000);
+ BUILD_BUG_ON(OBD_FL_RECOV_RESEND != 0x00080000);
+ BUILD_BUG_ON(OBD_FL_NOSPC_BLK != 0x00100000);
+ BUILD_BUG_ON(OBD_FL_LOCAL_MASK != 0xf0000000);
/* Checks for struct lov_ost_data_v1 */
LASSERTF((int)sizeof(struct lov_ost_data_v1) == 24, "found %lld\n",
(long long)(int)offsetof(struct lov_mds_md_v1, lmm_objects[0]));
LASSERTF((int)sizeof(((struct lov_mds_md_v1 *)0)->lmm_objects[0]) == 24, "found %lld\n",
(long long)(int)sizeof(((struct lov_mds_md_v1 *)0)->lmm_objects[0]));
- CLASSERT(LOV_MAGIC_V1 == (0x0BD10000 | 0x0BD0));
+ BUILD_BUG_ON(LOV_MAGIC_V1 != (0x0BD10000 | 0x0BD0));
/* Checks for struct lov_mds_md_v3 */
LASSERTF((int)sizeof(struct lov_mds_md_v3) == 48, "found %lld\n",
(long long)(int)offsetof(struct lov_mds_md_v3, lmm_layout_gen));
LASSERTF((int)sizeof(((struct lov_mds_md_v3 *)0)->lmm_layout_gen) == 2, "found %lld\n",
(long long)(int)sizeof(((struct lov_mds_md_v3 *)0)->lmm_layout_gen));
- CLASSERT(LOV_MAXPOOLNAME == 15);
+ BUILD_BUG_ON(LOV_MAXPOOLNAME != 15);
LASSERTF((int)offsetof(struct lov_mds_md_v3, lmm_pool_name[16]) == 48, "found %lld\n",
(long long)(int)offsetof(struct lov_mds_md_v3, lmm_pool_name[16]));
LASSERTF((int)sizeof(((struct lov_mds_md_v3 *)0)->lmm_pool_name[16]) == 1, "found %lld\n",
(long long)(int)offsetof(struct lov_mds_md_v3, lmm_objects[0]));
LASSERTF((int)sizeof(((struct lov_mds_md_v3 *)0)->lmm_objects[0]) == 24, "found %lld\n",
(long long)(int)sizeof(((struct lov_mds_md_v3 *)0)->lmm_objects[0]));
- CLASSERT(LOV_MAGIC_V3 == (0x0BD30000 | 0x0BD0));
+ BUILD_BUG_ON(LOV_MAGIC_V3 != (0x0BD30000 | 0x0BD0));
LASSERTF(LOV_PATTERN_RAID0 == 0x00000001UL, "found 0x%.8xUL\n",
(unsigned int)LOV_PATTERN_RAID0);
LASSERTF(LOV_PATTERN_RAID1 == 0x00000002UL, "found 0x%.8xUL\n",
(long long)(int)offsetof(struct lmv_mds_md_v1, lmv_stripe_fids[0]));
LASSERTF((int)sizeof(((struct lmv_mds_md_v1 *)0)->lmv_stripe_fids[0]) == 16, "found %lld\n",
(long long)(int)sizeof(((struct lmv_mds_md_v1 *)0)->lmv_stripe_fids[0]));
- CLASSERT(LMV_MAGIC_V1 == 0x0CD20CD0);
- CLASSERT(LMV_MAGIC_STRIPE == 0x0CD40CD0);
- CLASSERT(LMV_HASH_TYPE_MASK == 0x0000ffff);
- CLASSERT(LMV_HASH_FLAG_MIGRATION == 0x80000000);
- CLASSERT(LMV_HASH_FLAG_DEAD == 0x40000000);
+ BUILD_BUG_ON(LMV_MAGIC_V1 != 0x0CD20CD0);
+ BUILD_BUG_ON(LMV_MAGIC_STRIPE != 0x0CD40CD0);
+ BUILD_BUG_ON(LMV_HASH_TYPE_MASK != 0x0000ffff);
+ BUILD_BUG_ON(LMV_HASH_FLAG_MIGRATION != 0x80000000);
+ BUILD_BUG_ON(LMV_HASH_FLAG_DEAD != 0x40000000);
/* Checks for struct obd_statfs */
LASSERTF((int)sizeof(struct obd_statfs) == 144, "found %lld\n",
(long long)(int)offsetof(struct lov_desc, ld_uuid));
LASSERTF((int)sizeof(((struct lov_desc *)0)->ld_uuid) == 40, "found %lld\n",
(long long)(int)sizeof(((struct lov_desc *)0)->ld_uuid));
- CLASSERT(LOV_DESC_MAGIC == 0xB0CCDE5C);
+ BUILD_BUG_ON(LOV_DESC_MAGIC != 0xB0CCDE5C);
/* Checks for struct ldlm_res_id */
LASSERTF((int)sizeof(struct ldlm_res_id) == 32, "found %lld\n",
(long long)(int)sizeof(struct ldlm_res_id));
- CLASSERT(RES_NAME_SIZE == 4);
+ BUILD_BUG_ON(RES_NAME_SIZE != 4);
LASSERTF((int)offsetof(struct ldlm_res_id, name[4]) == 32, "found %lld\n",
(long long)(int)offsetof(struct ldlm_res_id, name[4]));
LASSERTF((int)sizeof(((struct ldlm_res_id *)0)->name[4]) == 8, "found %lld\n",
/* Checks for struct mgs_send_param */
LASSERTF((int)sizeof(struct mgs_send_param) == 1024, "found %lld\n",
(long long)(int)sizeof(struct mgs_send_param));
- CLASSERT(MGS_PARAM_MAXLEN == 1024);
+ BUILD_BUG_ON(MGS_PARAM_MAXLEN != 1024);
LASSERTF((int)offsetof(struct mgs_send_param, mgs_param[1024]) == 1024, "found %lld\n",
(long long)(int)offsetof(struct mgs_send_param, mgs_param[1024]));
LASSERTF((int)sizeof(((struct mgs_send_param *)0)->mgs_param[1024]) == 1, "found %lld\n",
(long long)(int)offsetof(struct llog_logid, lgl_ogen));
LASSERTF((int)sizeof(((struct llog_logid *)0)->lgl_ogen) == 4, "found %lld\n",
(long long)(int)sizeof(((struct llog_logid *)0)->lgl_ogen));
- CLASSERT(OST_SZ_REC == 274730752);
- CLASSERT(MDS_UNLINK_REC == 274801668);
- CLASSERT(MDS_UNLINK64_REC == 275325956);
- CLASSERT(MDS_SETATTR64_REC == 275325953);
- CLASSERT(OBD_CFG_REC == 274857984);
- CLASSERT(LLOG_GEN_REC == 274989056);
- CLASSERT(CHANGELOG_REC == 275120128);
- CLASSERT(CHANGELOG_USER_REC == 275185664);
- CLASSERT(LLOG_HDR_MAGIC == 275010873);
- CLASSERT(LLOG_LOGID_MAGIC == 275010875);
+ BUILD_BUG_ON(OST_SZ_REC != 274730752);
+ BUILD_BUG_ON(MDS_UNLINK_REC != 274801668);
+ BUILD_BUG_ON(MDS_UNLINK64_REC != 275325956);
+ BUILD_BUG_ON(MDS_SETATTR64_REC != 275325953);
+ BUILD_BUG_ON(OBD_CFG_REC != 274857984);
+ BUILD_BUG_ON(LLOG_GEN_REC != 274989056);
+ BUILD_BUG_ON(CHANGELOG_REC != 275120128);
+ BUILD_BUG_ON(CHANGELOG_USER_REC != 275185664);
+ BUILD_BUG_ON(LLOG_HDR_MAGIC != 275010873);
+ BUILD_BUG_ON(LLOG_LOGID_MAGIC != 275010875);
/* Checks for struct llog_catid */
LASSERTF((int)sizeof(struct llog_catid) == 32, "found %lld\n",
(long long)(int)offsetof(struct llogd_body, lgd_cur_offset));
LASSERTF((int)sizeof(((struct llogd_body *)0)->lgd_cur_offset) == 8, "found %lld\n",
(long long)(int)sizeof(((struct llogd_body *)0)->lgd_cur_offset));
- CLASSERT(LLOG_ORIGIN_HANDLE_CREATE == 501);
- CLASSERT(LLOG_ORIGIN_HANDLE_NEXT_BLOCK == 502);
- CLASSERT(LLOG_ORIGIN_HANDLE_READ_HEADER == 503);
- CLASSERT(LLOG_ORIGIN_HANDLE_WRITE_REC == 504);
- CLASSERT(LLOG_ORIGIN_HANDLE_CLOSE == 505);
- CLASSERT(LLOG_ORIGIN_CONNECT == 506);
- CLASSERT(LLOG_CATINFO == 507);
- CLASSERT(LLOG_ORIGIN_HANDLE_PREV_BLOCK == 508);
- CLASSERT(LLOG_ORIGIN_HANDLE_DESTROY == 509);
- CLASSERT(LLOG_FIRST_OPC == 501);
- CLASSERT(LLOG_LAST_OPC == 510);
- CLASSERT(LLOG_CONFIG_ORIG_CTXT == 0);
- CLASSERT(LLOG_CONFIG_REPL_CTXT == 1);
- CLASSERT(LLOG_MDS_OST_ORIG_CTXT == 2);
- CLASSERT(LLOG_MDS_OST_REPL_CTXT == 3);
- CLASSERT(LLOG_SIZE_ORIG_CTXT == 4);
- CLASSERT(LLOG_SIZE_REPL_CTXT == 5);
- CLASSERT(LLOG_TEST_ORIG_CTXT == 8);
- CLASSERT(LLOG_TEST_REPL_CTXT == 9);
- CLASSERT(LLOG_CHANGELOG_ORIG_CTXT == 12);
- CLASSERT(LLOG_CHANGELOG_REPL_CTXT == 13);
- CLASSERT(LLOG_CHANGELOG_USER_ORIG_CTXT == 14);
- CLASSERT(LLOG_AGENT_ORIG_CTXT == 15);
- CLASSERT(LLOG_MAX_CTXTS == 16);
+ BUILD_BUG_ON(LLOG_ORIGIN_HANDLE_CREATE != 501);
+ BUILD_BUG_ON(LLOG_ORIGIN_HANDLE_NEXT_BLOCK != 502);
+ BUILD_BUG_ON(LLOG_ORIGIN_HANDLE_READ_HEADER != 503);
+ BUILD_BUG_ON(LLOG_ORIGIN_HANDLE_WRITE_REC != 504);
+ BUILD_BUG_ON(LLOG_ORIGIN_HANDLE_CLOSE != 505);
+ BUILD_BUG_ON(LLOG_ORIGIN_CONNECT != 506);
+ BUILD_BUG_ON(LLOG_CATINFO != 507);
+ BUILD_BUG_ON(LLOG_ORIGIN_HANDLE_PREV_BLOCK != 508);
+ BUILD_BUG_ON(LLOG_ORIGIN_HANDLE_DESTROY != 509);
+ BUILD_BUG_ON(LLOG_FIRST_OPC != 501);
+ BUILD_BUG_ON(LLOG_LAST_OPC != 510);
+ BUILD_BUG_ON(LLOG_CONFIG_ORIG_CTXT != 0);
+ BUILD_BUG_ON(LLOG_CONFIG_REPL_CTXT != 1);
+ BUILD_BUG_ON(LLOG_MDS_OST_ORIG_CTXT != 2);
+ BUILD_BUG_ON(LLOG_MDS_OST_REPL_CTXT != 3);
+ BUILD_BUG_ON(LLOG_SIZE_ORIG_CTXT != 4);
+ BUILD_BUG_ON(LLOG_SIZE_REPL_CTXT != 5);
+ BUILD_BUG_ON(LLOG_TEST_ORIG_CTXT != 8);
+ BUILD_BUG_ON(LLOG_TEST_REPL_CTXT != 9);
+ BUILD_BUG_ON(LLOG_CHANGELOG_ORIG_CTXT != 12);
+ BUILD_BUG_ON(LLOG_CHANGELOG_REPL_CTXT != 13);
+ BUILD_BUG_ON(LLOG_CHANGELOG_USER_ORIG_CTXT != 14);
+ BUILD_BUG_ON(LLOG_AGENT_ORIG_CTXT != 15);
+ BUILD_BUG_ON(LLOG_MAX_CTXTS != 16);
/* Checks for struct llogd_conn_body */
LASSERTF((int)sizeof(struct llogd_conn_body) == 40, "found %lld\n",
(long long)(int)offsetof(struct lustre_capa, lc_expiry));
LASSERTF((int)sizeof(((struct lustre_capa *)0)->lc_expiry) == 4, "found %lld\n",
(long long)(int)sizeof(((struct lustre_capa *)0)->lc_expiry));
- CLASSERT(CAPA_HMAC_MAX_LEN == 64);
+ BUILD_BUG_ON(CAPA_HMAC_MAX_LEN != 64);
LASSERTF((int)offsetof(struct lustre_capa, lc_hmac[64]) == 120, "found %lld\n",
(long long)(int)offsetof(struct lustre_capa, lc_hmac[64]));
LASSERTF((int)sizeof(((struct lustre_capa *)0)->lc_hmac[64]) == 1, "found %lld\n",
(long long)(int)offsetof(struct lustre_capa_key, lk_padding));
LASSERTF((int)sizeof(((struct lustre_capa_key *)0)->lk_padding) == 4, "found %lld\n",
(long long)(int)sizeof(((struct lustre_capa_key *)0)->lk_padding));
- CLASSERT(CAPA_HMAC_KEY_MAX_LEN == 56);
+ BUILD_BUG_ON(CAPA_HMAC_KEY_MAX_LEN != 56);
LASSERTF((int)offsetof(struct lustre_capa_key, lk_key[56]) == 72, "found %lld\n",
(long long)(int)offsetof(struct lustre_capa_key, lk_key[56]));
LASSERTF((int)sizeof(((struct lustre_capa_key *)0)->lk_key[56]) == 1, "found %lld\n",
(long long)(int)offsetof(struct fiemap, fm_extents));
LASSERTF((int)sizeof(((struct fiemap *)0)->fm_extents) == 0, "found %lld\n",
(long long)(int)sizeof(((struct fiemap *)0)->fm_extents));
- CLASSERT(FIEMAP_FLAG_SYNC == 0x00000001);
- CLASSERT(FIEMAP_FLAG_XATTR == 0x00000002);
- CLASSERT(FIEMAP_FLAG_DEVICE_ORDER == 0x40000000);
+ BUILD_BUG_ON(FIEMAP_FLAG_SYNC != 0x00000001);
+ BUILD_BUG_ON(FIEMAP_FLAG_XATTR != 0x00000002);
+ BUILD_BUG_ON(FIEMAP_FLAG_DEVICE_ORDER != 0x40000000);
/* Checks for struct fiemap_extent */
LASSERTF((int)sizeof(struct fiemap_extent) == 56, "found %lld\n",
(long long)(int)offsetof(struct fiemap_extent, fe_reserved[0]));
LASSERTF((int)sizeof(((struct fiemap_extent *)0)->fe_reserved[0]) == 4, "found %lld\n",
(long long)(int)sizeof(((struct fiemap_extent *)0)->fe_reserved[0]));
- CLASSERT(FIEMAP_EXTENT_LAST == 0x00000001);
- CLASSERT(FIEMAP_EXTENT_UNKNOWN == 0x00000002);
- CLASSERT(FIEMAP_EXTENT_DELALLOC == 0x00000004);
- CLASSERT(FIEMAP_EXTENT_ENCODED == 0x00000008);
- CLASSERT(FIEMAP_EXTENT_DATA_ENCRYPTED == 0x00000080);
- CLASSERT(FIEMAP_EXTENT_NOT_ALIGNED == 0x00000100);
- CLASSERT(FIEMAP_EXTENT_DATA_INLINE == 0x00000200);
- CLASSERT(FIEMAP_EXTENT_DATA_TAIL == 0x00000400);
- CLASSERT(FIEMAP_EXTENT_UNWRITTEN == 0x00000800);
- CLASSERT(FIEMAP_EXTENT_MERGED == 0x00001000);
- CLASSERT(FIEMAP_EXTENT_NO_DIRECT == 0x40000000);
- CLASSERT(FIEMAP_EXTENT_NET == 0x80000000);
+ BUILD_BUG_ON(FIEMAP_EXTENT_LAST != 0x00000001);
+ BUILD_BUG_ON(FIEMAP_EXTENT_UNKNOWN != 0x00000002);
+ BUILD_BUG_ON(FIEMAP_EXTENT_DELALLOC != 0x00000004);
+ BUILD_BUG_ON(FIEMAP_EXTENT_ENCODED != 0x00000008);
+ BUILD_BUG_ON(FIEMAP_EXTENT_DATA_ENCRYPTED != 0x00000080);
+ BUILD_BUG_ON(FIEMAP_EXTENT_NOT_ALIGNED != 0x00000100);
+ BUILD_BUG_ON(FIEMAP_EXTENT_DATA_INLINE != 0x00000200);
+ BUILD_BUG_ON(FIEMAP_EXTENT_DATA_TAIL != 0x00000400);
+ BUILD_BUG_ON(FIEMAP_EXTENT_UNWRITTEN != 0x00000800);
+ BUILD_BUG_ON(FIEMAP_EXTENT_MERGED != 0x00001000);
+ BUILD_BUG_ON(FIEMAP_EXTENT_NO_DIRECT != 0x40000000);
+ BUILD_BUG_ON(FIEMAP_EXTENT_NET != 0x80000000);
/* Checks for type posix_acl_xattr_entry */
LASSERTF((int)sizeof(struct posix_acl_xattr_entry) == 8, "found %lld\n",
(long long)(int)offsetof(struct link_ea_header, padding2));
LASSERTF((int)sizeof(((struct link_ea_header *)0)->padding2) == 4, "found %lld\n",
(long long)(int)sizeof(((struct link_ea_header *)0)->padding2));
- CLASSERT(LINK_EA_MAGIC == 0x11EAF1DFUL);
+ BUILD_BUG_ON(LINK_EA_MAGIC != 0x11EAF1DFUL);
/* Checks for struct link_ea_entry */
LASSERTF((int)sizeof(struct link_ea_entry) == 18, "found %lld\n",
source "drivers/staging/media/omap4iss/Kconfig"
+source "drivers/staging/media/platform/bcm2835/Kconfig"
+
source "drivers/staging/media/s5p-cec/Kconfig"
# Keep LIRC at the end, as it has sub-menus
obj-$(CONFIG_VIDEO_SAMSUNG_S5P_CEC) += s5p-cec/
obj-$(CONFIG_DVB_CXD2099) += cxd2099/
obj-$(CONFIG_LIRC_STAGING) += lirc/
+obj-$(CONFIG_VIDEO_BCM2835) += platform/bcm2835/
obj-$(CONFIG_VIDEO_DM365_VPFE) += davinci_vpfe/
obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/
obj-$(CONFIG_VIDEO_STI_HDMI_CEC) += st-cec/
static bool debug;
static bool interface;
-module_param(interface, bool, S_IRUGO);
+module_param(interface, bool, 0444);
module_param(debug, bool, 0644);
/**
/*** module initialization and cleanup ***/
-static int __init lirc_parallel_init(void)
+static void lirc_parallel_attach(struct parport *port)
{
- int result;
-
- result = platform_driver_register(&lirc_parallel_driver);
- if (result) {
- pr_notice("platform_driver_register returned %d\n", result);
- return result;
- }
+ struct pardev_cb lirc_parallel_cb;
- lirc_parallel_dev = platform_device_alloc(LIRC_DRIVER_NAME, 0);
- if (!lirc_parallel_dev) {
- result = -ENOMEM;
- goto exit_driver_unregister;
- }
+ if (port->base != io)
+ return;
- result = platform_device_add(lirc_parallel_dev);
- if (result)
- goto exit_device_put;
+ pport = port;
+ memset(&lirc_parallel_cb, 0, sizeof(lirc_parallel_cb));
+ lirc_parallel_cb.preempt = pf;
+ lirc_parallel_cb.wakeup = kf;
+ lirc_parallel_cb.irq_func = lirc_lirc_irq_handler;
- pport = parport_find_base(io);
- if (!pport) {
- pr_notice("no port at %x found\n", io);
- result = -ENXIO;
- goto exit_device_del;
- }
- ppdevice = parport_register_device(pport, LIRC_DRIVER_NAME,
- pf, kf, lirc_lirc_irq_handler, 0,
- NULL);
- parport_put_port(pport);
+ ppdevice = parport_register_dev_model(port, LIRC_DRIVER_NAME,
+ &lirc_parallel_cb, 0);
if (!ppdevice) {
pr_notice("parport_register_device() failed\n");
- result = -ENXIO;
- goto exit_device_del;
+ return;
}
+
if (parport_claim(ppdevice) != 0)
goto skip_init;
is_claimed = 1;
is_claimed = 0;
parport_release(ppdevice);
+
skip_init:
+ return;
+}
+
+static void lirc_parallel_detach(struct parport *port)
+{
+ if (port->base != io)
+ return;
+
+ parport_unregister_device(ppdevice);
+}
+
+static struct parport_driver lirc_parport_driver = {
+ .name = LIRC_DRIVER_NAME,
+ .match_port = lirc_parallel_attach,
+ .detach = lirc_parallel_detach,
+ .devmodel = true,
+};
+
+static int __init lirc_parallel_init(void)
+{
+ int result;
+
+ result = platform_driver_register(&lirc_parallel_driver);
+ if (result) {
+ pr_notice("platform_driver_register returned %d\n", result);
+ return result;
+ }
+
+ lirc_parallel_dev = platform_device_alloc(LIRC_DRIVER_NAME, 0);
+ if (!lirc_parallel_dev) {
+ result = -ENOMEM;
+ goto exit_driver_unregister;
+ }
+
+ result = platform_device_add(lirc_parallel_dev);
+ if (result)
+ goto exit_device_put;
+
+ result = parport_register_driver(&lirc_parport_driver);
+ if (result) {
+ pr_notice("parport_register_driver returned %d\n", result);
+ goto exit_device_del;
+ }
+
driver.dev = &lirc_parallel_dev->dev;
driver.minor = lirc_register_driver(&driver);
if (driver.minor < 0) {
pr_notice("register_chrdev() failed\n");
- parport_unregister_device(ppdevice);
result = -EIO;
- goto exit_device_del;
+ goto exit_unregister;
}
pr_info("installed using port 0x%04x irq %d\n", io, irq);
return 0;
+exit_unregister:
+ parport_unregister_driver(&lirc_parport_driver);
exit_device_del:
platform_device_del(lirc_parallel_dev);
exit_device_put:
static void __exit lirc_parallel_exit(void)
{
- parport_unregister_device(ppdevice);
lirc_unregister_driver(driver.minor);
+ parport_unregister_driver(&lirc_parport_driver);
platform_device_unregister(lirc_parallel_dev);
platform_driver_unregister(&lirc_parallel_driver);
}
--- /dev/null
+config VIDEO_BCM2835
+ tristate "Broadcom BCM2835 camera driver"
+ depends on VIDEO_V4L2 && (ARCH_BCM2835 || COMPILE_TEST)
+ depends on BCM2835_VCHIQ
+ depends on ARM
+ select VIDEOBUF2_VMALLOC
+ help
+ Say Y here to enable camera host interface devices for
+ Broadcom BCM2835 SoC. This operates over the VCHIQ interface
+ to a service running on VideoCore.
--- /dev/null
+bcm2835-v4l2-$(CONFIG_VIDEO_BCM2835) := \
+ bcm2835-camera.o \
+ controls.o \
+ mmal-vchiq.o
+
+obj-$(CONFIG_VIDEO_BCM2835) += bcm2835-v4l2.o
+
+ccflags-y += \
+ -Idrivers/staging/vc04_services \
+ -D__VCCOREVER__=0x04000000
--- /dev/null
+1) Support dma-buf memory management.
+
+In order to zero-copy import camera images into the 3D or display
+pipelines, we need to export our buffers through dma-buf so that the
+vc4 driver can import them. This may involve bringing in the VCSM
+driver (which allows long-term management of regions of memory in the
+space that the VPU reserved and Linux otherwise doesn't have access
+to), or building some new protocol that allows VCSM-style management
+of Linux's CMA memory.
+
+2) Avoid extra copies for padding of images.
+
+We expose V4L2_PIX_FMT_* formats that have a specified stride/height
+padding in the V4L2 spec, but that padding doesn't match what the
+hardware can do. If we exposed the native padding requirements
+through the V4L2 "multiplanar" formats, the firmware would have one
+less copy it needed to do.
+
+3) Port to ARM64
+
+The bulk_receive() does some manual cache flushing that are 32-bit ARM
+only, which we should convert to proper cross-platform APIs.
+
+4) Convert to be a platform driver.
+
+Right now when the module probes, it tries to initialize VCHI and
+errors out if it wasn't ready yet. If bcm2835-v4l2 was built in, then
+VCHI generally isn't ready because it depends on both the firmware and
+mailbox drivers having already loaded.
+
+We should have VCHI create a platform device once it's initialized,
+and have this driver bind to it, so that we automatically load the
+v4l2 module after VCHI loads.
+
+5) Drop the gstreamer workaround.
+
+This was a temporary workaround for a bug that was fixed mid-2014, and
+we should remove it before stabilizing the driver.
+
--- /dev/null
+/*
+ * Broadcom BM2835 V4L2 driver
+ *
+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
+ * Dave Stevenson <dsteve@broadcom.com>
+ * Simon Mellor <simellor@broadcom.com>
+ * Luke Diamand <luked@broadcom.com>
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <media/videobuf2-vmalloc.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-common.h>
+#include <linux/delay.h>
+
+#include "mmal-common.h"
+#include "mmal-encodings.h"
+#include "mmal-vchiq.h"
+#include "mmal-msg.h"
+#include "mmal-parameters.h"
+#include "bcm2835-camera.h"
+
+#define BM2835_MMAL_VERSION "0.0.2"
+#define BM2835_MMAL_MODULE_NAME "bcm2835-v4l2"
+#define MIN_WIDTH 32
+#define MIN_HEIGHT 32
+#define MIN_BUFFER_SIZE (80 * 1024)
+
+#define MAX_VIDEO_MODE_WIDTH 1280
+#define MAX_VIDEO_MODE_HEIGHT 720
+
+#define MAX_BCM2835_CAMERAS 2
+
+MODULE_DESCRIPTION("Broadcom 2835 MMAL video capture");
+MODULE_AUTHOR("Vincent Sanders");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(BM2835_MMAL_VERSION);
+
+int bcm2835_v4l2_debug;
+module_param_named(debug, bcm2835_v4l2_debug, int, 0644);
+MODULE_PARM_DESC(bcm2835_v4l2_debug, "Debug level 0-2");
+
+#define UNSET (-1)
+static int video_nr[] = {[0 ... (MAX_BCM2835_CAMERAS - 1)] = UNSET };
+module_param_array(video_nr, int, NULL, 0644);
+MODULE_PARM_DESC(video_nr, "videoX start numbers, -1 is autodetect");
+
+static int max_video_width = MAX_VIDEO_MODE_WIDTH;
+static int max_video_height = MAX_VIDEO_MODE_HEIGHT;
+module_param(max_video_width, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+MODULE_PARM_DESC(max_video_width, "Threshold for video mode");
+module_param(max_video_height, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+MODULE_PARM_DESC(max_video_height, "Threshold for video mode");
+
+/* Gstreamer bug https://bugzilla.gnome.org/show_bug.cgi?id=726521
+ * v4l2src does bad (and actually wrong) things when the vidioc_enum_framesizes
+ * function says type V4L2_FRMSIZE_TYPE_STEPWISE, which we do by default.
+ * It's happier if we just don't say anything at all, when it then
+ * sets up a load of defaults that it thinks might work.
+ * If gst_v4l2src_is_broken is non-zero, then we remove the function from
+ * our function table list (actually switch to an alternate set, but same
+ * result).
+ */
+static int gst_v4l2src_is_broken;
+module_param(gst_v4l2src_is_broken, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+MODULE_PARM_DESC(gst_v4l2src_is_broken, "If non-zero, enable workaround for Gstreamer");
+
+/* global device data array */
+static struct bm2835_mmal_dev *gdev[MAX_BCM2835_CAMERAS];
+
+#define FPS_MIN 1
+#define FPS_MAX 90
+
+/* timeperframe: min/max and default */
+static const struct v4l2_fract
+ tpf_min = {.numerator = 1, .denominator = FPS_MAX},
+ tpf_max = {.numerator = 1, .denominator = FPS_MIN},
+ tpf_default = {.numerator = 1000, .denominator = 30000};
+
+/* video formats */
+static struct mmal_fmt formats[] = {
+ {
+ .name = "4:2:0, planar, YUV",
+ .fourcc = V4L2_PIX_FMT_YUV420,
+ .flags = 0,
+ .mmal = MMAL_ENCODING_I420,
+ .depth = 12,
+ .mmal_component = MMAL_COMPONENT_CAMERA,
+ .ybbp = 1,
+ },
+ {
+ .name = "4:2:2, packed, YUYV",
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .flags = 0,
+ .mmal = MMAL_ENCODING_YUYV,
+ .depth = 16,
+ .mmal_component = MMAL_COMPONENT_CAMERA,
+ .ybbp = 2,
+ },
+ {
+ .name = "RGB24 (LE)",
+ .fourcc = V4L2_PIX_FMT_RGB24,
+ .flags = 0,
+ .mmal = MMAL_ENCODING_RGB24,
+ .depth = 24,
+ .mmal_component = MMAL_COMPONENT_CAMERA,
+ .ybbp = 3,
+ },
+ {
+ .name = "JPEG",
+ .fourcc = V4L2_PIX_FMT_JPEG,
+ .flags = V4L2_FMT_FLAG_COMPRESSED,
+ .mmal = MMAL_ENCODING_JPEG,
+ .depth = 8,
+ .mmal_component = MMAL_COMPONENT_IMAGE_ENCODE,
+ .ybbp = 0,
+ },
+ {
+ .name = "H264",
+ .fourcc = V4L2_PIX_FMT_H264,
+ .flags = V4L2_FMT_FLAG_COMPRESSED,
+ .mmal = MMAL_ENCODING_H264,
+ .depth = 8,
+ .mmal_component = MMAL_COMPONENT_VIDEO_ENCODE,
+ .ybbp = 0,
+ },
+ {
+ .name = "MJPEG",
+ .fourcc = V4L2_PIX_FMT_MJPEG,
+ .flags = V4L2_FMT_FLAG_COMPRESSED,
+ .mmal = MMAL_ENCODING_MJPEG,
+ .depth = 8,
+ .mmal_component = MMAL_COMPONENT_VIDEO_ENCODE,
+ .ybbp = 0,
+ },
+ {
+ .name = "4:2:2, packed, YVYU",
+ .fourcc = V4L2_PIX_FMT_YVYU,
+ .flags = 0,
+ .mmal = MMAL_ENCODING_YVYU,
+ .depth = 16,
+ .mmal_component = MMAL_COMPONENT_CAMERA,
+ .ybbp = 2,
+ },
+ {
+ .name = "4:2:2, packed, VYUY",
+ .fourcc = V4L2_PIX_FMT_VYUY,
+ .flags = 0,
+ .mmal = MMAL_ENCODING_VYUY,
+ .depth = 16,
+ .mmal_component = MMAL_COMPONENT_CAMERA,
+ .ybbp = 2,
+ },
+ {
+ .name = "4:2:2, packed, UYVY",
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .flags = 0,
+ .mmal = MMAL_ENCODING_UYVY,
+ .depth = 16,
+ .mmal_component = MMAL_COMPONENT_CAMERA,
+ .ybbp = 2,
+ },
+ {
+ .name = "4:2:0, planar, NV12",
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .flags = 0,
+ .mmal = MMAL_ENCODING_NV12,
+ .depth = 12,
+ .mmal_component = MMAL_COMPONENT_CAMERA,
+ .ybbp = 1,
+ },
+ {
+ .name = "RGB24 (BE)",
+ .fourcc = V4L2_PIX_FMT_BGR24,
+ .flags = 0,
+ .mmal = MMAL_ENCODING_BGR24,
+ .depth = 24,
+ .mmal_component = MMAL_COMPONENT_CAMERA,
+ .ybbp = 3,
+ },
+ {
+ .name = "4:2:0, planar, YVU",
+ .fourcc = V4L2_PIX_FMT_YVU420,
+ .flags = 0,
+ .mmal = MMAL_ENCODING_YV12,
+ .depth = 12,
+ .mmal_component = MMAL_COMPONENT_CAMERA,
+ .ybbp = 1,
+ },
+ {
+ .name = "4:2:0, planar, NV21",
+ .fourcc = V4L2_PIX_FMT_NV21,
+ .flags = 0,
+ .mmal = MMAL_ENCODING_NV21,
+ .depth = 12,
+ .mmal_component = MMAL_COMPONENT_CAMERA,
+ .ybbp = 1,
+ },
+ {
+ .name = "RGB32 (BE)",
+ .fourcc = V4L2_PIX_FMT_BGR32,
+ .flags = 0,
+ .mmal = MMAL_ENCODING_BGRA,
+ .depth = 32,
+ .mmal_component = MMAL_COMPONENT_CAMERA,
+ .ybbp = 4,
+ },
+};
+
+static struct mmal_fmt *get_format(struct v4l2_format *f)
+{
+ struct mmal_fmt *fmt;
+ unsigned int k;
+
+ for (k = 0; k < ARRAY_SIZE(formats); k++) {
+ fmt = &formats[k];
+ if (fmt->fourcc == f->fmt.pix.pixelformat)
+ break;
+ }
+
+ if (k == ARRAY_SIZE(formats))
+ return NULL;
+
+ return &formats[k];
+}
+
+/* ------------------------------------------------------------------
+ Videobuf queue operations
+ ------------------------------------------------------------------*/
+
+static int queue_setup(struct vb2_queue *vq,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], struct device *alloc_ctxs[])
+{
+ struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vq);
+ unsigned long size;
+
+ /* refuse queue setup if port is not configured */
+ if (dev->capture.port == NULL) {
+ v4l2_err(&dev->v4l2_dev,
+ "%s: capture port not configured\n", __func__);
+ return -EINVAL;
+ }
+
+ size = dev->capture.port->current_buffer.size;
+ if (size == 0) {
+ v4l2_err(&dev->v4l2_dev,
+ "%s: capture port buffer size is zero\n", __func__);
+ return -EINVAL;
+ }
+
+ if (*nbuffers < (dev->capture.port->current_buffer.num + 2))
+ *nbuffers = (dev->capture.port->current_buffer.num + 2);
+
+ *nplanes = 1;
+
+ sizes[0] = size;
+
+ /*
+ * videobuf2-vmalloc allocator is context-less so no need to set
+ * alloc_ctxs array.
+ */
+
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p\n",
+ __func__, dev);
+
+ return 0;
+}
+
+static int buffer_prepare(struct vb2_buffer *vb)
+{
+ struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+ unsigned long size;
+
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p\n",
+ __func__, dev);
+
+ BUG_ON(dev->capture.port == NULL);
+ BUG_ON(dev->capture.fmt == NULL);
+
+ size = dev->capture.stride * dev->capture.height;
+ if (vb2_plane_size(vb, 0) < size) {
+ v4l2_err(&dev->v4l2_dev,
+ "%s data will not fit into plane (%lu < %lu)\n",
+ __func__, vb2_plane_size(vb, 0), size);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static inline bool is_capturing(struct bm2835_mmal_dev *dev)
+{
+ return dev->capture.camera_port ==
+ &dev->
+ component[MMAL_COMPONENT_CAMERA]->output[MMAL_CAMERA_PORT_CAPTURE];
+}
+
+static void buffer_cb(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_port *port,
+ int status,
+ struct mmal_buffer *buf,
+ unsigned long length, u32 mmal_flags, s64 dts, s64 pts)
+{
+ struct bm2835_mmal_dev *dev = port->cb_ctx;
+
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "%s: status:%d, buf:%p, length:%lu, flags %u, pts %lld\n",
+ __func__, status, buf, length, mmal_flags, pts);
+
+ if (status != 0) {
+ /* error in transfer */
+ if (buf != NULL) {
+ /* there was a buffer with the error so return it */
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+ }
+ return;
+ } else if (length == 0) {
+ /* stream ended */
+ if (buf != NULL) {
+ /* this should only ever happen if the port is
+ * disabled and there are buffers still queued
+ */
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+ pr_debug("Empty buffer");
+ } else if (dev->capture.frame_count) {
+ /* grab another frame */
+ if (is_capturing(dev)) {
+ pr_debug("Grab another frame");
+ vchiq_mmal_port_parameter_set(
+ instance,
+ dev->capture.
+ camera_port,
+ MMAL_PARAMETER_CAPTURE,
+ &dev->capture.
+ frame_count,
+ sizeof(dev->capture.frame_count));
+ }
+ } else {
+ /* signal frame completion */
+ complete(&dev->capture.frame_cmplt);
+ }
+ } else {
+ if (dev->capture.frame_count) {
+ if (dev->capture.vc_start_timestamp != -1 &&
+ pts != 0) {
+ struct timeval timestamp;
+ s64 runtime_us = pts -
+ dev->capture.vc_start_timestamp;
+ u32 div = 0;
+ u32 rem = 0;
+
+ div =
+ div_u64_rem(runtime_us, USEC_PER_SEC, &rem);
+ timestamp.tv_sec =
+ dev->capture.kernel_start_ts.tv_sec + div;
+ timestamp.tv_usec =
+ dev->capture.kernel_start_ts.tv_usec + rem;
+
+ if (timestamp.tv_usec >=
+ USEC_PER_SEC) {
+ timestamp.tv_sec++;
+ timestamp.tv_usec -=
+ USEC_PER_SEC;
+ }
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "Convert start time %d.%06d and %llu "
+ "with offset %llu to %d.%06d\n",
+ (int)dev->capture.kernel_start_ts.
+ tv_sec,
+ (int)dev->capture.kernel_start_ts.
+ tv_usec,
+ dev->capture.vc_start_timestamp, pts,
+ (int)timestamp.tv_sec,
+ (int)timestamp.tv_usec);
+ buf->vb.vb2_buf.timestamp = timestamp.tv_sec * 1000000000ULL +
+ timestamp.tv_usec * 1000ULL;
+ } else {
+ buf->vb.vb2_buf.timestamp = ktime_get_ns();
+ }
+
+ vb2_set_plane_payload(&buf->vb.vb2_buf, 0, length);
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
+
+ if (mmal_flags & MMAL_BUFFER_HEADER_FLAG_EOS &&
+ is_capturing(dev)) {
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "Grab another frame as buffer has EOS");
+ vchiq_mmal_port_parameter_set(
+ instance,
+ dev->capture.
+ camera_port,
+ MMAL_PARAMETER_CAPTURE,
+ &dev->capture.
+ frame_count,
+ sizeof(dev->capture.frame_count));
+ }
+ } else {
+ /* signal frame completion */
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+ complete(&dev->capture.frame_cmplt);
+ }
+ }
+}
+
+static int enable_camera(struct bm2835_mmal_dev *dev)
+{
+ int ret;
+
+ if (!dev->camera_use_count) {
+ ret = vchiq_mmal_port_parameter_set(
+ dev->instance,
+ &dev->component[MMAL_COMPONENT_CAMERA]->control,
+ MMAL_PARAMETER_CAMERA_NUM, &dev->camera_num,
+ sizeof(dev->camera_num));
+ if (ret < 0) {
+ v4l2_err(&dev->v4l2_dev,
+ "Failed setting camera num, ret %d\n", ret);
+ return -EINVAL;
+ }
+
+ ret = vchiq_mmal_component_enable(
+ dev->instance,
+ dev->component[MMAL_COMPONENT_CAMERA]);
+ if (ret < 0) {
+ v4l2_err(&dev->v4l2_dev,
+ "Failed enabling camera, ret %d\n", ret);
+ return -EINVAL;
+ }
+ }
+ dev->camera_use_count++;
+ v4l2_dbg(1, bcm2835_v4l2_debug,
+ &dev->v4l2_dev, "enabled camera (refcount %d)\n",
+ dev->camera_use_count);
+ return 0;
+}
+
+static int disable_camera(struct bm2835_mmal_dev *dev)
+{
+ int ret;
+
+ if (!dev->camera_use_count) {
+ v4l2_err(&dev->v4l2_dev,
+ "Disabled the camera when already disabled\n");
+ return -EINVAL;
+ }
+ dev->camera_use_count--;
+ if (!dev->camera_use_count) {
+ unsigned int i = 0xFFFFFFFF;
+
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "Disabling camera\n");
+ ret =
+ vchiq_mmal_component_disable(
+ dev->instance,
+ dev->component[MMAL_COMPONENT_CAMERA]);
+ if (ret < 0) {
+ v4l2_err(&dev->v4l2_dev,
+ "Failed disabling camera, ret %d\n", ret);
+ return -EINVAL;
+ }
+ vchiq_mmal_port_parameter_set(
+ dev->instance,
+ &dev->component[MMAL_COMPONENT_CAMERA]->control,
+ MMAL_PARAMETER_CAMERA_NUM, &i,
+ sizeof(i));
+ }
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "Camera refcount now %d\n", dev->camera_use_count);
+ return 0;
+}
+
+static void buffer_queue(struct vb2_buffer *vb)
+{
+ struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+ struct vb2_v4l2_buffer *vb2 = to_vb2_v4l2_buffer(vb);
+ struct mmal_buffer *buf = container_of(vb2, struct mmal_buffer, vb);
+ int ret;
+
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "%s: dev:%p buf:%p\n", __func__, dev, buf);
+
+ buf->buffer = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
+ buf->buffer_size = vb2_plane_size(&buf->vb.vb2_buf, 0);
+
+ ret = vchiq_mmal_submit_buffer(dev->instance, dev->capture.port, buf);
+ if (ret < 0)
+ v4l2_err(&dev->v4l2_dev, "%s: error submitting buffer\n",
+ __func__);
+}
+
+static int start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+ struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vq);
+ int ret;
+ int parameter_size;
+
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p\n",
+ __func__, dev);
+
+ /* ensure a format has actually been set */
+ if (dev->capture.port == NULL)
+ return -EINVAL;
+
+ if (enable_camera(dev) < 0) {
+ v4l2_err(&dev->v4l2_dev, "Failed to enable camera\n");
+ return -EINVAL;
+ }
+
+ /*init_completion(&dev->capture.frame_cmplt); */
+
+ /* enable frame capture */
+ dev->capture.frame_count = 1;
+
+ /* if the preview is not already running, wait for a few frames for AGC
+ * to settle down.
+ */
+ if (!dev->component[MMAL_COMPONENT_PREVIEW]->enabled)
+ msleep(300);
+
+ /* enable the connection from camera to encoder (if applicable) */
+ if (dev->capture.camera_port != dev->capture.port
+ && dev->capture.camera_port) {
+ ret = vchiq_mmal_port_enable(dev->instance,
+ dev->capture.camera_port, NULL);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev,
+ "Failed to enable encode tunnel - error %d\n",
+ ret);
+ return -1;
+ }
+ }
+
+ /* Get VC timestamp at this point in time */
+ parameter_size = sizeof(dev->capture.vc_start_timestamp);
+ if (vchiq_mmal_port_parameter_get(dev->instance,
+ dev->capture.camera_port,
+ MMAL_PARAMETER_SYSTEM_TIME,
+ &dev->capture.vc_start_timestamp,
+ ¶meter_size)) {
+ v4l2_err(&dev->v4l2_dev,
+ "Failed to get VC start time - update your VC f/w\n");
+
+ /* Flag to indicate just to rely on kernel timestamps */
+ dev->capture.vc_start_timestamp = -1;
+ } else
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "Start time %lld size %d\n",
+ dev->capture.vc_start_timestamp, parameter_size);
+
+ v4l2_get_timestamp(&dev->capture.kernel_start_ts);
+
+ /* enable the camera port */
+ dev->capture.port->cb_ctx = dev;
+ ret =
+ vchiq_mmal_port_enable(dev->instance, dev->capture.port, buffer_cb);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev,
+ "Failed to enable capture port - error %d. "
+ "Disabling camera port again\n", ret);
+
+ vchiq_mmal_port_disable(dev->instance,
+ dev->capture.camera_port);
+ if (disable_camera(dev) < 0) {
+ v4l2_err(&dev->v4l2_dev, "Failed to disable camera\n");
+ return -EINVAL;
+ }
+ return -1;
+ }
+
+ /* capture the first frame */
+ vchiq_mmal_port_parameter_set(dev->instance,
+ dev->capture.camera_port,
+ MMAL_PARAMETER_CAPTURE,
+ &dev->capture.frame_count,
+ sizeof(dev->capture.frame_count));
+ return 0;
+}
+
+/* abort streaming and wait for last buffer */
+static void stop_streaming(struct vb2_queue *vq)
+{
+ int ret;
+ struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vq);
+
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p\n",
+ __func__, dev);
+
+ init_completion(&dev->capture.frame_cmplt);
+ dev->capture.frame_count = 0;
+
+ /* ensure a format has actually been set */
+ if (dev->capture.port == NULL) {
+ v4l2_err(&dev->v4l2_dev,
+ "no capture port - stream not started?\n");
+ return;
+ }
+
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "stopping capturing\n");
+
+ /* stop capturing frames */
+ vchiq_mmal_port_parameter_set(dev->instance,
+ dev->capture.camera_port,
+ MMAL_PARAMETER_CAPTURE,
+ &dev->capture.frame_count,
+ sizeof(dev->capture.frame_count));
+
+ /* wait for last frame to complete */
+ ret = wait_for_completion_timeout(&dev->capture.frame_cmplt, HZ);
+ if (ret <= 0)
+ v4l2_err(&dev->v4l2_dev,
+ "error %d waiting for frame completion\n", ret);
+
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "disabling connection\n");
+
+ /* disable the connection from camera to encoder */
+ ret = vchiq_mmal_port_disable(dev->instance, dev->capture.camera_port);
+ if (!ret && dev->capture.camera_port != dev->capture.port) {
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "disabling port\n");
+ ret = vchiq_mmal_port_disable(dev->instance, dev->capture.port);
+ } else if (dev->capture.camera_port != dev->capture.port) {
+ v4l2_err(&dev->v4l2_dev, "port_disable failed, error %d\n",
+ ret);
+ }
+
+ if (disable_camera(dev) < 0)
+ v4l2_err(&dev->v4l2_dev, "Failed to disable camera\n");
+}
+
+static void bm2835_mmal_lock(struct vb2_queue *vq)
+{
+ struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vq);
+
+ mutex_lock(&dev->mutex);
+}
+
+static void bm2835_mmal_unlock(struct vb2_queue *vq)
+{
+ struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vq);
+
+ mutex_unlock(&dev->mutex);
+}
+
+static struct vb2_ops bm2835_mmal_video_qops = {
+ .queue_setup = queue_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_queue = buffer_queue,
+ .start_streaming = start_streaming,
+ .stop_streaming = stop_streaming,
+ .wait_prepare = bm2835_mmal_unlock,
+ .wait_finish = bm2835_mmal_lock,
+};
+
+/* ------------------------------------------------------------------
+ IOCTL operations
+ ------------------------------------------------------------------*/
+
+static int set_overlay_params(struct bm2835_mmal_dev *dev,
+ struct vchiq_mmal_port *port)
+{
+ int ret;
+ struct mmal_parameter_displayregion prev_config = {
+ .set = MMAL_DISPLAY_SET_LAYER | MMAL_DISPLAY_SET_ALPHA |
+ MMAL_DISPLAY_SET_DEST_RECT | MMAL_DISPLAY_SET_FULLSCREEN,
+ .layer = PREVIEW_LAYER,
+ .alpha = dev->overlay.global_alpha,
+ .fullscreen = 0,
+ .dest_rect = {
+ .x = dev->overlay.w.left,
+ .y = dev->overlay.w.top,
+ .width = dev->overlay.w.width,
+ .height = dev->overlay.w.height,
+ },
+ };
+ ret = vchiq_mmal_port_parameter_set(dev->instance, port,
+ MMAL_PARAMETER_DISPLAYREGION,
+ &prev_config, sizeof(prev_config));
+
+ return ret;
+}
+
+/* overlay ioctl */
+static int vidioc_enum_fmt_vid_overlay(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct mmal_fmt *fmt;
+
+ if (f->index >= ARRAY_SIZE(formats))
+ return -EINVAL;
+
+ fmt = &formats[f->index];
+
+ strlcpy(f->description, fmt->name, sizeof(f->description));
+ f->pixelformat = fmt->fourcc;
+ f->flags = fmt->flags;
+
+ return 0;
+}
+
+static int vidioc_g_fmt_vid_overlay(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct bm2835_mmal_dev *dev = video_drvdata(file);
+
+ f->fmt.win = dev->overlay;
+
+ return 0;
+}
+
+static int vidioc_try_fmt_vid_overlay(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct bm2835_mmal_dev *dev = video_drvdata(file);
+
+ f->fmt.win.field = V4L2_FIELD_NONE;
+ f->fmt.win.chromakey = 0;
+ f->fmt.win.clips = NULL;
+ f->fmt.win.clipcount = 0;
+ f->fmt.win.bitmap = NULL;
+
+ v4l_bound_align_image(&f->fmt.win.w.width, MIN_WIDTH, dev->max_width, 1,
+ &f->fmt.win.w.height, MIN_HEIGHT, dev->max_height,
+ 1, 0);
+ v4l_bound_align_image(&f->fmt.win.w.left, MIN_WIDTH, dev->max_width, 1,
+ &f->fmt.win.w.top, MIN_HEIGHT, dev->max_height,
+ 1, 0);
+
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "Overlay: Now w/h %dx%d l/t %dx%d\n",
+ f->fmt.win.w.width, f->fmt.win.w.height,
+ f->fmt.win.w.left, f->fmt.win.w.top);
+
+ v4l2_dump_win_format(1,
+ bcm2835_v4l2_debug,
+ &dev->v4l2_dev,
+ &f->fmt.win,
+ __func__);
+ return 0;
+}
+
+static int vidioc_s_fmt_vid_overlay(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct bm2835_mmal_dev *dev = video_drvdata(file);
+
+ vidioc_try_fmt_vid_overlay(file, priv, f);
+
+ dev->overlay = f->fmt.win;
+ if (dev->component[MMAL_COMPONENT_PREVIEW]->enabled) {
+ set_overlay_params(dev,
+ &dev->component[MMAL_COMPONENT_PREVIEW]->input[0]);
+ }
+
+ return 0;
+}
+
+static int vidioc_overlay(struct file *file, void *f, unsigned int on)
+{
+ int ret;
+ struct bm2835_mmal_dev *dev = video_drvdata(file);
+ struct vchiq_mmal_port *src;
+ struct vchiq_mmal_port *dst;
+
+ if ((on && dev->component[MMAL_COMPONENT_PREVIEW]->enabled) ||
+ (!on && !dev->component[MMAL_COMPONENT_PREVIEW]->enabled))
+ return 0; /* already in requested state */
+
+ src =
+ &dev->component[MMAL_COMPONENT_CAMERA]->
+ output[MMAL_CAMERA_PORT_PREVIEW];
+
+ if (!on) {
+ /* disconnect preview ports and disable component */
+ ret = vchiq_mmal_port_disable(dev->instance, src);
+ if (!ret)
+ ret =
+ vchiq_mmal_port_connect_tunnel(dev->instance, src,
+ NULL);
+ if (ret >= 0)
+ ret = vchiq_mmal_component_disable(
+ dev->instance,
+ dev->component[MMAL_COMPONENT_PREVIEW]);
+
+ disable_camera(dev);
+ return ret;
+ }
+
+ /* set preview port format and connect it to output */
+ dst = &dev->component[MMAL_COMPONENT_PREVIEW]->input[0];
+
+ ret = vchiq_mmal_port_set_format(dev->instance, src);
+ if (ret < 0)
+ goto error;
+
+ ret = set_overlay_params(dev, dst);
+ if (ret < 0)
+ goto error;
+
+ if (enable_camera(dev) < 0)
+ goto error;
+
+ ret = vchiq_mmal_component_enable(
+ dev->instance,
+ dev->component[MMAL_COMPONENT_PREVIEW]);
+ if (ret < 0)
+ goto error;
+
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "connecting %p to %p\n",
+ src, dst);
+ ret = vchiq_mmal_port_connect_tunnel(dev->instance, src, dst);
+ if (!ret)
+ ret = vchiq_mmal_port_enable(dev->instance, src, NULL);
+error:
+ return ret;
+}
+
+static int vidioc_g_fbuf(struct file *file, void *fh,
+ struct v4l2_framebuffer *a)
+{
+ /* The video overlay must stay within the framebuffer and can't be
+ positioned independently. */
+ struct bm2835_mmal_dev *dev = video_drvdata(file);
+ struct vchiq_mmal_port *preview_port =
+ &dev->component[MMAL_COMPONENT_CAMERA]->
+ output[MMAL_CAMERA_PORT_PREVIEW];
+
+ a->capability = V4L2_FBUF_CAP_EXTERNOVERLAY |
+ V4L2_FBUF_CAP_GLOBAL_ALPHA;
+ a->flags = V4L2_FBUF_FLAG_OVERLAY;
+ a->fmt.width = preview_port->es.video.width;
+ a->fmt.height = preview_port->es.video.height;
+ a->fmt.pixelformat = V4L2_PIX_FMT_YUV420;
+ a->fmt.bytesperline = preview_port->es.video.width;
+ a->fmt.sizeimage = (preview_port->es.video.width *
+ preview_port->es.video.height * 3) >> 1;
+ a->fmt.colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+ return 0;
+}
+
+/* input ioctls */
+static int vidioc_enum_input(struct file *file, void *priv,
+ struct v4l2_input *inp)
+{
+ /* only a single camera input */
+ if (inp->index != 0)
+ return -EINVAL;
+
+ inp->type = V4L2_INPUT_TYPE_CAMERA;
+ sprintf(inp->name, "Camera %u", inp->index);
+ return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ *i = 0;
+ return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+ if (i != 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+/* capture ioctls */
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct bm2835_mmal_dev *dev = video_drvdata(file);
+ u32 major;
+ u32 minor;
+
+ vchiq_mmal_version(dev->instance, &major, &minor);
+
+ strcpy(cap->driver, "bm2835 mmal");
+ snprintf(cap->card, sizeof(cap->card), "mmal service %d.%d",
+ major, minor);
+
+ snprintf(cap->bus_info, sizeof(cap->bus_info),
+ "platform:%s", dev->v4l2_dev.name);
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY |
+ V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+
+ return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct mmal_fmt *fmt;
+
+ if (f->index >= ARRAY_SIZE(formats))
+ return -EINVAL;
+
+ fmt = &formats[f->index];
+
+ strlcpy(f->description, fmt->name, sizeof(f->description));
+ f->pixelformat = fmt->fourcc;
+ f->flags = fmt->flags;
+
+ return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct bm2835_mmal_dev *dev = video_drvdata(file);
+
+ f->fmt.pix.width = dev->capture.width;
+ f->fmt.pix.height = dev->capture.height;
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+ f->fmt.pix.pixelformat = dev->capture.fmt->fourcc;
+ f->fmt.pix.bytesperline = dev->capture.stride;
+ f->fmt.pix.sizeimage = dev->capture.buffersize;
+
+ if (dev->capture.fmt->fourcc == V4L2_PIX_FMT_RGB24)
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
+ else if (dev->capture.fmt->fourcc == V4L2_PIX_FMT_JPEG)
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
+ else
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ f->fmt.pix.priv = 0;
+
+ v4l2_dump_pix_format(1, bcm2835_v4l2_debug, &dev->v4l2_dev, &f->fmt.pix,
+ __func__);
+ return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct bm2835_mmal_dev *dev = video_drvdata(file);
+ struct mmal_fmt *mfmt;
+
+ mfmt = get_format(f);
+ if (!mfmt) {
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "Fourcc format (0x%08x) unknown.\n",
+ f->fmt.pix.pixelformat);
+ f->fmt.pix.pixelformat = formats[0].fourcc;
+ mfmt = get_format(f);
+ }
+
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "Clipping/aligning %dx%d format %08X\n",
+ f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.pixelformat);
+
+ v4l_bound_align_image(&f->fmt.pix.width, MIN_WIDTH, dev->max_width, 1,
+ &f->fmt.pix.height, MIN_HEIGHT, dev->max_height,
+ 1, 0);
+ f->fmt.pix.bytesperline = f->fmt.pix.width * mfmt->ybbp;
+
+ /* Image buffer has to be padded to allow for alignment, even though
+ * we then remove that padding before delivering the buffer.
+ */
+ f->fmt.pix.sizeimage = ((f->fmt.pix.height + 15) & ~15) *
+ (((f->fmt.pix.width + 31) & ~31) * mfmt->depth) >> 3;
+
+ if ((mfmt->flags & V4L2_FMT_FLAG_COMPRESSED) &&
+ f->fmt.pix.sizeimage < MIN_BUFFER_SIZE)
+ f->fmt.pix.sizeimage = MIN_BUFFER_SIZE;
+
+ if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24)
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
+ else if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG)
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
+ else
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ f->fmt.pix.priv = 0;
+
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "Now %dx%d format %08X\n",
+ f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.pixelformat);
+
+ v4l2_dump_pix_format(1, bcm2835_v4l2_debug, &dev->v4l2_dev, &f->fmt.pix,
+ __func__);
+ return 0;
+}
+
+static int mmal_setup_components(struct bm2835_mmal_dev *dev,
+ struct v4l2_format *f)
+{
+ int ret;
+ struct vchiq_mmal_port *port = NULL, *camera_port = NULL;
+ struct vchiq_mmal_component *encode_component = NULL;
+ struct mmal_fmt *mfmt = get_format(f);
+
+ BUG_ON(!mfmt);
+
+ if (dev->capture.encode_component) {
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "vid_cap - disconnect previous tunnel\n");
+
+ /* Disconnect any previous connection */
+ vchiq_mmal_port_connect_tunnel(dev->instance,
+ dev->capture.camera_port, NULL);
+ dev->capture.camera_port = NULL;
+ ret = vchiq_mmal_component_disable(dev->instance,
+ dev->capture.
+ encode_component);
+ if (ret)
+ v4l2_err(&dev->v4l2_dev,
+ "Failed to disable encode component %d\n",
+ ret);
+
+ dev->capture.encode_component = NULL;
+ }
+ /* format dependent port setup */
+ switch (mfmt->mmal_component) {
+ case MMAL_COMPONENT_CAMERA:
+ /* Make a further decision on port based on resolution */
+ if (f->fmt.pix.width <= max_video_width
+ && f->fmt.pix.height <= max_video_height)
+ camera_port = port =
+ &dev->component[MMAL_COMPONENT_CAMERA]->
+ output[MMAL_CAMERA_PORT_VIDEO];
+ else
+ camera_port = port =
+ &dev->component[MMAL_COMPONENT_CAMERA]->
+ output[MMAL_CAMERA_PORT_CAPTURE];
+ break;
+ case MMAL_COMPONENT_IMAGE_ENCODE:
+ encode_component = dev->component[MMAL_COMPONENT_IMAGE_ENCODE];
+ port = &dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->output[0];
+ camera_port =
+ &dev->component[MMAL_COMPONENT_CAMERA]->
+ output[MMAL_CAMERA_PORT_CAPTURE];
+ break;
+ case MMAL_COMPONENT_VIDEO_ENCODE:
+ encode_component = dev->component[MMAL_COMPONENT_VIDEO_ENCODE];
+ port = &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
+ camera_port =
+ &dev->component[MMAL_COMPONENT_CAMERA]->
+ output[MMAL_CAMERA_PORT_VIDEO];
+ break;
+ default:
+ break;
+ }
+
+ if (!port)
+ return -EINVAL;
+
+ if (encode_component)
+ camera_port->format.encoding = MMAL_ENCODING_OPAQUE;
+ else
+ camera_port->format.encoding = mfmt->mmal;
+
+ if (dev->rgb_bgr_swapped) {
+ if (camera_port->format.encoding == MMAL_ENCODING_RGB24)
+ camera_port->format.encoding = MMAL_ENCODING_BGR24;
+ else if (camera_port->format.encoding == MMAL_ENCODING_BGR24)
+ camera_port->format.encoding = MMAL_ENCODING_RGB24;
+ }
+
+ camera_port->format.encoding_variant = 0;
+ camera_port->es.video.width = f->fmt.pix.width;
+ camera_port->es.video.height = f->fmt.pix.height;
+ camera_port->es.video.crop.x = 0;
+ camera_port->es.video.crop.y = 0;
+ camera_port->es.video.crop.width = f->fmt.pix.width;
+ camera_port->es.video.crop.height = f->fmt.pix.height;
+ camera_port->es.video.frame_rate.num = 0;
+ camera_port->es.video.frame_rate.den = 1;
+ camera_port->es.video.color_space = MMAL_COLOR_SPACE_JPEG_JFIF;
+
+ ret = vchiq_mmal_port_set_format(dev->instance, camera_port);
+
+ if (!ret
+ && camera_port ==
+ &dev->component[MMAL_COMPONENT_CAMERA]->
+ output[MMAL_CAMERA_PORT_VIDEO]) {
+ bool overlay_enabled =
+ !!dev->component[MMAL_COMPONENT_PREVIEW]->enabled;
+ struct vchiq_mmal_port *preview_port =
+ &dev->component[MMAL_COMPONENT_CAMERA]->
+ output[MMAL_CAMERA_PORT_PREVIEW];
+ /* Preview and encode ports need to match on resolution */
+ if (overlay_enabled) {
+ /* Need to disable the overlay before we can update
+ * the resolution
+ */
+ ret =
+ vchiq_mmal_port_disable(dev->instance,
+ preview_port);
+ if (!ret)
+ ret =
+ vchiq_mmal_port_connect_tunnel(
+ dev->instance,
+ preview_port,
+ NULL);
+ }
+ preview_port->es.video.width = f->fmt.pix.width;
+ preview_port->es.video.height = f->fmt.pix.height;
+ preview_port->es.video.crop.x = 0;
+ preview_port->es.video.crop.y = 0;
+ preview_port->es.video.crop.width = f->fmt.pix.width;
+ preview_port->es.video.crop.height = f->fmt.pix.height;
+ preview_port->es.video.frame_rate.num =
+ dev->capture.timeperframe.denominator;
+ preview_port->es.video.frame_rate.den =
+ dev->capture.timeperframe.numerator;
+ ret = vchiq_mmal_port_set_format(dev->instance, preview_port);
+ if (overlay_enabled) {
+ ret = vchiq_mmal_port_connect_tunnel(
+ dev->instance,
+ preview_port,
+ &dev->component[MMAL_COMPONENT_PREVIEW]->input[0]);
+ if (!ret)
+ ret = vchiq_mmal_port_enable(dev->instance,
+ preview_port,
+ NULL);
+ }
+ }
+
+ if (ret) {
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "%s failed to set format %dx%d %08X\n", __func__,
+ f->fmt.pix.width, f->fmt.pix.height,
+ f->fmt.pix.pixelformat);
+ /* ensure capture is not going to be tried */
+ dev->capture.port = NULL;
+ } else {
+ if (encode_component) {
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "vid_cap - set up encode comp\n");
+
+ /* configure buffering */
+ camera_port->current_buffer.size =
+ camera_port->recommended_buffer.size;
+ camera_port->current_buffer.num =
+ camera_port->recommended_buffer.num;
+
+ ret =
+ vchiq_mmal_port_connect_tunnel(
+ dev->instance,
+ camera_port,
+ &encode_component->input[0]);
+ if (ret) {
+ v4l2_dbg(1, bcm2835_v4l2_debug,
+ &dev->v4l2_dev,
+ "%s failed to create connection\n",
+ __func__);
+ /* ensure capture is not going to be tried */
+ dev->capture.port = NULL;
+ } else {
+ port->es.video.width = f->fmt.pix.width;
+ port->es.video.height = f->fmt.pix.height;
+ port->es.video.crop.x = 0;
+ port->es.video.crop.y = 0;
+ port->es.video.crop.width = f->fmt.pix.width;
+ port->es.video.crop.height = f->fmt.pix.height;
+ port->es.video.frame_rate.num =
+ dev->capture.timeperframe.denominator;
+ port->es.video.frame_rate.den =
+ dev->capture.timeperframe.numerator;
+
+ port->format.encoding = mfmt->mmal;
+ port->format.encoding_variant = 0;
+ /* Set any encoding specific parameters */
+ switch (mfmt->mmal_component) {
+ case MMAL_COMPONENT_VIDEO_ENCODE:
+ port->format.bitrate =
+ dev->capture.encode_bitrate;
+ break;
+ case MMAL_COMPONENT_IMAGE_ENCODE:
+ /* Could set EXIF parameters here */
+ break;
+ default:
+ break;
+ }
+ ret = vchiq_mmal_port_set_format(dev->instance,
+ port);
+ if (ret)
+ v4l2_dbg(1, bcm2835_v4l2_debug,
+ &dev->v4l2_dev,
+ "%s failed to set format %dx%d fmt %08X\n",
+ __func__,
+ f->fmt.pix.width,
+ f->fmt.pix.height,
+ f->fmt.pix.pixelformat
+ );
+ }
+
+ if (!ret) {
+ ret = vchiq_mmal_component_enable(
+ dev->instance,
+ encode_component);
+ if (ret) {
+ v4l2_dbg(1, bcm2835_v4l2_debug,
+ &dev->v4l2_dev,
+ "%s Failed to enable encode components\n",
+ __func__);
+ }
+ }
+ if (!ret) {
+ /* configure buffering */
+ port->current_buffer.num = 1;
+ port->current_buffer.size =
+ f->fmt.pix.sizeimage;
+ if (port->format.encoding ==
+ MMAL_ENCODING_JPEG) {
+ v4l2_dbg(1, bcm2835_v4l2_debug,
+ &dev->v4l2_dev,
+ "JPG - buf size now %d was %d\n",
+ f->fmt.pix.sizeimage,
+ port->current_buffer.size);
+ port->current_buffer.size =
+ (f->fmt.pix.sizeimage <
+ (100 << 10))
+ ? (100 << 10) : f->fmt.pix.
+ sizeimage;
+ }
+ v4l2_dbg(1, bcm2835_v4l2_debug,
+ &dev->v4l2_dev,
+ "vid_cap - cur_buf.size set to %d\n",
+ f->fmt.pix.sizeimage);
+ port->current_buffer.alignment = 0;
+ }
+ } else {
+ /* configure buffering */
+ camera_port->current_buffer.num = 1;
+ camera_port->current_buffer.size = f->fmt.pix.sizeimage;
+ camera_port->current_buffer.alignment = 0;
+ }
+
+ if (!ret) {
+ dev->capture.fmt = mfmt;
+ dev->capture.stride = f->fmt.pix.bytesperline;
+ dev->capture.width = camera_port->es.video.crop.width;
+ dev->capture.height = camera_port->es.video.crop.height;
+ dev->capture.buffersize = port->current_buffer.size;
+
+ /* select port for capture */
+ dev->capture.port = port;
+ dev->capture.camera_port = camera_port;
+ dev->capture.encode_component = encode_component;
+ v4l2_dbg(1, bcm2835_v4l2_debug,
+ &dev->v4l2_dev,
+ "Set dev->capture.fmt %08X, %dx%d, stride %d, size %d",
+ port->format.encoding,
+ dev->capture.width, dev->capture.height,
+ dev->capture.stride, dev->capture.buffersize);
+ }
+ }
+
+ /* todo: Need to convert the vchiq/mmal error into a v4l2 error. */
+ return ret;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ int ret;
+ struct bm2835_mmal_dev *dev = video_drvdata(file);
+ struct mmal_fmt *mfmt;
+
+ /* try the format to set valid parameters */
+ ret = vidioc_try_fmt_vid_cap(file, priv, f);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev,
+ "vid_cap - vidioc_try_fmt_vid_cap failed\n");
+ return ret;
+ }
+
+ /* if a capture is running refuse to set format */
+ if (vb2_is_busy(&dev->capture.vb_vidq)) {
+ v4l2_info(&dev->v4l2_dev, "%s device busy\n", __func__);
+ return -EBUSY;
+ }
+
+ /* If the format is unsupported v4l2 says we should switch to
+ * a supported one and not return an error. */
+ mfmt = get_format(f);
+ if (!mfmt) {
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "Fourcc format (0x%08x) unknown.\n",
+ f->fmt.pix.pixelformat);
+ f->fmt.pix.pixelformat = formats[0].fourcc;
+ mfmt = get_format(f);
+ }
+
+ ret = mmal_setup_components(dev, f);
+ if (ret != 0) {
+ v4l2_err(&dev->v4l2_dev,
+ "%s: failed to setup mmal components: %d\n",
+ __func__, ret);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int vidioc_enum_framesizes(struct file *file, void *fh,
+ struct v4l2_frmsizeenum *fsize)
+{
+ struct bm2835_mmal_dev *dev = video_drvdata(file);
+ static const struct v4l2_frmsize_stepwise sizes = {
+ MIN_WIDTH, 0, 2,
+ MIN_HEIGHT, 0, 2
+ };
+ int i;
+
+ if (fsize->index)
+ return -EINVAL;
+ for (i = 0; i < ARRAY_SIZE(formats); i++)
+ if (formats[i].fourcc == fsize->pixel_format)
+ break;
+ if (i == ARRAY_SIZE(formats))
+ return -EINVAL;
+ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+ fsize->stepwise = sizes;
+ fsize->stepwise.max_width = dev->max_width;
+ fsize->stepwise.max_height = dev->max_height;
+ return 0;
+}
+
+/* timeperframe is arbitrary and continuous */
+static int vidioc_enum_frameintervals(struct file *file, void *priv,
+ struct v4l2_frmivalenum *fival)
+{
+ struct bm2835_mmal_dev *dev = video_drvdata(file);
+ int i;
+
+ if (fival->index)
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(formats); i++)
+ if (formats[i].fourcc == fival->pixel_format)
+ break;
+ if (i == ARRAY_SIZE(formats))
+ return -EINVAL;
+
+ /* regarding width & height - we support any within range */
+ if (fival->width < MIN_WIDTH || fival->width > dev->max_width ||
+ fival->height < MIN_HEIGHT || fival->height > dev->max_height)
+ return -EINVAL;
+
+ fival->type = V4L2_FRMIVAL_TYPE_CONTINUOUS;
+
+ /* fill in stepwise (step=1.0 is required by V4L2 spec) */
+ fival->stepwise.min = tpf_min;
+ fival->stepwise.max = tpf_max;
+ fival->stepwise.step = (struct v4l2_fract) {1, 1};
+
+ return 0;
+}
+
+static int vidioc_g_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *parm)
+{
+ struct bm2835_mmal_dev *dev = video_drvdata(file);
+
+ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+ parm->parm.capture.timeperframe = dev->capture.timeperframe;
+ parm->parm.capture.readbuffers = 1;
+ return 0;
+}
+
+#define FRACT_CMP(a, OP, b) \
+ ((u64)(a).numerator * (b).denominator OP \
+ (u64)(b).numerator * (a).denominator)
+
+static int vidioc_s_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *parm)
+{
+ struct bm2835_mmal_dev *dev = video_drvdata(file);
+ struct v4l2_fract tpf;
+ struct mmal_parameter_rational fps_param;
+
+ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ tpf = parm->parm.capture.timeperframe;
+
+ /* tpf: {*, 0} resets timing; clip to [min, max]*/
+ tpf = tpf.denominator ? tpf : tpf_default;
+ tpf = FRACT_CMP(tpf, <, tpf_min) ? tpf_min : tpf;
+ tpf = FRACT_CMP(tpf, >, tpf_max) ? tpf_max : tpf;
+
+ dev->capture.timeperframe = tpf;
+ parm->parm.capture.timeperframe = tpf;
+ parm->parm.capture.readbuffers = 1;
+ parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+
+ fps_param.num = 0; /* Select variable fps, and then use
+ * FPS_RANGE to select the actual limits.
+ */
+ fps_param.den = 1;
+ set_framerate_params(dev);
+
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops camera0_ioctl_ops = {
+ /* overlay */
+ .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_overlay,
+ .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_vid_overlay,
+ .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay,
+ .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay,
+ .vidioc_overlay = vidioc_overlay,
+ .vidioc_g_fbuf = vidioc_g_fbuf,
+
+ /* inputs */
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+
+ /* capture */
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+
+ /* buffer management */
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_enum_framesizes = vidioc_enum_framesizes,
+ .vidioc_enum_frameintervals = vidioc_enum_frameintervals,
+ .vidioc_g_parm = vidioc_g_parm,
+ .vidioc_s_parm = vidioc_s_parm,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+
+ .vidioc_log_status = v4l2_ctrl_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static const struct v4l2_ioctl_ops camera0_ioctl_ops_gstreamer = {
+ /* overlay */
+ .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_overlay,
+ .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_vid_overlay,
+ .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay,
+ .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay,
+ .vidioc_overlay = vidioc_overlay,
+ .vidioc_g_fbuf = vidioc_g_fbuf,
+
+ /* inputs */
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+
+ /* capture */
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+
+ /* buffer management */
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ /* Remove this function ptr to fix gstreamer bug
+ .vidioc_enum_framesizes = vidioc_enum_framesizes, */
+ .vidioc_enum_frameintervals = vidioc_enum_frameintervals,
+ .vidioc_g_parm = vidioc_g_parm,
+ .vidioc_s_parm = vidioc_s_parm,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+
+ .vidioc_log_status = v4l2_ctrl_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+/* ------------------------------------------------------------------
+ Driver init/finalise
+ ------------------------------------------------------------------*/
+
+static const struct v4l2_file_operations camera0_fops = {
+ .owner = THIS_MODULE,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
+ .read = vb2_fop_read,
+ .poll = vb2_fop_poll,
+ .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
+ .mmap = vb2_fop_mmap,
+};
+
+static struct video_device vdev_template = {
+ .name = "camera0",
+ .fops = &camera0_fops,
+ .ioctl_ops = &camera0_ioctl_ops,
+ .release = video_device_release_empty,
+};
+
+/* Returns the number of cameras, and also the max resolution supported
+ * by those cameras.
+ */
+static int get_num_cameras(struct vchiq_mmal_instance *instance,
+ unsigned int resolutions[][2], int num_resolutions)
+{
+ int ret;
+ struct vchiq_mmal_component *cam_info_component;
+ struct mmal_parameter_camera_info_t cam_info = {0};
+ int param_size = sizeof(cam_info);
+ int i;
+
+ /* create a camera_info component */
+ ret = vchiq_mmal_component_init(instance, "camera_info",
+ &cam_info_component);
+ if (ret < 0)
+ /* Unusual failure - let's guess one camera. */
+ return 1;
+
+ if (vchiq_mmal_port_parameter_get(instance,
+ &cam_info_component->control,
+ MMAL_PARAMETER_CAMERA_INFO,
+ &cam_info,
+ ¶m_size)) {
+ pr_info("Failed to get camera info\n");
+ }
+ for (i = 0;
+ i < (cam_info.num_cameras > num_resolutions ?
+ num_resolutions :
+ cam_info.num_cameras);
+ i++) {
+ resolutions[i][0] = cam_info.cameras[i].max_width;
+ resolutions[i][1] = cam_info.cameras[i].max_height;
+ }
+
+ vchiq_mmal_component_finalise(instance,
+ cam_info_component);
+
+ return cam_info.num_cameras;
+}
+
+static int set_camera_parameters(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_component *camera,
+ struct bm2835_mmal_dev *dev)
+{
+ int ret;
+ struct mmal_parameter_camera_config cam_config = {
+ .max_stills_w = dev->max_width,
+ .max_stills_h = dev->max_height,
+ .stills_yuv422 = 1,
+ .one_shot_stills = 1,
+ .max_preview_video_w = (max_video_width > 1920) ?
+ max_video_width : 1920,
+ .max_preview_video_h = (max_video_height > 1088) ?
+ max_video_height : 1088,
+ .num_preview_video_frames = 3,
+ .stills_capture_circular_buffer_height = 0,
+ .fast_preview_resume = 0,
+ .use_stc_timestamp = MMAL_PARAM_TIMESTAMP_MODE_RAW_STC
+ };
+
+ ret = vchiq_mmal_port_parameter_set(instance, &camera->control,
+ MMAL_PARAMETER_CAMERA_CONFIG,
+ &cam_config, sizeof(cam_config));
+ return ret;
+}
+
+#define MAX_SUPPORTED_ENCODINGS 20
+
+/* MMAL instance and component init */
+static int __init mmal_init(struct bm2835_mmal_dev *dev)
+{
+ int ret;
+ struct mmal_es_format *format;
+ u32 bool_true = 1;
+ u32 supported_encodings[MAX_SUPPORTED_ENCODINGS];
+ int param_size;
+ struct vchiq_mmal_component *camera;
+
+ ret = vchiq_mmal_init(&dev->instance);
+ if (ret < 0)
+ return ret;
+
+ /* get the camera component ready */
+ ret = vchiq_mmal_component_init(dev->instance, "ril.camera",
+ &dev->component[MMAL_COMPONENT_CAMERA]);
+ if (ret < 0)
+ goto unreg_mmal;
+
+ camera = dev->component[MMAL_COMPONENT_CAMERA];
+ if (camera->outputs < MMAL_CAMERA_PORT_COUNT) {
+ ret = -EINVAL;
+ goto unreg_camera;
+ }
+
+ ret = set_camera_parameters(dev->instance,
+ camera,
+ dev);
+ if (ret < 0)
+ goto unreg_camera;
+
+ /* There was an error in the firmware that meant the camera component
+ * produced BGR instead of RGB.
+ * This is now fixed, but in order to support the old firmwares, we
+ * have to check.
+ */
+ dev->rgb_bgr_swapped = true;
+ param_size = sizeof(supported_encodings);
+ ret = vchiq_mmal_port_parameter_get(dev->instance,
+ &camera->output[MMAL_CAMERA_PORT_CAPTURE],
+ MMAL_PARAMETER_SUPPORTED_ENCODINGS,
+ &supported_encodings,
+ ¶m_size);
+ if (ret == 0) {
+ int i;
+
+ for (i = 0; i < param_size / sizeof(u32); i++) {
+ if (supported_encodings[i] == MMAL_ENCODING_BGR24) {
+ /* Found BGR24 first - old firmware. */
+ break;
+ }
+ if (supported_encodings[i] == MMAL_ENCODING_RGB24) {
+ /* Found RGB24 first
+ * new firmware, so use RGB24.
+ */
+ dev->rgb_bgr_swapped = false;
+ break;
+ }
+ }
+ }
+ format = &camera->output[MMAL_CAMERA_PORT_PREVIEW].format;
+
+ format->encoding = MMAL_ENCODING_OPAQUE;
+ format->encoding_variant = MMAL_ENCODING_I420;
+
+ format->es->video.width = 1024;
+ format->es->video.height = 768;
+ format->es->video.crop.x = 0;
+ format->es->video.crop.y = 0;
+ format->es->video.crop.width = 1024;
+ format->es->video.crop.height = 768;
+ format->es->video.frame_rate.num = 0; /* Rely on fps_range */
+ format->es->video.frame_rate.den = 1;
+
+ format = &camera->output[MMAL_CAMERA_PORT_VIDEO].format;
+
+ format->encoding = MMAL_ENCODING_OPAQUE;
+ format->encoding_variant = MMAL_ENCODING_I420;
+
+ format->es->video.width = 1024;
+ format->es->video.height = 768;
+ format->es->video.crop.x = 0;
+ format->es->video.crop.y = 0;
+ format->es->video.crop.width = 1024;
+ format->es->video.crop.height = 768;
+ format->es->video.frame_rate.num = 0; /* Rely on fps_range */
+ format->es->video.frame_rate.den = 1;
+
+ vchiq_mmal_port_parameter_set(dev->instance,
+ &camera->output[MMAL_CAMERA_PORT_VIDEO],
+ MMAL_PARAMETER_NO_IMAGE_PADDING,
+ &bool_true, sizeof(bool_true));
+
+ format = &camera->output[MMAL_CAMERA_PORT_CAPTURE].format;
+
+ format->encoding = MMAL_ENCODING_OPAQUE;
+
+ format->es->video.width = 2592;
+ format->es->video.height = 1944;
+ format->es->video.crop.x = 0;
+ format->es->video.crop.y = 0;
+ format->es->video.crop.width = 2592;
+ format->es->video.crop.height = 1944;
+ format->es->video.frame_rate.num = 0; /* Rely on fps_range */
+ format->es->video.frame_rate.den = 1;
+
+ dev->capture.width = format->es->video.width;
+ dev->capture.height = format->es->video.height;
+ dev->capture.fmt = &formats[0];
+ dev->capture.encode_component = NULL;
+ dev->capture.timeperframe = tpf_default;
+ dev->capture.enc_profile = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH;
+ dev->capture.enc_level = V4L2_MPEG_VIDEO_H264_LEVEL_4_0;
+
+ vchiq_mmal_port_parameter_set(dev->instance,
+ &camera->output[MMAL_CAMERA_PORT_CAPTURE],
+ MMAL_PARAMETER_NO_IMAGE_PADDING,
+ &bool_true, sizeof(bool_true));
+
+ /* get the preview component ready */
+ ret = vchiq_mmal_component_init(
+ dev->instance, "ril.video_render",
+ &dev->component[MMAL_COMPONENT_PREVIEW]);
+ if (ret < 0)
+ goto unreg_camera;
+
+ if (dev->component[MMAL_COMPONENT_PREVIEW]->inputs < 1) {
+ ret = -EINVAL;
+ pr_debug("too few input ports %d needed %d\n",
+ dev->component[MMAL_COMPONENT_PREVIEW]->inputs, 1);
+ goto unreg_preview;
+ }
+
+ /* get the image encoder component ready */
+ ret = vchiq_mmal_component_init(
+ dev->instance, "ril.image_encode",
+ &dev->component[MMAL_COMPONENT_IMAGE_ENCODE]);
+ if (ret < 0)
+ goto unreg_preview;
+
+ if (dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->inputs < 1) {
+ ret = -EINVAL;
+ v4l2_err(&dev->v4l2_dev, "too few input ports %d needed %d\n",
+ dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->inputs,
+ 1);
+ goto unreg_image_encoder;
+ }
+
+ /* get the video encoder component ready */
+ ret = vchiq_mmal_component_init(dev->instance, "ril.video_encode",
+ &dev->
+ component[MMAL_COMPONENT_VIDEO_ENCODE]);
+ if (ret < 0)
+ goto unreg_image_encoder;
+
+ if (dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->inputs < 1) {
+ ret = -EINVAL;
+ v4l2_err(&dev->v4l2_dev, "too few input ports %d needed %d\n",
+ dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->inputs,
+ 1);
+ goto unreg_vid_encoder;
+ }
+
+ {
+ struct vchiq_mmal_port *encoder_port =
+ &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
+ encoder_port->format.encoding = MMAL_ENCODING_H264;
+ ret = vchiq_mmal_port_set_format(dev->instance,
+ encoder_port);
+ }
+
+ {
+ unsigned int enable = 1;
+
+ vchiq_mmal_port_parameter_set(
+ dev->instance,
+ &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->control,
+ MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT,
+ &enable, sizeof(enable));
+
+ vchiq_mmal_port_parameter_set(dev->instance,
+ &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->control,
+ MMAL_PARAMETER_MINIMISE_FRAGMENTATION,
+ &enable,
+ sizeof(enable));
+ }
+ ret = bm2835_mmal_set_all_camera_controls(dev);
+ if (ret < 0)
+ goto unreg_vid_encoder;
+
+ return 0;
+
+unreg_vid_encoder:
+ pr_err("Cleanup: Destroy video encoder\n");
+ vchiq_mmal_component_finalise(
+ dev->instance,
+ dev->component[MMAL_COMPONENT_VIDEO_ENCODE]);
+
+unreg_image_encoder:
+ pr_err("Cleanup: Destroy image encoder\n");
+ vchiq_mmal_component_finalise(
+ dev->instance,
+ dev->component[MMAL_COMPONENT_IMAGE_ENCODE]);
+
+unreg_preview:
+ pr_err("Cleanup: Destroy video render\n");
+ vchiq_mmal_component_finalise(dev->instance,
+ dev->component[MMAL_COMPONENT_PREVIEW]);
+
+unreg_camera:
+ pr_err("Cleanup: Destroy camera\n");
+ vchiq_mmal_component_finalise(dev->instance,
+ dev->component[MMAL_COMPONENT_CAMERA]);
+
+unreg_mmal:
+ vchiq_mmal_finalise(dev->instance);
+ return ret;
+}
+
+static int __init bm2835_mmal_init_device(struct bm2835_mmal_dev *dev,
+ struct video_device *vfd)
+{
+ int ret;
+
+ *vfd = vdev_template;
+ if (gst_v4l2src_is_broken) {
+ v4l2_info(&dev->v4l2_dev,
+ "Work-around for gstreamer issue is active.\n");
+ vfd->ioctl_ops = &camera0_ioctl_ops_gstreamer;
+ }
+
+ vfd->v4l2_dev = &dev->v4l2_dev;
+
+ vfd->lock = &dev->mutex;
+
+ vfd->queue = &dev->capture.vb_vidq;
+
+ /* video device needs to be able to access instance data */
+ video_set_drvdata(vfd, dev);
+
+ ret = video_register_device(vfd,
+ VFL_TYPE_GRABBER,
+ video_nr[dev->camera_num]);
+ if (ret < 0)
+ return ret;
+
+ v4l2_info(vfd->v4l2_dev,
+ "V4L2 device registered as %s - stills mode > %dx%d\n",
+ video_device_node_name(vfd),
+ max_video_width, max_video_height);
+
+ return 0;
+}
+
+static void bcm2835_cleanup_instance(struct bm2835_mmal_dev *dev)
+{
+ if (!dev)
+ return;
+
+ v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
+ video_device_node_name(&dev->vdev));
+
+ video_unregister_device(&dev->vdev);
+
+ if (dev->capture.encode_component) {
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "mmal_exit - disconnect tunnel\n");
+ vchiq_mmal_port_connect_tunnel(dev->instance,
+ dev->capture.camera_port, NULL);
+ vchiq_mmal_component_disable(dev->instance,
+ dev->capture.encode_component);
+ }
+ vchiq_mmal_component_disable(dev->instance,
+ dev->component[MMAL_COMPONENT_CAMERA]);
+
+ vchiq_mmal_component_finalise(dev->instance,
+ dev->
+ component[MMAL_COMPONENT_VIDEO_ENCODE]);
+
+ vchiq_mmal_component_finalise(dev->instance,
+ dev->
+ component[MMAL_COMPONENT_IMAGE_ENCODE]);
+
+ vchiq_mmal_component_finalise(dev->instance,
+ dev->component[MMAL_COMPONENT_PREVIEW]);
+
+ vchiq_mmal_component_finalise(dev->instance,
+ dev->component[MMAL_COMPONENT_CAMERA]);
+
+ v4l2_ctrl_handler_free(&dev->ctrl_handler);
+
+ v4l2_device_unregister(&dev->v4l2_dev);
+
+ kfree(dev);
+}
+
+static struct v4l2_format default_v4l2_format = {
+ .fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG,
+ .fmt.pix.width = 1024,
+ .fmt.pix.bytesperline = 0,
+ .fmt.pix.height = 768,
+ .fmt.pix.sizeimage = 1024 * 768,
+};
+
+static int __init bm2835_mmal_init(void)
+{
+ int ret;
+ struct bm2835_mmal_dev *dev;
+ struct vb2_queue *q;
+ int camera;
+ unsigned int num_cameras;
+ struct vchiq_mmal_instance *instance;
+ unsigned int resolutions[MAX_BCM2835_CAMERAS][2];
+
+ ret = vchiq_mmal_init(&instance);
+ if (ret < 0)
+ return ret;
+
+ num_cameras = get_num_cameras(instance,
+ resolutions,
+ MAX_BCM2835_CAMERAS);
+ if (num_cameras > MAX_BCM2835_CAMERAS)
+ num_cameras = MAX_BCM2835_CAMERAS;
+
+ for (camera = 0; camera < num_cameras; camera++) {
+ dev = kzalloc(sizeof(struct bm2835_mmal_dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ dev->camera_num = camera;
+ dev->max_width = resolutions[camera][0];
+ dev->max_height = resolutions[camera][1];
+
+ /* setup device defaults */
+ dev->overlay.w.left = 150;
+ dev->overlay.w.top = 50;
+ dev->overlay.w.width = 1024;
+ dev->overlay.w.height = 768;
+ dev->overlay.clipcount = 0;
+ dev->overlay.field = V4L2_FIELD_NONE;
+ dev->overlay.global_alpha = 255;
+
+ dev->capture.fmt = &formats[3]; /* JPEG */
+
+ /* v4l device registration */
+ snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
+ "%s", BM2835_MMAL_MODULE_NAME);
+ ret = v4l2_device_register(NULL, &dev->v4l2_dev);
+ if (ret)
+ goto free_dev;
+
+ /* setup v4l controls */
+ ret = bm2835_mmal_init_controls(dev, &dev->ctrl_handler);
+ if (ret < 0)
+ goto unreg_dev;
+ dev->v4l2_dev.ctrl_handler = &dev->ctrl_handler;
+
+ /* mmal init */
+ dev->instance = instance;
+ ret = mmal_init(dev);
+ if (ret < 0)
+ goto unreg_dev;
+
+ /* initialize queue */
+ q = &dev->capture.vb_vidq;
+ memset(q, 0, sizeof(*q));
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
+ q->drv_priv = dev;
+ q->buf_struct_size = sizeof(struct mmal_buffer);
+ q->ops = &bm2835_mmal_video_qops;
+ q->mem_ops = &vb2_vmalloc_memops;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ ret = vb2_queue_init(q);
+ if (ret < 0)
+ goto unreg_dev;
+
+ /* v4l2 core mutex used to protect all fops and v4l2 ioctls. */
+ mutex_init(&dev->mutex);
+
+ /* initialise video devices */
+ ret = bm2835_mmal_init_device(dev, &dev->vdev);
+ if (ret < 0)
+ goto unreg_dev;
+
+ /* Really want to call vidioc_s_fmt_vid_cap with the default
+ * format, but currently the APIs don't join up.
+ */
+ ret = mmal_setup_components(dev, &default_v4l2_format);
+ if (ret < 0) {
+ v4l2_err(&dev->v4l2_dev,
+ "%s: could not setup components\n", __func__);
+ goto unreg_dev;
+ }
+
+ v4l2_info(&dev->v4l2_dev,
+ "Broadcom 2835 MMAL video capture ver %s loaded.\n",
+ BM2835_MMAL_VERSION);
+
+ gdev[camera] = dev;
+ }
+ return 0;
+
+unreg_dev:
+ v4l2_ctrl_handler_free(&dev->ctrl_handler);
+ v4l2_device_unregister(&dev->v4l2_dev);
+
+free_dev:
+ kfree(dev);
+
+ for ( ; camera > 0; camera--) {
+ bcm2835_cleanup_instance(gdev[camera]);
+ gdev[camera] = NULL;
+ }
+ pr_info("%s: error %d while loading driver\n",
+ BM2835_MMAL_MODULE_NAME, ret);
+
+ return ret;
+}
+
+static void __exit bm2835_mmal_exit(void)
+{
+ int camera;
+ struct vchiq_mmal_instance *instance = gdev[0]->instance;
+
+ for (camera = 0; camera < MAX_BCM2835_CAMERAS; camera++) {
+ bcm2835_cleanup_instance(gdev[camera]);
+ gdev[camera] = NULL;
+ }
+ vchiq_mmal_finalise(instance);
+}
+
+module_init(bm2835_mmal_init);
+module_exit(bm2835_mmal_exit);
--- /dev/null
+/*
+ * Broadcom BM2835 V4L2 driver
+ *
+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
+ * Dave Stevenson <dsteve@broadcom.com>
+ * Simon Mellor <simellor@broadcom.com>
+ * Luke Diamand <luked@broadcom.com>
+ *
+ * core driver device
+ */
+
+#define V4L2_CTRL_COUNT 29 /* number of v4l controls */
+
+enum {
+ MMAL_COMPONENT_CAMERA = 0,
+ MMAL_COMPONENT_PREVIEW,
+ MMAL_COMPONENT_IMAGE_ENCODE,
+ MMAL_COMPONENT_VIDEO_ENCODE,
+ MMAL_COMPONENT_COUNT
+};
+
+enum {
+ MMAL_CAMERA_PORT_PREVIEW = 0,
+ MMAL_CAMERA_PORT_VIDEO,
+ MMAL_CAMERA_PORT_CAPTURE,
+ MMAL_CAMERA_PORT_COUNT
+};
+
+#define PREVIEW_LAYER 2
+
+extern int bcm2835_v4l2_debug;
+
+struct bm2835_mmal_dev {
+ /* v4l2 devices */
+ struct v4l2_device v4l2_dev;
+ struct video_device vdev;
+ struct mutex mutex;
+
+ /* controls */
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct v4l2_ctrl *ctrls[V4L2_CTRL_COUNT];
+ enum v4l2_scene_mode scene_mode;
+ struct mmal_colourfx colourfx;
+ int hflip;
+ int vflip;
+ int red_gain;
+ int blue_gain;
+ enum mmal_parameter_exposuremode exposure_mode_user;
+ enum v4l2_exposure_auto_type exposure_mode_v4l2_user;
+ /* active exposure mode may differ if selected via a scene mode */
+ enum mmal_parameter_exposuremode exposure_mode_active;
+ enum mmal_parameter_exposuremeteringmode metering_mode;
+ unsigned int manual_shutter_speed;
+ bool exp_auto_priority;
+ bool manual_iso_enabled;
+ uint32_t iso;
+
+ /* allocated mmal instance and components */
+ struct vchiq_mmal_instance *instance;
+ struct vchiq_mmal_component *component[MMAL_COMPONENT_COUNT];
+ int camera_use_count;
+
+ struct v4l2_window overlay;
+
+ struct {
+ unsigned int width; /* width */
+ unsigned int height; /* height */
+ unsigned int stride; /* stride */
+ unsigned int buffersize; /* buffer size with padding */
+ struct mmal_fmt *fmt;
+ struct v4l2_fract timeperframe;
+
+ /* H264 encode bitrate */
+ int encode_bitrate;
+ /* H264 bitrate mode. CBR/VBR */
+ int encode_bitrate_mode;
+ /* H264 profile */
+ enum v4l2_mpeg_video_h264_profile enc_profile;
+ /* H264 level */
+ enum v4l2_mpeg_video_h264_level enc_level;
+ /* JPEG Q-factor */
+ int q_factor;
+
+ struct vb2_queue vb_vidq;
+
+ /* VC start timestamp for streaming */
+ s64 vc_start_timestamp;
+ /* Kernel start timestamp for streaming */
+ struct timeval kernel_start_ts;
+
+ struct vchiq_mmal_port *port; /* port being used for capture */
+ /* camera port being used for capture */
+ struct vchiq_mmal_port *camera_port;
+ /* component being used for encode */
+ struct vchiq_mmal_component *encode_component;
+ /* number of frames remaining which driver should capture */
+ unsigned int frame_count;
+ /* last frame completion */
+ struct completion frame_cmplt;
+
+ } capture;
+
+ unsigned int camera_num;
+ unsigned int max_width;
+ unsigned int max_height;
+ unsigned int rgb_bgr_swapped;
+};
+
+int bm2835_mmal_init_controls(
+ struct bm2835_mmal_dev *dev,
+ struct v4l2_ctrl_handler *hdl);
+
+int bm2835_mmal_set_all_camera_controls(struct bm2835_mmal_dev *dev);
+int set_framerate_params(struct bm2835_mmal_dev *dev);
+
+/* Debug helpers */
+
+#define v4l2_dump_pix_format(level, debug, dev, pix_fmt, desc) \
+{ \
+ v4l2_dbg(level, debug, dev, \
+"%s: w %u h %u field %u pfmt 0x%x bpl %u sz_img %u colorspace 0x%x priv %u\n", \
+ desc == NULL ? "" : desc, \
+ (pix_fmt)->width, (pix_fmt)->height, (pix_fmt)->field, \
+ (pix_fmt)->pixelformat, (pix_fmt)->bytesperline, \
+ (pix_fmt)->sizeimage, (pix_fmt)->colorspace, (pix_fmt)->priv); \
+}
+#define v4l2_dump_win_format(level, debug, dev, win_fmt, desc) \
+{ \
+ v4l2_dbg(level, debug, dev, \
+"%s: w %u h %u l %u t %u field %u chromakey %06X clip %p " \
+"clipcount %u bitmap %p\n", \
+ desc == NULL ? "" : desc, \
+ (win_fmt)->w.width, (win_fmt)->w.height, \
+ (win_fmt)->w.left, (win_fmt)->w.top, \
+ (win_fmt)->field, \
+ (win_fmt)->chromakey, \
+ (win_fmt)->clips, (win_fmt)->clipcount, \
+ (win_fmt)->bitmap); \
+}
--- /dev/null
+/*
+ * Broadcom BM2835 V4L2 driver
+ *
+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
+ * Dave Stevenson <dsteve@broadcom.com>
+ * Simon Mellor <simellor@broadcom.com>
+ * Luke Diamand <luked@broadcom.com>
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <media/videobuf2-vmalloc.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-common.h>
+
+#include "mmal-common.h"
+#include "mmal-vchiq.h"
+#include "mmal-parameters.h"
+#include "bcm2835-camera.h"
+
+/* The supported V4L2_CID_AUTO_EXPOSURE_BIAS values are from -4.0 to +4.0.
+ * MMAL values are in 1/6th increments so the MMAL range is -24 to +24.
+ * V4L2 docs say value "is expressed in terms of EV, drivers should interpret
+ * the values as 0.001 EV units, where the value 1000 stands for +1 EV."
+ * V4L2 is limited to a max of 32 values in a menu, so count in 1/3rds from
+ * -4 to +4
+ */
+static const s64 ev_bias_qmenu[] = {
+ -4000, -3667, -3333,
+ -3000, -2667, -2333,
+ -2000, -1667, -1333,
+ -1000, -667, -333,
+ 0, 333, 667,
+ 1000, 1333, 1667,
+ 2000, 2333, 2667,
+ 3000, 3333, 3667,
+ 4000
+};
+
+/* Supported ISO values (*1000)
+ * ISOO = auto ISO
+ */
+static const s64 iso_qmenu[] = {
+ 0, 100000, 200000, 400000, 800000,
+};
+static const uint32_t iso_values[] = {
+ 0, 100, 200, 400, 800,
+};
+
+static const s64 mains_freq_qmenu[] = {
+ V4L2_CID_POWER_LINE_FREQUENCY_DISABLED,
+ V4L2_CID_POWER_LINE_FREQUENCY_50HZ,
+ V4L2_CID_POWER_LINE_FREQUENCY_60HZ,
+ V4L2_CID_POWER_LINE_FREQUENCY_AUTO
+};
+
+/* Supported video encode modes */
+static const s64 bitrate_mode_qmenu[] = {
+ (s64)V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+ (s64)V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
+};
+
+enum bm2835_mmal_ctrl_type {
+ MMAL_CONTROL_TYPE_STD,
+ MMAL_CONTROL_TYPE_STD_MENU,
+ MMAL_CONTROL_TYPE_INT_MENU,
+ MMAL_CONTROL_TYPE_CLUSTER, /* special cluster entry */
+};
+
+struct bm2835_mmal_v4l2_ctrl;
+
+typedef int(bm2835_mmal_v4l2_ctrl_cb)(
+ struct bm2835_mmal_dev *dev,
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl);
+
+struct bm2835_mmal_v4l2_ctrl {
+ u32 id; /* v4l2 control identifier */
+ enum bm2835_mmal_ctrl_type type;
+ /* control minimum value or
+ * mask for MMAL_CONTROL_TYPE_STD_MENU */
+ s32 min;
+ s32 max; /* maximum value of control */
+ s32 def; /* default value of control */
+ s32 step; /* step size of the control */
+ const s64 *imenu; /* integer menu array */
+ u32 mmal_id; /* mmal parameter id */
+ bm2835_mmal_v4l2_ctrl_cb *setter;
+ bool ignore_errors;
+};
+
+struct v4l2_to_mmal_effects_setting {
+ u32 v4l2_effect;
+ u32 mmal_effect;
+ s32 col_fx_enable;
+ s32 col_fx_fixed_cbcr;
+ u32 u;
+ u32 v;
+ u32 num_effect_params;
+ u32 effect_params[MMAL_MAX_IMAGEFX_PARAMETERS];
+};
+
+static const struct v4l2_to_mmal_effects_setting
+ v4l2_to_mmal_effects_values[] = {
+ { V4L2_COLORFX_NONE, MMAL_PARAM_IMAGEFX_NONE,
+ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
+ { V4L2_COLORFX_BW, MMAL_PARAM_IMAGEFX_NONE,
+ 1, 0, 128, 128, 0, {0, 0, 0, 0, 0} },
+ { V4L2_COLORFX_SEPIA, MMAL_PARAM_IMAGEFX_NONE,
+ 1, 0, 87, 151, 0, {0, 0, 0, 0, 0} },
+ { V4L2_COLORFX_NEGATIVE, MMAL_PARAM_IMAGEFX_NEGATIVE,
+ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
+ { V4L2_COLORFX_EMBOSS, MMAL_PARAM_IMAGEFX_EMBOSS,
+ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
+ { V4L2_COLORFX_SKETCH, MMAL_PARAM_IMAGEFX_SKETCH,
+ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
+ { V4L2_COLORFX_SKY_BLUE, MMAL_PARAM_IMAGEFX_PASTEL,
+ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
+ { V4L2_COLORFX_GRASS_GREEN, MMAL_PARAM_IMAGEFX_WATERCOLOUR,
+ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
+ { V4L2_COLORFX_SKIN_WHITEN, MMAL_PARAM_IMAGEFX_WASHEDOUT,
+ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
+ { V4L2_COLORFX_VIVID, MMAL_PARAM_IMAGEFX_SATURATION,
+ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
+ { V4L2_COLORFX_AQUA, MMAL_PARAM_IMAGEFX_NONE,
+ 1, 0, 171, 121, 0, {0, 0, 0, 0, 0} },
+ { V4L2_COLORFX_ART_FREEZE, MMAL_PARAM_IMAGEFX_HATCH,
+ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
+ { V4L2_COLORFX_SILHOUETTE, MMAL_PARAM_IMAGEFX_FILM,
+ 0, 0, 0, 0, 0, {0, 0, 0, 0, 0} },
+ { V4L2_COLORFX_SOLARIZATION, MMAL_PARAM_IMAGEFX_SOLARIZE,
+ 0, 0, 0, 0, 5, {1, 128, 160, 160, 48} },
+ { V4L2_COLORFX_ANTIQUE, MMAL_PARAM_IMAGEFX_COLOURBALANCE,
+ 0, 0, 0, 0, 3, {108, 274, 238, 0, 0} },
+ { V4L2_COLORFX_SET_CBCR, MMAL_PARAM_IMAGEFX_NONE,
+ 1, 1, 0, 0, 0, {0, 0, 0, 0, 0} }
+};
+
+struct v4l2_mmal_scene_config {
+ enum v4l2_scene_mode v4l2_scene;
+ enum mmal_parameter_exposuremode exposure_mode;
+ enum mmal_parameter_exposuremeteringmode metering_mode;
+};
+
+static const struct v4l2_mmal_scene_config scene_configs[] = {
+ /* V4L2_SCENE_MODE_NONE automatically added */
+ {
+ V4L2_SCENE_MODE_NIGHT,
+ MMAL_PARAM_EXPOSUREMODE_NIGHT,
+ MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE
+ },
+ {
+ V4L2_SCENE_MODE_SPORTS,
+ MMAL_PARAM_EXPOSUREMODE_SPORTS,
+ MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE
+ },
+};
+
+/* control handlers*/
+
+static int ctrl_set_rational(struct bm2835_mmal_dev *dev,
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+{
+ struct mmal_parameter_rational rational_value;
+ struct vchiq_mmal_port *control;
+
+ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+
+ rational_value.num = ctrl->val;
+ rational_value.den = 100;
+
+ return vchiq_mmal_port_parameter_set(dev->instance, control,
+ mmal_ctrl->mmal_id,
+ &rational_value,
+ sizeof(rational_value));
+}
+
+static int ctrl_set_value(struct bm2835_mmal_dev *dev,
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+{
+ u32 u32_value;
+ struct vchiq_mmal_port *control;
+
+ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+
+ u32_value = ctrl->val;
+
+ return vchiq_mmal_port_parameter_set(dev->instance, control,
+ mmal_ctrl->mmal_id,
+ &u32_value, sizeof(u32_value));
+}
+
+static int ctrl_set_iso(struct bm2835_mmal_dev *dev,
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+{
+ u32 u32_value;
+ struct vchiq_mmal_port *control;
+
+ if (ctrl->val > mmal_ctrl->max || ctrl->val < mmal_ctrl->min)
+ return 1;
+
+ if (ctrl->id == V4L2_CID_ISO_SENSITIVITY)
+ dev->iso = iso_values[ctrl->val];
+ else if (ctrl->id == V4L2_CID_ISO_SENSITIVITY_AUTO)
+ dev->manual_iso_enabled =
+ (ctrl->val == V4L2_ISO_SENSITIVITY_MANUAL ?
+ true :
+ false);
+
+ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+
+ if (dev->manual_iso_enabled)
+ u32_value = dev->iso;
+ else
+ u32_value = 0;
+
+ return vchiq_mmal_port_parameter_set(dev->instance, control,
+ MMAL_PARAMETER_ISO,
+ &u32_value, sizeof(u32_value));
+}
+
+static int ctrl_set_value_ev(struct bm2835_mmal_dev *dev,
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+{
+ s32 s32_value;
+ struct vchiq_mmal_port *control;
+
+ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+
+ s32_value = (ctrl->val - 12) * 2; /* Convert from index to 1/6ths */
+
+ return vchiq_mmal_port_parameter_set(dev->instance, control,
+ mmal_ctrl->mmal_id,
+ &s32_value, sizeof(s32_value));
+}
+
+static int ctrl_set_rotate(struct bm2835_mmal_dev *dev,
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+{
+ int ret;
+ u32 u32_value;
+ struct vchiq_mmal_component *camera;
+
+ camera = dev->component[MMAL_COMPONENT_CAMERA];
+
+ u32_value = ((ctrl->val % 360) / 90) * 90;
+
+ ret = vchiq_mmal_port_parameter_set(dev->instance, &camera->output[0],
+ mmal_ctrl->mmal_id,
+ &u32_value, sizeof(u32_value));
+ if (ret < 0)
+ return ret;
+
+ ret = vchiq_mmal_port_parameter_set(dev->instance, &camera->output[1],
+ mmal_ctrl->mmal_id,
+ &u32_value, sizeof(u32_value));
+ if (ret < 0)
+ return ret;
+
+ ret = vchiq_mmal_port_parameter_set(dev->instance, &camera->output[2],
+ mmal_ctrl->mmal_id,
+ &u32_value, sizeof(u32_value));
+
+ return ret;
+}
+
+static int ctrl_set_flip(struct bm2835_mmal_dev *dev,
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+{
+ int ret;
+ u32 u32_value;
+ struct vchiq_mmal_component *camera;
+
+ if (ctrl->id == V4L2_CID_HFLIP)
+ dev->hflip = ctrl->val;
+ else
+ dev->vflip = ctrl->val;
+
+ camera = dev->component[MMAL_COMPONENT_CAMERA];
+
+ if (dev->hflip && dev->vflip)
+ u32_value = MMAL_PARAM_MIRROR_BOTH;
+ else if (dev->hflip)
+ u32_value = MMAL_PARAM_MIRROR_HORIZONTAL;
+ else if (dev->vflip)
+ u32_value = MMAL_PARAM_MIRROR_VERTICAL;
+ else
+ u32_value = MMAL_PARAM_MIRROR_NONE;
+
+ ret = vchiq_mmal_port_parameter_set(dev->instance, &camera->output[0],
+ mmal_ctrl->mmal_id,
+ &u32_value, sizeof(u32_value));
+ if (ret < 0)
+ return ret;
+
+ ret = vchiq_mmal_port_parameter_set(dev->instance, &camera->output[1],
+ mmal_ctrl->mmal_id,
+ &u32_value, sizeof(u32_value));
+ if (ret < 0)
+ return ret;
+
+ ret = vchiq_mmal_port_parameter_set(dev->instance, &camera->output[2],
+ mmal_ctrl->mmal_id,
+ &u32_value, sizeof(u32_value));
+
+ return ret;
+}
+
+static int ctrl_set_exposure(struct bm2835_mmal_dev *dev,
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+{
+ enum mmal_parameter_exposuremode exp_mode = dev->exposure_mode_user;
+ u32 shutter_speed = 0;
+ struct vchiq_mmal_port *control;
+ int ret = 0;
+
+ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+
+ if (mmal_ctrl->mmal_id == MMAL_PARAMETER_SHUTTER_SPEED) {
+ /* V4L2 is in 100usec increments.
+ * MMAL is 1usec.
+ */
+ dev->manual_shutter_speed = ctrl->val * 100;
+ } else if (mmal_ctrl->mmal_id == MMAL_PARAMETER_EXPOSURE_MODE) {
+ switch (ctrl->val) {
+ case V4L2_EXPOSURE_AUTO:
+ exp_mode = MMAL_PARAM_EXPOSUREMODE_AUTO;
+ break;
+
+ case V4L2_EXPOSURE_MANUAL:
+ exp_mode = MMAL_PARAM_EXPOSUREMODE_OFF;
+ break;
+ }
+ dev->exposure_mode_user = exp_mode;
+ dev->exposure_mode_v4l2_user = ctrl->val;
+ } else if (mmal_ctrl->id == V4L2_CID_EXPOSURE_AUTO_PRIORITY) {
+ dev->exp_auto_priority = ctrl->val;
+ }
+
+ if (dev->scene_mode == V4L2_SCENE_MODE_NONE) {
+ if (exp_mode == MMAL_PARAM_EXPOSUREMODE_OFF)
+ shutter_speed = dev->manual_shutter_speed;
+
+ ret = vchiq_mmal_port_parameter_set(dev->instance,
+ control,
+ MMAL_PARAMETER_SHUTTER_SPEED,
+ &shutter_speed,
+ sizeof(shutter_speed));
+ ret += vchiq_mmal_port_parameter_set(dev->instance,
+ control,
+ MMAL_PARAMETER_EXPOSURE_MODE,
+ &exp_mode,
+ sizeof(u32));
+ dev->exposure_mode_active = exp_mode;
+ }
+ /* exposure_dynamic_framerate (V4L2_CID_EXPOSURE_AUTO_PRIORITY) should
+ * always apply irrespective of scene mode.
+ */
+ ret += set_framerate_params(dev);
+
+ return ret;
+}
+
+static int ctrl_set_metering_mode(struct bm2835_mmal_dev *dev,
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+{
+ switch (ctrl->val) {
+ case V4L2_EXPOSURE_METERING_AVERAGE:
+ dev->metering_mode = MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE;
+ break;
+
+ case V4L2_EXPOSURE_METERING_CENTER_WEIGHTED:
+ dev->metering_mode = MMAL_PARAM_EXPOSUREMETERINGMODE_BACKLIT;
+ break;
+
+ case V4L2_EXPOSURE_METERING_SPOT:
+ dev->metering_mode = MMAL_PARAM_EXPOSUREMETERINGMODE_SPOT;
+ break;
+
+ /* todo matrix weighting not added to Linux API till 3.9
+ case V4L2_EXPOSURE_METERING_MATRIX:
+ dev->metering_mode = MMAL_PARAM_EXPOSUREMETERINGMODE_MATRIX;
+ break;
+ */
+ }
+
+ if (dev->scene_mode == V4L2_SCENE_MODE_NONE) {
+ struct vchiq_mmal_port *control;
+ u32 u32_value = dev->metering_mode;
+
+ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+
+ return vchiq_mmal_port_parameter_set(dev->instance, control,
+ mmal_ctrl->mmal_id,
+ &u32_value, sizeof(u32_value));
+ } else
+ return 0;
+}
+
+static int ctrl_set_flicker_avoidance(struct bm2835_mmal_dev *dev,
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+{
+ u32 u32_value;
+ struct vchiq_mmal_port *control;
+
+ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+
+ switch (ctrl->val) {
+ case V4L2_CID_POWER_LINE_FREQUENCY_DISABLED:
+ u32_value = MMAL_PARAM_FLICKERAVOID_OFF;
+ break;
+ case V4L2_CID_POWER_LINE_FREQUENCY_50HZ:
+ u32_value = MMAL_PARAM_FLICKERAVOID_50HZ;
+ break;
+ case V4L2_CID_POWER_LINE_FREQUENCY_60HZ:
+ u32_value = MMAL_PARAM_FLICKERAVOID_60HZ;
+ break;
+ case V4L2_CID_POWER_LINE_FREQUENCY_AUTO:
+ u32_value = MMAL_PARAM_FLICKERAVOID_AUTO;
+ break;
+ }
+
+ return vchiq_mmal_port_parameter_set(dev->instance, control,
+ mmal_ctrl->mmal_id,
+ &u32_value, sizeof(u32_value));
+}
+
+static int ctrl_set_awb_mode(struct bm2835_mmal_dev *dev,
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+{
+ u32 u32_value;
+ struct vchiq_mmal_port *control;
+
+ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+
+ switch (ctrl->val) {
+ case V4L2_WHITE_BALANCE_MANUAL:
+ u32_value = MMAL_PARAM_AWBMODE_OFF;
+ break;
+
+ case V4L2_WHITE_BALANCE_AUTO:
+ u32_value = MMAL_PARAM_AWBMODE_AUTO;
+ break;
+
+ case V4L2_WHITE_BALANCE_INCANDESCENT:
+ u32_value = MMAL_PARAM_AWBMODE_INCANDESCENT;
+ break;
+
+ case V4L2_WHITE_BALANCE_FLUORESCENT:
+ u32_value = MMAL_PARAM_AWBMODE_FLUORESCENT;
+ break;
+
+ case V4L2_WHITE_BALANCE_FLUORESCENT_H:
+ u32_value = MMAL_PARAM_AWBMODE_TUNGSTEN;
+ break;
+
+ case V4L2_WHITE_BALANCE_HORIZON:
+ u32_value = MMAL_PARAM_AWBMODE_HORIZON;
+ break;
+
+ case V4L2_WHITE_BALANCE_DAYLIGHT:
+ u32_value = MMAL_PARAM_AWBMODE_SUNLIGHT;
+ break;
+
+ case V4L2_WHITE_BALANCE_FLASH:
+ u32_value = MMAL_PARAM_AWBMODE_FLASH;
+ break;
+
+ case V4L2_WHITE_BALANCE_CLOUDY:
+ u32_value = MMAL_PARAM_AWBMODE_CLOUDY;
+ break;
+
+ case V4L2_WHITE_BALANCE_SHADE:
+ u32_value = MMAL_PARAM_AWBMODE_SHADE;
+ break;
+ }
+
+ return vchiq_mmal_port_parameter_set(dev->instance, control,
+ mmal_ctrl->mmal_id,
+ &u32_value, sizeof(u32_value));
+}
+
+static int ctrl_set_awb_gains(struct bm2835_mmal_dev *dev,
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+{
+ struct vchiq_mmal_port *control;
+ struct mmal_parameter_awbgains gains;
+
+ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+
+ if (ctrl->id == V4L2_CID_RED_BALANCE)
+ dev->red_gain = ctrl->val;
+ else if (ctrl->id == V4L2_CID_BLUE_BALANCE)
+ dev->blue_gain = ctrl->val;
+
+ gains.r_gain.num = dev->red_gain;
+ gains.b_gain.num = dev->blue_gain;
+ gains.r_gain.den = gains.b_gain.den = 1000;
+
+ return vchiq_mmal_port_parameter_set(dev->instance, control,
+ mmal_ctrl->mmal_id,
+ &gains, sizeof(gains));
+}
+
+static int ctrl_set_image_effect(struct bm2835_mmal_dev *dev,
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+{
+ int ret = -EINVAL;
+ int i, j;
+ struct vchiq_mmal_port *control;
+ struct mmal_parameter_imagefx_parameters imagefx;
+
+ for (i = 0; i < ARRAY_SIZE(v4l2_to_mmal_effects_values); i++) {
+ if (ctrl->val == v4l2_to_mmal_effects_values[i].v4l2_effect) {
+ imagefx.effect =
+ v4l2_to_mmal_effects_values[i].mmal_effect;
+ imagefx.num_effect_params =
+ v4l2_to_mmal_effects_values[i].num_effect_params;
+
+ if (imagefx.num_effect_params > MMAL_MAX_IMAGEFX_PARAMETERS)
+ imagefx.num_effect_params = MMAL_MAX_IMAGEFX_PARAMETERS;
+
+ for (j = 0; j < imagefx.num_effect_params; j++)
+ imagefx.effect_parameter[j] =
+ v4l2_to_mmal_effects_values[i].effect_params[j];
+
+ dev->colourfx.enable =
+ v4l2_to_mmal_effects_values[i].col_fx_enable;
+ if (!v4l2_to_mmal_effects_values[i].col_fx_fixed_cbcr) {
+ dev->colourfx.u =
+ v4l2_to_mmal_effects_values[i].u;
+ dev->colourfx.v =
+ v4l2_to_mmal_effects_values[i].v;
+ }
+
+ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+
+ ret = vchiq_mmal_port_parameter_set(
+ dev->instance, control,
+ MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS,
+ &imagefx, sizeof(imagefx));
+ if (ret)
+ goto exit;
+
+ ret = vchiq_mmal_port_parameter_set(
+ dev->instance, control,
+ MMAL_PARAMETER_COLOUR_EFFECT,
+ &dev->colourfx, sizeof(dev->colourfx));
+ }
+ }
+
+exit:
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "mmal_ctrl:%p ctrl id:0x%x ctrl val:%d imagefx:0x%x color_effect:%s u:%d v:%d ret %d(%d)\n",
+ mmal_ctrl, ctrl->id, ctrl->val, imagefx.effect,
+ dev->colourfx.enable ? "true" : "false",
+ dev->colourfx.u, dev->colourfx.v,
+ ret, (ret == 0 ? 0 : -EINVAL));
+ return (ret == 0 ? 0 : EINVAL);
+}
+
+static int ctrl_set_colfx(struct bm2835_mmal_dev *dev,
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+{
+ int ret = -EINVAL;
+ struct vchiq_mmal_port *control;
+
+ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+
+ dev->colourfx.enable = (ctrl->val & 0xff00) >> 8;
+ dev->colourfx.enable = ctrl->val & 0xff;
+
+ ret = vchiq_mmal_port_parameter_set(dev->instance, control,
+ MMAL_PARAMETER_COLOUR_EFFECT,
+ &dev->colourfx,
+ sizeof(dev->colourfx));
+
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "%s: After: mmal_ctrl:%p ctrl id:0x%x ctrl val:%d ret %d(%d)\n",
+ __func__, mmal_ctrl, ctrl->id, ctrl->val, ret,
+ (ret == 0 ? 0 : -EINVAL));
+ return (ret == 0 ? 0 : EINVAL);
+}
+
+static int ctrl_set_bitrate(struct bm2835_mmal_dev *dev,
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+{
+ int ret;
+ struct vchiq_mmal_port *encoder_out;
+
+ dev->capture.encode_bitrate = ctrl->val;
+
+ encoder_out = &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
+
+ ret = vchiq_mmal_port_parameter_set(dev->instance, encoder_out,
+ mmal_ctrl->mmal_id,
+ &ctrl->val, sizeof(ctrl->val));
+ ret = 0;
+ return ret;
+}
+
+static int ctrl_set_bitrate_mode(struct bm2835_mmal_dev *dev,
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+{
+ u32 bitrate_mode;
+ struct vchiq_mmal_port *encoder_out;
+
+ encoder_out = &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
+
+ dev->capture.encode_bitrate_mode = ctrl->val;
+ switch (ctrl->val) {
+ default:
+ case V4L2_MPEG_VIDEO_BITRATE_MODE_VBR:
+ bitrate_mode = MMAL_VIDEO_RATECONTROL_VARIABLE;
+ break;
+ case V4L2_MPEG_VIDEO_BITRATE_MODE_CBR:
+ bitrate_mode = MMAL_VIDEO_RATECONTROL_CONSTANT;
+ break;
+ }
+
+ vchiq_mmal_port_parameter_set(dev->instance, encoder_out,
+ mmal_ctrl->mmal_id,
+ &bitrate_mode,
+ sizeof(bitrate_mode));
+ return 0;
+}
+
+static int ctrl_set_image_encode_output(struct bm2835_mmal_dev *dev,
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+{
+ u32 u32_value;
+ struct vchiq_mmal_port *jpeg_out;
+
+ jpeg_out = &dev->component[MMAL_COMPONENT_IMAGE_ENCODE]->output[0];
+
+ u32_value = ctrl->val;
+
+ return vchiq_mmal_port_parameter_set(dev->instance, jpeg_out,
+ mmal_ctrl->mmal_id,
+ &u32_value, sizeof(u32_value));
+}
+
+static int ctrl_set_video_encode_param_output(struct bm2835_mmal_dev *dev,
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+{
+ u32 u32_value;
+ struct vchiq_mmal_port *vid_enc_ctl;
+
+ vid_enc_ctl = &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0];
+
+ u32_value = ctrl->val;
+
+ return vchiq_mmal_port_parameter_set(dev->instance, vid_enc_ctl,
+ mmal_ctrl->mmal_id,
+ &u32_value, sizeof(u32_value));
+}
+
+static int ctrl_set_video_encode_profile_level(struct bm2835_mmal_dev *dev,
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+{
+ struct mmal_parameter_video_profile param;
+ int ret = 0;
+
+ if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_PROFILE) {
+ switch (ctrl->val) {
+ case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
+ case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
+ case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
+ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
+ dev->capture.enc_profile = ctrl->val;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ } else if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_LEVEL) {
+ switch (ctrl->val) {
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
+ dev->capture.enc_level = ctrl->val;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ }
+
+ if (!ret) {
+ switch (dev->capture.enc_profile) {
+ case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
+ param.profile = MMAL_VIDEO_PROFILE_H264_BASELINE;
+ break;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
+ param.profile =
+ MMAL_VIDEO_PROFILE_H264_CONSTRAINED_BASELINE;
+ break;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
+ param.profile = MMAL_VIDEO_PROFILE_H264_MAIN;
+ break;
+ case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
+ param.profile = MMAL_VIDEO_PROFILE_H264_HIGH;
+ break;
+ default:
+ /* Should never get here */
+ break;
+ }
+
+ switch (dev->capture.enc_level) {
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
+ param.level = MMAL_VIDEO_LEVEL_H264_1;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
+ param.level = MMAL_VIDEO_LEVEL_H264_1b;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
+ param.level = MMAL_VIDEO_LEVEL_H264_11;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
+ param.level = MMAL_VIDEO_LEVEL_H264_12;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
+ param.level = MMAL_VIDEO_LEVEL_H264_13;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
+ param.level = MMAL_VIDEO_LEVEL_H264_2;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
+ param.level = MMAL_VIDEO_LEVEL_H264_21;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
+ param.level = MMAL_VIDEO_LEVEL_H264_22;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
+ param.level = MMAL_VIDEO_LEVEL_H264_3;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
+ param.level = MMAL_VIDEO_LEVEL_H264_31;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
+ param.level = MMAL_VIDEO_LEVEL_H264_32;
+ break;
+ case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
+ param.level = MMAL_VIDEO_LEVEL_H264_4;
+ break;
+ default:
+ /* Should never get here */
+ break;
+ }
+
+ ret = vchiq_mmal_port_parameter_set(dev->instance,
+ &dev->component[MMAL_COMPONENT_VIDEO_ENCODE]->output[0],
+ mmal_ctrl->mmal_id,
+ ¶m, sizeof(param));
+ }
+ return ret;
+}
+
+static int ctrl_set_scene_mode(struct bm2835_mmal_dev *dev,
+ struct v4l2_ctrl *ctrl,
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl)
+{
+ int ret = 0;
+ int shutter_speed;
+ struct vchiq_mmal_port *control;
+
+ v4l2_dbg(0, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "scene mode selected %d, was %d\n", ctrl->val,
+ dev->scene_mode);
+ control = &dev->component[MMAL_COMPONENT_CAMERA]->control;
+
+ if (ctrl->val == dev->scene_mode)
+ return 0;
+
+ if (ctrl->val == V4L2_SCENE_MODE_NONE) {
+ /* Restore all user selections */
+ dev->scene_mode = V4L2_SCENE_MODE_NONE;
+
+ if (dev->exposure_mode_user == MMAL_PARAM_EXPOSUREMODE_OFF)
+ shutter_speed = dev->manual_shutter_speed;
+ else
+ shutter_speed = 0;
+
+ v4l2_dbg(0, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "%s: scene mode none: shut_speed %d, exp_mode %d, metering %d\n",
+ __func__, shutter_speed, dev->exposure_mode_user,
+ dev->metering_mode);
+ ret = vchiq_mmal_port_parameter_set(dev->instance,
+ control,
+ MMAL_PARAMETER_SHUTTER_SPEED,
+ &shutter_speed,
+ sizeof(shutter_speed));
+ ret += vchiq_mmal_port_parameter_set(dev->instance,
+ control,
+ MMAL_PARAMETER_EXPOSURE_MODE,
+ &dev->exposure_mode_user,
+ sizeof(u32));
+ dev->exposure_mode_active = dev->exposure_mode_user;
+ ret += vchiq_mmal_port_parameter_set(dev->instance,
+ control,
+ MMAL_PARAMETER_EXP_METERING_MODE,
+ &dev->metering_mode,
+ sizeof(u32));
+ ret += set_framerate_params(dev);
+ } else {
+ /* Set up scene mode */
+ int i;
+ const struct v4l2_mmal_scene_config *scene = NULL;
+ int shutter_speed;
+ enum mmal_parameter_exposuremode exposure_mode;
+ enum mmal_parameter_exposuremeteringmode metering_mode;
+
+ for (i = 0; i < ARRAY_SIZE(scene_configs); i++) {
+ if (scene_configs[i].v4l2_scene ==
+ ctrl->val) {
+ scene = &scene_configs[i];
+ break;
+ }
+ }
+ if (!scene)
+ return -EINVAL;
+ if (i >= ARRAY_SIZE(scene_configs))
+ return -EINVAL;
+
+ /* Set all the values */
+ dev->scene_mode = ctrl->val;
+
+ if (scene->exposure_mode == MMAL_PARAM_EXPOSUREMODE_OFF)
+ shutter_speed = dev->manual_shutter_speed;
+ else
+ shutter_speed = 0;
+ exposure_mode = scene->exposure_mode;
+ metering_mode = scene->metering_mode;
+
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "%s: scene mode none: shut_speed %d, exp_mode %d, metering %d\n",
+ __func__, shutter_speed, exposure_mode, metering_mode);
+
+ ret = vchiq_mmal_port_parameter_set(dev->instance, control,
+ MMAL_PARAMETER_SHUTTER_SPEED,
+ &shutter_speed,
+ sizeof(shutter_speed));
+ ret += vchiq_mmal_port_parameter_set(dev->instance, control,
+ MMAL_PARAMETER_EXPOSURE_MODE,
+ &exposure_mode,
+ sizeof(u32));
+ dev->exposure_mode_active = exposure_mode;
+ ret += vchiq_mmal_port_parameter_set(dev->instance, control,
+ MMAL_PARAMETER_EXPOSURE_MODE,
+ &exposure_mode,
+ sizeof(u32));
+ ret += vchiq_mmal_port_parameter_set(dev->instance, control,
+ MMAL_PARAMETER_EXP_METERING_MODE,
+ &metering_mode,
+ sizeof(u32));
+ ret += set_framerate_params(dev);
+ }
+ if (ret) {
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "%s: Setting scene to %d, ret=%d\n",
+ __func__, ctrl->val, ret);
+ ret = -EINVAL;
+ }
+ return 0;
+}
+
+static int bm2835_mmal_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct bm2835_mmal_dev *dev =
+ container_of(ctrl->handler, struct bm2835_mmal_dev,
+ ctrl_handler);
+ const struct bm2835_mmal_v4l2_ctrl *mmal_ctrl = ctrl->priv;
+ int ret;
+
+ if ((mmal_ctrl == NULL) ||
+ (mmal_ctrl->id != ctrl->id) ||
+ (mmal_ctrl->setter == NULL)) {
+ pr_warn("mmal_ctrl:%p ctrl id:%d\n", mmal_ctrl, ctrl->id);
+ return -EINVAL;
+ }
+
+ ret = mmal_ctrl->setter(dev, ctrl, mmal_ctrl);
+ if (ret)
+ pr_warn("ctrl id:%d/MMAL param %08X- returned ret %d\n",
+ ctrl->id, mmal_ctrl->mmal_id, ret);
+ if (mmal_ctrl->ignore_errors)
+ ret = 0;
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops bm2835_mmal_ctrl_ops = {
+ .s_ctrl = bm2835_mmal_s_ctrl,
+};
+
+static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = {
+ {
+ V4L2_CID_SATURATION, MMAL_CONTROL_TYPE_STD,
+ -100, 100, 0, 1, NULL,
+ MMAL_PARAMETER_SATURATION,
+ &ctrl_set_rational,
+ false
+ },
+ {
+ V4L2_CID_SHARPNESS, MMAL_CONTROL_TYPE_STD,
+ -100, 100, 0, 1, NULL,
+ MMAL_PARAMETER_SHARPNESS,
+ &ctrl_set_rational,
+ false
+ },
+ {
+ V4L2_CID_CONTRAST, MMAL_CONTROL_TYPE_STD,
+ -100, 100, 0, 1, NULL,
+ MMAL_PARAMETER_CONTRAST,
+ &ctrl_set_rational,
+ false
+ },
+ {
+ V4L2_CID_BRIGHTNESS, MMAL_CONTROL_TYPE_STD,
+ 0, 100, 50, 1, NULL,
+ MMAL_PARAMETER_BRIGHTNESS,
+ &ctrl_set_rational,
+ false
+ },
+ {
+ V4L2_CID_ISO_SENSITIVITY, MMAL_CONTROL_TYPE_INT_MENU,
+ 0, ARRAY_SIZE(iso_qmenu) - 1, 0, 1, iso_qmenu,
+ MMAL_PARAMETER_ISO,
+ &ctrl_set_iso,
+ false
+ },
+ {
+ V4L2_CID_ISO_SENSITIVITY_AUTO, MMAL_CONTROL_TYPE_STD_MENU,
+ 0, 1, V4L2_ISO_SENSITIVITY_AUTO, 1, NULL,
+ MMAL_PARAMETER_ISO,
+ &ctrl_set_iso,
+ false
+ },
+ {
+ V4L2_CID_IMAGE_STABILIZATION, MMAL_CONTROL_TYPE_STD,
+ 0, 1, 0, 1, NULL,
+ MMAL_PARAMETER_VIDEO_STABILISATION,
+ &ctrl_set_value,
+ false
+ },
+/* {
+ 0, MMAL_CONTROL_TYPE_CLUSTER, 3, 1, 0, NULL, 0, NULL
+ }, */
+ {
+ V4L2_CID_EXPOSURE_AUTO, MMAL_CONTROL_TYPE_STD_MENU,
+ ~0x03, 3, V4L2_EXPOSURE_AUTO, 0, NULL,
+ MMAL_PARAMETER_EXPOSURE_MODE,
+ &ctrl_set_exposure,
+ false
+ },
+/* todo this needs mixing in with set exposure
+ {
+ V4L2_CID_SCENE_MODE, MMAL_CONTROL_TYPE_STD_MENU,
+ },
+ */
+ {
+ V4L2_CID_EXPOSURE_ABSOLUTE, MMAL_CONTROL_TYPE_STD,
+ /* Units of 100usecs */
+ 1, 1 * 1000 * 10, 100 * 10, 1, NULL,
+ MMAL_PARAMETER_SHUTTER_SPEED,
+ &ctrl_set_exposure,
+ false
+ },
+ {
+ V4L2_CID_AUTO_EXPOSURE_BIAS, MMAL_CONTROL_TYPE_INT_MENU,
+ 0, ARRAY_SIZE(ev_bias_qmenu) - 1,
+ (ARRAY_SIZE(ev_bias_qmenu) + 1) / 2 - 1, 0, ev_bias_qmenu,
+ MMAL_PARAMETER_EXPOSURE_COMP,
+ &ctrl_set_value_ev,
+ false
+ },
+ {
+ V4L2_CID_EXPOSURE_AUTO_PRIORITY, MMAL_CONTROL_TYPE_STD,
+ 0, 1,
+ 0, 1, NULL,
+ 0, /* Dummy MMAL ID as it gets mapped into FPS range*/
+ &ctrl_set_exposure,
+ false
+ },
+ {
+ V4L2_CID_EXPOSURE_METERING,
+ MMAL_CONTROL_TYPE_STD_MENU,
+ ~0x7, 2, V4L2_EXPOSURE_METERING_AVERAGE, 0, NULL,
+ MMAL_PARAMETER_EXP_METERING_MODE,
+ &ctrl_set_metering_mode,
+ false
+ },
+ {
+ V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE,
+ MMAL_CONTROL_TYPE_STD_MENU,
+ ~0x3ff, 9, V4L2_WHITE_BALANCE_AUTO, 0, NULL,
+ MMAL_PARAMETER_AWB_MODE,
+ &ctrl_set_awb_mode,
+ false
+ },
+ {
+ V4L2_CID_RED_BALANCE, MMAL_CONTROL_TYPE_STD,
+ 1, 7999, 1000, 1, NULL,
+ MMAL_PARAMETER_CUSTOM_AWB_GAINS,
+ &ctrl_set_awb_gains,
+ false
+ },
+ {
+ V4L2_CID_BLUE_BALANCE, MMAL_CONTROL_TYPE_STD,
+ 1, 7999, 1000, 1, NULL,
+ MMAL_PARAMETER_CUSTOM_AWB_GAINS,
+ &ctrl_set_awb_gains,
+ false
+ },
+ {
+ V4L2_CID_COLORFX, MMAL_CONTROL_TYPE_STD_MENU,
+ 0, 15, V4L2_COLORFX_NONE, 0, NULL,
+ MMAL_PARAMETER_IMAGE_EFFECT,
+ &ctrl_set_image_effect,
+ false
+ },
+ {
+ V4L2_CID_COLORFX_CBCR, MMAL_CONTROL_TYPE_STD,
+ 0, 0xffff, 0x8080, 1, NULL,
+ MMAL_PARAMETER_COLOUR_EFFECT,
+ &ctrl_set_colfx,
+ false
+ },
+ {
+ V4L2_CID_ROTATE, MMAL_CONTROL_TYPE_STD,
+ 0, 360, 0, 90, NULL,
+ MMAL_PARAMETER_ROTATION,
+ &ctrl_set_rotate,
+ false
+ },
+ {
+ V4L2_CID_HFLIP, MMAL_CONTROL_TYPE_STD,
+ 0, 1, 0, 1, NULL,
+ MMAL_PARAMETER_MIRROR,
+ &ctrl_set_flip,
+ false
+ },
+ {
+ V4L2_CID_VFLIP, MMAL_CONTROL_TYPE_STD,
+ 0, 1, 0, 1, NULL,
+ MMAL_PARAMETER_MIRROR,
+ &ctrl_set_flip,
+ false
+ },
+ {
+ V4L2_CID_MPEG_VIDEO_BITRATE_MODE, MMAL_CONTROL_TYPE_STD_MENU,
+ 0, ARRAY_SIZE(bitrate_mode_qmenu) - 1,
+ 0, 0, bitrate_mode_qmenu,
+ MMAL_PARAMETER_RATECONTROL,
+ &ctrl_set_bitrate_mode,
+ false
+ },
+ {
+ V4L2_CID_MPEG_VIDEO_BITRATE, MMAL_CONTROL_TYPE_STD,
+ 25 * 1000, 25 * 1000 * 1000, 10 * 1000 * 1000, 25 * 1000, NULL,
+ MMAL_PARAMETER_VIDEO_BIT_RATE,
+ &ctrl_set_bitrate,
+ false
+ },
+ {
+ V4L2_CID_JPEG_COMPRESSION_QUALITY, MMAL_CONTROL_TYPE_STD,
+ 1, 100,
+ 30, 1, NULL,
+ MMAL_PARAMETER_JPEG_Q_FACTOR,
+ &ctrl_set_image_encode_output,
+ false
+ },
+ {
+ V4L2_CID_POWER_LINE_FREQUENCY, MMAL_CONTROL_TYPE_STD_MENU,
+ 0, ARRAY_SIZE(mains_freq_qmenu) - 1,
+ 1, 1, NULL,
+ MMAL_PARAMETER_FLICKER_AVOID,
+ &ctrl_set_flicker_avoidance,
+ false
+ },
+ {
+ V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER, MMAL_CONTROL_TYPE_STD,
+ 0, 1,
+ 0, 1, NULL,
+ MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER,
+ &ctrl_set_video_encode_param_output,
+ true /* Errors ignored as requires latest firmware to work */
+ },
+ {
+ V4L2_CID_MPEG_VIDEO_H264_PROFILE,
+ MMAL_CONTROL_TYPE_STD_MENU,
+ ~((1<<V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
+ (1<<V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) |
+ (1<<V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
+ (1<<V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)),
+ V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
+ V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, 1, NULL,
+ MMAL_PARAMETER_PROFILE,
+ &ctrl_set_video_encode_profile_level,
+ false
+ },
+ {
+ V4L2_CID_MPEG_VIDEO_H264_LEVEL, MMAL_CONTROL_TYPE_STD_MENU,
+ ~((1<<V4L2_MPEG_VIDEO_H264_LEVEL_1_0) |
+ (1<<V4L2_MPEG_VIDEO_H264_LEVEL_1B) |
+ (1<<V4L2_MPEG_VIDEO_H264_LEVEL_1_1) |
+ (1<<V4L2_MPEG_VIDEO_H264_LEVEL_1_2) |
+ (1<<V4L2_MPEG_VIDEO_H264_LEVEL_1_3) |
+ (1<<V4L2_MPEG_VIDEO_H264_LEVEL_2_0) |
+ (1<<V4L2_MPEG_VIDEO_H264_LEVEL_2_1) |
+ (1<<V4L2_MPEG_VIDEO_H264_LEVEL_2_2) |
+ (1<<V4L2_MPEG_VIDEO_H264_LEVEL_3_0) |
+ (1<<V4L2_MPEG_VIDEO_H264_LEVEL_3_1) |
+ (1<<V4L2_MPEG_VIDEO_H264_LEVEL_3_2) |
+ (1<<V4L2_MPEG_VIDEO_H264_LEVEL_4_0)),
+ V4L2_MPEG_VIDEO_H264_LEVEL_4_0,
+ V4L2_MPEG_VIDEO_H264_LEVEL_4_0, 1, NULL,
+ MMAL_PARAMETER_PROFILE,
+ &ctrl_set_video_encode_profile_level,
+ false
+ },
+ {
+ V4L2_CID_SCENE_MODE, MMAL_CONTROL_TYPE_STD_MENU,
+ -1, /* Min is computed at runtime */
+ V4L2_SCENE_MODE_TEXT,
+ V4L2_SCENE_MODE_NONE, 1, NULL,
+ MMAL_PARAMETER_PROFILE,
+ &ctrl_set_scene_mode,
+ false
+ },
+ {
+ V4L2_CID_MPEG_VIDEO_H264_I_PERIOD, MMAL_CONTROL_TYPE_STD,
+ 0, 0x7FFFFFFF, 60, 1, NULL,
+ MMAL_PARAMETER_INTRAPERIOD,
+ &ctrl_set_video_encode_param_output,
+ false
+ },
+};
+
+int bm2835_mmal_set_all_camera_controls(struct bm2835_mmal_dev *dev)
+{
+ int c;
+ int ret = 0;
+
+ for (c = 0; c < V4L2_CTRL_COUNT; c++) {
+ if ((dev->ctrls[c]) && (v4l2_ctrls[c].setter)) {
+ ret = v4l2_ctrls[c].setter(dev, dev->ctrls[c],
+ &v4l2_ctrls[c]);
+ if (!v4l2_ctrls[c].ignore_errors && ret) {
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "Failed when setting default values for ctrl %d\n",
+ c);
+ break;
+ }
+ }
+ }
+ return ret;
+}
+
+int set_framerate_params(struct bm2835_mmal_dev *dev)
+{
+ struct mmal_parameter_fps_range fps_range;
+ int ret;
+
+ if ((dev->exposure_mode_active != MMAL_PARAM_EXPOSUREMODE_OFF) &&
+ (dev->exp_auto_priority)) {
+ /* Variable FPS. Define min FPS as 1fps.
+ * Max as max defined FPS.
+ */
+ fps_range.fps_low.num = 1;
+ fps_range.fps_low.den = 1;
+ fps_range.fps_high.num = dev->capture.timeperframe.denominator;
+ fps_range.fps_high.den = dev->capture.timeperframe.numerator;
+ } else {
+ /* Fixed FPS - set min and max to be the same */
+ fps_range.fps_low.num = fps_range.fps_high.num =
+ dev->capture.timeperframe.denominator;
+ fps_range.fps_low.den = fps_range.fps_high.den =
+ dev->capture.timeperframe.numerator;
+ }
+
+ v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "Set fps range to %d/%d to %d/%d\n",
+ fps_range.fps_low.num,
+ fps_range.fps_low.den,
+ fps_range.fps_high.num,
+ fps_range.fps_high.den);
+
+ ret = vchiq_mmal_port_parameter_set(dev->instance,
+ &dev->component[MMAL_COMPONENT_CAMERA]->
+ output[MMAL_CAMERA_PORT_PREVIEW],
+ MMAL_PARAMETER_FPS_RANGE,
+ &fps_range, sizeof(fps_range));
+ ret += vchiq_mmal_port_parameter_set(dev->instance,
+ &dev->component[MMAL_COMPONENT_CAMERA]->
+ output[MMAL_CAMERA_PORT_VIDEO],
+ MMAL_PARAMETER_FPS_RANGE,
+ &fps_range, sizeof(fps_range));
+ ret += vchiq_mmal_port_parameter_set(dev->instance,
+ &dev->component[MMAL_COMPONENT_CAMERA]->
+ output[MMAL_CAMERA_PORT_CAPTURE],
+ MMAL_PARAMETER_FPS_RANGE,
+ &fps_range, sizeof(fps_range));
+ if (ret)
+ v4l2_dbg(0, bcm2835_v4l2_debug, &dev->v4l2_dev,
+ "Failed to set fps ret %d\n", ret);
+
+ return ret;
+}
+
+int bm2835_mmal_init_controls(struct bm2835_mmal_dev *dev,
+ struct v4l2_ctrl_handler *hdl)
+{
+ int c;
+ const struct bm2835_mmal_v4l2_ctrl *ctrl;
+
+ v4l2_ctrl_handler_init(hdl, V4L2_CTRL_COUNT);
+
+ for (c = 0; c < V4L2_CTRL_COUNT; c++) {
+ ctrl = &v4l2_ctrls[c];
+
+ switch (ctrl->type) {
+ case MMAL_CONTROL_TYPE_STD:
+ dev->ctrls[c] = v4l2_ctrl_new_std(hdl,
+ &bm2835_mmal_ctrl_ops, ctrl->id,
+ ctrl->min, ctrl->max, ctrl->step, ctrl->def);
+ break;
+
+ case MMAL_CONTROL_TYPE_STD_MENU:
+ {
+ int mask = ctrl->min;
+
+ if (ctrl->id == V4L2_CID_SCENE_MODE) {
+ /* Special handling to work out the mask
+ * value based on the scene_configs array
+ * at runtime. Reduces the chance of
+ * mismatches.
+ */
+ int i;
+ mask = 1<<V4L2_SCENE_MODE_NONE;
+ for (i = 0;
+ i < ARRAY_SIZE(scene_configs);
+ i++) {
+ mask |= 1<<scene_configs[i].v4l2_scene;
+ }
+ mask = ~mask;
+ }
+
+ dev->ctrls[c] = v4l2_ctrl_new_std_menu(hdl,
+ &bm2835_mmal_ctrl_ops, ctrl->id,
+ ctrl->max, mask, ctrl->def);
+ break;
+ }
+
+ case MMAL_CONTROL_TYPE_INT_MENU:
+ dev->ctrls[c] = v4l2_ctrl_new_int_menu(hdl,
+ &bm2835_mmal_ctrl_ops, ctrl->id,
+ ctrl->max, ctrl->def, ctrl->imenu);
+ break;
+
+ case MMAL_CONTROL_TYPE_CLUSTER:
+ /* skip this entry when constructing controls */
+ continue;
+ }
+
+ if (hdl->error)
+ break;
+
+ dev->ctrls[c]->priv = (void *)ctrl;
+ }
+
+ if (hdl->error) {
+ pr_err("error adding control %d/%d id 0x%x\n", c,
+ V4L2_CTRL_COUNT, ctrl->id);
+ return hdl->error;
+ }
+
+ for (c = 0; c < V4L2_CTRL_COUNT; c++) {
+ ctrl = &v4l2_ctrls[c];
+
+ switch (ctrl->type) {
+ case MMAL_CONTROL_TYPE_CLUSTER:
+ v4l2_ctrl_auto_cluster(ctrl->min,
+ &dev->ctrls[c + 1],
+ ctrl->max,
+ ctrl->def);
+ break;
+
+ case MMAL_CONTROL_TYPE_STD:
+ case MMAL_CONTROL_TYPE_STD_MENU:
+ case MMAL_CONTROL_TYPE_INT_MENU:
+ break;
+ }
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+ * Broadcom BM2835 V4L2 driver
+ *
+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
+ * Dave Stevenson <dsteve@broadcom.com>
+ * Simon Mellor <simellor@broadcom.com>
+ * Luke Diamand <luked@broadcom.com>
+ *
+ * MMAL structures
+ *
+ */
+
+#define MMAL_FOURCC(a, b, c, d) ((a) | (b << 8) | (c << 16) | (d << 24))
+#define MMAL_MAGIC MMAL_FOURCC('m', 'm', 'a', 'l')
+
+/** Special value signalling that time is not known */
+#define MMAL_TIME_UNKNOWN (1LL<<63)
+
+/* mapping between v4l and mmal video modes */
+struct mmal_fmt {
+ char *name;
+ u32 fourcc; /* v4l2 format id */
+ int flags; /* v4l2 flags field */
+ u32 mmal;
+ int depth;
+ u32 mmal_component; /* MMAL component index to be used to encode */
+ u32 ybbp; /* depth of first Y plane for planar formats */
+};
+
+/* buffer for one video frame */
+struct mmal_buffer {
+ /* v4l buffer data -- must be first */
+ struct vb2_v4l2_buffer vb;
+
+ /* list of buffers available */
+ struct list_head list;
+
+ void *buffer; /* buffer pointer */
+ unsigned long buffer_size; /* size of allocated buffer */
+};
+
+/* */
+struct mmal_colourfx {
+ s32 enable;
+ u32 u;
+ u32 v;
+};
--- /dev/null
+/*
+ * Broadcom BM2835 V4L2 driver
+ *
+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
+ * Dave Stevenson <dsteve@broadcom.com>
+ * Simon Mellor <simellor@broadcom.com>
+ * Luke Diamand <luked@broadcom.com>
+ */
+#ifndef MMAL_ENCODINGS_H
+#define MMAL_ENCODINGS_H
+
+#define MMAL_ENCODING_H264 MMAL_FOURCC('H', '2', '6', '4')
+#define MMAL_ENCODING_H263 MMAL_FOURCC('H', '2', '6', '3')
+#define MMAL_ENCODING_MP4V MMAL_FOURCC('M', 'P', '4', 'V')
+#define MMAL_ENCODING_MP2V MMAL_FOURCC('M', 'P', '2', 'V')
+#define MMAL_ENCODING_MP1V MMAL_FOURCC('M', 'P', '1', 'V')
+#define MMAL_ENCODING_WMV3 MMAL_FOURCC('W', 'M', 'V', '3')
+#define MMAL_ENCODING_WMV2 MMAL_FOURCC('W', 'M', 'V', '2')
+#define MMAL_ENCODING_WMV1 MMAL_FOURCC('W', 'M', 'V', '1')
+#define MMAL_ENCODING_WVC1 MMAL_FOURCC('W', 'V', 'C', '1')
+#define MMAL_ENCODING_VP8 MMAL_FOURCC('V', 'P', '8', ' ')
+#define MMAL_ENCODING_VP7 MMAL_FOURCC('V', 'P', '7', ' ')
+#define MMAL_ENCODING_VP6 MMAL_FOURCC('V', 'P', '6', ' ')
+#define MMAL_ENCODING_THEORA MMAL_FOURCC('T', 'H', 'E', 'O')
+#define MMAL_ENCODING_SPARK MMAL_FOURCC('S', 'P', 'R', 'K')
+#define MMAL_ENCODING_MJPEG MMAL_FOURCC('M', 'J', 'P', 'G')
+
+#define MMAL_ENCODING_JPEG MMAL_FOURCC('J', 'P', 'E', 'G')
+#define MMAL_ENCODING_GIF MMAL_FOURCC('G', 'I', 'F', ' ')
+#define MMAL_ENCODING_PNG MMAL_FOURCC('P', 'N', 'G', ' ')
+#define MMAL_ENCODING_PPM MMAL_FOURCC('P', 'P', 'M', ' ')
+#define MMAL_ENCODING_TGA MMAL_FOURCC('T', 'G', 'A', ' ')
+#define MMAL_ENCODING_BMP MMAL_FOURCC('B', 'M', 'P', ' ')
+
+#define MMAL_ENCODING_I420 MMAL_FOURCC('I', '4', '2', '0')
+#define MMAL_ENCODING_I420_SLICE MMAL_FOURCC('S', '4', '2', '0')
+#define MMAL_ENCODING_YV12 MMAL_FOURCC('Y', 'V', '1', '2')
+#define MMAL_ENCODING_I422 MMAL_FOURCC('I', '4', '2', '2')
+#define MMAL_ENCODING_I422_SLICE MMAL_FOURCC('S', '4', '2', '2')
+#define MMAL_ENCODING_YUYV MMAL_FOURCC('Y', 'U', 'Y', 'V')
+#define MMAL_ENCODING_YVYU MMAL_FOURCC('Y', 'V', 'Y', 'U')
+#define MMAL_ENCODING_UYVY MMAL_FOURCC('U', 'Y', 'V', 'Y')
+#define MMAL_ENCODING_VYUY MMAL_FOURCC('V', 'Y', 'U', 'Y')
+#define MMAL_ENCODING_NV12 MMAL_FOURCC('N', 'V', '1', '2')
+#define MMAL_ENCODING_NV21 MMAL_FOURCC('N', 'V', '2', '1')
+#define MMAL_ENCODING_ARGB MMAL_FOURCC('A', 'R', 'G', 'B')
+#define MMAL_ENCODING_RGBA MMAL_FOURCC('R', 'G', 'B', 'A')
+#define MMAL_ENCODING_ABGR MMAL_FOURCC('A', 'B', 'G', 'R')
+#define MMAL_ENCODING_BGRA MMAL_FOURCC('B', 'G', 'R', 'A')
+#define MMAL_ENCODING_RGB16 MMAL_FOURCC('R', 'G', 'B', '2')
+#define MMAL_ENCODING_RGB24 MMAL_FOURCC('R', 'G', 'B', '3')
+#define MMAL_ENCODING_RGB32 MMAL_FOURCC('R', 'G', 'B', '4')
+#define MMAL_ENCODING_BGR16 MMAL_FOURCC('B', 'G', 'R', '2')
+#define MMAL_ENCODING_BGR24 MMAL_FOURCC('B', 'G', 'R', '3')
+#define MMAL_ENCODING_BGR32 MMAL_FOURCC('B', 'G', 'R', '4')
+
+/** SAND Video (YUVUV128) format, native format understood by VideoCore.
+ * This format is *not* opaque - if requested you will receive full frames
+ * of YUV_UV video.
+ */
+#define MMAL_ENCODING_YUVUV128 MMAL_FOURCC('S', 'A', 'N', 'D')
+
+/** VideoCore opaque image format, image handles are returned to
+ * the host but not the actual image data.
+ */
+#define MMAL_ENCODING_OPAQUE MMAL_FOURCC('O', 'P', 'Q', 'V')
+
+/** An EGL image handle
+ */
+#define MMAL_ENCODING_EGL_IMAGE MMAL_FOURCC('E', 'G', 'L', 'I')
+
+/* }@ */
+
+/** \name Pre-defined audio encodings */
+/* @{ */
+#define MMAL_ENCODING_PCM_UNSIGNED_BE MMAL_FOURCC('P', 'C', 'M', 'U')
+#define MMAL_ENCODING_PCM_UNSIGNED_LE MMAL_FOURCC('p', 'c', 'm', 'u')
+#define MMAL_ENCODING_PCM_SIGNED_BE MMAL_FOURCC('P', 'C', 'M', 'S')
+#define MMAL_ENCODING_PCM_SIGNED_LE MMAL_FOURCC('p', 'c', 'm', 's')
+#define MMAL_ENCODING_PCM_FLOAT_BE MMAL_FOURCC('P', 'C', 'M', 'F')
+#define MMAL_ENCODING_PCM_FLOAT_LE MMAL_FOURCC('p', 'c', 'm', 'f')
+
+/* Pre-defined H264 encoding variants */
+
+/** ISO 14496-10 Annex B byte stream format */
+#define MMAL_ENCODING_VARIANT_H264_DEFAULT 0
+/** ISO 14496-15 AVC stream format */
+#define MMAL_ENCODING_VARIANT_H264_AVC1 MMAL_FOURCC('A', 'V', 'C', '1')
+/** Implicitly delineated NAL units without emulation prevention */
+#define MMAL_ENCODING_VARIANT_H264_RAW MMAL_FOURCC('R', 'A', 'W', ' ')
+
+
+/** \defgroup MmalColorSpace List of pre-defined video color spaces
+ * This defines a list of common color spaces. This list isn't exhaustive and
+ * is only provided as a convenience to avoid clients having to use FourCC
+ * codes directly. However components are allowed to define and use their own
+ * FourCC codes.
+ */
+/* @{ */
+
+/** Unknown color space */
+#define MMAL_COLOR_SPACE_UNKNOWN 0
+/** ITU-R BT.601-5 [SDTV] */
+#define MMAL_COLOR_SPACE_ITUR_BT601 MMAL_FOURCC('Y', '6', '0', '1')
+/** ITU-R BT.709-3 [HDTV] */
+#define MMAL_COLOR_SPACE_ITUR_BT709 MMAL_FOURCC('Y', '7', '0', '9')
+/** JPEG JFIF */
+#define MMAL_COLOR_SPACE_JPEG_JFIF MMAL_FOURCC('Y', 'J', 'F', 'I')
+/** Title 47 Code of Federal Regulations (2003) 73.682 (a) (20) */
+#define MMAL_COLOR_SPACE_FCC MMAL_FOURCC('Y', 'F', 'C', 'C')
+/** Society of Motion Picture and Television Engineers 240M (1999) */
+#define MMAL_COLOR_SPACE_SMPTE240M MMAL_FOURCC('Y', '2', '4', '0')
+/** ITU-R BT.470-2 System M */
+#define MMAL_COLOR_SPACE_BT470_2_M MMAL_FOURCC('Y', '_', '_', 'M')
+/** ITU-R BT.470-2 System BG */
+#define MMAL_COLOR_SPACE_BT470_2_BG MMAL_FOURCC('Y', '_', 'B', 'G')
+/** JPEG JFIF, but with 16..255 luma */
+#define MMAL_COLOR_SPACE_JFIF_Y16_255 MMAL_FOURCC('Y', 'Y', '1', '6')
+/* @} MmalColorSpace List */
+
+#endif /* MMAL_ENCODINGS_H */
--- /dev/null
+/*
+ * Broadcom BM2835 V4L2 driver
+ *
+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
+ * Dave Stevenson <dsteve@broadcom.com>
+ * Simon Mellor <simellor@broadcom.com>
+ * Luke Diamand <luked@broadcom.com>
+ */
+
+#ifndef MMAL_MSG_COMMON_H
+#define MMAL_MSG_COMMON_H
+
+enum mmal_msg_status {
+ MMAL_MSG_STATUS_SUCCESS = 0, /**< Success */
+ MMAL_MSG_STATUS_ENOMEM, /**< Out of memory */
+ MMAL_MSG_STATUS_ENOSPC, /**< Out of resources other than memory */
+ MMAL_MSG_STATUS_EINVAL, /**< Argument is invalid */
+ MMAL_MSG_STATUS_ENOSYS, /**< Function not implemented */
+ MMAL_MSG_STATUS_ENOENT, /**< No such file or directory */
+ MMAL_MSG_STATUS_ENXIO, /**< No such device or address */
+ MMAL_MSG_STATUS_EIO, /**< I/O error */
+ MMAL_MSG_STATUS_ESPIPE, /**< Illegal seek */
+ MMAL_MSG_STATUS_ECORRUPT, /**< Data is corrupt \attention */
+ MMAL_MSG_STATUS_ENOTREADY, /**< Component is not ready */
+ MMAL_MSG_STATUS_ECONFIG, /**< Component is not configured */
+ MMAL_MSG_STATUS_EISCONN, /**< Port is already connected */
+ MMAL_MSG_STATUS_ENOTCONN, /**< Port is disconnected */
+ MMAL_MSG_STATUS_EAGAIN, /**< Resource temporarily unavailable. */
+ MMAL_MSG_STATUS_EFAULT, /**< Bad address */
+};
+
+struct mmal_rect {
+ s32 x; /**< x coordinate (from left) */
+ s32 y; /**< y coordinate (from top) */
+ s32 width; /**< width */
+ s32 height; /**< height */
+};
+
+struct mmal_rational {
+ s32 num; /**< Numerator */
+ s32 den; /**< Denominator */
+};
+
+#endif /* MMAL_MSG_COMMON_H */
--- /dev/null
+/*
+ * Broadcom BM2835 V4L2 driver
+ *
+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
+ * Dave Stevenson <dsteve@broadcom.com>
+ * Simon Mellor <simellor@broadcom.com>
+ * Luke Diamand <luked@broadcom.com>
+ */
+
+#ifndef MMAL_MSG_FORMAT_H
+#define MMAL_MSG_FORMAT_H
+
+#include "mmal-msg-common.h"
+
+/* MMAL_ES_FORMAT_T */
+
+
+struct mmal_audio_format {
+ u32 channels; /**< Number of audio channels */
+ u32 sample_rate; /**< Sample rate */
+
+ u32 bits_per_sample; /**< Bits per sample */
+ u32 block_align; /**< Size of a block of data */
+};
+
+struct mmal_video_format {
+ u32 width; /**< Width of frame in pixels */
+ u32 height; /**< Height of frame in rows of pixels */
+ struct mmal_rect crop; /**< Visible region of the frame */
+ struct mmal_rational frame_rate; /**< Frame rate */
+ struct mmal_rational par; /**< Pixel aspect ratio */
+
+ /* FourCC specifying the color space of the video stream. See the
+ * \ref MmalColorSpace "pre-defined color spaces" for some examples.
+ */
+ u32 color_space;
+};
+
+struct mmal_subpicture_format {
+ u32 x_offset;
+ u32 y_offset;
+};
+
+union mmal_es_specific_format {
+ struct mmal_audio_format audio;
+ struct mmal_video_format video;
+ struct mmal_subpicture_format subpicture;
+};
+
+/** Definition of an elementary stream format (MMAL_ES_FORMAT_T) */
+struct mmal_es_format {
+ u32 type; /* enum mmal_es_type */
+
+ u32 encoding; /* FourCC specifying encoding of the elementary stream.*/
+ u32 encoding_variant; /* FourCC specifying the specific
+ * encoding variant of the elementary
+ * stream.
+ */
+
+ union mmal_es_specific_format *es; /* TODO: pointers in
+ * message serialisation?!?
+ */
+ /* Type specific
+ * information for the
+ * elementary stream
+ */
+
+ u32 bitrate; /**< Bitrate in bits per second */
+ u32 flags; /**< Flags describing properties of the elementary stream. */
+
+ u32 extradata_size; /**< Size of the codec specific data */
+ u8 *extradata; /**< Codec specific data */
+};
+
+#endif /* MMAL_MSG_FORMAT_H */
--- /dev/null
+/*
+ * Broadcom BM2835 V4L2 driver
+ *
+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
+ * Dave Stevenson <dsteve@broadcom.com>
+ * Simon Mellor <simellor@broadcom.com>
+ * Luke Diamand <luked@broadcom.com>
+ */
+
+/* MMAL_PORT_TYPE_T */
+enum mmal_port_type {
+ MMAL_PORT_TYPE_UNKNOWN = 0, /**< Unknown port type */
+ MMAL_PORT_TYPE_CONTROL, /**< Control port */
+ MMAL_PORT_TYPE_INPUT, /**< Input port */
+ MMAL_PORT_TYPE_OUTPUT, /**< Output port */
+ MMAL_PORT_TYPE_CLOCK, /**< Clock port */
+};
+
+/** The port is pass-through and doesn't need buffer headers allocated */
+#define MMAL_PORT_CAPABILITY_PASSTHROUGH 0x01
+/** The port wants to allocate the buffer payloads.
+ * This signals a preference that payload allocation should be done
+ * on this port for efficiency reasons. */
+#define MMAL_PORT_CAPABILITY_ALLOCATION 0x02
+/** The port supports format change events.
+ * This applies to input ports and is used to let the client know
+ * whether the port supports being reconfigured via a format
+ * change event (i.e. without having to disable the port). */
+#define MMAL_PORT_CAPABILITY_SUPPORTS_EVENT_FORMAT_CHANGE 0x04
+
+/* mmal port structure (MMAL_PORT_T)
+ *
+ * most elements are informational only, the pointer values for
+ * interogation messages are generally provided as additional
+ * strucures within the message. When used to set values only teh
+ * buffer_num, buffer_size and userdata parameters are writable.
+ */
+struct mmal_port {
+ void *priv; /* Private member used by the framework */
+ const char *name; /* Port name. Used for debugging purposes (RO) */
+
+ u32 type; /* Type of the port (RO) enum mmal_port_type */
+ u16 index; /* Index of the port in its type list (RO) */
+ u16 index_all; /* Index of the port in the list of all ports (RO) */
+
+ u32 is_enabled; /* Indicates whether the port is enabled or not (RO) */
+ struct mmal_es_format *format; /* Format of the elementary stream */
+
+ u32 buffer_num_min; /* Minimum number of buffers the port
+ * requires (RO). This is set by the
+ * component.
+ */
+
+ u32 buffer_size_min; /* Minimum size of buffers the port
+ * requires (RO). This is set by the
+ * component.
+ */
+
+ u32 buffer_alignment_min; /* Minimum alignment requirement for
+ * the buffers (RO). A value of
+ * zero means no special alignment
+ * requirements. This is set by the
+ * component.
+ */
+
+ u32 buffer_num_recommended; /* Number of buffers the port
+ * recommends for optimal
+ * performance (RO). A value of
+ * zero means no special
+ * recommendation. This is set
+ * by the component.
+ */
+
+ u32 buffer_size_recommended; /* Size of buffers the port
+ * recommends for optimal
+ * performance (RO). A value of
+ * zero means no special
+ * recommendation. This is set
+ * by the component.
+ */
+
+ u32 buffer_num; /* Actual number of buffers the port will use.
+ * This is set by the client.
+ */
+
+ u32 buffer_size; /* Actual maximum size of the buffers that
+ * will be sent to the port. This is set by
+ * the client.
+ */
+
+ void *component; /* Component this port belongs to (Read Only) */
+
+ void *userdata; /* Field reserved for use by the client */
+
+ u32 capabilities; /* Flags describing the capabilities of a
+ * port (RO). Bitwise combination of \ref
+ * portcapabilities "Port capabilities"
+ * values.
+ */
+
+};
--- /dev/null
+/*
+ * Broadcom BM2835 V4L2 driver
+ *
+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
+ * Dave Stevenson <dsteve@broadcom.com>
+ * Simon Mellor <simellor@broadcom.com>
+ * Luke Diamand <luked@broadcom.com>
+ */
+
+/* all the data structures which serialise the MMAL protocol. note
+ * these are directly mapped onto the recived message data.
+ *
+ * BEWARE: They seem to *assume* pointers are u32 and that there is no
+ * structure padding!
+ *
+ * NOTE: this implementation uses kernel types to ensure sizes. Rather
+ * than assigning values to enums to force their size the
+ * implementation uses fixed size types and not the enums (though the
+ * comments have the actual enum type
+ */
+
+#define VC_MMAL_VER 15
+#define VC_MMAL_MIN_VER 10
+#define VC_MMAL_SERVER_NAME MAKE_FOURCC("mmal")
+
+/* max total message size is 512 bytes */
+#define MMAL_MSG_MAX_SIZE 512
+/* with six 32bit header elements max payload is therefore 488 bytes */
+#define MMAL_MSG_MAX_PAYLOAD 488
+
+#include "mmal-msg-common.h"
+#include "mmal-msg-format.h"
+#include "mmal-msg-port.h"
+
+enum mmal_msg_type {
+ MMAL_MSG_TYPE_QUIT = 1,
+ MMAL_MSG_TYPE_SERVICE_CLOSED,
+ MMAL_MSG_TYPE_GET_VERSION,
+ MMAL_MSG_TYPE_COMPONENT_CREATE,
+ MMAL_MSG_TYPE_COMPONENT_DESTROY, /* 5 */
+ MMAL_MSG_TYPE_COMPONENT_ENABLE,
+ MMAL_MSG_TYPE_COMPONENT_DISABLE,
+ MMAL_MSG_TYPE_PORT_INFO_GET,
+ MMAL_MSG_TYPE_PORT_INFO_SET,
+ MMAL_MSG_TYPE_PORT_ACTION, /* 10 */
+ MMAL_MSG_TYPE_BUFFER_FROM_HOST,
+ MMAL_MSG_TYPE_BUFFER_TO_HOST,
+ MMAL_MSG_TYPE_GET_STATS,
+ MMAL_MSG_TYPE_PORT_PARAMETER_SET,
+ MMAL_MSG_TYPE_PORT_PARAMETER_GET, /* 15 */
+ MMAL_MSG_TYPE_EVENT_TO_HOST,
+ MMAL_MSG_TYPE_GET_CORE_STATS_FOR_PORT,
+ MMAL_MSG_TYPE_OPAQUE_ALLOCATOR,
+ MMAL_MSG_TYPE_CONSUME_MEM,
+ MMAL_MSG_TYPE_LMK, /* 20 */
+ MMAL_MSG_TYPE_OPAQUE_ALLOCATOR_DESC,
+ MMAL_MSG_TYPE_DRM_GET_LHS32,
+ MMAL_MSG_TYPE_DRM_GET_TIME,
+ MMAL_MSG_TYPE_BUFFER_FROM_HOST_ZEROLEN,
+ MMAL_MSG_TYPE_PORT_FLUSH, /* 25 */
+ MMAL_MSG_TYPE_HOST_LOG,
+ MMAL_MSG_TYPE_MSG_LAST
+};
+
+/* port action request messages differ depending on the action type */
+enum mmal_msg_port_action_type {
+ MMAL_MSG_PORT_ACTION_TYPE_UNKNOWN = 0, /* Unkown action */
+ MMAL_MSG_PORT_ACTION_TYPE_ENABLE, /* Enable a port */
+ MMAL_MSG_PORT_ACTION_TYPE_DISABLE, /* Disable a port */
+ MMAL_MSG_PORT_ACTION_TYPE_FLUSH, /* Flush a port */
+ MMAL_MSG_PORT_ACTION_TYPE_CONNECT, /* Connect ports */
+ MMAL_MSG_PORT_ACTION_TYPE_DISCONNECT, /* Disconnect ports */
+ MMAL_MSG_PORT_ACTION_TYPE_SET_REQUIREMENTS, /* Set buffer requirements*/
+};
+
+struct mmal_msg_header {
+ u32 magic;
+ u32 type; /** enum mmal_msg_type */
+
+ /* Opaque handle to the control service */
+ struct mmal_control_service *control_service;
+
+ struct mmal_msg_context *context; /** a u32 per message context */
+ u32 status; /** The status of the vchiq operation */
+ u32 padding;
+};
+
+/* Send from VC to host to report version */
+struct mmal_msg_version {
+ u32 flags;
+ u32 major;
+ u32 minor;
+ u32 minimum;
+};
+
+/* request to VC to create component */
+struct mmal_msg_component_create {
+ void *client_component; /* component context */
+ char name[128];
+ u32 pid; /* For debug */
+};
+
+/* reply from VC to component creation request */
+struct mmal_msg_component_create_reply {
+ u32 status; /** enum mmal_msg_status - how does this differ to
+ * the one in the header?
+ */
+ u32 component_handle; /* VideoCore handle for component */
+ u32 input_num; /* Number of input ports */
+ u32 output_num; /* Number of output ports */
+ u32 clock_num; /* Number of clock ports */
+};
+
+/* request to VC to destroy a component */
+struct mmal_msg_component_destroy {
+ u32 component_handle;
+};
+
+struct mmal_msg_component_destroy_reply {
+ u32 status; /** The component destruction status */
+};
+
+
+/* request and reply to VC to enable a component */
+struct mmal_msg_component_enable {
+ u32 component_handle;
+};
+
+struct mmal_msg_component_enable_reply {
+ u32 status; /** The component enable status */
+};
+
+
+/* request and reply to VC to disable a component */
+struct mmal_msg_component_disable {
+ u32 component_handle;
+};
+
+struct mmal_msg_component_disable_reply {
+ u32 status; /** The component disable status */
+};
+
+/* request to VC to get port information */
+struct mmal_msg_port_info_get {
+ u32 component_handle; /* component handle port is associated with */
+ u32 port_type; /* enum mmal_msg_port_type */
+ u32 index; /* port index to query */
+};
+
+/* reply from VC to get port info request */
+struct mmal_msg_port_info_get_reply {
+ u32 status; /** enum mmal_msg_status */
+ u32 component_handle; /* component handle port is associated with */
+ u32 port_type; /* enum mmal_msg_port_type */
+ u32 port_index; /* port indexed in query */
+ s32 found; /* unused */
+ u32 port_handle; /**< Handle to use for this port */
+ struct mmal_port port;
+ struct mmal_es_format format; /* elementry stream format */
+ union mmal_es_specific_format es; /* es type specific data */
+ u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE]; /* es extra data */
+};
+
+/* request to VC to set port information */
+struct mmal_msg_port_info_set {
+ u32 component_handle;
+ u32 port_type; /* enum mmal_msg_port_type */
+ u32 port_index; /* port indexed in query */
+ struct mmal_port port;
+ struct mmal_es_format format;
+ union mmal_es_specific_format es;
+ u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE];
+};
+
+/* reply from VC to port info set request */
+struct mmal_msg_port_info_set_reply {
+ u32 status;
+ u32 component_handle; /* component handle port is associated with */
+ u32 port_type; /* enum mmal_msg_port_type */
+ u32 index; /* port indexed in query */
+ s32 found; /* unused */
+ u32 port_handle; /**< Handle to use for this port */
+ struct mmal_port port;
+ struct mmal_es_format format;
+ union mmal_es_specific_format es;
+ u8 extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE];
+};
+
+
+/* port action requests that take a mmal_port as a parameter */
+struct mmal_msg_port_action_port {
+ u32 component_handle;
+ u32 port_handle;
+ u32 action; /* enum mmal_msg_port_action_type */
+ struct mmal_port port;
+};
+
+/* port action requests that take handles as a parameter */
+struct mmal_msg_port_action_handle {
+ u32 component_handle;
+ u32 port_handle;
+ u32 action; /* enum mmal_msg_port_action_type */
+ u32 connect_component_handle;
+ u32 connect_port_handle;
+};
+
+struct mmal_msg_port_action_reply {
+ u32 status; /** The port action operation status */
+};
+
+
+
+
+/* MMAL buffer transfer */
+
+/** Size of space reserved in a buffer message for short messages. */
+#define MMAL_VC_SHORT_DATA 128
+
+/** Signals that the current payload is the end of the stream of data */
+#define MMAL_BUFFER_HEADER_FLAG_EOS (1<<0)
+/** Signals that the start of the current payload starts a frame */
+#define MMAL_BUFFER_HEADER_FLAG_FRAME_START (1<<1)
+/** Signals that the end of the current payload ends a frame */
+#define MMAL_BUFFER_HEADER_FLAG_FRAME_END (1<<2)
+/** Signals that the current payload contains only complete frames (>1) */
+#define MMAL_BUFFER_HEADER_FLAG_FRAME \
+ (MMAL_BUFFER_HEADER_FLAG_FRAME_START|MMAL_BUFFER_HEADER_FLAG_FRAME_END)
+/** Signals that the current payload is a keyframe (i.e. self decodable) */
+#define MMAL_BUFFER_HEADER_FLAG_KEYFRAME (1<<3)
+/** Signals a discontinuity in the stream of data (e.g. after a seek).
+ * Can be used for instance by a decoder to reset its state */
+#define MMAL_BUFFER_HEADER_FLAG_DISCONTINUITY (1<<4)
+/** Signals a buffer containing some kind of config data for the component
+ * (e.g. codec config data) */
+#define MMAL_BUFFER_HEADER_FLAG_CONFIG (1<<5)
+/** Signals an encrypted payload */
+#define MMAL_BUFFER_HEADER_FLAG_ENCRYPTED (1<<6)
+/** Signals a buffer containing side information */
+#define MMAL_BUFFER_HEADER_FLAG_CODECSIDEINFO (1<<7)
+/** Signals a buffer which is the snapshot/postview image from a stills
+ * capture
+ */
+#define MMAL_BUFFER_HEADER_FLAGS_SNAPSHOT (1<<8)
+/** Signals a buffer which contains data known to be corrupted */
+#define MMAL_BUFFER_HEADER_FLAG_CORRUPTED (1<<9)
+/** Signals that a buffer failed to be transmitted */
+#define MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED (1<<10)
+
+struct mmal_driver_buffer {
+ u32 magic;
+ u32 component_handle;
+ u32 port_handle;
+ void *client_context;
+};
+
+/* buffer header */
+struct mmal_buffer_header {
+ struct mmal_buffer_header *next; /* next header */
+ void *priv; /* framework private data */
+ u32 cmd;
+ void *data;
+ u32 alloc_size;
+ u32 length;
+ u32 offset;
+ u32 flags;
+ s64 pts;
+ s64 dts;
+ void *type;
+ void *user_data;
+};
+
+struct mmal_buffer_header_type_specific {
+ union {
+ struct {
+ u32 planes;
+ u32 offset[4];
+ u32 pitch[4];
+ u32 flags;
+ } video;
+ } u;
+};
+
+struct mmal_msg_buffer_from_host {
+ /* The front 32 bytes of the buffer header are copied
+ * back to us in the reply to allow for context. This
+ * area is used to store two mmal_driver_buffer structures to
+ * allow for multiple concurrent service users.
+ */
+ /* control data */
+ struct mmal_driver_buffer drvbuf;
+
+ /* referenced control data for passthrough buffer management */
+ struct mmal_driver_buffer drvbuf_ref;
+ struct mmal_buffer_header buffer_header; /* buffer header itself */
+ struct mmal_buffer_header_type_specific buffer_header_type_specific;
+ s32 is_zero_copy;
+ s32 has_reference;
+
+ /** allows short data to be xfered in control message */
+ u32 payload_in_message;
+ u8 short_data[MMAL_VC_SHORT_DATA];
+};
+
+
+/* port parameter setting */
+
+#define MMAL_WORKER_PORT_PARAMETER_SPACE 96
+
+struct mmal_msg_port_parameter_set {
+ u32 component_handle; /* component */
+ u32 port_handle; /* port */
+ u32 id; /* Parameter ID */
+ u32 size; /* Parameter size */
+ uint32_t value[MMAL_WORKER_PORT_PARAMETER_SPACE];
+};
+
+struct mmal_msg_port_parameter_set_reply {
+ u32 status; /** enum mmal_msg_status todo: how does this
+ * differ to the one in the header?
+ */
+};
+
+/* port parameter getting */
+
+struct mmal_msg_port_parameter_get {
+ u32 component_handle; /* component */
+ u32 port_handle; /* port */
+ u32 id; /* Parameter ID */
+ u32 size; /* Parameter size */
+};
+
+struct mmal_msg_port_parameter_get_reply {
+ u32 status; /* Status of mmal_port_parameter_get call */
+ u32 id; /* Parameter ID */
+ u32 size; /* Parameter size */
+ uint32_t value[MMAL_WORKER_PORT_PARAMETER_SPACE];
+};
+
+/* event messages */
+#define MMAL_WORKER_EVENT_SPACE 256
+
+struct mmal_msg_event_to_host {
+ void *client_component; /* component context */
+
+ u32 port_type;
+ u32 port_num;
+
+ u32 cmd;
+ u32 length;
+ u8 data[MMAL_WORKER_EVENT_SPACE];
+ struct mmal_buffer_header *delayed_buffer;
+};
+
+/* all mmal messages are serialised through this structure */
+struct mmal_msg {
+ /* header */
+ struct mmal_msg_header h;
+ /* payload */
+ union {
+ struct mmal_msg_version version;
+
+ struct mmal_msg_component_create component_create;
+ struct mmal_msg_component_create_reply component_create_reply;
+
+ struct mmal_msg_component_destroy component_destroy;
+ struct mmal_msg_component_destroy_reply component_destroy_reply;
+
+ struct mmal_msg_component_enable component_enable;
+ struct mmal_msg_component_enable_reply component_enable_reply;
+
+ struct mmal_msg_component_disable component_disable;
+ struct mmal_msg_component_disable_reply component_disable_reply;
+
+ struct mmal_msg_port_info_get port_info_get;
+ struct mmal_msg_port_info_get_reply port_info_get_reply;
+
+ struct mmal_msg_port_info_set port_info_set;
+ struct mmal_msg_port_info_set_reply port_info_set_reply;
+
+ struct mmal_msg_port_action_port port_action_port;
+ struct mmal_msg_port_action_handle port_action_handle;
+ struct mmal_msg_port_action_reply port_action_reply;
+
+ struct mmal_msg_buffer_from_host buffer_from_host;
+
+ struct mmal_msg_port_parameter_set port_parameter_set;
+ struct mmal_msg_port_parameter_set_reply
+ port_parameter_set_reply;
+ struct mmal_msg_port_parameter_get
+ port_parameter_get;
+ struct mmal_msg_port_parameter_get_reply
+ port_parameter_get_reply;
+
+ struct mmal_msg_event_to_host event_to_host;
+
+ u8 payload[MMAL_MSG_MAX_PAYLOAD];
+ } u;
+};
--- /dev/null
+/*
+ * Broadcom BM2835 V4L2 driver
+ *
+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
+ * Dave Stevenson <dsteve@broadcom.com>
+ * Simon Mellor <simellor@broadcom.com>
+ * Luke Diamand <luked@broadcom.com>
+ */
+
+/* common parameters */
+
+/** @name Parameter groups
+ * Parameters are divided into groups, and then allocated sequentially within
+ * a group using an enum.
+ * @{
+ */
+
+/** Common parameter ID group, used with many types of component. */
+#define MMAL_PARAMETER_GROUP_COMMON (0<<16)
+/** Camera-specific parameter ID group. */
+#define MMAL_PARAMETER_GROUP_CAMERA (1<<16)
+/** Video-specific parameter ID group. */
+#define MMAL_PARAMETER_GROUP_VIDEO (2<<16)
+/** Audio-specific parameter ID group. */
+#define MMAL_PARAMETER_GROUP_AUDIO (3<<16)
+/** Clock-specific parameter ID group. */
+#define MMAL_PARAMETER_GROUP_CLOCK (4<<16)
+/** Miracast-specific parameter ID group. */
+#define MMAL_PARAMETER_GROUP_MIRACAST (5<<16)
+
+/* Common parameters */
+enum mmal_parameter_common_type {
+ MMAL_PARAMETER_UNUSED /**< Never a valid parameter ID */
+ = MMAL_PARAMETER_GROUP_COMMON,
+ MMAL_PARAMETER_SUPPORTED_ENCODINGS, /**< MMAL_PARAMETER_ENCODING_T */
+ MMAL_PARAMETER_URI, /**< MMAL_PARAMETER_URI_T */
+
+ /** MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T */
+ MMAL_PARAMETER_CHANGE_EVENT_REQUEST,
+
+ /** MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_ZERO_COPY,
+
+ /**< MMAL_PARAMETER_BUFFER_REQUIREMENTS_T */
+ MMAL_PARAMETER_BUFFER_REQUIREMENTS,
+
+ MMAL_PARAMETER_STATISTICS, /**< MMAL_PARAMETER_STATISTICS_T */
+ MMAL_PARAMETER_CORE_STATISTICS, /**< MMAL_PARAMETER_CORE_STATISTICS_T */
+ MMAL_PARAMETER_MEM_USAGE, /**< MMAL_PARAMETER_MEM_USAGE_T */
+ MMAL_PARAMETER_BUFFER_FLAG_FILTER, /**< MMAL_PARAMETER_UINT32_T */
+ MMAL_PARAMETER_SEEK, /**< MMAL_PARAMETER_SEEK_T */
+ MMAL_PARAMETER_POWERMON_ENABLE, /**< MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_LOGGING, /**< MMAL_PARAMETER_LOGGING_T */
+ MMAL_PARAMETER_SYSTEM_TIME, /**< MMAL_PARAMETER_UINT64_T */
+ MMAL_PARAMETER_NO_IMAGE_PADDING /**< MMAL_PARAMETER_BOOLEAN_T */
+};
+
+/* camera parameters */
+
+enum mmal_parameter_camera_type {
+ /* 0 */
+ /** @ref MMAL_PARAMETER_THUMBNAIL_CONFIG_T */
+ MMAL_PARAMETER_THUMBNAIL_CONFIGURATION
+ = MMAL_PARAMETER_GROUP_CAMERA,
+ MMAL_PARAMETER_CAPTURE_QUALITY, /**< Unused? */
+ MMAL_PARAMETER_ROTATION, /**< @ref MMAL_PARAMETER_INT32_T */
+ MMAL_PARAMETER_EXIF_DISABLE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_EXIF, /**< @ref MMAL_PARAMETER_EXIF_T */
+ MMAL_PARAMETER_AWB_MODE, /**< @ref MMAL_PARAM_AWBMODE_T */
+ MMAL_PARAMETER_IMAGE_EFFECT, /**< @ref MMAL_PARAMETER_IMAGEFX_T */
+ MMAL_PARAMETER_COLOUR_EFFECT, /**< @ref MMAL_PARAMETER_COLOURFX_T */
+ MMAL_PARAMETER_FLICKER_AVOID, /**< @ref MMAL_PARAMETER_FLICKERAVOID_T */
+ MMAL_PARAMETER_FLASH, /**< @ref MMAL_PARAMETER_FLASH_T */
+ MMAL_PARAMETER_REDEYE, /**< @ref MMAL_PARAMETER_REDEYE_T */
+ MMAL_PARAMETER_FOCUS, /**< @ref MMAL_PARAMETER_FOCUS_T */
+ MMAL_PARAMETER_FOCAL_LENGTHS, /**< Unused? */
+ MMAL_PARAMETER_EXPOSURE_COMP, /**< @ref MMAL_PARAMETER_INT32_T */
+ MMAL_PARAMETER_ZOOM, /**< @ref MMAL_PARAMETER_SCALEFACTOR_T */
+ MMAL_PARAMETER_MIRROR, /**< @ref MMAL_PARAMETER_MIRROR_T */
+
+ /* 0x10 */
+ MMAL_PARAMETER_CAMERA_NUM, /**< @ref MMAL_PARAMETER_UINT32_T */
+ MMAL_PARAMETER_CAPTURE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_EXPOSURE_MODE, /**< @ref MMAL_PARAMETER_EXPOSUREMODE_T */
+ MMAL_PARAMETER_EXP_METERING_MODE, /**< @ref MMAL_PARAMETER_EXPOSUREMETERINGMODE_T */
+ MMAL_PARAMETER_FOCUS_STATUS, /**< @ref MMAL_PARAMETER_FOCUS_STATUS_T */
+ MMAL_PARAMETER_CAMERA_CONFIG, /**< @ref MMAL_PARAMETER_CAMERA_CONFIG_T */
+ MMAL_PARAMETER_CAPTURE_STATUS, /**< @ref MMAL_PARAMETER_CAPTURE_STATUS_T */
+ MMAL_PARAMETER_FACE_TRACK, /**< @ref MMAL_PARAMETER_FACE_TRACK_T */
+ MMAL_PARAMETER_DRAW_BOX_FACES_AND_FOCUS, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_JPEG_Q_FACTOR, /**< @ref MMAL_PARAMETER_UINT32_T */
+ MMAL_PARAMETER_FRAME_RATE, /**< @ref MMAL_PARAMETER_FRAME_RATE_T */
+ MMAL_PARAMETER_USE_STC, /**< @ref MMAL_PARAMETER_CAMERA_STC_MODE_T */
+ MMAL_PARAMETER_CAMERA_INFO, /**< @ref MMAL_PARAMETER_CAMERA_INFO_T */
+ MMAL_PARAMETER_VIDEO_STABILISATION, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_FACE_TRACK_RESULTS, /**< @ref MMAL_PARAMETER_FACE_TRACK_RESULTS_T */
+ MMAL_PARAMETER_ENABLE_RAW_CAPTURE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+
+ /* 0x20 */
+ MMAL_PARAMETER_DPF_FILE, /**< @ref MMAL_PARAMETER_URI_T */
+ MMAL_PARAMETER_ENABLE_DPF_FILE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_DPF_FAIL_IS_FATAL, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_CAPTURE_MODE, /**< @ref MMAL_PARAMETER_CAPTUREMODE_T */
+ MMAL_PARAMETER_FOCUS_REGIONS, /**< @ref MMAL_PARAMETER_FOCUS_REGIONS_T */
+ MMAL_PARAMETER_INPUT_CROP, /**< @ref MMAL_PARAMETER_INPUT_CROP_T */
+ MMAL_PARAMETER_SENSOR_INFORMATION, /**< @ref MMAL_PARAMETER_SENSOR_INFORMATION_T */
+ MMAL_PARAMETER_FLASH_SELECT, /**< @ref MMAL_PARAMETER_FLASH_SELECT_T */
+ MMAL_PARAMETER_FIELD_OF_VIEW, /**< @ref MMAL_PARAMETER_FIELD_OF_VIEW_T */
+ MMAL_PARAMETER_HIGH_DYNAMIC_RANGE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_DYNAMIC_RANGE_COMPRESSION, /**< @ref MMAL_PARAMETER_DRC_T */
+ MMAL_PARAMETER_ALGORITHM_CONTROL, /**< @ref MMAL_PARAMETER_ALGORITHM_CONTROL_T */
+ MMAL_PARAMETER_SHARPNESS, /**< @ref MMAL_PARAMETER_RATIONAL_T */
+ MMAL_PARAMETER_CONTRAST, /**< @ref MMAL_PARAMETER_RATIONAL_T */
+ MMAL_PARAMETER_BRIGHTNESS, /**< @ref MMAL_PARAMETER_RATIONAL_T */
+ MMAL_PARAMETER_SATURATION, /**< @ref MMAL_PARAMETER_RATIONAL_T */
+
+ /* 0x30 */
+ MMAL_PARAMETER_ISO, /**< @ref MMAL_PARAMETER_UINT32_T */
+ MMAL_PARAMETER_ANTISHAKE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+
+ /** @ref MMAL_PARAMETER_IMAGEFX_PARAMETERS_T */
+ MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS,
+
+ /** @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_CAMERA_BURST_CAPTURE,
+
+ /** @ref MMAL_PARAMETER_UINT32_T */
+ MMAL_PARAMETER_CAMERA_MIN_ISO,
+
+ /** @ref MMAL_PARAMETER_CAMERA_USE_CASE_T */
+ MMAL_PARAMETER_CAMERA_USE_CASE,
+
+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_CAPTURE_STATS_PASS,
+
+ /** @ref MMAL_PARAMETER_UINT32_T */
+ MMAL_PARAMETER_CAMERA_CUSTOM_SENSOR_CONFIG,
+
+ /** @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_ENABLE_REGISTER_FILE,
+
+ /** @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_REGISTER_FAIL_IS_FATAL,
+
+ /** @ref MMAL_PARAMETER_CONFIGFILE_T */
+ MMAL_PARAMETER_CONFIGFILE_REGISTERS,
+
+ /** @ref MMAL_PARAMETER_CONFIGFILE_CHUNK_T */
+ MMAL_PARAMETER_CONFIGFILE_CHUNK_REGISTERS,
+ MMAL_PARAMETER_JPEG_ATTACH_LOG, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_ZERO_SHUTTER_LAG, /**< @ref MMAL_PARAMETER_ZEROSHUTTERLAG_T */
+ MMAL_PARAMETER_FPS_RANGE, /**< @ref MMAL_PARAMETER_FPS_RANGE_T */
+ MMAL_PARAMETER_CAPTURE_EXPOSURE_COMP, /**< @ref MMAL_PARAMETER_INT32_T */
+
+ /* 0x40 */
+ MMAL_PARAMETER_SW_SHARPEN_DISABLE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_FLASH_REQUIRED, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_SW_SATURATION_DISABLE, /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_SHUTTER_SPEED, /**< Takes a @ref MMAL_PARAMETER_UINT32_T */
+ MMAL_PARAMETER_CUSTOM_AWB_GAINS, /**< Takes a @ref MMAL_PARAMETER_AWB_GAINS_T */
+};
+
+struct mmal_parameter_rational {
+ s32 num; /**< Numerator */
+ s32 den; /**< Denominator */
+};
+
+enum mmal_parameter_camera_config_timestamp_mode {
+ MMAL_PARAM_TIMESTAMP_MODE_ZERO = 0, /* Always timestamp frames as 0 */
+ MMAL_PARAM_TIMESTAMP_MODE_RAW_STC, /* Use the raw STC value
+ * for the frame timestamp
+ */
+ MMAL_PARAM_TIMESTAMP_MODE_RESET_STC, /* Use the STC timestamp
+ * but subtract the
+ * timestamp of the first
+ * frame sent to give a
+ * zero based timestamp.
+ */
+};
+
+struct mmal_parameter_fps_range {
+ /**< Low end of the permitted framerate range */
+ struct mmal_parameter_rational fps_low;
+ /**< High end of the permitted framerate range */
+ struct mmal_parameter_rational fps_high;
+};
+
+
+/* camera configuration parameter */
+struct mmal_parameter_camera_config {
+ /* Parameters for setting up the image pools */
+ u32 max_stills_w; /* Max size of stills capture */
+ u32 max_stills_h;
+ u32 stills_yuv422; /* Allow YUV422 stills capture */
+ u32 one_shot_stills; /* Continuous or one shot stills captures. */
+
+ u32 max_preview_video_w; /* Max size of the preview or video
+ * capture frames
+ */
+ u32 max_preview_video_h;
+ u32 num_preview_video_frames;
+
+ /** Sets the height of the circular buffer for stills capture. */
+ u32 stills_capture_circular_buffer_height;
+
+ /** Allows preview/encode to resume as fast as possible after the stills
+ * input frame has been received, and then processes the still frame in
+ * the background whilst preview/encode has resumed.
+ * Actual mode is controlled by MMAL_PARAMETER_CAPTURE_MODE.
+ */
+ u32 fast_preview_resume;
+
+ /** Selects algorithm for timestamping frames if
+ * there is no clock component connected.
+ * enum mmal_parameter_camera_config_timestamp_mode
+ */
+ s32 use_stc_timestamp;
+};
+
+
+enum mmal_parameter_exposuremode {
+ MMAL_PARAM_EXPOSUREMODE_OFF,
+ MMAL_PARAM_EXPOSUREMODE_AUTO,
+ MMAL_PARAM_EXPOSUREMODE_NIGHT,
+ MMAL_PARAM_EXPOSUREMODE_NIGHTPREVIEW,
+ MMAL_PARAM_EXPOSUREMODE_BACKLIGHT,
+ MMAL_PARAM_EXPOSUREMODE_SPOTLIGHT,
+ MMAL_PARAM_EXPOSUREMODE_SPORTS,
+ MMAL_PARAM_EXPOSUREMODE_SNOW,
+ MMAL_PARAM_EXPOSUREMODE_BEACH,
+ MMAL_PARAM_EXPOSUREMODE_VERYLONG,
+ MMAL_PARAM_EXPOSUREMODE_FIXEDFPS,
+ MMAL_PARAM_EXPOSUREMODE_ANTISHAKE,
+ MMAL_PARAM_EXPOSUREMODE_FIREWORKS,
+};
+
+enum mmal_parameter_exposuremeteringmode {
+ MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE,
+ MMAL_PARAM_EXPOSUREMETERINGMODE_SPOT,
+ MMAL_PARAM_EXPOSUREMETERINGMODE_BACKLIT,
+ MMAL_PARAM_EXPOSUREMETERINGMODE_MATRIX,
+};
+
+enum mmal_parameter_awbmode {
+ MMAL_PARAM_AWBMODE_OFF,
+ MMAL_PARAM_AWBMODE_AUTO,
+ MMAL_PARAM_AWBMODE_SUNLIGHT,
+ MMAL_PARAM_AWBMODE_CLOUDY,
+ MMAL_PARAM_AWBMODE_SHADE,
+ MMAL_PARAM_AWBMODE_TUNGSTEN,
+ MMAL_PARAM_AWBMODE_FLUORESCENT,
+ MMAL_PARAM_AWBMODE_INCANDESCENT,
+ MMAL_PARAM_AWBMODE_FLASH,
+ MMAL_PARAM_AWBMODE_HORIZON,
+};
+
+enum mmal_parameter_imagefx {
+ MMAL_PARAM_IMAGEFX_NONE,
+ MMAL_PARAM_IMAGEFX_NEGATIVE,
+ MMAL_PARAM_IMAGEFX_SOLARIZE,
+ MMAL_PARAM_IMAGEFX_POSTERIZE,
+ MMAL_PARAM_IMAGEFX_WHITEBOARD,
+ MMAL_PARAM_IMAGEFX_BLACKBOARD,
+ MMAL_PARAM_IMAGEFX_SKETCH,
+ MMAL_PARAM_IMAGEFX_DENOISE,
+ MMAL_PARAM_IMAGEFX_EMBOSS,
+ MMAL_PARAM_IMAGEFX_OILPAINT,
+ MMAL_PARAM_IMAGEFX_HATCH,
+ MMAL_PARAM_IMAGEFX_GPEN,
+ MMAL_PARAM_IMAGEFX_PASTEL,
+ MMAL_PARAM_IMAGEFX_WATERCOLOUR,
+ MMAL_PARAM_IMAGEFX_FILM,
+ MMAL_PARAM_IMAGEFX_BLUR,
+ MMAL_PARAM_IMAGEFX_SATURATION,
+ MMAL_PARAM_IMAGEFX_COLOURSWAP,
+ MMAL_PARAM_IMAGEFX_WASHEDOUT,
+ MMAL_PARAM_IMAGEFX_POSTERISE,
+ MMAL_PARAM_IMAGEFX_COLOURPOINT,
+ MMAL_PARAM_IMAGEFX_COLOURBALANCE,
+ MMAL_PARAM_IMAGEFX_CARTOON,
+};
+
+enum MMAL_PARAM_FLICKERAVOID_T {
+ MMAL_PARAM_FLICKERAVOID_OFF,
+ MMAL_PARAM_FLICKERAVOID_AUTO,
+ MMAL_PARAM_FLICKERAVOID_50HZ,
+ MMAL_PARAM_FLICKERAVOID_60HZ,
+ MMAL_PARAM_FLICKERAVOID_MAX = 0x7FFFFFFF
+};
+
+struct mmal_parameter_awbgains {
+ struct mmal_parameter_rational r_gain; /**< Red gain */
+ struct mmal_parameter_rational b_gain; /**< Blue gain */
+};
+
+/** Manner of video rate control */
+enum mmal_parameter_rate_control_mode {
+ MMAL_VIDEO_RATECONTROL_DEFAULT,
+ MMAL_VIDEO_RATECONTROL_VARIABLE,
+ MMAL_VIDEO_RATECONTROL_CONSTANT,
+ MMAL_VIDEO_RATECONTROL_VARIABLE_SKIP_FRAMES,
+ MMAL_VIDEO_RATECONTROL_CONSTANT_SKIP_FRAMES
+};
+
+enum mmal_video_profile {
+ MMAL_VIDEO_PROFILE_H263_BASELINE,
+ MMAL_VIDEO_PROFILE_H263_H320CODING,
+ MMAL_VIDEO_PROFILE_H263_BACKWARDCOMPATIBLE,
+ MMAL_VIDEO_PROFILE_H263_ISWV2,
+ MMAL_VIDEO_PROFILE_H263_ISWV3,
+ MMAL_VIDEO_PROFILE_H263_HIGHCOMPRESSION,
+ MMAL_VIDEO_PROFILE_H263_INTERNET,
+ MMAL_VIDEO_PROFILE_H263_INTERLACE,
+ MMAL_VIDEO_PROFILE_H263_HIGHLATENCY,
+ MMAL_VIDEO_PROFILE_MP4V_SIMPLE,
+ MMAL_VIDEO_PROFILE_MP4V_SIMPLESCALABLE,
+ MMAL_VIDEO_PROFILE_MP4V_CORE,
+ MMAL_VIDEO_PROFILE_MP4V_MAIN,
+ MMAL_VIDEO_PROFILE_MP4V_NBIT,
+ MMAL_VIDEO_PROFILE_MP4V_SCALABLETEXTURE,
+ MMAL_VIDEO_PROFILE_MP4V_SIMPLEFACE,
+ MMAL_VIDEO_PROFILE_MP4V_SIMPLEFBA,
+ MMAL_VIDEO_PROFILE_MP4V_BASICANIMATED,
+ MMAL_VIDEO_PROFILE_MP4V_HYBRID,
+ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDREALTIME,
+ MMAL_VIDEO_PROFILE_MP4V_CORESCALABLE,
+ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDCODING,
+ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDCORE,
+ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDSCALABLE,
+ MMAL_VIDEO_PROFILE_MP4V_ADVANCEDSIMPLE,
+ MMAL_VIDEO_PROFILE_H264_BASELINE,
+ MMAL_VIDEO_PROFILE_H264_MAIN,
+ MMAL_VIDEO_PROFILE_H264_EXTENDED,
+ MMAL_VIDEO_PROFILE_H264_HIGH,
+ MMAL_VIDEO_PROFILE_H264_HIGH10,
+ MMAL_VIDEO_PROFILE_H264_HIGH422,
+ MMAL_VIDEO_PROFILE_H264_HIGH444,
+ MMAL_VIDEO_PROFILE_H264_CONSTRAINED_BASELINE,
+ MMAL_VIDEO_PROFILE_DUMMY = 0x7FFFFFFF
+};
+
+enum mmal_video_level {
+ MMAL_VIDEO_LEVEL_H263_10,
+ MMAL_VIDEO_LEVEL_H263_20,
+ MMAL_VIDEO_LEVEL_H263_30,
+ MMAL_VIDEO_LEVEL_H263_40,
+ MMAL_VIDEO_LEVEL_H263_45,
+ MMAL_VIDEO_LEVEL_H263_50,
+ MMAL_VIDEO_LEVEL_H263_60,
+ MMAL_VIDEO_LEVEL_H263_70,
+ MMAL_VIDEO_LEVEL_MP4V_0,
+ MMAL_VIDEO_LEVEL_MP4V_0b,
+ MMAL_VIDEO_LEVEL_MP4V_1,
+ MMAL_VIDEO_LEVEL_MP4V_2,
+ MMAL_VIDEO_LEVEL_MP4V_3,
+ MMAL_VIDEO_LEVEL_MP4V_4,
+ MMAL_VIDEO_LEVEL_MP4V_4a,
+ MMAL_VIDEO_LEVEL_MP4V_5,
+ MMAL_VIDEO_LEVEL_MP4V_6,
+ MMAL_VIDEO_LEVEL_H264_1,
+ MMAL_VIDEO_LEVEL_H264_1b,
+ MMAL_VIDEO_LEVEL_H264_11,
+ MMAL_VIDEO_LEVEL_H264_12,
+ MMAL_VIDEO_LEVEL_H264_13,
+ MMAL_VIDEO_LEVEL_H264_2,
+ MMAL_VIDEO_LEVEL_H264_21,
+ MMAL_VIDEO_LEVEL_H264_22,
+ MMAL_VIDEO_LEVEL_H264_3,
+ MMAL_VIDEO_LEVEL_H264_31,
+ MMAL_VIDEO_LEVEL_H264_32,
+ MMAL_VIDEO_LEVEL_H264_4,
+ MMAL_VIDEO_LEVEL_H264_41,
+ MMAL_VIDEO_LEVEL_H264_42,
+ MMAL_VIDEO_LEVEL_H264_5,
+ MMAL_VIDEO_LEVEL_H264_51,
+ MMAL_VIDEO_LEVEL_DUMMY = 0x7FFFFFFF
+};
+
+struct mmal_parameter_video_profile {
+ enum mmal_video_profile profile;
+ enum mmal_video_level level;
+};
+
+/* video parameters */
+
+enum mmal_parameter_video_type {
+ /** @ref MMAL_DISPLAYREGION_T */
+ MMAL_PARAMETER_DISPLAYREGION = MMAL_PARAMETER_GROUP_VIDEO,
+
+ /** @ref MMAL_PARAMETER_VIDEO_PROFILE_T */
+ MMAL_PARAMETER_SUPPORTED_PROFILES,
+
+ /** @ref MMAL_PARAMETER_VIDEO_PROFILE_T */
+ MMAL_PARAMETER_PROFILE,
+
+ /** @ref MMAL_PARAMETER_UINT32_T */
+ MMAL_PARAMETER_INTRAPERIOD,
+
+ /** @ref MMAL_PARAMETER_VIDEO_RATECONTROL_T */
+ MMAL_PARAMETER_RATECONTROL,
+
+ /** @ref MMAL_PARAMETER_VIDEO_NALUNITFORMAT_T */
+ MMAL_PARAMETER_NALUNITFORMAT,
+
+ /** @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_MINIMISE_FRAGMENTATION,
+
+ /** @ref MMAL_PARAMETER_UINT32_T.
+ * Setting the value to zero resets to the default (one slice per frame).
+ */
+ MMAL_PARAMETER_MB_ROWS_PER_SLICE,
+
+ /** @ref MMAL_PARAMETER_VIDEO_LEVEL_EXTENSION_T */
+ MMAL_PARAMETER_VIDEO_LEVEL_EXTENSION,
+
+ /** @ref MMAL_PARAMETER_VIDEO_EEDE_ENABLE_T */
+ MMAL_PARAMETER_VIDEO_EEDE_ENABLE,
+
+ /** @ref MMAL_PARAMETER_VIDEO_EEDE_LOSSRATE_T */
+ MMAL_PARAMETER_VIDEO_EEDE_LOSSRATE,
+
+ /** @ref MMAL_PARAMETER_BOOLEAN_T. Request an I-frame. */
+ MMAL_PARAMETER_VIDEO_REQUEST_I_FRAME,
+ /** @ref MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T */
+ MMAL_PARAMETER_VIDEO_INTRA_REFRESH,
+
+ /** @ref MMAL_PARAMETER_BOOLEAN_T. */
+ MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT,
+
+ /** @ref MMAL_PARAMETER_UINT32_T. Run-time bit rate control */
+ MMAL_PARAMETER_VIDEO_BIT_RATE,
+
+ /** @ref MMAL_PARAMETER_FRAME_RATE_T */
+ MMAL_PARAMETER_VIDEO_FRAME_RATE,
+
+ /** @ref MMAL_PARAMETER_UINT32_T. */
+ MMAL_PARAMETER_VIDEO_ENCODE_MIN_QUANT,
+
+ /** @ref MMAL_PARAMETER_UINT32_T. */
+ MMAL_PARAMETER_VIDEO_ENCODE_MAX_QUANT,
+
+ /** @ref MMAL_PARAMETER_VIDEO_ENCODE_RC_MODEL_T. */
+ MMAL_PARAMETER_VIDEO_ENCODE_RC_MODEL,
+
+ MMAL_PARAMETER_EXTRA_BUFFERS, /**< @ref MMAL_PARAMETER_UINT32_T. */
+ /** @ref MMAL_PARAMETER_UINT32_T.
+ * Changing this parameter from the default can reduce frame rate
+ * because image buffers need to be re-pitched.
+ */
+ MMAL_PARAMETER_VIDEO_ALIGN_HORIZ,
+
+ /** @ref MMAL_PARAMETER_UINT32_T.
+ * Changing this parameter from the default can reduce frame rate
+ * because image buffers need to be re-pitched.
+ */
+ MMAL_PARAMETER_VIDEO_ALIGN_VERT,
+
+ /** @ref MMAL_PARAMETER_BOOLEAN_T. */
+ MMAL_PARAMETER_VIDEO_DROPPABLE_PFRAMES,
+
+ /** @ref MMAL_PARAMETER_UINT32_T. */
+ MMAL_PARAMETER_VIDEO_ENCODE_INITIAL_QUANT,
+
+ /**< @ref MMAL_PARAMETER_UINT32_T. */
+ MMAL_PARAMETER_VIDEO_ENCODE_QP_P,
+
+ /**< @ref MMAL_PARAMETER_UINT32_T. */
+ MMAL_PARAMETER_VIDEO_ENCODE_RC_SLICE_DQUANT,
+
+ /** @ref MMAL_PARAMETER_UINT32_T */
+ MMAL_PARAMETER_VIDEO_ENCODE_FRAME_LIMIT_BITS,
+
+ /** @ref MMAL_PARAMETER_UINT32_T. */
+ MMAL_PARAMETER_VIDEO_ENCODE_PEAK_RATE,
+
+ /* H264 specific parameters */
+
+ /** @ref MMAL_PARAMETER_BOOLEAN_T. */
+ MMAL_PARAMETER_VIDEO_ENCODE_H264_DISABLE_CABAC,
+
+ /** @ref MMAL_PARAMETER_BOOLEAN_T. */
+ MMAL_PARAMETER_VIDEO_ENCODE_H264_LOW_LATENCY,
+
+ /** @ref MMAL_PARAMETER_BOOLEAN_T. */
+ MMAL_PARAMETER_VIDEO_ENCODE_H264_AU_DELIMITERS,
+
+ /** @ref MMAL_PARAMETER_UINT32_T. */
+ MMAL_PARAMETER_VIDEO_ENCODE_H264_DEBLOCK_IDC,
+
+ /** @ref MMAL_PARAMETER_VIDEO_ENCODER_H264_MB_INTRA_MODES_T. */
+ MMAL_PARAMETER_VIDEO_ENCODE_H264_MB_INTRA_MODE,
+
+ /** @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_VIDEO_ENCODE_HEADER_ON_OPEN,
+
+ /** @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_VIDEO_ENCODE_PRECODE_FOR_QP,
+
+ /** @ref MMAL_PARAMETER_VIDEO_DRM_INIT_INFO_T. */
+ MMAL_PARAMETER_VIDEO_DRM_INIT_INFO,
+
+ /** @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_VIDEO_TIMESTAMP_FIFO,
+
+ /** @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_VIDEO_DECODE_ERROR_CONCEALMENT,
+
+ /** @ref MMAL_PARAMETER_VIDEO_DRM_PROTECT_BUFFER_T. */
+ MMAL_PARAMETER_VIDEO_DRM_PROTECT_BUFFER,
+
+ /** @ref MMAL_PARAMETER_BYTES_T */
+ MMAL_PARAMETER_VIDEO_DECODE_CONFIG_VD3,
+
+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_VIDEO_ENCODE_H264_VCL_HRD_PARAMETERS,
+
+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_VIDEO_ENCODE_H264_LOW_DELAY_HRD_FLAG,
+
+ /**< @ref MMAL_PARAMETER_BOOLEAN_T */
+ MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER
+};
+
+/** Valid mirror modes */
+enum mmal_parameter_mirror {
+ MMAL_PARAM_MIRROR_NONE,
+ MMAL_PARAM_MIRROR_VERTICAL,
+ MMAL_PARAM_MIRROR_HORIZONTAL,
+ MMAL_PARAM_MIRROR_BOTH,
+};
+
+enum mmal_parameter_displaytransform {
+ MMAL_DISPLAY_ROT0 = 0,
+ MMAL_DISPLAY_MIRROR_ROT0 = 1,
+ MMAL_DISPLAY_MIRROR_ROT180 = 2,
+ MMAL_DISPLAY_ROT180 = 3,
+ MMAL_DISPLAY_MIRROR_ROT90 = 4,
+ MMAL_DISPLAY_ROT270 = 5,
+ MMAL_DISPLAY_ROT90 = 6,
+ MMAL_DISPLAY_MIRROR_ROT270 = 7,
+};
+
+enum mmal_parameter_displaymode {
+ MMAL_DISPLAY_MODE_FILL = 0,
+ MMAL_DISPLAY_MODE_LETTERBOX = 1,
+};
+
+enum mmal_parameter_displayset {
+ MMAL_DISPLAY_SET_NONE = 0,
+ MMAL_DISPLAY_SET_NUM = 1,
+ MMAL_DISPLAY_SET_FULLSCREEN = 2,
+ MMAL_DISPLAY_SET_TRANSFORM = 4,
+ MMAL_DISPLAY_SET_DEST_RECT = 8,
+ MMAL_DISPLAY_SET_SRC_RECT = 0x10,
+ MMAL_DISPLAY_SET_MODE = 0x20,
+ MMAL_DISPLAY_SET_PIXEL = 0x40,
+ MMAL_DISPLAY_SET_NOASPECT = 0x80,
+ MMAL_DISPLAY_SET_LAYER = 0x100,
+ MMAL_DISPLAY_SET_COPYPROTECT = 0x200,
+ MMAL_DISPLAY_SET_ALPHA = 0x400,
+};
+
+struct mmal_parameter_displayregion {
+ /** Bitfield that indicates which fields are set and should be
+ * used. All other fields will maintain their current value.
+ * \ref MMAL_DISPLAYSET_T defines the bits that can be
+ * combined.
+ */
+ u32 set;
+
+ /** Describes the display output device, with 0 typically
+ * being a directly connected LCD display. The actual values
+ * will depend on the hardware. Code using hard-wired numbers
+ * (e.g. 2) is certain to fail.
+ */
+
+ u32 display_num;
+ /** Indicates that we are using the full device screen area,
+ * rather than a window of the display. If zero, then
+ * dest_rect is used to specify a region of the display to
+ * use.
+ */
+
+ s32 fullscreen;
+ /** Indicates any rotation or flipping used to map frames onto
+ * the natural display orientation.
+ */
+ u32 transform; /* enum mmal_parameter_displaytransform */
+
+ /** Where to display the frame within the screen, if
+ * fullscreen is zero.
+ */
+ struct vchiq_mmal_rect dest_rect;
+
+ /** Indicates which area of the frame to display. If all
+ * values are zero, the whole frame will be used.
+ */
+ struct vchiq_mmal_rect src_rect;
+
+ /** If set to non-zero, indicates that any display scaling
+ * should disregard the aspect ratio of the frame region being
+ * displayed.
+ */
+ s32 noaspect;
+
+ /** Indicates how the image should be scaled to fit the
+ * display. \code MMAL_DISPLAY_MODE_FILL \endcode indicates
+ * that the image should fill the screen by potentially
+ * cropping the frames. Setting \code mode \endcode to \code
+ * MMAL_DISPLAY_MODE_LETTERBOX \endcode indicates that all the
+ * source region should be displayed and black bars added if
+ * necessary.
+ */
+ u32 mode; /* enum mmal_parameter_displaymode */
+
+ /** If non-zero, defines the width of a source pixel relative
+ * to \code pixel_y \endcode. If zero, then pixels default to
+ * being square.
+ */
+ u32 pixel_x;
+
+ /** If non-zero, defines the height of a source pixel relative
+ * to \code pixel_x \endcode. If zero, then pixels default to
+ * being square.
+ */
+ u32 pixel_y;
+
+ /** Sets the relative depth of the images, with greater values
+ * being in front of smaller values.
+ */
+ u32 layer;
+
+ /** Set to non-zero to ensure copy protection is used on
+ * output.
+ */
+ s32 copyprotect_required;
+
+ /** Level of opacity of the layer, where zero is fully
+ * transparent and 255 is fully opaque.
+ */
+ u32 alpha;
+};
+
+#define MMAL_MAX_IMAGEFX_PARAMETERS 5
+
+struct mmal_parameter_imagefx_parameters {
+ enum mmal_parameter_imagefx effect;
+ u32 num_effect_params;
+ u32 effect_parameter[MMAL_MAX_IMAGEFX_PARAMETERS];
+};
+
+#define MMAL_PARAMETER_CAMERA_INFO_MAX_CAMERAS 4
+#define MMAL_PARAMETER_CAMERA_INFO_MAX_FLASHES 2
+#define MMAL_PARAMETER_CAMERA_INFO_MAX_STR_LEN 16
+
+struct mmal_parameter_camera_info_camera_t {
+ u32 port_id;
+ u32 max_width;
+ u32 max_height;
+ u32 lens_present;
+ u8 camera_name[MMAL_PARAMETER_CAMERA_INFO_MAX_STR_LEN];
+};
+
+enum mmal_parameter_camera_info_flash_type_t {
+ /* Make values explicit to ensure they match values in config ini */
+ MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_XENON = 0,
+ MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_LED = 1,
+ MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_OTHER = 2,
+ MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_MAX = 0x7FFFFFFF
+};
+
+struct mmal_parameter_camera_info_flash_t {
+ enum mmal_parameter_camera_info_flash_type_t flash_type;
+};
+
+struct mmal_parameter_camera_info_t {
+ u32 num_cameras;
+ u32 num_flashes;
+ struct mmal_parameter_camera_info_camera_t
+ cameras[MMAL_PARAMETER_CAMERA_INFO_MAX_CAMERAS];
+ struct mmal_parameter_camera_info_flash_t
+ flashes[MMAL_PARAMETER_CAMERA_INFO_MAX_FLASHES];
+};
--- /dev/null
+/*
+ * Broadcom BM2835 V4L2 driver
+ *
+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
+ * Dave Stevenson <dsteve@broadcom.com>
+ * Simon Mellor <simellor@broadcom.com>
+ * Luke Diamand <luked@broadcom.com>
+ *
+ * V4L2 driver MMAL vchiq interface code
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/completion.h>
+#include <linux/vmalloc.h>
+#include <asm/cacheflush.h>
+#include <media/videobuf2-vmalloc.h>
+
+#include "mmal-common.h"
+#include "mmal-vchiq.h"
+#include "mmal-msg.h"
+
+#define USE_VCHIQ_ARM
+#include "interface/vchi/vchi.h"
+
+/* maximum number of components supported */
+#define VCHIQ_MMAL_MAX_COMPONENTS 4
+
+/*#define FULL_MSG_DUMP 1*/
+
+#ifdef DEBUG
+static const char *const msg_type_names[] = {
+ "UNKNOWN",
+ "QUIT",
+ "SERVICE_CLOSED",
+ "GET_VERSION",
+ "COMPONENT_CREATE",
+ "COMPONENT_DESTROY",
+ "COMPONENT_ENABLE",
+ "COMPONENT_DISABLE",
+ "PORT_INFO_GET",
+ "PORT_INFO_SET",
+ "PORT_ACTION",
+ "BUFFER_FROM_HOST",
+ "BUFFER_TO_HOST",
+ "GET_STATS",
+ "PORT_PARAMETER_SET",
+ "PORT_PARAMETER_GET",
+ "EVENT_TO_HOST",
+ "GET_CORE_STATS_FOR_PORT",
+ "OPAQUE_ALLOCATOR",
+ "CONSUME_MEM",
+ "LMK",
+ "OPAQUE_ALLOCATOR_DESC",
+ "DRM_GET_LHS32",
+ "DRM_GET_TIME",
+ "BUFFER_FROM_HOST_ZEROLEN",
+ "PORT_FLUSH",
+ "HOST_LOG",
+};
+#endif
+
+static const char *const port_action_type_names[] = {
+ "UNKNOWN",
+ "ENABLE",
+ "DISABLE",
+ "FLUSH",
+ "CONNECT",
+ "DISCONNECT",
+ "SET_REQUIREMENTS",
+};
+
+#if defined(DEBUG)
+#if defined(FULL_MSG_DUMP)
+#define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE) \
+ do { \
+ pr_debug(TITLE" type:%s(%d) length:%d\n", \
+ msg_type_names[(MSG)->h.type], \
+ (MSG)->h.type, (MSG_LEN)); \
+ print_hex_dump(KERN_DEBUG, "<<h: ", DUMP_PREFIX_OFFSET, \
+ 16, 4, (MSG), \
+ sizeof(struct mmal_msg_header), 1); \
+ print_hex_dump(KERN_DEBUG, "<<p: ", DUMP_PREFIX_OFFSET, \
+ 16, 4, \
+ ((u8 *)(MSG)) + sizeof(struct mmal_msg_header),\
+ (MSG_LEN) - sizeof(struct mmal_msg_header), 1); \
+ } while (0)
+#else
+#define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE) \
+ { \
+ pr_debug(TITLE" type:%s(%d) length:%d\n", \
+ msg_type_names[(MSG)->h.type], \
+ (MSG)->h.type, (MSG_LEN)); \
+ }
+#endif
+#else
+#define DBG_DUMP_MSG(MSG, MSG_LEN, TITLE)
+#endif
+
+/* normal message context */
+struct mmal_msg_context {
+ union {
+ struct {
+ /* work struct for defered callback - must come first */
+ struct work_struct work;
+ /* mmal instance */
+ struct vchiq_mmal_instance *instance;
+ /* mmal port */
+ struct vchiq_mmal_port *port;
+ /* actual buffer used to store bulk reply */
+ struct mmal_buffer *buffer;
+ /* amount of buffer used */
+ unsigned long buffer_used;
+ /* MMAL buffer flags */
+ u32 mmal_flags;
+ /* Presentation and Decode timestamps */
+ s64 pts;
+ s64 dts;
+
+ int status; /* context status */
+
+ } bulk; /* bulk data */
+
+ struct {
+ /* message handle to release */
+ VCHI_HELD_MSG_T msg_handle;
+ /* pointer to received message */
+ struct mmal_msg *msg;
+ /* received message length */
+ u32 msg_len;
+ /* completion upon reply */
+ struct completion cmplt;
+ } sync; /* synchronous response */
+ } u;
+
+};
+
+struct vchiq_mmal_instance {
+ VCHI_SERVICE_HANDLE_T handle;
+
+ /* ensure serialised access to service */
+ struct mutex vchiq_mutex;
+
+ /* ensure serialised access to bulk operations */
+ struct mutex bulk_mutex;
+
+ /* vmalloc page to receive scratch bulk xfers into */
+ void *bulk_scratch;
+
+ /* component to use next */
+ int component_idx;
+ struct vchiq_mmal_component component[VCHIQ_MMAL_MAX_COMPONENTS];
+};
+
+static struct mmal_msg_context *get_msg_context(struct vchiq_mmal_instance
+ *instance)
+{
+ struct mmal_msg_context *msg_context;
+
+ /* todo: should this be allocated from a pool to avoid kmalloc */
+ msg_context = kmalloc(sizeof(*msg_context), GFP_KERNEL);
+ memset(msg_context, 0, sizeof(*msg_context));
+
+ return msg_context;
+}
+
+static void release_msg_context(struct mmal_msg_context *msg_context)
+{
+ kfree(msg_context);
+}
+
+/* deals with receipt of event to host message */
+static void event_to_host_cb(struct vchiq_mmal_instance *instance,
+ struct mmal_msg *msg, u32 msg_len)
+{
+ pr_debug("unhandled event\n");
+ pr_debug("component:%p port type:%d num:%d cmd:0x%x length:%d\n",
+ msg->u.event_to_host.client_component,
+ msg->u.event_to_host.port_type,
+ msg->u.event_to_host.port_num,
+ msg->u.event_to_host.cmd, msg->u.event_to_host.length);
+}
+
+/* workqueue scheduled callback
+ *
+ * we do this because it is important we do not call any other vchiq
+ * sync calls from witin the message delivery thread
+ */
+static void buffer_work_cb(struct work_struct *work)
+{
+ struct mmal_msg_context *msg_context = (struct mmal_msg_context *)work;
+
+ msg_context->u.bulk.port->buffer_cb(msg_context->u.bulk.instance,
+ msg_context->u.bulk.port,
+ msg_context->u.bulk.status,
+ msg_context->u.bulk.buffer,
+ msg_context->u.bulk.buffer_used,
+ msg_context->u.bulk.mmal_flags,
+ msg_context->u.bulk.dts,
+ msg_context->u.bulk.pts);
+
+ /* release message context */
+ release_msg_context(msg_context);
+}
+
+/* enqueue a bulk receive for a given message context */
+static int bulk_receive(struct vchiq_mmal_instance *instance,
+ struct mmal_msg *msg,
+ struct mmal_msg_context *msg_context)
+{
+ unsigned long rd_len;
+ unsigned long flags = 0;
+ int ret;
+
+ /* bulk mutex stops other bulk operations while we have a
+ * receive in progress - released in callback
+ */
+ ret = mutex_lock_interruptible(&instance->bulk_mutex);
+ if (ret != 0)
+ return ret;
+
+ rd_len = msg->u.buffer_from_host.buffer_header.length;
+
+ /* take buffer from queue */
+ spin_lock_irqsave(&msg_context->u.bulk.port->slock, flags);
+ if (list_empty(&msg_context->u.bulk.port->buffers)) {
+ spin_unlock_irqrestore(&msg_context->u.bulk.port->slock, flags);
+ pr_err("buffer list empty trying to submit bulk receive\n");
+
+ /* todo: this is a serious error, we should never have
+ * committed a buffer_to_host operation to the mmal
+ * port without the buffer to back it up (underflow
+ * handling) and there is no obvious way to deal with
+ * this - how is the mmal servie going to react when
+ * we fail to do the xfer and reschedule a buffer when
+ * it arrives? perhaps a starved flag to indicate a
+ * waiting bulk receive?
+ */
+
+ mutex_unlock(&instance->bulk_mutex);
+
+ return -EINVAL;
+ }
+
+ msg_context->u.bulk.buffer =
+ list_entry(msg_context->u.bulk.port->buffers.next,
+ struct mmal_buffer, list);
+ list_del(&msg_context->u.bulk.buffer->list);
+
+ spin_unlock_irqrestore(&msg_context->u.bulk.port->slock, flags);
+
+ /* ensure we do not overrun the available buffer */
+ if (rd_len > msg_context->u.bulk.buffer->buffer_size) {
+ rd_len = msg_context->u.bulk.buffer->buffer_size;
+ pr_warn("short read as not enough receive buffer space\n");
+ /* todo: is this the correct response, what happens to
+ * the rest of the message data?
+ */
+ }
+
+ /* store length */
+ msg_context->u.bulk.buffer_used = rd_len;
+ msg_context->u.bulk.mmal_flags =
+ msg->u.buffer_from_host.buffer_header.flags;
+ msg_context->u.bulk.dts = msg->u.buffer_from_host.buffer_header.dts;
+ msg_context->u.bulk.pts = msg->u.buffer_from_host.buffer_header.pts;
+
+ // only need to flush L1 cache here, as VCHIQ takes care of the L2
+ // cache.
+ __cpuc_flush_dcache_area(msg_context->u.bulk.buffer->buffer, rd_len);
+
+ /* queue the bulk submission */
+ vchi_service_use(instance->handle);
+ ret = vchi_bulk_queue_receive(instance->handle,
+ msg_context->u.bulk.buffer->buffer,
+ /* Actual receive needs to be a multiple
+ * of 4 bytes
+ */
+ (rd_len + 3) & ~3,
+ VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE |
+ VCHI_FLAGS_BLOCK_UNTIL_QUEUED,
+ msg_context);
+
+ vchi_service_release(instance->handle);
+
+ if (ret != 0) {
+ /* callback will not be clearing the mutex */
+ mutex_unlock(&instance->bulk_mutex);
+ }
+
+ return ret;
+}
+
+/* enque a dummy bulk receive for a given message context */
+static int dummy_bulk_receive(struct vchiq_mmal_instance *instance,
+ struct mmal_msg_context *msg_context)
+{
+ int ret;
+
+ /* bulk mutex stops other bulk operations while we have a
+ * receive in progress - released in callback
+ */
+ ret = mutex_lock_interruptible(&instance->bulk_mutex);
+ if (ret != 0)
+ return ret;
+
+ /* zero length indicates this was a dummy transfer */
+ msg_context->u.bulk.buffer_used = 0;
+
+ /* queue the bulk submission */
+ vchi_service_use(instance->handle);
+
+ ret = vchi_bulk_queue_receive(instance->handle,
+ instance->bulk_scratch,
+ 8,
+ VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE |
+ VCHI_FLAGS_BLOCK_UNTIL_QUEUED,
+ msg_context);
+
+ vchi_service_release(instance->handle);
+
+ if (ret != 0) {
+ /* callback will not be clearing the mutex */
+ mutex_unlock(&instance->bulk_mutex);
+ }
+
+ return ret;
+}
+
+/* data in message, memcpy from packet into output buffer */
+static int inline_receive(struct vchiq_mmal_instance *instance,
+ struct mmal_msg *msg,
+ struct mmal_msg_context *msg_context)
+{
+ unsigned long flags = 0;
+
+ /* take buffer from queue */
+ spin_lock_irqsave(&msg_context->u.bulk.port->slock, flags);
+ if (list_empty(&msg_context->u.bulk.port->buffers)) {
+ spin_unlock_irqrestore(&msg_context->u.bulk.port->slock, flags);
+ pr_err("buffer list empty trying to receive inline\n");
+
+ /* todo: this is a serious error, we should never have
+ * committed a buffer_to_host operation to the mmal
+ * port without the buffer to back it up (with
+ * underflow handling) and there is no obvious way to
+ * deal with this. Less bad than the bulk case as we
+ * can just drop this on the floor but...unhelpful
+ */
+ return -EINVAL;
+ }
+
+ msg_context->u.bulk.buffer =
+ list_entry(msg_context->u.bulk.port->buffers.next,
+ struct mmal_buffer, list);
+ list_del(&msg_context->u.bulk.buffer->list);
+
+ spin_unlock_irqrestore(&msg_context->u.bulk.port->slock, flags);
+
+ memcpy(msg_context->u.bulk.buffer->buffer,
+ msg->u.buffer_from_host.short_data,
+ msg->u.buffer_from_host.payload_in_message);
+
+ msg_context->u.bulk.buffer_used =
+ msg->u.buffer_from_host.payload_in_message;
+
+ return 0;
+}
+
+/* queue the buffer availability with MMAL_MSG_TYPE_BUFFER_FROM_HOST */
+static int
+buffer_from_host(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_port *port, struct mmal_buffer *buf)
+{
+ struct mmal_msg_context *msg_context;
+ struct mmal_msg m;
+ int ret;
+
+ pr_debug("instance:%p buffer:%p\n", instance->handle, buf);
+
+ /* bulk mutex stops other bulk operations while we
+ * have a receive in progress
+ */
+ if (mutex_lock_interruptible(&instance->bulk_mutex))
+ return -EINTR;
+
+ /* get context */
+ msg_context = get_msg_context(instance);
+ if (msg_context == NULL)
+ return -ENOMEM;
+
+ /* store bulk message context for when data arrives */
+ msg_context->u.bulk.instance = instance;
+ msg_context->u.bulk.port = port;
+ msg_context->u.bulk.buffer = NULL; /* not valid until bulk xfer */
+ msg_context->u.bulk.buffer_used = 0;
+
+ /* initialise work structure ready to schedule callback */
+ INIT_WORK(&msg_context->u.bulk.work, buffer_work_cb);
+
+ /* prep the buffer from host message */
+ memset(&m, 0xbc, sizeof(m)); /* just to make debug clearer */
+
+ m.h.type = MMAL_MSG_TYPE_BUFFER_FROM_HOST;
+ m.h.magic = MMAL_MAGIC;
+ m.h.context = msg_context;
+ m.h.status = 0;
+
+ /* drvbuf is our private data passed back */
+ m.u.buffer_from_host.drvbuf.magic = MMAL_MAGIC;
+ m.u.buffer_from_host.drvbuf.component_handle = port->component->handle;
+ m.u.buffer_from_host.drvbuf.port_handle = port->handle;
+ m.u.buffer_from_host.drvbuf.client_context = msg_context;
+
+ /* buffer header */
+ m.u.buffer_from_host.buffer_header.cmd = 0;
+ m.u.buffer_from_host.buffer_header.data = buf->buffer;
+ m.u.buffer_from_host.buffer_header.alloc_size = buf->buffer_size;
+ m.u.buffer_from_host.buffer_header.length = 0; /* nothing used yet */
+ m.u.buffer_from_host.buffer_header.offset = 0; /* no offset */
+ m.u.buffer_from_host.buffer_header.flags = 0; /* no flags */
+ m.u.buffer_from_host.buffer_header.pts = MMAL_TIME_UNKNOWN;
+ m.u.buffer_from_host.buffer_header.dts = MMAL_TIME_UNKNOWN;
+
+ /* clear buffer type sepecific data */
+ memset(&m.u.buffer_from_host.buffer_header_type_specific, 0,
+ sizeof(m.u.buffer_from_host.buffer_header_type_specific));
+
+ /* no payload in message */
+ m.u.buffer_from_host.payload_in_message = 0;
+
+ vchi_service_use(instance->handle);
+
+ ret = vchi_queue_kernel_message(instance->handle,
+ &m,
+ sizeof(struct mmal_msg_header) +
+ sizeof(m.u.buffer_from_host));
+
+ if (ret != 0) {
+ release_msg_context(msg_context);
+ /* todo: is this correct error value? */
+ }
+
+ vchi_service_release(instance->handle);
+
+ mutex_unlock(&instance->bulk_mutex);
+
+ return ret;
+}
+
+/* submit a buffer to the mmal sevice
+ *
+ * the buffer_from_host uses size data from the ports next available
+ * mmal_buffer and deals with there being no buffer available by
+ * incrementing the underflow for later
+ */
+static int port_buffer_from_host(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_port *port)
+{
+ int ret;
+ struct mmal_buffer *buf;
+ unsigned long flags = 0;
+
+ if (!port->enabled)
+ return -EINVAL;
+
+ /* peek buffer from queue */
+ spin_lock_irqsave(&port->slock, flags);
+ if (list_empty(&port->buffers)) {
+ port->buffer_underflow++;
+ spin_unlock_irqrestore(&port->slock, flags);
+ return -ENOSPC;
+ }
+
+ buf = list_entry(port->buffers.next, struct mmal_buffer, list);
+
+ spin_unlock_irqrestore(&port->slock, flags);
+
+ /* issue buffer to mmal service */
+ ret = buffer_from_host(instance, port, buf);
+ if (ret) {
+ pr_err("adding buffer header failed\n");
+ /* todo: how should this be dealt with */
+ }
+
+ return ret;
+}
+
+/* deals with receipt of buffer to host message */
+static void buffer_to_host_cb(struct vchiq_mmal_instance *instance,
+ struct mmal_msg *msg, u32 msg_len)
+{
+ struct mmal_msg_context *msg_context;
+
+ pr_debug("buffer_to_host_cb: instance:%p msg:%p msg_len:%d\n",
+ instance, msg, msg_len);
+
+ if (msg->u.buffer_from_host.drvbuf.magic == MMAL_MAGIC) {
+ msg_context = msg->u.buffer_from_host.drvbuf.client_context;
+ } else {
+ pr_err("MMAL_MSG_TYPE_BUFFER_TO_HOST with bad magic\n");
+ return;
+ }
+
+ if (msg->h.status != MMAL_MSG_STATUS_SUCCESS) {
+ /* message reception had an error */
+ pr_warn("error %d in reply\n", msg->h.status);
+
+ msg_context->u.bulk.status = msg->h.status;
+
+ } else if (msg->u.buffer_from_host.buffer_header.length == 0) {
+ /* empty buffer */
+ if (msg->u.buffer_from_host.buffer_header.flags &
+ MMAL_BUFFER_HEADER_FLAG_EOS) {
+ msg_context->u.bulk.status =
+ dummy_bulk_receive(instance, msg_context);
+ if (msg_context->u.bulk.status == 0)
+ return; /* successful bulk submission, bulk
+ * completion will trigger callback
+ */
+ } else {
+ /* do callback with empty buffer - not EOS though */
+ msg_context->u.bulk.status = 0;
+ msg_context->u.bulk.buffer_used = 0;
+ }
+ } else if (msg->u.buffer_from_host.payload_in_message == 0) {
+ /* data is not in message, queue a bulk receive */
+ msg_context->u.bulk.status =
+ bulk_receive(instance, msg, msg_context);
+ if (msg_context->u.bulk.status == 0)
+ return; /* successful bulk submission, bulk
+ * completion will trigger callback
+ */
+
+ /* failed to submit buffer, this will end badly */
+ pr_err("error %d on bulk submission\n",
+ msg_context->u.bulk.status);
+
+ } else if (msg->u.buffer_from_host.payload_in_message <=
+ MMAL_VC_SHORT_DATA) {
+ /* data payload within message */
+ msg_context->u.bulk.status = inline_receive(instance, msg,
+ msg_context);
+ } else {
+ pr_err("message with invalid short payload\n");
+
+ /* signal error */
+ msg_context->u.bulk.status = -EINVAL;
+ msg_context->u.bulk.buffer_used =
+ msg->u.buffer_from_host.payload_in_message;
+ }
+
+ /* replace the buffer header */
+ port_buffer_from_host(instance, msg_context->u.bulk.port);
+
+ /* schedule the port callback */
+ schedule_work(&msg_context->u.bulk.work);
+}
+
+static void bulk_receive_cb(struct vchiq_mmal_instance *instance,
+ struct mmal_msg_context *msg_context)
+{
+ /* bulk receive operation complete */
+ mutex_unlock(&msg_context->u.bulk.instance->bulk_mutex);
+
+ /* replace the buffer header */
+ port_buffer_from_host(msg_context->u.bulk.instance,
+ msg_context->u.bulk.port);
+
+ msg_context->u.bulk.status = 0;
+
+ /* schedule the port callback */
+ schedule_work(&msg_context->u.bulk.work);
+}
+
+static void bulk_abort_cb(struct vchiq_mmal_instance *instance,
+ struct mmal_msg_context *msg_context)
+{
+ pr_err("%s: bulk ABORTED msg_context:%p\n", __func__, msg_context);
+
+ /* bulk receive operation complete */
+ mutex_unlock(&msg_context->u.bulk.instance->bulk_mutex);
+
+ /* replace the buffer header */
+ port_buffer_from_host(msg_context->u.bulk.instance,
+ msg_context->u.bulk.port);
+
+ msg_context->u.bulk.status = -EINTR;
+
+ schedule_work(&msg_context->u.bulk.work);
+}
+
+/* incoming event service callback */
+static void service_callback(void *param,
+ const VCHI_CALLBACK_REASON_T reason,
+ void *bulk_ctx)
+{
+ struct vchiq_mmal_instance *instance = param;
+ int status;
+ u32 msg_len;
+ struct mmal_msg *msg;
+ VCHI_HELD_MSG_T msg_handle;
+
+ if (!instance) {
+ pr_err("Message callback passed NULL instance\n");
+ return;
+ }
+
+ switch (reason) {
+ case VCHI_CALLBACK_MSG_AVAILABLE:
+ status = vchi_msg_hold(instance->handle, (void **)&msg,
+ &msg_len, VCHI_FLAGS_NONE, &msg_handle);
+ if (status) {
+ pr_err("Unable to dequeue a message (%d)\n", status);
+ break;
+ }
+
+ DBG_DUMP_MSG(msg, msg_len, "<<< reply message");
+
+ /* handling is different for buffer messages */
+ switch (msg->h.type) {
+ case MMAL_MSG_TYPE_BUFFER_FROM_HOST:
+ vchi_held_msg_release(&msg_handle);
+ break;
+
+ case MMAL_MSG_TYPE_EVENT_TO_HOST:
+ event_to_host_cb(instance, msg, msg_len);
+ vchi_held_msg_release(&msg_handle);
+
+ break;
+
+ case MMAL_MSG_TYPE_BUFFER_TO_HOST:
+ buffer_to_host_cb(instance, msg, msg_len);
+ vchi_held_msg_release(&msg_handle);
+ break;
+
+ default:
+ /* messages dependent on header context to complete */
+
+ /* todo: the msg.context really ought to be sanity
+ * checked before we just use it, afaict it comes back
+ * and is used raw from the videocore. Perhaps it
+ * should be verified the address lies in the kernel
+ * address space.
+ */
+ if (msg->h.context == NULL) {
+ pr_err("received message context was null!\n");
+ vchi_held_msg_release(&msg_handle);
+ break;
+ }
+
+ /* fill in context values */
+ msg->h.context->u.sync.msg_handle = msg_handle;
+ msg->h.context->u.sync.msg = msg;
+ msg->h.context->u.sync.msg_len = msg_len;
+
+ /* todo: should this check (completion_done()
+ * == 1) for no one waiting? or do we need a
+ * flag to tell us the completion has been
+ * interrupted so we can free the message and
+ * its context. This probably also solves the
+ * message arriving after interruption todo
+ * below
+ */
+
+ /* complete message so caller knows it happened */
+ complete(&msg->h.context->u.sync.cmplt);
+ break;
+ }
+
+ break;
+
+ case VCHI_CALLBACK_BULK_RECEIVED:
+ bulk_receive_cb(instance, bulk_ctx);
+ break;
+
+ case VCHI_CALLBACK_BULK_RECEIVE_ABORTED:
+ bulk_abort_cb(instance, bulk_ctx);
+ break;
+
+ case VCHI_CALLBACK_SERVICE_CLOSED:
+ /* TODO: consider if this requires action if received when
+ * driver is not explicitly closing the service
+ */
+ break;
+
+ default:
+ pr_err("Received unhandled message reason %d\n", reason);
+ break;
+ }
+}
+
+static int send_synchronous_mmal_msg(struct vchiq_mmal_instance *instance,
+ struct mmal_msg *msg,
+ unsigned int payload_len,
+ struct mmal_msg **msg_out,
+ VCHI_HELD_MSG_T *msg_handle_out)
+{
+ struct mmal_msg_context msg_context;
+ int ret;
+
+ /* payload size must not cause message to exceed max size */
+ if (payload_len >
+ (MMAL_MSG_MAX_SIZE - sizeof(struct mmal_msg_header))) {
+ pr_err("payload length %d exceeds max:%d\n", payload_len,
+ (MMAL_MSG_MAX_SIZE - sizeof(struct mmal_msg_header)));
+ return -EINVAL;
+ }
+
+ init_completion(&msg_context.u.sync.cmplt);
+
+ msg->h.magic = MMAL_MAGIC;
+ msg->h.context = &msg_context;
+ msg->h.status = 0;
+
+ DBG_DUMP_MSG(msg, (sizeof(struct mmal_msg_header) + payload_len),
+ ">>> sync message");
+
+ vchi_service_use(instance->handle);
+
+ ret = vchi_queue_kernel_message(instance->handle,
+ msg,
+ sizeof(struct mmal_msg_header) +
+ payload_len);
+
+ vchi_service_release(instance->handle);
+
+ if (ret) {
+ pr_err("error %d queuing message\n", ret);
+ return ret;
+ }
+
+ ret = wait_for_completion_timeout(&msg_context.u.sync.cmplt, 3 * HZ);
+ if (ret <= 0) {
+ pr_err("error %d waiting for sync completion\n", ret);
+ if (ret == 0)
+ ret = -ETIME;
+ /* todo: what happens if the message arrives after aborting */
+ return ret;
+ }
+
+ *msg_out = msg_context.u.sync.msg;
+ *msg_handle_out = msg_context.u.sync.msg_handle;
+
+ return 0;
+}
+
+static void dump_port_info(struct vchiq_mmal_port *port)
+{
+ pr_debug("port handle:0x%x enabled:%d\n", port->handle, port->enabled);
+
+ pr_debug("buffer minimum num:%d size:%d align:%d\n",
+ port->minimum_buffer.num,
+ port->minimum_buffer.size, port->minimum_buffer.alignment);
+
+ pr_debug("buffer recommended num:%d size:%d align:%d\n",
+ port->recommended_buffer.num,
+ port->recommended_buffer.size,
+ port->recommended_buffer.alignment);
+
+ pr_debug("buffer current values num:%d size:%d align:%d\n",
+ port->current_buffer.num,
+ port->current_buffer.size, port->current_buffer.alignment);
+
+ pr_debug("elementry stream: type:%d encoding:0x%x variant:0x%x\n",
+ port->format.type,
+ port->format.encoding, port->format.encoding_variant);
+
+ pr_debug(" bitrate:%d flags:0x%x\n",
+ port->format.bitrate, port->format.flags);
+
+ if (port->format.type == MMAL_ES_TYPE_VIDEO) {
+ pr_debug
+ ("es video format: width:%d height:%d colourspace:0x%x\n",
+ port->es.video.width, port->es.video.height,
+ port->es.video.color_space);
+
+ pr_debug(" : crop xywh %d,%d,%d,%d\n",
+ port->es.video.crop.x,
+ port->es.video.crop.y,
+ port->es.video.crop.width, port->es.video.crop.height);
+ pr_debug(" : framerate %d/%d aspect %d/%d\n",
+ port->es.video.frame_rate.num,
+ port->es.video.frame_rate.den,
+ port->es.video.par.num, port->es.video.par.den);
+ }
+}
+
+static void port_to_mmal_msg(struct vchiq_mmal_port *port, struct mmal_port *p)
+{
+ /* todo do readonly fields need setting at all? */
+ p->type = port->type;
+ p->index = port->index;
+ p->index_all = 0;
+ p->is_enabled = port->enabled;
+ p->buffer_num_min = port->minimum_buffer.num;
+ p->buffer_size_min = port->minimum_buffer.size;
+ p->buffer_alignment_min = port->minimum_buffer.alignment;
+ p->buffer_num_recommended = port->recommended_buffer.num;
+ p->buffer_size_recommended = port->recommended_buffer.size;
+
+ /* only three writable fields in a port */
+ p->buffer_num = port->current_buffer.num;
+ p->buffer_size = port->current_buffer.size;
+ p->userdata = port;
+}
+
+static int port_info_set(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_port *port)
+{
+ int ret;
+ struct mmal_msg m;
+ struct mmal_msg *rmsg;
+ VCHI_HELD_MSG_T rmsg_handle;
+
+ pr_debug("setting port info port %p\n", port);
+ if (!port)
+ return -1;
+ dump_port_info(port);
+
+ m.h.type = MMAL_MSG_TYPE_PORT_INFO_SET;
+
+ m.u.port_info_set.component_handle = port->component->handle;
+ m.u.port_info_set.port_type = port->type;
+ m.u.port_info_set.port_index = port->index;
+
+ port_to_mmal_msg(port, &m.u.port_info_set.port);
+
+ /* elementry stream format setup */
+ m.u.port_info_set.format.type = port->format.type;
+ m.u.port_info_set.format.encoding = port->format.encoding;
+ m.u.port_info_set.format.encoding_variant =
+ port->format.encoding_variant;
+ m.u.port_info_set.format.bitrate = port->format.bitrate;
+ m.u.port_info_set.format.flags = port->format.flags;
+
+ memcpy(&m.u.port_info_set.es, &port->es,
+ sizeof(union mmal_es_specific_format));
+
+ m.u.port_info_set.format.extradata_size = port->format.extradata_size;
+ memcpy(&m.u.port_info_set.extradata, port->format.extradata,
+ port->format.extradata_size);
+
+ ret = send_synchronous_mmal_msg(instance, &m,
+ sizeof(m.u.port_info_set),
+ &rmsg, &rmsg_handle);
+ if (ret)
+ return ret;
+
+ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_INFO_SET) {
+ /* got an unexpected message type in reply */
+ ret = -EINVAL;
+ goto release_msg;
+ }
+
+ /* return operation status */
+ ret = -rmsg->u.port_info_get_reply.status;
+
+ pr_debug("%s:result:%d component:0x%x port:%d\n", __func__, ret,
+ port->component->handle, port->handle);
+
+release_msg:
+ vchi_held_msg_release(&rmsg_handle);
+
+ return ret;
+}
+
+/* use port info get message to retrieve port information */
+static int port_info_get(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_port *port)
+{
+ int ret;
+ struct mmal_msg m;
+ struct mmal_msg *rmsg;
+ VCHI_HELD_MSG_T rmsg_handle;
+
+ /* port info time */
+ m.h.type = MMAL_MSG_TYPE_PORT_INFO_GET;
+ m.u.port_info_get.component_handle = port->component->handle;
+ m.u.port_info_get.port_type = port->type;
+ m.u.port_info_get.index = port->index;
+
+ ret = send_synchronous_mmal_msg(instance, &m,
+ sizeof(m.u.port_info_get),
+ &rmsg, &rmsg_handle);
+ if (ret)
+ return ret;
+
+ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_INFO_GET) {
+ /* got an unexpected message type in reply */
+ ret = -EINVAL;
+ goto release_msg;
+ }
+
+ /* return operation status */
+ ret = -rmsg->u.port_info_get_reply.status;
+ if (ret != MMAL_MSG_STATUS_SUCCESS)
+ goto release_msg;
+
+ if (rmsg->u.port_info_get_reply.port.is_enabled == 0)
+ port->enabled = false;
+ else
+ port->enabled = true;
+
+ /* copy the values out of the message */
+ port->handle = rmsg->u.port_info_get_reply.port_handle;
+
+ /* port type and index cached to use on port info set because
+ * it does not use a port handle
+ */
+ port->type = rmsg->u.port_info_get_reply.port_type;
+ port->index = rmsg->u.port_info_get_reply.port_index;
+
+ port->minimum_buffer.num =
+ rmsg->u.port_info_get_reply.port.buffer_num_min;
+ port->minimum_buffer.size =
+ rmsg->u.port_info_get_reply.port.buffer_size_min;
+ port->minimum_buffer.alignment =
+ rmsg->u.port_info_get_reply.port.buffer_alignment_min;
+
+ port->recommended_buffer.alignment =
+ rmsg->u.port_info_get_reply.port.buffer_alignment_min;
+ port->recommended_buffer.num =
+ rmsg->u.port_info_get_reply.port.buffer_num_recommended;
+
+ port->current_buffer.num = rmsg->u.port_info_get_reply.port.buffer_num;
+ port->current_buffer.size =
+ rmsg->u.port_info_get_reply.port.buffer_size;
+
+ /* stream format */
+ port->format.type = rmsg->u.port_info_get_reply.format.type;
+ port->format.encoding = rmsg->u.port_info_get_reply.format.encoding;
+ port->format.encoding_variant =
+ rmsg->u.port_info_get_reply.format.encoding_variant;
+ port->format.bitrate = rmsg->u.port_info_get_reply.format.bitrate;
+ port->format.flags = rmsg->u.port_info_get_reply.format.flags;
+
+ /* elementry stream format */
+ memcpy(&port->es,
+ &rmsg->u.port_info_get_reply.es,
+ sizeof(union mmal_es_specific_format));
+ port->format.es = &port->es;
+
+ port->format.extradata_size =
+ rmsg->u.port_info_get_reply.format.extradata_size;
+ memcpy(port->format.extradata,
+ rmsg->u.port_info_get_reply.extradata,
+ port->format.extradata_size);
+
+ pr_debug("received port info\n");
+ dump_port_info(port);
+
+release_msg:
+
+ pr_debug("%s:result:%d component:0x%x port:%d\n",
+ __func__, ret, port->component->handle, port->handle);
+
+ vchi_held_msg_release(&rmsg_handle);
+
+ return ret;
+}
+
+/* create comonent on vc */
+static int create_component(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_component *component,
+ const char *name)
+{
+ int ret;
+ struct mmal_msg m;
+ struct mmal_msg *rmsg;
+ VCHI_HELD_MSG_T rmsg_handle;
+
+ /* build component create message */
+ m.h.type = MMAL_MSG_TYPE_COMPONENT_CREATE;
+ m.u.component_create.client_component = component;
+ strncpy(m.u.component_create.name, name,
+ sizeof(m.u.component_create.name));
+
+ ret = send_synchronous_mmal_msg(instance, &m,
+ sizeof(m.u.component_create),
+ &rmsg, &rmsg_handle);
+ if (ret)
+ return ret;
+
+ if (rmsg->h.type != m.h.type) {
+ /* got an unexpected message type in reply */
+ ret = -EINVAL;
+ goto release_msg;
+ }
+
+ ret = -rmsg->u.component_create_reply.status;
+ if (ret != MMAL_MSG_STATUS_SUCCESS)
+ goto release_msg;
+
+ /* a valid component response received */
+ component->handle = rmsg->u.component_create_reply.component_handle;
+ component->inputs = rmsg->u.component_create_reply.input_num;
+ component->outputs = rmsg->u.component_create_reply.output_num;
+ component->clocks = rmsg->u.component_create_reply.clock_num;
+
+ pr_debug("Component handle:0x%x in:%d out:%d clock:%d\n",
+ component->handle,
+ component->inputs, component->outputs, component->clocks);
+
+release_msg:
+ vchi_held_msg_release(&rmsg_handle);
+
+ return ret;
+}
+
+/* destroys a component on vc */
+static int destroy_component(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_component *component)
+{
+ int ret;
+ struct mmal_msg m;
+ struct mmal_msg *rmsg;
+ VCHI_HELD_MSG_T rmsg_handle;
+
+ m.h.type = MMAL_MSG_TYPE_COMPONENT_DESTROY;
+ m.u.component_destroy.component_handle = component->handle;
+
+ ret = send_synchronous_mmal_msg(instance, &m,
+ sizeof(m.u.component_destroy),
+ &rmsg, &rmsg_handle);
+ if (ret)
+ return ret;
+
+ if (rmsg->h.type != m.h.type) {
+ /* got an unexpected message type in reply */
+ ret = -EINVAL;
+ goto release_msg;
+ }
+
+ ret = -rmsg->u.component_destroy_reply.status;
+
+release_msg:
+
+ vchi_held_msg_release(&rmsg_handle);
+
+ return ret;
+}
+
+/* enable a component on vc */
+static int enable_component(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_component *component)
+{
+ int ret;
+ struct mmal_msg m;
+ struct mmal_msg *rmsg;
+ VCHI_HELD_MSG_T rmsg_handle;
+
+ m.h.type = MMAL_MSG_TYPE_COMPONENT_ENABLE;
+ m.u.component_enable.component_handle = component->handle;
+
+ ret = send_synchronous_mmal_msg(instance, &m,
+ sizeof(m.u.component_enable),
+ &rmsg, &rmsg_handle);
+ if (ret)
+ return ret;
+
+ if (rmsg->h.type != m.h.type) {
+ /* got an unexpected message type in reply */
+ ret = -EINVAL;
+ goto release_msg;
+ }
+
+ ret = -rmsg->u.component_enable_reply.status;
+
+release_msg:
+ vchi_held_msg_release(&rmsg_handle);
+
+ return ret;
+}
+
+/* disable a component on vc */
+static int disable_component(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_component *component)
+{
+ int ret;
+ struct mmal_msg m;
+ struct mmal_msg *rmsg;
+ VCHI_HELD_MSG_T rmsg_handle;
+
+ m.h.type = MMAL_MSG_TYPE_COMPONENT_DISABLE;
+ m.u.component_disable.component_handle = component->handle;
+
+ ret = send_synchronous_mmal_msg(instance, &m,
+ sizeof(m.u.component_disable),
+ &rmsg, &rmsg_handle);
+ if (ret)
+ return ret;
+
+ if (rmsg->h.type != m.h.type) {
+ /* got an unexpected message type in reply */
+ ret = -EINVAL;
+ goto release_msg;
+ }
+
+ ret = -rmsg->u.component_disable_reply.status;
+
+release_msg:
+
+ vchi_held_msg_release(&rmsg_handle);
+
+ return ret;
+}
+
+/* get version of mmal implementation */
+static int get_version(struct vchiq_mmal_instance *instance,
+ u32 *major_out, u32 *minor_out)
+{
+ int ret;
+ struct mmal_msg m;
+ struct mmal_msg *rmsg;
+ VCHI_HELD_MSG_T rmsg_handle;
+
+ m.h.type = MMAL_MSG_TYPE_GET_VERSION;
+
+ ret = send_synchronous_mmal_msg(instance, &m,
+ sizeof(m.u.version),
+ &rmsg, &rmsg_handle);
+ if (ret)
+ return ret;
+
+ if (rmsg->h.type != m.h.type) {
+ /* got an unexpected message type in reply */
+ ret = -EINVAL;
+ goto release_msg;
+ }
+
+ *major_out = rmsg->u.version.major;
+ *minor_out = rmsg->u.version.minor;
+
+release_msg:
+ vchi_held_msg_release(&rmsg_handle);
+
+ return ret;
+}
+
+/* do a port action with a port as a parameter */
+static int port_action_port(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_port *port,
+ enum mmal_msg_port_action_type action_type)
+{
+ int ret;
+ struct mmal_msg m;
+ struct mmal_msg *rmsg;
+ VCHI_HELD_MSG_T rmsg_handle;
+
+ m.h.type = MMAL_MSG_TYPE_PORT_ACTION;
+ m.u.port_action_port.component_handle = port->component->handle;
+ m.u.port_action_port.port_handle = port->handle;
+ m.u.port_action_port.action = action_type;
+
+ port_to_mmal_msg(port, &m.u.port_action_port.port);
+
+ ret = send_synchronous_mmal_msg(instance, &m,
+ sizeof(m.u.port_action_port),
+ &rmsg, &rmsg_handle);
+ if (ret)
+ return ret;
+
+ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_ACTION) {
+ /* got an unexpected message type in reply */
+ ret = -EINVAL;
+ goto release_msg;
+ }
+
+ ret = -rmsg->u.port_action_reply.status;
+
+ pr_debug("%s:result:%d component:0x%x port:%d action:%s(%d)\n",
+ __func__,
+ ret, port->component->handle, port->handle,
+ port_action_type_names[action_type], action_type);
+
+release_msg:
+ vchi_held_msg_release(&rmsg_handle);
+
+ return ret;
+}
+
+/* do a port action with handles as parameters */
+static int port_action_handle(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_port *port,
+ enum mmal_msg_port_action_type action_type,
+ u32 connect_component_handle,
+ u32 connect_port_handle)
+{
+ int ret;
+ struct mmal_msg m;
+ struct mmal_msg *rmsg;
+ VCHI_HELD_MSG_T rmsg_handle;
+
+ m.h.type = MMAL_MSG_TYPE_PORT_ACTION;
+
+ m.u.port_action_handle.component_handle = port->component->handle;
+ m.u.port_action_handle.port_handle = port->handle;
+ m.u.port_action_handle.action = action_type;
+
+ m.u.port_action_handle.connect_component_handle =
+ connect_component_handle;
+ m.u.port_action_handle.connect_port_handle = connect_port_handle;
+
+ ret = send_synchronous_mmal_msg(instance, &m,
+ sizeof(m.u.port_action_handle),
+ &rmsg, &rmsg_handle);
+ if (ret)
+ return ret;
+
+ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_ACTION) {
+ /* got an unexpected message type in reply */
+ ret = -EINVAL;
+ goto release_msg;
+ }
+
+ ret = -rmsg->u.port_action_reply.status;
+
+ pr_debug("%s:result:%d component:0x%x port:%d action:%s(%d)" \
+ " connect component:0x%x connect port:%d\n",
+ __func__,
+ ret, port->component->handle, port->handle,
+ port_action_type_names[action_type],
+ action_type, connect_component_handle, connect_port_handle);
+
+release_msg:
+ vchi_held_msg_release(&rmsg_handle);
+
+ return ret;
+}
+
+static int port_parameter_set(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_port *port,
+ u32 parameter_id, void *value, u32 value_size)
+{
+ int ret;
+ struct mmal_msg m;
+ struct mmal_msg *rmsg;
+ VCHI_HELD_MSG_T rmsg_handle;
+
+ m.h.type = MMAL_MSG_TYPE_PORT_PARAMETER_SET;
+
+ m.u.port_parameter_set.component_handle = port->component->handle;
+ m.u.port_parameter_set.port_handle = port->handle;
+ m.u.port_parameter_set.id = parameter_id;
+ m.u.port_parameter_set.size = (2 * sizeof(u32)) + value_size;
+ memcpy(&m.u.port_parameter_set.value, value, value_size);
+
+ ret = send_synchronous_mmal_msg(instance, &m,
+ (4 * sizeof(u32)) + value_size,
+ &rmsg, &rmsg_handle);
+ if (ret)
+ return ret;
+
+ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_PARAMETER_SET) {
+ /* got an unexpected message type in reply */
+ ret = -EINVAL;
+ goto release_msg;
+ }
+
+ ret = -rmsg->u.port_parameter_set_reply.status;
+
+ pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n",
+ __func__,
+ ret, port->component->handle, port->handle, parameter_id);
+
+release_msg:
+ vchi_held_msg_release(&rmsg_handle);
+
+ return ret;
+}
+
+static int port_parameter_get(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_port *port,
+ u32 parameter_id, void *value, u32 *value_size)
+{
+ int ret;
+ struct mmal_msg m;
+ struct mmal_msg *rmsg;
+ VCHI_HELD_MSG_T rmsg_handle;
+
+ m.h.type = MMAL_MSG_TYPE_PORT_PARAMETER_GET;
+
+ m.u.port_parameter_get.component_handle = port->component->handle;
+ m.u.port_parameter_get.port_handle = port->handle;
+ m.u.port_parameter_get.id = parameter_id;
+ m.u.port_parameter_get.size = (2 * sizeof(u32)) + *value_size;
+
+ ret = send_synchronous_mmal_msg(instance, &m,
+ sizeof(struct
+ mmal_msg_port_parameter_get),
+ &rmsg, &rmsg_handle);
+ if (ret)
+ return ret;
+
+ if (rmsg->h.type != MMAL_MSG_TYPE_PORT_PARAMETER_GET) {
+ /* got an unexpected message type in reply */
+ pr_err("Incorrect reply type %d\n", rmsg->h.type);
+ ret = -EINVAL;
+ goto release_msg;
+ }
+
+ ret = -rmsg->u.port_parameter_get_reply.status;
+ if (ret) {
+ /* Copy only as much as we have space for
+ * but report true size of parameter
+ */
+ memcpy(value, &rmsg->u.port_parameter_get_reply.value,
+ *value_size);
+ *value_size = rmsg->u.port_parameter_get_reply.size;
+ } else
+ memcpy(value, &rmsg->u.port_parameter_get_reply.value,
+ rmsg->u.port_parameter_get_reply.size);
+
+ pr_debug("%s:result:%d component:0x%x port:%d parameter:%d\n", __func__,
+ ret, port->component->handle, port->handle, parameter_id);
+
+release_msg:
+ vchi_held_msg_release(&rmsg_handle);
+
+ return ret;
+}
+
+/* disables a port and drains buffers from it */
+static int port_disable(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_port *port)
+{
+ int ret;
+ struct list_head *q, *buf_head;
+ unsigned long flags = 0;
+
+ if (!port->enabled)
+ return 0;
+
+ port->enabled = false;
+
+ ret = port_action_port(instance, port,
+ MMAL_MSG_PORT_ACTION_TYPE_DISABLE);
+ if (ret == 0) {
+ /* drain all queued buffers on port */
+ spin_lock_irqsave(&port->slock, flags);
+
+ list_for_each_safe(buf_head, q, &port->buffers) {
+ struct mmal_buffer *mmalbuf;
+
+ mmalbuf = list_entry(buf_head, struct mmal_buffer,
+ list);
+ list_del(buf_head);
+ if (port->buffer_cb)
+ port->buffer_cb(instance,
+ port, 0, mmalbuf, 0, 0,
+ MMAL_TIME_UNKNOWN,
+ MMAL_TIME_UNKNOWN);
+ }
+
+ spin_unlock_irqrestore(&port->slock, flags);
+
+ ret = port_info_get(instance, port);
+ }
+
+ return ret;
+}
+
+/* enable a port */
+static int port_enable(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_port *port)
+{
+ unsigned int hdr_count;
+ struct list_head *buf_head;
+ int ret;
+
+ if (port->enabled)
+ return 0;
+
+ /* ensure there are enough buffers queued to cover the buffer headers */
+ if (port->buffer_cb != NULL) {
+ hdr_count = 0;
+ list_for_each(buf_head, &port->buffers) {
+ hdr_count++;
+ }
+ if (hdr_count < port->current_buffer.num)
+ return -ENOSPC;
+ }
+
+ ret = port_action_port(instance, port,
+ MMAL_MSG_PORT_ACTION_TYPE_ENABLE);
+ if (ret)
+ goto done;
+
+ port->enabled = true;
+
+ if (port->buffer_cb) {
+ /* send buffer headers to videocore */
+ hdr_count = 1;
+ list_for_each(buf_head, &port->buffers) {
+ struct mmal_buffer *mmalbuf;
+
+ mmalbuf = list_entry(buf_head, struct mmal_buffer,
+ list);
+ ret = buffer_from_host(instance, port, mmalbuf);
+ if (ret)
+ goto done;
+
+ hdr_count++;
+ if (hdr_count > port->current_buffer.num)
+ break;
+ }
+ }
+
+ ret = port_info_get(instance, port);
+
+done:
+ return ret;
+}
+
+/* ------------------------------------------------------------------
+ * Exported API
+ *------------------------------------------------------------------*/
+
+int vchiq_mmal_port_set_format(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_port *port)
+{
+ int ret;
+
+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
+ return -EINTR;
+
+ ret = port_info_set(instance, port);
+ if (ret)
+ goto release_unlock;
+
+ /* read what has actually been set */
+ ret = port_info_get(instance, port);
+
+release_unlock:
+ mutex_unlock(&instance->vchiq_mutex);
+
+ return ret;
+}
+
+int vchiq_mmal_port_parameter_set(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_port *port,
+ u32 parameter, void *value, u32 value_size)
+{
+ int ret;
+
+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
+ return -EINTR;
+
+ ret = port_parameter_set(instance, port, parameter, value, value_size);
+
+ mutex_unlock(&instance->vchiq_mutex);
+
+ return ret;
+}
+
+int vchiq_mmal_port_parameter_get(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_port *port,
+ u32 parameter, void *value, u32 *value_size)
+{
+ int ret;
+
+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
+ return -EINTR;
+
+ ret = port_parameter_get(instance, port, parameter, value, value_size);
+
+ mutex_unlock(&instance->vchiq_mutex);
+
+ return ret;
+}
+
+/* enable a port
+ *
+ * enables a port and queues buffers for satisfying callbacks if we
+ * provide a callback handler
+ */
+int vchiq_mmal_port_enable(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_port *port,
+ vchiq_mmal_buffer_cb buffer_cb)
+{
+ int ret;
+
+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
+ return -EINTR;
+
+ /* already enabled - noop */
+ if (port->enabled) {
+ ret = 0;
+ goto unlock;
+ }
+
+ port->buffer_cb = buffer_cb;
+
+ ret = port_enable(instance, port);
+
+unlock:
+ mutex_unlock(&instance->vchiq_mutex);
+
+ return ret;
+}
+
+int vchiq_mmal_port_disable(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_port *port)
+{
+ int ret;
+
+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
+ return -EINTR;
+
+ if (!port->enabled) {
+ mutex_unlock(&instance->vchiq_mutex);
+ return 0;
+ }
+
+ ret = port_disable(instance, port);
+
+ mutex_unlock(&instance->vchiq_mutex);
+
+ return ret;
+}
+
+/* ports will be connected in a tunneled manner so data buffers
+ * are not handled by client.
+ */
+int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_port *src,
+ struct vchiq_mmal_port *dst)
+{
+ int ret;
+
+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
+ return -EINTR;
+
+ /* disconnect ports if connected */
+ if (src->connected != NULL) {
+ ret = port_disable(instance, src);
+ if (ret) {
+ pr_err("failed disabling src port(%d)\n", ret);
+ goto release_unlock;
+ }
+
+ /* do not need to disable the destination port as they
+ * are connected and it is done automatically
+ */
+
+ ret = port_action_handle(instance, src,
+ MMAL_MSG_PORT_ACTION_TYPE_DISCONNECT,
+ src->connected->component->handle,
+ src->connected->handle);
+ if (ret < 0) {
+ pr_err("failed disconnecting src port\n");
+ goto release_unlock;
+ }
+ src->connected->enabled = false;
+ src->connected = NULL;
+ }
+
+ if (dst == NULL) {
+ /* do not make new connection */
+ ret = 0;
+ pr_debug("not making new connection\n");
+ goto release_unlock;
+ }
+
+ /* copy src port format to dst */
+ dst->format.encoding = src->format.encoding;
+ dst->es.video.width = src->es.video.width;
+ dst->es.video.height = src->es.video.height;
+ dst->es.video.crop.x = src->es.video.crop.x;
+ dst->es.video.crop.y = src->es.video.crop.y;
+ dst->es.video.crop.width = src->es.video.crop.width;
+ dst->es.video.crop.height = src->es.video.crop.height;
+ dst->es.video.frame_rate.num = src->es.video.frame_rate.num;
+ dst->es.video.frame_rate.den = src->es.video.frame_rate.den;
+
+ /* set new format */
+ ret = port_info_set(instance, dst);
+ if (ret) {
+ pr_debug("setting port info failed\n");
+ goto release_unlock;
+ }
+
+ /* read what has actually been set */
+ ret = port_info_get(instance, dst);
+ if (ret) {
+ pr_debug("read back port info failed\n");
+ goto release_unlock;
+ }
+
+ /* connect two ports together */
+ ret = port_action_handle(instance, src,
+ MMAL_MSG_PORT_ACTION_TYPE_CONNECT,
+ dst->component->handle, dst->handle);
+ if (ret < 0) {
+ pr_debug("connecting port %d:%d to %d:%d failed\n",
+ src->component->handle, src->handle,
+ dst->component->handle, dst->handle);
+ goto release_unlock;
+ }
+ src->connected = dst;
+
+release_unlock:
+
+ mutex_unlock(&instance->vchiq_mutex);
+
+ return ret;
+}
+
+int vchiq_mmal_submit_buffer(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_port *port,
+ struct mmal_buffer *buffer)
+{
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&port->slock, flags);
+ list_add_tail(&buffer->list, &port->buffers);
+ spin_unlock_irqrestore(&port->slock, flags);
+
+ /* the port previously underflowed because it was missing a
+ * mmal_buffer which has just been added, submit that buffer
+ * to the mmal service.
+ */
+ if (port->buffer_underflow) {
+ port_buffer_from_host(instance, port);
+ port->buffer_underflow--;
+ }
+
+ return 0;
+}
+
+/* Initialise a mmal component and its ports
+ *
+ */
+int vchiq_mmal_component_init(struct vchiq_mmal_instance *instance,
+ const char *name,
+ struct vchiq_mmal_component **component_out)
+{
+ int ret;
+ int idx; /* port index */
+ struct vchiq_mmal_component *component;
+
+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
+ return -EINTR;
+
+ if (instance->component_idx == VCHIQ_MMAL_MAX_COMPONENTS) {
+ ret = -EINVAL; /* todo is this correct error? */
+ goto unlock;
+ }
+
+ component = &instance->component[instance->component_idx];
+
+ ret = create_component(instance, component, name);
+ if (ret < 0)
+ goto unlock;
+
+ /* ports info needs gathering */
+ component->control.type = MMAL_PORT_TYPE_CONTROL;
+ component->control.index = 0;
+ component->control.component = component;
+ spin_lock_init(&component->control.slock);
+ INIT_LIST_HEAD(&component->control.buffers);
+ ret = port_info_get(instance, &component->control);
+ if (ret < 0)
+ goto release_component;
+
+ for (idx = 0; idx < component->inputs; idx++) {
+ component->input[idx].type = MMAL_PORT_TYPE_INPUT;
+ component->input[idx].index = idx;
+ component->input[idx].component = component;
+ spin_lock_init(&component->input[idx].slock);
+ INIT_LIST_HEAD(&component->input[idx].buffers);
+ ret = port_info_get(instance, &component->input[idx]);
+ if (ret < 0)
+ goto release_component;
+ }
+
+ for (idx = 0; idx < component->outputs; idx++) {
+ component->output[idx].type = MMAL_PORT_TYPE_OUTPUT;
+ component->output[idx].index = idx;
+ component->output[idx].component = component;
+ spin_lock_init(&component->output[idx].slock);
+ INIT_LIST_HEAD(&component->output[idx].buffers);
+ ret = port_info_get(instance, &component->output[idx]);
+ if (ret < 0)
+ goto release_component;
+ }
+
+ for (idx = 0; idx < component->clocks; idx++) {
+ component->clock[idx].type = MMAL_PORT_TYPE_CLOCK;
+ component->clock[idx].index = idx;
+ component->clock[idx].component = component;
+ spin_lock_init(&component->clock[idx].slock);
+ INIT_LIST_HEAD(&component->clock[idx].buffers);
+ ret = port_info_get(instance, &component->clock[idx]);
+ if (ret < 0)
+ goto release_component;
+ }
+
+ instance->component_idx++;
+
+ *component_out = component;
+
+ mutex_unlock(&instance->vchiq_mutex);
+
+ return 0;
+
+release_component:
+ destroy_component(instance, component);
+unlock:
+ mutex_unlock(&instance->vchiq_mutex);
+
+ return ret;
+}
+
+/*
+ * cause a mmal component to be destroyed
+ */
+int vchiq_mmal_component_finalise(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_component *component)
+{
+ int ret;
+
+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
+ return -EINTR;
+
+ if (component->enabled)
+ ret = disable_component(instance, component);
+
+ ret = destroy_component(instance, component);
+
+ mutex_unlock(&instance->vchiq_mutex);
+
+ return ret;
+}
+
+/*
+ * cause a mmal component to be enabled
+ */
+int vchiq_mmal_component_enable(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_component *component)
+{
+ int ret;
+
+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
+ return -EINTR;
+
+ if (component->enabled) {
+ mutex_unlock(&instance->vchiq_mutex);
+ return 0;
+ }
+
+ ret = enable_component(instance, component);
+ if (ret == 0)
+ component->enabled = true;
+
+ mutex_unlock(&instance->vchiq_mutex);
+
+ return ret;
+}
+
+/*
+ * cause a mmal component to be enabled
+ */
+int vchiq_mmal_component_disable(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_component *component)
+{
+ int ret;
+
+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
+ return -EINTR;
+
+ if (!component->enabled) {
+ mutex_unlock(&instance->vchiq_mutex);
+ return 0;
+ }
+
+ ret = disable_component(instance, component);
+ if (ret == 0)
+ component->enabled = false;
+
+ mutex_unlock(&instance->vchiq_mutex);
+
+ return ret;
+}
+
+int vchiq_mmal_version(struct vchiq_mmal_instance *instance,
+ u32 *major_out, u32 *minor_out)
+{
+ int ret;
+
+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
+ return -EINTR;
+
+ ret = get_version(instance, major_out, minor_out);
+
+ mutex_unlock(&instance->vchiq_mutex);
+
+ return ret;
+}
+
+int vchiq_mmal_finalise(struct vchiq_mmal_instance *instance)
+{
+ int status = 0;
+
+ if (instance == NULL)
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&instance->vchiq_mutex))
+ return -EINTR;
+
+ vchi_service_use(instance->handle);
+
+ status = vchi_service_close(instance->handle);
+ if (status != 0)
+ pr_err("mmal-vchiq: VCHIQ close failed");
+
+ mutex_unlock(&instance->vchiq_mutex);
+
+ vfree(instance->bulk_scratch);
+
+ kfree(instance);
+
+ return status;
+}
+
+int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance)
+{
+ int status;
+ struct vchiq_mmal_instance *instance;
+ static VCHI_CONNECTION_T *vchi_connection;
+ static VCHI_INSTANCE_T vchi_instance;
+ SERVICE_CREATION_T params = {
+ VCHI_VERSION_EX(VC_MMAL_VER, VC_MMAL_MIN_VER),
+ VC_MMAL_SERVER_NAME,
+ vchi_connection,
+ 0, /* rx fifo size (unused) */
+ 0, /* tx fifo size (unused) */
+ service_callback,
+ NULL, /* service callback parameter */
+ 1, /* unaligned bulk receives */
+ 1, /* unaligned bulk transmits */
+ 0 /* want crc check on bulk transfers */
+ };
+
+ /* compile time checks to ensure structure size as they are
+ * directly (de)serialised from memory.
+ */
+
+ /* ensure the header structure has packed to the correct size */
+ BUILD_BUG_ON(sizeof(struct mmal_msg_header) != 24);
+
+ /* ensure message structure does not exceed maximum length */
+ BUILD_BUG_ON(sizeof(struct mmal_msg) > MMAL_MSG_MAX_SIZE);
+
+ /* mmal port struct is correct size */
+ BUILD_BUG_ON(sizeof(struct mmal_port) != 64);
+
+ /* create a vchi instance */
+ status = vchi_initialise(&vchi_instance);
+ if (status) {
+ pr_err("Failed to initialise VCHI instance (status=%d)\n",
+ status);
+ return -EIO;
+ }
+
+ status = vchi_connect(NULL, 0, vchi_instance);
+ if (status) {
+ pr_err("Failed to connect VCHI instance (status=%d)\n", status);
+ return -EIO;
+ }
+
+ instance = kmalloc(sizeof(*instance), GFP_KERNEL);
+ memset(instance, 0, sizeof(*instance));
+
+ mutex_init(&instance->vchiq_mutex);
+ mutex_init(&instance->bulk_mutex);
+
+ instance->bulk_scratch = vmalloc(PAGE_SIZE);
+
+ params.callback_param = instance;
+
+ status = vchi_service_open(vchi_instance, ¶ms, &instance->handle);
+ if (status) {
+ pr_err("Failed to open VCHI service connection (status=%d)\n",
+ status);
+ goto err_close_services;
+ }
+
+ vchi_service_release(instance->handle);
+
+ *out_instance = instance;
+
+ return 0;
+
+err_close_services:
+
+ vchi_service_close(instance->handle);
+ vfree(instance->bulk_scratch);
+ kfree(instance);
+ return -ENODEV;
+}
--- /dev/null
+/*
+ * Broadcom BM2835 V4L2 driver
+ *
+ * Copyright © 2013 Raspberry Pi (Trading) Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ * Authors: Vincent Sanders <vincent.sanders@collabora.co.uk>
+ * Dave Stevenson <dsteve@broadcom.com>
+ * Simon Mellor <simellor@broadcom.com>
+ * Luke Diamand <luked@broadcom.com>
+ *
+ * MMAL interface to VCHIQ message passing
+ */
+
+#ifndef MMAL_VCHIQ_H
+#define MMAL_VCHIQ_H
+
+#include "mmal-msg-format.h"
+
+#define MAX_PORT_COUNT 4
+
+/* Maximum size of the format extradata. */
+#define MMAL_FORMAT_EXTRADATA_MAX_SIZE 128
+
+struct vchiq_mmal_instance;
+
+enum vchiq_mmal_es_type {
+ MMAL_ES_TYPE_UNKNOWN, /**< Unknown elementary stream type */
+ MMAL_ES_TYPE_CONTROL, /**< Elementary stream of control commands */
+ MMAL_ES_TYPE_AUDIO, /**< Audio elementary stream */
+ MMAL_ES_TYPE_VIDEO, /**< Video elementary stream */
+ MMAL_ES_TYPE_SUBPICTURE /**< Sub-picture elementary stream */
+};
+
+/* rectangle, used lots so it gets its own struct */
+struct vchiq_mmal_rect {
+ s32 x;
+ s32 y;
+ s32 width;
+ s32 height;
+};
+
+struct vchiq_mmal_port_buffer {
+ unsigned int num; /* number of buffers */
+ u32 size; /* size of buffers */
+ u32 alignment; /* alignment of buffers */
+};
+
+struct vchiq_mmal_port;
+
+typedef void (*vchiq_mmal_buffer_cb)(
+ struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_port *port,
+ int status, struct mmal_buffer *buffer,
+ unsigned long length, u32 mmal_flags, s64 dts, s64 pts);
+
+struct vchiq_mmal_port {
+ bool enabled;
+ u32 handle;
+ u32 type; /* port type, cached to use on port info set */
+ u32 index; /* port index, cached to use on port info set */
+
+ /* component port belongs to, allows simple deref */
+ struct vchiq_mmal_component *component;
+
+ struct vchiq_mmal_port *connected; /* port conencted to */
+
+ /* buffer info */
+ struct vchiq_mmal_port_buffer minimum_buffer;
+ struct vchiq_mmal_port_buffer recommended_buffer;
+ struct vchiq_mmal_port_buffer current_buffer;
+
+ /* stream format */
+ struct mmal_es_format format;
+ /* elementry stream format */
+ union mmal_es_specific_format es;
+
+ /* data buffers to fill */
+ struct list_head buffers;
+ /* lock to serialise adding and removing buffers from list */
+ spinlock_t slock;
+ /* count of how many buffer header refils have failed because
+ * there was no buffer to satisfy them
+ */
+ int buffer_underflow;
+ /* callback on buffer completion */
+ vchiq_mmal_buffer_cb buffer_cb;
+ /* callback context */
+ void *cb_ctx;
+};
+
+struct vchiq_mmal_component {
+ bool enabled;
+ u32 handle; /* VideoCore handle for component */
+ u32 inputs; /* Number of input ports */
+ u32 outputs; /* Number of output ports */
+ u32 clocks; /* Number of clock ports */
+ struct vchiq_mmal_port control; /* control port */
+ struct vchiq_mmal_port input[MAX_PORT_COUNT]; /* input ports */
+ struct vchiq_mmal_port output[MAX_PORT_COUNT]; /* output ports */
+ struct vchiq_mmal_port clock[MAX_PORT_COUNT]; /* clock ports */
+};
+
+
+int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance);
+int vchiq_mmal_finalise(struct vchiq_mmal_instance *instance);
+
+/* Initialise a mmal component and its ports
+*
+*/
+int vchiq_mmal_component_init(
+ struct vchiq_mmal_instance *instance,
+ const char *name,
+ struct vchiq_mmal_component **component_out);
+
+int vchiq_mmal_component_finalise(
+ struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_component *component);
+
+int vchiq_mmal_component_enable(
+ struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_component *component);
+
+int vchiq_mmal_component_disable(
+ struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_component *component);
+
+
+
+/* enable a mmal port
+ *
+ * enables a port and if a buffer callback provided enque buffer
+ * headers as apropriate for the port.
+ */
+int vchiq_mmal_port_enable(
+ struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_port *port,
+ vchiq_mmal_buffer_cb buffer_cb);
+
+/* disable a port
+ *
+ * disable a port will dequeue any pending buffers
+ */
+int vchiq_mmal_port_disable(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_port *port);
+
+
+int vchiq_mmal_port_parameter_set(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_port *port,
+ u32 parameter,
+ void *value,
+ u32 value_size);
+
+int vchiq_mmal_port_parameter_get(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_port *port,
+ u32 parameter,
+ void *value,
+ u32 *value_size);
+
+int vchiq_mmal_port_set_format(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_port *port);
+
+int vchiq_mmal_port_connect_tunnel(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_port *src,
+ struct vchiq_mmal_port *dst);
+
+int vchiq_mmal_version(struct vchiq_mmal_instance *instance,
+ u32 *major_out,
+ u32 *minor_out);
+
+int vchiq_mmal_submit_buffer(struct vchiq_mmal_instance *instance,
+ struct vchiq_mmal_port *port,
+ struct mmal_buffer *buf);
+
+#endif /* MMAL_VCHIQ_H */
/* command line parameter to select clock speed */
static char *clock_speed;
-module_param(clock_speed, charp, 0);
+module_param(clock_speed, charp, 0000);
MODULE_PARM_DESC(clock_speed, "MediaLB Clock Speed");
/*
* sub-buffer 1, 2, 4, 8, 16, 32, 64.
*/
static u8 fcnt = 4; /* (1 << fcnt) frames per subbuffer */
-module_param(fcnt, byte, 0);
+module_param(fcnt, byte, 0000);
MODULE_PARM_DESC(fcnt, "Num of frames per sub-buffer for sync channels as a power of 2");
static DEFINE_SPINLOCK(dim_lock);
/* IRQ / Polling option */
static bool polling_req;
-module_param(polling_req, bool, S_IRUGO);
+module_param(polling_req, bool, 0444);
MODULE_PARM_DESC(polling_req, "Request Polling. Default = 0 (use irq)");
/* Polling Rate */
static inline int drci_rd_reg(struct usb_device *dev, u16 reg, u16 *buf)
{
int retval;
- u16 *dma_buf = kzalloc(sizeof(u16), GFP_KERNEL);
+ __le16 *dma_buf = kzalloc(sizeof(*dma_buf), GFP_KERNEL);
u8 req_type = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
if (!dma_buf)
retval = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
DRCI_READ_REQ, req_type,
0x0000,
- reg, dma_buf, sizeof(u16), 5 * HZ);
+ reg, dma_buf, sizeof(*dma_buf), 5 * HZ);
*buf = le16_to_cpu(*dma_buf);
kfree(dma_buf);
#define MOST_DCI_RO_ATTR(_name) \
struct most_dci_attribute most_dci_attr_##_name = \
- __ATTR(_name, S_IRUGO, show_value, NULL)
+ __ATTR(_name, 0444, show_value, NULL)
#define MOST_DCI_ATTR(_name) \
struct most_dci_attribute most_dci_attr_##_name = \
- __ATTR(_name, S_IRUGO | S_IWUSR, show_value, store_value)
+ __ATTR(_name, 0644, show_value, store_value)
#define MOST_DCI_WO_ATTR(_name) \
struct most_dci_attribute most_dci_attr_##_name = \
- __ATTR(_name, S_IWUSR, NULL, store_value)
+ __ATTR(_name, 0200, NULL, store_value)
/**
* struct most_dci_attribute - to access the attributes of a dci object
.remove = nvec_power_remove,
.driver = {
.name = "nvec-power",
- }
+ }
};
module_platform_driver(nvec_power_driver);
fau -=
cvmx_pko_get_num_queues(priv->port) *
sizeof(u32);
- schedule_delayed_work(&priv->port_periodic_work, HZ);
+ schedule_delayed_work(&priv->port_periodic_work,
+ HZ);
}
}
}
if (ver < 0xdc02) {
dev_err(&dcon->client->dev,
- "DCON v1 is unsupported, giving up..\n");
+ "DCON v1 is unsupported, giving up..\n");
rc = -ENODEV;
goto err;
}
dcon_write(dcon, 0x3a, 0xc040);
dcon_write(dcon, DCON_REG_MEM_OPT_A, 0x0000); /* clear option bits */
dcon_write(dcon, DCON_REG_MEM_OPT_A,
- MEM_DLL_CLOCK_DELAY | MEM_POWER_DOWN);
+ MEM_DLL_CLOCK_DELAY | MEM_POWER_DOWN);
dcon_write(dcon, DCON_REG_MEM_OPT_B, MEM_SOFT_RESET);
/* Colour swizzle, AA, no passthrough, backlight */
dcon->ignore_fb_events = true;
err = fb_blank(dcon->fbinfo,
- blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK);
+ blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK);
dcon->ignore_fb_events = false;
unlock_fb_info(dcon->fbinfo);
console_unlock();
if (err) {
dev_err(&dcon->client->dev, "couldn't %sblank framebuffer\n",
- blank ? "" : "un");
+ blank ? "" : "un");
return false;
}
return true;
pr_info("dcon_source_switch to CPU\n");
/* Enable the scanline interrupt bit */
if (dcon_write(dcon, DCON_REG_MODE,
- dcon->disp_mode | MODE_SCAN_INT))
+ dcon->disp_mode | MODE_SCAN_INT))
pr_err("couldn't enable scanline interrupt!\n");
else
/* Wait up to one second for the scanline interrupt */
pdata->set_dconload(0);
dcon->load_time = ktime_get();
- wait_event_timeout(dcon->waitq, dcon->switched, HZ/2);
+ wait_event_timeout(dcon->waitq, dcon->switched, HZ / 2);
if (!dcon->switched) {
pr_err("Timeout entering DCON mode; expect a screen glitch.\n");
dcon, &dcon_bl_ops, &dcon_bl_props);
if (IS_ERR(dcon->bl_dev)) {
dev_err(&client->dev, "cannot register backlight dev (%ld)\n",
- PTR_ERR(dcon->bl_dev));
+ PTR_ERR(dcon->bl_dev));
dcon->bl_dev = NULL;
}
/* irq status will appear in PMIO_Rx50[6] on gpio12 */
tmp = inb(VX855_GPI_STATUS_CHG);
- return !!(tmp & BIT_GPIO12);
- return 0;
+ return !!(tmp & BIT_GPIO12);
}
static int dcon_init_xo_1_5(struct dcon_priv *dcon)
outb(tmp, 0x3c5);
}
-
static void dcon_wiggle_xo_1_5(void)
{
int x;
void init_mlme_ap_info(struct adapter *padapter)
{
- struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct sta_priv *pstapriv = &padapter->stapriv;
struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
{
struct sta_info *psta = NULL;
struct sta_priv *pstapriv = &padapter->stapriv;
- struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
/* free bc/mc sta_info */
psta = rtw_get_bcmc_stainfo(padapter);
- spin_lock_bh(&(pstapriv->sta_hash_lock));
+ spin_lock_bh(&pstapriv->sta_hash_lock);
rtw_free_stainfo(padapter, psta);
- spin_unlock_bh(&(pstapriv->sta_hash_lock));
+ spin_unlock_bh(&pstapriv->sta_hash_lock);
}
static void update_BCNTIM(struct adapter *padapter)
{
struct sta_priv *pstapriv = &padapter->stapriv;
- struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
- struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
- struct wlan_bssid_ex *pnetwork_mlmeext = &(pmlmeinfo->network);
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+ struct wlan_bssid_ex *pnetwork_mlmeext = &pmlmeinfo->network;
unsigned char *pie = pnetwork_mlmeext->IEs;
u8 *p, *dst_ie, *premainder_ie = NULL;
u8 *pbackup_remainder_ie = NULL;
offset += pnetwork_mlmeext->Ssid.SsidLength + 2;
/* get supported rates len */
- p = rtw_get_ie(pie + _BEACON_IE_OFFSET_,
- _SUPPORTEDRATES_IE_, &tmp_len,
- (pnetwork_mlmeext->IELength -
- _BEACON_IE_OFFSET_));
+ p = rtw_get_ie(pie + _BEACON_IE_OFFSET_, _SUPPORTEDRATES_IE_,
+ &tmp_len, (pnetwork_mlmeext->IELength -
+ _BEACON_IE_OFFSET_));
if (p)
offset += tmp_len+2;
if (remainder_ielen > 0) {
pbackup_remainder_ie = rtw_malloc(remainder_ielen);
if (pbackup_remainder_ie && premainder_ie)
- memcpy(pbackup_remainder_ie,
- premainder_ie, remainder_ielen);
+ memcpy(pbackup_remainder_ie, premainder_ie,
+ remainder_ielen);
}
*dst_ie++ = _TIM_IE_;
- if ((pstapriv->tim_bitmap&0xff00) &&
- (pstapriv->tim_bitmap&0x00fc))
+ if ((pstapriv->tim_bitmap&0xff00) && (pstapriv->tim_bitmap&0x00fc))
tim_ielen = 5;
else
tim_ielen = 4;
}
void rtw_add_bcn_ie(struct adapter *padapter, struct wlan_bssid_ex *pnetwork,
- u8 index, u8 *data, u8 len)
+ u8 index, u8 *data, u8 len)
{
struct ndis_802_11_var_ie *pIE;
u8 bmatch = false;
if (remainder_ielen > 0) {
pbackup_remainder_ie = rtw_malloc(remainder_ielen);
if (pbackup_remainder_ie && premainder_ie)
- memcpy(pbackup_remainder_ie,
- premainder_ie, remainder_ielen);
+ memcpy(pbackup_remainder_ie, premainder_ie,
+ remainder_ielen);
}
*dst_ie++ = index;
}
void rtw_remove_bcn_ie(struct adapter *padapter, struct wlan_bssid_ex *pnetwork,
- u8 index)
+ u8 index)
{
u8 *p, *dst_ie = NULL, *premainder_ie = NULL;
u8 *pbackup_remainder_ie = NULL;
if (remainder_ielen > 0) {
pbackup_remainder_ie = rtw_malloc(remainder_ielen);
if (pbackup_remainder_ie && premainder_ie)
- memcpy(pbackup_remainder_ie,
- premainder_ie, remainder_ielen);
+ memcpy(pbackup_remainder_ie, premainder_ie,
+ remainder_ielen);
}
/* copy remainder IE */
spin_unlock_bh(&pstapriv->auth_list_lock);
- spin_lock_bh(&(pstapriv->sta_hash_lock));
+ spin_lock_bh(&pstapriv->sta_hash_lock);
rtw_free_stainfo(padapter, psta);
- spin_unlock_bh(&(pstapriv->sta_hash_lock));
+ spin_unlock_bh(&pstapriv->sta_hash_lock);
spin_lock_bh(&pstapriv->auth_list_lock);
}
* for this station
*/
pstapriv->tim_bitmap |= BIT(psta->aid);
- update_beacon(padapter, _TIM_IE_,
- NULL, false);
+ update_beacon(padapter, _TIM_IE_, NULL,
+ false);
if (!pmlmeext->active_keep_alive_check)
continue;
unsigned char limit;
unsigned int tx_ra_bitmap = 0;
struct ht_priv *psta_ht = NULL;
- struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct wlan_bssid_ex *pcur_network = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network;
if (psta)
unsigned char network_type, raid;
int i, supportRateNum = 0;
unsigned int tx_ra_bitmap = 0;
- struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct wlan_bssid_ex *pcur_network = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network;
struct sta_info *psta = rtw_get_bcmc_stainfo(padapter);
void update_sta_info_apmode(struct adapter *padapter, struct sta_info *psta)
{
- struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct security_priv *psecuritypriv = &padapter->securitypriv;
- struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct ht_priv *phtpriv_ap = &pmlmepriv->htpriv;
struct ht_priv *phtpriv_sta = &psta->htpriv;
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);
+ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
DBG_88E("%s\n", __func__);
u32 acparm;
int ie_len;
struct registry_priv *pregpriv = &padapter->registrypriv;
- struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
- struct security_priv *psecuritypriv = &(padapter->securitypriv);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct security_priv *psecuritypriv = &padapter->securitypriv;
struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network;
- struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
- struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
- struct wlan_bssid_ex *pnetwork_mlmeext = &(pmlmeinfo->network);
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+ struct wlan_bssid_ex *pnetwork_mlmeext = &pmlmeinfo->network;
struct HT_info_element *pht_info = NULL;
bcn_interval = (u16)pnetwork->Configuration.BeaconPeriod;
u8 WMM_PARA_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01};
struct registry_priv *pregistrypriv = &padapter->registrypriv;
struct security_priv *psecuritypriv = &padapter->securitypriv;
- struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct wlan_bssid_ex *pbss_network = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network;
u8 *ie = pbss_network->IEs;
pbss_network->Rssi = 0;
- ether_addr_copy(pbss_network->MacAddress, myid(&(padapter->eeprompriv)));
+ ether_addr_copy(pbss_network->MacAddress, myid(&padapter->eeprompriv));
/* beacon interval */
p = rtw_get_beacon_interval_from_ie(ie);/* 8: TimeStamp, 2: Beacon Interval 2:Capability */
if ((NUM_ACL - 1) < pacl_list->num)
return -1;
- spin_lock_bh(&(pacl_node_q->lock));
+ spin_lock_bh(&pacl_node_q->lock);
phead = get_list_head(pacl_node_q);
plist = phead->next;
}
}
- spin_unlock_bh(&(pacl_node_q->lock));
+ spin_unlock_bh(&pacl_node_q->lock);
if (added)
return ret;
- spin_lock_bh(&(pacl_node_q->lock));
+ spin_lock_bh(&pacl_node_q->lock);
for (i = 0; i < NUM_ACL; i++) {
paclnode = &pacl_list->aclnode[i];
DBG_88E("%s, acl_num =%d\n", __func__, pacl_list->num);
- spin_unlock_bh(&(pacl_node_q->lock));
+ spin_unlock_bh(&pacl_node_q->lock);
return ret;
}
DBG_88E("%s(acl_num =%d) =%pM\n", __func__, pacl_list->num, (addr));
- spin_lock_bh(&(pacl_node_q->lock));
+ spin_lock_bh(&pacl_node_q->lock);
phead = get_list_head(pacl_node_q);
plist = phead->next;
}
}
- spin_unlock_bh(&(pacl_node_q->lock));
+ spin_unlock_bh(&pacl_node_q->lock);
DBG_88E("%s, acl_num =%d\n", __func__, pacl_list->num);
return 0;
static void update_bcn_erpinfo_ie(struct adapter *padapter)
{
- struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
- struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
- struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
- struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+ struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network;
unsigned char *p, *ie = pnetwork->IEs;
u32 len = 0;
u8 *pwps_ie = NULL, *pwps_ie_src;
u8 *premainder_ie, *pbackup_remainder_ie = NULL;
uint wps_ielen = 0, wps_offset, remainder_ielen;
- struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
- struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
- struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
- struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+ struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network;
unsigned char *ie = pnetwork->IEs;
u32 ielen = pnetwork->IELength;
if (!padapter)
return;
- pmlmepriv = &(padapter->mlmepriv);
- pmlmeext = &(padapter->mlmeextpriv);
+ pmlmepriv = &padapter->mlmepriv;
+ pmlmeext = &padapter->mlmeextpriv;
if (!pmlmeext->bstart_bss)
return;
{
u16 cur_op_mode, new_op_mode;
int op_mode_changes = 0;
- struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct ht_priv *phtpriv_ap = &pmlmepriv->htpriv;
if (pmlmepriv->htpriv.ht_option)
void bss_cap_update_on_sta_join(struct adapter *padapter, struct sta_info *psta)
{
u8 beacon_updated = false;
- struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
- struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
if (!(psta->flags & WLAN_STA_SHORT_PREAMBLE)) {
if (!psta->no_short_preamble_set) {
pmlmepriv->num_sta_ht_no_gf++;
}
DBG_88E("%s STA %pM - no greenfield, num of non-gf stations %d\n",
- __func__, (psta->hwaddr),
- pmlmepriv->num_sta_ht_no_gf);
+ __func__, (psta->hwaddr),
+ pmlmepriv->num_sta_ht_no_gf);
}
if ((ht_capab & IEEE80211_HT_CAP_SUP_WIDTH) == 0) {
pmlmepriv->num_sta_ht_20mhz++;
}
DBG_88E("%s STA %pM - 20 MHz HT, num of 20MHz HT STAs %d\n",
- __func__, (psta->hwaddr),
- pmlmepriv->num_sta_ht_20mhz);
+ __func__, (psta->hwaddr),
+ pmlmepriv->num_sta_ht_20mhz);
}
} else {
if (!psta->no_ht_set) {
u8 bss_cap_update_on_sta_leave(struct adapter *padapter, struct sta_info *psta)
{
u8 beacon_updated = false;
- struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
- struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
if (!psta)
return beacon_updated;
beacon_updated = bss_cap_update_on_sta_leave(padapter, psta);
- spin_lock_bh(&(pstapriv->sta_hash_lock));
+ spin_lock_bh(&pstapriv->sta_hash_lock);
rtw_free_stainfo(padapter, psta);
- spin_unlock_bh(&(pstapriv->sta_hash_lock));
+ spin_unlock_bh(&pstapriv->sta_hash_lock);
return beacon_updated;
}
struct sta_info *psta = NULL;
struct sta_priv *pstapriv = &padapter->stapriv;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
- struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
DBG_88E(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(padapter->pnetdev));
void sta_info_update(struct adapter *padapter, struct sta_info *psta)
{
int flags = psta->flags;
- struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
/* update wmm cap. */
if (WLAN_STA_WME&flags)
void start_ap_mode(struct adapter *padapter)
{
int i;
- struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct sta_priv *pstapriv = &padapter->stapriv;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
pmlmepriv->wps_assoc_resp_ie = NULL;
/* for ACL */
- INIT_LIST_HEAD(&(pacl_list->acl_node_q.queue));
+ INIT_LIST_HEAD(&pacl_list->acl_node_q.queue);
pacl_list->num = 0;
pacl_list->mode = 0;
for (i = 0; i < NUM_ACL; i++) {
struct rtw_wlan_acl_node *paclnode;
struct sta_info *psta = NULL;
struct sta_priv *pstapriv = &padapter->stapriv;
- struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
+ struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
struct __queue *pacl_node_q = &pacl_list->acl_node_q;
padapter->securitypriv.ndisencryptstatus = Ndis802_11WEPDisabled;
/* for ACL */
- spin_lock_bh(&(pacl_node_q->lock));
+ spin_lock_bh(&pacl_node_q->lock);
phead = get_list_head(pacl_node_q);
plist = phead->next;
while (phead != plist) {
pacl_list->num--;
}
}
- spin_unlock_bh(&(pacl_node_q->lock));
+ spin_unlock_bh(&pacl_node_q->lock);
DBG_88E("%s, free acl_node_queue, num =%d\n", __func__, pacl_list->num);
rtw_free_all_stainfo(padapter);
psta = rtw_get_bcmc_stainfo(padapter);
- spin_lock_bh(&(pstapriv->sta_hash_lock));
+ spin_lock_bh(&pstapriv->sta_hash_lock);
rtw_free_stainfo(padapter, psta);
- spin_unlock_bh(&(pstapriv->sta_hash_lock));
+ spin_unlock_bh(&pstapriv->sta_hash_lock);
rtw_init_bcmc_stainfo(padapter);
spin_lock_bh(&pmlmepriv->lock);
- if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) && (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true))
- _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
-
set_fwstate(pmlmepriv, _FW_LINKED);
spin_unlock_bh(&pmlmepriv->lock);
u8 lenc[2];
u16 lenbak, aaabak;
u16 aaa;
+
lenc[0] = usb_read8(adapter, REG_PKTBUF_DBG_DATA_L);
lenc[1] = usb_read8(adapter, REG_PKTBUF_DBG_DATA_L+1);
}
if ((tmp_header & 0x0F) == 0x0F) { /* word_en PG fail */
- if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) {
+ if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_)
return false;
- }
+
efuse_addr++;
continue;
} else if (pg_header != tmp_header) { /* offset PG fail */
struct pgpkt fixPkt;
+
fixPkt.offset = ((pg_header_temp & 0xE0) >> 5) | ((tmp_header & 0xF0) >> 1);
fixPkt.word_en = tmp_header & 0x0F;
fixPkt.word_cnts = Efuse_CalculateWordCnts(fixPkt.word_en);
bRet = true;
} else {
struct pgpkt fixPkt;
+
fixPkt.offset = (tmp_header>>4) & 0x0F;
fixPkt.word_en = tmp_header & 0x0F;
fixPkt.word_cnts = Efuse_CalculateWordCnts(fixPkt.word_en);
u8 Efuse_CalculateWordCnts(u8 word_en)
{
u8 word_cnts = 0;
+
if (!(word_en & BIT(0)))
word_cnts++; /* 0 : write enable */
if (!(word_en & BIT(1)))
unsigned char dot11_rate_table[] = {
2, 4, 11, 22, 12, 18, 24, 36, 48,
72, 96, 108, 0}; /* last element must be zero!! */
-
int i = 0;
+
while (dot11_rate_table[i] != 0) {
if (dot11_rate_table[i] == val)
return BIT(i);
{
int tmp, i;
u8 *p;
+
if (limit < 1)
return NULL;
uint rtw_get_rateset_len(u8 *rateset)
{
uint i = 0;
+
while (1) {
if ((rateset[i]) == 0)
break;
static int rtw_get_cipher_info(struct wlan_network *pnetwork)
{
- u32 wpa_ielen;
+ int wpa_ielen;
unsigned char *pbuf;
int group_cipher = 0, pairwise_cipher = 0, is8021x = 0;
int ret = _FAIL;
+
pbuf = rtw_get_wpa_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength - 12);
if (pbuf && (wpa_ielen > 0)) {
__le16 le_tmp;
u16 wpa_len = 0, rsn_len = 0;
struct HT_info_element *pht_info = NULL;
- unsigned int len;
+ int len;
unsigned char *p;
memcpy(&le_tmp, rtw_get_capability_from_ie(pnetwork->network.IEs), 2);
u8 bw_40MHz = 0, short_GI_20 = 0, short_GI_40 = 0;
u32 ht_ielen = 0;
- if (adapter->registrypriv.mp_mode == 1) {
- if (check_fwstate(pmlmepriv, WIFI_MP_STATE))
- return 0;
- }
-
if ((!check_fwstate(pmlmepriv, _FW_LINKED)) &&
(!check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)))
return 0;
void BlinkWorkItemCallback(struct work_struct *work)
{
struct LED_871x *pLed = container_of(work, struct LED_871x, BlinkWorkItem);
+
BlinkHandler(pLed);
}
}
} else {
int s_ret;
+
set_fwstate(pmlmepriv, _FW_UNDER_LINKING);
pmlmepriv->to_join = false;
s_ret = rtw_select_and_join_from_scanned_queue(pmlmepriv);
if (mac_id >= 0) {
u16 media_status;
+
media_status = (mac_id<<8)|0; /* MACID|OPMODE:0 means disconnect */
/* for STA, AP, ADHOC mode, report disconnect stauts to FW */
rtw_hal_set_hwreg(adapter, HW_VAR_H2C_MEDIA_STATUS_RPT, (u8 *)&media_status);
rtw_hal_get_def_var(adapter, HAL_DEF_IS_SUPPORT_ANT_DIV, &(supp_ant_div));
if (supp_ant_div) {
u8 cur_ant;
+
rtw_hal_get_def_var(adapter, HAL_DEF_CURRENT_ANTENNA, &(cur_ant));
DBG_88E("#### Opt_Ant_(%s), cur_Ant(%s)\n",
(2 == candidate->network.PhyInfo.Optimum_antenna) ? "A" : "B",
int rtw_ch_set_search_ch(struct rt_channel_info *ch_set, const u32 ch)
{
int i;
+
for (i = 0; ch_set[i].ChannelNum != 0; i++) {
if (ch == ch_set[i].ChannelNum)
break;
pxmitpriv->ack_tx = true;
pmgntframe->ack_report = 1;
- if (rtw_hal_mgnt_xmit(padapter, pmgntframe) == _SUCCESS) {
+ if (rtw_hal_mgnt_xmit(padapter, pmgntframe) == _SUCCESS)
ret = rtw_ack_tx_wait(pxmitpriv, timeout_ms);
- }
pxmitpriv->ack_tx = false;
mutex_unlock(&pxmitpriv->ack_tx_mutex);
u8 *wps_ie;
uint wps_ielen;
u8 sr = 0;
+
memcpy(pframe, cur_network->IEs, cur_network->IELength);
len_diff = update_hidden_ssid(
pframe+_BEACON_IE_OFFSET_
} else {
__le32 le_tmp32;
__le16 le_tmp16;
+
ether_addr_copy(pwlanhdr->addr1, pnetwork->MacAddress);
ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv));
ether_addr_copy(pwlanhdr->addr3, pnetwork->MacAddress);
if (ScanType == SCAN_ACTIVE) { /* obey the channel plan setting... */
int i;
+
for (i = 0; i < RTW_SSID_SCAN_AMOUNT; i++) {
if (pmlmeext->sitesurvey_res.ssid[i].SsidLength) {
/* todo: to issue two probe req??? */
u32 len;
u8 *p;
u16 val16, subtype;
- u8 *pframe = precv_frame->rx_data;
- u32 packet_len = precv_frame->len;
+ u8 *pframe = precv_frame->pkt->data;
+ u32 packet_len = precv_frame->pkt->len;
u8 ie_offset;
struct registry_priv *pregistrypriv = &padapter->registrypriv;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
p = rtw_get_ie(bssid->IEs + ie_offset, _HT_ADD_INFO_IE_, &len, bssid->IELength - ie_offset);
if (p) {
struct HT_info_element *HT_info = (struct HT_info_element *)(p + 2);
+
bssid->Configuration.DSConfig = HT_info->primary_channel;
} else { /* use current channel */
bssid->Configuration.DSConfig = rtw_get_oper_ch(padapter);
/* 20/40 BSS Coexistence check */
if ((pregistrypriv->wifi_spec == 1) && (!pmlmeinfo->bwmode_updated)) {
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
p = rtw_get_ie(bssid->IEs + ie_offset, _HT_CAPABILITY_IE_, &len, bssid->IELength - ie_offset);
if (p && len > 0) {
struct ieee80211_ht_cap *pHT_caps =
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)(&(pmlmeinfo->network));
+
pmlmeext->cur_channel = (u8)pnetwork->Configuration.DSConfig;
pmlmeinfo->bcn_interval = get_beacon_interval(pnetwork);
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
struct wlan_bssid_ex *cur = &(pmlmeinfo->network);
- u8 *pframe = precv_frame->rx_data;
- uint len = precv_frame->len;
+ u8 *pframe = precv_frame->pkt->data;
+ uint len = precv_frame->pkt->len;
if (check_fwstate(pmlmepriv, WIFI_STATION_STATE))
return _SUCCESS;
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct sta_priv *pstapriv = &padapter->stapriv;
- u8 *pframe = precv_frame->rx_data;
- uint len = precv_frame->len;
+ u8 *pframe = precv_frame->pkt->data;
+ uint len = precv_frame->pkt->len;
struct wlan_bssid_ex *pbss;
int ret = _SUCCESS;
struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
struct security_priv *psecuritypriv = &padapter->securitypriv;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
- u8 *pframe = precv_frame->rx_data;
- uint len = precv_frame->len;
+ u8 *pframe = precv_frame->pkt->data;
+ uint len = precv_frame->pkt->len;
if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE)
return _FAIL;
unsigned int go2asoc = 0;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
- u8 *pframe = precv_frame->rx_data;
- uint pkt_len = precv_frame->len;
+ u8 *pframe = precv_frame->pkt->data;
+ uint pkt_len = precv_frame->pkt->len;
DBG_88E("%s\n", __func__);
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
struct wlan_bssid_ex *cur = &(pmlmeinfo->network);
struct sta_priv *pstapriv = &padapter->stapriv;
- u8 *pframe = precv_frame->rx_data;
- uint pkt_len = precv_frame->len;
+ u8 *pframe = precv_frame->pkt->data;
+ uint pkt_len = precv_frame->pkt->len;
if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE)
return _FAIL;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
/* struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); */
- u8 *pframe = precv_frame->rx_data;
- uint pkt_len = precv_frame->len;
+ u8 *pframe = precv_frame->pkt->data;
+ uint pkt_len = precv_frame->pkt->len;
DBG_88E("%s\n", __func__);
UpdateBrateTbl(padapter, pmlmeinfo->network.SupportedRates);
report_assoc_result:
- if (res > 0) {
+ if (res > 0)
rtw_buf_update(&pmlmepriv->assoc_rsp, &pmlmepriv->assoc_rsp_len, pframe, pkt_len);
- } else {
+ else
rtw_buf_free(&pmlmepriv->assoc_rsp, &pmlmepriv->assoc_rsp_len);
- }
report_join_res(padapter, res);
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
- u8 *pframe = precv_frame->rx_data;
+ u8 *pframe = precv_frame->pkt->data;
struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
/* check A3 */
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
- u8 *pframe = precv_frame->rx_data;
+ u8 *pframe = precv_frame->pkt->data;
struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
/* check A3 */
{
struct sta_info *psta = NULL;
struct sta_priv *pstapriv = &padapter->stapriv;
- u8 *pframe = precv_frame->rx_data;
+ u8 *pframe = precv_frame->pkt->data;
u8 *frame_body = pframe + sizeof(struct ieee80211_hdr_3addr);
u8 category;
u8 action;
unsigned short tid, status, reason_code = 0;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
- u8 *pframe = precv_frame->rx_data;
+ u8 *pframe = precv_frame->pkt->data;
struct sta_priv *pstapriv = &padapter->stapriv;
/* check RA matches or not */
if (memcmp(myid(&(padapter->eeprompriv)), GetAddr1Ptr(pframe),
{
struct adapter *adapter = recv_frame->adapter;
struct mlme_ext_priv *mlmeext = &(adapter->mlmeextpriv);
- u8 *frame = recv_frame->rx_data;
+ u8 *frame = recv_frame->pkt->data;
u16 seq_ctrl = ((recv_frame->attrib.seq_num&0xffff) << 4) |
(recv_frame->attrib.frag_num & 0xf);
static unsigned int on_action_public_p2p(struct recv_frame *precv_frame)
{
- u8 *pframe = precv_frame->rx_data;
+ u8 *pframe = precv_frame->pkt->data;
u8 *frame_body;
u8 dialogToken = 0;
- frame_body = (unsigned char *)(pframe + sizeof(struct ieee80211_hdr_3addr));
+ frame_body = (unsigned char *)(pframe + sizeof(struct ieee80211_hdr_3addr));
dialogToken = frame_body[7];
if (rtw_action_public_decache(precv_frame, dialogToken) == _FAIL)
static unsigned int on_action_public_vendor(struct recv_frame *precv_frame)
{
unsigned int ret = _FAIL;
- u8 *pframe = precv_frame->rx_data;
+ u8 *pframe = precv_frame->pkt->data;
u8 *frame_body = pframe + sizeof(struct ieee80211_hdr_3addr);
if (!memcmp(frame_body + 2, P2P_OUI, 4))
static unsigned int on_action_public_default(struct recv_frame *precv_frame, u8 action)
{
unsigned int ret = _FAIL;
- u8 *pframe = precv_frame->rx_data;
+ u8 *pframe = precv_frame->pkt->data;
u8 *frame_body = pframe + sizeof(struct ieee80211_hdr_3addr);
u8 token;
struct recv_frame *precv_frame)
{
unsigned int ret = _FAIL;
- u8 *pframe = precv_frame->rx_data;
+ u8 *pframe = precv_frame->pkt->data;
u8 *frame_body = pframe + sizeof(struct ieee80211_hdr_3addr);
u8 category, action;
unsigned char category;
struct action_handler *ptable;
unsigned char *frame_body;
- u8 *pframe = precv_frame->rx_data;
+ u8 *pframe = precv_frame->pkt->data;
frame_body = (unsigned char *)(pframe + sizeof(struct ieee80211_hdr_3addr));
struct p2p_reg_class *reg = NULL;
for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
- if (!has_channel(channel_set, chanset_size, ch)) {
+ if (!has_channel(channel_set, chanset_size, ch))
continue;
- }
if ((0 == padapter->registrypriv.ht_enable) && (8 == o->inc))
continue;
static void _mgt_dispatcher(struct adapter *padapter, struct mlme_handler *ptable, struct recv_frame *precv_frame)
{
u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- u8 *pframe = precv_frame->rx_data;
+ u8 *pframe = precv_frame->pkt->data;
if (ptable->func) {
/* receive the frames that ra(a1) is my address or ra(a1) is bc address. */
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
#endif /* CONFIG_88EU_AP_MODE */
u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- u8 *pframe = precv_frame->rx_data;
+ u8 *pframe = precv_frame->pkt->data;
struct sta_info *psta = rtw_get_stainfo(&padapter->stapriv, GetAddr2Ptr(pframe));
RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
Following are the functions for the timer handlers
*****************************************************************************/
-void _linked_rx_signal_strehgth_display(struct adapter *padapter);
-void _linked_rx_signal_strehgth_display(struct adapter *padapter)
-{
- struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
- struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
- u8 mac_id;
- int UndecoratedSmoothedPWDB;
- if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE)
- mac_id = 0;
- else if ((pmlmeinfo->state&0x03) == _HW_STATE_AP_)
- mac_id = 2;
-
- rtw_hal_get_def_var(padapter, HW_DEF_RA_INFO_DUMP, &mac_id);
-
- rtw_hal_get_def_var(padapter, HAL_DEF_UNDERCORATEDSMOOTHEDPWDB, &UndecoratedSmoothedPWDB);
- DBG_88E("UndecoratedSmoothedPWDB:%d\n", UndecoratedSmoothedPWDB);
-}
static u8 chk_ap_is_alive(struct adapter *padapter, struct sta_info *psta)
{
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
struct sta_priv *pstapriv = &padapter->stapriv;
- if (padapter->bRxRSSIDisplay)
- _linked_rx_signal_strehgth_display(padapter);
-
if (is_client_associated_to_ap(padapter)) {
/* linked infrastructure client mode */
}
}
- if (tx_chk != _SUCCESS && pmlmeinfo->link_count++ == 0xf) {
+ if (tx_chk != _SUCCESS && pmlmeinfo->link_count++ == 0xf)
tx_chk = issue_nulldata(padapter, NULL, 0, 1, 0);
- }
}
if (rx_chk == _FAIL) {
DBG_88E("==>ips_leave cnts:%d\n", pwrpriv->ips_leave_cnts);
result = rtw_ips_pwr_up(padapter);
- if (result == _SUCCESS) {
+ if (result == _SUCCESS)
pwrpriv->rf_pwrstate = rf_on;
- }
+
DBG_88E_LEVEL(_drv_info_, "nolinked power save leave\n");
if ((_WEP40_ == psecuritypriv->dot11PrivacyAlgrthm) || (_WEP104_ == psecuritypriv->dot11PrivacyAlgrthm)) {
static void pwr_state_check_handler(unsigned long data)
{
struct adapter *padapter = (struct adapter *)data;
+
rtw_ps_cmd(padapter);
}
&(precvpriv->free_recv_queue.queue));
precvframe->pkt = NULL;
- precvframe->len = 0;
precvframe->adapter = padapter;
precvframe++;
list_del_init(&(precvframe->list));
- precvframe->len = 0;
-
list_add_tail(&(precvframe->list), get_list_head(pfree_recv_queue));
spin_unlock_bh(&pfree_recv_queue->lock);
{
u32 cnt = 0;
struct recv_frame *pending_frame;
+
while ((pending_frame = rtw_alloc_recvframe(&adapter->recvpriv.uc_swdec_pending_queue))) {
rtw_free_recvframe(pending_frame, &adapter->recvpriv.free_recv_queue);
DBG_88E("%s: dequeue uc_swdec_pending_queue\n", __func__);
}
/* icv_len included the mic code */
- datalen = precvframe->len-prxattrib->hdrlen -
+ datalen = precvframe->pkt->len-prxattrib->hdrlen -
prxattrib->iv_len-prxattrib->icv_len-8;
- pframe = precvframe->rx_data;
+ pframe = precvframe->pkt->data;
payload = pframe+prxattrib->hdrlen+prxattrib->iv_len;
RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n prxattrib->iv_len=%d prxattrib->icv_len=%d\n", prxattrib->iv_len, prxattrib->icv_len));
*(pframemic-10), *(pframemic-9)));
{
uint i;
+
RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
("\n ======demp packet (len=%d)======\n",
- precvframe->len));
- for (i = 0; i < precvframe->len; i += 8) {
+ precvframe->pkt->len));
+ for (i = 0; i < precvframe->pkt->len; i += 8) {
RT_TRACE(_module_rtl871x_recv_c_,
_drv_err_,
("0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x",
- *(precvframe->rx_data+i),
- *(precvframe->rx_data+i+1),
- *(precvframe->rx_data+i+2),
- *(precvframe->rx_data+i+3),
- *(precvframe->rx_data+i+4),
- *(precvframe->rx_data+i+5),
- *(precvframe->rx_data+i+6),
- *(precvframe->rx_data+i+7)));
+ *(precvframe->pkt->data+i),
+ *(precvframe->pkt->data+i+1),
+ *(precvframe->pkt->data+i+2),
+ *(precvframe->pkt->data+i+3),
+ *(precvframe->pkt->data+i+4),
+ *(precvframe->pkt->data+i+5),
+ *(precvframe->pkt->data+i+6),
+ *(precvframe->pkt->data+i+7)));
}
RT_TRACE(_module_rtl871x_recv_c_,
_drv_err_,
("\n ====== demp packet end [len=%d]======\n",
- precvframe->len));
+ precvframe->pkt->len));
RT_TRACE(_module_rtl871x_recv_c_,
_drv_err_,
("\n hrdlen=%d,\n",
RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("recvframe_chkmic: rtw_get_stainfo==NULL!!!\n"));
}
- recvframe_pull_tail(precvframe, 8);
+ skb_trim(precvframe->pkt, precvframe->pkt->len - 8);
}
exit:
RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("prxstat->decrypted=%x prxattrib->encrypt=0x%03x\n", prxattrib->bdecrypted, prxattrib->encrypt));
if (prxattrib->encrypt > 0) {
- u8 *iv = precv_frame->rx_data+prxattrib->hdrlen;
+ u8 *iv = precv_frame->pkt->data+prxattrib->hdrlen;
+
prxattrib->key_index = (((iv[3])>>6)&0x3);
if (prxattrib->key_index > WEP_KEYS) {
auth_alg = adapter->securitypriv.dot11AuthAlgrthm;
- ptr = precv_frame->rx_data;
+ ptr = precv_frame->pkt->data;
pfhdr = precv_frame;
pattrib = &pfhdr->attrib;
psta_addr = pattrib->ta;
{
#ifdef CONFIG_88EU_AP_MODE
unsigned char pwrbit;
- u8 *ptr = precv_frame->rx_data;
+ u8 *ptr = precv_frame->pkt->data;
struct rx_pkt_attrib *pattrib = &precv_frame->attrib;
struct sta_priv *pstapriv = &padapter->stapriv;
struct sta_info *psta = NULL;
struct rx_pkt_attrib *pattrib = &prframe->attrib;
struct recv_priv *precvpriv = &padapter->recvpriv;
- sz = prframe->len;
+ sz = prframe->pkt->len;
precvpriv->rx_bytes += sz;
padapter->mlmepriv.LinkDetectInfo.NumRxOkInPeriod++;
int sta2sta_data_frame(struct adapter *adapter, struct recv_frame *precv_frame,
struct sta_info **psta)
{
- u8 *ptr = precv_frame->rx_data;
int ret = _SUCCESS;
struct rx_pkt_attrib *pattrib = &precv_frame->attrib;
struct sta_priv *pstapriv = &adapter->stapriv;
sta_addr = pattrib->src;
}
- } else if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) {
- memcpy(pattrib->dst, GetAddr1Ptr(ptr), ETH_ALEN);
- memcpy(pattrib->src, GetAddr2Ptr(ptr), ETH_ALEN);
- memcpy(pattrib->bssid, GetAddr3Ptr(ptr), ETH_ALEN);
- memcpy(pattrib->ra, pattrib->dst, ETH_ALEN);
- memcpy(pattrib->ta, pattrib->src, ETH_ALEN);
-
- sta_addr = mybssid;
} else {
ret = _FAIL;
}
struct recv_frame *precv_frame,
struct sta_info **psta)
{
- u8 *ptr = precv_frame->rx_data;
+ u8 *ptr = precv_frame->pkt->data;
struct rx_pkt_attrib *pattrib = &precv_frame->attrib;
int ret = _SUCCESS;
struct sta_priv *pstapriv = &adapter->stapriv;
ret = RTW_RX_HANDLED;
goto exit;
}
- } else if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) &&
- (check_fwstate(pmlmepriv, _FW_LINKED) == true)) {
- memcpy(pattrib->dst, GetAddr1Ptr(ptr), ETH_ALEN);
- memcpy(pattrib->src, GetAddr2Ptr(ptr), ETH_ALEN);
- memcpy(pattrib->bssid, GetAddr3Ptr(ptr), ETH_ALEN);
- memcpy(pattrib->ra, pattrib->dst, ETH_ALEN);
- memcpy(pattrib->ta, pattrib->src, ETH_ALEN);
-
- /* */
- memcpy(pattrib->bssid, mybssid, ETH_ALEN);
-
- *psta = rtw_get_stainfo(pstapriv, pattrib->bssid); /* get sta_info */
- if (*psta == NULL) {
- RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under MP_MODE ; drop pkt\n"));
- ret = _FAIL;
- goto exit;
- }
} else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
/* Special case */
ret = RTW_RX_HANDLED;
struct rx_pkt_attrib *pattrib = &precv_frame->attrib;
struct sta_priv *pstapriv = &adapter->stapriv;
struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
- u8 *ptr = precv_frame->rx_data;
+ u8 *ptr = precv_frame->pkt->data;
unsigned char *mybssid = get_bssid(pmlmepriv);
int ret = _SUCCESS;
}
} else {
u8 *myhwaddr = myid(&adapter->eeprompriv);
+
if (memcmp(pattrib->ra, myhwaddr, ETH_ALEN)) {
ret = RTW_RX_HANDLED;
goto exit;
#ifdef CONFIG_88EU_AP_MODE
struct rx_pkt_attrib *pattrib = &precv_frame->attrib;
struct sta_priv *pstapriv = &padapter->stapriv;
- u8 *pframe = precv_frame->rx_data;
+ u8 *pframe = precv_frame->pkt->data;
if (GetFrameType(pframe) != WIFI_CTRL_TYPE)
return _FAIL;
/* for rx pkt statistics */
psta = rtw_get_stainfo(&padapter->stapriv,
- GetAddr2Ptr(precv_frame->rx_data));
+ GetAddr2Ptr(precv_frame->pkt->data));
if (psta) {
psta->sta_stats.rx_mgnt_pkts++;
- if (GetFrameSubType(precv_frame->rx_data) == WIFI_BEACON) {
+ if (GetFrameSubType(precv_frame->pkt->data) == WIFI_BEACON) {
psta->sta_stats.rx_beacon_pkts++;
- } else if (GetFrameSubType(precv_frame->rx_data) == WIFI_PROBEREQ) {
+ } else if (GetFrameSubType(precv_frame->pkt->data) == WIFI_PROBEREQ) {
psta->sta_stats.rx_probereq_pkts++;
- } else if (GetFrameSubType(precv_frame->rx_data) == WIFI_PROBERSP) {
+ } else if (GetFrameSubType(precv_frame->pkt->data) == WIFI_PROBERSP) {
if (!memcmp(padapter->eeprompriv.mac_addr,
- GetAddr1Ptr(precv_frame->rx_data), ETH_ALEN))
+ GetAddr1Ptr(precv_frame->pkt->data), ETH_ALEN))
psta->sta_stats.rx_probersp_pkts++;
- else if (is_broadcast_mac_addr(GetAddr1Ptr(precv_frame->rx_data)) ||
- is_multicast_mac_addr(GetAddr1Ptr(precv_frame->rx_data)))
+ else if (is_broadcast_mac_addr(GetAddr1Ptr(precv_frame->pkt->data)) ||
+ is_multicast_mac_addr(GetAddr1Ptr(precv_frame->pkt->data)))
psta->sta_stats.rx_probersp_bm_pkts++;
else
psta->sta_stats.rx_probersp_uo_pkts++;
u8 bretry;
u8 *psa, *pda, *pbssid;
struct sta_info *psta = NULL;
- u8 *ptr = precv_frame->rx_data;
+ u8 *ptr = precv_frame->pkt->data;
struct rx_pkt_attrib *pattrib = &precv_frame->attrib;
struct security_priv *psecuritypriv = &adapter->securitypriv;
int ret = _SUCCESS;
break;
}
- if (ret == _FAIL) {
+ if (ret == _FAIL)
goto exit;
- } else if (ret == RTW_RX_HANDLED) {
+ else if (ret == RTW_RX_HANDLED)
goto exit;
- }
if (psta == NULL) {
RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" after to_fr_ds_chk; psta==NULL\n"));
int retval = _SUCCESS;
u8 bDumpRxPkt;
struct rx_pkt_attrib *pattrib = &precv_frame->attrib;
- u8 *ptr = precv_frame->rx_data;
+ u8 *ptr = precv_frame->pkt->data;
u8 ver = (unsigned char)(*ptr)&0x3;
struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) {
int ch_set_idx = rtw_ch_set_search_ch(pmlmeext->channel_set, rtw_get_oper_ch(adapter));
+
if (ch_set_idx >= 0)
pmlmeext->channel_set[ch_set_idx].rx_count++;
}
retval = validate_recv_data_frame(adapter, precv_frame);
if (retval == _FAIL) {
struct recv_priv *precvpriv = &adapter->recvpriv;
+
precvpriv->rx_drop++;
}
break;
u8 *psnap_type;
struct ieee80211_snap_hdr *psnap;
- struct adapter *adapter = precvframe->adapter;
- struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
- u8 *ptr = precvframe->rx_data;
+ u8 *ptr = precvframe->pkt->data;
struct rx_pkt_attrib *pattrib = &precvframe->attrib;
if (pattrib->encrypt)
- recvframe_pull_tail(precvframe, pattrib->icv_len);
+ skb_trim(precvframe->pkt, precvframe->pkt->len - pattrib->icv_len);
psnap = (struct ieee80211_snap_hdr *)(ptr+pattrib->hdrlen + pattrib->iv_len);
psnap_type = ptr+pattrib->hdrlen + pattrib->iv_len+SNAP_SIZE;
}
rmv_len = pattrib->hdrlen + pattrib->iv_len + (bsnaphdr ? SNAP_SIZE : 0);
- len = precvframe->len - rmv_len;
+ len = precvframe->pkt->len - rmv_len;
RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
("\n===pattrib->hdrlen: %x, pattrib->iv_len:%x===\n\n", pattrib->hdrlen, pattrib->iv_len));
eth_type = ntohs(be_tmp); /* pattrib->ether_type */
pattrib->eth_type = eth_type;
- if ((check_fwstate(pmlmepriv, WIFI_MP_STATE))) {
- ptr += rmv_len;
- *ptr = 0x87;
- *(ptr+1) = 0x12;
-
- eth_type = 0x8712;
- /* append rx status for mp test packets */
- ptr = recvframe_pull(precvframe, (rmv_len-sizeof(struct ethhdr)+2)-24);
- memcpy(ptr, get_rxmem(precvframe), 24);
- ptr += 24;
- } else {
- ptr = recvframe_pull(precvframe, (rmv_len-sizeof(struct ethhdr) + (bsnaphdr ? 2 : 0)));
- }
+ ptr = skb_pull(precvframe->pkt, rmv_len - sizeof(struct ethhdr) + (bsnaphdr ? 2 : 0));
+ if (!ptr)
+ return _FAIL;
memcpy(ptr, pattrib->dst, ETH_ALEN);
memcpy(ptr+ETH_ALEN, pattrib->src, ETH_ALEN);
wlanhdr_offset = pnfhdr->attrib.hdrlen + pnfhdr->attrib.iv_len;
- recvframe_pull(pnextrframe, wlanhdr_offset);
+ skb_pull(pnextrframe->pkt, wlanhdr_offset);
/* append to first fragment frame's tail (if privacy frame, pull the ICV) */
- recvframe_pull_tail(prframe, pfhdr->attrib.icv_len);
+ skb_trim(prframe->pkt, prframe->pkt->len - pfhdr->attrib.icv_len);
/* memcpy */
- memcpy(pfhdr->rx_tail, pnfhdr->rx_data, pnfhdr->len);
+ memcpy(skb_tail_pointer(pfhdr->pkt), pnfhdr->pkt->data,
+ pnfhdr->pkt->len);
- recvframe_put(prframe, pnfhdr->len);
+ skb_put(prframe->pkt, pnfhdr->pkt->len);
pfhdr->attrib.icv_len = pnfhdr->attrib.icv_len;
plist = plist->next;
psta_addr = pfhdr->attrib.ta;
psta = rtw_get_stainfo(pstapriv, psta_addr);
if (psta == NULL) {
- u8 type = GetFrameType(pfhdr->rx_data);
+ u8 type = GetFrameType(pfhdr->pkt->data);
+
if (type != WIFI_DATA_TYPE) {
psta = rtw_get_bcmc_stainfo(padapter);
pdefrag_q = &psta->sta_recvpriv.defrag_q;
struct sk_buff *sub_skb, *subframes[MAX_SUBFRAME_COUNT];
struct recv_priv *precvpriv = &padapter->recvpriv;
struct __queue *pfree_recv_queue = &(precvpriv->free_recv_queue);
- nr_subframes = 0;
+ nr_subframes = 0;
pattrib = &prframe->attrib;
- recvframe_pull(prframe, prframe->attrib.hdrlen);
+ skb_pull(prframe->pkt, prframe->attrib.hdrlen);
if (prframe->attrib.iv_len > 0)
- recvframe_pull(prframe, prframe->attrib.iv_len);
+ skb_pull(prframe->pkt, prframe->attrib.iv_len);
- a_len = prframe->len;
+ a_len = prframe->pkt->len;
- pdata = prframe->rx_data;
+ pdata = prframe->pkt->data;
while (a_len > ETH_HLEN) {
/* Offset 12 denote 2 mac address */
if (padding_len == 4)
padding_len = 0;
- if (a_len < padding_len) {
+ if (a_len < padding_len)
goto exit;
- }
+
pdata += padding_len;
a_len -= padding_len;
}
}
exit:
-
- prframe->len = 0;
rtw_free_recvframe(prframe, pfree_recv_queue);/* free this recv_frame */
return _SUCCESS;
u8 avg_signal_qual = 0;
u8 _alpha = 3; /* this value is based on converging_constant = 5000 and sampling_interval = 1000 */
- if (adapter->recvpriv.is_signal_dbg) {
- /* update the user specific value, signal_strength_dbg, to signal_strength, rssi */
- adapter->recvpriv.signal_strength = adapter->recvpriv.signal_strength_dbg;
- adapter->recvpriv.rssi = (s8)translate_percentage_to_dbm((u8)adapter->recvpriv.signal_strength_dbg);
- } else {
- if (recvpriv->signal_strength_data.update_req == 0) {/* update_req is clear, means we got rx */
- avg_signal_strength = recvpriv->signal_strength_data.avg_val;
- /* after avg_vals are acquired, we can re-stat the signal values */
- recvpriv->signal_strength_data.update_req = 1;
- }
-
- if (recvpriv->signal_qual_data.update_req == 0) {/* update_req is clear, means we got rx */
- avg_signal_qual = recvpriv->signal_qual_data.avg_val;
- /* after avg_vals are acquired, we can re-stat the signal values */
- recvpriv->signal_qual_data.update_req = 1;
- }
+ if (recvpriv->signal_strength_data.update_req == 0) {
+ /* update_req is clear, means we got rx */
+ avg_signal_strength = recvpriv->signal_strength_data.avg_val;
+ /* after avg_vals are acquired, we can re-stat the signal
+ * values
+ */
+ recvpriv->signal_strength_data.update_req = 1;
+ }
- /* update value of signal_strength, rssi, signal_qual */
- if (check_fwstate(&adapter->mlmepriv, _FW_UNDER_SURVEY) == false) {
- tmp_s = avg_signal_strength+(_alpha-1)*recvpriv->signal_strength;
- if (tmp_s % _alpha)
- tmp_s = tmp_s/_alpha + 1;
- else
- tmp_s = tmp_s/_alpha;
- if (tmp_s > 100)
- tmp_s = 100;
+ if (recvpriv->signal_qual_data.update_req == 0) {
+ /* update_req is clear, means we got rx */
+ avg_signal_qual = recvpriv->signal_qual_data.avg_val;
+ /* after avg_vals are acquired, we can re-stat the signal
+ * values
+ */
+ recvpriv->signal_qual_data.update_req = 1;
+ }
- tmp_q = avg_signal_qual+(_alpha-1)*recvpriv->signal_qual;
- if (tmp_q % _alpha)
- tmp_q = tmp_q/_alpha + 1;
- else
- tmp_q = tmp_q/_alpha;
- if (tmp_q > 100)
- tmp_q = 100;
+ /* update value of signal_strength, rssi, signal_qual */
+ if (check_fwstate(&adapter->mlmepriv, _FW_UNDER_SURVEY) == false) {
+ tmp_s = avg_signal_strength +
+ (_alpha - 1) * recvpriv->signal_strength;
+ if (tmp_s % _alpha)
+ tmp_s = tmp_s / _alpha + 1;
+ else
+ tmp_s = tmp_s / _alpha;
+ if (tmp_s > 100)
+ tmp_s = 100;
+
+ tmp_q = avg_signal_qual +
+ (_alpha - 1) * recvpriv->signal_qual;
+ if (tmp_q % _alpha)
+ tmp_q = tmp_q / _alpha + 1;
+ else
+ tmp_q = tmp_q / _alpha;
+ if (tmp_q > 100)
+ tmp_q = 100;
- recvpriv->signal_strength = tmp_s;
- recvpriv->rssi = (s8)translate_percentage_to_dbm(tmp_s);
- recvpriv->signal_qual = tmp_q;
- }
+ recvpriv->signal_strength = tmp_s;
+ recvpriv->rssi = (s8)translate_percentage_to_dbm(tmp_s);
+ recvpriv->signal_qual = tmp_q;
}
+
rtw_set_signal_stat_timer(recvpriv);
}
u32 stateindex;
u8 *state;
u32 counter;
+
state = parc4ctx->state;
parc4ctx->x = 0;
parc4ctx->y = 0;
u32 y;
u32 sx, sy;
u8 *state;
+
state = parc4ctx->state;
x = (parc4ctx->x + 1) & 0xff;
sx = state[x];
static void arcfour_encrypt(struct arc4context *parc4ctx, u8 *dest, u8 *src, u32 len)
{
u32 i;
+
for (i = 0; i < len; i++)
dest[i] = src[i] ^ (unsigned char)arcfour_byte(parc4ctx);
}
{
u8 *p;
u32 crc;
+
if (bcrc32initialized == 0)
crc32_init();
struct security_priv *psecuritypriv = &padapter->securitypriv;
- pframe = (unsigned char *)((struct recv_frame *)precvframe)->rx_data;
+ pframe = (unsigned char *)((struct recv_frame *)precvframe)->pkt->data;
/* start to decrypt recvframe */
if ((prxattrib->encrypt == _WEP40_) || (prxattrib->encrypt == _WEP104_)) {
keylength = psecuritypriv->dot11DefKeylen[keyindex];
memcpy(&wepkey[0], iv, 3);
memcpy(&wepkey[3], &psecuritypriv->dot11DefKey[keyindex].skey[0], keylength);
- length = ((struct recv_frame *)precvframe)->len-prxattrib->hdrlen-prxattrib->iv_len;
+ length = ((struct recv_frame *)precvframe)->pkt->len-prxattrib->hdrlen-prxattrib->iv_len;
payload = pframe+prxattrib->iv_len+prxattrib->hdrlen;
{
s32 i;
u32 res = 0;
+
for (i = 0; i < 4; i++)
res |= ((u32)(*p++)) << (8*i);
return res;
/* Convert from Us3232 to Byte[] in a portable way */
{
long i;
+
for (i = 0; i < 4; i++) {
*p++ = (u8)(val & 0xff);
val >>= 8;
{
struct mic_data micdata;
u8 priority[4] = {0x0, 0x0, 0x0, 0x0};
+
rtw_secmicsetkey(&micdata, key);
priority[0] = pri;
/* 2-unsigned char by 2-unsigned char subset of the full AES S-box table */
static const unsigned short Sbox1[2][256] = { /* Sbox for hash (can be in ROM) */
{
- 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
- 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
- 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
- 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B,
- 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F,
- 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F,
- 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5,
- 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F,
- 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB,
- 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397,
- 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED,
- 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A,
- 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194,
- 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3,
- 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104,
- 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D,
- 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39,
- 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695,
- 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83,
- 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76,
- 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4,
- 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B,
- 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0,
- 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018,
- 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751,
- 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85,
- 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12,
- 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9,
- 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7,
- 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A,
- 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8,
- 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A,
+ 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
+ 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
+ 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
+ 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B,
+ 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F,
+ 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F,
+ 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5,
+ 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F,
+ 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB,
+ 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397,
+ 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED,
+ 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A,
+ 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194,
+ 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3,
+ 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104,
+ 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D,
+ 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39,
+ 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695,
+ 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83,
+ 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76,
+ 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4,
+ 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B,
+ 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0,
+ 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018,
+ 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751,
+ 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85,
+ 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12,
+ 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9,
+ 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7,
+ 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A,
+ 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8,
+ 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A,
},
{ /* second half of table is unsigned char-reversed version of first! */
- 0xA5C6, 0x84F8, 0x99EE, 0x8DF6, 0x0DFF, 0xBDD6, 0xB1DE, 0x5491,
- 0x5060, 0x0302, 0xA9CE, 0x7D56, 0x19E7, 0x62B5, 0xE64D, 0x9AEC,
- 0x458F, 0x9D1F, 0x4089, 0x87FA, 0x15EF, 0xEBB2, 0xC98E, 0x0BFB,
- 0xEC41, 0x67B3, 0xFD5F, 0xEA45, 0xBF23, 0xF753, 0x96E4, 0x5B9B,
- 0xC275, 0x1CE1, 0xAE3D, 0x6A4C, 0x5A6C, 0x417E, 0x02F5, 0x4F83,
- 0x5C68, 0xF451, 0x34D1, 0x08F9, 0x93E2, 0x73AB, 0x5362, 0x3F2A,
- 0x0C08, 0x5295, 0x6546, 0x5E9D, 0x2830, 0xA137, 0x0F0A, 0xB52F,
- 0x090E, 0x3624, 0x9B1B, 0x3DDF, 0x26CD, 0x694E, 0xCD7F, 0x9FEA,
- 0x1B12, 0x9E1D, 0x7458, 0x2E34, 0x2D36, 0xB2DC, 0xEEB4, 0xFB5B,
- 0xF6A4, 0x4D76, 0x61B7, 0xCE7D, 0x7B52, 0x3EDD, 0x715E, 0x9713,
- 0xF5A6, 0x68B9, 0x0000, 0x2CC1, 0x6040, 0x1FE3, 0xC879, 0xEDB6,
- 0xBED4, 0x468D, 0xD967, 0x4B72, 0xDE94, 0xD498, 0xE8B0, 0x4A85,
- 0x6BBB, 0x2AC5, 0xE54F, 0x16ED, 0xC586, 0xD79A, 0x5566, 0x9411,
- 0xCF8A, 0x10E9, 0x0604, 0x81FE, 0xF0A0, 0x4478, 0xBA25, 0xE34B,
- 0xF3A2, 0xFE5D, 0xC080, 0x8A05, 0xAD3F, 0xBC21, 0x4870, 0x04F1,
- 0xDF63, 0xC177, 0x75AF, 0x6342, 0x3020, 0x1AE5, 0x0EFD, 0x6DBF,
- 0x4C81, 0x1418, 0x3526, 0x2FC3, 0xE1BE, 0xA235, 0xCC88, 0x392E,
- 0x5793, 0xF255, 0x82FC, 0x477A, 0xACC8, 0xE7BA, 0x2B32, 0x95E6,
- 0xA0C0, 0x9819, 0xD19E, 0x7FA3, 0x6644, 0x7E54, 0xAB3B, 0x830B,
- 0xCA8C, 0x29C7, 0xD36B, 0x3C28, 0x79A7, 0xE2BC, 0x1D16, 0x76AD,
- 0x3BDB, 0x5664, 0x4E74, 0x1E14, 0xDB92, 0x0A0C, 0x6C48, 0xE4B8,
- 0x5D9F, 0x6EBD, 0xEF43, 0xA6C4, 0xA839, 0xA431, 0x37D3, 0x8BF2,
- 0x32D5, 0x438B, 0x596E, 0xB7DA, 0x8C01, 0x64B1, 0xD29C, 0xE049,
- 0xB4D8, 0xFAAC, 0x07F3, 0x25CF, 0xAFCA, 0x8EF4, 0xE947, 0x1810,
- 0xD56F, 0x88F0, 0x6F4A, 0x725C, 0x2438, 0xF157, 0xC773, 0x5197,
- 0x23CB, 0x7CA1, 0x9CE8, 0x213E, 0xDD96, 0xDC61, 0x860D, 0x850F,
- 0x90E0, 0x427C, 0xC471, 0xAACC, 0xD890, 0x0506, 0x01F7, 0x121C,
- 0xA3C2, 0x5F6A, 0xF9AE, 0xD069, 0x9117, 0x5899, 0x273A, 0xB927,
- 0x38D9, 0x13EB, 0xB32B, 0x3322, 0xBBD2, 0x70A9, 0x8907, 0xA733,
- 0xB62D, 0x223C, 0x9215, 0x20C9, 0x4987, 0xFFAA, 0x7850, 0x7AA5,
- 0x8F03, 0xF859, 0x8009, 0x171A, 0xDA65, 0x31D7, 0xC684, 0xB8D0,
- 0xC382, 0xB029, 0x775A, 0x111E, 0xCB7B, 0xFCA8, 0xD66D, 0x3A2C,
+ 0xA5C6, 0x84F8, 0x99EE, 0x8DF6, 0x0DFF, 0xBDD6, 0xB1DE, 0x5491,
+ 0x5060, 0x0302, 0xA9CE, 0x7D56, 0x19E7, 0x62B5, 0xE64D, 0x9AEC,
+ 0x458F, 0x9D1F, 0x4089, 0x87FA, 0x15EF, 0xEBB2, 0xC98E, 0x0BFB,
+ 0xEC41, 0x67B3, 0xFD5F, 0xEA45, 0xBF23, 0xF753, 0x96E4, 0x5B9B,
+ 0xC275, 0x1CE1, 0xAE3D, 0x6A4C, 0x5A6C, 0x417E, 0x02F5, 0x4F83,
+ 0x5C68, 0xF451, 0x34D1, 0x08F9, 0x93E2, 0x73AB, 0x5362, 0x3F2A,
+ 0x0C08, 0x5295, 0x6546, 0x5E9D, 0x2830, 0xA137, 0x0F0A, 0xB52F,
+ 0x090E, 0x3624, 0x9B1B, 0x3DDF, 0x26CD, 0x694E, 0xCD7F, 0x9FEA,
+ 0x1B12, 0x9E1D, 0x7458, 0x2E34, 0x2D36, 0xB2DC, 0xEEB4, 0xFB5B,
+ 0xF6A4, 0x4D76, 0x61B7, 0xCE7D, 0x7B52, 0x3EDD, 0x715E, 0x9713,
+ 0xF5A6, 0x68B9, 0x0000, 0x2CC1, 0x6040, 0x1FE3, 0xC879, 0xEDB6,
+ 0xBED4, 0x468D, 0xD967, 0x4B72, 0xDE94, 0xD498, 0xE8B0, 0x4A85,
+ 0x6BBB, 0x2AC5, 0xE54F, 0x16ED, 0xC586, 0xD79A, 0x5566, 0x9411,
+ 0xCF8A, 0x10E9, 0x0604, 0x81FE, 0xF0A0, 0x4478, 0xBA25, 0xE34B,
+ 0xF3A2, 0xFE5D, 0xC080, 0x8A05, 0xAD3F, 0xBC21, 0x4870, 0x04F1,
+ 0xDF63, 0xC177, 0x75AF, 0x6342, 0x3020, 0x1AE5, 0x0EFD, 0x6DBF,
+ 0x4C81, 0x1418, 0x3526, 0x2FC3, 0xE1BE, 0xA235, 0xCC88, 0x392E,
+ 0x5793, 0xF255, 0x82FC, 0x477A, 0xACC8, 0xE7BA, 0x2B32, 0x95E6,
+ 0xA0C0, 0x9819, 0xD19E, 0x7FA3, 0x6644, 0x7E54, 0xAB3B, 0x830B,
+ 0xCA8C, 0x29C7, 0xD36B, 0x3C28, 0x79A7, 0xE2BC, 0x1D16, 0x76AD,
+ 0x3BDB, 0x5664, 0x4E74, 0x1E14, 0xDB92, 0x0A0C, 0x6C48, 0xE4B8,
+ 0x5D9F, 0x6EBD, 0xEF43, 0xA6C4, 0xA839, 0xA431, 0x37D3, 0x8BF2,
+ 0x32D5, 0x438B, 0x596E, 0xB7DA, 0x8C01, 0x64B1, 0xD29C, 0xE049,
+ 0xB4D8, 0xFAAC, 0x07F3, 0x25CF, 0xAFCA, 0x8EF4, 0xE947, 0x1810,
+ 0xD56F, 0x88F0, 0x6F4A, 0x725C, 0x2438, 0xF157, 0xC773, 0x5197,
+ 0x23CB, 0x7CA1, 0x9CE8, 0x213E, 0xDD96, 0xDC61, 0x860D, 0x850F,
+ 0x90E0, 0x427C, 0xC471, 0xAACC, 0xD890, 0x0506, 0x01F7, 0x121C,
+ 0xA3C2, 0x5F6A, 0xF9AE, 0xD069, 0x9117, 0x5899, 0x273A, 0xB927,
+ 0x38D9, 0x13EB, 0xB32B, 0x3322, 0xBBD2, 0x70A9, 0x8907, 0xA733,
+ 0xB62D, 0x223C, 0x9215, 0x20C9, 0x4987, 0xFFAA, 0x7850, 0x7AA5,
+ 0x8F03, 0xF859, 0x8009, 0x171A, 0xDA65, 0x31D7, 0xC684, 0xB8D0,
+ 0xC382, 0xB029, 0x775A, 0x111E, 0xCB7B, 0xFCA8, 0xD66D, 0x3A2C,
}
};
u32 res = _SUCCESS;
- pframe = (unsigned char *)((struct recv_frame *)precvframe)->rx_data;
+ pframe = (unsigned char *)((struct recv_frame *)precvframe)->pkt->data;
/* 4 start to decrypt recvframe */
if (prxattrib->encrypt == _TKIP_) {
iv = pframe+prxattrib->hdrlen;
payload = pframe+prxattrib->iv_len+prxattrib->hdrlen;
- length = ((struct recv_frame *)precvframe)->len-prxattrib->hdrlen-prxattrib->iv_len;
+ length = ((struct recv_frame *)precvframe)->pkt->len-prxattrib->hdrlen-prxattrib->iv_len;
GET_TKIP_PN(iv, dot11txpn);
static void xor_128(u8 *a, u8 *b, u8 *out)
{
int i;
+
for (i = 0; i < 16; i++)
out[i] = a[i] ^ b[i];
}
static void xor_32(u8 *a, u8 *b, u8 *out)
{
int i;
+
for (i = 0; i < 4; i++)
out[i] = a[i] ^ b[i];
}
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
0x1b, 0x36, 0x36, 0x36
};
+
sbox_key[0] = sbox(key[13]);
sbox_key[1] = sbox(key[14]);
sbox_key[2] = sbox(key[15]);
u8 rotr[4];
u8 temp[4];
u8 tempb[4];
+
for (i = 0 ; i < 4; i++) {
if ((in[i] & 0x80) == 0x80)
add1b[i] = 0x1b;
u8 intermediatea[16];
u8 intermediateb[16];
u8 round_key[16];
+
for (i = 0; i < 16; i++)
round_key[i] = key[i];
for (round = 0; round < 11; round++) {
uint payload_length, u8 *pn_vector)
{
int i;
+
mic_iv[0] = 0x59;
if (qc_exists && a4_exists)
mic_iv[1] = mpdu[30] & 0x0f; /* QoS_TC */
static void construct_mic_header2(u8 *mic_header2, u8 *mpdu, int a4_exists, int qc_exists)
{
int i;
+
for (i = 0; i < 16; i++)
mic_header2[i] = 0x00;
static void construct_ctr_preload(u8 *ctr_preload, int a4_exists, int qc_exists, u8 *mpdu, u8 *pn_vector, int c)
{
int i;
+
for (i = 0; i < 16; i++)
ctr_preload[i] = 0x00;
i = 0;
static void bitwise_xor(u8 *ina, u8 *inb, u8 *out)
{
int i;
+
for (i = 0; i < 16; i++)
out[i] = ina[i] ^ inb[i];
}
uint qc_exists, a4_exists, i, j, payload_remainder,
num_blocks, payload_index;
int res = _SUCCESS;
+
u8 pn_vector[6];
u8 mic_iv[16];
u8 mic_header1[16];
struct rx_pkt_attrib *prxattrib = &((struct recv_frame *)precvframe)->attrib;
struct security_priv *psecuritypriv = &padapter->securitypriv;
u32 res = _SUCCESS;
- pframe = (unsigned char *)((struct recv_frame *)precvframe)->rx_data;
+
+ pframe = (unsigned char *)((struct recv_frame *)precvframe)->pkt->data;
/* 4 start to encrypt each fragment */
if (prxattrib->encrypt == _AES_) {
stainfo = rtw_get_stainfo(&padapter->stapriv, &prxattrib->ta[0]);
} else {
prwskey = &stainfo->dot118021x_UncstKey.skey[0];
}
- length = ((struct recv_frame *)precvframe)->len-prxattrib->hdrlen-prxattrib->iv_len;
+ length = ((struct recv_frame *)precvframe)->pkt->len-prxattrib->hdrlen-prxattrib->iv_len;
res = aes_decipher(prwskey, prxattrib->hdrlen, pframe, length);
} else {
RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_aes_encrypt: stainfo==NULL!!!\n"));
while (phead != plist) {
int i;
+
psta = container_of(plist, struct sta_info,
hash_list);
plist = plist->next;
u16 get_beacon_interval(struct wlan_bssid_ex *bss)
{
__le16 val;
+
memcpy((unsigned char *)&val, rtw_get_beacon_interval_from_ie(bss->IEs), 2);
return le16_to_cpu(val);
void update_tx_basic_rate(struct adapter *padapter, u8 wirelessmode)
{
unsigned char supported_rates[NDIS_802_11_LENGTH_RATES_EX];
+
memset(supported_rates, 0, NDIS_802_11_LENGTH_RATES_EX);
if ((wirelessmode & WIRELESS_11B) && (wirelessmode == WIRELESS_11B))
struct ndis_802_11_var_ie *pIE;
u8 epigram_vendor_flag;
u8 ralink_vendor_flag;
+
epigram_vendor_flag = 0;
ralink_vendor_flag = 0;
pxmitbuf++;
}
- if (pxmitpriv->pallocated_xmit_extbuf)
- vfree(pxmitpriv->pallocated_xmit_extbuf);
+ vfree(pxmitpriv->pallocated_xmit_extbuf);
rtw_free_hwxmits(padapter);
/* check HT op mode */
if (pattrib->ht_en) {
u8 htopmode = pmlmeinfo->HT_protection;
+
if ((pmlmeext->cur_bwmode && (htopmode == 2 || htopmode == 3)) ||
(!pmlmeext->cur_bwmode && htopmode == 3)) {
pattrib->vcs_mode = RTS_CTS;
/* The following is for DHCP and ARP packet, we use cck1M to tx these packets and let LPS awake some time */
/* to prevent DHCP protocol fail */
u8 tmp[24];
+
_rtw_pktfile_read(&pktfile, &tmp[0], 24);
pattrib->dhcp_pkt = 0;
if (pktfile.pkt_len > 282) {/* MINIMUM_DHCP_PACKET_SIZE) { */
pattrib->encrypt = 0;
- if ((pattrib->ether_type != ETH_P_PAE) && !check_fwstate(pmlmepriv, WIFI_MP_STATE)) {
+ if (pattrib->ether_type != ETH_P_PAE) {
RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("\npsta->ieee8021x_blocked == true, pattrib->ether_type(%.4x) != ETH_P_PAE\n", pattrib->ether_type));
res = _FAIL;
goto exit;
void rtw_init_hwxmits(struct hw_xmit *phwxmit, int entry)
{
int i;
+
for (i = 0; i < entry; i++, phwxmit++)
phwxmit->accnt = 0;
}
power_level_offset[11] = data;
if (regaddr == rTxAGC_B_Mcs11_Mcs08)
power_level_offset[12] = data;
- if (regaddr == rTxAGC_B_Mcs15_Mcs12) {
+ if (regaddr == rTxAGC_B_Mcs15_Mcs12)
power_level_offset[13] = data;
- }
}
static void rtl_addr_delay(struct adapter *adapt,
pkt_info.bPacketToSelf = false;
pkt_info.bPacketBeacon = false;
- wlanhdr = precvframe->rx_data;
+ wlanhdr = precvframe->pkt->data;
pkt_info.bPacketMatchBSSID = ((!IsFrameTypeCtrl(wlanhdr)) &&
!pattrib->icv_err && !pattrib->crc_err &&
if (res == _SUCCESS) {
rtw_dump_xframe(adapt, pxmitframe);
} else {
- DBG_88E("==> %s xmitframe_coalsece failed\n", __func__);
+ DBG_88E("==> %s xmitframe_coalesce failed\n", __func__);
rtw_free_xmitbuf(pxmitpriv, pxmitbuf);
rtw_free_xmitframe(pxmitpriv, pxmitframe);
}
u8 bFWReady;
u8 bReadPortCancel;
u8 bWritePortCancel;
- u8 bRxRSSIDisplay;
struct mutex hw_init_mutex;
};
netif_tx_queue_stopped(netdev_get_tx_queue(pnetdev, 3));
}
-int RTW_STATUS_CODE(int error_code);
-
-#define rtw_update_mem_stat(flag, sz) do {} while (0)
u8 *_rtw_malloc(u32 sz);
#define rtw_malloc(sz) _rtw_malloc((sz))
(((struct rtw_netdev_priv_indicator *)netdev_priv(netdev))->priv)
void rtw_free_netdev(struct net_device *netdev);
-#define NDEV_FMT "%s"
-#define NDEV_ARG(ndev) ndev->name
-#define ADPT_FMT "%s"
-#define ADPT_ARG(adapter) adapter->pnetdev->name
#define FUNC_NDEV_FMT "%s(%s)"
#define FUNC_NDEV_ARG(ndev) __func__, ndev->name
#define FUNC_ADPT_FMT "%s(%s)"
#define DBG_88E_LEVEL(_level, fmt, arg...) \
do { \
if (_level <= GlobalDebugLevel) \
- pr_info(DRIVER_PREFIX"ERROR " fmt, ##arg); \
+ pr_info(DRIVER_PREFIX fmt, ##arg); \
} while (0)
#define DBG_88E(...) \
#define WIFI_STA_ALIVE_CHK_STATE 0x00000400
#define WIFI_SITE_MONITOR 0x00000800 /* to indicate the station is under site surveying */
-#define WIFI_MP_STATE 0x00010000
-#define WIFI_MP_CTX_BACKGROUND 0x00020000 /* in continuous tx background */
-#define WIFI_MP_CTX_ST 0x00040000 /* in continuous tx with single-tone */
-#define WIFI_MP_CTX_BACKGROUND_PENDING 0x00080000 /* pending in continuous tx background due to out of skb */
-#define WIFI_MP_CTX_CCK_HW 0x00100000 /* in continuous tx */
-#define WIFI_MP_CTX_CCK_CS 0x00200000 /* in continuous tx with carrier suppression */
-#define WIFI_MP_LPBK_STATE 0x00400000
-
#define _FW_UNDER_LINKING WIFI_UNDER_LINKING
#define _FW_LINKED WIFI_ASOC_STATE
#define _FW_UNDER_SURVEY WIFI_SITE_MONITOR
* to Tx traffic. */
};
-struct profile_info {
- u8 ssidlen;
- u8 ssid[WLAN_SSID_MAXLEN];
- u8 peermac[ETH_ALEN];
-};
-
-struct tx_invite_req_info {
- u8 token;
- u8 benable;
- u8 go_ssid[WLAN_SSID_MAXLEN];
- u8 ssidlen;
- u8 go_bssid[ETH_ALEN];
- u8 peer_macaddr[ETH_ALEN];
- u8 operating_ch; /* This information will be set by using the
- * p2p_set op_ch=x */
- u8 peer_ch; /* The listen channel for peer P2P device */
-};
-
-struct tx_invite_resp_info {
- u8 token; /* Used to record the dialog token of p2p invitation
- * request frame. */
-};
-
-struct tx_provdisc_req_info {
- u16 wps_config_method_request; /* Used when sending the
- * provisioning request frame*/
- u16 peer_channel_num[2]; /* The channel number which the
- * receiver stands. */
- struct ndis_802_11_ssid ssid;
- u8 peerDevAddr[ETH_ALEN]; /* Peer device address */
- u8 peerIFAddr[ETH_ALEN]; /* Peer interface address */
- u8 benable; /* This provision discovery
- * request frame is trigger
- * to send or not */
-};
-
-/* When peer device issue prov_disc_req first, we should store the following
- * information */
-/* The UI must know this information to know which config method the
- * remote p2p device needs. */
-struct rx_provdisc_req_info {
- u8 peerDevAddr[ETH_ALEN]; /* Peer device address */
- u8 strconfig_method_desc_of_prov_disc_req[4]; /* description
- * for the config method located in the provisioning
- * discovery request frame. */
-};
-
-struct tx_nego_req_info {
- u16 peer_channel_num[2]; /* The channel number. */
- u8 peerDevAddr[ETH_ALEN]; /* Peer device address */
- u8 benable; /* This negotiation request frame is
- * trigger to send or not */
-};
-
-struct group_id_info {
- u8 go_device_addr[ETH_ALEN]; /* The GO's device address of
- * this P2P group */
- u8 ssid[WLAN_SSID_MAXLEN]; /* The SSID of this P2P group */
-};
-
-struct scan_limit_info {
- u8 scan_op_ch_only; /* When this flag is set, the driver
- * should only scan the op. channel */
- u8 operation_ch[2]; /* Store the op. chan of invitation */
-};
-
-struct wifidirect_info {
- struct adapter *padapter;
- struct timer_list find_phase_timer;
- struct timer_list restore_p2p_state_timer;
-
- /* Used to do the scanning. After confirming the peer is availalble,
- * the driver transmits the P2P frame to peer. */
- struct timer_list pre_tx_scan_timer;
- struct timer_list reset_ch_sitesurvey;
- struct timer_list reset_ch_sitesurvey2; /* Just for resetting the scan
- * limit function by using p2p nego */
- struct tx_provdisc_req_info tx_prov_disc_info;
- struct rx_provdisc_req_info rx_prov_disc_info;
- struct tx_invite_req_info invitereq_info;
- /* Store the profile information of persistent group */
- struct profile_info profileinfo[P2P_MAX_PERSISTENT_GROUP_NUM];
- struct tx_invite_resp_info inviteresp_info;
- struct tx_nego_req_info nego_req_info;
- /* Store the group id info when doing the group negot handshake. */
- struct group_id_info groupid_info;
- /* Used for get the limit scan channel from the Invitation procedure */
- struct scan_limit_info rx_invitereq_info;
- /* Used for get the limit scan chan from the P2P negotiation handshake*/
- struct scan_limit_info p2p_info;
- enum P2P_ROLE role;
- enum P2P_STATE pre_p2p_state;
- enum P2P_STATE p2p_state;
- /* The device address should be the mac address of this device. */
- u8 device_addr[ETH_ALEN];
- u8 interface_addr[ETH_ALEN];
- u8 social_chan[4];
- u8 listen_channel;
- u8 operating_channel;
- u8 listen_dwell; /* This value should be between 1 and 3 */
- u8 support_rate[8];
- u8 p2p_wildcard_ssid[P2P_WILDCARD_SSID_LEN];
- u8 intent; /* should only include the intent value. */
- u8 p2p_peer_interface_addr[ETH_ALEN];
- u8 p2p_peer_device_addr[ETH_ALEN];
- u8 peer_intent; /* Included the intent value and tie breaker value. */
- /* Device name for displaying on searching device screen */
- u8 device_name[WPS_MAX_DEVICE_NAME_LEN];
- u8 device_name_len;
- u8 profileindex; /* Used to point to the index of profileinfo array */
- u8 peer_operating_ch;
- u8 find_phase_state_exchange_cnt;
- /* The device password ID for group negotiation */
- u16 device_password_id_for_nego;
- u8 negotiation_dialog_token;
- /* SSID information for group negotitation */
- u8 nego_ssid[WLAN_SSID_MAXLEN];
- u8 nego_ssidlen;
- u8 p2p_group_ssid[WLAN_SSID_MAXLEN];
- u8 p2p_group_ssid_len;
- /* Flag to know if the persistent function should be supported or not.*/
- u8 persistent_supported;
- /* In the Sigma test, the Sigma will provide this enable from the
- * sta_set_p2p CAPI. */
- /* 0: disable */
- /* 1: enable */
- u8 session_available; /* Flag to set the WFD session available to
- * enable or disable "by Sigma" */
- /* In the Sigma test, the Sigma will disable the session available
- * by using the sta_preset CAPI. */
- /* 0: disable */
- /* 1: enable */
- u8 wfd_tdls_enable; /* Flag to enable or disable the TDLS by WFD Sigma*/
- /* 0: disable */
- /* 1: enable */
- u8 wfd_tdls_weaksec; /* Flag to enable or disable the weak security
- * function for TDLS by WFD Sigma */
- /* 0: disable */
- /* In this case, the driver can't issue the tdsl
- * setup request frame. */
- /* 1: enable */
- /* In this case, the driver can issue the tdls
- * setup request frame */
- /* even the current security is weak security. */
-
- /* This field will store the WPS value (PIN value or PBC) that UI had
- * got from the user. */
- enum P2P_WPSINFO ui_got_wps_info;
- u16 supported_wps_cm; /* This field describes the WPS config method
- * which this driver supported. */
- /* The value should be the combination of config
- * method defined in page104 of WPS v2.0 spec.*/
- /* This field will contain the length of body of P2P Channel List
- * attribute of group negotiation response frame. */
- uint channel_list_attr_len;
- /* This field will contain the body of P2P Channel List attribute of
- * group negotitation response frame. */
- /* We will use the channel_cnt and channel_list fields when constructing
- * the group negotiation confirm frame. */
- u8 channel_list_attr[100];
- enum P2P_PS_MODE p2p_ps_mode; /* indicate p2p ps mode */
- enum P2P_PS_STATE p2p_ps_state; /* indicate p2p ps state */
- u8 noa_index; /* Identifies and instance of Notice of Absence timing. */
- u8 ctwindow; /* Client traffic window. A period of time in TU after TBTT. */
- u8 opp_ps; /* opportunistic power save. */
- u8 noa_num; /* number of NoA descriptor in P2P IE. */
- u8 noa_count[P2P_MAX_NOA_NUM]; /* Count for owner, Type of client. */
- /* Max duration for owner, preferred or min acceptable duration for
- * client. */
- u32 noa_duration[P2P_MAX_NOA_NUM];
- /* Length of interval for owner, preferred or max acceptable interval
- * of client. */
- u32 noa_interval[P2P_MAX_NOA_NUM];
- /* schedule expressed in terms of the lower 4 bytes of the TSF timer. */
- u32 noa_start_time[P2P_MAX_NOA_NUM];
-};
-
struct mlme_priv {
spinlock_t lock;
int fw_state; /* shall we protect this variable? maybe not necessarily... */
__le32 rxdw5;
};
-#define EOR BIT(30)
-
/*
accesser of recv_priv: rtw_recv_entry(dispatch / passive level);
recv_thread(passive) ; returnpkt(dispatch)
struct recv_buf *precv_buf; /* 4 alignment */
struct __queue free_recv_buf_queue;
/* For display the phy informatiom */
- u8 is_signal_dbg; /* for debug */
- u8 signal_strength_dbg; /* for debug */
s8 rssi;
s8 rxpwdb;
u8 signal_strength;
struct sk_buff *pkt;
struct adapter *adapter;
struct rx_pkt_attrib attrib;
- uint len;
- u8 *rx_head;
- u8 *rx_data;
- u8 *rx_tail;
- u8 *rx_end;
struct sta_info *psta;
/* for A-MPDU Rx reordering buffer control */
struct recv_reorder_ctrl *preorder_ctrl;
void rtw_reordering_ctrl_timeout_handler(unsigned long data);
-static inline u8 *get_rxmem(struct recv_frame *precvframe)
-{
- /* always return rx_head... */
- if (precvframe == NULL)
- return NULL;
- return precvframe->rx_head;
-}
-
-static inline u8 *recvframe_pull(struct recv_frame *precvframe, int sz)
-{
- /* rx_data += sz; move rx_data sz bytes hereafter */
-
- /* used for extract sz bytes from rx_data, update rx_data and return
- * the updated rx_data to the caller */
-
- if (precvframe == NULL)
- return NULL;
- precvframe->rx_data += sz;
- if (precvframe->rx_data > precvframe->rx_tail) {
- precvframe->rx_data -= sz;
- return NULL;
- }
- precvframe->len -= sz;
- return precvframe->rx_data;
-}
-
-static inline u8 *recvframe_put(struct recv_frame *precvframe, int sz)
-{
- /* used for append sz bytes from ptr to rx_tail, update rx_tail
- * and return the updated rx_tail to the caller */
- /* after putting, rx_tail must be still larger than rx_end. */
-
- if (precvframe == NULL)
- return NULL;
-
- precvframe->rx_tail += sz;
-
- if (precvframe->rx_tail > precvframe->rx_end) {
- precvframe->rx_tail -= sz;
- return NULL;
- }
- precvframe->len += sz;
- return precvframe->rx_tail;
-}
-
-static inline u8 *recvframe_pull_tail(struct recv_frame *precvframe, int sz)
-{
- /* rmv data from rx_tail (by yitsen) */
-
- /* used for extract sz bytes from rx_end, update rx_end and return
- * the updated rx_end to the caller */
- /* after pulling, rx_end must be still larger than rx_data. */
-
- if (precvframe == NULL)
- return NULL;
- precvframe->rx_tail -= sz;
- if (precvframe->rx_tail < precvframe->rx_data) {
- precvframe->rx_tail += sz;
- return NULL;
- }
- precvframe->len -= sz;
- return precvframe->rx_tail;
-}
-
static inline s32 translate_percentage_to_dbm(u32 sig_stren_index)
{
s32 power; /* in dBm. */
#define TE2(i) rotr(Te0[((i) >> 8) & 0xff], 16)
#define TE3(i) rotr(Te0[(i) & 0xff], 24)
-#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ \
- ((u32)(pt)[2] << 8) ^ ((u32)(pt)[3]))
-
-#define PUTU32(ct, st) { \
-(ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); \
-(ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); }
-
-#define WPA_GET_BE32(a) ((((u32)(a)[0]) << 24) | (((u32)(a)[1]) << 16) | \
- (((u32)(a)[2]) << 8) | ((u32)(a)[3]))
-
-#define WPA_PUT_LE16(a, val) \
- do { \
- (a)[1] = ((u16)(val)) >> 8; \
- (a)[0] = ((u16)(val)) & 0xff; \
- } while (0)
-
-#define WPA_PUT_BE32(a, val) \
- do { \
- (a)[0] = (u8)((((u32)(val)) >> 24) & 0xff); \
- (a)[1] = (u8)((((u32)(val)) >> 16) & 0xff); \
- (a)[2] = (u8)((((u32)(val)) >> 8) & 0xff); \
- (a)[3] = (u8)(((u32)(val)) & 0xff); \
- } while (0)
-
-#define WPA_PUT_BE64(a, val) \
- do { \
- (a)[0] = (u8)(((u64)(val)) >> 56); \
- (a)[1] = (u8)(((u64)(val)) >> 48); \
- (a)[2] = (u8)(((u64)(val)) >> 40); \
- (a)[3] = (u8)(((u64)(val)) >> 32); \
- (a)[4] = (u8)(((u64)(val)) >> 24); \
- (a)[5] = (u8)(((u64)(val)) >> 16); \
- (a)[6] = (u8)(((u64)(val)) >> 8); \
- (a)[7] = (u8)(((u64)(val)) & 0xff); \
- } while (0)
-
/* ===== start - public domain SHA256 implementation ===== */
/* This is based on SHA256 implementation in LibTomCrypt that was released into
#define WLAN_HDR_A4_LEN 30
#define WLAN_HDR_A3_QOS_LEN 26
#define WLAN_HDR_A4_QOS_LEN 32
-#define WLAN_SSID_MAXLEN 32
#define WLAN_DATA_MAXLEN 2312
#define WLAN_A3_PN_OFFSET 24
Below is the definition for 802.11n
------------------------------------------------------------------------------*/
-#define SetOrderBit(pbuf) \
- do { \
- *(unsigned short *)(pbuf) |= cpu_to_le16(_ORDER_); \
- } while (0)
-
-#define GetOrderBit(pbuf) \
- (((*(unsigned short *)(pbuf)) & le16_to_cpu(_ORDER_)) != 0)
-
-
-/**
- * struct rtw_ieee80211_bar - HT Block Ack Request
- *
- * This structure refers to "HT BlockAckReq" as
- * described in 802.11n draft section 7.2.1.7.1
- */
-struct rtw_ieee80211_bar {
- unsigned short frame_control;
- unsigned short duration;
- unsigned char ra[6];
- unsigned char ta[6];
- unsigned short control;
- unsigned short start_seq_num;
-} __packed;
-
/* 802.11 BAR control masks */
#define IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL 0x0000
#define IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA 0x0004
#define WPS_ATTR_VENDOR_EXT 0x1049
#define WPS_ATTR_SELECTED_REGISTRAR 0x1041
-/* Value of WPS attribute "WPS_ATTR_DEVICE_NAME */
-#define WPS_MAX_DEVICE_NAME_LEN 32
-
/* Value of WPS Request Type Attribute */
#define WPS_REQ_TYPE_ENROLLEE_INFO_ONLY 0x00
#define WPS_REQ_TYPE_ENROLLEE_OPEN_8021X 0x01
#define P2P_STATUS_FAIL_USER_REJECT 0x0B
/* Value of Invitation Flags Attribute */
-#define P2P_INVITATION_FLAGS_PERSISTENT BIT(0)
-
-#define DMP_P2P_DEVCAP_SUPPORT (P2P_DEVCAP_SERVICE_DISCOVERY | \
- P2P_DEVCAP_CLIENT_DISCOVERABILITY | \
- P2P_DEVCAP_CONCURRENT_OPERATION | \
- P2P_DEVCAP_INVITATION_PROC)
-
-#define DMP_P2P_GRPCAP_SUPPORT (P2P_GRPCAP_INTRABSS)
/* Value of Device Capability Bitmap */
#define P2P_DEVCAP_SERVICE_DISCOVERY BIT(0)
#define P2P_PRESENCE_RESPONSE 2
#define P2P_GO_DISC_REQUEST 3
-
-#define P2P_MAX_PERSISTENT_GROUP_NUM 10
-
#define P2P_PROVISIONING_SCAN_CNT 3
-#define P2P_WILDCARD_SSID_LEN 7
-
/* default value, used when: (1)p2p disabled or (2)p2p enabled
* but only do 1 scan phase */
#define P2P_FINDPHASE_EX_NONE 0
#define P2P_RESET_SCAN_CH 25000
#define P2P_MAX_INTENT 15
-#define P2P_MAX_NOA_NUM 2
-
/* WPS Configuration Method */
#define WPS_CM_NONE 0x0000
#define WPS_CM_LABEL 0x0004
#define WPS_CM_SW_DISPLAY_P 0x2008
#define WPS_CM_LCD_DISPLAY_P 0x4008
-enum P2P_ROLE {
- P2P_ROLE_DISABLE = 0,
- P2P_ROLE_DEVICE = 1,
- P2P_ROLE_CLIENT = 2,
- P2P_ROLE_GO = 3
-};
-
-enum P2P_STATE {
- P2P_STATE_NONE = 0, /* P2P disable */
- /* P2P had enabled and do nothing */
- P2P_STATE_IDLE = 1,
- P2P_STATE_LISTEN = 2, /* In pure listen state */
- P2P_STATE_SCAN = 3, /* In scan phase */
- /* In the listen state of find phase */
- P2P_STATE_FIND_PHASE_LISTEN = 4,
- /* In the search state of find phase */
- P2P_STATE_FIND_PHASE_SEARCH = 5,
- /* In P2P provisioning discovery */
- P2P_STATE_TX_PROVISION_DIS_REQ = 6,
- P2P_STATE_RX_PROVISION_DIS_RSP = 7,
- P2P_STATE_RX_PROVISION_DIS_REQ = 8,
- /* Doing the group owner negotiation handshake */
- P2P_STATE_GONEGO_ING = 9,
- /* finish the group negotiation handshake with success */
- P2P_STATE_GONEGO_OK = 10,
- /* finish the group negotiation handshake with failure */
- P2P_STATE_GONEGO_FAIL = 11,
- /* receiving the P2P Invitation request and match with the profile. */
- P2P_STATE_RECV_INVITE_REQ_MATCH = 12,
- /* Doing the P2P WPS */
- P2P_STATE_PROVISIONING_ING = 13,
- /* Finish the P2P WPS */
- P2P_STATE_PROVISIONING_DONE = 14,
- /* Transmit the P2P Invitation request */
- P2P_STATE_TX_INVITE_REQ = 15,
- /* Receiving the P2P Invitation response */
- P2P_STATE_RX_INVITE_RESP_OK = 16,
- /* receiving the P2P Invitation request and dismatch with the profile. */
- P2P_STATE_RECV_INVITE_REQ_DISMATCH = 17,
- /* receiving the P2P Invitation request and this wifi is GO. */
- P2P_STATE_RECV_INVITE_REQ_GO = 18,
- /* receiving the P2P Invitation request to join an existing P2P Group. */
- P2P_STATE_RECV_INVITE_REQ_JOIN = 19,
- /* receiving the P2P Invitation response with failure */
- P2P_STATE_RX_INVITE_RESP_FAIL = 20,
- /* receiving p2p negotiation response with information is not available */
- P2P_STATE_RX_INFOR_NOREADY = 21,
- /* sending p2p negotiation response with information is not available */
- P2P_STATE_TX_INFOR_NOREADY = 22,
-};
-
-enum P2P_WPSINFO {
- P2P_NO_WPSINFO = 0,
- P2P_GOT_WPSINFO_PEER_DISPLAY_PIN = 1,
- P2P_GOT_WPSINFO_SELF_DISPLAY_PIN = 2,
- P2P_GOT_WPSINFO_PBC = 3,
-};
-
#define P2P_PRIVATE_IOCTL_SET_LEN 64
enum P2P_PROTO_WK_ID {
P2P_RO_CH_WK = 6,
};
-enum P2P_PS_STATE {
- P2P_PS_DISABLE = 0,
- P2P_PS_ENABLE = 1,
- P2P_PS_SCAN = 2,
- P2P_PS_SCAN_DONE = 3,
- P2P_PS_ALLSTASLEEP = 4, /* for P2P GO */
-};
-
-enum P2P_PS_MODE {
- P2P_PS_NONE = 0,
- P2P_PS_CTWINDOW = 1,
- P2P_PS_NOA = 2,
- P2P_PS_MIX = 3, /* CTWindow and NoA */
-};
-
/* =====================WFD Section===================== */
/* For Wi-Fi Display */
#define WFD_ATTR_DEVICE_INFO 0x00
if (p && ht_ielen > 0) {
struct ieee80211_ht_cap *pht_capie;
ht_cap = true;
+
pht_capie = (struct ieee80211_ht_cap *)(p + 2);
memcpy(&mcs_rate, pht_capie->mcs.rx_mask, 2);
bw_40MHz = !!(le16_to_cpu(pht_capie->cap_info) &
uint cnt = 0, total_ielen;
u8 *wpsie_ptr = NULL;
uint wps_ielen = 0;
-
u8 *ie_ptr = pnetwork->network.IEs + _FIXED_IE_LENGTH_;
+
total_ielen = pnetwork->network.IELength - _FIXED_IE_LENGTH_;
while (cnt < total_ielen) {
struct sta_info *psta, *pbcmc_sta;
struct sta_priv *pstapriv = &padapter->stapriv;
- if (check_fwstate(pmlmepriv, WIFI_STATION_STATE | WIFI_MP_STATE)) { /* sta mode */
+ if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) { /* sta mode */
psta = rtw_get_stainfo(pstapriv, get_bssid(pmlmepriv));
if (!psta) {
;
/* dump */
{
int i;
+
DBG_88E("\n wpa_ie(length:%d):\n", ielen);
for (i = 0; i < ielen; i += 8)
DBG_88E("0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x\n", buf[i], buf[i+1], buf[i+2], buf[i+3], buf[i+4], buf[i+5], buf[i+6], buf[i+7]);
struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
struct ndis_802_11_ssid ssid[RTW_SSID_SCAN_AMOUNT];
+
RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_set_scan\n"));
- if (padapter->registrypriv.mp_mode == 1) {
- if (check_fwstate(pmlmepriv, WIFI_MP_STATE)) {
- ret = -1;
- goto exit;
- }
- }
if (_FAIL == rtw_pwr_wakeup(padapter)) {
ret = -1;
goto exit;
u32 cnt = 0;
u32 wait_for_surveydone;
int wait_status;
+
RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_wx_get_scan\n"));
RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_, (" Start of Query SIOCGIWSCAN .\n"));
struct iw_point *erq = &(wrqu->encoding);
struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev);
struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+
DBG_88E("+rtw_wx_set_enc, flags = 0x%x\n", erq->flags);
memset(&wep, 0, sizeof(struct ndis_802_11_wep));
return;
attr = &frame->attrib;
- data = frame->rx_data;
- data_len = frame->len;
+ data = frame->pkt->data;
+ data_len = frame->pkt->len;
/* Broadcast and multicast frames don't have attr->{iv,icv}_len set */
SET_ICE_IV_LEN(iv_len, icv_len, attr->encrypt);
/* misc. */
padapter->bReadPortCancel = false;
padapter->bWritePortCancel = false;
- padapter->bRxRSSIDisplay = 0;
return _SUCCESS;
}
rtw_hal_def_value_init(padapter);
padapter->bReadPortCancel = false;
padapter->bWritePortCancel = false;
- padapter->bRxRSSIDisplay = 0;
pmlmepriv->scan_interval = SCAN_INTERVAL;/* 30*2 sec = 60sec */
padapter->xmitpriv.tx_pkts = 0;
#include <linux/vmalloc.h>
#include <rtw_ioctl_set.h>
-/*
- * Translate the OS dependent @param error_code to OS independent
- * RTW_STATUS_CODE
- * @return: one of RTW_STATUS_CODE
- */
-inline int RTW_STATUS_CODE(int error_code)
-{
- if (error_code >= 0)
- return _SUCCESS;
- return _FAIL;
-}
-
u8 *_rtw_malloc(u32 sz)
{
return kmalloc(sz, in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
void *rtw_malloc2d(int h, int w, int size)
{
int j;
-
void **a = kzalloc(h * sizeof(void *) + h * w * size, GFP_KERNEL);
+
if (!a)
goto out;
goto _recv_indicatepkt_drop;
}
- RT_TRACE(_module_recv_osdep_c_, _drv_info_,
- ("rtw_recv_indicatepkt():skb != NULL !!!\n"));
- RT_TRACE(_module_recv_osdep_c_, _drv_info_,
- ("rtw_recv_indicatepkt():precv_frame->rx_head =%p precv_frame->hdr.rx_data =%p\n",
- precv_frame->rx_head, precv_frame->rx_data));
- RT_TRACE(_module_recv_osdep_c_, _drv_info_,
- ("precv_frame->hdr.rx_tail =%p precv_frame->rx_end =%p precv_frame->hdr.len =%d\n",
- precv_frame->rx_tail, precv_frame->rx_end,
- precv_frame->len));
-
- skb->data = precv_frame->rx_data;
-
- skb_set_tail_pointer(skb, precv_frame->len);
-
- skb->len = precv_frame->len;
-
- RT_TRACE(_module_recv_osdep_c_, _drv_info_,
- ("skb->head =%p skb->data =%p skb->tail =%p skb->end =%p skb->len =%d\n",
- skb->head, skb->data, skb_tail_pointer(skb),
- skb_end_pointer(skb), skb->len));
-
if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
struct sk_buff *pskb2 = NULL;
struct sta_info *psta = NULL;
int rtw_android_cmdstr_to_num(char *cmdstr)
{
int cmd_num;
+
for (cmd_num = 0; cmd_num < ANDROID_WIFI_CMD_MAX; cmd_num++)
if (0 == strncasecmp(cmdstr, android_wifi_cmd_str[cmd_num],
strlen(android_wifi_cmd_str[cmd_num])))
for (i = 0; i < piface_desc->bNumEndpoints; i++) {
int ep_num;
+
pendp_desc = &phost_iface->endpoint[i].desc;
ep_num = usb_endpoint_num(pendp_desc);
}
INIT_LIST_HEAD(&precvframe->list);
- precvframe->len = 0;
update_recvframe_attrib_88e(precvframe, prxstat);
if (pkt_copy) {
pkt_copy->dev = adapt->pnetdev;
precvframe->pkt = pkt_copy;
- precvframe->rx_head = pkt_copy->data;
- precvframe->rx_end = pkt_copy->data + alloc_sz;
skb_reserve(pkt_copy, 8 - ((size_t)(pkt_copy->data) & 7));/* force pkt_copy->data at 8-byte alignment address */
skb_reserve(pkt_copy, shift_sz);/* force ip_hdr at 8-byte alignment address according to shift_sz. */
memcpy(pkt_copy->data, (pbuf + pattrib->drvinfo_sz + RXDESC_SIZE), skb_len);
- precvframe->rx_tail = pkt_copy->data;
- precvframe->rx_data = pkt_copy->data;
+ skb_put(precvframe->pkt, skb_len);
} else {
- if ((pattrib->mfrag == 1) && (pattrib->frag_num == 0)) {
- DBG_88E("recvbuf2recvframe: alloc_skb fail , drop frag frame\n");
- rtw_free_recvframe(precvframe, pfree_recv_queue);
- goto _exit_recvbuf2recvframe;
- }
- precvframe->pkt = skb_clone(pskb, GFP_ATOMIC);
- if (precvframe->pkt) {
- precvframe->rx_tail = pbuf + pattrib->drvinfo_sz + RXDESC_SIZE;
- precvframe->rx_head = precvframe->rx_tail;
- precvframe->rx_data = precvframe->rx_tail;
- precvframe->rx_end = pbuf + pattrib->drvinfo_sz + RXDESC_SIZE + alloc_sz;
- } else {
- DBG_88E("recvbuf2recvframe: skb_clone fail\n");
- rtw_free_recvframe(precvframe, pfree_recv_queue);
- goto _exit_recvbuf2recvframe;
- }
+ DBG_88E("recvbuf2recvframe: alloc_skb fail , drop frag frame\n");
+ rtw_free_recvframe(precvframe, pfree_recv_queue);
+ goto _exit_recvbuf2recvframe;
}
- recvframe_put(precvframe, skb_len);
-
switch (haldata->UsbRxAggMode) {
case USB_RX_AGG_DMA:
case USB_RX_AGG_MIX:
}
} else if (pattrib->pkt_rpt_type == TX_REPORT1) {
/* CCX-TXRPT ack for xmit mgmt frames. */
- handle_txrpt_ccx_88e(adapt, precvframe->rx_data);
+ handle_txrpt_ccx_88e(adapt, precvframe->pkt->data);
rtw_free_recvframe(precvframe, pfree_recv_queue);
} else if (pattrib->pkt_rpt_type == TX_REPORT2) {
ODM_RA_TxRPT2Handle_8188E(
&haldata->odmpriv,
- precvframe->rx_data,
+ precvframe->pkt->data,
pattrib->pkt_len,
pattrib->MacIDValidEntry[0],
pattrib->MacIDValidEntry[1]
);
rtw_free_recvframe(precvframe, pfree_recv_queue);
} else if (pattrib->pkt_rpt_type == HIS_REPORT) {
- interrupt_handler_8188eu(adapt, pattrib->pkt_len, precvframe->rx_data);
+ interrupt_handler_8188eu(adapt, pattrib->pkt_len, precvframe->pkt->data);
rtw_free_recvframe(precvframe, pfree_recv_queue);
}
pkt_cnt--;
if ((!precvbuf->reuse) || (precvbuf->pskb == NULL)) {
precvbuf->pskb = skb_dequeue(&precvpriv->free_recv_skb_queue);
- if (NULL != precvbuf->pskb)
+ if (precvbuf->pskb != NULL)
precvbuf->reuse = true;
}
*
* Contact Information:
* wlanfae <wlanfae@realtek.com>
-******************************************************************************/
+ ******************************************************************************/
#ifndef __INC_DOT11D_H
#define __INC_DOT11D_H
priv->polling_timer_on = 0;
_rtl92e_down(dev, true);
rtl92e_dm_deinit(dev);
- if (priv->pFirmware) {
- vfree(priv->pFirmware);
- priv->pFirmware = NULL;
- }
+ vfree(priv->pFirmware);
+ priv->pFirmware = NULL;
_rtl92e_free_rx_ring(dev);
for (i = 0; i < MAX_TX_QUEUE_COUNT; i++)
_rtl92e_free_tx_ring(dev, i);
MODULE_FIRMWARE(RTL8192E_MAIN_IMG_FW);
MODULE_FIRMWARE(RTL8192E_DATA_IMG_FW);
-module_param(ifname, charp, S_IRUGO|S_IWUSR);
-module_param(hwwep, int, S_IRUGO|S_IWUSR);
-module_param(channels, int, S_IRUGO|S_IWUSR);
+module_param(ifname, charp, 0644);
+module_param(hwwep, int, 0644);
+module_param(channels, int, 0644);
MODULE_PARM_DESC(ifname, " Net interface name, wlan%d=default");
MODULE_PARM_DESC(hwwep, " Try to use hardware WEP support(default use hw. set 0 to use software security)");
} else
sec.flags &= ~SEC_ACTIVE_KEY;
- if (param->u.crypt.alg != NULL) {
- memcpy(sec.keys[param->u.crypt.idx],
- param->u.crypt.key,
- param->u.crypt.key_len);
- sec.key_sizes[param->u.crypt.idx] = param->u.crypt.key_len;
- sec.flags |= (1 << param->u.crypt.idx);
-
- if (strcmp(param->u.crypt.alg, "R-WEP") == 0) {
- sec.flags |= SEC_LEVEL;
- sec.level = SEC_LEVEL_1;
- } else if (strcmp(param->u.crypt.alg, "R-TKIP") == 0) {
- sec.flags |= SEC_LEVEL;
- sec.level = SEC_LEVEL_2;
- } else if (strcmp(param->u.crypt.alg, "R-CCMP") == 0) {
- sec.flags |= SEC_LEVEL;
- sec.level = SEC_LEVEL_3;
- }
+ memcpy(sec.keys[param->u.crypt.idx],
+ param->u.crypt.key,
+ param->u.crypt.key_len);
+ sec.key_sizes[param->u.crypt.idx] = param->u.crypt.key_len;
+ sec.flags |= (1 << param->u.crypt.idx);
+
+ if (strcmp(param->u.crypt.alg, "R-WEP") == 0) {
+ sec.flags |= SEC_LEVEL;
+ sec.level = SEC_LEVEL_1;
+ } else if (strcmp(param->u.crypt.alg, "R-TKIP") == 0) {
+ sec.flags |= SEC_LEVEL;
+ sec.level = SEC_LEVEL_2;
+ } else if (strcmp(param->u.crypt.alg, "R-CCMP") == 0) {
+ sec.flags |= SEC_LEVEL;
+ sec.level = SEC_LEVEL_3;
}
done:
if (ieee->set_security)
//u32 STA_EDCA_PARAM[4];
//CHANNEL_ACCESS_SETTING ChannelAccessSetting;
+ struct ieee80211_rxb *stats_IndicateArray[REORDER_WIN_SIZE];
/* Callback functions */
void (*set_security)(struct net_device *dev,
static void enqueue_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb)
{
int nh;
+
nh = (ieee->mgmt_queue_head +1) % MGMT_QUEUE_NUM;
/*
(struct rtl_80211_hdr_3addr *) skb->data;
cb_desc *tcb_desc = (cb_desc *)(skb->cb + 8);
+
spin_lock_irqsave(&ieee->lock, flags);
/* called with 2nd param 0, no mgmt lock required */
static void ieee80211_send_beacon(struct ieee80211_device *ieee)
{
struct sk_buff *skb;
+
if(!ieee->ieee_up)
return;
//unsigned long flags;
{
short ch = 0;
u8 channel_map[MAX_CHANNEL_NUMBER+1];
+
memcpy(channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1);
mutex_lock(&ieee->scan_mutex);
struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, softmac_scan_wq);
static short watchdog;
u8 channel_map[MAX_CHANNEL_NUMBER+1];
+
memcpy(channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1);
if(!ieee->ieee_up)
return;
{
short ch = 0;
int i = 0;
+
if (ieee->proto_started)
return;
{
/* This is called when wpa_supplicant loads and closes the driver
* interface. */
- printk("%s WPA\n",value ? "enabling" : "disabling");
+ printk("%s WPA\n", value ? "enabling" : "disabling");
ieee->wpa_enabled = value;
return 0;
}
static int ieee80211_wpa_set_param(struct ieee80211_device *ieee, u8 name, u32 value)
{
- int ret=0;
+ int ret = 0;
unsigned long flags;
switch (name) {
break;
case IEEE_PARAM_TKIP_COUNTERMEASURES:
- ieee->tkip_countermeasures=value;
+ ieee->tkip_countermeasures = value;
break;
case IEEE_PARAM_DROP_UNENCRYPTED: {
}
case IEEE_PARAM_PRIVACY_INVOKED:
- ieee->privacy_invoked=value;
+ ieee->privacy_invoked = value;
break;
case IEEE_PARAM_AUTH_ALGS:
break;
case IEEE_PARAM_IEEE_802_1X:
- ieee->ieee802_1x=value;
+ ieee->ieee802_1x = value;
break;
case IEEE_PARAM_WPAX_SELECT:
// added for WPA2 mixed mode
break;
default:
- printk("Unknown WPA param: %d\n",name);
+ printk("Unknown WPA param: %d\n", name);
ret = -EOPNOTSUPP;
}
} else
sec.flags &= ~SEC_ACTIVE_KEY;
- if (param->u.crypt.alg != NULL) {
- memcpy(sec.keys[param->u.crypt.idx],
- param->u.crypt.key,
- param->u.crypt.key_len);
- sec.key_sizes[param->u.crypt.idx] = param->u.crypt.key_len;
- sec.flags |= (1 << param->u.crypt.idx);
-
- if (strcmp(param->u.crypt.alg, "WEP") == 0) {
- sec.flags |= SEC_LEVEL;
- sec.level = SEC_LEVEL_1;
- } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) {
- sec.flags |= SEC_LEVEL;
- sec.level = SEC_LEVEL_2;
- } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) {
- sec.flags |= SEC_LEVEL;
- sec.level = SEC_LEVEL_3;
- }
+ memcpy(sec.keys[param->u.crypt.idx],
+ param->u.crypt.key,
+ param->u.crypt.key_len);
+ sec.key_sizes[param->u.crypt.idx] = param->u.crypt.key_len;
+ sec.flags |= (1 << param->u.crypt.idx);
+
+ if (strcmp(param->u.crypt.alg, "WEP") == 0) {
+ sec.flags |= SEC_LEVEL;
+ sec.level = SEC_LEVEL_1;
+ } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) {
+ sec.flags |= SEC_LEVEL;
+ sec.level = SEC_LEVEL_2;
+ } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) {
+ sec.flags |= SEC_LEVEL;
+ sec.level = SEC_LEVEL_3;
}
done:
if (ieee->set_security)
if (!skb)
return NULL;
- disass = (struct ieee80211_disassoc *) skb_put(skb,sizeof(struct ieee80211_disassoc));
+ disass = (struct ieee80211_disassoc *) skb_put(skb, sizeof(struct ieee80211_disassoc));
disass->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_DISASSOC);
disass->header.duration_id = 0;
{
struct ieee80211_network *beacon = &ieee->current_network;
struct sk_buff *skb;
- skb = ieee80211_disassociate_skb(beacon,ieee,asRsn);
+
+ skb = ieee80211_disassociate_skb(beacon, ieee, asRsn);
if (skb) {
softmac_mgmt_xmit(skb, ieee);
//dev_kfree_skb_any(skb);//edit by thomas
int ieee80211_wpa_supplicant_ioctl(struct ieee80211_device *ieee, struct iw_point *p)
{
struct ieee_param *param;
- int ret=0;
+ int ret = 0;
mutex_lock(&ieee->wx_mutex);
//IEEE_DEBUG_INFO("wpa_supplicant: len=%d\n", p->length);
void notify_wx_assoc_event(struct ieee80211_device *ieee)
{
union iwreq_data wrqu;
+
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
if (ieee->state == IEEE80211_LINKED)
memcpy(wrqu.ap_addr.sa_data, ieee->current_network.bssid, ETH_ALEN);
memset(txb, 0, sizeof(struct ieee80211_txb));
txb->nr_frags = nr_frags;
- txb->frag_size = txb_size;
+ txb->frag_size = __cpu_to_le16(txb_size);
for (i = 0; i < nr_frags; i++) {
txb->fragments[i] = dev_alloc_skb(txb_size);
goto failed;
}
txb->encrypted = encrypt;
- txb->payload_size = bytes;
+ txb->payload_size = __cpu_to_le16(bytes);
//if (ieee->current_network.QoS_Enable)
if(qos_actived)
}
txb->encrypted = 0;
- txb->payload_size = skb->len;
+ txb->payload_size = __cpu_to_le16(skb->len);
memcpy(skb_put(txb->fragments[0],skb->len), skb->data, skb->len);
}
}else{
if ((*ieee->hard_start_xmit)(txb, dev) == 0) {
stats->tx_packets++;
- stats->tx_bytes += txb->payload_size;
+ stats->tx_bytes += __le16_to_cpu(txb->payload_size);
return 0;
}
ieee80211_txb_free(txb);
//u32 flags = 0;
unsigned long flags = 0;
- struct ieee80211_rxb *stats_IndicateArray[REORDER_WIN_SIZE];
u8 index = 0;
bool bPktInBuf = false;
pRxTs->RxIndicateSeq = (pRxTs->RxIndicateSeq + 1) % 4096;
IEEE80211_DEBUG(IEEE80211_DL_REORDER,"RxPktPendingTimeout(): IndicateSeq: %d\n", pReorderEntry->SeqNum);
- stats_IndicateArray[index] = pReorderEntry->prxb;
+ ieee->stats_IndicateArray[index] = pReorderEntry->prxb;
index++;
list_add_tail(&pReorderEntry->List, &ieee->RxReorder_Unused_List);
spin_unlock_irqrestore(&(ieee->reorder_spinlock), flags);
return;
}
- ieee80211_indicate_packets(ieee, stats_IndicateArray, index);
+ ieee80211_indicate_packets(ieee, ieee->stats_IndicateArray, index);
}
if(bPktInBuf && (pRxTs->RxTimeoutIndicateSeq==0xffff))
/*
- This is part of rtl8187 OpenSource driver
- Copyright (C) Andrea Merello 2004-2005 <andrea.merello@gmail.com>
- Released under the terms of GPL (General Public Licence)
-
- Parts of this driver are based on the GPL part of the
- official realtek driver
- Parts of this driver are based on the rtl8180 driver skeleton
- from Patric Schenke & Andres Salomon
- Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver
-
- We want to thank the Authors of such projects and the Ndiswrapper
- project Authors.
-*/
+ * This is part of rtl8187 OpenSource driver
+ * Copyright (C) Andrea Merello 2004-2005 <andrea.merello@gmail.com>
+ * Released under the terms of GPL (General Public Licence)
+ *
+ * Parts of this driver are based on the GPL part of the
+ * official realtek driver
+ * Parts of this driver are based on the rtl8180 driver skeleton
+ * from Patric Schenke & Andres Salomon
+ * Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver
+ *
+ * We want to thank the Authors of such projects and the Ndiswrapper
+ * project Authors.
+ */
/*This files contains card eeprom (93c46 or 93c56) programming routines*/
/*memory is addressed by WORDS*/
#define EPROM_TXPW2 0x1b
#define EPROM_TXPW1 0x3d
-
int eprom_read(struct net_device *dev, u32 addr); /* reads a 16 bits word */
}
if (wrqu->encoding.length == 0x5) {
- ieee->pairwise_key_type = KEY_TYPE_WEP40;
+ ieee->pairwise_key_type = KEY_TYPE_WEP40;
EnableHWSecurityConfig8192(dev);
setKey(dev,
}
else if (wrqu->encoding.length == 0xd) {
- ieee->pairwise_key_type = KEY_TYPE_WEP104;
- EnableHWSecurityConfig8192(dev);
+ ieee->pairwise_key_type = KEY_TYPE_WEP104;
+ EnableHWSecurityConfig8192(dev);
setKey(dev,
key_idx, /* EntryNo */
priv->stats.txretrycount += pstx_fb->retry_cnt;
priv->stats.txfeedbackretry += pstx_fb->retry_cnt;
-
}
-
-
/*-----------------------------------------------------------------------------
* Function: cmpk_handle_tx_feedback()
*
/* Collect info TX feedback packet to fill TCB. */
/* We can not know the packet length and transmit type: broadcast or uni
or multicast. */
-
}
static void cmdpkt_beacontimerinterrupt_819xusb(struct net_device *dev)
u16 tx_rate;
/* 87B have to S/W beacon for DTM encryption_cmn. */
if (priv->ieee80211->current_network.mode == IEEE_A ||
- priv->ieee80211->current_network.mode == IEEE_N_5G ||
- (priv->ieee80211->current_network.mode == IEEE_N_24G &&
- (!priv->ieee80211->pHTInfo->bCurSuppCCK))) {
+ priv->ieee80211->current_network.mode == IEEE_N_5G ||
+ (priv->ieee80211->current_network.mode == IEEE_N_24G &&
+ (!priv->ieee80211->pHTInfo->bCurSuppCCK))) {
tx_rate = 60;
DMESG("send beacon frame tx rate is 6Mbpm\n");
} else {
}
rtl819xusb_beacon_tx(dev, tx_rate); /* HW Beacon */
-
-
}
-
-
-
/*-----------------------------------------------------------------------------
* Function: cmpk_handle_interrupt_status()
*
return;
}
-
/* Statistics of beacon for ad-hoc mode. */
if (priv->ieee80211->iw_mode == IW_MODE_ADHOC) {
/* 2 maybe need endian transform? */
if (rx_intr_status.interrupt_status & ISR_BcnTimerIntr)
cmdpkt_beacontimerinterrupt_819xusb(dev);
-
}
/* Other informations in interrupt status we need? */
-
DMESG("<---- cmpk_handle_interrupt_status()\n");
-
}
-
/*-----------------------------------------------------------------------------
* Function: cmpk_handle_query_config_rx()
*
{
cmpk_query_cfg_t rx_query_cfg;
-
/* 1. Extract TX feedback info from RFD to temp structure buffer. */
/* It seems that FW use big endian(MIPS) and DRV use little endian in
windows OS. So we have to read the content byte by byte or transfer
(pmsg[10] << 8) | (pmsg[11] << 0);
rx_query_cfg.mask = (pmsg[12] << 24) | (pmsg[13] << 16) |
(pmsg[14] << 8) | (pmsg[15] << 0);
-
}
-
/*-----------------------------------------------------------------------------
* Function: cmpk_count_tx_status()
*
priv->stats.last_packet_rate = pstx_status->rate;
}
-
-
/*-----------------------------------------------------------------------------
* Function: cmpk_handle_tx_status()
*
memcpy((void *)&rx_tx_sts, (void *)pmsg, sizeof(cmpk_tx_status_t));
/* 2. Use tx feedback info to count TX statistics. */
cmpk_count_tx_status(dev, &rx_tx_sts);
-
}
-
/*-----------------------------------------------------------------------------
* Function: cmpk_handle_tx_rate_history()
*
u32 *ptemp;
struct r8192_priv *priv = ieee80211_priv(dev);
-
#ifdef ENABLE_PS
pAdapter->HalFunc.GetHwRegHandler(pAdapter, HW_VAR_RF_STATE,
(pu1Byte)(&rtState));
for (j = 0; j < 4; j++)
priv->stats.txrate.ht_mcs[j][i] += ptxrate->ht_mcs[j][i];
}
-
}
-
/*-----------------------------------------------------------------------------
* Function: cmpk_message_handle_rx()
*
pcmd_buff += cmd_length;
}
return 1; /* This is a command packet. */
-
}
static void update_fwhdr(struct fw_hdr *pfwhdr, const u8 *pmappedfw)
{
- pfwhdr->signature = le16_to_cpu(*(u16 *)pmappedfw);
- pfwhdr->version = le16_to_cpu(*(u16 *)(pmappedfw + 2));
+ pfwhdr->signature = le16_to_cpu(*(__le16 *)pmappedfw);
+ pfwhdr->version = le16_to_cpu(*(__le16 *)(pmappedfw + 2));
/* define the size of boot loader */
- pfwhdr->dmem_size = le32_to_cpu(*(uint *)(pmappedfw + 4));
+ pfwhdr->dmem_size = le32_to_cpu(*(__le32 *)(pmappedfw + 4));
/* define the size of FW in IMEM */
- pfwhdr->img_IMEM_size = le32_to_cpu(*(uint *)(pmappedfw + 8));
+ pfwhdr->img_IMEM_size = le32_to_cpu(*(__le32 *)(pmappedfw + 8));
/* define the size of FW in SRAM */
- pfwhdr->img_SRAM_size = le32_to_cpu(*(uint *)(pmappedfw + 12));
+ pfwhdr->img_SRAM_size = le32_to_cpu(*(__le32 *)(pmappedfw + 12));
/* define the size of DMEM variable */
- pfwhdr->fw_priv_sz = le32_to_cpu(*(uint *)(pmappedfw + 16));
+ pfwhdr->fw_priv_sz = le32_to_cpu(*(__le32 *)(pmappedfw + 16));
}
static u8 chk_fwhdr(struct fw_hdr *pfwhdr, u32 ulfilelength)
sz += 8;
ie += sz;
/*beacon interval : 2bytes*/
- *(u16 *)ie = cpu_to_le16((u16)pdev_network->Configuration.BeaconPeriod);
+ *(__le16 *)ie = cpu_to_le16((u16)pdev_network->Configuration.BeaconPeriod);
sz += 2;
ie += 2;
/*capability info*/
*(u16 *)ie = 0;
- *(u16 *)ie |= cpu_to_le16(cap_IBSS);
+ *(__le16 *)ie |= cpu_to_le16(cap_IBSS);
if (pregistrypriv->preamble == PREAMBLE_SHORT)
- *(u16 *)ie |= cpu_to_le16(cap_ShortPremble);
+ *(__le16 *)ie |= cpu_to_le16(cap_ShortPremble);
if (pdev_network->Privacy)
- *(u16 *)ie |= cpu_to_le16(cap_Privacy);
+ *(__le16 *)ie |= cpu_to_le16(cap_Privacy);
sz += 2;
ie += 2;
/*SSID*/
rateLen, pdev_network->rates, &sz);
/*DS parameter set*/
ie = r8712_set_ie(ie, _DSSET_IE_, 1,
- (u8 *)&(pdev_network->Configuration.DSConfig), &sz);
+ (u8 *)&pdev_network->Configuration.DSConfig, &sz);
/*IBSS Parameter Set*/
ie = r8712_set_ie(ie, _IBSS_PARA_IE_, 2,
- (u8 *)&(pdev_network->Configuration.ATIMWindow), &sz);
+ (u8 *)&pdev_network->Configuration.ATIMWindow, &sz);
return sz;
}
goto check_next_ie;
/*check version...*/
memcpy((u8 *)&val16, (pbuf + 6), sizeof(val16));
- val16 = le16_to_cpu(val16);
+ le16_to_cpus(&val16);
if (val16 != 0x0001)
goto check_next_ie;
*wpa_ie_len = *(pbuf + 1);
}
/*pairwise_cipher*/
if (left >= 2) {
- count = le16_to_cpu(*(u16 *)pos);
+ count = le16_to_cpu(*(__le16 *)pos);
pos += 2;
left -= 2;
if (count == 0 || left < count * WPA_SELECTOR_LEN)
}
/*pairwise_cipher*/
if (left >= 2) {
- count = le16_to_cpu(*(u16 *)pos);
+ count = le16_to_cpu(*(__le16 *)pos);
pos += 2;
left -= 2;
if (count == 0 || left < count * RSN_SELECTOR_LEN)
backupTKIPCountermeasure = adapter->securitypriv.
btkip_countermeasure;
memset((unsigned char *)&adapter->securitypriv, 0,
- sizeof(struct security_priv));
+ sizeof(struct security_priv));
setup_timer(&adapter->securitypriv.tkip_timer,
r8712_use_tkipkey_handler,
(unsigned long)adapter);
* for the following connection.
*/
memcpy(&adapter->securitypriv.PMKIDList[0],
- &backupPMKIDList[0],
- sizeof(struct RT_PMKID_LIST) * NUM_PMKID_CACHE);
+ &backupPMKIDList[0],
+ sizeof(struct RT_PMKID_LIST) * NUM_PMKID_CACHE);
adapter->securitypriv.PMKIDIndex = backupPMKIDIndex;
adapter->securitypriv.btkip_countermeasure =
backupTKIPCountermeasure;
int r8712_cmd_thread(void *context)
{
struct cmd_obj *pcmd;
- unsigned int cmdsz, wr_sz, *pcmdbuf;
+ unsigned int cmdsz, wr_sz;
+ __le32 *pcmdbuf;
struct tx_desc *pdesc;
void (*pcmd_callback)(struct _adapter *dev, struct cmd_obj *pcmd);
struct _adapter *padapter = context;
r8712_unregister_cmd_alive(padapter);
continue;
}
- pcmdbuf = (unsigned int *)pcmdpriv->cmd_buf;
+ pcmdbuf = (__le32 *)pcmdpriv->cmd_buf;
pdesc = (struct tx_desc *)pcmdbuf;
memset(pdesc, 0, TXDESC_SIZE);
pcmd = cmd_hdl_filter(padapter, pcmd);
thread_exit();
}
-void r8712_event_handle(struct _adapter *padapter, uint *peventbuf)
+void r8712_event_handle(struct _adapter *padapter, __le32 *peventbuf)
{
u8 evt_code, evt_seq;
u16 evt_sz;
#ifndef _RTL8712_EVENT_H_
#define _RTL8712_EVENT_H_
-void r8712_event_handle(struct _adapter *padapter, uint *peventbuf);
+void r8712_event_handle(struct _adapter *padapter, __le32 *peventbuf);
void r8712_got_addbareq_event_callback(struct _adapter *adapter, u8 *pbuf);
enum rtl8712_c2h_event {
memcpy(skb_push(sub_skb, ETH_ALEN), pattrib->dst,
ETH_ALEN);
} else {
- u16 len;
+ __be16 len;
/* Leave Ethernet header part of hdr and full payload */
len = htons(sub_skb->len);
memcpy(skb_push(sub_skb, 2), &len, 2);
void r8712_rxcmd_event_hdl(struct _adapter *padapter, void *prxcmdbuf)
{
- uint voffset;
+ __le32 voffset;
u8 *poffset;
u16 cmd_len, drvinfo_sz;
struct recv_stat *prxstat;
poffset = (u8 *)prxcmdbuf;
- voffset = *(uint *)poffset;
+ voffset = *(__le32 *)poffset;
prxstat = (struct recv_stat *)prxcmdbuf;
drvinfo_sz = (le32_to_cpu(prxstat->rxdw0) & 0x000f0000) >> 16;
drvinfo_sz <<= 3;
poffset += RXDESC_SIZE + drvinfo_sz;
do {
- voffset = *(uint *)poffset;
+ voffset = *(__le32 *)poffset;
cmd_len = (u16)(le32_to_cpu(voffset) & 0xffff);
- r8712_event_handle(padapter, (uint *)poffset);
+ r8712_event_handle(padapter, (__le32 *)poffset);
poffset += (cmd_len + 8);/*8 bytes alignment*/
} while (le32_to_cpu(voffset) & BIT(31));
/* CCK Driver info Structure is not the same as OFDM packet.*/
pcck_buf = (struct phy_cck_rx_status *)pphy_stat;
/* (1)Hardware does not provide RSSI for CCK
- * (2)PWDB, Average PWDB cacluated by hardware
+ * (2)PWDB, Average PWDB calculated by hardware
* (for rate adaptive)
*/
if (!cck_highpwr) {
rssi = query_rx_pwr_percentage(rx_pwr[i]);
total_rssi += rssi;
}
- /* (2)PWDB, Average PWDB cacluated by hardware (for
+ /* (2)PWDB, Average PWDB calculated by hardware (for
* rate adaptive)
*/
rx_pwr_all = (((pphy_head[PHY_STAT_PWDB_ALL_SHT]) >> 1) & 0x7f)
#define REORDER_WAIT_TIME 30 /* (ms)*/
struct recv_stat {
- unsigned int rxdw0;
- unsigned int rxdw1;
- unsigned int rxdw2;
- unsigned int rxdw3;
- unsigned int rxdw4;
- unsigned int rxdw5;
+ __le32 rxdw0;
+ __le32 rxdw1;
+ __le32 rxdw2;
+ __le32 rxdw3;
+ __le32 rxdw4;
+ __le32 rxdw5;
};
struct phy_cck_rx_status {
};
struct phy_stat {
- unsigned int phydw0;
- unsigned int phydw1;
- unsigned int phydw2;
- unsigned int phydw3;
- unsigned int phydw4;
- unsigned int phydw5;
- unsigned int phydw6;
- unsigned int phydw7;
+ __le32 phydw0;
+ __le32 phydw1;
+ __le32 phydw2;
+ __le32 phydw3;
+ __le32 phydw4;
+ __le32 phydw5;
+ __le32 phydw6;
+ __le32 phydw7;
};
#define PHY_STAT_GAIN_TRSW_SHT 0
#define PHY_STAT_PWDB_ALL_SHT 4
int last_txcmdsz = 0;
int padding_sz = 0;
- /* 802.3->802.11 convertor */
+ /* 802.3->802.11 converter */
r8712_xmitframe_coalesce(padapter, pxmitframe->pkt, pxmitframe);
/* free skb struct */
r8712_xmit_complete(padapter, pxmitframe);
}
} else if (pxmitframe->frame_tag == MGNT_FRAMETAG) {
/* offset 4 */
- ptxdesc->txdw1 |= (0x05) & 0x1f;/*CAM_ID(MAC_ID), default=5;*/
+ ptxdesc->txdw1 |= cpu_to_le32((0x05) & 0x1f);/*CAM_ID(MAC_ID), default=5;*/
qsel = (uint)(pattrib->qsel & 0x0000001f);
ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00);
ptxdesc->txdw1 |= cpu_to_le32(BIT(16));/* Non-QoS */
struct tx_desc {
/*DWORD 0*/
- unsigned int txdw0;
- unsigned int txdw1;
- unsigned int txdw2;
- unsigned int txdw3;
- unsigned int txdw4;
- unsigned int txdw5;
- unsigned int txdw6;
- unsigned int txdw7;
+ __le32 txdw0;
+ __le32 txdw1;
+ __le32 txdw2;
+ __le32 txdw3;
+ __le32 txdw4;
+ __le32 txdw5;
+ __le32 txdw6;
+ __le32 txdw7;
};
* Command-Event Mode
*/
struct sitesurvey_parm {
- sint passive_mode; /*active: 1, passive: 0 */
- sint bsslimit; /* 1 ~ 48 */
- sint ss_ssidlen;
+ __le32 passive_mode; /*active: 1, passive: 0 */
+ __le32 bsslimit; /* 1 ~ 48 */
+ __le32 ss_ssidlen;
u8 ss_ssid[IW_ESSID_MAX_SIZE + 1];
};
struct stassoc_event {
unsigned char macaddr[6];
unsigned char rsvd[2];
- int cam_id;
+ __le32 cam_id;
};
struct stadel_event {
iwe.cmd = SIOCGIWMODE;
memcpy((u8 *)&cap, r8712_get_capability_from_ie(pnetwork->network.IEs),
2);
- cap = le16_to_cpu(cap);
+ le16_to_cpus(&cap);
if (cap & (WLAN_CAPABILITY_IBSS | WLAN_CAPABILITY_BSS)) {
if (cap & WLAN_CAPABILITY_BSS)
iwe.u.mode = (u32)IW_MODE_MASTER;
piwstats->qual.level = 0;
piwstats->qual.noise = 0;
} else {
- /* show percentage, we need transfer dbm to orignal value. */
+ /* show percentage, we need transfer dbm to original value. */
tmp_level = padapter->recvpriv.fw_rssi;
tmp_qual = padapter->recvpriv.signal;
tmp_noise = padapter->recvpriv.noise;
struct security_priv *psecuritypriv = &adapter->securitypriv;
if ((psecuritypriv->PrivacyAlgrthm != _NO_PRIVACY_) &&
- (pnetwork->network.Privacy == 0))
+ (pnetwork->network.Privacy == cpu_to_le32(0)))
ret = false;
else if ((psecuritypriv->PrivacyAlgrthm == _NO_PRIVACY_) &&
- (pnetwork->network.Privacy == 1))
+ (pnetwork->network.Privacy == cpu_to_le32(1)))
ret = false;
else
ret = true;
return;
/* to do : init sta_info variable */
psta->qos_option = 0;
- psta->mac_id = le32_to_cpu((uint)pstassoc->cam_id);
+ psta->mac_id = le32_to_cpu(pstassoc->cam_id);
/* psta->aid = (uint)pstassoc->cam_id; */
if (adapter->securitypriv.AuthAlgrthm == 2)
pdev_network->Rssi = 0;
switch (pregistrypriv->wireless_mode) {
case WIRELESS_11B:
- pdev_network->NetworkTypeInUse = cpu_to_le32(Ndis802_11DS);
+ pdev_network->NetworkTypeInUse = Ndis802_11DS;
break;
case WIRELESS_11G:
case WIRELESS_11BG:
- pdev_network->NetworkTypeInUse = cpu_to_le32(Ndis802_11OFDM24);
+ pdev_network->NetworkTypeInUse = Ndis802_11OFDM24;
break;
case WIRELESS_11A:
- pdev_network->NetworkTypeInUse = cpu_to_le32(Ndis802_11OFDM5);
+ pdev_network->NetworkTypeInUse = Ndis802_11OFDM5;
break;
default:
/* TODO */
pregistrypriv->channel);
if (cur_network->network.InfrastructureMode == Ndis802_11IBSS)
pdev_network->Configuration.ATIMWindow = cpu_to_le32(3);
- pdev_network->InfrastructureMode = cpu_to_le32(
- cur_network->network.InfrastructureMode);
+ pdev_network->InfrastructureMode = cur_network->network.InfrastructureMode;
/* 1. Supported rates
* 2. IE
*/
res = _FAIL;
goto end_of_mp_start_test;
}
- /* 3 3. join psudo AdHoc */
+ /* 3 3. join pseudo AdHoc */
tgt_network->join_res = 1;
tgt_network->aid = psta->aid = 1;
memcpy(&tgt_network->network, &bssid, length);
spin_lock_irqsave(&pmlmepriv->lock, irqL);
if (!check_fwstate(pmlmepriv, WIFI_MP_STATE))
goto end_of_mp_stop_test;
- /* 3 1. disconnect psudo AdHoc */
+ /* 3 1. disconnect pseudo AdHoc */
r8712_os_indicate_disconnect(padapter);
/* 3 2. clear psta used in mp test mode. */
psta = r8712_get_stainfo(&padapter->stapriv,
/* get ether_type */
ptr = ptr + pfhdr->attrib.hdrlen + LLC_HEADER_SIZE;
memcpy(ðer_type, ptr, 2);
- ether_type = ntohs((unsigned short)ether_type);
+ be16_to_cpus(ðer_type);
if ((psta != NULL) && (psta->ieee8021x_blocked)) {
/* blocked
/* append rx status for mp test packets */
ptr = recvframe_pull(precvframe, (rmv_len -
sizeof(struct ethhdr) + 2) - 24);
+ if (!ptr)
+ return _FAIL;
memcpy(ptr, get_rxmem(precvframe), 24);
ptr += 24;
- } else
+ } else {
ptr = recvframe_pull(precvframe, (rmv_len -
sizeof(struct ethhdr) + (bsnaphdr ? 2 : 0)));
+ if (!ptr)
+ return _FAIL;
+ }
memcpy(ptr, pattrib->dst, ETH_ALEN);
memcpy(ptr + ETH_ALEN, pattrib->src, ETH_ALEN);
length = pattrib->last_txcmdsz - pattrib->
hdrlen - pattrib->iv_len -
pattrib->icv_len;
- *((u32 *)crc) = cpu_to_le32(getcrc32(
+ *((__le32 *)crc) = cpu_to_le32(getcrc32(
payload, length));
arcfour_init(&mycontext, wepkey, 3 + keylength);
arcfour_encrypt(&mycontext, payload, payload,
length = pxmitpriv->frag_len -
pattrib->hdrlen - pattrib->iv_len -
pattrib->icv_len;
- *((u32 *)crc) = cpu_to_le32(getcrc32(
+ *((__le32 *)crc) = cpu_to_le32(getcrc32(
payload, length));
arcfour_init(&mycontext, wepkey, 3 + keylength);
arcfour_encrypt(&mycontext, payload, payload,
arcfour_init(&mycontext, wepkey, 3 + keylength);
arcfour_encrypt(&mycontext, payload, payload, length);
/* calculate icv and compare the icv */
- *((u32 *)crc) = cpu_to_le32(getcrc32(payload, length - 4));
+ *((__le32 *)crc) = cpu_to_le32(getcrc32(payload, length - 4));
}
}
pattrib->hdrlen -
pattrib->iv_len -
pattrib->icv_len;
- *((u32 *)crc) = cpu_to_le32(
+ *((__le32 *)crc) = cpu_to_le32(
getcrc32(payload, length));
arcfour_init(&mycontext, rc4key, 16);
arcfour_encrypt(&mycontext, payload,
pattrib->hdrlen -
pattrib->iv_len -
pattrib->icv_len;
- *((u32 *)crc) = cpu_to_le32(getcrc32(
+ *((__le32 *)crc) = cpu_to_le32(getcrc32(
payload, length));
arcfour_init(&mycontext, rc4key, 16);
arcfour_encrypt(&mycontext, payload,
/* 4 decrypt payload include icv */
arcfour_init(&mycontext, rc4key, 16);
arcfour_encrypt(&mycontext, payload, payload, length);
- *((u32 *)crc) = cpu_to_le32(getcrc32(payload,
+ *((__le32 *)crc) = cpu_to_le32(getcrc32(payload,
length - 4));
if (crc[3] != payload[length - 1] ||
crc[2] != payload[length - 2] ||
u8 add1b[4];
u8 add1bf7[4];
u8 rotl[4];
- u8 swap_halfs[4];
+ u8 swap_halves[4];
u8 andf7[4];
u8 rotr[4];
u8 temp[4];
else
add1b[i] = 0x00;
}
- swap_halfs[0] = in[2]; /* Swap halves */
- swap_halfs[1] = in[3];
- swap_halfs[2] = in[0];
- swap_halfs[3] = in[1];
+ swap_halves[0] = in[2]; /* Swap halves */
+ swap_halves[1] = in[3];
+ swap_halves[2] = in[0];
+ swap_halves[3] = in[1];
rotl[0] = in[3]; /* Rotate left 8 bits */
rotl[1] = in[0];
rotl[2] = in[1];
rotr[2] = rotr[3];
rotr[3] = temp[0];
xor_32(add1bf7, rotr, temp);
- xor_32(swap_halfs, rotl, tempb);
+ xor_32(swap_halves, rotl, tempb);
xor_32(temp, tempb, out);
}
u8 aes_out[16];
u8 padded_buffer[16];
u8 mic[8];
- uint frtype = GetFrameType(pframe);
- uint frsubtype = GetFrameSubType(pframe);
+ u16 frtype = GetFrameType(pframe);
+ u16 frsubtype = GetFrameSubType(pframe);
frsubtype >>= 4;
memset((void *)mic_iv, 0, 16);
u16 wvalue;
u16 index;
u16 len;
- u32 data;
+ __le32 data;
struct intf_priv *pintfpriv = pintfhdl->pintfpriv;
request = 0x05;
u16 wvalue;
u16 index;
u16 len;
- u32 data;
+ __le32 data;
struct intf_priv *pintfpriv = pintfhdl->pintfpriv;
request = 0x05;
u16 wvalue;
u16 index;
u16 len;
- u32 data;
+ __le32 data;
struct intf_priv *pintfpriv = pintfhdl->pintfpriv;
request = 0x05;
u16 wvalue;
u16 index;
u16 len;
- u32 data;
+ __le32 data;
struct intf_priv *pintfpriv = pintfhdl->pintfpriv;
request = 0x05;
index = 0;
wvalue = (u16)(addr & 0x0000ffff);
len = 1;
- data = val;
- data = cpu_to_le32(data & 0x000000ff);
+ data = cpu_to_le32((u32)val & 0x000000ff);
r8712_usbctrl_vendorreq(pintfpriv, request, wvalue, index, &data, len,
requesttype);
}
u16 wvalue;
u16 index;
u16 len;
- u32 data;
+ __le32 data;
struct intf_priv *pintfpriv = pintfhdl->pintfpriv;
request = 0x05;
index = 0;
wvalue = (u16)(addr & 0x0000ffff);
len = 2;
- data = val;
- data = cpu_to_le32(data & 0x0000ffff);
+ data = cpu_to_le32((u32)val & 0x0000ffff);
r8712_usbctrl_vendorreq(pintfpriv, request, wvalue, index, &data, len,
requesttype);
}
u16 wvalue;
u16 index;
u16 len;
- u32 data;
+ __le32 data;
struct intf_priv *pintfpriv = pintfhdl->pintfpriv;
request = 0x05;
static void r8712_usb_read_port_complete(struct urb *purb)
{
- uint isevt, *pbuf;
+ uint isevt;
+ __le32 *pbuf;
struct recv_buf *precvbuf = (struct recv_buf *)purb->context;
struct _adapter *padapter = (struct _adapter *)precvbuf->adapter;
struct recv_priv *precvpriv = &padapter->recvpriv;
_pkt *pskb = precvbuf->pskb;
precvbuf->transfer_len = purb->actual_length;
- pbuf = (uint *)precvbuf->pbuf;
+ pbuf = (__le32 *)precvbuf->pbuf;
isevt = le32_to_cpu(*(pbuf + 1)) & 0x1ff;
if ((isevt & 0x1ff) == 0x1ff) {
r8712_rxcmd_event_hdl(padapter, pbuf);
#define GetOrder(pbuf) (((*(unsigned short *)(pbuf)) & \
le16_to_cpu(_ORDER_)) != 0)
-#define GetFrameType(pbuf) (le16_to_cpu(*(unsigned short *)(pbuf)) & \
+#define GetFrameType(pbuf) (le16_to_cpu(*(__le16 *)(pbuf)) & \
(BIT(3) | BIT(2)))
#define SetFrameType(pbuf, type) \
*(unsigned short *)(pbuf) |= cpu_to_le16(type); \
} while (0)
-#define GetFrameSubType(pbuf) (cpu_to_le16(*(unsigned short *)(pbuf)) & \
+#define GetFrameSubType(pbuf) (le16_to_cpu(*(__le16 *)(pbuf)) & \
(BIT(7) | BIT(6) | BIT(5) | BIT(4) | BIT(3) | \
BIT(2)))
unsigned char MacAddress[6];
u8 Reserved[2];
struct ndis_802_11_ssid Ssid;
- u32 Privacy;
+ __le32 Privacy;
s32 Rssi;
enum NDIS_802_11_NETWORK_TYPE NetworkTypeInUse;
struct NDIS_802_11_CONFIGURATION Configuration;
i++;
} while (i < 1024);
- if (retval != STATUS_SUCCESS) {
- kfree(buf);
- rtsx_trace(chip);
- return STATUS_FAIL;
- }
-
if ((buf[0] != 0xa5) && (buf[1] != 0xc3)) {
/* Signature code is wrong */
kfree(buf);
*/
static int device_reset(struct scsi_cmnd *srb)
{
- int result = 0;
struct rtsx_dev *dev = host_to_rtsx(srb->device->host);
dev_info(&dev->pci->dev, "%s called\n", __func__);
- return result < 0 ? FAILED : SUCCESS;
+ return SUCCESS;
}
/* Simulate a SCSI bus reset by resetting the device's USB port. */
static int bus_reset(struct scsi_cmnd *srb)
{
- int result = 0;
struct rtsx_dev *dev = host_to_rtsx(srb->device->host);
dev_info(&dev->pci->dev, "%s called\n", __func__);
- return result < 0 ? FAILED : SUCCESS;
+ return SUCCESS;
}
/*
void rtsx_add_cmd(struct rtsx_chip *chip,
u8 cmd_type, u16 reg_addr, u8 mask, u8 data)
{
- u32 *cb = (u32 *)(chip->host_cmds_ptr);
+ __le32 *cb = (__le32 *)(chip->host_cmds_ptr);
u32 val = 0;
val |= (u32)(cmd_type & 0x03) << 30;
static inline void rtsx_add_sg_tbl(
struct rtsx_chip *chip, u32 addr, u32 len, u8 option)
{
- u64 *sgb = (u64 *)(chip->host_sg_tbl_ptr);
+ __le64 *sgb = (__le64 *)(chip->host_sg_tbl_ptr);
u64 val = 0;
u32 temp_len = 0;
u8 temp_opt = 0;
/***********************************************************************
-**
-** Implementation of the Skein hash function.
-**
-** Source code author: Doug Whiting, 2008.
-**
-** This algorithm and source code is released to the public domain.
-**
-************************************************************************/
+ **
+ ** Implementation of the Skein hash function.
+ **
+ ** Source code author: Doug Whiting, 2008.
+ **
+ ** This algorithm and source code is released to the public domain.
+ **
+ ************************************************************************/
#include <linux/string.h> /* get the memcpy/memset functions */
#include <linux/export.h>
#ifndef _SKEIN_H_
#define _SKEIN_H_ 1
-/**************************************************************************
-**
-** Interface declarations and internal definitions for Skein hashing.
-**
-** Source code author: Doug Whiting, 2008.
-**
-** This algorithm and source code is released to the public domain.
-**
-***************************************************************************
-**
-** The following compile-time switches may be defined to control some
-** tradeoffs between speed, code size, error checking, and security.
-**
-** The "default" note explains what happens when the switch is not defined.
-**
-** SKEIN_ERR_CHECK -- how error checking is handled inside Skein
-** code. If not defined, most error checking
-** is disabled (for performance). Otherwise,
-** the switch value is interpreted as:
-** 0: use assert() to flag errors
-** 1: return SKEIN_FAIL to flag errors
-**
-***************************************************************************/
+/*
+ **************************************************************************
+ *
+ * Interface declarations and internal definitions for Skein hashing.
+ *
+ * Source code author: Doug Whiting, 2008.
+ *
+ * This algorithm and source code is released to the public domain.
+ *
+ **************************************************************************
+ *
+ * The following compile-time switches may be defined to control some
+ * tradeoffs between speed, code size, error checking, and security.
+ *
+ * The "default" note explains what happens when the switch is not defined.
+ *
+ * SKEIN_ERR_CHECK -- how error checking is handled inside Skein
+ * code. If not defined, most error checking
+ * is disabled (for performance). Otherwise,
+ * the switch value is interpreted as:
+ * 0: use assert() to flag errors
+ * 1: return SKEIN_FAIL to flag errors
+ *
+ **************************************************************************
+ */
/*Skein digest sizes for crypto api*/
#define SKEIN256_DIGEST_BIT_SIZE 256
int skein_1024_final(struct skein_1024_ctx *ctx, u8 *hash_val);
/*
-** Skein APIs for "extended" initialization: MAC keys, tree hashing.
-** After an init_ext() call, just use update/final calls as with init().
-**
-** Notes: Same parameters as _init() calls, plus tree_info/key/key_bytes.
-** When key_bytes == 0 and tree_info == SKEIN_SEQUENTIAL,
-** the results of init_ext() are identical to calling init().
-** The function init() may be called once to "precompute" the IV for
-** a given hash_bit_len value, then by saving a copy of the context
-** the IV computation may be avoided in later calls.
-** Similarly, the function init_ext() may be called once per MAC key
-** to precompute the MAC IV, then a copy of the context saved and
-** reused for each new MAC computation.
-**/
+ * Skein APIs for "extended" initialization: MAC keys, tree hashing.
+ * After an init_ext() call, just use update/final calls as with init().
+ *
+ * Notes: Same parameters as _init() calls, plus tree_info/key/key_bytes.
+ * When key_bytes == 0 and tree_info == SKEIN_SEQUENTIAL,
+ * the results of init_ext() are identical to calling init().
+ * The function init() may be called once to "precompute" the IV for
+ * a given hash_bit_len value, then by saving a copy of the context
+ * the IV computation may be avoided in later calls.
+ * Similarly, the function init_ext() may be called once per MAC key
+ * to precompute the MAC IV, then a copy of the context saved and
+ * reused for each new MAC computation.
+ */
int skein_256_init_ext(struct skein_256_ctx *ctx, size_t hash_bit_len,
u64 tree_info, const u8 *key, size_t key_bytes);
int skein_512_init_ext(struct skein_512_ctx *ctx, size_t hash_bit_len,
u64 tree_info, const u8 *key, size_t key_bytes);
/*
-** Skein APIs for MAC and tree hash:
-** final_pad: pad, do final block, but no OUTPUT type
-** output: do just the output stage
-*/
+ * Skein APIs for MAC and tree hash:
+ * final_pad: pad, do final block, but no OUTPUT type
+ * output: do just the output stage
+ */
int skein_256_final_pad(struct skein_256_ctx *ctx, u8 *hash_val);
int skein_512_final_pad(struct skein_512_ctx *ctx, u8 *hash_val);
int skein_1024_final_pad(struct skein_1024_ctx *ctx, u8 *hash_val);
int skein_1024_output(struct skein_1024_ctx *ctx, u8 *hash_val);
#endif
-/*****************************************************************
-** "Internal" Skein definitions
-** -- not needed for sequential hashing API, but will be
-** helpful for other uses of Skein (e.g., tree hash mode).
-** -- included here so that they can be shared between
-** reference and optimized code.
-******************************************************************/
+/*
+ *****************************************************************
+ * "Internal" Skein definitions
+ * -- not needed for sequential hashing API, but will be
+ * helpful for other uses of Skein (e.g., tree hash mode).
+ * -- included here so that they can be shared between
+ * reference and optimized code.
+ *****************************************************************
+ */
/* tweak word tweak[1]: bit field starting positions */
#define SKEIN_T1_BIT(BIT) ((BIT) - 64) /* second word */
#define SKEIN_CFG_TREE_INFO_SEQUENTIAL SKEIN_CFG_TREE_INFO(0, 0, 0)
/*
-** Skein macros for getting/setting tweak words, etc.
-** These are useful for partial input bytes, hash tree init/update, etc.
-**/
+ * Skein macros for getting/setting tweak words, etc.
+ * These are useful for partial input bytes, hash tree init/update, etc.
+ */
#define skein_get_tweak(ctx_ptr, TWK_NUM) ((ctx_ptr)->h.tweak[TWK_NUM])
#define skein_set_tweak(ctx_ptr, TWK_NUM, t_val) { \
(ctx_ptr)->h.tweak[TWK_NUM] = (t_val); \
#define skein_assert_ret(x, ret_code)
#define skein_assert(x)
-/*****************************************************************
-** Skein block function constants (shared across Ref and Opt code)
-******************************************************************/
+/*
+ *****************************************************************
+ * Skein block function constants (shared across Ref and Opt code)
+ *****************************************************************
+ */
enum {
/* SKEIN_256 round rotation constants */
R_256_0_0 = 14, R_256_0_1 = 16,
-/***********************************************************************
-**
-** Implementation of the Skein block functions.
-**
-** Source code author: Doug Whiting, 2008.
-**
-** This algorithm and source code is released to the public domain.
-**
-** Compile-time switches:
-**
-** SKEIN_USE_ASM -- set bits (256/512/1024) to select which
-** versions use ASM code for block processing
-** [default: use C for all block sizes]
-**
-************************************************************************/
+/*
+ ***********************************************************************
+ *
+ * Implementation of the Skein block functions.
+ *
+ * Source code author: Doug Whiting, 2008.
+ *
+ * This algorithm and source code is released to the public domain.
+ *
+ * Compile-time switches:
+ *
+ * SKEIN_USE_ASM -- set bits (256/512/1024) to select which
+ * versions use ASM code for block processing
+ * [default: use C for all block sizes]
+ *
+ ***********************************************************************
+ */
#include <linux/string.h>
#include <linux/bitops.h>
-/***********************************************************************
-**
-** Implementation of the Skein hash function.
-**
-** Source code author: Doug Whiting, 2008.
-**
-** This algorithm and source code is released to the public domain.
-**
-************************************************************************/
+/*
+ ***********************************************************************
+ *
+ * Implementation of the Skein hash function.
+ *
+ * Source code author: Doug Whiting, 2008.
+ *
+ * This algorithm and source code is released to the public domain.
+ *
+ ***********************************************************************
+ */
#ifndef _SKEIN_BLOCK_H_
#define _SKEIN_BLOCK_H_
#include "skein_base.h" /* get Skein macros and types */
/*
-***************** Pre-computed Skein IVs *******************
-**
-** NOTE: these values are not "magic" constants, but
-** are generated using the Threefish block function.
-** They are pre-computed here only for speed; i.e., to
-** avoid the need for a Threefish call during Init().
-**
-** The IV for any fixed hash length may be pre-computed.
-** Only the most common values are included here.
-**
-************************************************************
-**/
+ **************** Pre-computed Skein IVs *******************
+ *
+ * NOTE: these values are not "magic" constants, but
+ * are generated using the Threefish block function.
+ * They are pre-computed here only for speed; i.e., to
+ * avoid the need for a Threefish call during Init().
+ *
+ * The IV for any fixed hash length may be pre-computed.
+ * Only the most common values are included here.
+ *
+ ***********************************************************
+ */
#define MK_64 SKEIN_MK_64
chip = SM750LE;
pr_info("found sm750le\n");
}
- } else
+ } else {
chip = SM_UNKNOWN;
+ }
}
static unsigned int get_mxclk_freq(void)
if (sm750_get_chip_type() == SM750LE)
return MHz(130);
- pll_reg = PEEK32(MXCLK_PLL_CTRL);
+ pll_reg = peek32(MXCLK_PLL_CTRL);
M = (pll_reg & PLL_CTRL_M_MASK) >> PLL_CTRL_M_SHIFT;
N = (pll_reg & PLL_CTRL_N_MASK) >> PLL_CTRL_M_SHIFT;
OD = (pll_reg & PLL_CTRL_OD_MASK) >> PLL_CTRL_OD_SHIFT;
ulActualMxClk = sm750_calc_pll_value(frequency, &pll);
/* Master Clock Control: MXCLK_PLL */
- POKE32(MXCLK_PLL_CTRL, sm750_format_pll_reg(&pll));
+ poke32(MXCLK_PLL_CTRL, sm750_format_pll_reg(&pll));
}
}
divisor = DIV_ROUND_CLOSEST(get_mxclk_freq(), frequency);
/* Set the corresponding divisor in the register. */
- reg = PEEK32(CURRENT_GATE) & ~CURRENT_GATE_M2XCLK_MASK;
+ reg = peek32(CURRENT_GATE) & ~CURRENT_GATE_M2XCLK_MASK;
switch (divisor) {
default:
case 1:
divisor = DIV_ROUND_CLOSEST(get_mxclk_freq(), frequency);
/* Set the corresponding divisor in the register. */
- reg = PEEK32(CURRENT_GATE) & ~CURRENT_GATE_MCLK_MASK;
+ reg = peek32(CURRENT_GATE) & ~CURRENT_GATE_MCLK_MASK;
switch (divisor) {
default:
case 3:
return SZ_64M;
/* for 750,always use power mode0*/
- reg = PEEK32(MODE0_GATE);
+ reg = peek32(MODE0_GATE);
reg |= MODE0_GATE_GPIO;
- POKE32(MODE0_GATE, reg);
+ poke32(MODE0_GATE, reg);
/* get frame buffer size from GPIO */
- reg = PEEK32(MISC_CTRL) & MISC_CTRL_LOCALMEM_SIZE_MASK;
+ reg = peek32(MISC_CTRL) & MISC_CTRL_LOCALMEM_SIZE_MASK;
switch (reg) {
case MISC_CTRL_LOCALMEM_SIZE_8M:
data = SZ_8M; break; /* 8 Mega byte */
sm750_set_power_mode(pInitParam->powerMode);
/* Enable display power gate & LOCALMEM power gate*/
- reg = PEEK32(CURRENT_GATE);
+ reg = peek32(CURRENT_GATE);
reg |= (CURRENT_GATE_DISPLAY | CURRENT_GATE_LOCALMEM);
sm750_set_current_gate(reg);
if (sm750_get_chip_type() != SM750LE) {
/* set panel pll and graphic mode via mmio_88 */
- reg = PEEK32(VGA_CONFIGURATION);
+ reg = peek32(VGA_CONFIGURATION);
reg |= (VGA_CONFIGURATION_PLL | VGA_CONFIGURATION_MODE);
- POKE32(VGA_CONFIGURATION, reg);
+ poke32(VGA_CONFIGURATION, reg);
} else {
#if defined(__i386__) || defined(__x86_64__)
/* set graphic mode via IO method */
/* Set up master clock */
set_master_clock(MHz(pInitParam->masterClock));
-
/*
* Reset the memory controller.
* If the memory controller is not reset in SM750,
* The memory should be resetted after changing the MXCLK.
*/
if (pInitParam->resetMemory == 1) {
- reg = PEEK32(MISC_CTRL);
+ reg = peek32(MISC_CTRL);
reg &= ~MISC_CTRL_LOCALMEM_RESET;
- POKE32(MISC_CTRL, reg);
+ poke32(MISC_CTRL, reg);
reg |= MISC_CTRL_LOCALMEM_RESET;
- POKE32(MISC_CTRL, reg);
+ poke32(MISC_CTRL, reg);
}
if (pInitParam->setAllEngOff == 1) {
sm750_enable_2d_engine(0);
/* Disable Overlay, if a former application left it on */
- reg = PEEK32(VIDEO_DISPLAY_CTRL);
+ reg = peek32(VIDEO_DISPLAY_CTRL);
reg &= ~DISPLAY_CTRL_PLANE;
- POKE32(VIDEO_DISPLAY_CTRL, reg);
+ poke32(VIDEO_DISPLAY_CTRL, reg);
/* Disable video alpha, if a former application left it on */
- reg = PEEK32(VIDEO_ALPHA_DISPLAY_CTRL);
+ reg = peek32(VIDEO_ALPHA_DISPLAY_CTRL);
reg &= ~DISPLAY_CTRL_PLANE;
- POKE32(VIDEO_ALPHA_DISPLAY_CTRL, reg);
+ poke32(VIDEO_ALPHA_DISPLAY_CTRL, reg);
/* Disable alpha plane, if a former application left it on */
- reg = PEEK32(ALPHA_DISPLAY_CTRL);
+ reg = peek32(ALPHA_DISPLAY_CTRL);
reg &= ~DISPLAY_CTRL_PLANE;
- POKE32(ALPHA_DISPLAY_CTRL, reg);
+ poke32(ALPHA_DISPLAY_CTRL, reg);
/* Disable DMA Channel, if a former application left it on */
- reg = PEEK32(DMA_ABORT_INTERRUPT);
+ reg = peek32(DMA_ABORT_INTERRUPT);
reg |= DMA_ABORT_INTERRUPT_ABORT_1;
- POKE32(DMA_ABORT_INTERRUPT, reg);
+ poke32(DMA_ABORT_INTERRUPT, reg);
/* Disable DMA Power, if a former application left it on */
sm750_enable_dma(0);
return reg;
}
-
-
#include <linux/ioport.h>
#include <linux/uaccess.h>
+extern void __iomem *mmio750;
+
/* software control endianness */
-#define PEEK32(addr) readl(addr + mmio750)
-#define POKE32(addr, data) writel(data, addr + mmio750)
+static inline u32 peek32(u32 addr)
+{
+ return readl(addr + mmio750);
+}
-extern void __iomem *mmio750;
+static inline void poke32(u32 data, u32 addr)
+{
+ writel(data, addr + mmio750);
+}
/* This is all the chips recognized by this library */
typedef enum _logical_chip_type_t {
reserved = CRT_DISPLAY_CTRL_RESERVED_MASK;
}
- val = PEEK32(reg);
+ val = peek32(reg);
if (disp_state) {
/*
* Timing should be enabled first before enabling the
* disabled.
*/
val |= DISPLAY_CTRL_TIMING;
- POKE32(reg, val);
+ poke32(reg, val);
val |= DISPLAY_CTRL_PLANE;
*/
do {
cnt++;
- POKE32(reg, val);
- } while ((PEEK32(reg) & ~reserved) != (val & ~reserved));
+ poke32(reg, val);
+ } while ((peek32(reg) & ~reserved) != (val & ~reserved));
pr_debug("Set Plane enbit:after tried %d times\n", cnt);
} else {
/*
* before modifying the timing enable bit.
*/
val &= ~DISPLAY_CTRL_PLANE;
- POKE32(reg, val);
+ poke32(reg, val);
val &= ~DISPLAY_CTRL_TIMING;
- POKE32(reg, val);
+ poke32(reg, val);
}
}
* Do not wait when the Primary PLL is off or display control is
* already off. This will prevent the software to wait forever.
*/
- if (!(PEEK32(PANEL_PLL_CTRL) & PLL_CTRL_POWER) ||
- !(PEEK32(PANEL_DISPLAY_CTRL) & DISPLAY_CTRL_TIMING))
+ if (!(peek32(PANEL_PLL_CTRL) & PLL_CTRL_POWER) ||
+ !(peek32(PANEL_DISPLAY_CTRL) & DISPLAY_CTRL_TIMING))
return;
while (delay-- > 0) {
/* Wait for end of vsync. */
do {
- status = PEEK32(SYSTEM_CTRL);
+ status = peek32(SYSTEM_CTRL);
} while (status & SYSTEM_CTRL_PANEL_VSYNC_ACTIVE);
/* Wait for start of vsync. */
do {
- status = PEEK32(SYSTEM_CTRL);
+ status = peek32(SYSTEM_CTRL);
} while (!(status & SYSTEM_CTRL_PANEL_VSYNC_ACTIVE));
}
}
unsigned int reg;
/* disp should be 1 to open sequence */
- reg = PEEK32(PANEL_DISPLAY_CTRL);
+ reg = peek32(PANEL_DISPLAY_CTRL);
reg |= (disp ? PANEL_DISPLAY_CTRL_FPEN : 0);
- POKE32(PANEL_DISPLAY_CTRL, reg);
+ poke32(PANEL_DISPLAY_CTRL, reg);
primary_wait_vertical_sync(delay);
- reg = PEEK32(PANEL_DISPLAY_CTRL);
+ reg = peek32(PANEL_DISPLAY_CTRL);
reg |= (disp ? PANEL_DISPLAY_CTRL_DATA : 0);
- POKE32(PANEL_DISPLAY_CTRL, reg);
+ poke32(PANEL_DISPLAY_CTRL, reg);
primary_wait_vertical_sync(delay);
- reg = PEEK32(PANEL_DISPLAY_CTRL);
+ reg = peek32(PANEL_DISPLAY_CTRL);
reg |= (disp ? PANEL_DISPLAY_CTRL_VBIASEN : 0);
- POKE32(PANEL_DISPLAY_CTRL, reg);
+ poke32(PANEL_DISPLAY_CTRL, reg);
primary_wait_vertical_sync(delay);
- reg = PEEK32(PANEL_DISPLAY_CTRL);
+ reg = peek32(PANEL_DISPLAY_CTRL);
reg |= (disp ? PANEL_DISPLAY_CTRL_FPEN : 0);
- POKE32(PANEL_DISPLAY_CTRL, reg);
+ poke32(PANEL_DISPLAY_CTRL, reg);
primary_wait_vertical_sync(delay);
}
if (output & PNL_2_USAGE) {
/* set panel path controller select */
- reg = PEEK32(PANEL_DISPLAY_CTRL);
+ reg = peek32(PANEL_DISPLAY_CTRL);
reg &= ~PANEL_DISPLAY_CTRL_SELECT_MASK;
reg |= (((output & PNL_2_MASK) >> PNL_2_OFFSET) <<
PANEL_DISPLAY_CTRL_SELECT_SHIFT);
- POKE32(PANEL_DISPLAY_CTRL, reg);
+ poke32(PANEL_DISPLAY_CTRL, reg);
}
if (output & CRT_2_USAGE) {
/* set crt path controller select */
- reg = PEEK32(CRT_DISPLAY_CTRL);
+ reg = peek32(CRT_DISPLAY_CTRL);
reg &= ~CRT_DISPLAY_CTRL_SELECT_MASK;
reg |= (((output & CRT_2_MASK) >> CRT_2_OFFSET) <<
CRT_DISPLAY_CTRL_SELECT_SHIFT);
/*se blank off */
reg &= ~CRT_DISPLAY_CTRL_BLANK;
- POKE32(CRT_DISPLAY_CTRL, reg);
+ poke32(CRT_DISPLAY_CTRL, reg);
}
if (output & PRI_TP_USAGE) {
unsigned int value;
/* Enable GPIO 30 & 31 as IIC clock & data */
- value = PEEK32(GPIO_MUX);
+ value = peek32(GPIO_MUX);
value |= (GPIO_MUX_30 | GPIO_MUX_31);
- POKE32(GPIO_MUX, value);
+ poke32(GPIO_MUX, value);
/*
* Enable Hardware I2C power.
sm750_enable_i2c(1);
/* Enable the I2C Controller and set the bus speed mode */
- value = PEEK32(I2C_CTRL) & ~(I2C_CTRL_MODE | I2C_CTRL_EN);
+ value = peek32(I2C_CTRL) & ~(I2C_CTRL_MODE | I2C_CTRL_EN);
if (bus_speed_mode)
value |= I2C_CTRL_MODE;
value |= I2C_CTRL_EN;
- POKE32(I2C_CTRL, value);
+ poke32(I2C_CTRL, value);
return 0;
}
unsigned int value;
/* Disable I2C controller */
- value = PEEK32(I2C_CTRL) & ~I2C_CTRL_EN;
- POKE32(I2C_CTRL, value);
+ value = peek32(I2C_CTRL) & ~I2C_CTRL_EN;
+ poke32(I2C_CTRL, value);
/* Disable I2C Power */
sm750_enable_i2c(0);
/* Set GPIO 30 & 31 back as GPIO pins */
- value = PEEK32(GPIO_MUX);
+ value = peek32(GPIO_MUX);
value &= ~GPIO_MUX_30;
value &= ~GPIO_MUX_31;
- POKE32(GPIO_MUX, value);
+ poke32(GPIO_MUX, value);
}
static long hw_i2c_wait_tx_done(void)
/* Wait until the transfer is completed. */
timeout = HWI2C_WAIT_TIMEOUT;
- while (!(PEEK32(I2C_STATUS) & I2C_STATUS_TX) && (timeout != 0))
+ while (!(peek32(I2C_STATUS) & I2C_STATUS_TX) && (timeout != 0))
timeout--;
if (timeout == 0)
unsigned int total_bytes = 0;
/* Set the Device Address */
- POKE32(I2C_SLAVE_ADDRESS, addr & ~0x01);
+ poke32(I2C_SLAVE_ADDRESS, addr & ~0x01);
/*
* Write data.
* Reset I2C by writing 0 to I2C_RESET register to
* clear the previous status.
*/
- POKE32(I2C_RESET, 0);
+ poke32(I2C_RESET, 0);
/* Set the number of bytes to be written */
if (length < MAX_HWI2C_FIFO)
count = length - 1;
else
count = MAX_HWI2C_FIFO - 1;
- POKE32(I2C_BYTE_COUNT, count);
+ poke32(I2C_BYTE_COUNT, count);
/* Move the data to the I2C data register */
for (i = 0; i <= count; i++)
- POKE32(I2C_DATA0 + i, *buf++);
+ poke32(I2C_DATA0 + i, *buf++);
/* Start the I2C */
- POKE32(I2C_CTRL, PEEK32(I2C_CTRL) | I2C_CTRL_CTRL);
+ poke32(I2C_CTRL, peek32(I2C_CTRL) | I2C_CTRL_CTRL);
/* Wait until the transfer is completed. */
if (hw_i2c_wait_tx_done() != 0)
unsigned int total_bytes = 0;
/* Set the Device Address */
- POKE32(I2C_SLAVE_ADDRESS, addr | 0x01);
+ poke32(I2C_SLAVE_ADDRESS, addr | 0x01);
/*
* Read data and save them to the buffer.
* Reset I2C by writing 0 to I2C_RESET register to
* clear all the status.
*/
- POKE32(I2C_RESET, 0);
+ poke32(I2C_RESET, 0);
/* Set the number of bytes to be read */
if (length <= MAX_HWI2C_FIFO)
count = length - 1;
else
count = MAX_HWI2C_FIFO - 1;
- POKE32(I2C_BYTE_COUNT, count);
+ poke32(I2C_BYTE_COUNT, count);
/* Start the I2C */
- POKE32(I2C_CTRL, PEEK32(I2C_CTRL) | I2C_CTRL_CTRL);
+ poke32(I2C_CTRL, peek32(I2C_CTRL) | I2C_CTRL_CTRL);
/* Wait until transaction done. */
if (hw_i2c_wait_tx_done() != 0)
/* Save the data to the given buffer */
for (i = 0; i <= count; i++)
- *buf++ = PEEK32(I2C_DATA0 + i);
+ *buf++ = peek32(I2C_DATA0 + i);
/* Subtract length by 16 */
length -= (count + 1);
* Note that normal SM750/SM718 only use those two register for
* auto-centering mode.
*/
- POKE32(CRT_AUTO_CENTERING_TL, 0);
+ poke32(CRT_AUTO_CENTERING_TL, 0);
- POKE32(CRT_AUTO_CENTERING_BR,
+ poke32(CRT_AUTO_CENTERING_BR,
(((y - 1) << CRT_AUTO_CENTERING_BR_BOTTOM_SHIFT) &
CRT_AUTO_CENTERING_BR_BOTTOM_MASK) |
((x - 1) & CRT_AUTO_CENTERING_BR_RIGHT_MASK));
/* Set bit 14 of display controller */
dispControl |= DISPLAY_CTRL_CLOCK_PHASE;
- POKE32(CRT_DISPLAY_CTRL, dispControl);
+ poke32(CRT_DISPLAY_CTRL, dispControl);
return dispControl;
}
if (pll->clockType == SECONDARY_PLL) {
/* programe secondary pixel clock */
- POKE32(CRT_PLL_CTRL, sm750_format_pll_reg(pll));
- POKE32(CRT_HORIZONTAL_TOTAL,
+ poke32(CRT_PLL_CTRL, sm750_format_pll_reg(pll));
+ poke32(CRT_HORIZONTAL_TOTAL,
(((pModeParam->horizontal_total - 1) <<
CRT_HORIZONTAL_TOTAL_TOTAL_SHIFT) &
CRT_HORIZONTAL_TOTAL_TOTAL_MASK) |
((pModeParam->horizontal_display_end - 1) &
CRT_HORIZONTAL_TOTAL_DISPLAY_END_MASK));
- POKE32(CRT_HORIZONTAL_SYNC,
+ poke32(CRT_HORIZONTAL_SYNC,
((pModeParam->horizontal_sync_width <<
CRT_HORIZONTAL_SYNC_WIDTH_SHIFT) &
CRT_HORIZONTAL_SYNC_WIDTH_MASK) |
((pModeParam->horizontal_sync_start - 1) &
CRT_HORIZONTAL_SYNC_START_MASK));
- POKE32(CRT_VERTICAL_TOTAL,
+ poke32(CRT_VERTICAL_TOTAL,
(((pModeParam->vertical_total - 1) <<
CRT_VERTICAL_TOTAL_TOTAL_SHIFT) &
CRT_VERTICAL_TOTAL_TOTAL_MASK) |
((pModeParam->vertical_display_end - 1) &
CRT_VERTICAL_TOTAL_DISPLAY_END_MASK));
- POKE32(CRT_VERTICAL_SYNC,
+ poke32(CRT_VERTICAL_SYNC,
((pModeParam->vertical_sync_height <<
CRT_VERTICAL_SYNC_HEIGHT_SHIFT) &
CRT_VERTICAL_SYNC_HEIGHT_MASK) |
if (sm750_get_chip_type() == SM750LE) {
displayControlAdjust_SM750LE(pModeParam, tmp);
} else {
- reg = PEEK32(CRT_DISPLAY_CTRL) &
+ reg = peek32(CRT_DISPLAY_CTRL) &
~(DISPLAY_CTRL_VSYNC_PHASE |
DISPLAY_CTRL_HSYNC_PHASE |
DISPLAY_CTRL_TIMING | DISPLAY_CTRL_PLANE);
- POKE32(CRT_DISPLAY_CTRL, tmp | reg);
+ poke32(CRT_DISPLAY_CTRL, tmp | reg);
}
} else if (pll->clockType == PRIMARY_PLL) {
unsigned int reserved;
- POKE32(PANEL_PLL_CTRL, sm750_format_pll_reg(pll));
+ poke32(PANEL_PLL_CTRL, sm750_format_pll_reg(pll));
reg = ((pModeParam->horizontal_total - 1) <<
PANEL_HORIZONTAL_TOTAL_TOTAL_SHIFT) &
PANEL_HORIZONTAL_TOTAL_TOTAL_MASK;
reg |= ((pModeParam->horizontal_display_end - 1) &
PANEL_HORIZONTAL_TOTAL_DISPLAY_END_MASK);
- POKE32(PANEL_HORIZONTAL_TOTAL, reg);
+ poke32(PANEL_HORIZONTAL_TOTAL, reg);
- POKE32(PANEL_HORIZONTAL_SYNC,
+ poke32(PANEL_HORIZONTAL_SYNC,
((pModeParam->horizontal_sync_width <<
PANEL_HORIZONTAL_SYNC_WIDTH_SHIFT) &
PANEL_HORIZONTAL_SYNC_WIDTH_MASK) |
((pModeParam->horizontal_sync_start - 1) &
PANEL_HORIZONTAL_SYNC_START_MASK));
- POKE32(PANEL_VERTICAL_TOTAL,
+ poke32(PANEL_VERTICAL_TOTAL,
(((pModeParam->vertical_total - 1) <<
PANEL_VERTICAL_TOTAL_TOTAL_SHIFT) &
PANEL_VERTICAL_TOTAL_TOTAL_MASK) |
((pModeParam->vertical_display_end - 1) &
PANEL_VERTICAL_TOTAL_DISPLAY_END_MASK));
- POKE32(PANEL_VERTICAL_SYNC,
+ poke32(PANEL_VERTICAL_SYNC,
((pModeParam->vertical_sync_height <<
PANEL_VERTICAL_SYNC_HEIGHT_SHIFT) &
PANEL_VERTICAL_SYNC_HEIGHT_MASK) |
reserved = PANEL_DISPLAY_CTRL_RESERVED_MASK |
PANEL_DISPLAY_CTRL_VSYNC;
- reg = (PEEK32(PANEL_DISPLAY_CTRL) & ~reserved) &
+ reg = (peek32(PANEL_DISPLAY_CTRL) & ~reserved) &
~(DISPLAY_CTRL_CLOCK_PHASE | DISPLAY_CTRL_VSYNC_PHASE |
DISPLAY_CTRL_HSYNC_PHASE | DISPLAY_CTRL_TIMING |
DISPLAY_CTRL_PLANE);
* Note: This problem happens by design. The hardware will wait
* for the next vertical sync to turn on/off the plane.
*/
- POKE32(PANEL_DISPLAY_CTRL, tmp | reg);
+ poke32(PANEL_DISPLAY_CTRL, tmp | reg);
- while ((PEEK32(PANEL_DISPLAY_CTRL) & ~reserved) !=
+ while ((peek32(PANEL_DISPLAY_CTRL) & ~reserved) !=
(tmp | reg)) {
cnt++;
if (cnt > 1000)
break;
- POKE32(PANEL_DISPLAY_CTRL, tmp | reg);
+ poke32(PANEL_DISPLAY_CTRL, tmp | reg);
}
} else {
ret = -1;
unsigned int value;
if (sm750_get_chip_type() == SM750LE) {
- value = PEEK32(CRT_DISPLAY_CTRL) & ~CRT_DISPLAY_CTRL_DPMS_MASK;
+ value = peek32(CRT_DISPLAY_CTRL) & ~CRT_DISPLAY_CTRL_DPMS_MASK;
value |= (state << CRT_DISPLAY_CTRL_DPMS_SHIFT);
- POKE32(CRT_DISPLAY_CTRL, value);
+ poke32(CRT_DISPLAY_CTRL, value);
} else {
- value = PEEK32(SYSTEM_CTRL);
+ value = peek32(SYSTEM_CTRL);
value = (value & ~SYSTEM_CTRL_DPMS_MASK) | state;
- POKE32(SYSTEM_CTRL, value);
+ poke32(SYSTEM_CTRL, value);
}
}
{
if (sm750_get_chip_type() == SM750LE)
return 0;
- return PEEK32(POWER_MODE_CTRL) & POWER_MODE_CTRL_MODE_MASK;
+ return peek32(POWER_MODE_CTRL) & POWER_MODE_CTRL_MODE_MASK;
}
{
unsigned int ctrl = 0;
- ctrl = PEEK32(POWER_MODE_CTRL) & ~POWER_MODE_CTRL_MODE_MASK;
+ ctrl = peek32(POWER_MODE_CTRL) & ~POWER_MODE_CTRL_MODE_MASK;
if (sm750_get_chip_type() == SM750LE)
return;
}
/* Program new power mode. */
- POKE32(POWER_MODE_CTRL, ctrl);
+ poke32(POWER_MODE_CTRL, ctrl);
}
void sm750_set_current_gate(unsigned int gate)
{
if (get_power_mode() == POWER_MODE_CTRL_MODE_MODE1)
- POKE32(MODE1_GATE, gate);
+ poke32(MODE1_GATE, gate);
else
- POKE32(MODE0_GATE, gate);
+ poke32(MODE0_GATE, gate);
}
{
u32 gate;
- gate = PEEK32(CURRENT_GATE);
+ gate = peek32(CURRENT_GATE);
if (enable)
gate |= (CURRENT_GATE_DE | CURRENT_GATE_CSC);
else
u32 gate;
/* Enable DMA Gate */
- gate = PEEK32(CURRENT_GATE);
+ gate = peek32(CURRENT_GATE);
if (enable)
gate |= CURRENT_GATE_DMA;
else
u32 gate;
/* Enable GPIO Gate */
- gate = PEEK32(CURRENT_GATE);
+ gate = peek32(CURRENT_GATE);
if (enable)
gate |= CURRENT_GATE_GPIO;
else
u32 gate;
/* Enable I2C Gate */
- gate = PEEK32(CURRENT_GATE);
+ gate = peek32(CURRENT_GATE);
if (enable)
gate |= CURRENT_GATE_I2C;
else
DPMS_t;
#define setDAC(off) { \
- POKE32(MISC_CTRL, \
- (PEEK32(MISC_CTRL) & ~MISC_CTRL_DAC_POWER_OFF) | (off)); \
+ poke32(MISC_CTRL, \
+ (peek32(MISC_CTRL) & ~MISC_CTRL_DAC_POWER_OFF) | (off)); \
}
void ddk750_set_dpms(DPMS_t);
unsigned long gpio_data;
unsigned long gpio_dir;
- gpio_dir = PEEK32(sw_i2c_clk_gpio_data_dir_reg);
+ gpio_dir = peek32(sw_i2c_clk_gpio_data_dir_reg);
if (value) { /* High */
/*
* Set direction as input. This will automatically
* pull the signal up.
*/
gpio_dir &= ~(1 << sw_i2c_clk_gpio);
- POKE32(sw_i2c_clk_gpio_data_dir_reg, gpio_dir);
+ poke32(sw_i2c_clk_gpio_data_dir_reg, gpio_dir);
} else { /* Low */
/* Set the signal down */
- gpio_data = PEEK32(sw_i2c_clk_gpio_data_reg);
+ gpio_data = peek32(sw_i2c_clk_gpio_data_reg);
gpio_data &= ~(1 << sw_i2c_clk_gpio);
- POKE32(sw_i2c_clk_gpio_data_reg, gpio_data);
+ poke32(sw_i2c_clk_gpio_data_reg, gpio_data);
/* Set direction as output */
gpio_dir |= (1 << sw_i2c_clk_gpio);
- POKE32(sw_i2c_clk_gpio_data_dir_reg, gpio_dir);
+ poke32(sw_i2c_clk_gpio_data_dir_reg, gpio_dir);
}
}
unsigned long gpio_data;
unsigned long gpio_dir;
- gpio_dir = PEEK32(sw_i2c_data_gpio_data_dir_reg);
+ gpio_dir = peek32(sw_i2c_data_gpio_data_dir_reg);
if (value) { /* High */
/*
* Set direction as input. This will automatically
* pull the signal up.
*/
gpio_dir &= ~(1 << sw_i2c_data_gpio);
- POKE32(sw_i2c_data_gpio_data_dir_reg, gpio_dir);
+ poke32(sw_i2c_data_gpio_data_dir_reg, gpio_dir);
} else { /* Low */
/* Set the signal down */
- gpio_data = PEEK32(sw_i2c_data_gpio_data_reg);
+ gpio_data = peek32(sw_i2c_data_gpio_data_reg);
gpio_data &= ~(1 << sw_i2c_data_gpio);
- POKE32(sw_i2c_data_gpio_data_reg, gpio_data);
+ poke32(sw_i2c_data_gpio_data_reg, gpio_data);
/* Set direction as output */
gpio_dir |= (1 << sw_i2c_data_gpio);
- POKE32(sw_i2c_data_gpio_data_dir_reg, gpio_dir);
+ poke32(sw_i2c_data_gpio_data_dir_reg, gpio_dir);
}
}
unsigned long dir_mask = 1 << sw_i2c_data_gpio;
/* Make sure that the direction is input (High) */
- gpio_dir = PEEK32(sw_i2c_data_gpio_data_dir_reg);
+ gpio_dir = peek32(sw_i2c_data_gpio_data_dir_reg);
if ((gpio_dir & dir_mask) != ~dir_mask) {
gpio_dir &= ~(1 << sw_i2c_data_gpio);
- POKE32(sw_i2c_data_gpio_data_dir_reg, gpio_dir);
+ poke32(sw_i2c_data_gpio_data_dir_reg, gpio_dir);
}
/* Now read the SDA line */
- gpio_data = PEEK32(sw_i2c_data_gpio_data_reg);
+ gpio_data = peek32(sw_i2c_data_gpio_data_reg);
if (gpio_data & (1 << sw_i2c_data_gpio))
return 1;
else
sw_i2c_data_gpio = data_gpio;
/* Enable the GPIO pins for the i2c Clock and Data (GPIO MUX) */
- POKE32(sw_i2c_clk_gpio_mux_reg,
- PEEK32(sw_i2c_clk_gpio_mux_reg) & ~(1 << sw_i2c_clk_gpio));
- POKE32(sw_i2c_data_gpio_mux_reg,
- PEEK32(sw_i2c_data_gpio_mux_reg) & ~(1 << sw_i2c_data_gpio));
+ poke32(sw_i2c_clk_gpio_mux_reg,
+ peek32(sw_i2c_clk_gpio_mux_reg) & ~(1 << sw_i2c_clk_gpio));
+ poke32(sw_i2c_data_gpio_mux_reg,
+ peek32(sw_i2c_data_gpio_mux_reg) & ~(1 << sw_i2c_data_gpio));
/* Enable GPIO power */
sm750_enable_gpio(1);
FB_VMODE_NONINTERLACED},
};
-
/* no hardware cursor supported under version 2.6.10, kernel bug */
static int lynxfb_ops_cursor(struct fb_info *info, struct fb_cursor *fbcursor)
{
else {
if (!g_fbmode[0]) {
g_fbmode[0] = opt;
- dev_info(&sm750_dev->pdev->dev, "find fbmode0 : %s\n", g_fbmode[0]);
+ dev_info(&sm750_dev->pdev->dev,
+ "find fbmode0 : %s\n", g_fbmode[0]);
} else if (!g_fbmode[1]) {
g_fbmode[1] = opt;
- dev_info(&sm750_dev->pdev->dev, "find fbmode1 : %s\n", g_fbmode[1]);
+ dev_info(&sm750_dev->pdev->dev,
+ "find fbmode1 : %s\n", g_fbmode[1]);
} else {
dev_warn(&sm750_dev->pdev->dev, "How many view you wann set?\n");
}
-#define POKE32(addr, data) \
+#define poke32(addr, data) \
writel((data), cursor->mmio + (addr))
/* cursor control for voyager and 718/750*/
u32 reg;
reg = (cursor->offset & HWC_ADDRESS_ADDRESS_MASK) | HWC_ADDRESS_ENABLE;
- POKE32(HWC_ADDRESS, reg);
+ poke32(HWC_ADDRESS, reg);
}
void sm750_hw_cursor_disable(struct lynx_cursor *cursor)
{
- POKE32(HWC_ADDRESS, 0);
+ poke32(HWC_ADDRESS, 0);
}
void sm750_hw_cursor_setSize(struct lynx_cursor *cursor,
reg = (((y << HWC_LOCATION_Y_SHIFT) & HWC_LOCATION_Y_MASK) |
(x & HWC_LOCATION_X_MASK));
- POKE32(HWC_LOCATION, reg);
+ poke32(HWC_LOCATION, reg);
}
void sm750_hw_cursor_setColor(struct lynx_cursor *cursor,
u32 fg, u32 bg)
u32 reg = (fg << HWC_COLOR_12_2_RGB565_SHIFT) &
HWC_COLOR_12_2_RGB565_MASK;
- POKE32(HWC_COLOR_12, reg | (bg & HWC_COLOR_12_1_RGB565_MASK));
- POKE32(HWC_COLOR_3, 0xffe0);
+ poke32(HWC_COLOR_12, reg | (bg & HWC_COLOR_12_1_RGB565_MASK));
+ poke32(HWC_COLOR_3, 0xffe0);
}
void sm750_hw_cursor_setData(struct lynx_cursor *cursor,
ddk750_init_hw((struct initchip_param *)&sm750_dev->initParm);
/* for sm718, open pci burst */
if (sm750_dev->devid == 0x718) {
- POKE32(SYSTEM_CTRL,
- PEEK32(SYSTEM_CTRL) | SYSTEM_CTRL_PCI_BURST);
+ poke32(SYSTEM_CTRL,
+ peek32(SYSTEM_CTRL) | SYSTEM_CTRL_PCI_BURST);
}
if (sm750_get_chip_type() != SM750LE) {
unsigned int val;
/* does user need CRT? */
if (sm750_dev->nocrt) {
- POKE32(MISC_CTRL,
- PEEK32(MISC_CTRL) | MISC_CTRL_DAC_POWER_OFF);
+ poke32(MISC_CTRL,
+ peek32(MISC_CTRL) | MISC_CTRL_DAC_POWER_OFF);
/* shut off dpms */
- val = PEEK32(SYSTEM_CTRL) & ~SYSTEM_CTRL_DPMS_MASK;
+ val = peek32(SYSTEM_CTRL) & ~SYSTEM_CTRL_DPMS_MASK;
val |= SYSTEM_CTRL_DPMS_VPHN;
- POKE32(SYSTEM_CTRL, val);
+ poke32(SYSTEM_CTRL, val);
} else {
- POKE32(MISC_CTRL,
- PEEK32(MISC_CTRL) & ~MISC_CTRL_DAC_POWER_OFF);
+ poke32(MISC_CTRL,
+ peek32(MISC_CTRL) & ~MISC_CTRL_DAC_POWER_OFF);
/* turn on dpms */
- val = PEEK32(SYSTEM_CTRL) & ~SYSTEM_CTRL_DPMS_MASK;
+ val = peek32(SYSTEM_CTRL) & ~SYSTEM_CTRL_DPMS_MASK;
val |= SYSTEM_CTRL_DPMS_VPHP;
- POKE32(SYSTEM_CTRL, val);
+ poke32(SYSTEM_CTRL, val);
}
- val = PEEK32(PANEL_DISPLAY_CTRL) &
+ val = peek32(PANEL_DISPLAY_CTRL) &
~(PANEL_DISPLAY_CTRL_DUAL_DISPLAY |
PANEL_DISPLAY_CTRL_DOUBLE_PIXEL);
switch (sm750_dev->pnltype) {
val |= PANEL_DISPLAY_CTRL_DUAL_DISPLAY;
break;
}
- POKE32(PANEL_DISPLAY_CTRL, val);
+ poke32(PANEL_DISPLAY_CTRL, val);
} else {
/*
* for 750LE, no DVI chip initialization
/* just open DISPLAY_CONTROL_750LE register bit 3:0 */
u32 reg;
- reg = PEEK32(DISPLAY_CONTROL_750LE);
+ reg = peek32(DISPLAY_CONTROL_750LE);
reg |= 0xf;
- POKE32(DISPLAY_CONTROL_750LE, reg);
+ poke32(DISPLAY_CONTROL_750LE, reg);
}
pr_info("ddk setlogicdispout done\n");
if (crtc->channel != sm750_secondary) {
/* set pitch, offset, width, start address, etc... */
- POKE32(PANEL_FB_ADDRESS,
+ poke32(PANEL_FB_ADDRESS,
crtc->oScreen & PANEL_FB_ADDRESS_ADDRESS_MASK);
reg = var->xres * (var->bits_per_pixel >> 3);
reg = (reg << PANEL_FB_WIDTH_WIDTH_SHIFT) &
PANEL_FB_WIDTH_WIDTH_MASK;
reg |= (fix->line_length & PANEL_FB_WIDTH_OFFSET_MASK);
- POKE32(PANEL_FB_WIDTH, reg);
+ poke32(PANEL_FB_WIDTH, reg);
reg = ((var->xres - 1) << PANEL_WINDOW_WIDTH_WIDTH_SHIFT) &
PANEL_WINDOW_WIDTH_WIDTH_MASK;
reg |= (var->xoffset & PANEL_WINDOW_WIDTH_X_MASK);
- POKE32(PANEL_WINDOW_WIDTH, reg);
+ poke32(PANEL_WINDOW_WIDTH, reg);
reg = (var->yres_virtual - 1) <<
PANEL_WINDOW_HEIGHT_HEIGHT_SHIFT;
reg &= PANEL_WINDOW_HEIGHT_HEIGHT_MASK;
reg |= (var->yoffset & PANEL_WINDOW_HEIGHT_Y_MASK);
- POKE32(PANEL_WINDOW_HEIGHT, reg);
+ poke32(PANEL_WINDOW_HEIGHT, reg);
- POKE32(PANEL_PLANE_TL, 0);
+ poke32(PANEL_PLANE_TL, 0);
reg = ((var->yres - 1) << PANEL_PLANE_BR_BOTTOM_SHIFT) &
PANEL_PLANE_BR_BOTTOM_MASK;
reg |= ((var->xres - 1) & PANEL_PLANE_BR_RIGHT_MASK);
- POKE32(PANEL_PLANE_BR, reg);
+ poke32(PANEL_PLANE_BR, reg);
/* set pixel format */
- reg = PEEK32(PANEL_DISPLAY_CTRL);
- POKE32(PANEL_DISPLAY_CTRL, reg | (var->bits_per_pixel >> 4));
+ reg = peek32(PANEL_DISPLAY_CTRL);
+ poke32(PANEL_DISPLAY_CTRL, reg | (var->bits_per_pixel >> 4));
} else {
/* not implemented now */
- POKE32(CRT_FB_ADDRESS, crtc->oScreen);
+ poke32(CRT_FB_ADDRESS, crtc->oScreen);
reg = var->xres * (var->bits_per_pixel >> 3);
/*
* crtc->channel is not equal to par->index on numeric,
reg = ALIGN(reg, crtc->line_pad) << CRT_FB_WIDTH_WIDTH_SHIFT;
reg &= CRT_FB_WIDTH_WIDTH_MASK;
reg |= (fix->line_length & CRT_FB_WIDTH_OFFSET_MASK);
- POKE32(CRT_FB_WIDTH, reg);
+ poke32(CRT_FB_WIDTH, reg);
/* SET PIXEL FORMAT */
- reg = PEEK32(CRT_DISPLAY_CTRL);
+ reg = peek32(CRT_DISPLAY_CTRL);
reg |= ((var->bits_per_pixel >> 4) &
CRT_DISPLAY_CTRL_FORMAT_MASK);
- POKE32(CRT_DISPLAY_CTRL, reg);
+ poke32(CRT_DISPLAY_CTRL, reg);
}
exit:
{
static unsigned int add[] = {PANEL_PALETTE_RAM, CRT_PALETTE_RAM};
- POKE32(add[crtc->channel] + index * 4,
+ poke32(add[crtc->channel] + index * 4,
(red << 16) | (green << 8) | blue);
return 0;
}
if (output->paths & sm750_crt) {
unsigned int val;
- val = PEEK32(CRT_DISPLAY_CTRL) & ~CRT_DISPLAY_CTRL_DPMS_MASK;
- POKE32(CRT_DISPLAY_CTRL, val | dpms);
+ val = peek32(CRT_DISPLAY_CTRL) & ~CRT_DISPLAY_CTRL_DPMS_MASK;
+ poke32(CRT_DISPLAY_CTRL, val | dpms);
- val = PEEK32(CRT_DISPLAY_CTRL) & ~CRT_DISPLAY_CTRL_BLANK;
- POKE32(CRT_DISPLAY_CTRL, val | crtdb);
+ val = peek32(CRT_DISPLAY_CTRL) & ~CRT_DISPLAY_CTRL_BLANK;
+ poke32(CRT_DISPLAY_CTRL, val | crtdb);
}
return 0;
}
}
if (output->paths & sm750_crt) {
- unsigned int val = PEEK32(SYSTEM_CTRL) & ~SYSTEM_CTRL_DPMS_MASK;
+ unsigned int val = peek32(SYSTEM_CTRL) & ~SYSTEM_CTRL_DPMS_MASK;
- POKE32(SYSTEM_CTRL, val | dpms);
+ poke32(SYSTEM_CTRL, val | dpms);
- val = PEEK32(CRT_DISPLAY_CTRL) & ~CRT_DISPLAY_CTRL_BLANK;
- POKE32(CRT_DISPLAY_CTRL, val | crtdb);
+ val = peek32(CRT_DISPLAY_CTRL) & ~CRT_DISPLAY_CTRL_BLANK;
+ poke32(CRT_DISPLAY_CTRL, val | crtdb);
}
if (output->paths & sm750_panel) {
- unsigned int val = PEEK32(PANEL_DISPLAY_CTRL);
+ unsigned int val = peek32(PANEL_DISPLAY_CTRL);
val &= ~PANEL_DISPLAY_CTRL_DATA;
val |= pps;
- POKE32(PANEL_DISPLAY_CTRL, val);
+ poke32(PANEL_DISPLAY_CTRL, val);
}
return 0;
sm750_enable_2d_engine(1);
if (sm750_get_chip_type() == SM750LE) {
- reg = PEEK32(DE_STATE1);
+ reg = peek32(DE_STATE1);
reg |= DE_STATE1_DE_ABORT;
- POKE32(DE_STATE1, reg);
+ poke32(DE_STATE1, reg);
- reg = PEEK32(DE_STATE1);
+ reg = peek32(DE_STATE1);
reg &= ~DE_STATE1_DE_ABORT;
- POKE32(DE_STATE1, reg);
+ poke32(DE_STATE1, reg);
} else {
/* engine reset */
- reg = PEEK32(SYSTEM_CTRL);
+ reg = peek32(SYSTEM_CTRL);
reg |= SYSTEM_CTRL_DE_ABORT;
- POKE32(SYSTEM_CTRL, reg);
+ poke32(SYSTEM_CTRL, reg);
- reg = PEEK32(SYSTEM_CTRL);
+ reg = peek32(SYSTEM_CTRL);
reg &= ~SYSTEM_CTRL_DE_ABORT;
- POKE32(SYSTEM_CTRL, reg);
+ poke32(SYSTEM_CTRL, reg);
}
/* call 2d init */
DE_STATE2_DE_MEM_FIFO_EMPTY;
while (i--) {
- unsigned int val = PEEK32(DE_STATE2);
+ unsigned int val = peek32(DE_STATE2);
if ((val & mask) ==
(DE_STATE2_DE_FIFO_EMPTY | DE_STATE2_DE_MEM_FIFO_EMPTY))
SYSTEM_CTRL_DE_MEM_FIFO_EMPTY;
while (i--) {
- unsigned int val = PEEK32(SYSTEM_CTRL);
+ unsigned int val = peek32(SYSTEM_CTRL);
if ((val & mask) ==
(SYSTEM_CTRL_DE_FIFO_EMPTY | SYSTEM_CTRL_DE_MEM_FIFO_EMPTY))
((var->xoffset * var->bits_per_pixel) >> 3);
total += crtc->oScreen;
if (crtc->channel == sm750_primary) {
- POKE32(PANEL_FB_ADDRESS,
- PEEK32(PANEL_FB_ADDRESS) |
+ poke32(PANEL_FB_ADDRESS,
+ peek32(PANEL_FB_ADDRESS) |
(total & PANEL_FB_ADDRESS_ADDRESS_MASK));
} else {
- POKE32(CRT_FB_ADDRESS,
- PEEK32(CRT_FB_ADDRESS) |
+ poke32(CRT_FB_ADDRESS,
+ peek32(CRT_FB_ADDRESS) |
(total & CRT_FB_ADDRESS_ADDRESS_MASK));
}
return 0;
__ATTR_RO(version);
static struct kobj_attribute delimiters_attribute =
- __ATTR(delimiters, S_IWUSR | S_IRUGO, punc_show, punc_store);
+ __ATTR(delimiters, 0644, punc_show, punc_store);
static struct kobj_attribute ex_num_attribute =
- __ATTR(ex_num, S_IWUSR | S_IRUGO, punc_show, punc_store);
+ __ATTR(ex_num, 0644, punc_show, punc_store);
static struct kobj_attribute punc_all_attribute =
- __ATTR(punc_all, S_IWUSR | S_IRUGO, punc_show, punc_store);
+ __ATTR(punc_all, 0644, punc_show, punc_store);
static struct kobj_attribute punc_most_attribute =
- __ATTR(punc_most, S_IWUSR | S_IRUGO, punc_show, punc_store);
+ __ATTR(punc_most, 0644, punc_show, punc_store);
static struct kobj_attribute punc_some_attribute =
- __ATTR(punc_some, S_IWUSR | S_IRUGO, punc_show, punc_store);
+ __ATTR(punc_some, 0644, punc_show, punc_store);
static struct kobj_attribute repeats_attribute =
- __ATTR(repeats, S_IWUSR | S_IRUGO, punc_show, punc_store);
+ __ATTR(repeats, 0644, punc_show, punc_store);
static struct kobj_attribute attrib_bleep_attribute =
- __ATTR(attrib_bleep, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(attrib_bleep, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute bell_pos_attribute =
- __ATTR(bell_pos, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(bell_pos, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute bleep_time_attribute =
- __ATTR(bleep_time, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(bleep_time, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute bleeps_attribute =
- __ATTR(bleeps, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(bleeps, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute cursor_time_attribute =
- __ATTR(cursor_time, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(cursor_time, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute key_echo_attribute =
- __ATTR(key_echo, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(key_echo, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute no_interrupt_attribute =
- __ATTR(no_interrupt, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(no_interrupt, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute punc_level_attribute =
- __ATTR(punc_level, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(punc_level, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute reading_punc_attribute =
- __ATTR(reading_punc, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(reading_punc, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute say_control_attribute =
- __ATTR(say_control, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(say_control, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute say_word_ctl_attribute =
- __ATTR(say_word_ctl, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(say_word_ctl, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute spell_delay_attribute =
- __ATTR(spell_delay, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(spell_delay, 0644, spk_var_show, spk_var_store);
/*
* These attributes are i18n related.
*/
static struct kobj_attribute announcements_attribute =
- __ATTR(announcements, S_IWUSR | S_IRUGO, message_show, message_store);
+ __ATTR(announcements, 0644, message_show, message_store);
static struct kobj_attribute characters_attribute =
- __ATTR(characters, S_IWUSR | S_IRUGO, chars_chartab_show,
+ __ATTR(characters, 0644, chars_chartab_show,
chars_chartab_store);
static struct kobj_attribute chartab_attribute =
- __ATTR(chartab, S_IWUSR | S_IRUGO, chars_chartab_show,
+ __ATTR(chartab, 0644, chars_chartab_show,
chars_chartab_store);
static struct kobj_attribute ctl_keys_attribute =
- __ATTR(ctl_keys, S_IWUSR | S_IRUGO, message_show, message_store);
+ __ATTR(ctl_keys, 0644, message_show, message_store);
static struct kobj_attribute colors_attribute =
- __ATTR(colors, S_IWUSR | S_IRUGO, message_show, message_store);
+ __ATTR(colors, 0644, message_show, message_store);
static struct kobj_attribute formatted_attribute =
- __ATTR(formatted, S_IWUSR | S_IRUGO, message_show, message_store);
+ __ATTR(formatted, 0644, message_show, message_store);
static struct kobj_attribute function_names_attribute =
- __ATTR(function_names, S_IWUSR | S_IRUGO, message_show, message_store);
+ __ATTR(function_names, 0644, message_show, message_store);
static struct kobj_attribute key_names_attribute =
- __ATTR(key_names, S_IWUSR | S_IRUGO, message_show, message_store);
+ __ATTR(key_names, 0644, message_show, message_store);
static struct kobj_attribute states_attribute =
- __ATTR(states, S_IWUSR | S_IRUGO, message_show, message_store);
+ __ATTR(states, 0644, message_show, message_store);
/*
* Create groups of attributes so that we can create and destroy them all
MODULE_VERSION(SPEAKUP_VERSION);
char *synth_name;
-module_param_named(synth, synth_name, charp, S_IRUGO);
-module_param_named(quiet, spk_quiet_boot, bool, S_IRUGO);
+module_param_named(synth, synth_name, charp, 0444);
+module_param_named(quiet, spk_quiet_boot, bool, 0444);
MODULE_PARM_DESC(synth, "Synth to start if speakup is built in.");
MODULE_PARM_DESC(quiet, "Do not announce when the synthesizer is found.");
#define SHIFT_TBL_SIZE 64
#define MAX_DESC_LEN 72
-/* proc permissions */
-#define USER_R (S_IFREG|S_IRUGO)
-#define USER_W (S_IFREG|S_IWUGO)
-
#define TOGGLE_0 .u.n = {NULL, 0, 0, 1, 0, 0, NULL }
#define TOGGLE_1 .u.n = {NULL, 1, 0, 1, 0, 0, NULL }
#define MAXVARLEN 15
* These attributes will appear in /sys/accessibility/speakup/acntpc.
*/
static struct kobj_attribute caps_start_attribute =
- __ATTR(caps_start, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute caps_stop_attribute =
- __ATTR(caps_stop, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute pitch_attribute =
- __ATTR(pitch, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(pitch, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute rate_attribute =
- __ATTR(rate, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(rate, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute tone_attribute =
- __ATTR(tone, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(tone, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute vol_attribute =
- __ATTR(vol, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(vol, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute delay_time_attribute =
- __ATTR(delay_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute direct_attribute =
- __ATTR(direct, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(direct, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute full_time_attribute =
- __ATTR(full_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(full_time, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute jiffy_delta_attribute =
- __ATTR(jiffy_delta, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute trigger_time_attribute =
- __ATTR(trigger_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
/*
* Create a group of attributes so that we can create and destroy them all
speakup_info.port_tts = 0;
}
-module_param_named(port, port_forced, int, S_IRUGO);
-module_param_named(start, synth_acntpc.startup, short, S_IRUGO);
+module_param_named(port, port_forced, int, 0444);
+module_param_named(start, synth_acntpc.startup, short, 0444);
MODULE_PARM_DESC(port, "Set the port for the synthesizer (override probing).");
MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
* These attributes will appear in /sys/accessibility/speakup/acntsa.
*/
static struct kobj_attribute caps_start_attribute =
- __ATTR(caps_start, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute caps_stop_attribute =
- __ATTR(caps_stop, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute pitch_attribute =
- __ATTR(pitch, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(pitch, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute rate_attribute =
- __ATTR(rate, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(rate, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute tone_attribute =
- __ATTR(tone, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(tone, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute vol_attribute =
- __ATTR(vol, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(vol, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute delay_time_attribute =
- __ATTR(delay_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute direct_attribute =
- __ATTR(direct, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(direct, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute full_time_attribute =
- __ATTR(full_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(full_time, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute jiffy_delta_attribute =
- __ATTR(jiffy_delta, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute trigger_time_attribute =
- __ATTR(trigger_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
/*
* Create a group of attributes so that we can create and destroy them all
return failed;
}
-module_param_named(ser, synth_acntsa.ser, int, S_IRUGO);
-module_param_named(start, synth_acntsa.startup, short, S_IRUGO);
+module_param_named(ser, synth_acntsa.ser, int, 0444);
+module_param_named(start, synth_acntsa.startup, short, 0444);
MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
* These attributes will appear in /sys/accessibility/speakup/apollo.
*/
static struct kobj_attribute caps_start_attribute =
- __ATTR(caps_start, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute caps_stop_attribute =
- __ATTR(caps_stop, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute lang_attribute =
- __ATTR(lang, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(lang, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute pitch_attribute =
- __ATTR(pitch, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(pitch, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute rate_attribute =
- __ATTR(rate, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(rate, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute voice_attribute =
- __ATTR(voice, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(voice, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute vol_attribute =
- __ATTR(vol, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(vol, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute delay_time_attribute =
- __ATTR(delay_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute direct_attribute =
- __ATTR(direct, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(direct, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute full_time_attribute =
- __ATTR(full_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(full_time, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute jiffy_delta_attribute =
- __ATTR(jiffy_delta, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute trigger_time_attribute =
- __ATTR(trigger_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
/*
* Create a group of attributes so that we can create and destroy them all
spk_serial_out(PROCSPEECH);
}
-module_param_named(ser, synth_apollo.ser, int, S_IRUGO);
-module_param_named(start, synth_apollo.startup, short, S_IRUGO);
+module_param_named(ser, synth_apollo.ser, int, 0444);
+module_param_named(start, synth_apollo.startup, short, 0444);
MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
* These attributes will appear in /sys/accessibility/speakup/audptr.
*/
static struct kobj_attribute caps_start_attribute =
- __ATTR(caps_start, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute caps_stop_attribute =
- __ATTR(caps_stop, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute pitch_attribute =
- __ATTR(pitch, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(pitch, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute punct_attribute =
- __ATTR(punct, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(punct, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute rate_attribute =
- __ATTR(rate, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(rate, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute tone_attribute =
- __ATTR(tone, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(tone, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute vol_attribute =
- __ATTR(vol, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(vol, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute delay_time_attribute =
- __ATTR(delay_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute direct_attribute =
- __ATTR(direct, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(direct, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute full_time_attribute =
- __ATTR(full_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(full_time, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute jiffy_delta_attribute =
- __ATTR(jiffy_delta, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute trigger_time_attribute =
- __ATTR(trigger_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
/*
* Create a group of attributes so that we can create and destroy them all
return 0;
}
-module_param_named(ser, synth_audptr.ser, int, S_IRUGO);
-module_param_named(start, synth_audptr.startup, short, S_IRUGO);
+module_param_named(ser, synth_audptr.ser, int, 0444);
+module_param_named(start, synth_audptr.startup, short, 0444);
MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
/*
* originally written by: Kirk Reiser <kirk@braille.uwo.ca>
-* this version considerably modified by David Borowski, david575@rogers.com
+ * this version considerably modified by David Borowski, david575@rogers.com
*
* Copyright (C) 1998-99 Kirk Reiser.
* Copyright (C) 2003 David Borowski.
* These attributes will appear in /sys/accessibility/speakup/bns.
*/
static struct kobj_attribute caps_start_attribute =
- __ATTR(caps_start, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute caps_stop_attribute =
- __ATTR(caps_stop, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute pitch_attribute =
- __ATTR(pitch, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(pitch, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute rate_attribute =
- __ATTR(rate, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(rate, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute tone_attribute =
- __ATTR(tone, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(tone, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute vol_attribute =
- __ATTR(vol, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(vol, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute delay_time_attribute =
- __ATTR(delay_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute direct_attribute =
- __ATTR(direct, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(direct, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute full_time_attribute =
- __ATTR(full_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(full_time, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute jiffy_delta_attribute =
- __ATTR(jiffy_delta, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute trigger_time_attribute =
- __ATTR(trigger_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
/*
* Create a group of attributes so that we can create and destroy them all
},
};
-module_param_named(ser, synth_bns.ser, int, S_IRUGO);
-module_param_named(start, synth_bns.startup, short, S_IRUGO);
+module_param_named(ser, synth_bns.ser, int, 0444);
+module_param_named(start, synth_bns.startup, short, 0444);
MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
* These attributes will appear in /sys/accessibility/speakup/decext.
*/
static struct kobj_attribute caps_start_attribute =
- __ATTR(caps_start, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute caps_stop_attribute =
- __ATTR(caps_stop, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute pitch_attribute =
- __ATTR(pitch, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(pitch, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute punct_attribute =
- __ATTR(punct, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(punct, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute rate_attribute =
- __ATTR(rate, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(rate, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute voice_attribute =
- __ATTR(voice, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(voice, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute vol_attribute =
- __ATTR(vol, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(vol, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute delay_time_attribute =
- __ATTR(delay_time, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute direct_attribute =
- __ATTR(direct, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(direct, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute full_time_attribute =
- __ATTR(full_time, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(full_time, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute jiffy_delta_attribute =
- __ATTR(jiffy_delta, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute trigger_time_attribute =
- __ATTR(trigger_time, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
/*
* Create a group of attributes so that we can create and destroy them all
spk_synth_immediate(synth, "\033P;10z\033\\");
}
-module_param_named(ser, synth_decext.ser, int, S_IRUGO);
-module_param_named(start, synth_decext.startup, short, S_IRUGO);
+module_param_named(ser, synth_decext.ser, int, 0444);
+module_param_named(start, synth_decext.startup, short, 0444);
MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
* These attributes will appear in /sys/accessibility/speakup/decpc.
*/
static struct kobj_attribute caps_start_attribute =
- __ATTR(caps_start, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute caps_stop_attribute =
- __ATTR(caps_stop, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute pitch_attribute =
- __ATTR(pitch, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(pitch, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute punct_attribute =
- __ATTR(punct, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(punct, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute rate_attribute =
- __ATTR(rate, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(rate, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute voice_attribute =
- __ATTR(voice, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(voice, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute vol_attribute =
- __ATTR(vol, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(vol, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute delay_time_attribute =
- __ATTR(delay_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute direct_attribute =
- __ATTR(direct, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(direct, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute full_time_attribute =
- __ATTR(full_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(full_time, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute jiffy_delta_attribute =
- __ATTR(jiffy_delta, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute trigger_time_attribute =
- __ATTR(trigger_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
/*
* Create a group of attributes so that we can create and destroy them all
speakup_info.port_tts = 0;
}
-module_param_named(start, synth_dec_pc.startup, short, S_IRUGO);
+module_param_named(start, synth_dec_pc.startup, short, 0444);
MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
* These attributes will appear in /sys/accessibility/speakup/dectlk.
*/
static struct kobj_attribute caps_start_attribute =
- __ATTR(caps_start, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute caps_stop_attribute =
- __ATTR(caps_stop, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute pitch_attribute =
- __ATTR(pitch, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(pitch, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute punct_attribute =
- __ATTR(punct, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(punct, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute rate_attribute =
- __ATTR(rate, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(rate, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute voice_attribute =
- __ATTR(voice, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(voice, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute vol_attribute =
- __ATTR(vol, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(vol, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute delay_time_attribute =
- __ATTR(delay_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute direct_attribute =
- __ATTR(direct, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(direct, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute full_time_attribute =
- __ATTR(full_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(full_time, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute jiffy_delta_attribute =
- __ATTR(jiffy_delta, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute trigger_time_attribute =
- __ATTR(trigger_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
/*
* Create a group of attributes so that we can create and destroy them all
spk_serial_out(SYNTH_CLEAR);
}
-module_param_named(ser, synth_dectlk.ser, int, S_IRUGO);
-module_param_named(start, synth_dectlk.startup, short, S_IRUGO);
+module_param_named(ser, synth_dectlk.ser, int, 0444);
+module_param_named(start, synth_dectlk.startup, short, 0444);
MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
* These attributes will appear in /sys/accessibility/speakup/dtlk.
*/
static struct kobj_attribute caps_start_attribute =
- __ATTR(caps_start, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute caps_stop_attribute =
- __ATTR(caps_stop, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute freq_attribute =
- __ATTR(freq, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(freq, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute pitch_attribute =
- __ATTR(pitch, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(pitch, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute punct_attribute =
- __ATTR(punct, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(punct, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute rate_attribute =
- __ATTR(rate, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(rate, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute tone_attribute =
- __ATTR(tone, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(tone, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute voice_attribute =
- __ATTR(voice, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(voice, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute vol_attribute =
- __ATTR(vol, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(vol, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute delay_time_attribute =
- __ATTR(delay_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute direct_attribute =
- __ATTR(direct, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(direct, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute full_time_attribute =
- __ATTR(full_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(full_time, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute jiffy_delta_attribute =
- __ATTR(jiffy_delta, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute trigger_time_attribute =
- __ATTR(trigger_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
/*
* Create a group of attributes so that we can create and destroy them all
speakup_info.port_tts = 0;
}
-module_param_named(port, port_forced, int, S_IRUGO);
-module_param_named(start, synth_dtlk.startup, short, S_IRUGO);
+module_param_named(port, port_forced, int, 0444);
+module_param_named(start, synth_dtlk.startup, short, 0444);
MODULE_PARM_DESC(port, "Set the port for the synthesizer (override probing).");
MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
* These attributes will appear in /sys/accessibility/speakup/dummy.
*/
static struct kobj_attribute caps_start_attribute =
- __ATTR(caps_start, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute caps_stop_attribute =
- __ATTR(caps_stop, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute pitch_attribute =
- __ATTR(pitch, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(pitch, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute rate_attribute =
- __ATTR(rate, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(rate, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute tone_attribute =
- __ATTR(tone, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(tone, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute vol_attribute =
- __ATTR(vol, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(vol, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute delay_time_attribute =
- __ATTR(delay_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute direct_attribute =
- __ATTR(direct, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(direct, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute full_time_attribute =
- __ATTR(full_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(full_time, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute jiffy_delta_attribute =
- __ATTR(jiffy_delta, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute trigger_time_attribute =
- __ATTR(trigger_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
/*
* Create a group of attributes so that we can create and destroy them all
},
};
-module_param_named(ser, synth_dummy.ser, int, S_IRUGO);
-module_param_named(start, synth_dummy.startup, short, S_IRUGO);
+module_param_named(ser, synth_dummy.ser, int, 0444);
+module_param_named(start, synth_dummy.startup, short, 0444);
MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
* These attributes will appear in /sys/accessibility/speakup/keypc.
*/
static struct kobj_attribute caps_start_attribute =
- __ATTR(caps_start, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute caps_stop_attribute =
- __ATTR(caps_stop, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute pitch_attribute =
- __ATTR(pitch, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(pitch, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute rate_attribute =
- __ATTR(rate, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(rate, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute delay_time_attribute =
- __ATTR(delay_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute direct_attribute =
- __ATTR(direct, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(direct, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute full_time_attribute =
- __ATTR(full_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(full_time, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute jiffy_delta_attribute =
- __ATTR(jiffy_delta, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute trigger_time_attribute =
- __ATTR(trigger_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
/*
* Create a group of attributes so that we can create and destroy them all
synth_port = 0;
}
-module_param_named(port, port_forced, int, S_IRUGO);
-module_param_named(start, synth_keypc.startup, short, S_IRUGO);
+module_param_named(port, port_forced, int, 0444);
+module_param_named(start, synth_keypc.startup, short, 0444);
MODULE_PARM_DESC(port, "Set the port for the synthesizer (override probing).");
MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
* These attributes will appear in /sys/accessibility/speakup/ltlk.
*/
static struct kobj_attribute caps_start_attribute =
- __ATTR(caps_start, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute caps_stop_attribute =
- __ATTR(caps_stop, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute freq_attribute =
- __ATTR(freq, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(freq, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute pitch_attribute =
- __ATTR(pitch, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(pitch, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute punct_attribute =
- __ATTR(punct, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(punct, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute rate_attribute =
- __ATTR(rate, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(rate, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute tone_attribute =
- __ATTR(tone, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(tone, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute voice_attribute =
- __ATTR(voice, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(voice, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute vol_attribute =
- __ATTR(vol, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(vol, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute delay_time_attribute =
- __ATTR(delay_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute direct_attribute =
- __ATTR(direct, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(direct, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute full_time_attribute =
- __ATTR(full_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(full_time, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute jiffy_delta_attribute =
- __ATTR(jiffy_delta, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute trigger_time_attribute =
- __ATTR(trigger_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
/*
* Create a group of attributes so that we can create and destroy them all
return failed;
}
-module_param_named(ser, synth_ltlk.ser, int, S_IRUGO);
-module_param_named(start, synth_ltlk.startup, short, S_IRUGO);
+module_param_named(ser, synth_ltlk.ser, int, 0444);
+module_param_named(start, synth_ltlk.startup, short, 0444);
MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
/* These attributes will appear in /sys/accessibility/speakup/soft. */
static struct kobj_attribute caps_start_attribute =
- __ATTR(caps_start, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute caps_stop_attribute =
- __ATTR(caps_stop, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute freq_attribute =
- __ATTR(freq, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(freq, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute pitch_attribute =
- __ATTR(pitch, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(pitch, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute punct_attribute =
- __ATTR(punct, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(punct, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute rate_attribute =
- __ATTR(rate, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(rate, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute tone_attribute =
- __ATTR(tone, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(tone, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute voice_attribute =
- __ATTR(voice, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(voice, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute vol_attribute =
- __ATTR(vol, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(vol, 0644, spk_var_show, spk_var_store);
/*
* We should uncomment the following definition, when we agree on a
* method of passing a language designation to the software synthesizer.
* static struct kobj_attribute lang_attribute =
- * __ATTR(lang, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
+ * __ATTR(lang, 0644, spk_var_show, spk_var_store);
*/
static struct kobj_attribute delay_time_attribute =
- __ATTR(delay_time, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute direct_attribute =
- __ATTR(direct, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(direct, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute full_time_attribute =
- __ATTR(full_time, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(full_time, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute jiffy_delta_attribute =
- __ATTR(jiffy_delta, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute trigger_time_attribute =
- __ATTR(trigger_time, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
/*
* Create a group of attributes so that we can create and destroy them all
return 0;
}
-module_param_named(start, synth_soft.startup, short, S_IRUGO);
+module_param_named(start, synth_soft.startup, short, 0444);
MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
/* These attributes will appear in /sys/accessibility/speakup/spkout. */
static struct kobj_attribute caps_start_attribute =
- __ATTR(caps_start, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute caps_stop_attribute =
- __ATTR(caps_stop, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute pitch_attribute =
- __ATTR(pitch, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(pitch, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute punct_attribute =
- __ATTR(punct, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(punct, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute rate_attribute =
- __ATTR(rate, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(rate, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute tone_attribute =
- __ATTR(tone, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(tone, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute vol_attribute =
- __ATTR(vol, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(vol, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute delay_time_attribute =
- __ATTR(delay_time, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute direct_attribute =
- __ATTR(direct, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(direct, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute full_time_attribute =
- __ATTR(full_time, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(full_time, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute jiffy_delta_attribute =
- __ATTR(jiffy_delta, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute trigger_time_attribute =
- __ATTR(trigger_time, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
/*
* Create a group of attributes so that we can create and destroy them all
outb(SYNTH_CLEAR, speakup_info.port_tts);
}
-module_param_named(ser, synth_spkout.ser, int, S_IRUGO);
-module_param_named(start, synth_spkout.startup, short, S_IRUGO);
+module_param_named(ser, synth_spkout.ser, int, 0444);
+module_param_named(start, synth_spkout.startup, short, 0444);
MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
/* These attributes will appear in /sys/accessibility/speakup/txprt. */
static struct kobj_attribute caps_start_attribute =
- __ATTR(caps_start, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(caps_start, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute caps_stop_attribute =
- __ATTR(caps_stop, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(caps_stop, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute pitch_attribute =
- __ATTR(pitch, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(pitch, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute rate_attribute =
- __ATTR(rate, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(rate, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute tone_attribute =
- __ATTR(tone, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(tone, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute vol_attribute =
- __ATTR(vol, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(vol, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute delay_time_attribute =
- __ATTR(delay_time, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(delay_time, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute direct_attribute =
- __ATTR(direct, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(direct, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute full_time_attribute =
- __ATTR(full_time, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(full_time, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute jiffy_delta_attribute =
- __ATTR(jiffy_delta, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute trigger_time_attribute =
- __ATTR(trigger_time, S_IWUSR | S_IRUGO, spk_var_show, spk_var_store);
+ __ATTR(trigger_time, 0644, spk_var_show, spk_var_store);
/*
* Create a group of attributes so that we can create and destroy them all
},
};
-module_param_named(ser, synth_txprt.ser, int, S_IRUGO);
-module_param_named(start, synth_txprt.startup, short, S_IRUGO);
+module_param_named(ser, synth_txprt.ser, int, 0444);
+module_param_named(start, synth_txprt.startup, short, 0444);
MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based).");
MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded.");
int spk_synth_is_alive_nop(struct spk_synth *synth);
int spk_synth_is_alive_restart(struct spk_synth *synth);
void synth_printf(const char *buf, ...);
-int synth_request_region(u_long, u_long);
-int synth_release_region(u_long, u_long);
+int synth_request_region(unsigned long start, unsigned long n);
+int synth_release_region(unsigned long start, unsigned long n);
int synth_add(struct spk_synth *in_synth);
void synth_remove(struct spk_synth *in_synth);
#include <linux/uuid.h>
/*
-* Whenever this file is changed a corresponding change must be made in
-* the Console/ServicePart/visordiag_early/supervisor_channel.h file
-* which is needed for Linux kernel compiles. These two files must be
-* in sync.
-*/
+ * Whenever this file is changed a corresponding change must be made in
+ * the Console/ServicePart/visordiag_early/supervisor_channel.h file
+ * which is needed for Linux kernel compiles. These two files must be
+ * in sync.
+ */
/* define the following to prevent include nesting in kernel header
* files of similar abbreviated content
}
/*
-* Routine Description:
-* Tries to insert the prebuilt signal pointed to by pSignal into the nth
-* Queue of the Channel pointed to by pChannel
-*
-* Parameters:
-* pChannel: (IN) points to the IO Channel
-* Queue: (IN) nth Queue of the IO Channel
-* pSignal: (IN) pointer to the signal
-*
-* Assumptions:
-* - pChannel, Queue and pSignal are valid.
-* - If insertion fails due to a full queue, the caller will determine the
-* retry policy (e.g. wait & try again, report an error, etc.).
-*
-* Return value: 1 if the insertion succeeds, 0 if the queue was
-* full.
-*/
+ * Routine Description:
+ * Tries to insert the prebuilt signal pointed to by pSignal into the nth
+ * Queue of the Channel pointed to by pChannel
+ *
+ * Parameters:
+ * pChannel: (IN) points to the IO Channel
+ * Queue: (IN) nth Queue of the IO Channel
+ * pSignal: (IN) pointer to the signal
+ *
+ * Assumptions:
+ * - pChannel, Queue and pSignal are valid.
+ * - If insertion fails due to a full queue, the caller will determine the
+ * retry policy (e.g. wait & try again, report an error, etc.).
+ *
+ * Return value: 1 if the insertion succeeds, 0 if the queue was
+ * full.
+ */
unsigned char spar_signal_insert(struct channel_header __iomem *ch, u32 queue,
void *sig);
/*
-* Routine Description:
-* Removes one signal from Channel pChannel's nth Queue at the
-* time of the call and copies it into the memory pointed to by
-* pSignal.
-*
-* Parameters:
-* pChannel: (IN) points to the IO Channel
-* Queue: (IN) nth Queue of the IO Channel
-* pSignal: (IN) pointer to where the signals are to be copied
-*
-* Assumptions:
-* - pChannel and Queue are valid.
-* - pSignal points to a memory area large enough to hold queue's SignalSize
-*
-* Return value: 1 if the removal succeeds, 0 if the queue was
-* empty.
-*/
+ * Routine Description:
+ * Removes one signal from Channel pChannel's nth Queue at the
+ * time of the call and copies it into the memory pointed to by
+ * pSignal.
+ *
+ * Parameters:
+ * pChannel: (IN) points to the IO Channel
+ * Queue: (IN) nth Queue of the IO Channel
+ * pSignal: (IN) pointer to where the signals are to be copied
+ *
+ * Assumptions:
+ * - pChannel and Queue are valid.
+ * - pSignal points to a memory area large enough to hold queue's SignalSize
+ *
+ * Return value: 1 if the removal succeeds, 0 if the queue was
+ * empty.
+ */
unsigned char spar_signal_remove(struct channel_header __iomem *ch, u32 queue,
void *sig);
/*
-* Routine Description:
-* Removes all signals present in Channel pChannel's nth Queue at the
-* time of the call and copies them into the memory pointed to by
-* pSignal. Returns the # of signals copied as the value of the routine.
-*
-* Parameters:
-* pChannel: (IN) points to the IO Channel
-* Queue: (IN) nth Queue of the IO Channel
-* pSignal: (IN) pointer to where the signals are to be copied
-*
-* Assumptions:
-* - pChannel and Queue are valid.
-* - pSignal points to a memory area large enough to hold Queue's MaxSignals
-* # of signals, each of which is Queue's SignalSize.
-*
-* Return value:
-* # of signals copied.
-*/
+ * Routine Description:
+ * Removes all signals present in Channel pChannel's nth Queue at the
+ * time of the call and copies them into the memory pointed to by
+ * pSignal. Returns the # of signals copied as the value of the routine.
+ *
+ * Parameters:
+ * pChannel: (IN) points to the IO Channel
+ * Queue: (IN) nth Queue of the IO Channel
+ * pSignal: (IN) pointer to where the signals are to be copied
+ *
+ * Assumptions:
+ * - pChannel and Queue are valid.
+ * - pSignal points to a memory area large enough to hold Queue's MaxSignals
+ * # of signals, each of which is Queue's SignalSize.
+ *
+ * Return value:
+ * # of signals copied.
+ */
unsigned int spar_signal_remove_all(struct channel_header *ch, u32 queue,
void *sig);
/*
-* Routine Description:
-* Determine whether a signal queue is empty.
-*
-* Parameters:
-* pChannel: (IN) points to the IO Channel
-* Queue: (IN) nth Queue of the IO Channel
-*
-* Return value:
-* 1 if the signal queue is empty, 0 otherwise.
-*/
+ * Routine Description:
+ * Determine whether a signal queue is empty.
+ *
+ * Parameters:
+ * pChannel: (IN) points to the IO Channel
+ * Queue: (IN) nth Queue of the IO Channel
+ *
+ * Return value:
+ * 1 if the signal queue is empty, 0 otherwise.
+ */
unsigned char spar_signalqueue_empty(struct channel_header __iomem *ch,
u32 queue);
ULTRA_CONTROLVM_CHANNEL_PROTOCOL_VERSIONID, \
ULTRA_CONTROLVM_CHANNEL_PROTOCOL_SIGNATURE)
-#define MAX_SERIAL_NUM 32
-
/* Defines for various channel queues */
#define CONTROLVM_QUEUE_REQUEST 0
#define CONTROLVM_QUEUE_RESPONSE 1
struct controlvm_message saved_crash_msg[CONTROLVM_CRASHMSG_MAX];
};
-/* Offsets for VM channel attributes */
-#define VM_CH_REQ_QUEUE_OFFSET \
- offsetof(struct spar_controlvm_channel_protocol, request_queue)
-#define VM_CH_RESP_QUEUE_OFFSET \
- offsetof(struct spar_controlvm_channel_protocol, response_queue)
-#define VM_CH_EVENT_QUEUE_OFFSET \
- offsetof(struct spar_controlvm_channel_protocol, event_queue)
-#define VM_CH_ACK_QUEUE_OFFSET \
- offsetof(struct spar_controlvm_channel_protocol, event_ack_queue)
-#define VM_CH_REQ_MSG_OFFSET \
- offsetof(struct spar_controlvm_channel_protocol, request_msg)
-#define VM_CH_RESP_MSG_OFFSET \
- offsetof(struct spar_controlvm_channel_protocol, response_msg)
-#define VM_CH_EVENT_MSG_OFFSET \
- offsetof(struct spar_controlvm_channel_protocol, event_msg)
-#define VM_CH_ACK_MSG_OFFSET \
- offsetof(struct spar_controlvm_channel_protocol, event_ack_msg)
-#define VM_CH_CRASH_MSG_OFFSET \
- offsetof(struct spar_controlvm_channel_protocol, saved_crash_msg)
-
/* The following header will be located at the beginning of PayloadVmOffset for
* various ControlVm commands. The receiver of a ControlVm command with a
* PayloadVmOffset will dereference this address and then use connection_offset,
/* General Errors------------------------------------------------------[0-99] */
#define CONTROLVM_RESP_SUCCESS 0
-#define CONTROLVM_RESP_ERROR_ALREADY_DONE 1
-#define CONTROLVM_RESP_ERROR_IOREMAP_FAILED 2
-#define CONTROLVM_RESP_ERROR_KMALLOC_FAILED 3
-#define CONTROLVM_RESP_ERROR_MESSAGE_ID_UNKNOWN 4
-#define CONTROLVM_RESP_ERROR_MESSAGE_ID_INVALID_FOR_CLIENT 5
+#define CONTROLVM_RESP_ALREADY_DONE 1
+#define CONTROLVM_RESP_IOREMAP_FAILED 2
+#define CONTROLVM_RESP_KMALLOC_FAILED 3
+#define CONTROLVM_RESP_ID_UNKNOWN 4
+#define CONTROLVM_RESP_ID_INVALID_FOR_CLIENT 5
/* CONTROLVM_INIT_CHIPSET-------------------------------------------[100-199] */
-#define CONTROLVM_RESP_ERROR_CLIENT_SWITCHCOUNT_NONZERO 100
-#define CONTROLVM_RESP_ERROR_EXPECTED_CHIPSET_INIT 101
+#define CONTROLVM_RESP_CLIENT_SWITCHCOUNT_NONZERO 100
+#define CONTROLVM_RESP_EXPECTED_CHIPSET_INIT 101
/* Maximum Limit----------------------------------------------------[200-299] */
#define CONTROLVM_RESP_ERROR_MAX_BUSES 201 /* BUS_CREATE */
#define CONTROLVM_RESP_ERROR_MAX_DEVICES 202 /* DEVICE_CREATE */
/* Payload and Parameter Related------------------------------------[400-499] */
-#define CONTROLVM_RESP_ERROR_PAYLOAD_INVALID 400 /* SWITCH_ATTACHEXTPORT,
+#define CONTROLVM_RESP_PAYLOAD_INVALID 400 /* SWITCH_ATTACHEXTPORT,
* DEVICE_CONFIGURE
*/
-#define CONTROLVM_RESP_ERROR_INITIATOR_PARAMETER_INVALID 401 /* Multiple */
-#define CONTROLVM_RESP_ERROR_TARGET_PARAMETER_INVALID 402 /* DEVICE_CONFIGURE */
-#define CONTROLVM_RESP_ERROR_CLIENT_PARAMETER_INVALID 403 /* DEVICE_CONFIGURE */
+#define CONTROLVM_RESP_INITIATOR_PARAMETER_INVALID 401 /* Multiple */
+#define CONTROLVM_RESP_TARGET_PARAMETER_INVALID 402 /* DEVICE_CONFIGURE */
+#define CONTROLVM_RESP_CLIENT_PARAMETER_INVALID 403 /* DEVICE_CONFIGURE */
/* Specified[Packet Structure] Value-------------------------------[500-599] */
-#define CONTROLVM_RESP_ERROR_BUS_INVALID 500 /* SWITCH_ATTACHINTPORT,
+#define CONTROLVM_RESP_BUS_INVALID 500 /* SWITCH_ATTACHINTPORT,
* BUS_CONFIGURE,
* DEVICE_CREATE,
* DEVICE_CONFIG
* DEVICE_DESTROY
*/
-#define CONTROLVM_RESP_ERROR_DEVICE_INVALID 501 /* SWITCH_ATTACHINTPORT */
+#define CONTROLVM_RESP_DEVICE_INVALID 501 /* SWITCH_ATTACHINTPORT */
/* DEVICE_CREATE,
* DEVICE_CONFIGURE,
* DEVICE_DESTROY
*/
-#define CONTROLVM_RESP_ERROR_CHANNEL_INVALID 502 /* DEVICE_CREATE,
+#define CONTROLVM_RESP_CHANNEL_INVALID 502 /* DEVICE_CREATE,
* DEVICE_CONFIGURE
*/
/* Partition Driver Callback Interface----------------------[600-699] */
-#define CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE 604 /* BUS_CREATE,
- * BUS_DESTROY,
- * DEVICE_CREATE,
- * DEVICE_DESTROY
- */
+#define CONTROLVM_RESP_VIRTPCI_DRIVER_FAILURE 604 /* BUS_CREATE,
+ * BUS_DESTROY,
+ * DEVICE_CREATE,
+ * DEVICE_DESTROY
+ */
/* Unable to invoke VIRTPCI callback */
-#define CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR 605
- /* BUS_CREATE,
- * BUS_DESTROY,
- * DEVICE_CREATE,
- * DEVICE_DESTROY
- */
+#define CONTROLVM_RESP_VIRTPCI_DRIVER_CALLBACK_ERROR 605 /* BUS_CREATE,
+ * BUS_DESTROY,
+ * DEVICE_CREATE,
+ * DEVICE_DESTROY
+ */
/* VIRTPCI Callback returned error */
-#define CONTROLVM_RESP_ERROR_GENERIC_DRIVER_CALLBACK_ERROR 606
+#define CONTROLVM_RESP_GENERIC_DRIVER_CALLBACK_ERROR 606
/* SWITCH_ATTACHEXTPORT,
* SWITCH_DETACHEXTPORT
* DEVICE_CONFIGURE
/* Bus Related------------------------------------------------------[700-799] */
#define CONTROLVM_RESP_ERROR_BUS_DEVICE_ATTACHED 700 /* BUS_DESTROY */
/* Channel Related--------------------------------------------------[800-899] */
-#define CONTROLVM_RESP_ERROR_CHANNEL_TYPE_UNKNOWN 800 /* GET_CHANNELINFO,
+#define CONTROLVM_RESP_CHANNEL_TYPE_UNKNOWN 800 /* GET_CHANNELINFO,
* DEVICE_DESTROY
*/
-#define CONTROLVM_RESP_ERROR_CHANNEL_SIZE_TOO_SMALL 801 /* DEVICE_CREATE */
+#define CONTROLVM_RESP_CHANNEL_SIZE_TOO_SMALL 801 /* DEVICE_CREATE */
/* Chipset Shutdown Related---------------------------------------[1000-1099] */
-#define CONTROLVM_RESP_ERROR_CHIPSET_SHUTDOWN_FAILED 1000
-#define CONTROLVM_RESP_ERROR_CHIPSET_SHUTDOWN_ALREADY_ACTIVE 1001
+#define CONTROLVM_RESP_CHIPSET_SHUTDOWN_FAILED 1000
+#define CONTROLVM_RESP_CHIPSET_SHUTDOWN_ALREADY_ACTIVE 1001
/* Chipset Stop Related-------------------------------------------[1100-1199] */
-#define CONTROLVM_RESP_ERROR_CHIPSET_STOP_FAILED_BUS 1100
-#define CONTROLVM_RESP_ERROR_CHIPSET_STOP_FAILED_SWITCH 1101
+#define CONTROLVM_RESP_CHIPSET_STOP_FAILED_BUS 1100
+#define CONTROLVM_RESP_CHIPSET_STOP_FAILED_SWITCH 1101
/* Device Related-------------------------------------------------[1400-1499] */
-#define CONTROLVM_RESP_ERROR_DEVICE_UDEV_TIMEOUT 1400
+#define CONTROLVM_RESP_DEVICE_UDEV_TIMEOUT 1400
#endif /* __CONTROLVMCHANNEL_H__ */
vdev = to_visor_device(dev);
guid = visorchannel_get_uuid(vdev->visorchannel);
- return snprintf(buf, PAGE_SIZE, "visorbus:%pUl\n", &guid);
+ return sprintf(buf, "visorbus:%pUl\n", &guid);
}
static DEVICE_ATTR_RO(modalias);
if (!vdev->visorchannel)
return 0;
- return snprintf(buf, PAGE_SIZE, "0x%llx\n",
- visorchannel_get_physaddr(vdev->visorchannel));
+ return sprintf(buf, "0x%llx\n",
+ visorchannel_get_physaddr(vdev->visorchannel));
}
static DEVICE_ATTR_RO(physaddr);
if (!vdev->visorchannel)
return 0;
- return snprintf(buf, PAGE_SIZE, "0x%lx\n",
+ return sprintf(buf, "0x%lx\n",
visorchannel_get_nbytes(vdev->visorchannel));
}
static DEVICE_ATTR_RO(nbytes);
if (!vdev->visorchannel)
return 0;
- return snprintf(buf, PAGE_SIZE, "0x%llx\n",
- visorchannel_get_clientpartition(vdev->visorchannel));
+ return sprintf(buf, "0x%llx\n",
+ visorchannel_get_clientpartition(vdev->visorchannel));
}
static DEVICE_ATTR_RO(clientpartition);
if (!vdev->visorchannel)
return 0;
- return snprintf(buf, PAGE_SIZE, "%s\n",
- visorchannel_id(vdev->visorchannel, typeid));
+ return sprintf(buf, "%s\n",
+ visorchannel_id(vdev->visorchannel, typeid));
}
static DEVICE_ATTR_RO(typeguid);
if (!vdev->visorchannel)
return 0;
- return snprintf(buf, PAGE_SIZE, "%s\n",
- visorchannel_zoneid(vdev->visorchannel, zoneid));
+ return sprintf(buf, "%s\n",
+ visorchannel_zoneid(vdev->visorchannel, zoneid));
}
static DEVICE_ATTR_RO(zoneguid);
if (!i)
return 0;
drv = to_visor_driver(xdrv);
- return snprintf(buf, PAGE_SIZE, "%s\n", drv->channel_types[i - 1].name);
+ return sprintf(buf, "%s\n", drv->channel_types[i - 1].name);
}
static DEVICE_ATTR_RO(typename);
struct visor_device *vdev = to_visor_device(dev);
u64 handle = visorchannel_get_clientpartition(vdev->visorchannel);
- return snprintf(buf, PAGE_SIZE, "0x%llx\n", handle);
+ return sprintf(buf, "0x%llx\n", handle);
}
static DEVICE_ATTR_RO(partition_handle);
char *buf) {
struct visor_device *vdev = to_visor_device(dev);
- return snprintf(buf, PAGE_SIZE, "{%pUb}\n", &vdev->partition_uuid);
+ return sprintf(buf, "{%pUb}\n", &vdev->partition_uuid);
}
static DEVICE_ATTR_RO(partition_guid);
char *buf) {
struct visor_device *vdev = to_visor_device(dev);
- return snprintf(buf, PAGE_SIZE, "%s\n", vdev->name);
+ return sprintf(buf, "%s\n", vdev->name);
}
static DEVICE_ATTR_RO(partition_name);
struct visor_device *vdev = to_visor_device(dev);
u64 addr = visorchannel_get_physaddr(vdev->visorchannel);
- return snprintf(buf, PAGE_SIZE, "0x%llx\n", addr);
+ return sprintf(buf, "0x%llx\n", addr);
}
static DEVICE_ATTR_RO(channel_addr);
struct visor_device *vdev = to_visor_device(dev);
u64 nbytes = visorchannel_get_nbytes(vdev->visorchannel);
- return snprintf(buf, PAGE_SIZE, "0x%llx\n", nbytes);
+ return sprintf(buf, "0x%llx\n", nbytes);
}
static DEVICE_ATTR_RO(channel_bytes);
struct visor_device *dev = (struct visor_device *)__opaque;
struct visor_driver *drv = to_visor_driver(dev->device.driver);
- if (drv->channel_interrupt)
- drv->channel_interrupt(dev);
+ drv->channel_interrupt(dev);
mod_timer(&dev->timer, jiffies + POLLJIFFIES_NORMALCHANNEL);
}
void
visorbus_enable_channel_interrupts(struct visor_device *dev)
{
+ struct visor_driver *drv = to_visor_driver(dev->device.driver);
+
+ if (!drv->channel_interrupt) {
+ dev_err(&dev->device, "%s no interrupt function!\n", __func__);
+ return;
+ }
+
dev_start_periodic_work(dev);
}
EXPORT_SYMBOL_GPL(visorbus_enable_channel_interrupts);
goto err_hdr_info;
}
dev->debugfs_client_bus_info =
- debugfs_create_file("client_bus_info", S_IRUSR | S_IRGRP,
+ debugfs_create_file("client_bus_info", 0440,
dev->debugfs_dir, dev,
&client_bus_info_debugfs_fops);
if (!dev->debugfs_client_bus_info) {
debugfs_remove_recursive(visorbus_debugfs_dir);
}
-module_param_named(forcematch, visorbus_forcematch, int, S_IRUGO);
+module_param_named(forcematch, visorbus_forcematch, int, 0444);
MODULE_PARM_DESC(visorbus_forcematch,
"1 to force a successful dev <--> drv match");
-module_param_named(forcenomatch, visorbus_forcenomatch, int, S_IRUGO);
+module_param_named(forcenomatch, visorbus_forcenomatch, int, 0444);
MODULE_PARM_DESC(visorbus_forcenomatch,
"1 to force an UNsuccessful dev <--> drv match");
spinlock_t insert_lock; /* protect head writes in chan_hdr */
spinlock_t remove_lock; /* protect tail writes in chan_hdr */
- struct {
- struct signal_queue_header req_queue;
- struct signal_queue_header rsp_queue;
- struct signal_queue_header event_queue;
- struct signal_queue_header ack_queue;
- } safe_uis_queue;
uuid_le type;
uuid_le inst;
};
static struct visorchannel **file_controlvm_channel;
static struct visorchannel *controlvm_channel;
-
-/* Manages the request payload in the controlvm channel */
-struct visor_controlvm_payload_info {
- u8 *ptr; /* pointer to base address of payload pool */
- u64 offset; /*
- * offset from beginning of controlvm
- * channel to beginning of payload * pool
- */
- u32 bytes; /* number of bytes in payload pool */
-};
-
-static struct visor_controlvm_payload_info controlvm_payload_info;
static unsigned long controlvm_payload_bytes_buffered;
/*
static struct controlvm_message controlvm_pending_msg;
static bool controlvm_pending_msg_valid;
-/*
- * This describes a buffer and its current state of transfer (e.g., how many
- * bytes have already been supplied as putfile data, and how many bytes are
- * remaining) for a putfile_request.
- */
-struct putfile_active_buffer {
- /* a payload from a controlvm message, containing a file data buffer */
- struct parser_context *parser_ctx;
- /* points within data area of parser_ctx to next byte of data */
- size_t bytes_remaining;
-};
-
-#define PUTFILE_REQUEST_SIG 0x0906101302281211
-/*
- * This identifies a single remote --> local CONTROLVM_TRANSMIT_FILE
- * conversation. Structs of this type are dynamically linked into
- * <Putfile_request_list>.
- */
-struct putfile_request {
- u64 sig; /* PUTFILE_REQUEST_SIG */
-
- /* header from original TransmitFile request */
- struct controlvm_message_header controlvm_header;
-
- /* link to next struct putfile_request */
- struct list_head next_putfile_request;
-
- /*
- * head of putfile_buffer_entry list, which describes the data to be
- * supplied as putfile data;
- * - this list is added to when controlvm messages come in that supply
- * file data
- * - this list is removed from via the hotplug program that is actually
- * consuming these buffers to write as file data
- */
- struct list_head input_buffer_list;
- spinlock_t req_list_lock; /* lock for input_buffer_list */
-
- /* waiters for input_buffer_list to go non-empty */
- wait_queue_head_t input_buffer_wq;
-
- /* data not yet read within current putfile_buffer_entry */
- struct putfile_active_buffer active_buf;
-
- /*
- * <0 = failed, 0 = in-progress, >0 = successful;
- * note that this must be set with req_list_lock, and if you set <0,
- * it is your responsibility to also free up all of the other objects
- * in this struct (like input_buffer_list, active_buf.parser_ctx)
- * before releasing the lock
- */
- int completion_status;
-};
-
struct parahotplug_request {
struct list_head list;
int id;
visorchannel_read(controlvm_channel,
offsetof(struct spar_controlvm_channel_protocol,
tool_action), &tool_action, sizeof(u8));
- return scnprintf(buf, PAGE_SIZE, "%u\n", tool_action);
+ return sprintf(buf, "%u\n", tool_action);
}
static ssize_t toolaction_store(struct device *dev,
offsetof(struct spar_controlvm_channel_protocol,
efi_spar_ind), &efi_spar_indication,
sizeof(struct efi_spar_indication));
- return scnprintf(buf, PAGE_SIZE, "%u\n",
- efi_spar_indication.boot_to_tool);
+ return sprintf(buf, "%u\n", efi_spar_indication.boot_to_tool);
}
static ssize_t boottotool_store(struct device *dev,
offsetof(struct spar_controlvm_channel_protocol,
installation_error),
&error, sizeof(u32));
- return scnprintf(buf, PAGE_SIZE, "%i\n", error);
+ return sprintf(buf, "%i\n", error);
}
static ssize_t error_store(struct device *dev, struct device_attribute *attr,
offsetof(struct spar_controlvm_channel_protocol,
installation_text_id),
&text_id, sizeof(u32));
- return scnprintf(buf, PAGE_SIZE, "%i\n", text_id);
+ return sprintf(buf, "%i\n", text_id);
}
static ssize_t textid_store(struct device *dev, struct device_attribute *attr,
offsetof(struct spar_controlvm_channel_protocol,
installation_remaining_steps),
&remaining_steps, sizeof(u16));
- return scnprintf(buf, PAGE_SIZE, "%hu\n", remaining_steps);
+ return sprintf(buf, "%hu\n", remaining_steps);
}
static ssize_t remaining_steps_store(struct device *dev,
{
struct spar_controlvm_parameters_header *phdr = NULL;
- if (!ctx)
- return NULL_UUID_LE;
phdr = (struct spar_controlvm_parameters_header *)(ctx->data);
return phdr->id;
}
-/*
- * Describes the state from the perspective of which controlvm messages have
- * been received for a bus or device.
- */
-
-enum PARSER_WHICH_STRING {
- PARSERSTRING_INITIATOR,
- PARSERSTRING_TARGET,
- PARSERSTRING_CONNECTION,
- PARSERSTRING_NAME, /* TODO: only PARSERSTRING_NAME is used ? */
-};
-
-static void
-parser_param_start(struct parser_context *ctx,
- enum PARSER_WHICH_STRING which_string)
-{
- struct spar_controlvm_parameters_header *phdr = NULL;
-
- if (!ctx)
- return;
-
- phdr = (struct spar_controlvm_parameters_header *)(ctx->data);
- switch (which_string) {
- case PARSERSTRING_INITIATOR:
- ctx->curr = ctx->data + phdr->initiator_offset;
- ctx->bytes_remaining = phdr->initiator_length;
- break;
- case PARSERSTRING_TARGET:
- ctx->curr = ctx->data + phdr->target_offset;
- ctx->bytes_remaining = phdr->target_length;
- break;
- case PARSERSTRING_CONNECTION:
- ctx->curr = ctx->data + phdr->connection_offset;
- ctx->bytes_remaining = phdr->connection_length;
- break;
- case PARSERSTRING_NAME:
- ctx->curr = ctx->data + phdr->name_offset;
- ctx->bytes_remaining = phdr->name_length;
- break;
- default:
- break;
- }
-}
-
static void parser_done(struct parser_context *ctx)
{
- if (!ctx)
- return;
controlvm_payload_bytes_buffered -= ctx->param_bytes;
kfree(ctx);
}
void *value = NULL;
int i;
- if (!ctx)
- return NULL;
pscan = ctx->curr;
nscan = ctx->bytes_remaining;
if (nscan == 0)
return value;
}
+static void *
+parser_name_get(struct parser_context *ctx)
+{
+ struct spar_controlvm_parameters_header *phdr = NULL;
+
+ phdr = (struct spar_controlvm_parameters_header *)(ctx->data);
+
+ if (phdr->name_offset + phdr->name_length > ctx->param_bytes)
+ return NULL;
+
+ ctx->curr = ctx->data + phdr->name_offset;
+ ctx->bytes_remaining = phdr->name_length;
+ return parser_string_get(ctx);
+}
+
struct visor_busdev {
u32 bus_no;
u32 dev_no;
POSTCODE_LINUX(CHIPSET_INIT_ENTRY_PC, 0, 0, DIAG_SEVERITY_PRINT);
if (chipset_inited) {
- rc = -CONTROLVM_RESP_ERROR_ALREADY_DONE;
+ rc = -CONTROLVM_RESP_ALREADY_DONE;
res = -EIO;
goto out_respond;
}
return err;
}
- if (typ == CRASH_BUS) {
+ switch (typ) {
+ case CRASH_DEV:
+ local_crash_msg_offset += sizeof(struct controlvm_message);
err = visorchannel_write(controlvm_channel,
local_crash_msg_offset,
msg,
- sizeof(struct controlvm_message));
+ sizeof(struct controlvm_message));
if (err) {
- POSTCODE_LINUX(SAVE_MSG_BUS_FAILURE_PC, 0, 0,
+ POSTCODE_LINUX(SAVE_MSG_DEV_FAILURE_PC, 0, 0,
DIAG_SEVERITY_ERR);
return err;
}
- } else {
- local_crash_msg_offset += sizeof(struct controlvm_message);
+ break;
+ case CRASH_BUS:
err = visorchannel_write(controlvm_channel,
local_crash_msg_offset,
msg,
sizeof(struct controlvm_message));
if (err) {
- POSTCODE_LINUX(SAVE_MSG_DEV_FAILURE_PC, 0, 0,
+ POSTCODE_LINUX(SAVE_MSG_BUS_FAILURE_PC, 0, 0,
DIAG_SEVERITY_ERR);
return err;
}
+ break;
+ default:
+ pr_info("Invalid crash_obj_type\n");
+ break;
}
return 0;
}
POSTCODE_LINUX(BUS_CREATE_ENTRY_PC, 0, bus_no, DIAG_SEVERITY_PRINT);
- if (uuid_le_cmp(cmd->create_bus.bus_inst_uuid, spar_siovm_uuid) == 0)
- save_crash_message(inmsg, CRASH_BUS);
+ if (uuid_le_cmp(cmd->create_bus.bus_inst_uuid, spar_siovm_uuid) == 0) {
+ err = save_crash_message(inmsg, CRASH_BUS);
+ if (err)
+ goto err_free_bus_info;
+ }
if (inmsg->hdr.flags.response_expected == 1) {
pmsg_hdr = kzalloc(sizeof(*pmsg_hdr),
if (err)
goto err_respond;
- bus_info->partition_uuid = parser_id_get(parser_ctx);
- parser_param_start(parser_ctx, PARSERSTRING_NAME);
- bus_info->name = parser_string_get(parser_ctx);
+ if (parser_ctx) {
+ bus_info->partition_uuid = parser_id_get(parser_ctx);
+ bus_info->name = parser_name_get(parser_ctx);
+ }
POSTCODE_LINUX(BUS_CONFIGURE_EXIT_PC, 0, bus_no,
DIAG_SEVERITY_PRINT);
return err;
}
-static void
+static int
my_device_create(struct controlvm_message *inmsg)
{
struct controlvm_message_packet *cmd = &inmsg->cmd;
struct visor_device *dev_info = NULL;
struct visor_device *bus_info;
struct visorchannel *visorchannel;
- int rc = CONTROLVM_RESP_SUCCESS;
+ int err;
bus_info = visorbus_get_device_by_id(bus_no, BUS_ROOT_DEVICE, NULL);
if (!bus_info) {
POSTCODE_LINUX(DEVICE_CREATE_FAILURE_PC, dev_no, bus_no,
DIAG_SEVERITY_ERR);
- rc = -CONTROLVM_RESP_ERROR_BUS_INVALID;
- goto out_respond;
+ err = -ENODEV;
+ goto err_respond;
}
if (bus_info->state.created == 0) {
POSTCODE_LINUX(DEVICE_CREATE_FAILURE_PC, dev_no, bus_no,
DIAG_SEVERITY_ERR);
- rc = -CONTROLVM_RESP_ERROR_BUS_INVALID;
- goto out_respond;
+ err = -EINVAL;
+ goto err_respond;
}
dev_info = visorbus_get_device_by_id(bus_no, dev_no, NULL);
if (dev_info && (dev_info->state.created == 1)) {
POSTCODE_LINUX(DEVICE_CREATE_FAILURE_PC, dev_no, bus_no,
DIAG_SEVERITY_ERR);
- rc = -CONTROLVM_RESP_ERROR_ALREADY_DONE;
- goto out_respond;
+ err = -EEXIST;
+ goto err_respond;
}
dev_info = kzalloc(sizeof(*dev_info), GFP_KERNEL);
if (!dev_info) {
POSTCODE_LINUX(DEVICE_CREATE_FAILURE_PC, dev_no, bus_no,
DIAG_SEVERITY_ERR);
- rc = -CONTROLVM_RESP_ERROR_KMALLOC_FAILED;
- goto out_respond;
+ err = -ENOMEM;
+ goto err_respond;
}
dev_info->chipset_bus_no = bus_no;
if (!visorchannel) {
POSTCODE_LINUX(DEVICE_CREATE_FAILURE_PC, dev_no, bus_no,
DIAG_SEVERITY_ERR);
- rc = -CONTROLVM_RESP_ERROR_KMALLOC_FAILED;
- goto out_free_dev_info;
+ err = -ENOMEM;
+ goto err_free_dev_info;
}
dev_info->visorchannel = visorchannel;
dev_info->channel_type_guid = cmd->create_device.data_type_uuid;
if (uuid_le_cmp(cmd->create_device.data_type_uuid,
- spar_vhba_channel_protocol_uuid) == 0)
- save_crash_message(inmsg, CRASH_DEV);
+ spar_vhba_channel_protocol_uuid) == 0) {
+ err = save_crash_message(inmsg, CRASH_DEV);
+ if (err)
+ goto err_free_dev_info;
+ }
if (inmsg->hdr.flags.response_expected == 1) {
pmsg_hdr = kzalloc(sizeof(*pmsg_hdr), GFP_KERNEL);
if (!pmsg_hdr) {
- rc = -CONTROLVM_RESP_ERROR_KMALLOC_FAILED;
- goto out_free_dev_info;
+ err = -ENOMEM;
+ goto err_free_dev_info;
}
memcpy(pmsg_hdr, &inmsg->hdr,
chipset_device_create(dev_info);
POSTCODE_LINUX(DEVICE_CREATE_EXIT_PC, dev_no, bus_no,
DIAG_SEVERITY_PRINT);
- return;
+ return 0;
-out_free_dev_info:
+err_free_dev_info:
kfree(dev_info);
-out_respond:
+err_respond:
if (inmsg->hdr.flags.response_expected == 1)
- device_responder(inmsg->hdr.id, &inmsg->hdr, rc);
+ device_responder(inmsg->hdr.id, &inmsg->hdr, err);
+ return err;
}
-static void
+static int
my_device_changestate(struct controlvm_message *inmsg)
{
struct controlvm_message_packet *cmd = &inmsg->cmd;
u32 dev_no = cmd->device_change_state.dev_no;
struct spar_segment_state state = cmd->device_change_state.state;
struct visor_device *dev_info;
- int rc = CONTROLVM_RESP_SUCCESS;
+ int err;
dev_info = visorbus_get_device_by_id(bus_no, dev_no, NULL);
if (!dev_info) {
POSTCODE_LINUX(DEVICE_CHANGESTATE_FAILURE_PC, dev_no, bus_no,
DIAG_SEVERITY_ERR);
- rc = -CONTROLVM_RESP_ERROR_DEVICE_INVALID;
+ err = -ENODEV;
goto err_respond;
}
if (dev_info->state.created == 0) {
POSTCODE_LINUX(DEVICE_CHANGESTATE_FAILURE_PC, dev_no, bus_no,
DIAG_SEVERITY_ERR);
- rc = -CONTROLVM_RESP_ERROR_DEVICE_INVALID;
+ err = -EINVAL;
goto err_respond;
}
if (dev_info->pending_msg_hdr) {
/* only non-NULL if dev is still waiting on a response */
- rc = -CONTROLVM_RESP_ERROR_MESSAGE_ID_INVALID_FOR_CLIENT;
+ err = -EIO;
goto err_respond;
}
if (inmsg->hdr.flags.response_expected == 1) {
pmsg_hdr = kzalloc(sizeof(*pmsg_hdr), GFP_KERNEL);
if (!pmsg_hdr) {
- rc = -CONTROLVM_RESP_ERROR_KMALLOC_FAILED;
+ err = -ENOMEM;
goto err_respond;
}
* Response will be sent from chipset_device_pause.
*/
chipset_device_pause(dev_info);
-
- return;
+ return 0;
err_respond:
if (inmsg->hdr.flags.response_expected == 1)
- device_responder(inmsg->hdr.id, &inmsg->hdr, rc);
+ device_responder(inmsg->hdr.id, &inmsg->hdr, err);
+ return err;
}
-static void
+static int
my_device_destroy(struct controlvm_message *inmsg)
{
struct controlvm_message_packet *cmd = &inmsg->cmd;
u32 bus_no = cmd->destroy_device.bus_no;
u32 dev_no = cmd->destroy_device.dev_no;
struct visor_device *dev_info;
- int rc = CONTROLVM_RESP_SUCCESS;
+ int err;
dev_info = visorbus_get_device_by_id(bus_no, dev_no, NULL);
if (!dev_info) {
- rc = -CONTROLVM_RESP_ERROR_DEVICE_INVALID;
+ err = -ENODEV;
goto err_respond;
}
if (dev_info->state.created == 0) {
- rc = -CONTROLVM_RESP_ERROR_ALREADY_DONE;
+ err = -EINVAL;
goto err_respond;
}
if (dev_info->pending_msg_hdr) {
/* only non-NULL if dev is still waiting on a response */
- rc = -CONTROLVM_RESP_ERROR_MESSAGE_ID_INVALID_FOR_CLIENT;
+ err = -EIO;
goto err_respond;
}
if (inmsg->hdr.flags.response_expected == 1) {
pmsg_hdr = kzalloc(sizeof(*pmsg_hdr), GFP_KERNEL);
if (!pmsg_hdr) {
- rc = -CONTROLVM_RESP_ERROR_KMALLOC_FAILED;
+ err = -ENOMEM;
goto err_respond;
}
}
chipset_device_destroy(dev_info);
- return;
+ return 0;
err_respond:
if (inmsg->hdr.flags.response_expected == 1)
- device_responder(inmsg->hdr.id, &inmsg->hdr, rc);
-}
-
-/**
- * initialize_controlvm_payload_info() - init controlvm_payload_info struct
- * @phys_addr: the physical address of controlvm channel
- * @offset: the offset to payload
- * @bytes: the size of the payload in bytes
- * @info: the returning valid struct
- *
- * When provided with the physical address of the controlvm channel
- * (phys_addr), the offset to the payload area we need to manage
- * (offset), and the size of this payload area (bytes), fills in the
- * controlvm_payload_info struct.
- *
- * Return: CONTROLVM_RESP_SUCCESS for success or a negative for failure
- */
-static int
-initialize_controlvm_payload_info(u64 phys_addr, u64 offset, u32 bytes,
- struct visor_controlvm_payload_info *info)
-{
- u8 *payload = NULL;
-
- if (!info)
- return -CONTROLVM_RESP_ERROR_PAYLOAD_INVALID;
-
- if ((offset == 0) || (bytes == 0))
- return -CONTROLVM_RESP_ERROR_PAYLOAD_INVALID;
-
- payload = memremap(phys_addr + offset, bytes, MEMREMAP_WB);
- if (!payload)
- return -CONTROLVM_RESP_ERROR_IOREMAP_FAILED;
-
- memset(info, 0, sizeof(struct visor_controlvm_payload_info));
- info->offset = offset;
- info->bytes = bytes;
- info->ptr = payload;
-
- return CONTROLVM_RESP_SUCCESS;
-}
-
-static void
-destroy_controlvm_payload_info(struct visor_controlvm_payload_info *info)
-{
- if (info->ptr) {
- memunmap(info->ptr);
- info->ptr = NULL;
- }
- memset(info, 0, sizeof(struct visor_controlvm_payload_info));
-}
-
-static void
-initialize_controlvm_payload(void)
-{
- u64 phys_addr = visorchannel_get_physaddr(controlvm_channel);
- u64 payload_offset = 0;
- u32 payload_bytes = 0;
-
- if (visorchannel_read(controlvm_channel,
- offsetof(struct spar_controlvm_channel_protocol,
- request_payload_offset),
- &payload_offset, sizeof(payload_offset)) < 0) {
- POSTCODE_LINUX(CONTROLVM_INIT_FAILURE_PC, 0, 0,
- DIAG_SEVERITY_ERR);
- return;
- }
- if (visorchannel_read(controlvm_channel,
- offsetof(struct spar_controlvm_channel_protocol,
- request_payload_bytes),
- &payload_bytes, sizeof(payload_bytes)) < 0) {
- POSTCODE_LINUX(CONTROLVM_INIT_FAILURE_PC, 0, 0,
- DIAG_SEVERITY_ERR);
- return;
- }
- initialize_controlvm_payload_info(phys_addr,
- payload_offset, payload_bytes,
- &controlvm_payload_info);
+ device_responder(inmsg->hdr.id, &inmsg->hdr, err);
+ return err;
}
/*
- * The general parahotplug flow works as follows. The visorchipset
- * driver receives a DEVICE_CHANGESTATE message from Command
- * specifying a physical device to enable or disable. The CONTROLVM
- * message handler calls parahotplug_process_message, which then adds
- * the message to a global list and kicks off a udev event which
- * causes a user level script to enable or disable the specified
- * device. The udev script then writes to
- * /proc/visorchipset/parahotplug, which causes parahotplug_proc_write
- * to get called, at which point the appropriate CONTROLVM message is
- * retrieved from the list and responded to.
+ * The general parahotplug flow works as follows. The visorchipset receives
+ * a DEVICE_CHANGESTATE message from Command specifying a physical device
+ * to enable or disable. The CONTROLVM message handler calls
+ * parahotplug_process_message, which then adds the message to a global list
+ * and kicks off a udev event which causes a user level script to enable or
+ * disable the specified device. The udev script then writes to
+ * /sys/devices/platform/visorchipset/parahotplug, which causes the
+ * parahotplug store functions to get called, at which point the
+ * appropriate CONTROLVM message is retrieved from the list and responded
+ * to.
*/
#define PARAHOTPLUG_TIMEOUT_MS 2000
/**
- * parahotplug_next_id() - generate unique int to match an outstanding CONTROLVM
- * message with a udev script /proc response
+ * parahotplug_next_id() - generate unique int to match an outstanding
+ * CONTROLVM message with a udev script /sys
+ * response
*
* Return: a unique integer value
*/
* @id: the id of the request
* @active: indicates whether the request is assigned to active partition
*
- * Called from the /proc handler, which means the user script has
+ * Called from the /sys handler, which means the user script has
* finished the enable/disable. Find the matching identifier, and
* respond to the CONTROLVM message with success.
*
*
* devices are automatically enabled at
* initialization.
- */
+ */
parahotplug_request_kickoff(req);
controlvm_respond_physdev_changestate
(&inmsg->hdr,
}
}
-/**
- * visorchipset_chipset_ready() - sends chipset_ready action
+/*
+ * chipset_ready_uevent() - sends chipset_ready action
*
* Send ACTION=online for DEVPATH=/sys/devices/platform/visorchipset.
*
- * Return: CONTROLVM_RESP_SUCCESS
+ * Return: 0 on success, negative on failure
*/
static int
-visorchipset_chipset_ready(void)
+chipset_ready_uevent(struct controlvm_message_header *msg_hdr)
{
kobject_uevent(&visorchipset_platform_device.dev.kobj, KOBJ_ONLINE);
- return CONTROLVM_RESP_SUCCESS;
+
+ if (msg_hdr->flags.response_expected)
+ return controlvm_respond(msg_hdr, CONTROLVM_RESP_SUCCESS);
+
+ return 0;
}
+/*
+ * chipset_selftest_uevent() - sends chipset_selftest action
+ *
+ * Send ACTION=online for DEVPATH=/sys/devices/platform/visorchipset.
+ *
+ * Return: 0 on success, negative on failure
+ */
static int
-visorchipset_chipset_selftest(void)
+chipset_selftest_uevent(struct controlvm_message_header *msg_hdr)
{
char env_selftest[20];
char *envp[] = { env_selftest, NULL };
sprintf(env_selftest, "SPARSP_SELFTEST=%d", 1);
kobject_uevent_env(&visorchipset_platform_device.dev.kobj, KOBJ_CHANGE,
envp);
- return CONTROLVM_RESP_SUCCESS;
+
+ if (msg_hdr->flags.response_expected)
+ return controlvm_respond(msg_hdr, CONTROLVM_RESP_SUCCESS);
+
+ return 0;
}
-/**
- * visorchipset_chipset_notready() - sends chipset_notready action
+/*
+ * chipset_notready_uevent() - sends chipset_notready action
*
* Send ACTION=offline for DEVPATH=/sys/devices/platform/visorchipset.
*
- * Return: CONTROLVM_RESP_SUCCESS
+ * Return: 0 on success, negative on failure
*/
static int
-visorchipset_chipset_notready(void)
+chipset_notready_uevent(struct controlvm_message_header *msg_hdr)
{
kobject_uevent(&visorchipset_platform_device.dev.kobj, KOBJ_OFFLINE);
- return CONTROLVM_RESP_SUCCESS;
-}
-
-static void
-chipset_ready(struct controlvm_message_header *msg_hdr)
-{
- int rc = visorchipset_chipset_ready();
- if (rc != CONTROLVM_RESP_SUCCESS)
- rc = -rc;
if (msg_hdr->flags.response_expected)
- controlvm_respond(msg_hdr, rc);
-}
-
-static void
-chipset_selftest(struct controlvm_message_header *msg_hdr)
-{
- int rc = visorchipset_chipset_selftest();
+ return controlvm_respond(msg_hdr, CONTROLVM_RESP_SUCCESS);
- if (rc != CONTROLVM_RESP_SUCCESS)
- rc = -rc;
- if (msg_hdr->flags.response_expected)
- controlvm_respond(msg_hdr, rc);
-}
-
-static void
-chipset_notready(struct controlvm_message_header *msg_hdr)
-{
- int rc = visorchipset_chipset_notready();
-
- if (rc != CONTROLVM_RESP_SUCCESS)
- rc = -rc;
- if (msg_hdr->flags.response_expected)
- controlvm_respond(msg_hdr, rc);
+ return 0;
}
static inline unsigned int
int allocbytes = sizeof(struct parser_context) + bytes;
struct parser_context *ctx;
- if (retry)
- *retry = false;
+ *retry = false;
/*
* alloc an 0 extra byte to ensure payload is
allocbytes++;
if ((controlvm_payload_bytes_buffered + bytes)
> MAX_CONTROLVM_PAYLOAD_BYTES) {
- if (retry)
- *retry = true;
+ *retry = true;
return NULL;
}
ctx = kzalloc(allocbytes, GFP_KERNEL | __GFP_NORETRY);
if (!ctx) {
- if (retry)
- *retry = true;
+ *retry = true;
return NULL;
}
controlvm_respond(&inmsg.hdr, CONTROLVM_RESP_SUCCESS);
break;
case CONTROLVM_CHIPSET_READY:
- chipset_ready(&inmsg.hdr);
+ chipset_ready_uevent(&inmsg.hdr);
break;
case CONTROLVM_CHIPSET_SELFTEST:
- chipset_selftest(&inmsg.hdr);
+ chipset_selftest_uevent(&inmsg.hdr);
break;
case CONTROLVM_CHIPSET_STOP:
- chipset_notready(&inmsg.hdr);
+ chipset_notready_uevent(&inmsg.hdr);
break;
default:
if (inmsg.hdr.flags.response_expected)
controlvm_respond
- (&inmsg.hdr,
- -CONTROLVM_RESP_ERROR_MESSAGE_ID_UNKNOWN);
+ (&inmsg.hdr, -CONTROLVM_RESP_ID_UNKNOWN);
break;
}
if (req->msg.hdr.flags.response_expected)
controlvm_respond_physdev_changestate(
&req->msg.hdr,
- CONTROLVM_RESP_ERROR_DEVICE_UDEV_TIMEOUT,
+ CONTROLVM_RESP_DEVICE_UDEV_TIMEOUT,
req->msg.cmd.device_change_state.state);
parahotplug_request_destroy(req);
}
if (!controlvm_channel)
goto error;
- if (SPAR_CONTROLVM_CHANNEL_OK_CLIENT(
- visorchannel_get_header(controlvm_channel))) {
- initialize_controlvm_payload();
- } else {
+ if (!SPAR_CONTROLVM_CHANNEL_OK_CLIENT(
+ visorchannel_get_header(controlvm_channel)))
goto error_destroy_channel;
- }
major_dev = MKDEV(visorchipset_major, 0);
err = visorchipset_file_init(major_dev, &controlvm_channel);
if (err < 0)
- goto error_destroy_payload;
+ goto error_destroy_channel;
/* if booting in a crash kernel */
if (is_kdump_kernel())
cancel_delayed_work_sync(&periodic_controlvm_work);
visorchipset_file_cleanup(major_dev);
-error_destroy_payload:
- destroy_controlvm_payload_info(&controlvm_payload_info);
-
error_destroy_channel:
visorchannel_destroy(controlvm_channel);
visorbus_exit();
cancel_delayed_work_sync(&periodic_controlvm_work);
- destroy_controlvm_payload_info(&controlvm_payload_info);
visorchannel_destroy(controlvm_channel);
acpi_bus_unregister_driver(&unisys_acpi_driver);
}
-module_param_named(major, visorchipset_major, int, S_IRUGO);
+module_param_named(major, visorchipset_major, int, 0444);
MODULE_PARM_DESC(visorchipset_major,
"major device number to use for the device node");
#define __IOMONINTF_H__
/*
-* This file contains all structures needed to support the VMCALLs for IO
-* Virtualization. The VMCALLs are provided by Monitor and used by IO code
-* running on IO Partitions.
-*/
+ * This file contains all structures needed to support the VMCALLs for IO
+ * Virtualization. The VMCALLs are provided by Monitor and used by IO code
+ * running on IO Partitions.
+ */
static inline unsigned long
__unisys_vmcall_gnuc(unsigned long tuple, unsigned long reg_ebx,
unsigned long reg_ecx)
/* The Send and Receive Buffers of the IO Queue may both be full */
#define IOS_ERROR_THRESHOLD 1000
-/* MAX_BUF = 6 lines x 10 MAXVHBA x 80 characters
- * = 4800 bytes ~ 2^13 = 8192 bytes
- */
-#define MAX_BUF 8192
#define MAX_PENDING_REQUESTS (MIN_NUMSIGNALS * 2)
#define VISORHBA_ERROR_COUNT 30
/**
* visornic_disable_with_timeout - Disable network adapter
- * @netdev: netdevice to disale
+ * @netdev: netdevice to disable
* @timeout: timeout to wait for disable
*
* Disable the network adapter and inform the IO Partition that we
if (devdata->enab_dis_acked)
break;
if (devdata->server_down || devdata->server_change_state) {
- spin_unlock_irqrestore(&devdata->priv_lock, flags);
dev_dbg(&netdev->dev, "%s server went away\n",
__func__);
- return -EIO;
+ break;
}
set_current_state(TASK_INTERRUPTIBLE);
spin_unlock_irqrestore(&devdata->priv_lock, flags);
return -ENOMEM;
count = i;
- /* Ensure we can alloc 2/3rd of the requeested number of buffers.
+ /* Ensure we can alloc 2/3rd of the requested number of buffers.
* 2/3 is an arbitrary choice; used also in ndis init.c
*/
if (count < ((2 * devdata->num_rcv_bufs) / 3)) {
*
* Sends enable to IOVM, inits, and posts receive buffers to IOVM
* timeout is defined in msecs (timeout of 0 specifies infinite wait)
- * Return 0 for success, negavite for failure.
+ * Return 0 for success, negative for failure.
*/
static int
visornic_enable_with_timeout(struct net_device *netdev, const int timeout)
unsigned long flags;
int wait = 0;
+ napi_enable(&devdata->napi);
+
/* NOTE: the other end automatically unposts the rcv buffers when it
* gets a disable.
*/
/* send enable and wait for ack -- don't hold lock when sending enable
* because if the queue is full, insert might sleep.
*/
- napi_enable(&devdata->napi);
send_enbdis(netdev, 1, devdata);
spin_lock_irqsave(&devdata->priv_lock, flags);
if (devdata->enab_dis_acked)
break;
if (devdata->server_down || devdata->server_change_state) {
- spin_unlock_irqrestore(&devdata->priv_lock, flags);
dev_dbg(&netdev->dev, "%s server went away\n",
__func__);
- return -EIO;
+ break;
}
set_current_state(TASK_INTERRUPTIBLE);
spin_unlock_irqrestore(&devdata->priv_lock, flags);
* @skb: Packet to be sent
* @netdev: net device the packet is being sent from
*
- * Convert the skb to a cmdrsp so the IO Partition can undersand it.
+ * Convert the skb to a cmdrsp so the IO Partition can understand it.
* Send the XMIT command to the IO Partition for processing. This
* function is protected from concurrent calls by a spinlock xmit_lock
* in the net_device struct, but as soon as the function returns it
*
* Got a receive packet back from the IO Part, handle it and send
* it up the stack.
- * Returns 1 iff an skb was receieved, otherwise 0
+ * Returns 1 iff an skb was received, otherwise 0
*/
static int
visornic_rx(struct uiscmdrsp *cmdrsp)
}
}
- /* set up packet's protocl type using ethernet header - this
+ /* set up packet's protocol type using ethernet header - this
* sets up skb->pkt_type & it also PULLS out the eth header
*/
skb->protocol = eth_type_trans(skb, netdev);
* @cmdrsp: io channel command response message
* @devdata: visornic device to drain
*
- * Drain the respones queue of any responses from the IO partition.
+ * Drain the response queue of any responses from the IO partition.
* Process the responses as we get them.
* Returns when response queue is empty or when the thread stops.
*/
* poll_for_irq - Checks the status of the response queue.
* @v: void pointer to the visronic devdata
*
- * Main function of the vnic_incoming thread. Peridocially check the
+ * Main function of the vnic_incoming thread. Periodically check the
* response queue and drain it if needed.
* Returns when thread has stopped.
*/
netdev->watchdog_timeo = 5 * HZ;
SET_NETDEV_DEV(netdev, &dev->device);
- /* Get MAC adddress from channel and read it into the device. */
+ /* Get MAC address from channel and read it into the device. */
netdev->addr_len = ETH_ALEN;
channel_offset = offsetof(struct spar_io_channel_protocol,
vnic.macaddr);
/* TODO: Setup Interrupt information */
/* Let's start our threads to get responses */
- netif_napi_add(netdev, &devdata->napi, visornic_poll, 64);
+ netif_napi_add(netdev, &devdata->napi, visornic_poll, NAPI_WEIGHT);
setup_timer(&devdata->irq_poll_timer, poll_for_irq,
(unsigned long)devdata);
goto cleanup_napi_add;
}
- /* Let's start our threads to get responses */
- netif_napi_add(netdev, &devdata->napi, visornic_poll, NAPI_WEIGHT);
-
- /* Note: Interupts have to be enable before the while
+ /* Note: Interrupts have to be enable before the while
* loop below because the napi routine is responsible for
* setting enab_dis_acked
*/
goto cleanup_napi_add;
}
- /* create debgug/sysfs directories */
+ /* create debug/sysfs directories */
devdata->eth_debugfs_dir = debugfs_create_dir(netdev->name,
visornic_debugfs_dir);
if (!devdata->eth_debugfs_dir) {
*/
mod_timer(&devdata->irq_poll_timer, msecs_to_jiffies(2));
- init_rcv_bufs(netdev, devdata);
-
rtnl_lock();
dev_open(netdev);
rtnl_unlock();
System driver struct
*****************************************************************************/
-struct opaque_vchi_connection_api_t
-{
+struct opaque_vchi_connection_api_t {
// Routine to init the connection
VCHI_CONNECTION_INIT_T init;
MESSAGE_EVENT_MSG_DISCARDED
} MESSAGE_EVENT_TYPE_T;
-typedef enum vchi_msg_flags
-{
+typedef enum vchi_msg_flags {
VCHI_MSG_FLAGS_NONE = 0x0,
VCHI_MSG_FLAGS_TERMINATE_DMA = 0x1
} VCHI_MSG_FLAGS_T;
-typedef enum message_tx_channel
-{
+typedef enum message_tx_channel {
MESSAGE_TX_CHANNEL_MESSAGE = 0,
MESSAGE_TX_CHANNEL_BULK = 1 // drivers may provide multiple bulk channels, from 1 upwards
} MESSAGE_TX_CHANNEL_T;
#define MESSAGE_TX_CHANNEL_BULK_PREV(c) (MESSAGE_TX_CHANNEL_BULK+((c)-MESSAGE_TX_CHANNEL_BULK+VCHI_MAX_BULK_TX_CHANNELS_PER_CONNECTION-1)%VCHI_MAX_BULK_TX_CHANNELS_PER_CONNECTION)
#define MESSAGE_TX_CHANNEL_BULK_NEXT(c) (MESSAGE_TX_CHANNEL_BULK+((c)-MESSAGE_TX_CHANNEL_BULK+1)%VCHI_MAX_BULK_TX_CHANNELS_PER_CONNECTION)
-typedef enum message_rx_channel
-{
+typedef enum message_rx_channel {
MESSAGE_RX_CHANNEL_MESSAGE = 0,
MESSAGE_RX_CHANNEL_BULK = 1 // drivers may provide multiple bulk channels, from 1 upwards
} MESSAGE_RX_CHANNEL_T;
#define VCHI_VERSION(v_) { v_, v_ }
#define VCHI_VERSION_EX(v_, m_) { v_, m_ }
-typedef enum
-{
+typedef enum {
VCHI_VEC_POINTER,
VCHI_VEC_HANDLE,
VCHI_VEC_LIST
typedef struct vchi_msg_vector_ex {
VCHI_MSG_VECTOR_TYPE_T type;
- union
- {
+ union {
// a memory handle
- struct
- {
+ struct {
VCHI_MEM_HANDLE_T handle;
uint32_t offset;
int32_t vec_len;
} handle;
// an ordinary data pointer
- struct
- {
+ struct {
const void *vec_base;
int32_t vec_len;
} ptr;
// a nested vector list
- struct
- {
+ struct {
struct vchi_msg_vector_ex *vec;
uint32_t vec_len;
} list;
// Descriptor for a held message. Allocated by client, initialised by vchi_msg_hold,
// vchi_msg_iter_hold or vchi_msg_iter_hold_next. Fields are for internal VCHI use only.
-typedef struct
-{
+typedef struct {
struct opaque_vchi_service_t *service;
void *message;
} VCHI_HELD_MSG_T;
VCHI_SERVICE_OPTION_T option,
int value);
-// Routine to send a message across a service
-extern int32_t
- vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,
- ssize_t (*copy_callback)(void *context, void *dest,
- size_t offset, size_t maxsize),
- void *context,
- uint32_t data_size);
+/* Routine to send a message from kernel memory across a service */
+extern int
+vchi_queue_kernel_message(VCHI_SERVICE_HANDLE_T 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,
+ void __user *data,
+ unsigned int size);
// Routine to receive a msg from a service
// Dequeue is equivalent to hold, copy into client buffer, release
//flags used when sending messages (must be bitmapped)
-typedef enum
-{
+typedef enum {
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
} VCHI_CRC_CONTROL_T;
//callback reasons when an event occurs on a service
-typedef enum
-{
+typedef enum {
VCHI_CALLBACK_REASON_MIN,
//This indicates that there is data available
} VCHI_CALLBACK_REASON_T;
// service control options
-typedef enum
-{
+typedef enum {
VCHI_SERVICE_OPTION_MIN,
VCHI_SERVICE_OPTION_TRACE,
+++ /dev/null
-/**
- * Copyright (c) 2010-2012 Broadcom. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- * to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") version 2, as published by the Free
- * Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef VCHIQ_2835_H
-#define VCHIQ_2835_H
-
-#include "vchiq_pagelist.h"
-
-#define VCHIQ_PLATFORM_FRAGMENTS_OFFSET_IDX 0
-#define VCHIQ_PLATFORM_FRAGMENTS_COUNT_IDX 1
-
-#endif /* VCHIQ_2835_H */
#define TOTAL_SLOTS (VCHIQ_SLOT_ZERO_SLOTS + 2 * 32)
#include "vchiq_arm.h"
-#include "vchiq_2835.h"
#include "vchiq_connected.h"
#include "vchiq_killable.h"
+#include "vchiq_pagelist.h"
#define MAX_FRAGMENTS (VCHIQ_NUM_CURRENT_BULKS * 2)
+#define VCHIQ_PLATFORM_FRAGMENTS_OFFSET_IDX 0
+#define VCHIQ_PLATFORM_FRAGMENTS_COUNT_IDX 1
+
#define BELL0 0x00
#define BELL2 0x08
typedef struct vchiq_2835_state_struct {
- int inited;
- VCHIQ_ARM_STATE_T arm_state;
+ int inited;
+ VCHIQ_ARM_STATE_T arm_state;
} VCHIQ_2835_ARM_STATE_T;
struct vchiq_pagelist_info {
vchiq_call_connected_callbacks();
- return 0;
+ return 0;
}
VCHIQ_STATUS_T
vchiq_platform_init_state(VCHIQ_STATE_T *state)
{
- VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
- state->platform_state = kzalloc(sizeof(VCHIQ_2835_ARM_STATE_T), GFP_KERNEL);
- ((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->inited = 1;
- status = vchiq_arm_init_state(state, &((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->arm_state);
- if(status != VCHIQ_SUCCESS)
- {
- ((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->inited = 0;
- }
- return status;
+ VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
+ state->platform_state = kzalloc(sizeof(VCHIQ_2835_ARM_STATE_T), GFP_KERNEL);
+ ((VCHIQ_2835_ARM_STATE_T *)state->platform_state)->inited = 1;
+ status = vchiq_arm_init_state(state, &((VCHIQ_2835_ARM_STATE_T *)state->platform_state)->arm_state);
+ if (status != VCHIQ_SUCCESS)
+ {
+ ((VCHIQ_2835_ARM_STATE_T *)state->platform_state)->inited = 0;
+ }
+ return status;
}
VCHIQ_ARM_STATE_T*
vchiq_platform_get_arm_state(VCHIQ_STATE_T *state)
{
- if(!((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->inited)
- {
- BUG();
- }
- return &((VCHIQ_2835_ARM_STATE_T*)state->platform_state)->arm_state;
+ if (!((VCHIQ_2835_ARM_STATE_T *)state->platform_state)->inited)
+ {
+ BUG();
+ }
+ return &((VCHIQ_2835_ARM_STATE_T *)state->platform_state)->arm_state;
}
void
VCHIQ_STATUS_T
vchiq_platform_suspend(VCHIQ_STATE_T *state)
{
- return VCHIQ_ERROR;
+ return VCHIQ_ERROR;
}
VCHIQ_STATUS_T
vchiq_platform_resume(VCHIQ_STATE_T *state)
{
- return VCHIQ_SUCCESS;
+ return VCHIQ_SUCCESS;
}
void
}
int
-vchiq_platform_videocore_wanted(VCHIQ_STATE_T* state)
+vchiq_platform_videocore_wanted(VCHIQ_STATE_T *state)
{
- return 1; // autosuspend not supported - videocore always wanted
+ return 1; // autosuspend not supported - videocore always wanted
}
int
vchiq_platform_use_suspend_timer(void)
{
- return 0;
+ return 0;
}
void
vchiq_dump_platform_use_state(VCHIQ_STATE_T *state)
#define VCHIQ_MINOR 0
/* Some per-instance constants */
-#define MAX_COMPLETIONS 16
+#define MAX_COMPLETIONS 128
#define MAX_SERVICES 64
#define MAX_ELEMENTS 8
-#define MSG_QUEUE_SIZE 64
+#define MSG_QUEUE_SIZE 128
#define KEEPALIVE_VER 1
#define KEEPALIVE_VER_MIN KEEPALIVE_VER
(VCHIQ_IOC_MAX + 1));
static void
-dump_phys_mem(void *virt_addr, uint32_t num_bytes);
+dump_phys_mem(void *virt_addr, u32 num_bytes);
/****************************************************************************
*
void *bulk_userdata)
{
VCHIQ_COMPLETION_DATA_T *completion;
+ int insert;
DEBUG_INITIALISE(g_state.local)
- while (instance->completion_insert ==
- (instance->completion_remove + MAX_COMPLETIONS)) {
+ insert = instance->completion_insert;
+ while ((insert - instance->completion_remove) >= MAX_COMPLETIONS) {
/* Out of space - wait for the client */
DEBUG_TRACE(SERVICE_CALLBACK_LINE);
vchiq_log_trace(vchiq_arm_log_level,
} else if (instance->closing) {
vchiq_log_info(vchiq_arm_log_level,
"service_callback closing");
- return VCHIQ_ERROR;
+ return VCHIQ_SUCCESS;
}
DEBUG_TRACE(SERVICE_CALLBACK_LINE);
}
- completion =
- &instance->completions[instance->completion_insert &
- (MAX_COMPLETIONS - 1)];
+ completion = &instance->completions[insert & (MAX_COMPLETIONS - 1)];
completion->header = header;
completion->reason = reason;
wmb();
if (reason == VCHIQ_MESSAGE_AVAILABLE)
- user_service->message_available_pos =
- instance->completion_insert;
- instance->completion_insert++;
+ user_service->message_available_pos = insert;
+
+ insert++;
+ instance->completion_insert = insert;
up(&instance->insert_event);
USER_SERVICE_T *user_service;
VCHIQ_SERVICE_T *service;
VCHIQ_INSTANCE_T instance;
+ bool skip_completion = false;
DEBUG_INITIALISE(g_state.local)
DEBUG_TRACE(SERVICE_CALLBACK_LINE);
user_service->msg_queue[user_service->msg_insert &
(MSG_QUEUE_SIZE - 1)] = header;
user_service->msg_insert++;
- spin_unlock(&msg_queue_spinlock);
-
- up(&user_service->insert_event);
/* If there is a thread waiting in DEQUEUE_MESSAGE, or if
** there is a MESSAGE_AVAILABLE in the completion queue then
if (((user_service->message_available_pos -
instance->completion_remove) >= 0) ||
user_service->dequeue_pending) {
- DEBUG_TRACE(SERVICE_CALLBACK_LINE);
user_service->dequeue_pending = 0;
- return VCHIQ_SUCCESS;
+ skip_completion = true;
}
+ spin_unlock(&msg_queue_spinlock);
+ up(&user_service->insert_event);
+
header = NULL;
}
DEBUG_TRACE(SERVICE_CALLBACK_LINE);
+ if (skip_completion)
+ return VCHIQ_SUCCESS;
+
return add_completion(instance, reason, header, user_service,
bulk_userdata);
}
USER_SERVICE_T *user_service =
(USER_SERVICE_T *)service->base.userdata;
/* close_pending is false on first entry, and when the
- wait in vchiq_close_service has been interrupted. */
+ wait in vchiq_close_service has been interrupted. */
if (!user_service->close_pending) {
status = vchiq_close_service(service->handle);
if (status != VCHIQ_SUCCESS)
USER_SERVICE_T *user_service =
(USER_SERVICE_T *)service->base.userdata;
/* close_pending is false on first entry, and when the
- wait in vchiq_close_service has been interrupted. */
+ wait in vchiq_close_service has been interrupted. */
if (!user_service->close_pending) {
status = vchiq_remove_service(service->handle);
if (status != VCHIQ_SUCCESS)
}
DEBUG_TRACE(AWAIT_COMPLETION_LINE);
- /* A read memory barrier is needed to stop prefetch of a stale
- ** completion record
- */
- rmb();
-
if (ret == 0) {
int msgbufcount = args.msgbufcount;
+ int remove = instance->completion_remove;
+
for (ret = 0; ret < args.count; ret++) {
VCHIQ_COMPLETION_DATA_T *completion;
VCHIQ_SERVICE_T *service;
USER_SERVICE_T *user_service;
VCHIQ_HEADER_T *header;
- if (instance->completion_remove ==
- instance->completion_insert)
+
+ if (remove == instance->completion_insert)
break;
+
completion = &instance->completions[
- instance->completion_remove &
- (MAX_COMPLETIONS - 1)];
+ remove & (MAX_COMPLETIONS - 1)];
+
+ /*
+ * A read memory barrier is needed to stop
+ * prefetch of a stale completion record
+ */
+ rmb();
service = completion->service_userdata;
user_service = service->base.userdata;
break;
}
- instance->completion_remove++;
+ /*
+ * Ensure that the above copy has completed
+ * before advancing the remove pointer.
+ */
+ mb();
+ remove++;
+ instance->completion_remove = remove;
}
if (msgbufcount != args.msgbufcount) {
***************************************************************************/
static void
-dump_phys_mem(void *virt_addr, uint32_t num_bytes)
+dump_phys_mem(void *virt_addr, u32 num_bytes)
{
int rc;
- uint8_t *end_virt_addr = virt_addr + num_bytes;
+ u8 *end_virt_addr = virt_addr + num_bytes;
int num_pages;
int offset;
int end_offset;
int prev_idx;
struct page *page;
struct page **pages;
- uint8_t *kmapped_virt_ptr;
+ u8 *kmapped_virt_ptr;
/* Align virtAddr and endVirtAddr to 16 byte boundaries. */
if (vchiq_arm_log_level >= VCHIQ_LOG_TRACE)
vchiq_log_dump_mem("ph",
- (uint32_t)(unsigned long)&kmapped_virt_ptr[
+ (u32)(unsigned long)&kmapped_virt_ptr[
page_offset],
&kmapped_virt_ptr[page_offset], 16);
&arm_state->blocked_blocker, timeout_val)
<= 0) {
vchiq_log_error(vchiq_susp_log_level, "%s wait for "
- "previously blocked clients failed" , __func__);
+ "previously blocked clients failed", __func__);
status = VCHIQ_ERROR;
write_lock_bh(&arm_state->susp_res_lock);
goto out;
if (resume_count > 1) {
status = VCHIQ_ERROR;
vchiq_log_error(vchiq_susp_log_level, "%s waited too "
- "many times for resume" , __func__);
+ "many times for resume", __func__);
goto out;
}
write_unlock_bh(&arm_state->susp_res_lock);
return resume;
}
-void
-vchiq_platform_check_resume(VCHIQ_STATE_T *state)
-{
- VCHIQ_ARM_STATE_T *arm_state = vchiq_platform_get_arm_state(state);
- int res = 0;
-
- if (!arm_state)
- goto out;
-
- vchiq_log_trace(vchiq_susp_log_level, "%s", __func__);
-
- write_lock_bh(&arm_state->susp_res_lock);
- if (arm_state->wake_address == 0) {
- vchiq_log_info(vchiq_susp_log_level,
- "%s: already awake", __func__);
- goto unlock;
- }
- if (arm_state->vc_resume_state == VC_RESUME_IN_PROGRESS) {
- vchiq_log_info(vchiq_susp_log_level,
- "%s: already resuming", __func__);
- goto unlock;
- }
-
- if (arm_state->vc_resume_state == VC_RESUME_REQUESTED) {
- set_resume_state(arm_state, VC_RESUME_IN_PROGRESS);
- res = 1;
- } else
- vchiq_log_trace(vchiq_susp_log_level,
- "%s: not resuming (resume state %s)", __func__,
- resume_state_names[arm_state->vc_resume_state +
- VC_RESUME_NUM_OFFSET]);
-
-unlock:
- write_unlock_bh(&arm_state->susp_res_lock);
-
- if (res)
- vchiq_platform_resume(state);
-
-out:
- vchiq_log_trace(vchiq_susp_log_level, "%s exit", __func__);
- return;
-
-}
-
-
-
VCHIQ_STATUS_T
vchiq_use_internal(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service,
enum USE_TYPE_E use_type)
if (state->conn_state == VCHIQ_CONNSTATE_CONNECTED) {
write_lock_bh(&arm_state->susp_res_lock);
if (!arm_state->first_connect) {
- char threadname[10];
+ char threadname[16];
arm_state->first_connect = 1;
write_unlock_bh(&arm_state->susp_res_lock);
- snprintf(threadname, sizeof(threadname), "VCHIQka-%d",
+ snprintf(threadname, sizeof(threadname), "vchiq-keep/%d",
state->id);
arm_state->ka_thread = kthread_create(
&vchiq_keepalive_thread_func,
extern void
vchiq_check_suspend(VCHIQ_STATE_T *state);
- VCHIQ_STATUS_T
+VCHIQ_STATUS_T
vchiq_use_service(VCHIQ_SERVICE_HANDLE_T handle);
extern VCHIQ_STATUS_T
static DEFINE_SPINLOCK(service_spinlock);
DEFINE_SPINLOCK(bulk_waiter_spinlock);
-DEFINE_SPINLOCK(quota_spinlock);
+static DEFINE_SPINLOCK(quota_spinlock);
VCHIQ_STATE_T *vchiq_states[VCHIQ_MAX_STATES];
static unsigned int handle_seq;
inline void
request_poll(VCHIQ_STATE_T *state, VCHIQ_SERVICE_T *service, int poll_type)
{
- uint32_t value;
+ u32 value;
if (service) {
do {
BITSET_T service_found[BITSET_SIZE(VCHIQ_MAX_SERVICES)];
int slot_queue_available;
- /* Use a read memory barrier to ensure that any state that may have
- ** been modified by another thread is not masked by stale prefetched
- ** values. */
- rmb();
-
/* Find slots which have been freed by the other side, and return them
** to the available queue. */
slot_queue_available = state->slot_queue_available;
+ /*
+ * Use a memory barrier to ensure that any state that may have been
+ * modified by another thread is not masked by stale prefetched
+ * values.
+ */
+ mb();
+
while (slot_queue_available != local->slot_queue_recycle) {
unsigned int pos;
int slot_index = local->slot_queue[slot_queue_available++ &
char *data = (char *)SLOT_DATA_FROM_INDEX(state, slot_index);
int data_found = 0;
+ /*
+ * Beware of the address dependency - data is calculated
+ * using an index written by the other side.
+ */
+ rmb();
+
vchiq_log_trace(vchiq_core_log_level, "%d: pfq %d=%pK %x %x",
state->id, slot_index, data,
local->slot_queue_recycle, slot_queue_available);
up(&state->data_quota_event);
}
+ /*
+ * Don't allow the slot to be reused until we are no
+ * longer interested in it.
+ */
+ mb();
+
state->slot_queue_available = slot_queue_available;
up(&state->slot_available_event);
}
VCHIQ_LOG_INFO))
vchiq_log_dump_mem("Sent", 0,
header->data,
- min((size_t)64,
+ min((size_t)16,
(size_t)callback_result));
spin_lock("a_spinlock);
VCHIQ_LOG_INFO))
vchiq_log_dump_mem("Sent", 0,
header->data,
- min((size_t)64,
+ min((size_t)16,
(size_t)callback_result));
VCHIQ_SERVICE_STATS_INC(service, ctrl_tx_count);
int group, i;
for (group = 0; group < BITSET_SIZE(state->unused_service); group++) {
- uint32_t flags;
+ u32 flags;
flags = atomic_xchg(&state->poll_services[group], 0);
for (i = 0; flags; i++) {
if (flags & (1 << i)) {
VCHIQ_SERVICE_T *service =
find_service_by_port(state,
(group<<5) + i);
- uint32_t service_flags;
+ u32 service_flags;
flags &= ~(1 << i);
if (!service)
continue;
{
VCHIQ_SERVICE_T *service = NULL;
int msgid, size;
- int type;
unsigned int localport, remoteport;
msgid = header->msgid;
size = header->size;
- type = VCHIQ_MSG_TYPE(msgid);
localport = VCHIQ_MSG_DSTPORT(msgid);
remoteport = VCHIQ_MSG_SRCPORT(msgid);
if (size >= sizeof(struct vchiq_open_payload)) {
/* No available service, or an invalid request - send a CLOSE */
if (queue_message(state, NULL,
VCHIQ_MAKE_MSG(VCHIQ_MSG_CLOSE, 0, VCHIQ_MSG_SRCPORT(msgid)),
- NULL, 0, 0, 0) == VCHIQ_RETRY)
+ NULL, NULL, 0, 0) == VCHIQ_RETRY)
goto bail_not_ready;
return 1;
remoteport, localport, size);
if (size > 0)
vchiq_log_dump_mem("Rcvd", 0, header->data,
- min(64, size));
+ min(16, size));
}
if (((unsigned long)header & VCHIQ_SLOT_MASK) +
/* Send a PAUSE in response */
if (queue_message(state, NULL,
VCHIQ_MAKE_MSG(VCHIQ_MSG_PAUSE, 0, 0),
- NULL, 0, 0, QMFLAGS_NO_MUTEX_UNLOCK)
+ NULL, NULL, 0, QMFLAGS_NO_MUTEX_UNLOCK)
== VCHIQ_RETRY)
goto bail_not_ready;
if (state->is_master)
pause_bulks(state);
if (queue_message(state, NULL,
VCHIQ_MAKE_MSG(VCHIQ_MSG_PAUSE, 0, 0),
- NULL, 0, 0,
+ NULL, NULL, 0,
QMFLAGS_NO_MUTEX_UNLOCK)
!= VCHIQ_RETRY) {
vchiq_set_conn_state(state,
case VCHIQ_CONNSTATE_RESUMING:
if (queue_message(state, NULL,
VCHIQ_MAKE_MSG(VCHIQ_MSG_RESUME, 0, 0),
- NULL, 0, 0, QMFLAGS_NO_MUTEX_LOCK)
+ NULL, NULL, 0, QMFLAGS_NO_MUTEX_LOCK)
!= VCHIQ_RETRY) {
if (state->is_master)
resume_bulks(state);
remoteport, localport, size);
if (size > 0)
vchiq_log_dump_mem("Rcvd", 0, header->data,
- min(64, size));
+ min(16, size));
}
switch (type) {
VCHIQ_SHARED_STATE_T *local;
VCHIQ_SHARED_STATE_T *remote;
VCHIQ_STATUS_T status;
- char threadname[10];
+ char threadname[16];
static int id;
int i;
/*
bring up slot handler thread
*/
- snprintf(threadname, sizeof(threadname), "VCHIQ-%d", state->id);
+ snprintf(threadname, sizeof(threadname), "vchiq-slot/%d", state->id);
state->slot_handler_thread = kthread_create(&slot_handler_func,
(void *)state,
threadname);
set_user_nice(state->slot_handler_thread, -19);
wake_up_process(state->slot_handler_thread);
- snprintf(threadname, sizeof(threadname), "VCHIQr-%d", state->id);
+ snprintf(threadname, sizeof(threadname), "vchiq-recy/%d", state->id);
state->recycle_thread = kthread_create(&recycle_func,
(void *)state,
threadname);
set_user_nice(state->recycle_thread, -19);
wake_up_process(state->recycle_thread);
- snprintf(threadname, sizeof(threadname), "VCHIQs-%d", state->id);
+ snprintf(threadname, sizeof(threadname), "vchiq-sync/%d", state->id);
state->sync_thread = kthread_create(&sync_func,
(void *)state,
threadname);
(VCHIQ_MSG_CLOSE,
service->localport,
VCHIQ_MSG_DSTPORT(service->remoteport)),
- NULL, 0, 0, 0);
+ NULL, NULL, 0, 0);
}
break;
(VCHIQ_MSG_CLOSE,
service->localport,
VCHIQ_MSG_DSTPORT(service->remoteport)),
- NULL, 0, 0, QMFLAGS_NO_MUTEX_UNLOCK);
+ NULL, NULL, 0, QMFLAGS_NO_MUTEX_UNLOCK);
if (status == VCHIQ_SUCCESS) {
if (!close_recvd) {
if (state->conn_state == VCHIQ_CONNSTATE_DISCONNECTED) {
if (queue_message(state, NULL,
- VCHIQ_MAKE_MSG(VCHIQ_MSG_CONNECT, 0, 0), NULL, 0,
+ VCHIQ_MAKE_MSG(VCHIQ_MSG_CONNECT, 0, 0), NULL, NULL,
0, QMFLAGS_IS_BLOCKING) == VCHIQ_RETRY)
return VCHIQ_RETRY;
VCHIQ_STATUS_T
vchiq_get_peer_version(VCHIQ_SERVICE_HANDLE_T handle, short *peer_version)
{
- VCHIQ_STATUS_T status = VCHIQ_ERROR;
- VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
+ VCHIQ_STATUS_T status = VCHIQ_ERROR;
+ VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
- if (!service ||
- (vchiq_check_service(service) != VCHIQ_SUCCESS) ||
- !peer_version)
- goto exit;
- *peer_version = service->peer_version;
- status = VCHIQ_SUCCESS;
+ if (!service ||
+ (vchiq_check_service(service) != VCHIQ_SUCCESS) ||
+ !peer_version)
+ goto exit;
+ *peer_version = service->peer_version;
+ status = VCHIQ_SUCCESS;
exit:
- if (service)
- unlock_service(service);
- return status;
+ if (service)
+ unlock_service(service);
+ return status;
}
VCHIQ_STATUS_T
return status;
}
-void
+static void
vchiq_dump_shared_state(void *dump_context, VCHIQ_STATE_T *state,
VCHIQ_SHARED_STATE_T *shared, const char *label)
{
service->stats.bulk_stalls,
service->stats.bulk_aborted_count,
service->stats.error_count);
- }
+ }
}
vchiq_dump(dump_context, buf, len + 1);
if (state->conn_state != VCHIQ_CONNSTATE_DISCONNECTED)
status = queue_message(state, NULL,
VCHIQ_MAKE_MSG(VCHIQ_MSG_REMOTE_USE, 0, 0),
- NULL, 0, 0, 0);
+ NULL, NULL, 0, 0);
return status;
}
if (state->conn_state != VCHIQ_CONNSTATE_DISCONNECTED)
status = queue_message(state, NULL,
VCHIQ_MAKE_MSG(VCHIQ_MSG_REMOTE_RELEASE, 0, 0),
- NULL, 0, 0, 0);
+ NULL, NULL, 0, 0);
return status;
}
if (state->conn_state != VCHIQ_CONNSTATE_DISCONNECTED)
status = queue_message(state, NULL,
VCHIQ_MAKE_MSG(VCHIQ_MSG_REMOTE_USE_ACTIVE, 0, 0),
- NULL, 0, 0, 0);
+ NULL, NULL, 0, 0);
return status;
}
-void vchiq_log_dump_mem(const char *label, uint32_t addr, const void *void_mem,
+void vchiq_log_dump_mem(const char *label, u32 addr, const void *void_mem,
size_t num_bytes)
{
- const uint8_t *mem = (const uint8_t *)void_mem;
+ const u8 *mem = (const u8 *)void_mem;
size_t offset;
char line_buf[100];
char *s;
for (offset = 0; offset < 16; offset++) {
if (offset < num_bytes) {
- uint8_t ch = mem[offset];
+ u8 ch = mem[offset];
if ((ch < ' ') || (ch > '~'))
ch = '.';
#include "vchiq_core.h"
-typedef struct vchiq_debugfs_node_struct
-{
+typedef struct vchiq_debugfs_node_struct {
struct dentry *dentry;
} VCHIQ_DEBUGFS_NODE_T;
VCHIQ_STATUS_T status = VCHIQ_ERROR;
VCHIQ_STATE_T *state;
VCHIQ_INSTANCE_T instance = NULL;
- int i;
+ int i;
vchiq_log_trace(vchiq_core_log_level, "%s called", __func__);
- /* VideoCore may not be ready due to boot up timing.
- It may never be ready if kernel and firmware are mismatched, so don't block forever. */
- for (i=0; i<VCHIQ_INIT_RETRIES; i++) {
+ /* VideoCore may not be ready due to boot up timing.
+ It may never be ready if kernel and firmware are mismatched, so don't block forever. */
+ for (i = 0; i < VCHIQ_INIT_RETRIES; i++) {
state = vchiq_get_state();
if (state)
break;
udelay(500);
}
- if (i==VCHIQ_INIT_RETRIES) {
+ if (i == VCHIQ_INIT_RETRIES) {
vchiq_log_error(vchiq_core_log_level,
"%s: videocore not initialized\n", __func__);
goto failed;
- } else if (i>0) {
+ } else if (i > 0) {
vchiq_log_warning(vchiq_core_log_level,
"%s: videocore initialized after %d retries\n", __func__, i);
}
*
***************************************************************************/
-int vchiq_is_connected(VCHIQ_INSTANCE_T instance)
+static int vchiq_is_connected(VCHIQ_INSTANCE_T instance)
{
return instance->connected;
}
#include "vchiq_util.h"
-#include <stddef.h>
-
#define vchiq_status_to_vchi(status) ((int32_t)status)
typedef struct {
* Returns: int32_t - success == 0
*
***********************************************************/
+static
int32_t vchi_msg_queue(VCHI_SERVICE_HANDLE_T handle,
ssize_t (*copy_callback)(void *context, void *dest,
size_t offset, size_t maxsize),
return vchiq_status_to_vchi(status);
}
-EXPORT_SYMBOL(vchi_msg_queue);
+
+static ssize_t
+vchi_queue_kernel_message_callback(void *context,
+ void *dest,
+ size_t offset,
+ size_t maxsize)
+{
+ memcpy(dest, context + offset, maxsize);
+ return maxsize;
+}
+
+int
+vchi_queue_kernel_message(VCHI_SERVICE_HANDLE_T handle,
+ void *data,
+ unsigned int size)
+{
+ return vchi_msg_queue(handle,
+ vchi_queue_kernel_message_callback,
+ data,
+ size);
+}
+EXPORT_SYMBOL(vchi_queue_kernel_message);
+
+struct vchi_queue_user_message_context {
+ void __user *data;
+};
+
+static ssize_t
+vchi_queue_user_message_callback(void *context,
+ void *dest,
+ size_t offset,
+ size_t maxsize)
+{
+ struct vchi_queue_user_message_context *copycontext = context;
+
+ if (copy_from_user(dest, copycontext->data + offset, maxsize))
+ return -EFAULT;
+
+ return maxsize;
+}
+
+int
+vchi_queue_user_message(VCHI_SERVICE_HANDLE_T handle,
+ void __user *data,
+ unsigned int size)
+{
+ struct vchi_queue_user_message_context copycontext = {
+ .data = data
+ };
+
+ return vchi_msg_queue(handle,
+ vchi_queue_user_message_callback,
+ ©context,
+ size);
+}
+EXPORT_SYMBOL(vchi_queue_user_message);
/***********************************************************
* Name: vchi_bulk_queue_receive
SHIM_SERVICE_T *service =
(SHIM_SERVICE_T *)VCHIQ_GET_SERVICE_USERDATA(handle);
- if (!service->callback)
+ if (!service->callback)
goto release;
switch (reason) {
}
release:
- vchiq_release_message(service->handle, header);
+ vchiq_release_message(service->handle, header);
done:
return VCHIQ_SUCCESS;
}
}
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 VCHI_SERVICE_HANDLE_T handle, short *peer_version)
{
- int32_t ret = -1;
- SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
- if(service)
- {
- VCHIQ_STATUS_T status = vchiq_get_peer_version(service->handle, peer_version);
- ret = vchiq_status_to_vchi( status );
- }
- return ret;
+ int32_t ret = -1;
+ SHIM_SERVICE_T *service = (SHIM_SERVICE_T *)handle;
+ if (service)
+ {
+ VCHIQ_STATUS_T status;
+
+ status = vchiq_get_peer_version(service->handle, peer_version);
+ ret = vchiq_status_to_vchi(status);
+ }
+ return ret;
}
EXPORT_SYMBOL(vchi_get_peer_version);
return;
while (queue->write == queue->read + queue->size) {
- if (down_interruptible(&queue->pop) != 0) {
+ if (down_interruptible(&queue->pop) != 0)
flush_signals(current);
- }
}
/*
VCHIQ_HEADER_T *vchiu_queue_peek(VCHIU_QUEUE_T *queue)
{
while (queue->write == queue->read) {
- if (down_interruptible(&queue->push) != 0) {
+ if (down_interruptible(&queue->push) != 0)
flush_signals(current);
- }
}
up(&queue->push); // We haven't removed anything from the queue.
VCHIQ_HEADER_T *header;
while (queue->write == queue->read) {
- if (down_interruptible(&queue->push) != 0) {
+ if (down_interruptible(&queue->push) != 0)
flush_signals(current);
- }
}
/*
static int bus[VME_USER_BUS_MAX];
static unsigned int bus_num;
-/* Currently Documentation/admin-guide/devices.rst defines the following for VME:
+/* Currently Documentation/admin-guide/devices.rst defines the
+ * following for VME:
*
* 221 char VME bus
* 0 = /dev/bus/vme/m0 First master image
void BBvSetVGAGainOffset(struct vnt_private *, unsigned char byData);
/* VT3253 Baseband */
-bool BBbVT3253Init(struct vnt_private *);
-void BBvSoftwareReset(struct vnt_private *);
-void BBvPowerSaveModeON(struct vnt_private *);
-void BBvPowerSaveModeOFF(struct vnt_private *);
-void BBvSetTxAntennaMode(struct vnt_private *, unsigned char byAntennaMode);
-void BBvSetRxAntennaMode(struct vnt_private *, unsigned char byAntennaMode);
-void BBvSetDeepSleep(struct vnt_private *, unsigned char byLocalID);
-void BBvExitDeepSleep(struct vnt_private *, unsigned char byLocalID);
+bool BBbVT3253Init(struct vnt_private *priv);
+void BBvSoftwareReset(struct vnt_private *priv);
+void BBvPowerSaveModeON(struct vnt_private *priv);
+void BBvPowerSaveModeOFF(struct vnt_private *priv);
+void BBvSetTxAntennaMode(struct vnt_private *priv, unsigned char byAntennaMode);
+void BBvSetRxAntennaMode(struct vnt_private *priv, unsigned char byAntennaMode);
+void BBvSetDeepSleep(struct vnt_private *priv, unsigned char byLocalID);
+void BBvExitDeepSleep(struct vnt_private *priv, unsigned char byLocalID);
#endif /* __BASEBAND_H__ */
struct vnt_private;
-void vnt_set_channel(struct vnt_private *, u32);
-void vnt_set_rspinf(struct vnt_private *, u8);
-void vnt_update_ifs(struct vnt_private *);
-void vnt_update_top_rates(struct vnt_private *);
-int vnt_ofdm_min_rate(struct vnt_private *);
-void vnt_adjust_tsf(struct vnt_private *, u8, u64, u64);
-bool vnt_get_current_tsf(struct vnt_private *, u64 *);
-bool vnt_clear_current_tsf(struct vnt_private *);
-void vnt_reset_next_tbtt(struct vnt_private *, u16);
-void vnt_update_next_tbtt(struct vnt_private *, u64, u16);
-u64 vnt_get_next_tbtt(u64, u16);
-u64 vnt_get_tsf_offset(u8 byRxRate, u64 qwTSF1, u64 qwTSF2);
-int vnt_radio_power_off(struct vnt_private *);
-int vnt_radio_power_on(struct vnt_private *);
-u8 vnt_get_pkt_type(struct vnt_private *);
-void vnt_set_bss_mode(struct vnt_private *);
+void vnt_set_channel(struct vnt_private *priv, u32 connection_channel);
+void vnt_set_rspinf(struct vnt_private *priv, u8 bb_type);
+void vnt_update_ifs(struct vnt_private *priv);
+void vnt_update_top_rates(struct vnt_private *priv);
+int vnt_ofdm_min_rate(struct vnt_private *priv);
+void vnt_adjust_tsf(struct vnt_private *priv, u8 rx_rate,
+ u64 time_stamp, u64 local_tsf);
+bool vnt_get_current_tsf(struct vnt_private *priv, u64 *current_tsf);
+bool vnt_clear_current_tsf(struct vnt_private *priv);
+void vnt_reset_next_tbtt(struct vnt_private *priv, u16 beacon_interval);
+void vnt_update_next_tbtt(struct vnt_private *priv, u64 tsf,
+ u16 beacon_interval);
+u64 vnt_get_next_tbtt(u64 tsf, u16 beacon_interval);
+u64 vnt_get_tsf_offset(u8 rx_rate, u64 tsf1, u64 tsf2);
+int vnt_radio_power_off(struct vnt_private *priv);
+int vnt_radio_power_on(struct vnt_private *priv);
+u8 vnt_get_pkt_type(struct vnt_private *priv);
+void vnt_set_bss_mode(struct vnt_private *priv);
#endif /* __CARD_H__ */
#include "device.h"
-void vnt_init_bands(struct vnt_private *);
+void vnt_init_bands(struct vnt_private *priv);
#endif /* _CHANNEL_H_ */
#include "device.h"
-int vnt_rx_data(struct vnt_private *, struct vnt_rcb *,
+int vnt_rx_data(struct vnt_private *priv, struct vnt_rcb *ptr_rcb,
unsigned long bytes_received);
#endif /* __RXTX_H__ */
#include "device.h"
-int vnt_download_firmware(struct vnt_private *);
-int vnt_firmware_branch_to_sram(struct vnt_private *);
-int vnt_check_firmware_version(struct vnt_private *);
+int vnt_download_firmware(struct vnt_private *priv);
+int vnt_firmware_branch_to_sram(struct vnt_private *priv);
+int vnt_check_firmware_version(struct vnt_private *priv);
#endif /* __FIRMWARE_H__ */
if (int_data->isr0 != 0) {
if (int_data->isr0 & ISR_BNTX &&
- priv->op_mode == NL80211_IFTYPE_AP)
+ priv->op_mode == NL80211_IFTYPE_AP)
vnt_schedule_command(priv, WLAN_CMD_BECON_SEND);
if (int_data->isr0 & ISR_TBTT &&
u8 sw[2];
} __packed;
-void vnt_int_start_interrupt(struct vnt_private *);
-void vnt_int_process_data(struct vnt_private *);
+void vnt_int_start_interrupt(struct vnt_private *priv);
+void vnt_int_process_data(struct vnt_private *priv);
#endif /* __INT_H__ */
}
static int vnt_set_keymode(struct ieee80211_hw *hw, u8 *mac_addr,
- struct ieee80211_key_conf *key, u32 key_type, u32 mode,
- bool onfly_latch)
+ struct ieee80211_key_conf *key, u32 key_type,
+ u32 mode, bool onfly_latch)
{
struct vnt_private *priv = hw->priv;
u8 broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
}
int vnt_set_keys(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
- struct ieee80211_vif *vif, struct ieee80211_key_conf *key)
+ struct ieee80211_vif *vif, struct ieee80211_key_conf *key)
{
struct ieee80211_bss_conf *conf = &vif->bss_conf;
struct vnt_private *priv = hw->priv;
vnt_mac_disable_keyentry(priv, u);
vnt_set_keymode(hw, mac_addr, key, VNT_KEY_DEFAULTKEY,
- KEY_CTL_WEP, true);
+ KEY_CTL_WEP, true);
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
vnt_set_keymode(hw, mac_addr, key, VNT_KEY_PAIRWISE,
- key_dec_mode, true);
+ key_dec_mode, true);
} else {
vnt_set_keymode(hw, mac_addr, key, VNT_KEY_DEFAULTKEY,
- key_dec_mode, true);
+ key_dec_mode, true);
vnt_set_keymode(hw, (u8 *)conf->bssid, key,
- VNT_KEY_GROUP_ADDRESS, key_dec_mode, true);
+ VNT_KEY_GROUP_ADDRESS, key_dec_mode, true);
}
return 0;
#define VNT_KEY_ONFLY 0x8000
#define VNT_KEY_ONFLY_ALL 0x4000
-int vnt_key_init_table(struct vnt_private *);
+int vnt_key_init_table(struct vnt_private *priv);
int vnt_set_keys(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
struct ieee80211_vif *vif, struct ieee80211_key_conf *key);
__le64 le_mc = cpu_to_le64(mc_filter);
vnt_control_out(priv, MESSAGE_TYPE_WRITE, MAC_REG_MAR0,
- MESSAGE_REQUEST_MACREG, sizeof(le_mc), (u8 *)&le_mc);
+ MESSAGE_REQUEST_MACREG, sizeof(le_mc), (u8 *)&le_mc);
}
/*
data[1] = EnCFG_BBType_MASK;
vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK, MAC_REG_ENCFG0,
- MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data);
+ MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data);
}
/*
void vnt_mac_disable_keyentry(struct vnt_private *priv, u8 entry_idx)
{
vnt_control_out(priv, MESSAGE_TYPE_CLRKEYENTRY, 0, 0,
- sizeof(entry_idx), &entry_idx);
+ sizeof(entry_idx), &entry_idx);
}
/*
*
*/
void vnt_mac_set_keyentry(struct vnt_private *priv, u16 key_ctl, u32 entry_idx,
- u32 key_idx, u8 *addr, u8 *key)
+ u32 key_idx, u8 *addr, u8 *key)
{
struct vnt_mac_set_key set_key;
u16 offset;
memcpy(set_key.key, key, WLAN_KEY_LEN_CCMP);
dev_dbg(&priv->usb->dev, "offset %d key ctl %d set key %24ph\n",
- offset, key_ctl, (u8 *)&set_key);
+ offset, key_ctl, (u8 *)&set_key);
vnt_control_out(priv, MESSAGE_TYPE_SETKEY, offset,
- (u16)key_idx, sizeof(struct vnt_mac_set_key), (u8 *)&set_key);
+ (u16)key_idx, sizeof(struct vnt_mac_set_key),
+ (u8 *)&set_key);
}
void vnt_mac_reg_bits_off(struct vnt_private *priv, u8 reg_ofs, u8 bits)
data[1] = bits;
vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK,
- reg_ofs, MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data);
+ reg_ofs, MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data),
+ data);
}
void vnt_mac_reg_bits_on(struct vnt_private *priv, u8 reg_ofs, u8 bits)
data[0] = bits;
data[1] = bits;
- vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK,
- reg_ofs, MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data);
+ vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK, reg_ofs,
+ MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data);
}
void vnt_mac_write_word(struct vnt_private *priv, u8 reg_ofs, u16 word)
data[0] = (u8)(word & 0xff);
data[1] = (u8)(word >> 8);
- vnt_control_out(priv, MESSAGE_TYPE_WRITE,
- reg_ofs, MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data);
+ vnt_control_out(priv, MESSAGE_TYPE_WRITE, reg_ofs,
+ MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data);
}
void vnt_mac_set_bssid_addr(struct vnt_private *priv, u8 *addr)
{
vnt_control_out(priv, MESSAGE_TYPE_WRITE, MAC_REG_BSSID0,
- MESSAGE_REQUEST_MACREG, ETH_ALEN, addr);
+ MESSAGE_REQUEST_MACREG, ETH_ALEN, addr);
}
void vnt_mac_enable_protect_mode(struct vnt_private *priv)
data[0] = EnCFG_ProtectMd;
data[1] = EnCFG_ProtectMd;
- vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK,
- MAC_REG_ENCFG0, MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data);
+ vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK, MAC_REG_ENCFG0,
+ MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data);
}
void vnt_mac_disable_protect_mode(struct vnt_private *priv)
data[0] = 0;
data[1] = EnCFG_ProtectMd;
- vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK,
- MAC_REG_ENCFG0, MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data);
+ vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK, MAC_REG_ENCFG0,
+ MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data);
}
void vnt_mac_enable_barker_preamble_mode(struct vnt_private *priv)
data[0] = EnCFG_BarkerPream;
data[1] = EnCFG_BarkerPream;
- vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK,
- MAC_REG_ENCFG2, MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data);
+ vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK, MAC_REG_ENCFG2,
+ MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data);
}
void vnt_mac_disable_barker_preamble_mode(struct vnt_private *priv)
data[0] = 0;
data[1] = EnCFG_BarkerPream;
- vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK,
- MAC_REG_ENCFG2, MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data);
+ vnt_control_out(priv, MESSAGE_TYPE_WRITE_MASK, MAC_REG_ENCFG2,
+ MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data);
}
void vnt_mac_set_beacon_interval(struct vnt_private *priv, u16 interval)
data[0] = (u8)(interval & 0xff);
data[1] = (u8)(interval >> 8);
- vnt_control_out(priv, MESSAGE_TYPE_WRITE,
- MAC_REG_BI, MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data);
+ vnt_control_out(priv, MESSAGE_TYPE_WRITE, MAC_REG_BI,
+ MESSAGE_REQUEST_MACREG, ARRAY_SIZE(data), data);
}
void vnt_mac_set_led(struct vnt_private *priv, u8 state, u8 led)
u8 key[WLAN_KEY_LEN_CCMP];
} __packed;
-void vnt_mac_set_filter(struct vnt_private *, u64);
-void vnt_mac_shutdown(struct vnt_private *);
-void vnt_mac_set_bb_type(struct vnt_private *, u8);
-void vnt_mac_disable_keyentry(struct vnt_private *, u8);
-void vnt_mac_set_keyentry(struct vnt_private *, u16, u32, u32, u8 *, u8 *);
-void vnt_mac_reg_bits_off(struct vnt_private *, u8, u8);
-void vnt_mac_reg_bits_on(struct vnt_private *, u8, u8);
-void vnt_mac_write_word(struct vnt_private *, u8, u16);
-void vnt_mac_set_bssid_addr(struct vnt_private *, u8 *);
-void vnt_mac_enable_protect_mode(struct vnt_private *);
-void vnt_mac_disable_protect_mode(struct vnt_private *);
-void vnt_mac_enable_barker_preamble_mode(struct vnt_private *);
-void vnt_mac_disable_barker_preamble_mode(struct vnt_private *);
-void vnt_mac_set_beacon_interval(struct vnt_private *, u16);
-void vnt_mac_set_led(struct vnt_private *priv, u8, u8);
+void vnt_mac_set_filter(struct vnt_private *priv, u64 mc_filter);
+void vnt_mac_shutdown(struct vnt_private *priv);
+void vnt_mac_set_bb_type(struct vnt_private *priv, u8 type);
+void vnt_mac_disable_keyentry(struct vnt_private *priv, u8 entry_idx);
+void vnt_mac_set_keyentry(struct vnt_private *priv, u16 key_ctl, u32 entry_idx,
+ u32 key_idx, u8 *addr, u8 *key);
+void vnt_mac_reg_bits_off(struct vnt_private *priv, u8 reg_ofs, u8 bits);
+void vnt_mac_reg_bits_on(struct vnt_private *priv, u8 reg_ofs, u8 bits);
+void vnt_mac_write_word(struct vnt_private *priv, u8 reg_ofs, u16 word);
+void vnt_mac_set_bssid_addr(struct vnt_private *priv, u8 *addr);
+void vnt_mac_enable_protect_mode(struct vnt_private *priv);
+void vnt_mac_disable_protect_mode(struct vnt_private *priv);
+void vnt_mac_enable_barker_preamble_mode(struct vnt_private *priv);
+void vnt_mac_disable_barker_preamble_mode(struct vnt_private *priv);
+void vnt_mac_set_beacon_interval(struct vnt_private *priv, u16 interval);
+void vnt_mac_set_led(struct vnt_private *privpriv, u8 state, u8 led);
#endif /* __MAC_H__ */
u8 calib_tx_iq = 0, calib_tx_dc = 0, calib_rx_iq = 0;
dev_dbg(&priv->usb->dev, "---->INIbInitAdapter. [%d][%d]\n",
- DEVICE_INIT_COLD, priv->packet_type);
+ DEVICE_INIT_COLD, priv->packet_type);
if (!vnt_check_firmware_version(priv)) {
if (vnt_download_firmware(priv) == true) {
init_cmd->long_retry_limit = priv->long_retry_limit;
/* issue card_init command to device */
- status = vnt_control_out(priv,
- MESSAGE_TYPE_CARDINIT, 0, 0,
- sizeof(struct vnt_cmd_card_init), (u8 *)init_cmd);
+ status = vnt_control_out(priv, MESSAGE_TYPE_CARDINIT, 0, 0,
+ sizeof(struct vnt_cmd_card_init),
+ (u8 *)init_cmd);
if (status != STATUS_SUCCESS) {
dev_dbg(&priv->usb->dev, "Issue Card init fail\n");
return false;
}
status = vnt_control_in(priv, MESSAGE_TYPE_INIT_RSP, 0, 0,
- sizeof(struct vnt_rsp_card_init), (u8 *)init_rsp);
+ sizeof(struct vnt_rsp_card_init),
+ (u8 *)init_rsp);
if (status != STATUS_SUCCESS) {
dev_dbg(&priv->usb->dev,
"Cardinit request in status fail!\n");
}
/* local ID for AES functions */
- status = vnt_control_in(priv, MESSAGE_TYPE_READ,
- MAC_REG_LOCALID, MESSAGE_REQUEST_MACREG, 1,
- &priv->local_id);
+ status = vnt_control_in(priv, MESSAGE_TYPE_READ, MAC_REG_LOCALID,
+ MESSAGE_REQUEST_MACREG, 1, &priv->local_id);
if (status != STATUS_SUCCESS)
return false;
if (priv->rf_type == RF_VT3226D0) {
if ((priv->eeprom[EEP_OFS_MAJOR_VER] == 0x1) &&
(priv->eeprom[EEP_OFS_MINOR_VER] >= 0x4)) {
-
calib_tx_iq = priv->eeprom[EEP_OFS_CALIB_TX_IQ];
calib_tx_dc = priv->eeprom[EEP_OFS_CALIB_TX_DC];
calib_rx_iq = priv->eeprom[EEP_OFS_CALIB_RX_IQ];
if ((priv->radio_ctl & EEP_RADIOCTL_ENABLE) != 0) {
status = vnt_control_in(priv, MESSAGE_TYPE_READ,
- MAC_REG_GPIOCTL1, MESSAGE_REQUEST_MACREG, 1, &tmp);
+ MAC_REG_GPIOCTL1,
+ MESSAGE_REQUEST_MACREG, 1, &tmp);
if (status != STATUS_SUCCESS)
return false;
if ((tmp & GPIO3_DATA) == 0)
vnt_mac_reg_bits_on(priv, MAC_REG_GPIOCTL1,
- GPIO3_INTMD);
+ GPIO3_INTMD);
else
vnt_mac_reg_bits_off(priv, MAC_REG_GPIOCTL1,
- GPIO3_INTMD);
+ GPIO3_INTMD);
}
vnt_mac_set_led(priv, LEDSTS_TMLEN, 0x38);
for (ii = 0; ii < priv->num_tx_context; ii++) {
tx_context = kmalloc(sizeof(struct vnt_usb_send_context),
- GFP_KERNEL);
+ GFP_KERNEL);
if (!tx_context)
goto free_tx;
priv->rcb[ii] = kzalloc(sizeof(struct vnt_rcb), GFP_KERNEL);
if (!priv->rcb[ii]) {
dev_err(&priv->usb->dev,
- "failed to allocate rcb no %d\n", ii);
+ "failed to allocate rcb no %d\n", ii);
goto free_rx_tx;
}
}
static void vnt_tx_80211(struct ieee80211_hw *hw,
- struct ieee80211_tx_control *control, struct sk_buff *skb)
+ struct ieee80211_tx_control *control,
+ struct sk_buff *skb)
{
struct vnt_private *priv = hw->priv;
}
static void vnt_remove_interface(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif)
+ struct ieee80211_vif *vif)
{
struct vnt_private *priv = hw->priv;
}
if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) ||
- (conf->flags & IEEE80211_CONF_OFFCHANNEL)) {
+ (conf->flags & IEEE80211_CONF_OFFCHANNEL)) {
vnt_set_channel(priv, conf->chandef.chan->hw_value);
if (conf->chandef.chan->band == NL80211_BAND_5GHZ)
}
static void vnt_bss_info_changed(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif, struct ieee80211_bss_conf *conf,
- u32 changed)
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *conf, u32 changed)
{
struct vnt_private *priv = hw->priv;
if (changed & BSS_CHANGED_BSSID && conf->bssid)
vnt_mac_set_bssid_addr(priv, (u8 *)conf->bssid);
-
if (changed & BSS_CHANGED_BASIC_RATES) {
priv->basic_rates = conf->basic_rates;
if (changed & BSS_CHANGED_TXPOWER)
vnt_rf_setpower(priv, priv->current_rate,
- conf->chandef.chan->hw_value);
+ conf->chandef.chan->hw_value);
if (changed & BSS_CHANGED_BEACON_ENABLED) {
dev_dbg(&priv->usb->dev,
- "Beacon enable %d\n", conf->enable_beacon);
+ "Beacon enable %d\n", conf->enable_beacon);
if (conf->enable_beacon) {
vnt_beacon_enable(priv, vif, conf);
}
static u64 vnt_prepare_multicast(struct ieee80211_hw *hw,
- struct netdev_hw_addr_list *mc_list)
+ struct netdev_hw_addr_list *mc_list)
{
struct vnt_private *priv = hw->priv;
struct netdev_hw_addr *ha;
}
static void vnt_configure(struct ieee80211_hw *hw,
- unsigned int changed_flags, unsigned int *total_flags, u64 multicast)
+ unsigned int changed_flags,
+ unsigned int *total_flags, u64 multicast)
{
struct vnt_private *priv = hw->priv;
u8 rx_mode = 0;
*total_flags &= FIF_ALLMULTI | FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC;
rc = vnt_control_in(priv, MESSAGE_TYPE_READ, MAC_REG_RCR,
- MESSAGE_REQUEST_MACREG, sizeof(u8), &rx_mode);
+ MESSAGE_REQUEST_MACREG, sizeof(u8), &rx_mode);
if (!rc)
rx_mode = RCR_MULTICAST | RCR_BROADCAST;
} else {
rx_mode &= ~(RCR_MULTICAST | RCR_BROADCAST);
}
-
}
if (changed_flags & (FIF_OTHER_BSS | FIF_BCN_PRBRESP_PROMISC)) {
}
static int vnt_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
- struct ieee80211_vif *vif, struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key)
+ struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key)
{
struct vnt_private *priv = hw->priv;
}
static int vnt_get_stats(struct ieee80211_hw *hw,
- struct ieee80211_low_level_stats *stats)
+ struct ieee80211_low_level_stats *stats)
{
struct vnt_private *priv = hw->priv;
int vnt_init(struct vnt_private *priv)
{
-
if (!(vnt_init_registers(priv)))
return -EAGAIN;
udev = usb_get_dev(interface_to_usbdev(intf));
dev_notice(&udev->dev, "%s Ver. %s\n",
- DEVICE_FULL_DRV_NAM, DEVICE_VERSION);
+ DEVICE_FULL_DRV_NAM, DEVICE_VERSION);
dev_notice(&udev->dev,
- "Copyright (c) 2004 VIA Networking Technologies, Inc.\n");
+ "Copyright (c) 2004 VIA Networking Technologies, Inc.\n");
hw = ieee80211_alloc_hw(sizeof(struct vnt_private), &vnt_mac_ops);
if (!hw) {
#define C_PWBT 1000 /* micro sec. power up before TBTT */
-void vnt_disable_power_saving(struct vnt_private *);
-void vnt_enable_power_saving(struct vnt_private *, u16);
-int vnt_next_tbtt_wakeup(struct vnt_private *);
+void vnt_disable_power_saving(struct vnt_private *priv);
+void vnt_enable_power_saving(struct vnt_private *priv, u16 listen_interval);
+int vnt_next_tbtt_wakeup(struct vnt_private *priv);
#endif /* __POWER_H__ */
#define VNT_RF_MAX_POWER 0x3f
#define VNT_RF_REG_LEN 0x17 /* 24 bit length */
-int vnt_rf_write_embedded(struct vnt_private *, u32);
-int vnt_rf_setpower(struct vnt_private *, u32, u32);
-int vnt_rf_set_txpower(struct vnt_private *, u8, u32);
-void vnt_rf_rssi_to_dbm(struct vnt_private *, u8, long *);
-void vnt_rf_table_download(struct vnt_private *);
+int vnt_rf_write_embedded(struct vnt_private *priv, u32 data);
+int vnt_rf_setpower(struct vnt_private *priv, u32 rate, u32 channel);
+int vnt_rf_set_txpower(struct vnt_private *priv, u8 power, u32 rate);
+void vnt_rf_rssi_to_dbm(struct vnt_private *priv, u8 rssi, long *dbm);
+void vnt_rf_table_download(struct vnt_private *priv);
#endif /* __RF_H__ */
struct ieee80211_mgmt mgmt_hdr;
} __packed;
-int vnt_tx_packet(struct vnt_private *, struct sk_buff *);
-int vnt_beacon_make(struct vnt_private *, struct ieee80211_vif *);
-int vnt_beacon_enable(struct vnt_private *, struct ieee80211_vif *,
- struct ieee80211_bss_conf *);
+int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb);
+int vnt_beacon_make(struct vnt_private *priv, struct ieee80211_vif *vif);
+int vnt_beacon_enable(struct vnt_private *priv, struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *conf);
#endif /* __RXTX_H__ */
#include "device.h"
-int vnt_control_out(struct vnt_private *, u8, u16, u16, u16, u8 *);
-int vnt_control_in(struct vnt_private *, u8, u16, u16, u16, u8 *);
+int vnt_control_out(struct vnt_private *priv, u8 request, u16 value,
+ u16 index, u16 length, u8 *buffer);
+int vnt_control_in(struct vnt_private *priv, u8 request, u16 value,
+ u16 index, u16 length, u8 *buffer);
-void vnt_control_out_u8(struct vnt_private *, u8, u8, u8);
-void vnt_control_in_u8(struct vnt_private *, u8, u8, u8 *);
+void vnt_control_out_u8(struct vnt_private *priv, u8 reg, u8 ref_off, u8 data);
+void vnt_control_in_u8(struct vnt_private *priv, u8 reg, u8 reg_off, u8 *data);
-int vnt_start_interrupt_urb(struct vnt_private *);
-int vnt_submit_rx_urb(struct vnt_private *, struct vnt_rcb *);
-int vnt_tx_context(struct vnt_private *, struct vnt_usb_send_context *);
+int vnt_start_interrupt_urb(struct vnt_private *priv);
+int vnt_submit_rx_urb(struct vnt_private *priv, struct vnt_rcb *rcb);
+int vnt_tx_context(struct vnt_private *priv,
+ struct vnt_usb_send_context *context);
#endif /* __USBPIPE_H__ */
struct vnt_private;
-void vnt_reset_command_timer(struct vnt_private *);
+void vnt_reset_command_timer(struct vnt_private *priv);
-int vnt_schedule_command(struct vnt_private *, enum vnt_cmd);
+int vnt_schedule_command(struct vnt_private *priv, enum vnt_cmd);
void vnt_run_command(struct work_struct *work);
pNewJoinBssParam->rsn_found = true;
index += pu8IEs[index + 1] + 2;
continue;
- } else
+ } else {
index += pu8IEs[index + 1] + 2;
+ }
}
}
return ret;
if (!wait_for_completion_timeout(&wilc->sync_event,
- msecs_to_jiffies(5000)))
+ msecs_to_jiffies(5000)))
return -ETIME;
return 0;
tx_data->skb = skb;
eth_h = (struct ethhdr *)(skb->data);
- if (eth_h->h_proto == 0x8e88)
+ if (eth_h->h_proto == cpu_to_be16(0x8e88))
netdev_dbg(ndev, "EAPOL transmitted\n");
ih = (struct iphdr *)(skb->data + sizeof(struct ethhdr));
#include "wilc_wlan_if.h"
-
static struct dentry *wilc_dir;
/*
* --------------------------------------------------------------------------------
*/
-
static ssize_t wilc_debug_level_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos)
{
char buf[128];
}
static ssize_t wilc_debug_level_write(struct file *filp, const char __user *buf,
- size_t count, loff_t *ppos)
+ size_t count, loff_t *ppos)
{
int flag = 0;
int ret;
return ret;
}
-
static int wilc_sdio_cmd53(struct wilc *wilc, struct sdio_cmd53 *cmd)
{
struct sdio_func *func = container_of(wilc->dev, struct sdio_func, dev);
dev_dbg(&func->dev, "Initializing netdev\n");
ret = wilc_netdev_init(&wilc, &func->dev, HIF_SDIO, gpio,
- &wilc_hif_sdio);
+ &wilc_hif_sdio);
if (ret) {
dev_err(&func->dev, "Couldn't initialize netdev\n");
return ret;
__LINE__);
goto _fail_;
}
-
}
} else {
if (g_sdio.irq_gpio) {
__LINE__);
goto _fail_;
}
-
}
if (!ret)
break;
{
s32 s32Error = 0;
u32 i;
+ u32 sel_bssi_idx = UINT_MAX;
u8 u8security = NO_ENCRYPT;
enum AUTHTYPE tenuAuth_type = ANY;
memcmp(last_scanned_shadow[i].ssid,
sme->ssid,
sme->ssid_len) == 0) {
- if (!sme->bssid)
- break;
- else
+ if (!sme->bssid) {
+ if (sel_bssi_idx == UINT_MAX ||
+ last_scanned_shadow[i].rssi >
+ last_scanned_shadow[sel_bssi_idx].rssi)
+ sel_bssi_idx = i;
+ } else {
if (memcmp(last_scanned_shadow[i].bssid,
sme->bssid,
- ETH_ALEN) == 0)
+ ETH_ALEN) == 0) {
+ sel_bssi_idx = i;
break;
+ }
+ }
}
}
- if (i < last_scanned_cnt) {
- pstrNetworkInfo = &last_scanned_shadow[i];
+ if (sel_bssi_idx < last_scanned_cnt) {
+ pstrNetworkInfo = &last_scanned_shadow[sel_bssi_idx];
} else {
s32Error = -ENOENT;
wilc_connecting = 0;
msg_join.authtype.data = P80211ENUM_authalg_sharedkey;
else
netdev_warn(dev,
- "Unhandled authorisation type for connect (%d)\n",
- sme->auth_type);
+ "Unhandled authorisation type for connect (%d)\n",
+ sme->auth_type);
/* Set the encryption - we only support wep */
if (is_wep) {
void prism2_roamed(struct wlandevice *wlandev)
{
cfg80211_roamed(wlandev->netdev, NULL, wlandev->bssid,
- NULL, 0, NULL, 0, GFP_KERNEL);
+ NULL, 0, NULL, 0, GFP_KERNEL);
}
/* Structures for declaring wiphy interface */
result = hfa384x_drvr_getconfig(hw, rid, val, sizeof(u16));
if (result == 0)
- *((u16 *)val) = le16_to_cpu(*((u16 *)val));
+ le16_to_cpus(val);
return result;
}
static inline int hfa384x_drvr_setconfig16(struct hfa384x *hw, u16 rid, u16 val)
{
- u16 value = cpu_to_le16(val);
+ __le16 value = cpu_to_le16(val);
return hfa384x_drvr_setconfig(hw, rid, &value, sizeof(value));
}
struct p80211_hdr_a3 *hdr;
hdr = (struct p80211_hdr_a3 *)skb->data;
- if (p80211_rx_typedrop(wlandev, hdr->fc))
+ if (p80211_rx_typedrop(wlandev, le16_to_cpu(hdr->fc)))
return CONV_TO_ETHER_SKIPPED;
/* perform mcast filtering: allow my local address through but reject
/* Set the driver state */
/* Do we want the prism2 header? */
if ((msg->prismheader.status ==
- P80211ENUM_msgitem_status_data_ok)
- && (msg->prismheader.data == P80211ENUM_truth_true)) {
+ P80211ENUM_msgitem_status_data_ok) &&
+ (msg->prismheader.data == P80211ENUM_truth_true)) {
hw->sniffhdr = 0;
wlandev->netdev->type = ARPHRD_IEEE80211_PRISM;
- } else
- if ((msg->wlanheader.status ==
- P80211ENUM_msgitem_status_data_ok)
- && (msg->wlanheader.data == P80211ENUM_truth_true)) {
+ } else if ((msg->wlanheader.status ==
+ P80211ENUM_msgitem_status_data_ok) &&
+ (msg->wlanheader.data == P80211ENUM_truth_true)) {
hw->sniffhdr = 1;
wlandev->netdev->type = ARPHRD_IEEE80211_PRISM;
} else {
struct p80211msg_dot11req_mibset *msg, void *data);
static struct mibrec mibtab[] = {
-
/* dot11smt MIB's */
{DIDmib_dot11smt_dot11WEPDefaultKeysTable_key(1),
F_STA | F_WRITE,
struct p80211msg_dot11req_mibset *msg,
void *data)
{
-
return prism2mib_flag(mib, isget, wlandev, hw, msg, data);
}
{
switch (var->bits_per_pixel) {
case 8:
- var->red.offset = var->green.offset = var->blue.offset = 0;
- var->red.length = var->green.length = var->blue.length = 6;
+ var->red.offset = 0;
+ var->green.offset = 0;
+ var->blue.offset = 0;
+ var->red.length = 6;
+ var->green.length = 6;
+ var->blue.length = 6;
xgifb_info->video_cmap_len = 256;
break;
case 16:
xgifb_info->video_vheight = info->var.yres_virtual;
xgifb_info->video_height =
XGIbios_mode[xgifb_info->mode_idx].yres;
- xgifb_info->org_x = xgifb_info->org_y = 0;
+ xgifb_info->org_x = 0;
+ xgifb_info->org_y = 0;
xgifb_info->video_linelength = info->var.xres_virtual
* (xgifb_info->video_bpp >> 3);
switch (xgifb_info->video_bpp) {
var->yoffset = var->yres_virtual - var->yres - 1;
/* Set everything else to 0 */
- var->red.msb_right =
- var->green.msb_right =
- var->blue.msb_right =
- var->transp.offset = var->transp.length = var->transp.msb_right = 0;
+ var->red.msb_right = 0;
+ var->green.msb_right = 0;
+ var->blue.msb_right = 0;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ var->transp.msb_right = 0;
return 0;
}
{
u8 cr32, temp = 0;
- xgifb_info->TV_plug = xgifb_info->TV_type = 0;
+ xgifb_info->TV_plug = 0;
+ xgifb_info->TV_type = 0;
cr32 = xgifb_reg_get(XGICR, IND_XGI_SCRATCH_REG_CR32);
goto error_0;
}
- xgifb_info->video_vbase = hw_info->pjVideoMemoryAddress =
+ xgifb_info->video_vbase =
+ ioremap_wc(xgifb_info->video_base, xgifb_info->video_size);
+ hw_info->pjVideoMemoryAddress =
ioremap_wc(xgifb_info->video_base, xgifb_info->video_size);
xgifb_info->mmio_vbase = ioremap(xgifb_info->mmio_base,
xgifb_info->mmio_size);
xgifb_info->video_vheight =
xgifb_info->video_height =
XGIbios_mode[xgifb_info->mode_idx].yres;
- xgifb_info->org_x = xgifb_info->org_y = 0;
+ xgifb_info->org_x = 0;
+ xgifb_info->org_y = 0;
xgifb_info->video_linelength =
xgifb_info->video_width *
(xgifb_info->video_bpp >> 3);
if ((data & 0x10) == 0) {
data = xgifb_reg_get(pVBInfo->P3c4, 0x39);
- data = (data & 0x02) >> 1;
- return data;
+ return (data & 0x02) >> 1;
}
return data & 0x01;
}
case TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED:
case TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED:
case TCM_COPY_TARGET_DEVICE_NOT_REACHABLE:
+ case TCM_TOO_MANY_TARGET_DESCS:
+ case TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE:
+ case TCM_TOO_MANY_SEGMENT_DESCS:
+ case TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE:
break;
case TCM_OUT_OF_RESOURCES:
sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
.key = ILLEGAL_REQUEST,
.asc = 0x26, /* INVALID FIELD IN PARAMETER LIST */
},
+ [TCM_TOO_MANY_TARGET_DESCS] = {
+ .key = ILLEGAL_REQUEST,
+ .asc = 0x26,
+ .ascq = 0x06, /* TOO MANY TARGET DESCRIPTORS */
+ },
+ [TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE] = {
+ .key = ILLEGAL_REQUEST,
+ .asc = 0x26,
+ .ascq = 0x07, /* UNSUPPORTED TARGET DESCRIPTOR TYPE CODE */
+ },
+ [TCM_TOO_MANY_SEGMENT_DESCS] = {
+ .key = ILLEGAL_REQUEST,
+ .asc = 0x26,
+ .ascq = 0x08, /* TOO MANY SEGMENT DESCRIPTORS */
+ },
+ [TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE] = {
+ .key = ILLEGAL_REQUEST,
+ .asc = 0x26,
+ .ascq = 0x09, /* UNSUPPORTED SEGMENT DESCRIPTOR TYPE CODE */
+ },
[TCM_PARAMETER_LIST_LENGTH_ERROR] = {
.key = ILLEGAL_REQUEST,
.asc = 0x1a, /* PARAMETER LIST LENGTH ERROR */
return 0;
}
-static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op *xop,
- bool src)
+static int target_xcopy_locate_se_dev_e4(const unsigned char *dev_wwn,
+ struct se_device **found_dev)
{
struct se_device *se_dev;
- unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN], *dev_wwn;
+ unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN];
int rc;
- if (src)
- dev_wwn = &xop->dst_tid_wwn[0];
- else
- dev_wwn = &xop->src_tid_wwn[0];
-
mutex_lock(&g_device_mutex);
list_for_each_entry(se_dev, &g_device_list, g_dev_node) {
if (rc != 0)
continue;
- if (src) {
- xop->dst_dev = se_dev;
- pr_debug("XCOPY 0xe4: Setting xop->dst_dev: %p from located"
- " se_dev\n", xop->dst_dev);
- } else {
- xop->src_dev = se_dev;
- pr_debug("XCOPY 0xe4: Setting xop->src_dev: %p from located"
- " se_dev\n", xop->src_dev);
- }
+ *found_dev = se_dev;
+ pr_debug("XCOPY 0xe4: located se_dev: %p\n", se_dev);
rc = target_depend_item(&se_dev->dev_group.cg_item);
if (rc != 0) {
}
static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op *xop,
- unsigned char *p, bool src)
+ unsigned char *p, unsigned short cscd_index)
{
unsigned char *desc = p;
unsigned short ript;
return -EINVAL;
}
- if (src) {
+ if (cscd_index != xop->stdi && cscd_index != xop->dtdi) {
+ pr_debug("XCOPY 0xe4: ignoring CSCD entry %d - neither src nor "
+ "dest\n", cscd_index);
+ return 0;
+ }
+
+ if (cscd_index == xop->stdi) {
memcpy(&xop->src_tid_wwn[0], &desc[8], XCOPY_NAA_IEEE_REGEX_LEN);
/*
* Determine if the source designator matches the local device
pr_debug("XCOPY 0xe4: Set xop->src_dev %p from source"
" received xop\n", xop->src_dev);
}
- } else {
+ }
+
+ if (cscd_index == xop->dtdi) {
memcpy(&xop->dst_tid_wwn[0], &desc[8], XCOPY_NAA_IEEE_REGEX_LEN);
/*
- * Determine if the destination designator matches the local device
+ * Determine if the destination designator matches the local
+ * device. If @cscd_index corresponds to both source (stdi) and
+ * destination (dtdi), or dtdi comes after stdi, then
+ * XCOL_DEST_RECV_OP wins.
*/
if (!memcmp(&xop->local_dev_wwn[0], &xop->dst_tid_wwn[0],
XCOPY_NAA_IEEE_REGEX_LEN)) {
{
struct se_device *local_dev = se_cmd->se_dev;
unsigned char *desc = p;
- int offset = tdll % XCOPY_TARGET_DESC_LEN, rc, ret = 0;
+ int offset = tdll % XCOPY_TARGET_DESC_LEN, rc;
+ unsigned short cscd_index = 0;
unsigned short start = 0;
- bool src = true;
*sense_ret = TCM_INVALID_PARAMETER_LIST;
if (offset != 0) {
pr_err("XCOPY target descriptor list length is not"
" multiple of %d\n", XCOPY_TARGET_DESC_LEN);
+ *sense_ret = TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE;
return -EINVAL;
}
- if (tdll > 64) {
+ if (tdll > RCR_OP_MAX_TARGET_DESC_COUNT * XCOPY_TARGET_DESC_LEN) {
pr_err("XCOPY target descriptor supports a maximum"
" two src/dest descriptors, tdll: %hu too large..\n", tdll);
+ /* spc4r37 6.4.3.4 CSCD DESCRIPTOR LIST LENGTH field */
+ *sense_ret = TCM_TOO_MANY_TARGET_DESCS;
return -EINVAL;
}
/*
while (start < tdll) {
/*
- * Check target descriptor identification with 0xE4 type with
- * use VPD 0x83 WWPN matching ..
+ * Check target descriptor identification with 0xE4 type, and
+ * compare the current index with the CSCD descriptor IDs in
+ * the segment descriptor. Use VPD 0x83 WWPN matching ..
*/
switch (desc[0]) {
case 0xe4:
rc = target_xcopy_parse_tiddesc_e4(se_cmd, xop,
- &desc[0], src);
+ &desc[0], cscd_index);
if (rc != 0)
goto out;
- /*
- * Assume target descriptors are in source -> destination order..
- */
- if (src)
- src = false;
- else
- src = true;
start += XCOPY_TARGET_DESC_LEN;
desc += XCOPY_TARGET_DESC_LEN;
- ret++;
+ cscd_index++;
break;
default:
pr_err("XCOPY unsupported descriptor type code:"
" 0x%02x\n", desc[0]);
+ *sense_ret = TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE;
goto out;
}
}
- if (xop->op_origin == XCOL_SOURCE_RECV_OP)
- rc = target_xcopy_locate_se_dev_e4(se_cmd, xop, true);
- else
- rc = target_xcopy_locate_se_dev_e4(se_cmd, xop, false);
+ switch (xop->op_origin) {
+ case XCOL_SOURCE_RECV_OP:
+ rc = target_xcopy_locate_se_dev_e4(xop->dst_tid_wwn,
+ &xop->dst_dev);
+ break;
+ case XCOL_DEST_RECV_OP:
+ rc = target_xcopy_locate_se_dev_e4(xop->src_tid_wwn,
+ &xop->src_dev);
+ break;
+ default:
+ pr_err("XCOPY CSCD descriptor IDs not found in CSCD list - "
+ "stdi: %hu dtdi: %hu\n", xop->stdi, xop->dtdi);
+ rc = -EINVAL;
+ break;
+ }
/*
* If a matching IEEE NAA 0x83 descriptor for the requested device
* is not located on this node, return COPY_ABORTED with ASQ/ASQC
pr_debug("XCOPY TGT desc: Dest dev: %p NAA IEEE WWN: 0x%16phN\n",
xop->dst_dev, &xop->dst_tid_wwn[0]);
- return ret;
+ return cscd_index;
out:
return -EINVAL;
xop->stdi = get_unaligned_be16(&desc[4]);
xop->dtdi = get_unaligned_be16(&desc[6]);
+
+ if (xop->stdi > XCOPY_CSCD_DESC_ID_LIST_OFF_MAX ||
+ xop->dtdi > XCOPY_CSCD_DESC_ID_LIST_OFF_MAX) {
+ pr_err("XCOPY segment desc 0x02: unsupported CSCD ID > 0x%x; stdi: %hu dtdi: %hu\n",
+ XCOPY_CSCD_DESC_ID_LIST_OFF_MAX, xop->stdi, xop->dtdi);
+ return -EINVAL;
+ }
+
pr_debug("XCOPY seg desc 0x02: desc_len: %hu stdi: %hu dtdi: %hu, DC: %d\n",
desc_len, xop->stdi, xop->dtdi, dc);
static int target_xcopy_parse_segment_descriptors(struct se_cmd *se_cmd,
struct xcopy_op *xop, unsigned char *p,
- unsigned int sdll)
+ unsigned int sdll, sense_reason_t *sense_ret)
{
unsigned char *desc = p;
unsigned int start = 0;
int offset = sdll % XCOPY_SEGMENT_DESC_LEN, rc, ret = 0;
+ *sense_ret = TCM_INVALID_PARAMETER_LIST;
+
if (offset != 0) {
pr_err("XCOPY segment descriptor list length is not"
" multiple of %d\n", XCOPY_SEGMENT_DESC_LEN);
+ *sense_ret = TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE;
+ return -EINVAL;
+ }
+ if (sdll > RCR_OP_MAX_SG_DESC_COUNT * XCOPY_SEGMENT_DESC_LEN) {
+ pr_err("XCOPY supports %u segment descriptor(s), sdll: %u too"
+ " large..\n", RCR_OP_MAX_SG_DESC_COUNT, sdll);
+ /* spc4r37 6.4.3.5 SEGMENT DESCRIPTOR LIST LENGTH field */
+ *sense_ret = TCM_TOO_MANY_SEGMENT_DESCS;
return -EINVAL;
}
default:
pr_err("XCOPY unsupported segment descriptor"
"type: 0x%02x\n", desc[0]);
+ *sense_ret = TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE;
goto out;
}
}
return TCM_UNSUPPORTED_SCSI_OPCODE;
}
+ if (se_cmd->data_length == 0) {
+ target_complete_cmd(se_cmd, SAM_STAT_GOOD);
+ return TCM_NO_SENSE;
+ }
+ if (se_cmd->data_length < XCOPY_HDR_LEN) {
+ pr_err("XCOPY parameter truncation: length %u < hdr_len %u\n",
+ se_cmd->data_length, XCOPY_HDR_LEN);
+ return TCM_PARAMETER_LIST_LENGTH_ERROR;
+ }
+
xop = kzalloc(sizeof(struct xcopy_op), GFP_KERNEL);
if (!xop) {
pr_err("Unable to allocate xcopy_op\n");
*/
tdll = get_unaligned_be16(&p[2]);
sdll = get_unaligned_be32(&p[8]);
+ if (tdll + sdll > RCR_OP_MAX_DESC_LIST_LEN) {
+ pr_err("XCOPY descriptor list length %u exceeds maximum %u\n",
+ tdll + sdll, RCR_OP_MAX_DESC_LIST_LEN);
+ ret = TCM_PARAMETER_LIST_LENGTH_ERROR;
+ goto out;
+ }
inline_dl = get_unaligned_be32(&p[12]);
if (inline_dl != 0) {
goto out;
}
+ if (se_cmd->data_length < (XCOPY_HDR_LEN + tdll + sdll + inline_dl)) {
+ pr_err("XCOPY parameter truncation: data length %u too small "
+ "for tdll: %hu sdll: %u inline_dl: %u\n",
+ se_cmd->data_length, tdll, sdll, inline_dl);
+ ret = TCM_PARAMETER_LIST_LENGTH_ERROR;
+ goto out;
+ }
+
pr_debug("Processing XCOPY with list_id: 0x%02x list_id_usage: 0x%02x"
" tdll: %hu sdll: %u inline_dl: %u\n", list_id, list_id_usage,
tdll, sdll, inline_dl);
+ /*
+ * skip over the target descriptors until segment descriptors
+ * have been passed - CSCD ids are needed to determine src and dest.
+ */
+ seg_desc = &p[16] + tdll;
+
+ rc = target_xcopy_parse_segment_descriptors(se_cmd, xop, seg_desc,
+ sdll, &ret);
+ if (rc <= 0)
+ goto out;
+
+ pr_debug("XCOPY: Processed %d segment descriptors, length: %u\n", rc,
+ rc * XCOPY_SEGMENT_DESC_LEN);
+
rc = target_xcopy_parse_target_descriptors(se_cmd, xop, &p[16], tdll, &ret);
if (rc <= 0)
goto out;
pr_debug("XCOPY: Processed %d target descriptors, length: %u\n", rc,
rc * XCOPY_TARGET_DESC_LEN);
- seg_desc = &p[16];
- seg_desc += (rc * XCOPY_TARGET_DESC_LEN);
-
- rc = target_xcopy_parse_segment_descriptors(se_cmd, xop, seg_desc, sdll);
- if (rc <= 0) {
- xcopy_pt_undepend_remotedev(xop);
- goto out;
- }
transport_kunmap_data_sg(se_cmd);
- pr_debug("XCOPY: Processed %d segment descriptors, length: %u\n", rc,
- rc * XCOPY_SEGMENT_DESC_LEN);
INIT_WORK(&xop->xop_work, target_xcopy_do_work);
queue_work(xcopy_wq, &xop->xop_work);
return TCM_NO_SENSE;
#include <target/target_core_base.h>
+#define XCOPY_HDR_LEN 16
#define XCOPY_TARGET_DESC_LEN 32
#define XCOPY_SEGMENT_DESC_LEN 28
#define XCOPY_NAA_IEEE_REGEX_LEN 16
#define XCOPY_MAX_SECTORS 1024
+/*
+ * SPC4r37 6.4.6.1
+ * Table 150 — CSCD descriptor ID values
+ */
+#define XCOPY_CSCD_DESC_ID_LIST_OFF_MAX 0x07FF
+
enum xcopy_origin_list {
XCOL_SOURCE_RECV_OP = 0x01,
XCOL_DEST_RECV_OP = 0x02,
void (*control)(void __iomem *reg, bool on);
/* Per-sensor methods */
- int (*get_temp)(struct chip_tsadc_table table,
+ int (*get_temp)(const struct chip_tsadc_table *table,
int chn, void __iomem *reg, int *temp);
- void (*set_alarm_temp)(struct chip_tsadc_table table,
- int chn, void __iomem *reg, int temp);
- void (*set_tshut_temp)(struct chip_tsadc_table table,
- int chn, void __iomem *reg, int temp);
+ int (*set_alarm_temp)(const struct chip_tsadc_table *table,
+ int chn, void __iomem *reg, int temp);
+ int (*set_tshut_temp)(const struct chip_tsadc_table *table,
+ int chn, void __iomem *reg, int temp);
void (*set_tshut_mode)(int chn, void __iomem *reg, enum tshut_mode m);
/* Per-table methods */
{3452, 115000},
{3437, 120000},
{3421, 125000},
+ {0, 125000},
};
static const struct tsadc_table rk3368_code_table[] = {
{TSADCV3_DATA_MASK, 125000},
};
-static u32 rk_tsadcv2_temp_to_code(struct chip_tsadc_table table,
+static u32 rk_tsadcv2_temp_to_code(const struct chip_tsadc_table *table,
int temp)
{
int high, low, mid;
- u32 error = 0;
+ unsigned long num;
+ unsigned int denom;
+ u32 error = table->data_mask;
low = 0;
- high = table.length - 1;
+ high = (table->length - 1) - 1; /* ignore the last check for table */
mid = (high + low) / 2;
/* Return mask code data when the temp is over table range */
- if (temp < table.id[low].temp || temp > table.id[high].temp) {
- error = table.data_mask;
+ if (temp < table->id[low].temp || temp > table->id[high].temp)
goto exit;
- }
while (low <= high) {
- if (temp == table.id[mid].temp)
- return table.id[mid].code;
- else if (temp < table.id[mid].temp)
+ if (temp == table->id[mid].temp)
+ return table->id[mid].code;
+ else if (temp < table->id[mid].temp)
high = mid - 1;
else
low = mid + 1;
mid = (low + high) / 2;
}
+ /*
+ * The conversion code granularity provided by the table. Let's
+ * assume that the relationship between temperature and
+ * analog value between 2 table entries is linear and interpolate
+ * to produce less granular result.
+ */
+ num = abs(table->id[mid + 1].code - table->id[mid].code);
+ num *= temp - table->id[mid].temp;
+ denom = table->id[mid + 1].temp - table->id[mid].temp;
+
+ switch (table->mode) {
+ case ADC_DECREMENT:
+ return table->id[mid].code - (num / denom);
+ case ADC_INCREMENT:
+ return table->id[mid].code + (num / denom);
+ default:
+ pr_err("%s: unknown table mode: %d\n", __func__, table->mode);
+ return error;
+ }
+
exit:
- pr_err("Invalid the conversion, error=%d\n", error);
+ pr_err("%s: invalid temperature, temp=%d error=%d\n",
+ __func__, temp, error);
return error;
}
-static int rk_tsadcv2_code_to_temp(struct chip_tsadc_table table, u32 code,
- int *temp)
+static int rk_tsadcv2_code_to_temp(const struct chip_tsadc_table *table,
+ u32 code, int *temp)
{
unsigned int low = 1;
- unsigned int high = table.length - 1;
+ unsigned int high = table->length - 1;
unsigned int mid = (low + high) / 2;
unsigned int num;
unsigned long denom;
- WARN_ON(table.length < 2);
+ WARN_ON(table->length < 2);
- switch (table.mode) {
+ switch (table->mode) {
case ADC_DECREMENT:
- code &= table.data_mask;
- if (code < table.id[high].code)
+ code &= table->data_mask;
+ if (code <= table->id[high].code)
return -EAGAIN; /* Incorrect reading */
while (low <= high) {
- if (code >= table.id[mid].code &&
- code < table.id[mid - 1].code)
+ if (code >= table->id[mid].code &&
+ code < table->id[mid - 1].code)
break;
- else if (code < table.id[mid].code)
+ else if (code < table->id[mid].code)
low = mid + 1;
else
high = mid - 1;
}
break;
case ADC_INCREMENT:
- code &= table.data_mask;
- if (code < table.id[low].code)
+ code &= table->data_mask;
+ if (code < table->id[low].code)
return -EAGAIN; /* Incorrect reading */
while (low <= high) {
- if (code <= table.id[mid].code &&
- code > table.id[mid - 1].code)
+ if (code <= table->id[mid].code &&
+ code > table->id[mid - 1].code)
break;
- else if (code > table.id[mid].code)
+ else if (code > table->id[mid].code)
low = mid + 1;
else
high = mid - 1;
}
break;
default:
- pr_err("Invalid the conversion table\n");
+ pr_err("%s: unknown table mode: %d\n", __func__, table->mode);
+ return -EINVAL;
}
/*
* temperature between 2 table entries is linear and interpolate
* to produce less granular result.
*/
- num = table.id[mid].temp - table.id[mid - 1].temp;
- num *= abs(table.id[mid - 1].code - code);
- denom = abs(table.id[mid - 1].code - table.id[mid].code);
- *temp = table.id[mid - 1].temp + (num / denom);
+ num = table->id[mid].temp - table->id[mid - 1].temp;
+ num *= abs(table->id[mid - 1].code - code);
+ denom = abs(table->id[mid - 1].code - table->id[mid].code);
+ *temp = table->id[mid - 1].temp + (num / denom);
return 0;
}
writel_relaxed(val, regs + TSADCV2_AUTO_CON);
}
-static int rk_tsadcv2_get_temp(struct chip_tsadc_table table,
+static int rk_tsadcv2_get_temp(const struct chip_tsadc_table *table,
int chn, void __iomem *regs, int *temp)
{
u32 val;
return rk_tsadcv2_code_to_temp(table, val, temp);
}
-static void rk_tsadcv2_alarm_temp(struct chip_tsadc_table table,
- int chn, void __iomem *regs, int temp)
+static int rk_tsadcv2_alarm_temp(const struct chip_tsadc_table *table,
+ int chn, void __iomem *regs, int temp)
{
- u32 alarm_value, int_en;
+ u32 alarm_value;
+ u32 int_en, int_clr;
+
+ /*
+ * In some cases, some sensors didn't need the trip points, the
+ * set_trips will pass {-INT_MAX, INT_MAX} to trigger tsadc alarm
+ * in the end, ignore this case and disable the high temperature
+ * interrupt.
+ */
+ if (temp == INT_MAX) {
+ int_clr = readl_relaxed(regs + TSADCV2_INT_EN);
+ int_clr &= ~TSADCV2_INT_SRC_EN(chn);
+ writel_relaxed(int_clr, regs + TSADCV2_INT_EN);
+ return 0;
+ }
/* Make sure the value is valid */
alarm_value = rk_tsadcv2_temp_to_code(table, temp);
- if (alarm_value == table.data_mask)
- return;
+ if (alarm_value == table->data_mask)
+ return -ERANGE;
- writel_relaxed(alarm_value & table.data_mask,
+ writel_relaxed(alarm_value & table->data_mask,
regs + TSADCV2_COMP_INT(chn));
int_en = readl_relaxed(regs + TSADCV2_INT_EN);
int_en |= TSADCV2_INT_SRC_EN(chn);
writel_relaxed(int_en, regs + TSADCV2_INT_EN);
+
+ return 0;
}
-static void rk_tsadcv2_tshut_temp(struct chip_tsadc_table table,
- int chn, void __iomem *regs, int temp)
+static int rk_tsadcv2_tshut_temp(const struct chip_tsadc_table *table,
+ int chn, void __iomem *regs, int temp)
{
u32 tshut_value, val;
/* Make sure the value is valid */
tshut_value = rk_tsadcv2_temp_to_code(table, temp);
- if (tshut_value == table.data_mask)
- return;
+ if (tshut_value == table->data_mask)
+ return -ERANGE;
writel_relaxed(tshut_value, regs + TSADCV2_COMP_SHUT(chn));
/* TSHUT will be valid */
val = readl_relaxed(regs + TSADCV2_AUTO_CON);
writel_relaxed(val | TSADCV2_AUTO_SRC_EN(chn), regs + TSADCV2_AUTO_CON);
+
+ return 0;
}
static void rk_tsadcv2_tshut_mode(int chn, void __iomem *regs,
dev_dbg(&thermal->pdev->dev, "%s: sensor %d: low: %d, high %d\n",
__func__, sensor->id, low, high);
- tsadc->set_alarm_temp(tsadc->table,
- sensor->id, thermal->regs, high);
-
- return 0;
+ return tsadc->set_alarm_temp(&tsadc->table,
+ sensor->id, thermal->regs, high);
}
static int rockchip_thermal_get_temp(void *_sensor, int *out_temp)
const struct rockchip_tsadc_chip *tsadc = sensor->thermal->chip;
int retval;
- retval = tsadc->get_temp(tsadc->table,
+ retval = tsadc->get_temp(&tsadc->table,
sensor->id, thermal->regs, out_temp);
dev_dbg(&thermal->pdev->dev, "sensor %d - temp: %d, retval: %d\n",
sensor->id, *out_temp, retval);
int error;
tsadc->set_tshut_mode(id, thermal->regs, thermal->tshut_mode);
- tsadc->set_tshut_temp(tsadc->table, id, thermal->regs,
+
+ error = tsadc->set_tshut_temp(&tsadc->table, id, thermal->regs,
thermal->tshut_temp);
+ if (error)
+ dev_err(&pdev->dev, "%s: invalid tshut=%d, error=%d\n",
+ __func__, thermal->tshut_temp, error);
sensor->thermal = thermal;
sensor->id = id;
thermal->chip->set_tshut_mode(id, thermal->regs,
thermal->tshut_mode);
- thermal->chip->set_tshut_temp(thermal->chip->table,
+
+ error = thermal->chip->set_tshut_temp(&thermal->chip->table,
id, thermal->regs,
thermal->tshut_temp);
+ if (error)
+ dev_err(&pdev->dev, "%s: invalid tshut=%d, error=%d\n",
+ __func__, thermal->tshut_temp, error);
}
thermal->chip->control(thermal->regs, true);
if (!strncmp(dev_name(dev), "thermal_zone",
sizeof("thermal_zone") - 1)) {
tz = to_thermal_zone(dev);
+ kfree(tz->trip_type_attrs);
+ kfree(tz->trip_temp_attrs);
+ kfree(tz->trip_hyst_attrs);
+ kfree(tz->trips_attribute_group.attrs);
+ kfree(tz->device.groups);
kfree(tz);
} else if (!strncmp(dev_name(dev), "cooling_device",
sizeof("cooling_device") - 1)) {
thermal_zone_device_set_polling(tz, 0);
- kfree(tz->trip_type_attrs);
- kfree(tz->trip_temp_attrs);
- kfree(tz->trip_hyst_attrs);
- kfree(tz->trips_attribute_group.attrs);
thermal_set_governor(tz, NULL);
thermal_remove_hwmon_sysfs(tz);
idr_destroy(&tz->idr);
mutex_destroy(&tz->lock);
device_unregister(&tz->device);
- kfree(tz->device.groups);
}
EXPORT_SYMBOL_GPL(thermal_zone_device_unregister);
.device = uart_console_device,
.setup = univ8250_console_setup,
.match = univ8250_console_match,
- .flags = CON_PRINTBUFFER | CON_ANYTIME | CON_CONSDEV,
+ .flags = CON_PRINTBUFFER | CON_ANYTIME,
.index = -1,
.data = &serial8250_reg,
};
static void serial8250_io_resume(struct pci_dev *dev)
{
struct serial_private *priv = pci_get_drvdata(dev);
- const struct pciserial_board *board;
+ struct serial_private *new;
if (!priv)
return;
- board = priv->board;
- kfree(priv);
- priv = pciserial_init_ports(dev, board);
-
- if (!IS_ERR(priv)) {
- pci_set_drvdata(dev, priv);
+ new = pciserial_init_ports(dev, priv->board);
+ if (!IS_ERR(new)) {
+ pci_set_drvdata(dev, new);
+ kfree(priv);
}
}
* Enable previously disabled RX interrupts.
*/
if (!(p->port.rs485.flags & SER_RS485_RX_DURING_TX)) {
- serial8250_clear_fifos(p);
+ serial8250_clear_and_reinit_fifos(p);
p->ier |= UART_IER_RLSI | UART_IER_RDI;
serial_port_out(&p->port, UART_IER, p->ier);
/* disable PDC transmit */
atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS);
}
+
+ /*
+ * Disable the transmitter.
+ * This is mandatory when DMA is used, otherwise the DMA buffer
+ * is fully transmitted.
+ */
+ atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXDIS);
+
/* Disable interrupts */
atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask);
/* Enable interrupts */
atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask);
+
+ /* re-enable the transmitter */
+ atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN);
}
/*
*/
if (!uart_circ_empty(xmit))
atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx);
+ else if ((port->rs485.flags & SER_RS485_ENABLED) &&
+ !(port->rs485.flags & SER_RS485_RX_DURING_TX)) {
+ /* DMA done, stop TX, start RX for RS485 */
+ atmel_start_rx(port);
+ }
spin_unlock_irqrestore(&port->lock, flags);
}
desc->callback = atmel_complete_tx_dma;
desc->callback_param = atmel_port;
atmel_port->cookie_tx = dmaengine_submit(desc);
-
- } else {
- if (port->rs485.flags & SER_RS485_ENABLED) {
- /* DMA done, stop TX, start RX for RS485 */
- atmel_start_rx(port);
- }
}
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
INPUT_DEVICE_ID_MATCH_KEYBIT,
- .evbit = { BIT_MASK(EV_KEY) },
- .keybit = { BIT_MASK(KEY_LEFTALT) },
+ .evbit = { [BIT_WORD(EV_KEY)] = BIT_MASK(EV_KEY) },
+ .keybit = { [BIT_WORD(KEY_LEFTALT)] = BIT_MASK(KEY_LEFTALT) },
},
{ },
};
/* CBM - Flash disk */
{ USB_DEVICE(0x0204, 0x6025), .driver_info = USB_QUIRK_RESET_RESUME },
+ /* WORLDE easy key (easykey.25) MIDI controller */
+ { USB_DEVICE(0x0218, 0x0401), .driver_info =
+ USB_QUIRK_CONFIG_INTF_STRINGS },
+
/* HP 5300/5370C scanner */
{ USB_DEVICE(0x03f0, 0x0701), .driver_info =
USB_QUIRK_STRING_FETCH_255 },
/* Gadget parameters */
bool g_dma;
bool g_dma_desc;
- u16 g_rx_fifo_size;
- u16 g_np_tx_fifo_size;
+ u32 g_rx_fifo_size;
+ u32 g_np_tx_fifo_size;
u32 g_tx_fifo_size[MAX_EPS_CHANNELS];
};
/* keep other bits untouched (so e.g. forced modes are not lost) */
usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
usbcfg &= ~(GUSBCFG_TOUTCAL_MASK | GUSBCFG_PHYIF16 | GUSBCFG_SRPCAP |
- GUSBCFG_HNPCAP);
+ GUSBCFG_HNPCAP | GUSBCFG_USBTRDTIM_MASK);
if (hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS &&
(hsotg->params.speed == DWC2_SPEED_PARAM_FULL ||
__func__, epctrl, epctrl_reg);
/* Allocate DMA descriptor chain for non-ctrl endpoints */
- if (using_desc_dma(hsotg)) {
- hs_ep->desc_list = dma_alloc_coherent(hsotg->dev,
+ if (using_desc_dma(hsotg) && !hs_ep->desc_list) {
+ hs_ep->desc_list = dmam_alloc_coherent(hsotg->dev,
MAX_DMA_DESC_NUM_GENERIC *
sizeof(struct dwc2_dma_desc),
&hs_ep->desc_list_dma, GFP_ATOMIC);
error2:
if (ret && using_desc_dma(hsotg) && hs_ep->desc_list) {
- dma_free_coherent(hsotg->dev, MAX_DMA_DESC_NUM_GENERIC *
+ dmam_free_coherent(hsotg->dev, MAX_DMA_DESC_NUM_GENERIC *
sizeof(struct dwc2_dma_desc),
hs_ep->desc_list, hs_ep->desc_list_dma);
hs_ep->desc_list = NULL;
return -EINVAL;
}
- /* Remove DMA memory allocated for non-control Endpoints */
- if (using_desc_dma(hsotg)) {
- dma_free_coherent(hsotg->dev, MAX_DMA_DESC_NUM_GENERIC *
- sizeof(struct dwc2_dma_desc),
- hs_ep->desc_list, hs_ep->desc_list_dma);
- hs_ep->desc_list = NULL;
- }
-
epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index);
spin_lock_irqsave(&hsotg->lock, flags);
/* keep other bits untouched (so e.g. forced modes are not lost) */
usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
usbcfg &= ~(GUSBCFG_TOUTCAL_MASK | GUSBCFG_PHYIF16 | GUSBCFG_SRPCAP |
- GUSBCFG_HNPCAP);
+ GUSBCFG_HNPCAP | GUSBCFG_USBTRDTIM_MASK);
/* set the PLL on, remove the HNP/SRP and set the PHY */
trdtim = (hsotg->phyif == GUSBCFG_PHYIF8) ? 9 : 5;
if (!HCD_HW_ACCESSIBLE(hcd))
goto unlock;
+ if (hsotg->op_state == OTG_STATE_B_PERIPHERAL)
+ goto unlock;
+
if (!hsotg->params.hibernation)
goto skip_power_saving;
{
#ifdef VERBOSE_DEBUG
struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
- char *pipetype;
- char *speed;
+ char *pipetype = NULL;
+ char *speed = NULL;
dev_vdbg(hsotg->dev, "%s, urb %p\n", fn_name, urb);
dev_vdbg(hsotg->dev, " Device address: %d\n",
}
/**
- * dwc2_set_param_u16() - Set a u16 parameter
+ * dwc2_set_param_u32() - Set a u32 parameter
*
* See dwc2_set_param().
*/
-static void dwc2_set_param_u16(struct dwc2_hsotg *hsotg, u16 *param,
+static void dwc2_set_param_u32(struct dwc2_hsotg *hsotg, u32 *param,
bool lookup, char *property, u16 legacy,
u16 def, u16 min, u16 max)
{
dwc2_set_param(hsotg, param, lookup, property,
- legacy, def, min, max, 2);
+ legacy, def, min, max, 4);
}
/**
* auto-detect if the hardware does not support the
* default.
*/
- dwc2_set_param_u16(hsotg, &p->g_rx_fifo_size,
+ dwc2_set_param_u32(hsotg, &p->g_rx_fifo_size,
true, "g-rx-fifo-size", 2048,
hw->rx_fifo_size,
16, hw->rx_fifo_size);
- dwc2_set_param_u16(hsotg, &p->g_np_tx_fifo_size,
+ dwc2_set_param_u32(hsotg, &p->g_np_tx_fifo_size,
true, "g-np-tx-fifo-size", 1024,
hw->dev_nperio_tx_fifo_size,
16, hw->dev_nperio_tx_fifo_size);
exynos->axius_clk = devm_clk_get(dev, "usbdrd30_axius_clk");
if (IS_ERR(exynos->axius_clk)) {
dev_err(dev, "no AXI UpScaler clk specified\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto axius_clk_err;
}
clk_prepare_enable(exynos->axius_clk);
} else {
regulator_disable(exynos->vdd33);
err2:
clk_disable_unprepare(exynos->axius_clk);
+axius_clk_err:
clk_disable_unprepare(exynos->susp_clk);
clk_disable_unprepare(exynos->clk);
return ret;
cdev->os_desc_req->buf = kmalloc(4096, GFP_KERNEL);
if (!cdev->os_desc_req->buf) {
ret = -ENOMEM;
- kfree(cdev->os_desc_req);
+ usb_ep_free_request(ep0, cdev->os_desc_req);
goto end;
}
cdev->os_desc_req->context = cdev;
unsigned long flags;
spin_lock_irqsave(&func->ffs->eps_lock, flags);
- do {
+ while (count--) {
/* pending requests get nuked */
if (likely(ep->ep))
usb_ep_disable(ep->ep);
__ffs_epfile_read_buffer_free(epfile);
++epfile;
}
- } while (--count);
+ }
spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
}
int ret = 0;
spin_lock_irqsave(&func->ffs->eps_lock, flags);
- do {
+ while(count--) {
struct usb_endpoint_descriptor *ds;
int desc_idx;
++ep;
++epfile;
- } while (--count);
+ }
spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
return ret;
if (len < sizeof(*d) || h->interface >= ffs->interfaces_count)
return -EINVAL;
length = le32_to_cpu(d->dwSize);
+ if (len < length)
+ return -EINVAL;
type = le32_to_cpu(d->dwPropertyDataType);
if (type < USB_EXT_PROP_UNICODE ||
type > USB_EXT_PROP_UNICODE_MULTI) {
return -EINVAL;
}
pnl = le16_to_cpu(d->wPropertyNameLength);
+ if (length < 14 + pnl) {
+ pr_vdebug("invalid os descriptor length: %d pnl:%d (descriptor %d)\n",
+ length, pnl, type);
+ return -EINVAL;
+ }
pdl = le32_to_cpu(*(u32 *)((u8 *)data + 10 + pnl));
if (length != 14 + pnl + pdl) {
pr_vdebug("invalid os descriptor length: %d pnl:%d pdl:%d (descriptor %d)\n",
}
}
if (flags & (1 << i)) {
+ if (len < 4) {
+ goto error;
+ }
os_descs_count = get_unaligned_le32(data);
data += 4;
len -= 4;
ENTER();
- if (unlikely(get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC ||
+ if (unlikely(len < 16 ||
+ get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC ||
get_unaligned_le32(data + 4) != len))
goto error;
str_count = get_unaligned_le32(data + 8);
/* cleanup after autoconfig */
spin_lock_irqsave(&func->ffs->eps_lock, flags);
- do {
+ while (count--) {
if (ep->ep && ep->req)
usb_ep_free_request(ep->ep, ep->req);
ep->req = NULL;
++ep;
- } while (--count);
+ }
spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
kfree(func->eps);
func->eps = NULL;
dev_err(&pdev->dev, "of_probe: name error(%d)\n", ret);
goto err;
}
- ep->ep.name = kasprintf(GFP_KERNEL, "ep%d", ep->index);
+ sprintf(ep->name, "ep%d", ep->index);
+ ep->ep.name = ep->name;
ep->ep_regs = udc->regs + USBA_EPT_BASE(i);
ep->dma_regs = udc->regs + USBA_DMA_BASE(i);
void __iomem *ep_regs;
void __iomem *dma_regs;
void __iomem *fifo;
+ char name[8];
struct usb_ep ep;
struct usba_udc *udc;
return -ENODEV;
/* Try to set 64-bit DMA first */
- if (WARN_ON(!pdev->dev.dma_mask))
+ if (!pdev->dev.dma_mask)
/* Platform did not initialize dma_mask */
ret = dma_coerce_mask_and_coherent(&pdev->dev,
DMA_BIT_MASK(64));
spin_lock_irqsave(&xhci->lock, flags);
ep->stop_cmds_pending--;
- if (xhci->xhc_state & XHCI_STATE_REMOVING) {
- spin_unlock_irqrestore(&xhci->lock, flags);
- return;
- }
- if (xhci->xhc_state & XHCI_STATE_DYING) {
- xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
- "Stop EP timer ran, but another timer marked "
- "xHCI as DYING, exiting.");
- spin_unlock_irqrestore(&xhci->lock, flags);
- return;
- }
if (!(ep->stop_cmds_pending == 0 && (ep->ep_state & EP_HALT_PENDING))) {
xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
"Stop EP timer ran, but no command pending, "
xhci_urb_free_priv(urb_priv);
return ret;
}
- if ((xhci->xhc_state & XHCI_STATE_DYING) ||
- (xhci->xhc_state & XHCI_STATE_HALTED)) {
- xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,
- "Ep 0x%x: URB %p to be canceled on "
- "non-responsive xHCI host.",
- urb->ep->desc.bEndpointAddress, urb);
- /* Let the stop endpoint command watchdog timer (which set this
- * state) finish cleaning up the endpoint TD lists. We must
- * have caught it in the middle of dropping a lock and giving
- * back an URB.
- */
- goto done;
- }
ep_index = xhci_get_endpoint_index(&urb->ep->desc);
ep = &xhci->devs[urb->dev->slot_id]->eps[ep_index];
| MUSB_PORT_STAT_RESUME;
musb->rh_timer = jiffies
+ msecs_to_jiffies(USB_RESUME_TIMEOUT);
- musb->need_finish_resume = 1;
-
musb->xceiv->otg->state = OTG_STATE_A_HOST;
musb->is_active = 1;
musb_host_resume_root_hub(musb);
+ schedule_delayed_work(&musb->finish_resume_work,
+ msecs_to_jiffies(USB_RESUME_TIMEOUT));
break;
case OTG_STATE_B_WAIT_ACON:
musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
static void musb_irq_work(struct work_struct *data)
{
struct musb *musb = container_of(data, struct musb, irq_work.work);
+ int error;
+
+ error = pm_runtime_get_sync(musb->controller);
+ if (error < 0) {
+ dev_err(musb->controller, "Could not enable: %i\n", error);
+
+ return;
+ }
musb_pm_runtime_check_session(musb);
musb->xceiv_old_state = musb->xceiv->otg->state;
sysfs_notify(&musb->controller->kobj, NULL, "mode");
}
+
+ pm_runtime_mark_last_busy(musb->controller);
+ pm_runtime_put_autosuspend(musb->controller);
}
static void musb_recover_from_babble(struct musb *musb)
mask = MUSB_DEVCTL_BDEVICE | MUSB_DEVCTL_FSDEV | MUSB_DEVCTL_LSDEV;
if ((devctl & mask) != (musb->context.devctl & mask))
musb->port1_status = 0;
- if (musb->need_finish_resume) {
- musb->need_finish_resume = 0;
- schedule_delayed_work(&musb->finish_resume_work,
- msecs_to_jiffies(USB_RESUME_TIMEOUT));
- }
/*
* The USB HUB code expects the device to be in RPM_ACTIVE once it came
musb_restore_context(musb);
- if (musb->need_finish_resume) {
- musb->need_finish_resume = 0;
- schedule_delayed_work(&musb->finish_resume_work,
- msecs_to_jiffies(USB_RESUME_TIMEOUT));
- }
-
spin_lock_irqsave(&musb->lock, flags);
error = musb_run_resume_work(musb);
if (error)
/* is_suspended means USB B_PERIPHERAL suspend */
unsigned is_suspended:1;
- unsigned need_finish_resume :1;
/* may_wakeup means remote wakeup is enabled */
unsigned may_wakeup:1;
unsigned i;
seq_printf(s, "MUSB (M)HDRC Register Dump\n");
+ pm_runtime_get_sync(musb->controller);
for (i = 0; i < ARRAY_SIZE(musb_regmap); i++) {
switch (musb_regmap[i].size) {
}
}
+ pm_runtime_mark_last_busy(musb->controller);
+ pm_runtime_put_autosuspend(musb->controller);
return 0;
}
struct musb *musb = s->private;
unsigned test;
+ pm_runtime_get_sync(musb->controller);
test = musb_readb(musb->mregs, MUSB_TESTMODE);
+ pm_runtime_mark_last_busy(musb->controller);
+ pm_runtime_put_autosuspend(musb->controller);
if (test & MUSB_TEST_FORCE_HOST)
seq_printf(s, "force host\n");
u8 test;
char buf[18];
+ pm_runtime_get_sync(musb->controller);
test = musb_readb(musb->mregs, MUSB_TESTMODE);
if (test) {
dev_err(musb->controller, "Error: test mode is already set. "
"Please do USB Bus Reset to start a new test.\n");
- return count;
+ goto ret;
}
memset(buf, 0x00, sizeof(buf));
musb_writeb(musb->mregs, MUSB_TESTMODE, test);
+ret:
+ pm_runtime_mark_last_busy(musb->controller);
+ pm_runtime_put_autosuspend(musb->controller);
return count;
}
switch (musb->xceiv->otg->state) {
case OTG_STATE_A_HOST:
case OTG_STATE_A_WAIT_BCON:
+ pm_runtime_get_sync(musb->controller);
+
reg = musb_readb(musb->mregs, MUSB_DEVCTL);
connect = reg & MUSB_DEVCTL_SESSION ? 1 : 0;
+
+ pm_runtime_mark_last_busy(musb->controller);
+ pm_runtime_put_autosuspend(musb->controller);
break;
default:
connect = -1;
if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
return -EFAULT;
+ pm_runtime_get_sync(musb->controller);
if (!strncmp(buf, "0", 1)) {
switch (musb->xceiv->otg->state) {
case OTG_STATE_A_HOST:
}
}
+ pm_runtime_mark_last_busy(musb->controller);
+ pm_runtime_put_autosuspend(musb->controller);
return count;
}
unsigned baud_rate; /* set baud rate */
u8 line_control; /* set line control value RTS/DTR */
u8 line_status; /* active status of modem control inputs */
+ u8 lcr;
};
static void ch341_set_termios(struct tty_struct *tty,
r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
value, index, NULL, 0, DEFAULT_TIMEOUT);
+ if (r < 0)
+ dev_err(&dev->dev, "failed to send control message: %d\n", r);
return r;
}
r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
value, index, buf, bufsize, DEFAULT_TIMEOUT);
- return r;
+ if (r < bufsize) {
+ if (r >= 0) {
+ dev_err(&dev->dev,
+ "short control message received (%d < %u)\n",
+ r, bufsize);
+ r = -EIO;
+ }
+
+ dev_err(&dev->dev, "failed to receive control message: %d\n",
+ r);
+ return r;
+ }
+
+ return 0;
}
-static int ch341_init_set_baudrate(struct usb_device *dev,
- struct ch341_private *priv, unsigned ctrl)
+static int ch341_set_baudrate_lcr(struct usb_device *dev,
+ struct ch341_private *priv, u8 lcr)
{
short a;
int r;
factor = 0x10000 - factor;
a = (factor & 0xff00) | divisor;
- /* 0x9c is "enable SFR_UART Control register and timer" */
- r = ch341_control_out(dev, CH341_REQ_SERIAL_INIT,
- 0x9c | (ctrl << 8), a | 0x80);
+ /*
+ * CH341A buffers data until a full endpoint-size packet (32 bytes)
+ * has been received unless bit 7 is set.
+ */
+ a |= BIT(7);
+
+ r = ch341_control_out(dev, CH341_REQ_WRITE_REG, 0x1312, a);
+ if (r)
+ return r;
+
+ r = ch341_control_out(dev, CH341_REQ_WRITE_REG, 0x2518, lcr);
+ if (r)
+ return r;
return r;
}
static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv)
{
+ const unsigned int size = 2;
char *buffer;
int r;
- const unsigned size = 8;
unsigned long flags;
buffer = kmalloc(size, GFP_KERNEL);
if (r < 0)
goto out;
- /* setup the private status if available */
- if (r == 2) {
- r = 0;
- spin_lock_irqsave(&priv->lock, flags);
- priv->line_status = (~(*buffer)) & CH341_BITS_MODEM_STAT;
- spin_unlock_irqrestore(&priv->lock, flags);
- } else
- r = -EPROTO;
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->line_status = (~(*buffer)) & CH341_BITS_MODEM_STAT;
+ spin_unlock_irqrestore(&priv->lock, flags);
out: kfree(buffer);
return r;
static int ch341_configure(struct usb_device *dev, struct ch341_private *priv)
{
+ const unsigned int size = 2;
char *buffer;
int r;
- const unsigned size = 8;
buffer = kmalloc(size, GFP_KERNEL);
if (!buffer)
if (r < 0)
goto out;
- r = ch341_init_set_baudrate(dev, priv, 0);
+ r = ch341_set_baudrate_lcr(dev, priv, priv->lcr);
if (r < 0)
goto out;
spin_lock_init(&priv->lock);
priv->baud_rate = DEFAULT_BAUD_RATE;
- priv->line_control = CH341_BIT_RTS | CH341_BIT_DTR;
r = ch341_configure(port->serial->dev, priv);
if (r < 0)
r = ch341_configure(serial->dev, priv);
if (r)
- goto out;
+ return r;
if (tty)
ch341_set_termios(tty, port, NULL);
if (r) {
dev_err(&port->dev, "%s - failed to submit interrupt urb: %d\n",
__func__, r);
- goto out;
+ return r;
}
r = usb_serial_generic_open(tty, port);
+ if (r)
+ goto err_kill_interrupt_urb;
+
+ return 0;
+
+err_kill_interrupt_urb:
+ usb_kill_urb(port->interrupt_in_urb);
-out: return r;
+ return r;
}
/* Old_termios contains the original termios settings and
baud_rate = tty_get_baud_rate(tty);
- priv->baud_rate = baud_rate;
ctrl = CH341_LCR_ENABLE_RX | CH341_LCR_ENABLE_TX;
switch (C_CSIZE(tty)) {
ctrl |= CH341_LCR_STOP_BITS_2;
if (baud_rate) {
- spin_lock_irqsave(&priv->lock, flags);
- priv->line_control |= (CH341_BIT_DTR | CH341_BIT_RTS);
- spin_unlock_irqrestore(&priv->lock, flags);
- r = ch341_init_set_baudrate(port->serial->dev, priv, ctrl);
+ priv->baud_rate = baud_rate;
+
+ r = ch341_set_baudrate_lcr(port->serial->dev, priv, ctrl);
if (r < 0 && old_termios) {
priv->baud_rate = tty_termios_baud_rate(old_termios);
tty_termios_copy_hw(&tty->termios, old_termios);
+ } else if (r == 0) {
+ priv->lcr = ctrl;
}
- } else {
- spin_lock_irqsave(&priv->lock, flags);
- priv->line_control &= ~(CH341_BIT_DTR | CH341_BIT_RTS);
- spin_unlock_irqrestore(&priv->lock, flags);
}
- ch341_set_handshake(port->serial->dev, priv->line_control);
+ spin_lock_irqsave(&priv->lock, flags);
+ if (C_BAUD(tty) == B0)
+ priv->line_control &= ~(CH341_BIT_DTR | CH341_BIT_RTS);
+ else if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
+ priv->line_control |= (CH341_BIT_DTR | CH341_BIT_RTS);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ ch341_set_handshake(port->serial->dev, priv->line_control);
}
static void ch341_break_ctl(struct tty_struct *tty, int break_state)
static int ch341_reset_resume(struct usb_serial *serial)
{
- struct ch341_private *priv;
-
- priv = usb_get_serial_port_data(serial->port[0]);
+ struct usb_serial_port *port = serial->port[0];
+ struct ch341_private *priv = usb_get_serial_port_data(port);
+ int ret;
/* reconfigure ch341 serial port after bus-reset */
ch341_configure(serial->dev, priv);
- return 0;
+ if (tty_port_initialized(&port->port)) {
+ ret = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
+ if (ret) {
+ dev_err(&port->dev, "failed to submit interrupt urb: %d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ return usb_serial_generic_resume(serial);
}
static struct usb_serial_driver ch341_device = {
status_buf, KLSI_STATUSBUF_LEN,
10000
);
- if (rc < 0)
- dev_err(&port->dev, "Reading line status failed (error = %d)\n",
- rc);
- else {
+ if (rc != KLSI_STATUSBUF_LEN) {
+ dev_err(&port->dev, "reading line status failed: %d\n", rc);
+ if (rc >= 0)
+ rc = -EIO;
+ } else {
status = get_unaligned_le16(status_buf);
dev_info(&port->serial->dev->dev, "read status %x %x\n",
{ USB_DEVICE_AND_INTERFACE_INFO(WETELECOM_VENDOR_ID, WETELECOM_PRODUCT_WMD200, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(WETELECOM_VENDOR_ID, WETELECOM_PRODUCT_6802, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(WETELECOM_VENDOR_ID, WETELECOM_PRODUCT_WMD300, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0x421d, 0xff, 0xff, 0xff) }, /* HP lt2523 (Novatel E371) */
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, option_ids);
{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) },
{ USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) },
+ { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID2) },
{ USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
{ USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) },
#define ATEN_VENDOR_ID 0x0557
#define ATEN_VENDOR_ID2 0x0547
#define ATEN_PRODUCT_ID 0x2008
+#define ATEN_PRODUCT_ID2 0x2118
#define IODATA_VENDOR_ID 0x04bb
#define IODATA_PRODUCT_ID 0x0a03
{USB_DEVICE(0x1410, 0xa021)}, /* Novatel Gobi 3000 Composite */
{USB_DEVICE(0x413c, 0x8193)}, /* Dell Gobi 3000 QDL */
{USB_DEVICE(0x413c, 0x8194)}, /* Dell Gobi 3000 Composite */
+ {USB_DEVICE(0x413c, 0x81a6)}, /* Dell DW5570 QDL (MC8805) */
{USB_DEVICE(0x1199, 0x68a4)}, /* Sierra Wireless QDL */
{USB_DEVICE(0x1199, 0x68a5)}, /* Sierra Wireless Modem */
{USB_DEVICE(0x1199, 0x68a8)}, /* Sierra Wireless QDL */
struct scatterlist sg[4], sg_dst;
void *dst_buf;
size_t dst_size;
- const u8 bzero[16] = { 0 };
u8 iv[crypto_skcipher_ivsize(tfm_cbc)];
size_t zero_padding;
sg_set_buf(&sg[1], &scratch->b1, sizeof(scratch->b1));
sg_set_buf(&sg[2], b, blen);
/* 0 if well behaved :) */
- sg_set_buf(&sg[3], bzero, zero_padding);
+ sg_set_page(&sg[3], ZERO_PAGE(0), zero_padding, 0);
sg_init_one(&sg_dst, dst_buf, dst_size);
skcipher_request_set_tfm(req, tfm_cbc);
mutex_lock(&container->lock);
ret = tce_iommu_create_default_window(container);
- if (ret)
- return ret;
-
- ret = tce_iommu_create_window(container, create.page_shift,
- create.window_size, create.levels,
- &create.start_addr);
+ if (!ret)
+ ret = tce_iommu_create_window(container,
+ create.page_shift,
+ create.window_size, create.levels,
+ &create.start_addr);
mutex_unlock(&container->lock);
/* pr_debug("tce_vfio: Attaching group #%u to iommu %p\n",
iommu_group_id(iommu_group), iommu_group); */
table_group = iommu_group_get_iommudata(iommu_group);
+ if (!table_group) {
+ ret = -ENODEV;
+ goto unlock_exit;
+ }
if (tce_groups_attached(container) && (!table_group->ops ||
!table_group->ops->take_ownership ||
#include <linux/uaccess.h>
#include <linux/vfio.h>
#include <linux/workqueue.h>
-#include <linux/pid_namespace.h>
#include <linux/mdev.h>
#include <linux/notifier.h>
unsigned long *pfn_base, bool do_accounting)
{
unsigned long limit;
- bool lock_cap = ns_capable(task_active_pid_ns(dma->task)->user_ns,
- CAP_IPC_LOCK);
+ bool lock_cap = has_capability(dma->task, CAP_IPC_LOCK);
struct mm_struct *mm;
int ret;
bool rsvd;
struct iov_iter out_iter, in_iter, prot_iter, data_iter;
u64 tag;
u32 exp_data_len, data_direction;
- unsigned out, in;
+ unsigned int out = 0, in = 0;
int head, ret, prot_bytes;
size_t req_size, rsp_size = sizeof(struct virtio_scsi_cmd_resp);
size_t out_size, in_size;
NULL,
};
-static struct target_core_fabric_ops vhost_scsi_ops = {
+static const struct target_core_fabric_ops vhost_scsi_ops = {
.module = THIS_MODULE,
.name = "vhost",
.get_fabric_name = vhost_scsi_get_fabric_name,
static void vhost_init_is_le(struct vhost_virtqueue *vq)
{
- if (vhost_has_feature(vq, VIRTIO_F_VERSION_1))
- vq->is_le = true;
+ vq->is_le = vhost_has_feature(vq, VIRTIO_F_VERSION_1)
+ || virtio_legacy_is_little_endian();
}
#endif /* CONFIG_VHOST_CROSS_ENDIAN_LEGACY */
static void vhost_reset_is_le(struct vhost_virtqueue *vq)
{
- vq->is_le = virtio_legacy_is_little_endian();
+ vhost_init_is_le(vq);
}
struct vhost_flush_struct {
int r;
bool is_le = vq->is_le;
- if (!vq->private_data) {
- vhost_reset_is_le(vq);
+ if (!vq->private_data)
return 0;
- }
vhost_init_is_le(vq);
static int vhost_vsock_start(struct vhost_vsock *vsock)
{
+ struct vhost_virtqueue *vq;
size_t i;
int ret;
goto err;
for (i = 0; i < ARRAY_SIZE(vsock->vqs); i++) {
- struct vhost_virtqueue *vq = &vsock->vqs[i];
+ vq = &vsock->vqs[i];
mutex_lock(&vq->mutex);
if (!vhost_vq_access_ok(vq)) {
ret = -EFAULT;
- mutex_unlock(&vq->mutex);
goto err_vq;
}
if (!vq->private_data) {
vq->private_data = vsock;
- vhost_vq_init_access(vq);
+ ret = vhost_vq_init_access(vq);
+ if (ret)
+ goto err_vq;
}
mutex_unlock(&vq->mutex);
return 0;
err_vq:
+ vq->private_data = NULL;
+ mutex_unlock(&vq->mutex);
+
for (i = 0; i < ARRAY_SIZE(vsock->vqs); i++) {
- struct vhost_virtqueue *vq = &vsock->vqs[i];
+ vq = &vsock->vqs[i];
mutex_lock(&vq->mutex);
vq->private_data = NULL;
int fb_copy_cmap(const struct fb_cmap *from, struct fb_cmap *to)
{
- int tooff = 0, fromoff = 0;
- int size;
+ unsigned int tooff = 0, fromoff = 0;
+ size_t size;
if (to->start > from->start)
fromoff = to->start - from->start;
else
tooff = from->start - to->start;
- size = to->len - tooff;
- if (size > (int) (from->len - fromoff))
- size = from->len - fromoff;
- if (size <= 0)
+ if (fromoff >= from->len || tooff >= to->len)
+ return -EINVAL;
+
+ size = min_t(size_t, to->len - tooff, from->len - fromoff);
+ if (size == 0)
return -EINVAL;
size *= sizeof(u16);
int fb_cmap_to_user(const struct fb_cmap *from, struct fb_cmap_user *to)
{
- int tooff = 0, fromoff = 0;
- int size;
+ unsigned int tooff = 0, fromoff = 0;
+ size_t size;
if (to->start > from->start)
fromoff = to->start - from->start;
else
tooff = from->start - to->start;
- size = to->len - tooff;
- if (size > (int) (from->len - fromoff))
- size = from->len - fromoff;
- if (size <= 0)
+ if (fromoff >= from->len || tooff >= to->len)
+ return -EINVAL;
+
+ size = min_t(size_t, to->len - tooff, from->len - fromoff);
+ if (size == 0)
return -EINVAL;
size *= sizeof(u16);
#define pr_fmt(fmt) "virtio-mmio: " fmt
#include <linux/acpi.h>
+#include <linux/dma-mapping.h>
#include <linux/highmem.h>
#include <linux/interrupt.h>
#include <linux/io.h>
struct virtio_mmio_device *vm_dev;
struct resource *mem;
unsigned long magic;
+ int rc;
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem)
}
vm_dev->vdev.id.vendor = readl(vm_dev->base + VIRTIO_MMIO_VENDOR_ID);
- if (vm_dev->version == 1)
+ if (vm_dev->version == 1) {
writel(PAGE_SIZE, vm_dev->base + VIRTIO_MMIO_GUEST_PAGE_SIZE);
+ rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
+ /*
+ * In the legacy case, ensure our coherently-allocated virtio
+ * ring will be at an address expressable as a 32-bit PFN.
+ */
+ if (!rc)
+ dma_set_coherent_mask(&pdev->dev,
+ DMA_BIT_MASK(32 + PAGE_SHIFT));
+ } else {
+ rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+ }
+ if (rc)
+ rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+ if (rc)
+ dev_warn(&pdev->dev, "Failed to enable 64-bit or 32-bit DMA. Trying to continue, but this might not work.\n");
+
platform_set_drvdata(pdev, vm_dev);
return register_virtio_device(&vm_dev->vdev);
vme_bound = ioread32(bridge->base + CA91CX42_VSI_BD[i]);
pci_offset = ioread32(bridge->base + CA91CX42_VSI_TO[i]);
- *pci_base = (dma_addr_t)vme_base + pci_offset;
+ *pci_base = (dma_addr_t)*vme_base + pci_offset;
*size = (unsigned long long)((vme_bound - *vme_base) + granularity);
*enabled = 0;
static unsigned long platform_mmio;
static unsigned long platform_mmio_alloc;
static unsigned long platform_mmiolen;
+static uint64_t callback_via;
static unsigned long alloc_xen_mmio(unsigned long len)
{
return addr;
}
+static uint64_t get_callback_via(struct pci_dev *pdev)
+{
+ u8 pin;
+ int irq;
+
+ irq = pdev->irq;
+ if (irq < 16)
+ return irq; /* ISA IRQ */
+
+ pin = pdev->pin;
+
+ /* We don't know the GSI. Specify the PCI INTx line instead. */
+ return ((uint64_t)0x01 << HVM_CALLBACK_VIA_TYPE_SHIFT) | /* PCI INTx identifier */
+ ((uint64_t)pci_domain_nr(pdev->bus) << 32) |
+ ((uint64_t)pdev->bus->number << 16) |
+ ((uint64_t)(pdev->devfn & 0xff) << 8) |
+ ((uint64_t)(pin - 1) & 3);
+}
+
+static irqreturn_t do_hvm_evtchn_intr(int irq, void *dev_id)
+{
+ xen_hvm_evtchn_do_upcall();
+ return IRQ_HANDLED;
+}
+
+static int xen_allocate_irq(struct pci_dev *pdev)
+{
+ return request_irq(pdev->irq, do_hvm_evtchn_intr,
+ IRQF_NOBALANCING | IRQF_TRIGGER_RISING,
+ "xen-platform-pci", pdev);
+}
+
+static int platform_pci_resume(struct pci_dev *pdev)
+{
+ int err;
+ if (!xen_pv_domain())
+ return 0;
+ err = xen_set_callback_via(callback_via);
+ if (err) {
+ dev_err(&pdev->dev, "platform_pci_resume failure!\n");
+ return err;
+ }
+ return 0;
+}
+
static int platform_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
platform_mmio = mmio_addr;
platform_mmiolen = mmio_len;
+ /*
+ * Xen HVM guests always use the vector callback mechanism.
+ * L1 Dom0 in a nested Xen environment is a PV guest inside in an
+ * HVM environment. It needs the platform-pci driver to get
+ * notifications from L0 Xen, but it cannot use the vector callback
+ * as it is not exported by L1 Xen.
+ */
+ if (xen_pv_domain()) {
+ ret = xen_allocate_irq(pdev);
+ if (ret) {
+ dev_warn(&pdev->dev, "request_irq failed err=%d\n", ret);
+ goto out;
+ }
+ callback_via = get_callback_via(pdev);
+ ret = xen_set_callback_via(callback_via);
+ if (ret) {
+ dev_warn(&pdev->dev, "Unable to set the evtchn callback "
+ "err=%d\n", ret);
+ goto out;
+ }
+ }
+
max_nr_gframes = gnttab_max_grant_frames();
grant_frames = alloc_xen_mmio(PAGE_SIZE * max_nr_gframes);
ret = gnttab_setup_auto_xlat_frames(grant_frames);
.name = DRV_NAME,
.probe = platform_pci_probe,
.id_table = platform_pci_tbl,
+#ifdef CONFIG_PM
+ .resume_early = platform_pci_resume,
+#endif
};
builtin_pci_driver(platform_driver);
if (map == SWIOTLB_MAP_ERROR)
return DMA_ERROR_CODE;
+ dev_addr = xen_phys_to_bus(map);
xen_dma_map_page(dev, pfn_to_page(map >> PAGE_SHIFT),
dev_addr, map & ~PAGE_MASK, size, dir, attrs);
- dev_addr = xen_phys_to_bus(map);
/*
* Ensure that the address returned is DMA'ble
sg_dma_len(sgl) = 0;
return 0;
}
+ dev_addr = xen_phys_to_bus(map);
xen_dma_map_page(hwdev, pfn_to_page(map >> PAGE_SHIFT),
dev_addr,
map & ~PAGE_MASK,
sg->length,
dir,
attrs);
- sg->dma_address = xen_phys_to_bus(map);
+ sg->dma_address = dev_addr;
} else {
/* we are not interested in the dma_addr returned by
* xen_dma_map_page, only in the potential cache flushes executed
bool "Direct Access (DAX) support"
depends on MMU
depends on !(ARM || MIPS || SPARC)
+ select FS_IOMAP
help
Direct Access (DAX) can be used on memory-backed block devices.
If the block device supports DAX and the filesystem supports DAX,
* Tell lockdep we inherited freeze protection from submission
* thread.
*/
- __sb_writers_acquired(file_inode(file)->i_sb, SB_FREEZE_WRITE);
+ if (S_ISREG(file_inode(file)->i_mode))
+ __sb_writers_acquired(file_inode(file)->i_sb, SB_FREEZE_WRITE);
file_end_write(file);
}
* by telling it the lock got released so that it doesn't
* complain about held lock when we return to userspace.
*/
- __sb_writers_release(file_inode(file)->i_sb, SB_FREEZE_WRITE);
+ if (S_ISREG(file_inode(file)->i_mode))
+ __sb_writers_release(file_inode(file)->i_sb, SB_FREEZE_WRITE);
}
kfree(iovec);
return ret;
goto end_coredump;
}
}
+ dump_truncate(cprm);
if (!elf_core_write_extra_data(cprm))
goto end_coredump;
struct blk_plug plug;
struct blkdev_dio *dio;
struct bio *bio;
- bool is_read = (iov_iter_rw(iter) == READ);
+ bool is_read = (iov_iter_rw(iter) == READ), is_sync;
loff_t pos = iocb->ki_pos;
blk_qc_t qc = BLK_QC_T_NONE;
int ret;
bio_get(bio); /* extra ref for the completion handler */
dio = container_of(bio, struct blkdev_dio, bio);
- dio->is_sync = is_sync_kiocb(iocb);
+ dio->is_sync = is_sync = is_sync_kiocb(iocb);
if (dio->is_sync)
dio->waiter = current;
else
}
blk_finish_plug(&plug);
- if (!dio->is_sync)
+ if (!is_sync)
return -EIOCBQUEUED;
for (;;) {
unsigned long flags;
while (1) {
+ void *wtag;
+
spin_lock_irqsave(lock, flags);
if (list_empty(list))
break;
spin_unlock_irqrestore(lock, flags);
/*
- * we don't want to call the ordered free functions
- * with the lock held though
+ * We don't want to call the ordered free functions with the
+ * lock held though. Save the work as tag for the trace event,
+ * because the callback could free the structure.
*/
+ wtag = work;
work->ordered_free(work);
- trace_btrfs_all_work_done(work);
+ trace_btrfs_all_work_done(wq->fs_info, wtag);
}
spin_unlock_irqrestore(lock, flags);
}
static void normal_work_helper(struct btrfs_work *work)
{
struct __btrfs_workqueue *wq;
+ void *wtag;
int need_order = 0;
/*
if (work->ordered_func)
need_order = 1;
wq = work->wq;
+ /* Safe for tracepoints in case work gets freed by the callback */
+ wtag = work;
trace_btrfs_work_sched(work);
thresh_exec_hook(wq);
run_ordered_work(wq);
}
if (!need_order)
- trace_btrfs_all_work_done(work);
+ trace_btrfs_all_work_done(wq->fs_info, wtag);
}
void btrfs_init_work(struct btrfs_work *work, btrfs_work_func_t uniq_func,
if (ref && ref->seq &&
btrfs_check_delayed_seq(fs_info, delayed_refs, ref->seq)) {
spin_unlock(&locked_ref->lock);
- btrfs_delayed_ref_unlock(locked_ref);
spin_lock(&delayed_refs->lock);
locked_ref->processing = 0;
delayed_refs->num_heads_ready++;
spin_unlock(&delayed_refs->lock);
+ btrfs_delayed_ref_unlock(locked_ref);
locked_ref = NULL;
cond_resched();
count++;
*/
if (must_insert_reserved)
locked_ref->must_insert_reserved = 1;
+ spin_lock(&delayed_refs->lock);
locked_ref->processing = 0;
+ delayed_refs->num_heads_ready++;
+ spin_unlock(&delayed_refs->lock);
btrfs_debug(fs_info,
"run_delayed_extent_op returned %d",
ret);
spin_unlock(&cluster->refill_lock);
- down_read(&used_bg->data_rwsem);
+ /* We should only have one-level nested. */
+ down_read_nested(&used_bg->data_rwsem, SINGLE_DEPTH_NESTING);
spin_lock(&cluster->refill_lock);
if (used_bg == cluster->block_group)
break;
case S_IFDIR:
inode->i_fop = &btrfs_dir_file_operations;
- if (root == fs_info->tree_root)
- inode->i_op = &btrfs_dir_ro_inode_operations;
- else
- inode->i_op = &btrfs_dir_inode_operations;
+ inode->i_op = &btrfs_dir_inode_operations;
break;
case S_IFLNK:
inode->i_op = &btrfs_symlink_inode_operations;
if (found_type > min_type) {
del_item = 1;
} else {
- if (item_end < new_size)
+ if (item_end < new_size) {
+ /*
+ * With NO_HOLES mode, for the following mapping
+ *
+ * [0-4k][hole][8k-12k]
+ *
+ * if truncating isize down to 6k, it ends up
+ * isize being 8k.
+ */
+ if (btrfs_fs_incompat(root->fs_info, NO_HOLES))
+ last_size = new_size;
break;
+ }
if (found_key.offset >= new_size)
del_item = 1;
else
inode->i_ino = BTRFS_EMPTY_SUBVOL_DIR_OBJECTID;
inode->i_op = &btrfs_dir_ro_inode_operations;
+ inode->i_opflags &= ~IOP_XATTR;
inode->i_fop = &simple_dir_operations;
inode->i_mode = S_IFDIR | S_IRUGO | S_IWUSR | S_IXUGO;
inode->i_mtime = current_time(inode);
write_unlock(&em_tree->lock);
out:
- trace_btrfs_get_extent(root, em);
+ trace_btrfs_get_extent(root, inode, em);
btrfs_free_path(path);
if (trans) {
struct extent_map *em = NULL;
int ret;
- down_read(&BTRFS_I(inode)->dio_sem);
if (type != BTRFS_ORDERED_NOCOW) {
em = create_pinned_em(inode, start, len, orig_start,
block_start, block_len, orig_block_len,
em = ERR_PTR(ret);
}
out:
- up_read(&BTRFS_I(inode)->dio_sem);
return em;
}
* within our reservation, otherwise we need to adjust our inode
* counter appropriately.
*/
- if (dio_data->outstanding_extents) {
+ if (dio_data->outstanding_extents >= num_extents) {
dio_data->outstanding_extents -= num_extents;
} else {
+ /*
+ * If dio write length has been split due to no large enough
+ * contiguous space, we need to compensate our inode counter
+ * appropriately.
+ */
+ u64 num_needed = num_extents - dio_data->outstanding_extents;
+
spin_lock(&BTRFS_I(inode)->lock);
- BTRFS_I(inode)->outstanding_extents += num_extents;
+ BTRFS_I(inode)->outstanding_extents += num_needed;
spin_unlock(&BTRFS_I(inode)->lock);
}
}
dio_data.unsubmitted_oe_range_start = (u64)offset;
dio_data.unsubmitted_oe_range_end = (u64)offset;
current->journal_info = &dio_data;
+ down_read(&BTRFS_I(inode)->dio_sem);
} else if (test_bit(BTRFS_INODE_READDIO_NEED_LOCK,
&BTRFS_I(inode)->runtime_flags)) {
inode_dio_end(inode);
iter, btrfs_get_blocks_direct, NULL,
btrfs_submit_direct, flags);
if (iov_iter_rw(iter) == WRITE) {
+ up_read(&BTRFS_I(inode)->dio_sem);
current->journal_info = NULL;
if (ret < 0 && ret != -EIOCBQUEUED) {
if (dio_data.reserve)
break;
}
+ btrfs_block_rsv_release(fs_info, rsv, -1);
ret = btrfs_block_rsv_migrate(&fs_info->trans_block_rsv,
rsv, min_size, 0);
BUG_ON(ret); /* shouldn't happen */
static const struct inode_operations btrfs_dir_ro_inode_operations = {
.lookup = btrfs_lookup,
.permission = btrfs_permission,
- .get_acl = btrfs_get_acl,
- .set_acl = btrfs_set_acl,
.update_time = btrfs_update_time,
};
*/
#define LOG_INODE_ALL 0
#define LOG_INODE_EXISTS 1
+#define LOG_OTHER_INODE 2
/*
* directory trouble cases
if (S_ISDIR(inode->i_mode) ||
(!test_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
&BTRFS_I(inode)->runtime_flags) &&
- inode_only == LOG_INODE_EXISTS))
+ inode_only >= LOG_INODE_EXISTS))
max_key.type = BTRFS_XATTR_ITEM_KEY;
else
max_key.type = (u8)-1;
return ret;
}
- mutex_lock(&BTRFS_I(inode)->log_mutex);
+ if (inode_only == LOG_OTHER_INODE) {
+ inode_only = LOG_INODE_EXISTS;
+ mutex_lock_nested(&BTRFS_I(inode)->log_mutex,
+ SINGLE_DEPTH_NESTING);
+ } else {
+ mutex_lock(&BTRFS_I(inode)->log_mutex);
+ }
/*
* a brute force approach to making sure we get the most uptodate
* unpin it.
*/
err = btrfs_log_inode(trans, root, other_inode,
- LOG_INODE_EXISTS,
+ LOG_OTHER_INODE,
0, LLONG_MAX, ctx);
iput(other_inode);
if (err)
out:
btrfs_free_path(path);
- if (ret)
- btrfs_warn(fs_info, "btrfs_uuid_tree_iterate failed %d", ret);
- return 0;
+ return ret;
}
dout(" head snapc %p has %d dirty pages\n",
snapc, ci->i_wrbuffer_ref_head);
if (truncate_size)
- *truncate_size = capsnap->truncate_size;
+ *truncate_size = ci->i_truncate_size;
if (truncate_seq)
- *truncate_seq = capsnap->truncate_seq;
+ *truncate_seq = ci->i_truncate_seq;
}
spin_unlock(&ci->i_ceph_lock);
return snapc;
add_wait_queue(&ci->i_cap_wq, &wait);
while (!try_get_cap_refs(ci, need, want, endoff,
- true, &_got, &err))
+ true, &_got, &err)) {
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
+ }
remove_wait_queue(&ci->i_cap_wq, &wait);
struct ceph_mds_client *mdsc =
ceph_sb_to_client(dir->i_sb)->mdsc;
struct ceph_mds_request *req;
- int op, mask, err;
+ int op, err;
+ u32 mask;
if (flags & LOOKUP_RCU)
return -ECHILD;
mask = CEPH_STAT_CAP_INODE | CEPH_CAP_AUTH_SHARED;
if (ceph_security_xattr_wanted(dir))
mask |= CEPH_CAP_XATTR_SHARED;
- req->r_args.getattr.mask = mask;
+ req->r_args.getattr.mask = cpu_to_le32(mask);
err = ceph_mdsc_do_request(mdsc, NULL, req);
switch (err) {
{
struct ceph_frag_tree_split *ls = (struct ceph_frag_tree_split*)l;
struct ceph_frag_tree_split *rs = (struct ceph_frag_tree_split*)r;
- return ceph_frag_compare(ls->frag, rs->frag);
+ return ceph_frag_compare(le32_to_cpu(ls->frag),
+ le32_to_cpu(rs->frag));
}
static bool is_frag_child(u32 f, struct ceph_inode_frag *frag)
struct ceph_mds_reply_info_parsed *info,
u64 features)
{
- if (info->head->op == CEPH_MDS_OP_GETFILELOCK)
+ u32 op = le32_to_cpu(info->head->op);
+
+ if (op == CEPH_MDS_OP_GETFILELOCK)
return parse_reply_info_filelock(p, end, info, features);
- else if (info->head->op == CEPH_MDS_OP_READDIR ||
- info->head->op == CEPH_MDS_OP_LSSNAP)
+ else if (op == CEPH_MDS_OP_READDIR || op == CEPH_MDS_OP_LSSNAP)
return parse_reply_info_dir(p, end, info, features);
- else if (info->head->op == CEPH_MDS_OP_CREATE)
+ else if (op == CEPH_MDS_OP_CREATE)
return parse_reply_info_create(p, end, info, features);
else
return -EIO;
dout("do_request mdsmap err %d\n", err);
goto finish;
}
+ if (mdsc->mdsmap->m_epoch == 0) {
+ dout("do_request no mdsmap, waiting for map\n");
+ list_add(&req->r_wait, &mdsc->waiting_for_map);
+ goto finish;
+ }
if (!(mdsc->fsc->mount_options->flags &
CEPH_MOUNT_OPT_MOUNTWAIT) &&
!ceph_mdsmap_is_cluster_available(mdsc->mdsmap)) {
rc = -ENOMEM;
goto error_exit;
}
+ spin_lock_init(&cifsFile->file_info_lock);
file->private_data = cifsFile;
cifsFile->tlink = cifs_get_tlink(tlink);
tcon = tlink_tcon(tlink);
return mod ? dump_skip(cprm, align - mod) : 1;
}
EXPORT_SYMBOL(dump_align);
+
+/*
+ * Ensures that file size is big enough to contain the current file
+ * postion. This prevents gdb from complaining about a truncated file
+ * if the last "write" to the file was dump_skip.
+ */
+void dump_truncate(struct coredump_params *cprm)
+{
+ struct file *file = cprm->file;
+ loff_t offset;
+
+ if (file->f_op->llseek && file->f_op->llseek != no_llseek) {
+ offset = file->f_op->llseek(file, 0, SEEK_CUR);
+ if (i_size_read(file->f_mapping->host) < offset)
+ do_truncate(file->f_path.dentry, offset, 0, file);
+ }
+}
+EXPORT_SYMBOL(dump_truncate);
pgoff_t index, unsigned long pfn)
{
struct vm_area_struct *vma;
- pte_t *ptep;
- pte_t pte;
+ pte_t pte, *ptep = NULL;
+ pmd_t *pmdp = NULL;
spinlock_t *ptl;
bool changed;
address = pgoff_address(index, vma);
changed = false;
- if (follow_pte(vma->vm_mm, address, &ptep, &ptl))
+ if (follow_pte_pmd(vma->vm_mm, address, &ptep, &pmdp, &ptl))
continue;
- if (pfn != pte_pfn(*ptep))
- goto unlock;
- if (!pte_dirty(*ptep) && !pte_write(*ptep))
- goto unlock;
- flush_cache_page(vma, address, pfn);
- pte = ptep_clear_flush(vma, address, ptep);
- pte = pte_wrprotect(pte);
- pte = pte_mkclean(pte);
- set_pte_at(vma->vm_mm, address, ptep, pte);
- changed = true;
-unlock:
- pte_unmap_unlock(ptep, ptl);
+ if (pmdp) {
+#ifdef CONFIG_FS_DAX_PMD
+ pmd_t pmd;
+
+ if (pfn != pmd_pfn(*pmdp))
+ goto unlock_pmd;
+ if (!pmd_dirty(*pmdp) && !pmd_write(*pmdp))
+ goto unlock_pmd;
+
+ flush_cache_page(vma, address, pfn);
+ pmd = pmdp_huge_clear_flush(vma, address, pmdp);
+ pmd = pmd_wrprotect(pmd);
+ pmd = pmd_mkclean(pmd);
+ set_pmd_at(vma->vm_mm, address, pmdp, pmd);
+ changed = true;
+unlock_pmd:
+ spin_unlock(ptl);
+#endif
+ } else {
+ if (pfn != pte_pfn(*ptep))
+ goto unlock_pte;
+ if (!pte_dirty(*ptep) && !pte_write(*ptep))
+ goto unlock_pte;
+
+ flush_cache_page(vma, address, pfn);
+ pte = ptep_clear_flush(vma, address, ptep);
+ pte = pte_wrprotect(pte);
+ pte = pte_mkclean(pte);
+ set_pte_at(vma->vm_mm, address, ptep, pte);
+ changed = true;
+unlock_pte:
+ pte_unmap_unlock(ptep, ptl);
+ }
if (changed)
mmu_notifier_invalidate_page(vma->vm_mm, address);
}
EXPORT_SYMBOL_GPL(__dax_zero_page_range);
-#ifdef CONFIG_FS_IOMAP
static sector_t dax_iomap_sector(struct iomap *iomap, loff_t pos)
{
return iomap->blkno + (((pos & PAGE_MASK) - iomap->offset) >> 9);
struct blk_dax_ctl dax = { 0 };
ssize_t map_len;
+ if (fatal_signal_pending(current)) {
+ ret = -EINTR;
+ break;
+ }
+
dax.sector = dax_iomap_sector(iomap, pos);
dax.size = (length + offset + PAGE_SIZE - 1) & PAGE_MASK;
map_len = dax_map_atomic(iomap->bdev, &dax);
}
EXPORT_SYMBOL_GPL(dax_iomap_pmd_fault);
#endif /* CONFIG_FS_DAX_PMD */
-#endif /* CONFIG_FS_IOMAP */
}
spin_lock(&dentry->d_lock);
if (!d_unlinked(dentry)) {
- dentry->d_flags |= DCACHE_MOUNTED;
- ret = 0;
+ ret = -EBUSY;
+ if (!d_mountpoint(dentry)) {
+ dentry->d_flags |= DCACHE_MOUNTED;
+ ret = 0;
+ }
}
spin_unlock(&dentry->d_lock);
out:
struct buffer_head *map_bh)
{
const unsigned blkbits = sdio->blkbits;
+ const unsigned i_blkbits = blkbits + sdio->blkfactor;
int ret = 0;
while (sdio->block_in_file < sdio->final_block_in_request) {
clean_bdev_aliases(
map_bh->b_bdev,
map_bh->b_blocknr,
- map_bh->b_size >> blkbits);
+ map_bh->b_size >> i_blkbits);
}
if (!sdio->blkfactor)
config EXT2_FS
tristate "Second extended fs support"
- select FS_IOMAP if FS_DAX
help
Ext2 is a standard Linux file system for hard disks.
select CRC16
select CRYPTO
select CRYPTO_CRC32C
- select FS_IOMAP if FS_DAX
help
This is the next generation of the ext3 filesystem.
}
sector = SECTOR_FROM_BLOCK(blkstart);
- if (sector & (bdev_zone_size(bdev) - 1) ||
- nr_sects != bdev_zone_size(bdev)) {
+ if (sector & (bdev_zone_sectors(bdev) - 1) ||
+ nr_sects != bdev_zone_sectors(bdev)) {
f2fs_msg(sbi->sb, KERN_INFO,
"(%d) %s: Unaligned discard attempted (block %x + %x)",
devi, sbi->s_ndevs ? FDEV(devi).path: "",
return 0;
if (sbi->blocks_per_blkz && sbi->blocks_per_blkz !=
- SECTOR_TO_BLOCK(bdev_zone_size(bdev)))
+ SECTOR_TO_BLOCK(bdev_zone_sectors(bdev)))
return -EINVAL;
- sbi->blocks_per_blkz = SECTOR_TO_BLOCK(bdev_zone_size(bdev));
+ sbi->blocks_per_blkz = SECTOR_TO_BLOCK(bdev_zone_sectors(bdev));
if (sbi->log_blocks_per_blkz && sbi->log_blocks_per_blkz !=
__ilog2_u32(sbi->blocks_per_blkz))
return -EINVAL;
sbi->log_blocks_per_blkz = __ilog2_u32(sbi->blocks_per_blkz);
FDEV(devi).nr_blkz = SECTOR_TO_BLOCK(nr_sectors) >>
sbi->log_blocks_per_blkz;
- if (nr_sectors & (bdev_zone_size(bdev) - 1))
+ if (nr_sectors & (bdev_zone_sectors(bdev) - 1))
FDEV(devi).nr_blkz++;
FDEV(devi).blkz_type = kmalloc(FDEV(devi).nr_blkz, GFP_KERNEL);
hlist_for_each_entry(object, &cookie->backing_objects, cookie_link) {
if (invalidate)
set_bit(FSCACHE_OBJECT_RETIRED, &object->flags);
+ clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags);
fscache_raise_event(object, FSCACHE_OBJECT_EV_KILL);
}
} else {
wait_on_atomic_t(&cookie->n_active, fscache_wait_atomic_t,
TASK_UNINTERRUPTIBLE);
+ /* Make sure any pending writes are cancelled. */
+ if (cookie->def->type != FSCACHE_COOKIE_TYPE_INDEX)
+ fscache_invalidate_writes(cookie);
+
/* Reset the cookie state if it wasn't relinquished */
if (!test_bit(FSCACHE_COOKIE_RELINQUISHED, &cookie->flags)) {
atomic_inc(&cookie->n_active);
cookie->flags = 1 << FSCACHE_COOKIE_ENABLED;
spin_lock_init(&cookie->lock);
+ spin_lock_init(&cookie->stores_lock);
INIT_HLIST_HEAD(&cookie->backing_objects);
/* check the netfs type is not already present */
static const struct fscache_state *fscache_object_available(struct fscache_object *, int);
static const struct fscache_state *fscache_parent_ready(struct fscache_object *, int);
static const struct fscache_state *fscache_update_object(struct fscache_object *, int);
+static const struct fscache_state *fscache_object_dead(struct fscache_object *, int);
#define __STATE_NAME(n) fscache_osm_##n
#define STATE(n) (&__STATE_NAME(n))
static WORK_STATE(KILL_OBJECT, "KILL", fscache_kill_object);
static WORK_STATE(KILL_DEPENDENTS, "KDEP", fscache_kill_dependents);
static WORK_STATE(DROP_OBJECT, "DROP", fscache_drop_object);
-static WORK_STATE(OBJECT_DEAD, "DEAD", (void*)2UL);
+static WORK_STATE(OBJECT_DEAD, "DEAD", fscache_object_dead);
static WAIT_STATE(WAIT_FOR_INIT, "?INI",
TRANSIT_TO(INIT_OBJECT, 1 << FSCACHE_OBJECT_EV_NEW_CHILD));
event = -1;
if (new_state == NO_TRANSIT) {
_debug("{OBJ%x} %s notrans", object->debug_id, state->name);
+ if (unlikely(state == STATE(OBJECT_DEAD))) {
+ _leave(" [dead]");
+ return;
+ }
fscache_enqueue_object(object);
event_mask = object->oob_event_mask;
goto unmask_events;
object->state = state = new_state;
if (state->work) {
- if (unlikely(state->work == ((void *)2UL))) {
+ if (unlikely(state == STATE(OBJECT_DEAD))) {
_leave(" [dead]");
return;
}
fscache_mark_object_dead(object);
object->oob_event_mask = 0;
+ if (test_bit(FSCACHE_OBJECT_RETIRED, &object->flags)) {
+ /* Reject any new read/write ops and abort any that are pending. */
+ clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags);
+ fscache_cancel_all_ops(object);
+ }
+
if (list_empty(&object->dependents) &&
object->n_ops == 0 &&
object->n_children == 0)
}
}
EXPORT_SYMBOL(fscache_object_mark_killed);
+
+/*
+ * The object is dead. We can get here if an object gets queued by an event
+ * that would lead to its death (such as EV_KILL) when the dispatcher is
+ * already running (and so can be requeued) but hasn't yet cleared the event
+ * mask.
+ */
+static const struct fscache_state *fscache_object_dead(struct fscache_object *object,
+ int event)
+{
+ if (!test_and_set_bit(FSCACHE_OBJECT_RUN_AFTER_DEAD,
+ &object->flags))
+ return NO_TRANSIT;
+
+ WARN(true, "FS-Cache object redispatched after death");
+ return NO_TRANSIT;
+}
struct fuse_req *req;
req = list_entry(head->next, struct fuse_req, list);
req->out.h.error = -ECONNABORTED;
- clear_bit(FR_PENDING, &req->flags);
clear_bit(FR_SENT, &req->flags);
list_del_init(&req->list);
request_end(fc, req);
spin_lock(&fiq->waitq.lock);
fiq->connected = 0;
list_splice_init(&fiq->pending, &to_end2);
+ list_for_each_entry(req, &to_end2, list)
+ clear_bit(FR_PENDING, &req->flags);
while (forget_pending(fiq))
kfree(dequeue_forget(fiq, 1, NULL));
wake_up_all_locked(&fiq->waitq);
if (sec || nsec) {
struct timespec64 ts = {
sec,
- max_t(u32, nsec, NSEC_PER_SEC - 1)
+ min_t(u32, nsec, NSEC_PER_SEC - 1)
};
return get_jiffies_64() + timespec64_to_jiffies(&ts);
BUG_ON(pos + len > iomap->offset + iomap->length);
+ if (fatal_signal_pending(current))
+ return -EINTR;
+
page = grab_cache_page_write_begin(inode->i_mapping, index, flags);
if (!page)
return -ENOMEM;
struct inode *root;
struct qstr d_name = QSTR_INIT(name, strlen(name));
- s = sget(fs_type, NULL, set_anon_super, MS_NOUSER, NULL);
+ s = sget_userns(fs_type, NULL, set_anon_super, MS_KERNMOUNT|MS_NOUSER,
+ &init_user_ns, NULL);
if (IS_ERR(s))
return ERR_CAST(s);
return NULL;
}
-static struct mountpoint *new_mountpoint(struct dentry *dentry)
+static struct mountpoint *get_mountpoint(struct dentry *dentry)
{
- struct hlist_head *chain = mp_hash(dentry);
- struct mountpoint *mp;
+ struct mountpoint *mp, *new = NULL;
int ret;
- mp = kmalloc(sizeof(struct mountpoint), GFP_KERNEL);
- if (!mp)
+ if (d_mountpoint(dentry)) {
+mountpoint:
+ read_seqlock_excl(&mount_lock);
+ mp = lookup_mountpoint(dentry);
+ read_sequnlock_excl(&mount_lock);
+ if (mp)
+ goto done;
+ }
+
+ if (!new)
+ new = kmalloc(sizeof(struct mountpoint), GFP_KERNEL);
+ if (!new)
return ERR_PTR(-ENOMEM);
+
+ /* Exactly one processes may set d_mounted */
ret = d_set_mounted(dentry);
- if (ret) {
- kfree(mp);
- return ERR_PTR(ret);
- }
- mp->m_dentry = dentry;
- mp->m_count = 1;
- hlist_add_head(&mp->m_hash, chain);
- INIT_HLIST_HEAD(&mp->m_list);
+ /* Someone else set d_mounted? */
+ if (ret == -EBUSY)
+ goto mountpoint;
+
+ /* The dentry is not available as a mountpoint? */
+ mp = ERR_PTR(ret);
+ if (ret)
+ goto done;
+
+ /* Add the new mountpoint to the hash table */
+ read_seqlock_excl(&mount_lock);
+ new->m_dentry = dentry;
+ new->m_count = 1;
+ hlist_add_head(&new->m_hash, mp_hash(dentry));
+ INIT_HLIST_HEAD(&new->m_list);
+ read_sequnlock_excl(&mount_lock);
+
+ mp = new;
+ new = NULL;
+done:
+ kfree(new);
return mp;
}
struct mount *mnt;
namespace_lock();
+ lock_mount_hash();
mp = lookup_mountpoint(dentry);
if (IS_ERR_OR_NULL(mp))
goto out_unlock;
- lock_mount_hash();
event++;
while (!hlist_empty(&mp->m_list)) {
mnt = hlist_entry(mp->m_list.first, struct mount, mnt_mp_list);
}
else umount_tree(mnt, UMOUNT_CONNECTED);
}
- unlock_mount_hash();
put_mountpoint(mp);
out_unlock:
+ unlock_mount_hash();
namespace_unlock();
}
namespace_lock();
mnt = lookup_mnt(path);
if (likely(!mnt)) {
- struct mountpoint *mp = lookup_mountpoint(dentry);
- if (!mp)
- mp = new_mountpoint(dentry);
+ struct mountpoint *mp = get_mountpoint(dentry);
if (IS_ERR(mp)) {
namespace_unlock();
inode_unlock(dentry->d_inode);
static void unlock_mount(struct mountpoint *where)
{
struct dentry *dentry = where->m_dentry;
+
+ read_seqlock_excl(&mount_lock);
put_mountpoint(where);
+ read_sequnlock_excl(&mount_lock);
+
namespace_unlock();
inode_unlock(dentry->d_inode);
}
touch_mnt_namespace(current->nsproxy->mnt_ns);
/* A moved mount should not expire automatically */
list_del_init(&new_mnt->mnt_expire);
+ put_mountpoint(root_mp);
unlock_mount_hash();
chroot_fs_refs(&root, &new);
- put_mountpoint(root_mp);
error = 0;
out4:
unlock_mount(old_mp);
#include <linux/mm.h>
#include <linux/delay.h>
#include <linux/errno.h>
-#include <linux/file.h>
#include <linux/string.h>
#include <linux/ratelimit.h>
#include <linux/printk.h>
return nfs4_call_sync_sequence(clnt, server, msg, args, res);
}
-static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo)
+static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo,
+ unsigned long timestamp)
{
struct nfs_inode *nfsi = NFS_I(dir);
NFS_INO_INVALID_ACL;
}
dir->i_version = cinfo->after;
+ nfsi->read_cache_jiffies = timestamp;
nfsi->attr_gencount = nfs_inc_attr_generation_counter();
nfs_fscache_invalidate(dir);
spin_unlock(&dir->i_lock);
nfs_fattr_map_and_free_names(server, &data->f_attr);
if (o_arg->open_flags & O_CREAT) {
- update_changeattr(dir, &o_res->cinfo);
if (o_arg->open_flags & O_EXCL)
data->file_created = 1;
else if (o_res->cinfo.before != o_res->cinfo.after)
data->file_created = 1;
+ if (data->file_created || dir->i_version != o_res->cinfo.after)
+ update_changeattr(dir, &o_res->cinfo,
+ o_res->f_attr->time_start);
}
if ((o_res->rflags & NFS4_OPEN_RESULT_LOCKTYPE_POSIX) == 0)
server->caps &= ~NFS_CAP_POSIX_LOCK;
sattr->ia_valid |= ATTR_MTIME;
/* Except MODE, it seems harmless of setting twice. */
- if ((attrset[1] & FATTR4_WORD1_MODE))
+ if (opendata->o_arg.createmode != NFS4_CREATE_EXCLUSIVE &&
+ attrset[1] & FATTR4_WORD1_MODE)
sattr->ia_valid &= ~ATTR_MODE;
if (attrset[2] & FATTR4_WORD2_SECURITY_LABEL)
.rpc_argp = &args,
.rpc_resp = &res,
};
+ unsigned long timestamp = jiffies;
int status;
status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 1);
if (status == 0)
- update_changeattr(dir, &res.cinfo);
+ update_changeattr(dir, &res.cinfo, timestamp);
return status;
}
if (nfs4_async_handle_error(task, res->server, NULL,
&data->timeout) == -EAGAIN)
return 0;
- update_changeattr(dir, &res->cinfo);
+ if (task->tk_status == 0)
+ update_changeattr(dir, &res->cinfo, res->dir_attr->time_start);
return 1;
}
if (nfs4_async_handle_error(task, res->server, NULL, &data->timeout) == -EAGAIN)
return 0;
- update_changeattr(old_dir, &res->old_cinfo);
- update_changeattr(new_dir, &res->new_cinfo);
+ if (task->tk_status == 0) {
+ update_changeattr(old_dir, &res->old_cinfo, res->old_fattr->time_start);
+ if (new_dir != old_dir)
+ update_changeattr(new_dir, &res->new_cinfo, res->new_fattr->time_start);
+ }
return 1;
}
status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
if (!status) {
- update_changeattr(dir, &res.cinfo);
+ update_changeattr(dir, &res.cinfo, res.fattr->time_start);
status = nfs_post_op_update_inode(inode, res.fattr);
if (!status)
nfs_setsecurity(inode, res.fattr, res.label);
int status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &data->msg,
&data->arg.seq_args, &data->res.seq_res, 1);
if (status == 0) {
- update_changeattr(dir, &data->res.dir_cinfo);
+ update_changeattr(dir, &data->res.dir_cinfo,
+ data->res.fattr->time_start);
status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, data->res.label);
}
return status;
p->server = server;
atomic_inc(&lsp->ls_count);
p->ctx = get_nfs_open_context(ctx);
- get_file(fl->fl_file);
memcpy(&p->fl, fl, sizeof(p->fl));
return p;
out_free_seqid:
nfs_free_seqid(data->arg.lock_seqid);
nfs4_put_lock_state(data->lsp);
put_nfs_open_context(data->ctx);
- fput(data->fl.fl_file);
kfree(data);
dprintk("%s: done!\n", __func__);
}
goto out;
}
+ nfs4_sequence_free_slot(&lgp->res.seq_res);
err = nfs4_handle_exception(server, nfs4err, exception);
if (!status) {
if (exception->retry)
case -NFS4ERR_BADXDR:
case -NFS4ERR_RESOURCE:
case -NFS4ERR_NOFILEHANDLE:
+ case -NFS4ERR_MOVED:
/* Non-seqid mutating errors */
return;
};
break;
case -NFS4ERR_STALE_CLIENTID:
set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
- nfs4_state_clear_reclaim_reboot(clp);
nfs4_state_start_reclaim_reboot(clp);
break;
case -NFS4ERR_EXPIRED:
send = pnfs_prepare_layoutreturn(lo, &stateid, NULL);
spin_unlock(&ino->i_lock);
- pnfs_free_lseg_list(&tmp_list);
if (send)
status = pnfs_send_layoutreturn(lo, &stateid, IOMODE_ANY, true);
out_put_layout_hdr:
+ pnfs_free_lseg_list(&tmp_list);
pnfs_put_layout_hdr(lo);
out:
dprintk("<-- %s status: %d\n", __func__, status);
struct nfs4_layout_stateid *ls;
struct nfs4_stid *stp;
- stp = nfs4_alloc_stid(cstate->clp, nfs4_layout_stateid_cache);
+ stp = nfs4_alloc_stid(cstate->clp, nfs4_layout_stateid_cache,
+ nfsd4_free_layout_stateid);
if (!stp)
return NULL;
- stp->sc_free = nfsd4_free_layout_stateid;
+
get_nfs4_file(fp);
stp->sc_file = fp;
return co;
}
-struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl,
- struct kmem_cache *slab)
+struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab,
+ void (*sc_free)(struct nfs4_stid *))
{
struct nfs4_stid *stid;
int new_id;
idr_preload_end();
if (new_id < 0)
goto out_free;
+
+ stid->sc_free = sc_free;
stid->sc_client = cl;
stid->sc_stateid.si_opaque.so_id = new_id;
stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid;
static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp)
{
struct nfs4_stid *stid;
- struct nfs4_ol_stateid *stp;
- stid = nfs4_alloc_stid(clp, stateid_slab);
+ stid = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_ol_stateid);
if (!stid)
return NULL;
- stp = openlockstateid(stid);
- stp->st_stid.sc_free = nfs4_free_ol_stateid;
- return stp;
+ return openlockstateid(stid);
}
static void nfs4_free_deleg(struct nfs4_stid *stid)
goto out_dec;
if (delegation_blocked(¤t_fh->fh_handle))
goto out_dec;
- dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab));
+ dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab, nfs4_free_deleg));
if (dp == NULL)
goto out_dec;
- dp->dl_stid.sc_free = nfs4_free_deleg;
/*
* delegation seqid's are never incremented. The 4.1 special
* meaning of seqid 0 isn't meaningful, really, but let's avoid
stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner);
get_nfs4_file(fp);
stp->st_stid.sc_file = fp;
- stp->st_stid.sc_free = nfs4_free_lock_stateid;
stp->st_access_bmap = 0;
stp->st_deny_bmap = open_stp->st_deny_bmap;
stp->st_openstp = open_stp;
lst = find_lock_stateid(lo, fi);
if (lst == NULL) {
spin_unlock(&clp->cl_lock);
- ns = nfs4_alloc_stid(clp, stateid_slab);
+ ns = nfs4_alloc_stid(clp, stateid_slab, nfs4_free_lock_stateid);
if (ns == NULL)
return NULL;
p++; /* to be backfilled later */
if (bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) {
- u32 *supp = nfsd_suppattrs[minorversion];
+ u32 supp[3];
+
+ memcpy(supp, nfsd_suppattrs[minorversion], sizeof(supp));
if (!IS_POSIXACL(dentry->d_inode))
supp[0] &= ~FATTR4_WORD0_ACL;
__be32 nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate,
stateid_t *stateid, unsigned char typemask,
struct nfs4_stid **s, struct nfsd_net *nn);
-struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl,
- struct kmem_cache *slab);
+struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab,
+ void (*sc_free)(struct nfs4_stid *));
void nfs4_unhash_stid(struct nfs4_stid *s);
void nfs4_put_stid(struct nfs4_stid *s);
void nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid);
}
}
-static __be32
-nfsd_get_write_access(struct svc_rqst *rqstp, struct svc_fh *fhp,
- struct iattr *iap)
-{
- struct inode *inode = d_inode(fhp->fh_dentry);
- int host_err;
-
- if (iap->ia_size < inode->i_size) {
- __be32 err;
-
- err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry,
- NFSD_MAY_TRUNC | NFSD_MAY_OWNER_OVERRIDE);
- if (err)
- return err;
- }
-
- host_err = get_write_access(inode);
- if (host_err)
- goto out_nfserrno;
-
- host_err = locks_verify_truncate(inode, NULL, iap->ia_size);
- if (host_err)
- goto out_put_write_access;
- return 0;
-
-out_put_write_access:
- put_write_access(inode);
-out_nfserrno:
- return nfserrno(host_err);
-}
-
/*
* Set various file attributes. After this call fhp needs an fh_put.
*/
__be32 err;
int host_err;
bool get_write_count;
- int size_change = 0;
if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE))
accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE;
/* Get inode */
err = fh_verify(rqstp, fhp, ftype, accmode);
if (err)
- goto out;
+ return err;
if (get_write_count) {
host_err = fh_want_write(fhp);
if (host_err)
- return nfserrno(host_err);
+ goto out_host_err;
}
dentry = fhp->fh_dentry;
iap->ia_valid &= ~ATTR_MODE;
if (!iap->ia_valid)
- goto out;
+ return 0;
nfsd_sanitize_attrs(inode, iap);
+ if (check_guard && guardtime != inode->i_ctime.tv_sec)
+ return nfserr_notsync;
+
/*
* The size case is special, it changes the file in addition to the
- * attributes.
+ * attributes, and file systems don't expect it to be mixed with
+ * "random" attribute changes. We thus split out the size change
+ * into a separate call for vfs_truncate, and do the rest as a
+ * a separate setattr call.
*/
if (iap->ia_valid & ATTR_SIZE) {
- err = nfsd_get_write_access(rqstp, fhp, iap);
- if (err)
- goto out;
- size_change = 1;
+ struct path path = {
+ .mnt = fhp->fh_export->ex_path.mnt,
+ .dentry = dentry,
+ };
+ bool implicit_mtime = false;
/*
- * RFC5661, Section 18.30.4:
- * Changing the size of a file with SETATTR indirectly
- * changes the time_modify and change attributes.
- *
- * (and similar for the older RFCs)
+ * vfs_truncate implicity updates the mtime IFF the file size
+ * actually changes. Avoid the additional seattr call below if
+ * the only other attribute that the client sends is the mtime.
*/
- if (iap->ia_size != i_size_read(inode))
- iap->ia_valid |= ATTR_MTIME;
- }
+ if (iap->ia_size != i_size_read(inode) &&
+ ((iap->ia_valid & ~(ATTR_SIZE | ATTR_MTIME)) == 0))
+ implicit_mtime = true;
- iap->ia_valid |= ATTR_CTIME;
+ host_err = vfs_truncate(&path, iap->ia_size);
+ if (host_err)
+ goto out_host_err;
- if (check_guard && guardtime != inode->i_ctime.tv_sec) {
- err = nfserr_notsync;
- goto out_put_write_access;
+ iap->ia_valid &= ~ATTR_SIZE;
+ if (implicit_mtime)
+ iap->ia_valid &= ~ATTR_MTIME;
+ if (!iap->ia_valid)
+ goto done;
}
+ iap->ia_valid |= ATTR_CTIME;
+
fh_lock(fhp);
host_err = notify_change(dentry, iap, NULL);
fh_unlock(fhp);
- err = nfserrno(host_err);
+ if (host_err)
+ goto out_host_err;
-out_put_write_access:
- if (size_change)
- put_write_access(inode);
- if (!err)
- err = nfserrno(commit_metadata(fhp));
-out:
- return err;
+done:
+ host_err = commit_metadata(fhp);
+out_host_err:
+ return nfserrno(host_err);
}
#if defined(CONFIG_NFSD_V4)
mlog(ML_BASTS, "lockres %s, level %d => %d\n", lockres->l_name,
lockres->l_level, new_level);
+ /*
+ * On DLM_LKF_VALBLK, fsdlm behaves differently with o2cb. It always
+ * expects DLM_LKF_VALBLK being set if the LKB has LVB, so that
+ * we can recover correctly from node failure. Otherwise, we may get
+ * invalid LVB in LKB, but without DLM_SBF_VALNOTVALIDÂ being set.
+ */
+ if (!ocfs2_is_o2cb_active() &&
+ lockres->l_ops->flags & LOCK_TYPE_USES_LVB)
+ lvb = 1;
+
if (lvb)
dlm_flags |= DLM_LKF_VALBLK;
*/
static struct ocfs2_stack_plugin *active_stack;
+inline int ocfs2_is_o2cb_active(void)
+{
+ return !strcmp(active_stack->sp_name, OCFS2_STACK_PLUGIN_O2CB);
+}
+EXPORT_SYMBOL_GPL(ocfs2_is_o2cb_active);
+
static struct ocfs2_stack_plugin *ocfs2_stack_lookup(const char *name)
{
struct ocfs2_stack_plugin *p;
int ocfs2_stack_glue_register(struct ocfs2_stack_plugin *plugin);
void ocfs2_stack_glue_unregister(struct ocfs2_stack_plugin *plugin);
+/* In ocfs2_downconvert_lock(), we need to know which stack we are using */
+int ocfs2_is_o2cb_active(void);
+
extern struct kset *ocfs2_kset;
#endif /* STACKGLUE_H */
static int ovl_lookup_layer(struct dentry *base, struct ovl_lookup_data *d,
struct dentry **ret)
{
- const char *s = d->name.name;
+ /* Counting down from the end, since the prefix can change */
+ size_t rem = d->name.len - 1;
struct dentry *dentry = NULL;
int err;
- if (*s != '/')
+ if (d->name.name[0] != '/')
return ovl_lookup_single(base, d, d->name.name, d->name.len,
0, "", ret);
- while (*s++ == '/' && !IS_ERR_OR_NULL(base) && d_can_lookup(base)) {
+ while (!IS_ERR_OR_NULL(base) && d_can_lookup(base)) {
+ const char *s = d->name.name + d->name.len - rem;
const char *next = strchrnul(s, '/');
- size_t slen = strlen(s);
+ size_t thislen = next - s;
+ bool end = !next[0];
- if (WARN_ON(slen > d->name.len) ||
- WARN_ON(strcmp(d->name.name + d->name.len - slen, s)))
+ /* Verify we did not go off the rails */
+ if (WARN_ON(s[-1] != '/'))
return -EIO;
- err = ovl_lookup_single(base, d, s, next - s,
- d->name.len - slen, next, &base);
+ err = ovl_lookup_single(base, d, s, thislen,
+ d->name.len - rem, next, &base);
dput(dentry);
if (err)
return err;
dentry = base;
- s = next;
+ if (end)
+ break;
+
+ rem -= thislen + 1;
+
+ if (WARN_ON(rem >= d->name.len))
+ return -EIO;
}
*ret = dentry;
return 0;
int error;
if (type == ACL_TYPE_ACCESS) {
- error = posix_acl_equiv_mode(acl, &inode->i_mode);
- if (error < 0)
- return 0;
- if (error == 0)
- acl = NULL;
+ error = posix_acl_update_mode(inode,
+ &inode->i_mode, &acl);
+ if (error)
+ return error;
}
inode->i_ctime = current_time(inode);
iter.tgid += 1, iter = next_tgid(ns, iter)) {
char name[PROC_NUMBUF];
int len;
+
+ cond_resched();
if (!has_pid_permissions(ns, iter.task, 2))
continue;
ctl_dir = container_of(head, struct ctl_dir, header);
if (!dir_emit_dots(file, ctx))
- return 0;
+ goto out;
pos = 2;
break;
}
}
+out:
sysctl_head_finish(head);
return 0;
}
#include <linux/highmem.h>
#include <linux/pagemap.h>
#include <linux/uaccess.h>
+#include <linux/major.h>
#include "internal.h"
static struct kmem_cache *romfs_inode_cachep;
static int romfs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
struct super_block *sb = dentry->d_sb;
- u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
+ u64 id = 0;
+
+ /* When calling huge_encode_dev(),
+ * use sb->s_bdev->bd_dev when,
+ * - CONFIG_ROMFS_ON_BLOCK defined
+ * use sb->s_dev when,
+ * - CONFIG_ROMFS_ON_BLOCK undefined and
+ * - CONFIG_ROMFS_ON_MTD defined
+ * leave id as 0 when,
+ * - CONFIG_ROMFS_ON_BLOCK undefined and
+ * - CONFIG_ROMFS_ON_MTD undefined
+ */
+ if (sb->s_bdev)
+ id = huge_encode_dev(sb->s_bdev->bd_dev);
+ else if (sb->s_dev)
+ id = huge_encode_dev(sb->s_dev);
buf->f_type = ROMFS_MAGIC;
buf->f_namelen = ROMFS_MAXFN;
sb->s_flags |= MS_RDONLY | MS_NOATIME;
sb->s_op = &romfs_super_ops;
+#ifdef CONFIG_ROMFS_ON_MTD
+ /* Use same dev ID from the underlying mtdblock device */
+ if (sb->s_mtd)
+ sb->s_dev = MKDEV(MTD_BLOCK_MAJOR, sb->s_mtd->index);
+#endif
/* read the image superblock and check it */
rsb = kmalloc(512, GFP_KERNEL);
if (!rsb)
config UBIFS_FS_ENCRYPTION
bool "UBIFS Encryption"
- depends on UBIFS_FS
+ depends on UBIFS_FS && BLOCK
select FS_ENCRYPTION
default n
help
dbg_gen("dent '%pd', mode %#hx in dir ino %lu",
dentry, mode, dir->i_ino);
- if (ubifs_crypt_is_encrypted(dir)) {
- err = fscrypt_get_encryption_info(dir);
- if (err)
- return err;
-
- if (!fscrypt_has_encryption_key(dir)) {
- return -EPERM;
- }
- }
-
err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm);
if (err)
return err;
ubifs_assert(inode_is_locked(dir));
ubifs_assert(inode_is_locked(inode));
- if (ubifs_crypt_is_encrypted(dir)) {
- if (!fscrypt_has_permitted_context(dir, inode))
- return -EPERM;
-
- err = fscrypt_get_encryption_info(inode);
- if (err)
- return err;
-
- if (!fscrypt_has_encryption_key(inode))
- return -EPERM;
- }
+ if (ubifs_crypt_is_encrypted(dir) &&
+ !fscrypt_has_permitted_context(dir, inode))
+ return -EPERM;
err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm);
if (err)
if (err)
return err;
- if (ubifs_crypt_is_encrypted(dir)) {
- err = fscrypt_get_encryption_info(dir);
- if (err)
- goto out_budg;
-
- if (!fscrypt_has_encryption_key(dir)) {
- err = -EPERM;
- goto out_budg;
- }
- }
-
err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm);
if (err)
goto out_budg;
return err;
}
- if (ubifs_crypt_is_encrypted(dir)) {
- err = fscrypt_get_encryption_info(dir);
- if (err)
- goto out_budg;
-
- if (!fscrypt_has_encryption_key(dir)) {
- err = -EPERM;
- goto out_budg;
- }
- }
-
err = fscrypt_setup_filename(dir, &dentry->d_name, 0, &nm);
if (err)
goto out_budg;
goto out_inode;
}
- err = fscrypt_get_encryption_info(inode);
- if (err) {
- kfree(sd);
- goto out_inode;
- }
-
- if (!fscrypt_has_encryption_key(inode)) {
- kfree(sd);
- err = -EPERM;
- goto out_inode;
- }
-
ostr.name = sd->encrypted_path;
ostr.len = disk_link.len;
case FS_IOC32_SETFLAGS:
cmd = FS_IOC_SETFLAGS;
break;
+ case FS_IOC_SET_ENCRYPTION_POLICY:
+ case FS_IOC_GET_ENCRYPTION_POLICY:
+ break;
default:
return -ENOIOCTLCMD;
}
} else {
data->compr_size = 0;
+ out_len = compr_len;
}
dlen = UBIFS_DATA_NODE_SZ + out_len;
dn->compr_type = cpu_to_le16(compr_type);
dn->size = cpu_to_le32(*new_len);
*new_len = UBIFS_DATA_NODE_SZ + out_len;
+ err = 0;
out:
kfree(buf);
return err;
#include <linux/slab.h>
#include "ubifs.h"
+static int try_read_node(const struct ubifs_info *c, void *buf, int type,
+ int len, int lnum, int offs);
+static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key,
+ struct ubifs_zbranch *zbr, void *node);
+
/*
* Returned codes of 'matches_name()' and 'fallible_matches_name()' functions.
* @NAME_LESS: name corresponding to the first argument is less than second
return 0;
}
- err = ubifs_tnc_read_node(c, zbr, node);
+ if (c->replaying) {
+ err = fallible_read_node(c, &zbr->key, zbr, node);
+ /*
+ * When the node was not found, return -ENOENT, 0 otherwise.
+ * Negative return codes stay as-is.
+ */
+ if (err == 0)
+ err = -ENOENT;
+ else if (err == 1)
+ err = 0;
+ } else {
+ err = ubifs_tnc_read_node(c, zbr, node);
+ }
if (err)
return err;
if (fname_len(nm) > 0) {
if (err) {
/* Handle collisions */
- err = resolve_collision(c, key, &znode, &n, nm);
+ if (c->replaying)
+ err = fallible_resolve_collision(c, key, &znode, &n,
+ nm, 0);
+ else
+ err = resolve_collision(c, key, &znode, &n, nm);
dbg_tnc("rc returned %d, znode %p, n %d",
err, znode, n);
if (unlikely(err < 0))
struct uffd_msg msg;
wait_queue_t wq;
struct userfaultfd_ctx *ctx;
+ bool waken;
};
struct userfaultfd_wake_range {
if (len && (start > uwq->msg.arg.pagefault.address ||
start + len <= uwq->msg.arg.pagefault.address))
goto out;
+ WRITE_ONCE(uwq->waken, true);
+ /*
+ * The implicit smp_mb__before_spinlock in try_to_wake_up()
+ * renders uwq->waken visible to other CPUs before the task is
+ * waken.
+ */
ret = wake_up_state(wq->private, mode);
if (ret)
/*
struct userfaultfd_wait_queue uwq;
int ret;
bool must_wait, return_to_userland;
+ long blocking_state;
BUG_ON(!rwsem_is_locked(&mm->mmap_sem));
uwq.wq.private = current;
uwq.msg = userfault_msg(vmf->address, vmf->flags, reason);
uwq.ctx = ctx;
+ uwq.waken = false;
return_to_userland =
(vmf->flags & (FAULT_FLAG_USER|FAULT_FLAG_KILLABLE)) ==
(FAULT_FLAG_USER|FAULT_FLAG_KILLABLE);
+ blocking_state = return_to_userland ? TASK_INTERRUPTIBLE :
+ TASK_KILLABLE;
spin_lock(&ctx->fault_pending_wqh.lock);
/*
* following the spin_unlock to happen before the list_add in
* __add_wait_queue.
*/
- set_current_state(return_to_userland ? TASK_INTERRUPTIBLE :
- TASK_KILLABLE);
+ set_current_state(blocking_state);
spin_unlock(&ctx->fault_pending_wqh.lock);
must_wait = userfaultfd_must_wait(ctx, vmf->address, vmf->flags,
wake_up_poll(&ctx->fd_wqh, POLLIN);
schedule();
ret |= VM_FAULT_MAJOR;
+
+ /*
+ * False wakeups can orginate even from rwsem before
+ * up_read() however userfaults will wait either for a
+ * targeted wakeup on the specific uwq waitqueue from
+ * wake_userfault() or for signals or for uffd
+ * release.
+ */
+ while (!READ_ONCE(uwq.waken)) {
+ /*
+ * This needs the full smp_store_mb()
+ * guarantee as the state write must be
+ * visible to other CPUs before reading
+ * uwq.waken from other CPUs.
+ */
+ set_current_state(blocking_state);
+ if (READ_ONCE(uwq.waken) ||
+ READ_ONCE(ctx->released) ||
+ (return_to_userland ? signal_pending(current) :
+ fatal_signal_pending(current)))
+ break;
+ schedule();
+ }
}
__set_current_state(TASK_RUNNING);
#include "xfs_rmap_btree.h"
#include "xfs_btree.h"
#include "xfs_refcount_btree.h"
+#include "xfs_ialloc_btree.h"
/*
* Per-AG Block Reservations
struct xfs_mount *mp = pag->pag_mount;
struct xfs_ag_resv *resv;
int error;
+ xfs_extlen_t reserved;
- resv = xfs_perag_resv(pag, type);
if (used > ask)
ask = used;
- resv->ar_asked = ask;
- resv->ar_reserved = resv->ar_orig_reserved = ask - used;
- mp->m_ag_max_usable -= ask;
+ reserved = ask - used;
- trace_xfs_ag_resv_init(pag, type, ask);
-
- error = xfs_mod_fdblocks(mp, -(int64_t)resv->ar_reserved, true);
- if (error)
+ error = xfs_mod_fdblocks(mp, -(int64_t)reserved, true);
+ if (error) {
trace_xfs_ag_resv_init_error(pag->pag_mount, pag->pag_agno,
error, _RET_IP_);
+ xfs_warn(mp,
+"Per-AG reservation for AG %u failed. Filesystem may run out of space.",
+ pag->pag_agno);
+ return error;
+ }
- return error;
+ mp->m_ag_max_usable -= ask;
+
+ resv = xfs_perag_resv(pag, type);
+ resv->ar_asked = ask;
+ resv->ar_reserved = resv->ar_orig_reserved = reserved;
+
+ trace_xfs_ag_resv_init(pag, type, ask);
+ return 0;
}
/* Create a per-AG block reservation. */
xfs_ag_resv_init(
struct xfs_perag *pag)
{
+ struct xfs_mount *mp = pag->pag_mount;
+ xfs_agnumber_t agno = pag->pag_agno;
xfs_extlen_t ask;
xfs_extlen_t used;
int error = 0;
if (pag->pag_meta_resv.ar_asked == 0) {
ask = used = 0;
- error = xfs_refcountbt_calc_reserves(pag->pag_mount,
- pag->pag_agno, &ask, &used);
+ error = xfs_refcountbt_calc_reserves(mp, agno, &ask, &used);
if (error)
goto out;
- error = __xfs_ag_resv_init(pag, XFS_AG_RESV_METADATA,
- ask, used);
+ error = xfs_finobt_calc_reserves(mp, agno, &ask, &used);
if (error)
goto out;
+
+ error = __xfs_ag_resv_init(pag, XFS_AG_RESV_METADATA,
+ ask, used);
+ if (error) {
+ /*
+ * Because we didn't have per-AG reservations when the
+ * finobt feature was added we might not be able to
+ * reserve all needed blocks. Warn and fall back to the
+ * old and potentially buggy code in that case, but
+ * ensure we do have the reservation for the refcountbt.
+ */
+ ask = used = 0;
+
+ mp->m_inotbt_nores = true;
+
+ error = xfs_refcountbt_calc_reserves(mp, agno, &ask,
+ &used);
+ if (error)
+ goto out;
+
+ error = __xfs_ag_resv_init(pag, XFS_AG_RESV_METADATA,
+ ask, used);
+ if (error)
+ goto out;
+ }
}
/* Create the AGFL metadata reservation */
if (pag->pag_agfl_resv.ar_asked == 0) {
ask = used = 0;
- error = xfs_rmapbt_calc_reserves(pag->pag_mount, pag->pag_agno,
- &ask, &used);
+ error = xfs_rmapbt_calc_reserves(mp, agno, &ask, &used);
if (error)
goto out;
goto out;
}
+#ifdef DEBUG
+ /* need to read in the AGF for the ASSERT below to work */
+ error = xfs_alloc_pagf_init(pag->pag_mount, NULL, pag->pag_agno, 0);
+ if (error)
+ return error;
+
ASSERT(xfs_perag_resv(pag, XFS_AG_RESV_METADATA)->ar_reserved +
xfs_perag_resv(pag, XFS_AG_RESV_AGFL)->ar_reserved <=
pag->pagf_freeblks + pag->pagf_flcount);
+#endif
out:
return error;
}
xfs_alloc_set_aside(
struct xfs_mount *mp)
{
- unsigned int blocks;
-
- blocks = 4 + (mp->m_sb.sb_agcount * XFS_ALLOC_AGFL_RESERVE);
- return blocks;
+ return mp->m_sb.sb_agcount * (XFS_ALLOC_AGFL_RESERVE + 4);
}
/*
return;
ASSERT(rlen >= args->minlen && rlen <= args->maxlen);
ASSERT(rlen % args->prod == args->mod);
+ ASSERT(args->pag->pagf_freeblks + args->pag->pagf_flcount >=
+ rlen + args->minleft);
args->len = rlen;
}
-/*
- * Fix up length if there is too little space left in the a.g.
- * Return 1 if ok, 0 if too little, should give up.
- */
-STATIC int
-xfs_alloc_fix_minleft(
- xfs_alloc_arg_t *args) /* allocation argument structure */
-{
- xfs_agf_t *agf; /* a.g. freelist header */
- int diff; /* free space difference */
-
- if (args->minleft == 0)
- return 1;
- agf = XFS_BUF_TO_AGF(args->agbp);
- diff = be32_to_cpu(agf->agf_freeblks)
- - args->len - args->minleft;
- if (diff >= 0)
- return 1;
- args->len += diff; /* shrink the allocated space */
- /* casts to (int) catch length underflows */
- if ((int)args->len >= (int)args->minlen)
- return 1;
- args->agbno = NULLAGBLOCK;
- return 0;
-}
-
/*
* Update the two btrees, logically removing from freespace the extent
* starting at rbno, rlen blocks. The extent is contained within the
xfs_alloc_arg_t *args) /* argument structure for allocation */
{
int error=0;
- xfs_extlen_t reservation;
- xfs_extlen_t oldmax;
ASSERT(args->minlen > 0);
ASSERT(args->maxlen > 0);
ASSERT(args->mod < args->prod);
ASSERT(args->alignment > 0);
- /*
- * Clamp maxlen to the amount of free space minus any reservations
- * that have been made.
- */
- oldmax = args->maxlen;
- reservation = xfs_ag_resv_needed(args->pag, args->resv);
- if (args->maxlen > args->pag->pagf_freeblks - reservation)
- args->maxlen = args->pag->pagf_freeblks - reservation;
- if (args->maxlen == 0) {
- args->agbno = NULLAGBLOCK;
- args->maxlen = oldmax;
- return 0;
- }
-
/*
* Branch to correct routine based on the type.
*/
/* NOTREACHED */
}
- args->maxlen = oldmax;
-
if (error || args->agbno == NULLAGBLOCK)
return error;
args->len = XFS_AGBLOCK_MIN(tend, args->agbno + args->maxlen)
- args->agbno;
xfs_alloc_fix_len(args);
- if (!xfs_alloc_fix_minleft(args))
- goto not_found;
-
ASSERT(args->agbno + args->len <= tend);
/*
XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0);
ASSERT(ltbno + ltlen <= be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length));
args->len = blen;
- if (!xfs_alloc_fix_minleft(args)) {
- xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR);
- trace_xfs_alloc_near_nominleft(args);
- return 0;
- }
- blen = args->len;
+
/*
* We are allocating starting at bnew for blen blocks.
*/
*/
args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen);
xfs_alloc_fix_len(args);
- if (!xfs_alloc_fix_minleft(args)) {
- trace_xfs_alloc_near_nominleft(args);
- xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_NOERROR);
- xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR);
- return 0;
- }
rlen = args->len;
(void)xfs_alloc_compute_diff(args->agbno, rlen, args->alignment,
args->datatype, ltbnoa, ltlena, <new);
}
xfs_alloc_fix_len(args);
- if (!xfs_alloc_fix_minleft(args))
- goto out_nominleft;
rlen = args->len;
XFS_WANT_CORRUPTED_GOTO(args->mp, rlen <= flen, error0);
/*
int flags)
{
struct xfs_perag *pag = args->pag;
- xfs_extlen_t longest;
+ xfs_extlen_t alloc_len, longest;
xfs_extlen_t reservation; /* blocks that are still reserved */
int available;
reservation = xfs_ag_resv_needed(pag, args->resv);
/* do we have enough contiguous free space for the allocation? */
+ alloc_len = args->minlen + (args->alignment - 1) + args->minalignslop;
longest = xfs_alloc_longest_free_extent(args->mp, pag, min_free,
reservation);
- if ((args->minlen + args->alignment + args->minalignslop - 1) > longest)
+ if (longest < alloc_len)
return false;
/* do we have enough free space remaining for the allocation? */
available = (int)(pag->pagf_freeblks + pag->pagf_flcount -
- reservation - min_free - args->total);
- if (available < (int)args->minleft || available <= 0)
+ reservation - min_free - args->minleft);
+ if (available < (int)max(args->total, alloc_len))
return false;
+ /*
+ * Clamp maxlen to the amount of free space available for the actual
+ * extent allocation.
+ */
+ if (available < (int)args->maxlen && !(flags & XFS_ALLOC_FLAG_CHECK)) {
+ args->maxlen = available;
+ ASSERT(args->maxlen > 0);
+ ASSERT(args->maxlen >= args->minlen);
+ }
+
return true;
}
}
need = xfs_alloc_min_freelist(mp, pag);
- if (!xfs_alloc_space_available(args, need, flags))
+ if (!xfs_alloc_space_available(args, need, flags |
+ XFS_ALLOC_FLAG_CHECK))
goto out_agbp_relse;
/*
xfs_agblock_t agsize; /* allocation group size */
int error;
int flags; /* XFS_ALLOC_FLAG_... locking flags */
- xfs_extlen_t minleft;/* minimum left value, temp copy */
xfs_mount_t *mp; /* mount structure pointer */
xfs_agnumber_t sagno; /* starting allocation group number */
xfs_alloctype_t type; /* input allocation type */
int bump_rotor = 0;
- int no_min = 0;
xfs_agnumber_t rotorstep = xfs_rotorstep; /* inode32 agf stepper */
mp = args->mp;
trace_xfs_alloc_vextent_badargs(args);
return 0;
}
- minleft = args->minleft;
switch (type) {
case XFS_ALLOCTYPE_THIS_AG:
*/
args->agno = XFS_FSB_TO_AGNO(mp, args->fsbno);
args->pag = xfs_perag_get(mp, args->agno);
- args->minleft = 0;
error = xfs_alloc_fix_freelist(args, 0);
- args->minleft = minleft;
if (error) {
trace_xfs_alloc_vextent_nofix(args);
goto error0;
*/
for (;;) {
args->pag = xfs_perag_get(mp, args->agno);
- if (no_min) args->minleft = 0;
error = xfs_alloc_fix_freelist(args, flags);
- args->minleft = minleft;
if (error) {
trace_xfs_alloc_vextent_nofix(args);
goto error0;
* or switch to non-trylock mode.
*/
if (args->agno == sagno) {
- if (no_min == 1) {
+ if (flags == 0) {
args->agbno = NULLAGBLOCK;
trace_xfs_alloc_vextent_allfailed(args);
break;
}
- if (flags == 0) {
- no_min = 1;
- } else {
- flags = 0;
- if (type == XFS_ALLOCTYPE_START_BNO) {
- args->agbno = XFS_FSB_TO_AGBNO(mp,
- args->fsbno);
- args->type = XFS_ALLOCTYPE_NEAR_BNO;
- }
+
+ flags = 0;
+ if (type == XFS_ALLOCTYPE_START_BNO) {
+ args->agbno = XFS_FSB_TO_AGBNO(mp,
+ args->fsbno);
+ args->type = XFS_ALLOCTYPE_NEAR_BNO;
}
}
xfs_perag_put(args->pag);
#define XFS_ALLOC_FLAG_FREEING 0x00000002 /* indicate caller is freeing extents*/
#define XFS_ALLOC_FLAG_NORMAP 0x00000004 /* don't modify the rmapbt */
#define XFS_ALLOC_FLAG_NOSHRINK 0x00000008 /* don't shrink the freelist */
-
+#define XFS_ALLOC_FLAG_CHECK 0x00000010 /* test only, don't modify args */
/*
* Argument structure for xfs_alloc routines.
if (XFS_FORCED_SHUTDOWN(ip->i_mount))
return -EIO;
- if (!xfs_inode_hasattr(ip))
- return -ENOATTR;
-
error = xfs_attr_args_init(&args, ip, name, flags);
if (error)
return error;
if (XFS_FORCED_SHUTDOWN(dp->i_mount))
return -EIO;
- if (!xfs_inode_hasattr(dp))
- return -ENOATTR;
-
error = xfs_attr_args_init(&args, dp, name, flags);
if (error)
return error;
align = xfs_get_cowextsz_hint(ap->ip);
else if (xfs_alloc_is_userdata(ap->datatype))
align = xfs_get_extsz_hint(ap->ip);
- if (unlikely(align)) {
+ if (align) {
error = xfs_bmap_extsize_align(mp, &ap->got, &ap->prev,
align, 0, ap->eof, 0, ap->conv,
&ap->offset, &ap->length);
args.minlen = ap->minlen;
}
/* apply extent size hints if obtained earlier */
- if (unlikely(align)) {
+ if (align) {
args.prod = align;
if ((args.mod = (xfs_extlen_t)do_mod(ap->offset, args.prod)))
args.mod = (xfs_extlen_t)(args.prod - args.mod);
args.fsbno = 0;
args.type = XFS_ALLOCTYPE_FIRST_AG;
args.total = ap->minlen;
- args.minleft = 0;
if ((error = xfs_alloc_vextent(&args)))
return error;
ap->dfops->dop_low = true;
if (error)
return error;
- if (bma->dfops->dop_low)
- bma->minleft = 0;
if (bma->cur)
bma->cur->bc_private.b.firstblock = *bma->firstblock;
if (bma->blkno == NULLFSBLOCK)
int n; /* current extent index */
xfs_fileoff_t obno; /* old block number (offset) */
int whichfork; /* data or attr fork */
- char inhole; /* current location is hole in file */
- char wasdelay; /* old extent was delayed */
#ifdef DEBUG
xfs_fileoff_t orig_bno; /* original block number value */
bma.firstblock = firstblock;
while (bno < end && n < *nmap) {
- inhole = eof || bma.got.br_startoff > bno;
- wasdelay = !inhole && isnullstartblock(bma.got.br_startblock);
+ bool need_alloc = false, wasdelay = false;
- /*
- * Make sure we only reflink into a hole.
- */
- if (flags & XFS_BMAPI_REMAP)
- ASSERT(inhole);
- if (flags & XFS_BMAPI_COWFORK)
- ASSERT(!inhole);
+ /* in hole or beyoned EOF? */
+ if (eof || bma.got.br_startoff > bno) {
+ if (flags & XFS_BMAPI_DELALLOC) {
+ /*
+ * For the COW fork we can reasonably get a
+ * request for converting an extent that races
+ * with other threads already having converted
+ * part of it, as there converting COW to
+ * regular blocks is not protected using the
+ * IOLOCK.
+ */
+ ASSERT(flags & XFS_BMAPI_COWFORK);
+ if (!(flags & XFS_BMAPI_COWFORK)) {
+ error = -EIO;
+ goto error0;
+ }
+
+ if (eof || bno >= end)
+ break;
+ } else {
+ need_alloc = true;
+ }
+ } else {
+ /*
+ * Make sure we only reflink into a hole.
+ */
+ ASSERT(!(flags & XFS_BMAPI_REMAP));
+ if (isnullstartblock(bma.got.br_startblock))
+ wasdelay = true;
+ }
/*
* First, deal with the hole before the allocated space
* that we found, if any.
*/
- if (inhole || wasdelay) {
+ if (need_alloc || wasdelay) {
bma.eof = eof;
bma.conv = !!(flags & XFS_BMAPI_CONVERT);
bma.wasdel = wasdelay;
/* Map something in the CoW fork. */
#define XFS_BMAPI_COWFORK 0x200
+/* Only convert delalloc space, don't allocate entirely new extents */
+#define XFS_BMAPI_DELALLOC 0x400
+
#define XFS_BMAPI_FLAGS \
{ XFS_BMAPI_ENTIRE, "ENTIRE" }, \
{ XFS_BMAPI_METADATA, "METADATA" }, \
{ XFS_BMAPI_CONVERT, "CONVERT" }, \
{ XFS_BMAPI_ZERO, "ZERO" }, \
{ XFS_BMAPI_REMAP, "REMAP" }, \
- { XFS_BMAPI_COWFORK, "COWFORK" }
+ { XFS_BMAPI_COWFORK, "COWFORK" }, \
+ { XFS_BMAPI_DELALLOC, "DELALLOC" }
static inline int xfs_bmapi_aflag(int w)
if (args.fsbno == NULLFSBLOCK && args.minleft) {
/*
* Could not find an AG with enough free space to satisfy
- * a full btree split. Try again without minleft and if
+ * a full btree split. Try again and if
* successful activate the lowspace algorithm.
*/
args.fsbno = 0;
args.type = XFS_ALLOCTYPE_FIRST_AG;
- args.minleft = 0;
error = xfs_alloc_vextent(&args);
if (error)
goto error0;
struct xfs_name xfs_name_dotdot = { (unsigned char *)"..", 2, XFS_DIR3_FT_DIR };
/*
- * @mode, if set, indicates that the type field needs to be set up.
- * This uses the transformation from file mode to DT_* as defined in linux/fs.h
- * for file type specification. This will be propagated into the directory
- * structure if appropriate for the given operation and filesystem config.
+ * Convert inode mode to directory entry filetype
*/
-const unsigned char xfs_mode_to_ftype[S_IFMT >> S_SHIFT] = {
- [0] = XFS_DIR3_FT_UNKNOWN,
- [S_IFREG >> S_SHIFT] = XFS_DIR3_FT_REG_FILE,
- [S_IFDIR >> S_SHIFT] = XFS_DIR3_FT_DIR,
- [S_IFCHR >> S_SHIFT] = XFS_DIR3_FT_CHRDEV,
- [S_IFBLK >> S_SHIFT] = XFS_DIR3_FT_BLKDEV,
- [S_IFIFO >> S_SHIFT] = XFS_DIR3_FT_FIFO,
- [S_IFSOCK >> S_SHIFT] = XFS_DIR3_FT_SOCK,
- [S_IFLNK >> S_SHIFT] = XFS_DIR3_FT_SYMLINK,
-};
+unsigned char xfs_mode_to_ftype(int mode)
+{
+ switch (mode & S_IFMT) {
+ case S_IFREG:
+ return XFS_DIR3_FT_REG_FILE;
+ case S_IFDIR:
+ return XFS_DIR3_FT_DIR;
+ case S_IFCHR:
+ return XFS_DIR3_FT_CHRDEV;
+ case S_IFBLK:
+ return XFS_DIR3_FT_BLKDEV;
+ case S_IFIFO:
+ return XFS_DIR3_FT_FIFO;
+ case S_IFSOCK:
+ return XFS_DIR3_FT_SOCK;
+ case S_IFLNK:
+ return XFS_DIR3_FT_SYMLINK;
+ default:
+ return XFS_DIR3_FT_UNKNOWN;
+ }
+}
/*
* ASCII case-insensitive (ie. A-Z) support for directories that was
if ((rval = xfs_bmap_last_offset(args->dp, &last, XFS_DATA_FORK)))
return rval;
rval = XFS_FSB_TO_B(args->dp->i_mount, last) == args->geo->blksize;
- ASSERT(rval == 0 || args->dp->i_d.di_size == args->geo->blksize);
+ if (rval != 0 && args->dp->i_d.di_size != args->geo->blksize)
+ return -EFSCORRUPTED;
*vp = rval;
return 0;
}
#ifndef __XFS_DIR2_H__
#define __XFS_DIR2_H__
+#include "xfs_da_format.h"
+#include "xfs_da_btree.h"
+
struct xfs_defer_ops;
struct xfs_da_args;
struct xfs_inode;
extern struct xfs_name xfs_name_dotdot;
/*
- * directory filetype conversion tables.
+ * Convert inode mode to directory entry filetype
*/
-#define S_SHIFT 12
-extern const unsigned char xfs_mode_to_ftype[];
+extern unsigned char xfs_mode_to_ftype(int mode);
/*
* directory operations vector for encode/decode routines
}
STATIC int
-xfs_inobt_alloc_block(
+__xfs_inobt_alloc_block(
struct xfs_btree_cur *cur,
union xfs_btree_ptr *start,
union xfs_btree_ptr *new,
- int *stat)
+ int *stat,
+ enum xfs_ag_resv_type resv)
{
xfs_alloc_arg_t args; /* block allocation args */
int error; /* error return value */
args.maxlen = 1;
args.prod = 1;
args.type = XFS_ALLOCTYPE_NEAR_BNO;
+ args.resv = resv;
error = xfs_alloc_vextent(&args);
if (error) {
return 0;
}
+STATIC int
+xfs_inobt_alloc_block(
+ struct xfs_btree_cur *cur,
+ union xfs_btree_ptr *start,
+ union xfs_btree_ptr *new,
+ int *stat)
+{
+ return __xfs_inobt_alloc_block(cur, start, new, stat, XFS_AG_RESV_NONE);
+}
+
+STATIC int
+xfs_finobt_alloc_block(
+ struct xfs_btree_cur *cur,
+ union xfs_btree_ptr *start,
+ union xfs_btree_ptr *new,
+ int *stat)
+{
+ return __xfs_inobt_alloc_block(cur, start, new, stat,
+ XFS_AG_RESV_METADATA);
+}
+
STATIC int
xfs_inobt_free_block(
struct xfs_btree_cur *cur,
.dup_cursor = xfs_inobt_dup_cursor,
.set_root = xfs_finobt_set_root,
- .alloc_block = xfs_inobt_alloc_block,
+ .alloc_block = xfs_finobt_alloc_block,
.free_block = xfs_inobt_free_block,
.get_minrecs = xfs_inobt_get_minrecs,
.get_maxrecs = xfs_inobt_get_maxrecs,
return 0;
}
#endif /* DEBUG */
+
+static xfs_extlen_t
+xfs_inobt_max_size(
+ struct xfs_mount *mp)
+{
+ /* Bail out if we're uninitialized, which can happen in mkfs. */
+ if (mp->m_inobt_mxr[0] == 0)
+ return 0;
+
+ return xfs_btree_calc_size(mp, mp->m_inobt_mnr,
+ (uint64_t)mp->m_sb.sb_agblocks * mp->m_sb.sb_inopblock /
+ XFS_INODES_PER_CHUNK);
+}
+
+static int
+xfs_inobt_count_blocks(
+ struct xfs_mount *mp,
+ xfs_agnumber_t agno,
+ xfs_btnum_t btnum,
+ xfs_extlen_t *tree_blocks)
+{
+ struct xfs_buf *agbp;
+ struct xfs_btree_cur *cur;
+ int error;
+
+ error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp);
+ if (error)
+ return error;
+
+ cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno, btnum);
+ error = xfs_btree_count_blocks(cur, tree_blocks);
+ xfs_btree_del_cursor(cur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR);
+ xfs_buf_relse(agbp);
+
+ return error;
+}
+
+/*
+ * Figure out how many blocks to reserve and how many are used by this btree.
+ */
+int
+xfs_finobt_calc_reserves(
+ struct xfs_mount *mp,
+ xfs_agnumber_t agno,
+ xfs_extlen_t *ask,
+ xfs_extlen_t *used)
+{
+ xfs_extlen_t tree_len = 0;
+ int error;
+
+ if (!xfs_sb_version_hasfinobt(&mp->m_sb))
+ return 0;
+
+ error = xfs_inobt_count_blocks(mp, agno, XFS_BTNUM_FINO, &tree_len);
+ if (error)
+ return error;
+
+ *ask += xfs_inobt_max_size(mp);
+ *used += tree_len;
+ return 0;
+}
#define xfs_inobt_rec_check_count(mp, rec) 0
#endif /* DEBUG */
+int xfs_finobt_calc_reserves(struct xfs_mount *mp, xfs_agnumber_t agno,
+ xfs_extlen_t *ask, xfs_extlen_t *used);
+
#endif /* __XFS_IALLOC_BTREE_H__ */
#include "xfs_icache.h"
#include "xfs_trans.h"
#include "xfs_ialloc.h"
+#include "xfs_dir2.h"
/*
* Check that none of the inode's in the buffer have a next
xfs_ino_t ino,
struct xfs_dinode *dip)
{
+ uint16_t mode;
uint16_t flags;
uint64_t flags2;
if (be64_to_cpu(dip->di_size) & (1ULL << 63))
return false;
- /* No zero-length symlinks. */
- if (S_ISLNK(be16_to_cpu(dip->di_mode)) && dip->di_size == 0)
+ mode = be16_to_cpu(dip->di_mode);
+ if (mode && xfs_mode_to_ftype(mode) == XFS_DIR3_FT_UNKNOWN)
+ return false;
+
+ /* No zero-length symlinks/dirs. */
+ if ((S_ISLNK(mode) || S_ISDIR(mode)) && dip->di_size == 0)
return false;
/* only version 3 or greater inodes are extensively verified here */
sbp->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG ||
sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG ||
sbp->sb_blocksize != (1 << sbp->sb_blocklog) ||
- sbp->sb_dirblklog > XFS_MAX_BLOCKSIZE_LOG ||
+ sbp->sb_dirblklog + sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG ||
sbp->sb_inodesize < XFS_DINODE_MIN_SIZE ||
sbp->sb_inodesize > XFS_DINODE_MAX_SIZE ||
sbp->sb_inodelog < XFS_DINODE_MIN_LOG ||
* block_invalidatepage() can send pages that are still marked dirty
* but otherwise have invalidated buffers.
*
- * We've historically freed buffers on the latter. Instead, quietly
- * filter out all dirty pages to avoid spurious buffer state warnings.
- * This can likely be removed once shrink_active_list() is fixed.
+ * We want to release the latter to avoid unnecessary buildup of the
+ * LRU, skip the former and warn if we've left any lingering
+ * delalloc/unwritten buffers on clean pages. Skip pages with delalloc
+ * or unwritten buffers and warn if the page is not dirty. Otherwise
+ * try to release the buffers.
*/
- if (PageDirty(page))
- return 0;
-
xfs_count_page_state(page, &delalloc, &unwritten);
- if (WARN_ON_ONCE(delalloc))
+ if (delalloc) {
+ WARN_ON_ONCE(!PageDirty(page));
return 0;
- if (WARN_ON_ONCE(unwritten))
+ }
+ if (unwritten) {
+ WARN_ON_ONCE(!PageDirty(page));
return 0;
+ }
return try_to_free_buffers(page);
}
xfs_bmbt_irec_t *map; /* buffer for user's data */
xfs_mount_t *mp; /* file system mount point */
int nex; /* # of user extents can do */
- int nexleft; /* # of user extents left */
int subnex; /* # of bmapi's can do */
int nmap; /* number of map entries */
struct getbmapx *out; /* output structure */
goto out_free_map;
}
- nexleft = nex;
-
do {
- nmap = (nexleft > subnex) ? subnex : nexleft;
+ nmap = (nex> subnex) ? subnex : nex;
error = xfs_bmapi_read(ip, XFS_BB_TO_FSBT(mp, bmv->bmv_offset),
XFS_BB_TO_FSB(mp, bmv->bmv_length),
map, &nmap, bmapi_flags);
goto out_free_map;
ASSERT(nmap <= subnex);
- for (i = 0; i < nmap && nexleft && bmv->bmv_length &&
- cur_ext < bmv->bmv_count; i++) {
+ for (i = 0; i < nmap && bmv->bmv_length &&
+ cur_ext < bmv->bmv_count - 1; i++) {
out[cur_ext].bmv_oflags = 0;
if (map[i].br_state == XFS_EXT_UNWRITTEN)
out[cur_ext].bmv_oflags |= BMV_OF_PREALLOC;
continue;
}
+ /*
+ * In order to report shared extents accurately,
+ * we report each distinct shared/unshared part
+ * of a single bmbt record using multiple bmap
+ * extents. To make that happen, we iterate the
+ * same map array item multiple times, each
+ * time trimming out the subextent that we just
+ * reported.
+ *
+ * Because of this, we must check the out array
+ * index (cur_ext) directly against bmv_count-1
+ * to avoid overflows.
+ */
if (inject_map.br_startblock != NULLFSBLOCK) {
map[i] = inject_map;
i--;
- } else
- nexleft--;
+ }
bmv->bmv_entries++;
cur_ext++;
}
- } while (nmap && nexleft && bmv->bmv_length &&
- cur_ext < bmv->bmv_count);
+ } while (nmap && bmv->bmv_length && cur_ext < bmv->bmv_count - 1);
out_free_map:
kmem_free(map);
out_free_pages:
for (i = 0; i < bp->b_page_count; i++)
__free_page(bp->b_pages[i]);
+ bp->b_flags &= ~_XBF_PAGES;
return error;
}
/* Simple advance */
next_id = *id + 1;
+ /* If we'd wrap past the max ID, stop */
+ if (next_id < *id)
+ return -ENOENT;
+
/* If new ID is within the current chunk, advancing it sufficed */
if (next_id % mp->m_quotainfo->qi_dqperchunk) {
*id = next_id;
int error;
/*
- * The ifree transaction might need to allocate blocks for record
- * insertion to the finobt. We don't want to fail here at ENOSPC, so
- * allow ifree to dip into the reserved block pool if necessary.
- *
- * Freeing large sets of inodes generally means freeing inode chunks,
- * directory and file data blocks, so this should be relatively safe.
- * Only under severe circumstances should it be possible to free enough
- * inodes to exhaust the reserve block pool via finobt expansion while
- * at the same time not creating free space in the filesystem.
+ * We try to use a per-AG reservation for any block needed by the finobt
+ * tree, but as the finobt feature predates the per-AG reservation
+ * support a degraded file system might not have enough space for the
+ * reservation at mount time. In that case try to dip into the reserved
+ * pool and pray.
*
* Send a warning if the reservation does happen to fail, as the inode
* now remains allocated and sits on the unlinked list until the fs is
* repaired.
*/
- error = xfs_trans_alloc(mp, &M_RES(mp)->tr_ifree,
- XFS_IFREE_SPACE_RES(mp), 0, XFS_TRANS_RESERVE, &tp);
+ if (unlikely(mp->m_inotbt_nores)) {
+ error = xfs_trans_alloc(mp, &M_RES(mp)->tr_ifree,
+ XFS_IFREE_SPACE_RES(mp), 0, XFS_TRANS_RESERVE,
+ &tp);
+ } else {
+ error = xfs_trans_alloc(mp, &M_RES(mp)->tr_ifree, 0, 0, 0, &tp);
+ }
if (error) {
if (error == -ENOSPC) {
xfs_warn_ratelimited(mp,
xfs_trans_t *tp;
int nimaps;
int error = 0;
- int flags = 0;
+ int flags = XFS_BMAPI_DELALLOC;
int nres;
if (whichfork == XFS_COW_FORK)
static void
xfs_dentry_to_name(
+ struct xfs_name *namep,
+ struct dentry *dentry)
+{
+ namep->name = dentry->d_name.name;
+ namep->len = dentry->d_name.len;
+ namep->type = XFS_DIR3_FT_UNKNOWN;
+}
+
+static int
+xfs_dentry_mode_to_name(
struct xfs_name *namep,
struct dentry *dentry,
int mode)
{
namep->name = dentry->d_name.name;
namep->len = dentry->d_name.len;
- namep->type = xfs_mode_to_ftype[(mode & S_IFMT) >> S_SHIFT];
+ namep->type = xfs_mode_to_ftype(mode);
+
+ if (unlikely(namep->type == XFS_DIR3_FT_UNKNOWN))
+ return -EFSCORRUPTED;
+
+ return 0;
}
STATIC void
* xfs_init_security we must back out.
* ENOSPC can hit here, among other things.
*/
- xfs_dentry_to_name(&teardown, dentry, 0);
+ xfs_dentry_to_name(&teardown, dentry);
xfs_remove(XFS_I(dir), &teardown, XFS_I(inode));
}
if (error)
return error;
+ /* Verify mode is valid also for tmpfile case */
+ error = xfs_dentry_mode_to_name(&name, dentry, mode);
+ if (unlikely(error))
+ goto out_free_acl;
+
if (!tmpfile) {
- xfs_dentry_to_name(&name, dentry, mode);
error = xfs_create(XFS_I(dir), &name, mode, rdev, &ip);
} else {
error = xfs_create_tmpfile(XFS_I(dir), dentry, mode, &ip);
if (dentry->d_name.len >= MAXNAMELEN)
return ERR_PTR(-ENAMETOOLONG);
- xfs_dentry_to_name(&name, dentry, 0);
+ xfs_dentry_to_name(&name, dentry);
error = xfs_lookup(XFS_I(dir), &name, &cip, NULL);
if (unlikely(error)) {
if (unlikely(error != -ENOENT))
if (dentry->d_name.len >= MAXNAMELEN)
return ERR_PTR(-ENAMETOOLONG);
- xfs_dentry_to_name(&xname, dentry, 0);
+ xfs_dentry_to_name(&xname, dentry);
error = xfs_lookup(XFS_I(dir), &xname, &ip, &ci_name);
if (unlikely(error)) {
if (unlikely(error != -ENOENT))
struct xfs_name name;
int error;
- xfs_dentry_to_name(&name, dentry, inode->i_mode);
+ error = xfs_dentry_mode_to_name(&name, dentry, inode->i_mode);
+ if (unlikely(error))
+ return error;
error = xfs_link(XFS_I(dir), XFS_I(inode), &name);
if (unlikely(error))
struct xfs_name name;
int error;
- xfs_dentry_to_name(&name, dentry, 0);
+ xfs_dentry_to_name(&name, dentry);
error = xfs_remove(XFS_I(dir), &name, XFS_I(d_inode(dentry)));
if (error)
mode = S_IFLNK |
(irix_symlink_mode ? 0777 & ~current_umask() : S_IRWXUGO);
- xfs_dentry_to_name(&name, dentry, mode);
+ error = xfs_dentry_mode_to_name(&name, dentry, mode);
+ if (unlikely(error))
+ goto out;
error = xfs_symlink(XFS_I(dir), &name, symname, mode, &cip);
if (unlikely(error))
{
struct inode *new_inode = d_inode(ndentry);
int omode = 0;
+ int error;
struct xfs_name oname;
struct xfs_name nname;
if (flags & RENAME_EXCHANGE)
omode = d_inode(ndentry)->i_mode;
- xfs_dentry_to_name(&oname, odentry, omode);
- xfs_dentry_to_name(&nname, ndentry, d_inode(odentry)->i_mode);
+ error = xfs_dentry_mode_to_name(&oname, odentry, omode);
+ if (omode && unlikely(error))
+ return error;
+
+ error = xfs_dentry_mode_to_name(&nname, ndentry,
+ d_inode(odentry)->i_mode);
+ if (unlikely(error))
+ return error;
return xfs_rename(XFS_I(odir), &oname, XFS_I(d_inode(odentry)),
XFS_I(ndir), &nname,
}
#define ASSERT_ALWAYS(expr) \
- (unlikely(expr) ? (void)0 : assfail(#expr, __FILE__, __LINE__))
+ (likely(expr) ? (void)0 : assfail(#expr, __FILE__, __LINE__))
#ifdef DEBUG
#define ASSERT(expr) \
- (unlikely(expr) ? (void)0 : assfail(#expr, __FILE__, __LINE__))
+ (likely(expr) ? (void)0 : assfail(#expr, __FILE__, __LINE__))
#ifndef STATIC
# define STATIC noinline
#ifdef XFS_WARN
#define ASSERT(expr) \
- (unlikely(expr) ? (void)0 : asswarn(#expr, __FILE__, __LINE__))
+ (likely(expr) ? (void)0 : asswarn(#expr, __FILE__, __LINE__))
#ifndef STATIC
# define STATIC static noinline
xfs_mount_t *mp,
uint flags)
{
- int error;
-
trace_xfs_log_force(mp, 0, _RET_IP_);
- error = _xfs_log_force(mp, flags, NULL);
- if (error)
- xfs_warn(mp, "%s: error %d returned.", __func__, error);
+ _xfs_log_force(mp, flags, NULL);
}
/*
xfs_lsn_t lsn,
uint flags)
{
- int error;
-
trace_xfs_log_force(mp, lsn, _RET_IP_);
- error = _xfs_log_force_lsn(mp, lsn, flags, NULL);
- if (error)
- xfs_warn(mp, "%s: error %d returned.", __func__, error);
+ _xfs_log_force_lsn(mp, lsn, flags, NULL);
}
/*
int m_fixedfsid[2]; /* unchanged for life of FS */
uint m_dmevmask; /* DMI events for this FS */
__uint64_t m_flags; /* global mount flags */
+ bool m_inotbt_nores; /* no per-AG finobt resv. */
int m_ialloc_inos; /* inodes in inode allocation */
int m_ialloc_blks; /* blocks in inode allocation */
int m_ialloc_min_blks;/* min blocks in sparse inode
* the case in all other instances. It's OK that we do this because
* quotacheck is done only at mount time.
*/
- error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_EXCL, &ip);
+ error = xfs_iget(mp, NULL, ino, XFS_IGET_DONTCACHE, XFS_ILOCK_EXCL,
+ &ip);
if (error) {
*res = BULKSTAT_RV_NOTHING;
return error;
#ifndef KSYM_ALIGN
#define KSYM_ALIGN 8
#endif
-#ifndef KCRC_ALIGN
-#define KCRC_ALIGN 8
-#endif
#else
#define __put .long
#ifndef KSYM_ALIGN
#define KSYM_ALIGN 4
#endif
+#endif
#ifndef KCRC_ALIGN
#define KCRC_ALIGN 4
#endif
-#endif
#ifdef CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX
#define KSYM(name) _##name
.section ___kcrctab\sec+\name,"a"
.balign KCRC_ALIGN
KSYM(__kcrctab_\name):
- __put KSYM(__crc_\name)
+#if defined(CONFIG_MODULE_REL_CRCS)
+ .long KSYM(__crc_\name) - .
+#else
+ .long KSYM(__crc_\name)
+#endif
.weak KSYM(__crc_\name)
.previous
#endif
struct drm_minor *control; /**< Control node */
struct drm_minor *primary; /**< Primary node */
struct drm_minor *render; /**< Render node */
+ bool registered;
/* currently active master for this device. Protected by master_mutex */
struct drm_master *master;
struct drm_crtc *ptr;
struct drm_crtc_state *state;
struct drm_crtc_commit *commit;
- s64 __user *out_fence_ptr;
+ s32 __user *out_fence_ptr;
};
struct __drm_connnectors_state {
* core drm connector interfaces. Everything added from this callback
* should be unregistered in the early_unregister callback.
*
+ * This is called while holding drm_connector->mutex.
+ *
* Returns:
*
* 0 on success, or a negative error code on failure.
* late_register(). It is called from drm_connector_unregister(),
* early in the driver unload sequence to disable userspace access
* before data structures are torndown.
+ *
+ * This is called while holding drm_connector->mutex.
*/
void (*early_unregister)(struct drm_connector *connector);
* @interlace_allowed: can this connector handle interlaced modes?
* @doublescan_allowed: can this connector handle doublescan?
* @stereo_allowed: can this connector handle stereo modes?
- * @registered: is this connector exposed (registered) with userspace?
* @modes: modes available on this connector (from fill_modes() + user)
* @status: one of the drm_connector_status enums (connected, not, or unknown)
* @probed_modes: list of modes derived directly from the display
char *name;
+ /**
+ * @mutex: Lock for general connector state, but currently only protects
+ * @registered. Most of the connector state is still protected by the
+ * mutex in &drm_mode_config.
+ */
+ struct mutex mutex;
+
/**
* @index: Compacted connector index, which matches the position inside
* the mode_config.list for drivers not supporting hot-add/removing. Can
bool interlace_allowed;
bool doublescan_allowed;
bool stereo_allowed;
+ /**
+ * @registered: Is this connector exposed (registered) with userspace?
+ * Protected by @mutex.
+ */
bool registered;
struct list_head modes; /* list of modes on this connector */
/**
* @prop_out_fence_ptr: Sync File fd pointer representing the
* outgoing fences for a CRTC. Userspace should provide a pointer to a
- * value of type s64, and then cast that pointer to u64.
+ * value of type s32, and then cast that pointer to u64.
*/
struct drm_property *prop_out_fence_ptr;
/**
void kvm_timer_vcpu_put(struct kvm_vcpu *vcpu);
+void kvm_timer_init_vhe(void);
#endif
}
}
-static inline unsigned int blk_queue_zone_size(struct request_queue *q)
+static inline unsigned int blk_queue_zone_sectors(struct request_queue *q)
{
return blk_queue_is_zoned(q) ? q->limits.chunk_sectors : 0;
}
return blk_rq_cur_bytes(rq) >> 9;
}
+/*
+ * Some commands like WRITE SAME have a payload or data transfer size which
+ * is different from the size of the request. Any driver that supports such
+ * commands using the RQF_SPECIAL_PAYLOAD flag needs to use this helper to
+ * calculate the data transfer size.
+ */
+static inline unsigned int blk_rq_payload_bytes(struct request *rq)
+{
+ if (rq->rq_flags & RQF_SPECIAL_PAYLOAD)
+ return rq->special_vec.bv_len;
+ return blk_rq_bytes(rq);
+}
+
static inline unsigned int blk_queue_get_max_sectors(struct request_queue *q,
int op)
{
return false;
}
-static inline unsigned int bdev_zone_size(struct block_device *bdev)
+static inline unsigned int bdev_zone_sectors(struct block_device *bdev)
{
struct request_queue *q = bdev_get_queue(bdev);
if (q)
- return blk_queue_zone_size(q);
+ return blk_queue_zone_sectors(q);
return 0;
}
u64 bpf_get_stackid(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5);
bool bpf_prog_array_compatible(struct bpf_array *array, const struct bpf_prog *fp);
-int bpf_prog_calc_digest(struct bpf_prog *fp);
+int bpf_prog_calc_tag(struct bpf_prog *fp);
const struct bpf_func_proto *bpf_get_trace_printk_proto(void);
void bpf_map_put_with_uref(struct bpf_map *map);
void bpf_map_put(struct bpf_map *map);
int bpf_map_precharge_memlock(u32 pages);
+void *bpf_map_area_alloc(size_t size);
+void bpf_map_area_free(void *base);
extern int sysctl_unprivileged_bpf_disabled;
extern int can_proto_register(const struct can_proto *cp);
extern void can_proto_unregister(const struct can_proto *cp);
-extern int can_rx_register(struct net_device *dev, canid_t can_id,
- canid_t mask,
- void (*func)(struct sk_buff *, void *),
- void *data, char *ident);
+int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask,
+ void (*func)(struct sk_buff *, void *),
+ void *data, char *ident, struct sock *sk);
extern void can_rx_unregister(struct net_device *dev, canid_t can_id,
canid_t mask,
extern int dump_skip(struct coredump_params *cprm, size_t nr);
extern int dump_emit(struct coredump_params *cprm, const void *addr, int nr);
extern int dump_align(struct coredump_params *cprm, int align);
+extern void dump_truncate(struct coredump_params *cprm);
#ifdef CONFIG_COREDUMP
extern void do_coredump(const siginfo_t *siginfo);
#else
CPUHP_CREATE_THREADS,
CPUHP_PERF_PREPARE,
CPUHP_PERF_X86_PREPARE,
- CPUHP_PERF_X86_UNCORE_PREP,
CPUHP_PERF_X86_AMD_UNCORE_PREP,
- CPUHP_PERF_X86_RAPL_PREP,
CPUHP_PERF_BFIN,
CPUHP_PERF_POWER,
CPUHP_PERF_SUPERH,
CPUHP_ZCOMP_PREPARE,
CPUHP_TIMERS_DEAD,
CPUHP_MIPS_SOC_PREPARE,
+ CPUHP_BP_PREPARE_DYN,
+ CPUHP_BP_PREPARE_DYN_END = CPUHP_BP_PREPARE_DYN + 20,
CPUHP_BRINGUP_CPU,
CPUHP_AP_IDLE_DEAD,
CPUHP_AP_OFFLINE,
CPUHP_AP_IRQ_ARMADA_XP_STARTING,
CPUHP_AP_IRQ_BCM2836_STARTING,
CPUHP_AP_ARM_MVEBU_COHERENCY,
- CPUHP_AP_PERF_X86_UNCORE_STARTING,
CPUHP_AP_PERF_X86_AMD_UNCORE_STARTING,
CPUHP_AP_PERF_X86_STARTING,
CPUHP_AP_PERF_X86_AMD_IBS_STARTING,
#define EFI_PAGE_SHIFT 12
#define EFI_PAGE_SIZE (1UL << EFI_PAGE_SHIFT)
+#define EFI_PAGES_MAX (U64_MAX >> EFI_PAGE_SHIFT)
typedef struct {
u32 type;
#endif
extern void __iomem *efi_lookup_mapped_addr(u64 phys_addr);
+extern phys_addr_t __init efi_memmap_alloc(unsigned int num_entries);
extern int __init efi_memmap_init_early(struct efi_memory_map_data *data);
extern int __init efi_memmap_init_late(phys_addr_t addr, unsigned long size);
extern void __init efi_memmap_unmap(void);
#ifdef CONFIG_MODVERSIONS
/* Mark the CRC weak since genksyms apparently decides not to
* generate a checksums for some symbols */
+#if defined(CONFIG_MODULE_REL_CRCS)
#define __CRC_SYMBOL(sym, sec) \
- extern __visible void *__crc_##sym __attribute__((weak)); \
- static const unsigned long __kcrctab_##sym \
- __used \
- __attribute__((section("___kcrctab" sec "+" #sym), used)) \
- = (unsigned long) &__crc_##sym;
+ asm(" .section \"___kcrctab" sec "+" #sym "\", \"a\" \n" \
+ " .weak " VMLINUX_SYMBOL_STR(__crc_##sym) " \n" \
+ " .long " VMLINUX_SYMBOL_STR(__crc_##sym) " - . \n" \
+ " .previous \n");
+#else
+#define __CRC_SYMBOL(sym, sec) \
+ asm(" .section \"___kcrctab" sec "+" #sym "\", \"a\" \n" \
+ " .weak " VMLINUX_SYMBOL_STR(__crc_##sym) " \n" \
+ " .long " VMLINUX_SYMBOL_STR(__crc_##sym) " \n" \
+ " .previous \n");
+#endif
#else
#define __CRC_SYMBOL(sym, sec)
#endif
/* BPF program can access up to 512 bytes of stack space. */
#define MAX_BPF_STACK 512
+#define BPF_TAG_SIZE 8
+
/* Helper macros for filter block array initializers. */
/* ALU ops on registers, bpf_add|sub|...: dst_reg += src_reg */
kmemcheck_bitfield_end(meta);
enum bpf_prog_type type; /* Type of BPF program */
u32 len; /* Number of filter blocks */
- u32 digest[SHA_DIGEST_WORDS]; /* Program digest */
+ u8 tag[BPF_TAG_SIZE];
struct bpf_prog_aux *aux; /* Auxiliary fields */
struct sock_fprog_kern *orig_prog; /* Original BPF program */
unsigned int (*bpf_func)(const void *ctx,
return prog->len * sizeof(struct bpf_insn);
}
-static inline u32 bpf_prog_digest_scratch_size(const struct bpf_prog *prog)
+static inline u32 bpf_prog_tag_scratch_size(const struct bpf_prog *prog)
{
return round_up(bpf_prog_insn_size(prog) +
sizeof(__be64) + 1, SHA_MESSAGE_BYTES);
#define FSCACHE_OBJECT_IS_AVAILABLE 5 /* T if object has become active */
#define FSCACHE_OBJECT_RETIRED 6 /* T if object was retired on relinquishment */
#define FSCACHE_OBJECT_KILLED_BY_CACHE 7 /* T if object was killed by the cache */
+#define FSCACHE_OBJECT_RUN_AFTER_DEAD 8 /* T if object has been dispatched after death */
struct list_head cache_link; /* link in cache->object_list */
struct hlist_node cookie_link; /* link in cookie->backing_objects */
#define ___GFP_ACCOUNT 0x100000u
#define ___GFP_NOTRACK 0x200000u
#define ___GFP_DIRECT_RECLAIM 0x400000u
-#define ___GFP_OTHER_NODE 0x800000u
-#define ___GFP_WRITE 0x1000000u
-#define ___GFP_KSWAPD_RECLAIM 0x2000000u
+#define ___GFP_WRITE 0x800000u
+#define ___GFP_KSWAPD_RECLAIM 0x1000000u
/* If the above are modified, __GFP_BITS_SHIFT may need updating */
/*
* __GFP_NOTRACK_FALSE_POSITIVE is an alias of __GFP_NOTRACK. It's a means of
* distinguishing in the source between false positives and allocations that
* cannot be supported (e.g. page tables).
- *
- * __GFP_OTHER_NODE is for allocations that are on a remote node but that
- * should not be accounted for as a remote allocation in vmstat. A
- * typical user would be khugepaged collapsing a huge page on a remote
- * node.
*/
#define __GFP_COLD ((__force gfp_t)___GFP_COLD)
#define __GFP_NOWARN ((__force gfp_t)___GFP_NOWARN)
#define __GFP_ZERO ((__force gfp_t)___GFP_ZERO)
#define __GFP_NOTRACK ((__force gfp_t)___GFP_NOTRACK)
#define __GFP_NOTRACK_FALSE_POSITIVE (__GFP_NOTRACK)
-#define __GFP_OTHER_NODE ((__force gfp_t)___GFP_OTHER_NODE)
/* Room for N __GFP_FOO bits */
-#define __GFP_BITS_SHIFT 26
+#define __GFP_BITS_SHIFT 25
#define __GFP_BITS_MASK ((__force gfp_t)((1 << __GFP_BITS_SHIFT) - 1))
/*
extern void free_hot_cold_page_list(struct list_head *list, bool cold);
struct page_frag_cache;
-extern void __page_frag_drain(struct page *page, unsigned int order,
- unsigned int count);
-extern void *__alloc_page_frag(struct page_frag_cache *nc,
- unsigned int fragsz, gfp_t gfp_mask);
-extern void __free_page_frag(void *addr);
+extern void __page_frag_cache_drain(struct page *page, unsigned int count);
+extern void *page_frag_alloc(struct page_frag_cache *nc,
+ unsigned int fragsz, gfp_t gfp_mask);
+extern void page_frag_free(void *addr);
#define __free_page(page) __free_pages((page), 0)
#define free_page(addr) free_pages((addr), 0)
struct irq_chip *irqchip,
int parent_irq);
-int _gpiochip_irqchip_add(struct gpio_chip *gpiochip,
+int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
+ struct irq_chip *irqchip,
+ unsigned int first_irq,
+ irq_flow_handler_t handler,
+ unsigned int type,
+ bool nested,
+ struct lock_class_key *lock_key);
+
+#ifdef CONFIG_LOCKDEP
+
+/*
+ * Lockdep requires that each irqchip instance be created with a
+ * unique key so as to avoid unnecessary warnings. This upfront
+ * boilerplate static inlines provides such a key for each
+ * unique instance.
+ */
+static inline int gpiochip_irqchip_add(struct gpio_chip *gpiochip,
+ struct irq_chip *irqchip,
+ unsigned int first_irq,
+ irq_flow_handler_t handler,
+ unsigned int type)
+{
+ static struct lock_class_key key;
+
+ return gpiochip_irqchip_add_key(gpiochip, irqchip, first_irq,
+ handler, type, false, &key);
+}
+
+static inline int gpiochip_irqchip_add_nested(struct gpio_chip *gpiochip,
struct irq_chip *irqchip,
unsigned int first_irq,
irq_flow_handler_t handler,
- unsigned int type,
- bool nested,
- struct lock_class_key *lock_key);
+ unsigned int type)
+{
+
+ static struct lock_class_key key;
+
+ return gpiochip_irqchip_add_key(gpiochip, irqchip, first_irq,
+ handler, type, true, &key);
+}
+#else
+static inline int gpiochip_irqchip_add(struct gpio_chip *gpiochip,
+ struct irq_chip *irqchip,
+ unsigned int first_irq,
+ irq_flow_handler_t handler,
+ unsigned int type)
+{
+ return gpiochip_irqchip_add_key(gpiochip, irqchip, first_irq,
+ handler, type, false, NULL);
+}
-/* FIXME: I assume threaded IRQchips do not have the lockdep problem */
static inline int gpiochip_irqchip_add_nested(struct gpio_chip *gpiochip,
struct irq_chip *irqchip,
unsigned int first_irq,
irq_flow_handler_t handler,
unsigned int type)
{
- return _gpiochip_irqchip_add(gpiochip, irqchip, first_irq,
- handler, type, true, NULL);
+ return gpiochip_irqchip_add_key(gpiochip, irqchip, first_irq,
+ handler, type, true, NULL);
}
-
-#ifdef CONFIG_LOCKDEP
-#define gpiochip_irqchip_add(...) \
-( \
- ({ \
- static struct lock_class_key _key; \
- _gpiochip_irqchip_add(__VA_ARGS__, false, &_key); \
- }) \
-)
-#else
-#define gpiochip_irqchip_add(...) \
- _gpiochip_irqchip_add(__VA_ARGS__, false, NULL)
-#endif
+#endif /* CONFIG_LOCKDEP */
#endif /* CONFIG_GPIOLIB_IRQCHIP */
atomic_t data_ready;
atomic_t user_requested_state;
struct iio_trigger *trigger;
+ int timestamp_ns_scale;
struct hid_sensor_hub_attribute_info poll;
struct hid_sensor_hub_attribute_info report_state;
struct hid_sensor_hub_attribute_info power_state;
s32 hid_sensor_read_poll_value(struct hid_sensor_common *st);
+int64_t hid_sensor_convert_timestamp(struct hid_sensor_common *st,
+ int64_t raw_value);
+
#endif
#define HID_USAGE_SENSOR_ANGL_VELOCITY_Y_AXIS 0x200458
#define HID_USAGE_SENSOR_ANGL_VELOCITY_Z_AXIS 0x200459
+/* Gravity vector */
+#define HID_USAGE_SENSOR_GRAVITY_VECTOR 0x20007B
+
/* ORIENTATION: Compass 3D: (200083) */
#define HID_USAGE_SENSOR_COMPASS_3D 0x200083
#define HID_USAGE_SENSOR_DATA_ORIENTATION 0x200470
#define HID_USAGE_SENSOR_TIME_HOUR 0x200525
#define HID_USAGE_SENSOR_TIME_MINUTE 0x200526
#define HID_USAGE_SENSOR_TIME_SECOND 0x200527
+#define HID_USAGE_SENSOR_TIME_TIMESTAMP 0x200529
/* Units */
#define HID_USAGE_SENSOR_UNITS_NOT_SPECIFIED 0x00
u32 ring_data_startoffset;
u32 priv_write_index;
u32 priv_read_index;
+ u32 cached_read_index;
};
/*
return write;
}
+static inline u32 hv_get_cached_bytes_to_write(
+ const struct hv_ring_buffer_info *rbi)
+{
+ u32 read_loc, write_loc, dsize, write;
+
+ dsize = rbi->ring_datasize;
+ read_loc = rbi->cached_read_index;
+ write_loc = rbi->ring_buffer->write_index;
+
+ write = write_loc >= read_loc ? dsize - (write_loc - read_loc) :
+ read_loc - write_loc;
+ return write;
+}
/*
* VMBUS version is 32 bit entity broken up into
* two 16 bit quantities: major_number. minor_number.
static inline void hv_signal_on_read(struct vmbus_channel *channel)
{
- u32 cur_write_sz;
+ u32 cur_write_sz, cached_write_sz;
u32 pending_sz;
struct hv_ring_buffer_info *rbi = &channel->inbound;
cur_write_sz = hv_get_bytes_to_write(rbi);
- if (cur_write_sz >= pending_sz)
+ if (cur_write_sz < pending_sz)
+ return;
+
+ cached_write_sz = hv_get_cached_bytes_to_write(rbi);
+ if (cached_write_sz < pending_sz)
vmbus_setevent(channel);
return;
}
+static inline void
+init_cached_read_index(struct vmbus_channel *channel)
+{
+ struct hv_ring_buffer_info *rbi = &channel->inbound;
+
+ rbi->cached_read_index = rbi->ring_buffer->read_index;
+}
+
/*
* An API to support in-place processing of incoming VMBUS packets.
*/
* This call commits the read index and potentially signals the host.
* Here is the pattern for using the "in-place" consumption APIs:
*
+ * init_cached_read_index();
+ *
* while (get_next_pkt_raw() {
* process the packet "in-place";
* put_pkt_raw();
#define I2C_CLIENT_TEN 0x10 /* we have a ten bit chip address */
/* Must equal I2C_M_TEN below */
#define I2C_CLIENT_SLAVE 0x20 /* we are the slave */
+#define I2C_CLIENT_HOST_NOTIFY 0x40 /* We want to use I2C host notify */
#define I2C_CLIENT_WAKE 0x80 /* for board_info; true iff can wake */
#define I2C_CLIENT_SCCB 0x9000 /* Use Omnivision SCCB protocol */
/* Must match I2C_M_STOP|IGNORE_NAK */
#define _IIO_BUFFER_GENERIC_H_
#include <linux/sysfs.h>
#include <linux/iio/iio.h>
-#include <linux/kref.h>
-
-#ifdef CONFIG_IIO_BUFFER
struct iio_buffer;
-/**
- * INDIO_BUFFER_FLAG_FIXED_WATERMARK - Watermark level of the buffer can not be
- * configured. It has a fixed value which will be buffer specific.
- */
-#define INDIO_BUFFER_FLAG_FIXED_WATERMARK BIT(0)
-
-/**
- * struct iio_buffer_access_funcs - access functions for buffers.
- * @store_to: actually store stuff to the buffer
- * @read_first_n: try to get a specified number of bytes (must exist)
- * @data_available: indicates how much data is available for reading from
- * the buffer.
- * @request_update: if a parameter change has been marked, update underlying
- * storage.
- * @set_bytes_per_datum:set number of bytes per datum
- * @set_length: set number of datums in buffer
- * @enable: called if the buffer is attached to a device and the
- * device starts sampling. Calls are balanced with
- * @disable.
- * @disable: called if the buffer is attached to a device and the
- * device stops sampling. Calles are balanced with @enable.
- * @release: called when the last reference to the buffer is dropped,
- * should free all resources allocated by the buffer.
- * @modes: Supported operating modes by this buffer type
- * @flags: A bitmask combination of INDIO_BUFFER_FLAG_*
- *
- * The purpose of this structure is to make the buffer element
- * modular as event for a given driver, different usecases may require
- * different buffer designs (space efficiency vs speed for example).
- *
- * It is worth noting that a given buffer implementation may only support a
- * small proportion of these functions. The core code 'should' cope fine with
- * any of them not existing.
- **/
-struct iio_buffer_access_funcs {
- int (*store_to)(struct iio_buffer *buffer, const void *data);
- int (*read_first_n)(struct iio_buffer *buffer,
- size_t n,
- char __user *buf);
- size_t (*data_available)(struct iio_buffer *buffer);
-
- int (*request_update)(struct iio_buffer *buffer);
-
- int (*set_bytes_per_datum)(struct iio_buffer *buffer, size_t bpd);
- int (*set_length)(struct iio_buffer *buffer, int length);
-
- int (*enable)(struct iio_buffer *buffer, struct iio_dev *indio_dev);
- int (*disable)(struct iio_buffer *buffer, struct iio_dev *indio_dev);
-
- void (*release)(struct iio_buffer *buffer);
-
- unsigned int modes;
- unsigned int flags;
-};
-
-/**
- * struct iio_buffer - general buffer structure
- * @length: [DEVICE] number of datums in buffer
- * @bytes_per_datum: [DEVICE] size of individual datum including timestamp
- * @scan_el_attrs: [DRIVER] control of scan elements if that scan mode
- * control method is used
- * @scan_mask: [INTERN] bitmask used in masking scan mode elements
- * @scan_timestamp: [INTERN] does the scan mode include a timestamp
- * @access: [DRIVER] buffer access functions associated with the
- * implementation.
- * @scan_el_dev_attr_list:[INTERN] list of scan element related attributes.
- * @buffer_group: [INTERN] attributes of the buffer group
- * @scan_el_group: [DRIVER] attribute group for those attributes not
- * created from the iio_chan_info array.
- * @pollq: [INTERN] wait queue to allow for polling on the buffer.
- * @stufftoread: [INTERN] flag to indicate new data.
- * @attrs: [INTERN] standard attributes of the buffer
- * @demux_list: [INTERN] list of operations required to demux the scan.
- * @demux_bounce: [INTERN] buffer for doing gather from incoming scan.
- * @buffer_list: [INTERN] entry in the devices list of current buffers.
- * @ref: [INTERN] reference count of the buffer.
- * @watermark: [INTERN] number of datums to wait for poll/read.
- */
-struct iio_buffer {
- int length;
- int bytes_per_datum;
- struct attribute_group *scan_el_attrs;
- long *scan_mask;
- bool scan_timestamp;
- const struct iio_buffer_access_funcs *access;
- struct list_head scan_el_dev_attr_list;
- struct attribute_group buffer_group;
- struct attribute_group scan_el_group;
- wait_queue_head_t pollq;
- bool stufftoread;
- const struct attribute **attrs;
- struct list_head demux_list;
- void *demux_bounce;
- struct list_head buffer_list;
- struct kref ref;
- unsigned int watermark;
-};
-
-/**
- * iio_update_buffers() - add or remove buffer from active list
- * @indio_dev: device to add buffer to
- * @insert_buffer: buffer to insert
- * @remove_buffer: buffer_to_remove
- *
- * Note this will tear down the all buffering and build it up again
- */
-int iio_update_buffers(struct iio_dev *indio_dev,
- struct iio_buffer *insert_buffer,
- struct iio_buffer *remove_buffer);
-
-/**
- * iio_buffer_init() - Initialize the buffer structure
- * @buffer: buffer to be initialized
- **/
-void iio_buffer_init(struct iio_buffer *buffer);
+void iio_buffer_set_attrs(struct iio_buffer *buffer,
+ const struct attribute **attrs);
-int iio_scan_mask_query(struct iio_dev *indio_dev,
- struct iio_buffer *buffer, int bit);
-
-/**
- * iio_push_to_buffers() - push to a registered buffer.
- * @indio_dev: iio_dev structure for device.
- * @data: Full scan.
- */
int iio_push_to_buffers(struct iio_dev *indio_dev, const void *data);
-/*
+/**
* iio_push_to_buffers_with_timestamp() - push data and timestamp to buffers
* @indio_dev: iio_dev structure for device.
* @data: sample data
return iio_push_to_buffers(indio_dev, data);
}
-int iio_update_demux(struct iio_dev *indio_dev);
-
bool iio_validate_scan_mask_onehot(struct iio_dev *indio_dev,
- const unsigned long *mask);
-
-struct iio_buffer *iio_buffer_get(struct iio_buffer *buffer);
-void iio_buffer_put(struct iio_buffer *buffer);
-
-/**
- * iio_device_attach_buffer - Attach a buffer to a IIO device
- * @indio_dev: The device the buffer should be attached to
- * @buffer: The buffer to attach to the device
- *
- * This function attaches a buffer to a IIO device. The buffer stays attached to
- * the device until the device is freed. The function should only be called at
- * most once per device.
- */
-static inline void iio_device_attach_buffer(struct iio_dev *indio_dev,
- struct iio_buffer *buffer)
-{
- indio_dev->buffer = iio_buffer_get(buffer);
-}
-
-#else /* CONFIG_IIO_BUFFER */
-
-static inline void iio_buffer_get(struct iio_buffer *buffer) {}
-static inline void iio_buffer_put(struct iio_buffer *buffer) {}
+ const unsigned long *mask);
-#endif /* CONFIG_IIO_BUFFER */
+void iio_device_attach_buffer(struct iio_dev *indio_dev,
+ struct iio_buffer *buffer);
#endif /* _IIO_BUFFER_GENERIC_H_ */
--- /dev/null
+#ifndef _IIO_BUFFER_GENERIC_IMPL_H_
+#define _IIO_BUFFER_GENERIC_IMPL_H_
+#include <linux/sysfs.h>
+#include <linux/kref.h>
+
+#ifdef CONFIG_IIO_BUFFER
+
+struct iio_dev;
+struct iio_buffer;
+
+/**
+ * INDIO_BUFFER_FLAG_FIXED_WATERMARK - Watermark level of the buffer can not be
+ * configured. It has a fixed value which will be buffer specific.
+ */
+#define INDIO_BUFFER_FLAG_FIXED_WATERMARK BIT(0)
+
+/**
+ * struct iio_buffer_access_funcs - access functions for buffers.
+ * @store_to: actually store stuff to the buffer
+ * @read_first_n: try to get a specified number of bytes (must exist)
+ * @data_available: indicates how much data is available for reading from
+ * the buffer.
+ * @request_update: if a parameter change has been marked, update underlying
+ * storage.
+ * @set_bytes_per_datum:set number of bytes per datum
+ * @set_length: set number of datums in buffer
+ * @enable: called if the buffer is attached to a device and the
+ * device starts sampling. Calls are balanced with
+ * @disable.
+ * @disable: called if the buffer is attached to a device and the
+ * device stops sampling. Calles are balanced with @enable.
+ * @release: called when the last reference to the buffer is dropped,
+ * should free all resources allocated by the buffer.
+ * @modes: Supported operating modes by this buffer type
+ * @flags: A bitmask combination of INDIO_BUFFER_FLAG_*
+ *
+ * The purpose of this structure is to make the buffer element
+ * modular as event for a given driver, different usecases may require
+ * different buffer designs (space efficiency vs speed for example).
+ *
+ * It is worth noting that a given buffer implementation may only support a
+ * small proportion of these functions. The core code 'should' cope fine with
+ * any of them not existing.
+ **/
+struct iio_buffer_access_funcs {
+ int (*store_to)(struct iio_buffer *buffer, const void *data);
+ int (*read_first_n)(struct iio_buffer *buffer,
+ size_t n,
+ char __user *buf);
+ size_t (*data_available)(struct iio_buffer *buffer);
+
+ int (*request_update)(struct iio_buffer *buffer);
+
+ int (*set_bytes_per_datum)(struct iio_buffer *buffer, size_t bpd);
+ int (*set_length)(struct iio_buffer *buffer, int length);
+
+ int (*enable)(struct iio_buffer *buffer, struct iio_dev *indio_dev);
+ int (*disable)(struct iio_buffer *buffer, struct iio_dev *indio_dev);
+
+ void (*release)(struct iio_buffer *buffer);
+
+ unsigned int modes;
+ unsigned int flags;
+};
+
+/**
+ * struct iio_buffer - general buffer structure
+ *
+ * Note that the internals of this structure should only be of interest to
+ * those writing new buffer implementations.
+ */
+struct iio_buffer {
+ /** @length: Number of datums in buffer. */
+ int length;
+
+ /** @bytes_per_datum: Size of individual datum including timestamp. */
+ int bytes_per_datum;
+
+ /**
+ * @access: Buffer access functions associated with the
+ * implementation.
+ */
+ const struct iio_buffer_access_funcs *access;
+
+ /** @scan_mask: Bitmask used in masking scan mode elements. */
+ long *scan_mask;
+
+ /** @demux_list: List of operations required to demux the scan. */
+ struct list_head demux_list;
+
+ /** @pollq: Wait queue to allow for polling on the buffer. */
+ wait_queue_head_t pollq;
+
+ /** @watermark: Number of datums to wait for poll/read. */
+ unsigned int watermark;
+
+ /* private: */
+ /*
+ * @scan_el_attrs: Control of scan elements if that scan mode
+ * control method is used.
+ */
+ struct attribute_group *scan_el_attrs;
+
+ /* @scan_timestamp: Does the scan mode include a timestamp. */
+ bool scan_timestamp;
+
+ /* @scan_el_dev_attr_list: List of scan element related attributes. */
+ struct list_head scan_el_dev_attr_list;
+
+ /* @buffer_group: Attributes of the buffer group. */
+ struct attribute_group buffer_group;
+
+ /*
+ * @scan_el_group: Attribute group for those attributes not
+ * created from the iio_chan_info array.
+ */
+ struct attribute_group scan_el_group;
+
+ /* @stufftoread: Flag to indicate new data. */
+ bool stufftoread;
+
+ /* @attrs: Standard attributes of the buffer. */
+ const struct attribute **attrs;
+
+ /* @demux_bounce: Buffer for doing gather from incoming scan. */
+ void *demux_bounce;
+
+ /* @buffer_list: Entry in the devices list of current buffers. */
+ struct list_head buffer_list;
+
+ /* @ref: Reference count of the buffer. */
+ struct kref ref;
+};
+
+/**
+ * iio_update_buffers() - add or remove buffer from active list
+ * @indio_dev: device to add buffer to
+ * @insert_buffer: buffer to insert
+ * @remove_buffer: buffer_to_remove
+ *
+ * Note this will tear down the all buffering and build it up again
+ */
+int iio_update_buffers(struct iio_dev *indio_dev,
+ struct iio_buffer *insert_buffer,
+ struct iio_buffer *remove_buffer);
+
+/**
+ * iio_buffer_init() - Initialize the buffer structure
+ * @buffer: buffer to be initialized
+ **/
+void iio_buffer_init(struct iio_buffer *buffer);
+
+struct iio_buffer *iio_buffer_get(struct iio_buffer *buffer);
+void iio_buffer_put(struct iio_buffer *buffer);
+
+#else /* CONFIG_IIO_BUFFER */
+
+static inline void iio_buffer_get(struct iio_buffer *buffer) {}
+static inline void iio_buffer_put(struct iio_buffer *buffer) {}
+
+#endif /* CONFIG_IIO_BUFFER */
+#endif /* _IIO_BUFFER_GENERIC_IMPL_H_ */
}
#endif
+#ifdef CONFIG_ACPI
+int st_sensors_match_acpi_device(struct device *dev);
+#else
+static inline int st_sensors_match_acpi_device(struct device *dev)
+{
+ return -ENODEV;
+}
+#endif
+
#endif /* ST_SENSORS_I2C_H */
#ifndef __LINUX_IIO_KFIFO_BUF_H__
#define __LINUX_IIO_KFIFO_BUF_H__
-#include <linux/kfifo.h>
-#include <linux/iio/iio.h>
-#include <linux/iio/buffer.h>
+struct iio_buffer;
+struct device;
struct iio_buffer *iio_kfifo_allocate(void);
void iio_kfifo_free(struct iio_buffer *r);
--- /dev/null
+/*
+ * Copyright (C) STMicroelectronics 2016
+ *
+ * Author: Benjamin Gaignard <benjamin.gaignard@st.com>
+ *
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#ifndef _STM32_TIMER_TRIGGER_H_
+#define _STM32_TIMER_TRIGGER_H_
+
+#define TIM1_TRGO "tim1_trgo"
+#define TIM1_CH1 "tim1_ch1"
+#define TIM1_CH2 "tim1_ch2"
+#define TIM1_CH3 "tim1_ch3"
+#define TIM1_CH4 "tim1_ch4"
+
+#define TIM2_TRGO "tim2_trgo"
+#define TIM2_CH1 "tim2_ch1"
+#define TIM2_CH2 "tim2_ch2"
+#define TIM2_CH3 "tim2_ch3"
+#define TIM2_CH4 "tim2_ch4"
+
+#define TIM3_TRGO "tim3_trgo"
+#define TIM3_CH1 "tim3_ch1"
+#define TIM3_CH2 "tim3_ch2"
+#define TIM3_CH3 "tim3_ch3"
+#define TIM3_CH4 "tim3_ch4"
+
+#define TIM4_TRGO "tim4_trgo"
+#define TIM4_CH1 "tim4_ch1"
+#define TIM4_CH2 "tim4_ch2"
+#define TIM4_CH3 "tim4_ch3"
+#define TIM4_CH4 "tim4_ch4"
+
+#define TIM5_TRGO "tim5_trgo"
+#define TIM5_CH1 "tim5_ch1"
+#define TIM5_CH2 "tim5_ch2"
+#define TIM5_CH3 "tim5_ch3"
+#define TIM5_CH4 "tim5_ch4"
+
+#define TIM6_TRGO "tim6_trgo"
+
+#define TIM7_TRGO "tim7_trgo"
+
+#define TIM8_TRGO "tim8_trgo"
+#define TIM8_CH1 "tim8_ch1"
+#define TIM8_CH2 "tim8_ch2"
+#define TIM8_CH3 "tim8_ch3"
+#define TIM8_CH4 "tim8_ch4"
+
+#define TIM9_TRGO "tim9_trgo"
+#define TIM9_CH1 "tim9_ch1"
+#define TIM9_CH2 "tim9_ch2"
+
+#define TIM12_TRGO "tim12_trgo"
+#define TIM12_CH1 "tim12_ch1"
+#define TIM12_CH2 "tim12_ch2"
+
+bool is_stm32_timer_trigger(struct iio_trigger *trig);
+
+#endif
*
* IRQD_TRIGGER_MASK - Mask for the trigger type bits
* IRQD_SETAFFINITY_PENDING - Affinity setting is pending
+ * IRQD_ACTIVATED - Interrupt has already been activated
* IRQD_NO_BALANCING - Balancing disabled for this IRQ
* IRQD_PER_CPU - Interrupt is per cpu
* IRQD_AFFINITY_SET - Interrupt affinity was set
enum {
IRQD_TRIGGER_MASK = 0xf,
IRQD_SETAFFINITY_PENDING = (1 << 8),
+ IRQD_ACTIVATED = (1 << 9),
IRQD_NO_BALANCING = (1 << 10),
IRQD_PER_CPU = (1 << 11),
IRQD_AFFINITY_SET = (1 << 12),
return __irqd_to_state(d) & IRQD_AFFINITY_MANAGED;
}
+static inline bool irqd_is_activated(struct irq_data *d)
+{
+ return __irqd_to_state(d) & IRQD_ACTIVATED;
+}
+
+static inline void irqd_set_activated(struct irq_data *d)
+{
+ __irqd_to_state(d) |= IRQD_ACTIVATED;
+}
+
+static inline void irqd_clr_activated(struct irq_data *d)
+{
+ __irqd_to_state(d) &= ~IRQD_ACTIVATED;
+}
+
#undef __irqd_to_state
static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d)
#ifdef HAVE_JUMP_LABEL
extern void static_key_slow_dec_deferred(struct static_key_deferred *key);
+extern void static_key_deferred_flush(struct static_key_deferred *key);
extern void
jump_label_rate_limit(struct static_key_deferred *key, unsigned long rl);
STATIC_KEY_CHECK_USE();
static_key_slow_dec(&key->key);
}
+static inline void static_key_deferred_flush(struct static_key_deferred *key)
+{
+ STATIC_KEY_CHECK_USE();
+}
static inline void
jump_label_rate_limit(struct static_key_deferred *key,
unsigned long rl)
#define TAINT_FLAGS_COUNT 16
struct taint_flag {
- char true; /* character printed when tainted */
- char false; /* character printed when not tainted */
+ char c_true; /* character printed when tainted */
+ char c_false; /* character printed when not tainted */
bool module; /* also show as a per-module taint flag */
};
* ... and so on.
*/
-#define order_base_2(n) ilog2(roundup_pow_of_two(n))
+static inline __attribute_const__
+int __order_base_2(unsigned long n)
+{
+ return n > 1 ? ilog2(n - 1) + 1 : 0;
+}
+#define order_base_2(n) \
+( \
+ __builtin_constant_p(n) ? ( \
+ ((n) == 0 || (n) == 1) ? 0 : \
+ ilog2((n) - 1) + 1) : \
+ __order_base_2(n) \
+)
#endif /* _LINUX_LOG2_H */
*/
struct mem_cgroup_per_node {
struct lruvec lruvec;
- unsigned long lru_size[NR_LRU_LISTS];
+ unsigned long lru_zone_size[MAX_NR_ZONES][NR_LRU_LISTS];
struct mem_cgroup_reclaim_iter iter[DEF_PRIORITY + 1];
int mem_cgroup_select_victim_node(struct mem_cgroup *memcg);
void mem_cgroup_update_lru_size(struct lruvec *lruvec, enum lru_list lru,
- int nr_pages);
+ int zid, int nr_pages);
unsigned long mem_cgroup_node_nr_lru_pages(struct mem_cgroup *memcg,
int nid, unsigned int lru_mask);
unsigned long mem_cgroup_get_lru_size(struct lruvec *lruvec, enum lru_list lru)
{
struct mem_cgroup_per_node *mz;
+ unsigned long nr_pages = 0;
+ int zid;
mz = container_of(lruvec, struct mem_cgroup_per_node, lruvec);
- return mz->lru_size[lru];
+ for (zid = 0; zid < MAX_NR_ZONES; zid++)
+ nr_pages += mz->lru_zone_size[zid][lru];
+ return nr_pages;
+}
+
+static inline
+unsigned long mem_cgroup_get_zone_lru_size(struct lruvec *lruvec,
+ enum lru_list lru, int zone_idx)
+{
+ struct mem_cgroup_per_node *mz;
+
+ mz = container_of(lruvec, struct mem_cgroup_per_node, lruvec);
+ return mz->lru_zone_size[zone_idx][lru];
}
void mem_cgroup_handle_over_high(void);
{
return 0;
}
+static inline
+unsigned long mem_cgroup_get_zone_lru_size(struct lruvec *lruvec,
+ enum lru_list lru, int zone_idx)
+{
+ return 0;
+}
static inline unsigned long
mem_cgroup_node_nr_lru_pages(struct mem_cgroup *memcg,
extern int add_one_highpage(struct page *page, int pfn, int bad_ppro);
/* VM interface that may be used by firmware interface */
extern int online_pages(unsigned long, unsigned long, int);
-extern int test_pages_in_a_zone(unsigned long, unsigned long);
+extern int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn,
+ unsigned long *valid_start, unsigned long *valid_end);
extern void __offline_isolated_pages(unsigned long, unsigned long);
typedef void (*online_page_callback_t)(struct page *page);
unsigned long map_offset);
extern struct page *sparse_decode_mem_map(unsigned long coded_mem_map,
unsigned long pnum);
-extern int zone_can_shift(unsigned long pfn, unsigned long nr_pages,
- enum zone_type target);
+extern bool zone_can_shift(unsigned long pfn, unsigned long nr_pages,
+ enum zone_type target, int *zone_shift);
#endif /* __LINUX_MEMORY_HOTPLUG_H */
MOTIONSENSE_TYPE_PROX = 3,
MOTIONSENSE_TYPE_LIGHT = 4,
MOTIONSENSE_TYPE_ACTIVITY = 5,
- MOTIONSENSE_TYPE_MAX
+ MOTIONSENSE_TYPE_BARO = 6,
+ MOTIONSENSE_TYPE_MAX,
};
/* List of motion sensor locations. */
--- /dev/null
+/*
+ * Copyright (C) STMicroelectronics 2016
+ *
+ * Author: Benjamin Gaignard <benjamin.gaignard@st.com>
+ *
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#ifndef _LINUX_STM32_GPTIMER_H_
+#define _LINUX_STM32_GPTIMER_H_
+
+#include <linux/clk.h>
+#include <linux/regmap.h>
+
+#define TIM_CR1 0x00 /* Control Register 1 */
+#define TIM_CR2 0x04 /* Control Register 2 */
+#define TIM_SMCR 0x08 /* Slave mode control reg */
+#define TIM_DIER 0x0C /* DMA/interrupt register */
+#define TIM_SR 0x10 /* Status register */
+#define TIM_EGR 0x14 /* Event Generation Reg */
+#define TIM_CCMR1 0x18 /* Capt/Comp 1 Mode Reg */
+#define TIM_CCMR2 0x1C /* Capt/Comp 2 Mode Reg */
+#define TIM_CCER 0x20 /* Capt/Comp Enable Reg */
+#define TIM_PSC 0x28 /* Prescaler */
+#define TIM_ARR 0x2c /* Auto-Reload Register */
+#define TIM_CCR1 0x34 /* Capt/Comp Register 1 */
+#define TIM_CCR2 0x38 /* Capt/Comp Register 2 */
+#define TIM_CCR3 0x3C /* Capt/Comp Register 3 */
+#define TIM_CCR4 0x40 /* Capt/Comp Register 4 */
+#define TIM_BDTR 0x44 /* Break and Dead-Time Reg */
+
+#define TIM_CR1_CEN BIT(0) /* Counter Enable */
+#define TIM_CR1_ARPE BIT(7) /* Auto-reload Preload Ena */
+#define TIM_CR2_MMS (BIT(4) | BIT(5) | BIT(6)) /* Master mode selection */
+#define TIM_SMCR_SMS (BIT(0) | BIT(1) | BIT(2)) /* Slave mode selection */
+#define TIM_SMCR_TS (BIT(4) | BIT(5) | BIT(6)) /* Trigger selection */
+#define TIM_DIER_UIE BIT(0) /* Update interrupt */
+#define TIM_SR_UIF BIT(0) /* Update interrupt flag */
+#define TIM_EGR_UG BIT(0) /* Update Generation */
+#define TIM_CCMR_PE BIT(3) /* Channel Preload Enable */
+#define TIM_CCMR_M1 (BIT(6) | BIT(5)) /* Channel PWM Mode 1 */
+#define TIM_CCER_CC1E BIT(0) /* Capt/Comp 1 out Ena */
+#define TIM_CCER_CC1P BIT(1) /* Capt/Comp 1 Polarity */
+#define TIM_CCER_CC1NE BIT(2) /* Capt/Comp 1N out Ena */
+#define TIM_CCER_CC1NP BIT(3) /* Capt/Comp 1N Polarity */
+#define TIM_CCER_CC2E BIT(4) /* Capt/Comp 2 out Ena */
+#define TIM_CCER_CC3E BIT(8) /* Capt/Comp 3 out Ena */
+#define TIM_CCER_CC4E BIT(12) /* Capt/Comp 4 out Ena */
+#define TIM_CCER_CCXE (BIT(0) | BIT(4) | BIT(8) | BIT(12))
+#define TIM_BDTR_BKE BIT(12) /* Break input enable */
+#define TIM_BDTR_BKP BIT(13) /* Break input polarity */
+#define TIM_BDTR_AOE BIT(14) /* Automatic Output Enable */
+#define TIM_BDTR_MOE BIT(15) /* Main Output Enable */
+#define TIM_BDTR_BKF (BIT(16) | BIT(17) | BIT(18) | BIT(19))
+#define TIM_BDTR_BK2F (BIT(20) | BIT(21) | BIT(22) | BIT(23))
+#define TIM_BDTR_BK2E BIT(24) /* Break 2 input enable */
+#define TIM_BDTR_BK2P BIT(25) /* Break 2 input polarity */
+
+#define MAX_TIM_PSC 0xFFFF
+#define TIM_CR2_MMS_SHIFT 4
+#define TIM_SMCR_TS_SHIFT 4
+#define TIM_BDTR_BKF_MASK 0xF
+#define TIM_BDTR_BKF_SHIFT 16
+#define TIM_BDTR_BK2F_SHIFT 20
+
+struct stm32_timers {
+ struct clk *clk;
+ struct regmap *regmap;
+ u32 max_arr;
+};
+#endif
#define PHY_ID_KSZ886X 0x00221430
#define PHY_ID_KSZ8863 0x00221435
+#define PHY_ID_KSZ8795 0x00221550
+
/* struct phy_device dev_flags definitions */
#define MICREL_PHY_50MHZ_CLK 0x00000001
#define MICREL_PHY_FXEN 0x00000002
struct vm_area_struct *vma);
void unmap_mapping_range(struct address_space *mapping,
loff_t const holebegin, loff_t const holelen, int even_cows);
-int follow_pte(struct mm_struct *mm, unsigned long address, pte_t **ptepp,
- spinlock_t **ptlp);
+int follow_pte_pmd(struct mm_struct *mm, unsigned long address,
+ pte_t **ptepp, pmd_t **pmdpp, spinlock_t **ptlp);
int follow_pfn(struct vm_area_struct *vma, unsigned long address,
unsigned long *pfn);
int follow_phys(struct vm_area_struct *vma, unsigned long address,
{
__update_lru_size(lruvec, lru, zid, nr_pages);
#ifdef CONFIG_MEMCG
- mem_cgroup_update_lru_size(lruvec, lru, nr_pages);
+ mem_cgroup_update_lru_size(lruvec, lru, zid, nr_pages);
#endif
}
* @zonelist - The zonelist to search for a suitable zone
* @highest_zoneidx - The zone index of the highest zone to return
* @nodes - An optional nodemask to filter the zonelist with
- * @zone - The first suitable zone found is returned via this parameter
+ * @return - Zoneref pointer for the first suitable zone found (see below)
*
* This function returns the first zone at or below a given zone index that is
* within the allowed nodemask. The zoneref returned is a cursor that can be
* used to iterate the zonelist with next_zones_zonelist by advancing it by
* one before calling.
+ *
+ * When no eligible zone is found, zoneref->zone is NULL (zoneref itself is
+ * never NULL). This may happen either genuinely, or due to concurrent nodemask
+ * update due to cpuset modification.
*/
static inline struct zoneref *first_zones_zonelist(struct zonelist *zonelist,
enum zone_type highest_zoneidx,
/* Exported symbols */
const struct kernel_symbol *syms;
- const unsigned long *crcs;
+ const s32 *crcs;
unsigned int num_syms;
/* Kernel parameters. */
/* GPL-only exported symbols. */
unsigned int num_gpl_syms;
const struct kernel_symbol *gpl_syms;
- const unsigned long *gpl_crcs;
+ const s32 *gpl_crcs;
#ifdef CONFIG_UNUSED_SYMBOLS
/* unused exported symbols. */
const struct kernel_symbol *unused_syms;
- const unsigned long *unused_crcs;
+ const s32 *unused_crcs;
unsigned int num_unused_syms;
/* GPL-only, unused exported symbols. */
unsigned int num_unused_gpl_syms;
const struct kernel_symbol *unused_gpl_syms;
- const unsigned long *unused_gpl_crcs;
+ const s32 *unused_gpl_crcs;
#endif
#ifdef CONFIG_MODULE_SIG
/* symbols that will be GPL-only in the near future. */
const struct kernel_symbol *gpl_future_syms;
- const unsigned long *gpl_future_crcs;
+ const s32 *gpl_future_crcs;
unsigned int num_gpl_future_syms;
/* Exception table */
struct symsearch {
const struct kernel_symbol *start, *stop;
- const unsigned long *crcs;
+ const s32 *crcs;
enum {
NOT_GPL_ONLY,
GPL_ONLY,
*/
const struct kernel_symbol *find_symbol(const char *name,
struct module **owner,
- const unsigned long **crc,
+ const s32 **crc,
bool gplok,
bool warn);
* of useless work if you return NETDEV_TX_BUSY.
* Required; cannot be NULL.
*
- * netdev_features_t (*ndo_fix_features)(struct net_device *dev,
- * netdev_features_t features);
- * Adjusts the requested feature flags according to device-specific
- * constraints, and returns the resulting flags. Must not modify
- * the device state.
+ * netdev_features_t (*ndo_features_check)(struct sk_buff *skb,
+ * struct net_device *dev
+ * netdev_features_t features);
+ * Called by core transmit path to determine if device is capable of
+ * performing offload operations on a given packet. This is to give
+ * the device an opportunity to implement any restrictions that cannot
+ * be otherwise expressed by feature flags. The check is called with
+ * the set of features that the stack has calculated and it returns
+ * those the driver believes to be appropriate.
*
* u16 (*ndo_select_queue)(struct net_device *dev, struct sk_buff *skb,
* void *accel_priv, select_queue_fallback_t fallback);
* Called to release previously enslaved netdev.
*
* Feature/offload setting functions.
+ * netdev_features_t (*ndo_fix_features)(struct net_device *dev,
+ * netdev_features_t features);
+ * Adjusts the requested feature flags according to device-specific
+ * constraints, and returns the resulting flags. Must not modify
+ * the device state.
+ *
* int (*ndo_set_features)(struct net_device *dev, netdev_features_t features);
* Called to update device configuration to new features. Passed
* feature set might be less than what was returned by ndo_fix_features()).
* Callback to use for xmit over the accelerated station. This
* is used in place of ndo_start_xmit on accelerated net
* devices.
- * netdev_features_t (*ndo_features_check)(struct sk_buff *skb,
- * struct net_device *dev
- * netdev_features_t features);
- * Called by core transmit path to determine if device is capable of
- * performing offload operations on a given packet. This is to give
- * the device an opportunity to implement any restrictions that cannot
- * be otherwise expressed by feature flags. The check is called with
- * the set of features that the stack has calculated and it returns
- * those the driver believes to be appropriate.
* int (*ndo_set_tx_maxrate)(struct net_device *dev,
* int queue_index, u32 maxrate);
* Called when a user wants to set a max-rate limitation of specific
return NAPI_GRO_CB(skb)->frag0_len < hlen;
}
+static inline void skb_gro_frag0_invalidate(struct sk_buff *skb)
+{
+ NAPI_GRO_CB(skb)->frag0 = NULL;
+ NAPI_GRO_CB(skb)->frag0_len = 0;
+}
+
static inline void *skb_gro_header_slow(struct sk_buff *skb, unsigned int hlen,
unsigned int offset)
{
if (!pskb_may_pull(skb, hlen))
return NULL;
- NAPI_GRO_CB(skb)->frag0 = NULL;
- NAPI_GRO_CB(skb)->frag0_len = 0;
+ skb_gro_frag0_invalidate(skb);
return skb->data + offset;
}
static inline bool seqid_mutating_err(u32 err)
{
- /* rfc 3530 section 8.1.5: */
+ /* See RFC 7530, section 9.1.7 */
switch (err) {
case NFS4ERR_STALE_CLIENTID:
case NFS4ERR_STALE_STATEID:
case NFS4ERR_BADXDR:
case NFS4ERR_RESOURCE:
case NFS4ERR_NOFILEHANDLE:
+ case NFS4ERR_MOVED:
return false;
};
return true;
extern int watchdog_thresh;
extern unsigned long watchdog_enabled;
extern unsigned long *watchdog_cpumask_bits;
+extern atomic_t watchdog_park_in_progress;
#ifdef CONFIG_SMP
extern int sysctl_softlockup_all_cpu_backtrace;
extern int sysctl_hardlockup_all_cpu_backtrace;
static inline bool percpu_ref_tryget(struct percpu_ref *ref)
{
unsigned long __percpu *percpu_count;
- int ret;
+ bool ret;
rcu_read_lock_sched();
static inline bool percpu_ref_tryget_live(struct percpu_ref *ref)
{
unsigned long __percpu *percpu_count;
- int ret = false;
+ bool ret = false;
rcu_read_lock_sched();
extern void perf_event_disable_local(struct perf_event *event);
extern void perf_event_disable_inatomic(struct perf_event *event);
extern void perf_event_task_tick(void);
+extern int perf_event_account_interrupt(struct perf_event *event);
#else /* !CONFIG_PERF_EVENTS: */
static inline void *
perf_aux_output_begin(struct perf_output_handle *handle,
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <linux/mod_devicetable.h>
-#include <linux/phy_led_triggers.h>
#include <linux/atomic.h>
#ifdef CONFIG_LED_TRIGGER_PHY
#include <linux/leds.h>
+#include <linux/phy.h>
#define PHY_LED_TRIGGER_SPEED_SUFFIX_SIZE 10
-#define PHY_MII_BUS_ID_SIZE (20 - 3)
-#define PHY_LINK_LED_TRIGGER_NAME_SIZE (PHY_MII_BUS_ID_SIZE + \
+#define PHY_LINK_LED_TRIGGER_NAME_SIZE (MII_BUS_ID_SIZE + \
FIELD_SIZEOF(struct mdio_device, addr)+\
PHY_LED_TRIGGER_SPEED_SUFFIX_SIZE)
#error "Unknown RCU implementation specified to kernel configuration"
#endif
+#define RCU_SCHEDULER_INACTIVE 0
+#define RCU_SCHEDULER_INIT 1
+#define RCU_SCHEDULER_RUNNING 2
+
/*
* init_rcu_head_on_stack()/destroy_rcu_head_on_stack() are needed for dynamic
* initialization and destruction of rcu_head on the stack. rcu_head structures
* @crash_comp: completion used to sync crash handler and the rproc reload
* @recovery_disabled: flag that state if recovery was disabled
* @max_notifyid: largest allocated notify id.
- * @table_ptr: our copy of the resource table
+ * @table_ptr: pointer to the resource table in effect
+ * @cached_table: copy of the resource table
* @has_iommu: flag to indicate if remote processor is behind an MMU
*/
struct rproc {
bool recovery_disabled;
int max_notifyid;
struct resource_table *table_ptr;
+ struct resource_table *cached_table;
bool has_iommu;
bool auto_boot;
};
#define SIGNAL_UNKILLABLE 0x00000040 /* for init: ignore fatal signals */
+#define SIGNAL_STOP_MASK (SIGNAL_CLD_MASK | SIGNAL_STOP_STOPPED | \
+ SIGNAL_STOP_CONTINUED)
+
+static inline void signal_set_stop_flags(struct signal_struct *sig,
+ unsigned int flags)
+{
+ WARN_ON(sig->flags & (SIGNAL_GROUP_EXIT|SIGNAL_GROUP_COREDUMP));
+ sig->flags = (sig->flags & ~SIGNAL_STOP_MASK) | flags;
+}
+
/* If true, all threads except ->group_exit_task have pending SIGKILL */
static inline int signal_group_exit(const struct signal_struct *sig)
{
static inline void skb_free_frag(void *addr)
{
- __free_page_frag(addr);
+ page_frag_free(addr);
}
void *napi_alloc_frag(unsigned int fragsz);
* (PAGE_SIZE*2). Larger requests are passed to the page allocator.
*/
#define KMALLOC_SHIFT_HIGH (PAGE_SHIFT + 1)
-#define KMALLOC_SHIFT_MAX (MAX_ORDER + PAGE_SHIFT)
+#define KMALLOC_SHIFT_MAX (MAX_ORDER + PAGE_SHIFT - 1)
#ifndef KMALLOC_SHIFT_LOW
#define KMALLOC_SHIFT_LOW 3
#endif
* be allocated from the same page.
*/
#define KMALLOC_SHIFT_HIGH PAGE_SHIFT
-#define KMALLOC_SHIFT_MAX 30
+#define KMALLOC_SHIFT_MAX (MAX_ORDER + PAGE_SHIFT - 1)
#ifndef KMALLOC_SHIFT_LOW
#define KMALLOC_SHIFT_LOW 3
#endif
void rpc_clnt_xprt_switch_add_xprt(struct rpc_clnt *, struct rpc_xprt *);
bool rpc_clnt_xprt_switch_has_addr(struct rpc_clnt *clnt,
const struct sockaddr *sap);
+void rpc_cleanup_clids(void);
#endif /* __KERNEL__ */
#endif /* _LINUX_SUNRPC_CLNT_H */
#define XPT_LISTENER 10 /* listening endpoint */
#define XPT_CACHE_AUTH 11 /* cache auth info */
#define XPT_LOCAL 12 /* connection from loopback interface */
+#define XPT_KILL_TEMP 13 /* call xpo_kill_temp_xprt before closing */
struct svc_serv *xpt_server; /* service for transport */
atomic_t xpt_reserved; /* space on outq that is rsvd */
};
#ifdef CONFIG_SUSPEND
-extern suspend_state_t mem_sleep_default;
-
/**
* suspend_set_ops - set platform dependent suspend operations
* @ops: The new suspend operations to set.
SWP_FILE = (1 << 7), /* set after swap_activate success */
SWP_AREA_DISCARD = (1 << 8), /* single-time swap area discards */
SWP_PAGE_DISCARD = (1 << 9), /* freed swap page-cluster discards */
+ SWP_STABLE_WRITES = (1 << 10), /* no overwrite PG_writeback pages */
/* add others here before... */
- SWP_SCANNING = (1 << 10), /* refcount in scan_swap_map */
+ SWP_SCANNING = (1 << 11), /* refcount in scan_swap_map */
};
#define SWAP_CLUSTER_MAX 32UL
/* TCP Fast Open Cookie as stored in memory */
struct tcp_fastopen_cookie {
+ union {
+ u8 val[TCP_FASTOPEN_COOKIE_MAX];
+#if IS_ENABLED(CONFIG_IPV6)
+ struct in6_addr addr;
+#endif
+ };
s8 len;
- u8 val[TCP_FASTOPEN_COOKIE_MAX];
bool exp; /* In RFC6994 experimental option format */
};
#ifndef _LINUX_TIMERFD_H
#define _LINUX_TIMERFD_H
-/* For O_CLOEXEC and O_NONBLOCK */
-#include <linux/fcntl.h>
-
-/* For _IO helpers */
-#include <linux/ioctl.h>
-
-/*
- * CAREFUL: Check include/asm-generic/fcntl.h when defining
- * new flags, since they might collide with O_* ones. We want
- * to re-use O_* flags that couldn't possibly have a meaning
- * from eventfd, in order to leave a free define-space for
- * shared O_* flags.
- */
-#define TFD_TIMER_ABSTIME (1 << 0)
-#define TFD_TIMER_CANCEL_ON_SET (1 << 1)
-#define TFD_CLOEXEC O_CLOEXEC
-#define TFD_NONBLOCK O_NONBLOCK
+#include <uapi/linux/timerfd.h>
#define TFD_SHARED_FCNTL_FLAGS (TFD_CLOEXEC | TFD_NONBLOCK)
/* Flags for timerfd_create. */
/* Flags for timerfd_settime. */
#define TFD_SETTIME_FLAGS (TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET)
-#define TFD_IOC_SET_TICKS _IOW('T', 0, u64)
-
#endif /* _LINUX_TIMERFD_H */
static inline int virtio_net_hdr_from_skb(const struct sk_buff *skb,
struct virtio_net_hdr *hdr,
- bool little_endian)
+ bool little_endian,
+ bool has_data_valid)
{
memset(hdr, 0, sizeof(*hdr)); /* no info leak */
skb_checksum_start_offset(skb));
hdr->csum_offset = __cpu_to_virtio16(little_endian,
skb->csum_offset);
- } else if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
+ } else if (has_data_valid &&
+ skb->ip_summed == CHECKSUM_UNNECESSARY) {
hdr->flags = VIRTIO_NET_HDR_F_DATA_VALID;
} /* else everything is zero */
{
u32 hash;
+ /* @flowlabel may include more than a flow label, eg, the traffic class.
+ * Here we want only the flow label value.
+ */
+ flowlabel &= IPV6_FLOWLABEL_MASK;
+
if (flowlabel ||
net->ipv6.sysctl.auto_flowlabels == IP6_AUTO_FLOW_LABEL_OFF ||
(!autolabel &&
* upper-layer output functions
*/
int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
- struct ipv6_txoptions *opt, int tclass);
+ __u32 mark, struct ipv6_txoptions *opt, int tclass);
int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr);
int (*get_encap_size)(struct lwtunnel_state *lwtstate);
int (*cmp_encap)(struct lwtunnel_state *a, struct lwtunnel_state *b);
int (*xmit)(struct sk_buff *skb);
+
+ struct module *owner;
};
#ifdef CONFIG_LWTUNNEL
unsigned int num);
int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *op,
unsigned int num);
+int lwtunnel_valid_encap_type(u16 encap_type);
+int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int len);
int lwtunnel_build_state(struct net_device *dev, u16 encap_type,
struct nlattr *encap,
unsigned int family, const void *cfg,
return -EOPNOTSUPP;
}
+static inline int lwtunnel_valid_encap_type(u16 encap_type)
+{
+ return -EOPNOTSUPP;
+}
+static inline int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int len)
+{
+ return -EOPNOTSUPP;
+}
+
static inline int lwtunnel_build_state(struct net_device *dev, u16 encap_type,
struct nlattr *encap,
unsigned int family, const void *cfg,
unsigned int skip;
int err;
int (*fn)(const struct nft_ctx *ctx,
- const struct nft_set *set,
+ struct nft_set *set,
const struct nft_set_iter *iter,
- const struct nft_set_elem *elem);
+ struct nft_set_elem *elem);
};
/**
void (*remove)(const struct nft_set *set,
const struct nft_set_elem *elem);
void (*walk)(const struct nft_ctx *ctx,
- const struct nft_set *set,
+ struct nft_set *set,
struct nft_set_iter *iter);
unsigned int (*privsize)(const struct nlattr * const nla[]);
extern const struct nla_policy nft_fib_policy[];
+static inline bool
+nft_fib_is_loopback(const struct sk_buff *skb, const struct net_device *in)
+{
+ return skb->pkt_type == PACKET_LOOPBACK || in->flags & IFF_LOOPBACK;
+}
+
int nft_fib_dump(struct sk_buff *skb, const struct nft_expr *expr);
int nft_fib_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
const struct nlattr * const tb[]);
}
}
+static inline enum ib_mtu ib_mtu_int_to_enum(int mtu)
+{
+ if (mtu >= 4096)
+ return IB_MTU_4096;
+ else if (mtu >= 2048)
+ return IB_MTU_2048;
+ else if (mtu >= 1024)
+ return IB_MTU_1024;
+ else if (mtu >= 512)
+ return IB_MTU_512;
+ else
+ return IB_MTU_256;
+}
+
enum ib_port_state {
IB_PORT_NOP = 0,
IB_PORT_DOWN = 1,
/**
* fc_set_wwpn() - Set the World Wide Port Name of a local port
* @lport: The local port whose WWPN is to be set
- * @wwnn: The new WWPN
+ * @wwpn: The new WWPN
*/
-static inline void fc_set_wwpn(struct fc_lport *lport, u64 wwnn)
+static inline void fc_set_wwpn(struct fc_lport *lport, u64 wwpn)
{
- lport->wwpn = wwnn;
+ lport->wwpn = wwpn;
}
/**
struct mcip_bcr {
#ifdef CONFIG_CPU_BIG_ENDIAN
- unsigned int pad3:8,
- idu:1, llm:1, num_cores:6,
- iocoh:1, gfrc:1, dbg:1, pad2:1,
- msg:1, sem:1, ipi:1, pad:1,
+ unsigned int pad4:6, pw_dom:1, pad3:1,
+ idu:1, pad2:1, num_cores:6,
+ pad:1, gfrc:1, dbg:1, pw:1,
+ msg:1, sem:1, ipi:1, slv:1,
ver:8;
#else
unsigned int ver:8,
- pad:1, ipi:1, sem:1, msg:1,
- pad2:1, dbg:1, gfrc:1, iocoh:1,
- num_cores:6, llm:1, idu:1,
- pad3:8;
+ slv:1, ipi:1, sem:1, msg:1,
+ pw:1, dbg:1, gfrc:1, pad:1,
+ num_cores:6, pad2:1, idu:1,
+ pad3:1, pw_dom:1, pad4:6;
#endif
};
HDMI_AC97,
HDMI_SPDIF,
} fmt;
- int bit_clk_inv:1;
- int frame_clk_inv:1;
- int bit_clk_master:1;
- int frame_clk_master:1;
+ unsigned int bit_clk_inv:1;
+ unsigned int frame_clk_inv:1;
+ unsigned int bit_clk_master:1;
+ unsigned int frame_clk_master:1;
};
/*
unsigned int suspended:1; /* is in suspend PM state */
struct list_head list;
+ struct list_head card_aux_list; /* for auxiliary bound components */
struct list_head card_list;
struct snd_soc_dai_driver *dai_drv;
*/
struct snd_soc_aux_dev *aux_dev;
int num_aux_devs;
+ struct list_head aux_comp_list;
const struct snd_kcontrol_new *controls;
int num_controls;
INIT_LIST_HEAD(&card->widgets);
INIT_LIST_HEAD(&card->paths);
INIT_LIST_HEAD(&card->dapm_list);
+ INIT_LIST_HEAD(&card->aux_comp_list);
INIT_LIST_HEAD(&card->component_dev_list);
}
TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED = R(0x16),
TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED = R(0x17),
TCM_COPY_TARGET_DEVICE_NOT_REACHABLE = R(0x18),
+ TCM_TOO_MANY_TARGET_DESCS = R(0x19),
+ TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE = R(0x1a),
+ TCM_TOO_MANY_SEGMENT_DESCS = R(0x1b),
+ TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE = R(0x1c),
#undef R
};
BTRFS_I(inode)->root->root_key.objectid;
),
- TP_printk_btrfs("root = %llu(%s), gen = %llu, ino = %lu, blocks = %llu, "
- "disk_i_size = %llu, last_trans = %llu, logged_trans = %llu",
+ TP_printk_btrfs("root=%llu(%s) gen=%llu ino=%lu blocks=%llu "
+ "disk_i_size=%llu last_trans=%llu logged_trans=%llu",
show_root_type(__entry->root_objectid),
(unsigned long long)__entry->generation,
(unsigned long)__entry->ino,
TRACE_EVENT_CONDITION(btrfs_get_extent,
- TP_PROTO(struct btrfs_root *root, struct extent_map *map),
+ TP_PROTO(struct btrfs_root *root, struct inode *inode,
+ struct extent_map *map),
- TP_ARGS(root, map),
+ TP_ARGS(root, inode, map),
TP_CONDITION(map),
TP_STRUCT__entry_btrfs(
__field( u64, root_objectid )
+ __field( u64, ino )
__field( u64, start )
__field( u64, len )
__field( u64, orig_start )
TP_fast_assign_btrfs(root->fs_info,
__entry->root_objectid = root->root_key.objectid;
- __entry->start = map->start;
+ __entry->ino = btrfs_ino(inode);
+ __entry->start = map->start;
__entry->len = map->len;
__entry->orig_start = map->orig_start;
__entry->block_start = map->block_start;
__entry->compress_type = map->compress_type;
),
- TP_printk_btrfs("root = %llu(%s), start = %llu, len = %llu, "
- "orig_start = %llu, block_start = %llu(%s), "
- "block_len = %llu, flags = %s, refs = %u, "
- "compress_type = %u",
+ TP_printk_btrfs("root=%llu(%s) ino=%llu start=%llu len=%llu "
+ "orig_start=%llu block_start=%llu(%s) "
+ "block_len=%llu flags=%s refs=%u "
+ "compress_type=%u",
show_root_type(__entry->root_objectid),
+ (unsigned long long)__entry->ino,
(unsigned long long)__entry->start,
(unsigned long long)__entry->len,
(unsigned long long)__entry->orig_start,
__field( int, compress_type )
__field( int, refs )
__field( u64, root_objectid )
+ __field( u64, truncated_len )
),
TP_fast_assign_btrfs(btrfs_sb(inode->i_sb),
__entry->refs = atomic_read(&ordered->refs);
__entry->root_objectid =
BTRFS_I(inode)->root->root_key.objectid;
+ __entry->truncated_len = ordered->truncated_len;
),
- TP_printk_btrfs("root = %llu(%s), ino = %llu, file_offset = %llu, "
- "start = %llu, len = %llu, disk_len = %llu, "
- "bytes_left = %llu, flags = %s, compress_type = %d, "
- "refs = %d",
+ TP_printk_btrfs("root=%llu(%s) ino=%llu file_offset=%llu "
+ "start=%llu len=%llu disk_len=%llu "
+ "truncated_len=%llu "
+ "bytes_left=%llu flags=%s compress_type=%d "
+ "refs=%d",
show_root_type(__entry->root_objectid),
(unsigned long long)__entry->ino,
(unsigned long long)__entry->file_offset,
(unsigned long long)__entry->start,
(unsigned long long)__entry->len,
(unsigned long long)__entry->disk_len,
+ (unsigned long long)__entry->truncated_len,
(unsigned long long)__entry->bytes_left,
show_ordered_flags(__entry->flags),
__entry->compress_type, __entry->refs)
BTRFS_I(inode)->root->root_key.objectid;
),
- TP_printk_btrfs("root = %llu(%s), ino = %lu, page_index = %lu, "
- "nr_to_write = %ld, pages_skipped = %ld, range_start = %llu, "
- "range_end = %llu, for_kupdate = %d, "
- "for_reclaim = %d, range_cyclic = %d, writeback_index = %lu",
+ TP_printk_btrfs("root=%llu(%s) ino=%lu page_index=%lu "
+ "nr_to_write=%ld pages_skipped=%ld range_start=%llu "
+ "range_end=%llu for_kupdate=%d "
+ "for_reclaim=%d range_cyclic=%d writeback_index=%lu",
show_root_type(__entry->root_objectid),
(unsigned long)__entry->ino, __entry->index,
__entry->nr_to_write, __entry->pages_skipped,
BTRFS_I(page->mapping->host)->root->root_key.objectid;
),
- TP_printk_btrfs("root = %llu(%s), ino = %lu, page_index = %lu, start = %llu, "
- "end = %llu, uptodate = %d",
+ TP_printk_btrfs("root=%llu(%s) ino=%lu page_index=%lu start=%llu "
+ "end=%llu uptodate=%d",
show_root_type(__entry->root_objectid),
(unsigned long)__entry->ino, (unsigned long)__entry->index,
(unsigned long long)__entry->start,
BTRFS_I(inode)->root->root_key.objectid;
),
- TP_printk_btrfs("root = %llu(%s), ino = %ld, parent = %ld, datasync = %d",
+ TP_printk_btrfs("root=%llu(%s) ino=%ld parent=%ld datasync=%d",
show_root_type(__entry->root_objectid),
(unsigned long)__entry->ino, (unsigned long)__entry->parent,
__entry->datasync)
__entry->create = create;
),
- TP_printk("%pU: block_group offset = %llu, size = %llu, "
- "flags = %llu(%s), bytes_used = %llu, bytes_super = %llu, "
- "create = %d", __entry->fsid,
+ TP_printk("%pU: block_group offset=%llu size=%llu "
+ "flags=%llu(%s) bytes_used=%llu bytes_super=%llu "
+ "create=%d", __entry->fsid,
(unsigned long long)__entry->offset,
(unsigned long long)__entry->size,
(unsigned long long)__entry->flags,
__entry->seq = ref->seq;
),
- TP_printk_btrfs("bytenr = %llu, num_bytes = %llu, action = %s, "
- "parent = %llu(%s), ref_root = %llu(%s), level = %d, "
- "type = %s, seq = %llu",
+ TP_printk_btrfs("bytenr=%llu num_bytes=%llu action=%s "
+ "parent=%llu(%s) ref_root=%llu(%s) level=%d "
+ "type=%s seq=%llu",
(unsigned long long)__entry->bytenr,
(unsigned long long)__entry->num_bytes,
show_ref_action(__entry->action),
__entry->seq = ref->seq;
),
- TP_printk_btrfs("bytenr = %llu, num_bytes = %llu, action = %s, "
- "parent = %llu(%s), ref_root = %llu(%s), owner = %llu, "
- "offset = %llu, type = %s, seq = %llu",
+ TP_printk_btrfs("bytenr=%llu num_bytes=%llu action=%s "
+ "parent=%llu(%s) ref_root=%llu(%s) owner=%llu "
+ "offset=%llu type=%s seq=%llu",
(unsigned long long)__entry->bytenr,
(unsigned long long)__entry->num_bytes,
show_ref_action(__entry->action),
__entry->is_data = head_ref->is_data;
),
- TP_printk_btrfs("bytenr = %llu, num_bytes = %llu, action = %s, is_data = %d",
+ TP_printk_btrfs("bytenr=%llu num_bytes=%llu action=%s is_data=%d",
(unsigned long long)__entry->bytenr,
(unsigned long long)__entry->num_bytes,
show_ref_action(__entry->action),
__entry->root_objectid = fs_info->chunk_root->root_key.objectid;
),
- TP_printk_btrfs("root = %llu(%s), offset = %llu, size = %llu, "
- "num_stripes = %d, sub_stripes = %d, type = %s",
+ TP_printk_btrfs("root=%llu(%s) offset=%llu size=%llu "
+ "num_stripes=%d sub_stripes=%d type=%s",
show_root_type(__entry->root_objectid),
(unsigned long long)__entry->offset,
(unsigned long long)__entry->size,
__entry->cow_level = btrfs_header_level(cow);
),
- TP_printk_btrfs("root = %llu(%s), refs = %d, orig_buf = %llu "
- "(orig_level = %d), cow_buf = %llu (cow_level = %d)",
+ TP_printk_btrfs("root=%llu(%s) refs=%d orig_buf=%llu "
+ "(orig_level=%d) cow_buf=%llu (cow_level=%d)",
show_root_type(__entry->root_objectid),
__entry->refs,
(unsigned long long)__entry->buf_start,
__assign_str(reason, reason)
),
- TP_printk("%pU: %s: flush = %d(%s), flags = %llu(%s), bytes = %llu",
+ TP_printk("%pU: %s: flush=%d(%s) flags=%llu(%s) bytes=%llu",
__entry->fsid, __get_str(reason), __entry->flush,
show_flush_action(__entry->flush),
(unsigned long long)__entry->flags,
__entry->ret = ret;
),
- TP_printk("%pU: state = %d(%s), flags = %llu(%s), num_bytes = %llu, "
- "orig_bytes = %llu, ret = %d", __entry->fsid, __entry->state,
+ TP_printk("%pU: state=%d(%s) flags=%llu(%s) num_bytes=%llu "
+ "orig_bytes=%llu ret=%d", __entry->fsid, __entry->state,
show_flush_state(__entry->state),
(unsigned long long)__entry->flags,
__print_flags((unsigned long)__entry->flags, "|",
__entry->len = len;
),
- TP_printk_btrfs("root = %llu(%s), start = %llu, len = %llu",
+ TP_printk_btrfs("root=%llu(%s) start=%llu len=%llu",
show_root_type(BTRFS_EXTENT_TREE_OBJECTID),
(unsigned long long)__entry->start,
(unsigned long long)__entry->len)
__entry->data = data;
),
- TP_printk_btrfs("root = %Lu(%s), len = %Lu, empty_size = %Lu, flags = %Lu(%s)",
+ TP_printk_btrfs("root=%Lu(%s) len=%Lu empty_size=%Lu flags=%Lu(%s)",
show_root_type(BTRFS_EXTENT_TREE_OBJECTID),
__entry->num_bytes, __entry->empty_size, __entry->data,
__print_flags((unsigned long)__entry->data, "|",
__entry->len = len;
),
- TP_printk_btrfs("root = %Lu(%s), block_group = %Lu, flags = %Lu(%s), "
- "start = %Lu, len = %Lu",
+ TP_printk_btrfs("root=%Lu(%s) block_group=%Lu flags=%Lu(%s) "
+ "start=%Lu len=%Lu",
show_root_type(BTRFS_EXTENT_TREE_OBJECTID),
__entry->bg_objectid,
__entry->flags, __print_flags((unsigned long)__entry->flags,
__entry->min_bytes = min_bytes;
),
- TP_printk_btrfs("block_group = %Lu, flags = %Lu(%s), start = %Lu, len = %Lu,"
- " empty_size = %Lu, min_bytes = %Lu", __entry->bg_objectid,
+ TP_printk_btrfs("block_group=%Lu flags=%Lu(%s) start=%Lu len=%Lu "
+ "empty_size=%Lu min_bytes=%Lu", __entry->bg_objectid,
__entry->flags,
__print_flags((unsigned long)__entry->flags, "|",
BTRFS_GROUP_FLAGS), __entry->start,
__entry->bg_objectid = block_group->key.objectid;
),
- TP_printk_btrfs("block_group = %Lu", __entry->bg_objectid)
+ TP_printk_btrfs("block_group=%Lu", __entry->bg_objectid)
);
TRACE_EVENT(btrfs_setup_cluster,
__entry->bitmap = bitmap;
),
- TP_printk_btrfs("block_group = %Lu, flags = %Lu(%s), window_start = %Lu, "
- "size = %Lu, max_size = %Lu, bitmap = %d",
+ TP_printk_btrfs("block_group=%Lu flags=%Lu(%s) window_start=%Lu "
+ "size=%Lu max_size=%Lu bitmap=%d",
__entry->bg_objectid,
__entry->flags,
__print_flags((unsigned long)__entry->flags, "|",
__entry->ip = IP
),
- TP_printk("state=%p; mask = %s; caller = %pS", __entry->state,
+ TP_printk("state=%p mask=%s caller=%pS", __entry->state,
show_gfp_flags(__entry->mask), (void *)__entry->ip)
);
__entry->ip = IP
),
- TP_printk(" state=%p; caller = %pS", __entry->state,
+ TP_printk("state=%p caller=%pS", __entry->state,
(void *)__entry->ip)
);
__entry->normal_work = &work->normal_work;
),
- TP_printk_btrfs("work=%p (normal_work=%p), wq=%p, func=%pf, ordered_func=%p,"
- " ordered_free=%p",
+ TP_printk_btrfs("work=%p (normal_work=%p) wq=%p func=%pf ordered_func=%p "
+ "ordered_free=%p",
__entry->work, __entry->normal_work, __entry->wq,
__entry->func, __entry->ordered_func, __entry->ordered_free)
);
-/* For situiations that the work is freed */
+/*
+ * For situiations when the work is freed, we pass fs_info and a tag that that
+ * matches address of the work structure so it can be paired with the
+ * scheduling event.
+ */
DECLARE_EVENT_CLASS(btrfs__work__done,
- TP_PROTO(struct btrfs_work *work),
+ TP_PROTO(struct btrfs_fs_info *fs_info, void *wtag),
- TP_ARGS(work),
+ TP_ARGS(fs_info, wtag),
TP_STRUCT__entry_btrfs(
- __field( void *, work )
+ __field( void *, wtag )
),
- TP_fast_assign_btrfs(btrfs_work_owner(work),
- __entry->work = work;
+ TP_fast_assign_btrfs(fs_info,
+ __entry->wtag = wtag;
),
- TP_printk_btrfs("work->%p", __entry->work)
+ TP_printk_btrfs("work->%p", __entry->wtag)
);
DEFINE_EVENT(btrfs__work, btrfs_work_queued,
DEFINE_EVENT(btrfs__work__done, btrfs_all_work_done,
- TP_PROTO(struct btrfs_work *work),
+ TP_PROTO(struct btrfs_fs_info *fs_info, void *wtag),
- TP_ARGS(work)
+ TP_ARGS(fs_info, wtag)
);
DEFINE_EVENT(btrfs__work, btrfs_ordered_sched,
__entry->high = high;
),
- TP_printk_btrfs("name=%s%s, wq=%p", __get_str(name),
+ TP_printk_btrfs("name=%s%s wq=%p", __get_str(name),
__print_flags(__entry->high, "",
{(WQ_HIGHPRI), "-high"}),
__entry->wq)
__entry->free_reserved = free_reserved;
),
- TP_printk_btrfs("rootid=%llu, ino=%lu, free_reserved=%llu",
+ TP_printk_btrfs("rootid=%llu ino=%lu free_reserved=%llu",
__entry->rootid, __entry->ino, __entry->free_reserved)
);
__entry->op = op;
),
- TP_printk_btrfs("root=%llu, ino=%lu, start=%llu, len=%llu, reserved=%llu, op=%s",
+ TP_printk_btrfs("root=%llu ino=%lu start=%llu len=%llu reserved=%llu op=%s",
__entry->rootid, __entry->ino, __entry->start, __entry->len,
__entry->reserved,
__print_flags((unsigned long)__entry->op, "",
__entry->reserved = reserved;
),
- TP_printk_btrfs("root=%llu, reserved=%llu, op=free",
+ TP_printk_btrfs("root=%llu reserved=%llu op=free",
__entry->ref_root, __entry->reserved)
);
__entry->num_bytes = rec->num_bytes;
),
- TP_printk_btrfs("bytenr = %llu, num_bytes = %llu",
+ TP_printk_btrfs("bytenr=%llu num_bytes=%llu",
(unsigned long long)__entry->bytenr,
(unsigned long long)__entry->num_bytes)
);
__entry->nr_new_roots = nr_new_roots;
),
- TP_printk_btrfs("bytenr = %llu, num_bytes = %llu, nr_old_roots = %llu, "
- "nr_new_roots = %llu",
+ TP_printk_btrfs("bytenr=%llu num_bytes=%llu nr_old_roots=%llu "
+ "nr_new_roots=%llu",
__entry->bytenr,
__entry->num_bytes,
__entry->nr_old_roots,
__entry->cur_new_count = cur_new_count;
),
- TP_printk_btrfs("qgid = %llu, cur_old_count = %llu, cur_new_count = %llu",
+ TP_printk_btrfs("qgid=%llu cur_old_count=%llu cur_new_count=%llu",
__entry->qgid,
__entry->cur_old_count,
__entry->cur_new_count)
{(unsigned long)__GFP_WRITE, "__GFP_WRITE"}, \
{(unsigned long)__GFP_RECLAIM, "__GFP_RECLAIM"}, \
{(unsigned long)__GFP_DIRECT_RECLAIM, "__GFP_DIRECT_RECLAIM"},\
- {(unsigned long)__GFP_KSWAPD_RECLAIM, "__GFP_KSWAPD_RECLAIM"},\
- {(unsigned long)__GFP_OTHER_NODE, "__GFP_OTHER_NODE"} \
+ {(unsigned long)__GFP_KSWAPD_RECLAIM, "__GFP_KSWAPD_RECLAIM"}\
#define show_gfp_flags(flags) \
(flags) ? __print_flags(flags, "|", \
header-y += termios.h
header-y += thermal.h
header-y += time.h
+header-y += timerfd.h
header-y += times.h
header-y += timex.h
header-y += tiocl.h
__u8 audio_out_compensated,
__u8 audio_out_delay)
{
- msg->len = 7;
+ msg->len = 6;
msg->msg[0] |= 0xf; /* broadcast */
msg->msg[1] = CEC_MSG_REPORT_CURRENT_LATENCY;
msg->msg[2] = phys_addr >> 8;
msg->msg[3] = phys_addr & 0xff;
msg->msg[4] = video_latency;
msg->msg[5] = (low_latency_mode << 2) | audio_out_compensated;
- msg->msg[6] = audio_out_delay;
+ if (audio_out_compensated == 3)
+ msg->msg[msg->len++] = audio_out_delay;
}
static inline void cec_ops_report_current_latency(const struct cec_msg *msg,
*video_latency = msg->msg[4];
*low_latency_mode = (msg->msg[5] >> 2) & 1;
*audio_out_compensated = msg->msg[5] & 3;
- *audio_out_delay = msg->msg[6];
+ if (*audio_out_compensated == 3 && msg->len >= 7)
+ *audio_out_delay = msg->msg[6];
+ else
+ *audio_out_delay = 0;
}
static inline void cec_msg_request_current_latency(struct cec_msg *msg,
ETHTOOL_LINK_MODE_10000baseLR_Full_BIT = 44,
ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT = 45,
ETHTOOL_LINK_MODE_10000baseER_Full_BIT = 46,
+ ETHTOOL_LINK_MODE_2500baseT_Full_BIT = 47,
+ ETHTOOL_LINK_MODE_5000baseT_Full_BIT = 48,
/* Last allowed bit for __ETHTOOL_LINK_MODE_LEGACY_MASK is bit
*/
__ETHTOOL_LINK_MODE_LAST
- = ETHTOOL_LINK_MODE_10000baseER_Full_BIT,
+ = ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
};
#define __ETHTOOL_LINK_MODE_LEGACY_MASK(base_name) \
IIO_ELECTRICALCONDUCTIVITY,
IIO_COUNT,
IIO_INDEX,
+ IIO_GRAVITY,
};
enum iio_modifier {
#define NF_LOG_MACDECODE 0x20 /* Decode MAC header */
#define NF_LOG_MASK 0x2f
+#define NF_LOG_PREFIXLEN 128
+
#endif /* _NETFILTER_NF_LOG_H */
/**
* enum nft_rule_compat_attributes - nf_tables rule compat attributes
*
- * @NFTA_RULE_COMPAT_PROTO: numerice value of handled protocol (NLA_U32)
+ * @NFTA_RULE_COMPAT_PROTO: numeric value of handled protocol (NLA_U32)
* @NFTA_RULE_COMPAT_FLAGS: bitmask of enum nft_rule_compat_flags (NLA_U32)
*/
enum nft_rule_compat_attributes {
* enum nft_byteorder_ops - nf_tables byteorder operators
*
* @NFT_BYTEORDER_NTOH: network to host operator
- * @NFT_BYTEORDER_HTON: host to network opertaor
+ * @NFT_BYTEORDER_HTON: host to network operator
*/
enum nft_byteorder_ops {
NFT_BYTEORDER_NTOH,
*
* @NL80211_ATTR_OPMODE_NOTIF: Operating mode field from Operating Mode
* Notification Element based on association request when used with
- * %NL80211_CMD_NEW_STATION; u8 attribute.
+ * %NL80211_CMD_NEW_STATION or %NL80211_CMD_SET_STATION (only when
+ * %NL80211_FEATURE_FULL_AP_CLIENT_STATE is supported, or with TDLS);
+ * u8 attribute.
*
* @NL80211_ATTR_VENDOR_ID: The vendor ID, either a 24-bit OUI or, if
* %NL80211_VENDOR_ID_IS_LINUX is set, a special Linux ID (not used yet)
TCA_BPF_NAME,
TCA_BPF_FLAGS,
TCA_BPF_FLAGS_GEN,
- TCA_BPF_DIGEST,
+ TCA_BPF_TAG,
__TCA_BPF_MAX,
};
TCA_ACT_BPF_FD,
TCA_ACT_BPF_NAME,
TCA_ACT_BPF_PAD,
- TCA_ACT_BPF_DIGEST,
+ TCA_ACT_BPF_TAG,
__TCA_ACT_BPF_MAX,
};
#define TCA_ACT_BPF_MAX (__TCA_ACT_BPF_MAX - 1)
--- /dev/null
+/*
+ * include/linux/timerfd.h
+ *
+ * Copyright (C) 2007 Davide Libenzi <davidel@xmailserver.org>
+ *
+ */
+
+#ifndef _UAPI_LINUX_TIMERFD_H
+#define _UAPI_LINUX_TIMERFD_H
+
+#include <linux/types.h>
+
+/* For O_CLOEXEC and O_NONBLOCK */
+#include <linux/fcntl.h>
+
+/* For _IO helpers */
+#include <linux/ioctl.h>
+
+/*
+ * CAREFUL: Check include/asm-generic/fcntl.h when defining
+ * new flags, since they might collide with O_* ones. We want
+ * to re-use O_* flags that couldn't possibly have a meaning
+ * from eventfd, in order to leave a free define-space for
+ * shared O_* flags.
+ *
+ * Also make sure to update the masks in include/linux/timerfd.h
+ * when adding new flags.
+ */
+#define TFD_TIMER_ABSTIME (1 << 0)
+#define TFD_TIMER_CANCEL_ON_SET (1 << 1)
+#define TFD_CLOEXEC O_CLOEXEC
+#define TFD_NONBLOCK O_NONBLOCK
+
+#define TFD_IOC_SET_TICKS _IOW('T', 0, __u64)
+
+#endif /* _UAPI_LINUX_TIMERFD_H */
header-y += ocrdma-abi.h
header-y += hns-abi.h
header-y += vmw_pvrdma-abi.h
+header-y += qedr-abi.h
* SOFTWARE.
*/
#ifndef CXGB3_ABI_USER_H
-#define CXBG3_ABI_USER_H
+#define CXGB3_ABI_USER_H
#include <linux/types.h>
Say N.
+config SOCK_CGROUP_DATA
+ bool
+ default n
+
endif # CGROUPS
config CHECKPOINT_RESTORE
make them incompatible with the kernel you are running. If
unsure, say N.
+config MODULE_REL_CRCS
+ bool
+ depends on MODVERSIONS
+
config MODULE_SRCVERSION_ALL
bool "Source checksum for all modules"
help
}
rcu_read_lock();
- sem_lock(sma, sops, nsops);
+ locknum = sem_lock(sma, sops, nsops);
if (!ipc_valid_object(&sma->sem_perm))
goto out_unlock_free;
*/
#include <linux/bpf.h>
#include <linux/err.h>
-#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/filter.h>
attr->value_size == 0 || attr->map_flags)
return ERR_PTR(-EINVAL);
- if (attr->value_size >= 1 << (KMALLOC_SHIFT_MAX - 1))
+ if (attr->value_size > KMALLOC_MAX_SIZE)
/* if value_size is bigger, the user space won't be able to
* access the elements.
*/
if (array_size >= U32_MAX - PAGE_SIZE)
return ERR_PTR(-ENOMEM);
-
/* allocate all map elements and zero-initialize them */
- array = kzalloc(array_size, GFP_USER | __GFP_NOWARN);
- if (!array) {
- array = vzalloc(array_size);
- if (!array)
- return ERR_PTR(-ENOMEM);
- }
+ array = bpf_map_area_alloc(array_size);
+ if (!array)
+ return ERR_PTR(-ENOMEM);
/* copy mandatory map attributes */
array->map.map_type = attr->map_type;
if (array_size >= U32_MAX - PAGE_SIZE ||
elem_size > PCPU_MIN_UNIT_SIZE || bpf_array_alloc_percpu(array)) {
- kvfree(array);
+ bpf_map_area_free(array);
return ERR_PTR(-ENOMEM);
}
out:
if (array->map.map_type == BPF_MAP_TYPE_PERCPU_ARRAY)
bpf_array_free_percpu(array);
- kvfree(array);
+ bpf_map_area_free(array);
}
static const struct bpf_map_ops array_ops = {
/* make sure it's empty */
for (i = 0; i < array->map.max_entries; i++)
BUG_ON(array->ptrs[i] != NULL);
- kvfree(array);
+
+ bpf_map_area_free(array);
}
static void *fd_array_map_lookup_elem(struct bpf_map *map, void *key)
vfree(fp);
}
-int bpf_prog_calc_digest(struct bpf_prog *fp)
+int bpf_prog_calc_tag(struct bpf_prog *fp)
{
const u32 bits_offset = SHA_MESSAGE_BYTES - sizeof(__be64);
- u32 raw_size = bpf_prog_digest_scratch_size(fp);
+ u32 raw_size = bpf_prog_tag_scratch_size(fp);
+ u32 digest[SHA_DIGEST_WORDS];
u32 ws[SHA_WORKSPACE_WORDS];
u32 i, bsize, psize, blocks;
struct bpf_insn *dst;
if (!raw)
return -ENOMEM;
- sha_init(fp->digest);
+ sha_init(digest);
memset(ws, 0, sizeof(ws));
/* We need to take out the map fd for the digest calculation
*bits = cpu_to_be64((psize - 1) << 3);
while (blocks--) {
- sha_transform(fp->digest, todo, ws);
+ sha_transform(digest, todo, ws);
todo += SHA_MESSAGE_BYTES;
}
- result = (__force __be32 *)fp->digest;
+ result = (__force __be32 *)digest;
for (i = 0; i < SHA_DIGEST_WORDS; i++)
- result[i] = cpu_to_be32(fp->digest[i]);
+ result[i] = cpu_to_be32(digest[i]);
+ memcpy(fp->tag, result, sizeof(fp->tag));
vfree(raw);
return 0;
#include <linux/bpf.h>
#include <linux/jhash.h>
#include <linux/filter.h>
-#include <linux/vmalloc.h>
#include "percpu_freelist.h"
#include "bpf_lru_list.h"
free_percpu(pptr);
}
free_elems:
- vfree(htab->elems);
+ bpf_map_area_free(htab->elems);
}
static struct htab_elem *prealloc_lru_pop(struct bpf_htab *htab, void *key,
{
int err = -ENOMEM, i;
- htab->elems = vzalloc(htab->elem_size * htab->map.max_entries);
+ htab->elems = bpf_map_area_alloc(htab->elem_size *
+ htab->map.max_entries);
if (!htab->elems)
return -ENOMEM;
*/
goto free_htab;
- if (htab->map.value_size >= (1 << (KMALLOC_SHIFT_MAX - 1)) -
+ if (htab->map.value_size >= KMALLOC_MAX_SIZE -
MAX_BPF_STACK - sizeof(struct htab_elem))
/* if value_size is bigger, the user space won't be able to
* access the elements via bpf syscall. This check also makes
goto free_htab;
err = -ENOMEM;
- htab->buckets = kmalloc_array(htab->n_buckets, sizeof(struct bucket),
- GFP_USER | __GFP_NOWARN);
-
- if (!htab->buckets) {
- htab->buckets = vmalloc(htab->n_buckets * sizeof(struct bucket));
- if (!htab->buckets)
- goto free_htab;
- }
+ htab->buckets = bpf_map_area_alloc(htab->n_buckets *
+ sizeof(struct bucket));
+ if (!htab->buckets)
+ goto free_htab;
for (i = 0; i < htab->n_buckets; i++) {
INIT_HLIST_HEAD(&htab->buckets[i].head);
free_extra_elems:
free_percpu(htab->extra_elems);
free_buckets:
- kvfree(htab->buckets);
+ bpf_map_area_free(htab->buckets);
free_htab:
kfree(htab);
return ERR_PTR(err);
prealloc_destroy(htab);
free_percpu(htab->extra_elems);
- kvfree(htab->buckets);
+ bpf_map_area_free(htab->buckets);
kfree(htab);
}
#include <linux/bpf.h>
#include <linux/jhash.h>
#include <linux/filter.h>
-#include <linux/vmalloc.h>
#include <linux/stacktrace.h>
#include <linux/perf_event.h>
#include "percpu_freelist.h"
u32 elem_size = sizeof(struct stack_map_bucket) + smap->map.value_size;
int err;
- smap->elems = vzalloc(elem_size * smap->map.max_entries);
+ smap->elems = bpf_map_area_alloc(elem_size * smap->map.max_entries);
if (!smap->elems)
return -ENOMEM;
return 0;
free_elems:
- vfree(smap->elems);
+ bpf_map_area_free(smap->elems);
return err;
}
if (cost >= U32_MAX - PAGE_SIZE)
return ERR_PTR(-E2BIG);
- smap = kzalloc(cost, GFP_USER | __GFP_NOWARN);
- if (!smap) {
- smap = vzalloc(cost);
- if (!smap)
- return ERR_PTR(-ENOMEM);
- }
+ smap = bpf_map_area_alloc(cost);
+ if (!smap)
+ return ERR_PTR(-ENOMEM);
err = -E2BIG;
cost += n_buckets * (value_size + sizeof(struct stack_map_bucket));
put_buffers:
put_callchain_buffers();
free_smap:
- kvfree(smap);
+ bpf_map_area_free(smap);
return ERR_PTR(err);
}
/* wait for bpf programs to complete before freeing stack map */
synchronize_rcu();
- vfree(smap->elems);
+ bpf_map_area_free(smap->elems);
pcpu_freelist_destroy(&smap->freelist);
- kvfree(smap);
+ bpf_map_area_free(smap);
put_callchain_buffers();
}
#include <linux/bpf.h>
#include <linux/syscalls.h>
#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/mmzone.h>
#include <linux/anon_inodes.h>
#include <linux/file.h>
#include <linux/license.h>
list_add(&tl->list_node, &bpf_map_types);
}
+void *bpf_map_area_alloc(size_t size)
+{
+ /* We definitely need __GFP_NORETRY, so OOM killer doesn't
+ * trigger under memory pressure as we really just want to
+ * fail instead.
+ */
+ const gfp_t flags = __GFP_NOWARN | __GFP_NORETRY | __GFP_ZERO;
+ void *area;
+
+ if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) {
+ area = kmalloc(size, GFP_USER | flags);
+ if (area != NULL)
+ return area;
+ }
+
+ return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM | flags,
+ PAGE_KERNEL);
+}
+
+void bpf_map_area_free(void *area)
+{
+ kvfree(area);
+}
+
int bpf_map_precharge_memlock(u32 pages)
{
struct user_struct *user = get_current_user();
static void bpf_prog_show_fdinfo(struct seq_file *m, struct file *filp)
{
const struct bpf_prog *prog = filp->private_data;
- char prog_digest[sizeof(prog->digest) * 2 + 1] = { };
+ char prog_tag[sizeof(prog->tag) * 2 + 1] = { };
- bin2hex(prog_digest, prog->digest, sizeof(prog->digest));
+ bin2hex(prog_tag, prog->tag, sizeof(prog->tag));
seq_printf(m,
"prog_type:\t%u\n"
"prog_jited:\t%u\n"
- "prog_digest:\t%s\n"
+ "prog_tag:\t%s\n"
"memlock:\t%llu\n",
prog->type,
prog->jited,
- prog_digest,
+ prog_tag,
prog->pages * 1ULL << PAGE_SHIFT);
}
#endif
int insn_cnt = env->prog->len;
int i, j, err;
- err = bpf_prog_calc_digest(env->prog);
+ err = bpf_prog_calc_tag(env->prog);
if (err)
return err;
{
return has_ns_capability(t, &init_user_ns, cap);
}
+EXPORT_SYMBOL(has_capability);
/**
* has_ns_capability_noaudit - Does a task have a capability (unaudited)
return ERR_PTR(err);
}
+/*
+ * The returned cgroup is fully initialized including its control mask, but
+ * it isn't associated with its kernfs_node and doesn't have the control
+ * mask applied.
+ */
static struct cgroup *cgroup_create(struct cgroup *parent)
{
struct cgroup_root *root = parent->root;
cgroup_propagate_control(cgrp);
- /* @cgrp doesn't have dir yet so the following will only create csses */
- ret = cgroup_apply_control_enable(cgrp);
- if (ret)
- goto out_destroy;
-
return cgrp;
out_cancel_ref:
out_free_cgrp:
kfree(cgrp);
return ERR_PTR(ret);
-out_destroy:
- cgroup_destroy_locked(cgrp);
- return ERR_PTR(ret);
}
static int cgroup_mkdir(struct kernfs_node *parent_kn, const char *name,
{
struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);
int prev_state, ret = 0;
- bool hasdied = false;
if (num_online_cpus() == 1)
return -EBUSY;
cpuhp_kick_ap_work(cpu);
}
- hasdied = prev_state != st->state && st->state == CPUHP_OFFLINE;
out:
cpu_hotplug_done();
return ret;
*/
static int cpuhp_reserve_state(enum cpuhp_state state)
{
- enum cpuhp_state i;
+ enum cpuhp_state i, end;
+ struct cpuhp_step *step;
- for (i = CPUHP_AP_ONLINE_DYN; i <= CPUHP_AP_ONLINE_DYN_END; i++) {
- if (!cpuhp_ap_states[i].name)
+ switch (state) {
+ case CPUHP_AP_ONLINE_DYN:
+ step = cpuhp_ap_states + CPUHP_AP_ONLINE_DYN;
+ end = CPUHP_AP_ONLINE_DYN_END;
+ break;
+ case CPUHP_BP_PREPARE_DYN:
+ step = cpuhp_bp_states + CPUHP_BP_PREPARE_DYN;
+ end = CPUHP_BP_PREPARE_DYN_END;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ for (i = state; i <= end; i++, step++) {
+ if (!step->name)
return i;
}
WARN(1, "No more dynamic states available for CPU hotplug\n");
mutex_lock(&cpuhp_state_mutex);
- if (state == CPUHP_AP_ONLINE_DYN) {
+ if (state == CPUHP_AP_ONLINE_DYN || state == CPUHP_BP_PREPARE_DYN) {
ret = cpuhp_reserve_state(state);
if (ret < 0)
goto out;
static void
list_add_event(struct perf_event *event, struct perf_event_context *ctx)
{
-
lockdep_assert_held(&ctx->lock);
WARN_ON_ONCE(event->attach_state & PERF_ATTACH_CONTEXT);
{
struct perf_event *group_leader = event->group_leader, *pos;
+ lockdep_assert_held(&event->ctx->lock);
+
/*
* We can have double attach due to group movement in perf_event_open.
*/
struct perf_event *sibling, *tmp;
struct list_head *list = NULL;
+ lockdep_assert_held(&event->ctx->lock);
+
/*
* We can have double detach due to exit/hot-unplug + close.
*/
*/
static void perf_remove_from_context(struct perf_event *event, unsigned long flags)
{
- lockdep_assert_held(&event->ctx->mutex);
+ struct perf_event_context *ctx = event->ctx;
+
+ lockdep_assert_held(&ctx->mutex);
event_function_call(event, __perf_remove_from_context, (void *)flags);
+
+ /*
+ * The above event_function_call() can NO-OP when it hits
+ * TASK_TOMBSTONE. In that case we must already have been detached
+ * from the context (by perf_event_exit_event()) but the grouping
+ * might still be in-tact.
+ */
+ WARN_ON_ONCE(event->attach_state & PERF_ATTACH_CONTEXT);
+ if ((flags & DETACH_GROUP) &&
+ (event->attach_state & PERF_ATTACH_GROUP)) {
+ /*
+ * Since in that case we cannot possibly be scheduled, simply
+ * detach now.
+ */
+ raw_spin_lock_irq(&ctx->lock);
+ perf_group_detach(event);
+ raw_spin_unlock_irq(&ctx->lock);
+ }
}
/*
struct perf_event_context *ctx = event->ctx;
struct perf_cpu_context *cpuctx = __get_cpu_context(ctx);
struct perf_event_context *task_ctx = cpuctx->task_ctx;
- bool activate = true;
+ bool reprogram = true;
int ret = 0;
raw_spin_lock(&cpuctx->ctx.lock);
raw_spin_lock(&ctx->lock);
task_ctx = ctx;
- /* If we're on the wrong CPU, try again */
- if (task_cpu(ctx->task) != smp_processor_id()) {
- ret = -ESRCH;
- goto unlock;
- }
+ reprogram = (ctx->task == current);
/*
- * If we're on the right CPU, see if the task we target is
- * current, if not we don't have to activate the ctx, a future
- * context switch will do that for us.
+ * If the task is running, it must be running on this CPU,
+ * otherwise we cannot reprogram things.
+ *
+ * If its not running, we don't care, ctx->lock will
+ * serialize against it becoming runnable.
*/
- if (ctx->task != current)
- activate = false;
- else
- WARN_ON_ONCE(cpuctx->task_ctx && cpuctx->task_ctx != ctx);
+ if (task_curr(ctx->task) && !reprogram) {
+ ret = -ESRCH;
+ goto unlock;
+ }
+ WARN_ON_ONCE(reprogram && cpuctx->task_ctx && cpuctx->task_ctx != ctx);
} else if (task_ctx) {
raw_spin_lock(&task_ctx->lock);
}
- if (activate) {
+ if (reprogram) {
ctx_sched_out(ctx, cpuctx, EVENT_TIME);
add_event_to_ctx(event, ctx);
ctx_resched(cpuctx, task_ctx);
/*
* Installing events is tricky because we cannot rely on ctx->is_active
* to be set in case this is the nr_events 0 -> 1 transition.
+ *
+ * Instead we use task_curr(), which tells us if the task is running.
+ * However, since we use task_curr() outside of rq::lock, we can race
+ * against the actual state. This means the result can be wrong.
+ *
+ * If we get a false positive, we retry, this is harmless.
+ *
+ * If we get a false negative, things are complicated. If we are after
+ * perf_event_context_sched_in() ctx::lock will serialize us, and the
+ * value must be correct. If we're before, it doesn't matter since
+ * perf_event_context_sched_in() will program the counter.
+ *
+ * However, this hinges on the remote context switch having observed
+ * our task->perf_event_ctxp[] store, such that it will in fact take
+ * ctx::lock in perf_event_context_sched_in().
+ *
+ * We do this by task_function_call(), if the IPI fails to hit the task
+ * we know any future context switch of task must see the
+ * perf_event_ctpx[] store.
*/
-again:
+
/*
- * Cannot use task_function_call() because we need to run on the task's
- * CPU regardless of whether its current or not.
+ * This smp_mb() orders the task->perf_event_ctxp[] store with the
+ * task_cpu() load, such that if the IPI then does not find the task
+ * running, a future context switch of that task must observe the
+ * store.
*/
- if (!cpu_function_call(task_cpu(task), __perf_install_in_context, event))
+ smp_mb();
+again:
+ if (!task_function_call(task, __perf_install_in_context, event))
return;
raw_spin_lock_irq(&ctx->lock);
raw_spin_unlock_irq(&ctx->lock);
return;
}
- raw_spin_unlock_irq(&ctx->lock);
/*
- * Since !ctx->is_active doesn't mean anything, we must IPI
- * unconditionally.
+ * If the task is not running, ctx->lock will avoid it becoming so,
+ * thus we can safely install the event.
*/
- goto again;
+ if (task_curr(task)) {
+ raw_spin_unlock_irq(&ctx->lock);
+ goto again;
+ }
+ add_event_to_ctx(event, ctx);
+ raw_spin_unlock_irq(&ctx->lock);
}
/*
char *buf = NULL;
char *name;
+ if (vma->vm_flags & VM_READ)
+ prot |= PROT_READ;
+ if (vma->vm_flags & VM_WRITE)
+ prot |= PROT_WRITE;
+ if (vma->vm_flags & VM_EXEC)
+ prot |= PROT_EXEC;
+
+ if (vma->vm_flags & VM_MAYSHARE)
+ flags = MAP_SHARED;
+ else
+ flags = MAP_PRIVATE;
+
+ if (vma->vm_flags & VM_DENYWRITE)
+ flags |= MAP_DENYWRITE;
+ if (vma->vm_flags & VM_MAYEXEC)
+ flags |= MAP_EXECUTABLE;
+ if (vma->vm_flags & VM_LOCKED)
+ flags |= MAP_LOCKED;
+ if (vma->vm_flags & VM_HUGETLB)
+ flags |= MAP_HUGETLB;
+
if (file) {
struct inode *inode;
dev_t dev;
maj = MAJOR(dev);
min = MINOR(dev);
- if (vma->vm_flags & VM_READ)
- prot |= PROT_READ;
- if (vma->vm_flags & VM_WRITE)
- prot |= PROT_WRITE;
- if (vma->vm_flags & VM_EXEC)
- prot |= PROT_EXEC;
-
- if (vma->vm_flags & VM_MAYSHARE)
- flags = MAP_SHARED;
- else
- flags = MAP_PRIVATE;
-
- if (vma->vm_flags & VM_DENYWRITE)
- flags |= MAP_DENYWRITE;
- if (vma->vm_flags & VM_MAYEXEC)
- flags |= MAP_EXECUTABLE;
- if (vma->vm_flags & VM_LOCKED)
- flags |= MAP_LOCKED;
- if (vma->vm_flags & VM_HUGETLB)
- flags |= MAP_HUGETLB;
-
goto got_name;
} else {
if (vma->vm_ops && vma->vm_ops->name) {
perf_output_end(&handle);
}
-/*
- * Generic event overflow handling, sampling.
- */
-
-static int __perf_event_overflow(struct perf_event *event,
- int throttle, struct perf_sample_data *data,
- struct pt_regs *regs)
+static int
+__perf_event_account_interrupt(struct perf_event *event, int throttle)
{
- int events = atomic_read(&event->event_limit);
struct hw_perf_event *hwc = &event->hw;
- u64 seq;
int ret = 0;
-
- /*
- * Non-sampling counters might still use the PMI to fold short
- * hardware counters, ignore those.
- */
- if (unlikely(!is_sampling_event(event)))
- return 0;
+ u64 seq;
seq = __this_cpu_read(perf_throttled_seq);
if (seq != hwc->interrupts_seq) {
perf_adjust_period(event, delta, hwc->last_period, true);
}
+ return ret;
+}
+
+int perf_event_account_interrupt(struct perf_event *event)
+{
+ return __perf_event_account_interrupt(event, 1);
+}
+
+/*
+ * Generic event overflow handling, sampling.
+ */
+
+static int __perf_event_overflow(struct perf_event *event,
+ int throttle, struct perf_sample_data *data,
+ struct pt_regs *regs)
+{
+ int events = atomic_read(&event->event_limit);
+ int ret = 0;
+
+ /*
+ * Non-sampling counters might still use the PMI to fold short
+ * hardware counters, ignore those.
+ */
+ if (unlikely(!is_sampling_event(event)))
+ return 0;
+
+ ret = __perf_event_account_interrupt(event, throttle);
+
/*
* XXX event_limit might not quite work as expected on inherited
* events
return 0;
}
+/*
+ * Variation on perf_event_ctx_lock_nested(), except we take two context
+ * mutexes.
+ */
+static struct perf_event_context *
+__perf_event_ctx_lock_double(struct perf_event *group_leader,
+ struct perf_event_context *ctx)
+{
+ struct perf_event_context *gctx;
+
+again:
+ rcu_read_lock();
+ gctx = READ_ONCE(group_leader->ctx);
+ if (!atomic_inc_not_zero(&gctx->refcount)) {
+ rcu_read_unlock();
+ goto again;
+ }
+ rcu_read_unlock();
+
+ mutex_lock_double(&gctx->mutex, &ctx->mutex);
+
+ if (group_leader->ctx != gctx) {
+ mutex_unlock(&ctx->mutex);
+ mutex_unlock(&gctx->mutex);
+ put_ctx(gctx);
+ goto again;
+ }
+
+ return gctx;
+}
+
/**
* sys_perf_event_open - open a performance event, associate it to a task/cpu
*
}
if (move_group) {
- gctx = group_leader->ctx;
- mutex_lock_double(&gctx->mutex, &ctx->mutex);
+ gctx = __perf_event_ctx_lock_double(group_leader, ctx);
+
if (gctx->task == TASK_TOMBSTONE) {
err = -ESRCH;
goto err_locked;
}
+
+ /*
+ * Check if we raced against another sys_perf_event_open() call
+ * moving the software group underneath us.
+ */
+ if (!(group_leader->group_caps & PERF_EV_CAP_SOFTWARE)) {
+ /*
+ * If someone moved the group out from under us, check
+ * if this new event wound up on the same ctx, if so
+ * its the regular !move_group case, otherwise fail.
+ */
+ if (gctx != ctx) {
+ err = -EINVAL;
+ goto err_locked;
+ } else {
+ perf_event_ctx_unlock(group_leader, gctx);
+ move_group = 0;
+ }
+ }
} else {
mutex_lock(&ctx->mutex);
}
perf_unpin_context(ctx);
if (move_group)
- mutex_unlock(&gctx->mutex);
+ perf_event_ctx_unlock(group_leader, gctx);
mutex_unlock(&ctx->mutex);
if (task) {
err_locked:
if (move_group)
- mutex_unlock(&gctx->mutex);
+ perf_event_ctx_unlock(group_leader, gctx);
mutex_unlock(&ctx->mutex);
/* err_file: */
fput(event_file);
}
EXPORT_SYMBOL_GPL(irq_domain_free_irqs_parent);
+static void __irq_domain_activate_irq(struct irq_data *irq_data)
+{
+ if (irq_data && irq_data->domain) {
+ struct irq_domain *domain = irq_data->domain;
+
+ if (irq_data->parent_data)
+ __irq_domain_activate_irq(irq_data->parent_data);
+ if (domain->ops->activate)
+ domain->ops->activate(domain, irq_data);
+ }
+}
+
+static void __irq_domain_deactivate_irq(struct irq_data *irq_data)
+{
+ if (irq_data && irq_data->domain) {
+ struct irq_domain *domain = irq_data->domain;
+
+ if (domain->ops->deactivate)
+ domain->ops->deactivate(domain, irq_data);
+ if (irq_data->parent_data)
+ __irq_domain_deactivate_irq(irq_data->parent_data);
+ }
+}
+
/**
* irq_domain_activate_irq - Call domain_ops->activate recursively to activate
* interrupt
*/
void irq_domain_activate_irq(struct irq_data *irq_data)
{
- if (irq_data && irq_data->domain) {
- struct irq_domain *domain = irq_data->domain;
-
- if (irq_data->parent_data)
- irq_domain_activate_irq(irq_data->parent_data);
- if (domain->ops->activate)
- domain->ops->activate(domain, irq_data);
+ if (!irqd_is_activated(irq_data)) {
+ __irq_domain_activate_irq(irq_data);
+ irqd_set_activated(irq_data);
}
}
*/
void irq_domain_deactivate_irq(struct irq_data *irq_data)
{
- if (irq_data && irq_data->domain) {
- struct irq_domain *domain = irq_data->domain;
-
- if (domain->ops->deactivate)
- domain->ops->deactivate(domain, irq_data);
- if (irq_data->parent_data)
- irq_domain_deactivate_irq(irq_data->parent_data);
+ if (irqd_is_activated(irq_data)) {
+ __irq_domain_deactivate_irq(irq_data);
+ irqd_clr_activated(irq_data);
}
}
}
EXPORT_SYMBOL_GPL(static_key_slow_dec_deferred);
+void static_key_deferred_flush(struct static_key_deferred *key)
+{
+ STATIC_KEY_CHECK_USE();
+ flush_delayed_work(&key->work);
+}
+EXPORT_SYMBOL_GPL(static_key_deferred_flush);
+
void jump_label_rate_limit(struct static_key_deferred *key,
unsigned long rl)
{
/* pages are dead and unused, undo the arch mapping */
align_start = res->start & ~(SECTION_SIZE - 1);
align_size = ALIGN(resource_size(res), SECTION_SIZE);
+ mem_hotplug_begin();
arch_remove_memory(align_start, align_size);
+ mem_hotplug_done();
untrack_pfn(NULL, PHYS_PFN(align_start), align_size);
pgmap_radix_release(res);
dev_WARN_ONCE(dev, pgmap->altmap && pgmap->altmap->alloc,
if (error)
goto err_pfn_remap;
+ mem_hotplug_begin();
error = arch_add_memory(nid, align_start, align_size, true);
+ mem_hotplug_done();
if (error)
goto err_add_memory;
extern const struct kernel_symbol __stop___ksymtab_gpl[];
extern const struct kernel_symbol __start___ksymtab_gpl_future[];
extern const struct kernel_symbol __stop___ksymtab_gpl_future[];
-extern const unsigned long __start___kcrctab[];
-extern const unsigned long __start___kcrctab_gpl[];
-extern const unsigned long __start___kcrctab_gpl_future[];
+extern const s32 __start___kcrctab[];
+extern const s32 __start___kcrctab_gpl[];
+extern const s32 __start___kcrctab_gpl_future[];
#ifdef CONFIG_UNUSED_SYMBOLS
extern const struct kernel_symbol __start___ksymtab_unused[];
extern const struct kernel_symbol __stop___ksymtab_unused[];
extern const struct kernel_symbol __start___ksymtab_unused_gpl[];
extern const struct kernel_symbol __stop___ksymtab_unused_gpl[];
-extern const unsigned long __start___kcrctab_unused[];
-extern const unsigned long __start___kcrctab_unused_gpl[];
+extern const s32 __start___kcrctab_unused[];
+extern const s32 __start___kcrctab_unused_gpl[];
#endif
#ifndef CONFIG_MODVERSIONS
/* Output */
struct module *owner;
- const unsigned long *crc;
+ const s32 *crc;
const struct kernel_symbol *sym;
};
* (optional) module which owns it. Needs preempt disabled or module_mutex. */
const struct kernel_symbol *find_symbol(const char *name,
struct module **owner,
- const unsigned long **crc,
+ const s32 **crc,
bool gplok,
bool warn)
{
for (i = 0; i < TAINT_FLAGS_COUNT; i++) {
if (taint_flags[i].module && test_bit(i, &mod->taints))
- buf[l++] = taint_flags[i].true;
+ buf[l++] = taint_flags[i].c_true;
}
return l;
}
#ifdef CONFIG_MODVERSIONS
-/* If the arch applies (non-zero) relocations to kernel kcrctab, unapply it. */
-static unsigned long maybe_relocated(unsigned long crc,
- const struct module *crc_owner)
+
+static u32 resolve_rel_crc(const s32 *crc)
{
-#ifdef ARCH_RELOCATES_KCRCTAB
- if (crc_owner == NULL)
- return crc - (unsigned long)reloc_start;
-#endif
- return crc;
+ return *(u32 *)((void *)crc + *crc);
}
static int check_version(Elf_Shdr *sechdrs,
unsigned int versindex,
const char *symname,
struct module *mod,
- const unsigned long *crc,
- const struct module *crc_owner)
+ const s32 *crc)
{
unsigned int i, num_versions;
struct modversion_info *versions;
/ sizeof(struct modversion_info);
for (i = 0; i < num_versions; i++) {
+ u32 crcval;
+
if (strcmp(versions[i].name, symname) != 0)
continue;
- if (versions[i].crc == maybe_relocated(*crc, crc_owner))
+ if (IS_ENABLED(CONFIG_MODULE_REL_CRCS))
+ crcval = resolve_rel_crc(crc);
+ else
+ crcval = *crc;
+ if (versions[i].crc == crcval)
return 1;
- pr_debug("Found checksum %lX vs module %lX\n",
- maybe_relocated(*crc, crc_owner), versions[i].crc);
+ pr_debug("Found checksum %X vs module %lX\n",
+ crcval, versions[i].crc);
goto bad_version;
}
unsigned int versindex,
struct module *mod)
{
- const unsigned long *crc;
+ const s32 *crc;
/*
* Since this should be found in kernel (which can't be removed), no
}
preempt_enable();
return check_version(sechdrs, versindex,
- VMLINUX_SYMBOL_STR(module_layout), mod, crc,
- NULL);
+ VMLINUX_SYMBOL_STR(module_layout), mod, crc);
}
/* First part is kernel version, which we ignore if module has crcs. */
unsigned int versindex,
const char *symname,
struct module *mod,
- const unsigned long *crc,
- const struct module *crc_owner)
+ const s32 *crc)
{
return 1;
}
{
struct module *owner;
const struct kernel_symbol *sym;
- const unsigned long *crc;
+ const s32 *crc;
int err;
/*
if (!sym)
goto unlock;
- if (!check_version(info->sechdrs, info->index.vers, name, mod, crc,
- owner)) {
+ if (!check_version(info->sechdrs, info->index.vers, name, mod, crc)) {
sym = ERR_PTR(-EINVAL);
goto getname;
}
* Delay timeout seconds before rebooting the machine.
* We can't use the "normal" timers since we just panicked.
*/
- pr_emerg("Rebooting in %d seconds..", panic_timeout);
+ pr_emerg("Rebooting in %d seconds..\n", panic_timeout);
for (i = 0; i < panic_timeout * 1000; i += PANIC_TIMER_STEP) {
touch_nmi_watchdog();
for (i = 0; i < TAINT_FLAGS_COUNT; i++) {
const struct taint_flag *t = &taint_flags[i];
*s++ = test_bit(i, &tainted_mask) ?
- t->true : t->false;
+ t->c_true : t->c_false;
}
*s = 0;
} else
static void delayed_free_pidns(struct rcu_head *p)
{
- kmem_cache_free(pid_ns_cachep,
- container_of(p, struct pid_namespace, rcu));
+ struct pid_namespace *ns = container_of(p, struct pid_namespace, rcu);
+
+ dec_pid_namespaces(ns->ucounts);
+ put_user_ns(ns->user_ns);
+
+ kmem_cache_free(pid_ns_cachep, ns);
}
static void destroy_pid_namespace(struct pid_namespace *ns)
ns_free_inum(&ns->ns);
for (i = 0; i < PIDMAP_ENTRIES; i++)
kfree(ns->pidmap[i].page);
- dec_pid_namespaces(ns->ucounts);
- put_user_ns(ns->user_ns);
call_rcu(&ns->rcu, delayed_free_pidns);
}
const char *mem_sleep_states[PM_SUSPEND_MAX];
suspend_state_t mem_sleep_current = PM_SUSPEND_FREEZE;
-suspend_state_t mem_sleep_default = PM_SUSPEND_MAX;
+static suspend_state_t mem_sleep_default = PM_SUSPEND_MEM;
unsigned int pm_suspend_global_flags;
EXPORT_SYMBOL_GPL(pm_suspend_global_flags);
}
if (valid_state(PM_SUSPEND_MEM)) {
mem_sleep_states[PM_SUSPEND_MEM] = mem_sleep_labels[PM_SUSPEND_MEM];
- if (mem_sleep_default >= PM_SUSPEND_MEM)
+ if (mem_sleep_default == PM_SUSPEND_MEM)
mem_sleep_current = PM_SUSPEND_MEM;
}
#define TPS(x) tracepoint_string(x)
void rcu_early_boot_tests(void);
+void rcu_test_sync_prims(void);
/*
* This function really isn't for public consumption, but RCU is special in
* benefits of doing might_sleep() to reduce latency.)
*
* Cool, huh? (Due to Josh Triplett.)
- *
- * But we want to make this a static inline later. The cond_resched()
- * currently makes this problematic.
*/
void synchronize_sched(void)
{
lock_is_held(&rcu_lock_map) ||
lock_is_held(&rcu_sched_lock_map),
"Illegal synchronize_sched() in RCU read-side critical section");
- cond_resched();
}
EXPORT_SYMBOL_GPL(synchronize_sched);
/*
* During boot, we forgive RCU lockdep issues. After this function is
- * invoked, we start taking RCU lockdep issues seriously.
+ * invoked, we start taking RCU lockdep issues seriously. Note that unlike
+ * Tree RCU, Tiny RCU transitions directly from RCU_SCHEDULER_INACTIVE
+ * to RCU_SCHEDULER_RUNNING, skipping the RCU_SCHEDULER_INIT stage.
+ * The reason for this is that Tiny RCU does not need kthreads, so does
+ * not have to care about the fact that the scheduler is half-initialized
+ * at a certain phase of the boot process.
*/
void __init rcu_scheduler_starting(void)
{
WARN_ON(nr_context_switches() > 0);
- rcu_scheduler_active = 1;
+ rcu_scheduler_active = RCU_SCHEDULER_RUNNING;
}
#endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */
int sysctl_panic_on_rcu_stall __read_mostly;
/*
- * The rcu_scheduler_active variable transitions from zero to one just
- * before the first task is spawned. So when this variable is zero, RCU
- * can assume that there is but one task, allowing RCU to (for example)
+ * The rcu_scheduler_active variable is initialized to the value
+ * RCU_SCHEDULER_INACTIVE and transitions RCU_SCHEDULER_INIT just before the
+ * first task is spawned. So when this variable is RCU_SCHEDULER_INACTIVE,
+ * RCU can assume that there is but one task, allowing RCU to (for example)
* optimize synchronize_rcu() to a simple barrier(). When this variable
- * is one, RCU must actually do all the hard work required to detect real
- * grace periods. This variable is also used to suppress boot-time false
- * positives from lockdep-RCU error checking.
+ * is RCU_SCHEDULER_INIT, RCU must actually do all the hard work required
+ * to detect real grace periods. This variable is also used to suppress
+ * boot-time false positives from lockdep-RCU error checking. Finally, it
+ * transitions from RCU_SCHEDULER_INIT to RCU_SCHEDULER_RUNNING after RCU
+ * is fully initialized, including all of its kthreads having been spawned.
*/
int rcu_scheduler_active __read_mostly;
EXPORT_SYMBOL_GPL(rcu_scheduler_active);
early_initcall(rcu_spawn_gp_kthread);
/*
- * This function is invoked towards the end of the scheduler's initialization
- * process. Before this is called, the idle task might contain
- * RCU read-side critical sections (during which time, this idle
- * task is booting the system). After this function is called, the
- * idle tasks are prohibited from containing RCU read-side critical
- * sections. This function also enables RCU lockdep checking.
+ * This function is invoked towards the end of the scheduler's
+ * initialization process. Before this is called, the idle task might
+ * contain synchronous grace-period primitives (during which time, this idle
+ * task is booting the system, and such primitives are no-ops). After this
+ * function is called, any synchronous grace-period primitives are run as
+ * expedited, with the requesting task driving the grace period forward.
+ * A later core_initcall() rcu_exp_runtime_mode() will switch to full
+ * runtime RCU functionality.
*/
void rcu_scheduler_starting(void)
{
WARN_ON(num_online_cpus() != 1);
WARN_ON(nr_context_switches() > 0);
- rcu_scheduler_active = 1;
+ rcu_test_sync_prims();
+ rcu_scheduler_active = RCU_SCHEDULER_INIT;
+ rcu_test_sync_prims();
}
/*
struct work_struct rew_work;
};
+/*
+ * Common code to drive an expedited grace period forward, used by
+ * workqueues and mid-boot-time tasks.
+ */
+static void rcu_exp_sel_wait_wake(struct rcu_state *rsp,
+ smp_call_func_t func, unsigned long s)
+{
+ /* Initialize the rcu_node tree in preparation for the wait. */
+ sync_rcu_exp_select_cpus(rsp, func);
+
+ /* Wait and clean up, including waking everyone. */
+ rcu_exp_wait_wake(rsp, s);
+}
+
/*
* Work-queue handler to drive an expedited grace period forward.
*/
{
struct rcu_exp_work *rewp;
- /* Initialize the rcu_node tree in preparation for the wait. */
rewp = container_of(wp, struct rcu_exp_work, rew_work);
- sync_rcu_exp_select_cpus(rewp->rew_rsp, rewp->rew_func);
-
- /* Wait and clean up, including waking everyone. */
- rcu_exp_wait_wake(rewp->rew_rsp, rewp->rew_s);
+ rcu_exp_sel_wait_wake(rewp->rew_rsp, rewp->rew_func, rewp->rew_s);
}
/*
if (exp_funnel_lock(rsp, s))
return; /* Someone else did our work for us. */
- /* Marshall arguments and schedule the expedited grace period. */
- rew.rew_func = func;
- rew.rew_rsp = rsp;
- rew.rew_s = s;
- INIT_WORK_ONSTACK(&rew.rew_work, wait_rcu_exp_gp);
- schedule_work(&rew.rew_work);
+ /* Ensure that load happens before action based on it. */
+ if (unlikely(rcu_scheduler_active == RCU_SCHEDULER_INIT)) {
+ /* Direct call during scheduler init and early_initcalls(). */
+ rcu_exp_sel_wait_wake(rsp, func, s);
+ } else {
+ /* Marshall arguments & schedule the expedited grace period. */
+ rew.rew_func = func;
+ rew.rew_rsp = rsp;
+ rew.rew_s = s;
+ INIT_WORK_ONSTACK(&rew.rew_work, wait_rcu_exp_gp);
+ schedule_work(&rew.rew_work);
+ }
/* Wait for expedited grace period to complete. */
rdp = per_cpu_ptr(rsp->rda, raw_smp_processor_id());
{
struct rcu_state *rsp = rcu_state_p;
+ if (rcu_scheduler_active == RCU_SCHEDULER_INACTIVE)
+ return;
_synchronize_rcu_expedited(rsp, sync_rcu_exp_handler);
}
EXPORT_SYMBOL_GPL(synchronize_rcu_expedited);
EXPORT_SYMBOL_GPL(synchronize_rcu_expedited);
#endif /* #else #ifdef CONFIG_PREEMPT_RCU */
+
+/*
+ * Switch to run-time mode once Tree RCU has fully initialized.
+ */
+static int __init rcu_exp_runtime_mode(void)
+{
+ rcu_test_sync_prims();
+ rcu_scheduler_active = RCU_SCHEDULER_RUNNING;
+ rcu_test_sync_prims();
+ return 0;
+}
+core_initcall(rcu_exp_runtime_mode);
lock_is_held(&rcu_lock_map) ||
lock_is_held(&rcu_sched_lock_map),
"Illegal synchronize_rcu() in RCU read-side critical section");
- if (!rcu_scheduler_active)
+ if (rcu_scheduler_active == RCU_SCHEDULER_INACTIVE)
return;
if (rcu_gp_is_expedited())
synchronize_rcu_expedited();
* Should expedited grace-period primitives always fall back to their
* non-expedited counterparts? Intended for use within RCU. Note
* that if the user specifies both rcu_expedited and rcu_normal, then
- * rcu_normal wins.
+ * rcu_normal wins. (Except during the time period during boot from
+ * when the first task is spawned until the rcu_exp_runtime_mode()
+ * core_initcall() is invoked, at which point everything is expedited.)
*/
bool rcu_gp_is_normal(void)
{
- return READ_ONCE(rcu_normal);
+ return READ_ONCE(rcu_normal) &&
+ rcu_scheduler_active != RCU_SCHEDULER_INIT;
}
EXPORT_SYMBOL_GPL(rcu_gp_is_normal);
/*
* Should normal grace-period primitives be expedited? Intended for
* use within RCU. Note that this function takes the rcu_expedited
- * sysfs/boot variable into account as well as the rcu_expedite_gp()
- * nesting. So looping on rcu_unexpedite_gp() until rcu_gp_is_expedited()
- * returns false is a -really- bad idea.
+ * sysfs/boot variable and rcu_scheduler_active into account as well
+ * as the rcu_expedite_gp() nesting. So looping on rcu_unexpedite_gp()
+ * until rcu_gp_is_expedited() returns false is a -really- bad idea.
*/
bool rcu_gp_is_expedited(void)
{
- return rcu_expedited || atomic_read(&rcu_expedited_nesting);
+ return rcu_expedited || atomic_read(&rcu_expedited_nesting) ||
+ rcu_scheduler_active == RCU_SCHEDULER_INIT;
}
EXPORT_SYMBOL_GPL(rcu_gp_is_expedited);
int notrace debug_lockdep_rcu_enabled(void)
{
- return rcu_scheduler_active && debug_locks &&
+ return rcu_scheduler_active != RCU_SCHEDULER_INACTIVE && debug_locks &&
current->lockdep_recursion == 0;
}
EXPORT_SYMBOL_GPL(debug_lockdep_rcu_enabled);
void synchronize_rcu_tasks(void)
{
/* Complain if the scheduler has not started. */
- RCU_LOCKDEP_WARN(!rcu_scheduler_active,
+ RCU_LOCKDEP_WARN(rcu_scheduler_active == RCU_SCHEDULER_INACTIVE,
"synchronize_rcu_tasks called too soon");
/* Wait for the grace period. */
#endif /* #ifdef CONFIG_TASKS_RCU */
+/*
+ * Test each non-SRCU synchronous grace-period wait API. This is
+ * useful just after a change in mode for these primitives, and
+ * during early boot.
+ */
+void rcu_test_sync_prims(void)
+{
+ if (!IS_ENABLED(CONFIG_PROVE_RCU))
+ return;
+ synchronize_rcu();
+ synchronize_rcu_bh();
+ synchronize_sched();
+ synchronize_rcu_expedited();
+ synchronize_rcu_bh_expedited();
+ synchronize_sched_expedited();
+}
+
#ifdef CONFIG_PROVE_RCU
/*
early_boot_test_call_rcu_bh();
if (rcu_self_test_sched)
early_boot_test_call_rcu_sched();
+ rcu_test_sync_prims();
}
static int rcu_verify_early_boot_tests(void)
* fresh group stop. Read comment in do_signal_stop() for details.
*/
if (!sig->group_stop_count && !(sig->flags & SIGNAL_STOP_STOPPED)) {
- sig->flags = SIGNAL_STOP_STOPPED;
+ signal_set_stop_flags(sig, SIGNAL_STOP_STOPPED);
return true;
}
return false;
* will take ->siglock, notice SIGNAL_CLD_MASK, and
* notify its parent. See get_signal_to_deliver().
*/
- signal->flags = why | SIGNAL_STOP_CONTINUED;
+ signal_set_stop_flags(signal, why | SIGNAL_STOP_CONTINUED);
signal->group_stop_count = 0;
signal->group_exit_code = 0;
}
break;
if (neg)
continue;
+ val = convmul * val / convdiv;
if ((min && val < *min) || (max && val > *max))
continue;
*i = val;
tick = expires;
/* Skip reprogram of event if its not changed */
- if (ts->tick_stopped && (expires == dev->next_event))
+ if (ts->tick_stopped && (expires == ts->next_tick))
goto out;
/*
trace_tick_stop(1, TICK_DEP_MASK_NONE);
}
+ ts->next_tick = tick;
+
/*
* If the expiration time == KTIME_MAX, then we simply stop
* the tick timer.
else
tick_program_event(tick, 1);
out:
- /* Update the estimated sleep length */
+ /*
+ * Update the estimated sleep length until the next timer
+ * (not only the tick).
+ */
ts->sleep_length = ktime_sub(dev->next_event, now);
return tick;
}
* timer is modified for nohz sleeps. This is necessary
* to resume the tick timer operation in the timeline
* when the CPU returns from nohz sleep.
+ * @next_tick: Next tick to be fired when in dynticks mode.
* @tick_stopped: Indicator that the idle tick has been stopped
* @idle_jiffies: jiffies at the entry to idle for idle time accounting
* @idle_calls: Total number of idle calls
unsigned long check_clocks;
enum tick_nohz_mode nohz_mode;
ktime_t last_tick;
+ ktime_t next_tick;
int inidle;
int tick_stopped;
unsigned long idle_jiffies;
static struct cpumask save_cpumask;
static bool disable_migrate;
-static void move_to_next_cpu(void)
+static void move_to_next_cpu(bool initmask)
{
static struct cpumask *current_mask;
int next_cpu;
return;
/* Just pick the first CPU on first iteration */
- if (!current_mask) {
+ if (initmask) {
current_mask = &save_cpumask;
get_online_cpus();
cpumask_and(current_mask, cpu_online_mask, tracing_buffer_mask);
static int kthread_fn(void *data)
{
u64 interval;
+ bool initmask = true;
while (!kthread_should_stop()) {
- move_to_next_cpu();
+ move_to_next_cpu(initmask);
+ initmask = false;
local_irq_disable();
get_sample();
return a1 + a2 + a3 + a4 + a5 + a6;
}
-static struct __init trace_event_file *
+static __init struct trace_event_file *
find_trace_probe_file(struct trace_kprobe *tk, struct trace_array *tr)
{
struct trace_event_file *file;
struct hlist_head *hashent = ucounts_hashentry(ns, uid);
struct ucounts *ucounts, *new;
- spin_lock(&ucounts_lock);
+ spin_lock_irq(&ucounts_lock);
ucounts = find_ucounts(ns, uid, hashent);
if (!ucounts) {
- spin_unlock(&ucounts_lock);
+ spin_unlock_irq(&ucounts_lock);
new = kzalloc(sizeof(*new), GFP_KERNEL);
if (!new)
new->uid = uid;
atomic_set(&new->count, 0);
- spin_lock(&ucounts_lock);
+ spin_lock_irq(&ucounts_lock);
ucounts = find_ucounts(ns, uid, hashent);
if (ucounts) {
kfree(new);
}
if (!atomic_add_unless(&ucounts->count, 1, INT_MAX))
ucounts = NULL;
- spin_unlock(&ucounts_lock);
+ spin_unlock_irq(&ucounts_lock);
return ucounts;
}
static void put_ucounts(struct ucounts *ucounts)
{
+ unsigned long flags;
+
if (atomic_dec_and_test(&ucounts->count)) {
- spin_lock(&ucounts_lock);
+ spin_lock_irqsave(&ucounts_lock, flags);
hlist_del_init(&ucounts->node);
- spin_unlock(&ucounts_lock);
+ spin_unlock_irqrestore(&ucounts_lock, flags);
kfree(ucounts);
}
#define for_each_watchdog_cpu(cpu) \
for_each_cpu_and((cpu), cpu_online_mask, &watchdog_cpumask)
+atomic_t watchdog_park_in_progress = ATOMIC_INIT(0);
+
/*
* The 'watchdog_running' variable is set to 1 when the watchdog threads
* are registered/started and is set to 0 when the watchdog threads are
int duration;
int softlockup_all_cpu_backtrace = sysctl_softlockup_all_cpu_backtrace;
+ if (atomic_read(&watchdog_park_in_progress) != 0)
+ return HRTIMER_NORESTART;
+
/* kick the hardlockup detector */
watchdog_interrupt_count();
{
int cpu, ret = 0;
+ atomic_set(&watchdog_park_in_progress, 1);
+
for_each_watchdog_cpu(cpu) {
ret = kthread_park(per_cpu(softlockup_watchdog, cpu));
if (ret)
break;
}
+ atomic_set(&watchdog_park_in_progress, 0);
+
return ret;
}
/* Ensure the watchdog never gets throttled */
event->hw.interrupts = 0;
+ if (atomic_read(&watchdog_park_in_progress) != 0)
+ return;
+
if (__this_cpu_read(watchdog_nmi_touch) == true) {
__this_cpu_write(watchdog_nmi_touch, false);
return;
config DEBUG_INFO_SPLIT
bool "Produce split debuginfo in .dwo files"
- depends on DEBUG_INFO
+ depends on DEBUG_INFO && !FRV
help
Generate debug info into separate .dwo files. This significantly
reduces the build directory size for builds with DEBUG_INFO,
return err;
}
-EXPORT_SYMBOL_GPL(ioremap_page_range);
}
EXPORT_SYMBOL(iov_iter_copy_from_user_atomic);
+static inline void pipe_truncate(struct iov_iter *i)
+{
+ struct pipe_inode_info *pipe = i->pipe;
+ if (pipe->nrbufs) {
+ size_t off = i->iov_offset;
+ int idx = i->idx;
+ int nrbufs = (idx - pipe->curbuf) & (pipe->buffers - 1);
+ if (off) {
+ pipe->bufs[idx].len = off - pipe->bufs[idx].offset;
+ idx = next_idx(idx, pipe);
+ nrbufs++;
+ }
+ while (pipe->nrbufs > nrbufs) {
+ pipe_buf_release(pipe, &pipe->bufs[idx]);
+ idx = next_idx(idx, pipe);
+ pipe->nrbufs--;
+ }
+ }
+}
+
static void pipe_advance(struct iov_iter *i, size_t size)
{
struct pipe_inode_info *pipe = i->pipe;
- struct pipe_buffer *buf;
- int idx = i->idx;
- size_t off = i->iov_offset, orig_sz;
-
if (unlikely(i->count < size))
size = i->count;
- orig_sz = size;
-
if (size) {
+ struct pipe_buffer *buf;
+ size_t off = i->iov_offset, left = size;
+ int idx = i->idx;
if (off) /* make it relative to the beginning of buffer */
- size += off - pipe->bufs[idx].offset;
+ left += off - pipe->bufs[idx].offset;
while (1) {
buf = &pipe->bufs[idx];
- if (size <= buf->len)
+ if (left <= buf->len)
break;
- size -= buf->len;
+ left -= buf->len;
idx = next_idx(idx, pipe);
}
- buf->len = size;
i->idx = idx;
- off = i->iov_offset = buf->offset + size;
- }
- if (off)
- idx = next_idx(idx, pipe);
- if (pipe->nrbufs) {
- int unused = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1);
- /* [curbuf,unused) is in use. Free [idx,unused) */
- while (idx != unused) {
- pipe_buf_release(pipe, &pipe->bufs[idx]);
- idx = next_idx(idx, pipe);
- pipe->nrbufs--;
- }
+ i->iov_offset = buf->offset + left;
}
- i->count -= orig_sz;
+ i->count -= size;
+ /* ... and discard everything past that point */
+ pipe_truncate(i);
}
void iov_iter_advance(struct iov_iter *i, size_t size)
size_t count)
{
BUG_ON(direction != ITER_PIPE);
+ WARN_ON(pipe->nrbufs == pipe->buffers);
i->type = direction;
i->pipe = pipe;
i->idx = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1);
struct radix_tree_node *old = child;
offset = child->offset + 1;
child = child->parent;
- WARN_ON_ONCE(!list_empty(&node->private_list));
+ WARN_ON_ONCE(!list_empty(&old->private_list));
radix_tree_node_free(old);
if (old == entry_to_node(node))
return;
: 1UL << (BITS_PER_LONG - IO_TLB_SHIFT);
/*
- * For mappings greater than a page, we limit the stride (and
- * hence alignment) to a page size.
+ * For mappings greater than or equal to a page, we limit the stride
+ * (and hence alignment) to a page size.
*/
nslots = ALIGN(size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
- if (size > PAGE_SIZE)
+ if (size >= PAGE_SIZE)
stride = (1 << (PAGE_SHIFT - IO_TLB_SHIFT));
else
stride = 1;
dax_radix_locked_entry(0, RADIX_DAX_EMPTY));
/* Wakeup waiters for exceptional entry lock */
dax_wake_mapping_entry_waiter(mapping, page->index, p,
- false);
+ true);
}
}
__radix_tree_replace(&mapping->page_tree, node, slot, page,
cond_resched();
find_page:
+ if (fatal_signal_pending(current)) {
+ error = -EINTR;
+ goto out;
+ }
+
page = find_get_page(mapping, index);
if (!page) {
page_cache_sync_readahead(mapping,
assert_spin_locked(pmd_lockptr(mm, pmd));
+ /*
+ * When we COW a devmap PMD entry, we split it into PTEs, so we should
+ * not be in this function with `flags & FOLL_COW` set.
+ */
+ WARN_ONCE(flags & FOLL_COW, "mm: In follow_devmap_pmd with FOLL_COW set");
+
if (flags & FOLL_WRITE && !pmd_write(*pmd))
return NULL;
{
pmd_t entry;
unsigned long haddr;
+ bool write = vmf->flags & FAULT_FLAG_WRITE;
vmf->ptl = pmd_lock(vmf->vma->vm_mm, vmf->pmd);
if (unlikely(!pmd_same(*vmf->pmd, orig_pmd)))
goto unlock;
entry = pmd_mkyoung(orig_pmd);
+ if (write)
+ entry = pmd_mkdirty(entry);
haddr = vmf->address & HPAGE_PMD_MASK;
- if (pmdp_set_access_flags(vmf->vma, haddr, vmf->pmd, entry,
- vmf->flags & FAULT_FLAG_WRITE))
+ if (pmdp_set_access_flags(vmf->vma, haddr, vmf->pmd, entry, write))
update_mmu_cache_pmd(vmf->vma, vmf->address, vmf->pmd);
unlock:
}
for (i = 0; i < HPAGE_PMD_NR; i++) {
- pages[i] = alloc_page_vma_node(GFP_HIGHUSER_MOVABLE |
- __GFP_OTHER_NODE, vma,
+ pages[i] = alloc_page_vma_node(GFP_HIGHUSER_MOVABLE, vma,
vmf->address, page_to_nid(page));
if (unlikely(!pages[i] ||
mem_cgroup_try_charge(pages[i], vma->vm_mm,
return ret;
}
+/*
+ * FOLL_FORCE can write to even unwritable pmd's, but only
+ * after we've gone through a COW cycle and they are dirty.
+ */
+static inline bool can_follow_write_pmd(pmd_t pmd, unsigned int flags)
+{
+ return pmd_write(pmd) ||
+ ((flags & FOLL_FORCE) && (flags & FOLL_COW) && pmd_dirty(pmd));
+}
+
struct page *follow_trans_huge_pmd(struct vm_area_struct *vma,
unsigned long addr,
pmd_t *pmd,
assert_spin_locked(pmd_lockptr(mm, pmd));
- if (flags & FOLL_WRITE && !pmd_write(*pmd))
+ if (flags & FOLL_WRITE && !can_follow_write_pmd(*pmd, flags))
goto out;
/* Avoid dumping huge zero page */
}
/*
- * When releasing a hugetlb pool reservation, any surplus pages that were
- * allocated to satisfy the reservation must be explicitly freed if they were
- * never used.
- * Called with hugetlb_lock held.
+ * This routine has two main purposes:
+ * 1) Decrement the reservation count (resv_huge_pages) by the value passed
+ * in unused_resv_pages. This corresponds to the prior adjustments made
+ * to the associated reservation map.
+ * 2) Free any unused surplus pages that may have been allocated to satisfy
+ * the reservation. As many as unused_resv_pages may be freed.
+ *
+ * Called with hugetlb_lock held. However, the lock could be dropped (and
+ * reacquired) during calls to cond_resched_lock. Whenever dropping the lock,
+ * we must make sure nobody else can claim pages we are in the process of
+ * freeing. Do this by ensuring resv_huge_page always is greater than the
+ * number of huge pages we plan to free when dropping the lock.
*/
static void return_unused_surplus_pages(struct hstate *h,
unsigned long unused_resv_pages)
{
unsigned long nr_pages;
- /* Uncommit the reservation */
- h->resv_huge_pages -= unused_resv_pages;
-
/* Cannot return gigantic pages currently */
if (hstate_is_gigantic(h))
- return;
+ goto out;
+ /*
+ * Part (or even all) of the reservation could have been backed
+ * by pre-allocated pages. Only free surplus pages.
+ */
nr_pages = min(unused_resv_pages, h->surplus_huge_pages);
/*
* when the nodes with surplus pages have no free pages.
* free_pool_huge_page() will balance the the freed pages across the
* on-line nodes with memory and will handle the hstate accounting.
+ *
+ * Note that we decrement resv_huge_pages as we free the pages. If
+ * we drop the lock, resv_huge_pages will still be sufficiently large
+ * to cover subsequent pages we may free.
*/
while (nr_pages--) {
+ h->resv_huge_pages--;
+ unused_resv_pages--;
if (!free_pool_huge_page(h, &node_states[N_MEMORY], 1))
- break;
+ goto out;
cond_resched_lock(&hugetlb_lock);
}
+
+out:
+ /* Fully uncommit the reservation */
+ h->resv_huge_pages -= unused_resv_pages;
}
*
*/
+#include <linux/ftrace.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/printk.h>
if (likely(!kasan_report_enabled()))
return;
+ disable_trace_on_warning();
+
info.access_addr = (void *)addr;
info.access_size = size;
info.is_write = is_write;
VM_BUG_ON(address & ~HPAGE_PMD_MASK);
/* Only allocate from the target node */
- gfp = alloc_hugepage_khugepaged_gfpmask() | __GFP_OTHER_NODE | __GFP_THISNODE;
+ gfp = alloc_hugepage_khugepaged_gfpmask() | __GFP_THISNODE;
/*
* Before allocating the hugepage, release the mmap_sem read lock.
struct vm_area_struct *vma;
unsigned long addr;
pmd_t *pmd, _pmd;
- bool deposited = false;
i_mmap_lock_write(mapping);
vma_interval_tree_foreach(vma, &mapping->i_mmap, pgoff, pgoff) {
spinlock_t *ptl = pmd_lock(vma->vm_mm, pmd);
/* assume page table is clear */
_pmd = pmdp_collapse_flush(vma, addr, pmd);
- /*
- * now deposit the pgtable for arch that need it
- * otherwise free it.
- */
- if (arch_needs_pgtable_deposit()) {
- /*
- * The deposit should be visibile only after
- * collapse is seen by others.
- */
- smp_wmb();
- pgtable_trans_huge_deposit(vma->vm_mm, pmd,
- pmd_pgtable(_pmd));
- deposited = true;
- }
spin_unlock(ptl);
up_write(&vma->vm_mm->mmap_sem);
- if (!deposited) {
- atomic_long_dec(&vma->vm_mm->nr_ptes);
- pte_free(vma->vm_mm, pmd_pgtable(_pmd));
- }
+ atomic_long_dec(&vma->vm_mm->nr_ptes);
+ pte_free(vma->vm_mm, pmd_pgtable(_pmd));
}
}
i_mmap_unlock_write(mapping);
VM_BUG_ON(start & (HPAGE_PMD_NR - 1));
/* Only allocate from the target node */
- gfp = alloc_hugepage_khugepaged_gfpmask() |
- __GFP_OTHER_NODE | __GFP_THISNODE;
+ gfp = alloc_hugepage_khugepaged_gfpmask() | __GFP_THISNODE;
new_page = khugepaged_alloc_page(hpage, gfp, node);
if (!new_page) {
unsigned long mem_cgroup_node_nr_lru_pages(struct mem_cgroup *memcg,
int nid, unsigned int lru_mask)
{
+ struct lruvec *lruvec = mem_cgroup_lruvec(NODE_DATA(nid), memcg);
unsigned long nr = 0;
- struct mem_cgroup_per_node *mz;
enum lru_list lru;
VM_BUG_ON((unsigned)nid >= nr_node_ids);
for_each_lru(lru) {
if (!(BIT(lru) & lru_mask))
continue;
- mz = mem_cgroup_nodeinfo(memcg, nid);
- nr += mz->lru_size[lru];
+ nr += mem_cgroup_get_lru_size(lruvec, lru);
}
return nr;
}
* mem_cgroup_update_lru_size - account for adding or removing an lru page
* @lruvec: mem_cgroup per zone lru vector
* @lru: index of lru list the page is sitting on
+ * @zid: zone id of the accounted pages
* @nr_pages: positive when adding or negative when removing
*
* This function must be called under lru_lock, just before a page is added
* so as to allow it to check that lru_size 0 is consistent with list_empty).
*/
void mem_cgroup_update_lru_size(struct lruvec *lruvec, enum lru_list lru,
- int nr_pages)
+ int zid, int nr_pages)
{
struct mem_cgroup_per_node *mz;
unsigned long *lru_size;
long size;
- bool empty;
if (mem_cgroup_disabled())
return;
mz = container_of(lruvec, struct mem_cgroup_per_node, lruvec);
- lru_size = mz->lru_size + lru;
- empty = list_empty(lruvec->lists + lru);
+ lru_size = &mz->lru_zone_size[zid][lru];
if (nr_pages < 0)
*lru_size += nr_pages;
size = *lru_size;
- if (WARN_ONCE(size < 0 || empty != !size,
- "%s(%p, %d, %d): lru_size %ld but %sempty\n",
- __func__, lruvec, lru, nr_pages, size, empty ? "" : "not ")) {
+ if (WARN_ONCE(size < 0,
+ "%s(%p, %d, %d): lru_size %ld\n",
+ __func__, lruvec, lru, nr_pages, size)) {
VM_BUG_ON(1);
*lru_size = 0;
}
return ret;
}
- /* Try charges one by one with reclaim */
+ /* Try charges one by one with reclaim, but do not retry */
while (count--) {
- ret = try_charge(mc.to, GFP_KERNEL & ~__GFP_NORETRY, 1);
+ ret = try_charge(mc.to, GFP_KERNEL | __GFP_NORETRY, 1);
if (ret)
return ret;
mc.precharge++;
}
#endif /* __PAGETABLE_PMD_FOLDED */
-static int __follow_pte(struct mm_struct *mm, unsigned long address,
- pte_t **ptepp, spinlock_t **ptlp)
+static int __follow_pte_pmd(struct mm_struct *mm, unsigned long address,
+ pte_t **ptepp, pmd_t **pmdpp, spinlock_t **ptlp)
{
pgd_t *pgd;
pud_t *pud;
pmd = pmd_offset(pud, address);
VM_BUG_ON(pmd_trans_huge(*pmd));
- if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
- goto out;
- /* We cannot handle huge page PFN maps. Luckily they don't exist. */
- if (pmd_huge(*pmd))
+ if (pmd_huge(*pmd)) {
+ if (!pmdpp)
+ goto out;
+
+ *ptlp = pmd_lock(mm, pmd);
+ if (pmd_huge(*pmd)) {
+ *pmdpp = pmd;
+ return 0;
+ }
+ spin_unlock(*ptlp);
+ }
+
+ if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
goto out;
ptep = pte_offset_map_lock(mm, pmd, address, ptlp);
return -EINVAL;
}
-int follow_pte(struct mm_struct *mm, unsigned long address, pte_t **ptepp,
- spinlock_t **ptlp)
+static inline int follow_pte(struct mm_struct *mm, unsigned long address,
+ pte_t **ptepp, spinlock_t **ptlp)
+{
+ int res;
+
+ /* (void) is needed to make gcc happy */
+ (void) __cond_lock(*ptlp,
+ !(res = __follow_pte_pmd(mm, address, ptepp, NULL,
+ ptlp)));
+ return res;
+}
+
+int follow_pte_pmd(struct mm_struct *mm, unsigned long address,
+ pte_t **ptepp, pmd_t **pmdpp, spinlock_t **ptlp)
{
int res;
/* (void) is needed to make gcc happy */
(void) __cond_lock(*ptlp,
- !(res = __follow_pte(mm, address, ptepp, ptlp)));
+ !(res = __follow_pte_pmd(mm, address, ptepp, pmdpp,
+ ptlp)));
return res;
}
+EXPORT_SYMBOL(follow_pte_pmd);
/**
* follow_pfn - look up PFN at a user virtual address
node_set_state(node, N_MEMORY);
}
-int zone_can_shift(unsigned long pfn, unsigned long nr_pages,
- enum zone_type target)
+bool zone_can_shift(unsigned long pfn, unsigned long nr_pages,
+ enum zone_type target, int *zone_shift)
{
struct zone *zone = page_zone(pfn_to_page(pfn));
enum zone_type idx = zone_idx(zone);
int i;
+ *zone_shift = 0;
+
if (idx < target) {
/* pages must be at end of current zone */
if (pfn + nr_pages != zone_end_pfn(zone))
- return 0;
+ return false;
/* no zones in use between current zone and target */
for (i = idx + 1; i < target; i++)
if (zone_is_initialized(zone - idx + i))
- return 0;
+ return false;
}
if (target < idx) {
/* pages must be at beginning of current zone */
if (pfn != zone->zone_start_pfn)
- return 0;
+ return false;
/* no zones in use between current zone and target */
for (i = target + 1; i < idx; i++)
if (zone_is_initialized(zone - idx + i))
- return 0;
+ return false;
}
- return target - idx;
+ *zone_shift = target - idx;
+ return true;
}
/* Must be protected by mem_hotplug_begin() */
!can_online_high_movable(zone))
return -EINVAL;
- if (online_type == MMOP_ONLINE_KERNEL)
- zone_shift = zone_can_shift(pfn, nr_pages, ZONE_NORMAL);
- else if (online_type == MMOP_ONLINE_MOVABLE)
- zone_shift = zone_can_shift(pfn, nr_pages, ZONE_MOVABLE);
+ if (online_type == MMOP_ONLINE_KERNEL) {
+ if (!zone_can_shift(pfn, nr_pages, ZONE_NORMAL, &zone_shift))
+ return -EINVAL;
+ } else if (online_type == MMOP_ONLINE_MOVABLE) {
+ if (!zone_can_shift(pfn, nr_pages, ZONE_MOVABLE, &zone_shift))
+ return -EINVAL;
+ }
zone = move_pfn_range(zone_shift, pfn, pfn + nr_pages);
if (!zone)
}
/*
- * Confirm all pages in a range [start, end) is belongs to the same zone.
+ * Confirm all pages in a range [start, end) belong to the same zone.
+ * When true, return its valid [start, end).
*/
-int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn)
+int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn,
+ unsigned long *valid_start, unsigned long *valid_end)
{
unsigned long pfn, sec_end_pfn;
+ unsigned long start, end;
struct zone *zone = NULL;
struct page *page;
int i;
- for (pfn = start_pfn, sec_end_pfn = SECTION_ALIGN_UP(start_pfn);
+ for (pfn = start_pfn, sec_end_pfn = SECTION_ALIGN_UP(start_pfn + 1);
pfn < end_pfn;
- pfn = sec_end_pfn + 1, sec_end_pfn += PAGES_PER_SECTION) {
+ pfn = sec_end_pfn, sec_end_pfn += PAGES_PER_SECTION) {
/* Make sure the memory section is present first */
if (!present_section_nr(pfn_to_section_nr(pfn)))
continue;
page = pfn_to_page(pfn + i);
if (zone && page_zone(page) != zone)
return 0;
+ if (!zone)
+ start = pfn + i;
zone = page_zone(page);
+ end = pfn + MAX_ORDER_NR_PAGES;
}
}
- return 1;
+
+ if (zone) {
+ *valid_start = start;
+ *valid_end = end;
+ return 1;
+ } else {
+ return 0;
+ }
}
/*
long offlined_pages;
int ret, drain, retry_max, node;
unsigned long flags;
+ unsigned long valid_start, valid_end;
struct zone *zone;
struct memory_notify arg;
return -EINVAL;
/* This makes hotplug much easier...and readable.
we assume this for now. .*/
- if (!test_pages_in_a_zone(start_pfn, end_pfn))
+ if (!test_pages_in_a_zone(start_pfn, end_pfn, &valid_start, &valid_end))
return -EINVAL;
- zone = page_zone(pfn_to_page(start_pfn));
+ zone = page_zone(pfn_to_page(valid_start));
node = zone_to_nid(zone);
nr_pages = end_pfn - start_pfn;
nmask = policy_nodemask(gfp, pol);
zl = policy_zonelist(gfp, pol, node);
- mpol_cond_put(pol);
page = __alloc_pages_nodemask(gfp, order, zl, nmask);
+ mpol_cond_put(pol);
out:
if (unlikely(!page && read_mems_allowed_retry(cpuset_mems_cookie)))
goto retry_cpuset;
#endif
for (page = start_page; page <= end_page;) {
- /* Make sure we are not inadvertently changing nodes */
- VM_BUG_ON_PAGE(page_to_nid(page) != zone_to_nid(zone), page);
-
if (!pfn_valid_within(page_to_pfn(page))) {
page++;
continue;
}
+ /* Make sure we are not inadvertently changing nodes */
+ VM_BUG_ON_PAGE(page_to_nid(page) != zone_to_nid(zone), page);
+
if (!PageBuddy(page)) {
page++;
continue;
* Update NUMA hit/miss statistics
*
* Must be called with interrupts disabled.
- *
- * When __GFP_OTHER_NODE is set assume the node of the preferred
- * zone is the local node. This is useful for daemons who allocate
- * memory on behalf of other processes.
*/
-static inline void zone_statistics(struct zone *preferred_zone, struct zone *z,
- gfp_t flags)
+static inline void zone_statistics(struct zone *preferred_zone, struct zone *z)
{
#ifdef CONFIG_NUMA
- int local_nid = numa_node_id();
enum zone_stat_item local_stat = NUMA_LOCAL;
- if (unlikely(flags & __GFP_OTHER_NODE)) {
+ if (z->node != numa_node_id())
local_stat = NUMA_OTHER;
- local_nid = preferred_zone->node;
- }
- if (z->node == local_nid) {
+ if (z->node == preferred_zone->node)
__inc_zone_state(z, NUMA_HIT);
- __inc_zone_state(z, local_stat);
- } else {
+ else {
__inc_zone_state(z, NUMA_MISS);
__inc_zone_state(preferred_zone, NUMA_FOREIGN);
}
+ __inc_zone_state(z, local_stat);
#endif
}
}
__count_zid_vm_events(PGALLOC, page_zonenum(page), 1 << order);
- zone_statistics(preferred_zone, zone, gfp_flags);
+ zone_statistics(preferred_zone, zone);
local_irq_restore(flags);
VM_BUG_ON_PAGE(bad_range(zone, page), page);
struct page *page = NULL;
unsigned int alloc_flags;
unsigned long did_some_progress;
- enum compact_priority compact_priority = DEF_COMPACT_PRIORITY;
+ enum compact_priority compact_priority;
enum compact_result compact_result;
- int compaction_retries = 0;
- int no_progress_loops = 0;
+ int compaction_retries;
+ int no_progress_loops;
unsigned long alloc_start = jiffies;
unsigned int stall_timeout = 10 * HZ;
+ unsigned int cpuset_mems_cookie;
/*
* In the slowpath, we sanity check order to avoid ever trying to
(__GFP_ATOMIC|__GFP_DIRECT_RECLAIM)))
gfp_mask &= ~__GFP_ATOMIC;
+retry_cpuset:
+ compaction_retries = 0;
+ no_progress_loops = 0;
+ compact_priority = DEF_COMPACT_PRIORITY;
+ cpuset_mems_cookie = read_mems_allowed_begin();
+ /*
+ * We need to recalculate the starting point for the zonelist iterator
+ * because we might have used different nodemask in the fast path, or
+ * there was a cpuset modification and we are retrying - otherwise we
+ * could end up iterating over non-eligible zones endlessly.
+ */
+ ac->preferred_zoneref = first_zones_zonelist(ac->zonelist,
+ ac->high_zoneidx, ac->nodemask);
+ if (!ac->preferred_zoneref->zone)
+ goto nopage;
+
+
/*
* The fast path uses conservative alloc_flags to succeed only until
* kswapd needs to be woken up, and to avoid the cost of setting up
&compaction_retries))
goto retry;
+ /*
+ * It's possible we raced with cpuset update so the OOM would be
+ * premature (see below the nopage: label for full explanation).
+ */
+ if (read_mems_allowed_retry(cpuset_mems_cookie))
+ goto retry_cpuset;
+
/* Reclaim has failed us, start killing things */
page = __alloc_pages_may_oom(gfp_mask, order, ac, &did_some_progress);
if (page)
}
nopage:
+ /*
+ * When updating a task's mems_allowed or mempolicy nodemask, it is
+ * possible to race with parallel threads in such a way that our
+ * allocation can fail while the mask is being updated. If we are about
+ * to fail, check if the cpuset changed during allocation and if so,
+ * retry.
+ */
+ if (read_mems_allowed_retry(cpuset_mems_cookie))
+ goto retry_cpuset;
+
warn_alloc(gfp_mask,
"page allocation failure: order:%u", order);
got_pg:
struct zonelist *zonelist, nodemask_t *nodemask)
{
struct page *page;
- unsigned int cpuset_mems_cookie;
unsigned int alloc_flags = ALLOC_WMARK_LOW;
gfp_t alloc_mask = gfp_mask; /* The gfp_t that was actually used for allocation */
struct alloc_context ac = {
if (IS_ENABLED(CONFIG_CMA) && ac.migratetype == MIGRATE_MOVABLE)
alloc_flags |= ALLOC_CMA;
-retry_cpuset:
- cpuset_mems_cookie = read_mems_allowed_begin();
-
/* Dirty zone balancing only done in the fast path */
ac.spread_dirty_pages = (gfp_mask & __GFP_WRITE);
*/
ac.preferred_zoneref = first_zones_zonelist(ac.zonelist,
ac.high_zoneidx, ac.nodemask);
- if (!ac.preferred_zoneref) {
+ if (!ac.preferred_zoneref->zone) {
page = NULL;
+ /*
+ * This might be due to race with cpuset_current_mems_allowed
+ * update, so make sure we retry with original nodemask in the
+ * slow path.
+ */
goto no_zone;
}
if (likely(page))
goto out;
+no_zone:
/*
* Runtime PM, block IO and its error handling path can deadlock
* because I/O on the device might not complete.
* Restore the original nodemask if it was potentially replaced with
* &cpuset_current_mems_allowed to optimize the fast-path attempt.
*/
- if (cpusets_enabled())
+ if (unlikely(ac.nodemask != nodemask))
ac.nodemask = nodemask;
- page = __alloc_pages_slowpath(alloc_mask, order, &ac);
-no_zone:
- /*
- * When updating a task's mems_allowed, it is possible to race with
- * parallel threads in such a way that an allocation can fail while
- * the mask is being updated. If a page allocation is about to fail,
- * check if the cpuset changed during allocation and if so, retry.
- */
- if (unlikely(!page && read_mems_allowed_retry(cpuset_mems_cookie))) {
- alloc_mask = gfp_mask;
- goto retry_cpuset;
- }
+ page = __alloc_pages_slowpath(alloc_mask, order, &ac);
out:
if (memcg_kmem_enabled() && (gfp_mask & __GFP_ACCOUNT) && page &&
* drivers to provide a backing region of memory for use as either an
* sk_buff->head, or to be used in the "frags" portion of skb_shared_info.
*/
-static struct page *__page_frag_refill(struct page_frag_cache *nc,
- gfp_t gfp_mask)
+static struct page *__page_frag_cache_refill(struct page_frag_cache *nc,
+ gfp_t gfp_mask)
{
struct page *page = NULL;
gfp_t gfp = gfp_mask;
return page;
}
-void __page_frag_drain(struct page *page, unsigned int order,
- unsigned int count)
+void __page_frag_cache_drain(struct page *page, unsigned int count)
{
VM_BUG_ON_PAGE(page_ref_count(page) == 0, page);
if (page_ref_sub_and_test(page, count)) {
+ unsigned int order = compound_order(page);
+
if (order == 0)
free_hot_cold_page(page, false);
else
__free_pages_ok(page, order);
}
}
-EXPORT_SYMBOL(__page_frag_drain);
+EXPORT_SYMBOL(__page_frag_cache_drain);
-void *__alloc_page_frag(struct page_frag_cache *nc,
- unsigned int fragsz, gfp_t gfp_mask)
+void *page_frag_alloc(struct page_frag_cache *nc,
+ unsigned int fragsz, gfp_t gfp_mask)
{
unsigned int size = PAGE_SIZE;
struct page *page;
if (unlikely(!nc->va)) {
refill:
- page = __page_frag_refill(nc, gfp_mask);
+ page = __page_frag_cache_refill(nc, gfp_mask);
if (!page)
return NULL;
return nc->va + offset;
}
-EXPORT_SYMBOL(__alloc_page_frag);
+EXPORT_SYMBOL(page_frag_alloc);
/*
* Frees a page fragment allocated out of either a compound or order 0 page.
*/
-void __free_page_frag(void *addr)
+void page_frag_free(void *addr)
{
struct page *page = virt_to_head_page(addr);
if (unlikely(put_page_testzero(page)))
__free_pages_ok(page, compound_order(page));
}
-EXPORT_SYMBOL(__free_page_frag);
+EXPORT_SYMBOL(page_frag_free);
static void *make_alloc_exact(unsigned long addr, unsigned int order,
size_t size)
.zone = page_zone(pfn_to_page(start)),
.mode = MIGRATE_SYNC,
.ignore_skip_hint = true,
+ .gfp_mask = GFP_KERNEL,
};
INIT_LIST_HEAD(&cc.migratepages);
struct shrink_control *sc, unsigned long nr_to_split)
{
LIST_HEAD(list), *pos, *next;
+ LIST_HEAD(to_remove);
struct inode *inode;
struct shmem_inode_info *info;
struct page *page;
/* Check if there's anything to gain */
if (round_up(inode->i_size, PAGE_SIZE) ==
round_up(inode->i_size, HPAGE_PMD_SIZE)) {
- list_del_init(&info->shrinklist);
+ list_move(&info->shrinklist, &to_remove);
removed++;
- iput(inode);
goto next;
}
}
spin_unlock(&sbinfo->shrinklist_lock);
+ list_for_each_safe(pos, next, &to_remove) {
+ info = list_entry(pos, struct shmem_inode_info, shrinklist);
+ inode = &info->vfs_inode;
+ list_del_init(&info->shrinklist);
+ iput(inode);
+ }
+
list_for_each_safe(pos, next, &list) {
int ret;
unsigned int pos;
unsigned int *list;
unsigned int count;
- unsigned int rand;
};
struct rnd_state rnd_state;
};
} else {
state->list = cachep->random_seq;
state->count = count;
- state->pos = 0;
- state->rand = rand;
+ state->pos = rand % count;
ret = true;
}
return ret;
/* Get the next entry on the list and randomize it using a random shift */
static freelist_idx_t next_random_slot(union freelist_init_state *state)
{
- return (state->list[state->pos++] + state->rand) % state->count;
+ if (state->pos >= state->count)
+ state->pos = 0;
+ return state->list[state->pos++];
}
/* Swap two freelist entries */
return 1;
}
-static void print_section(char *text, u8 *addr, unsigned int length)
+static void print_section(char *level, char *text, u8 *addr,
+ unsigned int length)
{
metadata_access_enable();
- print_hex_dump(KERN_ERR, text, DUMP_PREFIX_ADDRESS, 16, 1, addr,
+ print_hex_dump(level, text, DUMP_PREFIX_ADDRESS, 16, 1, addr,
length, 1);
metadata_access_disable();
}
p, p - addr, get_freepointer(s, p));
if (s->flags & SLAB_RED_ZONE)
- print_section("Redzone ", p - s->red_left_pad, s->red_left_pad);
+ print_section(KERN_ERR, "Redzone ", p - s->red_left_pad,
+ s->red_left_pad);
else if (p > addr + 16)
- print_section("Bytes b4 ", p - 16, 16);
+ print_section(KERN_ERR, "Bytes b4 ", p - 16, 16);
- print_section("Object ", p, min_t(unsigned long, s->object_size,
- PAGE_SIZE));
+ print_section(KERN_ERR, "Object ", p,
+ min_t(unsigned long, s->object_size, PAGE_SIZE));
if (s->flags & SLAB_RED_ZONE)
- print_section("Redzone ", p + s->object_size,
+ print_section(KERN_ERR, "Redzone ", p + s->object_size,
s->inuse - s->object_size);
if (s->offset)
if (off != size_from_object(s))
/* Beginning of the filler is the free pointer */
- print_section("Padding ", p + off, size_from_object(s) - off);
+ print_section(KERN_ERR, "Padding ", p + off,
+ size_from_object(s) - off);
dump_stack();
}
end--;
slab_err(s, page, "Padding overwritten. 0x%p-0x%p", fault, end - 1);
- print_section("Padding ", end - remainder, remainder);
+ print_section(KERN_ERR, "Padding ", end - remainder, remainder);
restore_bytes(s, "slab padding", POISON_INUSE, end - remainder, end);
return 0;
page->freelist);
if (!alloc)
- print_section("Object ", (void *)object,
+ print_section(KERN_INFO, "Object ", (void *)object,
s->object_size);
dump_stack();
count = page_trans_huge_mapcount(page, total_mapcount);
if (count <= 1 && PageSwapCache(page)) {
count += page_swapcount(page);
- if (count == 1 && !PageWriteback(page)) {
+ if (count != 1)
+ goto out;
+ if (!PageWriteback(page)) {
delete_from_swap_cache(page);
SetPageDirty(page);
+ } else {
+ swp_entry_t entry;
+ struct swap_info_struct *p;
+
+ entry.val = page_private(page);
+ p = swap_info_get(entry);
+ if (p->flags & SWP_STABLE_WRITES) {
+ spin_unlock(&p->lock);
+ return false;
+ }
+ spin_unlock(&p->lock);
}
}
+out:
return count <= 1;
}
error = -ENOMEM;
goto bad_swap;
}
+
+ if (bdi_cap_stable_pages_required(inode_to_bdi(inode)))
+ p->flags |= SWP_STABLE_WRITES;
+
if (p->bdev && blk_queue_nonrot(bdev_get_queue(p->bdev))) {
int cpu;
return node_page_state(lruvec_pgdat(lruvec), NR_LRU_BASE + lru);
}
+unsigned long lruvec_zone_lru_size(struct lruvec *lruvec, enum lru_list lru,
+ int zone_idx)
+{
+ if (!mem_cgroup_disabled())
+ return mem_cgroup_get_zone_lru_size(lruvec, lru, zone_idx);
+
+ return zone_page_state(&lruvec_pgdat(lruvec)->node_zones[zone_idx],
+ NR_ZONE_LRU_BASE + lru);
+}
+
/*
* Add a shrinker callback to be called from the vm.
*/
* be complete before mem_cgroup_update_lru_size due to a santity check.
*/
static __always_inline void update_lru_sizes(struct lruvec *lruvec,
- enum lru_list lru, unsigned long *nr_zone_taken,
- unsigned long nr_taken)
+ enum lru_list lru, unsigned long *nr_zone_taken)
{
int zid;
continue;
__update_lru_size(lruvec, lru, zid, -nr_zone_taken[zid]);
- }
-
#ifdef CONFIG_MEMCG
- mem_cgroup_update_lru_size(lruvec, lru, -nr_taken);
+ mem_cgroup_update_lru_size(lruvec, lru, zid, -nr_zone_taken[zid]);
#endif
+ }
+
}
/*
*nr_scanned = scan;
trace_mm_vmscan_lru_isolate(sc->reclaim_idx, sc->order, nr_to_scan, scan,
nr_taken, mode, is_file_lru(lru));
- update_lru_sizes(lruvec, lru, nr_zone_taken, nr_taken);
+ update_lru_sizes(lruvec, lru, nr_zone_taken);
return nr_taken;
}
if (!managed_zone(zone))
continue;
- inactive_zone = zone_page_state(zone,
- NR_ZONE_LRU_BASE + (file * LRU_FILE));
- active_zone = zone_page_state(zone,
- NR_ZONE_LRU_BASE + (file * LRU_FILE) + LRU_ACTIVE);
+ inactive_zone = lruvec_zone_lru_size(lruvec, file * LRU_FILE, zid);
+ active_zone = lruvec_zone_lru_size(lruvec, (file * LRU_FILE) + LRU_ACTIVE, zid);
inactive -= min(inactive, inactive_zone);
active -= min(active, active_zone);
/* Enable/disable zswap (disabled by default) */
static bool zswap_enabled;
-module_param_named(enabled, zswap_enabled, bool, 0644);
+static int zswap_enabled_param_set(const char *,
+ const struct kernel_param *);
+static struct kernel_param_ops zswap_enabled_param_ops = {
+ .set = zswap_enabled_param_set,
+ .get = param_get_bool,
+};
+module_param_cb(enabled, &zswap_enabled_param_ops, &zswap_enabled, 0644);
/* Crypto compressor to use */
#define ZSWAP_COMPRESSOR_DEFAULT "lzo"
/* used by param callback function */
static bool zswap_init_started;
+/* fatal error during init */
+static bool zswap_init_failed;
+
/*********************************
* helpers and fwd declarations
**********************************/
char *s = strstrip((char *)val);
int ret;
+ if (zswap_init_failed) {
+ pr_err("can't set param, initialization failed\n");
+ return -ENODEV;
+ }
+
/* no change required */
if (!strcmp(s, *(char **)kp->arg))
return 0;
return __zswap_param_set(val, kp, NULL, zswap_compressor);
}
+static int zswap_enabled_param_set(const char *val,
+ const struct kernel_param *kp)
+{
+ if (zswap_init_failed) {
+ pr_err("can't enable, initialization failed\n");
+ return -ENODEV;
+ }
+
+ return param_set_bool(val, kp);
+}
+
/*********************************
* writeback code
**********************************/
dstmem_fail:
zswap_entry_cache_destroy();
cache_fail:
+ /* if built-in, we aren't unloaded on failure; don't allow use */
+ zswap_init_failed = true;
+ zswap_enabled = false;
return -ENOMEM;
}
/* must be late so crypto has time to come up */
config HWBM
bool
-config SOCK_CGROUP_DATA
- bool
- default n
-
config CGROUP_NET_PRIO
bool "Network priority cgroup"
depends on CGROUPS
{
ax25_clear_queues(ax25);
- if (!sock_flag(ax25->sk, SOCK_DESTROY))
+ if (!ax25->sk || !sock_flag(ax25->sk, SOCK_DESTROY))
ax25_stop_heartbeat(ax25);
ax25_stop_t1timer(ax25);
ax25_stop_t2timer(ax25);
primary_if = batadv_primary_if_get_selected(bat_priv);
if (!primary_if) {
ret = -EINVAL;
- goto put_primary_if;
+ goto free_skb;
}
/* Create one header to be copied to all fragments */
skb_fragment = batadv_frag_create(skb, &frag_header, mtu);
if (!skb_fragment) {
ret = -ENOMEM;
- goto free_skb;
+ goto put_primary_if;
}
batadv_inc_counter(bat_priv, BATADV_CNT_FRAG_TX);
ret = batadv_send_unicast_skb(skb_fragment, neigh_node);
if (ret != NET_XMIT_SUCCESS) {
ret = NET_XMIT_DROP;
- goto free_skb;
+ goto put_primary_if;
}
frag_header.no++;
/* The initial check in this function should cover this case */
if (frag_header.no == BATADV_FRAG_MAX_FRAGMENTS - 1) {
ret = -EINVAL;
- goto free_skb;
+ goto put_primary_if;
}
}
if (batadv_skb_head_push(skb, header_size) < 0 ||
pskb_expand_head(skb, header_size + ETH_HLEN, 0, GFP_ATOMIC) < 0) {
ret = -ENOMEM;
- goto free_skb;
+ goto put_primary_if;
}
memcpy(skb->data, &frag_header, header_size);
br_nf_hook_thresh(NF_BR_PRE_ROUTING,
net, sk, skb, skb->dev,
NULL,
- br_nf_pre_routing_finish);
+ br_nf_pre_routing_finish_bridge);
return 0;
}
ether_addr_copy(eth_hdr(skb)->h_dest, dev->dev_addr);
return 0;
}
-static int br_dev_newlink(struct net *src_net, struct net_device *dev,
- struct nlattr *tb[], struct nlattr *data[])
-{
- struct net_bridge *br = netdev_priv(dev);
-
- if (tb[IFLA_ADDRESS]) {
- spin_lock_bh(&br->lock);
- br_stp_change_bridge_id(br, nla_data(tb[IFLA_ADDRESS]));
- spin_unlock_bh(&br->lock);
- }
-
- return register_netdevice(dev);
-}
-
static int br_port_slave_changelink(struct net_device *brdev,
struct net_device *dev,
struct nlattr *tb[],
return 0;
}
+static int br_dev_newlink(struct net *src_net, struct net_device *dev,
+ struct nlattr *tb[], struct nlattr *data[])
+{
+ struct net_bridge *br = netdev_priv(dev);
+ int err;
+
+ if (tb[IFLA_ADDRESS]) {
+ spin_lock_bh(&br->lock);
+ br_stp_change_bridge_id(br, nla_data(tb[IFLA_ADDRESS]));
+ spin_unlock_bh(&br->lock);
+ }
+
+ err = br_changelink(dev, tb, data);
+ if (err)
+ return err;
+
+ return register_netdevice(dev);
+}
+
static size_t br_get_size(const struct net_device *brdev)
{
return nla_total_size(sizeof(u32)) + /* IFLA_BR_FORWARD_DELAY */
* @func: callback function on filter match
* @data: returned parameter for callback function
* @ident: string for calling module identification
+ * @sk: socket pointer (might be NULL)
*
* Description:
* Invokes the callback function with the received sk_buff and the given
*/
int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask,
void (*func)(struct sk_buff *, void *), void *data,
- char *ident)
+ char *ident, struct sock *sk)
{
struct receiver *r;
struct hlist_head *rl;
r->func = func;
r->data = data;
r->ident = ident;
+ r->sk = sk;
hlist_add_head_rcu(&r->list, rl);
d->entries++;
static void can_rx_delete_receiver(struct rcu_head *rp)
{
struct receiver *r = container_of(rp, struct receiver, rcu);
+ struct sock *sk = r->sk;
kmem_cache_free(rcv_cache, r);
+ if (sk)
+ sock_put(sk);
}
/**
spin_unlock(&can_rcvlists_lock);
/* schedule the receiver item for deletion */
- if (r)
+ if (r) {
+ if (r->sk)
+ sock_hold(r->sk);
call_rcu(&r->rcu, can_rx_delete_receiver);
+ }
}
EXPORT_SYMBOL(can_rx_unregister);
struct receiver {
struct hlist_node list;
- struct rcu_head rcu;
canid_t can_id;
canid_t mask;
unsigned long matches;
void (*func)(struct sk_buff *, void *);
void *data;
char *ident;
+ struct sock *sk;
+ struct rcu_head rcu;
};
#define CAN_SFF_RCV_ARRAY_SZ (1 << CAN_SFF_ID_BITS)
static void bcm_remove_op(struct bcm_op *op)
{
- hrtimer_cancel(&op->timer);
- hrtimer_cancel(&op->thrtimer);
-
- if (op->tsklet.func)
- tasklet_kill(&op->tsklet);
+ if (op->tsklet.func) {
+ while (test_bit(TASKLET_STATE_SCHED, &op->tsklet.state) ||
+ test_bit(TASKLET_STATE_RUN, &op->tsklet.state) ||
+ hrtimer_active(&op->timer)) {
+ hrtimer_cancel(&op->timer);
+ tasklet_kill(&op->tsklet);
+ }
+ }
- if (op->thrtsklet.func)
- tasklet_kill(&op->thrtsklet);
+ if (op->thrtsklet.func) {
+ while (test_bit(TASKLET_STATE_SCHED, &op->thrtsklet.state) ||
+ test_bit(TASKLET_STATE_RUN, &op->thrtsklet.state) ||
+ hrtimer_active(&op->thrtimer)) {
+ hrtimer_cancel(&op->thrtimer);
+ tasklet_kill(&op->thrtsklet);
+ }
+ }
if ((op->frames) && (op->frames != &op->sframe))
kfree(op->frames);
err = can_rx_register(dev, op->can_id,
REGMASK(op->can_id),
bcm_rx_handler, op,
- "bcm");
+ "bcm", sk);
op->rx_reg_dev = dev;
dev_put(dev);
} else
err = can_rx_register(NULL, op->can_id,
REGMASK(op->can_id),
- bcm_rx_handler, op, "bcm");
+ bcm_rx_handler, op, "bcm", sk);
if (err) {
/* this bcm rx op is broken -> remove it */
list_del(&op->list);
{
return can_rx_register(gwj->src.dev, gwj->ccgw.filter.can_id,
gwj->ccgw.filter.can_mask, can_can_gw_rcv,
- gwj, "gw");
+ gwj, "gw", NULL);
}
static inline void cgw_unregister_filter(struct cgw_job *gwj)
for (i = 0; i < count; i++) {
err = can_rx_register(dev, filter[i].can_id,
filter[i].can_mask,
- raw_rcv, sk, "raw");
+ raw_rcv, sk, "raw", sk);
if (err) {
/* clean up successfully registered filters */
while (--i >= 0)
if (err_mask)
err = can_rx_register(dev, 0, err_mask | CAN_ERR_FLAG,
- raw_rcv, sk, "raw");
+ raw_rcv, sk, "raw", sk);
return err;
}
SKCIPHER_REQUEST_ON_STACK(req, key->tfm);
struct sg_table sgt;
struct scatterlist prealloc_sg;
- char iv[AES_BLOCK_SIZE];
+ char iv[AES_BLOCK_SIZE] __aligned(8);
int pad_byte = AES_BLOCK_SIZE - (in_len & (AES_BLOCK_SIZE - 1));
int crypt_len = encrypt ? in_len + pad_byte : in_len;
int ret;
if (skb->ip_summed != CHECKSUM_NONE &&
!can_checksum_protocol(features, type)) {
features &= ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
- } else if (illegal_highdma(skb->dev, skb)) {
- features &= ~NETIF_F_SG;
}
+ if (illegal_highdma(skb->dev, skb))
+ features &= ~NETIF_F_SG;
return features;
}
pinfo->nr_frags &&
!PageHighMem(skb_frag_page(frag0))) {
NAPI_GRO_CB(skb)->frag0 = skb_frag_address(frag0);
- NAPI_GRO_CB(skb)->frag0_len = skb_frag_size(frag0);
+ NAPI_GRO_CB(skb)->frag0_len = min_t(unsigned int,
+ skb_frag_size(frag0),
+ skb->end - skb->tail);
}
}
static noinline_for_stack int ethtool_set_channels(struct net_device *dev,
void __user *useraddr)
{
- struct ethtool_channels channels, max;
+ struct ethtool_channels channels, max = { .cmd = ETHTOOL_GCHANNELS };
u32 max_rx_in_use = 0;
if (!dev->ethtool_ops->set_channels || !dev->ethtool_ops->get_channels)
* The function will try to retrieve a be32 entity at
* offset poff
*/
-__be16 skb_flow_get_be16(const struct sk_buff *skb, int poff, void *data,
- int hlen)
+static __be16 skb_flow_get_be16(const struct sk_buff *skb, int poff,
+ void *data, int hlen)
{
__be16 *u, _u;
.fill_encap = bpf_fill_encap_info,
.get_encap_size = bpf_encap_nlsize,
.cmp_encap = bpf_encap_cmp,
+ .owner = THIS_MODULE,
};
static int __init bpf_lwt_init(void)
#include <net/lwtunnel.h>
#include <net/rtnetlink.h>
#include <net/ip6_fib.h>
+#include <net/nexthop.h>
#ifdef CONFIG_MODULES
ret = -EOPNOTSUPP;
rcu_read_lock();
ops = rcu_dereference(lwtun_encaps[encap_type]);
+ if (likely(ops && ops->build_state && try_module_get(ops->owner))) {
+ ret = ops->build_state(dev, encap, family, cfg, lws);
+ if (ret)
+ module_put(ops->owner);
+ }
+ rcu_read_unlock();
+
+ return ret;
+}
+EXPORT_SYMBOL(lwtunnel_build_state);
+
+int lwtunnel_valid_encap_type(u16 encap_type)
+{
+ const struct lwtunnel_encap_ops *ops;
+ int ret = -EINVAL;
+
+ if (encap_type == LWTUNNEL_ENCAP_NONE ||
+ encap_type > LWTUNNEL_ENCAP_MAX)
+ return ret;
+
+ rcu_read_lock();
+ ops = rcu_dereference(lwtun_encaps[encap_type]);
+ rcu_read_unlock();
#ifdef CONFIG_MODULES
if (!ops) {
const char *encap_type_str = lwtunnel_encap_str(encap_type);
if (encap_type_str) {
- rcu_read_unlock();
+ __rtnl_unlock();
request_module("rtnl-lwt-%s", encap_type_str);
+ rtnl_lock();
+
rcu_read_lock();
ops = rcu_dereference(lwtun_encaps[encap_type]);
+ rcu_read_unlock();
}
}
#endif
- if (likely(ops && ops->build_state))
- ret = ops->build_state(dev, encap, family, cfg, lws);
- rcu_read_unlock();
+ return ops ? 0 : -EOPNOTSUPP;
+}
+EXPORT_SYMBOL(lwtunnel_valid_encap_type);
- return ret;
+int lwtunnel_valid_encap_type_attr(struct nlattr *attr, int remaining)
+{
+ struct rtnexthop *rtnh = (struct rtnexthop *)attr;
+ struct nlattr *nla_entype;
+ struct nlattr *attrs;
+ struct nlattr *nla;
+ u16 encap_type;
+ int attrlen;
+
+ while (rtnh_ok(rtnh, remaining)) {
+ attrlen = rtnh_attrlen(rtnh);
+ if (attrlen > 0) {
+ attrs = rtnh_attrs(rtnh);
+ nla = nla_find(attrs, attrlen, RTA_ENCAP);
+ nla_entype = nla_find(attrs, attrlen, RTA_ENCAP_TYPE);
+
+ if (nla_entype) {
+ encap_type = nla_get_u16(nla_entype);
+
+ if (lwtunnel_valid_encap_type(encap_type) != 0)
+ return -EOPNOTSUPP;
+ }
+ }
+ rtnh = rtnh_next(rtnh, &remaining);
+ }
+
+ return 0;
}
-EXPORT_SYMBOL(lwtunnel_build_state);
+EXPORT_SYMBOL(lwtunnel_valid_encap_type_attr);
void lwtstate_free(struct lwtunnel_state *lws)
{
} else {
kfree(lws);
}
+ module_put(ops->owner);
}
EXPORT_SYMBOL(lwtstate_free);
local_irq_save(flags);
nc = this_cpu_ptr(&netdev_alloc_cache);
- data = __alloc_page_frag(nc, fragsz, gfp_mask);
+ data = page_frag_alloc(nc, fragsz, gfp_mask);
local_irq_restore(flags);
return data;
}
{
struct napi_alloc_cache *nc = this_cpu_ptr(&napi_alloc_cache);
- return __alloc_page_frag(&nc->page, fragsz, gfp_mask);
+ return page_frag_alloc(&nc->page, fragsz, gfp_mask);
}
void *napi_alloc_frag(unsigned int fragsz)
local_irq_save(flags);
nc = this_cpu_ptr(&netdev_alloc_cache);
- data = __alloc_page_frag(nc, len, gfp_mask);
+ data = page_frag_alloc(nc, len, gfp_mask);
pfmemalloc = nc->pfmemalloc;
local_irq_restore(flags);
if (sk_memalloc_socks())
gfp_mask |= __GFP_MEMALLOC;
- data = __alloc_page_frag(&nc->page, len, gfp_mask);
+ data = page_frag_alloc(&nc->page, len, gfp_mask);
if (unlikely(!data))
return NULL;
"sk_lock-AF_RXRPC" , "sk_lock-AF_ISDN" , "sk_lock-AF_PHONET" ,
"sk_lock-AF_IEEE802154", "sk_lock-AF_CAIF" , "sk_lock-AF_ALG" ,
"sk_lock-AF_NFC" , "sk_lock-AF_VSOCK" , "sk_lock-AF_KCM" ,
- "sk_lock-AF_MAX"
+ "sk_lock-AF_QIPCRTR", "sk_lock-AF_MAX"
};
static const char *const af_family_slock_key_strings[AF_MAX+1] = {
"slock-AF_UNSPEC", "slock-AF_UNIX" , "slock-AF_INET" ,
"slock-AF_RXRPC" , "slock-AF_ISDN" , "slock-AF_PHONET" ,
"slock-AF_IEEE802154", "slock-AF_CAIF" , "slock-AF_ALG" ,
"slock-AF_NFC" , "slock-AF_VSOCK" ,"slock-AF_KCM" ,
- "slock-AF_MAX"
+ "slock-AF_QIPCRTR", "slock-AF_MAX"
};
static const char *const af_family_clock_key_strings[AF_MAX+1] = {
"clock-AF_UNSPEC", "clock-AF_UNIX" , "clock-AF_INET" ,
"clock-AF_RXRPC" , "clock-AF_ISDN" , "clock-AF_PHONET" ,
"clock-AF_IEEE802154", "clock-AF_CAIF" , "clock-AF_ALG" ,
"clock-AF_NFC" , "clock-AF_VSOCK" , "clock-AF_KCM" ,
- "clock-AF_MAX"
+ "clock-AF_QIPCRTR", "clock-AF_MAX"
};
/*
opt = ireq->ipv6_opt;
if (!opt)
opt = rcu_dereference(np->opt);
- err = ip6_xmit(sk, skb, &fl6, opt, np->tclass);
+ err = ip6_xmit(sk, skb, &fl6, sk->sk_mark, opt, np->tclass);
rcu_read_unlock();
err = net_xmit_eval(err);
}
dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL);
if (!IS_ERR(dst)) {
skb_dst_set(skb, dst);
- ip6_xmit(ctl_sk, skb, &fl6, NULL, 0);
+ ip6_xmit(ctl_sk, skb, &fl6, 0, NULL, 0);
DCCP_INC_STATS(DCCP_MIB_OUTSEGS);
DCCP_INC_STATS(DCCP_MIB_OUTRSTS);
return;
return err;
}
- err = dsa_cpu_port_ethtool_setup(dst->ds[0]);
- if (err)
- return err;
+ if (dst->ds[0]) {
+ err = dsa_cpu_port_ethtool_setup(dst->ds[0]);
+ if (err)
+ return err;
+ }
/* If we use a tagging format that doesn't have an ethertype
* field, make sure that all packets from this point on get
dsa_ds_unapply(dst, ds);
}
- dsa_cpu_port_ethtool_restore(dst->ds[0]);
+ if (dst->ds[0])
+ dsa_cpu_port_ethtool_restore(dst->ds[0]);
pr_info("DSA: tree %d unapplied\n", dst->tree);
dst->applied = false;
/* Use already configured phy mode */
if (p->phy_interface == PHY_INTERFACE_MODE_NA)
p->phy_interface = p->phy->interface;
- phy_connect_direct(slave_dev, p->phy, dsa_slave_adjust_link,
- p->phy_interface);
-
- return 0;
+ return phy_connect_direct(slave_dev, p->phy, dsa_slave_adjust_link,
+ p->phy_interface);
}
static int dsa_slave_phy_setup(struct dsa_slave_priv *p,
{
struct dsa_slave_priv *p = netdev_priv(slave_dev);
+ netif_device_detach(slave_dev);
+
if (p->phy) {
phy_stop(p->phy);
p->old_pause = -1;
#include <net/rtnetlink.h>
#include <net/xfrm.h>
#include <net/l3mdev.h>
+#include <net/lwtunnel.h>
#include <trace/events/fib.h>
#ifndef CONFIG_IP_MULTIPLE_TABLES
cfg->fc_mx_len = nla_len(attr);
break;
case RTA_MULTIPATH:
+ err = lwtunnel_valid_encap_type_attr(nla_data(attr),
+ nla_len(attr));
+ if (err < 0)
+ goto errout;
cfg->fc_mp = nla_data(attr);
cfg->fc_mp_len = nla_len(attr);
break;
break;
case RTA_ENCAP_TYPE:
cfg->fc_encap_type = nla_get_u16(attr);
+ err = lwtunnel_valid_encap_type(cfg->fc_encap_type);
+ if (err < 0)
+ goto errout;
break;
}
}
nla_put_u32(skb, RTA_FLOW, fi->fib_nh[0].nh_tclassid))
goto nla_put_failure;
#endif
- if (fi->fib_nh->nh_lwtstate)
- lwtunnel_fill_encap(skb, fi->fib_nh->nh_lwtstate);
+ if (fi->fib_nh->nh_lwtstate &&
+ lwtunnel_fill_encap(skb, fi->fib_nh->nh_lwtstate) < 0)
+ goto nla_put_failure;
}
#ifdef CONFIG_IP_ROUTE_MULTIPATH
if (fi->fib_nhs > 1) {
nla_put_u32(skb, RTA_FLOW, nh->nh_tclassid))
goto nla_put_failure;
#endif
- if (nh->nh_lwtstate)
- lwtunnel_fill_encap(skb, nh->nh_lwtstate);
+ if (nh->nh_lwtstate &&
+ lwtunnel_fill_encap(skb, nh->nh_lwtstate) < 0)
+ goto nla_put_failure;
+
/* length of rtnetlink header + attributes */
rtnh->rtnh_len = nlmsg_get_pos(skb) - (void *) rtnh;
} endfor_nexthops(fi);
void fib_select_path(struct net *net, struct fib_result *res,
struct flowi4 *fl4, int mp_hash)
{
+ bool oif_check;
+
+ oif_check = (fl4->flowi4_oif == 0 ||
+ fl4->flowi4_flags & FLOWI_FLAG_SKIP_NH_OIF);
+
#ifdef CONFIG_IP_ROUTE_MULTIPATH
- if (res->fi->fib_nhs > 1 && fl4->flowi4_oif == 0) {
+ if (res->fi->fib_nhs > 1 && oif_check) {
if (mp_hash < 0)
mp_hash = get_hash_from_flowi4(fl4) >> 1;
#endif
if (!res->prefixlen &&
res->table->tb_num_default > 1 &&
- res->type == RTN_UNICAST && !fl4->flowi4_oif)
+ res->type == RTN_UNICAST && oif_check)
fib_select_default(fl4, res);
if (!fl4->saddr)
sk->sk_protocol = ip_hdr(skb)->protocol;
sk->sk_bound_dev_if = arg->bound_dev_if;
sk->sk_sndbuf = sysctl_wmem_default;
+ sk->sk_mark = fl4.flowi4_mark;
err = ip_append_data(sk, &fl4, ip_reply_glue_bits, arg->iov->iov_base,
len, 0, &ipc, &rt, MSG_DONTWAIT);
if (unlikely(err)) {
.fill_encap = ip_tun_fill_encap_info,
.get_encap_size = ip_tun_encap_nlsize,
.cmp_encap = ip_tun_cmp_encap,
+ .owner = THIS_MODULE,
};
static const struct nla_policy ip6_tun_policy[LWTUNNEL_IP6_MAX + 1] = {
.fill_encap = ip6_tun_fill_encap_info,
.get_encap_size = ip6_tun_encap_nlsize,
.cmp_encap = ip_tun_cmp_encap,
+ .owner = THIS_MODULE,
};
void __init ip_tunnel_core_init(void)
rcu_read_lock_bh();
c = __clusterip_config_find(net, clusterip);
if (c) {
+#ifdef CONFIG_PROC_FS
+ if (!c->pde)
+ c = NULL;
+ else
+#endif
if (unlikely(!atomic_inc_not_zero(&c->refcount)))
c = NULL;
else if (entry)
static struct clusterip_config *
clusterip_config_init(const struct ipt_clusterip_tgt_info *i, __be32 ip,
- struct net_device *dev)
+ struct net_device *dev)
{
+ struct net *net = dev_net(dev);
struct clusterip_config *c;
- struct clusterip_net *cn = net_generic(dev_net(dev), clusterip_net_id);
+ struct clusterip_net *cn = net_generic(net, clusterip_net_id);
c = kzalloc(sizeof(*c), GFP_ATOMIC);
if (!c)
- return NULL;
+ return ERR_PTR(-ENOMEM);
c->dev = dev;
c->clusterip = ip;
atomic_set(&c->refcount, 1);
atomic_set(&c->entries, 1);
+ spin_lock_bh(&cn->lock);
+ if (__clusterip_config_find(net, ip)) {
+ spin_unlock_bh(&cn->lock);
+ kfree(c);
+
+ return ERR_PTR(-EBUSY);
+ }
+
+ list_add_rcu(&c->list, &cn->configs);
+ spin_unlock_bh(&cn->lock);
+
#ifdef CONFIG_PROC_FS
{
char buffer[16];
cn->procdir,
&clusterip_proc_fops, c);
if (!c->pde) {
+ spin_lock_bh(&cn->lock);
+ list_del_rcu(&c->list);
+ spin_unlock_bh(&cn->lock);
kfree(c);
- return NULL;
+
+ return ERR_PTR(-ENOMEM);
}
}
#endif
- spin_lock_bh(&cn->lock);
- list_add_rcu(&c->list, &cn->configs);
- spin_unlock_bh(&cn->lock);
-
return c;
}
config = clusterip_config_init(cipinfo,
e->ip.dst.s_addr, dev);
- if (!config) {
+ if (IS_ERR(config)) {
dev_put(dev);
- return -ENOMEM;
+ return PTR_ERR(config);
}
dev_mc_add(config->dev, config->clustermac);
}
return dev_match || flags & XT_RPFILTER_LOOSE;
}
-static bool rpfilter_is_local(const struct sk_buff *skb)
+static bool
+rpfilter_is_loopback(const struct sk_buff *skb, const struct net_device *in)
{
- const struct rtable *rt = skb_rtable(skb);
- return rt && (rt->rt_flags & RTCF_LOCAL);
+ return skb->pkt_type == PACKET_LOOPBACK || in->flags & IFF_LOOPBACK;
}
static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par)
info = par->matchinfo;
invert = info->flags & XT_RPFILTER_INVERT;
- if (rpfilter_is_local(skb))
+ if (rpfilter_is_loopback(skb, xt_in(par)))
return true ^ invert;
iph = ip_hdr(skb);
/* ip_route_me_harder expects skb->dst to be set */
skb_dst_set_noref(nskb, skb_dst(oldskb));
+ nskb->mark = IP4_REPLY_MARK(net, oldskb->mark);
+
skb_reserve(nskb, LL_MAX_HEADER);
niph = nf_reject_iphdr_put(nskb, oldskb, IPPROTO_TCP,
ip4_dst_hoplimit(skb_dst(nskb)));
return addr;
}
-static bool fib4_is_local(const struct sk_buff *skb)
-{
- const struct rtable *rt = skb_rtable(skb);
-
- return rt && (rt->rt_flags & RTCF_LOCAL);
-}
-
#define DSCP_BITS 0xfc
void nft_fib4_eval_type(const struct nft_expr *expr, struct nft_regs *regs,
else
oif = NULL;
- if (nft_hook(pkt) == NF_INET_PRE_ROUTING && fib4_is_local(pkt->skb)) {
- nft_fib_store_result(dest, priv->result, pkt, LOOPBACK_IFINDEX);
+ if (nft_hook(pkt) == NF_INET_PRE_ROUTING &&
+ nft_fib_is_loopback(pkt->skb, nft_in(pkt))) {
+ nft_fib_store_result(dest, priv->result, pkt,
+ nft_in(pkt)->ifindex);
return;
}
switch (res.type) {
case RTN_UNICAST:
break;
- case RTN_LOCAL: /* should not appear here, see fib4_is_local() above */
+ case RTN_LOCAL: /* Should not see RTN_LOCAL here */
return;
default:
break;
r->rtm_dst_len = 32;
r->rtm_src_len = 0;
r->rtm_tos = fl4->flowi4_tos;
- r->rtm_table = table_id;
+ r->rtm_table = table_id < 256 ? table_id : RT_TABLE_COMPAT;
if (nla_put_u32(skb, RTA_TABLE, table_id))
goto nla_put_failure;
r->rtm_type = rt->rt_type;
.data = &init_net.ipv4.sysctl_tcp_notsent_lowat,
.maxlen = sizeof(unsigned int),
.mode = 0644,
- .proc_handler = proc_dointvec,
+ .proc_handler = proc_douintvec,
},
{
.procname = "tcp_tw_reuse",
struct tcp_fastopen_cookie tmp;
if (__tcp_fastopen_cookie_gen(&ip6h->saddr, &tmp)) {
- struct in6_addr *buf = (struct in6_addr *) tmp.val;
+ struct in6_addr *buf = &tmp.addr;
int i;
for (i = 0; i < 4; i++)
* scaled. So correct it appropriately.
*/
tp->snd_wnd = ntohs(tcp_hdr(skb)->window);
+ tp->max_window = tp->snd_wnd;
/* Activate the retrans timer so that SYNACK can be retransmitted.
* The request socket is not added to the ehash
if (sock_flag(sk, SOCK_QUEUE_SHRUNK)) {
sock_reset_flag(sk, SOCK_QUEUE_SHRUNK);
/* pairs with tcp_poll() */
- smp_mb__after_atomic();
+ smp_mb();
if (sk->sk_socket &&
test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) {
tcp_new_space(sk);
return ret;
}
-EXPORT_SYMBOL_GPL(tcp_peer_is_proven);
void tcp_fetch_timewait_stamp(struct sock *sk, struct dst_entry *dst)
{
int full_space = min_t(int, tp->window_clamp, allowed_space);
int window;
- if (mss > full_space)
+ if (unlikely(mss > full_space)) {
mss = full_space;
-
+ if (mss <= 0)
+ return 0;
+ }
if (free_space < (full_space >> 1)) {
icsk->icsk_ack.quick = 0;
struct net_device *dev;
struct inet6_dev *idev;
- rcu_read_lock();
- for_each_netdev_rcu(net, dev) {
+ for_each_netdev(net, dev) {
idev = __in6_dev_get(dev);
if (idev) {
int changed = (!idev->cnf.disable_ipv6) ^ (!newf);
dev_disable_change(idev);
}
}
- rcu_read_unlock();
}
static int addrconf_disable_ipv6(struct ctl_table *table, int *p, int newf)
.fill_encap = ila_fill_encap_info,
.get_encap_size = ila_encap_nlsize,
.cmp_encap = ila_encap_cmp,
+ .owner = THIS_MODULE,
};
int ila_lwt_init(void)
/* Restore final destination back after routing done */
fl6.daddr = sk->sk_v6_daddr;
- res = ip6_xmit(sk, skb, &fl6, rcu_dereference(np->opt),
+ res = ip6_xmit(sk, skb, &fl6, sk->sk_mark, rcu_dereference(np->opt),
np->tclass);
rcu_read_unlock();
return res;
return -1;
offset = ip6_tnl_parse_tlv_enc_lim(skb, skb_network_header(skb));
+ /* ip6_tnl_parse_tlv_enc_lim() might have reallocated skb->head */
+ ipv6h = ipv6_hdr(skb);
+
if (offset > 0) {
struct ipv6_tlv_tnl_enc_lim *tel;
tel = (struct ipv6_tlv_tnl_enc_lim *)&skb_network_header(skb)[offset];
ops = rcu_dereference(inet6_offloads[proto]);
if (!ops || !ops->callbacks.gro_receive) {
__pskb_pull(skb, skb_gro_offset(skb));
+ skb_gro_frag0_invalidate(skb);
proto = ipv6_gso_pull_exthdrs(skb, proto);
skb_gro_pull(skb, -skb_transport_offset(skb));
skb_reset_transport_header(skb);
* which are using proper atomic operations or spinlocks.
*/
int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
- struct ipv6_txoptions *opt, int tclass)
+ __u32 mark, struct ipv6_txoptions *opt, int tclass)
{
struct net *net = sock_net(sk);
const struct ipv6_pinfo *np = inet6_sk(sk);
skb->protocol = htons(ETH_P_IPV6);
skb->priority = sk->sk_priority;
- skb->mark = sk->sk_mark;
+ skb->mark = mark;
mtu = dst_mtu(dst);
if ((skb->len <= mtu) || skb->ignore_df || skb_is_gso(skb)) {
*/
if (transhdrlen && sk->sk_protocol == IPPROTO_UDP &&
headersize == sizeof(struct ipv6hdr) &&
- length < mtu - headersize &&
+ length <= mtu - headersize &&
!(flags & MSG_MORE) &&
rt->dst.dev->features & (NETIF_F_IPV6_CSUM | NETIF_F_HW_CSUM))
csummode = CHECKSUM_PARTIAL;
__u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw)
{
- const struct ipv6hdr *ipv6h = (const struct ipv6hdr *) raw;
- __u8 nexthdr = ipv6h->nexthdr;
- __u16 off = sizeof(*ipv6h);
+ const struct ipv6hdr *ipv6h = (const struct ipv6hdr *)raw;
+ unsigned int nhoff = raw - skb->data;
+ unsigned int off = nhoff + sizeof(*ipv6h);
+ u8 next, nexthdr = ipv6h->nexthdr;
while (ipv6_ext_hdr(nexthdr) && nexthdr != NEXTHDR_NONE) {
- __u16 optlen = 0;
struct ipv6_opt_hdr *hdr;
- if (raw + off + sizeof(*hdr) > skb->data &&
- !pskb_may_pull(skb, raw - skb->data + off + sizeof (*hdr)))
+ u16 optlen;
+
+ if (!pskb_may_pull(skb, off + sizeof(*hdr)))
break;
- hdr = (struct ipv6_opt_hdr *) (raw + off);
+ hdr = (struct ipv6_opt_hdr *)(skb->data + off);
if (nexthdr == NEXTHDR_FRAGMENT) {
struct frag_hdr *frag_hdr = (struct frag_hdr *) hdr;
if (frag_hdr->frag_off)
} else {
optlen = ipv6_optlen(hdr);
}
+ /* cache hdr->nexthdr, since pskb_may_pull() might
+ * invalidate hdr
+ */
+ next = hdr->nexthdr;
if (nexthdr == NEXTHDR_DEST) {
- __u16 i = off + 2;
+ u16 i = 2;
+
+ /* Remember : hdr is no longer valid at this point. */
+ if (!pskb_may_pull(skb, off + optlen))
+ break;
+
while (1) {
struct ipv6_tlv_tnl_enc_lim *tel;
/* No more room for encapsulation limit */
- if (i + sizeof (*tel) > off + optlen)
+ if (i + sizeof(*tel) > optlen)
break;
- tel = (struct ipv6_tlv_tnl_enc_lim *) &raw[i];
+ tel = (struct ipv6_tlv_tnl_enc_lim *)(skb->data + off + i);
/* return index of option if found and valid */
if (tel->type == IPV6_TLV_TNL_ENCAP_LIMIT &&
tel->length == 1)
- return i;
+ return i + off - nhoff;
/* else jump to next option */
if (tel->type)
i += tel->length + 2;
i++;
}
}
- nexthdr = hdr->nexthdr;
+ nexthdr = next;
off += optlen;
}
return 0;
t->parms.name);
goto tx_err_dst_release;
}
- mtu = dst_mtu(dst) - psh_hlen;
+ mtu = dst_mtu(dst) - psh_hlen - t->tun_hlen;
if (encap_limit >= 0) {
max_headroom += 8;
mtu -= 8;
mtu = IPV6_MIN_MTU;
if (skb_dst(skb) && !t->parms.collect_md)
skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu);
- if (skb->len > mtu && !skb_is_gso(skb)) {
+ if (skb->len - t->tun_hlen > mtu && !skb_is_gso(skb)) {
*pmtu = mtu;
err = -EMSGSIZE;
goto tx_err_dst_release;
fl6.flowlabel = key->label;
} else {
offset = ip6_tnl_parse_tlv_enc_lim(skb, skb_network_header(skb));
+ /* ip6_tnl_parse_tlv_enc_lim() might have reallocated skb->head */
+ ipv6h = ipv6_hdr(skb);
if (offset > 0) {
struct ipv6_tlv_tnl_enc_lim *tel;
struct vti6_net *ip6n = net_generic(net, vti6_net_id);
int err;
+ dev->rtnl_link_ops = &vti6_link_ops;
err = register_netdevice(dev);
if (err < 0)
goto out;
strcpy(t->parms.name, dev->name);
- dev->rtnl_link_ops = &vti6_link_ops;
dev_hold(dev);
vti6_tnl_link(ip6n, t);
static void mld_ifc_timer_expire(unsigned long data);
static void mld_ifc_event(struct inet6_dev *idev);
static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *pmc);
-static void mld_del_delrec(struct inet6_dev *idev, const struct in6_addr *addr);
+static void mld_del_delrec(struct inet6_dev *idev, struct ifmcaddr6 *pmc);
static void mld_clear_delrec(struct inet6_dev *idev);
static bool mld_in_v1_mode(const struct inet6_dev *idev);
static int sf_setstate(struct ifmcaddr6 *pmc);
dev_mc_del(dev, buf);
}
- if (mc->mca_flags & MAF_NOREPORT)
- goto done;
spin_unlock_bh(&mc->mca_lock);
+ if (mc->mca_flags & MAF_NOREPORT)
+ return;
if (!mc->idev->dead)
igmp6_leave_group(mc);
spin_lock_bh(&mc->mca_lock);
if (del_timer(&mc->mca_timer))
atomic_dec(&mc->mca_refcnt);
-done:
- ip6_mc_clear_src(mc);
spin_unlock_bh(&mc->mca_lock);
}
spin_unlock_bh(&idev->mc_lock);
}
-static void mld_del_delrec(struct inet6_dev *idev, const struct in6_addr *pmca)
+static void mld_del_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im)
{
struct ifmcaddr6 *pmc, *pmc_prev;
- struct ip6_sf_list *psf, *psf_next;
+ struct ip6_sf_list *psf;
+ struct in6_addr *pmca = &im->mca_addr;
spin_lock_bh(&idev->mc_lock);
pmc_prev = NULL;
}
spin_unlock_bh(&idev->mc_lock);
+ spin_lock_bh(&im->mca_lock);
if (pmc) {
- for (psf = pmc->mca_tomb; psf; psf = psf_next) {
- psf_next = psf->sf_next;
- kfree(psf);
+ im->idev = pmc->idev;
+ im->mca_crcount = idev->mc_qrv;
+ im->mca_sfmode = pmc->mca_sfmode;
+ if (pmc->mca_sfmode == MCAST_INCLUDE) {
+ im->mca_tomb = pmc->mca_tomb;
+ im->mca_sources = pmc->mca_sources;
+ for (psf = im->mca_sources; psf; psf = psf->sf_next)
+ psf->sf_crcount = im->mca_crcount;
}
in6_dev_put(pmc->idev);
- kfree(pmc);
}
+ spin_unlock_bh(&im->mca_lock);
}
static void mld_clear_delrec(struct inet6_dev *idev)
mca_get(mc);
write_unlock_bh(&idev->lock);
- mld_del_delrec(idev, &mc->mca_addr);
+ mld_del_delrec(idev, mc);
igmp6_group_added(mc);
ma_put(mc);
return 0;
write_unlock_bh(&idev->lock);
igmp6_group_dropped(ma);
+ ip6_mc_clear_src(ma);
ma_put(ma);
return 0;
/* Withdraw multicast list */
read_lock_bh(&idev->lock);
- mld_ifc_stop_timer(idev);
- mld_gq_stop_timer(idev);
- mld_dad_stop_timer(idev);
for (i = idev->mc_list; i; i = i->next)
igmp6_group_dropped(i);
- read_unlock_bh(&idev->lock);
- mld_clear_delrec(idev);
+ /* Should stop timer after group drop. or we will
+ * start timer again in mld_ifc_event()
+ */
+ mld_ifc_stop_timer(idev);
+ mld_gq_stop_timer(idev);
+ mld_dad_stop_timer(idev);
+ read_unlock_bh(&idev->lock);
}
static void ipv6_mc_reset(struct inet6_dev *idev)
read_lock_bh(&idev->lock);
ipv6_mc_reset(idev);
- for (i = idev->mc_list; i; i = i->next)
+ for (i = idev->mc_list; i; i = i->next) {
+ mld_del_delrec(idev, i);
igmp6_group_added(i);
+ }
read_unlock_bh(&idev->lock);
}
/* Deactivate timers */
ipv6_mc_down(idev);
+ mld_clear_delrec(idev);
/* Delete all-nodes address. */
/* We cannot call ipv6_dev_mc_dec() directly, our caller in
write_lock_bh(&idev->lock);
while ((i = idev->mc_list) != NULL) {
idev->mc_list = i->next;
- write_unlock_bh(&idev->lock);
- igmp6_group_dropped(i);
+ write_unlock_bh(&idev->lock);
ma_put(i);
-
write_lock_bh(&idev->lock);
}
write_unlock_bh(&idev->lock);
return ret;
}
-static bool rpfilter_is_local(const struct sk_buff *skb)
+static bool
+rpfilter_is_loopback(const struct sk_buff *skb, const struct net_device *in)
{
- const struct rt6_info *rt = (const void *) skb_dst(skb);
- return rt && (rt->rt6i_flags & RTF_LOCAL);
+ return skb->pkt_type == PACKET_LOOPBACK || in->flags & IFF_LOOPBACK;
}
static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par)
struct ipv6hdr *iph;
bool invert = info->flags & XT_RPFILTER_INVERT;
- if (rpfilter_is_local(skb))
+ if (rpfilter_is_loopback(skb, xt_in(par)))
return true ^ invert;
iph = ipv6_hdr(skb);
fl6.fl6_sport = otcph->dest;
fl6.fl6_dport = otcph->source;
fl6.flowi6_oif = l3mdev_master_ifindex(skb_dst(oldskb)->dev);
+ fl6.flowi6_mark = IP6_REPLY_MARK(net, oldskb->mark);
security_skb_classify_flow(oldskb, flowi6_to_flowi(&fl6));
dst = ip6_route_output(net, NULL, &fl6);
if (dst->error) {
skb_dst_set(nskb, dst);
+ nskb->mark = fl6.flowi6_mark;
+
skb_reserve(nskb, hh_len + dst->header_len);
ip6h = nf_reject_ip6hdr_put(nskb, oldskb, IPPROTO_TCP,
ip6_dst_hoplimit(dst));
#include <net/ip6_fib.h>
#include <net/ip6_route.h>
-static bool fib6_is_local(const struct sk_buff *skb)
-{
- const struct rt6_info *rt = (const void *)skb_dst(skb);
-
- return rt && (rt->rt6i_flags & RTF_LOCAL);
-}
-
static int get_ifindex(const struct net_device *dev)
{
return dev ? dev->ifindex : 0;
lookup_flags = nft_fib6_flowi_init(&fl6, priv, pkt, oif);
- if (nft_hook(pkt) == NF_INET_PRE_ROUTING && fib6_is_local(pkt->skb)) {
- nft_fib_store_result(dest, priv->result, pkt, LOOPBACK_IFINDEX);
+ if (nft_hook(pkt) == NF_INET_PRE_ROUTING &&
+ nft_fib_is_loopback(pkt->skb, nft_in(pkt))) {
+ nft_fib_store_result(dest, priv->result, pkt,
+ nft_in(pkt)->ifindex);
return;
}
struct fib6_node *fn;
/* Get the "current" route for this destination and
- * check if the redirect has come from approriate router.
+ * check if the redirect has come from appropriate router.
*
* RFC 4861 specifies that redirects should only be
* accepted if they come from the nexthop to the target.
old MTU is the lowest MTU in the path, update the route PMTU
to reflect the increase. In this case if the other nodes' MTU
also have the lowest MTU, TOO BIG MESSAGE will be lead to
- PMTU discouvery.
+ PMTU discovery.
*/
if (rt->dst.dev == arg->dev &&
dst_metric_raw(&rt->dst, RTAX_MTU) &&
if (tb[RTA_MULTIPATH]) {
cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]);
cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]);
+
+ err = lwtunnel_valid_encap_type_attr(cfg->fc_mp,
+ cfg->fc_mp_len);
+ if (err < 0)
+ goto errout;
}
if (tb[RTA_PREF]) {
if (tb[RTA_ENCAP])
cfg->fc_encap = tb[RTA_ENCAP];
- if (tb[RTA_ENCAP_TYPE])
+ if (tb[RTA_ENCAP_TYPE]) {
cfg->fc_encap_type = nla_get_u16(tb[RTA_ENCAP_TYPE]);
+ err = lwtunnel_valid_encap_type(cfg->fc_encap_type);
+ if (err < 0)
+ goto errout;
+ }
+
if (tb[RTA_EXPIRES]) {
unsigned long timeout = addrconf_timeout_fixup(nla_get_u32(tb[RTA_EXPIRES]), HZ);
if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt->rt6i_flags)))
goto nla_put_failure;
- lwtunnel_fill_encap(skb, rt->dst.lwtstate);
+ if (lwtunnel_fill_encap(skb, rt->dst.lwtstate) < 0)
+ goto nla_put_failure;
nlmsg_end(skb, nlh);
return 0;
val = nla_data(info->attrs[SEG6_ATTR_DST]);
t_new = kmemdup(val, sizeof(*val), GFP_KERNEL);
+ if (!t_new)
+ return -ENOMEM;
mutex_lock(&sdata->lock);
*p_tfm = tfm;
}
- p_tfm = this_cpu_ptr(algo->tfms);
+ p_tfm = raw_cpu_ptr(algo->tfms);
tfm = *p_tfm;
shsize = sizeof(*shash) + crypto_shash_descsize(tfm);
slwt = seg6_lwt_lwtunnel(orig_dst->lwtstate);
#ifdef CONFIG_DST_CACHE
+ preempt_disable();
dst = dst_cache_get(&slwt->cache);
+ preempt_enable();
#endif
if (unlikely(!dst)) {
}
#ifdef CONFIG_DST_CACHE
+ preempt_disable();
dst_cache_set_ip6(&slwt->cache, dst, &fl6.saddr);
+ preempt_enable();
#endif
}
.fill_encap = seg6_fill_encap_info,
.get_encap_size = seg6_encap_nlsize,
.cmp_encap = seg6_encap_cmp,
+ .owner = THIS_MODULE,
};
int __init seg6_iptunnel_init(void)
opt = ireq->ipv6_opt;
if (!opt)
opt = rcu_dereference(np->opt);
- err = ip6_xmit(sk, skb, fl6, opt, np->tclass);
+ err = ip6_xmit(sk, skb, fl6, sk->sk_mark, opt, np->tclass);
rcu_read_unlock();
err = net_xmit_eval(err);
}
dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL);
if (!IS_ERR(dst)) {
skb_dst_set(buff, dst);
- ip6_xmit(ctl_sk, buff, &fl6, NULL, tclass);
+ ip6_xmit(ctl_sk, buff, &fl6, fl6.flowi6_mark, NULL, tclass);
TCP_INC_STATS(net, TCP_MIB_OUTSEGS);
if (rst)
TCP_INC_STATS(net, TCP_MIB_OUTRSTS);
{
struct sock *sk = sock->sk;
struct iucv_sock *iucv = iucv_sk(sk);
- size_t headroom, linear;
+ size_t headroom = 0;
+ size_t linear;
struct sk_buff *skb;
struct iucv_message txmsg = {0};
struct cmsghdr *cmsg;
* this is fine for SOCK_SEQPACKET (unless we want to support
* segmented records using the MSG_EOR flag), but
* for SOCK_STREAM we might want to improve it in future */
- headroom = (iucv->transport == AF_IUCV_TRANS_HIPER)
- ? sizeof(struct af_iucv_trans_hdr) + ETH_HLEN : 0;
- if (headroom + len < PAGE_SIZE) {
+ if (iucv->transport == AF_IUCV_TRANS_HIPER) {
+ headroom = sizeof(struct af_iucv_trans_hdr) + ETH_HLEN;
linear = len;
} else {
- /* In nonlinear "classic" iucv skb,
- * reserve space for iucv_array
- */
- if (iucv->transport != AF_IUCV_TRANS_HIPER)
- headroom += sizeof(struct iucv_array) *
- (MAX_SKB_FRAGS + 1);
- linear = PAGE_SIZE - headroom;
+ if (len < PAGE_SIZE) {
+ linear = len;
+ } else {
+ /* In nonlinear "classic" iucv skb,
+ * reserve space for iucv_array
+ */
+ headroom = sizeof(struct iucv_array) *
+ (MAX_SKB_FRAGS + 1);
+ linear = PAGE_SIZE - headroom;
+ }
}
skb = sock_alloc_send_pskb(sk, headroom + linear, len - linear,
noblock, &err, 0);
!(sta->sdata->bss && sta->sdata->bss == sdata->bss))
continue;
- if (!sta->uploaded || !test_sta_flag(sta, WLAN_STA_ASSOC))
- continue;
-
max_bw = max(max_bw, ieee80211_get_sta_bw(&sta->sta));
}
rcu_read_unlock();
* Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
* Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH
+ * Copyright (c) 2016 Intel Deutschland GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
} else if (ieee80211_is_action(mgmt->frame_control) &&
mgmt->u.action.category == WLAN_CATEGORY_VHT) {
switch (mgmt->u.action.u.vht_group_notif.action_code) {
+ case WLAN_VHT_ACTION_OPMODE_NOTIF: {
+ struct ieee80211_rx_status *status;
+ enum nl80211_band band;
+ u8 opmode;
+
+ status = IEEE80211_SKB_RXCB(skb);
+ band = status->band;
+ opmode = mgmt->u.action.u.vht_opmode_notif.operating_mode;
+
+ mutex_lock(&local->sta_mtx);
+ sta = sta_info_get_bss(sdata, mgmt->sa);
+
+ if (sta)
+ ieee80211_vht_handle_opmode(sdata, sta,
+ opmode,
+ band);
+
+ mutex_unlock(&local->sta_mtx);
+ break;
+ }
case WLAN_VHT_ACTION_GROUPID_MGMT:
ieee80211_process_mu_groups(sdata, mgmt);
break;
supp_ht = supp_ht || sband->ht_cap.ht_supported;
supp_vht = supp_vht || sband->vht_cap.vht_supported;
- if (sband->ht_cap.ht_supported)
- local->rx_chains =
- max(ieee80211_mcs_to_chains(&sband->ht_cap.mcs),
- local->rx_chains);
+ if (!sband->ht_cap.ht_supported)
+ continue;
/* TODO: consider VHT for RX chains, hopefully it's the same */
+ local->rx_chains =
+ max(ieee80211_mcs_to_chains(&sband->ht_cap.mcs),
+ local->rx_chains);
+
+ /* no need to mask, SM_PS_DISABLED has all bits set */
+ sband->ht_cap.cap |= WLAN_HT_CAP_SM_PS_DISABLED <<
+ IEEE80211_HT_CAP_SM_PS_SHIFT;
}
/* if low-level driver supports AP, we also support VLAN */
if (!ifmsh->mshcfg.dot11MeshForwarding)
goto out;
- fwd_skb = skb_copy_expand(skb, local->tx_headroom, 0, GFP_ATOMIC);
+ fwd_skb = skb_copy_expand(skb, local->tx_headroom +
+ sdata->encrypt_headroom, 0, GFP_ATOMIC);
if (!fwd_skb) {
net_info_ratelimited("%s: failed to clone mesh frame\n",
sdata->name);
switch (mgmt->u.action.u.vht_opmode_notif.action_code) {
case WLAN_VHT_ACTION_OPMODE_NOTIF: {
- u8 opmode;
-
/* verify opmode is present */
if (len < IEEE80211_MIN_ACTION_SIZE + 2)
goto invalid;
-
- opmode = mgmt->u.action.u.vht_opmode_notif.operating_mode;
-
- ieee80211_vht_handle_opmode(rx->sdata, rx->sta,
- opmode, status->band);
- goto handled;
+ goto queue;
}
case WLAN_VHT_ACTION_GROUPID_MGMT: {
if (len < IEEE80211_MIN_ACTION_SIZE + 25)
u64_stats_update_end(&stats->syncp);
if (fast_rx->internal_forward) {
- struct sta_info *dsta = sta_info_get(rx->sdata, skb->data);
+ struct sk_buff *xmit_skb = NULL;
+ bool multicast = is_multicast_ether_addr(skb->data);
+
+ if (multicast) {
+ xmit_skb = skb_copy(skb, GFP_ATOMIC);
+ } else if (sta_info_get(rx->sdata, skb->data)) {
+ xmit_skb = skb;
+ skb = NULL;
+ }
- if (dsta) {
+ if (xmit_skb) {
/*
* Send to wireless media and increase priority by 256
* to keep the received priority instead of
* reclassifying the frame (see cfg80211_classify8021d).
*/
- skb->priority += 256;
- skb->protocol = htons(ETH_P_802_3);
- skb_reset_network_header(skb);
- skb_reset_mac_header(skb);
- dev_queue_xmit(skb);
- return true;
+ xmit_skb->priority += 256;
+ xmit_skb->protocol = htons(ETH_P_802_3);
+ skb_reset_network_header(xmit_skb);
+ skb_reset_mac_header(xmit_skb);
+ dev_queue_xmit(xmit_skb);
}
+
+ if (!skb)
+ return true;
}
/* deliver to local stack */
/* This will evaluate to 1, 3, 5 or 7. */
for (ac = IEEE80211_AC_VO; ac < IEEE80211_NUM_ACS; ac++)
- if (ignored_acs & BIT(ac))
- continue;
+ if (!(ignored_acs & ieee80211_ac_to_qos_mask[ac]))
+ break;
tid = 7 - 2 * ac;
ieee80211_send_null_response(sta, tid, reason, true, false);
static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local,
struct ieee80211_vif *vif,
- struct ieee80211_sta *pubsta,
+ struct sta_info *sta,
struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
if (!ieee80211_is_data(hdr->frame_control))
return NULL;
- if (pubsta) {
+ if (sta) {
u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
- txq = pubsta->txq[tid];
+ if (!sta->uploaded)
+ return NULL;
+
+ txq = sta->sta.txq[tid];
} else if (vif) {
txq = vif->txq;
}
struct fq *fq = &local->fq;
struct ieee80211_vif *vif;
struct txq_info *txqi;
- struct ieee80211_sta *pubsta;
if (!local->ops->wake_tx_queue ||
sdata->vif.type == NL80211_IFTYPE_MONITOR)
return false;
- if (sta && sta->uploaded)
- pubsta = &sta->sta;
- else
- pubsta = NULL;
-
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
sdata = container_of(sdata->bss,
struct ieee80211_sub_if_data, u.ap);
vif = &sdata->vif;
- txqi = ieee80211_get_txq(local, vif, pubsta, skb);
+ txqi = ieee80211_get_txq(local, vif, sta, skb);
if (!txqi)
return false;
u32 changed = __ieee80211_vht_handle_opmode(sdata, sta, opmode, band);
- if (changed > 0)
+ if (changed > 0) {
+ ieee80211_recalc_min_chandef(sdata);
rate_control_rate_update(local, sband, sta, changed);
+ }
}
void ieee80211_get_vht_mask_from_cap(__le16 vht_cap,
}
EXPORT_SYMBOL_GPL(mpls_pkt_too_big);
-static u32 mpls_multipath_hash(struct mpls_route *rt,
- struct sk_buff *skb, bool bos)
+static u32 mpls_multipath_hash(struct mpls_route *rt, struct sk_buff *skb)
{
struct mpls_entry_decoded dec;
+ unsigned int mpls_hdr_len = 0;
struct mpls_shim_hdr *hdr;
bool eli_seen = false;
int label_index;
u32 hash = 0;
- for (label_index = 0; label_index < MAX_MP_SELECT_LABELS && !bos;
+ for (label_index = 0; label_index < MAX_MP_SELECT_LABELS;
label_index++) {
- if (!pskb_may_pull(skb, sizeof(*hdr) * label_index))
+ mpls_hdr_len += sizeof(*hdr);
+ if (!pskb_may_pull(skb, mpls_hdr_len))
break;
/* Read and decode the current label */
eli_seen = true;
}
- bos = dec.bos;
- if (bos && pskb_may_pull(skb, sizeof(*hdr) * label_index +
- sizeof(struct iphdr))) {
+ if (!dec.bos)
+ continue;
+
+ /* found bottom label; does skb have room for a header? */
+ if (pskb_may_pull(skb, mpls_hdr_len + sizeof(struct iphdr))) {
const struct iphdr *v4hdr;
- v4hdr = (const struct iphdr *)(mpls_hdr(skb) +
- label_index);
+ v4hdr = (const struct iphdr *)(hdr + 1);
if (v4hdr->version == 4) {
hash = jhash_3words(ntohl(v4hdr->saddr),
ntohl(v4hdr->daddr),
v4hdr->protocol, hash);
} else if (v4hdr->version == 6 &&
- pskb_may_pull(skb, sizeof(*hdr) * label_index +
- sizeof(struct ipv6hdr))) {
+ pskb_may_pull(skb, mpls_hdr_len +
+ sizeof(struct ipv6hdr))) {
const struct ipv6hdr *v6hdr;
- v6hdr = (const struct ipv6hdr *)(mpls_hdr(skb) +
- label_index);
-
+ v6hdr = (const struct ipv6hdr *)(hdr + 1);
hash = __ipv6_addr_jhash(&v6hdr->saddr, hash);
hash = __ipv6_addr_jhash(&v6hdr->daddr, hash);
hash = jhash_1word(v6hdr->nexthdr, hash);
}
}
+
+ break;
}
return hash;
}
static struct mpls_nh *mpls_select_multipath(struct mpls_route *rt,
- struct sk_buff *skb, bool bos)
+ struct sk_buff *skb)
{
int alive = ACCESS_ONCE(rt->rt_nhn_alive);
u32 hash = 0;
if (alive <= 0)
return NULL;
- hash = mpls_multipath_hash(rt, skb, bos);
+ hash = mpls_multipath_hash(rt, skb);
nh_index = hash % alive;
if (alive == rt->rt_nhn)
goto out;
hdr = mpls_hdr(skb);
dec = mpls_entry_decode(hdr);
- /* Pop the label */
- skb_pull(skb, sizeof(*hdr));
- skb_reset_network_header(skb);
-
- skb_orphan(skb);
-
rt = mpls_route_input_rcu(net, dec.label);
if (!rt)
goto drop;
- nh = mpls_select_multipath(rt, skb, dec.bos);
+ nh = mpls_select_multipath(rt, skb);
if (!nh)
goto drop;
if (!mpls_output_possible(out_dev))
goto drop;
+ /* Pop the label */
+ skb_pull(skb, sizeof(*hdr));
+ skb_reset_network_header(skb);
+
+ skb_orphan(skb);
+
if (skb_warn_if_lro(skb))
goto drop;
.fill_encap = mpls_fill_encap_info,
.get_encap_size = mpls_encap_nlsize,
.cmp_encap = mpls_encap_cmp,
+ .owner = THIS_MODULE,
};
static int __init mpls_iptunnel_init(void)
depends on NF_CONNTRACK
tristate "Netfilter nf_tables conntrack module"
help
- This option adds the "meta" expression that you can use to match
+ This option adds the "ct" expression that you can use to match
connection tracking information such as the flow state.
config NFT_SET_RBTREE
static __read_mostly bool nf_conntrack_locks_all;
/* every gc cycle scans at most 1/GC_MAX_BUCKETS_DIV part of table */
-#define GC_MAX_BUCKETS_DIV 64u
-/* upper bound of scan intervals */
-#define GC_INTERVAL_MAX (2 * HZ)
-/* maximum conntracks to evict per gc run */
-#define GC_MAX_EVICTS 256u
+#define GC_MAX_BUCKETS_DIV 128u
+/* upper bound of full table scan */
+#define GC_MAX_SCAN_JIFFIES (16u * HZ)
+/* desired ratio of entries found to be expired */
+#define GC_EVICT_RATIO 50u
static struct conntrack_gc_work conntrack_gc_work;
static void gc_worker(struct work_struct *work)
{
+ unsigned int min_interval = max(HZ / GC_MAX_BUCKETS_DIV, 1u);
unsigned int i, goal, buckets = 0, expired_count = 0;
struct conntrack_gc_work *gc_work;
unsigned int ratio, scanned = 0;
*/
rcu_read_unlock();
cond_resched_rcu_qs();
- } while (++buckets < goal &&
- expired_count < GC_MAX_EVICTS);
+ } while (++buckets < goal);
if (gc_work->exiting)
return;
* 1. Minimize time until we notice a stale entry
* 2. Maximize scan intervals to not waste cycles
*
- * Normally, expired_count will be 0, this increases the next_run time
- * to priorize 2) above.
+ * Normally, expire ratio will be close to 0.
*
- * As soon as a timed-out entry is found, move towards 1) and increase
- * the scan frequency.
- * In case we have lots of evictions next scan is done immediately.
+ * As soon as a sizeable fraction of the entries have expired
+ * increase scan frequency.
*/
ratio = scanned ? expired_count * 100 / scanned : 0;
- if (ratio >= 90 || expired_count == GC_MAX_EVICTS) {
- gc_work->next_gc_run = 0;
- next_run = 0;
- } else if (expired_count) {
- gc_work->next_gc_run /= 2U;
- next_run = msecs_to_jiffies(1);
+ if (ratio > GC_EVICT_RATIO) {
+ gc_work->next_gc_run = min_interval;
} else {
- if (gc_work->next_gc_run < GC_INTERVAL_MAX)
- gc_work->next_gc_run += msecs_to_jiffies(1);
+ unsigned int max = GC_MAX_SCAN_JIFFIES / GC_MAX_BUCKETS_DIV;
- next_run = gc_work->next_gc_run;
+ BUILD_BUG_ON((GC_MAX_SCAN_JIFFIES / GC_MAX_BUCKETS_DIV) == 0);
+
+ gc_work->next_gc_run += min_interval;
+ if (gc_work->next_gc_run > max)
+ gc_work->next_gc_run = max;
}
+ next_run = gc_work->next_gc_run;
gc_work->last_bucket = i;
queue_delayed_work(system_long_wq, &gc_work->dwork, next_run);
}
static void conntrack_gc_work_init(struct conntrack_gc_work *gc_work)
{
INIT_DELAYED_WORK(&gc_work->dwork, gc_worker);
- gc_work->next_gc_run = GC_INTERVAL_MAX;
+ gc_work->next_gc_run = HZ;
gc_work->exiting = false;
}
nf_ct_untracked_status_or(IPS_CONFIRMED | IPS_UNTRACKED);
conntrack_gc_work_init(&conntrack_gc_work);
- queue_delayed_work(system_long_wq, &conntrack_gc_work.dwork, GC_INTERVAL_MAX);
+ queue_delayed_work(system_long_wq, &conntrack_gc_work.dwork, HZ);
return 0;
/* Internal logging interface, which relies on the real
LOG target modules */
-#define NF_LOG_PREFIXLEN 128
#define NFLOGGER_NAME_LEN 64
static struct nf_logger __rcu *loggers[NFPROTO_NUMPROTO][NF_LOG_TYPE_MAX] __read_mostly;
}
static const struct nla_policy nft_chain_policy[NFTA_CHAIN_MAX + 1] = {
- [NFTA_CHAIN_TABLE] = { .type = NLA_STRING },
+ [NFTA_CHAIN_TABLE] = { .type = NLA_STRING,
+ .len = NFT_TABLE_MAXNAMELEN - 1 },
[NFTA_CHAIN_HANDLE] = { .type = NLA_U64 },
[NFTA_CHAIN_NAME] = { .type = NLA_STRING,
.len = NFT_CHAIN_MAXNAMELEN - 1 },
}
static const struct nla_policy nft_rule_policy[NFTA_RULE_MAX + 1] = {
- [NFTA_RULE_TABLE] = { .type = NLA_STRING },
+ [NFTA_RULE_TABLE] = { .type = NLA_STRING,
+ .len = NFT_TABLE_MAXNAMELEN - 1 },
[NFTA_RULE_CHAIN] = { .type = NLA_STRING,
.len = NFT_CHAIN_MAXNAMELEN - 1 },
[NFTA_RULE_HANDLE] = { .type = NLA_U64 },
* is called on error from nf_tables_newrule().
*/
expr = nft_expr_first(rule);
- while (expr->ops && expr != nft_expr_last(rule)) {
+ while (expr != nft_expr_last(rule) && expr->ops) {
nf_tables_expr_destroy(ctx, expr);
expr = nft_expr_next(expr);
}
}
static const struct nla_policy nft_set_policy[NFTA_SET_MAX + 1] = {
- [NFTA_SET_TABLE] = { .type = NLA_STRING },
+ [NFTA_SET_TABLE] = { .type = NLA_STRING,
+ .len = NFT_TABLE_MAXNAMELEN - 1 },
[NFTA_SET_NAME] = { .type = NLA_STRING,
.len = NFT_SET_MAXNAMELEN - 1 },
[NFTA_SET_FLAGS] = { .type = NLA_U32 },
}
static int nf_tables_bind_check_setelem(const struct nft_ctx *ctx,
- const struct nft_set *set,
+ struct nft_set *set,
const struct nft_set_iter *iter,
- const struct nft_set_elem *elem)
+ struct nft_set_elem *elem)
{
const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
enum nft_registers dreg;
};
static const struct nla_policy nft_set_elem_list_policy[NFTA_SET_ELEM_LIST_MAX + 1] = {
- [NFTA_SET_ELEM_LIST_TABLE] = { .type = NLA_STRING },
- [NFTA_SET_ELEM_LIST_SET] = { .type = NLA_STRING },
+ [NFTA_SET_ELEM_LIST_TABLE] = { .type = NLA_STRING,
+ .len = NFT_TABLE_MAXNAMELEN - 1 },
+ [NFTA_SET_ELEM_LIST_SET] = { .type = NLA_STRING,
+ .len = NFT_SET_MAXNAMELEN - 1 },
[NFTA_SET_ELEM_LIST_ELEMENTS] = { .type = NLA_NESTED },
[NFTA_SET_ELEM_LIST_SET_ID] = { .type = NLA_U32 },
};
};
static int nf_tables_dump_setelem(const struct nft_ctx *ctx,
- const struct nft_set *set,
+ struct nft_set *set,
const struct nft_set_iter *iter,
- const struct nft_set_elem *elem)
+ struct nft_set_elem *elem)
{
struct nft_set_dump_args *args;
{
struct net *net = sock_net(skb->sk);
u8 genmask = nft_genmask_cur(net);
- const struct nft_set *set;
+ struct nft_set *set;
struct nft_set_dump_args args;
struct nft_ctx ctx;
struct nlattr *nla[NFTA_SET_ELEM_LIST_MAX + 1];
goto err5;
}
+ if (set->size &&
+ !atomic_add_unless(&set->nelems, 1, set->size + set->ndeact)) {
+ err = -ENFILE;
+ goto err6;
+ }
+
nft_trans_elem(trans) = elem;
list_add_tail(&trans->list, &ctx->net->nft.commit_list);
return 0;
+err6:
+ set->ops->remove(set, &elem);
err5:
kfree(trans);
err4:
return -EBUSY;
nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
- if (set->size &&
- !atomic_add_unless(&set->nelems, 1, set->size + set->ndeact))
- return -ENFILE;
-
err = nft_add_set_elem(&ctx, set, attr, nlh->nlmsg_flags);
- if (err < 0) {
- atomic_dec(&set->nelems);
+ if (err < 0)
break;
- }
}
return err;
}
}
static int nft_flush_set(const struct nft_ctx *ctx,
- const struct nft_set *set,
+ struct nft_set *set,
const struct nft_set_iter *iter,
- const struct nft_set_elem *elem)
+ struct nft_set_elem *elem)
{
struct nft_trans *trans;
int err;
err = -ENOENT;
goto err1;
}
+ set->ndeact++;
- nft_trans_elem_set(trans) = (struct nft_set *)set;
- nft_trans_elem(trans) = *((struct nft_set_elem *)elem);
+ nft_trans_elem_set(trans) = set;
+ nft_trans_elem(trans) = *elem;
list_add_tail(&trans->list, &ctx->net->nft.commit_list);
return 0;
EXPORT_SYMBOL_GPL(nf_tables_obj_lookup);
static const struct nla_policy nft_obj_policy[NFTA_OBJ_MAX + 1] = {
- [NFTA_OBJ_TABLE] = { .type = NLA_STRING },
- [NFTA_OBJ_NAME] = { .type = NLA_STRING },
+ [NFTA_OBJ_TABLE] = { .type = NLA_STRING,
+ .len = NFT_TABLE_MAXNAMELEN - 1 },
+ [NFTA_OBJ_NAME] = { .type = NLA_STRING,
+ .len = NFT_OBJ_MAXNAMELEN - 1 },
[NFTA_OBJ_TYPE] = { .type = NLA_U32 },
[NFTA_OBJ_DATA] = { .type = NLA_NESTED },
};
if (idx > s_idx)
memset(&cb->args[1], 0,
sizeof(cb->args) - sizeof(cb->args[0]));
- if (filter->table[0] &&
+ if (filter && filter->table[0] &&
strcmp(filter->table, table->name))
goto cont;
- if (filter->type != NFT_OBJECT_UNSPEC &&
+ if (filter &&
+ filter->type != NFT_OBJECT_UNSPEC &&
obj->type->type != filter->type)
goto cont;
const struct nft_chain *chain);
static int nf_tables_loop_check_setelem(const struct nft_ctx *ctx,
- const struct nft_set *set,
+ struct nft_set *set,
const struct nft_set_iter *iter,
- const struct nft_set_elem *elem)
+ struct nft_set_elem *elem)
{
const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
const struct nft_data *data;
{
const struct nft_rule *rule;
const struct nft_expr *expr, *last;
- const struct nft_set *set;
+ struct nft_set *set;
struct nft_set_binding *binding;
struct nft_set_iter iter;
}
static const struct nla_policy nft_dynset_policy[NFTA_DYNSET_MAX + 1] = {
- [NFTA_DYNSET_SET_NAME] = { .type = NLA_STRING },
+ [NFTA_DYNSET_SET_NAME] = { .type = NLA_STRING,
+ .len = NFT_SET_MAXNAMELEN - 1 },
[NFTA_DYNSET_SET_ID] = { .type = NLA_U32 },
[NFTA_DYNSET_OP] = { .type = NLA_U32 },
[NFTA_DYNSET_SREG_KEY] = { .type = NLA_U32 },
static const struct nla_policy nft_log_policy[NFTA_LOG_MAX + 1] = {
[NFTA_LOG_GROUP] = { .type = NLA_U16 },
- [NFTA_LOG_PREFIX] = { .type = NLA_STRING },
+ [NFTA_LOG_PREFIX] = { .type = NLA_STRING,
+ .len = NF_LOG_PREFIXLEN - 1 },
[NFTA_LOG_SNAPLEN] = { .type = NLA_U32 },
[NFTA_LOG_QTHRESHOLD] = { .type = NLA_U16 },
[NFTA_LOG_LEVEL] = { .type = NLA_U32 },
}
static const struct nla_policy nft_lookup_policy[NFTA_LOOKUP_MAX + 1] = {
- [NFTA_LOOKUP_SET] = { .type = NLA_STRING },
+ [NFTA_LOOKUP_SET] = { .type = NLA_STRING,
+ .len = NFT_SET_MAXNAMELEN - 1 },
[NFTA_LOOKUP_SET_ID] = { .type = NLA_U32 },
[NFTA_LOOKUP_SREG] = { .type = NLA_U32 },
[NFTA_LOOKUP_DREG] = { .type = NLA_U32 },
}
static const struct nla_policy nft_objref_policy[NFTA_OBJREF_MAX + 1] = {
- [NFTA_OBJREF_IMM_NAME] = { .type = NLA_STRING },
+ [NFTA_OBJREF_IMM_NAME] = { .type = NLA_STRING,
+ .len = NFT_OBJ_MAXNAMELEN - 1 },
[NFTA_OBJREF_IMM_TYPE] = { .type = NLA_U32 },
[NFTA_OBJREF_SET_SREG] = { .type = NLA_U32 },
- [NFTA_OBJREF_SET_NAME] = { .type = NLA_STRING },
+ [NFTA_OBJREF_SET_NAME] = { .type = NLA_STRING,
+ .len = NFT_SET_MAXNAMELEN - 1 },
[NFTA_OBJREF_SET_ID] = { .type = NLA_U32 },
};
return 0;
}
+static int nft_payload_csum_inet(struct sk_buff *skb, const u32 *src,
+ __wsum fsum, __wsum tsum, int csum_offset)
+{
+ __sum16 sum;
+
+ if (skb_copy_bits(skb, csum_offset, &sum, sizeof(sum)) < 0)
+ return -1;
+
+ nft_csum_replace(&sum, fsum, tsum);
+ if (!skb_make_writable(skb, csum_offset + sizeof(sum)) ||
+ skb_store_bits(skb, csum_offset, &sum, sizeof(sum)) < 0)
+ return -1;
+
+ return 0;
+}
+
static void nft_payload_set_eval(const struct nft_expr *expr,
struct nft_regs *regs,
const struct nft_pktinfo *pkt)
const u32 *src = ®s->data[priv->sreg];
int offset, csum_offset;
__wsum fsum, tsum;
- __sum16 sum;
switch (priv->base) {
case NFT_PAYLOAD_LL_HEADER:
csum_offset = offset + priv->csum_offset;
offset += priv->offset;
- if (priv->csum_type == NFT_PAYLOAD_CSUM_INET &&
+ if ((priv->csum_type == NFT_PAYLOAD_CSUM_INET || priv->csum_flags) &&
(priv->base != NFT_PAYLOAD_TRANSPORT_HEADER ||
skb->ip_summed != CHECKSUM_PARTIAL)) {
- if (skb_copy_bits(skb, csum_offset, &sum, sizeof(sum)) < 0)
- goto err;
-
fsum = skb_checksum(skb, offset, priv->len, 0);
tsum = csum_partial(src, priv->len, 0);
- nft_csum_replace(&sum, fsum, tsum);
- if (!skb_make_writable(skb, csum_offset + sizeof(sum)) ||
- skb_store_bits(skb, csum_offset, &sum, sizeof(sum)) < 0)
+ if (priv->csum_type == NFT_PAYLOAD_CSUM_INET &&
+ nft_payload_csum_inet(skb, src, fsum, tsum, csum_offset))
goto err;
if (priv->csum_flags &&
if (priv->queues_total > 1) {
if (priv->flags & NFT_QUEUE_FLAG_CPU_FANOUT) {
- int cpu = smp_processor_id();
+ int cpu = raw_smp_processor_id();
queue = priv->queuenum + cpu % priv->queues_total;
} else {
static int nft_quota_do_dump(struct sk_buff *skb, struct nft_quota *priv,
bool reset)
{
+ u64 consumed, consumed_cap;
u32 flags = priv->flags;
- u64 consumed;
-
- if (reset) {
- consumed = atomic64_xchg(&priv->consumed, 0);
- if (test_and_clear_bit(NFT_QUOTA_DEPLETED_BIT, &priv->flags))
- flags |= NFT_QUOTA_F_DEPLETED;
- } else {
- consumed = atomic64_read(&priv->consumed);
- }
/* Since we inconditionally increment consumed quota for each packet
* that we see, don't go over the quota boundary in what we send to
* userspace.
*/
- if (consumed > priv->quota)
- consumed = priv->quota;
+ consumed = atomic64_read(&priv->consumed);
+ if (consumed >= priv->quota) {
+ consumed_cap = priv->quota;
+ flags |= NFT_QUOTA_F_DEPLETED;
+ } else {
+ consumed_cap = consumed;
+ }
if (nla_put_be64(skb, NFTA_QUOTA_BYTES, cpu_to_be64(priv->quota),
NFTA_QUOTA_PAD) ||
- nla_put_be64(skb, NFTA_QUOTA_CONSUMED, cpu_to_be64(consumed),
+ nla_put_be64(skb, NFTA_QUOTA_CONSUMED, cpu_to_be64(consumed_cap),
NFTA_QUOTA_PAD) ||
nla_put_be32(skb, NFTA_QUOTA_FLAGS, htonl(flags)))
goto nla_put_failure;
+
+ if (reset) {
+ atomic64_sub(consumed, &priv->consumed);
+ clear_bit(NFT_QUOTA_DEPLETED_BIT, &priv->flags);
+ }
return 0;
nla_put_failure:
rhashtable_remove_fast(&priv->ht, &he->node, nft_hash_params);
}
-static void nft_hash_walk(const struct nft_ctx *ctx, const struct nft_set *set,
+static void nft_hash_walk(const struct nft_ctx *ctx, struct nft_set *set,
struct nft_set_iter *iter)
{
struct nft_hash *priv = nft_set_priv(set);
}
static void nft_rbtree_walk(const struct nft_ctx *ctx,
- const struct nft_set *set,
+ struct nft_set *set,
struct nft_set_iter *iter)
{
const struct nft_rbtree *priv = nft_set_priv(set);
printk(KERN_INFO "NetLabel: Initializing\n");
printk(KERN_INFO "NetLabel: domain hash size = %u\n",
(1 << NETLBL_DOMHSH_BITSIZE));
- printk(KERN_INFO "NetLabel: protocols ="
- " UNLABELED"
- " CIPSOv4"
- "\n");
+ printk(KERN_INFO "NetLabel: protocols = UNLABELED CIPSOv4 CALIPSO\n");
ret_val = netlbl_domhsh_init(NETLBL_DOMHSH_BITSIZE);
if (ret_val != 0)
int hooknum, nh_off, err = NF_ACCEPT;
nh_off = skb_network_offset(skb);
- skb_pull(skb, nh_off);
+ skb_pull_rcsum(skb, nh_off);
/* See HOOK2MANIP(). */
if (maniptype == NF_NAT_MANIP_SRC)
err = nf_nat_packet(ct, ctinfo, hooknum, skb);
push:
skb_push(skb, nh_off);
+ skb_postpush_rcsum(skb, skb->data, nh_off);
return err;
}
/* The conntrack module expects to be working at L3. */
nh_ofs = skb_network_offset(skb);
- skb_pull(skb, nh_ofs);
+ skb_pull_rcsum(skb, nh_ofs);
if (key->ip.frag != OVS_FRAG_TYPE_NONE) {
err = handle_fragments(net, key, info->zone.id, skb);
err = ovs_ct_lookup(net, key, info, skb);
skb_push(skb, nh_ofs);
+ skb_postpush_rcsum(skb, skb->data, nh_ofs);
if (err)
kfree_skb(skb);
return err;
return -EINVAL;
*len -= sizeof(vnet_hdr);
- if (virtio_net_hdr_from_skb(skb, &vnet_hdr, vio_le()))
+ if (virtio_net_hdr_from_skb(skb, &vnet_hdr, vio_le(), true))
return -EINVAL;
return memcpy_to_msg(msg, (void *)&vnet_hdr, sizeof(vnet_hdr));
if (po->has_vnet_hdr) {
if (virtio_net_hdr_from_skb(skb, h.raw + macoff -
sizeof(struct virtio_net_hdr),
- vio_le())) {
+ vio_le(), true)) {
spin_lock(&sk->sk_receive_queue.lock);
goto drop_n_account;
}
const int pkt_len = 20;
struct qrtr_hdr *hdr;
struct sk_buff *skb;
- u32 *buf;
+ __le32 *buf;
skb = alloc_skb(QRTR_HDR_SIZE + pkt_len, GFP_KERNEL);
if (!skb)
hdr->dst_node_id = cpu_to_le32(dst_node);
hdr->dst_port_id = cpu_to_le32(QRTR_PORT_CTRL);
- buf = (u32 *)skb_put(skb, pkt_len);
+ buf = (__le32 *)skb_put(skb, pkt_len);
memset(buf, 0, pkt_len);
buf[0] = cpu_to_le32(QRTR_TYPE_RESUME_TX);
buf[1] = cpu_to_le32(src_node);
goto err;
}
act->order = i;
- if (event == RTM_GETACTION)
- act->tcfa_refcnt++;
list_add_tail(&act->list, &actions);
}
return ret;
}
err:
- tcf_action_destroy(&actions, 0);
+ if (event != RTM_GETACTION)
+ tcf_action_destroy(&actions, 0);
return ret;
}
nla_put_string(skb, TCA_ACT_BPF_NAME, prog->bpf_name))
return -EMSGSIZE;
- nla = nla_reserve(skb, TCA_ACT_BPF_DIGEST,
- sizeof(prog->filter->digest));
+ nla = nla_reserve(skb, TCA_ACT_BPF_TAG, sizeof(prog->filter->tag));
if (nla == NULL)
return -EMSGSIZE;
- memcpy(nla_data(nla), prog->filter->digest, nla_len(nla));
+ memcpy(nla_data(nla), prog->filter->tag, nla_len(nla));
return 0;
}
nla_put_string(skb, TCA_BPF_NAME, prog->bpf_name))
return -EMSGSIZE;
- nla = nla_reserve(skb, TCA_BPF_DIGEST, sizeof(prog->filter->digest));
+ nla = nla_reserve(skb, TCA_BPF_TAG, sizeof(prog->filter->tag));
if (nla == NULL)
return -EMSGSIZE;
- memcpy(nla_data(nla), prog->filter->digest, nla_len(nla));
+ memcpy(nla_data(nla), prog->filter->tag, nla_len(nla));
return 0;
}
&mask->icmp.type,
TCA_FLOWER_KEY_ICMPV6_TYPE_MASK,
sizeof(key->icmp.type));
- fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV4_CODE,
+ fl_set_key_val(tb, &key->icmp.code, TCA_FLOWER_KEY_ICMPV6_CODE,
&mask->icmp.code,
- TCA_FLOWER_KEY_ICMPV4_CODE_MASK,
+ TCA_FLOWER_KEY_ICMPV6_CODE_MASK,
sizeof(key->icmp.code));
}
#include <net/sch_generic.h>
#include <net/pkt_cls.h>
-struct cls_mall_filter {
+struct cls_mall_head {
struct tcf_exts exts;
struct tcf_result res;
u32 handle;
- struct rcu_head rcu;
u32 flags;
-};
-
-struct cls_mall_head {
- struct cls_mall_filter *filter;
struct rcu_head rcu;
};
struct tcf_result *res)
{
struct cls_mall_head *head = rcu_dereference_bh(tp->root);
- struct cls_mall_filter *f = head->filter;
- if (tc_skip_sw(f->flags))
+ if (tc_skip_sw(head->flags))
return -1;
- return tcf_exts_exec(skb, &f->exts, res);
+ return tcf_exts_exec(skb, &head->exts, res);
}
static int mall_init(struct tcf_proto *tp)
{
- struct cls_mall_head *head;
-
- head = kzalloc(sizeof(*head), GFP_KERNEL);
- if (!head)
- return -ENOBUFS;
-
- rcu_assign_pointer(tp->root, head);
-
return 0;
}
-static void mall_destroy_filter(struct rcu_head *head)
+static void mall_destroy_rcu(struct rcu_head *rcu)
{
- struct cls_mall_filter *f = container_of(head, struct cls_mall_filter, rcu);
+ struct cls_mall_head *head = container_of(rcu, struct cls_mall_head,
+ rcu);
- tcf_exts_destroy(&f->exts);
-
- kfree(f);
+ tcf_exts_destroy(&head->exts);
+ kfree(head);
}
static int mall_replace_hw_filter(struct tcf_proto *tp,
- struct cls_mall_filter *f,
+ struct cls_mall_head *head,
unsigned long cookie)
{
struct net_device *dev = tp->q->dev_queue->dev;
offload.type = TC_SETUP_MATCHALL;
offload.cls_mall = &mall_offload;
offload.cls_mall->command = TC_CLSMATCHALL_REPLACE;
- offload.cls_mall->exts = &f->exts;
+ offload.cls_mall->exts = &head->exts;
offload.cls_mall->cookie = cookie;
return dev->netdev_ops->ndo_setup_tc(dev, tp->q->handle, tp->protocol,
}
static void mall_destroy_hw_filter(struct tcf_proto *tp,
- struct cls_mall_filter *f,
+ struct cls_mall_head *head,
unsigned long cookie)
{
struct net_device *dev = tp->q->dev_queue->dev;
{
struct cls_mall_head *head = rtnl_dereference(tp->root);
struct net_device *dev = tp->q->dev_queue->dev;
- struct cls_mall_filter *f = head->filter;
- if (!force && f)
- return false;
+ if (!head)
+ return true;
- if (f) {
- if (tc_should_offload(dev, tp, f->flags))
- mall_destroy_hw_filter(tp, f, (unsigned long) f);
+ if (tc_should_offload(dev, tp, head->flags))
+ mall_destroy_hw_filter(tp, head, (unsigned long) head);
- call_rcu(&f->rcu, mall_destroy_filter);
- }
- kfree_rcu(head, rcu);
+ call_rcu(&head->rcu, mall_destroy_rcu);
return true;
}
static unsigned long mall_get(struct tcf_proto *tp, u32 handle)
{
- struct cls_mall_head *head = rtnl_dereference(tp->root);
- struct cls_mall_filter *f = head->filter;
-
- if (f && f->handle == handle)
- return (unsigned long) f;
- return 0;
+ return 0UL;
}
static const struct nla_policy mall_policy[TCA_MATCHALL_MAX + 1] = {
};
static int mall_set_parms(struct net *net, struct tcf_proto *tp,
- struct cls_mall_filter *f,
+ struct cls_mall_head *head,
unsigned long base, struct nlattr **tb,
struct nlattr *est, bool ovr)
{
return err;
if (tb[TCA_MATCHALL_CLASSID]) {
- f->res.classid = nla_get_u32(tb[TCA_MATCHALL_CLASSID]);
- tcf_bind_filter(tp, &f->res, base);
+ head->res.classid = nla_get_u32(tb[TCA_MATCHALL_CLASSID]);
+ tcf_bind_filter(tp, &head->res, base);
}
- tcf_exts_change(tp, &f->exts, &e);
+ tcf_exts_change(tp, &head->exts, &e);
return 0;
}
unsigned long *arg, bool ovr)
{
struct cls_mall_head *head = rtnl_dereference(tp->root);
- struct cls_mall_filter *fold = (struct cls_mall_filter *) *arg;
struct net_device *dev = tp->q->dev_queue->dev;
- struct cls_mall_filter *f;
struct nlattr *tb[TCA_MATCHALL_MAX + 1];
+ struct cls_mall_head *new;
u32 flags = 0;
int err;
if (!tca[TCA_OPTIONS])
return -EINVAL;
- if (head->filter)
- return -EBUSY;
-
- if (fold)
- return -EINVAL;
+ if (head)
+ return -EEXIST;
err = nla_parse_nested(tb, TCA_MATCHALL_MAX,
tca[TCA_OPTIONS], mall_policy);
return -EINVAL;
}
- f = kzalloc(sizeof(*f), GFP_KERNEL);
- if (!f)
+ new = kzalloc(sizeof(*new), GFP_KERNEL);
+ if (!new)
return -ENOBUFS;
- tcf_exts_init(&f->exts, TCA_MATCHALL_ACT, 0);
+ tcf_exts_init(&new->exts, TCA_MATCHALL_ACT, 0);
if (!handle)
handle = 1;
- f->handle = handle;
- f->flags = flags;
+ new->handle = handle;
+ new->flags = flags;
- err = mall_set_parms(net, tp, f, base, tb, tca[TCA_RATE], ovr);
+ err = mall_set_parms(net, tp, new, base, tb, tca[TCA_RATE], ovr);
if (err)
goto errout;
if (tc_should_offload(dev, tp, flags)) {
- err = mall_replace_hw_filter(tp, f, (unsigned long) f);
+ err = mall_replace_hw_filter(tp, new, (unsigned long) new);
if (err) {
if (tc_skip_sw(flags))
goto errout;
}
}
- *arg = (unsigned long) f;
- rcu_assign_pointer(head->filter, f);
-
+ *arg = (unsigned long) head;
+ rcu_assign_pointer(tp->root, new);
+ if (head)
+ call_rcu(&head->rcu, mall_destroy_rcu);
return 0;
errout:
- kfree(f);
+ kfree(new);
return err;
}
static int mall_delete(struct tcf_proto *tp, unsigned long arg)
{
- struct cls_mall_head *head = rtnl_dereference(tp->root);
- struct cls_mall_filter *f = (struct cls_mall_filter *) arg;
- struct net_device *dev = tp->q->dev_queue->dev;
-
- if (tc_should_offload(dev, tp, f->flags))
- mall_destroy_hw_filter(tp, f, (unsigned long) f);
-
- RCU_INIT_POINTER(head->filter, NULL);
- tcf_unbind_filter(tp, &f->res);
- call_rcu(&f->rcu, mall_destroy_filter);
- return 0;
+ return -EOPNOTSUPP;
}
static void mall_walk(struct tcf_proto *tp, struct tcf_walker *arg)
{
struct cls_mall_head *head = rtnl_dereference(tp->root);
- struct cls_mall_filter *f = head->filter;
if (arg->count < arg->skip)
goto skip;
- if (arg->fn(tp, (unsigned long) f, arg) < 0)
+ if (arg->fn(tp, (unsigned long) head, arg) < 0)
arg->stop = 1;
skip:
arg->count++;
static int mall_dump(struct net *net, struct tcf_proto *tp, unsigned long fh,
struct sk_buff *skb, struct tcmsg *t)
{
- struct cls_mall_filter *f = (struct cls_mall_filter *) fh;
+ struct cls_mall_head *head = (struct cls_mall_head *) fh;
struct nlattr *nest;
- if (!f)
+ if (!head)
return skb->len;
- t->tcm_handle = f->handle;
+ t->tcm_handle = head->handle;
nest = nla_nest_start(skb, TCA_OPTIONS);
if (!nest)
goto nla_put_failure;
- if (f->res.classid &&
- nla_put_u32(skb, TCA_MATCHALL_CLASSID, f->res.classid))
+ if (head->res.classid &&
+ nla_put_u32(skb, TCA_MATCHALL_CLASSID, head->res.classid))
goto nla_put_failure;
- if (tcf_exts_dump(skb, &f->exts))
+ if (tcf_exts_dump(skb, &head->exts))
goto nla_put_failure;
nla_nest_end(skb, nest);
- if (tcf_exts_dump_stats(skb, &f->exts) < 0)
+ if (tcf_exts_dump_stats(skb, &head->exts) < 0)
goto nla_put_failure;
return skb->len;
SCTP_INC_STATS(sock_net(sk), SCTP_MIB_OUTSCTPPACKS);
rcu_read_lock();
- res = ip6_xmit(sk, skb, fl6, rcu_dereference(np->opt), np->tclass);
+ res = ip6_xmit(sk, skb, fl6, sk->sk_mark, rcu_dereference(np->opt),
+ np->tclass);
rcu_read_unlock();
return res;
}
goto out;
}
- segs = skb_segment(skb, features | NETIF_F_HW_CSUM);
+ segs = skb_segment(skb, features | NETIF_F_HW_CSUM | NETIF_F_SG);
if (IS_ERR(segs))
goto out;
(new_transport->state == SCTP_PF)))
new_transport = asoc->peer.active_path;
if (new_transport->state == SCTP_UNCONFIRMED) {
- WARN_ONCE(1, "Atempt to send packet on unconfirmed path.");
+ WARN_ONCE(1, "Attempt to send packet on unconfirmed path.");
sctp_chunk_fail(chunk, 0);
sctp_chunk_free(chunk);
continue;
sctp_assoc_t id)
{
struct sctp_association *addr_asoc = NULL, *id_asoc = NULL;
- struct sctp_transport *transport;
+ struct sctp_af *af = sctp_get_af_specific(addr->ss_family);
union sctp_addr *laddr = (union sctp_addr *)addr;
+ struct sctp_transport *transport;
+
+ if (sctp_verify_addr(sk, laddr, af->sockaddr_len))
+ return NULL;
addr_asoc = sctp_endpoint_lookup_assoc(sctp_sk(sk)->ep,
laddr,
return used;
}
-int sockfs_setattr(struct dentry *dentry, struct iattr *iattr)
+static int sockfs_setattr(struct dentry *dentry, struct iattr *iattr)
{
int err = simple_setattr(dentry, iattr);
if (!oa->data)
return -ENOMEM;
- creds = kmalloc(sizeof(struct svc_cred), GFP_KERNEL);
+ creds = kzalloc(sizeof(struct svc_cred), GFP_KERNEL);
if (!creds) {
kfree(oa->data);
return -ENOMEM;
case RPC_GSS_PROC_DESTROY:
if (gss_write_verf(rqstp, rsci->mechctx, gc->gc_seq))
goto auth_err;
- rsci->h.expiry_time = get_seconds();
+ rsci->h.expiry_time = seconds_since_boot();
set_bit(CACHE_NEGATIVE, &rsci->h.flags);
if (resv->iov_len + 4 > PAGE_SIZE)
goto drop;
static DEFINE_IDA(rpc_clids);
+void rpc_cleanup_clids(void)
+{
+ ida_destroy(&rpc_clids);
+}
+
static int rpc_alloc_clid(struct rpc_clnt *clnt)
{
int clid;
static void __exit
cleanup_sunrpc(void)
{
+ rpc_cleanup_clids();
rpcauth_remove_module();
cleanup_socket_xprt();
svc_cleanup_xprt_sock();
if (test_bit(XPT_CLOSE, &xprt->xpt_flags)) {
dprintk("svc_recv: found XPT_CLOSE\n");
+ if (test_and_clear_bit(XPT_KILL_TEMP, &xprt->xpt_flags))
+ xprt->xpt_ops->xpo_kill_temp_xprt(xprt);
svc_delete_xprt(xprt);
/* Leave XPT_BUSY set on the dead xprt: */
goto out;
le = to_be_closed.next;
list_del_init(le);
xprt = list_entry(le, struct svc_xprt, xpt_list);
- dprintk("svc_age_temp_xprts_now: closing %p\n", xprt);
- xprt->xpt_ops->xpo_kill_temp_xprt(xprt);
- svc_close_xprt(xprt);
+ set_bit(XPT_CLOSE, &xprt->xpt_flags);
+ set_bit(XPT_KILL_TEMP, &xprt->xpt_flags);
+ dprintk("svc_age_temp_xprts_now: queuing xprt %p for closing\n",
+ xprt);
+ svc_xprt_enqueue(xprt);
}
}
EXPORT_SYMBOL_GPL(svc_age_temp_xprts_now);
atomic_inc(&rdma_stat_read);
return ret;
err:
- ib_dma_unmap_sg(xprt->sc_cm_id->device,
- frmr->sg, frmr->sg_nents, frmr->direction);
svc_rdma_put_context(ctxt, 0);
svc_rdma_put_frmr(xprt, frmr);
return ret;
/* Send response, if necessary */
if (respond && (mtyp == DSC_REQ_MSG)) {
- rskb = tipc_buf_acquire(MAX_H_SIZE);
+ rskb = tipc_buf_acquire(MAX_H_SIZE, GFP_ATOMIC);
if (!rskb)
return;
tipc_disc_init_msg(net, rskb, DSC_RESP_MSG, bearer);
req = kmalloc(sizeof(*req), GFP_ATOMIC);
if (!req)
return -ENOMEM;
- req->buf = tipc_buf_acquire(MAX_H_SIZE);
+ req->buf = tipc_buf_acquire(MAX_H_SIZE, GFP_ATOMIC);
if (!req->buf) {
kfree(req);
return -ENOMEM;
msg_set_seqno(hdr, seqno++);
pktlen = msg_size(hdr);
msg_set_size(&tnlhdr, pktlen + INT_H_SIZE);
- tnlskb = tipc_buf_acquire(pktlen + INT_H_SIZE);
+ tnlskb = tipc_buf_acquire(pktlen + INT_H_SIZE, GFP_ATOMIC);
if (!tnlskb) {
pr_warn("%sunable to send packet\n", link_co_err);
return;
* NOTE: Headroom is reserved to allow prepending of a data link header.
* There may also be unrequested tailroom present at the buffer's end.
*/
-struct sk_buff *tipc_buf_acquire(u32 size)
+struct sk_buff *tipc_buf_acquire(u32 size, gfp_t gfp)
{
struct sk_buff *skb;
unsigned int buf_size = (BUF_HEADROOM + size + 3) & ~3u;
- skb = alloc_skb_fclone(buf_size, GFP_ATOMIC);
+ skb = alloc_skb_fclone(buf_size, gfp);
if (skb) {
skb_reserve(skb, BUF_HEADROOM);
skb_put(skb, size);
struct tipc_msg *msg;
struct sk_buff *buf;
- buf = tipc_buf_acquire(hdr_sz + data_sz);
+ buf = tipc_buf_acquire(hdr_sz + data_sz, GFP_ATOMIC);
if (unlikely(!buf))
return NULL;
/* No fragmentation needed? */
if (likely(msz <= pktmax)) {
- skb = tipc_buf_acquire(msz);
+ skb = tipc_buf_acquire(msz, GFP_KERNEL);
if (unlikely(!skb))
return -ENOMEM;
skb_orphan(skb);
msg_set_importance(&pkthdr, msg_importance(mhdr));
/* Prepare first fragment */
- skb = tipc_buf_acquire(pktmax);
+ skb = tipc_buf_acquire(pktmax, GFP_KERNEL);
if (!skb)
return -ENOMEM;
skb_orphan(skb);
pktsz = drem + INT_H_SIZE;
else
pktsz = pktmax;
- skb = tipc_buf_acquire(pktsz);
+ skb = tipc_buf_acquire(pktsz, GFP_KERNEL);
if (!skb) {
rc = -ENOMEM;
goto error;
if (msz > (max / 2))
return false;
- _skb = tipc_buf_acquire(max);
+ _skb = tipc_buf_acquire(max, GFP_ATOMIC);
if (!_skb)
return false;
/* Never return SHORT header; expand by replacing buffer if necessary */
if (msg_short(hdr)) {
- *skb = tipc_buf_acquire(BASIC_H_SIZE + dlen);
+ *skb = tipc_buf_acquire(BASIC_H_SIZE + dlen, GFP_ATOMIC);
if (!*skb)
goto exit;
memcpy((*skb)->data + BASIC_H_SIZE, msg_data(hdr), dlen);
return (msg_user(hdr) == LINK_PROTOCOL) && (msg_type(hdr) == RESET_MSG);
}
-struct sk_buff *tipc_buf_acquire(u32 size);
+struct sk_buff *tipc_buf_acquire(u32 size, gfp_t gfp);
bool tipc_msg_validate(struct sk_buff *skb);
bool tipc_msg_reverse(u32 own_addr, struct sk_buff **skb, int err);
void tipc_msg_init(u32 own_addr, struct tipc_msg *m, u32 user, u32 type,
u32 dest)
{
struct tipc_net *tn = net_generic(net, tipc_net_id);
- struct sk_buff *buf = tipc_buf_acquire(INT_H_SIZE + size);
+ struct sk_buff *buf = tipc_buf_acquire(INT_H_SIZE + size, GFP_ATOMIC);
struct tipc_msg *msg;
if (buf != NULL) {
write_lock_bh(&n->lock);
}
+static void tipc_node_write_unlock_fast(struct tipc_node *n)
+{
+ write_unlock_bh(&n->lock);
+}
+
static void tipc_node_write_unlock(struct tipc_node *n)
{
struct net *net = n->net;
}
tipc_node_write_lock(n);
list_add_tail(subscr, &n->publ_list);
- tipc_node_write_unlock(n);
+ tipc_node_write_unlock_fast(n);
tipc_node_put(n);
}
}
tipc_node_write_lock(n);
list_del_init(subscr);
- tipc_node_write_unlock(n);
+ tipc_node_write_unlock_fast(n);
tipc_node_put(n);
}
static void tipc_recv_work(struct work_struct *work);
static void tipc_send_work(struct work_struct *work);
static void tipc_clean_outqueues(struct tipc_conn *con);
-static void tipc_sock_release(struct tipc_conn *con);
static void tipc_conn_kref_release(struct kref *kref)
{
struct tipc_conn *con = container_of(kref, struct tipc_conn, kref);
- struct sockaddr_tipc *saddr = con->server->saddr;
+ struct tipc_server *s = con->server;
+ struct sockaddr_tipc *saddr = s->saddr;
struct socket *sock = con->sock;
struct sock *sk;
}
saddr->scope = -TIPC_NODE_SCOPE;
kernel_bind(sock, (struct sockaddr *)saddr, sizeof(*saddr));
- tipc_sock_release(con);
sock_release(sock);
con->sock = NULL;
+
+ spin_lock_bh(&s->idr_lock);
+ idr_remove(&s->conn_idr, con->conid);
+ s->idr_in_use--;
+ spin_unlock_bh(&s->idr_lock);
}
tipc_clean_outqueues(con);
spin_lock_bh(&s->idr_lock);
con = idr_find(&s->conn_idr, conid);
- if (con)
+ if (con && test_bit(CF_CONNECTED, &con->flags))
conn_get(con);
+ else
+ con = NULL;
spin_unlock_bh(&s->idr_lock);
return con;
}
write_unlock_bh(&sk->sk_callback_lock);
}
-static void tipc_sock_release(struct tipc_conn *con)
-{
- struct tipc_server *s = con->server;
-
- if (con->conid)
- s->tipc_conn_release(con->conid, con->usr_data);
-
- tipc_unregister_callbacks(con);
-}
-
static void tipc_close_conn(struct tipc_conn *con)
{
struct tipc_server *s = con->server;
if (test_and_clear_bit(CF_CONNECTED, &con->flags)) {
+ tipc_unregister_callbacks(con);
- spin_lock_bh(&s->idr_lock);
- idr_remove(&s->conn_idr, con->conid);
- s->idr_in_use--;
- spin_unlock_bh(&s->idr_lock);
+ if (con->conid)
+ s->tipc_conn_release(con->conid, con->usr_data);
/* We shouldn't flush pending works as we may be in the
* thread. In fact the races with pending rx/tx work structs
if (!con)
return -EINVAL;
+ if (!test_bit(CF_CONNECTED, &con->flags)) {
+ conn_put(con);
+ return 0;
+ }
+
e = tipc_alloc_entry(data, len);
if (!e) {
conn_put(con);
list_add_tail(&e->list, &con->outqueue);
spin_unlock_bh(&con->outqueue_lock);
- if (test_bit(CF_CONNECTED, &con->flags)) {
- if (!queue_work(s->send_wq, &con->swork))
- conn_put(con);
- } else {
+ if (!queue_work(s->send_wq, &con->swork))
conn_put(con);
- }
return 0;
}
int ret;
spin_lock_bh(&con->outqueue_lock);
- while (1) {
+ while (test_bit(CF_CONNECTED, &con->flags)) {
e = list_entry(con->outqueue.next, struct outqueue_entry,
list);
if ((struct list_head *) e == &con->outqueue)
void tipc_server_stop(struct tipc_server *s)
{
struct tipc_conn *con;
- int total = 0;
int id;
spin_lock_bh(&s->idr_lock);
- for (id = 0; total < s->idr_in_use; id++) {
+ for (id = 0; s->idr_in_use; id++) {
con = idr_find(&s->conn_idr, id);
if (con) {
- total++;
spin_unlock_bh(&s->idr_lock);
tipc_close_conn(con);
spin_lock_bh(&s->idr_lock);
static void tipc_subscrp_delete(struct tipc_subscription *sub);
static void tipc_subscrb_put(struct tipc_subscriber *subscriber);
+static void tipc_subscrp_put(struct tipc_subscription *subscription);
+static void tipc_subscrp_get(struct tipc_subscription *subscription);
/**
* htohl - convert value to endianness used by destination
{
struct tipc_name_seq seq;
+ tipc_subscrp_get(sub);
tipc_subscrp_convert_seq(&sub->evt.s.seq, sub->swap, &seq);
if (!tipc_subscrp_check_overlap(&seq, found_lower, found_upper))
return;
tipc_subscrp_send_event(sub, found_lower, found_upper, event, port_ref,
node);
+ tipc_subscrp_put(sub);
}
static void tipc_subscrp_timeout(unsigned long data)
{
struct tipc_subscription *sub = (struct tipc_subscription *)data;
- struct tipc_subscriber *subscriber = sub->subscriber;
/* Notify subscriber of timeout */
tipc_subscrp_send_event(sub, sub->evt.s.seq.lower, sub->evt.s.seq.upper,
TIPC_SUBSCR_TIMEOUT, 0, 0);
- spin_lock_bh(&subscriber->lock);
- tipc_subscrp_delete(sub);
- spin_unlock_bh(&subscriber->lock);
-
- tipc_subscrb_put(subscriber);
+ tipc_subscrp_put(sub);
}
static void tipc_subscrb_kref_release(struct kref *kref)
{
- struct tipc_subscriber *subcriber = container_of(kref,
- struct tipc_subscriber, kref);
-
- kfree(subcriber);
+ kfree(container_of(kref,struct tipc_subscriber, kref));
}
static void tipc_subscrb_put(struct tipc_subscriber *subscriber)
kref_get(&subscriber->kref);
}
+static void tipc_subscrp_kref_release(struct kref *kref)
+{
+ struct tipc_subscription *sub = container_of(kref,
+ struct tipc_subscription,
+ kref);
+ struct tipc_net *tn = net_generic(sub->net, tipc_net_id);
+ struct tipc_subscriber *subscriber = sub->subscriber;
+
+ spin_lock_bh(&subscriber->lock);
+ tipc_nametbl_unsubscribe(sub);
+ list_del(&sub->subscrp_list);
+ atomic_dec(&tn->subscription_count);
+ spin_unlock_bh(&subscriber->lock);
+ kfree(sub);
+ tipc_subscrb_put(subscriber);
+}
+
+static void tipc_subscrp_put(struct tipc_subscription *subscription)
+{
+ kref_put(&subscription->kref, tipc_subscrp_kref_release);
+}
+
+static void tipc_subscrp_get(struct tipc_subscription *subscription)
+{
+ kref_get(&subscription->kref);
+}
+
+/* tipc_subscrb_subscrp_delete - delete a specific subscription or all
+ * subscriptions for a given subscriber.
+ */
+static void tipc_subscrb_subscrp_delete(struct tipc_subscriber *subscriber,
+ struct tipc_subscr *s)
+{
+ struct list_head *subscription_list = &subscriber->subscrp_list;
+ struct tipc_subscription *sub, *temp;
+
+ spin_lock_bh(&subscriber->lock);
+ list_for_each_entry_safe(sub, temp, subscription_list, subscrp_list) {
+ if (s && memcmp(s, &sub->evt.s, sizeof(struct tipc_subscr)))
+ continue;
+
+ tipc_subscrp_get(sub);
+ spin_unlock_bh(&subscriber->lock);
+ tipc_subscrp_delete(sub);
+ tipc_subscrp_put(sub);
+ spin_lock_bh(&subscriber->lock);
+
+ if (s)
+ break;
+ }
+ spin_unlock_bh(&subscriber->lock);
+}
+
static struct tipc_subscriber *tipc_subscrb_create(int conid)
{
struct tipc_subscriber *subscriber;
pr_warn("Subscriber rejected, no memory\n");
return NULL;
}
- kref_init(&subscriber->kref);
INIT_LIST_HEAD(&subscriber->subscrp_list);
+ kref_init(&subscriber->kref);
subscriber->conid = conid;
spin_lock_init(&subscriber->lock);
static void tipc_subscrb_delete(struct tipc_subscriber *subscriber)
{
- struct tipc_subscription *sub, *temp;
- u32 timeout;
-
- spin_lock_bh(&subscriber->lock);
- /* Destroy any existing subscriptions for subscriber */
- list_for_each_entry_safe(sub, temp, &subscriber->subscrp_list,
- subscrp_list) {
- timeout = htohl(sub->evt.s.timeout, sub->swap);
- if ((timeout == TIPC_WAIT_FOREVER) || del_timer(&sub->timer)) {
- tipc_subscrp_delete(sub);
- tipc_subscrb_put(subscriber);
- }
- }
- spin_unlock_bh(&subscriber->lock);
-
+ tipc_subscrb_subscrp_delete(subscriber, NULL);
tipc_subscrb_put(subscriber);
}
static void tipc_subscrp_delete(struct tipc_subscription *sub)
{
- struct tipc_net *tn = net_generic(sub->net, tipc_net_id);
+ u32 timeout = htohl(sub->evt.s.timeout, sub->swap);
- tipc_nametbl_unsubscribe(sub);
- list_del(&sub->subscrp_list);
- kfree(sub);
- atomic_dec(&tn->subscription_count);
+ if (timeout == TIPC_WAIT_FOREVER || del_timer(&sub->timer))
+ tipc_subscrp_put(sub);
}
static void tipc_subscrp_cancel(struct tipc_subscr *s,
struct tipc_subscriber *subscriber)
{
- struct tipc_subscription *sub, *temp;
- u32 timeout;
-
- spin_lock_bh(&subscriber->lock);
- /* Find first matching subscription, exit if not found */
- list_for_each_entry_safe(sub, temp, &subscriber->subscrp_list,
- subscrp_list) {
- if (!memcmp(s, &sub->evt.s, sizeof(struct tipc_subscr))) {
- timeout = htohl(sub->evt.s.timeout, sub->swap);
- if ((timeout == TIPC_WAIT_FOREVER) ||
- del_timer(&sub->timer)) {
- tipc_subscrp_delete(sub);
- tipc_subscrb_put(subscriber);
- }
- break;
- }
- }
- spin_unlock_bh(&subscriber->lock);
+ tipc_subscrb_subscrp_delete(subscriber, s);
}
static struct tipc_subscription *tipc_subscrp_create(struct net *net,
sub->swap = swap;
memcpy(&sub->evt.s, s, sizeof(*s));
atomic_inc(&tn->subscription_count);
+ kref_init(&sub->kref);
return sub;
}
spin_lock_bh(&subscriber->lock);
list_add(&sub->subscrp_list, &subscriber->subscrp_list);
- tipc_subscrb_get(subscriber);
sub->subscriber = subscriber;
tipc_nametbl_subscribe(sub);
+ tipc_subscrb_get(subscriber);
spin_unlock_bh(&subscriber->lock);
+ setup_timer(&sub->timer, tipc_subscrp_timeout, (unsigned long)sub);
timeout = htohl(sub->evt.s.timeout, swap);
- if (timeout == TIPC_WAIT_FOREVER)
- return;
- setup_timer(&sub->timer, tipc_subscrp_timeout, (unsigned long)sub);
- mod_timer(&sub->timer, jiffies + msecs_to_jiffies(timeout));
+ if (timeout != TIPC_WAIT_FOREVER)
+ mod_timer(&sub->timer, jiffies + msecs_to_jiffies(timeout));
}
/* Handle one termination request for the subscriber */
* @evt: template for events generated by subscription
*/
struct tipc_subscription {
+ struct kref kref;
struct tipc_subscriber *subscriber;
struct net *net;
struct timer_list timer;
unsigned int hash;
struct unix_address *addr;
struct hlist_head *list;
+ struct path path = { NULL, NULL };
err = -EINVAL;
if (sunaddr->sun_family != AF_UNIX)
goto out;
addr_len = err;
+ if (sun_path[0]) {
+ umode_t mode = S_IFSOCK |
+ (SOCK_INODE(sock)->i_mode & ~current_umask());
+ err = unix_mknod(sun_path, mode, &path);
+ if (err) {
+ if (err == -EEXIST)
+ err = -EADDRINUSE;
+ goto out;
+ }
+ }
+
err = mutex_lock_interruptible(&u->bindlock);
if (err)
- goto out;
+ goto out_put;
err = -EINVAL;
if (u->addr)
atomic_set(&addr->refcnt, 1);
if (sun_path[0]) {
- struct path path;
- umode_t mode = S_IFSOCK |
- (SOCK_INODE(sock)->i_mode & ~current_umask());
- err = unix_mknod(sun_path, mode, &path);
- if (err) {
- if (err == -EEXIST)
- err = -EADDRINUSE;
- unix_release_addr(addr);
- goto out_up;
- }
addr->hash = UNIX_HASH_SIZE;
hash = d_backing_inode(path.dentry)->i_ino & (UNIX_HASH_SIZE - 1);
spin_lock(&unix_table_lock);
spin_unlock(&unix_table_lock);
out_up:
mutex_unlock(&u->bindlock);
+out_put:
+ if (err)
+ path_put(&path);
out:
return err;
}
break;
}
+ /*
+ * Older kernel versions ignored this attribute entirely, so don't
+ * reject attempts to update it but mark it as unused instead so the
+ * driver won't look at the data.
+ */
+ if (statype != CFG80211_STA_AP_CLIENT_UNASSOC &&
+ statype != CFG80211_STA_TDLS_PEER_SETUP)
+ params->opmode_notif_used = false;
+
return 0;
}
EXPORT_SYMBOL(cfg80211_check_station_change);
params.local_pm = pm;
}
+ if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) {
+ params.opmode_notif_used = true;
+ params.opmode_notif =
+ nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]);
+ }
+
/* Include parameters for TDLS peer (will check later) */
err = nl80211_set_station_tdls(info, ¶ms);
if (err)
list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
bool schedule_destroy_work = false;
- bool schedule_scan_stop = false;
struct cfg80211_sched_scan_request *sched_scan_req =
rcu_dereference(rdev->sched_scan_req);
if (sched_scan_req && notify->portid &&
- sched_scan_req->owner_nlportid == notify->portid)
- schedule_scan_stop = true;
+ sched_scan_req->owner_nlportid == notify->portid) {
+ sched_scan_req->owner_nlportid = 0;
+
+ if (rdev->ops->sched_scan_stop &&
+ rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
+ schedule_work(&rdev->sched_scan_stop_wk);
+ }
list_for_each_entry_rcu(wdev, &rdev->wiphy.wdev_list, list) {
cfg80211_mlme_unregister_socket(wdev, notify->portid);
spin_unlock(&rdev->destroy_list_lock);
schedule_work(&rdev->destroy_work);
}
- } else if (schedule_scan_stop) {
- sched_scan_req->owner_nlportid = 0;
-
- if (rdev->ops->sched_scan_stop &&
- rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
- schedule_work(&rdev->sched_scan_stop_wk);
}
}
#include <unistd.h>
#include <string.h>
#include <errno.h>
-#include <net/ethernet.h>
+#include <linux/if_ether.h>
#include <net/if.h>
#include <linux/if_packet.h>
#include <arpa/inet.h>
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*/
+#define KBUILD_MODNAME "foo"
#include <uapi/linux/bpf.h>
#include <uapi/linux/if_ether.h>
#include <uapi/linux/if_packet.h>
#include <string.h>
#include <fcntl.h>
#include <poll.h>
-#include <sys/ioctl.h>
#include <linux/perf_event.h>
#include <linux/bpf.h>
#include <errno.h>
* encapsulating the incoming packet in an IPv4/v6 header
* and then XDP_TX it out.
*/
+#define KBUILD_MODNAME "foo"
#include <uapi/linux/bpf.h>
#include <linux/in.h>
#include <linux/if_ether.h>
{
unsigned int size = 0;
struct mdev_state *mdev_state;
- int bar_index;
+ u32 bar_index;
if (!mdev)
return -EINVAL;
if (!mdev_state)
return -EINVAL;
- mutex_lock(&mdev_state->ops_lock);
bar_index = region_info->index;
+ if (bar_index >= VFIO_PCI_NUM_REGIONS)
+ return -EINVAL;
+
+ mutex_lock(&mdev_state->ops_lock);
switch (bar_index) {
case VFIO_PCI_CONFIG_REGION_INDEX:
memcpy(&mdev_state->dev_info, &info, sizeof(info));
- return copy_to_user((void __user *)arg, &info, minsz);
+ if (copy_to_user((void __user *)arg, &info, minsz))
+ return -EFAULT;
+
+ return 0;
}
case VFIO_DEVICE_GET_REGION_INFO:
{
if (ret)
return ret;
- return copy_to_user((void __user *)arg, &info, minsz);
+ if (copy_to_user((void __user *)arg, &info, minsz))
+ return -EFAULT;
+
+ return 0;
}
case VFIO_DEVICE_GET_IRQ_INFO:
if (ret)
return ret;
- if (info.count == -1)
- return -EINVAL;
+ if (copy_to_user((void __user *)arg, &info, minsz))
+ return -EFAULT;
- return copy_to_user((void __user *)arg, &info, minsz);
+ return 0;
}
case VFIO_DEVICE_SET_IRQS:
{
$(CPP) -D__GENKSYMS__ $(c_flags) $< | \
$(GENKSYMS) $(if $(1), -T $(2)) \
$(patsubst y,-s _,$(CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX)) \
+ $(patsubst y,-R,$(CONFIG_MODULE_REL_CRCS)) \
$(if $(KBUILD_PRESERVE),-p) \
-r $(firstword $(wildcard $(2:.symtypes=.symref) /dev/null))
$(CPP) -D__GENKSYMS__ $(c_flags) -xc - | \
$(GENKSYMS) $(if $(1), -T $(2)) \
$(patsubst y,-s _,$(CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX)) \
+ $(patsubst y,-R,$(CONFIG_MODULE_REL_CRCS)) \
$(if $(KBUILD_PRESERVE),-p) \
-r $(firstword $(wildcard $(2:.symtypes=.symref) /dev/null))
int in_source_file;
static int flag_debug, flag_dump_defs, flag_reference, flag_dump_types,
- flag_preserve, flag_warnings;
+ flag_preserve, flag_warnings, flag_rel_crcs;
static const char *mod_prefix = "";
static int errors;
fputs(">\n", debugfile);
/* Used as a linker script. */
- printf("%s__crc_%s = 0x%08lx ;\n", mod_prefix, name, crc);
+ printf(!flag_rel_crcs ? "%s__crc_%s = 0x%08lx;\n" :
+ "SECTIONS { .rodata : ALIGN(4) { "
+ "%s__crc_%s = .; LONG(0x%08lx); } }\n",
+ mod_prefix, name, crc);
}
}
static void genksyms_usage(void)
{
- fputs("Usage:\n" "genksyms [-adDTwqhV] > /path/to/.tmp_obj.ver\n" "\n"
+ fputs("Usage:\n" "genksyms [-adDTwqhVR] > /path/to/.tmp_obj.ver\n" "\n"
#ifdef __GNU_LIBRARY__
" -s, --symbol-prefix Select symbol prefix\n"
" -d, --debug Increment the debug level (repeatable)\n"
" -q, --quiet Disable warnings (default)\n"
" -h, --help Print this message\n"
" -V, --version Print the release version\n"
+ " -R, --relative-crc Emit section relative symbol CRCs\n"
#else /* __GNU_LIBRARY__ */
" -s Select symbol prefix\n"
" -d Increment the debug level (repeatable)\n"
" -q Disable warnings (default)\n"
" -h Print this message\n"
" -V Print the release version\n"
+ " -R Emit section relative symbol CRCs\n"
#endif /* __GNU_LIBRARY__ */
, stderr);
}
{"preserve", 0, 0, 'p'},
{"version", 0, 0, 'V'},
{"help", 0, 0, 'h'},
+ {"relative-crc", 0, 0, 'R'},
{0, 0, 0, 0}
};
- while ((o = getopt_long(argc, argv, "s:dwqVDr:T:ph",
+ while ((o = getopt_long(argc, argv, "s:dwqVDr:T:phR",
&long_opts[0], NULL)) != EOF)
#else /* __GNU_LIBRARY__ */
- while ((o = getopt(argc, argv, "s:dwqVDr:T:ph")) != EOF)
+ while ((o = getopt(argc, argv, "s:dwqVDr:T:phR")) != EOF)
#endif /* __GNU_LIBRARY__ */
switch (o) {
case 's':
case 'h':
genksyms_usage();
return 0;
+ case 'R':
+ flag_rel_crcs = 1;
+ break;
default:
genksyms_usage();
return 1;
"_SDA2_BASE_", /* ppc */
NULL };
+ static char *special_prefixes[] = {
+ "__crc_", /* modversions */
+ NULL };
+
static char *special_suffixes[] = {
"_veneer", /* arm */
"_from_arm", /* arm */
if (strcmp(sym_name, special_symbols[i]) == 0)
return 0;
+ for (i = 0; special_prefixes[i]; i++) {
+ int l = strlen(special_prefixes[i]);
+
+ if (l <= strlen(sym_name) &&
+ strncmp(sym_name, special_prefixes[i], l) == 0)
+ return 0;
+ }
+
for (i = 0; special_suffixes[i]; i++) {
int l = strlen(sym_name) - strlen(special_suffixes[i]);
if (strncmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) {
is_crc = true;
crc = (unsigned int) sym->st_value;
+ if (sym->st_shndx != SHN_UNDEF && sym->st_shndx != SHN_ABS) {
+ unsigned int *crcp;
+
+ /* symbol points to the CRC in the ELF object */
+ crcp = (void *)info->hdr + sym->st_value +
+ info->sechdrs[sym->st_shndx].sh_offset -
+ (info->hdr->e_type != ET_REL ?
+ info->sechdrs[sym->st_shndx].sh_addr : 0);
+ crc = *crcp;
+ }
sym_update_crc(symname + strlen(CRC_PFX), mod, crc,
export);
}
nau8825_xtalk_backup(nau8825);
/* Config IIS as master to output signal by codec */
regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL2,
- NAU8825_I2S_MS_MASK | NAU8825_I2S_DRV_MASK |
+ NAU8825_I2S_MS_MASK | NAU8825_I2S_LRC_DIV_MASK |
NAU8825_I2S_BLK_DIV_MASK, NAU8825_I2S_MS_MASTER |
- (0x2 << NAU8825_I2S_DRV_SFT) | 0x1);
+ (0x2 << NAU8825_I2S_LRC_DIV_SFT) | 0x1);
/* Ramp up headphone volume to 0dB to get better performance and
* avoid pop noise in headphone.
*/
NAU8825_IRQ_RMS_EN, NAU8825_IRQ_RMS_EN);
/* Recover default value for IIS */
regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL2,
- NAU8825_I2S_MS_MASK | NAU8825_I2S_DRV_MASK |
+ NAU8825_I2S_MS_MASK | NAU8825_I2S_LRC_DIV_MASK |
NAU8825_I2S_BLK_DIV_MASK, NAU8825_I2S_MS_SLAVE);
/* Restore value of specific register for cross talk */
nau8825_xtalk_restore(nau8825);
NAU8825_FLL_INTEGER_MASK, fll_param->fll_int);
/* FLL pre-scaler */
regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL4,
- NAU8825_FLL_REF_DIV_MASK, fll_param->clk_ref_div);
+ NAU8825_FLL_REF_DIV_MASK,
+ fll_param->clk_ref_div << NAU8825_FLL_REF_DIV_SFT);
/* select divided VCO input */
regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL5,
NAU8825_FLL_CLK_SW_MASK, NAU8825_FLL_CLK_SW_REF);
#define NAU8825_FLL_CLK_SRC_FS (0x3 << NAU8825_FLL_CLK_SRC_SFT)
/* FLL4 (0x07) */
-#define NAU8825_FLL_REF_DIV_MASK (0x3 << 10)
+#define NAU8825_FLL_REF_DIV_SFT 10
+#define NAU8825_FLL_REF_DIV_MASK (0x3 << NAU8825_FLL_REF_DIV_SFT)
/* FLL5 (0x08) */
#define NAU8825_FLL_PDB_DAC_EN (0x1 << 15)
/* I2S_PCM_CTRL2 (0x1d) */
#define NAU8825_I2S_TRISTATE (1 << 15) /* 0 - normal mode, 1 - Hi-Z output */
-#define NAU8825_I2S_DRV_SFT 12
-#define NAU8825_I2S_DRV_MASK (0x3 << NAU8825_I2S_DRV_SFT)
+#define NAU8825_I2S_LRC_DIV_SFT 12
+#define NAU8825_I2S_LRC_DIV_MASK (0x3 << NAU8825_I2S_LRC_DIV_SFT)
#define NAU8825_I2S_MS_SFT 3
#define NAU8825_I2S_MS_MASK (1 << NAU8825_I2S_MS_SFT)
#define NAU8825_I2S_MS_MASTER (1 << NAU8825_I2S_MS_SFT)
}
}
+ regmap_update_bits(rt5645->regmap, RT5645_ADDA_CLK1,
+ RT5645_I2S_PD1_MASK, RT5645_I2S_PD1_2);
+
if (rt5645->pdata.jd_invert) {
regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV);
{ 108, 0x00 }, { 109, 0x00 },
};
+static bool aic3x_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case AIC3X_RESET:
+ return true;
+ default:
+ return false;
+ }
+}
+
static const struct regmap_config aic3x_regmap = {
.reg_bits = 8,
.val_bits = 8,
.max_register = DAC_ICC_ADJ,
.reg_defaults = aic3x_reg,
.num_reg_defaults = ARRAY_SIZE(aic3x_reg),
+
+ .volatile_reg = aic3x_volatile_reg,
+
.cache_type = REGCACHE_RBTREE,
};
const struct wmfw_region *region;
const struct wm_adsp_region *mem;
const char *region_name;
- char *file, *text;
+ char *file, *text = NULL;
struct wm_adsp_buf *buf;
unsigned int reg;
int regions = 0;
regions, le32_to_cpu(region->len), offset,
region_name);
+ if ((pos + le32_to_cpu(region->len) + sizeof(*region)) >
+ firmware->size) {
+ adsp_err(dsp,
+ "%s.%d: %s region len %d bytes exceeds file length %zu\n",
+ file, regions, region_name,
+ le32_to_cpu(region->len), firmware->size);
+ ret = -EINVAL;
+ goto out_fw;
+ }
+
if (text) {
memcpy(text, region->data, le32_to_cpu(region->len));
adsp_info(dsp, "%s: %s\n", file, text);
kfree(text);
+ text = NULL;
}
if (reg) {
regmap_async_complete(regmap);
wm_adsp_buf_free(&buf_list);
release_firmware(firmware);
+ kfree(text);
out:
kfree(file);
}
if (reg) {
+ if ((pos + le32_to_cpu(blk->len) + sizeof(*blk)) >
+ firmware->size) {
+ adsp_err(dsp,
+ "%s.%d: %s region len %d bytes exceeds file length %zu\n",
+ file, blocks, region_name,
+ le32_to_cpu(blk->len),
+ firmware->size);
+ ret = -EINVAL;
+ goto out_fw;
+ }
+
buf = wm_adsp_buf_alloc(blk->data,
le32_to_cpu(blk->len),
&buf_list);
}
if (!pdata) {
- ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
- if (ret == -EPROBE_DEFER) {
- dev_err(&pdev->dev,
- "failed to register PCM, deferring probe\n");
- return ret;
- } else if (ret) {
- dev_err(&pdev->dev,
- "Could not register DMA PCM: %d\n"
- "falling back to PIO mode\n", ret);
+ if (irq >= 0) {
ret = dw_pcm_register(pdev);
- if (ret) {
- dev_err(&pdev->dev,
- "Could not register PIO PCM: %d\n",
+ dev->use_pio = true;
+ } else {
+ ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL,
+ 0);
+ dev->use_pio = false;
+ }
+
+ if (ret) {
+ dev_err(&pdev->dev, "could not register pcm: %d\n",
ret);
- goto err_clk_disable;
- }
+ goto err_clk_disable;
}
}
* @dbg_stats: Debugging statistics
*
* @soc: SoC specific data
+ *
+ * @fifo_watermark: the FIFO watermark setting. Notifies DMA when
+ * there are @fifo_watermark or fewer words in TX fifo or
+ * @fifo_watermark or more empty words in RX fifo.
+ * @dma_maxburst: max number of words to transfer in one go. So far,
+ * this is always the same as fifo_watermark.
*/
struct fsl_ssi_private {
struct regmap *regs;
const struct fsl_ssi_soc_data *soc;
struct device *dev;
+
+ u32 fifo_watermark;
+ u32 dma_maxburst;
};
/*
regmap_write(regs, CCSR_SSI_SRCR, srcr);
regmap_write(regs, CCSR_SSI_SCR, scr);
- /*
- * Set the watermark for transmit FIFI 0 and receive FIFO 0. We don't
- * use FIFO 1. We program the transmit water to signal a DMA transfer
- * if there are only two (or fewer) elements left in the FIFO. Two
- * elements equals one frame (left channel, right channel). This value,
- * however, depends on the depth of the transmit buffer.
- *
- * We set the watermark on the same level as the DMA burstsize. For
- * fiq it is probably better to use the biggest possible watermark
- * size.
- */
- if (ssi_private->use_dma)
- wm = ssi_private->fifo_depth - 2;
- else
- wm = ssi_private->fifo_depth;
+ wm = ssi_private->fifo_watermark;
regmap_write(regs, CCSR_SSI_SFCSR,
CCSR_SSI_SFCSR_TFWM0(wm) | CCSR_SSI_SFCSR_RFWM0(wm) |
dev_dbg(&pdev->dev, "could not get baud clock: %ld\n",
PTR_ERR(ssi_private->baudclk));
- /*
- * We have burstsize be "fifo_depth - 2" to match the SSI
- * watermark setting in fsl_ssi_startup().
- */
- ssi_private->dma_params_tx.maxburst = ssi_private->fifo_depth - 2;
- ssi_private->dma_params_rx.maxburst = ssi_private->fifo_depth - 2;
+ ssi_private->dma_params_tx.maxburst = ssi_private->dma_maxburst;
+ ssi_private->dma_params_rx.maxburst = ssi_private->dma_maxburst;
ssi_private->dma_params_tx.addr = ssi_private->ssi_phys + CCSR_SSI_STX0;
ssi_private->dma_params_rx.addr = ssi_private->ssi_phys + CCSR_SSI_SRX0;
/* Older 8610 DTs didn't have the fifo-depth property */
ssi_private->fifo_depth = 8;
+ /*
+ * Set the watermark for transmit FIFO 0 and receive FIFO 0. We don't
+ * use FIFO 1 but set the watermark appropriately nontheless.
+ * We program the transmit water to signal a DMA transfer
+ * if there are N elements left in the FIFO. For chips with 15-deep
+ * FIFOs, set watermark to 8. This allows the SSI to operate at a
+ * high data rate without channel slipping. Behavior is unchanged
+ * for the older chips with a fifo depth of only 8. A value of 4
+ * might be appropriate for the older chips, but is left at
+ * fifo_depth-2 until sombody has a chance to test.
+ *
+ * We set the watermark on the same level as the DMA burstsize. For
+ * fiq it is probably better to use the biggest possible watermark
+ * size.
+ */
+ switch (ssi_private->fifo_depth) {
+ case 15:
+ /*
+ * 2 samples is not enough when running at high data
+ * rates (like 48kHz @ 16 bits/channel, 16 channels)
+ * 8 seems to split things evenly and leave enough time
+ * for the DMA to fill the FIFO before it's over/under
+ * run.
+ */
+ ssi_private->fifo_watermark = 8;
+ ssi_private->dma_maxburst = 8;
+ break;
+ case 8:
+ default:
+ /*
+ * maintain old behavior for older chips.
+ * Keeping it the same because I don't have an older
+ * board to test with.
+ * I suspect this could be changed to be something to
+ * leave some more space in the fifo.
+ */
+ ssi_private->fifo_watermark = ssi_private->fifo_depth - 2;
+ ssi_private->dma_maxburst = ssi_private->fifo_depth - 2;
+ break;
+ }
+
dev_set_drvdata(&pdev->dev, ssi_private);
if (ssi_private->soc->imx) {
* for Jack detection and button press
*/
ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_RCCLK,
- 0,
+ 48000 * 512,
SND_SOC_CLOCK_IN);
if (!ret) {
if ((byt_rt5640_quirk & BYT_RT5640_MCLK_EN) && priv->mclk)
if ((byt_rt5640_quirk & BYT_RT5640_MCLK_EN) && (is_valleyview())) {
priv->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3");
if (IS_ERR(priv->mclk)) {
+ ret_val = PTR_ERR(priv->mclk);
+
dev_err(&pdev->dev,
- "Failed to get MCLK from pmc_plt_clk_3: %ld\n",
- PTR_ERR(priv->mclk));
- return PTR_ERR(priv->mclk);
+ "Failed to get MCLK from pmc_plt_clk_3: %d\n",
+ ret_val);
+
+ /*
+ * Fall back to bit clock usage for -ENOENT (clock not
+ * available likely due to missing dependencies), bail
+ * for all other errors, including -EPROBE_DEFER
+ */
+ if (ret_val != -ENOENT)
+ return ret_val;
+ byt_rt5640_quirk &= ~BYT_RT5640_MCLK_EN;
}
}
snd_pcm_set_sync(substream);
mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream);
+ if (!mconfig)
+ return -EINVAL;
+
skl_tplg_d0i3_get(skl, mconfig->d0i3_caps);
return 0;
void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx)
{
+
+ if (ctx->dsp->fw)
+ release_firmware(ctx->dsp->fw);
skl_clear_module_table(ctx->dsp);
skl_freeup_uuid_list(ctx);
skl_ipc_free(&ctx->ipc);
return -ENOMEM;
ret = snd_ctl_add(card, kctrl);
- if (ret < 0) {
- snd_ctl_free_one(kctrl);
+ if (ret < 0)
return ret;
- }
cfg->update = update;
cfg->card = card;
component->init = aux_dev->init;
component->auxiliary = 1;
+ list_add(&component->card_aux_list, &card->aux_comp_list);
return 0;
static int soc_probe_aux_devices(struct snd_soc_card *card)
{
- struct snd_soc_component *comp;
+ struct snd_soc_component *comp, *tmp;
int order;
int ret;
for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST;
order++) {
- list_for_each_entry(comp, &card->component_dev_list, card_list) {
- if (!comp->auxiliary)
- continue;
-
+ list_for_each_entry_safe(comp, tmp, &card->aux_comp_list,
+ card_aux_list) {
if (comp->driver->probe_order == order) {
ret = soc_probe_component(card, comp);
if (ret < 0) {
comp->name, ret);
return ret;
}
+ list_del(&comp->card_aux_list);
}
}
}
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
fe->dpcm[stream].state = SND_SOC_DPCM_STATE_STOP;
break;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PAUSED;
+ break;
}
out:
== SND_SOC_TPLG_TYPE_MIXER)
kfree(kcontrol->tlv.p);
- snd_ctl_remove(card, kcontrol);
-
/* Private value is used as struct soc_mixer_control
* for volume mixers or soc_bytes_ext for bytes
* controls.
*/
kfree((void *)kcontrol->private_value);
+ snd_ctl_remove(card, kcontrol);
}
kfree(w->kcontrol_news);
}
case USB_ID(0x045E, 0x076F): /* MS Lifecam HD-6000 */
case USB_ID(0x045E, 0x0772): /* MS Lifecam Studio */
case USB_ID(0x045E, 0x0779): /* MS Lifecam HD-3000 */
+ case USB_ID(0x047F, 0x02F7): /* Plantronics BT-600 */
case USB_ID(0x047F, 0x0415): /* Plantronics BT-300 */
case USB_ID(0x047F, 0xAA05): /* Plantronics DA45 */
case USB_ID(0x04D8, 0xFEEA): /* Benchmark DAC1 Pre */
[IIO_RESISTANCE] = "resistance",
[IIO_PH] = "ph",
[IIO_UVINDEX] = "uvindex",
+ [IIO_GRAVITY] = "gravity",
};
static const char * const iio_ev_type_text[] = {
case IIO_RESISTANCE:
case IIO_PH:
case IIO_UVINDEX:
+ case IIO_GRAVITY:
break;
default:
return false;
else
err = get_arg(p, opt, flags, (const char **)opt->value);
+ if (opt->set)
+ *(bool *)opt->set = true;
+
/* PARSE_OPT_NOEMPTY: Allow NULL but disallow empty string. */
if (opt->flags & PARSE_OPT_NOEMPTY) {
const char *val = *(const char **)opt->value;
{ .type = OPTION_STRING, .short_name = (s), .long_name = (l), \
.value = check_vtype(v, const char **), (a), .help = (h), \
.flags = PARSE_OPT_OPTARG, .defval = (intptr_t)(d) }
+#define OPT_STRING_OPTARG_SET(s, l, v, os, a, h, d) \
+ { .type = OPTION_STRING, .short_name = (s), .long_name = (l), \
+ .value = check_vtype(v, const char **), (a), .help = (h), \
+ .flags = PARSE_OPT_OPTARG, .defval = (intptr_t)(d), \
+ .set = check_vtype(os, bool *)}
#define OPT_STRING_NOEMPTY(s, l, v, a, h) { .type = OPTION_STRING, .short_name = (s), .long_name = (l), .value = check_vtype(v, const char **), (a), .help = (h), .flags = PARSE_OPT_NOEMPTY}
#define OPT_DATE(s, l, v, h) \
{ .type = OPTION_CALLBACK, .short_name = (s), .long_name = (l), .value = (v), .argh = "time", .help = (h), .callback = parse_opt_approxidate_cb }
trace_seq_printf(s, "%lld ", val);
if (pevent_get_field_val(s, event, "prev_prio", record, &val, 0) == 0)
- trace_seq_printf(s, "[%lld] ", val);
+ trace_seq_printf(s, "[%d] ", (int) val);
if (pevent_get_field_val(s, event, "prev_state", record, &val, 0) == 0)
write_state(s, val);
trace_seq_printf(s, "%lld", val);
if (pevent_get_field_val(s, event, "next_prio", record, &val, 0) == 0)
- trace_seq_printf(s, " [%lld]", val);
+ trace_seq_printf(s, " [%d]", (int) val);
return 0;
}
*type = INSN_RETURN;
break;
- case 0xc5: /* iret */
case 0xca: /* retf */
case 0xcb: /* retf */
+ case 0xcf: /* iret */
*type = INSN_CONTEXT_SWITCH;
break;
particular perf.data snapshot should be kept or not.
Implies --timestamp-filename, --no-buildid and --no-buildid-cache.
+The reason for the latter two is to reduce the data file switching
+overhead. You can still switch them on with:
+
+ --switch-output --no-no-buildid --no-no-buildid-cache
--dry-run::
Parse options then exit. --dry-run can be used to detect errors in cmdline
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \
$(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'
-install-bin: install-tools install-tests
+install-bin: install-tools install-tests install-traceevent-plugins
-install: install-bin try-install-man install-traceevent-plugins
+install: install-bin try-install-man
install-python_ext:
$(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)'
{ "__GFP_RECLAIM", "R" },
{ "__GFP_DIRECT_RECLAIM", "DR" },
{ "__GFP_KSWAPD_RECLAIM", "KR" },
- { "__GFP_OTHER_NODE", "ON" },
};
static size_t max_gfp_len;
* perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
* using pipes, etc.
*/
-struct option __record_options[] = {
+static struct option __record_options[] = {
OPT_CALLBACK('e', "event", &record.evlist, "event",
"event selector. use 'perf list' to list available events",
parse_events_option),
* overhead. Still generate buildid if they are required
* explicitly using
*
- * perf record --signal-trigger --no-no-buildid \
+ * perf record --switch-output --no-no-buildid \
* --no-no-buildid-cache
*
* Following code equals to:
u64 skipped_samples;
const char *time_str;
struct perf_time_interval ptime;
+ struct perf_time_interval hist_time;
};
/* per thread run time data */
timehist_print_sample(sched, sample, &al, thread, t);
out:
+ if (sched->hist_time.start == 0 && t >= ptime->start)
+ sched->hist_time.start = t;
+ if (ptime->end == 0 || t <= ptime->end)
+ sched->hist_time.end = t;
+
if (tr) {
/* time of this sched_switch event becomes last time task seen */
tr->last_time = sample->time;
struct thread *t;
struct thread_runtime *r;
int i;
+ u64 hist_time = sched->hist_time.end - sched->hist_time.start;
memset(&totals, 0, sizeof(totals));
totals.sched_count += r->run_stats.n;
printf(" CPU %2d idle for ", i);
print_sched_time(r->total_run_time, 6);
- printf(" msec\n");
+ printf(" msec (%6.2f%%)\n", 100.0 * r->total_run_time / hist_time);
} else
printf(" CPU %2d idle entire time window\n", i);
}
printf("\n"
" Total number of unique tasks: %" PRIu64 "\n"
- "Total number of context switches: %" PRIu64 "\n"
- " Total run time (msec): ",
+ "Total number of context switches: %" PRIu64 "\n",
totals.task_count, totals.sched_count);
+ printf(" Total run time (msec): ");
print_sched_time(totals.total_run_time, 2);
printf("\n");
+
+ printf(" Total scheduling time (msec): ");
+ print_sched_time(hist_time, 2);
+ printf(" (x %d)\n", sched->max_cpu);
}
typedef int (*sched_handler)(struct perf_tool *tool,
/* A file path -- this is an offline module */
if (module && strchr(module, '/'))
- return machine__findnew_module_map(host_machine, 0, module);
+ return dso__new_map(module);
if (!module)
module = "kernel";
if (strncmp(pos->dso->short_name + 1, module,
pos->dso->short_name_len - 2) == 0 &&
module[pos->dso->short_name_len - 2] == '\0') {
+ map__get(pos);
return pos;
}
}
return kernel_get_module_map(target);
}
-static void put_target_map(struct map *map, bool user)
-{
- if (map && user) {
- /* Only the user map needs to be released */
- map__put(map);
- }
-}
-
-
static int convert_exec_to_group(const char *exec, char **result)
{
char *ptr1, *ptr2, *exec_copy;
return true;
}
-/*
- * NOTE:
- * '.gnu.linkonce.this_module' section of kernel module elf directly
- * maps to 'struct module' from linux/module.h. This section contains
- * actual module name which will be used by kernel after loading it.
- * But, we cannot use 'struct module' here since linux/module.h is not
- * exposed to user-space. Offset of 'name' has remained same from long
- * time, so hardcoding it here.
- */
-#ifdef __LP64__
-#define MOD_NAME_OFFSET 24
-#else
-#define MOD_NAME_OFFSET 12
-#endif
-
/*
* @module can be module name of module file path. In case of path,
* inspect elf and find out what is actual module name.
Elf_Data *data;
Elf_Scn *sec;
char *mod_name = NULL;
+ int name_offset;
fd = open(module, O_RDONLY);
if (fd < 0)
if (!data || !data->d_buf)
goto ret_err;
- mod_name = strdup((char *)data->d_buf + MOD_NAME_OFFSET);
+ /*
+ * NOTE:
+ * '.gnu.linkonce.this_module' section of kernel module elf directly
+ * maps to 'struct module' from linux/module.h. This section contains
+ * actual module name which will be used by kernel after loading it.
+ * But, we cannot use 'struct module' here since linux/module.h is not
+ * exposed to user-space. Offset of 'name' has remained same from long
+ * time, so hardcoding it here.
+ */
+ if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
+ name_offset = 12;
+ else /* expect ELFCLASS64 by default */
+ name_offset = 24;
+
+ mod_name = strdup((char *)data->d_buf + name_offset);
ret_err:
elf_end(elf);
}
out:
- put_target_map(map, uprobes);
+ map__put(map);
return ret;
}
return ret ? : -ENOENT;
}
+/* Adjust symbol name and address */
+static int post_process_probe_trace_point(struct probe_trace_point *tp,
+ struct map *map, unsigned long offs)
+{
+ struct symbol *sym;
+ u64 addr = tp->address + tp->offset - offs;
+
+ sym = map__find_symbol(map, addr);
+ if (!sym)
+ return -ENOENT;
+
+ if (strcmp(sym->name, tp->symbol)) {
+ /* If we have no realname, use symbol for it */
+ if (!tp->realname)
+ tp->realname = tp->symbol;
+ else
+ free(tp->symbol);
+ tp->symbol = strdup(sym->name);
+ if (!tp->symbol)
+ return -ENOMEM;
+ }
+ tp->offset = addr - sym->start;
+ tp->address -= offs;
+
+ return 0;
+}
+
+/*
+ * Rename DWARF symbols to ELF symbols -- gcc sometimes optimizes functions
+ * and generate new symbols with suffixes such as .constprop.N or .isra.N
+ * etc. Since those symbols are not recorded in DWARF, we have to find
+ * correct generated symbols from offline ELF binary.
+ * For online kernel or uprobes we don't need this because those are
+ * rebased on _text, or already a section relative address.
+ */
+static int
+post_process_offline_probe_trace_events(struct probe_trace_event *tevs,
+ int ntevs, const char *pathname)
+{
+ struct map *map;
+ unsigned long stext = 0;
+ int i, ret = 0;
+
+ /* Prepare a map for offline binary */
+ map = dso__new_map(pathname);
+ if (!map || get_text_start_address(pathname, &stext) < 0) {
+ pr_warning("Failed to get ELF symbols for %s\n", pathname);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ntevs; i++) {
+ ret = post_process_probe_trace_point(&tevs[i].point,
+ map, stext);
+ if (ret < 0)
+ break;
+ }
+ map__put(map);
+
+ return ret;
+}
+
static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs,
int ntevs, const char *exec)
{
return ret;
}
-static int add_module_to_probe_trace_events(struct probe_trace_event *tevs,
- int ntevs, const char *module)
+static int
+post_process_module_probe_trace_events(struct probe_trace_event *tevs,
+ int ntevs, const char *module,
+ struct debuginfo *dinfo)
{
+ Dwarf_Addr text_offs = 0;
int i, ret = 0;
char *mod_name = NULL;
+ struct map *map;
if (!module)
return 0;
- mod_name = find_module_name(module);
+ map = get_target_map(module, false);
+ if (!map || debuginfo__get_text_offset(dinfo, &text_offs, true) < 0) {
+ pr_warning("Failed to get ELF symbols for %s\n", module);
+ return -EINVAL;
+ }
+ mod_name = find_module_name(module);
for (i = 0; i < ntevs; i++) {
+ ret = post_process_probe_trace_point(&tevs[i].point,
+ map, (unsigned long)text_offs);
+ if (ret < 0)
+ break;
tevs[i].point.module =
strdup(mod_name ? mod_name : module);
if (!tevs[i].point.module) {
}
free(mod_name);
+ map__put(map);
+
return ret;
}
/* Skip post process if the target is an offline kernel */
if (symbol_conf.ignore_vmlinux_buildid)
- return 0;
+ return post_process_offline_probe_trace_events(tevs, ntevs,
+ symbol_conf.vmlinux_name);
reloc_sym = kernel_get_ref_reloc_sym();
if (!reloc_sym) {
static int post_process_probe_trace_events(struct perf_probe_event *pev,
struct probe_trace_event *tevs,
int ntevs, const char *module,
- bool uprobe)
+ bool uprobe, struct debuginfo *dinfo)
{
int ret;
ret = add_exec_to_probe_trace_events(tevs, ntevs, module);
else if (module)
/* Currently ref_reloc_sym based probe is not for drivers */
- ret = add_module_to_probe_trace_events(tevs, ntevs, module);
+ ret = post_process_module_probe_trace_events(tevs, ntevs,
+ module, dinfo);
else
ret = post_process_kernel_probe_trace_events(tevs, ntevs);
}
}
- debuginfo__delete(dinfo);
-
if (ntevs > 0) { /* Succeeded to find trace events */
pr_debug("Found %d probe_trace_events.\n", ntevs);
ret = post_process_probe_trace_events(pev, *tevs, ntevs,
- pev->target, pev->uprobes);
+ pev->target, pev->uprobes, dinfo);
if (ret < 0 || ret == ntevs) {
+ pr_debug("Post processing failed or all events are skipped. (%d)\n", ret);
clear_probe_trace_events(*tevs, ntevs);
zfree(tevs);
+ ntevs = 0;
}
- if (ret != ntevs)
- return ret < 0 ? ret : ntevs;
- ntevs = 0;
- /* Fall through */
}
+ debuginfo__delete(dinfo);
+
if (ntevs == 0) { /* No error but failed to find probe point. */
pr_warning("Probe point '%s' not found.\n",
synthesize_perf_probe_point(&pev->point));
return -ENOENT;
- }
- /* Error path : ntevs < 0 */
- pr_debug("An error occurred in debuginfo analysis (%d).\n", ntevs);
- if (ntevs < 0) {
+ } else if (ntevs < 0) {
+ /* Error path : ntevs < 0 */
+ pr_debug("An error occurred in debuginfo analysis (%d).\n", ntevs);
if (ntevs == -EBADF)
pr_warning("Warning: No dwarf info found in the vmlinux - "
"please rebuild kernel with CONFIG_DEBUG_INFO=y.\n");
}
out:
- put_target_map(map, pev->uprobes);
+ map__put(map);
free(syms);
return ret;
return ret;
/* Get a symbol map */
- if (user)
- map = dso__new_map(target);
- else
- map = kernel_get_module_map(target);
+ map = get_target_map(target, user);
if (!map) {
pr_err("Failed to get a map for %s\n", (target) ? : "kernel");
return -EINVAL;
}
end:
- if (user) {
- map__put(map);
- }
+ map__put(map);
exit_probe_symbol_maps();
return ret;
}
/* For the kernel module, we need a special code to get a DIE */
-static int debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs)
+int debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs,
+ bool adjust_offset)
{
int n, i;
Elf32_Word shndx;
if (!shdr)
return -ENOENT;
*offs = shdr->sh_addr;
+ if (adjust_offset)
+ *offs -= shdr->sh_offset;
}
}
return 0;
Dwarf_Addr _addr = 0, baseaddr = 0;
const char *fname = NULL, *func = NULL, *basefunc = NULL, *tmp;
int baseline = 0, lineno = 0, ret = 0;
- bool reloc = false;
-retry:
+ /* We always need to relocate the address for aranges */
+ if (debuginfo__get_text_offset(dbg, &baseaddr, false) == 0)
+ addr += baseaddr;
/* Find cu die */
if (!dwarf_addrdie(dbg->dbg, (Dwarf_Addr)addr, &cudie)) {
- if (!reloc && debuginfo__get_text_offset(dbg, &baseaddr) == 0) {
- addr += baseaddr;
- reloc = true;
- goto retry;
- }
pr_warning("Failed to find debug information for address %lx\n",
addr);
ret = -EINVAL;
int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr,
struct perf_probe_point *ppt);
+int debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs,
+ bool adjust_offset);
+
/* Find a line range */
int debuginfo__find_line_range(struct debuginfo *dbg, struct line_range *lr);
break;
} else {
int n = namesz + descsz;
+
+ if (n > (int)sizeof(bf)) {
+ n = sizeof(bf);
+ pr_debug("%s: truncating reading of build id in sysfs file %s: n_namesz=%u, n_descsz=%u.\n",
+ __func__, filename, nhdr.n_namesz, nhdr.n_descsz);
+ }
if (read(fd, bf, n) != n)
break;
}
done;
@# Ask all targets to emit their test scripts
- echo "#!/bin/bash" > $(ALL_SCRIPT)
+ echo "#!/bin/sh" > $(ALL_SCRIPT)
echo "cd \$$(dirname \$$0)" >> $(ALL_SCRIPT)
echo "ROOT=\$$PWD" >> $(ALL_SCRIPT)
-#!/bin/bash
+#!/bin/sh
SRC_TREE=../../../../
return map_subset(lru_map, expected) && map_subset(expected, lru_map);
}
-static int sched_next_online(int pid, int next_to_try)
+static int sched_next_online(int pid, int *next_to_try)
{
cpu_set_t cpuset;
+ int next = *next_to_try;
+ int ret = -1;
- if (next_to_try == nr_cpus)
- return -1;
-
- while (next_to_try < nr_cpus) {
+ while (next < nr_cpus) {
CPU_ZERO(&cpuset);
- CPU_SET(next_to_try++, &cpuset);
- if (!sched_setaffinity(pid, sizeof(cpuset), &cpuset))
+ CPU_SET(next++, &cpuset);
+ if (!sched_setaffinity(pid, sizeof(cpuset), &cpuset)) {
+ ret = 0;
break;
+ }
}
- return next_to_try;
+ *next_to_try = next;
+ return ret;
}
/* Size of the LRU amp is 2
{
unsigned long long key, value[nr_cpus];
int lru_map_fd, expected_map_fd;
+ int next_cpu = 0;
printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
map_flags);
- assert(sched_next_online(0, 0) != -1);
+ assert(sched_next_online(0, &next_cpu) != -1);
if (map_flags & BPF_F_NO_COMMON_LRU)
lru_map_fd = create_map(map_type, map_flags, 2 * nr_cpus);
int lru_map_fd, expected_map_fd;
unsigned int batch_size;
unsigned int map_size;
+ int next_cpu = 0;
if (map_flags & BPF_F_NO_COMMON_LRU)
/* Ther percpu lru list (i.e each cpu has its own LRU
printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
map_flags);
- assert(sched_next_online(0, 0) != -1);
+ assert(sched_next_online(0, &next_cpu) != -1);
batch_size = tgt_free / 2;
assert(batch_size * 2 == tgt_free);
int lru_map_fd, expected_map_fd;
unsigned int batch_size;
unsigned int map_size;
+ int next_cpu = 0;
if (map_flags & BPF_F_NO_COMMON_LRU)
/* Ther percpu lru list (i.e each cpu has its own LRU
printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
map_flags);
- assert(sched_next_online(0, 0) != -1);
+ assert(sched_next_online(0, &next_cpu) != -1);
batch_size = tgt_free / 2;
assert(batch_size * 2 == tgt_free);
int lru_map_fd, expected_map_fd;
unsigned int batch_size;
unsigned int map_size;
+ int next_cpu = 0;
printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
map_flags);
- assert(sched_next_online(0, 0) != -1);
+ assert(sched_next_online(0, &next_cpu) != -1);
batch_size = tgt_free / 2;
assert(batch_size * 2 == tgt_free);
int lru_map_fd, expected_map_fd;
unsigned long long key, value[nr_cpus];
unsigned long long end_key;
+ int next_cpu = 0;
printf("%s (map_type:%d map_flags:0x%X): ", __func__, map_type,
map_flags);
- assert(sched_next_online(0, 0) != -1);
+ assert(sched_next_online(0, &next_cpu) != -1);
if (map_flags & BPF_F_NO_COMMON_LRU)
lru_map_fd = create_map(map_type, map_flags,
static void test_lru_sanity5(int map_type, int map_flags)
{
unsigned long long key, value[nr_cpus];
- int next_sched_cpu = 0;
+ int next_cpu = 0;
int map_fd;
- int i;
if (map_flags & BPF_F_NO_COMMON_LRU)
return;
key = 0;
assert(!bpf_map_update(map_fd, &key, value, BPF_NOEXIST));
- for (i = 0; i < nr_cpus; i++) {
+ while (sched_next_online(0, &next_cpu) != -1) {
pid_t pid;
pid = fork();
if (pid == 0) {
- next_sched_cpu = sched_next_online(0, next_sched_cpu);
- if (next_sched_cpu != -1)
- do_test_lru_sanity5(key, map_fd);
+ do_test_lru_sanity5(key, map_fd);
exit(0);
} else if (pid == -1) {
- printf("couldn't spawn #%d process\n", i);
+ printf("couldn't spawn process to test key:%llu\n",
+ key);
exit(1);
} else {
int status;
- /* It is mostly redundant and just allow the parent
- * process to update next_shced_cpu for the next child
- * process
- */
- next_sched_cpu = sched_next_online(pid, next_sched_cpu);
-
assert(waitpid(pid, &status, 0) == pid);
assert(status == 0);
key++;
}
close(map_fd);
+ /* At least one key should be tested */
+ assert(key > 0);
printf("Pass\n");
}
-#!/bin/bash
+#!/bin/sh
echo "--------------------"
echo "running socket test"
FAIL_IF(ebb_event_enable(&event));
- mtspr(SPRN_PMC1, pmc_sample_period(sample_period));
+ mtspr(SPRN_PMC2, pmc_sample_period(sample_period));
mtspr(SPRN_PMC5, 0);
mtspr(SPRN_PMC6, 0);
tracing_off();
close_test_fds();
- printf("test %2d PASSED (itertation %d)\n", test_nr, iteration_nr);
+ printf("test %2d PASSED (iteration %d)\n", test_nr, iteration_nr);
dprintf1("======================\n\n");
}
iteration_nr++;
#define VMEXIT_CYCLES 500
#define VMENTRY_CYCLES 500
+#elif defined(__s390x__)
+static inline void wait_cycles(unsigned long long cycles)
+{
+ asm volatile("0: brctg %0,0b" : : "d" (cycles));
+}
+
+/* tweak me */
+#define VMEXIT_CYCLES 200
+#define VMENTRY_CYCLES 200
+
#else
static inline void wait_cycles(unsigned long long cycles)
{
/* Is there a portable way to do this? */
#if defined(__x86_64__) || defined(__i386__)
#define cpu_relax() asm ("rep; nop" ::: "memory")
+#elif defined(__s390x__)
+#define cpu_relax() barrier()
#else
#define cpu_relax() assert(0)
#endif
#!/bin/sh
+CPUS_ONLINE=$(lscpu --online -p=cpu|grep -v -e '#')
#use last CPU for host. Why not the first?
#many devices tend to use cpu0 by default so
#it tends to be busier
-HOST_AFFINITY=$(lscpu -p=cpu | tail -1)
+HOST_AFFINITY=$(echo "${CPUS_ONLINE}"|tail -n 1)
#run command on all cpus
-for cpu in $(seq 0 $HOST_AFFINITY)
+for cpu in $CPUS_ONLINE
do
#Don't run guest and host on same CPU
#It actually works ok if using signalling
#include <clocksource/arm_arch_timer.h>
#include <asm/arch_timer.h>
+#include <asm/kvm_hyp.h>
#include <kvm/arm_vgic.h>
#include <kvm/arm_arch_timer.h>
struct kvm_vcpu *vcpu;
vcpu = container_of(work, struct kvm_vcpu, arch.timer_cpu.expired);
- vcpu->arch.timer_cpu.armed = false;
-
- WARN_ON(!kvm_timer_should_fire(vcpu));
/*
* If the vcpu is blocked we want to wake it up so that it will see
{
kvm->arch.timer.cntvoff = kvm_phys_timer_read();
}
+
+/*
+ * On VHE system, we only need to configure trap on physical timer and counter
+ * accesses in EL0 and EL1 once, not for every world switch.
+ * The host kernel runs at EL2 with HCR_EL2.TGE == 1,
+ * and this makes those bits have no effect for the host kernel execution.
+ */
+void kvm_timer_init_vhe(void)
+{
+ /* When HCR_EL2.E2H ==1, EL1PCEN and EL1PCTEN are shifted by 10 */
+ u32 cnthctl_shift = 10;
+ u64 val;
+
+ /*
+ * Disallow physical timer access for the guest.
+ * Physical counter access is allowed.
+ */
+ val = read_sysreg(cnthctl_el2);
+ val &= ~(CNTHCTL_EL1PCEN << cnthctl_shift);
+ val |= (CNTHCTL_EL1PCTEN << cnthctl_shift);
+ write_sysreg(val, cnthctl_el2);
+}
/* Disable the virtual timer */
write_sysreg_el0(0, cntv_ctl);
- /* Allow physical timer/counter access for the host */
- val = read_sysreg(cnthctl_el2);
- val |= CNTHCTL_EL1PCTEN | CNTHCTL_EL1PCEN;
- write_sysreg(val, cnthctl_el2);
+ /*
+ * We don't need to do this for VHE since the host kernel runs in EL2
+ * with HCR_EL2.TGE ==1, which makes those bits have no impact.
+ */
+ if (!has_vhe()) {
+ /* Allow physical timer/counter access for the host */
+ val = read_sysreg(cnthctl_el2);
+ val |= CNTHCTL_EL1PCTEN | CNTHCTL_EL1PCEN;
+ write_sysreg(val, cnthctl_el2);
+ }
/* Clear cntvoff for the host */
write_sysreg(0, cntvoff_el2);
struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
u64 val;
- /*
- * Disallow physical timer access for the guest
- * Physical counter access is allowed
- */
- val = read_sysreg(cnthctl_el2);
- val &= ~CNTHCTL_EL1PCEN;
- val |= CNTHCTL_EL1PCTEN;
- write_sysreg(val, cnthctl_el2);
+ /* Those bits are already configured at boot on VHE-system */
+ if (!has_vhe()) {
+ /*
+ * Disallow physical timer access for the guest
+ * Physical counter access is allowed
+ */
+ val = read_sysreg(cnthctl_el2);
+ val &= ~CNTHCTL_EL1PCEN;
+ val |= CNTHCTL_EL1PCTEN;
+ write_sysreg(val, cnthctl_el2);
+ }
if (timer->enabled) {
write_sysreg(kvm->arch.timer.cntvoff, cntvoff_el2);
{
struct vgic_dist *dist = &kvm->arch.vgic;
- mutex_lock(&kvm->lock);
-
dist->ready = false;
dist->initialized = false;
kfree(dist->spis);
dist->nr_spis = 0;
-
- mutex_unlock(&kvm->lock);
}
void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
INIT_LIST_HEAD(&vgic_cpu->ap_list_head);
}
-void kvm_vgic_destroy(struct kvm *kvm)
+/* To be called with kvm->lock held */
+static void __kvm_vgic_destroy(struct kvm *kvm)
{
struct kvm_vcpu *vcpu;
int i;
kvm_vgic_vcpu_destroy(vcpu);
}
+void kvm_vgic_destroy(struct kvm *kvm)
+{
+ mutex_lock(&kvm->lock);
+ __kvm_vgic_destroy(kvm);
+ mutex_unlock(&kvm->lock);
+}
+
/**
* vgic_lazy_init: Lazy init is only allowed if the GIC exposed to the guest
* is a GICv2. A GICv3 must be explicitly initialized by the guest using the
ret = vgic_v2_map_resources(kvm);
else
ret = vgic_v3_map_resources(kvm);
+
+ if (ret)
+ __kvm_vgic_destroy(kvm);
+
out:
mutex_unlock(&kvm->lock);
return ret;
dist->ready = true;
out:
- if (ret)
- kvm_vgic_destroy(kvm);
return ret;
}
dist->ready = true;
out:
- if (ret)
- kvm_vgic_destroy(kvm);
return ret;
}
mutex_lock(&lock);
list_for_each_entry(tmp, &consumers, node) {
- if (tmp->token == consumer->token) {
+ if (tmp->token == consumer->token || tmp == consumer) {
mutex_unlock(&lock);
module_put(THIS_MODULE);
return -EBUSY;
mutex_lock(&lock);
list_for_each_entry(tmp, &consumers, node) {
- if (tmp->token != consumer->token)
+ if (tmp != consumer)
continue;
list_for_each_entry(producer, &producers, node) {