1
0
Fork 0

Char/Misc driver patches for 5.12-rc1

Here is the large set of char/misc/whatever driver subsystem updates for
 5.12-rc1.  Over time it seems like this tree is collecting more and more
 tiny driver subsystems in one place, making it easier for those
 maintainers, which is why this is getting larger.
 
 Included in here are:
 	- coresight driver updates
 	- habannalabs driver updates
 	- virtual acrn driver addition (proper acks from the x86
 	  maintainers)
 	- broadcom misc driver addition
 	- speakup driver updates
 	- soundwire driver updates
 	- fpga driver updates
 	- amba driver updates
 	- mei driver updates
 	- vfio driver updates
 	- greybus driver updates
 	- nvmeem driver updates
 	- phy driver updates
 	- mhi driver updates
 	- interconnect driver udpates
 	- fsl-mc bus driver updates
 	- random driver fix
 	- some small misc driver updates (rtsx, pvpanic, etc.)
 
 All of these have been in linux-next for a while, with the only reported
 issue being a merge conflict in include/linux/mod_devicetable.h that you
 will hit in your tree due to the dfl_device_id addition from the fpga
 subsystem in here.  The resolution should be simple.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCYDZf9w8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+yk3xgCcCEN+pCJTum+uAzSNH3YKs/onaDgAnRSVwOUw
 tNW6n1JhXLYl9f5JdhvS
 =MOHs
 -----END PGP SIGNATURE-----

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

Pull char/misc driver updates from Greg KH:
 "Here is the large set of char/misc/whatever driver subsystem updates
  for 5.12-rc1. Over time it seems like this tree is collecting more and
  more tiny driver subsystems in one place, making it easier for those
  maintainers, which is why this is getting larger.

  Included in here are:

   - coresight driver updates

   - habannalabs driver updates

   - virtual acrn driver addition (proper acks from the x86 maintainers)

   - broadcom misc driver addition

   - speakup driver updates

   - soundwire driver updates

   - fpga driver updates

   - amba driver updates

   - mei driver updates

   - vfio driver updates

   - greybus driver updates

   - nvmeem driver updates

   - phy driver updates

   - mhi driver updates

   - interconnect driver udpates

   - fsl-mc bus driver updates

   - random driver fix

   - some small misc driver updates (rtsx, pvpanic, etc.)

  All of these have been in linux-next for a while, with the only
  reported issue being a merge conflict due to the dfl_device_id
  addition from the fpga subsystem in here"

* tag 'char-misc-5.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (311 commits)
  spmi: spmi-pmic-arb: Fix hw_irq overflow
  Documentation: coresight: Add PID tracing description
  coresight: etm-perf: Support PID tracing for kernel at EL2
  coresight: etm-perf: Clarify comment on perf options
  ACRN: update MAINTAINERS: mailing list is subscribers-only
  regmap: sdw-mbq: use MODULE_LICENSE("GPL")
  regmap: sdw: use no_pm routines for SoundWire 1.2 MBQ
  regmap: sdw: use _no_pm functions in regmap_read/write
  soundwire: intel: fix possible crash when no device is detected
  MAINTAINERS: replace my with email with replacements
  mhi: Fix double dma free
  uapi: map_to_7segment: Update example in documentation
  uio: uio_pci_generic: don't fail probe if pdev->irq equals to IRQ_NOTCONNECTED
  drivers/misc/vmw_vmci: restrict too big queue size in qp_host_alloc_queue
  firewire: replace tricky statement by two simple ones
  vme: make remove callback return void
  firmware: google: make coreboot driver's remove callback return void
  firmware: xilinx: Use explicit values for all enum values
  sample/acrn: Introduce a sample of HSM ioctl interface usage
  virt: acrn: Introduce an interface for Service VM to control vCPU
  ...
master
Linus Torvalds 2021-02-24 10:25:37 -08:00
commit e229b429bb
279 changed files with 18903 additions and 5072 deletions

View File

@ -1244,10 +1244,10 @@ S: 80050-430 - Curitiba - Paraná
S: Brazil
N: Oded Gabbay
E: oded.gabbay@gmail.com
D: HabanaLabs and AMD KFD maintainer
S: 12 Shraga Raphaeli
S: Petah-Tikva, 4906418
E: ogabbay@kernel.org
D: HabanaLabs maintainer
S: 29 Duchifat St.
S: Ra'anana 4372029
S: Israel
N: Kumar Gala

View File

@ -0,0 +1,19 @@
What: /sys/bus/fsl-mc/rescan
Date: January 2021
KernelVersion: 5.12
Contact: Ioana Ciornei <ioana.ciornei@nxp.com>
Description: Writing a non-zero value to this attribute will
force a rescan of fsl-mc bus in the system and
synchronize the objects under fsl-mc bus and the
Management Complex firmware.
Users: Userspace drivers and management tools
What: /sys/bus/fsl-mc/autorescan
Date: January 2021
KernelVersion: 5.12
Contact: Ioana Ciornei <ioana.ciornei@nxp.com>
Description: Writing a zero value to this attribute will
disable the DPRC IRQs on which automatic rescan
of the fsl-mc bus is performed. A non-zero value
will enable the DPRC IRQs.
Users: Userspace drivers and management tools

View File

@ -273,7 +273,7 @@ Description: In `/sys/accessibility/speakup` is a directory corresponding to
Below is a description of values and parameters for soft
synthesizer, which is currently the most commonly used.
What: /sys/accessibility/speakup/soft/caps_start
What: /sys/accessibility/speakup/<synth-name>/caps_start
KernelVersion: 2.6
Contact: speakup@linux-speakup.org
Description: This is the string that is sent to the synthesizer to cause it
@ -281,7 +281,7 @@ Description: This is the string that is sent to the synthesizer to cause it
and most others, this causes the pitch of the voice to rise
above the currently set pitch.
What: /sys/accessibility/speakup/soft/caps_stop
What: /sys/accessibility/speakup/<synth-name>/caps_stop
KernelVersion: 2.6
Contact: speakup@linux-speakup.org
Description: This is the string sent to the synthesizer to cause it to stop
@ -290,12 +290,12 @@ Description: This is the string sent to the synthesizer to cause it to stop
down to the
currently set pitch.
What: /sys/accessibility/speakup/soft/delay_time
What: /sys/accessibility/speakup/<synth-name>/delay_time
KernelVersion: 2.6
Contact: speakup@linux-speakup.org
Description: TODO:
What: /sys/accessibility/speakup/soft/direct
What: /sys/accessibility/speakup/<synth-name>/direct
KernelVersion: 2.6
Contact: speakup@linux-speakup.org
Description: Controls if punctuation is spoken by speakup, or by the
@ -306,36 +306,43 @@ Description: Controls if punctuation is spoken by speakup, or by the
than". Zero lets speakup speak the punctuation. One lets the
synthesizer itself speak punctuation.
What: /sys/accessibility/speakup/soft/freq
What: /sys/accessibility/speakup/<synth-name>/freq
KernelVersion: 2.6
Contact: speakup@linux-speakup.org
Description: Gets or sets the frequency of the speech synthesizer. Range is
0-9.
What: /sys/accessibility/speakup/soft/full_time
What: /sys/accessibility/speakup/<synth-name>/flush_time
KernelVersion: 5.12
Contact: speakup@linux-speakup.org
Description: Gets or sets the timeout to wait for the synthesizer flush to
complete. This can be used when the cable gets faulty and flush
notifications are getting lost.
What: /sys/accessibility/speakup/<synth-name>/full_time
KernelVersion: 2.6
Contact: speakup@linux-speakup.org
Description: TODO:
What: /sys/accessibility/speakup/soft/jiffy_delta
What: /sys/accessibility/speakup/<synth-name>/jiffy_delta
KernelVersion: 2.6
Contact: speakup@linux-speakup.org
Description: This controls how many jiffys the kernel gives to the
synthesizer. Setting this too high can make a system unstable,
or even crash it.
What: /sys/accessibility/speakup/soft/pitch
What: /sys/accessibility/speakup/<synth-name>/pitch
KernelVersion: 2.6
Contact: speakup@linux-speakup.org
Description: Gets or sets the pitch of the synthesizer. The range is 0-9.
What: /sys/accessibility/speakup/soft/inflection
What: /sys/accessibility/speakup/<synth-name>/inflection
KernelVersion: 5.8
Contact: speakup@linux-speakup.org
Description: Gets or sets the inflection of the synthesizer, i.e. the pitch
range. The range is 0-9.
What: /sys/accessibility/speakup/soft/punct
What: /sys/accessibility/speakup/<synth-name>/punct
KernelVersion: 2.6
Contact: speakup@linux-speakup.org
Description: Gets or sets the amount of punctuation spoken by the
@ -343,13 +350,13 @@ Description: Gets or sets the amount of punctuation spoken by the
TODO: How is this related to speakup's punc_level, or
reading_punc.
What: /sys/accessibility/speakup/soft/rate
What: /sys/accessibility/speakup/<synth-name>/rate
KernelVersion: 2.6
Contact: speakup@linux-speakup.org
Description: Gets or sets the rate of the synthesizer. Range is from zero
slowest, to nine fastest.
What: /sys/accessibility/speakup/soft/tone
What: /sys/accessibility/speakup/<synth-name>/tone
KernelVersion: 2.6
Contact: speakup@linux-speakup.org
Description: Gets or sets the tone of the speech synthesizer. The range for
@ -357,12 +364,12 @@ Description: Gets or sets the tone of the speech synthesizer. The range for
difference if using espeak and the espeakup connector.
TODO: does espeakup support different tonalities?
What: /sys/accessibility/speakup/soft/trigger_time
What: /sys/accessibility/speakup/<synth-name>/trigger_time
KernelVersion: 2.6
Contact: speakup@linux-speakup.org
Description: TODO:
What: /sys/accessibility/speakup/soft/voice
What: /sys/accessibility/speakup/<synth-name>/voice
KernelVersion: 2.6
Contact: speakup@linux-speakup.org
Description: Gets or sets the voice used by the synthesizer if the
@ -371,7 +378,7 @@ Description: Gets or sets the voice used by the synthesizer if the
voices, this parameter will not set the voice when the espeakup
connector is used between speakup and espeak.
What: /sys/accessibility/speakup/soft/vol
What: /sys/accessibility/speakup/<synth-name>/vol
KernelVersion: 2.6
Contact: speakup@linux-speakup.org
Description: Gets or sets the volume of the speech synthesizer. Range is 0-9,

View File

@ -1,7 +1,7 @@
What: /sys/kernel/debug/habanalabs/hl<n>/addr
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Sets the device address to be used for read or write through
PCI bar, or the device VA of a host mapped memory to be read or
written directly from the host. The latter option is allowed
@ -11,7 +11,7 @@ Description: Sets the device address to be used for read or write through
What: /sys/kernel/debug/habanalabs/hl<n>/clk_gate
Date: May 2020
KernelVersion: 5.8
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Allow the root user to disable/enable in runtime the clock
gating mechanism in Gaudi. Due to how Gaudi is built, the
clock gating needs to be disabled in order to access the
@ -34,28 +34,28 @@ Description: Allow the root user to disable/enable in runtime the clock
What: /sys/kernel/debug/habanalabs/hl<n>/command_buffers
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Displays a list with information about the currently allocated
command buffers
What: /sys/kernel/debug/habanalabs/hl<n>/command_submission
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Displays a list with information about the currently active
command submissions
What: /sys/kernel/debug/habanalabs/hl<n>/command_submission_jobs
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Displays a list with detailed information about each JOB (CB) of
each active command submission
What: /sys/kernel/debug/habanalabs/hl<n>/data32
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Allows the root user to read or write directly through the
device's PCI bar. Writing to this file generates a write
transaction while reading from the file generates a read
@ -70,7 +70,7 @@ Description: Allows the root user to read or write directly through the
What: /sys/kernel/debug/habanalabs/hl<n>/data64
Date: Jan 2020
KernelVersion: 5.6
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Allows the root user to read or write 64 bit data directly
through the device's PCI bar. Writing to this file generates a
write transaction while reading from the file generates a read
@ -85,7 +85,7 @@ Description: Allows the root user to read or write 64 bit data directly
What: /sys/kernel/debug/habanalabs/hl<n>/device
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Enables the root user to set the device to specific state.
Valid values are "disable", "enable", "suspend", "resume".
User can read this property to see the valid values
@ -93,28 +93,28 @@ Description: Enables the root user to set the device to specific state.
What: /sys/kernel/debug/habanalabs/hl<n>/engines
Date: Jul 2019
KernelVersion: 5.3
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Displays the status registers values of the device engines and
their derived idle status
What: /sys/kernel/debug/habanalabs/hl<n>/i2c_addr
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Sets I2C device address for I2C transaction that is generated
by the device's CPU
What: /sys/kernel/debug/habanalabs/hl<n>/i2c_bus
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Sets I2C bus address for I2C transaction that is generated by
the device's CPU
What: /sys/kernel/debug/habanalabs/hl<n>/i2c_data
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Triggers an I2C transaction that is generated by the device's
CPU. Writing to this file generates a write transaction while
reading from the file generates a read transcation
@ -122,32 +122,32 @@ Description: Triggers an I2C transaction that is generated by the device's
What: /sys/kernel/debug/habanalabs/hl<n>/i2c_reg
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Sets I2C register id for I2C transaction that is generated by
the device's CPU
What: /sys/kernel/debug/habanalabs/hl<n>/led0
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Sets the state of the first S/W led on the device
What: /sys/kernel/debug/habanalabs/hl<n>/led1
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Sets the state of the second S/W led on the device
What: /sys/kernel/debug/habanalabs/hl<n>/led2
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Sets the state of the third S/W led on the device
What: /sys/kernel/debug/habanalabs/hl<n>/mmu
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Displays the hop values and physical address for a given ASID
and virtual address. The user should write the ASID and VA into
the file and then read the file to get the result.
@ -157,14 +157,14 @@ Description: Displays the hop values and physical address for a given ASID
What: /sys/kernel/debug/habanalabs/hl<n>/set_power_state
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Sets the PCI power state. Valid values are "1" for D0 and "2"
for D3Hot
What: /sys/kernel/debug/habanalabs/hl<n>/userptr
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Displays a list with information about the currently user
pointers (user virtual addresses) that are pinned and mapped
to DMA addresses
@ -172,13 +172,21 @@ Description: Displays a list with information about the currently user
What: /sys/kernel/debug/habanalabs/hl<n>/vm
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Displays a list with information about all the active virtual
address mappings per ASID
What: /sys/kernel/debug/habanalabs/hl<n>/stop_on_err
Date: Mar 2020
KernelVersion: 5.6
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Sets the stop-on_error option for the device engines. Value of
"0" is for disable, otherwise enable.
What: /sys/kernel/debug/habanalabs/hl<n>/dump_security_violations
Date: Jan 2021
KernelVersion: 5.12
Contact: ogabbay@kernel.org
Description: Dumps all security violations to dmesg. This will also ack
all security violations meanings those violations will not be
dumped next time user calls this API

View File

@ -371,6 +371,14 @@ Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (Read) Print the content of the Device ID Register
(0xFC8). The value is taken directly from the HW.
What: /sys/bus/coresight/devices/etm<N>/mgmt/trcdevarch
Date: January 2021
KernelVersion: 5.12
Contact: Mathieu Poirier <mathieu.poirier@linaro.org>
Description: (Read) Print the content of the Device Architecture Register
(offset 0xFBC). The value is taken directly read
from the HW.
What: /sys/bus/coresight/devices/etm<N>/mgmt/trcdevtype
Date: April 2015
KernelVersion: 4.01

View File

@ -0,0 +1,25 @@
What: /sys/bus/dfl/devices/dfl_dev.X/infX_cal_fail
Date: Oct 2020
KernelVersion: 5.12
Contact: Xu Yilun <yilun.xu@intel.com>
Description: Read-only. It indicates if the calibration failed on this
memory interface. "1" for calibration failure, "0" for OK.
Format: %u
What: /sys/bus/dfl/devices/dfl_dev.X/infX_init_done
Date: Oct 2020
KernelVersion: 5.12
Contact: Xu Yilun <yilun.xu@intel.com>
Description: Read-only. It indicates if the initialization completed on
this memory interface. "1" for initialization complete, "0"
for not yet.
Format: %u
What: /sys/bus/dfl/devices/dfl_dev.X/infX_clear
Date: Oct 2020
KernelVersion: 5.12
Contact: Xu Yilun <yilun.xu@intel.com>
Description: Write-only. Writing "1" to this file will zero out all memory
data in this memory interface. Writing of other values is
invalid.
Format: %u

View File

@ -0,0 +1,47 @@
What: /sys/bus/dfl/devices/dfl_dev.X/fec_mode
Date: Oct 2020
KernelVersion: 5.12
Contact: Xu Yilun <yilun.xu@intel.com>
Description: Read-only. Returns the FEC mode of the 25G links of the
ethernet retimers configured by Nios firmware. "rs" for Reed
Solomon FEC, "kr" for Fire Code FEC, "no" for NO FEC.
"not supported" if the FEC mode setting is not supported, this
happens when the Nios firmware version major < 3, or no link is
configured to 25G.
Format: string
What: /sys/bus/dfl/devices/dfl_dev.X/retimer_A_mode
Date: Oct 2020
KernelVersion: 5.12
Contact: Xu Yilun <yilun.xu@intel.com>
Description: Read-only. Returns the enumeration value of the working mode of
the retimer A configured by the Nios firmware. The value is
read out from shared registers filled by the Nios firmware. Now
the values could be:
- "0": Reset
- "1": 4x10G
- "2": 4x25G
- "3": 2x25G
- "4": 2x25G+2x10G
- "5": 1x25G
If the Nios firmware is updated in future to support more
retimer modes, more enumeration value is expected.
Format: 0x%x
What: /sys/bus/dfl/devices/dfl_dev.X/retimer_B_mode
Date: Oct 2020
KernelVersion: 5.12
Contact: Xu Yilun <yilun.xu@intel.com>
Description: Read-only. Returns the enumeration value of the working mode of
the retimer B configured by the Nios firmware. The value format
is the same as retimer_A_mode.
What: /sys/bus/dfl/devices/dfl_dev.X/nios_fw_version
Date: Oct 2020
KernelVersion: 5.12
Contact: Xu Yilun <yilun.xu@intel.com>
Description: Read-only. Returns the version of the Nios firmware in the
FPGA. Its format is "major.minor.patch".
Format: %x.%x.%x

View File

@ -0,0 +1,24 @@
What: /sys/devices/pci0000:00/*/QEMU0001:00/capability
Date: Jan 2021
Contact: zhenwei pi <pizhenwei@bytedance.com>
Description:
Read-only attribute. Capabilities of pvpanic device which
are supported by QEMU.
Format: %x.
Detailed bit definition refers to section <Bit Definition>
from pvpanic device specification:
https://git.qemu.org/?p=qemu.git;a=blob_plain;f=docs/specs/pvpanic.txt
What: /sys/devices/pci0000:00/*/QEMU0001:00/events
Date: Jan 2021
Contact: zhenwei pi <pizhenwei@bytedance.com>
Description:
RW attribute. Set/get which features in-use. This attribute
is used to enable/disable feature(s) of pvpanic device.
Notice that this value should be a subset of capability.
Format: %x.
Also refer to pvpanic device specification.

View File

@ -1,7 +1,7 @@
What: /sys/class/habanalabs/hl<n>/armcp_kernel_ver
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Version of the Linux kernel running on the device's CPU.
Will be DEPRECATED in Linux kernel version 5.10, and be
replaced with cpucp_kernel_ver
@ -9,7 +9,7 @@ Description: Version of the Linux kernel running on the device's CPU.
What: /sys/class/habanalabs/hl<n>/armcp_ver
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Version of the application running on the device's CPU
Will be DEPRECATED in Linux kernel version 5.10, and be
replaced with cpucp_ver
@ -17,7 +17,7 @@ Description: Version of the application running on the device's CPU
What: /sys/class/habanalabs/hl<n>/clk_max_freq_mhz
Date: Jun 2019
KernelVersion: not yet upstreamed
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Allows the user to set the maximum clock frequency, in MHz.
The device clock might be set to lower value than the maximum.
The user should read the clk_cur_freq_mhz to see the actual
@ -27,52 +27,52 @@ Description: Allows the user to set the maximum clock frequency, in MHz.
What: /sys/class/habanalabs/hl<n>/clk_cur_freq_mhz
Date: Jun 2019
KernelVersion: not yet upstreamed
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Displays the current frequency, in MHz, of the device clock.
This property is valid only for the Gaudi ASIC family
What: /sys/class/habanalabs/hl<n>/cpld_ver
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Version of the Device's CPLD F/W
What: /sys/class/habanalabs/hl<n>/cpucp_kernel_ver
Date: Oct 2020
KernelVersion: 5.10
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Version of the Linux kernel running on the device's CPU
What: /sys/class/habanalabs/hl<n>/cpucp_ver
Date: Oct 2020
KernelVersion: 5.10
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Version of the application running on the device's CPU
What: /sys/class/habanalabs/hl<n>/device_type
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Displays the code name of the device according to its type.
The supported values are: "GOYA"
What: /sys/class/habanalabs/hl<n>/eeprom
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: A binary file attribute that contains the contents of the
on-board EEPROM
What: /sys/class/habanalabs/hl<n>/fuse_ver
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Displays the device's version from the eFuse
What: /sys/class/habanalabs/hl<n>/hard_reset
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Interface to trigger a hard-reset operation for the device.
Hard-reset will reset ALL internal components of the device
except for the PCI interface and the internal PLLs
@ -80,14 +80,14 @@ Description: Interface to trigger a hard-reset operation for the device.
What: /sys/class/habanalabs/hl<n>/hard_reset_cnt
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Displays how many times the device have undergone a hard-reset
operation since the driver was loaded
What: /sys/class/habanalabs/hl<n>/high_pll
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Allows the user to set the maximum clock frequency for MME, TPC
and IC when the power management profile is set to "automatic".
This property is valid only for the Goya ASIC family
@ -95,7 +95,7 @@ Description: Allows the user to set the maximum clock frequency for MME, TPC
What: /sys/class/habanalabs/hl<n>/ic_clk
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Allows the user to set the maximum clock frequency, in Hz, of
the Interconnect fabric. Writes to this parameter affect the
device only when the power management profile is set to "manual"
@ -107,27 +107,27 @@ Description: Allows the user to set the maximum clock frequency, in Hz, of
What: /sys/class/habanalabs/hl<n>/ic_clk_curr
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Displays the current clock frequency, in Hz, of the Interconnect
fabric. This property is valid only for the Goya ASIC family
What: /sys/class/habanalabs/hl<n>/infineon_ver
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Version of the Device's power supply F/W code
What: /sys/class/habanalabs/hl<n>/max_power
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Allows the user to set the maximum power consumption of the
device in milliwatts.
What: /sys/class/habanalabs/hl<n>/mme_clk
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Allows the user to set the maximum clock frequency, in Hz, of
the MME compute engine. Writes to this parameter affect the
device only when the power management profile is set to "manual"
@ -139,21 +139,21 @@ Description: Allows the user to set the maximum clock frequency, in Hz, of
What: /sys/class/habanalabs/hl<n>/mme_clk_curr
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Displays the current clock frequency, in Hz, of the MME compute
engine. This property is valid only for the Goya ASIC family
What: /sys/class/habanalabs/hl<n>/pci_addr
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Displays the PCI address of the device. This is needed so the
user would be able to open a device based on its PCI address
What: /sys/class/habanalabs/hl<n>/pm_mng_profile
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Power management profile. Values are "auto", "manual". In "auto"
mode, the driver will set the maximum clock frequency to a high
value when a user-space process opens the device's file (unless
@ -167,13 +167,13 @@ Description: Power management profile. Values are "auto", "manual". In "auto"
What: /sys/class/habanalabs/hl<n>/preboot_btl_ver
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Version of the device's preboot F/W code
What: /sys/class/habanalabs/hl<n>/soft_reset
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Interface to trigger a soft-reset operation for the device.
Soft-reset will reset only the compute and DMA engines of the
device
@ -181,26 +181,26 @@ Description: Interface to trigger a soft-reset operation for the device.
What: /sys/class/habanalabs/hl<n>/soft_reset_cnt
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Displays how many times the device have undergone a soft-reset
operation since the driver was loaded
What: /sys/class/habanalabs/hl<n>/status
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Status of the card: "Operational", "Malfunction", "In reset".
What: /sys/class/habanalabs/hl<n>/thermal_ver
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Version of the Device's thermal daemon
What: /sys/class/habanalabs/hl<n>/tpc_clk
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Allows the user to set the maximum clock frequency, in Hz, of
the TPC compute engines. Writes to this parameter affect the
device only when the power management profile is set to "manual"
@ -212,12 +212,12 @@ Description: Allows the user to set the maximum clock frequency, in Hz, of
What: /sys/class/habanalabs/hl<n>/tpc_clk_curr
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Displays the current clock frequency, in Hz, of the TPC compute
engines. This property is valid only for the Goya ASIC family
What: /sys/class/habanalabs/hl<n>/uboot_ver
Date: Jan 2019
KernelVersion: 5.1
Contact: oded.gabbay@gmail.com
Contact: ogabbay@kernel.org
Description: Version of the u-boot running on the device's CPU

View File

@ -1033,7 +1033,9 @@ speakup + keypad 3, you would hear:
The speakup key is depressed, so the name of the key state is speakup.
This part of the message comes from the states collection.
14.2. Loading Your Own Messages
14.2. Changing language
14.2.1. Loading Your Own Messages
The files under the i18n subdirectory all follow the same format.
They consist of lines, with one message per line.
@ -1066,8 +1068,50 @@ echo '1 azul' > /speakup/i18n/colors
The next time that Speakup says message 1 from the colors group, it will
say "azul", rather than "blue."
14.2.2. Choose a language
In the future, translations into various languages will be made available,
and most users will just load the files necessary for their language.
and most users will just load the files necessary for their language. So far,
only French language is available beyond native Canadian English language.
French is only available after you are logged in.
Canadian English is the default language. To toggle another language,
download the source of Speakup and untar it in your home directory. The
following command should let you do this:
tar xvjf speakup-<version>.tar.bz2
where <version> is the version number of the application.
Next, change to the newly created directory, then into the tools/ directory, and
run the script speakup_setlocale. You are asked the language that you want to
use. Type the number associated to your language (e.g. fr for French) then press
Enter. Needed files are copied in the i18n directory.
Note: the speakupconf must be installed on your system so that settings are saved.
Otherwise, you will have an error: your language will be loaded but you will
have to run the script again every time Speakup restarts.
See section 16.1. for information about speakupconf.
You will have to repeat these steps for any change of locale, i.e. if you wish
change the speakup's language or charset (iso-8859-15 ou UTF-8).
If you wish store the settings, note that at your next login, you will need to
do:
speakup load
Alternatively, you can add the above line to your file
~/.bashrc or ~/.bash_profile.
If your system administrator ran himself the script, all the users will be able
to change from English to the language choosed by root and do directly
speakupconf load (or add this to the ~/.bashrc or
~/.bash_profile file). If there are several languages to handle, the
administrator (or every user) will have to run the first steps until speakupconf
save, choosing the appropriate language, in every user's home directory. Every
user will then be able to do speakupconf load, Speakup will load his own settings.
14.3. No Support for Non-Western-European Languages

View File

@ -34,9 +34,12 @@ its hardware characteristcs.
Program Flow Trace Macrocell:
"arm,coresight-etm3x", "arm,primecell";
- Embedded Trace Macrocell (version 4.x):
- Embedded Trace Macrocell (version 4.x), with memory mapped access.
"arm,coresight-etm4x", "arm,primecell";
- Embedded Trace Macrocell (version 4.x), with system register access only.
"arm,coresight-etm4x-sysreg";
- Coresight programmable Replicator :
"arm,coresight-dynamic-replicator", "arm,primecell";

View File

@ -22,23 +22,7 @@ Required properties:
MIPI TX Configuration Module
============================
The MIPI TX configuration module controls the MIPI D-PHY.
Required properties:
- compatible: "mediatek,<chip>-mipi-tx"
- the supported chips are mt2701, 7623, mt8173 and mt8183.
- reg: Physical base address and length of the controller's registers
- clocks: PLL reference clock
- clock-output-names: name of the output clock line to the DSI encoder
- #clock-cells: must be <0>;
- #phy-cells: must be <0>.
Optional properties:
- drive-strength-microamp: adjust driving current, should be 3000 ~ 6000. And
the step is 200.
- nvmem-cells: A phandle to the calibration data provided by a nvmem device. If
unspecified default values shall be used.
- nvmem-cell-names: Should be "calibration-data"
See phy/mediatek,dsi-phy.yaml
Example:

View File

@ -53,23 +53,7 @@ Required properties:
HDMI PHY
========
The HDMI PHY serializes the HDMI encoder's three channel 10-bit parallel
output and drives the HDMI pads.
Required properties:
- compatible: "mediatek,<chip>-hdmi-phy"
- the supported chips are mt2701, mt7623 and mt8173
- reg: Physical base address and length of the module's registers
- clocks: PLL reference clock
- clock-names: must contain "pll_ref"
- clock-output-names: must be "hdmitx_dig_cts" on mt8173
- #phy-cells: must be <0>
- #clock-cells: must be <0>
Optional properties:
- mediatek,ibias: TX DRV bias current for <1.65Gbps, defaults to 0xa
- mediatek,ibias_up: TX DRV bias current for >1.65Gbps, defaults to 0x1c
See phy/mediatek,hdmi-phy.yaml
Example:

View File

