mirror of
https://github.com/tbsdtv/linux_media.git
synced 2025-07-22 12:21:00 +02:00
Merge tag 'driver-core-5.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core
Pull driver core and debugfs updates from Greg KH: "Here is the "big" driver core and debugfs changes for 5.3-rc1 It's a lot of different patches, all across the tree due to some api changes and lots of debugfs cleanups. Other than the debugfs cleanups, in this set of changes we have: - bus iteration function cleanups - scripts/get_abi.pl tool to display and parse Documentation/ABI entries in a simple way - cleanups to Documenatation/ABI/ entries to make them parse easier due to typos and other minor things - default_attrs use for some ktype users - driver model documentation file conversions to .rst - compressed firmware file loading - deferred probe fixes All of these have been in linux-next for a while, with a bunch of merge issues that Stephen has been patient with me for" * tag 'driver-core-5.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (102 commits) debugfs: make error message a bit more verbose orangefs: fix build warning from debugfs cleanup patch ubifs: fix build warning after debugfs cleanup patch driver: core: Allow subsystems to continue deferring probe drivers: base: cacheinfo: Ensure cpu hotplug work is done before Intel RDT arch_topology: Remove error messages on out-of-memory conditions lib: notifier-error-inject: no need to check return value of debugfs_create functions swiotlb: no need to check return value of debugfs_create functions ceph: no need to check return value of debugfs_create functions sunrpc: no need to check return value of debugfs_create functions ubifs: no need to check return value of debugfs_create functions orangefs: no need to check return value of debugfs_create functions nfsd: no need to check return value of debugfs_create functions lib: 842: no need to check return value of debugfs_create functions debugfs: provide pr_fmt() macro debugfs: log errors when something goes wrong drivers: s390/cio: Fix compilation warning about const qualifiers drivers: Add generic helper to match by of_node driver_find_device: Unify the match function with class_find_device() bus_find_device: Unify the match callback with class_find_device ...
This commit is contained in:
@@ -5,7 +5,7 @@ Description: It is possible to switch the cpi setting of the mouse with the
|
||||
press of a button.
|
||||
When read, this file returns the raw number of the actual cpi
|
||||
setting reported by the mouse. This number has to be further
|
||||
processed to receive the real dpi value.
|
||||
processed to receive the real dpi value:
|
||||
|
||||
VALUE DPI
|
||||
1 400
|
||||
|
@@ -1,5 +1,4 @@
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/
|
||||
asic_health
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/asic_health
|
||||
|
||||
Date: June 2018
|
||||
KernelVersion: 4.19
|
||||
@@ -9,9 +8,8 @@ Description: This file shows ASIC health status. The possible values are:
|
||||
|
||||
The files are read only.
|
||||
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/
|
||||
cpld1_version
|
||||
cpld2_version
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/cpld1_version
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/cpld2_version
|
||||
Date: June 2018
|
||||
KernelVersion: 4.19
|
||||
Contact: Vadim Pasternak <vadimpmellanox.com>
|
||||
@@ -20,8 +18,7 @@ Description: These files show with which CPLD versions have been burned
|
||||
|
||||
The files are read only.
|
||||
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/
|
||||
fan_dir
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/fan_dir
|
||||
|
||||
Date: December 2018
|
||||
KernelVersion: 5.0
|
||||
@@ -32,8 +29,7 @@ Description: This file shows the system fans direction:
|
||||
|
||||
The files are read only.
|
||||
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/
|
||||
jtag_enable
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/jtag_enable
|
||||
|
||||
Date: November 2018
|
||||
KernelVersion: 5.0
|
||||
@@ -43,8 +39,7 @@ Description: These files show with which CPLD versions have been burned
|
||||
|
||||
The files are read only.
|
||||
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/
|
||||
jtag_enable
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/jtag_enable
|
||||
|
||||
Date: November 2018
|
||||
KernelVersion: 5.0
|
||||
@@ -87,16 +82,15 @@ Description: These files allow asserting system power cycling, switching
|
||||
|
||||
The files are write only.
|
||||
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/
|
||||
reset_aux_pwr_or_ref
|
||||
reset_asic_thermal
|
||||
reset_hotswap_or_halt
|
||||
reset_hotswap_or_wd
|
||||
reset_fw_reset
|
||||
reset_long_pb
|
||||
reset_main_pwr_fail
|
||||
reset_short_pb
|
||||
reset_sw_reset
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_aux_pwr_or_ref
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_asic_thermal
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_hotswap_or_halt
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_hotswap_or_wd
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_fw_reset
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_long_pb
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_main_pwr_fail
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_short_pb
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_sw_reset
|
||||
Date: June 2018
|
||||
KernelVersion: 4.19
|
||||
Contact: Vadim Pasternak <vadimpmellanox.com>
|
||||
@@ -110,11 +104,10 @@ Description: These files show the system reset cause, as following: power
|
||||
|
||||
The files are read only.
|
||||
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/
|
||||
reset_comex_pwr_fail
|
||||
reset_from_comex
|
||||
reset_system
|
||||
reset_voltmon_upgrade_fail
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_comex_pwr_fail
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_from_comex
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_system
|
||||
What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_voltmon_upgrade_fail
|
||||
|
||||
Date: November 2018
|
||||
KernelVersion: 5.0
|
||||
|
@@ -1,6 +1,6 @@
|
||||
Where: /sys/fs/pstore/... (or /dev/pstore/...)
|
||||
What: /sys/fs/pstore/... (or /dev/pstore/...)
|
||||
Date: March 2011
|
||||
Kernel Version: 2.6.39
|
||||
KernelVersion: 2.6.39
|
||||
Contact: tony.luck@intel.com
|
||||
Description: Generic interface to platform dependent persistent storage.
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
Where: /sys/bus/event_source/devices/<dev>/format
|
||||
What: /sys/bus/event_source/devices/<dev>/format
|
||||
Date: January 2012
|
||||
Kernel Version: 3.3
|
||||
KernelVersion: 3.3
|
||||
Contact: Jiri Olsa <jolsa@redhat.com>
|
||||
Description:
|
||||
Attribute group to describe the magic bits that go into
|
||||
|
@@ -1,20 +1,20 @@
|
||||
Where: /sys/bus/i2c/devices/.../heading0_input
|
||||
What: /sys/bus/i2c/devices/.../heading0_input
|
||||
Date: April 2010
|
||||
Kernel Version: 2.6.36?
|
||||
KernelVersion: 2.6.36?
|
||||
Contact: alan.cox@intel.com
|
||||
Description: Reports the current heading from the compass as a floating
|
||||
point value in degrees.
|
||||
|
||||
Where: /sys/bus/i2c/devices/.../power_state
|
||||
What: /sys/bus/i2c/devices/.../power_state
|
||||
Date: April 2010
|
||||
Kernel Version: 2.6.36?
|
||||
KernelVersion: 2.6.36?
|
||||
Contact: alan.cox@intel.com
|
||||
Description: Sets the power state of the device. 0 sets the device into
|
||||
sleep mode, 1 wakes it up.
|
||||
|
||||
Where: /sys/bus/i2c/devices/.../calibration
|
||||
What: /sys/bus/i2c/devices/.../calibration
|
||||
Date: April 2010
|
||||
Kernel Version: 2.6.36?
|
||||
KernelVersion: 2.6.36?
|
||||
Contact: alan.cox@intel.com
|
||||
Description: Sets the calibration on or off (1 = on, 0 = off). See the
|
||||
chip data sheet.
|
||||
|
@@ -1,4 +1,4 @@
|
||||
What /sys/bus/iio/devices/iio:deviceX/sensor_sensitivity
|
||||
What: /sys/bus/iio/devices/iio:deviceX/sensor_sensitivity
|
||||
Date: January 2017
|
||||
KernelVersion: 4.11
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
@@ -6,7 +6,7 @@ Description:
|
||||
Show or set the gain boost of the amp, from 0-31 range.
|
||||
default 31
|
||||
|
||||
What /sys/bus/iio/devices/iio:deviceX/sensor_max_range
|
||||
What: /sys/bus/iio/devices/iio:deviceX/sensor_max_range
|
||||
Date: January 2017
|
||||
KernelVersion: 4.11
|
||||
Contact: linux-iio@vger.kernel.org
|
||||
|
@@ -1,4 +1,4 @@
|
||||
What /sys/bus/iio/devices/iio:deviceX/in_proximity_input
|
||||
What: /sys/bus/iio/devices/iio:deviceX/in_proximity_input
|
||||
Date: March 2014
|
||||
KernelVersion: 3.15
|
||||
Contact: Matt Ranostay <matt.ranostay@konsulko.com>
|
||||
@@ -6,7 +6,7 @@ Description:
|
||||
Get the current distance in meters of storm (1km steps)
|
||||
1000-40000 = distance in meters
|
||||
|
||||
What /sys/bus/iio/devices/iio:deviceX/sensor_sensitivity
|
||||
What: /sys/bus/iio/devices/iio:deviceX/sensor_sensitivity
|
||||
Date: March 2014
|
||||
KernelVersion: 3.15
|
||||
Contact: Matt Ranostay <matt.ranostay@konsulko.com>
|
||||
|
@@ -9,9 +9,9 @@ errors may be "seen" / reported by the link partner and not the
|
||||
problematic endpoint itself (which may report all counters as 0 as it never
|
||||
saw any problems).
|
||||
|
||||
Where: /sys/bus/pci/devices/<dev>/aer_dev_correctable
|
||||
What: /sys/bus/pci/devices/<dev>/aer_dev_correctable
|
||||
Date: July 2018
|
||||
Kernel Version: 4.19.0
|
||||
KernelVersion: 4.19.0
|
||||
Contact: linux-pci@vger.kernel.org, rajatja@google.com
|
||||
Description: List of correctable errors seen and reported by this
|
||||
PCI device using ERR_COR. Note that since multiple errors may
|
||||
@@ -31,9 +31,9 @@ Header Log Overflow 0
|
||||
TOTAL_ERR_COR 2
|
||||
-------------------------------------------------------------------------
|
||||
|
||||
Where: /sys/bus/pci/devices/<dev>/aer_dev_fatal
|
||||
What: /sys/bus/pci/devices/<dev>/aer_dev_fatal
|
||||
Date: July 2018
|
||||
Kernel Version: 4.19.0
|
||||
KernelVersion: 4.19.0
|
||||
Contact: linux-pci@vger.kernel.org, rajatja@google.com
|
||||
Description: List of uncorrectable fatal errors seen and reported by this
|
||||
PCI device using ERR_FATAL. Note that since multiple errors may
|
||||
@@ -62,9 +62,9 @@ TLP Prefix Blocked Error 0
|
||||
TOTAL_ERR_FATAL 0
|
||||
-------------------------------------------------------------------------
|
||||
|
||||
Where: /sys/bus/pci/devices/<dev>/aer_dev_nonfatal
|
||||
What: /sys/bus/pci/devices/<dev>/aer_dev_nonfatal
|
||||
Date: July 2018
|
||||
Kernel Version: 4.19.0
|
||||
KernelVersion: 4.19.0
|
||||
Contact: linux-pci@vger.kernel.org, rajatja@google.com
|
||||
Description: List of uncorrectable nonfatal errors seen and reported by this
|
||||
PCI device using ERR_NONFATAL. Note that since multiple errors
|
||||
@@ -103,20 +103,20 @@ collectors) that are AER capable. These indicate the number of error messages as
|
||||
device, so these counters include them and are thus cumulative of all the error
|
||||
messages on the PCI hierarchy originating at that root port.
|
||||
|
||||
Where: /sys/bus/pci/devices/<dev>/aer_stats/aer_rootport_total_err_cor
|
||||
What: /sys/bus/pci/devices/<dev>/aer_stats/aer_rootport_total_err_cor
|
||||
Date: July 2018
|
||||
Kernel Version: 4.19.0
|
||||
KernelVersion: 4.19.0
|
||||
Contact: linux-pci@vger.kernel.org, rajatja@google.com
|
||||
Description: Total number of ERR_COR messages reported to rootport.
|
||||
|
||||
Where: /sys/bus/pci/devices/<dev>/aer_stats/aer_rootport_total_err_fatal
|
||||
What: /sys/bus/pci/devices/<dev>/aer_stats/aer_rootport_total_err_fatal
|
||||
Date: July 2018
|
||||
Kernel Version: 4.19.0
|
||||
KernelVersion: 4.19.0
|
||||
Contact: linux-pci@vger.kernel.org, rajatja@google.com
|
||||
Description: Total number of ERR_FATAL messages reported to rootport.
|
||||
|
||||
Where: /sys/bus/pci/devices/<dev>/aer_stats/aer_rootport_total_err_nonfatal
|
||||
What: /sys/bus/pci/devices/<dev>/aer_stats/aer_rootport_total_err_nonfatal
|
||||
Date: July 2018
|
||||
Kernel Version: 4.19.0
|
||||
KernelVersion: 4.19.0
|
||||
Contact: linux-pci@vger.kernel.org, rajatja@google.com
|
||||
Description: Total number of ERR_NONFATAL messages reported to rootport.
|
||||
|
@@ -1,68 +1,68 @@
|
||||
Where: /sys/bus/pci/devices/<dev>/ccissX/cXdY/model
|
||||
What: /sys/bus/pci/devices/<dev>/ccissX/cXdY/model
|
||||
Date: March 2009
|
||||
Kernel Version: 2.6.30
|
||||
KernelVersion: 2.6.30
|
||||
Contact: iss_storagedev@hp.com
|
||||
Description: Displays the SCSI INQUIRY page 0 model for logical drive
|
||||
Y of controller X.
|
||||
|
||||
Where: /sys/bus/pci/devices/<dev>/ccissX/cXdY/rev
|
||||
What: /sys/bus/pci/devices/<dev>/ccissX/cXdY/rev
|
||||
Date: March 2009
|
||||
Kernel Version: 2.6.30
|
||||
KernelVersion: 2.6.30
|
||||
Contact: iss_storagedev@hp.com
|
||||
Description: Displays the SCSI INQUIRY page 0 revision for logical
|
||||
drive Y of controller X.
|
||||
|
||||
Where: /sys/bus/pci/devices/<dev>/ccissX/cXdY/unique_id
|
||||
What: /sys/bus/pci/devices/<dev>/ccissX/cXdY/unique_id
|
||||
Date: March 2009
|
||||
Kernel Version: 2.6.30
|
||||
KernelVersion: 2.6.30
|
||||
Contact: iss_storagedev@hp.com
|
||||
Description: Displays the SCSI INQUIRY page 83 serial number for logical
|
||||
drive Y of controller X.
|
||||
|
||||
Where: /sys/bus/pci/devices/<dev>/ccissX/cXdY/vendor
|
||||
What: /sys/bus/pci/devices/<dev>/ccissX/cXdY/vendor
|
||||
Date: March 2009
|
||||
Kernel Version: 2.6.30
|
||||
KernelVersion: 2.6.30
|
||||
Contact: iss_storagedev@hp.com
|
||||
Description: Displays the SCSI INQUIRY page 0 vendor for logical drive
|
||||
Y of controller X.
|
||||
|
||||
Where: /sys/bus/pci/devices/<dev>/ccissX/cXdY/block:cciss!cXdY
|
||||
What: /sys/bus/pci/devices/<dev>/ccissX/cXdY/block:cciss!cXdY
|
||||
Date: March 2009
|
||||
Kernel Version: 2.6.30
|
||||
KernelVersion: 2.6.30
|
||||
Contact: iss_storagedev@hp.com
|
||||
Description: A symbolic link to /sys/block/cciss!cXdY
|
||||
|
||||
Where: /sys/bus/pci/devices/<dev>/ccissX/rescan
|
||||
What: /sys/bus/pci/devices/<dev>/ccissX/rescan
|
||||
Date: August 2009
|
||||
Kernel Version: 2.6.31
|
||||
KernelVersion: 2.6.31
|
||||
Contact: iss_storagedev@hp.com
|
||||
Description: Kicks of a rescan of the controller to discover logical
|
||||
drive topology changes.
|
||||
|
||||
Where: /sys/bus/pci/devices/<dev>/ccissX/cXdY/lunid
|
||||
What: /sys/bus/pci/devices/<dev>/ccissX/cXdY/lunid
|
||||
Date: August 2009
|
||||
Kernel Version: 2.6.31
|
||||
KernelVersion: 2.6.31
|
||||
Contact: iss_storagedev@hp.com
|
||||
Description: Displays the 8-byte LUN ID used to address logical
|
||||
drive Y of controller X.
|
||||
|
||||
Where: /sys/bus/pci/devices/<dev>/ccissX/cXdY/raid_level
|
||||
What: /sys/bus/pci/devices/<dev>/ccissX/cXdY/raid_level
|
||||
Date: August 2009
|
||||
Kernel Version: 2.6.31
|
||||
KernelVersion: 2.6.31
|
||||
Contact: iss_storagedev@hp.com
|
||||
Description: Displays the RAID level of logical drive Y of
|
||||
controller X.
|
||||
|
||||
Where: /sys/bus/pci/devices/<dev>/ccissX/cXdY/usage_count
|
||||
What: /sys/bus/pci/devices/<dev>/ccissX/cXdY/usage_count
|
||||
Date: August 2009
|
||||
Kernel Version: 2.6.31
|
||||
KernelVersion: 2.6.31
|
||||
Contact: iss_storagedev@hp.com
|
||||
Description: Displays the usage count (number of opens) of logical drive Y
|
||||
of controller X.
|
||||
|
||||
Where: /sys/bus/pci/devices/<dev>/ccissX/resettable
|
||||
What: /sys/bus/pci/devices/<dev>/ccissX/resettable
|
||||
Date: February 2011
|
||||
Kernel Version: 2.6.38
|
||||
KernelVersion: 2.6.38
|
||||
Contact: iss_storagedev@hp.com
|
||||
Description: Value of 1 indicates the controller can honor the reset_devices
|
||||
kernel parameter. Value of 0 indicates reset_devices cannot be
|
||||
@@ -71,9 +71,9 @@ Description: Value of 1 indicates the controller can honor the reset_devices
|
||||
a dump device, as kdump requires resetting the device in order
|
||||
to work reliably.
|
||||
|
||||
Where: /sys/bus/pci/devices/<dev>/ccissX/transport_mode
|
||||
What: /sys/bus/pci/devices/<dev>/ccissX/transport_mode
|
||||
Date: July 2011
|
||||
Kernel Version: 3.0
|
||||
KernelVersion: 3.0
|
||||
Contact: iss_storagedev@hp.com
|
||||
Description: Value of "simple" indicates that the controller has been placed
|
||||
in "simple mode". Value of "performant" indicates that the
|
||||
|
@@ -1,14 +1,14 @@
|
||||
Where: /sys/bus/usb/.../powered
|
||||
What: /sys/bus/usb/.../powered
|
||||
Date: August 2008
|
||||
Kernel Version: 2.6.26
|
||||
KernelVersion: 2.6.26
|
||||
Contact: Harrison Metzger <harrisonmetz@gmail.com>
|
||||
Description: Controls whether the device's display will powered.
|
||||
A value of 0 is off and a non-zero value is on.
|
||||
|
||||
Where: /sys/bus/usb/.../mode_msb
|
||||
Where: /sys/bus/usb/.../mode_lsb
|
||||
What: /sys/bus/usb/.../mode_msb
|
||||
What: /sys/bus/usb/.../mode_lsb
|
||||
Date: August 2008
|
||||
Kernel Version: 2.6.26
|
||||
KernelVersion: 2.6.26
|
||||
Contact: Harrison Metzger <harrisonmetz@gmail.com>
|
||||
Description: Controls the devices display mode.
|
||||
For a 6 character display the values are
|
||||
@@ -16,24 +16,24 @@ Description: Controls the devices display mode.
|
||||
for an 8 character display the values are
|
||||
MSB 0x08; LSB 0xFF.
|
||||
|
||||
Where: /sys/bus/usb/.../textmode
|
||||
What: /sys/bus/usb/.../textmode
|
||||
Date: August 2008
|
||||
Kernel Version: 2.6.26
|
||||
KernelVersion: 2.6.26
|
||||
Contact: Harrison Metzger <harrisonmetz@gmail.com>
|
||||
Description: Controls the way the device interprets its text buffer.
|
||||
raw: each character controls its segment manually
|
||||
hex: each character is between 0-15
|
||||
ascii: each character is between '0'-'9' and 'A'-'F'.
|
||||
|
||||
Where: /sys/bus/usb/.../text
|
||||
What: /sys/bus/usb/.../text
|
||||
Date: August 2008
|
||||
Kernel Version: 2.6.26
|
||||
KernelVersion: 2.6.26
|
||||
Contact: Harrison Metzger <harrisonmetz@gmail.com>
|
||||
Description: The text (or data) for the device to display
|
||||
|
||||
Where: /sys/bus/usb/.../decimals
|
||||
What: /sys/bus/usb/.../decimals
|
||||
Date: August 2008
|
||||
Kernel Version: 2.6.26
|
||||
KernelVersion: 2.6.26
|
||||
Contact: Harrison Metzger <harrisonmetz@gmail.com>
|
||||
Description: Controls the decimal places on the device.
|
||||
To set the nth decimal place, give this field
|
||||
|
@@ -4,7 +4,7 @@ KernelVersion: 3.5
|
||||
Contact: Johan Hovold <jhovold@gmail.com>
|
||||
Description:
|
||||
Get the ALS output channel used as input in
|
||||
ALS-current-control mode (0, 1), where
|
||||
ALS-current-control mode (0, 1), where:
|
||||
|
||||
0 - out_current0 (backlight 0)
|
||||
1 - out_current1 (backlight 1)
|
||||
@@ -28,7 +28,7 @@ Date: April 2012
|
||||
KernelVersion: 3.5
|
||||
Contact: Johan Hovold <jhovold@gmail.com>
|
||||
Description:
|
||||
Set the brightness-mapping mode (0, 1), where
|
||||
Set the brightness-mapping mode (0, 1), where:
|
||||
|
||||
0 - exponential mode
|
||||
1 - linear mode
|
||||
@@ -38,7 +38,7 @@ Date: April 2012
|
||||
KernelVersion: 3.5
|
||||
Contact: Johan Hovold <jhovold@gmail.com>
|
||||
Description:
|
||||
Set the PWM-input control mask (5 bits), where
|
||||
Set the PWM-input control mask (5 bits), where:
|
||||
|
||||
bit 5 - PWM-input enabled in Zone 4
|
||||
bit 4 - PWM-input enabled in Zone 3
|
||||
|
@@ -1,6 +1,6 @@
|
||||
Note: Attributes that are shared between devices are stored in the directory
|
||||
pointed to by the symlink device/.
|
||||
Example: The real path of the attribute /sys/class/cxl/afu0.0s/irqs_max is
|
||||
Please note that attributes that are shared between devices are stored in
|
||||
the directory pointed to by the symlink device/.
|
||||
For example, the real path of the attribute /sys/class/cxl/afu0.0s/irqs_max is
|
||||
/sys/class/cxl/afu0.0s/device/irqs_max, i.e. /sys/class/cxl/afu0.0/irqs_max.
|
||||
|
||||
|
||||
|
@@ -47,7 +47,7 @@ Description:
|
||||
What: /sys/class/devfreq/.../trans_stat
|
||||
Date: October 2012
|
||||
Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
|
||||
Descrtiption:
|
||||
Description:
|
||||
This ABI shows the statistics of devfreq behavior on a
|
||||
specific device. It shows the time spent in each state and
|
||||
the number of transitions between states.
|
||||
|
@@ -4,7 +4,7 @@ KernelVersion: 3.5
|
||||
Contact: Johan Hovold <jhovold@gmail.com>
|
||||
Description:
|
||||
Set the ALS output channel to use as input in
|
||||
ALS-current-control mode (1, 2), where
|
||||
ALS-current-control mode (1, 2), where:
|
||||
|
||||
1 - out_current1
|
||||
2 - out_current2
|
||||
@@ -22,7 +22,7 @@ Date: April 2012
|
||||
KernelVersion: 3.5
|
||||
Contact: Johan Hovold <jhovold@gmail.com>
|
||||
Description:
|
||||
Set the pattern generator fall and rise times (0..7), where
|
||||
Set the pattern generator fall and rise times (0..7), where:
|
||||
|
||||
0 - 2048 us
|
||||
1 - 262 ms
|
||||
@@ -45,7 +45,7 @@ Date: April 2012
|
||||
KernelVersion: 3.5
|
||||
Contact: Johan Hovold <jhovold@gmail.com>
|
||||
Description:
|
||||
Set the brightness-mapping mode (0, 1), where
|
||||
Set the brightness-mapping mode (0, 1), where:
|
||||
|
||||
0 - exponential mode
|
||||
1 - linear mode
|
||||
@@ -55,7 +55,7 @@ Date: April 2012
|
||||
KernelVersion: 3.5
|
||||
Contact: Johan Hovold <jhovold@gmail.com>
|
||||
Description:
|
||||
Set the PWM-input control mask (5 bits), where
|
||||
Set the PWM-input control mask (5 bits), where:
|
||||
|
||||
bit 5 - PWM-input enabled in Zone 4
|
||||
bit 4 - PWM-input enabled in Zone 3
|
||||
|
@@ -5,7 +5,7 @@ Contact: Janne Kanniainen <janne.kanniainen@gmail.com>
|
||||
Description:
|
||||
Set the mode of LEDs. You should notice that changing the mode
|
||||
of one LED will update the mode of its two sibling devices as
|
||||
well.
|
||||
well. Possible values are:
|
||||
|
||||
0 - normal
|
||||
1 - audio
|
||||
@@ -13,4 +13,4 @@ Description:
|
||||
|
||||
Normal: LEDs are fully on when enabled
|
||||
Audio: LEDs brightness depends on sound level
|
||||
Breathing: LEDs brightness varies at human breathing rate
|
||||
Breathing: LEDs brightness varies at human breathing rate
|
||||
|
@@ -147,6 +147,6 @@ What: /sys/class/powercap/.../<power zone>/enabled
|
||||
Date: September 2013
|
||||
KernelVersion: 3.13
|
||||
Contact: linux-pm@vger.kernel.org
|
||||
Description
|
||||
Description:
|
||||
This allows to enable/disable power capping at power zone level.
|
||||
This applies to current power zone and its children.
|
||||
|
@@ -125,12 +125,6 @@ Description:
|
||||
The EUI-48 of this device in colon separated hex
|
||||
octets.
|
||||
|
||||
What: /sys/class/uwb_rc/uwbN/<EUI-48>/BPST
|
||||
Date: July 2008
|
||||
KernelVersion: 2.6.27
|
||||
Contact: linux-usb@vger.kernel.org
|
||||
Description:
|
||||
|
||||
What: /sys/class/uwb_rc/uwbN/<EUI-48>/IEs
|
||||
Date: July 2008
|
||||
KernelVersion: 2.6.27
|
||||
|
@@ -1,6 +1,6 @@
|
||||
What: /sys/bus/pci/drivers/altera-cvp/chkcfg
|
||||
Date: May 2017
|
||||
Kernel Version: 4.13
|
||||
KernelVersion: 4.13
|
||||
Contact: Anatolij Gustschin <agust@denx.de>
|
||||
Description:
|
||||
Contains either 1 or 0 and controls if configuration
|
||||
|
@@ -1,6 +1,6 @@
|
||||
What: For USB devices : /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/report_descriptor
|
||||
For BT devices : /sys/class/bluetooth/hci<addr>/<hid-bus>:<vendor-id>:<product-id>.<num>/report_descriptor
|
||||
Symlink : /sys/class/hidraw/hidraw<num>/device/report_descriptor
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/report_descriptor
|
||||
What: /sys/class/bluetooth/hci<addr>/<hid-bus>:<vendor-id>:<product-id>.<num>/report_descriptor
|
||||
What: /sys/class/hidraw/hidraw<num>/device/report_descriptor
|
||||
Date: Jan 2011
|
||||
KernelVersion: 2.0.39
|
||||
Contact: Alan Ott <alan@signal11.us>
|
||||
@@ -9,9 +9,9 @@ Description: When read, this file returns the device's raw binary HID
|
||||
This file cannot be written.
|
||||
Users: HIDAPI library (http://www.signal11.us/oss/hidapi)
|
||||
|
||||
What: For USB devices : /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/country
|
||||
For BT devices : /sys/class/bluetooth/hci<addr>/<hid-bus>:<vendor-id>:<product-id>.<num>/country
|
||||
Symlink : /sys/class/hidraw/hidraw<num>/device/country
|
||||
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/country
|
||||
What: /sys/class/bluetooth/hci<addr>/<hid-bus>:<vendor-id>:<product-id>.<num>/country
|
||||
What: /sys/class/hidraw/hidraw<num>/device/country
|
||||
Date: February 2015
|
||||
KernelVersion: 3.19
|
||||
Contact: Olivier Gay <ogay@logitech.com>
|
||||
|
@@ -5,7 +5,7 @@ Description: It is possible to switch the dpi setting of the mouse with the
|
||||
press of a button.
|
||||
When read, this file returns the raw number of the actual dpi
|
||||
setting reported by the mouse. This number has to be further
|
||||
processed to receive the real dpi value.
|
||||
processed to receive the real dpi value:
|
||||
|
||||
VALUE DPI
|
||||
1 800
|
||||
|
@@ -1,6 +1,6 @@
|
||||
What: /sys/class/tpm/tpmX/ppi/
|
||||
Date: August 2012
|
||||
Kernel Version: 3.6
|
||||
KernelVersion: 3.6
|
||||
Contact: xiaoyan.zhang@intel.com
|
||||
Description:
|
||||
This folder includes the attributes related with PPI (Physical
|
||||
|
@@ -1,6 +1,6 @@
|
||||
What: /sys/bus/scsi/drivers/st/debug_flag
|
||||
Date: October 2015
|
||||
Kernel Version: ?.?
|
||||
KernelVersion: ?.?
|
||||
Contact: shane.seymour@hpe.com
|
||||
Description:
|
||||
This file allows you to turn debug output from the st driver
|
||||
|
@@ -1,6 +1,6 @@
|
||||
What: /sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/speed
|
||||
Date: April 2010
|
||||
Kernel Version: 2.6.35
|
||||
KernelVersion: 2.6.35
|
||||
Contact: linux-bluetooth@vger.kernel.org
|
||||
Description:
|
||||
The /sys/bus/hid/devices/<bus>:<vid>:<pid>.<n>/speed file
|
||||
|
@@ -2,7 +2,7 @@ What: /sys/kernel/fscaps
|
||||
Date: February 2011
|
||||
KernelVersion: 2.6.38
|
||||
Contact: Ludwig Nussel <ludwig.nussel@suse.de>
|
||||
Description
|
||||
Description:
|
||||
Shows whether file system capabilities are honored
|
||||
when executing a binary
|
||||
|
||||
|
@@ -4,7 +4,7 @@ KernelVersion: 2.6.24
|
||||
Contact: Ken'ichi Ohmichi <oomichi@mxs.nes.nec.co.jp>
|
||||
Kexec Mailing List <kexec@lists.infradead.org>
|
||||
Vivek Goyal <vgoyal@redhat.com>
|
||||
Description
|
||||
Description:
|
||||
Shows physical address and size of vmcoreinfo ELF note.
|
||||
First value contains physical address of note in hex and
|
||||
second value contains the size of note in hex. This ELF
|
||||
|
@@ -399,7 +399,7 @@ symbol:
|
||||
will pass the struct gpio_chip* for the chip to all IRQ callbacks, so the
|
||||
callbacks need to embed the gpio_chip in its state container and obtain a
|
||||
pointer to the container using container_of().
|
||||
(See Documentation/driver-model/design-patterns.txt)
|
||||
(See Documentation/driver-model/design-patterns.rst)
|
||||
|
||||
- gpiochip_irqchip_add_nested(): adds a nested cascaded irqchip to a gpiochip,
|
||||
as discussed above regarding different types of cascaded irqchips. The
|
||||
|
@@ -1,5 +1,6 @@
|
||||
|
||||
==============
|
||||
Driver Binding
|
||||
==============
|
||||
|
||||
Driver binding is the process of associating a device with a device
|
||||
driver that can control it. Bus drivers have typically handled this
|
||||
@@ -25,7 +26,7 @@ device_register
|
||||
When a new device is added, the bus's list of drivers is iterated over
|
||||
to find one that supports it. In order to determine that, the device
|
||||
ID of the device must match one of the device IDs that the driver
|
||||
supports. The format and semantics for comparing IDs is bus-specific.
|
||||
supports. The format and semantics for comparing IDs is bus-specific.
|
||||
Instead of trying to derive a complex state machine and matching
|
||||
algorithm, it is up to the bus driver to provide a callback to compare
|
||||
a device against the IDs of a driver. The bus returns 1 if a match was
|
||||
@@ -36,14 +37,14 @@ int match(struct device * dev, struct device_driver * drv);
|
||||
If a match is found, the device's driver field is set to the driver
|
||||
and the driver's probe callback is called. This gives the driver a
|
||||
chance to verify that it really does support the hardware, and that
|
||||
it's in a working state.
|
||||
it's in a working state.
|
||||
|
||||
Device Class
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Upon the successful completion of probe, the device is registered with
|
||||
the class to which it belongs. Device drivers belong to one and only one
|
||||
class, and that is set in the driver's devclass field.
|
||||
class, and that is set in the driver's devclass field.
|
||||
devclass_add_device is called to enumerate the device within the class
|
||||
and actually register it with the class, which happens with the
|
||||
class's register_dev callback.
|
||||
@@ -53,7 +54,7 @@ Driver
|
||||
~~~~~~
|
||||
|
||||
When a driver is attached to a device, the device is inserted into the
|
||||
driver's list of devices.
|
||||
driver's list of devices.
|
||||
|
||||
|
||||
sysfs
|
||||
@@ -67,18 +68,18 @@ to the device's directory in the physical hierarchy.
|
||||
|
||||
A directory for the device is created in the class's directory. A
|
||||
symlink is created in that directory that points to the device's
|
||||
physical location in the sysfs tree.
|
||||
physical location in the sysfs tree.
|
||||
|
||||
A symlink can be created (though this isn't done yet) in the device's
|
||||
physical directory to either its class directory, or the class's
|
||||
top-level directory. One can also be created to point to its driver's
|
||||
directory also.
|
||||
directory also.
|
||||
|
||||
|
||||
driver_register
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
The process is almost identical for when a new driver is added.
|
||||
The process is almost identical for when a new driver is added.
|
||||
The bus's list of devices is iterated over to find a match. Devices
|
||||
that already have a driver are skipped. All the devices are iterated
|
||||
over, to bind as many devices as possible to the driver.
|
||||
@@ -94,5 +95,4 @@ of the driver is decremented. All symlinks between the two are removed.
|
||||
|
||||
When a driver is removed, the list of devices that it supports is
|
||||
iterated over, and the driver's remove callback is called for each
|
||||
one. The device is removed from that list and the symlinks removed.
|
||||
|
||||
one. The device is removed from that list and the symlinks removed.
|
@@ -1,5 +1,6 @@
|
||||
|
||||
Bus Types
|
||||
=========
|
||||
Bus Types
|
||||
=========
|
||||
|
||||
Definition
|
||||
~~~~~~~~~~
|
||||
@@ -13,12 +14,12 @@ Declaration
|
||||
|
||||
Each bus type in the kernel (PCI, USB, etc) should declare one static
|
||||
object of this type. They must initialize the name field, and may
|
||||
optionally initialize the match callback.
|
||||
optionally initialize the match callback::
|
||||
|
||||
struct bus_type pci_bus_type = {
|
||||
.name = "pci",
|
||||
.match = pci_bus_match,
|
||||
};
|
||||
struct bus_type pci_bus_type = {
|
||||
.name = "pci",
|
||||
.match = pci_bus_match,
|
||||
};
|
||||
|
||||
The structure should be exported to drivers in a header file:
|
||||
|
||||
@@ -30,8 +31,8 @@ Registration
|
||||
|
||||
When a bus driver is initialized, it calls bus_register. This
|
||||
initializes the rest of the fields in the bus object and inserts it
|
||||
into a global list of bus types. Once the bus object is registered,
|
||||
the fields in it are usable by the bus driver.
|
||||
into a global list of bus types. Once the bus object is registered,
|
||||
the fields in it are usable by the bus driver.
|
||||
|
||||
|
||||
Callbacks
|
||||
@@ -43,17 +44,17 @@ match(): Attaching Drivers to Devices
|
||||
The format of device ID structures and the semantics for comparing
|
||||
them are inherently bus-specific. Drivers typically declare an array
|
||||
of device IDs of devices they support that reside in a bus-specific
|
||||
driver structure.
|
||||
driver structure.
|
||||
|
||||
The purpose of the match callback is to give the bus an opportunity to
|
||||
determine if a particular driver supports a particular device by
|
||||
comparing the device IDs the driver supports with the device ID of a
|
||||
particular device, without sacrificing bus-specific functionality or
|
||||
type-safety.
|
||||
type-safety.
|
||||
|
||||
When a driver is registered with the bus, the bus's list of devices is
|
||||
iterated over, and the match callback is called for each device that
|
||||
does not have a driver associated with it.
|
||||
does not have a driver associated with it.
|
||||
|
||||
|
||||
|
||||
@@ -64,22 +65,23 @@ The lists of devices and drivers are intended to replace the local
|
||||
lists that many buses keep. They are lists of struct devices and
|
||||
struct device_drivers, respectively. Bus drivers are free to use the
|
||||
lists as they please, but conversion to the bus-specific type may be
|
||||
necessary.
|
||||
necessary.
|
||||
|
||||
The LDM core provides helper functions for iterating over each list.
|
||||
The LDM core provides helper functions for iterating over each list::
|
||||
|
||||
int bus_for_each_dev(struct bus_type * bus, struct device * start, void * data,
|
||||
int (*fn)(struct device *, void *));
|
||||
int bus_for_each_dev(struct bus_type * bus, struct device * start,
|
||||
void * data,
|
||||
int (*fn)(struct device *, void *));
|
||||
|
||||
int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,
|
||||
void * data, int (*fn)(struct device_driver *, void *));
|
||||
int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,
|
||||
void * data, int (*fn)(struct device_driver *, void *));
|
||||
|
||||
These helpers iterate over the respective list, and call the callback
|
||||
for each device or driver in the list. All list accesses are
|
||||
synchronized by taking the bus's lock (read currently). The reference
|
||||
count on each object in the list is incremented before the callback is
|
||||
called; it is decremented after the next object has been obtained. The
|
||||
lock is not held when calling the callback.
|
||||
lock is not held when calling the callback.
|
||||
|
||||
|
||||
sysfs
|
||||
@@ -87,14 +89,14 @@ sysfs
|
||||
There is a top-level directory named 'bus'.
|
||||
|
||||
Each bus gets a directory in the bus directory, along with two default
|
||||
directories:
|
||||
directories::
|
||||
|
||||
/sys/bus/pci/
|
||||
|-- devices
|
||||
`-- drivers
|
||||
|
||||
Drivers registered with the bus get a directory in the bus's drivers
|
||||
directory:
|
||||
directory::
|
||||
|
||||
/sys/bus/pci/
|
||||
|-- devices
|
||||
@@ -106,7 +108,7 @@ directory:
|
||||
|
||||
Each device that is discovered on a bus of that type gets a symlink in
|
||||
the bus's devices directory to the device's directory in the physical
|
||||
hierarchy:
|
||||
hierarchy::
|
||||
|
||||
/sys/bus/pci/
|
||||
|-- devices
|
||||
@@ -118,26 +120,27 @@ hierarchy:
|
||||
|
||||
Exporting Attributes
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
struct bus_attribute {
|
||||
|
||||
::
|
||||
|
||||
struct bus_attribute {
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct bus_type *, char * buf);
|
||||
ssize_t (*store)(struct bus_type *, const char * buf, size_t count);
|
||||
};
|
||||
};
|
||||
|
||||
Bus drivers can export attributes using the BUS_ATTR_RW macro that works
|
||||
similarly to the DEVICE_ATTR_RW macro for devices. For example, a
|
||||
definition like this:
|
||||
definition like this::
|
||||
|
||||
static BUS_ATTR_RW(debug);
|
||||
static BUS_ATTR_RW(debug);
|
||||
|
||||
is equivalent to declaring:
|
||||
is equivalent to declaring::
|
||||
|
||||
static bus_attribute bus_attr_debug;
|
||||
static bus_attribute bus_attr_debug;
|
||||
|
||||
This can then be used to add and remove the attribute from the bus's
|
||||
sysfs directory using:
|
||||
|
||||
int bus_create_file(struct bus_type *, struct bus_attribute *);
|
||||
void bus_remove_file(struct bus_type *, struct bus_attribute *);
|
||||
|
||||
sysfs directory using::
|
||||
|
||||
int bus_create_file(struct bus_type *, struct bus_attribute *);
|
||||
void bus_remove_file(struct bus_type *, struct bus_attribute *);
|
@@ -1,6 +1,6 @@
|
||||
|
||||
==============
|
||||
Device Classes
|
||||
|
||||
==============
|
||||
|
||||
Introduction
|
||||
~~~~~~~~~~~~
|
||||
@@ -13,37 +13,37 @@ device. The following device classes have been identified:
|
||||
Each device class defines a set of semantics and a programming interface
|
||||
that devices of that class adhere to. Device drivers are the
|
||||
implementation of that programming interface for a particular device on
|
||||
a particular bus.
|
||||
a particular bus.
|
||||
|
||||
Device classes are agnostic with respect to what bus a device resides
|
||||
on.
|
||||
on.
|
||||
|
||||
|
||||
Programming Interface
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
The device class structure looks like:
|
||||
The device class structure looks like::
|
||||
|
||||
|
||||
typedef int (*devclass_add)(struct device *);
|
||||
typedef void (*devclass_remove)(struct device *);
|
||||
typedef int (*devclass_add)(struct device *);
|
||||
typedef void (*devclass_remove)(struct device *);
|
||||
|
||||
See the kerneldoc for the struct class.
|
||||
|
||||
A typical device class definition would look like:
|
||||
A typical device class definition would look like::
|
||||
|
||||
struct device_class input_devclass = {
|
||||
struct device_class input_devclass = {
|
||||
.name = "input",
|
||||
.add_device = input_add_device,
|
||||
.remove_device = input_remove_device,
|
||||
};
|
||||
};
|
||||
|
||||
Each device class structure should be exported in a header file so it
|
||||
can be used by drivers, extensions and interfaces.
|
||||
|
||||
Device classes are registered and unregistered with the core using:
|
||||
Device classes are registered and unregistered with the core using::
|
||||
|
||||
int devclass_register(struct device_class * cls);
|
||||
void devclass_unregister(struct device_class * cls);
|
||||
int devclass_register(struct device_class * cls);
|
||||
void devclass_unregister(struct device_class * cls);
|
||||
|
||||
|
||||
Devices
|
||||
@@ -52,16 +52,16 @@ As devices are bound to drivers, they are added to the device class
|
||||
that the driver belongs to. Before the driver model core, this would
|
||||
typically happen during the driver's probe() callback, once the device
|
||||
has been initialized. It now happens after the probe() callback
|
||||
finishes from the core.
|
||||
finishes from the core.
|
||||
|
||||
The device is enumerated in the class. Each time a device is added to
|
||||
the class, the class's devnum field is incremented and assigned to the
|
||||
device. The field is never decremented, so if the device is removed
|
||||
from the class and re-added, it will receive a different enumerated
|
||||
value.
|
||||
value.
|
||||
|
||||
The class is allowed to create a class-specific structure for the
|
||||
device and store it in the device's class_data pointer.
|
||||
device and store it in the device's class_data pointer.
|
||||
|
||||
There is no list of devices in the device class. Each driver has a
|
||||
list of devices that it supports. The device class has a list of
|
||||
@@ -73,15 +73,15 @@ Device Drivers
|
||||
~~~~~~~~~~~~~~
|
||||
Device drivers are added to device classes when they are registered
|
||||
with the core. A driver specifies the class it belongs to by setting
|
||||
the struct device_driver::devclass field.
|
||||
the struct device_driver::devclass field.
|
||||
|
||||
|
||||
sysfs directory structure
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
There is a top-level sysfs directory named 'class'.
|
||||
There is a top-level sysfs directory named 'class'.
|
||||
|
||||
Each class gets a directory in the class directory, along with two
|
||||
default subdirectories:
|
||||
default subdirectories::
|
||||
|
||||
class/
|
||||
`-- input
|
||||
@@ -89,8 +89,8 @@ default subdirectories:
|
||||
`-- drivers
|
||||
|
||||
|
||||
Drivers registered with the class get a symlink in the drivers/ directory
|
||||
that points to the driver's directory (under its bus directory):
|
||||
Drivers registered with the class get a symlink in the drivers/ directory
|
||||
that points to the driver's directory (under its bus directory)::
|
||||
|
||||
class/
|
||||
`-- input
|
||||
@@ -99,8 +99,8 @@ that points to the driver's directory (under its bus directory):
|
||||
`-- usb:usb_mouse -> ../../../bus/drivers/usb_mouse/
|
||||
|
||||
|
||||
Each device gets a symlink in the devices/ directory that points to the
|
||||
device's directory in the physical hierarchy:
|
||||
Each device gets a symlink in the devices/ directory that points to the
|
||||
device's directory in the physical hierarchy::
|
||||
|
||||
class/
|
||||
`-- input
|
||||
@@ -111,37 +111,39 @@ device's directory in the physical hierarchy:
|
||||
|
||||
Exporting Attributes
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
struct devclass_attribute {
|
||||
|
||||
::
|
||||
|
||||
struct devclass_attribute {
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct device_class *, char * buf, size_t count, loff_t off);
|
||||
ssize_t (*store)(struct device_class *, const char * buf, size_t count, loff_t off);
|
||||
};
|
||||
};
|
||||
|
||||
Class drivers can export attributes using the DEVCLASS_ATTR macro that works
|
||||
similarly to the DEVICE_ATTR macro for devices. For example, a definition
|
||||
like this:
|
||||
similarly to the DEVICE_ATTR macro for devices. For example, a definition
|
||||
like this::
|
||||
|
||||
static DEVCLASS_ATTR(debug,0644,show_debug,store_debug);
|
||||
static DEVCLASS_ATTR(debug,0644,show_debug,store_debug);
|
||||
|
||||
is equivalent to declaring:
|
||||
is equivalent to declaring::
|
||||
|
||||
static devclass_attribute devclass_attr_debug;
|
||||
static devclass_attribute devclass_attr_debug;
|
||||
|
||||
The bus driver can add and remove the attribute from the class's
|
||||
sysfs directory using:
|
||||
sysfs directory using::
|
||||
|
||||
int devclass_create_file(struct device_class *, struct devclass_attribute *);
|
||||
void devclass_remove_file(struct device_class *, struct devclass_attribute *);
|
||||
int devclass_create_file(struct device_class *, struct devclass_attribute *);
|
||||
void devclass_remove_file(struct device_class *, struct devclass_attribute *);
|
||||
|
||||
In the example above, the file will be named 'debug' in placed in the
|
||||
class's directory in sysfs.
|
||||
class's directory in sysfs.
|
||||
|
||||
|
||||
Interfaces
|
||||
~~~~~~~~~~
|
||||
There may exist multiple mechanisms for accessing the same device of a
|
||||
particular class type. Device interfaces describe these mechanisms.
|
||||
particular class type. Device interfaces describe these mechanisms.
|
||||
|
||||
When a device is added to a device class, the core attempts to add it
|
||||
to every interface that is registered with the device class.
|
||||
|
@@ -1,6 +1,6 @@
|
||||
|
||||
=============================
|
||||
Device Driver Design Patterns
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
=============================
|
||||
|
||||
This document describes a few common design patterns found in device drivers.
|
||||
It is likely that subsystem maintainers will ask driver developers to
|
||||
@@ -19,23 +19,23 @@ that the device the driver binds to will appear in several instances. This
|
||||
means that the probe() function and all callbacks need to be reentrant.
|
||||
|
||||
The most common way to achieve this is to use the state container design
|
||||
pattern. It usually has this form:
|
||||
pattern. It usually has this form::
|
||||
|
||||
struct foo {
|
||||
spinlock_t lock; /* Example member */
|
||||
(...)
|
||||
};
|
||||
struct foo {
|
||||
spinlock_t lock; /* Example member */
|
||||
(...)
|
||||
};
|
||||
|
||||
static int foo_probe(...)
|
||||
{
|
||||
struct foo *foo;
|
||||
static int foo_probe(...)
|
||||
{
|
||||
struct foo *foo;
|
||||
|
||||
foo = devm_kzalloc(dev, sizeof(*foo), GFP_KERNEL);
|
||||
if (!foo)
|
||||
return -ENOMEM;
|
||||
spin_lock_init(&foo->lock);
|
||||
(...)
|
||||
}
|
||||
foo = devm_kzalloc(dev, sizeof(*foo), GFP_KERNEL);
|
||||
if (!foo)
|
||||
return -ENOMEM;
|
||||
spin_lock_init(&foo->lock);
|
||||
(...)
|
||||
}
|
||||
|
||||
This will create an instance of struct foo in memory every time probe() is
|
||||
called. This is our state container for this instance of the device driver.
|
||||
@@ -43,21 +43,21 @@ Of course it is then necessary to always pass this instance of the
|
||||
state around to all functions that need access to the state and its members.
|
||||
|
||||
For example, if the driver is registering an interrupt handler, you would
|
||||
pass around a pointer to struct foo like this:
|
||||
pass around a pointer to struct foo like this::
|
||||
|
||||
static irqreturn_t foo_handler(int irq, void *arg)
|
||||
{
|
||||
struct foo *foo = arg;
|
||||
(...)
|
||||
}
|
||||
static irqreturn_t foo_handler(int irq, void *arg)
|
||||
{
|
||||
struct foo *foo = arg;
|
||||
(...)
|
||||
}
|
||||
|
||||
static int foo_probe(...)
|
||||
{
|
||||
struct foo *foo;
|
||||
static int foo_probe(...)
|
||||
{
|
||||
struct foo *foo;
|
||||
|
||||
(...)
|
||||
ret = request_irq(irq, foo_handler, 0, "foo", foo);
|
||||
}
|
||||
(...)
|
||||
ret = request_irq(irq, foo_handler, 0, "foo", foo);
|
||||
}
|
||||
|
||||
This way you always get a pointer back to the correct instance of foo in
|
||||
your interrupt handler.
|
||||
@@ -66,38 +66,38 @@ your interrupt handler.
|
||||
2. container_of()
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
Continuing on the above example we add an offloaded work:
|
||||
Continuing on the above example we add an offloaded work::
|
||||
|
||||
struct foo {
|
||||
spinlock_t lock;
|
||||
struct workqueue_struct *wq;
|
||||
struct work_struct offload;
|
||||
(...)
|
||||
};
|
||||
struct foo {
|
||||
spinlock_t lock;
|
||||
struct workqueue_struct *wq;
|
||||
struct work_struct offload;
|
||||
(...)
|
||||
};
|
||||
|
||||
static void foo_work(struct work_struct *work)
|
||||
{
|
||||
struct foo *foo = container_of(work, struct foo, offload);
|
||||
static void foo_work(struct work_struct *work)
|
||||
{
|
||||
struct foo *foo = container_of(work, struct foo, offload);
|
||||
|
||||
(...)
|
||||
}
|
||||
(...)
|
||||
}
|
||||
|
||||
static irqreturn_t foo_handler(int irq, void *arg)
|
||||
{
|
||||
struct foo *foo = arg;
|
||||
static irqreturn_t foo_handler(int irq, void *arg)
|
||||
{
|
||||
struct foo *foo = arg;
|
||||
|
||||
queue_work(foo->wq, &foo->offload);
|
||||
(...)
|
||||
}
|
||||
queue_work(foo->wq, &foo->offload);
|
||||
(...)
|
||||
}
|
||||
|
||||
static int foo_probe(...)
|
||||
{
|
||||
struct foo *foo;
|
||||
static int foo_probe(...)
|
||||
{
|
||||
struct foo *foo;
|
||||
|
||||
foo->wq = create_singlethread_workqueue("foo-wq");
|
||||
INIT_WORK(&foo->offload, foo_work);
|
||||
(...)
|
||||
}
|
||||
foo->wq = create_singlethread_workqueue("foo-wq");
|
||||
INIT_WORK(&foo->offload, foo_work);
|
||||
(...)
|
||||
}
|
||||
|
||||
The design pattern is the same for an hrtimer or something similar that will
|
||||
return a single argument which is a pointer to a struct member in the
|
@@ -1,6 +1,6 @@
|
||||
|
||||
==========================
|
||||
The Basic Device Structure
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
==========================
|
||||
|
||||
See the kerneldoc for the struct device.
|
||||
|
||||
@@ -8,9 +8,9 @@ See the kerneldoc for the struct device.
|
||||
Programming Interface
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
The bus driver that discovers the device uses this to register the
|
||||
device with the core:
|
||||
device with the core::
|
||||
|
||||
int device_register(struct device * dev);
|
||||
int device_register(struct device * dev);
|
||||
|
||||
The bus should initialize the following fields:
|
||||
|
||||
@@ -20,30 +20,33 @@ The bus should initialize the following fields:
|
||||
- bus
|
||||
|
||||
A device is removed from the core when its reference count goes to
|
||||
0. The reference count can be adjusted using:
|
||||
0. The reference count can be adjusted using::
|
||||
|
||||
struct device * get_device(struct device * dev);
|
||||
void put_device(struct device * dev);
|
||||
struct device * get_device(struct device * dev);
|
||||
void put_device(struct device * dev);
|
||||
|
||||
get_device() will return a pointer to the struct device passed to it
|
||||
if the reference is not already 0 (if it's in the process of being
|
||||
removed already).
|
||||
|
||||
A driver can access the lock in the device structure using:
|
||||
A driver can access the lock in the device structure using::
|
||||
|
||||
void lock_device(struct device * dev);
|
||||
void unlock_device(struct device * dev);
|
||||
void lock_device(struct device * dev);
|
||||
void unlock_device(struct device * dev);
|
||||
|
||||
|
||||
Attributes
|
||||
~~~~~~~~~~
|
||||
struct device_attribute {
|
||||
|
||||
::
|
||||
|
||||
struct device_attribute {
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct device *dev, struct device_attribute *attr,
|
||||
char *buf);
|
||||
ssize_t (*store)(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count);
|
||||
};
|
||||
};
|
||||
|
||||
Attributes of devices can be exported by a device driver through sysfs.
|
||||
|
||||
@@ -54,39 +57,39 @@ As explained in Documentation/kobject.txt, device attributes must be
|
||||
created before the KOBJ_ADD uevent is generated. The only way to realize
|
||||
that is by defining an attribute group.
|
||||
|
||||
Attributes are declared using a macro called DEVICE_ATTR:
|
||||
Attributes are declared using a macro called DEVICE_ATTR::
|
||||
|
||||
#define DEVICE_ATTR(name,mode,show,store)
|
||||
#define DEVICE_ATTR(name,mode,show,store)
|
||||
|
||||
Example:
|
||||
Example:::
|
||||
|
||||
static DEVICE_ATTR(type, 0444, show_type, NULL);
|
||||
static DEVICE_ATTR(power, 0644, show_power, store_power);
|
||||
static DEVICE_ATTR(type, 0444, show_type, NULL);
|
||||
static DEVICE_ATTR(power, 0644, show_power, store_power);
|
||||
|
||||
This declares two structures of type struct device_attribute with respective
|
||||
names 'dev_attr_type' and 'dev_attr_power'. These two attributes can be
|
||||
organized as follows into a group:
|
||||
organized as follows into a group::
|
||||
|
||||
static struct attribute *dev_attrs[] = {
|
||||
static struct attribute *dev_attrs[] = {
|
||||
&dev_attr_type.attr,
|
||||
&dev_attr_power.attr,
|
||||
NULL,
|
||||
};
|
||||
};
|
||||
|
||||
static struct attribute_group dev_attr_group = {
|
||||
static struct attribute_group dev_attr_group = {
|
||||
.attrs = dev_attrs,
|
||||
};
|
||||
};
|
||||
|
||||
static const struct attribute_group *dev_attr_groups[] = {
|
||||
static const struct attribute_group *dev_attr_groups[] = {
|
||||
&dev_attr_group,
|
||||
NULL,
|
||||
};
|
||||
};
|
||||
|
||||
This array of groups can then be associated with a device by setting the
|
||||
group pointer in struct device before device_register() is invoked:
|
||||
group pointer in struct device before device_register() is invoked::
|
||||
|
||||
dev->groups = dev_attr_groups;
|
||||
device_register(dev);
|
||||
dev->groups = dev_attr_groups;
|
||||
device_register(dev);
|
||||
|
||||
The device_register() function will use the 'groups' pointer to create the
|
||||
device attributes and the device_unregister() function will use this pointer
|
@@ -1,3 +1,4 @@
|
||||
================================
|
||||
Devres - Managed Device Resource
|
||||
================================
|
||||
|
||||
@@ -5,17 +6,18 @@ Tejun Heo <teheo@suse.de>
|
||||
|
||||
First draft 10 January 2007
|
||||
|
||||
.. contents
|
||||
|
||||
1. Intro : Huh? Devres?
|
||||
2. Devres : Devres in a nutshell
|
||||
3. Devres Group : Group devres'es and release them together
|
||||
4. Details : Life time rules, calling context, ...
|
||||
5. Overhead : How much do we have to pay for this?
|
||||
6. List of managed interfaces : Currently implemented managed interfaces
|
||||
1. Intro : Huh? Devres?
|
||||
2. Devres : Devres in a nutshell
|
||||
3. Devres Group : Group devres'es and release them together
|
||||
4. Details : Life time rules, calling context, ...
|
||||
5. Overhead : How much do we have to pay for this?
|
||||
6. List of managed interfaces: Currently implemented managed interfaces
|
||||
|
||||
|
||||
1. Intro
|
||||
--------
|
||||
1. Intro
|
||||
--------
|
||||
|
||||
devres came up while trying to convert libata to use iomap. Each
|
||||
iomapped address should be kept and unmapped on driver detach. For
|
||||
@@ -42,8 +44,8 @@ would leak resources or even cause oops when failure occurs. iomap
|
||||
adds more to this mix. So do msi and msix.
|
||||
|
||||
|
||||
2. Devres
|
||||
---------
|
||||
2. Devres
|
||||
---------
|
||||
|
||||
devres is basically linked list of arbitrarily sized memory areas
|
||||
associated with a struct device. Each devres entry is associated with
|
||||
@@ -58,7 +60,7 @@ using dma_alloc_coherent(). The managed version is called
|
||||
dmam_alloc_coherent(). It is identical to dma_alloc_coherent() except
|
||||
for the DMA memory allocated using it is managed and will be
|
||||
automatically released on driver detach. Implementation looks like
|
||||
the following.
|
||||
the following::
|
||||
|
||||
struct dma_devres {
|
||||
size_t size;
|
||||
@@ -98,7 +100,7 @@ If a driver uses dmam_alloc_coherent(), the area is guaranteed to be
|
||||
freed whether initialization fails half-way or the device gets
|
||||
detached. If most resources are acquired using managed interface, a
|
||||
driver can have much simpler init and exit code. Init path basically
|
||||
looks like the following.
|
||||
looks like the following::
|
||||
|
||||
my_init_one()
|
||||
{
|
||||
@@ -119,7 +121,7 @@ looks like the following.
|
||||
return register_to_upper_layer(d);
|
||||
}
|
||||
|
||||
And exit path,
|
||||
And exit path::
|
||||
|
||||
my_remove_one()
|
||||
{
|
||||
@@ -140,13 +142,13 @@ on you. In some cases this may mean introducing checks that were not
|
||||
necessary before moving to the managed devm_* calls.
|
||||
|
||||
|
||||
3. Devres group
|
||||
---------------
|
||||
3. Devres group
|
||||
---------------
|
||||
|
||||
Devres entries can be grouped using devres group. When a group is
|
||||
released, all contained normal devres entries and properly nested
|
||||
groups are released. One usage is to rollback series of acquired
|
||||
resources on failure. For example,
|
||||
resources on failure. For example::
|
||||
|
||||
if (!devres_open_group(dev, NULL, GFP_KERNEL))
|
||||
return -ENOMEM;
|
||||
@@ -172,7 +174,7 @@ like above are usually useful in midlayer driver (e.g. libata core
|
||||
layer) where interface function shouldn't have side effect on failure.
|
||||
For LLDs, just returning error code suffices in most cases.
|
||||
|
||||
Each group is identified by void *id. It can either be explicitly
|
||||
Each group is identified by `void *id`. It can either be explicitly
|
||||
specified by @id argument to devres_open_group() or automatically
|
||||
created by passing NULL as @id as in the above example. In both
|
||||
cases, devres_open_group() returns the group's id. The returned id
|
||||
@@ -180,7 +182,7 @@ can be passed to other devres functions to select the target group.
|
||||
If NULL is given to those functions, the latest open group is
|
||||
selected.
|
||||
|
||||
For example, you can do something like the following.
|
||||
For example, you can do something like the following::
|
||||
|
||||
int my_midlayer_create_something()
|
||||
{
|
||||
@@ -199,8 +201,8 @@ For example, you can do something like the following.
|
||||
}
|
||||
|
||||
|
||||
4. Details
|
||||
----------
|
||||
4. Details
|
||||
----------
|
||||
|
||||
Lifetime of a devres entry begins on devres allocation and finishes
|
||||
when it is released or destroyed (removed and freed) - no reference
|
||||
@@ -220,8 +222,8 @@ All devres interface functions can be called without context if the
|
||||
right gfp mask is given.
|
||||
|
||||
|
||||
5. Overhead
|
||||
-----------
|
||||
5. Overhead
|
||||
-----------
|
||||
|
||||
Each devres bookkeeping info is allocated together with requested data
|
||||
area. With debug option turned off, bookkeeping info occupies 16
|
||||
@@ -237,8 +239,8 @@ and 400 bytes on 32bit machine after naive conversion (we can
|
||||
certainly invest a bit more effort into libata core layer).
|
||||
|
||||
|
||||
6. List of managed interfaces
|
||||
-----------------------------
|
||||
6. List of managed interfaces
|
||||
-----------------------------
|
||||
|
||||
CLOCK
|
||||
devm_clk_get()
|
@@ -1,5 +1,6 @@
|
||||
|
||||
==============
|
||||
Device Drivers
|
||||
==============
|
||||
|
||||
See the kerneldoc for the struct device_driver.
|
||||
|
||||
@@ -26,50 +27,50 @@ Declaration
|
||||
As stated above, struct device_driver objects are statically
|
||||
allocated. Below is an example declaration of the eepro100
|
||||
driver. This declaration is hypothetical only; it relies on the driver
|
||||
being converted completely to the new model.
|
||||
being converted completely to the new model::
|
||||
|
||||
static struct device_driver eepro100_driver = {
|
||||
.name = "eepro100",
|
||||
.bus = &pci_bus_type,
|
||||
|
||||
.probe = eepro100_probe,
|
||||
.remove = eepro100_remove,
|
||||
.suspend = eepro100_suspend,
|
||||
.resume = eepro100_resume,
|
||||
};
|
||||
static struct device_driver eepro100_driver = {
|
||||
.name = "eepro100",
|
||||
.bus = &pci_bus_type,
|
||||
|
||||
.probe = eepro100_probe,
|
||||
.remove = eepro100_remove,
|
||||
.suspend = eepro100_suspend,
|
||||
.resume = eepro100_resume,
|
||||
};
|
||||
|
||||
Most drivers will not be able to be converted completely to the new
|
||||
model because the bus they belong to has a bus-specific structure with
|
||||
bus-specific fields that cannot be generalized.
|
||||
bus-specific fields that cannot be generalized.
|
||||
|
||||
The most common example of this are device ID structures. A driver
|
||||
typically defines an array of device IDs that it supports. The format
|
||||
of these structures and the semantics for comparing device IDs are
|
||||
completely bus-specific. Defining them as bus-specific entities would
|
||||
sacrifice type-safety, so we keep bus-specific structures around.
|
||||
sacrifice type-safety, so we keep bus-specific structures around.
|
||||
|
||||
Bus-specific drivers should include a generic struct device_driver in
|
||||
the definition of the bus-specific driver. Like this:
|
||||
the definition of the bus-specific driver. Like this::
|
||||
|
||||
struct pci_driver {
|
||||
const struct pci_device_id *id_table;
|
||||
struct device_driver driver;
|
||||
};
|
||||
struct pci_driver {
|
||||
const struct pci_device_id *id_table;
|
||||
struct device_driver driver;
|
||||
};
|
||||
|
||||
A definition that included bus-specific fields would look like
|
||||
(using the eepro100 driver again):
|
||||
(using the eepro100 driver again)::
|
||||
|
||||
static struct pci_driver eepro100_driver = {
|
||||
.id_table = eepro100_pci_tbl,
|
||||
.driver = {
|
||||
static struct pci_driver eepro100_driver = {
|
||||
.id_table = eepro100_pci_tbl,
|
||||
.driver = {
|
||||
.name = "eepro100",
|
||||
.bus = &pci_bus_type,
|
||||
.probe = eepro100_probe,
|
||||
.remove = eepro100_remove,
|
||||
.suspend = eepro100_suspend,
|
||||
.resume = eepro100_resume,
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
Some may find the syntax of embedded struct initialization awkward or
|
||||
even a bit ugly. So far, it's the best way we've found to do what we want...
|
||||
@@ -77,12 +78,14 @@ even a bit ugly. So far, it's the best way we've found to do what we want...
|
||||
Registration
|
||||
~~~~~~~~~~~~
|
||||
|
||||
int driver_register(struct device_driver * drv);
|
||||
::
|
||||
|
||||
int driver_register(struct device_driver *drv);
|
||||
|
||||
The driver registers the structure on startup. For drivers that have
|
||||
no bus-specific fields (i.e. don't have a bus-specific driver
|
||||
structure), they would use driver_register and pass a pointer to their
|
||||
struct device_driver object.
|
||||
struct device_driver object.
|
||||
|
||||
Most drivers, however, will have a bus-specific structure and will
|
||||
need to register with the bus using something like pci_driver_register.
|
||||
@@ -101,7 +104,7 @@ By defining wrapper functions, the transition to the new model can be
|
||||
made easier. Drivers can ignore the generic structure altogether and
|
||||
let the bus wrapper fill in the fields. For the callbacks, the bus can
|
||||
define generic callbacks that forward the call to the bus-specific
|
||||
callbacks of the drivers.
|
||||
callbacks of the drivers.
|
||||
|
||||
This solution is intended to be only temporary. In order to get class
|
||||
information in the driver, the drivers must be modified anyway. Since
|
||||
@@ -113,16 +116,16 @@ Access
|
||||
~~~~~~
|
||||
|
||||
Once the object has been registered, it may access the common fields of
|
||||
the object, like the lock and the list of devices.
|
||||
the object, like the lock and the list of devices::
|
||||
|
||||
int driver_for_each_dev(struct device_driver * drv, void * data,
|
||||
int (*callback)(struct device * dev, void * data));
|
||||
int driver_for_each_dev(struct device_driver *drv, void *data,
|
||||
int (*callback)(struct device *dev, void *data));
|
||||
|
||||
The devices field is a list of all the devices that have been bound to
|
||||
the driver. The LDM core provides a helper function to operate on all
|
||||
the devices a driver controls. This helper locks the driver on each
|
||||
node access, and does proper reference counting on each device as it
|
||||
accesses it.
|
||||
accesses it.
|
||||
|
||||
|
||||
sysfs
|
||||
@@ -142,7 +145,9 @@ supports.
|
||||
Callbacks
|
||||
~~~~~~~~~
|
||||
|
||||
int (*probe) (struct device * dev);
|
||||
::
|
||||
|
||||
int (*probe) (struct device *dev);
|
||||
|
||||
The probe() entry is called in task context, with the bus's rwsem locked
|
||||
and the driver partially bound to the device. Drivers commonly use
|
||||
@@ -162,9 +167,9 @@ the driver to that device.
|
||||
|
||||
A driver's probe() may return a negative errno value to indicate that
|
||||
the driver did not bind to this device, in which case it should have
|
||||
released all resources it allocated.
|
||||
released all resources it allocated::
|
||||
|
||||
int (*remove) (struct device * dev);
|
||||
int (*remove) (struct device *dev);
|
||||
|
||||
remove is called to unbind a driver from a device. This may be
|
||||
called if a device is physically removed from the system, if the
|
||||
@@ -173,43 +178,46 @@ in other cases.
|
||||
|
||||
It is up to the driver to determine if the device is present or
|
||||
not. It should free any resources allocated specifically for the
|
||||
device; i.e. anything in the device's driver_data field.
|
||||
device; i.e. anything in the device's driver_data field.
|
||||
|
||||
If the device is still present, it should quiesce the device and place
|
||||
it into a supported low-power state.
|
||||
it into a supported low-power state::
|
||||
|
||||
int (*suspend) (struct device * dev, pm_message_t state);
|
||||
int (*suspend) (struct device *dev, pm_message_t state);
|
||||
|
||||
suspend is called to put the device in a low power state.
|
||||
suspend is called to put the device in a low power state::
|
||||
|
||||
int (*resume) (struct device * dev);
|
||||
int (*resume) (struct device *dev);
|
||||
|
||||
Resume is used to bring a device back from a low power state.
|
||||
|
||||
|
||||
Attributes
|
||||
~~~~~~~~~~
|
||||
struct driver_attribute {
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct device_driver *driver, char *buf);
|
||||
ssize_t (*store)(struct device_driver *, const char * buf, size_t count);
|
||||
};
|
||||
|
||||
Device drivers can export attributes via their sysfs directories.
|
||||
::
|
||||
|
||||
struct driver_attribute {
|
||||
struct attribute attr;
|
||||
ssize_t (*show)(struct device_driver *driver, char *buf);
|
||||
ssize_t (*store)(struct device_driver *, const char *buf, size_t count);
|
||||
};
|
||||
|
||||
Device drivers can export attributes via their sysfs directories.
|
||||
Drivers can declare attributes using a DRIVER_ATTR_RW and DRIVER_ATTR_RO
|
||||
macro that works identically to the DEVICE_ATTR_RW and DEVICE_ATTR_RO
|
||||
macros.
|
||||
|
||||
Example:
|
||||
Example::
|
||||
|
||||
DRIVER_ATTR_RW(debug);
|
||||
DRIVER_ATTR_RW(debug);
|
||||
|
||||
This is equivalent to declaring:
|
||||
This is equivalent to declaring::
|
||||
|
||||
struct driver_attribute driver_attr_debug;
|
||||
struct driver_attribute driver_attr_debug;
|
||||
|
||||
This can then be used to add and remove the attribute from the
|
||||
driver's directory using:
|
||||
driver's directory using::
|
||||
|
||||
int driver_create_file(struct device_driver *, const struct driver_attribute *);
|
||||
void driver_remove_file(struct device_driver *, const struct driver_attribute *);
|
||||
int driver_create_file(struct device_driver *, const struct driver_attribute *);
|
||||
void driver_remove_file(struct device_driver *, const struct driver_attribute *);
|
26
Documentation/driver-model/index.rst
Normal file
26
Documentation/driver-model/index.rst
Normal file
@@ -0,0 +1,26 @@
|
||||
:orphan:
|
||||
|
||||
============
|
||||
Driver Model
|
||||
============
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
binding
|
||||
bus
|
||||
class
|
||||
design-patterns
|
||||
device
|
||||
devres
|
||||
driver
|
||||
overview
|
||||
platform
|
||||
porting
|
||||
|
||||
.. only:: subproject and html
|
||||
|
||||
Indices
|
||||
=======
|
||||
|
||||
* :ref:`genindex`
|
@@ -1,4 +1,6 @@
|
||||
=============================
|
||||
The Linux Kernel Device Model
|
||||
=============================
|
||||
|
||||
Patrick Mochel <mochel@digitalimplant.org>
|
||||
|
||||
@@ -41,14 +43,14 @@ data structure. These fields must still be accessed by the bus layers,
|
||||
and sometimes by the device-specific drivers.
|
||||
|
||||
Other bus layers are encouraged to do what has been done for the PCI layer.
|
||||
struct pci_dev now looks like this:
|
||||
struct pci_dev now looks like this::
|
||||
|
||||
struct pci_dev {
|
||||
struct pci_dev {
|
||||
...
|
||||
|
||||
struct device dev; /* Generic device interface */
|
||||
...
|
||||
};
|
||||
};
|
||||
|
||||
Note first that the struct device dev within the struct pci_dev is
|
||||
statically allocated. This means only one allocation on device discovery.
|
||||
@@ -80,26 +82,26 @@ easy. This has been accomplished by implementing a special purpose virtual
|
||||
file system named sysfs.
|
||||
|
||||
Almost all mainstream Linux distros mount this filesystem automatically; you
|
||||
can see some variation of the following in the output of the "mount" command:
|
||||
can see some variation of the following in the output of the "mount" command::
|
||||
|
||||
$ mount
|
||||
...
|
||||
none on /sys type sysfs (rw,noexec,nosuid,nodev)
|
||||
...
|
||||
$
|
||||
$ mount
|
||||
...
|
||||
none on /sys type sysfs (rw,noexec,nosuid,nodev)
|
||||
...
|
||||
$
|
||||
|
||||
The auto-mounting of sysfs is typically accomplished by an entry similar to
|
||||
the following in the /etc/fstab file:
|
||||
the following in the /etc/fstab file::
|
||||
|
||||
none /sys sysfs defaults 0 0
|
||||
none /sys sysfs defaults 0 0
|
||||
|
||||
or something similar in the /lib/init/fstab file on Debian-based systems:
|
||||
or something similar in the /lib/init/fstab file on Debian-based systems::
|
||||
|
||||
none /sys sysfs nodev,noexec,nosuid 0 0
|
||||
none /sys sysfs nodev,noexec,nosuid 0 0
|
||||
|
||||
If sysfs is not automatically mounted, you can always do it manually with:
|
||||
If sysfs is not automatically mounted, you can always do it manually with::
|
||||
|
||||
# mount -t sysfs sysfs /sys
|
||||
# mount -t sysfs sysfs /sys
|
||||
|
||||
Whenever a device is inserted into the tree, a directory is created for it.
|
||||
This directory may be populated at each layer of discovery - the global layer,
|
||||
@@ -108,7 +110,7 @@ the bus layer, or the device layer.
|
||||
The global layer currently creates two files - 'name' and 'power'. The
|
||||
former only reports the name of the device. The latter reports the
|
||||
current power state of the device. It will also be used to set the current
|
||||
power state.
|
||||
power state.
|
||||
|
||||
The bus layer may also create files for the devices it finds while probing the
|
||||
bus. For example, the PCI layer currently creates 'irq' and 'resource' files
|
||||
@@ -118,6 +120,5 @@ A device-specific driver may also export files in its directory to expose
|
||||
device-specific data or tunable interfaces.
|
||||
|
||||
More information about the sysfs directory layout can be found in
|
||||
the other documents in this directory and in the file
|
||||
the other documents in this directory and in the file
|
||||
Documentation/filesystems/sysfs.txt.
|
||||
|
@@ -1,5 +1,7 @@
|
||||
============================
|
||||
Platform Devices and Drivers
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
============================
|
||||
|
||||
See <linux/platform_device.h> for the driver model interface to the
|
||||
platform bus: platform_device, and platform_driver. This pseudo-bus
|
||||
is used to connect devices on busses with minimal infrastructure,
|
||||
@@ -19,15 +21,15 @@ be connected through a segment of some other kind of bus; but its
|
||||
registers will still be directly addressable.
|
||||
|
||||
Platform devices are given a name, used in driver binding, and a
|
||||
list of resources such as addresses and IRQs.
|
||||
list of resources such as addresses and IRQs::
|
||||
|
||||
struct platform_device {
|
||||
struct platform_device {
|
||||
const char *name;
|
||||
u32 id;
|
||||
struct device dev;
|
||||
u32 num_resources;
|
||||
struct resource *resource;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Platform drivers
|
||||
@@ -35,9 +37,9 @@ Platform drivers
|
||||
Platform drivers follow the standard driver model convention, where
|
||||
discovery/enumeration is handled outside the drivers, and drivers
|
||||
provide probe() and remove() methods. They support power management
|
||||
and shutdown notifications using the standard conventions.
|
||||
and shutdown notifications using the standard conventions::
|
||||
|
||||
struct platform_driver {
|
||||
struct platform_driver {
|
||||
int (*probe)(struct platform_device *);
|
||||
int (*remove)(struct platform_device *);
|
||||
void (*shutdown)(struct platform_device *);
|
||||
@@ -46,25 +48,25 @@ struct platform_driver {
|
||||
int (*resume_early)(struct platform_device *);
|
||||
int (*resume)(struct platform_device *);
|
||||
struct device_driver driver;
|
||||
};
|
||||
};
|
||||
|
||||
Note that probe() should in general verify that the specified device hardware
|
||||
actually exists; sometimes platform setup code can't be sure. The probing
|
||||
can use device resources, including clocks, and device platform_data.
|
||||
|
||||
Platform drivers register themselves the normal way:
|
||||
Platform drivers register themselves the normal way::
|
||||
|
||||
int platform_driver_register(struct platform_driver *drv);
|
||||
|
||||
Or, in common situations where the device is known not to be hot-pluggable,
|
||||
the probe() routine can live in an init section to reduce the driver's
|
||||
runtime memory footprint:
|
||||
runtime memory footprint::
|
||||
|
||||
int platform_driver_probe(struct platform_driver *drv,
|
||||
int (*probe)(struct platform_device *))
|
||||
|
||||
Kernel modules can be composed of several platform drivers. The platform core
|
||||
provides helpers to register and unregister an array of drivers:
|
||||
provides helpers to register and unregister an array of drivers::
|
||||
|
||||
int __platform_register_drivers(struct platform_driver * const *drivers,
|
||||
unsigned int count, struct module *owner);
|
||||
@@ -73,7 +75,7 @@ provides helpers to register and unregister an array of drivers:
|
||||
|
||||
If one of the drivers fails to register, all drivers registered up to that
|
||||
point will be unregistered in reverse order. Note that there is a convenience
|
||||
macro that passes THIS_MODULE as owner parameter:
|
||||
macro that passes THIS_MODULE as owner parameter::
|
||||
|
||||
#define platform_register_drivers(drivers, count)
|
||||
|
||||
@@ -81,7 +83,7 @@ macro that passes THIS_MODULE as owner parameter:
|
||||
Device Enumeration
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
As a rule, platform specific (and often board-specific) setup code will
|
||||
register platform devices:
|
||||
register platform devices::
|
||||
|
||||
int platform_device_register(struct platform_device *pdev);
|
||||
|
||||
@@ -133,14 +135,14 @@ tend to already have "normal" modes, such as ones using device nodes that
|
||||
were created by PNP or by platform device setup.
|
||||
|
||||
None the less, there are some APIs to support such legacy drivers. Avoid
|
||||
using these calls except with such hotplug-deficient drivers.
|
||||
using these calls except with such hotplug-deficient drivers::
|
||||
|
||||
struct platform_device *platform_device_alloc(
|
||||
const char *name, int id);
|
||||
|
||||
You can use platform_device_alloc() to dynamically allocate a device, which
|
||||
you will then initialize with resources and platform_device_register().
|
||||
A better solution is usually:
|
||||
A better solution is usually::
|
||||
|
||||
struct platform_device *platform_device_register_simple(
|
||||
const char *name, int id,
|
@@ -1,5 +1,6 @@
|
||||
|
||||
=======================================
|
||||
Porting Drivers to the New Driver Model
|
||||
=======================================
|
||||
|
||||
Patrick Mochel
|
||||
|
||||
@@ -8,8 +9,8 @@ Patrick Mochel
|
||||
|
||||
Overview
|
||||
|
||||
Please refer to Documentation/driver-model/*.txt for definitions of
|
||||
various driver types and concepts.
|
||||
Please refer to `Documentation/driver-model/*.rst` for definitions of
|
||||
various driver types and concepts.
|
||||
|
||||
Most of the work of porting devices drivers to the new model happens
|
||||
at the bus driver layer. This was intentional, to minimize the
|
||||
@@ -18,11 +19,11 @@ of bus drivers.
|
||||
|
||||
In a nutshell, the driver model consists of a set of objects that can
|
||||
be embedded in larger, bus-specific objects. Fields in these generic
|
||||
objects can replace fields in the bus-specific objects.
|
||||
objects can replace fields in the bus-specific objects.
|
||||
|
||||
The generic objects must be registered with the driver model core. By
|
||||
doing so, they will exported via the sysfs filesystem. sysfs can be
|
||||
mounted by doing
|
||||
mounted by doing::
|
||||
|
||||
# mount -t sysfs sysfs /sys
|
||||
|
||||
@@ -30,108 +31,109 @@ mounted by doing
|
||||
|
||||
The Process
|
||||
|
||||
Step 0: Read include/linux/device.h for object and function definitions.
|
||||
Step 0: Read include/linux/device.h for object and function definitions.
|
||||
|
||||
Step 1: Registering the bus driver.
|
||||
Step 1: Registering the bus driver.
|
||||
|
||||
|
||||
- Define a struct bus_type for the bus driver.
|
||||
- Define a struct bus_type for the bus driver::
|
||||
|
||||
struct bus_type pci_bus_type = {
|
||||
.name = "pci",
|
||||
};
|
||||
struct bus_type pci_bus_type = {
|
||||
.name = "pci",
|
||||
};
|
||||
|
||||
|
||||
- Register the bus type.
|
||||
|
||||
This should be done in the initialization function for the bus type,
|
||||
which is usually the module_init(), or equivalent, function.
|
||||
which is usually the module_init(), or equivalent, function::
|
||||
|
||||
static int __init pci_driver_init(void)
|
||||
{
|
||||
return bus_register(&pci_bus_type);
|
||||
}
|
||||
static int __init pci_driver_init(void)
|
||||
{
|
||||
return bus_register(&pci_bus_type);
|
||||
}
|
||||
|
||||
subsys_initcall(pci_driver_init);
|
||||
subsys_initcall(pci_driver_init);
|
||||
|
||||
|
||||
The bus type may be unregistered (if the bus driver may be compiled
|
||||
as a module) by doing:
|
||||
as a module) by doing::
|
||||
|
||||
bus_unregister(&pci_bus_type);
|
||||
|
||||
|
||||
- Export the bus type for others to use.
|
||||
- Export the bus type for others to use.
|
||||
|
||||
Other code may wish to reference the bus type, so declare it in a
|
||||
Other code may wish to reference the bus type, so declare it in a
|
||||
shared header file and export the symbol.
|
||||
|
||||
From include/linux/pci.h:
|
||||
From include/linux/pci.h::
|
||||
|
||||
extern struct bus_type pci_bus_type;
|
||||
extern struct bus_type pci_bus_type;
|
||||
|
||||
|
||||
From file the above code appears in:
|
||||
From file the above code appears in::
|
||||
|
||||
EXPORT_SYMBOL(pci_bus_type);
|
||||
EXPORT_SYMBOL(pci_bus_type);
|
||||
|
||||
|
||||
|
||||
- This will cause the bus to show up in /sys/bus/pci/ with two
|
||||
subdirectories: 'devices' and 'drivers'.
|
||||
subdirectories: 'devices' and 'drivers'::
|
||||
|
||||
# tree -d /sys/bus/pci/
|
||||
/sys/bus/pci/
|
||||
|-- devices
|
||||
`-- drivers
|
||||
# tree -d /sys/bus/pci/
|
||||
/sys/bus/pci/
|
||||
|-- devices
|
||||
`-- drivers
|
||||
|
||||
|
||||
|
||||
Step 2: Registering Devices.
|
||||
Step 2: Registering Devices.
|
||||
|
||||
struct device represents a single device. It mainly contains metadata
|
||||
describing the relationship the device has to other entities.
|
||||
describing the relationship the device has to other entities.
|
||||
|
||||
|
||||
- Embed a struct device in the bus-specific device type.
|
||||
- Embed a struct device in the bus-specific device type::
|
||||
|
||||
|
||||
struct pci_dev {
|
||||
...
|
||||
struct device dev; /* Generic device interface */
|
||||
...
|
||||
};
|
||||
struct pci_dev {
|
||||
...
|
||||
struct device dev; /* Generic device interface */
|
||||
...
|
||||
};
|
||||
|
||||
It is recommended that the generic device not be the first item in
|
||||
It is recommended that the generic device not be the first item in
|
||||
the struct to discourage programmers from doing mindless casts
|
||||
between the object types. Instead macros, or inline functions,
|
||||
should be created to convert from the generic object type.
|
||||
should be created to convert from the generic object type::
|
||||
|
||||
|
||||
#define to_pci_dev(n) container_of(n, struct pci_dev, dev)
|
||||
#define to_pci_dev(n) container_of(n, struct pci_dev, dev)
|
||||
|
||||
or
|
||||
or
|
||||
|
||||
static inline struct pci_dev * to_pci_dev(struct kobject * kobj)
|
||||
{
|
||||
static inline struct pci_dev * to_pci_dev(struct kobject * kobj)
|
||||
{
|
||||
return container_of(n, struct pci_dev, dev);
|
||||
}
|
||||
}
|
||||
|
||||
This allows the compiler to verify type-safety of the operations
|
||||
This allows the compiler to verify type-safety of the operations
|
||||
that are performed (which is Good).
|
||||
|
||||
|
||||
- Initialize the device on registration.
|
||||
|
||||
When devices are discovered or registered with the bus type, the
|
||||
When devices are discovered or registered with the bus type, the
|
||||
bus driver should initialize the generic device. The most important
|
||||
things to initialize are the bus_id, parent, and bus fields.
|
||||
|
||||
The bus_id is an ASCII string that contains the device's address on
|
||||
the bus. The format of this string is bus-specific. This is
|
||||
necessary for representing devices in sysfs.
|
||||
necessary for representing devices in sysfs.
|
||||
|
||||
parent is the physical parent of the device. It is important that
|
||||
the bus driver sets this field correctly.
|
||||
the bus driver sets this field correctly.
|
||||
|
||||
The driver model maintains an ordered list of devices that it uses
|
||||
for power management. This list must be in order to guarantee that
|
||||
@@ -140,13 +142,13 @@ static inline struct pci_dev * to_pci_dev(struct kobject * kobj)
|
||||
devices.
|
||||
|
||||
Also, the location of the device's sysfs directory depends on a
|
||||
device's parent. sysfs exports a directory structure that mirrors
|
||||
device's parent. sysfs exports a directory structure that mirrors
|
||||
the device hierarchy. Accurately setting the parent guarantees that
|
||||
sysfs will accurately represent the hierarchy.
|
||||
|
||||
The device's bus field is a pointer to the bus type the device
|
||||
belongs to. This should be set to the bus_type that was declared
|
||||
and initialized before.
|
||||
and initialized before.
|
||||
|
||||
Optionally, the bus driver may set the device's name and release
|
||||
fields.
|
||||
@@ -155,107 +157,107 @@ static inline struct pci_dev * to_pci_dev(struct kobject * kobj)
|
||||
|
||||
"ATI Technologies Inc Radeon QD"
|
||||
|
||||
The release field is a callback that the driver model core calls
|
||||
when the device has been removed, and all references to it have
|
||||
The release field is a callback that the driver model core calls
|
||||
when the device has been removed, and all references to it have
|
||||
been released. More on this in a moment.
|
||||
|
||||
|
||||
- Register the device.
|
||||
- Register the device.
|
||||
|
||||
Once the generic device has been initialized, it can be registered
|
||||
with the driver model core by doing:
|
||||
with the driver model core by doing::
|
||||
|
||||
device_register(&dev->dev);
|
||||
|
||||
It can later be unregistered by doing:
|
||||
It can later be unregistered by doing::
|
||||
|
||||
device_unregister(&dev->dev);
|
||||
|
||||
This should happen on buses that support hotpluggable devices.
|
||||
This should happen on buses that support hotpluggable devices.
|
||||
If a bus driver unregisters a device, it should not immediately free
|
||||
it. It should instead wait for the driver model core to call the
|
||||
device's release method, then free the bus-specific object.
|
||||
it. It should instead wait for the driver model core to call the
|
||||
device's release method, then free the bus-specific object.
|
||||
(There may be other code that is currently referencing the device
|
||||
structure, and it would be rude to free the device while that is
|
||||
structure, and it would be rude to free the device while that is
|
||||
happening).
|
||||
|
||||
|
||||
When the device is registered, a directory in sysfs is created.
|
||||
The PCI tree in sysfs looks like:
|
||||
When the device is registered, a directory in sysfs is created.
|
||||
The PCI tree in sysfs looks like::
|
||||
|
||||
/sys/devices/pci0/
|
||||
|-- 00:00.0
|
||||
|-- 00:01.0
|
||||
| `-- 01:00.0
|
||||
|-- 00:02.0
|
||||
| `-- 02:1f.0
|
||||
| `-- 03:00.0
|
||||
|-- 00:1e.0
|
||||
| `-- 04:04.0
|
||||
|-- 00:1f.0
|
||||
|-- 00:1f.1
|
||||
| |-- ide0
|
||||
| | |-- 0.0
|
||||
| | `-- 0.1
|
||||
| `-- ide1
|
||||
| `-- 1.0
|
||||
|-- 00:1f.2
|
||||
|-- 00:1f.3
|
||||
`-- 00:1f.5
|
||||
/sys/devices/pci0/
|
||||
|-- 00:00.0
|
||||
|-- 00:01.0
|
||||
| `-- 01:00.0
|
||||
|-- 00:02.0
|
||||
| `-- 02:1f.0
|
||||
| `-- 03:00.0
|
||||
|-- 00:1e.0
|
||||
| `-- 04:04.0
|
||||
|-- 00:1f.0
|
||||
|-- 00:1f.1
|
||||
| |-- ide0
|
||||
| | |-- 0.0
|
||||
| | `-- 0.1
|
||||
| `-- ide1
|
||||
| `-- 1.0
|
||||
|-- 00:1f.2
|
||||
|-- 00:1f.3
|
||||
`-- 00:1f.5
|
||||
|
||||
Also, symlinks are created in the bus's 'devices' directory
|
||||
that point to the device's directory in the physical hierarchy.
|
||||
that point to the device's directory in the physical hierarchy::
|
||||
|
||||
/sys/bus/pci/devices/
|
||||
|-- 00:00.0 -> ../../../devices/pci0/00:00.0
|
||||
|-- 00:01.0 -> ../../../devices/pci0/00:01.0
|
||||
|-- 00:02.0 -> ../../../devices/pci0/00:02.0
|
||||
|-- 00:1e.0 -> ../../../devices/pci0/00:1e.0
|
||||
|-- 00:1f.0 -> ../../../devices/pci0/00:1f.0
|
||||
|-- 00:1f.1 -> ../../../devices/pci0/00:1f.1
|
||||
|-- 00:1f.2 -> ../../../devices/pci0/00:1f.2
|
||||
|-- 00:1f.3 -> ../../../devices/pci0/00:1f.3
|
||||
|-- 00:1f.5 -> ../../../devices/pci0/00:1f.5
|
||||
|-- 01:00.0 -> ../../../devices/pci0/00:01.0/01:00.0
|
||||
|-- 02:1f.0 -> ../../../devices/pci0/00:02.0/02:1f.0
|
||||
|-- 03:00.0 -> ../../../devices/pci0/00:02.0/02:1f.0/03:00.0
|
||||
`-- 04:04.0 -> ../../../devices/pci0/00:1e.0/04:04.0
|
||||
/sys/bus/pci/devices/
|
||||
|-- 00:00.0 -> ../../../devices/pci0/00:00.0
|
||||
|-- 00:01.0 -> ../../../devices/pci0/00:01.0
|
||||
|-- 00:02.0 -> ../../../devices/pci0/00:02.0
|
||||
|-- 00:1e.0 -> ../../../devices/pci0/00:1e.0
|
||||
|-- 00:1f.0 -> ../../../devices/pci0/00:1f.0
|
||||
|-- 00:1f.1 -> ../../../devices/pci0/00:1f.1
|
||||
|-- 00:1f.2 -> ../../../devices/pci0/00:1f.2
|
||||
|-- 00:1f.3 -> ../../../devices/pci0/00:1f.3
|
||||
|-- 00:1f.5 -> ../../../devices/pci0/00:1f.5
|
||||
|-- 01:00.0 -> ../../../devices/pci0/00:01.0/01:00.0
|
||||
|-- 02:1f.0 -> ../../../devices/pci0/00:02.0/02:1f.0
|
||||
|-- 03:00.0 -> ../../../devices/pci0/00:02.0/02:1f.0/03:00.0
|
||||
`-- 04:04.0 -> ../../../devices/pci0/00:1e.0/04:04.0
|
||||
|
||||
|
||||
|
||||
Step 3: Registering Drivers.
|
||||
|
||||
struct device_driver is a simple driver structure that contains a set
|
||||
of operations that the driver model core may call.
|
||||
of operations that the driver model core may call.
|
||||
|
||||
|
||||
- Embed a struct device_driver in the bus-specific driver.
|
||||
- Embed a struct device_driver in the bus-specific driver.
|
||||
|
||||
Just like with devices, do something like:
|
||||
Just like with devices, do something like::
|
||||
|
||||
struct pci_driver {
|
||||
...
|
||||
struct device_driver driver;
|
||||
};
|
||||
struct pci_driver {
|
||||
...
|
||||
struct device_driver driver;
|
||||
};
|
||||
|
||||
|
||||
- Initialize the generic driver structure.
|
||||
- Initialize the generic driver structure.
|
||||
|
||||
When the driver registers with the bus (e.g. doing pci_register_driver()),
|
||||
initialize the necessary fields of the driver: the name and bus
|
||||
fields.
|
||||
fields.
|
||||
|
||||
|
||||
- Register the driver.
|
||||
|
||||
After the generic driver has been initialized, call
|
||||
After the generic driver has been initialized, call::
|
||||
|
||||
driver_register(&drv->driver);
|
||||
|
||||
to register the driver with the core.
|
||||
|
||||
When the driver is unregistered from the bus, unregister it from the
|
||||
core by doing:
|
||||
core by doing::
|
||||
|
||||
driver_unregister(&drv->driver);
|
||||
|
||||
@@ -265,15 +267,15 @@ struct pci_driver {
|
||||
|
||||
- Sysfs representation.
|
||||
|
||||
Drivers are exported via sysfs in their bus's 'driver's directory.
|
||||
For example:
|
||||
Drivers are exported via sysfs in their bus's 'driver's directory.
|
||||
For example::
|
||||
|
||||
/sys/bus/pci/drivers/
|
||||
|-- 3c59x
|
||||
|-- Ensoniq AudioPCI
|
||||
|-- agpgart-amdk7
|
||||
|-- e100
|
||||
`-- serial
|
||||
/sys/bus/pci/drivers/
|
||||
|-- 3c59x
|
||||
|-- Ensoniq AudioPCI
|
||||
|-- agpgart-amdk7
|
||||
|-- e100
|
||||
`-- serial
|
||||
|
||||
|
||||
Step 4: Define Generic Methods for Drivers.
|
||||
@@ -281,30 +283,30 @@ Step 4: Define Generic Methods for Drivers.
|
||||
struct device_driver defines a set of operations that the driver model
|
||||
core calls. Most of these operations are probably similar to
|
||||
operations the bus already defines for drivers, but taking different
|
||||
parameters.
|
||||
parameters.
|
||||
|
||||
It would be difficult and tedious to force every driver on a bus to
|
||||
simultaneously convert their drivers to generic format. Instead, the
|
||||
bus driver should define single instances of the generic methods that
|
||||
forward call to the bus-specific drivers. For instance:
|
||||
forward call to the bus-specific drivers. For instance::
|
||||
|
||||
|
||||
static int pci_device_remove(struct device * dev)
|
||||
{
|
||||
struct pci_dev * pci_dev = to_pci_dev(dev);
|
||||
struct pci_driver * drv = pci_dev->driver;
|
||||
static int pci_device_remove(struct device * dev)
|
||||
{
|
||||
struct pci_dev * pci_dev = to_pci_dev(dev);
|
||||
struct pci_driver * drv = pci_dev->driver;
|
||||
|
||||
if (drv) {
|
||||
if (drv->remove)
|
||||
drv->remove(pci_dev);
|
||||
pci_dev->driver = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (drv) {
|
||||
if (drv->remove)
|
||||
drv->remove(pci_dev);
|
||||
pci_dev->driver = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
The generic driver should be initialized with these methods before it
|
||||
is registered.
|
||||
is registered::
|
||||
|
||||
/* initialize common driver fields */
|
||||
drv->driver.name = drv->name;
|
||||
@@ -320,23 +322,23 @@ is registered.
|
||||
|
||||
Ideally, the bus should only initialize the fields if they are not
|
||||
already set. This allows the drivers to implement their own generic
|
||||
methods.
|
||||
methods.
|
||||
|
||||
|
||||
Step 5: Support generic driver binding.
|
||||
Step 5: Support generic driver binding.
|
||||
|
||||
The model assumes that a device or driver can be dynamically
|
||||
registered with the bus at any time. When registration happens,
|
||||
devices must be bound to a driver, or drivers must be bound to all
|
||||
devices that it supports.
|
||||
devices that it supports.
|
||||
|
||||
A driver typically contains a list of device IDs that it supports. The
|
||||
bus driver compares these IDs to the IDs of devices registered with it.
|
||||
bus driver compares these IDs to the IDs of devices registered with it.
|
||||
The format of the device IDs, and the semantics for comparing them are
|
||||
bus-specific, so the generic model does attempt to generalize them.
|
||||
bus-specific, so the generic model does attempt to generalize them.
|
||||
|
||||
Instead, a bus may supply a method in struct bus_type that does the
|
||||
comparison:
|
||||
comparison::
|
||||
|
||||
int (*match)(struct device * dev, struct device_driver * drv);
|
||||
|
||||
@@ -346,59 +348,59 @@ and zero otherwise. It may also return error code (for example
|
||||
not possible.
|
||||
|
||||
When a device is registered, the bus's list of drivers is iterated
|
||||
over. bus->match() is called for each one until a match is found.
|
||||
over. bus->match() is called for each one until a match is found.
|
||||
|
||||
When a driver is registered, the bus's list of devices is iterated
|
||||
over. bus->match() is called for each device that is not already
|
||||
claimed by a driver.
|
||||
claimed by a driver.
|
||||
|
||||
When a device is successfully bound to a driver, device->driver is
|
||||
set, the device is added to a per-driver list of devices, and a
|
||||
symlink is created in the driver's sysfs directory that points to the
|
||||
device's physical directory:
|
||||
device's physical directory::
|
||||
|
||||
/sys/bus/pci/drivers/
|
||||
|-- 3c59x
|
||||
| `-- 00:0b.0 -> ../../../../devices/pci0/00:0b.0
|
||||
|-- Ensoniq AudioPCI
|
||||
|-- agpgart-amdk7
|
||||
| `-- 00:00.0 -> ../../../../devices/pci0/00:00.0
|
||||
|-- e100
|
||||
| `-- 00:0c.0 -> ../../../../devices/pci0/00:0c.0
|
||||
`-- serial
|
||||
/sys/bus/pci/drivers/
|
||||
|-- 3c59x
|
||||
| `-- 00:0b.0 -> ../../../../devices/pci0/00:0b.0
|
||||
|-- Ensoniq AudioPCI
|
||||
|-- agpgart-amdk7
|
||||
| `-- 00:00.0 -> ../../../../devices/pci0/00:00.0
|
||||
|-- e100
|
||||
| `-- 00:0c.0 -> ../../../../devices/pci0/00:0c.0
|
||||
`-- serial
|
||||
|
||||
|
||||
This driver binding should replace the existing driver binding
|
||||
mechanism the bus currently uses.
|
||||
mechanism the bus currently uses.
|
||||
|
||||
|
||||
Step 6: Supply a hotplug callback.
|
||||
|
||||
Whenever a device is registered with the driver model core, the
|
||||
userspace program /sbin/hotplug is called to notify userspace.
|
||||
userspace program /sbin/hotplug is called to notify userspace.
|
||||
Users can define actions to perform when a device is inserted or
|
||||
removed.
|
||||
removed.
|
||||
|
||||
The driver model core passes several arguments to userspace via
|
||||
environment variables, including
|
||||
|
||||
- ACTION: set to 'add' or 'remove'
|
||||
- DEVPATH: set to the device's physical path in sysfs.
|
||||
- DEVPATH: set to the device's physical path in sysfs.
|
||||
|
||||
A bus driver may also supply additional parameters for userspace to
|
||||
consume. To do this, a bus must implement the 'hotplug' method in
|
||||
struct bus_type:
|
||||
struct bus_type::
|
||||
|
||||
int (*hotplug) (struct device *dev, char **envp,
|
||||
int (*hotplug) (struct device *dev, char **envp,
|
||||
int num_envp, char *buffer, int buffer_size);
|
||||
|
||||
This is called immediately before /sbin/hotplug is executed.
|
||||
This is called immediately before /sbin/hotplug is executed.
|
||||
|
||||
|
||||
Step 7: Cleaning up the bus driver.
|
||||
|
||||
The generic bus, device, and driver structures provide several fields
|
||||
that can replace those defined privately to the bus driver.
|
||||
that can replace those defined privately to the bus driver.
|
||||
|
||||
- Device list.
|
||||
|
||||
@@ -407,36 +409,36 @@ type. This includes all devices on all instances of that bus type.
|
||||
An internal list that the bus uses may be removed, in favor of using
|
||||
this one.
|
||||
|
||||
The core provides an iterator to access these devices.
|
||||
The core provides an iterator to access these devices::
|
||||
|
||||
int bus_for_each_dev(struct bus_type * bus, struct device * start,
|
||||
void * data, int (*fn)(struct device *, void *));
|
||||
int bus_for_each_dev(struct bus_type * bus, struct device * start,
|
||||
void * data, int (*fn)(struct device *, void *));
|
||||
|
||||
|
||||
- Driver list.
|
||||
|
||||
struct bus_type also contains a list of all drivers registered with
|
||||
it. An internal list of drivers that the bus driver maintains may
|
||||
be removed in favor of using the generic one.
|
||||
it. An internal list of drivers that the bus driver maintains may
|
||||
be removed in favor of using the generic one.
|
||||
|
||||
The drivers may be iterated over, like devices:
|
||||
The drivers may be iterated over, like devices::
|
||||
|
||||
int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,
|
||||
void * data, int (*fn)(struct device_driver *, void *));
|
||||
int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,
|
||||
void * data, int (*fn)(struct device_driver *, void *));
|
||||
|
||||
|
||||
Please see drivers/base/bus.c for more information.
|
||||
|
||||
|
||||
- rwsem
|
||||
- rwsem
|
||||
|
||||
struct bus_type contains an rwsem that protects all core accesses to
|
||||
the device and driver lists. This can be used by the bus driver
|
||||
internally, and should be used when accessing the device or driver
|
||||
lists the bus maintains.
|
||||
lists the bus maintains.
|
||||
|
||||
|
||||
- Device and driver fields.
|
||||
- Device and driver fields.
|
||||
|
||||
Some of the fields in struct device and struct device_driver duplicate
|
||||
fields in the bus-specific representations of these objects. Feel free
|
||||
@@ -444,4 +446,3 @@ to remove the bus-specific ones and favor the generic ones. Note
|
||||
though, that this will likely mean fixing up all the drivers that
|
||||
reference the bus-specific fields (though those should all be 1-line
|
||||
changes).
|
||||
|
@@ -103,7 +103,7 @@ id_table an array of NULL terminated EISA id strings,
|
||||
(driver_data).
|
||||
|
||||
driver a generic driver, such as described in
|
||||
Documentation/driver-model/driver.txt. Only .name,
|
||||
Documentation/driver-model/driver.rst. Only .name,
|
||||
.probe and .remove members are mandatory.
|
||||
=============== ====================================================
|
||||
|
||||
@@ -152,7 +152,7 @@ state set of flags indicating the state of the device. Current
|
||||
flags are EISA_CONFIG_ENABLED and EISA_CONFIG_FORCED.
|
||||
res set of four 256 bytes I/O regions allocated to this device
|
||||
dma_mask DMA mask set from the parent device.
|
||||
dev generic device (see Documentation/driver-model/device.txt)
|
||||
dev generic device (see Documentation/driver-model/device.rst)
|
||||
======== ============================================================
|
||||
|
||||
You can get the 'struct eisa_device' from 'struct device' using the
|
||||
|
@@ -169,7 +169,7 @@ byte offsets over a base for the register block.
|
||||
|
||||
If you want to dump an u32 array in debugfs, you can create file with:
|
||||
|
||||
struct dentry *debugfs_create_u32_array(const char *name, umode_t mode,
|
||||
void debugfs_create_u32_array(const char *name, umode_t mode,
|
||||
struct dentry *parent,
|
||||
u32 *array, u32 elements);
|
||||
|
||||
|
@@ -89,7 +89,7 @@ increase the chances of your change being accepted.
|
||||
console. Excessive logging can seriously affect system performance.
|
||||
|
||||
* Use devres functions whenever possible to allocate resources. For rationale
|
||||
and supported functions, please see Documentation/driver-model/devres.txt.
|
||||
and supported functions, please see Documentation/driver-model/devres.rst.
|
||||
If a function is not supported by devres, consider using devm_add_action().
|
||||
|
||||
* If the driver has a detect function, make sure it is silent. Debug messages
|
||||
|
@@ -21,13 +21,10 @@ struct ptdump_info {
|
||||
|
||||
void ptdump_walk_pgd(struct seq_file *s, struct ptdump_info *info);
|
||||
#ifdef CONFIG_ARM_PTDUMP_DEBUGFS
|
||||
int ptdump_debugfs_register(struct ptdump_info *info, const char *name);
|
||||
void ptdump_debugfs_register(struct ptdump_info *info, const char *name);
|
||||
#else
|
||||
static inline int ptdump_debugfs_register(struct ptdump_info *info,
|
||||
const char *name)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void ptdump_debugfs_register(struct ptdump_info *info,
|
||||
const char *name) { }
|
||||
#endif /* CONFIG_ARM_PTDUMP_DEBUGFS */
|
||||
|
||||
void ptdump_check_wx(void);
|
||||
|
@@ -987,84 +987,44 @@ static int debug_clock_show(struct seq_file *s, void *unused)
|
||||
|
||||
DEFINE_SHOW_ATTRIBUTE(debug_clock);
|
||||
|
||||
static int clk_debugfs_register_one(struct clk *c)
|
||||
static void clk_debugfs_register_one(struct clk *c)
|
||||
{
|
||||
int err;
|
||||
struct dentry *d;
|
||||
struct clk *pa = c->parent;
|
||||
|
||||
d = debugfs_create_dir(c->name, pa ? pa->dent : clk_debugfs_root);
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
c->dent = d;
|
||||
|
||||
d = debugfs_create_u8("usecount", S_IRUGO, c->dent, &c->usecount);
|
||||
if (!d) {
|
||||
err = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
d = debugfs_create_ulong("rate", S_IRUGO, c->dent, &c->rate);
|
||||
if (!d) {
|
||||
err = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
d = debugfs_create_x8("flags", S_IRUGO, c->dent, &c->flags);
|
||||
if (!d) {
|
||||
err = -ENOMEM;
|
||||
goto err_out;
|
||||
}
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
debugfs_remove_recursive(c->dent);
|
||||
return err;
|
||||
debugfs_create_u8("usecount", S_IRUGO, c->dent, &c->usecount);
|
||||
debugfs_create_ulong("rate", S_IRUGO, c->dent, &c->rate);
|
||||
debugfs_create_x8("flags", S_IRUGO, c->dent, &c->flags);
|
||||
}
|
||||
|
||||
static int clk_debugfs_register(struct clk *c)
|
||||
static void clk_debugfs_register(struct clk *c)
|
||||
{
|
||||
int err;
|
||||
struct clk *pa = c->parent;
|
||||
|
||||
if (pa && !pa->dent) {
|
||||
err = clk_debugfs_register(pa);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
if (pa && !pa->dent)
|
||||
clk_debugfs_register(pa);
|
||||
|
||||
if (!c->dent) {
|
||||
err = clk_debugfs_register_one(c);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
if (!c->dent)
|
||||
clk_debugfs_register_one(c);
|
||||
}
|
||||
|
||||
static int __init clk_debugfs_init(void)
|
||||
{
|
||||
struct clk *c;
|
||||
struct dentry *d;
|
||||
int err;
|
||||
|
||||
d = debugfs_create_dir("clock", NULL);
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
clk_debugfs_root = d;
|
||||
|
||||
list_for_each_entry(c, &clocks, node) {
|
||||
err = clk_debugfs_register(c);
|
||||
if (err)
|
||||
goto err_out;
|
||||
}
|
||||
list_for_each_entry(c, &clocks, node)
|
||||
clk_debugfs_register(c);
|
||||
|
||||
d = debugfs_create_file("summary", S_IRUGO,
|
||||
d, NULL, &debug_clock_fops);
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
debugfs_create_file("summary", S_IRUGO, d, NULL, &debug_clock_fops);
|
||||
|
||||
return 0;
|
||||
err_out:
|
||||
debugfs_remove_recursive(clk_debugfs_root);
|
||||
return err;
|
||||
}
|
||||
late_initcall(clk_debugfs_init);
|
||||
|
||||
|
@@ -539,11 +539,8 @@ static void omap_pm_init_debugfs(void)
|
||||
struct dentry *d;
|
||||
|
||||
d = debugfs_create_dir("pm_debug", NULL);
|
||||
if (!d)
|
||||
return;
|
||||
|
||||
(void) debugfs_create_file("omap_pm", S_IWUSR | S_IRUGO,
|
||||
d, NULL, &omap_pm_debug_fops);
|
||||
debugfs_create_file("omap_pm", S_IWUSR | S_IRUGO, d, NULL,
|
||||
&omap_pm_debug_fops);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_DEBUG_FS */
|
||||
|
@@ -190,9 +190,8 @@ static int __init pwrdms_setup(struct powerdomain *pwrdm, void *dir)
|
||||
return 0;
|
||||
|
||||
d = debugfs_create_dir(pwrdm->name, (struct dentry *)dir);
|
||||
if (d)
|
||||
(void) debugfs_create_file("suspend", S_IRUGO|S_IWUSR, d,
|
||||
(void *)pwrdm, &pwrdm_suspend_fops);
|
||||
debugfs_create_file("suspend", S_IRUGO|S_IWUSR, d, pwrdm,
|
||||
&pwrdm_suspend_fops);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -230,16 +229,14 @@ static int __init pm_dbg_init(void)
|
||||
return 0;
|
||||
|
||||
d = debugfs_create_dir("pm_debug", NULL);
|
||||
if (!d)
|
||||
return -EINVAL;
|
||||
|
||||
(void) debugfs_create_file("count", 0444, d, NULL, &pm_dbg_counters_fops);
|
||||
(void) debugfs_create_file("time", 0444, d, NULL, &pm_dbg_timers_fops);
|
||||
debugfs_create_file("count", 0444, d, NULL, &pm_dbg_counters_fops);
|
||||
debugfs_create_file("time", 0444, d, NULL, &pm_dbg_timers_fops);
|
||||
|
||||
pwrdm_for_each(pwrdms_setup, (void *)d);
|
||||
|
||||
(void) debugfs_create_file("enable_off_mode", S_IRUGO | S_IWUSR, d,
|
||||
&enable_off_mode, &pm_dbg_option_fops);
|
||||
debugfs_create_file("enable_off_mode", S_IRUGO | S_IWUSR, d,
|
||||
&enable_off_mode, &pm_dbg_option_fops);
|
||||
pm_dbg_init_done = 1;
|
||||
|
||||
return 0;
|
||||
|
@@ -446,7 +446,7 @@ void ptdump_check_wx(void)
|
||||
static int ptdump_init(void)
|
||||
{
|
||||
ptdump_initialize();
|
||||
return ptdump_debugfs_register(&kernel_ptdump_info,
|
||||
"kernel_page_tables");
|
||||
ptdump_debugfs_register(&kernel_ptdump_info, "kernel_page_tables");
|
||||
return 0;
|
||||
}
|
||||
__initcall(ptdump_init);
|
||||
|
@@ -24,11 +24,7 @@ static const struct file_operations ptdump_fops = {
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
int ptdump_debugfs_register(struct ptdump_info *info, const char *name)
|
||||
void ptdump_debugfs_register(struct ptdump_info *info, const char *name)
|
||||
{
|
||||
struct dentry *pe;
|
||||
|
||||
pe = debugfs_create_file(name, 0400, NULL, info, &ptdump_fops);
|
||||
return pe ? 0 : -ENOMEM;
|
||||
|
||||
debugfs_create_file(name, 0400, NULL, info, &ptdump_fops);
|
||||
}
|
||||
|
@@ -147,13 +147,13 @@ static const struct dma_map_ops ibmebus_dma_ops = {
|
||||
.unmap_page = ibmebus_unmap_page,
|
||||
};
|
||||
|
||||
static int ibmebus_match_path(struct device *dev, void *data)
|
||||
static int ibmebus_match_path(struct device *dev, const void *data)
|
||||
{
|
||||
struct device_node *dn = to_platform_device(dev)->dev.of_node;
|
||||
return (of_find_node_by_path(data) == dn);
|
||||
}
|
||||
|
||||
static int ibmebus_match_node(struct device *dev, void *data)
|
||||
static int ibmebus_match_node(struct device *dev, const void *data)
|
||||
{
|
||||
return to_platform_device(dev)->dev.of_node == data;
|
||||
}
|
||||
|
@@ -9,9 +9,6 @@ EXPORT_SYMBOL(arch_debugfs_dir);
|
||||
static int __init arch_kdebugfs_init(void)
|
||||
{
|
||||
arch_debugfs_dir = debugfs_create_dir("sh", NULL);
|
||||
if (!arch_debugfs_dir)
|
||||
return -ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
arch_initcall(arch_kdebugfs_init);
|
||||
|
@@ -63,13 +63,8 @@ static const struct file_operations asids_debugfs_fops = {
|
||||
|
||||
static int __init asids_debugfs_init(void)
|
||||
{
|
||||
struct dentry *asids_dentry;
|
||||
|
||||
asids_dentry = debugfs_create_file("asids", S_IRUSR, arch_debugfs_dir,
|
||||
NULL, &asids_debugfs_fops);
|
||||
if (!asids_dentry)
|
||||
return -ENOMEM;
|
||||
|
||||
return PTR_ERR_OR_ZERO(asids_dentry);
|
||||
debugfs_create_file("asids", S_IRUSR, arch_debugfs_dir, NULL,
|
||||
&asids_debugfs_fops);
|
||||
return 0;
|
||||
}
|
||||
device_initcall(asids_debugfs_init);
|
||||
|
@@ -109,22 +109,10 @@ static const struct file_operations cache_debugfs_fops = {
|
||||
|
||||
static int __init cache_debugfs_init(void)
|
||||
{
|
||||
struct dentry *dcache_dentry, *icache_dentry;
|
||||
|
||||
dcache_dentry = debugfs_create_file("dcache", S_IRUSR, arch_debugfs_dir,
|
||||
(unsigned int *)CACHE_TYPE_DCACHE,
|
||||
&cache_debugfs_fops);
|
||||
if (!dcache_dentry)
|
||||
return -ENOMEM;
|
||||
|
||||
icache_dentry = debugfs_create_file("icache", S_IRUSR, arch_debugfs_dir,
|
||||
(unsigned int *)CACHE_TYPE_ICACHE,
|
||||
&cache_debugfs_fops);
|
||||
if (!icache_dentry) {
|
||||
debugfs_remove(dcache_dentry);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
debugfs_create_file("dcache", S_IRUSR, arch_debugfs_dir,
|
||||
(void *)CACHE_TYPE_DCACHE, &cache_debugfs_fops);
|
||||
debugfs_create_file("icache", S_IRUSR, arch_debugfs_dir,
|
||||
(void *)CACHE_TYPE_ICACHE, &cache_debugfs_fops);
|
||||
return 0;
|
||||
}
|
||||
module_init(cache_debugfs_init);
|
||||
|
@@ -861,13 +861,8 @@ static const struct file_operations pmb_debugfs_fops = {
|
||||
|
||||
static int __init pmb_debugfs_init(void)
|
||||
{
|
||||
struct dentry *dentry;
|
||||
|
||||
dentry = debugfs_create_file("pmb", S_IFREG | S_IRUGO,
|
||||
arch_debugfs_dir, NULL, &pmb_debugfs_fops);
|
||||
if (!dentry)
|
||||
return -ENOMEM;
|
||||
|
||||
debugfs_create_file("pmb", S_IFREG | S_IRUGO, arch_debugfs_dir, NULL,
|
||||
&pmb_debugfs_fops);
|
||||
return 0;
|
||||
}
|
||||
subsys_initcall(pmb_debugfs_init);
|
||||
|
@@ -149,22 +149,10 @@ static const struct file_operations tlb_debugfs_fops = {
|
||||
|
||||
static int __init tlb_debugfs_init(void)
|
||||
{
|
||||
struct dentry *itlb, *utlb;
|
||||
|
||||
itlb = debugfs_create_file("itlb", S_IRUSR, arch_debugfs_dir,
|
||||
(unsigned int *)TLB_TYPE_ITLB,
|
||||
&tlb_debugfs_fops);
|
||||
if (unlikely(!itlb))
|
||||
return -ENOMEM;
|
||||
|
||||
utlb = debugfs_create_file("utlb", S_IRUSR, arch_debugfs_dir,
|
||||
(unsigned int *)TLB_TYPE_UTLB,
|
||||
&tlb_debugfs_fops);
|
||||
if (unlikely(!utlb)) {
|
||||
debugfs_remove(itlb);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
debugfs_create_file("itlb", S_IRUSR, arch_debugfs_dir,
|
||||
(void *)TLB_TYPE_ITLB, &tlb_debugfs_fops);
|
||||
debugfs_create_file("utlb", S_IRUSR, arch_debugfs_dir,
|
||||
(void *)TLB_TYPE_UTLB, &tlb_debugfs_fops);
|
||||
return 0;
|
||||
}
|
||||
module_init(tlb_debugfs_init);
|
||||
|
@@ -67,33 +67,18 @@ static const struct file_operations fops_setup_data = {
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static int __init
|
||||
static void __init
|
||||
create_setup_data_node(struct dentry *parent, int no,
|
||||
struct setup_data_node *node)
|
||||
{
|
||||
struct dentry *d, *type, *data;
|
||||
struct dentry *d;
|
||||
char buf[16];
|
||||
|
||||
sprintf(buf, "%d", no);
|
||||
d = debugfs_create_dir(buf, parent);
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
|
||||
type = debugfs_create_x32("type", S_IRUGO, d, &node->type);
|
||||
if (!type)
|
||||
goto err_dir;
|
||||
|
||||
data = debugfs_create_file("data", S_IRUGO, d, node, &fops_setup_data);
|
||||
if (!data)
|
||||
goto err_type;
|
||||
|
||||
return 0;
|
||||
|
||||
err_type:
|
||||
debugfs_remove(type);
|
||||
err_dir:
|
||||
debugfs_remove(d);
|
||||
return -ENOMEM;
|
||||
debugfs_create_x32("type", S_IRUGO, d, &node->type);
|
||||
debugfs_create_file("data", S_IRUGO, d, node, &fops_setup_data);
|
||||
}
|
||||
|
||||
static int __init create_setup_data_nodes(struct dentry *parent)
|
||||
@@ -106,8 +91,6 @@ static int __init create_setup_data_nodes(struct dentry *parent)
|
||||
int no = 0;
|
||||
|
||||
d = debugfs_create_dir("setup_data", parent);
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
|
||||
pa_data = boot_params.hdr.setup_data;
|
||||
|
||||
@@ -128,19 +111,17 @@ static int __init create_setup_data_nodes(struct dentry *parent)
|
||||
node->paddr = pa_data;
|
||||
node->type = data->type;
|
||||
node->len = data->len;
|
||||
error = create_setup_data_node(d, no, node);
|
||||
create_setup_data_node(d, no, node);
|
||||
pa_data = data->next;
|
||||
|
||||
memunmap(data);
|
||||
if (error)
|
||||
goto err_dir;
|
||||
no++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_dir:
|
||||
debugfs_remove(d);
|
||||
debugfs_remove_recursive(d);
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -151,35 +132,18 @@ static struct debugfs_blob_wrapper boot_params_blob = {
|
||||
|
||||
static int __init boot_params_kdebugfs_init(void)
|
||||
{
|
||||
struct dentry *dbp, *version, *data;
|
||||
int error = -ENOMEM;
|
||||
struct dentry *dbp;
|
||||
int error;
|
||||
|
||||
dbp = debugfs_create_dir("boot_params", arch_debugfs_dir);
|
||||
if (!dbp)
|
||||
return -ENOMEM;
|
||||
|
||||
version = debugfs_create_x16("version", S_IRUGO, dbp,
|
||||
&boot_params.hdr.version);
|
||||
if (!version)
|
||||
goto err_dir;
|
||||
|
||||
data = debugfs_create_blob("data", S_IRUGO, dbp,
|
||||
&boot_params_blob);
|
||||
if (!data)
|
||||
goto err_version;
|
||||
debugfs_create_x16("version", S_IRUGO, dbp, &boot_params.hdr.version);
|
||||
debugfs_create_blob("data", S_IRUGO, dbp, &boot_params_blob);
|
||||
|
||||
error = create_setup_data_nodes(dbp);
|
||||
if (error)
|
||||
goto err_data;
|
||||
debugfs_remove_recursive(dbp);
|
||||
|
||||
return 0;
|
||||
|
||||
err_data:
|
||||
debugfs_remove(data);
|
||||
err_version:
|
||||
debugfs_remove(version);
|
||||
err_dir:
|
||||
debugfs_remove(dbp);
|
||||
return error;
|
||||
}
|
||||
#endif /* CONFIG_DEBUG_BOOT_PARAMS */
|
||||
@@ -189,8 +153,6 @@ static int __init arch_kdebugfs_init(void)
|
||||
int error = 0;
|
||||
|
||||
arch_debugfs_dir = debugfs_create_dir("x86", NULL);
|
||||
if (!arch_debugfs_dir)
|
||||
return -ENOMEM;
|
||||
|
||||
#ifdef CONFIG_DEBUG_BOOT_PARAMS
|
||||
error = boot_params_kdebugfs_init();
|
||||
|
@@ -26,8 +26,6 @@ static int ptdump_curknl_show(struct seq_file *m, void *v)
|
||||
DEFINE_SHOW_ATTRIBUTE(ptdump_curknl);
|
||||
|
||||
#ifdef CONFIG_PAGE_TABLE_ISOLATION
|
||||
static struct dentry *pe_curusr;
|
||||
|
||||
static int ptdump_curusr_show(struct seq_file *m, void *v)
|
||||
{
|
||||
if (current->mm->pgd) {
|
||||
@@ -42,8 +40,6 @@ DEFINE_SHOW_ATTRIBUTE(ptdump_curusr);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_EFI) && defined(CONFIG_X86_64)
|
||||
static struct dentry *pe_efi;
|
||||
|
||||
static int ptdump_efi_show(struct seq_file *m, void *v)
|
||||
{
|
||||
if (efi_mm.pgd)
|
||||
@@ -54,41 +50,24 @@ static int ptdump_efi_show(struct seq_file *m, void *v)
|
||||
DEFINE_SHOW_ATTRIBUTE(ptdump_efi);
|
||||
#endif
|
||||
|
||||
static struct dentry *dir, *pe_knl, *pe_curknl;
|
||||
static struct dentry *dir;
|
||||
|
||||
static int __init pt_dump_debug_init(void)
|
||||
{
|
||||
dir = debugfs_create_dir("page_tables", NULL);
|
||||
if (!dir)
|
||||
return -ENOMEM;
|
||||
|
||||
pe_knl = debugfs_create_file("kernel", 0400, dir, NULL,
|
||||
&ptdump_fops);
|
||||
if (!pe_knl)
|
||||
goto err;
|
||||
|
||||
pe_curknl = debugfs_create_file("current_kernel", 0400,
|
||||
dir, NULL, &ptdump_curknl_fops);
|
||||
if (!pe_curknl)
|
||||
goto err;
|
||||
debugfs_create_file("kernel", 0400, dir, NULL, &ptdump_fops);
|
||||
debugfs_create_file("current_kernel", 0400, dir, NULL,
|
||||
&ptdump_curknl_fops);
|
||||
|
||||
#ifdef CONFIG_PAGE_TABLE_ISOLATION
|
||||
pe_curusr = debugfs_create_file("current_user", 0400,
|
||||
dir, NULL, &ptdump_curusr_fops);
|
||||
if (!pe_curusr)
|
||||
goto err;
|
||||
debugfs_create_file("current_user", 0400, dir, NULL,
|
||||
&ptdump_curusr_fops);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_EFI) && defined(CONFIG_X86_64)
|
||||
pe_efi = debugfs_create_file("efi", 0400, dir, NULL, &ptdump_efi_fops);
|
||||
if (!pe_efi)
|
||||
goto err;
|
||||
debugfs_create_file("efi", 0400, dir, NULL, &ptdump_efi_fops);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
err:
|
||||
debugfs_remove_recursive(dir);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static void __exit pt_dump_debug_exit(void)
|
||||
|
@@ -104,24 +104,12 @@ DEFINE_SHOW_ATTRIBUTE(punit_dev_state);
|
||||
|
||||
static struct dentry *punit_dbg_file;
|
||||
|
||||
static int punit_dbgfs_register(struct punit_device *punit_device)
|
||||
static void punit_dbgfs_register(struct punit_device *punit_device)
|
||||
{
|
||||
struct dentry *dev_state;
|
||||
|
||||
punit_dbg_file = debugfs_create_dir("punit_atom", NULL);
|
||||
if (!punit_dbg_file)
|
||||
return -ENXIO;
|
||||
|
||||
dev_state = debugfs_create_file("dev_power_state", 0444,
|
||||
punit_dbg_file, punit_device,
|
||||
&punit_dev_state_fops);
|
||||
if (!dev_state) {
|
||||
pr_err("punit_dev_state register failed\n");
|
||||
debugfs_remove(punit_dbg_file);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
debugfs_create_file("dev_power_state", 0444, punit_dbg_file,
|
||||
punit_device, &punit_dev_state_fops);
|
||||
}
|
||||
|
||||
static void punit_dbgfs_unregister(void)
|
||||
@@ -145,15 +133,12 @@ MODULE_DEVICE_TABLE(x86cpu, intel_punit_cpu_ids);
|
||||
static int __init punit_atom_debug_init(void)
|
||||
{
|
||||
const struct x86_cpu_id *id;
|
||||
int ret;
|
||||
|
||||
id = x86_match_cpu(intel_punit_cpu_ids);
|
||||
if (!id)
|
||||
return -ENODEV;
|
||||
|
||||
ret = punit_dbgfs_register((struct punit_device *)id->driver_data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
punit_dbgfs_register((struct punit_device *)id->driver_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -35,7 +35,6 @@
|
||||
#include <linux/types.h>
|
||||
|
||||
struct imr_device {
|
||||
struct dentry *file;
|
||||
bool init;
|
||||
struct mutex lock;
|
||||
int max_imr;
|
||||
@@ -231,13 +230,11 @@ DEFINE_SHOW_ATTRIBUTE(imr_dbgfs_state);
|
||||
* imr_debugfs_register - register debugfs hooks.
|
||||
*
|
||||
* @idev: pointer to imr_device structure.
|
||||
* @return: 0 on success - errno on failure.
|
||||
*/
|
||||
static int imr_debugfs_register(struct imr_device *idev)
|
||||
static void imr_debugfs_register(struct imr_device *idev)
|
||||
{
|
||||
idev->file = debugfs_create_file("imr_state", 0444, NULL, idev,
|
||||
&imr_dbgfs_state_fops);
|
||||
return PTR_ERR_OR_ZERO(idev->file);
|
||||
debugfs_create_file("imr_state", 0444, NULL, idev,
|
||||
&imr_dbgfs_state_fops);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -582,7 +579,6 @@ static const struct x86_cpu_id imr_ids[] __initconst = {
|
||||
static int __init imr_init(void)
|
||||
{
|
||||
struct imr_device *idev = &imr_dev;
|
||||
int ret;
|
||||
|
||||
if (!x86_match_cpu(imr_ids) || !iosf_mbi_available())
|
||||
return -ENODEV;
|
||||
@@ -592,9 +588,7 @@ static int __init imr_init(void)
|
||||
idev->init = true;
|
||||
|
||||
mutex_init(&idev->lock);
|
||||
ret = imr_debugfs_register(idev);
|
||||
if (ret != 0)
|
||||
pr_warn("debugfs register failed!\n");
|
||||
imr_debugfs_register(idev);
|
||||
imr_fixup_memmap(idev);
|
||||
return 0;
|
||||
}
|
||||
|
@@ -461,31 +461,16 @@ static struct dentry *iosf_dbg;
|
||||
|
||||
static void iosf_sideband_debug_init(void)
|
||||
{
|
||||
struct dentry *d;
|
||||
|
||||
iosf_dbg = debugfs_create_dir("iosf_sb", NULL);
|
||||
if (IS_ERR_OR_NULL(iosf_dbg))
|
||||
return;
|
||||
|
||||
/* mdr */
|
||||
d = debugfs_create_x32("mdr", 0660, iosf_dbg, &dbg_mdr);
|
||||
if (!d)
|
||||
goto cleanup;
|
||||
debugfs_create_x32("mdr", 0660, iosf_dbg, &dbg_mdr);
|
||||
|
||||
/* mcrx */
|
||||
d = debugfs_create_x32("mcrx", 0660, iosf_dbg, &dbg_mcrx);
|
||||
if (!d)
|
||||
goto cleanup;
|
||||
debugfs_create_x32("mcrx", 0660, iosf_dbg, &dbg_mcrx);
|
||||
|
||||
/* mcr - initiates mailbox tranaction */
|
||||
d = debugfs_create_file("mcr", 0660, iosf_dbg, &dbg_mcr, &iosf_mcr_fops);
|
||||
if (!d)
|
||||
goto cleanup;
|
||||
|
||||
return;
|
||||
|
||||
cleanup:
|
||||
debugfs_remove_recursive(d);
|
||||
debugfs_create_file("mcr", 0660, iosf_dbg, &dbg_mcr, &iosf_mcr_fops);
|
||||
}
|
||||
|
||||
static void iosf_debugfs_init(void)
|
||||
|
@@ -66,7 +66,6 @@ static struct tunables tunables[] = {
|
||||
};
|
||||
|
||||
static struct dentry *tunables_dir;
|
||||
static struct dentry *tunables_file;
|
||||
|
||||
/* these correspond to the statistics printed by ptc_seq_show() */
|
||||
static char *stat_description[] = {
|
||||
@@ -1700,18 +1699,8 @@ static int __init uv_ptc_init(void)
|
||||
}
|
||||
|
||||
tunables_dir = debugfs_create_dir(UV_BAU_TUNABLES_DIR, NULL);
|
||||
if (!tunables_dir) {
|
||||
pr_err("unable to create debugfs directory %s\n",
|
||||
UV_BAU_TUNABLES_DIR);
|
||||
return -EINVAL;
|
||||
}
|
||||
tunables_file = debugfs_create_file(UV_BAU_TUNABLES_FILE, 0600,
|
||||
tunables_dir, NULL, &tunables_fops);
|
||||
if (!tunables_file) {
|
||||
pr_err("unable to create debugfs file %s\n",
|
||||
UV_BAU_TUNABLES_FILE);
|
||||
return -EINVAL;
|
||||
}
|
||||
debugfs_create_file(UV_BAU_TUNABLES_FILE, 0600, tunables_dir, NULL,
|
||||
&tunables_fops);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -9,13 +9,8 @@ static struct dentry *d_xen_debug;
|
||||
|
||||
struct dentry * __init xen_init_debugfs(void)
|
||||
{
|
||||
if (!d_xen_debug) {
|
||||
if (!d_xen_debug)
|
||||
d_xen_debug = debugfs_create_dir("xen", NULL);
|
||||
|
||||
if (!d_xen_debug)
|
||||
pr_warning("Could not create 'xen' debugfs directory\n");
|
||||
}
|
||||
|
||||
return d_xen_debug;
|
||||
}
|
||||
|
||||
|
@@ -817,9 +817,6 @@ static int __init xen_p2m_debugfs(void)
|
||||
{
|
||||
struct dentry *d_xen = xen_init_debugfs();
|
||||
|
||||
if (d_xen == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
d_mmu_debug = debugfs_create_dir("mmu", d_xen);
|
||||
|
||||
debugfs_create_file("p2m", 0600, d_mmu_debug, NULL, &p2m_dump_fops);
|
||||
|
@@ -508,10 +508,10 @@ struct hid_uid {
|
||||
const char *uid;
|
||||
};
|
||||
|
||||
static int match_hid_uid(struct device *dev, void *data)
|
||||
static int match_hid_uid(struct device *dev, const void *data)
|
||||
{
|
||||
struct acpi_device *adev = ACPI_COMPANION(dev);
|
||||
struct hid_uid *id = data;
|
||||
const struct hid_uid *id = data;
|
||||
|
||||
if (!adev)
|
||||
return 0;
|
||||
|
@@ -725,17 +725,15 @@ bool acpi_dev_found(const char *hid)
|
||||
EXPORT_SYMBOL(acpi_dev_found);
|
||||
|
||||
struct acpi_dev_match_info {
|
||||
const char *dev_name;
|
||||
struct acpi_device *adev;
|
||||
struct acpi_device_id hid[2];
|
||||
const char *uid;
|
||||
s64 hrv;
|
||||
};
|
||||
|
||||
static int acpi_dev_match_cb(struct device *dev, void *data)
|
||||
static int acpi_dev_match_cb(struct device *dev, const void *data)
|
||||
{
|
||||
struct acpi_device *adev = to_acpi_device(dev);
|
||||
struct acpi_dev_match_info *match = data;
|
||||
const struct acpi_dev_match_info *match = data;
|
||||
unsigned long long hrv;
|
||||
acpi_status status;
|
||||
|
||||
@@ -746,9 +744,6 @@ static int acpi_dev_match_cb(struct device *dev, void *data)
|
||||
strcmp(adev->pnp.unique_id, match->uid)))
|
||||
return 0;
|
||||
|
||||
match->dev_name = acpi_dev_name(adev);
|
||||
match->adev = adev;
|
||||
|
||||
if (match->hrv == -1)
|
||||
return 1;
|
||||
|
||||
@@ -818,7 +813,7 @@ acpi_dev_get_first_match_dev(const char *hid, const char *uid, s64 hrv)
|
||||
match.hrv = hrv;
|
||||
|
||||
dev = bus_find_device(&acpi_bus_type, NULL, &match, acpi_dev_match_cb);
|
||||
return dev ? match.adev : NULL;
|
||||
return dev ? to_acpi_device(dev) : NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(acpi_dev_get_first_match_dev);
|
||||
|
||||
|
@@ -134,10 +134,10 @@ static inline void gizmo_writel(struct tegra_ahb *ahb, u32 value, u32 offset)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TEGRA_IOMMU_SMMU
|
||||
static int tegra_ahb_match_by_smmu(struct device *dev, void *data)
|
||||
static int tegra_ahb_match_by_smmu(struct device *dev, const void *data)
|
||||
{
|
||||
struct tegra_ahb *ahb = dev_get_drvdata(dev);
|
||||
struct device_node *dn = data;
|
||||
const struct device_node *dn = data;
|
||||
|
||||
return (ahb->dev->of_node == dn) ? 1 : 0;
|
||||
}
|
||||
|
@@ -137,7 +137,6 @@ bool __init topology_parse_cpu_capacity(struct device_node *cpu_node, int cpu)
|
||||
sizeof(*raw_capacity),
|
||||
GFP_KERNEL);
|
||||
if (!raw_capacity) {
|
||||
pr_err("cpu_capacity: failed to allocate memory for raw capacities\n");
|
||||
cap_parsing_failed = true;
|
||||
return false;
|
||||
}
|
||||
@@ -217,10 +216,8 @@ static int __init register_cpufreq_notifier(void)
|
||||
if (!acpi_disabled || !raw_capacity)
|
||||
return -EINVAL;
|
||||
|
||||
if (!alloc_cpumask_var(&cpus_to_visit, GFP_KERNEL)) {
|
||||
pr_err("cpu_capacity: failed to allocate memory for cpus_to_visit\n");
|
||||
if (!alloc_cpumask_var(&cpus_to_visit, GFP_KERNEL))
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
cpumask_copy(cpus_to_visit, cpu_possible_mask);
|
||||
|
||||
|
@@ -323,8 +323,8 @@ EXPORT_SYMBOL_GPL(bus_for_each_dev);
|
||||
* return to the caller and not iterate over any more devices.
|
||||
*/
|
||||
struct device *bus_find_device(struct bus_type *bus,
|
||||
struct device *start, void *data,
|
||||
int (*match)(struct device *dev, void *data))
|
||||
struct device *start, const void *data,
|
||||
int (*match)(struct device *dev, const void *data))
|
||||
{
|
||||
struct klist_iter i;
|
||||
struct device *dev;
|
||||
@@ -342,7 +342,7 @@ struct device *bus_find_device(struct bus_type *bus,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bus_find_device);
|
||||
|
||||
static int match_name(struct device *dev, void *data)
|
||||
static int match_name(struct device *dev, const void *data)
|
||||
{
|
||||
const char *name = data;
|
||||
|
||||
|
@@ -660,7 +660,8 @@ static int cacheinfo_cpu_pre_down(unsigned int cpu)
|
||||
|
||||
static int __init cacheinfo_sysfs_init(void)
|
||||
{
|
||||
return cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "base/cacheinfo:online",
|
||||
return cpuhp_setup_state(CPUHP_AP_BASE_CACHEINFO_ONLINE,
|
||||
"base/cacheinfo:online",
|
||||
cacheinfo_cpu_online, cacheinfo_cpu_pre_down);
|
||||
}
|
||||
device_initcall(cacheinfo_sysfs_init);
|
||||
|
@@ -3356,3 +3356,9 @@ void device_set_of_node_from_dev(struct device *dev, const struct device *dev2)
|
||||
dev->of_node_reused = true;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(device_set_of_node_from_dev);
|
||||
|
||||
int device_match_of_node(struct device *dev, const void *np)
|
||||
{
|
||||
return dev->of_node == np;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(device_match_of_node);
|
||||
|
@@ -235,6 +235,19 @@ static int __init deferred_probe_timeout_setup(char *str)
|
||||
}
|
||||
__setup("deferred_probe_timeout=", deferred_probe_timeout_setup);
|
||||
|
||||
static int __driver_deferred_probe_check_state(struct device *dev)
|
||||
{
|
||||
if (!initcalls_done)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
if (!deferred_probe_timeout) {
|
||||
dev_WARN(dev, "deferred probe timeout, ignoring dependency");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* driver_deferred_probe_check_state() - Check deferred probe state
|
||||
* @dev: device to check
|
||||
@@ -248,14 +261,40 @@ __setup("deferred_probe_timeout=", deferred_probe_timeout_setup);
|
||||
*/
|
||||
int driver_deferred_probe_check_state(struct device *dev)
|
||||
{
|
||||
if (initcalls_done) {
|
||||
if (!deferred_probe_timeout) {
|
||||
dev_WARN(dev, "deferred probe timeout, ignoring dependency");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
dev_warn(dev, "ignoring dependency for device, assuming no driver");
|
||||
return -ENODEV;
|
||||
}
|
||||
int ret;
|
||||
|
||||
ret = __driver_deferred_probe_check_state(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
dev_warn(dev, "ignoring dependency for device, assuming no driver");
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/**
|
||||
* driver_deferred_probe_check_state_continue() - check deferred probe state
|
||||
* @dev: device to check
|
||||
*
|
||||
* Returns -ETIMEDOUT if deferred probe debug timeout has expired, or
|
||||
* -EPROBE_DEFER otherwise.
|
||||
*
|
||||
* Drivers or subsystems can opt-in to calling this function instead of
|
||||
* directly returning -EPROBE_DEFER.
|
||||
*
|
||||
* This is similar to driver_deferred_probe_check_state(), but it allows the
|
||||
* subsystem to keep deferring probe after built-in drivers have had a chance
|
||||
* to probe. One scenario where that is useful is if built-in drivers rely on
|
||||
* resources that are provided by modular drivers.
|
||||
*/
|
||||
int driver_deferred_probe_check_state_continue(struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = __driver_deferred_probe_check_state(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
|
@@ -133,7 +133,7 @@ static struct bus_type *generic_match_buses[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static int device_fwnode_match(struct device *dev, void *fwnode)
|
||||
static int device_fwnode_match(struct device *dev, const void *fwnode)
|
||||
{
|
||||
return dev_fwnode(dev) == fwnode;
|
||||
}
|
||||
|
@@ -73,8 +73,8 @@ EXPORT_SYMBOL_GPL(driver_for_each_device);
|
||||
* return to the caller and not iterate over any more devices.
|
||||
*/
|
||||
struct device *driver_find_device(struct device_driver *drv,
|
||||
struct device *start, void *data,
|
||||
int (*match)(struct device *dev, void *data))
|
||||
struct device *start, const void *data,
|
||||
int (*match)(struct device *dev, const void *data))
|
||||
{
|
||||
struct klist_iter i;
|
||||
struct device *dev;
|
||||
|
@@ -26,6 +26,9 @@ config FW_LOADER
|
||||
|
||||
if FW_LOADER
|
||||
|
||||
config FW_LOADER_PAGED_BUF
|
||||
bool
|
||||
|
||||
config EXTRA_FIRMWARE
|
||||
string "Build named firmware blobs into the kernel binary"
|
||||
help
|
||||
@@ -67,6 +70,7 @@ config EXTRA_FIRMWARE_DIR
|
||||
|
||||
config FW_LOADER_USER_HELPER
|
||||
bool "Enable the firmware sysfs fallback mechanism"
|
||||
select FW_LOADER_PAGED_BUF
|
||||
help
|
||||
This option enables a sysfs loading facility to enable firmware
|
||||
loading to the kernel through userspace as a fallback mechanism
|
||||
@@ -151,5 +155,19 @@ config FW_LOADER_USER_HELPER_FALLBACK
|
||||
|
||||
If you are unsure about this, say N here.
|
||||
|
||||
config FW_LOADER_COMPRESS
|
||||
bool "Enable compressed firmware support"
|
||||
select FW_LOADER_PAGED_BUF
|
||||
select XZ_DEC
|
||||
help
|
||||
This option enables the support for loading compressed firmware
|
||||
files. The caller of firmware API receives the decompressed file
|
||||
content. The compressed file is loaded as a fallback, only after
|
||||
loading the raw file failed at first.
|
||||
|
||||
Currently only XZ-compressed files are supported, and they have to
|
||||
be compressed with either none or crc32 integrity check type (pass
|
||||
"-C crc32" option to xz command).
|
||||
|
||||
endif # FW_LOADER
|
||||
endmenu
|
||||
|
@@ -219,20 +219,6 @@ static ssize_t firmware_loading_show(struct device *dev,
|
||||
return sprintf(buf, "%d\n", loading);
|
||||
}
|
||||
|
||||
/* one pages buffer should be mapped/unmapped only once */
|
||||
static int map_fw_priv_pages(struct fw_priv *fw_priv)
|
||||
{
|
||||
if (!fw_priv->is_paged_buf)
|
||||
return 0;
|
||||
|
||||
vunmap(fw_priv->data);
|
||||
fw_priv->data = vmap(fw_priv->pages, fw_priv->nr_pages, 0,
|
||||
PAGE_KERNEL_RO);
|
||||
if (!fw_priv->data)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* firmware_loading_store() - set value in the 'loading' control file
|
||||
* @dev: device pointer
|
||||
@@ -254,7 +240,6 @@ static ssize_t firmware_loading_store(struct device *dev,
|
||||
struct fw_priv *fw_priv;
|
||||
ssize_t written = count;
|
||||
int loading = simple_strtol(buf, NULL, 10);
|
||||
int i;
|
||||
|
||||
mutex_lock(&fw_lock);
|
||||
fw_priv = fw_sysfs->fw_priv;
|
||||
@@ -265,12 +250,7 @@ static ssize_t firmware_loading_store(struct device *dev,
|
||||
case 1:
|
||||
/* discarding any previous partial load */
|
||||
if (!fw_sysfs_done(fw_priv)) {
|
||||
for (i = 0; i < fw_priv->nr_pages; i++)
|
||||
__free_page(fw_priv->pages[i]);
|
||||
vfree(fw_priv->pages);
|
||||
fw_priv->pages = NULL;
|
||||
fw_priv->page_array_size = 0;
|
||||
fw_priv->nr_pages = 0;
|
||||
fw_free_paged_buf(fw_priv);
|
||||
fw_state_start(fw_priv);
|
||||
}
|
||||
break;
|
||||
@@ -284,7 +264,7 @@ static ssize_t firmware_loading_store(struct device *dev,
|
||||
* see the mapped 'buf->data' once the loading
|
||||
* is completed.
|
||||
* */
|
||||
rc = map_fw_priv_pages(fw_priv);
|
||||
rc = fw_map_paged_buf(fw_priv);
|
||||
if (rc)
|
||||
dev_err(dev, "%s: map pages failed\n",
|
||||
__func__);
|
||||
@@ -389,40 +369,13 @@ out:
|
||||
|
||||
static int fw_realloc_pages(struct fw_sysfs *fw_sysfs, int min_size)
|
||||
{
|
||||
struct fw_priv *fw_priv= fw_sysfs->fw_priv;
|
||||
int pages_needed = PAGE_ALIGN(min_size) >> PAGE_SHIFT;
|
||||
int err;
|
||||
|
||||
/* If the array of pages is too small, grow it... */
|
||||
if (fw_priv->page_array_size < pages_needed) {
|
||||
int new_array_size = max(pages_needed,
|
||||
fw_priv->page_array_size * 2);
|
||||
struct page **new_pages;
|
||||
|
||||
new_pages = vmalloc(array_size(new_array_size, sizeof(void *)));
|
||||
if (!new_pages) {
|
||||
fw_load_abort(fw_sysfs);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memcpy(new_pages, fw_priv->pages,
|
||||
fw_priv->page_array_size * sizeof(void *));
|
||||
memset(&new_pages[fw_priv->page_array_size], 0, sizeof(void *) *
|
||||
(new_array_size - fw_priv->page_array_size));
|
||||
vfree(fw_priv->pages);
|
||||
fw_priv->pages = new_pages;
|
||||
fw_priv->page_array_size = new_array_size;
|
||||
}
|
||||
|
||||
while (fw_priv->nr_pages < pages_needed) {
|
||||
fw_priv->pages[fw_priv->nr_pages] =
|
||||
alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
|
||||
|
||||
if (!fw_priv->pages[fw_priv->nr_pages]) {
|
||||
fw_load_abort(fw_sysfs);
|
||||
return -ENOMEM;
|
||||
}
|
||||
fw_priv->nr_pages++;
|
||||
}
|
||||
return 0;
|
||||
err = fw_grow_paged_buf(fw_sysfs->fw_priv,
|
||||
PAGE_ALIGN(min_size) >> PAGE_SHIFT);
|
||||
if (err)
|
||||
fw_load_abort(fw_sysfs);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -659,7 +612,7 @@ static bool fw_run_sysfs_fallback(enum fw_opt opt_flags)
|
||||
/* Also permit LSMs and IMA to fail firmware sysfs fallback */
|
||||
ret = security_kernel_load_data(LOADING_FIRMWARE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return false;
|
||||
|
||||
return fw_force_sysfs_fallback(opt_flags);
|
||||
}
|
||||
|
@@ -64,12 +64,14 @@ struct fw_priv {
|
||||
void *data;
|
||||
size_t size;
|
||||
size_t allocated_size;
|
||||
#ifdef CONFIG_FW_LOADER_USER_HELPER
|
||||
#ifdef CONFIG_FW_LOADER_PAGED_BUF
|
||||
bool is_paged_buf;
|
||||
bool need_uevent;
|
||||
struct page **pages;
|
||||
int nr_pages;
|
||||
int page_array_size;
|
||||
#endif
|
||||
#ifdef CONFIG_FW_LOADER_USER_HELPER
|
||||
bool need_uevent;
|
||||
struct list_head pending_list;
|
||||
#endif
|
||||
const char *fw_name;
|
||||
@@ -133,4 +135,14 @@ static inline void fw_state_done(struct fw_priv *fw_priv)
|
||||
int assign_fw(struct firmware *fw, struct device *device,
|
||||
enum fw_opt opt_flags);
|
||||
|
||||
#ifdef CONFIG_FW_LOADER_PAGED_BUF
|
||||
void fw_free_paged_buf(struct fw_priv *fw_priv);
|
||||
int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed);
|
||||
int fw_map_paged_buf(struct fw_priv *fw_priv);
|
||||
#else
|
||||
static inline void fw_free_paged_buf(struct fw_priv *fw_priv) {}
|
||||
int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed) { return -ENXIO; }
|
||||
int fw_map_paged_buf(struct fw_priv *fw_priv) { return -ENXIO; }
|
||||
#endif
|
||||
|
||||
#endif /* __FIRMWARE_LOADER_H */
|
||||
|
@@ -33,6 +33,7 @@
|
||||
#include <linux/syscore_ops.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/xz.h>
|
||||
|
||||
#include <generated/utsrelease.h>
|
||||
|
||||
@@ -251,15 +252,7 @@ static void __free_fw_priv(struct kref *ref)
|
||||
list_del(&fw_priv->list);
|
||||
spin_unlock(&fwc->lock);
|
||||
|
||||
#ifdef CONFIG_FW_LOADER_USER_HELPER
|
||||
if (fw_priv->is_paged_buf) {
|
||||
int i;
|
||||
vunmap(fw_priv->data);
|
||||
for (i = 0; i < fw_priv->nr_pages; i++)
|
||||
__free_page(fw_priv->pages[i]);
|
||||
vfree(fw_priv->pages);
|
||||
} else
|
||||
#endif
|
||||
fw_free_paged_buf(fw_priv); /* free leftover pages */
|
||||
if (!fw_priv->allocated_size)
|
||||
vfree(fw_priv->data);
|
||||
kfree_const(fw_priv->fw_name);
|
||||
@@ -274,6 +267,174 @@ static void free_fw_priv(struct fw_priv *fw_priv)
|
||||
spin_unlock(&fwc->lock);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FW_LOADER_PAGED_BUF
|
||||
void fw_free_paged_buf(struct fw_priv *fw_priv)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!fw_priv->pages)
|
||||
return;
|
||||
|
||||
for (i = 0; i < fw_priv->nr_pages; i++)
|
||||
__free_page(fw_priv->pages[i]);
|
||||
kvfree(fw_priv->pages);
|
||||
fw_priv->pages = NULL;
|
||||
fw_priv->page_array_size = 0;
|
||||
fw_priv->nr_pages = 0;
|
||||
}
|
||||
|
||||
int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed)
|
||||
{
|
||||
/* If the array of pages is too small, grow it */
|
||||
if (fw_priv->page_array_size < pages_needed) {
|
||||
int new_array_size = max(pages_needed,
|
||||
fw_priv->page_array_size * 2);
|
||||
struct page **new_pages;
|
||||
|
||||
new_pages = kvmalloc_array(new_array_size, sizeof(void *),
|
||||
GFP_KERNEL);
|
||||
if (!new_pages)
|
||||
return -ENOMEM;
|
||||
memcpy(new_pages, fw_priv->pages,
|
||||
fw_priv->page_array_size * sizeof(void *));
|
||||
memset(&new_pages[fw_priv->page_array_size], 0, sizeof(void *) *
|
||||
(new_array_size - fw_priv->page_array_size));
|
||||
kvfree(fw_priv->pages);
|
||||
fw_priv->pages = new_pages;
|
||||
fw_priv->page_array_size = new_array_size;
|
||||
}
|
||||
|
||||
while (fw_priv->nr_pages < pages_needed) {
|
||||
fw_priv->pages[fw_priv->nr_pages] =
|
||||
alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
|
||||
|
||||
if (!fw_priv->pages[fw_priv->nr_pages])
|
||||
return -ENOMEM;
|
||||
fw_priv->nr_pages++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fw_map_paged_buf(struct fw_priv *fw_priv)
|
||||
{
|
||||
/* one pages buffer should be mapped/unmapped only once */
|
||||
if (!fw_priv->pages)
|
||||
return 0;
|
||||
|
||||
vunmap(fw_priv->data);
|
||||
fw_priv->data = vmap(fw_priv->pages, fw_priv->nr_pages, 0,
|
||||
PAGE_KERNEL_RO);
|
||||
if (!fw_priv->data)
|
||||
return -ENOMEM;
|
||||
|
||||
/* page table is no longer needed after mapping, let's free */
|
||||
kvfree(fw_priv->pages);
|
||||
fw_priv->pages = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* XZ-compressed firmware support
|
||||
*/
|
||||
#ifdef CONFIG_FW_LOADER_COMPRESS
|
||||
/* show an error and return the standard error code */
|
||||
static int fw_decompress_xz_error(struct device *dev, enum xz_ret xz_ret)
|
||||
{
|
||||
if (xz_ret != XZ_STREAM_END) {
|
||||
dev_warn(dev, "xz decompression failed (xz_ret=%d)\n", xz_ret);
|
||||
return xz_ret == XZ_MEM_ERROR ? -ENOMEM : -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* single-shot decompression onto the pre-allocated buffer */
|
||||
static int fw_decompress_xz_single(struct device *dev, struct fw_priv *fw_priv,
|
||||
size_t in_size, const void *in_buffer)
|
||||
{
|
||||
struct xz_dec *xz_dec;
|
||||
struct xz_buf xz_buf;
|
||||
enum xz_ret xz_ret;
|
||||
|
||||
xz_dec = xz_dec_init(XZ_SINGLE, (u32)-1);
|
||||
if (!xz_dec)
|
||||
return -ENOMEM;
|
||||
|
||||
xz_buf.in_size = in_size;
|
||||
xz_buf.in = in_buffer;
|
||||
xz_buf.in_pos = 0;
|
||||
xz_buf.out_size = fw_priv->allocated_size;
|
||||
xz_buf.out = fw_priv->data;
|
||||
xz_buf.out_pos = 0;
|
||||
|
||||
xz_ret = xz_dec_run(xz_dec, &xz_buf);
|
||||
xz_dec_end(xz_dec);
|
||||
|
||||
fw_priv->size = xz_buf.out_pos;
|
||||
return fw_decompress_xz_error(dev, xz_ret);
|
||||
}
|
||||
|
||||
/* decompression on paged buffer and map it */
|
||||
static int fw_decompress_xz_pages(struct device *dev, struct fw_priv *fw_priv,
|
||||
size_t in_size, const void *in_buffer)
|
||||
{
|
||||
struct xz_dec *xz_dec;
|
||||
struct xz_buf xz_buf;
|
||||
enum xz_ret xz_ret;
|
||||
struct page *page;
|
||||
int err = 0;
|
||||
|
||||
xz_dec = xz_dec_init(XZ_DYNALLOC, (u32)-1);
|
||||
if (!xz_dec)
|
||||
return -ENOMEM;
|
||||
|
||||
xz_buf.in_size = in_size;
|
||||
xz_buf.in = in_buffer;
|
||||
xz_buf.in_pos = 0;
|
||||
|
||||
fw_priv->is_paged_buf = true;
|
||||
fw_priv->size = 0;
|
||||
do {
|
||||
if (fw_grow_paged_buf(fw_priv, fw_priv->nr_pages + 1)) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* decompress onto the new allocated page */
|
||||
page = fw_priv->pages[fw_priv->nr_pages - 1];
|
||||
xz_buf.out = kmap(page);
|
||||
xz_buf.out_pos = 0;
|
||||
xz_buf.out_size = PAGE_SIZE;
|
||||
xz_ret = xz_dec_run(xz_dec, &xz_buf);
|
||||
kunmap(page);
|
||||
fw_priv->size += xz_buf.out_pos;
|
||||
/* partial decompression means either end or error */
|
||||
if (xz_buf.out_pos != PAGE_SIZE)
|
||||
break;
|
||||
} while (xz_ret == XZ_OK);
|
||||
|
||||
err = fw_decompress_xz_error(dev, xz_ret);
|
||||
if (!err)
|
||||
err = fw_map_paged_buf(fw_priv);
|
||||
|
||||
out:
|
||||
xz_dec_end(xz_dec);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int fw_decompress_xz(struct device *dev, struct fw_priv *fw_priv,
|
||||
size_t in_size, const void *in_buffer)
|
||||
{
|
||||
/* if the buffer is pre-allocated, we can perform in single-shot mode */
|
||||
if (fw_priv->data)
|
||||
return fw_decompress_xz_single(dev, fw_priv, in_size, in_buffer);
|
||||
else
|
||||
return fw_decompress_xz_pages(dev, fw_priv, in_size, in_buffer);
|
||||
}
|
||||
#endif /* CONFIG_FW_LOADER_COMPRESS */
|
||||
|
||||
/* direct firmware loading support */
|
||||
static char fw_path_para[256];
|
||||
static const char * const fw_path[] = {
|
||||
@@ -293,7 +454,12 @@ module_param_string(path, fw_path_para, sizeof(fw_path_para), 0644);
|
||||
MODULE_PARM_DESC(path, "customized firmware image search path with a higher priority than default path");
|
||||
|
||||
static int
|
||||
fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv)
|
||||
fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv,
|
||||
const char *suffix,
|
||||
int (*decompress)(struct device *dev,
|
||||
struct fw_priv *fw_priv,
|
||||
size_t in_size,
|
||||
const void *in_buffer))
|
||||
{
|
||||
loff_t size;
|
||||
int i, len;
|
||||
@@ -301,9 +467,11 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv)
|
||||
char *path;
|
||||
enum kernel_read_file_id id = READING_FIRMWARE;
|
||||
size_t msize = INT_MAX;
|
||||
void *buffer = NULL;
|
||||
|
||||
/* Already populated data member means we're loading into a buffer */
|
||||
if (fw_priv->data) {
|
||||
if (!decompress && fw_priv->data) {
|
||||
buffer = fw_priv->data;
|
||||
id = READING_FIRMWARE_PREALLOC_BUFFER;
|
||||
msize = fw_priv->allocated_size;
|
||||
}
|
||||
@@ -317,15 +485,15 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv)
|
||||
if (!fw_path[i][0])
|
||||
continue;
|
||||
|
||||
len = snprintf(path, PATH_MAX, "%s/%s",
|
||||
fw_path[i], fw_priv->fw_name);
|
||||
len = snprintf(path, PATH_MAX, "%s/%s%s",
|
||||
fw_path[i], fw_priv->fw_name, suffix);
|
||||
if (len >= PATH_MAX) {
|
||||
rc = -ENAMETOOLONG;
|
||||
break;
|
||||
}
|
||||
|
||||
fw_priv->size = 0;
|
||||
rc = kernel_read_file_from_path(path, &fw_priv->data, &size,
|
||||
rc = kernel_read_file_from_path(path, &buffer, &size,
|
||||
msize, id);
|
||||
if (rc) {
|
||||
if (rc != -ENOENT)
|
||||
@@ -336,8 +504,24 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv)
|
||||
path);
|
||||
continue;
|
||||
}
|
||||
dev_dbg(device, "direct-loading %s\n", fw_priv->fw_name);
|
||||
fw_priv->size = size;
|
||||
if (decompress) {
|
||||
dev_dbg(device, "f/w decompressing %s\n",
|
||||
fw_priv->fw_name);
|
||||
rc = decompress(device, fw_priv, size, buffer);
|
||||
/* discard the superfluous original content */
|
||||
vfree(buffer);
|
||||
buffer = NULL;
|
||||
if (rc) {
|
||||
fw_free_paged_buf(fw_priv);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
dev_dbg(device, "direct-loading %s\n",
|
||||
fw_priv->fw_name);
|
||||
if (!fw_priv->data)
|
||||
fw_priv->data = buffer;
|
||||
fw_priv->size = size;
|
||||
}
|
||||
fw_state_done(fw_priv);
|
||||
break;
|
||||
}
|
||||
@@ -584,7 +768,13 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
|
||||
if (ret <= 0) /* error or already assigned */
|
||||
goto out;
|
||||
|
||||
ret = fw_get_filesystem_firmware(device, fw->priv);
|
||||
ret = fw_get_filesystem_firmware(device, fw->priv, "", NULL);
|
||||
#ifdef CONFIG_FW_LOADER_COMPRESS
|
||||
if (ret == -ENOENT)
|
||||
ret = fw_get_filesystem_firmware(device, fw->priv, ".xz",
|
||||
fw_decompress_xz);
|
||||
#endif
|
||||
|
||||
if (ret) {
|
||||
if (!(opt_flags & FW_OPT_NO_WARN))
|
||||
dev_warn(device,
|
||||
|
@@ -66,6 +66,7 @@ static DEVICE_ATTR(cpulist, S_IRUGO, node_read_cpulist, NULL);
|
||||
* @dev: Device for this memory access class
|
||||
* @list_node: List element in the node's access list
|
||||
* @access: The access class rank
|
||||
* @hmem_attrs: Heterogeneous memory performance attributes
|
||||
*/
|
||||
struct node_access_nodes {
|
||||
struct device dev;
|
||||
@@ -673,8 +674,8 @@ int register_cpu_under_node(unsigned int cpu, unsigned int nid)
|
||||
/**
|
||||
* register_memory_node_under_compute_node - link memory node to its compute
|
||||
* node for a given access class.
|
||||
* @mem_node: Memory node number
|
||||
* @cpu_node: Cpu node number
|
||||
* @mem_nid: Memory node number
|
||||
* @cpu_nid: Cpu node number
|
||||
* @access: Access class to register
|
||||
*
|
||||
* Description:
|
||||
|
@@ -5,7 +5,7 @@
|
||||
* Copyright (c) 2002-3 Patrick Mochel
|
||||
* Copyright (c) 2002-3 Open Source Development Labs
|
||||
*
|
||||
* Please see Documentation/driver-model/platform.txt for more
|
||||
* Please see Documentation/driver-model/platform.rst for more
|
||||
* information.
|
||||
*/
|
||||
|
||||
|
@@ -2819,9 +2819,9 @@ static const struct device_type bmc_device_type = {
|
||||
.groups = bmc_dev_attr_groups,
|
||||
};
|
||||
|
||||
static int __find_bmc_guid(struct device *dev, void *data)
|
||||
static int __find_bmc_guid(struct device *dev, const void *data)
|
||||
{
|
||||
guid_t *guid = data;
|
||||
const guid_t *guid = data;
|
||||
struct bmc_device *bmc;
|
||||
int rv;
|
||||
|
||||
@@ -2857,9 +2857,9 @@ struct prod_dev_id {
|
||||
unsigned char device_id;
|
||||
};
|
||||
|
||||
static int __find_bmc_prod_dev_id(struct device *dev, void *data)
|
||||
static int __find_bmc_prod_dev_id(struct device *dev, const void *data)
|
||||
{
|
||||
struct prod_dev_id *cid = data;
|
||||
const struct prod_dev_id *cid = data;
|
||||
struct bmc_device *bmc;
|
||||
int rv;
|
||||
|
||||
|
@@ -426,7 +426,7 @@ static int ipmi_remove(struct platform_device *pdev)
|
||||
return ipmi_si_remove_by_dev(&pdev->dev);
|
||||
}
|
||||
|
||||
static int pdev_match_name(struct device *dev, void *data)
|
||||
static int pdev_match_name(struct device *dev, const void *data)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
const char *name = data;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* System Control and Management Interface (SCMI) Message Protocol
|
||||
* driver common header file containing some definitions, structures
|
||||
|
@@ -17,9 +17,9 @@ struct acpi_hid_uid {
|
||||
char uid[11]; /* UINT_MAX + null byte */
|
||||
};
|
||||
|
||||
static int __init match_acpi_dev(struct device *dev, void *data)
|
||||
static int __init match_acpi_dev(struct device *dev, const void *data)
|
||||
{
|
||||
struct acpi_hid_uid hid_uid = *(struct acpi_hid_uid *)data;
|
||||
struct acpi_hid_uid hid_uid = *(const struct acpi_hid_uid *)data;
|
||||
struct acpi_device *adev = to_acpi_device(dev);
|
||||
|
||||
if (acpi_match_device_ids(adev, hid_uid.hid))
|
||||
|
@@ -1,4 +1,4 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
/*
|
||||
* Texas Instruments System Control Interface (TISCI) Protocol
|
||||
*
|
||||
|
@@ -22,11 +22,6 @@ static const struct of_device_id fpga_region_of_match[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, fpga_region_of_match);
|
||||
|
||||
static int fpga_region_of_node_match(struct device *dev, const void *data)
|
||||
{
|
||||
return dev->of_node == data;
|
||||
}
|
||||
|
||||
/**
|
||||
* of_fpga_region_find - find FPGA region
|
||||
* @np: device node of FPGA Region
|
||||
@@ -37,7 +32,7 @@ static int fpga_region_of_node_match(struct device *dev, const void *data)
|
||||
*/
|
||||
static struct fpga_region *of_fpga_region_find(struct device_node *np)
|
||||
{
|
||||
return fpga_region_class_find(NULL, np, fpga_region_of_node_match);
|
||||
return fpga_region_class_find(NULL, np, device_match_of_node);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -41,7 +41,7 @@ MODULE_PARM_DESC(mask, "GPIO channel mask.");
|
||||
|
||||
/*
|
||||
* FIXME: convert this singleton driver to use the state container
|
||||
* design pattern, see Documentation/driver-model/design-patterns.txt
|
||||
* design pattern, see Documentation/driver-model/design-patterns.rst
|
||||
*/
|
||||
static struct cs5535_gpio_chip {
|
||||
struct gpio_chip chip;
|
||||
|
@@ -93,7 +93,7 @@ static struct bus_type mipi_dsi_bus_type = {
|
||||
.pm = &mipi_dsi_device_pm_ops,
|
||||
};
|
||||
|
||||
static int of_device_match(struct device *dev, void *data)
|
||||
static int of_device_match(struct device *dev, const void *data)
|
||||
{
|
||||
return dev->of_node == data;
|
||||
}
|
||||
|
@@ -2372,10 +2372,10 @@ static int tegra_dc_parse_dt(struct tegra_dc *dc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_dc_match_by_pipe(struct device *dev, void *data)
|
||||
static int tegra_dc_match_by_pipe(struct device *dev, const void *data)
|
||||
{
|
||||
struct tegra_dc *dc = dev_get_drvdata(dev);
|
||||
unsigned int pipe = (unsigned long)data;
|
||||
unsigned int pipe = (unsigned long)(void *)data;
|
||||
|
||||
return dc->pipe == pipe;
|
||||
}
|
||||
|
@@ -525,23 +525,12 @@ static const struct file_operations debug_func_knob_fops = {
|
||||
|
||||
static int debug_func_init(void)
|
||||
{
|
||||
struct dentry *file;
|
||||
int ret;
|
||||
|
||||
/* Create debugfs node */
|
||||
debug_debugfs_dir = debugfs_create_dir("coresight_cpu_debug", NULL);
|
||||
if (!debug_debugfs_dir) {
|
||||
pr_err("%s: unable to create debugfs directory\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
file = debugfs_create_file("enable", 0644, debug_debugfs_dir, NULL,
|
||||
&debug_func_knob_fops);
|
||||
if (!file) {
|
||||
pr_err("%s: unable to create enable knob file\n", __func__);
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
debugfs_create_file("enable", 0644, debug_debugfs_dir, NULL,
|
||||
&debug_func_knob_fops);
|
||||
|
||||
/* Register function to be called for panic */
|
||||
ret = atomic_notifier_chain_register(&panic_notifier_list,
|
||||
|
@@ -37,7 +37,7 @@ static int coresight_alloc_conns(struct device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int coresight_device_fwnode_match(struct device *dev, void *fwnode)
|
||||
int coresight_device_fwnode_match(struct device *dev, const void *fwnode)
|
||||
{
|
||||
return dev_fwnode(dev) == fwnode;
|
||||
}
|
||||
|
@@ -498,9 +498,9 @@ struct coresight_device *coresight_get_sink(struct list_head *path)
|
||||
return csdev;
|
||||
}
|
||||
|
||||
static int coresight_enabled_sink(struct device *dev, void *data)
|
||||
static int coresight_enabled_sink(struct device *dev, const void *data)
|
||||
{
|
||||
bool *reset = data;
|
||||
const bool *reset = data;
|
||||
struct coresight_device *csdev = to_coresight_device(dev);
|
||||
|
||||
if ((csdev->type == CORESIGHT_DEV_TYPE_SINK ||
|
||||
@@ -544,7 +544,7 @@ struct coresight_device *coresight_get_enabled_sink(bool deactivate)
|
||||
return dev ? to_coresight_device(dev) : NULL;
|
||||
}
|
||||
|
||||
static int coresight_sink_by_id(struct device *dev, void *data)
|
||||
static int coresight_sink_by_id(struct device *dev, const void *data)
|
||||
{
|
||||
struct coresight_device *csdev = to_coresight_device(dev);
|
||||
unsigned long hash;
|
||||
|
@@ -789,10 +789,9 @@ static int intel_th_populate(struct intel_th *th)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int match_devt(struct device *dev, void *data)
|
||||
static int match_devt(struct device *dev, const void *data)
|
||||
{
|
||||
dev_t devt = (dev_t)(unsigned long)data;
|
||||
|
||||
dev_t devt = (dev_t)(unsigned long)(void *)data;
|
||||
return dev->devt == devt;
|
||||
}
|
||||
|
||||
|
@@ -457,7 +457,7 @@ static struct pci_driver amd_mp2_pci_driver = {
|
||||
};
|
||||
module_pci_driver(amd_mp2_pci_driver);
|
||||
|
||||
static int amd_mp2_device_match(struct device *dev, void *data)
|
||||
static int amd_mp2_device_match(struct device *dev, const void *data)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
@@ -320,7 +320,7 @@ u32 i2c_acpi_find_bus_speed(struct device *dev)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(i2c_acpi_find_bus_speed);
|
||||
|
||||
static int i2c_acpi_find_match_adapter(struct device *dev, void *data)
|
||||
static int i2c_acpi_find_match_adapter(struct device *dev, const void *data)
|
||||
{
|
||||
struct i2c_adapter *adapter = i2c_verify_adapter(dev);
|
||||
|
||||
@@ -330,7 +330,7 @@ static int i2c_acpi_find_match_adapter(struct device *dev, void *data)
|
||||
return ACPI_HANDLE(dev) == (acpi_handle)data;
|
||||
}
|
||||
|
||||
static int i2c_acpi_find_match_device(struct device *dev, void *data)
|
||||
static int i2c_acpi_find_match_device(struct device *dev, const void *data)
|
||||
{
|
||||
return ACPI_COMPANION(dev) == data;
|
||||
}
|
||||
|
@@ -112,12 +112,12 @@ void of_i2c_register_devices(struct i2c_adapter *adap)
|
||||
of_node_put(bus);
|
||||
}
|
||||
|
||||
static int of_dev_node_match(struct device *dev, void *data)
|
||||
static int of_dev_node_match(struct device *dev, const void *data)
|
||||
{
|
||||
return dev->of_node == data;
|
||||
}
|
||||
|
||||
static int of_dev_or_parent_node_match(struct device *dev, void *data)
|
||||
static int of_dev_or_parent_node_match(struct device *dev, const void *data)
|
||||
{
|
||||
if (dev->of_node == data)
|
||||
return 1;
|
||||
|
@@ -90,7 +90,7 @@ static const struct iio_chan_spec
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
|
||||
static int iio_dev_node_match(struct device *dev, void *data)
|
||||
static int iio_dev_node_match(struct device *dev, const void *data)
|
||||
{
|
||||
return dev->of_node == data && dev->type == &iio_device_type;
|
||||
}
|
||||
|
@@ -4498,7 +4498,7 @@ static const struct acpi_device_id hns_roce_acpi_match[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, hns_roce_acpi_match);
|
||||
|
||||
static int hns_roce_node_match(struct device *dev, void *fwnode)
|
||||
static int hns_roce_node_match(struct device *dev, const void *fwnode)
|
||||
{
|
||||
return dev->fwnode == fwnode;
|
||||
}
|
||||
|
@@ -2034,7 +2034,7 @@ arm_smmu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova)
|
||||
|
||||
static struct platform_driver arm_smmu_driver;
|
||||
|
||||
static int arm_smmu_match_node(struct device *dev, void *data)
|
||||
static int arm_smmu_match_node(struct device *dev, const void *data)
|
||||
{
|
||||
return dev->fwnode == data;
|
||||
}
|
||||
|
@@ -1426,7 +1426,7 @@ static bool arm_smmu_capable(enum iommu_cap cap)
|
||||
}
|
||||
}
|
||||
|
||||
static int arm_smmu_match_node(struct device *dev, void *data)
|
||||
static int arm_smmu_match_node(struct device *dev, const void *data)
|
||||
{
|
||||
return dev->fwnode == data;
|
||||
}
|
||||
|
@@ -296,8 +296,6 @@ struct flexrm_mbox {
|
||||
struct dma_pool *bd_pool;
|
||||
struct dma_pool *cmpl_pool;
|
||||
struct dentry *root;
|
||||
struct dentry *config;
|
||||
struct dentry *stats;
|
||||
struct mbox_controller controller;
|
||||
};
|
||||
|
||||
@@ -1603,7 +1601,6 @@ static int flexrm_mbox_probe(struct platform_device *pdev)
|
||||
1 << RING_CMPL_ALIGN_ORDER, 0);
|
||||
if (!mbox->cmpl_pool) {
|
||||
ret = -ENOMEM;
|
||||
goto fail_destroy_bd_pool;
|
||||
}
|
||||
|
||||
/* Allocate platform MSIs for each ring */
|
||||
@@ -1624,28 +1621,15 @@ static int flexrm_mbox_probe(struct platform_device *pdev)
|
||||
|
||||
/* Create debugfs root entry */
|
||||
mbox->root = debugfs_create_dir(dev_name(mbox->dev), NULL);
|
||||
if (IS_ERR_OR_NULL(mbox->root)) {
|
||||
ret = PTR_ERR_OR_ZERO(mbox->root);
|
||||
goto fail_free_msis;
|
||||
}
|
||||
|
||||
/* Create debugfs config entry */
|
||||
mbox->config = debugfs_create_devm_seqfile(mbox->dev,
|
||||
"config", mbox->root,
|
||||
flexrm_debugfs_conf_show);
|
||||
if (IS_ERR_OR_NULL(mbox->config)) {
|
||||
ret = PTR_ERR_OR_ZERO(mbox->config);
|
||||
goto fail_free_debugfs_root;
|
||||
}
|
||||
debugfs_create_devm_seqfile(mbox->dev, "config", mbox->root,
|
||||
flexrm_debugfs_conf_show);
|
||||
|
||||
/* Create debugfs stats entry */
|
||||
mbox->stats = debugfs_create_devm_seqfile(mbox->dev,
|
||||
"stats", mbox->root,
|
||||
flexrm_debugfs_stats_show);
|
||||
if (IS_ERR_OR_NULL(mbox->stats)) {
|
||||
ret = PTR_ERR_OR_ZERO(mbox->stats);
|
||||
goto fail_free_debugfs_root;
|
||||
}
|
||||
debugfs_create_devm_seqfile(mbox->dev, "stats", mbox->root,
|
||||
flexrm_debugfs_stats_show);
|
||||
|
||||
skip_debugfs:
|
||||
|
||||
/* Initialize mailbox controller */
|
||||
@@ -1676,11 +1660,9 @@ skip_debugfs:
|
||||
|
||||
fail_free_debugfs_root:
|
||||
debugfs_remove_recursive(mbox->root);
|
||||
fail_free_msis:
|
||||
platform_msi_domain_free_irqs(dev);
|
||||
fail_destroy_cmpl_pool:
|
||||
dma_pool_destroy(mbox->cmpl_pool);
|
||||
fail_destroy_bd_pool:
|
||||
dma_pool_destroy(mbox->bd_pool);
|
||||
fail:
|
||||
return ret;
|
||||
|
@@ -395,8 +395,6 @@ struct pdc_state {
|
||||
*/
|
||||
struct scatterlist *src_sg[PDC_RING_ENTRIES];
|
||||
|
||||
struct dentry *debugfs_stats; /* debug FS stats file for this PDC */
|
||||
|
||||
/* counters */
|
||||
u32 pdc_requests; /* number of request messages submitted */
|
||||
u32 pdc_replies; /* number of reply messages received */
|
||||
@@ -501,9 +499,8 @@ static void pdc_setup_debugfs(struct pdc_state *pdcs)
|
||||
debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
|
||||
|
||||
/* S_IRUSR == 0400 */
|
||||
pdcs->debugfs_stats = debugfs_create_file(spu_stats_name, 0400,
|
||||
debugfs_dir, pdcs,
|
||||
&pdc_debugfs_stats);
|
||||
debugfs_create_file(spu_stats_name, 0400, debugfs_dir, pdcs,
|
||||
&pdc_debugfs_stats);
|
||||
}
|
||||
|
||||
static void pdc_free_debugfs(void)
|
||||
@@ -1603,7 +1600,6 @@ static int pdc_probe(struct platform_device *pdev)
|
||||
if (err)
|
||||
goto cleanup_buf_pool;
|
||||
|
||||
pdcs->debugfs_stats = NULL;
|
||||
pdc_setup_debugfs(pdcs);
|
||||
|
||||
dev_dbg(dev, "pdc_probe() successful");
|
||||
|
@@ -92,9 +92,9 @@ static struct regmap_config altr_sysmgr_regmap_cfg = {
|
||||
* Matching function used by driver_find_device().
|
||||
* Return: True if match is found, otherwise false.
|
||||
*/
|
||||
static int sysmgr_match_phandle(struct device *dev, void *data)
|
||||
static int sysmgr_match_phandle(struct device *dev, const void *data)
|
||||
{
|
||||
return dev->of_node == (struct device_node *)data;
|
||||
return dev->of_node == (const struct device_node *)data;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -190,27 +190,6 @@ struct regmap *syscon_regmap_lookup_by_compatible(const char *s)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_compatible);
|
||||
|
||||
static int syscon_match_pdevname(struct device *dev, void *data)
|
||||
{
|
||||
return !strcmp(dev_name(dev), (const char *)data);
|
||||
}
|
||||
|
||||
struct regmap *syscon_regmap_lookup_by_pdevname(const char *s)
|
||||
{
|
||||
struct device *dev;
|
||||
struct syscon *syscon;
|
||||
|
||||
dev = driver_find_device(&syscon_driver.driver, NULL, (void *)s,
|
||||
syscon_match_pdevname);
|
||||
if (!dev)
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
|
||||
syscon = dev_get_drvdata(dev);
|
||||
|
||||
return syscon->regmap;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_pdevname);
|
||||
|
||||
struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np,
|
||||
const char *property)
|
||||
{
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user