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

Pull char/misc/IIO driver updates from Greg KH:
 "Here is the big set of char/misc/iio driver updates for 6.19-rc1. Lots
  of stuff in here including:

   - lots of IIO driver updates, cleanups, and additions

   - large interconnect driver changes as they get converted over to a
     dynamic system of ids

   - coresight driver updates

   - mwave driver updates

   - binder driver updates and changes

   - comedi driver fixes now that the fuzzers are being set loose on
     them

   - nvmem driver updates

   - new uio driver addition

   - lots of other small char/misc driver updates, full details in the
     shortlog

  All of these have been in linux-next for a while now"

* tag 'char-misc-6.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (304 commits)
  char: applicom: fix NULL pointer dereference in ac_ioctl
  hangcheck-timer: fix coding style spacing
  hangcheck-timer: Replace %Ld with %lld
  hangcheck-timer: replace printk(KERN_CRIT) with pr_crit
  uio: Add SVA support for PCI devices via uio_pci_generic_sva.c
  dt-bindings: slimbus: fix warning from example
  intel_th: Fix error handling in intel_th_output_open
  misc: rp1: Fix an error handling path in rp1_probe()
  char: xillybus: add WQ_UNBOUND to alloc_workqueue users
  misc: bh1770glc: use pm_runtime_resume_and_get() in power_state_store
  misc: cb710: Fix a NULL vs IS_ERR() check in probe()
  mux: mmio: Add suspend and resume support
  virt: acrn: split acrn_mmio_dev_res out of acrn_mmiodev
  greybus: gb-beagleplay: Fix timeout handling in bootloader functions
  greybus: add WQ_PERCPU to alloc_workqueue users
  char/mwave: drop typedefs
  char/mwave: drop printk wrapper
  char/mwave: remove printk tracing
  char/mwave: remove unneeded fops
  char/mwave: remove MWAVE_FUTZ_WITH_OTHER_DEVICES ifdeffery
  ...
This commit is contained in:
Linus Torvalds
2025-12-06 18:34:24 -08:00
302 changed files with 23678 additions and 14098 deletions

View File

@@ -898,6 +898,7 @@ What: /sys/.../iio:deviceX/events/in_tempY_thresh_rising_en
What: /sys/.../iio:deviceX/events/in_tempY_thresh_falling_en
What: /sys/.../iio:deviceX/events/in_capacitanceY_thresh_rising_en
What: /sys/.../iio:deviceX/events/in_capacitanceY_thresh_falling_en
What: /sys/.../iio:deviceX/events/in_pressure_thresh_rising_en
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
@@ -926,6 +927,7 @@ What: /sys/.../iio:deviceX/events/in_accel_y_roc_rising_en
What: /sys/.../iio:deviceX/events/in_accel_y_roc_falling_en
What: /sys/.../iio:deviceX/events/in_accel_z_roc_rising_en
What: /sys/.../iio:deviceX/events/in_accel_z_roc_falling_en
What: /sys/.../iio:deviceX/events/in_accel_x&y&z_roc_rising_en
What: /sys/.../iio:deviceX/events/in_anglvel_x_roc_rising_en
What: /sys/.../iio:deviceX/events/in_anglvel_x_roc_falling_en
What: /sys/.../iio:deviceX/events/in_anglvel_y_roc_rising_en
@@ -1001,6 +1003,7 @@ Description:
to the raw signal, allowing slow tracking to resume and the
adaptive threshold event detection to function as expected.
What: /sys/.../events/in_accel_mag_adaptive_rising_value
What: /sys/.../events/in_accel_thresh_rising_value
What: /sys/.../events/in_accel_thresh_falling_value
What: /sys/.../events/in_accel_x_raw_thresh_rising_value
@@ -1045,6 +1048,7 @@ What: /sys/.../events/in_capacitanceY_thresh_rising_value
What: /sys/.../events/in_capacitanceY_thresh_falling_value
What: /sys/.../events/in_capacitanceY_thresh_adaptive_rising_value
What: /sys/.../events/in_capacitanceY_thresh_falling_rising_value
What: /sys/.../events/in_pressure_thresh_rising_value
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
@@ -1147,6 +1151,7 @@ Description:
will get activated once in_voltage0_raw goes above 1200 and will become
deactivated again once the value falls below 1150.
What: /sys/.../events/in_accel_roc_rising_value
What: /sys/.../events/in_accel_x_raw_roc_rising_value
What: /sys/.../events/in_accel_x_raw_roc_falling_value
What: /sys/.../events/in_accel_y_raw_roc_rising_value
@@ -1193,6 +1198,8 @@ Description:
value is in raw device units or in processed units (as _raw
and _input do on sysfs direct channel read attributes).
What: /sys/.../events/in_accel_mag_adaptive_rising_period
What: /sys/.../events/in_accel_roc_rising_period
What: /sys/.../events/in_accel_x_thresh_rising_period
What: /sys/.../events/in_accel_x_thresh_falling_period
What: /sys/.../events/in_accel_x_roc_rising_period
@@ -1362,6 +1369,15 @@ Description:
number or direction is not specified, applies to all channels of
this type.
What: /sys/.../iio:deviceX/events/in_accel_x_mag_adaptive_rising_en
What: /sys/.../iio:deviceX/events/in_accel_y_mag_adaptive_rising_en
What: /sys/.../iio:deviceX/events/in_accel_z_mag_adaptive_rising_en
KernelVersion: 2.6.37
Contact: linux-iio@vger.kernel.org
Description:
Similar to in_accel_x_thresh[_rising|_falling]_en, but here the
magnitude of the channel is compared to the adaptive threshold.
What: /sys/.../iio:deviceX/events/in_accel_mag_referenced_en
What: /sys/.../iio:deviceX/events/in_accel_mag_referenced_rising_en
What: /sys/.../iio:deviceX/events/in_accel_mag_referenced_falling_en
@@ -2422,3 +2438,23 @@ Description:
Value representing the user's attention to the system expressed
in units as percentage. This usually means if the user is
looking at the screen or not.
What: /sys/.../events/in_accel_value_available
KernelVersion: 6.18
Contact: linux-iio@vger.kernel.org
Description:
List of available threshold values for acceleration event
generation. Applies to all event types on in_accel channels.
Units after application of scale and offset are m/s^2.
Expressed as:
- a range specified as "[min step max]"
What: /sys/.../events/in_accel_period_available
KernelVersion: 6.18
Contact: linux-iio@vger.kernel.org
Description:
List of available periods for accelerometer event detection in
seconds, expressed as:
- a range specified as "[min step max]"

View File

@@ -0,0 +1,29 @@
What: /sys/bus/pci/drivers/uio_pci_sva/<pci_dev>/pasid
Date: September 2025
Contact: Yaxing Guo <guoyaxing@bosc.ac.cn>
Description:
Process Address Space ID (PASID) assigned by IOMMU driver to
the device for use with Shared Virtual Addressing (SVA).
This read-only attribute exposes the PASID (A 20-bit identifier
used in PCIe Address Translation Services and iommu table walks)
allocated by the IOMMU driver during sva device binding.
User-space UIO applications must read this attribute to obtain
the PASID and program it into the device's configuration registers.
This enables the device to perform DMA using user-space virtual
address, with address translation handled by IOMMU.
UIO User-space applications must:
- Opening device and Mapping the device's register space via /dev/uioX
(This triggers the IOMMU driver to allocate the PASID)
- Reading the PASID from sysfs
- Writing the PASID to a device-specific register (with example offset)
The code may be like:
map = mmap(..., "/dev/uio0", ...);
f = fopen("/sys/.../pasid", "r");
fscanf(f, "%d", &pasid);
map[REG_PASID_OFFSET] = pasid;

View File

@@ -36,9 +36,12 @@ properties:
$nodename:
pattern: "^tpdm(@[0-9a-f]+)$"
compatible:
items:
- const: qcom,coresight-tpdm
- const: arm,primecell
oneOf:
- items:
- const: qcom,coresight-static-tpdm
- items:
- const: qcom,coresight-tpdm
- const: arm,primecell
reg:
maxItems: 1
@@ -147,4 +150,18 @@ examples:
};
};
};
turing-llm-tpdm {
compatible = "qcom,coresight-static-tpdm";
qcom,cmb-element-bits = <32>;
out-ports {
port {
turing_llm_tpdm_out: endpoint {
remote-endpoint = <&turing0_funnel_in1>;
};
};
};
};
...

View File

@@ -210,9 +210,9 @@ description: |
FPGA Bridges that exist on the FPGA fabric prior to the partial reconfiguration.
--
[1] www.altera.com/content/dam/altera-www/global/en_US/pdfs/literature/ug/ug_partrecon.pdf
[1] https://www.intel.com/programmable/technical-pdfs/683404.pdf
[2] tspace.library.utoronto.ca/bitstream/1807/67932/1/Byma_Stuart_A_201411_MAS_thesis.pdf
[3] https://www.xilinx.com/support/documentation/sw_manuals/xilinx14_1/ug702.pdf
[3] https://docs.amd.com/v/u/en-US/ug702
properties:
$nodename:

View File

@@ -35,15 +35,17 @@ properties:
spi-3wire: true
interrupts:
maxItems: 1
minItems: 1
maxItems: 2
interrupt-names:
minItems: 1
items:
- enum: [INT1, INT2]
- const: INT2
dependencies:
interrupts: [ interrupt-names ]
interrupt-names: [ interrupts ]
required:
- compatible
@@ -84,7 +86,8 @@ examples:
spi-cpol;
spi-cpha;
interrupt-parent = <&gpio0>;
interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "INT2";
interrupts = <0 IRQ_TYPE_LEVEL_HIGH>,
<1 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "INT1", "INT2";
};
};

View File

@@ -11,16 +11,19 @@ maintainers:
- Antoniu Miclaus <antoniu.miclaus@analog.com>
description: |
The ADXL380/ADXL382 is a low noise density, low power, 3-axis
accelerometer with selectable measurement ranges. The ADXL380
supports the ±4 g, ±8 g, and ±16 g ranges, and the ADXL382 supports
±15 g, ±30 g, and ±60 g ranges.
The ADXL380/ADXL382 and ADXL318/ADXL319 are low noise density,
low power, 3-axis accelerometers with selectable measurement ranges.
The ADXL380 and ADXL318 support the ±4 g, ±8 g, and ±16 g ranges,
while the ADXL382 and ADXL319 support ±15 g, ±30 g, and ±60 g ranges.
https://www.analog.com/en/products/adxl318.html
https://www.analog.com/en/products/adxl380.html
properties:
compatible:
enum:
- adi,adxl318
- adi,adxl319
- adi,adxl380
- adi,adxl382

View File

@@ -4,7 +4,7 @@
$id: http://devicetree.org/schemas/iio/accel/bosch,bma220.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Bosch BMA220 Trixial Acceleration Sensor
title: Bosch BMA220 Triaxial Acceleration Sensor
maintainers:
- Jonathan Cameron <Jonathan.Cameron@huawei.com>
@@ -20,6 +20,9 @@ properties:
interrupts:
maxItems: 1
spi-cpha: true
spi-cpol: true
vdda-supply: true
vddd-supply: true
vddio-supply: true
@@ -44,8 +47,10 @@ examples:
compatible = "bosch,bma220";
reg = <0>;
spi-max-frequency = <2500000>;
spi-cpol;
spi-cpha;
interrupt-parent = <&gpio0>;
interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
interrupts = <0 IRQ_TYPE_EDGE_RISING>;
};
};
...

View File

@@ -26,6 +26,11 @@ properties:
compatible:
enum:
- adi,ad4080
- adi,ad4081
- adi,ad4083
- adi,ad4084
- adi,ad4086
- adi,ad4087
reg:
maxItems: 1

View File

@@ -0,0 +1,89 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
# Copyright 2023-2025 Analog Devices Inc.
# Copyright 2023 Kim Seer Paller
# Copyright 2025 Marilene Andrade Garcia
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/adc/adi,max14001.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices MAX14001-MAX14002 ADC
maintainers:
- Kim Seer Paller <kimseer.paller@analog.com>
- Marilene Andrade Garcia <marilene.agarcia@gmail.com>
description: |
Single channel 10 bit ADC with SPI interface.
Datasheet can be found here
https://www.analog.com/media/en/technical-documentation/data-sheets/MAX14001-MAX14002.pdf
$ref: /schemas/spi/spi-peripheral-props.yaml#
properties:
compatible:
oneOf:
- const: adi,max14002
- items:
- const: adi,max14001
- const: adi,max14002
reg:
maxItems: 1
spi-max-frequency:
maximum: 5000000
vdd-supply:
description:
Isolated DC-DC power supply input voltage.
vddl-supply:
description:
Logic power supply.
refin-supply:
description:
ADC voltage reference supply.
interrupts:
minItems: 1
items:
- description: |
cout: comparator output signal that asserts high on the COUT pin
when ADC readings exceed the upper threshold and low when readings
fall below the lower threshold.
- description: |
fault: when fault reporting is enabled, the FAULT pin is asserted
low whenever one of the monitored fault conditions occurs.
interrupt-names:
minItems: 1
items:
- const: cout
- const: fault
required:
- compatible
- reg
- vdd-supply
- vddl-supply
unevaluatedProperties: false
examples:
- |
spi {
#address-cells = <1>;
#size-cells = <0>;
adc@0 {
compatible = "adi,max14001", "adi,max14002";
reg = <0>;
spi-max-frequency = <5000000>;
spi-lsb-first;
vdd-supply = <&vdd>;
vddl-supply = <&vddl>;
};
};
...

View File

@@ -29,6 +29,8 @@ properties:
enum:
- aspeed,ast2600-adc0
- aspeed,ast2600-adc1
- aspeed,ast2700-adc0
- aspeed,ast2700-adc1
description:
Their trimming data, which is used to calibrate internal reference volage,
locates in different address of OTP.

View File

@@ -42,6 +42,7 @@ properties:
- mediatek,mt8183-auxadc
- mediatek,mt8186-auxadc
- mediatek,mt8188-auxadc
- mediatek,mt8189-auxadc
- mediatek,mt8195-auxadc
- mediatek,mt8516-auxadc
- const: mediatek,mt8173-auxadc

View File

@@ -0,0 +1,135 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/adc/renesas,r9a09g077-adc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Renesas RZ/T2H / RZ/N2H ADC12
maintainers:
- Cosmin Tanislav <cosmin-gabriel.tanislav.xa@renesas.com>
description: |
A/D Converter block is a successive approximation analog-to-digital converter
with a 12-bit accuracy. Up to 16 analog input channels can be selected.
Conversions can be performed in single or continuous mode. Result of the ADC
is stored in a 16-bit data register corresponding to each channel.
properties:
compatible:
oneOf:
- items:
- const: renesas,r9a09g087-adc # RZ/N2H
- const: renesas,r9a09g077-adc # RZ/T2H
- items:
- const: renesas,r9a09g077-adc # RZ/T2H
reg:
maxItems: 1
interrupts:
items:
- description: A/D scan end interrupt
- description: A/D scan end interrupt for Group B
- description: A/D scan end interrupt for Group C
- description: Window A compare match
- description: Window B compare match
- description: Compare match
- description: Compare mismatch
interrupt-names:
items:
- const: adi
- const: gbadi
- const: gcadi
- const: cmpai
- const: cmpbi
- const: wcmpm
- const: wcmpum
clocks:
items:
- description: Converter clock
- description: Peripheral clock
clock-names:
items:
- const: adclk
- const: pclk
power-domains:
maxItems: 1
'#address-cells':
const: 1
'#size-cells':
const: 0
"#io-channel-cells":
const: 1
patternProperties:
"^channel@[0-9a-f]$":
$ref: adc.yaml
type: object
description: The external channels which are connected to the ADC.
properties:
reg:
description: The channel number.
maximum: 15
required:
- reg
additionalProperties: false
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
- power-domains
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/renesas,r9a09g077-cpg-mssr.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
adc@80008000 {
compatible = "renesas,r9a09g077-adc";
reg = <0x80008000 0x400>;
interrupts = <GIC_SPI 708 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 709 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 710 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 711 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 712 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 855 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 856 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "adi", "gbadi", "gcadi",
"cmpai", "cmpbi", "wcmpm", "wcmpum";
clocks = <&cpg CPG_CORE R9A09G077_CLK_PCLKL>,
<&cpg CPG_MOD 225>;
clock-names = "adclk", "pclk";
power-domains = <&cpg>;
#address-cells = <1>;
#size-cells = <0>;
#io-channel-cells = <1>;
channel@0 {
reg = <0x0>;
};
channel@1 {
reg = <0x1>;
};
channel@2 {
reg = <0x2>;
};
channel@3 {
reg = <0x3>;
};
};

View File

@@ -0,0 +1,111 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/adc/renesas,rzn1-adc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Renesas RZ/N1 Analog to Digital Converter (ADC)
maintainers:
- Herve Codina <herve.codina@bootlin.com>
description:
The Renesas RZ/N1 ADC controller available in the Renesas RZ/N1 SoCs family
can use up to two internal ADC cores (ADC1 and ADC2) those internal cores are
handled through ADC controller virtual channels.
properties:
compatible:
items:
- const: renesas,r9a06g032-adc # RZ/N1D
- const: renesas,rzn1-adc
reg:
maxItems: 1
clocks:
items:
- description: APB internal bus clock
- description: ADC clock
clock-names:
items:
- const: pclk
- const: adc
power-domains:
maxItems: 1
adc1-avdd-supply:
description:
ADC1 analog power supply.
adc1-vref-supply:
description:
ADC1 reference voltage supply.
adc2-avdd-supply:
description:
ADC2 analog power supply.
adc2-vref-supply:
description:
ADC2 reference voltage supply.
'#io-channel-cells':
const: 1
description: |
Channels numbers available:
if ADC1 is used (i.e. adc1-{avdd,vref}-supply present):
- 0: ADC1 IN0
- 1: ADC1 IN1
- 2: ADC1 IN2
- 3: ADC1 IN3
- 4: ADC1 IN4
- 5: ADC1 IN6
- 6: ADC1 IN7
- 7: ADC1 IN8
if ADC2 is used (i.e. adc2-{avdd,vref}-supply present):
- 8: ADC2 IN0
- 9: ADC2 IN1
- 10: ADC2 IN2
- 11: ADC2 IN3
- 12: ADC2 IN4
- 13: ADC2 IN6
- 14: ADC2 IN7
- 15: ADC2 IN8
required:
- compatible
- reg
- clocks
- clock-names
- power-domains
- '#io-channel-cells'
# At least one of avvd/vref supplies
anyOf:
- required:
- adc1-vref-supply
- adc1-avdd-supply
- required:
- adc2-vref-supply
- adc2-avdd-supply
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/r9a06g032-sysctrl.h>
adc: adc@40065000 {
compatible = "renesas,r9a06g032-adc", "renesas,rzn1-adc";
reg = <0x40065000 0x200>;
clocks = <&sysctrl R9A06G032_HCLK_ADC>, <&sysctrl R9A06G032_CLK_ADC>;
clock-names = "pclk", "adc";
power-domains = <&sysctrl>;
adc1-avdd-supply = <&adc1_avdd>;
adc1-vref-supply = <&adc1_vref>;
#io-channel-cells = <1>;
};
...

View File

@@ -16,6 +16,9 @@ properties:
- const: rockchip,rk3066-tsadc
- const: rockchip,rk3399-saradc
- const: rockchip,rk3528-saradc
- items:
- const: rockchip,rk3506-saradc
- const: rockchip,rk3528-saradc
- const: rockchip,rk3562-saradc
- const: rockchip,rk3588-saradc
- items:

View File

@@ -0,0 +1,138 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/dac/adi,ad5446.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices AD5446 and similar DACs
maintainers:
- Michael Hennerich <michael.hennerich@analog.com>
- Nuno Sá <nuno.sa@analog.com>
description:
Digital to Analog Converter devices supporting both SPI and I2C interfaces.
These devices feature a range of resolutions from 8-bit to 16-bit.
properties:
compatible:
oneOf:
- description: SPI DACs
enum:
- adi,ad5300
- adi,ad5310
- adi,ad5320
- adi,ad5444
- adi,ad5446
- adi,ad5450
- adi,ad5451
- adi,ad5452
- adi,ad5453
- adi,ad5512a
- adi,ad5541a
- adi,ad5542
- adi,ad5542a
- adi,ad5543
- adi,ad5553
- adi,ad5600
- adi,ad5601
- adi,ad5611
- adi,ad5621
- adi,ad5641
- adi,ad5620-2500
- adi,ad5620-1250
- adi,ad5640-2500
- adi,ad5640-1250
- adi,ad5660-2500
- adi,ad5660-1250
- adi,ad5662
- ti,dac081s101
- ti,dac101s101
- ti,dac121s101
- description: I2C DACs
enum:
- adi,ad5301
- adi,ad5311
- adi,ad5321
- adi,ad5602
- adi,ad5612
- adi,ad5622
reg:
maxItems: 1
vcc-supply:
description:
Reference voltage supply. If not supplied, devices with internal
voltage reference will use that.
required:
- compatible
- reg
allOf:
- if:
properties:
compatible:
contains:
enum:
- adi,ad5300
- adi,ad5310
- adi,ad5320
- adi,ad5444
- adi,ad5446
- adi,ad5450
- adi,ad5451
- adi,ad5452
- adi,ad5453
- adi,ad5512a
- adi,ad5541a
- adi,ad5542
- adi,ad5542a
- adi,ad5543
- adi,ad5553
- adi,ad5600
- adi,ad5601
- adi,ad5611
- adi,ad5621
- adi,ad5641
- adi,ad5620-2500
- adi,ad5620-1250
- adi,ad5640-2500
- adi,ad5640-1250
- adi,ad5660-2500
- adi,ad5660-1250
- adi,ad5662
- ti,dac081s101
- ti,dac101s101
- ti,dac121s101
then:
allOf:
- $ref: /schemas/spi/spi-peripheral-props.yaml#
unevaluatedProperties: false
examples:
- |
spi {
#address-cells = <1>;
#size-cells = <0>;
dac@0 {
compatible = "adi,ad5446";
reg = <0>;
vcc-supply = <&dac_vref>;
};
};
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
dac@42 {
compatible = "adi,ad5622";
reg = <0x42>;
vcc-supply = <&dac_vref>;
};
};
...

View File

@@ -27,6 +27,14 @@ properties:
LED current whilst the engine is running. First indexed value is
the configuration for the RED LED, and second value is for the IR LED.
maxim,pulse-width-us:
description: |
LED pulse width in microseconds. Appropriate pulse width depends on
factors such as optical window absorption, LED-to-sensor distance,
and expected reflectivity of the skin or contact surface.
enum: [200, 400, 800, 1600]
default: 1600
additionalProperties: false
required:

View File

@@ -0,0 +1,90 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/imu/bosch,smi330.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Bosch SMI330 6-Axis IMU
maintainers:
- Stefan Gutmann <stefam.gutmann@de.bosch.com>
description:
SMI330 is a 6-axis inertial measurement unit that supports acceleration and
gyroscopic measurements with hardware fifo buffering. Sensor also provides
events information such as motion, no-motion and tilt detection.
properties:
compatible:
const: bosch,smi330
reg:
maxItems: 1
vdd-supply:
description: provide VDD power to the sensor.
vddio-supply:
description: provide VDD IO power to the sensor.
interrupts:
minItems: 1
maxItems: 2
interrupt-names:
minItems: 1
maxItems: 2
items:
enum:
- INT1
- INT2
drive-open-drain:
type: boolean
description:
set if the interrupt pin(s) should be configured as
open drain. If not set, defaults to push-pull.
required:
- compatible
- reg
allOf:
- $ref: /schemas/spi/spi-peripheral-props.yaml#
unevaluatedProperties: false
examples:
- |
// Example for I2C
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
imu@68 {
compatible = "bosch,smi330";
reg = <0x68>;
vddio-supply = <&vddio>;
vdd-supply = <&vdd>;
interrupt-parent = <&gpio>;
interrupts = <26 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "INT1";
};
};
// Example for SPI
#include <dt-bindings/interrupt-controller/irq.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
imu@0 {
compatible = "bosch,smi330";
reg = <0>;
spi-max-frequency = <10000000>;
interrupt-parent = <&gpio>;
interrupts = <26 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "INT1";
};
};

View File

@@ -0,0 +1,90 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/imu/invensense,icm45600.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: InvenSense ICM-45600 Inertial Measurement Unit
maintainers:
- Remi Buisson <remi.buisson@tdk.com>
description: |
6-axis MotionTracking device that combines a 3-axis gyroscope and a 3-axis
accelerometer.
It has a configurable host interface that supports I3C, I2C and SPI serial
communication, features up to 8kB FIFO and 2 programmable interrupts with
ultra-low-power wake-on-motion support to minimize system power consumption.
Other industry-leading features include InvenSense on-chip APEX Motion
Processing engine for gesture recognition, activity classification, and
pedometer, along with programmable digital filters, and an embedded
temperature sensor.
https://invensense.tdk.com/wp-content/uploads/documentation/DS-000576_ICM-45605.pdf
properties:
compatible:
enum:
- invensense,icm45605
- invensense,icm45606
- invensense,icm45608
- invensense,icm45634
- invensense,icm45686
- invensense,icm45687
- invensense,icm45688p
- invensense,icm45689
reg:
maxItems: 1
interrupts:
minItems: 1
maxItems: 2
interrupt-names:
minItems: 1
items:
- enum: [int1, int2]
- const: int2
description: Choose chip interrupt pin to be used as interrupt input.
drive-open-drain:
type: boolean
vdd-supply: true
vddio-supply: true
mount-matrix: true
required:
- compatible
- reg
- vdd-supply
- vddio-supply
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
imu@68 {
compatible = "invensense,icm45605";
reg = <0x68>;
interrupt-parent = <&gpio2>;
interrupt-names = "int1";
interrupts = <7 IRQ_TYPE_EDGE_RISING>;
vdd-supply = <&vdd>;
vddio-supply = <&vddio>;
mount-matrix = "0", "-1", "0",
"1", "0", "0",
"0", "0", "1";
};
};

View File

@@ -86,7 +86,6 @@ unevaluatedProperties: false
required:
- compatible
- reg
- interrupts
examples:
- |

View File

@@ -0,0 +1,45 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/pressure/aosong,adp810.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: aosong adp810 differential pressure sensor
maintainers:
- Akhilesh Patil <akhilesh@ee.iitb.ac.in>
description:
ADP810 is differential pressure and temperature sensor. It has I2C bus
interface with fixed address of 0x25. This sensor supports 8 bit CRC for
reliable data transfer. It can measure differential pressure in the
range -500 to 500Pa and temperate in the range -40 to +85 degree celsius.
properties:
compatible:
enum:
- aosong,adp810
reg:
maxItems: 1
vdd-supply: true
required:
- compatible
- reg
- vdd-supply
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
pressure-sensor@25 {
compatible = "aosong,adp810";
reg = <0x25>;
vdd-supply = <&vdd_regulator>;
};
};

View File

@@ -0,0 +1,71 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/pressure/fsl,mpl3115.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MPL3115 precision pressure sensor with altimetry
maintainers:
- Antoni Pokusinski <apokusinski01@gmail.com>
description: |
MPL3115 is a pressure/altitude and temperature sensor with I2C interface.
It features two programmable interrupt lines which indicate events such as
data ready or pressure/temperature threshold reached.
https://www.nxp.com/docs/en/data-sheet/MPL3115A2.pdf
properties:
compatible:
const: fsl,mpl3115
reg:
maxItems: 1
vdd-supply: true
vddio-supply: true
interrupts:
minItems: 1
maxItems: 2
interrupt-names:
minItems: 1
maxItems: 2
items:
enum:
- INT1
- INT2
drive-open-drain:
type: boolean
description:
set if the specified interrupt pins should be configured as
open drain. If not set, defaults to push-pull.
required:
- compatible
- reg
- vdd-supply
- vddio-supply
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
pressure@60 {
compatible = "fsl,mpl3115";
reg = <0x60>;
vdd-supply = <&vdd>;
vddio-supply = <&vddio>;
interrupt-parent = <&gpio1>;
interrupts = <4 IRQ_TYPE_EDGE_FALLING>;
interrupt-names = "INT2";
};
};

View File

@@ -0,0 +1,54 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/iio/pressure/infineon,dps310.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Infineon DPS310 barometric pressure and temperature sensor
maintainers:
- Eddie James <eajames@linux.ibm.com>
description:
The DPS310 is a barometric pressure and temperature sensor with an I2C
interface.
properties:
compatible:
enum:
- infineon,dps310
reg:
maxItems: 1
"#io-channel-cells":
const: 0
vdd-supply:
description:
Voltage supply for the chip's analog blocks.
vddio-supply:
description:
Digital voltage supply for the chip's digital blocks and I/O interface.
required:
- compatible
- reg
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
dps: pressure-sensor@76 {
compatible = "infineon,dps310";
reg = <0x76>;
#io-channel-cells = <0>;
vdd-supply = <&vref1>;
vddio-supply = <&vref2>;
};
};

View File

@@ -0,0 +1,124 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/interconnect/qcom,kaanapali-rpmh.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm RPMh Network-On-Chip Interconnect on Kaanapali
maintainers:
- Raviteja Laggyshetty <raviteja.laggyshetty@oss.qualcomm.com>
description: |
RPMh interconnect providers support system bandwidth requirements through
RPMh hardware accelerators known as Bus Clock Manager (BCM). The provider is
able to communicate with the BCM through the Resource State Coordinator (RSC)
associated with each execution environment. Provider nodes must point to at
least one RPMh device child node pertaining to their RSC and each provider
can map to multiple RPMh resources.
See also: include/dt-bindings/interconnect/qcom,kaanapali-rpmh.h
properties:
compatible:
enum:
- qcom,kaanapali-aggre-noc
- qcom,kaanapali-clk-virt
- qcom,kaanapali-cnoc-main
- qcom,kaanapali-cnoc-cfg
- qcom,kaanapali-gem-noc
- qcom,kaanapali-lpass-ag-noc
- qcom,kaanapali-lpass-lpiaon-noc
- qcom,kaanapali-lpass-lpicx-noc
- qcom,kaanapali-mc-virt
- qcom,kaanapali-mmss-noc
- qcom,kaanapali-nsp-noc
- qcom,kaanapali-pcie-anoc
- qcom,kaanapali-system-noc
reg:
maxItems: 1
clocks:
minItems: 2
maxItems: 3
required:
- compatible
allOf:
- $ref: qcom,rpmh-common.yaml#
- if:
properties:
compatible:
contains:
enum:
- qcom,kaanapali-clk-virt
- qcom,kaanapali-mc-virt
then:
properties:
reg: false
else:
required:
- reg
- if:
properties:
compatible:
contains:
enum:
- qcom,kaanapali-pcie-anoc
then:
properties:
clocks:
items:
- description: aggre-NOC PCIe AXI clock
- description: cfg-NOC PCIe a-NOC AHB clock
- if:
properties:
compatible:
contains:
enum:
- qcom,kaanapali-aggre-noc
then:
properties:
clocks:
items:
- description: aggre UFS PHY AXI clock
- description: aggre USB3 PRIM AXI clock
- description: RPMH CC IPA clock
- if:
properties:
compatible:
contains:
enum:
- qcom,kaanapali-aggre-noc
- qcom,kaanapali-pcie-anoc
then:
required:
- clocks
else:
properties:
clocks: false
unevaluatedProperties: false
examples:
- |
clk_virt: interconnect-0 {
compatible = "qcom,kaanapali-clk-virt";
#interconnect-cells = <2>;
qcom,bcm-voters = <&apps_bcm_voter>;
};
aggre_noc: interconnect@16e0000 {
compatible = "qcom,kaanapali-aggre-noc";
reg = <0x016e0000 0x42400>;
#interconnect-cells = <2>;
clocks = <&gcc_aggre_ufs_phy_axi_clk>,
<&gcc_aggre_usb3_prim_axi_clk>,
<&rpmhcc_ipa_clk>;
qcom,bcm-voters = <&apps_bcm_voter>;
};

View File

@@ -25,6 +25,7 @@ properties:
- const: qcom,msm8998-bwmon # BWMON v4
- items:
- enum:
- qcom,kaanapali-cpu-bwmon
- qcom,qcm2290-cpu-bwmon
- qcom,qcs615-cpu-bwmon
- qcom,qcs8300-cpu-bwmon

View File