@ -1,77 +0,0 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/interconnect/qcom,qcs404.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm QCS404 Network-On-Chip interconnect
maintainers:
- Georgi Djakov <georgi.djakov@linaro.org>
description: |
The Qualcomm QCS404 interconnect providers support adjusting the
bandwidth requirements between the various NoC fabrics.
properties:
reg:
maxItems: 1
compatible:
enum:
- qcom,qcs404-bimc
- qcom,qcs404-pcnoc
- qcom,qcs404-snoc
'#interconnect-cells':
const: 1
clock-names:
items:
- const: bus
- const: bus_a
clocks:
items:
- description: Bus Clock
- description: Bus A Clock
required:
- compatible
- reg
- '#interconnect-cells'
- clock-names
- clocks
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/qcom,rpmcc.h>
bimc: interconnect@400000 {
reg = <0x00400000 0x80000>;
compatible = "qcom,qcs404-bimc";
#interconnect-cells = <1>;
clock-names = "bus", "bus_a";
clocks = <&rpmcc RPM_SMD_BIMC_CLK>,
<&rpmcc RPM_SMD_BIMC_A_CLK>;
};
pnoc: interconnect@500000 {
reg = <0x00500000 0x15080>;
compatible = "qcom,qcs404-pcnoc";
#interconnect-cells = <1>;
clock-names = "bus", "bus_a";
clocks = <&rpmcc RPM_SMD_PNOC_CLK>,
<&rpmcc RPM_SMD_PNOC_A_CLK>;
};
snoc: interconnect@580000 {
reg = <0x00580000 0x23080>;
compatible = "qcom,qcs404-snoc";
#interconnect-cells = <1>;
clock-names = "bus", "bus_a";
clocks = <&rpmcc RPM_SMD_SNOC_CLK>,
<&rpmcc RPM_SMD_SNOC_A_CLK>;
};

View File

@ -1,27 +1,35 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/interconnect/qcom,msm8916.yaml#
$id: http://devicetree.org/schemas/interconnect/qcom,rpm.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm MSM8916 Network-On-Chip interconnect
title: Qualcomm RPM Network-On-Chip Interconnect
maintainers:
- Georgi Djakov <georgi.djakov@linaro.org>
description: |
The Qualcomm MSM8916 interconnect providers support adjusting the
bandwidth requirements between the various NoC fabrics.
RPM interconnect providers support system bandwidth requirements through
RPM processor. The provider is able to communicate with the RPM through
the RPM shared memory device.
properties:
reg:
maxItems: 1
compatible:
enum:
- qcom,msm8916-bimc
- qcom,msm8916-pcnoc
- qcom,msm8916-snoc
reg:
maxItems: 1
- qcom,msm8939-bimc
- qcom,msm8939-pcnoc
- qcom,msm8939-snoc
- qcom,msm8939-snoc-mm
- qcom,qcs404-bimc
- qcom,qcs404-pcnoc
- qcom,qcs404-snoc
'#interconnect-cells':
const: 1

View File

@ -45,6 +45,10 @@ properties:
- qcom,sdm845-mem-noc
- qcom,sdm845-mmss-noc
- qcom,sdm845-system-noc
- qcom,sdx55-ipa-virt
- qcom,sdx55-mc-virt
- qcom,sdx55-mem-noc
- qcom,sdx55-system-noc
- qcom,sm8150-aggre1-noc
- qcom,sm8150-aggre2-noc
- qcom,sm8150-camnoc-noc

View File

@ -4,6 +4,7 @@ Required properties:
- compatible : shall be one of:
"atmel,at93c46d"
"eeprom-93xx46"
"microchip,93lc46b"
- data-size : number of data bits per word (either 8 or 16)
Optional properties:

View File

@ -0,0 +1,49 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/nvmem/rmem.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Reserved Memory Based nvmem Device
maintainers:
- Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
allOf:
- $ref: "nvmem.yaml#"
properties:
compatible:
items:
- enum:
- raspberrypi,bootloader-config
- const: nvmem-rmem
no-map:
$ref: /schemas/types.yaml#/definitions/flag
description:
Avoid creating a virtual mapping of the region as part of the OS'
standard mapping of system memory.
required:
- compatible
- no-map
unevaluatedProperties: false
examples:
- |
reserved-memory {
#address-cells = <1>;
#size-cells = <1>;
blconfig: nvram@10000000 {
compatible = "raspberrypi,bootloader-config", "nvmem-rmem";
#address-cells = <1>;
#size-cells = <1>;
reg = <0x10000000 0x1000>;
no-map;
};
};
...

View File

@ -1,86 +0,0 @@
Broadcom STB USB PHY
Required properties:
- compatible: should be one of
"brcm,brcmstb-usb-phy"
"brcm,bcm7216-usb-phy"
"brcm,bcm7211-usb-phy"
- reg and reg-names properties requirements are specific to the
compatible string.
"brcm,brcmstb-usb-phy":
- reg: 1 or 2 offset and length pairs. One for the base CTRL registers
and an optional pair for systems with USB 3.x support
- reg-names: not specified
"brcm,bcm7216-usb-phy":
- reg: 3 offset and length pairs for CTRL, XHCI_EC and XHCI_GBL
registers
- reg-names: "ctrl", "xhci_ec", "xhci_gbl"
"brcm,bcm7211-usb-phy":
- reg: 5 offset and length pairs for CTRL, XHCI_EC, XHCI_GBL,
USB_PHY and USB_MDIO registers and an optional pair
for the BDC registers
- reg-names: "ctrl", "xhci_ec", "xhci_gbl", "usb_phy", "usb_mdio", "bdc_ec"
- #phy-cells: Shall be 1 as it expects one argument for setting
the type of the PHY. Possible values are:
- PHY_TYPE_USB2 for USB1.1/2.0 PHY
- PHY_TYPE_USB3 for USB3.x PHY
Optional Properties:
- clocks : clock phandles.
- clock-names: String, clock name.
- interrupts: wakeup interrupt
- interrupt-names: "wakeup"
- brcm,ipp: Boolean, Invert Port Power.
Possible values are: 0 (Don't invert), 1 (Invert)
- brcm,ioc: Boolean, Invert Over Current detection.
Possible values are: 0 (Don't invert), 1 (Invert)
- dr_mode: String, PHY Device mode.
Possible values are: "host", "peripheral ", "drd" or "typec-pd"
If this property is not defined, the phy will default to "host" mode.
- brcm,syscon-piarbctl: phandle to syscon for handling config registers
NOTE: one or both of the following two properties must be set
- brcm,has-xhci: Boolean indicating the phy has an XHCI phy.
- brcm,has-eohci: Boolean indicating the phy has an EHCI/OHCI phy.
Example:
usbphy_0: usb-phy@f0470200 {
reg = <0xf0470200 0xb8>,
<0xf0471940 0x6c0>;
compatible = "brcm,brcmstb-usb-phy";
#phy-cells = <1>;
dr_mode = "host"
brcm,ioc = <1>;
brcm,ipp = <1>;
brcm,has-xhci;
brcm,has-eohci;
clocks = <&usb20>, <&usb30>;
clock-names = "sw_usb", "sw_usb3";
};
usb-phy@29f0200 {
reg = <0x29f0200 0x200>,
<0x29c0880 0x30>,
<0x29cc100 0x534>,
<0x2808000 0x24>,
<0x2980080 0x8>;
reg-names = "ctrl",
"xhci_ec",
"xhci_gbl",
"usb_phy",
"usb_mdio";
brcm,ioc = <0x0>;
brcm,ipp = <0x0>;
compatible = "brcm,bcm7211-usb-phy";
interrupts = <0x30>;
interrupt-parent = <&vpu_intr1_nosec_intc>;
interrupt-names = "wake";
#phy-cells = <0x1>;
brcm,has-xhci;
syscon-piarbctl = <&syscon_piarbctl>;
clocks = <&scmi_clk 256>;
clock-names = "sw_usb";
};

View File

@ -0,0 +1,196 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/phy/brcm,brcmstb-usb-phy.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Broadcom STB USB PHY
description: Broadcom's PHY that handles EHCI/OHCI and/or XHCI
maintainers:
- Al Cooper <alcooperx@gmail.com>
- Rafał Miłecki <rafal@milecki.pl>
properties:
compatible:
enum:
- brcm,bcm4908-usb-phy
- brcm,bcm7211-usb-phy
- brcm,bcm7216-usb-phy
- brcm,brcmstb-usb-phy
reg:
minItems: 1
maxItems: 6
items:
- description: the base CTRL register
- description: XHCI EC register
- description: XHCI GBL register
- description: USB PHY register
- description: USB MDIO register
- description: BDC register
reg-names:
minItems: 1
maxItems: 6
items:
- const: ctrl
- const: xhci_ec
- const: xhci_gbl
- const: usb_phy
- const: usb_mdio
- const: bdc_ec
clocks:
minItems: 1
maxItems: 2
clock-names:
minItems: 1
maxItems: 2
items:
- const: sw_usb
- const: sw_usb3
interrupts:
description: wakeup interrupt
interrupt-names:
const: wake
brcm,ipp:
$ref: /schemas/types.yaml#/definitions/uint32
description: Invert Port Power
minimum: 0
maximum: 1
brcm,ioc:
$ref: /schemas/types.yaml#/definitions/uint32
description: Invert Over Current detection
minimum: 0
maximum: 1
dr_mode:
description: PHY Device mode. If this property is not defined, the PHY will
default to "host" mode.
enum:
- host
- peripheral
- drd
- typec-pd
brcm,syscon-piarbctl:
description: phandle to syscon for handling config registers
$ref: /schemas/types.yaml#/definitions/phandle
brcm,has-xhci:
description: Indicates the PHY has an XHCI PHY.
type: boolean
brcm,has-eohci:
description: Indicates the PHY has an EHCI/OHCI PHY.
type: boolean
"#phy-cells":
description: |
Cell allows setting the type of the PHY. Possible values are:
- PHY_TYPE_USB2 for USB1.1/2.0 PHY
- PHY_TYPE_USB3 for USB3.x PHY
const: 1
required:
- reg
- "#phy-cells"
anyOf:
- required:
- brcm,has-xhci
- required:
- brcm,has-eohci
allOf:
- if:
properties:
compatible:
contains:
enum:
- const: brcm,bcm4908-usb-phy
- const: brcm,brcmstb-usb-phy
then:
properties:
reg:
minItems: 1
maxItems: 2
- if:
properties:
compatible:
contains:
const: brcm,bcm7211-usb-phy
then:
properties:
reg:
minItems: 5
maxItems: 6
reg-names:
minItems: 5
maxItems: 6
- if:
properties:
compatible:
contains:
const: brcm,bcm7216-usb-phy
then:
properties:
reg:
minItems: 3
maxItems: 3
reg-names:
minItems: 3
maxItems: 3
additionalProperties: false
examples:
- |
#include <dt-bindings/phy/phy.h>
usb-phy@f0470200 {
compatible = "brcm,brcmstb-usb-phy";
reg = <0xf0470200 0xb8>,
<0xf0471940 0x6c0>;
#phy-cells = <1>;
dr_mode = "host";
brcm,ioc = <1>;
brcm,ipp = <1>;
brcm,has-xhci;
brcm,has-eohci;
clocks = <&usb20>, <&usb30>;
clock-names = "sw_usb", "sw_usb3";
};
- |
#include <dt-bindings/phy/phy.h>
usb-phy@29f0200 {
compatible = "brcm,bcm7211-usb-phy";
reg = <0x29f0200 0x200>,
<0x29c0880 0x30>,
<0x29cc100 0x534>,
<0x2808000 0x24>,
<0x2980080 0x8>;
reg-names = "ctrl",
"xhci_ec",
"xhci_gbl",
"usb_phy",
"usb_mdio";
brcm,ioc = <0x0>;
brcm,ipp = <0x0>;
interrupts = <0x30>;
interrupt-parent = <&vpu_intr1_nosec_intc>;
interrupt-names = "wake";
#phy-cells = <0x1>;
brcm,has-xhci;
brcm,syscon-piarbctl = <&syscon_piarbctl>;
clocks = <&scmi_clk 256>;
clock-names = "sw_usb";
};

View File

@ -0,0 +1,85 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright (c) 2020 MediaTek
%YAML 1.2
---
$id: http://devicetree.org/schemas/phy/mediatek,dsi-phy.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek MIPI Display Serial Interface (DSI) PHY binding
maintainers:
- Chun-Kuang Hu <chunkuang.hu@kernel.org>
- Philipp Zabel <p.zabel@pengutronix.de>
- Chunfeng Yun <chunfeng.yun@mediatek.com>
description: The MIPI DSI PHY supports up to 4-lane output.
properties:
$nodename:
pattern: "^dsi-phy@[0-9a-f]+$"
compatible:
enum:
- mediatek,mt2701-mipi-tx
- mediatek,mt7623-mipi-tx
- mediatek,mt8173-mipi-tx
- mediatek,mt8183-mipi-tx
reg:
maxItems: 1
clocks:
items:
- description: PLL reference clock
clock-output-names:
maxItems: 1
"#phy-cells":
const: 0
"#clock-cells":
const: 0
nvmem-cells:
maxItems: 1
description: A phandle to the calibration data provided by a nvmem device,
if unspecified, default values shall be used.
nvmem-cell-names:
items:
- const: calibration-data
drive-strength-microamp:
description: adjust driving current
multipleOf: 200
minimum: 2000
maximum: 6000
default: 4600
required:
- compatible
- reg
- clocks
- clock-output-names
- "#phy-cells"
- "#clock-cells"
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/mt8173-clk.h>
dsi-phy@10215000 {
compatible = "mediatek,mt8173-mipi-tx";
reg = <0x10215000 0x1000>;
clocks = <&clk26m>;
clock-output-names = "mipi_tx0_pll";
drive-strength-microamp = <4000>;
nvmem-cells= <&mipi_tx_calibration>;
nvmem-cell-names = "calibration-data";
#clock-cells = <0>;
#phy-cells = <0>;
};
...

View File

@ -0,0 +1,92 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright (c) 2020 MediaTek
%YAML 1.2
---
$id: http://devicetree.org/schemas/phy/mediatek,hdmi-phy.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek High Definition Multimedia Interface (HDMI) PHY binding
maintainers:
- Chun-Kuang Hu <chunkuang.hu@kernel.org>
- Philipp Zabel <p.zabel@pengutronix.de>
- Chunfeng Yun <chunfeng.yun@mediatek.com>
description: |
The HDMI PHY serializes the HDMI encoder's three channel 10-bit parallel
output and drives the HDMI pads.
properties:
$nodename:
pattern: "^hdmi-phy@[0-9a-f]+$"
compatible:
enum:
- mediatek,mt2701-hdmi-phy
- mediatek,mt7623-hdmi-phy
- mediatek,mt8173-hdmi-phy
reg:
maxItems: 1
clocks:
items:
- description: PLL reference clock
clock-names:
items:
- const: pll_ref
clock-output-names:
items:
- const: hdmitx_dig_cts
"#phy-cells":
const: 0
"#clock-cells":
const: 0
mediatek,ibias:
description:
TX DRV bias current for < 1.65Gbps
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 63
default: 0xa
mediatek,ibias_up:
description:
TX DRV bias current for >= 1.65Gbps
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0
maximum: 63
default: 0x1c
required:
- compatible
- reg
- clocks
- clock-names
- clock-output-names
- "#phy-cells"
- "#clock-cells"
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/mt8173-clk.h>
hdmi_phy: hdmi-phy@10209100 {
compatible = "mediatek,mt8173-hdmi-phy";
reg = <0x10209100 0x24>;
clocks = <&apmixedsys CLK_APMIXED_HDMI_REF>;
clock-names = "pll_ref";
clock-output-names = "hdmitx_dig_cts";
mediatek,ibias = <0xa>;
mediatek,ibias_up = <0x1c>;
#clock-cells = <0>;
#phy-cells = <0>;
};
...

View File

@ -0,0 +1,260 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright (c) 2020 MediaTek
%YAML 1.2
---
$id: http://devicetree.org/schemas/phy/mediatek,tphy.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek T-PHY Controller Device Tree Bindings
maintainers:
- Chunfeng Yun <chunfeng.yun@mediatek.com>
description: |
The T-PHY controller supports physical layer functionality for a number of
controllers on MediaTek SoCs, includes USB2.0, USB3.0, PCIe and SATA.
Layout differences of banks between T-PHY V1 (mt8173/mt2701) and
T-PHY V2 (mt2712) when works on USB mode:
-----------------------------------
Version 1:
port offset bank
shared 0x0000 SPLLC
0x0100 FMREG
u2 port0 0x0800 U2PHY_COM
u3 port0 0x0900 U3PHYD
0x0a00 U3PHYD_BANK2
0x0b00 U3PHYA
0x0c00 U3PHYA_DA
u2 port1 0x1000 U2PHY_COM
u3 port1 0x1100 U3PHYD
0x1200 U3PHYD_BANK2
0x1300 U3PHYA
0x1400 U3PHYA_DA
u2 port2 0x1800 U2PHY_COM
...
Version 2:
port offset bank
u2 port0 0x0000 MISC
0x0100 FMREG
0x0300 U2PHY_COM
u3 port0 0x0700 SPLLC
0x0800 CHIP
0x0900 U3PHYD
0x0a00 U3PHYD_BANK2
0x0b00 U3PHYA
0x0c00 U3PHYA_DA
u2 port1 0x1000 MISC
0x1100 FMREG
0x1300 U2PHY_COM
u3 port1 0x1700 SPLLC
0x1800 CHIP
0x1900 U3PHYD
0x1a00 U3PHYD_BANK2
0x1b00 U3PHYA
0x1c00 U3PHYA_DA
u2 port2 0x2000 MISC
...
SPLLC shared by u3 ports and FMREG shared by u2 ports on V1 are put back
into each port; a new bank MISC for u2 ports and CHIP for u3 ports are
added on V2.
properties:
$nodename:
pattern: "^t-phy@[0-9a-f]+$"
compatible:
oneOf:
- items:
- enum:
- mediatek,mt2701-tphy
- mediatek,mt7623-tphy
- mediatek,mt7622-tphy
- mediatek,mt8516-tphy
- const: mediatek,generic-tphy-v1
- items:
- enum:
- mediatek,mt2712-tphy
- mediatek,mt7629-tphy
- mediatek,mt8183-tphy
- const: mediatek,generic-tphy-v2
- const: mediatek,mt2701-u3phy
deprecated: true
- const: mediatek,mt2712-u3phy
deprecated: true
- const: mediatek,mt8173-u3phy
reg:
description:
Register shared by multiple ports, exclude port's private register.
It is needed for T-PHY V1, such as mt2701 and mt8173, but not for
T-PHY V2, such as mt2712.
maxItems: 1
"#address-cells":
enum: [1, 2]
"#size-cells":
enum: [1, 2]
# Used with non-empty value if optional 'reg' is not provided.
# The format of the value is an arbitrary number of triplets of
# (child-bus-address, parent-bus-address, length).
ranges: true
mediatek,src-ref-clk-mhz:
description:
Frequency of reference clock for slew rate calibrate
default: 26
mediatek,src-coef:
description:
Coefficient for slew rate calibrate, depends on SoC process
$ref: /schemas/types.yaml#/definitions/uint32
default: 28
# Required child node:
patternProperties:
"^usb-phy@[0-9a-f]+$":
type: object
description:
A sub-node is required for each port the controller provides.
Address range information including the usual 'reg' property
is used inside these nodes to describe the controller's topology.
properties:
reg:
maxItems: 1
clocks:
minItems: 1
maxItems: 2
items:
- description: Reference clock, (HS is 48Mhz, SS/P is 24~27Mhz)
- description: Reference clock of analog phy
description:
Uses both clocks if the clock of analog and digital phys are
separated, otherwise uses "ref" clock only if needed.
clock-names:
minItems: 1
maxItems: 2
items:
- const: ref
- const: da_ref
"#phy-cells":
const: 1
description: |
The cells contain the following arguments.
- description: The PHY type
enum:
- PHY_TYPE_USB2
- PHY_TYPE_USB3
- PHY_TYPE_PCIE
- PHY_TYPE_SATA
# The following optional vendor properties are only for debug or HQA test
mediatek,eye-src:
description:
The value of slew rate calibrate (U2 phy)
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 1
maximum: 7
mediatek,eye-vrt:
description:
The selection of VRT reference voltage (U2 phy)
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 1
maximum: 7
mediatek,eye-term:
description:
The selection of HS_TX TERM reference voltage (U2 phy)
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 1
maximum: 7
mediatek,intr:
description:
The selection of internal resistor (U2 phy)
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 1
maximum: 31
mediatek,discth:
description:
The selection of disconnect threshold (U2 phy)
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 1
maximum: 15
mediatek,bc12:
description:
Specify the flag to enable BC1.2 if support it
type: boolean
required:
- reg
- "#phy-cells"
additionalProperties: false
required:
- compatible
- "#address-cells"
- "#size-cells"
- ranges
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/mt8173-clk.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/phy/phy.h>
usb@11271000 {
compatible = "mediatek,mt8173-mtu3", "mediatek,mtu3";
reg = <0x11271000 0x3000>, <0x11280700 0x0100>;
reg-names = "mac", "ippc";
phys = <&u2port0 PHY_TYPE_USB2>,
<&u3port0 PHY_TYPE_USB3>,
<&u2port1 PHY_TYPE_USB2>;
interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_LOW>;
clocks = <&topckgen CLK_TOP_USB30_SEL>;
clock-names = "sys_ck";
};
t-phy@11290000 {
compatible = "mediatek,mt8173-u3phy";
reg = <0x11290000 0x800>;
#address-cells = <1>;
#size-cells = <1>;
ranges;
u2port0: usb-phy@11290800 {
reg = <0x11290800 0x100>;
clocks = <&apmixedsys CLK_APMIXED_REF2USB_TX>, <&clk48m>;
clock-names = "ref", "da_ref";
#phy-cells = <1>;
};
u3port0: usb-phy@11290900 {
reg = <0x11290900 0x700>;
clocks = <&clk26m>;
clock-names = "ref";
#phy-cells = <1>;
};
u2port1: usb-phy@11291000 {
reg = <0x11291000 0x100>;
#phy-cells = <1>;
};
};
...

View File

@ -0,0 +1,64 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright (c) 2020 MediaTek
%YAML 1.2
---
$id: http://devicetree.org/schemas/phy/mediatek,ufs-phy.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek Universal Flash Storage (UFS) M-PHY binding
maintainers:
- Stanley Chu <stanley.chu@mediatek.com>
- Chunfeng Yun <chunfeng.yun@mediatek.com>
description: |
UFS M-PHY nodes are defined to describe on-chip UFS M-PHY hardware macro.
Each UFS M-PHY node should have its own node.
To bind UFS M-PHY with UFS host controller, the controller node should
contain a phandle reference to UFS M-PHY node.
properties:
$nodename:
pattern: "^ufs-phy@[0-9a-f]+$"
compatible:
const: mediatek,mt8183-ufsphy
reg:
maxItems: 1
clocks:
items:
- description: Unipro core control clock.
- description: M-PHY core control clock.
clock-names:
items:
- const: unipro
- const: mp
"#phy-cells":
const: 0
required:
- compatible
- reg
- "#phy-cells"
- clocks
- clock-names
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/mt8183-clk.h>
ufsphy: ufs-phy@11fa0000 {
compatible = "mediatek,mt8183-ufsphy";
reg = <0x11fa0000 0xc000>;
clocks = <&infracfg CLK_INFRA_UNIPRO_SCK>,
<&infracfg CLK_INFRA_UFS_MP_SAP_BCLK>;
clock-names = "unipro", "mp";
#phy-cells = <0>;
};
...

View File

@ -0,0 +1,199 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright (c) 2020 MediaTek
%YAML 1.2
---
$id: http://devicetree.org/schemas/phy/mediatek,xsphy.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek XS-PHY Controller Device Tree Bindings
maintainers:
- Chunfeng Yun <chunfeng.yun@mediatek.com>
description: |
The XS-PHY controller supports physical layer functionality for USB3.1
GEN2 controller on MediaTek SoCs.
Banks layout of xsphy
----------------------------------
port offset bank
u2 port0 0x0000 MISC
0x0100 FMREG
0x0300 U2PHY_COM
u2 port1 0x1000 MISC
0x1100 FMREG
0x1300 U2PHY_COM
u2 port2 0x2000 MISC
...
u31 common 0x3000 DIG_GLB
0x3100 PHYA_GLB
u31 port0 0x3400 DIG_LN_TOP
0x3500 DIG_LN_TX0
0x3600 DIG_LN_RX0
0x3700 DIG_LN_DAIF
0x3800 PHYA_LN
u31 port1 0x3a00 DIG_LN_TOP
0x3b00 DIG_LN_TX0
0x3c00 DIG_LN_RX0
0x3d00 DIG_LN_DAIF
0x3e00 PHYA_LN
...
DIG_GLB & PHYA_GLB are shared by U31 ports.
properties:
$nodename:
pattern: "^xs-phy@[0-9a-f]+$"
compatible:
items:
- enum:
- mediatek,mt3611-xsphy
- mediatek,mt3612-xsphy
- const: mediatek,xsphy
reg:
description:
Register shared by multiple U3 ports, exclude port's private register,
if only U2 ports provided, shouldn't use the property.
maxItems: 1
"#address-cells":
enum: [1, 2]
"#size-cells":
enum: [1, 2]
ranges: true
mediatek,src-ref-clk-mhz:
description:
Frequency of reference clock for slew rate calibrate
default: 26
mediatek,src-coef:
description:
Coefficient for slew rate calibrate, depends on SoC process
$ref: /schemas/types.yaml#/definitions/uint32
default: 17
# Required child node:
patternProperties:
"^usb-phy@[0-9a-f]+$":
type: object
description:
A sub-node is required for each port the controller provides.
Address range information including the usual 'reg' property
is used inside these nodes to describe the controller's topology.
properties:
reg:
maxItems: 1
clocks:
items:
- description: Reference clock, (HS is 48Mhz, SS/P is 24~27Mhz)
clock-names:
items:
- const: ref
"#phy-cells":
const: 1
description: |
The cells contain the following arguments.
- description: The PHY type
enum:
- PHY_TYPE_USB2
- PHY_TYPE_USB3
# The following optional vendor properties are only for debug or HQA test
mediatek,eye-src:
description:
The value of slew rate calibrate (U2 phy)
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 1
maximum: 7
mediatek,eye-vrt:
description:
The selection of VRT reference voltage (U2 phy)
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 1
maximum: 7
mediatek,eye-term:
description:
The selection of HS_TX TERM reference voltage (U2 phy)
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 1
maximum: 7
mediatek,efuse-intr:
description:
The selection of Internal Resistor (U2/U3 phy)
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 1
maximum: 63
mediatek,efuse-tx-imp:
description:
The selection of TX Impedance (U3 phy)
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 1
maximum: 31
mediatek,efuse-rx-imp:
description:
The selection of RX Impedance (U3 phy)
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 1
maximum: 31
required:
- reg
- clocks
- clock-names
- "#phy-cells"
additionalProperties: false
required:
- compatible
- "#address-cells"
- "#size-cells"
- ranges
additionalProperties: false
examples:
- |
#include <dt-bindings/phy/phy.h>
u3phy: xs-phy@11c40000 {
compatible = "mediatek,mt3611-xsphy", "mediatek,xsphy";
reg = <0x11c43000 0x0200>;
mediatek,src-ref-clk-mhz = <26>;
mediatek,src-coef = <17>;
#address-cells = <1>;
#size-cells = <1>;
ranges;
u2port0: usb-phy@11c40000 {
reg = <0x11c40000 0x0400>;
clocks = <&clk48m>;
clock-names = "ref";
mediatek,eye-src = <4>;
#phy-cells = <1>;
};
u3port0: usb-phy@11c43000 {
reg = <0x11c43400 0x0500>;
clocks = <&clk26m>;
clock-names = "ref";
mediatek,efuse-intr = <28>;
#phy-cells = <1>;
};
};
...

View File

@ -1,162 +0,0 @@
MediaTek T-PHY binding
--------------------------
T-phy controller supports physical layer functionality for a number of
controllers on MediaTek SoCs, such as, USB2.0, USB3.0, PCIe, and SATA.
Required properties (controller (parent) node):
- compatible : should be one of
"mediatek,generic-tphy-v1"
"mediatek,generic-tphy-v2"
"mediatek,mt2701-u3phy" (deprecated)
"mediatek,mt2712-u3phy" (deprecated)
"mediatek,mt8173-u3phy";
make use of "mediatek,generic-tphy-v1" on mt2701 instead and
"mediatek,generic-tphy-v2" on mt2712 instead.
- #address-cells: the number of cells used to represent physical
base addresses.
- #size-cells: the number of cells used to represent the size of an address.
- ranges: the address mapping relationship to the parent, defined with
- empty value: if optional 'reg' is used.
- non-empty value: if optional 'reg' is not used. should set
the child's base address to 0, the physical address
within parent's address space, and the length of
the address map.
Required nodes : a sub-node is required for each port the controller
provides. Address range information including the usual
'reg' property is used inside these nodes to describe
the controller's topology.
Optional properties (controller (parent) node):
- reg : offset and length of register shared by multiple ports,
exclude port's private register. It is needed on mt2701
and mt8173, but not on mt2712.
- mediatek,src-ref-clk-mhz : frequency of reference clock for slew rate
calibrate
- mediatek,src-coef : coefficient for slew rate calibrate, depends on
SoC process
Required properties (port (child) node):
- reg : address and length of the register set for the port.
- #phy-cells : should be 1 (See second example)
cell after port phandle is phy type from:
- PHY_TYPE_USB2
- PHY_TYPE_USB3
- PHY_TYPE_PCIE
- PHY_TYPE_SATA
Optional properties (PHY_TYPE_USB2 port (child) node):
- clocks : a list of phandle + clock-specifier pairs, one for each
entry in clock-names
- clock-names : may contain
"ref": 48M reference clock for HighSpeed (digital) phy; and 26M
reference clock for SuperSpeed (digital) phy, sometimes is
24M, 25M or 27M, depended on platform.
"da_ref": the reference clock of analog phy, used if the clocks
of analog and digital phys are separated, otherwise uses
"ref" clock only if needed.
- mediatek,eye-src : u32, the value of slew rate calibrate
- mediatek,eye-vrt : u32, the selection of VRT reference voltage
- mediatek,eye-term : u32, the selection of HS_TX TERM reference voltage
- mediatek,bc12 : bool, enable BC12 of u2phy if support it
- mediatek,discth : u32, the selection of disconnect threshold
- mediatek,intr : u32, the selection of internal R (resistance)
Example:
u3phy: usb-phy@11290000 {
compatible = "mediatek,mt8173-u3phy";
reg = <0 0x11290000 0 0x800>;
#address-cells = <2>;
#size-cells = <2>;
ranges;
u2port0: usb-phy@11290800 {
reg = <0 0x11290800 0 0x100>;
clocks = <&apmixedsys CLK_APMIXED_REF2USB_TX>;
clock-names = "ref";
#phy-cells = <1>;
};
u3port0: usb-phy@11290900 {
reg = <0 0x11290800 0 0x700>;
clocks = <&clk26m>;
clock-names = "ref";
#phy-cells = <1>;
};
u2port1: usb-phy@11291000 {
reg = <0 0x11291000 0 0x100>;
clocks = <&apmixedsys CLK_APMIXED_REF2USB_TX>;
clock-names = "ref";
#phy-cells = <1>;
};
};
Specifying phy control of devices
---------------------------------
Device nodes should specify the configuration required in their "phys"
property, containing a phandle to the phy port node and a device type;
phy-names for each port are optional.
Example:
#include <dt-bindings/phy/phy.h>
usb30: usb@11270000 {
...
phys = <&u2port0 PHY_TYPE_USB2>, <&u3port0 PHY_TYPE_USB3>;
phy-names = "usb2-0", "usb3-0";
...
};
Layout differences of banks between mt8173/mt2701 and mt2712
-------------------------------------------------------------
mt8173 and mt2701:
port offset bank
shared 0x0000 SPLLC
0x0100 FMREG
u2 port0 0x0800 U2PHY_COM
u3 port0 0x0900 U3PHYD
0x0a00 U3PHYD_BANK2
0x0b00 U3PHYA
0x0c00 U3PHYA_DA
u2 port1 0x1000 U2PHY_COM
u3 port1 0x1100 U3PHYD
0x1200 U3PHYD_BANK2
0x1300 U3PHYA
0x1400 U3PHYA_DA
u2 port2 0x1800 U2PHY_COM
...
mt2712:
port offset bank
u2 port0 0x0000 MISC
0x0100 FMREG
0x0300 U2PHY_COM
u3 port0 0x0700 SPLLC
0x0800 CHIP
0x0900 U3PHYD
0x0a00 U3PHYD_BANK2
0x0b00 U3PHYA
0x0c00 U3PHYA_DA
u2 port1 0x1000 MISC
0x1100 FMREG
0x1300 U2PHY_COM
u3 port1 0x1700 SPLLC
0x1800 CHIP
0x1900 U3PHYD
0x1a00 U3PHYD_BANK2
0x1b00 U3PHYA
0x1c00 U3PHYA_DA
u2 port2 0x2000 MISC
...
SPLLC shared by u3 ports and FMREG shared by u2 ports on
mt8173/mt2701 are put back into each port; a new bank MISC for
u2 ports and CHIP for u3 ports are added on mt2712.

View File

@ -1,38 +0,0 @@
MediaTek Universal Flash Storage (UFS) M-PHY binding
--------------------------------------------------------
UFS M-PHY nodes are defined to describe on-chip UFS M-PHY hardware macro.
Each UFS M-PHY node should have its own node.
To bind UFS M-PHY with UFS host controller, the controller node should
contain a phandle reference to UFS M-PHY node.
Required properties for UFS M-PHY nodes:
- compatible : Compatible list, contains the following controller:
"mediatek,mt8183-ufsphy" for ufs phy
persent on MT81xx chipsets.
- reg : Address and length of the UFS M-PHY register set.
- #phy-cells : This property shall be set to 0.
- clocks : List of phandle and clock specifier pairs.
- clock-names : List of clock input name strings sorted in the same
order as the clocks property. Following clocks are
mandatory.
"unipro": Unipro core control clock.
"mp": M-PHY core control clock.
Example:
ufsphy: phy@11fa0000 {
compatible = "mediatek,mt8183-ufsphy";
reg = <0 0x11fa0000 0 0xc000>;
#phy-cells = <0>;
clocks = <&infracfg_ao INFRACFG_AO_UNIPRO_SCK_CG>,
<&infracfg_ao INFRACFG_AO_UFS_MP_SAP_BCLK_CG>;
clock-names = "unipro", "mp";
};
ufshci@11270000 {
...
phys = <&ufsphy>;
};

View File

@ -1,109 +0,0 @@
MediaTek XS-PHY binding
--------------------------
The XS-PHY controller supports physical layer functionality for USB3.1
GEN2 controller on MediaTek SoCs.
Required properties (controller (parent) node):
- compatible : should be "mediatek,<soc-model>-xsphy", "mediatek,xsphy",
soc-model is the name of SoC, such as mt3611 etc;
when using "mediatek,xsphy" compatible string, you need SoC specific
ones in addition, one of:
- "mediatek,mt3611-xsphy"
- #address-cells, #size-cells : should use the same values as the root node
- ranges: must be present
Optional properties (controller (parent) node):
- reg : offset and length of register shared by multiple U3 ports,
exclude port's private register, if only U2 ports provided,
shouldn't use the property.
- mediatek,src-ref-clk-mhz : u32, frequency of reference clock for slew rate
calibrate
- mediatek,src-coef : u32, coefficient for slew rate calibrate, depends on
SoC process
Required nodes : a sub-node is required for each port the controller
provides. Address range information including the usual
'reg' property is used inside these nodes to describe
the controller's topology.
Required properties (port (child) node):
- reg : address and length of the register set for the port.
- clocks : a list of phandle + clock-specifier pairs, one for each
entry in clock-names
- clock-names : must contain
"ref": 48M reference clock for HighSpeed analog phy; and 26M
reference clock for SuperSpeedPlus analog phy, sometimes is
24M, 25M or 27M, depended on platform.
- #phy-cells : should be 1
cell after port phandle is phy type from:
- PHY_TYPE_USB2
- PHY_TYPE_USB3
The following optional properties are only for debug or HQA test
Optional properties (PHY_TYPE_USB2 port (child) node):
- mediatek,eye-src : u32, the value of slew rate calibrate
- mediatek,eye-vrt : u32, the selection of VRT reference voltage
- mediatek,eye-term : u32, the selection of HS_TX TERM reference voltage
- mediatek,efuse-intr : u32, the selection of Internal Resistor
Optional properties (PHY_TYPE_USB3 port (child) node):
- mediatek,efuse-intr : u32, the selection of Internal Resistor
- mediatek,efuse-tx-imp : u32, the selection of TX Impedance
- mediatek,efuse-rx-imp : u32, the selection of RX Impedance
Banks layout of xsphy
-------------------------------------------------------------
port offset bank
u2 port0 0x0000 MISC
0x0100 FMREG
0x0300 U2PHY_COM
u2 port1 0x1000 MISC
0x1100 FMREG
0x1300 U2PHY_COM
u2 port2 0x2000 MISC
...
u31 common 0x3000 DIG_GLB
0x3100 PHYA_GLB
u31 port0 0x3400 DIG_LN_TOP
0x3500 DIG_LN_TX0
0x3600 DIG_LN_RX0
0x3700 DIG_LN_DAIF
0x3800 PHYA_LN
u31 port1 0x3a00 DIG_LN_TOP
0x3b00 DIG_LN_TX0
0x3c00 DIG_LN_RX0
0x3d00 DIG_LN_DAIF
0x3e00 PHYA_LN
...
DIG_GLB & PHYA_GLB are shared by U31 ports.
Example:
u3phy: usb-phy@11c40000 {
compatible = "mediatek,mt3611-xsphy", "mediatek,xsphy";
reg = <0 0x11c43000 0 0x0200>;
mediatek,src-ref-clk-mhz = <26>;
mediatek,src-coef = <17>;
#address-cells = <2>;
#size-cells = <2>;
ranges;
u2port0: usb-phy@11c40000 {
reg = <0 0x11c40000 0 0x0400>;
clocks = <&clk48m>;
clock-names = "ref";
mediatek,eye-src = <4>;
#phy-cells = <1>;
};
u3port0: usb-phy@11c43000 {
reg = <0 0x11c43400 0 0x0500>;
clocks = <&clk26m>;
clock-names = "ref";
mediatek,efuse-intr = <28>;
#phy-cells = <1>;
};
};

View File

@ -45,6 +45,12 @@ properties:
"#size-cells":
const: 0
vdda1v1-supply:
description: regulator providing 1V1 power supply to the PLL block
vdda1v8-supply:
description: regulator providing 1V8 power supply to the PLL block
#Required child nodes:
patternProperties:
@ -61,12 +67,6 @@ patternProperties:
phy-supply:
description: regulator providing 3V3 power supply to the PHY.
vdda1v1-supply:
description: regulator providing 1V1 power supply to the PLL block
vdda1v8-supply:
description: regulator providing 1V8 power supply to the PLL block
"#phy-cells":
enum: [ 0x0, 0x1 ]
@ -90,8 +90,6 @@ patternProperties:
required:
- reg
- phy-supply
- vdda1v1-supply
- vdda1v8-supply
- "#phy-cells"
additionalProperties: false
@ -102,6 +100,8 @@ required:
- clocks
- "#address-cells"
- "#size-cells"
- vdda1v1-supply
- vdda1v8-supply
- usb-phy@0
- usb-phy@1
@ -116,22 +116,20 @@ examples:
reg = <0x5a006000 0x1000>;
clocks = <&rcc USBPHY_K>;
resets = <&rcc USBPHY_R>;
vdda1v1-supply = <&reg11>;
vdda1v8-supply = <&reg18>;
#address-cells = <1>;
#size-cells = <0>;
usbphyc_port0: usb-phy@0 {
reg = <0>;
phy-supply = <&vdd_usb>;
vdda1v1-supply = <&reg11>;
vdda1v8-supply = <&reg18>;
#phy-cells = <0>;
};
usbphyc_port1: usb-phy@1 {
reg = <1>;
phy-supply = <&vdd_usb>;
vdda1v1-supply = <&reg11>;
vdda1v8-supply = <&reg18>;
#phy-cells = <1>;
};
};

View File

@ -25,19 +25,32 @@ properties:
- qcom,msm8998-qmp-pcie-phy
- qcom,msm8998-qmp-ufs-phy
- qcom,msm8998-qmp-usb3-phy
- qcom,sc8180x-qmp-ufs-phy
- qcom,sc8180x-qmp-usb3-phy
- qcom,sdm845-qhp-pcie-phy
- qcom,sdm845-qmp-pcie-phy
- qcom,sdm845-qmp-ufs-phy
- qcom,sdm845-qmp-usb3-uni-phy
- qcom,sm8150-qmp-ufs-phy
- qcom,sm8150-qmp-usb3-phy
- qcom,sm8150-qmp-usb3-uni-phy
- qcom,sm8250-qmp-ufs-phy
- qcom,sm8250-qmp-gen3x1-pcie-phy
- qcom,sm8250-qmp-gen3x2-pcie-phy
- qcom,sm8250-qmp-modem-pcie-phy
- qcom,sm8250-qmp-usb3-phy
- qcom,sm8250-qmp-usb3-uni-phy
- qcom,sm8350-qmp-ufs-phy
- qcom,sm8350-qmp-usb3-phy
- qcom,sm8350-qmp-usb3-uni-phy
- qcom,sdx55-qmp-usb3-uni-phy
reg:
minItems: 1
maxItems: 2
items:
- description: Address and length of PHY's common serdes block.
- description: Address and length of PHY's DP_COM control block.
"#clock-cells":
enum: [ 1, 2 ]
@ -131,6 +144,32 @@ allOf:
items:
- const: phy
- const: common
- if:
properties:
compatible:
contains:
enum:
- qcom,sdx55-qmp-usb3-uni-phy
then:
properties:
clocks:
items:
- description: Phy aux clock.
- description: Phy config clock.
- description: 19.2 MHz ref clk.
clock-names:
items:
- const: aux
- const: cfg_ahb
- const: ref
resets:
items:
- description: reset of phy block.
- description: phy common block reset.
reset-names:
items:
- const: phy
- const: common
- if:
properties:
compatible:
@ -285,6 +324,64 @@ allOf:
reset-names:
items:
- const: phy
- if:
properties:
compatible:
contains:
enum:
- qcom,sm8150-qmp-usb3-phy
- qcom,sm8150-qmp-usb3-uni-phy
- qcom,sm8250-qmp-usb3-uni-phy
- qcom,sm8350-qmp-usb3-uni-phy
then:
properties:
clocks:
items:
- description: Phy aux clock.
- description: 19.2 MHz ref clk source.
- description: 19.2 MHz ref clk.
- description: Phy common block aux clock.
clock-names:
items:
- const: aux
- const: ref_clk_src
- const: ref
- const: com_aux
resets:
items:
- description: reset of phy block.
- description: phy common block reset.
reset-names:
items:
- const: phy
- const: common
- if:
properties:
compatible:
contains:
enum:
- qcom,sm8250-qmp-usb3-phy
- qcom,sm8350-qmp-usb3-phy
then:
properties:
clocks:
items:
- description: Phy aux clock.
- description: 19.2 MHz ref clk.
- description: Phy common block aux clock.
clock-names:
items:
- const: aux
- const: ref_clk_src
- const: com_aux
resets:
items:
- description: reset of phy block.
- description: phy common block reset.
reset-names:
items:
- const: phy
- const: common
examples:
- |

View File

@ -21,6 +21,8 @@ properties:
- qcom,ipq8074-qusb2-phy
- qcom,msm8996-qusb2-phy
- qcom,msm8998-qusb2-phy
- qcom,sdm660-qusb2-phy
- qcom,ipq6018-qusb2-phy
- items:
- enum:
- qcom,sc7180-qusb2-phy

View File

@ -16,6 +16,7 @@ properties:
compatible:
enum:
- qcom,usb-hs-28nm-femtophy
- qcom,usb-hs-28nm-mdm9607
reg:
maxItems: 1

View File

@ -17,6 +17,8 @@ properties:
enum:
- qcom,usb-snps-hs-7nm-phy
- qcom,sm8150-usb-hs-phy
- qcom,sm8250-usb-hs-phy
- qcom,sm8350-usb-hs-phy
- qcom,usb-snps-femto-v2-phy
reg:

View File

@ -16,11 +16,11 @@ Optional properties:
- drive-impedance-ohm: Specifies the drive impedance in Ohm.
Possible values are 33, 40, 50, 66 and 100.
If not set, the default value of 50 will be applied.
- enable-strobe-pulldown: Enable internal pull-down for the strobe line.
If not set, pull-down is not used.
- output-tapdelay-select: Specifies the phyctrl_otapdlysec register.
If not set, the register defaults to 0x4.
Maximum value 0xf.
- rockchip,enable-strobe-pulldown: Enable internal pull-down for the strobe
line. If not set, pull-down is not used.
- rockchip,output-tapdelay-select: Specifies the phyctrl_otapdlysec register.
If not set, the register defaults to 0x4.
Maximum value 0xf.
Example:

View File

@ -151,7 +151,7 @@ patternProperties:
WIZ node should have '1' subnode for the SERDES. It could be either
Sierra SERDES or Torrent SERDES. Sierra SERDES should follow the
bindings specified in
Documentation/devicetree/bindings/phy/phy-cadence-sierra.txt
Documentation/devicetree/bindings/phy/phy-cadence-sierra.yaml
Torrent SERDES should follow the bindings specified in
Documentation/devicetree/bindings/phy/phy-cadence-torrent.yaml

View File

@ -94,7 +94,6 @@ available subsections can be seen below.
pps
ptp
phy/index
pti_intel_mid
pwm
pldmfw/index
rfkill

View File

@ -1,108 +0,0 @@
.. SPDX-License-Identifier: GPL-2.0
=============
Intel MID PTI
=============
The Intel MID PTI project is HW implemented in Intel Atom
system-on-a-chip designs based on the Parallel Trace
Interface for MIPI P1149.7 cJTAG standard. The kernel solution
for this platform involves the following files::
./include/linux/pti.h
./drivers/.../n_tracesink.h
./drivers/.../n_tracerouter.c
./drivers/.../n_tracesink.c
./drivers/.../pti.c
pti.c is the driver that enables various debugging features
popular on platforms from certain mobile manufacturers.
n_tracerouter.c and n_tracesink.c allow extra system information to
be collected and routed to the pti driver, such as trace
debugging data from a modem. Although n_tracerouter
and n_tracesink are a part of the complete PTI solution,
these two line disciplines can work separately from
pti.c and route any data stream from one /dev/tty node
to another /dev/tty node via kernel-space. This provides
a stable, reliable connection that will not break unless
the user-space application shuts down (plus avoids
kernel->user->kernel context switch overheads of routing
data).
An example debugging usage for this driver system:
* Hook /dev/ttyPTI0 to syslogd. Opening this port will also start
a console device to further capture debugging messages to PTI.
* Hook /dev/ttyPTI1 to modem debugging data to write to PTI HW.
This is where n_tracerouter and n_tracesink are used.
* Hook /dev/pti to a user-level debugging application for writing
to PTI HW.
* `Use mipi_` Kernel Driver API in other device drivers for
debugging to PTI by first requesting a PTI write address via
mipi_request_masterchannel(1).
Below is example pseudo-code on how a 'privileged' application
can hook up n_tracerouter and n_tracesink to any tty on
a system. 'Privileged' means the application has enough
privileges to successfully manipulate the ldisc drivers
but is not just blindly executing as 'root'. Keep in mind
the use of ioctl(,TIOCSETD,) is not specific to the n_tracerouter
and n_tracesink line discpline drivers but is a generic
operation for a program to use a line discpline driver
on a tty port other than the default n_tty:
.. code-block:: c
/////////// To hook up n_tracerouter and n_tracesink /////////
// Note that n_tracerouter depends on n_tracesink.
#include <errno.h>
#define ONE_TTY "/dev/ttyOne"
#define TWO_TTY "/dev/ttyTwo"
// needed global to hand onto ldisc connection
static int g_fd_source = -1;
static int g_fd_sink = -1;
// these two vars used to grab LDISC values from loaded ldisc drivers
// in OS. Look at /proc/tty/ldiscs to get the right numbers from
// the ldiscs loaded in the system.
int source_ldisc_num, sink_ldisc_num = -1;
int retval;
g_fd_source = open(ONE_TTY, O_RDWR); // must be R/W
g_fd_sink = open(TWO_TTY, O_RDWR); // must be R/W
if (g_fd_source <= 0) || (g_fd_sink <= 0) {
// doubt you'll want to use these exact error lines of code
printf("Error on open(). errno: %d\n",errno);
return errno;
}
retval = ioctl(g_fd_sink, TIOCSETD, &sink_ldisc_num);
if (retval < 0) {
printf("Error on ioctl(). errno: %d\n", errno);
return errno;
}
retval = ioctl(g_fd_source, TIOCSETD, &source_ldisc_num);
if (retval < 0) {
printf("Error on ioctl(). errno: %d\n", errno);
return errno;
}
/////////// To disconnect n_tracerouter and n_tracesink ////////
// First make sure data through the ldiscs has stopped.
// Second, disconnect ldiscs. This provides a
// little cleaner shutdown on tty stack.
sink_ldisc_num = 0;
source_ldisc_num = 0;
ioctl(g_fd_uart, TIOCSETD, &sink_ldisc_num);
ioctl(g_fd_gadget, TIOCSETD, &source_ldisc_num);
// Three, program closes connection, and cleanup:
close(g_fd_uart);
close(g_fd_gadget);
g_fd_uart = g_fd_gadget = NULL;

View File

@ -501,6 +501,34 @@ Developer only needs to provide a sub feature driver with matched feature id.
FME Partial Reconfiguration Sub Feature driver (see drivers/fpga/dfl-fme-pr.c)
could be a reference.
Location of DFLs on a PCI Device
================================
The original method for finding a DFL on a PCI device assumed the start of the
first DFL to offset 0 of bar 0. If the first node of the DFL is an FME,
then further DFLs in the port(s) are specified in FME header registers.
Alternatively, a PCIe vendor specific capability structure can be used to
specify the location of all the DFLs on the device, providing flexibility
for the type of starting node in the DFL. Intel has reserved the
VSEC ID of 0x43 for this purpose. The vendor specific
data begins with a 4 byte vendor specific register for the number of DFLs followed 4 byte
Offset/BIR vendor specific registers for each DFL. Bits 2:0 of Offset/BIR register
indicates the BAR, and bits 31:3 form the 8 byte aligned offset where bits 2:0 are
zero.
::
+----------------------------+
|31 Number of DFLS 0|
+----------------------------+
|31 Offset 3|2 BIR 0|
+----------------------------+
. . .
+----------------------------+
|31 Offset 3|2 BIR 0|
+----------------------------+
Being able to specify more than one DFL per BAR has been considered, but it
was determined the use case did not provide value. Specifying a single DFL
per BAR simplifies the implementation and allows for extra error checking.
Open discussion
===============

View File

@ -512,6 +512,38 @@ The --itrace option controls the type and frequency of synthesized events
Note that only 64-bit programs are currently supported - further work is
required to support instruction decode of 32-bit Arm programs.
2.2) Tracing PID
The kernel can be built to write the PID value into the PE ContextID registers.
For a kernel running at EL1, the PID is stored in CONTEXTIDR_EL1. A PE may
implement Arm Virtualization Host Extensions (VHE), which the kernel can
run at EL2 as a virtualisation host; in this case, the PID value is stored in
CONTEXTIDR_EL2.
perf provides PMU formats that program the ETM to insert these values into the
trace data; the PMU formats are defined as below:
"contextid1": Available on both EL1 kernel and EL2 kernel. When the
kernel is running at EL1, "contextid1" enables the PID
tracing; when the kernel is running at EL2, this enables
tracing the PID of guest applications.
"contextid2": Only usable when the kernel is running at EL2. When
selected, enables PID tracing on EL2 kernel.
"contextid": Will be an alias for the option that enables PID
tracing. I.e,
contextid == contextid1, on EL1 kernel.
contextid == contextid2, on EL2 kernel.
perf will always enable PID tracing at the relevant EL, this is accomplished by
automatically enable the "contextid" config - but for EL2 it is possible to make
specific adjustments using configs "contextid1" and "contextid2", E.g. if a user
wants to trace PIDs for both host and guest, the two configs "contextid1" and
"contextid2" can be set at the same time:
perf record -e cs_etm/contextid1,contextid2/u -- vm
Generating coverage files for Feedback Directed Optimization: AutoFDO
---------------------------------------------------------------------

