Pull char/misc driver updates from Greg KH: "Here is the big char/misc driver update for 4.14-rc1. Lots of different stuff in here, it's been an active development cycle for some reason. Highlights are: - updated binder driver, this brings binder up to date with what shipped in the Android O release, plus some more changes that happened since then that are in the Android development trees. - coresight updates and fixes - mux driver file renames to be a bit "nicer" - intel_th driver updates - normal set of hyper-v updates and changes - small fpga subsystem and driver updates - lots of const code changes all over the driver trees - extcon driver updates - fmc driver subsystem upadates - w1 subsystem minor reworks and new features and drivers added - spmi driver updates Plus a smattering of other minor driver updates and fixes. All of these have been in linux-next with no reported issues for a while" * tag 'char-misc-4.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (244 commits) ANDROID: binder: don't queue async transactions to thread. ANDROID: binder: don't enqueue death notifications to thread todo. ANDROID: binder: Don't BUG_ON(!spin_is_locked()). ANDROID: binder: Add BINDER_GET_NODE_DEBUG_INFO ioctl ANDROID: binder: push new transactions to waiting threads. ANDROID: binder: remove proc waitqueue android: binder: Add page usage in binder stats android: binder: fixup crash introduced by moving buffer hdr drivers: w1: add hwmon temp support for w1_therm drivers: w1: refactor w1_slave_show to make the temp reading functionality separate drivers: w1: add hwmon support structures eeprom: idt_89hpesx: Support both ACPI and OF probing mcb: Fix an error handling path in 'chameleon_parse_cells()' MCB: add support for SC31 to mcb-lpc mux: make device_type const char: virtio: constify attribute_group structures. Documentation/ABI: document the nvmem sysfs files lkdtm: fix spelling mistake: "incremeted" -> "incremented" perf: cs-etm: Fix ETMv4 CONFIGR entry in perf.data file nvmem: include linux/err.h from header ...
Unified · Split
| @@ -0,0 +1,19 @@ | |||
| 1 | What: /sys/bus/nvmem/devices/.../nvmem | ||
| 2 | Date: July 2015 | ||
| 3 | KernelVersion: 4.2 | ||
| 4 | Contact: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> | ||
| 5 | Description: | ||
| 6 | This file allows user to read/write the raw NVMEM contents. | ||
| 7 | Permissions for write to this file depends on the nvmem | ||
| 8 | provider configuration. | ||
| 9 | |||
| 10 | ex: | ||
| 11 | hexdump /sys/bus/nvmem/devices/qfprom0/nvmem | ||
| 12 | |||
| 13 | 0000000 0000 0000 0000 0000 0000 0000 0000 0000 | ||
| 14 | * | ||
| 15 | 00000a0 db10 2240 0000 e000 0c00 0c00 0000 0c00 | ||
| 16 | 0000000 0000 0000 0000 0000 0000 0000 0000 0000 | ||
| 17 | ... | ||
| 18 | * | ||
| 19 | 0001000 | ||
| @@ -45,6 +45,8 @@ Contact: thunderbolt-software@lists.01.org · 44 unmodified lines | |||
| 45 | Description: When a devices supports Thunderbolt secure connect it will | 45 | Description: When a devices supports Thunderbolt secure connect it will |
| 46 | have this attribute. Writing 32 byte hex string changes | 46 | have this attribute. Writing 32 byte hex string changes |
| 47 | authorization to use the secure connection method instead. | 47 | authorization to use the secure connection method instead. |
| 48 | Writing an empty string clears the key and regular connection | ||
| 49 | method can be used again. | ||
| 48 | 50 | ||
| 49 | What: /sys/bus/thunderbolt/devices/.../device | 51 | What: /sys/bus/thunderbolt/devices/.../device |
| 50 | Date: Sep 2017 | 52 | Date: Sep 2017 |
| @@ -0,0 +1,8 @@ | |||
| 1 | What: /sys/bus/pci/drivers/altera-cvp/chkcfg | ||
| 2 | Date: May 2017 | ||
| 3 | Kernel Version: 4.13 | ||
| 4 | Contact: Anatolij Gustschin <agust@denx.de> | ||
| 5 | Description: | ||
| 6 | Contains either 1 or 0 and controls if configuration | ||
| 7 | error checking in altera-cvp driver is turned on or | ||
| 8 | off. | ||
| @@ -3081,3 +3081,8 @@ · 3080 unmodified lines | |||
| 3081 | 1 = /dev/osd1 Second OSD Device | 3081 | 1 = /dev/osd1 Second OSD Device |
| 3082 | ... | 3082 | ... |
| 3083 | 255 = /dev/osd255 256th OSD Device | 3083 | 255 = /dev/osd255 256th OSD Device |
| 3084 | |||
| 3085 | 384-511 char RESERVED FOR DYNAMIC ASSIGNMENT | ||
| 3086 | Character devices that request a dynamic allocation of major | ||
| 3087 | number will take numbers starting from 511 and downward, | ||
| 3088 | once the 234-254 range is full. | ||
| @@ -34,8 +34,8 @@ its hardware characteristcs. · 33 unmodified lines | |||
| 34 | - Embedded Trace Macrocell (version 4.x): | 34 | - Embedded Trace Macrocell (version 4.x): |
| 35 | "arm,coresight-etm4x", "arm,primecell"; | 35 | "arm,coresight-etm4x", "arm,primecell"; |
| 36 | 36 | ||
| 37 | - Qualcomm Configurable Replicator (version 1.x): | 37 | - Coresight programmable Replicator : |
| 38 | "qcom,coresight-replicator1x", "arm,primecell"; | 38 | "arm,coresight-dynamic-replicator", "arm,primecell"; |
| 39 | 39 | ||
| 40 | - System Trace Macrocell: | 40 | - System Trace Macrocell: |
| 41 | "arm,coresight-stm", "arm,primecell"; [1] | 41 | "arm,coresight-stm", "arm,primecell"; [1] |
| @@ -0,0 +1,24 @@ | |||
| 1 | ChromeOS EC USB Type-C cable and accessories detection | ||
| 2 | |||
| 3 | On ChromeOS systems with USB Type C ports, the ChromeOS Embedded Controller is | ||
| 4 | able to detect the state of external accessories such as display adapters | ||
| 5 | or USB devices when said accessories are attached or detached. | ||
| 6 | |||
| 7 | The node for this device must be under a cros-ec node like google,cros-ec-spi | ||
| 8 | or google,cros-ec-i2c. | ||
| 9 | |||
| 10 | Required properties: | ||
| 11 | - compatible: Should be "google,extcon-usbc-cros-ec". | ||
| 12 | - google,usb-port-id: Specifies the USB port ID to use. | ||
| 13 | |||
| 14 | Example: | ||
| 15 | cros-ec@0 { | ||
| 16 | compatible = "google,cros-ec-i2c"; | ||
| 17 | |||
| 18 | ... | ||
| 19 | |||
| 20 | extcon { | ||
| 21 | compatible = "google,extcon-usbc-cros-ec"; | ||
| 22 | google,usb-port-id = <0>; | ||
| 23 | }; | ||
| 24 | } | ||
| @@ -0,0 +1,29 @@ | |||
| 1 | Altera Passive Serial SPI FPGA Manager | ||
| 2 | |||
| 3 | Altera FPGAs support a method of loading the bitstream over what is | ||
| 4 | referred to as "passive serial". | ||
| 5 | The passive serial link is not technically SPI, and might require extra | ||
| 6 | circuits in order to play nicely with other SPI slaves on the same bus. | ||
| 7 | |||
| 8 | See https://www.altera.com/literature/hb/cyc/cyc_c51013.pdf | ||
| 9 | |||
| 10 | Required properties: | ||
| 11 | - compatible: Must be one of the following: | ||
| 12 | "altr,fpga-passive-serial", | ||
| 13 | "altr,fpga-arria10-passive-serial" | ||
| 14 | - reg: SPI chip select of the FPGA | ||
| 15 | - nconfig-gpios: config pin (referred to as nCONFIG in the manual) | ||
| 16 | - nstat-gpios: status pin (referred to as nSTATUS in the manual) | ||
| 17 | |||
| 18 | Optional properties: | ||
| 19 | - confd-gpios: confd pin (referred to as CONF_DONE in the manual) | ||
| 20 | |||
| 21 | Example: | ||
| 22 | fpga: fpga@0 { | ||
| 23 | compatible = "altr,fpga-passive-serial"; | ||
| 24 | spi-max-frequency = <20000000>; | ||
| 25 | reg = <0>; | ||
| 26 | nconfig-gpios = <&gpio4 9 GPIO_ACTIVE_LOW>; | ||
| 27 | nstat-gpios = <&gpio4 11 GPIO_ACTIVE_LOW>; | ||
| 28 | confd-gpios = <&gpio4 12 GPIO_ACTIVE_LOW>; | ||
| 29 | }; | ||
| @@ -0,0 +1,36 @@ | |||
| 1 | Xilinx LogiCORE Partial Reconfig Decoupler Softcore | ||
| 2 | |||
| 3 | The Xilinx LogiCORE Partial Reconfig Decoupler manages one or more | ||
| 4 | decouplers / fpga bridges. | ||
| 5 | The controller can decouple/disable the bridges which prevents signal | ||
| 6 | changes from passing through the bridge. The controller can also | ||
| 7 | couple / enable the bridges which allows traffic to pass through the | ||
| 8 | bridge normally. | ||
| 9 | |||
| 10 | The Driver supports only MMIO handling. A PR region can have multiple | ||
| 11 | PR Decouplers which can be handled independently or chained via decouple/ | ||
| 12 | decouple_status signals. | ||
| 13 | |||
| 14 | Required properties: | ||
| 15 | - compatible : Should contain "xlnx,pr-decoupler-1.00" followed by | ||
| 16 | "xlnx,pr-decoupler" | ||
| 17 | - regs : base address and size for decoupler module | ||
| 18 | - clocks : input clock to IP | ||
| 19 | - clock-names : should contain "aclk" | ||
| 20 | |||
| 21 | Optional properties: | ||
| 22 | - bridge-enable : 0 if driver should disable bridge at startup | ||
| 23 | 1 if driver should enable bridge at startup | ||
| 24 | Default is to leave bridge in current state. | ||
| 25 | |||
| 26 | See Documentation/devicetree/bindings/fpga/fpga-region.txt for generic bindings. | ||
| 27 | |||
| 28 | Example: | ||
| 29 | fpga-bridge@100000450 { | ||
| 30 | compatible = "xlnx,pr-decoupler-1.00", | ||
| 31 | "xlnx-pr-decoupler"; | ||
| 32 | regs = <0x10000045 0x10>; | ||
| 33 | clocks = <&clkc 15>; | ||
| 34 | clock-names = "aclk"; | ||
| 35 | bridge-enable = <0>; | ||
| 36 | }; | ||
| @@ -175,6 +175,7 @@ kosagi Sutajio Ko-Usagi PTE Ltd. · 174 unmodified lines | |||
| 175 | kyo Kyocera Corporation | 175 | kyo Kyocera Corporation |
| 176 | lacie LaCie | 176 | lacie LaCie |
| 177 | lantiq Lantiq Semiconductor | 177 | lantiq Lantiq Semiconductor |
| 178 | lattice Lattice Semiconductor | ||
| 178 | lego LEGO Systems A/S | 179 | lego LEGO Systems A/S |
| 179 | lenovo Lenovo Group Ltd. | 180 | lenovo Lenovo Group Ltd. |
| 180 | lg LG Corporation | 181 | lg LG Corporation |
| @@ -281,6 +281,8 @@ · 280 unmodified lines | |||
| 281 | capabilities of the underlying ICAP hardware | 281 | capabilities of the underlying ICAP hardware |
| 282 | differ between different families. May be | 282 | differ between different families. May be |
| 283 | 'virtex2p', 'virtex4', or 'virtex5'. | 283 | 'virtex2p', 'virtex4', or 'virtex5'. |
| 284 | - compatible : should contain "xlnx,xps-hwicap-1.00.a" or | ||
| 285 | "xlnx,opb-hwicap-1.00.b". | ||
| 284 | 286 | ||
| 285 | vi) Xilinx Uart 16550 | 287 | vi) Xilinx Uart 16550 |
| 286 | 288 | ||
| @@ -83,7 +83,7 @@ by writing the name of the desired stm device there, for example: · 82 unmodified lines | |||
| 83 | $ echo dummy_stm.0 > /sys/class/stm_source/console/stm_source_link | 83 | $ echo dummy_stm.0 > /sys/class/stm_source/console/stm_source_link |
| 84 | 84 | ||
| 85 | For examples on how to use stm_source interface in the kernel, refer | 85 | For examples on how to use stm_source interface in the kernel, refer |
| 86 | to stm_console or stm_heartbeat drivers. | 86 | to stm_console, stm_heartbeat or stm_ftrace drivers. |
| 87 | 87 | ||
| 88 | Each stm_source device will need to assume a master and a range of | 88 | Each stm_source device will need to assume a master and a range of |
| 89 | channels, depending on how many channels it requires. These are | 89 | channels, depending on how many channels it requires. These are |
| @@ -107,5 +107,16 @@ console in the STP stream, create a "console" policy entry (see the · 17 unmodified lines | |||
| 107 | beginning of this text on how to do that). When initialized, it will | 107 | beginning of this text on how to do that). When initialized, it will |
| 108 | consume one channel. | 108 | consume one channel. |
| 109 | 109 | ||
| 110 | stm_ftrace | ||
| 111 | ========== | ||
| 112 | |||
| 113 | This is another "stm_source" device, once the stm_ftrace has been | ||
| 114 | linked with an stm device, and if "function" tracer is enabled, | ||
| 115 | function address and parent function address which Ftrace subsystem | ||
| 116 | would store into ring buffer will be exported via the stm device at | ||
| 117 | the same time. | ||
| 118 | |||
| 119 | Currently only Ftrace "function" tracer is supported. | ||
| 120 | |||
| 110 | [1] https://software.intel.com/sites/default/files/managed/d3/3c/intel-th-developer-manual.pdf | 121 | [1] https://software.intel.com/sites/default/files/managed/d3/3c/intel-th-developer-manual.pdf |
| 111 | [2] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0444b/index.html | 122 | [2] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0444b/index.html |
| @@ -5362,10 +5362,11 @@ K: fmc_d.*register · 5361 unmodified lines | |||
| 5362 | 5362 | ||
| 5363 | FPGA MANAGER FRAMEWORK | 5363 | FPGA MANAGER FRAMEWORK |
| 5364 | M: Alan Tull <atull@kernel.org> | 5364 | M: Alan Tull <atull@kernel.org> |
| 5365 | R: Moritz Fischer <moritz.fischer@ettus.com> | 5365 | R: Moritz Fischer <mdf@kernel.org> |
| 5366 | L: linux-fpga@vger.kernel.org | 5366 | L: linux-fpga@vger.kernel.org |
| 5367 | S: Maintained | 5367 | S: Maintained |
| 5368 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/atull/linux-fpga.git | 5368 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/atull/linux-fpga.git |
| 5369 | Q: http://patchwork.kernel.org/project/linux-fpga/list/ | ||
| 5369 | F: Documentation/fpga/ | 5370 | F: Documentation/fpga/ |
| 5370 | F: Documentation/devicetree/bindings/fpga/ | 5371 | F: Documentation/devicetree/bindings/fpga/ |
| 5371 | F: drivers/fpga/ | 5372 | F: drivers/fpga/ |
| @@ -9484,6 +9485,7 @@ M: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> · 4112 unmodified lines | |||
| 9484 | S: Maintained | 9485 | S: Maintained |
| 9485 | F: drivers/nvmem/ | 9486 | F: drivers/nvmem/ |
| 9486 | F: Documentation/devicetree/bindings/nvmem/ | 9487 | F: Documentation/devicetree/bindings/nvmem/ |
| 9488 | F: Documentation/ABI/stable/sysfs-bus-nvmem | ||
| 9487 | F: include/linux/nvmem-consumer.h | 9489 | F: include/linux/nvmem-consumer.h |
| 9488 | F: include/linux/nvmem-provider.h | 9490 | F: include/linux/nvmem-provider.h |
| 9489 | 9491 | ||
| @@ -94,6 +94,15 @@ · 93 unmodified lines | |||
| 94 | pinctrl-names = "default"; | 94 | pinctrl-names = "default"; |
| 95 | pinctrl-0 = <&pinctrl_ecspi1 &pinctrl_ecspi1cs>; | 95 | pinctrl-0 = <&pinctrl_ecspi1 &pinctrl_ecspi1cs>; |
| 96 | status = "okay"; | 96 | status = "okay"; |
| 97 | |||
| 98 | fpga: fpga@0 { | ||
| 99 | compatible = "altr,fpga-passive-serial"; | ||
| 100 | spi-max-frequency = <20000000>; | ||
| 101 | reg = <0>; | ||
| 102 | pinctrl-0 = <&pinctrl_fpgaspi>; | ||
| 103 | nconfig-gpios = <&gpio4 9 GPIO_ACTIVE_LOW>; | ||
| 104 | nstat-gpios = <&gpio4 11 GPIO_ACTIVE_LOW>; | ||
| 105 | }; | ||
| 97 | }; | 106 | }; |
| 98 | 107 | ||
| 99 | &ecspi3 { | 108 | &ecspi3 { |
| @@ -319,6 +328,13 @@ · 219 unmodified lines | |||
| 319 | >; | 328 | >; |
| 320 | }; | 329 | }; |
| 321 | 330 | ||
| 331 | pinctrl_fpgaspi: fpgaspigrp { | ||
| 332 | fsl,pins = < | ||
| 333 | MX6QDL_PAD_KEY_ROW1__GPIO4_IO09 0x1b0b0 | ||
| 334 | MX6QDL_PAD_KEY_ROW2__GPIO4_IO11 0x1b0b0 | ||
| 335 | >; | ||
| 336 | }; | ||
| 337 | |||
| 322 | pinctrl_gpminand: gpminandgrp { | 338 | pinctrl_gpminand: gpminandgrp { |
| 323 | fsl,pins = < | 339 | fsl,pins = < |
| 324 | MX6QDL_PAD_NANDF_CLE__NAND_CLE 0xb0b1 | 340 | MX6QDL_PAD_NANDF_CLE__NAND_CLE 0xb0b1 |
| @@ -28,6 +28,8 @@ struct ms_hyperv_info { · 27 unmodified lines | |||
| 28 | u32 features; | 28 | u32 features; |
| 29 | u32 misc_features; | 29 | u32 misc_features; |
| 30 | u32 hints; | 30 | u32 hints; |
| 31 | u32 max_vp_index; | ||
| 32 | u32 max_lp_index; | ||
| 31 | }; | 33 | }; |
| 32 | 34 | ||
| 33 | extern struct ms_hyperv_info ms_hyperv; | 35 | extern struct ms_hyperv_info ms_hyperv; |
| @@ -179,9 +179,15 @@ static void __init ms_hyperv_init_platform(void) · 178 unmodified lines | |||
| 179 | ms_hyperv.misc_features = cpuid_edx(HYPERV_CPUID_FEATURES); | 179 | ms_hyperv.misc_features = cpuid_edx(HYPERV_CPUID_FEATURES); |
| 180 | ms_hyperv.hints = cpuid_eax(HYPERV_CPUID_ENLIGHTMENT_INFO); | 180 | ms_hyperv.hints = cpuid_eax(HYPERV_CPUID_ENLIGHTMENT_INFO); |
| 181 | 181 | ||
| 182 | pr_info("HyperV: features 0x%x, hints 0x%x\n", | 182 | pr_info("Hyper-V: features 0x%x, hints 0x%x\n", |
| 183 | ms_hyperv.features, ms_hyperv.hints); | 183 | ms_hyperv.features, ms_hyperv.hints); |
| 184 | 184 | ||
| 185 | ms_hyperv.max_vp_index = cpuid_eax(HVCPUID_IMPLEMENTATION_LIMITS); | ||
| 186 | ms_hyperv.max_lp_index = cpuid_ebx(HVCPUID_IMPLEMENTATION_LIMITS); | ||
| 187 | |||
| 188 | pr_debug("Hyper-V: max %u virtual processors, %u logical processors\n", | ||
| 189 | ms_hyperv.max_vp_index, ms_hyperv.max_lp_index); | ||
| 190 | |||
| 185 | /* | 191 | /* |
| 186 | * Extract host information. | 192 | * Extract host information. |
| 187 | */ | 193 | */ |
| @@ -214,7 +220,7 @@ static void __init ms_hyperv_init_platform(void) · 26 unmodified lines | |||
| 214 | rdmsrl(HV_X64_MSR_APIC_FREQUENCY, hv_lapic_frequency); | 220 | rdmsrl(HV_X64_MSR_APIC_FREQUENCY, hv_lapic_frequency); |
| 215 | hv_lapic_frequency = div_u64(hv_lapic_frequency, HZ); | 221 | hv_lapic_frequency = div_u64(hv_lapic_frequency, HZ); |
| 216 | lapic_timer_frequency = hv_lapic_frequency; | 222 | lapic_timer_frequency = hv_lapic_frequency; |
| 217 | pr_info("HyperV: LAPIC Timer Frequency: %#x\n", | 223 | pr_info("Hyper-V: LAPIC Timer Frequency: %#x\n", |
| 218 | lapic_timer_frequency); | 224 | lapic_timer_frequency); |
| 219 | } | 225 | } |
| 220 | 226 | ||
| @@ -248,7 +254,7 @@ static void __init ms_hyperv_init_platform(void) · 27 unmodified lines | |||
| 248 | } | 254 | } |
| 249 | 255 | ||
| 250 | const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = { | 256 | const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = { |
| 251 | .name = "Microsoft HyperV", | 257 | .name = "Microsoft Hyper-V", |
| 252 | .detect = ms_hyperv_platform, | 258 | .detect = ms_hyperv_platform, |
| 253 | .init_platform = ms_hyperv_init_platform, | 259 | .init_platform = ms_hyperv_init_platform, |
| 254 | }; | 260 | }; |
| @@ -242,6 +242,7 @@ EXPORT_SYMBOL_GPL(disk_map_sector_rcu); · 241 unmodified lines | |||
| 242 | * Can be deleted altogether. Later. | 242 | * Can be deleted altogether. Later. |
| 243 | * | 243 | * |
| 244 | */ | 244 | */ |
| 245 | #define BLKDEV_MAJOR_HASH_SIZE 255 | ||
| 245 | static struct blk_major_name { | 246 | static struct blk_major_name { |
| 246 | struct blk_major_name *next; | 247 | struct blk_major_name *next; |
| 247 | int major; | 248 | int major; |
| @@ -259,12 +260,11 @@ void blkdev_show(struct seq_file *seqf, off_t offset) · 11 unmodified lines | |||
| 259 | { | 260 | { |
| 260 | struct blk_major_name *dp; | 261 | struct blk_major_name *dp; |
| 261 | 262 | ||
| 262 | if (offset < BLKDEV_MAJOR_HASH_SIZE) { | 263 | mutex_lock(&block_class_lock); |
| 263 | mutex_lock(&block_class_lock); | 264 | for (dp = major_names[major_to_index(offset)]; dp; dp = dp->next) |
| 264 | for (dp = major_names[offset]; dp; dp = dp->next) | 265 | if (dp->major == offset) |
| 265 | seq_printf(seqf, "%3d %s\n", dp->major, dp->name); | 266 | seq_printf(seqf, "%3d %s\n", dp->major, dp->name); |
| 266 | mutex_unlock(&block_class_lock); | 267 | mutex_unlock(&block_class_lock); |
| 267 | } | ||
| 268 | } | 268 | } |
| 269 | #endif /* CONFIG_PROC_FS */ | 269 | #endif /* CONFIG_PROC_FS */ |
| 270 | 270 | ||
| @@ -309,6 +309,14 @@ int register_blkdev(unsigned int major, const char *name) · 38 unmodified lines | |||
| 309 | ret = major; | 309 | ret = major; |
| 310 | } | 310 | } |
| 311 | 311 | ||
| 312 | if (major >= BLKDEV_MAJOR_MAX) { | ||
| 313 | pr_err("register_blkdev: major requested (%d) is greater than the maximum (%d) for %s\n", | ||
| 314 | major, BLKDEV_MAJOR_MAX, name); | ||
| 315 | |||
| 316 | ret = -EINVAL; | ||
| 317 | goto out; | ||
| 318 | } | ||
| 319 | |||
| 312 | p = kmalloc(sizeof(struct blk_major_name), GFP_KERNEL); | 320 | p = kmalloc(sizeof(struct blk_major_name), GFP_KERNEL); |
| 313 | if (p == NULL) { | 321 | if (p == NULL) { |
| 314 | ret = -ENOMEM; | 322 | ret = -ENOMEM; |
| @@ -22,7 +22,7 @@ config ANDROID_BINDER_IPC · 21 unmodified lines | |||
| 22 | config ANDROID_BINDER_DEVICES | 22 | config ANDROID_BINDER_DEVICES |
| 23 | string "Android Binder devices" | 23 | string "Android Binder devices" |
| 24 | depends on ANDROID_BINDER_IPC | 24 | depends on ANDROID_BINDER_IPC |
| 25 | default "binder,hwbinder" | 25 | default "binder,hwbinder,vndbinder" |
| 26 | ---help--- | 26 | ---help--- |
| 27 | Default value for the binder.devices parameter. | 27 | Default value for the binder.devices parameter. |
| 28 | 28 | ||
| @@ -32,7 +32,7 @@ config ANDROID_BINDER_DEVICES · 3 unmodified lines | |||
| 32 | therefore logically separated from the other devices. | 32 | therefore logically separated from the other devices. |
| 33 | 33 | ||
| 34 | config ANDROID_BINDER_IPC_32BIT | 34 | config ANDROID_BINDER_IPC_32BIT |
| 35 | bool | 35 | bool "Use old (Android 4.4 and earlier) 32-bit binder API" |
| 36 | depends on !64BIT && ANDROID_BINDER_IPC | 36 | depends on !64BIT && ANDROID_BINDER_IPC |
| 37 | default y | 37 | default y |
| 38 | ---help--- | 38 | ---help--- |
| @@ -44,6 +44,16 @@ config ANDROID_BINDER_IPC_32BIT · 5 unmodified lines | |||
| 44 | 44 | ||
| 45 | Note that enabling this will break newer Android user-space. | 45 | Note that enabling this will break newer Android user-space. |
| 46 | 46 | ||
| 47 | config ANDROID_BINDER_IPC_SELFTEST | ||
| 48 | bool "Android Binder IPC Driver Selftest" | ||
| 49 | depends on ANDROID_BINDER_IPC | ||
| 50 | ---help--- | ||
| 51 | This feature allows binder selftest to run. | ||
| 52 | |||
| 53 | Binder selftest checks the allocation and free of binder buffers | ||
| 54 | exhaustively with combinations of various buffer sizes and | ||
| 55 | alignments. | ||
| 56 | |||
| 47 | endif # if ANDROID | 57 | endif # if ANDROID |
| 48 | 58 | ||
| 49 | endmenu | 59 | endmenu |
| @@ -1,3 +1,4 @@ | |||
| 1 | ccflags-y += -I$(src) # needed for trace events | 1 | ccflags-y += -I$(src) # needed for trace events |
| 2 | 2 | ||
| 3 | obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o | 3 | obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o binder_alloc.o |
| 4 | obj-$(CONFIG_ANDROID_BINDER_IPC_SELFTEST) += binder_alloc_selftest.o | ||
| @@ -15,6 +15,40 @@ · 14 unmodified lines | |||
| 15 | * | 15 | * |
| 16 | */ | 16 | */ |
| 17 | 17 | ||
| 18 | /* | ||
| 19 | * Locking overview | ||
| 20 | * | ||
| 21 | * There are 3 main spinlocks which must be acquired in the | ||
| 22 | * order shown: | ||
| 23 | * | ||
| 24 | * 1) proc->outer_lock : protects binder_ref | ||
| 25 | * binder_proc_lock() and binder_proc_unlock() are | ||
| 26 | * used to acq/rel. | ||
| 27 | * 2) node->lock : protects most fields of binder_node. | ||
| 28 | * binder_node_lock() and binder_node_unlock() are | ||
| 29 | * used to acq/rel | ||
| 30 | * 3) proc->inner_lock : protects the thread and node lists | ||
| 31 | * (proc->threads, proc->waiting_threads, proc->nodes) | ||
| 32 | * and all todo lists associated with the binder_proc | ||
| 33 | * (proc->todo, thread->todo, proc->delivered_death and | ||
| 34 | * node->async_todo), as well as thread->transaction_stack | ||
| 35 | * binder_inner_proc_lock() and binder_inner_proc_unlock() | ||
| 36 | * are used to acq/rel | ||
| 37 | * | ||
| 38 | * Any lock under procA must never be nested under any lock at the same | ||
| 39 | * level or below on procB. | ||
| 40 | * | ||
| 41 | * Functions that require a lock held on entry indicate which lock | ||
| 42 | * in the suffix of the function name: | ||
| 43 | * | ||
| 44 | * foo_olocked() : requires node->outer_lock | ||
| 45 | * foo_nlocked() : requires node->lock | ||
| 46 | * foo_ilocked() : requires proc->inner_lock | ||
| 47 | * foo_oilocked(): requires proc->outer_lock and proc->inner_lock | ||
| 48 | * foo_nilocked(): requires node->lock and proc->inner_lock | ||
| 49 | * ... | ||
| 50 | */ | ||
| 51 | |||
| 18 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 52 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
| 19 | 53 | ||
| 20 | #include <asm/cacheflush.h> | 54 | #include <asm/cacheflush.h> |
| @@ -24,7 +58,6 @@ · 3 unmodified lines | |||
| 24 | #include <linux/fs.h> | 58 | #include <linux/fs.h> |
| 25 | #include <linux/list.h> | 59 | #include <linux/list.h> |
| 26 | #include <linux/miscdevice.h> | 60 | #include <linux/miscdevice.h> |
| 27 | #include <linux/mm.h> | ||
| 28 | #include <linux/module.h> | 61 | #include <linux/module.h> |
| 29 | #include <linux/mutex.h> | 62 | #include <linux/mutex.h> |
| 30 | #include <linux/nsproxy.h> | 63 | #include <linux/nsproxy.h> |
| @@ -35,30 +68,31 @@ · 4 unmodified lines | |||
| 35 | #include <linux/sched/mm.h> | 68 | #include <linux/sched/mm.h> |
| 36 | #include <linux/seq_file.h> | 69 | #include <linux/seq_file.h> |
| 37 | #include <linux/uaccess.h> | 70 | #include <linux/uaccess.h> |
| 38 | #include <linux/vmalloc.h> | ||
| 39 | #include <linux/slab.h> | ||
| 40 | #include <linux/pid_namespace.h> | 71 | #include <linux/pid_namespace.h> |
| 41 | #include <linux/security.h> | 72 | #include <linux/security.h> |
| 73 | #include <linux/spinlock.h> | ||
| 42 | 74 | ||
| 43 | #ifdef CONFIG_ANDROID_BINDER_IPC_32BIT | 75 | #ifdef CONFIG_ANDROID_BINDER_IPC_32BIT |
| 44 | #define BINDER_IPC_32BIT 1 | 76 | #define BINDER_IPC_32BIT 1 |
| 45 | #endif | 77 | #endif |
| 46 | 78 | ||
| 47 | #include <uapi/linux/android/binder.h> | 79 | #include <uapi/linux/android/binder.h> |
| 80 | #include "binder_alloc.h" | ||
| 48 | #include "binder_trace.h" | 81 | #include "binder_trace.h" |
| 49 | 82 | ||
| 50 | static DEFINE_MUTEX(binder_main_lock); | 83 | static HLIST_HEAD(binder_deferred_list); |
| 51 | static DEFINE_MUTEX(binder_deferred_lock); | 84 | static DEFINE_MUTEX(binder_deferred_lock); |
| 52 | static DEFINE_MUTEX(binder_mmap_lock); | ||
| 53 | 85 | ||
| 54 | static HLIST_HEAD(binder_devices); | 86 | static HLIST_HEAD(binder_devices); |
| 55 | static HLIST_HEAD(binder_procs); | 87 | static HLIST_HEAD(binder_procs); |
| 56 | static HLIST_HEAD(binder_deferred_list); | 88 | static DEFINE_MUTEX(binder_procs_lock); |
| 89 | |||
| 57 | static HLIST_HEAD(binder_dead_nodes); | 90 | static HLIST_HEAD(binder_dead_nodes); |
| 91 | static DEFINE_SPINLOCK(binder_dead_nodes_lock); | ||
| 58 | 92 | ||
| 59 | static struct dentry *binder_debugfs_dir_entry_root; | 93 | static struct dentry *binder_debugfs_dir_entry_root; |
| 60 | static struct dentry *binder_debugfs_dir_entry_proc; | 94 | static struct dentry *binder_debugfs_dir_entry_proc; |
| 61 | static int binder_last_id; | 95 | static atomic_t binder_last_id; |
| 62 | 96 | ||
| 63 | #define BINDER_DEBUG_ENTRY(name) \ | 97 | #define BINDER_DEBUG_ENTRY(name) \ |
| 64 | static int binder_##name##_open(struct inode *inode, struct file *file) \ | 98 | static int binder_##name##_open(struct inode *inode, struct file *file) \ |
| @@ -88,8 +122,6 @@ BINDER_DEBUG_ENTRY(proc); · 23 unmodified lines | |||
| 88 | 122 | ||
| 89 | #define FORBIDDEN_MMAP_FLAGS (VM_WRITE) | 123 | #define FORBIDDEN_MMAP_FLAGS (VM_WRITE) |
| 90 | 124 | ||
| 91 | #define BINDER_SMALL_BUF_SIZE (PAGE_SIZE * 64) | ||
| 92 | |||
| 93 | enum { | 125 | enum { |
| 94 | BINDER_DEBUG_USER_ERROR = 1U << 0, | 126 | BINDER_DEBUG_USER_ERROR = 1U << 0, |
| 95 | BINDER_DEBUG_FAILED_TRANSACTION = 1U << 1, | 127 | BINDER_DEBUG_FAILED_TRANSACTION = 1U << 1, |
| @@ -104,17 +136,13 @@ enum { · 8 unmodified lines | |||
| 104 | BINDER_DEBUG_TRANSACTION_COMPLETE = 1U << 10, | 136 | BINDER_DEBUG_TRANSACTION_COMPLETE = 1U << 10, |
| 105 | BINDER_DEBUG_FREE_BUFFER = 1U << 11, | 137 | BINDER_DEBUG_FREE_BUFFER = 1U << 11, |
| 106 | BINDER_DEBUG_INTERNAL_REFS = 1U << 12, | 138 | BINDER_DEBUG_INTERNAL_REFS = 1U << 12, |
| 107 | BINDER_DEBUG_BUFFER_ALLOC = 1U << 13, | 139 | BINDER_DEBUG_PRIORITY_CAP = 1U << 13, |
| 108 | BINDER_DEBUG_PRIORITY_CAP = 1U << 14, | 140 | BINDER_DEBUG_SPINLOCKS = 1U << 14, |
| 109 | BINDER_DEBUG_BUFFER_ALLOC_ASYNC = 1U << 15, | ||
| 110 | }; | 141 | }; |
| 111 | static uint32_t binder_debug_mask = BINDER_DEBUG_USER_ERROR | | 142 | static uint32_t binder_debug_mask = BINDER_DEBUG_USER_ERROR | |
| 112 | BINDER_DEBUG_FAILED_TRANSACTION | BINDER_DEBUG_DEAD_TRANSACTION; | 143 | BINDER_DEBUG_FAILED_TRANSACTION | BINDER_DEBUG_DEAD_TRANSACTION; |
| 113 | module_param_named(debug_mask, binder_debug_mask, uint, S_IWUSR | S_IRUGO); | 144 | module_param_named(debug_mask, binder_debug_mask, uint, S_IWUSR | S_IRUGO); |
| 114 | 145 | ||
| 115 | static bool binder_debug_no_lock; | ||
| 116 | module_param_named(proc_no_lock, binder_debug_no_lock, bool, S_IWUSR | S_IRUGO); | ||
| 117 | |||
| 118 | static char *binder_devices_param = CONFIG_ANDROID_BINDER_DEVICES; | 146 | static char *binder_devices_param = CONFIG_ANDROID_BINDER_DEVICES; |
| 119 | module_param_named(devices, binder_devices_param, charp, 0444); | 147 | module_param_named(devices, binder_devices_param, charp, 0444); |
| 120 | 148 | ||
| @@ -171,26 +199,27 @@ enum binder_stat_types { · 50 unmodified lines | |||
| 171 | }; | 199 | }; |
| 172 | 200 | ||
| 173 | struct binder_stats { | 201 | struct binder_stats { |
| 174 | int br[_IOC_NR(BR_FAILED_REPLY) + 1]; | 202 | atomic_t br[_IOC_NR(BR_FAILED_REPLY) + 1]; |
| 175 | int bc[_IOC_NR(BC_REPLY_SG) + 1]; | 203 | atomic_t bc[_IOC_NR(BC_REPLY_SG) + 1]; |
| 176 | int obj_created[BINDER_STAT_COUNT]; | 204 | atomic_t obj_created[BINDER_STAT_COUNT]; |
| 177 | int obj_deleted[BINDER_STAT_COUNT]; | 205 | atomic_t obj_deleted[BINDER_STAT_COUNT]; |
| 178 | }; | 206 | }; |
| 179 | 207 | ||
| 180 | static struct binder_stats binder_stats; | 208 | static struct binder_stats binder_stats; |
| 181 | 209 | ||
| 182 | static inline void binder_stats_deleted(enum binder_stat_types type) | 210 | static inline void binder_stats_deleted(enum binder_stat_types type) |
| 183 | { | 211 | { |
| 184 | binder_stats.obj_deleted[type]++; | 212 | atomic_inc(&binder_stats.obj_deleted[type]); |
| 185 | } | 213 | } |
| 186 | 214 | ||
| 187 | static inline void binder_stats_created(enum binder_stat_types type) | 215 | static inline void binder_stats_created(enum binder_stat_types type) |
| 188 | { | 216 | { |
| 189 | binder_stats.obj_created[type]++; | 217 | atomic_inc(&binder_stats.obj_created[type]); |
| 190 | } | 218 | } |
| 191 | 219 | ||
| 192 | struct binder_transaction_log_entry { | 220 | struct binder_transaction_log_entry { |
| 193 | int debug_id; | 221 | int debug_id; |
| 222 | int debug_id_done; | ||
| 194 | int call_type; | 223 | int call_type; |
| 195 | int from_proc; | 224 | int from_proc; |
| 196 | int from_thread; | 225 | int from_thread; |
| @@ -200,11 +229,14 @@ struct binder_transaction_log_entry { · 3 unmodified lines | |||
| 200 | int to_node; | 229 | int to_node; |
| 201 | int data_size; | 230 | int data_size; |
| 202 | int offsets_size; | 231 | int offsets_size; |
| 232 | int return_error_line; | ||
| 233 | uint32_t return_error; | ||
| 234 | uint32_t return_error_param; | ||
| 203 | const char *context_name; | 235 | const char *context_name; |
| 204 | }; | 236 | }; |
| 205 | struct binder_transaction_log { | 237 | struct binder_transaction_log { |
| 206 | int next; | 238 | atomic_t cur; |
| 207 | int full; | 239 | bool full; |
| 208 | struct binder_transaction_log_entry entry[32]; | 240 | struct binder_transaction_log_entry entry[32]; |
| 209 | }; | 241 | }; |
| 210 | static struct binder_transaction_log binder_transaction_log; | 242 | static struct binder_transaction_log binder_transaction_log; |
| @@ -214,19 +246,26 @@ static struct binder_transaction_log_entry *binder_transaction_log_add( · 3 unmodified lines | |||
| 214 | struct binder_transaction_log *log) | 246 | struct binder_transaction_log *log) |
| 215 | { | 247 | { |
| 216 | struct binder_transaction_log_entry *e; | 248 | struct binder_transaction_log_entry *e; |
| 249 | unsigned int cur = atomic_inc_return(&log->cur); | ||
| 217 | 250 | ||
| 218 | e = &log->entry[log->next]; | 251 | if (cur >= ARRAY_SIZE(log->entry)) |
| 219 | memset(e, 0, sizeof(*e)); | ||
| 220 | log->next++; | ||
| 221 | if (log->next == ARRAY_SIZE(log->entry)) { | ||
| 222 | log->next = 0; | ||
| 223 | log->full = 1; | 252 | log->full = 1; |
| 224 | } | 253 | e = &log->entry[cur % ARRAY_SIZE(log->entry)]; |
| 254 | WRITE_ONCE(e->debug_id_done, 0); | ||
| 255 | /* | ||
| 256 | * write-barrier to synchronize access to e->debug_id_done. | ||
| 257 | * We make sure the initialized 0 value is seen before | ||
| 258 | * memset() other fields are zeroed by memset. | ||
| 259 | */ | ||
| 260 | smp_wmb(); | ||
| 261 | memset(e, 0, sizeof(*e)); | ||
| 225 | return e; | 262 | return e; |
| 226 | } | 263 | } |
| 227 | 264 | ||
| 228 | struct binder_context { | 265 | struct binder_context { |
| 229 | struct binder_node *binder_context_mgr_node; | 266 | struct binder_node *binder_context_mgr_node; |
| 267 | struct mutex context_mgr_node_lock; | ||
| 268 | |||
| 230 | kuid_t binder_context_mgr_uid; | 269 | kuid_t binder_context_mgr_uid; |
| 231 | const char *name; | 270 | const char *name; |
| 232 | }; | 271 | }; |
| @@ -237,11 +276,20 @@ struct binder_device { · 4 unmodified lines | |||
| 237 | struct binder_context context; | 276 | struct binder_context context; |
| 238 | }; | 277 | }; |
| 239 | 278 | ||
| 279 | /** | ||
| 280 | * struct binder_work - work enqueued on a worklist | ||
| 281 | * @entry: node enqueued on list | ||
| 282 | * @type: type of work to be performed | ||
| 283 | * | ||
| 284 | * There are separate work lists for proc, thread, and node (async). | ||
| 285 | */ | ||
| 240 | struct binder_work { | 286 | struct binder_work { |
| 241 | struct list_head entry; | 287 | struct list_head entry; |
| 288 | |||
| 242 | enum { | 289 | enum { |
| 243 | BINDER_WORK_TRANSACTION = 1, | 290 | BINDER_WORK_TRANSACTION = 1, |
| 244 | BINDER_WORK_TRANSACTION_COMPLETE, | 291 | BINDER_WORK_TRANSACTION_COMPLETE, |
| 292 | BINDER_WORK_RETURN_ERROR, | ||
| 245 | BINDER_WORK_NODE, | 293 | BINDER_WORK_NODE, |
| 246 | BINDER_WORK_DEAD_BINDER, | 294 | BINDER_WORK_DEAD_BINDER, |
| 247 | BINDER_WORK_DEAD_BINDER_AND_CLEAR, | 295 | BINDER_WORK_DEAD_BINDER_AND_CLEAR, |
| @@ -249,8 +297,72 @@ struct binder_work { · 1 unmodified line | |||
| 249 | } type; | 297 | } type; |
| 250 | }; | 298 | }; |
| 251 | 299 | ||
| 300 | struct binder_error { | ||
| 301 | struct binder_work work; | ||
| 302 | uint32_t cmd; | ||
| 303 | }; | ||
| 304 | |||
| 305 | /** | ||
| 306 | * struct binder_node - binder node bookkeeping | ||
| 307 | * @debug_id: unique ID for debugging | ||
| 308 | * (invariant after initialized) | ||
| 309 | * @lock: lock for node fields | ||
| 310 | * @work: worklist element for node work | ||
| 311 | * (protected by @proc->inner_lock) | ||
| 312 | * @rb_node: element for proc->nodes tree | ||
| 313 | * (protected by @proc->inner_lock) | ||
| 314 | * @dead_node: element for binder_dead_nodes list | ||
| 315 | * (protected by binder_dead_nodes_lock) | ||
| 316 | * @proc: binder_proc that owns this node | ||
| 317 | * (invariant after initialized) | ||
| 318 | * @refs: list of references on this node | ||
| 319 | * (protected by @lock) | ||
| 320 | * @internal_strong_refs: used to take strong references when | ||
| 321 | * initiating a transaction | ||
| 322 | * (protected by @proc->inner_lock if @proc | ||
| 323 | * and by @lock) | ||
| 324 | * @local_weak_refs: weak user refs from local process | ||
| 325 | * (protected by @proc->inner_lock if @proc | ||
| 326 | * and by @lock) | ||
| 327 | * @local_strong_refs: strong user refs from local process | ||
| 328 | * (protected by @proc->inner_lock if @proc | ||
| 329 | * and by @lock) | ||
| 330 | * @tmp_refs: temporary kernel refs | ||
| 331 | * (protected by @proc->inner_lock while @proc | ||
| 332 | * is valid, and by binder_dead_nodes_lock | ||
| 333 | * if @proc is NULL. During inc/dec and node release | ||
| 334 | * it is also protected by @lock to provide safety | ||
| 335 | * as the node dies and @proc becomes NULL) | ||
| 336 | * @ptr: userspace pointer for node | ||
| 337 | * (invariant, no lock needed) | ||
| 338 | * @cookie: userspace cookie for node | ||
| 339 | * (invariant, no lock needed) | ||
| 340 | * @has_strong_ref: userspace notified of strong ref | ||
| 341 | * (protected by @proc->inner_lock if @proc | ||
| 342 | * and by @lock) | ||
| 343 | * @pending_strong_ref: userspace has acked notification of strong ref | ||
| 344 | * (protected by @proc->inner_lock if @proc | ||
| 345 | * and by @lock) | ||
| 346 | * @has_weak_ref: userspace notified of weak ref | ||
| 347 | * (protected by @proc->inner_lock if @proc | ||
| 348 | * and by @lock) | ||
| 349 | * @pending_weak_ref: userspace has acked notification of weak ref | ||
| 350 | * (protected by @proc->inner_lock if @proc | ||
| 351 | * and by @lock) | ||
| 352 | * @has_async_transaction: async transaction to node in progress | ||
| 353 | * (protected by @lock) | ||
| 354 | * @accept_fds: file descriptor operations supported for node | ||
| 355 | * (invariant after initialized) | ||
| 356 | * @min_priority: minimum scheduling priority | ||
| 357 | * (invariant after initialized) | ||
| 358 | * @async_todo: list of async work items | ||
| 359 | * (protected by @proc->inner_lock) | ||
| 360 | * | ||
| 361 | * Bookkeeping structure for binder nodes. | ||
| 362 | */ | ||
| 252 | struct binder_node { | 363 | struct binder_node { |
| 253 | int debug_id; | 364 | int debug_id; |
| 365 | spinlock_t lock; | ||
| 254 | struct binder_work work; | 366 | struct binder_work work; |
| 255 | union { | 367 | union { |
| 256 | struct rb_node rb_node; | 368 | struct rb_node rb_node; |
| @@ -261,88 +373,167 @@ struct binder_node { · 4 unmodified lines | |||
| 261 | int internal_strong_refs; | 373 | int internal_strong_refs; |
| 262 | int local_weak_refs; | 374 | int local_weak_refs; |
| 263 | int local_strong_refs; | 375 | int local_strong_refs; |
| 376 | int tmp_refs; | ||
| 264 | binder_uintptr_t ptr; | 377 | binder_uintptr_t ptr; |
| 265 | binder_uintptr_t cookie; | 378 | binder_uintptr_t cookie; |
| 266 | unsigned has_strong_ref:1; | 379 | struct { |
| 267 | unsigned pending_strong_ref:1; | 380 | /* |
| 268 | unsigned has_weak_ref:1; | 381 | * bitfield elements protected by |
| 269 | unsigned pending_weak_ref:1; | 382 | * proc inner_lock |
| 270 | unsigned has_async_transaction:1; | 383 | */ |
| 271 | unsigned accept_fds:1; | 384 | u8 has_strong_ref:1; |
| 272 | unsigned min_priority:8; | 385 | u8 pending_strong_ref:1; |
| 386 | u8 has_weak_ref:1; | ||
| 387 | u8 pending_weak_ref:1; | ||
| 388 | }; | ||
| 389 | struct { | ||
| 390 | /* | ||
| 391 | * invariant after initialization | ||
| 392 | */ | ||
| 393 | u8 accept_fds:1; | ||
| 394 | u8 min_priority; | ||
| 395 | }; | ||
| 396 | bool has_async_transaction; | ||
| 273 | struct list_head async_todo; | 397 | struct list_head async_todo; |
| 274 | }; | 398 | }; |
| 275 | 399 | ||
| 276 | struct binder_ref_death { | 400 | struct binder_ref_death { |
| 401 | /** | ||
| 402 | * @work: worklist element for death notifications | ||
| 403 | * (protected by inner_lock of the proc that | ||
| 404 | * this ref belongs to) | ||
| 405 | */ | ||
| 277 | struct binder_work work; | 406 | struct binder_work work; |
| 278 | binder_uintptr_t cookie; | 407 | binder_uintptr_t cookie; |
| 279 | }; | 408 | }; |
| 280 | 409 | ||
| 410 | /** | ||
| 411 | * struct binder_ref_data - binder_ref counts and id | ||
| 412 | * @debug_id: unique ID for the ref | ||
| 413 | * @desc: unique userspace handle for ref | ||
| 414 | * @strong: strong ref count (debugging only if not locked) | ||
| 415 | * @weak: weak ref count (debugging only if not locked) | ||
| 416 | * | ||
| 417 | * Structure to hold ref count and ref id information. Since | ||
| 418 | * the actual ref can only be accessed with a lock, this structure | ||
| 419 | * is used to return information about the ref to callers of | ||
| 420 | * ref inc/dec functions. | ||
| 421 | */ | ||
| 422 | struct binder_ref_data { | ||
| 423 | int debug_id; | ||
| 424 | uint32_t desc; | ||
| 425 | int strong; | ||
| 426 | int weak; | ||
| 427 | }; | ||
| 428 | |||
| 429 | /** | ||
| 430 | * struct binder_ref - struct to track references on nodes | ||
| 431 | * @data: binder_ref_data containing id, handle, and current refcounts | ||
| 432 | * @rb_node_desc: node for lookup by @data.desc in proc's rb_tree | ||
| 433 | * @rb_node_node: node for lookup by @node in proc's rb_tree | ||
| 434 | * @node_entry: list entry for node->refs list in target node | ||
| 435 | * (protected by @node->lock) | ||
| 436 | * @proc: binder_proc containing ref | ||
| 437 | * @node: binder_node of target node. When cleaning up a | ||
| 438 | * ref for deletion in binder_cleanup_ref, a non-NULL | ||
| 439 | * @node indicates the node must be freed | ||
| 440 | * @death: pointer to death notification (ref_death) if requested | ||
| 441 | * (protected by @node->lock) | ||
| 442 | * | ||
| 443 | * Structure to track references from procA to target node (on procB). This | ||
| 444 | * structure is unsafe to access without holding @proc->outer_lock. | ||
| 445 | */ | ||
| 281 | struct binder_ref { | 446 | struct binder_ref { |
| 282 | /* Lookups needed: */ | 447 | /* Lookups needed: */ |
| 283 | /* node + proc => ref (transaction) */ | 448 | /* node + proc => ref (transaction) */ |
| 284 | /* desc + proc => ref (transaction, inc/dec ref) */ | 449 | /* desc + proc => ref (transaction, inc/dec ref) */ |
| 285 | /* node => refs + procs (proc exit) */ | 450 | /* node => refs + procs (proc exit) */ |
| 286 | int debug_id; | 451 | struct binder_ref_data data; |
| 287 | struct rb_node rb_node_desc; | 452 | struct rb_node rb_node_desc; |
| 288 | struct rb_node rb_node_node; | 453 | struct rb_node rb_node_node; |
| 289 | struct hlist_node node_entry; | 454 | struct hlist_node node_entry; |
| 290 | struct binder_proc *proc; | 455 | struct binder_proc *proc; |
| 291 | struct binder_node *node; | 456 | struct binder_node *node; |
| 292 | uint32_t desc; | ||
| 293 | int strong; | ||
| 294 | int weak; | ||
| 295 | struct binder_ref_death *death; | 457 | struct binder_ref_death *death; |
| 296 | }; | 458 | }; |
| 297 | 459 | ||
| 298 | struct binder_buffer { | ||
| 299 | struct list_head entry; /* free and allocated entries by address */ | ||
| 300 | struct rb_node rb_node; /* free entry by size or allocated entry */ | ||
| 301 | /* by address */ | ||
| 302 | unsigned free:1; | ||
| 303 | unsigned allow_user_free:1; | ||
| 304 | unsigned async_transaction:1; | ||
| 305 | unsigned debug_id:29; | ||
| 306 | |||
| 307 | struct binder_transaction *transaction; | ||
| 308 | |||
| 309 | struct binder_node *target_node; | ||
| 310 | size_t data_size; | ||
| 311 | size_t offsets_size; | ||
| 312 | size_t extra_buffers_size; | ||
| 313 | uint8_t data[0]; | ||
| 314 | }; | ||
| 315 | |||
| 316 | enum binder_deferred_state { | 460 | enum binder_deferred_state { |
| 317 | BINDER_DEFERRED_PUT_FILES = 0x01, | 461 | BINDER_DEFERRED_PUT_FILES = 0x01, |
| 318 | BINDER_DEFERRED_FLUSH = 0x02, | 462 | BINDER_DEFERRED_FLUSH = 0x02, |
| 319 | BINDER_DEFERRED_RELEASE = 0x04, | 463 | BINDER_DEFERRED_RELEASE = 0x04, |
| 320 | }; | 464 | }; |
| 321 | 465 | ||
| 466 | /** | ||
| 467 | * struct binder_proc - binder process bookkeeping | ||
| 468 | * @proc_node: element for binder_procs list | ||
| 469 | * @threads: rbtree of binder_threads in this proc | ||
| 470 | * (protected by @inner_lock) | ||
| 471 | * @nodes: rbtree of binder nodes associated with | ||
| 472 | * this proc ordered by node->ptr | ||
| 473 | * (protected by @inner_lock) | ||
| 474 | * @refs_by_desc: rbtree of refs ordered by ref->desc | ||
| 475 | * (protected by @outer_lock) | ||
| 476 | * @refs_by_node: rbtree of refs ordered by ref->node | ||
| 477 | * (protected by @outer_lock) | ||
| 478 | * @waiting_threads: threads currently waiting for proc work | ||
| 479 | * (protected by @inner_lock) | ||
| 480 | * @pid PID of group_leader of process | ||
| 481 | * (invariant after initialized) | ||
| 482 | * @tsk task_struct for group_leader of process | ||
| 483 | * (invariant after initialized) | ||
| 484 | * @files files_struct for process | ||
| 485 | * (invariant after initialized) | ||
| 486 | * @deferred_work_node: element for binder_deferred_list | ||
| 487 | * (protected by binder_deferred_lock) | ||
| 488 | * @deferred_work: bitmap of deferred work to perform | ||
| 489 | * (protected by binder_deferred_lock) | ||
| 490 | * @is_dead: process is dead and awaiting free | ||
| 491 | * when outstanding transactions are cleaned up | ||
| 492 | * (protected by @inner_lock) | ||
| 493 | * @todo: list of work for this process | ||
| 494 | * (protected by @inner_lock) | ||
| 495 | * @wait: wait queue head to wait for proc work | ||
| 496 | * (invariant after initialized) | ||
| 497 | * @stats: per-process binder statistics | ||
| 498 | * (atomics, no lock needed) | ||
| 499 | * @delivered_death: list of delivered death notification | ||
| 500 | * (protected by @inner_lock) | ||
| 501 | * @max_threads: cap on number of binder threads | ||
| 502 | * (protected by @inner_lock) | ||
| 503 | * @requested_threads: number of binder threads requested but not | ||
| 504 | * yet started. In current implementation, can | ||
| 505 | * only be 0 or 1. | ||
| 506 | * (protected by @inner_lock) | ||
| 507 | * @requested_threads_started: number binder threads started | ||
| 508 | * (protected by @inner_lock) | ||
| 509 | * @tmp_ref: temporary reference to indicate proc is in use | ||
| 510 | * (protected by @inner_lock) | ||
| 511 | * @default_priority: default scheduler priority | ||
| 512 | * (invariant after initialized) | ||
| 513 | * @debugfs_entry: debugfs node | ||
| 514 | * @alloc: binder allocator bookkeeping | ||
| 515 | * @context: binder_context for this proc | ||
| 516 | * (invariant after initialized) | ||
| 517 | * @inner_lock: can nest under outer_lock and/or node lock | ||
| 518 | * @outer_lock: no nesting under innor or node lock | ||
| 519 | * Lock order: 1) outer, 2) node, 3) inner | ||
| 520 | * | ||
| 521 | * Bookkeeping structure for binder processes | ||
| 522 | */ | ||
| 322 | struct binder_proc { | 523 | struct binder_proc { |
| 323 | struct hlist_node proc_node; | 524 | struct hlist_node proc_node; |
| 324 | struct rb_root threads; | 525 | struct rb_root threads; |
| 325 | struct rb_root nodes; | 526 | struct rb_root nodes; |
| 326 | struct rb_root refs_by_desc; | 527 | struct rb_root refs_by_desc; |
| 327 | struct rb_root refs_by_node; | 528 | struct rb_root refs_by_node; |
| 529 | struct list_head waiting_threads; | ||
| 328 | int pid; | 530 | int pid; |
| 329 | struct vm_area_struct *vma; | ||
| 330 | struct mm_struct *vma_vm_mm; | ||
| 331 | struct task_struct *tsk; | 531 | struct task_struct *tsk; |
| 332 | struct files_struct *files; | 532 | struct files_struct *files; |
| 333 | struct hlist_node deferred_work_node; | 533 | struct hlist_node deferred_work_node; |
| 334 | int deferred_work; | 534 | int deferred_work; |
| 335 | void *buffer; | 535 | bool is_dead; |
| 336 | ptrdiff_t user_buffer_offset; | ||
| 337 | |||
| 338 | struct list_head buffers; | ||
| 339 | struct rb_root free_buffers; | ||
| 340 | struct rb_root allocated_buffers; | ||
| 341 | size_t free_async_space; | ||
| 342 | 536 | ||
| 343 | struct page **pages; | ||
| 344 | size_t buffer_size; | ||
| 345 | uint32_t buffer_free; | ||
| 346 | struct list_head todo; | 537 | struct list_head todo; |
| 347 | wait_queue_head_t wait; | 538 | wait_queue_head_t wait; |
| 348 | struct binder_stats stats; | 539 | struct binder_stats stats; |
| @@ -350,10 +541,13 @@ struct binder_proc { · 1 unmodified line | |||
| 350 | int max_threads; | 541 | int max_threads; |
| 351 | int requested_threads; | 542 | int requested_threads; |
| 352 | int requested_threads_started; | 543 | int requested_threads_started; |
| 353 | int ready_threads; | 544 | int tmp_ref; |
| 354 | long default_priority; | 545 | long default_priority; |
| 355 | struct dentry *debugfs_entry; | 546 | struct dentry *debugfs_entry; |
| 547 | struct binder_alloc alloc; | ||
| 356 | struct binder_context *context; | 548 | struct binder_context *context; |
| 549 | spinlock_t inner_lock; | ||
| 550 | spinlock_t outer_lock; | ||
| 357 | }; | 551 | }; |
| 358 | 552 | ||
| 359 | enum { | 553 | enum { |
| @@ -362,22 +556,58 @@ enum { · 2 unmodified lines | |||
| 362 | BINDER_LOOPER_STATE_EXITED = 0x04, | 556 | BINDER_LOOPER_STATE_EXITED = 0x04, |
| 363 | BINDER_LOOPER_STATE_INVALID = 0x08, | 557 | BINDER_LOOPER_STATE_INVALID = 0x08, |
| 364 | BINDER_LOOPER_STATE_WAITING = 0x10, | 558 | BINDER_LOOPER_STATE_WAITING = 0x10, |
| 365 | BINDER_LOOPER_STATE_NEED_RETURN = 0x20 | 559 | BINDER_LOOPER_STATE_POLL = 0x20, |
| 366 | }; | 560 | }; |
| 367 | 561 | ||
| 562 | /** | ||
| 563 | * struct binder_thread - binder thread bookkeeping | ||
| 564 | * @proc: binder process for this thread | ||
| 565 | * (invariant after initialization) | ||
| 566 | * @rb_node: element for proc->threads rbtree | ||
| 567 | * (protected by @proc->inner_lock) | ||
| 568 | * @waiting_thread_node: element for @proc->waiting_threads list | ||
| 569 | * (protected by @proc->inner_lock) | ||
| 570 | * @pid: PID for this thread | ||
| 571 | * (invariant after initialization) | ||
| 572 | * @looper: bitmap of looping state | ||
| 573 | * (only accessed by this thread) | ||
| 574 | * @looper_needs_return: looping thread needs to exit driver | ||
| 575 | * (no lock needed) | ||
| 576 | * @transaction_stack: stack of in-progress transactions for this thread | ||
| 577 | * (protected by @proc->inner_lock) | ||
| 578 | * @todo: list of work to do for this thread | ||
| 579 | * (protected by @proc->inner_lock) | ||
| 580 | * @return_error: transaction errors reported by this thread | ||
| 581 | * (only accessed by this thread) | ||
| 582 | * @reply_error: transaction errors reported by target thread | ||
| 583 | * (protected by @proc->inner_lock) | ||
| 584 | * @wait: wait queue for thread work | ||
| 585 | * @stats: per-thread statistics | ||
| 586 | * (atomics, no lock needed) | ||
| 587 | * @tmp_ref: temporary reference to indicate thread is in use | ||
| 588 | * (atomic since @proc->inner_lock cannot | ||
| 589 | * always be acquired) | ||
| 590 | * @is_dead: thread is dead and awaiting free | ||
| 591 | * when outstanding transactions are cleaned up | ||
| 592 | * (protected by @proc->inner_lock) | ||
| 593 | * | ||
| 594 | * Bookkeeping structure for binder threads. | ||
| 595 | */ | ||
| 368 | struct binder_thread { | 596 | struct binder_thread { |
| 369 | struct binder_proc *proc; | 597 | struct binder_proc *proc; |
| 370 | struct rb_node rb_node; | 598 | struct rb_node rb_node; |
| 599 | struct list_head waiting_thread_node; | ||
| 371 | int pid; | 600 | int pid; |
| 372 | int looper; | 601 | int looper; /* only modified by this thread */ |
| 602 | bool looper_need_return; /* can be written by other thread */ | ||
| 373 | struct binder_transaction *transaction_stack; | 603 | struct binder_transaction *transaction_stack; |
| 374 | struct list_head todo; | 604 | struct list_head todo; |
| 375 | uint32_t return_error; /* Write failed, return error code in read buf */ | 605 | struct binder_error return_error; |
| 376 | uint32_t return_error2; /* Write failed, return error code in read */ | 606 | struct binder_error reply_error; |
| 377 | /* buffer. Used when sending a reply to a dead process that */ | ||
| 378 | /* we are also waiting on */ | ||
| 379 | wait_queue_head_t wait; | 607 | wait_queue_head_t wait; |
| 380 | struct binder_stats stats; | 608 | struct binder_stats stats; |
| 609 | atomic_t tmp_ref; | ||
| 610 | bool is_dead; | ||
| 381 | }; | 611 | }; |
| 382 | 612 | ||
| 383 | struct binder_transaction { | 613 | struct binder_transaction { |
| @@ -397,10 +627,253 @@ struct binder_transaction { · 13 unmodified lines | |||
| 397 | long priority; | 627 | long priority; |
| 398 | long saved_priority; | 628 | long saved_priority; |
| 399 | kuid_t sender_euid; | 629 | kuid_t sender_euid; |
| 630 | /** | ||
| 631 | * @lock: protects @from, @to_proc, and @to_thread | ||
| 632 | * | ||
| 633 | * @from, @to_proc, and @to_thread can be set to NULL | ||
| 634 | * during thread teardown | ||
| 635 | */ | ||
| 636 | spinlock_t lock; | ||
| 400 | }; | 637 | }; |
| 401 | 638 | ||
| 639 | /** | ||
| 640 | * binder_proc_lock() - Acquire outer lock for given binder_proc | ||
| 641 | * @proc: struct binder_proc to acquire | ||
| 642 | * | ||
| 643 | * Acquires proc->outer_lock. Used to protect binder_ref | ||
| 644 | * structures associated with the given proc. | ||
| 645 | */ | ||
| 646 | #define binder_proc_lock(proc) _binder_proc_lock(proc, __LINE__) | ||
| 647 | static void | ||
| 648 | _binder_proc_lock(struct binder_proc *proc, int line) | ||
| 649 | { | ||
| 650 | binder_debug(BINDER_DEBUG_SPINLOCKS, | ||
| 651 | "%s: line=%d\n", __func__, line); | ||
| 652 | spin_lock(&proc->outer_lock); | ||
| 653 | } | ||
| 654 | |||
| 655 | /** | ||
| 656 | * binder_proc_unlock() - Release spinlock for given binder_proc | ||
| 657 | * @proc: struct binder_proc to acquire | ||
| 658 | * | ||
| 659 | * Release lock acquired via binder_proc_lock() | ||
| 660 | */ | ||
| 661 | #define binder_proc_unlock(_proc) _binder_proc_unlock(_proc, __LINE__) | ||
| 662 | static void | ||
| 663 | _binder_proc_unlock(struct binder_proc *proc, int line) | ||
| 664 | { | ||
| 665 | binder_debug(BINDER_DEBUG_SPINLOCKS, | ||
| 666 | "%s: line=%d\n", __func__, line); | ||
| 667 | spin_unlock(&proc->outer_lock); | ||
| 668 | } | ||
| 669 | |||
| 670 | /** | ||
| 671 | * binder_inner_proc_lock() - Acquire inner lock for given binder_proc | ||
| 672 | * @proc: struct binder_proc to acquire | ||
| 673 | * | ||
| 674 | * Acquires proc->inner_lock. Used to protect todo lists | ||
| 675 | */ | ||
| 676 | #define binder_inner_proc_lock(proc) _binder_inner_proc_lock(proc, __LINE__) | ||
| 677 | static void | ||
| 678 | _binder_inner_proc_lock(struct binder_proc *proc, int line) | ||
| 679 | { | ||
| 680 | binder_debug(BINDER_DEBUG_SPINLOCKS, | ||
| 681 | "%s: line=%d\n", __func__, line); | ||
| 682 | spin_lock(&proc->inner_lock); | ||
| 683 | } | ||
| 684 | |||
| 685 | /** | ||
| 686 | * binder_inner_proc_unlock() - Release inner lock for given binder_proc | ||
| 687 | * @proc: struct binder_proc to acquire | ||
| 688 | * | ||
| 689 | * Release lock acquired via binder_inner_proc_lock() | ||
| 690 | */ | ||
| 691 | #define binder_inner_proc_unlock(proc) _binder_inner_proc_unlock(proc, __LINE__) | ||
| 692 | static void | ||
| 693 | _binder_inner_proc_unlock(struct binder_proc *proc, int line) | ||
| 694 | { | ||
| 695 | binder_debug(BINDER_DEBUG_SPINLOCKS, | ||
| 696 | "%s: line=%d\n", __func__, line); | ||
| 697 | spin_unlock(&proc->inner_lock); | ||
| 698 | } | ||
| 699 | |||
| 700 | /** | ||
| 701 | * binder_node_lock() - Acquire spinlock for given binder_node | ||
| 702 | * @node: struct binder_node to acquire | ||
| 703 | * | ||
| 704 | * Acquires node->lock. Used to protect binder_node fields | ||
| 705 | */ | ||
| 706 | #define binder_node_lock(node) _binder_node_lock(node, __LINE__) | ||
| 707 | static void | ||
| 708 | _binder_node_lock(struct binder_node *node, int line) | ||
| 709 | { | ||
| 710 | binder_debug(BINDER_DEBUG_SPINLOCKS, | ||
| 711 | "%s: line=%d\n", __func__, line); | ||
| 712 | spin_lock(&node->lock); | ||
| 713 | } | ||
| 714 | |||
| 715 | /** | ||
| 716 | * binder_node_unlock() - Release spinlock for given binder_proc | ||
| 717 | * @node: struct binder_node to acquire | ||
| 718 | * | ||
| 719 | * Release lock acquired via binder_node_lock() | ||
| 720 | */ | ||
| 721 | #define binder_node_unlock(node) _binder_node_unlock(node, __LINE__) | ||
| 722 | static void | ||
| 723 | _binder_node_unlock(struct binder_node *node, int line) | ||
| 724 | { | ||
| 725 | binder_debug(BINDER_DEBUG_SPINLOCKS, | ||
| 726 | "%s: line=%d\n", __func__, line); | ||
| 727 | spin_unlock(&node->lock); | ||
| 728 | } | ||
| 729 | |||
| 730 | /** | ||
| 731 | * binder_node_inner_lock() - Acquire node and inner locks | ||
| 732 | * @node: struct binder_node to acquire | ||
| 733 | * | ||
| 734 | * Acquires node->lock. If node->proc also acquires | ||
| 735 | * proc->inner_lock. Used to protect binder_node fields | ||
| 736 | */ | ||
| 737 | #define binder_node_inner_lock(node) _binder_node_inner_lock(node, __LINE__) | ||
| 738 | static void | ||
| 739 | _binder_node_inner_lock(struct binder_node *node, int line) | ||
| 740 | { | ||
| 741 | binder_debug(BINDER_DEBUG_SPINLOCKS, | ||
| 742 | "%s: line=%d\n", __func__, line); | ||
| 743 | spin_lock(&node->lock); | ||
| 744 | if (node->proc) | ||
| 745 | binder_inner_proc_lock(node->proc); | ||
| 746 | } | ||
| 747 | |||
| 748 | /** | ||
| 749 | * binder_node_unlock() - Release node and inner locks | ||
| 750 | * @node: struct binder_node to acquire | ||
| 751 | * | ||
| 752 | * Release lock acquired via binder_node_lock() | ||
| 753 | */ | ||
| 754 | #define binder_node_inner_unlock(node) _binder_node_inner_unlock(node, __LINE__) | ||
| 755 | static void | ||
| 756 | _binder_node_inner_unlock(struct binder_node *node, int line) | ||
| 757 | { | ||
| 758 | struct binder_proc *proc = node->proc; | ||
| 759 | |||
| 760 | binder_debug(BINDER_DEBUG_SPINLOCKS, | ||
| 761 | "%s: line=%d\n", __func__, line); | ||
| 762 | if (proc) | ||
| 763 | binder_inner_proc_unlock(proc); | ||
| 764 | spin_unlock(&node->lock); | ||
| 765 | } | ||
| 766 | |||
| 767 | static bool binder_worklist_empty_ilocked(struct list_head *list) | ||
| 768 | { | ||
| 769 | return list_empty(list); | ||
| 770 | } | ||
| 771 | |||
| 772 | /** | ||
| 773 | * binder_worklist_empty() - Check if no items on the work list | ||
| 774 | * @proc: binder_proc associated with list | ||
| 775 | * @list: list to check | ||
| 776 | * | ||
| 777 | * Return: true if there are no items on list, else false | ||
| 778 | */ | ||
| 779 | static bool binder_worklist_empty(struct binder_proc *proc, | ||
| 780 | struct list_head *list) | ||
| 781 | { | ||
| 782 | bool ret; | ||
| 783 | |||
| 784 | binder_inner_proc_lock(proc); | ||
| 785 | ret = binder_worklist_empty_ilocked(list); | ||
| 786 | binder_inner_proc_unlock(proc); | ||
| 787 | return ret; | ||
| 788 | } | ||
| 789 | |||
| 790 | static void | ||
| 791 | binder_enqueue_work_ilocked(struct binder_work *work, | ||
| 792 | struct list_head *target_list) | ||
| 793 | { | ||
| 794 | BUG_ON(target_list == NULL); | ||
| 795 | BUG_ON(work->entry.next && !list_empty(&work->entry)); | ||
| 796 | list_add_tail(&work->entry, target_list); | ||
| 797 | } | ||
| 798 | |||
| 799 | /** | ||
| 800 | * binder_enqueue_work() - Add an item to the work list | ||
| 801 | * @proc: binder_proc associated with list | ||
| 802 | * @work: struct binder_work to add to list | ||
| 803 | * @target_list: list to add work to | ||
| 804 | * | ||
| 805 | * Adds the work to the specified list. Asserts that work | ||
| 806 | * is not already on a list. | ||
| 807 | */ | ||
| 808 | static void | ||
| 809 | binder_enqueue_work(struct binder_proc *proc, | ||
| 810 | struct binder_work *work, | ||
| 811 | struct list_head *target_list) | ||
| 812 | { | ||
| 813 | binder_inner_proc_lock(proc); | ||
| 814 | binder_enqueue_work_ilocked(work, target_list); | ||
| 815 | binder_inner_proc_unlock(proc); | ||
| 816 | } | ||
| 817 | |||
| 818 | static void | ||
| 819 | binder_dequeue_work_ilocked(struct binder_work *work) | ||
| 820 | { | ||
| 821 | list_del_init(&work->entry); | ||
| 822 | } | ||
| 823 | |||
| 824 | /** | ||
| 825 | * binder_dequeue_work() - Removes an item from the work list | ||
| 826 | * @proc: binder_proc associated with list | ||
| 827 | * @work: struct binder_work to remove from list | ||
| 828 | * | ||
| 829 | * Removes the specified work item from whatever list it is on. | ||
| 830 | * Can safely be called if work is not on any list. | ||
| 831 | */ | ||
| 832 | static void | ||
| 833 | binder_dequeue_work(struct binder_proc *proc, struct binder_work *work) | ||
| 834 | { | ||
| 835 | binder_inner_proc_lock(proc); | ||
| 836 | binder_dequeue_work_ilocked(work); | ||
| 837 | binder_inner_proc_unlock(proc); | ||
| 838 | } | ||
| 839 | |||
| 840 | static struct binder_work *binder_dequeue_work_head_ilocked( | ||
| 841 | struct list_head *list) | ||
| 842 | { | ||
| 843 | struct binder_work *w; | ||
| 844 | |||
| 845 | w = list_first_entry_or_null(list, struct binder_work, entry); | ||
| 846 | if (w) | ||
| 847 | list_del_init(&w->entry); | ||
| 848 | return w; | ||
| 849 | } | ||
| 850 | |||
| 851 | /** | ||
| 852 | * binder_dequeue_work_head() - Dequeues the item at head of list | ||
| 853 | * @proc: binder_proc associated with list | ||
| 854 | * @list: list to dequeue head | ||
| 855 | * | ||
| 856 | * Removes the head of the list if there are items on the list | ||
| 857 | * | ||
| 858 | * Return: pointer dequeued binder_work, NULL if list was empty | ||
| 859 | */ | ||
| 860 | static struct binder_work *binder_dequeue_work_head( | ||
| 861 | struct binder_proc *proc, | ||
| 862 | struct list_head *list) | ||
| 863 | { | ||
| 864 | struct binder_work *w; | ||
| 865 | |||
| 866 | binder_inner_proc_lock(proc); | ||
| 867 | w = binder_dequeue_work_head_ilocked(list); | ||
| 868 | binder_inner_proc_unlock(proc); | ||
| 869 | return w; | ||
| 870 | } | ||
| 871 | |||
| 402 | static void | 872 | static void |
| 403 | binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer); | 873 | binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer); |
| 874 | static void binder_free_thread(struct binder_thread *thread); | ||
| 875 | static void binder_free_proc(struct binder_proc *proc); | ||
| 876 | static void binder_inc_node_tmpref_ilocked(struct binder_node *node); | ||
| 404 | 877 | ||
| 405 | static int task_get_unused_fd_flags(struct binder_proc *proc, int flags) | 878 | static int task_get_unused_fd_flags(struct binder_proc *proc, int flags) |
| 406 | { | 879 | { |
| @@ -451,484 +924,206 @@ static long task_close_fd(struct binder_proc *proc, unsigned int fd) · 44 unmodified lines | |||
| 451 | return retval; | 924 | return retval; |
| 452 | } | 925 | } |
| 453 | 926 | ||
| 454 | static inline void binder_lock(const char *tag) | 927 | static bool binder_has_work_ilocked(struct binder_thread *thread, |
| 928 | bool do_proc_work) | ||
| 455 | { | 929 | { |
| 456 | trace_binder_lock(tag); | 930 | return !binder_worklist_empty_ilocked(&thread->todo) || |
| 457 | mutex_lock(&binder_main_lock); | 931 | thread->looper_need_return || |
| 458 | trace_binder_locked(tag); | 932 | (do_proc_work && |
| 933 | !binder_worklist_empty_ilocked(&thread->proc->todo)); | ||
| 459 | } | 934 | } |
| 460 | 935 | ||
| 461 | static inline void binder_unlock(const char *tag) | 936 | static bool binder_has_work(struct binder_thread *thread, bool do_proc_work) |
| 462 | { | 937 | { |
| 463 | trace_binder_unlock(tag); | 938 | bool has_work; |
| 464 | mutex_unlock(&binder_main_lock); | ||
| 465 | } | ||
| 466 | 939 | ||
| 467 | static void binder_set_nice(long nice) | 940 | binder_inner_proc_lock(thread->proc); |
| 468 | { | 941 | has_work = binder_has_work_ilocked(thread, do_proc_work); |
| 469 | long min_nice; | 942 | binder_inner_proc_unlock(thread->proc); |
| 470 | 943 | ||
| 471 | if (can_nice(current, nice)) { | 944 | return has_work; |
| 472 | set_user_nice(current, nice); | ||
| 473 | return; | ||
| 474 | } | ||
| 475 | min_nice = rlimit_to_nice(current->signal->rlim[RLIMIT_NICE].rlim_cur); | ||
| 476 | binder_debug(BINDER_DEBUG_PRIORITY_CAP, | ||
| 477 | "%d: nice value %ld not allowed use %ld instead\n", | ||
| 478 | current->pid, nice, min_nice); | ||
| 479 | set_user_nice(current, min_nice); | ||
| 480 | if (min_nice <= MAX_NICE) | ||
| 481 | return; | ||
| 482 | binder_user_error("%d RLIMIT_NICE not set\n", current->pid); | ||
| 483 | } | 945 | } |
| 484 | 946 | ||
| 485 | static size_t binder_buffer_size(struct binder_proc *proc, | 947 | static bool binder_available_for_proc_work_ilocked(struct binder_thread *thread) |
| 486 | struct binder_buffer *buffer) | ||
| 487 | { | 948 | { |
| 488 | if (list_is_last(&buffer->entry, &proc->buffers)) | 949 | return !thread->transaction_stack && |
| 489 | return proc->buffer + proc->buffer_size - (void *)buffer->data; | 950 | binder_worklist_empty_ilocked(&thread->todo) && |
| 490 | return (size_t)list_entry(buffer->entry.next, | 951 | (thread->looper & (BINDER_LOOPER_STATE_ENTERED | |
| 491 | struct binder_buffer, entry) - (size_t)buffer->data; | 952 | BINDER_LOOPER_STATE_REGISTERED)); |
| 492 | } | 953 | } |
| 493 | 954 | ||
| 494 | static void binder_insert_free_buffer(struct binder_proc *proc, | 955 | static void binder_wakeup_poll_threads_ilocked(struct binder_proc *proc, |
| 495 | struct binder_buffer *new_buffer) | 956 | bool sync) |
| 496 | { | 957 | { |
| 497 | struct rb_node **p = &proc->free_buffers.rb_node; | 958 | struct rb_node *n; |
| 498 | struct rb_node *parent = NULL; | 959 | struct binder_thread *thread; |
| 499 | struct binder_buffer *buffer; | 960 | |
| 500 | size_t buffer_size; | 961 | for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) { |
| 501 | size_t new_buffer_size; | 962 | thread = rb_entry(n, struct binder_thread, rb_node); |
| 963 | if (thread->looper & BINDER_LOOPER_STATE_POLL && | ||
| 964 | binder_available_for_proc_work_ilocked(thread)) { | ||
| 965 | if (sync) | ||
| 966 | wake_up_interruptible_sync(&thread->wait); | ||
| 967 | else | ||
| 968 | wake_up_interruptible(&thread->wait); | ||
| 969 | } | ||
| 970 | } | ||
| 971 | } | ||
| 502 | 972 | ||
| 503 | BUG_ON(!new_buffer->free); | 973 | /** |
| 974 | * binder_select_thread_ilocked() - selects a thread for doing proc work. | ||
| 975 | * @proc: process to select a thread from | ||
| 976 | * | ||
| 977 | * Note that calling this function moves the thread off the waiting_threads | ||
| 978 | * list, so it can only be woken up by the caller of this function, or a | ||
| 979 | * signal. Therefore, callers *should* always wake up the thread this function | ||
| 980 | * returns. | ||
| 981 | * | ||
| 982 | * Return: If there's a thread currently waiting for process work, | ||
| 983 | * returns that thread. Otherwise returns NULL. | ||
| 984 | */ | ||
| 985 | static struct binder_thread * | ||
| 986 | binder_select_thread_ilocked(struct binder_proc *proc) | ||
| 987 | { | ||
| 988 | struct binder_thread *thread; | ||
| 504 | 989 | ||
| 505 | new_buffer_size = binder_buffer_size(proc, new_buffer); | 990 | assert_spin_locked(&proc->inner_lock); |
| 991 | thread = list_first_entry_or_null(&proc->waiting_threads, | ||
| 992 | struct binder_thread, | ||
| 993 | waiting_thread_node); | ||
| 506 | 994 | ||
| 507 | binder_debug(BINDER_DEBUG_BUFFER_ALLOC, | 995 | if (thread) |
| 508 | "%d: add free buffer, size %zd, at %p\n", | 996 | list_del_init(&thread->waiting_thread_node); |
| 509 | proc->pid, new_buffer_size, new_buffer); | ||
| 510 | 997 | ||
| 511 | while (*p) { | 998 | return thread; |
| 512 | parent = *p; | 999 | } |
| 513 | buffer = rb_entry(parent, struct binder_buffer, rb_node); | ||
| 514 | BUG_ON(!buffer->free); | ||
| 515 | 1000 | ||
| 516 | buffer_size = binder_buffer_size(proc, buffer); | 1001 | /** |
| 1002 | * binder_wakeup_thread_ilocked() - wakes up a thread for doing proc work. | ||
| 1003 | * @proc: process to wake up a thread in | ||
| 1004 | * @thread: specific thread to wake-up (may be NULL) | ||
| 1005 | * @sync: whether to do a synchronous wake-up | ||
| 1006 | * | ||
| 1007 | * This function wakes up a thread in the @proc process. | ||
| 1008 | * The caller may provide a specific thread to wake-up in | ||
| 1009 | * the @thread parameter. If @thread is NULL, this function | ||
| 1010 | * will wake up threads that have called poll(). | ||
| 1011 | * | ||
| 1012 | * Note that for this function to work as expected, callers | ||
| 1013 | * should first call binder_select_thread() to find a thread | ||
| 1014 | * to handle the work (if they don't have a thread already), | ||
| 1015 | * and pass the result into the @thread parameter. | ||
| 1016 | */ | ||
| 1017 | static void binder_wakeup_thread_ilocked(struct binder_proc *proc, | ||
| 1018 | struct binder_thread *thread, | ||
| 1019 | bool sync) | ||
| 1020 | { | ||
| 1021 | assert_spin_locked(&proc->inner_lock); | ||
| 517 | 1022 | ||
| 518 | if (new_buffer_size < buffer_size) | 1023 | if (thread) { |
| 519 | p = &parent->rb_left; | 1024 | if (sync) |
| 1025 | wake_up_interruptible_sync(&thread->wait); | ||
| 520 | else | 1026 | else |
| 521 | p = &parent->rb_right; | 1027 | wake_up_interruptible(&thread->wait); |
| 1028 | return; | ||
| 522 | } | 1029 | } |
| 523 | rb_link_node(&new_buffer->rb_node, parent, p); | 1030 | |
| 524 | rb_insert_color(&new_buffer->rb_node, &proc->free_buffers); | 1031 | /* Didn't find a thread waiting for proc work; this can happen |
| 1032 | * in two scenarios: | ||
| 1033 | * 1. All threads are busy handling transactions | ||
| 1034 | * In that case, one of those threads should call back into | ||
| 1035 | * the kernel driver soon and pick up this work. | ||
| 1036 | * 2. Threads are using the (e)poll interface, in which case | ||
| 1037 | * they may be blocked on the waitqueue without having been | ||
| 1038 | * added to waiting_threads. For this case, we just iterate | ||
| 1039 | * over all threads not handling transaction work, and | ||
| 1040 | * wake them all up. We wake all because we don't know whether | ||
| 1041 | * a thread that called into (e)poll is handling non-binder | ||
| 1042 | * work currently. | ||
| 1043 | */ | ||
| 1044 | binder_wakeup_poll_threads_ilocked(proc, sync); | ||
| 525 | } | 1045 | } |
| 526 | 1046 | ||
| 527 | static void binder_insert_allocated_buffer(struct binder_proc *proc, | 1047 | static void binder_wakeup_proc_ilocked(struct binder_proc *proc) |
| 528 | struct binder_buffer *new_buffer) | ||
| 529 | { | 1048 | { |
| 530 | struct rb_node **p = &proc->allocated_buffers.rb_node; | 1049 | struct binder_thread *thread = binder_select_thread_ilocked(proc); |
| 531 | struct rb_node *parent = NULL; | ||
| 532 | struct binder_buffer *buffer; | ||
| 533 | 1050 | ||
| 534 | BUG_ON(new_buffer->free); | 1051 | binder_wakeup_thread_ilocked(proc, thread, /* sync = */false); |
| 1052 | } | ||
| 535 | 1053 | ||
| 536 | while (*p) { | 1054 | static void binder_set_nice(long nice) |
| 537 | parent = *p; | 1055 | { |
| 538 | buffer = rb_entry(parent, struct binder_buffer, rb_node); | 1056 | long min_nice; |
| 539 | BUG_ON(buffer->free); | ||
| 540 | 1057 | ||
| 541 | if (new_buffer < buffer) | 1058 | if (can_nice(current, nice)) { |
| 542 | p = &parent->rb_left; | 1059 | set_user_nice(current, nice); |
| 543 | else if (new_buffer > buffer) | 1060 | return; |
| 544 | p = &parent->rb_right; | ||
| 545 | else | ||
| 546 | BUG(); | ||
| 547 | } | 1061 | } |
| 548 | rb_link_node(&new_buffer->rb_node, parent, p); | 1062 | min_nice = rlimit_to_nice(rlimit(RLIMIT_NICE)); |
| 549 | rb_insert_color(&new_buffer->rb_node, &proc->allocated_buffers); | 1063 | binder_debug(BINDER_DEBUG_PRIORITY_CAP, |
| 1064 | "%d: nice value %ld not allowed use %ld instead\n", | ||
| 1065 | current->pid, nice, min_nice); | ||
| 1066 | set_user_nice(current, min_nice); | ||
| 1067 | if (min_nice <= MAX_NICE) | ||
| 1068 | return; | ||
| 1069 | binder_user_error("%d RLIMIT_NICE not set\n", current->pid); | ||
| 550 | } | 1070 | } |
| 551 | 1071 | ||
| 552 | static struct binder_buffer *binder_buffer_lookup(struct binder_proc *proc, | 1072 | static struct binder_node *binder_get_node_ilocked(struct binder_proc *proc, |
| 553 | uintptr_t user_ptr) | 1073 | binder_uintptr_t ptr) |
| 554 | { | 1074 | { |
| 555 | struct rb_node *n = proc->allocated_buffers.rb_node; | 1075 | struct rb_node *n = proc->nodes.rb_node; |
| 556 | struct binder_buffer *buffer; | 1076 | struct binder_node *node; |
| 557 | struct binder_buffer *kern_ptr; | ||
| 558 | 1077 | ||
| 559 | kern_ptr = (struct binder_buffer *)(user_ptr - proc->user_buffer_offset | 1078 | assert_spin_locked(&proc->inner_lock); |
| 560 | - offsetof(struct binder_buffer, data)); | ||
| 561 | 1079 | ||
| 562 | while (n) { | 1080 | while (n) { |
| 563 | buffer = rb_entry(n, struct binder_buffer, rb_node); | 1081 | node = rb_entry(n, struct binder_node, rb_node); |
| 564 | BUG_ON(buffer->free); | ||
| 565 | 1082 | ||
| 566 | if (kern_ptr < buffer) | 1083 | if (ptr < node->ptr) |
| 567 | n = n->rb_left; | 1084 | n = n->rb_left; |
| 568 | else if (kern_ptr > buffer) | 1085 | else if (ptr > node->ptr) |
| 569 | n = n->rb_right; | 1086 | n = n->rb_right; |
| 570 | else | 1087 | else { |
| 571 | return buffer; | 1088 | /* |
| 1089 | * take an implicit weak reference | ||
| 1090 | * to ensure node stays alive until | ||
| 1091 | * call to binder_put_node() | ||
| 1092 | */ | ||
| 1093 | binder_inc_node_tmpref_ilocked(node); | ||
| 1094 | return node; | ||
| 1095 | } | ||
| 572 | } | 1096 | } |
| 573 | return NULL; | 1097 | return NULL; |
| 574 | } | 1098 | } |
| 575 | 1099 | ||
| 576 | static int binder_update_page_range(struct binder_proc *proc, int allocate, | 1100 | static struct binder_node *binder_get_node(struct binder_proc *proc, |
| 577 | void *start, void *end, | 1101 | binder_uintptr_t ptr) |
| 578 | struct vm_area_struct *vma) | ||
| 579 | { | 1102 | { |
| 580 | void *page_addr; | 1103 | struct binder_node *node; |
| 581 | unsigned long user_page_addr; | ||
| 582 | struct page **page; | ||
| 583 | struct mm_struct *mm; | ||
| 584 | |||
| 585 | binder_debug(BINDER_DEBUG_BUFFER_ALLOC, | ||
| 586 | "%d: %s pages %p-%p\n", proc->pid, | ||
| 587 | allocate ? "allocate" : "free", start, end); | ||
| 588 | |||
| 589 | if (end <= start) | ||
| 590 | return 0; | ||
| 591 | 1104 | ||
| 592 | trace_binder_update_page_range(proc, allocate, start, end); | 1105 | binder_inner_proc_lock(proc); |
| 1106 | node = binder_get_node_ilocked(proc, ptr); | ||
| 1107 | binder_inner_proc_unlock(proc); | ||
| 1108 | return node; | ||
| 1109 | } | ||
| 593 | 1110 | ||
| 594 | if (vma) | 1111 | static struct binder_node *binder_init_node_ilocked( |
| 595 | mm = NULL; | 1112 | struct binder_proc *proc, |
| 596 | else | 1113 | struct binder_node *new_node, |
| 597 | mm = get_task_mm(proc->tsk); | 1114 | struct flat_binder_object *fp) |
| 598 | |||
| 599 | if (mm) { | ||
| 600 | down_write(&mm->mmap_sem); | ||
| 601 | vma = proc->vma; | ||
| 602 | if (vma && mm != proc->vma_vm_mm) { | ||
| 603 | pr_err("%d: vma mm and task mm mismatch\n", | ||
| 604 | proc->pid); | ||
| 605 | vma = NULL; | ||
| 606 | } | ||
| 607 | } | ||
| 608 | |||
| 609 | if (allocate == 0) | ||
| 610 | goto free_range; | ||
| 611 | |||
| 612 | if (vma == NULL) { | ||
| 613 | pr_err("%d: binder_alloc_buf failed to map pages in userspace, no vma\n", | ||
| 614 | proc->pid); | ||
| 615 | goto err_no_vma; | ||
| 616 | } | ||
| 617 | |||
| 618 | for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) { | ||
| 619 | int ret; | ||
| 620 | |||
| 621 | page = &proc->pages[(page_addr - proc->buffer) / PAGE_SIZE]; | ||
| 622 | |||
| 623 | BUG_ON(*page); | ||
| 624 | *page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO); | ||
| 625 | if (*page == NULL) { | ||
| 626 | pr_err("%d: binder_alloc_buf failed for page at %p\n", | ||
| 627 | proc->pid, page_addr); | ||
| 628 | goto err_alloc_page_failed; | ||
| 629 | } | ||
| 630 | ret = map_kernel_range_noflush((unsigned long)page_addr, | ||
| 631 | PAGE_SIZE, PAGE_KERNEL, page); | ||
| 632 | flush_cache_vmap((unsigned long)page_addr, | ||
| 633 | (unsigned long)page_addr + PAGE_SIZE); | ||
| 634 | if (ret != 1) { | ||
| 635 | pr_err("%d: binder_alloc_buf failed to map page at %p in kernel\n", | ||
| 636 | proc->pid, page_addr); | ||
| 637 | goto err_map_kernel_failed; | ||
| 638 | } | ||
| 639 | user_page_addr = | ||
| 640 | (uintptr_t)page_addr + proc->user_buffer_offset; | ||
| 641 | ret = vm_insert_page(vma, user_page_addr, page[0]); | ||
| 642 | if (ret) { | ||
| 643 | pr_err("%d: binder_alloc_buf failed to map page at %lx in userspace\n", | ||
| 644 | proc->pid, user_page_addr); | ||
| 645 | goto err_vm_insert_page_failed; | ||
| 646 | } | ||
| 647 | /* vm_insert_page does not seem to increment the refcount */ | ||
| 648 | } | ||
| 649 | if (mm) { | ||
| 650 | up_write(&mm->mmap_sem); | ||
| 651 | mmput(mm); | ||
| 652 | } | ||
| 653 | return 0; | ||
| 654 | |||
| 655 | free_range: | ||
| 656 | for (page_addr = end - PAGE_SIZE; page_addr >= start; | ||
| 657 | page_addr -= PAGE_SIZE) { | ||
| 658 | page = &proc->pages[(page_addr - proc->buffer) / PAGE_SIZE]; | ||
| 659 | if (vma) | ||
| 660 | zap_page_range(vma, (uintptr_t)page_addr + | ||
| 661 | proc->user_buffer_offset, PAGE_SIZE); | ||
| 662 | err_vm_insert_page_failed: | ||
| 663 | unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE); | ||
| 664 | err_map_kernel_failed: | ||
| 665 | __free_page(*page); | ||
| 666 | *page = NULL; | ||
| 667 | err_alloc_page_failed: | ||
| 668 | ; | ||
| 669 | } | ||
| 670 | err_no_vma: | ||
| 671 | if (mm) { | ||
| 672 | up_write(&mm->mmap_sem); | ||
| 673 | mmput(mm); | ||
| 674 | } | ||
| 675 | return -ENOMEM; | ||
| 676 | } | ||
| 677 | |||
| 678 | static struct binder_buffer *binder_alloc_buf(struct binder_proc *proc, | ||
| 679 | size_t data_size, | ||
| 680 | size_t offsets_size, | ||
| 681 | size_t extra_buffers_size, | ||
| 682 | int is_async) | ||
| 683 | { | ||
| 684 | struct rb_node *n = proc->free_buffers.rb_node; | ||
| 685 | struct binder_buffer *buffer; | ||
| 686 | size_t buffer_size; | ||
| 687 | struct rb_node *best_fit = NULL; | ||
| 688 | void *has_page_addr; | ||
| 689 | void *end_page_addr; | ||
| 690 | size_t size, data_offsets_size; | ||
| 691 | |||
| 692 | if (proc->vma == NULL) { | ||
| 693 | pr_err("%d: binder_alloc_buf, no vma\n", | ||
| 694 | proc->pid); | ||
| 695 | return NULL; | ||
| 696 | } | ||
| 697 | |||
| 698 | data_offsets_size = ALIGN(data_size, sizeof(void *)) + | ||
| 699 | ALIGN(offsets_size, sizeof(void *)); | ||
| 700 | |||
| 701 | if (data_offsets_size < data_size || data_offsets_size < offsets_size) { | ||
| 702 | binder_user_error("%d: got transaction with invalid size %zd-%zd\n", | ||
| 703 | proc->pid, data_size, offsets_size); | ||
| 704 | return NULL; | ||
| 705 | } | ||
| 706 | size = data_offsets_size + ALIGN(extra_buffers_size, sizeof(void *)); | ||
| 707 | if (size < data_offsets_size || size < extra_buffers_size) { | ||
| 708 | binder_user_error("%d: got transaction with invalid extra_buffers_size %zd\n", | ||
| 709 | proc->pid, extra_buffers_size); | ||
| 710 | return NULL; | ||
| 711 | } | ||
| 712 | if (is_async && | ||
| 713 | proc->free_async_space < size + sizeof(struct binder_buffer)) { | ||
| 714 | binder_debug(BINDER_DEBUG_BUFFER_ALLOC, | ||
| 715 | "%d: binder_alloc_buf size %zd failed, no async space left\n", | ||
| 716 | proc->pid, size); | ||
| 717 | return NULL; | ||
| 718 | } | ||
| 719 | |||
| 720 | while (n) { | ||
| 721 | buffer = rb_entry(n, struct binder_buffer, rb_node); | ||
| 722 | BUG_ON(!buffer->free); | ||
| 723 | buffer_size = binder_buffer_size(proc, buffer); | ||
| 724 | |||
| 725 | if (size < buffer_size) { | ||
| 726 | best_fit = n; | ||
| 727 | n = n->rb_left; | ||
| 728 | } else if (size > buffer_size) | ||
| 729 | n = n->rb_right; | ||
| 730 | else { | ||
| 731 | best_fit = n; | ||
| 732 | break; | ||
| 733 | } | ||
| 734 | } | ||
| 735 | if (best_fit == NULL) { | ||
| 736 | pr_err("%d: binder_alloc_buf size %zd failed, no address space\n", | ||
| 737 | proc->pid, size); | ||
| 738 | return NULL; | ||
| 739 | } | ||
| 740 | if (n == NULL) { | ||
| 741 | buffer = rb_entry(best_fit, struct binder_buffer, rb_node); | ||
| 742 | buffer_size = binder_buffer_size(proc, buffer); | ||
| 743 | } | ||
| 744 | |||
| 745 | binder_debug(BINDER_DEBUG_BUFFER_ALLOC, | ||
| 746 | "%d: binder_alloc_buf size %zd got buffer %p size %zd\n", | ||
| 747 | proc->pid, size, buffer, buffer_size); | ||
| 748 | |||
| 749 | has_page_addr = | ||
| 750 | (void *)(((uintptr_t)buffer->data + buffer_size) & PAGE_MASK); | ||
| 751 | if (n == NULL) { | ||
| 752 | if (size + sizeof(struct binder_buffer) + 4 >= buffer_size) | ||
| 753 | buffer_size = size; /* no room for other buffers */ | ||
| 754 | else | ||
| 755 | buffer_size = size + sizeof(struct binder_buffer); | ||
| 756 | } | ||
| 757 | end_page_addr = | ||
| 758 | (void *)PAGE_ALIGN((uintptr_t)buffer->data + buffer_size); | ||
| 759 | if (end_page_addr > has_page_addr) | ||
| 760 | end_page_addr = has_page_addr; | ||
| 761 | if (binder_update_page_range(proc, 1, | ||
| 762 | (void *)PAGE_ALIGN((uintptr_t)buffer->data), end_page_addr, NULL)) | ||
| 763 | return NULL; | ||
| 764 | |||
| 765 | rb_erase(best_fit, &proc->free_buffers); | ||
| 766 | buffer->free = 0; | ||
| 767 | binder_insert_allocated_buffer(proc, buffer); | ||
| 768 | if (buffer_size != size) { | ||
| 769 | struct binder_buffer *new_buffer = (void *)buffer->data + size; | ||
| 770 | |||
| 771 | list_add(&new_buffer->entry, &buffer->entry); | ||
| 772 | new_buffer->free = 1; | ||
| 773 | binder_insert_free_buffer(proc, new_buffer); | ||
| 774 | } | ||
| 775 | binder_debug(BINDER_DEBUG_BUFFER_ALLOC, | ||
| 776 | "%d: binder_alloc_buf size %zd got %p\n", | ||
| 777 | proc->pid, size, buffer); | ||
| 778 | buffer->data_size = data_size; | ||
| 779 | buffer->offsets_size = offsets_size; | ||
| 780 | buffer->extra_buffers_size = extra_buffers_size; | ||
| 781 | buffer->async_transaction = is_async; | ||
| 782 | if (is_async) { | ||
| 783 | proc->free_async_space -= size + sizeof(struct binder_buffer); | ||
| 784 | binder_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC, | ||
| 785 | "%d: binder_alloc_buf size %zd async free %zd\n", | ||
| 786 | proc->pid, size, proc->free_async_space); | ||
| 787 | } | ||
| 788 | |||
| 789 | return buffer; | ||
| 790 | } | ||
| 791 | |||
| 792 | static void *buffer_start_page(struct binder_buffer *buffer) | ||
| 793 | { | ||
| 794 | return (void *)((uintptr_t)buffer & PAGE_MASK); | ||
| 795 | } | ||
| 796 | |||
| 797 | static void *buffer_end_page(struct binder_buffer *buffer) | ||
| 798 | { | ||
| 799 | return (void *)(((uintptr_t)(buffer + 1) - 1) & PAGE_MASK); | ||
| 800 | } | ||
| 801 | |||
| 802 | static void binder_delete_free_buffer(struct binder_proc *proc, | ||
| 803 | struct binder_buffer *buffer) | ||
| 804 | { | ||
| 805 | struct binder_buffer *prev, *next = NULL; | ||
| 806 | int free_page_end = 1; | ||
| 807 | int free_page_start = 1; | ||
| 808 | |||
| 809 | BUG_ON(proc->buffers.next == &buffer->entry); | ||
| 810 | prev = list_entry(buffer->entry.prev, struct binder_buffer, entry); | ||
| 811 | BUG_ON(!prev->free); | ||
| 812 | if (buffer_end_page(prev) == buffer_start_page(buffer)) { | ||
| 813 | free_page_start = 0; | ||
| 814 | if (buffer_end_page(prev) == buffer_end_page(buffer)) | ||
| 815 | free_page_end = 0; | ||
| 816 | binder_debug(BINDER_DEBUG_BUFFER_ALLOC, | ||
| 817 | "%d: merge free, buffer %p share page with %p\n", | ||
| 818 | proc->pid, buffer, prev); | ||
| 819 | } | ||
| 820 | |||
| 821 | if (!list_is_last(&buffer->entry, &proc->buffers)) { | ||
| 822 | next = list_entry(buffer->entry.next, | ||
| 823 | struct binder_buffer, entry); | ||
| 824 | if (buffer_start_page(next) == buffer_end_page(buffer)) { | ||
| 825 | free_page_end = 0; | ||
| 826 | if (buffer_start_page(next) == | ||
| 827 | buffer_start_page(buffer)) | ||
| 828 | free_page_start = 0; | ||
| 829 | binder_debug(BINDER_DEBUG_BUFFER_ALLOC, | ||
| 830 | "%d: merge free, buffer %p share page with %p\n", | ||
| 831 | proc->pid, buffer, prev); | ||
| 832 | } | ||
| 833 | } | ||
| 834 | list_del(&buffer->entry); | ||
| 835 | if (free_page_start || free_page_end) { | ||
| 836 | binder_debug(BINDER_DEBUG_BUFFER_ALLOC, | ||
| 837 | "%d: merge free, buffer %p do not share page%s%s with %p or %p\n", | ||
| 838 | proc->pid, buffer, free_page_start ? "" : " end", | ||
| 839 | free_page_end ? "" : " start", prev, next); | ||
| 840 | binder_update_page_range(proc, 0, free_page_start ? | ||
| 841 | buffer_start_page(buffer) : buffer_end_page(buffer), | ||
| 842 | (free_page_end ? buffer_end_page(buffer) : | ||
| 843 | buffer_start_page(buffer)) + PAGE_SIZE, NULL); | ||
| 844 | } | ||
| 845 | } | ||
| 846 | |||
| 847 | static void binder_free_buf(struct binder_proc *proc, | ||
| 848 | struct binder_buffer *buffer) | ||
| 849 | { | ||
| 850 | size_t size, buffer_size; | ||
| 851 | |||
| 852 | buffer_size = binder_buffer_size(proc, buffer); | ||
| 853 | |||
| 854 | size = ALIGN(buffer->data_size, sizeof(void *)) + | ||
| 855 | ALIGN(buffer->offsets_size, sizeof(void *)) + | ||
| 856 | ALIGN(buffer->extra_buffers_size, sizeof(void *)); | ||
| 857 | |||
| 858 | binder_debug(BINDER_DEBUG_BUFFER_ALLOC, | ||
| 859 | "%d: binder_free_buf %p size %zd buffer_size %zd\n", | ||
| 860 | proc->pid, buffer, size, buffer_size); | ||
| 861 | |||
| 862 | BUG_ON(buffer->free); | ||
| 863 | BUG_ON(size > buffer_size); | ||
| 864 | BUG_ON(buffer->transaction != NULL); | ||
| 865 | BUG_ON((void *)buffer < proc->buffer); | ||
| 866 | BUG_ON((void *)buffer > proc->buffer + proc->buffer_size); | ||
| 867 | |||
| 868 | if (buffer->async_transaction) { | ||
| 869 | proc->free_async_space += size + sizeof(struct binder_buffer); | ||
| 870 | |||
| 871 | binder_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC, | ||
| 872 | "%d: binder_free_buf size %zd async free %zd\n", | ||
| 873 | proc->pid, size, proc->free_async_space); | ||
| 874 | } | ||
| 875 | |||
| 876 | binder_update_page_range(proc, 0, | ||
| 877 | (void *)PAGE_ALIGN((uintptr_t)buffer->data), | ||
| 878 | (void *)(((uintptr_t)buffer->data + buffer_size) & PAGE_MASK), | ||
| 879 | NULL); | ||
| 880 | rb_erase(&buffer->rb_node, &proc->allocated_buffers); | ||
| 881 | buffer->free = 1; | ||
| 882 | if (!list_is_last(&buffer->entry, &proc->buffers)) { | ||
| 883 | struct binder_buffer *next = list_entry(buffer->entry.next, | ||
| 884 | struct binder_buffer, entry); | ||
| 885 | |||
| 886 | if (next->free) { | ||
| 887 | rb_erase(&next->rb_node, &proc->free_buffers); | ||
| 888 | binder_delete_free_buffer(proc, next); | ||
| 889 | } | ||
| 890 | } | ||
| 891 | if (proc->buffers.next != &buffer->entry) { | ||
| 892 | struct binder_buffer *prev = list_entry(buffer->entry.prev, | ||
| 893 | struct binder_buffer, entry); | ||
| 894 | |||
| 895 | if (prev->free) { | ||
| 896 | binder_delete_free_buffer(proc, buffer); | ||
| 897 | rb_erase(&prev->rb_node, &proc->free_buffers); | ||
| 898 | buffer = prev; | ||
| 899 | } | ||
| 900 | } | ||
| 901 | binder_insert_free_buffer(proc, buffer); | ||
| 902 | } | ||
| 903 | |||
| 904 | static struct binder_node *binder_get_node(struct binder_proc *proc, | ||
| 905 | binder_uintptr_t ptr) | ||
| 906 | { | ||
| 907 | struct rb_node *n = proc->nodes.rb_node; | ||
| 908 | struct binder_node *node; | ||
| 909 | |||
| 910 | while (n) { | ||
| 911 | node = rb_entry(n, struct binder_node, rb_node); | ||
| 912 | |||
| 913 | if (ptr < node->ptr) | ||
| 914 | n = n->rb_left; | ||
| 915 | else if (ptr > node->ptr) | ||
| 916 | n = n->rb_right; | ||
| 917 | else | ||
| 918 | return node; | ||
| 919 | } | ||
| 920 | return NULL; | ||
| 921 | } | ||
| 922 | |||
| 923 | static struct binder_node *binder_new_node(struct binder_proc *proc, | ||
| 924 | binder_uintptr_t ptr, | ||
| 925 | binder_uintptr_t cookie) | ||
| 926 | { | 1115 | { |
| 927 | struct rb_node **p = &proc->nodes.rb_node; | 1116 | struct rb_node **p = &proc->nodes.rb_node; |
| 928 | struct rb_node *parent = NULL; | 1117 | struct rb_node *parent = NULL; |
| 929 | struct binder_node *node; | 1118 | struct binder_node *node; |
| 1119 | binder_uintptr_t ptr = fp ? fp->binder : 0; | ||
| 1120 | binder_uintptr_t cookie = fp ? fp->cookie : 0; | ||
| 1121 | __u32 flags = fp ? fp->flags : 0; | ||
| 1122 | |||
| 1123 | assert_spin_locked(&proc->inner_lock); | ||
| 930 | 1124 | ||
| 931 | while (*p) { | 1125 | while (*p) { |
| 1126 | |||
| 932 | parent = *p; | 1127 | parent = *p; |
| 933 | node = rb_entry(parent, struct binder_node, rb_node); | 1128 | node = rb_entry(parent, struct binder_node, rb_node); |
| 934 | 1129 | ||
| @@ -936,33 +1131,74 @@ static struct binder_node *binder_new_node(struct binder_proc *proc, · 1 unmodified line | |||
| 936 | p = &(*p)->rb_left; | 1131 | p = &(*p)->rb_left; |
| 937 | else if (ptr > node->ptr) | 1132 | else if (ptr > node->ptr) |
| 938 | p = &(*p)->rb_right; | 1133 | p = &(*p)->rb_right; |
| 939 | else | 1134 | else { |
| 940 | return NULL; | 1135 | /* |
| 1136 | * A matching node is already in | ||
| 1137 | * the rb tree. Abandon the init | ||
| 1138 | * and return it. | ||
| 1139 | */ | ||
| 1140 | binder_inc_node_tmpref_ilocked(node); | ||
| 1141 | return node; | ||
| 1142 | } | ||
| 941 | } | 1143 | } |
| 942 | 1144 | node = new_node; | |
| 943 | node = kzalloc(sizeof(*node), GFP_KERNEL); | ||
| 944 | if (node == NULL) | ||
| 945 | return NULL; | ||
| 946 | binder_stats_created(BINDER_STAT_NODE); | 1145 | binder_stats_created(BINDER_STAT_NODE); |
| 1146 | node->tmp_refs++; | ||
| 947 | rb_link_node(&node->rb_node, parent, p); | 1147 | rb_link_node(&node->rb_node, parent, p); |
| 948 | rb_insert_color(&node->rb_node, &proc->nodes); | 1148 | rb_insert_color(&node->rb_node, &proc->nodes); |
| 949 | node->debug_id = ++binder_last_id; | 1149 | node->debug_id = atomic_inc_return(&binder_last_id); |
| 950 | node->proc = proc; | 1150 | node->proc = proc; |
| 951 | node->ptr = ptr; | 1151 | node->ptr = ptr; |
| 952 | node->cookie = cookie; | 1152 | node->cookie = cookie; |
| 953 | node->work.type = BINDER_WORK_NODE; | 1153 | node->work.type = BINDER_WORK_NODE; |
| 1154 | node->min_priority = flags & FLAT_BINDER_FLAG_PRIORITY_MASK; | ||
| 1155 | node->accept_fds = !!(flags & FLAT_BINDER_FLAG_ACCEPTS_FDS); | ||
| 1156 | spin_lock_init(&node->lock); | ||
| 954 | INIT_LIST_HEAD(&node->work.entry); | 1157 | INIT_LIST_HEAD(&node->work.entry); |
| 955 | INIT_LIST_HEAD(&node->async_todo); | 1158 | INIT_LIST_HEAD(&node->async_todo); |
| 956 | binder_debug(BINDER_DEBUG_INTERNAL_REFS, | 1159 | binder_debug(BINDER_DEBUG_INTERNAL_REFS, |
| 957 | "%d:%d node %d u%016llx c%016llx created\n", | 1160 | "%d:%d node %d u%016llx c%016llx created\n", |
| 958 | proc->pid, current->pid, node->debug_id, | 1161 | proc->pid, current->pid, node->debug_id, |
| 959 | (u64)node->ptr, (u64)node->cookie); | 1162 | (u64)node->ptr, (u64)node->cookie); |
| 1163 | |||
| 960 | return node; | 1164 | return node; |
| 961 | } | 1165 | } |
| 962 | 1166 | ||
| 963 | static int binder_inc_node(struct binder_node *node, int strong, int internal, | 1167 | static struct binder_node *binder_new_node(struct binder_proc *proc, |
| 964 | struct list_head *target_list) | 1168 | struct flat_binder_object *fp) |
| 1169 | { | ||
| 1170 | struct binder_node *node; | ||
| 1171 | struct binder_node *new_node = kzalloc(sizeof(*node), GFP_KERNEL); | ||
| 1172 | |||
| 1173 | if (!new_node) | ||
| 1174 | return NULL; | ||
| 1175 | binder_inner_proc_lock(proc); | ||
| 1176 | node = binder_init_node_ilocked(proc, new_node, fp); | ||
| 1177 | binder_inner_proc_unlock(proc); | ||
| 1178 | if (node != new_node) | ||
| 1179 | /* | ||
| 1180 | * The node was already added by another thread | ||
| 1181 | */ | ||
| 1182 | kfree(new_node); | ||
| 1183 | |||
| 1184 | return node; | ||
| 1185 | } | ||
| 1186 | |||
| 1187 | static void binder_free_node(struct binder_node *node) | ||
| 965 | { | 1188 | { |
| 1189 | kfree(node); | ||
| 1190 | binder_stats_deleted(BINDER_STAT_NODE); | ||
| 1191 | } | ||
| 1192 | |||
| 1193 | static int binder_inc_node_nilocked(struct binder_node *node, int strong, | ||
| 1194 | int internal, | ||
| 1195 | struct list_head *target_list) | ||
| 1196 | { | ||
| 1197 | struct binder_proc *proc = node->proc; | ||
| 1198 | |||
| 1199 | assert_spin_locked(&node->lock); | ||
| 1200 | if (proc) | ||
| 1201 | assert_spin_locked(&proc->inner_lock); | ||
| 966 | if (strong) { | 1202 | if (strong) { |
| 967 | if (internal) { | 1203 | if (internal) { |
| 968 | if (target_list == NULL && | 1204 | if (target_list == NULL && |
| @@ -978,8 +1214,8 @@ static int binder_inc_node(struct binder_node *node, int strong, int internal, · 9 unmodified lines | |||
| 978 | } else | 1214 | } else |
| 979 | node->local_strong_refs++; | 1215 | node->local_strong_refs++; |
| 980 | if (!node->has_strong_ref && target_list) { | 1216 | if (!node->has_strong_ref && target_list) { |
| 981 | list_del_init(&node->work.entry); | 1217 | binder_dequeue_work_ilocked(&node->work); |
| 982 | list_add_tail(&node->work.entry, target_list); | 1218 | binder_enqueue_work_ilocked(&node->work, target_list); |
| 983 | } | 1219 | } |
| 984 | } else { | 1220 | } else { |
| 985 | if (!internal) | 1221 | if (!internal) |
| @@ -990,58 +1226,169 @@ static int binder_inc_node(struct binder_node *node, int strong, int internal, · 4 unmodified lines | |||
| 990 | node->debug_id); | 1226 | node->debug_id); |
| 991 | return -EINVAL; | 1227 | return -EINVAL; |
| 992 | } | 1228 | } |
| 993 | list_add_tail(&node->work.entry, target_list); | 1229 | binder_enqueue_work_ilocked(&node->work, target_list); |
| 994 | } | 1230 | } |
| 995 | } | 1231 | } |
| 996 | return 0; | 1232 | return 0; |
| 997 | } | 1233 | } |
| 998 | 1234 | ||
| 999 | static int binder_dec_node(struct binder_node *node, int strong, int internal) | 1235 | static int binder_inc_node(struct binder_node *node, int strong, int internal, |
| 1236 | struct list_head *target_list) | ||
| 1237 | { | ||
| 1238 | int ret; | ||
| 1239 | |||
| 1240 | binder_node_inner_lock(node); | ||
| 1241 | ret = binder_inc_node_nilocked(node, strong, internal, target_list); | ||
| 1242 | binder_node_inner_unlock(node); | ||
| 1243 | |||
| 1244 | return ret; | ||
| 1245 | } | ||
| 1246 | |||
| 1247 | static bool binder_dec_node_nilocked(struct binder_node *node, | ||
| 1248 | int strong, int internal) | ||
| 1000 | { | 1249 | { |
| 1250 | struct binder_proc *proc = node->proc; | ||
| 1251 | |||
| 1252 | assert_spin_locked(&node->lock); | ||
| 1253 | if (proc) | ||
| 1254 | assert_spin_locked(&proc->inner_lock); | ||
| 1001 | if (strong) { | 1255 | if (strong) { |
| 1002 | if (internal) | 1256 | if (internal) |
| 1003 | node->internal_strong_refs--; | 1257 | node->internal_strong_refs--; |
| 1004 | else | 1258 | else |
| 1005 | node->local_strong_refs--; | 1259 | node->local_strong_refs--; |
| 1006 | if (node->local_strong_refs || node->internal_strong_refs) | 1260 | if (node->local_strong_refs || node->internal_strong_refs) |
| 1007 | return 0; | 1261 | return false; |
| 1008 | } else { | 1262 | } else { |
| 1009 | if (!internal) | 1263 | if (!internal) |
| 1010 | node->local_weak_refs--; | 1264 | node->local_weak_refs--; |
| 1011 | if (node->local_weak_refs || !hlist_empty(&node->refs)) | 1265 | if (node->local_weak_refs || node->tmp_refs || |
| 1012 | return 0; | 1266 | !hlist_empty(&node->refs)) |
| 1267 | return false; | ||
| 1013 | } | 1268 | } |
| 1014 | if (node->proc && (node->has_strong_ref || node->has_weak_ref)) { | 1269 | |
| 1270 | if (proc && (node->has_strong_ref || node->has_weak_ref)) { | ||
| 1015 | if (list_empty(&node->work.entry)) { | 1271 | if (list_empty(&node->work.entry)) { |
| 1016 | list_add_tail(&node->work.entry, &node->proc->todo); | 1272 | binder_enqueue_work_ilocked(&node->work, &proc->todo); |
| 1017 | wake_up_interruptible(&node->proc->wait); | 1273 | binder_wakeup_proc_ilocked(proc); |
| 1018 | } | 1274 | } |
| 1019 | } else { | 1275 | } else { |
| 1020 | if (hlist_empty(&node->refs) && !node->local_strong_refs && | 1276 | if (hlist_empty(&node->refs) && !node->local_strong_refs && |
| 1021 | !node->local_weak_refs) { | 1277 | !node->local_weak_refs && !node->tmp_refs) { |
| 1022 | list_del_init(&node->work.entry); | 1278 | if (proc) { |
| 1023 | if (node->proc) { | 1279 | binder_dequeue_work_ilocked(&node->work); |
| 1024 | rb_erase(&node->rb_node, &node->proc->nodes); | 1280 | rb_erase(&node->rb_node, &proc->nodes); |
| 1025 | binder_debug(BINDER_DEBUG_INTERNAL_REFS, | 1281 | binder_debug(BINDER_DEBUG_INTERNAL_REFS, |
| 1026 | "refless node %d deleted\n", | 1282 | "refless node %d deleted\n", |
| 1027 | node->debug_id); | 1283 | node->debug_id); |
| 1028 | } else { | 1284 | } else { |
| 1285 | BUG_ON(!list_empty(&node->work.entry)); | ||
| 1286 | spin_lock(&binder_dead_nodes_lock); | ||
| 1287 | /* | ||
| 1288 | * tmp_refs could have changed so | ||
| 1289 | * check it again | ||
| 1290 | */ | ||
| 1291 | if (node->tmp_refs) { | ||
| 1292 | spin_unlock(&binder_dead_nodes_lock); | ||
| 1293 | return false; | ||
| 1294 | } | ||
| 1029 | hlist_del(&node->dead_node); | 1295 | hlist_del(&node->dead_node); |
| 1296 | spin_unlock(&binder_dead_nodes_lock); | ||
| 1030 | binder_debug(BINDER_DEBUG_INTERNAL_REFS, | 1297 | binder_debug(BINDER_DEBUG_INTERNAL_REFS, |
| 1031 | "dead node %d deleted\n", | 1298 | "dead node %d deleted\n", |
| 1032 | node->debug_id); | 1299 | node->debug_id); |
| 1033 | } | 1300 | } |
| 1034 | kfree(node); | 1301 | return true; |
| 1035 | binder_stats_deleted(BINDER_STAT_NODE); | ||
| 1036 | } | 1302 | } |
| 1037 | } | 1303 | } |
| 1304 | return false; | ||
| 1305 | } | ||
| 1038 | 1306 | ||
| 1039 | return 0; | 1307 | static void binder_dec_node(struct binder_node *node, int strong, int internal) |
| 1308 | { | ||
| 1309 | bool free_node; | ||
| 1310 | |||
| 1311 | binder_node_inner_lock(node); | ||
| 1312 | free_node = binder_dec_node_nilocked(node, strong, internal); | ||
| 1313 | binder_node_inner_unlock(node); | ||
| 1314 | if (free_node) | ||
| 1315 | binder_free_node(node); | ||
| 1040 | } | 1316 | } |
| 1041 | 1317 | ||
| 1318 | static void binder_inc_node_tmpref_ilocked(struct binder_node *node) | ||
| 1319 | { | ||
| 1320 | /* | ||
| 1321 | * No call to binder_inc_node() is needed since we | ||
| 1322 | * don't need to inform userspace of any changes to | ||
| 1323 | * tmp_refs | ||
| 1324 | */ | ||
| 1325 | node->tmp_refs++; | ||
| 1326 | } | ||
| 1042 | 1327 | ||
| 1043 | static struct binder_ref *binder_get_ref(struct binder_proc *proc, | 1328 | /** |
| 1044 | u32 desc, bool need_strong_ref) | 1329 | * binder_inc_node_tmpref() - take a temporary reference on node |
| 1330 | * @node: node to reference | ||
| 1331 | * | ||
| 1332 | * Take reference on node to prevent the node from being freed | ||
| 1333 | * while referenced only by a local variable. The inner lock is | ||
| 1334 | * needed to serialize with the node work on the queue (which | ||
| 1335 | * isn't needed after the node is dead). If the node is dead | ||
| 1336 | * (node->proc is NULL), use binder_dead_nodes_lock to protect | ||
| 1337 | * node->tmp_refs against dead-node-only cases where the node | ||
| 1338 | * lock cannot be acquired (eg traversing the dead node list to | ||
| 1339 | * print nodes) | ||
| 1340 | */ | ||
| 1341 | static void binder_inc_node_tmpref(struct binder_node *node) | ||
| 1342 | { | ||
| 1343 | binder_node_lock(node); | ||
| 1344 | if (node->proc) | ||
| 1345 | binder_inner_proc_lock(node->proc); | ||
| 1346 | else | ||
| 1347 | spin_lock(&binder_dead_nodes_lock); | ||
| 1348 | binder_inc_node_tmpref_ilocked(node); | ||
| 1349 | if (node->proc) | ||
| 1350 | binder_inner_proc_unlock(node->proc); | ||
| 1351 | else | ||
| 1352 | spin_unlock(&binder_dead_nodes_lock); | ||
| 1353 | binder_node_unlock(node); | ||
| 1354 | } | ||
| 1355 | |||
| 1356 | /** | ||
| 1357 | * binder_dec_node_tmpref() - remove a temporary reference on node | ||
| 1358 | * @node: node to reference | ||
| 1359 | * | ||
| 1360 | * Release temporary reference on node taken via binder_inc_node_tmpref() | ||
| 1361 | */ | ||
| 1362 | static void binder_dec_node_tmpref(struct binder_node *node) | ||
| 1363 | { | ||
| 1364 | bool free_node; | ||
| 1365 | |||
| 1366 | binder_node_inner_lock(node); | ||
| 1367 | if (!node->proc) | ||
| 1368 | spin_lock(&binder_dead_nodes_lock); | ||
| 1369 | node->tmp_refs--; | ||
| 1370 | BUG_ON(node->tmp_refs < 0); | ||
| 1371 | if (!node->proc) | ||
| 1372 | spin_unlock(&binder_dead_nodes_lock); | ||
| 1373 | /* | ||
| 1374 | * Call binder_dec_node() to check if all refcounts are 0 | ||
| 1375 | * and cleanup is needed. Calling with strong=0 and internal=1 | ||
| 1376 | * causes no actual reference to be released in binder_dec_node(). | ||
| 1377 | * If that changes, a change is needed here too. | ||
| 1378 | */ | ||
| 1379 | free_node = binder_dec_node_nilocked(node, 0, 1); | ||
| 1380 | binder_node_inner_unlock(node); | ||
| 1381 | if (free_node) | ||
| 1382 | binder_free_node(node); | ||
| 1383 | } | ||
| 1384 | |||
| 1385 | static void binder_put_node(struct binder_node *node) | ||
| 1386 | { | ||
| 1387 | binder_dec_node_tmpref(node); | ||
| 1388 | } | ||
| 1389 | |||
| 1390 | static struct binder_ref *binder_get_ref_olocked(struct binder_proc *proc, | ||
| 1391 | u32 desc, bool need_strong_ref) | ||
| 1045 | { | 1392 | { |
| 1046 | struct rb_node *n = proc->refs_by_desc.rb_node; | 1393 | struct rb_node *n = proc->refs_by_desc.rb_node; |
| 1047 | struct binder_ref *ref; | 1394 | struct binder_ref *ref; |
| @@ -1049,11 +1396,11 @@ static struct binder_ref *binder_get_ref(struct binder_proc *proc, · 1 unmodified line | |||
| 1049 | while (n) { | 1396 | while (n) { |
| 1050 | ref = rb_entry(n, struct binder_ref, rb_node_desc); | 1397 | ref = rb_entry(n, struct binder_ref, rb_node_desc); |
| 1051 | 1398 | ||
| 1052 | if (desc < ref->desc) { | 1399 | if (desc < ref->data.desc) { |
| 1053 | n = n->rb_left; | 1400 | n = n->rb_left; |
| 1054 | } else if (desc > ref->desc) { | 1401 | } else if (desc > ref->data.desc) { |
| 1055 | n = n->rb_right; | 1402 | n = n->rb_right; |
| 1056 | } else if (need_strong_ref && !ref->strong) { | 1403 | } else if (need_strong_ref && !ref->data.strong) { |
| 1057 | binder_user_error("tried to use weak ref as strong ref\n"); | 1404 | binder_user_error("tried to use weak ref as strong ref\n"); |
| 1058 | return NULL; | 1405 | return NULL; |
| 1059 | } else { | 1406 | } else { |
| @@ -1063,14 +1410,34 @@ static struct binder_ref *binder_get_ref(struct binder_proc *proc, · 3 unmodified lines | |||
| 1063 | return NULL; | 1410 | return NULL; |
| 1064 | } | 1411 | } |
| 1065 | 1412 | ||
| 1066 | static struct binder_ref *binder_get_ref_for_node(struct binder_proc *proc, | 1413 | /** |
| 1067 | struct binder_node *node) | 1414 | * binder_get_ref_for_node_olocked() - get the ref associated with given node |
| 1415 | * @proc: binder_proc that owns the ref | ||
| 1416 | * @node: binder_node of target | ||
| 1417 | * @new_ref: newly allocated binder_ref to be initialized or %NULL | ||
| 1418 | * | ||
| 1419 | * Look up the ref for the given node and return it if it exists | ||
| 1420 | * | ||
| 1421 | * If it doesn't exist and the caller provides a newly allocated | ||
| 1422 | * ref, initialize the fields of the newly allocated ref and insert | ||
| 1423 | * into the given proc rb_trees and node refs list. | ||
| 1424 | * | ||
| 1425 | * Return: the ref for node. It is possible that another thread | ||
| 1426 | * allocated/initialized the ref first in which case the | ||
| 1427 | * returned ref would be different than the passed-in | ||
| 1428 | * new_ref. new_ref must be kfree'd by the caller in | ||
| 1429 | * this case. | ||
| 1430 | */ | ||
| 1431 | static struct binder_ref *binder_get_ref_for_node_olocked( | ||
| 1432 | struct binder_proc *proc, | ||
| 1433 | struct binder_node *node, | ||
| 1434 | struct binder_ref *new_ref) | ||
| 1068 | { | 1435 | { |
| 1069 | struct rb_node *n; | 1436 | struct binder_context *context = proc->context; |
| 1070 | struct rb_node **p = &proc->refs_by_node.rb_node; | 1437 | struct rb_node **p = &proc->refs_by_node.rb_node; |
| 1071 | struct rb_node *parent = NULL; | 1438 | struct rb_node *parent = NULL; |
| 1072 | struct binder_ref *ref, *new_ref; | 1439 | struct binder_ref *ref; |
| 1073 | struct binder_context *context = proc->context; | 1440 | struct rb_node *n; |
| 1074 | 1441 | ||
| 1075 | while (*p) { | 1442 | while (*p) { |
| 1076 | parent = *p; | 1443 | parent = *p; |
| @@ -1083,144 +1450,446 @@ static struct binder_ref *binder_get_ref_for_node(struct binder_proc *proc, · 6 unmodified lines | |||
| 1083 | else | 1450 | else |
| 1084 | return ref; | 1451 | return ref; |
| 1085 | } | 1452 | } |
| 1086 | new_ref = kzalloc(sizeof(*ref), GFP_KERNEL); | 1453 | if (!new_ref) |
| 1087 | if (new_ref == NULL) | ||
| 1088 | return NULL; | 1454 | return NULL; |
| 1455 | |||
| 1089 | binder_stats_created(BINDER_STAT_REF); | 1456 | binder_stats_created(BINDER_STAT_REF); |
| 1090 | new_ref->debug_id = ++binder_last_id; | 1457 | new_ref->data.debug_id = atomic_inc_return(&binder_last_id); |
| 1091 | new_ref->proc = proc; | 1458 | new_ref->proc = proc; |
| 1092 | new_ref->node = node; | 1459 | new_ref->node = node; |
| 1093 | rb_link_node(&new_ref->rb_node_node, parent, p); | 1460 | rb_link_node(&new_ref->rb_node_node, parent, p); |
| 1094 | rb_insert_color(&new_ref->rb_node_node, &proc->refs_by_node); | 1461 | rb_insert_color(&new_ref->rb_node_node, &proc->refs_by_node); |
| 1095 | 1462 | ||
| 1096 | new_ref->desc = (node == context->binder_context_mgr_node) ? 0 : 1; | 1463 | new_ref->data.desc = (node == context->binder_context_mgr_node) ? 0 : 1; |
| 1097 | for (n = rb_first(&proc->refs_by_desc); n != NULL; n = rb_next(n)) { | 1464 | for (n = rb_first(&proc->refs_by_desc); n != NULL; n = rb_next(n)) { |
| 1098 | ref = rb_entry(n, struct binder_ref, rb_node_desc); | 1465 | ref = rb_entry(n, struct binder_ref, rb_node_desc); |
| 1099 | if (ref->desc > new_ref->desc) | 1466 | if (ref->data.desc > new_ref->data.desc) |
| 1100 | break; | 1467 | break; |
| 1101 | new_ref->desc = ref->desc + 1; | 1468 | new_ref->data.desc = ref->data.desc + 1; |
| 1469 | } | ||
| 1470 | |||
| 1471 | p = &proc->refs_by_desc.rb_node; | ||
| 1472 | while (*p) { | ||
| 1473 | parent = *p; | ||
| 1474 | ref = rb_entry(parent, struct binder_ref, rb_node_desc); | ||
| 1475 | |||
| 1476 | if (new_ref->data.desc < ref->data.desc) | ||
| 1477 | p = &(*p)->rb_left; | ||
| 1478 | else if (new_ref->data.desc > ref->data.desc) | ||
| 1479 | p = &(*p)->rb_right; | ||
| 1480 | else | ||
| 1481 | BUG(); | ||
| 1482 | } | ||
| 1483 | rb_link_node(&new_ref->rb_node_desc, parent, p); | ||
| 1484 | rb_insert_color(&new_ref->rb_node_desc, &proc->refs_by_desc); | ||
| 1485 | |||
| 1486 | binder_node_lock(node); | ||
| 1487 | hlist_add_head(&new_ref->node_entry, &node->refs); | ||
| 1488 | |||
| 1489 | binder_debug(BINDER_DEBUG_INTERNAL_REFS, | ||
| 1490 | "%d new ref %d desc %d for node %d\n", | ||
| 1491 | proc->pid, new_ref->data.debug_id, new_ref->data.desc, | ||
| 1492 | node->debug_id); | ||
| 1493 | binder_node_unlock(node); | ||
| 1494 | return new_ref; | ||
| 1495 | } | ||
| 1496 | |||
| 1497 | static void binder_cleanup_ref_olocked(struct binder_ref *ref) | ||
| 1498 | { | ||
| 1499 | bool delete_node = false; | ||
| 1500 | |||
| 1501 | binder_debug(BINDER_DEBUG_INTERNAL_REFS, | ||
| 1502 | "%d delete ref %d desc %d for node %d\n", | ||
| 1503 | ref->proc->pid, ref->data.debug_id, ref->data.desc, | ||
| 1504 | ref->node->debug_id); | ||
| 1505 | |||
| 1506 | rb_erase(&ref->rb_node_desc, &ref->proc->refs_by_desc); | ||
| 1507 | rb_erase(&ref->rb_node_node, &ref->proc->refs_by_node); | ||
| 1508 | |||
| 1509 | binder_node_inner_lock(ref->node); | ||
| 1510 | if (ref->data.strong) | ||
| 1511 | binder_dec_node_nilocked(ref->node, 1, 1); | ||
| 1512 | |||
| 1513 | hlist_del(&ref->node_entry); | ||
| 1514 | delete_node = binder_dec_node_nilocked(ref->node, 0, 1); | ||
| 1515 | binder_node_inner_unlock(ref->node); | ||
| 1516 | /* | ||
| 1517 | * Clear ref->node unless we want the caller to free the node | ||
| 1518 | */ | ||
| 1519 | if (!delete_node) { | ||
| 1520 | /* | ||
| 1521 | * The caller uses ref->node to determine | ||
| 1522 | * whether the node needs to be freed. Clear | ||
| 1523 | * it since the node is still alive. | ||
| 1524 | */ | ||
| 1525 | ref->node = NULL; | ||
| 1526 | } | ||
| 1527 | |||
| 1528 | if (ref->death) { | ||
| 1529 | binder_debug(BINDER_DEBUG_DEAD_BINDER, | ||
| 1530 | "%d delete ref %d desc %d has death notification\n", | ||
| 1531 | ref->proc->pid, ref->data.debug_id, | ||
| 1532 | ref->data.desc); | ||
| 1533 | binder_dequeue_work(ref->proc, &ref->death->work); | ||
| 1534 | binder_stats_deleted(BINDER_STAT_DEATH); | ||
| 1535 | } | ||
| 1536 | binder_stats_deleted(BINDER_STAT_REF); | ||
| 1537 | } | ||
| 1538 | |||
| 1539 | /** | ||
| 1540 | * binder_inc_ref_olocked() - increment the ref for given handle | ||
| 1541 | * @ref: ref to be incremented | ||
| 1542 | * @strong: if true, strong increment, else weak | ||
| 1543 | * @target_list: list to queue node work on | ||
| 1544 | * | ||
| 1545 | * Increment the ref. @ref->proc->outer_lock must be held on entry | ||
| 1546 | * | ||
| 1547 | * Return: 0, if successful, else errno | ||
| 1548 | */ | ||
| 1549 | static int binder_inc_ref_olocked(struct binder_ref *ref, int strong, | ||
| 1550 | struct list_head *target_list) | ||
| 1551 | { | ||
| 1552 | int ret; | ||
| 1553 | |||
| 1554 | if (strong) { | ||
| 1555 | if (ref->data.strong == 0) { | ||
| 1556 | ret = binder_inc_node(ref->node, 1, 1, target_list); | ||
| 1557 | if (ret) | ||
| 1558 | return ret; | ||
| 1559 | } | ||
| 1560 | ref->data.strong++; | ||
| 1561 | } else { | ||
| 1562 | if (ref->data.weak == 0) { | ||
| 1563 | ret = binder_inc_node(ref->node, 0, 1, target_list); | ||
| 1564 | if (ret) | ||
| 1565 | return ret; | ||
| 1566 | } | ||
| 1567 | ref->data.weak++; | ||
| 1568 | } | ||
| 1569 | return 0; | ||
| 1570 | } | ||
| 1571 | |||
| 1572 | /** | ||
| 1573 | * binder_dec_ref() - dec the ref for given handle | ||
| 1574 | * @ref: ref to be decremented | ||
| 1575 | * @strong: if true, strong decrement, else weak | ||
| 1576 | * | ||
| 1577 | * Decrement the ref. | ||
| 1578 | * | ||
| 1579 | * Return: true if ref is cleaned up and ready to be freed | ||
| 1580 | */ | ||
| 1581 | static bool binder_dec_ref_olocked(struct binder_ref *ref, int strong) | ||
| 1582 | { | ||
| 1583 | if (strong) { | ||
| 1584 | if (ref->data.strong == 0) { | ||
| 1585 | binder_user_error("%d invalid dec strong, ref %d desc %d s %d w %d\n", | ||
| 1586 | ref->proc->pid, ref->data.debug_id, | ||
| 1587 | ref->data.desc, ref->data.strong, | ||
| 1588 | ref->data.weak); | ||
| 1589 | return false; | ||
| 1590 | } | ||
| 1591 | ref->data.strong--; | ||
| 1592 | if (ref->data.strong == 0) | ||
| 1593 | binder_dec_node(ref->node, strong, 1); | ||
| 1594 | } else { | ||
| 1595 | if (ref->data.weak == 0) { | ||
| 1596 | binder_user_error("%d invalid dec weak, ref %d desc %d s %d w %d\n", | ||
| 1597 | ref->proc->pid, ref->data.debug_id, | ||
| 1598 | ref->data.desc, ref->data.strong, | ||
| 1599 | ref->data.weak); | ||
| 1600 | return false; | ||
| 1601 | } | ||
| 1602 | ref->data.weak--; | ||
| 1603 | } | ||
| 1604 | if (ref->data.strong == 0 && ref->data.weak == 0) { | ||
| 1605 | binder_cleanup_ref_olocked(ref); | ||
| 1606 | return true; | ||
| 1607 | } | ||
| 1608 | return false; | ||
| 1609 | } | ||
| 1610 | |||
| 1611 | /** | ||
| 1612 | * binder_get_node_from_ref() - get the node from the given proc/desc | ||
| 1613 | * @proc: proc containing the ref | ||
| 1614 | * @desc: the handle associated with the ref | ||
| 1615 | * @need_strong_ref: if true, only return node if ref is strong | ||
| 1616 | * @rdata: the id/refcount data for the ref | ||
| 1617 | * | ||
| 1618 | * Given a proc and ref handle, return the associated binder_node | ||
| 1619 | * | ||
| 1620 | * Return: a binder_node or NULL if not found or not strong when strong required | ||
| 1621 | */ | ||
| 1622 | static struct binder_node *binder_get_node_from_ref( | ||
| 1623 | struct binder_proc *proc, | ||
| 1624 | u32 desc, bool need_strong_ref, | ||
| 1625 | struct binder_ref_data *rdata) | ||
| 1626 | { | ||
| 1627 | struct binder_node *node; | ||
| 1628 | struct binder_ref *ref; | ||
| 1629 | |||
| 1630 | binder_proc_lock(proc); | ||
| 1631 | ref = binder_get_ref_olocked(proc, desc, need_strong_ref); | ||
| 1632 | if (!ref) | ||
| 1633 | goto err_no_ref; | ||
| 1634 | node = ref->node; | ||
| 1635 | /* | ||
| 1636 | * Take an implicit reference on the node to ensure | ||
| 1637 | * it stays alive until the call to binder_put_node() | ||
| 1638 | */ | ||
| 1639 | binder_inc_node_tmpref(node); | ||
| 1640 | if (rdata) | ||
| 1641 | *rdata = ref->data; | ||
| 1642 | binder_proc_unlock(proc); | ||
| 1643 | |||
| 1644 | return node; | ||
| 1645 | |||
| 1646 | err_no_ref: | ||
| 1647 | binder_proc_unlock(proc); | ||
| 1648 | return NULL; | ||
| 1649 | } | ||
| 1650 | |||
| 1651 | /** | ||
| 1652 | * binder_free_ref() - free the binder_ref | ||
| 1653 | * @ref: ref to free | ||
| 1654 | * | ||
| 1655 | * Free the binder_ref. Free the binder_node indicated by ref->node | ||
| 1656 | * (if non-NULL) and the binder_ref_death indicated by ref->death. | ||
| 1657 | */ | ||
| 1658 | static void binder_free_ref(struct binder_ref *ref) | ||
| 1659 | { | ||
| 1660 | if (ref->node) | ||
| 1661 | binder_free_node(ref->node); | ||
| 1662 | kfree(ref->death); | ||
| 1663 | kfree(ref); | ||
| 1664 | } | ||
| 1665 | |||
| 1666 | /** | ||
| 1667 | * binder_update_ref_for_handle() - inc/dec the ref for given handle | ||
| 1668 | * @proc: proc containing the ref | ||
| 1669 | * @desc: the handle associated with the ref | ||
| 1670 | * @increment: true=inc reference, false=dec reference | ||
| 1671 | * @strong: true=strong reference, false=weak reference | ||
| 1672 | * @rdata: the id/refcount data for the ref | ||
| 1673 | * | ||
| 1674 | * Given a proc and ref handle, increment or decrement the ref | ||
| 1675 | * according to "increment" arg. | ||
| 1676 | * | ||
| 1677 | * Return: 0 if successful, else errno | ||
| 1678 | */ | ||
| 1679 | static int binder_update_ref_for_handle(struct binder_proc *proc, | ||
| 1680 | uint32_t desc, bool increment, bool strong, | ||
| 1681 | struct binder_ref_data *rdata) | ||
| 1682 | { | ||
| 1683 | int ret = 0; | ||
| 1684 | struct binder_ref *ref; | ||
| 1685 | bool delete_ref = false; | ||
| 1686 | |||
| 1687 | binder_proc_lock(proc); | ||
| 1688 | ref = binder_get_ref_olocked(proc, desc, strong); | ||
| 1689 | if (!ref) { | ||
| 1690 | ret = -EINVAL; | ||
| 1691 | goto err_no_ref; | ||
| 1102 | } | 1692 | } |
| 1693 | if (increment) | ||
| 1694 | ret = binder_inc_ref_olocked(ref, strong, NULL); | ||
| 1695 | else | ||
| 1696 | delete_ref = binder_dec_ref_olocked(ref, strong); | ||
| 1103 | 1697 | ||
| 1104 | p = &proc->refs_by_desc.rb_node; | 1698 | if (rdata) |
| 1105 | while (*p) { | 1699 | *rdata = ref->data; |
| 1106 | parent = *p; | 1700 | binder_proc_unlock(proc); |
| 1107 | ref = rb_entry(parent, struct binder_ref, rb_node_desc); | ||
| 1108 | 1701 | ||
| 1109 | if (new_ref->desc < ref->desc) | 1702 | if (delete_ref) |
| 1110 | p = &(*p)->rb_left; | 1703 | binder_free_ref(ref); |
| 1111 | else if (new_ref->desc > ref->desc) | 1704 | return ret; |
| 1112 | p = &(*p)->rb_right; | ||
| 1113 | else | ||
| 1114 | BUG(); | ||
| 1115 | } | ||
| 1116 | rb_link_node(&new_ref->rb_node_desc, parent, p); | ||
| 1117 | rb_insert_color(&new_ref->rb_node_desc, &proc->refs_by_desc); | ||
| 1118 | if (node) { | ||
| 1119 | hlist_add_head(&new_ref->node_entry, &node->refs); | ||
| 1120 | 1705 | ||
| 1121 | binder_debug(BINDER_DEBUG_INTERNAL_REFS, | 1706 | err_no_ref: |
| 1122 | "%d new ref %d desc %d for node %d\n", | 1707 | binder_proc_unlock(proc); |
| 1123 | proc->pid, new_ref->debug_id, new_ref->desc, | 1708 | return ret; |
| 1124 | node->debug_id); | 1709 | } |
| 1125 | } else { | 1710 | |
| 1126 | binder_debug(BINDER_DEBUG_INTERNAL_REFS, | 1711 | /** |
| 1127 | "%d new ref %d desc %d for dead node\n", | 1712 | * binder_dec_ref_for_handle() - dec the ref for given handle |
| 1128 | proc->pid, new_ref->debug_id, new_ref->desc); | 1713 | * @proc: proc containing the ref |
| 1129 | } | 1714 | * @desc: the handle associated with the ref |
| 1130 | return new_ref; | 1715 | * @strong: true=strong reference, false=weak reference |
| 1716 | * @rdata: the id/refcount data for the ref | ||
| 1717 | * | ||
| 1718 | * Just calls binder_update_ref_for_handle() to decrement the ref. | ||
| 1719 | * | ||
| 1720 | * Return: 0 if successful, else errno | ||
| 1721 | */ | ||
| 1722 | static int binder_dec_ref_for_handle(struct binder_proc *proc, | ||
| 1723 | uint32_t desc, bool strong, struct binder_ref_data *rdata) | ||
| 1724 | { | ||
| 1725 | return binder_update_ref_for_handle(proc, desc, false, strong, rdata); | ||
| 1131 | } | 1726 | } |
| 1132 | 1727 | ||
| 1133 | static void binder_delete_ref(struct binder_ref *ref) | 1728 | |
| 1729 | /** | ||
| 1730 | * binder_inc_ref_for_node() - increment the ref for given proc/node | ||
| 1731 | * @proc: proc containing the ref | ||
| 1732 | * @node: target node | ||
| 1733 | * @strong: true=strong reference, false=weak reference | ||
| 1734 | * @target_list: worklist to use if node is incremented | ||
| 1735 | * @rdata: the id/refcount data for the ref | ||
| 1736 | * | ||
| 1737 | * Given a proc and node, increment the ref. Create the ref if it | ||
| 1738 | * doesn't already exist | ||
| 1739 | * | ||
| 1740 | * Return: 0 if successful, else errno | ||
| 1741 | */ | ||
| 1742 | static int binder_inc_ref_for_node(struct binder_proc *proc, | ||
| 1743 | struct binder_node *node, | ||
| 1744 | bool strong, | ||
| 1745 | struct list_head *target_list, | ||
| 1746 | struct binder_ref_data *rdata) | ||
| 1134 | { | 1747 | { |
| 1135 | binder_debug(BINDER_DEBUG_INTERNAL_REFS, | 1748 | struct binder_ref *ref; |
| 1136 | "%d delete ref %d desc %d for node %d\n", | 1749 | struct binder_ref *new_ref = NULL; |
| 1137 | ref->proc->pid, ref->debug_id, ref->desc, | 1750 | int ret = 0; |
| 1138 | ref->node->debug_id); | ||
| 1139 | 1751 | ||
| 1140 | rb_erase(&ref->rb_node_desc, &ref->proc->refs_by_desc); | 1752 | binder_proc_lock(proc); |
| 1141 | rb_erase(&ref->rb_node_node, &ref->proc->refs_by_node); | 1753 | ref = binder_get_ref_for_node_olocked(proc, node, NULL); |
| 1142 | if (ref->strong) | 1754 | if (!ref) { |
| 1143 | binder_dec_node(ref->node, 1, 1); | 1755 | binder_proc_unlock(proc); |
| 1144 | hlist_del(&ref->node_entry); | 1756 | new_ref = kzalloc(sizeof(*ref), GFP_KERNEL); |
| 1145 | binder_dec_node(ref->node, 0, 1); | 1757 | if (!new_ref) |
| 1146 | if (ref->death) { | 1758 | return -ENOMEM; |
| 1147 | binder_debug(BINDER_DEBUG_DEAD_BINDER, | 1759 | binder_proc_lock(proc); |
| 1148 | "%d delete ref %d desc %d has death notification\n", | 1760 | ref = binder_get_ref_for_node_olocked(proc, node, new_ref); |
| 1149 | ref->proc->pid, ref->debug_id, ref->desc); | ||
| 1150 | list_del(&ref->death->work.entry); | ||
| 1151 | kfree(ref->death); | ||
| 1152 | binder_stats_deleted(BINDER_STAT_DEATH); | ||
| 1153 | } | 1761 | } |
| 1154 | kfree(ref); | 1762 | ret = binder_inc_ref_olocked(ref, strong, target_list); |
| 1155 | binder_stats_deleted(BINDER_STAT_REF); | 1763 | *rdata = ref->data; |
| 1764 | binder_proc_unlock(proc); | ||
| 1765 | if (new_ref && ref != new_ref) | ||
| 1766 | /* | ||
| 1767 | * Another thread created the ref first so | ||
| 1768 | * free the one we allocated | ||
| 1769 | */ | ||
| 1770 | kfree(new_ref); | ||
| 1771 | return ret; | ||
| 1156 | } | 1772 | } |
| 1157 | 1773 | ||
| 1158 | static int binder_inc_ref(struct binder_ref *ref, int strong, | 1774 | static void binder_pop_transaction_ilocked(struct binder_thread *target_thread, |
| 1159 | struct list_head *target_list) | 1775 | struct binder_transaction *t) |
| 1160 | { | 1776 | { |
| 1161 | int ret; | 1777 | BUG_ON(!target_thread); |
| 1778 | assert_spin_locked(&target_thread->proc->inner_lock); | ||
| 1779 | BUG_ON(target_thread->transaction_stack != t); | ||
| 1780 | BUG_ON(target_thread->transaction_stack->from != target_thread); | ||
| 1781 | target_thread->transaction_stack = | ||
| 1782 | target_thread->transaction_stack->from_parent; | ||
| 1783 | t->from = NULL; | ||
| 1784 | } | ||
| 1162 | 1785 | ||
| 1163 | if (strong) { | 1786 | /** |
| 1164 | if (ref->strong == 0) { | 1787 | * binder_thread_dec_tmpref() - decrement thread->tmp_ref |
| 1165 | ret = binder_inc_node(ref->node, 1, 1, target_list); | 1788 | * @thread: thread to decrement |
| 1166 | if (ret) | 1789 | * |
| 1167 | return ret; | 1790 | * A thread needs to be kept alive while being used to create or |
| 1168 | } | 1791 | * handle a transaction. binder_get_txn_from() is used to safely |
| 1169 | ref->strong++; | 1792 | * extract t->from from a binder_transaction and keep the thread |
| 1170 | } else { | 1793 | * indicated by t->from from being freed. When done with that |
| 1171 | if (ref->weak == 0) { | 1794 | * binder_thread, this function is called to decrement the |
| 1172 | ret = binder_inc_node(ref->node, 0, 1, target_list); | 1795 | * tmp_ref and free if appropriate (thread has been released |
| 1173 | if (ret) | 1796 | * and no transaction being processed by the driver) |
| 1174 | return ret; | 1797 | */ |
| 1175 | } | 1798 | static void binder_thread_dec_tmpref(struct binder_thread *thread) |
| 1176 | ref->weak++; | 1799 | { |
| 1800 | /* | ||
| 1801 | * atomic is used to protect the counter value while | ||
| 1802 | * it cannot reach zero or thread->is_dead is false | ||
| 1803 | */ | ||
| 1804 | binder_inner_proc_lock(thread->proc); | ||
| 1805 | atomic_dec(&thread->tmp_ref); | ||
| 1806 | if (thread->is_dead && !atomic_read(&thread->tmp_ref)) { | ||
| 1807 | binder_inner_proc_unlock(thread->proc); | ||
| 1808 | binder_free_thread(thread); | ||
| 1809 | return; | ||
| 1177 | } | 1810 | } |
| 1178 | return 0; | 1811 | binder_inner_proc_unlock(thread->proc); |
| 1179 | } | 1812 | } |
| 1180 | 1813 | ||
| 1814 | /** | ||
| 1815 | * binder_proc_dec_tmpref() - decrement proc->tmp_ref | ||
| 1816 | * @proc: proc to decrement | ||
| 1817 | * | ||
| 1818 | * A binder_proc needs to be kept alive while being used to create or | ||
| 1819 | * handle a transaction. proc->tmp_ref is incremented when | ||
| 1820 | * creating a new transaction or the binder_proc is currently in-use | ||
| 1821 | * by threads that are being released. When done with the binder_proc, | ||
| 1822 | * this function is called to decrement the counter and free the | ||
| 1823 | * proc if appropriate (proc has been released, all threads have | ||
| 1824 | * been released and not currenly in-use to process a transaction). | ||
| 1825 | */ | ||
| 1826 | static void binder_proc_dec_tmpref(struct binder_proc *proc) | ||
| 1827 | { | ||
| 1828 | binder_inner_proc_lock(proc); | ||
| 1829 | proc->tmp_ref--; | ||
| 1830 | if (proc->is_dead && RB_EMPTY_ROOT(&proc->threads) && | ||
| 1831 | !proc->tmp_ref) { | ||
| 1832 | binder_inner_proc_unlock(proc); | ||
| 1833 | binder_free_proc(proc); | ||
| 1834 | return; | ||
| 1835 | } | ||
| 1836 | binder_inner_proc_unlock(proc); | ||
| 1837 | } | ||
| 1181 | 1838 | ||
| 1182 | static int binder_dec_ref(struct binder_ref *ref, int strong) | 1839 | /** |
| 1840 | * binder_get_txn_from() - safely extract the "from" thread in transaction | ||
| 1841 | * @t: binder transaction for t->from | ||
| 1842 | * | ||
| 1843 | * Atomically return the "from" thread and increment the tmp_ref | ||
| 1844 | * count for the thread to ensure it stays alive until | ||
| 1845 | * binder_thread_dec_tmpref() is called. | ||
| 1846 | * | ||
| 1847 | * Return: the value of t->from | ||
| 1848 | */ | ||
| 1849 | static struct binder_thread *binder_get_txn_from( | ||
| 1850 | struct binder_transaction *t) | ||
| 1183 | { | 1851 | { |
| 1184 | if (strong) { | 1852 | struct binder_thread *from; |
| 1185 | if (ref->strong == 0) { | ||
| 1186 | binder_user_error("%d invalid dec strong, ref %d desc %d s %d w %d\n", | ||
| 1187 | ref->proc->pid, ref->debug_id, | ||
| 1188 | ref->desc, ref->strong, ref->weak); | ||
| 1189 | return -EINVAL; | ||
| 1190 | } | ||
| 1191 | ref->strong--; | ||
| 1192 | if (ref->strong == 0) { | ||
| 1193 | int ret; | ||
| 1194 | 1853 | ||
| 1195 | ret = binder_dec_node(ref->node, strong, 1); | 1854 | spin_lock(&t->lock); |
| 1196 | if (ret) | 1855 | from = t->from; |
| 1197 | return ret; | 1856 | if (from) |
| 1198 | } | 1857 | atomic_inc(&from->tmp_ref); |
| 1199 | } else { | 1858 | spin_unlock(&t->lock); |
| 1200 | if (ref->weak == 0) { | 1859 | return from; |
| 1201 | binder_user_error("%d invalid dec weak, ref %d desc %d s %d w %d\n", | ||
| 1202 | ref->proc->pid, ref->debug_id, | ||
| 1203 | ref->desc, ref->strong, ref->weak); | ||
| 1204 | return -EINVAL; | ||
| 1205 | } | ||
| 1206 | ref->weak--; | ||
| 1207 | } | ||
| 1208 | if (ref->strong == 0 && ref->weak == 0) | ||
| 1209 | binder_delete_ref(ref); | ||
| 1210 | return 0; | ||
| 1211 | } | 1860 | } |
| 1212 | 1861 | ||
| 1213 | static void binder_pop_transaction(struct binder_thread *target_thread, | 1862 | /** |
| 1214 | struct binder_transaction *t) | 1863 | * binder_get_txn_from_and_acq_inner() - get t->from and acquire inner lock |
| 1864 | * @t: binder transaction for t->from | ||
| 1865 | * | ||
| 1866 | * Same as binder_get_txn_from() except it also acquires the proc->inner_lock | ||
| 1867 | * to guarantee that the thread cannot be released while operating on it. | ||
| 1868 | * The caller must call binder_inner_proc_unlock() to release the inner lock | ||
| 1869 | * as well as call binder_dec_thread_txn() to release the reference. | ||
| 1870 | * | ||
| 1871 | * Return: the value of t->from | ||
| 1872 | */ | ||
| 1873 | static struct binder_thread *binder_get_txn_from_and_acq_inner( | ||
| 1874 | struct binder_transaction *t) | ||
| 1215 | { | 1875 | { |
| 1216 | if (target_thread) { | 1876 | struct binder_thread *from; |
| 1217 | BUG_ON(target_thread->transaction_stack != t); | 1877 | |
| 1218 | BUG_ON(target_thread->transaction_stack->from != target_thread); | 1878 | from = binder_get_txn_from(t); |
| 1219 | target_thread->transaction_stack = | 1879 | if (!from) |
| 1220 | target_thread->transaction_stack->from_parent; | 1880 | return NULL; |
| 1221 | t->from = NULL; | 1881 | binder_inner_proc_lock(from->proc); |
| 1882 | if (t->from) { | ||
| 1883 | BUG_ON(from != t->from); | ||
| 1884 | return from; | ||
| 1222 | } | 1885 | } |
| 1223 | t->need_reply = 0; | 1886 | binder_inner_proc_unlock(from->proc); |
| 1887 | binder_thread_dec_tmpref(from); | ||
| 1888 | return NULL; | ||
| 1889 | } | ||
| 1890 | |||
| 1891 | static void binder_free_transaction(struct binder_transaction *t) | ||
| 1892 | { | ||
| 1224 | if (t->buffer) | 1893 | if (t->buffer) |
| 1225 | t->buffer->transaction = NULL; | 1894 | t->buffer->transaction = NULL; |
| 1226 | kfree(t); | 1895 | kfree(t); |
| @@ -1235,30 +1904,28 @@ static void binder_send_failed_reply(struct binder_transaction *t, · 8 unmodified lines | |||
| 1235 | 1904 | ||
| 1236 | BUG_ON(t->flags & TF_ONE_WAY); | 1905 | BUG_ON(t->flags & TF_ONE_WAY); |
| 1237 | while (1) { | 1906 | while (1) { |
| 1238 | target_thread = t->from; | 1907 | target_thread = binder_get_txn_from_and_acq_inner(t); |
| 1239 | if (target_thread) { | 1908 | if (target_thread) { |
| 1240 | if (target_thread->return_error != BR_OK && | 1909 | binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, |
| 1241 | target_thread->return_error2 == BR_OK) { | 1910 | "send failed reply for transaction %d to %d:%d\n", |
| 1242 | target_thread->return_error2 = | 1911 | t->debug_id, |
| 1243 | target_thread->return_error; | 1912 | target_thread->proc->pid, |
| 1244 | target_thread->return_error = BR_OK; | 1913 | target_thread->pid); |
| 1245 | } | 1914 | |
| 1246 | if (target_thread->return_error == BR_OK) { | 1915 | binder_pop_transaction_ilocked(target_thread, t); |
| 1247 | binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, | 1916 | if (target_thread->reply_error.cmd == BR_OK) { |
| 1248 | "send failed reply for transaction %d to %d:%d\n", | 1917 | target_thread->reply_error.cmd = error_code; |
| 1249 | t->debug_id, | 1918 | binder_enqueue_work_ilocked( |
| 1250 | target_thread->proc->pid, | 1919 | &target_thread->reply_error.work, |
| 1251 | target_thread->pid); | 1920 | &target_thread->todo); |
| 1252 | |||
| 1253 | binder_pop_transaction(target_thread, t); | ||
| 1254 | target_thread->return_error = error_code; | ||
| 1255 | wake_up_interruptible(&target_thread->wait); | 1921 | wake_up_interruptible(&target_thread->wait); |
| 1256 | } else { | 1922 | } else { |
| 1257 | pr_err("reply failed, target thread, %d:%d, has error code %d already\n", | 1923 | WARN(1, "Unexpected reply error: %u\n", |
| 1258 | target_thread->proc->pid, | 1924 | target_thread->reply_error.cmd); |
| 1259 | target_thread->pid, | ||
| 1260 | target_thread->return_error); | ||
| 1261 | } | 1925 | } |
| 1926 | binder_inner_proc_unlock(target_thread->proc); | ||
| 1927 | binder_thread_dec_tmpref(target_thread); | ||
| 1928 | binder_free_transaction(t); | ||
| 1262 | return; | 1929 | return; |
| 1263 | } | 1930 | } |
| 1264 | next = t->from_parent; | 1931 | next = t->from_parent; |
| @@ -1267,7 +1934,7 @@ static void binder_send_failed_reply(struct binder_transaction *t, · 2 unmodified lines | |||
| 1267 | "send failed reply for transaction %d, target dead\n", | 1934 | "send failed reply for transaction %d, target dead\n", |
| 1268 | t->debug_id); | 1935 | t->debug_id); |
| 1269 | 1936 | ||
| 1270 | binder_pop_transaction(target_thread, t); | 1937 | binder_free_transaction(t); |
| 1271 | if (next == NULL) { | 1938 | if (next == NULL) { |
| 1272 | binder_debug(BINDER_DEBUG_DEAD_BINDER, | 1939 | binder_debug(BINDER_DEBUG_DEAD_BINDER, |
| 1273 | "reply failed, no target thread at root\n"); | 1940 | "reply failed, no target thread at root\n"); |
| @@ -1476,24 +2143,26 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, · 202 unmodified lines | |||
| 1476 | node->debug_id, (u64)node->ptr); | 2143 | node->debug_id, (u64)node->ptr); |
| 1477 | binder_dec_node(node, hdr->type == BINDER_TYPE_BINDER, | 2144 | binder_dec_node(node, hdr->type == BINDER_TYPE_BINDER, |
| 1478 | 0); | 2145 | 0); |
| 2146 | binder_put_node(node); | ||
| 1479 | } break; | 2147 | } break; |
| 1480 | case BINDER_TYPE_HANDLE: | 2148 | case BINDER_TYPE_HANDLE: |
| 1481 | case BINDER_TYPE_WEAK_HANDLE: { | 2149 | case BINDER_TYPE_WEAK_HANDLE: { |
| 1482 | struct flat_binder_object *fp; | 2150 | struct flat_binder_object *fp; |
| 1483 | struct binder_ref *ref; | 2151 | struct binder_ref_data rdata; |
| 2152 | int ret; | ||
| 1484 | 2153 | ||
| 1485 | fp = to_flat_binder_object(hdr); | 2154 | fp = to_flat_binder_object(hdr); |
| 1486 | ref = binder_get_ref(proc, fp->handle, | 2155 | ret = binder_dec_ref_for_handle(proc, fp->handle, |
| 1487 | hdr->type == BINDER_TYPE_HANDLE); | 2156 | hdr->type == BINDER_TYPE_HANDLE, &rdata); |
| 1488 | if (ref == NULL) { | 2157 | |
| 1489 | pr_err("transaction release %d bad handle %d\n", | 2158 | if (ret) { |
| 1490 | debug_id, fp->handle); | 2159 | pr_err("transaction release %d bad handle %d, ret = %d\n", |
| 2160 | debug_id, fp->handle, ret); | ||
| 1491 | break; | 2161 | break; |
| 1492 | } | 2162 | } |
| 1493 | binder_debug(BINDER_DEBUG_TRANSACTION, | 2163 | binder_debug(BINDER_DEBUG_TRANSACTION, |
| 1494 | " ref %d desc %d (node %d)\n", | 2164 | " ref %d desc %d\n", |
| 1495 | ref->debug_id, ref->desc, ref->node->debug_id); | 2165 | rdata.debug_id, rdata.desc); |
| 1496 | binder_dec_ref(ref, hdr->type == BINDER_TYPE_HANDLE); | ||
| 1497 | } break; | 2166 | } break; |
| 1498 | 2167 | ||
| 1499 | case BINDER_TYPE_FD: { | 2168 | case BINDER_TYPE_FD: { |
| @@ -1532,7 +2201,8 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, · 32 unmodified lines | |||
| 1532 | * back to kernel address space to access it | 2201 | * back to kernel address space to access it |
| 1533 | */ | 2202 | */ |
| 1534 | parent_buffer = parent->buffer - | 2203 | parent_buffer = parent->buffer - |
| 1535 | proc->user_buffer_offset; | 2204 | binder_alloc_get_user_buffer_offset( |
| 2205 | &proc->alloc); | ||
| 1536 | 2206 | ||
| 1537 | fd_buf_size = sizeof(u32) * fda->num_fds; | 2207 | fd_buf_size = sizeof(u32) * fda->num_fds; |
| 1538 | if (fda->num_fds >= SIZE_MAX / sizeof(u32)) { | 2208 | if (fda->num_fds >= SIZE_MAX / sizeof(u32)) { |
| @@ -1564,102 +2234,122 @@ static int binder_translate_binder(struct flat_binder_object *fp, · 25 unmodified lines | |||
| 1564 | struct binder_thread *thread) | 2234 | struct binder_thread *thread) |
| 1565 | { | 2235 | { |
| 1566 | struct binder_node *node; | 2236 | struct binder_node *node; |
| 1567 | struct binder_ref *ref; | ||
| 1568 | struct binder_proc *proc = thread->proc; | 2237 | struct binder_proc *proc = thread->proc; |
| 1569 | struct binder_proc *target_proc = t->to_proc; | 2238 | struct binder_proc *target_proc = t->to_proc; |
| 2239 | struct binder_ref_data rdata; | ||
| 2240 | int ret = 0; | ||
| 1570 | 2241 | ||
| 1571 | node = binder_get_node(proc, fp->binder); | 2242 | node = binder_get_node(proc, fp->binder); |
| 1572 | if (!node) { | 2243 | if (!node) { |
| 1573 | node = binder_new_node(proc, fp->binder, fp->cookie); | 2244 | node = binder_new_node(proc, fp); |
| 1574 | if (!node) | 2245 | if (!node) |
| 1575 | return -ENOMEM; | 2246 | return -ENOMEM; |
| 1576 | |||
| 1577 | node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK; | ||
| 1578 | node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS); | ||
| 1579 | } | 2247 | } |
| 1580 | if (fp->cookie != node->cookie) { | 2248 | if (fp->cookie != node->cookie) { |
| 1581 | binder_user_error("%d:%d sending u%016llx node %d, cookie mismatch %016llx != %016llx\n", | 2249 | binder_user_error("%d:%d sending u%016llx node %d, cookie mismatch %016llx != %016llx\n", |
| 1582 | proc->pid, thread->pid, (u64)fp->binder, | 2250 | proc->pid, thread->pid, (u64)fp->binder, |
| 1583 | node->debug_id, (u64)fp->cookie, | 2251 | node->debug_id, (u64)fp->cookie, |
| 1584 | (u64)node->cookie); | 2252 | (u64)node->cookie); |
| 1585 | return -EINVAL; | 2253 | ret = -EINVAL; |
| 2254 | goto done; | ||
| 2255 | } | ||
| 2256 | if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) { | ||
| 2257 | ret = -EPERM; | ||
| 2258 | goto done; | ||
| 1586 | } | 2259 | } |
| 1587 | if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) | ||
| 1588 | return -EPERM; | ||
| 1589 | 2260 | ||
| 1590 | ref = binder_get_ref_for_node(target_proc, node); | 2261 | ret = binder_inc_ref_for_node(target_proc, node, |
| 1591 | if (!ref) | 2262 | fp->hdr.type == BINDER_TYPE_BINDER, |
| 1592 | return -EINVAL; | 2263 | &thread->todo, &rdata); |
| 2264 | if (ret) | ||
| 2265 | goto done; | ||
| 1593 | 2266 | ||
| 1594 | if (fp->hdr.type == BINDER_TYPE_BINDER) | 2267 | if (fp->hdr.type == BINDER_TYPE_BINDER) |
| 1595 | fp->hdr.type = BINDER_TYPE_HANDLE; | 2268 | fp->hdr.type = BINDER_TYPE_HANDLE; |
| 1596 | else | 2269 | else |
| 1597 | fp->hdr.type = BINDER_TYPE_WEAK_HANDLE; | 2270 | fp->hdr.type = BINDER_TYPE_WEAK_HANDLE; |
| 1598 | fp->binder = 0; | 2271 | fp->binder = 0; |
| 1599 | fp->handle = ref->desc; | 2272 | fp->handle = rdata.desc; |
| 1600 | fp->cookie = 0; | 2273 | fp->cookie = 0; |
| 1601 | binder_inc_ref(ref, fp->hdr.type == BINDER_TYPE_HANDLE, &thread->todo); | ||
| 1602 | 2274 | ||
| 1603 | trace_binder_transaction_node_to_ref(t, node, ref); | 2275 | trace_binder_transaction_node_to_ref(t, node, &rdata); |
| 1604 | binder_debug(BINDER_DEBUG_TRANSACTION, | 2276 | binder_debug(BINDER_DEBUG_TRANSACTION, |
| 1605 | " node %d u%016llx -> ref %d desc %d\n", | 2277 | " node %d u%016llx -> ref %d desc %d\n", |
| 1606 | node->debug_id, (u64)node->ptr, | 2278 | node->debug_id, (u64)node->ptr, |
| 1607 | ref->debug_id, ref->desc); | 2279 | rdata.debug_id, rdata.desc); |
| 1608 | 2280 | done: | |
| 1609 | return 0; | 2281 | binder_put_node(node); |
| 2282 | return ret; | ||
| 1610 | } | 2283 | } |
| 1611 | 2284 | ||
| 1612 | static int binder_translate_handle(struct flat_binder_object *fp, | 2285 | static int binder_translate_handle(struct flat_binder_object *fp, |
| 1613 | struct binder_transaction *t, | 2286 | struct binder_transaction *t, |
| 1614 | struct binder_thread *thread) | 2287 | struct binder_thread *thread) |
| 1615 | { | 2288 | { |
| 1616 | struct binder_ref *ref; | ||
| 1617 | struct binder_proc *proc = thread->proc; | 2289 | struct binder_proc *proc = thread->proc; |
| 1618 | struct binder_proc *target_proc = t->to_proc; | 2290 | struct binder_proc *target_proc = t->to_proc; |
| 2291 | struct binder_node *node; | ||
| 2292 | struct binder_ref_data src_rdata; | ||
| 2293 | int ret = 0; | ||
| 1619 | 2294 | ||
| 1620 | ref = binder_get_ref(proc, fp->handle, | 2295 | node = binder_get_node_from_ref(proc, fp->handle, |
| 1621 | fp->hdr.type == BINDER_TYPE_HANDLE); | 2296 | fp->hdr.type == BINDER_TYPE_HANDLE, &src_rdata); |
| 1622 | if (!ref) { | 2297 | if (!node) { |
| 1623 | binder_user_error("%d:%d got transaction with invalid handle, %d\n", | 2298 | binder_user_error("%d:%d got transaction with invalid handle, %d\n", |
| 1624 | proc->pid, thread->pid, fp->handle); | 2299 | proc->pid, thread->pid, fp->handle); |
| 1625 | return -EINVAL; | 2300 | return -EINVAL; |
| 1626 | } | 2301 | } |
| 1627 | if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) | 2302 | if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) { |
| 1628 | return -EPERM; | 2303 | ret = -EPERM; |
| 2304 | goto done; | ||
| 2305 | } | ||
| 1629 | 2306 | ||
| 1630 | if (ref->node->proc == target_proc) { | 2307 | binder_node_lock(node); |
| 2308 | if (node->proc == target_proc) { | ||
| 1631 | if (fp->hdr.type == BINDER_TYPE_HANDLE) | 2309 | if (fp->hdr.type == BINDER_TYPE_HANDLE) |
| 1632 | fp->hdr.type = BINDER_TYPE_BINDER; | 2310 | fp->hdr.type = BINDER_TYPE_BINDER; |
| 1633 | else | 2311 | else |
| 1634 | fp->hdr.type = BINDER_TYPE_WEAK_BINDER; | 2312 | fp->hdr.type = BINDER_TYPE_WEAK_BINDER; |
| 1635 | fp->binder = ref->node->ptr; | 2313 | fp->binder = node->ptr; |
| 1636 | fp->cookie = ref->node->cookie; | 2314 | fp->cookie = node->cookie; |
| 1637 | binder_inc_node(ref->node, fp->hdr.type == BINDER_TYPE_BINDER, | 2315 | if (node->proc) |
| 1638 | 0, NULL); | 2316 | binder_inner_proc_lock(node->proc); |
| 1639 | trace_binder_transaction_ref_to_node(t, ref); | 2317 | binder_inc_node_nilocked(node, |
| 2318 | fp->hdr.type == BINDER_TYPE_BINDER, | ||
| 2319 | 0, NULL); | ||
| 2320 | if (node->proc) | ||
| 2321 | binder_inner_proc_unlock(node->proc); | ||
| 2322 | trace_binder_transaction_ref_to_node(t, node, &src_rdata); | ||
| 1640 | binder_debug(BINDER_DEBUG_TRANSACTION, | 2323 | binder_debug(BINDER_DEBUG_TRANSACTION, |
| 1641 | " ref %d desc %d -> node %d u%016llx\n", | 2324 | " ref %d desc %d -> node %d u%016llx\n", |
| 1642 | ref->debug_id, ref->desc, ref->node->debug_id, | 2325 | src_rdata.debug_id, src_rdata.desc, node->debug_id, |
| 1643 | (u64)ref->node->ptr); | 2326 | (u64)node->ptr); |
| 2327 | binder_node_unlock(node); | ||
| 1644 | } else { | 2328 | } else { |
| 1645 | struct binder_ref *new_ref; | 2329 | int ret; |
| 2330 | struct binder_ref_data dest_rdata; | ||
| 1646 | 2331 | ||
| 1647 | new_ref = binder_get_ref_for_node(target_proc, ref->node); | 2332 | binder_node_unlock(node); |
| 1648 | if (!new_ref) | 2333 | ret = binder_inc_ref_for_node(target_proc, node, |
| 1649 | return -EINVAL; | 2334 | fp->hdr.type == BINDER_TYPE_HANDLE, |
| 2335 | NULL, &dest_rdata); | ||
| 2336 | if (ret) | ||
| 2337 | goto done; | ||
| 1650 | 2338 | ||
| 1651 | fp->binder = 0; | 2339 | fp->binder = 0; |
| 1652 | fp->handle = new_ref->desc; | 2340 | fp->handle = dest_rdata.desc; |
| 1653 | fp->cookie = 0; | 2341 | fp->cookie = 0; |
| 1654 | binder_inc_ref(new_ref, fp->hdr.type == BINDER_TYPE_HANDLE, | 2342 | trace_binder_transaction_ref_to_ref(t, node, &src_rdata, |
| 1655 | NULL); | 2343 | &dest_rdata); |
| 1656 | trace_binder_transaction_ref_to_ref(t, ref, new_ref); | ||
| 1657 | binder_debug(BINDER_DEBUG_TRANSACTION, | 2344 | binder_debug(BINDER_DEBUG_TRANSACTION, |
| 1658 | " ref %d desc %d -> ref %d desc %d (node %d)\n", | 2345 | " ref %d desc %d -> ref %d desc %d (node %d)\n", |
| 1659 | ref->debug_id, ref->desc, new_ref->debug_id, | 2346 | src_rdata.debug_id, src_rdata.desc, |
| 1660 | new_ref->desc, ref->node->debug_id); | 2347 | dest_rdata.debug_id, dest_rdata.desc, |
| 2348 | node->debug_id); | ||
| 1661 | } | 2349 | } |
| 1662 | return 0; | 2350 | done: |
| 2351 | binder_put_node(node); | ||
| 2352 | return ret; | ||
| 1663 | } | 2353 | } |
| 1664 | 2354 | ||
| 1665 | static int binder_translate_fd(int fd, | 2355 | static int binder_translate_fd(int fd, |
| @@ -1750,7 +2440,8 @@ static int binder_translate_fd_array(struct binder_fd_array_object *fda, · 84 unmodified lines | |||
| 1750 | * Since the parent was already fixed up, convert it | 2440 | * Since the parent was already fixed up, convert it |
| 1751 | * back to the kernel address space to access it | 2441 | * back to the kernel address space to access it |
| 1752 | */ | 2442 | */ |
| 1753 | parent_buffer = parent->buffer - target_proc->user_buffer_offset; | 2443 | parent_buffer = parent->buffer - |
| 2444 | binder_alloc_get_user_buffer_offset(&target_proc->alloc); | ||
| 1754 | fd_array = (u32 *)(parent_buffer + fda->parent_offset); | 2445 | fd_array = (u32 *)(parent_buffer + fda->parent_offset); |
| 1755 | if (!IS_ALIGNED((unsigned long)fd_array, sizeof(u32))) { | 2446 | if (!IS_ALIGNED((unsigned long)fd_array, sizeof(u32))) { |
| 1756 | binder_user_error("%d:%d parent offset not aligned correctly.\n", | 2447 | binder_user_error("%d:%d parent offset not aligned correctly.\n", |
| @@ -1818,12 +2509,80 @@ static int binder_fixup_parent(struct binder_transaction *t, · 61 unmodified lines | |||
| 1818 | return -EINVAL; | 2509 | return -EINVAL; |
| 1819 | } | 2510 | } |
| 1820 | parent_buffer = (u8 *)(parent->buffer - | 2511 | parent_buffer = (u8 *)(parent->buffer - |
| 1821 | target_proc->user_buffer_offset); | 2512 | binder_alloc_get_user_buffer_offset( |
| 2513 | &target_proc->alloc)); | ||
| 1822 | *(binder_uintptr_t *)(parent_buffer + bp->parent_offset) = bp->buffer; | 2514 | *(binder_uintptr_t *)(parent_buffer + bp->parent_offset) = bp->buffer; |
| 1823 | 2515 | ||
| 1824 | return 0; | 2516 | return 0; |
| 1825 | } | 2517 | } |
| 1826 | 2518 | ||
| 2519 | /** | ||
| 2520 | * binder_proc_transaction() - sends a transaction to a process and wakes it up | ||
| 2521 | * @t: transaction to send | ||
| 2522 | * @proc: process to send the transaction to | ||
| 2523 | * @thread: thread in @proc to send the transaction to (may be NULL) | ||
| 2524 | * | ||
| 2525 | * This function queues a transaction to the specified process. It will try | ||
| 2526 | * to find a thread in the target process to handle the transaction and | ||
| 2527 | * wake it up. If no thread is found, the work is queued to the proc | ||
| 2528 | * waitqueue. | ||
| 2529 | * | ||
| 2530 | * If the @thread parameter is not NULL, the transaction is always queued | ||
| 2531 | * to the waitlist of that specific thread. | ||
| 2532 | * | ||
| 2533 | * Return: true if the transactions was successfully queued | ||
| 2534 | * false if the target process or thread is dead | ||
| 2535 | */ | ||
| 2536 | static bool binder_proc_transaction(struct binder_transaction *t, | ||
| 2537 | struct binder_proc *proc, | ||
| 2538 | struct binder_thread *thread) | ||
| 2539 | { | ||
| 2540 | struct list_head *target_list = NULL; | ||
| 2541 | struct binder_node *node = t->buffer->target_node; | ||
| 2542 | bool oneway = !!(t->flags & TF_ONE_WAY); | ||
| 2543 | bool wakeup = true; | ||
| 2544 | |||
| 2545 | BUG_ON(!node); | ||
| 2546 | binder_node_lock(node); | ||
| 2547 | if (oneway) { | ||
| 2548 | BUG_ON(thread); | ||
| 2549 | if (node->has_async_transaction) { | ||
| 2550 | target_list = &node->async_todo; | ||
| 2551 | wakeup = false; | ||
| 2552 | } else { | ||
| 2553 | node->has_async_transaction = 1; | ||
| 2554 | } | ||
| 2555 | } | ||
| 2556 | |||
| 2557 | binder_inner_proc_lock(proc); | ||
| 2558 | |||
| 2559 | if (proc->is_dead || (thread && thread->is_dead)) { | ||
| 2560 | binder_inner_proc_unlock(proc); | ||
| 2561 | binder_node_unlock(node); | ||
| 2562 | return false; | ||
| 2563 | } | ||
| 2564 | |||
| 2565 | if (!thread && !target_list) | ||
| 2566 | thread = binder_select_thread_ilocked(proc); | ||
| 2567 | |||
| 2568 | if (thread) | ||
| 2569 | target_list = &thread->todo; | ||
| 2570 | else if (!target_list) | ||
| 2571 | target_list = &proc->todo; | ||
| 2572 | else | ||
| 2573 | BUG_ON(target_list != &node->async_todo); | ||
| 2574 | |||
| 2575 | binder_enqueue_work_ilocked(&t->work, target_list); | ||
| 2576 | |||
| 2577 | if (wakeup) | ||
| 2578 | binder_wakeup_thread_ilocked(proc, thread, !oneway /* sync */); | ||
| 2579 | |||
| 2580 | binder_inner_proc_unlock(proc); | ||
| 2581 | binder_node_unlock(node); | ||
| 2582 | |||
| 2583 | return true; | ||
| 2584 | } | ||
| 2585 | |||
| 1827 | static void binder_transaction(struct binder_proc *proc, | 2586 | static void binder_transaction(struct binder_proc *proc, |
| 1828 | struct binder_thread *thread, | 2587 | struct binder_thread *thread, |
| 1829 | struct binder_transaction_data *tr, int reply, | 2588 | struct binder_transaction_data *tr, int reply, |
| @@ -1835,19 +2594,21 @@ static void binder_transaction(struct binder_proc *proc, · 5 unmodified lines | |||
| 1835 | binder_size_t *offp, *off_end, *off_start; | 2594 | binder_size_t *offp, *off_end, *off_start; |
| 1836 | binder_size_t off_min; | 2595 | binder_size_t off_min; |
| 1837 | u8 *sg_bufp, *sg_buf_end; | 2596 | u8 *sg_bufp, *sg_buf_end; |
| 1838 | struct binder_proc *target_proc; | 2597 | struct binder_proc *target_proc = NULL; |
| 1839 | struct binder_thread *target_thread = NULL; | 2598 | struct binder_thread *target_thread = NULL; |
| 1840 | struct binder_node *target_node = NULL; | 2599 | struct binder_node *target_node = NULL; |
| 1841 | struct list_head *target_list; | ||
| 1842 | wait_queue_head_t *target_wait; | ||
| 1843 | struct binder_transaction *in_reply_to = NULL; | 2600 | struct binder_transaction *in_reply_to = NULL; |
| 1844 | struct binder_transaction_log_entry *e; | 2601 | struct binder_transaction_log_entry *e; |
| 1845 | uint32_t return_error; | 2602 | uint32_t return_error = 0; |
| 2603 | uint32_t return_error_param = 0; | ||
| 2604 | uint32_t return_error_line = 0; | ||
| 1846 | struct binder_buffer_object *last_fixup_obj = NULL; | 2605 | struct binder_buffer_object *last_fixup_obj = NULL; |
| 1847 | binder_size_t last_fixup_min_off = 0; | 2606 | binder_size_t last_fixup_min_off = 0; |
| 1848 | struct binder_context *context = proc->context; | 2607 | struct binder_context *context = proc->context; |
| 2608 | int t_debug_id = atomic_inc_return(&binder_last_id); | ||
| 1849 | 2609 | ||
| 1850 | e = binder_transaction_log_add(&binder_transaction_log); | 2610 | e = binder_transaction_log_add(&binder_transaction_log); |
| 2611 | e->debug_id = t_debug_id; | ||
| 1851 | e->call_type = reply ? 2 : !!(tr->flags & TF_ONE_WAY); | 2612 | e->call_type = reply ? 2 : !!(tr->flags & TF_ONE_WAY); |
| 1852 | e->from_proc = proc->pid; | 2613 | e->from_proc = proc->pid; |
| 1853 | e->from_thread = thread->pid; | 2614 | e->from_thread = thread->pid; |
| @@ -1857,29 +2618,40 @@ static void binder_transaction(struct binder_proc *proc, · 3 unmodified lines | |||
| 1857 | e->context_name = proc->context->name; | 2618 | e->context_name = proc->context->name; |
| 1858 | 2619 | ||
| 1859 | if (reply) { | 2620 | if (reply) { |
| 2621 | binder_inner_proc_lock(proc); | ||
| 1860 | in_reply_to = thread->transaction_stack; | 2622 | in_reply_to = thread->transaction_stack; |
| 1861 | if (in_reply_to == NULL) { | 2623 | if (in_reply_to == NULL) { |
| 2624 | binder_inner_proc_unlock(proc); | ||
| 1862 | binder_user_error("%d:%d got reply transaction with no transaction stack\n", | 2625 | binder_user_error("%d:%d got reply transaction with no transaction stack\n", |
| 1863 | proc->pid, thread->pid); | 2626 | proc->pid, thread->pid); |
| 1864 | return_error = BR_FAILED_REPLY; | 2627 | return_error = BR_FAILED_REPLY; |
| 2628 | return_error_param = -EPROTO; | ||
| 2629 | return_error_line = __LINE__; | ||
| 1865 | goto err_empty_call_stack; | 2630 | goto err_empty_call_stack; |
| 1866 | } | 2631 | } |
| 1867 | binder_set_nice(in_reply_to->saved_priority); | ||
| 1868 | if (in_reply_to->to_thread != thread) { | 2632 | if (in_reply_to->to_thread != thread) { |
| 2633 | spin_lock(&in_reply_to->lock); | ||
| 1869 | binder_user_error("%d:%d got reply transaction with bad transaction stack, transaction %d has target %d:%d\n", | 2634 | binder_user_error("%d:%d got reply transaction with bad transaction stack, transaction %d has target %d:%d\n", |
| 1870 | proc->pid, thread->pid, in_reply_to->debug_id, | 2635 | proc->pid, thread->pid, in_reply_to->debug_id, |
| 1871 | in_reply_to->to_proc ? | 2636 | in_reply_to->to_proc ? |
| 1872 | in_reply_to->to_proc->pid : 0, | 2637 | in_reply_to->to_proc->pid : 0, |
| 1873 | in_reply_to->to_thread ? | 2638 | in_reply_to->to_thread ? |
| 1874 | in_reply_to->to_thread->pid : 0); | 2639 | in_reply_to->to_thread->pid : 0); |
| 2640 | spin_unlock(&in_reply_to->lock); | ||
| 2641 | binder_inner_proc_unlock(proc); | ||
| 1875 | return_error = BR_FAILED_REPLY; | 2642 | return_error = BR_FAILED_REPLY; |
| 2643 | return_error_param = -EPROTO; | ||
| 2644 | return_error_line = __LINE__; | ||
| 1876 | in_reply_to = NULL; | 2645 | in_reply_to = NULL; |
| 1877 | goto err_bad_call_stack; | 2646 | goto err_bad_call_stack; |
| 1878 | } | 2647 | } |
| 1879 | thread->transaction_stack = in_reply_to->to_parent; | 2648 | thread->transaction_stack = in_reply_to->to_parent; |
| 1880 | target_thread = in_reply_to->from; | 2649 | binder_inner_proc_unlock(proc); |
| 2650 | binder_set_nice(in_reply_to->saved_priority); | ||
| 2651 | target_thread = binder_get_txn_from_and_acq_inner(in_reply_to); | ||
| 1881 | if (target_thread == NULL) { | 2652 | if (target_thread == NULL) { |
| 1882 | return_error = BR_DEAD_REPLY; | 2653 | return_error = BR_DEAD_REPLY; |
| 2654 | return_error_line = __LINE__; | ||
| 1883 | goto err_dead_binder; | 2655 | goto err_dead_binder; |
| 1884 | } | 2656 | } |
| 1885 | if (target_thread->transaction_stack != in_reply_to) { | 2657 | if (target_thread->transaction_stack != in_reply_to) { |
| @@ -1888,89 +2660,137 @@ static void binder_transaction(struct binder_proc *proc, · 2 unmodified lines | |||
| 1888 | target_thread->transaction_stack ? | 2660 | target_thread->transaction_stack ? |
| 1889 | target_thread->transaction_stack->debug_id : 0, | 2661 | target_thread->transaction_stack->debug_id : 0, |
| 1890 | in_reply_to->debug_id); | 2662 | in_reply_to->debug_id); |
| 2663 | binder_inner_proc_unlock(target_thread->proc); | ||
| 1891 | return_error = BR_FAILED_REPLY; | 2664 | return_error = BR_FAILED_REPLY; |
| 2665 | return_error_param = -EPROTO; | ||
| 2666 | return_error_line = __LINE__; | ||
| 1892 | in_reply_to = NULL; | 2667 | in_reply_to = NULL; |
| 1893 | target_thread = NULL; | 2668 | target_thread = NULL; |
| 1894 | goto err_dead_binder; | 2669 | goto err_dead_binder; |
| 1895 | } | 2670 | } |
| 1896 | target_proc = target_thread->proc; | 2671 | target_proc = target_thread->proc; |
| 2672 | target_proc->tmp_ref++; | ||
| 2673 | binder_inner_proc_unlock(target_thread->proc); | ||
| 1897 | } else { | 2674 | } else { |
| 1898 | if (tr->target.handle) { | 2675 | if (tr->target.handle) { |
| 1899 | struct binder_ref *ref; | 2676 | struct binder_ref *ref; |
| 1900 | 2677 | ||
| 1901 | ref = binder_get_ref(proc, tr->target.handle, true); | 2678 | /* |
| 1902 | if (ref == NULL) { | 2679 | * There must already be a strong ref |
| 2680 | * on this node. If so, do a strong | ||
| 2681 | * increment on the node to ensure it | ||
| 2682 | * stays alive until the transaction is | ||
| 2683 | * done. | ||
| 2684 | */ | ||
| 2685 | binder_proc_lock(proc); | ||
| 2686 | ref = binder_get_ref_olocked(proc, tr->target.handle, | ||
| 2687 | true); | ||
| 2688 | if (ref) { | ||
| 2689 | binder_inc_node(ref->node, 1, 0, NULL); | ||
| 2690 | target_node = ref->node; | ||
| 2691 | } | ||
| 2692 | binder_proc_unlock(proc); | ||
| 2693 | if (target_node == NULL) { | ||
| 1903 | binder_user_error("%d:%d got transaction to invalid handle\n", | 2694 | binder_user_error("%d:%d got transaction to invalid handle\n", |
| 1904 | proc->pid, thread->pid); | 2695 | proc->pid, thread->pid); |
| 1905 | return_error = BR_FAILED_REPLY; | 2696 | return_error = BR_FAILED_REPLY; |
| 2697 | return_error_param = -EINVAL; | ||
| 2698 | return_error_line = __LINE__; | ||
| 1906 | goto err_invalid_target_handle; | 2699 | goto err_invalid_target_handle; |
| 1907 | } | 2700 | } |
| 1908 | target_node = ref->node; | ||
| 1909 | } else { | 2701 | } else { |
| 2702 | mutex_lock(&context->context_mgr_node_lock); | ||
| 1910 | target_node = context->binder_context_mgr_node; | 2703 | target_node = context->binder_context_mgr_node; |
| 1911 | if (target_node == NULL) { | 2704 | if (target_node == NULL) { |
| 1912 | return_error = BR_DEAD_REPLY; | 2705 | return_error = BR_DEAD_REPLY; |
| 2706 | mutex_unlock(&context->context_mgr_node_lock); | ||
| 2707 | return_error_line = __LINE__; | ||
| 1913 | goto err_no_context_mgr_node; | 2708 | goto err_no_context_mgr_node; |
| 1914 | } | 2709 | } |
| 2710 | binder_inc_node(target_node, 1, 0, NULL); | ||
| 2711 | mutex_unlock(&context->context_mgr_node_lock); | ||
| 1915 | } | 2712 | } |
| 1916 | e->to_node = target_node->debug_id; | 2713 | e->to_node = target_node->debug_id; |
| 2714 | binder_node_lock(target_node); | ||
| 1917 | target_proc = target_node->proc; | 2715 | target_proc = target_node->proc; |
| 1918 | if (target_proc == NULL) { | 2716 | if (target_proc == NULL) { |
| 2717 | binder_node_unlock(target_node); | ||
| 1919 | return_error = BR_DEAD_REPLY; | 2718 | return_error = BR_DEAD_REPLY; |
| 2719 | return_error_line = __LINE__; | ||
| 1920 | goto err_dead_binder; | 2720 | goto err_dead_binder; |
| 1921 | } | 2721 | } |
| 2722 | binder_inner_proc_lock(target_proc); | ||
| 2723 | target_proc->tmp_ref++; | ||
| 2724 | binder_inner_proc_unlock(target_proc); | ||
| 2725 | binder_node_unlock(target_node); | ||
| 1922 | if (security_binder_transaction(proc->tsk, | 2726 | if (security_binder_transaction(proc->tsk, |
| 1923 | target_proc->tsk) < 0) { | 2727 | target_proc->tsk) < 0) { |
| 1924 | return_error = BR_FAILED_REPLY; | 2728 | return_error = BR_FAILED_REPLY; |
| 2729 | return_error_param = -EPERM; | ||
| 2730 | return_error_line = __LINE__; | ||
| 1925 | goto err_invalid_target_handle; | 2731 | goto err_invalid_target_handle; |
| 1926 | } | 2732 | } |
| 2733 | binder_inner_proc_lock(proc); | ||
| 1927 | if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) { | 2734 | if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) { |
| 1928 | struct binder_transaction *tmp; | 2735 | struct binder_transaction *tmp; |
| 1929 | 2736 | ||
| 1930 | tmp = thread->transaction_stack; | 2737 | tmp = thread->transaction_stack; |
| 1931 | if (tmp->to_thread != thread) { | 2738 | if (tmp->to_thread != thread) { |
| 2739 | spin_lock(&tmp->lock); | ||
| 1932 | binder_user_error("%d:%d got new transaction with bad transaction stack, transaction %d has target %d:%d\n", | 2740 | binder_user_error("%d:%d got new transaction with bad transaction stack, transaction %d has target %d:%d\n", |
| 1933 | proc->pid, thread->pid, tmp->debug_id, | 2741 | proc->pid, thread->pid, tmp->debug_id, |
| 1934 | tmp->to_proc ? tmp->to_proc->pid : 0, | 2742 | tmp->to_proc ? tmp->to_proc->pid : 0, |
| 1935 | tmp->to_thread ? | 2743 | tmp->to_thread ? |
| 1936 | tmp->to_thread->pid : 0); | 2744 | tmp->to_thread->pid : 0); |
| 2745 | spin_unlock(&tmp->lock); | ||
| 2746 | binder_inner_proc_unlock(proc); | ||
| 1937 | return_error = BR_FAILED_REPLY; | 2747 | return_error = BR_FAILED_REPLY; |
| 2748 | return_error_param = -EPROTO; | ||
| 2749 | return_error_line = __LINE__; | ||
| 1938 | goto err_bad_call_stack; | 2750 | goto err_bad_call_stack; |
| 1939 | } | 2751 | } |
| 1940 | while (tmp) { | 2752 | while (tmp) { |
| 1941 | if (tmp->from && tmp->from->proc == target_proc) | 2753 | struct binder_thread *from; |
| 1942 | target_thread = tmp->from; | 2754 | |
| 2755 | spin_lock(&tmp->lock); | ||
| 2756 | from = tmp->from; | ||
| 2757 | if (from && from->proc == target_proc) { | ||
| 2758 | atomic_inc(&from->tmp_ref); | ||
| 2759 | target_thread = from; | ||
| 2760 | spin_unlock(&tmp->lock); | ||
| 2761 | break; | ||
| 2762 | } | ||
| 2763 | spin_unlock(&tmp->lock); | ||
| 1943 | tmp = tmp->from_parent; | 2764 | tmp = tmp->from_parent; |
| 1944 | } | 2765 | } |
| 1945 | } | 2766 | } |
| 2767 | binder_inner_proc_unlock(proc); | ||
| 1946 | } | 2768 | } |
| 1947 | if (target_thread) { | 2769 | if (target_thread) |
| 1948 | e->to_thread = target_thread->pid; | 2770 | e->to_thread = target_thread->pid; |
| 1949 | target_list = &target_thread->todo; | ||
| 1950 | target_wait = &target_thread->wait; | ||
| 1951 | } else { | ||
| 1952 | target_list = &target_proc->todo; | ||
| 1953 | target_wait = &target_proc->wait; | ||
| 1954 | } | ||
| 1955 | e->to_proc = target_proc->pid; | 2771 | e->to_proc = target_proc->pid; |
| 1956 | 2772 | ||
| 1957 | /* TODO: reuse incoming transaction for reply */ | 2773 | /* TODO: reuse incoming transaction for reply */ |
| 1958 | t = kzalloc(sizeof(*t), GFP_KERNEL); | 2774 | t = kzalloc(sizeof(*t), GFP_KERNEL); |
| 1959 | if (t == NULL) { | 2775 | if (t == NULL) { |
| 1960 | return_error = BR_FAILED_REPLY; | 2776 | return_error = BR_FAILED_REPLY; |
| 2777 | return_error_param = -ENOMEM; | ||
| 2778 | return_error_line = __LINE__; | ||
| 1961 | goto err_alloc_t_failed; | 2779 | goto err_alloc_t_failed; |
| 1962 | } | 2780 | } |
| 1963 | binder_stats_created(BINDER_STAT_TRANSACTION); | 2781 | binder_stats_created(BINDER_STAT_TRANSACTION); |
| 2782 | spin_lock_init(&t->lock); | ||
| 1964 | 2783 | ||
| 1965 | tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL); | 2784 | tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL); |
| 1966 | if (tcomplete == NULL) { | 2785 | if (tcomplete == NULL) { |
| 1967 | return_error = BR_FAILED_REPLY; | 2786 | return_error = BR_FAILED_REPLY; |
| 2787 | return_error_param = -ENOMEM; | ||
| 2788 | return_error_line = __LINE__; | ||
| 1968 | goto err_alloc_tcomplete_failed; | 2789 | goto err_alloc_tcomplete_failed; |
| 1969 | } | 2790 | } |
| 1970 | binder_stats_created(BINDER_STAT_TRANSACTION_COMPLETE); | 2791 | binder_stats_created(BINDER_STAT_TRANSACTION_COMPLETE); |
| 1971 | 2792 | ||
| 1972 | t->debug_id = ++binder_last_id; | 2793 | t->debug_id = t_debug_id; |
| 1973 | e->debug_id = t->debug_id; | ||
| 1974 | 2794 | ||
| 1975 | if (reply) | 2795 | if (reply) |
| 1976 | binder_debug(BINDER_DEBUG_TRANSACTION, | 2796 | binder_debug(BINDER_DEBUG_TRANSACTION, |
| @@ -2004,11 +2824,18 @@ static void binder_transaction(struct binder_proc *proc, · 27 unmodified lines | |||
| 2004 | 2824 | ||
| 2005 | trace_binder_transaction(reply, t, target_node); | 2825 | trace_binder_transaction(reply, t, target_node); |
| 2006 | 2826 | ||
| 2007 | t->buffer = binder_alloc_buf(target_proc, tr->data_size, | 2827 | t->buffer = binder_alloc_new_buf(&target_proc->alloc, tr->data_size, |
| 2008 | tr->offsets_size, extra_buffers_size, | 2828 | tr->offsets_size, extra_buffers_size, |
| 2009 | !reply && (t->flags & TF_ONE_WAY)); | 2829 | !reply && (t->flags & TF_ONE_WAY)); |
| 2010 | if (t->buffer == NULL) { | 2830 | if (IS_ERR(t->buffer)) { |
| 2011 | return_error = BR_FAILED_REPLY; | 2831 | /* |
| 2832 | * -ESRCH indicates VMA cleared. The target is dying. | ||
| 2833 | */ | ||
| 2834 | return_error_param = PTR_ERR(t->buffer); | ||
| 2835 | return_error = return_error_param == -ESRCH ? | ||
| 2836 | BR_DEAD_REPLY : BR_FAILED_REPLY; | ||
| 2837 | return_error_line = __LINE__; | ||
| 2838 | t->buffer = NULL; | ||
| 2012 | goto err_binder_alloc_buf_failed; | 2839 | goto err_binder_alloc_buf_failed; |
| 2013 | } | 2840 | } |
| 2014 | t->buffer->allow_user_free = 0; | 2841 | t->buffer->allow_user_free = 0; |
| @@ -2016,9 +2843,6 @@ static void binder_transaction(struct binder_proc *proc, · 1 unmodified line | |||
| 2016 | t->buffer->transaction = t; | 2843 | t->buffer->transaction = t; |
| 2017 | t->buffer->target_node = target_node; | 2844 | t->buffer->target_node = target_node; |
| 2018 | trace_binder_transaction_alloc_buf(t->buffer); | 2845 | trace_binder_transaction_alloc_buf(t->buffer); |
| 2019 | if (target_node) | ||
| 2020 | binder_inc_node(target_node, 1, 0, NULL); | ||
| 2021 | |||
| 2022 | off_start = (binder_size_t *)(t->buffer->data + | 2846 | off_start = (binder_size_t *)(t->buffer->data + |
| 2023 | ALIGN(tr->data_size, sizeof(void *))); | 2847 | ALIGN(tr->data_size, sizeof(void *))); |
| 2024 | offp = off_start; | 2848 | offp = off_start; |
| @@ -2028,6 +2852,8 @@ static void binder_transaction(struct binder_proc *proc, · 3 unmodified lines | |||
| 2028 | binder_user_error("%d:%d got transaction with invalid data ptr\n", | 2852 | binder_user_error("%d:%d got transaction with invalid data ptr\n", |
| 2029 | proc->pid, thread->pid); | 2853 | proc->pid, thread->pid); |
| 2030 | return_error = BR_FAILED_REPLY; | 2854 | return_error = BR_FAILED_REPLY; |
| 2855 | return_error_param = -EFAULT; | ||
| 2856 | return_error_line = __LINE__; | ||
| 2031 | goto err_copy_data_failed; | 2857 | goto err_copy_data_failed; |
| 2032 | } | 2858 | } |
| 2033 | if (copy_from_user(offp, (const void __user *)(uintptr_t) | 2859 | if (copy_from_user(offp, (const void __user *)(uintptr_t) |
| @@ -2035,12 +2861,16 @@ static void binder_transaction(struct binder_proc *proc, · 1 unmodified line | |||
| 2035 | binder_user_error("%d:%d got transaction with invalid offsets ptr\n", | 2861 | binder_user_error("%d:%d got transaction with invalid offsets ptr\n", |
| 2036 | proc->pid, thread->pid); | 2862 | proc->pid, thread->pid); |
| 2037 | return_error = BR_FAILED_REPLY; | 2863 | return_error = BR_FAILED_REPLY; |
| 2864 | return_error_param = -EFAULT; | ||
| 2865 | return_error_line = __LINE__; | ||
| 2038 | goto err_copy_data_failed; | 2866 | goto err_copy_data_failed; |
| 2039 | } | 2867 | } |
| 2040 | if (!IS_ALIGNED(tr->offsets_size, sizeof(binder_size_t))) { | 2868 | if (!IS_ALIGNED(tr->offsets_size, sizeof(binder_size_t))) { |
| 2041 | binder_user_error("%d:%d got transaction with invalid offsets size, %lld\n", | 2869 | binder_user_error("%d:%d got transaction with invalid offsets size, %lld\n", |
| 2042 | proc->pid, thread->pid, (u64)tr->offsets_size); | 2870 | proc->pid, thread->pid, (u64)tr->offsets_size); |
| 2043 | return_error = BR_FAILED_REPLY; | 2871 | return_error = BR_FAILED_REPLY; |
| 2872 | return_error_param = -EINVAL; | ||
| 2873 | return_error_line = __LINE__; | ||
| 2044 | goto err_bad_offset; | 2874 | goto err_bad_offset; |
| 2045 | } | 2875 | } |
| 2046 | if (!IS_ALIGNED(extra_buffers_size, sizeof(u64))) { | 2876 | if (!IS_ALIGNED(extra_buffers_size, sizeof(u64))) { |
| @@ -2048,6 +2878,8 @@ static void binder_transaction(struct binder_proc *proc, · 1 unmodified line | |||
| 2048 | proc->pid, thread->pid, | 2878 | proc->pid, thread->pid, |
| 2049 | (u64)extra_buffers_size); | 2879 | (u64)extra_buffers_size); |
| 2050 | return_error = BR_FAILED_REPLY; | 2880 | return_error = BR_FAILED_REPLY; |
| 2881 | return_error_param = -EINVAL; | ||
| 2882 | return_error_line = __LINE__; | ||
| 2051 | goto err_bad_offset; | 2883 | goto err_bad_offset; |
| 2052 | } | 2884 | } |
| 2053 | off_end = (void *)off_start + tr->offsets_size; | 2885 | off_end = (void *)off_start + tr->offsets_size; |
| @@ -2064,6 +2896,8 @@ static void binder_transaction(struct binder_proc *proc, · 10 unmodified lines | |||
| 2064 | (u64)off_min, | 2896 | (u64)off_min, |
| 2065 | (u64)t->buffer->data_size); | 2897 | (u64)t->buffer->data_size); |
| 2066 | return_error = BR_FAILED_REPLY; | 2898 | return_error = BR_FAILED_REPLY; |
| 2899 | return_error_param = -EINVAL; | ||
| 2900 | return_error_line = __LINE__; | ||
| 2067 | goto err_bad_offset; | 2901 | goto err_bad_offset; |
| 2068 | } | 2902 | } |
| 2069 | 2903 | ||
| @@ -2078,6 +2912,8 @@ static void binder_transaction(struct binder_proc *proc, · 8 unmodified lines | |||
| 2078 | ret = binder_translate_binder(fp, t, thread); | 2912 | ret = binder_translate_binder(fp, t, thread); |
| 2079 | if (ret < 0) { | 2913 | if (ret < 0) { |
| 2080 | return_error = BR_FAILED_REPLY; | 2914 | return_error = BR_FAILED_REPLY; |
| 2915 | return_error_param = ret; | ||
| 2916 | return_error_line = __LINE__; | ||
| 2081 | goto err_translate_failed; | 2917 | goto err_translate_failed; |
| 2082 | } | 2918 | } |
| 2083 | } break; | 2919 | } break; |
| @@ -2089,6 +2925,8 @@ static void binder_transaction(struct binder_proc *proc, · 5 unmodified lines | |||
| 2089 | ret = binder_translate_handle(fp, t, thread); | 2925 | ret = binder_translate_handle(fp, t, thread); |
| 2090 | if (ret < 0) { | 2926 | if (ret < 0) { |
| 2091 | return_error = BR_FAILED_REPLY; | 2927 | return_error = BR_FAILED_REPLY; |
| 2928 | return_error_param = ret; | ||
| 2929 | return_error_line = __LINE__; | ||
| 2092 | goto err_translate_failed; | 2930 | goto err_translate_failed; |
| 2093 | } | 2931 | } |
| 2094 | } break; | 2932 | } break; |
| @@ -2100,6 +2938,8 @@ static void binder_transaction(struct binder_proc *proc, · 5 unmodified lines | |||
| 2100 | 2938 | ||
| 2101 | if (target_fd < 0) { | 2939 | if (target_fd < 0) { |
| 2102 | return_error = BR_FAILED_REPLY; | 2940 | return_error = BR_FAILED_REPLY; |
| 2941 | return_error_param = target_fd; | ||
| 2942 | return_error_line = __LINE__; | ||
| 2103 | goto err_translate_failed; | 2943 | goto err_translate_failed; |
| 2104 | } | 2944 | } |
| 2105 | fp->pad_binder = 0; | 2945 | fp->pad_binder = 0; |
| @@ -2116,6 +2956,8 @@ static void binder_transaction(struct binder_proc *proc, · 10 unmodified lines | |||
| 2116 | binder_user_error("%d:%d got transaction with invalid parent offset or type\n", | 2956 | binder_user_error("%d:%d got transaction with invalid parent offset or type\n", |
| 2117 | proc->pid, thread->pid); | 2957 | proc->pid, thread->pid); |
| 2118 | return_error = BR_FAILED_REPLY; | 2958 | return_error = BR_FAILED_REPLY; |
| 2959 | return_error_param = -EINVAL; | ||
| 2960 | return_error_line = __LINE__; | ||
| 2119 | goto err_bad_parent; | 2961 | goto err_bad_parent; |
| 2120 | } | 2962 | } |
| 2121 | if (!binder_validate_fixup(t->buffer, off_start, | 2963 | if (!binder_validate_fixup(t->buffer, off_start, |
| @@ -2125,12 +2967,16 @@ static void binder_transaction(struct binder_proc *proc, · 3 unmodified lines | |||
| 2125 | binder_user_error("%d:%d got transaction with out-of-order buffer fixup\n", | 2967 | binder_user_error("%d:%d got transaction with out-of-order buffer fixup\n", |
| 2126 | proc->pid, thread->pid); | 2968 | proc->pid, thread->pid); |
| 2127 | return_error = BR_FAILED_REPLY; | 2969 | return_error = BR_FAILED_REPLY; |
| 2970 | return_error_param = -EINVAL; | ||
| 2971 | return_error_line = __LINE__; | ||
| 2128 | goto err_bad_parent; | 2972 | goto err_bad_parent; |
| 2129 | } | 2973 | } |
| 2130 | ret = binder_translate_fd_array(fda, parent, t, thread, | 2974 | ret = binder_translate_fd_array(fda, parent, t, thread, |
| 2131 | in_reply_to); | 2975 | in_reply_to); |
| 2132 | if (ret < 0) { | 2976 | if (ret < 0) { |
| 2133 | return_error = BR_FAILED_REPLY; | 2977 | return_error = BR_FAILED_REPLY; |
| 2978 | return_error_param = ret; | ||
| 2979 | return_error_line = __LINE__; | ||
| 2134 | goto err_translate_failed; | 2980 | goto err_translate_failed; |
| 2135 | } | 2981 | } |
| 2136 | last_fixup_obj = parent; | 2982 | last_fixup_obj = parent; |
| @@ -2146,6 +2992,8 @@ static void binder_transaction(struct binder_proc *proc, · 9 unmodified lines | |||
| 2146 | binder_user_error("%d:%d got transaction with too large buffer\n", | 2992 | binder_user_error("%d:%d got transaction with too large buffer\n", |
| 2147 | proc->pid, thread->pid); | 2993 | proc->pid, thread->pid); |
| 2148 | return_error = BR_FAILED_REPLY; | 2994 | return_error = BR_FAILED_REPLY; |
| 2995 | return_error_param = -EINVAL; | ||
| 2996 | return_error_line = __LINE__; | ||
| 2149 | goto err_bad_offset; | 2997 | goto err_bad_offset; |
| 2150 | } | 2998 | } |
| 2151 | if (copy_from_user(sg_bufp, | 2999 | if (copy_from_user(sg_bufp, |
| @@ -2153,12 +3001,15 @@ static void binder_transaction(struct binder_proc *proc, · 1 unmodified line | |||
| 2153 | bp->buffer, bp->length)) { | 3001 | bp->buffer, bp->length)) { |
| 2154 | binder_user_error("%d:%d got transaction with invalid offsets ptr\n", | 3002 | binder_user_error("%d:%d got transaction with invalid offsets ptr\n", |
| 2155 | proc->pid, thread->pid); | 3003 | proc->pid, thread->pid); |
| 3004 | return_error_param = -EFAULT; | ||
| 2156 | return_error = BR_FAILED_REPLY; | 3005 | return_error = BR_FAILED_REPLY; |
| 3006 | return_error_line = __LINE__; | ||
| 2157 | goto err_copy_data_failed; | 3007 | goto err_copy_data_failed; |
| 2158 | } | 3008 | } |
| 2159 | /* Fixup buffer pointer to target proc address space */ | 3009 | /* Fixup buffer pointer to target proc address space */ |
| 2160 | bp->buffer = (uintptr_t)sg_bufp + | 3010 | bp->buffer = (uintptr_t)sg_bufp + |
| 2161 | target_proc->user_buffer_offset; | 3011 | binder_alloc_get_user_buffer_offset( |
| 3012 | &target_proc->alloc); | ||
| 2162 | sg_bufp += ALIGN(bp->length, sizeof(u64)); | 3013 | sg_bufp += ALIGN(bp->length, sizeof(u64)); |
| 2163 | 3014 | ||
| 2164 | ret = binder_fixup_parent(t, thread, bp, off_start, | 3015 | ret = binder_fixup_parent(t, thread, bp, off_start, |
| @@ -2167,6 +3018,8 @@ static void binder_transaction(struct binder_proc *proc, · 2 unmodified lines | |||
| 2167 | last_fixup_min_off); | 3018 | last_fixup_min_off); |
| 2168 | if (ret < 0) { | 3019 | if (ret < 0) { |
| 2169 | return_error = BR_FAILED_REPLY; | 3020 | return_error = BR_FAILED_REPLY; |
| 3021 | return_error_param = ret; | ||
| 3022 | return_error_line = __LINE__; | ||
| 2170 | goto err_translate_failed; | 3023 | goto err_translate_failed; |
| 2171 | } | 3024 | } |
| 2172 | last_fixup_obj = bp; | 3025 | last_fixup_obj = bp; |
| @@ -2176,38 +3029,60 @@ static void binder_transaction(struct binder_proc *proc, · 3 unmodified lines | |||
| 2176 | binder_user_error("%d:%d got transaction with invalid object type, %x\n", | 3029 | binder_user_error("%d:%d got transaction with invalid object type, %x\n", |
| 2177 | proc->pid, thread->pid, hdr->type); | 3030 | proc->pid, thread->pid, hdr->type); |
| 2178 | return_error = BR_FAILED_REPLY; | 3031 | return_error = BR_FAILED_REPLY; |
| 3032 | return_error_param = -EINVAL; | ||
| 3033 | return_error_line = __LINE__; | ||
| 2179 | goto err_bad_object_type; | 3034 | goto err_bad_object_type; |
| 2180 | } | 3035 | } |
| 2181 | } | 3036 | } |
| 3037 | tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE; | ||
| 3038 | binder_enqueue_work(proc, tcomplete, &thread->todo); | ||
| 3039 | t->work.type = BINDER_WORK_TRANSACTION; | ||
| 3040 | |||
| 2182 | if (reply) { | 3041 | if (reply) { |
| 3042 | binder_inner_proc_lock(target_proc); | ||
| 3043 | if (target_thread->is_dead) { | ||
| 3044 | binder_inner_proc_unlock(target_proc); | ||
| 3045 | goto err_dead_proc_or_thread; | ||
| 3046 | } | ||
| 2183 | BUG_ON(t->buffer->async_transaction != 0); | 3047 | BUG_ON(t->buffer->async_transaction != 0); |
| 2184 | binder_pop_transaction(target_thread, in_reply_to); | 3048 | binder_pop_transaction_ilocked(target_thread, in_reply_to); |
| 3049 | binder_enqueue_work_ilocked(&t->work, &target_thread->todo); | ||
| 3050 | binder_inner_proc_unlock(target_proc); | ||
| 3051 | wake_up_interruptible_sync(&target_thread->wait); | ||
| 3052 | binder_free_transaction(in_reply_to); | ||
| 2185 | } else if (!(t->flags & TF_ONE_WAY)) { | 3053 | } else if (!(t->flags & TF_ONE_WAY)) { |
| 2186 | BUG_ON(t->buffer->async_transaction != 0); | 3054 | BUG_ON(t->buffer->async_transaction != 0); |
| 3055 | binder_inner_proc_lock(proc); | ||
| 2187 | t->need_reply = 1; | 3056 | t->need_reply = 1; |
| 2188 | t->from_parent = thread->transaction_stack; | 3057 | t->from_parent = thread->transaction_stack; |
| 2189 | thread->transaction_stack = t; | 3058 | thread->transaction_stack = t; |
| 3059 | binder_inner_proc_unlock(proc); | ||
| 3060 | if (!binder_proc_transaction(t, target_proc, target_thread)) { | ||
| 3061 | binder_inner_proc_lock(proc); | ||
| 3062 | binder_pop_transaction_ilocked(thread, t); | ||
| 3063 | binder_inner_proc_unlock(proc); | ||
| 3064 | goto err_dead_proc_or_thread; | ||
| 3065 | } | ||
| 2190 | } else { | 3066 | } else { |
| 2191 | BUG_ON(target_node == NULL); | 3067 | BUG_ON(target_node == NULL); |
| 2192 | BUG_ON(t->buffer->async_transaction != 1); | 3068 | BUG_ON(t->buffer->async_transaction != 1); |
| 2193 | if (target_node->has_async_transaction) { | 3069 | if (!binder_proc_transaction(t, target_proc, NULL)) |
| 2194 | target_list = &target_node->async_todo; | 3070 | goto err_dead_proc_or_thread; |
| 2195 | target_wait = NULL; | ||
| 2196 | } else | ||
| 2197 | target_node->has_async_transaction = 1; | ||
| 2198 | } | ||
| 2199 | t->work.type = BINDER_WORK_TRANSACTION; | ||
| 2200 | list_add_tail(&t->work.entry, target_list); | ||
| 2201 | tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE; | ||
| 2202 | list_add_tail(&tcomplete->entry, &thread->todo); | ||
| 2203 | if (target_wait) { | ||
| 2204 | if (reply || !(t->flags & TF_ONE_WAY)) | ||
| 2205 | wake_up_interruptible_sync(target_wait); | ||
| 2206 | else | ||
| 2207 | wake_up_interruptible(target_wait); | ||
| 2208 | } | 3071 | } |
| 3072 | if (target_thread) | ||
| 3073 | binder_thread_dec_tmpref(target_thread); | ||
| 3074 | binder_proc_dec_tmpref(target_proc); | ||
| 3075 | /* | ||
| 3076 | * write barrier to synchronize with initialization | ||
| 3077 | * of log entry | ||
| 3078 | */ | ||
| 3079 | smp_wmb(); | ||
| 3080 | WRITE_ONCE(e->debug_id_done, t_debug_id); | ||
| 2209 | return; | 3081 | return; |
| 2210 | 3082 | ||
| 3083 | err_dead_proc_or_thread: | ||
| 3084 | return_error = BR_DEAD_REPLY; | ||
| 3085 | return_error_line = __LINE__; | ||
| 2211 | err_translate_failed: | 3086 | err_translate_failed: |
| 2212 | err_bad_object_type: | 3087 | err_bad_object_type: |
| 2213 | err_bad_offset: | 3088 | err_bad_offset: |
| @@ -2215,8 +3090,9 @@ err_bad_parent: · 1 unmodified line | |||
| 2215 | err_copy_data_failed: | 3090 | err_copy_data_failed: |
| 2216 | trace_binder_transaction_failed_buffer_release(t->buffer); | 3091 | trace_binder_transaction_failed_buffer_release(t->buffer); |
| 2217 | binder_transaction_buffer_release(target_proc, t->buffer, offp); | 3092 | binder_transaction_buffer_release(target_proc, t->buffer, offp); |
| 3093 | target_node = NULL; | ||
| 2218 | t->buffer->transaction = NULL; | 3094 | t->buffer->transaction = NULL; |
| 2219 | binder_free_buf(target_proc, t->buffer); | 3095 | binder_alloc_free_buf(&target_proc->alloc, t->buffer); |
| 2220 | err_binder_alloc_buf_failed: | 3096 | err_binder_alloc_buf_failed: |
| 2221 | kfree(tcomplete); | 3097 | kfree(tcomplete); |
| 2222 | binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); | 3098 | binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); |
| @@ -2229,24 +3105,49 @@ err_empty_call_stack: · 6 unmodified lines | |||
| 2229 | err_dead_binder: | 3105 | err_dead_binder: |
| 2230 | err_invalid_target_handle: | 3106 | err_invalid_target_handle: |
| 2231 | err_no_context_mgr_node: | 3107 | err_no_context_mgr_node: |
| 3108 | if (target_thread) | ||
| 3109 | binder_thread_dec_tmpref(target_thread); | ||
| 3110 | if (target_proc) | ||
| 3111 | binder_proc_dec_tmpref(target_proc); | ||
| 3112 | if (target_node) | ||
| 3113 | binder_dec_node(target_node, 1, 0); | ||
| 3114 | |||
| 2232 | binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, | 3115 | binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, |
| 2233 | "%d:%d transaction failed %d, size %lld-%lld\n", | 3116 | "%d:%d transaction failed %d/%d, size %lld-%lld line %d\n", |
| 2234 | proc->pid, thread->pid, return_error, | 3117 | proc->pid, thread->pid, return_error, return_error_param, |
| 2235 | (u64)tr->data_size, (u64)tr->offsets_size); | 3118 | (u64)tr->data_size, (u64)tr->offsets_size, |
| 3119 | return_error_line); | ||
| 2236 | 3120 | ||
| 2237 | { | 3121 | { |
| 2238 | struct binder_transaction_log_entry *fe; | 3122 | struct binder_transaction_log_entry *fe; |
| 2239 | 3123 | ||
| 3124 | e->return_error = return_error; | ||
| 3125 | e->return_error_param = return_error_param; | ||
| 3126 | e->return_error_line = return_error_line; | ||
| 2240 | fe = binder_transaction_log_add(&binder_transaction_log_failed); | 3127 | fe = binder_transaction_log_add(&binder_transaction_log_failed); |
| 2241 | *fe = *e; | 3128 | *fe = *e; |
| 3129 | /* | ||
| 3130 | * write barrier to synchronize with initialization | ||
| 3131 | * of log entry | ||
| 3132 | */ | ||
| 3133 | smp_wmb(); | ||
| 3134 | WRITE_ONCE(e->debug_id_done, t_debug_id); | ||
| 3135 | WRITE_ONCE(fe->debug_id_done, t_debug_id); | ||
| 2242 | } | 3136 | } |
| 2243 | 3137 | ||
| 2244 | BUG_ON(thread->return_error != BR_OK); | 3138 | BUG_ON(thread->return_error.cmd != BR_OK); |
| 2245 | if (in_reply_to) { | 3139 | if (in_reply_to) { |
| 2246 | thread->return_error = BR_TRANSACTION_COMPLETE; | 3140 | thread->return_error.cmd = BR_TRANSACTION_COMPLETE; |
| 3141 | binder_enqueue_work(thread->proc, | ||
| 3142 | &thread->return_error.work, | ||
| 3143 | &thread->todo); | ||
| 2247 | binder_send_failed_reply(in_reply_to, return_error); | 3144 | binder_send_failed_reply(in_reply_to, return_error); |
| 2248 | } else | 3145 | } else { |
| 2249 | thread->return_error = return_error; | 3146 | thread->return_error.cmd = return_error; |
| 3147 | binder_enqueue_work(thread->proc, | ||
| 3148 | &thread->return_error.work, | ||
| 3149 | &thread->todo); | ||
| 3150 | } | ||
| 2250 | } | 3151 | } |
| 2251 | 3152 | ||
| 2252 | static int binder_thread_write(struct binder_proc *proc, | 3153 | static int binder_thread_write(struct binder_proc *proc, |
| @@ -2260,15 +3161,17 @@ static int binder_thread_write(struct binder_proc *proc, · 7 unmodified lines | |||
| 2260 | void __user *ptr = buffer + *consumed; | 3161 | void __user *ptr = buffer + *consumed; |
| 2261 | void __user *end = buffer + size; | 3162 | void __user *end = buffer + size; |
| 2262 | 3163 | ||
| 2263 | while (ptr < end && thread->return_error == BR_OK) { | 3164 | while (ptr < end && thread->return_error.cmd == BR_OK) { |
| 3165 | int ret; | ||
| 3166 | |||
| 2264 | if (get_user(cmd, (uint32_t __user *)ptr)) | 3167 | if (get_user(cmd, (uint32_t __user *)ptr)) |
| 2265 | return -EFAULT; | 3168 | return -EFAULT; |
| 2266 | ptr += sizeof(uint32_t); | 3169 | ptr += sizeof(uint32_t); |
| 2267 | trace_binder_command(cmd); | 3170 | trace_binder_command(cmd); |
| 2268 | if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) { | 3171 | if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) { |
| 2269 | binder_stats.bc[_IOC_NR(cmd)]++; | 3172 | atomic_inc(&binder_stats.bc[_IOC_NR(cmd)]); |
| 2270 | proc->stats.bc[_IOC_NR(cmd)]++; | 3173 | atomic_inc(&proc->stats.bc[_IOC_NR(cmd)]); |
| 2271 | thread->stats.bc[_IOC_NR(cmd)]++; | 3174 | atomic_inc(&thread->stats.bc[_IOC_NR(cmd)]); |
| 2272 | } | 3175 | } |
| 2273 | switch (cmd) { | 3176 | switch (cmd) { |
| 2274 | case BC_INCREFS: | 3177 | case BC_INCREFS: |
| @@ -2276,53 +3179,61 @@ static int binder_thread_write(struct binder_proc *proc, · 1 unmodified line | |||
| 2276 | case BC_RELEASE: | 3179 | case BC_RELEASE: |
| 2277 | case BC_DECREFS: { | 3180 | case BC_DECREFS: { |
| 2278 | uint32_t target; | 3181 | uint32_t target; |
| 2279 | struct binder_ref *ref; | ||
| 2280 | const char *debug_string; | 3182 | const char *debug_string; |
| 3183 | bool strong = cmd == BC_ACQUIRE || cmd == BC_RELEASE; | ||
| 3184 | bool increment = cmd == BC_INCREFS || cmd == BC_ACQUIRE; | ||
| 3185 | struct binder_ref_data rdata; | ||
| 2281 | 3186 | ||
| 2282 | if (get_user(target, (uint32_t __user *)ptr)) | 3187 | if (get_user(target, (uint32_t __user *)ptr)) |
| 2283 | return -EFAULT; | 3188 | return -EFAULT; |
| 3189 | |||
| 2284 | ptr += sizeof(uint32_t); | 3190 | ptr += sizeof(uint32_t); |
| 2285 | if (target == 0 && context->binder_context_mgr_node && | 3191 | ret = -1; |
| 2286 | (cmd == BC_INCREFS || cmd == BC_ACQUIRE)) { | 3192 | if (increment && !target) { |
| 2287 | ref = binder_get_ref_for_node(proc, | 3193 | struct binder_node *ctx_mgr_node; |
| 2288 | context->binder_context_mgr_node); | 3194 | mutex_lock(&context->context_mgr_node_lock); |
| 2289 | if (ref->desc != target) { | 3195 | ctx_mgr_node = context->binder_context_mgr_node; |
| 2290 | binder_user_error("%d:%d tried to acquire reference to desc 0, got %d instead\n", | 3196 | if (ctx_mgr_node) |
| 2291 | proc->pid, thread->pid, | 3197 | ret = binder_inc_ref_for_node( |
| 2292 | ref->desc); | 3198 | proc, ctx_mgr_node, |
| 2293 | } | 3199 | strong, NULL, &rdata); |
| 2294 | } else | 3200 | mutex_unlock(&context->context_mgr_node_lock); |
| 2295 | ref = binder_get_ref(proc, target, | 3201 | } |
| 2296 | cmd == BC_ACQUIRE || | 3202 | if (ret) |
| 2297 | cmd == BC_RELEASE); | 3203 | ret = binder_update_ref_for_handle( |
| 2298 | if (ref == NULL) { | 3204 | proc, target, increment, strong, |
| 2299 | binder_user_error("%d:%d refcount change on invalid ref %d\n", | 3205 | &rdata); |
| 2300 | proc->pid, thread->pid, target); | 3206 | if (!ret && rdata.desc != target) { |
| 2301 | break; | 3207 | binder_user_error("%d:%d tried to acquire reference to desc %d, got %d instead\n", |
| 3208 | proc->pid, thread->pid, | ||
| 3209 | target, rdata.desc); | ||
| 2302 | } | 3210 | } |
| 2303 | switch (cmd) { | 3211 | switch (cmd) { |
| 2304 | case BC_INCREFS: | 3212 | case BC_INCREFS: |
| 2305 | debug_string = "IncRefs"; | 3213 | debug_string = "IncRefs"; |
| 2306 | binder_inc_ref(ref, 0, NULL); | ||
| 2307 | break; | 3214 | break; |
| 2308 | case BC_ACQUIRE: | 3215 | case BC_ACQUIRE: |
| 2309 | debug_string = "Acquire"; | 3216 | debug_string = "Acquire"; |
| 2310 | binder_inc_ref(ref, 1, NULL); | ||
| 2311 | break; | 3217 | break; |
| 2312 | case BC_RELEASE: | 3218 | case BC_RELEASE: |
| 2313 | debug_string = "Release"; | 3219 | debug_string = "Release"; |
| 2314 | binder_dec_ref(ref, 1); | ||
| 2315 | break; | 3220 | break; |
| 2316 | case BC_DECREFS: | 3221 | case BC_DECREFS: |
| 2317 | default: | 3222 | default: |
| 2318 | debug_string = "DecRefs"; | 3223 | debug_string = "DecRefs"; |
| 2319 | binder_dec_ref(ref, 0); | 3224 | break; |
| 3225 | } | ||
| 3226 | if (ret) { | ||
| 3227 | binder_user_error("%d:%d %s %d refcount change on invalid ref %d ret %d\n", | ||
| 3228 | proc->pid, thread->pid, debug_string, | ||
| 3229 | strong, target, ret); | ||
| 2320 | break; | 3230 | break; |
| 2321 | } | 3231 | } |
| 2322 | binder_debug(BINDER_DEBUG_USER_REFS, | 3232 | binder_debug(BINDER_DEBUG_USER_REFS, |
| 2323 | "%d:%d %s ref %d desc %d s %d w %d for node %d\n", | 3233 | "%d:%d %s ref %d desc %d s %d w %d\n", |
| 2324 | proc->pid, thread->pid, debug_string, ref->debug_id, | 3234 | proc->pid, thread->pid, debug_string, |
| 2325 | ref->desc, ref->strong, ref->weak, ref->node->debug_id); | 3235 | rdata.debug_id, rdata.desc, rdata.strong, |
| 3236 | rdata.weak); | ||
| 2326 | break; | 3237 | break; |
| 2327 | } | 3238 | } |
| 2328 | case BC_INCREFS_DONE: | 3239 | case BC_INCREFS_DONE: |
| @@ -2330,6 +3241,7 @@ static int binder_thread_write(struct binder_proc *proc, · 1 unmodified line | |||
| 2330 | binder_uintptr_t node_ptr; | 3241 | binder_uintptr_t node_ptr; |
| 2331 | binder_uintptr_t cookie; | 3242 | binder_uintptr_t cookie; |
| 2332 | struct binder_node *node; | 3243 | struct binder_node *node; |
| 3244 | bool free_node; | ||
| 2333 | 3245 | ||
| 2334 | if (get_user(node_ptr, (binder_uintptr_t __user *)ptr)) | 3246 | if (get_user(node_ptr, (binder_uintptr_t __user *)ptr)) |
| 2335 | return -EFAULT; | 3247 | return -EFAULT; |
| @@ -2354,13 +3266,17 @@ static int binder_thread_write(struct binder_proc *proc, · 18 unmodified lines | |||
| 2354 | "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE", | 3266 | "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE", |
| 2355 | (u64)node_ptr, node->debug_id, | 3267 | (u64)node_ptr, node->debug_id, |
| 2356 | (u64)cookie, (u64)node->cookie); | 3268 | (u64)cookie, (u64)node->cookie); |
| 3269 | binder_put_node(node); | ||
| 2357 | break; | 3270 | break; |
| 2358 | } | 3271 | } |
| 3272 | binder_node_inner_lock(node); | ||
| 2359 | if (cmd == BC_ACQUIRE_DONE) { | 3273 | if (cmd == BC_ACQUIRE_DONE) { |
| 2360 | if (node->pending_strong_ref == 0) { | 3274 | if (node->pending_strong_ref == 0) { |
| 2361 | binder_user_error("%d:%d BC_ACQUIRE_DONE node %d has no pending acquire request\n", | 3275 | binder_user_error("%d:%d BC_ACQUIRE_DONE node %d has no pending acquire request\n", |
| 2362 | proc->pid, thread->pid, | 3276 | proc->pid, thread->pid, |
| 2363 | node->debug_id); | 3277 | node->debug_id); |
| 3278 | binder_node_inner_unlock(node); | ||
| 3279 | binder_put_node(node); | ||
| 2364 | break; | 3280 | break; |
| 2365 | } | 3281 | } |
| 2366 | node->pending_strong_ref = 0; | 3282 | node->pending_strong_ref = 0; |
| @@ -2369,16 +3285,23 @@ static int binder_thread_write(struct binder_proc *proc, · 2 unmodified lines | |||
| 2369 | binder_user_error("%d:%d BC_INCREFS_DONE node %d has no pending increfs request\n", | 3285 | binder_user_error("%d:%d BC_INCREFS_DONE node %d has no pending increfs request\n", |
| 2370 | proc->pid, thread->pid, | 3286 | proc->pid, thread->pid, |
| 2371 | node->debug_id); | 3287 | node->debug_id); |
| 3288 | binder_node_inner_unlock(node); | ||
| 3289 | binder_put_node(node); | ||
| 2372 | break; | 3290 | break; |
| 2373 | } | 3291 | } |
| 2374 | node->pending_weak_ref = 0; | 3292 | node->pending_weak_ref = 0; |
| 2375 | } | 3293 | } |
| 2376 | binder_dec_node(node, cmd == BC_ACQUIRE_DONE, 0); | 3294 | free_node = binder_dec_node_nilocked(node, |
| 3295 | cmd == BC_ACQUIRE_DONE, 0); | ||
| 3296 | WARN_ON(free_node); | ||
| 2377 | binder_debug(BINDER_DEBUG_USER_REFS, | 3297 | binder_debug(BINDER_DEBUG_USER_REFS, |
| 2378 | "%d:%d %s node %d ls %d lw %d\n", | 3298 | "%d:%d %s node %d ls %d lw %d tr %d\n", |
| 2379 | proc->pid, thread->pid, | 3299 | proc->pid, thread->pid, |
| 2380 | cmd == BC_INCREFS_DONE ? "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE", | 3300 | cmd == BC_INCREFS_DONE ? "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE", |
| 2381 | node->debug_id, node->local_strong_refs, node->local_weak_refs); | 3301 | node->debug_id, node->local_strong_refs, |
| 3302 | node->local_weak_refs, node->tmp_refs); | ||
| 3303 | binder_node_inner_unlock(node); | ||
| 3304 | binder_put_node(node); | ||
| 2382 | break; | 3305 | break; |
| 2383 | } | 3306 | } |
| 2384 | case BC_ATTEMPT_ACQUIRE: | 3307 | case BC_ATTEMPT_ACQUIRE: |
| @@ -2396,7 +3319,8 @@ static int binder_thread_write(struct binder_proc *proc, · 11 unmodified lines | |||
| 2396 | return -EFAULT; | 3319 | return -EFAULT; |
| 2397 | ptr += sizeof(binder_uintptr_t); | 3320 | ptr += sizeof(binder_uintptr_t); |
| 2398 | 3321 | ||
| 2399 | buffer = binder_buffer_lookup(proc, data_ptr); | 3322 | buffer = binder_alloc_prepare_to_free(&proc->alloc, |
| 3323 | data_ptr); | ||
| 2400 | if (buffer == NULL) { | 3324 | if (buffer == NULL) { |
| 2401 | binder_user_error("%d:%d BC_FREE_BUFFER u%016llx no match\n", | 3325 | binder_user_error("%d:%d BC_FREE_BUFFER u%016llx no match\n", |
| 2402 | proc->pid, thread->pid, (u64)data_ptr); | 3326 | proc->pid, thread->pid, (u64)data_ptr); |
| @@ -2418,15 +3342,27 @@ static int binder_thread_write(struct binder_proc *proc, · 15 unmodified lines | |||
| 2418 | buffer->transaction = NULL; | 3342 | buffer->transaction = NULL; |
| 2419 | } | 3343 | } |
| 2420 | if (buffer->async_transaction && buffer->target_node) { | 3344 | if (buffer->async_transaction && buffer->target_node) { |
| 2421 | BUG_ON(!buffer->target_node->has_async_transaction); | 3345 | struct binder_node *buf_node; |
| 2422 | if (list_empty(&buffer->target_node->async_todo)) | 3346 | struct binder_work *w; |
| 2423 | buffer->target_node->has_async_transaction = 0; | 3347 | |
| 2424 | else | 3348 | buf_node = buffer->target_node; |
| 2425 | list_move_tail(buffer->target_node->async_todo.next, &thread->todo); | 3349 | binder_node_inner_lock(buf_node); |
| 3350 | BUG_ON(!buf_node->has_async_transaction); | ||
| 3351 | BUG_ON(buf_node->proc != proc); | ||
| 3352 | w = binder_dequeue_work_head_ilocked( | ||
| 3353 | &buf_node->async_todo); | ||
| 3354 | if (!w) { | ||
| 3355 | buf_node->has_async_transaction = 0; | ||
| 3356 | } else { | ||
| 3357 | binder_enqueue_work_ilocked( | ||
| 3358 | w, &proc->todo); | ||
| 3359 | binder_wakeup_proc_ilocked(proc); | ||
| 3360 | } | ||
| 3361 | binder_node_inner_unlock(buf_node); | ||
| 2426 | } | 3362 | } |
| 2427 | trace_binder_transaction_buffer_release(buffer); | 3363 | trace_binder_transaction_buffer_release(buffer); |
| 2428 | binder_transaction_buffer_release(proc, buffer, NULL); | 3364 | binder_transaction_buffer_release(proc, buffer, NULL); |
| 2429 | binder_free_buf(proc, buffer); | 3365 | binder_alloc_free_buf(&proc->alloc, buffer); |
| 2430 | break; | 3366 | break; |
| 2431 | } | 3367 | } |
| 2432 | 3368 | ||
| @@ -2457,6 +3393,7 @@ static int binder_thread_write(struct binder_proc *proc, · 24 unmodified lines | |||
| 2457 | binder_debug(BINDER_DEBUG_THREADS, | 3393 | binder_debug(BINDER_DEBUG_THREADS, |
| 2458 | "%d:%d BC_REGISTER_LOOPER\n", | 3394 | "%d:%d BC_REGISTER_LOOPER\n", |
| 2459 | proc->pid, thread->pid); | 3395 | proc->pid, thread->pid); |
| 3396 | binder_inner_proc_lock(proc); | ||
| 2460 | if (thread->looper & BINDER_LOOPER_STATE_ENTERED) { | 3397 | if (thread->looper & BINDER_LOOPER_STATE_ENTERED) { |
| 2461 | thread->looper |= BINDER_LOOPER_STATE_INVALID; | 3398 | thread->looper |= BINDER_LOOPER_STATE_INVALID; |
| 2462 | binder_user_error("%d:%d ERROR: BC_REGISTER_LOOPER called after BC_ENTER_LOOPER\n", | 3399 | binder_user_error("%d:%d ERROR: BC_REGISTER_LOOPER called after BC_ENTER_LOOPER\n", |
| @@ -2470,6 +3407,7 @@ static int binder_thread_write(struct binder_proc *proc, · 7 unmodified lines | |||
| 2470 | proc->requested_threads_started++; | 3407 | proc->requested_threads_started++; |
| 2471 | } | 3408 | } |
| 2472 | thread->looper |= BINDER_LOOPER_STATE_REGISTERED; | 3409 | thread->looper |= BINDER_LOOPER_STATE_REGISTERED; |
| 3410 | binder_inner_proc_unlock(proc); | ||
| 2473 | break; | 3411 | break; |
| 2474 | case BC_ENTER_LOOPER: | 3412 | case BC_ENTER_LOOPER: |
| 2475 | binder_debug(BINDER_DEBUG_THREADS, | 3413 | binder_debug(BINDER_DEBUG_THREADS, |
| @@ -2494,7 +3432,7 @@ static int binder_thread_write(struct binder_proc *proc, · 18 unmodified lines | |||
| 2494 | uint32_t target; | 3432 | uint32_t target; |
| 2495 | binder_uintptr_t cookie; | 3433 | binder_uintptr_t cookie; |
| 2496 | struct binder_ref *ref; | 3434 | struct binder_ref *ref; |
| 2497 | struct binder_ref_death *death; | 3435 | struct binder_ref_death *death = NULL; |
| 2498 | 3436 | ||
| 2499 | if (get_user(target, (uint32_t __user *)ptr)) | 3437 | if (get_user(target, (uint32_t __user *)ptr)) |
| 2500 | return -EFAULT; | 3438 | return -EFAULT; |
| @@ -2502,7 +3440,29 @@ static int binder_thread_write(struct binder_proc *proc, · 1 unmodified line | |||
| 2502 | if (get_user(cookie, (binder_uintptr_t __user *)ptr)) | 3440 | if (get_user(cookie, (binder_uintptr_t __user *)ptr)) |
| 2503 | return -EFAULT; | 3441 | return -EFAULT; |
| 2504 | ptr += sizeof(binder_uintptr_t); | 3442 | ptr += sizeof(binder_uintptr_t); |
| 2505 | ref = binder_get_ref(proc, target, false); | 3443 | if (cmd == BC_REQUEST_DEATH_NOTIFICATION) { |
| 3444 | /* | ||
| 3445 | * Allocate memory for death notification | ||
| 3446 | * before taking lock | ||
| 3447 | */ | ||
| 3448 | death = kzalloc(sizeof(*death), GFP_KERNEL); | ||
| 3449 | if (death == NULL) { | ||
| 3450 | WARN_ON(thread->return_error.cmd != | ||
| 3451 | BR_OK); | ||
| 3452 | thread->return_error.cmd = BR_ERROR; | ||
| 3453 | binder_enqueue_work( | ||
| 3454 | thread->proc, | ||
| 3455 | &thread->return_error.work, | ||
| 3456 | &thread->todo); | ||
| 3457 | binder_debug( | ||
| 3458 | BINDER_DEBUG_FAILED_TRANSACTION, | ||
| 3459 | "%d:%d BC_REQUEST_DEATH_NOTIFICATION failed\n", | ||
| 3460 | proc->pid, thread->pid); | ||
| 3461 | break; | ||
| 3462 | } | ||
| 3463 | } | ||
| 3464 | binder_proc_lock(proc); | ||
| 3465 | ref = binder_get_ref_olocked(proc, target, false); | ||
| 2506 | if (ref == NULL) { | 3466 | if (ref == NULL) { |
| 2507 | binder_user_error("%d:%d %s invalid ref %d\n", | 3467 | binder_user_error("%d:%d %s invalid ref %d\n", |
| 2508 | proc->pid, thread->pid, | 3468 | proc->pid, thread->pid, |
| @@ -2510,6 +3470,8 @@ static int binder_thread_write(struct binder_proc *proc, · 1 unmodified line | |||
| 2510 | "BC_REQUEST_DEATH_NOTIFICATION" : | 3470 | "BC_REQUEST_DEATH_NOTIFICATION" : |
| 2511 | "BC_CLEAR_DEATH_NOTIFICATION", | 3471 | "BC_CLEAR_DEATH_NOTIFICATION", |
| 2512 | target); | 3472 | target); |
| 3473 | binder_proc_unlock(proc); | ||
| 3474 | kfree(death); | ||
| 2513 | break; | 3475 | break; |
| 2514 | } | 3476 | } |
| 2515 | 3477 | ||
| @@ -2519,21 +3481,18 @@ static int binder_thread_write(struct binder_proc *proc, · 3 unmodified lines | |||
| 2519 | cmd == BC_REQUEST_DEATH_NOTIFICATION ? | 3481 | cmd == BC_REQUEST_DEATH_NOTIFICATION ? |
| 2520 | "BC_REQUEST_DEATH_NOTIFICATION" : | 3482 | "BC_REQUEST_DEATH_NOTIFICATION" : |
| 2521 | "BC_CLEAR_DEATH_NOTIFICATION", | 3483 | "BC_CLEAR_DEATH_NOTIFICATION", |
| 2522 | (u64)cookie, ref->debug_id, ref->desc, | 3484 | (u64)cookie, ref->data.debug_id, |
| 2523 | ref->strong, ref->weak, ref->node->debug_id); | 3485 | ref->data.desc, ref->data.strong, |
| 3486 | ref->data.weak, ref->node->debug_id); | ||
| 2524 | 3487 | ||
| 3488 | binder_node_lock(ref->node); | ||
| 2525 | if (cmd == BC_REQUEST_DEATH_NOTIFICATION) { | 3489 | if (cmd == BC_REQUEST_DEATH_NOTIFICATION) { |
| 2526 | if (ref->death) { | 3490 | if (ref->death) { |
| 2527 | binder_user_error("%d:%d BC_REQUEST_DEATH_NOTIFICATION death notification already set\n", | 3491 | binder_user_error("%d:%d BC_REQUEST_DEATH_NOTIFICATION death notification already set\n", |
| 2528 | proc->pid, thread->pid); | 3492 | proc->pid, thread->pid); |
| 2529 | break; | 3493 | binder_node_unlock(ref->node); |
| 2530 | } | 3494 | binder_proc_unlock(proc); |
| 2531 | death = kzalloc(sizeof(*death), GFP_KERNEL); | 3495 | kfree(death); |
| 2532 | if (death == NULL) { | ||
| 2533 | thread->return_error = BR_ERROR; | ||
| 2534 | binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, | ||
| 2535 | "%d:%d BC_REQUEST_DEATH_NOTIFICATION failed\n", | ||
| 2536 | proc->pid, thread->pid); | ||
| 2537 | break; | 3496 | break; |
| 2538 | } | 3497 | } |
| 2539 | binder_stats_created(BINDER_STAT_DEATH); | 3498 | binder_stats_created(BINDER_STAT_DEATH); |
| @@ -2542,17 +3501,19 @@ static int binder_thread_write(struct binder_proc *proc, · 2 unmodified lines | |||
| 2542 | ref->death = death; | 3501 | ref->death = death; |
| 2543 | if (ref->node->proc == NULL) { | 3502 | if (ref->node->proc == NULL) { |
| 2544 | ref->death->work.type = BINDER_WORK_DEAD_BINDER; | 3503 | ref->death->work.type = BINDER_WORK_DEAD_BINDER; |
| 2545 | if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) { | 3504 | |
| 2546 | list_add_tail(&ref->death->work.entry, &thread->todo); | 3505 | binder_inner_proc_lock(proc); |
| 2547 | } else { | 3506 | binder_enqueue_work_ilocked( |
| 2548 | list_add_tail(&ref->death->work.entry, &proc->todo); | 3507 | &ref->death->work, &proc->todo); |
| 2549 | wake_up_interruptible(&proc->wait); | 3508 | binder_wakeup_proc_ilocked(proc); |
| 2550 | } | 3509 | binder_inner_proc_unlock(proc); |
| 2551 | } | 3510 | } |
| 2552 | } else { | 3511 | } else { |
| 2553 | if (ref->death == NULL) { | 3512 | if (ref->death == NULL) { |
| 2554 | binder_user_error("%d:%d BC_CLEAR_DEATH_NOTIFICATION death notification not active\n", | 3513 | binder_user_error("%d:%d BC_CLEAR_DEATH_NOTIFICATION death notification not active\n", |
| 2555 | proc->pid, thread->pid); | 3514 | proc->pid, thread->pid); |
| 3515 | binder_node_unlock(ref->node); | ||
| 3516 | binder_proc_unlock(proc); | ||
| 2556 | break; | 3517 | break; |
| 2557 | } | 3518 | } |
| 2558 | death = ref->death; | 3519 | death = ref->death; |
| @@ -2561,22 +3522,35 @@ static int binder_thread_write(struct binder_proc *proc, · 2 unmodified lines | |||
| 2561 | proc->pid, thread->pid, | 3522 | proc->pid, thread->pid, |
| 2562 | (u64)death->cookie, | 3523 | (u64)death->cookie, |
| 2563 | (u64)cookie); | 3524 | (u64)cookie); |
| 3525 | binder_node_unlock(ref->node); | ||
| 3526 | binder_proc_unlock(proc); | ||
| 2564 | break; | 3527 | break; |
| 2565 | } | 3528 | } |
| 2566 | ref->death = NULL; | 3529 | ref->death = NULL; |
| 3530 | binder_inner_proc_lock(proc); | ||
| 2567 | if (list_empty(&death->work.entry)) { | 3531 | if (list_empty(&death->work.entry)) { |
| 2568 | death->work.type = BINDER_WORK_CLEAR_DEATH_NOTIFICATION; | 3532 | death->work.type = BINDER_WORK_CLEAR_DEATH_NOTIFICATION; |
| 2569 | if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) { | 3533 | if (thread->looper & |
| 2570 | list_add_tail(&death->work.entry, &thread->todo); | 3534 | (BINDER_LOOPER_STATE_REGISTERED | |
| 2571 | } else { | 3535 | BINDER_LOOPER_STATE_ENTERED)) |
| 2572 | list_add_tail(&death->work.entry, &proc->todo); | 3536 | binder_enqueue_work_ilocked( |
| 2573 | wake_up_interruptible(&proc->wait); | 3537 | &death->work, |
| 3538 | &thread->todo); | ||
| 3539 | else { | ||
| 3540 | binder_enqueue_work_ilocked( | ||
| 3541 | &death->work, | ||
| 3542 | &proc->todo); | ||
| 3543 | binder_wakeup_proc_ilocked( | ||
| 3544 | proc); | ||
| 2574 | } | 3545 | } |
| 2575 | } else { | 3546 | } else { |
| 2576 | BUG_ON(death->work.type != BINDER_WORK_DEAD_BINDER); | 3547 | BUG_ON(death->work.type != BINDER_WORK_DEAD_BINDER); |
| 2577 | death->work.type = BINDER_WORK_DEAD_BINDER_AND_CLEAR; | 3548 | death->work.type = BINDER_WORK_DEAD_BINDER_AND_CLEAR; |
| 2578 | } | 3549 | } |
| 3550 | binder_inner_proc_unlock(proc); | ||
| 2579 | } | 3551 | } |
| 3552 | binder_node_unlock(ref->node); | ||
| 3553 | binder_proc_unlock(proc); | ||
| 2580 | } break; | 3554 | } break; |
| 2581 | case BC_DEAD_BINDER_DONE: { | 3555 | case BC_DEAD_BINDER_DONE: { |
| 2582 | struct binder_work *w; | 3556 | struct binder_work *w; |
| @@ -2587,8 +3561,13 @@ static int binder_thread_write(struct binder_proc *proc, · 4 unmodified lines | |||
| 2587 | return -EFAULT; | 3561 | return -EFAULT; |
| 2588 | 3562 | ||
| 2589 | ptr += sizeof(cookie); | 3563 | ptr += sizeof(cookie); |
| 2590 | list_for_each_entry(w, &proc->delivered_death, entry) { | 3564 | binder_inner_proc_lock(proc); |
| 2591 | struct binder_ref_death *tmp_death = container_of(w, struct binder_ref_death, work); | 3565 | list_for_each_entry(w, &proc->delivered_death, |
| 3566 | entry) { | ||
| 3567 | struct binder_ref_death *tmp_death = | ||
| 3568 | container_of(w, | ||
| 3569 | struct binder_ref_death, | ||
| 3570 | work); | ||
| 2592 | 3571 | ||
| 2593 | if (tmp_death->cookie == cookie) { | 3572 | if (tmp_death->cookie == cookie) { |
| 2594 | death = tmp_death; | 3573 | death = tmp_death; |
| @@ -2602,19 +3581,25 @@ static int binder_thread_write(struct binder_proc *proc, · 7 unmodified lines | |||
| 2602 | if (death == NULL) { | 3581 | if (death == NULL) { |
| 2603 | binder_user_error("%d:%d BC_DEAD_BINDER_DONE %016llx not found\n", | 3582 | binder_user_error("%d:%d BC_DEAD_BINDER_DONE %016llx not found\n", |
| 2604 | proc->pid, thread->pid, (u64)cookie); | 3583 | proc->pid, thread->pid, (u64)cookie); |
| 3584 | binder_inner_proc_unlock(proc); | ||
| 2605 | break; | 3585 | break; |
| 2606 | } | 3586 | } |
| 2607 | 3587 | binder_dequeue_work_ilocked(&death->work); | |
| 2608 | list_del_init(&death->work.entry); | ||
| 2609 | if (death->work.type == BINDER_WORK_DEAD_BINDER_AND_CLEAR) { | 3588 | if (death->work.type == BINDER_WORK_DEAD_BINDER_AND_CLEAR) { |
| 2610 | death->work.type = BINDER_WORK_CLEAR_DEATH_NOTIFICATION; | 3589 | death->work.type = BINDER_WORK_CLEAR_DEATH_NOTIFICATION; |
| 2611 | if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) { | 3590 | if (thread->looper & |
| 2612 | list_add_tail(&death->work.entry, &thread->todo); | 3591 | (BINDER_LOOPER_STATE_REGISTERED | |
| 2613 | } else { | 3592 | BINDER_LOOPER_STATE_ENTERED)) |
| 2614 | list_add_tail(&death->work.entry, &proc->todo); | 3593 | binder_enqueue_work_ilocked( |
| 2615 | wake_up_interruptible(&proc->wait); | 3594 | &death->work, &thread->todo); |
| 3595 | else { | ||
| 3596 | binder_enqueue_work_ilocked( | ||
| 3597 | &death->work, | ||
| 3598 | &proc->todo); | ||
| 3599 | binder_wakeup_proc_ilocked(proc); | ||
| 2616 | } | 3600 | } |
| 2617 | } | 3601 | } |
| 3602 | binder_inner_proc_unlock(proc); | ||
| 2618 | } break; | 3603 | } break; |
| 2619 | 3604 | ||
| 2620 | default: | 3605 | default: |
| @@ -2632,23 +3617,79 @@ static void binder_stat_br(struct binder_proc *proc, · 11 unmodified lines | |||
| 2632 | { | 3617 | { |
| 2633 | trace_binder_return(cmd); | 3618 | trace_binder_return(cmd); |
| 2634 | if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.br)) { | 3619 | if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.br)) { |
| 2635 | binder_stats.br[_IOC_NR(cmd)]++; | 3620 | atomic_inc(&binder_stats.br[_IOC_NR(cmd)]); |
| 2636 | proc->stats.br[_IOC_NR(cmd)]++; | 3621 | atomic_inc(&proc->stats.br[_IOC_NR(cmd)]); |
| 2637 | thread->stats.br[_IOC_NR(cmd)]++; | 3622 | atomic_inc(&thread->stats.br[_IOC_NR(cmd)]); |
| 2638 | } | 3623 | } |
| 2639 | } | 3624 | } |
| 2640 | 3625 | ||
| 2641 | static int binder_has_proc_work(struct binder_proc *proc, | 3626 | static int binder_has_thread_work(struct binder_thread *thread) |
| 2642 | struct binder_thread *thread) | 3627 | { |
| 3628 | return !binder_worklist_empty(thread->proc, &thread->todo) || | ||
| 3629 | thread->looper_need_return; | ||
| 3630 | } | ||
| 3631 | |||
| 3632 | static int binder_put_node_cmd(struct binder_proc *proc, | ||
| 3633 | struct binder_thread *thread, | ||
| 3634 | void __user **ptrp, | ||
| 3635 | binder_uintptr_t node_ptr, | ||
| 3636 | binder_uintptr_t node_cookie, | ||
| 3637 | int node_debug_id, | ||
| 3638 | uint32_t cmd, const char *cmd_name) | ||
| 2643 | { | 3639 | { |
| 2644 | return !list_empty(&proc->todo) || | 3640 | void __user *ptr = *ptrp; |
| 2645 | (thread->looper & BINDER_LOOPER_STATE_NEED_RETURN); | 3641 | |
| 3642 | if (put_user(cmd, (uint32_t __user *)ptr)) | ||
| 3643 | return -EFAULT; | ||
| 3644 | ptr += sizeof(uint32_t); | ||
| 3645 | |||
| 3646 | if (put_user(node_ptr, (binder_uintptr_t __user *)ptr)) | ||
| 3647 | return -EFAULT; | ||
| 3648 | ptr += sizeof(binder_uintptr_t); | ||
| 3649 | |||
| 3650 | if (put_user(node_cookie, (binder_uintptr_t __user *)ptr)) | ||
| 3651 | return -EFAULT; | ||
| 3652 | ptr += sizeof(binder_uintptr_t); | ||
| 3653 | |||
| 3654 | binder_stat_br(proc, thread, cmd); | ||
| 3655 | binder_debug(BINDER_DEBUG_USER_REFS, "%d:%d %s %d u%016llx c%016llx\n", | ||
| 3656 | proc->pid, thread->pid, cmd_name, node_debug_id, | ||
| 3657 | (u64)node_ptr, (u64)node_cookie); | ||
| 3658 | |||
| 3659 | *ptrp = ptr; | ||
| 3660 | return 0; | ||
| 2646 | } | 3661 | } |
| 2647 | 3662 | ||
| 2648 | static int binder_has_thread_work(struct binder_thread *thread) | 3663 | static int binder_wait_for_work(struct binder_thread *thread, |
| 3664 | bool do_proc_work) | ||
| 2649 | { | 3665 | { |
| 2650 | return !list_empty(&thread->todo) || thread->return_error != BR_OK || | 3666 | DEFINE_WAIT(wait); |
| 2651 | (thread->looper & BINDER_LOOPER_STATE_NEED_RETURN); | 3667 | struct binder_proc *proc = thread->proc; |
| 3668 | int ret = 0; | ||
| 3669 | |||
| 3670 | freezer_do_not_count(); | ||
| 3671 | binder_inner_proc_lock(proc); | ||
| 3672 | for (;;) { | ||
| 3673 | prepare_to_wait(&thread->wait, &wait, TASK_INTERRUPTIBLE); | ||
| 3674 | if (binder_has_work_ilocked(thread, do_proc_work)) | ||
| 3675 | break; | ||
| 3676 | if (do_proc_work) | ||
| 3677 | list_add(&thread->waiting_thread_node, | ||
| 3678 | &proc->waiting_threads); | ||
| 3679 | binder_inner_proc_unlock(proc); | ||
| 3680 | schedule(); | ||
| 3681 | binder_inner_proc_lock(proc); | ||
| 3682 | list_del_init(&thread->waiting_thread_node); | ||
| 3683 | if (signal_pending(current)) { | ||
| 3684 | ret = -ERESTARTSYS; | ||
| 3685 | break; | ||
| 3686 | } | ||
| 3687 | } | ||
| 3688 | finish_wait(&thread->wait, &wait); | ||
| 3689 | binder_inner_proc_unlock(proc); | ||
| 3690 | freezer_count(); | ||
| 3691 | |||
| 3692 | return ret; | ||
| 2652 | } | 3693 | } |
| 2653 | 3694 | ||
| 2654 | static int binder_thread_read(struct binder_proc *proc, | 3695 | static int binder_thread_read(struct binder_proc *proc, |
| @@ -2670,37 +3711,15 @@ static int binder_thread_read(struct binder_proc *proc, · 15 unmodified lines | |||
| 2670 | } | 3711 | } |
| 2671 | 3712 | ||
| 2672 | retry: | 3713 | retry: |
| 2673 | wait_for_proc_work = thread->transaction_stack == NULL && | 3714 | binder_inner_proc_lock(proc); |
| 2674 | list_empty(&thread->todo); | 3715 | wait_for_proc_work = binder_available_for_proc_work_ilocked(thread); |
| 2675 | 3716 | binder_inner_proc_unlock(proc); | |
| 2676 | if (thread->return_error != BR_OK && ptr < end) { | ||
| 2677 | if (thread->return_error2 != BR_OK) { | ||
| 2678 | if (put_user(thread->return_error2, (uint32_t __user *)ptr)) | ||
| 2679 | return -EFAULT; | ||
| 2680 | ptr += sizeof(uint32_t); | ||
| 2681 | binder_stat_br(proc, thread, thread->return_error2); | ||
| 2682 | if (ptr == end) | ||
| 2683 | goto done; | ||
| 2684 | thread->return_error2 = BR_OK; | ||
| 2685 | } | ||
| 2686 | if (put_user(thread->return_error, (uint32_t __user *)ptr)) | ||
| 2687 | return -EFAULT; | ||
| 2688 | ptr += sizeof(uint32_t); | ||
| 2689 | binder_stat_br(proc, thread, thread->return_error); | ||
| 2690 | thread->return_error = BR_OK; | ||
| 2691 | goto done; | ||
| 2692 | } | ||
| 2693 | |||
| 2694 | 3717 | ||
| 2695 | thread->looper |= BINDER_LOOPER_STATE_WAITING; | 3718 | thread->looper |= BINDER_LOOPER_STATE_WAITING; |
| 2696 | if (wait_for_proc_work) | ||
| 2697 | proc->ready_threads++; | ||
| 2698 | |||
| 2699 | binder_unlock(__func__); | ||
| 2700 | 3719 | ||
| 2701 | trace_binder_wait_for_work(wait_for_proc_work, | 3720 | trace_binder_wait_for_work(wait_for_proc_work, |
| 2702 | !!thread->transaction_stack, | 3721 | !!thread->transaction_stack, |
| 2703 | !list_empty(&thread->todo)); | 3722 | !binder_worklist_empty(proc, &thread->todo)); |
| 2704 | if (wait_for_proc_work) { | 3723 | if (wait_for_proc_work) { |
| 2705 | if (!(thread->looper & (BINDER_LOOPER_STATE_REGISTERED | | 3724 | if (!(thread->looper & (BINDER_LOOPER_STATE_REGISTERED | |
| 2706 | BINDER_LOOPER_STATE_ENTERED))) { | 3725 | BINDER_LOOPER_STATE_ENTERED))) { |
| @@ -2710,23 +3729,15 @@ retry: · 3 unmodified lines | |||
| 2710 | binder_stop_on_user_error < 2); | 3729 | binder_stop_on_user_error < 2); |
| 2711 | } | 3730 | } |
| 2712 | binder_set_nice(proc->default_priority); | 3731 | binder_set_nice(proc->default_priority); |
| 2713 | if (non_block) { | ||
| 2714 | if (!binder_has_proc_work(proc, thread)) | ||
| 2715 | ret = -EAGAIN; | ||
| 2716 | } else | ||
| 2717 | ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread)); | ||
| 2718 | } else { | ||
| 2719 | if (non_block) { | ||
| 2720 | if (!binder_has_thread_work(thread)) | ||
| 2721 | ret = -EAGAIN; | ||
| 2722 | } else | ||
| 2723 | ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread)); | ||
| 2724 | } | 3732 | } |
| 2725 | 3733 | ||
| 2726 | binder_lock(__func__); | 3734 | if (non_block) { |
| 3735 | if (!binder_has_work(thread, wait_for_proc_work)) | ||
| 3736 | ret = -EAGAIN; | ||
| 3737 | } else { | ||
| 3738 | ret = binder_wait_for_work(thread, wait_for_proc_work); | ||
| 3739 | } | ||
| 2727 | 3740 | ||
| 2728 | if (wait_for_proc_work) | ||
| 2729 | proc->ready_threads--; | ||
| 2730 | thread->looper &= ~BINDER_LOOPER_STATE_WAITING; | 3741 | thread->looper &= ~BINDER_LOOPER_STATE_WAITING; |
| 2731 | 3742 | ||
| 2732 | if (ret) | 3743 | if (ret) |
| @@ -2735,31 +3746,52 @@ retry: · 2 unmodified lines | |||
| 2735 | while (1) { | 3746 | while (1) { |
| 2736 | uint32_t cmd; | 3747 | uint32_t cmd; |
| 2737 | struct binder_transaction_data tr; | 3748 | struct binder_transaction_data tr; |
| 2738 | struct binder_work *w; | 3749 | struct binder_work *w = NULL; |
| 3750 | struct list_head *list = NULL; | ||
| 2739 | struct binder_transaction *t = NULL; | 3751 | struct binder_transaction *t = NULL; |
| 3752 | struct binder_thread *t_from; | ||
| 3753 | |||
| 3754 | binder_inner_proc_lock(proc); | ||
| 3755 | if (!binder_worklist_empty_ilocked(&thread->todo)) | ||
| 3756 | list = &thread->todo; | ||
| 3757 | else if (!binder_worklist_empty_ilocked(&proc->todo) && | ||
| 3758 | wait_for_proc_work) | ||
| 3759 | list = &proc->todo; | ||
| 3760 | else { | ||
| 3761 | binder_inner_proc_unlock(proc); | ||
| 2740 | 3762 | ||
| 2741 | if (!list_empty(&thread->todo)) { | ||
| 2742 | w = list_first_entry(&thread->todo, struct binder_work, | ||
| 2743 | entry); | ||
| 2744 | } else if (!list_empty(&proc->todo) && wait_for_proc_work) { | ||
| 2745 | w = list_first_entry(&proc->todo, struct binder_work, | ||
| 2746 | entry); | ||
| 2747 | } else { | ||
| 2748 | /* no data added */ | 3763 | /* no data added */ |
| 2749 | if (ptr - buffer == 4 && | 3764 | if (ptr - buffer == 4 && !thread->looper_need_return) |
| 2750 | !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN)) | ||
| 2751 | goto retry; | 3765 | goto retry; |
| 2752 | break; | 3766 | break; |
| 2753 | } | 3767 | } |
| 2754 | 3768 | ||
| 2755 | if (end - ptr < sizeof(tr) + 4) | 3769 | if (end - ptr < sizeof(tr) + 4) { |
| 3770 | binder_inner_proc_unlock(proc); | ||
| 2756 | break; | 3771 | break; |
| 3772 | } | ||
| 3773 | w = binder_dequeue_work_head_ilocked(list); | ||
| 2757 | 3774 | ||
| 2758 | switch (w->type) { | 3775 | switch (w->type) { |
| 2759 | case BINDER_WORK_TRANSACTION: { | 3776 | case BINDER_WORK_TRANSACTION: { |
| 3777 | binder_inner_proc_unlock(proc); | ||
| 2760 | t = container_of(w, struct binder_transaction, work); | 3778 | t = container_of(w, struct binder_transaction, work); |
| 2761 | } break; | 3779 | } break; |
| 3780 | case BINDER_WORK_RETURN_ERROR: { | ||
| 3781 | struct binder_error *e = container_of( | ||
| 3782 | w, struct binder_error, work); | ||
| 3783 | |||
| 3784 | WARN_ON(e->cmd == BR_OK); | ||
| 3785 | binder_inner_proc_unlock(proc); | ||
| 3786 | if (put_user(e->cmd, (uint32_t __user *)ptr)) | ||
| 3787 | return -EFAULT; | ||
| 3788 | e->cmd = BR_OK; | ||
| 3789 | ptr += sizeof(uint32_t); | ||
| 3790 | |||
| 3791 | binder_stat_br(proc, thread, e->cmd); | ||
| 3792 | } break; | ||
| 2762 | case BINDER_WORK_TRANSACTION_COMPLETE: { | 3793 | case BINDER_WORK_TRANSACTION_COMPLETE: { |
| 3794 | binder_inner_proc_unlock(proc); | ||
| 2763 | cmd = BR_TRANSACTION_COMPLETE; | 3795 | cmd = BR_TRANSACTION_COMPLETE; |
| 2764 | if (put_user(cmd, (uint32_t __user *)ptr)) | 3796 | if (put_user(cmd, (uint32_t __user *)ptr)) |
| 2765 | return -EFAULT; | 3797 | return -EFAULT; |
| @@ -2769,113 +3801,134 @@ retry: · 3 unmodified lines | |||
| 2769 | binder_debug(BINDER_DEBUG_TRANSACTION_COMPLETE, | 3801 | binder_debug(BINDER_DEBUG_TRANSACTION_COMPLETE, |
| 2770 | "%d:%d BR_TRANSACTION_COMPLETE\n", | 3802 | "%d:%d BR_TRANSACTION_COMPLETE\n", |
| 2771 | proc->pid, thread->pid); | 3803 | proc->pid, thread->pid); |
| 2772 | |||
| 2773 | list_del(&w->entry); | ||
| 2774 | kfree(w); | 3804 | kfree(w); |
| 2775 | binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); | 3805 | binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); |
| 2776 | } break; | 3806 | } break; |
| 2777 | case BINDER_WORK_NODE: { | 3807 | case BINDER_WORK_NODE: { |
| 2778 | struct binder_node *node = container_of(w, struct binder_node, work); | 3808 | struct binder_node *node = container_of(w, struct binder_node, work); |
| 2779 | uint32_t cmd = BR_NOOP; | 3809 | int strong, weak; |
| 2780 | const char *cmd_name; | 3810 | binder_uintptr_t node_ptr = node->ptr; |
| 2781 | int strong = node->internal_strong_refs || node->local_strong_refs; | 3811 | binder_uintptr_t node_cookie = node->cookie; |
| 2782 | int weak = !hlist_empty(&node->refs) || node->local_weak_refs || strong; | 3812 | int node_debug_id = node->debug_id; |
| 2783 | 3813 | int has_weak_ref; | |
| 2784 | if (weak && !node->has_weak_ref) { | 3814 | int has_strong_ref; |
| 2785 | cmd = BR_INCREFS; | 3815 | void __user *orig_ptr = ptr; |
| 2786 | cmd_name = "BR_INCREFS"; | 3816 | |
| 3817 | BUG_ON(proc != node->proc); | ||
| 3818 | strong = node->internal_strong_refs || | ||
| 3819 | node->local_strong_refs; | ||
| 3820 | weak = !hlist_empty(&node->refs) || | ||
| 3821 | node->local_weak_refs || | ||
| 3822 | node->tmp_refs || strong; | ||
| 3823 | has_strong_ref = node->has_strong_ref; | ||
| 3824 | has_weak_ref = node->has_weak_ref; | ||
| 3825 | |||
| 3826 | if (weak && !has_weak_ref) { | ||
| 2787 | node->has_weak_ref = 1; | 3827 | node->has_weak_ref = 1; |
| 2788 | node->pending_weak_ref = 1; | 3828 | node->pending_weak_ref = 1; |
| 2789 | node->local_weak_refs++; | 3829 | node->local_weak_refs++; |
| 2790 | } else if (strong && !node->has_strong_ref) { | 3830 | } |
| 2791 | cmd = BR_ACQUIRE; | 3831 | if (strong && !has_strong_ref) { |
| 2792 | cmd_name = "BR_ACQUIRE"; | ||
| 2793 | node->has_strong_ref = 1; | 3832 | node->has_strong_ref = 1; |
| 2794 | node->pending_strong_ref = 1; | 3833 | node->pending_strong_ref = 1; |
| 2795 | node->local_strong_refs++; | 3834 | node->local_strong_refs++; |
| 2796 | } else if (!strong && node->has_strong_ref) { | 3835 | } |
| 2797 | cmd = BR_RELEASE; | 3836 | if (!strong && has_strong_ref) |
| 2798 | cmd_name = "BR_RELEASE"; | ||
| 2799 | node->has_strong_ref = 0; | 3837 | node->has_strong_ref = 0; |
| 2800 | } else if (!weak && node->has_weak_ref) { | 3838 | if (!weak && has_weak_ref) |
| 2801 | cmd = BR_DECREFS; | ||
| 2802 | cmd_name = "BR_DECREFS"; | ||
| 2803 | node->has_weak_ref = 0; | 3839 | node->has_weak_ref = 0; |
| 2804 | } | 3840 | if (!weak && !strong) { |
| 2805 | if (cmd != BR_NOOP) { | 3841 | binder_debug(BINDER_DEBUG_INTERNAL_REFS, |
| 2806 | if (put_user(cmd, (uint32_t __user *)ptr)) | 3842 | "%d:%d node %d u%016llx c%016llx deleted\n", |
| 2807 | return -EFAULT; | 3843 | proc->pid, thread->pid, |
| 2808 | ptr += sizeof(uint32_t); | 3844 | node_debug_id, |
| 2809 | if (put_user(node->ptr, | 3845 | (u64)node_ptr, |
| 2810 | (binder_uintptr_t __user *)ptr)) | 3846 | (u64)node_cookie); |
| 2811 | return -EFAULT; | 3847 | rb_erase(&node->rb_node, &proc->nodes); |
| 2812 | ptr += sizeof(binder_uintptr_t); | 3848 | binder_inner_proc_unlock(proc); |
| 2813 | if (put_user(node->cookie, | 3849 | binder_node_lock(node); |
| 2814 | (binder_uintptr_t __user *)ptr)) | 3850 | /* |
| 2815 | return -EFAULT; | 3851 | * Acquire the node lock before freeing the |
| 2816 | ptr += sizeof(binder_uintptr_t); | 3852 | * node to serialize with other threads that |
| 2817 | 3853 | * may have been holding the node lock while | |
| 2818 | binder_stat_br(proc, thread, cmd); | 3854 | * decrementing this node (avoids race where |
| 2819 | binder_debug(BINDER_DEBUG_USER_REFS, | 3855 | * this thread frees while the other thread |
| 2820 | "%d:%d %s %d u%016llx c%016llx\n", | 3856 | * is unlocking the node after the final |
| 2821 | proc->pid, thread->pid, cmd_name, | 3857 | * decrement) |
| 2822 | node->debug_id, | 3858 | */ |
| 2823 | (u64)node->ptr, (u64)node->cookie); | 3859 | binder_node_unlock(node); |
| 2824 | } else { | 3860 | binder_free_node(node); |
| 2825 | list_del_init(&w->entry); | 3861 | } else |
| 2826 | if (!weak && !strong) { | 3862 | binder_inner_proc_unlock(proc); |
| 2827 | binder_debug(BINDER_DEBUG_INTERNAL_REFS, | 3863 | |
| 2828 | "%d:%d node %d u%016llx c%016llx deleted\n", | 3864 | if (weak && !has_weak_ref) |
| 2829 | proc->pid, thread->pid, | 3865 | ret = binder_put_node_cmd( |
| 2830 | node->debug_id, | 3866 | proc, thread, &ptr, node_ptr, |
| 2831 | (u64)node->ptr, | 3867 | node_cookie, node_debug_id, |
| 2832 | (u64)node->cookie); | 3868 | BR_INCREFS, "BR_INCREFS"); |
| 2833 | rb_erase(&node->rb_node, &proc->nodes); | 3869 | if (!ret && strong && !has_strong_ref) |
| 2834 | kfree(node); | 3870 | ret = binder_put_node_cmd( |
| 2835 | binder_stats_deleted(BINDER_STAT_NODE); | 3871 | proc, thread, &ptr, node_ptr, |
| 2836 | } else { | 3872 | node_cookie, node_debug_id, |
| 2837 | binder_debug(BINDER_DEBUG_INTERNAL_REFS, | 3873 | BR_ACQUIRE, "BR_ACQUIRE"); |
| 2838 | "%d:%d node %d u%016llx c%016llx state unchanged\n", | 3874 | if (!ret && !strong && has_strong_ref) |
| 2839 | proc->pid, thread->pid, | 3875 | ret = binder_put_node_cmd( |
| 2840 | node->debug_id, | 3876 | proc, thread, &ptr, node_ptr, |
| 2841 | (u64)node->ptr, | 3877 | node_cookie, node_debug_id, |
| 2842 | (u64)node->cookie); | 3878 | BR_RELEASE, "BR_RELEASE"); |
| 2843 | } | 3879 | if (!ret && !weak && has_weak_ref) |
| 2844 | } | 3880 | ret = binder_put_node_cmd( |
| 3881 | proc, thread, &ptr, node_ptr, | ||
| 3882 | node_cookie, node_debug_id, | ||
| 3883 | BR_DECREFS, "BR_DECREFS"); | ||
| 3884 | if (orig_ptr == ptr) | ||
| 3885 | binder_debug(BINDER_DEBUG_INTERNAL_REFS, | ||
| 3886 | "%d:%d node %d u%016llx c%016llx state unchanged\n", | ||
| 3887 | proc->pid, thread->pid, | ||
| 3888 | node_debug_id, | ||
| 3889 | (u64)node_ptr, | ||
| 3890 | (u64)node_cookie); | ||
| 3891 | if (ret) | ||
| 3892 | return ret; | ||
| 2845 | } break; | 3893 | } break; |
| 2846 | case BINDER_WORK_DEAD_BINDER: | 3894 | case BINDER_WORK_DEAD_BINDER: |
| 2847 | case BINDER_WORK_DEAD_BINDER_AND_CLEAR: | 3895 | case BINDER_WORK_DEAD_BINDER_AND_CLEAR: |
| 2848 | case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: { | 3896 | case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: { |
| 2849 | struct binder_ref_death *death; | 3897 | struct binder_ref_death *death; |
| 2850 | uint32_t cmd; | 3898 | uint32_t cmd; |
| 3899 | binder_uintptr_t cookie; | ||
| 2851 | 3900 | ||
| 2852 | death = container_of(w, struct binder_ref_death, work); | 3901 | death = container_of(w, struct binder_ref_death, work); |
| 2853 | if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) | 3902 | if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) |
| 2854 | cmd = BR_CLEAR_DEATH_NOTIFICATION_DONE; | 3903 | cmd = BR_CLEAR_DEATH_NOTIFICATION_DONE; |
| 2855 | else | 3904 | else |
| 2856 | cmd = BR_DEAD_BINDER; | 3905 | cmd = BR_DEAD_BINDER; |
| 2857 | if (put_user(cmd, (uint32_t __user *)ptr)) | 3906 | cookie = death->cookie; |
| 2858 | return -EFAULT; | 3907 | |
| 2859 | ptr += sizeof(uint32_t); | ||
| 2860 | if (put_user(death->cookie, | ||
| 2861 | (binder_uintptr_t __user *)ptr)) | ||
| 2862 | return -EFAULT; | ||
| 2863 | ptr += sizeof(binder_uintptr_t); | ||
| 2864 | binder_stat_br(proc, thread, cmd); | ||
| 2865 | binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION, | 3908 | binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION, |
| 2866 | "%d:%d %s %016llx\n", | 3909 | "%d:%d %s %016llx\n", |
| 2867 | proc->pid, thread->pid, | 3910 | proc->pid, thread->pid, |
| 2868 | cmd == BR_DEAD_BINDER ? | 3911 | cmd == BR_DEAD_BINDER ? |
| 2869 | "BR_DEAD_BINDER" : | 3912 | "BR_DEAD_BINDER" : |
| 2870 | "BR_CLEAR_DEATH_NOTIFICATION_DONE", | 3913 | "BR_CLEAR_DEATH_NOTIFICATION_DONE", |
| 2871 | (u64)death->cookie); | 3914 | (u64)cookie); |
| 2872 | |||
| 2873 | if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) { | 3915 | if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) { |
| 2874 | list_del(&w->entry); | 3916 | binder_inner_proc_unlock(proc); |
| 2875 | kfree(death); | 3917 | kfree(death); |
| 2876 | binder_stats_deleted(BINDER_STAT_DEATH); | 3918 | binder_stats_deleted(BINDER_STAT_DEATH); |
| 2877 | } else | 3919 | } else { |
| 2878 | list_move(&w->entry, &proc->delivered_death); | 3920 | binder_enqueue_work_ilocked( |
| 3921 | w, &proc->delivered_death); | ||
| 3922 | binder_inner_proc_unlock(proc); | ||
| 3923 | } | ||
| 3924 | if (put_user(cmd, (uint32_t __user *)ptr)) | ||
| 3925 | return -EFAULT; | ||
| 3926 | ptr += sizeof(uint32_t); | ||
| 3927 | if (put_user(cookie, | ||
| 3928 | (binder_uintptr_t __user *)ptr)) | ||
| 3929 | return -EFAULT; | ||
| 3930 | ptr += sizeof(binder_uintptr_t); | ||
| 3931 | binder_stat_br(proc, thread, cmd); | ||
| 2879 | if (cmd == BR_DEAD_BINDER) | 3932 | if (cmd == BR_DEAD_BINDER) |
| 2880 | goto done; /* DEAD_BINDER notifications can cause transactions */ | 3933 | goto done; /* DEAD_BINDER notifications can cause transactions */ |
| 2881 | } break; | 3934 | } break; |
| @@ -2907,8 +3960,9 @@ retry: · 25 unmodified lines | |||
| 2907 | tr.flags = t->flags; | 3960 | tr.flags = t->flags; |
| 2908 | tr.sender_euid = from_kuid(current_user_ns(), t->sender_euid); | 3961 | tr.sender_euid = from_kuid(current_user_ns(), t->sender_euid); |
| 2909 | 3962 | ||
| 2910 | if (t->from) { | 3963 | t_from = binder_get_txn_from(t); |
| 2911 | struct task_struct *sender = t->from->proc->tsk; | 3964 | if (t_from) { |
| 3965 | struct task_struct *sender = t_from->proc->tsk; | ||
| 2912 | 3966 | ||
| 2913 | tr.sender_pid = task_tgid_nr_ns(sender, | 3967 | tr.sender_pid = task_tgid_nr_ns(sender, |
| 2914 | task_active_pid_ns(current)); | 3968 | task_active_pid_ns(current)); |
| @@ -2918,18 +3972,24 @@ retry: · 3 unmodified lines | |||
| 2918 | 3972 | ||
| 2919 | tr.data_size = t->buffer->data_size; | 3973 | tr.data_size = t->buffer->data_size; |
| 2920 | tr.offsets_size = t->buffer->offsets_size; | 3974 | tr.offsets_size = t->buffer->offsets_size; |
| 2921 | tr.data.ptr.buffer = (binder_uintptr_t)( | 3975 | tr.data.ptr.buffer = (binder_uintptr_t) |
| 2922 | (uintptr_t)t->buffer->data + | 3976 | ((uintptr_t)t->buffer->data + |
| 2923 | proc->user_buffer_offset); | 3977 | binder_alloc_get_user_buffer_offset(&proc->alloc)); |
| 2924 | tr.data.ptr.offsets = tr.data.ptr.buffer + | 3978 | tr.data.ptr.offsets = tr.data.ptr.buffer + |
| 2925 | ALIGN(t->buffer->data_size, | 3979 | ALIGN(t->buffer->data_size, |
| 2926 | sizeof(void *)); | 3980 | sizeof(void *)); |
| 2927 | 3981 | ||
| 2928 | if (put_user(cmd, (uint32_t __user *)ptr)) | 3982 | if (put_user(cmd, (uint32_t __user *)ptr)) { |
| 3983 | if (t_from) | ||
| 3984 | binder_thread_dec_tmpref(t_from); | ||
| 2929 | return -EFAULT; | 3985 | return -EFAULT; |
| 3986 | } | ||
| 2930 | ptr += sizeof(uint32_t); | 3987 | ptr += sizeof(uint32_t); |
| 2931 | if (copy_to_user(ptr, &tr, sizeof(tr))) | 3988 | if (copy_to_user(ptr, &tr, sizeof(tr))) { |
| 3989 | if (t_from) | ||
| 3990 | binder_thread_dec_tmpref(t_from); | ||
| 2932 | return -EFAULT; | 3991 | return -EFAULT; |
| 3992 | } | ||
| 2933 | ptr += sizeof(tr); | 3993 | ptr += sizeof(tr); |
| 2934 | 3994 | ||
| 2935 | trace_binder_transaction_received(t); | 3995 | trace_binder_transaction_received(t); |
| @@ -2939,21 +3999,22 @@ retry: · 3 unmodified lines | |||
| 2939 | proc->pid, thread->pid, | 3999 | proc->pid, thread->pid, |
| 2940 | (cmd == BR_TRANSACTION) ? "BR_TRANSACTION" : | 4000 | (cmd == BR_TRANSACTION) ? "BR_TRANSACTION" : |
| 2941 | "BR_REPLY", | 4001 | "BR_REPLY", |
| 2942 | t->debug_id, t->from ? t->from->proc->pid : 0, | 4002 | t->debug_id, t_from ? t_from->proc->pid : 0, |
| 2943 | t->from ? t->from->pid : 0, cmd, | 4003 | t_from ? t_from->pid : 0, cmd, |
| 2944 | t->buffer->data_size, t->buffer->offsets_size, | 4004 | t->buffer->data_size, t->buffer->offsets_size, |
| 2945 | (u64)tr.data.ptr.buffer, (u64)tr.data.ptr.offsets); | 4005 | (u64)tr.data.ptr.buffer, (u64)tr.data.ptr.offsets); |
| 2946 | 4006 | ||
| 2947 | list_del(&t->work.entry); | 4007 | if (t_from) |
| 4008 | binder_thread_dec_tmpref(t_from); | ||
| 2948 | t->buffer->allow_user_free = 1; | 4009 | t->buffer->allow_user_free = 1; |
| 2949 | if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) { | 4010 | if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) { |
| 4011 | binder_inner_proc_lock(thread->proc); | ||
| 2950 | t->to_parent = thread->transaction_stack; | 4012 | t->to_parent = thread->transaction_stack; |
| 2951 | t->to_thread = thread; | 4013 | t->to_thread = thread; |
| 2952 | thread->transaction_stack = t; | 4014 | thread->transaction_stack = t; |
| 4015 | binder_inner_proc_unlock(thread->proc); | ||
| 2953 | } else { | 4016 | } else { |
| 2954 | t->buffer->transaction = NULL; | 4017 | binder_free_transaction(t); |
| 2955 | kfree(t); | ||
| 2956 | binder_stats_deleted(BINDER_STAT_TRANSACTION); | ||
| 2957 | } | 4018 | } |
| 2958 | break; | 4019 | break; |
| 2959 | } | 4020 | } |
| @@ -2961,29 +4022,36 @@ retry: · 1 unmodified line | |||
| 2961 | done: | 4022 | done: |
| 2962 | 4023 | ||
| 2963 | *consumed = ptr - buffer; | 4024 | *consumed = ptr - buffer; |
| 2964 | if (proc->requested_threads + proc->ready_threads == 0 && | 4025 | binder_inner_proc_lock(proc); |
| 4026 | if (proc->requested_threads == 0 && | ||
| 4027 | list_empty(&thread->proc->waiting_threads) && | ||
| 2965 | proc->requested_threads_started < proc->max_threads && | 4028 | proc->requested_threads_started < proc->max_threads && |
| 2966 | (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | | 4029 | (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | |
| 2967 | BINDER_LOOPER_STATE_ENTERED)) /* the user-space code fails to */ | 4030 | BINDER_LOOPER_STATE_ENTERED)) /* the user-space code fails to */ |
| 2968 | /*spawn a new thread if we leave this out */) { | 4031 | /*spawn a new thread if we leave this out */) { |
| 2969 | proc->requested_threads++; | 4032 | proc->requested_threads++; |
| 4033 | binder_inner_proc_unlock(proc); | ||
| 2970 | binder_debug(BINDER_DEBUG_THREADS, | 4034 | binder_debug(BINDER_DEBUG_THREADS, |
| 2971 | "%d:%d BR_SPAWN_LOOPER\n", | 4035 | "%d:%d BR_SPAWN_LOOPER\n", |
| 2972 | proc->pid, thread->pid); | 4036 | proc->pid, thread->pid); |
| 2973 | if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer)) | 4037 | if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer)) |
| 2974 | return -EFAULT; | 4038 | return -EFAULT; |
| 2975 | binder_stat_br(proc, thread, BR_SPAWN_LOOPER); | 4039 | binder_stat_br(proc, thread, BR_SPAWN_LOOPER); |
| 2976 | } | 4040 | } else |
| 4041 | binder_inner_proc_unlock(proc); | ||
| 2977 | return 0; | 4042 | return 0; |
| 2978 | } | 4043 | } |
| 2979 | 4044 | ||
| 2980 | static void binder_release_work(struct list_head *list) | 4045 | static void binder_release_work(struct binder_proc *proc, |
| 4046 | struct list_head *list) | ||
| 2981 | { | 4047 | { |
| 2982 | struct binder_work *w; | 4048 | struct binder_work *w; |
| 2983 | 4049 | ||
| 2984 | while (!list_empty(list)) { | 4050 | while (1) { |
| 2985 | w = list_first_entry(list, struct binder_work, entry); | 4051 | w = binder_dequeue_work_head(proc, list); |
| 2986 | list_del_init(&w->entry); | 4052 | if (!w) |
| 4053 | return; | ||
| 4054 | |||
| 2987 | switch (w->type) { | 4055 | switch (w->type) { |
| 2988 | case BINDER_WORK_TRANSACTION: { | 4056 | case BINDER_WORK_TRANSACTION: { |
| 2989 | struct binder_transaction *t; | 4057 | struct binder_transaction *t; |
| @@ -2996,11 +4064,17 @@ static void binder_release_work(struct list_head *list) · 6 unmodified lines | |||
| 2996 | binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, | 4064 | binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, |
| 2997 | "undelivered transaction %d\n", | 4065 | "undelivered transaction %d\n", |
| 2998 | t->debug_id); | 4066 | t->debug_id); |
| 2999 | t->buffer->transaction = NULL; | 4067 | binder_free_transaction(t); |
| 3000 | kfree(t); | ||
| 3001 | binder_stats_deleted(BINDER_STAT_TRANSACTION); | ||
| 3002 | } | 4068 | } |
| 3003 | } break; | 4069 | } break; |
| 4070 | case BINDER_WORK_RETURN_ERROR: { | ||
| 4071 | struct binder_error *e = container_of( | ||
| 4072 | w, struct binder_error, work); | ||
| 4073 | |||
| 4074 | binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, | ||
| 4075 | "undelivered TRANSACTION_ERROR: %u\n", | ||
| 4076 | e->cmd); | ||
| 4077 | } break; | ||
| 3004 | case BINDER_WORK_TRANSACTION_COMPLETE: { | 4078 | case BINDER_WORK_TRANSACTION_COMPLETE: { |
| 3005 | binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, | 4079 | binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, |
| 3006 | "undelivered TRANSACTION_COMPLETE\n"); | 4080 | "undelivered TRANSACTION_COMPLETE\n"); |
| @@ -3027,7 +4101,8 @@ static void binder_release_work(struct list_head *list) · 20 unmodified lines | |||
| 3027 | 4101 | ||
| 3028 | } | 4102 | } |
| 3029 | 4103 | ||
| 3030 | static struct binder_thread *binder_get_thread(struct binder_proc *proc) | 4104 | static struct binder_thread *binder_get_thread_ilocked( |
| 4105 | struct binder_proc *proc, struct binder_thread *new_thread) | ||
| 3031 | { | 4106 | { |
| 3032 | struct binder_thread *thread = NULL; | 4107 | struct binder_thread *thread = NULL; |
| 3033 | struct rb_node *parent = NULL; | 4108 | struct rb_node *parent = NULL; |
| @@ -3042,38 +4117,99 @@ static struct binder_thread *binder_get_thread(struct binder_proc *proc) · 8 unmodified lines | |||
| 3042 | else if (current->pid > thread->pid) | 4117 | else if (current->pid > thread->pid) |
| 3043 | p = &(*p)->rb_right; | 4118 | p = &(*p)->rb_right; |
| 3044 | else | 4119 | else |
| 3045 | break; | 4120 | return thread; |
| 3046 | } | 4121 | } |
| 3047 | if (*p == NULL) { | 4122 | if (!new_thread) |
| 3048 | thread = kzalloc(sizeof(*thread), GFP_KERNEL); | 4123 | return NULL; |
| 3049 | if (thread == NULL) | 4124 | thread = new_thread; |
| 4125 | binder_stats_created(BINDER_STAT_THREAD); | ||
| 4126 | thread->proc = proc; | ||
| 4127 | thread->pid = current->pid; | ||
| 4128 | atomic_set(&thread->tmp_ref, 0); | ||
| 4129 | init_waitqueue_head(&thread->wait); | ||
| 4130 | INIT_LIST_HEAD(&thread->todo); | ||
| 4131 | rb_link_node(&thread->rb_node, parent, p); | ||
| 4132 | rb_insert_color(&thread->rb_node, &proc->threads); | ||
| 4133 | thread->looper_need_return = true; | ||
| 4134 | thread->return_error.work.type = BINDER_WORK_RETURN_ERROR; | ||
| 4135 | thread->return_error.cmd = BR_OK; | ||
| 4136 | thread->reply_error.work.type = BINDER_WORK_RETURN_ERROR; | ||
| 4137 | thread->reply_error.cmd = BR_OK; | ||
| 4138 | INIT_LIST_HEAD(&new_thread->waiting_thread_node); | ||
| 4139 | return thread; | ||
| 4140 | } | ||
| 4141 | |||
| 4142 | static struct binder_thread *binder_get_thread(struct binder_proc *proc) | ||
| 4143 | { | ||
| 4144 | struct binder_thread *thread; | ||
| 4145 | struct binder_thread *new_thread; | ||
| 4146 | |||
| 4147 | binder_inner_proc_lock(proc); | ||
| 4148 | thread = binder_get_thread_ilocked(proc, NULL); | ||
| 4149 | binder_inner_proc_unlock(proc); | ||
| 4150 | if (!thread) { | ||
| 4151 | new_thread = kzalloc(sizeof(*thread), GFP_KERNEL); | ||
| 4152 | if (new_thread == NULL) | ||
| 3050 | return NULL; | 4153 | return NULL; |
| 3051 | binder_stats_created(BINDER_STAT_THREAD); | 4154 | binder_inner_proc_lock(proc); |
| 3052 | thread->proc = proc; | 4155 | thread = binder_get_thread_ilocked(proc, new_thread); |
| 3053 | thread->pid = current->pid; | 4156 | binder_inner_proc_unlock(proc); |
| 3054 | init_waitqueue_head(&thread->wait); | 4157 | if (thread != new_thread) |
| 3055 | INIT_LIST_HEAD(&thread->todo); | 4158 | kfree(new_thread); |
| 3056 | rb_link_node(&thread->rb_node, parent, p); | ||
| 3057 | rb_insert_color(&thread->rb_node, &proc->threads); | ||
| 3058 | thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN; | ||
| 3059 | thread->return_error = BR_OK; | ||
| 3060 | thread->return_error2 = BR_OK; | ||
| 3061 | } | 4159 | } |
| 3062 | return thread; | 4160 | return thread; |
| 3063 | } | 4161 | } |
| 3064 | 4162 | ||
| 3065 | static int binder_free_thread(struct binder_proc *proc, | 4163 | static void binder_free_proc(struct binder_proc *proc) |
| 3066 | struct binder_thread *thread) | 4164 | { |
| 4165 | BUG_ON(!list_empty(&proc->todo)); | ||
| 4166 | BUG_ON(!list_empty(&proc->delivered_death)); | ||
| 4167 | binder_alloc_deferred_release(&proc->alloc); | ||
| 4168 | put_task_struct(proc->tsk); | ||
| 4169 | binder_stats_deleted(BINDER_STAT_PROC); | ||
| 4170 | kfree(proc); | ||
| 4171 | } | ||
| 4172 | |||
| 4173 | static void binder_free_thread(struct binder_thread *thread) | ||
| 4174 | { | ||
| 4175 | BUG_ON(!list_empty(&thread->todo)); | ||
| 4176 | binder_stats_deleted(BINDER_STAT_THREAD); | ||
| 4177 | binder_proc_dec_tmpref(thread->proc); | ||
| 4178 | kfree(thread); | ||
| 4179 | } | ||
| 4180 | |||
| 4181 | static int binder_thread_release(struct binder_proc *proc, | ||
| 4182 | struct binder_thread *thread) | ||
| 3067 | { | 4183 | { |
| 3068 | struct binder_transaction *t; | 4184 | struct binder_transaction *t; |
| 3069 | struct binder_transaction *send_reply = NULL; | 4185 | struct binder_transaction *send_reply = NULL; |
| 3070 | int active_transactions = 0; | 4186 | int active_transactions = 0; |
| 4187 | struct binder_transaction *last_t = NULL; | ||
| 3071 | 4188 | ||
| 4189 | binder_inner_proc_lock(thread->proc); | ||
| 4190 | /* | ||
| 4191 | * take a ref on the proc so it survives | ||
| 4192 | * after we remove this thread from proc->threads. | ||
| 4193 | * The corresponding dec is when we actually | ||
| 4194 | * free the thread in binder_free_thread() | ||
| 4195 | */ | ||
| 4196 | proc->tmp_ref++; | ||
| 4197 | /* | ||
| 4198 | * take a ref on this thread to ensure it | ||
| 4199 | * survives while we are releasing it | ||
| 4200 | */ | ||
| 4201 | atomic_inc(&thread->tmp_ref); | ||
| 3072 | rb_erase(&thread->rb_node, &proc->threads); | 4202 | rb_erase(&thread->rb_node, &proc->threads); |
| 3073 | t = thread->transaction_stack; | 4203 | t = thread->transaction_stack; |
| 3074 | if (t && t->to_thread == thread) | 4204 | if (t) { |
| 3075 | send_reply = t; | 4205 | spin_lock(&t->lock); |
| 4206 | if (t->to_thread == thread) | ||
| 4207 | send_reply = t; | ||
| 4208 | } | ||
| 4209 | thread->is_dead = true; | ||
| 4210 | |||
| 3076 | while (t) { | 4211 | while (t) { |
| 4212 | last_t = t; | ||
| 3077 | active_transactions++; | 4213 | active_transactions++; |
| 3078 | binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, | 4214 | binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, |
| 3079 | "release %d:%d transaction %d %s, still active\n", | 4215 | "release %d:%d transaction %d %s, still active\n", |
| @@ -3094,12 +4230,16 @@ static int binder_free_thread(struct binder_proc *proc, · 14 unmodified lines | |||
| 3094 | t = t->from_parent; | 4230 | t = t->from_parent; |
| 3095 | } else | 4231 | } else |
| 3096 | BUG(); | 4232 | BUG(); |
| 4233 | spin_unlock(&last_t->lock); | ||
| 4234 | if (t) | ||
| 4235 | spin_lock(&t->lock); | ||
| 3097 | } | 4236 | } |
| 4237 | binder_inner_proc_unlock(thread->proc); | ||
| 4238 | |||
| 3098 | if (send_reply) | 4239 | if (send_reply) |
| 3099 | binder_send_failed_reply(send_reply, BR_DEAD_REPLY); | 4240 | binder_send_failed_reply(send_reply, BR_DEAD_REPLY); |
| 3100 | binder_release_work(&thread->todo); | 4241 | binder_release_work(proc, &thread->todo); |
| 3101 | kfree(thread); | 4242 | binder_thread_dec_tmpref(thread); |
| 3102 | binder_stats_deleted(BINDER_STAT_THREAD); | ||
| 3103 | return active_transactions; | 4243 | return active_transactions; |
| 3104 | } | 4244 | } |
| 3105 | 4245 | ||
| @@ -3108,30 +4248,24 @@ static unsigned int binder_poll(struct file *filp, · 2 unmodified lines | |||
| 3108 | { | 4248 | { |
| 3109 | struct binder_proc *proc = filp->private_data; | 4249 | struct binder_proc *proc = filp->private_data; |
| 3110 | struct binder_thread *thread = NULL; | 4250 | struct binder_thread *thread = NULL; |
| 3111 | int wait_for_proc_work; | 4251 | bool wait_for_proc_work; |
| 3112 | |||
| 3113 | binder_lock(__func__); | ||
| 3114 | 4252 | ||
| 3115 | thread = binder_get_thread(proc); | 4253 | thread = binder_get_thread(proc); |
| 3116 | 4254 | ||
| 3117 | wait_for_proc_work = thread->transaction_stack == NULL && | 4255 | binder_inner_proc_lock(thread->proc); |
| 3118 | list_empty(&thread->todo) && thread->return_error == BR_OK; | 4256 | thread->looper |= BINDER_LOOPER_STATE_POLL; |
| 4257 | wait_for_proc_work = binder_available_for_proc_work_ilocked(thread); | ||
| 3119 | 4258 | ||
| 3120 | binder_unlock(__func__); | 4259 | binder_inner_proc_unlock(thread->proc); |
| 4260 | |||
| 4261 | if (binder_has_work(thread, wait_for_proc_work)) | ||
| 4262 | return POLLIN; | ||
| 4263 | |||
| 4264 | poll_wait(filp, &thread->wait, wait); | ||
| 4265 | |||
| 4266 | if (binder_has_thread_work(thread)) | ||
| 4267 | return POLLIN; | ||
| 3121 | 4268 | ||
| 3122 | if (wait_for_proc_work) { | ||
| 3123 | if (binder_has_proc_work(proc, thread)) | ||
| 3124 | return POLLIN; | ||
| 3125 | poll_wait(filp, &proc->wait, wait); | ||
| 3126 | if (binder_has_proc_work(proc, thread)) | ||
| 3127 | return POLLIN; | ||
| 3128 | } else { | ||
| 3129 | if (binder_has_thread_work(thread)) | ||
| 3130 | return POLLIN; | ||
| 3131 | poll_wait(filp, &thread->wait, wait); | ||
| 3132 | if (binder_has_thread_work(thread)) | ||
| 3133 | return POLLIN; | ||
| 3134 | } | ||
| 3135 | return 0; | 4269 | return 0; |
| 3136 | } | 4270 | } |
| 3137 | 4271 | ||
| @@ -3178,8 +4312,10 @@ static int binder_ioctl_write_read(struct file *filp, · 40 unmodified lines | |||
| 3178 | &bwr.read_consumed, | 4312 | &bwr.read_consumed, |
| 3179 | filp->f_flags & O_NONBLOCK); | 4313 | filp->f_flags & O_NONBLOCK); |
| 3180 | trace_binder_read_done(ret); | 4314 | trace_binder_read_done(ret); |
| 3181 | if (!list_empty(&proc->todo)) | 4315 | binder_inner_proc_lock(proc); |
| 3182 | wake_up_interruptible(&proc->wait); | 4316 | if (!binder_worklist_empty_ilocked(&proc->todo)) |
| 4317 | binder_wakeup_proc_ilocked(proc); | ||
| 4318 | binder_inner_proc_unlock(proc); | ||
| 3183 | if (ret < 0) { | 4319 | if (ret < 0) { |
| 3184 | if (copy_to_user(ubuf, &bwr, sizeof(bwr))) | 4320 | if (copy_to_user(ubuf, &bwr, sizeof(bwr))) |
| 3185 | ret = -EFAULT; | 4321 | ret = -EFAULT; |
| @@ -3204,9 +4340,10 @@ static int binder_ioctl_set_ctx_mgr(struct file *filp) · 18 unmodified lines | |||
| 3204 | int ret = 0; | 4340 | int ret = 0; |
| 3205 | struct binder_proc *proc = filp->private_data; | 4341 | struct binder_proc *proc = filp->private_data; |
| 3206 | struct binder_context *context = proc->context; | 4342 | struct binder_context *context = proc->context; |
| 3207 | 4343 | struct binder_node *new_node; | |
| 3208 | kuid_t curr_euid = current_euid(); | 4344 | kuid_t curr_euid = current_euid(); |
| 3209 | 4345 | ||
| 4346 | mutex_lock(&context->context_mgr_node_lock); | ||
| 3210 | if (context->binder_context_mgr_node) { | 4347 | if (context->binder_context_mgr_node) { |
| 3211 | pr_err("BINDER_SET_CONTEXT_MGR already set\n"); | 4348 | pr_err("BINDER_SET_CONTEXT_MGR already set\n"); |
| 3212 | ret = -EBUSY; | 4349 | ret = -EBUSY; |
| @@ -3227,19 +4364,49 @@ static int binder_ioctl_set_ctx_mgr(struct file *filp) · 14 unmodified lines | |||
| 3227 | } else { | 4364 | } else { |
| 3228 | context->binder_context_mgr_uid = curr_euid; | 4365 | context->binder_context_mgr_uid = curr_euid; |
| 3229 | } | 4366 | } |
| 3230 | context->binder_context_mgr_node = binder_new_node(proc, 0, 0); | 4367 | new_node = binder_new_node(proc, NULL); |
| 3231 | if (!context->binder_context_mgr_node) { | 4368 | if (!new_node) { |
| 3232 | ret = -ENOMEM; | 4369 | ret = -ENOMEM; |
| 3233 | goto out; | 4370 | goto out; |
| 3234 | } | 4371 | } |
| 3235 | context->binder_context_mgr_node->local_weak_refs++; | 4372 | binder_node_lock(new_node); |
| 3236 | context->binder_context_mgr_node->local_strong_refs++; | 4373 | new_node->local_weak_refs++; |
| 3237 | context->binder_context_mgr_node->has_strong_ref = 1; | 4374 | new_node->local_strong_refs++; |
| 3238 | context->binder_context_mgr_node->has_weak_ref = 1; | 4375 | new_node->has_strong_ref = 1; |
| 4376 | new_node->has_weak_ref = 1; | ||
| 4377 | context->binder_context_mgr_node = new_node; | ||
| 4378 | binder_node_unlock(new_node); | ||
| 4379 | binder_put_node(new_node); | ||
| 3239 | out: | 4380 | out: |
| 4381 | mutex_unlock(&context->context_mgr_node_lock); | ||
| 3240 | return ret; | 4382 | return ret; |
| 3241 | } | 4383 | } |
| 3242 | 4384 | ||
| 4385 | static int binder_ioctl_get_node_debug_info(struct binder_proc *proc, | ||
| 4386 | struct binder_node_debug_info *info) | ||
| 4387 | { | ||
| 4388 | struct rb_node *n; | ||
| 4389 | binder_uintptr_t ptr = info->ptr; | ||
| 4390 | |||
| 4391 | memset(info, 0, sizeof(*info)); | ||
| 4392 | |||
| 4393 | binder_inner_proc_lock(proc); | ||
| 4394 | for (n = rb_first(&proc->nodes); n != NULL; n = rb_next(n)) { | ||
| 4395 | struct binder_node *node = rb_entry(n, struct binder_node, | ||
| 4396 | rb_node); | ||
| 4397 | if (node->ptr > ptr) { | ||
| 4398 | info->ptr = node->ptr; | ||
| 4399 | info->cookie = node->cookie; | ||
| 4400 | info->has_strong_ref = node->has_strong_ref; | ||
| 4401 | info->has_weak_ref = node->has_weak_ref; | ||
| 4402 | break; | ||
| 4403 | } | ||
| 4404 | } | ||
| 4405 | binder_inner_proc_unlock(proc); | ||
| 4406 | |||
| 4407 | return 0; | ||
| 4408 | } | ||
| 4409 | |||
| 3243 | static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) | 4410 | static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
| 3244 | { | 4411 | { |
| 3245 | int ret; | 4412 | int ret; |
| @@ -3251,13 +4418,14 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) · 5 unmodified lines | |||
| 3251 | /*pr_info("binder_ioctl: %d:%d %x %lx\n", | 4418 | /*pr_info("binder_ioctl: %d:%d %x %lx\n", |
| 3252 | proc->pid, current->pid, cmd, arg);*/ | 4419 | proc->pid, current->pid, cmd, arg);*/ |
| 3253 | 4420 | ||
| 4421 | binder_selftest_alloc(&proc->alloc); | ||
| 4422 | |||
| 3254 | trace_binder_ioctl(cmd, arg); | 4423 | trace_binder_ioctl(cmd, arg); |
| 3255 | 4424 | ||
| 3256 | ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); | 4425 | ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); |
| 3257 | if (ret) | 4426 | if (ret) |
| 3258 | goto err_unlocked; | 4427 | goto err_unlocked; |
| 3259 | 4428 | ||
| 3260 | binder_lock(__func__); | ||
| 3261 | thread = binder_get_thread(proc); | 4429 | thread = binder_get_thread(proc); |
| 3262 | if (thread == NULL) { | 4430 | if (thread == NULL) { |
| 3263 | ret = -ENOMEM; | 4431 | ret = -ENOMEM; |
| @@ -3270,12 +4438,19 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) · 6 unmodified lines | |||
| 3270 | if (ret) | 4438 | if (ret) |
| 3271 | goto err; | 4439 | goto err; |
| 3272 | break; | 4440 | break; |
| 3273 | case BINDER_SET_MAX_THREADS: | 4441 | case BINDER_SET_MAX_THREADS: { |
| 3274 | if (copy_from_user(&proc->max_threads, ubuf, sizeof(proc->max_threads))) { | 4442 | int max_threads; |
| 4443 | |||
| 4444 | if (copy_from_user(&max_threads, ubuf, | ||
| 4445 | sizeof(max_threads))) { | ||
| 3275 | ret = -EINVAL; | 4446 | ret = -EINVAL; |
| 3276 | goto err; | 4447 | goto err; |
| 3277 | } | 4448 | } |
| 4449 | binder_inner_proc_lock(proc); | ||
| 4450 | proc->max_threads = max_threads; | ||
| 4451 | binder_inner_proc_unlock(proc); | ||
| 3278 | break; | 4452 | break; |
| 4453 | } | ||
| 3279 | case BINDER_SET_CONTEXT_MGR: | 4454 | case BINDER_SET_CONTEXT_MGR: |
| 3280 | ret = binder_ioctl_set_ctx_mgr(filp); | 4455 | ret = binder_ioctl_set_ctx_mgr(filp); |
| 3281 | if (ret) | 4456 | if (ret) |
| @@ -3284,7 +4459,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) · 2 unmodified lines | |||
| 3284 | case BINDER_THREAD_EXIT: | 4459 | case BINDER_THREAD_EXIT: |
| 3285 | binder_debug(BINDER_DEBUG_THREADS, "%d:%d exit\n", | 4460 | binder_debug(BINDER_DEBUG_THREADS, "%d:%d exit\n", |
| 3286 | proc->pid, thread->pid); | 4461 | proc->pid, thread->pid); |
| 3287 | binder_free_thread(proc, thread); | 4462 | binder_thread_release(proc, thread); |
| 3288 | thread = NULL; | 4463 | thread = NULL; |
| 3289 | break; | 4464 | break; |
| 3290 | case BINDER_VERSION: { | 4465 | case BINDER_VERSION: { |
| @@ -3301,6 +4476,24 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) · 10 unmodified lines | |||
| 3301 | } | 4476 | } |
| 3302 | break; | 4477 | break; |
| 3303 | } | 4478 | } |
| 4479 | case BINDER_GET_NODE_DEBUG_INFO: { | ||
| 4480 | struct binder_node_debug_info info; | ||
| 4481 | |||
| 4482 | if (copy_from_user(&info, ubuf, sizeof(info))) { | ||
| 4483 | ret = -EFAULT; | ||
| 4484 | goto err; | ||
| 4485 | } | ||
| 4486 | |||
| 4487 | ret = binder_ioctl_get_node_debug_info(proc, &info); | ||
| 4488 | if (ret < 0) | ||
| 4489 | goto err; | ||
| 4490 | |||
| 4491 | if (copy_to_user(ubuf, &info, sizeof(info))) { | ||
| 4492 | ret = -EFAULT; | ||
| 4493 | goto err; | ||
| 4494 | } | ||
| 4495 | break; | ||
| 4496 | } | ||
| 3304 | default: | 4497 | default: |
| 3305 | ret = -EINVAL; | 4498 | ret = -EINVAL; |
| 3306 | goto err; | 4499 | goto err; |
| @@ -3308,8 +4501,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) · 1 unmodified line | |||
| 3308 | ret = 0; | 4501 | ret = 0; |
| 3309 | err: | 4502 | err: |
| 3310 | if (thread) | 4503 | if (thread) |
| 3311 | thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN; | 4504 | thread->looper_need_return = false; |
| 3312 | binder_unlock(__func__); | ||
| 3313 | wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); | 4505 | wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2); |
| 3314 | if (ret && ret != -ERESTARTSYS) | 4506 | if (ret && ret != -ERESTARTSYS) |
| 3315 | pr_info("%d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret); | 4507 | pr_info("%d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret); |
| @@ -3338,8 +4530,7 @@ static void binder_vma_close(struct vm_area_struct *vma) · 22 unmodified lines | |||
| 3338 | proc->pid, vma->vm_start, vma->vm_end, | 4530 | proc->pid, vma->vm_start, vma->vm_end, |
| 3339 | (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, | 4531 | (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, |
| 3340 | (unsigned long)pgprot_val(vma->vm_page_prot)); | 4532 | (unsigned long)pgprot_val(vma->vm_page_prot)); |
| 3341 | proc->vma = NULL; | 4533 | binder_alloc_vma_close(&proc->alloc); |
| 3342 | proc->vma_vm_mm = NULL; | ||
| 3343 | binder_defer_work(proc, BINDER_DEFERRED_PUT_FILES); | 4534 | binder_defer_work(proc, BINDER_DEFERRED_PUT_FILES); |
| 3344 | } | 4535 | } |
| 3345 | 4536 | ||
| @@ -3357,10 +4548,8 @@ static const struct vm_operations_struct binder_vm_ops = { · 11 unmodified lines | |||
| 3357 | static int binder_mmap(struct file *filp, struct vm_area_struct *vma) | 4548 | static int binder_mmap(struct file *filp, struct vm_area_struct *vma) |
| 3358 | { | 4549 | { |
| 3359 | int ret; | 4550 | int ret; |
| 3360 | struct vm_struct *area; | ||
| 3361 | struct binder_proc *proc = filp->private_data; | 4551 | struct binder_proc *proc = filp->private_data; |
| 3362 | const char *failure_string; | 4552 | const char *failure_string; |
| 3363 | struct binder_buffer *buffer; | ||
| 3364 | 4553 | ||
| 3365 | if (proc->tsk != current->group_leader) | 4554 | if (proc->tsk != current->group_leader) |
| 3366 | return -EINVAL; | 4555 | return -EINVAL; |
| @@ -3369,8 +4558,8 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) · 2 unmodified lines | |||
| 3369 | vma->vm_end = vma->vm_start + SZ_4M; | 4558 | vma->vm_end = vma->vm_start + SZ_4M; |
| 3370 | 4559 | ||
| 3371 | binder_debug(BINDER_DEBUG_OPEN_CLOSE, | 4560 | binder_debug(BINDER_DEBUG_OPEN_CLOSE, |
| 3372 | "binder_mmap: %d %lx-%lx (%ld K) vma %lx pagep %lx\n", | 4561 | "%s: %d %lx-%lx (%ld K) vma %lx pagep %lx\n", |
| 3373 | proc->pid, vma->vm_start, vma->vm_end, | 4562 | __func__, proc->pid, vma->vm_start, vma->vm_end, |
| 3374 | (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, | 4563 | (vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags, |
| 3375 | (unsigned long)pgprot_val(vma->vm_page_prot)); | 4564 | (unsigned long)pgprot_val(vma->vm_page_prot)); |
| 3376 | 4565 | ||
| @@ -3380,73 +4569,15 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma) · 3 unmodified lines | |||
| 3380 | goto err_bad_arg; | 4569 | goto err_bad_arg; |
| 3381 | } | 4570 | } |
| 3382 | vma->vm_flags = (vma->vm_flags | VM_DONTCOPY) & ~VM_MAYWRITE; | 4571 | vma->vm_flags = (vma->vm_flags | VM_DONTCOPY) & ~VM_MAYWRITE; |
| 3383 | |||
| 3384 | mutex_lock(&binder_mmap_lock); | ||
| 3385 | if (proc->buffer) { | ||
| 3386 | ret = -EBUSY; | ||
| 3387 | failure_string = "already mapped"; | ||
| 3388 | goto err_already_mapped; | ||
| 3389 | } | ||
| 3390 | |||
| 3391 | area = get_vm_area(vma->vm_end - vma->vm_start, VM_IOREMAP); | ||
| 3392 | if (area == NULL) { | ||
| 3393 | ret = -ENOMEM; | ||
| 3394 | failure_string = "get_vm_area"; | ||
| 3395 | goto err_get_vm_area_failed; | ||
| 3396 | } | ||
| 3397 | proc->buffer = area->addr; | ||
| 3398 | proc->user_buffer_offset = vma->vm_start - (uintptr_t)proc->buffer; | ||
| 3399 | mutex_unlock(&binder_mmap_lock); | ||
| 3400 | |||
| 3401 | #ifdef CONFIG_CPU_CACHE_VIPT | ||
| 3402 | if (cache_is_vipt_aliasing()) { | ||
| 3403 | while (CACHE_COLOUR((vma->vm_start ^ (uint32_t)proc->buffer))) { | ||
| 3404 | pr_info("binder_mmap: %d %lx-%lx maps %p bad alignment\n", proc->pid, vma->vm_start, vma->vm_end, proc->buffer); | ||
| 3405 | vma->vm_start += PAGE_SIZE; | ||
| 3406 | } | ||
| 3407 | } | ||
| 3408 | #endif | ||
| 3409 | proc->pages = kzalloc(sizeof(proc->pages[0]) * ((vma->vm_end - vma->vm_start) / PAGE_SIZE), GFP_KERNEL); | ||
| 3410 | if (proc->pages == NULL) { | ||
| 3411 | ret = -ENOMEM; | ||
| 3412 | failure_string = "alloc page array"; | ||
| 3413 | goto err_alloc_pages_failed; | ||
| 3414 | } | ||
| 3415 | proc->buffer_size = vma->vm_end - vma->vm_start; | ||
| 3416 | |||
| 3417 | vma->vm_ops = &binder_vm_ops; | 4572 | vma->vm_ops = &binder_vm_ops; |
| 3418 | vma->vm_private_data = proc; | 4573 | vma->vm_private_data = proc; |
| 3419 | 4574 | ||
| 3420 | if (binder_update_page_range(proc, 1, proc->buffer, proc->buffer + PAGE_SIZE, vma)) { | 4575 | ret = binder_alloc_mmap_handler(&proc->alloc, vma); |
| 3421 | ret = -ENOMEM; | 4576 | if (ret) |
| 3422 | failure_string = "alloc small buf"; | 4577 | return ret; |
| 3423 | goto err_alloc_small_buf_failed; | ||
| 3424 | } | ||
| 3425 | buffer = proc->buffer; | ||
| 3426 | INIT_LIST_HEAD(&proc->buffers); | ||
| 3427 | list_add(&buffer->entry, &proc->buffers); | ||
| 3428 | buffer->free = 1; | ||
| 3429 | binder_insert_free_buffer(proc, buffer); | ||
| 3430 | proc->free_async_space = proc->buffer_size / 2; | ||
| 3431 | barrier(); | ||
| 3432 | proc->files = get_files_struct(current); | 4578 | proc->files = get_files_struct(current); |
| 3433 | proc->vma = vma; | ||
| 3434 | proc->vma_vm_mm = vma->vm_mm; | ||
| 3435 | |||
| 3436 | /*pr_info("binder_mmap: %d %lx-%lx maps %p\n", | ||
| 3437 | proc->pid, vma->vm_start, vma->vm_end, proc->buffer);*/ | ||
| 3438 | return 0; | 4579 | return 0; |
| 3439 | 4580 | ||
| 3440 | err_alloc_small_buf_failed: | ||
| 3441 | kfree(proc->pages); | ||
| 3442 | proc->pages = NULL; | ||
| 3443 | err_alloc_pages_failed: | ||
| 3444 | mutex_lock(&binder_mmap_lock); | ||
| 3445 | vfree(proc->buffer); | ||
| 3446 | proc->buffer = NULL; | ||
| 3447 | err_get_vm_area_failed: | ||
| 3448 | err_already_mapped: | ||
| 3449 | mutex_unlock(&binder_mmap_lock); | ||
| 3450 | err_bad_arg: | 4581 | err_bad_arg: |
| 3451 | pr_err("binder_mmap: %d %lx-%lx %s failed %d\n", | 4582 | pr_err("binder_mmap: %d %lx-%lx %s failed %d\n", |
| 3452 | proc->pid, vma->vm_start, vma->vm_end, failure_string, ret); | 4583 | proc->pid, vma->vm_start, vma->vm_end, failure_string, ret); |
| @@ -3464,24 +4595,26 @@ static int binder_open(struct inode *nodp, struct file *filp) · 11 unmodified lines | |||
| 3464 | proc = kzalloc(sizeof(*proc), GFP_KERNEL); | 4595 | proc = kzalloc(sizeof(*proc), GFP_KERNEL); |
| 3465 | if (proc == NULL) | 4596 | if (proc == NULL) |
| 3466 | return -ENOMEM; | 4597 | return -ENOMEM; |
| 4598 | spin_lock_init(&proc->inner_lock); | ||
| 4599 | spin_lock_init(&proc->outer_lock); | ||
| 3467 | get_task_struct(current->group_leader); | 4600 | get_task_struct(current->group_leader); |
| 3468 | proc->tsk = current->group_leader; | 4601 | proc->tsk = current->group_leader; |
| 3469 | INIT_LIST_HEAD(&proc->todo); | 4602 | INIT_LIST_HEAD(&proc->todo); |
| 3470 | init_waitqueue_head(&proc->wait); | ||
| 3471 | proc->default_priority = task_nice(current); | 4603 | proc->default_priority = task_nice(current); |
| 3472 | binder_dev = container_of(filp->private_data, struct binder_device, | 4604 | binder_dev = container_of(filp->private_data, struct binder_device, |
| 3473 | miscdev); | 4605 | miscdev); |
| 3474 | proc->context = &binder_dev->context; | 4606 | proc->context = &binder_dev->context; |
| 3475 | 4607 | binder_alloc_init(&proc->alloc); | |
| 3476 | binder_lock(__func__); | ||
| 3477 | 4608 | ||
| 3478 | binder_stats_created(BINDER_STAT_PROC); | 4609 | binder_stats_created(BINDER_STAT_PROC); |
| 3479 | hlist_add_head(&proc->proc_node, &binder_procs); | ||
| 3480 | proc->pid = current->group_leader->pid; | 4610 | proc->pid = current->group_leader->pid; |
| 3481 | INIT_LIST_HEAD(&proc->delivered_death); | 4611 | INIT_LIST_HEAD(&proc->delivered_death); |
| 4612 | INIT_LIST_HEAD(&proc->waiting_threads); | ||
| 3482 | filp->private_data = proc; | 4613 | filp->private_data = proc; |
| 3483 | 4614 | ||
| 3484 | binder_unlock(__func__); | 4615 | mutex_lock(&binder_procs_lock); |
| 4616 | hlist_add_head(&proc->proc_node, &binder_procs); | ||
| 4617 | mutex_unlock(&binder_procs_lock); | ||
| 3485 | 4618 | ||
| 3486 | if (binder_debugfs_dir_entry_proc) { | 4619 | if (binder_debugfs_dir_entry_proc) { |
| 3487 | char strbuf[11]; | 4620 | char strbuf[11]; |
| @@ -3517,16 +4650,17 @@ static void binder_deferred_flush(struct binder_proc *proc) · 29 unmodified lines | |||
| 3517 | struct rb_node *n; | 4650 | struct rb_node *n; |
| 3518 | int wake_count = 0; | 4651 | int wake_count = 0; |
| 3519 | 4652 | ||
| 4653 | binder_inner_proc_lock(proc); | ||
| 3520 | for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) { | 4654 | for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) { |
| 3521 | struct binder_thread *thread = rb_entry(n, struct binder_thread, rb_node); | 4655 | struct binder_thread *thread = rb_entry(n, struct binder_thread, rb_node); |
| 3522 | 4656 | ||
| 3523 | thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN; | 4657 | thread->looper_need_return = true; |
| 3524 | if (thread->looper & BINDER_LOOPER_STATE_WAITING) { | 4658 | if (thread->looper & BINDER_LOOPER_STATE_WAITING) { |
| 3525 | wake_up_interruptible(&thread->wait); | 4659 | wake_up_interruptible(&thread->wait); |
| 3526 | wake_count++; | 4660 | wake_count++; |
| 3527 | } | 4661 | } |
| 3528 | } | 4662 | } |
| 3529 | wake_up_interruptible_all(&proc->wait); | 4663 | binder_inner_proc_unlock(proc); |
| 3530 | 4664 | ||
| 3531 | binder_debug(BINDER_DEBUG_OPEN_CLOSE, | 4665 | binder_debug(BINDER_DEBUG_OPEN_CLOSE, |
| 3532 | "binder_flush: %d woke %d threads\n", proc->pid, | 4666 | "binder_flush: %d woke %d threads\n", proc->pid, |
| @@ -3547,13 +4681,21 @@ static int binder_node_release(struct binder_node *node, int refs) · 14 unmodified lines | |||
| 3547 | { | 4681 | { |
| 3548 | struct binder_ref *ref; | 4682 | struct binder_ref *ref; |
| 3549 | int death = 0; | 4683 | int death = 0; |
| 4684 | struct binder_proc *proc = node->proc; | ||
| 3550 | 4685 | ||
| 3551 | list_del_init(&node->work.entry); | 4686 | binder_release_work(proc, &node->async_todo); |
| 3552 | binder_release_work(&node->async_todo); | ||
| 3553 | 4687 | ||
| 3554 | if (hlist_empty(&node->refs)) { | 4688 | binder_node_lock(node); |
| 3555 | kfree(node); | 4689 | binder_inner_proc_lock(proc); |
| 3556 | binder_stats_deleted(BINDER_STAT_NODE); | 4690 | binder_dequeue_work_ilocked(&node->work); |
| 4691 | /* | ||
| 4692 | * The caller must have taken a temporary ref on the node, | ||
| 4693 | */ | ||
| 4694 | BUG_ON(!node->tmp_refs); | ||
| 4695 | if (hlist_empty(&node->refs) && node->tmp_refs == 1) { | ||
| 4696 | binder_inner_proc_unlock(proc); | ||
| 4697 | binder_node_unlock(node); | ||
| 4698 | binder_free_node(node); | ||
| 3557 | 4699 | ||
| 3558 | return refs; | 4700 | return refs; |
| 3559 | } | 4701 | } |
| @@ -3561,45 +4703,58 @@ static int binder_node_release(struct binder_node *node, int refs) · 1 unmodified line | |||
| 3561 | node->proc = NULL; | 4703 | node->proc = NULL; |
| 3562 | node->local_strong_refs = 0; | 4704 | node->local_strong_refs = 0; |
| 3563 | node->local_weak_refs = 0; | 4705 | node->local_weak_refs = 0; |
| 4706 | binder_inner_proc_unlock(proc); | ||
| 4707 | |||
| 4708 | spin_lock(&binder_dead_nodes_lock); | ||
| 3564 | hlist_add_head(&node->dead_node, &binder_dead_nodes); | 4709 | hlist_add_head(&node->dead_node, &binder_dead_nodes); |
| 4710 | spin_unlock(&binder_dead_nodes_lock); | ||
| 3565 | 4711 | ||
| 3566 | hlist_for_each_entry(ref, &node->refs, node_entry) { | 4712 | hlist_for_each_entry(ref, &node->refs, node_entry) { |
| 3567 | refs++; | 4713 | refs++; |
| 3568 | 4714 | /* | |
| 3569 | if (!ref->death) | 4715 | * Need the node lock to synchronize |
| 4716 | * with new notification requests and the | ||
| 4717 | * inner lock to synchronize with queued | ||
| 4718 | * death notifications. | ||
| 4719 | */ | ||
| 4720 | binder_inner_proc_lock(ref->proc); | ||
| 4721 | if (!ref->death) { | ||
| 4722 | binder_inner_proc_unlock(ref->proc); | ||
| 3570 | continue; | 4723 | continue; |
| 4724 | } | ||
| 3571 | 4725 | ||
| 3572 | death++; | 4726 | death++; |
| 3573 | 4727 | ||
| 3574 | if (list_empty(&ref->death->work.entry)) { | 4728 | BUG_ON(!list_empty(&ref->death->work.entry)); |
| 3575 | ref->death->work.type = BINDER_WORK_DEAD_BINDER; | 4729 | ref->death->work.type = BINDER_WORK_DEAD_BINDER; |
| 3576 | list_add_tail(&ref->death->work.entry, | 4730 | binder_enqueue_work_ilocked(&ref->death->work, |
| 3577 | &ref->proc->todo); | 4731 | &ref->proc->todo); |
| 3578 | wake_up_interruptible(&ref->proc->wait); | 4732 | binder_wakeup_proc_ilocked(ref->proc); |
| 3579 | } else | 4733 | binder_inner_proc_unlock(ref->proc); |
| 3580 | BUG(); | ||
| 3581 | } | 4734 | } |
| 3582 | 4735 | ||
| 3583 | binder_debug(BINDER_DEBUG_DEAD_BINDER, | 4736 | binder_debug(BINDER_DEBUG_DEAD_BINDER, |
| 3584 | "node %d now dead, refs %d, death %d\n", | 4737 | "node %d now dead, refs %d, death %d\n", |
| 3585 | node->debug_id, refs, death); | 4738 | node->debug_id, refs, death); |
| 4739 | binder_node_unlock(node); | ||
| 4740 | binder_put_node(node); | ||
| 3586 | 4741 | ||
| 3587 | return refs; | 4742 | return refs; |
| 3588 | } | 4743 | } |
| 3589 | 4744 | ||
| 3590 | static void binder_deferred_release(struct binder_proc *proc) | 4745 | static void binder_deferred_release(struct binder_proc *proc) |
| 3591 | { | 4746 | { |
| 3592 | struct binder_transaction *t; | ||
| 3593 | struct binder_context *context = proc->context; | 4747 | struct binder_context *context = proc->context; |
| 3594 | struct rb_node *n; | 4748 | struct rb_node *n; |
| 3595 | int threads, nodes, incoming_refs, outgoing_refs, buffers, | 4749 | int threads, nodes, incoming_refs, outgoing_refs, active_transactions; |
| 3596 | active_transactions, page_count; | ||
| 3597 | 4750 | ||
| 3598 | BUG_ON(proc->vma); | ||
| 3599 | BUG_ON(proc->files); | 4751 | BUG_ON(proc->files); |
| 3600 | 4752 | ||
| 4753 | mutex_lock(&binder_procs_lock); | ||
| 3601 | hlist_del(&proc->proc_node); | 4754 | hlist_del(&proc->proc_node); |
| 4755 | mutex_unlock(&binder_procs_lock); | ||
| 3602 | 4756 | ||
| 4757 | mutex_lock(&context->context_mgr_node_lock); | ||
| 3603 | if (context->binder_context_mgr_node && | 4758 | if (context->binder_context_mgr_node && |
| 3604 | context->binder_context_mgr_node->proc == proc) { | 4759 | context->binder_context_mgr_node->proc == proc) { |
| 3605 | binder_debug(BINDER_DEBUG_DEAD_BINDER, | 4760 | binder_debug(BINDER_DEBUG_DEAD_BINDER, |
| @@ -3607,15 +4762,25 @@ static void binder_deferred_release(struct binder_proc *proc) · 1 unmodified line | |||
| 3607 | __func__, proc->pid); | 4762 | __func__, proc->pid); |
| 3608 | context->binder_context_mgr_node = NULL; | 4763 | context->binder_context_mgr_node = NULL; |
| 3609 | } | 4764 | } |
| 4765 | mutex_unlock(&context->context_mgr_node_lock); | ||
| 4766 | binder_inner_proc_lock(proc); | ||
| 4767 | /* | ||
| 4768 | * Make sure proc stays alive after we | ||
| 4769 | * remove all the threads | ||
| 4770 | */ | ||
| 4771 | proc->tmp_ref++; | ||
| 3610 | 4772 | ||
| 4773 | proc->is_dead = true; | ||
| 3611 | threads = 0; | 4774 | threads = 0; |
| 3612 | active_transactions = 0; | 4775 | active_transactions = 0; |
| 3613 | while ((n = rb_first(&proc->threads))) { | 4776 | while ((n = rb_first(&proc->threads))) { |
| 3614 | struct binder_thread *thread; | 4777 | struct binder_thread *thread; |
| 3615 | 4778 | ||
| 3616 | thread = rb_entry(n, struct binder_thread, rb_node); | 4779 | thread = rb_entry(n, struct binder_thread, rb_node); |
| 4780 | binder_inner_proc_unlock(proc); | ||
| 3617 | threads++; | 4781 | threads++; |
| 3618 | active_transactions += binder_free_thread(proc, thread); | 4782 | active_transactions += binder_thread_release(proc, thread); |
| 4783 | binder_inner_proc_lock(proc); | ||
| 3619 | } | 4784 | } |
| 3620 | 4785 | ||
| 3621 | nodes = 0; | 4786 | nodes = 0; |
| @@ -3625,73 +4790,42 @@ static void binder_deferred_release(struct binder_proc *proc) · 3 unmodified lines | |||
| 3625 | 4790 | ||
| 3626 | node = rb_entry(n, struct binder_node, rb_node); | 4791 | node = rb_entry(n, struct binder_node, rb_node); |
| 3627 | nodes++; | 4792 | nodes++; |
| 4793 | /* | ||
| 4794 | * take a temporary ref on the node before | ||
| 4795 | * calling binder_node_release() which will either | ||
| 4796 | * kfree() the node or call binder_put_node() | ||
| 4797 | */ | ||
| 4798 | binder_inc_node_tmpref_ilocked(node); | ||
| 3628 | rb_erase(&node->rb_node, &proc->nodes); | 4799 | rb_erase(&node->rb_node, &proc->nodes); |
| 4800 | binder_inner_proc_unlock(proc); | ||
| 3629 | incoming_refs = binder_node_release(node, incoming_refs); | 4801 | incoming_refs = binder_node_release(node, incoming_refs); |
| 4802 | binder_inner_proc_lock(proc); | ||
| 3630 | } | 4803 | } |
| 4804 | binder_inner_proc_unlock(proc); | ||
| 3631 | 4805 | ||
| 3632 | outgoing_refs = 0; | 4806 | outgoing_refs = 0; |
| 4807 | binder_proc_lock(proc); | ||
| 3633 | while ((n = rb_first(&proc->refs_by_desc))) { | 4808 | while ((n = rb_first(&proc->refs_by_desc))) { |
| 3634 | struct binder_ref *ref; | 4809 | struct binder_ref *ref; |
| 3635 | 4810 | ||
| 3636 | ref = rb_entry(n, struct binder_ref, rb_node_desc); | 4811 | ref = rb_entry(n, struct binder_ref, rb_node_desc); |
| 3637 | outgoing_refs++; | 4812 | outgoing_refs++; |
| 3638 | binder_delete_ref(ref); | 4813 | binder_cleanup_ref_olocked(ref); |
| 3639 | } | 4814 | binder_proc_unlock(proc); |
| 3640 | 4815 | binder_free_ref(ref); | |
| 3641 | binder_release_work(&proc->todo); | 4816 | binder_proc_lock(proc); |
| 3642 | binder_release_work(&proc->delivered_death); | ||
| 3643 | |||
| 3644 | buffers = 0; | ||
| 3645 | while ((n = rb_first(&proc->allocated_buffers))) { | ||
| 3646 | struct binder_buffer *buffer; | ||
| 3647 | |||
| 3648 | buffer = rb_entry(n, struct binder_buffer, rb_node); | ||
| 3649 | |||
| 3650 | t = buffer->transaction; | ||
| 3651 | if (t) { | ||
| 3652 | t->buffer = NULL; | ||
| 3653 | buffer->transaction = NULL; | ||
| 3654 | pr_err("release proc %d, transaction %d, not freed\n", | ||
| 3655 | proc->pid, t->debug_id); | ||
| 3656 | /*BUG();*/ | ||
| 3657 | } | ||
| 3658 | |||
| 3659 | binder_free_buf(proc, buffer); | ||
| 3660 | buffers++; | ||
| 3661 | } | 4817 | } |
| 4818 | binder_proc_unlock(proc); | ||
| 3662 | 4819 | ||
| 3663 | binder_stats_deleted(BINDER_STAT_PROC); | 4820 | binder_release_work(proc, &proc->todo); |
| 3664 | 4821 | binder_release_work(proc, &proc->delivered_death); | |
| 3665 | page_count = 0; | ||
| 3666 | if (proc->pages) { | ||
| 3667 | int i; | ||
| 3668 | |||
| 3669 | for (i = 0; i < proc->buffer_size / PAGE_SIZE; i++) { | ||
| 3670 | void *page_addr; | ||
| 3671 | |||
| 3672 | if (!proc->pages[i]) | ||
| 3673 | continue; | ||
| 3674 | |||
| 3675 | page_addr = proc->buffer + i * PAGE_SIZE; | ||
| 3676 | binder_debug(BINDER_DEBUG_BUFFER_ALLOC, | ||
| 3677 | "%s: %d: page %d at %p not freed\n", | ||
| 3678 | __func__, proc->pid, i, page_addr); | ||
| 3679 | unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE); | ||
| 3680 | __free_page(proc->pages[i]); | ||
| 3681 | page_count++; | ||
| 3682 | } | ||
| 3683 | kfree(proc->pages); | ||
| 3684 | vfree(proc->buffer); | ||
| 3685 | } | ||
| 3686 | |||
| 3687 | put_task_struct(proc->tsk); | ||
| 3688 | 4822 | ||
| 3689 | binder_debug(BINDER_DEBUG_OPEN_CLOSE, | 4823 | binder_debug(BINDER_DEBUG_OPEN_CLOSE, |
| 3690 | "%s: %d threads %d, nodes %d (ref %d), refs %d, active transactions %d, buffers %d, pages %d\n", | 4824 | "%s: %d threads %d, nodes %d (ref %d), refs %d, active transactions %d\n", |
| 3691 | __func__, proc->pid, threads, nodes, incoming_refs, | 4825 | __func__, proc->pid, threads, nodes, incoming_refs, |
| 3692 | outgoing_refs, active_transactions, buffers, page_count); | 4826 | outgoing_refs, active_transactions); |
| 3693 | 4827 | ||
| 3694 | kfree(proc); | 4828 | binder_proc_dec_tmpref(proc); |
| 3695 | } | 4829 | } |
| 3696 | 4830 | ||
| 3697 | static void binder_deferred_func(struct work_struct *work) | 4831 | static void binder_deferred_func(struct work_struct *work) |
| @@ -3702,7 +4836,6 @@ static void binder_deferred_func(struct work_struct *work) · 4 unmodified lines | |||
| 3702 | int defer; | 4836 | int defer; |
| 3703 | 4837 | ||
| 3704 | do { | 4838 | do { |
| 3705 | binder_lock(__func__); | ||
| 3706 | mutex_lock(&binder_deferred_lock); | 4839 | mutex_lock(&binder_deferred_lock); |
| 3707 | if (!hlist_empty(&binder_deferred_list)) { | 4840 | if (!hlist_empty(&binder_deferred_list)) { |
| 3708 | proc = hlist_entry(binder_deferred_list.first, | 4841 | proc = hlist_entry(binder_deferred_list.first, |
| @@ -3729,7 +4862,6 @@ static void binder_deferred_func(struct work_struct *work) · 20 unmodified lines | |||
| 3729 | if (defer & BINDER_DEFERRED_RELEASE) | 4862 | if (defer & BINDER_DEFERRED_RELEASE) |
| 3730 | binder_deferred_release(proc); /* frees proc */ | 4863 | binder_deferred_release(proc); /* frees proc */ |
| 3731 | 4864 | ||
| 3732 | binder_unlock(__func__); | ||
| 3733 | if (files) | 4865 | if (files) |
| 3734 | put_files_struct(files); | 4866 | put_files_struct(files); |
| 3735 | } while (proc); | 4867 | } while (proc); |
| @@ -3749,41 +4881,51 @@ binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer) · 13 unmodified lines | |||
| 3749 | mutex_unlock(&binder_deferred_lock); | 4881 | mutex_unlock(&binder_deferred_lock); |
| 3750 | } | 4882 | } |
| 3751 | 4883 | ||
| 3752 | static void print_binder_transaction(struct seq_file *m, const char *prefix, | 4884 | static void print_binder_transaction_ilocked(struct seq_file *m, |
| 3753 | struct binder_transaction *t) | ||
587 more lines aren’t shown here.
| @@ -0,0 +1,1009 @@ | |||
| 1 | /* binder_alloc.c | ||
| 2 | * | ||
| 3 | * Android IPC Subsystem | ||
| 4 | * | ||
| 5 | * Copyright (C) 2007-2017 Google, Inc. | ||
| 6 | * | ||
| 7 | * This software is licensed under the terms of the GNU General Public | ||
| 8 | * License version 2, as published by the Free Software Foundation, and | ||
| 9 | * may be copied, distributed, and modified under those terms. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | */ | ||
| 17 | |||
| 18 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
| 19 | |||
| 20 | #include <asm/cacheflush.h> | ||
| 21 | #include <linux/list.h> | ||
| 22 | #include <linux/sched/mm.h> | ||
| 23 | #include <linux/module.h> | ||
| 24 | #include <linux/rtmutex.h> | ||
| 25 | #include <linux/rbtree.h> | ||
| 26 | #include <linux/seq_file.h> | ||
| 27 | #include <linux/vmalloc.h> | ||
| 28 | #include <linux/slab.h> | ||
| 29 | #include <linux/sched.h> | ||
| 30 | #include <linux/list_lru.h> | ||
| 31 | #include "binder_alloc.h" | ||
| 32 | #include "binder_trace.h" | ||
| 33 | |||
| 34 | struct list_lru binder_alloc_lru; | ||
| 35 | |||
| 36 | static DEFINE_MUTEX(binder_alloc_mmap_lock); | ||
| 37 | |||
| 38 | enum { | ||
| 39 | BINDER_DEBUG_OPEN_CLOSE = 1U << 1, | ||
| 40 | BINDER_DEBUG_BUFFER_ALLOC = 1U << 2, | ||
| 41 | BINDER_DEBUG_BUFFER_ALLOC_ASYNC = 1U << 3, | ||
| 42 | }; | ||
| 43 | static uint32_t binder_alloc_debug_mask; | ||
| 44 | |||
| 45 | module_param_named(debug_mask, binder_alloc_debug_mask, | ||
| 46 | uint, 0644); | ||
| 47 | |||
| 48 | #define binder_alloc_debug(mask, x...) \ | ||
| 49 | do { \ | ||
| 50 | if (binder_alloc_debug_mask & mask) \ | ||
| 51 | pr_info(x); \ | ||
| 52 | } while (0) | ||
| 53 | |||
| 54 | static struct binder_buffer *binder_buffer_next(struct binder_buffer *buffer) | ||
| 55 | { | ||
| 56 | return list_entry(buffer->entry.next, struct binder_buffer, entry); | ||
| 57 | } | ||
| 58 | |||
| 59 | static struct binder_buffer *binder_buffer_prev(struct binder_buffer *buffer) | ||
| 60 | { | ||
| 61 | return list_entry(buffer->entry.prev, struct binder_buffer, entry); | ||
| 62 | } | ||
| 63 | |||
| 64 | static size_t binder_alloc_buffer_size(struct binder_alloc *alloc, | ||
| 65 | struct binder_buffer *buffer) | ||
| 66 | { | ||
| 67 | if (list_is_last(&buffer->entry, &alloc->buffers)) | ||
| 68 | return (u8 *)alloc->buffer + | ||
| 69 | alloc->buffer_size - (u8 *)buffer->data; | ||
| 70 | return (u8 *)binder_buffer_next(buffer)->data - (u8 *)buffer->data; | ||
| 71 | } | ||
| 72 | |||
| 73 | static void binder_insert_free_buffer(struct binder_alloc *alloc, | ||
| 74 | struct binder_buffer *new_buffer) | ||
| 75 | { | ||
| 76 | struct rb_node **p = &alloc->free_buffers.rb_node; | ||
| 77 | struct rb_node *parent = NULL; | ||
| 78 | struct binder_buffer *buffer; | ||
| 79 | size_t buffer_size; | ||
| 80 | size_t new_buffer_size; | ||
| 81 | |||
| 82 | BUG_ON(!new_buffer->free); | ||
| 83 | |||
| 84 | new_buffer_size = binder_alloc_buffer_size(alloc, new_buffer); | ||
| 85 | |||
| 86 | binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, | ||
| 87 | "%d: add free buffer, size %zd, at %pK\n", | ||
| 88 | alloc->pid, new_buffer_size, new_buffer); | ||
| 89 | |||
| 90 | while (*p) { | ||
| 91 | parent = *p; | ||
| 92 | buffer = rb_entry(parent, struct binder_buffer, rb_node); | ||
| 93 | BUG_ON(!buffer->free); | ||
| 94 | |||
| 95 | buffer_size = binder_alloc_buffer_size(alloc, buffer); | ||
| 96 | |||
| 97 | if (new_buffer_size < buffer_size) | ||
| 98 | p = &parent->rb_left; | ||
| 99 | else | ||
| 100 | p = &parent->rb_right; | ||
| 101 | } | ||
| 102 | rb_link_node(&new_buffer->rb_node, parent, p); | ||
| 103 | rb_insert_color(&new_buffer->rb_node, &alloc->free_buffers); | ||
| 104 | } | ||
| 105 | |||
| 106 | static void binder_insert_allocated_buffer_locked( | ||
| 107 | struct binder_alloc *alloc, struct binder_buffer *new_buffer) | ||
| 108 | { | ||
| 109 | struct rb_node **p = &alloc->allocated_buffers.rb_node; | ||
| 110 | struct rb_node *parent = NULL; | ||
| 111 | struct binder_buffer *buffer; | ||
| 112 | |||
| 113 | BUG_ON(new_buffer->free); | ||
| 114 | |||
| 115 | while (*p) { | ||
| 116 | parent = *p; | ||
| 117 | buffer = rb_entry(parent, struct binder_buffer, rb_node); | ||
| 118 | BUG_ON(buffer->free); | ||
| 119 | |||
| 120 | if (new_buffer->data < buffer->data) | ||
| 121 | p = &parent->rb_left; | ||
| 122 | else if (new_buffer->data > buffer->data) | ||
| 123 | p = &parent->rb_right; | ||
| 124 | else | ||
| 125 | BUG(); | ||
| 126 | } | ||
| 127 | rb_link_node(&new_buffer->rb_node, parent, p); | ||
| 128 | rb_insert_color(&new_buffer->rb_node, &alloc->allocated_buffers); | ||
| 129 | } | ||
| 130 | |||
| 131 | static struct binder_buffer *binder_alloc_prepare_to_free_locked( | ||
| 132 | struct binder_alloc *alloc, | ||
| 133 | uintptr_t user_ptr) | ||
| 134 | { | ||
| 135 | struct rb_node *n = alloc->allocated_buffers.rb_node; | ||
| 136 | struct binder_buffer *buffer; | ||
| 137 | void *kern_ptr; | ||
| 138 | |||
| 139 | kern_ptr = (void *)(user_ptr - alloc->user_buffer_offset); | ||
| 140 | |||
| 141 | while (n) { | ||
| 142 | buffer = rb_entry(n, struct binder_buffer, rb_node); | ||
| 143 | BUG_ON(buffer->free); | ||
| 144 | |||
| 145 | if (kern_ptr < buffer->data) | ||
| 146 | n = n->rb_left; | ||
| 147 | else if (kern_ptr > buffer->data) | ||
| 148 | n = n->rb_right; | ||
| 149 | else { | ||
| 150 | /* | ||
| 151 | * Guard against user threads attempting to | ||
| 152 | * free the buffer twice | ||
| 153 | */ | ||
| 154 | if (buffer->free_in_progress) { | ||
| 155 | pr_err("%d:%d FREE_BUFFER u%016llx user freed buffer twice\n", | ||
| 156 | alloc->pid, current->pid, (u64)user_ptr); | ||
| 157 | return NULL; | ||
| 158 | } | ||
| 159 | buffer->free_in_progress = 1; | ||
| 160 | return buffer; | ||
| 161 | } | ||
| 162 | } | ||
| 163 | return NULL; | ||
| 164 | } | ||
| 165 | |||
| 166 | /** | ||
| 167 | * binder_alloc_buffer_lookup() - get buffer given user ptr | ||
| 168 | * @alloc: binder_alloc for this proc | ||
| 169 | * @user_ptr: User pointer to buffer data | ||
| 170 | * | ||
| 171 | * Validate userspace pointer to buffer data and return buffer corresponding to | ||
| 172 | * that user pointer. Search the rb tree for buffer that matches user data | ||
| 173 | * pointer. | ||
| 174 | * | ||
| 175 | * Return: Pointer to buffer or NULL | ||
| 176 | */ | ||
| 177 | struct binder_buffer *binder_alloc_prepare_to_free(struct binder_alloc *alloc, | ||
| 178 | uintptr_t user_ptr) | ||
| 179 | { | ||
| 180 | struct binder_buffer *buffer; | ||
| 181 | |||
| 182 | mutex_lock(&alloc->mutex); | ||
| 183 | buffer = binder_alloc_prepare_to_free_locked(alloc, user_ptr); | ||
| 184 | mutex_unlock(&alloc->mutex); | ||
| 185 | return buffer; | ||
| 186 | } | ||
| 187 | |||
| 188 | static int binder_update_page_range(struct binder_alloc *alloc, int allocate, | ||
| 189 | void *start, void *end, | ||
| 190 | struct vm_area_struct *vma) | ||
| 191 | { | ||
| 192 | void *page_addr; | ||
| 193 | unsigned long user_page_addr; | ||
| 194 | struct binder_lru_page *page; | ||
| 195 | struct mm_struct *mm = NULL; | ||
| 196 | bool need_mm = false; | ||
| 197 | |||
| 198 | binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, | ||
| 199 | "%d: %s pages %pK-%pK\n", alloc->pid, | ||
| 200 | allocate ? "allocate" : "free", start, end); | ||
| 201 | |||
| 202 | if (end <= start) | ||
| 203 | return 0; | ||
| 204 | |||
| 205 | trace_binder_update_page_range(alloc, allocate, start, end); | ||
| 206 | |||
| 207 | if (allocate == 0) | ||
| 208 | goto free_range; | ||
| 209 | |||
| 210 | for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) { | ||
| 211 | page = &alloc->pages[(page_addr - alloc->buffer) / PAGE_SIZE]; | ||
| 212 | if (!page->page_ptr) { | ||
| 213 | need_mm = true; | ||
| 214 | break; | ||
| 215 | } | ||
| 216 | } | ||
| 217 | |||
| 218 | if (!vma && need_mm) | ||
| 219 | mm = get_task_mm(alloc->tsk); | ||
| 220 | |||
| 221 | if (mm) { | ||
| 222 | down_write(&mm->mmap_sem); | ||
| 223 | vma = alloc->vma; | ||
| 224 | if (vma && mm != alloc->vma_vm_mm) { | ||
| 225 | pr_err("%d: vma mm and task mm mismatch\n", | ||
| 226 | alloc->pid); | ||
| 227 | vma = NULL; | ||
| 228 | } | ||
| 229 | } | ||
| 230 | |||
| 231 | if (!vma && need_mm) { | ||
| 232 | pr_err("%d: binder_alloc_buf failed to map pages in userspace, no vma\n", | ||
| 233 | alloc->pid); | ||
| 234 | goto err_no_vma; | ||
| 235 | } | ||
| 236 | |||
| 237 | for (page_addr = start; page_addr < end; page_addr += PAGE_SIZE) { | ||
| 238 | int ret; | ||
| 239 | bool on_lru; | ||
| 240 | size_t index; | ||
| 241 | |||
| 242 | index = (page_addr - alloc->buffer) / PAGE_SIZE; | ||
| 243 | page = &alloc->pages[index]; | ||
| 244 | |||
| 245 | if (page->page_ptr) { | ||
| 246 | trace_binder_alloc_lru_start(alloc, index); | ||
| 247 | |||
| 248 | on_lru = list_lru_del(&binder_alloc_lru, &page->lru); | ||
| 249 | WARN_ON(!on_lru); | ||
| 250 | |||
| 251 | trace_binder_alloc_lru_end(alloc, index); | ||
| 252 | continue; | ||
| 253 | } | ||
| 254 | |||
| 255 | if (WARN_ON(!vma)) | ||
| 256 | goto err_page_ptr_cleared; | ||
| 257 | |||
| 258 | trace_binder_alloc_page_start(alloc, index); | ||
| 259 | page->page_ptr = alloc_page(GFP_KERNEL | | ||
| 260 | __GFP_HIGHMEM | | ||
| 261 | __GFP_ZERO); | ||
| 262 | if (!page->page_ptr) { | ||
| 263 | pr_err("%d: binder_alloc_buf failed for page at %pK\n", | ||
| 264 | alloc->pid, page_addr); | ||
| 265 | goto err_alloc_page_failed; | ||
| 266 | } | ||
| 267 | page->alloc = alloc; | ||
| 268 | INIT_LIST_HEAD(&page->lru); | ||
| 269 | |||
| 270 | ret = map_kernel_range_noflush((unsigned long)page_addr, | ||
| 271 | PAGE_SIZE, PAGE_KERNEL, | ||
| 272 | &page->page_ptr); | ||
| 273 | flush_cache_vmap((unsigned long)page_addr, | ||
| 274 | (unsigned long)page_addr + PAGE_SIZE); | ||
| 275 | if (ret != 1) { | ||
| 276 | pr_err("%d: binder_alloc_buf failed to map page at %pK in kernel\n", | ||
| 277 | alloc->pid, page_addr); | ||
| 278 | goto err_map_kernel_failed; | ||
| 279 | } | ||
| 280 | user_page_addr = | ||
| 281 | (uintptr_t)page_addr + alloc->user_buffer_offset; | ||
| 282 | ret = vm_insert_page(vma, user_page_addr, page[0].page_ptr); | ||
| 283 | if (ret) { | ||
| 284 | pr_err("%d: binder_alloc_buf failed to map page at %lx in userspace\n", | ||
| 285 | alloc->pid, user_page_addr); | ||
| 286 | goto err_vm_insert_page_failed; | ||
| 287 | } | ||
| 288 | |||
| 289 | trace_binder_alloc_page_end(alloc, index); | ||
| 290 | /* vm_insert_page does not seem to increment the refcount */ | ||
| 291 | } | ||
| 292 | if (mm) { | ||
| 293 | up_write(&mm->mmap_sem); | ||
| 294 | mmput(mm); | ||
| 295 | } | ||
| 296 | return 0; | ||
| 297 | |||
| 298 | free_range: | ||
| 299 | for (page_addr = end - PAGE_SIZE; page_addr >= start; | ||
| 300 | page_addr -= PAGE_SIZE) { | ||
| 301 | bool ret; | ||
| 302 | size_t index; | ||
| 303 | |||
| 304 | index = (page_addr - alloc->buffer) / PAGE_SIZE; | ||
| 305 | page = &alloc->pages[index]; | ||
| 306 | |||
| 307 | trace_binder_free_lru_start(alloc, index); | ||
| 308 | |||
| 309 | ret = list_lru_add(&binder_alloc_lru, &page->lru); | ||
| 310 | WARN_ON(!ret); | ||
| 311 | |||
| 312 | trace_binder_free_lru_end(alloc, index); | ||
| 313 | continue; | ||
| 314 | |||
| 315 | err_vm_insert_page_failed: | ||
| 316 | unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE); | ||
| 317 | err_map_kernel_failed: | ||
| 318 | __free_page(page->page_ptr); | ||
| 319 | page->page_ptr = NULL; | ||
| 320 | err_alloc_page_failed: | ||
| 321 | err_page_ptr_cleared: | ||
| 322 | ; | ||
| 323 | } | ||
| 324 | err_no_vma: | ||
| 325 | if (mm) { | ||
| 326 | up_write(&mm->mmap_sem); | ||
| 327 | mmput(mm); | ||
| 328 | } | ||
| 329 | return vma ? -ENOMEM : -ESRCH; | ||
| 330 | } | ||
| 331 | |||
| 332 | struct binder_buffer *binder_alloc_new_buf_locked(struct binder_alloc *alloc, | ||
| 333 | size_t data_size, | ||
| 334 | size_t offsets_size, | ||
| 335 | size_t extra_buffers_size, | ||
| 336 | int is_async) | ||
| 337 | { | ||
| 338 | struct rb_node *n = alloc->free_buffers.rb_node; | ||
| 339 | struct binder_buffer *buffer; | ||
| 340 | size_t buffer_size; | ||
| 341 | struct rb_node *best_fit = NULL; | ||
| 342 | void *has_page_addr; | ||
| 343 | void *end_page_addr; | ||
| 344 | size_t size, data_offsets_size; | ||
| 345 | int ret; | ||
| 346 | |||
| 347 | if (alloc->vma == NULL) { | ||
| 348 | pr_err("%d: binder_alloc_buf, no vma\n", | ||
| 349 | alloc->pid); | ||
| 350 | return ERR_PTR(-ESRCH); | ||
| 351 | } | ||
| 352 | |||
| 353 | data_offsets_size = ALIGN(data_size, sizeof(void *)) + | ||
| 354 | ALIGN(offsets_size, sizeof(void *)); | ||
| 355 | |||
| 356 | if (data_offsets_size < data_size || data_offsets_size < offsets_size) { | ||
| 357 | binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, | ||
| 358 | "%d: got transaction with invalid size %zd-%zd\n", | ||
| 359 | alloc->pid, data_size, offsets_size); | ||
| 360 | return ERR_PTR(-EINVAL); | ||
| 361 | } | ||
| 362 | size = data_offsets_size + ALIGN(extra_buffers_size, sizeof(void *)); | ||
| 363 | if (size < data_offsets_size || size < extra_buffers_size) { | ||
| 364 | binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, | ||
| 365 | "%d: got transaction with invalid extra_buffers_size %zd\n", | ||
| 366 | alloc->pid, extra_buffers_size); | ||
| 367 | return ERR_PTR(-EINVAL); | ||
| 368 | } | ||
| 369 | if (is_async && | ||
| 370 | alloc->free_async_space < size + sizeof(struct binder_buffer)) { | ||
| 371 | binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, | ||
| 372 | "%d: binder_alloc_buf size %zd failed, no async space left\n", | ||
| 373 | alloc->pid, size); | ||
| 374 | return ERR_PTR(-ENOSPC); | ||
| 375 | } | ||
| 376 | |||
| 377 | /* Pad 0-size buffers so they get assigned unique addresses */ | ||
| 378 | size = max(size, sizeof(void *)); | ||
| 379 | |||
| 380 | while (n) { | ||
| 381 | buffer = rb_entry(n, struct binder_buffer, rb_node); | ||
| 382 | BUG_ON(!buffer->free); | ||
| 383 | buffer_size = binder_alloc_buffer_size(alloc, buffer); | ||
| 384 | |||
| 385 | if (size < buffer_size) { | ||
| 386 | best_fit = n; | ||
| 387 | n = n->rb_left; | ||
| 388 | } else if (size > buffer_size) | ||
| 389 | n = n->rb_right; | ||
| 390 | else { | ||
| 391 | best_fit = n; | ||
| 392 | break; | ||
| 393 | } | ||
| 394 | } | ||
| 395 | if (best_fit == NULL) { | ||
| 396 | size_t allocated_buffers = 0; | ||
| 397 | size_t largest_alloc_size = 0; | ||
| 398 | size_t total_alloc_size = 0; | ||
| 399 | size_t free_buffers = 0; | ||
| 400 | size_t largest_free_size = 0; | ||
| 401 | size_t total_free_size = 0; | ||
| 402 | |||
| 403 | for (n = rb_first(&alloc->allocated_buffers); n != NULL; | ||
| 404 | n = rb_next(n)) { | ||
| 405 | buffer = rb_entry(n, struct binder_buffer, rb_node); | ||
| 406 | buffer_size = binder_alloc_buffer_size(alloc, buffer); | ||
| 407 | allocated_buffers++; | ||
| 408 | total_alloc_size += buffer_size; | ||
| 409 | if (buffer_size > largest_alloc_size) | ||
| 410 | largest_alloc_size = buffer_size; | ||
| 411 | } | ||
| 412 | for (n = rb_first(&alloc->free_buffers); n != NULL; | ||
| 413 | n = rb_next(n)) { | ||
| 414 | buffer = rb_entry(n, struct binder_buffer, rb_node); | ||
| 415 | buffer_size = binder_alloc_buffer_size(alloc, buffer); | ||
| 416 | free_buffers++; | ||
| 417 | total_free_size += buffer_size; | ||
| 418 | if (buffer_size > largest_free_size) | ||
| 419 | largest_free_size = buffer_size; | ||
| 420 | } | ||
| 421 | pr_err("%d: binder_alloc_buf size %zd failed, no address space\n", | ||
| 422 | alloc->pid, size); | ||
| 423 | pr_err("allocated: %zd (num: %zd largest: %zd), free: %zd (num: %zd largest: %zd)\n", | ||
| 424 | total_alloc_size, allocated_buffers, largest_alloc_size, | ||
| 425 | total_free_size, free_buffers, largest_free_size); | ||
| 426 | return ERR_PTR(-ENOSPC); | ||
| 427 | } | ||
| 428 | if (n == NULL) { | ||
| 429 | buffer = rb_entry(best_fit, struct binder_buffer, rb_node); | ||
| 430 | buffer_size = binder_alloc_buffer_size(alloc, buffer); | ||
| 431 | } | ||
| 432 | |||
| 433 | binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, | ||
| 434 | "%d: binder_alloc_buf size %zd got buffer %pK size %zd\n", | ||
| 435 | alloc->pid, size, buffer, buffer_size); | ||
| 436 | |||
| 437 | has_page_addr = | ||
| 438 | (void *)(((uintptr_t)buffer->data + buffer_size) & PAGE_MASK); | ||
| 439 | WARN_ON(n && buffer_size != size); | ||
| 440 | end_page_addr = | ||
| 441 | (void *)PAGE_ALIGN((uintptr_t)buffer->data + size); | ||
| 442 | if (end_page_addr > has_page_addr) | ||
| 443 | end_page_addr = has_page_addr; | ||
| 444 | ret = binder_update_page_range(alloc, 1, | ||
| 445 | (void *)PAGE_ALIGN((uintptr_t)buffer->data), end_page_addr, NULL); | ||
| 446 | if (ret) | ||
| 447 | return ERR_PTR(ret); | ||
| 448 | |||
| 449 | if (buffer_size != size) { | ||
| 450 | struct binder_buffer *new_buffer; | ||
| 451 | |||
| 452 | new_buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); | ||
| 453 | if (!new_buffer) { | ||
| 454 | pr_err("%s: %d failed to alloc new buffer struct\n", | ||
| 455 | __func__, alloc->pid); | ||
| 456 | goto err_alloc_buf_struct_failed; | ||
| 457 | } | ||
| 458 | new_buffer->data = (u8 *)buffer->data + size; | ||
| 459 | list_add(&new_buffer->entry, &buffer->entry); | ||
| 460 | new_buffer->free = 1; | ||
| 461 | binder_insert_free_buffer(alloc, new_buffer); | ||
| 462 | } | ||
| 463 | |||
| 464 | rb_erase(best_fit, &alloc->free_buffers); | ||
| 465 | buffer->free = 0; | ||
| 466 | buffer->free_in_progress = 0; | ||
| 467 | binder_insert_allocated_buffer_locked(alloc, buffer); | ||
| 468 | binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, | ||
| 469 | "%d: binder_alloc_buf size %zd got %pK\n", | ||
| 470 | alloc->pid, size, buffer); | ||
| 471 | buffer->data_size = data_size; | ||
| 472 | buffer->offsets_size = offsets_size; | ||
| 473 | buffer->async_transaction = is_async; | ||
| 474 | buffer->extra_buffers_size = extra_buffers_size; | ||
| 475 | if (is_async) { | ||
| 476 | alloc->free_async_space -= size + sizeof(struct binder_buffer); | ||
| 477 | binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC, | ||
| 478 | "%d: binder_alloc_buf size %zd async free %zd\n", | ||
| 479 | alloc->pid, size, alloc->free_async_space); | ||
| 480 | } | ||
| 481 | return buffer; | ||
| 482 | |||
| 483 | err_alloc_buf_struct_failed: | ||
| 484 | binder_update_page_range(alloc, 0, | ||
| 485 | (void *)PAGE_ALIGN((uintptr_t)buffer->data), | ||
| 486 | end_page_addr, NULL); | ||
| 487 | return ERR_PTR(-ENOMEM); | ||
| 488 | } | ||
| 489 | |||
| 490 | /** | ||
| 491 | * binder_alloc_new_buf() - Allocate a new binder buffer | ||
| 492 | * @alloc: binder_alloc for this proc | ||
| 493 | * @data_size: size of user data buffer | ||
| 494 | * @offsets_size: user specified buffer offset | ||
| 495 | * @extra_buffers_size: size of extra space for meta-data (eg, security context) | ||
| 496 | * @is_async: buffer for async transaction | ||
| 497 | * | ||
| 498 | * Allocate a new buffer given the requested sizes. Returns | ||
| 499 | * the kernel version of the buffer pointer. The size allocated | ||
| 500 | * is the sum of the three given sizes (each rounded up to | ||
| 501 | * pointer-sized boundary) | ||
| 502 | * | ||
| 503 | * Return: The allocated buffer or %NULL if error | ||
| 504 | */ | ||
| 505 | struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc, | ||
| 506 | size_t data_size, | ||
| 507 | size_t offsets_size, | ||
| 508 | size_t extra_buffers_size, | ||
| 509 | int is_async) | ||
| 510 | { | ||
| 511 | struct binder_buffer *buffer; | ||
| 512 | |||
| 513 | mutex_lock(&alloc->mutex); | ||
| 514 | buffer = binder_alloc_new_buf_locked(alloc, data_size, offsets_size, | ||
| 515 | extra_buffers_size, is_async); | ||
| 516 | mutex_unlock(&alloc->mutex); | ||
| 517 | return buffer; | ||
| 518 | } | ||
| 519 | |||
| 520 | static void *buffer_start_page(struct binder_buffer *buffer) | ||
| 521 | { | ||
| 522 | return (void *)((uintptr_t)buffer->data & PAGE_MASK); | ||
| 523 | } | ||
| 524 | |||
| 525 | static void *prev_buffer_end_page(struct binder_buffer *buffer) | ||
| 526 | { | ||
| 527 | return (void *)(((uintptr_t)(buffer->data) - 1) & PAGE_MASK); | ||
| 528 | } | ||
| 529 | |||
| 530 | static void binder_delete_free_buffer(struct binder_alloc *alloc, | ||
| 531 | struct binder_buffer *buffer) | ||
| 532 | { | ||
| 533 | struct binder_buffer *prev, *next = NULL; | ||
| 534 | bool to_free = true; | ||
| 535 | BUG_ON(alloc->buffers.next == &buffer->entry); | ||
| 536 | prev = binder_buffer_prev(buffer); | ||
| 537 | BUG_ON(!prev->free); | ||
| 538 | if (prev_buffer_end_page(prev) == buffer_start_page(buffer)) { | ||
| 539 | to_free = false; | ||
| 540 | binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, | ||
| 541 | "%d: merge free, buffer %pK share page with %pK\n", | ||
| 542 | alloc->pid, buffer->data, prev->data); | ||
| 543 | } | ||
| 544 | |||
| 545 | if (!list_is_last(&buffer->entry, &alloc->buffers)) { | ||
| 546 | next = binder_buffer_next(buffer); | ||
| 547 | if (buffer_start_page(next) == buffer_start_page(buffer)) { | ||
| 548 | to_free = false; | ||
| 549 | binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, | ||
| 550 | "%d: merge free, buffer %pK share page with %pK\n", | ||
| 551 | alloc->pid, | ||
| 552 | buffer->data, | ||
| 553 | next->data); | ||
| 554 | } | ||
| 555 | } | ||
| 556 | |||
| 557 | if (PAGE_ALIGNED(buffer->data)) { | ||
| 558 | binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, | ||
| 559 | "%d: merge free, buffer start %pK is page aligned\n", | ||
| 560 | alloc->pid, buffer->data); | ||
| 561 | to_free = false; | ||
| 562 | } | ||
| 563 | |||
| 564 | if (to_free) { | ||
| 565 | binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, | ||
| 566 | "%d: merge free, buffer %pK do not share page with %pK or %pK\n", | ||
| 567 | alloc->pid, buffer->data, | ||
| 568 | prev->data, next->data); | ||
| 569 | binder_update_page_range(alloc, 0, buffer_start_page(buffer), | ||
| 570 | buffer_start_page(buffer) + PAGE_SIZE, | ||
| 571 | NULL); | ||
| 572 | } | ||
| 573 | list_del(&buffer->entry); | ||
| 574 | kfree(buffer); | ||
| 575 | } | ||
| 576 | |||
| 577 | static void binder_free_buf_locked(struct binder_alloc *alloc, | ||
| 578 | struct binder_buffer *buffer) | ||
| 579 | { | ||
| 580 | size_t size, buffer_size; | ||
| 581 | |||
| 582 | buffer_size = binder_alloc_buffer_size(alloc, buffer); | ||
| 583 | |||
| 584 | size = ALIGN(buffer->data_size, sizeof(void *)) + | ||
| 585 | ALIGN(buffer->offsets_size, sizeof(void *)) + | ||
| 586 | ALIGN(buffer->extra_buffers_size, sizeof(void *)); | ||
| 587 | |||
| 588 | binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, | ||
| 589 | "%d: binder_free_buf %pK size %zd buffer_size %zd\n", | ||
| 590 | alloc->pid, buffer, size, buffer_size); | ||
| 591 | |||
| 592 | BUG_ON(buffer->free); | ||
| 593 | BUG_ON(size > buffer_size); | ||
| 594 | BUG_ON(buffer->transaction != NULL); | ||
| 595 | BUG_ON(buffer->data < alloc->buffer); | ||
| 596 | BUG_ON(buffer->data > alloc->buffer + alloc->buffer_size); | ||
| 597 | |||
| 598 | if (buffer->async_transaction) { | ||
| 599 | alloc->free_async_space += size + sizeof(struct binder_buffer); | ||
| 600 | |||
| 601 | binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC_ASYNC, | ||
| 602 | "%d: binder_free_buf size %zd async free %zd\n", | ||
| 603 | alloc->pid, size, alloc->free_async_space); | ||
| 604 | } | ||
| 605 | |||
| 606 | binder_update_page_range(alloc, 0, | ||
| 607 | (void *)PAGE_ALIGN((uintptr_t)buffer->data), | ||
| 608 | (void *)(((uintptr_t)buffer->data + buffer_size) & PAGE_MASK), | ||
| 609 | NULL); | ||
| 610 | |||
| 611 | rb_erase(&buffer->rb_node, &alloc->allocated_buffers); | ||
| 612 | buffer->free = 1; | ||
| 613 | if (!list_is_last(&buffer->entry, &alloc->buffers)) { | ||
| 614 | struct binder_buffer *next = binder_buffer_next(buffer); | ||
| 615 | |||
| 616 | if (next->free) { | ||
| 617 | rb_erase(&next->rb_node, &alloc->free_buffers); | ||
| 618 | binder_delete_free_buffer(alloc, next); | ||
| 619 | } | ||
| 620 | } | ||
| 621 | if (alloc->buffers.next != &buffer->entry) { | ||
| 622 | struct binder_buffer *prev = binder_buffer_prev(buffer); | ||
| 623 | |||
| 624 | if (prev->free) { | ||
| 625 | binder_delete_free_buffer(alloc, buffer); | ||
| 626 | rb_erase(&prev->rb_node, &alloc->free_buffers); | ||
| 627 | buffer = prev; | ||
| 628 | } | ||
| 629 | } | ||
| 630 | binder_insert_free_buffer(alloc, buffer); | ||
| 631 | } | ||
| 632 | |||
| 633 | /** | ||
| 634 | * binder_alloc_free_buf() - free a binder buffer | ||
| 635 | * @alloc: binder_alloc for this proc | ||
| 636 | * @buffer: kernel pointer to buffer | ||
| 637 | * | ||
| 638 | * Free the buffer allocated via binder_alloc_new_buffer() | ||
| 639 | */ | ||
| 640 | void binder_alloc_free_buf(struct binder_alloc *alloc, | ||
| 641 | struct binder_buffer *buffer) | ||
| 642 | { | ||
| 643 | mutex_lock(&alloc->mutex); | ||
| 644 | binder_free_buf_locked(alloc, buffer); | ||
| 645 | mutex_unlock(&alloc->mutex); | ||
| 646 | } | ||
| 647 | |||
| 648 | /** | ||
| 649 | * binder_alloc_mmap_handler() - map virtual address space for proc | ||
| 650 | * @alloc: alloc structure for this proc | ||
| 651 | * @vma: vma passed to mmap() | ||
| 652 | * | ||
| 653 | * Called by binder_mmap() to initialize the space specified in | ||
| 654 | * vma for allocating binder buffers | ||
| 655 | * | ||
| 656 | * Return: | ||
| 657 | * 0 = success | ||
| 658 | * -EBUSY = address space already mapped | ||
| 659 | * -ENOMEM = failed to map memory to given address space | ||
| 660 | */ | ||
| 661 | int binder_alloc_mmap_handler(struct binder_alloc *alloc, | ||
| 662 | struct vm_area_struct *vma) | ||
| 663 | { | ||
| 664 | int ret; | ||
| 665 | struct vm_struct *area; | ||
| 666 | const char *failure_string; | ||
| 667 | struct binder_buffer *buffer; | ||
| 668 | |||
| 669 | mutex_lock(&binder_alloc_mmap_lock); | ||
| 670 | if (alloc->buffer) { | ||
| 671 | ret = -EBUSY; | ||
| 672 | failure_string = "already mapped"; | ||
| 673 | goto err_already_mapped; | ||
| 674 | } | ||
| 675 | |||
| 676 | area = get_vm_area(vma->vm_end - vma->vm_start, VM_IOREMAP); | ||
| 677 | if (area == NULL) { | ||
| 678 | ret = -ENOMEM; | ||
| 679 | failure_string = "get_vm_area"; | ||
| 680 | goto err_get_vm_area_failed; | ||
| 681 | } | ||
| 682 | alloc->buffer = area->addr; | ||
| 683 | alloc->user_buffer_offset = | ||
| 684 | vma->vm_start - (uintptr_t)alloc->buffer; | ||
| 685 | mutex_unlock(&binder_alloc_mmap_lock); | ||
| 686 | |||
| 687 | #ifdef CONFIG_CPU_CACHE_VIPT | ||
| 688 | if (cache_is_vipt_aliasing()) { | ||
| 689 | while (CACHE_COLOUR( | ||
| 690 | (vma->vm_start ^ (uint32_t)alloc->buffer))) { | ||
| 691 | pr_info("%s: %d %lx-%lx maps %pK bad alignment\n", | ||
| 692 | __func__, alloc->pid, vma->vm_start, | ||
| 693 | vma->vm_end, alloc->buffer); | ||
| 694 | vma->vm_start += PAGE_SIZE; | ||
| 695 | } | ||
| 696 | } | ||
| 697 | #endif | ||
| 698 | alloc->pages = kzalloc(sizeof(alloc->pages[0]) * | ||
| 699 | ((vma->vm_end - vma->vm_start) / PAGE_SIZE), | ||
| 700 | GFP_KERNEL); | ||
| 701 | if (alloc->pages == NULL) { | ||
| 702 | ret = -ENOMEM; | ||
| 703 | failure_string = "alloc page array"; | ||
| 704 | goto err_alloc_pages_failed; | ||
| 705 | } | ||
| 706 | alloc->buffer_size = vma->vm_end - vma->vm_start; | ||
| 707 | |||
| 708 | buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); | ||
| 709 | if (!buffer) { | ||
| 710 | ret = -ENOMEM; | ||
| 711 | failure_string = "alloc buffer struct"; | ||
| 712 | goto err_alloc_buf_struct_failed; | ||
| 713 | } | ||
| 714 | |||
| 715 | buffer->data = alloc->buffer; | ||
| 716 | list_add(&buffer->entry, &alloc->buffers); | ||
| 717 | buffer->free = 1; | ||
| 718 | binder_insert_free_buffer(alloc, buffer); | ||
| 719 | alloc->free_async_space = alloc->buffer_size / 2; | ||
| 720 | barrier(); | ||
| 721 | alloc->vma = vma; | ||
| 722 | alloc->vma_vm_mm = vma->vm_mm; | ||
| 723 | |||
| 724 | return 0; | ||
| 725 | |||
| 726 | err_alloc_buf_struct_failed: | ||
| 727 | kfree(alloc->pages); | ||
| 728 | alloc->pages = NULL; | ||
| 729 | err_alloc_pages_failed: | ||
| 730 | mutex_lock(&binder_alloc_mmap_lock); | ||
| 731 | vfree(alloc->buffer); | ||
| 732 | alloc->buffer = NULL; | ||
| 733 | err_get_vm_area_failed: | ||
| 734 | err_already_mapped: | ||
| 735 | mutex_unlock(&binder_alloc_mmap_lock); | ||
| 736 | pr_err("%s: %d %lx-%lx %s failed %d\n", __func__, | ||
| 737 | alloc->pid, vma->vm_start, vma->vm_end, failure_string, ret); | ||
| 738 | return ret; | ||
| 739 | } | ||
| 740 | |||
| 741 | |||
| 742 | void binder_alloc_deferred_release(struct binder_alloc *alloc) | ||
| 743 | { | ||
| 744 | struct rb_node *n; | ||
| 745 | int buffers, page_count; | ||
| 746 | struct binder_buffer *buffer; | ||
| 747 | |||
| 748 | BUG_ON(alloc->vma); | ||
| 749 | |||
| 750 | buffers = 0; | ||
| 751 | mutex_lock(&alloc->mutex); | ||
| 752 | while ((n = rb_first(&alloc->allocated_buffers))) { | ||
| 753 | buffer = rb_entry(n, struct binder_buffer, rb_node); | ||
| 754 | |||
| 755 | /* Transaction should already have been freed */ | ||
| 756 | BUG_ON(buffer->transaction); | ||
| 757 | |||
| 758 | binder_free_buf_locked(alloc, buffer); | ||
| 759 | buffers++; | ||
| 760 | } | ||
| 761 | |||
| 762 | while (!list_empty(&alloc->buffers)) { | ||
| 763 | buffer = list_first_entry(&alloc->buffers, | ||
| 764 | struct binder_buffer, entry); | ||
| 765 | WARN_ON(!buffer->free); | ||
| 766 | |||
| 767 | list_del(&buffer->entry); | ||
| 768 | WARN_ON_ONCE(!list_empty(&alloc->buffers)); | ||
| 769 | kfree(buffer); | ||
| 770 | } | ||
| 771 | |||
| 772 | page_count = 0; | ||
| 773 | if (alloc->pages) { | ||
| 774 | int i; | ||
| 775 | |||
| 776 | for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) { | ||
| 777 | void *page_addr; | ||
| 778 | bool on_lru; | ||
| 779 | |||
| 780 | if (!alloc->pages[i].page_ptr) | ||
| 781 | continue; | ||
| 782 | |||
| 783 | on_lru = list_lru_del(&binder_alloc_lru, | ||
| 784 | &alloc->pages[i].lru); | ||
| 785 | page_addr = alloc->buffer + i * PAGE_SIZE; | ||
| 786 | binder_alloc_debug(BINDER_DEBUG_BUFFER_ALLOC, | ||
| 787 | "%s: %d: page %d at %pK %s\n", | ||
| 788 | __func__, alloc->pid, i, page_addr, | ||
| 789 | on_lru ? "on lru" : "active"); | ||
| 790 | unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE); | ||
| 791 | __free_page(alloc->pages[i].page_ptr); | ||
| 792 | page_count++; | ||
| 793 | } | ||
| 794 | kfree(alloc->pages); | ||
| 795 | vfree(alloc->buffer); | ||
| 796 | } | ||
| 797 | mutex_unlock(&alloc->mutex); | ||
| 798 | |||
| 799 | binder_alloc_debug(BINDER_DEBUG_OPEN_CLOSE, | ||
| 800 | "%s: %d buffers %d, pages %d\n", | ||
| 801 | __func__, alloc->pid, buffers, page_count); | ||
| 802 | } | ||
| 803 | |||
| 804 | static void print_binder_buffer(struct seq_file *m, const char *prefix, | ||
| 805 | struct binder_buffer *buffer) | ||
| 806 | { | ||
| 807 | seq_printf(m, "%s %d: %pK size %zd:%zd:%zd %s\n", | ||
| 808 | prefix, buffer->debug_id, buffer->data, | ||
| 809 | buffer->data_size, buffer->offsets_size, | ||
| 810 | buffer->extra_buffers_size, | ||
| 811 | buffer->transaction ? "active" : "delivered"); | ||
| 812 | } | ||
| 813 | |||
| 814 | /** | ||
| 815 | * binder_alloc_print_allocated() - print buffer info | ||
| 816 | * @m: seq_file for output via seq_printf() | ||
| 817 | * @alloc: binder_alloc for this proc | ||
| 818 | * | ||
| 819 | * Prints information about every buffer associated with | ||
| 820 | * the binder_alloc state to the given seq_file | ||
| 821 | */ | ||
| 822 | void binder_alloc_print_allocated(struct seq_file *m, | ||
| 823 | struct binder_alloc *alloc) | ||
| 824 | { | ||
| 825 | struct rb_node *n; | ||
| 826 | |||
| 827 | mutex_lock(&alloc->mutex); | ||
| 828 | for (n = rb_first(&alloc->allocated_buffers); n != NULL; n = rb_next(n)) | ||
| 829 | print_binder_buffer(m, " buffer", | ||
| 830 | rb_entry(n, struct binder_buffer, rb_node)); | ||
| 831 | mutex_unlock(&alloc->mutex); | ||
| 832 | } | ||
| 833 | |||
| 834 | /** | ||
| 835 | * binder_alloc_print_pages() - print page usage | ||
| 836 | * @m: seq_file for output via seq_printf() | ||
| 837 | * @alloc: binder_alloc for this proc | ||
| 838 | */ | ||
| 839 | void binder_alloc_print_pages(struct seq_file *m, | ||
| 840 | struct binder_alloc *alloc) | ||
| 841 | { | ||
| 842 | struct binder_lru_page *page; | ||
| 843 | int i; | ||
| 844 | int active = 0; | ||
| 845 | int lru = 0; | ||
| 846 | int free = 0; | ||
| 847 | |||
| 848 | mutex_lock(&alloc->mutex); | ||
| 849 | for (i = 0; i < alloc->buffer_size / PAGE_SIZE; i++) { | ||
| 850 | page = &alloc->pages[i]; | ||
| 851 | if (!page->page_ptr) | ||
| 852 | free++; | ||
| 853 | else if (list_empty(&page->lru)) | ||
| 854 | active++; | ||
| 855 | else | ||
| 856 | lru++; | ||
| 857 | } | ||
| 858 | mutex_unlock(&alloc->mutex); | ||
| 859 | seq_printf(m, " pages: %d:%d:%d\n", active, lru, free); | ||
| 860 | } | ||
| 861 | |||
| 862 | /** | ||
| 863 | * binder_alloc_get_allocated_count() - return count of buffers | ||
| 864 | * @alloc: binder_alloc for this proc | ||
| 865 | * | ||
| 866 | * Return: count of allocated buffers | ||
| 867 | */ | ||
| 868 | int binder_alloc_get_allocated_count(struct binder_alloc *alloc) | ||
| 869 | { | ||
| 870 | struct rb_node *n; | ||
| 871 | int count = 0; | ||
| 872 | |||
| 873 | mutex_lock(&alloc->mutex); | ||
| 874 | for (n = rb_first(&alloc->allocated_buffers); n != NULL; n = rb_next(n)) | ||
| 875 | count++; | ||
| 876 | mutex_unlock(&alloc->mutex); | ||
| 877 | return count; | ||
| 878 | } | ||
| 879 | |||
| 880 | |||
| 881 | /** | ||
| 882 | * binder_alloc_vma_close() - invalidate address space | ||
| 883 | * @alloc: binder_alloc for this proc | ||
| 884 | * | ||
| 885 | * Called from binder_vma_close() when releasing address space. | ||
| 886 | * Clears alloc->vma to prevent new incoming transactions from | ||
| 887 | * allocating more buffers. | ||
| 888 | */ | ||
| 889 | void binder_alloc_vma_close(struct binder_alloc *alloc) | ||
| 890 | { | ||
| 891 | WRITE_ONCE(alloc->vma, NULL); | ||
| 892 | WRITE_ONCE(alloc->vma_vm_mm, NULL); | ||
| 893 | } | ||
| 894 | |||
| 895 | /** | ||
| 896 | * binder_alloc_free_page() - shrinker callback to free pages | ||
| 897 | * @item: item to free | ||
| 898 | * @lock: lock protecting the item | ||
| 899 | * @cb_arg: callback argument | ||
| 900 | * | ||
| 901 | * Called from list_lru_walk() in binder_shrink_scan() to free | ||
| 902 | * up pages when the system is under memory pressure. | ||
| 903 | */ | ||
| 904 | enum lru_status binder_alloc_free_page(struct list_head *item, | ||
| 905 | struct list_lru_one *lru, | ||
| 906 | spinlock_t *lock, | ||
| 907 | void *cb_arg) | ||
| 908 | { | ||
| 909 | struct mm_struct *mm = NULL; | ||
| 910 | struct binder_lru_page *page = container_of(item, | ||
| 911 | struct binder_lru_page, | ||
| 912 | lru); | ||
| 913 | struct binder_alloc *alloc; | ||
| 914 | uintptr_t page_addr; | ||
| 915 | size_t index; | ||
| 916 | |||
| 917 | alloc = page->alloc; | ||
| 918 | if (!mutex_trylock(&alloc->mutex)) | ||
| 919 | goto err_get_alloc_mutex_failed; | ||
| 920 | |||
| 921 | if (!page->page_ptr) | ||
| 922 | goto err_page_already_freed; | ||
| 923 | |||
| 924 | index = page - alloc->pages; | ||
| 925 | page_addr = (uintptr_t)alloc->buffer + index * PAGE_SIZE; | ||
| 926 | if (alloc->vma) { | ||
| 927 | mm = get_task_mm(alloc->tsk); | ||
| 928 | if (!mm) | ||
| 929 | goto err_get_task_mm_failed; | ||
| 930 | if (!down_write_trylock(&mm->mmap_sem)) | ||
| 931 | goto err_down_write_mmap_sem_failed; | ||
| 932 | |||
| 933 | trace_binder_unmap_user_start(alloc, index); | ||
| 934 | |||
| 935 | zap_page_range(alloc->vma, | ||
| 936 | page_addr + alloc->user_buffer_offset, | ||
| 937 | PAGE_SIZE); | ||
| 938 | |||
| 939 | trace_binder_unmap_user_end(alloc, index); | ||
| 940 | |||
| 941 | up_write(&mm->mmap_sem); | ||
| 942 | mmput(mm); | ||
| 943 | } | ||
| 944 | |||
| 945 | trace_binder_unmap_kernel_start(alloc, index); | ||
| 946 | |||
| 947 | unmap_kernel_range(page_addr, PAGE_SIZE); | ||
| 948 | __free_page(page->page_ptr); | ||
| 949 | page->page_ptr = NULL; | ||
| 950 | |||
| 951 | trace_binder_unmap_kernel_end(alloc, index); | ||
| 952 | |||
| 953 | list_lru_isolate(lru, item); | ||
| 954 | |||
| 955 | mutex_unlock(&alloc->mutex); | ||
| 956 | return LRU_REMOVED; | ||
| 957 | |||
| 958 | err_down_write_mmap_sem_failed: | ||
| 959 | mmput(mm); | ||
| 960 | err_get_task_mm_failed: | ||
| 961 | err_page_already_freed: | ||
| 962 | mutex_unlock(&alloc->mutex); | ||
| 963 | err_get_alloc_mutex_failed: | ||
| 964 | return LRU_SKIP; | ||
| 965 | } | ||
| 966 | |||
| 967 | static unsigned long | ||
| 968 | binder_shrink_count(struct shrinker *shrink, struct shrink_control *sc) | ||
| 969 | { | ||
| 970 | unsigned long ret = list_lru_count(&binder_alloc_lru); | ||
| 971 | return ret; | ||
| 972 | } | ||
| 973 | |||
| 974 | static unsigned long | ||
| 975 | binder_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) | ||
| 976 | { | ||
| 977 | unsigned long ret; | ||
| 978 | |||
| 979 | ret = list_lru_walk(&binder_alloc_lru, binder_alloc_free_page, | ||
| 980 | NULL, sc->nr_to_scan); | ||
| 981 | return ret; | ||
| 982 | } | ||
| 983 | |||
| 984 | struct shrinker binder_shrinker = { | ||
| 985 | .count_objects = binder_shrink_count, | ||
| 986 | .scan_objects = binder_shrink_scan, | ||
| 987 | .seeks = DEFAULT_SEEKS, | ||
| 988 | }; | ||
| 989 | |||
| 990 | /** | ||
| 991 | * binder_alloc_init() - called by binder_open() for per-proc initialization | ||
| 992 | * @alloc: binder_alloc for this proc | ||
| 993 | * | ||
| 994 | * Called from binder_open() to initialize binder_alloc fields for | ||
| 995 | * new binder proc | ||
| 996 | */ | ||
| 997 | void binder_alloc_init(struct binder_alloc *alloc) | ||
| 998 | { | ||
| 999 | alloc->tsk = current->group_leader; | ||
| 1000 | alloc->pid = current->group_leader->pid; | ||
| 1001 | mutex_init(&alloc->mutex); | ||
| 1002 | INIT_LIST_HEAD(&alloc->buffers); | ||
| 1003 | } | ||
| 1004 | |||
| 1005 | void binder_alloc_shrinker_init(void) | ||
| 1006 | { | ||
| 1007 | list_lru_init(&binder_alloc_lru); | ||
| 1008 | register_shrinker(&binder_shrinker); | ||
| 1009 | } | ||
| @@ -0,0 +1,187 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2017 Google, Inc. | ||
| 3 | * | ||
| 4 | * This software is licensed under the terms of the GNU General Public | ||
| 5 | * License version 2, as published by the Free Software Foundation, and | ||
| 6 | * may be copied, distributed, and modified under those terms. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | */ | ||
| 14 | |||
| 15 | #ifndef _LINUX_BINDER_ALLOC_H | ||
| 16 | #define _LINUX_BINDER_ALLOC_H | ||
| 17 | |||
| 18 | #include <linux/rbtree.h> | ||
| 19 | #include <linux/list.h> | ||
| 20 | #include <linux/mm.h> | ||
| 21 | #include <linux/rtmutex.h> | ||
| 22 | #include <linux/vmalloc.h> | ||
| 23 | #include <linux/slab.h> | ||
| 24 | #include <linux/list_lru.h> | ||
| 25 | |||
| 26 | extern struct list_lru binder_alloc_lru; | ||
| 27 | struct binder_transaction; | ||
| 28 | |||
| 29 | /** | ||
| 30 | * struct binder_buffer - buffer used for binder transactions | ||
| 31 | * @entry: entry alloc->buffers | ||
| 32 | * @rb_node: node for allocated_buffers/free_buffers rb trees | ||
| 33 | * @free: true if buffer is free | ||
| 34 | * @allow_user_free: describe the second member of struct blah, | ||
| 35 | * @async_transaction: describe the second member of struct blah, | ||
| 36 | * @debug_id: describe the second member of struct blah, | ||
| 37 | * @transaction: describe the second member of struct blah, | ||
| 38 | * @target_node: describe the second member of struct blah, | ||
| 39 | * @data_size: describe the second member of struct blah, | ||
| 40 | * @offsets_size: describe the second member of struct blah, | ||
| 41 | * @extra_buffers_size: describe the second member of struct blah, | ||
| 42 | * @data:i describe the second member of struct blah, | ||
| 43 | * | ||
| 44 | * Bookkeeping structure for binder transaction buffers | ||
| 45 | */ | ||
| 46 | struct binder_buffer { | ||
| 47 | struct list_head entry; /* free and allocated entries by address */ | ||
| 48 | struct rb_node rb_node; /* free entry by size or allocated entry */ | ||
| 49 | /* by address */ | ||
| 50 | unsigned free:1; | ||
| 51 | unsigned allow_user_free:1; | ||
| 52 | unsigned async_transaction:1; | ||
| 53 | unsigned free_in_progress:1; | ||
| 54 | unsigned debug_id:28; | ||
| 55 | |||
| 56 | struct binder_transaction *transaction; | ||
| 57 | |||
| 58 | struct binder_node *target_node; | ||
| 59 | size_t data_size; | ||
| 60 | size_t offsets_size; | ||
| 61 | size_t extra_buffers_size; | ||
| 62 | void *data; | ||
| 63 | }; | ||
| 64 | |||
| 65 | /** | ||
| 66 | * struct binder_lru_page - page object used for binder shrinker | ||
| 67 | * @page_ptr: pointer to physical page in mmap'd space | ||
| 68 | * @lru: entry in binder_alloc_lru | ||
| 69 | * @alloc: binder_alloc for a proc | ||
| 70 | */ | ||
| 71 | struct binder_lru_page { | ||
| 72 | struct list_head lru; | ||
| 73 | struct page *page_ptr; | ||
| 74 | struct binder_alloc *alloc; | ||
| 75 | }; | ||
| 76 | |||
| 77 | /** | ||
| 78 | * struct binder_alloc - per-binder proc state for binder allocator | ||
| 79 | * @vma: vm_area_struct passed to mmap_handler | ||
| 80 | * (invarient after mmap) | ||
| 81 | * @tsk: tid for task that called init for this proc | ||
| 82 | * (invariant after init) | ||
| 83 | * @vma_vm_mm: copy of vma->vm_mm (invarient after mmap) | ||
| 84 | * @buffer: base of per-proc address space mapped via mmap | ||
| 85 | * @user_buffer_offset: offset between user and kernel VAs for buffer | ||
| 86 | * @buffers: list of all buffers for this proc | ||
| 87 | * @free_buffers: rb tree of buffers available for allocation | ||
| 88 | * sorted by size | ||
| 89 | * @allocated_buffers: rb tree of allocated buffers sorted by address | ||
| 90 | * @free_async_space: VA space available for async buffers. This is | ||
| 91 | * initialized at mmap time to 1/2 the full VA space | ||
| 92 | * @pages: array of binder_lru_page | ||
| 93 | * @buffer_size: size of address space specified via mmap | ||
| 94 | * @pid: pid for associated binder_proc (invariant after init) | ||
| 95 | * | ||
| 96 | * Bookkeeping structure for per-proc address space management for binder | ||
| 97 | * buffers. It is normally initialized during binder_init() and binder_mmap() | ||
| 98 | * calls. The address space is used for both user-visible buffers and for | ||
| 99 | * struct binder_buffer objects used to track the user buffers | ||
| 100 | */ | ||
| 101 | struct binder_alloc { | ||
| 102 | struct mutex mutex; | ||
| 103 | struct task_struct *tsk; | ||
| 104 | struct vm_area_struct *vma; | ||
| 105 | struct mm_struct *vma_vm_mm; | ||
| 106 | void *buffer; | ||
| 107 | ptrdiff_t user_buffer_offset; | ||
| 108 | struct list_head buffers; | ||
| 109 | struct rb_root free_buffers; | ||
| 110 | struct rb_root allocated_buffers; | ||
| 111 | size_t free_async_space; | ||
| 112 | struct binder_lru_page *pages; | ||
| 113 | size_t buffer_size; | ||
| 114 | uint32_t buffer_free; | ||
| 115 | int pid; | ||
| 116 | }; | ||
| 117 | |||
| 118 | #ifdef CONFIG_ANDROID_BINDER_IPC_SELFTEST | ||
| 119 | void binder_selftest_alloc(struct binder_alloc *alloc); | ||
| 120 | #else | ||
| 121 | static inline void binder_selftest_alloc(struct binder_alloc *alloc) {} | ||
| 122 | #endif | ||
| 123 | enum lru_status binder_alloc_free_page(struct list_head *item, | ||
| 124 | struct list_lru_one *lru, | ||
| 125 | spinlock_t *lock, void *cb_arg); | ||
| 126 | extern struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc, | ||
| 127 | size_t data_size, | ||
| 128 | size_t offsets_size, | ||
| 129 | size_t extra_buffers_size, | ||
| 130 | int is_async); | ||
| 131 | extern void binder_alloc_init(struct binder_alloc *alloc); | ||
| 132 | void binder_alloc_shrinker_init(void); | ||
| 133 | extern void binder_alloc_vma_close(struct binder_alloc *alloc); | ||
| 134 | extern struct binder_buffer * | ||
| 135 | binder_alloc_prepare_to_free(struct binder_alloc *alloc, | ||
| 136 | uintptr_t user_ptr); | ||
| 137 | extern void binder_alloc_free_buf(struct binder_alloc *alloc, | ||
| 138 | struct binder_buffer *buffer); | ||
| 139 | extern int binder_alloc_mmap_handler(struct binder_alloc *alloc, | ||
| 140 | struct vm_area_struct *vma); | ||
| 141 | extern void binder_alloc_deferred_release(struct binder_alloc *alloc); | ||
| 142 | extern int binder_alloc_get_allocated_count(struct binder_alloc *alloc); | ||
| 143 | extern void binder_alloc_print_allocated(struct seq_file *m, | ||
| 144 | struct binder_alloc *alloc); | ||
| 145 | void binder_alloc_print_pages(struct seq_file *m, | ||
| 146 | struct binder_alloc *alloc); | ||
| 147 | |||
| 148 | /** | ||
| 149 | * binder_alloc_get_free_async_space() - get free space available for async | ||
| 150 | * @alloc: binder_alloc for this proc | ||
| 151 | * | ||
| 152 | * Return: the bytes remaining in the address-space for async transactions | ||
| 153 | */ | ||
| 154 | static inline size_t | ||
| 155 | binder_alloc_get_free_async_space(struct binder_alloc *alloc) | ||
| 156 | { | ||
| 157 | size_t free_async_space; | ||
| 158 | |||
| 159 | mutex_lock(&alloc->mutex); | ||
| 160 | free_async_space = alloc->free_async_space; | ||
| 161 | mutex_unlock(&alloc->mutex); | ||
| 162 | return free_async_space; | ||
| 163 | } | ||
| 164 | |||
| 165 | /** | ||
| 166 | * binder_alloc_get_user_buffer_offset() - get offset between kernel/user addrs | ||
| 167 | * @alloc: binder_alloc for this proc | ||
| 168 | * | ||
| 169 | * Return: the offset between kernel and user-space addresses to use for | ||
| 170 | * virtual address conversion | ||
| 171 | */ | ||
| 172 | static inline ptrdiff_t | ||
| 173 | binder_alloc_get_user_buffer_offset(struct binder_alloc *alloc) | ||
| 174 | { | ||
| 175 | /* | ||
| 176 | * user_buffer_offset is constant if vma is set and | ||
| 177 | * undefined if vma is not set. It is possible to | ||
| 178 | * get here with !alloc->vma if the target process | ||
| 179 | * is dying while a transaction is being initiated. | ||
| 180 | * Returning the old value is ok in this case and | ||
| 181 | * the transaction will fail. | ||
| 182 | */ | ||
| 183 | return alloc->user_buffer_offset; | ||
| 184 | } | ||
| 185 | |||
| 186 | #endif /* _LINUX_BINDER_ALLOC_H */ | ||
| 187 | |||
| @@ -0,0 +1,310 @@ | |||
| 1 | /* binder_alloc_selftest.c | ||
| 2 | * | ||
| 3 | * Android IPC Subsystem | ||
| 4 | * | ||
| 5 | * Copyright (C) 2017 Google, Inc. | ||
| 6 | * | ||
| 7 | * This software is licensed under the terms of the GNU General Public | ||
| 8 | * License version 2, as published by the Free Software Foundation, and | ||
| 9 | * may be copied, distributed, and modified under those terms. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | */ | ||
| 17 | |||
| 18 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
| 19 | |||
| 20 | #include <linux/mm_types.h> | ||
| 21 | #include <linux/err.h> | ||
| 22 | #include "binder_alloc.h" | ||
| 23 | |||
| 24 | #define BUFFER_NUM 5 | ||
| 25 | #define BUFFER_MIN_SIZE (PAGE_SIZE / 8) | ||
| 26 | |||
| 27 | static bool binder_selftest_run = true; | ||
| 28 | static int binder_selftest_failures; | ||
| 29 | static DEFINE_MUTEX(binder_selftest_lock); | ||
| 30 | |||
| 31 | /** | ||
| 32 | * enum buf_end_align_type - Page alignment of a buffer | ||
| 33 | * end with regard to the end of the previous buffer. | ||
| 34 | * | ||
| 35 | * In the pictures below, buf2 refers to the buffer we | ||
| 36 | * are aligning. buf1 refers to previous buffer by addr. | ||
| 37 | * Symbol [ means the start of a buffer, ] means the end | ||
| 38 | * of a buffer, and | means page boundaries. | ||
| 39 | */ | ||
| 40 | enum buf_end_align_type { | ||
| 41 | /** | ||
| 42 | * @SAME_PAGE_UNALIGNED: The end of this buffer is on | ||
| 43 | * the same page as the end of the previous buffer and | ||
| 44 | * is not page aligned. Examples: | ||
| 45 | * buf1 ][ buf2 ][ ... | ||
| 46 | * buf1 ]|[ buf2 ][ ... | ||
| 47 | */ | ||
| 48 | SAME_PAGE_UNALIGNED = 0, | ||
| 49 | /** | ||
| 50 | * @SAME_PAGE_ALIGNED: When the end of the previous buffer | ||
| 51 | * is not page aligned, the end of this buffer is on the | ||
| 52 | * same page as the end of the previous buffer and is page | ||
| 53 | * aligned. When the previous buffer is page aligned, the | ||
| 54 | * end of this buffer is aligned to the next page boundary. | ||
| 55 | * Examples: | ||
| 56 | * buf1 ][ buf2 ]| ... | ||
| 57 | * buf1 ]|[ buf2 ]| ... | ||
| 58 | */ | ||
| 59 | SAME_PAGE_ALIGNED, | ||
| 60 | /** | ||
| 61 | * @NEXT_PAGE_UNALIGNED: The end of this buffer is on | ||
| 62 | * the page next to the end of the previous buffer and | ||
| 63 | * is not page aligned. Examples: | ||
| 64 | * buf1 ][ buf2 | buf2 ][ ... | ||
| 65 | * buf1 ]|[ buf2 | buf2 ][ ... | ||
| 66 | */ | ||
| 67 | NEXT_PAGE_UNALIGNED, | ||
| 68 | /** | ||
| 69 | * @NEXT_PAGE_ALIGNED: The end of this buffer is on | ||
| 70 | * the page next to the end of the previous buffer and | ||
| 71 | * is page aligned. Examples: | ||
| 72 | * buf1 ][ buf2 | buf2 ]| ... | ||
| 73 | * buf1 ]|[ buf2 | buf2 ]| ... | ||
| 74 | */ | ||
| 75 | NEXT_PAGE_ALIGNED, | ||
| 76 | /** | ||
| 77 | * @NEXT_NEXT_UNALIGNED: The end of this buffer is on | ||
| 78 | * the page that follows the page after the end of the | ||
| 79 | * previous buffer and is not page aligned. Examples: | ||
| 80 | * buf1 ][ buf2 | buf2 | buf2 ][ ... | ||
| 81 | * buf1 ]|[ buf2 | buf2 | buf2 ][ ... | ||
| 82 | */ | ||
| 83 | NEXT_NEXT_UNALIGNED, | ||
| 84 | LOOP_END, | ||
| 85 | }; | ||
| 86 | |||
| 87 | static void pr_err_size_seq(size_t *sizes, int *seq) | ||
| 88 | { | ||
| 89 | int i; | ||
| 90 | |||
| 91 | pr_err("alloc sizes: "); | ||
| 92 | for (i = 0; i < BUFFER_NUM; i++) | ||
| 93 | pr_cont("[%zu]", sizes[i]); | ||
| 94 | pr_cont("\n"); | ||
| 95 | pr_err("free seq: "); | ||
| 96 | for (i = 0; i < BUFFER_NUM; i++) | ||
| 97 | pr_cont("[%d]", seq[i]); | ||
| 98 | pr_cont("\n"); | ||
| 99 | } | ||
| 100 | |||
| 101 | static bool check_buffer_pages_allocated(struct binder_alloc *alloc, | ||
| 102 | struct binder_buffer *buffer, | ||
| 103 | size_t size) | ||
| 104 | { | ||
| 105 | void *page_addr, *end; | ||
| 106 | int page_index; | ||
| 107 | |||
| 108 | end = (void *)PAGE_ALIGN((uintptr_t)buffer->data + size); | ||
| 109 | page_addr = buffer->data; | ||
| 110 | for (; page_addr < end; page_addr += PAGE_SIZE) { | ||
| 111 | page_index = (page_addr - alloc->buffer) / PAGE_SIZE; | ||
| 112 | if (!alloc->pages[page_index].page_ptr || | ||
| 113 | !list_empty(&alloc->pages[page_index].lru)) { | ||
| 114 | pr_err("expect alloc but is %s at page index %d\n", | ||
| 115 | alloc->pages[page_index].page_ptr ? | ||
| 116 | "lru" : "free", page_index); | ||
| 117 | return false; | ||
| 118 | } | ||
| 119 | } | ||
| 120 | return true; | ||
| 121 | } | ||
| 122 | |||
| 123 | static void binder_selftest_alloc_buf(struct binder_alloc *alloc, | ||
| 124 | struct binder_buffer *buffers[], | ||
| 125 | size_t *sizes, int *seq) | ||
| 126 | { | ||
| 127 | int i; | ||
| 128 | |||
| 129 | for (i = 0; i < BUFFER_NUM; i++) { | ||
| 130 | buffers[i] = binder_alloc_new_buf(alloc, sizes[i], 0, 0, 0); | ||
| 131 | if (IS_ERR(buffers[i]) || | ||
| 132 | !check_buffer_pages_allocated(alloc, buffers[i], | ||
| 133 | sizes[i])) { | ||
| 134 | pr_err_size_seq(sizes, seq); | ||
| 135 | binder_selftest_failures++; | ||
| 136 | } | ||
| 137 | } | ||
| 138 | } | ||
| 139 | |||
| 140 | static void binder_selftest_free_buf(struct binder_alloc *alloc, | ||
| 141 | struct binder_buffer *buffers[], | ||
| 142 | size_t *sizes, int *seq, size_t end) | ||
| 143 | { | ||
| 144 | int i; | ||
| 145 | |||
| 146 | for (i = 0; i < BUFFER_NUM; i++) | ||
| 147 | binder_alloc_free_buf(alloc, buffers[seq[i]]); | ||
| 148 | |||
| 149 | for (i = 0; i < end / PAGE_SIZE; i++) { | ||
| 150 | /** | ||
| 151 | * Error message on a free page can be false positive | ||
| 152 | * if binder shrinker ran during binder_alloc_free_buf | ||
| 153 | * calls above. | ||
| 154 | */ | ||
| 155 | if (list_empty(&alloc->pages[i].lru)) { | ||
| 156 | pr_err_size_seq(sizes, seq); | ||
| 157 | pr_err("expect lru but is %s at page index %d\n", | ||
| 158 | alloc->pages[i].page_ptr ? "alloc" : "free", i); | ||
| 159 | binder_selftest_failures++; | ||
| 160 | } | ||
| 161 | } | ||
| 162 | } | ||
| 163 | |||
| 164 | static void binder_selftest_free_page(struct binder_alloc *alloc) | ||
| 165 | { | ||
| 166 | int i; | ||
| 167 | unsigned long count; | ||
| 168 | |||
| 169 | while ((count = list_lru_count(&binder_alloc_lru))) { | ||
| 170 | list_lru_walk(&binder_alloc_lru, binder_alloc_free_page, | ||
| 171 | NULL, count); | ||
| 172 | } | ||
| 173 | |||
| 174 | for (i = 0; i < (alloc->buffer_size / PAGE_SIZE); i++) { | ||
| 175 | if (alloc->pages[i].page_ptr) { | ||
| 176 | pr_err("expect free but is %s at page index %d\n", | ||
| 177 | list_empty(&alloc->pages[i].lru) ? | ||
| 178 | "alloc" : "lru", i); | ||
| 179 | binder_selftest_failures++; | ||
| 180 | } | ||
| 181 | } | ||
| 182 | } | ||
| 183 | |||
| 184 | static void binder_selftest_alloc_free(struct binder_alloc *alloc, | ||
| 185 | size_t *sizes, int *seq, size_t end) | ||
| 186 | { | ||
| 187 | struct binder_buffer *buffers[BUFFER_NUM]; | ||
| 188 | |||
| 189 | binder_selftest_alloc_buf(alloc, buffers, sizes, seq); | ||
| 190 | binder_selftest_free_buf(alloc, buffers, sizes, seq, end); | ||
| 191 | |||
| 192 | /* Allocate from lru. */ | ||
| 193 | binder_selftest_alloc_buf(alloc, buffers, sizes, seq); | ||
| 194 | if (list_lru_count(&binder_alloc_lru)) | ||
| 195 | pr_err("lru list should be empty but is not\n"); | ||
| 196 | |||
| 197 | binder_selftest_free_buf(alloc, buffers, sizes, seq, end); | ||
| 198 | binder_selftest_free_page(alloc); | ||
| 199 | } | ||
| 200 | |||
| 201 | static bool is_dup(int *seq, int index, int val) | ||
| 202 | { | ||
| 203 | int i; | ||
| 204 | |||
| 205 | for (i = 0; i < index; i++) { | ||
| 206 | if (seq[i] == val) | ||
| 207 | return true; | ||
| 208 | } | ||
| 209 | return false; | ||
| 210 | } | ||
| 211 | |||
| 212 | /* Generate BUFFER_NUM factorial free orders. */ | ||
| 213 | static void binder_selftest_free_seq(struct binder_alloc *alloc, | ||
| 214 | size_t *sizes, int *seq, | ||
| 215 | int index, size_t end) | ||
| 216 | { | ||
| 217 | int i; | ||
| 218 | |||
| 219 | if (index == BUFFER_NUM) { | ||
| 220 | binder_selftest_alloc_free(alloc, sizes, seq, end); | ||
| 221 | return; | ||
| 222 | } | ||
| 223 | for (i = 0; i < BUFFER_NUM; i++) { | ||
| 224 | if (is_dup(seq, index, i)) | ||
| 225 | continue; | ||
| 226 | seq[index] = i; | ||
| 227 | binder_selftest_free_seq(alloc, sizes, seq, index + 1, end); | ||
| 228 | } | ||
| 229 | } | ||
| 230 | |||
| 231 | static void binder_selftest_alloc_size(struct binder_alloc *alloc, | ||
| 232 | size_t *end_offset) | ||
| 233 | { | ||
| 234 | int i; | ||
| 235 | int seq[BUFFER_NUM] = {0}; | ||
| 236 | size_t front_sizes[BUFFER_NUM]; | ||
| 237 | size_t back_sizes[BUFFER_NUM]; | ||
| 238 | size_t last_offset, offset = 0; | ||
| 239 | |||
| 240 | for (i = 0; i < BUFFER_NUM; i++) { | ||
| 241 | last_offset = offset; | ||
| 242 | offset = end_offset[i]; | ||
| 243 | front_sizes[i] = offset - last_offset; | ||
| 244 | back_sizes[BUFFER_NUM - i - 1] = front_sizes[i]; | ||
| 245 | } | ||
| 246 | /* | ||
| 247 | * Buffers share the first or last few pages. | ||
| 248 | * Only BUFFER_NUM - 1 buffer sizes are adjustable since | ||
| 249 | * we need one giant buffer before getting to the last page. | ||
| 250 | */ | ||
| 251 | back_sizes[0] += alloc->buffer_size - end_offset[BUFFER_NUM - 1]; | ||
| 252 | binder_selftest_free_seq(alloc, front_sizes, seq, 0, | ||
| 253 | end_offset[BUFFER_NUM - 1]); | ||
| 254 | binder_selftest_free_seq(alloc, back_sizes, seq, 0, alloc->buffer_size); | ||
| 255 | } | ||
| 256 | |||
| 257 | static void binder_selftest_alloc_offset(struct binder_alloc *alloc, | ||
| 258 | size_t *end_offset, int index) | ||
| 259 | { | ||
| 260 | int align; | ||
| 261 | size_t end, prev; | ||
| 262 | |||
| 263 | if (index == BUFFER_NUM) { | ||
| 264 | binder_selftest_alloc_size(alloc, end_offset); | ||
| 265 | return; | ||
| 266 | } | ||
| 267 | prev = index == 0 ? 0 : end_offset[index - 1]; | ||
| 268 | end = prev; | ||
| 269 | |||
| 270 | BUILD_BUG_ON(BUFFER_MIN_SIZE * BUFFER_NUM >= PAGE_SIZE); | ||
| 271 | |||
| 272 | for (align = SAME_PAGE_UNALIGNED; align < LOOP_END; align++) { | ||
| 273 | if (align % 2) | ||
| 274 | end = ALIGN(end, PAGE_SIZE); | ||
| 275 | else | ||
| 276 | end += BUFFER_MIN_SIZE; | ||
| 277 | end_offset[index] = end; | ||
| 278 | binder_selftest_alloc_offset(alloc, end_offset, index + 1); | ||
| 279 | } | ||
| 280 | } | ||
| 281 | |||
| 282 | /** | ||
| 283 | * binder_selftest_alloc() - Test alloc and free of buffer pages. | ||
| 284 | * @alloc: Pointer to alloc struct. | ||
| 285 | * | ||
| 286 | * Allocate BUFFER_NUM buffers to cover all page alignment cases, | ||
| 287 | * then free them in all orders possible. Check that pages are | ||
| 288 | * correctly allocated, put onto lru when buffers are freed, and | ||
| 289 | * are freed when binder_alloc_free_page is called. | ||
| 290 | */ | ||
| 291 | void binder_selftest_alloc(struct binder_alloc *alloc) | ||
| 292 | { | ||
| 293 | size_t end_offset[BUFFER_NUM]; | ||
| 294 | |||
| 295 | if (!binder_selftest_run) | ||
| 296 | return; | ||
| 297 | mutex_lock(&binder_selftest_lock); | ||
| 298 | if (!binder_selftest_run || !alloc->vma) | ||
| 299 | goto done; | ||
| 300 | pr_info("STARTED\n"); | ||
| 301 | binder_selftest_alloc_offset(alloc, end_offset, 0); | ||
| 302 | binder_selftest_run = false; | ||
| 303 | if (binder_selftest_failures > 0) | ||
| 304 | pr_info("%d tests FAILED\n", binder_selftest_failures); | ||
| 305 | else | ||
| 306 | pr_info("PASSED\n"); | ||
| 307 | |||
| 308 | done: | ||
| 309 | mutex_unlock(&binder_selftest_lock); | ||
| 310 | } | ||
| @@ -23,7 +23,8 @@ · 22 unmodified lines | |||
| 23 | struct binder_buffer; | 23 | struct binder_buffer; |
| 24 | struct binder_node; | 24 | struct binder_node; |
| 25 | struct binder_proc; | 25 | struct binder_proc; |
| 26 | struct binder_ref; | 26 | struct binder_alloc; |
| 27 | struct binder_ref_data; | ||
| 27 | struct binder_thread; | 28 | struct binder_thread; |
| 28 | struct binder_transaction; | 29 | struct binder_transaction; |
| 29 | 30 | ||
| @@ -146,8 +147,8 @@ TRACE_EVENT(binder_transaction_received, · 116 unmodified lines | |||
| 146 | 147 | ||
| 147 | TRACE_EVENT(binder_transaction_node_to_ref, | 148 | TRACE_EVENT(binder_transaction_node_to_ref, |
| 148 | TP_PROTO(struct binder_transaction *t, struct binder_node *node, | 149 | TP_PROTO(struct binder_transaction *t, struct binder_node *node, |
| 149 | struct binder_ref *ref), | 150 | struct binder_ref_data *rdata), |
| 150 | TP_ARGS(t, node, ref), | 151 | TP_ARGS(t, node, rdata), |
| 151 | 152 | ||
| 152 | TP_STRUCT__entry( | 153 | TP_STRUCT__entry( |
| 153 | __field(int, debug_id) | 154 | __field(int, debug_id) |
| @@ -160,8 +161,8 @@ TRACE_EVENT(binder_transaction_node_to_ref, · 6 unmodified lines | |||
| 160 | __entry->debug_id = t->debug_id; | 161 | __entry->debug_id = t->debug_id; |
| 161 | __entry->node_debug_id = node->debug_id; | 162 | __entry->node_debug_id = node->debug_id; |
| 162 | __entry->node_ptr = node->ptr; | 163 | __entry->node_ptr = node->ptr; |
| 163 | __entry->ref_debug_id = ref->debug_id; | 164 | __entry->ref_debug_id = rdata->debug_id; |
| 164 | __entry->ref_desc = ref->desc; | 165 | __entry->ref_desc = rdata->desc; |
| 165 | ), | 166 | ), |
| 166 | TP_printk("transaction=%d node=%d src_ptr=0x%016llx ==> dest_ref=%d dest_desc=%d", | 167 | TP_printk("transaction=%d node=%d src_ptr=0x%016llx ==> dest_ref=%d dest_desc=%d", |
| 167 | __entry->debug_id, __entry->node_debug_id, | 168 | __entry->debug_id, __entry->node_debug_id, |
| @@ -170,8 +171,9 @@ TRACE_EVENT(binder_transaction_node_to_ref, · 2 unmodified lines | |||
| 170 | ); | 171 | ); |
| 171 | 172 | ||
| 172 | TRACE_EVENT(binder_transaction_ref_to_node, | 173 | TRACE_EVENT(binder_transaction_ref_to_node, |
| 173 | TP_PROTO(struct binder_transaction *t, struct binder_ref *ref), | 174 | TP_PROTO(struct binder_transaction *t, struct binder_node *node, |
| 174 | TP_ARGS(t, ref), | 175 | struct binder_ref_data *rdata), |
| 176 | TP_ARGS(t, node, rdata), | ||
| 175 | 177 | ||
| 176 | TP_STRUCT__entry( | 178 | TP_STRUCT__entry( |
| 177 | __field(int, debug_id) | 179 | __field(int, debug_id) |
| @@ -182,10 +184,10 @@ TRACE_EVENT(binder_transaction_ref_to_node, · 4 unmodified lines | |||
| 182 | ), | 184 | ), |
| 183 | TP_fast_assign( | 185 | TP_fast_assign( |
| 184 | __entry->debug_id = t->debug_id; | 186 | __entry->debug_id = t->debug_id; |
| 185 | __entry->ref_debug_id = ref->debug_id; | 187 | __entry->ref_debug_id = rdata->debug_id; |
| 186 | __entry->ref_desc = ref->desc; | 188 | __entry->ref_desc = rdata->desc; |
| 187 | __entry->node_debug_id = ref->node->debug_id; | 189 | __entry->node_debug_id = node->debug_id; |
| 188 | __entry->node_ptr = ref->node->ptr; | 190 | __entry->node_ptr = node->ptr; |
| 189 | ), | 191 | ), |
| 190 | TP_printk("transaction=%d node=%d src_ref=%d src_desc=%d ==> dest_ptr=0x%016llx", | 192 | TP_printk("transaction=%d node=%d src_ref=%d src_desc=%d ==> dest_ptr=0x%016llx", |
| 191 | __entry->debug_id, __entry->node_debug_id, | 193 | __entry->debug_id, __entry->node_debug_id, |
| @@ -194,9 +196,10 @@ TRACE_EVENT(binder_transaction_ref_to_node, · 2 unmodified lines | |||
| 194 | ); | 196 | ); |
| 195 | 197 | ||
| 196 | TRACE_EVENT(binder_transaction_ref_to_ref, | 198 | TRACE_EVENT(binder_transaction_ref_to_ref, |
| 197 | TP_PROTO(struct binder_transaction *t, struct binder_ref *src_ref, | 199 | TP_PROTO(struct binder_transaction *t, struct binder_node *node, |
| 198 | struct binder_ref *dest_ref), | 200 | struct binder_ref_data *src_ref, |
| 199 | TP_ARGS(t, src_ref, dest_ref), | 201 | struct binder_ref_data *dest_ref), |
| 202 | TP_ARGS(t, node, src_ref, dest_ref), | ||
| 200 | 203 | ||
| 201 | TP_STRUCT__entry( | 204 | TP_STRUCT__entry( |
| 202 | __field(int, debug_id) | 205 | __field(int, debug_id) |
| @@ -208,7 +211,7 @@ TRACE_EVENT(binder_transaction_ref_to_ref, · 5 unmodified lines | |||
| 208 | ), | 211 | ), |
| 209 | TP_fast_assign( | 212 | TP_fast_assign( |
| 210 | __entry->debug_id = t->debug_id; | 213 | __entry->debug_id = t->debug_id; |
| 211 | __entry->node_debug_id = src_ref->node->debug_id; | 214 | __entry->node_debug_id = node->debug_id; |
| 212 | __entry->src_ref_debug_id = src_ref->debug_id; | 215 | __entry->src_ref_debug_id = src_ref->debug_id; |
| 213 | __entry->src_ref_desc = src_ref->desc; | 216 | __entry->src_ref_desc = src_ref->desc; |
| 214 | __entry->dest_ref_debug_id = dest_ref->debug_id; | 217 | __entry->dest_ref_debug_id = dest_ref->debug_id; |
| @@ -268,9 +271,9 @@ DEFINE_EVENT(binder_buffer_class, binder_transaction_failed_buffer_release, · 53 unmodified lines | |||
| 268 | TP_ARGS(buffer)); | 271 | TP_ARGS(buffer)); |
| 269 | 272 | ||
| 270 | TRACE_EVENT(binder_update_page_range, | 273 | TRACE_EVENT(binder_update_page_range, |
| 271 | TP_PROTO(struct binder_proc *proc, bool allocate, | 274 | TP_PROTO(struct binder_alloc *alloc, bool allocate, |
| 272 | void *start, void *end), | 275 | void *start, void *end), |
| 273 | TP_ARGS(proc, allocate, start, end), | 276 | TP_ARGS(alloc, allocate, start, end), |
| 274 | TP_STRUCT__entry( | 277 | TP_STRUCT__entry( |
| 275 | __field(int, proc) | 278 | __field(int, proc) |
| 276 | __field(bool, allocate) | 279 | __field(bool, allocate) |
| @@ -278,9 +281,9 @@ TRACE_EVENT(binder_update_page_range, · 1 unmodified line | |||
| 278 | __field(size_t, size) | 281 | __field(size_t, size) |
| 279 | ), | 282 | ), |
| 280 | TP_fast_assign( | 283 | TP_fast_assign( |
| 281 | __entry->proc = proc->pid; | 284 | __entry->proc = alloc->pid; |
| 282 | __entry->allocate = allocate; | 285 | __entry->allocate = allocate; |
| 283 | __entry->offset = start - proc->buffer; | 286 | __entry->offset = start - alloc->buffer; |
| 284 | __entry->size = end - start; | 287 | __entry->size = end - start; |
| 285 | ), | 288 | ), |
| 286 | TP_printk("proc=%d allocate=%d offset=%zu size=%zu", | 289 | TP_printk("proc=%d allocate=%d offset=%zu size=%zu", |
| @@ -288,6 +291,61 @@ TRACE_EVENT(binder_update_page_range, · 1 unmodified line | |||
| 288 | __entry->offset, __entry->size) | 291 | __entry->offset, __entry->size) |
| 289 | ); | 292 | ); |
| 290 | 293 | ||
| 294 | DECLARE_EVENT_CLASS(binder_lru_page_class, | ||
| 295 | TP_PROTO(const struct binder_alloc *alloc, size_t page_index), | ||
| 296 | TP_ARGS(alloc, page_index), | ||
| 297 | TP_STRUCT__entry( | ||
| 298 | __field(int, proc) | ||
| 299 | __field(size_t, page_index) | ||
| 300 | ), | ||
| 301 | TP_fast_assign( | ||
| 302 | __entry->proc = alloc->pid; | ||
| 303 | __entry->page_index = page_index; | ||
| 304 | ), | ||
| 305 | TP_printk("proc=%d page_index=%zu", | ||
| 306 | __entry->proc, __entry->page_index) | ||
| 307 | ); | ||
| 308 | |||
| 309 | DEFINE_EVENT(binder_lru_page_class, binder_alloc_lru_start, | ||
| 310 | TP_PROTO(const struct binder_alloc *alloc, size_t page_index), | ||
| 311 | TP_ARGS(alloc, page_index)); | ||
| 312 | |||
| 313 | DEFINE_EVENT(binder_lru_page_class, binder_alloc_lru_end, | ||
| 314 | TP_PROTO(const struct binder_alloc *alloc, size_t page_index), | ||
| 315 | TP_ARGS(alloc, page_index)); | ||
| 316 | |||
| 317 | DEFINE_EVENT(binder_lru_page_class, binder_free_lru_start, | ||
| 318 | TP_PROTO(const struct binder_alloc *alloc, size_t page_index), | ||
| 319 | TP_ARGS(alloc, page_index)); | ||
| 320 | |||
| 321 | DEFINE_EVENT(binder_lru_page_class, binder_free_lru_end, | ||
| 322 | TP_PROTO(const struct binder_alloc *alloc, size_t page_index), | ||
| 323 | TP_ARGS(alloc, page_index)); | ||
| 324 | |||
| 325 | DEFINE_EVENT(binder_lru_page_class, binder_alloc_page_start, | ||
| 326 | TP_PROTO(const struct binder_alloc *alloc, size_t page_index), | ||
| 327 | TP_ARGS(alloc, page_index)); | ||
| 328 | |||
| 329 | DEFINE_EVENT(binder_lru_page_class, binder_alloc_page_end, | ||
| 330 | TP_PROTO(const struct binder_alloc *alloc, size_t page_index), | ||
| 331 | TP_ARGS(alloc, page_index)); | ||
| 332 | |||
| 333 | DEFINE_EVENT(binder_lru_page_class, binder_unmap_user_start, | ||
| 334 | TP_PROTO(const struct binder_alloc *alloc, size_t page_index), | ||
| 335 | TP_ARGS(alloc, page_index)); | ||
| 336 | |||
| 337 | DEFINE_EVENT(binder_lru_page_class, binder_unmap_user_end, | ||
| 338 | TP_PROTO(const struct binder_alloc *alloc, size_t page_index), | ||
| 339 | TP_ARGS(alloc, page_index)); | ||
| 340 | |||
| 341 | DEFINE_EVENT(binder_lru_page_class, binder_unmap_kernel_start, | ||
| 342 | TP_PROTO(const struct binder_alloc *alloc, size_t page_index), | ||
| 343 | TP_ARGS(alloc, page_index)); | ||
| 344 | |||
| 345 | DEFINE_EVENT(binder_lru_page_class, binder_unmap_kernel_end, | ||
| 346 | TP_PROTO(const struct binder_alloc *alloc, size_t page_index), | ||
| 347 | TP_ARGS(alloc, page_index)); | ||
| 348 | |||
| 291 | TRACE_EVENT(binder_command, | 349 | TRACE_EVENT(binder_command, |
| 292 | TP_PROTO(uint32_t cmd), | 350 | TP_PROTO(uint32_t cmd), |
| 293 | TP_ARGS(cmd), | 351 | TP_ARGS(cmd), |
| @@ -877,21 +877,21 @@ static void lcd_clear_fast_tilcd(struct charlcd *charlcd) · 876 unmodified lines | |||
| 877 | spin_unlock_irq(&pprt_lock); | 877 | spin_unlock_irq(&pprt_lock); |
| 878 | } | 878 | } |
| 879 | 879 | ||
| 880 | static struct charlcd_ops charlcd_serial_ops = { | 880 | static const struct charlcd_ops charlcd_serial_ops = { |
| 881 | .write_cmd = lcd_write_cmd_s, | 881 | .write_cmd = lcd_write_cmd_s, |
| 882 | .write_data = lcd_write_data_s, | 882 | .write_data = lcd_write_data_s, |
| 883 | .clear_fast = lcd_clear_fast_s, | 883 | .clear_fast = lcd_clear_fast_s, |
| 884 | .backlight = lcd_backlight, | 884 | .backlight = lcd_backlight, |
| 885 | }; | 885 | }; |
| 886 | 886 | ||
| 887 | static struct charlcd_ops charlcd_parallel_ops = { | 887 | static const struct charlcd_ops charlcd_parallel_ops = { |
| 888 | .write_cmd = lcd_write_cmd_p8, | 888 | .write_cmd = lcd_write_cmd_p8, |
| 889 | .write_data = lcd_write_data_p8, | 889 | .write_data = lcd_write_data_p8, |
| 890 | .clear_fast = lcd_clear_fast_p8, | 890 | .clear_fast = lcd_clear_fast_p8, |
| 891 | .backlight = lcd_backlight, | 891 | .backlight = lcd_backlight, |
| 892 | }; | 892 | }; |
| 893 | 893 | ||
| 894 | static struct charlcd_ops charlcd_tilcd_ops = { | 894 | static const struct charlcd_ops charlcd_tilcd_ops = { |
| 895 | .write_cmd = lcd_write_cmd_tilcd, | 895 | .write_cmd = lcd_write_cmd_tilcd, |
| 896 | .write_data = lcd_write_data_tilcd, | 896 | .write_data = lcd_write_data_tilcd, |
| 897 | .clear_fast = lcd_clear_fast_tilcd, | 897 | .clear_fast = lcd_clear_fast_tilcd, |
| @@ -67,7 +67,7 @@ static char *applicom_pci_devnames[] = { · 66 unmodified lines | |||
| 67 | "PCI2000PFB" | 67 | "PCI2000PFB" |
| 68 | }; | 68 | }; |
| 69 | 69 | ||
| 70 | static struct pci_device_id applicom_pci_tbl[] = { | 70 | static const struct pci_device_id applicom_pci_tbl[] = { |
| 71 | { PCI_VDEVICE(APPLICOM, PCI_DEVICE_ID_APPLICOM_PCIGENERIC) }, | 71 | { PCI_VDEVICE(APPLICOM, PCI_DEVICE_ID_APPLICOM_PCIGENERIC) }, |
| 72 | { PCI_VDEVICE(APPLICOM, PCI_DEVICE_ID_APPLICOM_PCI2000IBS_CAN) }, | 72 | { PCI_VDEVICE(APPLICOM, PCI_DEVICE_ID_APPLICOM_PCI2000IBS_CAN) }, |
| 73 | { PCI_VDEVICE(APPLICOM, PCI_DEVICE_ID_APPLICOM_PCI2000PFB) }, | 73 | { PCI_VDEVICE(APPLICOM, PCI_DEVICE_ID_APPLICOM_PCI2000PFB) }, |
| @@ -128,10 +128,11 @@ int smapi_query_DSP_cfg(SMAPI_DSP_SETTINGS * pSettings) · 127 unmodified lines | |||
| 128 | { | 128 | { |
| 129 | int bRC = -EIO; | 129 | int bRC = -EIO; |
| 130 | unsigned short usAX, usBX, usCX, usDX, usDI, usSI; | 130 | unsigned short usAX, usBX, usCX, usDX, usDI, usSI; |
| 131 | unsigned short ausDspBases[] = { 0x0030, 0x4E30, 0x8E30, 0xCE30, 0x0130, 0x0350, 0x0070, 0x0DB0 }; | 131 | static const unsigned short ausDspBases[] = { |
| 132 | unsigned short ausUartBases[] = { 0x03F8, 0x02F8, 0x03E8, 0x02E8 }; | 132 | 0x0030, 0x4E30, 0x8E30, 0xCE30, |
| 133 | unsigned short numDspBases = 8; | 133 | 0x0130, 0x0350, 0x0070, 0x0DB0 }; |
| 134 | unsigned short numUartBases = 4; | 134 | static const unsigned short ausUartBases[] = { |
| 135 | 0x03F8, 0x02F8, 0x03E8, 0x02E8 }; | ||
| 135 | 136 | ||
| 136 | PRINTK_1(TRACE_SMAPI, "smapi::smapi_query_DSP_cfg entry\n"); | 137 | PRINTK_1(TRACE_SMAPI, "smapi::smapi_query_DSP_cfg entry\n"); |
| 137 | 138 | ||
| @@ -148,7 +149,7 @@ int smapi_query_DSP_cfg(SMAPI_DSP_SETTINGS * pSettings) · 10 unmodified lines | |||
| 148 | pSettings->bDSPEnabled = ((usCX & 0x0001) != 0); | 149 | pSettings->bDSPEnabled = ((usCX & 0x0001) != 0); |
| 149 | pSettings->usDspIRQ = usSI & 0x00FF; | 150 | pSettings->usDspIRQ = usSI & 0x00FF; |
| 150 | pSettings->usDspDMA = (usSI & 0xFF00) >> 8; | 151 | pSettings->usDspDMA = (usSI & 0xFF00) >> 8; |
| 151 | if ((usDI & 0x00FF) < numDspBases) { | 152 | if ((usDI & 0x00FF) < ARRAY_SIZE(ausDspBases)) { |
| 152 | pSettings->usDspBaseIO = ausDspBases[usDI & 0x00FF]; | 153 | pSettings->usDspBaseIO = ausDspBases[usDI & 0x00FF]; |
| 153 | } else { | 154 | } else { |
| 154 | pSettings->usDspBaseIO = 0; | 155 | pSettings->usDspBaseIO = 0; |
| @@ -176,7 +177,7 @@ int smapi_query_DSP_cfg(SMAPI_DSP_SETTINGS * pSettings) · 21 unmodified lines | |||
| 176 | 177 | ||
| 177 | pSettings->bModemEnabled = ((usCX & 0x0001) != 0); | 178 | pSettings->bModemEnabled = ((usCX & 0x0001) != 0); |
| 178 | pSettings->usUartIRQ = usSI & 0x000F; | 179 | pSettings->usUartIRQ = usSI & 0x000F; |
| 179 | if (((usSI & 0xFF00) >> 8) < numUartBases) { | 180 | if (((usSI & 0xFF00) >> 8) < ARRAY_SIZE(ausUartBases)) { |
| 180 | pSettings->usUartBaseIO = ausUartBases[(usSI & 0xFF00) >> 8]; | 181 | pSettings->usUartBaseIO = ausUartBases[(usSI & 0xFF00) >> 8]; |
| 181 | } else { | 182 | } else { |
| 182 | pSettings->usUartBaseIO = 0; | 183 | pSettings->usUartBaseIO = 0; |
| @@ -205,15 +206,16 @@ int smapi_set_DSP_cfg(void) · 22 unmodified lines | |||
| 205 | int bRC = -EIO; | 206 | int bRC = -EIO; |
| 206 | int i; | 207 | int i; |
| 207 | unsigned short usAX, usBX, usCX, usDX, usDI, usSI; | 208 | unsigned short usAX, usBX, usCX, usDX, usDI, usSI; |
| 208 | unsigned short ausDspBases[] = { 0x0030, 0x4E30, 0x8E30, 0xCE30, 0x0130, 0x0350, 0x0070, 0x0DB0 }; | 209 | static const unsigned short ausDspBases[] = { |
| 209 | unsigned short ausUartBases[] = { 0x03F8, 0x02F8, 0x03E8, 0x02E8 }; | 210 | 0x0030, 0x4E30, 0x8E30, 0xCE30, |
| 210 | unsigned short ausDspIrqs[] = { 5, 7, 10, 11, 15 }; | 211 | 0x0130, 0x0350, 0x0070, 0x0DB0 }; |
| 211 | unsigned short ausUartIrqs[] = { 3, 4 }; | 212 | static const unsigned short ausUartBases[] = { |
| 212 | 213 | 0x03F8, 0x02F8, 0x03E8, 0x02E8 }; | |
| 213 | unsigned short numDspBases = 8; | 214 | static const unsigned short ausDspIrqs[] = { |
| 214 | unsigned short numUartBases = 4; | 215 | 5, 7, 10, 11, 15 }; |
| 215 | unsigned short numDspIrqs = 5; | 216 | static const unsigned short ausUartIrqs[] = { |
| 216 | unsigned short numUartIrqs = 2; | 217 | 3, 4 }; |
| 218 | |||
| 217 | unsigned short dspio_index = 0, uartio_index = 0; | 219 | unsigned short dspio_index = 0, uartio_index = 0; |
| 218 | 220 | ||
| 219 | PRINTK_5(TRACE_SMAPI, | 221 | PRINTK_5(TRACE_SMAPI, |
| @@ -221,11 +223,11 @@ int smapi_set_DSP_cfg(void) · 1 unmodified line | |||
| 221 | mwave_3780i_irq, mwave_3780i_io, mwave_uart_irq, mwave_uart_io); | 223 | mwave_3780i_irq, mwave_3780i_io, mwave_uart_irq, mwave_uart_io); |
| 222 | 224 | ||
| 223 | if (mwave_3780i_io) { | 225 | if (mwave_3780i_io) { |
| 224 | for (i = 0; i < numDspBases; i++) { | 226 | for (i = 0; i < ARRAY_SIZE(ausDspBases); i++) { |
| 225 | if (mwave_3780i_io == ausDspBases[i]) | 227 | if (mwave_3780i_io == ausDspBases[i]) |
| 226 | break; | 228 | break; |
| 227 | } | 229 | } |
| 228 | if (i == numDspBases) { | 230 | if (i == ARRAY_SIZE(ausDspBases)) { |
| 229 | PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_set_DSP_cfg: Error: Invalid mwave_3780i_io address %x. Aborting.\n", mwave_3780i_io); | 231 | PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_set_DSP_cfg: Error: Invalid mwave_3780i_io address %x. Aborting.\n", mwave_3780i_io); |
| 230 | return bRC; | 232 | return bRC; |
| 231 | } | 233 | } |
| @@ -233,22 +235,22 @@ int smapi_set_DSP_cfg(void) · 1 unmodified line | |||
| 233 | } | 235 | } |
| 234 | 236 | ||
| 235 | if (mwave_3780i_irq) { | 237 | if (mwave_3780i_irq) { |
| 236 | for (i = 0; i < numDspIrqs; i++) { | 238 | for (i = 0; i < ARRAY_SIZE(ausDspIrqs); i++) { |
| 237 | if (mwave_3780i_irq == ausDspIrqs[i]) | 239 | if (mwave_3780i_irq == ausDspIrqs[i]) |
| 238 | break; | 240 | break; |
| 239 | } | 241 | } |
| 240 | if (i == numDspIrqs) { | 242 | if (i == ARRAY_SIZE(ausDspIrqs)) { |
| 241 | PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_set_DSP_cfg: Error: Invalid mwave_3780i_irq %x. Aborting.\n", mwave_3780i_irq); | 243 | PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_set_DSP_cfg: Error: Invalid mwave_3780i_irq %x. Aborting.\n", mwave_3780i_irq); |
| 242 | return bRC; | 244 | return bRC; |
| 243 | } | 245 | } |
| 244 | } | 246 | } |
| 245 | 247 | ||
| 246 | if (mwave_uart_io) { | 248 | if (mwave_uart_io) { |
| 247 | for (i = 0; i < numUartBases; i++) { | 249 | for (i = 0; i < ARRAY_SIZE(ausUartBases); i++) { |
| 248 | if (mwave_uart_io == ausUartBases[i]) | 250 | if (mwave_uart_io == ausUartBases[i]) |
| 249 | break; | 251 | break; |
| 250 | } | 252 | } |
| 251 | if (i == numUartBases) { | 253 | if (i == ARRAY_SIZE(ausUartBases)) { |
| 252 | PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_set_DSP_cfg: Error: Invalid mwave_uart_io address %x. Aborting.\n", mwave_uart_io); | 254 | PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_set_DSP_cfg: Error: Invalid mwave_uart_io address %x. Aborting.\n", mwave_uart_io); |
| 253 | return bRC; | 255 | return bRC; |
| 254 | } | 256 | } |
| @@ -257,11 +259,11 @@ int smapi_set_DSP_cfg(void) · 2 unmodified lines | |||
| 257 | 259 | ||
| 258 | 260 | ||
| 259 | if (mwave_uart_irq) { | 261 | if (mwave_uart_irq) { |
| 260 | for (i = 0; i < numUartIrqs; i++) { | 262 | for (i = 0; i < ARRAY_SIZE(ausUartIrqs); i++) { |
| 261 | if (mwave_uart_irq == ausUartIrqs[i]) | 263 | if (mwave_uart_irq == ausUartIrqs[i]) |
| 262 | break; | 264 | break; |
| 263 | } | 265 | } |
| 264 | if (i == numUartIrqs) { | 266 | if (i == ARRAY_SIZE(ausUartIrqs)) { |
| 265 | PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_set_DSP_cfg: Error: Invalid mwave_uart_irq %x. Aborting.\n", mwave_uart_irq); | 267 | PRINTK_ERROR(KERN_ERR_MWAVE "smapi::smapi_set_DSP_cfg: Error: Invalid mwave_uart_irq %x. Aborting.\n", mwave_uart_irq); |
| 266 | return bRC; | 268 | return bRC; |
| 267 | } | 269 | } |
| @@ -101,9 +101,6 @@ static DEFINE_IDA(ida_index); · 100 unmodified lines | |||
| 101 | #define PP_BUFFER_SIZE 1024 | 101 | #define PP_BUFFER_SIZE 1024 |
| 102 | #define PARDEVICE_MAX 8 | 102 | #define PARDEVICE_MAX 8 |
| 103 | 103 | ||
| 104 | /* ROUND_UP macro from fs/select.c */ | ||
| 105 | #define ROUND_UP(x,y) (((x)+(y)-1)/(y)) | ||
| 106 | |||
| 107 | static DEFINE_MUTEX(pp_do_mutex); | 104 | static DEFINE_MUTEX(pp_do_mutex); |
| 108 | 105 | ||
| 109 | /* define fixed sized ioctl cmd for y2038 migration */ | 106 | /* define fixed sized ioctl cmd for y2038 migration */ |
| @@ -766,7 +766,7 @@ static struct attribute *tlclk_sysfs_entries[] = { · 765 unmodified lines | |||
| 766 | NULL | 766 | NULL |
| 767 | }; | 767 | }; |
| 768 | 768 | ||
| 769 | static struct attribute_group tlclk_attribute_group = { | 769 | static const struct attribute_group tlclk_attribute_group = { |
| 770 | .name = NULL, /* put in device directory */ | 770 | .name = NULL, /* put in device directory */ |
| 771 | .attrs = tlclk_sysfs_entries, | 771 | .attrs = tlclk_sysfs_entries, |
| 772 | }; | 772 | }; |
| @@ -1308,7 +1308,7 @@ static struct attribute *port_sysfs_entries[] = { · 1307 unmodified lines | |||
| 1308 | NULL | 1308 | NULL |
| 1309 | }; | 1309 | }; |
| 1310 | 1310 | ||
| 1311 | static struct attribute_group port_attribute_group = { | 1311 | static const struct attribute_group port_attribute_group = { |
| 1312 | .name = NULL, /* put in device directory */ | 1312 | .name = NULL, /* put in device directory */ |
| 1313 | .attrs = port_sysfs_entries, | 1313 | .attrs = port_sysfs_entries, |
| 1314 | }; | 1314 | }; |
| @@ -86,8 +86,7 @@ · 85 unmodified lines | |||
| 86 | #include <linux/cdev.h> | 86 | #include <linux/cdev.h> |
| 87 | #include <linux/platform_device.h> | 87 | #include <linux/platform_device.h> |
| 88 | #include <linux/slab.h> | 88 | #include <linux/slab.h> |
| 89 | 89 | #include <linux/io.h> | |
| 90 | #include <asm/io.h> | ||
| 91 | #include <linux/uaccess.h> | 90 | #include <linux/uaccess.h> |
| 92 | 91 | ||
| 93 | #ifdef CONFIG_OF | 92 | #ifdef CONFIG_OF |
| @@ -222,6 +221,8 @@ static const struct config_registers v6_config_registers = { · 128 unmodified lines | |||
| 222 | * hwicap_command_desync - Send a DESYNC command to the ICAP port. | 221 | * hwicap_command_desync - Send a DESYNC command to the ICAP port. |
| 223 | * @drvdata: a pointer to the drvdata. | 222 | * @drvdata: a pointer to the drvdata. |
| 224 | * | 223 | * |
| 224 | * Returns: '0' on success and failure value on error | ||
| 225 | * | ||
| 225 | * This command desynchronizes the ICAP After this command, a | 226 | * This command desynchronizes the ICAP After this command, a |
| 226 | * bitstream containing a NULL packet, followed by a SYNCH packet is | 227 | * bitstream containing a NULL packet, followed by a SYNCH packet is |
| 227 | * required before the ICAP will recognize commands. | 228 | * required before the ICAP will recognize commands. |
| @@ -251,10 +252,12 @@ static int hwicap_command_desync(struct hwicap_drvdata *drvdata) · 23 unmodified lines | |||
| 251 | * hwicap_get_configuration_register - Query a configuration register. | 252 | * hwicap_get_configuration_register - Query a configuration register. |
| 252 | * @drvdata: a pointer to the drvdata. | 253 | * @drvdata: a pointer to the drvdata. |
| 253 | * @reg: a constant which represents the configuration | 254 | * @reg: a constant which represents the configuration |
| 254 | * register value to be returned. | 255 | * register value to be returned. |
| 255 | * Examples: XHI_IDCODE, XHI_FLR. | 256 | * Examples: XHI_IDCODE, XHI_FLR. |
| 256 | * @reg_data: returns the value of the register. | 257 | * @reg_data: returns the value of the register. |
| 257 | * | 258 | * |
| 259 | * Returns: '0' on success and failure value on error | ||
| 260 | * | ||
| 258 | * Sends a query packet to the ICAP and then receives the response. | 261 | * Sends a query packet to the ICAP and then receives the response. |
| 259 | * The icap is left in Synched state. | 262 | * The icap is left in Synched state. |
| 260 | */ | 263 | */ |
| @@ -320,7 +323,8 @@ static int hwicap_initialize_hwicap(struct hwicap_drvdata *drvdata) · 59 unmodified lines | |||
| 320 | dev_dbg(drvdata->dev, "initializing\n"); | 323 | dev_dbg(drvdata->dev, "initializing\n"); |
| 321 | 324 | ||
| 322 | /* Abort any current transaction, to make sure we have the | 325 | /* Abort any current transaction, to make sure we have the |
| 323 | * ICAP in a good state. */ | 326 | * ICAP in a good state. |
| 327 | */ | ||
| 324 | dev_dbg(drvdata->dev, "Reset...\n"); | 328 | dev_dbg(drvdata->dev, "Reset...\n"); |
| 325 | drvdata->config->reset(drvdata); | 329 | drvdata->config->reset(drvdata); |
| 326 | 330 | ||
| @@ -632,7 +636,6 @@ static int hwicap_setup(struct device *dev, int id, · 305 unmodified lines | |||
| 632 | 636 | ||
| 633 | drvdata = kzalloc(sizeof(struct hwicap_drvdata), GFP_KERNEL); | 637 | drvdata = kzalloc(sizeof(struct hwicap_drvdata), GFP_KERNEL); |
| 634 | if (!drvdata) { | 638 | if (!drvdata) { |
| 635 | dev_err(dev, "Couldn't allocate device private record\n"); | ||
| 636 | retval = -ENOMEM; | 639 | retval = -ENOMEM; |
| 637 | goto failed0; | 640 | goto failed0; |
| 638 | } | 641 | } |
| @@ -759,20 +762,20 @@ static int hwicap_of_probe(struct platform_device *op, · 120 unmodified lines | |||
| 759 | id = of_get_property(op->dev.of_node, "port-number", NULL); | 762 | id = of_get_property(op->dev.of_node, "port-number", NULL); |
| 760 | 763 | ||
| 761 | /* It's most likely that we're using V4, if the family is not | 764 | /* It's most likely that we're using V4, if the family is not |
| 762 | specified */ | 765 | * specified |
| 766 | */ | ||
| 763 | regs = &v4_config_registers; | 767 | regs = &v4_config_registers; |
| 764 | family = of_get_property(op->dev.of_node, "xlnx,family", NULL); | 768 | family = of_get_property(op->dev.of_node, "xlnx,family", NULL); |
| 765 | 769 | ||
| 766 | if (family) { | 770 | if (family) { |
| 767 | if (!strcmp(family, "virtex2p")) { | 771 | if (!strcmp(family, "virtex2p")) |
| 768 | regs = &v2_config_registers; | 772 | regs = &v2_config_registers; |
| 769 | } else if (!strcmp(family, "virtex4")) { | 773 | else if (!strcmp(family, "virtex4")) |
| 770 | regs = &v4_config_registers; | 774 | regs = &v4_config_registers; |
| 771 | } else if (!strcmp(family, "virtex5")) { | 775 | else if (!strcmp(family, "virtex5")) |
| 772 | regs = &v5_config_registers; | 776 | regs = &v5_config_registers; |
| 773 | } else if (!strcmp(family, "virtex6")) { | 777 | else if (!strcmp(family, "virtex6")) |
| 774 | regs = &v6_config_registers; | 778 | regs = &v6_config_registers; |
| 775 | } | ||
| 776 | } | 779 | } |
| 777 | return hwicap_setup(&op->dev, id ? *id : -1, &res, config, | 780 | return hwicap_setup(&op->dev, id ? *id : -1, &res, config, |
| 778 | regs); | 781 | regs); |
| @@ -802,20 +805,20 @@ static int hwicap_drv_probe(struct platform_device *pdev) · 23 unmodified lines | |||
| 802 | return -ENODEV; | 805 | return -ENODEV; |
| 803 | 806 | ||
| 804 | /* It's most likely that we're using V4, if the family is not | 807 | /* It's most likely that we're using V4, if the family is not |
| 805 | specified */ | 808 | * specified |
| 809 | */ | ||
| 806 | regs = &v4_config_registers; | 810 | regs = &v4_config_registers; |
| 807 | family = pdev->dev.platform_data; | 811 | family = pdev->dev.platform_data; |
| 808 | 812 | ||
| 809 | if (family) { | 813 | if (family) { |
| 810 | if (!strcmp(family, "virtex2p")) { | 814 | if (!strcmp(family, "virtex2p")) |
| 811 | regs = &v2_config_registers; | 815 | regs = &v2_config_registers; |
| 812 | } else if (!strcmp(family, "virtex4")) { | 816 | else if (!strcmp(family, "virtex4")) |
| 813 | regs = &v4_config_registers; | 817 | regs = &v4_config_registers; |
| 814 | } else if (!strcmp(family, "virtex5")) { | 818 | else if (!strcmp(family, "virtex5")) |
| 815 | regs = &v5_config_registers; | 819 | regs = &v5_config_registers; |
| 816 | } else if (!strcmp(family, "virtex6")) { | 820 | else if (!strcmp(family, "virtex6")) |
| 817 | regs = &v6_config_registers; | 821 | regs = &v6_config_registers; |
| 818 | } | ||
| 819 | } | 822 | } |
| 820 | 823 | ||
| 821 | return hwicap_setup(&pdev->dev, pdev->id, res, | 824 | return hwicap_setup(&pdev->dev, pdev->id, res, |
| @@ -62,11 +62,13 @@ struct hwicap_drvdata { · 61 unmodified lines | |||
| 62 | 62 | ||
| 63 | struct hwicap_driver_config { | 63 | struct hwicap_driver_config { |
| 64 | /* Read configuration data given by size into the data buffer. | 64 | /* Read configuration data given by size into the data buffer. |
| 65 | Return 0 if successful. */ | 65 | * Return 0 if successful. |
| 66 | */ | ||
| 66 | int (*get_configuration)(struct hwicap_drvdata *drvdata, u32 *data, | 67 | int (*get_configuration)(struct hwicap_drvdata *drvdata, u32 *data, |
| 67 | u32 size); | 68 | u32 size); |
| 68 | /* Write configuration data given by size from the data buffer. | 69 | /* Write configuration data given by size from the data buffer. |
| 69 | Return 0 if successful. */ | 70 | * Return 0 if successful. |
| 71 | */ | ||
| 70 | int (*set_configuration)(struct hwicap_drvdata *drvdata, u32 *data, | 72 | int (*set_configuration)(struct hwicap_drvdata *drvdata, u32 *data, |
| 71 | u32 size); | 73 | u32 size); |
| 72 | /* Get the status register, bit pattern given by: | 74 | /* Get the status register, bit pattern given by: |
| @@ -193,11 +195,12 @@ struct config_registers { · 120 unmodified lines | |||
| 193 | * hwicap_type_1_read - Generates a Type 1 read packet header. | 195 | * hwicap_type_1_read - Generates a Type 1 read packet header. |
| 194 | * @reg: is the address of the register to be read back. | 196 | * @reg: is the address of the register to be read back. |
| 195 | * | 197 | * |
| 198 | * Return: | ||
| 196 | * Generates a Type 1 read packet header, which is used to indirectly | 199 | * Generates a Type 1 read packet header, which is used to indirectly |
| 197 | * read registers in the configuration logic. This packet must then | 200 | * read registers in the configuration logic. This packet must then |
| 198 | * be sent through the icap device, and a return packet received with | 201 | * be sent through the icap device, and a return packet received with |
| 199 | * the information. | 202 | * the information. |
| 200 | **/ | 203 | */ |
| 201 | static inline u32 hwicap_type_1_read(u32 reg) | 204 | static inline u32 hwicap_type_1_read(u32 reg) |
| 202 | { | 205 | { |
| 203 | return (XHI_TYPE_1 << XHI_TYPE_SHIFT) | | 206 | return (XHI_TYPE_1 << XHI_TYPE_SHIFT) | |
| @@ -208,7 +211,9 @@ static inline u32 hwicap_type_1_read(u32 reg) · 4 unmodified lines | |||
| 208 | /** | 211 | /** |
| 209 | * hwicap_type_1_write - Generates a Type 1 write packet header | 212 | * hwicap_type_1_write - Generates a Type 1 write packet header |
| 210 | * @reg: is the address of the register to be read back. | 213 | * @reg: is the address of the register to be read back. |
| 211 | **/ | 214 | * |
| 215 | * Return: Type 1 write packet header | ||
| 216 | */ | ||
| 212 | static inline u32 hwicap_type_1_write(u32 reg) | 217 | static inline u32 hwicap_type_1_write(u32 reg) |
| 213 | { | 218 | { |
| 214 | return (XHI_TYPE_1 << XHI_TYPE_SHIFT) | | 219 | return (XHI_TYPE_1 << XHI_TYPE_SHIFT) | |
| @@ -150,4 +150,11 @@ config EXTCON_USB_GPIO · 149 unmodified lines | |||
| 150 | Say Y here to enable GPIO based USB cable detection extcon support. | 150 | Say Y here to enable GPIO based USB cable detection extcon support. |
| 151 | Used typically if GPIO is used for USB ID pin detection. | 151 | Used typically if GPIO is used for USB ID pin detection. |
| 152 | 152 | ||
| 153 | config EXTCON_USBC_CROS_EC | ||
| 154 | tristate "ChromeOS Embedded Controller EXTCON support" | ||
| 155 | depends on MFD_CROS_EC | ||
| 156 | help | ||
| 157 | Say Y here to enable USB Type C cable detection extcon support when | ||
| 158 | using Chrome OS EC based USB Type-C ports. | ||
| 159 | |||
| 153 | endif | 160 | endif |
| @@ -20,3 +20,4 @@ obj-$(CONFIG_EXTCON_QCOM_SPMI_MISC) += extcon-qcom-spmi-misc.o · 19 unmodified lines | |||
| 20 | obj-$(CONFIG_EXTCON_RT8973A) += extcon-rt8973a.o | 20 | obj-$(CONFIG_EXTCON_RT8973A) += extcon-rt8973a.o |
| 21 | obj-$(CONFIG_EXTCON_SM5502) += extcon-sm5502.o | 21 | obj-$(CONFIG_EXTCON_SM5502) += extcon-sm5502.o |
| 22 | obj-$(CONFIG_EXTCON_USB_GPIO) += extcon-usb-gpio.o | 22 | obj-$(CONFIG_EXTCON_USB_GPIO) += extcon-usb-gpio.o |
| 23 | obj-$(CONFIG_EXTCON_USBC_CROS_EC) += extcon-usbc-cros-ec.o | ||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * drivers/extcon/devres.c - EXTCON device's resource management | 2 | * drivers/extcon/devres.c - EXTCON device's resource management |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2016 Samsung Electronics | 4 | * Copyright (C) 2016 Samsung Electronics |
| 5 | * Author: Chanwoo Choi <cw00.choi@samsung.com> | 5 | * Author: Chanwoo Choi <cw00.choi@samsung.com> |
| @@ -59,10 +59,9 @@ static void devm_extcon_dev_notifier_all_unreg(struct device *dev, void *res) · 53 unmodified lines | |||
| 59 | 59 | ||
| 60 | /** | 60 | /** |
| 61 | * devm_extcon_dev_allocate - Allocate managed extcon device | 61 | * devm_extcon_dev_allocate - Allocate managed extcon device |
| 62 | * @dev: device owning the extcon device being created | 62 | * @dev: the device owning the extcon device being created |
| 63 | * @supported_cable: Array of supported extcon ending with EXTCON_NONE. | 63 | * @supported_cable: the array of the supported external connectors |
| 64 | * If supported_cable is NULL, cable name related APIs | 64 | * ending with EXTCON_NONE. |
| 65 | * are disabled. | ||
| 66 | * | 65 | * |
| 67 | * This function manages automatically the memory of extcon device using device | 66 | * This function manages automatically the memory of extcon device using device |
| 68 | * resource management and simplify the control of freeing the memory of extcon | 67 | * resource management and simplify the control of freeing the memory of extcon |
| @@ -97,8 +96,8 @@ EXPORT_SYMBOL_GPL(devm_extcon_dev_allocate); · 28 unmodified lines | |||
| 97 | 96 | ||
| 98 | /** | 97 | /** |
| 99 | * devm_extcon_dev_free() - Resource-managed extcon_dev_unregister() | 98 | * devm_extcon_dev_free() - Resource-managed extcon_dev_unregister() |
| 100 | * @dev: device the extcon belongs to | 99 | * @dev: the device owning the extcon device being created |
| 101 | * @edev: the extcon device to unregister | 100 | * @edev: the extcon device to be freed |
| 102 | * | 101 | * |
| 103 | * Free the memory that is allocated with devm_extcon_dev_allocate() | 102 | * Free the memory that is allocated with devm_extcon_dev_allocate() |
| 104 | * function. | 103 | * function. |
| @@ -112,10 +111,9 @@ EXPORT_SYMBOL_GPL(devm_extcon_dev_free); · 7 unmodified lines | |||
| 112 | 111 | ||
| 113 | /** | 112 | /** |
| 114 | * devm_extcon_dev_register() - Resource-managed extcon_dev_register() | 113 | * devm_extcon_dev_register() - Resource-managed extcon_dev_register() |
| 115 | * @dev: device to allocate extcon device | 114 | * @dev: the device owning the extcon device being created |
| 116 | * @edev: the new extcon device to register | 115 | * @edev: the extcon device to be registered |
| 117 | * | 116 | * |
| 118 | * Managed extcon_dev_register() function. If extcon device is attached with | ||
| 119 | * this function, that extcon device is automatically unregistered on driver | 117 | * this function, that extcon device is automatically unregistered on driver |
| 120 | * detach. Internally this function calls extcon_dev_register() function. | 118 | * detach. Internally this function calls extcon_dev_register() function. |
| 121 | * To get more information, refer that function. | 119 | * To get more information, refer that function. |
| @@ -149,8 +147,8 @@ EXPORT_SYMBOL_GPL(devm_extcon_dev_register); · 27 unmodified lines | |||
| 149 | 147 | ||
| 150 | /** | 148 | /** |
| 151 | * devm_extcon_dev_unregister() - Resource-managed extcon_dev_unregister() | 149 | * devm_extcon_dev_unregister() - Resource-managed extcon_dev_unregister() |
| 152 | * @dev: device the extcon belongs to | 150 | * @dev: the device owning the extcon device being created |
| 153 | * @edev: the extcon device to unregister | 151 | * @edev: the extcon device to unregistered |
| 154 | * | 152 | * |
| 155 | * Unregister extcon device that is registered with devm_extcon_dev_register() | 153 | * Unregister extcon device that is registered with devm_extcon_dev_register() |
| 156 | * function. | 154 | * function. |
| @@ -164,10 +162,10 @@ EXPORT_SYMBOL_GPL(devm_extcon_dev_unregister); · 7 unmodified lines | |||
| 164 | 162 | ||
| 165 | /** | 163 | /** |
| 166 | * devm_extcon_register_notifier() - Resource-managed extcon_register_notifier() | 164 | * devm_extcon_register_notifier() - Resource-managed extcon_register_notifier() |
| 167 | * @dev: device to allocate extcon device | 165 | * @dev: the device owning the extcon device being created |
| 168 | * @edev: the extcon device that has the external connecotr. | 166 | * @edev: the extcon device |
| 169 | * @id: the unique id of each external connector in extcon enumeration. | 167 | * @id: the unique id among the extcon enumeration |
| 170 | * @nb: a notifier block to be registered. | 168 | * @nb: a notifier block to be registered |
| 171 | * | 169 | * |
| 172 | * This function manages automatically the notifier of extcon device using | 170 | * This function manages automatically the notifier of extcon device using |
| 173 | * device resource management and simplify the control of unregistering | 171 | * device resource management and simplify the control of unregistering |
| @@ -208,10 +206,10 @@ EXPORT_SYMBOL(devm_extcon_register_notifier); · 34 unmodified lines | |||
| 208 | /** | 206 | /** |
| 209 | * devm_extcon_unregister_notifier() | 207 | * devm_extcon_unregister_notifier() |
| 210 | - Resource-managed extcon_unregister_notifier() | 208 | - Resource-managed extcon_unregister_notifier() |
| 211 | * @dev: device to allocate extcon device | 209 | * @dev: the device owning the extcon device being created |
| 212 | * @edev: the extcon device that has the external connecotr. | 210 | * @edev: the extcon device |
| 213 | * @id: the unique id of each external connector in extcon enumeration. | 211 | * @id: the unique id among the extcon enumeration |
| 214 | * @nb: a notifier block to be registered. | 212 | * @nb: a notifier block to be registered |
| 215 | */ | 213 | */ |
| 216 | void devm_extcon_unregister_notifier(struct device *dev, | 214 | void devm_extcon_unregister_notifier(struct device *dev, |
| 217 | struct extcon_dev *edev, unsigned int id, | 215 | struct extcon_dev *edev, unsigned int id, |
| @@ -225,9 +223,9 @@ EXPORT_SYMBOL(devm_extcon_unregister_notifier); · 7 unmodified lines | |||
| 225 | /** | 223 | /** |
| 226 | * devm_extcon_register_notifier_all() | 224 | * devm_extcon_register_notifier_all() |
| 227 | * - Resource-managed extcon_register_notifier_all() | 225 | * - Resource-managed extcon_register_notifier_all() |
| 228 | * @dev: device to allocate extcon device | 226 | * @dev: the device owning the extcon device being created |
| 229 | * @edev: the extcon device that has the external connecotr. | 227 | * @edev: the extcon device |
| 230 | * @nb: a notifier block to be registered. | 228 | * @nb: a notifier block to be registered |
| 231 | * | 229 | * |
| 232 | * This function manages automatically the notifier of extcon device using | 230 | * This function manages automatically the notifier of extcon device using |
| 233 | * device resource management and simplify the control of unregistering | 231 | * device resource management and simplify the control of unregistering |
| @@ -263,9 +261,9 @@ EXPORT_SYMBOL(devm_extcon_register_notifier_all); · 29 unmodified lines | |||
| 263 | /** | 261 | /** |
| 264 | * devm_extcon_unregister_notifier_all() | 262 | * devm_extcon_unregister_notifier_all() |
| 265 | * - Resource-managed extcon_unregister_notifier_all() | 263 | * - Resource-managed extcon_unregister_notifier_all() |
| 266 | * @dev: device to allocate extcon device | 264 | * @dev: the device owning the extcon device being created |
| 267 | * @edev: the extcon device that has the external connecotr. | 265 | * @edev: the extcon device |
| 268 | * @nb: a notifier block to be registered. | 266 | * @nb: a notifier block to be registered |
| 269 | */ | 267 | */ |
| 270 | void devm_extcon_unregister_notifier_all(struct device *dev, | 268 | void devm_extcon_unregister_notifier_all(struct device *dev, |
| 271 | struct extcon_dev *edev, | 269 | struct extcon_dev *edev, |
| @@ -171,7 +171,7 @@ static int int3496_remove(struct platform_device *pdev) · 170 unmodified lines | |||
| 171 | return 0; | 171 | return 0; |
| 172 | } | 172 | } |
| 173 | 173 | ||
| 174 | static struct acpi_device_id int3496_acpi_match[] = { | 174 | static const struct acpi_device_id int3496_acpi_match[] = { |
| 175 | { "INT3496" }, | 175 | { "INT3496" }, |
| 176 | { } | 176 | { } |
| 177 | }; | 177 | }; |
| @@ -811,9 +811,8 @@ static int max77693_muic_chg_handler(struct max77693_muic_info *info) · 810 unmodified lines | |||
| 811 | */ | 811 | */ |
| 812 | extcon_set_state_sync(info->edev, EXTCON_CHG_USB_DCP, | 812 | extcon_set_state_sync(info->edev, EXTCON_CHG_USB_DCP, |
| 813 | attached); | 813 | attached); |
| 814 | if (!cable_attached) | 814 | extcon_set_state_sync(info->edev, EXTCON_DISP_MHL, |
| 815 | extcon_set_state_sync(info->edev, | 815 | cable_attached); |
| 816 | EXTCON_DISP_MHL, cable_attached); | ||
| 817 | break; | 816 | break; |
| 818 | } | 817 | } |
| 819 | 818 | ||
| @@ -0,0 +1,417 @@ | |||
| 1 | /** | ||
| 2 | * drivers/extcon/extcon-usbc-cros-ec - ChromeOS Embedded Controller extcon | ||
| 3 | * | ||
| 4 | * Copyright (C) 2017 Google, Inc | ||
| 5 | * Author: Benson Leung <bleung@chromium.org> | ||
| 6 | * | ||
| 7 | * This software is licensed under the terms of the GNU General Public | ||
| 8 | * License version 2, as published by the Free Software Foundation, and | ||
| 9 | * may be copied, distributed, and modified under those terms. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/extcon.h> | ||
| 18 | #include <linux/kernel.h> | ||
| 19 | #include <linux/mfd/cros_ec.h> | ||
| 20 | #include <linux/module.h> | ||
| 21 | #include <linux/notifier.h> | ||
| 22 | #include <linux/of.h> | ||
| 23 | #include <linux/platform_device.h> | ||
| 24 | #include <linux/slab.h> | ||
| 25 | #include <linux/sched.h> | ||
| 26 | |||
| 27 | struct cros_ec_extcon_info { | ||
| 28 | struct device *dev; | ||
| 29 | struct extcon_dev *edev; | ||
| 30 | |||
| 31 | int port_id; | ||
| 32 | |||
| 33 | struct cros_ec_device *ec; | ||
| 34 | |||
| 35 | struct notifier_block notifier; | ||
| 36 | |||
| 37 | bool dp; /* DisplayPort enabled */ | ||
| 38 | bool mux; /* SuperSpeed (usb3) enabled */ | ||
| 39 | unsigned int power_type; | ||
| 40 | }; | ||
| 41 | |||
| 42 | static const unsigned int usb_type_c_cable[] = { | ||
| 43 | EXTCON_DISP_DP, | ||
| 44 | EXTCON_NONE, | ||
| 45 | }; | ||
| 46 | |||
| 47 | /** | ||
| 48 | * cros_ec_pd_command() - Send a command to the EC. | ||
| 49 | * @info: pointer to struct cros_ec_extcon_info | ||
| 50 | * @command: EC command | ||
| 51 | * @version: EC command version | ||
| 52 | * @outdata: EC command output data | ||
| 53 | * @outsize: Size of outdata | ||
| 54 | * @indata: EC command input data | ||
| 55 | * @insize: Size of indata | ||
| 56 | * | ||
| 57 | * Return: 0 on success, <0 on failure. | ||
| 58 | */ | ||
| 59 | static int cros_ec_pd_command(struct cros_ec_extcon_info *info, | ||
| 60 | unsigned int command, | ||
| 61 | unsigned int version, | ||
| 62 | void *outdata, | ||
| 63 | unsigned int outsize, | ||
| 64 | void *indata, | ||
| 65 | unsigned int insize) | ||
| 66 | { | ||
| 67 | struct cros_ec_command *msg; | ||
| 68 | int ret; | ||
| 69 | |||
| 70 | msg = kzalloc(sizeof(*msg) + max(outsize, insize), GFP_KERNEL); | ||
| 71 | if (!msg) | ||
| 72 | return -ENOMEM; | ||
| 73 | |||
| 74 | msg->version = version; | ||
| 75 | msg->command = command; | ||
| 76 | msg->outsize = outsize; | ||
| 77 | msg->insize = insize; | ||
| 78 | |||
| 79 | if (outsize) | ||
| 80 | memcpy(msg->data, outdata, outsize); | ||
| 81 | |||
| 82 | ret = cros_ec_cmd_xfer_status(info->ec, msg); | ||
| 83 | if (ret >= 0 && insize) | ||
| 84 | memcpy(indata, msg->data, insize); | ||
| 85 | |||
| 86 | kfree(msg); | ||
| 87 | return ret; | ||
| 88 | } | ||
| 89 | |||
| 90 | /** | ||
| 91 | * cros_ec_usb_get_power_type() - Get power type info about PD device attached | ||
| 92 | * to given port. | ||
| 93 | * @info: pointer to struct cros_ec_extcon_info | ||
| 94 | * | ||
| 95 | * Return: power type on success, <0 on failure. | ||
| 96 | */ | ||
| 97 | static int cros_ec_usb_get_power_type(struct cros_ec_extcon_info *info) | ||
| 98 | { | ||
| 99 | struct ec_params_usb_pd_power_info req; | ||
| 100 | struct ec_response_usb_pd_power_info resp; | ||
| 101 | int ret; | ||
| 102 | |||
| 103 | req.port = info->port_id; | ||
| 104 | ret = cros_ec_pd_command(info, EC_CMD_USB_PD_POWER_INFO, 0, | ||
| 105 | &req, sizeof(req), &resp, sizeof(resp)); | ||
| 106 | if (ret < 0) | ||
| 107 | return ret; | ||
| 108 | |||
| 109 | return resp.type; | ||
| 110 | } | ||
| 111 | |||
| 112 | /** | ||
| 113 | * cros_ec_usb_get_pd_mux_state() - Get PD mux state for given port. | ||
| 114 | * @info: pointer to struct cros_ec_extcon_info | ||
| 115 | * | ||
| 116 | * Return: PD mux state on success, <0 on failure. | ||
| 117 | */ | ||
| 118 | static int cros_ec_usb_get_pd_mux_state(struct cros_ec_extcon_info *info) | ||
| 119 | { | ||
| 120 | struct ec_params_usb_pd_mux_info req; | ||
| 121 | struct ec_response_usb_pd_mux_info resp; | ||
| 122 | int ret; | ||
| 123 | |||
| 124 | req.port = info->port_id; | ||
| 125 | ret = cros_ec_pd_command(info, EC_CMD_USB_PD_MUX_INFO, 0, | ||
| 126 | &req, sizeof(req), | ||
| 127 | &resp, sizeof(resp)); | ||
| 128 | if (ret < 0) | ||
| 129 | return ret; | ||
| 130 | |||
| 131 | return resp.flags; | ||
| 132 | } | ||
| 133 | |||
| 134 | /** | ||
| 135 | * cros_ec_usb_get_role() - Get role info about possible PD device attached to a | ||
| 136 | * given port. | ||
| 137 | * @info: pointer to struct cros_ec_extcon_info | ||
| 138 | * @polarity: pointer to cable polarity (return value) | ||
| 139 | * | ||
| 140 | * Return: role info on success, -ENOTCONN if no cable is connected, <0 on | ||
| 141 | * failure. | ||
| 142 | */ | ||
| 143 | static int cros_ec_usb_get_role(struct cros_ec_extcon_info *info, | ||
| 144 | bool *polarity) | ||
| 145 | { | ||
| 146 | struct ec_params_usb_pd_control pd_control; | ||
| 147 | struct ec_response_usb_pd_control_v1 resp; | ||
| 148 | int ret; | ||
| 149 | |||
| 150 | pd_control.port = info->port_id; | ||
| 151 | pd_control.role = USB_PD_CTRL_ROLE_NO_CHANGE; | ||
| 152 | pd_control.mux = USB_PD_CTRL_MUX_NO_CHANGE; | ||
| 153 | ret = cros_ec_pd_command(info, EC_CMD_USB_PD_CONTROL, 1, | ||
| 154 | &pd_control, sizeof(pd_control), | ||
| 155 | &resp, sizeof(resp)); | ||
| 156 | if (ret < 0) | ||
| 157 | return ret; | ||
| 158 | |||
| 159 | if (!(resp.enabled & PD_CTRL_RESP_ENABLED_CONNECTED)) | ||
| 160 | return -ENOTCONN; | ||
| 161 | |||
| 162 | *polarity = resp.polarity; | ||
| 163 | |||
| 164 | return resp.role; | ||
| 165 | } | ||
| 166 | |||
| 167 | /** | ||
| 168 | * cros_ec_pd_get_num_ports() - Get number of EC charge ports. | ||
| 169 | * @info: pointer to struct cros_ec_extcon_info | ||
| 170 | * | ||
| 171 | * Return: number of ports on success, <0 on failure. | ||
| 172 | */ | ||
| 173 | static int cros_ec_pd_get_num_ports(struct cros_ec_extcon_info *info) | ||
| 174 | { | ||
| 175 | struct ec_response_usb_pd_ports resp; | ||
| 176 | int ret; | ||
| 177 | |||
| 178 | ret = cros_ec_pd_command(info, EC_CMD_USB_PD_PORTS, | ||
| 179 | 0, NULL, 0, &resp, sizeof(resp)); | ||
| 180 | if (ret < 0) | ||
| 181 | return ret; | ||
| 182 | |||
| 183 | return resp.num_ports; | ||
| 184 | } | ||
| 185 | |||
| 186 | static int extcon_cros_ec_detect_cable(struct cros_ec_extcon_info *info, | ||
| 187 | bool force) | ||
| 188 | { | ||
| 189 | struct device *dev = info->dev; | ||
| 190 | int role, power_type; | ||
| 191 | bool polarity = false; | ||
| 192 | bool dp = false; | ||
| 193 | bool mux = false; | ||
| 194 | bool hpd = false; | ||
| 195 | |||
| 196 | power_type = cros_ec_usb_get_power_type(info); | ||
| 197 | if (power_type < 0) { | ||
| 198 | dev_err(dev, "failed getting power type err = %d\n", | ||
| 199 | power_type); | ||
| 200 | return power_type; | ||
| 201 | } | ||
| 202 | |||
| 203 | role = cros_ec_usb_get_role(info, &polarity); | ||
| 204 | if (role < 0) { | ||
| 205 | if (role != -ENOTCONN) { | ||
| 206 | dev_err(dev, "failed getting role err = %d\n", role); | ||
| 207 | return role; | ||
| 208 | } | ||
| 209 | } else { | ||
| 210 | int pd_mux_state; | ||
| 211 | |||
| 212 | pd_mux_state = cros_ec_usb_get_pd_mux_state(info); | ||
| 213 | if (pd_mux_state < 0) | ||
| 214 | pd_mux_state = USB_PD_MUX_USB_ENABLED; | ||
| 215 | |||
| 216 | dp = pd_mux_state & USB_PD_MUX_DP_ENABLED; | ||
| 217 | mux = pd_mux_state & USB_PD_MUX_USB_ENABLED; | ||
| 218 | hpd = pd_mux_state & USB_PD_MUX_HPD_IRQ; | ||
| 219 | } | ||
| 220 | |||
| 221 | if (force || info->dp != dp || info->mux != mux || | ||
| 222 | info->power_type != power_type) { | ||
| 223 | |||
| 224 | info->dp = dp; | ||
| 225 | info->mux = mux; | ||
| 226 | info->power_type = power_type; | ||
| 227 | |||
| 228 | extcon_set_state(info->edev, EXTCON_DISP_DP, dp); | ||
| 229 | |||
| 230 | extcon_set_property(info->edev, EXTCON_DISP_DP, | ||
| 231 | EXTCON_PROP_USB_TYPEC_POLARITY, | ||
| 232 | (union extcon_property_value)(int)polarity); | ||
| 233 | extcon_set_property(info->edev, EXTCON_DISP_DP, | ||
| 234 | EXTCON_PROP_USB_SS, | ||
| 235 | (union extcon_property_value)(int)mux); | ||
| 236 | extcon_set_property(info->edev, EXTCON_DISP_DP, | ||
| 237 | EXTCON_PROP_DISP_HPD, | ||
| 238 | (union extcon_property_value)(int)hpd); | ||
| 239 | |||
| 240 | extcon_sync(info->edev, EXTCON_DISP_DP); | ||
| 241 | |||
| 242 | } else if (hpd) { | ||
| 243 | extcon_set_property(info->edev, EXTCON_DISP_DP, | ||
| 244 | EXTCON_PROP_DISP_HPD, | ||
| 245 | (union extcon_property_value)(int)hpd); | ||
| 246 | extcon_sync(info->edev, EXTCON_DISP_DP); | ||
| 247 | } | ||
| 248 | |||
| 249 | return 0; | ||
| 250 | } | ||
| 251 | |||
| 252 | static int extcon_cros_ec_event(struct notifier_block *nb, | ||
| 253 | unsigned long queued_during_suspend, | ||
| 254 | void *_notify) | ||
| 255 | { | ||
| 256 | struct cros_ec_extcon_info *info; | ||
| 257 | struct cros_ec_device *ec; | ||
| 258 | u32 host_event; | ||
| 259 | |||
| 260 | info = container_of(nb, struct cros_ec_extcon_info, notifier); | ||
| 261 | ec = info->ec; | ||
| 262 | |||
| 263 | host_event = cros_ec_get_host_event(ec); | ||
| 264 | if (host_event & (EC_HOST_EVENT_MASK(EC_HOST_EVENT_PD_MCU) | | ||
| 265 | EC_HOST_EVENT_MASK(EC_HOST_EVENT_USB_MUX))) { | ||
| 266 | extcon_cros_ec_detect_cable(info, false); | ||
| 267 | return NOTIFY_OK; | ||
| 268 | } | ||
| 269 | |||
| 270 | return NOTIFY_DONE; | ||
| 271 | } | ||
| 272 | |||
| 273 | static int extcon_cros_ec_probe(struct platform_device *pdev) | ||
| 274 | { | ||
| 275 | struct cros_ec_extcon_info *info; | ||
| 276 | struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent); | ||
| 277 | struct device *dev = &pdev->dev; | ||
| 278 | struct device_node *np = dev->of_node; | ||
| 279 | int numports, ret; | ||
| 280 | |||
| 281 | info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); | ||
| 282 | if (!info) | ||
| 283 | return -ENOMEM; | ||
| 284 | |||
| 285 | info->dev = dev; | ||
| 286 | info->ec = ec; | ||
| 287 | |||
| 288 | if (np) { | ||
| 289 | u32 port; | ||
| 290 | |||
| 291 | ret = of_property_read_u32(np, "google,usb-port-id", &port); | ||
| 292 | if (ret < 0) { | ||
| 293 | dev_err(dev, "Missing google,usb-port-id property\n"); | ||
| 294 | return ret; | ||
| 295 | } | ||
| 296 | info->port_id = port; | ||
| 297 | } else { | ||
| 298 | info->port_id = pdev->id; | ||
| 299 | } | ||
| 300 | |||
| 301 | numports = cros_ec_pd_get_num_ports(info); | ||
| 302 | if (numports < 0) { | ||
| 303 | dev_err(dev, "failed getting number of ports! ret = %d\n", | ||
| 304 | numports); | ||
| 305 | return numports; | ||
| 306 | } | ||
| 307 | |||
| 308 | if (info->port_id >= numports) { | ||
| 309 | dev_err(dev, "This system only supports %d ports\n", numports); | ||
| 310 | return -ENODEV; | ||
| 311 | } | ||
| 312 | |||
| 313 | info->edev = devm_extcon_dev_allocate(dev, usb_type_c_cable); | ||
| 314 | if (IS_ERR(info->edev)) { | ||
| 315 | dev_err(dev, "failed to allocate extcon device\n"); | ||
| 316 | return -ENOMEM; | ||
| 317 | } | ||
| 318 | |||
| 319 | ret = devm_extcon_dev_register(dev, info->edev); | ||
| 320 | if (ret < 0) { | ||
| 321 | dev_err(dev, "failed to register extcon device\n"); | ||
| 322 | return ret; | ||
| 323 | } | ||
| 324 | |||
| 325 | extcon_set_property_capability(info->edev, EXTCON_DISP_DP, | ||
| 326 | EXTCON_PROP_USB_TYPEC_POLARITY); | ||
| 327 | extcon_set_property_capability(info->edev, EXTCON_DISP_DP, | ||
| 328 | EXTCON_PROP_USB_SS); | ||
| 329 | extcon_set_property_capability(info->edev, EXTCON_DISP_DP, | ||
| 330 | EXTCON_PROP_DISP_HPD); | ||
| 331 | |||
| 332 | platform_set_drvdata(pdev, info); | ||
| 333 | |||
| 334 | /* Get PD events from the EC */ | ||
| 335 | info->notifier.notifier_call = extcon_cros_ec_event; | ||
| 336 | ret = blocking_notifier_chain_register(&info->ec->event_notifier, | ||
| 337 | &info->notifier); | ||
| 338 | if (ret < 0) { | ||
| 339 | dev_err(dev, "failed to register notifier\n"); | ||
| 340 | return ret; | ||
| 341 | } | ||
| 342 | |||
| 343 | /* Perform initial detection */ | ||
| 344 | ret = extcon_cros_ec_detect_cable(info, true); | ||
| 345 | if (ret < 0) { | ||
| 346 | dev_err(dev, "failed to detect initial cable state\n"); | ||
| 347 | goto unregister_notifier; | ||
| 348 | } | ||
| 349 | |||
| 350 | return 0; | ||
| 351 | |||
| 352 | unregister_notifier: | ||
| 353 | blocking_notifier_chain_unregister(&info->ec->event_notifier, | ||
| 354 | &info->notifier); | ||
| 355 | return ret; | ||
| 356 | } | ||
| 357 | |||
| 358 | static int extcon_cros_ec_remove(struct platform_device *pdev) | ||
| 359 | { | ||
| 360 | struct cros_ec_extcon_info *info = platform_get_drvdata(pdev); | ||
| 361 | |||
| 362 | blocking_notifier_chain_unregister(&info->ec->event_notifier, | ||
| 363 | &info->notifier); | ||
| 364 | |||
| 365 | return 0; | ||
| 366 | } | ||
| 367 | |||
| 368 | #ifdef CONFIG_PM_SLEEP | ||
| 369 | static int extcon_cros_ec_suspend(struct device *dev) | ||
| 370 | { | ||
| 371 | return 0; | ||
| 372 | } | ||
| 373 | |||
| 374 | static int extcon_cros_ec_resume(struct device *dev) | ||
| 375 | { | ||
| 376 | int ret; | ||
| 377 | struct cros_ec_extcon_info *info = dev_get_drvdata(dev); | ||
| 378 | |||
| 379 | ret = extcon_cros_ec_detect_cable(info, true); | ||
| 380 | if (ret < 0) | ||
| 381 | dev_err(dev, "failed to detect cable state on resume\n"); | ||
| 382 | |||
| 383 | return 0; | ||
| 384 | } | ||
| 385 | |||
| 386 | static const struct dev_pm_ops extcon_cros_ec_dev_pm_ops = { | ||
| 387 | SET_SYSTEM_SLEEP_PM_OPS(extcon_cros_ec_suspend, extcon_cros_ec_resume) | ||
| 388 | }; | ||
| 389 | |||
| 390 | #define DEV_PM_OPS (&extcon_cros_ec_dev_pm_ops) | ||
| 391 | #else | ||
| 392 | #define DEV_PM_OPS NULL | ||
| 393 | #endif /* CONFIG_PM_SLEEP */ | ||
| 394 | |||
| 395 | #ifdef CONFIG_OF | ||
| 396 | static const struct of_device_id extcon_cros_ec_of_match[] = { | ||
| 397 | { .compatible = "google,extcon-usbc-cros-ec" }, | ||
| 398 | { /* sentinel */ } | ||
| 399 | }; | ||
| 400 | MODULE_DEVICE_TABLE(of, extcon_cros_ec_of_match); | ||
| 401 | #endif /* CONFIG_OF */ | ||
| 402 | |||
| 403 | static struct platform_driver extcon_cros_ec_driver = { | ||
| 404 | .driver = { | ||
| 405 | .name = "extcon-usbc-cros-ec", | ||
| 406 | .of_match_table = of_match_ptr(extcon_cros_ec_of_match), | ||
| 407 | .pm = DEV_PM_OPS, | ||
| 408 | }, | ||
| 409 | .remove = extcon_cros_ec_remove, | ||
| 410 | .probe = extcon_cros_ec_probe, | ||
| 411 | }; | ||
| 412 | |||
| 413 | module_platform_driver(extcon_cros_ec_driver); | ||
| 414 | |||
| 415 | MODULE_DESCRIPTION("ChromeOS Embedded Controller extcon driver"); | ||
| 416 | MODULE_AUTHOR("Benson Leung <bleung@chromium.org>"); | ||
| 417 | MODULE_LICENSE("GPL"); | ||
| @@ -1,7 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * drivers/extcon/extcon.c - External Connector (extcon) framework. | 2 | * drivers/extcon/extcon.c - External Connector (extcon) framework. |
| 3 | * | ||
| 4 | * External connector (extcon) class driver | ||
| 5 | * | 3 | * |
| 6 | * Copyright (C) 2015 Samsung Electronics | 4 | * Copyright (C) 2015 Samsung Electronics |
| 7 | * Author: Chanwoo Choi <cw00.choi@samsung.com> | 5 | * Author: Chanwoo Choi <cw00.choi@samsung.com> |
| @@ -37,7 +35,6 @@ · 29 unmodified lines | |||
| 37 | #include "extcon.h" | 35 | #include "extcon.h" |
| 38 | 36 | ||
| 39 | #define SUPPORTED_CABLE_MAX 32 | 37 | #define SUPPORTED_CABLE_MAX 32 |
| 40 | #define CABLE_NAME_MAX 30 | ||
| 41 | 38 | ||
| 42 | struct __extcon_info { | 39 | struct __extcon_info { |
| 43 | unsigned int type; | 40 | unsigned int type; |
| @@ -200,13 +197,13 @@ struct __extcon_info { · 156 unmodified lines | |||
| 200 | }; | 197 | }; |
| 201 | 198 | ||
| 202 | /** | 199 | /** |
| 203 | * struct extcon_cable - An internal data for each cable of extcon device. | 200 | * struct extcon_cable - An internal data for an external connector. |
| 204 | * @edev: The extcon device | 201 | * @edev: the extcon device |
| 205 | * @cable_index: Index of this cable in the edev | 202 | * @cable_index: the index of this cable in the edev |
| 206 | * @attr_g: Attribute group for the cable | 203 | * @attr_g: the attribute group for the cable |
| 207 | * @attr_name: "name" sysfs entry | 204 | * @attr_name: "name" sysfs entry |
| 208 | * @attr_state: "state" sysfs entry | 205 | * @attr_state: "state" sysfs entry |
| 209 | * @attrs: Array pointing to attr_name and attr_state for attr_g | 206 | * @attrs: the array pointing to attr_name and attr_state for attr_g |
| 210 | */ | 207 | */ |
| 211 | struct extcon_cable { | 208 | struct extcon_cable { |
| 212 | struct extcon_dev *edev; | 209 | struct extcon_dev *edev; |
| @@ -234,15 +231,6 @@ static struct class *extcon_class; · 21 unmodified lines | |||
| 234 | static LIST_HEAD(extcon_dev_list); | 231 | static LIST_HEAD(extcon_dev_list); |
| 235 | static DEFINE_MUTEX(extcon_dev_list_lock); | 232 | static DEFINE_MUTEX(extcon_dev_list_lock); |
| 236 | 233 | ||
| 237 | /** | ||
| 238 | * check_mutually_exclusive - Check if new_state violates mutually_exclusive | ||
| 239 | * condition. | ||
| 240 | * @edev: the extcon device | ||
| 241 | * @new_state: new cable attach status for @edev | ||
| 242 | * | ||
| 243 | * Returns 0 if nothing violates. Returns the index + 1 for the first | ||
| 244 | * violated condition. | ||
| 245 | */ | ||
| 246 | static int check_mutually_exclusive(struct extcon_dev *edev, u32 new_state) | 234 | static int check_mutually_exclusive(struct extcon_dev *edev, u32 new_state) |
| 247 | { | 235 | { |
| 248 | int i = 0; | 236 | int i = 0; |
| @@ -417,11 +405,13 @@ static ssize_t cable_state_show(struct device *dev, · 168 unmodified lines | |||
| 417 | } | 405 | } |
| 418 | 406 | ||
| 419 | /** | 407 | /** |
| 420 | * extcon_sync() - Synchronize the states for both the attached/detached | 408 | * extcon_sync() - Synchronize the state for an external connector. |
| 421 | * @edev: the extcon device that has the cable. | 409 | * @edev: the extcon device |
| 410 | * | ||
| 411 | * Note that this function send a notification in order to synchronize | ||
| 412 | * the state and property of an external connector. | ||
| 422 | * | 413 | * |
| 423 | * This function send a notification to synchronize the all states of a | 414 | * Returns 0 if success or error number if fail. |
| 424 | * specific external connector | ||
| 425 | */ | 415 | */ |
| 426 | int extcon_sync(struct extcon_dev *edev, unsigned int id) | 416 | int extcon_sync(struct extcon_dev *edev, unsigned int id) |
| 427 | { | 417 | { |
| @@ -497,9 +487,11 @@ int extcon_sync(struct extcon_dev *edev, unsigned int id) · 69 unmodified lines | |||
| 497 | EXPORT_SYMBOL_GPL(extcon_sync); | 487 | EXPORT_SYMBOL_GPL(extcon_sync); |
| 498 | 488 | ||
| 499 | /** | 489 | /** |
| 500 | * extcon_get_state() - Get the state of a external connector. | 490 | * extcon_get_state() - Get the state of an external connector. |
| 501 | * @edev: the extcon device that has the cable. | 491 | * @edev: the extcon device |
| 502 | * @id: the unique id of each external connector in extcon enumeration. | 492 | * @id: the unique id indicating an external connector |
| 493 | * | ||
| 494 | * Returns 0 if success or error number if fail. | ||
| 503 | */ | 495 | */ |
| 504 | int extcon_get_state(struct extcon_dev *edev, const unsigned int id) | 496 | int extcon_get_state(struct extcon_dev *edev, const unsigned int id) |
| 505 | { | 497 | { |
| @@ -522,20 +514,19 @@ int extcon_get_state(struct extcon_dev *edev, const unsigned int id) · 16 unmodified lines | |||
| 522 | EXPORT_SYMBOL_GPL(extcon_get_state); | 514 | EXPORT_SYMBOL_GPL(extcon_get_state); |
| 523 | 515 | ||
| 524 | /** | 516 | /** |
| 525 | * extcon_set_state() - Set the state of a external connector. | 517 | * extcon_set_state() - Set the state of an external connector. |
| 526 | * without a notification. | 518 | * @edev: the extcon device |
| 527 | * @edev: the extcon device that has the cable. | 519 | * @id: the unique id indicating an external connector |
| 528 | * @id: the unique id of each external connector | 520 | * @state: the new state of an external connector. |
| 529 | * in extcon enumeration. | 521 | * the default semantics is true: attached / false: detached. |
| 530 | * @state: the new cable status. The default semantics is | 522 | * |
| 531 | * true: attached / false: detached. | 523 | * Note that this function set the state of an external connector without |
| 524 | * a notification. To synchronize the state of an external connector, | ||
| 525 | * have to use extcon_set_state_sync() and extcon_sync(). | ||
| 532 | * | 526 | * |
| 533 | * This function only set the state of a external connector without | 527 | * Returns 0 if success or error number if fail. |
| 534 | * a notification. To synchronize the data of a external connector, | ||
| 535 | * use extcon_set_state_sync() and extcon_sync(). | ||
| 536 | */ | 528 | */ |
| 537 | int extcon_set_state(struct extcon_dev *edev, unsigned int id, | 529 | int extcon_set_state(struct extcon_dev *edev, unsigned int id, bool state) |
| 538 | bool cable_state) | ||
| 539 | { | 530 | { |
| 540 | unsigned long flags; | 531 | unsigned long flags; |
| 541 | int index, ret = 0; | 532 | int index, ret = 0; |
| @@ -550,11 +541,11 @@ int extcon_set_state(struct extcon_dev *edev, unsigned int id, · 8 unmodified lines | |||
| 550 | spin_lock_irqsave(&edev->lock, flags); | 541 | spin_lock_irqsave(&edev->lock, flags); |
| 551 | 542 | ||
| 552 | /* Check whether the external connector's state is changed. */ | 543 | /* Check whether the external connector's state is changed. */ |
| 553 | if (!is_extcon_changed(edev, index, cable_state)) | 544 | if (!is_extcon_changed(edev, index, state)) |
| 554 | goto out; | 545 | goto out; |
| 555 | 546 | ||
| 556 | if (check_mutually_exclusive(edev, | 547 | if (check_mutually_exclusive(edev, |
| 557 | (edev->state & ~BIT(index)) | (cable_state & BIT(index)))) { | 548 | (edev->state & ~BIT(index)) | (state & BIT(index)))) { |
| 558 | ret = -EPERM; | 549 | ret = -EPERM; |
| 559 | goto out; | 550 | goto out; |
| 560 | } | 551 | } |
| @@ -563,11 +554,11 @@ int extcon_set_state(struct extcon_dev *edev, unsigned int id, · 2 unmodified lines | |||
| 563 | * Initialize the value of extcon property before setting | 554 | * Initialize the value of extcon property before setting |
| 564 | * the detached state for an external connector. | 555 | * the detached state for an external connector. |
| 565 | */ | 556 | */ |
| 566 | if (!cable_state) | 557 | if (!state) |
| 567 | init_property(edev, id, index); | 558 | init_property(edev, id, index); |
| 568 | 559 | ||
| 569 | /* Update the state for a external connector. */ | 560 | /* Update the state for an external connector. */ |
| 570 | if (cable_state) | 561 | if (state) |
| 571 | edev->state |= BIT(index); | 562 | edev->state |= BIT(index); |
| 572 | else | 563 | else |
| 573 | edev->state &= ~(BIT(index)); | 564 | edev->state &= ~(BIT(index)); |
| @@ -579,19 +570,18 @@ out: · 5 unmodified lines | |||
| 579 | EXPORT_SYMBOL_GPL(extcon_set_state); | 570 | EXPORT_SYMBOL_GPL(extcon_set_state); |
| 580 | 571 | ||
| 581 | /** | 572 | /** |
| 582 | * extcon_set_state_sync() - Set the state of a external connector | 573 | * extcon_set_state_sync() - Set the state of an external connector with sync. |
| 583 | * with a notification. | 574 | * @edev: the extcon device |
| 584 | * @edev: the extcon device that has the cable. | 575 | * @id: the unique id indicating an external connector |
| 585 | * @id: the unique id of each external connector | 576 | * @state: the new state of external connector. |
| 586 | * in extcon enumeration. | 577 | * the default semantics is true: attached / false: detached. |
| 587 | * @state: the new cable status. The default semantics is | 578 | * |
| 588 | * true: attached / false: detached. | 579 | * Note that this function set the state of external connector |
| 580 | * and synchronize the state by sending a notification. | ||
| 589 | * | 581 | * |
| 590 | * This function set the state of external connector and synchronize the data | 582 | * Returns 0 if success or error number if fail. |
| 591 | * by usning a notification. | ||
| 592 | */ | 583 | */ |
| 593 | int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id, | 584 | int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id, bool state) |
| 594 | bool cable_state) | ||
| 595 | { | 585 | { |
| 596 | int ret, index; | 586 | int ret, index; |
| 597 | unsigned long flags; | 587 | unsigned long flags; |
| @@ -602,12 +592,12 @@ int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id, · 4 unmodified lines | |||
| 602 | 592 | ||
| 603 | /* Check whether the external connector's state is changed. */ | 593 | /* Check whether the external connector's state is changed. */ |
| 604 | spin_lock_irqsave(&edev->lock, flags); | 594 | spin_lock_irqsave(&edev->lock, flags); |
| 605 | ret = is_extcon_changed(edev, index, cable_state); | 595 | ret = is_extcon_changed(edev, index, state); |
| 606 | spin_unlock_irqrestore(&edev->lock, flags); | 596 | spin_unlock_irqrestore(&edev->lock, flags); |
| 607 | if (!ret) | 597 | if (!ret) |
| 608 | return 0; | 598 | return 0; |
| 609 | 599 | ||
| 610 | ret = extcon_set_state(edev, id, cable_state); | 600 | ret = extcon_set_state(edev, id, state); |
| 611 | if (ret < 0) | 601 | if (ret < 0) |
| 612 | return ret; | 602 | return ret; |
| 613 | 603 | ||
| @@ -616,19 +606,18 @@ int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id, · 2 unmodified lines | |||
| 616 | EXPORT_SYMBOL_GPL(extcon_set_state_sync); | 606 | EXPORT_SYMBOL_GPL(extcon_set_state_sync); |
| 617 | 607 | ||
| 618 | /** | 608 | /** |
| 619 | * extcon_get_property() - Get the property value of a specific cable. | 609 | * extcon_get_property() - Get the property value of an external connector. |
| 620 | * @edev: the extcon device that has the cable. | 610 | * @edev: the extcon device |
| 621 | * @id: the unique id of each external connector | 611 | * @id: the unique id indicating an external connector |
| 622 | * in extcon enumeration. | 612 | * @prop: the property id indicating an extcon property |
| 623 | * @prop: the property id among enum extcon_property. | 613 | * @prop_val: the pointer which store the value of extcon property |
| 624 | * @prop_val: the pointer which store the value of property. | ||
| 625 | * | 614 | * |
| 626 | * When getting the property value of external connector, the external connector | 615 | * Note that when getting the property value of external connector, |
| 627 | * should be attached. If detached state, function just return 0 without | 616 | * the external connector should be attached. If detached state, function |
| 628 | * property value. Also, the each property should be included in the list of | 617 | * return 0 without property value. Also, the each property should be |
| 629 | * supported properties according to the type of external connectors. | 618 | * included in the list of supported properties according to extcon type. |
| 630 | * | 619 | * |
| 631 | * Returns 0 if success or error number if fail | 620 | * Returns 0 if success or error number if fail. |
| 632 | */ | 621 | */ |
| 633 | int extcon_get_property(struct extcon_dev *edev, unsigned int id, | 622 | int extcon_get_property(struct extcon_dev *edev, unsigned int id, |
| 634 | unsigned int prop, | 623 | unsigned int prop, |
| @@ -698,17 +687,16 @@ int extcon_get_property(struct extcon_dev *edev, unsigned int id, · 63 unmodified lines | |||
| 698 | EXPORT_SYMBOL_GPL(extcon_get_property); | 687 | EXPORT_SYMBOL_GPL(extcon_get_property); |
| 699 | 688 | ||
| 700 | /** | 689 | /** |
| 701 | * extcon_set_property() - Set the property value of a specific cable. | 690 | * extcon_set_property() - Set the property value of an external connector. |
| 702 | * @edev: the extcon device that has the cable. | 691 | * @edev: the extcon device |
| 703 | * @id: the unique id of each external connector | 692 | * @id: the unique id indicating an external connector |
| 704 | * in extcon enumeration. | 693 | * @prop: the property id indicating an extcon property |
| 705 | * @prop: the property id among enum extcon_property. | 694 | * @prop_val: the pointer including the new value of extcon property |
| 706 | * @prop_val: the pointer including the new value of property. | ||
| 707 | * | 695 | * |
| 708 | * The each property should be included in the list of supported properties | 696 | * Note that each property should be included in the list of supported |
| 709 | * according to the type of external connectors. | 697 | * properties according to the extcon type. |
| 710 | * | 698 | * |
| 711 | * Returns 0 if success or error number if fail | 699 | * Returns 0 if success or error number if fail. |
| 712 | */ | 700 | */ |
| 713 | int extcon_set_property(struct extcon_dev *edev, unsigned int id, | 701 | int extcon_set_property(struct extcon_dev *edev, unsigned int id, |
| 714 | unsigned int prop, | 702 | unsigned int prop, |
| @@ -766,15 +754,14 @@ int extcon_set_property(struct extcon_dev *edev, unsigned int id, · 51 unmodified lines | |||
| 766 | EXPORT_SYMBOL_GPL(extcon_set_property); | 754 | EXPORT_SYMBOL_GPL(extcon_set_property); |
| 767 | 755 | ||
| 768 | /** | 756 | /** |
| 769 | * extcon_set_property_sync() - Set the property value of a specific cable | 757 | * extcon_set_property_sync() - Set property of an external connector with sync. |
| 770 | with a notification. | 758 | * @prop_val: the pointer including the new value of extcon property |
| 771 | * @prop_val: the pointer including the new value of property. | ||
| 772 | * | 759 | * |
| 773 | * When setting the property value of external connector, the external connector | 760 | * Note that when setting the property value of external connector, |
| 774 | * should be attached. The each property should be included in the list of | 761 | * the external connector should be attached. The each property should |
| 775 | * supported properties according to the type of external connectors. | 762 | * be included in the list of supported properties according to extcon type. |
| 776 | * | 763 | * |
| 777 | * Returns 0 if success or error number if fail | 764 | * Returns 0 if success or error number if fail. |
| 778 | */ | 765 | */ |
| 779 | int extcon_set_property_sync(struct extcon_dev *edev, unsigned int id, | 766 | int extcon_set_property_sync(struct extcon_dev *edev, unsigned int id, |
| 780 | unsigned int prop, | 767 | unsigned int prop, |
| @@ -791,12 +778,11 @@ int extcon_set_property_sync(struct extcon_dev *edev, unsigned int id, · 10 unmodified lines | |||
| 791 | EXPORT_SYMBOL_GPL(extcon_set_property_sync); | 778 | EXPORT_SYMBOL_GPL(extcon_set_property_sync); |
| 792 | 779 | ||
| 793 | /** | 780 | /** |
| 794 | * extcon_get_property_capability() - Get the capability of property | 781 | * extcon_get_property_capability() - Get the capability of the property |
| 795 | * of an external connector. | 782 | * for an external connector. |
| 796 | * @edev: the extcon device that has the cable. | 783 | * @edev: the extcon device |
| 797 | * @id: the unique id of each external connector | 784 | * @id: the unique id indicating an external connector |
| 798 | * in extcon enumeration. | 785 | * @prop: the property id indicating an extcon property |
| 799 | * @prop: the property id among enum extcon_property. | ||
| 800 | * | 786 | * |
| 801 | * Returns 1 if the property is available or 0 if not available. | 787 | * Returns 1 if the property is available or 0 if not available. |
| 802 | */ | 788 | */ |
| @@ -822,18 +808,17 @@ int extcon_get_property_capability(struct extcon_dev *edev, unsigned int id, · 19 unmodified lines | |||
| 822 | EXPORT_SYMBOL_GPL(extcon_get_property_capability); | 808 | EXPORT_SYMBOL_GPL(extcon_get_property_capability); |
| 823 | 809 | ||
| 824 | /** | 810 | /** |
| 825 | * extcon_set_property_capability() - Set the capability of a property | 811 | * extcon_set_property_capability() - Set the capability of the property |
| 826 | * of an external connector. | 812 | * for an external connector. |
| 827 | * @edev: the extcon device that has the cable. | 813 | * @edev: the extcon device |
| 828 | * @id: the unique id of each external connector | 814 | * @id: the unique id indicating an external connector |
| 829 | * in extcon enumeration. | 815 | * @prop: the property id indicating an extcon property |
| 830 | * @prop: the property id among enum extcon_property. | ||
| 831 | * | 816 | * |
| 832 | * This function set the capability of a property for an external connector | 817 | * Note that this function set the capability of the property |
| 833 | * to mark the bit in capability bitmap which mean the available state of | 818 | * for an external connector in order to mark the bit in capability |
| 834 | * a property. | 819 | * bitmap which mean the available state of the property. |
| 835 | * | 820 | * |
| 836 | * Returns 0 if success or error number if fail | 821 | * Returns 0 if success or error number if fail. |
| 837 | */ | 822 | */ |
| 838 | int extcon_set_property_capability(struct extcon_dev *edev, unsigned int id, | 823 | int extcon_set_property_capability(struct extcon_dev *edev, unsigned int id, |
| 839 | unsigned int prop) | 824 | unsigned int prop) |
| @@ -881,8 +866,10 @@ int extcon_set_property_capability(struct extcon_dev *edev, unsigned int id, · 41 unmodified lines | |||
| 881 | EXPORT_SYMBOL_GPL(extcon_set_property_capability); | 866 | EXPORT_SYMBOL_GPL(extcon_set_property_capability); |
| 882 | 867 | ||
| 883 | /** | 868 | /** |
| 884 | * extcon_get_extcon_dev() - Get the extcon device instance from the name | 869 | * extcon_get_extcon_dev() - Get the extcon device instance from the name. |
| 885 | * @extcon_name: The extcon name provided with extcon_dev_register() | 870 | * @extcon_name: the extcon name provided with extcon_dev_register() |
| 871 | * | ||
| 872 | * Return the pointer of extcon device if success or ERR_PTR(err) if fail. | ||
| 886 | */ | 873 | */ |
| 887 | struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name) | 874 | struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name) |
| 888 | { | 875 | { |
| @@ -904,15 +891,17 @@ out: · 15 unmodified lines | |||
| 904 | EXPORT_SYMBOL_GPL(extcon_get_extcon_dev); | 891 | EXPORT_SYMBOL_GPL(extcon_get_extcon_dev); |
| 905 | 892 | ||
| 906 | /** | 893 | /** |
| 907 | * extcon_register_notifier() - Register a notifiee to get notified by | 894 | * extcon_register_notifier() - Register a notifier block to get notified by |
| 908 | * any attach status changes from the extcon. | 895 | * any state changes from the extcon. |
| 909 | * @edev: the extcon device that has the external connecotr. | 896 | * @edev: the extcon device |
| 910 | * @id: the unique id of each external connector in extcon enumeration. | 897 | * @id: the unique id indicating an external connector |
| 911 | * @nb: a notifier block to be registered. | 898 | * @nb: a notifier block to be registered |
| 912 | * | 899 | * |
| 913 | * Note that the second parameter given to the callback of nb (val) is | 900 | * Note that the second parameter given to the callback of nb (val) is |
| 914 | * "old_state", not the current state. The current state can be retrieved | 901 | * the current state of an external connector and the third pameter |
| 915 | * by looking at the third pameter (edev pointer)'s state value. | 902 | * is the pointer of extcon device. |
| 903 | * | ||
| 904 | * Returns 0 if success or error number if fail. | ||
| 916 | */ | 905 | */ |
| 917 | int extcon_register_notifier(struct extcon_dev *edev, unsigned int id, | 906 | int extcon_register_notifier(struct extcon_dev *edev, unsigned int id, |
| 918 | struct notifier_block *nb) | 907 | struct notifier_block *nb) |
| @@ -936,10 +925,12 @@ int extcon_register_notifier(struct extcon_dev *edev, unsigned int id, · 17 unmodified lines | |||
| 936 | EXPORT_SYMBOL_GPL(extcon_register_notifier); | 925 | EXPORT_SYMBOL_GPL(extcon_register_notifier); |
| 937 | 926 | ||
| 938 | /** | 927 | /** |
| 939 | * extcon_unregister_notifier() - Unregister a notifiee from the extcon device. | 928 | * extcon_unregister_notifier() - Unregister a notifier block from the extcon. |
| 940 | * @edev: the extcon device that has the external connecotr. | 929 | * @edev: the extcon device |
| 941 | * @id: the unique id of each external connector in extcon enumeration. | 930 | * @id: the unique id indicating an external connector |
| 942 | * @nb: a notifier block to be registered. | 931 | * @nb: a notifier block to be registered |
| 932 | * | ||
| 933 | * Returns 0 if success or error number if fail. | ||
| 943 | */ | 934 | */ |
| 944 | int extcon_unregister_notifier(struct extcon_dev *edev, unsigned int id, | 935 | int extcon_unregister_notifier(struct extcon_dev *edev, unsigned int id, |
| 945 | struct notifier_block *nb) | 936 | struct notifier_block *nb) |
| @@ -963,16 +954,16 @@ int extcon_unregister_notifier(struct extcon_dev *edev, unsigned int id, · 17 unmodified lines | |||
| 963 | EXPORT_SYMBOL_GPL(extcon_unregister_notifier); | 954 | EXPORT_SYMBOL_GPL(extcon_unregister_notifier); |
| 964 | 955 | ||
| 965 | /** | 956 | /** |
| 966 | * extcon_register_notifier_all() - Register a notifier block for all connectors | 957 | * extcon_register_notifier_all() - Register a notifier block for all connectors. |
| 967 | * @edev: the extcon device that has the external connector. | 958 | * @edev: the extcon device |
| 968 | * @nb: a notifier block to be registered. | 959 | * @nb: a notifier block to be registered |
| 969 | * | 960 | * |
| 970 | * This function registers a notifier block in order to receive the state | 961 | * Note that this function registers a notifier block in order to receive |
| 971 | * change of all supported external connectors from extcon device. | 962 | * the state change of all supported external connectors from extcon device. |
| 972 | * And the second parameter given to the callback of nb (val) is | 963 | * And the second parameter given to the callback of nb (val) is |
| 973 | * the current state and third parameter is the edev pointer. | 964 | * the current state and the third pameter is the pointer of extcon device. |
| 974 | * | 965 | * |
| 975 | * Returns 0 if success or error number if fail | 966 | * Returns 0 if success or error number if fail. |
| 976 | */ | 967 | */ |
| 977 | int extcon_register_notifier_all(struct extcon_dev *edev, | 968 | int extcon_register_notifier_all(struct extcon_dev *edev, |
| 978 | struct notifier_block *nb) | 969 | struct notifier_block *nb) |
| @@ -993,10 +984,10 @@ EXPORT_SYMBOL_GPL(extcon_register_notifier_all); · 14 unmodified lines | |||
| 993 | 984 | ||
| 994 | /** | 985 | /** |
| 995 | * extcon_unregister_notifier_all() - Unregister a notifier block from extcon. | 986 | * extcon_unregister_notifier_all() - Unregister a notifier block from extcon. |
| 996 | * @edev: the extcon device that has the external connecotr. | 987 | * @edev: the extcon device |
| 997 | * @nb: a notifier block to be registered. | 988 | * @nb: a notifier block to be registered |
| 998 | * | 989 | * |
| 999 | * Returns 0 if success or error number if fail | 990 | * Returns 0 if success or error number if fail. |
| 1000 | */ | 991 | */ |
| 1001 | int extcon_unregister_notifier_all(struct extcon_dev *edev, | 992 | int extcon_unregister_notifier_all(struct extcon_dev *edev, |
| 1002 | struct notifier_block *nb) | 993 | struct notifier_block *nb) |
| @@ -1045,15 +1036,14 @@ static void dummy_sysfs_dev_release(struct device *dev) · 42 unmodified lines | |||
| 1045 | 1036 | ||
| 1046 | /* | 1037 | /* |
| 1047 | * extcon_dev_allocate() - Allocate the memory of extcon device. | 1038 | * extcon_dev_allocate() - Allocate the memory of extcon device. |
| 1048 | * @supported_cable: Array of supported extcon ending with EXTCON_NONE. | 1039 | * @supported_cable: the array of the supported external connectors |
| 1049 | * If supported_cable is NULL, cable name related APIs | 1040 | * ending with EXTCON_NONE. |
| 1050 | * are disabled. | ||
| 1051 | * | 1041 | * |
| 1052 | * This function allocates the memory for extcon device without allocating | 1042 | * Note that this function allocates the memory for extcon device |
| 1053 | * memory in each extcon provider driver and initialize default setting for | 1043 | * and initialize default setting for the extcon device. |
| 1054 | * extcon device. | ||
| 1055 | * | 1044 | * |
| 1056 | * Return the pointer of extcon device if success or ERR_PTR(err) if fail | 1045 | * Returns the pointer memory of allocated extcon_dev if success |
| 1046 | * or ERR_PTR(err) if fail. | ||
| 1057 | */ | 1047 | */ |
| 1058 | struct extcon_dev *extcon_dev_allocate(const unsigned int *supported_cable) | 1048 | struct extcon_dev *extcon_dev_allocate(const unsigned int *supported_cable) |
| 1059 | { | 1049 | { |
| @@ -1074,7 +1064,7 @@ struct extcon_dev *extcon_dev_allocate(const unsigned int *supported_cable) · 14 unmodified lines | |||
| 1074 | 1064 | ||
| 1075 | /* | 1065 | /* |
| 1076 | * extcon_dev_free() - Free the memory of extcon device. | 1066 | * extcon_dev_free() - Free the memory of extcon device. |
| 1077 | * @edev: the extcon device to free | 1067 | * @edev: the extcon device |
| 1078 | */ | 1068 | */ |
| 1079 | void extcon_dev_free(struct extcon_dev *edev) | 1069 | void extcon_dev_free(struct extcon_dev *edev) |
| 1080 | { | 1070 | { |
| @@ -1083,13 +1073,18 @@ void extcon_dev_free(struct extcon_dev *edev) · 2 unmodified lines | |||
| 1083 | EXPORT_SYMBOL_GPL(extcon_dev_free); | 1073 | EXPORT_SYMBOL_GPL(extcon_dev_free); |
| 1084 | 1074 | ||
| 1085 | /** | 1075 | /** |
| 1086 | * extcon_dev_register() - Register a new extcon device | 1076 | * extcon_dev_register() - Register an new extcon device |
| 1087 | * @edev : the new extcon device (should be allocated before calling) | 1077 | * @edev: the extcon device to be registered |
| 1088 | * | 1078 | * |
| 1089 | * Among the members of edev struct, please set the "user initializing data" | 1079 | * Among the members of edev struct, please set the "user initializing data" |
| 1090 | * in any case and set the "optional callbacks" if required. However, please | ||
| 1091 | * do not set the values of "internal data", which are initialized by | 1080 | * do not set the values of "internal data", which are initialized by |
| 1092 | * this function. | 1081 | * this function. |
| 1082 | * | ||
| 1083 | * Note that before calling this funciton, have to allocate the memory | ||
| 1084 | * of an extcon device by using the extcon_dev_allocate(). And the extcon | ||
| 1085 | * dev should include the supported_cable information. | ||
| 1086 | * | ||
| 1087 | * Returns 0 if success or error number if fail. | ||
| 1093 | */ | 1088 | */ |
| 1094 | int extcon_dev_register(struct extcon_dev *edev) | 1089 | int extcon_dev_register(struct extcon_dev *edev) |
| 1095 | { | 1090 | { |
| @@ -1296,7 +1291,7 @@ EXPORT_SYMBOL_GPL(extcon_dev_register); · 200 unmodified lines | |||
| 1296 | 1291 | ||
| 1297 | /** | 1292 | /** |
| 1298 | * extcon_dev_unregister() - Unregister the extcon device. | 1293 | * extcon_dev_unregister() - Unregister the extcon device. |
| 1299 | * @edev: the extcon device instance to be unregistered. | 1294 | * @edev: the extcon device to be unregistered. |
| 1300 | * | 1295 | * |
| 1301 | * Note that this does not call kfree(edev) because edev was not allocated | 1296 | * Note that this does not call kfree(edev) because edev was not allocated |
| 1302 | * by this class. | 1297 | * by this class. |
| @@ -1342,11 +1337,11 @@ EXPORT_SYMBOL_GPL(extcon_dev_unregister); · 39 unmodified lines | |||
| 1342 | 1337 | ||
| 1343 | #ifdef CONFIG_OF | 1338 | #ifdef CONFIG_OF |
| 1344 | /* | 1339 | /* |
| 1345 | * extcon_get_edev_by_phandle - Get the extcon device from devicetree | 1340 | * extcon_get_edev_by_phandle - Get the extcon device from devicetree. |
| 1346 | * @dev - instance to the given device | 1341 | * @dev : the instance to the given device |
| 1347 | * @index - index into list of extcon_dev | 1342 | * @index : the index into list of extcon_dev |
| 1348 | * | 1343 | * |
| 1349 | * return the instance of extcon device | 1344 | * Return the pointer of extcon device if success or ERR_PTR(err) if fail. |
| 1350 | */ | 1345 | */ |
| 1351 | struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index) | 1346 | struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index) |
| 1352 | { | 1347 | { |
| @@ -1363,8 +1358,8 @@ struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, int index) · 10 unmodified lines | |||
| 1363 | 1358 | ||
| 1364 | node = of_parse_phandle(dev->of_node, "extcon", index); | 1359 | node = of_parse_phandle(dev->of_node, "extcon", index); |
| 1365 | if (!node) { | 1360 | if (!node) { |
| 1366 | dev_dbg(dev, "failed to get phandle in %s node\n", | 1361 | dev_dbg(dev, "failed to get phandle in %pOF node\n", |
| 1367 | dev->of_node->full_name); | 1362 | dev->of_node); |
| 1368 | return ERR_PTR(-ENODEV); | 1363 | return ERR_PTR(-ENODEV); |
| 1369 | } | 1364 | } |
| 1370 | 1365 | ||
| @@ -1411,8 +1406,6 @@ static void __exit extcon_class_exit(void) · 40 unmodified lines | |||
| 1411 | module_exit(extcon_class_exit); | 1406 | module_exit(extcon_class_exit); |
| 1412 | 1407 | ||
| 1413 | MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>"); | 1408 | MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>"); |
| 1414 | MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>"); | ||
| 1415 | MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>"); | ||
| 1416 | MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); | 1409 | MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); |
| 1417 | MODULE_DESCRIPTION("External connector (extcon) class driver"); | 1410 | MODULE_DESCRIPTION("External Connector (extcon) framework"); |
| 1418 | MODULE_LICENSE("GPL"); | 1411 | MODULE_LICENSE("GPL v2"); |
| @@ -202,7 +202,7 @@ static int vpd_section_init(const char *name, struct vpd_section *sec, · 201 unmodified lines | |||
| 202 | sec->raw_name = kasprintf(GFP_KERNEL, "%s_raw", name); | 202 | sec->raw_name = kasprintf(GFP_KERNEL, "%s_raw", name); |
| 203 | if (!sec->raw_name) { | 203 | if (!sec->raw_name) { |
| 204 | err = -ENOMEM; | 204 | err = -ENOMEM; |
| 205 | goto err_iounmap; | 205 | goto err_memunmap; |
| 206 | } | 206 | } |
| 207 | 207 | ||
| 208 | sysfs_bin_attr_init(&sec->bin_attr); | 208 | sysfs_bin_attr_init(&sec->bin_attr); |
| @@ -233,8 +233,8 @@ err_sysfs_remove: · 24 unmodified lines | |||
| 233 | sysfs_remove_bin_file(vpd_kobj, &sec->bin_attr); | 233 | sysfs_remove_bin_file(vpd_kobj, &sec->bin_attr); |
| 234 | err_free_raw_name: | 234 | err_free_raw_name: |
| 235 | kfree(sec->raw_name); | 235 | kfree(sec->raw_name); |
| 236 | err_iounmap: | 236 | err_memunmap: |
| 237 | iounmap(sec->baseaddr); | 237 | memunmap(sec->baseaddr); |
| 238 | return err; | 238 | return err; |
| 239 | } | 239 | } |
| 240 | 240 | ||
| @@ -245,7 +245,7 @@ static int vpd_section_destroy(struct vpd_section *sec) · 4 unmodified lines | |||
| 245 | kobject_put(sec->kobj); | 245 | kobject_put(sec->kobj); |
| 246 | sysfs_remove_bin_file(vpd_kobj, &sec->bin_attr); | 246 | sysfs_remove_bin_file(vpd_kobj, &sec->bin_attr); |
| 247 | kfree(sec->raw_name); | 247 | kfree(sec->raw_name); |
| 248 | iounmap(sec->baseaddr); | 248 | memunmap(sec->baseaddr); |
| 249 | } | 249 | } |
| 250 | 250 | ||
| 251 | return 0; | 251 | return 0; |
| @@ -262,7 +262,7 @@ static int vpd_sections_init(phys_addr_t physaddr) · 10 unmodified lines | |||
| 262 | return -ENOMEM; | 262 | return -ENOMEM; |
| 263 | 263 | ||
| 264 | memcpy_fromio(&header, temp, sizeof(struct vpd_cbmem)); | 264 | memcpy_fromio(&header, temp, sizeof(struct vpd_cbmem)); |
| 265 | iounmap(temp); | 265 | memunmap(temp); |
| 266 | 266 | ||
| 267 | if (header.magic != VPD_CBMEM_MAGIC) | 267 | if (header.magic != VPD_CBMEM_MAGIC) |
| 268 | return -ENODEV; | 268 | return -ENODEV; |
| @@ -6,6 +6,7 @@ fmc-y += fmc-match.o · 5 unmodified lines | |||
| 6 | fmc-y += fmc-sdb.o | 6 | fmc-y += fmc-sdb.o |
| 7 | fmc-y += fru-parse.o | 7 | fmc-y += fru-parse.o |
| 8 | fmc-y += fmc-dump.o | 8 | fmc-y += fmc-dump.o |
| 9 | fmc-y += fmc-debug.o | ||
| 9 | 10 | ||
| 10 | obj-$(CONFIG_FMC_FAKEDEV) += fmc-fakedev.o | 11 | obj-$(CONFIG_FMC_FAKEDEV) += fmc-fakedev.o |
| 11 | obj-$(CONFIG_FMC_TRIVIAL) += fmc-trivial.o | 12 | obj-$(CONFIG_FMC_TRIVIAL) += fmc-trivial.o |
| @@ -129,8 +129,7 @@ static int fc_probe(struct fmc_device *fmc) · 128 unmodified lines | |||
| 129 | 129 | ||
| 130 | struct fc_instance *fc; | 130 | struct fc_instance *fc; |
| 131 | 131 | ||
| 132 | if (fmc->op->validate) | 132 | index = fmc_validate(fmc, &fc_drv); |
| 133 | index = fmc->op->validate(fmc, &fc_drv); | ||
| 134 | if (index < 0) | 133 | if (index < 0) |
| 135 | return -EINVAL; /* not our device: invalid */ | 134 | return -EINVAL; /* not our device: invalid */ |
| 136 | 135 | ||
| @@ -13,6 +13,9 @@ · 12 unmodified lines | |||
| 13 | #include <linux/init.h> | 13 | #include <linux/init.h> |
| 14 | #include <linux/device.h> | 14 | #include <linux/device.h> |
| 15 | #include <linux/fmc.h> | 15 | #include <linux/fmc.h> |
| 16 | #include <linux/fmc-sdb.h> | ||
| 17 | |||
| 18 | #include "fmc-private.h" | ||
| 16 | 19 | ||
| 17 | static int fmc_check_version(unsigned long version, const char *name) | 20 | static int fmc_check_version(unsigned long version, const char *name) |
| 18 | { | 21 | { |
| @@ -118,6 +121,61 @@ static struct bin_attribute fmc_eeprom_attr = { · 99 unmodified lines | |||
| 118 | .write = fmc_write_eeprom, | 121 | .write = fmc_write_eeprom, |
| 119 | }; | 122 | }; |
| 120 | 123 | ||
| 124 | int fmc_irq_request(struct fmc_device *fmc, irq_handler_t h, | ||
| 125 | char *name, int flags) | ||
| 126 | { | ||
| 127 | if (fmc->op->irq_request) | ||
| 128 | return fmc->op->irq_request(fmc, h, name, flags); | ||
| 129 | return -EPERM; | ||
| 130 | } | ||
| 131 | EXPORT_SYMBOL(fmc_irq_request); | ||
| 132 | |||
| 133 | void fmc_irq_free(struct fmc_device *fmc) | ||
| 134 | { | ||
| 135 | if (fmc->op->irq_free) | ||
| 136 | fmc->op->irq_free(fmc); | ||
| 137 | } | ||
| 138 | EXPORT_SYMBOL(fmc_irq_free); | ||
| 139 | |||
| 140 | void fmc_irq_ack(struct fmc_device *fmc) | ||
| 141 | { | ||
| 142 | if (likely(fmc->op->irq_ack)) | ||
| 143 | fmc->op->irq_ack(fmc); | ||
| 144 | } | ||
| 145 | EXPORT_SYMBOL(fmc_irq_ack); | ||
| 146 | |||
| 147 | int fmc_validate(struct fmc_device *fmc, struct fmc_driver *drv) | ||
| 148 | { | ||
| 149 | if (fmc->op->validate) | ||
| 150 | return fmc->op->validate(fmc, drv); | ||
| 151 | return -EPERM; | ||
| 152 | } | ||
| 153 | EXPORT_SYMBOL(fmc_validate); | ||
| 154 | |||
| 155 | int fmc_gpio_config(struct fmc_device *fmc, struct fmc_gpio *gpio, int ngpio) | ||
| 156 | { | ||
| 157 | if (fmc->op->gpio_config) | ||
| 158 | return fmc->op->gpio_config(fmc, gpio, ngpio); | ||
| 159 | return -EPERM; | ||
| 160 | } | ||
| 161 | EXPORT_SYMBOL(fmc_gpio_config); | ||
| 162 | |||
| 163 | int fmc_read_ee(struct fmc_device *fmc, int pos, void *d, int l) | ||
| 164 | { | ||
| 165 | if (fmc->op->read_ee) | ||
| 166 | return fmc->op->read_ee(fmc, pos, d, l); | ||
| 167 | return -EPERM; | ||
| 168 | } | ||
| 169 | EXPORT_SYMBOL(fmc_read_ee); | ||
| 170 | |||
| 171 | int fmc_write_ee(struct fmc_device *fmc, int pos, const void *d, int l) | ||
| 172 | { | ||
| 173 | if (fmc->op->write_ee) | ||
| 174 | return fmc->op->write_ee(fmc, pos, d, l); | ||
| 175 | return -EPERM; | ||
| 176 | } | ||
| 177 | EXPORT_SYMBOL(fmc_write_ee); | ||
| 178 | |||
| 121 | /* | 179 | /* |
| 122 | * Functions for client modules follow | 180 | * Functions for client modules follow |
| 123 | */ | 181 | */ |
| @@ -141,7 +199,8 @@ EXPORT_SYMBOL(fmc_driver_unregister); · 17 unmodified lines | |||
| 141 | * When a device set is registered, all eeproms must be read | 199 | * When a device set is registered, all eeproms must be read |
| 142 | * and all FRUs must be parsed | 200 | * and all FRUs must be parsed |
| 143 | */ | 201 | */ |
| 144 | int fmc_device_register_n(struct fmc_device **devs, int n) | 202 | int fmc_device_register_n_gw(struct fmc_device **devs, int n, |
| 203 | struct fmc_gateware *gw) | ||
| 145 | { | 204 | { |
| 146 | struct fmc_device *fmc, **devarray; | 205 | struct fmc_device *fmc, **devarray; |
| 147 | uint32_t device_id; | 206 | uint32_t device_id; |
| @@ -221,6 +280,21 @@ int fmc_device_register_n(struct fmc_device **devs, int n) · 73 unmodified lines | |||
| 221 | else | 280 | else |
| 222 | dev_set_name(&fmc->dev, "%s-%04x", fmc->mezzanine_name, | 281 | dev_set_name(&fmc->dev, "%s-%04x", fmc->mezzanine_name, |
| 223 | device_id); | 282 | device_id); |
| 283 | |||
| 284 | if (gw) { | ||
| 285 | /* | ||
| 286 | * The carrier already know the bitstream to load | ||
| 287 | * for this set of FMC mezzanines. | ||
| 288 | */ | ||
| 289 | ret = fmc->op->reprogram_raw(fmc, NULL, | ||
| 290 | gw->bitstream, gw->len); | ||
| 291 | if (ret) { | ||
| 292 | dev_warn(fmc->hwdev, | ||
| 293 | "Invalid gateware for FMC mezzanine\n"); | ||
| 294 | goto out; | ||
| 295 | } | ||
| 296 | } | ||
| 297 | |||
| 224 | ret = device_add(&fmc->dev); | 298 | ret = device_add(&fmc->dev); |
| 225 | if (ret < 0) { | 299 | if (ret < 0) { |
| 226 | dev_err(fmc->hwdev, "Slot %i: Failed in registering " | 300 | dev_err(fmc->hwdev, "Slot %i: Failed in registering " |
| @@ -234,18 +308,16 @@ int fmc_device_register_n(struct fmc_device **devs, int n) · 7 unmodified lines | |||
| 234 | } | 308 | } |
| 235 | /* This device went well, give information to the user */ | 309 | /* This device went well, give information to the user */ |
| 236 | fmc_dump_eeprom(fmc); | 310 | fmc_dump_eeprom(fmc); |
| 237 | fmc_dump_sdb(fmc); | 311 | fmc_debug_init(fmc); |
| 238 | } | 312 | } |
| 239 | return 0; | 313 | return 0; |
| 240 | 314 | ||
| 241 | out1: | 315 | out1: |
| 242 | device_del(&fmc->dev); | 316 | device_del(&fmc->dev); |
| 243 | out: | 317 | out: |
| 244 | fmc_free_id_info(fmc); | ||
| 245 | put_device(&fmc->dev); | ||
| 246 | |||
| 247 | kfree(devarray); | 318 | kfree(devarray); |
| 248 | for (i--; i >= 0; i--) { | 319 | for (i--; i >= 0; i--) { |
| 320 | fmc_debug_exit(devs[i]); | ||
| 249 | sysfs_remove_bin_file(&devs[i]->dev.kobj, &fmc_eeprom_attr); | 321 | sysfs_remove_bin_file(&devs[i]->dev.kobj, &fmc_eeprom_attr); |
| 250 | device_del(&devs[i]->dev); | 322 | device_del(&devs[i]->dev); |
| 251 | fmc_free_id_info(devs[i]); | 323 | fmc_free_id_info(devs[i]); |
| @@ -254,8 +326,20 @@ out: · 2 unmodified lines | |||
| 254 | return ret; | 326 | return ret; |
| 255 | 327 | ||
| 256 | } | 328 | } |
| 329 | EXPORT_SYMBOL(fmc_device_register_n_gw); | ||
| 330 | |||
| 331 | int fmc_device_register_n(struct fmc_device **devs, int n) | ||
| 332 | { | ||
| 333 | return fmc_device_register_n_gw(devs, n, NULL); | ||
| 334 | } | ||
| 257 | EXPORT_SYMBOL(fmc_device_register_n); | 335 | EXPORT_SYMBOL(fmc_device_register_n); |
| 258 | 336 | ||
| 337 | int fmc_device_register_gw(struct fmc_device *fmc, struct fmc_gateware *gw) | ||
| 338 | { | ||
| 339 | return fmc_device_register_n_gw(&fmc, 1, gw); | ||
| 340 | } | ||
| 341 | EXPORT_SYMBOL(fmc_device_register_gw); | ||
| 342 | |||
| 259 | int fmc_device_register(struct fmc_device *fmc) | 343 | int fmc_device_register(struct fmc_device *fmc) |
| 260 | { | 344 | { |
| 261 | return fmc_device_register_n(&fmc, 1); | 345 | return fmc_device_register_n(&fmc, 1); |
| @@ -273,6 +357,7 @@ void fmc_device_unregister_n(struct fmc_device **devs, int n) · 11 unmodified lines | |||
| 273 | kfree(devs[0]->devarray); | 357 | kfree(devs[0]->devarray); |
| 274 | 358 | ||
| 275 | for (i = 0; i < n; i++) { | 359 | for (i = 0; i < n; i++) { |
| 360 | fmc_debug_exit(devs[i]); | ||
| 276 | sysfs_remove_bin_file(&devs[i]->dev.kobj, &fmc_eeprom_attr); | 361 | sysfs_remove_bin_file(&devs[i]->dev.kobj, &fmc_eeprom_attr); |
| 277 | device_del(&devs[i]->dev); | 362 | device_del(&devs[i]->dev); |
| 278 | fmc_free_id_info(devs[i]); | 363 | fmc_free_id_info(devs[i]); |
| @@ -0,0 +1,173 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2015 CERN (www.cern.ch) | ||
| 3 | * Author: Federico Vaga <federico.vaga@cern.ch> | ||
| 4 | * | ||
| 5 | * Released according to the GNU GPL, version 2 or any later version. | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/module.h> | ||
| 9 | #include <linux/device.h> | ||
| 10 | #include <linux/init.h> | ||
| 11 | #include <linux/fs.h> | ||
| 12 | #include <linux/debugfs.h> | ||
| 13 | #include <linux/seq_file.h> | ||
| 14 | #include <asm/byteorder.h> | ||
| 15 | |||
| 16 | #include <linux/fmc.h> | ||
| 17 | #include <linux/sdb.h> | ||
| 18 | #include <linux/fmc-sdb.h> | ||
| 19 | |||
| 20 | #define FMC_DBG_SDB_DUMP "dump_sdb" | ||
| 21 | |||
| 22 | static char *__strip_trailing_space(char *buf, char *str, int len) | ||
| 23 | { | ||
| 24 | int i = len - 1; | ||
| 25 | |||
| 26 | memcpy(buf, str, len); | ||
| 27 | buf[len] = '\0'; | ||
| 28 | while (i >= 0 && buf[i] == ' ') | ||
| 29 | buf[i--] = '\0'; | ||
| 30 | return buf; | ||
| 31 | } | ||
| 32 | |||
| 33 | #define __sdb_string(buf, field) ({ \ | ||
| 34 | BUILD_BUG_ON(sizeof(buf) < sizeof(field)); \ | ||
| 35 | __strip_trailing_space(buf, (void *)(field), sizeof(field)); \ | ||
| 36 | }) | ||
| 37 | |||
| 38 | /** | ||
| 39 | * We do not check seq_printf() errors because we want to see things in any case | ||
| 40 | */ | ||
| 41 | static void fmc_sdb_dump_recursive(struct fmc_device *fmc, struct seq_file *s, | ||
| 42 | const struct sdb_array *arr) | ||
| 43 | { | ||
| 44 | unsigned long base = arr->baseaddr; | ||
| 45 | int i, j, n = arr->len, level = arr->level; | ||
| 46 | char tmp[64]; | ||
| 47 | |||
| 48 | for (i = 0; i < n; i++) { | ||
| 49 | union sdb_record *r; | ||
| 50 | struct sdb_product *p; | ||
| 51 | struct sdb_component *c; | ||
| 52 | |||
| 53 | r = &arr->record[i]; | ||
| 54 | c = &r->dev.sdb_component; | ||
| 55 | p = &c->product; | ||
| 56 | |||
| 57 | for (j = 0; j < level; j++) | ||
| 58 | seq_printf(s, " "); | ||
| 59 | switch (r->empty.record_type) { | ||
| 60 | case sdb_type_interconnect: | ||
| 61 | seq_printf(s, "%08llx:%08x %.19s\n", | ||
| 62 | __be64_to_cpu(p->vendor_id), | ||
| 63 | __be32_to_cpu(p->device_id), | ||
| 64 | p->name); | ||
| 65 | break; | ||
| 66 | case sdb_type_device: | ||
| 67 | seq_printf(s, "%08llx:%08x %.19s (%08llx-%08llx)\n", | ||
| 68 | __be64_to_cpu(p->vendor_id), | ||
| 69 | __be32_to_cpu(p->device_id), | ||
| 70 | p->name, | ||
| 71 | __be64_to_cpu(c->addr_first) + base, | ||
| 72 | __be64_to_cpu(c->addr_last) + base); | ||
| 73 | break; | ||
| 74 | case sdb_type_bridge: | ||
| 75 | seq_printf(s, "%08llx:%08x %.19s (bridge: %08llx)\n", | ||
| 76 | __be64_to_cpu(p->vendor_id), | ||
| 77 | __be32_to_cpu(p->device_id), | ||
| 78 | p->name, | ||
| 79 | __be64_to_cpu(c->addr_first) + base); | ||
| 80 | if (IS_ERR(arr->subtree[i])) { | ||
| 81 | seq_printf(s, "SDB: (bridge error %li)\n", | ||
| 82 | PTR_ERR(arr->subtree[i])); | ||
| 83 | break; | ||
| 84 | } | ||
| 85 | fmc_sdb_dump_recursive(fmc, s, arr->subtree[i]); | ||
| 86 | break; | ||
| 87 | case sdb_type_integration: | ||
| 88 | seq_printf(s, "integration\n"); | ||
| 89 | break; | ||
| 90 | case sdb_type_repo_url: | ||
| 91 | seq_printf(s, "Synthesis repository: %s\n", | ||
| 92 | __sdb_string(tmp, r->repo_url.repo_url)); | ||
| 93 | break; | ||
| 94 | case sdb_type_synthesis: | ||
| 95 | seq_printf(s, "Bitstream '%s' ", | ||
| 96 | __sdb_string(tmp, r->synthesis.syn_name)); | ||
| 97 | seq_printf(s, "synthesized %08x by %s ", | ||
| 98 | __be32_to_cpu(r->synthesis.date), | ||
| 99 | __sdb_string(tmp, r->synthesis.user_name)); | ||
| 100 | seq_printf(s, "(%s version %x), ", | ||
| 101 | __sdb_string(tmp, r->synthesis.tool_name), | ||
| 102 | __be32_to_cpu(r->synthesis.tool_version)); | ||
| 103 | seq_printf(s, "commit %pm\n", | ||
| 104 | r->synthesis.commit_id); | ||
| 105 | break; | ||
| 106 | case sdb_type_empty: | ||
| 107 | seq_printf(s, "empty\n"); | ||
| 108 | break; | ||
| 109 | default: | ||
| 110 | seq_printf(s, "UNKNOWN TYPE 0x%02x\n", | ||
| 111 | r->empty.record_type); | ||
| 112 | break; | ||
| 113 | } | ||
| 114 | } | ||
| 115 | } | ||
| 116 | |||
| 117 | static int fmc_sdb_dump(struct seq_file *s, void *offset) | ||
| 118 | { | ||
| 119 | struct fmc_device *fmc = s->private; | ||
| 120 | |||
| 121 | if (!fmc->sdb) { | ||
| 122 | seq_printf(s, "no SDB information\n"); | ||
| 123 | return 0; | ||
| 124 | } | ||
| 125 | |||
| 126 | seq_printf(s, "FMC: %s (%s), slot %i, device %s\n", dev_name(fmc->hwdev), | ||
| 127 | fmc->carrier_name, fmc->slot_id, dev_name(&fmc->dev)); | ||
| 128 | /* Dump SDB information */ | ||
| 129 | fmc_sdb_dump_recursive(fmc, s, fmc->sdb); | ||
| 130 | |||
| 131 | return 0; | ||
| 132 | } | ||
| 133 | |||
| 134 | |||
| 135 | static int fmc_sdb_dump_open(struct inode *inode, struct file *file) | ||
| 136 | { | ||
| 137 | struct fmc_device *fmc = inode->i_private; | ||
| 138 | |||
| 139 | return single_open(file, fmc_sdb_dump, fmc); | ||
| 140 | } | ||
| 141 | |||
| 142 | |||
| 143 | const struct file_operations fmc_dbgfs_sdb_dump = { | ||
| 144 | .owner = THIS_MODULE, | ||
| 145 | .open = fmc_sdb_dump_open, | ||
| 146 | .read = seq_read, | ||
| 147 | .llseek = seq_lseek, | ||
| 148 | .release = single_release, | ||
| 149 | }; | ||
| 150 | |||
| 151 | int fmc_debug_init(struct fmc_device *fmc) | ||
| 152 | { | ||
| 153 | fmc->dbg_dir = debugfs_create_dir(dev_name(&fmc->dev), NULL); | ||
| 154 | if (IS_ERR_OR_NULL(fmc->dbg_dir)) { | ||
| 155 | pr_err("FMC: Cannot create debugfs\n"); | ||
| 156 | return PTR_ERR(fmc->dbg_dir); | ||
| 157 | } | ||
| 158 | |||
| 159 | fmc->dbg_sdb_dump = debugfs_create_file(FMC_DBG_SDB_DUMP, 0444, | ||
| 160 | fmc->dbg_dir, fmc, | ||
| 161 | &fmc_dbgfs_sdb_dump); | ||
| 162 | if (IS_ERR_OR_NULL(fmc->dbg_sdb_dump)) | ||
| 163 | pr_err("FMC: Cannot create debugfs file %s\n", | ||
| 164 | FMC_DBG_SDB_DUMP); | ||
| 165 | |||
| 166 | return 0; | ||
| 167 | } | ||
| 168 | |||
| 169 | void fmc_debug_exit(struct fmc_device *fmc) | ||
| 170 | { | ||
| 171 | if (fmc->dbg_dir) | ||
| 172 | debugfs_remove_recursive(fmc->dbg_dir); | ||
| 173 | } | ||
| @@ -15,8 +15,6 @@ · 14 unmodified lines | |||
| 15 | 15 | ||
| 16 | static int fmc_must_dump_eeprom; | 16 | static int fmc_must_dump_eeprom; |
| 17 | module_param_named(dump_eeprom, fmc_must_dump_eeprom, int, 0644); | 17 | module_param_named(dump_eeprom, fmc_must_dump_eeprom, int, 0644); |
| 18 | static int fmc_must_dump_sdb; | ||
| 19 | module_param_named(dump_sdb, fmc_must_dump_sdb, int, 0644); | ||
| 20 | 18 | ||
| 21 | #define LINELEN 16 | 19 | #define LINELEN 16 |
| 22 | 20 | ||
| @@ -59,42 +57,3 @@ void fmc_dump_eeprom(const struct fmc_device *fmc) · 36 unmodified lines | |||
| 59 | for (i = 0; i < fmc->eeprom_len; i += LINELEN, line += LINELEN) | 57 | for (i = 0; i < fmc->eeprom_len; i += LINELEN, line += LINELEN) |
| 60 | prev = dump_line(i, line, prev); | 58 | prev = dump_line(i, line, prev); |
| 61 | } | 59 | } |
| 62 | |||
| 63 | void fmc_dump_sdb(const struct fmc_device *fmc) | ||
| 64 | { | ||
| 65 | const uint8_t *line, *prev; | ||
| 66 | int i, len; | ||
| 67 | |||
| 68 | if (!fmc->sdb) | ||
| 69 | return; | ||
| 70 | if (!fmc_must_dump_sdb) | ||
| 71 | return; | ||
| 72 | |||
| 73 | /* If the argument is not-zero, do simple dump (== show) */ | ||
| 74 | if (fmc_must_dump_sdb > 0) | ||
| 75 | fmc_show_sdb_tree(fmc); | ||
| 76 | |||
| 77 | if (fmc_must_dump_sdb == 1) | ||
| 78 | return; | ||
| 79 | |||
| 80 | /* If bigger than 1, dump it seriously, to help debugging */ | ||
| 81 | |||
| 82 | /* | ||
| 83 | * Here we should really use libsdbfs (which is designed to | ||
| 84 | * work in kernel space as well) , but it doesn't support | ||
| 85 | * directories yet, and it requires better intergration (it | ||
| 86 | * should be used instead of fmc-specific code). | ||
| 87 | * | ||
| 88 | * So, lazily, just dump the top-level array | ||
| 89 | */ | ||
| 90 | pr_info("FMC: %s (%s), slot %i, device %s\n", dev_name(fmc->hwdev), | ||
| 91 | fmc->carrier_name, fmc->slot_id, dev_name(&fmc->dev)); | ||
| 92 | pr_info("FMC: poor dump of sdb first level:\n"); | ||
| 93 | |||
| 94 | len = fmc->sdb->len * sizeof(union sdb_record); | ||
| 95 | line = (void *)fmc->sdb->record; | ||
| 96 | prev = NULL; | ||
| 97 | for (i = 0; i < len; i += LINELEN, line += LINELEN) | ||
| 98 | prev = dump_line(i, line, prev); | ||
| 99 | return; | ||
| 100 | } | ||
| @@ -63,7 +63,7 @@ int fmc_fill_id_info(struct fmc_device *fmc) · 62 unmodified lines | |||
| 63 | if (!fmc->eeprom) | 63 | if (!fmc->eeprom) |
| 64 | return -ENOMEM; | 64 | return -ENOMEM; |
| 65 | allocated = 1; | 65 | allocated = 1; |
| 66 | ret = fmc->op->read_ee(fmc, 0, fmc->eeprom, fmc->eeprom_len); | 66 | ret = fmc_read_ee(fmc, 0, fmc->eeprom, fmc->eeprom_len); |
| 67 | if (ret < 0) | 67 | if (ret < 0) |
| 68 | goto out; | 68 | goto out; |
| 69 | } | 69 | } |
| @@ -0,0 +1,9 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2015 CERN (www.cern.ch) | ||
| 3 | * Author: Federico Vaga <federico.vaga@cern.ch> | ||
| 4 | * | ||
| 5 | * Released according to the GNU GPL, version 2 or any later version. | ||
| 6 | */ | ||
| 7 | |||
| 8 | extern int fmc_debug_init(struct fmc_device *fmc); | ||
| 9 | extern void fmc_debug_exit(struct fmc_device *fmc); | ||
| @@ -127,12 +127,12 @@ int fmc_free_sdb_tree(struct fmc_device *fmc) · 126 unmodified lines | |||
| 127 | EXPORT_SYMBOL(fmc_free_sdb_tree); | 127 | EXPORT_SYMBOL(fmc_free_sdb_tree); |
| 128 | 128 | ||
| 129 | /* This helper calls reprogram and inizialized sdb as well */ | 129 | /* This helper calls reprogram and inizialized sdb as well */ |
| 130 | int fmc_reprogram(struct fmc_device *fmc, struct fmc_driver *d, char *gw, | 130 | int fmc_reprogram_raw(struct fmc_device *fmc, struct fmc_driver *d, |
| 131 | int sdb_entry) | 131 | void *gw, unsigned long len, int sdb_entry) |
| 132 | { | 132 | { |
| 133 | int ret; | 133 | int ret; |
| 134 | 134 | ||
| 135 | ret = fmc->op->reprogram(fmc, d, gw); | 135 | ret = fmc->op->reprogram_raw(fmc, d, gw, len); |
| 136 | if (ret < 0) | 136 | if (ret < 0) |
| 137 | return ret; | 137 | return ret; |
| 138 | if (sdb_entry < 0) | 138 | if (sdb_entry < 0) |
| @@ -145,108 +145,39 @@ int fmc_reprogram(struct fmc_device *fmc, struct fmc_driver *d, char *gw, · 6 unmodified lines | |||
| 145 | sdb_entry); | 145 | sdb_entry); |
| 146 | return -ENODEV; | 146 | return -ENODEV; |
| 147 | } | 147 | } |
| 148 | fmc_dump_sdb(fmc); | ||
| 149 | return 0; | ||
| 150 | } | ||
| 151 | EXPORT_SYMBOL(fmc_reprogram); | ||
| 152 | |||
| 153 | static char *__strip_trailing_space(char *buf, char *str, int len) | ||
| 154 | { | ||
| 155 | int i = len - 1; | ||
| 156 | 148 | ||
| 157 | memcpy(buf, str, len); | 149 | return 0; |
| 158 | while(i >= 0 && buf[i] == ' ') | ||
| 159 | buf[i--] = '\0'; | ||
| 160 | return buf; | ||
| 161 | } | 150 | } |
| 151 | EXPORT_SYMBOL(fmc_reprogram_raw); | ||
| 162 | 152 | ||
| 163 | #define __sdb_string(buf, field) ({ \ | 153 | /* This helper calls reprogram and inizialized sdb as well */ |
| 164 | BUILD_BUG_ON(sizeof(buf) < sizeof(field)); \ | 154 | int fmc_reprogram(struct fmc_device *fmc, struct fmc_driver *d, char *gw, |
| 165 | __strip_trailing_space(buf, (void *)(field), sizeof(field)); \ | 155 | int sdb_entry) |
| 166 | }) | ||
| 167 | |||
| 168 | static void __fmc_show_sdb_tree(const struct fmc_device *fmc, | ||
| 169 | const struct sdb_array *arr) | ||
| 170 | { | 156 | { |
| 171 | unsigned long base = arr->baseaddr; | 157 | int ret; |
| 172 | int i, j, n = arr->len, level = arr->level; | ||
| 173 | char buf[64]; | ||
| 174 | |||
| 175 | for (i = 0; i < n; i++) { | ||
| 176 | union sdb_record *r; | ||
| 177 | struct sdb_product *p; | ||
| 178 | struct sdb_component *c; | ||
| 179 | r = &arr->record[i]; | ||
| 180 | c = &r->dev.sdb_component; | ||
| 181 | p = &c->product; | ||
| 182 | 158 | ||
| 183 | dev_info(&fmc->dev, "SDB: "); | 159 | ret = fmc->op->reprogram(fmc, d, gw); |
| 160 | if (ret < 0) | ||
| 161 | return ret; | ||
| 162 | if (sdb_entry < 0) | ||
| 163 | return ret; | ||
| 184 | 164 | ||
| 185 | for (j = 0; j < level; j++) | 165 | /* We are required to find SDB at a given offset */ |
| 186 | printk(KERN_CONT " "); | 166 | ret = fmc_scan_sdb_tree(fmc, sdb_entry); |
| 187 | switch (r->empty.record_type) { | 167 | if (ret < 0) { |
| 188 | case sdb_type_interconnect: | 168 | dev_err(&fmc->dev, "Can't find SDB at address 0x%x\n", |
| 189 | printk(KERN_CONT "%08llx:%08x %.19s\n", | 169 | sdb_entry); |
| 190 | __be64_to_cpu(p->vendor_id), | 170 | return -ENODEV; |
| 191 | __be32_to_cpu(p->device_id), | ||
| 192 | p->name); | ||
| 193 | break; | ||
| 194 | case sdb_type_device: | ||
| 195 | printk(KERN_CONT "%08llx:%08x %.19s (%08llx-%08llx)\n", | ||
| 196 | __be64_to_cpu(p->vendor_id), | ||
| 197 | __be32_to_cpu(p->device_id), | ||
| 198 | p->name, | ||
| 199 | __be64_to_cpu(c->addr_first) + base, | ||
| 200 | __be64_to_cpu(c->addr_last) + base); | ||
| 201 | break; | ||
| 202 | case sdb_type_bridge: | ||
| 203 | printk(KERN_CONT "%08llx:%08x %.19s (bridge: %08llx)\n", | ||
| 204 | __be64_to_cpu(p->vendor_id), | ||
| 205 | __be32_to_cpu(p->device_id), | ||
| 206 | p->name, | ||
| 207 | __be64_to_cpu(c->addr_first) + base); | ||
| 208 | if (IS_ERR(arr->subtree[i])) { | ||
| 209 | dev_info(&fmc->dev, "SDB: (bridge error %li)\n", | ||
| 210 | PTR_ERR(arr->subtree[i])); | ||
| 211 | break; | ||
| 212 | } | ||
| 213 | __fmc_show_sdb_tree(fmc, arr->subtree[i]); | ||
| 214 | break; | ||
| 215 | case sdb_type_integration: | ||
| 216 | printk(KERN_CONT "integration\n"); | ||
| 217 | break; | ||
| 218 | case sdb_type_repo_url: | ||
| 219 | printk(KERN_CONT "Synthesis repository: %s\n", | ||
| 220 | __sdb_string(buf, r->repo_url.repo_url)); | ||
| 221 | break; | ||
| 222 | case sdb_type_synthesis: | ||
| 223 | printk(KERN_CONT "Bitstream '%s' ", | ||
| 224 | __sdb_string(buf, r->synthesis.syn_name)); | ||
| 225 | printk(KERN_CONT "synthesized %08x by %s ", | ||
| 226 | __be32_to_cpu(r->synthesis.date), | ||
| 227 | __sdb_string(buf, r->synthesis.user_name)); | ||
| 228 | printk(KERN_CONT "(%s version %x), ", | ||
| 229 | __sdb_string(buf, r->synthesis.tool_name), | ||
| 230 | __be32_to_cpu(r->synthesis.tool_version)); | ||
| 231 | printk(KERN_CONT "commit %pm\n", | ||
| 232 | r->synthesis.commit_id); | ||
| 233 | break; | ||
| 234 | case sdb_type_empty: | ||
| 235 | printk(KERN_CONT "empty\n"); | ||
| 236 | break; | ||
| 237 | default: | ||
| 238 | printk(KERN_CONT "UNKNOWN TYPE 0x%02x\n", | ||
| 239 | r->empty.record_type); | ||
| 240 | break; | ||
| 241 | } | ||
| 242 | } | 171 | } |
| 172 | |||
| 173 | return 0; | ||
| 243 | } | 174 | } |
| 175 | EXPORT_SYMBOL(fmc_reprogram); | ||
| 244 | 176 | ||
| 245 | void fmc_show_sdb_tree(const struct fmc_device *fmc) | 177 | void fmc_show_sdb_tree(const struct fmc_device *fmc) |
| 246 | { | 178 | { |
| 247 | if (!fmc->sdb) | 179 | pr_err("%s: not supported anymore, use debugfs to dump SDB\n", |
| 248 | return; | 180 | __func__); |
| 249 | __fmc_show_sdb_tree(fmc, fmc->sdb); | ||
| 250 | } | 181 | } |
| 251 | EXPORT_SYMBOL(fmc_show_sdb_tree); | 182 | EXPORT_SYMBOL(fmc_show_sdb_tree); |
| 252 | 183 | ||
| @@ -24,7 +24,7 @@ static irqreturn_t t_handler(int irq, void *dev_id) · 23 unmodified lines | |||
| 24 | { | 24 | { |
| 25 | struct fmc_device *fmc = dev_id; | 25 | struct fmc_device *fmc = dev_id; |
| 26 | 26 | ||
| 27 | fmc->op->irq_ack(fmc); | 27 | fmc_irq_ack(fmc); |
| 28 | dev_info(&fmc->dev, "received irq %i\n", irq); | 28 | dev_info(&fmc->dev, "received irq %i\n", irq); |
| 29 | return IRQ_HANDLED; | 29 | return IRQ_HANDLED; |
| 30 | } | 30 | } |
| @@ -46,25 +46,21 @@ static int t_probe(struct fmc_device *fmc) · 15 unmodified lines | |||
| 46 | int ret; | 46 | int ret; |
| 47 | int index = 0; | 47 | int index = 0; |
| 48 | 48 | ||
| 49 | if (fmc->op->validate) | 49 | index = fmc_validate(fmc, &t_drv); |
| 50 | index = fmc->op->validate(fmc, &t_drv); | ||
| 51 | if (index < 0) | 50 | if (index < 0) |
| 52 | return -EINVAL; /* not our device: invalid */ | 51 | return -EINVAL; /* not our device: invalid */ |
| 53 | 52 | ||
| 54 | ret = fmc->op->irq_request(fmc, t_handler, "fmc-trivial", IRQF_SHARED); | 53 | ret = fmc_irq_request(fmc, t_handler, "fmc-trivial", IRQF_SHARED); |
| 55 | if (ret < 0) | 54 | if (ret < 0) |
| 56 | return ret; | 55 | return ret; |
| 57 | /* ignore error code of call below, we really don't care */ | 56 | /* ignore error code of call below, we really don't care */ |
| 58 | fmc->op->gpio_config(fmc, t_gpio, ARRAY_SIZE(t_gpio)); | 57 | fmc_gpio_config(fmc, t_gpio, ARRAY_SIZE(t_gpio)); |
| 59 | 58 | ||
| 60 | /* Reprogram, if asked to. ESRCH == no filename specified */ | 59 | ret = fmc_reprogram(fmc, &t_drv, "", 0); |
| 61 | ret = -ESRCH; | 60 | if (ret == -EPERM) /* programming not supported */ |
| 62 | if (fmc->op->reprogram) | ||
| 63 | ret = fmc->op->reprogram(fmc, &t_drv, ""); | ||
| 64 | if (ret == -ESRCH) | ||
| 65 | ret = 0; | 61 | ret = 0; |
| 66 | if (ret < 0) | 62 | if (ret < 0) |
| 67 | fmc->op->irq_free(fmc); | 63 | fmc_irq_free(fmc); |
| 68 | 64 | ||
| 69 | /* FIXME: reprogram LM32 too */ | 65 | /* FIXME: reprogram LM32 too */ |
| 70 | return ret; | 66 | return ret; |
| @@ -72,7 +68,7 @@ static int t_probe(struct fmc_device *fmc) · 1 unmodified line | |||
| 72 | 68 | ||
| 73 | static int t_remove(struct fmc_device *fmc) | 69 | static int t_remove(struct fmc_device *fmc) |
| 74 | { | 70 | { |
| 75 | fmc->op->irq_free(fmc); | 71 | fmc_irq_free(fmc); |
| 76 | return 0; | 72 | return 0; |
| 77 | } | 73 | } |
| 78 | 74 | ||
| @@ -50,7 +50,7 @@ static int fwe_run_tlv(struct fmc_device *fmc, const struct firmware *fw, · 49 unmodified lines | |||
| 50 | if (write) { | 50 | if (write) { |
| 51 | dev_info(&fmc->dev, "write %i bytes at 0x%04x\n", | 51 | dev_info(&fmc->dev, "write %i bytes at 0x%04x\n", |
| 52 | thislen, thisaddr); | 52 | thislen, thisaddr); |
| 53 | err = fmc->op->write_ee(fmc, thisaddr, p + 5, thislen); | 53 | err = fmc_write_ee(fmc, thisaddr, p + 5, thislen); |
| 54 | } | 54 | } |
| 55 | if (err < 0) { | 55 | if (err < 0) { |
| 56 | dev_err(&fmc->dev, "write failure @0x%04x\n", | 56 | dev_err(&fmc->dev, "write failure @0x%04x\n", |
| @@ -70,7 +70,7 @@ static int fwe_run_bin(struct fmc_device *fmc, const struct firmware *fw) · 13 unmodified lines | |||
| 70 | int ret; | 70 | int ret; |
| 71 | 71 | ||
| 72 | dev_info(&fmc->dev, "programming %zi bytes\n", fw->size); | 72 | dev_info(&fmc->dev, "programming %zi bytes\n", fw->size); |
| 73 | ret = fmc->op->write_ee(fmc, 0, (void *)fw->data, fw->size); | 73 | ret = fmc_write_ee(fmc, 0, (void *)fw->data, fw->size); |
| 74 | if (ret < 0) { | 74 | if (ret < 0) { |
| 75 | dev_info(&fmc->dev, "write_eeprom: error %i\n", ret); | 75 | dev_info(&fmc->dev, "write_eeprom: error %i\n", ret); |
| 76 | return ret; | 76 | return ret; |
| @@ -115,8 +115,8 @@ static int fwe_probe(struct fmc_device *fmc) · 38 unmodified lines | |||
| 115 | KBUILD_MODNAME); | 115 | KBUILD_MODNAME); |
| 116 | return -ENODEV; | 116 | return -ENODEV; |
| 117 | } | 117 | } |
| 118 | if (fmc->op->validate) | 118 | |
| 119 | index = fmc->op->validate(fmc, &fwe_drv); | 119 | index = fmc_validate(fmc, &fwe_drv); |
| 120 | if (index < 0) { | 120 | if (index < 0) { |
| 121 | pr_err("%s: refusing device \"%s\"\n", KBUILD_MODNAME, | 121 | pr_err("%s: refusing device \"%s\"\n", KBUILD_MODNAME, |
| 122 | dev_name(dev)); | 122 | dev_name(dev)); |
| @@ -31,12 +31,11 @@ static char *__fru_alloc_get_tl(struct fru_common_header *header, int nr) · 30 unmodified lines | |||
| 31 | { | 31 | { |
| 32 | struct fru_type_length *tl; | 32 | struct fru_type_length *tl; |
| 33 | char *res; | 33 | char *res; |
| 34 | int len; | ||
| 35 | 34 | ||
| 36 | tl = __fru_get_board_tl(header, nr); | 35 | tl = __fru_get_board_tl(header, nr); |
| 37 | if (!tl) | 36 | if (!tl) |
| 38 | return NULL; | 37 | return NULL; |
| 39 | len = fru_strlen(tl); | 38 | |
| 40 | res = fru_alloc(fru_strlen(tl) + 1); | 39 | res = fru_alloc(fru_strlen(tl) + 1); |
| 41 | if (!res) | 40 | if (!res) |
| 42 | return NULL; | 41 | return NULL; |
| @@ -2,9 +2,7 @@ · 1 unmodified line | |||
| 2 | # FPGA framework configuration | 2 | # FPGA framework configuration |
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | menu "FPGA Configuration Support" | 5 | menuconfig FPGA |
| 6 | |||
| 7 | config FPGA | ||
| 8 | tristate "FPGA Configuration Framework" | 6 | tristate "FPGA Configuration Framework" |
| 9 | help | 7 | help |
| 10 | Say Y here if you want support for configuring FPGAs from the | 8 | Say Y here if you want support for configuring FPGAs from the |
| @@ -26,6 +24,20 @@ config FPGA_MGR_ICE40_SPI · 15 unmodified lines | |||
| 26 | help | 24 | help |
| 27 | FPGA manager driver support for Lattice iCE40 FPGAs over SPI. | 25 | FPGA manager driver support for Lattice iCE40 FPGAs over SPI. |
| 28 | 26 | ||
| 27 | config FPGA_MGR_ALTERA_CVP | ||
| 28 | tristate "Altera Arria-V/Cyclone-V/Stratix-V CvP FPGA Manager" | ||
| 29 | depends on PCI | ||
| 30 | help | ||
| 31 | FPGA manager driver support for Arria-V, Cyclone-V, Stratix-V | ||
| 32 | and Arria 10 Altera FPGAs using the CvP interface over PCIe. | ||
| 33 | |||
| 34 | config FPGA_MGR_ALTERA_PS_SPI | ||
| 35 | tristate "Altera FPGA Passive Serial over SPI" | ||
| 36 | depends on SPI | ||
| 37 | help | ||
| 38 | FPGA manager driver support for Altera Arria/Cyclone/Stratix | ||
| 39 | using the passive serial interface over SPI. | ||
| 40 | |||
| 29 | config FPGA_MGR_SOCFPGA | 41 | config FPGA_MGR_SOCFPGA |
| 30 | tristate "Altera SOCFPGA FPGA Manager" | 42 | tristate "Altera SOCFPGA FPGA Manager" |
| 31 | depends on ARCH_SOCFPGA || COMPILE_TEST | 43 | depends on ARCH_SOCFPGA || COMPILE_TEST |
| @@ -106,5 +118,3 @@ config XILINX_PR_DECOUPLER · 74 unmodified lines | |||
| 106 | being reprogrammed during partial reconfig. | 118 | being reprogrammed during partial reconfig. |
| 107 | 119 | ||
| 108 | endif # FPGA | 120 | endif # FPGA |
| 109 | |||
| 110 | endmenu | ||
| @@ -6,6 +6,8 @@ · 5 unmodified lines | |||
| 6 | obj-$(CONFIG_FPGA) += fpga-mgr.o | 6 | obj-$(CONFIG_FPGA) += fpga-mgr.o |
| 7 | 7 | ||
| 8 | # FPGA Manager Drivers | 8 | # FPGA Manager Drivers |
| 9 | obj-$(CONFIG_FPGA_MGR_ALTERA_CVP) += altera-cvp.o | ||
| 10 | obj-$(CONFIG_FPGA_MGR_ALTERA_PS_SPI) += altera-ps-spi.o | ||
| 9 | obj-$(CONFIG_FPGA_MGR_ICE40_SPI) += ice40-spi.o | 11 | obj-$(CONFIG_FPGA_MGR_ICE40_SPI) += ice40-spi.o |
| 10 | obj-$(CONFIG_FPGA_MGR_SOCFPGA) += socfpga.o | 12 | obj-$(CONFIG_FPGA_MGR_SOCFPGA) += socfpga.o |
| 11 | obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10) += socfpga-a10.o | 13 | obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10) += socfpga-a10.o |
| @@ -0,0 +1,500 @@ | |||
| 1 | /* | ||
| 2 | * FPGA Manager Driver for Altera Arria/Cyclone/Stratix CvP | ||
| 3 | * | ||
| 4 | * Copyright (C) 2017 DENX Software Engineering | ||
| 5 | * | ||
| 6 | * Anatolij Gustschin <agust@denx.de> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; version 2 of the License. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * Manage Altera FPGA firmware using PCIe CvP. | ||
| 18 | * Firmware must be in binary "rbf" format. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <linux/delay.h> | ||
| 22 | #include <linux/device.h> | ||
| 23 | #include <linux/fpga/fpga-mgr.h> | ||
| 24 | #include <linux/module.h> | ||
| 25 | #include <linux/pci.h> | ||
| 26 | #include <linux/sizes.h> | ||
| 27 | |||
| 28 | #define CVP_BAR 0 /* BAR used for data transfer in memory mode */ | ||
| 29 | #define CVP_DUMMY_WR 244 /* dummy writes to clear CvP state machine */ | ||
| 30 | #define TIMEOUT_US 2000 /* CVP STATUS timeout for USERMODE polling */ | ||
| 31 | |||
| 32 | /* Vendor Specific Extended Capability Registers */ | ||
| 33 | #define VSE_PCIE_EXT_CAP_ID 0x200 | ||
| 34 | #define VSE_PCIE_EXT_CAP_ID_VAL 0x000b /* 16bit */ | ||
| 35 | |||
| 36 | #define VSE_CVP_STATUS 0x21c /* 32bit */ | ||
| 37 | #define VSE_CVP_STATUS_CFG_RDY BIT(18) /* CVP_CONFIG_READY */ | ||
| 38 | #define VSE_CVP_STATUS_CFG_ERR BIT(19) /* CVP_CONFIG_ERROR */ | ||
| 39 | #define VSE_CVP_STATUS_CVP_EN BIT(20) /* ctrl block is enabling CVP */ | ||
| 40 | #define VSE_CVP_STATUS_USERMODE BIT(21) /* USERMODE */ | ||
| 41 | #define VSE_CVP_STATUS_CFG_DONE BIT(23) /* CVP_CONFIG_DONE */ | ||
| 42 | #define VSE_CVP_STATUS_PLD_CLK_IN_USE BIT(24) /* PLD_CLK_IN_USE */ | ||
| 43 | |||
| 44 | #define VSE_CVP_MODE_CTRL 0x220 /* 32bit */ | ||
| 45 | #define VSE_CVP_MODE_CTRL_CVP_MODE BIT(0) /* CVP (1) or normal mode (0) */ | ||
| 46 | #define VSE_CVP_MODE_CTRL_HIP_CLK_SEL BIT(1) /* PMA (1) or fabric clock (0) */ | ||
| 47 | #define VSE_CVP_MODE_CTRL_NUMCLKS_OFF 8 /* NUMCLKS bits offset */ | ||
| 48 | #define VSE_CVP_MODE_CTRL_NUMCLKS_MASK GENMASK(15, 8) | ||
| 49 | |||
| 50 | #define VSE_CVP_DATA 0x228 /* 32bit */ | ||
| 51 | #define VSE_CVP_PROG_CTRL 0x22c /* 32bit */ | ||
| 52 | #define VSE_CVP_PROG_CTRL_CONFIG BIT(0) | ||
| 53 | #define VSE_CVP_PROG_CTRL_START_XFER BIT(1) | ||
| 54 | |||
| 55 | #define VSE_UNCOR_ERR_STATUS 0x234 /* 32bit */ | ||
| 56 | #define VSE_UNCOR_ERR_CVP_CFG_ERR BIT(5) /* CVP_CONFIG_ERROR_LATCHED */ | ||
| 57 | |||
| 58 | #define DRV_NAME "altera-cvp" | ||
| 59 | #define ALTERA_CVP_MGR_NAME "Altera CvP FPGA Manager" | ||
| 60 | |||
| 61 | /* Optional CvP config error status check for debugging */ | ||
| 62 | static bool altera_cvp_chkcfg; | ||
| 63 | |||
| 64 | struct altera_cvp_conf { | ||
| 65 | struct fpga_manager *mgr; | ||
| 66 | struct pci_dev *pci_dev; | ||
| 67 | void __iomem *map; | ||
| 68 | void (*write_data)(struct altera_cvp_conf *, u32); | ||
| 69 | char mgr_name[64]; | ||
| 70 | u8 numclks; | ||
| 71 | }; | ||
| 72 | |||
| 73 | static enum fpga_mgr_states altera_cvp_state(struct fpga_manager *mgr) | ||
| 74 | { | ||
| 75 | struct altera_cvp_conf *conf = mgr->priv; | ||
| 76 | u32 status; | ||
| 77 | |||
| 78 | pci_read_config_dword(conf->pci_dev, VSE_CVP_STATUS, &status); | ||
| 79 | |||
| 80 | if (status & VSE_CVP_STATUS_CFG_DONE) | ||
| 81 | return FPGA_MGR_STATE_OPERATING; | ||
| 82 | |||
| 83 | if (status & VSE_CVP_STATUS_CVP_EN) | ||
| 84 | return FPGA_MGR_STATE_POWER_UP; | ||
| 85 | |||
| 86 | return FPGA_MGR_STATE_UNKNOWN; | ||
| 87 | } | ||
| 88 | |||
| 89 | static void altera_cvp_write_data_iomem(struct altera_cvp_conf *conf, u32 val) | ||
| 90 | { | ||
| 91 | writel(val, conf->map); | ||
| 92 | } | ||
| 93 | |||
| 94 | static void altera_cvp_write_data_config(struct altera_cvp_conf *conf, u32 val) | ||
| 95 | { | ||
| 96 | pci_write_config_dword(conf->pci_dev, VSE_CVP_DATA, val); | ||
| 97 | } | ||
| 98 | |||
| 99 | /* switches between CvP clock and internal clock */ | ||
| 100 | static void altera_cvp_dummy_write(struct altera_cvp_conf *conf) | ||
| 101 | { | ||
| 102 | unsigned int i; | ||
| 103 | u32 val; | ||
| 104 | |||
| 105 | /* set 1 CVP clock cycle for every CVP Data Register Write */ | ||
| 106 | pci_read_config_dword(conf->pci_dev, VSE_CVP_MODE_CTRL, &val); | ||
| 107 | val &= ~VSE_CVP_MODE_CTRL_NUMCLKS_MASK; | ||
| 108 | val |= 1 << VSE_CVP_MODE_CTRL_NUMCLKS_OFF; | ||
| 109 | pci_write_config_dword(conf->pci_dev, VSE_CVP_MODE_CTRL, val); | ||
| 110 | |||
| 111 | for (i = 0; i < CVP_DUMMY_WR; i++) | ||
| 112 | conf->write_data(conf, 0); /* dummy data, could be any value */ | ||
| 113 | } | ||
| 114 | |||
| 115 | static int altera_cvp_wait_status(struct altera_cvp_conf *conf, u32 status_mask, | ||
| 116 | u32 status_val, int timeout_us) | ||
| 117 | { | ||
| 118 | unsigned int retries; | ||
| 119 | u32 val; | ||
| 120 | |||
| 121 | retries = timeout_us / 10; | ||
| 122 | if (timeout_us % 10) | ||
| 123 | retries++; | ||
| 124 | |||
| 125 | do { | ||
| 126 | pci_read_config_dword(conf->pci_dev, VSE_CVP_STATUS, &val); | ||
| 127 | if ((val & status_mask) == status_val) | ||
| 128 | return 0; | ||
| 129 | |||
| 130 | /* use small usleep value to re-check and break early */ | ||
| 131 | usleep_range(10, 11); | ||
| 132 | } while (--retries); | ||
| 133 | |||
| 134 | return -ETIMEDOUT; | ||
| 135 | } | ||
| 136 | |||
| 137 | static int altera_cvp_teardown(struct fpga_manager *mgr, | ||
| 138 | struct fpga_image_info *info) | ||
| 139 | { | ||
| 140 | struct altera_cvp_conf *conf = mgr->priv; | ||
| 141 | struct pci_dev *pdev = conf->pci_dev; | ||
| 142 | int ret; | ||
| 143 | u32 val; | ||
| 144 | |||
| 145 | /* STEP 12 - reset START_XFER bit */ | ||
| 146 | pci_read_config_dword(pdev, VSE_CVP_PROG_CTRL, &val); | ||
| 147 | val &= ~VSE_CVP_PROG_CTRL_START_XFER; | ||
| 148 | pci_write_config_dword(pdev, VSE_CVP_PROG_CTRL, val); | ||
| 149 | |||
| 150 | /* STEP 13 - reset CVP_CONFIG bit */ | ||
| 151 | val &= ~VSE_CVP_PROG_CTRL_CONFIG; | ||
| 152 | pci_write_config_dword(pdev, VSE_CVP_PROG_CTRL, val); | ||
| 153 | |||
| 154 | /* | ||
| 155 | * STEP 14 | ||
| 156 | * - set CVP_NUMCLKS to 1 and then issue CVP_DUMMY_WR dummy | ||
| 157 | * writes to the HIP | ||
| 158 | */ | ||
| 159 | altera_cvp_dummy_write(conf); /* from CVP clock to internal clock */ | ||
| 160 | |||
| 161 | /* STEP 15 - poll CVP_CONFIG_READY bit for 0 with 10us timeout */ | ||
| 162 | ret = altera_cvp_wait_status(conf, VSE_CVP_STATUS_CFG_RDY, 0, 10); | ||
| 163 | if (ret) | ||
| 164 | dev_err(&mgr->dev, "CFG_RDY == 0 timeout\n"); | ||
| 165 | |||
| 166 | return ret; | ||
| 167 | } | ||
| 168 | |||
| 169 | static int altera_cvp_write_init(struct fpga_manager *mgr, | ||
| 170 | struct fpga_image_info *info, | ||
| 171 | const char *buf, size_t count) | ||
| 172 | { | ||
| 173 | struct altera_cvp_conf *conf = mgr->priv; | ||
| 174 | struct pci_dev *pdev = conf->pci_dev; | ||
| 175 | u32 iflags, val; | ||
| 176 | int ret; | ||
| 177 | |||
| 178 | iflags = info ? info->flags : 0; | ||
| 179 | |||
| 180 | if (iflags & FPGA_MGR_PARTIAL_RECONFIG) { | ||
| 181 | dev_err(&mgr->dev, "Partial reconfiguration not supported.\n"); | ||
| 182 | return -EINVAL; | ||
| 183 | } | ||
| 184 | |||
| 185 | /* Determine allowed clock to data ratio */ | ||
| 186 | if (iflags & FPGA_MGR_COMPRESSED_BITSTREAM) | ||
| 187 | conf->numclks = 8; /* ratio for all compressed images */ | ||
| 188 | else if (iflags & FPGA_MGR_ENCRYPTED_BITSTREAM) | ||
| 189 | conf->numclks = 4; /* for uncompressed and encrypted images */ | ||
| 190 | else | ||
| 191 | conf->numclks = 1; /* for uncompressed and unencrypted images */ | ||
| 192 | |||
| 193 | /* STEP 1 - read CVP status and check CVP_EN flag */ | ||
| 194 | pci_read_config_dword(pdev, VSE_CVP_STATUS, &val); | ||
| 195 | if (!(val & VSE_CVP_STATUS_CVP_EN)) { | ||
| 196 | dev_err(&mgr->dev, "CVP mode off: 0x%04x\n", val); | ||
| 197 | return -ENODEV; | ||
| 198 | } | ||
| 199 | |||
| 200 | if (val & VSE_CVP_STATUS_CFG_RDY) { | ||
| 201 | dev_warn(&mgr->dev, "CvP already started, teardown first\n"); | ||
| 202 | ret = altera_cvp_teardown(mgr, info); | ||
| 203 | if (ret) | ||
| 204 | return ret; | ||
| 205 | } | ||
| 206 | |||
| 207 | /* | ||
| 208 | * STEP 2 | ||
| 209 | * - set HIP_CLK_SEL and CVP_MODE (must be set in the order mentioned) | ||
| 210 | */ | ||
| 211 | /* switch from fabric to PMA clock */ | ||
| 212 | pci_read_config_dword(pdev, VSE_CVP_MODE_CTRL, &val); | ||
| 213 | val |= VSE_CVP_MODE_CTRL_HIP_CLK_SEL; | ||
| 214 | pci_write_config_dword(pdev, VSE_CVP_MODE_CTRL, val); | ||
| 215 | |||
| 216 | /* set CVP mode */ | ||
| 217 | pci_read_config_dword(pdev, VSE_CVP_MODE_CTRL, &val); | ||
| 218 | val |= VSE_CVP_MODE_CTRL_CVP_MODE; | ||
| 219 | pci_write_config_dword(pdev, VSE_CVP_MODE_CTRL, val); | ||
| 220 | |||
| 221 | /* | ||
| 222 | * STEP 3 | ||
| 223 | * - set CVP_NUMCLKS to 1 and issue CVP_DUMMY_WR dummy writes to the HIP | ||
| 224 | */ | ||
| 225 | altera_cvp_dummy_write(conf); | ||
| 226 | |||
| 227 | /* STEP 4 - set CVP_CONFIG bit */ | ||
| 228 | pci_read_config_dword(pdev, VSE_CVP_PROG_CTRL, &val); | ||
| 229 | /* request control block to begin transfer using CVP */ | ||
| 230 | val |= VSE_CVP_PROG_CTRL_CONFIG; | ||
| 231 | pci_write_config_dword(pdev, VSE_CVP_PROG_CTRL, val); | ||
| 232 | |||
| 233 | /* STEP 5 - poll CVP_CONFIG READY for 1 with 10us timeout */ | ||
| 234 | ret = altera_cvp_wait_status(conf, VSE_CVP_STATUS_CFG_RDY, | ||
| 235 | VSE_CVP_STATUS_CFG_RDY, 10); | ||
| 236 | if (ret) { | ||
| 237 | dev_warn(&mgr->dev, "CFG_RDY == 1 timeout\n"); | ||
| 238 | return ret; | ||
| 239 | } | ||
| 240 | |||
| 241 | /* | ||
| 242 | * STEP 6 | ||
| 243 | * - set CVP_NUMCLKS to 1 and issue CVP_DUMMY_WR dummy writes to the HIP | ||
| 244 | */ | ||
| 245 | altera_cvp_dummy_write(conf); | ||
| 246 | |||
| 247 | /* STEP 7 - set START_XFER */ | ||
| 248 | pci_read_config_dword(pdev, VSE_CVP_PROG_CTRL, &val); | ||
| 249 | val |= VSE_CVP_PROG_CTRL_START_XFER; | ||
| 250 | pci_write_config_dword(pdev, VSE_CVP_PROG_CTRL, val); | ||
| 251 | |||
| 252 | /* STEP 8 - start transfer (set CVP_NUMCLKS for bitstream) */ | ||
| 253 | pci_read_config_dword(pdev, VSE_CVP_MODE_CTRL, &val); | ||
| 254 | val &= ~VSE_CVP_MODE_CTRL_NUMCLKS_MASK; | ||
| 255 | val |= conf->numclks << VSE_CVP_MODE_CTRL_NUMCLKS_OFF; | ||
| 256 | pci_write_config_dword(pdev, VSE_CVP_MODE_CTRL, val); | ||
| 257 | |||
| 258 | return 0; | ||
| 259 | } | ||
| 260 | |||
| 261 | static inline int altera_cvp_chk_error(struct fpga_manager *mgr, size_t bytes) | ||
| 262 | { | ||
| 263 | struct altera_cvp_conf *conf = mgr->priv; | ||
| 264 | u32 val; | ||
| 265 | |||
| 266 | /* STEP 10 (optional) - check CVP_CONFIG_ERROR flag */ | ||
| 267 | pci_read_config_dword(conf->pci_dev, VSE_CVP_STATUS, &val); | ||
| 268 | if (val & VSE_CVP_STATUS_CFG_ERR) { | ||
| 269 | dev_err(&mgr->dev, "CVP_CONFIG_ERROR after %zu bytes!\n", | ||
| 270 | bytes); | ||
| 271 | return -EPROTO; | ||
| 272 | } | ||
| 273 | return 0; | ||
| 274 | } | ||
| 275 | |||
| 276 | static int altera_cvp_write(struct fpga_manager *mgr, const char *buf, | ||
| 277 | size_t count) | ||
| 278 | { | ||
| 279 | struct altera_cvp_conf *conf = mgr->priv; | ||
| 280 | const u32 *data; | ||
| 281 | size_t done, remaining; | ||
| 282 | int status = 0; | ||
| 283 | u32 mask; | ||
| 284 | |||
| 285 | /* STEP 9 - write 32-bit data from RBF file to CVP data register */ | ||
| 286 | data = (u32 *)buf; | ||
| 287 | remaining = count; | ||
| 288 | done = 0; | ||
| 289 | |||
| 290 | while (remaining >= 4) { | ||
| 291 | conf->write_data(conf, *data++); | ||
| 292 | done += 4; | ||
| 293 | remaining -= 4; | ||
| 294 | |||
| 295 | /* | ||
| 296 | * STEP 10 (optional) and STEP 11 | ||
| 297 | * - check error flag | ||
| 298 | * - loop until data transfer completed | ||
| 299 | * Config images can be huge (more than 40 MiB), so | ||
| 300 | * only check after a new 4k data block has been written. | ||
| 301 | * This reduces the number of checks and speeds up the | ||
| 302 | * configuration process. | ||
| 303 | */ | ||
| 304 | if (altera_cvp_chkcfg && !(done % SZ_4K)) { | ||
| 305 | status = altera_cvp_chk_error(mgr, done); | ||
| 306 | if (status < 0) | ||
| 307 | return status; | ||
| 308 | } | ||
| 309 | } | ||
| 310 | |||
| 311 | /* write up to 3 trailing bytes, if any */ | ||
| 312 | mask = BIT(remaining * 8) - 1; | ||
| 313 | if (mask) | ||
| 314 | conf->write_data(conf, *data & mask); | ||
| 315 | |||
| 316 | if (altera_cvp_chkcfg) | ||
| 317 | status = altera_cvp_chk_error(mgr, count); | ||
| 318 | |||
| 319 | return status; | ||
| 320 | } | ||
| 321 | |||
| 322 | static int altera_cvp_write_complete(struct fpga_manager *mgr, | ||
| 323 | struct fpga_image_info *info) | ||
| 324 | { | ||
| 325 | struct altera_cvp_conf *conf = mgr->priv; | ||
| 326 | struct pci_dev *pdev = conf->pci_dev; | ||
| 327 | int ret; | ||
| 328 | u32 mask; | ||
| 329 | u32 val; | ||
| 330 | |||
| 331 | ret = altera_cvp_teardown(mgr, info); | ||
| 332 | if (ret) | ||
| 333 | return ret; | ||
| 334 | |||
| 335 | /* STEP 16 - check CVP_CONFIG_ERROR_LATCHED bit */ | ||
| 336 | pci_read_config_dword(pdev, VSE_UNCOR_ERR_STATUS, &val); | ||
| 337 | if (val & VSE_UNCOR_ERR_CVP_CFG_ERR) { | ||
| 338 | dev_err(&mgr->dev, "detected CVP_CONFIG_ERROR_LATCHED!\n"); | ||
| 339 | return -EPROTO; | ||
| 340 | } | ||
| 341 | |||
| 342 | /* STEP 17 - reset CVP_MODE and HIP_CLK_SEL bit */ | ||
| 343 | pci_read_config_dword(pdev, VSE_CVP_MODE_CTRL, &val); | ||
| 344 | val &= ~VSE_CVP_MODE_CTRL_HIP_CLK_SEL; | ||
| 345 | val &= ~VSE_CVP_MODE_CTRL_CVP_MODE; | ||
| 346 | pci_write_config_dword(pdev, VSE_CVP_MODE_CTRL, val); | ||
| 347 | |||
| 348 | /* STEP 18 - poll PLD_CLK_IN_USE and USER_MODE bits */ | ||
| 349 | mask = VSE_CVP_STATUS_PLD_CLK_IN_USE | VSE_CVP_STATUS_USERMODE; | ||
| 350 | ret = altera_cvp_wait_status(conf, mask, mask, TIMEOUT_US); | ||
| 351 | if (ret) | ||
| 352 | dev_err(&mgr->dev, "PLD_CLK_IN_USE|USERMODE timeout\n"); | ||
| 353 | |||
| 354 | return ret; | ||
| 355 | } | ||
| 356 | |||
| 357 | static const struct fpga_manager_ops altera_cvp_ops = { | ||
| 358 | .state = altera_cvp_state, | ||
| 359 | .write_init = altera_cvp_write_init, | ||
| 360 | .write = altera_cvp_write, | ||
| 361 | .write_complete = altera_cvp_write_complete, | ||
| 362 | }; | ||
| 363 | |||
| 364 | static ssize_t show_chkcfg(struct device_driver *dev, char *buf) | ||
| 365 | { | ||
| 366 | return snprintf(buf, 3, "%d\n", altera_cvp_chkcfg); | ||
| 367 | } | ||
| 368 | |||
| 369 | static ssize_t store_chkcfg(struct device_driver *drv, const char *buf, | ||
| 370 | size_t count) | ||
| 371 | { | ||
| 372 | int ret; | ||
| 373 | |||
| 374 | ret = kstrtobool(buf, &altera_cvp_chkcfg); | ||
| 375 | if (ret) | ||
| 376 | return ret; | ||
| 377 | |||
| 378 | return count; | ||
| 379 | } | ||
| 380 | |||
| 381 | static DRIVER_ATTR(chkcfg, 0600, show_chkcfg, store_chkcfg); | ||
| 382 | |||
| 383 | static int altera_cvp_probe(struct pci_dev *pdev, | ||
| 384 | const struct pci_device_id *dev_id); | ||
| 385 | static void altera_cvp_remove(struct pci_dev *pdev); | ||
| 386 | |||
| 387 | #define PCI_VENDOR_ID_ALTERA 0x1172 | ||
| 388 | |||
| 389 | static struct pci_device_id altera_cvp_id_tbl[] = { | ||
| 390 | { PCI_VDEVICE(ALTERA, PCI_ANY_ID) }, | ||
| 391 | { } | ||
| 392 | }; | ||
| 393 | MODULE_DEVICE_TABLE(pci, altera_cvp_id_tbl); | ||
| 394 | |||
| 395 | static struct pci_driver altera_cvp_driver = { | ||
| 396 | .name = DRV_NAME, | ||
| 397 | .id_table = altera_cvp_id_tbl, | ||
| 398 | .probe = altera_cvp_probe, | ||
| 399 | .remove = altera_cvp_remove, | ||
| 400 | }; | ||
| 401 | |||
| 402 | static int altera_cvp_probe(struct pci_dev *pdev, | ||
| 403 | const struct pci_device_id *dev_id) | ||
| 404 | { | ||
| 405 | struct altera_cvp_conf *conf; | ||
| 406 | u16 cmd, val; | ||
| 407 | int ret; | ||
| 408 | |||
| 409 | /* | ||
| 410 | * First check if this is the expected FPGA device. PCI config | ||
| 411 | * space access works without enabling the PCI device, memory | ||
| 412 | * space access is enabled further down. | ||
| 413 | */ | ||
| 414 | pci_read_config_word(pdev, VSE_PCIE_EXT_CAP_ID, &val); | ||
| 415 | if (val != VSE_PCIE_EXT_CAP_ID_VAL) { | ||
| 416 | dev_err(&pdev->dev, "Wrong EXT_CAP_ID value 0x%x\n", val); | ||
| 417 | return -ENODEV; | ||
| 418 | } | ||
| 419 | |||
| 420 | conf = devm_kzalloc(&pdev->dev, sizeof(*conf), GFP_KERNEL); | ||
| 421 | if (!conf) | ||
| 422 | return -ENOMEM; | ||
| 423 | |||
| 424 | /* | ||
| 425 | * Enable memory BAR access. We cannot use pci_enable_device() here | ||
| 426 | * because it will make the driver unusable with FPGA devices that | ||
| 427 | * have additional big IOMEM resources (e.g. 4GiB BARs) on 32-bit | ||
| 428 | * platform. Such BARs will not have an assigned address range and | ||
| 429 | * pci_enable_device() will fail, complaining about not claimed BAR, | ||
| 430 | * even if the concerned BAR is not needed for FPGA configuration | ||
| 431 | * at all. Thus, enable the device via PCI config space command. | ||
| 432 | */ | ||
| 433 | pci_read_config_word(pdev, PCI_COMMAND, &cmd); | ||
| 434 | if (!(cmd & PCI_COMMAND_MEMORY)) { | ||
| 435 | cmd |= PCI_COMMAND_MEMORY; | ||
| 436 | pci_write_config_word(pdev, PCI_COMMAND, cmd); | ||
| 437 | } | ||
| 438 | |||
| 439 | ret = pci_request_region(pdev, CVP_BAR, "CVP"); | ||
| 440 | if (ret) { | ||
| 441 | dev_err(&pdev->dev, "Requesting CVP BAR region failed\n"); | ||
| 442 | goto err_disable; | ||
| 443 | } | ||
| 444 | |||
| 445 | conf->pci_dev = pdev; | ||
| 446 | conf->write_data = altera_cvp_write_data_iomem; | ||
| 447 | |||
| 448 | conf->map = pci_iomap(pdev, CVP_BAR, 0); | ||
| 449 | if (!conf->map) { | ||
| 450 | dev_warn(&pdev->dev, "Mapping CVP BAR failed\n"); | ||
| 451 | conf->write_data = altera_cvp_write_data_config; | ||
| 452 | } | ||
| 453 | |||
| 454 | snprintf(conf->mgr_name, sizeof(conf->mgr_name), "%s @%s", | ||
| 455 | ALTERA_CVP_MGR_NAME, pci_name(pdev)); | ||
| 456 | |||
| 457 | ret = fpga_mgr_register(&pdev->dev, conf->mgr_name, | ||
| 458 | &altera_cvp_ops, conf); | ||
| 459 | if (ret) | ||
| 460 | goto err_unmap; | ||
| 461 | |||
| 462 | ret = driver_create_file(&altera_cvp_driver.driver, | ||
| 463 | &driver_attr_chkcfg); | ||
| 464 | if (ret) { | ||
| 465 | dev_err(&pdev->dev, "Can't create sysfs chkcfg file\n"); | ||
| 466 | fpga_mgr_unregister(&pdev->dev); | ||
| 467 | goto err_unmap; | ||
| 468 | } | ||
| 469 | |||
| 470 | return 0; | ||
| 471 | |||
| 472 | err_unmap: | ||
| 473 | pci_iounmap(pdev, conf->map); | ||
| 474 | pci_release_region(pdev, CVP_BAR); | ||
| 475 | err_disable: | ||
| 476 | cmd &= ~PCI_COMMAND_MEMORY; | ||
| 477 | pci_write_config_word(pdev, PCI_COMMAND, cmd); | ||
| 478 | return ret; | ||
| 479 | } | ||
| 480 | |||
| 481 | static void altera_cvp_remove(struct pci_dev *pdev) | ||
| 482 | { | ||
| 483 | struct fpga_manager *mgr = pci_get_drvdata(pdev); | ||
| 484 | struct altera_cvp_conf *conf = mgr->priv; | ||
| 485 | u16 cmd; | ||
| 486 | |||
| 487 | driver_remove_file(&altera_cvp_driver.driver, &driver_attr_chkcfg); | ||
| 488 | fpga_mgr_unregister(&pdev->dev); | ||
| 489 | pci_iounmap(pdev, conf->map); | ||
| 490 | pci_release_region(pdev, CVP_BAR); | ||
| 491 | pci_read_config_word(pdev, PCI_COMMAND, &cmd); | ||
| 492 | cmd &= ~PCI_COMMAND_MEMORY; | ||
| 493 | pci_write_config_word(pdev, PCI_COMMAND, cmd); | ||
| 494 | } | ||
| 495 | |||
| 496 | module_pci_driver(altera_cvp_driver); | ||
| 497 | |||
| 498 | MODULE_LICENSE("GPL v2"); | ||
| 499 | MODULE_AUTHOR("Anatolij Gustschin <agust@denx.de>"); | ||
| 500 | MODULE_DESCRIPTION("Module to load Altera FPGA over CvP"); | ||
| @@ -66,7 +66,7 @@ static int alt_hps2fpga_enable_show(struct fpga_bridge *bridge) · 65 unmodified lines | |||
| 66 | 66 | ||
| 67 | /* The L3 REMAP register is write only, so keep a cached value. */ | 67 | /* The L3 REMAP register is write only, so keep a cached value. */ |
| 68 | static unsigned int l3_remap_shadow; | 68 | static unsigned int l3_remap_shadow; |
| 69 | static spinlock_t l3_remap_lock; | 69 | static DEFINE_SPINLOCK(l3_remap_lock); |
| 70 | 70 | ||
| 71 | static int _alt_hps2fpga_enable_set(struct altera_hps2fpga_data *priv, | 71 | static int _alt_hps2fpga_enable_set(struct altera_hps2fpga_data *priv, |
| 72 | bool enable) | 72 | bool enable) |
| @@ -143,9 +143,15 @@ static int alt_fpga_bridge_probe(struct platform_device *pdev) · 70 unmodified lines | |||
| 143 | int ret; | 143 | int ret; |
| 144 | 144 | ||
| 145 | of_id = of_match_device(altera_fpga_of_match, dev); | 145 | of_id = of_match_device(altera_fpga_of_match, dev); |
| 146 | if (!of_id) { | ||
| 147 | dev_err(dev, "failed to match device\n"); | ||
| 148 | return -ENODEV; | ||
| 149 | } | ||
| 150 | |||
| 146 | priv = (struct altera_hps2fpga_data *)of_id->data; | 151 | priv = (struct altera_hps2fpga_data *)of_id->data; |
| 147 | 152 | ||
| 148 | priv->bridge_reset = of_reset_control_get_by_index(dev->of_node, 0); | 153 | priv->bridge_reset = of_reset_control_get_exclusive_by_index(dev->of_node, |
| 154 | 0); | ||
| 149 | if (IS_ERR(priv->bridge_reset)) { | 155 | if (IS_ERR(priv->bridge_reset)) { |
| 150 | dev_err(dev, "Could not get %s reset control\n", priv->name); | 156 | dev_err(dev, "Could not get %s reset control\n", priv->name); |
| 151 | return PTR_ERR(priv->bridge_reset); | 157 | return PTR_ERR(priv->bridge_reset); |
| @@ -171,8 +177,6 @@ static int alt_fpga_bridge_probe(struct platform_device *pdev) · 19 unmodified lines | |||
| 171 | return -EBUSY; | 177 | return -EBUSY; |
| 172 | } | 178 | } |
| 173 | 179 | ||
| 174 | spin_lock_init(&l3_remap_lock); | ||
| 175 | |||
| 176 | if (!of_property_read_u32(dev->of_node, "bridge-enable", &enable)) { | 180 | if (!of_property_read_u32(dev->of_node, "bridge-enable", &enable)) { |
| 177 | if (enable > 1) { | 181 | if (enable > 1) { |
| 178 | dev_warn(dev, "invalid bridge-enable %u > 1\n", enable); | 182 | dev_warn(dev, "invalid bridge-enable %u > 1\n", enable); |
| @@ -0,0 +1,308 @@ | |||
| 1 | /* | ||
| 2 | * Altera Passive Serial SPI Driver | ||
| 3 | * | ||
| 4 | * Copyright (c) 2017 United Western Technologies, Corporation | ||
| 5 | * | ||
| 6 | * Joshua Clayton <stillcompiling@gmail.com> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify it | ||
| 9 | * under the terms and conditions of the GNU General Public License, | ||
| 10 | * version 2, as published by the Free Software Foundation. | ||
| 11 | * | ||
| 12 | * Manage Altera FPGA firmware that is loaded over SPI using the passive | ||
| 13 | * serial configuration method. | ||
| 14 | * Firmware must be in binary "rbf" format. | ||
| 15 | * Works on Arria 10, Cyclone V and Stratix V. Should work on Cyclone series. | ||
| 16 | * May work on other Altera FPGAs. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <linux/bitrev.h> | ||
| 20 | #include <linux/delay.h> | ||
| 21 | #include <linux/fpga/fpga-mgr.h> | ||
| 22 | #include <linux/gpio/consumer.h> | ||
| 23 | #include <linux/module.h> | ||
| 24 | #include <linux/of_gpio.h> | ||
| 25 | #include <linux/of_device.h> | ||
| 26 | #include <linux/spi/spi.h> | ||
| 27 | #include <linux/sizes.h> | ||
| 28 | |||
| 29 | enum altera_ps_devtype { | ||
| 30 | CYCLONE5, | ||
| 31 | ARRIA10, | ||
| 32 | }; | ||
| 33 | |||
| 34 | struct altera_ps_data { | ||
| 35 | enum altera_ps_devtype devtype; | ||
| 36 | int status_wait_min_us; | ||
| 37 | int status_wait_max_us; | ||
| 38 | int t_cfg_us; | ||
| 39 | int t_st2ck_us; | ||
| 40 | }; | ||
| 41 | |||
| 42 | struct altera_ps_conf { | ||
| 43 | struct gpio_desc *config; | ||
| 44 | struct gpio_desc *confd; | ||
| 45 | struct gpio_desc *status; | ||
| 46 | struct spi_device *spi; | ||
| 47 | const struct altera_ps_data *data; | ||
| 48 | u32 info_flags; | ||
| 49 | char mgr_name[64]; | ||
| 50 | }; | ||
| 51 | |||
| 52 | /* | Arria 10 | Cyclone5 | Stratix5 | | ||
| 53 | * t_CF2ST0 | [; 600] | [; 600] | [; 600] |ns | ||
| 54 | * t_CFG | [2;] | [2;] | [2;] |µs | ||
| 55 | * t_STATUS | [268; 3000] | [268; 1506] | [268; 1506] |µs | ||
| 56 | * t_CF2ST1 | [; 3000] | [; 1506] | [; 1506] |µs | ||
| 57 | * t_CF2CK | [3010;] | [1506;] | [1506;] |µs | ||
| 58 | * t_ST2CK | [10;] | [2;] | [2;] |µs | ||
| 59 | * t_CD2UM | [175; 830] | [175; 437] | [175; 437] |µs | ||
| 60 | */ | ||
| 61 | static struct altera_ps_data c5_data = { | ||
| 62 | /* these values for Cyclone5 are compatible with Stratix5 */ | ||
| 63 | .devtype = CYCLONE5, | ||
| 64 | .status_wait_min_us = 268, | ||
| 65 | .status_wait_max_us = 1506, | ||
| 66 | .t_cfg_us = 2, | ||
| 67 | .t_st2ck_us = 2, | ||
| 68 | }; | ||
| 69 | |||
| 70 | static struct altera_ps_data a10_data = { | ||
| 71 | .devtype = ARRIA10, | ||
| 72 | .status_wait_min_us = 268, /* min(t_STATUS) */ | ||
| 73 | .status_wait_max_us = 3000, /* max(t_CF2ST1) */ | ||
| 74 | .t_cfg_us = 2, /* max { min(t_CFG), max(tCF2ST0) } */ | ||
| 75 | .t_st2ck_us = 10, /* min(t_ST2CK) */ | ||
| 76 | }; | ||
| 77 | |||
| 78 | static const struct of_device_id of_ef_match[] = { | ||
| 79 | { .compatible = "altr,fpga-passive-serial", .data = &c5_data }, | ||
| 80 | { .compatible = "altr,fpga-arria10-passive-serial", .data = &a10_data }, | ||
| 81 | {} | ||
| 82 | }; | ||
| 83 | MODULE_DEVICE_TABLE(of, of_ef_match); | ||
| 84 | |||
| 85 | static enum fpga_mgr_states altera_ps_state(struct fpga_manager *mgr) | ||
| 86 | { | ||
| 87 | struct altera_ps_conf *conf = mgr->priv; | ||
| 88 | |||
| 89 | if (gpiod_get_value_cansleep(conf->status)) | ||
| 90 | return FPGA_MGR_STATE_RESET; | ||
| 91 | |||
| 92 | return FPGA_MGR_STATE_UNKNOWN; | ||
| 93 | } | ||
| 94 | |||
| 95 | static inline void altera_ps_delay(int delay_us) | ||
| 96 | { | ||
| 97 | if (delay_us > 10) | ||
| 98 | usleep_range(delay_us, delay_us + 5); | ||
| 99 | else | ||
| 100 | udelay(delay_us); | ||
| 101 | } | ||
| 102 | |||
| 103 | static int altera_ps_write_init(struct fpga_manager *mgr, | ||
| 104 | struct fpga_image_info *info, | ||
| 105 | const char *buf, size_t count) | ||
| 106 | { | ||
| 107 | struct altera_ps_conf *conf = mgr->priv; | ||
| 108 | int min, max, waits; | ||
| 109 | int i; | ||
| 110 | |||
| 111 | conf->info_flags = info->flags; | ||
| 112 | |||
| 113 | if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) { | ||
| 114 | dev_err(&mgr->dev, "Partial reconfiguration not supported.\n"); | ||
| 115 | return -EINVAL; | ||
| 116 | } | ||
| 117 | |||
| 118 | gpiod_set_value_cansleep(conf->config, 1); | ||
| 119 | |||
| 120 | /* wait min reset pulse time */ | ||
| 121 | altera_ps_delay(conf->data->t_cfg_us); | ||
| 122 | |||
| 123 | if (!gpiod_get_value_cansleep(conf->status)) { | ||
| 124 | dev_err(&mgr->dev, "Status pin failed to show a reset\n"); | ||
| 125 | return -EIO; | ||
| 126 | } | ||
| 127 | |||
| 128 | gpiod_set_value_cansleep(conf->config, 0); | ||
| 129 | |||
| 130 | min = conf->data->status_wait_min_us; | ||
| 131 | max = conf->data->status_wait_max_us; | ||
| 132 | waits = max / min; | ||
| 133 | if (max % min) | ||
| 134 | waits++; | ||
| 135 | |||
| 136 | /* wait for max { max(t_STATUS), max(t_CF2ST1) } */ | ||
| 137 | for (i = 0; i < waits; i++) { | ||
| 138 | usleep_range(min, min + 10); | ||
| 139 | if (!gpiod_get_value_cansleep(conf->status)) { | ||
| 140 | /* wait for min(t_ST2CK)*/ | ||
| 141 | altera_ps_delay(conf->data->t_st2ck_us); | ||
| 142 | return 0; | ||
| 143 | } | ||
| 144 | } | ||
| 145 | |||
| 146 | dev_err(&mgr->dev, "Status pin not ready.\n"); | ||
| 147 | return -EIO; | ||
| 148 | } | ||
| 149 | |||
| 150 | static void rev_buf(char *buf, size_t len) | ||
| 151 | { | ||
| 152 | u32 *fw32 = (u32 *)buf; | ||
| 153 | size_t extra_bytes = (len & 0x03); | ||
| 154 | const u32 *fw_end = (u32 *)(buf + len - extra_bytes); | ||
| 155 | |||
| 156 | /* set buffer to lsb first */ | ||
| 157 | while (fw32 < fw_end) { | ||
| 158 | *fw32 = bitrev8x4(*fw32); | ||
| 159 | fw32++; | ||
| 160 | } | ||
| 161 | |||
| 162 | if (extra_bytes) { | ||
| 163 | buf = (char *)fw_end; | ||
| 164 | while (extra_bytes) { | ||
| 165 | *buf = bitrev8(*buf); | ||
| 166 | buf++; | ||
| 167 | extra_bytes--; | ||
| 168 | } | ||
| 169 | } | ||
| 170 | } | ||
| 171 | |||
| 172 | static int altera_ps_write(struct fpga_manager *mgr, const char *buf, | ||
| 173 | size_t count) | ||
| 174 | { | ||
| 175 | struct altera_ps_conf *conf = mgr->priv; | ||
| 176 | const char *fw_data = buf; | ||
| 177 | const char *fw_data_end = fw_data + count; | ||
| 178 | |||
| 179 | while (fw_data < fw_data_end) { | ||
| 180 | int ret; | ||
| 181 | size_t stride = min_t(size_t, fw_data_end - fw_data, SZ_4K); | ||
| 182 | |||
| 183 | if (!(conf->info_flags & FPGA_MGR_BITSTREAM_LSB_FIRST)) | ||
| 184 | rev_buf((char *)fw_data, stride); | ||
| 185 | |||
| 186 | ret = spi_write(conf->spi, fw_data, stride); | ||
| 187 | if (ret) { | ||
| 188 | dev_err(&mgr->dev, "spi error in firmware write: %d\n", | ||
| 189 | ret); | ||
| 190 | return ret; | ||
| 191 | } | ||
| 192 | fw_data += stride; | ||
| 193 | } | ||
| 194 | |||
| 195 | return 0; | ||
| 196 | } | ||
| 197 | |||
| 198 | static int altera_ps_write_complete(struct fpga_manager *mgr, | ||
| 199 | struct fpga_image_info *info) | ||
| 200 | { | ||
| 201 | struct altera_ps_conf *conf = mgr->priv; | ||
| 202 | const char dummy[] = {0}; | ||
| 203 | int ret; | ||
| 204 | |||
| 205 | if (gpiod_get_value_cansleep(conf->status)) { | ||
| 206 | dev_err(&mgr->dev, "Error during configuration.\n"); | ||
| 207 | return -EIO; | ||
| 208 | } | ||
| 209 | |||
| 210 | if (!IS_ERR(conf->confd)) { | ||
| 211 | if (!gpiod_get_raw_value_cansleep(conf->confd)) { | ||
| 212 | dev_err(&mgr->dev, "CONF_DONE is inactive!\n"); | ||
| 213 | return -EIO; | ||
| 214 | } | ||
| 215 | } | ||
| 216 | |||
| 217 | /* | ||
| 218 | * After CONF_DONE goes high, send two additional falling edges on DCLK | ||
| 219 | * to begin initialization and enter user mode | ||
| 220 | */ | ||
| 221 | ret = spi_write(conf->spi, dummy, 1); | ||
| 222 | if (ret) { | ||
| 223 | dev_err(&mgr->dev, "spi error during end sequence: %d\n", ret); | ||
| 224 | return ret; | ||
| 225 | } | ||
| 226 | |||
| 227 | return 0; | ||
| 228 | } | ||
| 229 | |||
| 230 | static const struct fpga_manager_ops altera_ps_ops = { | ||
| 231 | .state = altera_ps_state, | ||
| 232 | .write_init = altera_ps_write_init, | ||
| 233 | .write = altera_ps_write, | ||
| 234 | .write_complete = altera_ps_write_complete, | ||
| 235 | }; | ||
| 236 | |||
| 237 | static int altera_ps_probe(struct spi_device *spi) | ||
| 238 | { | ||
| 239 | struct altera_ps_conf *conf; | ||
| 240 | const struct of_device_id *of_id; | ||
| 241 | |||
| 242 | conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL); | ||
| 243 | if (!conf) | ||
| 244 | return -ENOMEM; | ||
| 245 | |||
| 246 | of_id = of_match_device(of_ef_match, &spi->dev); | ||
| 247 | if (!of_id) | ||
| 248 | return -ENODEV; | ||
| 249 | |||
| 250 | conf->data = of_id->data; | ||
| 251 | conf->spi = spi; | ||
| 252 | conf->config = devm_gpiod_get(&spi->dev, "nconfig", GPIOD_OUT_HIGH); | ||
| 253 | if (IS_ERR(conf->config)) { | ||
| 254 | dev_err(&spi->dev, "Failed to get config gpio: %ld\n", | ||
| 255 | PTR_ERR(conf->config)); | ||
| 256 | return PTR_ERR(conf->config); | ||
| 257 | } | ||
| 258 | |||
| 259 | conf->status = devm_gpiod_get(&spi->dev, "nstat", GPIOD_IN); | ||
| 260 | if (IS_ERR(conf->status)) { | ||
| 261 | dev_err(&spi->dev, "Failed to get status gpio: %ld\n", | ||
| 262 | PTR_ERR(conf->status)); | ||
| 263 | return PTR_ERR(conf->status); | ||
| 264 | } | ||
| 265 | |||
| 266 | conf->confd = devm_gpiod_get(&spi->dev, "confd", GPIOD_IN); | ||
| 267 | if (IS_ERR(conf->confd)) { | ||
| 268 | dev_warn(&spi->dev, "Not using confd gpio: %ld\n", | ||
| 269 | PTR_ERR(conf->confd)); | ||
| 270 | } | ||
| 271 | |||
| 272 | /* Register manager with unique name */ | ||
| 273 | snprintf(conf->mgr_name, sizeof(conf->mgr_name), "%s %s", | ||
| 274 | dev_driver_string(&spi->dev), dev_name(&spi->dev)); | ||
| 275 | |||
| 276 | return fpga_mgr_register(&spi->dev, conf->mgr_name, | ||
| 277 | &altera_ps_ops, conf); | ||
| 278 | } | ||
| 279 | |||
| 280 | static int altera_ps_remove(struct spi_device *spi) | ||
| 281 | { | ||
| 282 | fpga_mgr_unregister(&spi->dev); | ||
| 283 | |||
| 284 | return 0; | ||
| 285 | } | ||
| 286 | |||
| 287 | static const struct spi_device_id altera_ps_spi_ids[] = { | ||
| 288 | {"cyclone-ps-spi", 0}, | ||
| 289 | {} | ||
| 290 | }; | ||
| 291 | MODULE_DEVICE_TABLE(spi, altera_ps_spi_ids); | ||
| 292 | |||
| 293 | static struct spi_driver altera_ps_driver = { | ||
| 294 | .driver = { | ||
| 295 | .name = "altera-ps-spi", | ||
| 296 | .owner = THIS_MODULE, | ||
| 297 | .of_match_table = of_match_ptr(of_ef_match), | ||
| 298 | }, | ||
| 299 | .id_table = altera_ps_spi_ids, | ||
| 300 | .probe = altera_ps_probe, | ||
| 301 | .remove = altera_ps_remove, | ||
| 302 | }; | ||
| 303 | |||
| 304 | module_spi_driver(altera_ps_driver) | ||
| 305 | |||
| 306 | MODULE_LICENSE("GPL v2"); | ||
| 307 | MODULE_AUTHOR("Joshua Clayton <stillcompiling@gmail.com>"); | ||
| 308 | MODULE_DESCRIPTION("Module to load Altera FPGA firmware over SPI"); | ||
| @@ -319,8 +319,8 @@ static int child_regions_with_firmware(struct device_node *overlay) · 318 unmodified lines | |||
| 319 | of_node_put(child_region); | 319 | of_node_put(child_region); |
| 320 | 320 | ||
| 321 | if (ret) | 321 | if (ret) |
| 322 | pr_err("firmware-name not allowed in child FPGA region: %s", | 322 | pr_err("firmware-name not allowed in child FPGA region: %pOF", |
| 323 | child_region->full_name); | 323 | child_region); |
| 324 | 324 | ||
| 325 | return ret; | 325 | return ret; |
| 326 | } | 326 | } |
| @@ -475,7 +475,7 @@ static ssize_t fsi_slave_sysfs_raw_write(struct file *file, · 474 unmodified lines | |||
| 475 | return count; | 475 | return count; |
| 476 | } | 476 | } |
| 477 | 477 | ||
| 478 | static struct bin_attribute fsi_slave_raw_attr = { | 478 | static const struct bin_attribute fsi_slave_raw_attr = { |
| 479 | .attr = { | 479 | .attr = { |
| 480 | .name = "raw", | 480 | .name = "raw", |
| 481 | .mode = 0600, | 481 | .mode = 0600, |
| @@ -499,7 +499,7 @@ static ssize_t fsi_slave_sysfs_term_write(struct file *file, · 17 unmodified lines | |||
| 499 | return count; | 499 | return count; |
| 500 | } | 500 | } |
| 501 | 501 | ||
| 502 | static struct bin_attribute fsi_slave_term_attr = { | 502 | static const struct bin_attribute fsi_slave_term_attr = { |
| 503 | .attr = { | 503 | .attr = { |
| 504 | .name = "term", | 504 | .name = "term", |
| 505 | .mode = 0200, | 505 | .mode = 0200, |
| @@ -57,12 +57,6 @@ static int put_scom(struct scom_device *scom_dev, uint64_t value, · 56 unmodified lines | |||
| 57 | int rc; | 57 | int rc; |
| 58 | uint32_t data; | 58 | uint32_t data; |
| 59 | 59 | ||
| 60 | data = cpu_to_be32(SCOM_RESET_CMD); | ||
| 61 | rc = fsi_device_write(scom_dev->fsi_dev, SCOM_RESET_REG, &data, | ||
| 62 | sizeof(uint32_t)); | ||
| 63 | if (rc) | ||
| 64 | return rc; | ||
| 65 | |||
| 66 | data = cpu_to_be32((value >> 32) & 0xffffffff); | 60 | data = cpu_to_be32((value >> 32) & 0xffffffff); |
| 67 | rc = fsi_device_write(scom_dev->fsi_dev, SCOM_DATA0_REG, &data, | 61 | rc = fsi_device_write(scom_dev->fsi_dev, SCOM_DATA0_REG, &data, |
| 68 | sizeof(uint32_t)); | 62 | sizeof(uint32_t)); |
| @@ -186,6 +180,7 @@ static const struct file_operations scom_fops = { · 117 unmodified lines | |||
| 186 | 180 | ||
| 187 | static int scom_probe(struct device *dev) | 181 | static int scom_probe(struct device *dev) |
| 188 | { | 182 | { |
| 183 | uint32_t data; | ||
| 189 | struct fsi_device *fsi_dev = to_fsi_dev(dev); | 184 | struct fsi_device *fsi_dev = to_fsi_dev(dev); |
| 190 | struct scom_device *scom; | 185 | struct scom_device *scom; |
| 191 | 186 | ||
| @@ -202,6 +197,9 @@ static int scom_probe(struct device *dev) · 10 unmodified lines | |||
| 202 | scom->mdev.parent = dev; | 197 | scom->mdev.parent = dev; |
| 203 | list_add(&scom->link, &scom_devices); | 198 | list_add(&scom->link, &scom_devices); |
| 204 | 199 | ||
| 200 | data = cpu_to_be32(SCOM_RESET_CMD); | ||
| 201 | fsi_device_write(fsi_dev, SCOM_RESET_REG, &data, sizeof(uint32_t)); | ||
| 202 | |||
| 205 | return misc_register(&scom->mdev); | 203 | return misc_register(&scom->mdev); |
| 206 | } | 204 | } |
| 207 | 205 | ||
| @@ -177,6 +177,11 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size, · 176 unmodified lines | |||
| 177 | &vmbus_connection.chn_msg_list); | 177 | &vmbus_connection.chn_msg_list); |
| 178 | spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); | 178 | spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); |
| 179 | 179 | ||
| 180 | if (newchannel->rescind) { | ||
| 181 | err = -ENODEV; | ||
| 182 | goto error_free_gpadl; | ||
| 183 | } | ||
| 184 | |||
| 180 | ret = vmbus_post_msg(open_msg, | 185 | ret = vmbus_post_msg(open_msg, |
| 181 | sizeof(struct vmbus_channel_open_channel), true); | 186 | sizeof(struct vmbus_channel_open_channel), true); |
| 182 | 187 | ||
| @@ -421,6 +426,11 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer, · 238 unmodified lines | |||
| 421 | 426 | ||
| 422 | spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); | 427 | spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); |
| 423 | 428 | ||
| 429 | if (channel->rescind) { | ||
| 430 | ret = -ENODEV; | ||
| 431 | goto cleanup; | ||
| 432 | } | ||
| 433 | |||
| 424 | ret = vmbus_post_msg(gpadlmsg, msginfo->msgsize - | 434 | ret = vmbus_post_msg(gpadlmsg, msginfo->msgsize - |
| 425 | sizeof(*msginfo), true); | 435 | sizeof(*msginfo), true); |
| 426 | if (ret != 0) | 436 | if (ret != 0) |
| @@ -494,6 +504,10 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, u32 gpadl_handle) · 67 unmodified lines | |||
| 494 | list_add_tail(&info->msglistentry, | 504 | list_add_tail(&info->msglistentry, |
| 495 | &vmbus_connection.chn_msg_list); | 505 | &vmbus_connection.chn_msg_list); |
| 496 | spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); | 506 | spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); |
| 507 | |||
| 508 | if (channel->rescind) | ||
| 509 | goto post_msg_err; | ||
| 510 | |||
| 497 | ret = vmbus_post_msg(msg, sizeof(struct vmbus_channel_gpadl_teardown), | 511 | ret = vmbus_post_msg(msg, sizeof(struct vmbus_channel_gpadl_teardown), |
| 498 | true); | 512 | true); |
| 499 | 513 | ||
| @@ -451,6 +451,12 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel) · 450 unmodified lines | |||
| 451 | /* Make sure this is a new offer */ | 451 | /* Make sure this is a new offer */ |
| 452 | mutex_lock(&vmbus_connection.channel_mutex); | 452 | mutex_lock(&vmbus_connection.channel_mutex); |
| 453 | 453 | ||
| 454 | /* | ||
| 455 | * Now that we have acquired the channel_mutex, | ||
| 456 | * we can release the potentially racing rescind thread. | ||
| 457 | */ | ||
| 458 | atomic_dec(&vmbus_connection.offer_in_progress); | ||
| 459 | |||
| 454 | list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) { | 460 | list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) { |
| 455 | if (!uuid_le_cmp(channel->offermsg.offer.if_type, | 461 | if (!uuid_le_cmp(channel->offermsg.offer.if_type, |
| 456 | newchannel->offermsg.offer.if_type) && | 462 | newchannel->offermsg.offer.if_type) && |
| @@ -481,7 +487,6 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel) · 24 unmodified lines | |||
| 481 | channel->num_sc++; | 487 | channel->num_sc++; |
| 482 | spin_unlock_irqrestore(&channel->lock, flags); | 488 | spin_unlock_irqrestore(&channel->lock, flags); |
| 483 | } else { | 489 | } else { |
| 484 | atomic_dec(&vmbus_connection.offer_in_progress); | ||
| 485 | goto err_free_chan; | 490 | goto err_free_chan; |
| 486 | } | 491 | } |
| 487 | } | 492 | } |
| @@ -510,7 +515,6 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel) · 22 unmodified lines | |||
| 510 | if (!fnew) { | 515 | if (!fnew) { |
| 511 | if (channel->sc_creation_callback != NULL) | 516 | if (channel->sc_creation_callback != NULL) |
| 512 | channel->sc_creation_callback(newchannel); | 517 | channel->sc_creation_callback(newchannel); |
| 513 | atomic_dec(&vmbus_connection.offer_in_progress); | ||
| 514 | return; | 518 | return; |
| 515 | } | 519 | } |
| 516 | 520 | ||
| @@ -541,7 +545,7 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel) · 24 unmodified lines | |||
| 541 | goto err_deq_chan; | 545 | goto err_deq_chan; |
| 542 | } | 546 | } |
| 543 | 547 | ||
| 544 | atomic_dec(&vmbus_connection.offer_in_progress); | 548 | newchannel->probe_done = true; |
| 545 | return; | 549 | return; |
| 546 | 550 | ||
| 547 | err_deq_chan: | 551 | err_deq_chan: |
| @@ -882,8 +886,27 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr) · 334 unmodified lines | |||
| 882 | channel->rescind = true; | 886 | channel->rescind = true; |
| 883 | spin_unlock_irqrestore(&channel->lock, flags); | 887 | spin_unlock_irqrestore(&channel->lock, flags); |
| 884 | 888 | ||
| 889 | /* | ||
| 890 | * Now that we have posted the rescind state, perform | ||
| 891 | * rescind related cleanup. | ||
| 892 | */ | ||
| 885 | vmbus_rescind_cleanup(channel); | 893 | vmbus_rescind_cleanup(channel); |
| 886 | 894 | ||
| 895 | /* | ||
| 896 | * Now wait for offer handling to complete. | ||
| 897 | */ | ||
| 898 | while (READ_ONCE(channel->probe_done) == false) { | ||
| 899 | /* | ||
| 900 | * We wait here until any channel offer is currently | ||
| 901 | * being processed. | ||
| 902 | */ | ||
| 903 | msleep(1); | ||
| 904 | } | ||
| 905 | |||
| 906 | /* | ||
| 907 | * At this point, the rescind handling can proceed safely. | ||
| 908 | */ | ||
| 909 | |||
| 887 | if (channel->device_obj) { | 910 | if (channel->device_obj) { |
| 888 | if (channel->chn_rescind_callback) { | 911 | if (channel->chn_rescind_callback) { |
| 889 | channel->chn_rescind_callback(channel); | 912 | channel->chn_rescind_callback(channel); |
| @@ -584,10 +584,6 @@ static int hv_memory_notifier(struct notifier_block *nb, unsigned long val, · 583 unmodified lines | |||
| 584 | 584 | ||
| 585 | switch (val) { | 585 | switch (val) { |
| 586 | case MEM_ONLINE: | 586 | case MEM_ONLINE: |
| 587 | spin_lock_irqsave(&dm_device.ha_lock, flags); | ||
| 588 | dm_device.num_pages_onlined += mem->nr_pages; | ||
| 589 | spin_unlock_irqrestore(&dm_device.ha_lock, flags); | ||
| 590 | /* Fall through */ | ||
| 591 | case MEM_CANCEL_ONLINE: | 587 | case MEM_CANCEL_ONLINE: |
| 592 | if (dm_device.ha_waiting) { | 588 | if (dm_device.ha_waiting) { |
| 593 | dm_device.ha_waiting = false; | 589 | dm_device.ha_waiting = false; |
| @@ -644,6 +640,9 @@ static void hv_page_online_one(struct hv_hotadd_state *has, struct page *pg) · 50 unmodified lines | |||
| 644 | __online_page_set_limits(pg); | 640 | __online_page_set_limits(pg); |
| 645 | __online_page_increment_counters(pg); | 641 | __online_page_increment_counters(pg); |
| 646 | __online_page_free(pg); | 642 | __online_page_free(pg); |
| 643 | |||
| 644 | WARN_ON_ONCE(!spin_is_locked(&dm_device.ha_lock)); | ||
| 645 | dm_device.num_pages_onlined++; | ||
| 647 | } | 646 | } |
| 648 | 647 | ||
| 649 | static void hv_bring_pgs_online(struct hv_hotadd_state *has, | 648 | static void hv_bring_pgs_online(struct hv_hotadd_state *has, |
| @@ -1036,8 +1035,8 @@ static void process_info(struct hv_dynmem_device *dm, struct dm_info_msg *msg) · 386 unmodified lines | |||
| 1036 | if (info_hdr->data_size == sizeof(__u64)) { | 1035 | if (info_hdr->data_size == sizeof(__u64)) { |
| 1037 | __u64 *max_page_count = (__u64 *)&info_hdr[1]; | 1036 | __u64 *max_page_count = (__u64 *)&info_hdr[1]; |
| 1038 | 1037 | ||
| 1039 | pr_info("INFO_TYPE_MAX_PAGE_CNT = %llu\n", | 1038 | pr_info("Max. dynamic memory size: %llu MB\n", |
| 1040 | *max_page_count); | 1039 | (*max_page_count) >> (20 - PAGE_SHIFT)); |
| 1041 | } | 1040 | } |
| 1042 | 1041 | ||
| 1043 | break; | 1042 | break; |
| @@ -1656,6 +1655,7 @@ static int balloon_probe(struct hv_device *dev, · 612 unmodified lines | |||
| 1656 | } | 1655 | } |
| 1657 | 1656 | ||
| 1658 | dm_device.state = DM_INITIALIZED; | 1657 | dm_device.state = DM_INITIALIZED; |
| 1658 | last_post_time = jiffies; | ||
| 1659 | 1659 | ||
| 1660 | return 0; | 1660 | return 0; |
| 1661 | 1661 | ||
| @@ -304,7 +304,7 @@ static int process_ob_ipinfo(void *in_msg, void *out_msg, int op) · 303 unmodified lines | |||
| 304 | strlen((char *)in->body.kvp_ip_val.adapter_id), | 304 | strlen((char *)in->body.kvp_ip_val.adapter_id), |
| 305 | UTF16_HOST_ENDIAN, | 305 | UTF16_HOST_ENDIAN, |
| 306 | (wchar_t *)out->kvp_ip_val.adapter_id, | 306 | (wchar_t *)out->kvp_ip_val.adapter_id, |
| 307 | MAX_IP_ADDR_SIZE); | 307 | MAX_ADAPTER_ID_SIZE); |
| 308 | if (len < 0) | 308 | if (len < 0) |
| 309 | return len; | 309 | return len; |
| 310 | 310 | ||
| @@ -29,6 +29,7 @@ · 28 unmodified lines | |||
| 29 | #include <linux/uio.h> | 29 | #include <linux/uio.h> |
| 30 | #include <linux/vmalloc.h> | 30 | #include <linux/vmalloc.h> |
| 31 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
| 32 | #include <linux/prefetch.h> | ||
| 32 | 33 | ||
| 33 | #include "hyperv_vmbus.h" | 34 | #include "hyperv_vmbus.h" |
| 34 | 35 | ||
| @@ -94,30 +95,6 @@ hv_set_next_write_location(struct hv_ring_buffer_info *ring_info, · 59 unmodified lines | |||
| 94 | ring_info->ring_buffer->write_index = next_write_location; | 95 | ring_info->ring_buffer->write_index = next_write_location; |
| 95 | } | 96 | } |
| 96 | 97 | ||
| 97 | /* Get the next read location for the specified ring buffer. */ | ||
| 98 | static inline u32 | ||
| 99 | hv_get_next_read_location(const struct hv_ring_buffer_info *ring_info) | ||
| 100 | { | ||
| 101 | return ring_info->ring_buffer->read_index; | ||
| 102 | } | ||
| 103 | |||
| 104 | /* | ||
| 105 | * Get the next read location + offset for the specified ring buffer. | ||
| 106 | * This allows the caller to skip. | ||
| 107 | */ | ||
| 108 | static inline u32 | ||
| 109 | hv_get_next_readlocation_withoffset(const struct hv_ring_buffer_info *ring_info, | ||
| 110 | u32 offset) | ||
| 111 | { | ||
| 112 | u32 next = ring_info->ring_buffer->read_index; | ||
| 113 | |||
| 114 | next += offset; | ||
| 115 | if (next >= ring_info->ring_datasize) | ||
| 116 | next -= ring_info->ring_datasize; | ||
| 117 | |||
| 118 | return next; | ||
| 119 | } | ||
| 120 | |||
| 121 | /* Set the next read location for the specified ring buffer. */ | 98 | /* Set the next read location for the specified ring buffer. */ |
| 122 | static inline void | 99 | static inline void |
| 123 | hv_set_next_read_location(struct hv_ring_buffer_info *ring_info, | 100 | hv_set_next_read_location(struct hv_ring_buffer_info *ring_info, |
| @@ -141,29 +118,6 @@ hv_get_ring_bufferindices(struct hv_ring_buffer_info *ring_info) · 17 unmodified lines | |||
| 141 | return (u64)ring_info->ring_buffer->write_index << 32; | 118 | return (u64)ring_info->ring_buffer->write_index << 32; |
| 142 | } | 119 | } |
| 143 | 120 | ||
| 144 | /* | ||
| 145 | * Helper routine to copy to source from ring buffer. | ||
| 146 | * Assume there is enough room. Handles wrap-around in src case only!! | ||
| 147 | */ | ||
| 148 | static u32 hv_copyfrom_ringbuffer( | ||
| 149 | const struct hv_ring_buffer_info *ring_info, | ||
| 150 | void *dest, | ||
| 151 | u32 destlen, | ||
| 152 | u32 start_read_offset) | ||
| 153 | { | ||
| 154 | void *ring_buffer = hv_get_ring_buffer(ring_info); | ||
| 155 | u32 ring_buffer_size = hv_get_ring_buffersize(ring_info); | ||
| 156 | |||
| 157 | memcpy(dest, ring_buffer + start_read_offset, destlen); | ||
| 158 | |||
| 159 | start_read_offset += destlen; | ||
| 160 | if (start_read_offset >= ring_buffer_size) | ||
| 161 | start_read_offset -= ring_buffer_size; | ||
| 162 | |||
| 163 | return start_read_offset; | ||
| 164 | } | ||
| 165 | |||
| 166 | |||
| 167 | /* | 121 | /* |
| 168 | * Helper routine to copy from source to ring buffer. | 122 | * Helper routine to copy from source to ring buffer. |
| 169 | * Assume there is enough room. Handles wrap-around in dest case only!! | 123 | * Assume there is enough room. Handles wrap-around in dest case only!! |
| @@ -334,33 +288,22 @@ int hv_ringbuffer_write(struct vmbus_channel *channel, · 164 unmodified lines | |||
| 334 | return 0; | 288 | return 0; |
| 335 | } | 289 | } |
| 336 | 290 | ||
| 337 | static inline void | ||
| 338 | init_cached_read_index(struct hv_ring_buffer_info *rbi) | ||
| 339 | { | ||
| 340 | rbi->cached_read_index = rbi->ring_buffer->read_index; | ||
| 341 | } | ||
| 342 | |||
| 343 | int hv_ringbuffer_read(struct vmbus_channel *channel, | 291 | int hv_ringbuffer_read(struct vmbus_channel *channel, |
| 344 | void *buffer, u32 buflen, u32 *buffer_actual_len, | 292 | void *buffer, u32 buflen, u32 *buffer_actual_len, |
| 345 | u64 *requestid, bool raw) | 293 | u64 *requestid, bool raw) |
| 346 | { | 294 | { |
| 347 | u32 bytes_avail_toread; | 295 | struct vmpacket_descriptor *desc; |
| 348 | u32 next_read_location; | 296 | u32 packetlen, offset; |
| 349 | u64 prev_indices = 0; | 297 | |
| 350 | struct vmpacket_descriptor desc; | 298 | if (unlikely(buflen == 0)) |
| 351 | u32 offset; | ||
| 352 | u32 packetlen; | ||
| 353 | struct hv_ring_buffer_info *inring_info = &channel->inbound; | ||
| 354 | |||
| 355 | if (buflen <= 0) | ||
| 356 | return -EINVAL; | 299 | return -EINVAL; |
| 357 | 300 | ||
| 358 | *buffer_actual_len = 0; | 301 | *buffer_actual_len = 0; |
| 359 | *requestid = 0; | 302 | *requestid = 0; |
| 360 | 303 | ||
| 361 | bytes_avail_toread = hv_get_bytes_to_read(inring_info); | ||
| 362 | /* Make sure there is something to read */ | 304 | /* Make sure there is something to read */ |
| 363 | if (bytes_avail_toread < sizeof(desc)) { | 305 | desc = hv_pkt_iter_first(channel); |
| 306 | if (desc == NULL) { | ||
| 364 | /* | 307 | /* |
| 365 | * No error is set when there is even no header, drivers are | 308 | * No error is set when there is even no header, drivers are |
| 366 | * supposed to analyze buffer_actual_len. | 309 | * supposed to analyze buffer_actual_len. |
| @@ -368,48 +311,22 @@ int hv_ringbuffer_read(struct vmbus_channel *channel, · 1 unmodified line | |||
| 368 | return 0; | 311 | return 0; |
| 369 | } | 312 | } |
| 370 | 313 | ||
| 371 | init_cached_read_index(inring_info); | 314 | offset = raw ? 0 : (desc->offset8 << 3); |
| 372 | 315 | packetlen = (desc->len8 << 3) - offset; | |
| 373 | next_read_location = hv_get_next_read_location(inring_info); | ||
| 374 | next_read_location = hv_copyfrom_ringbuffer(inring_info, &desc, | ||
| 375 | sizeof(desc), | ||
| 376 | next_read_location); | ||
| 377 | |||
| 378 | offset = raw ? 0 : (desc.offset8 << 3); | ||
| 379 | packetlen = (desc.len8 << 3) - offset; | ||
| 380 | *buffer_actual_len = packetlen; | 316 | *buffer_actual_len = packetlen; |
| 381 | *requestid = desc.trans_id; | 317 | *requestid = desc->trans_id; |
| 382 | |||
| 383 | if (bytes_avail_toread < packetlen + offset) | ||
| 384 | return -EAGAIN; | ||
| 385 | 318 | ||
| 386 | if (packetlen > buflen) | 319 | if (unlikely(packetlen > buflen)) |
| 387 | return -ENOBUFS; | 320 | return -ENOBUFS; |
| 388 | 321 | ||
| 389 | next_read_location = | 322 | /* since ring is double mapped, only one copy is necessary */ |
| 390 | hv_get_next_readlocation_withoffset(inring_info, offset); | 323 | memcpy(buffer, (const char *)desc + offset, packetlen); |
| 391 | 324 | ||
| 392 | next_read_location = hv_copyfrom_ringbuffer(inring_info, | 325 | /* Advance ring index to next packet descriptor */ |
| 393 | buffer, | 326 | __hv_pkt_iter_next(channel, desc); |
| 394 | packetlen, | ||
| 395 | next_read_location); | ||
| 396 | 327 | ||
| 397 | next_read_location = hv_copyfrom_ringbuffer(inring_info, | 328 | /* Notify host of update */ |
| 398 | &prev_indices, | 329 | hv_pkt_iter_close(channel); |
| 399 | sizeof(u64), | ||
| 400 | next_read_location); | ||
| 401 | |||
| 402 | /* | ||
| 403 | * Make sure all reads are done before we update the read index since | ||
| 404 | * the writer may start writing to the read area once the read index | ||
| 405 | * is updated. | ||
| 406 | */ | ||
| 407 | virt_mb(); | ||
| 408 | |||
| 409 | /* Update the read index */ | ||
| 410 | hv_set_next_read_location(inring_info, next_read_location); | ||
| 411 | |||
| 412 | hv_signal_on_read(channel); | ||
| 413 | 330 | ||
| 414 | return 0; | 331 | return 0; |
| 415 | } | 332 | } |
| @@ -440,14 +357,16 @@ static u32 hv_pkt_iter_avail(const struct hv_ring_buffer_info *rbi) · 24 unmodified lines | |||
| 440 | struct vmpacket_descriptor *hv_pkt_iter_first(struct vmbus_channel *channel) | 357 | struct vmpacket_descriptor *hv_pkt_iter_first(struct vmbus_channel *channel) |
| 441 | { | 358 | { |
| 442 | struct hv_ring_buffer_info *rbi = &channel->inbound; | 359 | struct hv_ring_buffer_info *rbi = &channel->inbound; |
| 443 | 360 | struct vmpacket_descriptor *desc; | |
| 444 | /* set state for later hv_signal_on_read() */ | ||
| 445 | init_cached_read_index(rbi); | ||
| 446 | 361 | ||
| 447 | if (hv_pkt_iter_avail(rbi) < sizeof(struct vmpacket_descriptor)) | 362 | if (hv_pkt_iter_avail(rbi) < sizeof(struct vmpacket_descriptor)) |
| 448 | return NULL; | 363 | return NULL; |
| 449 | 364 | ||
| 450 | return hv_get_ring_buffer(rbi) + rbi->priv_read_index; | 365 | desc = hv_get_ring_buffer(rbi) + rbi->priv_read_index; |
| 366 | if (desc) | ||
| 367 | prefetch((char *)desc + (desc->len8 << 3)); | ||
| 368 | |||
| 369 | return desc; | ||
| 451 | } | 370 | } |
| 452 | EXPORT_SYMBOL_GPL(hv_pkt_iter_first); | 371 | EXPORT_SYMBOL_GPL(hv_pkt_iter_first); |
| 453 | 372 | ||
| @@ -471,10 +390,7 @@ __hv_pkt_iter_next(struct vmbus_channel *channel, · 17 unmodified lines | |||
| 471 | rbi->priv_read_index -= dsize; | 390 | rbi->priv_read_index -= dsize; |
| 472 | 391 | ||
| 473 | /* more data? */ | 392 | /* more data? */ |
| 474 | if (hv_pkt_iter_avail(rbi) < sizeof(struct vmpacket_descriptor)) | 393 | return hv_pkt_iter_first(channel); |
| 475 | return NULL; | ||
| 476 | else | ||
| 477 | return hv_get_ring_buffer(rbi) + rbi->priv_read_index; | ||
| 478 | } | 394 | } |
| 479 | EXPORT_SYMBOL_GPL(__hv_pkt_iter_next); | 395 | EXPORT_SYMBOL_GPL(__hv_pkt_iter_next); |
| 480 | 396 | ||
| @@ -484,6 +400,7 @@ EXPORT_SYMBOL_GPL(__hv_pkt_iter_next); · 3 unmodified lines | |||
| 484 | void hv_pkt_iter_close(struct vmbus_channel *channel) | 400 | void hv_pkt_iter_close(struct vmbus_channel *channel) |
| 485 | { | 401 | { |
| 486 | struct hv_ring_buffer_info *rbi = &channel->inbound; | 402 | struct hv_ring_buffer_info *rbi = &channel->inbound; |
| 403 | u32 orig_write_sz = hv_get_bytes_to_write(rbi); | ||
| 487 | 404 | ||
| 488 | /* | 405 | /* |
| 489 | * Make sure all reads are done before we update the read index since | 406 | * Make sure all reads are done before we update the read index since |
| @@ -493,6 +410,40 @@ void hv_pkt_iter_close(struct vmbus_channel *channel) · 3 unmodified lines | |||
| 493 | virt_rmb(); | 410 | virt_rmb(); |
| 494 | rbi->ring_buffer->read_index = rbi->priv_read_index; | 411 | rbi->ring_buffer->read_index = rbi->priv_read_index; |
| 495 | 412 | ||
| 496 | hv_signal_on_read(channel); | 413 | /* |
| 414 | * Issue a full memory barrier before making the signaling decision. | ||
| 415 | * Here is the reason for having this barrier: | ||
| 416 | * If the reading of the pend_sz (in this function) | ||
| 417 | * were to be reordered and read before we commit the new read | ||
| 418 | * index (in the calling function) we could | ||
| 419 | * have a problem. If the host were to set the pending_sz after we | ||
| 420 | * have sampled pending_sz and go to sleep before we commit the | ||
| 421 | * read index, we could miss sending the interrupt. Issue a full | ||
| 422 | * memory barrier to address this. | ||
| 423 | */ | ||
| 424 | virt_mb(); | ||
| 425 | |||
| 426 | /* If host has disabled notifications then skip */ | ||
| 427 | if (rbi->ring_buffer->interrupt_mask) | ||
| 428 | return; | ||
| 429 | |||
| 430 | if (rbi->ring_buffer->feature_bits.feat_pending_send_sz) { | ||
| 431 | u32 pending_sz = READ_ONCE(rbi->ring_buffer->pending_send_sz); | ||
| 432 | |||
| 433 | /* | ||
| 434 | * If there was space before we began iteration, | ||
| 435 | * then host was not blocked. Also handles case where | ||
| 436 | * pending_sz is zero then host has nothing pending | ||
| 437 | * and does not need to be signaled. | ||
| 438 | */ | ||
| 439 | if (orig_write_sz > pending_sz) | ||
| 440 | return; | ||
| 441 | |||
| 442 | /* If pending write will not fit, don't give false hope. */ | ||
| 443 | if (hv_get_bytes_to_write(rbi) < pending_sz) | ||
| 444 | return; | ||
| 445 | } | ||
| 446 | |||
| 447 | vmbus_setevent(channel); | ||
| 497 | } | 448 | } |
| 498 | EXPORT_SYMBOL_GPL(hv_pkt_iter_close); | 449 | EXPORT_SYMBOL_GPL(hv_pkt_iter_close); |
| @@ -940,6 +940,9 @@ static void vmbus_chan_sched(struct hv_per_cpu_context *hv_cpu) · 939 unmodified lines | |||
| 940 | if (channel->offermsg.child_relid != relid) | 940 | if (channel->offermsg.child_relid != relid) |
| 941 | continue; | 941 | continue; |
| 942 | 942 | ||
| 943 | if (channel->rescind) | ||
| 944 | continue; | ||
| 945 | |||
| 943 | switch (channel->callback_mode) { | 946 | switch (channel->callback_mode) { |
| 944 | case HV_CALL_ISR: | 947 | case HV_CALL_ISR: |
| 945 | vmbus_channel_isr(channel); | 948 | vmbus_channel_isr(channel); |
| @@ -70,13 +70,13 @@ config CORESIGHT_SOURCE_ETM4X · 69 unmodified lines | |||
| 70 | for instruction level tracing. Depending on the implemented version | 70 | for instruction level tracing. Depending on the implemented version |
| 71 | data tracing may also be available. | 71 | data tracing may also be available. |
| 72 | 72 | ||
| 73 | config CORESIGHT_QCOM_REPLICATOR | 73 | config CORESIGHT_DYNAMIC_REPLICATOR |
| 74 | bool "Qualcomm CoreSight Replicator driver" | 74 | bool "CoreSight Programmable Replicator driver" |
| 75 | depends on CORESIGHT_LINKS_AND_SINKS | 75 | depends on CORESIGHT_LINKS_AND_SINKS |
| 76 | help | 76 | help |
| 77 | This enables support for Qualcomm CoreSight link driver. The | 77 | This enables support for dynamic CoreSight replicator link driver. |
| 78 | programmable ATB replicator sends the ATB trace stream from the | 78 | The programmable ATB replicator allows independent filtering of the |
| 79 | ETB/ETF to the TPIUi and ETR. | 79 | trace data based on the traceid. |
| 80 | 80 | ||
| 81 | config CORESIGHT_STM | 81 | config CORESIGHT_STM |
| 82 | bool "CoreSight System Trace Macrocell driver" | 82 | bool "CoreSight System Trace Macrocell driver" |
| @@ -14,6 +14,6 @@ obj-$(CONFIG_CORESIGHT_SOURCE_ETM3X) += coresight-etm3x.o coresight-etm-cp14.o \ · 13 unmodified lines | |||
| 14 | coresight-etm3x-sysfs.o | 14 | coresight-etm3x-sysfs.o |
| 15 | obj-$(CONFIG_CORESIGHT_SOURCE_ETM4X) += coresight-etm4x.o \ | 15 | obj-$(CONFIG_CORESIGHT_SOURCE_ETM4X) += coresight-etm4x.o \ |
| 16 | coresight-etm4x-sysfs.o | 16 | coresight-etm4x-sysfs.o |
| 17 | obj-$(CONFIG_CORESIGHT_QCOM_REPLICATOR) += coresight-replicator-qcom.o | 17 | obj-$(CONFIG_CORESIGHT_DYNAMIC_REPLICATOR) += coresight-dynamic-replicator.o |
| 18 | obj-$(CONFIG_CORESIGHT_STM) += coresight-stm.o | 18 | obj-$(CONFIG_CORESIGHT_STM) += coresight-stm.o |
| 19 | obj-$(CONFIG_CORESIGHT_CPU_DEBUG) += coresight-cpu-debug.o | 19 | obj-$(CONFIG_CORESIGHT_CPU_DEBUG) += coresight-cpu-debug.o |
| @@ -667,7 +667,7 @@ static int debug_remove(struct amba_device *adev) · 666 unmodified lines | |||
| 667 | return 0; | 667 | return 0; |
| 668 | } | 668 | } |
| 669 | 669 | ||
| 670 | static struct amba_id debug_ids[] = { | 670 | static const struct amba_id debug_ids[] = { |
| 671 | { /* Debug for Cortex-A53 */ | 671 | { /* Debug for Cortex-A53 */ |
| 672 | .id = 0x000bbd03, | 672 | .id = 0x000bbd03, |
| 673 | .mask = 0x000fffff, | 673 | .mask = 0x000fffff, |
| @@ -95,6 +95,28 @@ static const struct coresight_ops replicator_cs_ops = { · 94 unmodified lines | |||
| 95 | .link_ops = &replicator_link_ops, | 95 | .link_ops = &replicator_link_ops, |
| 96 | }; | 96 | }; |
| 97 | 97 | ||
| 98 | #define coresight_replicator_reg(name, offset) \ | ||
| 99 | coresight_simple_reg32(struct replicator_state, name, offset) | ||
| 100 | |||
| 101 | coresight_replicator_reg(idfilter0, REPLICATOR_IDFILTER0); | ||
| 102 | coresight_replicator_reg(idfilter1, REPLICATOR_IDFILTER1); | ||
| 103 | |||
| 104 | static struct attribute *replicator_mgmt_attrs[] = { | ||
| 105 | &dev_attr_idfilter0.attr, | ||
| 106 | &dev_attr_idfilter1.attr, | ||
| 107 | NULL, | ||
| 108 | }; | ||
| 109 | |||
| 110 | static const struct attribute_group replicator_mgmt_group = { | ||
| 111 | .attrs = replicator_mgmt_attrs, | ||
| 112 | .name = "mgmt", | ||
| 113 | }; | ||
| 114 | |||
| 115 | static const struct attribute_group *replicator_groups[] = { | ||
| 116 | &replicator_mgmt_group, | ||
| 117 | NULL, | ||
| 118 | }; | ||
| 119 | |||
| 98 | static int replicator_probe(struct amba_device *adev, const struct amba_id *id) | 120 | static int replicator_probe(struct amba_device *adev, const struct amba_id *id) |
| 99 | { | 121 | { |
| 100 | int ret; | 122 | int ret; |
| @@ -139,11 +161,11 @@ static int replicator_probe(struct amba_device *adev, const struct amba_id *id) · 38 unmodified lines | |||
| 139 | desc.ops = &replicator_cs_ops; | 161 | desc.ops = &replicator_cs_ops; |
| 140 | desc.pdata = adev->dev.platform_data; | 162 | desc.pdata = adev->dev.platform_data; |
| 141 | desc.dev = &adev->dev; | 163 | desc.dev = &adev->dev; |
| 164 | desc.groups = replicator_groups; | ||
| 142 | drvdata->csdev = coresight_register(&desc); | 165 | drvdata->csdev = coresight_register(&desc); |
| 143 | if (IS_ERR(drvdata->csdev)) | 166 | if (IS_ERR(drvdata->csdev)) |
| 144 | return PTR_ERR(drvdata->csdev); | 167 | return PTR_ERR(drvdata->csdev); |
| 145 | 168 | ||
| 146 | dev_info(dev, "%s initialized\n", (char *)id->data); | ||
| 147 | return 0; | 169 | return 0; |
| 148 | } | 170 | } |
| 149 | 171 | ||
| @@ -175,18 +197,22 @@ static const struct dev_pm_ops replicator_dev_pm_ops = { · 25 unmodified lines | |||
| 175 | NULL) | 197 | NULL) |
| 176 | }; | 198 | }; |
| 177 | 199 | ||
| 178 | static struct amba_id replicator_ids[] = { | 200 | static const struct amba_id replicator_ids[] = { |
| 179 | { | 201 | { |
| 180 | .id = 0x0003b909, | 202 | .id = 0x0003b909, |
| 181 | .mask = 0x0003ffff, | 203 | .mask = 0x0003ffff, |
| 182 | .data = "REPLICATOR 1.0", | 204 | }, |
| 205 | { | ||
| 206 | /* Coresight SoC-600 */ | ||
| 207 | .id = 0x000bb9ec, | ||
| 208 | .mask = 0x000fffff, | ||
| 183 | }, | 209 | }, |
| 184 | { 0, 0 }, | 210 | { 0, 0 }, |
| 185 | }; | 211 | }; |
| 186 | 212 | ||
| 187 | static struct amba_driver replicator_driver = { | 213 | static struct amba_driver replicator_driver = { |
| 188 | .drv = { | 214 | .drv = { |
| 189 | .name = "coresight-replicator-qcom", | 215 | .name = "coresight-dynamic-replicator", |
| 190 | .pm = &replicator_dev_pm_ops, | 216 | .pm = &replicator_dev_pm_ops, |
| 191 | .suppress_bind_attrs = true, | 217 | .suppress_bind_attrs = true, |
| 192 | }, | 218 | }, |
| @@ -200,8 +200,10 @@ static void etb_disable_hw(struct etb_drvdata *drvdata) · 199 unmodified lines | |||
| 200 | 200 | ||
| 201 | static void etb_dump_hw(struct etb_drvdata *drvdata) | 201 | static void etb_dump_hw(struct etb_drvdata *drvdata) |
| 202 | { | 202 | { |
| 203 | bool lost = false; | ||
| 203 | int i; | 204 | int i; |
| 204 | u8 *buf_ptr; | 205 | u8 *buf_ptr; |
| 206 | const u32 *barrier; | ||
| 205 | u32 read_data, depth; | 207 | u32 read_data, depth; |
| 206 | u32 read_ptr, write_ptr; | 208 | u32 read_ptr, write_ptr; |
| 207 | u32 frame_off, frame_endoff; | 209 | u32 frame_off, frame_endoff; |
| @@ -223,20 +225,26 @@ static void etb_dump_hw(struct etb_drvdata *drvdata) · 15 unmodified lines | |||
| 223 | } | 225 | } |
| 224 | 226 | ||
| 225 | if ((readl_relaxed(drvdata->base + ETB_STATUS_REG) | 227 | if ((readl_relaxed(drvdata->base + ETB_STATUS_REG) |
| 226 | & ETB_STATUS_RAM_FULL) == 0) | 228 | & ETB_STATUS_RAM_FULL) == 0) { |
| 227 | writel_relaxed(0x0, drvdata->base + ETB_RAM_READ_POINTER); | 229 | writel_relaxed(0x0, drvdata->base + ETB_RAM_READ_POINTER); |
| 228 | else | 230 | } else { |
| 229 | writel_relaxed(write_ptr, drvdata->base + ETB_RAM_READ_POINTER); | 231 | writel_relaxed(write_ptr, drvdata->base + ETB_RAM_READ_POINTER); |
| 232 | lost = true; | ||
| 233 | } | ||
| 230 | 234 | ||
| 231 | depth = drvdata->buffer_depth; | 235 | depth = drvdata->buffer_depth; |
| 232 | buf_ptr = drvdata->buf; | 236 | buf_ptr = drvdata->buf; |
| 237 | barrier = barrier_pkt; | ||
| 233 | for (i = 0; i < depth; i++) { | 238 | for (i = 0; i < depth; i++) { |
| 234 | read_data = readl_relaxed(drvdata->base + | 239 | read_data = readl_relaxed(drvdata->base + |
| 235 | ETB_RAM_READ_DATA_REG); | 240 | ETB_RAM_READ_DATA_REG); |
| 236 | *buf_ptr++ = read_data >> 0; | 241 | if (lost && *barrier) { |
| 237 | *buf_ptr++ = read_data >> 8; | 242 | read_data = *barrier; |
| 238 | *buf_ptr++ = read_data >> 16; | 243 | barrier++; |
| 239 | *buf_ptr++ = read_data >> 24; | 244 | } |
| 245 | |||
| 246 | *(u32 *)buf_ptr = read_data; | ||
| 247 | buf_ptr += 4; | ||
| 240 | } | 248 | } |
| 241 | 249 | ||
| 242 | if (frame_off) { | 250 | if (frame_off) { |
| @@ -353,8 +361,10 @@ static void etb_update_buffer(struct coresight_device *csdev, · 110 unmodified lines | |||
| 353 | struct perf_output_handle *handle, | 361 | struct perf_output_handle *handle, |
| 354 | void *sink_config) | 362 | void *sink_config) |
| 355 | { | 363 | { |
| 364 | bool lost = false; | ||
| 356 | int i, cur; | 365 | int i, cur; |
| 357 | u8 *buf_ptr; | 366 | u8 *buf_ptr; |
| 367 | const u32 *barrier; | ||
| 358 | u32 read_ptr, write_ptr, capacity; | 368 | u32 read_ptr, write_ptr, capacity; |
| 359 | u32 status, read_data, to_read; | 369 | u32 status, read_data, to_read; |
| 360 | unsigned long offset; | 370 | unsigned long offset; |
| @@ -366,8 +376,8 @@ static void etb_update_buffer(struct coresight_device *csdev, · 5 unmodified lines | |||
| 366 | 376 | ||
| 367 | capacity = drvdata->buffer_depth * ETB_FRAME_SIZE_WORDS; | 377 | capacity = drvdata->buffer_depth * ETB_FRAME_SIZE_WORDS; |
| 368 | 378 | ||
| 369 | CS_UNLOCK(drvdata->base); | ||
| 370 | etb_disable_hw(drvdata); | 379 | etb_disable_hw(drvdata); |
| 380 | CS_UNLOCK(drvdata->base); | ||
| 371 | 381 | ||
| 372 | /* unit is in words, not bytes */ | 382 | /* unit is in words, not bytes */ |
| 373 | read_ptr = readl_relaxed(drvdata->base + ETB_RAM_READ_POINTER); | 383 | read_ptr = readl_relaxed(drvdata->base + ETB_RAM_READ_POINTER); |
| @@ -384,7 +394,7 @@ static void etb_update_buffer(struct coresight_device *csdev, · 10 unmodified lines | |||
| 384 | (unsigned long)write_ptr); | 394 | (unsigned long)write_ptr); |
| 385 | 395 | ||
| 386 | write_ptr &= ~(ETB_FRAME_SIZE_WORDS - 1); | 396 | write_ptr &= ~(ETB_FRAME_SIZE_WORDS - 1); |
| 387 | perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED); | 397 | lost = true; |
| 388 | } | 398 | } |
| 389 | 399 | ||
| 390 | /* | 400 | /* |
| @@ -395,7 +405,7 @@ static void etb_update_buffer(struct coresight_device *csdev, · 4 unmodified lines | |||
| 395 | */ | 405 | */ |
| 396 | status = readl_relaxed(drvdata->base + ETB_STATUS_REG); | 406 | status = readl_relaxed(drvdata->base + ETB_STATUS_REG); |
| 397 | if (status & ETB_STATUS_RAM_FULL) { | 407 | if (status & ETB_STATUS_RAM_FULL) { |
| 398 | perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED); | 408 | lost = true; |
| 399 | to_read = capacity; | 409 | to_read = capacity; |
| 400 | read_ptr = write_ptr; | 410 | read_ptr = write_ptr; |
| 401 | } else { | 411 | } else { |
| @@ -428,22 +438,30 @@ static void etb_update_buffer(struct coresight_device *csdev, · 26 unmodified lines | |||
| 428 | if (read_ptr > (drvdata->buffer_depth - 1)) | 438 | if (read_ptr > (drvdata->buffer_depth - 1)) |
| 429 | read_ptr -= drvdata->buffer_depth; | 439 | read_ptr -= drvdata->buffer_depth; |
| 430 | /* let the decoder know we've skipped ahead */ | 440 | /* let the decoder know we've skipped ahead */ |
| 431 | perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED); | 441 | lost = true; |
| 432 | } | 442 | } |
| 433 | 443 | ||
| 444 | if (lost) | ||
| 445 | perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED); | ||
| 446 | |||
| 434 | /* finally tell HW where we want to start reading from */ | 447 | /* finally tell HW where we want to start reading from */ |
| 435 | writel_relaxed(read_ptr, drvdata->base + ETB_RAM_READ_POINTER); | 448 | writel_relaxed(read_ptr, drvdata->base + ETB_RAM_READ_POINTER); |
| 436 | 449 | ||
| 437 | cur = buf->cur; | 450 | cur = buf->cur; |
| 438 | offset = buf->offset; | 451 | offset = buf->offset; |
| 452 | barrier = barrier_pkt; | ||
| 453 | |||
| 439 | for (i = 0; i < to_read; i += 4) { | 454 | for (i = 0; i < to_read; i += 4) { |
| 440 | buf_ptr = buf->data_pages[cur] + offset; | 455 | buf_ptr = buf->data_pages[cur] + offset; |
| 441 | read_data = readl_relaxed(drvdata->base + | 456 | read_data = readl_relaxed(drvdata->base + |
| 442 | ETB_RAM_READ_DATA_REG); | 457 | ETB_RAM_READ_DATA_REG); |
| 443 | *buf_ptr++ = read_data >> 0; | 458 | if (lost && *barrier) { |
| 444 | *buf_ptr++ = read_data >> 8; | 459 | read_data = *barrier; |
| 445 | *buf_ptr++ = read_data >> 16; | 460 | barrier++; |
| 446 | *buf_ptr++ = read_data >> 24; | 461 | } |
| 462 | |||
| 463 | *(u32 *)buf_ptr = read_data; | ||
| 464 | buf_ptr += 4; | ||
| 447 | 465 | ||
| 448 | offset += 4; | 466 | offset += 4; |
| 449 | if (offset >= PAGE_SIZE) { | 467 | if (offset >= PAGE_SIZE) { |
| @@ -557,17 +575,17 @@ static const struct file_operations etb_fops = { · 107 unmodified lines | |||
| 557 | .llseek = no_llseek, | 575 | .llseek = no_llseek, |
| 558 | }; | 576 | }; |
| 559 | 577 | ||
| 560 | #define coresight_etb10_simple_func(name, offset) \ | 578 | #define coresight_etb10_reg(name, offset) \ |
| 561 | coresight_simple_func(struct etb_drvdata, NULL, name, offset) | 579 | coresight_simple_reg32(struct etb_drvdata, name, offset) |
| 562 | 580 | ||
| 563 | coresight_etb10_simple_func(rdp, ETB_RAM_DEPTH_REG); | 581 | coresight_etb10_reg(rdp, ETB_RAM_DEPTH_REG); |
| 564 | coresight_etb10_simple_func(sts, ETB_STATUS_REG); | 582 | coresight_etb10_reg(sts, ETB_STATUS_REG); |
| 565 | coresight_etb10_simple_func(rrp, ETB_RAM_READ_POINTER); | 583 | coresight_etb10_reg(rrp, ETB_RAM_READ_POINTER); |
| 566 | coresight_etb10_simple_func(rwp, ETB_RAM_WRITE_POINTER); | 584 | coresight_etb10_reg(rwp, ETB_RAM_WRITE_POINTER); |
| 567 | coresight_etb10_simple_func(trg, ETB_TRG); | 585 | coresight_etb10_reg(trg, ETB_TRG); |
| 568 | coresight_etb10_simple_func(ctl, ETB_CTL_REG); | 586 | coresight_etb10_reg(ctl, ETB_CTL_REG); |
| 569 | coresight_etb10_simple_func(ffsr, ETB_FFSR); | 587 | coresight_etb10_reg(ffsr, ETB_FFSR); |
| 570 | coresight_etb10_simple_func(ffcr, ETB_FFCR); | 588 | coresight_etb10_reg(ffcr, ETB_FFCR); |
| 571 | 589 | ||
| 572 | static struct attribute *coresight_etb_mgmt_attrs[] = { | 590 | static struct attribute *coresight_etb_mgmt_attrs[] = { |
| 573 | &dev_attr_rdp.attr, | 591 | &dev_attr_rdp.attr, |
| @@ -728,7 +746,7 @@ static const struct dev_pm_ops etb_dev_pm_ops = { · 154 unmodified lines | |||
| 728 | SET_RUNTIME_PM_OPS(etb_runtime_suspend, etb_runtime_resume, NULL) | 746 | SET_RUNTIME_PM_OPS(etb_runtime_suspend, etb_runtime_resume, NULL) |
| 729 | }; | 747 | }; |
| 730 | 748 | ||
| 731 | static struct amba_id etb_ids[] = { | 749 | static const struct amba_id etb_ids[] = { |
| 732 | { | 750 | { |
| 733 | .id = 0x0003b907, | 751 | .id = 0x0003b907, |
| 734 | .mask = 0x0003ffff, | 752 | .mask = 0x0003ffff, |
| @@ -53,14 +53,16 @@ static DEFINE_PER_CPU(struct coresight_device *, csdev_src); · 52 unmodified lines | |||
| 53 | /* ETMv3.5/PTM's ETMCR is 'config' */ | 53 | /* ETMv3.5/PTM's ETMCR is 'config' */ |
| 54 | PMU_FORMAT_ATTR(cycacc, "config:" __stringify(ETM_OPT_CYCACC)); | 54 | PMU_FORMAT_ATTR(cycacc, "config:" __stringify(ETM_OPT_CYCACC)); |
| 55 | PMU_FORMAT_ATTR(timestamp, "config:" __stringify(ETM_OPT_TS)); | 55 | PMU_FORMAT_ATTR(timestamp, "config:" __stringify(ETM_OPT_TS)); |
| 56 | PMU_FORMAT_ATTR(retstack, "config:" __stringify(ETM_OPT_RETSTK)); | ||
| 56 | 57 | ||
| 57 | static struct attribute *etm_config_formats_attr[] = { | 58 | static struct attribute *etm_config_formats_attr[] = { |
| 58 | &format_attr_cycacc.attr, | 59 | &format_attr_cycacc.attr, |
| 59 | &format_attr_timestamp.attr, | 60 | &format_attr_timestamp.attr, |
| 61 | &format_attr_retstack.attr, | ||
| 60 | NULL, | 62 | NULL, |
| 61 | }; | 63 | }; |
| 62 | 64 | ||
| 63 | static struct attribute_group etm_pmu_format_group = { | 65 | static const struct attribute_group etm_pmu_format_group = { |
| 64 | .name = "format", | 66 | .name = "format", |
| 65 | .attrs = etm_config_formats_attr, | 67 | .attrs = etm_config_formats_attr, |
| 66 | }; | 68 | }; |
| @@ -106,6 +106,7 @@ · 105 unmodified lines | |||
| 106 | #define ETMTECR1_START_STOP BIT(25) | 106 | #define ETMTECR1_START_STOP BIT(25) |
| 107 | /* ETMCCER - 0x1E8 */ | 107 | /* ETMCCER - 0x1E8 */ |
| 108 | #define ETMCCER_TIMESTAMP BIT(22) | 108 | #define ETMCCER_TIMESTAMP BIT(22) |
| 109 | #define ETMCCER_RETSTACK BIT(23) | ||
| 109 | 110 | ||
| 110 | #define ETM_MODE_EXCLUDE BIT(0) | 111 | #define ETM_MODE_EXCLUDE BIT(0) |
| 111 | #define ETM_MODE_CYCACC BIT(1) | 112 | #define ETM_MODE_CYCACC BIT(1) |
| @@ -1232,19 +1232,19 @@ static struct attribute *coresight_etm_attrs[] = { · 1231 unmodified lines | |||
| 1232 | NULL, | 1232 | NULL, |
| 1233 | }; | 1233 | }; |
| 1234 | 1234 | ||
| 1235 | #define coresight_etm3x_simple_func(name, offset) \ | 1235 | #define coresight_etm3x_reg(name, offset) \ |
| 1236 | coresight_simple_func(struct etm_drvdata, NULL, name, offset) | 1236 | coresight_simple_reg32(struct etm_drvdata, name, offset) |
| 1237 | 1237 | ||
| 1238 | coresight_etm3x_simple_func(etmccr, ETMCCR); | 1238 | coresight_etm3x_reg(etmccr, ETMCCR); |
| 1239 | coresight_etm3x_simple_func(etmccer, ETMCCER); | 1239 | coresight_etm3x_reg(etmccer, ETMCCER); |
| 1240 | coresight_etm3x_simple_func(etmscr, ETMSCR); | 1240 | coresight_etm3x_reg(etmscr, ETMSCR); |
| 1241 | coresight_etm3x_simple_func(etmidr, ETMIDR); | 1241 | coresight_etm3x_reg(etmidr, ETMIDR); |
| 1242 | coresight_etm3x_simple_func(etmcr, ETMCR); | 1242 | coresight_etm3x_reg(etmcr, ETMCR); |
| 1243 | coresight_etm3x_simple_func(etmtraceidr, ETMTRACEIDR); | 1243 | coresight_etm3x_reg(etmtraceidr, ETMTRACEIDR); |
| 1244 | coresight_etm3x_simple_func(etmteevr, ETMTEEVR); | 1244 | coresight_etm3x_reg(etmteevr, ETMTEEVR); |
| 1245 | coresight_etm3x_simple_func(etmtssvr, ETMTSSCR); | 1245 | coresight_etm3x_reg(etmtssvr, ETMTSSCR); |
| 1246 | coresight_etm3x_simple_func(etmtecr1, ETMTECR1); | 1246 | coresight_etm3x_reg(etmtecr1, ETMTECR1); |
| 1247 | coresight_etm3x_simple_func(etmtecr2, ETMTECR2); | 1247 | coresight_etm3x_reg(etmtecr2, ETMTECR2); |
| 1248 | 1248 | ||
| 1249 | static struct attribute *coresight_etm_mgmt_attrs[] = { | 1249 | static struct attribute *coresight_etm_mgmt_attrs[] = { |
| 1250 | &dev_attr_etmccr.attr, | 1250 | &dev_attr_etmccr.attr, |
| @@ -243,6 +243,8 @@ void etm_set_default(struct etm_config *config) · 242 unmodified lines | |||
| 243 | } | 243 | } |
| 244 | 244 | ||
| 245 | config->ctxid_mask = 0x0; | 245 | config->ctxid_mask = 0x0; |
| 246 | /* Setting default to 1024 as per TRM recommendation */ | ||
| 247 | config->sync_freq = 0x400; | ||
| 246 | } | 248 | } |
| 247 | 249 | ||
| 248 | void etm_config_trace_mode(struct etm_config *config) | 250 | void etm_config_trace_mode(struct etm_config *config) |
| @@ -308,7 +310,9 @@ void etm_config_trace_mode(struct etm_config *config) · 59 unmodified lines | |||
| 308 | config->addr_type[1] = ETM_ADDR_TYPE_RANGE; | 310 | config->addr_type[1] = ETM_ADDR_TYPE_RANGE; |
| 309 | } | 311 | } |
| 310 | 312 | ||
| 311 | #define ETM3X_SUPPORTED_OPTIONS (ETMCR_CYC_ACC | ETMCR_TIMESTAMP_EN) | 313 | #define ETM3X_SUPPORTED_OPTIONS (ETMCR_CYC_ACC | \ |
| 314 | ETMCR_TIMESTAMP_EN | \ | ||
| 315 | ETMCR_RETURN_STACK) | ||
| 312 | 316 | ||
| 313 | static int etm_parse_event_config(struct etm_drvdata *drvdata, | 317 | static int etm_parse_event_config(struct etm_drvdata *drvdata, |
| 314 | struct perf_event *event) | 318 | struct perf_event *event) |
| @@ -339,14 +343,24 @@ static int etm_parse_event_config(struct etm_drvdata *drvdata, · 24 unmodified lines | |||
| 339 | etm_config_trace_mode(config); | 343 | etm_config_trace_mode(config); |
| 340 | 344 | ||
| 341 | /* | 345 | /* |
| 342 | * At this time only cycle accurate and timestamp options are | 346 | * At this time only cycle accurate, return stack and timestamp |
| 343 | * available. | 347 | * options are available. |
| 344 | */ | 348 | */ |
| 345 | if (attr->config & ~ETM3X_SUPPORTED_OPTIONS) | 349 | if (attr->config & ~ETM3X_SUPPORTED_OPTIONS) |
| 346 | return -EINVAL; | 350 | return -EINVAL; |
| 347 | 351 | ||
| 348 | config->ctrl = attr->config; | 352 | config->ctrl = attr->config; |
| 349 | 353 | ||
| 354 | /* | ||
| 355 | * Possible to have cores with PTM (supports ret stack) and ETM | ||
| 356 | * (never has ret stack) on the same SoC. So if we have a request | ||
| 357 | * for return stack that can't be honoured on this core then | ||
| 358 | * clear the bit - trace will still continue normally | ||
| 359 | */ | ||
| 360 | if ((config->ctrl & ETMCR_RETURN_STACK) && | ||
| 361 | !(drvdata->etmccer & ETMCCER_RETSTACK)) | ||
| 362 | config->ctrl &= ~ETMCR_RETURN_STACK; | ||
| 363 | |||
| 350 | return 0; | 364 | return 0; |
| 351 | } | 365 | } |
| 352 | 366 | ||
| @@ -885,7 +899,7 @@ static const struct dev_pm_ops etm_dev_pm_ops = { · 532 unmodified lines | |||
| 885 | SET_RUNTIME_PM_OPS(etm_runtime_suspend, etm_runtime_resume, NULL) | 899 | SET_RUNTIME_PM_OPS(etm_runtime_suspend, etm_runtime_resume, NULL) |
| 886 | }; | 900 | }; |
| 887 | 901 | ||
| 888 | static struct amba_id etm_ids[] = { | 902 | static const struct amba_id etm_ids[] = { |
| 889 | { /* ETM 3.3 */ | 903 | { /* ETM 3.3 */ |
| 890 | .id = 0x0003b921, | 904 | .id = 0x0003b921, |
| 891 | .mask = 0x0003ffff, | 905 | .mask = 0x0003ffff, |
| @@ -2066,23 +2066,23 @@ static u32 etmv4_cross_read(const struct device *dev, u32 offset) · 2065 unmodified lines | |||
| 2066 | return reg.data; | 2066 | return reg.data; |
| 2067 | } | 2067 | } |
| 2068 | 2068 | ||
| 2069 | #define coresight_etm4x_simple_func(name, offset) \ | 2069 | #define coresight_etm4x_reg(name, offset) \ |
| 2070 | coresight_simple_func(struct etmv4_drvdata, NULL, name, offset) | 2070 | coresight_simple_reg32(struct etmv4_drvdata, name, offset) |
| 2071 | 2071 | ||
| 2072 | #define coresight_etm4x_cross_read(name, offset) \ | 2072 | #define coresight_etm4x_cross_read(name, offset) \ |
| 2073 | coresight_simple_func(struct etmv4_drvdata, etmv4_cross_read, \ | 2073 | coresight_simple_func(struct etmv4_drvdata, etmv4_cross_read, \ |
| 2074 | name, offset) | 2074 | name, offset) |
| 2075 | 2075 | ||
| 2076 | coresight_etm4x_simple_func(trcpdcr, TRCPDCR); | 2076 | coresight_etm4x_reg(trcpdcr, TRCPDCR); |
| 2077 | coresight_etm4x_simple_func(trcpdsr, TRCPDSR); | 2077 | coresight_etm4x_reg(trcpdsr, TRCPDSR); |
| 2078 | coresight_etm4x_simple_func(trclsr, TRCLSR); | 2078 | coresight_etm4x_reg(trclsr, TRCLSR); |
| 2079 | coresight_etm4x_simple_func(trcauthstatus, TRCAUTHSTATUS); | 2079 | coresight_etm4x_reg(trcauthstatus, TRCAUTHSTATUS); |
| 2080 | coresight_etm4x_simple_func(trcdevid, TRCDEVID); | 2080 | coresight_etm4x_reg(trcdevid, TRCDEVID); |
| 2081 | coresight_etm4x_simple_func(trcdevtype, TRCDEVTYPE); | 2081 | coresight_etm4x_reg(trcdevtype, TRCDEVTYPE); |
| 2082 | coresight_etm4x_simple_func(trcpidr0, TRCPIDR0); | 2082 | coresight_etm4x_reg(trcpidr0, TRCPIDR0); |
| 2083 | coresight_etm4x_simple_func(trcpidr1, TRCPIDR1); | 2083 | coresight_etm4x_reg(trcpidr1, TRCPIDR1); |
| 2084 | coresight_etm4x_simple_func(trcpidr2, TRCPIDR2); | 2084 | coresight_etm4x_reg(trcpidr2, TRCPIDR2); |
| 2085 | coresight_etm4x_simple_func(trcpidr3, TRCPIDR3); | 2085 | coresight_etm4x_reg(trcpidr3, TRCPIDR3); |
| 2086 | coresight_etm4x_cross_read(trcoslsr, TRCOSLSR); | 2086 | coresight_etm4x_cross_read(trcoslsr, TRCOSLSR); |
| 2087 | coresight_etm4x_cross_read(trcconfig, TRCCONFIGR); | 2087 | coresight_etm4x_cross_read(trcconfig, TRCCONFIGR); |
| 2088 | coresight_etm4x_cross_read(trctraceid, TRCTRACEIDR); | 2088 | coresight_etm4x_cross_read(trctraceid, TRCTRACEIDR); |
| @@ -224,6 +224,10 @@ static int etm4_parse_event_config(struct etmv4_drvdata *drvdata, · 223 unmodified lines | |||
| 224 | if (attr->config & BIT(ETM_OPT_TS)) | 224 | if (attr->config & BIT(ETM_OPT_TS)) |
| 225 | /* bit[11], Global timestamp tracing bit */ | 225 | /* bit[11], Global timestamp tracing bit */ |
| 226 | config->cfg |= BIT(11); | 226 | config->cfg |= BIT(11); |
| 227 | /* return stack - enable if selected and supported */ | ||
| 228 | if ((attr->config & BIT(ETM_OPT_RETSTK)) && drvdata->retstack) | ||
| 229 | /* bit[12], Return stack enable bit */ | ||
| 230 | config->cfg |= BIT(12); | ||
| 227 | 231 | ||
| 228 | out: | 232 | out: |
| 229 | return ret; | 233 | return ret; |
| @@ -1048,7 +1052,7 @@ err_arch_supported: · 818 unmodified lines | |||
| 1048 | return ret; | 1052 | return ret; |
| 1049 | } | 1053 | } |
| 1050 | 1054 | ||
| 1051 | static struct amba_id etm4_ids[] = { | 1055 | static const struct amba_id etm4_ids[] = { |
| 1052 | { /* ETM 4.0 - Cortex-A53 */ | 1056 | { /* ETM 4.0 - Cortex-A53 */ |
| 1053 | .id = 0x000bb95d, | 1057 | .id = 0x000bb95d, |
| 1054 | .mask = 0x000fffff, | 1058 | .mask = 0x000fffff, |
| @@ -246,11 +246,16 @@ static const struct dev_pm_ops funnel_dev_pm_ops = { · 245 unmodified lines | |||
| 246 | SET_RUNTIME_PM_OPS(funnel_runtime_suspend, funnel_runtime_resume, NULL) | 246 | SET_RUNTIME_PM_OPS(funnel_runtime_suspend, funnel_runtime_resume, NULL) |
| 247 | }; | 247 | }; |
| 248 | 248 | ||
| 249 | static struct amba_id funnel_ids[] = { | 249 | static const struct amba_id funnel_ids[] = { |
| 250 | { | 250 | { |
| 251 | .id = 0x0003b908, | 251 | .id = 0x0003b908, |
| 252 | .mask = 0x0003ffff, | 252 | .mask = 0x0003ffff, |
| 253 | }, | 253 | }, |
| 254 | { | ||
| 255 | /* Coresight SoC-600 */ | ||
| 256 | .id = 0x000bb9eb, | ||
| 257 | .mask = 0x000fffff, | ||
| 258 | }, | ||
| 254 | { 0, 0}, | 259 | { 0, 0}, |
| 255 | }; | 260 | }; |
| 256 | 261 | ||
| @@ -39,23 +39,33 @@ · 38 unmodified lines | |||
| 39 | #define ETM_MODE_EXCL_USER BIT(31) | 39 | #define ETM_MODE_EXCL_USER BIT(31) |
| 40 | 40 | ||
| 41 | typedef u32 (*coresight_read_fn)(const struct device *, u32 offset); | 41 | typedef u32 (*coresight_read_fn)(const struct device *, u32 offset); |
| 42 | #define coresight_simple_func(type, func, name, offset) \ | 42 | #define __coresight_simple_func(type, func, name, lo_off, hi_off) \ |
| 43 | static ssize_t name##_show(struct device *_dev, \ | 43 | static ssize_t name##_show(struct device *_dev, \ |
| 44 | struct device_attribute *attr, char *buf) \ | 44 | struct device_attribute *attr, char *buf) \ |
| 45 | { \ | 45 | { \ |
| 46 | type *drvdata = dev_get_drvdata(_dev->parent); \ | 46 | type *drvdata = dev_get_drvdata(_dev->parent); \ |
| 47 | coresight_read_fn fn = func; \ | 47 | coresight_read_fn fn = func; \ |
| 48 | u32 val; \ | 48 | u64 val; \ |
| 49 | pm_runtime_get_sync(_dev->parent); \ | 49 | pm_runtime_get_sync(_dev->parent); \ |
| 50 | if (fn) \ | 50 | if (fn) \ |
| 51 | val = fn(_dev->parent, offset); \ | 51 | val = (u64)fn(_dev->parent, lo_off); \ |
| 52 | else \ | 52 | else \ |
| 53 | val = readl_relaxed(drvdata->base + offset); \ | 53 | val = coresight_read_reg_pair(drvdata->base, \ |
| 54 | lo_off, hi_off); \ | ||
| 54 | pm_runtime_put_sync(_dev->parent); \ | 55 | pm_runtime_put_sync(_dev->parent); \ |
| 55 | return scnprintf(buf, PAGE_SIZE, "0x%x\n", val); \ | 56 | return scnprintf(buf, PAGE_SIZE, "0x%llx\n", val); \ |
| 56 | } \ | 57 | } \ |
| 57 | static DEVICE_ATTR_RO(name) | 58 | static DEVICE_ATTR_RO(name) |
| 58 | 59 | ||
| 60 | #define coresight_simple_func(type, func, name, offset) \ | ||
| 61 | __coresight_simple_func(type, func, name, offset, -1) | ||
| 62 | #define coresight_simple_reg32(type, name, offset) \ | ||
| 63 | __coresight_simple_func(type, NULL, name, offset, -1) | ||
| 64 | #define coresight_simple_reg64(type, name, lo_off, hi_off) \ | ||
| 65 | __coresight_simple_func(type, NULL, name, lo_off, hi_off) | ||
| 66 | |||
| 67 | extern const u32 barrier_pkt[5]; | ||
| 68 | |||
| 59 | enum etm_addr_type { | 69 | enum etm_addr_type { |
| 60 | ETM_ADDR_TYPE_NONE, | 70 | ETM_ADDR_TYPE_NONE, |
| 61 | ETM_ADDR_TYPE_SINGLE, | 71 | ETM_ADDR_TYPE_SINGLE, |
| @@ -106,6 +116,25 @@ static inline void CS_UNLOCK(void __iomem *addr) · 44 unmodified lines | |||
| 106 | } while (0); | 116 | } while (0); |
| 107 | } | 117 | } |
| 108 | 118 | ||
| 119 | static inline u64 | ||
| 120 | coresight_read_reg_pair(void __iomem *addr, s32 lo_offset, s32 hi_offset) | ||
| 121 | { | ||
| 122 | u64 val; | ||
| 123 | |||
| 124 | val = readl_relaxed(addr + lo_offset); | ||
| 125 | val |= (hi_offset < 0) ? 0 : | ||
| 126 | (u64)readl_relaxed(addr + hi_offset) << 32; | ||
| 127 | return val; | ||
| 128 | } | ||
| 129 | |||
| 130 | static inline void coresight_write_reg_pair(void __iomem *addr, u64 val, | ||
| 131 | s32 lo_offset, s32 hi_offset) | ||
| 132 | { | ||
| 133 | writel_relaxed((u32)val, addr + lo_offset); | ||
| 134 | if (hi_offset >= 0) | ||
| 135 | writel_relaxed((u32)(val >> 32), addr + hi_offset); | ||
| 136 | } | ||
| 137 | |||
| 109 | void coresight_disable_path(struct list_head *path); | 138 | void coresight_disable_path(struct list_head *path); |
| 110 | int coresight_enable_path(struct list_head *path, u32 mode); | 139 | int coresight_enable_path(struct list_head *path, u32 mode); |
| 111 | struct coresight_device *coresight_get_sink(struct list_head *path); | 140 | struct coresight_device *coresight_get_sink(struct list_head *path); |
| @@ -276,7 +276,7 @@ static void stm_disable(struct coresight_device *csdev, · 275 unmodified lines | |||
| 276 | spin_unlock(&drvdata->spinlock); | 276 | spin_unlock(&drvdata->spinlock); |
| 277 | 277 | ||
| 278 | /* Wait until the engine has completely stopped */ | 278 | /* Wait until the engine has completely stopped */ |
| 279 | coresight_timeout(drvdata, STMTCSR, STMTCSR_BUSY_BIT, 0); | 279 | coresight_timeout(drvdata->base, STMTCSR, STMTCSR_BUSY_BIT, 0); |
| 280 | 280 | ||
| 281 | pm_runtime_put(drvdata->dev); | 281 | pm_runtime_put(drvdata->dev); |
| 282 | 282 | ||
| @@ -307,7 +307,8 @@ static inline bool stm_addr_unaligned(const void *addr, u8 write_bytes) · 24 unmodified lines | |||
| 307 | return ((unsigned long)addr & (write_bytes - 1)); | 307 | return ((unsigned long)addr & (write_bytes - 1)); |
| 308 | } | 308 | } |
| 309 | 309 | ||
| 310 | static void stm_send(void *addr, const void *data, u32 size, u8 write_bytes) | 310 | static void stm_send(void __iomem *addr, const void *data, |
| 311 | u32 size, u8 write_bytes) | ||
| 311 | { | 312 | { |
| 312 | u8 paload[8]; | 313 | u8 paload[8]; |
| 313 | 314 | ||
| @@ -414,7 +415,7 @@ static ssize_t notrace stm_generic_packet(struct stm_data *stm_data, · 100 unmodified lines | |||
| 414 | unsigned int size, | 415 | unsigned int size, |
| 415 | const unsigned char *payload) | 416 | const unsigned char *payload) |
| 416 | { | 417 | { |
| 417 | unsigned long ch_addr; | 418 | void __iomem *ch_addr; |
| 418 | struct stm_drvdata *drvdata = container_of(stm_data, | 419 | struct stm_drvdata *drvdata = container_of(stm_data, |
| 419 | struct stm_drvdata, stm); | 420 | struct stm_drvdata, stm); |
| 420 | 421 | ||
| @@ -424,7 +425,7 @@ static ssize_t notrace stm_generic_packet(struct stm_data *stm_data, · 3 unmodified lines | |||
| 424 | if (channel >= drvdata->numsp) | 425 | if (channel >= drvdata->numsp) |
| 425 | return -EINVAL; | 426 | return -EINVAL; |
| 426 | 427 | ||
| 427 | ch_addr = (unsigned long)stm_channel_addr(drvdata, channel); | 428 | ch_addr = stm_channel_addr(drvdata, channel); |
| 428 | 429 | ||
| 429 | flags = (flags == STP_PACKET_TIMESTAMPED) ? STM_FLAG_TIMESTAMPED : 0; | 430 | flags = (flags == STP_PACKET_TIMESTAMPED) ? STM_FLAG_TIMESTAMPED : 0; |
| 430 | flags |= test_bit(channel, drvdata->chs.guaranteed) ? | 431 | flags |= test_bit(channel, drvdata->chs.guaranteed) ? |
| @@ -437,20 +438,20 @@ static ssize_t notrace stm_generic_packet(struct stm_data *stm_data, · 6 unmodified lines | |||
| 437 | 438 | ||
| 438 | switch (packet) { | 439 | switch (packet) { |
| 439 | case STP_PACKET_FLAG: | 440 | case STP_PACKET_FLAG: |
| 440 | ch_addr |= stm_channel_off(STM_PKT_TYPE_FLAG, flags); | 441 | ch_addr += stm_channel_off(STM_PKT_TYPE_FLAG, flags); |
| 441 | 442 | ||
| 442 | /* | 443 | /* |
| 443 | * The generic STM core sets a size of '0' on flag packets. | 444 | * The generic STM core sets a size of '0' on flag packets. |
| 444 | * As such send a flag packet of size '1' and tell the | 445 | * As such send a flag packet of size '1' and tell the |
| 445 | * core we did so. | 446 | * core we did so. |
| 446 | */ | 447 | */ |
| 447 | stm_send((void *)ch_addr, payload, 1, drvdata->write_bytes); | 448 | stm_send(ch_addr, payload, 1, drvdata->write_bytes); |
| 448 | size = 1; | 449 | size = 1; |
| 449 | break; | 450 | break; |
| 450 | 451 | ||
| 451 | case STP_PACKET_DATA: | 452 | case STP_PACKET_DATA: |
| 452 | ch_addr |= stm_channel_off(STM_PKT_TYPE_DATA, flags); | 453 | ch_addr += stm_channel_off(STM_PKT_TYPE_DATA, flags); |
| 453 | stm_send((void *)ch_addr, payload, size, | 454 | stm_send(ch_addr, payload, size, |
| 454 | drvdata->write_bytes); | 455 | drvdata->write_bytes); |
| 455 | break; | 456 | break; |
| 456 | 457 | ||
| @@ -635,21 +636,21 @@ static ssize_t traceid_store(struct device *dev, · 178 unmodified lines | |||
| 635 | } | 636 | } |
| 636 | static DEVICE_ATTR_RW(traceid); | 637 | static DEVICE_ATTR_RW(traceid); |
| 637 | 638 | ||
| 638 | #define coresight_stm_simple_func(name, offset) \ | 639 | #define coresight_stm_reg(name, offset) \ |
| 639 | coresight_simple_func(struct stm_drvdata, NULL, name, offset) | 640 | coresight_simple_reg32(struct stm_drvdata, name, offset) |
| 640 | 641 | ||
| 641 | coresight_stm_simple_func(tcsr, STMTCSR); | 642 | coresight_stm_reg(tcsr, STMTCSR); |
| 642 | coresight_stm_simple_func(tsfreqr, STMTSFREQR); | 643 | coresight_stm_reg(tsfreqr, STMTSFREQR); |
| 643 | coresight_stm_simple_func(syncr, STMSYNCR); | 644 | coresight_stm_reg(syncr, STMSYNCR); |
| 644 | coresight_stm_simple_func(sper, STMSPER); | 645 | coresight_stm_reg(sper, STMSPER); |
| 645 | coresight_stm_simple_func(spter, STMSPTER); | 646 | coresight_stm_reg(spter, STMSPTER); |
| 646 | coresight_stm_simple_func(privmaskr, STMPRIVMASKR); | 647 | coresight_stm_reg(privmaskr, STMPRIVMASKR); |
| 647 | coresight_stm_simple_func(spscr, STMSPSCR); | 648 | coresight_stm_reg(spscr, STMSPSCR); |
| 648 | coresight_stm_simple_func(spmscr, STMSPMSCR); | 649 | coresight_stm_reg(spmscr, STMSPMSCR); |
| 649 | coresight_stm_simple_func(spfeat1r, STMSPFEAT1R); | 650 | coresight_stm_reg(spfeat1r, STMSPFEAT1R); |
| 650 | coresight_stm_simple_func(spfeat2r, STMSPFEAT2R); | 651 | coresight_stm_reg(spfeat2r, STMSPFEAT2R); |
| 651 | coresight_stm_simple_func(spfeat3r, STMSPFEAT3R); | 652 | coresight_stm_reg(spfeat3r, STMSPFEAT3R); |
| 652 | coresight_stm_simple_func(devid, CORESIGHT_DEVID); | 653 | coresight_stm_reg(devid, CORESIGHT_DEVID); |
| 653 | 654 | ||
| 654 | static struct attribute *coresight_stm_attrs[] = { | 655 | static struct attribute *coresight_stm_attrs[] = { |
| 655 | &dev_attr_hwevent_enable.attr, | 656 | &dev_attr_hwevent_enable.attr, |
| @@ -914,7 +915,7 @@ static const struct dev_pm_ops stm_dev_pm_ops = { · 258 unmodified lines | |||
| 914 | SET_RUNTIME_PM_OPS(stm_runtime_suspend, stm_runtime_resume, NULL) | 915 | SET_RUNTIME_PM_OPS(stm_runtime_suspend, stm_runtime_resume, NULL) |
| 915 | }; | 916 | }; |
| 916 | 917 | ||
| 917 | static struct amba_id stm_ids[] = { | 918 | static const struct amba_id stm_ids[] = { |
| 918 | { | 919 | { |
| 919 | .id = 0x0003b962, | 920 | .id = 0x0003b962, |
| 920 | .mask = 0x0003ffff, | 921 | .mask = 0x0003ffff, |
| @@ -43,17 +43,34 @@ static void tmc_etb_enable_hw(struct tmc_drvdata *drvdata) · 42 unmodified lines | |||
| 43 | 43 | ||
| 44 | static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata) | 44 | static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata) |
| 45 | { | 45 | { |
| 46 | bool lost = false; | ||
| 46 | char *bufp; | 47 | char *bufp; |
| 47 | u32 read_data; | 48 | const u32 *barrier; |
| 49 | u32 read_data, status; | ||
| 48 | int i; | 50 | int i; |
| 49 | 51 | ||
| 52 | /* | ||
| 53 | * Get a hold of the status register and see if a wrap around | ||
| 54 | * has occurred. | ||
| 55 | */ | ||
| 56 | status = readl_relaxed(drvdata->base + TMC_STS); | ||
| 57 | if (status & TMC_STS_FULL) | ||
| 58 | lost = true; | ||
| 59 | |||
| 50 | bufp = drvdata->buf; | 60 | bufp = drvdata->buf; |
| 51 | drvdata->len = 0; | 61 | drvdata->len = 0; |
| 62 | barrier = barrier_pkt; | ||
| 52 | while (1) { | 63 | while (1) { |
| 53 | for (i = 0; i < drvdata->memwidth; i++) { | 64 | for (i = 0; i < drvdata->memwidth; i++) { |
| 54 | read_data = readl_relaxed(drvdata->base + TMC_RRD); | 65 | read_data = readl_relaxed(drvdata->base + TMC_RRD); |
| 55 | if (read_data == 0xFFFFFFFF) | 66 | if (read_data == 0xFFFFFFFF) |
| 56 | return; | 67 | return; |
| 68 | |||
| 69 | if (lost && *barrier) { | ||
| 70 | read_data = *barrier; | ||
| 71 | barrier++; | ||
| 72 | } | ||
| 73 | |||
| 57 | memcpy(bufp, &read_data, 4); | 74 | memcpy(bufp, &read_data, 4); |
| 58 | bufp += 4; | 75 | bufp += 4; |
| 59 | drvdata->len += 4; | 76 | drvdata->len += 4; |
| @@ -369,9 +386,11 @@ static void tmc_update_etf_buffer(struct coresight_device *csdev, · 309 unmodified lines | |||
| 369 | struct perf_output_handle *handle, | 386 | struct perf_output_handle *handle, |
| 370 | void *sink_config) | 387 | void *sink_config) |
| 371 | { | 388 | { |
| 389 | bool lost = false; | ||
| 372 | int i, cur; | 390 | int i, cur; |
| 391 | const u32 *barrier; | ||
| 373 | u32 *buf_ptr; | 392 | u32 *buf_ptr; |
| 374 | u32 read_ptr, write_ptr; | 393 | u64 read_ptr, write_ptr; |
| 375 | u32 status, to_read; | 394 | u32 status, to_read; |
| 376 | unsigned long offset; | 395 | unsigned long offset; |
| 377 | struct cs_buffers *buf = sink_config; | 396 | struct cs_buffers *buf = sink_config; |
| @@ -388,8 +407,8 @@ static void tmc_update_etf_buffer(struct coresight_device *csdev, · 10 unmodified lines | |||
| 388 | 407 | ||
| 389 | tmc_flush_and_stop(drvdata); | 408 | tmc_flush_and_stop(drvdata); |
| 390 | 409 | ||
| 391 | read_ptr = readl_relaxed(drvdata->base + TMC_RRP); | 410 | read_ptr = tmc_read_rrp(drvdata); |
| 392 | write_ptr = readl_relaxed(drvdata->base + TMC_RWP); | 411 | write_ptr = tmc_read_rwp(drvdata); |
| 393 | 412 | ||
| 394 | /* | 413 | /* |
| 395 | * Get a hold of the status register and see if a wrap around | 414 | * Get a hold of the status register and see if a wrap around |
| @@ -397,7 +416,7 @@ static void tmc_update_etf_buffer(struct coresight_device *csdev, · 1 unmodified line | |||
| 397 | */ | 416 | */ |
| 398 | status = readl_relaxed(drvdata->base + TMC_STS); | 417 | status = readl_relaxed(drvdata->base + TMC_STS); |
| 399 | if (status & TMC_STS_FULL) { | 418 | if (status & TMC_STS_FULL) { |
| 400 | perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED); | 419 | lost = true; |
| 401 | to_read = drvdata->size; | 420 | to_read = drvdata->size; |
| 402 | } else { | 421 | } else { |
| 403 | to_read = CIRC_CNT(write_ptr, read_ptr, drvdata->size); | 422 | to_read = CIRC_CNT(write_ptr, read_ptr, drvdata->size); |
| @@ -441,18 +460,27 @@ static void tmc_update_etf_buffer(struct coresight_device *csdev, · 37 unmodified lines | |||
| 441 | if (read_ptr > (drvdata->size - 1)) | 460 | if (read_ptr > (drvdata->size - 1)) |
| 442 | read_ptr -= drvdata->size; | 461 | read_ptr -= drvdata->size; |
| 443 | /* Tell the HW */ | 462 | /* Tell the HW */ |
| 444 | writel_relaxed(read_ptr, drvdata->base + TMC_RRP); | 463 | tmc_write_rrp(drvdata, read_ptr); |
| 445 | perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED); | 464 | lost = true; |
| 446 | } | 465 | } |
| 447 | 466 | ||
| 467 | if (lost) | ||
| 468 | perf_aux_output_flag(handle, PERF_AUX_FLAG_TRUNCATED); | ||
| 469 | |||
| 448 | cur = buf->cur; | 470 | cur = buf->cur; |
| 449 | offset = buf->offset; | 471 | offset = buf->offset; |
| 472 | barrier = barrier_pkt; | ||
| 450 | 473 | ||
| 451 | /* for every byte to read */ | 474 | /* for every byte to read */ |
| 452 | for (i = 0; i < to_read; i += 4) { | 475 | for (i = 0; i < to_read; i += 4) { |
| 453 | buf_ptr = buf->data_pages[cur] + offset; | 476 | buf_ptr = buf->data_pages[cur] + offset; |
| 454 | *buf_ptr = readl_relaxed(drvdata->base + TMC_RRD); | 477 | *buf_ptr = readl_relaxed(drvdata->base + TMC_RRD); |
| 455 | 478 | ||
| 479 | if (lost && *barrier) { | ||
| 480 | *buf_ptr = *barrier; | ||
| 481 | barrier++; | ||
| 482 | } | ||
| 483 | |||
| 456 | offset += 4; | 484 | offset += 4; |
| 457 | if (offset >= PAGE_SIZE) { | 485 | if (offset >= PAGE_SIZE) { |
| 458 | offset = 0; | 486 | offset = 0; |
| @@ -22,7 +22,7 @@ · 21 unmodified lines | |||
| 22 | 22 | ||
| 23 | static void tmc_etr_enable_hw(struct tmc_drvdata *drvdata) | 23 | static void tmc_etr_enable_hw(struct tmc_drvdata *drvdata) |
| 24 | { | 24 | { |
| 25 | u32 axictl; | 25 | u32 axictl, sts; |
| 26 | 26 | ||
| 27 | /* Zero out the memory to help with debug */ | 27 | /* Zero out the memory to help with debug */ |
| 28 | memset(drvdata->vaddr, 0, drvdata->size); | 28 | memset(drvdata->vaddr, 0, drvdata->size); |
| @@ -36,17 +36,29 @@ static void tmc_etr_enable_hw(struct tmc_drvdata *drvdata) · 7 unmodified lines | |||
| 36 | writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE); | 36 | writel_relaxed(TMC_MODE_CIRCULAR_BUFFER, drvdata->base + TMC_MODE); |
| 37 | 37 | ||
| 38 | axictl = readl_relaxed(drvdata->base + TMC_AXICTL); | 38 | axictl = readl_relaxed(drvdata->base + TMC_AXICTL); |
| 39 | axictl |= TMC_AXICTL_WR_BURST_16; | 39 | axictl &= ~TMC_AXICTL_CLEAR_MASK; |
| 40 | writel_relaxed(axictl, drvdata->base + TMC_AXICTL); | 40 | axictl |= (TMC_AXICTL_PROT_CTL_B1 | TMC_AXICTL_WR_BURST_16); |
| 41 | axictl &= ~TMC_AXICTL_SCT_GAT_MODE; | 41 | axictl |= TMC_AXICTL_AXCACHE_OS; |
| 42 | writel_relaxed(axictl, drvdata->base + TMC_AXICTL); | 42 | |
| 43 | axictl = (axictl & | 43 | if (tmc_etr_has_cap(drvdata, TMC_ETR_AXI_ARCACHE)) { |
| 44 | ~(TMC_AXICTL_PROT_CTL_B0 | TMC_AXICTL_PROT_CTL_B1)) | | 44 | axictl &= ~TMC_AXICTL_ARCACHE_MASK; |
| 45 | TMC_AXICTL_PROT_CTL_B1; | 45 | axictl |= TMC_AXICTL_ARCACHE_OS; |
| 46 | } | ||
| 47 | |||
| 46 | writel_relaxed(axictl, drvdata->base + TMC_AXICTL); | 48 | writel_relaxed(axictl, drvdata->base + TMC_AXICTL); |
| 49 | tmc_write_dba(drvdata, drvdata->paddr); | ||
| 50 | /* | ||
| 51 | * If the TMC pointers must be programmed before the session, | ||
| 52 | * we have to set it properly (i.e, RRP/RWP to base address and | ||
| 53 | * STS to "not full"). | ||
| 54 | */ | ||
| 55 | if (tmc_etr_has_cap(drvdata, TMC_ETR_SAVE_RESTORE)) { | ||
| 56 | tmc_write_rrp(drvdata, drvdata->paddr); | ||
| 57 | tmc_write_rwp(drvdata, drvdata->paddr); | ||
| 58 | sts = readl_relaxed(drvdata->base + TMC_STS) & ~TMC_STS_FULL; | ||
| 59 | writel_relaxed(sts, drvdata->base + TMC_STS); | ||
| 60 | } | ||
| 47 | 61 | ||
| 48 | writel_relaxed(drvdata->paddr, drvdata->base + TMC_DBALO); | ||
| 49 | writel_relaxed(0x0, drvdata->base + TMC_DBAHI); | ||
| 50 | writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI | | 62 | writel_relaxed(TMC_FFCR_EN_FMT | TMC_FFCR_EN_TI | |
| 51 | TMC_FFCR_FON_FLIN | TMC_FFCR_FON_TRIG_EVT | | 63 | TMC_FFCR_FON_FLIN | TMC_FFCR_FON_TRIG_EVT | |
| 52 | TMC_FFCR_TRIGON_TRIGIN, | 64 | TMC_FFCR_TRIGON_TRIGIN, |
| @@ -59,9 +71,12 @@ static void tmc_etr_enable_hw(struct tmc_drvdata *drvdata) · 6 unmodified lines | |||
| 59 | 71 | ||
| 60 | static void tmc_etr_dump_hw(struct tmc_drvdata *drvdata) | 72 | static void tmc_etr_dump_hw(struct tmc_drvdata *drvdata) |
| 61 | { | 73 | { |
| 62 | u32 rwp, val; | 74 | const u32 *barrier; |
| 75 | u32 val; | ||
| 76 | u32 *temp; | ||
| 77 | u64 rwp; | ||
| 63 | 78 | ||
| 64 | rwp = readl_relaxed(drvdata->base + TMC_RWP); | 79 | rwp = tmc_read_rwp(drvdata); |
| 65 | val = readl_relaxed(drvdata->base + TMC_STS); | 80 | val = readl_relaxed(drvdata->base + TMC_STS); |
| 66 | 81 | ||
| 67 | /* | 82 | /* |
| @@ -71,6 +86,16 @@ static void tmc_etr_dump_hw(struct tmc_drvdata *drvdata) · 3 unmodified lines | |||
| 71 | if (val & TMC_STS_FULL) { | 86 | if (val & TMC_STS_FULL) { |
| 72 | drvdata->buf = drvdata->vaddr + rwp - drvdata->paddr; | 87 | drvdata->buf = drvdata->vaddr + rwp - drvdata->paddr; |
| 73 | drvdata->len = drvdata->size; | 88 | drvdata->len = drvdata->size; |
| 89 | |||
| 90 | barrier = barrier_pkt; | ||
| 91 | temp = (u32 *)drvdata->buf; | ||
| 92 | |||
| 93 | while (*barrier) { | ||
| 94 | *temp = *barrier; | ||
| 95 | temp++; | ||
| 96 | barrier++; | ||
| 97 | } | ||
| 98 | |||
| 74 | } else { | 99 | } else { |
| 75 | drvdata->buf = drvdata->vaddr; | 100 | drvdata->buf = drvdata->vaddr; |
| 76 | drvdata->len = rwp - drvdata->paddr; | 101 | drvdata->len = rwp - drvdata->paddr; |
| @@ -217,20 +217,24 @@ static enum tmc_mem_intf_width tmc_get_memwidth(u32 devid) · 216 unmodified lines | |||
| 217 | return memwidth; | 217 | return memwidth; |
| 218 | } | 218 | } |
| 219 | 219 | ||
| 220 | #define coresight_tmc_simple_func(name, offset) \ | 220 | #define coresight_tmc_reg(name, offset) \ |
| 221 | coresight_simple_func(struct tmc_drvdata, NULL, name, offset) | 221 | coresight_simple_reg32(struct tmc_drvdata, name, offset) |
| 222 | 222 | #define coresight_tmc_reg64(name, lo_off, hi_off) \ | |
| 223 | coresight_tmc_simple_func(rsz, TMC_RSZ); | 223 | coresight_simple_reg64(struct tmc_drvdata, name, lo_off, hi_off) |
| 224 | coresight_tmc_simple_func(sts, TMC_STS); | 224 | |
| 225 | coresight_tmc_simple_func(rrp, TMC_RRP); | 225 | coresight_tmc_reg(rsz, TMC_RSZ); |
| 226 | coresight_tmc_simple_func(rwp, TMC_RWP); | 226 | coresight_tmc_reg(sts, TMC_STS); |
| 227 | coresight_tmc_simple_func(trg, TMC_TRG); | 227 | coresight_tmc_reg(trg, TMC_TRG); |
| 228 | coresight_tmc_simple_func(ctl, TMC_CTL); | 228 | coresight_tmc_reg(ctl, TMC_CTL); |
| 229 | coresight_tmc_simple_func(ffsr, TMC_FFSR); | 229 | coresight_tmc_reg(ffsr, TMC_FFSR); |
| 230 | coresight_tmc_simple_func(ffcr, TMC_FFCR); | 230 | coresight_tmc_reg(ffcr, TMC_FFCR); |
| 231 | coresight_tmc_simple_func(mode, TMC_MODE); | 231 | coresight_tmc_reg(mode, TMC_MODE); |
| 232 | coresight_tmc_simple_func(pscr, TMC_PSCR); | 232 | coresight_tmc_reg(pscr, TMC_PSCR); |
| 233 | coresight_tmc_simple_func(devid, CORESIGHT_DEVID); | 233 | coresight_tmc_reg(axictl, TMC_AXICTL); |
| 234 | coresight_tmc_reg(devid, CORESIGHT_DEVID); | ||
| 235 | coresight_tmc_reg64(rrp, TMC_RRP, TMC_RRPHI); | ||
| 236 | coresight_tmc_reg64(rwp, TMC_RWP, TMC_RWPHI); | ||
| 237 | coresight_tmc_reg64(dba, TMC_DBALO, TMC_DBAHI); | ||
| 234 | 238 | ||
| 235 | static struct attribute *coresight_tmc_mgmt_attrs[] = { | 239 | static struct attribute *coresight_tmc_mgmt_attrs[] = { |
| 236 | &dev_attr_rsz.attr, | 240 | &dev_attr_rsz.attr, |
| @@ -244,6 +248,8 @@ static struct attribute *coresight_tmc_mgmt_attrs[] = { · 7 unmodified lines | |||
| 244 | &dev_attr_mode.attr, | 248 | &dev_attr_mode.attr, |
| 245 | &dev_attr_pscr.attr, | 249 | &dev_attr_pscr.attr, |
| 246 | &dev_attr_devid.attr, | 250 | &dev_attr_devid.attr, |
| 251 | &dev_attr_dba.attr, | ||
| 252 | &dev_attr_axictl.attr, | ||
| 247 | NULL, | 253 | NULL, |
| 248 | }; | 254 | }; |
| 249 | 255 | ||
| @@ -293,6 +299,42 @@ const struct attribute_group *coresight_tmc_groups[] = { · 43 unmodified lines | |||
| 293 | NULL, | 299 | NULL, |
| 294 | }; | 300 | }; |
| 295 | 301 | ||
| 302 | /* Detect and initialise the capabilities of a TMC ETR */ | ||
| 303 | static int tmc_etr_setup_caps(struct tmc_drvdata *drvdata, | ||
| 304 | u32 devid, void *dev_caps) | ||
| 305 | { | ||
| 306 | u32 dma_mask = 0; | ||
| 307 | |||
| 308 | /* Set the unadvertised capabilities */ | ||
| 309 | tmc_etr_init_caps(drvdata, (u32)(unsigned long)dev_caps); | ||
| 310 | |||
| 311 | if (!(devid & TMC_DEVID_NOSCAT)) | ||
| 312 | tmc_etr_set_cap(drvdata, TMC_ETR_SG); | ||
| 313 | |||
| 314 | /* Check if the AXI address width is available */ | ||
| 315 | if (devid & TMC_DEVID_AXIAW_VALID) | ||
| 316 | dma_mask = ((devid >> TMC_DEVID_AXIAW_SHIFT) & | ||
| 317 | TMC_DEVID_AXIAW_MASK); | ||
| 318 | |||
| 319 | /* | ||
| 320 | * Unless specified in the device configuration, ETR uses a 40-bit | ||
| 321 | * AXI master in place of the embedded SRAM of ETB/ETF. | ||
| 322 | */ | ||
| 323 | switch (dma_mask) { | ||
| 324 | case 32: | ||
| 325 | case 40: | ||
| 326 | case 44: | ||
| 327 | case 48: | ||
| 328 | case 52: | ||
| 329 | dev_info(drvdata->dev, "Detected dma mask %dbits\n", dma_mask); | ||
| 330 | break; | ||
| 331 | default: | ||
| 332 | dma_mask = 40; | ||
| 333 | } | ||
| 334 | |||
| 335 | return dma_set_mask_and_coherent(drvdata->dev, DMA_BIT_MASK(dma_mask)); | ||
| 336 | } | ||
| 337 | |||
| 296 | static int tmc_probe(struct amba_device *adev, const struct amba_id *id) | 338 | static int tmc_probe(struct amba_device *adev, const struct amba_id *id) |
| 297 | { | 339 | { |
| 298 | int ret = 0; | 340 | int ret = 0; |
| @@ -354,25 +396,29 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id) · 55 unmodified lines | |||
| 354 | desc.dev = dev; | 396 | desc.dev = dev; |
| 355 | desc.groups = coresight_tmc_groups; | 397 | desc.groups = coresight_tmc_groups; |
| 356 | 398 | ||
| 357 | if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) { | 399 | switch (drvdata->config_type) { |
| 400 | case TMC_CONFIG_TYPE_ETB: | ||
| 358 | desc.type = CORESIGHT_DEV_TYPE_SINK; | 401 | desc.type = CORESIGHT_DEV_TYPE_SINK; |
| 359 | desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER; | 402 | desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER; |
| 360 | desc.ops = &tmc_etb_cs_ops; | 403 | desc.ops = &tmc_etb_cs_ops; |
| 361 | } else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) { | 404 | break; |
| 405 | case TMC_CONFIG_TYPE_ETR: | ||
| 362 | desc.type = CORESIGHT_DEV_TYPE_SINK; | 406 | desc.type = CORESIGHT_DEV_TYPE_SINK; |
| 363 | desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER; | 407 | desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER; |
| 364 | desc.ops = &tmc_etr_cs_ops; | 408 | desc.ops = &tmc_etr_cs_ops; |
| 365 | /* | 409 | ret = tmc_etr_setup_caps(drvdata, devid, id->data); |
| 366 | * ETR configuration uses a 40-bit AXI master in place of | ||
| 367 | * the embedded SRAM of ETB/ETF. | ||
| 368 | */ | ||
| 369 | ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40)); | ||
| 370 | if (ret) | 410 | if (ret) |
| 371 | goto out; | 411 | goto out; |
| 372 | } else { | 412 | break; |
| 413 | case TMC_CONFIG_TYPE_ETF: | ||
| 373 | desc.type = CORESIGHT_DEV_TYPE_LINKSINK; | 414 | desc.type = CORESIGHT_DEV_TYPE_LINKSINK; |
| 374 | desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_FIFO; | 415 | desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_FIFO; |
| 375 | desc.ops = &tmc_etf_cs_ops; | 416 | desc.ops = &tmc_etf_cs_ops; |
| 417 | break; | ||
| 418 | default: | ||
| 419 | pr_err("%s: Unsupported TMC config\n", pdata->name); | ||
| 420 | ret = -EINVAL; | ||
| 421 | goto out; | ||
| 376 | } | 422 | } |
| 377 | 423 | ||
| 378 | drvdata->csdev = coresight_register(&desc); | 424 | drvdata->csdev = coresight_register(&desc); |
| @@ -391,11 +437,27 @@ out: · 12 unmodified lines | |||
| 391 | return ret; | 437 | return ret; |
| 392 | } | 438 | } |
| 393 | 439 | ||
| 394 | static struct amba_id tmc_ids[] = { | 440 | static const struct amba_id tmc_ids[] = { |
| 395 | { | 441 | { |
| 396 | .id = 0x0003b961, | 442 | .id = 0x0003b961, |
| 397 | .mask = 0x0003ffff, | 443 | .mask = 0x0003ffff, |
| 398 | }, | 444 | }, |
| 445 | { | ||
| 446 | /* Coresight SoC 600 TMC-ETR/ETS */ | ||
| 447 | .id = 0x000bb9e8, | ||
| 448 | .mask = 0x000fffff, | ||
| 449 | .data = (void *)(unsigned long)CORESIGHT_SOC_600_ETR_CAPS, | ||
| 450 | }, | ||
| 451 | { | ||
| 452 | /* Coresight SoC 600 TMC-ETB */ | ||
| 453 | .id = 0x000bb9e9, | ||
| 454 | .mask = 0x000fffff, | ||
| 455 | }, | ||
| 456 | { | ||
| 457 | /* Coresight SoC 600 TMC-ETF */ | ||
| 458 | .id = 0x000bb9ea, | ||
| 459 | .mask = 0x000fffff, | ||
| 460 | }, | ||
| 399 | { 0, 0}, | 461 | { 0, 0}, |
| 400 | }; | 462 | }; |
| 401 | 463 | ||
| @@ -54,11 +54,32 @@ · 53 unmodified lines | |||
| 54 | #define TMC_STS_TMCREADY_BIT 2 | 54 | #define TMC_STS_TMCREADY_BIT 2 |
| 55 | #define TMC_STS_FULL BIT(0) | 55 | #define TMC_STS_FULL BIT(0) |
| 56 | #define TMC_STS_TRIGGERED BIT(1) | 56 | #define TMC_STS_TRIGGERED BIT(1) |
| 57 | /* TMC_AXICTL - 0x110 */ | 57 | /* |
| 58 | * TMC_AXICTL - 0x110 | ||
| 59 | * | ||
| 60 | * TMC AXICTL format for SoC-400 | ||
| 61 | * Bits [0-1] : ProtCtrlBit0-1 | ||
| 62 | * Bits [2-5] : CacheCtrlBits 0-3 (AXCACHE) | ||
| 63 | * Bit 6 : Reserved | ||
| 64 | * Bit 7 : ScatterGatherMode | ||
| 65 | * Bits [8-11] : WrBurstLen | ||
| 66 | * Bits [12-31] : Reserved. | ||
| 67 | * TMC AXICTL format for SoC-600, as above except: | ||
| 68 | * Bits [2-5] : AXI WCACHE | ||
| 69 | * Bits [16-19] : AXI RCACHE | ||
| 70 | * Bits [20-31] : Reserved | ||
| 71 | */ | ||
| 72 | #define TMC_AXICTL_CLEAR_MASK 0xfbf | ||
| 73 | #define TMC_AXICTL_ARCACHE_MASK (0xf << 16) | ||
| 74 | |||
| 58 | #define TMC_AXICTL_PROT_CTL_B0 BIT(0) | 75 | #define TMC_AXICTL_PROT_CTL_B0 BIT(0) |
| 59 | #define TMC_AXICTL_PROT_CTL_B1 BIT(1) | 76 | #define TMC_AXICTL_PROT_CTL_B1 BIT(1) |
| 60 | #define TMC_AXICTL_SCT_GAT_MODE BIT(7) | 77 | #define TMC_AXICTL_SCT_GAT_MODE BIT(7) |
| 61 | #define TMC_AXICTL_WR_BURST_16 0xF00 | 78 | #define TMC_AXICTL_WR_BURST_16 0xF00 |
| 79 | /* Write-back Read and Write-allocate */ | ||
| 80 | #define TMC_AXICTL_AXCACHE_OS (0xf << 2) | ||
| 81 | #define TMC_AXICTL_ARCACHE_OS (0xf << 16) | ||
| 82 | |||
| 62 | /* TMC_FFCR - 0x304 */ | 83 | /* TMC_FFCR - 0x304 */ |
| 63 | #define TMC_FFCR_FLUSHMAN_BIT 6 | 84 | #define TMC_FFCR_FLUSHMAN_BIT 6 |
| 64 | #define TMC_FFCR_EN_FMT BIT(0) | 85 | #define TMC_FFCR_EN_FMT BIT(0) |
| @@ -69,6 +90,12 @@ · 4 unmodified lines | |||
| 69 | #define TMC_FFCR_STOP_ON_FLUSH BIT(12) | 90 | #define TMC_FFCR_STOP_ON_FLUSH BIT(12) |
| 70 | 91 | ||
| 71 | 92 | ||
| 93 | #define TMC_DEVID_NOSCAT BIT(24) | ||
| 94 | |||
| 95 | #define TMC_DEVID_AXIAW_VALID BIT(16) | ||
| 96 | #define TMC_DEVID_AXIAW_SHIFT 17 | ||
| 97 | #define TMC_DEVID_AXIAW_MASK 0x7f | ||
| 98 | |||
| 72 | enum tmc_config_type { | 99 | enum tmc_config_type { |
| 73 | TMC_CONFIG_TYPE_ETB, | 100 | TMC_CONFIG_TYPE_ETB, |
| 74 | TMC_CONFIG_TYPE_ETR, | 101 | TMC_CONFIG_TYPE_ETR, |
| @@ -88,6 +115,24 @@ enum tmc_mem_intf_width { · 13 unmodified lines | |||
| 88 | TMC_MEM_INTF_WIDTH_256BITS = 8, | 115 | TMC_MEM_INTF_WIDTH_256BITS = 8, |
| 89 | }; | 116 | }; |
| 90 | 117 | ||
| 118 | /* TMC ETR Capability bit definitions */ | ||
| 119 | #define TMC_ETR_SG (0x1U << 0) | ||
| 120 | /* ETR has separate read/write cache encodings */ | ||
| 121 | #define TMC_ETR_AXI_ARCACHE (0x1U << 1) | ||
| 122 | /* | ||
| 123 | * TMC_ETR_SAVE_RESTORE - Values of RRP/RWP/STS.Full are | ||
| 124 | * retained when TMC leaves Disabled state, allowing us to continue | ||
| 125 | * the tracing from a point where we stopped. This also implies that | ||
| 126 | * the RRP/RWP/STS.Full should always be programmed to the correct | ||
| 127 | * value. Unfortunately this is not advertised by the hardware, | ||
| 128 | * so we have to rely on PID of the IP to detect the functionality. | ||
| 129 | */ | ||
| 130 | #define TMC_ETR_SAVE_RESTORE (0x1U << 2) | ||
| 131 | |||
| 132 | /* Coresight SoC-600 TMC-ETR unadvertised capabilities */ | ||
| 133 | #define CORESIGHT_SOC_600_ETR_CAPS \ | ||
| 134 | (TMC_ETR_SAVE_RESTORE | TMC_ETR_AXI_ARCACHE) | ||
| 135 | |||
| 91 | /** | 136 | /** |
| 92 | * struct tmc_drvdata - specifics associated to an TMC component | 137 | * struct tmc_drvdata - specifics associated to an TMC component |
| 93 | * @base: memory mapped base address for this component. | 138 | * @base: memory mapped base address for this component. |
| @@ -104,6 +149,8 @@ enum tmc_mem_intf_width { · 10 unmodified lines | |||
| 104 | * @config_type: TMC variant, must be of type @tmc_config_type. | 149 | * @config_type: TMC variant, must be of type @tmc_config_type. |
| 105 | * @memwidth: width of the memory interface databus, in bytes. | 150 | * @memwidth: width of the memory interface databus, in bytes. |
| 106 | * @trigger_cntr: amount of words to store after a trigger. | 151 | * @trigger_cntr: amount of words to store after a trigger. |
| 152 | * @etr_caps: Bitmask of capabilities of the TMC ETR, inferred from the | ||
| 153 | * device configuration register (DEVID) | ||
| 107 | */ | 154 | */ |
| 108 | struct tmc_drvdata { | 155 | struct tmc_drvdata { |
| 109 | void __iomem *base; | 156 | void __iomem *base; |
| @@ -121,6 +168,7 @@ struct tmc_drvdata { · 11 unmodified lines | |||
| 121 | enum tmc_config_type config_type; | 168 | enum tmc_config_type config_type; |
| 122 | enum tmc_mem_intf_width memwidth; | 169 | enum tmc_mem_intf_width memwidth; |
| 123 | u32 trigger_cntr; | 170 | u32 trigger_cntr; |
| 171 | u32 etr_caps; | ||
| 124 | }; | 172 | }; |
| 125 | 173 | ||
| 126 | /* Generic functions */ | 174 | /* Generic functions */ |
| @@ -139,4 +187,39 @@ extern const struct coresight_ops tmc_etf_cs_ops; · 12 unmodified lines | |||
| 139 | int tmc_read_prepare_etr(struct tmc_drvdata *drvdata); | 187 | int tmc_read_prepare_etr(struct tmc_drvdata *drvdata); |
| 140 | int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata); | 188 | int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata); |
| 141 | extern const struct coresight_ops tmc_etr_cs_ops; | 189 | extern const struct coresight_ops tmc_etr_cs_ops; |
| 190 | |||
| 191 | |||
| 192 | #define TMC_REG_PAIR(name, lo_off, hi_off) \ | ||
| 193 | static inline u64 \ | ||
| 194 | tmc_read_##name(struct tmc_drvdata *drvdata) \ | ||
| 195 | { \ | ||
| 196 | return coresight_read_reg_pair(drvdata->base, lo_off, hi_off); \ | ||
| 197 | } \ | ||
| 198 | static inline void \ | ||
| 199 | tmc_write_##name(struct tmc_drvdata *drvdata, u64 val) \ | ||
| 200 | { \ | ||
| 201 | coresight_write_reg_pair(drvdata->base, val, lo_off, hi_off); \ | ||
| 202 | } | ||
| 203 | |||
| 204 | TMC_REG_PAIR(rrp, TMC_RRP, TMC_RRPHI) | ||
| 205 | TMC_REG_PAIR(rwp, TMC_RWP, TMC_RWPHI) | ||
| 206 | TMC_REG_PAIR(dba, TMC_DBALO, TMC_DBAHI) | ||
| 207 | |||
| 208 | /* Initialise the caps from unadvertised static capabilities of the device */ | ||
| 209 | static inline void tmc_etr_init_caps(struct tmc_drvdata *drvdata, u32 dev_caps) | ||
| 210 | { | ||
| 211 | WARN_ON(drvdata->etr_caps); | ||
| 212 | drvdata->etr_caps = dev_caps; | ||
| 213 | } | ||
| 214 | |||
| 215 | static inline void tmc_etr_set_cap(struct tmc_drvdata *drvdata, u32 cap) | ||
| 216 | { | ||
| 217 | drvdata->etr_caps |= cap; | ||
| 218 | } | ||
| 219 | |||
| 220 | static inline bool tmc_etr_has_cap(struct tmc_drvdata *drvdata, u32 cap) | ||
| 221 | { | ||
| 222 | return !!(drvdata->etr_caps & cap); | ||
| 223 | } | ||
| 224 | |||
| 142 | #endif | 225 | #endif |
| @@ -192,7 +192,7 @@ static const struct dev_pm_ops tpiu_dev_pm_ops = { · 191 unmodified lines | |||
| 192 | SET_RUNTIME_PM_OPS(tpiu_runtime_suspend, tpiu_runtime_resume, NULL) | 192 | SET_RUNTIME_PM_OPS(tpiu_runtime_suspend, tpiu_runtime_resume, NULL) |
| 193 | }; | 193 | }; |
| 194 | 194 | ||
| 195 | static struct amba_id tpiu_ids[] = { | 195 | static const struct amba_id tpiu_ids[] = { |
| 196 | { | 196 | { |
| 197 | .id = 0x0003b912, | 197 | .id = 0x0003b912, |
| 198 | .mask = 0x0003ffff, | 198 | .mask = 0x0003ffff, |
| @@ -201,6 +201,11 @@ static struct amba_id tpiu_ids[] = { · 2 unmodified lines | |||
| 201 | .id = 0x0004b912, | 201 | .id = 0x0004b912, |
| 202 | .mask = 0x0007ffff, | 202 | .mask = 0x0007ffff, |
| 203 | }, | 203 | }, |
| 204 | { | ||
| 205 | /* Coresight SoC-600 */ | ||
| 206 | .id = 0x000bb9e7, | ||
| 207 | .mask = 0x000fffff, | ||
| 208 | }, | ||
| 204 | { 0, 0}, | 209 | { 0, 0}, |
| 205 | }; | 210 | }; |
| 206 | 211 | ||
| @@ -53,6 +53,14 @@ static DEFINE_PER_CPU(struct list_head *, tracer_path); · 52 unmodified lines | |||
| 53 | */ | 53 | */ |
| 54 | static struct list_head *stm_path; | 54 | static struct list_head *stm_path; |
| 55 | 55 | ||
| 56 | /* | ||
| 57 | * When losing synchronisation a new barrier packet needs to be inserted at the | ||
| 58 | * beginning of the data collected in a buffer. That way the decoder knows that | ||
| 59 | * it needs to look for another sync sequence. | ||
| 60 | */ | ||
| 61 | const u32 barrier_pkt[5] = {0x7fffffff, 0x7fffffff, | ||
| 62 | 0x7fffffff, 0x7fffffff, 0x0}; | ||
| 63 | |||
| 56 | static int coresight_id_match(struct device *dev, void *data) | 64 | static int coresight_id_match(struct device *dev, void *data) |
| 57 | { | 65 | { |
| 58 | int trace_id, i_trace_id; | 66 | int trace_id, i_trace_id; |
| @@ -101,17 +101,53 @@ out_pm: · 100 unmodified lines | |||
| 101 | return ret; | 101 | return ret; |
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | static void intel_th_device_remove(struct intel_th_device *thdev); | ||
| 105 | |||
| 104 | static int intel_th_remove(struct device *dev) | 106 | static int intel_th_remove(struct device *dev) |
| 105 | { | 107 | { |
| 106 | struct intel_th_driver *thdrv = to_intel_th_driver(dev->driver); | 108 | struct intel_th_driver *thdrv = to_intel_th_driver(dev->driver); |
| 107 | struct intel_th_device *thdev = to_intel_th_device(dev); | 109 | struct intel_th_device *thdev = to_intel_th_device(dev); |
| 108 | struct intel_th_device *hub = to_intel_th_device(dev->parent); | 110 | struct intel_th_device *hub = to_intel_th_hub(thdev); |
| 109 | int err; | 111 | int err; |
| 110 | 112 | ||
| 111 | if (thdev->type == INTEL_TH_SWITCH) { | 113 | if (thdev->type == INTEL_TH_SWITCH) { |
| 114 | struct intel_th *th = to_intel_th(hub); | ||
| 115 | int i, lowest; | ||
| 116 | |||
| 117 | /* disconnect outputs */ | ||
| 112 | err = device_for_each_child(dev, thdev, intel_th_child_remove); | 118 | err = device_for_each_child(dev, thdev, intel_th_child_remove); |
| 113 | if (err) | 119 | if (err) |
| 114 | return err; | 120 | return err; |
| 121 | |||
| 122 | /* | ||
| 123 | * Remove outputs, that is, hub's children: they are created | ||
| 124 | * at hub's probe time by having the hub call | ||
| 125 | * intel_th_output_enable() for each of them. | ||
| 126 | */ | ||
| 127 | for (i = 0, lowest = -1; i < th->num_thdevs; i++) { | ||
| 128 | /* | ||
| 129 | * Move the non-output devices from higher up the | ||
| 130 | * th->thdev[] array to lower positions to maintain | ||
| 131 | * a contiguous array. | ||
| 132 | */ | ||
| 133 | if (th->thdev[i]->type != INTEL_TH_OUTPUT) { | ||
| 134 | if (lowest >= 0) { | ||
| 135 | th->thdev[lowest] = th->thdev[i]; | ||
| 136 | th->thdev[i] = NULL; | ||
| 137 | ++lowest; | ||
| 138 | } | ||
| 139 | |||
| 140 | continue; | ||
| 141 | } | ||
| 142 | |||
| 143 | if (lowest == -1) | ||
| 144 | lowest = i; | ||
| 145 | |||
| 146 | intel_th_device_remove(th->thdev[i]); | ||
| 147 | th->thdev[i] = NULL; | ||
| 148 | } | ||
| 149 | |||
| 150 | th->num_thdevs = lowest; | ||
| 115 | } | 151 | } |
| 116 | 152 | ||
| 117 | if (thdrv->attr_group) | 153 | if (thdrv->attr_group) |
| @@ -156,21 +192,6 @@ static struct device_type intel_th_source_device_type = { · 38 unmodified lines | |||
| 156 | .release = intel_th_device_release, | 192 | .release = intel_th_device_release, |
| 157 | }; | 193 | }; |
| 158 | 194 | ||
| 159 | static struct intel_th *to_intel_th(struct intel_th_device *thdev) | ||
| 160 | { | ||
| 161 | /* | ||
| 162 | * subdevice tree is flat: if this one is not a switch, its | ||
| 163 | * parent must be | ||
| 164 | */ | ||
| 165 | if (thdev->type != INTEL_TH_SWITCH) | ||
| 166 | thdev = to_intel_th_hub(thdev); | ||
| 167 | |||
| 168 | if (WARN_ON_ONCE(!thdev || thdev->type != INTEL_TH_SWITCH)) | ||
| 169 | return NULL; | ||
| 170 | |||
| 171 | return dev_get_drvdata(thdev->dev.parent); | ||
| 172 | } | ||
| 173 | |||
| 174 | static char *intel_th_output_devnode(struct device *dev, umode_t *mode, | 195 | static char *intel_th_output_devnode(struct device *dev, umode_t *mode, |
| 175 | kuid_t *uid, kgid_t *gid) | 196 | kuid_t *uid, kgid_t *gid) |
| 176 | { | 197 | { |
| @@ -205,6 +226,7 @@ static int intel_th_output_activate(struct intel_th_device *thdev) · 28 unmodified lines | |||
| 205 | { | 226 | { |
| 206 | struct intel_th_driver *thdrv = | 227 | struct intel_th_driver *thdrv = |
| 207 | to_intel_th_driver_or_null(thdev->dev.driver); | 228 | to_intel_th_driver_or_null(thdev->dev.driver); |
| 229 | struct intel_th *th = to_intel_th(thdev); | ||
| 208 | int ret = 0; | 230 | int ret = 0; |
| 209 | 231 | ||
| 210 | if (!thdrv) | 232 | if (!thdrv) |
| @@ -215,15 +237,28 @@ static int intel_th_output_activate(struct intel_th_device *thdev) · 4 unmodified lines | |||
| 215 | 237 | ||
| 216 | pm_runtime_get_sync(&thdev->dev); | 238 | pm_runtime_get_sync(&thdev->dev); |
| 217 | 239 | ||
| 240 | if (th->activate) | ||
| 241 | ret = th->activate(th); | ||
| 242 | if (ret) | ||
| 243 | goto fail_put; | ||
| 244 | |||
| 218 | if (thdrv->activate) | 245 | if (thdrv->activate) |
| 219 | ret = thdrv->activate(thdev); | 246 | ret = thdrv->activate(thdev); |
| 220 | else | 247 | else |
| 221 | intel_th_trace_enable(thdev); | 248 | intel_th_trace_enable(thdev); |
| 222 | 249 | ||
| 223 | if (ret) { | 250 | if (ret) |
| 224 | pm_runtime_put(&thdev->dev); | 251 | goto fail_deactivate; |
| 225 | module_put(thdrv->driver.owner); | 252 | |
| 226 | } | 253 | return 0; |
| 254 | |||
| 255 | fail_deactivate: | ||
| 256 | if (th->deactivate) | ||
| 257 | th->deactivate(th); | ||
| 258 | |||
| 259 | fail_put: | ||
| 260 | pm_runtime_put(&thdev->dev); | ||
| 261 | module_put(thdrv->driver.owner); | ||
| 227 | 262 | ||
| 228 | return ret; | 263 | return ret; |
| 229 | } | 264 | } |
| @@ -232,6 +267,7 @@ static void intel_th_output_deactivate(struct intel_th_device *thdev) · 2 unmodified lines | |||
| 232 | { | 267 | { |
| 233 | struct intel_th_driver *thdrv = | 268 | struct intel_th_driver *thdrv = |
| 234 | to_intel_th_driver_or_null(thdev->dev.driver); | 269 | to_intel_th_driver_or_null(thdev->dev.driver); |
| 270 | struct intel_th *th = to_intel_th(thdev); | ||
| 235 | 271 | ||
| 236 | if (!thdrv) | 272 | if (!thdrv) |
| 237 | return; | 273 | return; |
| @@ -241,6 +277,9 @@ static void intel_th_output_deactivate(struct intel_th_device *thdev) · 3 unmodified lines | |||
| 241 | else | 277 | else |
| 242 | intel_th_trace_disable(thdev); | 278 | intel_th_trace_disable(thdev); |
| 243 | 279 | ||
| 280 | if (th->deactivate) | ||
| 281 | th->deactivate(th); | ||
| 282 | |||
| 244 | pm_runtime_put(&thdev->dev); | 283 | pm_runtime_put(&thdev->dev); |
| 245 | module_put(thdrv->driver.owner); | 284 | module_put(thdrv->driver.owner); |
| 246 | } | 285 | } |
| @@ -326,10 +365,10 @@ intel_th_device_alloc(struct intel_th *th, unsigned int type, const char *name, · 79 unmodified lines | |||
| 326 | struct device *parent; | 365 | struct device *parent; |
| 327 | struct intel_th_device *thdev; | 366 | struct intel_th_device *thdev; |
| 328 | 367 | ||
| 329 | if (type == INTEL_TH_SWITCH) | 368 | if (type == INTEL_TH_OUTPUT) |
| 330 | parent = th->dev; | ||
| 331 | else | ||
| 332 | parent = &th->hub->dev; | 369 | parent = &th->hub->dev; |
| 370 | else | ||
| 371 | parent = th->dev; | ||
| 333 | 372 | ||
| 334 | thdev = kzalloc(sizeof(*thdev) + strlen(name) + 1, GFP_KERNEL); | 373 | thdev = kzalloc(sizeof(*thdev) + strlen(name) + 1, GFP_KERNEL); |
| 335 | if (!thdev) | 374 | if (!thdev) |
| @@ -392,13 +431,14 @@ static const struct intel_th_subdevice { · 56 unmodified lines | |||
| 392 | unsigned otype; | 431 | unsigned otype; |
| 393 | unsigned scrpd; | 432 | unsigned scrpd; |
| 394 | int id; | 433 | int id; |
| 395 | } intel_th_subdevices[TH_SUBDEVICE_MAX] = { | 434 | } intel_th_subdevices[] = { |
| 396 | { | 435 | { |
| 397 | .nres = 1, | 436 | .nres = 1, |
| 398 | .res = { | 437 | .res = { |
| 399 | { | 438 | { |
| 439 | /* Handle TSCU from GTH driver */ | ||
| 400 | .start = REG_GTH_OFFSET, | 440 | .start = REG_GTH_OFFSET, |
| 401 | .end = REG_GTH_OFFSET + REG_GTH_LENGTH - 1, | 441 | .end = REG_TSCU_OFFSET + REG_TSCU_LENGTH - 1, |
| 402 | .flags = IORESOURCE_MEM, | 442 | .flags = IORESOURCE_MEM, |
| 403 | }, | 443 | }, |
| 404 | }, | 444 | }, |
| @@ -479,6 +519,21 @@ static const struct intel_th_subdevice { · 74 unmodified lines | |||
| 479 | .otype = GTH_PTI, | 519 | .otype = GTH_PTI, |
| 480 | .scrpd = SCRPD_PTI_IS_PRIM_DEST, | 520 | .scrpd = SCRPD_PTI_IS_PRIM_DEST, |
| 481 | }, | 521 | }, |
| 522 | { | ||
| 523 | .nres = 1, | ||
| 524 | .res = { | ||
| 525 | { | ||
| 526 | .start = REG_PTI_OFFSET, | ||
| 527 | .end = REG_PTI_OFFSET + REG_PTI_LENGTH - 1, | ||
| 528 | .flags = IORESOURCE_MEM, | ||
| 529 | }, | ||
| 530 | }, | ||
| 531 | .id = -1, | ||
| 532 | .name = "lpp", | ||
| 533 | .type = INTEL_TH_OUTPUT, | ||
| 534 | .otype = GTH_LPP, | ||
| 535 | .scrpd = SCRPD_PTI_IS_PRIM_DEST, | ||
| 536 | }, | ||
| 482 | { | 537 | { |
| 483 | .nres = 1, | 538 | .nres = 1, |
| 484 | .res = { | 539 | .res = { |
| @@ -526,98 +581,182 @@ static inline void intel_th_request_hub_module_flush(struct intel_th *th) · 41 unmodified lines | |||
| 526 | } | 581 | } |
| 527 | #endif /* CONFIG_MODULES */ | 582 | #endif /* CONFIG_MODULES */ |
| 528 | 583 | ||
| 529 | static int intel_th_populate(struct intel_th *th, struct resource *devres, | 584 | static struct intel_th_device * |
| 530 | unsigned int ndevres, int irq) | 585 | intel_th_subdevice_alloc(struct intel_th *th, |
| 586 | const struct intel_th_subdevice *subdev) | ||
| 531 | { | 587 | { |
| 588 | struct intel_th_device *thdev; | ||
| 532 | struct resource res[3]; | 589 | struct resource res[3]; |
| 533 | unsigned int req = 0; | 590 | unsigned int req = 0; |
| 534 | int src, dst, err; | 591 | int r, err; |
| 535 | 592 | ||
| 536 | /* create devices for each intel_th_subdevice */ | 593 | thdev = intel_th_device_alloc(th, subdev->type, subdev->name, |
| 537 | for (src = 0, dst = 0; src < ARRAY_SIZE(intel_th_subdevices); src++) { | 594 | subdev->id); |
| 538 | const struct intel_th_subdevice *subdev = | 595 | if (!thdev) |
| 539 | &intel_th_subdevices[src]; | 596 | return ERR_PTR(-ENOMEM); |
| 540 | struct intel_th_device *thdev; | ||
| 541 | int r; | ||
| 542 | 597 | ||
| 543 | /* only allow SOURCE and SWITCH devices in host mode */ | 598 | thdev->drvdata = th->drvdata; |
| 544 | if (host_mode && subdev->type == INTEL_TH_OUTPUT) | 599 | |
| 545 | continue; | 600 | memcpy(res, subdev->res, |
| 601 | sizeof(struct resource) * subdev->nres); | ||
| 602 | |||
| 603 | for (r = 0; r < subdev->nres; r++) { | ||
| 604 | struct resource *devres = th->resource; | ||
| 605 | int bar = TH_MMIO_CONFIG; | ||
| 606 | |||
| 607 | /* | ||
| 608 | * Take .end == 0 to mean 'take the whole bar', | ||
| 609 | * .start then tells us which bar it is. Default to | ||
| 610 | * TH_MMIO_CONFIG. | ||
| 611 | */ | ||
| 612 | if (!res[r].end && res[r].flags == IORESOURCE_MEM) { | ||
| 613 | bar = res[r].start; | ||
| 614 | res[r].start = 0; | ||
| 615 | res[r].end = resource_size(&devres[bar]) - 1; | ||
| 616 | } | ||
| 617 | |||
| 618 | if (res[r].flags & IORESOURCE_MEM) { | ||
| 619 | res[r].start += devres[bar].start; | ||
| 620 | res[r].end += devres[bar].start; | ||
| 546 | 621 | ||
| 547 | thdev = intel_th_device_alloc(th, subdev->type, subdev->name, | 622 | dev_dbg(th->dev, "%s:%d @ %pR\n", |
| 548 | subdev->id); | 623 | subdev->name, r, &res[r]); |
| 549 | if (!thdev) { | 624 | } else if (res[r].flags & IORESOURCE_IRQ) { |
| 550 | err = -ENOMEM; | 625 | res[r].start = th->irq; |
| 551 | goto kill_subdevs; | ||
| 552 | } | 626 | } |
| 627 | } | ||
| 553 | 628 | ||
| 554 | memcpy(res, subdev->res, | 629 | err = intel_th_device_add_resources(thdev, res, subdev->nres); |
| 555 | sizeof(struct resource) * subdev->nres); | 630 | if (err) { |
| 631 | put_device(&thdev->dev); | ||
| 632 | goto fail_put_device; | ||
| 633 | } | ||
| 556 | 634 | ||
| 557 | for (r = 0; r < subdev->nres; r++) { | 635 | if (subdev->type == INTEL_TH_OUTPUT) { |
| 558 | int bar = TH_MMIO_CONFIG; | 636 | thdev->dev.devt = MKDEV(th->major, th->num_thdevs); |
| 637 | thdev->output.type = subdev->otype; | ||
| 638 | thdev->output.port = -1; | ||
| 639 | thdev->output.scratchpad = subdev->scrpd; | ||
| 640 | } else if (subdev->type == INTEL_TH_SWITCH) { | ||
| 641 | thdev->host_mode = host_mode; | ||
| 642 | th->hub = thdev; | ||
| 643 | } | ||
| 559 | 644 | ||
| 560 | /* | 645 | err = device_add(&thdev->dev); |
| 561 | * Take .end == 0 to mean 'take the whole bar', | 646 | if (err) { |
| 562 | * .start then tells us which bar it is. Default to | 647 | put_device(&thdev->dev); |
| 563 | * TH_MMIO_CONFIG. | 648 | goto fail_free_res; |
| 564 | */ | 649 | } |
| 565 | if (!res[r].end && res[r].flags == IORESOURCE_MEM) { | ||
| 566 | bar = res[r].start; | ||
| 567 | res[r].start = 0; | ||
| 568 | res[r].end = resource_size(&devres[bar]) - 1; | ||
| 569 | } | ||
| 570 | 650 | ||
| 571 | if (res[r].flags & IORESOURCE_MEM) { | 651 | /* need switch driver to be loaded to enumerate the rest */ |
| 572 | res[r].start += devres[bar].start; | 652 | if (subdev->type == INTEL_TH_SWITCH && !req) { |
| 573 | res[r].end += devres[bar].start; | 653 | err = intel_th_request_hub_module(th); |
| 654 | if (!err) | ||
| 655 | req++; | ||
| 656 | } | ||
| 574 | 657 | ||
| 575 | dev_dbg(th->dev, "%s:%d @ %pR\n", | 658 | return thdev; |
| 576 | subdev->name, r, &res[r]); | ||
| 577 | } else if (res[r].flags & IORESOURCE_IRQ) { | ||
| 578 | res[r].start = irq; | ||
| 579 | } | ||
| 580 | } | ||
| 581 | 659 | ||
| 582 | err = intel_th_device_add_resources(thdev, res, subdev->nres); | 660 | fail_free_res: |
| 583 | if (err) { | 661 | kfree(thdev->resource); |
| 584 | put_device(&thdev->dev); | ||
| 585 | goto kill_subdevs; | ||
| 586 | } | ||
| 587 | 662 | ||
| 588 | if (subdev->type == INTEL_TH_OUTPUT) { | 663 | fail_put_device: |
| 589 | thdev->dev.devt = MKDEV(th->major, dst); | 664 | put_device(&thdev->dev); |
| 590 | thdev->output.type = subdev->otype; | 665 | |
| 591 | thdev->output.port = -1; | 666 | return ERR_PTR(err); |
| 592 | thdev->output.scratchpad = subdev->scrpd; | 667 | } |
| 593 | } else if (subdev->type == INTEL_TH_SWITCH) { | ||
| 594 | thdev->host_mode = host_mode; | ||
| 595 | } | ||
| 596 | 668 | ||
| 597 | err = device_add(&thdev->dev); | 669 | /** |
| 598 | if (err) { | 670 | * intel_th_output_enable() - find and enable a device for a given output type |
| 599 | put_device(&thdev->dev); | 671 | * @th: Intel TH instance |
| 600 | goto kill_subdevs; | 672 | * @otype: output type |
| 673 | * | ||
| 674 | * Go through the unallocated output devices, find the first one whos type | ||
| 675 | * matches @otype and instantiate it. These devices are removed when the hub | ||
| 676 | * device is removed, see intel_th_remove(). | ||
| 677 | */ | ||
| 678 | int intel_th_output_enable(struct intel_th *th, unsigned int otype) | ||
| 679 | { | ||
| 680 | struct intel_th_device *thdev; | ||
| 681 | int src = 0, dst = 0; | ||
| 682 | |||
| 683 | for (src = 0, dst = 0; dst <= th->num_thdevs; src++, dst++) { | ||
| 684 | for (; src < ARRAY_SIZE(intel_th_subdevices); src++) { | ||
| 685 | if (intel_th_subdevices[src].type != INTEL_TH_OUTPUT) | ||
| 686 | continue; | ||
| 687 | |||
| 688 | if (intel_th_subdevices[src].otype != otype) | ||
| 689 | continue; | ||
| 690 | |||
| 691 | break; | ||
| 601 | } | 692 | } |
| 602 | 693 | ||
| 603 | /* need switch driver to be loaded to enumerate the rest */ | 694 | /* no unallocated matching subdevices */ |
| 604 | if (subdev->type == INTEL_TH_SWITCH && !req) { | 695 | if (src == ARRAY_SIZE(intel_th_subdevices)) |
| 605 | th->hub = thdev; | 696 | return -ENODEV; |
| 606 | err = intel_th_request_hub_module(th); | 697 | |
| 607 | if (!err) | 698 | for (; dst < th->num_thdevs; dst++) { |
| 608 | req++; | 699 | if (th->thdev[dst]->type != INTEL_TH_OUTPUT) |
| 700 | continue; | ||
| 701 | |||
| 702 | if (th->thdev[dst]->output.type != otype) | ||
| 703 | continue; | ||
| 704 | |||
| 705 | break; | ||
| 609 | } | 706 | } |
| 610 | 707 | ||
| 611 | th->thdev[dst++] = thdev; | 708 | /* |
| 709 | * intel_th_subdevices[src] matches our requirements and is | ||
| 710 | * not matched in th::thdev[] | ||
| 711 | */ | ||
| 712 | if (dst == th->num_thdevs) | ||
| 713 | goto found; | ||
| 612 | } | 714 | } |
| 613 | 715 | ||
| 716 | return -ENODEV; | ||
| 717 | |||
| 718 | found: | ||
| 719 | thdev = intel_th_subdevice_alloc(th, &intel_th_subdevices[src]); | ||
| 720 | if (IS_ERR(thdev)) | ||
| 721 | return PTR_ERR(thdev); | ||
| 722 | |||
| 723 | th->thdev[th->num_thdevs++] = thdev; | ||
| 724 | |||
| 614 | return 0; | 725 | return 0; |
| 726 | } | ||
| 727 | EXPORT_SYMBOL_GPL(intel_th_output_enable); | ||
| 728 | |||
| 729 | static int intel_th_populate(struct intel_th *th) | ||
| 730 | { | ||
| 731 | int src; | ||
| 732 | |||
| 733 | /* create devices for each intel_th_subdevice */ | ||
| 734 | for (src = 0; src < ARRAY_SIZE(intel_th_subdevices); src++) { | ||
| 735 | const struct intel_th_subdevice *subdev = | ||
| 736 | &intel_th_subdevices[src]; | ||
| 737 | struct intel_th_device *thdev; | ||
| 738 | |||
| 739 | /* only allow SOURCE and SWITCH devices in host mode */ | ||
| 740 | if (host_mode && subdev->type == INTEL_TH_OUTPUT) | ||
| 741 | continue; | ||
| 615 | 742 | ||
| 616 | kill_subdevs: | 743 | /* |
| 617 | for (; dst >= 0; dst--) | 744 | * don't enable port OUTPUTs in this path; SWITCH enables them |
| 618 | intel_th_device_remove(th->thdev[dst]); | 745 | * via intel_th_output_enable() |
| 746 | */ | ||
| 747 | if (subdev->type == INTEL_TH_OUTPUT && | ||
| 748 | subdev->otype != GTH_NONE) | ||
| 749 | continue; | ||
| 750 | |||
| 751 | thdev = intel_th_subdevice_alloc(th, subdev); | ||
| 752 | /* note: caller should free subdevices from th::thdev[] */ | ||
| 753 | if (IS_ERR(thdev)) | ||
| 754 | return PTR_ERR(thdev); | ||
| 755 | |||
| 756 | th->thdev[th->num_thdevs++] = thdev; | ||
| 757 | } | ||
| 619 | 758 | ||
| 620 | return err; | 759 | return 0; |
| 621 | } | 760 | } |
| 622 | 761 | ||
| 623 | static int match_devt(struct device *dev, void *data) | 762 | static int match_devt(struct device *dev, void *data) |
| @@ -670,8 +809,8 @@ static const struct file_operations intel_th_output_fops = { · 46 unmodified lines | |||
| 670 | * @irq: irq number | 809 | * @irq: irq number |
| 671 | */ | 810 | */ |
| 672 | struct intel_th * | 811 | struct intel_th * |
| 673 | intel_th_alloc(struct device *dev, struct resource *devres, | 812 | intel_th_alloc(struct device *dev, struct intel_th_drvdata *drvdata, |
| 674 | unsigned int ndevres, int irq) | 813 | struct resource *devres, unsigned int ndevres, int irq) |
| 675 | { | 814 | { |
| 676 | struct intel_th *th; | 815 | struct intel_th *th; |
| 677 | int err; | 816 | int err; |
| @@ -693,6 +832,11 @@ intel_th_alloc(struct device *dev, struct resource *devres, · 15 unmodified lines | |||
| 693 | goto err_ida; | 832 | goto err_ida; |
| 694 | } | 833 | } |
| 695 | th->dev = dev; | 834 | th->dev = dev; |
| 835 | th->drvdata = drvdata; | ||
| 836 | |||
| 837 | th->resource = devres; | ||
| 838 | th->num_resources = ndevres; | ||
| 839 | th->irq = irq; | ||
| 696 | 840 | ||
| 697 | dev_set_drvdata(dev, th); | 841 | dev_set_drvdata(dev, th); |
| 698 | 842 | ||
| @@ -700,18 +844,15 @@ intel_th_alloc(struct device *dev, struct resource *devres, · 1 unmodified line | |||
| 700 | pm_runtime_put(dev); | 844 | pm_runtime_put(dev); |
| 701 | pm_runtime_allow(dev); | 845 | pm_runtime_allow(dev); |
| 702 | 846 | ||
| 703 | err = intel_th_populate(th, devres, ndevres, irq); | 847 | err = intel_th_populate(th); |
| 704 | if (err) | 848 | if (err) { |
| 705 | goto err_chrdev; | 849 | /* free the subdevices and undo everything */ |
| 850 | intel_th_free(th); | ||
| 851 | return ERR_PTR(err); | ||
| 852 | } | ||
| 706 | 853 | ||
| 707 | return th; | 854 | return th; |
| 708 | 855 | ||
| 709 | err_chrdev: | ||
| 710 | pm_runtime_forbid(dev); | ||
| 711 | |||
| 712 | __unregister_chrdev(th->major, 0, TH_POSSIBLE_OUTPUTS, | ||
| 713 | "intel_th/output"); | ||
| 714 | |||
| 715 | err_ida: | 856 | err_ida: |
| 716 | ida_simple_remove(&intel_th_ida, th->id); | 857 | ida_simple_remove(&intel_th_ida, th->id); |
| 717 | 858 | ||
| @@ -727,11 +868,15 @@ void intel_th_free(struct intel_th *th) · 9 unmodified lines | |||
| 727 | int i; | 868 | int i; |
| 728 | 869 | ||
| 729 | intel_th_request_hub_module_flush(th); | 870 | intel_th_request_hub_module_flush(th); |
| 730 | for (i = 0; i < TH_SUBDEVICE_MAX; i++) | ||
| 731 | if (th->thdev[i] && th->thdev[i] != th->hub) | ||
| 732 | intel_th_device_remove(th->thdev[i]); | ||
| 733 | 871 | ||
| 734 | intel_th_device_remove(th->hub); | 872 | intel_th_device_remove(th->hub); |
| 873 | for (i = 0; i < th->num_thdevs; i++) { | ||
| 874 | if (th->thdev[i] != th->hub) | ||
| 875 | intel_th_device_remove(th->thdev[i]); | ||
| 876 | th->thdev[i] = NULL; | ||
| 877 | } | ||
| 878 | |||
| 879 | th->num_thdevs = 0; | ||
| 735 | 880 | ||
| 736 | pm_runtime_get_sync(th->dev); | 881 | pm_runtime_get_sync(th->dev); |
| 737 | pm_runtime_forbid(th->dev); | 882 | pm_runtime_forbid(th->dev); |
| @@ -285,16 +285,16 @@ gth_output_parm_get(struct gth_device *gth, int port, unsigned int parm) · 284 unmodified lines | |||
| 285 | */ | 285 | */ |
| 286 | static int intel_th_gth_reset(struct gth_device *gth) | 286 | static int intel_th_gth_reset(struct gth_device *gth) |
| 287 | { | 287 | { |
| 288 | u32 scratchpad; | 288 | u32 reg; |
| 289 | int port, i; | 289 | int port, i; |
| 290 | 290 | ||
| 291 | scratchpad = ioread32(gth->base + REG_GTH_SCRPD0); | 291 | reg = ioread32(gth->base + REG_GTH_SCRPD0); |
| 292 | if (scratchpad & SCRPD_DEBUGGER_IN_USE) | 292 | if (reg & SCRPD_DEBUGGER_IN_USE) |
| 293 | return -EBUSY; | 293 | return -EBUSY; |
| 294 | 294 | ||
| 295 | /* Always save/restore STH and TU registers in S0ix entry/exit */ | 295 | /* Always save/restore STH and TU registers in S0ix entry/exit */ |
| 296 | scratchpad |= SCRPD_STH_IS_ENABLED | SCRPD_TRIGGER_IS_ENABLED; | 296 | reg |= SCRPD_STH_IS_ENABLED | SCRPD_TRIGGER_IS_ENABLED; |
| 297 | iowrite32(scratchpad, gth->base + REG_GTH_SCRPD0); | 297 | iowrite32(reg, gth->base + REG_GTH_SCRPD0); |
| 298 | 298 | ||
| 299 | /* output ports */ | 299 | /* output ports */ |
| 300 | for (port = 0; port < 8; port++) { | 300 | for (port = 0; port < 8; port++) { |
| @@ -512,6 +512,15 @@ static void intel_th_gth_disable(struct intel_th_device *thdev, · 211 unmodified lines | |||
| 512 | iowrite32(reg, gth->base + REG_GTH_SCRPD0); | 512 | iowrite32(reg, gth->base + REG_GTH_SCRPD0); |
| 513 | } | 513 | } |
| 514 | 514 | ||
| 515 | static void gth_tscu_resync(struct gth_device *gth) | ||
| 516 | { | ||
| 517 | u32 reg; | ||
| 518 | |||
| 519 | reg = ioread32(gth->base + REG_TSCU_TSUCTRL); | ||
| 520 | reg &= ~TSUCTRL_CTCRESYNC; | ||
| 521 | iowrite32(reg, gth->base + REG_TSCU_TSUCTRL); | ||
| 522 | } | ||
| 523 | |||
| 515 | /** | 524 | /** |
| 516 | * intel_th_gth_enable() - enable tracing to an output device | 525 | * intel_th_gth_enable() - enable tracing to an output device |
| 517 | * @thdev: GTH device | 526 | * @thdev: GTH device |
| @@ -524,6 +533,7 @@ static void intel_th_gth_enable(struct intel_th_device *thdev, · 6 unmodified lines | |||
| 524 | struct intel_th_output *output) | 533 | struct intel_th_output *output) |
| 525 | { | 534 | { |
| 526 | struct gth_device *gth = dev_get_drvdata(&thdev->dev); | 535 | struct gth_device *gth = dev_get_drvdata(&thdev->dev); |
| 536 | struct intel_th *th = to_intel_th(thdev); | ||
| 527 | u32 scr = 0xfc0000, scrpd; | 537 | u32 scr = 0xfc0000, scrpd; |
| 528 | int master; | 538 | int master; |
| 529 | 539 | ||
| @@ -539,6 +549,9 @@ static void intel_th_gth_enable(struct intel_th_device *thdev, · 9 unmodified lines | |||
| 539 | output->active = true; | 549 | output->active = true; |
| 540 | spin_unlock(>h->gth_lock); | 550 | spin_unlock(>h->gth_lock); |
| 541 | 551 | ||
| 552 | if (INTEL_TH_CAP(th, tscu_enable)) | ||
| 553 | gth_tscu_resync(gth); | ||
| 554 | |||
| 542 | scrpd = ioread32(gth->base + REG_GTH_SCRPD0); | 555 | scrpd = ioread32(gth->base + REG_GTH_SCRPD0); |
| 543 | scrpd |= output->scratchpad; | 556 | scrpd |= output->scratchpad; |
| 544 | iowrite32(scrpd, gth->base + REG_GTH_SCRPD0); | 557 | iowrite32(scrpd, gth->base + REG_GTH_SCRPD0); |
| @@ -639,6 +652,7 @@ intel_th_gth_set_output(struct intel_th_device *thdev, unsigned int master) · 94 unmodified lines | |||
| 639 | static int intel_th_gth_probe(struct intel_th_device *thdev) | 652 | static int intel_th_gth_probe(struct intel_th_device *thdev) |
| 640 | { | 653 | { |
| 641 | struct device *dev = &thdev->dev; | 654 | struct device *dev = &thdev->dev; |
| 655 | struct intel_th *th = dev_get_drvdata(dev->parent); | ||
| 642 | struct gth_device *gth; | 656 | struct gth_device *gth; |
| 643 | struct resource *res; | 657 | struct resource *res; |
| 644 | void __iomem *base; | 658 | void __iomem *base; |
| @@ -660,6 +674,8 @@ static int intel_th_gth_probe(struct intel_th_device *thdev) · 15 unmodified lines | |||
| 660 | gth->base = base; | 674 | gth->base = base; |
| 661 | spin_lock_init(>h->gth_lock); | 675 | spin_lock_init(>h->gth_lock); |
| 662 | 676 | ||
| 677 | dev_set_drvdata(dev, gth); | ||
| 678 | |||
| 663 | /* | 679 | /* |
| 664 | * Host mode can be signalled via SW means or via SCRPD_DEBUGGER_IN_USE | 680 | * Host mode can be signalled via SW means or via SCRPD_DEBUGGER_IN_USE |
| 665 | * bit. Either way, don't reset HW in this case, and don't export any | 681 | * bit. Either way, don't reset HW in this case, and don't export any |
| @@ -667,7 +683,7 @@ static int intel_th_gth_probe(struct intel_th_device *thdev) · 1 unmodified line | |||
| 667 | * drivers to ports, see intel_th_gth_assign(). | 683 | * drivers to ports, see intel_th_gth_assign(). |
| 668 | */ | 684 | */ |
| 669 | if (thdev->host_mode) | 685 | if (thdev->host_mode) |
| 670 | goto done; | 686 | return 0; |
| 671 | 687 | ||
| 672 | ret = intel_th_gth_reset(gth); | 688 | ret = intel_th_gth_reset(gth); |
| 673 | if (ret) { | 689 | if (ret) { |
| @@ -676,7 +692,7 @@ static int intel_th_gth_probe(struct intel_th_device *thdev) · 2 unmodified lines | |||
| 676 | 692 | ||
| 677 | thdev->host_mode = true; | 693 | thdev->host_mode = true; |
| 678 | 694 | ||
| 679 | goto done; | 695 | return 0; |
| 680 | } | 696 | } |
| 681 | 697 | ||
| 682 | for (i = 0; i < TH_CONFIGURABLE_MASTERS + 1; i++) | 698 | for (i = 0; i < TH_CONFIGURABLE_MASTERS + 1; i++) |
| @@ -687,6 +703,13 @@ static int intel_th_gth_probe(struct intel_th_device *thdev) · 4 unmodified lines | |||
| 687 | gth->output[i].index = i; | 703 | gth->output[i].index = i; |
| 688 | gth->output[i].port_type = | 704 | gth->output[i].port_type = |
| 689 | gth_output_parm_get(gth, i, TH_OUTPUT_PARM(port)); | 705 | gth_output_parm_get(gth, i, TH_OUTPUT_PARM(port)); |
| 706 | if (gth->output[i].port_type == GTH_NONE) | ||
| 707 | continue; | ||
| 708 | |||
| 709 | ret = intel_th_output_enable(th, gth->output[i].port_type); | ||
| 710 | /* -ENODEV is ok, we just won't have that device enumerated */ | ||
| 711 | if (ret && ret != -ENODEV) | ||
| 712 | return ret; | ||
| 690 | } | 713 | } |
| 691 | 714 | ||
| 692 | if (intel_th_output_attributes(gth) || | 715 | if (intel_th_output_attributes(gth) || |
| @@ -698,9 +721,6 @@ static int intel_th_gth_probe(struct intel_th_device *thdev) · 5 unmodified lines | |||
| 698 | return -ENOMEM; | 721 | return -ENOMEM; |
| 699 | } | 722 | } |
| 700 | 723 | ||
| 701 | done: | ||
| 702 | dev_set_drvdata(dev, gth); | ||
| 703 | |||
| 704 | return 0; | 724 | return 0; |
| 705 | } | 725 | } |
| 706 | 726 | ||
| @@ -55,9 +55,14 @@ enum { · 54 unmodified lines | |||
| 55 | REG_GTH_SCRPD1 = 0xe4, /* ScratchPad[1] */ | 55 | REG_GTH_SCRPD1 = 0xe4, /* ScratchPad[1] */ |
| 56 | REG_GTH_SCRPD2 = 0xe8, /* ScratchPad[2] */ | 56 | REG_GTH_SCRPD2 = 0xe8, /* ScratchPad[2] */ |
| 57 | REG_GTH_SCRPD3 = 0xec, /* ScratchPad[3] */ | 57 | REG_GTH_SCRPD3 = 0xec, /* ScratchPad[3] */ |
| 58 | REG_TSCU_TSUCTRL = 0x2000, /* TSCU control register */ | ||
| 59 | REG_TSCU_TSCUSTAT = 0x2004, /* TSCU status register */ | ||
| 58 | }; | 60 | }; |
| 59 | 61 | ||
| 60 | /* waiting for Pipeline Empty bit(s) to assert for GTH */ | 62 | /* waiting for Pipeline Empty bit(s) to assert for GTH */ |
| 61 | #define GTH_PLE_WAITLOOP_DEPTH 10000 | 63 | #define GTH_PLE_WAITLOOP_DEPTH 10000 |
| 62 | 64 | ||
| 65 | #define TSUCTRL_CTCRESYNC BIT(0) | ||
| 66 | #define TSCUSTAT_CTCSYNCING BIT(1) | ||
| 67 | |||
| 63 | #endif /* __INTEL_TH_GTH_H__ */ | 68 | #endif /* __INTEL_TH_GTH_H__ */ |
| @@ -47,9 +47,20 @@ struct intel_th_output { · 46 unmodified lines | |||
| 47 | bool active; | 47 | bool active; |
| 48 | }; | 48 | }; |
| 49 | 49 | ||
| 50 | /** | ||
| 51 | * struct intel_th_drvdata - describes hardware capabilities and quirks | ||
| 52 | * @tscu_enable: device needs SW to enable time stamping unit | ||
| 53 | */ | ||
| 54 | struct intel_th_drvdata { | ||
| 55 | unsigned int tscu_enable : 1; | ||
| 56 | }; | ||
| 57 | |||
| 58 | #define INTEL_TH_CAP(_th, _cap) ((_th)->drvdata ? (_th)->drvdata->_cap : 0) | ||
| 59 | |||
| 50 | /** | 60 | /** |
| 51 | * struct intel_th_device - device on the intel_th bus | 61 | * struct intel_th_device - device on the intel_th bus |
| 52 | * @dev: device | 62 | * @dev: device |
| 63 | * @drvdata: hardware capabilities/quirks | ||
| 53 | * @resource: array of resources available to this device | 64 | * @resource: array of resources available to this device |
| 54 | * @num_resources: number of resources in @resource array | 65 | * @num_resources: number of resources in @resource array |
| 55 | * @type: INTEL_TH_{SOURCE,OUTPUT,SWITCH} | 66 | * @type: INTEL_TH_{SOURCE,OUTPUT,SWITCH} |
| @@ -59,11 +70,12 @@ struct intel_th_output { · 3 unmodified lines | |||
| 59 | * @name: device name to match the driver | 70 | * @name: device name to match the driver |
| 60 | */ | 71 | */ |
| 61 | struct intel_th_device { | 72 | struct intel_th_device { |
| 62 | struct device dev; | 73 | struct device dev; |
| 63 | struct resource *resource; | 74 | struct intel_th_drvdata *drvdata; |
| 64 | unsigned int num_resources; | 75 | struct resource *resource; |
| 65 | unsigned int type; | 76 | unsigned int num_resources; |
| 66 | int id; | 77 | unsigned int type; |
| 78 | int id; | ||
| 67 | 79 | ||
| 68 | /* INTEL_TH_SWITCH specific */ | 80 | /* INTEL_TH_SWITCH specific */ |
| 69 | bool host_mode; | 81 | bool host_mode; |
| @@ -96,6 +108,17 @@ intel_th_device_get_resource(struct intel_th_device *thdev, unsigned int type, · 26 unmodified lines | |||
| 96 | return NULL; | 108 | return NULL; |
| 97 | } | 109 | } |
| 98 | 110 | ||
| 111 | /* | ||
| 112 | * GTH, output ports configuration | ||
| 113 | */ | ||
| 114 | enum { | ||
| 115 | GTH_NONE = 0, | ||
| 116 | GTH_MSU, /* memory/usb */ | ||
| 117 | GTH_CTP, /* Common Trace Port */ | ||
| 118 | GTH_LPP, /* Low Power Path */ | ||
| 119 | GTH_PTI, /* MIPI-PTI */ | ||
| 120 | }; | ||
| 121 | |||
| 99 | /** | 122 | /** |
| 100 | * intel_th_output_assigned() - if an output device is assigned to a switch port | 123 | * intel_th_output_assigned() - if an output device is assigned to a switch port |
| 101 | * @thdev: the output device | 124 | * @thdev: the output device |
| @@ -106,7 +129,8 @@ static inline bool · 4 unmodified lines | |||
| 106 | intel_th_output_assigned(struct intel_th_device *thdev) | 129 | intel_th_output_assigned(struct intel_th_device *thdev) |
| 107 | { | 130 | { |
| 108 | return thdev->type == INTEL_TH_OUTPUT && | 131 | return thdev->type == INTEL_TH_OUTPUT && |
| 109 | thdev->output.port >= 0; | 132 | (thdev->output.port >= 0 || |
| 133 | thdev->output.type == GTH_NONE); | ||
| 110 | } | 134 | } |
| 111 | 135 | ||
| 112 | /** | 136 | /** |
| @@ -161,8 +185,18 @@ struct intel_th_driver { · 48 unmodified lines | |||
| 161 | #define to_intel_th_driver_or_null(_d) \ | 185 | #define to_intel_th_driver_or_null(_d) \ |
| 162 | ((_d) ? to_intel_th_driver(_d) : NULL) | 186 | ((_d) ? to_intel_th_driver(_d) : NULL) |
| 163 | 187 | ||
| 188 | /* | ||
| 189 | * Subdevice tree structure is as follows: | ||
| 190 | * + struct intel_th device (pci; dev_{get,set}_drvdata() | ||
| 191 | * + struct intel_th_device INTEL_TH_SWITCH (GTH) | ||
| 192 | * + struct intel_th_device INTEL_TH_OUTPUT (MSU, PTI) | ||
| 193 | * + struct intel_th_device INTEL_TH_SOURCE (STH) | ||
| 194 | * | ||
| 195 | * In other words, INTEL_TH_OUTPUT devices are children of INTEL_TH_SWITCH; | ||
| 196 | * INTEL_TH_SWITCH and INTEL_TH_SOURCE are children of the intel_th device. | ||
| 197 | */ | ||
| 164 | static inline struct intel_th_device * | 198 | static inline struct intel_th_device * |
| 165 | to_intel_th_hub(struct intel_th_device *thdev) | 199 | to_intel_th_parent(struct intel_th_device *thdev) |
| 166 | { | 200 | { |
| 167 | struct device *parent = thdev->dev.parent; | 201 | struct device *parent = thdev->dev.parent; |
| 168 | 202 | ||
| @@ -172,9 +206,20 @@ to_intel_th_hub(struct intel_th_device *thdev) · 3 unmodified lines | |||
| 172 | return to_intel_th_device(parent); | 206 | return to_intel_th_device(parent); |
| 173 | } | 207 | } |
| 174 | 208 | ||
| 209 | static inline struct intel_th *to_intel_th(struct intel_th_device *thdev) | ||
| 210 | { | ||
| 211 | if (thdev->type == INTEL_TH_OUTPUT) | ||
| 212 | thdev = to_intel_th_parent(thdev); | ||
| 213 | |||
| 214 | if (WARN_ON_ONCE(!thdev || thdev->type == INTEL_TH_OUTPUT)) | ||
| 215 | return NULL; | ||
| 216 | |||
| 217 | return dev_get_drvdata(thdev->dev.parent); | ||
| 218 | } | ||
| 219 | |||
| 175 | struct intel_th * | 220 | struct intel_th * |
| 176 | intel_th_alloc(struct device *dev, struct resource *devres, | 221 | intel_th_alloc(struct device *dev, struct intel_th_drvdata *drvdata, |
| 177 | unsigned int ndevres, int irq); | 222 | struct resource *devres, unsigned int ndevres, int irq); |
| 178 | void intel_th_free(struct intel_th *th); | 223 | void intel_th_free(struct intel_th *th); |
| 179 | 224 | ||
| 180 | int intel_th_driver_register(struct intel_th_driver *thdrv); | 225 | int intel_th_driver_register(struct intel_th_driver *thdrv); |
| @@ -184,6 +229,7 @@ int intel_th_trace_enable(struct intel_th_device *thdev); · 3 unmodified lines | |||
| 184 | int intel_th_trace_disable(struct intel_th_device *thdev); | 229 | int intel_th_trace_disable(struct intel_th_device *thdev); |
| 185 | int intel_th_set_output(struct intel_th_device *thdev, | 230 | int intel_th_set_output(struct intel_th_device *thdev, |
| 186 | unsigned int master); | 231 | unsigned int master); |
| 232 | int intel_th_output_enable(struct intel_th *th, unsigned int otype); | ||
| 187 | 233 | ||
| 188 | enum { | 234 | enum { |
| 189 | TH_MMIO_CONFIG = 0, | 235 | TH_MMIO_CONFIG = 0, |
| @@ -191,8 +237,9 @@ enum { · 1 unmodified line | |||
| 191 | TH_MMIO_END, | 237 | TH_MMIO_END, |
| 192 | }; | 238 | }; |
| 193 | 239 | ||
| 194 | #define TH_SUBDEVICE_MAX 6 | ||
| 195 | #define TH_POSSIBLE_OUTPUTS 8 | 240 | #define TH_POSSIBLE_OUTPUTS 8 |
| 241 | /* Total number of possible subdevices: outputs + GTH + STH */ | ||
| 242 | #define TH_SUBDEVICE_MAX (TH_POSSIBLE_OUTPUTS + 2) | ||
| 196 | #define TH_CONFIGURABLE_MASTERS 256 | 243 | #define TH_CONFIGURABLE_MASTERS 256 |
| 197 | #define TH_MSC_MAX 2 | 244 | #define TH_MSC_MAX 2 |
| 198 | 245 | ||
| @@ -201,6 +248,10 @@ enum { · 2 unmodified lines | |||
| 201 | * @dev: driver core's device | 248 | * @dev: driver core's device |
| 202 | * @thdev: subdevices | 249 | * @thdev: subdevices |
| 203 | * @hub: "switch" subdevice (GTH) | 250 | * @hub: "switch" subdevice (GTH) |
| 251 | * @resource: resources of the entire controller | ||
| 252 | * @num_thdevs: number of devices in the @thdev array | ||
| 253 | * @num_resources: number or resources in the @resource array | ||
| 254 | * @irq: irq number | ||
| 204 | * @id: this Intel TH controller's device ID in the system | 255 | * @id: this Intel TH controller's device ID in the system |
| 205 | * @major: device node major for output devices | 256 | * @major: device node major for output devices |
| 206 | */ | 257 | */ |
| @@ -209,6 +260,14 @@ struct intel_th { · 2 unmodified lines | |||
| 209 | 260 | ||
| 210 | struct intel_th_device *thdev[TH_SUBDEVICE_MAX]; | 261 | struct intel_th_device *thdev[TH_SUBDEVICE_MAX]; |
| 211 | struct intel_th_device *hub; | 262 | struct intel_th_device *hub; |
| 263 | struct intel_th_drvdata *drvdata; | ||
| 264 | |||
| 265 | struct resource *resource; | ||
| 266 | int (*activate)(struct intel_th *); | ||
| 267 | void (*deactivate)(struct intel_th *); | ||
| 268 | unsigned int num_thdevs; | ||
| 269 | unsigned int num_resources; | ||
| 270 | int irq; | ||
| 212 | 271 | ||
| 213 | int id; | 272 | int id; |
| 214 | int major; | 273 | int major; |
| @@ -220,6 +279,17 @@ struct intel_th { · 5 unmodified lines | |||
| 220 | #endif | 279 | #endif |
| 221 | }; | 280 | }; |
| 222 | 281 | ||
| 282 | static inline struct intel_th_device * | ||
| 283 | to_intel_th_hub(struct intel_th_device *thdev) | ||
| 284 | { | ||
| 285 | if (thdev->type == INTEL_TH_SWITCH) | ||
| 286 | return thdev; | ||
| 287 | else if (thdev->type == INTEL_TH_OUTPUT) | ||
| 288 | return to_intel_th_parent(thdev); | ||
| 289 | |||
| 290 | return to_intel_th(thdev)->hub; | ||
| 291 | } | ||
| 292 | |||
| 223 | /* | 293 | /* |
| 224 | * Register windows | 294 | * Register windows |
| 225 | */ | 295 | */ |
| @@ -228,6 +298,10 @@ enum { · 2 unmodified lines | |||
| 228 | REG_GTH_OFFSET = 0x0000, | 298 | REG_GTH_OFFSET = 0x0000, |
| 229 | REG_GTH_LENGTH = 0x2000, | 299 | REG_GTH_LENGTH = 0x2000, |
| 230 | 300 | ||
| 301 | /* Timestamp counter unit (TSCU) */ | ||
| 302 | REG_TSCU_OFFSET = 0x2000, | ||
| 303 | REG_TSCU_LENGTH = 0x1000, | ||
| 304 | |||
| 231 | /* Software Trace Hub (STH) [0x4000..0x4fff] */ | 305 | /* Software Trace Hub (STH) [0x4000..0x4fff] */ |
| 232 | REG_STH_OFFSET = 0x4000, | 306 | REG_STH_OFFSET = 0x4000, |
| 233 | REG_STH_LENGTH = 0x2000, | 307 | REG_STH_LENGTH = 0x2000, |
| @@ -249,16 +323,6 @@ enum { · 15 unmodified lines | |||
| 249 | REG_DCIH_LENGTH = REG_MSU_LENGTH, | 323 | REG_DCIH_LENGTH = REG_MSU_LENGTH, |
| 250 | }; | 324 | }; |
| 251 | 325 | ||
| 252 | /* | ||
| 253 | * GTH, output ports configuration | ||
| 254 | */ | ||
| 255 | enum { | ||
| 256 | GTH_NONE = 0, | ||
| 257 | GTH_MSU, /* memory/usb */ | ||
| 258 | GTH_CTP, /* Common Trace Port */ | ||
| 259 | GTH_PTI = 4, /* MIPI-PTI */ | ||
| 260 | }; | ||
| 261 | |||
| 262 | /* | 326 | /* |
| 263 | * Scratchpad bits: tell firmware and external debuggers | 327 | * Scratchpad bits: tell firmware and external debuggers |
| 264 | * what we are up to. | 328 | * what we are up to. |
| @@ -709,17 +709,17 @@ static int msc_buffer_win_alloc(struct msc *msc, unsigned int nr_blocks) · 708 unmodified lines | |||
| 709 | } | 709 | } |
| 710 | 710 | ||
| 711 | for (i = 0; i < nr_blocks; i++) { | 711 | for (i = 0; i < nr_blocks; i++) { |
| 712 | win->block[i].bdesc = dma_alloc_coherent(msc_dev(msc), size, | 712 | win->block[i].bdesc = |
| 713 | &win->block[i].addr, | 713 | dma_alloc_coherent(msc_dev(msc)->parent->parent, size, |
| 714 | GFP_KERNEL); | 714 | &win->block[i].addr, GFP_KERNEL); |
| 715 | |||
| 716 | if (!win->block[i].bdesc) | ||
| 717 | goto err_nomem; | ||
| 715 | 718 | ||
| 716 | #ifdef CONFIG_X86 | 719 | #ifdef CONFIG_X86 |
| 717 | /* Set the page as uncached */ | 720 | /* Set the page as uncached */ |
| 718 | set_memory_uc((unsigned long)win->block[i].bdesc, 1); | 721 | set_memory_uc((unsigned long)win->block[i].bdesc, 1); |
| 719 | #endif | 722 | #endif |
| 720 | |||
| 721 | if (!win->block[i].bdesc) | ||
| 722 | goto err_nomem; | ||
| 723 | } | 723 | } |
| 724 | 724 | ||
| 725 | win->msc = msc; | 725 | win->msc = msc; |
| @@ -27,9 +27,53 @@ · 26 unmodified lines | |||
| 27 | 27 | ||
| 28 | #define BAR_MASK (BIT(TH_MMIO_CONFIG) | BIT(TH_MMIO_SW)) | 28 | #define BAR_MASK (BIT(TH_MMIO_CONFIG) | BIT(TH_MMIO_SW)) |
| 29 | 29 | ||
| 30 | #define PCI_REG_NPKDSC 0x80 | ||
| 31 | #define NPKDSC_TSACT BIT(5) | ||
| 32 | |||
| 33 | static int intel_th_pci_activate(struct intel_th *th) | ||
| 34 | { | ||
| 35 | struct pci_dev *pdev = to_pci_dev(th->dev); | ||
| 36 | u32 npkdsc; | ||
| 37 | int err; | ||
| 38 | |||
| 39 | if (!INTEL_TH_CAP(th, tscu_enable)) | ||
| 40 | return 0; | ||
| 41 | |||
| 42 | err = pci_read_config_dword(pdev, PCI_REG_NPKDSC, &npkdsc); | ||
| 43 | if (!err) { | ||
| 44 | npkdsc |= NPKDSC_TSACT; | ||
| 45 | err = pci_write_config_dword(pdev, PCI_REG_NPKDSC, npkdsc); | ||
| 46 | } | ||
| 47 | |||
| 48 | if (err) | ||
| 49 | dev_err(&pdev->dev, "failed to read NPKDSC register\n"); | ||
| 50 | |||
| 51 | return err; | ||
| 52 | } | ||
| 53 | |||
| 54 | static void intel_th_pci_deactivate(struct intel_th *th) | ||
| 55 | { | ||
| 56 | struct pci_dev *pdev = to_pci_dev(th->dev); | ||
| 57 | u32 npkdsc; | ||
| 58 | int err; | ||
| 59 | |||
| 60 | if (!INTEL_TH_CAP(th, tscu_enable)) | ||
| 61 | return; | ||
| 62 | |||
| 63 | err = pci_read_config_dword(pdev, PCI_REG_NPKDSC, &npkdsc); | ||
| 64 | if (!err) { | ||
| 65 | npkdsc |= NPKDSC_TSACT; | ||
| 66 | err = pci_write_config_dword(pdev, PCI_REG_NPKDSC, npkdsc); | ||
| 67 | } | ||
| 68 | |||
| 69 | if (err) | ||
| 70 | dev_err(&pdev->dev, "failed to read NPKDSC register\n"); | ||
| 71 | } | ||
| 72 | |||
| 30 | static int intel_th_pci_probe(struct pci_dev *pdev, | 73 | static int intel_th_pci_probe(struct pci_dev *pdev, |
| 31 | const struct pci_device_id *id) | 74 | const struct pci_device_id *id) |
| 32 | { | 75 | { |
| 76 | struct intel_th_drvdata *drvdata = (void *)id->driver_data; | ||
| 33 | struct intel_th *th; | 77 | struct intel_th *th; |
| 34 | int err; | 78 | int err; |
| 35 | 79 | ||
| @@ -41,11 +85,16 @@ static int intel_th_pci_probe(struct pci_dev *pdev, · 5 unmodified lines | |||
| 41 | if (err) | 85 | if (err) |
| 42 | return err; | 86 | return err; |
| 43 | 87 | ||
| 44 | th = intel_th_alloc(&pdev->dev, pdev->resource, | 88 | th = intel_th_alloc(&pdev->dev, drvdata, pdev->resource, |
| 45 | DEVICE_COUNT_RESOURCE, pdev->irq); | 89 | DEVICE_COUNT_RESOURCE, pdev->irq); |
| 46 | if (IS_ERR(th)) | 90 | if (IS_ERR(th)) |
| 47 | return PTR_ERR(th); | 91 | return PTR_ERR(th); |
| 48 | 92 | ||
| 93 | th->activate = intel_th_pci_activate; | ||
| 94 | th->deactivate = intel_th_pci_deactivate; | ||
| 95 | |||
| 96 | pci_set_master(pdev); | ||
| 97 | |||
| 49 | return 0; | 98 | return 0; |
| 50 | } | 99 | } |
| 51 | 100 | ||
| @@ -56,6 +105,10 @@ static void intel_th_pci_remove(struct pci_dev *pdev) · 4 unmodified lines | |||
| 56 | intel_th_free(th); | 105 | intel_th_free(th); |
| 57 | } | 106 | } |
| 58 | 107 | ||
| 108 | static const struct intel_th_drvdata intel_th_2x = { | ||
| 109 | .tscu_enable = 1, | ||
| 110 | }; | ||
| 111 | |||
| 59 | static const struct pci_device_id intel_th_pci_id_table[] = { | 112 | static const struct pci_device_id intel_th_pci_id_table[] = { |
| 60 | { | 113 | { |
| 61 | PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x9d26), | 114 | PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x9d26), |
| @@ -93,7 +146,17 @@ static const struct pci_device_id intel_th_pci_id_table[] = { · 31 unmodified lines | |||
| 93 | { | 146 | { |
| 94 | /* Gemini Lake */ | 147 | /* Gemini Lake */ |
| 95 | PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x318e), | 148 | PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x318e), |
| 96 | .driver_data = (kernel_ulong_t)0, | 149 | .driver_data = (kernel_ulong_t)&intel_th_2x, |
| 150 | }, | ||
| 151 | { | ||
| 152 | /* Cannon Lake H */ | ||
| 153 | PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xa326), | ||
| 154 | .driver_data = (kernel_ulong_t)&intel_th_2x, | ||
| 155 | }, | ||
| 156 | { | ||
| 157 | /* Cannon Lake LP */ | ||
| 158 | PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x9da6), | ||
| 159 | .driver_data = (kernel_ulong_t)&intel_th_2x, | ||
| 97 | }, | 160 | }, |
| 98 | { 0 }, | 161 | { 0 }, |
| 99 | }; | 162 | }; |
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Intel(R) Trace Hub PTI output driver | 2 | * Intel(R) Trace Hub PTI output driver |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2014-2015 Intel Corporation. | 4 | * Copyright (C) 2014-2016 Intel Corporation. |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
| 7 | * under the terms and conditions of the GNU General Public License, | 7 | * under the terms and conditions of the GNU General Public License, |
| @@ -34,6 +34,8 @@ struct pti_device { · 26 unmodified lines | |||
| 34 | unsigned int freeclk; | 34 | unsigned int freeclk; |
| 35 | unsigned int clkdiv; | 35 | unsigned int clkdiv; |
| 36 | unsigned int patgen; | 36 | unsigned int patgen; |
| 37 | unsigned int lpp_dest_mask; | ||
| 38 | unsigned int lpp_dest; | ||
| 37 | }; | 39 | }; |
| 38 | 40 | ||
| 39 | /* map PTI widths to MODE settings of PTI_CTL register */ | 41 | /* map PTI widths to MODE settings of PTI_CTL register */ |
| @@ -163,6 +165,7 @@ static int intel_th_pti_activate(struct intel_th_device *thdev) · 123 unmodified lines | |||
| 163 | ctl |= PTI_FCEN; | 165 | ctl |= PTI_FCEN; |
| 164 | ctl |= pti->mode << __ffs(PTI_MODE); | 166 | ctl |= pti->mode << __ffs(PTI_MODE); |
| 165 | ctl |= pti->clkdiv << __ffs(PTI_CLKDIV); | 167 | ctl |= pti->clkdiv << __ffs(PTI_CLKDIV); |
| 168 | ctl |= pti->lpp_dest << __ffs(LPP_DEST); | ||
| 166 | 169 | ||
| 167 | iowrite32(ctl, pti->base + REG_PTI_CTL); | 170 | iowrite32(ctl, pti->base + REG_PTI_CTL); |
| 168 | 171 | ||
| @@ -192,6 +195,15 @@ static void read_hw_config(struct pti_device *pti) · 23 unmodified lines | |||
| 192 | pti->mode = pti_width_mode(4); | 195 | pti->mode = pti_width_mode(4); |
| 193 | if (!pti->clkdiv) | 196 | if (!pti->clkdiv) |
| 194 | pti->clkdiv = 1; | 197 | pti->clkdiv = 1; |
| 198 | |||
| 199 | if (pti->thdev->output.type == GTH_LPP) { | ||
| 200 | if (ctl & LPP_PTIPRESENT) | ||
| 201 | pti->lpp_dest_mask |= LPP_DEST_PTI; | ||
| 202 | if (ctl & LPP_BSSBPRESENT) | ||
| 203 | pti->lpp_dest_mask |= LPP_DEST_EXI; | ||
| 204 | if (ctl & LPP_DEST) | ||
| 205 | pti->lpp_dest = 1; | ||
| 206 | } | ||
| 195 | } | 207 | } |
| 196 | 208 | ||
| 197 | static int intel_th_pti_probe(struct intel_th_device *thdev) | 209 | static int intel_th_pti_probe(struct intel_th_device *thdev) |
| @@ -239,10 +251,103 @@ static struct intel_th_driver intel_th_pti_driver = { · 41 unmodified lines | |||
| 239 | }, | 251 | }, |
| 240 | }; | 252 | }; |
| 241 | 253 | ||
| 242 | module_driver(intel_th_pti_driver, | 254 | static const char * const lpp_dest_str[] = { "pti", "exi" }; |
| 243 | intel_th_driver_register, | 255 | |
| 244 | intel_th_driver_unregister); | 256 | static ssize_t lpp_dest_show(struct device *dev, struct device_attribute *attr, |
| 257 | char *buf) | ||
| 258 | { | ||
| 259 | struct pti_device *pti = dev_get_drvdata(dev); | ||
| 260 | ssize_t ret = 0; | ||
| 261 | int i; | ||
| 262 | |||
| 263 | for (i = ARRAY_SIZE(lpp_dest_str) - 1; i >= 0; i--) { | ||
| 264 | const char *fmt = pti->lpp_dest == i ? "[%s] " : "%s "; | ||
| 265 | |||
| 266 | if (!(pti->lpp_dest_mask & BIT(i))) | ||
| 267 | continue; | ||
| 268 | |||
| 269 | ret += scnprintf(buf + ret, PAGE_SIZE - ret, | ||
| 270 | fmt, lpp_dest_str[i]); | ||
| 271 | } | ||
| 272 | |||
| 273 | if (ret) | ||
| 274 | buf[ret - 1] = '\n'; | ||
| 275 | |||
| 276 | return ret; | ||
| 277 | } | ||
| 278 | |||
| 279 | static ssize_t lpp_dest_store(struct device *dev, struct device_attribute *attr, | ||
| 280 | const char *buf, size_t size) | ||
| 281 | { | ||
| 282 | struct pti_device *pti = dev_get_drvdata(dev); | ||
| 283 | ssize_t ret = -EINVAL; | ||
| 284 | int i; | ||
| 285 | |||
| 286 | for (i = 0; i < ARRAY_SIZE(lpp_dest_str); i++) | ||
| 287 | if (sysfs_streq(buf, lpp_dest_str[i])) | ||
| 288 | break; | ||
| 289 | |||
| 290 | if (i < ARRAY_SIZE(lpp_dest_str) && pti->lpp_dest_mask & BIT(i)) { | ||
| 291 | pti->lpp_dest = i; | ||
| 292 | ret = size; | ||
| 293 | } | ||
| 294 | |||
| 295 | return ret; | ||
| 296 | } | ||
| 297 | |||
| 298 | static DEVICE_ATTR_RW(lpp_dest); | ||
| 299 | |||
| 300 | static struct attribute *lpp_output_attrs[] = { | ||
| 301 | &dev_attr_mode.attr, | ||
| 302 | &dev_attr_freerunning_clock.attr, | ||
| 303 | &dev_attr_clock_divider.attr, | ||
| 304 | &dev_attr_lpp_dest.attr, | ||
| 305 | NULL, | ||
| 306 | }; | ||
| 307 | |||
| 308 | static struct attribute_group lpp_output_group = { | ||
| 309 | .attrs = lpp_output_attrs, | ||
| 310 | }; | ||
| 311 | |||
| 312 | static struct intel_th_driver intel_th_lpp_driver = { | ||
| 313 | .probe = intel_th_pti_probe, | ||
| 314 | .remove = intel_th_pti_remove, | ||
| 315 | .activate = intel_th_pti_activate, | ||
| 316 | .deactivate = intel_th_pti_deactivate, | ||
| 317 | .attr_group = &lpp_output_group, | ||
| 318 | .driver = { | ||
| 319 | .name = "lpp", | ||
| 320 | .owner = THIS_MODULE, | ||
| 321 | }, | ||
| 322 | }; | ||
| 323 | |||
| 324 | static int __init intel_th_pti_lpp_init(void) | ||
| 325 | { | ||
| 326 | int err; | ||
| 327 | |||
| 328 | err = intel_th_driver_register(&intel_th_pti_driver); | ||
| 329 | if (err) | ||
| 330 | return err; | ||
| 331 | |||
| 332 | err = intel_th_driver_register(&intel_th_lpp_driver); | ||
| 333 | if (err) { | ||
| 334 | intel_th_driver_unregister(&intel_th_pti_driver); | ||
| 335 | return err; | ||
| 336 | } | ||
| 337 | |||
| 338 | return 0; | ||
| 339 | } | ||
| 340 | |||
| 341 | module_init(intel_th_pti_lpp_init); | ||
| 342 | |||
| 343 | static void __exit intel_th_pti_lpp_exit(void) | ||
| 344 | { | ||
| 345 | intel_th_driver_unregister(&intel_th_pti_driver); | ||
| 346 | intel_th_driver_unregister(&intel_th_lpp_driver); | ||
| 347 | } | ||
| 348 | |||
| 349 | module_exit(intel_th_pti_lpp_exit); | ||
| 245 | 350 | ||
| 246 | MODULE_LICENSE("GPL v2"); | 351 | MODULE_LICENSE("GPL v2"); |
| 247 | MODULE_DESCRIPTION("Intel(R) Trace Hub PTI output driver"); | 352 | MODULE_DESCRIPTION("Intel(R) Trace Hub PTI/LPP output driver"); |
| 248 | MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>"); | 353 | MODULE_AUTHOR("Alexander Shishkin <alexander.shishkin@linux.intel.com>"); |
| @@ -23,7 +23,15 @@ enum { · 22 unmodified lines | |||
| 23 | #define PTI_EN BIT(0) | 23 | #define PTI_EN BIT(0) |
| 24 | #define PTI_FCEN BIT(1) | 24 | #define PTI_FCEN BIT(1) |
| 25 | #define PTI_MODE 0xf0 | 25 | #define PTI_MODE 0xf0 |
| 26 | #define LPP_PTIPRESENT BIT(8) | ||
| 27 | #define LPP_BSSBPRESENT BIT(9) | ||
| 26 | #define PTI_CLKDIV 0x000f0000 | 28 | #define PTI_CLKDIV 0x000f0000 |
| 27 | #define PTI_PATGENMODE 0x00f00000 | 29 | #define PTI_PATGENMODE 0x00f00000 |
| 30 | #define LPP_DEST BIT(25) | ||
| 31 | #define LPP_BSSBACT BIT(30) | ||
| 32 | #define LPP_LPPBUSY BIT(31) | ||
| 33 | |||
| 34 | #define LPP_DEST_PTI BIT(0) | ||
| 35 | #define LPP_DEST_EXI BIT(1) | ||
| 28 | 36 | ||
| 29 | #endif /* __INTEL_TH_STH_H__ */ | 37 | #endif /* __INTEL_TH_STH_H__ */ |
| @@ -566,7 +566,7 @@ static int stm_char_policy_set_ioctl(struct stm_file *stmf, void __user *arg) · 565 unmodified lines | |||
| 566 | if (copy_from_user(&size, arg, sizeof(size))) | 566 | if (copy_from_user(&size, arg, sizeof(size))) |
| 567 | return -EFAULT; | 567 | return -EFAULT; |
| 568 | 568 | ||
| 569 | if (size >= PATH_MAX + sizeof(*id)) | 569 | if (size < sizeof(*id) || size >= PATH_MAX + sizeof(*id)) |
| 570 | return -EINVAL; | 570 | return -EINVAL; |
| 571 | 571 | ||
| 572 | /* | 572 | /* |
| @@ -114,6 +114,12 @@ static struct resource sc24_fpga_resource = { · 113 unmodified lines | |||
| 114 | .flags = IORESOURCE_MEM, | 114 | .flags = IORESOURCE_MEM, |
| 115 | }; | 115 | }; |
| 116 | 116 | ||
| 117 | static struct resource sc31_fpga_resource = { | ||
| 118 | .start = 0xf000e000, | ||
| 119 | .end = 0xf000e000 + CHAM_HEADER_SIZE, | ||
| 120 | .flags = IORESOURCE_MEM, | ||
| 121 | }; | ||
| 122 | |||
| 117 | static struct platform_driver mcb_lpc_driver = { | 123 | static struct platform_driver mcb_lpc_driver = { |
| 118 | .driver = { | 124 | .driver = { |
| 119 | .name = "mcb-lpc", | 125 | .name = "mcb-lpc", |
| @@ -132,6 +138,15 @@ static const struct dmi_system_id mcb_lpc_dmi_table[] = { · 12 unmodified lines | |||
| 132 | .driver_data = (void *)&sc24_fpga_resource, | 138 | .driver_data = (void *)&sc24_fpga_resource, |
| 133 | .callback = mcb_lpc_create_platform_device, | 139 | .callback = mcb_lpc_create_platform_device, |
| 134 | }, | 140 | }, |
| 141 | { | ||
| 142 | .ident = "SC31", | ||
| 143 | .matches = { | ||
| 144 | DMI_MATCH(DMI_SYS_VENDOR, "MEN"), | ||
| 145 | DMI_MATCH(DMI_PRODUCT_VERSION, "14SC31"), | ||
| 146 | }, | ||
| 147 | .driver_data = (void *)&sc31_fpga_resource, | ||
| 148 | .callback = mcb_lpc_create_platform_device, | ||
| 149 | }, | ||
| 135 | {} | 150 | {} |
| 136 | }; | 151 | }; |
| 137 | MODULE_DEVICE_TABLE(dmi, mcb_lpc_dmi_table); | 152 | MODULE_DEVICE_TABLE(dmi, mcb_lpc_dmi_table); |
| @@ -182,7 +182,7 @@ int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase, · 181 unmodified lines | |||
| 182 | int num_cells = 0; | 182 | int num_cells = 0; |
| 183 | uint32_t dtype; | 183 | uint32_t dtype; |
| 184 | int bar_count; | 184 | int bar_count; |
| 185 | int ret = 0; | 185 | int ret; |
| 186 | u32 hsize; | 186 | u32 hsize; |
| 187 | 187 | ||
| 188 | hsize = sizeof(struct chameleon_fpga_header); | 188 | hsize = sizeof(struct chameleon_fpga_header); |
| @@ -210,8 +210,10 @@ int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase, · 21 unmodified lines | |||
| 210 | header->filename); | 210 | header->filename); |
| 211 | 211 | ||
| 212 | bar_count = chameleon_get_bar(&p, mapbase, &cb); | 212 | bar_count = chameleon_get_bar(&p, mapbase, &cb); |
| 213 | if (bar_count < 0) | 213 | if (bar_count < 0) { |
| 214 | ret = bar_count; | ||
| 214 | goto free_header; | 215 | goto free_header; |
| 216 | } | ||
| 215 | 217 | ||
| 216 | for_each_chameleon_cell(dtype, p) { | 218 | for_each_chameleon_cell(dtype, p) { |
| 217 | switch (dtype) { | 219 | switch (dtype) { |
| @@ -60,6 +60,7 @@ lkdtm-$(CONFIG_LKDTM) += lkdtm_core.o · 59 unmodified lines | |||
| 60 | lkdtm-$(CONFIG_LKDTM) += lkdtm_bugs.o | 60 | lkdtm-$(CONFIG_LKDTM) += lkdtm_bugs.o |
| 61 | lkdtm-$(CONFIG_LKDTM) += lkdtm_heap.o | 61 | lkdtm-$(CONFIG_LKDTM) += lkdtm_heap.o |
| 62 | lkdtm-$(CONFIG_LKDTM) += lkdtm_perms.o | 62 | lkdtm-$(CONFIG_LKDTM) += lkdtm_perms.o |
| 63 | lkdtm-$(CONFIG_LKDTM) += lkdtm_refcount.o | ||
| 63 | lkdtm-$(CONFIG_LKDTM) += lkdtm_rodata_objcopy.o | 64 | lkdtm-$(CONFIG_LKDTM) += lkdtm_rodata_objcopy.o |
| 64 | lkdtm-$(CONFIG_LKDTM) += lkdtm_usercopy.o | 65 | lkdtm-$(CONFIG_LKDTM) += lkdtm_usercopy.o |
| 65 | 66 | ||
| @@ -197,7 +197,7 @@ static struct attribute *mid_att_als[] = { · 196 unmodified lines | |||
| 197 | NULL | 197 | NULL |
| 198 | }; | 198 | }; |
| 199 | 199 | ||
| 200 | static struct attribute_group m_als_gr = { | 200 | static const struct attribute_group m_als_gr = { |
| 201 | .name = "apds9802als", | 201 | .name = "apds9802als", |
| 202 | .attrs = mid_att_als | 202 | .attrs = mid_att_als |
| 203 | }; | 203 | }; |
| @@ -298,7 +298,7 @@ static UNIVERSAL_DEV_PM_OPS(apds9802als_pm_ops, apds9802als_suspend, · 94 unmodified lines | |||
| 298 | #define APDS9802ALS_PM_OPS NULL | 298 | #define APDS9802ALS_PM_OPS NULL |
| 299 | #endif /* CONFIG_PM */ | 299 | #endif /* CONFIG_PM */ |
| 300 | 300 | ||
| 301 | static struct i2c_device_id apds9802als_id[] = { | 301 | static const struct i2c_device_id apds9802als_id[] = { |
| 302 | { DRIVER_NAME, 0 }, | 302 | { DRIVER_NAME, 0 }, |
| 303 | { } | 303 | { } |
| 304 | }; | 304 | }; |
| @@ -1051,7 +1051,7 @@ static struct attribute *sysfs_attrs_ctrl[] = { · 1050 unmodified lines | |||
| 1051 | NULL | 1051 | NULL |
| 1052 | }; | 1052 | }; |
| 1053 | 1053 | ||
| 1054 | static struct attribute_group apds990x_attribute_group[] = { | 1054 | static const struct attribute_group apds990x_attribute_group[] = { |
| 1055 | {.attrs = sysfs_attrs_ctrl }, | 1055 | {.attrs = sysfs_attrs_ctrl }, |
| 1056 | }; | 1056 | }; |
| 1057 | 1057 | ||
| @@ -20,6 +20,7 @@ · 19 unmodified lines | |||
| 20 | #include <linux/mfd/syscon.h> | 20 | #include <linux/mfd/syscon.h> |
| 21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
| 22 | #include <linux/of.h> | 22 | #include <linux/of.h> |
| 23 | #include <linux/of_device.h> | ||
| 23 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
| 24 | #include <linux/regmap.h> | 25 | #include <linux/regmap.h> |
| 25 | 26 | ||
| @@ -51,6 +52,13 @@ · 25 unmodified lines | |||
| 51 | #define HICRB_ENSNP0D BIT(14) | 52 | #define HICRB_ENSNP0D BIT(14) |
| 52 | #define HICRB_ENSNP1D BIT(15) | 53 | #define HICRB_ENSNP1D BIT(15) |
| 53 | 54 | ||
| 55 | struct aspeed_lpc_snoop_model_data { | ||
| 56 | /* The ast2400 has bits 14 and 15 as reserved, whereas the ast2500 | ||
| 57 | * can use them. | ||
| 58 | */ | ||
| 59 | unsigned int has_hicrb_ensnp; | ||
| 60 | }; | ||
| 61 | |||
| 54 | struct aspeed_lpc_snoop { | 62 | struct aspeed_lpc_snoop { |
| 55 | struct regmap *regmap; | 63 | struct regmap *regmap; |
| 56 | int irq; | 64 | int irq; |
| @@ -123,10 +131,13 @@ static int aspeed_lpc_snoop_config_irq(struct aspeed_lpc_snoop *lpc_snoop, · 66 unmodified lines | |||
| 123 | } | 131 | } |
| 124 | 132 | ||
| 125 | static int aspeed_lpc_enable_snoop(struct aspeed_lpc_snoop *lpc_snoop, | 133 | static int aspeed_lpc_enable_snoop(struct aspeed_lpc_snoop *lpc_snoop, |
| 126 | int channel, u16 lpc_port) | 134 | struct device *dev, |
| 135 | int channel, u16 lpc_port) | ||
| 127 | { | 136 | { |
| 128 | int rc = 0; | 137 | int rc = 0; |
| 129 | u32 hicr5_en, snpwadr_mask, snpwadr_shift, hicrb_en; | 138 | u32 hicr5_en, snpwadr_mask, snpwadr_shift, hicrb_en; |
| 139 | const struct aspeed_lpc_snoop_model_data *model_data = | ||
| 140 | of_device_get_match_data(dev); | ||
| 130 | 141 | ||
| 131 | /* Create FIFO datastructure */ | 142 | /* Create FIFO datastructure */ |
| 132 | rc = kfifo_alloc(&lpc_snoop->snoop_fifo[channel], | 143 | rc = kfifo_alloc(&lpc_snoop->snoop_fifo[channel], |
| @@ -155,7 +166,9 @@ static int aspeed_lpc_enable_snoop(struct aspeed_lpc_snoop *lpc_snoop, · 22 unmodified lines | |||
| 155 | regmap_update_bits(lpc_snoop->regmap, HICR5, hicr5_en, hicr5_en); | 166 | regmap_update_bits(lpc_snoop->regmap, HICR5, hicr5_en, hicr5_en); |
| 156 | regmap_update_bits(lpc_snoop->regmap, SNPWADR, snpwadr_mask, | 167 | regmap_update_bits(lpc_snoop->regmap, SNPWADR, snpwadr_mask, |
| 157 | lpc_port << snpwadr_shift); | 168 | lpc_port << snpwadr_shift); |
| 158 | regmap_update_bits(lpc_snoop->regmap, HICRB, hicrb_en, hicrb_en); | 169 | if (model_data->has_hicrb_ensnp) |
| 170 | regmap_update_bits(lpc_snoop->regmap, HICRB, | ||
| 171 | hicrb_en, hicrb_en); | ||
| 159 | 172 | ||
| 160 | return rc; | 173 | return rc; |
| 161 | } | 174 | } |
| @@ -213,14 +226,14 @@ static int aspeed_lpc_snoop_probe(struct platform_device *pdev) · 51 unmodified lines | |||
| 213 | if (rc) | 226 | if (rc) |
| 214 | return rc; | 227 | return rc; |
| 215 | 228 | ||
| 216 | rc = aspeed_lpc_enable_snoop(lpc_snoop, 0, port); | 229 | rc = aspeed_lpc_enable_snoop(lpc_snoop, dev, 0, port); |
| 217 | if (rc) | 230 | if (rc) |
| 218 | return rc; | 231 | return rc; |
| 219 | 232 | ||
| 220 | /* Configuration of 2nd snoop channel port is optional */ | 233 | /* Configuration of 2nd snoop channel port is optional */ |
| 221 | if (of_property_read_u32_index(dev->of_node, "snoop-ports", | 234 | if (of_property_read_u32_index(dev->of_node, "snoop-ports", |
| 222 | 1, &port) == 0) { | 235 | 1, &port) == 0) { |
| 223 | rc = aspeed_lpc_enable_snoop(lpc_snoop, 1, port); | 236 | rc = aspeed_lpc_enable_snoop(lpc_snoop, dev, 1, port); |
| 224 | if (rc) | 237 | if (rc) |
| 225 | aspeed_lpc_disable_snoop(lpc_snoop, 0); | 238 | aspeed_lpc_disable_snoop(lpc_snoop, 0); |
| 226 | } | 239 | } |
| @@ -239,8 +252,19 @@ static int aspeed_lpc_snoop_remove(struct platform_device *pdev) · 12 unmodified lines | |||
| 239 | return 0; | 252 | return 0; |
| 240 | } | 253 | } |
| 241 | 254 | ||
| 255 | static const struct aspeed_lpc_snoop_model_data ast2400_model_data = { | ||
| 256 | .has_hicrb_ensnp = 0, | ||
| 257 | }; | ||
| 258 | |||
| 259 | static const struct aspeed_lpc_snoop_model_data ast2500_model_data = { | ||
| 260 | .has_hicrb_ensnp = 1, | ||
| 261 | }; | ||
| 262 | |||
| 242 | static const struct of_device_id aspeed_lpc_snoop_match[] = { | 263 | static const struct of_device_id aspeed_lpc_snoop_match[] = { |
| 243 | { .compatible = "aspeed,ast2500-lpc-snoop" }, | 264 | { .compatible = "aspeed,ast2400-lpc-snoop", |
| 265 | .data = &ast2400_model_data }, | ||
| 266 | { .compatible = "aspeed,ast2500-lpc-snoop", | ||
| 267 | .data = &ast2500_model_data }, | ||
| 244 | { }, | 268 | { }, |
| 245 | }; | 269 | }; |
| 246 | 270 | ||
| @@ -1175,7 +1175,7 @@ static struct attribute *sysfs_attrs[] = { · 1174 unmodified lines | |||
| 1175 | NULL | 1175 | NULL |
| 1176 | }; | 1176 | }; |
| 1177 | 1177 | ||
| 1178 | static struct attribute_group bh1770_attribute_group = { | 1178 | static const struct attribute_group bh1770_attribute_group = { |
| 1179 | .attrs = sysfs_attrs | 1179 | .attrs = sysfs_attrs |
| 1180 | }; | 1180 | }; |
| 1181 | 1181 | ||
| @@ -173,7 +173,7 @@ static ssize_t ds1682_eeprom_write(struct file *filp, struct kobject *kobj, · 172 unmodified lines | |||
| 173 | return count; | 173 | return count; |
| 174 | } | 174 | } |
| 175 | 175 | ||
| 176 | static struct bin_attribute ds1682_eeprom_attr = { | 176 | static const struct bin_attribute ds1682_eeprom_attr = { |
| 177 | .attr = { | 177 | .attr = { |
| 178 | .name = "eeprom", | 178 | .name = "eeprom", |
| 179 | .mode = S_IRUGO | S_IWUSR, | 179 | .mode = S_IRUGO | S_IWUSR, |
| @@ -114,7 +114,7 @@ static ssize_t eeprom_read(struct file *filp, struct kobject *kobj, · 113 unmodified lines | |||
| 114 | return count; | 114 | return count; |
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | static struct bin_attribute eeprom_attr = { | 117 | static const struct bin_attribute eeprom_attr = { |
| 118 | .attr = { | 118 | .attr = { |
| 119 | .name = "eeprom", | 119 | .name = "eeprom", |
| 120 | .mode = S_IRUGO, | 120 | .mode = S_IRUGO, |
| @@ -377,8 +377,6 @@ static int eeprom_93xx46_probe_dt(struct spi_device *spi) · 376 unmodified lines | |||
| 377 | struct device_node *np = spi->dev.of_node; | 377 | struct device_node *np = spi->dev.of_node; |
| 378 | struct eeprom_93xx46_platform_data *pd; | 378 | struct eeprom_93xx46_platform_data *pd; |
| 379 | u32 tmp; | 379 | u32 tmp; |
| 380 | int gpio; | ||
| 381 | enum of_gpio_flags of_flags; | ||
| 382 | int ret; | 380 | int ret; |
| 383 | 381 | ||
| 384 | pd = devm_kzalloc(&spi->dev, sizeof(*pd), GFP_KERNEL); | 382 | pd = devm_kzalloc(&spi->dev, sizeof(*pd), GFP_KERNEL); |
| @@ -403,22 +401,14 @@ static int eeprom_93xx46_probe_dt(struct spi_device *spi) · 18 unmodified lines | |||
| 403 | if (of_property_read_bool(np, "read-only")) | 401 | if (of_property_read_bool(np, "read-only")) |
| 404 | pd->flags |= EE_READONLY; | 402 | pd->flags |= EE_READONLY; |
| 405 | 403 | ||
| 406 | gpio = of_get_named_gpio_flags(np, "select-gpios", 0, &of_flags); | 404 | pd->select = devm_gpiod_get_optional(&spi->dev, "select", |
| 407 | if (gpio_is_valid(gpio)) { | 405 | GPIOD_OUT_LOW); |
| 408 | unsigned long flags = | 406 | if (IS_ERR(pd->select)) |
| 409 | of_flags == OF_GPIO_ACTIVE_LOW ? GPIOF_ACTIVE_LOW : 0; | 407 | return PTR_ERR(pd->select); |
| 410 | 408 | ||
| 411 | ret = devm_gpio_request_one(&spi->dev, gpio, flags, | 409 | pd->prepare = select_assert; |
| 412 | "eeprom_93xx46_select"); | 410 | pd->finish = select_deassert; |
| 413 | if (ret) | 411 | gpiod_direction_output(pd->select, 0); |
| 414 | return ret; | ||
| 415 | |||
| 416 | pd->select = gpio_to_desc(gpio); | ||
| 417 | pd->prepare = select_assert; | ||
| 418 | pd->finish = select_deassert; | ||
| 419 | |||
| 420 | gpiod_direction_output(pd->select, 0); | ||
| 421 | } | ||
| 422 | 412 | ||
| 423 | if (of_id->data) { | 413 | if (of_id->data) { |
| 424 | const struct eeprom_93xx46_devtype_data *data = of_id->data; | 414 | const struct eeprom_93xx46_devtype_data *data = of_id->data; |
| @@ -77,7 +77,7 @@ · 76 unmodified lines | |||
| 77 | #include <linux/sysfs.h> | 77 | #include <linux/sysfs.h> |
| 78 | #include <linux/debugfs.h> | 78 | #include <linux/debugfs.h> |
| 79 | #include <linux/mod_devicetable.h> | 79 | #include <linux/mod_devicetable.h> |
| 80 | #include <linux/of.h> | 80 | #include <linux/property.h> |
| 81 | #include <linux/i2c.h> | 81 | #include <linux/i2c.h> |
| 82 | #include <linux/pci_ids.h> | 82 | #include <linux/pci_ids.h> |
| 83 | #include <linux/delay.h> | 83 | #include <linux/delay.h> |
| @@ -1089,101 +1089,85 @@ static void idt_set_defval(struct idt_89hpesx_dev *pdev) · 1005 unmodified lines | |||
| 1089 | pdev->eeaddr = 0; | 1089 | pdev->eeaddr = 0; |
| 1090 | } | 1090 | } |
| 1091 | 1091 | ||
| 1092 | #ifdef CONFIG_OF | ||
| 1093 | static const struct i2c_device_id ee_ids[]; | 1092 | static const struct i2c_device_id ee_ids[]; |
| 1093 | |||
| 1094 | /* | 1094 | /* |
| 1095 | * idt_ee_match_id() - check whether the node belongs to compatible EEPROMs | 1095 | * idt_ee_match_id() - check whether the node belongs to compatible EEPROMs |
| 1096 | */ | 1096 | */ |
| 1097 | static const struct i2c_device_id *idt_ee_match_id(struct device_node *node) | 1097 | static const struct i2c_device_id *idt_ee_match_id(struct fwnode_handle *fwnode) |
| 1098 | { | 1098 | { |
| 1099 | const struct i2c_device_id *id = ee_ids; | 1099 | const struct i2c_device_id *id = ee_ids; |
| 1100 | const char *compatible, *p; | ||
| 1100 | char devname[I2C_NAME_SIZE]; | 1101 | char devname[I2C_NAME_SIZE]; |
| 1102 | int ret; | ||
| 1101 | 1103 | ||
| 1102 | /* Retrieve the device name without manufacturer name */ | 1104 | ret = fwnode_property_read_string(fwnode, "compatible", &compatible); |
| 1103 | if (of_modalias_node(node, devname, sizeof(devname))) | 1105 | if (ret) |
| 1104 | return NULL; | 1106 | return NULL; |
| 1105 | 1107 | ||
| 1108 | p = strchr(compatible, ','); | ||
| 1109 | strlcpy(devname, p ? p + 1 : compatible, sizeof(devname)); | ||
| 1106 | /* Search through the device name */ | 1110 | /* Search through the device name */ |
| 1107 | while (id->name[0]) { | 1111 | while (id->name[0]) { |
| 1108 | if (strcmp(devname, id->name) == 0) | 1112 | if (strcmp(devname, id->name) == 0) |
| 1109 | return id; | 1113 | return id; |
| 1110 | id++; | 1114 | id++; |
| 1111 | } | 1115 | } |
| 1112 | return NULL; | 1116 | return NULL; |
| 1113 | } | 1117 | } |
| 1114 | 1118 | ||
| 1115 | /* | 1119 | /* |
| 1116 | * idt_get_ofdata() - get IDT i2c-device parameters from device tree | 1120 | * idt_get_fw_data() - get IDT i2c-device parameters from device tree |
| 1117 | * @pdev: Pointer to the driver data | 1121 | * @pdev: Pointer to the driver data |
| 1118 | */ | 1122 | */ |
| 1119 | static void idt_get_ofdata(struct idt_89hpesx_dev *pdev) | 1123 | static void idt_get_fw_data(struct idt_89hpesx_dev *pdev) |
| 1120 | { | 1124 | { |
| 1121 | const struct device_node *node = pdev->client->dev.of_node; | ||
| 1122 | struct device *dev = &pdev->client->dev; | 1125 | struct device *dev = &pdev->client->dev; |
| 1126 | struct fwnode_handle *fwnode; | ||
| 1127 | const struct i2c_device_id *ee_id = NULL; | ||
| 1128 | u32 eeprom_addr; | ||
| 1129 | int ret; | ||
| 1123 | 1130 | ||
| 1124 | /* Read dts node parameters */ | 1131 | device_for_each_child_node(dev, fwnode) { |
| 1125 | if (node) { | 1132 | ee_id = idt_ee_match_id(fwnode); |
| 1126 | const struct i2c_device_id *ee_id = NULL; | 1133 | if (IS_ERR_OR_NULL(ee_id)) { |
| 1127 | struct device_node *child; | 1134 | dev_warn(dev, "Skip unsupported EEPROM device"); |
| 1128 | const __be32 *addr_be; | 1135 | continue; |
| 1129 | int len; | 1136 | } else |
| 1130 | 1137 | break; | |
| 1131 | /* Walk through all child nodes looking for compatible one */ | 1138 | } |
| 1132 | for_each_available_child_of_node(node, child) { | ||
| 1133 | ee_id = idt_ee_match_id(child); | ||
| 1134 | if (IS_ERR_OR_NULL(ee_id)) { | ||
| 1135 | dev_warn(dev, "Skip unsupported child node %s", | ||
| 1136 | child->full_name); | ||
| 1137 | continue; | ||
| 1138 | } else | ||
| 1139 | break; | ||
| 1140 | } | ||
| 1141 | |||
| 1142 | /* If there is no child EEPROM device, then set zero size */ | ||
| 1143 | if (!ee_id) { | ||
| 1144 | idt_set_defval(pdev); | ||
| 1145 | return; | ||
| 1146 | } | ||
| 1147 | 1139 | ||
| 1148 | /* Retrieve EEPROM size */ | 1140 | /* If there is no fwnode EEPROM device, then set zero size */ |
| 1149 | pdev->eesize = (u32)ee_id->driver_data; | 1141 | if (!ee_id) { |
| 1150 | 1142 | dev_warn(dev, "No fwnode, EEPROM access disabled"); | |
| 1151 | /* Get custom EEPROM address from 'reg' attribute */ | 1143 | idt_set_defval(pdev); |
| 1152 | addr_be = of_get_property(child, "reg", &len); | 1144 | return; |
| 1153 | if (!addr_be || (len < sizeof(*addr_be))) { | 1145 | } |
| 1154 | dev_warn(dev, "No reg on %s, use default address %d", | ||
| 1155 | child->full_name, EEPROM_DEF_ADDR); | ||
| 1156 | pdev->inieecmd = 0; | ||
| 1157 | pdev->eeaddr = EEPROM_DEF_ADDR << 1; | ||
| 1158 | } else { | ||
| 1159 | pdev->inieecmd = EEPROM_USA; | ||
| 1160 | pdev->eeaddr = be32_to_cpup(addr_be) << 1; | ||
| 1161 | } | ||
| 1162 | 1146 | ||
| 1163 | /* Check EEPROM 'read-only' flag */ | 1147 | /* Retrieve EEPROM size */ |
| 1164 | if (of_get_property(child, "read-only", NULL)) | 1148 | pdev->eesize = (u32)ee_id->driver_data; |
| 1165 | pdev->eero = true; | ||
| 1166 | else /* if (!of_get_property(node, "read-only", NULL)) */ | ||
| 1167 | pdev->eero = false; | ||
| 1168 | 1149 | ||
| 1169 | dev_dbg(dev, "EEPROM of %u bytes found by %hhu", | 1150 | /* Get custom EEPROM address from 'reg' attribute */ |
| 1170 | pdev->eesize, pdev->eeaddr); | 1151 | ret = fwnode_property_read_u32(fwnode, "reg", &eeprom_addr); |
| 1152 | if (ret || (eeprom_addr == 0)) { | ||
| 1153 | dev_warn(dev, "No EEPROM reg found, use default address 0x%x", | ||
| 1154 | EEPROM_DEF_ADDR); | ||
| 1155 | pdev->inieecmd = 0; | ||
| 1156 | pdev->eeaddr = EEPROM_DEF_ADDR << 1; | ||
| 1171 | } else { | 1157 | } else { |
| 1172 | dev_warn(dev, "No dts node, EEPROM access disabled"); | 1158 | pdev->inieecmd = EEPROM_USA; |
| 1173 | idt_set_defval(pdev); | 1159 | pdev->eeaddr = eeprom_addr << 1; |
| 1174 | } | 1160 | } |
| 1175 | } | ||
| 1176 | #else | ||
| 1177 | static void idt_get_ofdata(struct idt_89hpesx_dev *pdev) | ||
| 1178 | { | ||
| 1179 | struct device *dev = &pdev->client->dev; | ||
| 1180 | 1161 | ||
| 1181 | dev_warn(dev, "OF table is unsupported, EEPROM access disabled"); | 1162 | /* Check EEPROM 'read-only' flag */ |
| 1163 | if (fwnode_property_read_bool(fwnode, "read-only")) | ||
| 1164 | pdev->eero = true; | ||
| 1165 | else /* if (!fwnode_property_read_bool(node, "read-only")) */ | ||
| 1166 | pdev->eero = false; | ||
| 1182 | 1167 | ||
| 1183 | /* Nothing we can do, just set the default values */ | 1168 | dev_info(dev, "EEPROM of %d bytes found by 0x%x", |
| 1184 | idt_set_defval(pdev); | 1169 | pdev->eesize, pdev->eeaddr); |
| 1185 | } | 1170 | } |
| 1186 | #endif /* CONFIG_OF */ | ||
| 1187 | 1171 | ||
| 1188 | /* | 1172 | /* |
| 1189 | * idt_create_pdev() - create and init data structure of the driver | 1173 | * idt_create_pdev() - create and init data structure of the driver |
| @@ -1203,8 +1187,8 @@ static struct idt_89hpesx_dev *idt_create_pdev(struct i2c_client *client) · 13 unmodified lines | |||
| 1203 | pdev->client = client; | 1187 | pdev->client = client; |
| 1204 | i2c_set_clientdata(client, pdev); | 1188 | i2c_set_clientdata(client, pdev); |
| 1205 | 1189 | ||
| 1206 | /* Read OF nodes information */ | 1190 | /* Read firmware nodes information */ |
| 1207 | idt_get_ofdata(pdev); | 1191 | idt_get_fw_data(pdev); |
| 1208 | 1192 | ||
| 1209 | /* Initialize basic CSR CMD field - use full DWORD-sized r/w ops */ | 1193 | /* Initialize basic CSR CMD field - use full DWORD-sized r/w ops */ |
| 1210 | pdev->inicsrcmd = CSR_DWE; | 1194 | pdev->inicsrcmd = CSR_DWE; |
| @@ -124,7 +124,7 @@ static ssize_t max6875_read(struct file *filp, struct kobject *kobj, · 123 unmodified lines | |||
| 124 | return count; | 124 | return count; |
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | static struct bin_attribute user_eeprom_attr = { | 127 | static const struct bin_attribute user_eeprom_attr = { |
| 128 | .attr = { | 128 | .attr = { |
| 129 | .name = "eeprom", | 129 | .name = "eeprom", |
| 130 | .mode = S_IRUGO, | 130 | .mode = S_IRUGO, |
| @@ -132,7 +132,7 @@ static int hmc6352_remove(struct i2c_client *client) · 131 unmodified lines | |||
| 132 | return 0; | 132 | return 0; |
| 133 | } | 133 | } |
| 134 | 134 | ||
| 135 | static struct i2c_device_id hmc6352_id[] = { | 135 | static const struct i2c_device_id hmc6352_id[] = { |
| 136 | { "hmc6352", 0 }, | 136 | { "hmc6352", 0 }, |
| 137 | { } | 137 | { } |
| 138 | }; | 138 | }; |
| @@ -857,7 +857,7 @@ out: · 856 unmodified lines | |||
| 857 | return error; | 857 | return error; |
| 858 | } | 858 | } |
| 859 | 859 | ||
| 860 | static struct pci_device_id ilo_devices[] = { | 860 | static const struct pci_device_id ilo_devices[] = { |
| 861 | { PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xB204) }, | 861 | { PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xB204) }, |
| 862 | { PCI_DEVICE(PCI_VENDOR_ID_HP, 0x3307) }, | 862 | { PCI_DEVICE(PCI_VENDOR_ID_HP, 0x3307) }, |
| 863 | { } | 863 | { } |
| @@ -454,7 +454,7 @@ ioc4_remove(struct pci_dev *pdev) · 453 unmodified lines | |||
| 454 | kfree(idd); | 454 | kfree(idd); |
| 455 | } | 455 | } |
| 456 | 456 | ||
| 457 | static struct pci_device_id ioc4_id_table[] = { | 457 | static const struct pci_device_id ioc4_id_table[] = { |
| 458 | {PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC4, PCI_ANY_ID, | 458 | {PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC4, PCI_ANY_ID, |
| 459 | PCI_ANY_ID, 0x0b4000, 0xFFFFFF}, | 459 | PCI_ANY_ID, 0x0b4000, 0xFFFFFF}, |
| 460 | {0} | 460 | {0} |
| @@ -145,7 +145,7 @@ static struct attribute *mid_att_als[] = { · 144 unmodified lines | |||
| 145 | NULL | 145 | NULL |
| 146 | }; | 146 | }; |
| 147 | 147 | ||
| 148 | static struct attribute_group m_als_gr = { | 148 | static const struct attribute_group m_als_gr = { |
| 149 | .name = "isl29020", | 149 | .name = "isl29020", |
| 150 | .attrs = mid_att_als | 150 | .attrs = mid_att_als |
| 151 | }; | 151 | }; |
| @@ -188,7 +188,7 @@ static int isl29020_remove(struct i2c_client *client) · 36 unmodified lines | |||
| 188 | return 0; | 188 | return 0; |
| 189 | } | 189 | } |
| 190 | 190 | ||
| 191 | static struct i2c_device_id isl29020_id[] = { | 191 | static const struct i2c_device_id isl29020_id[] = { |
| 192 | { "isl29020", 0 }, | 192 | { "isl29020", 0 }, |
| 193 | { } | 193 | { } |
| 194 | }; | 194 | }; |
| @@ -856,7 +856,7 @@ static struct attribute *lis3lv02d_attributes[] = { · 855 unmodified lines | |||
| 856 | NULL | 856 | NULL |
| 857 | }; | 857 | }; |
| 858 | 858 | ||
| 859 | static struct attribute_group lis3lv02d_attribute_group = { | 859 | static const struct attribute_group lis3lv02d_attribute_group = { |
| 860 | .attrs = lis3lv02d_attributes | 860 | .attrs = lis3lv02d_attributes |
| 861 | }; | 861 | }; |
| 862 | 862 | ||
| @@ -14,20 +14,17 @@ void lkdtm_EXCEPTION(void); · 13 unmodified lines | |||
| 14 | void lkdtm_LOOP(void); | 14 | void lkdtm_LOOP(void); |
| 15 | void lkdtm_OVERFLOW(void); | 15 | void lkdtm_OVERFLOW(void); |
| 16 | void lkdtm_CORRUPT_STACK(void); | 16 | void lkdtm_CORRUPT_STACK(void); |
| 17 | void lkdtm_CORRUPT_STACK_STRONG(void); | ||
| 17 | void lkdtm_UNALIGNED_LOAD_STORE_WRITE(void); | 18 | void lkdtm_UNALIGNED_LOAD_STORE_WRITE(void); |
| 18 | void lkdtm_SOFTLOCKUP(void); | 19 | void lkdtm_SOFTLOCKUP(void); |
| 19 | void lkdtm_HARDLOCKUP(void); | 20 | void lkdtm_HARDLOCKUP(void); |
| 20 | void lkdtm_SPINLOCKUP(void); | 21 | void lkdtm_SPINLOCKUP(void); |
| 21 | void lkdtm_HUNG_TASK(void); | 22 | void lkdtm_HUNG_TASK(void); |
| 22 | void lkdtm_REFCOUNT_SATURATE_INC(void); | ||
| 23 | void lkdtm_REFCOUNT_SATURATE_ADD(void); | ||
| 24 | void lkdtm_REFCOUNT_ZERO_DEC(void); | ||
| 25 | void lkdtm_REFCOUNT_ZERO_INC(void); | ||
| 26 | void lkdtm_REFCOUNT_ZERO_SUB(void); | ||
| 27 | void lkdtm_REFCOUNT_ZERO_ADD(void); | ||
| 28 | void lkdtm_CORRUPT_LIST_ADD(void); | 23 | void lkdtm_CORRUPT_LIST_ADD(void); |
| 29 | void lkdtm_CORRUPT_LIST_DEL(void); | 24 | void lkdtm_CORRUPT_LIST_DEL(void); |
| 30 | void lkdtm_CORRUPT_USER_DS(void); | 25 | void lkdtm_CORRUPT_USER_DS(void); |
| 26 | void lkdtm_STACK_GUARD_PAGE_LEADING(void); | ||
| 27 | void lkdtm_STACK_GUARD_PAGE_TRAILING(void); | ||
| 31 | 28 | ||
| 32 | /* lkdtm_heap.c */ | 29 | /* lkdtm_heap.c */ |
| 33 | void lkdtm_OVERWRITE_ALLOCATION(void); | 30 | void lkdtm_OVERWRITE_ALLOCATION(void); |
| @@ -49,6 +46,27 @@ void lkdtm_EXEC_RODATA(void); · 15 unmodified lines | |||
| 49 | void lkdtm_EXEC_USERSPACE(void); | 46 | void lkdtm_EXEC_USERSPACE(void); |
| 50 | void lkdtm_ACCESS_USERSPACE(void); | 47 | void lkdtm_ACCESS_USERSPACE(void); |
| 51 | 48 | ||
| 49 | /* lkdtm_refcount.c */ | ||
| 50 | void lkdtm_REFCOUNT_INC_OVERFLOW(void); | ||
| 51 | void lkdtm_REFCOUNT_ADD_OVERFLOW(void); | ||
| 52 | void lkdtm_REFCOUNT_INC_NOT_ZERO_OVERFLOW(void); | ||
| 53 | void lkdtm_REFCOUNT_ADD_NOT_ZERO_OVERFLOW(void); | ||
| 54 | void lkdtm_REFCOUNT_DEC_ZERO(void); | ||
| 55 | void lkdtm_REFCOUNT_DEC_NEGATIVE(void); | ||
| 56 | void lkdtm_REFCOUNT_DEC_AND_TEST_NEGATIVE(void); | ||
| 57 | void lkdtm_REFCOUNT_SUB_AND_TEST_NEGATIVE(void); | ||
| 58 | void lkdtm_REFCOUNT_INC_ZERO(void); | ||
| 59 | void lkdtm_REFCOUNT_ADD_ZERO(void); | ||
| 60 | void lkdtm_REFCOUNT_INC_SATURATED(void); | ||
| 61 | void lkdtm_REFCOUNT_DEC_SATURATED(void); | ||
| 62 | void lkdtm_REFCOUNT_ADD_SATURATED(void); | ||
| 63 | void lkdtm_REFCOUNT_INC_NOT_ZERO_SATURATED(void); | ||
| 64 | void lkdtm_REFCOUNT_ADD_NOT_ZERO_SATURATED(void); | ||
| 65 | void lkdtm_REFCOUNT_DEC_AND_TEST_SATURATED(void); | ||
| 66 | void lkdtm_REFCOUNT_SUB_AND_TEST_SATURATED(void); | ||
| 67 | void lkdtm_REFCOUNT_TIMING(void); | ||
| 68 | void lkdtm_ATOMIC_TIMING(void); | ||
| 69 | |||
| 52 | /* lkdtm_rodata.c */ | 70 | /* lkdtm_rodata.c */ |
| 53 | void lkdtm_rodata_do_nothing(void); | 71 | void lkdtm_rodata_do_nothing(void); |
| 54 | 72 | ||
| @@ -6,9 +6,9 @@ · 5 unmodified lines | |||
| 6 | */ | 6 | */ |
| 7 | #include "lkdtm.h" | 7 | #include "lkdtm.h" |
| 8 | #include <linux/list.h> | 8 | #include <linux/list.h> |
| 9 | #include <linux/refcount.h> | ||
| 10 | #include <linux/sched.h> | 9 | #include <linux/sched.h> |
| 11 | #include <linux/sched/signal.h> | 10 | #include <linux/sched/signal.h> |
| 11 | #include <linux/sched/task_stack.h> | ||
| 12 | #include <linux/uaccess.h> | 12 | #include <linux/uaccess.h> |
| 13 | 13 | ||
| 14 | struct lkdtm_list { | 14 | struct lkdtm_list { |
| @@ -85,16 +85,31 @@ void lkdtm_OVERFLOW(void) · 70 unmodified lines | |||
| 85 | 85 | ||
| 86 | static noinline void __lkdtm_CORRUPT_STACK(void *stack) | 86 | static noinline void __lkdtm_CORRUPT_STACK(void *stack) |
| 87 | { | 87 | { |
| 88 | memset(stack, 'a', 64); | 88 | memset(stack, '\xff', 64); |
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | /* This should trip the stack canary, not corrupt the return address. */ | ||
| 91 | noinline void lkdtm_CORRUPT_STACK(void) | 92 | noinline void lkdtm_CORRUPT_STACK(void) |
| 92 | { | 93 | { |
| 93 | /* Use default char array length that triggers stack protection. */ | 94 | /* Use default char array length that triggers stack protection. */ |
| 94 | char data[8]; | 95 | char data[8] __aligned(sizeof(void *)); |
| 96 | |||
| 97 | __lkdtm_CORRUPT_STACK(&data); | ||
| 98 | |||
| 99 | pr_info("Corrupted stack containing char array ...\n"); | ||
| 100 | } | ||
| 101 | |||
| 102 | /* Same as above but will only get a canary with -fstack-protector-strong */ | ||
| 103 | noinline void lkdtm_CORRUPT_STACK_STRONG(void) | ||
| 104 | { | ||
| 105 | union { | ||
| 106 | unsigned short shorts[4]; | ||
| 107 | unsigned long *ptr; | ||
| 108 | } data __aligned(sizeof(void *)); | ||
| 109 | |||
| 95 | __lkdtm_CORRUPT_STACK(&data); | 110 | __lkdtm_CORRUPT_STACK(&data); |
| 96 | 111 | ||
| 97 | pr_info("Corrupted stack with '%16s'...\n", data); | 112 | pr_info("Corrupted stack containing union ...\n"); |
| 98 | } | 113 | } |
| 99 | 114 | ||
| 100 | void lkdtm_UNALIGNED_LOAD_STORE_WRITE(void) | 115 | void lkdtm_UNALIGNED_LOAD_STORE_WRITE(void) |
| @@ -137,88 +152,6 @@ void lkdtm_HUNG_TASK(void) · 36 unmodified lines | |||
| 137 | schedule(); | 152 | schedule(); |
| 138 | } | 153 | } |
| 139 | 154 | ||
| 140 | void lkdtm_REFCOUNT_SATURATE_INC(void) | ||
| 141 | { | ||
| 142 | refcount_t over = REFCOUNT_INIT(UINT_MAX - 1); | ||
| 143 | |||
| 144 | pr_info("attempting good refcount decrement\n"); | ||
| 145 | refcount_dec(&over); | ||
| 146 | refcount_inc(&over); | ||
| 147 | |||
| 148 | pr_info("attempting bad refcount inc overflow\n"); | ||
| 149 | refcount_inc(&over); | ||
| 150 | refcount_inc(&over); | ||
| 151 | if (refcount_read(&over) == UINT_MAX) | ||
| 152 | pr_err("Correctly stayed saturated, but no BUG?!\n"); | ||
| 153 | else | ||
| 154 | pr_err("Fail: refcount wrapped\n"); | ||
| 155 | } | ||
| 156 | |||
| 157 | void lkdtm_REFCOUNT_SATURATE_ADD(void) | ||
| 158 | { | ||
| 159 | refcount_t over = REFCOUNT_INIT(UINT_MAX - 1); | ||
| 160 | |||
| 161 | pr_info("attempting good refcount decrement\n"); | ||
| 162 | refcount_dec(&over); | ||
| 163 | refcount_inc(&over); | ||
| 164 | |||
| 165 | pr_info("attempting bad refcount add overflow\n"); | ||
| 166 | refcount_add(2, &over); | ||
| 167 | if (refcount_read(&over) == UINT_MAX) | ||
| 168 | pr_err("Correctly stayed saturated, but no BUG?!\n"); | ||
| 169 | else | ||
| 170 | pr_err("Fail: refcount wrapped\n"); | ||
| 171 | } | ||
| 172 | |||
| 173 | void lkdtm_REFCOUNT_ZERO_DEC(void) | ||
| 174 | { | ||
| 175 | refcount_t zero = REFCOUNT_INIT(1); | ||
| 176 | |||
| 177 | pr_info("attempting bad refcount decrement to zero\n"); | ||
| 178 | refcount_dec(&zero); | ||
| 179 | if (refcount_read(&zero) == 0) | ||
| 180 | pr_err("Stayed at zero, but no BUG?!\n"); | ||
| 181 | else | ||
| 182 | pr_err("Fail: refcount went crazy\n"); | ||
| 183 | } | ||
| 184 | |||
| 185 | void lkdtm_REFCOUNT_ZERO_SUB(void) | ||
| 186 | { | ||
| 187 | refcount_t zero = REFCOUNT_INIT(1); | ||
| 188 | |||
| 189 | pr_info("attempting bad refcount subtract past zero\n"); | ||
| 190 | if (!refcount_sub_and_test(2, &zero)) | ||
| 191 | pr_info("wrap attempt was noticed\n"); | ||
| 192 | if (refcount_read(&zero) == 1) | ||
| 193 | pr_err("Correctly stayed above 0, but no BUG?!\n"); | ||
| 194 | else | ||
| 195 | pr_err("Fail: refcount wrapped\n"); | ||
| 196 | } | ||
| 197 | |||
| 198 | void lkdtm_REFCOUNT_ZERO_INC(void) | ||
| 199 | { | ||
| 200 | refcount_t zero = REFCOUNT_INIT(0); | ||
| 201 | |||
| 202 | pr_info("attempting bad refcount increment from zero\n"); | ||
| 203 | refcount_inc(&zero); | ||
| 204 | if (refcount_read(&zero) == 0) | ||
| 205 | pr_err("Stayed at zero, but no BUG?!\n"); | ||
| 206 | else | ||
| 207 | pr_err("Fail: refcount went past zero\n"); | ||
| 208 | } | ||
| 209 | |||
| 210 | void lkdtm_REFCOUNT_ZERO_ADD(void) | ||
| 211 | { | ||
| 212 | refcount_t zero = REFCOUNT_INIT(0); | ||
| 213 | |||
| 214 | pr_info("attempting bad refcount addition from zero\n"); | ||
| 215 | refcount_add(2, &zero); | ||
| 216 | if (refcount_read(&zero) == 0) | ||
| 217 | pr_err("Stayed at zero, but no BUG?!\n"); | ||
| 218 | else | ||
| 219 | pr_err("Fail: refcount went past zero\n"); | ||
| 220 | } | ||
| 221 | |||
| 222 | void lkdtm_CORRUPT_LIST_ADD(void) | 155 | void lkdtm_CORRUPT_LIST_ADD(void) |
| 223 | { | 156 | { |
| 224 | /* | 157 | /* |
| @@ -282,6 +215,7 @@ void lkdtm_CORRUPT_LIST_DEL(void) · 57 unmodified lines | |||
| 282 | pr_err("list_del() corruption not detected!\n"); | 215 | pr_err("list_del() corruption not detected!\n"); |
| 283 | } | 216 | } |
| 284 | 217 | ||
| 218 | /* Test if unbalanced set_fs(KERNEL_DS)/set_fs(USER_DS) check exists. */ | ||
| 285 | void lkdtm_CORRUPT_USER_DS(void) | 219 | void lkdtm_CORRUPT_USER_DS(void) |
| 286 | { | 220 | { |
| 287 | pr_info("setting bad task size limit\n"); | 221 | pr_info("setting bad task size limit\n"); |
| @@ -290,3 +224,31 @@ void lkdtm_CORRUPT_USER_DS(void) · 2 unmodified lines | |||
| 290 | /* Make sure we do not keep running with a KERNEL_DS! */ | 224 | /* Make sure we do not keep running with a KERNEL_DS! */ |
| 291 | force_sig(SIGKILL, current); | 225 | force_sig(SIGKILL, current); |
| 292 | } | 226 | } |
| 227 | |||
| 228 | /* Test that VMAP_STACK is actually allocating with a leading guard page */ | ||
| 229 | void lkdtm_STACK_GUARD_PAGE_LEADING(void) | ||
| 230 | { | ||
| 231 | const unsigned char *stack = task_stack_page(current); | ||
| 232 | const unsigned char *ptr = stack - 1; | ||
| 233 | volatile unsigned char byte; | ||
| 234 | |||
| 235 | pr_info("attempting bad read from page below current stack\n"); | ||
| 236 | |||
| 237 | byte = *ptr; | ||
| 238 | |||
| 239 | pr_err("FAIL: accessed page before stack!\n"); | ||
| 240 | } | ||
| 241 | |||
| 242 | /* Test that VMAP_STACK is actually allocating with a trailing guard page */ | ||
| 243 | void lkdtm_STACK_GUARD_PAGE_TRAILING(void) | ||
| 244 | { | ||
| 245 | const unsigned char *stack = task_stack_page(current); | ||
| 246 | const unsigned char *ptr = stack + THREAD_SIZE; | ||
| 247 | volatile unsigned char byte; | ||
| 248 | |||
| 249 | pr_info("attempting bad read from page above current stack\n"); | ||
| 250 | |||
| 251 | byte = *ptr; | ||
| 252 | |||
| 253 | pr_err("FAIL: accessed page after stack!\n"); | ||
| 254 | } | ||
| @@ -201,6 +201,9 @@ struct crashtype crashtypes[] = { · 200 unmodified lines | |||
| 201 | CRASHTYPE(CORRUPT_LIST_DEL), | 201 | CRASHTYPE(CORRUPT_LIST_DEL), |
| 202 | CRASHTYPE(CORRUPT_USER_DS), | 202 | CRASHTYPE(CORRUPT_USER_DS), |
| 203 | CRASHTYPE(CORRUPT_STACK), | 203 | CRASHTYPE(CORRUPT_STACK), |
| 204 | CRASHTYPE(CORRUPT_STACK_STRONG), | ||
| 205 | CRASHTYPE(STACK_GUARD_PAGE_LEADING), | ||
| 206 | CRASHTYPE(STACK_GUARD_PAGE_TRAILING), | ||
| 204 | CRASHTYPE(UNALIGNED_LOAD_STORE_WRITE), | 207 | CRASHTYPE(UNALIGNED_LOAD_STORE_WRITE), |
| 205 | CRASHTYPE(OVERWRITE_ALLOCATION), | 208 | CRASHTYPE(OVERWRITE_ALLOCATION), |
| 206 | CRASHTYPE(WRITE_AFTER_FREE), | 209 | CRASHTYPE(WRITE_AFTER_FREE), |
| @@ -221,12 +224,25 @@ struct crashtype crashtypes[] = { · 14 unmodified lines | |||
| 221 | CRASHTYPE(WRITE_RO), | 224 | CRASHTYPE(WRITE_RO), |
| 222 | CRASHTYPE(WRITE_RO_AFTER_INIT), | 225 | CRASHTYPE(WRITE_RO_AFTER_INIT), |
| 223 | CRASHTYPE(WRITE_KERN), | 226 | CRASHTYPE(WRITE_KERN), |
| 224 | CRASHTYPE(REFCOUNT_SATURATE_INC), | 227 | CRASHTYPE(REFCOUNT_INC_OVERFLOW), |
| 225 | CRASHTYPE(REFCOUNT_SATURATE_ADD), | 228 | CRASHTYPE(REFCOUNT_ADD_OVERFLOW), |
| 226 | CRASHTYPE(REFCOUNT_ZERO_DEC), | 229 | CRASHTYPE(REFCOUNT_INC_NOT_ZERO_OVERFLOW), |
| 227 | CRASHTYPE(REFCOUNT_ZERO_INC), | 230 | CRASHTYPE(REFCOUNT_ADD_NOT_ZERO_OVERFLOW), |
| 228 | CRASHTYPE(REFCOUNT_ZERO_SUB), | 231 | CRASHTYPE(REFCOUNT_DEC_ZERO), |
| 229 | CRASHTYPE(REFCOUNT_ZERO_ADD), | 232 | CRASHTYPE(REFCOUNT_DEC_NEGATIVE), |
| 233 | CRASHTYPE(REFCOUNT_DEC_AND_TEST_NEGATIVE), | ||
| 234 | CRASHTYPE(REFCOUNT_SUB_AND_TEST_NEGATIVE), | ||
| 235 | CRASHTYPE(REFCOUNT_INC_ZERO), | ||
| 236 | CRASHTYPE(REFCOUNT_ADD_ZERO), | ||
| 237 | CRASHTYPE(REFCOUNT_INC_SATURATED), | ||
| 238 | CRASHTYPE(REFCOUNT_DEC_SATURATED), | ||
| 239 | CRASHTYPE(REFCOUNT_ADD_SATURATED), | ||
| 240 | CRASHTYPE(REFCOUNT_INC_NOT_ZERO_SATURATED), | ||
| 241 | CRASHTYPE(REFCOUNT_ADD_NOT_ZERO_SATURATED), | ||
| 242 | CRASHTYPE(REFCOUNT_DEC_AND_TEST_SATURATED), | ||
| 243 | CRASHTYPE(REFCOUNT_SUB_AND_TEST_SATURATED), | ||
| 244 | CRASHTYPE(REFCOUNT_TIMING), | ||
| 245 | CRASHTYPE(ATOMIC_TIMING), | ||
| 230 | CRASHTYPE(USERCOPY_HEAP_SIZE_TO), | 246 | CRASHTYPE(USERCOPY_HEAP_SIZE_TO), |
| 231 | CRASHTYPE(USERCOPY_HEAP_SIZE_FROM), | 247 | CRASHTYPE(USERCOPY_HEAP_SIZE_FROM), |
| 232 | CRASHTYPE(USERCOPY_HEAP_FLAG_TO), | 248 | CRASHTYPE(USERCOPY_HEAP_FLAG_TO), |
| @@ -0,0 +1,400 @@ | |||
| 1 | /* | ||
| 2 | * This is for all the tests related to refcount bugs (e.g. overflow, | ||
| 3 | * underflow, reaching zero untested, etc). | ||
| 4 | */ | ||
| 5 | #include "lkdtm.h" | ||
| 6 | #include <linux/refcount.h> | ||
| 7 | |||
| 8 | #ifdef CONFIG_REFCOUNT_FULL | ||
| 9 | #define REFCOUNT_MAX (UINT_MAX - 1) | ||
| 10 | #define REFCOUNT_SATURATED UINT_MAX | ||
| 11 | #else | ||
| 12 | #define REFCOUNT_MAX INT_MAX | ||
| 13 | #define REFCOUNT_SATURATED (INT_MIN / 2) | ||
| 14 | #endif | ||
| 15 | |||
| 16 | static void overflow_check(refcount_t *ref) | ||
| 17 | { | ||
| 18 | switch (refcount_read(ref)) { | ||
| 19 | case REFCOUNT_SATURATED: | ||
| 20 | pr_info("Overflow detected: saturated\n"); | ||
| 21 | break; | ||
| 22 | case REFCOUNT_MAX: | ||
| 23 | pr_warn("Overflow detected: unsafely reset to max\n"); | ||
| 24 | break; | ||
| 25 | default: | ||
| 26 | pr_err("Fail: refcount wrapped to %d\n", refcount_read(ref)); | ||
| 27 | } | ||
| 28 | } | ||
| 29 | |||
| 30 | /* | ||
| 31 | * A refcount_inc() above the maximum value of the refcount implementation, | ||
| 32 | * should at least saturate, and at most also WARN. | ||
| 33 | */ | ||
| 34 | void lkdtm_REFCOUNT_INC_OVERFLOW(void) | ||
| 35 | { | ||
| 36 | refcount_t over = REFCOUNT_INIT(REFCOUNT_MAX - 1); | ||
| 37 | |||
| 38 | pr_info("attempting good refcount_inc() without overflow\n"); | ||
| 39 | refcount_dec(&over); | ||
| 40 | refcount_inc(&over); | ||
| 41 | |||
| 42 | pr_info("attempting bad refcount_inc() overflow\n"); | ||
| 43 | refcount_inc(&over); | ||
| 44 | refcount_inc(&over); | ||
| 45 | |||
| 46 | overflow_check(&over); | ||
| 47 | } | ||
| 48 | |||
| 49 | /* refcount_add() should behave just like refcount_inc() above. */ | ||
| 50 | void lkdtm_REFCOUNT_ADD_OVERFLOW(void) | ||
| 51 | { | ||
| 52 | refcount_t over = REFCOUNT_INIT(REFCOUNT_MAX - 1); | ||
| 53 | |||
| 54 | pr_info("attempting good refcount_add() without overflow\n"); | ||
| 55 | refcount_dec(&over); | ||
| 56 | refcount_dec(&over); | ||
| 57 | refcount_dec(&over); | ||
| 58 | refcount_dec(&over); | ||
| 59 | refcount_add(4, &over); | ||
| 60 | |||
| 61 | pr_info("attempting bad refcount_add() overflow\n"); | ||
| 62 | refcount_add(4, &over); | ||
| 63 | |||
| 64 | overflow_check(&over); | ||
| 65 | } | ||
| 66 | |||
| 67 | /* refcount_inc_not_zero() should behave just like refcount_inc() above. */ | ||
| 68 | void lkdtm_REFCOUNT_INC_NOT_ZERO_OVERFLOW(void) | ||
| 69 | { | ||
| 70 | refcount_t over = REFCOUNT_INIT(REFCOUNT_MAX); | ||
| 71 | |||
| 72 | pr_info("attempting bad refcount_inc_not_zero() overflow\n"); | ||
| 73 | if (!refcount_inc_not_zero(&over)) | ||
| 74 | pr_warn("Weird: refcount_inc_not_zero() reported zero\n"); | ||
| 75 | |||
| 76 | overflow_check(&over); | ||
| 77 | } | ||
| 78 | |||
| 79 | /* refcount_add_not_zero() should behave just like refcount_inc() above. */ | ||
| 80 | void lkdtm_REFCOUNT_ADD_NOT_ZERO_OVERFLOW(void) | ||
| 81 | { | ||
| 82 | refcount_t over = REFCOUNT_INIT(REFCOUNT_MAX); | ||
| 83 | |||
| 84 | pr_info("attempting bad refcount_add_not_zero() overflow\n"); | ||
| 85 | if (!refcount_add_not_zero(6, &over)) | ||
| 86 | pr_warn("Weird: refcount_add_not_zero() reported zero\n"); | ||
| 87 | |||
| 88 | overflow_check(&over); | ||
| 89 | } | ||
| 90 | |||
| 91 | static void check_zero(refcount_t *ref) | ||
| 92 | { | ||
| 93 | switch (refcount_read(ref)) { | ||
| 94 | case REFCOUNT_SATURATED: | ||
| 95 | pr_info("Zero detected: saturated\n"); | ||
| 96 | break; | ||
| 97 | case REFCOUNT_MAX: | ||
| 98 | pr_warn("Zero detected: unsafely reset to max\n"); | ||
| 99 | break; | ||
| 100 | case 0: | ||
| 101 | pr_warn("Still at zero: refcount_inc/add() must not inc-from-0\n"); | ||
| 102 | break; | ||
| 103 | default: | ||
| 104 | pr_err("Fail: refcount went crazy: %d\n", refcount_read(ref)); | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | /* | ||
| 109 | * A refcount_dec(), as opposed to a refcount_dec_and_test(), when it hits | ||
| 110 | * zero it should either saturate (when inc-from-zero isn't protected) | ||
| 111 | * or stay at zero (when inc-from-zero is protected) and should WARN for both. | ||
| 112 | */ | ||
| 113 | void lkdtm_REFCOUNT_DEC_ZERO(void) | ||
| 114 | { | ||
| 115 | refcount_t zero = REFCOUNT_INIT(2); | ||
| 116 | |||
| 117 | pr_info("attempting good refcount_dec()\n"); | ||
| 118 | refcount_dec(&zero); | ||
| 119 | |||
| 120 | pr_info("attempting bad refcount_dec() to zero\n"); | ||
| 121 | refcount_dec(&zero); | ||
| 122 | |||
| 123 | check_zero(&zero); | ||
| 124 | } | ||
| 125 | |||
| 126 | static void check_negative(refcount_t *ref, int start) | ||
| 127 | { | ||
| 128 | /* | ||
| 129 | * CONFIG_REFCOUNT_FULL refuses to move a refcount at all on an | ||
| 130 | * over-sub, so we have to track our starting position instead of | ||
| 131 | * looking only at zero-pinning. | ||
| 132 | */ | ||
| 133 | if (refcount_read(ref) == start) { | ||
| 134 | pr_warn("Still at %d: refcount_inc/add() must not inc-from-0\n", | ||
| 135 | start); | ||
| 136 | return; | ||
| 137 | } | ||
| 138 | |||
| 139 | switch (refcount_read(ref)) { | ||
| 140 | case REFCOUNT_SATURATED: | ||
| 141 | pr_info("Negative detected: saturated\n"); | ||
| 142 | break; | ||
| 143 | case REFCOUNT_MAX: | ||
| 144 | pr_warn("Negative detected: unsafely reset to max\n"); | ||
| 145 | break; | ||
| 146 | default: | ||
| 147 | pr_err("Fail: refcount went crazy: %d\n", refcount_read(ref)); | ||
| 148 | } | ||
| 149 | } | ||
| 150 | |||
| 151 | /* A refcount_dec() going negative should saturate and may WARN. */ | ||
| 152 | void lkdtm_REFCOUNT_DEC_NEGATIVE(void) | ||
| 153 | { | ||
| 154 | refcount_t neg = REFCOUNT_INIT(0); | ||
| 155 | |||
| 156 | pr_info("attempting bad refcount_dec() below zero\n"); | ||
| 157 | refcount_dec(&neg); | ||
| 158 | |||
| 159 | check_negative(&neg, 0); | ||
| 160 | } | ||
| 161 | |||
| 162 | /* | ||
| 163 | * A refcount_dec_and_test() should act like refcount_dec() above when | ||
| 164 | * going negative. | ||
| 165 | */ | ||
| 166 | void lkdtm_REFCOUNT_DEC_AND_TEST_NEGATIVE(void) | ||
| 167 | { | ||
| 168 | refcount_t neg = REFCOUNT_INIT(0); | ||
| 169 | |||
| 170 | pr_info("attempting bad refcount_dec_and_test() below zero\n"); | ||
| 171 | if (refcount_dec_and_test(&neg)) | ||
| 172 | pr_warn("Weird: refcount_dec_and_test() reported zero\n"); | ||
| 173 | |||
| 174 | check_negative(&neg, 0); | ||
| 175 | } | ||
| 176 | |||
| 177 | /* | ||
| 178 | * A refcount_sub_and_test() should act like refcount_dec_and_test() | ||
| 179 | * above when going negative. | ||
| 180 | */ | ||
| 181 | void lkdtm_REFCOUNT_SUB_AND_TEST_NEGATIVE(void) | ||
| 182 | { | ||
| 183 | refcount_t neg = REFCOUNT_INIT(3); | ||
| 184 | |||
| 185 | pr_info("attempting bad refcount_sub_and_test() below zero\n"); | ||
| 186 | if (refcount_sub_and_test(5, &neg)) | ||
| 187 | pr_warn("Weird: refcount_sub_and_test() reported zero\n"); | ||
| 188 | |||
| 189 | check_negative(&neg, 3); | ||
| 190 | } | ||
| 191 | |||
| 192 | static void check_from_zero(refcount_t *ref) | ||
| 193 | { | ||
| 194 | switch (refcount_read(ref)) { | ||
| 195 | case 0: | ||
| 196 | pr_info("Zero detected: stayed at zero\n"); | ||
| 197 | break; | ||
| 198 | case REFCOUNT_SATURATED: | ||
| 199 | pr_info("Zero detected: saturated\n"); | ||
| 200 | break; | ||
| 201 | case REFCOUNT_MAX: | ||
| 202 | pr_warn("Zero detected: unsafely reset to max\n"); | ||
| 203 | break; | ||
| 204 | default: | ||
| 205 | pr_info("Fail: zero not detected, incremented to %d\n", | ||
| 206 | refcount_read(ref)); | ||
| 207 | } | ||
| 208 | } | ||
| 209 | |||
| 210 | /* | ||
| 211 | * A refcount_inc() from zero should pin to zero or saturate and may WARN. | ||
| 212 | * Only CONFIG_REFCOUNT_FULL provides this protection currently. | ||
| 213 | */ | ||
| 214 | void lkdtm_REFCOUNT_INC_ZERO(void) | ||
| 215 | { | ||
| 216 | refcount_t zero = REFCOUNT_INIT(0); | ||
| 217 | |||
| 218 | pr_info("attempting safe refcount_inc_not_zero() from zero\n"); | ||
| 219 | if (!refcount_inc_not_zero(&zero)) { | ||
| 220 | pr_info("Good: zero detected\n"); | ||
| 221 | if (refcount_read(&zero) == 0) | ||
| 222 | pr_info("Correctly stayed at zero\n"); | ||
| 223 | else | ||
| 224 | pr_err("Fail: refcount went past zero!\n"); | ||
| 225 | } else { | ||
| 226 | pr_err("Fail: Zero not detected!?\n"); | ||
| 227 | } | ||
| 228 | |||
| 229 | pr_info("attempting bad refcount_inc() from zero\n"); | ||
| 230 | refcount_inc(&zero); | ||
| 231 | |||
| 232 | check_from_zero(&zero); | ||
| 233 | } | ||
| 234 | |||
| 235 | /* | ||
| 236 | * A refcount_add() should act like refcount_inc() above when starting | ||
| 237 | * at zero. | ||
| 238 | */ | ||
| 239 | void lkdtm_REFCOUNT_ADD_ZERO(void) | ||
| 240 | { | ||
| 241 | refcount_t zero = REFCOUNT_INIT(0); | ||
| 242 | |||
| 243 | pr_info("attempting safe refcount_add_not_zero() from zero\n"); | ||
| 244 | if (!refcount_add_not_zero(3, &zero)) { | ||
| 245 | pr_info("Good: zero detected\n"); | ||
| 246 | if (refcount_read(&zero) == 0) | ||
| 247 | pr_info("Correctly stayed at zero\n"); | ||
| 248 | else | ||
| 249 | pr_err("Fail: refcount went past zero\n"); | ||
| 250 | } else { | ||
| 251 | pr_err("Fail: Zero not detected!?\n"); | ||
| 252 | } | ||
| 253 | |||
| 254 | pr_info("attempting bad refcount_add() from zero\n"); | ||
| 255 | refcount_add(3, &zero); | ||
| 256 | |||
| 257 | check_from_zero(&zero); | ||
| 258 | } | ||
| 259 | |||
| 260 | static void check_saturated(refcount_t *ref) | ||
| 261 | { | ||
| 262 | switch (refcount_read(ref)) { | ||
| 263 | case REFCOUNT_SATURATED: | ||
| 264 | pr_info("Saturation detected: still saturated\n"); | ||
| 265 | break; | ||
| 266 | case REFCOUNT_MAX: | ||
| 267 | pr_warn("Saturation detected: unsafely reset to max\n"); | ||
| 268 | break; | ||
| 269 | default: | ||
| 270 | pr_err("Fail: refcount went crazy: %d\n", refcount_read(ref)); | ||
| 271 | } | ||
| 272 | } | ||
| 273 | |||
| 274 | /* | ||
| 275 | * A refcount_inc() from a saturated value should at most warn about | ||
| 276 | * being saturated already. | ||
| 277 | */ | ||
| 278 | void lkdtm_REFCOUNT_INC_SATURATED(void) | ||
| 279 | { | ||
| 280 | refcount_t sat = REFCOUNT_INIT(REFCOUNT_SATURATED); | ||
| 281 | |||
| 282 | pr_info("attempting bad refcount_inc() from saturated\n"); | ||
| 283 | refcount_inc(&sat); | ||
| 284 | |||
| 285 | check_saturated(&sat); | ||
| 286 | } | ||
| 287 | |||
| 288 | /* Should act like refcount_inc() above from saturated. */ | ||
| 289 | void lkdtm_REFCOUNT_DEC_SATURATED(void) | ||
| 290 | { | ||
| 291 | refcount_t sat = REFCOUNT_INIT(REFCOUNT_SATURATED); | ||
| 292 | |||
| 293 | pr_info("attempting bad refcount_dec() from saturated\n"); | ||
| 294 | refcount_dec(&sat); | ||
| 295 | |||
| 296 | check_saturated(&sat); | ||
| 297 | } | ||
| 298 | |||
| 299 | /* Should act like refcount_inc() above from saturated. */ | ||
| 300 | void lkdtm_REFCOUNT_ADD_SATURATED(void) | ||
| 301 | { | ||
| 302 | refcount_t sat = REFCOUNT_INIT(REFCOUNT_SATURATED); | ||
| 303 | |||
| 304 | pr_info("attempting bad refcount_dec() from saturated\n"); | ||
| 305 | refcount_add(8, &sat); | ||
| 306 | |||
| 307 | check_saturated(&sat); | ||
| 308 | } | ||
| 309 | |||
| 310 | /* Should act like refcount_inc() above from saturated. */ | ||
| 311 | void lkdtm_REFCOUNT_INC_NOT_ZERO_SATURATED(void) | ||
| 312 | { | ||
| 313 | refcount_t sat = REFCOUNT_INIT(REFCOUNT_SATURATED); | ||
| 314 | |||
| 315 | pr_info("attempting bad refcount_inc_not_zero() from saturated\n"); | ||
| 316 | if (!refcount_inc_not_zero(&sat)) | ||
| 317 | pr_warn("Weird: refcount_inc_not_zero() reported zero\n"); | ||
| 318 | |||
| 319 | check_saturated(&sat); | ||
| 320 | } | ||
| 321 | |||
| 322 | /* Should act like refcount_inc() above from saturated. */ | ||
| 323 | void lkdtm_REFCOUNT_ADD_NOT_ZERO_SATURATED(void) | ||
| 324 | { | ||
| 325 | refcount_t sat = REFCOUNT_INIT(REFCOUNT_SATURATED); | ||
| 326 | |||
| 327 | pr_info("attempting bad refcount_add_not_zero() from saturated\n"); | ||
| 328 | if (!refcount_add_not_zero(7, &sat)) | ||
| 329 | pr_warn("Weird: refcount_add_not_zero() reported zero\n"); | ||
| 330 | |||
| 331 | check_saturated(&sat); | ||
| 332 | } | ||
| 333 | |||
| 334 | /* Should act like refcount_inc() above from saturated. */ | ||
| 335 | void lkdtm_REFCOUNT_DEC_AND_TEST_SATURATED(void) | ||
| 336 | { | ||
| 337 | refcount_t sat = REFCOUNT_INIT(REFCOUNT_SATURATED); | ||
| 338 | |||
| 339 | pr_info("attempting bad refcount_dec_and_test() from saturated\n"); | ||
| 340 | if (refcount_dec_and_test(&sat)) | ||
| 341 | pr_warn("Weird: refcount_dec_and_test() reported zero\n"); | ||
| 342 | |||
| 343 | check_saturated(&sat); | ||
| 344 | } | ||
| 345 | |||
| 346 | /* Should act like refcount_inc() above from saturated. */ | ||
| 347 | void lkdtm_REFCOUNT_SUB_AND_TEST_SATURATED(void) | ||
| 348 | { | ||
| 349 | refcount_t sat = REFCOUNT_INIT(REFCOUNT_SATURATED); | ||
| 350 | |||
| 351 | pr_info("attempting bad refcount_sub_and_test() from saturated\n"); | ||
| 352 | if (refcount_sub_and_test(8, &sat)) | ||
| 353 | pr_warn("Weird: refcount_sub_and_test() reported zero\n"); | ||
| 354 | |||
| 355 | check_saturated(&sat); | ||
| 356 | } | ||
| 357 | |||
| 358 | /* Used to time the existing atomic_t when used for reference counting */ | ||
| 359 | void lkdtm_ATOMIC_TIMING(void) | ||
| 360 | { | ||
| 361 | unsigned int i; | ||
| 362 | atomic_t count = ATOMIC_INIT(1); | ||
| 363 | |||
| 364 | for (i = 0; i < INT_MAX - 1; i++) | ||
| 365 | atomic_inc(&count); | ||
| 366 | |||
| 367 | for (i = INT_MAX; i > 0; i--) | ||
| 368 | if (atomic_dec_and_test(&count)) | ||
| 369 | break; | ||
| 370 | |||
| 371 | if (i != 1) | ||
| 372 | pr_err("atomic timing: out of sync up/down cycle: %u\n", i - 1); | ||
| 373 | else | ||
| 374 | pr_info("atomic timing: done\n"); | ||
| 375 | } | ||
| 376 | |||
| 377 | /* | ||
| 378 | * This can be compared to ATOMIC_TIMING when implementing fast refcount | ||
| 379 | * protections. Looking at the number of CPU cycles tells the real story | ||
| 380 | * about performance. For example: | ||
| 381 | * cd /sys/kernel/debug/provoke-crash | ||
| 382 | * perf stat -B -- cat <(echo REFCOUNT_TIMING) > DIRECT | ||
| 383 | */ | ||
| 384 | void lkdtm_REFCOUNT_TIMING(void) | ||
| 385 | { | ||
| 386 | unsigned int i; | ||
| 387 | refcount_t count = REFCOUNT_INIT(1); | ||
| 388 | |||
| 389 | for (i = 0; i < INT_MAX - 1; i++) | ||
| 390 | refcount_inc(&count); | ||
| 391 | |||
| 392 | for (i = INT_MAX; i > 0; i--) | ||
| 393 | if (refcount_dec_and_test(&count)) | ||
| 394 | break; | ||
| 395 | |||
| 396 | if (i != 1) | ||
| 397 | pr_err("refcount: out of sync up/down cycle: %u\n", i - 1); | ||
| 398 | else | ||
| 399 | pr_info("refcount timing: done\n"); | ||
| 400 | } | ||
| @@ -845,7 +845,7 @@ static void mei_cl_bus_dev_release(struct device *dev) · 844 unmodified lines | |||
| 845 | kfree(cldev); | 845 | kfree(cldev); |
| 846 | } | 846 | } |
| 847 | 847 | ||
| 848 | static struct device_type mei_cl_device_type = { | 848 | static const struct device_type mei_cl_device_type = { |
| 849 | .release = mei_cl_bus_dev_release, | 849 | .release = mei_cl_bus_dev_release, |
| 850 | }; | 850 | }; |
| 851 | 851 | ||
| @@ -1354,10 +1354,10 @@ static bool mei_me_fw_type_sps(struct pci_dev *pdev) · 1353 unmodified lines | |||
| 1354 | .quirk_probe = mei_me_fw_type_sps | 1354 | .quirk_probe = mei_me_fw_type_sps |
| 1355 | 1355 | ||
| 1356 | 1356 | ||
| 1357 | #define MEI_CFG_LEGACY_HFS \ | 1357 | #define MEI_CFG_ICH_HFS \ |
| 1358 | .fw_status.count = 0 | 1358 | .fw_status.count = 0 |
| 1359 | 1359 | ||
| 1360 | #define MEI_CFG_ICH_HFS \ | 1360 | #define MEI_CFG_ICH10_HFS \ |
| 1361 | .fw_status.count = 1, \ | 1361 | .fw_status.count = 1, \ |
| 1362 | .fw_status.status[0] = PCI_CFG_HFS_1 | 1362 | .fw_status.status[0] = PCI_CFG_HFS_1 |
| 1363 | 1363 | ||
| @@ -1376,38 +1376,61 @@ static bool mei_me_fw_type_sps(struct pci_dev *pdev) · 12 unmodified lines | |||
| 1376 | .fw_status.status[5] = PCI_CFG_HFS_6 | 1376 | .fw_status.status[5] = PCI_CFG_HFS_6 |
| 1377 | 1377 | ||
| 1378 | /* ICH Legacy devices */ | 1378 | /* ICH Legacy devices */ |
| 1379 | const struct mei_cfg mei_me_legacy_cfg = { | 1379 | static const struct mei_cfg mei_me_ich_cfg = { |
| 1380 | MEI_CFG_LEGACY_HFS, | 1380 | MEI_CFG_ICH_HFS, |
| 1381 | }; | 1381 | }; |
| 1382 | 1382 | ||
| 1383 | /* ICH devices */ | 1383 | /* ICH devices */ |
| 1384 | const struct mei_cfg mei_me_ich_cfg = { | 1384 | static const struct mei_cfg mei_me_ich10_cfg = { |
| 1385 | MEI_CFG_ICH_HFS, | 1385 | MEI_CFG_ICH10_HFS, |
| 1386 | }; | 1386 | }; |
| 1387 | 1387 | ||
| 1388 | /* PCH devices */ | 1388 | /* PCH devices */ |
| 1389 | const struct mei_cfg mei_me_pch_cfg = { | 1389 | static const struct mei_cfg mei_me_pch_cfg = { |
| 1390 | MEI_CFG_PCH_HFS, | 1390 | MEI_CFG_PCH_HFS, |
| 1391 | }; | 1391 | }; |
| 1392 | 1392 | ||
| 1393 | |||
| 1394 | /* PCH Cougar Point and Patsburg with quirk for Node Manager exclusion */ | 1393 | /* PCH Cougar Point and Patsburg with quirk for Node Manager exclusion */ |
| 1395 | const struct mei_cfg mei_me_pch_cpt_pbg_cfg = { | 1394 | static const struct mei_cfg mei_me_pch_cpt_pbg_cfg = { |
| 1396 | MEI_CFG_PCH_HFS, | 1395 | MEI_CFG_PCH_HFS, |
| 1397 | MEI_CFG_FW_NM, | 1396 | MEI_CFG_FW_NM, |
| 1398 | }; | 1397 | }; |
| 1399 | 1398 | ||
| 1400 | /* PCH8 Lynx Point and newer devices */ | 1399 | /* PCH8 Lynx Point and newer devices */ |
| 1401 | const struct mei_cfg mei_me_pch8_cfg = { | 1400 | static const struct mei_cfg mei_me_pch8_cfg = { |
| 1402 | MEI_CFG_PCH8_HFS, | 1401 | MEI_CFG_PCH8_HFS, |
| 1403 | }; | 1402 | }; |
| 1404 | 1403 | ||
| 1405 | /* PCH8 Lynx Point with quirk for SPS Firmware exclusion */ | 1404 | /* PCH8 Lynx Point with quirk for SPS Firmware exclusion */ |
| 1406 | const struct mei_cfg mei_me_pch8_sps_cfg = { | 1405 | static const struct mei_cfg mei_me_pch8_sps_cfg = { |
| 1407 | MEI_CFG_PCH8_HFS, | 1406 | MEI_CFG_PCH8_HFS, |
| 1408 | MEI_CFG_FW_SPS, | 1407 | MEI_CFG_FW_SPS, |
| 1409 | }; | 1408 | }; |
| 1410 | 1409 | ||
| 1410 | /* | ||
| 1411 | * mei_cfg_list - A list of platform platform specific configurations. | ||
| 1412 | * Note: has to be synchronized with enum mei_cfg_idx. | ||
| 1413 | */ | ||
| 1414 | static const struct mei_cfg *const mei_cfg_list[] = { | ||
| 1415 | [MEI_ME_UNDEF_CFG] = NULL, | ||
| 1416 | [MEI_ME_ICH_CFG] = &mei_me_ich_cfg, | ||
| 1417 | [MEI_ME_ICH10_CFG] = &mei_me_ich10_cfg, | ||
| 1418 | [MEI_ME_PCH_CFG] = &mei_me_pch_cfg, | ||
| 1419 | [MEI_ME_PCH_CPT_PBG_CFG] = &mei_me_pch_cpt_pbg_cfg, | ||
| 1420 | [MEI_ME_PCH8_CFG] = &mei_me_pch8_cfg, | ||
| 1421 | [MEI_ME_PCH8_SPS_CFG] = &mei_me_pch8_sps_cfg, | ||
| 1422 | }; | ||
| 1423 | |||
| 1424 | const struct mei_cfg *mei_me_get_cfg(kernel_ulong_t idx) | ||
| 1425 | { | ||
| 1426 | BUILD_BUG_ON(ARRAY_SIZE(mei_cfg_list) != MEI_ME_NUM_CFG); | ||
| 1427 | |||
| 1428 | if (idx >= MEI_ME_NUM_CFG) | ||
| 1429 | return NULL; | ||
| 1430 | |||
| 1431 | return mei_cfg_list[idx]; | ||
| 1432 | }; | ||
| 1433 | |||
| 1411 | /** | 1434 | /** |
| 1412 | * mei_me_dev_init - allocates and initializes the mei device structure | 1435 | * mei_me_dev_init - allocates and initializes the mei device structure |
| 1413 | * | 1436 | * |
| @@ -41,8 +41,7 @@ struct mei_cfg { · 40 unmodified lines | |||
| 41 | #define MEI_PCI_DEVICE(dev, cfg) \ | 41 | #define MEI_PCI_DEVICE(dev, cfg) \ |
| 42 | .vendor = PCI_VENDOR_ID_INTEL, .device = (dev), \ | 42 | .vendor = PCI_VENDOR_ID_INTEL, .device = (dev), \ |
| 43 | .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, \ | 43 | .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, \ |
| 44 | .driver_data = (kernel_ulong_t)&(cfg) | 44 | .driver_data = (kernel_ulong_t)(cfg), |
| 45 | |||
| 46 | 45 | ||
| 47 | #define MEI_ME_RPM_TIMEOUT 500 /* ms */ | 46 | #define MEI_ME_RPM_TIMEOUT 500 /* ms */ |
| 48 | 47 | ||
| @@ -63,12 +62,36 @@ struct mei_me_hw { · 14 unmodified lines | |||
| 63 | 62 | ||
| 64 | #define to_me_hw(dev) (struct mei_me_hw *)((dev)->hw) | 63 | #define to_me_hw(dev) (struct mei_me_hw *)((dev)->hw) |
| 65 | 64 | ||
| 66 | extern const struct mei_cfg mei_me_legacy_cfg; | 65 | /** |
| 67 | extern const struct mei_cfg mei_me_ich_cfg; | 66 | * enum mei_cfg_idx - indices to platform specific configurations. |
| 68 | extern const struct mei_cfg mei_me_pch_cfg; | 67 | * |
| 69 | extern const struct mei_cfg mei_me_pch_cpt_pbg_cfg; | 68 | * Note: has to be synchronized with mei_cfg_list[] |
| 70 | extern const struct mei_cfg mei_me_pch8_cfg; | 69 | * |
| 71 | extern const struct mei_cfg mei_me_pch8_sps_cfg; | 70 | * @MEI_ME_UNDEF_CFG: Lower sentinel. |
| 71 | * @MEI_ME_ICH_CFG: I/O Controller Hub legacy devices. | ||
| 72 | * @MEI_ME_ICH10_CFG: I/O Controller Hub platforms Gen10 | ||
| 73 | * @MEI_ME_PCH_CFG: Platform Controller Hub platforms (Up to Gen8). | ||
| 74 | * @MEI_ME_PCH_CPT_PBG_CFG:Platform Controller Hub workstations | ||
| 75 | * with quirk for Node Manager exclusion. | ||
| 76 | * @MEI_ME_PCH8_CFG: Platform Controller Hub Gen8 and newer | ||
| 77 | * client platforms. | ||
| 78 | * @MEI_ME_PCH8_SPS_CFG: Platform Controller Hub Gen8 and newer | ||
| 79 | * servers platforms with quirk for | ||
| 80 | * SPS firmware exclusion. | ||
| 81 | * @MEI_ME_NUM_CFG: Upper Sentinel. | ||
| 82 | */ | ||
| 83 | enum mei_cfg_idx { | ||
| 84 | MEI_ME_UNDEF_CFG, | ||
| 85 | MEI_ME_ICH_CFG, | ||
| 86 | MEI_ME_ICH10_CFG, | ||
| 87 | MEI_ME_PCH_CFG, | ||
| 88 | MEI_ME_PCH_CPT_PBG_CFG, | ||
| 89 | MEI_ME_PCH8_CFG, | ||
| 90 | MEI_ME_PCH8_SPS_CFG, | ||
| 91 | MEI_ME_NUM_CFG, | ||
| 92 | }; | ||
| 93 | |||
| 94 | const struct mei_cfg *mei_me_get_cfg(kernel_ulong_t idx); | ||
| 72 | 95 | ||
| 73 | struct mei_device *mei_me_dev_init(struct pci_dev *pdev, | 96 | struct mei_device *mei_me_dev_init(struct pci_dev *pdev, |
| 74 | const struct mei_cfg *cfg); | 97 | const struct mei_cfg *cfg); |
| @@ -43,57 +43,58 @@ · 42 unmodified lines | |||
| 43 | 43 | ||
| 44 | /* mei_pci_tbl - PCI Device ID Table */ | 44 | /* mei_pci_tbl - PCI Device ID Table */ |
| 45 | static const struct pci_device_id mei_me_pci_tbl[] = { | 45 | static const struct pci_device_id mei_me_pci_tbl[] = { |
| 46 | {MEI_PCI_DEVICE(MEI_DEV_ID_82946GZ, mei_me_legacy_cfg)}, | 46 | {MEI_PCI_DEVICE(MEI_DEV_ID_82946GZ, MEI_ME_ICH_CFG)}, |
| 47 | {MEI_PCI_DEVICE(MEI_DEV_ID_82G35, mei_me_legacy_cfg)}, | 47 | {MEI_PCI_DEVICE(MEI_DEV_ID_82G35, MEI_ME_ICH_CFG)}, |
| 48 | {MEI_PCI_DEVICE(MEI_DEV_ID_82Q965, mei_me_legacy_cfg)}, | 48 | {MEI_PCI_DEVICE(MEI_DEV_ID_82Q965, MEI_ME_ICH_CFG)}, |
| 49 | {MEI_PCI_DEVICE(MEI_DEV_ID_82G965, mei_me_legacy_cfg)}, | 49 | {MEI_PCI_DEVICE(MEI_DEV_ID_82G965, MEI_ME_ICH_CFG)}, |
| 50 | {MEI_PCI_DEVICE(MEI_DEV_ID_82GM965, mei_me_legacy_cfg)}, | 50 | {MEI_PCI_DEVICE(MEI_DEV_ID_82GM965, MEI_ME_ICH_CFG)}, |
| 51 | {MEI_PCI_DEVICE(MEI_DEV_ID_82GME965, mei_me_legacy_cfg)}, | 51 | {MEI_PCI_DEVICE(MEI_DEV_ID_82GME965, MEI_ME_ICH_CFG)}, |
| 52 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_82Q35, mei_me_legacy_cfg)}, | 52 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_82Q35, MEI_ME_ICH_CFG)}, |
| 53 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_82G33, mei_me_legacy_cfg)}, | 53 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_82G33, MEI_ME_ICH_CFG)}, |
| 54 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_82Q33, mei_me_legacy_cfg)}, | 54 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_82Q33, MEI_ME_ICH_CFG)}, |
| 55 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_82X38, mei_me_legacy_cfg)}, | 55 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_82X38, MEI_ME_ICH_CFG)}, |
| 56 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_3200, mei_me_legacy_cfg)}, | 56 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_3200, MEI_ME_ICH_CFG)}, |
| 57 | 57 | ||
| 58 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_6, mei_me_legacy_cfg)}, | 58 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_6, MEI_ME_ICH_CFG)}, |
| 59 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_7, mei_me_legacy_cfg)}, | 59 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_7, MEI_ME_ICH_CFG)}, |
| 60 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_8, mei_me_legacy_cfg)}, | 60 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_8, MEI_ME_ICH_CFG)}, |
| 61 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_9, mei_me_legacy_cfg)}, | 61 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_9, MEI_ME_ICH_CFG)}, |
| 62 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_10, mei_me_legacy_cfg)}, | 62 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_10, MEI_ME_ICH_CFG)}, |
| 63 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9M_1, mei_me_legacy_cfg)}, | 63 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9M_1, MEI_ME_ICH_CFG)}, |
| 64 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9M_2, mei_me_legacy_cfg)}, | 64 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9M_2, MEI_ME_ICH_CFG)}, |
| 65 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9M_3, mei_me_legacy_cfg)}, | 65 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9M_3, MEI_ME_ICH_CFG)}, |
| 66 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9M_4, mei_me_legacy_cfg)}, | 66 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9M_4, MEI_ME_ICH_CFG)}, |
| 67 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH10_1, mei_me_ich_cfg)}, | 67 | |
| 68 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH10_2, mei_me_ich_cfg)}, | 68 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH10_1, MEI_ME_ICH10_CFG)}, |
| 69 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH10_3, mei_me_ich_cfg)}, | 69 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH10_2, MEI_ME_ICH10_CFG)}, |
| 70 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH10_4, mei_me_ich_cfg)}, | 70 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH10_3, MEI_ME_ICH10_CFG)}, |
| 71 | 71 | {MEI_PCI_DEVICE(MEI_DEV_ID_ICH10_4, MEI_ME_ICH10_CFG)}, | |
| 72 | {MEI_PCI_DEVICE(MEI_DEV_ID_IBXPK_1, mei_me_pch_cfg)}, | 72 | |
| 73 | {MEI_PCI_DEVICE(MEI_DEV_ID_IBXPK_2, mei_me_pch_cfg)}, | 73 | {MEI_PCI_DEVICE(MEI_DEV_ID_IBXPK_1, MEI_ME_PCH_CFG)}, |
| 74 | {MEI_PCI_DEVICE(MEI_DEV_ID_CPT_1, mei_me_pch_cpt_pbg_cfg)}, | 74 | {MEI_PCI_DEVICE(MEI_DEV_ID_IBXPK_2, MEI_ME_PCH_CFG)}, |
| 75 | {MEI_PCI_DEVICE(MEI_DEV_ID_PBG_1, mei_me_pch_cpt_pbg_cfg)}, | 75 | {MEI_PCI_DEVICE(MEI_DEV_ID_CPT_1, MEI_ME_PCH_CPT_PBG_CFG)}, |
| 76 | {MEI_PCI_DEVICE(MEI_DEV_ID_PPT_1, mei_me_pch_cfg)}, | 76 | {MEI_PCI_DEVICE(MEI_DEV_ID_PBG_1, MEI_ME_PCH_CPT_PBG_CFG)}, |
| 77 | {MEI_PCI_DEVICE(MEI_DEV_ID_PPT_2, mei_me_pch_cfg)}, | 77 | {MEI_PCI_DEVICE(MEI_DEV_ID_PPT_1, MEI_ME_PCH_CFG)}, |
| 78 | {MEI_PCI_DEVICE(MEI_DEV_ID_PPT_3, mei_me_pch_cfg)}, | 78 | {MEI_PCI_DEVICE(MEI_DEV_ID_PPT_2, MEI_ME_PCH_CFG)}, |
| 79 | {MEI_PCI_DEVICE(MEI_DEV_ID_LPT_H, mei_me_pch8_sps_cfg)}, | 79 | {MEI_PCI_DEVICE(MEI_DEV_ID_PPT_3, MEI_ME_PCH_CFG)}, |
| 80 | {MEI_PCI_DEVICE(MEI_DEV_ID_LPT_W, mei_me_pch8_sps_cfg)}, | 80 | {MEI_PCI_DEVICE(MEI_DEV_ID_LPT_H, MEI_ME_PCH8_SPS_CFG)}, |
| 81 | {MEI_PCI_DEVICE(MEI_DEV_ID_LPT_LP, mei_me_pch8_cfg)}, | 81 | {MEI_PCI_DEVICE(MEI_DEV_ID_LPT_W, MEI_ME_PCH8_SPS_CFG)}, |
| 82 | {MEI_PCI_DEVICE(MEI_DEV_ID_LPT_HR, mei_me_pch8_sps_cfg)}, | 82 | {MEI_PCI_DEVICE(MEI_DEV_ID_LPT_LP, MEI_ME_PCH8_CFG)}, |
| 83 | {MEI_PCI_DEVICE(MEI_DEV_ID_WPT_LP, mei_me_pch8_cfg)}, | 83 | {MEI_PCI_DEVICE(MEI_DEV_ID_LPT_HR, MEI_ME_PCH8_SPS_CFG)}, |
| 84 | {MEI_PCI_DEVICE(MEI_DEV_ID_WPT_LP_2, mei_me_pch8_cfg)}, | 84 | {MEI_PCI_DEVICE(MEI_DEV_ID_WPT_LP, MEI_ME_PCH8_CFG)}, |
| 85 | 85 | {MEI_PCI_DEVICE(MEI_DEV_ID_WPT_LP_2, MEI_ME_PCH8_CFG)}, | |
| 86 | {MEI_PCI_DEVICE(MEI_DEV_ID_SPT, mei_me_pch8_cfg)}, | 86 | |
| 87 | {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_2, mei_me_pch8_cfg)}, | 87 | {MEI_PCI_DEVICE(MEI_DEV_ID_SPT, MEI_ME_PCH8_CFG)}, |
| 88 | {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H, mei_me_pch8_sps_cfg)}, | 88 | {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_2, MEI_ME_PCH8_CFG)}, |
| 89 | {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H_2, mei_me_pch8_sps_cfg)}, | 89 | {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H, MEI_ME_PCH8_SPS_CFG)}, |
| 90 | {MEI_PCI_DEVICE(MEI_DEV_ID_LBG, mei_me_pch8_cfg)}, | 90 | {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H_2, MEI_ME_PCH8_SPS_CFG)}, |
| 91 | 91 | {MEI_PCI_DEVICE(MEI_DEV_ID_LBG, MEI_ME_PCH8_CFG)}, | |
| 92 | {MEI_PCI_DEVICE(MEI_DEV_ID_BXT_M, mei_me_pch8_cfg)}, | 92 | |
| 93 | {MEI_PCI_DEVICE(MEI_DEV_ID_APL_I, mei_me_pch8_cfg)}, | 93 | {MEI_PCI_DEVICE(MEI_DEV_ID_BXT_M, MEI_ME_PCH8_CFG)}, |
| 94 | 94 | {MEI_PCI_DEVICE(MEI_DEV_ID_APL_I, MEI_ME_PCH8_CFG)}, | |
| 95 | {MEI_PCI_DEVICE(MEI_DEV_ID_KBP, mei_me_pch8_cfg)}, | 95 | |
| 96 | {MEI_PCI_DEVICE(MEI_DEV_ID_KBP_2, mei_me_pch8_cfg)}, | 96 | {MEI_PCI_DEVICE(MEI_DEV_ID_KBP, MEI_ME_PCH8_CFG)}, |
| 97 | {MEI_PCI_DEVICE(MEI_DEV_ID_KBP_2, MEI_ME_PCH8_CFG)}, | ||
| 97 | 98 | ||
| 98 | /* required last entry */ | 99 | /* required last entry */ |
| 99 | {0, } | 100 | {0, } |
| @@ -138,12 +139,15 @@ static bool mei_me_quirk_probe(struct pci_dev *pdev, · 38 unmodified lines | |||
| 138 | */ | 139 | */ |
| 139 | static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | 140 | static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
| 140 | { | 141 | { |
| 141 | const struct mei_cfg *cfg = (struct mei_cfg *)(ent->driver_data); | 142 | const struct mei_cfg *cfg; |
| 142 | struct mei_device *dev; | 143 | struct mei_device *dev; |
| 143 | struct mei_me_hw *hw; | 144 | struct mei_me_hw *hw; |
| 144 | unsigned int irqflags; | 145 | unsigned int irqflags; |
| 145 | int err; | 146 | int err; |
| 146 | 147 | ||
| 148 | cfg = mei_me_get_cfg(ent->driver_data); | ||
| 149 | if (!cfg) | ||
| 150 | return -ENODEV; | ||
| 147 | 151 | ||
| 148 | if (!mei_me_quirk_probe(pdev, cfg)) | 152 | if (!mei_me_quirk_probe(pdev, cfg)) |
| 149 | return -ENODEV; | 153 | return -ENODEV; |
| @@ -491,6 +495,7 @@ static struct pci_driver mei_me_driver = { · 341 unmodified lines | |||
| 491 | .remove = mei_me_remove, | 495 | .remove = mei_me_remove, |
| 492 | .shutdown = mei_me_shutdown, | 496 | .shutdown = mei_me_shutdown, |
| 493 | .driver.pm = MEI_ME_PM_OPS, | 497 | .driver.pm = MEI_ME_PM_OPS, |
| 498 | .driver.probe_type = PROBE_PREFER_ASYNCHRONOUS, | ||
| 494 | }; | 499 | }; |
| 495 | 500 | ||
| 496 | module_pci_driver(mei_me_driver); | 501 | module_pci_driver(mei_me_driver); |
| @@ -659,7 +659,7 @@ static ssize_t store_pch_mac(struct device *dev, struct device_attribute *attr, · 658 unmodified lines | |||
| 659 | 659 | ||
| 660 | static DEVICE_ATTR(pch_mac, S_IRUGO | S_IWUSR, show_pch_mac, store_pch_mac); | 660 | static DEVICE_ATTR(pch_mac, S_IRUGO | S_IWUSR, show_pch_mac, store_pch_mac); |
| 661 | 661 | ||
| 662 | static struct bin_attribute pch_bin_attr = { | 662 | static const struct bin_attribute pch_bin_attr = { |
| 663 | .attr = { | 663 | .attr = { |
| 664 | .name = "pch_firmware", | 664 | .name = "pch_firmware", |
| 665 | .mode = S_IRUGO | S_IWUSR, | 665 | .mode = S_IRUGO | S_IWUSR, |
| @@ -891,7 +891,7 @@ static int pch_phub_resume(struct pci_dev *pdev) · 225 unmodified lines | |||
| 891 | #define pch_phub_resume NULL | 891 | #define pch_phub_resume NULL |
| 892 | #endif /* CONFIG_PM */ | 892 | #endif /* CONFIG_PM */ |
| 893 | 893 | ||
| 894 | static struct pci_device_id pch_phub_pcidev_id[] = { | 894 | static const struct pci_device_id pch_phub_pcidev_id[] = { |
| 895 | { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH1_PHUB), 1, }, | 895 | { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH1_PHUB), 1, }, |
| 896 | { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ROHM_ML7213_PHUB), 2, }, | 896 | { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ROHM_ML7213_PHUB), 2, }, |
| 897 | { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ROHM_ML7223_mPHUB), 3, }, | 897 | { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ROHM_ML7223_mPHUB), 3, }, |
| @@ -196,15 +196,15 @@ static int sram_reserve_regions(struct sram_dev *sram, struct resource *res) · 195 unmodified lines | |||
| 196 | ret = of_address_to_resource(child, 0, &child_res); | 196 | ret = of_address_to_resource(child, 0, &child_res); |
| 197 | if (ret < 0) { | 197 | if (ret < 0) { |
| 198 | dev_err(sram->dev, | 198 | dev_err(sram->dev, |
| 199 | "could not get address for node %s\n", | 199 | "could not get address for node %pOF\n", |
| 200 | child->full_name); | 200 | child); |
| 201 | goto err_chunks; | 201 | goto err_chunks; |
| 202 | } | 202 | } |
| 203 | 203 | ||
| 204 | if (child_res.start < res->start || child_res.end > res->end) { | 204 | if (child_res.start < res->start || child_res.end > res->end) { |
| 205 | dev_err(sram->dev, | 205 | dev_err(sram->dev, |
| 206 | "reserved block %s outside the sram area\n", | 206 | "reserved block %pOF outside the sram area\n", |
| 207 | child->full_name); | 207 | child); |
| 208 | ret = -EINVAL; | 208 | ret = -EINVAL; |
| 209 | goto err_chunks; | 209 | goto err_chunks; |
| 210 | } | 210 | } |
| @@ -230,8 +230,8 @@ static int sram_reserve_regions(struct sram_dev *sram, struct resource *res) · 19 unmodified lines | |||
| 230 | ret = of_property_read_string(child, "label", &label); | 230 | ret = of_property_read_string(child, "label", &label); |
| 231 | if (ret && ret != -EINVAL) { | 231 | if (ret && ret != -EINVAL) { |
| 232 | dev_err(sram->dev, | 232 | dev_err(sram->dev, |
| 233 | "%s has invalid label name\n", | 233 | "%pOF has invalid label name\n", |
| 234 | child->full_name); | 234 | child); |
| 235 | goto err_chunks; | 235 | goto err_chunks; |
| 236 | } | 236 | } |
| 237 | if (!label) | 237 | if (!label) |
| @@ -660,7 +660,7 @@ static struct attribute *uim_attrs[] = { · 659 unmodified lines | |||
| 660 | NULL, | 660 | NULL, |
| 661 | }; | 661 | }; |
| 662 | 662 | ||
| 663 | static struct attribute_group uim_attr_grp = { | 663 | static const struct attribute_group uim_attr_grp = { |
| 664 | .attrs = uim_attrs, | 664 | .attrs = uim_attrs, |
| 665 | }; | 665 | }; |
| 666 | 666 | ||
| @@ -415,7 +415,7 @@ static void tifm_7xx1_remove(struct pci_dev *dev) · 414 unmodified lines | |||
| 415 | tifm_free_adapter(fm); | 415 | tifm_free_adapter(fm); |
| 416 | } | 416 | } |
| 417 | 417 | ||
| 418 | static struct pci_device_id tifm_7xx1_pci_tbl [] = { | 418 | static const struct pci_device_id tifm_7xx1_pci_tbl[] = { |
| 419 | { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX21_XX11_FM, PCI_ANY_ID, | 419 | { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX21_XX11_FM, PCI_ANY_ID, |
| 420 | PCI_ANY_ID, 0, 0, 0 }, /* xx21 - the one I have */ | 420 | PCI_ANY_ID, 0, 0, 0 }, /* xx21 - the one I have */ |
| 421 | { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX12_FM, PCI_ANY_ID, | 421 | { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX12_FM, PCI_ANY_ID, |
| @@ -2235,14 +2235,8 @@ int vmci_qp_broker_detach(struct vmci_handle handle, struct vmci_ctx *context) · 2234 unmodified lines | |||
| 2235 | handle.context, handle.resource, | 2235 | handle.context, handle.resource, |
| 2236 | result); | 2236 | result); |
| 2237 | 2237 | ||
| 2238 | if (entry->vmci_page_files) | 2238 | qp_host_unregister_user_memory(entry->produce_q, |
| 2239 | qp_host_unregister_user_memory(entry->produce_q, | 2239 | entry->consume_q); |
| 2240 | entry-> | ||
| 2241 | consume_q); | ||
| 2242 | else | ||
| 2243 | qp_host_unregister_user_memory(entry->produce_q, | ||
| 2244 | entry-> | ||
| 2245 | consume_q); | ||
| 2246 | 2240 | ||
| 2247 | } | 2241 | } |
| 2248 | 2242 | ||
| @@ -2,6 +2,11 @@ · 1 unmodified line | |||
| 2 | # Makefile for multiplexer devices. | 2 | # Makefile for multiplexer devices. |
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | mux-core-objs := core.o | ||
| 6 | mux-adg792a-objs := adg792a.o | ||
| 7 | mux-gpio-objs := gpio.o | ||
| 8 | mux-mmio-objs := mmio.o | ||
| 9 | |||
| 5 | obj-$(CONFIG_MULTIPLEXER) += mux-core.o | 10 | obj-$(CONFIG_MULTIPLEXER) += mux-core.o |
| 6 | obj-$(CONFIG_MUX_ADG792A) += mux-adg792a.o | 11 | obj-$(CONFIG_MUX_ADG792A) += mux-adg792a.o |
| 7 | obj-$(CONFIG_MUX_GPIO) += mux-gpio.o | 12 | obj-$(CONFIG_MUX_GPIO) += mux-gpio.o |
File renamed without changes.
| @@ -58,7 +58,7 @@ static void mux_chip_release(struct device *dev) · 57 unmodified lines | |||
| 58 | kfree(mux_chip); | 58 | kfree(mux_chip); |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | static struct device_type mux_type = { | 61 | static const struct device_type mux_type = { |
| 62 | .name = "mux-chip", | 62 | .name = "mux-chip", |
| 63 | .release = mux_chip_release, | 63 | .release = mux_chip_release, |
| 64 | }; | 64 | }; |
| @@ -452,8 +452,8 @@ struct mux_control *mux_control_get(struct device *dev, const char *mux_name) · 387 unmodified lines | |||
| 452 | "mux-controls", "#mux-control-cells", | 452 | "mux-controls", "#mux-control-cells", |
| 453 | index, &args); | 453 | index, &args); |
| 454 | if (ret) { | 454 | if (ret) { |
| 455 | dev_err(dev, "%s: failed to get mux-control %s(%i)\n", | 455 | dev_err(dev, "%pOF: failed to get mux-control %s(%i)\n", |
| 456 | np->full_name, mux_name ?: "", index); | 456 | np, mux_name ?: "", index); |
| 457 | return ERR_PTR(ret); | 457 | return ERR_PTR(ret); |
| 458 | } | 458 | } |
| 459 | 459 | ||
| @@ -464,8 +464,8 @@ struct mux_control *mux_control_get(struct device *dev, const char *mux_name) · 4 unmodified lines | |||
| 464 | 464 | ||
| 465 | if (args.args_count > 1 || | 465 | if (args.args_count > 1 || |
| 466 | (!args.args_count && (mux_chip->controllers > 1))) { | 466 | (!args.args_count && (mux_chip->controllers > 1))) { |
| 467 | dev_err(dev, "%s: wrong #mux-control-cells for %s\n", | 467 | dev_err(dev, "%pOF: wrong #mux-control-cells for %pOF\n", |
| 468 | np->full_name, args.np->full_name); | 468 | np, args.np); |
| 469 | return ERR_PTR(-EINVAL); | 469 | return ERR_PTR(-EINVAL); |
| 470 | } | 470 | } |
| 471 | 471 | ||
| @@ -474,8 +474,8 @@ struct mux_control *mux_control_get(struct device *dev, const char *mux_name) · 2 unmodified lines | |||
| 474 | controller = args.args[0]; | 474 | controller = args.args[0]; |
| 475 | 475 | ||
| 476 | if (controller >= mux_chip->controllers) { | 476 | if (controller >= mux_chip->controllers) { |
| 477 | dev_err(dev, "%s: bad mux controller %u specified in %s\n", | 477 | dev_err(dev, "%pOF: bad mux controller %u specified in %pOF\n", |
| 478 | np->full_name, controller, args.np->full_name); | 478 | np, controller, args.np); |
| 479 | return ERR_PTR(-EINVAL); | 479 | return ERR_PTR(-EINVAL); |
| 480 | } | 480 | } |
| 481 | 481 | ||
File renamed without changes.
File renamed without changes.
| @@ -290,7 +290,7 @@ static struct nvmem_cell *nvmem_find_cell(const char *cell_id) · 289 unmodified lines | |||
| 290 | mutex_lock(&nvmem_cells_mutex); | 290 | mutex_lock(&nvmem_cells_mutex); |
| 291 | 291 | ||
| 292 | list_for_each_entry(p, &nvmem_cells, node) | 292 | list_for_each_entry(p, &nvmem_cells, node) |
| 293 | if (p && !strcmp(p->name, cell_id)) { | 293 | if (!strcmp(p->name, cell_id)) { |
| 294 | mutex_unlock(&nvmem_cells_mutex); | 294 | mutex_unlock(&nvmem_cells_mutex); |
| 295 | return p; | 295 | return p; |
| 296 | } | 296 | } |
| @@ -794,8 +794,8 @@ struct nvmem_cell *of_nvmem_cell_get(struct device_node *np, · 497 unmodified lines | |||
| 794 | 794 | ||
| 795 | addr = of_get_property(cell_np, "reg", &len); | 795 | addr = of_get_property(cell_np, "reg", &len); |
| 796 | if (!addr || (len < 2 * sizeof(u32))) { | 796 | if (!addr || (len < 2 * sizeof(u32))) { |
| 797 | dev_err(&nvmem->dev, "nvmem: invalid reg on %s\n", | 797 | dev_err(&nvmem->dev, "nvmem: invalid reg on %pOF\n", |
| 798 | cell_np->full_name); | 798 | cell_np); |
| 799 | rval = -EINVAL; | 799 | rval = -EINVAL; |
| 800 | goto err_mem; | 800 | goto err_mem; |
| 801 | } | 801 | } |
| @@ -1110,6 +1110,43 @@ int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len) · 308 unmodified lines | |||
| 1110 | } | 1110 | } |
| 1111 | EXPORT_SYMBOL_GPL(nvmem_cell_write); | 1111 | EXPORT_SYMBOL_GPL(nvmem_cell_write); |
| 1112 | 1112 | ||
| 1113 | /** | ||
| 1114 | * nvmem_cell_read_u32() - Read a cell value as an u32 | ||
| 1115 | * | ||
| 1116 | * @dev: Device that requests the nvmem cell. | ||
| 1117 | * @cell_id: Name of nvmem cell to read. | ||
| 1118 | * @val: pointer to output value. | ||
| 1119 | * | ||
| 1120 | * Return: 0 on success or negative errno. | ||
| 1121 | */ | ||
| 1122 | int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val) | ||
| 1123 | { | ||
| 1124 | struct nvmem_cell *cell; | ||
| 1125 | void *buf; | ||
| 1126 | size_t len; | ||
| 1127 | |||
| 1128 | cell = nvmem_cell_get(dev, cell_id); | ||
| 1129 | if (IS_ERR(cell)) | ||
| 1130 | return PTR_ERR(cell); | ||
| 1131 | |||
| 1132 | buf = nvmem_cell_read(cell, &len); | ||
| 1133 | if (IS_ERR(buf)) { | ||
| 1134 | nvmem_cell_put(cell); | ||
| 1135 | return PTR_ERR(buf); | ||
| 1136 | } | ||
| 1137 | if (len != sizeof(*val)) { | ||
| 1138 | kfree(buf); | ||
| 1139 | nvmem_cell_put(cell); | ||
| 1140 | return -EINVAL; | ||
| 1141 | } | ||
| 1142 | memcpy(val, buf, sizeof(*val)); | ||
| 1143 | |||
| 1144 | kfree(buf); | ||
| 1145 | nvmem_cell_put(cell); | ||
| 1146 | return 0; | ||
| 1147 | } | ||
| 1148 | EXPORT_SYMBOL_GPL(nvmem_cell_read_u32); | ||
| 1149 | |||
| 1113 | /** | 1150 | /** |
| 1114 | * nvmem_device_cell_read() - Read a given nvmem device and cell | 1151 | * nvmem_device_cell_read() - Read a given nvmem device and cell |
| 1115 | * | 1152 | * |
| @@ -197,7 +197,7 @@ static int lpc18xx_eeprom_probe(struct platform_device *pdev) · 196 unmodified lines | |||
| 197 | return ret; | 197 | return ret; |
| 198 | } | 198 | } |
| 199 | 199 | ||
| 200 | rst = devm_reset_control_get(dev, NULL); | 200 | rst = devm_reset_control_get_exclusive(dev, NULL); |
| 201 | if (IS_ERR(rst)) { | 201 | if (IS_ERR(rst)) { |
| 202 | dev_err(dev, "failed to get reset: %ld\n", PTR_ERR(rst)); | 202 | dev_err(dev, "failed to get reset: %ld\n", PTR_ERR(rst)); |
| 203 | ret = PTR_ERR(rst); | 203 | ret = PTR_ERR(rst); |
| @@ -44,7 +44,7 @@ static struct daisydev { · 43 unmodified lines | |||
| 44 | } *topology = NULL; | 44 | } *topology = NULL; |
| 45 | static DEFINE_SPINLOCK(topology_lock); | 45 | static DEFINE_SPINLOCK(topology_lock); |
| 46 | 46 | ||
| 47 | static int numdevs = 0; | 47 | static int numdevs; |
| 48 | 48 | ||
| 49 | /* Forward-declaration of lower-level functions. */ | 49 | /* Forward-declaration of lower-level functions. */ |
| 50 | static int mux_present(struct parport *port); | 50 | static int mux_present(struct parport *port); |
| @@ -18,7 +18,7 @@ · 17 unmodified lines | |||
| 18 | #include <asm/irq.h> | 18 | #include <asm/irq.h> |
| 19 | #include <asm/atariints.h> | 19 | #include <asm/atariints.h> |
| 20 | 20 | ||
| 21 | static struct parport *this_port = NULL; | 21 | static struct parport *this_port; |
| 22 | 22 | ||
| 23 | static unsigned char | 23 | static unsigned char |
| 24 | parport_atari_read_data(struct parport *p) | 24 | parport_atari_read_data(struct parport *p) |
| @@ -358,8 +358,7 @@ static int parport_ax88796_probe(struct platform_device *pdev) · 357 unmodified lines | |||
| 358 | exit_unmap: | 358 | exit_unmap: |
| 359 | iounmap(dd->base); | 359 | iounmap(dd->base); |
| 360 | exit_res: | 360 | exit_res: |
| 361 | release_resource(dd->io); | 361 | release_mem_region(dd->io->start, size); |
| 362 | kfree(dd->io); | ||
| 363 | exit_mem: | 362 | exit_mem: |
| 364 | kfree(dd); | 363 | kfree(dd); |
| 365 | return ret; | 364 | return ret; |
| @@ -373,8 +372,7 @@ static int parport_ax88796_remove(struct platform_device *pdev) · 7 unmodified lines | |||
| 373 | free_irq(p->irq, p); | 372 | free_irq(p->irq, p); |
| 374 | parport_remove_port(p); | 373 | parport_remove_port(p); |
| 375 | iounmap(dd->base); | 374 | iounmap(dd->base); |
| 376 | release_resource(dd->io); | 375 | release_mem_region(dd->io->start, resource_size(dd->io)); |
| 377 | kfree(dd->io); | ||
| 378 | kfree(dd); | 376 | kfree(dd); |
| 379 | 377 | ||
| 380 | return 0; | 378 | return 0; |
| @@ -138,7 +138,7 @@ static unsigned int features = ~0U; · 137 unmodified lines | |||
| 138 | static bool verbose_probing = DEFAULT_VERBOSE_PROBING; | 138 | static bool verbose_probing = DEFAULT_VERBOSE_PROBING; |
| 139 | 139 | ||
| 140 | /* We do not support more than one port. */ | 140 | /* We do not support more than one port. */ |
| 141 | static struct parport *this_port = NULL; | 141 | static struct parport *this_port; |
| 142 | 142 | ||
| 143 | /* Timing constants for FIFO modes. */ | 143 | /* Timing constants for FIFO modes. */ |
| 144 | #define FIFO_NFAULT_TIMEOUT 100 /* milliseconds */ | 144 | #define FIFO_NFAULT_TIMEOUT 100 /* milliseconds */ |
| @@ -174,7 +174,7 @@ DPRINTK(KERN_DEBUG "read_status %02x\n", status); · 173 unmodified lines | |||
| 174 | return status; | 174 | return status; |
| 175 | } | 175 | } |
| 176 | 176 | ||
| 177 | static int use_cnt = 0; | 177 | static int use_cnt; |
| 178 | 178 | ||
| 179 | static irqreturn_t mfc3_interrupt(int irq, void *dev_id) | 179 | static irqreturn_t mfc3_interrupt(int irq, void *dev_id) |
| 180 | { | 180 | { |
| @@ -1083,9 +1083,9 @@ static void show_parconfig_winbond(int io, int key) · 1082 unmodified lines | |||
| 1083 | printk(KERN_INFO "Winbond LPT Config: active=%s, io=0x%02x%02x irq=%d, ", | 1083 | printk(KERN_INFO "Winbond LPT Config: active=%s, io=0x%02x%02x irq=%d, ", |
| 1084 | (cr30 & 0x01) ? "yes" : "no", cr60, cr61, cr70 & 0x0f); | 1084 | (cr30 & 0x01) ? "yes" : "no", cr60, cr61, cr70 & 0x0f); |
| 1085 | if ((cr74 & 0x07) > 3) | 1085 | if ((cr74 & 0x07) > 3) |
| 1086 | printk("dma=none\n"); | 1086 | pr_cont("dma=none\n"); |
| 1087 | else | 1087 | else |
| 1088 | printk("dma=%d\n", cr74 & 0x07); | 1088 | pr_cont("dma=%d\n", cr74 & 0x07); |
| 1089 | printk(KERN_INFO | 1089 | printk(KERN_INFO |
| 1090 | "Winbond LPT Config: irqtype=%s, ECP fifo threshold=%d\n", | 1090 | "Winbond LPT Config: irqtype=%s, ECP fifo threshold=%d\n", |
| 1091 | irqtypes[crf0>>7], (crf0>>3)&0x0f); | 1091 | irqtypes[crf0>>7], (crf0>>3)&0x0f); |
| @@ -1685,14 +1685,14 @@ static int parport_ECP_supported(struct parport *pb) · 593 unmodified lines | |||
| 1685 | pb->base, config, configb); | 1685 | pb->base, config, configb); |
| 1686 | printk(KERN_DEBUG "0x%lx: ECP settings irq=", pb->base); | 1686 | printk(KERN_DEBUG "0x%lx: ECP settings irq=", pb->base); |
| 1687 | if ((configb >> 3) & 0x07) | 1687 | if ((configb >> 3) & 0x07) |
| 1688 | printk("%d", intrline[(configb >> 3) & 0x07]); | 1688 | pr_cont("%d", intrline[(configb >> 3) & 0x07]); |
| 1689 | else | 1689 | else |
| 1690 | printk("<none or set by other means>"); | 1690 | pr_cont("<none or set by other means>"); |
| 1691 | printk(" dma="); | 1691 | pr_cont(" dma="); |
| 1692 | if ((configb & 0x03) == 0x00) | 1692 | if ((configb & 0x03) == 0x00) |
| 1693 | printk("<none or set by other means>\n"); | 1693 | pr_cont("<none or set by other means>\n"); |
| 1694 | else | 1694 | else |
| 1695 | printk("%d\n", configb & 0x07); | 1695 | pr_cont("%d\n", configb & 0x07); |
| 1696 | } | 1696 | } |
| 1697 | 1697 | ||
| 1698 | /* Go back to mode 000 */ | 1698 | /* Go back to mode 000 */ |
| @@ -2399,8 +2399,8 @@ static int sio_ite_8872_probe(struct pci_dev *pdev, int autoirq, int autodma, · 700 unmodified lines | |||
| 2399 | "parport_pc: ITE 8872 parallel port: io=0x%X", | 2399 | "parport_pc: ITE 8872 parallel port: io=0x%X", |
| 2400 | ite8872_lpt); | 2400 | ite8872_lpt); |
| 2401 | if (irq != PARPORT_IRQ_NONE) | 2401 | if (irq != PARPORT_IRQ_NONE) |
| 2402 | printk(", irq=%d", irq); | 2402 | pr_cont(", irq=%d", irq); |
| 2403 | printk("\n"); | 2403 | pr_cont("\n"); |
| 2404 | return 1; | 2404 | return 1; |
| 2405 | } | 2405 | } |
| 2406 | 2406 | ||
| @@ -2581,10 +2581,10 @@ static int sio_via_probe(struct pci_dev *pdev, int autoirq, int autodma, · 174 unmodified lines | |||
| 2581 | printk(KERN_INFO | 2581 | printk(KERN_INFO |
| 2582 | "parport_pc: VIA parallel port: io=0x%X", port1); | 2582 | "parport_pc: VIA parallel port: io=0x%X", port1); |
| 2583 | if (irq != PARPORT_IRQ_NONE) | 2583 | if (irq != PARPORT_IRQ_NONE) |
| 2584 | printk(", irq=%d", irq); | 2584 | pr_cont(", irq=%d", irq); |
| 2585 | if (dma != PARPORT_DMA_NONE) | 2585 | if (dma != PARPORT_DMA_NONE) |
| 2586 | printk(", dma=%d", dma); | 2586 | pr_cont(", dma=%d", dma); |
| 2587 | printk("\n"); | 2587 | pr_cont("\n"); |
| 2588 | return 1; | 2588 | return 1; |
| 2589 | } | 2589 | } |
| 2590 | 2590 | ||
| @@ -253,16 +253,16 @@ static void extcon_work(struct work_struct *work) · 252 unmodified lines | |||
| 253 | vbus = gpiod_get_value_cansleep(driver->vbus_gpiod); | 253 | vbus = gpiod_get_value_cansleep(driver->vbus_gpiod); |
| 254 | 254 | ||
| 255 | if (!id && vbus) { /* Host connected */ | 255 | if (!id && vbus) { /* Host connected */ |
| 256 | extcon_set_cable_state_(driver->edev, EXTCON_USB_HOST, true); | 256 | extcon_set_state_sync(driver->edev, EXTCON_USB_HOST, true); |
| 257 | pr_debug("Host cable connected\n"); | 257 | pr_debug("Host cable connected\n"); |
| 258 | driver->data->new_state = EVT_HOST; | 258 | driver->data->new_state = EVT_HOST; |
| 259 | connect_change(driver); | 259 | connect_change(driver); |
| 260 | } else if (id && !vbus) { /* Disconnected */ | 260 | } else if (id && !vbus) { /* Disconnected */ |
| 261 | extcon_set_cable_state_(driver->edev, EXTCON_USB_HOST, false); | 261 | extcon_set_state_sync(driver->edev, EXTCON_USB_HOST, false); |
| 262 | extcon_set_cable_state_(driver->edev, EXTCON_USB, false); | 262 | extcon_set_state_sync(driver->edev, EXTCON_USB, false); |
| 263 | pr_debug("Cable disconnected\n"); | 263 | pr_debug("Cable disconnected\n"); |
| 264 | } else if (id && vbus) { /* Device connected */ | 264 | } else if (id && vbus) { /* Device connected */ |
| 265 | extcon_set_cable_state_(driver->edev, EXTCON_USB, true); | 265 | extcon_set_state_sync(driver->edev, EXTCON_USB, true); |
| 266 | pr_debug("Device cable connected\n"); | 266 | pr_debug("Device cable connected\n"); |
| 267 | driver->data->new_state = EVT_DEVICE; | 267 | driver->data->new_state = EVT_DEVICE; |
| 268 | connect_change(driver); | 268 | connect_change(driver); |
| @@ -155,12 +155,12 @@ static int qcom_usb_hs_phy_power_on(struct phy *phy) · 154 unmodified lines | |||
| 155 | } | 155 | } |
| 156 | 156 | ||
| 157 | if (uphy->vbus_edev) { | 157 | if (uphy->vbus_edev) { |
| 158 | state = extcon_get_cable_state_(uphy->vbus_edev, EXTCON_USB); | 158 | state = extcon_get_state(uphy->vbus_edev, EXTCON_USB); |
| 159 | /* setup initial state */ | 159 | /* setup initial state */ |
| 160 | qcom_usb_hs_phy_vbus_notifier(&uphy->vbus_notify, state, | 160 | qcom_usb_hs_phy_vbus_notifier(&uphy->vbus_notify, state, |
| 161 | uphy->vbus_edev); | 161 | uphy->vbus_edev); |
| 162 | ret = extcon_register_notifier(uphy->vbus_edev, EXTCON_USB, | 162 | ret = devm_extcon_register_notifier(&ulpi->dev, uphy->vbus_edev, |
| 163 | &uphy->vbus_notify); | 163 | EXTCON_USB, &uphy->vbus_notify); |
| 164 | if (ret) | 164 | if (ret) |
| 165 | goto err_ulpi; | 165 | goto err_ulpi; |
| 166 | } | 166 | } |
| @@ -179,16 +179,8 @@ err_sleep: · 12 unmodified lines | |||
| 179 | 179 | ||
| 180 | static int qcom_usb_hs_phy_power_off(struct phy *phy) | 180 | static int qcom_usb_hs_phy_power_off(struct phy *phy) |
| 181 | { | 181 | { |
| 182 | int ret; | ||
| 183 | struct qcom_usb_hs_phy *uphy = phy_get_drvdata(phy); | 182 | struct qcom_usb_hs_phy *uphy = phy_get_drvdata(phy); |
| 184 | 183 | ||
| 185 | if (uphy->vbus_edev) { | ||
| 186 | ret = extcon_unregister_notifier(uphy->vbus_edev, EXTCON_USB, | ||
| 187 | &uphy->vbus_notify); | ||
| 188 | if (ret) | ||
| 189 | return ret; | ||
| 190 | } | ||
| 191 | |||
| 192 | regulator_disable(uphy->v3p3); | 184 | regulator_disable(uphy->v3p3); |
| 193 | regulator_disable(uphy->v1p8); | 185 | regulator_disable(uphy->v1p8); |
| 194 | clk_disable_unprepare(uphy->sleep_clk); | 186 | clk_disable_unprepare(uphy->sleep_clk); |
| @@ -562,7 +562,7 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work) · 561 unmodified lines | |||
| 562 | rockchip_usb2phy_power_off(rport->phy); | 562 | rockchip_usb2phy_power_off(rport->phy); |
| 563 | /* fall through */ | 563 | /* fall through */ |
| 564 | case OTG_STATE_B_IDLE: | 564 | case OTG_STATE_B_IDLE: |
| 565 | if (extcon_get_cable_state_(rphy->edev, EXTCON_USB_HOST) > 0) { | 565 | if (extcon_get_state(rphy->edev, EXTCON_USB_HOST) > 0) { |
| 566 | dev_dbg(&rport->phy->dev, "usb otg host connect\n"); | 566 | dev_dbg(&rport->phy->dev, "usb otg host connect\n"); |
| 567 | rport->state = OTG_STATE_A_HOST; | 567 | rport->state = OTG_STATE_A_HOST; |
| 568 | rockchip_usb2phy_power_on(rport->phy); | 568 | rockchip_usb2phy_power_on(rport->phy); |
| @@ -615,7 +615,7 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work) · 46 unmodified lines | |||
| 615 | rport->vbus_attached = vbus_attach; | 615 | rport->vbus_attached = vbus_attach; |
| 616 | 616 | ||
| 617 | if (notify_charger && rphy->edev) { | 617 | if (notify_charger && rphy->edev) { |
| 618 | extcon_set_cable_state_(rphy->edev, | 618 | extcon_set_state_sync(rphy->edev, |
| 619 | cable, vbus_attach); | 619 | cable, vbus_attach); |
| 620 | if (cable == EXTCON_CHG_USB_SDP) | 620 | if (cable == EXTCON_CHG_USB_SDP) |
| 621 | extcon_set_state_sync(rphy->edev, | 621 | extcon_set_state_sync(rphy->edev, |
| @@ -636,7 +636,7 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work) · 14 unmodified lines | |||
| 636 | sch_work = true; | 636 | sch_work = true; |
| 637 | break; | 637 | break; |
| 638 | case OTG_STATE_A_HOST: | 638 | case OTG_STATE_A_HOST: |
| 639 | if (extcon_get_cable_state_(rphy->edev, EXTCON_USB_HOST) == 0) { | 639 | if (extcon_get_state(rphy->edev, EXTCON_USB_HOST) == 0) { |
| 640 | dev_dbg(&rport->phy->dev, "usb otg host disconnect\n"); | 640 | dev_dbg(&rport->phy->dev, "usb otg host disconnect\n"); |
| 641 | rport->state = OTG_STATE_B_IDLE; | 641 | rport->state = OTG_STATE_B_IDLE; |
| 642 | rockchip_usb2phy_power_off(rport->phy); | 642 | rockchip_usb2phy_power_off(rport->phy); |
| @@ -1066,8 +1066,8 @@ static int rockchip_usb2phy_otg_port_init(struct rockchip_usb2phy *rphy, · 423 unmodified lines | |||
| 1066 | if (!IS_ERR(rphy->edev)) { | 1066 | if (!IS_ERR(rphy->edev)) { |
| 1067 | rport->event_nb.notifier_call = rockchip_otg_event; | 1067 | rport->event_nb.notifier_call = rockchip_otg_event; |
| 1068 | 1068 | ||
| 1069 | ret = extcon_register_notifier(rphy->edev, EXTCON_USB_HOST, | 1069 | ret = devm_extcon_register_notifier(rphy->dev, rphy->edev, |
| 1070 | &rport->event_nb); | 1070 | EXTCON_USB_HOST, &rport->event_nb); |
| 1071 | if (ret) | 1071 | if (ret) |
| 1072 | dev_err(rphy->dev, "register USB HOST notifier failed\n"); | 1072 | dev_err(rphy->dev, "register USB HOST notifier failed\n"); |
| 1073 | } | 1073 | } |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. | 2 | * Copyright (c) 2012-2015, 2017, The Linux Foundation. All rights reserved. |
| 3 | * | 3 | * |
| 4 | * This program is free software; you can redistribute it and/or modify | 4 | * This program is free software; you can redistribute it and/or modify |
| 5 | * it under the terms of the GNU General Public License version 2 and | 5 | * it under the terms of the GNU General Public License version 2 and |
| @@ -29,6 +29,7 @@ · 23 unmodified lines | |||
| 29 | #define PMIC_ARB_VERSION 0x0000 | 29 | #define PMIC_ARB_VERSION 0x0000 |
| 30 | #define PMIC_ARB_VERSION_V2_MIN 0x20010000 | 30 | #define PMIC_ARB_VERSION_V2_MIN 0x20010000 |
| 31 | #define PMIC_ARB_VERSION_V3_MIN 0x30000000 | 31 | #define PMIC_ARB_VERSION_V3_MIN 0x30000000 |
| 32 | #define PMIC_ARB_VERSION_V5_MIN 0x50000000 | ||
| 32 | #define PMIC_ARB_INT_EN 0x0004 | 33 | #define PMIC_ARB_INT_EN 0x0004 |
| 33 | 34 | ||
| 34 | /* PMIC Arbiter channel registers offsets */ | 35 | /* PMIC Arbiter channel registers offsets */ |
| @@ -39,7 +40,6 @@ · 4 unmodified lines | |||
| 39 | #define PMIC_ARB_WDATA1 0x14 | 40 | #define PMIC_ARB_WDATA1 0x14 |
| 40 | #define PMIC_ARB_RDATA0 0x18 | 41 | #define PMIC_ARB_RDATA0 0x18 |
| 41 | #define PMIC_ARB_RDATA1 0x1C | 42 | #define PMIC_ARB_RDATA1 0x1C |
| 42 | #define PMIC_ARB_REG_CHNL(N) (0x800 + 0x4 * (N)) | ||
| 43 | 43 | ||
| 44 | /* Mapping Table */ | 44 | /* Mapping Table */ |
| 45 | #define SPMI_MAPPING_TABLE_REG(N) (0x0B00 + (4 * (N))) | 45 | #define SPMI_MAPPING_TABLE_REG(N) (0x0B00 + (4 * (N))) |
| @@ -51,7 +51,9 @@ · 5 unmodified lines | |||
| 51 | 51 | ||
| 52 | #define SPMI_MAPPING_TABLE_TREE_DEPTH 16 /* Maximum of 16-bits */ | 52 | #define SPMI_MAPPING_TABLE_TREE_DEPTH 16 /* Maximum of 16-bits */ |
| 53 | #define PMIC_ARB_MAX_PPID BIT(12) /* PPID is 12bit */ | 53 | #define PMIC_ARB_MAX_PPID BIT(12) /* PPID is 12bit */ |
| 54 | #define PMIC_ARB_CHAN_VALID BIT(15) | 54 | #define PMIC_ARB_APID_VALID BIT(15) |
| 55 | #define PMIC_ARB_CHAN_IS_IRQ_OWNER(reg) ((reg) & BIT(24)) | ||
| 56 | #define INVALID_EE 0xFF | ||
| 55 | 57 | ||
| 56 | /* Ownership Table */ | 58 | /* Ownership Table */ |
| 57 | #define SPMI_OWNERSHIP_TABLE_REG(N) (0x0700 + (4 * (N))) | 59 | #define SPMI_OWNERSHIP_TABLE_REG(N) (0x0700 + (4 * (N))) |
| @@ -86,6 +88,15 @@ enum pmic_arb_cmd_op_code { · 28 unmodified lines | |||
| 86 | PMIC_ARB_OP_ZERO_WRITE = 16, | 88 | PMIC_ARB_OP_ZERO_WRITE = 16, |
| 87 | }; | 89 | }; |
| 88 | 90 | ||
| 91 | /* | ||
| 92 | * PMIC arbiter version 5 uses different register offsets for read/write vs | ||
| 93 | * observer channels. | ||
| 94 | */ | ||
| 95 | enum pmic_arb_channel { | ||
| 96 | PMIC_ARB_CHANNEL_RW, | ||
| 97 | PMIC_ARB_CHANNEL_OBS, | ||
| 98 | }; | ||
| 99 | |||
| 89 | /* Maximum number of support PMIC peripherals */ | 100 | /* Maximum number of support PMIC peripherals */ |
| 90 | #define PMIC_ARB_MAX_PERIPHS 512 | 101 | #define PMIC_ARB_MAX_PERIPHS 512 |
| 91 | #define PMIC_ARB_TIMEOUT_US 100 | 102 | #define PMIC_ARB_TIMEOUT_US 100 |
| @@ -97,22 +108,23 @@ enum pmic_arb_cmd_op_code { · 5 unmodified lines | |||
| 97 | /* interrupt enable bit */ | 108 | /* interrupt enable bit */ |
| 98 | #define SPMI_PIC_ACC_ENABLE_BIT BIT(0) | 109 | #define SPMI_PIC_ACC_ENABLE_BIT BIT(0) |
| 99 | 110 | ||
| 100 | #define HWIRQ(slave_id, periph_id, irq_id, apid) \ | 111 | #define spec_to_hwirq(slave_id, periph_id, irq_id, apid) \ |
| 101 | ((((slave_id) & 0xF) << 28) | \ | 112 | ((((slave_id) & 0xF) << 28) | \ |
| 102 | (((periph_id) & 0xFF) << 20) | \ | 113 | (((periph_id) & 0xFF) << 20) | \ |
| 103 | (((irq_id) & 0x7) << 16) | \ | 114 | (((irq_id) & 0x7) << 16) | \ |
| 104 | (((apid) & 0x1FF) << 0)) | 115 | (((apid) & 0x1FF) << 0)) |
| 105 | 116 | ||
| 106 | #define HWIRQ_SID(hwirq) (((hwirq) >> 28) & 0xF) | 117 | #define hwirq_to_sid(hwirq) (((hwirq) >> 28) & 0xF) |
| 107 | #define HWIRQ_PER(hwirq) (((hwirq) >> 20) & 0xFF) | 118 | #define hwirq_to_per(hwirq) (((hwirq) >> 20) & 0xFF) |
| 108 | #define HWIRQ_IRQ(hwirq) (((hwirq) >> 16) & 0x7) | 119 | #define hwirq_to_irq(hwirq) (((hwirq) >> 16) & 0x7) |
| 109 | #define HWIRQ_APID(hwirq) (((hwirq) >> 0) & 0x1FF) | 120 | #define hwirq_to_apid(hwirq) (((hwirq) >> 0) & 0x1FF) |
| 110 | 121 | ||
| 111 | struct pmic_arb_ver_ops; | 122 | struct pmic_arb_ver_ops; |
| 112 | 123 | ||
| 113 | struct apid_data { | 124 | struct apid_data { |
| 114 | u16 ppid; | 125 | u16 ppid; |
| 115 | u8 owner; | 126 | u8 write_ee; |
| 127 | u8 irq_ee; | ||
| 116 | }; | 128 | }; |
| 117 | 129 | ||
| 118 | /** | 130 | /** |
| @@ -128,12 +140,11 @@ struct apid_data { · 9 unmodified lines | |||
| 128 | * @ee: the current Execution Environment | 140 | * @ee: the current Execution Environment |
| 129 | * @min_apid: minimum APID (used for bounding IRQ search) | 141 | * @min_apid: minimum APID (used for bounding IRQ search) |
| 130 | * @max_apid: maximum APID | 142 | * @max_apid: maximum APID |
| 131 | * @max_periph: maximum number of PMIC peripherals supported by HW. | ||
| 132 | * @mapping_table: in-memory copy of PPID -> APID mapping table. | 143 | * @mapping_table: in-memory copy of PPID -> APID mapping table. |
| 133 | * @domain: irq domain object for PMIC IRQ domain | 144 | * @domain: irq domain object for PMIC IRQ domain |
| 134 | * @spmic: SPMI controller object | 145 | * @spmic: SPMI controller object |
| 135 | * @ver_ops: version dependent operations. | 146 | * @ver_ops: version dependent operations. |
| 136 | * @ppid_to_apid in-memory copy of PPID -> channel (APID) mapping table. | 147 | * @ppid_to_apid in-memory copy of PPID -> APID mapping table. |
| 137 | */ | 148 | */ |
| 138 | struct spmi_pmic_arb { | 149 | struct spmi_pmic_arb { |
| 139 | void __iomem *rd_base; | 150 | void __iomem *rd_base; |
| @@ -148,7 +159,6 @@ struct spmi_pmic_arb { · 8 unmodified lines | |||
| 148 | u8 ee; | 159 | u8 ee; |
| 149 | u16 min_apid; | 160 | u16 min_apid; |
| 150 | u16 max_apid; | 161 | u16 max_apid; |
| 151 | u16 max_periph; | ||
| 152 | u32 *mapping_table; | 162 | u32 *mapping_table; |
| 153 | DECLARE_BITMAP(mapping_table_valid, PMIC_ARB_MAX_PERIPHS); | 163 | DECLARE_BITMAP(mapping_table_valid, PMIC_ARB_MAX_PERIPHS); |
| 154 | struct irq_domain *domain; | 164 | struct irq_domain *domain; |
| @@ -164,92 +174,94 @@ struct spmi_pmic_arb { · 9 unmodified lines | |||
| 164 | * | 174 | * |
| 165 | * @ver_str: version string. | 175 | * @ver_str: version string. |
| 166 | * @ppid_to_apid: finds the apid for a given ppid. | 176 | * @ppid_to_apid: finds the apid for a given ppid. |
| 167 | * @mode: access rights to specified pmic peripheral. | ||
| 168 | * @non_data_cmd: on v1 issues an spmi non-data command. | 177 | * @non_data_cmd: on v1 issues an spmi non-data command. |
| 169 | * on v2 no HW support, returns -EOPNOTSUPP. | 178 | * on v2 no HW support, returns -EOPNOTSUPP. |
| 170 | * @offset: on v1 offset of per-ee channel. | 179 | * @offset: on v1 offset of per-ee channel. |
| 171 | * on v2 offset of per-ee and per-ppid channel. | 180 | * on v2 offset of per-ee and per-ppid channel. |
| 172 | * @fmt_cmd: formats a GENI/SPMI command. | 181 | * @fmt_cmd: formats a GENI/SPMI command. |
| 173 | * @owner_acc_status: on v1 offset of PMIC_ARB_SPMI_PIC_OWNERm_ACC_STATUSn | 182 | * @owner_acc_status: on v1 address of PMIC_ARB_SPMI_PIC_OWNERm_ACC_STATUSn |
| 174 | * on v2 offset of SPMI_PIC_OWNERm_ACC_STATUSn. | 183 | * on v2 address of SPMI_PIC_OWNERm_ACC_STATUSn. |
| 175 | * @acc_enable: on v1 offset of PMIC_ARB_SPMI_PIC_ACC_ENABLEn | 184 | * @acc_enable: on v1 address of PMIC_ARB_SPMI_PIC_ACC_ENABLEn |
| 176 | * on v2 offset of SPMI_PIC_ACC_ENABLEn. | 185 | * on v2 address of SPMI_PIC_ACC_ENABLEn. |
| 177 | * @irq_status: on v1 offset of PMIC_ARB_SPMI_PIC_IRQ_STATUSn | 186 | * @irq_status: on v1 address of PMIC_ARB_SPMI_PIC_IRQ_STATUSn |
| 178 | * on v2 offset of SPMI_PIC_IRQ_STATUSn. | 187 | * on v2 address of SPMI_PIC_IRQ_STATUSn. |
| 179 | * @irq_clear: on v1 offset of PMIC_ARB_SPMI_PIC_IRQ_CLEARn | 188 | * @irq_clear: on v1 address of PMIC_ARB_SPMI_PIC_IRQ_CLEARn |
| 180 | * on v2 offset of SPMI_PIC_IRQ_CLEARn. | 189 | * on v2 address of SPMI_PIC_IRQ_CLEARn. |
| 190 | * @apid_map_offset: offset of PMIC_ARB_REG_CHNLn | ||
| 181 | */ | 191 | */ |
| 182 | struct pmic_arb_ver_ops { | 192 | struct pmic_arb_ver_ops { |
| 183 | const char *ver_str; | 193 | const char *ver_str; |
| 184 | int (*ppid_to_apid)(struct spmi_pmic_arb *pa, u8 sid, u16 addr, | 194 | int (*ppid_to_apid)(struct spmi_pmic_arb *pmic_arb, u16 ppid); |
| 185 | u16 *apid); | ||
| 186 | int (*mode)(struct spmi_pmic_arb *dev, u8 sid, u16 addr, | ||
| 187 | mode_t *mode); | ||
| 188 | /* spmi commands (read_cmd, write_cmd, cmd) functionality */ | 195 | /* spmi commands (read_cmd, write_cmd, cmd) functionality */ |
| 189 | int (*offset)(struct spmi_pmic_arb *dev, u8 sid, u16 addr, | 196 | int (*offset)(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr, |
| 190 | u32 *offset); | 197 | enum pmic_arb_channel ch_type); |
| 191 | u32 (*fmt_cmd)(u8 opc, u8 sid, u16 addr, u8 bc); | 198 | u32 (*fmt_cmd)(u8 opc, u8 sid, u16 addr, u8 bc); |
| 192 | int (*non_data_cmd)(struct spmi_controller *ctrl, u8 opc, u8 sid); | 199 | int (*non_data_cmd)(struct spmi_controller *ctrl, u8 opc, u8 sid); |
| 193 | /* Interrupts controller functionality (offset of PIC registers) */ | 200 | /* Interrupts controller functionality (offset of PIC registers) */ |
| 194 | u32 (*owner_acc_status)(u8 m, u16 n); | 201 | void __iomem *(*owner_acc_status)(struct spmi_pmic_arb *pmic_arb, u8 m, |
| 195 | u32 (*acc_enable)(u16 n); | 202 | u16 n); |
| 196 | u32 (*irq_status)(u16 n); | 203 | void __iomem *(*acc_enable)(struct spmi_pmic_arb *pmic_arb, u16 n); |
| 197 | u32 (*irq_clear)(u16 n); | 204 | void __iomem *(*irq_status)(struct spmi_pmic_arb *pmic_arb, u16 n); |
| 205 | void __iomem *(*irq_clear)(struct spmi_pmic_arb *pmic_arb, u16 n); | ||
| 206 | u32 (*apid_map_offset)(u16 n); | ||
| 198 | }; | 207 | }; |
| 199 | 208 | ||
| 200 | static inline void pmic_arb_base_write(struct spmi_pmic_arb *pa, | 209 | static inline void pmic_arb_base_write(struct spmi_pmic_arb *pmic_arb, |
| 201 | u32 offset, u32 val) | 210 | u32 offset, u32 val) |
| 202 | { | 211 | { |
| 203 | writel_relaxed(val, pa->wr_base + offset); | 212 | writel_relaxed(val, pmic_arb->wr_base + offset); |
| 204 | } | 213 | } |
| 205 | 214 | ||
| 206 | static inline void pmic_arb_set_rd_cmd(struct spmi_pmic_arb *pa, | 215 | static inline void pmic_arb_set_rd_cmd(struct spmi_pmic_arb *pmic_arb, |
| 207 | u32 offset, u32 val) | 216 | u32 offset, u32 val) |
| 208 | { | 217 | { |
| 209 | writel_relaxed(val, pa->rd_base + offset); | 218 | writel_relaxed(val, pmic_arb->rd_base + offset); |
| 210 | } | 219 | } |
| 211 | 220 | ||
| 212 | /** | 221 | /** |
| 213 | * pa_read_data: reads pmic-arb's register and copy 1..4 bytes to buf | 222 | * pmic_arb_read_data: reads pmic-arb's register and copy 1..4 bytes to buf |
| 214 | * @bc: byte count -1. range: 0..3 | 223 | * @bc: byte count -1. range: 0..3 |
| 215 | * @reg: register's address | 224 | * @reg: register's address |
| 216 | * @buf: output parameter, length must be bc + 1 | 225 | * @buf: output parameter, length must be bc + 1 |
| 217 | */ | 226 | */ |
| 218 | static void pa_read_data(struct spmi_pmic_arb *pa, u8 *buf, u32 reg, u8 bc) | 227 | static void |
| 228 | pmic_arb_read_data(struct spmi_pmic_arb *pmic_arb, u8 *buf, u32 reg, u8 bc) | ||
| 219 | { | 229 | { |
| 220 | u32 data = __raw_readl(pa->rd_base + reg); | 230 | u32 data = __raw_readl(pmic_arb->rd_base + reg); |
| 221 | 231 | ||
| 222 | memcpy(buf, &data, (bc & 3) + 1); | 232 | memcpy(buf, &data, (bc & 3) + 1); |
| 223 | } | 233 | } |
| 224 | 234 | ||
| 225 | /** | 235 | /** |
| 226 | * pa_write_data: write 1..4 bytes from buf to pmic-arb's register | 236 | * pmic_arb_write_data: write 1..4 bytes from buf to pmic-arb's register |
| 227 | * @bc: byte-count -1. range: 0..3. | 237 | * @bc: byte-count -1. range: 0..3. |
| 228 | * @reg: register's address. | 238 | * @reg: register's address. |
| 229 | * @buf: buffer to write. length must be bc + 1. | 239 | * @buf: buffer to write. length must be bc + 1. |
| 230 | */ | 240 | */ |
| 231 | static void | 241 | static void pmic_arb_write_data(struct spmi_pmic_arb *pmic_arb, const u8 *buf, |
| 232 | pa_write_data(struct spmi_pmic_arb *pa, const u8 *buf, u32 reg, u8 bc) | 242 | u32 reg, u8 bc) |
| 233 | { | 243 | { |
| 234 | u32 data = 0; | 244 | u32 data = 0; |
| 235 | 245 | ||
| 236 | memcpy(&data, buf, (bc & 3) + 1); | 246 | memcpy(&data, buf, (bc & 3) + 1); |
| 237 | pmic_arb_base_write(pa, reg, data); | 247 | __raw_writel(data, pmic_arb->wr_base + reg); |
| 238 | } | 248 | } |
| 239 | 249 | ||
| 240 | static int pmic_arb_wait_for_done(struct spmi_controller *ctrl, | 250 | static int pmic_arb_wait_for_done(struct spmi_controller *ctrl, |
| 241 | void __iomem *base, u8 sid, u16 addr) | 251 | void __iomem *base, u8 sid, u16 addr, |
| 252 | enum pmic_arb_channel ch_type) | ||
| 242 | { | 253 | { |
| 243 | struct spmi_pmic_arb *pa = spmi_controller_get_drvdata(ctrl); | 254 | struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl); |
| 244 | u32 status = 0; | 255 | u32 status = 0; |
| 245 | u32 timeout = PMIC_ARB_TIMEOUT_US; | 256 | u32 timeout = PMIC_ARB_TIMEOUT_US; |
| 246 | u32 offset; | 257 | u32 offset; |
| 247 | int rc; | 258 | int rc; |
| 248 | 259 | ||
| 249 | rc = pa->ver_ops->offset(pa, sid, addr, &offset); | 260 | rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr, ch_type); |
| 250 | if (rc) | 261 | if (rc < 0) |
| 251 | return rc; | 262 | return rc; |
| 252 | 263 | ||
| 264 | offset = rc; | ||
| 253 | offset += PMIC_ARB_STATUS; | 265 | offset += PMIC_ARB_STATUS; |
| 254 | 266 | ||
| 255 | while (timeout--) { | 267 | while (timeout--) { |
| @@ -257,22 +269,19 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl, · 1 unmodified line | |||
| 257 | 269 | ||
| 258 | if (status & PMIC_ARB_STATUS_DONE) { | 270 | if (status & PMIC_ARB_STATUS_DONE) { |
| 259 | if (status & PMIC_ARB_STATUS_DENIED) { | 271 | if (status & PMIC_ARB_STATUS_DENIED) { |
| 260 | dev_err(&ctrl->dev, | 272 | dev_err(&ctrl->dev, "%s: transaction denied (0x%x)\n", |
| 261 | "%s: transaction denied (0x%x)\n", | ||
| 262 | __func__, status); | 273 | __func__, status); |
| 263 | return -EPERM; | 274 | return -EPERM; |
| 264 | } | 275 | } |
| 265 | 276 | ||
| 266 | if (status & PMIC_ARB_STATUS_FAILURE) { | 277 | if (status & PMIC_ARB_STATUS_FAILURE) { |
| 267 | dev_err(&ctrl->dev, | 278 | dev_err(&ctrl->dev, "%s: transaction failed (0x%x)\n", |
| 268 | "%s: transaction failed (0x%x)\n", | ||
| 269 | __func__, status); | 279 | __func__, status); |
| 270 | return -EIO; | 280 | return -EIO; |
| 271 | } | 281 | } |
| 272 | 282 | ||
| 273 | if (status & PMIC_ARB_STATUS_DROPPED) { | 283 | if (status & PMIC_ARB_STATUS_DROPPED) { |
| 274 | dev_err(&ctrl->dev, | 284 | dev_err(&ctrl->dev, "%s: transaction dropped (0x%x)\n", |
| 275 | "%s: transaction dropped (0x%x)\n", | ||
| 276 | __func__, status); | 285 | __func__, status); |
| 277 | return -EIO; | 286 | return -EIO; |
| 278 | } | 287 | } |
| @@ -282,8 +291,7 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl, · 3 unmodified lines | |||
| 282 | udelay(1); | 291 | udelay(1); |
| 283 | } | 292 | } |
| 284 | 293 | ||
| 285 | dev_err(&ctrl->dev, | 294 | dev_err(&ctrl->dev, "%s: timeout, status 0x%x\n", |
| 286 | "%s: timeout, status 0x%x\n", | ||
| 287 | __func__, status); | 295 | __func__, status); |
| 288 | return -ETIMEDOUT; | 296 | return -ETIMEDOUT; |
| 289 | } | 297 | } |
| @@ -291,22 +299,24 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl, · 1 unmodified line | |||
| 291 | static int | 299 | static int |
| 292 | pmic_arb_non_data_cmd_v1(struct spmi_controller *ctrl, u8 opc, u8 sid) | 300 | pmic_arb_non_data_cmd_v1(struct spmi_controller *ctrl, u8 opc, u8 sid) |
| 293 | { | 301 | { |
| 294 | struct spmi_pmic_arb *pa = spmi_controller_get_drvdata(ctrl); | 302 | struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl); |
| 295 | unsigned long flags; | 303 | unsigned long flags; |
| 296 | u32 cmd; | 304 | u32 cmd; |
| 297 | int rc; | 305 | int rc; |
| 298 | u32 offset; | 306 | u32 offset; |
| 299 | 307 | ||
| 300 | rc = pa->ver_ops->offset(pa, sid, 0, &offset); | 308 | rc = pmic_arb->ver_ops->offset(pmic_arb, sid, 0, PMIC_ARB_CHANNEL_RW); |
| 301 | if (rc) | 309 | if (rc < 0) |
| 302 | return rc; | 310 | return rc; |
| 303 | 311 | ||
| 312 | offset = rc; | ||
| 304 | cmd = ((opc | 0x40) << 27) | ((sid & 0xf) << 20); | 313 | cmd = ((opc | 0x40) << 27) | ((sid & 0xf) << 20); |
| 305 | 314 | ||
| 306 | raw_spin_lock_irqsave(&pa->lock, flags); | 315 | raw_spin_lock_irqsave(&pmic_arb->lock, flags); |
| 307 | pmic_arb_base_write(pa, offset + PMIC_ARB_CMD, cmd); | 316 | pmic_arb_base_write(pmic_arb, offset + PMIC_ARB_CMD, cmd); |
| 308 | rc = pmic_arb_wait_for_done(ctrl, pa->wr_base, sid, 0); | 317 | rc = pmic_arb_wait_for_done(ctrl, pmic_arb->wr_base, sid, 0, |
| 309 | raw_spin_unlock_irqrestore(&pa->lock, flags); | 318 | PMIC_ARB_CHANNEL_RW); |
| 319 | raw_spin_unlock_irqrestore(&pmic_arb->lock, flags); | ||
| 310 | 320 | ||
| 311 | return rc; | 321 | return rc; |
| 312 | } | 322 | } |
| @@ -320,7 +330,7 @@ pmic_arb_non_data_cmd_v2(struct spmi_controller *ctrl, u8 opc, u8 sid) · 7 unmodified lines | |||
| 320 | /* Non-data command */ | 330 | /* Non-data command */ |
| 321 | static int pmic_arb_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid) | 331 | static int pmic_arb_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid) |
| 322 | { | 332 | { |
| 323 | struct spmi_pmic_arb *pa = spmi_controller_get_drvdata(ctrl); | 333 | struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl); |
| 324 | 334 | ||
| 325 | dev_dbg(&ctrl->dev, "cmd op:0x%x sid:%d\n", opc, sid); | 335 | dev_dbg(&ctrl->dev, "cmd op:0x%x sid:%d\n", opc, sid); |
| 326 | 336 | ||
| @@ -328,38 +338,27 @@ static int pmic_arb_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid) · 1 unmodified line | |||
| 328 | if (opc < SPMI_CMD_RESET || opc > SPMI_CMD_WAKEUP) | 338 | if (opc < SPMI_CMD_RESET || opc > SPMI_CMD_WAKEUP) |
| 329 | return -EINVAL; | 339 | return -EINVAL; |
| 330 | 340 | ||
| 331 | return pa->ver_ops->non_data_cmd(ctrl, opc, sid); | 341 | return pmic_arb->ver_ops->non_data_cmd(ctrl, opc, sid); |
| 332 | } | 342 | } |
| 333 | 343 | ||
| 334 | static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, | 344 | static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, |
| 335 | u16 addr, u8 *buf, size_t len) | 345 | u16 addr, u8 *buf, size_t len) |
| 336 | { | 346 | { |
| 337 | struct spmi_pmic_arb *pa = spmi_controller_get_drvdata(ctrl); | 347 | struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl); |
| 338 | unsigned long flags; | 348 | unsigned long flags; |
| 339 | u8 bc = len - 1; | 349 | u8 bc = len - 1; |
| 340 | u32 cmd; | 350 | u32 cmd; |
| 341 | int rc; | 351 | int rc; |
| 342 | u32 offset; | 352 | u32 offset; |
| 343 | mode_t mode; | ||
| 344 | |||
| 345 | rc = pa->ver_ops->offset(pa, sid, addr, &offset); | ||
| 346 | if (rc) | ||
| 347 | return rc; | ||
| 348 | 353 | ||
| 349 | rc = pa->ver_ops->mode(pa, sid, addr, &mode); | 354 | rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr, |
| 350 | if (rc) | 355 | PMIC_ARB_CHANNEL_OBS); |
| 356 | if (rc < 0) | ||
| 351 | return rc; | 357 | return rc; |
| 352 | 358 | ||
| 353 | if (!(mode & S_IRUSR)) { | 359 | offset = rc; |
| 354 | dev_err(&pa->spmic->dev, | ||
| 355 | "error: impermissible read from peripheral sid:%d addr:0x%x\n", | ||
| 356 | sid, addr); | ||
| 357 | return -EPERM; | ||
| 358 | } | ||
| 359 | |||
| 360 | if (bc >= PMIC_ARB_MAX_TRANS_BYTES) { | 360 | if (bc >= PMIC_ARB_MAX_TRANS_BYTES) { |
| 361 | dev_err(&ctrl->dev, | 361 | dev_err(&ctrl->dev, "pmic-arb supports 1..%d bytes per trans, but:%zu requested", |
| 362 | "pmic-arb supports 1..%d bytes per trans, but:%zu requested", | ||
| 363 | PMIC_ARB_MAX_TRANS_BYTES, len); | 362 | PMIC_ARB_MAX_TRANS_BYTES, len); |
| 364 | return -EINVAL; | 363 | return -EINVAL; |
| 365 | } | 364 | } |
| @@ -374,54 +373,45 @@ static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, · 8 unmodified lines | |||
| 374 | else | 373 | else |
| 375 | return -EINVAL; | 374 | return -EINVAL; |
| 376 | 375 | ||
| 377 | cmd = pa->ver_ops->fmt_cmd(opc, sid, addr, bc); | 376 | cmd = pmic_arb->ver_ops->fmt_cmd(opc, sid, addr, bc); |
| 378 | 377 | ||
| 379 | raw_spin_lock_irqsave(&pa->lock, flags); | 378 | raw_spin_lock_irqsave(&pmic_arb->lock, flags); |
| 380 | pmic_arb_set_rd_cmd(pa, offset + PMIC_ARB_CMD, cmd); | 379 | pmic_arb_set_rd_cmd(pmic_arb, offset + PMIC_ARB_CMD, cmd); |
| 381 | rc = pmic_arb_wait_for_done(ctrl, pa->rd_base, sid, addr); | 380 | rc = pmic_arb_wait_for_done(ctrl, pmic_arb->rd_base, sid, addr, |
| 381 | PMIC_ARB_CHANNEL_OBS); | ||
| 382 | if (rc) | 382 | if (rc) |
| 383 | goto done; | 383 | goto done; |
| 384 | 384 | ||
| 385 | pa_read_data(pa, buf, offset + PMIC_ARB_RDATA0, | 385 | pmic_arb_read_data(pmic_arb, buf, offset + PMIC_ARB_RDATA0, |
| 386 | min_t(u8, bc, 3)); | 386 | min_t(u8, bc, 3)); |
| 387 | 387 | ||
| 388 | if (bc > 3) | 388 | if (bc > 3) |
| 389 | pa_read_data(pa, buf + 4, offset + PMIC_ARB_RDATA1, bc - 4); | 389 | pmic_arb_read_data(pmic_arb, buf + 4, offset + PMIC_ARB_RDATA1, |
| 390 | bc - 4); | ||
| 390 | 391 | ||
| 391 | done: | 392 | done: |
| 392 | raw_spin_unlock_irqrestore(&pa->lock, flags); | 393 | raw_spin_unlock_irqrestore(&pmic_arb->lock, flags); |
| 393 | return rc; | 394 | return rc; |
| 394 | } | 395 | } |
| 395 | 396 | ||
| 396 | static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, | 397 | static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, |
| 397 | u16 addr, const u8 *buf, size_t len) | 398 | u16 addr, const u8 *buf, size_t len) |
| 398 | { | 399 | { |
| 399 | struct spmi_pmic_arb *pa = spmi_controller_get_drvdata(ctrl); | 400 | struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl); |
| 400 | unsigned long flags; | 401 | unsigned long flags; |
| 401 | u8 bc = len - 1; | 402 | u8 bc = len - 1; |
| 402 | u32 cmd; | 403 | u32 cmd; |
| 403 | int rc; | 404 | int rc; |
| 404 | u32 offset; | 405 | u32 offset; |
| 405 | mode_t mode; | ||
| 406 | |||
| 407 | rc = pa->ver_ops->offset(pa, sid, addr, &offset); | ||
| 408 | if (rc) | ||
| 409 | return rc; | ||
| 410 | 406 | ||
| 411 | rc = pa->ver_ops->mode(pa, sid, addr, &mode); | 407 | rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr, |
| 412 | if (rc) | 408 | PMIC_ARB_CHANNEL_RW); |
| 409 | if (rc < 0) | ||
| 413 | return rc; | 410 | return rc; |
| 414 | 411 | ||
| 415 | if (!(mode & S_IWUSR)) { | 412 | offset = rc; |
| 416 | dev_err(&pa->spmic->dev, | ||
| 417 | "error: impermissible write to peripheral sid:%d addr:0x%x\n", | ||
| 418 | sid, addr); | ||
| 419 | return -EPERM; | ||
| 420 | } | ||
| 421 | |||
| 422 | if (bc >= PMIC_ARB_MAX_TRANS_BYTES) { | 413 | if (bc >= PMIC_ARB_MAX_TRANS_BYTES) { |
| 423 | dev_err(&ctrl->dev, | 414 | dev_err(&ctrl->dev, "pmic-arb supports 1..%d bytes per trans, but:%zu requested", |
| 424 | "pmic-arb supports 1..%d bytes per trans, but:%zu requested", | ||
| 425 | PMIC_ARB_MAX_TRANS_BYTES, len); | 415 | PMIC_ARB_MAX_TRANS_BYTES, len); |
| 426 | return -EINVAL; | 416 | return -EINVAL; |
| 427 | } | 417 | } |
| @@ -429,7 +419,7 @@ static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, · 1 unmodified line | |||
| 429 | /* Check the opcode */ | 419 | /* Check the opcode */ |
| 430 | if (opc >= 0x40 && opc <= 0x5F) | 420 | if (opc >= 0x40 && opc <= 0x5F) |
| 431 | opc = PMIC_ARB_OP_WRITE; | 421 | opc = PMIC_ARB_OP_WRITE; |
| 432 | else if (opc >= 0x00 && opc <= 0x0F) | 422 | else if (opc <= 0x0F) |
| 433 | opc = PMIC_ARB_OP_EXT_WRITE; | 423 | opc = PMIC_ARB_OP_EXT_WRITE; |
| 434 | else if (opc >= 0x30 && opc <= 0x37) | 424 | else if (opc >= 0x30 && opc <= 0x37) |
| 435 | opc = PMIC_ARB_OP_EXT_WRITEL; | 425 | opc = PMIC_ARB_OP_EXT_WRITEL; |
| @@ -438,18 +428,21 @@ static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid, · 2 unmodified lines | |||
| 438 | else | 428 | else |
| 439 | return -EINVAL; | 429 | return -EINVAL; |
| 440 | 430 | ||
| 441 | cmd = pa->ver_ops->fmt_cmd(opc, sid, addr, bc); | 431 | cmd = pmic_arb->ver_ops->fmt_cmd(opc, sid, addr, bc); |
| 442 | 432 | ||
| 443 | /* Write data to FIFOs */ | 433 | /* Write data to FIFOs */ |
| 444 | raw_spin_lock_irqsave(&pa->lock, flags); | 434 | raw_spin_lock_irqsave(&pmic_arb->lock, flags); |
| 445 | pa_write_data(pa, buf, offset + PMIC_ARB_WDATA0, min_t(u8, bc, 3)); | 435 | pmic_arb_write_data(pmic_arb, buf, offset + PMIC_ARB_WDATA0, |
| 436 | min_t(u8, bc, 3)); | ||
| 446 | if (bc > 3) | 437 | if (bc > 3) |
| 447 | pa_write_data(pa, buf + 4, offset + PMIC_ARB_WDATA1, bc - 4); | 438 | pmic_arb_write_data(pmic_arb, buf + 4, offset + PMIC_ARB_WDATA1, |
| 439 | bc - 4); | ||
| 448 | 440 | ||
| 449 | /* Start the transaction */ | 441 | /* Start the transaction */ |
| 450 | pmic_arb_base_write(pa, offset + PMIC_ARB_CMD, cmd); | 442 | pmic_arb_base_write(pmic_arb, offset + PMIC_ARB_CMD, cmd); |
| 451 | rc = pmic_arb_wait_for_done(ctrl, pa->wr_base, sid, addr); | 443 | rc = pmic_arb_wait_for_done(ctrl, pmic_arb->wr_base, sid, addr, |
| 452 | raw_spin_unlock_irqrestore(&pa->lock, flags); | 444 | PMIC_ARB_CHANNEL_RW); |
| 445 | raw_spin_unlock_irqrestore(&pmic_arb->lock, flags); | ||
| 453 | 446 | ||
| 454 | return rc; | 447 | return rc; |
| 455 | } | 448 | } |
| @@ -475,67 +468,64 @@ struct spmi_pmic_arb_qpnpint_type { · 19 unmodified lines | |||
| 475 | static void qpnpint_spmi_write(struct irq_data *d, u8 reg, void *buf, | 468 | static void qpnpint_spmi_write(struct irq_data *d, u8 reg, void *buf, |
| 476 | size_t len) | 469 | size_t len) |
| 477 | { | 470 | { |
| 478 | struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d); | 471 | struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d); |
| 479 | u8 sid = HWIRQ_SID(d->hwirq); | 472 | u8 sid = hwirq_to_sid(d->hwirq); |
| 480 | u8 per = HWIRQ_PER(d->hwirq); | 473 | u8 per = hwirq_to_per(d->hwirq); |
| 481 | 474 | ||
| 482 | if (pmic_arb_write_cmd(pa->spmic, SPMI_CMD_EXT_WRITEL, sid, | 475 | if (pmic_arb_write_cmd(pmic_arb->spmic, SPMI_CMD_EXT_WRITEL, sid, |
| 483 | (per << 8) + reg, buf, len)) | 476 | (per << 8) + reg, buf, len)) |
| 484 | dev_err_ratelimited(&pa->spmic->dev, | 477 | dev_err_ratelimited(&pmic_arb->spmic->dev, "failed irqchip transaction on %x\n", |
| 485 | "failed irqchip transaction on %x\n", | ||
| 486 | d->irq); | 478 | d->irq); |
| 487 | } | 479 | } |
| 488 | 480 | ||
| 489 | static void qpnpint_spmi_read(struct irq_data *d, u8 reg, void *buf, size_t len) | 481 | static void qpnpint_spmi_read(struct irq_data *d, u8 reg, void *buf, size_t len) |
| 490 | { | 482 | { |
| 491 | struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d); | 483 | struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d); |
| 492 | u8 sid = HWIRQ_SID(d->hwirq); | 484 | u8 sid = hwirq_to_sid(d->hwirq); |
| 493 | u8 per = HWIRQ_PER(d->hwirq); | 485 | u8 per = hwirq_to_per(d->hwirq); |
| 494 | 486 | ||
| 495 | if (pmic_arb_read_cmd(pa->spmic, SPMI_CMD_EXT_READL, sid, | 487 | if (pmic_arb_read_cmd(pmic_arb->spmic, SPMI_CMD_EXT_READL, sid, |
| 496 | (per << 8) + reg, buf, len)) | 488 | (per << 8) + reg, buf, len)) |
| 497 | dev_err_ratelimited(&pa->spmic->dev, | 489 | dev_err_ratelimited(&pmic_arb->spmic->dev, "failed irqchip transaction on %x\n", |
| 498 | "failed irqchip transaction on %x\n", | ||
| 499 | d->irq); | 490 | d->irq); |
| 500 | } | 491 | } |
| 501 | 492 | ||
| 502 | static void cleanup_irq(struct spmi_pmic_arb *pa, u16 apid, int id) | 493 | static void cleanup_irq(struct spmi_pmic_arb *pmic_arb, u16 apid, int id) |
| 503 | { | 494 | { |
| 504 | u16 ppid = pa->apid_data[apid].ppid; | 495 | u16 ppid = pmic_arb->apid_data[apid].ppid; |
| 505 | u8 sid = ppid >> 8; | 496 | u8 sid = ppid >> 8; |
| 506 | u8 per = ppid & 0xFF; | 497 | u8 per = ppid & 0xFF; |
| 507 | u8 irq_mask = BIT(id); | 498 | u8 irq_mask = BIT(id); |
| 508 | 499 | ||
| 509 | writel_relaxed(irq_mask, pa->intr + pa->ver_ops->irq_clear(apid)); | 500 | writel_relaxed(irq_mask, pmic_arb->ver_ops->irq_clear(pmic_arb, apid)); |
| 510 | 501 | ||
| 511 | if (pmic_arb_write_cmd(pa->spmic, SPMI_CMD_EXT_WRITEL, sid, | 502 | if (pmic_arb_write_cmd(pmic_arb->spmic, SPMI_CMD_EXT_WRITEL, sid, |
| 512 | (per << 8) + QPNPINT_REG_LATCHED_CLR, &irq_mask, 1)) | 503 | (per << 8) + QPNPINT_REG_LATCHED_CLR, &irq_mask, 1)) |
| 513 | dev_err_ratelimited(&pa->spmic->dev, | 504 | dev_err_ratelimited(&pmic_arb->spmic->dev, "failed to ack irq_mask = 0x%x for ppid = %x\n", |
| 514 | "failed to ack irq_mask = 0x%x for ppid = %x\n", | ||
| 515 | irq_mask, ppid); | 505 | irq_mask, ppid); |
| 516 | 506 | ||
| 517 | if (pmic_arb_write_cmd(pa->spmic, SPMI_CMD_EXT_WRITEL, sid, | 507 | if (pmic_arb_write_cmd(pmic_arb->spmic, SPMI_CMD_EXT_WRITEL, sid, |
| 518 | (per << 8) + QPNPINT_REG_EN_CLR, &irq_mask, 1)) | 508 | (per << 8) + QPNPINT_REG_EN_CLR, &irq_mask, 1)) |
| 519 | dev_err_ratelimited(&pa->spmic->dev, | 509 | dev_err_ratelimited(&pmic_arb->spmic->dev, "failed to ack irq_mask = 0x%x for ppid = %x\n", |
| 520 | "failed to ack irq_mask = 0x%x for ppid = %x\n", | ||
| 521 | irq_mask, ppid); | 510 | irq_mask, ppid); |
| 522 | } | 511 | } |
| 523 | 512 | ||
| 524 | static void periph_interrupt(struct spmi_pmic_arb *pa, u16 apid) | 513 | static void periph_interrupt(struct spmi_pmic_arb *pmic_arb, u16 apid) |
| 525 | { | 514 | { |
| 526 | unsigned int irq; | 515 | unsigned int irq; |
| 527 | u32 status; | 516 | u32 status; |
| 528 | int id; | 517 | int id; |
| 529 | u8 sid = (pa->apid_data[apid].ppid >> 8) & 0xF; | 518 | u8 sid = (pmic_arb->apid_data[apid].ppid >> 8) & 0xF; |
| 530 | u8 per = pa->apid_data[apid].ppid & 0xFF; | 519 | u8 per = pmic_arb->apid_data[apid].ppid & 0xFF; |
| 531 | 520 | ||
| 532 | status = readl_relaxed(pa->intr + pa->ver_ops->irq_status(apid)); | 521 | status = readl_relaxed(pmic_arb->ver_ops->irq_status(pmic_arb, apid)); |
| 533 | while (status) { | 522 | while (status) { |
| 534 | id = ffs(status) - 1; | 523 | id = ffs(status) - 1; |
| 535 | status &= ~BIT(id); | 524 | status &= ~BIT(id); |
| 536 | irq = irq_find_mapping(pa->domain, HWIRQ(sid, per, id, apid)); | 525 | irq = irq_find_mapping(pmic_arb->domain, |
| 526 | spec_to_hwirq(sid, per, id, apid)); | ||
| 537 | if (irq == 0) { | 527 | if (irq == 0) { |
| 538 | cleanup_irq(pa, apid, id); | 528 | cleanup_irq(pmic_arb, apid, id); |
| 539 | continue; | 529 | continue; |
| 540 | } | 530 | } |
| 541 | generic_handle_irq(irq); | 531 | generic_handle_irq(irq); |
| @@ -544,27 +534,28 @@ static void periph_interrupt(struct spmi_pmic_arb *pa, u16 apid) · 2 unmodified lines | |||
| 544 | 534 | ||
| 545 | static void pmic_arb_chained_irq(struct irq_desc *desc) | 535 | static void pmic_arb_chained_irq(struct irq_desc *desc) |
| 546 | { | 536 | { |
| 547 | struct spmi_pmic_arb *pa = irq_desc_get_handler_data(desc); | 537 | struct spmi_pmic_arb *pmic_arb = irq_desc_get_handler_data(desc); |
| 538 | const struct pmic_arb_ver_ops *ver_ops = pmic_arb->ver_ops; | ||
| 548 | struct irq_chip *chip = irq_desc_get_chip(desc); | 539 | struct irq_chip *chip = irq_desc_get_chip(desc); |
| 549 | void __iomem *intr = pa->intr; | 540 | int first = pmic_arb->min_apid >> 5; |
| 550 | int first = pa->min_apid >> 5; | 541 | int last = pmic_arb->max_apid >> 5; |
| 551 | int last = pa->max_apid >> 5; | 542 | u8 ee = pmic_arb->ee; |
| 552 | u32 status, enable; | 543 | u32 status, enable; |
| 553 | int i, id, apid; | 544 | int i, id, apid; |
| 554 | 545 | ||
| 555 | chained_irq_enter(chip, desc); | 546 | chained_irq_enter(chip, desc); |
| 556 | 547 | ||
| 557 | for (i = first; i <= last; ++i) { | 548 | for (i = first; i <= last; ++i) { |
| 558 | status = readl_relaxed(intr + | 549 | status = readl_relaxed( |
| 559 | pa->ver_ops->owner_acc_status(pa->ee, i)); | 550 | ver_ops->owner_acc_status(pmic_arb, ee, i)); |
| 560 | while (status) { | 551 | while (status) { |
| 561 | id = ffs(status) - 1; | 552 | id = ffs(status) - 1; |
| 562 | status &= ~BIT(id); | 553 | status &= ~BIT(id); |
| 563 | apid = id + i * 32; | 554 | apid = id + i * 32; |
| 564 | enable = readl_relaxed(intr + | 555 | enable = readl_relaxed( |
| 565 | pa->ver_ops->acc_enable(apid)); | 556 | ver_ops->acc_enable(pmic_arb, apid)); |
| 566 | if (enable & SPMI_PIC_ACC_ENABLE_BIT) | 557 | if (enable & SPMI_PIC_ACC_ENABLE_BIT) |
| 567 | periph_interrupt(pa, apid); | 558 | periph_interrupt(pmic_arb, apid); |
| 568 | } | 559 | } |
| 569 | } | 560 | } |
| 570 | 561 | ||
| @@ -573,12 +564,12 @@ static void pmic_arb_chained_irq(struct irq_desc *desc) · 2 unmodified lines | |||
| 573 | 564 | ||
| 574 | static void qpnpint_irq_ack(struct irq_data *d) | 565 | static void qpnpint_irq_ack(struct irq_data *d) |
| 575 | { | 566 | { |
| 576 | struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d); | 567 | struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d); |
| 577 | u8 irq = HWIRQ_IRQ(d->hwirq); | 568 | u8 irq = hwirq_to_irq(d->hwirq); |
| 578 | u16 apid = HWIRQ_APID(d->hwirq); | 569 | u16 apid = hwirq_to_apid(d->hwirq); |
| 579 | u8 data; | 570 | u8 data; |
| 580 | 571 | ||
| 581 | writel_relaxed(BIT(irq), pa->intr + pa->ver_ops->irq_clear(apid)); | 572 | writel_relaxed(BIT(irq), pmic_arb->ver_ops->irq_clear(pmic_arb, apid)); |
| 582 | 573 | ||
| 583 | data = BIT(irq); | 574 | data = BIT(irq); |
| 584 | qpnpint_spmi_write(d, QPNPINT_REG_LATCHED_CLR, &data, 1); | 575 | qpnpint_spmi_write(d, QPNPINT_REG_LATCHED_CLR, &data, 1); |
| @@ -586,7 +577,7 @@ static void qpnpint_irq_ack(struct irq_data *d) · 1 unmodified line | |||
| 586 | 577 | ||
| 587 | static void qpnpint_irq_mask(struct irq_data *d) | 578 | static void qpnpint_irq_mask(struct irq_data *d) |
| 588 | { | 579 | { |
| 589 | u8 irq = HWIRQ_IRQ(d->hwirq); | 580 | u8 irq = hwirq_to_irq(d->hwirq); |
| 590 | u8 data = BIT(irq); | 581 | u8 data = BIT(irq); |
| 591 | 582 | ||
| 592 | qpnpint_spmi_write(d, QPNPINT_REG_EN_CLR, &data, 1); | 583 | qpnpint_spmi_write(d, QPNPINT_REG_EN_CLR, &data, 1); |
| @@ -594,13 +585,14 @@ static void qpnpint_irq_mask(struct irq_data *d) · 1 unmodified line | |||
| 594 | 585 | ||
| 595 | static void qpnpint_irq_unmask(struct irq_data *d) | 586 | static void qpnpint_irq_unmask(struct irq_data *d) |
| 596 | { | 587 | { |
| 597 | struct spmi_pmic_arb *pa = irq_data_get_irq_chip_data(d); | 588 | struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d); |
| 598 | u8 irq = HWIRQ_IRQ(d->hwirq); | 589 | const struct pmic_arb_ver_ops *ver_ops = pmic_arb->ver_ops; |
| 599 | u16 apid = HWIRQ_APID(d->hwirq); | 590 | u8 irq = hwirq_to_irq(d->hwirq); |
| 591 | u16 apid = hwirq_to_apid(d->hwirq); | ||
| 600 | u8 buf[2]; | 592 | u8 buf[2]; |
| 601 | 593 | ||
| 602 | writel_relaxed(SPMI_PIC_ACC_ENABLE_BIT, | 594 | writel_relaxed(SPMI_PIC_ACC_ENABLE_BIT, |
| 603 | pa->intr + pa->ver_ops->acc_enable(apid)); | 595 | ver_ops->acc_enable(pmic_arb, apid)); |
| 604 | 596 | ||
| 605 | qpnpint_spmi_read(d, QPNPINT_REG_EN_SET, &buf[0], 1); | 597 | qpnpint_spmi_read(d, QPNPINT_REG_EN_SET, &buf[0], 1); |
| 606 | if (!(buf[0] & BIT(irq))) { | 598 | if (!(buf[0] & BIT(irq))) { |
| @@ -618,44 +610,51 @@ static void qpnpint_irq_unmask(struct irq_data *d) · 11 unmodified lines | |||
| 618 | static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type) | 610 | static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type) |
| 619 | { | 611 | { |
| 620 | struct spmi_pmic_arb_qpnpint_type type; | 612 | struct spmi_pmic_arb_qpnpint_type type; |
| 621 | u8 irq = HWIRQ_IRQ(d->hwirq); | 613 | irq_flow_handler_t flow_handler; |
| 622 | u8 bit_mask_irq = BIT(irq); | 614 | u8 irq = hwirq_to_irq(d->hwirq); |
| 623 | 615 | ||
| 624 | qpnpint_spmi_read(d, QPNPINT_REG_SET_TYPE, &type, sizeof(type)); | 616 | qpnpint_spmi_read(d, QPNPINT_REG_SET_TYPE, &type, sizeof(type)); |
| 625 | 617 | ||
| 626 | if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) { | 618 | if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) { |
| 627 | type.type |= bit_mask_irq; | 619 | type.type |= BIT(irq); |
| 628 | if (flow_type & IRQF_TRIGGER_RISING) | 620 | if (flow_type & IRQF_TRIGGER_RISING) |
| 629 | type.polarity_high |= bit_mask_irq; | 621 | type.polarity_high |= BIT(irq); |
| 630 | if (flow_type & IRQF_TRIGGER_FALLING) | 622 | if (flow_type & IRQF_TRIGGER_FALLING) |
| 631 | type.polarity_low |= bit_mask_irq; | 623 | type.polarity_low |= BIT(irq); |
| 624 | |||
| 625 | flow_handler = handle_edge_irq; | ||
| 632 | } else { | 626 | } else { |
| 633 | if ((flow_type & (IRQF_TRIGGER_HIGH)) && | 627 | if ((flow_type & (IRQF_TRIGGER_HIGH)) && |
| 634 | (flow_type & (IRQF_TRIGGER_LOW))) | 628 | (flow_type & (IRQF_TRIGGER_LOW))) |
| 635 | return -EINVAL; | 629 | return -EINVAL; |
| 636 | 630 | ||
| 637 | type.type &= ~bit_mask_irq; /* level trig */ | 631 | type.type &= ~BIT(irq); /* level trig */ |
| 638 | if (flow_type & IRQF_TRIGGER_HIGH) | 632 | if (flow_type & IRQF_TRIGGER_HIGH) |
| 639 | type.polarity_high |= bit_mask_irq; | 633 | type.polarity_high |= BIT(irq); |
| 640 | else | 634 | else |
| 641 | type.polarity_low |= bit_mask_irq; | 635 | type.polarity_low |= BIT(irq); |
| 636 | |||
| 637 | flow_handler = handle_level_irq; | ||
| 642 | } | 638 | } |
| 643 | 639 | ||
| 644 | qpnpint_spmi_write(d, QPNPINT_REG_SET_TYPE, &type, sizeof(type)); | 640 | qpnpint_spmi_write(d, QPNPINT_REG_SET_TYPE, &type, sizeof(type)); |
| 645 | 641 | irq_set_handler_locked(d, flow_handler); | |
| 646 | if (flow_type & IRQ_TYPE_EDGE_BOTH) | ||
| 647 | irq_set_handler_locked(d, handle_edge_irq); | ||
| 648 | else | ||
| 649 | irq_set_handler_locked(d, handle_level_irq); | ||
| 650 | 642 | ||
| 651 | return 0; | 643 | return 0; |
| 652 | } | 644 | } |
| 653 | 645 | ||
| 646 | static int qpnpint_irq_set_wake(struct irq_data *d, unsigned int on) | ||
| 647 | { | ||
| 648 | struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d); | ||
| 649 | |||
| 650 | return irq_set_irq_wake(pmic_arb->irq, on); | ||
| 651 | } | ||
| 652 | |||
| 654 | static int qpnpint_get_irqchip_state(struct irq_data *d, | 653 | static int qpnpint_get_irqchip_state(struct irq_data *d, |
| 655 | enum irqchip_irq_state which, | 654 | enum irqchip_irq_state which, |
| 656 | bool *state) | 655 | bool *state) |
| 657 | { | 656 | { |
| 658 | u8 irq = HWIRQ_IRQ(d->hwirq); | 657 | u8 irq = hwirq_to_irq(d->hwirq); |
| 659 | u8 status = 0; | 658 | u8 status = 0; |
| 660 | 659 | ||
| 661 | if (which != IRQCHIP_STATE_LINE_LEVEL) | 660 | if (which != IRQCHIP_STATE_LINE_LEVEL) |
| @@ -667,15 +666,34 @@ static int qpnpint_get_irqchip_state(struct irq_data *d, · 5 unmodified lines | |||
| 667 | return 0; | 666 | return 0; |
| 668 | } | 667 | } |
| 669 | 668 | ||
| 669 | static int qpnpint_irq_request_resources(struct irq_data *d) | ||
| 670 | { | ||
| 671 | struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d); | ||
| 672 | u16 periph = hwirq_to_per(d->hwirq); | ||
| 673 | u16 apid = hwirq_to_apid(d->hwirq); | ||
| 674 | u16 sid = hwirq_to_sid(d->hwirq); | ||
| 675 | u16 irq = hwirq_to_irq(d->hwirq); | ||
| 676 | |||
| 677 | if (pmic_arb->apid_data[apid].irq_ee != pmic_arb->ee) { | ||
| 678 | dev_err(&pmic_arb->spmic->dev, "failed to xlate sid = %#x, periph = %#x, irq = %u: ee=%u but owner=%u\n", | ||
| 679 | sid, periph, irq, pmic_arb->ee, | ||
| 680 | pmic_arb->apid_data[apid].irq_ee); | ||
| 681 | return -ENODEV; | ||
| 682 | } | ||
| 683 | |||
| 684 | return 0; | ||
| 685 | } | ||
| 686 | |||
| 670 | static struct irq_chip pmic_arb_irqchip = { | 687 | static struct irq_chip pmic_arb_irqchip = { |
| 671 | .name = "pmic_arb", | 688 | .name = "pmic_arb", |
| 672 | .irq_ack = qpnpint_irq_ack, | 689 | .irq_ack = qpnpint_irq_ack, |
| 673 | .irq_mask = qpnpint_irq_mask, | 690 | .irq_mask = qpnpint_irq_mask, |
| 674 | .irq_unmask = qpnpint_irq_unmask, | 691 | .irq_unmask = qpnpint_irq_unmask, |
| 675 | .irq_set_type = qpnpint_irq_set_type, | 692 | .irq_set_type = qpnpint_irq_set_type, |
| 693 | .irq_set_wake = qpnpint_irq_set_wake, | ||
| 676 | .irq_get_irqchip_state = qpnpint_get_irqchip_state, | 694 | .irq_get_irqchip_state = qpnpint_get_irqchip_state, |
| 677 | .flags = IRQCHIP_MASK_ON_SUSPEND | 695 | .irq_request_resources = qpnpint_irq_request_resources, |
| 678 | | IRQCHIP_SKIP_SET_WAKE, | 696 | .flags = IRQCHIP_MASK_ON_SUSPEND, |
| 679 | }; | 697 | }; |
| 680 | 698 | ||
| 681 | static int qpnpint_irq_domain_dt_translate(struct irq_domain *d, | 699 | static int qpnpint_irq_domain_dt_translate(struct irq_domain *d, |
| @@ -685,12 +703,11 @@ static int qpnpint_irq_domain_dt_translate(struct irq_domain *d, · 3 unmodified lines | |||
| 685 | unsigned long *out_hwirq, | 703 | unsigned long *out_hwirq, |
| 686 | unsigned int *out_type) | 704 | unsigned int *out_type) |
| 687 | { | 705 | { |
| 688 | struct spmi_pmic_arb *pa = d->host_data; | 706 | struct spmi_pmic_arb *pmic_arb = d->host_data; |
| 707 | u16 apid, ppid; | ||
| 689 | int rc; | 708 | int rc; |
| 690 | u16 apid; | ||
| 691 | 709 | ||
| 692 | dev_dbg(&pa->spmic->dev, | 710 | dev_dbg(&pmic_arb->spmic->dev, "intspec[0] 0x%1x intspec[1] 0x%02x intspec[2] 0x%02x\n", |
| 693 | "intspec[0] 0x%1x intspec[1] 0x%02x intspec[2] 0x%02x\n", | ||
| 694 | intspec[0], intspec[1], intspec[2]); | 711 | intspec[0], intspec[1], intspec[2]); |
| 695 | 712 | ||
| 696 | if (irq_domain_get_of_node(d) != controller) | 713 | if (irq_domain_get_of_node(d) != controller) |
| @@ -700,25 +717,25 @@ static int qpnpint_irq_domain_dt_translate(struct irq_domain *d, · 3 unmodified lines | |||
| 700 | if (intspec[0] > 0xF || intspec[1] > 0xFF || intspec[2] > 0x7) | 717 | if (intspec[0] > 0xF || intspec[1] > 0xFF || intspec[2] > 0x7) |
| 701 | return -EINVAL; | 718 | return -EINVAL; |
| 702 | 719 | ||
| 703 | rc = pa->ver_ops->ppid_to_apid(pa, intspec[0], | 720 | ppid = intspec[0] << 8 | intspec[1]; |
| 704 | (intspec[1] << 8), &apid); | 721 | rc = pmic_arb->ver_ops->ppid_to_apid(pmic_arb, ppid); |
| 705 | if (rc < 0) { | 722 | if (rc < 0) { |
| 706 | dev_err(&pa->spmic->dev, | 723 | dev_err(&pmic_arb->spmic->dev, "failed to xlate sid = %#x, periph = %#x, irq = %u rc = %d\n", |
| 707 | "failed to xlate sid = 0x%x, periph = 0x%x, irq = %x rc = %d\n", | ||
| 708 | intspec[0], intspec[1], intspec[2], rc); | 724 | intspec[0], intspec[1], intspec[2], rc); |
| 709 | return rc; | 725 | return rc; |
| 710 | } | 726 | } |
| 711 | 727 | ||
| 728 | apid = rc; | ||
| 712 | /* Keep track of {max,min}_apid for bounding search during interrupt */ | 729 | /* Keep track of {max,min}_apid for bounding search during interrupt */ |
| 713 | if (apid > pa->max_apid) | 730 | if (apid > pmic_arb->max_apid) |
| 714 | pa->max_apid = apid; | 731 | pmic_arb->max_apid = apid; |
| 715 | if (apid < pa->min_apid) | 732 | if (apid < pmic_arb->min_apid) |
| 716 | pa->min_apid = apid; | 733 | pmic_arb->min_apid = apid; |
| 717 | 734 | ||
| 718 | *out_hwirq = HWIRQ(intspec[0], intspec[1], intspec[2], apid); | 735 | *out_hwirq = spec_to_hwirq(intspec[0], intspec[1], intspec[2], apid); |
| 719 | *out_type = intspec[3] & IRQ_TYPE_SENSE_MASK; | 736 | *out_type = intspec[3] & IRQ_TYPE_SENSE_MASK; |
| 720 | 737 | ||
| 721 | dev_dbg(&pa->spmic->dev, "out_hwirq = %lu\n", *out_hwirq); | 738 | dev_dbg(&pmic_arb->spmic->dev, "out_hwirq = %lu\n", *out_hwirq); |
| 722 | 739 | ||
| 723 | return 0; | 740 | return 0; |
| 724 | } | 741 | } |
| @@ -727,9 +744,9 @@ static int qpnpint_irq_domain_map(struct irq_domain *d, · 2 unmodified lines | |||
| 727 | unsigned int virq, | 744 | unsigned int virq, |
| 728 | irq_hw_number_t hwirq) | 745 | irq_hw_number_t hwirq) |
| 729 | { | 746 | { |
| 730 | struct spmi_pmic_arb *pa = d->host_data; | 747 | struct spmi_pmic_arb *pmic_arb = d->host_data; |
| 731 | 748 | ||
| 732 | dev_dbg(&pa->spmic->dev, "virq = %u, hwirq = %lu\n", virq, hwirq); | 749 | dev_dbg(&pmic_arb->spmic->dev, "virq = %u, hwirq = %lu\n", virq, hwirq); |
| 733 | 750 | ||
| 734 | irq_set_chip_and_handler(virq, &pmic_arb_irqchip, handle_level_irq); | 751 | irq_set_chip_and_handler(virq, &pmic_arb_irqchip, handle_level_irq); |
| 735 | irq_set_chip_data(virq, d->host_data); | 752 | irq_set_chip_data(virq, d->host_data); |
| @@ -737,24 +754,23 @@ static int qpnpint_irq_domain_map(struct irq_domain *d, · 1 unmodified line | |||
| 737 | return 0; | 754 | return 0; |
| 738 | } | 755 | } |
| 739 | 756 | ||
| 740 | static int | 757 | static int pmic_arb_ppid_to_apid_v1(struct spmi_pmic_arb *pmic_arb, u16 ppid) |
| 741 | pmic_arb_ppid_to_apid_v1(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u16 *apid) | ||
| 742 | { | 758 | { |
| 743 | u16 ppid = sid << 8 | ((addr >> 8) & 0xFF); | 759 | u32 *mapping_table = pmic_arb->mapping_table; |
| 744 | u32 *mapping_table = pa->mapping_table; | ||
| 745 | int index = 0, i; | 760 | int index = 0, i; |
| 746 | u16 apid_valid; | 761 | u16 apid_valid; |
| 762 | u16 apid; | ||
| 747 | u32 data; | 763 | u32 data; |
| 748 | 764 | ||
| 749 | apid_valid = pa->ppid_to_apid[ppid]; | 765 | apid_valid = pmic_arb->ppid_to_apid[ppid]; |
| 750 | if (apid_valid & PMIC_ARB_CHAN_VALID) { | 766 | if (apid_valid & PMIC_ARB_APID_VALID) { |
| 751 | *apid = (apid_valid & ~PMIC_ARB_CHAN_VALID); | 767 | apid = apid_valid & ~PMIC_ARB_APID_VALID; |
| 752 | return 0; | 768 | return apid; |
| 753 | } | 769 | } |
| 754 | 770 | ||
| 755 | for (i = 0; i < SPMI_MAPPING_TABLE_TREE_DEPTH; ++i) { | 771 | for (i = 0; i < SPMI_MAPPING_TABLE_TREE_DEPTH; ++i) { |
| 756 | if (!test_and_set_bit(index, pa->mapping_table_valid)) | 772 | if (!test_and_set_bit(index, pmic_arb->mapping_table_valid)) |
| 757 | mapping_table[index] = readl_relaxed(pa->cnfg + | 773 | mapping_table[index] = readl_relaxed(pmic_arb->cnfg + |
| 758 | SPMI_MAPPING_TABLE_REG(index)); | 774 | SPMI_MAPPING_TABLE_REG(index)); |
| 759 | 775 | ||
| 760 | data = mapping_table[index]; | 776 | data = mapping_table[index]; |
| @@ -763,21 +779,21 @@ pmic_arb_ppid_to_apid_v1(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u16 *apid) · 2 unmodified lines | |||
| 763 | if (SPMI_MAPPING_BIT_IS_1_FLAG(data)) { | 779 | if (SPMI_MAPPING_BIT_IS_1_FLAG(data)) { |
| 764 | index = SPMI_MAPPING_BIT_IS_1_RESULT(data); | 780 | index = SPMI_MAPPING_BIT_IS_1_RESULT(data); |
| 765 | } else { | 781 | } else { |
| 766 | *apid = SPMI_MAPPING_BIT_IS_1_RESULT(data); | 782 | apid = SPMI_MAPPING_BIT_IS_1_RESULT(data); |
| 767 | pa->ppid_to_apid[ppid] | 783 | pmic_arb->ppid_to_apid[ppid] |
| 768 | = *apid | PMIC_ARB_CHAN_VALID; | 784 | = apid | PMIC_ARB_APID_VALID; |
| 769 | pa->apid_data[*apid].ppid = ppid; | 785 | pmic_arb->apid_data[apid].ppid = ppid; |
| 770 | return 0; | 786 | return apid; |
| 771 | } | 787 | } |
| 772 | } else { | 788 | } else { |
| 773 | if (SPMI_MAPPING_BIT_IS_0_FLAG(data)) { | 789 | if (SPMI_MAPPING_BIT_IS_0_FLAG(data)) { |
| 774 | index = SPMI_MAPPING_BIT_IS_0_RESULT(data); | 790 | index = SPMI_MAPPING_BIT_IS_0_RESULT(data); |
| 775 | } else { | 791 | } else { |
| 776 | *apid = SPMI_MAPPING_BIT_IS_0_RESULT(data); | 792 | apid = SPMI_MAPPING_BIT_IS_0_RESULT(data); |
| 777 | pa->ppid_to_apid[ppid] | 793 | pmic_arb->ppid_to_apid[ppid] |
| 778 | = *apid | PMIC_ARB_CHAN_VALID; | 794 | = apid | PMIC_ARB_APID_VALID; |
| 779 | pa->apid_data[*apid].ppid = ppid; | 795 | pmic_arb->apid_data[apid].ppid = ppid; |
| 780 | return 0; | 796 | return apid; |
| 781 | } | 797 | } |
| 782 | } | 798 | } |
| 783 | } | 799 | } |
| @@ -785,105 +801,178 @@ pmic_arb_ppid_to_apid_v1(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u16 *apid) · 1 unmodified line | |||
| 785 | return -ENODEV; | 801 | return -ENODEV; |
| 786 | } | 802 | } |
| 787 | 803 | ||
| 788 | static int | ||
| 789 | pmic_arb_mode_v1_v3(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t *mode) | ||
| 790 | { | ||
| 791 | *mode = S_IRUSR | S_IWUSR; | ||
| 792 | return 0; | ||
| 793 | } | ||
| 794 | |||
| 795 | /* v1 offset per ee */ | 804 | /* v1 offset per ee */ |
| 796 | static int | 805 | static int pmic_arb_offset_v1(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr, |
| 797 | pmic_arb_offset_v1(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u32 *offset) | 806 | enum pmic_arb_channel ch_type) |
| 798 | { | 807 | { |
| 799 | *offset = 0x800 + 0x80 * pa->channel; | 808 | return 0x800 + 0x80 * pmic_arb->channel; |
| 800 | return 0; | ||
| 801 | } | 809 | } |
| 802 | 810 | ||
| 803 | static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pa, u16 ppid) | 811 | static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pmic_arb, u16 ppid) |
| 804 | { | 812 | { |
| 813 | struct apid_data *apidd = &pmic_arb->apid_data[pmic_arb->last_apid]; | ||
| 805 | u32 regval, offset; | 814 | u32 regval, offset; |
| 806 | u16 apid; | 815 | u16 id, apid; |
| 807 | u16 id; | ||
| 808 | |||
| 809 | /* | ||
| 810 | * PMIC_ARB_REG_CHNL is a table in HW mapping channel to ppid. | ||
| 811 | * ppid_to_apid is an in-memory invert of that table. | ||
| 812 | */ | ||
| 813 | for (apid = pa->last_apid; apid < pa->max_periph; apid++) { | ||
| 814 | regval = readl_relaxed(pa->cnfg + | ||
| 815 | SPMI_OWNERSHIP_TABLE_REG(apid)); | ||
| 816 | pa->apid_data[apid].owner = SPMI_OWNERSHIP_PERIPH2OWNER(regval); | ||
| 817 | 816 | ||
| 818 | offset = PMIC_ARB_REG_CHNL(apid); | 817 | for (apid = pmic_arb->last_apid; ; apid++, apidd++) { |
| 819 | if (offset >= pa->core_size) | 818 | offset = pmic_arb->ver_ops->apid_map_offset(apid); |
| 819 | if (offset >= pmic_arb->core_size) | ||
| 820 | break; | 820 | break; |
| 821 | 821 | ||
| 822 | regval = readl_relaxed(pa->core + offset); | 822 | regval = readl_relaxed(pmic_arb->cnfg + |
| 823 | SPMI_OWNERSHIP_TABLE_REG(apid)); | ||
| 824 | apidd->irq_ee = SPMI_OWNERSHIP_PERIPH2OWNER(regval); | ||
| 825 | apidd->write_ee = apidd->irq_ee; | ||
| 826 | |||
| 827 | regval = readl_relaxed(pmic_arb->core + offset); | ||
| 823 | if (!regval) | 828 | if (!regval) |
| 824 | continue; | 829 | continue; |
| 825 | 830 | ||
| 826 | id = (regval >> 8) & PMIC_ARB_PPID_MASK; | 831 | id = (regval >> 8) & PMIC_ARB_PPID_MASK; |
| 827 | pa->ppid_to_apid[id] = apid | PMIC_ARB_CHAN_VALID; | 832 | pmic_arb->ppid_to_apid[id] = apid | PMIC_ARB_APID_VALID; |
| 828 | pa->apid_data[apid].ppid = id; | 833 | apidd->ppid = id; |
| 829 | if (id == ppid) { | 834 | if (id == ppid) { |
| 830 | apid |= PMIC_ARB_CHAN_VALID; | 835 | apid |= PMIC_ARB_APID_VALID; |
| 831 | break; | 836 | break; |
| 832 | } | 837 | } |
| 833 | } | 838 | } |
| 834 | pa->last_apid = apid & ~PMIC_ARB_CHAN_VALID; | 839 | pmic_arb->last_apid = apid & ~PMIC_ARB_APID_VALID; |
| 835 | 840 | ||
| 836 | return apid; | 841 | return apid; |
| 837 | } | 842 | } |
| 838 | 843 | ||
| 839 | 844 | static int pmic_arb_ppid_to_apid_v2(struct spmi_pmic_arb *pmic_arb, u16 ppid) | |
| 840 | static int | ||
| 841 | pmic_arb_ppid_to_apid_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u16 *apid) | ||
| 842 | { | 845 | { |
| 843 | u16 ppid = (sid << 8) | (addr >> 8); | ||
| 844 | u16 apid_valid; | 846 | u16 apid_valid; |
| 845 | 847 | ||
| 846 | apid_valid = pa->ppid_to_apid[ppid]; | 848 | apid_valid = pmic_arb->ppid_to_apid[ppid]; |
| 847 | if (!(apid_valid & PMIC_ARB_CHAN_VALID)) | 849 | if (!(apid_valid & PMIC_ARB_APID_VALID)) |
| 848 | apid_valid = pmic_arb_find_apid(pa, ppid); | 850 | apid_valid = pmic_arb_find_apid(pmic_arb, ppid); |
| 849 | if (!(apid_valid & PMIC_ARB_CHAN_VALID)) | 851 | if (!(apid_valid & PMIC_ARB_APID_VALID)) |
| 850 | return -ENODEV; | 852 | return -ENODEV; |
| 851 | 853 | ||
| 852 | *apid = (apid_valid & ~PMIC_ARB_CHAN_VALID); | 854 | return apid_valid & ~PMIC_ARB_APID_VALID; |
| 855 | } | ||
| 856 | |||
| 857 | static int pmic_arb_read_apid_map_v5(struct spmi_pmic_arb *pmic_arb) | ||
| 858 | { | ||
| 859 | struct apid_data *apidd = pmic_arb->apid_data; | ||
| 860 | struct apid_data *prev_apidd; | ||
| 861 | u16 i, apid, ppid; | ||
| 862 | bool valid, is_irq_ee; | ||
| 863 | u32 regval, offset; | ||
| 864 | |||
| 865 | /* | ||
| 866 | * In order to allow multiple EEs to write to a single PPID in arbiter | ||
| 867 | * version 5, there is more than one APID mapped to each PPID. | ||
| 868 | * The owner field for each of these mappings specifies the EE which is | ||
| 869 | * allowed to write to the APID. The owner of the last (highest) APID | ||
| 870 | * for a given PPID will receive interrupts from the PPID. | ||
| 871 | */ | ||
| 872 | for (i = 0; ; i++, apidd++) { | ||
| 873 | offset = pmic_arb->ver_ops->apid_map_offset(i); | ||
| 874 | if (offset >= pmic_arb->core_size) | ||
| 875 | break; | ||
| 876 | |||
| 877 | regval = readl_relaxed(pmic_arb->core + offset); | ||
| 878 | if (!regval) | ||
| 879 | continue; | ||
| 880 | ppid = (regval >> 8) & PMIC_ARB_PPID_MASK; | ||
| 881 | is_irq_ee = PMIC_ARB_CHAN_IS_IRQ_OWNER(regval); | ||
| 882 | |||
| 883 | regval = readl_relaxed(pmic_arb->cnfg + | ||
| 884 | SPMI_OWNERSHIP_TABLE_REG(i)); | ||
| 885 | apidd->write_ee = SPMI_OWNERSHIP_PERIPH2OWNER(regval); | ||
| 886 | |||
| 887 | apidd->irq_ee = is_irq_ee ? apidd->write_ee : INVALID_EE; | ||
| 888 | |||
| 889 | valid = pmic_arb->ppid_to_apid[ppid] & PMIC_ARB_APID_VALID; | ||
| 890 | apid = pmic_arb->ppid_to_apid[ppid] & ~PMIC_ARB_APID_VALID; | ||
| 891 | prev_apidd = &pmic_arb->apid_data[apid]; | ||
| 892 | |||
| 893 | if (valid && is_irq_ee && | ||
| 894 | prev_apidd->write_ee == pmic_arb->ee) { | ||
| 895 | /* | ||
| 896 | * Duplicate PPID mapping after the one for this EE; | ||
| 897 | * override the irq owner | ||
| 898 | */ | ||
| 899 | prev_apidd->irq_ee = apidd->irq_ee; | ||
| 900 | } else if (!valid || is_irq_ee) { | ||
| 901 | /* First PPID mapping or duplicate for another EE */ | ||
| 902 | pmic_arb->ppid_to_apid[ppid] = i | PMIC_ARB_APID_VALID; | ||
| 903 | } | ||
| 904 | |||
| 905 | apidd->ppid = ppid; | ||
| 906 | pmic_arb->last_apid = i; | ||
| 907 | } | ||
| 908 | |||
| 909 | /* Dump the mapping table for debug purposes. */ | ||
| 910 | dev_dbg(&pmic_arb->spmic->dev, "PPID APID Write-EE IRQ-EE\n"); | ||
| 911 | for (ppid = 0; ppid < PMIC_ARB_MAX_PPID; ppid++) { | ||
| 912 | apid = pmic_arb->ppid_to_apid[ppid]; | ||
| 913 | if (apid & PMIC_ARB_APID_VALID) { | ||
| 914 | apid &= ~PMIC_ARB_APID_VALID; | ||
| 915 | apidd = &pmic_arb->apid_data[apid]; | ||
| 916 | dev_dbg(&pmic_arb->spmic->dev, "%#03X %3u %2u %2u\n", | ||
| 917 | ppid, apid, apidd->write_ee, apidd->irq_ee); | ||
| 918 | } | ||
| 919 | } | ||
| 920 | |||
| 853 | return 0; | 921 | return 0; |
| 854 | } | 922 | } |
| 855 | 923 | ||
| 856 | static int | 924 | static int pmic_arb_ppid_to_apid_v5(struct spmi_pmic_arb *pmic_arb, u16 ppid) |
| 857 | pmic_arb_mode_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, mode_t *mode) | 925 | { |
| 926 | if (!(pmic_arb->ppid_to_apid[ppid] & PMIC_ARB_APID_VALID)) | ||
| 927 | return -ENODEV; | ||
| 928 | |||
| 929 | return pmic_arb->ppid_to_apid[ppid] & ~PMIC_ARB_APID_VALID; | ||
| 930 | } | ||
| 931 | |||
| 932 | /* v2 offset per ppid and per ee */ | ||
| 933 | static int pmic_arb_offset_v2(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr, | ||
| 934 | enum pmic_arb_channel ch_type) | ||
| 858 | { | 935 | { |
| 859 | u16 apid; | 936 | u16 apid; |
| 937 | u16 ppid; | ||
| 860 | int rc; | 938 | int rc; |
| 861 | 939 | ||
| 862 | rc = pmic_arb_ppid_to_apid_v2(pa, sid, addr, &apid); | 940 | ppid = sid << 8 | ((addr >> 8) & 0xFF); |
| 941 | rc = pmic_arb_ppid_to_apid_v2(pmic_arb, ppid); | ||
| 863 | if (rc < 0) | 942 | if (rc < 0) |
| 864 | return rc; | 943 | return rc; |
| 865 | 944 | ||
| 866 | *mode = 0; | 945 | apid = rc; |
| 867 | *mode |= S_IRUSR; | 946 | return 0x1000 * pmic_arb->ee + 0x8000 * apid; |
| 868 | |||
| 869 | if (pa->ee == pa->apid_data[apid].owner) | ||
| 870 | *mode |= S_IWUSR; | ||
| 871 | return 0; | ||
| 872 | } | 947 | } |
| 873 | 948 | ||
| 874 | /* v2 offset per ppid and per ee */ | 949 | /* |
| 875 | static int | 950 | * v5 offset per ee and per apid for observer channels and per apid for |
| 876 | pmic_arb_offset_v2(struct spmi_pmic_arb *pa, u8 sid, u16 addr, u32 *offset) | 951 | * read/write channels. |
| 952 | */ | ||
| 953 | static int pmic_arb_offset_v5(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr, | ||
| 954 | enum pmic_arb_channel ch_type) | ||
| 877 | { | 955 | { |
| 878 | u16 apid; | 956 | u16 apid; |
| 879 | int rc; | 957 | int rc; |
| 958 | u32 offset = 0; | ||
| 959 | u16 ppid = (sid << 8) | (addr >> 8); | ||
| 880 | 960 | ||
| 881 | rc = pmic_arb_ppid_to_apid_v2(pa, sid, addr, &apid); | 961 | rc = pmic_arb_ppid_to_apid_v5(pmic_arb, ppid); |
| 882 | if (rc < 0) | 962 | if (rc < 0) |
| 883 | return rc; | 963 | return rc; |
| 884 | 964 | ||
| 885 | *offset = 0x1000 * pa->ee + 0x8000 * apid; | 965 | apid = rc; |
| 886 | return 0; | 966 | switch (ch_type) { |
| 967 | case PMIC_ARB_CHANNEL_OBS: | ||
| 968 | offset = 0x10000 * pmic_arb->ee + 0x80 * apid; | ||
| 969 | break; | ||
| 970 | case PMIC_ARB_CHANNEL_RW: | ||
| 971 | offset = 0x10000 * apid; | ||
| 972 | break; | ||
| 973 | } | ||
| 974 | |||
| 975 | return offset; | ||
| 887 | } | 976 | } |
| 888 | 977 | ||
| 889 | static u32 pmic_arb_fmt_cmd_v1(u8 opc, u8 sid, u16 addr, u8 bc) | 978 | static u32 pmic_arb_fmt_cmd_v1(u8 opc, u8 sid, u16 addr, u8 bc) |
| @@ -896,55 +985,97 @@ static u32 pmic_arb_fmt_cmd_v2(u8 opc, u8 sid, u16 addr, u8 bc) · 6 unmodified lines | |||
| 896 | return (opc << 27) | ((addr & 0xff) << 4) | (bc & 0x7); | 985 | return (opc << 27) | ((addr & 0xff) << 4) | (bc & 0x7); |
| 897 | } | 986 | } |
| 898 | 987 | ||
| 899 | static u32 pmic_arb_owner_acc_status_v1(u8 m, u16 n) | 988 | static void __iomem * |
| 989 | pmic_arb_owner_acc_status_v1(struct spmi_pmic_arb *pmic_arb, u8 m, u16 n) | ||
| 990 | { | ||
| 991 | return pmic_arb->intr + 0x20 * m + 0x4 * n; | ||
| 992 | } | ||
| 993 | |||
| 994 | static void __iomem * | ||
| 995 | pmic_arb_owner_acc_status_v2(struct spmi_pmic_arb *pmic_arb, u8 m, u16 n) | ||
| 996 | { | ||
| 997 | return pmic_arb->intr + 0x100000 + 0x1000 * m + 0x4 * n; | ||
| 998 | } | ||
| 999 | |||
| 1000 | static void __iomem * | ||
| 1001 | pmic_arb_owner_acc_status_v3(struct spmi_pmic_arb *pmic_arb, u8 m, u16 n) | ||
| 1002 | { | ||
| 1003 | return pmic_arb->intr + 0x200000 + 0x1000 * m + 0x4 * n; | ||
| 1004 | } | ||
| 1005 | |||
| 1006 | static void __iomem * | ||
| 1007 | pmic_arb_owner_acc_status_v5(struct spmi_pmic_arb *pmic_arb, u8 m, u16 n) | ||
| 1008 | { | ||
| 1009 | return pmic_arb->intr + 0x10000 * m + 0x4 * n; | ||
| 1010 | } | ||
| 1011 | |||
| 1012 | static void __iomem * | ||
| 1013 | pmic_arb_acc_enable_v1(struct spmi_pmic_arb *pmic_arb, u16 n) | ||
| 1014 | { | ||
| 1015 | return pmic_arb->intr + 0x200 + 0x4 * n; | ||
| 1016 | } | ||
| 1017 | |||
| 1018 | static void __iomem * | ||
| 1019 | pmic_arb_acc_enable_v2(struct spmi_pmic_arb *pmic_arb, u16 n) | ||
| 1020 | { | ||
| 1021 | return pmic_arb->intr + 0x1000 * n; | ||
| 1022 | } | ||
| 1023 | |||
| 1024 | static void __iomem * | ||
| 1025 | pmic_arb_acc_enable_v5(struct spmi_pmic_arb *pmic_arb, u16 n) | ||
| 900 | { | 1026 | { |
| 901 | return 0x20 * m + 0x4 * n; | 1027 | return pmic_arb->wr_base + 0x100 + 0x10000 * n; |
| 902 | } | 1028 | } |
| 903 | 1029 | ||
| 904 | static u32 pmic_arb_owner_acc_status_v2(u8 m, u16 n) | 1030 | static void __iomem * |
| 1031 | pmic_arb_irq_status_v1(struct spmi_pmic_arb *pmic_arb, u16 n) | ||
| 905 | { | 1032 | { |
| 906 | return 0x100000 + 0x1000 * m + 0x4 * n; | 1033 | return pmic_arb->intr + 0x600 + 0x4 * n; |
| 907 | } | 1034 | } |
| 908 | 1035 | ||
| 909 | static u32 pmic_arb_owner_acc_status_v3(u8 m, u16 n) | 1036 | static void __iomem * |
| 1037 | pmic_arb_irq_status_v2(struct spmi_pmic_arb *pmic_arb, u16 n) | ||
| 910 | { | 1038 | { |
| 911 | return 0x200000 + 0x1000 * m + 0x4 * n; | 1039 | return pmic_arb->intr + 0x4 + 0x1000 * n; |
| 912 | } | 1040 | } |
| 913 | 1041 | ||
| 914 | static u32 pmic_arb_acc_enable_v1(u16 n) | 1042 | static void __iomem * |
| 1043 | pmic_arb_irq_status_v5(struct spmi_pmic_arb *pmic_arb, u16 n) | ||
| 915 | { | 1044 | { |
| 916 | return 0x200 + 0x4 * n; | 1045 | return pmic_arb->wr_base + 0x104 + 0x10000 * n; |
| 917 | } | 1046 | } |
| 918 | 1047 | ||
| 919 | static u32 pmic_arb_acc_enable_v2(u16 n) | 1048 | static void __iomem * |
| 1049 | pmic_arb_irq_clear_v1(struct spmi_pmic_arb *pmic_arb, u16 n) | ||
| 920 | { | 1050 | { |
| 921 | return 0x1000 * n; | 1051 | return pmic_arb->intr + 0xA00 + 0x4 * n; |
| 922 | } | 1052 | } |
| 923 | 1053 | ||
| 924 | static u32 pmic_arb_irq_status_v1(u16 n) | 1054 | static void __iomem * |
| 1055 | pmic_arb_irq_clear_v2(struct spmi_pmic_arb *pmic_arb, u16 n) | ||
| 925 | { | 1056 | { |
| 926 | return 0x600 + 0x4 * n; | 1057 | return pmic_arb->intr + 0x8 + 0x1000 * n; |
| 927 | } | 1058 | } |
| 928 | 1059 | ||
| 929 | static u32 pmic_arb_irq_status_v2(u16 n) | 1060 | static void __iomem * |
| 1061 | pmic_arb_irq_clear_v5(struct spmi_pmic_arb *pmic_arb, u16 n) | ||
| 930 | { | 1062 | { |
| 931 | return 0x4 + 0x1000 * n; | 1063 | return pmic_arb->wr_base + 0x108 + 0x10000 * n; |
| 932 | } | 1064 | } |
| 933 | 1065 | ||
| 934 | static u32 pmic_arb_irq_clear_v1(u16 n) | 1066 | static u32 pmic_arb_apid_map_offset_v2(u16 n) |
| 935 | { | 1067 | { |
| 936 | return 0xA00 + 0x4 * n; | 1068 | return 0x800 + 0x4 * n; |
| 937 | } | 1069 | } |
| 938 | 1070 | ||
| 939 | static u32 pmic_arb_irq_clear_v2(u16 n) | 1071 | static u32 pmic_arb_apid_map_offset_v5(u16 n) |
| 940 | { | 1072 | { |
| 941 | return 0x8 + 0x1000 * n; | 1073 | return 0x900 + 0x4 * n; |
| 942 | } | 1074 | } |
| 943 | 1075 | ||
| 944 | static const struct pmic_arb_ver_ops pmic_arb_v1 = { | 1076 | static const struct pmic_arb_ver_ops pmic_arb_v1 = { |
| 945 | .ver_str = "v1", | 1077 | .ver_str = "v1", |
| 946 | .ppid_to_apid = pmic_arb_ppid_to_apid_v1, | 1078 | .ppid_to_apid = pmic_arb_ppid_to_apid_v1, |
| 947 | .mode = pmic_arb_mode_v1_v3, | ||
| 948 | .non_data_cmd = pmic_arb_non_data_cmd_v1, | 1079 | .non_data_cmd = pmic_arb_non_data_cmd_v1, |
| 949 | .offset = pmic_arb_offset_v1, | 1080 | .offset = pmic_arb_offset_v1, |
| 950 | .fmt_cmd = pmic_arb_fmt_cmd_v1, | 1081 | .fmt_cmd = pmic_arb_fmt_cmd_v1, |
| @@ -952,12 +1083,12 @@ static const struct pmic_arb_ver_ops pmic_arb_v1 = { · 1 unmodified line | |||
| 952 | .acc_enable = pmic_arb_acc_enable_v1, | 1083 | .acc_enable = pmic_arb_acc_enable_v1, |
| 953 | .irq_status = pmic_arb_irq_status_v1, | 1084 | .irq_status = pmic_arb_irq_status_v1, |
| 954 | .irq_clear = pmic_arb_irq_clear_v1, | 1085 | .irq_clear = pmic_arb_irq_clear_v1, |
| 1086 | .apid_map_offset = pmic_arb_apid_map_offset_v2, | ||
| 955 | }; | 1087 | }; |
| 956 | 1088 | ||
| 957 | static const struct pmic_arb_ver_ops pmic_arb_v2 = { | 1089 | static const struct pmic_arb_ver_ops pmic_arb_v2 = { |
| 958 | .ver_str = "v2", | 1090 | .ver_str = "v2", |
| 959 | .ppid_to_apid = pmic_arb_ppid_to_apid_v2, | 1091 | .ppid_to_apid = pmic_arb_ppid_to_apid_v2, |
| 960 | .mode = pmic_arb_mode_v2, | ||
| 961 | .non_data_cmd = pmic_arb_non_data_cmd_v2, | 1092 | .non_data_cmd = pmic_arb_non_data_cmd_v2, |
| 962 | .offset = pmic_arb_offset_v2, | 1093 | .offset = pmic_arb_offset_v2, |
| 963 | .fmt_cmd = pmic_arb_fmt_cmd_v2, | 1094 | .fmt_cmd = pmic_arb_fmt_cmd_v2, |
| @@ -965,12 +1096,12 @@ static const struct pmic_arb_ver_ops pmic_arb_v2 = { · 1 unmodified line | |||
| 965 | .acc_enable = pmic_arb_acc_enable_v2, | 1096 | .acc_enable = pmic_arb_acc_enable_v2, |
| 966 | .irq_status = pmic_arb_irq_status_v2, | 1097 | .irq_status = pmic_arb_irq_status_v2, |
| 967 | .irq_clear = pmic_arb_irq_clear_v2, | 1098 | .irq_clear = pmic_arb_irq_clear_v2, |
| 1099 | .apid_map_offset = pmic_arb_apid_map_offset_v2, | ||
| 968 | }; | 1100 | }; |
| 969 | 1101 | ||
| 970 | static const struct pmic_arb_ver_ops pmic_arb_v3 = { | 1102 | static const struct pmic_arb_ver_ops pmic_arb_v3 = { |
| 971 | .ver_str = "v3", | 1103 | .ver_str = "v3", |
| 972 | .ppid_to_apid = pmic_arb_ppid_to_apid_v2, | 1104 | .ppid_to_apid = pmic_arb_ppid_to_apid_v2, |
| 973 | .mode = pmic_arb_mode_v1_v3, | ||
| 974 | .non_data_cmd = pmic_arb_non_data_cmd_v2, | 1105 | .non_data_cmd = pmic_arb_non_data_cmd_v2, |
| 975 | .offset = pmic_arb_offset_v2, | 1106 | .offset = pmic_arb_offset_v2, |
| 976 | .fmt_cmd = pmic_arb_fmt_cmd_v2, | 1107 | .fmt_cmd = pmic_arb_fmt_cmd_v2, |
| @@ -978,6 +1109,20 @@ static const struct pmic_arb_ver_ops pmic_arb_v3 = { · 1 unmodified line | |||
| 978 | .acc_enable = pmic_arb_acc_enable_v2, | 1109 | .acc_enable = pmic_arb_acc_enable_v2, |
| 979 | .irq_status = pmic_arb_irq_status_v2, | 1110 | .irq_status = pmic_arb_irq_status_v2, |
| 980 | .irq_clear = pmic_arb_irq_clear_v2, | 1111 | .irq_clear = pmic_arb_irq_clear_v2, |
| 1112 | .apid_map_offset = pmic_arb_apid_map_offset_v2, | ||
| 1113 | }; | ||
| 1114 | |||
| 1115 | static const struct pmic_arb_ver_ops pmic_arb_v5 = { | ||
| 1116 | .ver_str = "v5", | ||
| 1117 | .ppid_to_apid = pmic_arb_ppid_to_apid_v5, | ||
| 1118 | .non_data_cmd = pmic_arb_non_data_cmd_v2, | ||
| 1119 | .offset = pmic_arb_offset_v5, | ||
| 1120 | .fmt_cmd = pmic_arb_fmt_cmd_v2, | ||
| 1121 | .owner_acc_status = pmic_arb_owner_acc_status_v5, | ||
| 1122 | .acc_enable = pmic_arb_acc_enable_v5, | ||
| 1123 | .irq_status = pmic_arb_irq_status_v5, | ||
| 1124 | .irq_clear = pmic_arb_irq_clear_v5, | ||
| 1125 | .apid_map_offset = pmic_arb_apid_map_offset_v5, | ||
| 981 | }; | 1126 | }; |
| 982 | 1127 | ||
| 983 | static const struct irq_domain_ops pmic_arb_irq_domain_ops = { | 1128 | static const struct irq_domain_ops pmic_arb_irq_domain_ops = { |
| @@ -987,37 +1132,34 @@ static const struct irq_domain_ops pmic_arb_irq_domain_ops = { · 3 unmodified lines | |||
| 987 | 1132 | ||
| 988 | static int spmi_pmic_arb_probe(struct platform_device *pdev) | 1133 | static int spmi_pmic_arb_probe(struct platform_device *pdev) |
| 989 | { | 1134 | { |
| 990 | struct spmi_pmic_arb *pa; | 1135 | struct spmi_pmic_arb *pmic_arb; |
| 991 | struct spmi_controller *ctrl; | 1136 | struct spmi_controller *ctrl; |
| 992 | struct resource *res; | 1137 | struct resource *res; |
| 993 | void __iomem *core; | 1138 | void __iomem *core; |
| 1139 | u32 *mapping_table; | ||
| 994 | u32 channel, ee, hw_ver; | 1140 | u32 channel, ee, hw_ver; |
| 995 | int err; | 1141 | int err; |
| 996 | 1142 | ||
| 997 | ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*pa)); | 1143 | ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*pmic_arb)); |
| 998 | if (!ctrl) | 1144 | if (!ctrl) |
| 999 | return -ENOMEM; | 1145 | return -ENOMEM; |
| 1000 | 1146 | ||
| 1001 | pa = spmi_controller_get_drvdata(ctrl); | 1147 | pmic_arb = spmi_controller_get_drvdata(ctrl); |
| 1002 | pa->spmic = ctrl; | 1148 | pmic_arb->spmic = ctrl; |
| 1003 | 1149 | ||
| 1004 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core"); | 1150 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core"); |
| 1005 | pa->core_size = resource_size(res); | ||
| 1006 | if (pa->core_size <= 0x800) { | ||
| 1007 | dev_err(&pdev->dev, "core_size is smaller than 0x800. Failing Probe\n"); | ||
| 1008 | err = -EINVAL; | ||
| 1009 | goto err_put_ctrl; | ||
| 1010 | } | ||
| 1011 | |||
| 1012 | core = devm_ioremap_resource(&ctrl->dev, res); | 1151 | core = devm_ioremap_resource(&ctrl->dev, res); |
| 1013 | if (IS_ERR(core)) { | 1152 | if (IS_ERR(core)) { |
| 1014 | err = PTR_ERR(core); | 1153 | err = PTR_ERR(core); |
| 1015 | goto err_put_ctrl; | 1154 | goto err_put_ctrl; |
| 1016 | } | 1155 | } |
| 1017 | 1156 | ||
| 1018 | pa->ppid_to_apid = devm_kcalloc(&ctrl->dev, PMIC_ARB_MAX_PPID, | 1157 | pmic_arb->core_size = resource_size(res); |
| 1019 | sizeof(*pa->ppid_to_apid), GFP_KERNEL); | 1158 | |
| 1020 | if (!pa->ppid_to_apid) { | 1159 | pmic_arb->ppid_to_apid = devm_kcalloc(&ctrl->dev, PMIC_ARB_MAX_PPID, |
| 1160 | sizeof(*pmic_arb->ppid_to_apid), | ||
| 1161 | GFP_KERNEL); | ||
| 1162 | if (!pmic_arb->ppid_to_apid) { | ||
| 1021 | err = -ENOMEM; | 1163 | err = -ENOMEM; |
| 1022 | goto err_put_ctrl; | 1164 | goto err_put_ctrl; |
| 1023 | } | 1165 | } |
| @@ -1025,57 +1167,56 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev) · 1 unmodified line | |||
| 1025 | hw_ver = readl_relaxed(core + PMIC_ARB_VERSION); | 1167 | hw_ver = readl_relaxed(core + PMIC_ARB_VERSION); |
| 1026 | 1168 | ||
| 1027 | if (hw_ver < PMIC_ARB_VERSION_V2_MIN) { | 1169 | if (hw_ver < PMIC_ARB_VERSION_V2_MIN) { |
| 1028 | pa->ver_ops = &pmic_arb_v1; | 1170 | pmic_arb->ver_ops = &pmic_arb_v1; |
| 1029 | pa->wr_base = core; | 1171 | pmic_arb->wr_base = core; |
| 1030 | pa->rd_base = core; | 1172 | pmic_arb->rd_base = core; |
| 1031 | } else { | 1173 | } else { |
| 1032 | pa->core = core; | 1174 | pmic_arb->core = core; |
| 1033 | 1175 | ||
| 1034 | if (hw_ver < PMIC_ARB_VERSION_V3_MIN) | 1176 | if (hw_ver < PMIC_ARB_VERSION_V3_MIN) |
| 1035 | pa->ver_ops = &pmic_arb_v2; | 1177 | pmic_arb->ver_ops = &pmic_arb_v2; |
| 1178 | else if (hw_ver < PMIC_ARB_VERSION_V5_MIN) | ||
| 1179 | pmic_arb->ver_ops = &pmic_arb_v3; | ||
| 1036 | else | 1180 | else |
| 1037 | pa->ver_ops = &pmic_arb_v3; | 1181 | pmic_arb->ver_ops = &pmic_arb_v5; |
| 1038 | |||
| 1039 | /* the apid to ppid table starts at PMIC_ARB_REG_CHNL(0) */ | ||
| 1040 | pa->max_periph = (pa->core_size - PMIC_ARB_REG_CHNL(0)) / 4; | ||
| 1041 | 1182 | ||
| 1042 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, | 1183 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, |
| 1043 | "obsrvr"); | 1184 | "obsrvr"); |
| 1044 | pa->rd_base = devm_ioremap_resource(&ctrl->dev, res); | 1185 | pmic_arb->rd_base = devm_ioremap_resource(&ctrl->dev, res); |
| 1045 | if (IS_ERR(pa->rd_base)) { | 1186 | if (IS_ERR(pmic_arb->rd_base)) { |
| 1046 | err = PTR_ERR(pa->rd_base); | 1187 | err = PTR_ERR(pmic_arb->rd_base); |
| 1047 | goto err_put_ctrl; | 1188 | goto err_put_ctrl; |
| 1048 | } | 1189 | } |
| 1049 | 1190 | ||
| 1050 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, | 1191 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, |
| 1051 | "chnls"); | 1192 | "chnls"); |
| 1052 | pa->wr_base = devm_ioremap_resource(&ctrl->dev, res); | 1193 | pmic_arb->wr_base = devm_ioremap_resource(&ctrl->dev, res); |
| 1053 | if (IS_ERR(pa->wr_base)) { | 1194 | if (IS_ERR(pmic_arb->wr_base)) { |
| 1054 | err = PTR_ERR(pa->wr_base); | 1195 | err = PTR_ERR(pmic_arb->wr_base); |
| 1055 | goto err_put_ctrl; | 1196 | goto err_put_ctrl; |
| 1056 | } | 1197 | } |
| 1057 | } | 1198 | } |
| 1058 | 1199 | ||
| 1059 | dev_info(&ctrl->dev, "PMIC arbiter version %s (0x%x)\n", | 1200 | dev_info(&ctrl->dev, "PMIC arbiter version %s (0x%x)\n", |
| 1060 | pa->ver_ops->ver_str, hw_ver); | 1201 | pmic_arb->ver_ops->ver_str, hw_ver); |
| 1061 | 1202 | ||
| 1062 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intr"); | 1203 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intr"); |
| 1063 | pa->intr = devm_ioremap_resource(&ctrl->dev, res); | 1204 | pmic_arb->intr = devm_ioremap_resource(&ctrl->dev, res); |
| 1064 | if (IS_ERR(pa->intr)) { | 1205 | if (IS_ERR(pmic_arb->intr)) { |
| 1065 | err = PTR_ERR(pa->intr); | 1206 | err = PTR_ERR(pmic_arb->intr); |
| 1066 | goto err_put_ctrl; | 1207 | goto err_put_ctrl; |
| 1067 | } | 1208 | } |
| 1068 | 1209 | ||
| 1069 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cnfg"); | 1210 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cnfg"); |
| 1070 | pa->cnfg = devm_ioremap_resource(&ctrl->dev, res); | 1211 | pmic_arb->cnfg = devm_ioremap_resource(&ctrl->dev, res); |
| 1071 | if (IS_ERR(pa->cnfg)) { | 1212 | if (IS_ERR(pmic_arb->cnfg)) { |
| 1072 | err = PTR_ERR(pa->cnfg); | 1213 | err = PTR_ERR(pmic_arb->cnfg); |
| 1073 | goto err_put_ctrl; | 1214 | goto err_put_ctrl; |
| 1074 | } | 1215 | } |
| 1075 | 1216 | ||
| 1076 | pa->irq = platform_get_irq_byname(pdev, "periph_irq"); | 1217 | pmic_arb->irq = platform_get_irq_byname(pdev, "periph_irq"); |
| 1077 | if (pa->irq < 0) { | 1218 | if (pmic_arb->irq < 0) { |
| 1078 | err = pa->irq; | 1219 | err = pmic_arb->irq; |
| 1079 | goto err_put_ctrl; | 1220 | goto err_put_ctrl; |
| 1080 | } | 1221 | } |
| 1081 | 1222 | ||
| @@ -1092,7 +1233,7 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev) · 10 unmodified lines | |||
| 1092 | goto err_put_ctrl; | 1233 | goto err_put_ctrl; |
| 1093 | } | 1234 | } |
| 1094 | 1235 | ||
| 1095 | pa->channel = channel; | 1236 | pmic_arb->channel = channel; |
| 1096 | 1237 | ||
| 1097 | err = of_property_read_u32(pdev->dev.of_node, "qcom,ee", &ee); | 1238 | err = of_property_read_u32(pdev->dev.of_node, "qcom,ee", &ee); |
| 1098 | if (err) { | 1239 | if (err) { |
| @@ -1106,39 +1247,47 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev) · 7 unmodified lines | |||
| 1106 | goto err_put_ctrl; | 1247 | goto err_put_ctrl; |
| 1107 | } | 1248 | } |
| 1108 | 1249 | ||
| 1109 | pa->ee = ee; | 1250 | pmic_arb->ee = ee; |
| 1110 | 1251 | mapping_table = devm_kcalloc(&ctrl->dev, PMIC_ARB_MAX_PERIPHS, | |
| 1111 | pa->mapping_table = devm_kcalloc(&ctrl->dev, PMIC_ARB_MAX_PERIPHS - 1, | 1252 | sizeof(*mapping_table), GFP_KERNEL); |
| 1112 | sizeof(*pa->mapping_table), GFP_KERNEL); | 1253 | if (!mapping_table) { |
| 1113 | if (!pa->mapping_table) { | ||
| 1114 | err = -ENOMEM; | 1254 | err = -ENOMEM; |
| 1115 | goto err_put_ctrl; | 1255 | goto err_put_ctrl; |
| 1116 | } | 1256 | } |
| 1117 | 1257 | ||
| 1258 | pmic_arb->mapping_table = mapping_table; | ||
| 1118 | /* Initialize max_apid/min_apid to the opposite bounds, during | 1259 | /* Initialize max_apid/min_apid to the opposite bounds, during |
| 1119 | * the irq domain translation, we are sure to update these */ | 1260 | * the irq domain translation, we are sure to update these */ |
| 1120 | pa->max_apid = 0; | 1261 | pmic_arb->max_apid = 0; |
| 1121 | pa->min_apid = PMIC_ARB_MAX_PERIPHS - 1; | 1262 | pmic_arb->min_apid = PMIC_ARB_MAX_PERIPHS - 1; |
| 1122 | 1263 | ||
| 1123 | platform_set_drvdata(pdev, ctrl); | 1264 | platform_set_drvdata(pdev, ctrl); |
| 1124 | raw_spin_lock_init(&pa->lock); | 1265 | raw_spin_lock_init(&pmic_arb->lock); |
| 1125 | 1266 | ||
| 1126 | ctrl->cmd = pmic_arb_cmd; | 1267 | ctrl->cmd = pmic_arb_cmd; |
| 1127 | ctrl->read_cmd = pmic_arb_read_cmd; | 1268 | ctrl->read_cmd = pmic_arb_read_cmd; |
| 1128 | ctrl->write_cmd = pmic_arb_write_cmd; | 1269 | ctrl->write_cmd = pmic_arb_write_cmd; |
| 1129 | 1270 | ||
| 1271 | if (hw_ver >= PMIC_ARB_VERSION_V5_MIN) { | ||
| 1272 | err = pmic_arb_read_apid_map_v5(pmic_arb); | ||
| 1273 | if (err) { | ||
| 1274 | dev_err(&pdev->dev, "could not read APID->PPID mapping table, rc= %d\n", | ||
| 1275 | err); | ||
| 1276 | goto err_put_ctrl; | ||
| 1277 | } | ||
| 1278 | } | ||
| 1279 | |||
| 1130 | dev_dbg(&pdev->dev, "adding irq domain\n"); | 1280 | dev_dbg(&pdev->dev, "adding irq domain\n"); |
| 1131 | pa->domain = irq_domain_add_tree(pdev->dev.of_node, | 1281 | pmic_arb->domain = irq_domain_add_tree(pdev->dev.of_node, |
| 1132 | &pmic_arb_irq_domain_ops, pa); | 1282 | &pmic_arb_irq_domain_ops, pmic_arb); |
| 1133 | if (!pa->domain) { | 1283 | if (!pmic_arb->domain) { |
| 1134 | dev_err(&pdev->dev, "unable to create irq_domain\n"); | 1284 | dev_err(&pdev->dev, "unable to create irq_domain\n"); |
| 1135 | err = -ENOMEM; | 1285 | err = -ENOMEM; |
| 1136 | goto err_put_ctrl; | 1286 | goto err_put_ctrl; |
| 1137 | } | 1287 | } |
| 1138 | 1288 | ||
| 1139 | irq_set_chained_handler_and_data(pa->irq, pmic_arb_chained_irq, pa); | 1289 | irq_set_chained_handler_and_data(pmic_arb->irq, pmic_arb_chained_irq, |
| 1140 | enable_irq_wake(pa->irq); | 1290 | pmic_arb); |
| 1141 | |||
| 1142 | err = spmi_controller_add(ctrl); | 1291 | err = spmi_controller_add(ctrl); |
| 1143 | if (err) | 1292 | if (err) |
| 1144 | goto err_domain_remove; | 1293 | goto err_domain_remove; |
| @@ -1146,8 +1295,8 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev) · 1 unmodified line | |||
| 1146 | return 0; | 1295 | return 0; |
| 1147 | 1296 | ||
| 1148 | err_domain_remove: | 1297 | err_domain_remove: |
| 1149 | irq_set_chained_handler_and_data(pa->irq, NULL, NULL); | 1298 | irq_set_chained_handler_and_data(pmic_arb->irq, NULL, NULL); |
| 1150 | irq_domain_remove(pa->domain); | 1299 | irq_domain_remove(pmic_arb->domain); |
| 1151 | err_put_ctrl: | 1300 | err_put_ctrl: |
| 1152 | spmi_controller_put(ctrl); | 1301 | spmi_controller_put(ctrl); |
| 1153 | return err; | 1302 | return err; |
| @@ -1156,10 +1305,10 @@ err_put_ctrl: · 2 unmodified lines | |||
| 1156 | static int spmi_pmic_arb_remove(struct platform_device *pdev) | 1305 | static int spmi_pmic_arb_remove(struct platform_device *pdev) |
| 1157 | { | 1306 | { |
| 1158 | struct spmi_controller *ctrl = platform_get_drvdata(pdev); | 1307 | struct spmi_controller *ctrl = platform_get_drvdata(pdev); |
| 1159 | struct spmi_pmic_arb *pa = spmi_controller_get_drvdata(ctrl); | 1308 | struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl); |
| 1160 | spmi_controller_remove(ctrl); | 1309 | spmi_controller_remove(ctrl); |
| 1161 | irq_set_chained_handler_and_data(pa->irq, NULL, NULL); | 1310 | irq_set_chained_handler_and_data(pmic_arb->irq, NULL, NULL); |
| 1162 | irq_domain_remove(pa->domain); | 1311 | irq_domain_remove(pmic_arb->domain); |
| 1163 | spmi_controller_put(ctrl); | 1312 | spmi_controller_put(ctrl); |
| 1164 | return 0; | 1313 | return 0; |
| 1165 | } | 1314 | } |
| @@ -466,27 +466,25 @@ static void of_spmi_register_devices(struct spmi_controller *ctrl) · 465 unmodified lines | |||
| 466 | struct spmi_device *sdev; | 466 | struct spmi_device *sdev; |
| 467 | u32 reg[2]; | 467 | u32 reg[2]; |
| 468 | 468 | ||
| 469 | dev_dbg(&ctrl->dev, "adding child %s\n", node->full_name); | 469 | dev_dbg(&ctrl->dev, "adding child %pOF\n", node); |
| 470 | 470 | ||
| 471 | err = of_property_read_u32_array(node, "reg", reg, 2); | 471 | err = of_property_read_u32_array(node, "reg", reg, 2); |
| 472 | if (err) { | 472 | if (err) { |
| 473 | dev_err(&ctrl->dev, | 473 | dev_err(&ctrl->dev, |
| 474 | "node %s err (%d) does not have 'reg' property\n", | 474 | "node %pOF err (%d) does not have 'reg' property\n", |
| 475 | node->full_name, err); | 475 | node, err); |
| 476 | continue; | 476 | continue; |
| 477 | } | 477 | } |
| 478 | 478 | ||
| 479 | if (reg[1] != SPMI_USID) { | 479 | if (reg[1] != SPMI_USID) { |
| 480 | dev_err(&ctrl->dev, | 480 | dev_err(&ctrl->dev, |
| 481 | "node %s contains unsupported 'reg' entry\n", | 481 | "node %pOF contains unsupported 'reg' entry\n", |
| 482 | node->full_name); | 482 | node); |
| 483 | continue; | 483 | continue; |
| 484 | } | 484 | } |
| 485 | 485 | ||
| 486 | if (reg[0] >= SPMI_MAX_SLAVE_ID) { | 486 | if (reg[0] >= SPMI_MAX_SLAVE_ID) { |
| 487 | dev_err(&ctrl->dev, | 487 | dev_err(&ctrl->dev, "invalid usid on node %pOF\n", node); |
| 488 | "invalid usid on node %s\n", | ||
| 489 | node->full_name); | ||
| 490 | continue; | 488 | continue; |
| 491 | } | 489 | } |
| 492 | 490 | ||
| @@ -804,7 +804,7 @@ struct tb_cfg_result tb_cfg_reset(struct tb_ctl *ctl, u64 route, · 803 unmodified lines | |||
| 804 | req->request_type = TB_CFG_PKG_RESET; | 804 | req->request_type = TB_CFG_PKG_RESET; |
| 805 | req->response = &reply; | 805 | req->response = &reply; |
| 806 | req->response_size = sizeof(reply); | 806 | req->response_size = sizeof(reply); |
| 807 | req->response_type = sizeof(TB_CFG_PKG_RESET); | 807 | req->response_type = TB_CFG_PKG_RESET; |
| 808 | 808 | ||
| 809 | res = tb_cfg_request_sync(ctl, req, timeout_msec); | 809 | res = tb_cfg_request_sync(ctl, req, timeout_msec); |
| 810 | 810 | ||
| @@ -807,11 +807,11 @@ static ssize_t key_store(struct device *dev, struct device_attribute *attr, · 806 unmodified lines | |||
| 807 | struct tb_switch *sw = tb_to_switch(dev); | 807 | struct tb_switch *sw = tb_to_switch(dev); |
| 808 | u8 key[TB_SWITCH_KEY_SIZE]; | 808 | u8 key[TB_SWITCH_KEY_SIZE]; |
| 809 | ssize_t ret = count; | 809 | ssize_t ret = count; |
| 810 | bool clear = false; | ||
| 810 | 811 | ||
| 811 | if (count < 64) | 812 | if (!strcmp(buf, "\n")) |
| 812 | return -EINVAL; | 813 | clear = true; |
| 813 | 814 | else if (hex2bin(key, buf, sizeof(key))) | |
| 814 | if (hex2bin(key, buf, sizeof(key))) | ||
| 815 | return -EINVAL; | 815 | return -EINVAL; |
| 816 | 816 | ||
| 817 | if (mutex_lock_interruptible(&switch_lock)) | 817 | if (mutex_lock_interruptible(&switch_lock)) |
| @@ -821,15 +821,19 @@ static ssize_t key_store(struct device *dev, struct device_attribute *attr, · 3 unmodified lines | |||
| 821 | ret = -EBUSY; | 821 | ret = -EBUSY; |
| 822 | } else { | 822 | } else { |
| 823 | kfree(sw->key); | 823 | kfree(sw->key); |
| 824 | sw->key = kmemdup(key, sizeof(key), GFP_KERNEL); | 824 | if (clear) { |
| 825 | if (!sw->key) | 825 | sw->key = NULL; |
| 826 | ret = -ENOMEM; | 826 | } else { |
| 827 | sw->key = kmemdup(key, sizeof(key), GFP_KERNEL); | ||
| 828 | if (!sw->key) | ||
| 829 | ret = -ENOMEM; | ||
| 830 | } | ||
| 827 | } | 831 | } |
| 828 | 832 | ||
| 829 | mutex_unlock(&switch_lock); | 833 | mutex_unlock(&switch_lock); |
| 830 | return ret; | 834 | return ret; |
| 831 | } | 835 | } |
| 832 | static DEVICE_ATTR_RW(key); | 836 | static DEVICE_ATTR(key, 0600, key_show, key_store); |
| 833 | 837 | ||
| 834 | static ssize_t nvm_authenticate_show(struct device *dev, | 838 | static ssize_t nvm_authenticate_show(struct device *dev, |
| 835 | struct device_attribute *attr, char *buf) | 839 | struct device_attribute *attr, char *buf) |
| @@ -184,7 +184,7 @@ static int udc_plat_probe(struct platform_device *pdev) · 183 unmodified lines | |||
| 184 | goto exit_phy; | 184 | goto exit_phy; |
| 185 | } | 185 | } |
| 186 | 186 | ||
| 187 | ret = extcon_get_cable_state_(udc->edev, EXTCON_USB); | 187 | ret = extcon_get_state(udc->edev, EXTCON_USB); |
| 188 | if (ret < 0) { | 188 | if (ret < 0) { |
| 189 | dev_err(dev, "Can't get cable state\n"); | 189 | dev_err(dev, "Can't get cable state\n"); |
| 190 | goto exit_extcon; | 190 | goto exit_extcon; |
| @@ -273,7 +273,7 @@ static int udc_plat_suspend(struct device *dev) · 82 unmodified lines | |||
| 273 | udc = dev_get_drvdata(dev); | 273 | udc = dev_get_drvdata(dev); |
| 274 | stop_udc(udc); | 274 | stop_udc(udc); |
| 275 | 275 | ||
| 276 | if (extcon_get_cable_state_(udc->edev, EXTCON_USB) > 0) { | 276 | if (extcon_get_state(udc->edev, EXTCON_USB) > 0) { |
| 277 | dev_dbg(udc->dev, "device -> idle\n"); | 277 | dev_dbg(udc->dev, "device -> idle\n"); |
| 278 | stop_udc(udc); | 278 | stop_udc(udc); |
| 279 | } | 279 | } |
| @@ -303,7 +303,7 @@ static int udc_plat_resume(struct device *dev) · 23 unmodified lines | |||
| 303 | return ret; | 303 | return ret; |
| 304 | } | 304 | } |
| 305 | 305 | ||
| 306 | if (extcon_get_cable_state_(udc->edev, EXTCON_USB) > 0) { | 306 | if (extcon_get_state(udc->edev, EXTCON_USB) > 0) { |
| 307 | dev_dbg(udc->dev, "idle -> device\n"); | 307 | dev_dbg(udc->dev, "idle -> device\n"); |
| 308 | start_udc(udc); | 308 | start_udc(udc); |
| 309 | } | 309 | } |
| @@ -95,7 +95,8 @@ static struct { · 94 unmodified lines | |||
| 95 | 95 | ||
| 96 | struct ds1wm_data { | 96 | struct ds1wm_data { |
| 97 | void __iomem *map; | 97 | void __iomem *map; |
| 98 | int bus_shift; /* # of shifts to calc register offsets */ | 98 | unsigned int bus_shift; /* # of shifts to calc register offsets */ |
| 99 | bool is_hw_big_endian; | ||
| 99 | struct platform_device *pdev; | 100 | struct platform_device *pdev; |
| 100 | const struct mfd_cell *cell; | 101 | const struct mfd_cell *cell; |
| 101 | int irq; | 102 | int irq; |
| @@ -115,12 +116,65 @@ struct ds1wm_data { · 13 unmodified lines | |||
| 115 | static inline void ds1wm_write_register(struct ds1wm_data *ds1wm_data, u32 reg, | 116 | static inline void ds1wm_write_register(struct ds1wm_data *ds1wm_data, u32 reg, |
| 116 | u8 val) | 117 | u8 val) |
| 117 | { | 118 | { |
| 118 | __raw_writeb(val, ds1wm_data->map + (reg << ds1wm_data->bus_shift)); | 119 | if (ds1wm_data->is_hw_big_endian) { |
| 120 | switch (ds1wm_data->bus_shift) { | ||
| 121 | case 0: | ||
| 122 | iowrite8(val, ds1wm_data->map + (reg << 0)); | ||
| 123 | break; | ||
| 124 | case 1: | ||
| 125 | iowrite16be((u16)val, ds1wm_data->map + (reg << 1)); | ||
| 126 | break; | ||
| 127 | case 2: | ||
| 128 | iowrite32be((u32)val, ds1wm_data->map + (reg << 2)); | ||
| 129 | break; | ||
| 130 | } | ||
| 131 | } else { | ||
| 132 | switch (ds1wm_data->bus_shift) { | ||
| 133 | case 0: | ||
| 134 | iowrite8(val, ds1wm_data->map + (reg << 0)); | ||
| 135 | break; | ||
| 136 | case 1: | ||
| 137 | iowrite16((u16)val, ds1wm_data->map + (reg << 1)); | ||
| 138 | break; | ||
| 139 | case 2: | ||
| 140 | iowrite32((u32)val, ds1wm_data->map + (reg << 2)); | ||
| 141 | break; | ||
| 142 | } | ||
| 143 | } | ||
| 119 | } | 144 | } |
| 120 | 145 | ||
| 121 | static inline u8 ds1wm_read_register(struct ds1wm_data *ds1wm_data, u32 reg) | 146 | static inline u8 ds1wm_read_register(struct ds1wm_data *ds1wm_data, u32 reg) |
| 122 | { | 147 | { |
| 123 | return __raw_readb(ds1wm_data->map + (reg << ds1wm_data->bus_shift)); | 148 | u32 val = 0; |
| 149 | |||
| 150 | if (ds1wm_data->is_hw_big_endian) { | ||
| 151 | switch (ds1wm_data->bus_shift) { | ||
| 152 | case 0: | ||
| 153 | val = ioread8(ds1wm_data->map + (reg << 0)); | ||
| 154 | break; | ||
| 155 | case 1: | ||
| 156 | val = ioread16be(ds1wm_data->map + (reg << 1)); | ||
| 157 | break; | ||
| 158 | case 2: | ||
| 159 | val = ioread32be(ds1wm_data->map + (reg << 2)); | ||
| 160 | break; | ||
| 161 | } | ||
| 162 | } else { | ||
| 163 | switch (ds1wm_data->bus_shift) { | ||
| 164 | case 0: | ||
| 165 | val = ioread8(ds1wm_data->map + (reg << 0)); | ||
| 166 | break; | ||
| 167 | case 1: | ||
| 168 | val = ioread16(ds1wm_data->map + (reg << 1)); | ||
| 169 | break; | ||
| 170 | case 2: | ||
| 171 | val = ioread32(ds1wm_data->map + (reg << 2)); | ||
| 172 | break; | ||
| 173 | } | ||
| 174 | } | ||
| 175 | dev_dbg(&ds1wm_data->pdev->dev, | ||
| 176 | "ds1wm_read_register reg: %d, 32 bit val:%x\n", reg, val); | ||
| 177 | return (u8)val; | ||
| 124 | } | 178 | } |
| 125 | 179 | ||
| 126 | 180 | ||
| @@ -455,6 +509,7 @@ static int ds1wm_probe(struct platform_device *pdev) · 328 unmodified lines | |||
| 455 | struct ds1wm_driver_data *plat; | 509 | struct ds1wm_driver_data *plat; |
| 456 | struct resource *res; | 510 | struct resource *res; |
| 457 | int ret; | 511 | int ret; |
| 512 | u8 inten; | ||
| 458 | 513 | ||
| 459 | if (!pdev) | 514 | if (!pdev) |
| 460 | return -ENODEV; | 515 | return -ENODEV; |
| @@ -473,9 +528,6 @@ static int ds1wm_probe(struct platform_device *pdev) · 12 unmodified lines | |||
| 473 | if (!ds1wm_data->map) | 528 | if (!ds1wm_data->map) |
| 474 | return -ENOMEM; | 529 | return -ENOMEM; |
| 475 | 530 | ||
| 476 | /* calculate bus shift from mem resource */ | ||
| 477 | ds1wm_data->bus_shift = resource_size(res) >> 3; | ||
| 478 | |||
| 479 | ds1wm_data->pdev = pdev; | 531 | ds1wm_data->pdev = pdev; |
| 480 | ds1wm_data->cell = mfd_get_cell(pdev); | 532 | ds1wm_data->cell = mfd_get_cell(pdev); |
| 481 | if (!ds1wm_data->cell) | 533 | if (!ds1wm_data->cell) |
| @@ -484,6 +536,26 @@ static int ds1wm_probe(struct platform_device *pdev) · 2 unmodified lines | |||
| 484 | if (!plat) | 536 | if (!plat) |
| 485 | return -ENODEV; | 537 | return -ENODEV; |
| 486 | 538 | ||
| 539 | /* how many bits to shift register number to get register offset */ | ||
| 540 | if (plat->bus_shift > 2) { | ||
| 541 | dev_err(&ds1wm_data->pdev->dev, | ||
| 542 | "illegal bus shift %d, not written", | ||
| 543 | ds1wm_data->bus_shift); | ||
| 544 | return -EINVAL; | ||
| 545 | } | ||
| 546 | |||
| 547 | ds1wm_data->bus_shift = plat->bus_shift; | ||
| 548 | /* make sure resource has space for 8 registers */ | ||
| 549 | if ((8 << ds1wm_data->bus_shift) > resource_size(res)) { | ||
| 550 | dev_err(&ds1wm_data->pdev->dev, | ||
| 551 | "memory resource size %d to small, should be %d\n", | ||
| 552 | (int)resource_size(res), | ||
| 553 | 8 << ds1wm_data->bus_shift); | ||
| 554 | return -EINVAL; | ||
| 555 | } | ||
| 556 | |||
| 557 | ds1wm_data->is_hw_big_endian = plat->is_hw_big_endian; | ||
| 558 | |||
| 487 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | 559 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
| 488 | if (!res) | 560 | if (!res) |
| 489 | return -ENXIO; | 561 | return -ENXIO; |
| @@ -491,15 +563,30 @@ static int ds1wm_probe(struct platform_device *pdev) · 1 unmodified line | |||
| 491 | ds1wm_data->int_en_reg_none = (plat->active_high ? DS1WM_INTEN_IAS : 0); | 563 | ds1wm_data->int_en_reg_none = (plat->active_high ? DS1WM_INTEN_IAS : 0); |
| 492 | ds1wm_data->reset_recover_delay = plat->reset_recover_delay; | 564 | ds1wm_data->reset_recover_delay = plat->reset_recover_delay; |
| 493 | 565 | ||
| 566 | /* Mask interrupts, set IAS before claiming interrupt */ | ||
| 567 | inten = ds1wm_read_register(ds1wm_data, DS1WM_INT_EN); | ||
| 568 | ds1wm_write_register(ds1wm_data, | ||
| 569 | DS1WM_INT_EN, ds1wm_data->int_en_reg_none); | ||
| 570 | |||
| 494 | if (res->flags & IORESOURCE_IRQ_HIGHEDGE) | 571 | if (res->flags & IORESOURCE_IRQ_HIGHEDGE) |
| 495 | irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_EDGE_RISING); | 572 | irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_EDGE_RISING); |
| 496 | if (res->flags & IORESOURCE_IRQ_LOWEDGE) | 573 | if (res->flags & IORESOURCE_IRQ_LOWEDGE) |
| 497 | irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_EDGE_FALLING); | 574 | irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_EDGE_FALLING); |
| 575 | if (res->flags & IORESOURCE_IRQ_HIGHLEVEL) | ||
| 576 | irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_LEVEL_HIGH); | ||
| 577 | if (res->flags & IORESOURCE_IRQ_LOWLEVEL) | ||
| 578 | irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_LEVEL_LOW); | ||
| 498 | 579 | ||
| 499 | ret = devm_request_irq(&pdev->dev, ds1wm_data->irq, ds1wm_isr, | 580 | ret = devm_request_irq(&pdev->dev, ds1wm_data->irq, ds1wm_isr, |
| 500 | IRQF_SHARED, "ds1wm", ds1wm_data); | 581 | IRQF_SHARED, "ds1wm", ds1wm_data); |
| 501 | if (ret) | 582 | if (ret) { |
| 583 | dev_err(&ds1wm_data->pdev->dev, | ||
| 584 | "devm_request_irq %d failed with errno %d\n", | ||
| 585 | ds1wm_data->irq, | ||
| 586 | ret); | ||
| 587 | |||
| 502 | return ret; | 588 | return ret; |
| 589 | } | ||
| 503 | 590 | ||
| 504 | ds1wm_up(ds1wm_data); | 591 | ds1wm_up(ds1wm_data); |
| 505 | 592 | ||
| @@ -509,6 +596,13 @@ static int ds1wm_probe(struct platform_device *pdev) · 3 unmodified lines | |||
| 509 | if (ret) | 596 | if (ret) |
| 510 | goto err; | 597 | goto err; |
| 511 | 598 | ||
| 599 | dev_dbg(&ds1wm_data->pdev->dev, | ||
| 600 | "ds1wm: probe successful, IAS: %d, rec.delay: %d, clockrate: %d, bus-shift: %d, is Hw Big Endian: %d\n", | ||
| 601 | plat->active_high, | ||
| 602 | plat->reset_recover_delay, | ||
| 603 | plat->clock_rate, | ||
| 604 | ds1wm_data->bus_shift, | ||
| 605 | ds1wm_data->is_hw_big_endian); | ||
| 512 | return 0; | 606 | return 0; |
| 513 | 607 | ||
| 514 | err: | 608 | err: |
| @@ -70,6 +70,8 @@ MODULE_PARM_DESC(active_pullup, "Active pullup (apply to all buses): " \ · 69 unmodified lines | |||
| 70 | #define DS2482_REG_CFG_PPM 0x02 /* presence pulse masking */ | 70 | #define DS2482_REG_CFG_PPM 0x02 /* presence pulse masking */ |
| 71 | #define DS2482_REG_CFG_APU 0x01 /* active pull-up */ | 71 | #define DS2482_REG_CFG_APU 0x01 /* active pull-up */ |
| 72 | 72 | ||
| 73 | /* extra configurations - e.g. 1WS */ | ||
| 74 | int extra_config; | ||
| 73 | 75 | ||
| 74 | /** | 76 | /** |
| 75 | * Write and verify codes for the CHANNEL_SELECT command (DS2482-800 only). | 77 | * Write and verify codes for the CHANNEL_SELECT command (DS2482-800 only). |
| @@ -403,7 +405,7 @@ static u8 ds2482_w1_reset_bus(void *data) · 327 unmodified lines | |||
| 403 | /* If the chip did reset since detect, re-config it */ | 405 | /* If the chip did reset since detect, re-config it */ |
| 404 | if (err & DS2482_REG_STS_RST) | 406 | if (err & DS2482_REG_STS_RST) |
| 405 | ds2482_send_cmd_data(pdev, DS2482_CMD_WRITE_CONFIG, | 407 | ds2482_send_cmd_data(pdev, DS2482_CMD_WRITE_CONFIG, |
| 406 | ds2482_calculate_config(0x00)); | 408 | ds2482_calculate_config(extra_config)); |
| 407 | } | 409 | } |
| 408 | 410 | ||
| 409 | mutex_unlock(&pdev->access_lock); | 411 | mutex_unlock(&pdev->access_lock); |
| @@ -429,8 +431,7 @@ static u8 ds2482_w1_set_pullup(void *data, int delay) · 19 unmodified lines | |||
| 429 | ds2482_wait_1wire_idle(pdev); | 431 | ds2482_wait_1wire_idle(pdev); |
| 430 | /* note: it seems like both SPU and APU have to be set! */ | 432 | /* note: it seems like both SPU and APU have to be set! */ |
| 431 | retval = ds2482_send_cmd_data(pdev, DS2482_CMD_WRITE_CONFIG, | 433 | retval = ds2482_send_cmd_data(pdev, DS2482_CMD_WRITE_CONFIG, |
| 432 | ds2482_calculate_config(DS2482_REG_CFG_SPU | | 434 | ds2482_calculate_config(extra_config|DS2482_REG_CFG_SPU|DS2482_REG_CFG_APU)); |
| 433 | DS2482_REG_CFG_APU)); | ||
| 434 | ds2482_wait_1wire_idle(pdev); | 435 | ds2482_wait_1wire_idle(pdev); |
| 435 | } | 436 | } |
| 436 | 437 | ||
| @@ -483,7 +484,7 @@ static int ds2482_probe(struct i2c_client *client, · 46 unmodified lines | |||
| 483 | 484 | ||
| 484 | /* Set all config items to 0 (off) */ | 485 | /* Set all config items to 0 (off) */ |
| 485 | ds2482_send_cmd_data(data, DS2482_CMD_WRITE_CONFIG, | 486 | ds2482_send_cmd_data(data, DS2482_CMD_WRITE_CONFIG, |
| 486 | ds2482_calculate_config(0x00)); | 487 | ds2482_calculate_config(extra_config)); |
| 487 | 488 | ||
| 488 | mutex_init(&data->access_lock); | 489 | mutex_init(&data->access_lock); |
| 489 | 490 | ||
| @@ -558,4 +559,7 @@ module_i2c_driver(ds2482_driver); · 68 unmodified lines | |||
| 558 | 559 | ||
| 559 | MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>"); | 560 | MODULE_AUTHOR("Ben Gardner <bgardner@wabtec.com>"); |
| 560 | MODULE_DESCRIPTION("DS2482 driver"); | 561 | MODULE_DESCRIPTION("DS2482 driver"); |
| 562 | module_param(extra_config, int, S_IRUGO | S_IWUSR); | ||
| 563 | MODULE_PARM_DESC(extra_config, "Extra Configuration settings 1=APU,2=PPM,3=SPU,8=1WS"); | ||
| 564 | |||
| 561 | MODULE_LICENSE("GPL"); | 565 | MODULE_LICENSE("GPL"); |
| @@ -1088,7 +1088,7 @@ static void ds_disconnect(struct usb_interface *intf) · 1087 unmodified lines | |||
| 1088 | kfree(dev); | 1088 | kfree(dev); |
| 1089 | } | 1089 | } |
| 1090 | 1090 | ||
| 1091 | static struct usb_device_id ds_id_table [] = { | 1091 | static const struct usb_device_id ds_id_table[] = { |
| 1092 | { USB_DEVICE(0x04fa, 0x2490) }, | 1092 | { USB_DEVICE(0x04fa, 0x2490) }, |
| 1093 | { }, | 1093 | { }, |
| 1094 | }; | 1094 | }; |
| @@ -65,6 +65,14 @@ config W1_SLAVE_DS2423 · 64 unmodified lines | |||
| 65 | Say Y here if you want to use a 1-wire | 65 | Say Y here if you want to use a 1-wire |
| 66 | counter family device (DS2423). | 66 | counter family device (DS2423). |
| 67 | 67 | ||
| 68 | config W1_SLAVE_DS2805 | ||
| 69 | tristate "112-byte EEPROM support (DS28E05)" | ||
| 70 | help | ||
| 71 | Say Y here if you want to use a 1-wire | ||
| 72 | is a 112-byte user-programmable EEPROM is | ||
| 73 | organized as 7 pages of 16 bytes each with 64bit | ||
| 74 | unique number. Requires OverDrive Speed to talk to. | ||
| 75 | |||
| 68 | config W1_SLAVE_DS2431 | 76 | config W1_SLAVE_DS2431 |
| 69 | tristate "1kb EEPROM family support (DS2431)" | 77 | tristate "1kb EEPROM family support (DS2431)" |
| 70 | help | 78 | help |
| @@ -10,6 +10,7 @@ obj-$(CONFIG_W1_SLAVE_DS2413) += w1_ds2413.o · 9 unmodified lines | |||
| 10 | obj-$(CONFIG_W1_SLAVE_DS2406) += w1_ds2406.o | 10 | obj-$(CONFIG_W1_SLAVE_DS2406) += w1_ds2406.o |
| 11 | obj-$(CONFIG_W1_SLAVE_DS2423) += w1_ds2423.o | 11 | obj-$(CONFIG_W1_SLAVE_DS2423) += w1_ds2423.o |
| 12 | obj-$(CONFIG_W1_SLAVE_DS2431) += w1_ds2431.o | 12 | obj-$(CONFIG_W1_SLAVE_DS2431) += w1_ds2431.o |
| 13 | obj-$(CONFIG_W1_SLAVE_DS2805) += w1_ds2805.o | ||
| 13 | obj-$(CONFIG_W1_SLAVE_DS2433) += w1_ds2433.o | 14 | obj-$(CONFIG_W1_SLAVE_DS2433) += w1_ds2433.o |
| 14 | obj-$(CONFIG_W1_SLAVE_DS2438) += w1_ds2438.o | 15 | obj-$(CONFIG_W1_SLAVE_DS2438) += w1_ds2438.o |
| 15 | obj-$(CONFIG_W1_SLAVE_DS2760) += w1_ds2760.o | 16 | obj-$(CONFIG_W1_SLAVE_DS2760) += w1_ds2760.o |
| @@ -51,7 +51,7 @@ · 50 unmodified lines | |||
| 51 | #define DS2438_CURRENT_MSB 0x06 | 51 | #define DS2438_CURRENT_MSB 0x06 |
| 52 | #define DS2438_THRESHOLD 0x07 | 52 | #define DS2438_THRESHOLD 0x07 |
| 53 | 53 | ||
| 54 | int w1_ds2438_get_page(struct w1_slave *sl, int pageno, u8 *buf) | 54 | static int w1_ds2438_get_page(struct w1_slave *sl, int pageno, u8 *buf) |
| 55 | { | 55 | { |
| 56 | unsigned int retries = W1_DS2438_RETRIES; | 56 | unsigned int retries = W1_DS2438_RETRIES; |
| 57 | u8 w1_buf[2]; | 57 | u8 w1_buf[2]; |
| @@ -85,7 +85,7 @@ int w1_ds2438_get_page(struct w1_slave *sl, int pageno, u8 *buf) · 27 unmodified lines | |||
| 85 | return -1; | 85 | return -1; |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | int w1_ds2438_get_temperature(struct w1_slave *sl, int16_t *temperature) | 88 | static int w1_ds2438_get_temperature(struct w1_slave *sl, int16_t *temperature) |
| 89 | { | 89 | { |
| 90 | unsigned int retries = W1_DS2438_RETRIES; | 90 | unsigned int retries = W1_DS2438_RETRIES; |
| 91 | u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/]; | 91 | u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/]; |
| @@ -127,7 +127,7 @@ post_unlock: · 35 unmodified lines | |||
| 127 | return ret; | 127 | return ret; |
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | int w1_ds2438_change_config_bit(struct w1_slave *sl, u8 mask, u8 value) | 130 | static int w1_ds2438_change_config_bit(struct w1_slave *sl, u8 mask, u8 value) |
| 131 | { | 131 | { |
| 132 | unsigned int retries = W1_DS2438_RETRIES; | 132 | unsigned int retries = W1_DS2438_RETRIES; |
| 133 | u8 w1_buf[3]; | 133 | u8 w1_buf[3]; |
| @@ -186,7 +186,8 @@ int w1_ds2438_change_config_bit(struct w1_slave *sl, u8 mask, u8 value) · 52 unmodified lines | |||
| 186 | return -1; | 186 | return -1; |
| 187 | } | 187 | } |
| 188 | 188 | ||
| 189 | uint16_t w1_ds2438_get_voltage(struct w1_slave *sl, int adc_input, uint16_t *voltage) | 189 | static uint16_t w1_ds2438_get_voltage(struct w1_slave *sl, |
| 190 | int adc_input, uint16_t *voltage) | ||
| 190 | { | 191 | { |
| 191 | unsigned int retries = W1_DS2438_RETRIES; | 192 | unsigned int retries = W1_DS2438_RETRIES; |
| 192 | u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/]; | 193 | u8 w1_buf[DS2438_PAGE_SIZE + 1 /*for CRC*/]; |
| @@ -0,0 +1,313 @@ | |||
| 1 | /* | ||
| 2 | * w1_ds2805 - w1 family 0d (DS28E05) driver | ||
| 3 | * | ||
| 4 | * Copyright (c) 2016 Andrew Worsley amworsley@gmail.com | ||
| 5 | * | ||
| 6 | * This source code is licensed under the GNU General Public License, | ||
| 7 | * Version 2. See the file COPYING for more details. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <linux/kernel.h> | ||
| 11 | #include <linux/module.h> | ||
| 12 | #include <linux/moduleparam.h> | ||
| 13 | #include <linux/device.h> | ||
| 14 | #include <linux/types.h> | ||
| 15 | #include <linux/delay.h> | ||
| 16 | |||
| 17 | #include <linux/w1.h> | ||
| 18 | |||
| 19 | #define W1_EEPROM_DS2805 0x0D | ||
| 20 | |||
| 21 | #define W1_F0D_EEPROM_SIZE 128 | ||
| 22 | #define W1_F0D_PAGE_BITS 3 | ||
| 23 | #define W1_F0D_PAGE_SIZE (1<<W1_F0D_PAGE_BITS) | ||
| 24 | #define W1_F0D_PAGE_MASK 0x0F | ||
| 25 | |||
| 26 | #define W1_F0D_SCRATCH_BITS 1 | ||
| 27 | #define W1_F0D_SCRATCH_SIZE (1<<W1_F0D_SCRATCH_BITS) | ||
| 28 | #define W1_F0D_SCRATCH_MASK (W1_F0D_SCRATCH_SIZE-1) | ||
| 29 | |||
| 30 | #define W1_F0D_READ_EEPROM 0xF0 | ||
| 31 | #define W1_F0D_WRITE_EEPROM 0x55 | ||
| 32 | #define W1_F0D_RELEASE 0xFF | ||
| 33 | |||
| 34 | #define W1_F0D_CS_OK 0xAA /* Chip Status Ok */ | ||
| 35 | |||
| 36 | #define W1_F0D_TPROG_MS 16 | ||
| 37 | |||
| 38 | #define W1_F0D_READ_RETRIES 10 | ||
| 39 | #define W1_F0D_READ_MAXLEN W1_F0D_EEPROM_SIZE | ||
| 40 | |||
| 41 | /* | ||
| 42 | * Check the file size bounds and adjusts count as needed. | ||
| 43 | * This would not be needed if the file size didn't reset to 0 after a write. | ||
| 44 | */ | ||
| 45 | static inline size_t w1_f0d_fix_count(loff_t off, size_t count, size_t size) | ||
| 46 | { | ||
| 47 | if (off > size) | ||
| 48 | return 0; | ||
| 49 | |||
| 50 | if ((off + count) > size) | ||
| 51 | return size - off; | ||
| 52 | |||
| 53 | return count; | ||
| 54 | } | ||
| 55 | |||
| 56 | /* | ||
| 57 | * Read a block from W1 ROM two times and compares the results. | ||
| 58 | * If they are equal they are returned, otherwise the read | ||
| 59 | * is repeated W1_F0D_READ_RETRIES times. | ||
| 60 | * | ||
| 61 | * count must not exceed W1_F0D_READ_MAXLEN. | ||
| 62 | */ | ||
| 63 | static int w1_f0d_readblock(struct w1_slave *sl, int off, int count, char *buf) | ||
| 64 | { | ||
| 65 | u8 wrbuf[3]; | ||
| 66 | u8 cmp[W1_F0D_READ_MAXLEN]; | ||
| 67 | int tries = W1_F0D_READ_RETRIES; | ||
| 68 | |||
| 69 | do { | ||
| 70 | wrbuf[0] = W1_F0D_READ_EEPROM; | ||
| 71 | wrbuf[1] = off & 0x7f; | ||
| 72 | wrbuf[2] = 0; | ||
| 73 | |||
| 74 | if (w1_reset_select_slave(sl)) | ||
| 75 | return -1; | ||
| 76 | |||
| 77 | w1_write_block(sl->master, wrbuf, sizeof(wrbuf)); | ||
| 78 | w1_read_block(sl->master, buf, count); | ||
| 79 | |||
| 80 | if (w1_reset_select_slave(sl)) | ||
| 81 | return -1; | ||
| 82 | |||
| 83 | w1_write_block(sl->master, wrbuf, sizeof(wrbuf)); | ||
| 84 | w1_read_block(sl->master, cmp, count); | ||
| 85 | |||
| 86 | if (!memcmp(cmp, buf, count)) | ||
| 87 | return 0; | ||
| 88 | } while (--tries); | ||
| 89 | |||
| 90 | dev_err(&sl->dev, "proof reading failed %d times\n", | ||
| 91 | W1_F0D_READ_RETRIES); | ||
| 92 | |||
| 93 | return -1; | ||
| 94 | } | ||
| 95 | |||
| 96 | static ssize_t w1_f0d_read_bin(struct file *filp, struct kobject *kobj, | ||
| 97 | struct bin_attribute *bin_attr, | ||
| 98 | char *buf, loff_t off, size_t count) | ||
| 99 | { | ||
| 100 | struct w1_slave *sl = kobj_to_w1_slave(kobj); | ||
| 101 | int todo = count; | ||
| 102 | |||
| 103 | count = w1_f0d_fix_count(off, count, W1_F0D_EEPROM_SIZE); | ||
| 104 | if (count == 0) | ||
| 105 | return 0; | ||
| 106 | |||
| 107 | mutex_lock(&sl->master->mutex); | ||
| 108 | |||
| 109 | /* read directly from the EEPROM in chunks of W1_F0D_READ_MAXLEN */ | ||
| 110 | while (todo > 0) { | ||
| 111 | int block_read; | ||
| 112 | |||
| 113 | if (todo >= W1_F0D_READ_MAXLEN) | ||
| 114 | block_read = W1_F0D_READ_MAXLEN; | ||
| 115 | else | ||
| 116 | block_read = todo; | ||
| 117 | |||
| 118 | if (w1_f0d_readblock(sl, off, block_read, buf) < 0) { | ||
| 119 | count = -EIO; | ||
| 120 | break; | ||
| 121 | } | ||
| 122 | |||
| 123 | todo -= W1_F0D_READ_MAXLEN; | ||
| 124 | buf += W1_F0D_READ_MAXLEN; | ||
| 125 | off += W1_F0D_READ_MAXLEN; | ||
| 126 | } | ||
| 127 | |||
| 128 | mutex_unlock(&sl->master->mutex); | ||
| 129 | |||
| 130 | return count; | ||
| 131 | } | ||
| 132 | |||
| 133 | /* | ||
| 134 | * Writes to the scratchpad and reads it back for verification. | ||
| 135 | * Then copies the scratchpad to EEPROM. | ||
| 136 | * The data must be aligned at W1_F0D_SCRATCH_SIZE bytes and | ||
| 137 | * must be W1_F0D_SCRATCH_SIZE bytes long. | ||
| 138 | * The master must be locked. | ||
| 139 | * | ||
| 140 | * @param sl The slave structure | ||
| 141 | * @param addr Address for the write | ||
| 142 | * @param len length must be <= (W1_F0D_PAGE_SIZE - (addr & W1_F0D_PAGE_MASK)) | ||
| 143 | * @param data The data to write | ||
| 144 | * @return 0=Success -1=failure | ||
| 145 | */ | ||
| 146 | static int w1_f0d_write(struct w1_slave *sl, int addr, int len, const u8 *data) | ||
| 147 | { | ||
| 148 | int tries = W1_F0D_READ_RETRIES; | ||
| 149 | u8 wrbuf[3]; | ||
| 150 | u8 rdbuf[W1_F0D_SCRATCH_SIZE]; | ||
| 151 | u8 cs; | ||
| 152 | |||
| 153 | if ((addr & 1) || (len != 2)) { | ||
| 154 | dev_err(&sl->dev, "%s: bad addr/len - addr=%#x len=%d\n", | ||
| 155 | __func__, addr, len); | ||
| 156 | return -1; | ||
| 157 | } | ||
| 158 | |||
| 159 | retry: | ||
| 160 | |||
| 161 | /* Write the data to the scratchpad */ | ||
| 162 | if (w1_reset_select_slave(sl)) | ||
| 163 | return -1; | ||
| 164 | |||
| 165 | wrbuf[0] = W1_F0D_WRITE_EEPROM; | ||
| 166 | wrbuf[1] = addr & 0xff; | ||
| 167 | wrbuf[2] = 0xff; /* ?? from Example */ | ||
| 168 | |||
| 169 | w1_write_block(sl->master, wrbuf, sizeof(wrbuf)); | ||
| 170 | w1_write_block(sl->master, data, len); | ||
| 171 | |||
| 172 | w1_read_block(sl->master, rdbuf, sizeof(rdbuf)); | ||
| 173 | /* Compare what was read against the data written */ | ||
| 174 | if ((rdbuf[0] != data[0]) || (rdbuf[1] != data[1])) { | ||
| 175 | |||
| 176 | if (--tries) | ||
| 177 | goto retry; | ||
| 178 | |||
| 179 | dev_err(&sl->dev, | ||
| 180 | "could not write to eeprom, scratchpad compare failed %d times\n", | ||
| 181 | W1_F0D_READ_RETRIES); | ||
| 182 | pr_info("%s: rdbuf = %#x %#x data = %#x %#x\n", | ||
| 183 | __func__, rdbuf[0], rdbuf[1], data[0], data[1]); | ||
| 184 | |||
| 185 | return -1; | ||
| 186 | } | ||
| 187 | |||
| 188 | /* Trigger write out to EEPROM */ | ||
| 189 | w1_write_8(sl->master, W1_F0D_RELEASE); | ||
| 190 | |||
| 191 | /* Sleep for tprog ms to wait for the write to complete */ | ||
| 192 | msleep(W1_F0D_TPROG_MS); | ||
| 193 | |||
| 194 | /* Check CS (Command Status) == 0xAA ? */ | ||
| 195 | cs = w1_read_8(sl->master); | ||
| 196 | if (cs != W1_F0D_CS_OK) { | ||
| 197 | dev_err(&sl->dev, "save to eeprom failed = CS=%#x\n", cs); | ||
| 198 | return -1; | ||
| 199 | } | ||
| 200 | |||
| 201 | return 0; | ||
| 202 | } | ||
| 203 | |||
| 204 | static ssize_t w1_f0d_write_bin(struct file *filp, struct kobject *kobj, | ||
| 205 | struct bin_attribute *bin_attr, | ||
| 206 | char *buf, loff_t off, size_t count) | ||
| 207 | { | ||
| 208 | struct w1_slave *sl = kobj_to_w1_slave(kobj); | ||
| 209 | int addr, len; | ||
| 210 | int copy; | ||
| 211 | |||
| 212 | count = w1_f0d_fix_count(off, count, W1_F0D_EEPROM_SIZE); | ||
| 213 | if (count == 0) | ||
| 214 | return 0; | ||
| 215 | |||
| 216 | mutex_lock(&sl->master->mutex); | ||
| 217 | |||
| 218 | /* Can only write data in blocks of the size of the scratchpad */ | ||
| 219 | addr = off; | ||
| 220 | len = count; | ||
| 221 | while (len > 0) { | ||
| 222 | |||
| 223 | /* if len too short or addr not aligned */ | ||
| 224 | if (len < W1_F0D_SCRATCH_SIZE || addr & W1_F0D_SCRATCH_MASK) { | ||
| 225 | char tmp[W1_F0D_SCRATCH_SIZE]; | ||
| 226 | |||
| 227 | /* read the block and update the parts to be written */ | ||
| 228 | if (w1_f0d_readblock(sl, addr & ~W1_F0D_SCRATCH_MASK, | ||
| 229 | W1_F0D_SCRATCH_SIZE, tmp)) { | ||
| 230 | count = -EIO; | ||
| 231 | goto out_up; | ||
| 232 | } | ||
| 233 | |||
| 234 | /* copy at most to the boundary of the PAGE or len */ | ||
| 235 | copy = W1_F0D_SCRATCH_SIZE - | ||
| 236 | (addr & W1_F0D_SCRATCH_MASK); | ||
| 237 | |||
| 238 | if (copy > len) | ||
| 239 | copy = len; | ||
| 240 | |||
| 241 | memcpy(&tmp[addr & W1_F0D_SCRATCH_MASK], buf, copy); | ||
| 242 | if (w1_f0d_write(sl, addr & ~W1_F0D_SCRATCH_MASK, | ||
| 243 | W1_F0D_SCRATCH_SIZE, tmp) < 0) { | ||
| 244 | count = -EIO; | ||
| 245 | goto out_up; | ||
| 246 | } | ||
| 247 | } else { | ||
| 248 | |||
| 249 | copy = W1_F0D_SCRATCH_SIZE; | ||
| 250 | if (w1_f0d_write(sl, addr, copy, buf) < 0) { | ||
| 251 | count = -EIO; | ||
| 252 | goto out_up; | ||
| 253 | } | ||
| 254 | } | ||
| 255 | buf += copy; | ||
| 256 | addr += copy; | ||
| 257 | len -= copy; | ||
| 258 | } | ||
| 259 | |||
| 260 | out_up: | ||
| 261 | mutex_unlock(&sl->master->mutex); | ||
| 262 | |||
| 263 | return count; | ||
| 264 | } | ||
| 265 | |||
| 266 | static struct bin_attribute w1_f0d_bin_attr = { | ||
| 267 | .attr = { | ||
| 268 | .name = "eeprom", | ||
| 269 | .mode = S_IRUGO | S_IWUSR, | ||
| 270 | }, | ||
| 271 | .size = W1_F0D_EEPROM_SIZE, | ||
| 272 | .read = w1_f0d_read_bin, | ||
| 273 | .write = w1_f0d_write_bin, | ||
| 274 | }; | ||
| 275 | |||
| 276 | static int w1_f0d_add_slave(struct w1_slave *sl) | ||
| 277 | { | ||
| 278 | return sysfs_create_bin_file(&sl->dev.kobj, &w1_f0d_bin_attr); | ||
| 279 | } | ||
| 280 | |||
| 281 | static void w1_f0d_remove_slave(struct w1_slave *sl) | ||
| 282 | { | ||
| 283 | sysfs_remove_bin_file(&sl->dev.kobj, &w1_f0d_bin_attr); | ||
| 284 | } | ||
| 285 | |||
| 286 | static struct w1_family_ops w1_f0d_fops = { | ||
| 287 | .add_slave = w1_f0d_add_slave, | ||
| 288 | .remove_slave = w1_f0d_remove_slave, | ||
| 289 | }; | ||
| 290 | |||
| 291 | static struct w1_family w1_family_2d = { | ||
| 292 | .fid = W1_EEPROM_DS2805, | ||
| 293 | .fops = &w1_f0d_fops, | ||
| 294 | }; | ||
| 295 | |||
| 296 | static int __init w1_f0d_init(void) | ||
| 297 | { | ||
| 298 | pr_info("%s()\n", __func__); | ||
| 299 | return w1_register_family(&w1_family_2d); | ||
| 300 | } | ||
| 301 | |||
| 302 | static void __exit w1_f0d_fini(void) | ||
| 303 | { | ||
| 304 | pr_info("%s()\n", __func__); | ||
| 305 | w1_unregister_family(&w1_family_2d); | ||
| 306 | } | ||
| 307 | |||
| 308 | module_init(w1_f0d_init); | ||
| 309 | module_exit(w1_f0d_fini); | ||
| 310 | |||
| 311 | MODULE_LICENSE("GPL"); | ||
| 312 | MODULE_AUTHOR("Andrew Worsley amworsley@gmail.com"); | ||
| 313 | MODULE_DESCRIPTION("w1 family 0d driver for DS2805, 1kb EEPROM"); | ||
| @@ -29,6 +29,7 @@ · 28 unmodified lines | |||
| 29 | #include <linux/types.h> | 29 | #include <linux/types.h> |
| 30 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
| 31 | #include <linux/delay.h> | 31 | #include <linux/delay.h> |
| 32 | #include <linux/hwmon.h> | ||
| 32 | 33 | ||
| 33 | #include <linux/w1.h> | 34 | #include <linux/w1.h> |
| 34 | 35 | ||
| @@ -59,6 +60,12 @@ struct w1_therm_family_data { · 24 unmodified lines | |||
| 59 | atomic_t refcnt; | 60 | atomic_t refcnt; |
| 60 | }; | 61 | }; |
| 61 | 62 | ||
| 63 | struct therm_info { | ||
| 64 | u8 rom[9]; | ||
| 65 | u8 crc; | ||
| 66 | u8 verdict; | ||
| 67 | }; | ||
| 68 | |||
| 62 | /* return the address of the refcnt in the family data */ | 69 | /* return the address of the refcnt in the family data */ |
| 63 | #define THERM_REFCNT(family_data) \ | 70 | #define THERM_REFCNT(family_data) \ |
| 64 | (&((struct w1_therm_family_data *)family_data)->refcnt) | 71 | (&((struct w1_therm_family_data *)family_data)->refcnt) |
| @@ -107,19 +114,72 @@ static struct attribute *w1_ds28ea00_attrs[] = { · 42 unmodified lines | |||
| 107 | &dev_attr_w1_seq.attr, | 114 | &dev_attr_w1_seq.attr, |
| 108 | NULL, | 115 | NULL, |
| 109 | }; | 116 | }; |
| 117 | |||
| 110 | ATTRIBUTE_GROUPS(w1_therm); | 118 | ATTRIBUTE_GROUPS(w1_therm); |
| 111 | ATTRIBUTE_GROUPS(w1_ds28ea00); | 119 | ATTRIBUTE_GROUPS(w1_ds28ea00); |
| 112 | 120 | ||
| 121 | #if IS_REACHABLE(CONFIG_HWMON) | ||
| 122 | static int w1_read_temp(struct device *dev, u32 attr, int channel, | ||
| 123 | long *val); | ||
| 124 | |||
| 125 | static umode_t w1_is_visible(const void *_data, enum hwmon_sensor_types type, | ||
| 126 | u32 attr, int channel) | ||
| 127 | { | ||
| 128 | return attr == hwmon_temp_input ? 0444 : 0; | ||
| 129 | } | ||
| 130 | |||
| 131 | static int w1_read(struct device *dev, enum hwmon_sensor_types type, | ||
| 132 | u32 attr, int channel, long *val) | ||
| 133 | { | ||
| 134 | switch (type) { | ||
| 135 | case hwmon_temp: | ||
| 136 | return w1_read_temp(dev, attr, channel, val); | ||
| 137 | default: | ||
| 138 | return -EOPNOTSUPP; | ||
| 139 | } | ||
| 140 | } | ||
| 141 | |||
| 142 | static const u32 w1_temp_config[] = { | ||
| 143 | HWMON_T_INPUT, | ||
| 144 | 0 | ||
| 145 | }; | ||
| 146 | |||
| 147 | static const struct hwmon_channel_info w1_temp = { | ||
| 148 | .type = hwmon_temp, | ||
| 149 | .config = w1_temp_config, | ||
| 150 | }; | ||
| 151 | |||
| 152 | static const struct hwmon_channel_info *w1_info[] = { | ||
| 153 | &w1_temp, | ||
| 154 | NULL | ||
| 155 | }; | ||
| 156 | |||
| 157 | static const struct hwmon_ops w1_hwmon_ops = { | ||
| 158 | .is_visible = w1_is_visible, | ||
| 159 | .read = w1_read, | ||
| 160 | }; | ||
| 161 | |||
| 162 | static const struct hwmon_chip_info w1_chip_info = { | ||
| 163 | .ops = &w1_hwmon_ops, | ||
| 164 | .info = w1_info, | ||
| 165 | }; | ||
| 166 | #define W1_CHIPINFO (&w1_chip_info) | ||
| 167 | #else | ||
| 168 | #define W1_CHIPINFO NULL | ||
| 169 | #endif | ||
| 170 | |||
| 113 | static struct w1_family_ops w1_therm_fops = { | 171 | static struct w1_family_ops w1_therm_fops = { |
| 114 | .add_slave = w1_therm_add_slave, | 172 | .add_slave = w1_therm_add_slave, |
| 115 | .remove_slave = w1_therm_remove_slave, | 173 | .remove_slave = w1_therm_remove_slave, |
| 116 | .groups = w1_therm_groups, | 174 | .groups = w1_therm_groups, |
| 175 | .chip_info = W1_CHIPINFO, | ||
| 117 | }; | 176 | }; |
| 118 | 177 | ||
| 119 | static struct w1_family_ops w1_ds28ea00_fops = { | 178 | static struct w1_family_ops w1_ds28ea00_fops = { |
| 120 | .add_slave = w1_therm_add_slave, | 179 | .add_slave = w1_therm_add_slave, |
| 121 | .remove_slave = w1_therm_remove_slave, | 180 | .remove_slave = w1_therm_remove_slave, |
| 122 | .groups = w1_ds28ea00_groups, | 181 | .groups = w1_ds28ea00_groups, |
| 182 | .chip_info = W1_CHIPINFO, | ||
| 123 | }; | 183 | }; |
| 124 | 184 | ||
| 125 | static struct w1_family w1_therm_family_DS18S20 = { | 185 | static struct w1_family w1_therm_family_DS18S20 = { |
| @@ -422,33 +482,31 @@ static ssize_t w1_slave_store(struct device *device, · 296 unmodified lines | |||
| 422 | return ret ? : size; | 482 | return ret ? : size; |
| 423 | } | 483 | } |
| 424 | 484 | ||
| 425 | static ssize_t w1_slave_show(struct device *device, | 485 | static ssize_t read_therm(struct device *device, |
| 426 | struct device_attribute *attr, char *buf) | 486 | struct w1_slave *sl, struct therm_info *info) |
| 427 | { | 487 | { |
| 428 | struct w1_slave *sl = dev_to_w1_slave(device); | ||
| 429 | struct w1_master *dev = sl->master; | 488 | struct w1_master *dev = sl->master; |
| 430 | u8 rom[9], crc, verdict, external_power; | 489 | u8 external_power; |
| 431 | int i, ret, max_trying = 10; | 490 | int ret, max_trying = 10; |
| 432 | ssize_t c = PAGE_SIZE; | ||
| 433 | u8 *family_data = sl->family_data; | 491 | u8 *family_data = sl->family_data; |
| 434 | 492 | ||
| 435 | ret = mutex_lock_interruptible(&dev->bus_mutex); | 493 | ret = mutex_lock_interruptible(&dev->bus_mutex); |
| 436 | if (ret != 0) | 494 | if (ret != 0) |
| 437 | goto post_unlock; | 495 | goto error; |
| 438 | 496 | ||
| 439 | if (!sl->family_data) { | 497 | if (!family_data) { |
| 440 | ret = -ENODEV; | 498 | ret = -ENODEV; |
| 441 | goto pre_unlock; | 499 | goto mt_unlock; |
| 442 | } | 500 | } |
| 443 | 501 | ||
| 444 | /* prevent the slave from going away in sleep */ | 502 | /* prevent the slave from going away in sleep */ |
| 445 | atomic_inc(THERM_REFCNT(family_data)); | 503 | atomic_inc(THERM_REFCNT(family_data)); |
| 446 | memset(rom, 0, sizeof(rom)); | 504 | memset(info->rom, 0, sizeof(info->rom)); |
| 447 | 505 | ||
| 448 | while (max_trying--) { | 506 | while (max_trying--) { |
| 449 | 507 | ||
| 450 | verdict = 0; | 508 | info->verdict = 0; |
| 451 | crc = 0; | 509 | info->crc = 0; |
| 452 | 510 | ||
| 453 | if (!w1_reset_select_slave(sl)) { | 511 | if (!w1_reset_select_slave(sl)) { |
| 454 | int count = 0; | 512 | int count = 0; |
| @@ -474,47 +532,69 @@ static ssize_t w1_slave_show(struct device *device, · 19 unmodified lines | |||
| 474 | sleep_rem = msleep_interruptible(tm); | 532 | sleep_rem = msleep_interruptible(tm); |
| 475 | if (sleep_rem != 0) { | 533 | if (sleep_rem != 0) { |
| 476 | ret = -EINTR; | 534 | ret = -EINTR; |
| 477 | goto post_unlock; | 535 | goto dec_refcnt; |
| 478 | } | 536 | } |
| 479 | 537 | ||
| 480 | ret = mutex_lock_interruptible(&dev->bus_mutex); | 538 | ret = mutex_lock_interruptible(&dev->bus_mutex); |
| 481 | if (ret != 0) | 539 | if (ret != 0) |
| 482 | goto post_unlock; | 540 | goto dec_refcnt; |
| 483 | } else if (!w1_strong_pullup) { | 541 | } else if (!w1_strong_pullup) { |
| 484 | sleep_rem = msleep_interruptible(tm); | 542 | sleep_rem = msleep_interruptible(tm); |
| 485 | if (sleep_rem != 0) { | 543 | if (sleep_rem != 0) { |
| 486 | ret = -EINTR; | 544 | ret = -EINTR; |
| 487 | goto pre_unlock; | 545 | goto dec_refcnt; |
| 488 | } | 546 | } |
| 489 | } | 547 | } |
| 490 | 548 | ||
| 491 | if (!w1_reset_select_slave(sl)) { | 549 | if (!w1_reset_select_slave(sl)) { |
| 492 | 550 | ||
| 493 | w1_write_8(dev, W1_READ_SCRATCHPAD); | 551 | w1_write_8(dev, W1_READ_SCRATCHPAD); |
| 494 | count = w1_read_block(dev, rom, 9); | 552 | count = w1_read_block(dev, info->rom, 9); |
| 495 | if (count != 9) { | 553 | if (count != 9) { |
| 496 | dev_warn(device, "w1_read_block() " | 554 | dev_warn(device, "w1_read_block() " |
| 497 | "returned %u instead of 9.\n", | 555 | "returned %u instead of 9.\n", |
| 498 | count); | 556 | count); |
| 499 | } | 557 | } |
| 500 | 558 | ||
| 501 | crc = w1_calc_crc8(rom, 8); | 559 | info->crc = w1_calc_crc8(info->rom, 8); |
| 502 | 560 | ||
| 503 | if (rom[8] == crc) | 561 | if (info->rom[8] == info->crc) |
| 504 | verdict = 1; | 562 | info->verdict = 1; |
| 505 | } | 563 | } |
| 506 | } | 564 | } |
| 507 | 565 | ||
| 508 | if (verdict) | 566 | if (info->verdict) |
| 509 | break; | 567 | break; |
| 510 | } | 568 | } |
| 511 | 569 | ||
| 570 | dec_refcnt: | ||
| 571 | atomic_dec(THERM_REFCNT(family_data)); | ||
| 572 | mt_unlock: | ||
| 573 | mutex_unlock(&dev->bus_mutex); | ||
| 574 | error: | ||
| 575 | return ret; | ||
| 576 | } | ||
| 577 | |||
| 578 | static ssize_t w1_slave_show(struct device *device, | ||
| 579 | struct device_attribute *attr, char *buf) | ||
| 580 | { | ||
| 581 | struct w1_slave *sl = dev_to_w1_slave(device); | ||
| 582 | struct therm_info info; | ||
| 583 | u8 *family_data = sl->family_data; | ||
| 584 | int ret, i; | ||
| 585 | ssize_t c = PAGE_SIZE; | ||
| 586 | u8 fid = sl->family->fid; | ||
| 587 | |||
| 588 | ret = read_therm(device, sl, &info); | ||
| 589 | if (ret) | ||
| 590 | return ret; | ||
| 591 | |||
| 512 | for (i = 0; i < 9; ++i) | 592 | for (i = 0; i < 9; ++i) |
| 513 | c -= snprintf(buf + PAGE_SIZE - c, c, "%02x ", rom[i]); | 593 | c -= snprintf(buf + PAGE_SIZE - c, c, "%02x ", info.rom[i]); |
| 514 | c -= snprintf(buf + PAGE_SIZE - c, c, ": crc=%02x %s\n", | 594 | c -= snprintf(buf + PAGE_SIZE - c, c, ": crc=%02x %s\n", |
| 515 | crc, (verdict) ? "YES" : "NO"); | 595 | info.crc, (info.verdict) ? "YES" : "NO"); |
| 516 | if (verdict) | 596 | if (info.verdict) |
| 517 | memcpy(family_data, rom, sizeof(rom)); | 597 | memcpy(family_data, info.rom, sizeof(info.rom)); |
| 518 | else | 598 | else |
| 519 | dev_warn(device, "Read failed CRC check\n"); | 599 | dev_warn(device, "Read failed CRC check\n"); |
| 520 | 600 | ||
| @@ -523,16 +603,42 @@ static ssize_t w1_slave_show(struct device *device, · 2 unmodified lines | |||
| 523 | ((u8 *)family_data)[i]); | 603 | ((u8 *)family_data)[i]); |
| 524 | 604 | ||
| 525 | c -= snprintf(buf + PAGE_SIZE - c, c, "t=%d\n", | 605 | c -= snprintf(buf + PAGE_SIZE - c, c, "t=%d\n", |
| 526 | w1_convert_temp(rom, sl->family->fid)); | 606 | w1_convert_temp(info.rom, fid)); |
| 527 | ret = PAGE_SIZE - c; | 607 | ret = PAGE_SIZE - c; |
| 608 | return ret; | ||
| 609 | } | ||
| 528 | 610 | ||
| 529 | pre_unlock: | 611 | #if IS_REACHABLE(CONFIG_HWMON) |
| 530 | mutex_unlock(&dev->bus_mutex); | 612 | static int w1_read_temp(struct device *device, u32 attr, int channel, |
| 613 | long *val) | ||
| 614 | { | ||
| 615 | struct w1_slave *sl = dev_get_drvdata(device); | ||
| 616 | struct therm_info info; | ||
| 617 | u8 fid = sl->family->fid; | ||
| 618 | int ret; | ||
| 619 | |||
| 620 | switch (attr) { | ||
| 621 | case hwmon_temp_input: | ||
| 622 | ret = read_therm(device, sl, &info); | ||
| 623 | if (ret) | ||
| 624 | return ret; | ||
| 625 | |||
| 626 | if (!info.verdict) { | ||
| 627 | ret = -EIO; | ||
| 628 | return ret; | ||
| 629 | } | ||
| 630 | |||
| 631 | *val = w1_convert_temp(info.rom, fid); | ||
| 632 | ret = 0; | ||
| 633 | break; | ||
| 634 | default: | ||
| 635 | ret = -EOPNOTSUPP; | ||
| 636 | break; | ||
| 637 | } | ||
| 531 | 638 | ||
| 532 | post_unlock: | ||
| 533 | atomic_dec(THERM_REFCNT(family_data)); | ||
| 534 | return ret; | 639 | return ret; |
| 535 | } | 640 | } |
| 641 | #endif | ||
| 536 | 642 | ||
| 537 | #define W1_42_CHAIN 0x99 | 643 | #define W1_42_CHAIN 0x99 |
| 538 | #define W1_42_CHAIN_OFF 0x3C | 644 | #define W1_42_CHAIN_OFF 0x3C |
| @@ -25,6 +25,7 @@ · 24 unmodified lines | |||
| 25 | #include <linux/sched.h> | 25 | #include <linux/sched.h> |
| 26 | #include <linux/kthread.h> | 26 | #include <linux/kthread.h> |
| 27 | #include <linux/freezer.h> | 27 | #include <linux/freezer.h> |
| 28 | #include <linux/hwmon.h> | ||
| 28 | 29 | ||
| 29 | #include <linux/atomic.h> | 30 | #include <linux/atomic.h> |
| 30 | 31 | ||
| @@ -568,7 +569,7 @@ static struct attribute *w1_master_default_attrs[] = { · 537 unmodified lines | |||
| 568 | NULL | 569 | NULL |
| 569 | }; | 570 | }; |
| 570 | 571 | ||
| 571 | static struct attribute_group w1_master_defattr_group = { | 572 | static const struct attribute_group w1_master_defattr_group = { |
| 572 | .attrs = w1_master_default_attrs, | 573 | .attrs = w1_master_default_attrs, |
| 573 | }; | 574 | }; |
| 574 | 575 | ||
| @@ -649,9 +650,24 @@ static int w1_family_notify(unsigned long action, struct w1_slave *sl) · 74 unmodified lines | |||
| 649 | return err; | 650 | return err; |
| 650 | } | 651 | } |
| 651 | } | 652 | } |
| 652 | 653 | if (IS_REACHABLE(CONFIG_HWMON) && fops->chip_info) { | |
| 654 | struct device *hwmon | ||
| 655 | = hwmon_device_register_with_info(&sl->dev, | ||
| 656 | "w1_slave_temp", sl, | ||
| 657 | fops->chip_info, | ||
| 658 | NULL); | ||
| 659 | if (IS_ERR(hwmon)) { | ||
| 660 | dev_warn(&sl->dev, | ||
| 661 | "could not create hwmon device\n"); | ||
| 662 | } else { | ||
| 663 | sl->hwmon = hwmon; | ||
| 664 | } | ||
| 665 | } | ||
| 653 | break; | 666 | break; |
| 654 | case BUS_NOTIFY_DEL_DEVICE: | 667 | case BUS_NOTIFY_DEL_DEVICE: |
| 668 | if (IS_REACHABLE(CONFIG_HWMON) && fops->chip_info && | ||
| 669 | sl->hwmon) | ||
| 670 | hwmon_device_unregister(sl->hwmon); | ||
| 655 | if (fops->remove_slave) | 671 | if (fops->remove_slave) |
| 656 | sl->family->fops->remove_slave(sl); | 672 | sl->family->fops->remove_slave(sl); |
| 657 | if (fops->groups) | 673 | if (fops->groups) |
| @@ -729,6 +745,8 @@ int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn) · 71 unmodified lines | |||
| 729 | atomic_set(&sl->refcnt, 1); | 745 | atomic_set(&sl->refcnt, 1); |
| 730 | atomic_inc(&sl->master->refcnt); | 746 | atomic_inc(&sl->master->refcnt); |
| 731 | dev->slave_count++; | 747 | dev->slave_count++; |
| 748 | dev_info(&dev->dev, "Attaching one wire slave %02x.%012llx crc %02x\n", | ||
| 749 | rn->family, (unsigned long long)rn->id, rn->crc); | ||
| 732 | 750 | ||
| 733 | /* slave modules need to be loaded in a context with unlocked mutex */ | 751 | /* slave modules need to be loaded in a context with unlocked mutex */ |
| 734 | mutex_unlock(&dev->mutex); | 752 | mutex_unlock(&dev->mutex); |
| @@ -28,6 +28,8 @@ static struct kobj_map *cdev_map; · 27 unmodified lines | |||
| 28 | 28 | ||
| 29 | static DEFINE_MUTEX(chrdevs_lock); | 29 | static DEFINE_MUTEX(chrdevs_lock); |
| 30 | 30 | ||
| 31 | #define CHRDEV_MAJOR_HASH_SIZE 255 | ||
| 32 | |||
| 31 | static struct char_device_struct { | 33 | static struct char_device_struct { |
| 32 | struct char_device_struct *next; | 34 | struct char_device_struct *next; |
| 33 | unsigned int major; | 35 | unsigned int major; |
| @@ -49,16 +51,39 @@ void chrdev_show(struct seq_file *f, off_t offset) · 15 unmodified lines | |||
| 49 | { | 51 | { |
| 50 | struct char_device_struct *cd; | 52 | struct char_device_struct *cd; |
| 51 | 53 | ||
| 52 | if (offset < CHRDEV_MAJOR_HASH_SIZE) { | 54 | mutex_lock(&chrdevs_lock); |
| 53 | mutex_lock(&chrdevs_lock); | 55 | for (cd = chrdevs[major_to_index(offset)]; cd; cd = cd->next) { |
| 54 | for (cd = chrdevs[offset]; cd; cd = cd->next) | 56 | if (cd->major == offset) |
| 55 | seq_printf(f, "%3d %s\n", cd->major, cd->name); | 57 | seq_printf(f, "%3d %s\n", cd->major, cd->name); |
| 56 | mutex_unlock(&chrdevs_lock); | ||
| 57 | } | 58 | } |
| 59 | mutex_unlock(&chrdevs_lock); | ||
| 58 | } | 60 | } |
| 59 | 61 | ||
| 60 | #endif /* CONFIG_PROC_FS */ | 62 | #endif /* CONFIG_PROC_FS */ |
| 61 | 63 | ||
| 64 | static int find_dynamic_major(void) | ||
| 65 | { | ||
| 66 | int i; | ||
| 67 | struct char_device_struct *cd; | ||
| 68 | |||
| 69 | for (i = ARRAY_SIZE(chrdevs)-1; i > CHRDEV_MAJOR_DYN_END; i--) { | ||
| 70 | if (chrdevs[i] == NULL) | ||
| 71 | return i; | ||
| 72 | } | ||
| 73 | |||
| 74 | for (i = CHRDEV_MAJOR_DYN_EXT_START; | ||
| 75 | i > CHRDEV_MAJOR_DYN_EXT_END; i--) { | ||
| 76 | for (cd = chrdevs[major_to_index(i)]; cd; cd = cd->next) | ||
| 77 | if (cd->major == i) | ||
| 78 | break; | ||
| 79 | |||
| 80 | if (cd == NULL || cd->major != i) | ||
| 81 | return i; | ||
| 82 | } | ||
| 83 | |||
| 84 | return -EBUSY; | ||
| 85 | } | ||
| 86 | |||
| 62 | /* | 87 | /* |
| 63 | * Register a single major with a specified minor range. | 88 | * Register a single major with a specified minor range. |
| 64 | * | 89 | * |
| @@ -84,22 +109,21 @@ __register_chrdev_region(unsigned int major, unsigned int baseminor, · 19 unmodified lines | |||
| 84 | 109 | ||
| 85 | mutex_lock(&chrdevs_lock); | 110 | mutex_lock(&chrdevs_lock); |
| 86 | 111 | ||
| 87 | /* temporary */ | ||
| 88 | if (major == 0) { | 112 | if (major == 0) { |
| 89 | for (i = ARRAY_SIZE(chrdevs)-1; i > 0; i--) { | 113 | ret = find_dynamic_major(); |
| 90 | if (chrdevs[i] == NULL) | 114 | if (ret < 0) { |
| 91 | break; | 115 | pr_err("CHRDEV \"%s\" dynamic allocation region is full\n", |
| 92 | } | 116 | name); |
| 93 | |||
| 94 | if (i < CHRDEV_MAJOR_DYN_END) | ||
| 95 | pr_warn("CHRDEV \"%s\" major number %d goes below the dynamic allocation range\n", | ||
| 96 | name, i); | ||
| 97 | |||
| 98 | if (i == 0) { | ||
| 99 | ret = -EBUSY; | ||
| 100 | goto out; | 117 | goto out; |
| 101 | } | 118 | } |
| 102 | major = i; | 119 | major = ret; |
| 120 | } | ||
| 121 | |||
| 122 | if (major >= CHRDEV_MAJOR_MAX) { | ||
| 123 | pr_err("CHRDEV \"%s\" major requested (%d) is greater than the maximum (%d)\n", | ||
| 124 | name, major, CHRDEV_MAJOR_MAX); | ||
| 125 | ret = -EINVAL; | ||
| 126 | goto out; | ||
| 103 | } | 127 | } |
| 104 | 128 | ||
| 105 | cd->major = major; | 129 | cd->major = major; |
| @@ -7,14 +7,14 @@ static int devinfo_show(struct seq_file *f, void *v) · 6 unmodified lines | |||
| 7 | { | 7 | { |
| 8 | int i = *(loff_t *) v; | 8 | int i = *(loff_t *) v; |
| 9 | 9 | ||
| 10 | if (i < CHRDEV_MAJOR_HASH_SIZE) { | 10 | if (i < CHRDEV_MAJOR_MAX) { |
| 11 | if (i == 0) | 11 | if (i == 0) |
| 12 | seq_puts(f, "Character devices:\n"); | 12 | seq_puts(f, "Character devices:\n"); |
| 13 | chrdev_show(f, i); | 13 | chrdev_show(f, i); |
| 14 | } | 14 | } |
| 15 | #ifdef CONFIG_BLOCK | 15 | #ifdef CONFIG_BLOCK |
| 16 | else { | 16 | else { |
| 17 | i -= CHRDEV_MAJOR_HASH_SIZE; | 17 | i -= CHRDEV_MAJOR_MAX; |
| 18 | if (i == 0) | 18 | if (i == 0) |
| 19 | seq_puts(f, "\nBlock devices:\n"); | 19 | seq_puts(f, "\nBlock devices:\n"); |
| 20 | blkdev_show(f, i); | 20 | blkdev_show(f, i); |
| @@ -25,7 +25,7 @@ static int devinfo_show(struct seq_file *f, void *v) · 4 unmodified lines | |||
| 25 | 25 | ||
| 26 | static void *devinfo_start(struct seq_file *f, loff_t *pos) | 26 | static void *devinfo_start(struct seq_file *f, loff_t *pos) |
| 27 | { | 27 | { |
| 28 | if (*pos < (BLKDEV_MAJOR_HASH_SIZE + CHRDEV_MAJOR_HASH_SIZE)) | 28 | if (*pos < (BLKDEV_MAJOR_MAX + CHRDEV_MAJOR_MAX)) |
| 29 | return pos; | 29 | return pos; |
| 30 | return NULL; | 30 | return NULL; |
| 31 | } | 31 | } |
| @@ -33,7 +33,7 @@ static void *devinfo_start(struct seq_file *f, loff_t *pos) · 1 unmodified line | |||
| 33 | static void *devinfo_next(struct seq_file *f, void *v, loff_t *pos) | 33 | static void *devinfo_next(struct seq_file *f, void *v, loff_t *pos) |
| 34 | { | 34 | { |
| 35 | (*pos)++; | 35 | (*pos)++; |
| 36 | if (*pos >= (BLKDEV_MAJOR_HASH_SIZE + CHRDEV_MAJOR_HASH_SIZE)) | 36 | if (*pos >= (BLKDEV_MAJOR_MAX + CHRDEV_MAJOR_MAX)) |
| 37 | return NULL; | 37 | return NULL; |
| 38 | return pos; | 38 | return pos; |
| 39 | } | 39 | } |
| @@ -29,6 +29,8 @@ static inline u32 __bitrev32(u32 x) · 28 unmodified lines | |||
| 29 | 29 | ||
| 30 | #endif /* CONFIG_HAVE_ARCH_BITREVERSE */ | 30 | #endif /* CONFIG_HAVE_ARCH_BITREVERSE */ |
| 31 | 31 | ||
| 32 | #define __bitrev8x4(x) (__bitrev32(swab32(x))) | ||
| 33 | |||
| 32 | #define __constant_bitrev32(x) \ | 34 | #define __constant_bitrev32(x) \ |
| 33 | ({ \ | 35 | ({ \ |
| 34 | u32 __x = x; \ | 36 | u32 __x = x; \ |
| @@ -50,6 +52,15 @@ static inline u32 __bitrev32(u32 x) · 15 unmodified lines | |||
| 50 | __x; \ | 52 | __x; \ |
| 51 | }) | 53 | }) |
| 52 | 54 | ||
| 55 | #define __constant_bitrev8x4(x) \ | ||
| 56 | ({ \ | ||
| 57 | u32 __x = x; \ | ||
| 58 | __x = ((__x & (u32)0xF0F0F0F0UL) >> 4) | ((__x & (u32)0x0F0F0F0FUL) << 4); \ | ||
| 59 | __x = ((__x & (u32)0xCCCCCCCCUL) >> 2) | ((__x & (u32)0x33333333UL) << 2); \ | ||
| 60 | __x = ((__x & (u32)0xAAAAAAAAUL) >> 1) | ((__x & (u32)0x55555555UL) << 1); \ | ||
| 61 | __x; \ | ||
| 62 | }) | ||
| 63 | |||
| 53 | #define __constant_bitrev8(x) \ | 64 | #define __constant_bitrev8(x) \ |
| 54 | ({ \ | 65 | ({ \ |
| 55 | u8 __x = x; \ | 66 | u8 __x = x; \ |
| @@ -75,6 +86,14 @@ static inline u32 __bitrev32(u32 x) · 19 unmodified lines | |||
| 75 | __bitrev16(__x); \ | 86 | __bitrev16(__x); \ |
| 76 | }) | 87 | }) |
| 77 | 88 | ||
| 89 | #define bitrev8x4(x) \ | ||
| 90 | ({ \ | ||
| 91 | u32 __x = x; \ | ||
| 92 | __builtin_constant_p(__x) ? \ | ||
| 93 | __constant_bitrev8x4(__x) : \ | ||
| 94 | __bitrev8x4(__x); \ | ||
| 95 | }) | ||
| 96 | |||
| 78 | #define bitrev8(x) \ | 97 | #define bitrev8(x) \ |
| 79 | ({ \ | 98 | ({ \ |
| 80 | u8 __x = x; \ | 99 | u8 __x = x; \ |
| @@ -24,6 +24,12 @@ · 23 unmodified lines | |||
| 24 | /* ETMv3.5/PTM's ETMCR config bit */ | 24 | /* ETMv3.5/PTM's ETMCR config bit */ |
| 25 | #define ETM_OPT_CYCACC 12 | 25 | #define ETM_OPT_CYCACC 12 |
| 26 | #define ETM_OPT_TS 28 | 26 | #define ETM_OPT_TS 28 |
| 27 | #define ETM_OPT_RETSTK 29 | ||
| 28 | |||
| 29 | /* ETMv4 CONFIGR programming bits for the ETM OPTs */ | ||
| 30 | #define ETM4_CFG_BIT_CYCACC 4 | ||
| 31 | #define ETM4_CFG_BIT_TS 11 | ||
| 32 | #define ETM4_CFG_BIT_RETSTK 12 | ||
| 27 | 33 | ||
| 28 | static inline int coresight_get_trace_id(int cpu) | 34 | static inline int coresight_get_trace_id(int cpu) |
| 29 | { | 35 | { |
| @@ -2,8 +2,7 @@ · 1 unmodified line | |||
| 2 | * Module: eeprom_93xx46 | 2 | * Module: eeprom_93xx46 |
| 3 | * platform description for 93xx46 EEPROMs. | 3 | * platform description for 93xx46 EEPROMs. |
| 4 | */ | 4 | */ |
| 5 | 5 | #include <linux/gpio/consumer.h> | |
| 6 | struct gpio_desc; | ||
| 7 | 6 | ||
| 8 | struct eeprom_93xx46_platform_data { | 7 | struct eeprom_93xx46_platform_data { |
| 9 | unsigned char flags; | 8 | unsigned char flags; |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * External connector (extcon) class driver | 2 | * External Connector (extcon) framework |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2015 Samsung Electronics | 4 | * Copyright (C) 2015 Samsung Electronics |
| 5 | * Author: Chanwoo Choi <cw00.choi@samsung.com> | 5 | * Author: Chanwoo Choi <cw00.choi@samsung.com> |
| @@ -20,8 +20,7 @@ · 14 unmodified lines | |||
| 20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 22 | * GNU General Public License for more details. | 22 | * GNU General Public License for more details. |
| 23 | * | 23 | */ |
| 24 | */ | ||
| 25 | 24 | ||
| 26 | #ifndef __LINUX_EXTCON_H__ | 25 | #ifndef __LINUX_EXTCON_H__ |
| 27 | #define __LINUX_EXTCON_H__ | 26 | #define __LINUX_EXTCON_H__ |
| @@ -93,7 +92,7 @@ · 65 unmodified lines | |||
| 93 | #define EXTCON_NUM 63 | 92 | #define EXTCON_NUM 63 |
| 94 | 93 | ||
| 95 | /* | 94 | /* |
| 96 | * Define the property of supported external connectors. | 95 | * Define the properties of supported external connectors. |
| 97 | * | 96 | * |
| 98 | * When adding the new extcon property, they *must* have | 97 | * When adding the new extcon property, they *must* have |
| 99 | * the type/value/default information. Also, you *have to* | 98 | * the type/value/default information. Also, you *have to* |
| @@ -176,44 +175,42 @@ struct extcon_dev; · 76 unmodified lines | |||
| 176 | 175 | ||
| 177 | #if IS_ENABLED(CONFIG_EXTCON) | 176 | #if IS_ENABLED(CONFIG_EXTCON) |
| 178 | 177 | ||
| 179 | /* | 178 | /* Following APIs register/unregister the extcon device. */ |
| 180 | * Following APIs are for notifiers or configurations. | ||
| 181 | * Notifiers are the external port and connection devices. | ||
| 182 | */ | ||
| 183 | extern int extcon_dev_register(struct extcon_dev *edev); | 179 | extern int extcon_dev_register(struct extcon_dev *edev); |
| 184 | extern void extcon_dev_unregister(struct extcon_dev *edev); | 180 | extern void extcon_dev_unregister(struct extcon_dev *edev); |
| 185 | extern int devm_extcon_dev_register(struct device *dev, | 181 | extern int devm_extcon_dev_register(struct device *dev, |
| 186 | struct extcon_dev *edev); | 182 | struct extcon_dev *edev); |
| 187 | extern void devm_extcon_dev_unregister(struct device *dev, | 183 | extern void devm_extcon_dev_unregister(struct device *dev, |
| 188 | struct extcon_dev *edev); | 184 | struct extcon_dev *edev); |
| 189 | extern struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name); | ||
| 190 | 185 | ||
| 191 | /* | 186 | /* Following APIs allocate/free the memory of the extcon device. */ |
| 192 | * Following APIs control the memory of extcon device. | ||
| 193 | */ | ||
| 194 | extern struct extcon_dev *extcon_dev_allocate(const unsigned int *cable); | 187 | extern struct extcon_dev *extcon_dev_allocate(const unsigned int *cable); |
| 195 | extern void extcon_dev_free(struct extcon_dev *edev); | 188 | extern void extcon_dev_free(struct extcon_dev *edev); |
| 196 | extern struct extcon_dev *devm_extcon_dev_allocate(struct device *dev, | 189 | extern struct extcon_dev *devm_extcon_dev_allocate(struct device *dev, |
| 197 | const unsigned int *cable); | 190 | const unsigned int *cable); |
| 198 | extern void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev); | 191 | extern void devm_extcon_dev_free(struct device *dev, struct extcon_dev *edev); |
| 199 | 192 | ||
| 193 | /* Synchronize the state and property value for each external connector. */ | ||
| 194 | extern int extcon_sync(struct extcon_dev *edev, unsigned int id); | ||
| 195 | |||
| 200 | /* | 196 | /* |
| 201 | * get/set_state access each bit of the 32b encoded state value. | 197 | * Following APIs get/set the connected state of each external connector. |
| 202 | * They are used to access the status of each cable based on the cable id. | 198 | * The 'id' argument indicates the defined external connector. |
| 203 | */ | 199 | */ |
| 204 | extern int extcon_get_state(struct extcon_dev *edev, unsigned int id); | 200 | extern int extcon_get_state(struct extcon_dev *edev, unsigned int id); |
| 205 | extern int extcon_set_state(struct extcon_dev *edev, unsigned int id, | 201 | extern int extcon_set_state(struct extcon_dev *edev, unsigned int id, |
| 206 | bool cable_state); | 202 | bool state); |
| 207 | extern int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id, | 203 | extern int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id, |
| 208 | bool cable_state); | 204 | bool state); |
| 209 | /* | ||
| 210 | * Synchronize the state and property data for a specific external connector. | ||
| 211 | */ | ||
| 212 | extern int extcon_sync(struct extcon_dev *edev, unsigned int id); | ||
| 213 | 205 | ||
| 214 | /* | 206 | /* |
| 215 | * get/set_property access the property value of each external connector. | 207 | * Following APIs get/set the property of each external connector. |
| 216 | * They are used to access the property of each cable based on the property id. | 208 | * The 'id' argument indicates the defined external connector |
| 209 | * and the 'prop' indicates the extcon property. | ||
| 210 | * | ||
| 211 | * And extcon_get/set_property_capability() set the capability of the property | ||
| 212 | * for each external connector. They are used to set the capability of the | ||
| 213 | * property of each external connector based on the id and property. | ||
| 217 | */ | 214 | */ |
| 218 | extern int extcon_get_property(struct extcon_dev *edev, unsigned int id, | 215 | extern int extcon_get_property(struct extcon_dev *edev, unsigned int id, |
| 219 | unsigned int prop, | 216 | unsigned int prop, |
| @@ -224,28 +221,24 @@ extern int extcon_set_property(struct extcon_dev *edev, unsigned int id, · 4 unmodified lines | |||
| 224 | extern int extcon_set_property_sync(struct extcon_dev *edev, unsigned int id, | 221 | extern int extcon_set_property_sync(struct extcon_dev *edev, unsigned int id, |
| 225 | unsigned int prop, | 222 | unsigned int prop, |
| 226 | union extcon_property_value prop_val); | 223 | union extcon_property_value prop_val); |
| 227 | |||
| 228 | /* | ||
| 229 | * get/set_property_capability set the capability of the property for each | ||
| 230 | * external connector. They are used to set the capability of the property | ||
| 231 | * of each external connector based on the id and property. | ||
| 232 | */ | ||
| 233 | extern int extcon_get_property_capability(struct extcon_dev *edev, | 224 | extern int extcon_get_property_capability(struct extcon_dev *edev, |
| 234 | unsigned int id, unsigned int prop); | 225 | unsigned int id, unsigned int prop); |
| 235 | extern int extcon_set_property_capability(struct extcon_dev *edev, | 226 | extern int extcon_set_property_capability(struct extcon_dev *edev, |
| 236 | unsigned int id, unsigned int prop); | 227 | unsigned int id, unsigned int prop); |
| 237 | 228 | ||
| 238 | /* | 229 | /* |
| 239 | * Following APIs are to monitor the status change of the external connectors. | 230 | * Following APIs register the notifier block in order to detect |
| 231 | * the change of both state and property value for each external connector. | ||
| 232 | * | ||
| 240 | * extcon_register_notifier(*edev, id, *nb) : Register a notifier block | 233 | * extcon_register_notifier(*edev, id, *nb) : Register a notifier block |
| 241 | * for specific external connector of the extcon. | 234 | * for specific external connector of the extcon. |
| 242 | * extcon_register_notifier_all(*edev, *nb) : Register a notifier block | 235 | * extcon_register_notifier_all(*edev, *nb) : Register a notifier block |
| 243 | * for all supported external connectors of the extcon. | 236 | * for all supported external connectors of the extcon. |
| 244 | */ | 237 | */ |
| 245 | extern int extcon_register_notifier(struct extcon_dev *edev, unsigned int id, | 238 | extern int extcon_register_notifier(struct extcon_dev *edev, unsigned int id, |
| 246 | struct notifier_block *nb); | 239 | struct notifier_block *nb); |
| 247 | extern int extcon_unregister_notifier(struct extcon_dev *edev, unsigned int id, | 240 | extern int extcon_unregister_notifier(struct extcon_dev *edev, unsigned int id, |
| 248 | struct notifier_block *nb); | 241 | struct notifier_block *nb); |
| 249 | extern int devm_extcon_register_notifier(struct device *dev, | 242 | extern int devm_extcon_register_notifier(struct device *dev, |
| 250 | struct extcon_dev *edev, unsigned int id, | 243 | struct extcon_dev *edev, unsigned int id, |
| 251 | struct notifier_block *nb); | 244 | struct notifier_block *nb); |
| @@ -265,16 +258,15 @@ extern void devm_extcon_unregister_notifier_all(struct device *dev, · 13 unmodified lines | |||
| 265 | struct notifier_block *nb); | 258 | struct notifier_block *nb); |
| 266 | 259 | ||
| 267 | /* | 260 | /* |
| 268 | * Following API get the extcon device from devicetree. | 261 | * Following APIs get the extcon_dev from devicetree or by through extcon name. |
| 269 | * This function use phandle of devicetree to get extcon device directly. | ||
| 270 | */ | 262 | */ |
| 263 | extern struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name); | ||
| 271 | extern struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, | 264 | extern struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, |
| 272 | int index); | 265 | int index); |
| 273 | 266 | ||
| 274 | /* Following API to get information of extcon device */ | 267 | /* Following API get the name of extcon device. */ |
| 275 | extern const char *extcon_get_edev_name(struct extcon_dev *edev); | 268 | extern const char *extcon_get_edev_name(struct extcon_dev *edev); |
| 276 | 269 | ||
| 277 | |||
| 278 | #else /* CONFIG_EXTCON */ | 270 | #else /* CONFIG_EXTCON */ |
| 279 | static inline int extcon_dev_register(struct extcon_dev *edev) | 271 | static inline int extcon_dev_register(struct extcon_dev *edev) |
| 280 | { | 272 | { |
| @@ -284,13 +276,13 @@ static inline int extcon_dev_register(struct extcon_dev *edev) · 3 unmodified lines | |||
| 284 | static inline void extcon_dev_unregister(struct extcon_dev *edev) { } | 276 | static inline void extcon_dev_unregister(struct extcon_dev *edev) { } |
| 285 | 277 | ||
| 286 | static inline int devm_extcon_dev_register(struct device *dev, | 278 | static inline int devm_extcon_dev_register(struct device *dev, |
| 287 | struct extcon_dev *edev) | 279 | struct extcon_dev *edev) |
| 288 | { | 280 | { |
| 289 | return -EINVAL; | 281 | return -EINVAL; |
| 290 | } | 282 | } |
| 291 | 283 | ||
| 292 | static inline void devm_extcon_dev_unregister(struct device *dev, | 284 | static inline void devm_extcon_dev_unregister(struct device *dev, |
| 293 | struct extcon_dev *edev) { } | 285 | struct extcon_dev *edev) { } |
| 294 | 286 | ||
| 295 | static inline struct extcon_dev *extcon_dev_allocate(const unsigned int *cable) | 287 | static inline struct extcon_dev *extcon_dev_allocate(const unsigned int *cable) |
| 296 | { | 288 | { |
| @@ -300,7 +292,7 @@ static inline struct extcon_dev *extcon_dev_allocate(const unsigned int *cable) · 3 unmodified lines | |||
| 300 | static inline void extcon_dev_free(struct extcon_dev *edev) { } | 292 | static inline void extcon_dev_free(struct extcon_dev *edev) { } |
| 301 | 293 | ||
| 302 | static inline struct extcon_dev *devm_extcon_dev_allocate(struct device *dev, | 294 | static inline struct extcon_dev *devm_extcon_dev_allocate(struct device *dev, |
| 303 | const unsigned int *cable) | 295 | const unsigned int *cable) |
| 304 | { | 296 | { |
| 305 | return ERR_PTR(-ENOSYS); | 297 | return ERR_PTR(-ENOSYS); |
| 306 | } | 298 | } |
| @@ -314,13 +306,13 @@ static inline int extcon_get_state(struct extcon_dev *edev, unsigned int id) · 7 unmodified lines | |||
| 314 | } | 306 | } |
| 315 | 307 | ||
| 316 | static inline int extcon_set_state(struct extcon_dev *edev, unsigned int id, | 308 | static inline int extcon_set_state(struct extcon_dev *edev, unsigned int id, |
| 317 | bool cable_state) | 309 | bool state) |
| 318 | { | 310 | { |
| 319 | return 0; | 311 | return 0; |
| 320 | } | 312 | } |
| 321 | 313 | ||
| 322 | static inline int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id, | 314 | static inline int extcon_set_state_sync(struct extcon_dev *edev, unsigned int id, |
| 323 | bool cable_state) | 315 | bool state) |
| 324 | { | 316 | { |
| 325 | return 0; | 317 | return 0; |
| 326 | } | 318 | } |
| @@ -331,52 +323,45 @@ static inline int extcon_sync(struct extcon_dev *edev, unsigned int id) · 4 unmodified lines | |||
| 331 | } | 323 | } |
| 332 | 324 | ||
| 333 | static inline int extcon_get_property(struct extcon_dev *edev, unsigned int id, | 325 | static inline int extcon_get_property(struct extcon_dev *edev, unsigned int id, |
| 334 | unsigned int prop, | 326 | unsigned int prop, |
| 335 | union extcon_property_value *prop_val) | 327 | union extcon_property_value *prop_val) |
| 336 | { | 328 | { |
| 337 | return 0; | 329 | return 0; |
| 338 | } | 330 | } |
| 339 | static inline int extcon_set_property(struct extcon_dev *edev, unsigned int id, | 331 | static inline int extcon_set_property(struct extcon_dev *edev, unsigned int id, |
| 340 | unsigned int prop, | 332 | unsigned int prop, |
| 341 | union extcon_property_value prop_val) | 333 | union extcon_property_value prop_val) |
| 342 | { | 334 | { |
| 343 | return 0; | 335 | return 0; |
| 344 | } | 336 | } |
| 345 | 337 | ||
| 346 | static inline int extcon_set_property_sync(struct extcon_dev *edev, | 338 | static inline int extcon_set_property_sync(struct extcon_dev *edev, |
| 347 | unsigned int id, unsigned int prop, | 339 | unsigned int id, unsigned int prop, |
| 348 | union extcon_property_value prop_val) | 340 | union extcon_property_value prop_val) |
| 349 | { | 341 | { |
| 350 | return 0; | 342 | return 0; |
| 351 | } | 343 | } |
| 352 | 344 | ||
| 353 | static inline int extcon_get_property_capability(struct extcon_dev *edev, | 345 | static inline int extcon_get_property_capability(struct extcon_dev *edev, |
| 354 | unsigned int id, unsigned int prop) | 346 | unsigned int id, unsigned int prop) |
| 355 | { | 347 | { |
| 356 | return 0; | 348 | return 0; |
| 357 | } | 349 | } |
| 358 | 350 | ||
| 359 | static inline int extcon_set_property_capability(struct extcon_dev *edev, | 351 | static inline int extcon_set_property_capability(struct extcon_dev *edev, |
| 360 | unsigned int id, unsigned int prop) | 352 | unsigned int id, unsigned int prop) |
| 361 | { | 353 | { |
| 362 | return 0; | 354 | return 0; |
| 363 | } | 355 | } |
| 364 | 356 | ||
| 365 | static inline struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name) | ||
| 366 | { | ||
| 367 | return NULL; | ||
| 368 | } | ||
| 369 | |||
| 370 | static inline int extcon_register_notifier(struct extcon_dev *edev, | 357 | static inline int extcon_register_notifier(struct extcon_dev *edev, |
| 371 | unsigned int id, | 358 | unsigned int id, struct notifier_block *nb) |
| 372 | struct notifier_block *nb) | ||
| 373 | { | 359 | { |
| 374 | return 0; | 360 | return 0; |
| 375 | } | 361 | } |
| 376 | 362 | ||
| 377 | static inline int extcon_unregister_notifier(struct extcon_dev *edev, | 363 | static inline int extcon_unregister_notifier(struct extcon_dev *edev, |
| 378 | unsigned int id, | 364 | unsigned int id, struct notifier_block *nb) |
| 379 | struct notifier_block *nb) | ||
| 380 | { | 365 | { |
| 381 | return 0; | 366 | return 0; |
| 382 | } | 367 | } |
| @@ -392,8 +377,13 @@ static inline void devm_extcon_unregister_notifier(struct device *dev, · 9 unmodified lines | |||
| 392 | struct extcon_dev *edev, unsigned int id, | 377 | struct extcon_dev *edev, unsigned int id, |
| 393 | struct notifier_block *nb) { } | 378 | struct notifier_block *nb) { } |
| 394 | 379 | ||
| 380 | static inline struct extcon_dev *extcon_get_extcon_dev(const char *extcon_name) | ||
| 381 | { | ||
| 382 | return ERR_PTR(-ENODEV); | ||
| 383 | } | ||
| 384 | |||
| 395 | static inline struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, | 385 | static inline struct extcon_dev *extcon_get_edev_by_phandle(struct device *dev, |
| 396 | int index) | 386 | int index) |
| 397 | { | 387 | { |
| 398 | return ERR_PTR(-ENODEV); | 388 | return ERR_PTR(-ENODEV); |
| 399 | } | 389 | } |
| @@ -411,26 +401,14 @@ struct extcon_specific_cable_nb { · 11 unmodified lines | |||
| 411 | }; | 401 | }; |
| 412 | 402 | ||
| 413 | static inline int extcon_register_interest(struct extcon_specific_cable_nb *obj, | 403 | static inline int extcon_register_interest(struct extcon_specific_cable_nb *obj, |
| 414 | const char *extcon_name, const char *cable_name, | 404 | const char *extcon_name, const char *cable_name, |
| 415 | struct notifier_block *nb) | 405 | struct notifier_block *nb) |
| 416 | { | 406 | { |
| 417 | return -EINVAL; | 407 | return -EINVAL; |
| 418 | } | 408 | } |
| 419 | 409 | ||
| 420 | static inline int extcon_unregister_interest(struct extcon_specific_cable_nb | 410 | static inline int extcon_unregister_interest(struct extcon_specific_cable_nb *obj) |
| 421 | *obj) | ||
| 422 | { | 411 | { |
| 423 | return -EINVAL; | 412 | return -EINVAL; |
| 424 | } | 413 | } |
| 425 | |||
| 426 | static inline int extcon_get_cable_state_(struct extcon_dev *edev, unsigned int id) | ||
| 427 | { | ||
| 428 | return extcon_get_state(edev, id); | ||
| 429 | } | ||
| 430 | |||
| 431 | static inline int extcon_set_cable_state_(struct extcon_dev *edev, unsigned int id, | ||
| 432 | bool cable_state) | ||
| 433 | { | ||
| 434 | return extcon_set_state_sync(edev, id, cable_state); | ||
| 435 | } | ||
| 436 | #endif /* __LINUX_EXTCON_H__ */ | 414 | #endif /* __LINUX_EXTCON_H__ */ |
| @@ -132,6 +132,8 @@ struct fmc_operations { · 131 unmodified lines | |||
| 132 | uint32_t (*read32)(struct fmc_device *fmc, int offset); | 132 | uint32_t (*read32)(struct fmc_device *fmc, int offset); |
| 133 | void (*write32)(struct fmc_device *fmc, uint32_t value, int offset); | 133 | void (*write32)(struct fmc_device *fmc, uint32_t value, int offset); |
| 134 | int (*validate)(struct fmc_device *fmc, struct fmc_driver *drv); | 134 | int (*validate)(struct fmc_device *fmc, struct fmc_driver *drv); |
| 135 | int (*reprogram_raw)(struct fmc_device *f, struct fmc_driver *d, | ||
| 136 | void *gw, unsigned long len); | ||
| 135 | int (*reprogram)(struct fmc_device *f, struct fmc_driver *d, char *gw); | 137 | int (*reprogram)(struct fmc_device *f, struct fmc_driver *d, char *gw); |
| 136 | int (*irq_request)(struct fmc_device *fmc, irq_handler_t h, | 138 | int (*irq_request)(struct fmc_device *fmc, irq_handler_t h, |
| 137 | char *name, int flags); | 139 | char *name, int flags); |
| @@ -144,6 +146,8 @@ struct fmc_operations { · 6 unmodified lines | |||
| 144 | }; | 146 | }; |
| 145 | 147 | ||
| 146 | /* Prefer this helper rather than calling of fmc->reprogram directly */ | 148 | /* Prefer this helper rather than calling of fmc->reprogram directly */ |
| 149 | int fmc_reprogram_raw(struct fmc_device *fmc, struct fmc_driver *d, | ||
| 150 | void *gw, unsigned long len, int sdb_entry); | ||
| 147 | extern int fmc_reprogram(struct fmc_device *f, struct fmc_driver *d, char *gw, | 151 | extern int fmc_reprogram(struct fmc_device *f, struct fmc_driver *d, char *gw, |
| 148 | int sdb_entry); | 152 | int sdb_entry); |
| 149 | 153 | ||
| @@ -180,6 +184,9 @@ struct fmc_device { · 30 unmodified lines | |||
| 180 | uint32_t device_id; /* Filled by the device */ | 184 | uint32_t device_id; /* Filled by the device */ |
| 181 | char *mezzanine_name; /* Defaults to ``fmc'' */ | 185 | char *mezzanine_name; /* Defaults to ``fmc'' */ |
| 182 | void *mezzanine_data; | 186 | void *mezzanine_data; |
| 187 | |||
| 188 | struct dentry *dbg_dir; | ||
| 189 | struct dentry *dbg_sdb_dump; | ||
| 183 | }; | 190 | }; |
| 184 | #define to_fmc_device(x) container_of((x), struct fmc_device, dev) | 191 | #define to_fmc_device(x) container_of((x), struct fmc_device, dev) |
| 185 | 192 | ||
| @@ -217,14 +224,23 @@ static inline void fmc_set_drvdata(struct fmc_device *fmc, void *data) · 31 unmodified lines | |||
| 217 | dev_set_drvdata(&fmc->dev, data); | 224 | dev_set_drvdata(&fmc->dev, data); |
| 218 | } | 225 | } |
| 219 | 226 | ||
| 220 | /* The 4 access points */ | 227 | struct fmc_gateware { |
| 228 | void *bitstream; | ||
| 229 | unsigned long len; | ||
| 230 | }; | ||
| 231 | |||
| 232 | /* The 5 access points */ | ||
| 221 | extern int fmc_driver_register(struct fmc_driver *drv); | 233 | extern int fmc_driver_register(struct fmc_driver *drv); |
| 222 | extern void fmc_driver_unregister(struct fmc_driver *drv); | 234 | extern void fmc_driver_unregister(struct fmc_driver *drv); |
| 223 | extern int fmc_device_register(struct fmc_device *tdev); | 235 | extern int fmc_device_register(struct fmc_device *tdev); |
| 236 | extern int fmc_device_register_gw(struct fmc_device *tdev, | ||
| 237 | struct fmc_gateware *gw); | ||
| 224 | extern void fmc_device_unregister(struct fmc_device *tdev); | 238 | extern void fmc_device_unregister(struct fmc_device *tdev); |
| 225 | 239 | ||
| 226 | /* Two more for device sets, all driven by the same FPGA */ | 240 | /* Three more for device sets, all driven by the same FPGA */ |
| 227 | extern int fmc_device_register_n(struct fmc_device **devs, int n); | 241 | extern int fmc_device_register_n(struct fmc_device **devs, int n); |
| 242 | extern int fmc_device_register_n_gw(struct fmc_device **devs, int n, | ||
| 243 | struct fmc_gateware *gw); | ||
| 228 | extern void fmc_device_unregister_n(struct fmc_device **devs, int n); | 244 | extern void fmc_device_unregister_n(struct fmc_device **devs, int n); |
| 229 | 245 | ||
| 230 | /* Internal cross-calls between files; not exported to other modules */ | 246 | /* Internal cross-calls between files; not exported to other modules */ |
| @@ -232,6 +248,23 @@ extern int fmc_match(struct device *dev, struct device_driver *drv); · 1 unmodified line | |||
| 232 | extern int fmc_fill_id_info(struct fmc_device *fmc); | 248 | extern int fmc_fill_id_info(struct fmc_device *fmc); |
| 233 | extern void fmc_free_id_info(struct fmc_device *fmc); | 249 | extern void fmc_free_id_info(struct fmc_device *fmc); |
| 234 | extern void fmc_dump_eeprom(const struct fmc_device *fmc); | 250 | extern void fmc_dump_eeprom(const struct fmc_device *fmc); |
| 235 | extern void fmc_dump_sdb(const struct fmc_device *fmc); | 251 | |
| 252 | /* helpers for FMC operations */ | ||
| 253 | extern int fmc_irq_request(struct fmc_device *fmc, irq_handler_t h, | ||
| 254 | char *name, int flags); | ||
| 255 | extern void fmc_irq_free(struct fmc_device *fmc); | ||
| 256 | extern void fmc_irq_ack(struct fmc_device *fmc); | ||
| 257 | extern int fmc_validate(struct fmc_device *fmc, struct fmc_driver *drv); | ||
| 258 | extern int fmc_gpio_config(struct fmc_device *fmc, struct fmc_gpio *gpio, | ||
| 259 | int ngpio); | ||
| 260 | extern int fmc_read_ee(struct fmc_device *fmc, int pos, void *d, int l); | ||
| 261 | extern int fmc_write_ee(struct fmc_device *fmc, int pos, const void *d, int l); | ||
| 262 | |||
| 263 | /* helpers for FMC operations */ | ||
| 264 | extern int fmc_irq_request(struct fmc_device *fmc, irq_handler_t h, | ||
| 265 | char *name, int flags); | ||
| 266 | extern void fmc_irq_free(struct fmc_device *fmc); | ||
| 267 | extern void fmc_irq_ack(struct fmc_device *fmc); | ||
| 268 | extern int fmc_validate(struct fmc_device *fmc, struct fmc_driver *drv); | ||
| 236 | 269 | ||
| 237 | #endif /* __LINUX_FMC_H__ */ | 270 | #endif /* __LINUX_FMC_H__ */ |
| @@ -67,10 +67,14 @@ enum fpga_mgr_states { · 66 unmodified lines | |||
| 67 | * FPGA Manager flags | 67 | * FPGA Manager flags |
| 68 | * FPGA_MGR_PARTIAL_RECONFIG: do partial reconfiguration if supported | 68 | * FPGA_MGR_PARTIAL_RECONFIG: do partial reconfiguration if supported |
| 69 | * FPGA_MGR_EXTERNAL_CONFIG: FPGA has been configured prior to Linux booting | 69 | * FPGA_MGR_EXTERNAL_CONFIG: FPGA has been configured prior to Linux booting |
| 70 | * FPGA_MGR_BITSTREAM_LSB_FIRST: SPI bitstream bit order is LSB first | ||
| 71 | * FPGA_MGR_COMPRESSED_BITSTREAM: FPGA bitstream is compressed | ||
| 70 | */ | 72 | */ |
| 71 | #define FPGA_MGR_PARTIAL_RECONFIG BIT(0) | 73 | #define FPGA_MGR_PARTIAL_RECONFIG BIT(0) |
| 72 | #define FPGA_MGR_EXTERNAL_CONFIG BIT(1) | 74 | #define FPGA_MGR_EXTERNAL_CONFIG BIT(1) |
| 73 | #define FPGA_MGR_ENCRYPTED_BITSTREAM BIT(2) | 75 | #define FPGA_MGR_ENCRYPTED_BITSTREAM BIT(2) |
| 76 | #define FPGA_MGR_BITSTREAM_LSB_FIRST BIT(3) | ||
| 77 | #define FPGA_MGR_COMPRESSED_BITSTREAM BIT(4) | ||
| 74 | 78 | ||
| 75 | /** | 79 | /** |
| 76 | * struct fpga_image_info - information specific to a FPGA image | 80 | * struct fpga_image_info - information specific to a FPGA image |
| @@ -2473,9 +2473,13 @@ static inline void bd_unlink_disk_holder(struct block_device *bdev, · 2472 unmodified lines | |||
| 2473 | #endif | 2473 | #endif |
| 2474 | 2474 | ||
| 2475 | /* fs/char_dev.c */ | 2475 | /* fs/char_dev.c */ |
| 2476 | #define CHRDEV_MAJOR_HASH_SIZE 255 | 2476 | #define CHRDEV_MAJOR_MAX 512 |
| 2477 | /* Marks the bottom of the first segment of free char majors */ | 2477 | /* Marks the bottom of the first segment of free char majors */ |
| 2478 | #define CHRDEV_MAJOR_DYN_END 234 | 2478 | #define CHRDEV_MAJOR_DYN_END 234 |
| 2479 | /* Marks the top and bottom of the second segment of free char majors */ | ||
| 2480 | #define CHRDEV_MAJOR_DYN_EXT_START 511 | ||
| 2481 | #define CHRDEV_MAJOR_DYN_EXT_END 384 | ||
| 2482 | |||
| 2479 | extern int alloc_chrdev_region(dev_t *, unsigned, unsigned, const char *); | 2483 | extern int alloc_chrdev_region(dev_t *, unsigned, unsigned, const char *); |
| 2480 | extern int register_chrdev_region(dev_t, unsigned, const char *); | 2484 | extern int register_chrdev_region(dev_t, unsigned, const char *); |
| 2481 | extern int __register_chrdev(unsigned int major, unsigned int baseminor, | 2485 | extern int __register_chrdev(unsigned int major, unsigned int baseminor, |
| @@ -2502,14 +2506,14 @@ static inline void unregister_chrdev(unsigned int major, const char *name) · 20 unmodified lines | |||
| 2502 | #define BDEVT_SIZE 10 /* Largest string for MAJ:MIN for blkdev */ | 2506 | #define BDEVT_SIZE 10 /* Largest string for MAJ:MIN for blkdev */ |
| 2503 | 2507 | ||
| 2504 | #ifdef CONFIG_BLOCK | 2508 | #ifdef CONFIG_BLOCK |
| 2505 | #define BLKDEV_MAJOR_HASH_SIZE 255 | 2509 | #define BLKDEV_MAJOR_MAX 512 |
| 2506 | extern const char *__bdevname(dev_t, char *buffer); | 2510 | extern const char *__bdevname(dev_t, char *buffer); |
| 2507 | extern const char *bdevname(struct block_device *bdev, char *buffer); | 2511 | extern const char *bdevname(struct block_device *bdev, char *buffer); |
| 2508 | extern struct block_device *lookup_bdev(const char *); | 2512 | extern struct block_device *lookup_bdev(const char *); |
| 2509 | extern void blkdev_show(struct seq_file *,off_t); | 2513 | extern void blkdev_show(struct seq_file *,off_t); |
| 2510 | 2514 | ||
| 2511 | #else | 2515 | #else |
| 2512 | #define BLKDEV_MAJOR_HASH_SIZE 0 | 2516 | #define BLKDEV_MAJOR_MAX 0 |
| 2513 | #endif | 2517 | #endif |
| 2514 | 2518 | ||
| 2515 | extern void init_special_inode(struct inode *, umode_t, dev_t); | 2519 | extern void init_special_inode(struct inode *, umode_t, dev_t); |
| @@ -124,10 +124,7 @@ struct hv_ring_buffer_info { · 123 unmodified lines | |||
| 124 | spinlock_t ring_lock; | 124 | spinlock_t ring_lock; |
| 125 | 125 | ||
| 126 | u32 ring_datasize; /* < ring_size */ | 126 | u32 ring_datasize; /* < ring_size */ |
| 127 | u32 ring_data_startoffset; | ||
| 128 | u32 priv_write_index; | ||
| 129 | u32 priv_read_index; | 127 | u32 priv_read_index; |
| 130 | u32 cached_read_index; | ||
| 131 | }; | 128 | }; |
| 132 | 129 | ||
| 133 | /* | 130 | /* |
| @@ -180,19 +177,6 @@ static inline u32 hv_get_bytes_to_write(const struct hv_ring_buffer_info *rbi) · 46 unmodified lines | |||
| 180 | return write; | 177 | return write; |
| 181 | } | 178 | } |
| 182 | 179 | ||
| 183 | static inline u32 hv_get_cached_bytes_to_write( | ||
| 184 | const struct hv_ring_buffer_info *rbi) | ||
| 185 | { | ||
| 186 | u32 read_loc, write_loc, dsize, write; | ||
| 187 | |||
| 188 | dsize = rbi->ring_datasize; | ||
| 189 | read_loc = rbi->cached_read_index; | ||
| 190 | write_loc = rbi->ring_buffer->write_index; | ||
| 191 | |||
| 192 | write = write_loc >= read_loc ? dsize - (write_loc - read_loc) : | ||
| 193 | read_loc - write_loc; | ||
| 194 | return write; | ||
| 195 | } | ||
| 196 | /* | 180 | /* |
| 197 | * VMBUS version is 32 bit entity broken up into | 181 | * VMBUS version is 32 bit entity broken up into |
| 198 | * two 16 bit quantities: major_number. minor_number. | 182 | * two 16 bit quantities: major_number. minor_number. |
| @@ -895,6 +879,8 @@ struct vmbus_channel { · 696 unmodified lines | |||
| 895 | */ | 879 | */ |
| 896 | enum hv_numa_policy affinity_policy; | 880 | enum hv_numa_policy affinity_policy; |
| 897 | 881 | ||
| 882 | bool probe_done; | ||
| 883 | |||
| 898 | }; | 884 | }; |
| 899 | 885 | ||
| 900 | static inline bool is_hvsock_channel(const struct vmbus_channel *c) | 886 | static inline bool is_hvsock_channel(const struct vmbus_channel *c) |
| @@ -1473,55 +1459,6 @@ hv_get_ring_buffer(const struct hv_ring_buffer_info *ring_info) · 572 unmodified lines | |||
| 1473 | return ring_info->ring_buffer->buffer; | 1459 | return ring_info->ring_buffer->buffer; |
| 1474 | } | 1460 | } |
| 1475 | 1461 | ||
| 1476 | /* | ||
| 1477 | * To optimize the flow management on the send-side, | ||
| 1478 | * when the sender is blocked because of lack of | ||
| 1479 | * sufficient space in the ring buffer, potential the | ||
| 1480 | * consumer of the ring buffer can signal the producer. | ||
| 1481 | * This is controlled by the following parameters: | ||
| 1482 | * | ||
| 1483 | * 1. pending_send_sz: This is the size in bytes that the | ||
| 1484 | * producer is trying to send. | ||
| 1485 | * 2. The feature bit feat_pending_send_sz set to indicate if | ||
| 1486 | * the consumer of the ring will signal when the ring | ||
| 1487 | * state transitions from being full to a state where | ||
| 1488 | * there is room for the producer to send the pending packet. | ||
| 1489 | */ | ||
| 1490 | |||
| 1491 | static inline void hv_signal_on_read(struct vmbus_channel *channel) | ||
| 1492 | { | ||
| 1493 | u32 cur_write_sz, cached_write_sz; | ||
| 1494 | u32 pending_sz; | ||
| 1495 | struct hv_ring_buffer_info *rbi = &channel->inbound; | ||
| 1496 | |||
| 1497 | /* | ||
| 1498 | * Issue a full memory barrier before making the signaling decision. | ||
| 1499 | * Here is the reason for having this barrier: | ||
| 1500 | * If the reading of the pend_sz (in this function) | ||
| 1501 | * were to be reordered and read before we commit the new read | ||
| 1502 | * index (in the calling function) we could | ||
| 1503 | * have a problem. If the host were to set the pending_sz after we | ||
| 1504 | * have sampled pending_sz and go to sleep before we commit the | ||
| 1505 | * read index, we could miss sending the interrupt. Issue a full | ||
| 1506 | * memory barrier to address this. | ||
| 1507 | */ | ||
| 1508 | virt_mb(); | ||
| 1509 | |||
| 1510 | pending_sz = READ_ONCE(rbi->ring_buffer->pending_send_sz); | ||
| 1511 | /* If the other end is not blocked on write don't bother. */ | ||
| 1512 | if (pending_sz == 0) | ||
| 1513 | return; | ||
| 1514 | |||
| 1515 | cur_write_sz = hv_get_bytes_to_write(rbi); | ||
| 1516 | |||
| 1517 | if (cur_write_sz < pending_sz) | ||
| 1518 | return; | ||
| 1519 | |||
| 1520 | cached_write_sz = hv_get_cached_bytes_to_write(rbi); | ||
| 1521 | if (cached_write_sz < pending_sz) | ||
| 1522 | vmbus_setevent(channel); | ||
| 1523 | } | ||
| 1524 | |||
| 1525 | /* | 1462 | /* |
| 1526 | * Mask off host interrupt callback notifications | 1463 | * Mask off host interrupt callback notifications |
| 1527 | */ | 1464 | */ |
| @@ -285,6 +285,11 @@ enum host_event_code { · 284 unmodified lines | |||
| 285 | EC_HOST_EVENT_HANG_DETECT = 20, | 285 | EC_HOST_EVENT_HANG_DETECT = 20, |
| 286 | /* Hang detect logic detected a hang and warm rebooted the AP */ | 286 | /* Hang detect logic detected a hang and warm rebooted the AP */ |
| 287 | EC_HOST_EVENT_HANG_REBOOT = 21, | 287 | EC_HOST_EVENT_HANG_REBOOT = 21, |
| 288 | /* PD MCU triggering host event */ | ||
| 289 | EC_HOST_EVENT_PD_MCU = 22, | ||
| 290 | |||
| 291 | /* EC desires to change state of host-controlled USB mux */ | ||
| 292 | EC_HOST_EVENT_USB_MUX = 28, | ||
| 288 | 293 | ||
| 289 | /* | 294 | /* |
| 290 | * The high bit of the event mask is not used as a host event code. If | 295 | * The high bit of the event mask is not used as a host event code. If |
| @@ -2905,6 +2910,76 @@ struct ec_params_usb_pd_control { · 2614 unmodified lines | |||
| 2905 | uint8_t mux; | 2910 | uint8_t mux; |
| 2906 | } __packed; | 2911 | } __packed; |
| 2907 | 2912 | ||
| 2913 | #define PD_CTRL_RESP_ENABLED_COMMS (1 << 0) /* Communication enabled */ | ||
| 2914 | #define PD_CTRL_RESP_ENABLED_CONNECTED (1 << 1) /* Device connected */ | ||
| 2915 | #define PD_CTRL_RESP_ENABLED_PD_CAPABLE (1 << 2) /* Partner is PD capable */ | ||
| 2916 | |||
| 2917 | struct ec_response_usb_pd_control_v1 { | ||
| 2918 | uint8_t enabled; | ||
| 2919 | uint8_t role; | ||
| 2920 | uint8_t polarity; | ||
| 2921 | char state[32]; | ||
| 2922 | } __packed; | ||
| 2923 | |||
| 2924 | #define EC_CMD_USB_PD_PORTS 0x102 | ||
| 2925 | |||
| 2926 | struct ec_response_usb_pd_ports { | ||
| 2927 | uint8_t num_ports; | ||
| 2928 | } __packed; | ||
| 2929 | |||
| 2930 | #define EC_CMD_USB_PD_POWER_INFO 0x103 | ||
| 2931 | |||
| 2932 | #define PD_POWER_CHARGING_PORT 0xff | ||
| 2933 | struct ec_params_usb_pd_power_info { | ||
| 2934 | uint8_t port; | ||
| 2935 | } __packed; | ||
| 2936 | |||
| 2937 | enum usb_chg_type { | ||
| 2938 | USB_CHG_TYPE_NONE, | ||
| 2939 | USB_CHG_TYPE_PD, | ||
| 2940 | USB_CHG_TYPE_C, | ||
| 2941 | USB_CHG_TYPE_PROPRIETARY, | ||
| 2942 | USB_CHG_TYPE_BC12_DCP, | ||
| 2943 | USB_CHG_TYPE_BC12_CDP, | ||
| 2944 | USB_CHG_TYPE_BC12_SDP, | ||
| 2945 | USB_CHG_TYPE_OTHER, | ||
| 2946 | USB_CHG_TYPE_VBUS, | ||
| 2947 | USB_CHG_TYPE_UNKNOWN, | ||
| 2948 | }; | ||
| 2949 | |||
| 2950 | struct usb_chg_measures { | ||
| 2951 | uint16_t voltage_max; | ||
| 2952 | uint16_t voltage_now; | ||
| 2953 | uint16_t current_max; | ||
| 2954 | uint16_t current_lim; | ||
| 2955 | } __packed; | ||
| 2956 | |||
| 2957 | struct ec_response_usb_pd_power_info { | ||
| 2958 | uint8_t role; | ||
| 2959 | uint8_t type; | ||
| 2960 | uint8_t dualrole; | ||
| 2961 | uint8_t reserved1; | ||
| 2962 | struct usb_chg_measures meas; | ||
| 2963 | uint32_t max_power; | ||
| 2964 | } __packed; | ||
| 2965 | |||
| 2966 | /* Get info about USB-C SS muxes */ | ||
| 2967 | #define EC_CMD_USB_PD_MUX_INFO 0x11a | ||
| 2968 | |||
| 2969 | struct ec_params_usb_pd_mux_info { | ||
| 2970 | uint8_t port; /* USB-C port number */ | ||
| 2971 | } __packed; | ||
| 2972 | |||
| 2973 | /* Flags representing mux state */ | ||
| 2974 | #define USB_PD_MUX_USB_ENABLED (1 << 0) | ||
| 2975 | #define USB_PD_MUX_DP_ENABLED (1 << 1) | ||
| 2976 | #define USB_PD_MUX_POLARITY_INVERTED (1 << 2) | ||
| 2977 | #define USB_PD_MUX_HPD_IRQ (1 << 3) | ||
| 2978 | |||
| 2979 | struct ec_response_usb_pd_mux_info { | ||
| 2980 | uint8_t flags; /* USB_PD_MUX_*-encoded USB mux state */ | ||
| 2981 | } __packed; | ||
| 2982 | |||
| 2908 | /*****************************************************************************/ | 2983 | /*****************************************************************************/ |
| 2909 | /* | 2984 | /* |
| 2910 | * Passthru commands | 2985 | * Passthru commands |
| @@ -1,13 +1,28 @@ | |||
| 1 | /* MFD cell driver data for the DS1WM driver */ | 1 | /* MFD cell driver data for the DS1WM driver |
| 2 | * | ||
| 3 | * to be defined in the MFD device that is | ||
| 4 | * using this driver for one of his sub devices | ||
| 5 | */ | ||
| 2 | 6 | ||
| 3 | struct ds1wm_driver_data { | 7 | struct ds1wm_driver_data { |
| 4 | int active_high; | 8 | int active_high; |
| 5 | int clock_rate; | 9 | int clock_rate; |
| 6 | /* in milliseconds, the amount of time to */ | 10 | /* in milliseconds, the amount of time to |
| 7 | /* sleep following a reset pulse. Zero */ | 11 | * sleep following a reset pulse. Zero |
| 8 | /* should work if your bus devices recover*/ | 12 | * should work if your bus devices recover |
| 9 | /* time respects the 1-wire spec since the*/ | 13 | * time respects the 1-wire spec since the |
| 10 | /* ds1wm implements the precise timings of*/ | 14 | * ds1wm implements the precise timings of |
| 11 | /* a reset pulse/presence detect sequence.*/ | 15 | * a reset pulse/presence detect sequence. |
| 16 | */ | ||
| 12 | unsigned int reset_recover_delay; | 17 | unsigned int reset_recover_delay; |
| 18 | |||
| 19 | /* Say 1 here for big endian Hardware | ||
| 20 | * (only relevant with bus-shift > 0 | ||
| 21 | */ | ||
| 22 | bool is_hw_big_endian; | ||
| 23 | |||
| 24 | /* left shift of register number to get register address offsett. | ||
| 25 | * Only 0,1,2 allowed for 8,16 or 32 bit bus width respectively | ||
| 26 | */ | ||
| 27 | unsigned int bus_shift; | ||
| 13 | }; | 28 | }; |
| @@ -13,6 +13,8 @@ · 12 unmodified lines | |||
| 13 | #ifndef _LINUX_MUX_CONSUMER_H | 13 | #ifndef _LINUX_MUX_CONSUMER_H |
| 14 | #define _LINUX_MUX_CONSUMER_H | 14 | #define _LINUX_MUX_CONSUMER_H |
| 15 | 15 | ||
| 16 | #include <linux/compiler.h> | ||
| 17 | |||
| 16 | struct device; | 18 | struct device; |
| 17 | struct mux_control; | 19 | struct mux_control; |
| 18 | 20 | ||
| @@ -12,6 +12,9 @@ · 11 unmodified lines | |||
| 12 | #ifndef _LINUX_NVMEM_CONSUMER_H | 12 | #ifndef _LINUX_NVMEM_CONSUMER_H |
| 13 | #define _LINUX_NVMEM_CONSUMER_H | 13 | #define _LINUX_NVMEM_CONSUMER_H |
| 14 | 14 | ||
| 15 | #include <linux/err.h> | ||
| 16 | #include <linux/errno.h> | ||
| 17 | |||
| 15 | struct device; | 18 | struct device; |
| 16 | struct device_node; | 19 | struct device_node; |
| 17 | /* consumer cookie */ | 20 | /* consumer cookie */ |
| @@ -35,6 +38,7 @@ void nvmem_cell_put(struct nvmem_cell *cell); · 17 unmodified lines | |||
| 35 | void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell); | 38 | void devm_nvmem_cell_put(struct device *dev, struct nvmem_cell *cell); |
| 36 | void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len); | 39 | void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len); |
| 37 | int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len); | 40 | int nvmem_cell_write(struct nvmem_cell *cell, void *buf, size_t len); |
| 41 | int nvmem_cell_read_u32(struct device *dev, const char *cell_id, u32 *val); | ||
| 38 | 42 | ||
| 39 | /* direct nvmem device read/write interface */ | 43 | /* direct nvmem device read/write interface */ |
| 40 | struct nvmem_device *nvmem_device_get(struct device *dev, const char *name); | 44 | struct nvmem_device *nvmem_device_get(struct device *dev, const char *name); |
| @@ -85,6 +89,12 @@ static inline int nvmem_cell_write(struct nvmem_cell *cell, · 44 unmodified lines | |||
| 85 | return -ENOSYS; | 89 | return -ENOSYS; |
| 86 | } | 90 | } |
| 87 | 91 | ||
| 92 | static inline int nvmem_cell_read_u32(struct device *dev, | ||
| 93 | const char *cell_id, u32 *val) | ||
| 94 | { | ||
| 95 | return -ENOSYS; | ||
| 96 | } | ||
| 97 | |||
| 88 | static inline struct nvmem_device *nvmem_device_get(struct device *dev, | 98 | static inline struct nvmem_device *nvmem_device_get(struct device *dev, |
| 89 | const char *name) | 99 | const char *name) |
| 90 | { | 100 | { |
| @@ -68,6 +68,7 @@ struct w1_reg_num { · 67 unmodified lines | |||
| 68 | * @family: module for device family type | 68 | * @family: module for device family type |
| 69 | * @family_data: pointer for use by the family module | 69 | * @family_data: pointer for use by the family module |
| 70 | * @dev: kernel device identifier | 70 | * @dev: kernel device identifier |
| 71 | * @hwmon: pointer to hwmon device | ||
| 71 | * | 72 | * |
| 72 | */ | 73 | */ |
| 73 | struct w1_slave { | 74 | struct w1_slave { |
| @@ -83,6 +84,7 @@ struct w1_slave { · 9 unmodified lines | |||
| 83 | struct w1_family *family; | 84 | struct w1_family *family; |
| 84 | void *family_data; | 85 | void *family_data; |
| 85 | struct device dev; | 86 | struct device dev; |
| 87 | struct device *hwmon; | ||
| 86 | }; | 88 | }; |
| 87 | 89 | ||
| 88 | typedef void (*w1_slave_found_callback)(struct w1_master *, u64); | 90 | typedef void (*w1_slave_found_callback)(struct w1_master *, u64); |
| @@ -250,11 +252,13 @@ void w1_remove_master_device(struct w1_bus_master *master); · 161 unmodified lines | |||
| 250 | * @add_slave: add_slave | 252 | * @add_slave: add_slave |
| 251 | * @remove_slave: remove_slave | 253 | * @remove_slave: remove_slave |
| 252 | * @groups: sysfs group | 254 | * @groups: sysfs group |
| 255 | * @chip_info: pointer to struct hwmon_chip_info | ||
| 253 | */ | 256 | */ |
| 254 | struct w1_family_ops { | 257 | struct w1_family_ops { |
| 255 | int (*add_slave)(struct w1_slave *sl); | 258 | int (*add_slave)(struct w1_slave *sl); |
| 256 | void (*remove_slave)(struct w1_slave *sl); | 259 | void (*remove_slave)(struct w1_slave *sl); |
| 257 | const struct attribute_group **groups; | 260 | const struct attribute_group **groups; |
| 261 | const struct hwmon_chip_info *chip_info; | ||
| 258 | }; | 262 | }; |
| 259 | 263 | ||
| 260 | /** | 264 | /** |
| @@ -132,6 +132,7 @@ enum { · 131 unmodified lines | |||
| 132 | 132 | ||
| 133 | /* struct binder_fd_array_object - object describing an array of fds in a buffer | 133 | /* struct binder_fd_array_object - object describing an array of fds in a buffer |
| 134 | * @hdr: common header structure | 134 | * @hdr: common header structure |
| 135 | * @pad: padding to ensure correct alignment | ||
| 135 | * @num_fds: number of file descriptors in the buffer | 136 | * @num_fds: number of file descriptors in the buffer |
| 136 | * @parent: index in offset array to buffer holding the fd array | 137 | * @parent: index in offset array to buffer holding the fd array |
| 137 | * @parent_offset: start offset of fd array in the buffer | 138 | * @parent_offset: start offset of fd array in the buffer |
| @@ -152,6 +153,7 @@ enum { · 14 unmodified lines | |||
| 152 | */ | 153 | */ |
| 153 | struct binder_fd_array_object { | 154 | struct binder_fd_array_object { |
| 154 | struct binder_object_header hdr; | 155 | struct binder_object_header hdr; |
| 156 | __u32 pad; | ||
| 155 | binder_size_t num_fds; | 157 | binder_size_t num_fds; |
| 156 | binder_size_t parent; | 158 | binder_size_t parent; |
| 157 | binder_size_t parent_offset; | 159 | binder_size_t parent_offset; |
| @@ -184,6 +186,19 @@ struct binder_version { · 26 unmodified lines | |||
| 184 | #define BINDER_CURRENT_PROTOCOL_VERSION 8 | 186 | #define BINDER_CURRENT_PROTOCOL_VERSION 8 |
| 185 | #endif | 187 | #endif |
| 186 | 188 | ||
| 189 | /* | ||
| 190 | * Use with BINDER_GET_NODE_DEBUG_INFO, driver reads ptr, writes to all fields. | ||
| 191 | * Set ptr to NULL for the first call to get the info for the first node, and | ||
| 192 | * then repeat the call passing the previously returned value to get the next | ||
| 193 | * nodes. ptr will be 0 when there are no more nodes. | ||
| 194 | */ | ||
| 195 | struct binder_node_debug_info { | ||
| 196 | binder_uintptr_t ptr; | ||
| 197 | binder_uintptr_t cookie; | ||
| 198 | __u32 has_strong_ref; | ||
| 199 | __u32 has_weak_ref; | ||
| 200 | }; | ||
| 201 | |||
| 187 | #define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read) | 202 | #define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read) |
| 188 | #define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64) | 203 | #define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64) |
| 189 | #define BINDER_SET_MAX_THREADS _IOW('b', 5, __u32) | 204 | #define BINDER_SET_MAX_THREADS _IOW('b', 5, __u32) |
| @@ -191,6 +206,7 @@ struct binder_version { · 1 unmodified line | |||
| 191 | #define BINDER_SET_CONTEXT_MGR _IOW('b', 7, __s32) | 206 | #define BINDER_SET_CONTEXT_MGR _IOW('b', 7, __s32) |
| 192 | #define BINDER_THREAD_EXIT _IOW('b', 8, __s32) | 207 | #define BINDER_THREAD_EXIT _IOW('b', 8, __s32) |
| 193 | #define BINDER_VERSION _IOWR('b', 9, struct binder_version) | 208 | #define BINDER_VERSION _IOWR('b', 9, struct binder_version) |
| 209 | #define BINDER_GET_NODE_DEBUG_INFO _IOWR('b', 11, struct binder_node_debug_info) | ||
| 194 | 210 | ||
| 195 | /* | 211 | /* |
| 196 | * NOTE: Two special error codes you should check for when calling | 212 | * NOTE: Two special error codes you should check for when calling |
| @@ -10,6 +10,7 @@ · 9 unmodified lines | |||
| 10 | # CONFIG_USELIB is not set | 10 | # CONFIG_USELIB is not set |
| 11 | CONFIG_ANDROID=y | 11 | CONFIG_ANDROID=y |
| 12 | CONFIG_ANDROID_BINDER_IPC=y | 12 | CONFIG_ANDROID_BINDER_IPC=y |
| 13 | CONFIG_ANDROID_BINDER_DEVICES=binder,hwbinder,vndbinder | ||
| 13 | CONFIG_ANDROID_LOW_MEMORY_KILLER=y | 14 | CONFIG_ANDROID_LOW_MEMORY_KILLER=y |
| 14 | CONFIG_ARMV8_DEPRECATED=y | 15 | CONFIG_ARMV8_DEPRECATED=y |
| 15 | CONFIG_ASHMEM=y | 16 | CONFIG_ASHMEM=y |
| @@ -138,14 +138,17 @@ void print_usage(char *argv[]) · 137 unmodified lines | |||
| 138 | 138 | ||
| 139 | int main(int argc, char *argv[]) | 139 | int main(int argc, char *argv[]) |
| 140 | { | 140 | { |
| 141 | int fcopy_fd, len; | 141 | int fcopy_fd; |
| 142 | int error; | 142 | int error; |
| 143 | int daemonize = 1, long_index = 0, opt; | 143 | int daemonize = 1, long_index = 0, opt; |
| 144 | int version = FCOPY_CURRENT_VERSION; | 144 | int version = FCOPY_CURRENT_VERSION; |
| 145 | char *buffer[4096 * 2]; | 145 | union { |
| 146 | struct hv_fcopy_hdr *in_msg; | 146 | struct hv_fcopy_hdr hdr; |
| 147 | struct hv_start_fcopy start; | ||
| 148 | struct hv_do_fcopy copy; | ||
| 149 | __u32 kernel_modver; | ||
| 150 | } buffer = { }; | ||
| 147 | int in_handshake = 1; | 151 | int in_handshake = 1; |
| 148 | __u32 kernel_modver; | ||
| 149 | 152 | ||
| 150 | static struct option long_options[] = { | 153 | static struct option long_options[] = { |
| 151 | {"help", no_argument, 0, 'h' }, | 154 | {"help", no_argument, 0, 'h' }, |
| @@ -195,32 +198,31 @@ int main(int argc, char *argv[]) · 43 unmodified lines | |||
| 195 | * In this loop we process fcopy messages after the | 198 | * In this loop we process fcopy messages after the |
| 196 | * handshake is complete. | 199 | * handshake is complete. |
| 197 | */ | 200 | */ |
| 198 | len = pread(fcopy_fd, buffer, (4096 * 2), 0); | 201 | ssize_t len; |
| 202 | |||
| 203 | len = pread(fcopy_fd, &buffer, sizeof(buffer), 0); | ||
| 199 | if (len < 0) { | 204 | if (len < 0) { |
| 200 | syslog(LOG_ERR, "pread failed: %s", strerror(errno)); | 205 | syslog(LOG_ERR, "pread failed: %s", strerror(errno)); |
| 201 | exit(EXIT_FAILURE); | 206 | exit(EXIT_FAILURE); |
| 202 | } | 207 | } |
| 203 | 208 | ||
| 204 | if (in_handshake) { | 209 | if (in_handshake) { |
| 205 | if (len != sizeof(kernel_modver)) { | 210 | if (len != sizeof(buffer.kernel_modver)) { |
| 206 | syslog(LOG_ERR, "invalid version negotiation"); | 211 | syslog(LOG_ERR, "invalid version negotiation"); |
| 207 | exit(EXIT_FAILURE); | 212 | exit(EXIT_FAILURE); |
| 208 | } | 213 | } |
| 209 | kernel_modver = *(__u32 *)buffer; | ||
| 210 | in_handshake = 0; | 214 | in_handshake = 0; |
| 211 | syslog(LOG_INFO, "kernel module version: %d", | 215 | syslog(LOG_INFO, "kernel module version: %u", |
| 212 | kernel_modver); | 216 | buffer.kernel_modver); |
| 213 | continue; | 217 | continue; |
| 214 | } | 218 | } |
| 215 | 219 | ||
| 216 | in_msg = (struct hv_fcopy_hdr *)buffer; | 220 | switch (buffer.hdr.operation) { |
| 217 | |||
| 218 | switch (in_msg->operation) { | ||
| 219 | case START_FILE_COPY: | 221 | case START_FILE_COPY: |
| 220 | error = hv_start_fcopy((struct hv_start_fcopy *)in_msg); | 222 | error = hv_start_fcopy(&buffer.start); |
| 221 | break; | 223 | break; |
| 222 | case WRITE_TO_FILE: | 224 | case WRITE_TO_FILE: |
| 223 | error = hv_copy_data((struct hv_do_fcopy *)in_msg); | 225 | error = hv_copy_data(&buffer.copy); |
| 224 | break; | 226 | break; |
| 225 | case COMPLETE_FCOPY: | 227 | case COMPLETE_FCOPY: |
| 226 | error = hv_copy_finished(); | 228 | error = hv_copy_finished(); |
| @@ -231,7 +233,7 @@ int main(int argc, char *argv[]) · 4 unmodified lines | |||
| 231 | 233 | ||
| 232 | default: | 234 | default: |
| 233 | syslog(LOG_ERR, "Unknown operation: %d", | 235 | syslog(LOG_ERR, "Unknown operation: %d", |
| 234 | in_msg->operation); | 236 | buffer.hdr.operation); |
| 235 | 237 | ||
| 236 | } | 238 | } |
| 237 | 239 | ||
| @@ -1136,7 +1136,7 @@ static int process_ip_string(FILE *f, char *ip_string, int type) · 1135 unmodified lines | |||
| 1136 | int i = 0; | 1136 | int i = 0; |
| 1137 | int j = 0; | 1137 | int j = 0; |
| 1138 | char str[256]; | 1138 | char str[256]; |
| 1139 | char sub_str[10]; | 1139 | char sub_str[13]; |
| 1140 | int offset = 0; | 1140 | int offset = 0; |
| 1141 | 1141 | ||
| 1142 | memset(addr, 0, sizeof(addr)); | 1142 | memset(addr, 0, sizeof(addr)); |
| @@ -21,6 +21,7 @@ · 20 unmodified lines | |||
| 21 | #include <sys/types.h> | 21 | #include <sys/types.h> |
| 22 | #include <sys/poll.h> | 22 | #include <sys/poll.h> |
| 23 | #include <sys/ioctl.h> | 23 | #include <sys/ioctl.h> |
| 24 | #include <sys/stat.h> | ||
| 24 | #include <fcntl.h> | 25 | #include <fcntl.h> |
| 25 | #include <stdio.h> | 26 | #include <stdio.h> |
| 26 | #include <mntent.h> | 27 | #include <mntent.h> |
| @@ -30,6 +31,7 @@ · 3 unmodified lines | |||
| 30 | #include <ctype.h> | 31 | #include <ctype.h> |
| 31 | #include <errno.h> | 32 | #include <errno.h> |
| 32 | #include <linux/fs.h> | 33 | #include <linux/fs.h> |
| 34 | #include <linux/major.h> | ||
| 33 | #include <linux/hyperv.h> | 35 | #include <linux/hyperv.h> |
| 34 | #include <syslog.h> | 36 | #include <syslog.h> |
| 35 | #include <getopt.h> | 37 | #include <getopt.h> |
| @@ -70,6 +72,7 @@ static int vss_operate(int operation) · 34 unmodified lines | |||
| 70 | char match[] = "/dev/"; | 72 | char match[] = "/dev/"; |
| 71 | FILE *mounts; | 73 | FILE *mounts; |
| 72 | struct mntent *ent; | 74 | struct mntent *ent; |
| 75 | struct stat sb; | ||
| 73 | char errdir[1024] = {0}; | 76 | char errdir[1024] = {0}; |
| 74 | unsigned int cmd; | 77 | unsigned int cmd; |
| 75 | int error = 0, root_seen = 0, save_errno = 0; | 78 | int error = 0, root_seen = 0, save_errno = 0; |
| @@ -92,6 +95,10 @@ static int vss_operate(int operation) · 16 unmodified lines | |||
| 92 | while ((ent = getmntent(mounts))) { | 95 | while ((ent = getmntent(mounts))) { |
| 93 | if (strncmp(ent->mnt_fsname, match, strlen(match))) | 96 | if (strncmp(ent->mnt_fsname, match, strlen(match))) |
| 94 | continue; | 97 | continue; |
| 98 | if (stat(ent->mnt_fsname, &sb) == -1) | ||
| 99 | continue; | ||
| 100 | if (S_ISBLK(sb.st_mode) && major(sb.st_rdev) == LOOP_MAJOR) | ||
| 101 | continue; | ||
| 95 | if (hasmntopt(ent, MNTOPT_RO) != NULL) | 102 | if (hasmntopt(ent, MNTOPT_RO) != NULL) |
| 96 | continue; | 103 | continue; |
| 97 | if (strcmp(ent->mnt_type, "vfat") == 0) | 104 | if (strcmp(ent->mnt_type, "vfat") == 0) |
| @@ -24,6 +24,12 @@ · 23 unmodified lines | |||
| 24 | /* ETMv3.5/PTM's ETMCR config bit */ | 24 | /* ETMv3.5/PTM's ETMCR config bit */ |
| 25 | #define ETM_OPT_CYCACC 12 | 25 | #define ETM_OPT_CYCACC 12 |
| 26 | #define ETM_OPT_TS 28 | 26 | #define ETM_OPT_TS 28 |
| 27 | #define ETM_OPT_RETSTK 29 | ||
| 28 | |||
| 29 | /* ETMv4 CONFIGR programming bits for the ETM OPTs */ | ||
| 30 | #define ETM4_CFG_BIT_CYCACC 4 | ||
| 31 | #define ETM4_CFG_BIT_TS 11 | ||
| 32 | #define ETM4_CFG_BIT_RETSTK 12 | ||
| 27 | 33 | ||
| 28 | static inline int coresight_get_trace_id(int cpu) | 34 | static inline int coresight_get_trace_id(int cpu) |
| 29 | { | 35 | { |
| @@ -266,6 +266,32 @@ static u64 cs_etm_get_config(struct auxtrace_record *itr) · 265 unmodified lines | |||
| 266 | return config; | 266 | return config; |
| 267 | } | 267 | } |
| 268 | 268 | ||
| 269 | #ifndef BIT | ||
| 270 | #define BIT(N) (1UL << (N)) | ||
| 271 | #endif | ||
| 272 | |||
| 273 | static u64 cs_etmv4_get_config(struct auxtrace_record *itr) | ||
| 274 | { | ||
| 275 | u64 config = 0; | ||
| 276 | u64 config_opts = 0; | ||
| 277 | |||
| 278 | /* | ||
| 279 | * The perf event variable config bits represent both | ||
| 280 | * the command line options and register programming | ||
| 281 | * bits in ETMv3/PTM. For ETMv4 we must remap options | ||
| 282 | * to real bits | ||
| 283 | */ | ||
| 284 | config_opts = cs_etm_get_config(itr); | ||
| 285 | if (config_opts & BIT(ETM_OPT_CYCACC)) | ||
| 286 | config |= BIT(ETM4_CFG_BIT_CYCACC); | ||
| 287 | if (config_opts & BIT(ETM_OPT_TS)) | ||
| 288 | config |= BIT(ETM4_CFG_BIT_TS); | ||
| 289 | if (config_opts & BIT(ETM_OPT_RETSTK)) | ||
| 290 | config |= BIT(ETM4_CFG_BIT_RETSTK); | ||
| 291 | |||
| 292 | return config; | ||
| 293 | } | ||
| 294 | |||
| 269 | static size_t | 295 | static size_t |
| 270 | cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused, | 296 | cs_etm_info_priv_size(struct auxtrace_record *itr __maybe_unused, |
| 271 | struct perf_evlist *evlist __maybe_unused) | 297 | struct perf_evlist *evlist __maybe_unused) |
| @@ -363,7 +389,7 @@ static void cs_etm_get_metadata(int cpu, u32 *offset, · 91 unmodified lines | |||
| 363 | magic = __perf_cs_etmv4_magic; | 389 | magic = __perf_cs_etmv4_magic; |
| 364 | /* Get trace configuration register */ | 390 | /* Get trace configuration register */ |
| 365 | info->priv[*offset + CS_ETMV4_TRCCONFIGR] = | 391 | info->priv[*offset + CS_ETMV4_TRCCONFIGR] = |
| 366 | cs_etm_get_config(itr); | 392 | cs_etmv4_get_config(itr); |
| 367 | /* Get traceID from the framework */ | 393 | /* Get traceID from the framework */ |
| 368 | info->priv[*offset + CS_ETMV4_TRCTRACEIDR] = | 394 | info->priv[*offset + CS_ETMV4_TRCTRACEIDR] = |
| 369 | coresight_get_trace_id(cpu); | 395 | coresight_get_trace_id(cpu); |