@@ -33,18 +33,66 @@ properties:
- qcom,sa8775p-pcie-anoc
- qcom,sa8775p-system-noc
reg:
maxItems: 1
clocks:
minItems: 2
maxItems: 5
required:
- compatible
allOf:
- $ref: qcom,rpmh-common.yaml#
- if:
properties:
compatible:
contains:
enum:
- qcom,sa8775p-aggre1-noc
then:
properties:
clocks:
items:
- description: aggre UFS PHY AXI clock
- description: aggre QUP PRIM AXI clock
- description: aggre USB2 PRIM AXI clock
- description: aggre USB3 PRIM AXI clock
- description: aggre USB3 SEC AXI clock
- if:
properties:
compatible:
contains:
enum:
- qcom,sa8775p-aggre2-noc
then:
properties:
clocks:
items:
- description: aggre UFS CARD AXI clock
- description: RPMH CC IPA clock
unevaluatedProperties: false
examples:
- |
aggre1_noc: interconnect-aggre1-noc {
compatible = "qcom,sa8775p-aggre1-noc";
#include <dt-bindings/clock/qcom,sa8775p-gcc.h>
clk_virt: interconnect-clk-virt {
compatible = "qcom,sa8775p-clk-virt";
#interconnect-cells = <2>;
qcom,bcm-voters = <&apps_bcm_voter>;
};
aggre1_noc: interconnect@16c0000 {
compatible = "qcom,sa8775p-aggre1-noc";
reg = <0x016c0000 0x18080>;
#interconnect-cells = <2>;
qcom,bcm-voters = <&apps_bcm_voter>;
clocks = <&gcc GCC_AGGRE_UFS_PHY_AXI_CLK>,
<&gcc GCC_AGGRE_NOC_QUPV3_AXI_CLK>,
<&gcc GCC_AGGRE_USB2_PRIM_AXI_CLK>,
<&gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>,
<&gcc GCC_AGGRE_USB3_SEC_AXI_CLK>;
};

View File

@@ -12,9 +12,6 @@ maintainers:
description:
Qualcomm RPMh-based interconnect provider on SM6350.
allOf:
- $ref: qcom,rpmh-common.yaml#
properties:
compatible:
enum:
@@ -30,7 +27,9 @@ properties:
reg:
maxItems: 1
'#interconnect-cells': true
clocks:
minItems: 1
maxItems: 2
patternProperties:
'^interconnect-[a-z0-9\-]+$':
@@ -46,8 +45,6 @@ patternProperties:
- qcom,sm6350-clk-virt
- qcom,sm6350-compute-noc
'#interconnect-cells': true
required:
- compatible
@@ -57,10 +54,54 @@ required:
- compatible
- reg
allOf:
- $ref: qcom,rpmh-common.yaml#
- if:
properties:
compatible:
contains:
enum:
- qcom,sm6350-aggre1-noc
then:
properties:
clocks:
items:
- description: aggre UFS PHY AXI clock
- if:
properties:
compatible:
contains:
enum:
- qcom,sm6350-aggre2-noc
then:
properties:
clocks:
items:
- description: aggre USB3 PRIM AXI clock
- description: RPMH CC IPA clock
- if:
properties:
compatible:
contains:
enum:
- qcom,sm6350-aggre1-noc
- qcom,sm6350-aggre2-noc
then:
required:
- clocks
else:
properties:
clocks: false
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,gcc-sm6350.h>
#include <dt-bindings/clock/qcom,rpmh.h>
config_noc: interconnect@1500000 {
compatible = "qcom,sm6350-config-noc";
reg = <0x01500000 0x28000>;
@@ -68,14 +109,16 @@ examples:
qcom,bcm-voters = <&apps_bcm_voter>;
};
system_noc: interconnect@1620000 {
compatible = "qcom,sm6350-system-noc";
reg = <0x01620000 0x17080>;
aggre2_noc: interconnect@1700000 {
compatible = "qcom,sm6350-aggre2-noc";
reg = <0x01700000 0x1f880>;
#interconnect-cells = <2>;
qcom,bcm-voters = <&apps_bcm_voter>;
clocks = <&gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>,
<&rpmhcc RPMH_IPA_CLK>;
clk_virt: interconnect-clk-virt {
compatible = "qcom,sm6350-clk-virt";
compute_noc: interconnect-compute-noc {
compatible = "qcom,sm6350-compute-noc";
#interconnect-cells = <2>;
qcom,bcm-voters = <&apps_bcm_voter>;
};

View File

@@ -14,7 +14,8 @@ maintainers:
description: |
This binding represents the on-chip eFuse OTP controller found on
i.MX6Q/D, i.MX6DL/S, i.MX6SL, i.MX6SX, i.MX6UL, i.MX6ULL/ULZ, i.MX6SLL,
i.MX7D/S, i.MX7ULP, i.MX8MQ, i.MX8MM, i.MX8MN i.MX8MP and i.MX93/5 SoCs.
i.MX7D/S, i.MX7ULP, i.MX8MQ, i.MX8MM, i.MX8MN i.MX8MP, i.MX93, i.MX94,
and i.MX95.
allOf:
- $ref: nvmem.yaml#
@@ -36,6 +37,7 @@ properties:
- fsl,imx8mq-ocotp
- fsl,imx8mm-ocotp
- fsl,imx93-ocotp
- fsl,imx94-ocotp
- fsl,imx95-ocotp
- const: syscon
- items:

View File

@@ -46,6 +46,12 @@ properties:
type: object
description: Command to use for automatic booting
env-size:
description:
Size in bytes of the environment data used by U-Boot for CRC
calculation. If omitted, the full NVMEM region size is used.
$ref: /schemas/types.yaml#/definitions/uint32
ethaddr:
type: object
description: Ethernet interfaces base MAC address.
@@ -104,6 +110,7 @@ examples:
partition-u-boot-env {
compatible = "brcm,env";
env-size = <0x20000>;
ethaddr {
};

View File

@@ -25,7 +25,9 @@ properties:
compatible:
oneOf:
- items:
- const: mediatek,mt8188-efuse
- enum:
- mediatek,mt8188-efuse
- mediatek,mt8189-efuse
- const: mediatek,mt8186-efuse
- const: mediatek,mt8186-efuse
@@ -48,6 +50,7 @@ properties:
- mediatek,mt7988-efuse
- mediatek,mt8173-efuse
- mediatek,mt8183-efuse
- mediatek,mt8189-efuse
- mediatek,mt8192-efuse
- mediatek,mt8195-efuse
- mediatek,mt8516-efuse

View File

@@ -39,6 +39,7 @@ properties:
- qcom,qcs404-qfprom
- qcom,qcs615-qfprom
- qcom,qcs8300-qfprom
- qcom,sa8775p-qfprom
- qcom,sar2130p-qfprom
- qcom,sc7180-qfprom
- qcom,sc7280-qfprom

View File

@@ -31,7 +31,7 @@ properties:
maxItems: 1
patternProperties:
"^.*@[0-9a-f]+$":
"@[0-9a-f]+$":
type: object
$ref: layouts/fixed-cell.yaml
unevaluatedProperties: false

View File

@@ -75,16 +75,22 @@ examples:
#size-cells = <1>;
ranges;
slim@28080000 {
controller@28080000 {
compatible = "qcom,slim-ngd-v1.5.0";
reg = <0x091c0000 0x2c000>;
interrupts = <GIC_SPI 163 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <2>;
dmas = <&slimbam 3>, <&slimbam 4>;
dma-names = "rx", "tx";
#address-cells = <1>;
#size-cells = <0>;
audio-codec@1,0 {
slim@1 {
reg = <1>;
#address-cells = <2>;
#size-cells = <0>;
codec@1,0 {
compatible = "slim217,1a0";
reg = <1 0>;
};
};
};
};
};

View File

@@ -121,8 +121,6 @@ properties:
- fsl,mma7660
# MMA8450Q: Xtrinsic Low-power, 3-axis Xtrinsic Accelerometer
- fsl,mma8450
# MPL3115: Absolute Digital Pressure Sensor
- fsl,mpl3115
# MPR121: Proximity Capacitive Touch Sensor Controller
- fsl,mpr121
# Honeywell Humidicon HIH-6130 humidity/temperature sensor
@@ -135,8 +133,6 @@ properties:
- ibm,cffps2
# IBM On-Chip Controller hwmon device
- ibm,p8-occ-hwmon
# Infineon barometric pressure and temperature sensor
- infineon,dps310
# Infineon IR36021 digital POL buck controller
- infineon,ir36021
# Infineon IRPS5401 Voltage Regulator (PMIC)

View File

@@ -264,5 +264,5 @@ Configure RMS voltage event thresholds (requires interrupts):
8. IIO Interfacing Tools
========================
See ``Documentation/iio/iio_tools.rst`` for the description of the available IIO
See Documentation/iio/iio_tools.rst for the description of the available IIO
interfacing tools.

View File

@@ -374,11 +374,11 @@ Obtain buffered data:
00001740 01 1a 00 00 ff ff fe 31 00 00 46 aa 00 03 37 f7 |.......1..F...7.|
...
See ``Documentation/iio/iio_devbuf.rst`` for more information about how buffered
See Documentation/iio/iio_devbuf.rst for more information about how buffered
data is structured.
4. IIO Interfacing Tools
========================
See ``Documentation/iio/iio_tools.rst`` for the description of the available IIO
See Documentation/iio/iio_tools.rst for the description of the available IIO
interfacing tools.

View File

@@ -436,11 +436,11 @@ Obtain buffered data::
00006b60 09 63 00 00 00 00 1b 13 00 00 22 2f 00 03 23 91 |.c........"/..#.|
...
See ``Documentation/iio/iio_devbuf.rst`` for more information about how buffered
See Documentation/iio/iio_devbuf.rst for more information about how buffered
data is structured.
4. IIO Interfacing Tools
========================
See ``Documentation/iio/iio_tools.rst`` for the description of the available IIO
See Documentation/iio/iio_tools.rst for the description of the available IIO
interfacing tools.

View File

@@ -366,11 +366,11 @@ Obtain buffered data:
0000ceb0 00 00 0d 2f 00 00 05 25 00 00 07 8d 00 00 a2 ce |.../...%........|
...
See ``Documentation/iio/iio_devbuf.rst`` for more information about how buffered
See Documentation/iio/iio_devbuf.rst for more information about how buffered
data is structured.
4. IIO Interfacing Tools
========================
See ``Documentation/iio/iio_tools.rst`` for the description of the available IIO
See Documentation/iio/iio_tools.rst for the description of the available IIO
interfacing tools.

View File

@@ -433,11 +433,11 @@ Obtain buffered data:
00000f0 00004 00014 00015 00005 00012 00011 00005 00012
...
See ``Documentation/iio/iio_devbuf.rst`` for more information about how buffered
See Documentation/iio/iio_devbuf.rst for more information about how buffered
data is structured.
4. IIO Interfacing Tools
========================
See ``Documentation/iio/iio_tools.rst`` for the description of the available IIO
See Documentation/iio/iio_tools.rst for the description of the available IIO
interfacing tools.

View File

@@ -223,11 +223,11 @@ Obtain buffered data:
002bc3c0 f7 fd 00 cb fb 94 24 80 f7 e3 00 f2 fb b8 24 80 |......$.......$.|
...
See ``Documentation/iio/iio_devbuf.rst`` for more information about how buffered
See Documentation/iio/iio_devbuf.rst for more information about how buffered
data is structured.
4. IIO Interfacing Tools
========================
See ``Documentation/iio/iio_tools.rst`` for the description of the available IIO
See Documentation/iio/iio_tools.rst for the description of the available IIO
interfacing tools.

View File

@@ -440,6 +440,18 @@ W: http://wiki.analog.com/AD5398
W: https://ez.analog.com/linux-software-drivers
F: drivers/regulator/ad5398.c
AD5446 ANALOG DEVICES INC AD5446 DAC DRIVER
M: Michael Hennerich <michael.hennerich@analog.com>
M: Nuno Sá <nuno.sa@analog.com>
L: linux-iio@vger.kernel.org
S: Supported
W: https://ez.analog.com/linux-software-drivers
F: Documentation/devicetree/bindings/iio/dac/adi,ad5446.yaml
F: drivers/iio/dac/ad5446-i2c.c
F: drivers/iio/dac/ad5446-spi.c
F: drivers/iio/dac/ad5446.c
F: drivers/iio/dac/ad5446.h
AD714X CAPACITANCE TOUCH SENSOR DRIVER (AD7142/3/7/8/7A)
M: Michael Hennerich <michael.hennerich@analog.com>
S: Supported
@@ -1809,11 +1821,9 @@ ANDROID DRIVERS
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
M: Arve Hjønnevåg <arve@android.com>
M: Todd Kjos <tkjos@android.com>
M: Martijn Coenen <maco@android.com>
M: Joel Fernandes <joelagnelf@nvidia.com>
M: Christian Brauner <christian@brauner.io>
M: Carlos Llamas <cmllamas@google.com>
M: Suren Baghdasaryan <surenb@google.com>
M: Alice Ryhl <aliceryhl@google.com>
L: linux-kernel@vger.kernel.org
S: Supported
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git
@@ -3794,6 +3804,13 @@ S: Maintained
F: Documentation/devicetree/bindings/iio/chemical/aosong,ags02ma.yaml
F: drivers/iio/chemical/ags02ma.c
AOSONG ADP810 DIFFERENTIAL PRESSURE SENSOR DRIVER
M: Akhilesh Patil <akhilesh@ee.iitb.ac.in>
L: linux-iio@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/iio/pressure/aosong,adp810.yaml
F: drivers/iio/pressure/adp810.c
ASC7621 HARDWARE MONITOR DRIVER
M: George Joseph <george.joseph@fairview5.com>
L: linux-hwmon@vger.kernel.org
@@ -4526,6 +4543,13 @@ F: include/net/bond*
F: include/uapi/linux/if_bonding.h
F: tools/testing/selftests/drivers/net/bonding/
BOSCH SENSORTEC BMA220 ACCELEROMETER IIO DRIVER
M: Petre Rodan <petre.rodan@subdimension.ro>
L: linux-iio@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/iio/accel/bosch,bma220.yaml
F: drivers/iio/accel/bma220*
BOSCH SENSORTEC BMA400 ACCELEROMETER IIO DRIVER
M: Dan Robertson <dan@dlrobertson.com>
L: linux-iio@vger.kernel.org
@@ -12312,11 +12336,13 @@ L: industrypack-devel@lists.sourceforge.net
S: Maintained
W: http://industrypack.sourceforge.net
F: drivers/ipack/
F: include/linux/ipack.h
INFINEON DPS310 Driver
M: Eddie James <eajames@linux.ibm.com>
L: linux-iio@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/iio/pressure/infineon,dps310.yaml
F: drivers/iio/pressure/dps310.c
INFINEON PEB2466 ASoC CODEC
@@ -12839,7 +12865,7 @@ F: drivers/mfd/intel-m10-bmc*
F: include/linux/mfd/intel-m10-bmc.h
INTEL MAX10 BMC SECURE UPDATES
M: Matthew Gerlach <matthew.gerlach@altera.com>
M: Xu Yilun <yilun.xu@intel.com>
L: linux-fpga@vger.kernel.org
S: Maintained
F: Documentation/ABI/testing/sysfs-driver-intel-m10-bmc-sec-update
@@ -13138,6 +13164,14 @@ F: Documentation/ABI/testing/sysfs-bus-iio-inv_icm42600
F: Documentation/devicetree/bindings/iio/imu/invensense,icm42600.yaml
F: drivers/iio/imu/inv_icm42600/
INVENSENSE ICM-456xx IMU DRIVER
M: Remi Buisson <remi.buisson@tdk.com>
L: linux-iio@vger.kernel.org
S: Maintained
W: https://invensense.tdk.com/
F: Documentation/devicetree/bindings/iio/imu/invensense,icm45600.yaml
F: drivers/iio/imu/inv_icm45600/
INVENSENSE MPU-3050 GYROSCOPE DRIVER
M: Linus Walleij <linus.walleij@linaro.org>
L: linux-iio@vger.kernel.org
@@ -15300,6 +15334,15 @@ S: Orphan
F: drivers/video/fbdev/matrox/matroxfb_*
F: include/uapi/linux/matroxfb.h
MAX14001/MAX14002 IIO ADC DRIVER
M: Kim Seer Paller <kimseer.paller@analog.com>
M: Marilene Andrade Garcia <marilene.agarcia@gmail.com>
L: linux-iio@vger.kernel.org
S: Maintained
W: https://ez.analog.com/linux-software-drivers
F: Documentation/devicetree/bindings/iio/adc/adi,max14001.yaml
F: drivers/iio/adc/max14001.c
MAX15301 DRIVER
M: Daniel Nilsson <daniel.nilsson@flex.com>
L: linux-hwmon@vger.kernel.org
@@ -18946,7 +18989,7 @@ OCXL (Open Coherent Accelerator Processor Interface OpenCAPI) DRIVER
M: Frederic Barrat <fbarrat@linux.ibm.com>
M: Andrew Donnellan <ajd@linux.ibm.com>
L: linuxppc-dev@lists.ozlabs.org
S: Supported
S: Odd Fixes
F: Documentation/userspace-api/accelerators/ocxl.rst
F: arch/powerpc/include/asm/pnv-ocxl.h
F: arch/powerpc/platforms/powernv/ocxl.c
@@ -22115,6 +22158,14 @@ S: Supported
F: Documentation/devicetree/bindings/timer/renesas,rz-mtu3.yaml
F: drivers/counter/rz-mtu3-cnt.c
RENESAS RZ/T2H / RZ/N2H A/D DRIVER
M: Cosmin Tanislav <cosmin-gabriel.tanislav.xa@renesas.com>
L: linux-iio@vger.kernel.org
L: linux-renesas-soc@vger.kernel.org
S: Supported
F: Documentation/devicetree/bindings/iio/adc/renesas,r9a09g077-adc.yaml
F: drivers/iio/adc/rzt2h_adc.c
RENESAS RTCA-3 RTC DRIVER
M: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
L: linux-rtc@vger.kernel.org
@@ -22136,6 +22187,13 @@ F: include/dt-bindings/net/pcs-rzn1-miic.h
F: include/linux/pcs-rzn1-miic.h
F: net/dsa/tag_rzn1_a5psw.c
RENESAS RZ/N1 ADC DRIVER
M: Herve Codina <herve.codina@bootlin.com>
L: linux-renesas-soc@vger.kernel.org
S: Supported
F: Documentation/devicetree/bindings/iio/adc/renesas,rzn1-adc.yaml
F: drivers/iio/adc/rzn1-adc.c
RENESAS RZ/N1 DWMAC GLUE LAYER
M: Romain Gantois <romain.gantois@bootlin.com>
S: Maintained

View File

@@ -1371,7 +1371,7 @@ static void sa1111_bus_remove(struct device *dev)
drv->remove(sadev);
}
struct bus_type sa1111_bus_type = {
const struct bus_type sa1111_bus_type = {
.name = "sa1111-rab",
.match = sa1111_match,
.probe = sa1111_bus_probe,

View File

@@ -368,7 +368,7 @@
extern struct bus_type sa1111_bus_type;
extern const struct bus_type sa1111_bus_type;
#define SA1111_DEVID_SBI (1 << 0)
#define SA1111_DEVID_SK (1 << 1)

View File

@@ -3496,6 +3496,9 @@
<&gcc GCC_USB20_MASTER_CLK>;
assigned-clock-rates = <19200000>, <60000000>;
interconnects = <&pnoc MASTER_USB_HS &bimc SLAVE_EBI_CH0>,
<&bimc MASTER_AMPSS_M0 &pnoc SLAVE_USB_HS>;
interconnect-names = "usb-ddr", "apps-usb";
power-domains = <&gcc USB30_GDSC>;
qcom,select-utmi-as-pipe-clk;
status = "disabled";

View File

@@ -464,7 +464,7 @@ void spu_init_channels(struct spu *spu)
}
EXPORT_SYMBOL_GPL(spu_init_channels);
static struct bus_type spu_subsys = {
static const struct bus_type spu_subsys = {
.name = "spu",
.dev_name = "spu",
};

View File

@@ -465,7 +465,7 @@ static struct attribute *ps3_system_bus_dev_attrs[] = {
};
ATTRIBUTE_GROUPS(ps3_system_bus_dev);
static struct bus_type ps3_system_bus_type = {
static const struct bus_type ps3_system_bus_type = {
.name = "ps3_system_bus",
.match = ps3_system_bus_match,
.uevent = ps3_system_bus_uevent,

View File

@@ -375,7 +375,7 @@ static struct device_attribute *cmm_attrs[] = {
static DEVICE_ULONG_ATTR(simulate_loan_target_kb, 0644,
simulate_loan_target_kb);
static struct bus_type cmm_subsys = {
static const struct bus_type cmm_subsys = {
.name = "cmm",
.dev_name = "cmm",
};

View File

@@ -126,7 +126,7 @@ static ssize_t show_hibernate(struct device *dev,
static DEVICE_ATTR(hibernate, 0644, show_hibernate, store_hibernate);
static struct bus_type suspend_subsys = {
static const struct bus_type suspend_subsys = {
.name = "power",
.dev_name = "power",
};

View File

@@ -4669,6 +4669,8 @@ static int binder_wait_for_work(struct binder_thread *thread,
*
* If we fail to allocate an fd, skip the install and release
* any fds that have already been allocated.
*
* Return: 0 on success, a negative errno code on failure.
*/
static int binder_apply_fd_fixups(struct binder_proc *proc,
struct binder_transaction *t)

View File

@@ -541,10 +541,10 @@ impl Node {
guard = self.owner.inner.lock();
}
let death_list = core::mem::take(&mut self.inner.access_mut(&mut guard).death_list);
drop(guard);
for death in death_list {
while let Some(death) = self.inner.access_mut(&mut guard).death_list.pop_front() {
drop(guard);
death.into_arc().set_dead();
guard = self.owner.inner.lock();
}
}

View File

@@ -1392,8 +1392,12 @@ impl Process {
work.into_arc().cancel();
}
let delivered_deaths = take(&mut self.inner.lock().delivered_deaths);
drop(delivered_deaths);
// Clear delivered_deaths list.
//
// Scope ensures that MutexGuard is dropped while executing the body.
while let Some(delivered_death) = { self.inner.lock().delivered_deaths.pop_front() } {
drop(delivered_death);
}
// Free any resources kept alive by allocated buffers.
let omapping = self.inner.lock().mapping.take();
@@ -1653,15 +1657,6 @@ impl Process {
}
}
pub(crate) fn compat_ioctl(
this: ArcBorrow<'_, Process>,
file: &File,
cmd: u32,
arg: usize,
) -> Result {
Self::ioctl(this, file, cmd, arg)
}
pub(crate) fn mmap(
this: ArcBorrow<'_, Process>,
_file: &File,

View File

@@ -313,8 +313,8 @@ pub static rust_binder_fops: AssertSync<kernel::bindings::file_operations> = {
let ops = kernel::bindings::file_operations {
owner: THIS_MODULE.as_ptr(),
poll: Some(rust_binder_poll),
unlocked_ioctl: Some(rust_binder_unlocked_ioctl),
compat_ioctl: Some(rust_binder_compat_ioctl),
unlocked_ioctl: Some(rust_binder_ioctl),
compat_ioctl: Some(bindings::compat_ptr_ioctl),
mmap: Some(rust_binder_mmap),
open: Some(rust_binder_open),
release: Some(rust_binder_release),
@@ -402,23 +402,7 @@ unsafe extern "C" fn rust_binder_release(
/// # Safety
/// Only called by binderfs.
unsafe extern "C" fn rust_binder_compat_ioctl(
file: *mut bindings::file,
cmd: kernel::ffi::c_uint,
arg: kernel::ffi::c_ulong,
) -> kernel::ffi::c_long {
// SAFETY: We previously set `private_data` in `rust_binder_open`.
let f = unsafe { Arc::<Process>::borrow((*file).private_data) };
// SAFETY: The caller ensures that the file is valid.
match Process::compat_ioctl(f, unsafe { File::from_raw_file(file) }, cmd as _, arg as _) {
Ok(()) => 0,
Err(err) => err.to_errno() as isize,
}
}
/// # Safety
/// Only called by binderfs.
unsafe extern "C" fn rust_binder_unlocked_ioctl(
unsafe extern "C" fn rust_binder_ioctl(
file: *mut bindings::file,
cmd: kernel::ffi::c_uint,
arg: kernel::ffi::c_ulong,

View File

@@ -1323,12 +1323,12 @@ impl Thread {
}
BC_FREE_BUFFER => {
let buffer = self.process.buffer_get(reader.read()?);
if let Some(buffer) = &buffer {
if let Some(buffer) = buffer {
if buffer.looper_need_return_on_free() {
self.inner.lock().looper_need_return = true;
}
drop(buffer);
}
drop(buffer);
}
BC_INCREFS => {
self.process

View File

@@ -211,6 +211,9 @@ err:
/**
* binder_ctl_ioctl - handle binder device node allocation requests
* @file: The file pointer for the binder-control device node.
* @cmd: The ioctl command.
* @arg: The ioctl argument.
*
* The request handler for the binder-control device. All requests operate on
* the binderfs mount the binder-control device resides in:

View File

@@ -554,7 +554,7 @@ static void binder_alloc_test_exit(struct kunit *test)
static struct kunit_case binder_alloc_test_cases[] = {
KUNIT_CASE(binder_alloc_test_init_freelist),
KUNIT_CASE(binder_alloc_test_mmap),
KUNIT_CASE(binder_alloc_exhaustive_test),
KUNIT_CASE_SLOW(binder_alloc_exhaustive_test),
{}
};

View File

@@ -38,7 +38,7 @@ config FW_LOADER_DEBUG
config RUST_FW_LOADER_ABSTRACTIONS
bool "Rust Firmware Loader abstractions"
depends on RUST
depends on FW_LOADER=y
select FW_LOADER
help
This enables the Rust abstractions for the firmware loader API.

View File

@@ -11,7 +11,7 @@
#include "../common.h"
extern struct bus_type mhi_ep_bus_type;
extern const struct bus_type mhi_ep_bus_type;
#define MHI_REG_OFFSET 0x100
#define BHI_REG_OFFSET 0x200

View File

@@ -1494,7 +1494,7 @@ int mhi_ep_register_controller(struct mhi_ep_cntrl *mhi_cntrl,
INIT_WORK(&mhi_cntrl->cmd_ring_work, mhi_ep_cmd_ring_worker);
INIT_WORK(&mhi_cntrl->ch_ring_work, mhi_ep_ch_ring_worker);
mhi_cntrl->wq = alloc_workqueue("mhi_ep_wq", 0, 0);
mhi_cntrl->wq = alloc_workqueue("mhi_ep_wq", WQ_PERCPU, 0);
if (!mhi_cntrl->wq) {
ret = -ENOMEM;
goto err_destroy_ring_item_cache;
@@ -1703,7 +1703,7 @@ static int mhi_ep_match(struct device *dev, const struct device_driver *drv)
return 0;
};
struct bus_type mhi_ep_bus_type = {
const struct bus_type mhi_ep_bus_type = {
.name = "mhi_ep",
.dev_name = "mhi_ep",
.match = mhi_ep_match,

View File

@@ -663,6 +663,17 @@ static const struct mhi_pci_dev_info mhi_foxconn_t99w696_info = {
.sideband_wake = false,
};
static const struct mhi_pci_dev_info mhi_foxconn_t99w760_info = {
.name = "foxconn-t99w760",
.edl = "qcom/sdx35/foxconn/xbl_s_devprg_ns.melf",
.edl_trigger = true,
.config = &modem_foxconn_sdx61_config,
.bar_num = MHI_PCI_DEFAULT_BAR_NUM,
.dma_data_width = 32,
.mru_default = 32768,
.sideband_wake = false,
};
static const struct mhi_channel_config mhi_mv3x_channels[] = {
MHI_CHANNEL_CONFIG_UL(0, "LOOPBACK", 64, 0),
MHI_CHANNEL_CONFIG_DL(1, "LOOPBACK", 64, 0),
@@ -877,6 +888,16 @@ static const struct mhi_pci_dev_info mhi_telit_fn990b40_info = {
.edl_trigger = true,
};
static const struct mhi_pci_dev_info mhi_telit_fe990b40_info = {
.name = "telit-fe990b40",
.config = &modem_telit_fn920c04_config,
.bar_num = MHI_PCI_DEFAULT_BAR_NUM,
.dma_data_width = 32,
.sideband_wake = false,
.mru_default = 32768,
.edl_trigger = true,
};
static const struct mhi_pci_dev_info mhi_netprisma_lcur57_info = {
.name = "netprisma-lcur57",
.edl = "qcom/prog_firehose_sdx24.mbn",
@@ -933,6 +954,9 @@ static const struct pci_device_id mhi_pci_id_table[] = {
/* Telit FN990B40 (sdx72) */
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0309, 0x1c5d, 0x201a),
.driver_data = (kernel_ulong_t) &mhi_telit_fn990b40_info },
/* Telit FE990B40 (sdx72) */
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_QCOM, 0x0309, 0x1c5d, 0x2025),
.driver_data = (kernel_ulong_t) &mhi_telit_fe990b40_info },
{ PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0309),
.driver_data = (kernel_ulong_t) &mhi_qcom_sdx75_info },
/* QDU100, x100-DU */
@@ -997,6 +1021,8 @@ static const struct pci_device_id mhi_pci_id_table[] = {
/* DW5934e(sdx72), Non-eSIM */
{ PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe11e),
.driver_data = (kernel_ulong_t) &mhi_foxconn_dw5934e_info },
{ PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe123),
.driver_data = (kernel_ulong_t) &mhi_foxconn_t99w760_info },
/* MV31-W (Cinterion) */
{ PCI_DEVICE(PCI_VENDOR_ID_THALES, 0x00b3),
.driver_data = (kernel_ulong_t) &mhi_mv31_info },

View File

@@ -170,7 +170,7 @@ static int cdx_unregister_device(struct device *dev,
return 0;
}
static void cdx_unregister_devices(struct bus_type *bus)
static void cdx_unregister_devices(const struct bus_type *bus)
{
/* Reset all the devices attached to cdx bus */
bus_for_each_dev(bus, NULL, NULL, cdx_unregister_device);
@@ -651,7 +651,7 @@ static struct attribute *cdx_bus_attrs[] = {
};
ATTRIBUTE_GROUPS(cdx_bus);
struct bus_type cdx_bus_type = {
const struct bus_type cdx_bus_type = {
.name = "cdx",
.match = cdx_bus_match,
.probe = cdx_probe,

View File

@@ -80,8 +80,8 @@ static ssize_t adi_read(struct file *file, char __user *buf,
bytes_read += ver_buf_sz;
ver_buf_idx = 0;
ver_buf_sz = min(count - bytes_read,
(size_t)MAX_BUF_SZ);
ver_buf_sz = min_t(size_t, count - bytes_read,
MAX_BUF_SZ);
}
}
@@ -157,7 +157,7 @@ static ssize_t adi_write(struct file *file, const char __user *buf,
}
bytes_written += ver_buf_sz;
ver_buf_sz = min(count - bytes_written, (size_t)MAX_BUF_SZ);
ver_buf_sz = min_t(size_t, count - bytes_written, MAX_BUF_SZ);
} while (bytes_written < count);
(*offp) += bytes_written;

View File

@@ -142,18 +142,10 @@ static struct apm_queue kapmd_queue;
static DEFINE_MUTEX(state_lock);
/*
* Compatibility cruft until the IPAQ people move over to the new
* interface.
*/
static void __apm_get_power_status(struct apm_power_info *info)
{
}
/*
* This allows machines to provide their own "apm get power status" function.
*/
void (*apm_get_power_status)(struct apm_power_info *) = __apm_get_power_status;
void (*apm_get_power_status)(struct apm_power_info *);
EXPORT_SYMBOL(apm_get_power_status);

View File

@@ -835,7 +835,10 @@ static long ac_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
ret = -ENOTTY;
break;
}
Dummy = readb(apbs[IndexCard].RamIO + VERS);
if (cmd != 6)
Dummy = readb(apbs[IndexCard].RamIO + VERS);
kfree(adgl);
mutex_unlock(&ac_mutex);
return ret;

View File

@@ -69,7 +69,8 @@ MODULE_VERSION(VERSION_STR);
static int __init hangcheck_parse_tick(char *str)
{
int par;
if (get_option(&str,&par))
if (get_option(&str, &par))
hangcheck_tick = par;
return 1;
}
@@ -77,7 +78,8 @@ static int __init hangcheck_parse_tick(char *str)
static int __init hangcheck_parse_margin(char *str)
{
int par;
if (get_option(&str,&par))
if (get_option(&str, &par))
hangcheck_margin = par;
return 1;
}
@@ -85,7 +87,8 @@ static int __init hangcheck_parse_margin(char *str)
static int __init hangcheck_parse_reboot(char *str)
{
int par;
if (get_option(&str,&par))
if (get_option(&str, &par))
hangcheck_reboot = par;
return 1;
}
@@ -93,7 +96,8 @@ static int __init hangcheck_parse_reboot(char *str)
static int __init hangcheck_parse_dump_tasks(char *str)
{
int par;
if (get_option(&str,&par))
if (get_option(&str, &par))
hangcheck_dump_tasks = par;
return 1;
}
@@ -126,23 +130,23 @@ static void hangcheck_fire(struct timer_list *unused)
if (tsc_diff > hangcheck_tsc_margin) {
if (hangcheck_dump_tasks) {
printk(KERN_CRIT "Hangcheck: Task state:\n");
pr_crit("Hangcheck: Task state:\n");
#ifdef CONFIG_MAGIC_SYSRQ
handle_sysrq('t');
#endif /* CONFIG_MAGIC_SYSRQ */
}
if (hangcheck_reboot) {
printk(KERN_CRIT "Hangcheck: hangcheck is restarting the machine.\n");
pr_crit("Hangcheck: hangcheck is restarting the machine.\n");
emergency_restart();
} else {
printk(KERN_CRIT "Hangcheck: hangcheck value past margin!\n");
pr_crit("Hangcheck: hangcheck value past margin!\n");
}
}
#if 0
/*
* Enable to investigate delays in detail
*/
printk("Hangcheck: called %Ld ns since last time (%Ld ns overshoot)\n",
pr_debug("Hangcheck: called %lld ns since last time (%lld ns overshoot)\n",
tsc_diff, tsc_diff - hangcheck_tick*TIMER_FREQ);
#endif
mod_timer(&hangcheck_ticktock, jiffies + (hangcheck_tick*HZ));
@@ -152,7 +156,7 @@ static void hangcheck_fire(struct timer_list *unused)
static int __init hangcheck_init(void)
{
printk("Hangcheck: starting hangcheck timer %s (tick is %d seconds, margin is %d seconds).\n",
pr_debug("Hangcheck: starting hangcheck timer %s (tick is %d seconds, margin is %d seconds).\n",
VERSION_STR, hangcheck_tick, hangcheck_margin);
hangcheck_tsc_margin =
(unsigned long long)hangcheck_margin + hangcheck_tick;
@@ -168,7 +172,7 @@ static int __init hangcheck_init(void)
static void __exit hangcheck_exit(void)
{
timer_delete_sync(&hangcheck_ticktock);
printk("Hangcheck: Stopped hangcheck timer.\n");
pr_debug("Hangcheck: Stopped hangcheck timer.\n");
}
module_init(hangcheck_init);

View File

@@ -46,6 +46,8 @@
* First release to the public
*/
#define pr_fmt(fmt) "3780i: " fmt
#include <linux/kernel.h>
#include <linux/unistd.h>
#include <linux/delay.h>
@@ -75,18 +77,12 @@ unsigned short dsp3780I_ReadMsaCfg(unsigned short usDspBaseIO,
unsigned long flags;
unsigned short val;
PRINTK_3(TRACE_3780I,
"3780i::dsp3780I_ReadMsaCfg entry usDspBaseIO %x ulMsaAddr %lx\n",
usDspBaseIO, ulMsaAddr);
spin_lock_irqsave(&dsp_lock, flags);
OutWordDsp(DSP_MsaAddrLow, (unsigned short) ulMsaAddr);
OutWordDsp(DSP_MsaAddrHigh, (unsigned short) (ulMsaAddr >> 16));
val = InWordDsp(DSP_MsaDataDSISHigh);
spin_unlock_irqrestore(&dsp_lock, flags);
PRINTK_2(TRACE_3780I, "3780i::dsp3780I_ReadMsaCfg exit val %x\n", val);
return val;
}
@@ -95,10 +91,6 @@ void dsp3780I_WriteMsaCfg(unsigned short usDspBaseIO,
{
unsigned long flags;
PRINTK_4(TRACE_3780I,
"3780i::dsp3780i_WriteMsaCfg entry usDspBaseIO %x ulMsaAddr %lx usValue %x\n",
usDspBaseIO, ulMsaAddr, usValue);
spin_lock_irqsave(&dsp_lock, flags);
OutWordDsp(DSP_MsaAddrLow, (unsigned short) ulMsaAddr);
OutWordDsp(DSP_MsaAddrHigh, (unsigned short) (ulMsaAddr >> 16));
@@ -112,64 +104,18 @@ static void dsp3780I_WriteGenCfg(unsigned short usDspBaseIO, unsigned uIndex,
DSP_ISA_SLAVE_CONTROL rSlaveControl;
DSP_ISA_SLAVE_CONTROL rSlaveControl_Save;
PRINTK_4(TRACE_3780I,
"3780i::dsp3780i_WriteGenCfg entry usDspBaseIO %x uIndex %x ucValue %x\n",
usDspBaseIO, uIndex, ucValue);
MKBYTE(rSlaveControl) = InByteDsp(DSP_IsaSlaveControl);
PRINTK_2(TRACE_3780I,
"3780i::dsp3780i_WriteGenCfg rSlaveControl %x\n",
MKBYTE(rSlaveControl));
rSlaveControl_Save = rSlaveControl;
rSlaveControl.ConfigMode = true;
PRINTK_2(TRACE_3780I,
"3780i::dsp3780i_WriteGenCfg entry rSlaveControl+ConfigMode %x\n",
MKBYTE(rSlaveControl));
OutByteDsp(DSP_IsaSlaveControl, MKBYTE(rSlaveControl));
OutByteDsp(DSP_ConfigAddress, (unsigned char) uIndex);
OutByteDsp(DSP_ConfigData, ucValue);
OutByteDsp(DSP_IsaSlaveControl, MKBYTE(rSlaveControl_Save));
PRINTK_1(TRACE_3780I, "3780i::dsp3780i_WriteGenCfg exit\n");
}
#if 0
unsigned char dsp3780I_ReadGenCfg(unsigned short usDspBaseIO,
unsigned uIndex)
{
DSP_ISA_SLAVE_CONTROL rSlaveControl;
DSP_ISA_SLAVE_CONTROL rSlaveControl_Save;
unsigned char ucValue;
PRINTK_3(TRACE_3780I,
"3780i::dsp3780i_ReadGenCfg entry usDspBaseIO %x uIndex %x\n",
usDspBaseIO, uIndex);
MKBYTE(rSlaveControl) = InByteDsp(DSP_IsaSlaveControl);
rSlaveControl_Save = rSlaveControl;
rSlaveControl.ConfigMode = true;
OutByteDsp(DSP_IsaSlaveControl, MKBYTE(rSlaveControl));
OutByteDsp(DSP_ConfigAddress, (unsigned char) uIndex);
ucValue = InByteDsp(DSP_ConfigData);
OutByteDsp(DSP_IsaSlaveControl, MKBYTE(rSlaveControl_Save));
PRINTK_2(TRACE_3780I,
"3780i::dsp3780i_ReadGenCfg exit ucValue %x\n", ucValue);
return ucValue;
}
#endif /* 0 */
int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings,
int dsp3780I_EnableDSP(struct dsp_3780i_config_settings *pSettings,
unsigned short *pIrqMap,
unsigned short *pDmaMap)
{
@@ -191,25 +137,13 @@ int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings,
DSP_CLOCK_CONTROL_2 rClockControl2;
DSP_ISA_SLAVE_CONTROL rSlaveControl;
DSP_HBRIDGE_CONTROL rHBridgeControl;
unsigned short ChipID = 0;
unsigned short tval;
PRINTK_2(TRACE_3780I,
"3780i::dsp3780I_EnableDSP entry pSettings->bDSPEnabled %x\n",
pSettings->bDSPEnabled);
if (!pSettings->bDSPEnabled) {
PRINTK_ERROR( KERN_ERR "3780i::dsp3780I_EnableDSP: Error: DSP not enabled. Aborting.\n" );
pr_err("%s: Error: DSP not enabled. Aborting.\n", __func__);
return -EIO;
}
PRINTK_2(TRACE_3780I,
"3780i::dsp3780i_EnableDSP entry pSettings->bModemEnabled %x\n",
pSettings->bModemEnabled);
if (pSettings->bModemEnabled) {
rUartCfg1.Reserved = rUartCfg2.Reserved = 0;
rUartCfg1.IrqActiveLow = pSettings->bUartIrqActiveLow;
@@ -282,23 +216,10 @@ int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings,
rSlaveControl.ConfigMode = false;
rSlaveControl.Reserved = 0;
PRINTK_4(TRACE_3780I,
"3780i::dsp3780i_EnableDSP usDspBaseIO %x index %x taddr %x\n",
usDspBaseIO, DSP_IsaSlaveControl,
usDspBaseIO + DSP_IsaSlaveControl);
PRINTK_2(TRACE_3780I,
"3780i::dsp3780i_EnableDSP rSlaveContrl %x\n",
MKWORD(rSlaveControl));
spin_lock_irqsave(&dsp_lock, flags);
OutWordDsp(DSP_IsaSlaveControl, MKWORD(rSlaveControl));
MKWORD(tval) = InWordDsp(DSP_IsaSlaveControl);
PRINTK_2(TRACE_3780I,
"3780i::dsp3780i_EnableDSP rSlaveControl 2 %x\n", tval);
for (i = 0; i < 11; i++)
udelay(2000);
@@ -307,10 +228,6 @@ int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings,
MKWORD(tval) = InWordDsp(DSP_IsaSlaveControl);
PRINTK_2(TRACE_3780I,
"3780i::dsp3780i_EnableDSP rSlaveControl 3 %x\n", tval);
/* Program our general configuration registers */
WriteGenCfg(DSP_HBridgeCfg1Index, MKBYTE(rHBridgeCfg1));
WriteGenCfg(DSP_HBridgeCfg2Index, MKBYTE(rHBridgeCfg2));
@@ -331,10 +248,6 @@ int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings,
rHBridgeControl.IoAutoInc = false;
rHBridgeControl.DiagnosticMode = false;
PRINTK_3(TRACE_3780I,
"3780i::dsp3780i_EnableDSP DSP_HBridgeControl %x rHBridgeControl %x\n",
DSP_HBridgeControl, MKWORD(rHBridgeControl));
OutWordDsp(DSP_HBridgeControl, MKWORD(rHBridgeControl));
spin_unlock_irqrestore(&dsp_lock, flags);
WriteMsaCfg(DSP_LBusTimeoutDisable, MKWORD(rLBusTimeoutDisable));
@@ -342,24 +255,17 @@ int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings,
WriteMsaCfg(DSP_ClockControl_2, MKWORD(rClockControl2));
WriteMsaCfg(DSP_ChipReset, MKWORD(rChipReset));
ChipID = ReadMsaCfg(DSP_ChipID);
PRINTK_2(TRACE_3780I,
"3780i::dsp3780I_EnableDSP exiting bRC=true, ChipID %x\n",
ChipID);
ReadMsaCfg(DSP_ChipID);
return 0;
}
int dsp3780I_DisableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings)
int dsp3780I_DisableDSP(struct dsp_3780i_config_settings *pSettings)
{
unsigned long flags;
unsigned short usDspBaseIO = pSettings->usDspBaseIO;
DSP_ISA_SLAVE_CONTROL rSlaveControl;
PRINTK_1(TRACE_3780I, "3780i::dsp3780i_DisableDSP entry\n");
rSlaveControl.ClockControl = 0;
rSlaveControl.SoftReset = true;
rSlaveControl.ConfigMode = false;
@@ -375,29 +281,20 @@ int dsp3780I_DisableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings)
udelay(5);
PRINTK_1(TRACE_3780I, "3780i::dsp3780i_DisableDSP exit\n");
return 0;
}
int dsp3780I_Reset(DSP_3780I_CONFIG_SETTINGS * pSettings)
int dsp3780I_Reset(struct dsp_3780i_config_settings *pSettings)
{
unsigned long flags;
unsigned short usDspBaseIO = pSettings->usDspBaseIO;
DSP_BOOT_DOMAIN rBootDomain;
DSP_HBRIDGE_CONTROL rHBridgeControl;
PRINTK_1(TRACE_3780I, "3780i::dsp3780i_Reset entry\n");
spin_lock_irqsave(&dsp_lock, flags);
/* Mask DSP to PC interrupt */
MKWORD(rHBridgeControl) = InWordDsp(DSP_HBridgeControl);
PRINTK_2(TRACE_3780I, "3780i::dsp3780i_Reset rHBridgeControl %x\n",
MKWORD(rHBridgeControl));
rHBridgeControl.EnableDspInt = false;
OutWordDsp(DSP_HBridgeControl, MKWORD(rHBridgeControl));
spin_unlock_irqrestore(&dsp_lock, flags);
@@ -408,9 +305,6 @@ int dsp3780I_Reset(DSP_3780I_CONFIG_SETTINGS * pSettings)
rBootDomain.NMI = true;
rBootDomain.Reserved = 0;
PRINTK_2(TRACE_3780I, "3780i::dsp3780i_Reset rBootDomain %x\n",
MKWORD(rBootDomain));
WriteMsaCfg(DSP_MspBootDomain, MKWORD(rBootDomain));
/* Reset all the chiplets and then reactivate them */
@@ -419,24 +313,17 @@ int dsp3780I_Reset(DSP_3780I_CONFIG_SETTINGS * pSettings)
WriteMsaCfg(DSP_ChipReset,
(unsigned short) (~pSettings->usChipletEnable));
PRINTK_1(TRACE_3780I, "3780i::dsp3780i_Reset exit bRC=0\n");
return 0;
}
int dsp3780I_Run(DSP_3780I_CONFIG_SETTINGS * pSettings)
int dsp3780I_Run(struct dsp_3780i_config_settings *pSettings)
{
unsigned long flags;
unsigned short usDspBaseIO = pSettings->usDspBaseIO;
DSP_BOOT_DOMAIN rBootDomain;
DSP_HBRIDGE_CONTROL rHBridgeControl;
PRINTK_1(TRACE_3780I, "3780i::dsp3780i_Run entry\n");
/* Transition the core to a running state */
rBootDomain.ResetCore = true;
rBootDomain.Halt = false;
@@ -459,15 +346,9 @@ int dsp3780I_Run(DSP_3780I_CONFIG_SETTINGS * pSettings)
MKWORD(rHBridgeControl) = InWordDsp(DSP_HBridgeControl);
rHBridgeControl.EnableDspInt = true;
PRINTK_2(TRACE_3780I, "3780i::dsp3780i_Run rHBridgeControl %x\n",
MKWORD(rHBridgeControl));
OutWordDsp(DSP_HBridgeControl, MKWORD(rHBridgeControl));
spin_unlock_irqrestore(&dsp_lock, flags);
PRINTK_1(TRACE_3780I, "3780i::dsp3780i_Run exit bRC=true\n");
return 0;
}
@@ -479,12 +360,6 @@ int dsp3780I_ReadDStore(unsigned short usDspBaseIO, void __user *pvBuffer,
unsigned short __user *pusBuffer = pvBuffer;
unsigned short val;
PRINTK_5(TRACE_3780I,
"3780i::dsp3780I_ReadDStore entry usDspBaseIO %x, pusBuffer %p, uCount %x, ulDSPAddr %lx\n",
usDspBaseIO, pusBuffer, uCount, ulDSPAddr);
/* Set the initial MSA address. No adjustments need to be made to data store addresses */
spin_lock_irqsave(&dsp_lock, flags);
OutWordDsp(DSP_MsaAddrLow, (unsigned short) ulDSPAddr);
@@ -499,17 +374,9 @@ int dsp3780I_ReadDStore(unsigned short usDspBaseIO, void __user *pvBuffer,
if(put_user(val, pusBuffer++))
return -EFAULT;
PRINTK_3(TRACE_3780I,
"3780I::dsp3780I_ReadDStore uCount %x val %x\n",
uCount, val);
PaceMsaAccess(usDspBaseIO);
}
PRINTK_1(TRACE_3780I,
"3780I::dsp3780I_ReadDStore exit bRC=true\n");
return 0;
}
@@ -521,12 +388,6 @@ int dsp3780I_ReadAndClearDStore(unsigned short usDspBaseIO,
unsigned short __user *pusBuffer = pvBuffer;
unsigned short val;
PRINTK_5(TRACE_3780I,
"3780i::dsp3780I_ReadAndDStore entry usDspBaseIO %x, pusBuffer %p, uCount %x, ulDSPAddr %lx\n",
usDspBaseIO, pusBuffer, uCount, ulDSPAddr);
/* Set the initial MSA address. No adjustments need to be made to data store addresses */
spin_lock_irqsave(&dsp_lock, flags);
OutWordDsp(DSP_MsaAddrLow, (unsigned short) ulDSPAddr);
@@ -541,17 +402,9 @@ int dsp3780I_ReadAndClearDStore(unsigned short usDspBaseIO,
if(put_user(val, pusBuffer++))
return -EFAULT;
PRINTK_3(TRACE_3780I,
"3780I::dsp3780I_ReadAndCleanDStore uCount %x val %x\n",
uCount, val);
PaceMsaAccess(usDspBaseIO);
}
PRINTK_1(TRACE_3780I,
"3780I::dsp3780I_ReadAndClearDStore exit bRC=true\n");
return 0;
}
@@ -562,12 +415,6 @@ int dsp3780I_WriteDStore(unsigned short usDspBaseIO, void __user *pvBuffer,
unsigned long flags;
unsigned short __user *pusBuffer = pvBuffer;
PRINTK_5(TRACE_3780I,
"3780i::dsp3780D_WriteDStore entry usDspBaseIO %x, pusBuffer %p, uCount %x, ulDSPAddr %lx\n",
usDspBaseIO, pusBuffer, uCount, ulDSPAddr);
/* Set the initial MSA address. No adjustments need to be made to data store addresses */
spin_lock_irqsave(&dsp_lock, flags);
OutWordDsp(DSP_MsaAddrLow, (unsigned short) ulDSPAddr);
@@ -583,17 +430,9 @@ int dsp3780I_WriteDStore(unsigned short usDspBaseIO, void __user *pvBuffer,
OutWordDsp(DSP_MsaDataDSISHigh, val);
spin_unlock_irqrestore(&dsp_lock, flags);
PRINTK_3(TRACE_3780I,
"3780I::dsp3780I_WriteDStore uCount %x val %x\n",
uCount, val);
PaceMsaAccess(usDspBaseIO);
}
PRINTK_1(TRACE_3780I,
"3780I::dsp3780D_WriteDStore exit bRC=true\n");
return 0;
}
@@ -604,10 +443,6 @@ int dsp3780I_ReadIStore(unsigned short usDspBaseIO, void __user *pvBuffer,
unsigned long flags;
unsigned short __user *pusBuffer = pvBuffer;
PRINTK_5(TRACE_3780I,
"3780i::dsp3780I_ReadIStore entry usDspBaseIO %x, pusBuffer %p, uCount %x, ulDSPAddr %lx\n",
usDspBaseIO, pusBuffer, uCount, ulDSPAddr);
/*
* Set the initial MSA address. To convert from an instruction store
* address to an MSA address
@@ -631,17 +466,10 @@ int dsp3780I_ReadIStore(unsigned short usDspBaseIO, void __user *pvBuffer,
if(put_user(val_hi, pusBuffer++))
return -EFAULT;
PRINTK_4(TRACE_3780I,
"3780I::dsp3780I_ReadIStore uCount %x val_lo %x val_hi %x\n",
uCount, val_lo, val_hi);
PaceMsaAccess(usDspBaseIO);
}
PRINTK_1(TRACE_3780I,
"3780I::dsp3780I_ReadIStore exit bRC=true\n");
return 0;
}
@@ -652,11 +480,6 @@ int dsp3780I_WriteIStore(unsigned short usDspBaseIO, void __user *pvBuffer,
unsigned long flags;
unsigned short __user *pusBuffer = pvBuffer;
PRINTK_5(TRACE_3780I,
"3780i::dsp3780I_WriteIStore entry usDspBaseIO %x, pusBuffer %p, uCount %x, ulDSPAddr %lx\n",
usDspBaseIO, pusBuffer, uCount, ulDSPAddr);
/*
* Set the initial MSA address. To convert from an instruction store
* address to an MSA address
@@ -680,17 +503,9 @@ int dsp3780I_WriteIStore(unsigned short usDspBaseIO, void __user *pvBuffer,
OutWordDsp(DSP_MsaDataDSISHigh, val_hi);
spin_unlock_irqrestore(&dsp_lock, flags);
PRINTK_4(TRACE_3780I,
"3780I::dsp3780I_WriteIStore uCount %x val_lo %x val_hi %x\n",
uCount, val_lo, val_hi);
PaceMsaAccess(usDspBaseIO);
}
PRINTK_1(TRACE_3780I,
"3780I::dsp3780I_WriteIStore exit bRC=true\n");
return 0;
}
@@ -700,12 +515,6 @@ int dsp3780I_GetIPCSource(unsigned short usDspBaseIO,
{
unsigned long flags;
DSP_HBRIDGE_CONTROL rHBridgeControl;
unsigned short temp;
PRINTK_3(TRACE_3780I,
"3780i::dsp3780I_GetIPCSource entry usDspBaseIO %x pusIPCSource %p\n",
usDspBaseIO, pusIPCSource);
/*
* Disable DSP to PC interrupts, read the interrupt register,
@@ -717,22 +526,11 @@ int dsp3780I_GetIPCSource(unsigned short usDspBaseIO,
OutWordDsp(DSP_HBridgeControl, MKWORD(rHBridgeControl));
*pusIPCSource = InWordDsp(DSP_Interrupt);
temp = (unsigned short) ~(*pusIPCSource);
PRINTK_3(TRACE_3780I,
"3780i::dsp3780I_GetIPCSource, usIPCSource %x ~ %x\n",
*pusIPCSource, temp);
OutWordDsp(DSP_Interrupt, (unsigned short) ~(*pusIPCSource));
rHBridgeControl.EnableDspInt = true;
OutWordDsp(DSP_HBridgeControl, MKWORD(rHBridgeControl));
spin_unlock_irqrestore(&dsp_lock, flags);
PRINTK_2(TRACE_3780I,
"3780i::dsp3780I_GetIPCSource exit usIPCSource %x\n",
*pusIPCSource);
return 0;
}

View File

@@ -261,7 +261,7 @@ typedef struct {
* the only values maintained by the 3780i support layer are the saved UART
* registers.
*/
typedef struct _DSP_3780I_CONFIG_SETTINGS {
struct dsp_3780i_config_settings {
/* Location of base configuration register */
unsigned short usBaseConfigIO;
@@ -313,16 +313,16 @@ typedef struct _DSP_3780I_CONFIG_SETTINGS {
unsigned char ucSCR; /* Scratch register */
unsigned char ucDLL; /* Divisor latch, low byte */
unsigned char ucDLM; /* Divisor latch, high byte */
} DSP_3780I_CONFIG_SETTINGS;
};
/* 3780i support functions */
int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings,
int dsp3780I_EnableDSP(struct dsp_3780i_config_settings *pSettings,
unsigned short *pIrqMap,
unsigned short *pDmaMap);
int dsp3780I_DisableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings);
int dsp3780I_Reset(DSP_3780I_CONFIG_SETTINGS * pSettings);
int dsp3780I_Run(DSP_3780I_CONFIG_SETTINGS * pSettings);
int dsp3780I_DisableDSP(struct dsp_3780i_config_settings *pSettings);
int dsp3780I_Reset(struct dsp_3780i_config_settings *pSettings);
int dsp3780I_Run(struct dsp_3780i_config_settings *pSettings);
int dsp3780I_ReadDStore(unsigned short usDspBaseIO, void __user *pvBuffer,
unsigned uCount, unsigned long ulDSPAddr);
int dsp3780I_ReadAndClearDStore(unsigned short usDspBaseIO,

View File

@@ -8,9 +8,3 @@
obj-$(CONFIG_MWAVE) += mwave.o
mwave-y := mwavedd.o smapi.o tp3780i.o 3780i.o
# To have the mwave driver disable other uarts if necessary
# ccflags-y := -DMWAVE_FUTZ_WITH_OTHER_DEVICES
# To compile in lots (~20 KiB) of run-time enablable printk()s for debugging:
ccflags-y += -DMW_TRACE

View File

@@ -4,16 +4,6 @@ Module options
The mwave module takes the following options. Note that these options
are not saved by the BIOS and so do not persist after unload and reload.
mwave_debug=value, where value is bitwise OR of trace flags:
0x0001 mwavedd api tracing
0x0002 smapi api tracing
0x0004 3780i tracing
0x0008 tp3780i tracing
Tracing only occurs if the driver has been compiled with the
MW_TRACE macro #defined (i.e. let ccflags-y := -DMW_TRACE
in the Makefile).
mwave_3780i_irq=5/7/10/11/15
If the dsp irq has not been setup and stored in bios by the
thinkpad configuration utility then this parameter allows the

View File

@@ -46,6 +46,8 @@
* First release to the public
*/
#define pr_fmt(fmt) "mwavedd: " fmt
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
@@ -75,131 +77,62 @@ MODULE_LICENSE("GPL");
* We'll depend on users using the tpctl utility to do that for now
*/
static DEFINE_MUTEX(mwave_mutex);
int mwave_debug = 0;
int mwave_3780i_irq = 0;
int mwave_3780i_io = 0;
int mwave_uart_irq = 0;
int mwave_uart_io = 0;
module_param(mwave_debug, int, 0);
module_param_hw(mwave_3780i_irq, int, irq, 0);
module_param_hw(mwave_3780i_io, int, ioport, 0);
module_param_hw(mwave_uart_irq, int, irq, 0);
module_param_hw(mwave_uart_io, int, ioport, 0);
static int mwave_open(struct inode *inode, struct file *file);
static int mwave_close(struct inode *inode, struct file *file);
static long mwave_ioctl(struct file *filp, unsigned int iocmd,
unsigned long ioarg);
MWAVE_DEVICE_DATA mwave_s_mdd;
static int mwave_open(struct inode *inode, struct file *file)
{
unsigned int retval = 0;
PRINTK_3(TRACE_MWAVE,
"mwavedd::mwave_open, entry inode %p file %p\n",
inode, file);
PRINTK_2(TRACE_MWAVE,
"mwavedd::mwave_open, exit return retval %x\n", retval);
return retval;
}
static int mwave_close(struct inode *inode, struct file *file)
{
unsigned int retval = 0;
PRINTK_3(TRACE_MWAVE,
"mwavedd::mwave_close, entry inode %p file %p\n",
inode, file);
PRINTK_2(TRACE_MWAVE, "mwavedd::mwave_close, exit retval %x\n",
retval);
return retval;
}
struct mwave_device_data mwave_s_mdd;
static long mwave_ioctl(struct file *file, unsigned int iocmd,
unsigned long ioarg)
{
unsigned int retval = 0;
pMWAVE_DEVICE_DATA pDrvData = &mwave_s_mdd;
struct mwave_device_data *pDrvData = &mwave_s_mdd;
void __user *arg = (void __user *)ioarg;
PRINTK_4(TRACE_MWAVE,
"mwavedd::mwave_ioctl, entry file %p cmd %x arg %x\n",
file, iocmd, (int) ioarg);
switch (iocmd) {
case IOCTL_MW_RESET:
PRINTK_1(TRACE_MWAVE,
"mwavedd::mwave_ioctl, IOCTL_MW_RESET"
" calling tp3780I_ResetDSP\n");
mutex_lock(&mwave_mutex);
retval = tp3780I_ResetDSP(&pDrvData->rBDData);
mutex_unlock(&mwave_mutex);
PRINTK_2(TRACE_MWAVE,
"mwavedd::mwave_ioctl, IOCTL_MW_RESET"
" retval %x from tp3780I_ResetDSP\n",
retval);
break;
case IOCTL_MW_RUN:
PRINTK_1(TRACE_MWAVE,
"mwavedd::mwave_ioctl, IOCTL_MW_RUN"
" calling tp3780I_StartDSP\n");
mutex_lock(&mwave_mutex);
retval = tp3780I_StartDSP(&pDrvData->rBDData);
mutex_unlock(&mwave_mutex);
PRINTK_2(TRACE_MWAVE,
"mwavedd::mwave_ioctl, IOCTL_MW_RUN"
" retval %x from tp3780I_StartDSP\n",
retval);
break;
case IOCTL_MW_DSP_ABILITIES: {
MW_ABILITIES rAbilities;
struct mw_abilities rAbilities;
PRINTK_1(TRACE_MWAVE,
"mwavedd::mwave_ioctl,"
" IOCTL_MW_DSP_ABILITIES calling"
" tp3780I_QueryAbilities\n");
mutex_lock(&mwave_mutex);
retval = tp3780I_QueryAbilities(&pDrvData->rBDData,
&rAbilities);
mutex_unlock(&mwave_mutex);
PRINTK_2(TRACE_MWAVE,
"mwavedd::mwave_ioctl, IOCTL_MW_DSP_ABILITIES"
" retval %x from tp3780I_QueryAbilities\n",
retval);
if (retval == 0) {
if( copy_to_user(arg, &rAbilities,
sizeof(MW_ABILITIES)) )
if (copy_to_user(arg, &rAbilities, sizeof(rAbilities)))
return -EFAULT;
}
PRINTK_2(TRACE_MWAVE,
"mwavedd::mwave_ioctl, IOCTL_MW_DSP_ABILITIES"
" exit retval %x\n",
retval);
}
break;
case IOCTL_MW_READ_DATA:
case IOCTL_MW_READCLEAR_DATA: {
MW_READWRITE rReadData;
struct mw_readwrite rReadData;
unsigned short __user *pusBuffer = NULL;
if( copy_from_user(&rReadData, arg,
sizeof(MW_READWRITE)) )
sizeof(struct mw_readwrite)) )
return -EFAULT;
pusBuffer = (unsigned short __user *) (rReadData.pBuf);
PRINTK_4(TRACE_MWAVE,
"mwavedd::mwave_ioctl IOCTL_MW_READ_DATA,"
" size %lx, ioarg %lx pusBuffer %p\n",
rReadData.ulDataLength, ioarg, pusBuffer);
mutex_lock(&mwave_mutex);
retval = tp3780I_ReadWriteDspDStore(&pDrvData->rBDData,
iocmd,
@@ -211,19 +144,13 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd,
break;
case IOCTL_MW_READ_INST: {
MW_READWRITE rReadData;
struct mw_readwrite rReadData;
unsigned short __user *pusBuffer = NULL;
if( copy_from_user(&rReadData, arg,
sizeof(MW_READWRITE)) )
if (copy_from_user(&rReadData, arg, sizeof(rReadData)))
return -EFAULT;
pusBuffer = (unsigned short __user *) (rReadData.pBuf);
PRINTK_4(TRACE_MWAVE,
"mwavedd::mwave_ioctl IOCTL_MW_READ_INST,"
" size %lx, ioarg %lx pusBuffer %p\n",
rReadData.ulDataLength / 2, ioarg,
pusBuffer);
mutex_lock(&mwave_mutex);
retval = tp3780I_ReadWriteDspDStore(&pDrvData->rBDData,
iocmd, pusBuffer,
@@ -234,19 +161,13 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd,
break;
case IOCTL_MW_WRITE_DATA: {
MW_READWRITE rWriteData;
struct mw_readwrite rWriteData;
unsigned short __user *pusBuffer = NULL;
if( copy_from_user(&rWriteData, arg,
sizeof(MW_READWRITE)) )
if (copy_from_user(&rWriteData, arg, sizeof(rWriteData)))
return -EFAULT;
pusBuffer = (unsigned short __user *) (rWriteData.pBuf);
PRINTK_4(TRACE_MWAVE,
"mwavedd::mwave_ioctl IOCTL_MW_WRITE_DATA,"
" size %lx, ioarg %lx pusBuffer %p\n",
rWriteData.ulDataLength, ioarg,
pusBuffer);
mutex_lock(&mwave_mutex);
retval = tp3780I_ReadWriteDspDStore(&pDrvData->rBDData,
iocmd, pusBuffer,
@@ -257,19 +178,13 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd,
break;
case IOCTL_MW_WRITE_INST: {
MW_READWRITE rWriteData;
struct mw_readwrite rWriteData;
unsigned short __user *pusBuffer = NULL;
if( copy_from_user(&rWriteData, arg,
sizeof(MW_READWRITE)) )
if (copy_from_user(&rWriteData, arg, sizeof(rWriteData)))
return -EFAULT;
pusBuffer = (unsigned short __user *)(rWriteData.pBuf);
PRINTK_4(TRACE_MWAVE,
"mwavedd::mwave_ioctl IOCTL_MW_WRITE_INST,"
" size %lx, ioarg %lx pusBuffer %p\n",
rWriteData.ulDataLength, ioarg,
pusBuffer);
mutex_lock(&mwave_mutex);
retval = tp3780I_ReadWriteDspIStore(&pDrvData->rBDData,
iocmd, pusBuffer,
@@ -283,30 +198,17 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd,
unsigned int ipcnum = (unsigned int) ioarg;
if (ipcnum >= ARRAY_SIZE(pDrvData->IPCs)) {
PRINTK_ERROR(KERN_ERR_MWAVE
"mwavedd::mwave_ioctl:"
" IOCTL_MW_REGISTER_IPC:"
" Error: Invalid ipcnum %x\n",
ipcnum);
pr_err("%s: IOCTL_MW_REGISTER_IPC: Error: Invalid ipcnum %x\n",
__func__, ipcnum);
return -EINVAL;
}
ipcnum = array_index_nospec(ipcnum,
ARRAY_SIZE(pDrvData->IPCs));
PRINTK_3(TRACE_MWAVE,
"mwavedd::mwave_ioctl IOCTL_MW_REGISTER_IPC"
" ipcnum %x entry usIntCount %x\n",
ipcnum,
pDrvData->IPCs[ipcnum].usIntCount);
mutex_lock(&mwave_mutex);
pDrvData->IPCs[ipcnum].bIsHere = false;
pDrvData->IPCs[ipcnum].bIsEnabled = true;
mutex_unlock(&mwave_mutex);
PRINTK_2(TRACE_MWAVE,
"mwavedd::mwave_ioctl IOCTL_MW_REGISTER_IPC"
" ipcnum %x exit\n",
ipcnum);
}
break;
@@ -314,28 +216,17 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd,
unsigned int ipcnum = (unsigned int) ioarg;
if (ipcnum >= ARRAY_SIZE(pDrvData->IPCs)) {
PRINTK_ERROR(KERN_ERR_MWAVE
"mwavedd::mwave_ioctl:"
" IOCTL_MW_GET_IPC: Error:"
" Invalid ipcnum %x\n", ipcnum);
pr_err("%s: IOCTL_MW_GET_IPC: Error: Invalid ipcnum %x\n", __func__,
ipcnum);
return -EINVAL;
}
ipcnum = array_index_nospec(ipcnum,
ARRAY_SIZE(pDrvData->IPCs));
PRINTK_3(TRACE_MWAVE,
"mwavedd::mwave_ioctl IOCTL_MW_GET_IPC"
" ipcnum %x, usIntCount %x\n",
ipcnum,
pDrvData->IPCs[ipcnum].usIntCount);
mutex_lock(&mwave_mutex);
if (pDrvData->IPCs[ipcnum].bIsEnabled == true) {
DECLARE_WAITQUEUE(wait, current);
PRINTK_2(TRACE_MWAVE,
"mwavedd::mwave_ioctl, thread for"
" ipc %x going to sleep\n",
ipcnum);
add_wait_queue(&pDrvData->IPCs[ipcnum].ipc_wait_queue, &wait);
pDrvData->IPCs[ipcnum].bIsHere = true;
set_current_state(TASK_INTERRUPTIBLE);
@@ -343,31 +234,15 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd,
/* the interrupt handler while we were gone */
if (pDrvData->IPCs[ipcnum].usIntCount == 1) { /* first int has occurred (race condition) */
pDrvData->IPCs[ipcnum].usIntCount = 2; /* first int has been handled */
PRINTK_2(TRACE_MWAVE,
"mwavedd::mwave_ioctl"
" IOCTL_MW_GET_IPC ipcnum %x"
" handling first int\n",
ipcnum);
} else { /* either 1st int has not yet occurred, or we have already handled the first int */
schedule();
if (pDrvData->IPCs[ipcnum].usIntCount == 1) {
pDrvData->IPCs[ipcnum].usIntCount = 2;
}
PRINTK_2(TRACE_MWAVE,
"mwavedd::mwave_ioctl"
" IOCTL_MW_GET_IPC ipcnum %x"
" woke up and returning to"
" application\n",
ipcnum);
}
pDrvData->IPCs[ipcnum].bIsHere = false;
remove_wait_queue(&pDrvData->IPCs[ipcnum].ipc_wait_queue, &wait);
set_current_state(TASK_RUNNING);
PRINTK_2(TRACE_MWAVE,
"mwavedd::mwave_ioctl IOCTL_MW_GET_IPC,"
" returning thread for ipc %x"
" processing\n",
ipcnum);
}
mutex_unlock(&mwave_mutex);
}
@@ -376,16 +251,9 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd,
case IOCTL_MW_UNREGISTER_IPC: {
unsigned int ipcnum = (unsigned int) ioarg;
PRINTK_2(TRACE_MWAVE,
"mwavedd::mwave_ioctl IOCTL_MW_UNREGISTER_IPC"
" ipcnum %x\n",
ipcnum);
if (ipcnum >= ARRAY_SIZE(pDrvData->IPCs)) {
PRINTK_ERROR(KERN_ERR_MWAVE
"mwavedd::mwave_ioctl:"
" IOCTL_MW_UNREGISTER_IPC:"
" Error: Invalid ipcnum %x\n",
ipcnum);
pr_err("%s: IOCTL_MW_UNREGISTER_IPC: Error: Invalid ipcnum %x\n",
__func__, ipcnum);
return -EINVAL;
}
ipcnum = array_index_nospec(ipcnum,
@@ -405,35 +273,9 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd,
return -ENOTTY;
} /* switch */
PRINTK_2(TRACE_MWAVE, "mwavedd::mwave_ioctl, exit retval %x\n", retval);
return retval;
}
static ssize_t mwave_read(struct file *file, char __user *buf, size_t count,
loff_t * ppos)
{
PRINTK_5(TRACE_MWAVE,
"mwavedd::mwave_read entry file %p, buf %p, count %zx ppos %p\n",
file, buf, count, ppos);
return -EINVAL;
}
static ssize_t mwave_write(struct file *file, const char __user *buf,
size_t count, loff_t * ppos)
{
PRINTK_5(TRACE_MWAVE,
"mwavedd::mwave_write entry file %p, buf %p,"
" count %zx ppos %p\n",
file, buf, count, ppos);
return -EINVAL;
}
static int register_serial_portandirq(unsigned int port, int irq)
{
struct uart_8250_port uart;
@@ -446,9 +288,7 @@ static int register_serial_portandirq(unsigned int port, int irq)
/* OK */
break;
default:
PRINTK_ERROR(KERN_ERR_MWAVE
"mwavedd::register_serial_portandirq:"
" Error: Illegal port %x\n", port );
pr_err("%s: Error: Illegal port %x\n", __func__, port);
return -1;
} /* switch */
/* port is okay */
@@ -461,9 +301,7 @@ static int register_serial_portandirq(unsigned int port, int irq)
/* OK */
break;
default:
PRINTK_ERROR(KERN_ERR_MWAVE
"mwavedd::register_serial_portandirq:"
" Error: Illegal irq %x\n", irq );
pr_err("%s: Error: Illegal irq %x\n", __func__, irq);
return -1;
} /* switch */
/* irq is okay */
@@ -478,56 +316,14 @@ static int register_serial_portandirq(unsigned int port, int irq)
return serial8250_register_8250_port(&uart);
}
static const struct file_operations mwave_fops = {
.owner = THIS_MODULE,
.read = mwave_read,
.write = mwave_write,
.unlocked_ioctl = mwave_ioctl,
.open = mwave_open,
.release = mwave_close,
.llseek = default_llseek,
};
static struct miscdevice mwave_misc_dev = { MWAVE_MINOR, "mwave", &mwave_fops };
#if 0 /* totally b0rked */
/*
* sysfs support <paulsch@us.ibm.com>
*/
struct device mwave_device;
/* Prevent code redundancy, create a macro for mwave_show_* functions. */
#define mwave_show_function(attr_name, format_string, field) \
static ssize_t mwave_show_##attr_name(struct device *dev, struct device_attribute *attr, char *buf) \
{ \
DSP_3780I_CONFIG_SETTINGS *pSettings = \
&mwave_s_mdd.rBDData.rDspSettings; \
return sprintf(buf, format_string, pSettings->field); \
}
/* All of our attributes are read attributes. */
#define mwave_dev_rd_attr(attr_name, format_string, field) \
mwave_show_function(attr_name, format_string, field) \
static DEVICE_ATTR(attr_name, S_IRUGO, mwave_show_##attr_name, NULL)
mwave_dev_rd_attr (3780i_dma, "%i\n", usDspDma);
mwave_dev_rd_attr (3780i_irq, "%i\n", usDspIrq);
mwave_dev_rd_attr (3780i_io, "%#.4x\n", usDspBaseIO);
mwave_dev_rd_attr (uart_irq, "%i\n", usUartIrq);
mwave_dev_rd_attr (uart_io, "%#.4x\n", usUartBaseIO);
static struct device_attribute * const mwave_dev_attrs[] = {
&dev_attr_3780i_dma,
&dev_attr_3780i_irq,
&dev_attr_3780i_io,
&dev_attr_uart_irq,
&dev_attr_uart_io,
};
#endif
/*
* mwave_init is called on module load
*
@@ -536,20 +332,7 @@ static struct device_attribute * const mwave_dev_attrs[] = {
*/
static void mwave_exit(void)
{
pMWAVE_DEVICE_DATA pDrvData = &mwave_s_mdd;
PRINTK_1(TRACE_MWAVE, "mwavedd::mwave_exit entry\n");
#if 0
for (i = 0; i < pDrvData->nr_registered_attrs; i++)
device_remove_file(&mwave_device, mwave_dev_attrs[i]);
pDrvData->nr_registered_attrs = 0;
if (pDrvData->device_registered) {
device_unregister(&mwave_device);
pDrvData->device_registered = false;
}
#endif
struct mwave_device_data *pDrvData = &mwave_s_mdd;
if ( pDrvData->sLine >= 0 ) {
serial8250_unregister_port(pDrvData->sLine);
@@ -566,8 +349,6 @@ static void mwave_exit(void)
if (pDrvData->bBDInitialized) {
tp3780I_Cleanup(&pDrvData->rBDData);
}
PRINTK_1(TRACE_MWAVE, "mwavedd::mwave_exit exit\n");
}
module_exit(mwave_exit);
@@ -576,11 +357,9 @@ static int __init mwave_init(void)
{
int i;
int retval = 0;
pMWAVE_DEVICE_DATA pDrvData = &mwave_s_mdd;
struct mwave_device_data *pDrvData = &mwave_s_mdd;
PRINTK_1(TRACE_MWAVE, "mwavedd::mwave_init entry\n");
memset(&mwave_s_mdd, 0, sizeof(MWAVE_DEVICE_DATA));
memset(&mwave_s_mdd, 0, sizeof(mwave_s_mdd));
pDrvData->bBDInitialized = false;
pDrvData->bResourcesClaimed = false;
@@ -597,60 +376,34 @@ static int __init mwave_init(void)
}
retval = tp3780I_InitializeBoardData(&pDrvData->rBDData);
PRINTK_2(TRACE_MWAVE,
"mwavedd::mwave_init, return from tp3780I_InitializeBoardData"
" retval %x\n",
retval);
if (retval) {
PRINTK_ERROR(KERN_ERR_MWAVE
"mwavedd::mwave_init: Error:"
" Failed to initialize board data\n");
pr_err("%s: Error: Failed to initialize board data\n", __func__);
goto cleanup_error;
}
pDrvData->bBDInitialized = true;
retval = tp3780I_CalcResources(&pDrvData->rBDData);
PRINTK_2(TRACE_MWAVE,
"mwavedd::mwave_init, return from tp3780I_CalcResources"
" retval %x\n",
retval);
if (retval) {
PRINTK_ERROR(KERN_ERR_MWAVE
"mwavedd:mwave_init: Error:"
" Failed to calculate resources\n");
pr_err("%s: Error: Failed to calculate resources\n", __func__);
goto cleanup_error;
}
retval = tp3780I_ClaimResources(&pDrvData->rBDData);
PRINTK_2(TRACE_MWAVE,
"mwavedd::mwave_init, return from tp3780I_ClaimResources"
" retval %x\n",
retval);
if (retval) {
PRINTK_ERROR(KERN_ERR_MWAVE
"mwavedd:mwave_init: Error:"
" Failed to claim resources\n");
pr_err("%s: Error: Failed to claim resources\n", __func__);
goto cleanup_error;
}
pDrvData->bResourcesClaimed = true;
retval = tp3780I_EnableDSP(&pDrvData->rBDData);
PRINTK_2(TRACE_MWAVE,
"mwavedd::mwave_init, return from tp3780I_EnableDSP"
" retval %x\n",
retval);
if (retval) {
PRINTK_ERROR(KERN_ERR_MWAVE
"mwavedd:mwave_init: Error:"
" Failed to enable DSP\n");
pr_err("%s: Error: Failed to enable DSP\n", __func__);
goto cleanup_error;
}
pDrvData->bDSPEnabled = true;
if (misc_register(&mwave_misc_dev) < 0) {
PRINTK_ERROR(KERN_ERR_MWAVE
"mwavedd:mwave_init: Error:"
" Failed to register misc device\n");
pr_err("%s: Error: Failed to register misc device\n", __func__);
goto cleanup_error;
}
pDrvData->bMwaveDevRegistered = true;
@@ -660,40 +413,16 @@ static int __init mwave_init(void)
pDrvData->rBDData.rDspSettings.usUartIrq
);
if (pDrvData->sLine < 0) {
PRINTK_ERROR(KERN_ERR_MWAVE
"mwavedd:mwave_init: Error:"
" Failed to register serial driver\n");
pr_err("%s: Error: Failed to register serial driver\n", __func__);
goto cleanup_error;
}
/* uart is registered */
#if 0
/* sysfs */
memset(&mwave_device, 0, sizeof (struct device));
dev_set_name(&mwave_device, "mwave");
if (device_register(&mwave_device))
goto cleanup_error;
pDrvData->device_registered = true;
for (i = 0; i < ARRAY_SIZE(mwave_dev_attrs); i++) {
if(device_create_file(&mwave_device, mwave_dev_attrs[i])) {
PRINTK_ERROR(KERN_ERR_MWAVE
"mwavedd:mwave_init: Error:"
" Failed to create sysfs file %s\n",
mwave_dev_attrs[i]->attr.name);
goto cleanup_error;
}
pDrvData->nr_registered_attrs++;
}
#endif
/* SUCCESS! */
return 0;
cleanup_error:
PRINTK_ERROR(KERN_ERR_MWAVE
"mwavedd::mwave_init: Error:"
" Failed to initialize\n");
pr_err("%s: Error: Failed to initialize\n", __func__);
mwave_exit(); /* clean up */
return -EIO;

View File

@@ -56,97 +56,35 @@
#include <linux/uaccess.h>
#include <linux/wait.h>
extern int mwave_debug;
extern int mwave_3780i_irq;
extern int mwave_3780i_io;
extern int mwave_uart_irq;
extern int mwave_uart_io;
#define PRINTK_ERROR printk
#define KERN_ERR_MWAVE KERN_ERR "mwave: "
#define TRACE_MWAVE 0x0001
#define TRACE_SMAPI 0x0002
#define TRACE_3780I 0x0004
#define TRACE_TP3780I 0x0008
#ifdef MW_TRACE
#define PRINTK_1(f,s) \
if (f & (mwave_debug)) { \
printk(s); \
}
#define PRINTK_2(f,s,v1) \
if (f & (mwave_debug)) { \
printk(s,v1); \
}
#define PRINTK_3(f,s,v1,v2) \
if (f & (mwave_debug)) { \
printk(s,v1,v2); \
}
#define PRINTK_4(f,s,v1,v2,v3) \
if (f & (mwave_debug)) { \
printk(s,v1,v2,v3); \
}
#define PRINTK_5(f,s,v1,v2,v3,v4) \
if (f & (mwave_debug)) { \
printk(s,v1,v2,v3,v4); \
}
#define PRINTK_6(f,s,v1,v2,v3,v4,v5) \
if (f & (mwave_debug)) { \
printk(s,v1,v2,v3,v4,v5); \
}
#define PRINTK_7(f,s,v1,v2,v3,v4,v5,v6) \
if (f & (mwave_debug)) { \
printk(s,v1,v2,v3,v4,v5,v6); \
}
#define PRINTK_8(f,s,v1,v2,v3,v4,v5,v6,v7) \
if (f & (mwave_debug)) { \
printk(s,v1,v2,v3,v4,v5,v6,v7); \
}
#else
#define PRINTK_1(f,s)
#define PRINTK_2(f,s,v1)
#define PRINTK_3(f,s,v1,v2)
#define PRINTK_4(f,s,v1,v2,v3)
#define PRINTK_5(f,s,v1,v2,v3,v4)
#define PRINTK_6(f,s,v1,v2,v3,v4,v5)
#define PRINTK_7(f,s,v1,v2,v3,v4,v5,v6)
#define PRINTK_8(f,s,v1,v2,v3,v4,v5,v6,v7)
#endif
typedef struct _MWAVE_IPC {
struct mwave_ipc {
unsigned short usIntCount; /* 0=none, 1=first, 2=greater than 1st */
bool bIsEnabled;
bool bIsHere;
/* entry spin lock */
wait_queue_head_t ipc_wait_queue;
} MWAVE_IPC;
};
typedef struct _MWAVE_DEVICE_DATA {
THINKPAD_BD_DATA rBDData; /* board driver's data area */
struct mwave_device_data {
struct thinkpad_bd_data rBDData; /* board driver's data area */
unsigned long ulIPCSource_ISR; /* IPC source bits for recently processed intr, set during ISR processing */
unsigned long ulIPCSource_DPC; /* IPC source bits for recently processed intr, set during DPC processing */
bool bBDInitialized;
bool bResourcesClaimed;
bool bDSPEnabled;
bool bDSPReset;
MWAVE_IPC IPCs[16];
struct mwave_ipc IPCs[16];
bool bMwaveDevRegistered;
short sLine;
int nr_registered_attrs;
int device_registered;
} MWAVE_DEVICE_DATA, *pMWAVE_DEVICE_DATA;
};
extern MWAVE_DEVICE_DATA mwave_s_mdd;
extern struct mwave_device_data mwave_s_mdd;
#endif

View File

@@ -53,7 +53,7 @@
#include <linux/miscdevice.h>
typedef struct _MW_ABILITIES {
struct mw_abilities {
unsigned long instr_per_sec;
unsigned long data_size;
unsigned long inst_size;
@@ -63,27 +63,27 @@ typedef struct _MW_ABILITIES {
unsigned long component_list[7];
char mwave_os_name[16];
char bios_task_name[16];
} MW_ABILITIES, *pMW_ABILITIES;
};
typedef struct _MW_READWRITE {
struct mw_readwrite {
unsigned short usDspAddress; /* The dsp address */
unsigned long ulDataLength; /* The size in bytes of the data or user buffer */
void __user *pBuf; /* Input:variable sized buffer */
} MW_READWRITE, *pMW_READWRITE;
};
#define IOCTL_MW_RESET _IO(MWAVE_MINOR,1)
#define IOCTL_MW_RUN _IO(MWAVE_MINOR,2)
#define IOCTL_MW_DSP_ABILITIES _IOR(MWAVE_MINOR,3,MW_ABILITIES)
#define IOCTL_MW_READ_DATA _IOR(MWAVE_MINOR,4,MW_READWRITE)
#define IOCTL_MW_READCLEAR_DATA _IOR(MWAVE_MINOR,5,MW_READWRITE)
#define IOCTL_MW_READ_INST _IOR(MWAVE_MINOR,6,MW_READWRITE)
#define IOCTL_MW_WRITE_DATA _IOW(MWAVE_MINOR,7,MW_READWRITE)
#define IOCTL_MW_WRITE_INST _IOW(MWAVE_MINOR,8,MW_READWRITE)
#define IOCTL_MW_DSP_ABILITIES _IOR(MWAVE_MINOR,3,struct mw_abilities)
#define IOCTL_MW_READ_DATA _IOR(MWAVE_MINOR,4,struct mw_readwrite)
#define IOCTL_MW_READCLEAR_DATA _IOR(MWAVE_MINOR,5,struct mw_readwrite)
#define IOCTL_MW_READ_INST _IOR(MWAVE_MINOR,6,struct mw_readwrite)
#define IOCTL_MW_WRITE_DATA _IOW(MWAVE_MINOR,7,struct mw_readwrite)
#define IOCTL_MW_WRITE_INST _IOW(MWAVE_MINOR,8,struct mw_readwrite)
#define IOCTL_MW_REGISTER_IPC _IOW(MWAVE_MINOR,9,int)
#define IOCTL_MW_UNREGISTER_IPC _IOW(MWAVE_MINOR,10,int)
#define IOCTL_MW_GET_IPC _IOW(MWAVE_MINOR,11,int)
#define IOCTL_MW_TRACE _IOR(MWAVE_MINOR,12,MW_READWRITE)
#define IOCTL_MW_TRACE _IOR(MWAVE_MINOR,12,struct mw_readwrite)
#endif

View File

@@ -46,6 +46,8 @@
* First release to the public
*/
#define pr_fmt(fmt) "smapi: " fmt
#include <linux/kernel.h>
#include <linux/mc146818rtc.h> /* CMOS defines */
#include "smapi.h"
@@ -69,10 +71,6 @@ static int smapi_request(unsigned short inBX, unsigned short inCX,
unsigned short usSmapiOK = -EIO, *pusSmapiOK = &usSmapiOK;
unsigned int inBXCX = (inBX << 16) | inCX;
unsigned int inDISI = (inDI << 16) | inSI;
int retval = 0;
PRINTK_5(TRACE_SMAPI, "inBX %x inCX %x inDI %x inSI %x\n",
inBX, inCX, inDI, inSI);
__asm__ __volatile__("movw $0x5380,%%ax\n\t"
"movl %7,%%ebx\n\t"
@@ -107,10 +105,6 @@ static int smapi_request(unsigned short inBX, unsigned short inCX,
:"%eax", "%ebx", "%ecx", "%edx", "%edi",
"%esi");
PRINTK_8(TRACE_SMAPI,
"myoutAX %x myoutBX %x myoutCX %x myoutDX %x myoutDI %x myoutSI %x usSmapiOK %x\n",
myoutAX, myoutBX, myoutCX, myoutDX, myoutDI, myoutSI,
usSmapiOK);
*outAX = myoutAX;
*outBX = myoutBX;
*outCX = myoutCX;
@@ -118,13 +112,11 @@ static int smapi_request(unsigned short inBX, unsigned short inCX,
*outDI = myoutDI;
*outSI = myoutSI;
retval = (usSmapiOK == 1) ? 0 : -EIO;
PRINTK_2(TRACE_SMAPI, "smapi::smapi_request exit retval %x\n", retval);
return retval;
return usSmapiOK == 1 ? 0 : -EIO;
}
int smapi_query_DSP_cfg(SMAPI_DSP_SETTINGS * pSettings)
int smapi_query_DSP_cfg(struct smapi_dsp_settings *pSettings)
{
int bRC;
unsigned short usAX, usBX, usCX, usDX, usDI, usSI;
@@ -134,17 +126,13 @@ int smapi_query_DSP_cfg(SMAPI_DSP_SETTINGS * pSettings)
static const unsigned short ausUartBases[] = {
0x03F8, 0x02F8, 0x03E8, 0x02E8 };
PRINTK_1(TRACE_SMAPI, "smapi::smapi_query_DSP_cfg entry\n");
bRC = smapi_request(0x1802, 0x0000, 0, 0,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) {
PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_query_DSP_cfg: Error: Could not get DSP Settings. Aborting.\n");
pr_err("%s: Error: Could not get DSP Settings. Aborting.\n", __func__);
return bRC;
}
PRINTK_1(TRACE_SMAPI, "smapi::smapi_query_DSP_cfg, smapi_request OK\n");
pSettings->bDSPPresent = ((usBX & 0x0100) != 0);
pSettings->bDSPEnabled = ((usCX & 0x0001) != 0);
pSettings->usDspIRQ = usSI & 0x00FF;
@@ -154,27 +142,20 @@ int smapi_query_DSP_cfg(SMAPI_DSP_SETTINGS * pSettings)
} else {
pSettings->usDspBaseIO = 0;
}
PRINTK_6(TRACE_SMAPI,
"smapi::smapi_query_DSP_cfg get DSP Settings bDSPPresent %x bDSPEnabled %x usDspIRQ %x usDspDMA %x usDspBaseIO %x\n",
pSettings->bDSPPresent, pSettings->bDSPEnabled,
pSettings->usDspIRQ, pSettings->usDspDMA,
pSettings->usDspBaseIO);
/* check for illegal values */
if ( pSettings->usDspBaseIO == 0 )
PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_query_DSP_cfg: Worry: DSP base I/O address is 0\n");
pr_err("%s: Worry: DSP base I/O address is 0\n", __func__);
if ( pSettings->usDspIRQ == 0 )
PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_query_DSP_cfg: Worry: DSP IRQ line is 0\n");
pr_err("%s: Worry: DSP IRQ line is 0\n", __func__);
bRC = smapi_request(0x1804, 0x0000, 0, 0,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) {
PRINTK_ERROR("smapi::smapi_query_DSP_cfg: Error: Could not get DSP modem settings. Aborting.\n");
pr_err("%s: Error: Could not get DSP modem settings. Aborting.\n", __func__);
return bRC;
}
PRINTK_1(TRACE_SMAPI, "smapi::smapi_query_DSP_cfg, smapi_request OK\n");
pSettings->bModemEnabled = ((usCX & 0x0001) != 0);
pSettings->usUartIRQ = usSI & 0x000F;
if (((usSI & 0xFF00) >> 8) < ARRAY_SIZE(ausUartBases)) {
@@ -183,19 +164,11 @@ int smapi_query_DSP_cfg(SMAPI_DSP_SETTINGS * pSettings)
pSettings->usUartBaseIO = 0;
}
PRINTK_4(TRACE_SMAPI,
"smapi::smapi_query_DSP_cfg get DSP modem settings bModemEnabled %x usUartIRQ %x usUartBaseIO %x\n",
pSettings->bModemEnabled,
pSettings->usUartIRQ,
pSettings->usUartBaseIO);
/* check for illegal values */
if ( pSettings->usUartBaseIO == 0 )
PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_query_DSP_cfg: Worry: UART base I/O address is 0\n");
pr_err("%s: Worry: UART base I/O address is 0\n", __func__);
if ( pSettings->usUartIRQ == 0 )
PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_query_DSP_cfg: Worry: UART IRQ line is 0\n");
PRINTK_2(TRACE_SMAPI, "smapi::smapi_query_DSP_cfg exit bRC %x\n", bRC);
pr_err("%s: Worry: UART IRQ line is 0\n", __func__);
return bRC;
}
@@ -218,17 +191,14 @@ int smapi_set_DSP_cfg(void)
unsigned short dspio_index = 0, uartio_index = 0;
PRINTK_5(TRACE_SMAPI,
"smapi::smapi_set_DSP_cfg entry mwave_3780i_irq %x mwave_3780i_io %x mwave_uart_irq %x mwave_uart_io %x\n",
mwave_3780i_irq, mwave_3780i_io, mwave_uart_irq, mwave_uart_io);
if (mwave_3780i_io) {
for (i = 0; i < ARRAY_SIZE(ausDspBases); i++) {
if (mwave_3780i_io == ausDspBases[i])
break;
}
if (i == ARRAY_SIZE(ausDspBases)) {
PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_set_DSP_cfg: Error: Invalid mwave_3780i_io address %x. Aborting.\n", mwave_3780i_io);
pr_err("%s: Error: Invalid mwave_3780i_io address %x. Aborting.\n",
__func__, mwave_3780i_io);
return bRC;
}
dspio_index = i;
@@ -240,7 +210,8 @@ int smapi_set_DSP_cfg(void)
break;
}
if (i == ARRAY_SIZE(ausDspIrqs)) {
PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_set_DSP_cfg: Error: Invalid mwave_3780i_irq %x. Aborting.\n", mwave_3780i_irq);
pr_err("%s: Error: Invalid mwave_3780i_irq %x. Aborting.\n", __func__,
mwave_3780i_irq);
return bRC;
}
}
@@ -251,7 +222,8 @@ int smapi_set_DSP_cfg(void)
break;
}
if (i == ARRAY_SIZE(ausUartBases)) {
PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_set_DSP_cfg: Error: Invalid mwave_uart_io address %x. Aborting.\n", mwave_uart_io);
pr_err("%s: Error: Invalid mwave_uart_io address %x. Aborting.\n", __func__,
mwave_uart_io);
return bRC;
}
uartio_index = i;
@@ -264,7 +236,8 @@ int smapi_set_DSP_cfg(void)
break;
}
if (i == ARRAY_SIZE(ausUartIrqs)) {
PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_set_DSP_cfg: Error: Invalid mwave_uart_irq %x. Aborting.\n", mwave_uart_irq);
pr_err("%s: Error: Invalid mwave_uart_irq %x. Aborting.\n", __func__,
mwave_uart_irq);
return bRC;
}
}
@@ -279,46 +252,15 @@ int smapi_set_DSP_cfg(void)
if (usBX & 0x0100) { /* serial port A is present */
if (usCX & 1) { /* serial port is enabled */
if ((usSI & 0xFF) == mwave_uart_irq) {
#ifndef MWAVE_FUTZ_WITH_OTHER_DEVICES
PRINTK_ERROR(KERN_ERR_MWAVE
"smapi::smapi_set_DSP_cfg: Serial port A irq %x conflicts with mwave_uart_irq %x\n", usSI & 0xFF, mwave_uart_irq);
#else
PRINTK_3(TRACE_SMAPI,
"smapi::smapi_set_DSP_cfg: Serial port A irq %x conflicts with mwave_uart_irq %x\n", usSI & 0xFF, mwave_uart_irq);
#endif
#ifdef MWAVE_FUTZ_WITH_OTHER_DEVICES
PRINTK_1(TRACE_SMAPI,
"smapi::smapi_set_DSP_cfg Disabling conflicting serial port\n");
bRC = smapi_request(0x1403, 0x0100, 0, usSI,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
bRC = smapi_request(0x1402, 0x0000, 0, 0,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
#else
pr_err("%s: Serial port A irq %x conflicts with mwave_uart_irq %x\n",
__func__, usSI & 0xFF, mwave_uart_irq);
goto exit_conflict;
#endif
} else {
if ((usSI >> 8) == uartio_index) {
#ifndef MWAVE_FUTZ_WITH_OTHER_DEVICES
PRINTK_ERROR(KERN_ERR_MWAVE
"smapi::smapi_set_DSP_cfg: Serial port A base I/O address %x conflicts with mwave uart I/O %x\n", ausUartBases[usSI >> 8], ausUartBases[uartio_index]);
#else
PRINTK_3(TRACE_SMAPI,
"smapi::smapi_set_DSP_cfg: Serial port A base I/O address %x conflicts with mwave uart I/O %x\n", ausUartBases[usSI >> 8], ausUartBases[uartio_index]);
#endif
#ifdef MWAVE_FUTZ_WITH_OTHER_DEVICES
PRINTK_1(TRACE_SMAPI,
"smapi::smapi_set_DSP_cfg Disabling conflicting serial port A\n");
bRC = smapi_request (0x1403, 0x0100, 0, usSI,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
bRC = smapi_request (0x1402, 0x0000, 0, 0,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
#else
pr_err("%s: Serial port A base I/O address %x conflicts with mwave uart I/O %x\n",
__func__, ausUartBases[usSI >> 8],
ausUartBases[uartio_index]);
goto exit_conflict;
#endif
}
}
}
@@ -332,46 +274,15 @@ int smapi_set_DSP_cfg(void)
if (usBX & 0x0100) { /* serial port B is present */
if (usCX & 1) { /* serial port is enabled */
if ((usSI & 0xFF) == mwave_uart_irq) {
#ifndef MWAVE_FUTZ_WITH_OTHER_DEVICES
PRINTK_ERROR(KERN_ERR_MWAVE
"smapi::smapi_set_DSP_cfg: Serial port B irq %x conflicts with mwave_uart_irq %x\n", usSI & 0xFF, mwave_uart_irq);
#else
PRINTK_3(TRACE_SMAPI,
"smapi::smapi_set_DSP_cfg: Serial port B irq %x conflicts with mwave_uart_irq %x\n", usSI & 0xFF, mwave_uart_irq);
#endif
#ifdef MWAVE_FUTZ_WITH_OTHER_DEVICES
PRINTK_1(TRACE_SMAPI,
"smapi::smapi_set_DSP_cfg Disabling conflicting serial port B\n");
bRC = smapi_request(0x1405, 0x0100, 0, usSI,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
bRC = smapi_request(0x1404, 0x0000, 0, 0,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
#else
pr_err("%s: Serial port B irq %x conflicts with mwave_uart_irq %x\n",
__func__, usSI & 0xFF, mwave_uart_irq);
goto exit_conflict;
#endif
} else {
if ((usSI >> 8) == uartio_index) {
#ifndef MWAVE_FUTZ_WITH_OTHER_DEVICES
PRINTK_ERROR(KERN_ERR_MWAVE
"smapi::smapi_set_DSP_cfg: Serial port B base I/O address %x conflicts with mwave uart I/O %x\n", ausUartBases[usSI >> 8], ausUartBases[uartio_index]);
#else
PRINTK_3(TRACE_SMAPI,
"smapi::smapi_set_DSP_cfg: Serial port B base I/O address %x conflicts with mwave uart I/O %x\n", ausUartBases[usSI >> 8], ausUartBases[uartio_index]);
#endif
#ifdef MWAVE_FUTZ_WITH_OTHER_DEVICES
PRINTK_1 (TRACE_SMAPI,
"smapi::smapi_set_DSP_cfg Disabling conflicting serial port B\n");
bRC = smapi_request (0x1405, 0x0100, 0, usSI,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
bRC = smapi_request (0x1404, 0x0000, 0, 0,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
#else
pr_err("%s: Serial port B base I/O address %x conflicts with mwave uart I/O %x\n",
__func__, ausUartBases[usSI >> 8],
ausUartBases[uartio_index]);
goto exit_conflict;
#endif
}
}
}
@@ -387,58 +298,15 @@ int smapi_set_DSP_cfg(void)
/* bRC == 0 */
if ((usCX & 0xff) != 0xff) { /* IR port not disabled */
if ((usCX & 0xff) == mwave_uart_irq) {
#ifndef MWAVE_FUTZ_WITH_OTHER_DEVICES
PRINTK_ERROR(KERN_ERR_MWAVE
"smapi::smapi_set_DSP_cfg: IR port irq %x conflicts with mwave_uart_irq %x\n", usCX & 0xff, mwave_uart_irq);
#else
PRINTK_3(TRACE_SMAPI,
"smapi::smapi_set_DSP_cfg: IR port irq %x conflicts with mwave_uart_irq %x\n", usCX & 0xff, mwave_uart_irq);
#endif
#ifdef MWAVE_FUTZ_WITH_OTHER_DEVICES
PRINTK_1(TRACE_SMAPI,
"smapi::smapi_set_DSP_cfg Disabling conflicting IR port\n");
bRC = smapi_request(0x1701, 0x0100, 0, 0,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
bRC = smapi_request(0x1700, 0, 0, 0,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
bRC = smapi_request(0x1705, 0x01ff, 0, usSI,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
bRC = smapi_request(0x1704, 0x0000, 0, 0,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
#else
pr_err("%s: IR port irq %x conflicts with mwave_uart_irq %x\n",
__func__, usCX & 0xff, mwave_uart_irq);
goto exit_conflict;
#endif
} else {
if ((usSI & 0xff) == uartio_index) {
#ifndef MWAVE_FUTZ_WITH_OTHER_DEVICES
PRINTK_ERROR(KERN_ERR_MWAVE
"smapi::smapi_set_DSP_cfg: IR port base I/O address %x conflicts with mwave uart I/O %x\n", ausUartBases[usSI & 0xff], ausUartBases[uartio_index]);
#else
PRINTK_3(TRACE_SMAPI,
"smapi::smapi_set_DSP_cfg: IR port base I/O address %x conflicts with mwave uart I/O %x\n", ausUartBases[usSI & 0xff], ausUartBases[uartio_index]);
#endif
#ifdef MWAVE_FUTZ_WITH_OTHER_DEVICES
PRINTK_1(TRACE_SMAPI,
"smapi::smapi_set_DSP_cfg Disabling conflicting IR port\n");
bRC = smapi_request(0x1701, 0x0100, 0, 0,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
bRC = smapi_request(0x1700, 0, 0, 0,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
bRC = smapi_request(0x1705, 0x01ff, 0, usSI,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
bRC = smapi_request(0x1704, 0x0000, 0, 0,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC) goto exit_smapi_request_error;
#else
pr_err("%s: IR port base I/O address %x conflicts with mwave uart I/O %x\n",
__func__, ausUartBases[usSI & 0xff],
ausUartBases[uartio_index]);
goto exit_conflict;
#endif
}
}
}
@@ -482,7 +350,6 @@ int smapi_set_DSP_cfg(void)
if (bRC) goto exit_smapi_request_error;
/* normal exit: */
PRINTK_1(TRACE_SMAPI, "smapi::smapi_set_DSP_cfg exit\n");
return 0;
exit_conflict:
@@ -490,64 +357,32 @@ exit_conflict:
return -EIO;
exit_smapi_request_error:
PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_set_DSP_cfg exit on smapi_request error bRC %x\n", bRC);
pr_err("%s: exit on smapi_request error bRC %x\n", __func__, bRC);
return bRC;
}
int smapi_set_DSP_power_state(bool bOn)
{
int bRC;
unsigned short usAX, usBX, usCX, usDX, usDI, usSI;
unsigned short usPowerFunction;
PRINTK_2(TRACE_SMAPI, "smapi::smapi_set_DSP_power_state entry bOn %x\n", bOn);
usPowerFunction = (bOn) ? 1 : 0;
bRC = smapi_request(0x4901, 0x0000, 0, usPowerFunction,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
PRINTK_2(TRACE_SMAPI, "smapi::smapi_set_DSP_power_state exit bRC %x\n", bRC);
return bRC;
return smapi_request(0x4901, 0x0000, 0, usPowerFunction, &usAX, &usBX, &usCX, &usDX, &usDI,
&usSI);
}
#if 0
static int SmapiQuerySystemID(void)
{
int bRC = -EIO;
unsigned short usAX = 0xffff, usBX = 0xffff, usCX = 0xffff,
usDX = 0xffff, usDI = 0xffff, usSI = 0xffff;
printk("smapi::SmapiQUerySystemID entry\n");
bRC = smapi_request(0x0000, 0, 0, 0,
&usAX, &usBX, &usCX, &usDX, &usDI, &usSI);
if (bRC == 0) {
printk("AX=%x, BX=%x, CX=%x, DX=%x, DI=%x, SI=%x\n",
usAX, usBX, usCX, usDX, usDI, usSI);
} else {
printk("smapi::SmapiQuerySystemID smapi_request error\n");
}
return bRC;
}
#endif /* 0 */
int smapi_init(void)
{
int retval = -EIO;
unsigned short usSmapiID = 0;
unsigned long flags;
PRINTK_1(TRACE_SMAPI, "smapi::smapi_init entry\n");
spin_lock_irqsave(&rtc_lock, flags);
usSmapiID = CMOS_READ(0x7C);
usSmapiID |= (CMOS_READ(0x7D) << 8);
spin_unlock_irqrestore(&rtc_lock, flags);
PRINTK_2(TRACE_SMAPI, "smapi::smapi_init usSmapiID %x\n", usSmapiID);
if (usSmapiID == 0x5349) {
spin_lock_irqsave(&rtc_lock, flags);
@@ -555,16 +390,13 @@ int smapi_init(void)
g_usSmapiPort |= (CMOS_READ(0x7F) << 8);
spin_unlock_irqrestore(&rtc_lock, flags);
if (g_usSmapiPort == 0) {
PRINTK_ERROR("smapi::smapi_init, ERROR unable to read from SMAPI port\n");
pr_err("%s: ERROR unable to read from SMAPI port\n", __func__);
} else {
PRINTK_2(TRACE_SMAPI,
"smapi::smapi_init, exit true g_usSmapiPort %x\n",
g_usSmapiPort);
retval = 0;
//SmapiQuerySystemID();
}
} else {
PRINTK_ERROR("smapi::smapi_init, ERROR invalid usSmapiID\n");
pr_err("%s: ERROR invalid usSmapiID\n", __func__);
retval = -ENXIO;
}

View File

@@ -49,7 +49,7 @@
#ifndef _LINUX_SMAPI_H
#define _LINUX_SMAPI_H
typedef struct {
struct smapi_dsp_settings {
int bDSPPresent;
int bDSPEnabled;
int bModemEnabled;
@@ -65,10 +65,10 @@ typedef struct {
unsigned short usSndblstIRQ;
unsigned short usSndblstDMA;
unsigned short usSndblstBaseIO;
} SMAPI_DSP_SETTINGS;
};
int smapi_init(void);
int smapi_query_DSP_cfg(SMAPI_DSP_SETTINGS * pSettings);
int smapi_query_DSP_cfg(struct smapi_dsp_settings *pSettings);
int smapi_set_DSP_cfg(void);
int smapi_set_DSP_power_state(bool bOn);

View File

@@ -46,6 +46,8 @@
* First release to the public
*/
#define pr_fmt(fmt) "tp3780i: " fmt
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/ptrace.h>
@@ -65,16 +67,14 @@ static unsigned short s_ausThinkpadDmaToField[8] =
static unsigned short s_numIrqs = 16, s_numDmas = 8;
static void EnableSRAM(THINKPAD_BD_DATA * pBDData)
static void EnableSRAM(struct thinkpad_bd_data *pBDData)
{
DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
struct dsp_3780i_config_settings *pSettings = &pBDData->rDspSettings;
unsigned short usDspBaseIO = pSettings->usDspBaseIO;
DSP_GPIO_OUTPUT_DATA_15_8 rGpioOutputData;
DSP_GPIO_DRIVER_ENABLE_15_8 rGpioDriverEnable;
DSP_GPIO_MODE_15_8 rGpioMode;
PRINTK_1(TRACE_TP3780I, "tp3780i::EnableSRAM, entry\n");
MKWORD(rGpioMode) = ReadMsaCfg(DSP_GpioModeControl_15_8);
rGpioMode.GpioMode10 = 0;
WriteMsaCfg(DSP_GpioModeControl_15_8, MKWORD(rGpioMode));
@@ -88,54 +88,31 @@ static void EnableSRAM(THINKPAD_BD_DATA * pBDData)
rGpioOutputData.Latch10 = 0;
rGpioOutputData.Mask10 = true;
WriteMsaCfg(DSP_GpioOutputData_15_8, MKWORD(rGpioOutputData));
PRINTK_1(TRACE_TP3780I, "tp3780i::EnableSRAM exit\n");
}
static irqreturn_t UartInterrupt(int irq, void *dev_id)
{
PRINTK_3(TRACE_TP3780I,
"tp3780i::UartInterrupt entry irq %x dev_id %p\n", irq, dev_id);
return IRQ_HANDLED;
}
static irqreturn_t DspInterrupt(int irq, void *dev_id)
{
pMWAVE_DEVICE_DATA pDrvData = &mwave_s_mdd;
DSP_3780I_CONFIG_SETTINGS *pSettings = &pDrvData->rBDData.rDspSettings;
struct mwave_device_data *pDrvData = &mwave_s_mdd;
struct dsp_3780i_config_settings *pSettings = &pDrvData->rBDData.rDspSettings;
unsigned short usDspBaseIO = pSettings->usDspBaseIO;
unsigned short usIPCSource = 0, usIsolationMask, usPCNum;
PRINTK_3(TRACE_TP3780I,
"tp3780i::DspInterrupt entry irq %x dev_id %p\n", irq, dev_id);
if (dsp3780I_GetIPCSource(usDspBaseIO, &usIPCSource) == 0) {
PRINTK_2(TRACE_TP3780I,
"tp3780i::DspInterrupt, return from dsp3780i_GetIPCSource, usIPCSource %x\n",
usIPCSource);
usIsolationMask = 1;
for (usPCNum = 1; usPCNum <= 16; usPCNum++) {
if (usIPCSource & usIsolationMask) {
usIPCSource &= ~usIsolationMask;
PRINTK_3(TRACE_TP3780I,
"tp3780i::DspInterrupt usPCNum %x usIPCSource %x\n",
usPCNum, usIPCSource);
if (pDrvData->IPCs[usPCNum - 1].usIntCount == 0) {
pDrvData->IPCs[usPCNum - 1].usIntCount = 1;
}
PRINTK_2(TRACE_TP3780I,
"tp3780i::DspInterrupt usIntCount %x\n",
pDrvData->IPCs[usPCNum - 1].usIntCount);
if (pDrvData->IPCs[usPCNum - 1].bIsEnabled == true) {
PRINTK_2(TRACE_TP3780I,
"tp3780i::DspInterrupt, waking up usPCNum %x\n",
usPCNum - 1);
wake_up_interruptible(&pDrvData->IPCs[usPCNum - 1].ipc_wait_queue);
} else {
PRINTK_2(TRACE_TP3780I,
"tp3780i::DspInterrupt, no one waiting for IPC %x\n",
usPCNum - 1);
}
}
if (usIPCSource == 0)
@@ -143,56 +120,42 @@ static irqreturn_t DspInterrupt(int irq, void *dev_id)
/* try next IPC */
usIsolationMask = usIsolationMask << 1;
}
} else {
PRINTK_1(TRACE_TP3780I,
"tp3780i::DspInterrupt, return false from dsp3780i_GetIPCSource\n");
}
PRINTK_1(TRACE_TP3780I, "tp3780i::DspInterrupt exit\n");
return IRQ_HANDLED;
}
int tp3780I_InitializeBoardData(THINKPAD_BD_DATA * pBDData)
int tp3780I_InitializeBoardData(struct thinkpad_bd_data *pBDData)
{
int retval = 0;
DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_InitializeBoardData entry pBDData %p\n", pBDData);
struct dsp_3780i_config_settings *pSettings = &pBDData->rDspSettings;
pBDData->bDSPEnabled = false;
pSettings->bInterruptClaimed = false;
retval = smapi_init();
if (retval) {
PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_InitializeBoardData: Error: SMAPI is not available on this machine\n");
pr_err("%s: Error: SMAPI is not available on this machine\n", __func__);
} else {
if (mwave_3780i_irq || mwave_3780i_io || mwave_uart_irq || mwave_uart_io) {
retval = smapi_set_DSP_cfg();
}
}
PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_InitializeBoardData exit retval %x\n", retval);
return retval;
}
void tp3780I_Cleanup(THINKPAD_BD_DATA *pBDData)
void tp3780I_Cleanup(struct thinkpad_bd_data *pBDData)
{
PRINTK_2(TRACE_TP3780I,
"tp3780i::tp3780I_Cleanup entry and exit pBDData %p\n", pBDData);
}
int tp3780I_CalcResources(THINKPAD_BD_DATA * pBDData)
int tp3780I_CalcResources(struct thinkpad_bd_data *pBDData)
{
SMAPI_DSP_SETTINGS rSmapiInfo;
DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
PRINTK_2(TRACE_TP3780I,
"tp3780i::tp3780I_CalcResources entry pBDData %p\n", pBDData);
struct smapi_dsp_settings rSmapiInfo;
struct dsp_3780i_config_settings *pSettings = &pBDData->rDspSettings;
if (smapi_query_DSP_cfg(&rSmapiInfo)) {
PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_CalcResources: Error: Could not query DSP config. Aborting.\n");
pr_err("%s: Error: Could not query DSP config. Aborting.\n", __func__);
return -EIO;
}
@@ -203,7 +166,7 @@ int tp3780I_CalcResources(THINKPAD_BD_DATA * pBDData)
|| ( rSmapiInfo.usUartIRQ == 0 )
|| ( rSmapiInfo.usUartBaseIO == 0 )
) {
PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_CalcResources: Error: Illegal resource setting. Aborting.\n");
pr_err("%s: Error: Illegal resource setting. Aborting.\n", __func__);
return -EIO;
}
@@ -225,41 +188,31 @@ int tp3780I_CalcResources(THINKPAD_BD_DATA * pBDData)
pBDData->bShareDspIrq = pBDData->bShareUartIrq = 0;
}
PRINTK_1(TRACE_TP3780I, "tp3780i::tp3780I_CalcResources exit\n");
return 0;
}
int tp3780I_ClaimResources(THINKPAD_BD_DATA * pBDData)
int tp3780I_ClaimResources(struct thinkpad_bd_data *pBDData)
{
int retval = 0;
DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
struct dsp_3780i_config_settings *pSettings = &pBDData->rDspSettings;
struct resource *pres;
PRINTK_2(TRACE_TP3780I,
"tp3780i::tp3780I_ClaimResources entry pBDData %p\n", pBDData);
pres = request_region(pSettings->usDspBaseIO, 16, "mwave_3780i");
if ( pres == NULL ) retval = -EIO;
if (retval) {
PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_ClaimResources: Error: Could not claim I/O region starting at %x\n", pSettings->usDspBaseIO);
retval = -EIO;
pr_err("%s: Error: Could not claim I/O region starting at %x\n", __func__,
pSettings->usDspBaseIO);
return -EIO;
}
PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_ClaimResources exit retval %x\n", retval);
return retval;
}
int tp3780I_ReleaseResources(THINKPAD_BD_DATA * pBDData)
int tp3780I_ReleaseResources(struct thinkpad_bd_data *pBDData)
{
int retval = 0;
DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
PRINTK_2(TRACE_TP3780I,
"tp3780i::tp3780I_ReleaseResources entry pBDData %p\n", pBDData);
struct dsp_3780i_config_settings *pSettings = &pBDData->rDspSettings;
release_region(pSettings->usDspBaseIO & (~3), 16);
@@ -268,28 +221,23 @@ int tp3780I_ReleaseResources(THINKPAD_BD_DATA * pBDData)
pSettings->bInterruptClaimed = false;
}
PRINTK_2(TRACE_TP3780I,
"tp3780i::tp3780I_ReleaseResources exit retval %x\n", retval);
return retval;
return 0;
}
int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData)
int tp3780I_EnableDSP(struct thinkpad_bd_data *pBDData)
{
DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
struct dsp_3780i_config_settings *pSettings = &pBDData->rDspSettings;
bool bDSPPoweredUp = false, bInterruptAllocated = false;
PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_EnableDSP entry pBDData %p\n", pBDData);
if (pBDData->bDSPEnabled) {
PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_EnableDSP: Error: DSP already enabled!\n");
pr_err("%s: Error: DSP already enabled!\n", __func__);
goto exit_cleanup;
}
if (!pSettings->bDSPEnabled) {
PRINTK_ERROR(KERN_ERR_MWAVE "tp3780::tp3780I_EnableDSP: Error: pSettings->bDSPEnabled not set\n");
pr_err("%s: Error: pSettings->bDSPEnabled not set\n", __func__);
goto exit_cleanup;
}
@@ -299,7 +247,7 @@ int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData)
|| (s_ausThinkpadIrqToField[pSettings->usDspIrq] == 0xFFFF)
|| (s_ausThinkpadDmaToField[pSettings->usDspDma] == 0xFFFF)
) {
PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_EnableDSP: Error: invalid irq %x\n", pSettings->usDspIrq);
pr_err("%s: Error: invalid irq %x\n", __func__, pSettings->usDspIrq);
goto exit_cleanup;
}
@@ -307,7 +255,8 @@ int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData)
((pSettings->usDspBaseIO & 0xF00F) != 0)
|| (pSettings->usDspBaseIO & 0x0FF0) == 0
) {
PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_EnableDSP: Error: Invalid DSP base I/O address %x\n", pSettings->usDspBaseIO);
pr_err("%s: Error: Invalid DSP base I/O address %x\n", __func__,
pSettings->usDspBaseIO);
goto exit_cleanup;
}
@@ -316,7 +265,7 @@ int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData)
pSettings->usUartIrq >= s_numIrqs
|| s_ausThinkpadIrqToField[pSettings->usUartIrq] == 0xFFFF
) {
PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_EnableDSP: Error: Invalid UART IRQ %x\n", pSettings->usUartIrq);
pr_err("%s: Error: Invalid UART IRQ %x\n", __func__, pSettings->usUartIrq);
goto exit_cleanup;
}
switch (pSettings->usUartBaseIO) {
@@ -327,7 +276,8 @@ int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData)
break;
default:
PRINTK_ERROR("tp3780i::tp3780I_EnableDSP: Error: Invalid UART base I/O address %x\n", pSettings->usUartBaseIO);
pr_err("%s: Error: Invalid UART base I/O address %x\n", __func__,
pSettings->usUartBaseIO);
goto exit_cleanup;
}
}
@@ -356,33 +306,30 @@ int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData)
pSettings->usChipletEnable = TP_CFG_ChipletEnable;
if (request_irq(pSettings->usUartIrq, &UartInterrupt, 0, "mwave_uart", NULL)) {
PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_EnableDSP: Error: Could not get UART IRQ %x\n", pSettings->usUartIrq);
pr_err("%s: Error: Could not get UART IRQ %x\n", __func__, pSettings->usUartIrq);
goto exit_cleanup;
} else { /* no conflict just release */
free_irq(pSettings->usUartIrq, NULL);
}
if (request_irq(pSettings->usDspIrq, &DspInterrupt, 0, "mwave_3780i", NULL)) {
PRINTK_ERROR("tp3780i::tp3780I_EnableDSP: Error: Could not get 3780i IRQ %x\n", pSettings->usDspIrq);
pr_err("%s: Error: Could not get 3780i IRQ %x\n", __func__, pSettings->usDspIrq);
goto exit_cleanup;
} else {
PRINTK_3(TRACE_TP3780I,
"tp3780i::tp3780I_EnableDSP, got interrupt %x bShareDspIrq %x\n",
pSettings->usDspIrq, pBDData->bShareDspIrq);
bInterruptAllocated = true;
pSettings->bInterruptClaimed = true;
}
smapi_set_DSP_power_state(false);
if (smapi_set_DSP_power_state(true)) {
PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_EnableDSP: Error: smapi_set_DSP_power_state(true) failed\n");
pr_err("%s: Error: smapi_set_DSP_power_state(true) failed\n", __func__);
goto exit_cleanup;
} else {
bDSPPoweredUp = true;
}
if (dsp3780I_EnableDSP(pSettings, s_ausThinkpadIrqToField, s_ausThinkpadDmaToField)) {
PRINTK_ERROR("tp3780i::tp3780I_EnableDSP: Error: dsp7880I_EnableDSP() failed\n");
pr_err("%s: Error: dsp7880I_EnableDSP() failed\n", __func__);
goto exit_cleanup;
}
@@ -390,12 +337,10 @@ int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData)
pBDData->bDSPEnabled = true;
PRINTK_1(TRACE_TP3780I, "tp3780i::tp3780I_EnableDSP exit\n");
return 0;
exit_cleanup:
PRINTK_ERROR("tp3780i::tp3780I_EnableDSP: Cleaning up\n");
pr_err("%s: Cleaning up\n", __func__);
if (bDSPPoweredUp)
smapi_set_DSP_power_state(false);
if (bInterruptAllocated) {
@@ -406,12 +351,9 @@ exit_cleanup:
}
int tp3780I_DisableDSP(THINKPAD_BD_DATA * pBDData)
int tp3780I_DisableDSP(struct thinkpad_bd_data *pBDData)
{
int retval = 0;
DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_DisableDSP entry pBDData %p\n", pBDData);
struct dsp_3780i_config_settings *pSettings = &pBDData->rDspSettings;
if (pBDData->bDSPEnabled) {
dsp3780I_DisableDSP(&pBDData->rDspSettings);
@@ -423,56 +365,38 @@ int tp3780I_DisableDSP(THINKPAD_BD_DATA * pBDData)
pBDData->bDSPEnabled = false;
}
PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_DisableDSP exit retval %x\n", retval);
return retval;
return 0;
}
int tp3780I_ResetDSP(THINKPAD_BD_DATA * pBDData)
int tp3780I_ResetDSP(struct thinkpad_bd_data *pBDData)
{
int retval = 0;
DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_ResetDSP entry pBDData %p\n",
pBDData);
struct dsp_3780i_config_settings *pSettings = &pBDData->rDspSettings;
if (dsp3780I_Reset(pSettings) == 0) {
EnableSRAM(pBDData);
} else {
retval = -EIO;
return 0;
}
PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_ResetDSP exit retval %x\n", retval);
return retval;
return -EIO;
}
int tp3780I_StartDSP(THINKPAD_BD_DATA * pBDData)
int tp3780I_StartDSP(struct thinkpad_bd_data *pBDData)
{
int retval = 0;
DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_StartDSP entry pBDData %p\n", pBDData);
struct dsp_3780i_config_settings *pSettings = &pBDData->rDspSettings;
if (dsp3780I_Run(pSettings) == 0) {
// @BUG @TBD EnableSRAM(pBDData);
} else {
retval = -EIO;
return -EIO;
}
PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_StartDSP exit retval %x\n", retval);
return retval;
return 0;
}
int tp3780I_QueryAbilities(THINKPAD_BD_DATA * pBDData, MW_ABILITIES * pAbilities)
int tp3780I_QueryAbilities(struct thinkpad_bd_data *pBDData, struct mw_abilities *pAbilities)
{
PRINTK_2(TRACE_TP3780I,
"tp3780i::tp3780I_QueryAbilities entry pBDData %p\n", pBDData);
memset(pAbilities, 0, sizeof(*pAbilities));
/* fill out standard constant fields */
pAbilities->instr_per_sec = pBDData->rDspSettings.uIps;
@@ -497,25 +421,17 @@ int tp3780I_QueryAbilities(THINKPAD_BD_DATA * pBDData, MW_ABILITIES * pAbilities
memcpy(pAbilities->bios_task_name, TP_ABILITIES_BIOSTASK_NAME,
sizeof(TP_ABILITIES_BIOSTASK_NAME));
PRINTK_1(TRACE_TP3780I,
"tp3780i::tp3780I_QueryAbilities exit retval=SUCCESSFUL\n");
return 0;
}
int tp3780I_ReadWriteDspDStore(THINKPAD_BD_DATA * pBDData, unsigned int uOpcode,
int tp3780I_ReadWriteDspDStore(struct thinkpad_bd_data *pBDData, unsigned int uOpcode,
void __user *pvBuffer, unsigned int uCount,
unsigned long ulDSPAddr)
{
int retval = 0;
DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
struct dsp_3780i_config_settings *pSettings = &pBDData->rDspSettings;
unsigned short usDspBaseIO = pSettings->usDspBaseIO;
bool bRC = 0;
PRINTK_6(TRACE_TP3780I,
"tp3780i::tp3780I_ReadWriteDspDStore entry pBDData %p, uOpcode %x, pvBuffer %p, uCount %x, ulDSPAddr %lx\n",
pBDData, uOpcode, pvBuffer, uCount, ulDSPAddr);
if (pBDData->bDSPEnabled) {
switch (uOpcode) {
case IOCTL_MW_READ_DATA:
@@ -532,26 +448,18 @@ int tp3780I_ReadWriteDspDStore(THINKPAD_BD_DATA * pBDData, unsigned int uOpcode,
}
}
retval = (bRC) ? -EIO : 0;
PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_ReadWriteDspDStore exit retval %x\n", retval);
return retval;
return bRC ? -EIO : 0;
}
int tp3780I_ReadWriteDspIStore(THINKPAD_BD_DATA * pBDData, unsigned int uOpcode,
int tp3780I_ReadWriteDspIStore(struct thinkpad_bd_data *pBDData, unsigned int uOpcode,
void __user *pvBuffer, unsigned int uCount,
unsigned long ulDSPAddr)
{
int retval = 0;
DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
struct dsp_3780i_config_settings *pSettings = &pBDData->rDspSettings;
unsigned short usDspBaseIO = pSettings->usDspBaseIO;
bool bRC = 0;
PRINTK_6(TRACE_TP3780I,
"tp3780i::tp3780I_ReadWriteDspIStore entry pBDData %p, uOpcode %x, pvBuffer %p, uCount %x, ulDSPAddr %lx\n",
pBDData, uOpcode, pvBuffer, uCount, ulDSPAddr);
if (pBDData->bDSPEnabled) {
switch (uOpcode) {
case IOCTL_MW_READ_INST:
@@ -564,11 +472,6 @@ int tp3780I_ReadWriteDspIStore(THINKPAD_BD_DATA * pBDData, unsigned int uOpcode,
}
}
retval = (bRC) ? -EIO : 0;
PRINTK_2(TRACE_TP3780I,
"tp3780i::tp3780I_ReadWriteDspIStore exit retval %x\n", retval);
return retval;
return bRC ? -EIO : 0;
}

View File

@@ -75,27 +75,27 @@
#define TP_CFG_PllBypass 0 /* don't bypass */
#define TP_CFG_ChipletEnable 0xFFFF /* Enable all chiplets */
typedef struct {
struct thinkpad_bd_data {
int bDSPEnabled;
int bShareDspIrq;
int bShareUartIrq;
DSP_3780I_CONFIG_SETTINGS rDspSettings;
} THINKPAD_BD_DATA;
struct dsp_3780i_config_settings rDspSettings;
};
int tp3780I_InitializeBoardData(THINKPAD_BD_DATA * pBDData);
int tp3780I_CalcResources(THINKPAD_BD_DATA * pBDData);
int tp3780I_ClaimResources(THINKPAD_BD_DATA * pBDData);
int tp3780I_ReleaseResources(THINKPAD_BD_DATA * pBDData);
int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData);
int tp3780I_DisableDSP(THINKPAD_BD_DATA * pBDData);
int tp3780I_ResetDSP(THINKPAD_BD_DATA * pBDData);
int tp3780I_StartDSP(THINKPAD_BD_DATA * pBDData);
int tp3780I_QueryAbilities(THINKPAD_BD_DATA * pBDData, MW_ABILITIES * pAbilities);
void tp3780I_Cleanup(THINKPAD_BD_DATA *pBDData);
int tp3780I_ReadWriteDspDStore(THINKPAD_BD_DATA * pBDData, unsigned int uOpcode,
int tp3780I_InitializeBoardData(struct thinkpad_bd_data *pBDData);
int tp3780I_CalcResources(struct thinkpad_bd_data *pBDData);
int tp3780I_ClaimResources(struct thinkpad_bd_data *pBDData);
int tp3780I_ReleaseResources(struct thinkpad_bd_data *pBDData);
int tp3780I_EnableDSP(struct thinkpad_bd_data *pBDData);
int tp3780I_DisableDSP(struct thinkpad_bd_data *pBDData);
int tp3780I_ResetDSP(struct thinkpad_bd_data *pBDData);
int tp3780I_StartDSP(struct thinkpad_bd_data *pBDData);
int tp3780I_QueryAbilities(struct thinkpad_bd_data *pBDData, struct mw_abilities *pAbilities);
void tp3780I_Cleanup(struct thinkpad_bd_data *pBDData);
int tp3780I_ReadWriteDspDStore(struct thinkpad_bd_data *pBDData, unsigned int uOpcode,
void __user *pvBuffer, unsigned int uCount,
unsigned long ulDSPAddr);
int tp3780I_ReadWriteDspIStore(THINKPAD_BD_DATA * pBDData, unsigned int uOpcode,
int tp3780I_ReadWriteDspIStore(struct thinkpad_bd_data *pBDData, unsigned int uOpcode,
void __user *pvBuffer, unsigned int uCount,
unsigned long ulDSPAddr);

View File

@@ -1973,7 +1973,7 @@ EXPORT_SYMBOL(xillybus_endpoint_remove);
static int __init xillybus_init(void)
{
xillybus_wq = alloc_workqueue(xillyname, 0, 0);
xillybus_wq = alloc_workqueue(xillyname, WQ_UNBOUND, 0);
if (!xillybus_wq)
return -ENOMEM;

View File

@@ -2163,7 +2163,7 @@ static int xillyusb_probe(struct usb_interface *interface,
spin_lock_init(&xdev->error_lock);
xdev->in_counter = 0;
xdev->in_bytes_left = 0;
xdev->workq = alloc_workqueue(xillyname, WQ_HIGHPRI, 0);
xdev->workq = alloc_workqueue(xillyname, WQ_HIGHPRI | WQ_UNBOUND, 0);
if (!xdev->workq) {
dev_err(&interface->dev, "Failed to allocate work queue\n");
@@ -2275,7 +2275,7 @@ static int __init xillyusb_init(void)
{
int rc = 0;
wakeup_wq = alloc_workqueue(xillyname, 0, 0);
wakeup_wq = alloc_workqueue(xillyname, WQ_UNBOUND, 0);
if (!wakeup_wq)
return -ENOMEM;

View File

@@ -273,19 +273,8 @@ unsigned int comedi_buf_write_n_available(struct comedi_subdevice *s)
return free_end - async->buf_write_count;
}
/**
* comedi_buf_write_alloc() - Reserve buffer space for writing
* @s: COMEDI subdevice.
* @nbytes: Maximum space to reserve in bytes.
*
* Reserve up to @nbytes bytes of space to be written in the COMEDI acquisition
* data buffer associated with the subdevice. The amount reserved is limited
* by the space available.
*
* Return: The amount of space reserved in bytes.
*/
unsigned int comedi_buf_write_alloc(struct comedi_subdevice *s,
unsigned int nbytes)
unsigned int _comedi_buf_write_alloc(struct comedi_subdevice *s,
unsigned int nbytes)
{
struct comedi_async *async = s->async;
unsigned int unalloc = comedi_buf_write_n_unalloc(s);
@@ -303,6 +292,29 @@ unsigned int comedi_buf_write_alloc(struct comedi_subdevice *s,
return nbytes;
}
/**
* comedi_buf_write_alloc() - Reserve buffer space for writing
* @s: COMEDI subdevice.
* @nbytes: Maximum space to reserve in bytes.
*
* Reserve up to @nbytes bytes of space to be written in the COMEDI acquisition
* data buffer associated with the subdevice. The amount reserved is limited
* by the space available.
*
* Return: The amount of space reserved in bytes.
*/
unsigned int comedi_buf_write_alloc(struct comedi_subdevice *s,
unsigned int nbytes)
{
if (comedi_get_is_subdevice_running(s)) {
nbytes = _comedi_buf_write_alloc(s, nbytes);
comedi_put_is_subdevice_running(s);
} else {
nbytes = 0;
}
return nbytes;
}
EXPORT_SYMBOL_GPL(comedi_buf_write_alloc);
/*
@@ -362,6 +374,24 @@ unsigned int comedi_buf_write_n_allocated(struct comedi_subdevice *s)
return async->buf_write_alloc_count - async->buf_write_count;
}
unsigned int _comedi_buf_write_free(struct comedi_subdevice *s,
unsigned int nbytes)
{
struct comedi_async *async = s->async;
unsigned int allocated = comedi_buf_write_n_allocated(s);
if (nbytes > allocated)
nbytes = allocated;
async->buf_write_count += nbytes;
async->buf_write_ptr += nbytes;
comedi_buf_munge(s, async->buf_write_count - async->munge_count);
if (async->buf_write_ptr >= async->prealloc_bufsz)
async->buf_write_ptr %= async->prealloc_bufsz;
return nbytes;
}
/**
* comedi_buf_write_free() - Free buffer space after it is written
* @s: COMEDI subdevice.
@@ -380,34 +410,17 @@ unsigned int comedi_buf_write_n_allocated(struct comedi_subdevice *s)
unsigned int comedi_buf_write_free(struct comedi_subdevice *s,
unsigned int nbytes)
{
struct comedi_async *async = s->async;
unsigned int allocated = comedi_buf_write_n_allocated(s);
if (nbytes > allocated)
nbytes = allocated;
async->buf_write_count += nbytes;
async->buf_write_ptr += nbytes;
comedi_buf_munge(s, async->buf_write_count - async->munge_count);
if (async->buf_write_ptr >= async->prealloc_bufsz)
async->buf_write_ptr %= async->prealloc_bufsz;
if (comedi_get_is_subdevice_running(s)) {
nbytes = _comedi_buf_write_free(s, nbytes);
comedi_put_is_subdevice_running(s);
} else {
nbytes = 0;
}
return nbytes;
}
EXPORT_SYMBOL_GPL(comedi_buf_write_free);
/**
* comedi_buf_read_n_available() - Determine amount of readable buffer space
* @s: COMEDI subdevice.
*
* Determine the amount of readable buffer space in the COMEDI acquisition data
* buffer associated with the subdevice. The readable buffer space is that
* which has been freed by the writer and "munged" to the sample data format
* expected by COMEDI if necessary.
*
* Return: The amount of readable buffer space.
*/
unsigned int comedi_buf_read_n_available(struct comedi_subdevice *s)
unsigned int _comedi_buf_read_n_available(struct comedi_subdevice *s)
{
struct comedi_async *async = s->async;
unsigned int num_bytes;
@@ -425,8 +438,53 @@ unsigned int comedi_buf_read_n_available(struct comedi_subdevice *s)
return num_bytes;
}
/**
* comedi_buf_read_n_available() - Determine amount of readable buffer space
* @s: COMEDI subdevice.
*
* Determine the amount of readable buffer space in the COMEDI acquisition data
* buffer associated with the subdevice. The readable buffer space is that
* which has been freed by the writer and "munged" to the sample data format
* expected by COMEDI if necessary.
*
* Return: The amount of readable buffer space.
*/
unsigned int comedi_buf_read_n_available(struct comedi_subdevice *s)
{
unsigned int num_bytes;
if (comedi_get_is_subdevice_running(s)) {
num_bytes = _comedi_buf_read_n_available(s);
comedi_put_is_subdevice_running(s);
} else {
num_bytes = 0;
}
return num_bytes;
}
EXPORT_SYMBOL_GPL(comedi_buf_read_n_available);
unsigned int _comedi_buf_read_alloc(struct comedi_subdevice *s,
unsigned int nbytes)
{
struct comedi_async *async = s->async;
unsigned int available;
available = async->munge_count - async->buf_read_alloc_count;
if (nbytes > available)
nbytes = available;
async->buf_read_alloc_count += nbytes;
/*
* ensure the async buffer 'counts' are read before we
* attempt to read data from the read-alloc'ed buffer space
*/
smp_rmb();
return nbytes;
}
/**
* comedi_buf_read_alloc() - Reserve buffer space for reading
* @s: COMEDI subdevice.
@@ -445,21 +503,12 @@ EXPORT_SYMBOL_GPL(comedi_buf_read_n_available);
unsigned int comedi_buf_read_alloc(struct comedi_subdevice *s,
unsigned int nbytes)
{
struct comedi_async *async = s->async;
unsigned int available;
available = async->munge_count - async->buf_read_alloc_count;
if (nbytes > available)
nbytes = available;
async->buf_read_alloc_count += nbytes;
/*
* ensure the async buffer 'counts' are read before we
* attempt to read data from the read-alloc'ed buffer space
*/
smp_rmb();
if (comedi_get_is_subdevice_running(s)) {
nbytes = _comedi_buf_read_alloc(s, nbytes);
comedi_put_is_subdevice_running(s);
} else {
nbytes = 0;
}
return nbytes;
}
EXPORT_SYMBOL_GPL(comedi_buf_read_alloc);
@@ -469,6 +518,28 @@ static unsigned int comedi_buf_read_n_allocated(struct comedi_async *async)
return async->buf_read_alloc_count - async->buf_read_count;
}
unsigned int _comedi_buf_read_free(struct comedi_subdevice *s,
unsigned int nbytes)
{
struct comedi_async *async = s->async;
unsigned int allocated;
/*
* ensure data has been read out of buffer before
* the async read count is incremented
*/
smp_mb();
allocated = comedi_buf_read_n_allocated(async);
if (nbytes > allocated)
nbytes = allocated;
async->buf_read_count += nbytes;
async->buf_read_ptr += nbytes;
async->buf_read_ptr %= async->prealloc_bufsz;
return nbytes;
}
/**
* comedi_buf_read_free() - Free buffer space after it has been read
* @s: COMEDI subdevice.
@@ -485,22 +556,12 @@ static unsigned int comedi_buf_read_n_allocated(struct comedi_async *async)
unsigned int comedi_buf_read_free(struct comedi_subdevice *s,
unsigned int nbytes)
{
struct comedi_async *async = s->async;
unsigned int allocated;
/*
* ensure data has been read out of buffer before
* the async read count is incremented
*/
smp_mb();
allocated = comedi_buf_read_n_allocated(async);
if (nbytes > allocated)
nbytes = allocated;
async->buf_read_count += nbytes;
async->buf_read_ptr += nbytes;
async->buf_read_ptr %= async->prealloc_bufsz;
if (comedi_get_is_subdevice_running(s)) {
nbytes = _comedi_buf_read_free(s, nbytes);
comedi_put_is_subdevice_running(s);
} else {
nbytes = 0;
}
return nbytes;
}
EXPORT_SYMBOL_GPL(comedi_buf_read_free);
@@ -558,6 +619,38 @@ static void comedi_buf_memcpy_from(struct comedi_subdevice *s,
}
}
static unsigned int _comedi_buf_write_samples(struct comedi_subdevice *s,
const void *data,
unsigned int nsamples)
{
unsigned int max_samples;
unsigned int nbytes;
/*
* Make sure there is enough room in the buffer for all the samples.
* If not, clamp the nsamples to the number that will fit, flag the
* buffer overrun and add the samples that fit.
*/
max_samples = comedi_bytes_to_samples(s, comedi_buf_write_n_unalloc(s));
if (nsamples > max_samples) {
dev_warn(s->device->class_dev, "buffer overrun\n");
s->async->events |= COMEDI_CB_OVERFLOW;
nsamples = max_samples;
}
if (nsamples == 0)
return 0;
nbytes = comedi_samples_to_bytes(s, nsamples);
nbytes = _comedi_buf_write_alloc(s, nbytes);
comedi_buf_memcpy_to(s, data, nbytes);
_comedi_buf_write_free(s, nbytes);
_comedi_inc_scan_progress(s, nbytes);
s->async->events |= COMEDI_CB_BLOCK;
return nbytes;
}
/**
* comedi_buf_write_samples() - Write sample data to COMEDI buffer
* @s: COMEDI subdevice.
@@ -577,35 +670,43 @@ static void comedi_buf_memcpy_from(struct comedi_subdevice *s,
*/
unsigned int comedi_buf_write_samples(struct comedi_subdevice *s,
const void *data, unsigned int nsamples)
{
unsigned int nbytes;
if (comedi_get_is_subdevice_running(s)) {
nbytes = _comedi_buf_write_samples(s, data, nsamples);
comedi_put_is_subdevice_running(s);
} else {
nbytes = 0;
}
return nbytes;
}
EXPORT_SYMBOL_GPL(comedi_buf_write_samples);
static unsigned int _comedi_buf_read_samples(struct comedi_subdevice *s,
void *data, unsigned int nsamples)
{
unsigned int max_samples;
unsigned int nbytes;
/*
* Make sure there is enough room in the buffer for all the samples.
* If not, clamp the nsamples to the number that will fit, flag the
* buffer overrun and add the samples that fit.
*/
max_samples = comedi_bytes_to_samples(s, comedi_buf_write_n_unalloc(s));
if (nsamples > max_samples) {
dev_warn(s->device->class_dev, "buffer overrun\n");
s->async->events |= COMEDI_CB_OVERFLOW;
/* clamp nsamples to the number of full samples available */
max_samples = comedi_bytes_to_samples(s,
_comedi_buf_read_n_available(s));
if (nsamples > max_samples)
nsamples = max_samples;
}
if (nsamples == 0)
return 0;
nbytes = comedi_buf_write_alloc(s,
nbytes = _comedi_buf_read_alloc(s,
comedi_samples_to_bytes(s, nsamples));
comedi_buf_memcpy_to(s, data, nbytes);
comedi_buf_write_free(s, nbytes);
comedi_inc_scan_progress(s, nbytes);
comedi_buf_memcpy_from(s, data, nbytes);
_comedi_buf_read_free(s, nbytes);
_comedi_inc_scan_progress(s, nbytes);
s->async->events |= COMEDI_CB_BLOCK;
return nbytes;
}
EXPORT_SYMBOL_GPL(comedi_buf_write_samples);
/**
* comedi_buf_read_samples() - Read sample data from COMEDI buffer
@@ -624,25 +725,14 @@ EXPORT_SYMBOL_GPL(comedi_buf_write_samples);
unsigned int comedi_buf_read_samples(struct comedi_subdevice *s,
void *data, unsigned int nsamples)
{
unsigned int max_samples;
unsigned int nbytes;
/* clamp nsamples to the number of full samples available */
max_samples = comedi_bytes_to_samples(s,
comedi_buf_read_n_available(s));
if (nsamples > max_samples)
nsamples = max_samples;
if (nsamples == 0)
return 0;
nbytes = comedi_buf_read_alloc(s,
comedi_samples_to_bytes(s, nsamples));
comedi_buf_memcpy_from(s, data, nbytes);
comedi_buf_read_free(s, nbytes);
comedi_inc_scan_progress(s, nbytes);
s->async->events |= COMEDI_CB_BLOCK;
if (comedi_get_is_subdevice_running(s)) {
nbytes = _comedi_buf_read_samples(s, data, nsamples);
comedi_put_is_subdevice_running(s);
} else {
nbytes = 0;
}
return nbytes;
}
EXPORT_SYMBOL_GPL(comedi_buf_read_samples);

View File

@@ -38,6 +38,7 @@
* COMEDI_SRF_ERROR: indicates an COMEDI_CB_ERROR event has occurred
* since the last command was started
* COMEDI_SRF_RUNNING: command is running
* COMEDI_SRF_BUSY: command was started and subdevice still busy
* COMEDI_SRF_FREE_SPRIV: free s->private on detach
*
* COMEDI_SRF_BUSY_MASK: runflags that indicate the subdevice is "busy"
@@ -45,9 +46,11 @@
#define COMEDI_SRF_RT BIT(1)
#define COMEDI_SRF_ERROR BIT(2)
#define COMEDI_SRF_RUNNING BIT(27)
#define COMEDI_SRF_BUSY BIT(28)
#define COMEDI_SRF_FREE_SPRIV BIT(31)
#define COMEDI_SRF_BUSY_MASK (COMEDI_SRF_ERROR | COMEDI_SRF_RUNNING)
#define COMEDI_SRF_BUSY_MASK \
(COMEDI_SRF_ERROR | COMEDI_SRF_RUNNING | COMEDI_SRF_BUSY)
/**
* struct comedi_file - Per-file private data for COMEDI device
@@ -665,6 +668,11 @@ static bool comedi_is_runflags_in_error(unsigned int runflags)
return runflags & COMEDI_SRF_ERROR;
}
static bool comedi_is_runflags_busy(unsigned int runflags)
{
return runflags & COMEDI_SRF_BUSY;
}
/**
* comedi_is_subdevice_running() - Check if async command running on subdevice
* @s: COMEDI subdevice.
@@ -687,6 +695,46 @@ static bool __comedi_is_subdevice_running(struct comedi_subdevice *s)
return comedi_is_runflags_running(runflags);
}
/**
* comedi_get_is_subdevice_running() - Get if async command running on subdevice
* @s: COMEDI subdevice.
*
* If an asynchronous COMEDI command is running on the subdevice, increment
* a reference counter. If the function return value indicates that a
* command is running, then the details of the command will not be destroyed
* before a matching call to comedi_put_is_subdevice_running().
*
* Return: %true if an asynchronous COMEDI command is active on the
* subdevice, else %false.
*/
bool comedi_get_is_subdevice_running(struct comedi_subdevice *s)
{
unsigned long flags;
bool running;
spin_lock_irqsave(&s->spin_lock, flags);
running = __comedi_is_subdevice_running(s);
if (running)
refcount_inc(&s->async->run_active);
spin_unlock_irqrestore(&s->spin_lock, flags);
return running;
}
EXPORT_SYMBOL_GPL(comedi_get_is_subdevice_running);
/**
* comedi_put_is_subdevice_running() - Put if async command running on subdevice
* @s: COMEDI subdevice.
*
* Decrements the reference counter that was incremented when
* comedi_get_is_subdevice_running() returned %true.
*/
void comedi_put_is_subdevice_running(struct comedi_subdevice *s)
{
if (refcount_dec_and_test(&s->async->run_active))
complete_all(&s->async->run_complete);
}
EXPORT_SYMBOL_GPL(comedi_put_is_subdevice_running);
bool comedi_can_auto_free_spriv(struct comedi_subdevice *s)
{
unsigned int runflags = __comedi_get_subdevice_runflags(s);
@@ -736,20 +784,28 @@ static void do_become_nonbusy(struct comedi_device *dev,
struct comedi_subdevice *s)
{
struct comedi_async *async = s->async;
unsigned int runflags;
unsigned long flags;
lockdep_assert_held(&dev->mutex);
comedi_update_subdevice_runflags(s, COMEDI_SRF_RUNNING, 0);
if (async) {
spin_lock_irqsave(&s->spin_lock, flags);
runflags = __comedi_get_subdevice_runflags(s);
__comedi_clear_subdevice_runflags(s, COMEDI_SRF_RUNNING |
COMEDI_SRF_BUSY);
spin_unlock_irqrestore(&s->spin_lock, flags);
if (comedi_is_runflags_busy(runflags)) {
/*
* "Run active" counter was set to 1 when setting up the
* command. Decrement it and wait for it to become 0.
*/
comedi_put_is_subdevice_running(s);
wait_for_completion(&async->run_complete);
comedi_buf_reset(s);
async->inttrig = NULL;
kfree(async->cmd.chanlist);
async->cmd.chanlist = NULL;
s->busy = NULL;
wake_up_interruptible_all(&async->wait_head);
} else {
dev_err(dev->class_dev,
"BUG: (?) %s called with async=NULL\n", __func__);
s->busy = NULL;
}
}
@@ -1150,15 +1206,15 @@ static int do_bufinfo_ioctl(struct comedi_device *dev,
if (!(async->cmd.flags & CMDF_WRITE)) {
/* command was set up in "read" direction */
if (bi.bytes_read) {
comedi_buf_read_alloc(s, bi.bytes_read);
bi.bytes_read = comedi_buf_read_free(s, bi.bytes_read);
_comedi_buf_read_alloc(s, bi.bytes_read);
bi.bytes_read = _comedi_buf_read_free(s, bi.bytes_read);
}
/*
* If nothing left to read, and command has stopped, and
* {"read" position not updated or command stopped normally},
* then become non-busy.
*/
if (comedi_buf_read_n_available(s) == 0 &&
if (_comedi_buf_read_n_available(s) == 0 &&
!comedi_is_runflags_running(runflags) &&
(bi.bytes_read == 0 ||
!comedi_is_runflags_in_error(runflags))) {
@@ -1175,9 +1231,9 @@ static int do_bufinfo_ioctl(struct comedi_device *dev,
if (comedi_is_runflags_in_error(runflags))
retval = -EPIPE;
} else if (bi.bytes_written) {
comedi_buf_write_alloc(s, bi.bytes_written);
_comedi_buf_write_alloc(s, bi.bytes_written);
bi.bytes_written =
comedi_buf_write_free(s, bi.bytes_written);
_comedi_buf_write_free(s, bi.bytes_written);
}
bi.bytes_read = 0;
}
@@ -1860,8 +1916,14 @@ static int do_cmd_ioctl(struct comedi_device *dev,
if (async->cmd.flags & CMDF_WAKE_EOS)
async->cb_mask |= COMEDI_CB_EOS;
/*
* Set the "run active" counter with an initial count of 1 that will
* complete the "safe to reset" event when it is decremented to 0.
*/
refcount_set(&s->async->run_active, 1);
reinit_completion(&s->async->run_complete);
comedi_update_subdevice_runflags(s, COMEDI_SRF_BUSY_MASK,
COMEDI_SRF_RUNNING);
COMEDI_SRF_RUNNING | COMEDI_SRF_BUSY);
/*
* Set s->busy _after_ setting COMEDI_SRF_RUNNING flag to avoid
@@ -2284,15 +2346,10 @@ static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
rc = check_insnlist_len(dev, insnlist.n_insns);
if (rc)
break;
insns = kcalloc(insnlist.n_insns, sizeof(*insns), GFP_KERNEL);
if (!insns) {
rc = -ENOMEM;
break;
}
if (copy_from_user(insns, insnlist.insns,
sizeof(*insns) * insnlist.n_insns)) {
rc = -EFAULT;
kfree(insns);
insns = memdup_array_user(insnlist.insns, insnlist.n_insns,
sizeof(*insns));
if (IS_ERR(insns)) {
rc = PTR_ERR(insns);
break;
}
rc = do_insnlist_ioctl(dev, insns, insnlist.n_insns, file);
@@ -2512,7 +2569,7 @@ static __poll_t comedi_poll(struct file *file, poll_table *wait)
poll_wait(file, &s->async->wait_head, wait);
if (s->busy != file || !comedi_is_subdevice_running(s) ||
(s->async->cmd.flags & CMDF_WRITE) ||
comedi_buf_read_n_available(s) > 0)
_comedi_buf_read_n_available(s) > 0)
mask |= EPOLLIN | EPOLLRDNORM;
}
@@ -2645,7 +2702,7 @@ static ssize_t comedi_write(struct file *file, const char __user *buf,
break;
/* Allocate all free buffer space. */
comedi_buf_write_alloc(s, async->prealloc_bufsz);
_comedi_buf_write_alloc(s, async->prealloc_bufsz);
m = comedi_buf_write_n_allocated(s);
n = min_t(size_t, m, nbytes);
@@ -2673,7 +2730,7 @@ static ssize_t comedi_write(struct file *file, const char __user *buf,
n -= m;
retval = -EFAULT;
}
comedi_buf_write_free(s, n);
_comedi_buf_write_free(s, n);
count += n;
nbytes -= n;
@@ -2759,7 +2816,7 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
while (count == 0 && !retval) {
set_current_state(TASK_INTERRUPTIBLE);
m = comedi_buf_read_n_available(s);
m = _comedi_buf_read_n_available(s);
n = min_t(size_t, m, nbytes);
if (n == 0) {
@@ -2799,8 +2856,8 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
retval = -EFAULT;
}
comedi_buf_read_alloc(s, n);
comedi_buf_read_free(s, n);
_comedi_buf_read_alloc(s, n);
_comedi_buf_read_free(s, n);
count += n;
nbytes -= n;
@@ -2834,7 +2891,7 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes,
s == new_s && new_s->async == async && s->busy == file &&
!(async->cmd.flags & CMDF_WRITE) &&
!comedi_is_subdevice_running(s) &&
comedi_buf_read_n_available(s) == 0)
_comedi_buf_read_n_available(s) == 0)
do_become_nonbusy(dev, s);
mutex_unlock(&dev->mutex);
}
@@ -3023,7 +3080,12 @@ static int compat_chaninfo(struct file *file, unsigned long arg)
chaninfo.rangelist = compat_ptr(chaninfo32.rangelist);
mutex_lock(&dev->mutex);
err = do_chaninfo_ioctl(dev, &chaninfo);
if (!dev->attached) {
dev_dbg(dev->class_dev, "no driver attached\n");
err = -ENODEV;
} else {
err = do_chaninfo_ioctl(dev, &chaninfo);
}
mutex_unlock(&dev->mutex);
return err;
}
@@ -3044,7 +3106,12 @@ static int compat_rangeinfo(struct file *file, unsigned long arg)
rangeinfo.range_ptr = compat_ptr(rangeinfo32.range_ptr);
mutex_lock(&dev->mutex);
err = do_rangeinfo_ioctl(dev, &rangeinfo);
if (!dev->attached) {
dev_dbg(dev->class_dev, "no driver attached\n");
err = -ENODEV;
} else {
err = do_rangeinfo_ioctl(dev, &rangeinfo);
}
mutex_unlock(&dev->mutex);
return err;
}
@@ -3120,7 +3187,12 @@ static int compat_cmd(struct file *file, unsigned long arg)
return rc;
mutex_lock(&dev->mutex);
rc = do_cmd_ioctl(dev, &cmd, &copy, file);
if (!dev->attached) {
dev_dbg(dev->class_dev, "no driver attached\n");
rc = -ENODEV;
} else {
rc = do_cmd_ioctl(dev, &cmd, &copy, file);
}
mutex_unlock(&dev->mutex);
if (copy) {
/* Special case: copy cmd back to user. */
@@ -3145,7 +3217,12 @@ static int compat_cmdtest(struct file *file, unsigned long arg)
return rc;
mutex_lock(&dev->mutex);
rc = do_cmdtest_ioctl(dev, &cmd, &copy, file);
if (!dev->attached) {
dev_dbg(dev->class_dev, "no driver attached\n");
rc = -ENODEV;
} else {
rc = do_cmdtest_ioctl(dev, &cmd, &copy, file);
}
mutex_unlock(&dev->mutex);
if (copy) {
err = put_compat_cmd(compat_ptr(arg), &cmd);
@@ -3205,7 +3282,12 @@ static int compat_insnlist(struct file *file, unsigned long arg)
}
mutex_lock(&dev->mutex);
rc = do_insnlist_ioctl(dev, insns, insnlist32.n_insns, file);
if (!dev->attached) {
dev_dbg(dev->class_dev, "no driver attached\n");
rc = -ENODEV;
} else {
rc = do_insnlist_ioctl(dev, insns, insnlist32.n_insns, file);
}
mutex_unlock(&dev->mutex);
kfree(insns);
return rc;
@@ -3224,7 +3306,12 @@ static int compat_insn(struct file *file, unsigned long arg)
return rc;
mutex_lock(&dev->mutex);
rc = do_insn_ioctl(dev, &insn, file);
if (!dev->attached) {
dev_dbg(dev->class_dev, "no driver attached\n");
rc = -ENODEV;
} else {
rc = do_insn_ioctl(dev, &insn, file);
}
mutex_unlock(&dev->mutex);
return rc;
}
@@ -3299,18 +3386,7 @@ static const struct file_operations comedi_fops = {
.llseek = noop_llseek,
};
/**
* comedi_event() - Handle events for asynchronous COMEDI command
* @dev: COMEDI device.
* @s: COMEDI subdevice.
* Context: in_interrupt() (usually), @s->spin_lock spin-lock not held.
*
* If an asynchronous COMEDI command is active on the subdevice, process
* any %COMEDI_CB_... event flags that have been set, usually by an
* interrupt handler. These may change the run state of the asynchronous
* command, wake a task, and/or send a %SIGIO signal.
*/
void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
void _comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
{
struct comedi_async *async = s->async;
unsigned int events;
@@ -3346,6 +3422,25 @@ void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
if (si_code)
kill_fasync(&dev->async_queue, SIGIO, si_code);
}
/**
* comedi_event() - Handle events for asynchronous COMEDI command
* @dev: COMEDI device.
* @s: COMEDI subdevice.
* Context: in_interrupt() (usually), @s->spin_lock spin-lock not held.
*
* If an asynchronous COMEDI command is active on the subdevice, process
* any %COMEDI_CB_... event flags that have been set, usually by an
* interrupt handler. These may change the run state of the asynchronous
* command, wake a task, and/or send a %SIGIO signal.
*/
void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
{
if (comedi_get_is_subdevice_running(s)) {
comedi_event(dev, s);
comedi_put_is_subdevice_running(s);
}
}
EXPORT_SYMBOL_GPL(comedi_event);
/* Note: the ->mutex is pre-locked on successful return */

View File

@@ -36,6 +36,18 @@ struct comedi_buf_map *
comedi_buf_map_from_subdev_get(struct comedi_subdevice *s);
unsigned int comedi_buf_write_n_available(struct comedi_subdevice *s);
unsigned int comedi_buf_write_n_allocated(struct comedi_subdevice *s);
unsigned int _comedi_buf_write_alloc(struct comedi_subdevice *s,
unsigned int nbytes);
unsigned int _comedi_buf_write_free(struct comedi_subdevice *s,
unsigned int nbytes);
unsigned int _comedi_buf_read_n_available(struct comedi_subdevice *s);
unsigned int _comedi_buf_read_alloc(struct comedi_subdevice *s,
unsigned int nbytes);
unsigned int _comedi_buf_read_free(struct comedi_subdevice *s,
unsigned int nbytes);
void _comedi_inc_scan_progress(struct comedi_subdevice *s,
unsigned int num_bytes);
void _comedi_event(struct comedi_device *dev, struct comedi_subdevice *s);
void comedi_device_cancel_all(struct comedi_device *dev);
bool comedi_can_auto_free_spriv(struct comedi_subdevice *s);

View File

@@ -441,6 +441,13 @@ unsigned int comedi_bytes_per_scan_cmd(struct comedi_subdevice *s,
}
EXPORT_SYMBOL_GPL(comedi_bytes_per_scan_cmd);
static unsigned int _comedi_bytes_per_scan(struct comedi_subdevice *s)
{
struct comedi_cmd *cmd = &s->async->cmd;
return comedi_bytes_per_scan_cmd(s, cmd);
}
/**
* comedi_bytes_per_scan() - Get length of asynchronous command "scan" in bytes
* @s: COMEDI subdevice.
@@ -458,9 +465,16 @@ EXPORT_SYMBOL_GPL(comedi_bytes_per_scan_cmd);
*/
unsigned int comedi_bytes_per_scan(struct comedi_subdevice *s)
{
struct comedi_cmd *cmd = &s->async->cmd;
unsigned int num_bytes;
return comedi_bytes_per_scan_cmd(s, cmd);
if (comedi_get_is_subdevice_running(s)) {
num_bytes = _comedi_bytes_per_scan(s);
comedi_put_is_subdevice_running(s);
} else {
/* Use nomimal, single sample scan length. */
num_bytes = comedi_samples_to_bytes(s, 1);
}
return num_bytes;
}
EXPORT_SYMBOL_GPL(comedi_bytes_per_scan);
@@ -482,6 +496,17 @@ static unsigned int __comedi_nscans_left(struct comedi_subdevice *s,
return nscans;
}
static unsigned int _comedi_nscans_left(struct comedi_subdevice *s,
unsigned int nscans)
{
if (nscans == 0) {
unsigned int nbytes = _comedi_buf_read_n_available(s);
nscans = nbytes / _comedi_bytes_per_scan(s);
}
return __comedi_nscans_left(s, nscans);
}
/**
* comedi_nscans_left() - Return the number of scans left in the command
* @s: COMEDI subdevice.
@@ -499,25 +524,18 @@ static unsigned int __comedi_nscans_left(struct comedi_subdevice *s,
unsigned int comedi_nscans_left(struct comedi_subdevice *s,
unsigned int nscans)
{
if (nscans == 0) {
unsigned int nbytes = comedi_buf_read_n_available(s);
nscans = nbytes / comedi_bytes_per_scan(s);
if (comedi_get_is_subdevice_running(s)) {
nscans = _comedi_nscans_left(s, nscans);
comedi_put_is_subdevice_running(s);
} else {
nscans = 0;
}
return __comedi_nscans_left(s, nscans);
return nscans;
}
EXPORT_SYMBOL_GPL(comedi_nscans_left);
/**
* comedi_nsamples_left() - Return the number of samples left in the command
* @s: COMEDI subdevice.
* @nsamples: The expected number of samples.
*
* Returns the number of samples remaining to complete the command, or the
* specified expected number of samples (@nsamples), whichever is fewer.
*/
unsigned int comedi_nsamples_left(struct comedi_subdevice *s,
unsigned int nsamples)
static unsigned int _comedi_nsamples_left(struct comedi_subdevice *s,
unsigned int nsamples)
{
struct comedi_async *async = s->async;
struct comedi_cmd *cmd = &async->cmd;
@@ -538,24 +556,34 @@ unsigned int comedi_nsamples_left(struct comedi_subdevice *s,
return samples_left;
return nsamples;
}
EXPORT_SYMBOL_GPL(comedi_nsamples_left);
/**
* comedi_inc_scan_progress() - Update scan progress in asynchronous command
* comedi_nsamples_left() - Return the number of samples left in the command
* @s: COMEDI subdevice.
* @num_bytes: Amount of data in bytes to increment scan progress.
* @nsamples: The expected number of samples.
*
* Increments the scan progress by the number of bytes specified by @num_bytes.
* If the scan progress reaches or exceeds the scan length in bytes, reduce
* it modulo the scan length in bytes and set the "end of scan" asynchronous
* event flag (%COMEDI_CB_EOS) to be processed later.
* Returns the number of samples remaining to complete the command, or the
* specified expected number of samples (@nsamples), whichever is fewer.
*/
void comedi_inc_scan_progress(struct comedi_subdevice *s,
unsigned int num_bytes)
unsigned int comedi_nsamples_left(struct comedi_subdevice *s,
unsigned int nsamples)
{
if (comedi_get_is_subdevice_running(s)) {
nsamples = _comedi_nsamples_left(s, nsamples);
comedi_put_is_subdevice_running(s);
} else {
nsamples = 0;
}
return nsamples;
}
EXPORT_SYMBOL_GPL(comedi_nsamples_left);
void _comedi_inc_scan_progress(struct comedi_subdevice *s,
unsigned int num_bytes)
{
struct comedi_async *async = s->async;
struct comedi_cmd *cmd = &async->cmd;
unsigned int scan_length = comedi_bytes_per_scan(s);
unsigned int scan_length = _comedi_bytes_per_scan(s);
/* track the 'cur_chan' for non-SDF_PACKED subdevices */
if (!(s->subdev_flags & SDF_PACKED)) {
@@ -576,8 +604,43 @@ void comedi_inc_scan_progress(struct comedi_subdevice *s,
async->events |= COMEDI_CB_EOS;
}
}
/**
* comedi_inc_scan_progress() - Update scan progress in asynchronous command
* @s: COMEDI subdevice.
* @num_bytes: Amount of data in bytes to increment scan progress.
*
* Increments the scan progress by the number of bytes specified by @num_bytes.
* If the scan progress reaches or exceeds the scan length in bytes, reduce
* it modulo the scan length in bytes and set the "end of scan" asynchronous
* event flag (%COMEDI_CB_EOS) to be processed later.
*/
void comedi_inc_scan_progress(struct comedi_subdevice *s,
unsigned int num_bytes)
{
if (comedi_get_is_subdevice_running(s)) {
_comedi_inc_scan_progress(s, num_bytes);
comedi_put_is_subdevice_running(s);
}
}
EXPORT_SYMBOL_GPL(comedi_inc_scan_progress);
static unsigned int _comedi_handle_events(struct comedi_device *dev,
struct comedi_subdevice *s)
{
unsigned int events = s->async->events;
if (events == 0)
return events;
if ((events & COMEDI_CB_CANCEL_MASK) && s->cancel)
s->cancel(dev, s);
_comedi_event(dev, s);
return events;
}
/**
* comedi_handle_events() - Handle events and possibly stop acquisition
* @dev: COMEDI device.
@@ -597,16 +660,14 @@ EXPORT_SYMBOL_GPL(comedi_inc_scan_progress);
unsigned int comedi_handle_events(struct comedi_device *dev,
struct comedi_subdevice *s)
{
unsigned int events = s->async->events;
if (events == 0)
return events;
if ((events & COMEDI_CB_CANCEL_MASK) && s->cancel)
s->cancel(dev, s);
comedi_event(dev, s);
unsigned int events;
if (comedi_get_is_subdevice_running(s)) {
events = _comedi_handle_events(dev, s);
comedi_put_is_subdevice_running(s);
} else {
events = 0;
}
return events;
}
EXPORT_SYMBOL_GPL(comedi_handle_events);
@@ -677,6 +738,7 @@ static int __comedi_device_postconfig_async(struct comedi_device *dev,
return -ENOMEM;
init_waitqueue_head(&async->wait_head);
init_completion(&async->run_complete);
s->async = async;
async->max_bufsize = comedi_default_buf_maxsize_kb * 1024;

View File

@@ -77,19 +77,17 @@ static int dev_8255_attach(struct comedi_device *dev,
* base address of the chip.
*/
ret = __comedi_request_region(dev, iobase, I8255_SIZE);
if (ret)
return ret;
ret = subdev_8255_io_init(dev, s, iobase);
if (ret) {
/*
* Release the I/O port region here, as the
* "detach" handler cannot find it.
*/
release_region(iobase, I8255_SIZE);
s->type = COMEDI_SUBD_UNUSED;
} else {
ret = subdev_8255_io_init(dev, s, iobase);
if (ret) {
/*
* Release the I/O port region here, as the
* "detach" handler cannot find it.
*/
release_region(iobase, I8255_SIZE);
s->type = COMEDI_SUBD_UNUSED;
return ret;
}
return ret;
}
}

View File

@@ -249,9 +249,6 @@ static int c6xdigio_attach(struct comedi_device *dev,
if (ret)
return ret;
/* Make sure that PnP ports get activated */
pnp_register_driver(&c6xdigio_pnp_driver);
s = &dev->subdevices[0];
/* pwm output subdevice */
s->type = COMEDI_SUBD_PWM;
@@ -278,19 +275,46 @@ static int c6xdigio_attach(struct comedi_device *dev,
return 0;
}
static void c6xdigio_detach(struct comedi_device *dev)
{
comedi_legacy_detach(dev);
pnp_unregister_driver(&c6xdigio_pnp_driver);
}
static struct comedi_driver c6xdigio_driver = {
.driver_name = "c6xdigio",
.module = THIS_MODULE,
.attach = c6xdigio_attach,
.detach = c6xdigio_detach,
.detach = comedi_legacy_detach,
};
module_comedi_driver(c6xdigio_driver);
static bool c6xdigio_pnp_registered = false;
static int __init c6xdigio_module_init(void)
{
int ret;
ret = comedi_driver_register(&c6xdigio_driver);
if (ret)
return ret;
if (IS_ENABLED(CONFIG_PNP)) {
/* Try to activate the PnP ports */
ret = pnp_register_driver(&c6xdigio_pnp_driver);
if (ret) {
pr_warn("failed to register pnp driver - err %d\n",
ret);
ret = 0; /* ignore the error. */
} else {
c6xdigio_pnp_registered = true;
}
}
return 0;
}
module_init(c6xdigio_module_init);
static void __exit c6xdigio_module_exit(void)
{
if (c6xdigio_pnp_registered)
pnp_unregister_driver(&c6xdigio_pnp_driver);
comedi_driver_unregister(&c6xdigio_driver);
}
module_exit(c6xdigio_module_exit);
MODULE_AUTHOR("Comedi https://www.comedi.org");
MODULE_DESCRIPTION("Comedi driver for the C6x_DIGIO DSP daughter card");

View File

@@ -205,7 +205,7 @@ static int do_dev_config(struct comedi_device *dev, struct comedi_devconfig *it)
snprintf(file, sizeof(file), "/dev/comedi%d", minor);
file[sizeof(file) - 1] = 0;
d = comedi_open(file);
d = comedi_open_from(file, dev->minor);
if (!d) {
dev_err(dev->class_dev,
@@ -326,7 +326,7 @@ static void bonding_detach(struct comedi_device *dev)
if (!bdev)
continue;
if (!test_and_set_bit(bdev->minor, devs_closed))
comedi_close(bdev->dev);
comedi_close_from(bdev->dev, dev->minor);
kfree(bdev);
}
kfree(devpriv->devs);

View File

@@ -67,6 +67,11 @@
#define MULTIQ3_TRSFRCNTR_OL 0x10 /* xfer CNTR to OL (x and y) */
#define MULTIQ3_EFLAG_RESET 0x06 /* reset E bit of flag reg */
/*
* Limit on the number of optional encoder channels
*/
#define MULTIQ3_MAX_ENC_CHANS 8
static void multiq3_set_ctrl(struct comedi_device *dev, unsigned int bits)
{
/*
@@ -312,6 +317,10 @@ static int multiq3_attach(struct comedi_device *dev,
s->insn_read = multiq3_encoder_insn_read;
s->insn_config = multiq3_encoder_insn_config;
/* sanity check for number of encoder channels */
if (s->n_chan > MULTIQ3_MAX_ENC_CHANS)
s->n_chan = MULTIQ3_MAX_ENC_CHANS;
for (i = 0; i < s->n_chan; i++)
multiq3_encoder_reset(dev, i);

View File

@@ -1111,10 +1111,9 @@ static void pcl818_detach(struct comedi_device *dev)
{
struct pcl818_private *devpriv = dev->private;
if (devpriv) {
pcl818_ai_cancel(dev, dev->read_subdev);
if (devpriv)
pcl818_reset(dev);
}
pcl818_free_dma(dev);
comedi_legacy_detach(dev);
}

View File

@@ -15,6 +15,7 @@
#include <linux/fcntl.h>
#include <linux/mm.h>
#include <linux/io.h>
#include <linux/bitmap.h>
#include <linux/comedi.h>
#include <linux/comedi/comedidev.h>
@@ -24,7 +25,104 @@ MODULE_AUTHOR("David Schleef <ds@schleef.org>");
MODULE_DESCRIPTION("Comedi kernel library");
MODULE_LICENSE("GPL");
struct comedi_device *comedi_open(const char *filename)
static DEFINE_MUTEX(kcomedilib_to_from_lock);
/*
* Row index is the "to" node, column index is the "from" node, element value
* is the number of links from the "from" node to the "to" node.
*/
static unsigned char
kcomedilib_to_from[COMEDI_NUM_BOARD_MINORS][COMEDI_NUM_BOARD_MINORS];
static bool kcomedilib_set_link_from_to(unsigned int from, unsigned int to)
{
DECLARE_BITMAP(destinations[2], COMEDI_NUM_BOARD_MINORS);
unsigned int cur = 0;
bool okay = true;
/*
* Allow "from" node to be out of range (no loop checking),
* but require "to" node to be in range.
*/
if (to >= COMEDI_NUM_BOARD_MINORS)
return false;
if (from >= COMEDI_NUM_BOARD_MINORS)
return true;
/*
* Check that kcomedilib_to_from[to][from] can be made non-zero
* without creating a loop.
*
* Termination of the loop-testing code relies on the assumption that
* kcomedilib_to_from[][] does not contain any loops.
*
* Start with a set destinations set containing "from" as the only
* element and work backwards looking for loops.
*/
bitmap_zero(destinations[cur], COMEDI_NUM_BOARD_MINORS);
set_bit(from, destinations[cur]);
mutex_lock(&kcomedilib_to_from_lock);
do {
unsigned int next = 1 - cur;
unsigned int t = 0;
if (test_bit(to, destinations[cur])) {
/* Loop detected. */
okay = false;
break;
}
/* Create next set of destinations. */
bitmap_zero(destinations[next], COMEDI_NUM_BOARD_MINORS);
while ((t = find_next_bit(destinations[cur],
COMEDI_NUM_BOARD_MINORS,
t)) < COMEDI_NUM_BOARD_MINORS) {
unsigned int f;
for (f = 0; f < COMEDI_NUM_BOARD_MINORS; f++) {
if (kcomedilib_to_from[t][f])
set_bit(f, destinations[next]);
}
t++;
}
cur = next;
} while (!bitmap_empty(destinations[cur], COMEDI_NUM_BOARD_MINORS));
if (okay) {
/* Allow a maximum of 255 links from "from" to "to". */
if (kcomedilib_to_from[to][from] < 255)
kcomedilib_to_from[to][from]++;
else
okay = false;
}
mutex_unlock(&kcomedilib_to_from_lock);
return okay;
}
static void kcomedilib_clear_link_from_to(unsigned int from, unsigned int to)
{
if (to < COMEDI_NUM_BOARD_MINORS && from < COMEDI_NUM_BOARD_MINORS) {
mutex_lock(&kcomedilib_to_from_lock);
if (kcomedilib_to_from[to][from])
kcomedilib_to_from[to][from]--;
mutex_unlock(&kcomedilib_to_from_lock);
}
}
/**
* comedi_open_from() - Open a COMEDI device from the kernel with loop checks
* @filename: Fake pathname of the form "/dev/comediN".
* @from: Device number it is being opened from (if in range).
*
* Converts @filename to a COMEDI device number and "opens" it if it exists
* and is attached to a low-level COMEDI driver.
*
* If @from is in range, refuse to open the device if doing so would form a
* loop of devices opening each other. There is also a limit of 255 on the
* number of concurrent opens from one device to another.
*
* Return: A pointer to the COMEDI device on success.
* Return %NULL on failure.
*/
struct comedi_device *comedi_open_from(const char *filename, int from)
{
struct comedi_device *dev, *retval = NULL;
unsigned int minor;
@@ -43,7 +141,7 @@ struct comedi_device *comedi_open(const char *filename)
return NULL;
down_read(&dev->attach_lock);
if (dev->attached)
if (dev->attached && kcomedilib_set_link_from_to(from, minor))
retval = dev;
else
retval = NULL;
@@ -54,14 +152,26 @@ struct comedi_device *comedi_open(const char *filename)
return retval;
}
EXPORT_SYMBOL_GPL(comedi_open);
EXPORT_SYMBOL_GPL(comedi_open_from);
int comedi_close(struct comedi_device *dev)
/**
* comedi_close_from() - Close a COMEDI device from the kernel with loop checks
* @dev: COMEDI device.
* @from: Device number it was opened from (if in range).
*
* Closes a COMEDI device previously opened by comedi_open_from().
*
* If @from is in range, it should be match the one used by comedi_open_from().
*
* Returns: 0
*/
int comedi_close_from(struct comedi_device *dev, int from)
{
kcomedilib_clear_link_from_to(from, dev->minor);
comedi_dev_put(dev);
return 0;
}
EXPORT_SYMBOL_GPL(comedi_close);
EXPORT_SYMBOL_GPL(comedi_close_from);
static int comedi_do_insn(struct comedi_device *dev,
struct comedi_insn *insn,

View File

@@ -135,7 +135,7 @@ static int eisa_bus_uevent(const struct device *dev, struct kobj_uevent_env *env
return 0;
}
struct bus_type eisa_bus_type = {
const struct bus_type eisa_bus_type = {
.name = "eisa",
.match = eisa_bus_match,
.uevent = eisa_bus_uevent,

View File

@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2018-2019, Intel Corporation
* Copyright (C) 2025, Altera Corporation
*/
#include <linux/arm-smccc.h>
@@ -14,11 +15,9 @@
#include <linux/firmware/intel/stratix10-svc-client.h>
#include <linux/string.h>
#include <linux/sysfs.h>
#include <linux/delay.h>
#define RSU_STATE_MASK GENMASK_ULL(31, 0)
#define RSU_VERSION_MASK GENMASK_ULL(63, 32)
#define RSU_ERROR_LOCATION_MASK GENMASK_ULL(31, 0)
#define RSU_ERROR_DETAIL_MASK GENMASK_ULL(63, 32)
#define RSU_ERASE_SIZE_MASK GENMASK_ULL(63, 32)
#define RSU_DCMF0_MASK GENMASK_ULL(31, 0)
#define RSU_DCMF1_MASK GENMASK_ULL(63, 32)
#define RSU_DCMF2_MASK GENMASK_ULL(31, 0)
@@ -35,7 +34,8 @@
#define INVALID_DCMF_STATUS 0xFFFFFFFF
#define INVALID_SPT_ADDRESS 0x0
#define RSU_GET_SPT_CMD 0x5A
#define RSU_RETRY_SLEEP_MS (1U)
#define RSU_ASYNC_MSG_RETRY (3U)
#define RSU_GET_SPT_RESP_LEN (4 * sizeof(unsigned int))
typedef void (*rsu_callback)(struct stratix10_svc_client *client,
@@ -64,7 +64,6 @@ typedef void (*rsu_callback)(struct stratix10_svc_client *client,
* @max_retry: the preset max retry value
* @spt0_address: address of spt0
* @spt1_address: address of spt1
* @get_spt_response_buf: response from sdm for get_spt command
*/
struct stratix10_rsu_priv {
struct stratix10_svc_chan *chan;
@@ -99,47 +98,32 @@ struct stratix10_rsu_priv {
unsigned long spt0_address;
unsigned long spt1_address;
unsigned int *get_spt_response_buf;
};
typedef void (*rsu_async_callback)(struct device *dev,
struct stratix10_rsu_priv *priv, struct stratix10_svc_cb_data *data);
/**
* rsu_status_callback() - Status callback from Intel Service Layer
* @client: pointer to service client
* rsu_async_status_callback() - Status callback from rsu_async_send()
* @dev: pointer to device object
* @priv: pointer to priv object
* @data: pointer to callback data structure
*
* Callback from Intel service layer for RSU status request. Status is
* only updated after a system reboot, so a get updated status call is
* made during driver probe.
* Callback from rsu_async_send() to get the system rsu error status.
*/
static void rsu_status_callback(struct stratix10_svc_client *client,
struct stratix10_svc_cb_data *data)
static void rsu_async_status_callback(struct device *dev,
struct stratix10_rsu_priv *priv,
struct stratix10_svc_cb_data *data)
{
struct stratix10_rsu_priv *priv = client->priv;
struct arm_smccc_res *res = (struct arm_smccc_res *)data->kaddr1;
struct arm_smccc_1_2_regs *res = (struct arm_smccc_1_2_regs *)data->kaddr1;
if (data->status == BIT(SVC_STATUS_OK)) {
priv->status.version = FIELD_GET(RSU_VERSION_MASK,
res->a2);
priv->status.state = FIELD_GET(RSU_STATE_MASK, res->a2);
priv->status.fail_image = res->a1;
priv->status.current_image = res->a0;
priv->status.error_location =
FIELD_GET(RSU_ERROR_LOCATION_MASK, res->a3);
priv->status.error_details =
FIELD_GET(RSU_ERROR_DETAIL_MASK, res->a3);
} else {
dev_err(client->dev, "COMMAND_RSU_STATUS returned 0x%lX\n",
res->a0);
priv->status.version = 0;
priv->status.state = 0;
priv->status.fail_image = 0;
priv->status.current_image = 0;
priv->status.error_location = 0;
priv->status.error_details = 0;
}
complete(&priv->completion);
priv->status.current_image = res->a2;
priv->status.fail_image = res->a3;
priv->status.state = res->a4;
priv->status.version = res->a5;
priv->status.error_location = res->a7;
priv->status.error_details = res->a8;
priv->retry_counter = res->a9;
}
/**
@@ -163,32 +147,6 @@ static void rsu_command_callback(struct stratix10_svc_client *client,
complete(&priv->completion);
}
/**
* rsu_retry_callback() - Callback from Intel service layer for getting
* the current image's retry counter from the firmware
* @client: pointer to client
* @data: pointer to callback data structure
*
* Callback from Intel service layer for retry counter, which is used by
* user to know how many times the images is still allowed to reload
* itself before giving up and starting RSU fail-over flow.
*/
static void rsu_retry_callback(struct stratix10_svc_client *client,
struct stratix10_svc_cb_data *data)
{
struct stratix10_rsu_priv *priv = client->priv;
unsigned int *counter = (unsigned int *)data->kaddr1;
if (data->status == BIT(SVC_STATUS_OK))
priv->retry_counter = *counter;
else if (data->status == BIT(SVC_STATUS_NO_SUPPORT))
dev_warn(client->dev, "Secure FW doesn't support retry\n");
else
dev_err(client->dev, "Failed to get retry counter %lu\n",
BIT(data->status));
complete(&priv->completion);
}
/**
* rsu_max_retry_callback() - Callback from Intel service layer for getting
@@ -270,34 +228,19 @@ static void rsu_dcmf_status_callback(struct stratix10_svc_client *client,
complete(&priv->completion);
}
static void rsu_get_spt_callback(struct stratix10_svc_client *client,
struct stratix10_svc_cb_data *data)
/**
* rsu_async_get_spt_table_callback() - Callback to be used by the rsu_async_send()
* to retrieve the SPT table information.
* @dev: pointer to device object
* @priv: pointer to priv object
* @data: pointer to callback data structure
*/
static void rsu_async_get_spt_table_callback(struct device *dev,
struct stratix10_rsu_priv *priv,
struct stratix10_svc_cb_data *data)
{
struct stratix10_rsu_priv *priv = client->priv;
unsigned long *mbox_err = (unsigned long *)data->kaddr1;
unsigned long *resp_len = (unsigned long *)data->kaddr2;
if (data->status != BIT(SVC_STATUS_OK) || (*mbox_err) ||
(*resp_len != RSU_GET_SPT_RESP_LEN))
goto error;
priv->spt0_address = priv->get_spt_response_buf[0];
priv->spt0_address <<= 32;
priv->spt0_address |= priv->get_spt_response_buf[1];
priv->spt1_address = priv->get_spt_response_buf[2];
priv->spt1_address <<= 32;
priv->spt1_address |= priv->get_spt_response_buf[3];
goto complete;
error:
dev_err(client->dev, "failed to get SPTs\n");
complete:
stratix10_svc_free_memory(priv->chan, priv->get_spt_response_buf);
priv->get_spt_response_buf = NULL;
complete(&priv->completion);
priv->spt0_address = *((unsigned long *)data->kaddr1);
priv->spt1_address = *((unsigned long *)data->kaddr2);
}
/**
@@ -329,14 +272,6 @@ static int rsu_send_msg(struct stratix10_rsu_priv *priv,
if (arg)
msg.arg[0] = arg;
if (command == COMMAND_MBOX_SEND_CMD) {
msg.arg[1] = 0;
msg.payload = NULL;
msg.payload_length = 0;
msg.payload_output = priv->get_spt_response_buf;
msg.payload_length_output = RSU_GET_SPT_RESP_LEN;
}
ret = stratix10_svc_send(priv->chan, &msg);
if (ret < 0)
goto status_done;
@@ -362,6 +297,95 @@ status_done:
return ret;
}
/**
* soc64_async_callback() - Callback from Intel service layer for async requests
* @ptr: pointer to the completion object
*/
static void soc64_async_callback(void *ptr)
{
if (ptr)
complete(ptr);
}
/**
* rsu_send_async_msg() - send an async message to Intel service layer
* @dev: pointer to device object
* @priv: pointer to rsu private data
* @command: RSU status or update command
* @arg: the request argument, notify status
* @callback: function pointer for the callback (status or update)
*/
static int rsu_send_async_msg(struct device *dev, struct stratix10_rsu_priv *priv,
enum stratix10_svc_command_code command,
unsigned long arg,
rsu_async_callback callback)
{
struct stratix10_svc_client_msg msg = {0};
struct stratix10_svc_cb_data data = {0};
struct completion completion;
int status, index, ret;
void *handle = NULL;
msg.command = command;
msg.arg[0] = arg;
init_completion(&completion);
for (index = 0; index < RSU_ASYNC_MSG_RETRY; index++) {
status = stratix10_svc_async_send(priv->chan, &msg,
&handle, soc64_async_callback,
&completion);
if (status == 0)
break;
dev_warn(dev, "Failed to send async message\n");
msleep(RSU_RETRY_SLEEP_MS);
}
if (status && !handle) {
dev_err(dev, "Failed to send async message\n");
return -ETIMEDOUT;
}
ret = wait_for_completion_io_timeout(&completion, RSU_TIMEOUT);
if (ret > 0)
dev_dbg(dev, "Received async interrupt\n");
else if (ret == 0)
dev_dbg(dev, "Timeout occurred. Trying to poll the response\n");
for (index = 0; index < RSU_ASYNC_MSG_RETRY; index++) {
status = stratix10_svc_async_poll(priv->chan, handle, &data);
if (status == -EAGAIN) {
dev_dbg(dev, "Async message is still in progress\n");
} else if (status < 0) {
dev_alert(dev, "Failed to poll async message\n");
ret = -ETIMEDOUT;
} else if (status == 0) {
ret = 0;
break;
}
msleep(RSU_RETRY_SLEEP_MS);
}
if (ret) {
dev_err(dev, "Failed to get async response\n");
goto status_done;
}
if (data.status == 0) {
ret = 0;
if (callback)
callback(dev, priv, &data);
} else {
dev_err(dev, "%s returned 0x%x from SDM\n", __func__,
data.status);
ret = -EFAULT;
}
status_done:
stratix10_svc_async_done(priv->chan, handle);
return ret;
}
/*
* This driver exposes some optional features of the Intel Stratix 10 SoC FPGA.
* The sysfs interfaces exposed here are FPGA Remote System Update (RSU)
@@ -454,8 +478,7 @@ static ssize_t max_retry_show(struct device *dev,
if (!priv)
return -ENODEV;
return scnprintf(buf, sizeof(priv->max_retry),
"0x%08x\n", priv->max_retry);
return sysfs_emit(buf, "0x%08x\n", priv->max_retry);
}
static ssize_t dcmf0_show(struct device *dev,
@@ -597,27 +620,20 @@ static ssize_t notify_store(struct device *dev,
if (ret)
return ret;
ret = rsu_send_msg(priv, COMMAND_RSU_NOTIFY,
status, rsu_command_callback);
ret = rsu_send_async_msg(dev, priv, COMMAND_RSU_NOTIFY, status, NULL);
if (ret) {
dev_err(dev, "Error, RSU notify returned %i\n", ret);
return ret;
}
/* to get the updated state */
ret = rsu_send_msg(priv, COMMAND_RSU_STATUS,
0, rsu_status_callback);
ret = rsu_send_async_msg(dev, priv, COMMAND_RSU_STATUS, 0,
rsu_async_status_callback);
if (ret) {
dev_err(dev, "Error, getting RSU status %i\n", ret);
return ret;
}
ret = rsu_send_msg(priv, COMMAND_RSU_RETRY, 0, rsu_retry_callback);
if (ret) {
dev_err(dev, "Error, getting RSU retry %i\n", ret);
return ret;
}
return count;
}
@@ -632,7 +648,7 @@ static ssize_t spt0_address_show(struct device *dev,
if (priv->spt0_address == INVALID_SPT_ADDRESS)
return -EIO;
return scnprintf(buf, PAGE_SIZE, "0x%08lx\n", priv->spt0_address);
return sysfs_emit(buf, "0x%08lx\n", priv->spt0_address);
}
static ssize_t spt1_address_show(struct device *dev,
@@ -646,7 +662,7 @@ static ssize_t spt1_address_show(struct device *dev,
if (priv->spt1_address == INVALID_SPT_ADDRESS)
return -EIO;
return scnprintf(buf, PAGE_SIZE, "0x%08lx\n", priv->spt1_address);
return sysfs_emit(buf, "0x%08lx\n", priv->spt1_address);
}
static DEVICE_ATTR_RO(current_image);
@@ -737,12 +753,19 @@ static int stratix10_rsu_probe(struct platform_device *pdev)
return PTR_ERR(priv->chan);
}
ret = stratix10_svc_add_async_client(priv->chan, false);
if (ret) {
dev_err(dev, "failed to add async client\n");
stratix10_svc_free_channel(priv->chan);
return ret;
}
init_completion(&priv->completion);
platform_set_drvdata(pdev, priv);
/* get the initial state from firmware */
ret = rsu_send_msg(priv, COMMAND_RSU_STATUS,
0, rsu_status_callback);
ret = rsu_send_async_msg(dev, priv, COMMAND_RSU_STATUS, 0,
rsu_async_status_callback);
if (ret) {
dev_err(dev, "Error, getting RSU status %i\n", ret);
stratix10_svc_free_channel(priv->chan);
@@ -763,12 +786,6 @@ static int stratix10_rsu_probe(struct platform_device *pdev)
stratix10_svc_free_channel(priv->chan);
}
ret = rsu_send_msg(priv, COMMAND_RSU_RETRY, 0, rsu_retry_callback);
if (ret) {
dev_err(dev, "Error, getting RSU retry %i\n", ret);
stratix10_svc_free_channel(priv->chan);
}
ret = rsu_send_msg(priv, COMMAND_RSU_MAX_RETRY, 0,
rsu_max_retry_callback);
if (ret) {
@@ -776,18 +793,12 @@ static int stratix10_rsu_probe(struct platform_device *pdev)
stratix10_svc_free_channel(priv->chan);
}
priv->get_spt_response_buf =
stratix10_svc_allocate_memory(priv->chan, RSU_GET_SPT_RESP_LEN);
if (IS_ERR(priv->get_spt_response_buf)) {
dev_err(dev, "failed to allocate get spt buffer\n");
} else {
ret = rsu_send_msg(priv, COMMAND_MBOX_SEND_CMD,
RSU_GET_SPT_CMD, rsu_get_spt_callback);
if (ret) {
dev_err(dev, "Error, getting SPT table %i\n", ret);
stratix10_svc_free_channel(priv->chan);
}
ret = rsu_send_async_msg(dev, priv, COMMAND_RSU_GET_SPT_TABLE, 0,
rsu_async_get_spt_table_callback);
if (ret) {
dev_err(dev, "Error, getting SPT table %i\n", ret);
stratix10_svc_free_channel(priv->chan);
}
return ret;

View File

@@ -1,11 +1,15 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2017-2018, Intel Corporation
* Copyright (C) 2025, Altera Corporation
*/
#include <linux/atomic.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/genalloc.h>
#include <linux/hashtable.h>
#include <linux/idr.h>
#include <linux/io.h>
#include <linux/kfifo.h>
#include <linux/kthread.h>
@@ -34,7 +38,7 @@
* timeout is set to 30 seconds (30 * 1000) at Intel Stratix10 SoC.
*/
#define SVC_NUM_DATA_IN_FIFO 32
#define SVC_NUM_CHANNEL 3
#define SVC_NUM_CHANNEL 4
#define FPGA_CONFIG_DATA_CLAIM_TIMEOUT_MS 200
#define FPGA_CONFIG_STATUS_TIMEOUT_SEC 30
#define BYTE_TO_WORD_SIZE 4
@@ -43,6 +47,55 @@
#define STRATIX10_RSU "stratix10-rsu"
#define INTEL_FCS "intel-fcs"
/* Maximum number of SDM client IDs. */
#define MAX_SDM_CLIENT_IDS 16
/* Client ID for SIP Service Version 1. */
#define SIP_SVC_V1_CLIENT_ID 0x1
/* Maximum number of SDM job IDs. */
#define MAX_SDM_JOB_IDS 16
/* Number of bits used for asynchronous transaction hashing. */
#define ASYNC_TRX_HASH_BITS 3
/*
* Total number of transaction IDs, which is a combination of
* client ID and job ID.
*/
#define TOTAL_TRANSACTION_IDS \
(MAX_SDM_CLIENT_IDS * MAX_SDM_JOB_IDS)
/* Minimum major version of the ATF for Asynchronous transactions. */
#define ASYNC_ATF_MINIMUM_MAJOR_VERSION 0x3
/* Minimum minor version of the ATF for Asynchronous transactions.*/
#define ASYNC_ATF_MINIMUM_MINOR_VERSION 0x0
/* Job ID field in the transaction ID */
#define STRATIX10_JOB_FIELD GENMASK(3, 0)
/* Client ID field in the transaction ID */
#define STRATIX10_CLIENT_FIELD GENMASK(7, 4)
/* Transaction ID mask for Stratix10 service layer */
#define STRATIX10_TRANS_ID_FIELD GENMASK(7, 0)
/* Macro to extract the job ID from a transaction ID. */
#define STRATIX10_GET_JOBID(transaction_id) \
(FIELD_GET(STRATIX10_JOB_FIELD, transaction_id))
/* Macro to set the job ID in a transaction ID. */
#define STRATIX10_SET_JOBID(jobid) \
(FIELD_PREP(STRATIX10_JOB_FIELD, jobid))
/* Macro to set the client ID in a transaction ID. */
#define STRATIX10_SET_CLIENTID(clientid) \
(FIELD_PREP(STRATIX10_CLIENT_FIELD, clientid))
/* Macro to set a transaction ID using a client ID and a job ID. */
#define STRATIX10_SET_TRANSACTIONID(clientid, jobid) \
(STRATIX10_SET_CLIENTID(clientid) | STRATIX10_SET_JOBID(jobid))
/* Macro to set a transaction ID for SIP SMC Async transactions */
#define STRATIX10_SIP_SMC_SET_TRANSACTIONID_X1(transaction_id) \
(FIELD_PREP(STRATIX10_TRANS_ID_FIELD, transaction_id))
/* 10-bit mask for extracting the SDM status code */
#define STRATIX10_SDM_STATUS_MASK GENMASK(9, 0)
/* Macro to get the SDM mailbox error status */
#define STRATIX10_GET_SDM_STATUS_CODE(status) \
(FIELD_GET(STRATIX10_SDM_STATUS_MASK, status))
typedef void (svc_invoke_fn)(unsigned long, unsigned long, unsigned long,
unsigned long, unsigned long, unsigned long,
unsigned long, unsigned long,
@@ -52,6 +105,7 @@ struct stratix10_svc_chan;
/**
* struct stratix10_svc - svc private data
* @stratix10_svc_rsu: pointer to stratix10 RSU device
* @intel_svc_fcs: pointer to the FCS device
*/
struct stratix10_svc {
struct platform_device *stratix10_svc_rsu;
@@ -63,7 +117,7 @@ struct stratix10_svc {
* @sync_complete: state for a completion
* @addr: physical address of shared memory block
* @size: size of shared memory block
* @invoke_fn: function to issue secure monitor or hypervisor call
* @invoke_fn: service clients to handle secure monitor or hypervisor calls
*
* This struct is used to save physical address and size of shared memory
* block. The shared memory blocked is allocated by secure monitor software
@@ -121,6 +175,74 @@ struct stratix10_svc_data {
u64 arg[3];
};
/**
* struct stratix10_svc_async_handler - Asynchronous handler for Stratix10
* service layer
* @transaction_id: Unique identifier for the transaction
* @achan: Pointer to the asynchronous channel structure
* @cb_arg: Argument to be passed to the callback function
* @cb: Callback function to be called upon completion
* @msg: Pointer to the client message structure
* @next: Node in the hash list
* @res: Response structure to store result from the secure firmware
*
* This structure is used to handle asynchronous transactions in the
* Stratix10 service layer. It maintains the necessary information
* for processing and completing asynchronous requests.
*/
struct stratix10_svc_async_handler {
u8 transaction_id;
struct stratix10_async_chan *achan;
void *cb_arg;
async_callback_t cb;
struct stratix10_svc_client_msg *msg;
struct hlist_node next;
struct arm_smccc_1_2_regs res;
};
/**
* struct stratix10_async_chan - Structure representing an asynchronous channel
* @async_client_id: Unique client identifier for the asynchronous operation
* @job_id_pool: Pointer to the job ID pool associated with this channel
*/
struct stratix10_async_chan {
unsigned long async_client_id;
struct ida job_id_pool;
};
/**
* struct stratix10_async_ctrl - Control structure for Stratix10
* asynchronous operations
* @initialized: Flag indicating whether the control structure has
* been initialized
* @invoke_fn: Function pointer for invoking Stratix10 service calls
* to EL3 secure firmware
* @async_id_pool: Pointer to the ID pool used for asynchronous
* operations
* @common_achan_refcount: Atomic reference count for the common
* asynchronous channel usage
* @common_async_chan: Pointer to the common asynchronous channel
* structure
* @trx_list_lock: Spinlock for protecting the transaction list
* operations
* @trx_list: Hash table for managing asynchronous transactions
*/
struct stratix10_async_ctrl {
bool initialized;
void (*invoke_fn)(struct stratix10_async_ctrl *actrl,
const struct arm_smccc_1_2_regs *args,
struct arm_smccc_1_2_regs *res);
struct ida async_id_pool;
atomic_t common_achan_refcount;
struct stratix10_async_chan *common_async_chan;
/* spinlock to protect trx_list hash table */
spinlock_t trx_list_lock;
DECLARE_HASHTABLE(trx_list, ASYNC_TRX_HASH_BITS);
};
/**
* struct stratix10_svc_controller - service controller
* @dev: device
@@ -135,6 +257,7 @@ struct stratix10_svc_data {
* @svc_fifo_lock: protect access to service message data queue
* @invoke_fn: function to issue secure monitor call or hypervisor call
* @svc: manages the list of client svc drivers
* @actrl: async control structure
*
* This struct is used to create communication channels for service clients, to
* handle secure monitor or hypervisor call.
@@ -152,6 +275,7 @@ struct stratix10_svc_controller {
spinlock_t svc_fifo_lock;
svc_invoke_fn *invoke_fn;
struct stratix10_svc *svc;
struct stratix10_async_ctrl actrl;
};
/**
@@ -160,20 +284,28 @@ struct stratix10_svc_controller {
* @scl: pointer to service client which owns the channel
* @name: service client name associated with the channel
* @lock: protect access to the channel
* @async_chan: reference to asynchronous channel object for this channel
*
* This struct is used by service client to communicate with service layer, each
* service client has its own channel created by service controller.
* This struct is used by service client to communicate with service layer.
* Each service client has its own channel created by service controller.
*/
struct stratix10_svc_chan {
struct stratix10_svc_controller *ctrl;
struct stratix10_svc_client *scl;
char *name;
spinlock_t lock;
struct stratix10_async_chan *async_chan;
};
static LIST_HEAD(svc_ctrl);
static LIST_HEAD(svc_data_mem);
/*
* svc_mem_lock protects access to the svc_data_mem list for
* concurrent multi-client operations
*/
static DEFINE_MUTEX(svc_mem_lock);
/**
* svc_pa_to_va() - translate physical address to virtual address
* @addr: to be translated physical address
@@ -186,6 +318,7 @@ static void *svc_pa_to_va(unsigned long addr)
struct stratix10_svc_data_mem *pmem;
pr_debug("claim back P-addr=0x%016x\n", (unsigned int)addr);
guard(mutex)(&svc_mem_lock);
list_for_each_entry(pmem, &svc_data_mem, node)
if (pmem->paddr == addr)
return pmem->vaddr;
@@ -343,6 +476,8 @@ static void svc_thread_recv_status_ok(struct stratix10_svc_data *p_data,
case COMMAND_RSU_MAX_RETRY:
case COMMAND_RSU_DCMF_STATUS:
case COMMAND_FIRMWARE_VERSION:
case COMMAND_HWMON_READTEMP:
case COMMAND_HWMON_READVOLT:
cb_data->status = BIT(SVC_STATUS_OK);
cb_data->kaddr1 = &res.a1;
break;
@@ -527,7 +662,17 @@ static int svc_normal_to_secure_thread(void *data)
a1 = (unsigned long)pdata->paddr;
a2 = 0;
break;
/* for HWMON */
case COMMAND_HWMON_READTEMP:
a0 = INTEL_SIP_SMC_HWMON_READTEMP;
a1 = pdata->arg[0];
a2 = 0;
break;
case COMMAND_HWMON_READVOLT:
a0 = INTEL_SIP_SMC_HWMON_READVOLT;
a1 = pdata->arg[0];
a2 = 0;
break;
/* for polling */
case COMMAND_POLL_SERVICE_STATUS:
a0 = INTEL_SIP_SMC_SERVICE_COMPLETED;
@@ -924,6 +1069,591 @@ struct stratix10_svc_chan *stratix10_svc_request_channel_byname(
}
EXPORT_SYMBOL_GPL(stratix10_svc_request_channel_byname);
/**
* stratix10_svc_add_async_client - Add an asynchronous client to the
* Stratix10 service channel.
* @chan: Pointer to the Stratix10 service channel structure.
* @use_unique_clientid: Boolean flag indicating whether to use a
* unique client ID.
*
* This function adds an asynchronous client to the specified
* Stratix10 service channel. If the `use_unique_clientid` flag is
* set to true, a unique client ID is allocated for the asynchronous
* channel. Otherwise, a common asynchronous channel is used.
*
* Return: 0 on success, or a negative error code on failure:
* -EINVAL if the channel is NULL or the async controller is
* not initialized.
* -EALREADY if the async channel is already allocated.
* -ENOMEM if memory allocation fails.
* Other negative values if ID allocation fails.
*/
int stratix10_svc_add_async_client(struct stratix10_svc_chan *chan,
bool use_unique_clientid)
{
struct stratix10_svc_controller *ctrl;
struct stratix10_async_ctrl *actrl;
struct stratix10_async_chan *achan;
int ret = 0;
if (!chan)
return -EINVAL;
ctrl = chan->ctrl;
actrl = &ctrl->actrl;
if (!actrl->initialized) {
dev_err(ctrl->dev, "Async controller not initialized\n");
return -EINVAL;
}
if (chan->async_chan) {
dev_err(ctrl->dev, "async channel already allocated\n");
return -EALREADY;
}
if (use_unique_clientid &&
atomic_read(&actrl->common_achan_refcount) > 0) {
chan->async_chan = actrl->common_async_chan;
atomic_inc(&actrl->common_achan_refcount);
return 0;
}
achan = kzalloc(sizeof(*achan), GFP_KERNEL);
if (!achan)
return -ENOMEM;
ida_init(&achan->job_id_pool);
ret = ida_alloc_max(&actrl->async_id_pool, MAX_SDM_CLIENT_IDS,
GFP_KERNEL);
if (ret < 0) {
dev_err(ctrl->dev,
"Failed to allocate async client id\n");
ida_destroy(&achan->job_id_pool);
kfree(achan);
return ret;
}
achan->async_client_id = ret;
chan->async_chan = achan;
if (use_unique_clientid &&
atomic_read(&actrl->common_achan_refcount) == 0) {
actrl->common_async_chan = achan;
atomic_inc(&actrl->common_achan_refcount);
}
return 0;
}
EXPORT_SYMBOL_GPL(stratix10_svc_add_async_client);
/**
* stratix10_svc_remove_async_client - Remove an asynchronous client
* from the Stratix10 service
* channel.
* @chan: Pointer to the Stratix10 service channel structure.
*
* This function removes an asynchronous client associated with the
* given service channel. It checks if the channel and the
* asynchronous channel are valid, and then proceeds to decrement
* the reference count for the common asynchronous channel if
* applicable. If the reference count reaches zero, it destroys the
* job ID pool and deallocates the asynchronous client ID. For
* non-common asynchronous channels, it directly destroys the job ID
* pool, deallocates the asynchronous client ID, and frees the
* memory allocated for the asynchronous channel.
*
* Return: 0 on success, -EINVAL if the channel or asynchronous
* channel is invalid.
*/
int stratix10_svc_remove_async_client(struct stratix10_svc_chan *chan)
{
struct stratix10_svc_controller *ctrl;
struct stratix10_async_ctrl *actrl;
struct stratix10_async_chan *achan;
if (!chan)
return -EINVAL;
ctrl = chan->ctrl;
actrl = &ctrl->actrl;
achan = chan->async_chan;
if (!achan) {
dev_err(ctrl->dev, "async channel not allocated\n");
return -EINVAL;
}
if (achan == actrl->common_async_chan) {
atomic_dec(&actrl->common_achan_refcount);
if (atomic_read(&actrl->common_achan_refcount) == 0) {
ida_destroy(&achan->job_id_pool);
ida_free(&actrl->async_id_pool,
achan->async_client_id);
kfree(achan);
actrl->common_async_chan = NULL;
}
} else {
ida_destroy(&achan->job_id_pool);
ida_free(&actrl->async_id_pool, achan->async_client_id);
kfree(achan);
}
chan->async_chan = NULL;
return 0;
}
EXPORT_SYMBOL_GPL(stratix10_svc_remove_async_client);
/**
* stratix10_svc_async_send - Send an asynchronous message to the
* Stratix10 service
* @chan: Pointer to the service channel structure
* @msg: Pointer to the message to be sent
* @handler: Pointer to the handler for the asynchronous message
* used by caller for later reference.
* @cb: Callback function to be called upon completion
* @cb_arg: Argument to be passed to the callback function
*
* This function sends an asynchronous message to the SDM mailbox in
* EL3 secure firmware. It performs various checks and setups,
* including allocating a job ID, setting up the transaction ID and
* packaging it to El3 firmware. The function handles different
* commands by setting up the appropriate arguments for the SMC call.
* If the SMC call is successful, the handler is set up and the
* function returns 0. If the SMC call fails, appropriate error
* handling is performed along with cleanup of resources.
*
* Return: 0 on success, -EINVAL for invalid argument, -ENOMEM if
* memory is not available, -EAGAIN if EL3 firmware is busy, -EBADF
* if the message is rejected by EL3 firmware and -EIO on other
* errors from EL3 firmware.
*/
int stratix10_svc_async_send(struct stratix10_svc_chan *chan, void *msg,
void **handler, async_callback_t cb, void *cb_arg)
{
struct arm_smccc_1_2_regs args = { 0 }, res = { 0 };
struct stratix10_svc_async_handler *handle = NULL;
struct stratix10_svc_client_msg *p_msg =
(struct stratix10_svc_client_msg *)msg;
struct stratix10_svc_controller *ctrl;
struct stratix10_async_ctrl *actrl;
struct stratix10_async_chan *achan;
int ret = 0;
if (!chan || !msg || !handler)
return -EINVAL;
achan = chan->async_chan;
ctrl = chan->ctrl;
actrl = &ctrl->actrl;
if (!actrl->initialized) {
dev_err(ctrl->dev, "Async controller not initialized\n");
return -EINVAL;
}
if (!achan) {
dev_err(ctrl->dev, "Async channel not allocated\n");
return -EINVAL;
}
handle = kzalloc(sizeof(*handle), GFP_KERNEL);
if (!handle)
return -ENOMEM;
ret = ida_alloc_max(&achan->job_id_pool, MAX_SDM_JOB_IDS,
GFP_KERNEL);
if (ret < 0) {
dev_err(ctrl->dev, "Failed to allocate job id\n");
kfree(handle);
return -ENOMEM;
}
handle->transaction_id =
STRATIX10_SET_TRANSACTIONID(achan->async_client_id, ret);
handle->cb = cb;
handle->msg = p_msg;
handle->cb_arg = cb_arg;
handle->achan = achan;
/*set the transaction jobid in args.a1*/
args.a1 =
STRATIX10_SIP_SMC_SET_TRANSACTIONID_X1(handle->transaction_id);
switch (p_msg->command) {
case COMMAND_RSU_GET_SPT_TABLE:
args.a0 = INTEL_SIP_SMC_ASYNC_RSU_GET_SPT;
break;
case COMMAND_RSU_STATUS:
args.a0 = INTEL_SIP_SMC_ASYNC_RSU_GET_ERROR_STATUS;
break;
case COMMAND_RSU_NOTIFY:
args.a0 = INTEL_SIP_SMC_ASYNC_RSU_NOTIFY;
args.a2 = p_msg->arg[0];
break;
default:
dev_err(ctrl->dev, "Invalid command ,%d\n", p_msg->command);
ret = -EINVAL;
goto deallocate_id;
}
/**
* There is a chance that during the execution of async_send()
* in one core, an interrupt might be received in another core;
* to mitigate this we are adding the handle to the DB and then
* send the smc call. If the smc call is rejected or busy then
* we will deallocate the handle for the client to retry again.
*/
scoped_guard(spinlock_bh, &actrl->trx_list_lock) {
hash_add(actrl->trx_list, &handle->next,
handle->transaction_id);
}
actrl->invoke_fn(actrl, &args, &res);
switch (res.a0) {
case INTEL_SIP_SMC_STATUS_OK:
dev_dbg(ctrl->dev,
"Async message sent with transaction_id 0x%02x\n",
handle->transaction_id);
*handler = handle;
return 0;
case INTEL_SIP_SMC_STATUS_BUSY:
dev_warn(ctrl->dev, "Mailbox is busy, try after some time\n");
ret = -EAGAIN;
break;
case INTEL_SIP_SMC_STATUS_REJECTED:
dev_err(ctrl->dev, "Async message rejected\n");
ret = -EBADF;
break;
default:
dev_err(ctrl->dev,
"Failed to send async message ,got status as %ld\n",
res.a0);
ret = -EIO;
}
scoped_guard(spinlock_bh, &actrl->trx_list_lock) {
hash_del(&handle->next);
}
deallocate_id:
ida_free(&achan->job_id_pool,
STRATIX10_GET_JOBID(handle->transaction_id));
kfree(handle);
return ret;
}
EXPORT_SYMBOL_GPL(stratix10_svc_async_send);
/**
* stratix10_svc_async_prepare_response - Prepare the response data for
* an asynchronous transaction.
* @chan: Pointer to the service channel structure.
* @handle: Pointer to the asynchronous handler structure.
* @data: Pointer to the callback data structure.
*
* This function prepares the response data for an asynchronous transaction. It
* extracts the response data from the SMC response structure and stores it in
* the callback data structure. The function also logs the completion of the
* asynchronous transaction.
*
* Return: 0 on success, -ENOENT if the command is invalid
*/
static int stratix10_svc_async_prepare_response(struct stratix10_svc_chan *chan,
struct stratix10_svc_async_handler *handle,
struct stratix10_svc_cb_data *data)
{
struct stratix10_svc_client_msg *p_msg =
(struct stratix10_svc_client_msg *)handle->msg;
struct stratix10_svc_controller *ctrl = chan->ctrl;
data->status = STRATIX10_GET_SDM_STATUS_CODE(handle->res.a1);
switch (p_msg->command) {
case COMMAND_RSU_NOTIFY:
break;
case COMMAND_RSU_GET_SPT_TABLE:
data->kaddr1 = (void *)&handle->res.a2;
data->kaddr2 = (void *)&handle->res.a3;
break;
case COMMAND_RSU_STATUS:
/* COMMAND_RSU_STATUS has more elements than the cb_data
* can acomodate, so passing the response structure to the
* response function to be handled before done command is
* executed by the client.
*/
data->kaddr1 = (void *)&handle->res;
break;
default:
dev_alert(ctrl->dev, "Invalid command\n ,%d", p_msg->command);
return -ENOENT;
}
dev_dbg(ctrl->dev, "Async message completed transaction_id 0x%02x\n",
handle->transaction_id);
return 0;
}
/**
* stratix10_svc_async_poll - Polls the status of an asynchronous
* transaction.
* @chan: Pointer to the service channel structure.
* @tx_handle: Handle to the transaction being polled.
* @data: Pointer to the callback data structure.
*
* This function polls the status of an asynchronous transaction
* identified by the given transaction handle. It ensures that the
* necessary structures are initialized and valid before proceeding
* with the poll operation. The function sets up the necessary
* arguments for the SMC call, invokes the call, and prepares the
* response data if the call is successful. If the call fails, the
* function returns the error mapped to the SVC status error.
*
* Return: 0 on success, -EINVAL if any input parameter is invalid,
* -EAGAIN if the transaction is still in progress,
* -EPERM if the command is invalid, or other negative
* error codes on failure.
*/
int stratix10_svc_async_poll(struct stratix10_svc_chan *chan,
void *tx_handle,
struct stratix10_svc_cb_data *data)
{
struct stratix10_svc_async_handler *handle;
struct arm_smccc_1_2_regs args = { 0 };
struct stratix10_svc_controller *ctrl;
struct stratix10_async_ctrl *actrl;
struct stratix10_async_chan *achan;
int ret;
if (!chan || !tx_handle || !data)
return -EINVAL;
ctrl = chan->ctrl;
actrl = &ctrl->actrl;
achan = chan->async_chan;
if (!achan) {
dev_err(ctrl->dev, "Async channel not allocated\n");
return -EINVAL;
}
handle = (struct stratix10_svc_async_handler *)tx_handle;
scoped_guard(spinlock_bh, &actrl->trx_list_lock) {
if (!hash_hashed(&handle->next)) {
dev_err(ctrl->dev, "Invalid transaction handler");
return -EINVAL;
}
}
args.a0 = INTEL_SIP_SMC_ASYNC_POLL;
args.a1 =
STRATIX10_SIP_SMC_SET_TRANSACTIONID_X1(handle->transaction_id);
actrl->invoke_fn(actrl, &args, &handle->res);
/*clear data for response*/
memset(data, 0, sizeof(*data));
if (handle->res.a0 == INTEL_SIP_SMC_STATUS_OK) {
ret = stratix10_svc_async_prepare_response(chan, handle, data);
if (ret) {
dev_err(ctrl->dev, "Error in preparation of response,%d\n", ret);
WARN_ON_ONCE(1);
}
return 0;
} else if (handle->res.a0 == INTEL_SIP_SMC_STATUS_BUSY) {
dev_dbg(ctrl->dev, "async message is still in progress\n");
return -EAGAIN;
}
dev_err(ctrl->dev,
"Failed to poll async message ,got status as %ld\n",
handle->res.a0);
return -EINVAL;
}
EXPORT_SYMBOL_GPL(stratix10_svc_async_poll);
/**
* stratix10_svc_async_done - Completes an asynchronous transaction.
* @chan: Pointer to the service channel structure.
* @tx_handle: Handle to the transaction being completed.
*
* This function completes an asynchronous transaction identified by
* the given transaction handle. It ensures that the necessary
* structures are initialized and valid before proceeding with the
* completion operation. The function deallocates the transaction ID,
* frees the memory allocated for the handler, and removes the handler
* from the transaction list.
*
* Return: 0 on success, -EINVAL if any input parameter is invalid,
* or other negative error codes on failure.
*/
int stratix10_svc_async_done(struct stratix10_svc_chan *chan, void *tx_handle)
{
struct stratix10_svc_async_handler *handle;
struct stratix10_svc_controller *ctrl;
struct stratix10_async_chan *achan;
struct stratix10_async_ctrl *actrl;
if (!chan || !tx_handle)
return -EINVAL;
ctrl = chan->ctrl;
achan = chan->async_chan;
actrl = &ctrl->actrl;
if (!achan) {
dev_err(ctrl->dev, "async channel not allocated\n");
return -EINVAL;
}
handle = (struct stratix10_svc_async_handler *)tx_handle;
scoped_guard(spinlock_bh, &actrl->trx_list_lock) {
if (!hash_hashed(&handle->next)) {
dev_err(ctrl->dev, "Invalid transaction handle");
return -EINVAL;
}
hash_del(&handle->next);
}
ida_free(&achan->job_id_pool,
STRATIX10_GET_JOBID(handle->transaction_id));
kfree(handle);
return 0;
}
EXPORT_SYMBOL_GPL(stratix10_svc_async_done);
static inline void stratix10_smc_1_2(struct stratix10_async_ctrl *actrl,
const struct arm_smccc_1_2_regs *args,
struct arm_smccc_1_2_regs *res)
{
arm_smccc_1_2_smc(args, res);
}
/**
* stratix10_svc_async_init - Initialize the Stratix10 service
* controller for asynchronous operations.
* @controller: Pointer to the Stratix10 service controller structure.
*
* This function initializes the asynchronous service controller by
* setting up the necessary data structures and initializing the
* transaction list.
*
* Return: 0 on success, -EINVAL if the controller is NULL or already
* initialized, -ENOMEM if memory allocation fails,
* -EADDRINUSE if the client ID is already reserved, or other
* negative error codes on failure.
*/
static int stratix10_svc_async_init(struct stratix10_svc_controller *controller)
{
struct stratix10_async_ctrl *actrl;
struct arm_smccc_res res;
struct device *dev;
int ret;
if (!controller)
return -EINVAL;
actrl = &controller->actrl;
if (actrl->initialized)
return -EINVAL;
dev = controller->dev;
controller->invoke_fn(INTEL_SIP_SMC_SVC_VERSION, 0, 0, 0, 0, 0, 0, 0, &res);
if (res.a0 != INTEL_SIP_SMC_STATUS_OK ||
!(res.a1 > ASYNC_ATF_MINIMUM_MAJOR_VERSION ||
(res.a1 == ASYNC_ATF_MINIMUM_MAJOR_VERSION &&
res.a2 >= ASYNC_ATF_MINIMUM_MINOR_VERSION))) {
dev_err(dev,
"Intel Service Layer Driver: ATF version is not compatible for async operation\n");
return -EINVAL;
}
actrl->invoke_fn = stratix10_smc_1_2;
ida_init(&actrl->async_id_pool);
/**
* SIP_SVC_V1_CLIENT_ID is used by V1/stratix10_svc_send() clients
* for communicating with SDM synchronously. We need to restrict
* this in V3/stratix10_svc_async_send() usage to distinguish
* between V1 and V3 messages in El3 firmware.
*/
ret = ida_alloc_range(&actrl->async_id_pool, SIP_SVC_V1_CLIENT_ID,
SIP_SVC_V1_CLIENT_ID, GFP_KERNEL);
if (ret < 0) {
dev_err(dev,
"Intel Service Layer Driver: Error on reserving SIP_SVC_V1_CLIENT_ID\n");
ida_destroy(&actrl->async_id_pool);
actrl->invoke_fn = NULL;
return -EADDRINUSE;
}
spin_lock_init(&actrl->trx_list_lock);
hash_init(actrl->trx_list);
atomic_set(&actrl->common_achan_refcount, 0);
actrl->initialized = true;
return 0;
}
/**
* stratix10_svc_async_exit - Clean up and exit the asynchronous
* service controller
* @ctrl: Pointer to the stratix10_svc_controller structure
*
* This function performs the necessary cleanup for the asynchronous
* service controller. It checks if the controller is valid and if it
* has been initialized. It then locks the transaction list and safely
* removes and deallocates each handler in the list. The function also
* removes any asynchronous clients associated with the controller's
* channels and destroys the asynchronous ID pool. Finally, it resets
* the asynchronous ID pool and invoke function pointers to NULL.
*
* Return: 0 on success, -EINVAL if the controller is invalid or not
* initialized.
*/
static int stratix10_svc_async_exit(struct stratix10_svc_controller *ctrl)
{
struct stratix10_svc_async_handler *handler;
struct stratix10_async_ctrl *actrl;
struct hlist_node *tmp;
int i;
if (!ctrl)
return -EINVAL;
actrl = &ctrl->actrl;
if (!actrl->initialized)
return -EINVAL;
actrl->initialized = false;
scoped_guard(spinlock_bh, &actrl->trx_list_lock) {
hash_for_each_safe(actrl->trx_list, i, tmp, handler, next) {
ida_free(&handler->achan->job_id_pool,
STRATIX10_GET_JOBID(handler->transaction_id));
hash_del(&handler->next);
kfree(handler);
}
}
for (i = 0; i < SVC_NUM_CHANNEL; i++) {
if (ctrl->chans[i].async_chan) {
stratix10_svc_remove_async_client(&ctrl->chans[i]);
ctrl->chans[i].async_chan = NULL;
}
}
ida_destroy(&actrl->async_id_pool);
actrl->invoke_fn = NULL;
return 0;
}
/**
* stratix10_svc_free_channel() - free service channel
* @chan: service channel to be freed
@@ -992,6 +1722,7 @@ int stratix10_svc_send(struct stratix10_svc_chan *chan, void *msg)
p_data->flag = ct->flags;
}
} else {
guard(mutex)(&svc_mem_lock);
list_for_each_entry(p_mem, &svc_data_mem, node)
if (p_mem->vaddr == p_msg->payload) {
p_data->paddr = p_mem->paddr;
@@ -1074,6 +1805,7 @@ void *stratix10_svc_allocate_memory(struct stratix10_svc_chan *chan,
if (!pmem)
return ERR_PTR(-ENOMEM);
guard(mutex)(&svc_mem_lock);
va = gen_pool_alloc(genpool, s);
if (!va)
return ERR_PTR(-ENOMEM);
@@ -1102,6 +1834,7 @@ EXPORT_SYMBOL_GPL(stratix10_svc_allocate_memory);
void stratix10_svc_free_memory(struct stratix10_svc_chan *chan, void *kaddr)
{
struct stratix10_svc_data_mem *pmem;
guard(mutex)(&svc_mem_lock);
list_for_each_entry(pmem, &svc_data_mem, node)
if (pmem->vaddr == kaddr) {
@@ -1176,11 +1909,18 @@ static int stratix10_svc_drv_probe(struct platform_device *pdev)
controller->invoke_fn = invoke_fn;
init_completion(&controller->complete_status);
ret = stratix10_svc_async_init(controller);
if (ret) {
dev_dbg(dev, "Intel Service Layer Driver: Error on stratix10_svc_async_init %d\n",
ret);
goto err_destroy_pool;
}
fifo_size = sizeof(struct stratix10_svc_data) * SVC_NUM_DATA_IN_FIFO;
ret = kfifo_alloc(&controller->svc_fifo, fifo_size, GFP_KERNEL);
if (ret) {
dev_err(dev, "failed to allocate FIFO\n");
goto err_destroy_pool;
goto err_async_exit;
}
spin_lock_init(&controller->svc_fifo_lock);
@@ -1199,6 +1939,11 @@ static int stratix10_svc_drv_probe(struct platform_device *pdev)
chans[2].name = SVC_CLIENT_FCS;
spin_lock_init(&chans[2].lock);
chans[3].scl = NULL;
chans[3].ctrl = controller;
chans[3].name = SVC_CLIENT_HWMON;
spin_lock_init(&chans[3].lock);
list_add_tail(&controller->node, &svc_ctrl);
platform_set_drvdata(pdev, controller);
@@ -1250,6 +1995,8 @@ err_unregister_rsu_dev:
platform_device_unregister(svc->stratix10_svc_rsu);
err_free_kfifo:
kfifo_free(&controller->svc_fifo);
err_async_exit:
stratix10_svc_async_exit(controller);
err_destroy_pool:
gen_pool_destroy(genpool);
return ret;
@@ -1260,6 +2007,8 @@ static void stratix10_svc_drv_remove(struct platform_device *pdev)
struct stratix10_svc_controller *ctrl = platform_get_drvdata(pdev);
struct stratix10_svc *svc = ctrl->svc;
stratix10_svc_async_exit(ctrl);
of_platform_depopulate(ctrl->dev);
platform_device_unregister(svc->intel_svc_fcs);

View File

@@ -22,9 +22,6 @@
#define TIMEOUT_US 2000 /* CVP STATUS timeout for USERMODE polling */
/* Vendor Specific Extended Capability Registers */
#define VSE_PCIE_EXT_CAP_ID 0x0
#define VSE_PCIE_EXT_CAP_ID_VAL 0x000b /* 16bit */
#define VSE_CVP_STATUS 0x1c /* 32bit */
#define VSE_CVP_STATUS_CFG_RDY BIT(18) /* CVP_CONFIG_READY */
#define VSE_CVP_STATUS_CFG_ERR BIT(19) /* CVP_CONFIG_ERROR */
@@ -577,25 +574,18 @@ static int altera_cvp_probe(struct pci_dev *pdev,
{
struct altera_cvp_conf *conf;
struct fpga_manager *mgr;
int ret, offset;
u16 cmd, val;
u16 cmd, offset;
u32 regval;
/* Discover the Vendor Specific Offset for this device */
offset = pci_find_next_ext_capability(pdev, 0, PCI_EXT_CAP_ID_VNDR);
if (!offset) {
dev_err(&pdev->dev, "No Vendor Specific Offset.\n");
return -ENODEV;
}
int ret;
/*
* First check if this is the expected FPGA device. PCI config
* space access works without enabling the PCI device, memory
* space access is enabled further down.
*/
pci_read_config_word(pdev, offset + VSE_PCIE_EXT_CAP_ID, &val);
if (val != VSE_PCIE_EXT_CAP_ID_VAL) {
dev_err(&pdev->dev, "Wrong EXT_CAP_ID value 0x%x\n", val);
offset = pci_find_vsec_capability(pdev, PCI_VENDOR_ID_ALTERA, 0x1172);
if (!offset) {
dev_err(&pdev->dev, "Wrong VSEC ID value\n");
return -ENODEV;
}

View File

@@ -57,6 +57,12 @@ static int xilinx_spi_probe(struct spi_device *spi)
return xilinx_core_probe(core);
}
static const struct spi_device_id xilinx_spi_ids[] = {
{ "fpga-slave-serial" },
{ },
};
MODULE_DEVICE_TABLE(spi, xilinx_spi_ids);
#ifdef CONFIG_OF
static const struct of_device_id xlnx_spi_of_match[] = {
{
@@ -73,6 +79,7 @@ static struct spi_driver xilinx_slave_spi_driver = {
.of_match_table = of_match_ptr(xlnx_spi_of_match),
},
.probe = xilinx_spi_probe,
.id_table = xilinx_spi_ids,
};
module_spi_driver(xilinx_slave_spi_driver)

View File

@@ -22,9 +22,9 @@
#include <linux/uaccess.h>
#include <linux/unaligned.h>
#define OCC_SRAM_BYTES 4096
#define OCC_CMD_DATA_BYTES 4090
#define OCC_RESP_DATA_BYTES 4089
#define OCC_SRAM_BYTES 8192
#define OCC_CMD_DATA_BYTES 8186
#define OCC_RESP_DATA_BYTES 8185
#define OCC_P9_SRAM_CMD_ADDR 0xFFFBE000
#define OCC_P9_SRAM_RSP_ADDR 0xFFFBF000
@@ -86,7 +86,7 @@ static int occ_open(struct inode *inode, struct file *file)
if (!client)
return -ENOMEM;
client->buffer = (u8 *)__get_free_page(GFP_KERNEL);
client->buffer = kvmalloc(OCC_SRAM_BYTES, GFP_KERNEL);
if (!client->buffer) {
kfree(client);
return -ENOMEM;
@@ -97,10 +97,6 @@ static int occ_open(struct inode *inode, struct file *file)
file->private_data = client;
get_device(occ->dev);
/* We allocate a 1-page buffer, make sure it all fits */
BUILD_BUG_ON((OCC_CMD_DATA_BYTES + 3) > PAGE_SIZE);
BUILD_BUG_ON((OCC_RESP_DATA_BYTES + 7) > PAGE_SIZE);
return 0;
}
@@ -176,7 +172,7 @@ static ssize_t occ_write(struct file *file, const char __user *buf,
}
/* Submit command; 4 bytes before the data and 2 bytes after */
rlen = PAGE_SIZE;
rlen = OCC_SRAM_BYTES;
rc = fsi_occ_submit(client->occ->dev, cmd, data_length + 6, cmd,
&rlen);
if (rc)
@@ -200,7 +196,7 @@ static int occ_release(struct inode *inode, struct file *file)
struct occ_client *client = file->private_data;
put_device(client->occ->dev);
free_page((unsigned long)client->buffer);
kvfree(client->buffer);
kfree(client);
return 0;

View File

@@ -644,8 +644,8 @@ static int cc1352_bootloader_wait_for_ack(struct gb_beagleplay *bg)
ret = wait_for_completion_timeout(
&bg->fwl_ack_com, msecs_to_jiffies(CC1352_BOOTLOADER_TIMEOUT));
if (ret < 0)
return dev_err_probe(&bg->sd->dev, ret,
if (!ret)
return dev_err_probe(&bg->sd->dev, -ETIMEDOUT,
"Failed to acquire ack semaphore");
switch (READ_ONCE(bg->fwl_ack)) {
@@ -683,8 +683,8 @@ static int cc1352_bootloader_get_status(struct gb_beagleplay *bg)
ret = wait_for_completion_timeout(
&bg->fwl_cmd_response_com,
msecs_to_jiffies(CC1352_BOOTLOADER_TIMEOUT));
if (ret < 0)
return dev_err_probe(&bg->sd->dev, ret,
if (!ret)
return dev_err_probe(&bg->sd->dev, -ETIMEDOUT,
"Failed to acquire last status semaphore");
switch (READ_ONCE(bg->fwl_cmd_response)) {
@@ -768,8 +768,8 @@ static int cc1352_bootloader_crc32(struct gb_beagleplay *bg, u32 *crc32)
ret = wait_for_completion_timeout(
&bg->fwl_cmd_response_com,
msecs_to_jiffies(CC1352_BOOTLOADER_TIMEOUT));
if (ret < 0)
return dev_err_probe(&bg->sd->dev, ret,
if (!ret)
return dev_err_probe(&bg->sd->dev, -ETIMEDOUT,
"Failed to acquire last status semaphore");
*crc32 = READ_ONCE(bg->fwl_cmd_response);

View File

@@ -1238,7 +1238,7 @@ int __init gb_operation_init(void)
goto err_destroy_message_cache;
gb_operation_completion_wq = alloc_workqueue("greybus_completion",
0, 0);
WQ_PERCPU, 0);
if (!gb_operation_completion_wq)
goto err_destroy_operation_cache;

View File

@@ -397,7 +397,7 @@ static int catu_wait_for_ready(struct catu_drvdata *drvdata)
}
static int catu_enable_hw(struct catu_drvdata *drvdata, enum cs_mode cs_mode,
void *data)
struct coresight_path *path)
{
int rc;
u32 control, mode;
@@ -425,7 +425,7 @@ static int catu_enable_hw(struct catu_drvdata *drvdata, enum cs_mode cs_mode,
etrdev = coresight_find_input_type(
csdev->pdata, CORESIGHT_DEV_TYPE_SINK, etr_subtype);
if (etrdev) {
etr_buf = tmc_etr_get_buffer(etrdev, cs_mode, data);
etr_buf = tmc_etr_get_buffer(etrdev, cs_mode, path);
if (IS_ERR(etr_buf))
return PTR_ERR(etr_buf);
}
@@ -455,7 +455,7 @@ static int catu_enable_hw(struct catu_drvdata *drvdata, enum cs_mode cs_mode,
}
static int catu_enable(struct coresight_device *csdev, enum cs_mode mode,
void *data)
struct coresight_path *path)
{
int rc = 0;
struct catu_drvdata *catu_drvdata = csdev_to_catu_drvdata(csdev);
@@ -463,7 +463,7 @@ static int catu_enable(struct coresight_device *csdev, enum cs_mode mode,
guard(raw_spinlock_irqsave)(&catu_drvdata->spinlock);
if (csdev->refcnt == 0) {
CS_UNLOCK(catu_drvdata->base);
rc = catu_enable_hw(catu_drvdata, mode, data);
rc = catu_enable_hw(catu_drvdata, mode, path);
CS_LOCK(catu_drvdata->base);
}
if (!rc)
@@ -488,7 +488,7 @@ static int catu_disable_hw(struct catu_drvdata *drvdata)
return rc;
}
static int catu_disable(struct coresight_device *csdev, void *__unused)
static int catu_disable(struct coresight_device *csdev, struct coresight_path *path)
{
int rc = 0;
struct catu_drvdata *catu_drvdata = csdev_to_catu_drvdata(csdev);

View File

@@ -300,9 +300,10 @@ unlock:
EXPORT_SYMBOL_GPL(coresight_add_helper);
static int coresight_enable_sink(struct coresight_device *csdev,
enum cs_mode mode, void *data)
enum cs_mode mode,
struct coresight_path *path)
{
return sink_ops(csdev)->enable(csdev, mode, data);
return sink_ops(csdev)->enable(csdev, mode, path);
}
static void coresight_disable_sink(struct coresight_device *csdev)
@@ -355,17 +356,20 @@ static bool coresight_is_helper(struct coresight_device *csdev)
}
static int coresight_enable_helper(struct coresight_device *csdev,
enum cs_mode mode, void *data)
enum cs_mode mode,
struct coresight_path *path)
{
return helper_ops(csdev)->enable(csdev, mode, data);
return helper_ops(csdev)->enable(csdev, mode, path);
}
static void coresight_disable_helper(struct coresight_device *csdev, void *data)
static void coresight_disable_helper(struct coresight_device *csdev,
struct coresight_path *path)
{
helper_ops(csdev)->disable(csdev, data);
helper_ops(csdev)->disable(csdev, path);
}
static void coresight_disable_helpers(struct coresight_device *csdev, void *data)
static void coresight_disable_helpers(struct coresight_device *csdev,
struct coresight_path *path)
{
int i;
struct coresight_device *helper;
@@ -373,7 +377,7 @@ static void coresight_disable_helpers(struct coresight_device *csdev, void *data
for (i = 0; i < csdev->pdata->nr_outconns; ++i) {
helper = csdev->pdata->out_conns[i]->dest_dev;
if (helper && coresight_is_helper(helper))
coresight_disable_helper(helper, data);
coresight_disable_helper(helper, path);
}
}
@@ -479,7 +483,8 @@ void coresight_disable_path(struct coresight_path *path)
EXPORT_SYMBOL_GPL(coresight_disable_path);
static int coresight_enable_helpers(struct coresight_device *csdev,
enum cs_mode mode, void *data)
enum cs_mode mode,
struct coresight_path *path)
{
int i, ret = 0;
struct coresight_device *helper;
@@ -489,7 +494,7 @@ static int coresight_enable_helpers(struct coresight_device *csdev,
if (!helper || !coresight_is_helper(helper))
continue;
ret = coresight_enable_helper(helper, mode, data);
ret = coresight_enable_helper(helper, mode, path);
if (ret)
return ret;
}
@@ -497,8 +502,7 @@ static int coresight_enable_helpers(struct coresight_device *csdev,
return 0;
}
int coresight_enable_path(struct coresight_path *path, enum cs_mode mode,
void *sink_data)
int coresight_enable_path(struct coresight_path *path, enum cs_mode mode)
{
int ret = 0;
u32 type;
@@ -528,7 +532,7 @@ int coresight_enable_path(struct coresight_path *path, enum cs_mode mode,
switch (type) {
case CORESIGHT_DEV_TYPE_SINK:
ret = coresight_enable_sink(csdev, mode, sink_data);
ret = coresight_enable_sink(csdev, mode, path);
/*
* Sink is the first component turned on. If we
* failed to enable the sink, there are no components

View File

@@ -156,17 +156,14 @@ static int ctcu_set_etr_traceid(struct coresight_device *csdev, struct coresight
return __ctcu_set_etr_traceid(csdev, traceid, port_num, enable);
}
static int ctcu_enable(struct coresight_device *csdev, enum cs_mode mode, void *data)
static int ctcu_enable(struct coresight_device *csdev, enum cs_mode mode,
struct coresight_path *path)
{
struct coresight_path *path = (struct coresight_path *)data;
return ctcu_set_etr_traceid(csdev, path, true);
}
static int ctcu_disable(struct coresight_device *csdev, void *data)
static int ctcu_disable(struct coresight_device *csdev, struct coresight_path *path)
{
struct coresight_path *path = (struct coresight_path *)data;
return ctcu_set_etr_traceid(csdev, path, false);
}

View File

@@ -799,14 +799,15 @@ static void cti_pm_release(struct cti_drvdata *drvdata)
}
/** cti ect operations **/
int cti_enable(struct coresight_device *csdev, enum cs_mode mode, void *data)
int cti_enable(struct coresight_device *csdev, enum cs_mode mode,
struct coresight_path *path)
{
struct cti_drvdata *drvdata = csdev_to_cti_drvdata(csdev);
return cti_enable_hw(drvdata);
}
int cti_disable(struct coresight_device *csdev, void *data)
int cti_disable(struct coresight_device *csdev, struct coresight_path *path)
{
struct cti_drvdata *drvdata = csdev_to_cti_drvdata(csdev);

View File

@@ -216,8 +216,9 @@ int cti_add_connection_entry(struct device *dev, struct cti_drvdata *drvdata,
const char *assoc_dev_name);
struct cti_trig_con *cti_allocate_trig_con(struct device *dev, int in_sigs,
int out_sigs);
int cti_enable(struct coresight_device *csdev, enum cs_mode mode, void *data);
int cti_disable(struct coresight_device *csdev, void *data);
int cti_enable(struct coresight_device *csdev, enum cs_mode mode,
struct coresight_path *path);
int cti_disable(struct coresight_device *csdev, struct coresight_path *path);
void cti_write_all_hw_regs(struct cti_drvdata *drvdata);
void cti_write_intack(struct device *dev, u32 ackval);
void cti_write_single_reg(struct cti_drvdata *drvdata, int offset, u32 value);

View File

@@ -52,7 +52,7 @@ static int dummy_source_trace_id(struct coresight_device *csdev, __maybe_unused
}
static int dummy_sink_enable(struct coresight_device *csdev, enum cs_mode mode,
void *data)
struct coresight_path *path)
{
dev_dbg(csdev->dev.parent, "Dummy sink enabled\n");

Some files were not shown because too many files have changed in this diff Show More