View File

@ -179,6 +179,7 @@ Code Seq# Include File Comments
'R' 00-1F linux/random.h conflict!
'R' 01 linux/rfkill.h conflict!
'R' C0-DF net/bluetooth/rfcomm.h
'R' E0 uapi/linux/fsl_mc.h
'S' all linux/cdrom.h conflict!
'S' 80-81 scsi/scsi_ioctl.h conflict!
'S' 82-FF scsi/scsi.h conflict!
@ -318,6 +319,7 @@ Code Seq# Include File Comments
0xA0 all linux/sdp/sdp.h Industrial Device Project
<mailto:kenji@bitgate.com>
0xA1 0 linux/vtpm_proxy.h TPM Emulator Proxy Driver
0xA2 all uapi/linux/acrn.h ACRN hypervisor
0xA3 80-8F Port ACL in development:
<mailto:tlewis@mindspring.com>
0xA3 90-9F linux/dtlk.h

View File

@ -0,0 +1,46 @@
.. SPDX-License-Identifier: GPL-2.0
===============
ACRN CPUID bits
===============
A guest VM running on an ACRN hypervisor can check some of its features using
CPUID.
ACRN cpuid functions are:
function: 0x40000000
returns::
eax = 0x40000010
ebx = 0x4e524341
ecx = 0x4e524341
edx = 0x4e524341
Note that this value in ebx, ecx and edx corresponds to the string
"ACRNACRNACRN". The value in eax corresponds to the maximum cpuid function
present in this leaf, and will be updated if more functions are added in the
future.
function: define ACRN_CPUID_FEATURES (0x40000001)
returns::
ebx, ecx, edx
eax = an OR'ed group of (1 << flag)
where ``flag`` is defined as below:
================================= =========== ================================
flag value meaning
================================= =========== ================================
ACRN_FEATURE_PRIVILEGED_VM 0 guest VM is a privileged VM
================================= =========== ================================
function: 0x40000010
returns::
ebx, ecx, edx
eax = (Virtual) TSC frequency in kHz.

View File

@ -0,0 +1,12 @@
.. SPDX-License-Identifier: GPL-2.0
===============
ACRN Hypervisor
===============
.. toctree::
:maxdepth: 1
introduction
io-request
cpuid

View File

@ -0,0 +1,43 @@
.. SPDX-License-Identifier: GPL-2.0
ACRN Hypervisor Introduction
============================
The ACRN Hypervisor is a Type 1 hypervisor, running directly on bare-metal
hardware. It has a privileged management VM, called Service VM, to manage User
VMs and do I/O emulation.
ACRN userspace is an application running in the Service VM that emulates
devices for a User VM based on command line configurations. ACRN Hypervisor
Service Module (HSM) is a kernel module in the Service VM which provides
hypervisor services to the ACRN userspace.
Below figure shows the architecture.
::
Service VM User VM
+----------------------------+ | +------------------+
| +--------------+ | | | |
| |ACRN userspace| | | | |
| +--------------+ | | | |
|-----------------ioctl------| | | | ...
|kernel space +----------+ | | | |
| | HSM | | | | Drivers |
| +----------+ | | | |
+--------------------|-------+ | +------------------+
+---------------------hypercall----------------------------------------+
| ACRN Hypervisor |
+----------------------------------------------------------------------+
| Hardware |
+----------------------------------------------------------------------+
ACRN userspace allocates memory for the User VM, configures and initializes the
devices used by the User VM, loads the virtual bootloader, initializes the
virtual CPU state and handles I/O request accesses from the User VM. It uses
ioctls to communicate with the HSM. HSM implements hypervisor services by
interacting with the ACRN Hypervisor via hypercalls. HSM exports a char device
interface (/dev/acrn_hsm) to userspace.
The ACRN hypervisor is open for contribution from anyone. The source repo is
available at https://github.com/projectacrn/acrn-hypervisor.

View File

@ -0,0 +1,97 @@
.. SPDX-License-Identifier: GPL-2.0
I/O request handling
====================
An I/O request of a User VM, which is constructed by the hypervisor, is
distributed by the ACRN Hypervisor Service Module to an I/O client
corresponding to the address range of the I/O request. Details of I/O request
handling are described in the following sections.
1. I/O request
--------------
For each User VM, there is a shared 4-KByte memory region used for I/O requests
communication between the hypervisor and Service VM. An I/O request is a
256-byte structure buffer, which is 'struct acrn_io_request', that is filled by
an I/O handler of the hypervisor when a trapped I/O access happens in a User
VM. ACRN userspace in the Service VM first allocates a 4-KByte page and passes
the GPA (Guest Physical Address) of the buffer to the hypervisor. The buffer is
used as an array of 16 I/O request slots with each I/O request slot being 256
bytes. This array is indexed by vCPU ID.
2. I/O clients
--------------
An I/O client is responsible for handling User VM I/O requests whose accessed
GPA falls in a certain range. Multiple I/O clients can be associated with each
User VM. There is a special client associated with each User VM, called the
default client, that handles all I/O requests that do not fit into the range of
any other clients. The ACRN userspace acts as the default client for each User
VM.
Below illustration shows the relationship between I/O requests shared buffer,
I/O requests and I/O clients.
::
+------------------------------------------------------+
| Service VM |
|+--------------------------------------------------+ |
|| +----------------------------------------+ | |
|| | shared page ACRN userspace | | |
|| | +-----------------+ +------------+ | | |
|| +----+->| acrn_io_request |<-+ default | | | |
|| | | | +-----------------+ | I/O client | | | |
|| | | | | ... | +------------+ | | |
|| | | | +-----------------+ | | |
|| | +-|--------------------------------------+ | |
||---|----|-----------------------------------------| |
|| | | kernel | |
|| | | +----------------------+ | |
|| | | | +-------------+ HSM | | |
|| | +--------------+ | | | |
|| | | | I/O clients | | | |
|| | | | | | | |
|| | | +-------------+ | | |
|| | +----------------------+ | |
|+---|----------------------------------------------+ |
+----|-------------------------------------------------+
|
+----|-------------------------------------------------+
| +-+-----------+ |
| | I/O handler | ACRN Hypervisor |
| +-------------+ |
+------------------------------------------------------+
3. I/O request state transition
-------------------------------
The state transitions of an ACRN I/O request are as follows.
::
FREE -> PENDING -> PROCESSING -> COMPLETE -> FREE -> ...
- FREE: this I/O request slot is empty
- PENDING: a valid I/O request is pending in this slot
- PROCESSING: the I/O request is being processed
- COMPLETE: the I/O request has been processed
An I/O request in COMPLETE or FREE state is owned by the hypervisor. HSM and
ACRN userspace are in charge of processing the others.
4. Processing flow of I/O requests
----------------------------------
a. The I/O handler of the hypervisor will fill an I/O request with PENDING
state when a trapped I/O access happens in a User VM.
b. The hypervisor makes an upcall, which is a notification interrupt, to
the Service VM.
c. The upcall handler schedules a worker to dispatch I/O requests.
d. The worker looks for the PENDING I/O requests, assigns them to different
registered clients based on the address of the I/O accesses, updates
their state to PROCESSING, and notifies the corresponding client to handle.
e. The notified client handles the assigned I/O requests.
f. The HSM updates I/O requests states to COMPLETE and notifies the hypervisor
of the completion via hypercalls.

View File

@ -12,6 +12,7 @@ Linux Virtualization Support
paravirt_ops
guest-halt-polling
ne_overview
acrn/index
.. only:: html and subproject

View File

@ -436,6 +436,15 @@ S: Orphan
F: drivers/platform/x86/wmi.c
F: include/uapi/linux/wmi.h
ACRN HYPERVISOR SERVICE MODULE
M: Shuo Liu <shuo.a.liu@intel.com>
L: acrn-dev@lists.projectacrn.org (subscribers-only)
S: Supported
W: https://projectacrn.org
F: Documentation/virt/acrn/
F: drivers/virt/acrn/
F: include/uapi/linux/acrn.h
AD1889 ALSA SOUND DRIVER
L: linux-parisc@vger.kernel.org
S: Maintained
@ -1017,7 +1026,7 @@ F: Documentation/devicetree/bindings/mux/adi,adgs1408.txt
F: drivers/mux/adgs1408.c
ANALOG DEVICES INC ADIN DRIVER
M: Alexandru Ardelean <alexaundru.ardelean@analog.com>
M: Michael Hennerich <michael.hennerich@analog.com>
L: netdev@vger.kernel.org
S: Supported
W: http://ez.analog.com/community/linux-device-drivers
@ -1025,7 +1034,7 @@ F: Documentation/devicetree/bindings/net/adi,adin.yaml
F: drivers/net/phy/adin.c
ANALOG DEVICES INC ADIS DRIVER LIBRARY
M: Alexandru Ardelean <alexandru.ardelean@analog.com>
M: Nuno Sa <nuno.sa@analog.com>
L: linux-iio@vger.kernel.org
S: Supported
F: drivers/iio/imu/adis.c
@ -3731,6 +3740,13 @@ L: netdev@vger.kernel.org
S: Supported
F: drivers/net/ethernet/broadcom/tg3.*
BROADCOM VK DRIVER
M: Scott Branden <scott.branden@broadcom.com>
L: bcm-kernel-feedback-list@broadcom.com
S: Supported
F: drivers/misc/bcm-vk/
F: include/uapi/linux/misc/bcm_vk.h
BROCADE BFA FC SCSI DRIVER
M: Anil Gurumurthy <anil.gurumurthy@qlogic.com>
M: Sudarsana Kalluru <sudarsana.kalluru@qlogic.com>
@ -6950,9 +6966,10 @@ M: Wu Hao <hao.wu@intel.com>
R: Tom Rix <trix@redhat.com>
L: linux-fpga@vger.kernel.org
S: Maintained
F: Documentation/ABI/testing/sysfs-bus-dfl
F: Documentation/ABI/testing/sysfs-bus-dfl*
F: Documentation/fpga/dfl.rst
F: drivers/fpga/dfl*
F: include/linux/dfl.h
F: include/uapi/linux/fpga-dfl.h
FPGA MANAGER FRAMEWORK
@ -14686,9 +14703,11 @@ M: Stuart Yoder <stuyoder@gmail.com>
M: Laurentiu Tudor <laurentiu.tudor@nxp.com>
L: linux-kernel@vger.kernel.org
S: Maintained
F: Documentation/ABI/stable/sysfs-bus-fsl-mc
F: Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt
F: Documentation/networking/device_drivers/ethernet/freescale/dpaa2/overview.rst
F: drivers/bus/fsl-mc/
F: include/uapi/linux/fsl_mc.h
QT1010 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
@ -16731,6 +16750,7 @@ R: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
R: Sanyog Kale <sanyog.r.kale@intel.com>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Supported
T: git git://git.kernel.org/pub/scm/linux/kernel/git/vkoul/soundwire.git
F: Documentation/driver-api/soundwire/
F: drivers/soundwire/
F: include/linux/soundwire/

View File

@ -191,6 +191,7 @@
#define SYS_GCR_EL1 sys_reg(3, 0, 1, 0, 6)
#define SYS_ZCR_EL1 sys_reg(3, 0, 1, 2, 0)
#define SYS_TRFCR_EL1 sys_reg(3, 0, 1, 2, 1)
#define SYS_TTBR0_EL1 sys_reg(3, 0, 2, 0, 0)
#define SYS_TTBR1_EL1 sys_reg(3, 0, 2, 0, 1)
@ -475,6 +476,7 @@
#define SYS_SCTLR_EL2 sys_reg(3, 4, 1, 0, 0)
#define SYS_ZCR_EL2 sys_reg(3, 4, 1, 2, 0)
#define SYS_TRFCR_EL2 sys_reg(3, 4, 1, 2, 1)
#define SYS_DACR32_EL2 sys_reg(3, 4, 3, 0, 0)
#define SYS_SPSR_EL2 sys_reg(3, 4, 4, 0, 0)
#define SYS_ELR_EL2 sys_reg(3, 4, 4, 0, 1)
@ -833,6 +835,7 @@
#define ID_AA64MMFR2_CNP_SHIFT 0
/* id_aa64dfr0 */
#define ID_AA64DFR0_TRACE_FILT_SHIFT 40
#define ID_AA64DFR0_DOUBLELOCK_SHIFT 36
#define ID_AA64DFR0_PMSVER_SHIFT 32
#define ID_AA64DFR0_CTX_CMPS_SHIFT 28
@ -1013,6 +1016,14 @@
/* Safe value for MPIDR_EL1: Bit31:RES1, Bit30:U:0, Bit24:MT:0 */
#define SYS_MPIDR_SAFE_VAL (BIT(31))
#define TRFCR_ELx_TS_SHIFT 5
#define TRFCR_ELx_TS_VIRTUAL ((0x1UL) << TRFCR_ELx_TS_SHIFT)
#define TRFCR_ELx_TS_GUEST_PHYSICAL ((0x2UL) << TRFCR_ELx_TS_SHIFT)
#define TRFCR_ELx_TS_PHYSICAL ((0x3UL) << TRFCR_ELx_TS_SHIFT)
#define TRFCR_EL2_CX BIT(3)
#define TRFCR_ELx_ExTRE BIT(1)
#define TRFCR_ELx_E0TRE BIT(0)
#ifdef __ASSEMBLY__
.irp num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30

View File

@ -0,0 +1,78 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_X86_ACRN_H
#define _ASM_X86_ACRN_H
/*
* This CPUID returns feature bitmaps in EAX.
* Guest VM uses this to detect the appropriate feature bit.
*/
#define ACRN_CPUID_FEATURES 0x40000001
/* Bit 0 indicates whether guest VM is privileged */
#define ACRN_FEATURE_PRIVILEGED_VM BIT(0)
void acrn_setup_intr_handler(void (*handler)(void));
void acrn_remove_intr_handler(void);
static inline u32 acrn_cpuid_base(void)
{
if (boot_cpu_has(X86_FEATURE_HYPERVISOR))
return hypervisor_cpuid_base("ACRNACRNACRN", 0);
return 0;
}
/*
* Hypercalls for ACRN
*
* - VMCALL instruction is used to implement ACRN hypercalls.
* - ACRN hypercall ABI:
* - Hypercall number is passed in R8 register.
* - Up to 2 arguments are passed in RDI, RSI.
* - Return value will be placed in RAX.
*
* Because GCC doesn't support R8 register as direct register constraints, use
* supported constraint as input with a explicit MOV to R8 in beginning of asm.
*/
static inline long acrn_hypercall0(unsigned long hcall_id)
{
long result;
asm volatile("movl %1, %%r8d\n\t"
"vmcall\n\t"
: "=a" (result)
: "g" (hcall_id)
: "r8", "memory");
return result;
}
static inline long acrn_hypercall1(unsigned long hcall_id,
unsigned long param1)
{
long result;
asm volatile("movl %1, %%r8d\n\t"
"vmcall\n\t"
: "=a" (result)
: "g" (hcall_id), "D" (param1)
: "r8", "memory");
return result;
}
static inline long acrn_hypercall2(unsigned long hcall_id,
unsigned long param1,
unsigned long param2)
{
long result;
asm volatile("movl %1, %%r8d\n\t"
"vmcall\n\t"
: "=a" (result)
: "g" (hcall_id), "D" (param1), "S" (param2)
: "r8", "memory");
return result;
}
#endif /* _ASM_X86_ACRN_H */

View File

@ -10,6 +10,8 @@
*/
#include <linux/interrupt.h>
#include <asm/acrn.h>
#include <asm/apic.h>
#include <asm/cpufeatures.h>
#include <asm/desc.h>
@ -19,7 +21,7 @@
static u32 __init acrn_detect(void)
{
return hypervisor_cpuid_base("ACRNACRNACRN", 0);
return acrn_cpuid_base();
}
static void __init acrn_init_platform(void)
@ -55,6 +57,18 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_acrn_hv_callback)
set_irq_regs(old_regs);
}
void acrn_setup_intr_handler(void (*handler)(void))
{
acrn_intr_handler = handler;
}
EXPORT_SYMBOL_GPL(acrn_setup_intr_handler);
void acrn_remove_intr_handler(void)
{
acrn_intr_handler = NULL;
}
EXPORT_SYMBOL_GPL(acrn_remove_intr_handler);
const __initconst struct hypervisor_x86 x86_hyper_acrn = {
.name = "ACRN",
.detect = acrn_detect,

View File

@ -27,11 +27,11 @@ static const struct old_serial_port *serstate;
static int timeouts;
static int spk_serial_out(struct spk_synth *in_synth, const char ch);
static void spk_serial_send_xchar(char ch);
static void spk_serial_tiocmset(unsigned int set, unsigned int clear);
static unsigned char spk_serial_in(void);
static unsigned char spk_serial_in_nowait(void);
static void spk_serial_flush_buffer(void);
static void spk_serial_send_xchar(struct spk_synth *in_synth, char ch);
static void spk_serial_tiocmset(struct spk_synth *in_synth, unsigned int set, unsigned int clear);
static unsigned char spk_serial_in(struct spk_synth *in_synth);
static unsigned char spk_serial_in_nowait(struct spk_synth *in_synth);
static void spk_serial_flush_buffer(struct spk_synth *in_synth);
static int spk_serial_wait_for_xmitr(struct spk_synth *in_synth);
struct spk_io_ops spk_serial_io_ops = {
@ -150,7 +150,7 @@ static void start_serial_interrupt(int irq)
outb(1, speakup_info.port_tts + UART_FCR); /* Turn FIFO On */
}
static void spk_serial_send_xchar(char ch)
static void spk_serial_send_xchar(struct spk_synth *synth, char ch)
{
int timeout = SPK_XMITR_TIMEOUT;
@ -162,7 +162,7 @@ static void spk_serial_send_xchar(char ch)
outb(ch, speakup_info.port_tts);
}
static void spk_serial_tiocmset(unsigned int set, unsigned int clear)
static void spk_serial_tiocmset(struct spk_synth *in_synth, unsigned int set, unsigned int clear)
{
int old = inb(speakup_info.port_tts + UART_MCR);
@ -251,7 +251,7 @@ static int spk_serial_wait_for_xmitr(struct spk_synth *in_synth)
return 1;
}
static unsigned char spk_serial_in(void)
static unsigned char spk_serial_in(struct spk_synth *in_synth)
{
int tmout = SPK_SERIAL_TIMEOUT;
@ -265,7 +265,7 @@ static unsigned char spk_serial_in(void)
return inb_p(speakup_info.port_tts + UART_RX);
}
static unsigned char spk_serial_in_nowait(void)
static unsigned char spk_serial_in_nowait(struct spk_synth *in_synth)
{
unsigned char lsr;
@ -275,7 +275,7 @@ static unsigned char spk_serial_in_nowait(void)
return inb_p(speakup_info.port_tts + UART_RX);
}
static void spk_serial_flush_buffer(void)
static void spk_serial_flush_buffer(struct spk_synth *in_synth)
{
/* TODO: flush the UART 16550 buffer */
}
@ -307,7 +307,7 @@ const char *spk_serial_synth_immediate(struct spk_synth *synth,
}
EXPORT_SYMBOL_GPL(spk_serial_synth_immediate);
void spk_serial_release(void)
void spk_serial_release(struct spk_synth *synth)
{
spk_stop_serial_interrupt();
if (speakup_info.port_tts == 0)

View File

@ -25,7 +25,7 @@
#define PROCSPEECH '\r'
static int synth_probe(struct spk_synth *synth);
static void accent_release(void);
static void accent_release(struct spk_synth *synth);
static const char *synth_immediate(struct spk_synth *synth, const char *buf);
static void do_catch_up(struct spk_synth *synth);
static void synth_flush(struct spk_synth *synth);
@ -294,7 +294,7 @@ static int synth_probe(struct spk_synth *synth)
return 0;
}
static void accent_release(void)
static void accent_release(struct spk_synth *synth)
{
spk_stop_serial_interrupt();
if (speakup_info.port_tts)

View File

@ -163,8 +163,8 @@ static void do_catch_up(struct spk_synth *synth)
full_time_val = full_time->u.n.value;
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
if (!synth->io_ops->synth_out(synth, ch)) {
synth->io_ops->tiocmset(0, UART_MCR_RTS);
synth->io_ops->tiocmset(UART_MCR_RTS, 0);
synth->io_ops->tiocmset(synth, 0, UART_MCR_RTS);
synth->io_ops->tiocmset(synth, UART_MCR_RTS, 0);
schedule_timeout(msecs_to_jiffies(full_time_val));
continue;
}

View File

@ -119,8 +119,8 @@ static struct spk_synth synth_audptr = {
static void synth_flush(struct spk_synth *synth)
{
synth->io_ops->flush_buffer();
synth->io_ops->send_xchar(SYNTH_CLEAR);
synth->io_ops->flush_buffer(synth);
synth->io_ops->send_xchar(synth, SYNTH_CLEAR);
synth->io_ops->synth_out(synth, PROCSPEECH);
}
@ -130,11 +130,11 @@ static void synth_version(struct spk_synth *synth)
char synth_id[40] = "";
synth->synth_immediate(synth, "\x05[Q]");
synth_id[test] = synth->io_ops->synth_in();
synth_id[test] = synth->io_ops->synth_in(synth);
if (synth_id[test] == 'A') {
do {
/* read version string from synth */
synth_id[++test] = synth->io_ops->synth_in();
synth_id[++test] = synth->io_ops->synth_in(synth);
} while (synth_id[test] != '\n' && test < 32);
synth_id[++test] = 0x00;
}

View File

@ -218,7 +218,7 @@ static void do_catch_up(struct spk_synth *synth)
static void synth_flush(struct spk_synth *synth)
{
in_escape = 0;
synth->io_ops->flush_buffer();
synth->io_ops->flush_buffer(synth);
synth->synth_immediate(synth, "\033P;10z\033\\");
}

View File

@ -125,7 +125,7 @@ enum { PRIMARY_DIC = 0, USER_DIC, COMMAND_DIC, ABBREV_DIC };
#define SYNTH_IO_EXTENT 8
static int synth_probe(struct spk_synth *synth);
static void dtpc_release(void);
static void dtpc_release(struct spk_synth *synth);
static const char *synth_immediate(struct spk_synth *synth, const char *buf);
static void do_catch_up(struct spk_synth *synth);
static void synth_flush(struct spk_synth *synth);
@ -474,7 +474,7 @@ static int synth_probe(struct spk_synth *synth)
return 0;
}
static void dtpc_release(void)
static void dtpc_release(struct spk_synth *synth)
{
spk_stop_serial_interrupt();
if (speakup_info.port_tts)

View File

@ -78,6 +78,8 @@ static struct kobj_attribute direct_attribute =
__ATTR(direct, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute full_time_attribute =
__ATTR(full_time, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute flush_time_attribute =
__ATTR(flush_time, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute jiffy_delta_attribute =
__ATTR(jiffy_delta, 0644, spk_var_show, spk_var_store);
static struct kobj_attribute trigger_time_attribute =
@ -99,6 +101,7 @@ static struct attribute *synth_attrs[] = {
&delay_time_attribute.attr,
&direct_attribute.attr,
&full_time_attribute.attr,
&flush_time_attribute.attr,
&jiffy_delta_attribute.attr,
&trigger_time_attribute.attr,
NULL, /* need to NULL terminate the list of attributes */
@ -118,6 +121,7 @@ static struct spk_synth synth_dectlk = {
.trigger = 50,
.jiffies = 50,
.full = 40000,
.flush_time = 4000,
.dev_name = SYNTH_DEFAULT_DEV,
.startup = SYNTH_START,
.checkval = SYNTH_CHECK,
@ -200,18 +204,23 @@ static void do_catch_up(struct spk_synth *synth)
static u_char last = '\0';
unsigned long flags;
unsigned long jiff_max;
unsigned long timeout = msecs_to_jiffies(4000);
unsigned long timeout;
DEFINE_WAIT(wait);
struct var_t *jiffy_delta;
struct var_t *delay_time;
struct var_t *flush_time;
int jiffy_delta_val;
int delay_time_val;
int timeout_val;
jiffy_delta = spk_get_var(JIFFY);
delay_time = spk_get_var(DELAY);
flush_time = spk_get_var(FLUSH);
spin_lock_irqsave(&speakup_info.spinlock, flags);
jiffy_delta_val = jiffy_delta->u.n.value;
timeout_val = flush_time->u.n.value;
spin_unlock_irqrestore(&speakup_info.spinlock, flags);
timeout = msecs_to_jiffies(timeout_val);
jiff_max = jiffies + jiffy_delta_val;
while (!kthread_should_stop()) {
@ -289,7 +298,7 @@ static void synth_flush(struct spk_synth *synth)
synth->io_ops->synth_out(synth, ']');
in_escape = 0;
is_flushing = 1;
synth->io_ops->flush_buffer();
synth->io_ops->flush_buffer(synth);
synth->io_ops->synth_out(synth, SYNTH_CLEAR);
}

View File

@ -24,7 +24,7 @@
#define PROCSPEECH 0x00
static int synth_probe(struct spk_synth *synth);
static void dtlk_release(void);
static void dtlk_release(struct spk_synth *synth);
static const char *synth_immediate(struct spk_synth *synth, const char *buf);
static void do_catch_up(struct spk_synth *synth);
static void synth_flush(struct spk_synth *synth);
@ -365,7 +365,7 @@ static int synth_probe(struct spk_synth *synth)
return 0;
}
static void dtlk_release(void)
static void dtlk_release(struct spk_synth *synth)
{
spk_stop_serial_interrupt();
if (speakup_info.port_tts)

View File

@ -24,7 +24,7 @@
#define SYNTH_CLEAR 0x03
static int synth_probe(struct spk_synth *synth);
static void keynote_release(void);
static void keynote_release(struct spk_synth *synth);
static const char *synth_immediate(struct spk_synth *synth, const char *buf);
static void do_catch_up(struct spk_synth *synth);
static void synth_flush(struct spk_synth *synth);
@ -295,7 +295,7 @@ static int synth_probe(struct spk_synth *synth)
return 0;
}
static void keynote_release(void)
static void keynote_release(struct spk_synth *synth)
{
spk_stop_serial_interrupt();
if (synth_port)

View File

@ -132,7 +132,7 @@ static void synth_interrogate(struct spk_synth *synth)
synth->synth_immediate(synth, "\x18\x01?");
for (i = 0; i < 50; i++) {
buf[i] = synth->io_ops->synth_in();
buf[i] = synth->io_ops->synth_in(synth);
if (i > 2 && buf[i] == 0x7f)
break;
}

View File

@ -24,7 +24,7 @@
#define CLEAR_SYNTH 0x18
static int softsynth_probe(struct spk_synth *synth);
static void softsynth_release(void);
static void softsynth_release(struct spk_synth *synth);
static int softsynth_is_alive(struct spk_synth *synth);
static unsigned char get_index(struct spk_synth *synth);
@ -402,7 +402,7 @@ static int softsynth_probe(struct spk_synth *synth)
return 0;
}
static void softsynth_release(void)
static void softsynth_release(struct spk_synth *synth)
{
misc_deregister(&synth_device);
misc_deregister(&synthu_device);

View File

@ -117,8 +117,8 @@ static struct spk_synth synth_spkout = {
static void synth_flush(struct spk_synth *synth)
{
synth->io_ops->flush_buffer();
synth->io_ops->send_xchar(SYNTH_CLEAR);
synth->io_ops->flush_buffer(synth);
synth->io_ops->send_xchar(synth, SYNTH_CLEAR);
}
module_param_named(ser, synth_spkout.ser, int, 0444);

View File

@ -34,8 +34,8 @@
const struct old_serial_port *spk_serial_init(int index);
void spk_stop_serial_interrupt(void);
void spk_serial_release(void);
void spk_ttyio_release(void);
void spk_serial_release(struct spk_synth *synth);
void spk_ttyio_release(struct spk_synth *synth);
void spk_ttyio_register_ldisc(void);
void spk_ttyio_unregister_ldisc(void);

View File

@ -12,14 +12,15 @@ struct spk_ldisc_data {
char buf;
struct completion completion;
bool buf_free;
struct spk_synth *synth;
};
static struct spk_synth *spk_ttyio_synth;
static struct tty_struct *speakup_tty;
/* mutex to protect against speakup_tty disappearing from underneath us while
* we are using it. this can happen when the device physically unplugged,
* while in use. it also serialises access to speakup_tty.
/*
* This allows to catch within spk_ttyio_ldisc_open whether it is getting set
* on for a speakup-driven device.
*/
static struct tty_struct *speakup_tty;
/* This mutex serializes the use of such global speakup_tty variable */
static DEFINE_MUTEX(speakup_tty_mutex);
static int ser_to_dev(int ser, dev_t *dev_no)
@ -67,22 +68,20 @@ static int spk_ttyio_ldisc_open(struct tty_struct *tty)
static void spk_ttyio_ldisc_close(struct tty_struct *tty)
{
mutex_lock(&speakup_tty_mutex);
kfree(speakup_tty->disc_data);
speakup_tty = NULL;
mutex_unlock(&speakup_tty_mutex);
kfree(tty->disc_data);
}
static int spk_ttyio_receive_buf2(struct tty_struct *tty,
const unsigned char *cp, char *fp, int count)
{
struct spk_ldisc_data *ldisc_data = tty->disc_data;
struct spk_synth *synth = ldisc_data->synth;
if (spk_ttyio_synth->read_buff_add) {
if (synth->read_buff_add) {
int i;
for (i = 0; i < count; i++)
spk_ttyio_synth->read_buff_add(cp[i]);
synth->read_buff_add(cp[i]);
return count;
}
@ -114,11 +113,11 @@ static struct tty_ldisc_ops spk_ttyio_ldisc_ops = {
static int spk_ttyio_out(struct spk_synth *in_synth, const char ch);
static int spk_ttyio_out_unicode(struct spk_synth *in_synth, u16 ch);
static void spk_ttyio_send_xchar(char ch);
static void spk_ttyio_tiocmset(unsigned int set, unsigned int clear);
static unsigned char spk_ttyio_in(void);
static unsigned char spk_ttyio_in_nowait(void);
static void spk_ttyio_flush_buffer(void);
static void spk_ttyio_send_xchar(struct spk_synth *in_synth, char ch);
static void spk_ttyio_tiocmset(struct spk_synth *in_synth, unsigned int set, unsigned int clear);
static unsigned char spk_ttyio_in(struct spk_synth *in_synth);
static unsigned char spk_ttyio_in_nowait(struct spk_synth *in_synth);
static void spk_ttyio_flush_buffer(struct spk_synth *in_synth);
static int spk_ttyio_wait_for_xmitr(struct spk_synth *in_synth);
struct spk_io_ops spk_ttyio_ops = {
@ -187,13 +186,17 @@ static int spk_ttyio_initialise_ldisc(struct spk_synth *synth)
mutex_lock(&speakup_tty_mutex);
speakup_tty = tty;
ret = tty_set_ldisc(tty, N_SPEAKUP);
if (ret)
speakup_tty = NULL;
speakup_tty = NULL;
mutex_unlock(&speakup_tty_mutex);
if (!ret)
if (!ret) {
/* Success */
struct spk_ldisc_data *ldisc_data = tty->disc_data;
ldisc_data->synth = synth;
synth->dev = tty;
return 0;
}
pr_err("speakup: Failed to set N_SPEAKUP on tty\n");
@ -221,29 +224,30 @@ void spk_ttyio_unregister_ldisc(void)
static int spk_ttyio_out(struct spk_synth *in_synth, const char ch)
{
mutex_lock(&speakup_tty_mutex);
if (in_synth->alive && speakup_tty && speakup_tty->ops->write) {
int ret = speakup_tty->ops->write(speakup_tty, &ch, 1);
struct tty_struct *tty = in_synth->dev;
int ret;
mutex_unlock(&speakup_tty_mutex);
if (ret == 0)
/* No room */
return 0;
if (ret < 0) {
pr_warn("%s: I/O error, deactivating speakup\n",
in_synth->long_name);
/* No synth any more, so nobody will restart TTYs,
* and we thus need to do it ourselves. Now that there
* is no synth we can let application flood anyway
*/
in_synth->alive = 0;
speakup_start_ttys();
return 0;
}
if (!in_synth->alive || !tty->ops->write)
return 0;
ret = tty->ops->write(tty, &ch, 1);
if (ret == 0)
/* No room */
return 0;
if (ret > 0)
/* Success */
return 1;
}
mutex_unlock(&speakup_tty_mutex);
pr_warn("%s: I/O error, deactivating speakup\n",
in_synth->long_name);
/* No synth any more, so nobody will restart TTYs,
* and we thus need to do it ourselves. Now that there
* is no synth we can let application flood anyway
*/
in_synth->alive = 0;
speakup_start_ttys();
return 0;
}
@ -264,47 +268,20 @@ static int spk_ttyio_out_unicode(struct spk_synth *in_synth, u16 ch)
return ret;
}
static int check_tty(struct tty_struct *tty)
static void spk_ttyio_send_xchar(struct spk_synth *in_synth, char ch)
{
if (!tty) {
pr_warn("%s: I/O error, deactivating speakup\n",
spk_ttyio_synth->long_name);
/* No synth any more, so nobody will restart TTYs, and we thus
* need to do it ourselves. Now that there is no synth we can
* let application flood anyway
*/
spk_ttyio_synth->alive = 0;
speakup_start_ttys();
return 1;
}
struct tty_struct *tty = in_synth->dev;
return 0;
if (tty->ops->send_xchar)
tty->ops->send_xchar(tty, ch);
}
static void spk_ttyio_send_xchar(char ch)
static void spk_ttyio_tiocmset(struct spk_synth *in_synth, unsigned int set, unsigned int clear)
{
mutex_lock(&speakup_tty_mutex);
if (check_tty(speakup_tty)) {
mutex_unlock(&speakup_tty_mutex);
return;
}
struct tty_struct *tty = in_synth->dev;
if (speakup_tty->ops->send_xchar)
speakup_tty->ops->send_xchar(speakup_tty, ch);
mutex_unlock(&speakup_tty_mutex);
}
static void spk_ttyio_tiocmset(unsigned int set, unsigned int clear)
{
mutex_lock(&speakup_tty_mutex);
if (check_tty(speakup_tty)) {
mutex_unlock(&speakup_tty_mutex);
return;
}
if (speakup_tty->ops->tiocmset)
speakup_tty->ops->tiocmset(speakup_tty, set, clear);
mutex_unlock(&speakup_tty_mutex);
if (tty->ops->tiocmset)
tty->ops->tiocmset(tty, set, clear);
}
static int spk_ttyio_wait_for_xmitr(struct spk_synth *in_synth)
@ -312,9 +289,10 @@ static int spk_ttyio_wait_for_xmitr(struct spk_synth *in_synth)
return 1;
}
static unsigned char ttyio_in(int timeout)
static unsigned char ttyio_in(struct spk_synth *in_synth, int timeout)
{
struct spk_ldisc_data *ldisc_data = speakup_tty->disc_data;
struct tty_struct *tty = in_synth->dev;
struct spk_ldisc_data *ldisc_data = tty->disc_data;
char rv;
if (!timeout) {
@ -334,35 +312,29 @@ static unsigned char ttyio_in(int timeout)
mb();
ldisc_data->buf_free = true;
/* Let TTY push more characters */
tty_schedule_flip(speakup_tty->port);
tty_schedule_flip(tty->port);
return rv;
}
static unsigned char spk_ttyio_in(void)
static unsigned char spk_ttyio_in(struct spk_synth *in_synth)
{
return ttyio_in(SPK_SYNTH_TIMEOUT);
return ttyio_in(in_synth, SPK_SYNTH_TIMEOUT);
}
static unsigned char spk_ttyio_in_nowait(void)
static unsigned char spk_ttyio_in_nowait(struct spk_synth *in_synth)
{
u8 rv = ttyio_in(0);
u8 rv = ttyio_in(in_synth, 0);
return (rv == 0xff) ? 0 : rv;
}
static void spk_ttyio_flush_buffer(void)
static void spk_ttyio_flush_buffer(struct spk_synth *in_synth)
{
mutex_lock(&speakup_tty_mutex);
if (check_tty(speakup_tty)) {
mutex_unlock(&speakup_tty_mutex);
return;
}
struct tty_struct *tty = in_synth->dev;
if (speakup_tty->ops->flush_buffer)
speakup_tty->ops->flush_buffer(speakup_tty);
mutex_unlock(&speakup_tty_mutex);
if (tty->ops->flush_buffer)
tty->ops->flush_buffer(tty);
}
int spk_ttyio_synth_probe(struct spk_synth *synth)
@ -373,37 +345,38 @@ int spk_ttyio_synth_probe(struct spk_synth *synth)
return rv;
synth->alive = 1;
spk_ttyio_synth = synth;
return 0;
}
EXPORT_SYMBOL_GPL(spk_ttyio_synth_probe);
void spk_ttyio_release(void)
void spk_ttyio_release(struct spk_synth *in_synth)
{
if (!speakup_tty)
return;
struct tty_struct *tty = in_synth->dev;
tty_lock(speakup_tty);
tty_lock(tty);
if (speakup_tty->ops->close)
speakup_tty->ops->close(speakup_tty, NULL);
if (tty->ops->close)
tty->ops->close(tty, NULL);
tty_ldisc_flush(speakup_tty);
tty_unlock(speakup_tty);
tty_kclose(speakup_tty);
tty_ldisc_flush(tty);
tty_unlock(tty);
tty_kclose(tty);
in_synth->dev = NULL;
}
EXPORT_SYMBOL_GPL(spk_ttyio_release);
const char *spk_ttyio_synth_immediate(struct spk_synth *synth, const char *buff)
const char *spk_ttyio_synth_immediate(struct spk_synth *in_synth, const char *buff)
{
struct tty_struct *tty = in_synth->dev;
u_char ch;
while ((ch = *buff)) {
if (ch == '\n')
ch = synth->procspeech;
if (tty_write_room(speakup_tty) < 1 ||
!synth->io_ops->synth_out(synth, ch))
ch = in_synth->procspeech;
if (tty_write_room(tty) < 1 ||
!in_synth->io_ops->synth_out(in_synth, ch))
return buff;
buff++;
}

View File

@ -48,7 +48,7 @@ enum var_id_t {
ATTRIB_BLEEP, BLEEPS,
RATE, PITCH, VOL, TONE, PUNCT, VOICE, FREQUENCY, LANG,
DIRECT, PAUSE,
CAPS_START, CAPS_STOP, CHARTAB, INFLECTION,
CAPS_START, CAPS_STOP, CHARTAB, INFLECTION, FLUSH,
MAXVARS
};
@ -157,11 +157,11 @@ struct spk_synth;
struct spk_io_ops {
int (*synth_out)(struct spk_synth *synth, const char ch);
int (*synth_out_unicode)(struct spk_synth *synth, u16 ch);
void (*send_xchar)(char ch);
void (*tiocmset)(unsigned int set, unsigned int clear);
unsigned char (*synth_in)(void);
unsigned char (*synth_in_nowait)(void);
void (*flush_buffer)(void);
void (*send_xchar)(struct spk_synth *synth, char ch);
void (*tiocmset)(struct spk_synth *synth, unsigned int set, unsigned int clear);
unsigned char (*synth_in)(struct spk_synth *synth);
unsigned char (*synth_in_nowait)(struct spk_synth *synth);
void (*flush_buffer)(struct spk_synth *synth);
int (*wait_for_xmitr)(struct spk_synth *synth);
};
@ -178,6 +178,7 @@ struct spk_synth {
int trigger;
int jiffies;
int full;
int flush_time;
int ser;
char *dev_name;
short flags;
@ -188,7 +189,7 @@ struct spk_synth {
int *default_vol;
struct spk_io_ops *io_ops;
int (*probe)(struct spk_synth *synth);
void (*release)(void);
void (*release)(struct spk_synth *synth);
const char *(*synth_immediate)(struct spk_synth *synth,
const char *buff);
void (*catch_up)(struct spk_synth *synth);
@ -200,6 +201,8 @@ struct spk_synth {
struct synth_indexing indexing;
int alive;
struct attribute_group attributes;
void *dev;
};
/*

View File

@ -137,14 +137,14 @@ EXPORT_SYMBOL_GPL(spk_do_catch_up_unicode);
void spk_synth_flush(struct spk_synth *synth)
{
synth->io_ops->flush_buffer();
synth->io_ops->flush_buffer(synth);
synth->io_ops->synth_out(synth, synth->clear);
}
EXPORT_SYMBOL_GPL(spk_synth_flush);
unsigned char spk_synth_get_index(struct spk_synth *synth)
{
return synth->io_ops->synth_in_nowait();
return synth->io_ops->synth_in_nowait(synth);
}
EXPORT_SYMBOL_GPL(spk_synth_get_index);
@ -348,6 +348,7 @@ struct var_t synth_time_vars[] = {
{ TRIGGER, .u.n = {NULL, 20, 10, 2000, 0, 0, NULL } },
{ JIFFY, .u.n = {NULL, 50, 20, 200, 0, 0, NULL } },
{ FULL, .u.n = {NULL, 400, 200, 60000, 0, 0, NULL } },
{ FLUSH, .u.n = {NULL, 4000, 100, 4000, 0, 0, NULL } },
V_LAST_VAR
};
@ -408,6 +409,8 @@ static int do_synth_init(struct spk_synth *in_synth)
synth_time_vars[2].u.n.default_val = synth->jiffies;
synth_time_vars[3].u.n.value =
synth_time_vars[3].u.n.default_val = synth->full;
synth_time_vars[4].u.n.value =
synth_time_vars[4].u.n.default_val = synth->flush_time;
synth_printf("%s", synth->init);
for (var = synth->vars;
(var->var_id >= 0) && (var->var_id < MAXVARS); var++)
@ -440,7 +443,7 @@ void synth_release(void)
sysfs_remove_group(speakup_kobj, &synth->attributes);
for (var = synth->vars; var->var_id != MAXVARS; var++)
speakup_unregister_var(var->var_id);
synth->release();
synth->release(synth);
synth = NULL;
}

View File

@ -23,6 +23,7 @@ static struct st_var_header var_headers[] = {
{ "trigger_time", TRIGGER, VAR_TIME, NULL, NULL },
{ "jiffy_delta", JIFFY, VAR_TIME, NULL, NULL },
{ "full_time", FULL, VAR_TIME, NULL, NULL },
{ "flush_time", FLUSH, VAR_TIME, NULL, NULL },
{ "spell_delay", SPELL_DELAY, VAR_NUM, &spk_spell_delay, NULL },
{ "bleeps", BLEEPS, VAR_NUM, &spk_bleeps, NULL },
{ "attrib_bleep", ATTRIB_BLEEP, VAR_NUM, &spk_attrib_bleep, NULL },

View File

@ -15,11 +15,11 @@ static int regmap_sdw_mbq_write(void *context, unsigned int reg, unsigned int va
struct sdw_slave *slave = dev_to_sdw_dev(dev);
int ret;
ret = sdw_write(slave, SDW_SDCA_MBQ_CTL(reg), (val >> 8) & 0xff);
ret = sdw_write_no_pm(slave, SDW_SDCA_MBQ_CTL(reg), (val >> 8) & 0xff);
if (ret < 0)
return ret;
return sdw_write(slave, reg, val & 0xff);
return sdw_write_no_pm(slave, reg, val & 0xff);
}
static int regmap_sdw_mbq_read(void *context, unsigned int reg, unsigned int *val)
@ -29,11 +29,11 @@ static int regmap_sdw_mbq_read(void *context, unsigned int reg, unsigned int *va
int read0;
int read1;
read0 = sdw_read(slave, reg);
read0 = sdw_read_no_pm(slave, reg);
if (read0 < 0)
return read0;
read1 = sdw_read(slave, SDW_SDCA_MBQ_CTL(reg));
read1 = sdw_read_no_pm(slave, SDW_SDCA_MBQ_CTL(reg));
if (read1 < 0)
return read1;
@ -98,4 +98,4 @@ struct regmap *__devm_regmap_init_sdw_mbq(struct sdw_slave *sdw,
EXPORT_SYMBOL_GPL(__devm_regmap_init_sdw_mbq);
MODULE_DESCRIPTION("Regmap SoundWire MBQ Module");
MODULE_LICENSE("GPL v2");
MODULE_LICENSE("GPL");

View File

@ -13,7 +13,7 @@ static int regmap_sdw_write(void *context, unsigned int reg, unsigned int val)
struct device *dev = context;
struct sdw_slave *slave = dev_to_sdw_dev(dev);
return sdw_write(slave, reg, val);
return sdw_write_no_pm(slave, reg, val);
}
static int regmap_sdw_read(void *context, unsigned int reg, unsigned int *val)
@ -22,7 +22,7 @@ static int regmap_sdw_read(void *context, unsigned int reg, unsigned int *val)
struct sdw_slave *slave = dev_to_sdw_dev(dev);
int read;
read = sdw_read(slave, reg);
read = sdw_read_no_pm(slave, reg);
if (read < 0)
return read;

View File

@ -14,3 +14,10 @@ config FSL_MC_BUS
architecture. The fsl-mc bus driver handles discovery of
DPAA2 objects (which are represented as Linux devices) and
binding objects to drivers.
config FSL_MC_UAPI_SUPPORT
bool "Management Complex (MC) userspace support"
depends on FSL_MC_BUS
help
Provides userspace support for interrogating, creating, destroying or
configuring DPAA2 objects exported by the Management Complex.

View File

@ -16,3 +16,6 @@ mc-bus-driver-objs := fsl-mc-bus.o \
fsl-mc-allocator.o \
fsl-mc-msi.o \
dpmcp.o
# MC userspace support
obj-$(CONFIG_FSL_MC_UAPI_SUPPORT) += fsl-mc-uapi.o

View File

@ -237,8 +237,8 @@ static void dprc_add_new_devices(struct fsl_mc_device *mc_bus_dev,
* populated before they can get allocation requests from probe callbacks
* of the device drivers for the non-allocatable devices.
*/
static int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev,
bool alloc_interrupts)
int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev,
bool alloc_interrupts)
{
int num_child_objects;
int dprc_get_obj_failures;
@ -458,8 +458,9 @@ out:
/*
* Disable and clear interrupt for a given DPRC object
*/
static int disable_dprc_irq(struct fsl_mc_device *mc_dev)
int disable_dprc_irq(struct fsl_mc_device *mc_dev)
{
struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev);
int error;
struct fsl_mc_io *mc_io = mc_dev->mc_io;
@ -496,9 +497,18 @@ static int disable_dprc_irq(struct fsl_mc_device *mc_dev)
return error;
}
mc_bus->irq_enabled = 0;
return 0;
}
int get_dprc_irq_state(struct fsl_mc_device *mc_dev)
{
struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev);
return mc_bus->irq_enabled;
}
static int register_dprc_irq_handler(struct fsl_mc_device *mc_dev)
{
int error;
@ -525,8 +535,9 @@ static int register_dprc_irq_handler(struct fsl_mc_device *mc_dev)
return 0;
}
static int enable_dprc_irq(struct fsl_mc_device *mc_dev)
int enable_dprc_irq(struct fsl_mc_device *mc_dev)
{
struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev);
int error;
/*
@ -554,6 +565,8 @@ static int enable_dprc_irq(struct fsl_mc_device *mc_dev)
return error;
}
mc_bus->irq_enabled = 1;
return 0;
}
@ -603,6 +616,7 @@ int dprc_setup(struct fsl_mc_device *mc_dev)
struct irq_domain *mc_msi_domain;
bool mc_io_created = false;
bool msi_domain_set = false;
bool uapi_created = false;
u16 major_ver, minor_ver;
size_t region_size;
int error;
@ -635,6 +649,11 @@ int dprc_setup(struct fsl_mc_device *mc_dev)
return error;
mc_io_created = true;
} else {
error = fsl_mc_uapi_create_device_file(mc_bus);
if (error < 0)
return -EPROBE_DEFER;
uapi_created = true;
}
mc_msi_domain = fsl_mc_find_msi_domain(&mc_dev->dev);
@ -692,6 +711,9 @@ error_cleanup_msi_domain:
mc_dev->mc_io = NULL;
}
if (uapi_created)
fsl_mc_uapi_remove_device_file(mc_bus);
return error;
}
EXPORT_SYMBOL_GPL(dprc_setup);
@ -763,6 +785,7 @@ static void dprc_teardown_irq(struct fsl_mc_device *mc_dev)
int dprc_cleanup(struct fsl_mc_device *mc_dev)
{
struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev);
int error;
/* this function should be called only for DPRCs, it
@ -793,6 +816,8 @@ int dprc_cleanup(struct fsl_mc_device *mc_dev)
if (!fsl_mc_is_root_dprc(&mc_dev->dev)) {
fsl_destroy_mc_io(mc_dev->mc_io);
mc_dev->mc_io = NULL;
} else {
fsl_mc_uapi_remove_device_file(mc_bus);
}
return 0;

View File

@ -41,7 +41,7 @@ struct fsl_mc {
struct fsl_mc_device *root_mc_bus_dev;
u8 num_translation_ranges;
struct fsl_mc_addr_translation_range *translation_ranges;
void *fsl_mc_regs;
void __iomem *fsl_mc_regs;
};
/**
@ -208,12 +208,108 @@ static struct attribute *fsl_mc_dev_attrs[] = {
ATTRIBUTE_GROUPS(fsl_mc_dev);
static int scan_fsl_mc_bus(struct device *dev, void *data)
{
struct fsl_mc_device *root_mc_dev;
struct fsl_mc_bus *root_mc_bus;
if (!fsl_mc_is_root_dprc(dev))
goto exit;
root_mc_dev = to_fsl_mc_device(dev);
root_mc_bus = to_fsl_mc_bus(root_mc_dev);
mutex_lock(&root_mc_bus->scan_mutex);
dprc_scan_objects(root_mc_dev, NULL);
mutex_unlock(&root_mc_bus->scan_mutex);
exit:
return 0;
}
static ssize_t rescan_store(struct bus_type *bus,
const char *buf, size_t count)
{
unsigned long val;
if (kstrtoul(buf, 0, &val) < 0)
return -EINVAL;
if (val)
bus_for_each_dev(bus, NULL, NULL, scan_fsl_mc_bus);
return count;
}
static BUS_ATTR_WO(rescan);
static int fsl_mc_bus_set_autorescan(struct device *dev, void *data)
{
struct fsl_mc_device *root_mc_dev;
unsigned long val;
char *buf = data;
if (!fsl_mc_is_root_dprc(dev))
goto exit;
root_mc_dev = to_fsl_mc_device(dev);
if (kstrtoul(buf, 0, &val) < 0)
return -EINVAL;
if (val)
enable_dprc_irq(root_mc_dev);
else
disable_dprc_irq(root_mc_dev);
exit:
return 0;
}
static int fsl_mc_bus_get_autorescan(struct device *dev, void *data)
{
struct fsl_mc_device *root_mc_dev;
char *buf = data;
if (!fsl_mc_is_root_dprc(dev))
goto exit;
root_mc_dev = to_fsl_mc_device(dev);
sprintf(buf, "%d\n", get_dprc_irq_state(root_mc_dev));
exit:
return 0;
}
static ssize_t autorescan_store(struct bus_type *bus,
const char *buf, size_t count)
{
bus_for_each_dev(bus, NULL, (void *)buf, fsl_mc_bus_set_autorescan);
return count;
}
static ssize_t autorescan_show(struct bus_type *bus, char *buf)
{
bus_for_each_dev(bus, NULL, (void *)buf, fsl_mc_bus_get_autorescan);
return strlen(buf);
}
static BUS_ATTR_RW(autorescan);
static struct attribute *fsl_mc_bus_attrs[] = {
&bus_attr_rescan.attr,
&bus_attr_autorescan.attr,
NULL,
};
ATTRIBUTE_GROUPS(fsl_mc_bus);
struct bus_type fsl_mc_bus_type = {
.name = "fsl-mc",
.match = fsl_mc_bus_match,
.uevent = fsl_mc_bus_uevent,
.dma_configure = fsl_mc_dma_configure,
.dev_groups = fsl_mc_dev_groups,
.bus_groups = fsl_mc_bus_groups,
};
EXPORT_SYMBOL_GPL(fsl_mc_bus_type);
@ -292,6 +388,11 @@ struct device_type fsl_mc_bus_dpdmai_type = {
};
EXPORT_SYMBOL_GPL(fsl_mc_bus_dpdmai_type);
struct device_type fsl_mc_bus_dpdbg_type = {
.name = "fsl_mc_bus_dpdbg"
};
EXPORT_SYMBOL_GPL(fsl_mc_bus_dpdbg_type);
static struct device_type *fsl_mc_get_device_type(const char *type)
{
static const struct {
@ -313,6 +414,7 @@ static struct device_type *fsl_mc_get_device_type(const char *type)
{ &fsl_mc_bus_dpaiop_type, "dpaiop" },
{ &fsl_mc_bus_dpci_type, "dpci" },
{ &fsl_mc_bus_dpdmai_type, "dpdmai" },
{ &fsl_mc_bus_dpdbg_type, "dpdbg" },
{ NULL, NULL }
};
int i;

View File

@ -10,6 +10,8 @@
#include <linux/fsl/mc.h>
#include <linux/mutex.h>
#include <linux/ioctl.h>
#include <linux/miscdevice.h>
/*
* Data Path Management Complex (DPMNG) General API
@ -542,6 +544,22 @@ struct fsl_mc_resource_pool {
struct fsl_mc_bus *mc_bus;
};
/**
* struct fsl_mc_uapi - information associated with a device file
* @misc: struct miscdevice linked to the root dprc
* @device: newly created device in /dev
* @mutex: mutex lock to serialize the open/release operations
* @local_instance_in_use: local MC I/O instance in use or not
* @static_mc_io: pointer to the static MC I/O object
*/
struct fsl_mc_uapi {
struct miscdevice misc;
struct device *device;
struct mutex mutex; /* serialize open/release operations */
u32 local_instance_in_use;
struct fsl_mc_io *static_mc_io;
};
/**
* struct fsl_mc_bus - logical bus that corresponds to a physical DPRC
* @mc_dev: fsl-mc device for the bus device itself.
@ -551,6 +569,7 @@ struct fsl_mc_resource_pool {
* @irq_resources: Pointer to array of IRQ objects for the IRQ pool
* @scan_mutex: Serializes bus scanning
* @dprc_attr: DPRC attributes
* @uapi_misc: struct that abstracts the interaction with userspace
*/
struct fsl_mc_bus {
struct fsl_mc_device mc_dev;
@ -558,6 +577,8 @@ struct fsl_mc_bus {
struct fsl_mc_device_irq *irq_resources;
struct mutex scan_mutex; /* serializes bus scanning */
struct dprc_attributes dprc_attr;
struct fsl_mc_uapi uapi_misc;
int irq_enabled;
};
#define to_fsl_mc_bus(_mc_dev) \
@ -574,6 +595,9 @@ int __init dprc_driver_init(void);
void dprc_driver_exit(void);
int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev,
bool alloc_interrupts);
int __init fsl_mc_allocator_driver_init(void);
void fsl_mc_allocator_driver_exit(void);
@ -612,4 +636,29 @@ void fsl_mc_get_root_dprc(struct device *dev,
struct fsl_mc_device *fsl_mc_device_lookup(struct fsl_mc_obj_desc *obj_desc,
struct fsl_mc_device *mc_bus_dev);
u16 mc_cmd_hdr_read_cmdid(struct fsl_mc_command *cmd);
#ifdef CONFIG_FSL_MC_UAPI_SUPPORT
int fsl_mc_uapi_create_device_file(struct fsl_mc_bus *mc_bus);
void fsl_mc_uapi_remove_device_file(struct fsl_mc_bus *mc_bus);
#else
static inline int fsl_mc_uapi_create_device_file(struct fsl_mc_bus *mc_bus)
{
return 0;
}
static inline void fsl_mc_uapi_remove_device_file(struct fsl_mc_bus *mc_bus)
{
}
#endif
int disable_dprc_irq(struct fsl_mc_device *mc_dev);
int enable_dprc_irq(struct fsl_mc_device *mc_dev);
int get_dprc_irq_state(struct fsl_mc_device *mc_dev);
#endif /* _FSL_MC_PRIVATE_H_ */

View File

@ -0,0 +1,597 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Management Complex (MC) userspace support
*
* Copyright 2021 NXP
*
*/
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
#include "fsl-mc-private.h"
struct uapi_priv_data {
struct fsl_mc_uapi *uapi;
struct fsl_mc_io *mc_io;
};
struct fsl_mc_cmd_desc {
u16 cmdid_value;
u16 cmdid_mask;
int size;
bool token;
int flags;
};
#define FSL_MC_CHECK_MODULE_ID BIT(0)
#define FSL_MC_CAP_NET_ADMIN_NEEDED BIT(1)
enum fsl_mc_cmd_index {
DPDBG_DUMP = 0,
DPDBG_SET,
DPRC_GET_CONTAINER_ID,
DPRC_CREATE_CONT,
DPRC_DESTROY_CONT,
DPRC_ASSIGN,
DPRC_UNASSIGN,
DPRC_GET_OBJ_COUNT,
DPRC_GET_OBJ,
DPRC_GET_RES_COUNT,
DPRC_GET_RES_IDS,
DPRC_SET_OBJ_LABEL,
DPRC_SET_LOCKED,
DPRC_CONNECT,
DPRC_DISCONNECT,
DPRC_GET_POOL,
DPRC_GET_POOL_COUNT,
DPRC_GET_CONNECTION,
DPCI_GET_LINK_STATE,
DPCI_GET_PEER_ATTR,
DPAIOP_GET_SL_VERSION,
DPAIOP_GET_STATE,
DPMNG_GET_VERSION,
DPSECI_GET_TX_QUEUE,
DPMAC_GET_COUNTER,
DPMAC_GET_MAC_ADDR,
DPNI_SET_PRIM_MAC,
DPNI_GET_PRIM_MAC,
DPNI_GET_STATISTICS,
DPNI_GET_LINK_STATE,
DPNI_GET_MAX_FRAME_LENGTH,
DPSW_GET_TAILDROP,
DPSW_SET_TAILDROP,
DPSW_IF_GET_COUNTER,
DPSW_IF_GET_MAX_FRAME_LENGTH,
DPDMUX_GET_COUNTER,
DPDMUX_IF_GET_MAX_FRAME_LENGTH,
GET_ATTR,
GET_IRQ_MASK,
GET_IRQ_STATUS,
CLOSE,
OPEN,
GET_API_VERSION,
DESTROY,
CREATE,
};
static struct fsl_mc_cmd_desc fsl_mc_accepted_cmds[] = {
[DPDBG_DUMP] = {
.cmdid_value = 0x1300,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 28,
},
[DPDBG_SET] = {
.cmdid_value = 0x1400,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 28,
},
[DPRC_GET_CONTAINER_ID] = {
.cmdid_value = 0x8300,
.cmdid_mask = 0xFFF0,
.token = false,
.size = 8,
},
[DPRC_CREATE_CONT] = {
.cmdid_value = 0x1510,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 40,
.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
},
[DPRC_DESTROY_CONT] = {
.cmdid_value = 0x1520,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 12,
.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
},
[DPRC_ASSIGN] = {
.cmdid_value = 0x1570,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 40,
.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
},
[DPRC_UNASSIGN] = {
.cmdid_value = 0x1580,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 40,
.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
},
[DPRC_GET_OBJ_COUNT] = {
.cmdid_value = 0x1590,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 16,
},
[DPRC_GET_OBJ] = {
.cmdid_value = 0x15A0,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 12,
},
[DPRC_GET_RES_COUNT] = {
.cmdid_value = 0x15B0,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 32,
},
[DPRC_GET_RES_IDS] = {
.cmdid_value = 0x15C0,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 40,
},
[DPRC_SET_OBJ_LABEL] = {
.cmdid_value = 0x1610,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 48,
.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
},
[DPRC_SET_LOCKED] = {
.cmdid_value = 0x16B0,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 16,
.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
},
[DPRC_CONNECT] = {
.cmdid_value = 0x1670,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 56,
.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
},
[DPRC_DISCONNECT] = {
.cmdid_value = 0x1680,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 32,
.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
},
[DPRC_GET_POOL] = {
.cmdid_value = 0x1690,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 12,
},
[DPRC_GET_POOL_COUNT] = {
.cmdid_value = 0x16A0,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 8,
},
[DPRC_GET_CONNECTION] = {
.cmdid_value = 0x16C0,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 32,
},
[DPCI_GET_LINK_STATE] = {
.cmdid_value = 0x0E10,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 8,
},
[DPCI_GET_PEER_ATTR] = {
.cmdid_value = 0x0E20,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 8,
},
[DPAIOP_GET_SL_VERSION] = {
.cmdid_value = 0x2820,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 8,
},
[DPAIOP_GET_STATE] = {
.cmdid_value = 0x2830,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 8,
},
[DPMNG_GET_VERSION] = {
.cmdid_value = 0x8310,
.cmdid_mask = 0xFFF0,
.token = false,
.size = 8,
},
[DPSECI_GET_TX_QUEUE] = {
.cmdid_value = 0x1970,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 14,
},
[DPMAC_GET_COUNTER] = {
.cmdid_value = 0x0c40,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 9,
},
[DPMAC_GET_MAC_ADDR] = {
.cmdid_value = 0x0c50,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 8,
},
[DPNI_SET_PRIM_MAC] = {
.cmdid_value = 0x2240,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 16,
.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
},
[DPNI_GET_PRIM_MAC] = {
.cmdid_value = 0x2250,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 8,
},
[DPNI_GET_STATISTICS] = {
.cmdid_value = 0x25D0,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 10,
},
[DPNI_GET_LINK_STATE] = {
.cmdid_value = 0x2150,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 8,
},
[DPNI_GET_MAX_FRAME_LENGTH] = {
.cmdid_value = 0x2170,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 8,
},
[DPSW_GET_TAILDROP] = {
.cmdid_value = 0x0A80,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 14,
},
[DPSW_SET_TAILDROP] = {
.cmdid_value = 0x0A90,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 24,
.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
},
[DPSW_IF_GET_COUNTER] = {
.cmdid_value = 0x0340,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 11,
},
[DPSW_IF_GET_MAX_FRAME_LENGTH] = {
.cmdid_value = 0x0450,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 10,
},
[DPDMUX_GET_COUNTER] = {
.cmdid_value = 0x0b20,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 11,
},
[DPDMUX_IF_GET_MAX_FRAME_LENGTH] = {
.cmdid_value = 0x0a20,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 10,
},
[GET_ATTR] = {
.cmdid_value = 0x0040,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 8,
},
[GET_IRQ_MASK] = {
.cmdid_value = 0x0150,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 13,
},
[GET_IRQ_STATUS] = {
.cmdid_value = 0x0160,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 13,
},
[CLOSE] = {
.cmdid_value = 0x8000,
.cmdid_mask = 0xFFF0,
.token = true,
.size = 8,
},
/* Common commands amongst all types of objects. Must be checked last. */
[OPEN] = {
.cmdid_value = 0x8000,
.cmdid_mask = 0xFC00,
.token = false,
.size = 12,
.flags = FSL_MC_CHECK_MODULE_ID,
},
[GET_API_VERSION] = {
.cmdid_value = 0xA000,
.cmdid_mask = 0xFC00,
.token = false,
.size = 8,
.flags = FSL_MC_CHECK_MODULE_ID,
},
[DESTROY] = {
.cmdid_value = 0x9800,
.cmdid_mask = 0xFC00,
.token = true,
.size = 12,
.flags = FSL_MC_CHECK_MODULE_ID | FSL_MC_CAP_NET_ADMIN_NEEDED,
},
[CREATE] = {
.cmdid_value = 0x9000,
.cmdid_mask = 0xFC00,
.token = true,
.size = 64,
.flags = FSL_MC_CHECK_MODULE_ID | FSL_MC_CAP_NET_ADMIN_NEEDED,
},
};
#define FSL_MC_NUM_ACCEPTED_CMDS ARRAY_SIZE(fsl_mc_accepted_cmds)
#define FSL_MC_MAX_MODULE_ID 0x10
static int fsl_mc_command_check(struct fsl_mc_device *mc_dev,
struct fsl_mc_command *mc_cmd)
{
struct fsl_mc_cmd_desc *desc = NULL;
int mc_cmd_max_size, i;
bool token_provided;
u16 cmdid, module_id;
char *mc_cmd_end;
char sum = 0;
/* Check if this is an accepted MC command */
cmdid = mc_cmd_hdr_read_cmdid(mc_cmd);
for (i = 0; i < FSL_MC_NUM_ACCEPTED_CMDS; i++) {
desc = &fsl_mc_accepted_cmds[i];
if ((cmdid & desc->cmdid_mask) == desc->cmdid_value)
break;
}
if (i == FSL_MC_NUM_ACCEPTED_CMDS) {
dev_err(&mc_dev->dev, "MC command 0x%04x: cmdid not accepted\n", cmdid);
return -EACCES;
}
/* Check if the size of the command is honored. Anything beyond the
* last valid byte of the command should be zeroed.
*/
mc_cmd_max_size = sizeof(*mc_cmd);
mc_cmd_end = ((char *)mc_cmd) + desc->size;
for (i = desc->size; i < mc_cmd_max_size; i++)
sum |= *mc_cmd_end++;
if (sum) {
dev_err(&mc_dev->dev, "MC command 0x%04x: garbage beyond max size of %d bytes!\n",
cmdid, desc->size);
return -EACCES;
}
/* Some MC commands request a token to be passed so that object
* identification is possible. Check if the token passed in the command
* is as expected.
*/
token_provided = mc_cmd_hdr_read_token(mc_cmd) ? true : false;
if (token_provided != desc->token) {
dev_err(&mc_dev->dev, "MC command 0x%04x: token 0x%04x is invalid!\n",
cmdid, mc_cmd_hdr_read_token(mc_cmd));
return -EACCES;
}
/* If needed, check if the module ID passed is valid */
if (desc->flags & FSL_MC_CHECK_MODULE_ID) {
/* The module ID is represented by bits [4:9] from the cmdid */
module_id = (cmdid & GENMASK(9, 4)) >> 4;
if (module_id == 0 || module_id > FSL_MC_MAX_MODULE_ID) {
dev_err(&mc_dev->dev, "MC command 0x%04x: unknown module ID 0x%x\n",
cmdid, module_id);
return -EACCES;
}
}
/* Some commands alter how hardware resources are managed. For these
* commands, check for CAP_NET_ADMIN.
*/
if (desc->flags & FSL_MC_CAP_NET_ADMIN_NEEDED) {
if (!capable(CAP_NET_ADMIN)) {
dev_err(&mc_dev->dev, "MC command 0x%04x: needs CAP_NET_ADMIN!\n",
cmdid);
return -EPERM;
}
}
return 0;
}
static int fsl_mc_uapi_send_command(struct fsl_mc_device *mc_dev, unsigned long arg,
struct fsl_mc_io *mc_io)
{
struct fsl_mc_command mc_cmd;
int error;
error = copy_from_user(&mc_cmd, (void __user *)arg, sizeof(mc_cmd));
if (error)
return -EFAULT;
error = fsl_mc_command_check(mc_dev, &mc_cmd);
if (error)
return error;
error = mc_send_command(mc_io, &mc_cmd);
if (error)
return error;
error = copy_to_user((void __user *)arg, &mc_cmd, sizeof(mc_cmd));
if (error)
return -EFAULT;
return 0;
}
static int fsl_mc_uapi_dev_open(struct inode *inode, struct file *filep)
{
struct fsl_mc_device *root_mc_device;
struct uapi_priv_data *priv_data;
struct fsl_mc_io *dynamic_mc_io;
struct fsl_mc_uapi *mc_uapi;
struct fsl_mc_bus *mc_bus;
int error;
priv_data = kzalloc(sizeof(*priv_data), GFP_KERNEL);
if (!priv_data)
return -ENOMEM;
mc_uapi = container_of(filep->private_data, struct fsl_mc_uapi, misc);
mc_bus = container_of(mc_uapi, struct fsl_mc_bus, uapi_misc);
root_mc_device = &mc_bus->mc_dev;
mutex_lock(&mc_uapi->mutex);
if (!mc_uapi->local_instance_in_use) {
priv_data->mc_io = mc_uapi->static_mc_io;
mc_uapi->local_instance_in_use = 1;
} else {
error = fsl_mc_portal_allocate(root_mc_device, 0,
&dynamic_mc_io);
if (error) {
dev_dbg(&root_mc_device->dev,
"Could not allocate MC portal\n");
goto error_portal_allocate;
}
priv_data->mc_io = dynamic_mc_io;
}
priv_data->uapi = mc_uapi;
filep->private_data = priv_data;
mutex_unlock(&mc_uapi->mutex);
return 0;
error_portal_allocate:
mutex_unlock(&mc_uapi->mutex);
kfree(priv_data);
return error;
}
static int fsl_mc_uapi_dev_release(struct inode *inode, struct file *filep)
{
struct uapi_priv_data *priv_data;
struct fsl_mc_uapi *mc_uapi;
struct fsl_mc_io *mc_io;
priv_data = filep->private_data;
mc_uapi = priv_data->uapi;
mc_io = priv_data->mc_io;
mutex_lock(&mc_uapi->mutex);
if (mc_io == mc_uapi->static_mc_io)
mc_uapi->local_instance_in_use = 0;
else
fsl_mc_portal_free(mc_io);
kfree(filep->private_data);
filep->private_data = NULL;
mutex_unlock(&mc_uapi->mutex);
return 0;
}
static long fsl_mc_uapi_dev_ioctl(struct file *file,
unsigned int cmd,
unsigned long arg)
{
struct uapi_priv_data *priv_data = file->private_data;
struct fsl_mc_device *root_mc_device;
struct fsl_mc_bus *mc_bus;
int error;
mc_bus = container_of(priv_data->uapi, struct fsl_mc_bus, uapi_misc);
root_mc_device = &mc_bus->mc_dev;
switch (cmd) {
case FSL_MC_SEND_MC_COMMAND:
error = fsl_mc_uapi_send_command(root_mc_device, arg, priv_data->mc_io);
break;
default:
dev_dbg(&root_mc_device->dev, "unexpected ioctl call number\n");
error = -EINVAL;
}
return error;
}
static const struct file_operations fsl_mc_uapi_dev_fops = {
.owner = THIS_MODULE,
.open = fsl_mc_uapi_dev_open,
.release = fsl_mc_uapi_dev_release,
.unlocked_ioctl = fsl_mc_uapi_dev_ioctl,
};
int fsl_mc_uapi_create_device_file(struct fsl_mc_bus *mc_bus)
{
struct fsl_mc_device *mc_dev = &mc_bus->mc_dev;
struct fsl_mc_uapi *mc_uapi = &mc_bus->uapi_misc;
int error;
mc_uapi->misc.minor = MISC_DYNAMIC_MINOR;
mc_uapi->misc.name = dev_name(&mc_dev->dev);
mc_uapi->misc.fops = &fsl_mc_uapi_dev_fops;
error = misc_register(&mc_uapi->misc);
if (error)
return error;
mc_uapi->static_mc_io = mc_bus->mc_dev.mc_io;
mutex_init(&mc_uapi->mutex);
return 0;
}
void fsl_mc_uapi_remove_device_file(struct fsl_mc_bus *mc_bus)
{
misc_deregister(&mc_bus->uapi_misc.misc);
}

View File

@ -35,7 +35,7 @@ static enum mc_cmd_status mc_cmd_hdr_read_status(struct fsl_mc_command *cmd)
return (enum mc_cmd_status)hdr->status;
}
static u16 mc_cmd_hdr_read_cmdid(struct fsl_mc_command *cmd)
u16 mc_cmd_hdr_read_cmdid(struct fsl_mc_command *cmd)
{
struct mc_cmd_header *hdr = (struct mc_cmd_header *)&cmd->header;
u16 cmd_id = le16_to_cpu(hdr->cmd_id);

View File

@ -151,12 +151,17 @@ int mhi_init_irq_setup(struct mhi_controller *mhi_cntrl)
{
struct mhi_event *mhi_event = mhi_cntrl->mhi_event;
struct device *dev = &mhi_cntrl->mhi_dev->dev;
unsigned long irq_flags = IRQF_SHARED | IRQF_NO_SUSPEND;
int i, ret;
/* if controller driver has set irq_flags, use it */
if (mhi_cntrl->irq_flags)
irq_flags = mhi_cntrl->irq_flags;
/* Setup BHI_INTVEC IRQ */
ret = request_threaded_irq(mhi_cntrl->irq[0], mhi_intvec_handler,
mhi_intvec_threaded_handler,
IRQF_SHARED | IRQF_NO_SUSPEND,
irq_flags,
"bhi", mhi_cntrl);
if (ret)
return ret;
@ -174,7 +179,7 @@ int mhi_init_irq_setup(struct mhi_controller *mhi_cntrl)
ret = request_irq(mhi_cntrl->irq[mhi_event->irq],
mhi_irq_handler,
IRQF_SHARED | IRQF_NO_SUSPEND,
irq_flags,
"mhi", mhi_event);
if (ret) {
dev_err(dev, "Error requesting irq:%d for ev:%d\n",
@ -552,6 +557,9 @@ void mhi_deinit_chan_ctxt(struct mhi_controller *mhi_cntrl,
tre_ring = &mhi_chan->tre_ring;
chan_ctxt = &mhi_cntrl->mhi_ctxt->chan_ctxt[mhi_chan->chan];
if (!chan_ctxt->rbase) /* Already uninitialized */
return;
mhi_free_coherent(mhi_cntrl, tre_ring->alloc_size,
tre_ring->pre_aligned, tre_ring->dma_handle);
vfree(buf_ring->base);

View File

@ -111,7 +111,14 @@ void mhi_ring_chan_db(struct mhi_controller *mhi_cntrl,
dma_addr_t db;
db = ring->iommu_base + (ring->wp - ring->base);
/*
* Writes to the new ring element must be visible to the hardware
* before letting h/w know there is new element to fetch.
*/
dma_wmb();
*ring->ctxt_wp = db;
mhi_chan->db_cfg.process_db(mhi_cntrl, &mhi_chan->db_cfg,
ring->db_addr, db);
}
@ -135,6 +142,19 @@ enum mhi_state mhi_get_mhi_state(struct mhi_controller *mhi_cntrl)
}
EXPORT_SYMBOL_GPL(mhi_get_mhi_state);
void mhi_soc_reset(struct mhi_controller *mhi_cntrl)
{
if (mhi_cntrl->reset) {
mhi_cntrl->reset(mhi_cntrl);
return;
}
/* Generic MHI SoC reset */
mhi_write_reg(mhi_cntrl, mhi_cntrl->regs, MHI_SOC_RESET_REQ_OFFSET,
MHI_SOC_RESET_REQ);
}
EXPORT_SYMBOL_GPL(mhi_soc_reset);
int mhi_map_single_no_bb(struct mhi_controller *mhi_cntrl,
struct mhi_buf_info *buf_info)
{
@ -959,118 +979,88 @@ static bool mhi_is_ring_full(struct mhi_controller *mhi_cntrl,
return (tmp == ring->rp);
}
int mhi_queue_skb(struct mhi_device *mhi_dev, enum dma_data_direction dir,
struct sk_buff *skb, size_t len, enum mhi_flags mflags)
static int mhi_queue(struct mhi_device *mhi_dev, struct mhi_buf_info *buf_info,
enum dma_data_direction dir, enum mhi_flags mflags)
{
struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl;
struct mhi_chan *mhi_chan = (dir == DMA_TO_DEVICE) ? mhi_dev->ul_chan :
mhi_dev->dl_chan;
struct mhi_ring *tre_ring = &mhi_chan->tre_ring;
struct mhi_buf_info buf_info = { };
unsigned long flags;
int ret;
/* If MHI host pre-allocates buffers then client drivers cannot queue */
if (mhi_chan->pre_alloc)
return -EINVAL;
if (mhi_is_ring_full(mhi_cntrl, tre_ring))
return -ENOMEM;
read_lock_bh(&mhi_cntrl->pm_lock);
if (unlikely(MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state))) {
read_unlock_bh(&mhi_cntrl->pm_lock);
if (unlikely(MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)))
return -EIO;
read_lock_irqsave(&mhi_cntrl->pm_lock, flags);
ret = mhi_is_ring_full(mhi_cntrl, tre_ring);
if (unlikely(ret)) {
ret = -ENOMEM;
goto exit_unlock;
}
/* we're in M3 or transitioning to M3 */
ret = mhi_gen_tre(mhi_cntrl, mhi_chan, buf_info, mflags);
if (unlikely(ret))
goto exit_unlock;
/* trigger M3 exit if necessary */
if (MHI_PM_IN_SUSPEND_STATE(mhi_cntrl->pm_state))
mhi_trigger_resume(mhi_cntrl);
/* Toggle wake to exit out of M2 */
/* Assert dev_wake (to exit/prevent M1/M2)*/
mhi_cntrl->wake_toggle(mhi_cntrl);
if (mhi_chan->dir == DMA_TO_DEVICE)
atomic_inc(&mhi_cntrl->pending_pkts);
if (unlikely(!MHI_DB_ACCESS_VALID(mhi_cntrl))) {
ret = -EIO;
goto exit_unlock;
}
mhi_ring_chan_db(mhi_cntrl, mhi_chan);
exit_unlock:
read_unlock_irqrestore(&mhi_cntrl->pm_lock, flags);
return ret;
}
int mhi_queue_skb(struct mhi_device *mhi_dev, enum dma_data_direction dir,
struct sk_buff *skb, size_t len, enum mhi_flags mflags)
{
struct mhi_chan *mhi_chan = (dir == DMA_TO_DEVICE) ? mhi_dev->ul_chan :
mhi_dev->dl_chan;
struct mhi_buf_info buf_info = { };
buf_info.v_addr = skb->data;
buf_info.cb_buf = skb;
buf_info.len = len;
ret = mhi_gen_tre(mhi_cntrl, mhi_chan, &buf_info, mflags);
if (unlikely(ret)) {
read_unlock_bh(&mhi_cntrl->pm_lock);
return ret;
}
if (unlikely(mhi_chan->pre_alloc))
return -EINVAL;
if (mhi_chan->dir == DMA_TO_DEVICE)
atomic_inc(&mhi_cntrl->pending_pkts);
if (likely(MHI_DB_ACCESS_VALID(mhi_cntrl))) {
read_lock_bh(&mhi_chan->lock);
mhi_ring_chan_db(mhi_cntrl, mhi_chan);
read_unlock_bh(&mhi_chan->lock);
}
read_unlock_bh(&mhi_cntrl->pm_lock);
return 0;
return mhi_queue(mhi_dev, &buf_info, dir, mflags);
}
EXPORT_SYMBOL_GPL(mhi_queue_skb);
int mhi_queue_dma(struct mhi_device *mhi_dev, enum dma_data_direction dir,
struct mhi_buf *mhi_buf, size_t len, enum mhi_flags mflags)
{
struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl;
struct mhi_chan *mhi_chan = (dir == DMA_TO_DEVICE) ? mhi_dev->ul_chan :
mhi_dev->dl_chan;
struct device *dev = &mhi_cntrl->mhi_dev->dev;
struct mhi_ring *tre_ring = &mhi_chan->tre_ring;
struct mhi_buf_info buf_info = { };
int ret;
/* If MHI host pre-allocates buffers then client drivers cannot queue */
if (mhi_chan->pre_alloc)
return -EINVAL;
if (mhi_is_ring_full(mhi_cntrl, tre_ring))
return -ENOMEM;
read_lock_bh(&mhi_cntrl->pm_lock);
if (unlikely(MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state))) {
dev_err(dev, "MHI is not in activate state, PM state: %s\n",
to_mhi_pm_state_str(mhi_cntrl->pm_state));
read_unlock_bh(&mhi_cntrl->pm_lock);
return -EIO;
}
/* we're in M3 or transitioning to M3 */
if (MHI_PM_IN_SUSPEND_STATE(mhi_cntrl->pm_state))
mhi_trigger_resume(mhi_cntrl);
/* Toggle wake to exit out of M2 */
mhi_cntrl->wake_toggle(mhi_cntrl);
buf_info.p_addr = mhi_buf->dma_addr;
buf_info.cb_buf = mhi_buf;
buf_info.pre_mapped = true;
buf_info.len = len;
ret = mhi_gen_tre(mhi_cntrl, mhi_chan, &buf_info, mflags);
if (unlikely(ret)) {
read_unlock_bh(&mhi_cntrl->pm_lock);
return ret;
}
if (unlikely(mhi_chan->pre_alloc))
return -EINVAL;
if (mhi_chan->dir == DMA_TO_DEVICE)
atomic_inc(&mhi_cntrl->pending_pkts);
if (likely(MHI_DB_ACCESS_VALID(mhi_cntrl))) {
read_lock_bh(&mhi_chan->lock);
mhi_ring_chan_db(mhi_cntrl, mhi_chan);
read_unlock_bh(&mhi_chan->lock);
}
read_unlock_bh(&mhi_cntrl->pm_lock);
return 0;
return mhi_queue(mhi_dev, &buf_info, dir, mflags);
}
EXPORT_SYMBOL_GPL(mhi_queue_dma);
@ -1124,57 +1114,13 @@ int mhi_gen_tre(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan,
int mhi_queue_buf(struct mhi_device *mhi_dev, enum dma_data_direction dir,
void *buf, size_t len, enum mhi_flags mflags)
{
struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl;
struct mhi_chan *mhi_chan = (dir == DMA_TO_DEVICE) ? mhi_dev->ul_chan :
mhi_dev->dl_chan;
struct mhi_ring *tre_ring;
struct mhi_buf_info buf_info = { };
unsigned long flags;
int ret;
/*
* this check here only as a guard, it's always
* possible mhi can enter error while executing rest of function,
* which is not fatal so we do not need to hold pm_lock
*/
if (unlikely(MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)))
return -EIO;
tre_ring = &mhi_chan->tre_ring;
if (mhi_is_ring_full(mhi_cntrl, tre_ring))
return -ENOMEM;
buf_info.v_addr = buf;
buf_info.cb_buf = buf;
buf_info.len = len;
ret = mhi_gen_tre(mhi_cntrl, mhi_chan, &buf_info, mflags);
if (unlikely(ret))
return ret;
read_lock_irqsave(&mhi_cntrl->pm_lock, flags);
/* we're in M3 or transitioning to M3 */
if (MHI_PM_IN_SUSPEND_STATE(mhi_cntrl->pm_state))
mhi_trigger_resume(mhi_cntrl);
/* Toggle wake to exit out of M2 */
mhi_cntrl->wake_toggle(mhi_cntrl);
if (mhi_chan->dir == DMA_TO_DEVICE)
atomic_inc(&mhi_cntrl->pending_pkts);
if (likely(MHI_DB_ACCESS_VALID(mhi_cntrl))) {
unsigned long flags;
read_lock_irqsave(&mhi_chan->lock, flags);
mhi_ring_chan_db(mhi_cntrl, mhi_chan);
read_unlock_irqrestore(&mhi_chan->lock, flags);
}
read_unlock_irqrestore(&mhi_cntrl->pm_lock, flags);
return 0;
return mhi_queue(mhi_dev, &buf_info, dir, mflags);
}
EXPORT_SYMBOL_GPL(mhi_queue_buf);

View File

@ -8,13 +8,21 @@
* Copyright (C) 2020 Linaro Ltd <loic.poulain@linaro.org>
*/
#include <linux/aer.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/mhi.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
#define MHI_PCI_DEFAULT_BAR_NUM 0
#define MHI_POST_RESET_DELAY_MS 500
#define HEALTH_CHECK_PERIOD (HZ * 2)
/**
* struct mhi_pci_dev_info - MHI PCI device specific information
* @config: MHI controller configuration
@ -76,6 +84,36 @@ struct mhi_pci_dev_info {
.offload_channel = false, \
}
#define MHI_CHANNEL_CONFIG_HW_UL(ch_num, ch_name, el_count, ev_ring) \
{ \
.num = ch_num, \
.name = ch_name, \
.num_elements = el_count, \
.event_ring = ev_ring, \
.dir = DMA_TO_DEVICE, \
.ee_mask = BIT(MHI_EE_AMSS), \
.pollcfg = 0, \
.doorbell = MHI_DB_BRST_ENABLE, \
.lpm_notify = false, \
.offload_channel = false, \
.doorbell_mode_switch = true, \
} \
#define MHI_CHANNEL_CONFIG_HW_DL(ch_num, ch_name, el_count, ev_ring) \
{ \
.num = ch_num, \
.name = ch_name, \
.num_elements = el_count, \
.event_ring = ev_ring, \
.dir = DMA_FROM_DEVICE, \
.ee_mask = BIT(MHI_EE_AMSS), \
.pollcfg = 0, \
.doorbell = MHI_DB_BRST_ENABLE, \
.lpm_notify = false, \
.offload_channel = false, \
.doorbell_mode_switch = true, \
}
#define MHI_EVENT_CONFIG_DATA(ev_ring) \
{ \
.num_elements = 128, \
@ -91,8 +129,8 @@ struct mhi_pci_dev_info {
#define MHI_EVENT_CONFIG_HW_DATA(ev_ring, ch_num) \
{ \
.num_elements = 128, \
.irq_moderation_ms = 5, \
.num_elements = 2048, \
.irq_moderation_ms = 1, \
.irq = (ev_ring) + 1, \
.priority = 1, \
.mode = MHI_DB_BRST_DISABLE, \
@ -104,27 +142,31 @@ struct mhi_pci_dev_info {
}
static const struct mhi_channel_config modem_qcom_v1_mhi_channels[] = {
MHI_CHANNEL_CONFIG_UL(4, "DIAG", 16, 1),
MHI_CHANNEL_CONFIG_DL(5, "DIAG", 16, 1),
MHI_CHANNEL_CONFIG_UL(12, "MBIM", 4, 0),
MHI_CHANNEL_CONFIG_DL(13, "MBIM", 4, 0),
MHI_CHANNEL_CONFIG_UL(14, "QMI", 4, 0),
MHI_CHANNEL_CONFIG_DL(15, "QMI", 4, 0),
MHI_CHANNEL_CONFIG_UL(20, "IPCR", 8, 0),
MHI_CHANNEL_CONFIG_DL(21, "IPCR", 8, 0),
MHI_CHANNEL_CONFIG_UL(100, "IP_HW0", 128, 1),
MHI_CHANNEL_CONFIG_DL(101, "IP_HW0", 128, 2),
MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0", 128, 2),
MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0", 128, 3),
};
static const struct mhi_event_config modem_qcom_v1_mhi_events[] = {
static struct mhi_event_config modem_qcom_v1_mhi_events[] = {
/* first ring is control+data ring */
MHI_EVENT_CONFIG_CTRL(0),
/* DIAG dedicated event ring */
MHI_EVENT_CONFIG_DATA(1),
/* Hardware channels request dedicated hardware event rings */
MHI_EVENT_CONFIG_HW_DATA(1, 100),
MHI_EVENT_CONFIG_HW_DATA(2, 101)
MHI_EVENT_CONFIG_HW_DATA(2, 100),
MHI_EVENT_CONFIG_HW_DATA(3, 101)
};
static const struct mhi_controller_config modem_qcom_v1_mhiv_config = {
static struct mhi_controller_config modem_qcom_v1_mhiv_config = {
.max_channels = 128,
.timeout_ms = 5000,
.timeout_ms = 8000,
.num_channels = ARRAY_SIZE(modem_qcom_v1_mhi_channels),
.ch_cfg = modem_qcom_v1_mhi_channels,
.num_events = ARRAY_SIZE(modem_qcom_v1_mhi_events),
@ -147,6 +189,18 @@ static const struct pci_device_id mhi_pci_id_table[] = {
};
MODULE_DEVICE_TABLE(pci, mhi_pci_id_table);
enum mhi_pci_device_status {
MHI_PCI_DEV_STARTED,
};
struct mhi_pci_device {
struct mhi_controller mhi_cntrl;
struct pci_saved_state *pci_state;
struct work_struct recovery_work;
struct timer_list health_check_timer;
unsigned long status;
};
static int mhi_pci_read_reg(struct mhi_controller *mhi_cntrl,
void __iomem *addr, u32 *out)
{
@ -163,7 +217,31 @@ static void mhi_pci_write_reg(struct mhi_controller *mhi_cntrl,
static void mhi_pci_status_cb(struct mhi_controller *mhi_cntrl,
enum mhi_callback cb)
{
struct pci_dev *pdev = to_pci_dev(mhi_cntrl->cntrl_dev);
/* Nothing to do for now */
switch (cb) {
case MHI_CB_FATAL_ERROR:
case MHI_CB_SYS_ERROR:
dev_warn(&pdev->dev, "firmware crashed (%u)\n", cb);
break;
default:
break;
}
}
static bool mhi_pci_is_alive(struct mhi_controller *mhi_cntrl)
{
struct pci_dev *pdev = to_pci_dev(mhi_cntrl->cntrl_dev);
u16 vendor = 0;
if (pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor))
return false;
if (vendor == (u16) ~0 || vendor == 0)
return false;
return true;
}
static int mhi_pci_claim(struct mhi_controller *mhi_cntrl,
@ -227,8 +305,12 @@ static int mhi_pci_get_irqs(struct mhi_controller *mhi_cntrl,
}
if (nr_vectors < mhi_cntrl->nr_irqs) {
dev_warn(&pdev->dev, "Not enough MSI vectors (%d/%d), use shared MSI\n",
nr_vectors, mhi_cntrl_config->num_events);
dev_warn(&pdev->dev, "using shared MSI\n");
/* Patch msi vectors, use only one (shared) */
for (i = 0; i < mhi_cntrl_config->num_events; i++)
mhi_cntrl_config->event_cfg[i].irq = 0;
mhi_cntrl->nr_irqs = 1;
}
irq = devm_kcalloc(&pdev->dev, mhi_cntrl->nr_irqs, sizeof(int), GFP_KERNEL);
@ -257,20 +339,89 @@ static void mhi_pci_runtime_put(struct mhi_controller *mhi_cntrl)
/* no PM for now */
}
static void mhi_pci_recovery_work(struct work_struct *work)
{
struct mhi_pci_device *mhi_pdev = container_of(work, struct mhi_pci_device,
recovery_work);
struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl;
struct pci_dev *pdev = to_pci_dev(mhi_cntrl->cntrl_dev);
int err;
dev_warn(&pdev->dev, "device recovery started\n");
del_timer(&mhi_pdev->health_check_timer);
/* Clean up MHI state */
if (test_and_clear_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status)) {
mhi_power_down(mhi_cntrl, false);
mhi_unprepare_after_power_down(mhi_cntrl);
}
/* Check if we can recover without full reset */
pci_set_power_state(pdev, PCI_D0);
pci_load_saved_state(pdev, mhi_pdev->pci_state);
pci_restore_state(pdev);
if (!mhi_pci_is_alive(mhi_cntrl))
goto err_try_reset;
err = mhi_prepare_for_power_up(mhi_cntrl);
if (err)
goto err_try_reset;
err = mhi_sync_power_up(mhi_cntrl);
if (err)
goto err_unprepare;
dev_dbg(&pdev->dev, "Recovery completed\n");
set_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status);
mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD);
return;
err_unprepare:
mhi_unprepare_after_power_down(mhi_cntrl);
err_try_reset:
if (pci_reset_function(pdev))
dev_err(&pdev->dev, "Recovery failed\n");
}
static void health_check(struct timer_list *t)
{
struct mhi_pci_device *mhi_pdev = from_timer(mhi_pdev, t, health_check_timer);
struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl;
if (!mhi_pci_is_alive(mhi_cntrl)) {
dev_err(mhi_cntrl->cntrl_dev, "Device died\n");
queue_work(system_long_wq, &mhi_pdev->recovery_work);
return;
}
/* reschedule in two seconds */
mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD);
}
static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
const struct mhi_pci_dev_info *info = (struct mhi_pci_dev_info *) id->driver_data;
const struct mhi_controller_config *mhi_cntrl_config;
struct mhi_pci_device *mhi_pdev;
struct mhi_controller *mhi_cntrl;
int err;
dev_dbg(&pdev->dev, "MHI PCI device found: %s\n", info->name);
mhi_cntrl = mhi_alloc_controller();
if (!mhi_cntrl)
/* mhi_pdev.mhi_cntrl must be zero-initialized */
mhi_pdev = devm_kzalloc(&pdev->dev, sizeof(*mhi_pdev), GFP_KERNEL);
if (!mhi_pdev)
return -ENOMEM;
INIT_WORK(&mhi_pdev->recovery_work, mhi_pci_recovery_work);
timer_setup(&mhi_pdev->health_check_timer, health_check, 0);
mhi_cntrl_config = info->config;
mhi_cntrl = &mhi_pdev->mhi_cntrl;
mhi_cntrl->cntrl_dev = &pdev->dev;
mhi_cntrl->iova_start = 0;
mhi_cntrl->iova_stop = (dma_addr_t)DMA_BIT_MASK(info->dma_data_width);
@ -285,17 +436,23 @@ static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
err = mhi_pci_claim(mhi_cntrl, info->bar_num, DMA_BIT_MASK(info->dma_data_width));
if (err)
goto err_release;
return err;
err = mhi_pci_get_irqs(mhi_cntrl, mhi_cntrl_config);
if (err)
goto err_release;
return err;
pci_set_drvdata(pdev, mhi_cntrl);
pci_set_drvdata(pdev, mhi_pdev);
/* Have stored pci confspace at hand for restore in sudden PCI error */
pci_save_state(pdev);
mhi_pdev->pci_state = pci_store_saved_state(pdev);
pci_enable_pcie_error_reporting(pdev);
err = mhi_register_controller(mhi_cntrl, mhi_cntrl_config);
if (err)
goto err_release;
return err;
/* MHI bus does not power up the controller by default */
err = mhi_prepare_for_power_up(mhi_cntrl);
@ -310,33 +467,209 @@ static int mhi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto err_unprepare;
}
set_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status);
/* start health check */
mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD);
return 0;
err_unprepare:
mhi_unprepare_after_power_down(mhi_cntrl);
err_unregister:
mhi_unregister_controller(mhi_cntrl);
err_release:
mhi_free_controller(mhi_cntrl);
return err;
}
static void mhi_pci_remove(struct pci_dev *pdev)
{
struct mhi_controller *mhi_cntrl = pci_get_drvdata(pdev);
struct mhi_pci_device *mhi_pdev = pci_get_drvdata(pdev);
struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl;
del_timer(&mhi_pdev->health_check_timer);
cancel_work_sync(&mhi_pdev->recovery_work);
if (test_and_clear_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status)) {
mhi_power_down(mhi_cntrl, true);
mhi_unprepare_after_power_down(mhi_cntrl);
}
mhi_power_down(mhi_cntrl, true);
mhi_unprepare_after_power_down(mhi_cntrl);
mhi_unregister_controller(mhi_cntrl);
mhi_free_controller(mhi_cntrl);
}
static void mhi_pci_reset_prepare(struct pci_dev *pdev)
{
struct mhi_pci_device *mhi_pdev = pci_get_drvdata(pdev);
struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl;
dev_info(&pdev->dev, "reset\n");
del_timer(&mhi_pdev->health_check_timer);
/* Clean up MHI state */
if (test_and_clear_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status)) {
mhi_power_down(mhi_cntrl, false);
mhi_unprepare_after_power_down(mhi_cntrl);
}
/* cause internal device reset */
mhi_soc_reset(mhi_cntrl);
/* Be sure device reset has been executed */
msleep(MHI_POST_RESET_DELAY_MS);
}
static void mhi_pci_reset_done(struct pci_dev *pdev)
{
struct mhi_pci_device *mhi_pdev = pci_get_drvdata(pdev);
struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl;
int err;
/* Restore initial known working PCI state */
pci_load_saved_state(pdev, mhi_pdev->pci_state);
pci_restore_state(pdev);
/* Is device status available ? */
if (!mhi_pci_is_alive(mhi_cntrl)) {
dev_err(&pdev->dev, "reset failed\n");
return;
}
err = mhi_prepare_for_power_up(mhi_cntrl);
if (err) {
dev_err(&pdev->dev, "failed to prepare MHI controller\n");
return;
}
err = mhi_sync_power_up(mhi_cntrl);
if (err) {
dev_err(&pdev->dev, "failed to power up MHI controller\n");
mhi_unprepare_after_power_down(mhi_cntrl);
return;
}
set_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status);
mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD);
}
static pci_ers_result_t mhi_pci_error_detected(struct pci_dev *pdev,
pci_channel_state_t state)
{
struct mhi_pci_device *mhi_pdev = pci_get_drvdata(pdev);
struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl;
dev_err(&pdev->dev, "PCI error detected, state = %u\n", state);
if (state == pci_channel_io_perm_failure)
return PCI_ERS_RESULT_DISCONNECT;
/* Clean up MHI state */
if (test_and_clear_bit(MHI_PCI_DEV_STARTED, &mhi_pdev->status)) {
mhi_power_down(mhi_cntrl, false);
mhi_unprepare_after_power_down(mhi_cntrl);
} else {
/* Nothing to do */
return PCI_ERS_RESULT_RECOVERED;
}
pci_disable_device(pdev);
return PCI_ERS_RESULT_NEED_RESET;
}
static pci_ers_result_t mhi_pci_slot_reset(struct pci_dev *pdev)
{
if (pci_enable_device(pdev)) {
dev_err(&pdev->dev, "Cannot re-enable PCI device after reset.\n");
return PCI_ERS_RESULT_DISCONNECT;
}
return PCI_ERS_RESULT_RECOVERED;
}
static void mhi_pci_io_resume(struct pci_dev *pdev)
{
struct mhi_pci_device *mhi_pdev = pci_get_drvdata(pdev);
dev_err(&pdev->dev, "PCI slot reset done\n");
queue_work(system_long_wq, &mhi_pdev->recovery_work);
}
static const struct pci_error_handlers mhi_pci_err_handler = {
.error_detected = mhi_pci_error_detected,
.slot_reset = mhi_pci_slot_reset,
.resume = mhi_pci_io_resume,
.reset_prepare = mhi_pci_reset_prepare,
.reset_done = mhi_pci_reset_done,
};
static int __maybe_unused mhi_pci_suspend(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct mhi_pci_device *mhi_pdev = dev_get_drvdata(dev);
struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl;
del_timer(&mhi_pdev->health_check_timer);
cancel_work_sync(&mhi_pdev->recovery_work);
/* Transition to M3 state */
mhi_pm_suspend(mhi_cntrl);
pci_save_state(pdev);
pci_disable_device(pdev);
pci_wake_from_d3(pdev, true);
pci_set_power_state(pdev, PCI_D3hot);
return 0;
}
static int __maybe_unused mhi_pci_resume(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct mhi_pci_device *mhi_pdev = dev_get_drvdata(dev);
struct mhi_controller *mhi_cntrl = &mhi_pdev->mhi_cntrl;
int err;
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
pci_set_master(pdev);
err = pci_enable_device(pdev);
if (err)
goto err_recovery;
/* Exit M3, transition to M0 state */
err = mhi_pm_resume(mhi_cntrl);
if (err) {
dev_err(&pdev->dev, "failed to resume device: %d\n", err);
goto err_recovery;
}
/* Resume health check */
mod_timer(&mhi_pdev->health_check_timer, jiffies + HEALTH_CHECK_PERIOD);
return 0;
err_recovery:
/* The device may have loose power or crashed, try recovering it */
queue_work(system_long_wq, &mhi_pdev->recovery_work);
return err;
}
static const struct dev_pm_ops mhi_pci_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(mhi_pci_suspend, mhi_pci_resume)
};
static struct pci_driver mhi_pci_driver = {
.name = "mhi-pci-generic",
.id_table = mhi_pci_id_table,
.probe = mhi_pci_probe,
.remove = mhi_pci_remove
.remove = mhi_pci_remove,
.err_handler = &mhi_pci_err_handler,
.driver.pm = &mhi_pci_pm_ops
};
module_pci_driver(mhi_pci_driver);

View File

@ -1959,7 +1959,7 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
return -EPERM;
if (crng_init < 2)
return -ENODATA;
crng_reseed(&primary_crng, NULL);
crng_reseed(&primary_crng, &input_pool);
crng_global_init_time = jiffies - 1;
return 0;
default:

View File

@ -192,7 +192,9 @@ static int fw_unit_remove(struct device *dev)
struct fw_driver *driver =
container_of(dev->driver, struct fw_driver, driver);
return driver->remove(fw_unit(dev)), 0;
driver->remove(fw_unit(dev));
return 0;
}
static int get_modalias(struct fw_unit *unit, char *buffer, size_t buffer_size)

View File

@ -46,14 +46,13 @@ static int coreboot_bus_probe(struct device *dev)
static int coreboot_bus_remove(struct device *dev)
{
int ret = 0;
struct coreboot_device *device = CB_DEV(dev);
struct coreboot_driver *driver = CB_DRV(dev->driver);
if (driver->remove)
ret = driver->remove(device);
driver->remove(device);
return ret;
return 0;
}
static struct bus_type coreboot_bus_type = {

View File

@ -72,7 +72,7 @@ struct coreboot_device {
/* A driver for handling devices described in coreboot tables. */
struct coreboot_driver {
int (*probe)(struct coreboot_device *);
int (*remove)(struct coreboot_device *);
void (*remove)(struct coreboot_device *);
struct device_driver drv;
u32 tag;
};

View File

@ -72,13 +72,11 @@ static int framebuffer_probe(struct coreboot_device *dev)
return PTR_ERR_OR_ZERO(pdev);
}
static int framebuffer_remove(struct coreboot_device *dev)
static void framebuffer_remove(struct coreboot_device *dev)
{
struct platform_device *pdev = dev_get_drvdata(&dev->dev);
platform_device_unregister(pdev);
return 0;
}
static struct coreboot_driver framebuffer_driver = {

View File

@ -91,11 +91,9 @@ static int memconsole_probe(struct coreboot_device *dev)
return memconsole_sysfs_init();
}
static int memconsole_remove(struct coreboot_device *dev)
static void memconsole_remove(struct coreboot_device *dev)
{
memconsole_exit();
return 0;
}
static struct coreboot_driver memconsole_driver = {

View File

@ -298,14 +298,12 @@ static int vpd_probe(struct coreboot_device *dev)
return 0;
}
static int vpd_remove(struct coreboot_device *dev)
static void vpd_remove(struct coreboot_device *dev)
{
vpd_section_destroy(&ro_vpd);
vpd_section_destroy(&rw_vpd);
kobject_put(vpd_kobj);
return 0;
}
static struct coreboot_driver vpd_driver = {

View File

@ -192,6 +192,17 @@ config FPGA_DFL_AFU
to the FPGA infrastructure via a Port. There may be more than one
Port/AFU per DFL based FPGA device.
config FPGA_DFL_NIOS_INTEL_PAC_N3000
tristate "FPGA DFL NIOS Driver for Intel PAC N3000"
depends on FPGA_DFL
select REGMAP
help
This is the driver for the N3000 Nios private feature on Intel
PAC (Programmable Acceleration Card) N3000. It communicates
with the embedded Nios processor to configure the retimers on
the card. It also instantiates the SPI master (spi-altera) for
the card's BMC (Board Management Controller).
config FPGA_DFL_PCI
tristate "FPGA DFL PCIe Device Driver"
depends on PCI && FPGA_DFL

View File

@ -44,5 +44,7 @@ dfl-fme-objs += dfl-fme-perf.o
dfl-afu-objs := dfl-afu-main.o dfl-afu-region.o dfl-afu-dma-region.o
dfl-afu-objs += dfl-afu-error.o
obj-$(CONFIG_FPGA_DFL_NIOS_INTEL_PAC_N3000) += dfl-n3000-nios.o
# Drivers for FPGAs which implement DFL
obj-$(CONFIG_FPGA_DFL_PCI) += dfl-pci.o

View File

@ -192,7 +192,7 @@ static struct attribute *fme_perf_cpumask_attrs[] = {
NULL,
};
static struct attribute_group fme_perf_cpumask_group = {
static const struct attribute_group fme_perf_cpumask_group = {
.attrs = fme_perf_cpumask_attrs,
};
@ -225,7 +225,7 @@ static struct attribute *fme_perf_format_attrs[] = {
NULL,
};
static struct attribute_group fme_perf_format_group = {
static const struct attribute_group fme_perf_format_group = {
.name = "format",
.attrs = fme_perf_format_attrs,
};
@ -239,7 +239,7 @@ static struct attribute *fme_perf_events_attrs_empty[] = {
NULL,
};
static struct attribute_group fme_perf_events_group = {
static const struct attribute_group fme_perf_events_group = {
.name = "events",
.attrs = fme_perf_events_attrs_empty,
};

View File

@ -0,0 +1,588 @@
// SPDX-License-Identifier: GPL-2.0
/*
* DFL device driver for Nios private feature on Intel PAC (Programmable
* Acceleration Card) N3000
*
* Copyright (C) 2019-2020 Intel Corporation, Inc.
*
* Authors:
* Wu Hao <hao.wu@intel.com>
* Xu Yilun <yilun.xu@intel.com>
*/
#include <linux/bitfield.h>
#include <linux/dfl.h>
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/stddef.h>
#include <linux/spi/altera.h>
#include <linux/spi/spi.h>
#include <linux/types.h>
/*
* N3000 Nios private feature registers, named as NIOS_SPI_XX on spec.
* NS is the abbreviation of NIOS_SPI.
*/
#define N3000_NS_PARAM 0x8
#define N3000_NS_PARAM_SHIFT_MODE_MSK BIT_ULL(1)
#define N3000_NS_PARAM_SHIFT_MODE_MSB 0
#define N3000_NS_PARAM_SHIFT_MODE_LSB 1
#define N3000_NS_PARAM_DATA_WIDTH GENMASK_ULL(7, 2)
#define N3000_NS_PARAM_NUM_CS GENMASK_ULL(13, 8)
#define N3000_NS_PARAM_CLK_POL BIT_ULL(14)
#define N3000_NS_PARAM_CLK_PHASE BIT_ULL(15)
#define N3000_NS_PARAM_PERIPHERAL_ID GENMASK_ULL(47, 32)
#define N3000_NS_CTRL 0x10
#define N3000_NS_CTRL_WR_DATA GENMASK_ULL(31, 0)
#define N3000_NS_CTRL_ADDR GENMASK_ULL(44, 32)
#define N3000_NS_CTRL_CMD_MSK GENMASK_ULL(63, 62)
#define N3000_NS_CTRL_CMD_NOP 0
#define N3000_NS_CTRL_CMD_RD 1
#define N3000_NS_CTRL_CMD_WR 2
#define N3000_NS_STAT 0x18
#define N3000_NS_STAT_RD_DATA GENMASK_ULL(31, 0)
#define N3000_NS_STAT_RW_VAL BIT_ULL(32)
/* Nios handshake registers, indirect access */
#define N3000_NIOS_INIT 0x1000
#define N3000_NIOS_INIT_DONE BIT(0)
#define N3000_NIOS_INIT_START BIT(1)
/* Mode for retimer A, link 0, the same below */
#define N3000_NIOS_INIT_REQ_FEC_MODE_A0_MSK GENMASK(9, 8)
#define N3000_NIOS_INIT_REQ_FEC_MODE_A1_MSK GENMASK(11, 10)
#define N3000_NIOS_INIT_REQ_FEC_MODE_A2_MSK GENMASK(13, 12)
#define N3000_NIOS_INIT_REQ_FEC_MODE_A3_MSK GENMASK(15, 14)
#define N3000_NIOS_INIT_REQ_FEC_MODE_B0_MSK GENMASK(17, 16)
#define N3000_NIOS_INIT_REQ_FEC_MODE_B1_MSK GENMASK(19, 18)
#define N3000_NIOS_INIT_REQ_FEC_MODE_B2_MSK GENMASK(21, 20)
#define N3000_NIOS_INIT_REQ_FEC_MODE_B3_MSK GENMASK(23, 22)
#define N3000_NIOS_INIT_REQ_FEC_MODE_NO 0x0
#define N3000_NIOS_INIT_REQ_FEC_MODE_KR 0x1
#define N3000_NIOS_INIT_REQ_FEC_MODE_RS 0x2
#define N3000_NIOS_FW_VERSION 0x1004
#define N3000_NIOS_FW_VERSION_PATCH GENMASK(23, 20)
#define N3000_NIOS_FW_VERSION_MINOR GENMASK(27, 24)
#define N3000_NIOS_FW_VERSION_MAJOR GENMASK(31, 28)
/* The retimers we use on Intel PAC N3000 is Parkvale, abbreviated to PKVL */
#define N3000_NIOS_PKVL_A_MODE_STS 0x1020
#define N3000_NIOS_PKVL_B_MODE_STS 0x1024
#define N3000_NIOS_PKVL_MODE_STS_GROUP_MSK GENMASK(15, 8)
#define N3000_NIOS_PKVL_MODE_STS_GROUP_OK 0x0
#define N3000_NIOS_PKVL_MODE_STS_ID_MSK GENMASK(7, 0)
/* When GROUP MASK field == GROUP_OK */
#define N3000_NIOS_PKVL_MODE_ID_RESET 0x0
#define N3000_NIOS_PKVL_MODE_ID_4X10G 0x1
#define N3000_NIOS_PKVL_MODE_ID_4X25G 0x2
#define N3000_NIOS_PKVL_MODE_ID_2X25G 0x3
#define N3000_NIOS_PKVL_MODE_ID_2X25G_2X10G 0x4
#define N3000_NIOS_PKVL_MODE_ID_1X25G 0x5
#define N3000_NIOS_REGBUS_RETRY_COUNT 10000 /* loop count */
#define N3000_NIOS_INIT_TIMEOUT 10000000 /* usec */
#define N3000_NIOS_INIT_TIME_INTV 100000 /* usec */
#define N3000_NIOS_INIT_REQ_FEC_MODE_MSK_ALL \
(N3000_NIOS_INIT_REQ_FEC_MODE_A0_MSK | \
N3000_NIOS_INIT_REQ_FEC_MODE_A1_MSK | \
N3000_NIOS_INIT_REQ_FEC_MODE_A2_MSK | \
N3000_NIOS_INIT_REQ_FEC_MODE_A3_MSK | \
N3000_NIOS_INIT_REQ_FEC_MODE_B0_MSK | \
N3000_NIOS_INIT_REQ_FEC_MODE_B1_MSK | \
N3000_NIOS_INIT_REQ_FEC_MODE_B2_MSK | \
N3000_NIOS_INIT_REQ_FEC_MODE_B3_MSK)
#define N3000_NIOS_INIT_REQ_FEC_MODE_NO_ALL \
(FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A0_MSK, \
N3000_NIOS_INIT_REQ_FEC_MODE_NO) | \
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A1_MSK, \
N3000_NIOS_INIT_REQ_FEC_MODE_NO) | \
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A2_MSK, \
N3000_NIOS_INIT_REQ_FEC_MODE_NO) | \
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A3_MSK, \
N3000_NIOS_INIT_REQ_FEC_MODE_NO) | \
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B0_MSK, \
N3000_NIOS_INIT_REQ_FEC_MODE_NO) | \
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B1_MSK, \
N3000_NIOS_INIT_REQ_FEC_MODE_NO) | \
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B2_MSK, \
N3000_NIOS_INIT_REQ_FEC_MODE_NO) | \
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B3_MSK, \
N3000_NIOS_INIT_REQ_FEC_MODE_NO))
#define N3000_NIOS_INIT_REQ_FEC_MODE_KR_ALL \
(FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A0_MSK, \
N3000_NIOS_INIT_REQ_FEC_MODE_KR) | \
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A1_MSK, \
N3000_NIOS_INIT_REQ_FEC_MODE_KR) | \
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A2_MSK, \
N3000_NIOS_INIT_REQ_FEC_MODE_KR) | \
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A3_MSK, \
N3000_NIOS_INIT_REQ_FEC_MODE_KR) | \
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B0_MSK, \
N3000_NIOS_INIT_REQ_FEC_MODE_KR) | \
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B1_MSK, \
N3000_NIOS_INIT_REQ_FEC_MODE_KR) | \
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B2_MSK, \
N3000_NIOS_INIT_REQ_FEC_MODE_KR) | \
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B3_MSK, \
N3000_NIOS_INIT_REQ_FEC_MODE_KR))
#define N3000_NIOS_INIT_REQ_FEC_MODE_RS_ALL \
(FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A0_MSK, \
N3000_NIOS_INIT_REQ_FEC_MODE_RS) | \
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A1_MSK, \
N3000_NIOS_INIT_REQ_FEC_MODE_RS) | \
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A2_MSK, \
N3000_NIOS_INIT_REQ_FEC_MODE_RS) | \
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_A3_MSK, \
N3000_NIOS_INIT_REQ_FEC_MODE_RS) | \
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B0_MSK, \
N3000_NIOS_INIT_REQ_FEC_MODE_RS) | \
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B1_MSK, \
N3000_NIOS_INIT_REQ_FEC_MODE_RS) | \
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B2_MSK, \
N3000_NIOS_INIT_REQ_FEC_MODE_RS) | \
FIELD_PREP(N3000_NIOS_INIT_REQ_FEC_MODE_B3_MSK, \
N3000_NIOS_INIT_REQ_FEC_MODE_RS))
struct n3000_nios {
void __iomem *base;
struct regmap *regmap;
struct device *dev;
struct platform_device *altera_spi;
};
static ssize_t nios_fw_version_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct n3000_nios *nn = dev_get_drvdata(dev);
unsigned int val;
int ret;
ret = regmap_read(nn->regmap, N3000_NIOS_FW_VERSION, &val);
if (ret)
return ret;
return sysfs_emit(buf, "%x.%x.%x\n",
(u8)FIELD_GET(N3000_NIOS_FW_VERSION_MAJOR, val),
(u8)FIELD_GET(N3000_NIOS_FW_VERSION_MINOR, val),
(u8)FIELD_GET(N3000_NIOS_FW_VERSION_PATCH, val));
}
static DEVICE_ATTR_RO(nios_fw_version);
#define IS_MODE_STATUS_OK(mode_stat) \
(FIELD_GET(N3000_NIOS_PKVL_MODE_STS_GROUP_MSK, (mode_stat)) == \
N3000_NIOS_PKVL_MODE_STS_GROUP_OK)
#define IS_RETIMER_FEC_SUPPORTED(retimer_mode) \
((retimer_mode) != N3000_NIOS_PKVL_MODE_ID_RESET && \
(retimer_mode) != N3000_NIOS_PKVL_MODE_ID_4X10G)
static int get_retimer_mode(struct n3000_nios *nn, unsigned int mode_stat_reg,
unsigned int *retimer_mode)
{
unsigned int val;
int ret;
ret = regmap_read(nn->regmap, mode_stat_reg, &val);
if (ret)
return ret;
if (!IS_MODE_STATUS_OK(val))
return -EFAULT;
*retimer_mode = FIELD_GET(N3000_NIOS_PKVL_MODE_STS_ID_MSK, val);
return 0;
}
static ssize_t retimer_A_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct n3000_nios *nn = dev_get_drvdata(dev);
unsigned int mode;
int ret;
ret = get_retimer_mode(nn, N3000_NIOS_PKVL_A_MODE_STS, &mode);
if (ret)
return ret;
return sysfs_emit(buf, "0x%x\n", mode);
}
static DEVICE_ATTR_RO(retimer_A_mode);
static ssize_t retimer_B_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct n3000_nios *nn = dev_get_drvdata(dev);
unsigned int mode;
int ret;
ret = get_retimer_mode(nn, N3000_NIOS_PKVL_B_MODE_STS, &mode);
if (ret)
return ret;
return sysfs_emit(buf, "0x%x\n", mode);
}
static DEVICE_ATTR_RO(retimer_B_mode);
static ssize_t fec_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
unsigned int val, retimer_a_mode, retimer_b_mode, fec_modes;
struct n3000_nios *nn = dev_get_drvdata(dev);
int ret;
/* FEC mode setting is not supported in early FW versions */
ret = regmap_read(nn->regmap, N3000_NIOS_FW_VERSION, &val);
if (ret)
return ret;
if (FIELD_GET(N3000_NIOS_FW_VERSION_MAJOR, val) < 3)
return sysfs_emit(buf, "not supported\n");
/* If no 25G links, FEC mode setting is not supported either */
ret = get_retimer_mode(nn, N3000_NIOS_PKVL_A_MODE_STS, &retimer_a_mode);
if (ret)
return ret;
ret = get_retimer_mode(nn, N3000_NIOS_PKVL_B_MODE_STS, &retimer_b_mode);
if (ret)
return ret;
if (!IS_RETIMER_FEC_SUPPORTED(retimer_a_mode) &&
!IS_RETIMER_FEC_SUPPORTED(retimer_b_mode))
return sysfs_emit(buf, "not supported\n");
/* get the valid FEC mode for 25G links */
ret = regmap_read(nn->regmap, N3000_NIOS_INIT, &val);
if (ret)
return ret;
/*
* FEC mode should always be the same for all links, as we set them
* in this way.
*/
fec_modes = (val & N3000_NIOS_INIT_REQ_FEC_MODE_MSK_ALL);
if (fec_modes == N3000_NIOS_INIT_REQ_FEC_MODE_NO_ALL)
return sysfs_emit(buf, "no\n");
else if (fec_modes == N3000_NIOS_INIT_REQ_FEC_MODE_KR_ALL)
return sysfs_emit(buf, "kr\n");
else if (fec_modes == N3000_NIOS_INIT_REQ_FEC_MODE_RS_ALL)
return sysfs_emit(buf, "rs\n");
return -EFAULT;
}
static DEVICE_ATTR_RO(fec_mode);
static struct attribute *n3000_nios_attrs[] = {
&dev_attr_nios_fw_version.attr,
&dev_attr_retimer_A_mode.attr,
&dev_attr_retimer_B_mode.attr,
&dev_attr_fec_mode.attr,
NULL,
};
ATTRIBUTE_GROUPS(n3000_nios);
static int n3000_nios_init_done_check(struct n3000_nios *nn)
{
unsigned int val, state_a, state_b;
struct device *dev = nn->dev;
int ret, ret2;
/*
* The SPI is shared by the Nios core inside the FPGA, Nios will use
* this SPI master to do some one time initialization after power up,
* and then release the control to OS. The driver needs to poll on
* INIT_DONE to see when driver could take the control.
*
* Please note that after Nios firmware version 3.0.0, INIT_START is
* introduced, so driver needs to trigger START firstly and then check
* INIT_DONE.
*/
ret = regmap_read(nn->regmap, N3000_NIOS_FW_VERSION, &val);
if (ret)
return ret;
/*
* If Nios version register is totally uninitialized(== 0x0), then the
* Nios firmware is missing. So host could take control of SPI master
* safely, but initialization work for Nios is not done. To restore the
* card, we need to reprogram a new Nios firmware via the BMC chip on
* SPI bus. So the driver doesn't error out, it continues to create the
* spi controller device and spi_board_info for BMC.
*/
if (val == 0) {
dev_err(dev, "Nios version reg = 0x%x, skip INIT_DONE check, but the retimer may be uninitialized\n",
val);
return 0;
}
if (FIELD_GET(N3000_NIOS_FW_VERSION_MAJOR, val) >= 3) {
/* read NIOS_INIT to check if retimer initialization is done */
ret = regmap_read(nn->regmap, N3000_NIOS_INIT, &val);
if (ret)
return ret;
/* check if retimers are initialized already */
if (val & (N3000_NIOS_INIT_DONE | N3000_NIOS_INIT_START))
goto nios_init_done;
/* configure FEC mode per module param */
val = N3000_NIOS_INIT_START;
/*
* When the retimer is to be set to 10G mode, there is no FEC
* mode setting, so the REQ_FEC_MODE field will be ignored by
* Nios firmware in this case. But we should still fill the FEC
* mode field cause host could not get the retimer working mode
* until the Nios init is done.
*
* For now the driver doesn't support the retimer FEC mode
* switching per user's request. It is always set to Reed
* Solomon FEC.
*
* The driver will set the same FEC mode for all links.
*/
val |= N3000_NIOS_INIT_REQ_FEC_MODE_RS_ALL;
ret = regmap_write(nn->regmap, N3000_NIOS_INIT, val);
if (ret)
return ret;
}
nios_init_done:
/* polls on NIOS_INIT_DONE */
ret = regmap_read_poll_timeout(nn->regmap, N3000_NIOS_INIT, val,
val & N3000_NIOS_INIT_DONE,
N3000_NIOS_INIT_TIME_INTV,
N3000_NIOS_INIT_TIMEOUT);
if (ret)
dev_err(dev, "NIOS_INIT_DONE %s\n",
(ret == -ETIMEDOUT) ? "timed out" : "check error");
ret2 = regmap_read(nn->regmap, N3000_NIOS_PKVL_A_MODE_STS, &state_a);
if (ret2)
return ret2;
ret2 = regmap_read(nn->regmap, N3000_NIOS_PKVL_B_MODE_STS, &state_b);
if (ret2)
return ret2;
if (!ret) {
/*
* After INIT_DONE is detected, it still needs to check if the
* Nios firmware reports any error during the retimer
* configuration.
*/
if (IS_MODE_STATUS_OK(state_a) && IS_MODE_STATUS_OK(state_b))
return 0;
/*
* If the retimer configuration is failed, the Nios firmware
* will still release the spi controller for host to
* communicate with the BMC. It makes possible for people to
* reprogram a new Nios firmware and restore the card. So the
* driver doesn't error out, it continues to create the spi
* controller device and spi_board_info for BMC.
*/
dev_err(dev, "NIOS_INIT_DONE OK, but err on retimer init\n");
}
dev_err(nn->dev, "PKVL_A_MODE_STS 0x%x\n", state_a);
dev_err(nn->dev, "PKVL_B_MODE_STS 0x%x\n", state_b);
return ret;
}
static struct spi_board_info m10_n3000_info = {
.modalias = "m10-n3000",
.max_speed_hz = 12500000,
.bus_num = 0,
.chip_select = 0,
};
static int create_altera_spi_controller(struct n3000_nios *nn)
{
struct altera_spi_platform_data pdata = { 0 };
struct platform_device_info pdevinfo = { 0 };
void __iomem *base = nn->base;
u64 v;
v = readq(base + N3000_NS_PARAM);
pdata.mode_bits = SPI_CS_HIGH;
if (FIELD_GET(N3000_NS_PARAM_CLK_POL, v))
pdata.mode_bits |= SPI_CPOL;
if (FIELD_GET(N3000_NS_PARAM_CLK_PHASE, v))
pdata.mode_bits |= SPI_CPHA;
pdata.num_chipselect = FIELD_GET(N3000_NS_PARAM_NUM_CS, v);
pdata.bits_per_word_mask =
SPI_BPW_RANGE_MASK(1, FIELD_GET(N3000_NS_PARAM_DATA_WIDTH, v));
pdata.num_devices = 1;
pdata.devices = &m10_n3000_info;
dev_dbg(nn->dev, "%s cs %u bpm 0x%x mode 0x%x\n", __func__,
pdata.num_chipselect, pdata.bits_per_word_mask,
pdata.mode_bits);
pdevinfo.name = "subdev_spi_altera";
pdevinfo.id = PLATFORM_DEVID_AUTO;
pdevinfo.parent = nn->dev;
pdevinfo.data = &pdata;
pdevinfo.size_data = sizeof(pdata);
nn->altera_spi = platform_device_register_full(&pdevinfo);
return PTR_ERR_OR_ZERO(nn->altera_spi);
}
static void destroy_altera_spi_controller(struct n3000_nios *nn)
{
platform_device_unregister(nn->altera_spi);
}
static int n3000_nios_poll_stat_timeout(void __iomem *base, u64 *v)
{
int loops;
/*
* We don't use the time based timeout here for performance.
*
* The regbus read/write is on the critical path of Intel PAC N3000
* image programing. The time based timeout checking will add too much
* overhead on it. Usually the state changes in 1 or 2 loops on the
* test server, and we set 10000 times loop here for safety.
*/
for (loops = N3000_NIOS_REGBUS_RETRY_COUNT; loops > 0 ; loops--) {
*v = readq(base + N3000_NS_STAT);
if (*v & N3000_NS_STAT_RW_VAL)
break;
cpu_relax();
}
return (loops > 0) ? 0 : -ETIMEDOUT;
}
static int n3000_nios_reg_write(void *context, unsigned int reg, unsigned int val)
{
struct n3000_nios *nn = context;
u64 v;
int ret;
v = FIELD_PREP(N3000_NS_CTRL_CMD_MSK, N3000_NS_CTRL_CMD_WR) |
FIELD_PREP(N3000_NS_CTRL_ADDR, reg) |
FIELD_PREP(N3000_NS_CTRL_WR_DATA, val);
writeq(v, nn->base + N3000_NS_CTRL);
ret = n3000_nios_poll_stat_timeout(nn->base, &v);
if (ret)
dev_err(nn->dev, "fail to write reg 0x%x val 0x%x: %d\n",
reg, val, ret);
return ret;
}
static int n3000_nios_reg_read(void *context, unsigned int reg, unsigned int *val)
{
struct n3000_nios *nn = context;
u64 v;
int ret;
v = FIELD_PREP(N3000_NS_CTRL_CMD_MSK, N3000_NS_CTRL_CMD_RD) |
FIELD_PREP(N3000_NS_CTRL_ADDR, reg);
writeq(v, nn->base + N3000_NS_CTRL);
ret = n3000_nios_poll_stat_timeout(nn->base, &v);
if (ret)
dev_err(nn->dev, "fail to read reg 0x%x: %d\n", reg, ret);
else
*val = FIELD_GET(N3000_NS_STAT_RD_DATA, v);
return ret;
}
static const struct regmap_config n3000_nios_regbus_cfg = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.fast_io = true,
.reg_write = n3000_nios_reg_write,
.reg_read = n3000_nios_reg_read,
};
static int n3000_nios_probe(struct dfl_device *ddev)
{
struct device *dev = &ddev->dev;
struct n3000_nios *nn;
int ret;
nn = devm_kzalloc(dev, sizeof(*nn), GFP_KERNEL);
if (!nn)
return -ENOMEM;
dev_set_drvdata(&ddev->dev, nn);
nn->dev = dev;
nn->base = devm_ioremap_resource(&ddev->dev, &ddev->mmio_res);
if (IS_ERR(nn->base))
return PTR_ERR(nn->base);
nn->regmap = devm_regmap_init(dev, NULL, nn, &n3000_nios_regbus_cfg);
if (IS_ERR(nn->regmap))
return PTR_ERR(nn->regmap);
ret = n3000_nios_init_done_check(nn);
if (ret)
return ret;
ret = create_altera_spi_controller(nn);
if (ret)
dev_err(dev, "altera spi controller create failed: %d\n", ret);
return ret;
}
static void n3000_nios_remove(struct dfl_device *ddev)
{
struct n3000_nios *nn = dev_get_drvdata(&ddev->dev);
destroy_altera_spi_controller(nn);
}
#define FME_FEATURE_ID_N3000_NIOS 0xd
static const struct dfl_device_id n3000_nios_ids[] = {
{ FME_ID, FME_FEATURE_ID_N3000_NIOS },
{ }
};
MODULE_DEVICE_TABLE(dfl, n3000_nios_ids);
static struct dfl_driver n3000_nios_driver = {
.drv = {
.name = "dfl-n3000-nios",
.dev_groups = n3000_nios_groups,
},
.id_table = n3000_nios_ids,
.probe = n3000_nios_probe,
.remove = n3000_nios_remove,
};
module_dfl_driver(n3000_nios_driver);
MODULE_DESCRIPTION("Driver for Nios private feature on Intel PAC N3000");
MODULE_AUTHOR("Intel Corporation");
MODULE_LICENSE("GPL v2");

View File

@ -27,6 +27,14 @@
#define DRV_VERSION "0.8"
#define DRV_NAME "dfl-pci"
#define PCI_VSEC_ID_INTEL_DFLS 0x43
#define PCI_VNDR_DFLS_CNT 0x8
#define PCI_VNDR_DFLS_RES 0xc
#define PCI_VNDR_DFLS_RES_BAR_MASK GENMASK(2, 0)
#define PCI_VNDR_DFLS_RES_OFF_MASK GENMASK(31, 3)
struct cci_drvdata {
struct dfl_fpga_cdev *cdev; /* container device */
};
@ -119,49 +127,94 @@ static int *cci_pci_create_irq_table(struct pci_dev *pcidev, unsigned int nvec)
return table;
}
/* enumerate feature devices under pci device */
static int cci_enumerate_feature_devs(struct pci_dev *pcidev)
static int find_dfls_by_vsec(struct pci_dev *pcidev, struct dfl_fpga_enum_info *info)
{
struct cci_drvdata *drvdata = pci_get_drvdata(pcidev);
int port_num, bar, i, nvec, ret = 0;
struct dfl_fpga_enum_info *info;
struct dfl_fpga_cdev *cdev;
u32 bir, offset, vndr_hdr, dfl_cnt, dfl_res;
int dfl_res_off, i, bars, voff = 0;
resource_size_t start, len;
while ((voff = pci_find_next_ext_capability(pcidev, voff, PCI_EXT_CAP_ID_VNDR))) {
vndr_hdr = 0;
pci_read_config_dword(pcidev, voff + PCI_VNDR_HEADER, &vndr_hdr);
if (PCI_VNDR_HEADER_ID(vndr_hdr) == PCI_VSEC_ID_INTEL_DFLS &&
pcidev->vendor == PCI_VENDOR_ID_INTEL)
break;
}
if (!voff) {
dev_dbg(&pcidev->dev, "%s no DFL VSEC found\n", __func__);
return -ENODEV;
}
dfl_cnt = 0;
pci_read_config_dword(pcidev, voff + PCI_VNDR_DFLS_CNT, &dfl_cnt);
if (dfl_cnt > PCI_STD_NUM_BARS) {
dev_err(&pcidev->dev, "%s too many DFLs %d > %d\n",
__func__, dfl_cnt, PCI_STD_NUM_BARS);
return -EINVAL;
}
dfl_res_off = voff + PCI_VNDR_DFLS_RES;
if (dfl_res_off + (dfl_cnt * sizeof(u32)) > PCI_CFG_SPACE_EXP_SIZE) {
dev_err(&pcidev->dev, "%s DFL VSEC too big for PCIe config space\n",
__func__);
return -EINVAL;
}
for (i = 0, bars = 0; i < dfl_cnt; i++, dfl_res_off += sizeof(u32)) {
dfl_res = GENMASK(31, 0);
pci_read_config_dword(pcidev, dfl_res_off, &dfl_res);
bir = dfl_res & PCI_VNDR_DFLS_RES_BAR_MASK;
if (bir >= PCI_STD_NUM_BARS) {
dev_err(&pcidev->dev, "%s bad bir number %d\n",
__func__, bir);
return -EINVAL;
}
if (bars & BIT(bir)) {
dev_err(&pcidev->dev, "%s DFL for BAR %d already specified\n",
__func__, bir);
return -EINVAL;
}
bars |= BIT(bir);
len = pci_resource_len(pcidev, bir);
offset = dfl_res & PCI_VNDR_DFLS_RES_OFF_MASK;
if (offset >= len) {
dev_err(&pcidev->dev, "%s bad offset %u >= %pa\n",
__func__, offset, &len);
return -EINVAL;
}
dev_dbg(&pcidev->dev, "%s BAR %d offset 0x%x\n", __func__, bir, offset);
len -= offset;
start = pci_resource_start(pcidev, bir) + offset;
dfl_fpga_enum_info_add_dfl(info, start, len);
}
return 0;
}
/* default method of finding dfls starting at offset 0 of bar 0 */
static int find_dfls_by_default(struct pci_dev *pcidev,
struct dfl_fpga_enum_info *info)
{
int port_num, bar, i, ret = 0;
resource_size_t start, len;
void __iomem *base;
int *irq_table;
u32 offset;
u64 v;
/* allocate enumeration info via pci_dev */
info = dfl_fpga_enum_info_alloc(&pcidev->dev);
if (!info)
return -ENOMEM;
/* add irq info for enumeration if the device support irq */
nvec = cci_pci_alloc_irq(pcidev);
if (nvec < 0) {
dev_err(&pcidev->dev, "Fail to alloc irq %d.\n", nvec);
ret = nvec;
goto enum_info_free_exit;
} else if (nvec) {
irq_table = cci_pci_create_irq_table(pcidev, nvec);
if (!irq_table) {
ret = -ENOMEM;
goto irq_free_exit;
}
ret = dfl_fpga_enum_info_add_irq(info, nvec, irq_table);
kfree(irq_table);
if (ret)
goto irq_free_exit;
}
/* start to find Device Feature List in Bar 0 */
/* start to find Device Feature List from Bar 0 */
base = cci_pci_ioremap_bar0(pcidev);
if (!base) {
ret = -ENOMEM;
goto irq_free_exit;
}
if (!base)
return -ENOMEM;
/*
* PF device has FME and Ports/AFUs, and VF device only has one
@ -208,12 +261,54 @@ static int cci_enumerate_feature_devs(struct pci_dev *pcidev)
dfl_fpga_enum_info_add_dfl(info, start, len);
} else {
ret = -ENODEV;
goto irq_free_exit;
}
/* release I/O mappings for next step enumeration */
pcim_iounmap_regions(pcidev, BIT(0));
return ret;
}
/* enumerate feature devices under pci device */
static int cci_enumerate_feature_devs(struct pci_dev *pcidev)
{
struct cci_drvdata *drvdata = pci_get_drvdata(pcidev);
struct dfl_fpga_enum_info *info;
struct dfl_fpga_cdev *cdev;
int nvec, ret = 0;
int *irq_table;
/* allocate enumeration info via pci_dev */
info = dfl_fpga_enum_info_alloc(&pcidev->dev);
if (!info)
return -ENOMEM;
/* add irq info for enumeration if the device support irq */
nvec = cci_pci_alloc_irq(pcidev);
if (nvec < 0) {
dev_err(&pcidev->dev, "Fail to alloc irq %d.\n", nvec);
ret = nvec;
goto enum_info_free_exit;
} else if (nvec) {
irq_table = cci_pci_create_irq_table(pcidev, nvec);
if (!irq_table) {
ret = -ENOMEM;
goto irq_free_exit;
}
ret = dfl_fpga_enum_info_add_irq(info, nvec, irq_table);
kfree(irq_table);
if (ret)
goto irq_free_exit;
}
ret = find_dfls_by_vsec(pcidev, info);
if (ret == -ENODEV)
ret = find_dfls_by_default(pcidev, info);
if (ret)
goto irq_free_exit;
/* start enumeration with prepared enumeration information */
cdev = dfl_fpga_feature_devs_enumerate(info);
if (IS_ERR(cdev)) {

View File

@ -10,6 +10,7 @@
* Wu Hao <hao.wu@intel.com>
* Xiao Guangrong <guangrong.xiao@linux.intel.com>
*/
#include <linux/dfl.h>
#include <linux/fpga-dfl.h>
#include <linux/module.h>
#include <linux/uaccess.h>
@ -298,8 +299,7 @@ static int dfl_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct dfl_device *ddev = to_dfl_dev(dev);
/* The type has 4 valid bits and feature_id has 12 valid bits */
return add_uevent_var(env, "MODALIAS=dfl:t%01Xf%03X",
return add_uevent_var(env, "MODALIAS=dfl:t%04Xf%04X",
ddev->type, ddev->feature_id);
}

View File

@ -22,6 +22,7 @@
#include <linux/interrupt.h>
#include <linux/iopoll.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/uuid.h>
@ -516,88 +517,4 @@ long dfl_feature_ioctl_set_irq(struct platform_device *pdev,
struct dfl_feature *feature,
unsigned long arg);
/**
* enum dfl_id_type - define the DFL FIU types
*/
enum dfl_id_type {
FME_ID,
PORT_ID,
DFL_ID_MAX,
};
/**
* struct dfl_device_id - dfl device identifier
* @type: contains 4 bits DFL FIU type of the device. See enum dfl_id_type.
* @feature_id: contains 12 bits feature identifier local to its DFL FIU type.
* @driver_data: driver specific data.
*/
struct dfl_device_id {
u8 type;
u16 feature_id;
unsigned long driver_data;
};
/**
* struct dfl_device - represent an dfl device on dfl bus
*
* @dev: generic device interface.
* @id: id of the dfl device.
* @type: type of DFL FIU of the device. See enum dfl_id_type.
* @feature_id: 16 bits feature identifier local to its DFL FIU type.
* @mmio_res: mmio resource of this dfl device.
* @irqs: list of Linux IRQ numbers of this dfl device.
* @num_irqs: number of IRQs supported by this dfl device.
* @cdev: pointer to DFL FPGA container device this dfl device belongs to.
* @id_entry: matched id entry in dfl driver's id table.
*/
struct dfl_device {
struct device dev;
int id;
u8 type;
u16 feature_id;
struct resource mmio_res;
int *irqs;
unsigned int num_irqs;
struct dfl_fpga_cdev *cdev;
const struct dfl_device_id *id_entry;
};
/**
* struct dfl_driver - represent an dfl device driver
*
* @drv: driver model structure.
* @id_table: pointer to table of device IDs the driver is interested in.
* { } member terminated.
* @probe: mandatory callback for device binding.
* @remove: callback for device unbinding.
*/
struct dfl_driver {
struct device_driver drv;
const struct dfl_device_id *id_table;
int (*probe)(struct dfl_device *dfl_dev);
void (*remove)(struct dfl_device *dfl_dev);
};
#define to_dfl_dev(d) container_of(d, struct dfl_device, dev)
#define to_dfl_drv(d) container_of(d, struct dfl_driver, drv)
/*
* use a macro to avoid include chaining to get THIS_MODULE.
*/
#define dfl_driver_register(drv) \
__dfl_driver_register(drv, THIS_MODULE)
int __dfl_driver_register(struct dfl_driver *dfl_drv, struct module *owner);
void dfl_driver_unregister(struct dfl_driver *dfl_drv);
/*
* module_dfl_driver() - Helper macro for drivers that don't do
* anything special in module init/exit. This eliminates a lot of
* boilerplate. Each module may only use this macro once, and
* calling it replaces module_init() and module_exit().
*/
#define module_dfl_driver(__dfl_driver) \
module_driver(__dfl_driver, dfl_driver_register, \
dfl_driver_unregister)
#endif /* __FPGA_DFL_H */

View File

@ -17,7 +17,7 @@ static DEFINE_IDA(fpga_bridge_ida);
static struct class *fpga_bridge_class;
/* Lock for adding/removing bridges to linked lists*/
static spinlock_t bridge_list_lock;
static DEFINE_SPINLOCK(bridge_list_lock);
/**
* fpga_bridge_enable - Enable transactions on the bridge
@ -479,8 +479,6 @@ static void fpga_bridge_dev_release(struct device *dev)
static int __init fpga_bridge_dev_init(void)
{
spin_lock_init(&bridge_list_lock);
fpga_bridge_class = class_create(THIS_MODULE, "fpga_bridge");
if (IS_ERR(fpga_bridge_class))
return PTR_ERR(fpga_bridge_class);

View File

@ -567,12 +567,9 @@ static int cport_enable(struct gb_host_device *hd, u16 cport_id,
USB_DIR_OUT | USB_TYPE_VENDOR |
USB_RECIP_INTERFACE, cport_id, 0,
req, sizeof(*req), ES2_USB_CTRL_TIMEOUT);
if (ret != sizeof(*req)) {
if (ret < 0) {
dev_err(&udev->dev, "failed to set cport flags for port %d\n",
cport_id);
if (ret >= 0)
ret = -EIO;
goto out;
}
@ -961,12 +958,10 @@ static int arpc_send(struct es2_ap_dev *es2, struct arpc *rpc, int timeout)
0, 0,
rpc->req, le16_to_cpu(rpc->req->size),
ES2_USB_CTRL_TIMEOUT);
if (retval != le16_to_cpu(rpc->req->size)) {
if (retval < 0) {
dev_err(&udev->dev,
"failed to send ARPC request %d: %d\n",
rpc->req->type, retval);
if (retval > 0)
retval = -EIO;
return retval;
}

View File

@ -40,7 +40,7 @@ DECLARE_EVENT_CLASS(gb_message,
__entry->result = message->header->result;
),
TP_printk("size=%hu operation_id=0x%04x type=0x%02x result=0x%02x",
TP_printk("size=%u operation_id=0x%04x type=0x%02x result=0x%02x",
__entry->size, __entry->operation_id,
__entry->type, __entry->result)
);
@ -317,7 +317,7 @@ DECLARE_EVENT_CLASS(gb_interface,
__entry->mode_switch = intf->mode_switch;
),
TP_printk("intf_id=%hhu device_id=%hhu module_id=%hhu D=%d J=%d A=%d E=%d M=%d",
TP_printk("intf_id=%u device_id=%u module_id=%u D=%d J=%d A=%d E=%d M=%d",
__entry->id, __entry->device_id, __entry->module_id,
__entry->disconnected, __entry->ejected, __entry->active,
__entry->enabled, __entry->mode_switch)
@ -391,7 +391,7 @@ DECLARE_EVENT_CLASS(gb_module,
__entry->disconnected = module->disconnected;
),
TP_printk("hd_bus_id=%d module_id=%hhu num_interfaces=%zu disconnected=%d",
TP_printk("hd_bus_id=%d module_id=%u num_interfaces=%zu disconnected=%d",
__entry->hd_bus_id, __entry->module_id,
__entry->num_interfaces, __entry->disconnected)
);

View File

@ -401,8 +401,9 @@ static const struct attribute_group *catu_groups[] = {
static inline int catu_wait_for_ready(struct catu_drvdata *drvdata)
{
return coresight_timeout(drvdata->base,
CATU_STATUS, CATU_STATUS_READY, 1);
struct csdev_access *csa = &drvdata->csdev->access;
return coresight_timeout(csa, CATU_STATUS, CATU_STATUS_READY, 1);
}
static int catu_enable_hw(struct catu_drvdata *drvdata, void *data)
@ -411,6 +412,7 @@ static int catu_enable_hw(struct catu_drvdata *drvdata, void *data)
u32 control, mode;
struct etr_buf *etr_buf = data;
struct device *dev = &drvdata->csdev->dev;
struct coresight_device *csdev = drvdata->csdev;
if (catu_wait_for_ready(drvdata))
dev_warn(dev, "Timeout while waiting for READY\n");
@ -421,7 +423,7 @@ static int catu_enable_hw(struct catu_drvdata *drvdata, void *data)
return -EBUSY;
}
rc = coresight_claim_device_unlocked(drvdata->base);
rc = coresight_claim_device_unlocked(csdev);
if (rc)
return rc;
@ -465,9 +467,10 @@ static int catu_disable_hw(struct catu_drvdata *drvdata)
{
int rc = 0;
struct device *dev = &drvdata->csdev->dev;
struct coresight_device *csdev = drvdata->csdev;
catu_write_control(drvdata, 0);
coresight_disclaim_device_unlocked(drvdata->base);
coresight_disclaim_device_unlocked(csdev);
if (catu_wait_for_ready(drvdata)) {
dev_info(dev, "Timeout while waiting for READY\n");
rc = -EAGAIN;
@ -551,6 +554,7 @@ static int catu_probe(struct amba_device *adev, const struct amba_id *id)
dev->platform_data = pdata;
drvdata->base = base;
catu_desc.access = CSDEV_ACCESS_IOMEM(base);
catu_desc.pdata = pdata;
catu_desc.dev = dev;
catu_desc.groups = catu_groups;

View File

@ -145,30 +145,32 @@ static int coresight_find_link_outport(struct coresight_device *csdev,
return -ENODEV;
}
static inline u32 coresight_read_claim_tags(void __iomem *base)
static inline u32 coresight_read_claim_tags(struct coresight_device *csdev)
{
return readl_relaxed(base + CORESIGHT_CLAIMCLR);
return csdev_access_relaxed_read32(&csdev->access, CORESIGHT_CLAIMCLR);
}
static inline bool coresight_is_claimed_self_hosted(void __iomem *base)
static inline bool coresight_is_claimed_self_hosted(struct coresight_device *csdev)
{
return coresight_read_claim_tags(base) == CORESIGHT_CLAIM_SELF_HOSTED;
return coresight_read_claim_tags(csdev) == CORESIGHT_CLAIM_SELF_HOSTED;
}
static inline bool coresight_is_claimed_any(void __iomem *base)
static inline bool coresight_is_claimed_any(struct coresight_device *csdev)
{
return coresight_read_claim_tags(base) != 0;
return coresight_read_claim_tags(csdev) != 0;
}
static inline void coresight_set_claim_tags(void __iomem *base)
static inline void coresight_set_claim_tags(struct coresight_device *csdev)
{
writel_relaxed(CORESIGHT_CLAIM_SELF_HOSTED, base + CORESIGHT_CLAIMSET);
csdev_access_relaxed_write32(&csdev->access, CORESIGHT_CLAIM_SELF_HOSTED,
CORESIGHT_CLAIMSET);
isb();
}
static inline void coresight_clear_claim_tags(void __iomem *base)
static inline void coresight_clear_claim_tags(struct coresight_device *csdev)
{
writel_relaxed(CORESIGHT_CLAIM_SELF_HOSTED, base + CORESIGHT_CLAIMCLR);
csdev_access_relaxed_write32(&csdev->access, CORESIGHT_CLAIM_SELF_HOSTED,
CORESIGHT_CLAIMCLR);
isb();
}
@ -182,27 +184,33 @@ static inline void coresight_clear_claim_tags(void __iomem *base)
* Called with CS_UNLOCKed for the component.
* Returns : 0 on success
*/
int coresight_claim_device_unlocked(void __iomem *base)
int coresight_claim_device_unlocked(struct coresight_device *csdev)
{
if (coresight_is_claimed_any(base))
if (WARN_ON(!csdev))
return -EINVAL;
if (coresight_is_claimed_any(csdev))
return -EBUSY;
coresight_set_claim_tags(base);
if (coresight_is_claimed_self_hosted(base))
coresight_set_claim_tags(csdev);
if (coresight_is_claimed_self_hosted(csdev))
return 0;
/* There was a race setting the tags, clean up and fail */
coresight_clear_claim_tags(base);
coresight_clear_claim_tags(csdev);
return -EBUSY;
}
EXPORT_SYMBOL_GPL(coresight_claim_device_unlocked);
int coresight_claim_device(void __iomem *base)
int coresight_claim_device(struct coresight_device *csdev)
{
int rc;
CS_UNLOCK(base);
rc = coresight_claim_device_unlocked(base);
CS_LOCK(base);
if (WARN_ON(!csdev))
return -EINVAL;
CS_UNLOCK(csdev->access.base);
rc = coresight_claim_device_unlocked(csdev);
CS_LOCK(csdev->access.base);
return rc;
}
@ -212,11 +220,14 @@ EXPORT_SYMBOL_GPL(coresight_claim_device);
* coresight_disclaim_device_unlocked : Clear the claim tags for the device.
* Called with CS_UNLOCKed for the component.
*/
void coresight_disclaim_device_unlocked(void __iomem *base)
void coresight_disclaim_device_unlocked(struct coresight_device *csdev)
{
if (coresight_is_claimed_self_hosted(base))
coresight_clear_claim_tags(base);
if (WARN_ON(!csdev))
return;
if (coresight_is_claimed_self_hosted(csdev))
coresight_clear_claim_tags(csdev);
else
/*
* The external agent may have not honoured our claim
@ -227,11 +238,14 @@ void coresight_disclaim_device_unlocked(void __iomem *base)
}
EXPORT_SYMBOL_GPL(coresight_disclaim_device_unlocked);
void coresight_disclaim_device(void __iomem *base)
void coresight_disclaim_device(struct coresight_device *csdev)
{
CS_UNLOCK(base);
coresight_disclaim_device_unlocked(base);
CS_LOCK(base);
if (WARN_ON(!csdev))
return;
CS_UNLOCK(csdev->access.base);
coresight_disclaim_device_unlocked(csdev);
CS_LOCK(csdev->access.base);
}
EXPORT_SYMBOL_GPL(coresight_disclaim_device);
@ -1418,23 +1432,24 @@ static void coresight_remove_conns(struct coresight_device *csdev)
}
/**
* coresight_timeout - loop until a bit has changed to a specific state.
* @addr: base address of the area of interest.
* @offset: address of a register, starting from @addr.
* coresight_timeout - loop until a bit has changed to a specific register
* state.
* @csa: coresight device access for the device
* @offset: Offset of the register from the base of the device.
* @position: the position of the bit of interest.
* @value: the value the bit should have.
*
* Return: 0 as soon as the bit has taken the desired state or -EAGAIN if
* TIMEOUT_US has elapsed, which ever happens first.
*/
int coresight_timeout(void __iomem *addr, u32 offset, int position, int value)
int coresight_timeout(struct csdev_access *csa, u32 offset,
int position, int value)
{
int i;
u32 val;
for (i = TIMEOUT_US; i > 0; i--) {
val = __raw_readl(addr + offset);
val = csdev_access_read32(csa, offset);
/* waiting on the bit to go from 0 to 1 */
if (value) {
if (val & BIT(position))
@ -1458,6 +1473,48 @@ int coresight_timeout(void __iomem *addr, u32 offset, int position, int value)
}
EXPORT_SYMBOL_GPL(coresight_timeout);
u32 coresight_relaxed_read32(struct coresight_device *csdev, u32 offset)
{
return csdev_access_relaxed_read32(&csdev->access, offset);
}
u32 coresight_read32(struct coresight_device *csdev, u32 offset)
{
return csdev_access_read32(&csdev->access, offset);
}
void coresight_relaxed_write32(struct coresight_device *csdev,
u32 val, u32 offset)
{
csdev_access_relaxed_write32(&csdev->access, val, offset);
}
void coresight_write32(struct coresight_device *csdev, u32 val, u32 offset)
{
csdev_access_write32(&csdev->access, val, offset);
}
u64 coresight_relaxed_read64(struct coresight_device *csdev, u32 offset)
{
return csdev_access_relaxed_read64(&csdev->access, offset);
}
u64 coresight_read64(struct coresight_device *csdev, u32 offset)
{
return csdev_access_read64(&csdev->access, offset);
}
void coresight_relaxed_write64(struct coresight_device *csdev,
u64 val, u32 offset)
{
csdev_access_relaxed_write64(&csdev->access, val, offset);
}
void coresight_write64(struct coresight_device *csdev, u64 val, u32 offset)
{
csdev_access_write64(&csdev->access, val, offset);
}
/*
* coresight_release_platform_data: Release references to the devices connected
* to the output port of this device.
@ -1522,6 +1579,7 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
csdev->type = desc->type;
csdev->subtype = desc->subtype;
csdev->ops = desc->ops;
csdev->access = desc->access;
csdev->orphan = false;
csdev->dev.type = &coresight_dev_type[desc->type];

View File

@ -102,7 +102,7 @@ static int cti_enable_hw(struct cti_drvdata *drvdata)
goto cti_state_unchanged;
/* claim the device */
rc = coresight_claim_device(drvdata->base);
rc = coresight_claim_device(drvdata->csdev);
if (rc)
goto cti_err_not_enabled;
@ -136,7 +136,7 @@ static void cti_cpuhp_enable_hw(struct cti_drvdata *drvdata)
goto cti_hp_not_enabled;
/* try to claim the device */
if (coresight_claim_device(drvdata->base))
if (coresight_claim_device(drvdata->csdev))
goto cti_hp_not_enabled;
cti_write_all_hw_regs(drvdata);
@ -154,6 +154,7 @@ static int cti_disable_hw(struct cti_drvdata *drvdata)
{
struct cti_config *config = &drvdata->config;
struct device *dev = &drvdata->csdev->dev;
struct coresight_device *csdev = drvdata->csdev;
spin_lock(&drvdata->spinlock);
@ -171,7 +172,7 @@ static int cti_disable_hw(struct cti_drvdata *drvdata)
writel_relaxed(0, drvdata->base + CTICONTROL);
config->hw_enabled = false;
coresight_disclaim_device_unlocked(drvdata->base);
coresight_disclaim_device_unlocked(csdev);
CS_LOCK(drvdata->base);
spin_unlock(&drvdata->spinlock);
pm_runtime_put(dev);
@ -655,6 +656,7 @@ static int cti_cpu_pm_notify(struct notifier_block *nb, unsigned long cmd,
void *v)
{
struct cti_drvdata *drvdata;
struct coresight_device *csdev;
unsigned int cpu = smp_processor_id();
int notify_res = NOTIFY_OK;
@ -662,6 +664,7 @@ static int cti_cpu_pm_notify(struct notifier_block *nb, unsigned long cmd,
return NOTIFY_OK;
drvdata = cti_cpu_drvdata[cpu];
csdev = drvdata->csdev;
if (WARN_ON_ONCE(drvdata->ctidev.cpu != cpu))
return NOTIFY_BAD;
@ -673,13 +676,13 @@ static int cti_cpu_pm_notify(struct notifier_block *nb, unsigned long cmd,
/* CTI regs all static - we have a copy & nothing to save */
drvdata->config.hw_powered = false;
if (drvdata->config.hw_enabled)
coresight_disclaim_device(drvdata->base);
coresight_disclaim_device(csdev);
break;
case CPU_PM_ENTER_FAILED:
drvdata->config.hw_powered = true;
if (drvdata->config.hw_enabled) {
if (coresight_claim_device(drvdata->base))
if (coresight_claim_device(csdev))
drvdata->config.hw_enabled = false;
}
break;
@ -692,7 +695,7 @@ static int cti_cpu_pm_notify(struct notifier_block *nb, unsigned long cmd,
/* check enable reference count to enable HW */
if (atomic_read(&drvdata->config.enable_req_count)) {
/* check we can claim the device as we re-power */
if (coresight_claim_device(drvdata->base))
if (coresight_claim_device(csdev))
goto cti_notify_exit;
drvdata->config.hw_enabled = true;
@ -736,7 +739,7 @@ static int cti_dying_cpu(unsigned int cpu)
spin_lock(&drvdata->spinlock);
drvdata->config.hw_powered = false;
if (drvdata->config.hw_enabled)
coresight_disclaim_device(drvdata->base);
coresight_disclaim_device(drvdata->csdev);
spin_unlock(&drvdata->spinlock);
return 0;
}
@ -868,6 +871,7 @@ static int cti_probe(struct amba_device *adev, const struct amba_id *id)
return PTR_ERR(base);
drvdata->base = base;
cti_desc.access = CSDEV_ACCESS_IOMEM(base);
dev_set_drvdata(dev, drvdata);

View File

@ -343,7 +343,6 @@ static int cti_plat_create_connection(struct device *dev,
{
struct cti_trig_con *tc = NULL;
int cpuid = -1, err = 0;
struct fwnode_handle *cs_fwnode = NULL;
struct coresight_device *csdev = NULL;
const char *assoc_name = "unknown";
char cpu_name_str[16];
@ -397,8 +396,9 @@ static int cti_plat_create_connection(struct device *dev,
assoc_name = cpu_name_str;
} else {
/* associated device ? */
cs_fwnode = fwnode_find_reference(fwnode,
CTI_DT_CSDEV_ASSOC, 0);
struct fwnode_handle *cs_fwnode = fwnode_find_reference(fwnode,
CTI_DT_CSDEV_ASSOC,
0);
if (!IS_ERR(cs_fwnode)) {
assoc_name = cti_plat_get_csdev_or_node_name(cs_fwnode,
&csdev);

View File

@ -132,7 +132,7 @@ static void __etb_enable_hw(struct etb_drvdata *drvdata)
static int etb_enable_hw(struct etb_drvdata *drvdata)
{
int rc = coresight_claim_device(drvdata->base);
int rc = coresight_claim_device(drvdata->csdev);
if (rc)
return rc;
@ -252,6 +252,7 @@ static void __etb_disable_hw(struct etb_drvdata *drvdata)
{
u32 ffcr;
struct device *dev = &drvdata->csdev->dev;
struct csdev_access *csa = &drvdata->csdev->access;
CS_UNLOCK(drvdata->base);
@ -263,7 +264,7 @@ static void __etb_disable_hw(struct etb_drvdata *drvdata)
ffcr |= ETB_FFCR_FON_MAN;
writel_relaxed(ffcr, drvdata->base + ETB_FFCR);
if (coresight_timeout(drvdata->base, ETB_FFCR, ETB_FFCR_BIT, 0)) {
if (coresight_timeout(csa, ETB_FFCR, ETB_FFCR_BIT, 0)) {
dev_err(dev,
"timeout while waiting for completion of Manual Flush\n");
}
@ -271,7 +272,7 @@ static void __etb_disable_hw(struct etb_drvdata *drvdata)
/* disable trace capture */
writel_relaxed(0x0, drvdata->base + ETB_CTL_REG);
if (coresight_timeout(drvdata->base, ETB_FFSR, ETB_FFSR_BIT, 1)) {
if (coresight_timeout(csa, ETB_FFSR, ETB_FFSR_BIT, 1)) {
dev_err(dev,
"timeout while waiting for Formatter to Stop\n");
}
@ -344,7 +345,7 @@ static void etb_disable_hw(struct etb_drvdata *drvdata)
{
__etb_disable_hw(drvdata);
etb_dump_hw(drvdata);
coresight_disclaim_device(drvdata->base);
coresight_disclaim_device(drvdata->csdev);
}
static int etb_disable(struct coresight_device *csdev)
@ -757,6 +758,7 @@ static int etb_probe(struct amba_device *adev, const struct amba_id *id)
return PTR_ERR(base);
drvdata->base = base;
desc.access = CSDEV_ACCESS_IOMEM(base);
spin_lock_init(&drvdata->spinlock);

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