Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'rproc-v5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/andersson/remoteproc

Pull remoteproc updates from Bjorn Andersson:
"This introduces a new "detached" state for remote processors that are
deemed to be running at the time Linux boots and the infrastructure
for "attaching" to these. It then introduces the support for
performing this operation for the STM32 platform.

The coredump functionality is moved out from the core file and gains
support for an optional mode where the recovery phase awaits the
notification from devcoredump that the dump should be released. This
allows userspace to grab the coredump in scenarios where vmalloc space
is too low for creating a complete copy of the coredump before handing
this to devcoredump.

A new character device based interface is introduced to allow tying
the stoppage of a remote processor to the termination of a user space
process. This is useful in situations when such process provides
crucial resources/operations for the firmware running on the remote
processor.

The Texas Instrument K3 driver gains support for the C66x and C71x
DSPs.

Qualcomm remoteprocs gains support for stashing relocation information
in IMEM, to aid post mortem debugging and the crash notification
mechanism is generalized to be reusable in cases where loosely coupled
drivers needs to know about the status of a remote processor. One such
example is the IPA hardware block, which is jointly owned with the
modem and migrated to this improved interface.

It also introduces a number of bug fixes and debug improvements for
the Qualcomm modem remoteproc driver.

And it cleans up the inconsistent interface for remoteproc drivers to
implement power management"

* tag 'rproc-v5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/andersson/remoteproc: (56 commits)
remoteproc: core: Register the character device interface
remoteproc: Add remoteproc character device interface
remoteproc: kill IPA notify code
net: ipa: new notification infrastructure
remoteproc: k3-dsp: Add support for C71x DSPs
dt-bindings: remoteproc: k3-dsp: Update bindings for C71x DSPs
remoteproc: k3-dsp: Add support for L2RAM loading on C66x DSPs
remoteproc: k3-dsp: Add a remoteproc driver of K3 C66x DSPs
dt-bindings: remoteproc: Add bindings for C66x DSPs on TI K3 SoCs
remoteproc: k3: Add TI-SCI processor control helper functions
remoteproc: Introduce rproc_of_parse_firmware() helper
dt-bindings: arm: keystone: Add common TI SCI bindings
remoteproc: qcom_q6v5_mss: Remove redundant running state
remoteproc: qcom: q6v5: Update running state before requesting stop
remoteproc: qcom_q6v5_mss: Add modem debug policy support
remoteproc: qcom_q6v5_mss: Validate modem blob firmware size before load
remoteproc: qcom_q6v5_mss: Validate MBA firmware size before load
rpmsg: update documentation
remoteproc: qcom_q6v5_mss: Add MBA log extraction support
remoteproc: Add coredump debugfs entry
...

+2796 -602
+44
Documentation/devicetree/bindings/arm/keystone/ti,k3-sci-common.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only or BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/arm/keystone/ti,k3-sci-common.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Common K3 TI-SCI bindings 8 + 9 + maintainers: 10 + - Nishanth Menon <nm@ti.com> 11 + 12 + description: | 13 + The TI K3 family of SoCs usually have a central System Controller Processor 14 + that is responsible for managing various SoC-level resources like clocks, 15 + resets, interrupts etc. The communication with that processor is performed 16 + through the TI-SCI protocol. 17 + 18 + Each specific device management node like a clock controller node, a reset 19 + controller node or an interrupt-controller node should define a common set 20 + of properties that enables them to implement the corresponding functionality 21 + over the TI-SCI protocol. The following are some of the common properties 22 + needed by such individual nodes. The required properties for each device 23 + management node is defined in the respective binding. 24 + 25 + properties: 26 + ti,sci: 27 + $ref: /schemas/types.yaml#/definitions/phandle 28 + description: 29 + Should be a phandle to the TI-SCI System Controller node 30 + 31 + ti,sci-dev-id: 32 + $ref: /schemas/types.yaml#/definitions/uint32 33 + description: | 34 + Should contain the TI-SCI device id corresponding to the device. Please 35 + refer to the corresponding System Controller documentation for valid 36 + values for the desired device. 37 + 38 + ti,sci-proc-ids: 39 + description: Should contain a single tuple of <proc_id host_id>. 40 + $ref: /schemas/types.yaml#/definitions/uint32-array 41 + items: 42 + - description: TI-SCI processor id for the remote processor device 43 + - description: TI-SCI host id to which processor control ownership 44 + should be transferred to
+44
Documentation/devicetree/bindings/remoteproc/qcom,pil-info.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/remoteproc/qcom,pil-info.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Qualcomm peripheral image loader relocation info binding 8 + 9 + maintainers: 10 + - Bjorn Andersson <bjorn.andersson@linaro.org> 11 + 12 + description: 13 + The Qualcomm peripheral image loader relocation memory region, in IMEM, is 14 + used for communicating remoteproc relocation information to post mortem 15 + debugging tools. 16 + 17 + properties: 18 + compatible: 19 + const: qcom,pil-reloc-info 20 + 21 + reg: 22 + maxItems: 1 23 + 24 + required: 25 + - compatible 26 + - reg 27 + 28 + examples: 29 + - | 30 + imem@146bf000 { 31 + compatible = "syscon", "simple-mfd"; 32 + reg = <0x146bf000 0x1000>; 33 + 34 + #address-cells = <1>; 35 + #size-cells = <1>; 36 + 37 + ranges = <0 0x146bf000 0x1000>; 38 + 39 + pil-reloc@94c { 40 + compatible = "qcom,pil-reloc-info"; 41 + reg = <0x94c 0xc8>; 42 + }; 43 + }; 44 + ...
+184
Documentation/devicetree/bindings/remoteproc/ti,k3-dsp-rproc.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only or BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/remoteproc/ti,k3-dsp-rproc.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: TI K3 DSP devices 8 + 9 + maintainers: 10 + - Suman Anna <s-anna@ti.com> 11 + 12 + description: | 13 + The TI K3 family of SoCs usually have one or more TI DSP Core sub-systems 14 + that are used to offload some of the processor-intensive tasks or algorithms, 15 + for achieving various system level goals. 16 + 17 + These processor sub-systems usually contain additional sub-modules like 18 + L1 and/or L2 caches/SRAMs, an Interrupt Controller, an external memory 19 + controller, a dedicated local power/sleep controller etc. The DSP processor 20 + cores in the K3 SoCs are usually either a TMS320C66x CorePac processor or a 21 + TMS320C71x CorePac processor. 22 + 23 + Each DSP Core sub-system is represented as a single DT node. Each node has a 24 + number of required or optional properties that enable the OS running on the 25 + host processor (Arm CorePac) to perform the device management of the remote 26 + processor and to communicate with the remote processor. 27 + 28 + allOf: 29 + - $ref: /schemas/arm/keystone/ti,k3-sci-common.yaml# 30 + 31 + properties: 32 + compatible: 33 + enum: 34 + - ti,j721e-c66-dsp 35 + - ti,j721e-c71-dsp 36 + description: 37 + Use "ti,j721e-c66-dsp" for C66x DSPs on K3 J721E SoCs 38 + Use "ti,j721e-c71-dsp" for C71x DSPs on K3 J721E SoCs 39 + 40 + resets: 41 + description: | 42 + Should contain the phandle to the reset controller node managing the 43 + local resets for this device, and a reset specifier. 44 + maxItems: 1 45 + 46 + firmware-name: 47 + description: | 48 + Should contain the name of the default firmware image 49 + file located on the firmware search path 50 + 51 + mboxes: 52 + description: | 53 + OMAP Mailbox specifier denoting the sub-mailbox, to be used for 54 + communication with the remote processor. This property should match 55 + with the sub-mailbox node used in the firmware image. 56 + maxItems: 1 57 + 58 + memory-region: 59 + minItems: 2 60 + maxItems: 8 61 + description: | 62 + phandle to the reserved memory nodes to be associated with the remoteproc 63 + device. There should be at least two reserved memory nodes defined. The 64 + reserved memory nodes should be carveout nodes, and should be defined as 65 + per the bindings in 66 + Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt 67 + items: 68 + - description: region used for dynamic DMA allocations like vrings and 69 + vring buffers 70 + - description: region reserved for firmware image sections 71 + additionalItems: true 72 + 73 + # Optional properties: 74 + # -------------------- 75 + 76 + sram: 77 + $ref: /schemas/types.yaml#/definitions/phandle-array 78 + minItems: 1 79 + maxItems: 4 80 + description: | 81 + phandles to one or more reserved on-chip SRAM regions. The regions 82 + should be defined as child nodes of the respective SRAM node, and 83 + should be defined as per the generic bindings in, 84 + Documentation/devicetree/bindings/sram/sram.yaml 85 + 86 + if: 87 + properties: 88 + compatible: 89 + enum: 90 + - ti,j721e-c66-dsp 91 + then: 92 + properties: 93 + reg: 94 + items: 95 + - description: Address and Size of the L2 SRAM internal memory region 96 + - description: Address and Size of the L1 PRAM internal memory region 97 + - description: Address and Size of the L1 DRAM internal memory region 98 + reg-names: 99 + items: 100 + - const: l2sram 101 + - const: l1pram 102 + - const: l1dram 103 + else: 104 + if: 105 + properties: 106 + compatible: 107 + enum: 108 + - ti,j721e-c71-dsp 109 + then: 110 + properties: 111 + reg: 112 + items: 113 + - description: Address and Size of the L2 SRAM internal memory region 114 + - description: Address and Size of the L1 DRAM internal memory region 115 + reg-names: 116 + items: 117 + - const: l2sram 118 + - const: l1dram 119 + 120 + required: 121 + - compatible 122 + - reg 123 + - reg-names 124 + - ti,sci 125 + - ti,sci-dev-id 126 + - ti,sci-proc-ids 127 + - resets 128 + - firmware-name 129 + - mboxes 130 + - memory-region 131 + 132 + unevaluatedProperties: false 133 + 134 + examples: 135 + - | 136 + / { 137 + model = "Texas Instruments K3 J721E SoC"; 138 + compatible = "ti,j721e"; 139 + #address-cells = <2>; 140 + #size-cells = <2>; 141 + 142 + bus@100000 { 143 + compatible = "simple-bus"; 144 + #address-cells = <2>; 145 + #size-cells = <2>; 146 + ranges = <0x00 0x00100000 0x00 0x00100000 0x00 0x00020000>, /* ctrl mmr */ 147 + <0x00 0x64800000 0x00 0x64800000 0x00 0x00800000>, /* C71_0 */ 148 + <0x4d 0x80800000 0x4d 0x80800000 0x00 0x00800000>, /* C66_0 */ 149 + <0x4d 0x81800000 0x4d 0x81800000 0x00 0x00800000>; /* C66_1 */ 150 + 151 + /* J721E C66_0 DSP node */ 152 + dsp@4d80800000 { 153 + compatible = "ti,j721e-c66-dsp"; 154 + reg = <0x4d 0x80800000 0x00 0x00048000>, 155 + <0x4d 0x80e00000 0x00 0x00008000>, 156 + <0x4d 0x80f00000 0x00 0x00008000>; 157 + reg-names = "l2sram", "l1pram", "l1dram"; 158 + ti,sci = <&dmsc>; 159 + ti,sci-dev-id = <142>; 160 + ti,sci-proc-ids = <0x03 0xFF>; 161 + resets = <&k3_reset 142 1>; 162 + firmware-name = "j7-c66_0-fw"; 163 + memory-region = <&c66_0_dma_memory_region>, 164 + <&c66_0_memory_region>; 165 + mboxes = <&mailbox0_cluster3 &mbox_c66_0>; 166 + }; 167 + 168 + /* J721E C71_0 DSP node */ 169 + c71_0: dsp@64800000 { 170 + compatible = "ti,j721e-c71-dsp"; 171 + reg = <0x00 0x64800000 0x00 0x00080000>, 172 + <0x00 0x64e00000 0x00 0x0000c000>; 173 + reg-names = "l2sram", "l1dram"; 174 + ti,sci = <&dmsc>; 175 + ti,sci-dev-id = <15>; 176 + ti,sci-proc-ids = <0x30 0xFF>; 177 + resets = <&k3_reset 15 1>; 178 + firmware-name = "j7-c71_0-fw"; 179 + memory-region = <&c71_0_dma_memory_region>, 180 + <&c71_0_memory_region>; 181 + mboxes = <&mailbox0_cluster4 &mbox_c71_0>; 182 + }; 183 + }; 184 + };
+3 -3
Documentation/staging/rpmsg.rst
··· 192 192 193 193 :: 194 194 195 - struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_channel *rpdev, 196 - void (*cb)(struct rpmsg_channel *, void *, int, void *, u32), 197 - void *priv, u32 addr); 195 + struct rpmsg_endpoint *rpmsg_create_ept(struct rpmsg_device *rpdev, 196 + rpmsg_rx_cb_t cb, void *priv, 197 + struct rpmsg_channel_info chinfo); 198 198 199 199 every rpmsg address in the system is bound to an rx callback (so when 200 200 inbound messages arrive, they are dispatched by the rpmsg bus using the
+1
Documentation/userspace-api/ioctl/ioctl-number.rst
··· 339 339 0xB4 00-0F linux/gpio.h <mailto:linux-gpio@vger.kernel.org> 340 340 0xB5 00-0F uapi/linux/rpmsg.h <mailto:linux-remoteproc@vger.kernel.org> 341 341 0xB6 all linux/fpga-dfl.h 342 + 0xB7 all uapi/linux/remoteproc_cdev.h <mailto:linux-remoteproc@vger.kernel.org> 342 343 0xC0 00-0F linux/usb/iowarrior.h 343 344 0xCA 00-0F uapi/misc/cxl.h 344 345 0xCA 10-2F uapi/misc/ocxl.h
+1
MAINTAINERS
··· 17065 17065 M: Santosh Shilimkar <ssantosh@kernel.org> 17066 17066 L: linux-arm-kernel@lists.infradead.org 17067 17067 S: Maintained 17068 + F: Documentation/devicetree/bindings/arm/keystone/ti,k3-sci-common.yaml 17068 17069 F: Documentation/devicetree/bindings/arm/keystone/ti,sci.txt 17069 17070 F: Documentation/devicetree/bindings/clock/ti,sci-clk.txt 17070 17071 F: Documentation/devicetree/bindings/interrupt-controller/ti,sci-inta.txt
+3
drivers/net/ipa/ipa.h
··· 10 10 #include <linux/device.h> 11 11 #include <linux/notifier.h> 12 12 #include <linux/pm_wakeup.h> 13 + #include <linux/notifier.h> 13 14 14 15 #include "ipa_version.h" 15 16 #include "gsi.h" ··· 74 73 enum ipa_version version; 75 74 struct platform_device *pdev; 76 75 struct rproc *modem_rproc; 76 + struct notifier_block nb; 77 + void *notifier; 77 78 struct ipa_smp2p *smp2p; 78 79 struct ipa_clock *clock; 79 80 atomic_t suspend_ref;
+35 -21
drivers/net/ipa/ipa_modem.c
··· 9 9 #include <linux/netdevice.h> 10 10 #include <linux/skbuff.h> 11 11 #include <linux/if_rmnet.h> 12 - #include <linux/remoteproc/qcom_q6v5_ipa_notify.h> 12 + #include <linux/remoteproc/qcom_rproc.h> 13 13 14 14 #include "ipa.h" 15 15 #include "ipa_data.h" ··· 311 311 dev_err(dev, "error %d zeroing modem memory regions\n", ret); 312 312 } 313 313 314 - static void ipa_modem_notify(void *data, enum qcom_rproc_event event) 314 + static int ipa_modem_notify(struct notifier_block *nb, unsigned long action, 315 + void *data) 315 316 { 316 - struct ipa *ipa = data; 317 - struct device *dev; 317 + struct ipa *ipa = container_of(nb, struct ipa, nb); 318 + struct qcom_ssr_notify_data *notify_data = data; 319 + struct device *dev = &ipa->pdev->dev; 318 320 319 - dev = &ipa->pdev->dev; 320 - switch (event) { 321 - case MODEM_STARTING: 321 + switch (action) { 322 + case QCOM_SSR_BEFORE_POWERUP: 322 323 dev_info(dev, "received modem starting event\n"); 323 324 ipa_smp2p_notify_reset(ipa); 324 325 break; 325 326 326 - case MODEM_RUNNING: 327 + case QCOM_SSR_AFTER_POWERUP: 327 328 dev_info(dev, "received modem running event\n"); 328 329 break; 329 330 330 - case MODEM_STOPPING: 331 - case MODEM_CRASHED: 331 + case QCOM_SSR_BEFORE_SHUTDOWN: 332 332 dev_info(dev, "received modem %s event\n", 333 - event == MODEM_STOPPING ? "stopping" 334 - : "crashed"); 333 + notify_data->crashed ? "crashed" : "stopping"); 335 334 if (ipa->setup_complete) 336 335 ipa_modem_crashed(ipa); 337 336 break; 338 337 339 - case MODEM_OFFLINE: 338 + case QCOM_SSR_AFTER_SHUTDOWN: 340 339 dev_info(dev, "received modem offline event\n"); 341 340 break; 342 341 343 - case MODEM_REMOVING: 344 - dev_info(dev, "received modem stopping event\n"); 345 - break; 346 - 347 342 default: 348 - dev_err(&ipa->pdev->dev, "unrecognized event %u\n", event); 343 + dev_err(dev, "received unrecognized event %lu\n", action); 349 344 break; 350 345 } 346 + 347 + return NOTIFY_OK; 351 348 } 352 349 353 350 int ipa_modem_init(struct ipa *ipa, bool modem_init) ··· 359 362 360 363 int ipa_modem_config(struct ipa *ipa) 361 364 { 362 - return qcom_register_ipa_notify(ipa->modem_rproc, ipa_modem_notify, 363 - ipa); 365 + void *notifier; 366 + 367 + ipa->nb.notifier_call = ipa_modem_notify; 368 + 369 + notifier = qcom_register_ssr_notifier("mpss", &ipa->nb); 370 + if (IS_ERR(notifier)) 371 + return PTR_ERR(notifier); 372 + 373 + ipa->notifier = notifier; 374 + 375 + return 0; 364 376 } 365 377 366 378 void ipa_modem_deconfig(struct ipa *ipa) 367 379 { 368 - qcom_deregister_ipa_notify(ipa->modem_rproc); 380 + struct device *dev = &ipa->pdev->dev; 381 + int ret; 382 + 383 + ret = qcom_unregister_ssr_notifier(ipa->notifier, &ipa->nb); 384 + if (ret) 385 + dev_err(dev, "error %d unregistering notifier", ret); 386 + 387 + ipa->notifier = NULL; 388 + memset(&ipa->nb, 0, sizeof(ipa->nb)); 369 389 } 370 390 371 391 int ipa_modem_setup(struct ipa *ipa)
+30 -4
drivers/remoteproc/Kconfig
··· 14 14 15 15 if REMOTEPROC 16 16 17 + config REMOTEPROC_CDEV 18 + bool "Remoteproc character device interface" 19 + help 20 + Say y here to have a character device interface for the remoteproc 21 + framework. Userspace can boot/shutdown remote processors through 22 + this interface. 23 + 24 + It's safe to say N if you don't want to use this interface. 25 + 17 26 config IMX_REMOTEPROC 18 27 tristate "IMX6/7 remoteproc support" 19 28 depends on ARCH_MXC ··· 125 116 It's safe to say N here if you're not interested in the Keystone 126 117 DSPs or just want to use a bare minimum kernel. 127 118 119 + config QCOM_PIL_INFO 120 + tristate 121 + 128 122 config QCOM_RPROC_COMMON 129 123 tristate 130 124 ··· 144 132 depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n 145 133 depends on QCOM_SYSMON || QCOM_SYSMON=n 146 134 select MFD_SYSCON 135 + select QCOM_PIL_INFO 147 136 select QCOM_MDT_LOADER 148 137 select QCOM_Q6V5_COMMON 149 138 select QCOM_RPROC_COMMON ··· 161 148 depends on QCOM_SYSMON || QCOM_SYSMON=n 162 149 select MFD_SYSCON 163 150 select QCOM_MDT_LOADER 151 + select QCOM_PIL_INFO 164 152 select QCOM_Q6V5_COMMON 165 - select QCOM_Q6V5_IPA_NOTIFY 166 153 select QCOM_RPROC_COMMON 167 154 select QCOM_SCM 168 155 help ··· 177 164 depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n 178 165 depends on QCOM_SYSMON || QCOM_SYSMON=n 179 166 select MFD_SYSCON 167 + select QCOM_PIL_INFO 180 168 select QCOM_MDT_LOADER 181 169 select QCOM_Q6V5_COMMON 182 170 select QCOM_RPROC_COMMON ··· 196 182 depends on QCOM_SYSMON || QCOM_SYSMON=n 197 183 select MFD_SYSCON 198 184 select QCOM_MDT_LOADER 185 + select QCOM_PIL_INFO 199 186 select QCOM_Q6V5_COMMON 200 187 select QCOM_RPROC_COMMON 201 188 select QCOM_SCM 202 189 help 203 190 Say y here to support the Qualcomm Peripheral Image Loader for the 204 191 Hexagon V5 based WCSS remote processors. 205 - 206 - config QCOM_Q6V5_IPA_NOTIFY 207 - tristate 208 192 209 193 config QCOM_SYSMON 210 194 tristate "Qualcomm sysmon driver" ··· 227 215 depends on QCOM_SMEM 228 216 depends on QCOM_SYSMON || QCOM_SYSMON=n 229 217 select QCOM_MDT_LOADER 218 + select QCOM_PIL_INFO 230 219 select QCOM_RPROC_COMMON 231 220 select QCOM_SCM 232 221 help ··· 261 248 offloaded to remote MCU processors using this framework). 262 249 263 250 This can be either built-in or a loadable module. 251 + 252 + config TI_K3_DSP_REMOTEPROC 253 + tristate "TI K3 DSP remoteproc support" 254 + depends on ARCH_K3 255 + select MAILBOX 256 + select OMAP2PLUS_MBOX 257 + help 258 + Say m here to support TI's C66x and C71x DSP remote processor 259 + subsystems on various TI K3 family of SoCs through the remote 260 + processor framework. 261 + 262 + It's safe to say N here if you're not interested in utilizing 263 + the DSP slave processors. 264 264 265 265 endif # REMOTEPROC 266 266
+4 -1
drivers/remoteproc/Makefile
··· 5 5 6 6 obj-$(CONFIG_REMOTEPROC) += remoteproc.o 7 7 remoteproc-y := remoteproc_core.o 8 + remoteproc-y += remoteproc_coredump.o 8 9 remoteproc-y += remoteproc_debugfs.o 9 10 remoteproc-y += remoteproc_sysfs.o 10 11 remoteproc-y += remoteproc_virtio.o 11 12 remoteproc-y += remoteproc_elf_loader.o 13 + obj-$(CONFIG_REMOTEPROC_CDEV) += remoteproc_cdev.o 12 14 obj-$(CONFIG_IMX_REMOTEPROC) += imx_rproc.o 13 15 obj-$(CONFIG_INGENIC_VPU_RPROC) += ingenic_rproc.o 14 16 obj-$(CONFIG_MTK_SCP) += mtk_scp.o mtk_scp_ipi.o ··· 18 16 obj-$(CONFIG_WKUP_M3_RPROC) += wkup_m3_rproc.o 19 17 obj-$(CONFIG_DA8XX_REMOTEPROC) += da8xx_remoteproc.o 20 18 obj-$(CONFIG_KEYSTONE_REMOTEPROC) += keystone_remoteproc.o 19 + obj-$(CONFIG_QCOM_PIL_INFO) += qcom_pil_info.o 21 20 obj-$(CONFIG_QCOM_RPROC_COMMON) += qcom_common.o 22 21 obj-$(CONFIG_QCOM_Q6V5_COMMON) += qcom_q6v5.o 23 22 obj-$(CONFIG_QCOM_Q6V5_ADSP) += qcom_q6v5_adsp.o 24 23 obj-$(CONFIG_QCOM_Q6V5_MSS) += qcom_q6v5_mss.o 25 24 obj-$(CONFIG_QCOM_Q6V5_PAS) += qcom_q6v5_pas.o 26 25 obj-$(CONFIG_QCOM_Q6V5_WCSS) += qcom_q6v5_wcss.o 27 - obj-$(CONFIG_QCOM_Q6V5_IPA_NOTIFY) += qcom_q6v5_ipa_notify.o 28 26 obj-$(CONFIG_QCOM_SYSMON) += qcom_sysmon.o 29 27 obj-$(CONFIG_QCOM_WCNSS_PIL) += qcom_wcnss_pil.o 30 28 qcom_wcnss_pil-y += qcom_wcnss.o ··· 32 30 obj-$(CONFIG_ST_REMOTEPROC) += st_remoteproc.o 33 31 obj-$(CONFIG_ST_SLIM_REMOTEPROC) += st_slim_rproc.o 34 32 obj-$(CONFIG_STM32_RPROC) += stm32_rproc.o 33 + obj-$(CONFIG_TI_K3_DSP_REMOTEPROC) += ti_k3_dsp_remoteproc.o
+26 -58
drivers/remoteproc/ingenic_rproc.c
··· 11 11 #include <linux/io.h> 12 12 #include <linux/module.h> 13 13 #include <linux/platform_device.h> 14 - #include <linux/pm_runtime.h> 15 14 #include <linux/remoteproc.h> 16 15 17 16 #include "remoteproc_internal.h" ··· 60 61 struct vpu_mem_info mem_info[ARRAY_SIZE(vpu_mem_map)]; 61 62 struct device *dev; 62 63 }; 64 + 65 + static int ingenic_rproc_prepare(struct rproc *rproc) 66 + { 67 + struct vpu *vpu = rproc->priv; 68 + int ret; 69 + 70 + /* The clocks must be enabled for the firmware to be loaded in TCSM */ 71 + ret = clk_bulk_prepare_enable(ARRAY_SIZE(vpu->clks), vpu->clks); 72 + if (ret) 73 + dev_err(vpu->dev, "Unable to start clocks: %d\n", ret); 74 + 75 + return ret; 76 + } 77 + 78 + static int ingenic_rproc_unprepare(struct rproc *rproc) 79 + { 80 + struct vpu *vpu = rproc->priv; 81 + 82 + clk_bulk_disable_unprepare(ARRAY_SIZE(vpu->clks), vpu->clks); 83 + 84 + return 0; 85 + } 63 86 64 87 static int ingenic_rproc_start(struct rproc *rproc) 65 88 { ··· 136 115 } 137 116 138 117 static struct rproc_ops ingenic_rproc_ops = { 118 + .prepare = ingenic_rproc_prepare, 119 + .unprepare = ingenic_rproc_unprepare, 139 120 .start = ingenic_rproc_start, 140 121 .stop = ingenic_rproc_stop, 141 122 .kick = ingenic_rproc_kick, ··· 156 133 writel(0, vpu->aux_base + REG_AUX_MSG_ACK); 157 134 158 135 return rproc_vq_interrupt(rproc, vring); 159 - } 160 - 161 - static void ingenic_rproc_disable_clks(void *data) 162 - { 163 - struct vpu *vpu = data; 164 - 165 - pm_runtime_resume(vpu->dev); 166 - pm_runtime_disable(vpu->dev); 167 - 168 - clk_bulk_disable_unprepare(ARRAY_SIZE(vpu->clks), vpu->clks); 169 136 } 170 137 171 138 static int ingenic_rproc_probe(struct platform_device *pdev) ··· 219 206 220 207 disable_irq(vpu->irq); 221 208 222 - /* The clocks must be enabled for the firmware to be loaded in TCSM */ 223 - ret = clk_bulk_prepare_enable(ARRAY_SIZE(vpu->clks), vpu->clks); 224 - if (ret) { 225 - dev_err(dev, "Unable to start clocks\n"); 226 - return ret; 227 - } 228 - 229 - pm_runtime_irq_safe(dev); 230 - pm_runtime_set_active(dev); 231 - pm_runtime_enable(dev); 232 - pm_runtime_get_sync(dev); 233 - pm_runtime_use_autosuspend(dev); 234 - 235 - ret = devm_add_action_or_reset(dev, ingenic_rproc_disable_clks, vpu); 236 - if (ret) { 237 - dev_err(dev, "Unable to register action\n"); 238 - goto out_pm_put; 239 - } 240 - 241 209 ret = devm_rproc_add(dev, rproc); 242 210 if (ret) { 243 211 dev_err(dev, "Failed to register remote processor\n"); 244 - goto out_pm_put; 212 + return ret; 245 213 } 246 214 247 - out_pm_put: 248 - pm_runtime_put_autosuspend(dev); 249 - 250 - return ret; 215 + return 0; 251 216 } 252 217 253 218 static const struct of_device_id ingenic_rproc_of_matches[] = { ··· 234 243 }; 235 244 MODULE_DEVICE_TABLE(of, ingenic_rproc_of_matches); 236 245 237 - static int __maybe_unused ingenic_rproc_suspend(struct device *dev) 238 - { 239 - struct vpu *vpu = dev_get_drvdata(dev); 240 - 241 - clk_bulk_disable(ARRAY_SIZE(vpu->clks), vpu->clks); 242 - 243 - return 0; 244 - } 245 - 246 - static int __maybe_unused ingenic_rproc_resume(struct device *dev) 247 - { 248 - struct vpu *vpu = dev_get_drvdata(dev); 249 - 250 - return clk_bulk_enable(ARRAY_SIZE(vpu->clks), vpu->clks); 251 - } 252 - 253 - static const struct dev_pm_ops __maybe_unused ingenic_rproc_pm = { 254 - SET_RUNTIME_PM_OPS(ingenic_rproc_suspend, ingenic_rproc_resume, NULL) 255 - }; 256 - 257 246 static struct platform_driver ingenic_rproc_driver = { 258 247 .probe = ingenic_rproc_probe, 259 248 .driver = { 260 249 .name = "ingenic-vpu", 261 - #ifdef CONFIG_PM 262 - .pm = &ingenic_rproc_pm, 263 - #endif 264 250 .of_match_table = ingenic_rproc_of_matches, 265 251 }, 266 252 };
+120 -13
drivers/remoteproc/qcom_common.c
··· 12 12 #include <linux/module.h> 13 13 #include <linux/notifier.h> 14 14 #include <linux/remoteproc.h> 15 + #include <linux/remoteproc/qcom_rproc.h> 15 16 #include <linux/rpmsg/qcom_glink.h> 16 17 #include <linux/rpmsg/qcom_smd.h> 18 + #include <linux/slab.h> 17 19 #include <linux/soc/qcom/mdt_loader.h> 18 20 19 21 #include "remoteproc_internal.h" ··· 25 23 #define to_smd_subdev(d) container_of(d, struct qcom_rproc_subdev, subdev) 26 24 #define to_ssr_subdev(d) container_of(d, struct qcom_rproc_ssr, subdev) 27 25 28 - static BLOCKING_NOTIFIER_HEAD(ssr_notifiers); 26 + struct qcom_ssr_subsystem { 27 + const char *name; 28 + struct srcu_notifier_head notifier_list; 29 + struct list_head list; 30 + }; 31 + 32 + static LIST_HEAD(qcom_ssr_subsystem_list); 33 + static DEFINE_MUTEX(qcom_ssr_subsys_lock); 29 34 30 35 static int glink_subdev_start(struct rproc_subdev *subdev) 31 36 { ··· 198 189 } 199 190 EXPORT_SYMBOL_GPL(qcom_remove_smd_subdev); 200 191 192 + static struct qcom_ssr_subsystem *qcom_ssr_get_subsys(const char *name) 193 + { 194 + struct qcom_ssr_subsystem *info; 195 + 196 + mutex_lock(&qcom_ssr_subsys_lock); 197 + /* Match in the global qcom_ssr_subsystem_list with name */ 198 + list_for_each_entry(info, &qcom_ssr_subsystem_list, list) 199 + if (!strcmp(info->name, name)) 200 + goto out; 201 + 202 + info = kzalloc(sizeof(*info), GFP_KERNEL); 203 + if (!info) { 204 + info = ERR_PTR(-ENOMEM); 205 + goto out; 206 + } 207 + info->name = kstrdup_const(name, GFP_KERNEL); 208 + srcu_init_notifier_head(&info->notifier_list); 209 + 210 + /* Add to global notification list */ 211 + list_add_tail(&info->list, &qcom_ssr_subsystem_list); 212 + 213 + out: 214 + mutex_unlock(&qcom_ssr_subsys_lock); 215 + return info; 216 + } 217 + 201 218 /** 202 219 * qcom_register_ssr_notifier() - register SSR notification handler 203 - * @nb: notifier_block to notify for restart notifications 220 + * @name: Subsystem's SSR name 221 + * @nb: notifier_block to be invoked upon subsystem's state change 204 222 * 205 - * Returns 0 on success, negative errno on failure. 223 + * This registers the @nb notifier block as part the notifier chain for a 224 + * remoteproc associated with @name. The notifier block's callback 225 + * will be invoked when the remote processor's SSR events occur 226 + * (pre/post startup and pre/post shutdown). 206 227 * 207 - * This register the @notify function as handler for restart notifications. As 208 - * remote processors are stopped this function will be called, with the SSR 209 - * name passed as a parameter. 228 + * Return: a subsystem cookie on success, ERR_PTR on failure. 210 229 */ 211 - int qcom_register_ssr_notifier(struct notifier_block *nb) 230 + void *qcom_register_ssr_notifier(const char *name, struct notifier_block *nb) 212 231 { 213 - return blocking_notifier_chain_register(&ssr_notifiers, nb); 232 + struct qcom_ssr_subsystem *info; 233 + 234 + info = qcom_ssr_get_subsys(name); 235 + if (IS_ERR(info)) 236 + return info; 237 + 238 + srcu_notifier_chain_register(&info->notifier_list, nb); 239 + 240 + return &info->notifier_list; 214 241 } 215 242 EXPORT_SYMBOL_GPL(qcom_register_ssr_notifier); 216 243 217 244 /** 218 245 * qcom_unregister_ssr_notifier() - unregister SSR notification handler 246 + * @notify: subsystem cookie returned from qcom_register_ssr_notifier 219 247 * @nb: notifier_block to unregister 248 + * 249 + * This function will unregister the notifier from the particular notifier 250 + * chain. 251 + * 252 + * Return: 0 on success, %ENOENT otherwise. 220 253 */ 221 - void qcom_unregister_ssr_notifier(struct notifier_block *nb) 254 + int qcom_unregister_ssr_notifier(void *notify, struct notifier_block *nb) 222 255 { 223 - blocking_notifier_chain_unregister(&ssr_notifiers, nb); 256 + return srcu_notifier_chain_unregister(notify, nb); 224 257 } 225 258 EXPORT_SYMBOL_GPL(qcom_unregister_ssr_notifier); 259 + 260 + static int ssr_notify_prepare(struct rproc_subdev *subdev) 261 + { 262 + struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev); 263 + struct qcom_ssr_notify_data data = { 264 + .name = ssr->info->name, 265 + .crashed = false, 266 + }; 267 + 268 + srcu_notifier_call_chain(&ssr->info->notifier_list, 269 + QCOM_SSR_BEFORE_POWERUP, &data); 270 + return 0; 271 + } 272 + 273 + static int ssr_notify_start(struct rproc_subdev *subdev) 274 + { 275 + struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev); 276 + struct qcom_ssr_notify_data data = { 277 + .name = ssr->info->name, 278 + .crashed = false, 279 + }; 280 + 281 + srcu_notifier_call_chain(&ssr->info->notifier_list, 282 + QCOM_SSR_AFTER_POWERUP, &data); 283 + return 0; 284 + } 285 + 286 + static void ssr_notify_stop(struct rproc_subdev *subdev, bool crashed) 287 + { 288 + struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev); 289 + struct qcom_ssr_notify_data data = { 290 + .name = ssr->info->name, 291 + .crashed = crashed, 292 + }; 293 + 294 + srcu_notifier_call_chain(&ssr->info->notifier_list, 295 + QCOM_SSR_BEFORE_SHUTDOWN, &data); 296 + } 226 297 227 298 static void ssr_notify_unprepare(struct rproc_subdev *subdev) 228 299 { 229 300 struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev); 301 + struct qcom_ssr_notify_data data = { 302 + .name = ssr->info->name, 303 + .crashed = false, 304 + }; 230 305 231 - blocking_notifier_call_chain(&ssr_notifiers, 0, (void *)ssr->name); 306 + srcu_notifier_call_chain(&ssr->info->notifier_list, 307 + QCOM_SSR_AFTER_SHUTDOWN, &data); 232 308 } 233 309 234 310 /** ··· 323 229 * @ssr_name: identifier to use for notifications originating from @rproc 324 230 * 325 231 * As the @ssr is registered with the @rproc SSR events will be sent to all 326 - * registered listeners in the system as the remoteproc is shut down. 232 + * registered listeners for the remoteproc when it's SSR events occur 233 + * (pre/post startup and pre/post shutdown). 327 234 */ 328 235 void qcom_add_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr, 329 236 const char *ssr_name) 330 237 { 331 - ssr->name = ssr_name; 238 + struct qcom_ssr_subsystem *info; 239 + 240 + info = qcom_ssr_get_subsys(ssr_name); 241 + if (IS_ERR(info)) { 242 + dev_err(&rproc->dev, "Failed to add ssr subdevice\n"); 243 + return; 244 + } 245 + 246 + ssr->info = info; 247 + ssr->subdev.prepare = ssr_notify_prepare; 248 + ssr->subdev.start = ssr_notify_start; 249 + ssr->subdev.stop = ssr_notify_stop; 332 250 ssr->subdev.unprepare = ssr_notify_unprepare; 333 251 334 252 rproc_add_subdev(rproc, &ssr->subdev); ··· 355 249 void qcom_remove_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr) 356 250 { 357 251 rproc_remove_subdev(rproc, &ssr->subdev); 252 + ssr->info = NULL; 358 253 } 359 254 EXPORT_SYMBOL_GPL(qcom_remove_ssr_subdev); 360 255
+3 -2
drivers/remoteproc/qcom_common.h
··· 26 26 struct qcom_smd_edge *edge; 27 27 }; 28 28 29 + struct qcom_ssr_subsystem; 30 + 29 31 struct qcom_rproc_ssr { 30 32 struct rproc_subdev subdev; 31 - 32 - const char *name; 33 + struct qcom_ssr_subsystem *info; 33 34 }; 34 35 35 36 void qcom_add_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink,
+129
drivers/remoteproc/qcom_pil_info.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (c) 2019-2020 Linaro Ltd. 4 + */ 5 + #include <linux/kernel.h> 6 + #include <linux/module.h> 7 + #include <linux/mutex.h> 8 + #include <linux/of_address.h> 9 + #include "qcom_pil_info.h" 10 + 11 + /* 12 + * The PIL relocation information region is used to communicate memory regions 13 + * occupied by co-processor firmware for post mortem crash analysis. 14 + * 15 + * It consists of an array of entries with an 8 byte textual identifier of the 16 + * region followed by a 64 bit base address and 32 bit size, both little 17 + * endian. 18 + */ 19 + #define PIL_RELOC_NAME_LEN 8 20 + #define PIL_RELOC_ENTRY_SIZE (PIL_RELOC_NAME_LEN + sizeof(__le64) + sizeof(__le32)) 21 + 22 + struct pil_reloc { 23 + void __iomem *base; 24 + size_t num_entries; 25 + }; 26 + 27 + static struct pil_reloc _reloc __read_mostly; 28 + static DEFINE_MUTEX(pil_reloc_lock); 29 + 30 + static int qcom_pil_info_init(void) 31 + { 32 + struct device_node *np; 33 + struct resource imem; 34 + void __iomem *base; 35 + int ret; 36 + 37 + /* Already initialized? */ 38 + if (_reloc.base) 39 + return 0; 40 + 41 + np = of_find_compatible_node(NULL, NULL, "qcom,pil-reloc-info"); 42 + if (!np) 43 + return -ENOENT; 44 + 45 + ret = of_address_to_resource(np, 0, &imem); 46 + of_node_put(np); 47 + if (ret < 0) 48 + return ret; 49 + 50 + base = ioremap(imem.start, resource_size(&imem)); 51 + if (!base) { 52 + pr_err("failed to map PIL relocation info region\n"); 53 + return -ENOMEM; 54 + } 55 + 56 + memset_io(base, 0, resource_size(&imem)); 57 + 58 + _reloc.base = base; 59 + _reloc.num_entries = resource_size(&imem) / PIL_RELOC_ENTRY_SIZE; 60 + 61 + return 0; 62 + } 63 + 64 + /** 65 + * qcom_pil_info_store() - store PIL information of image in IMEM 66 + * @image: name of the image 67 + * @base: base address of the loaded image 68 + * @size: size of the loaded image 69 + * 70 + * Return: 0 on success, negative errno on failure 71 + */ 72 + int qcom_pil_info_store(const char *image, phys_addr_t base, size_t size) 73 + { 74 + char buf[PIL_RELOC_NAME_LEN]; 75 + void __iomem *entry; 76 + int ret; 77 + int i; 78 + 79 + mutex_lock(&pil_reloc_lock); 80 + ret = qcom_pil_info_init(); 81 + if (ret < 0) { 82 + mutex_unlock(&pil_reloc_lock); 83 + return ret; 84 + } 85 + 86 + for (i = 0; i < _reloc.num_entries; i++) { 87 + entry = _reloc.base + i * PIL_RELOC_ENTRY_SIZE; 88 + 89 + memcpy_fromio(buf, entry, PIL_RELOC_NAME_LEN); 90 + 91 + /* 92 + * An empty record means we didn't find it, given that the 93 + * records are packed. 94 + */ 95 + if (!buf[0]) 96 + goto found_unused; 97 + 98 + if (!strncmp(buf, image, PIL_RELOC_NAME_LEN)) 99 + goto found_existing; 100 + } 101 + 102 + pr_warn("insufficient PIL info slots\n"); 103 + mutex_unlock(&pil_reloc_lock); 104 + return -ENOMEM; 105 + 106 + found_unused: 107 + memcpy_toio(entry, image, PIL_RELOC_NAME_LEN); 108 + found_existing: 109 + /* Use two writel() as base is only aligned to 4 bytes on odd entries */ 110 + writel(base, entry + PIL_RELOC_NAME_LEN); 111 + writel((u64)base >> 32, entry + PIL_RELOC_NAME_LEN + 4); 112 + writel(size, entry + PIL_RELOC_NAME_LEN + sizeof(__le64)); 113 + mutex_unlock(&pil_reloc_lock); 114 + 115 + return 0; 116 + } 117 + EXPORT_SYMBOL_GPL(qcom_pil_info_store); 118 + 119 + static void __exit pil_reloc_exit(void) 120 + { 121 + mutex_lock(&pil_reloc_lock); 122 + iounmap(_reloc.base); 123 + _reloc.base = NULL; 124 + mutex_unlock(&pil_reloc_lock); 125 + } 126 + module_exit(pil_reloc_exit); 127 + 128 + MODULE_DESCRIPTION("Qualcomm PIL relocation info"); 129 + MODULE_LICENSE("GPL v2");
+9
drivers/remoteproc/qcom_pil_info.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef __QCOM_PIL_INFO_H__ 3 + #define __QCOM_PIL_INFO_H__ 4 + 5 + #include <linux/types.h> 6 + 7 + int qcom_pil_info_store(const char *image, phys_addr_t base, size_t size); 8 + 9 + #endif
+2
drivers/remoteproc/qcom_q6v5.c
··· 153 153 { 154 154 int ret; 155 155 156 + q6v5->running = false; 157 + 156 158 qcom_smem_state_update_bits(q6v5->state, 157 159 BIT(q6v5->stop_bit), BIT(q6v5->stop_bit)); 158 160
+13 -3
drivers/remoteproc/qcom_q6v5_adsp.c
··· 26 26 #include <linux/soc/qcom/smem_state.h> 27 27 28 28 #include "qcom_common.h" 29 + #include "qcom_pil_info.h" 29 30 #include "qcom_q6v5.h" 30 31 #include "remoteproc_internal.h" 31 32 ··· 83 82 unsigned int halt_lpass; 84 83 85 84 int crash_reason_smem; 85 + const char *info_name; 86 86 87 87 struct completion start_done; 88 88 struct completion stop_done; ··· 166 164 static int adsp_load(struct rproc *rproc, const struct firmware *fw) 167 165 { 168 166 struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv; 167 + int ret; 169 168 170 - return qcom_mdt_load_no_init(adsp->dev, fw, rproc->firmware, 0, 171 - adsp->mem_region, adsp->mem_phys, adsp->mem_size, 172 - &adsp->mem_reloc); 169 + ret = qcom_mdt_load_no_init(adsp->dev, fw, rproc->firmware, 0, 170 + adsp->mem_region, adsp->mem_phys, 171 + adsp->mem_size, &adsp->mem_reloc); 172 + if (ret) 173 + return ret; 174 + 175 + qcom_pil_info_store(adsp->info_name, adsp->mem_phys, adsp->mem_size); 176 + 177 + return 0; 173 178 } 174 179 175 180 static int adsp_start(struct rproc *rproc) ··· 445 436 adsp = (struct qcom_adsp *)rproc->priv; 446 437 adsp->dev = &pdev->dev; 447 438 adsp->rproc = rproc; 439 + adsp->info_name = desc->sysmon_name; 448 440 platform_set_drvdata(pdev, adsp); 449 441 450 442 ret = adsp_alloc_memory_region(adsp);
-85
drivers/remoteproc/qcom_q6v5_ipa_notify.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 2 - 3 - /* 4 - * Qualcomm IPA notification subdev support 5 - * 6 - * Copyright (C) 2019 Linaro Ltd. 7 - */ 8 - 9 - #include <linux/kernel.h> 10 - #include <linux/module.h> 11 - #include <linux/remoteproc.h> 12 - #include <linux/remoteproc/qcom_q6v5_ipa_notify.h> 13 - 14 - static void 15 - ipa_notify_common(struct rproc_subdev *subdev, enum qcom_rproc_event event) 16 - { 17 - struct qcom_rproc_ipa_notify *ipa_notify; 18 - qcom_ipa_notify_t notify; 19 - 20 - ipa_notify = container_of(subdev, struct qcom_rproc_ipa_notify, subdev); 21 - notify = ipa_notify->notify; 22 - if (notify) 23 - notify(ipa_notify->data, event); 24 - } 25 - 26 - static int ipa_notify_prepare(struct rproc_subdev *subdev) 27 - { 28 - ipa_notify_common(subdev, MODEM_STARTING); 29 - 30 - return 0; 31 - } 32 - 33 - static int ipa_notify_start(struct rproc_subdev *subdev) 34 - { 35 - ipa_notify_common(subdev, MODEM_RUNNING); 36 - 37 - return 0; 38 - } 39 - 40 - static void ipa_notify_stop(struct rproc_subdev *subdev, bool crashed) 41 - 42 - { 43 - ipa_notify_common(subdev, crashed ? MODEM_CRASHED : MODEM_STOPPING); 44 - } 45 - 46 - static void ipa_notify_unprepare(struct rproc_subdev *subdev) 47 - { 48 - ipa_notify_common(subdev, MODEM_OFFLINE); 49 - } 50 - 51 - static void ipa_notify_removing(struct rproc_subdev *subdev) 52 - { 53 - ipa_notify_common(subdev, MODEM_REMOVING); 54 - } 55 - 56 - /* Register the IPA notification subdevice with the Q6V5 MSS remoteproc */ 57 - void qcom_add_ipa_notify_subdev(struct rproc *rproc, 58 - struct qcom_rproc_ipa_notify *ipa_notify) 59 - { 60 - ipa_notify->notify = NULL; 61 - ipa_notify->data = NULL; 62 - ipa_notify->subdev.prepare = ipa_notify_prepare; 63 - ipa_notify->subdev.start = ipa_notify_start; 64 - ipa_notify->subdev.stop = ipa_notify_stop; 65 - ipa_notify->subdev.unprepare = ipa_notify_unprepare; 66 - 67 - rproc_add_subdev(rproc, &ipa_notify->subdev); 68 - } 69 - EXPORT_SYMBOL_GPL(qcom_add_ipa_notify_subdev); 70 - 71 - /* Remove the IPA notification subdevice */ 72 - void qcom_remove_ipa_notify_subdev(struct rproc *rproc, 73 - struct qcom_rproc_ipa_notify *ipa_notify) 74 - { 75 - struct rproc_subdev *subdev = &ipa_notify->subdev; 76 - 77 - ipa_notify_removing(subdev); 78 - 79 - rproc_remove_subdev(rproc, subdev); 80 - ipa_notify->notify = NULL; /* Make it obvious */ 81 - } 82 - EXPORT_SYMBOL_GPL(qcom_remove_ipa_notify_subdev); 83 - 84 - MODULE_LICENSE("GPL v2"); 85 - MODULE_DESCRIPTION("Qualcomm IPA notification remoteproc subdev");
+90 -67
drivers/remoteproc/qcom_q6v5_mss.c
··· 9 9 10 10 #include <linux/clk.h> 11 11 #include <linux/delay.h> 12 + #include <linux/devcoredump.h> 12 13 #include <linux/dma-mapping.h> 13 14 #include <linux/interrupt.h> 14 15 #include <linux/kernel.h> ··· 23 22 #include <linux/regmap.h> 24 23 #include <linux/regulator/consumer.h> 25 24 #include <linux/remoteproc.h> 26 - #include "linux/remoteproc/qcom_q6v5_ipa_notify.h" 27 25 #include <linux/reset.h> 28 26 #include <linux/soc/qcom/mdt_loader.h> 29 27 #include <linux/iopoll.h> ··· 30 30 31 31 #include "remoteproc_internal.h" 32 32 #include "qcom_common.h" 33 + #include "qcom_pil_info.h" 33 34 #include "qcom_q6v5.h" 34 35 35 36 #include <linux/qcom_scm.h> 36 37 37 38 #define MPSS_CRASH_REASON_SMEM 421 39 + 40 + #define MBA_LOG_SIZE SZ_4K 38 41 39 42 /* RMB Status Register Values */ 40 43 #define RMB_PBL_SUCCESS 0x1 ··· 115 112 #define QDSP6SS_SLEEP 0x3C 116 113 #define QDSP6SS_BOOT_CORE_START 0x400 117 114 #define QDSP6SS_BOOT_CMD 0x404 118 - #define QDSP6SS_BOOT_STATUS 0x408 119 - #define BOOT_STATUS_TIMEOUT_US 200 120 115 #define BOOT_FSM_TIMEOUT 10000 121 116 122 117 struct reg_info { ··· 141 140 int version; 142 141 bool need_mem_protection; 143 142 bool has_alt_reset; 143 + bool has_mba_logs; 144 144 bool has_spare_reg; 145 145 }; 146 146 ··· 181 179 int active_reg_count; 182 180 int proxy_reg_count; 183 181 184 - bool running; 185 - 186 182 bool dump_mba_loaded; 187 - unsigned long dump_segment_mask; 188 - unsigned long dump_complete_mask; 183 + size_t current_dump_size; 184 + size_t total_dump_size; 189 185 190 186 phys_addr_t mba_phys; 191 187 void *mba_region; 192 188 size_t mba_size; 189 + size_t dp_size; 193 190 194 191 phys_addr_t mpss_phys; 195 192 phys_addr_t mpss_reloc; ··· 197 196 struct qcom_rproc_glink glink_subdev; 198 197 struct qcom_rproc_subdev smd_subdev; 199 198 struct qcom_rproc_ssr ssr_subdev; 200 - struct qcom_rproc_ipa_notify ipa_notify_subdev; 201 199 struct qcom_sysmon *sysmon; 202 200 bool need_mem_protection; 203 201 bool has_alt_reset; 202 + bool has_mba_logs; 204 203 bool has_spare_reg; 205 204 int mpss_perm; 206 205 int mba_perm; ··· 405 404 current_perm, next, perms); 406 405 } 407 406 407 + static void q6v5_debug_policy_load(struct q6v5 *qproc) 408 + { 409 + const struct firmware *dp_fw; 410 + 411 + if (request_firmware_direct(&dp_fw, "msadp", qproc->dev)) 412 + return; 413 + 414 + if (SZ_1M + dp_fw->size <= qproc->mba_size) { 415 + memcpy(qproc->mba_region + SZ_1M, dp_fw->data, dp_fw->size); 416 + qproc->dp_size = dp_fw->size; 417 + } 418 + 419 + release_firmware(dp_fw); 420 + } 421 + 408 422 static int q6v5_load(struct rproc *rproc, const struct firmware *fw) 409 423 { 410 424 struct q6v5 *qproc = rproc->priv; 411 425 426 + /* MBA is restricted to a maximum size of 1M */ 427 + if (fw->size > qproc->mba_size || fw->size > SZ_1M) { 428 + dev_err(qproc->dev, "MBA firmware load failed\n"); 429 + return -EINVAL; 430 + } 431 + 412 432 memcpy(qproc->mba_region, fw->data, fw->size); 433 + q6v5_debug_policy_load(qproc); 413 434 414 435 return 0; 415 436 } ··· 534 511 return val; 535 512 } 536 513 514 + static void q6v5_dump_mba_logs(struct q6v5 *qproc) 515 + { 516 + struct rproc *rproc = qproc->rproc; 517 + void *data; 518 + 519 + if (!qproc->has_mba_logs) 520 + return; 521 + 522 + if (q6v5_xfer_mem_ownership(qproc, &qproc->mba_perm, true, false, qproc->mba_phys, 523 + qproc->mba_size)) 524 + return; 525 + 526 + data = vmalloc(MBA_LOG_SIZE); 527 + if (!data) 528 + return; 529 + 530 + memcpy(data, qproc->mba_region, MBA_LOG_SIZE); 531 + dev_coredumpv(&rproc->dev, data, MBA_LOG_SIZE, GFP_KERNEL); 532 + } 533 + 537 534 static int q6v5proc_reset(struct q6v5 *qproc) 538 535 { 539 536 u32 val; ··· 622 579 /* De-assert the Q6 stop core signal */ 623 580 writel(1, qproc->reg_base + QDSP6SS_BOOT_CORE_START); 624 581 582 + /* Wait for 10 us for any staggering logic to settle */ 583 + usleep_range(10, 20); 584 + 625 585 /* Trigger the boot FSM to start the Q6 out-of-reset sequence */ 626 586 writel(1, qproc->reg_base + QDSP6SS_BOOT_CMD); 627 587 628 - /* Poll the QDSP6SS_BOOT_STATUS for FSM completion */ 629 - ret = readl_poll_timeout(qproc->reg_base + QDSP6SS_BOOT_STATUS, 630 - val, (val & BIT(0)) != 0, 1, 631 - BOOT_STATUS_TIMEOUT_US); 588 + /* Poll the MSS_STATUS for FSM completion */ 589 + ret = readl_poll_timeout(qproc->rmb_base + RMB_MBA_MSS_STATUS, 590 + val, (val & BIT(0)) != 0, 10, BOOT_FSM_TIMEOUT); 632 591 if (ret) { 633 592 dev_err(qproc->dev, "Boot FSM failed to complete.\n"); 634 593 /* Reset the modem so that boot FSM is in reset state */ ··· 874 829 { 875 830 int ret; 876 831 int xfermemop_ret; 832 + bool mba_load_err = false; 877 833 878 834 qcom_q6v5_prepare(&qproc->q6v5); 879 835 ··· 941 895 } 942 896 943 897 writel(qproc->mba_phys, qproc->rmb_base + RMB_MBA_IMAGE_REG); 898 + if (qproc->dp_size) { 899 + writel(qproc->mba_phys + SZ_1M, qproc->rmb_base + RMB_PMI_CODE_START_REG); 900 + writel(qproc->dp_size, qproc->rmb_base + RMB_PMI_CODE_LENGTH_REG); 901 + } 944 902 945 903 ret = q6v5proc_reset(qproc); 946 904 if (ret) ··· 968 918 q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_q6); 969 919 q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem); 970 920 q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_nc); 971 - 921 + mba_load_err = true; 972 922 reclaim_mba: 973 923 xfermemop_ret = q6v5_xfer_mem_ownership(qproc, &qproc->mba_perm, true, 974 924 false, qproc->mba_phys, ··· 976 926 if (xfermemop_ret) { 977 927 dev_err(qproc->dev, 978 928 "Failed to reclaim mba buffer, system may become unstable\n"); 929 + } else if (mba_load_err) { 930 + q6v5_dump_mba_logs(qproc); 979 931 } 980 932 981 933 disable_active_clks: ··· 1013 961 u32 val; 1014 962 1015 963 qproc->dump_mba_loaded = false; 964 + qproc->dp_size = 0; 1016 965 1017 966 q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_q6); 1018 967 q6v5proc_halt_axi_port(qproc, qproc->halt_map, qproc->halt_modem); ··· 1192 1139 } else if (phdr->p_filesz) { 1193 1140 /* Replace "xxx.xxx" with "xxx.bxx" */ 1194 1141 sprintf(fw_name + fw_name_len - 3, "b%02d", i); 1195 - ret = request_firmware(&seg_fw, fw_name, qproc->dev); 1142 + ret = request_firmware_into_buf(&seg_fw, fw_name, qproc->dev, 1143 + ptr, phdr->p_filesz); 1196 1144 if (ret) { 1197 1145 dev_err(qproc->dev, "failed to load %s\n", fw_name); 1198 1146 iounmap(ptr); 1199 1147 goto release_firmware; 1200 1148 } 1201 - 1202 - memcpy(ptr, seg_fw->data, seg_fw->size); 1203 1149 1204 1150 release_firmware(seg_fw); 1205 1151 } ··· 1242 1190 else if (ret < 0) 1243 1191 dev_err(qproc->dev, "MPSS authentication failed: %d\n", ret); 1244 1192 1193 + qcom_pil_info_store("modem", qproc->mpss_phys, qproc->mpss_size); 1194 + 1245 1195 release_firmware: 1246 1196 release_firmware(fw); 1247 1197 out: ··· 1254 1200 1255 1201 static void qcom_q6v5_dump_segment(struct rproc *rproc, 1256 1202 struct rproc_dump_segment *segment, 1257 - void *dest) 1203 + void *dest, size_t cp_offset, size_t size) 1258 1204 { 1259 1205 int ret = 0; 1260 1206 struct q6v5 *qproc = rproc->priv; 1261 - unsigned long mask = BIT((unsigned long)segment->priv); 1262 1207 int offset = segment->da - qproc->mpss_reloc; 1263 1208 void *ptr = NULL; 1264 1209 ··· 1274 1221 } 1275 1222 1276 1223 if (!ret) 1277 - ptr = ioremap_wc(qproc->mpss_phys + offset, segment->size); 1224 + ptr = ioremap_wc(qproc->mpss_phys + offset + cp_offset, size); 1278 1225 1279 1226 if (ptr) { 1280 - memcpy(dest, ptr, segment->size); 1227 + memcpy(dest, ptr, size); 1281 1228 iounmap(ptr); 1282 1229 } else { 1283 - memset(dest, 0xff, segment->size); 1230 + memset(dest, 0xff, size); 1284 1231 } 1285 1232 1286 - qproc->dump_segment_mask |= mask; 1233 + qproc->current_dump_size += size; 1287 1234 1288 1235 /* Reclaim mba after copying segments */ 1289 - if (qproc->dump_segment_mask == qproc->dump_complete_mask) { 1236 + if (qproc->current_dump_size == qproc->total_dump_size) { 1290 1237 if (qproc->dump_mba_loaded) { 1291 1238 /* Try to reset ownership back to Q6 */ 1292 1239 q6v5_xfer_mem_ownership(qproc, &qproc->mpss_perm, ··· 1308 1255 if (ret) 1309 1256 return ret; 1310 1257 1311 - dev_info(qproc->dev, "MBA booted, loading mpss\n"); 1258 + dev_info(qproc->dev, "MBA booted with%s debug policy, loading mpss\n", 1259 + qproc->dp_size ? "" : "out"); 1312 1260 1313 1261 ret = q6v5_mpss_load(qproc); 1314 1262 if (ret) ··· 1329 1275 "Failed to reclaim mba buffer system may become unstable\n"); 1330 1276 1331 1277 /* Reset Dump Segment Mask */ 1332 - qproc->dump_segment_mask = 0; 1333 - qproc->running = true; 1278 + qproc->current_dump_size = 0; 1334 1279 1335 1280 return 0; 1336 1281 1337 1282 reclaim_mpss: 1338 1283 q6v5_mba_reclaim(qproc); 1284 + q6v5_dump_mba_logs(qproc); 1339 1285 1340 1286 return ret; 1341 1287 } ··· 1344 1290 { 1345 1291 struct q6v5 *qproc = (struct q6v5 *)rproc->priv; 1346 1292 int ret; 1347 - 1348 - qproc->running = false; 1349 1293 1350 1294 ret = qcom_q6v5_request_stop(&qproc->q6v5); 1351 1295 if (ret == -ETIMEDOUT) ··· 1376 1324 1377 1325 ehdr = (struct elf32_hdr *)fw->data; 1378 1326 phdrs = (struct elf32_phdr *)(ehdr + 1); 1379 - qproc->dump_complete_mask = 0; 1327 + qproc->total_dump_size = 0; 1380 1328 1381 1329 for (i = 0; i < ehdr->e_phnum; i++) { 1382 1330 phdr = &phdrs[i]; ··· 1387 1335 ret = rproc_coredump_add_custom_segment(rproc, phdr->p_paddr, 1388 1336 phdr->p_memsz, 1389 1337 qcom_q6v5_dump_segment, 1390 - (void *)i); 1338 + NULL); 1391 1339 if (ret) 1392 1340 break; 1393 1341 1394 - qproc->dump_complete_mask |= BIT(i); 1342 + qproc->total_dump_size += phdr->p_memsz; 1395 1343 } 1396 1344 1397 1345 release_firmware(fw); ··· 1606 1554 return 0; 1607 1555 } 1608 1556 1609 - #if IS_ENABLED(CONFIG_QCOM_Q6V5_IPA_NOTIFY) 1610 - 1611 - /* Register IPA notification function */ 1612 - int qcom_register_ipa_notify(struct rproc *rproc, qcom_ipa_notify_t notify, 1613 - void *data) 1614 - { 1615 - struct qcom_rproc_ipa_notify *ipa_notify; 1616 - struct q6v5 *qproc = rproc->priv; 1617 - 1618 - if (!notify) 1619 - return -EINVAL; 1620 - 1621 - ipa_notify = &qproc->ipa_notify_subdev; 1622 - if (ipa_notify->notify) 1623 - return -EBUSY; 1624 - 1625 - ipa_notify->notify = notify; 1626 - ipa_notify->data = data; 1627 - 1628 - return 0; 1629 - } 1630 - EXPORT_SYMBOL_GPL(qcom_register_ipa_notify); 1631 - 1632 - /* Deregister IPA notification function */ 1633 - void qcom_deregister_ipa_notify(struct rproc *rproc) 1634 - { 1635 - struct q6v5 *qproc = rproc->priv; 1636 - 1637 - qproc->ipa_notify_subdev.notify = NULL; 1638 - } 1639 - EXPORT_SYMBOL_GPL(qcom_deregister_ipa_notify); 1640 - #endif /* !IS_ENABLED(CONFIG_QCOM_Q6V5_IPA_NOTIFY) */ 1641 - 1642 1557 static int q6v5_probe(struct platform_device *pdev) 1643 1558 { 1644 1559 const struct rproc_hexagon_res *desc; ··· 1720 1701 1721 1702 qproc->version = desc->version; 1722 1703 qproc->need_mem_protection = desc->need_mem_protection; 1704 + qproc->has_mba_logs = desc->has_mba_logs; 1723 1705 1724 1706 ret = qcom_q6v5_init(&qproc->q6v5, pdev, rproc, MPSS_CRASH_REASON_SMEM, 1725 1707 qcom_msa_handover); ··· 1732 1712 qcom_add_glink_subdev(rproc, &qproc->glink_subdev, "mpss"); 1733 1713 qcom_add_smd_subdev(rproc, &qproc->smd_subdev); 1734 1714 qcom_add_ssr_subdev(rproc, &qproc->ssr_subdev, "mpss"); 1735 - qcom_add_ipa_notify_subdev(rproc, &qproc->ipa_notify_subdev); 1736 1715 qproc->sysmon = qcom_add_sysmon_subdev(rproc, "modem", 0x12); 1737 1716 if (IS_ERR(qproc->sysmon)) { 1738 1717 ret = PTR_ERR(qproc->sysmon); ··· 1747 1728 remove_sysmon_subdev: 1748 1729 qcom_remove_sysmon_subdev(qproc->sysmon); 1749 1730 remove_subdevs: 1750 - qcom_remove_ipa_notify_subdev(qproc->rproc, &qproc->ipa_notify_subdev); 1751 1731 qcom_remove_ssr_subdev(rproc, &qproc->ssr_subdev); 1752 1732 qcom_remove_smd_subdev(rproc, &qproc->smd_subdev); 1753 1733 qcom_remove_glink_subdev(rproc, &qproc->glink_subdev); ··· 1768 1750 rproc_del(rproc); 1769 1751 1770 1752 qcom_remove_sysmon_subdev(qproc->sysmon); 1771 - qcom_remove_ipa_notify_subdev(rproc, &qproc->ipa_notify_subdev); 1772 1753 qcom_remove_ssr_subdev(rproc, &qproc->ssr_subdev); 1773 1754 qcom_remove_smd_subdev(rproc, &qproc->smd_subdev); 1774 1755 qcom_remove_glink_subdev(rproc, &qproc->glink_subdev); ··· 1809 1792 }, 1810 1793 .need_mem_protection = true, 1811 1794 .has_alt_reset = false, 1795 + .has_mba_logs = true, 1812 1796 .has_spare_reg = true, 1813 1797 .version = MSS_SC7180, 1814 1798 }; ··· 1845 1827 }, 1846 1828 .need_mem_protection = true, 1847 1829 .has_alt_reset = true, 1830 + .has_mba_logs = false, 1848 1831 .has_spare_reg = false, 1849 1832 .version = MSS_SDM845, 1850 1833 }; ··· 1873 1854 }, 1874 1855 .need_mem_protection = true, 1875 1856 .has_alt_reset = false, 1857 + .has_mba_logs = false, 1876 1858 .has_spare_reg = false, 1877 1859 .version = MSS_MSM8998, 1878 1860 }; ··· 1904 1884 }, 1905 1885 .need_mem_protection = true, 1906 1886 .has_alt_reset = false, 1887 + .has_mba_logs = false, 1907 1888 .has_spare_reg = false, 1908 1889 .version = MSS_MSM8996, 1909 1890 }; ··· 1938 1917 }, 1939 1918 .need_mem_protection = false, 1940 1919 .has_alt_reset = false, 1920 + .has_mba_logs = false, 1941 1921 .has_spare_reg = false, 1942 1922 .version = MSS_MSM8916, 1943 1923 }; ··· 1980 1958 }, 1981 1959 .need_mem_protection = false, 1982 1960 .has_alt_reset = false, 1961 + .has_mba_logs = false, 1983 1962 .has_spare_reg = false, 1984 1963 .version = MSS_MSM8974, 1985 1964 };
+12 -3
drivers/remoteproc/qcom_q6v5_pas.c
··· 25 25 #include <linux/soc/qcom/smem_state.h> 26 26 27 27 #include "qcom_common.h" 28 + #include "qcom_pil_info.h" 28 29 #include "qcom_q6v5.h" 29 30 #include "remoteproc_internal.h" 30 31 ··· 65 64 int pas_id; 66 65 int crash_reason_smem; 67 66 bool has_aggre2_clk; 67 + const char *info_name; 68 68 69 69 struct completion start_done; 70 70 struct completion stop_done; ··· 119 117 static int adsp_load(struct rproc *rproc, const struct firmware *fw) 120 118 { 121 119 struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv; 120 + int ret; 122 121 123 - return qcom_mdt_load(adsp->dev, fw, rproc->firmware, adsp->pas_id, 124 - adsp->mem_region, adsp->mem_phys, adsp->mem_size, 125 - &adsp->mem_reloc); 122 + ret = qcom_mdt_load(adsp->dev, fw, rproc->firmware, adsp->pas_id, 123 + adsp->mem_region, adsp->mem_phys, adsp->mem_size, 124 + &adsp->mem_reloc); 125 + if (ret) 126 + return ret; 126 127 128 + qcom_pil_info_store(adsp->info_name, adsp->mem_phys, adsp->mem_size); 129 + 130 + return 0; 127 131 } 128 132 129 133 static int adsp_start(struct rproc *rproc) ··· 413 405 adsp->rproc = rproc; 414 406 adsp->pas_id = desc->pas_id; 415 407 adsp->has_aggre2_clk = desc->has_aggre2_clk; 408 + adsp->info_name = desc->sysmon_name; 416 409 platform_set_drvdata(pdev, adsp); 417 410 418 411 device_wakeup_enable(adsp->dev);
+11 -3
drivers/remoteproc/qcom_q6v5_wcss.c
··· 14 14 #include <linux/reset.h> 15 15 #include <linux/soc/qcom/mdt_loader.h> 16 16 #include "qcom_common.h" 17 + #include "qcom_pil_info.h" 17 18 #include "qcom_q6v5.h" 18 19 19 20 #define WCSS_CRASH_REASON 421 ··· 425 424 static int q6v5_wcss_load(struct rproc *rproc, const struct firmware *fw) 426 425 { 427 426 struct q6v5_wcss *wcss = rproc->priv; 427 + int ret; 428 428 429 - return qcom_mdt_load_no_init(wcss->dev, fw, rproc->firmware, 430 - 0, wcss->mem_region, wcss->mem_phys, 431 - wcss->mem_size, &wcss->mem_reloc); 429 + ret = qcom_mdt_load_no_init(wcss->dev, fw, rproc->firmware, 430 + 0, wcss->mem_region, wcss->mem_phys, 431 + wcss->mem_size, &wcss->mem_reloc); 432 + if (ret) 433 + return ret; 434 + 435 + qcom_pil_info_store("wcnss", wcss->mem_phys, wcss->mem_size); 436 + 437 + return ret; 432 438 } 433 439 434 440 static const struct rproc_ops q6v5_wcss_ops = {
+2 -2
drivers/remoteproc/qcom_sysmon.c
··· 71 71 /** 72 72 * sysmon_send_event() - send notification of other remote's SSR event 73 73 * @sysmon: sysmon context 74 - * @name: other remote's name 74 + * @event: sysmon event context 75 75 */ 76 76 static void sysmon_send_event(struct qcom_sysmon *sysmon, 77 77 const struct sysmon_event *event) ··· 343 343 /** 344 344 * ssctl_send_event() - send notification of other remote's SSR event 345 345 * @sysmon: sysmon context 346 - * @name: other remote's name 346 + * @event: sysmon event context 347 347 */ 348 348 static void ssctl_send_event(struct qcom_sysmon *sysmon, 349 349 const struct sysmon_event *event)
+11 -3
drivers/remoteproc/qcom_wcnss.c
··· 27 27 28 28 #include "qcom_common.h" 29 29 #include "remoteproc_internal.h" 30 + #include "qcom_pil_info.h" 30 31 #include "qcom_wcnss.h" 31 32 32 33 #define WCNSS_CRASH_REASON_SMEM 422 ··· 146 145 static int wcnss_load(struct rproc *rproc, const struct firmware *fw) 147 146 { 148 147 struct qcom_wcnss *wcnss = (struct qcom_wcnss *)rproc->priv; 148 + int ret; 149 149 150 - return qcom_mdt_load(wcnss->dev, fw, rproc->firmware, WCNSS_PAS_ID, 151 - wcnss->mem_region, wcnss->mem_phys, 152 - wcnss->mem_size, &wcnss->mem_reloc); 150 + ret = qcom_mdt_load(wcnss->dev, fw, rproc->firmware, WCNSS_PAS_ID, 151 + wcnss->mem_region, wcnss->mem_phys, 152 + wcnss->mem_size, &wcnss->mem_reloc); 153 + if (ret) 154 + return ret; 155 + 156 + qcom_pil_info_store("wcnss", wcnss->mem_phys, wcnss->mem_size); 157 + 158 + return 0; 153 159 } 154 160 155 161 static void wcnss_indicate_nv_download(struct qcom_wcnss *wcnss)
+124
drivers/remoteproc/remoteproc_cdev.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Character device interface driver for Remoteproc framework. 4 + * 5 + * Copyright (c) 2020, The Linux Foundation. All rights reserved. 6 + */ 7 + 8 + #include <linux/cdev.h> 9 + #include <linux/compat.h> 10 + #include <linux/fs.h> 11 + #include <linux/module.h> 12 + #include <linux/remoteproc.h> 13 + #include <linux/uaccess.h> 14 + #include <uapi/linux/remoteproc_cdev.h> 15 + 16 + #include "remoteproc_internal.h" 17 + 18 + #define NUM_RPROC_DEVICES 64 19 + static dev_t rproc_major; 20 + 21 + static ssize_t rproc_cdev_write(struct file *filp, const char __user *buf, size_t len, loff_t *pos) 22 + { 23 + struct rproc *rproc = container_of(filp->f_inode->i_cdev, struct rproc, cdev); 24 + int ret = 0; 25 + char cmd[10]; 26 + 27 + if (!len || len > sizeof(cmd)) 28 + return -EINVAL; 29 + 30 + ret = copy_from_user(cmd, buf, len); 31 + if (ret) 32 + return -EFAULT; 33 + 34 + if (!strncmp(cmd, "start", len)) { 35 + if (rproc->state == RPROC_RUNNING) 36 + return -EBUSY; 37 + 38 + ret = rproc_boot(rproc); 39 + } else if (!strncmp(cmd, "stop", len)) { 40 + if (rproc->state != RPROC_RUNNING) 41 + return -EINVAL; 42 + 43 + rproc_shutdown(rproc); 44 + } else { 45 + dev_err(&rproc->dev, "Unrecognized option\n"); 46 + ret = -EINVAL; 47 + } 48 + 49 + return ret ? ret : len; 50 + } 51 + 52 + static long rproc_device_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) 53 + { 54 + struct rproc *rproc = container_of(filp->f_inode->i_cdev, struct rproc, cdev); 55 + void __user *argp = (void __user *)arg; 56 + s32 param; 57 + 58 + switch (ioctl) { 59 + case RPROC_SET_SHUTDOWN_ON_RELEASE: 60 + if (copy_from_user(&param, argp, sizeof(s32))) 61 + return -EFAULT; 62 + 63 + rproc->cdev_put_on_release = !!param; 64 + break; 65 + case RPROC_GET_SHUTDOWN_ON_RELEASE: 66 + param = (s32)rproc->cdev_put_on_release; 67 + if (copy_to_user(argp, &param, sizeof(s32))) 68 + return -EFAULT; 69 + 70 + break; 71 + default: 72 + dev_err(&rproc->dev, "Unsupported ioctl\n"); 73 + return -EINVAL; 74 + } 75 + 76 + return 0; 77 + } 78 + 79 + static int rproc_cdev_release(struct inode *inode, struct file *filp) 80 + { 81 + struct rproc *rproc = container_of(inode->i_cdev, struct rproc, cdev); 82 + 83 + if (rproc->cdev_put_on_release && rproc->state == RPROC_RUNNING) 84 + rproc_shutdown(rproc); 85 + 86 + return 0; 87 + } 88 + 89 + static const struct file_operations rproc_fops = { 90 + .write = rproc_cdev_write, 91 + .unlocked_ioctl = rproc_device_ioctl, 92 + .compat_ioctl = compat_ptr_ioctl, 93 + .release = rproc_cdev_release, 94 + }; 95 + 96 + int rproc_char_device_add(struct rproc *rproc) 97 + { 98 + int ret; 99 + 100 + cdev_init(&rproc->cdev, &rproc_fops); 101 + rproc->cdev.owner = THIS_MODULE; 102 + 103 + rproc->dev.devt = MKDEV(MAJOR(rproc_major), rproc->index); 104 + cdev_set_parent(&rproc->cdev, &rproc->dev.kobj); 105 + ret = cdev_add(&rproc->cdev, rproc->dev.devt, 1); 106 + if (ret < 0) 107 + dev_err(&rproc->dev, "Failed to add char dev for %s\n", rproc->name); 108 + 109 + return ret; 110 + } 111 + 112 + void rproc_char_device_remove(struct rproc *rproc) 113 + { 114 + __unregister_chrdev(MAJOR(rproc->dev.devt), rproc->index, 1, "remoteproc"); 115 + } 116 + 117 + void __init rproc_init_cdev(void) 118 + { 119 + int ret; 120 + 121 + ret = alloc_chrdev_region(&rproc_major, 0, NUM_RPROC_DEVICES, "remoteproc"); 122 + if (ret < 0) 123 + pr_err("Failed to alloc rproc_cdev region, err %d\n", ret); 124 + }
+236 -223
drivers/remoteproc/remoteproc_core.c
··· 26 26 #include <linux/firmware.h> 27 27 #include <linux/string.h> 28 28 #include <linux/debugfs.h> 29 - #include <linux/devcoredump.h> 30 29 #include <linux/rculist.h> 31 30 #include <linux/remoteproc.h> 32 - #include <linux/pm_runtime.h> 33 31 #include <linux/iommu.h> 34 32 #include <linux/idr.h> 35 33 #include <linux/elf.h> ··· 39 41 #include <linux/platform_device.h> 40 42 41 43 #include "remoteproc_internal.h" 42 - #include "remoteproc_elf_helpers.h" 43 44 44 45 #define HIGH_BITS_MASK 0xFFFFFFFF00000000ULL 45 46 ··· 241 244 * 242 245 * Return: a valid pointer on carveout entry on success or NULL on failure. 243 246 */ 247 + __printf(2, 3) 244 248 struct rproc_mem_entry * 245 249 rproc_find_carveout_by_name(struct rproc *rproc, const char *name, ...) 246 250 { ··· 409 411 410 412 idr_remove(&rproc->notifyids, rvring->notifyid); 411 413 412 - /* reset resource entry info */ 413 - rsc = (void *)rproc->table_ptr + rvring->rvdev->rsc_offset; 414 - rsc->vring[idx].da = 0; 415 - rsc->vring[idx].notifyid = -1; 414 + /* 415 + * At this point rproc_stop() has been called and the installed resource 416 + * table in the remote processor memory may no longer be accessible. As 417 + * such and as per rproc_stop(), rproc->table_ptr points to the cached 418 + * resource table (rproc->cached_table). The cached resource table is 419 + * only available when a remote processor has been booted by the 420 + * remoteproc core, otherwise it is NULL. 421 + * 422 + * Based on the above, reset the virtio device section in the cached 423 + * resource table only if there is one to work with. 424 + */ 425 + if (rproc->table_ptr) { 426 + rsc = (void *)rproc->table_ptr + rvring->rvdev->rsc_offset; 427 + rsc->vring[idx].da = 0; 428 + rsc->vring[idx].notifyid = -1; 429 + } 416 430 } 417 431 418 432 static int rproc_vdev_do_start(struct rproc_subdev *subdev) ··· 977 967 * This function allocates a rproc_mem_entry struct and fill it with parameters 978 968 * provided by client. 979 969 */ 970 + __printf(8, 9) 980 971 struct rproc_mem_entry * 981 972 rproc_mem_entry_init(struct device *dev, 982 973 void *va, dma_addr_t dma, size_t len, u32 da, ··· 1021 1010 * This function allocates a rproc_mem_entry struct and fill it with parameters 1022 1011 * provided by client. 1023 1012 */ 1013 + __printf(5, 6) 1024 1014 struct rproc_mem_entry * 1025 1015 rproc_of_resm_mem_entry_init(struct device *dev, u32 of_resm_idx, size_t len, 1026 1016 u32 da, const char *name, ...) ··· 1045 1033 return mem; 1046 1034 } 1047 1035 EXPORT_SYMBOL(rproc_of_resm_mem_entry_init); 1036 + 1037 + /** 1038 + * rproc_of_parse_firmware() - parse and return the firmware-name 1039 + * @dev: pointer on device struct representing a rproc 1040 + * @index: index to use for the firmware-name retrieval 1041 + * @fw_name: pointer to a character string, in which the firmware 1042 + * name is returned on success and unmodified otherwise. 1043 + * 1044 + * This is an OF helper function that parses a device's DT node for 1045 + * the "firmware-name" property and returns the firmware name pointer 1046 + * in @fw_name on success. 1047 + * 1048 + * Return: 0 on success, or an appropriate failure. 1049 + */ 1050 + int rproc_of_parse_firmware(struct device *dev, int index, const char **fw_name) 1051 + { 1052 + int ret; 1053 + 1054 + ret = of_property_read_string_index(dev->of_node, "firmware-name", 1055 + index, fw_name); 1056 + return ret ? ret : 0; 1057 + } 1058 + EXPORT_SYMBOL(rproc_of_parse_firmware); 1048 1059 1049 1060 /* 1050 1061 * A lookup table for resource handlers. The indices are defined in ··· 1274 1239 return 0; 1275 1240 } 1276 1241 1277 - /** 1278 - * rproc_coredump_cleanup() - clean up dump_segments list 1279 - * @rproc: the remote processor handle 1280 - */ 1281 - static void rproc_coredump_cleanup(struct rproc *rproc) 1282 - { 1283 - struct rproc_dump_segment *entry, *tmp; 1284 - 1285 - list_for_each_entry_safe(entry, tmp, &rproc->dump_segments, node) { 1286 - list_del(&entry->node); 1287 - kfree(entry); 1288 - } 1289 - } 1290 1242 1291 1243 /** 1292 1244 * rproc_resource_cleanup() - clean up and free all acquired resources ··· 1282 1260 * This function will free all resources acquired for @rproc, and it 1283 1261 * is called whenever @rproc either shuts down or fails to boot. 1284 1262 */ 1285 - static void rproc_resource_cleanup(struct rproc *rproc) 1263 + void rproc_resource_cleanup(struct rproc *rproc) 1286 1264 { 1287 1265 struct rproc_mem_entry *entry, *tmp; 1288 1266 struct rproc_debug_trace *trace, *ttmp; ··· 1326 1304 1327 1305 rproc_coredump_cleanup(rproc); 1328 1306 } 1307 + EXPORT_SYMBOL(rproc_resource_cleanup); 1329 1308 1330 1309 static int rproc_start(struct rproc *rproc, const struct firmware *fw) 1331 1310 { ··· 1393 1370 return ret; 1394 1371 } 1395 1372 1373 + static int rproc_attach(struct rproc *rproc) 1374 + { 1375 + struct device *dev = &rproc->dev; 1376 + int ret; 1377 + 1378 + ret = rproc_prepare_subdevices(rproc); 1379 + if (ret) { 1380 + dev_err(dev, "failed to prepare subdevices for %s: %d\n", 1381 + rproc->name, ret); 1382 + goto out; 1383 + } 1384 + 1385 + /* Attach to the remote processor */ 1386 + ret = rproc_attach_device(rproc); 1387 + if (ret) { 1388 + dev_err(dev, "can't attach to rproc %s: %d\n", 1389 + rproc->name, ret); 1390 + goto unprepare_subdevices; 1391 + } 1392 + 1393 + /* Start any subdevices for the remote processor */ 1394 + ret = rproc_start_subdevices(rproc); 1395 + if (ret) { 1396 + dev_err(dev, "failed to probe subdevices for %s: %d\n", 1397 + rproc->name, ret); 1398 + goto stop_rproc; 1399 + } 1400 + 1401 + rproc->state = RPROC_RUNNING; 1402 + 1403 + dev_info(dev, "remote processor %s is now attached\n", rproc->name); 1404 + 1405 + return 0; 1406 + 1407 + stop_rproc: 1408 + rproc->ops->stop(rproc); 1409 + unprepare_subdevices: 1410 + rproc_unprepare_subdevices(rproc); 1411 + out: 1412 + return ret; 1413 + } 1414 + 1396 1415 /* 1397 1416 * take a firmware and boot a remote processor with it. 1398 1417 */ ··· 1448 1383 if (ret) 1449 1384 return ret; 1450 1385 1451 - ret = pm_runtime_get_sync(dev); 1452 - if (ret < 0) { 1453 - dev_err(dev, "pm_runtime_get_sync failed: %d\n", ret); 1454 - return ret; 1455 - } 1456 - 1457 1386 dev_info(dev, "Booting fw image %s, size %zd\n", name, fw->size); 1458 1387 1459 1388 /* ··· 1457 1398 ret = rproc_enable_iommu(rproc); 1458 1399 if (ret) { 1459 1400 dev_err(dev, "can't enable iommu: %d\n", ret); 1460 - goto put_pm_runtime; 1401 + return ret; 1461 1402 } 1462 1403 1463 1404 /* Prepare rproc for firmware loading if needed */ ··· 1511 1452 rproc_unprepare_device(rproc); 1512 1453 disable_iommu: 1513 1454 rproc_disable_iommu(rproc); 1514 - put_pm_runtime: 1515 - pm_runtime_put(dev); 1455 + return ret; 1456 + } 1457 + 1458 + /* 1459 + * Attach to remote processor - similar to rproc_fw_boot() but without 1460 + * the steps that deal with the firmware image. 1461 + */ 1462 + static int rproc_actuate(struct rproc *rproc) 1463 + { 1464 + struct device *dev = &rproc->dev; 1465 + int ret; 1466 + 1467 + /* 1468 + * if enabling an IOMMU isn't relevant for this rproc, this is 1469 + * just a nop 1470 + */ 1471 + ret = rproc_enable_iommu(rproc); 1472 + if (ret) { 1473 + dev_err(dev, "can't enable iommu: %d\n", ret); 1474 + return ret; 1475 + } 1476 + 1477 + /* reset max_notifyid */ 1478 + rproc->max_notifyid = -1; 1479 + 1480 + /* reset handled vdev */ 1481 + rproc->nb_vdev = 0; 1482 + 1483 + /* 1484 + * Handle firmware resources required to attach to a remote processor. 1485 + * Because we are attaching rather than booting the remote processor, 1486 + * we expect the platform driver to properly set rproc->table_ptr. 1487 + */ 1488 + ret = rproc_handle_resources(rproc, rproc_loading_handlers); 1489 + if (ret) { 1490 + dev_err(dev, "Failed to process resources: %d\n", ret); 1491 + goto disable_iommu; 1492 + } 1493 + 1494 + /* Allocate carveout resources associated to rproc */ 1495 + ret = rproc_alloc_registered_carveouts(rproc); 1496 + if (ret) { 1497 + dev_err(dev, "Failed to allocate associated carveouts: %d\n", 1498 + ret); 1499 + goto clean_up_resources; 1500 + } 1501 + 1502 + ret = rproc_attach(rproc); 1503 + if (ret) 1504 + goto clean_up_resources; 1505 + 1506 + return 0; 1507 + 1508 + clean_up_resources: 1509 + rproc_resource_cleanup(rproc); 1510 + disable_iommu: 1511 + rproc_disable_iommu(rproc); 1516 1512 return ret; 1517 1513 } 1518 1514 ··· 1591 1477 static int rproc_trigger_auto_boot(struct rproc *rproc) 1592 1478 { 1593 1479 int ret; 1480 + 1481 + /* 1482 + * Since the remote processor is in a detached state, it has already 1483 + * been booted by another entity. As such there is no point in waiting 1484 + * for a firmware image to be loaded, we can simply initiate the process 1485 + * of attaching to it immediately. 1486 + */ 1487 + if (rproc->state == RPROC_DETACHED) 1488 + return rproc_boot(rproc); 1594 1489 1595 1490 /* 1596 1491 * We're initiating an asynchronous firmware loading, so we can ··· 1636 1513 1637 1514 rproc->state = RPROC_OFFLINE; 1638 1515 1516 + /* 1517 + * The remote processor has been stopped and is now offline, which means 1518 + * that the next time it is brought back online the remoteproc core will 1519 + * be responsible to load its firmware. As such it is no longer 1520 + * autonomous. 1521 + */ 1522 + rproc->autonomous = false; 1523 + 1639 1524 dev_info(dev, "stopped remote processor %s\n", rproc->name); 1640 1525 1641 1526 return 0; 1642 1527 } 1643 1528 1644 - /** 1645 - * rproc_coredump_add_segment() - add segment of device memory to coredump 1646 - * @rproc: handle of a remote processor 1647 - * @da: device address 1648 - * @size: size of segment 1649 - * 1650 - * Add device memory to the list of segments to be included in a coredump for 1651 - * the remoteproc. 1652 - * 1653 - * Return: 0 on success, negative errno on error. 1654 - */ 1655 - int rproc_coredump_add_segment(struct rproc *rproc, dma_addr_t da, size_t size) 1656 - { 1657 - struct rproc_dump_segment *segment; 1658 - 1659 - segment = kzalloc(sizeof(*segment), GFP_KERNEL); 1660 - if (!segment) 1661 - return -ENOMEM; 1662 - 1663 - segment->da = da; 1664 - segment->size = size; 1665 - 1666 - list_add_tail(&segment->node, &rproc->dump_segments); 1667 - 1668 - return 0; 1669 - } 1670 - EXPORT_SYMBOL(rproc_coredump_add_segment); 1671 - 1672 - /** 1673 - * rproc_coredump_add_custom_segment() - add custom coredump segment 1674 - * @rproc: handle of a remote processor 1675 - * @da: device address 1676 - * @size: size of segment 1677 - * @dumpfn: custom dump function called for each segment during coredump 1678 - * @priv: private data 1679 - * 1680 - * Add device memory to the list of segments to be included in the coredump 1681 - * and associate the segment with the given custom dump function and private 1682 - * data. 1683 - * 1684 - * Return: 0 on success, negative errno on error. 1685 - */ 1686 - int rproc_coredump_add_custom_segment(struct rproc *rproc, 1687 - dma_addr_t da, size_t size, 1688 - void (*dumpfn)(struct rproc *rproc, 1689 - struct rproc_dump_segment *segment, 1690 - void *dest), 1691 - void *priv) 1692 - { 1693 - struct rproc_dump_segment *segment; 1694 - 1695 - segment = kzalloc(sizeof(*segment), GFP_KERNEL); 1696 - if (!segment) 1697 - return -ENOMEM; 1698 - 1699 - segment->da = da; 1700 - segment->size = size; 1701 - segment->priv = priv; 1702 - segment->dump = dumpfn; 1703 - 1704 - list_add_tail(&segment->node, &rproc->dump_segments); 1705 - 1706 - return 0; 1707 - } 1708 - EXPORT_SYMBOL(rproc_coredump_add_custom_segment); 1709 - 1710 - /** 1711 - * rproc_coredump_set_elf_info() - set coredump elf information 1712 - * @rproc: handle of a remote processor 1713 - * @class: elf class for coredump elf file 1714 - * @machine: elf machine for coredump elf file 1715 - * 1716 - * Set elf information which will be used for coredump elf file. 1717 - * 1718 - * Return: 0 on success, negative errno on error. 1719 - */ 1720 - int rproc_coredump_set_elf_info(struct rproc *rproc, u8 class, u16 machine) 1721 - { 1722 - if (class != ELFCLASS64 && class != ELFCLASS32) 1723 - return -EINVAL; 1724 - 1725 - rproc->elf_class = class; 1726 - rproc->elf_machine = machine; 1727 - 1728 - return 0; 1729 - } 1730 - EXPORT_SYMBOL(rproc_coredump_set_elf_info); 1731 - 1732 - /** 1733 - * rproc_coredump() - perform coredump 1734 - * @rproc: rproc handle 1735 - * 1736 - * This function will generate an ELF header for the registered segments 1737 - * and create a devcoredump device associated with rproc. 1738 - */ 1739 - static void rproc_coredump(struct rproc *rproc) 1740 - { 1741 - struct rproc_dump_segment *segment; 1742 - void *phdr; 1743 - void *ehdr; 1744 - size_t data_size; 1745 - size_t offset; 1746 - void *data; 1747 - void *ptr; 1748 - u8 class = rproc->elf_class; 1749 - int phnum = 0; 1750 - 1751 - if (list_empty(&rproc->dump_segments)) 1752 - return; 1753 - 1754 - if (class == ELFCLASSNONE) { 1755 - dev_err(&rproc->dev, "Elf class is not set\n"); 1756 - return; 1757 - } 1758 - 1759 - data_size = elf_size_of_hdr(class); 1760 - list_for_each_entry(segment, &rproc->dump_segments, node) { 1761 - data_size += elf_size_of_phdr(class) + segment->size; 1762 - 1763 - phnum++; 1764 - } 1765 - 1766 - data = vmalloc(data_size); 1767 - if (!data) 1768 - return; 1769 - 1770 - ehdr = data; 1771 - 1772 - memset(ehdr, 0, elf_size_of_hdr(class)); 1773 - /* e_ident field is common for both elf32 and elf64 */ 1774 - elf_hdr_init_ident(ehdr, class); 1775 - 1776 - elf_hdr_set_e_type(class, ehdr, ET_CORE); 1777 - elf_hdr_set_e_machine(class, ehdr, rproc->elf_machine); 1778 - elf_hdr_set_e_version(class, ehdr, EV_CURRENT); 1779 - elf_hdr_set_e_entry(class, ehdr, rproc->bootaddr); 1780 - elf_hdr_set_e_phoff(class, ehdr, elf_size_of_hdr(class)); 1781 - elf_hdr_set_e_ehsize(class, ehdr, elf_size_of_hdr(class)); 1782 - elf_hdr_set_e_phentsize(class, ehdr, elf_size_of_phdr(class)); 1783 - elf_hdr_set_e_phnum(class, ehdr, phnum); 1784 - 1785 - phdr = data + elf_hdr_get_e_phoff(class, ehdr); 1786 - offset = elf_hdr_get_e_phoff(class, ehdr); 1787 - offset += elf_size_of_phdr(class) * elf_hdr_get_e_phnum(class, ehdr); 1788 - 1789 - list_for_each_entry(segment, &rproc->dump_segments, node) { 1790 - memset(phdr, 0, elf_size_of_phdr(class)); 1791 - elf_phdr_set_p_type(class, phdr, PT_LOAD); 1792 - elf_phdr_set_p_offset(class, phdr, offset); 1793 - elf_phdr_set_p_vaddr(class, phdr, segment->da); 1794 - elf_phdr_set_p_paddr(class, phdr, segment->da); 1795 - elf_phdr_set_p_filesz(class, phdr, segment->size); 1796 - elf_phdr_set_p_memsz(class, phdr, segment->size); 1797 - elf_phdr_set_p_flags(class, phdr, PF_R | PF_W | PF_X); 1798 - elf_phdr_set_p_align(class, phdr, 0); 1799 - 1800 - if (segment->dump) { 1801 - segment->dump(rproc, segment, data + offset); 1802 - } else { 1803 - ptr = rproc_da_to_va(rproc, segment->da, segment->size); 1804 - if (!ptr) { 1805 - dev_err(&rproc->dev, 1806 - "invalid coredump segment (%pad, %zu)\n", 1807 - &segment->da, segment->size); 1808 - memset(data + offset, 0xff, segment->size); 1809 - } else { 1810 - memcpy(data + offset, ptr, segment->size); 1811 - } 1812 - } 1813 - 1814 - offset += elf_phdr_get_p_filesz(class, phdr); 1815 - phdr += elf_size_of_phdr(class); 1816 - } 1817 - 1818 - dev_coredumpv(&rproc->dev, data, data_size, GFP_KERNEL); 1819 - } 1820 1529 1821 1530 /** 1822 1531 * rproc_trigger_recovery() - recover a remoteproc ··· 1770 1815 goto unlock_mutex; 1771 1816 } 1772 1817 1773 - /* skip the boot process if rproc is already powered up */ 1818 + /* skip the boot or attach process if rproc is already powered up */ 1774 1819 if (atomic_inc_return(&rproc->power) > 1) { 1775 1820 ret = 0; 1776 1821 goto unlock_mutex; 1777 1822 } 1778 1823 1779 - dev_info(dev, "powering up %s\n", rproc->name); 1824 + if (rproc->state == RPROC_DETACHED) { 1825 + dev_info(dev, "attaching to %s\n", rproc->name); 1780 1826 1781 - /* load firmware */ 1782 - ret = request_firmware(&firmware_p, rproc->firmware, dev); 1783 - if (ret < 0) { 1784 - dev_err(dev, "request_firmware failed: %d\n", ret); 1785 - goto downref_rproc; 1827 + ret = rproc_actuate(rproc); 1828 + } else { 1829 + dev_info(dev, "powering up %s\n", rproc->name); 1830 + 1831 + /* load firmware */ 1832 + ret = request_firmware(&firmware_p, rproc->firmware, dev); 1833 + if (ret < 0) { 1834 + dev_err(dev, "request_firmware failed: %d\n", ret); 1835 + goto downref_rproc; 1836 + } 1837 + 1838 + ret = rproc_fw_boot(rproc, firmware_p); 1839 + 1840 + release_firmware(firmware_p); 1786 1841 } 1787 - 1788 - ret = rproc_fw_boot(rproc, firmware_p); 1789 - 1790 - release_firmware(firmware_p); 1791 1842 1792 1843 downref_rproc: 1793 1844 if (ret) ··· 1851 1890 rproc_unprepare_device(rproc); 1852 1891 1853 1892 rproc_disable_iommu(rproc); 1854 - 1855 - pm_runtime_put(dev); 1856 1893 1857 1894 /* Free the copy of the resource table */ 1858 1895 kfree(rproc->cached_table); ··· 1911 1952 #endif 1912 1953 EXPORT_SYMBOL(rproc_get_by_phandle); 1913 1954 1955 + static int rproc_validate(struct rproc *rproc) 1956 + { 1957 + switch (rproc->state) { 1958 + case RPROC_OFFLINE: 1959 + /* 1960 + * An offline processor without a start() 1961 + * function makes no sense. 1962 + */ 1963 + if (!rproc->ops->start) 1964 + return -EINVAL; 1965 + break; 1966 + case RPROC_DETACHED: 1967 + /* 1968 + * A remote processor in a detached state without an 1969 + * attach() function makes not sense. 1970 + */ 1971 + if (!rproc->ops->attach) 1972 + return -EINVAL; 1973 + /* 1974 + * When attaching to a remote processor the device memory 1975 + * is already available and as such there is no need to have a 1976 + * cached table. 1977 + */ 1978 + if (rproc->cached_table) 1979 + return -EINVAL; 1980 + break; 1981 + default: 1982 + /* 1983 + * When adding a remote processor, the state of the device 1984 + * can be offline or detached, nothing else. 1985 + */ 1986 + return -EINVAL; 1987 + } 1988 + 1989 + return 0; 1990 + } 1991 + 1914 1992 /** 1915 1993 * rproc_add() - register a remote processor 1916 1994 * @rproc: the remote processor handle to register ··· 1977 1981 if (ret < 0) 1978 1982 return ret; 1979 1983 1984 + ret = rproc_validate(rproc); 1985 + if (ret < 0) 1986 + return ret; 1987 + 1980 1988 dev_info(dev, "%s is available\n", rproc->name); 1981 1989 1982 1990 /* create debugfs entries */ 1983 1991 rproc_create_debug_dir(rproc); 1992 + 1993 + /* add char device for this remoteproc */ 1994 + ret = rproc_char_device_add(rproc); 1995 + if (ret < 0) 1996 + return ret; 1997 + 1998 + /* 1999 + * Remind ourselves the remote processor has been attached to rather 2000 + * than booted by the remoteproc core. This is important because the 2001 + * RPROC_DETACHED state will be lost as soon as the remote processor 2002 + * has been attached to. Used in firmware_show() and reset in 2003 + * rproc_stop(). 2004 + */ 2005 + if (rproc->state == RPROC_DETACHED) 2006 + rproc->autonomous = true; 1984 2007 1985 2008 /* if rproc is marked always-on, request it to boot */ 1986 2009 if (rproc->auto_boot) { ··· 2198 2183 2199 2184 rproc->state = RPROC_OFFLINE; 2200 2185 2201 - pm_runtime_no_callbacks(&rproc->dev); 2202 - pm_runtime_enable(&rproc->dev); 2203 - 2204 2186 return rproc; 2205 2187 2206 2188 put_device: ··· 2217 2205 */ 2218 2206 void rproc_free(struct rproc *rproc) 2219 2207 { 2220 - pm_runtime_disable(&rproc->dev); 2221 2208 put_device(&rproc->dev); 2222 2209 } 2223 2210 EXPORT_SYMBOL(rproc_free); ··· 2267 2256 mutex_unlock(&rproc->lock); 2268 2257 2269 2258 rproc_delete_debug_dir(rproc); 2259 + rproc_char_device_remove(rproc); 2270 2260 2271 2261 /* the rproc is downref'ed as soon as it's removed from the klist */ 2272 2262 mutex_lock(&rproc_list_mutex); ··· 2436 2424 { 2437 2425 rproc_init_sysfs(); 2438 2426 rproc_init_debugfs(); 2427 + rproc_init_cdev(); 2439 2428 rproc_init_panic(); 2440 2429 2441 2430 return 0;
+325
drivers/remoteproc/remoteproc_coredump.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Coredump functionality for Remoteproc framework. 4 + * 5 + * Copyright (c) 2020, The Linux Foundation. All rights reserved. 6 + */ 7 + 8 + #include <linux/completion.h> 9 + #include <linux/devcoredump.h> 10 + #include <linux/device.h> 11 + #include <linux/kernel.h> 12 + #include <linux/remoteproc.h> 13 + #include "remoteproc_internal.h" 14 + #include "remoteproc_elf_helpers.h" 15 + 16 + struct rproc_coredump_state { 17 + struct rproc *rproc; 18 + void *header; 19 + struct completion dump_done; 20 + }; 21 + 22 + /** 23 + * rproc_coredump_cleanup() - clean up dump_segments list 24 + * @rproc: the remote processor handle 25 + */ 26 + void rproc_coredump_cleanup(struct rproc *rproc) 27 + { 28 + struct rproc_dump_segment *entry, *tmp; 29 + 30 + list_for_each_entry_safe(entry, tmp, &rproc->dump_segments, node) { 31 + list_del(&entry->node); 32 + kfree(entry); 33 + } 34 + } 35 + 36 + /** 37 + * rproc_coredump_add_segment() - add segment of device memory to coredump 38 + * @rproc: handle of a remote processor 39 + * @da: device address 40 + * @size: size of segment 41 + * 42 + * Add device memory to the list of segments to be included in a coredump for 43 + * the remoteproc. 44 + * 45 + * Return: 0 on success, negative errno on error. 46 + */ 47 + int rproc_coredump_add_segment(struct rproc *rproc, dma_addr_t da, size_t size) 48 + { 49 + struct rproc_dump_segment *segment; 50 + 51 + segment = kzalloc(sizeof(*segment), GFP_KERNEL); 52 + if (!segment) 53 + return -ENOMEM; 54 + 55 + segment->da = da; 56 + segment->size = size; 57 + 58 + list_add_tail(&segment->node, &rproc->dump_segments); 59 + 60 + return 0; 61 + } 62 + EXPORT_SYMBOL(rproc_coredump_add_segment); 63 + 64 + /** 65 + * rproc_coredump_add_custom_segment() - add custom coredump segment 66 + * @rproc: handle of a remote processor 67 + * @da: device address 68 + * @size: size of segment 69 + * @dumpfn: custom dump function called for each segment during coredump 70 + * @priv: private data 71 + * 72 + * Add device memory to the list of segments to be included in the coredump 73 + * and associate the segment with the given custom dump function and private 74 + * data. 75 + * 76 + * Return: 0 on success, negative errno on error. 77 + */ 78 + int rproc_coredump_add_custom_segment(struct rproc *rproc, 79 + dma_addr_t da, size_t size, 80 + void (*dumpfn)(struct rproc *rproc, 81 + struct rproc_dump_segment *segment, 82 + void *dest, size_t offset, 83 + size_t size), 84 + void *priv) 85 + { 86 + struct rproc_dump_segment *segment; 87 + 88 + segment = kzalloc(sizeof(*segment), GFP_KERNEL); 89 + if (!segment) 90 + return -ENOMEM; 91 + 92 + segment->da = da; 93 + segment->size = size; 94 + segment->priv = priv; 95 + segment->dump = dumpfn; 96 + 97 + list_add_tail(&segment->node, &rproc->dump_segments); 98 + 99 + return 0; 100 + } 101 + EXPORT_SYMBOL(rproc_coredump_add_custom_segment); 102 + 103 + /** 104 + * rproc_coredump_set_elf_info() - set coredump elf information 105 + * @rproc: handle of a remote processor 106 + * @class: elf class for coredump elf file 107 + * @machine: elf machine for coredump elf file 108 + * 109 + * Set elf information which will be used for coredump elf file. 110 + * 111 + * Return: 0 on success, negative errno on error. 112 + */ 113 + int rproc_coredump_set_elf_info(struct rproc *rproc, u8 class, u16 machine) 114 + { 115 + if (class != ELFCLASS64 && class != ELFCLASS32) 116 + return -EINVAL; 117 + 118 + rproc->elf_class = class; 119 + rproc->elf_machine = machine; 120 + 121 + return 0; 122 + } 123 + EXPORT_SYMBOL(rproc_coredump_set_elf_info); 124 + 125 + static void rproc_coredump_free(void *data) 126 + { 127 + struct rproc_coredump_state *dump_state = data; 128 + 129 + vfree(dump_state->header); 130 + complete(&dump_state->dump_done); 131 + } 132 + 133 + static void *rproc_coredump_find_segment(loff_t user_offset, 134 + struct list_head *segments, 135 + size_t *data_left) 136 + { 137 + struct rproc_dump_segment *segment; 138 + 139 + list_for_each_entry(segment, segments, node) { 140 + if (user_offset < segment->size) { 141 + *data_left = segment->size - user_offset; 142 + return segment; 143 + } 144 + user_offset -= segment->size; 145 + } 146 + 147 + *data_left = 0; 148 + return NULL; 149 + } 150 + 151 + static void rproc_copy_segment(struct rproc *rproc, void *dest, 152 + struct rproc_dump_segment *segment, 153 + size_t offset, size_t size) 154 + { 155 + void *ptr; 156 + 157 + if (segment->dump) { 158 + segment->dump(rproc, segment, dest, offset, size); 159 + } else { 160 + ptr = rproc_da_to_va(rproc, segment->da + offset, size); 161 + if (!ptr) { 162 + dev_err(&rproc->dev, 163 + "invalid copy request for segment %pad with offset %zu and size %zu)\n", 164 + &segment->da, offset, size); 165 + memset(dest, 0xff, size); 166 + } else { 167 + memcpy(dest, ptr, size); 168 + } 169 + } 170 + } 171 + 172 + static ssize_t rproc_coredump_read(char *buffer, loff_t offset, size_t count, 173 + void *data, size_t header_sz) 174 + { 175 + size_t seg_data, bytes_left = count; 176 + ssize_t copy_sz; 177 + struct rproc_dump_segment *seg; 178 + struct rproc_coredump_state *dump_state = data; 179 + struct rproc *rproc = dump_state->rproc; 180 + void *elfcore = dump_state->header; 181 + 182 + /* Copy the vmalloc'ed header first. */ 183 + if (offset < header_sz) { 184 + copy_sz = memory_read_from_buffer(buffer, count, &offset, 185 + elfcore, header_sz); 186 + 187 + return copy_sz; 188 + } 189 + 190 + /* 191 + * Find out the segment memory chunk to be copied based on offset. 192 + * Keep copying data until count bytes are read. 193 + */ 194 + while (bytes_left) { 195 + seg = rproc_coredump_find_segment(offset - header_sz, 196 + &rproc->dump_segments, 197 + &seg_data); 198 + /* EOF check */ 199 + if (!seg) { 200 + dev_info(&rproc->dev, "Ramdump done, %lld bytes read", 201 + offset); 202 + break; 203 + } 204 + 205 + copy_sz = min_t(size_t, bytes_left, seg_data); 206 + 207 + rproc_copy_segment(rproc, buffer, seg, seg->size - seg_data, 208 + copy_sz); 209 + 210 + offset += copy_sz; 211 + buffer += copy_sz; 212 + bytes_left -= copy_sz; 213 + } 214 + 215 + return count - bytes_left; 216 + } 217 + 218 + /** 219 + * rproc_coredump() - perform coredump 220 + * @rproc: rproc handle 221 + * 222 + * This function will generate an ELF header for the registered segments 223 + * and create a devcoredump device associated with rproc. Based on the 224 + * coredump configuration this function will directly copy the segments 225 + * from device memory to userspace or copy segments from device memory to 226 + * a separate buffer, which can then be read by userspace. 227 + * The first approach avoids using extra vmalloc memory. But it will stall 228 + * recovery flow until dump is read by userspace. 229 + */ 230 + void rproc_coredump(struct rproc *rproc) 231 + { 232 + struct rproc_dump_segment *segment; 233 + void *phdr; 234 + void *ehdr; 235 + size_t data_size; 236 + size_t offset; 237 + void *data; 238 + u8 class = rproc->elf_class; 239 + int phnum = 0; 240 + struct rproc_coredump_state dump_state; 241 + enum rproc_dump_mechanism dump_conf = rproc->dump_conf; 242 + 243 + if (list_empty(&rproc->dump_segments) || 244 + dump_conf == RPROC_COREDUMP_DISABLED) 245 + return; 246 + 247 + if (class == ELFCLASSNONE) { 248 + dev_err(&rproc->dev, "Elf class is not set\n"); 249 + return; 250 + } 251 + 252 + data_size = elf_size_of_hdr(class); 253 + list_for_each_entry(segment, &rproc->dump_segments, node) { 254 + /* 255 + * For default configuration buffer includes headers & segments. 256 + * For inline dump buffer just includes headers as segments are 257 + * directly read from device memory. 258 + */ 259 + data_size += elf_size_of_phdr(class); 260 + if (dump_conf == RPROC_COREDUMP_DEFAULT) 261 + data_size += segment->size; 262 + 263 + phnum++; 264 + } 265 + 266 + data = vmalloc(data_size); 267 + if (!data) 268 + return; 269 + 270 + ehdr = data; 271 + 272 + memset(ehdr, 0, elf_size_of_hdr(class)); 273 + /* e_ident field is common for both elf32 and elf64 */ 274 + elf_hdr_init_ident(ehdr, class); 275 + 276 + elf_hdr_set_e_type(class, ehdr, ET_CORE); 277 + elf_hdr_set_e_machine(class, ehdr, rproc->elf_machine); 278 + elf_hdr_set_e_version(class, ehdr, EV_CURRENT); 279 + elf_hdr_set_e_entry(class, ehdr, rproc->bootaddr); 280 + elf_hdr_set_e_phoff(class, ehdr, elf_size_of_hdr(class)); 281 + elf_hdr_set_e_ehsize(class, ehdr, elf_size_of_hdr(class)); 282 + elf_hdr_set_e_phentsize(class, ehdr, elf_size_of_phdr(class)); 283 + elf_hdr_set_e_phnum(class, ehdr, phnum); 284 + 285 + phdr = data + elf_hdr_get_e_phoff(class, ehdr); 286 + offset = elf_hdr_get_e_phoff(class, ehdr); 287 + offset += elf_size_of_phdr(class) * elf_hdr_get_e_phnum(class, ehdr); 288 + 289 + list_for_each_entry(segment, &rproc->dump_segments, node) { 290 + memset(phdr, 0, elf_size_of_phdr(class)); 291 + elf_phdr_set_p_type(class, phdr, PT_LOAD); 292 + elf_phdr_set_p_offset(class, phdr, offset); 293 + elf_phdr_set_p_vaddr(class, phdr, segment->da); 294 + elf_phdr_set_p_paddr(class, phdr, segment->da); 295 + elf_phdr_set_p_filesz(class, phdr, segment->size); 296 + elf_phdr_set_p_memsz(class, phdr, segment->size); 297 + elf_phdr_set_p_flags(class, phdr, PF_R | PF_W | PF_X); 298 + elf_phdr_set_p_align(class, phdr, 0); 299 + 300 + if (dump_conf == RPROC_COREDUMP_DEFAULT) 301 + rproc_copy_segment(rproc, data + offset, segment, 0, 302 + segment->size); 303 + 304 + offset += elf_phdr_get_p_filesz(class, phdr); 305 + phdr += elf_size_of_phdr(class); 306 + } 307 + if (dump_conf == RPROC_COREDUMP_DEFAULT) { 308 + dev_coredumpv(&rproc->dev, data, data_size, GFP_KERNEL); 309 + return; 310 + } 311 + 312 + /* Initialize the dump state struct to be used by rproc_coredump_read */ 313 + dump_state.rproc = rproc; 314 + dump_state.header = data; 315 + init_completion(&dump_state.dump_done); 316 + 317 + dev_coredumpm(&rproc->dev, NULL, &dump_state, data_size, GFP_KERNEL, 318 + rproc_coredump_read, rproc_coredump_free); 319 + 320 + /* 321 + * Wait until the dump is read and free is called. Data is freed 322 + * by devcoredump framework automatically after 5 minutes. 323 + */ 324 + wait_for_completion(&dump_state.dump_done); 325 + }
+90
drivers/remoteproc/remoteproc_debugfs.c
··· 28 28 static struct dentry *rproc_dbg; 29 29 30 30 /* 31 + * A coredump-configuration-to-string lookup table, for exposing a 32 + * human readable configuration via debugfs. Always keep in sync with 33 + * enum rproc_coredump_mechanism 34 + */ 35 + static const char * const rproc_coredump_str[] = { 36 + [RPROC_COREDUMP_DEFAULT] = "default", 37 + [RPROC_COREDUMP_INLINE] = "inline", 38 + [RPROC_COREDUMP_DISABLED] = "disabled", 39 + }; 40 + 41 + /* Expose the current coredump configuration via debugfs */ 42 + static ssize_t rproc_coredump_read(struct file *filp, char __user *userbuf, 43 + size_t count, loff_t *ppos) 44 + { 45 + struct rproc *rproc = filp->private_data; 46 + char buf[20]; 47 + int len; 48 + 49 + len = scnprintf(buf, sizeof(buf), "%s\n", 50 + rproc_coredump_str[rproc->dump_conf]); 51 + 52 + return simple_read_from_buffer(userbuf, count, ppos, buf, len); 53 + } 54 + 55 + /* 56 + * By writing to the 'coredump' debugfs entry, we control the behavior of the 57 + * coredump mechanism dynamically. The default value of this entry is "default". 58 + * 59 + * The 'coredump' debugfs entry supports these commands: 60 + * 61 + * default: This is the default coredump mechanism. When the remoteproc 62 + * crashes the entire coredump will be copied to a separate buffer 63 + * and exposed to userspace. 64 + * 65 + * inline: The coredump will not be copied to a separate buffer and the 66 + * recovery process will have to wait until data is read by 67 + * userspace. But this avoid usage of extra memory. 68 + * 69 + * disabled: This will disable coredump. Recovery will proceed without 70 + * collecting any dump. 71 + */ 72 + static ssize_t rproc_coredump_write(struct file *filp, 73 + const char __user *user_buf, size_t count, 74 + loff_t *ppos) 75 + { 76 + struct rproc *rproc = filp->private_data; 77 + int ret, err = 0; 78 + char buf[20]; 79 + 80 + if (count > sizeof(buf)) 81 + return -EINVAL; 82 + 83 + ret = copy_from_user(buf, user_buf, count); 84 + if (ret) 85 + return -EFAULT; 86 + 87 + /* remove end of line */ 88 + if (buf[count - 1] == '\n') 89 + buf[count - 1] = '\0'; 90 + 91 + if (rproc->state == RPROC_CRASHED) { 92 + dev_err(&rproc->dev, "can't change coredump configuration\n"); 93 + err = -EBUSY; 94 + goto out; 95 + } 96 + 97 + if (!strncmp(buf, "disable", count)) { 98 + rproc->dump_conf = RPROC_COREDUMP_DISABLED; 99 + } else if (!strncmp(buf, "inline", count)) { 100 + rproc->dump_conf = RPROC_COREDUMP_INLINE; 101 + } else if (!strncmp(buf, "default", count)) { 102 + rproc->dump_conf = RPROC_COREDUMP_DEFAULT; 103 + } else { 104 + dev_err(&rproc->dev, "Invalid coredump configuration\n"); 105 + err = -EINVAL; 106 + } 107 + out: 108 + return err ? err : count; 109 + } 110 + 111 + static const struct file_operations rproc_coredump_fops = { 112 + .read = rproc_coredump_read, 113 + .write = rproc_coredump_write, 114 + .open = simple_open, 115 + .llseek = generic_file_llseek, 116 + }; 117 + 118 + /* 31 119 * Some remote processors may support dumping trace logs into a shared 32 120 * memory buffer. We expose this trace buffer using debugfs, so users 33 121 * can easily tell what's going on remotely. ··· 425 337 rproc, &rproc_rsc_table_fops); 426 338 debugfs_create_file("carveout_memories", 0400, rproc->dbg_dir, 427 339 rproc, &rproc_carveouts_fops); 340 + debugfs_create_file("coredump", 0600, rproc->dbg_dir, 341 + rproc, &rproc_coredump_fops); 428 342 } 429 343 430 344 void __init rproc_init_debugfs(void)
+42
drivers/remoteproc/remoteproc_internal.h
··· 28 28 void rproc_release(struct kref *kref); 29 29 irqreturn_t rproc_vq_interrupt(struct rproc *rproc, int vq_id); 30 30 void rproc_vdev_release(struct kref *ref); 31 + int rproc_of_parse_firmware(struct device *dev, int index, 32 + const char **fw_name); 31 33 32 34 /* from remoteproc_virtio.c */ 33 35 int rproc_add_virtio_dev(struct rproc_vdev *rvdev, int id); ··· 48 46 extern struct class rproc_class; 49 47 int rproc_init_sysfs(void); 50 48 void rproc_exit_sysfs(void); 49 + 50 + /* from remoteproc_coredump.c */ 51 + void rproc_coredump_cleanup(struct rproc *rproc); 52 + void rproc_coredump(struct rproc *rproc); 53 + 54 + #ifdef CONFIG_REMOTEPROC_CDEV 55 + void rproc_init_cdev(void); 56 + void rproc_exit_cdev(void); 57 + int rproc_char_device_add(struct rproc *rproc); 58 + void rproc_char_device_remove(struct rproc *rproc); 59 + #else 60 + static inline void rproc_init_cdev(void) 61 + { 62 + } 63 + 64 + static inline void rproc_exit_cdev(void) 65 + { 66 + } 67 + 68 + /* 69 + * The character device interface is an optional feature, if it is not enabled 70 + * the function should not return an error. 71 + */ 72 + static inline int rproc_char_device_add(struct rproc *rproc) 73 + { 74 + return 0; 75 + } 76 + 77 + static inline void rproc_char_device_remove(struct rproc *rproc) 78 + { 79 + } 80 + #endif 51 81 52 82 void rproc_free_vring(struct rproc_vring *rvring); 53 83 int rproc_alloc_vring(struct rproc_vdev *rvdev, int i); ··· 109 75 { 110 76 if (rproc->ops->unprepare) 111 77 return rproc->ops->unprepare(rproc); 78 + 79 + return 0; 80 + } 81 + 82 + static inline int rproc_attach_device(struct rproc *rproc) 83 + { 84 + if (rproc->ops->attach) 85 + return rproc->ops->attach(rproc); 112 86 113 87 return 0; 114 88 }
+14 -1
drivers/remoteproc/remoteproc_sysfs.c
··· 15 15 char *buf) 16 16 { 17 17 struct rproc *rproc = to_rproc(dev); 18 + const char *firmware = rproc->firmware; 18 19 19 - return sprintf(buf, "%s\n", rproc->firmware); 20 + /* 21 + * If the remote processor has been started by an external 22 + * entity we have no idea of what image it is running. As such 23 + * simply display a generic string rather then rproc->firmware. 24 + * 25 + * Here we rely on the autonomous flag because a remote processor 26 + * may have been attached to and currently in a running state. 27 + */ 28 + if (rproc->autonomous) 29 + firmware = "unknown"; 30 + 31 + return sprintf(buf, "%s\n", firmware); 20 32 } 21 33 22 34 /* Change firmware name via sysfs */ ··· 84 72 [RPROC_RUNNING] = "running", 85 73 [RPROC_CRASHED] = "crashed", 86 74 [RPROC_DELETED] = "deleted", 75 + [RPROC_DETACHED] = "detached", 87 76 [RPROC_LAST] = "invalid", 88 77 }; 89 78
+196 -20
drivers/remoteproc/stm32_rproc.c
··· 39 39 #define STM32_MBX_VQ1_ID 1 40 40 #define STM32_MBX_SHUTDOWN "shutdown" 41 41 42 + #define RSC_TBL_SIZE 1024 43 + 44 + #define M4_STATE_OFF 0 45 + #define M4_STATE_INI 1 46 + #define M4_STATE_CRUN 2 47 + #define M4_STATE_CSTOP 3 48 + #define M4_STATE_STANDBY 4 49 + #define M4_STATE_CRASH 5 50 + 42 51 struct stm32_syscon { 43 52 struct regmap *map; 44 53 u32 reg; ··· 80 71 struct reset_control *rst; 81 72 struct stm32_syscon hold_boot; 82 73 struct stm32_syscon pdds; 74 + struct stm32_syscon m4_state; 75 + struct stm32_syscon rsctbl; 83 76 int wdg_irq; 84 77 u32 nb_rmems; 85 78 struct stm32_rproc_mem *rmems; 86 79 struct stm32_mbox mb[MBOX_NB_MBX]; 87 80 struct workqueue_struct *workqueue; 88 81 bool secured_soc; 82 + void __iomem *rsc_va; 89 83 }; 90 84 91 85 static int stm32_rproc_pa_to_da(struct rproc *rproc, phys_addr_t pa, u64 *da) ··· 140 128 return 0; 141 129 } 142 130 143 - static int stm32_rproc_of_memory_translations(struct rproc *rproc) 131 + static int stm32_rproc_of_memory_translations(struct platform_device *pdev, 132 + struct stm32_rproc *ddata) 144 133 { 145 - struct device *parent, *dev = rproc->dev.parent; 146 - struct stm32_rproc *ddata = rproc->priv; 134 + struct device *parent, *dev = &pdev->dev; 147 135 struct device_node *np; 148 136 struct stm32_rproc_mem *p_mems; 149 137 struct stm32_rproc_mem_ranges *mem_range; ··· 216 204 return 0; 217 205 } 218 206 219 - static int stm32_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw) 207 + static int stm32_rproc_parse_memory_regions(struct rproc *rproc) 220 208 { 221 209 struct device *dev = rproc->dev.parent; 222 210 struct device_node *np = dev->of_node; ··· 269 257 index++; 270 258 } 271 259 260 + return 0; 261 + } 262 + 263 + static int stm32_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw) 264 + { 265 + int ret = stm32_rproc_parse_memory_regions(rproc); 266 + 267 + if (ret) 268 + return ret; 269 + 272 270 return stm32_rproc_elf_load_rsc_table(rproc, fw); 273 271 } 274 272 275 273 static irqreturn_t stm32_rproc_wdg(int irq, void *data) 276 274 { 277 - struct rproc *rproc = data; 275 + struct platform_device *pdev = data; 276 + struct rproc *rproc = platform_get_drvdata(pdev); 278 277 279 278 rproc_report_crash(rproc, RPROC_WATCHDOG); 280 279 ··· 460 437 return stm32_rproc_set_hold_boot(rproc, true); 461 438 } 462 439 440 + static int stm32_rproc_attach(struct rproc *rproc) 441 + { 442 + stm32_rproc_add_coredump_trace(rproc); 443 + 444 + return stm32_rproc_set_hold_boot(rproc, true); 445 + } 446 + 463 447 static int stm32_rproc_stop(struct rproc *rproc) 464 448 { 465 449 struct stm32_rproc *ddata = rproc->priv; ··· 504 474 } 505 475 } 506 476 477 + /* update coprocessor state to OFF if available */ 478 + if (ddata->m4_state.map) { 479 + err = regmap_update_bits(ddata->m4_state.map, 480 + ddata->m4_state.reg, 481 + ddata->m4_state.mask, 482 + M4_STATE_OFF); 483 + if (err) { 484 + dev_err(&rproc->dev, "failed to set copro state\n"); 485 + return err; 486 + } 487 + } 488 + 507 489 return 0; 508 490 } 509 491 ··· 544 502 static struct rproc_ops st_rproc_ops = { 545 503 .start = stm32_rproc_start, 546 504 .stop = stm32_rproc_stop, 505 + .attach = stm32_rproc_attach, 547 506 .kick = stm32_rproc_kick, 548 507 .load = rproc_elf_load_segments, 549 508 .parse_fw = stm32_rproc_parse_fw, ··· 581 538 return err; 582 539 } 583 540 584 - static int stm32_rproc_parse_dt(struct platform_device *pdev) 541 + static int stm32_rproc_parse_dt(struct platform_device *pdev, 542 + struct stm32_rproc *ddata, bool *auto_boot) 585 543 { 586 544 struct device *dev = &pdev->dev; 587 545 struct device_node *np = dev->of_node; 588 - struct rproc *rproc = platform_get_drvdata(pdev); 589 - struct stm32_rproc *ddata = rproc->priv; 590 546 struct stm32_syscon tz; 591 547 unsigned int tzen; 592 548 int err, irq; ··· 596 554 597 555 if (irq > 0) { 598 556 err = devm_request_irq(dev, irq, stm32_rproc_wdg, 0, 599 - dev_name(dev), rproc); 557 + dev_name(dev), pdev); 600 558 if (err) { 601 559 dev_err(dev, "failed to request wdg irq\n"); 602 560 return err; ··· 631 589 632 590 err = regmap_read(tz.map, tz.reg, &tzen); 633 591 if (err) { 634 - dev_err(&rproc->dev, "failed to read tzen\n"); 592 + dev_err(dev, "failed to read tzen\n"); 635 593 return err; 636 594 } 637 595 ddata->secured_soc = tzen & tz.mask; ··· 647 605 if (err) 648 606 dev_info(dev, "failed to get pdds\n"); 649 607 650 - rproc->auto_boot = of_property_read_bool(np, "st,auto-boot"); 608 + *auto_boot = of_property_read_bool(np, "st,auto-boot"); 651 609 652 - return stm32_rproc_of_memory_translations(rproc); 610 + /* 611 + * See if we can check the M4 status, i.e if it was started 612 + * from the boot loader or not. 613 + */ 614 + err = stm32_rproc_get_syscon(np, "st,syscfg-m4-state", 615 + &ddata->m4_state); 616 + if (err) { 617 + /* remember this */ 618 + ddata->m4_state.map = NULL; 619 + /* no coprocessor state syscon (optional) */ 620 + dev_warn(dev, "m4 state not supported\n"); 621 + 622 + /* no need to go further */ 623 + return 0; 624 + } 625 + 626 + /* See if we can get the resource table */ 627 + err = stm32_rproc_get_syscon(np, "st,syscfg-rsc-tbl", 628 + &ddata->rsctbl); 629 + if (err) { 630 + /* no rsc table syscon (optional) */ 631 + dev_warn(dev, "rsc tbl syscon not supported\n"); 632 + } 633 + 634 + return 0; 635 + } 636 + 637 + static int stm32_rproc_get_m4_status(struct stm32_rproc *ddata, 638 + unsigned int *state) 639 + { 640 + /* See stm32_rproc_parse_dt() */ 641 + if (!ddata->m4_state.map) { 642 + /* 643 + * We couldn't get the coprocessor's state, assume 644 + * it is not running. 645 + */ 646 + state = M4_STATE_OFF; 647 + return 0; 648 + } 649 + 650 + return regmap_read(ddata->m4_state.map, ddata->m4_state.reg, state); 651 + } 652 + 653 + static int stm32_rproc_da_to_pa(struct platform_device *pdev, 654 + struct stm32_rproc *ddata, 655 + u64 da, phys_addr_t *pa) 656 + { 657 + struct device *dev = &pdev->dev; 658 + struct stm32_rproc_mem *p_mem; 659 + unsigned int i; 660 + 661 + for (i = 0; i < ddata->nb_rmems; i++) { 662 + p_mem = &ddata->rmems[i]; 663 + 664 + if (da < p_mem->dev_addr || 665 + da >= p_mem->dev_addr + p_mem->size) 666 + continue; 667 + 668 + *pa = da - p_mem->dev_addr + p_mem->bus_addr; 669 + dev_dbg(dev, "da %llx to pa %#x\n", da, *pa); 670 + 671 + return 0; 672 + } 673 + 674 + dev_err(dev, "can't translate da %llx\n", da); 675 + 676 + return -EINVAL; 677 + } 678 + 679 + static int stm32_rproc_get_loaded_rsc_table(struct platform_device *pdev, 680 + struct rproc *rproc, 681 + struct stm32_rproc *ddata) 682 + { 683 + struct device *dev = &pdev->dev; 684 + phys_addr_t rsc_pa; 685 + u32 rsc_da; 686 + int err; 687 + 688 + err = regmap_read(ddata->rsctbl.map, ddata->rsctbl.reg, &rsc_da); 689 + if (err) { 690 + dev_err(dev, "failed to read rsc tbl addr\n"); 691 + return err; 692 + } 693 + 694 + if (!rsc_da) 695 + /* no rsc table */ 696 + return 0; 697 + 698 + err = stm32_rproc_da_to_pa(pdev, ddata, rsc_da, &rsc_pa); 699 + if (err) 700 + return err; 701 + 702 + ddata->rsc_va = devm_ioremap_wc(dev, rsc_pa, RSC_TBL_SIZE); 703 + if (IS_ERR_OR_NULL(ddata->rsc_va)) { 704 + dev_err(dev, "Unable to map memory region: %pa+%zx\n", 705 + &rsc_pa, RSC_TBL_SIZE); 706 + ddata->rsc_va = NULL; 707 + return -ENOMEM; 708 + } 709 + 710 + /* 711 + * The resource table is already loaded in device memory, no need 712 + * to work with a cached table. 713 + */ 714 + rproc->cached_table = NULL; 715 + /* Assuming the resource table fits in 1kB is fair */ 716 + rproc->table_sz = RSC_TBL_SIZE; 717 + rproc->table_ptr = (struct resource_table *)ddata->rsc_va; 718 + 719 + return 0; 653 720 } 654 721 655 722 static int stm32_rproc_probe(struct platform_device *pdev) ··· 767 616 struct stm32_rproc *ddata; 768 617 struct device_node *np = dev->of_node; 769 618 struct rproc *rproc; 619 + unsigned int state; 770 620 int ret; 771 621 772 622 ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); ··· 778 626 if (!rproc) 779 627 return -ENOMEM; 780 628 781 - rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE); 782 - rproc->has_iommu = false; 783 629 ddata = rproc->priv; 630 + 631 + rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE); 632 + 633 + ret = stm32_rproc_parse_dt(pdev, ddata, &rproc->auto_boot); 634 + if (ret) 635 + goto free_rproc; 636 + 637 + ret = stm32_rproc_of_memory_translations(pdev, ddata); 638 + if (ret) 639 + goto free_rproc; 640 + 641 + ret = stm32_rproc_get_m4_status(ddata, &state); 642 + if (ret) 643 + goto free_rproc; 644 + 645 + if (state == M4_STATE_CRUN) { 646 + rproc->state = RPROC_DETACHED; 647 + 648 + ret = stm32_rproc_parse_memory_regions(rproc); 649 + if (ret) 650 + goto free_resources; 651 + 652 + ret = stm32_rproc_get_loaded_rsc_table(pdev, rproc, ddata); 653 + if (ret) 654 + goto free_resources; 655 + } 656 + 657 + rproc->has_iommu = false; 784 658 ddata->workqueue = create_workqueue(dev_name(dev)); 785 659 if (!ddata->workqueue) { 786 660 dev_err(dev, "cannot create workqueue\n"); 787 661 ret = -ENOMEM; 788 - goto free_rproc; 662 + goto free_resources; 789 663 } 790 664 791 665 platform_set_drvdata(pdev, rproc); 792 666 793 - ret = stm32_rproc_parse_dt(pdev); 794 - if (ret) 795 - goto free_wkq; 796 - 797 667 ret = stm32_rproc_request_mbox(rproc); 798 668 if (ret) 799 - goto free_rproc; 669 + goto free_wkq; 800 670 801 671 ret = rproc_add(rproc); 802 672 if (ret) ··· 830 656 stm32_rproc_free_mbox(rproc); 831 657 free_wkq: 832 658 destroy_workqueue(ddata->workqueue); 659 + free_resources: 660 + rproc_resource_cleanup(rproc); 833 661 free_rproc: 834 662 if (device_may_wakeup(dev)) { 835 663 dev_pm_clear_wake_irq(dev);
+787
drivers/remoteproc/ti_k3_dsp_remoteproc.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * TI K3 DSP Remote Processor(s) driver 4 + * 5 + * Copyright (C) 2018-2020 Texas Instruments Incorporated - https://www.ti.com/ 6 + * Suman Anna <s-anna@ti.com> 7 + */ 8 + 9 + #include <linux/io.h> 10 + #include <linux/mailbox_client.h> 11 + #include <linux/module.h> 12 + #include <linux/of_device.h> 13 + #include <linux/of_reserved_mem.h> 14 + #include <linux/omap-mailbox.h> 15 + #include <linux/platform_device.h> 16 + #include <linux/remoteproc.h> 17 + #include <linux/reset.h> 18 + #include <linux/slab.h> 19 + 20 + #include "omap_remoteproc.h" 21 + #include "remoteproc_internal.h" 22 + #include "ti_sci_proc.h" 23 + 24 + #define KEYSTONE_RPROC_LOCAL_ADDRESS_MASK (SZ_16M - 1) 25 + 26 + /** 27 + * struct k3_dsp_mem - internal memory structure 28 + * @cpu_addr: MPU virtual address of the memory region 29 + * @bus_addr: Bus address used to access the memory region 30 + * @dev_addr: Device address of the memory region from DSP view 31 + * @size: Size of the memory region 32 + */ 33 + struct k3_dsp_mem { 34 + void __iomem *cpu_addr; 35 + phys_addr_t bus_addr; 36 + u32 dev_addr; 37 + size_t size; 38 + }; 39 + 40 + /** 41 + * struct k3_dsp_mem_data - memory definitions for a DSP 42 + * @name: name for this memory entry 43 + * @dev_addr: device address for the memory entry 44 + */ 45 + struct k3_dsp_mem_data { 46 + const char *name; 47 + const u32 dev_addr; 48 + }; 49 + 50 + /** 51 + * struct k3_dsp_dev_data - device data structure for a DSP 52 + * @mems: pointer to memory definitions for a DSP 53 + * @num_mems: number of memory regions in @mems 54 + * @boot_align_addr: boot vector address alignment granularity 55 + * @uses_lreset: flag to denote the need for local reset management 56 + */ 57 + struct k3_dsp_dev_data { 58 + const struct k3_dsp_mem_data *mems; 59 + u32 num_mems; 60 + u32 boot_align_addr; 61 + bool uses_lreset; 62 + }; 63 + 64 + /** 65 + * struct k3_dsp_rproc - k3 DSP remote processor driver structure 66 + * @dev: cached device pointer 67 + * @rproc: remoteproc device handle 68 + * @mem: internal memory regions data 69 + * @num_mems: number of internal memory regions 70 + * @rmem: reserved memory regions data 71 + * @num_rmems: number of reserved memory regions 72 + * @reset: reset control handle 73 + * @data: pointer to DSP-specific device data 74 + * @tsp: TI-SCI processor control handle 75 + * @ti_sci: TI-SCI handle 76 + * @ti_sci_id: TI-SCI device identifier 77 + * @mbox: mailbox channel handle 78 + * @client: mailbox client to request the mailbox channel 79 + */ 80 + struct k3_dsp_rproc { 81 + struct device *dev; 82 + struct rproc *rproc; 83 + struct k3_dsp_mem *mem; 84 + int num_mems; 85 + struct k3_dsp_mem *rmem; 86 + int num_rmems; 87 + struct reset_control *reset; 88 + const struct k3_dsp_dev_data *data; 89 + struct ti_sci_proc *tsp; 90 + const struct ti_sci_handle *ti_sci; 91 + u32 ti_sci_id; 92 + struct mbox_chan *mbox; 93 + struct mbox_client client; 94 + }; 95 + 96 + /** 97 + * k3_dsp_rproc_mbox_callback() - inbound mailbox message handler 98 + * @client: mailbox client pointer used for requesting the mailbox channel 99 + * @data: mailbox payload 100 + * 101 + * This handler is invoked by the OMAP mailbox driver whenever a mailbox 102 + * message is received. Usually, the mailbox payload simply contains 103 + * the index of the virtqueue that is kicked by the remote processor, 104 + * and we let remoteproc core handle it. 105 + * 106 + * In addition to virtqueue indices, we also have some out-of-band values 107 + * that indicate different events. Those values are deliberately very 108 + * large so they don't coincide with virtqueue indices. 109 + */ 110 + static void k3_dsp_rproc_mbox_callback(struct mbox_client *client, void *data) 111 + { 112 + struct k3_dsp_rproc *kproc = container_of(client, struct k3_dsp_rproc, 113 + client); 114 + struct device *dev = kproc->rproc->dev.parent; 115 + const char *name = kproc->rproc->name; 116 + u32 msg = omap_mbox_message(data); 117 + 118 + dev_dbg(dev, "mbox msg: 0x%x\n", msg); 119 + 120 + switch (msg) { 121 + case RP_MBOX_CRASH: 122 + /* 123 + * remoteproc detected an exception, but error recovery is not 124 + * supported. So, just log this for now 125 + */ 126 + dev_err(dev, "K3 DSP rproc %s crashed\n", name); 127 + break; 128 + case RP_MBOX_ECHO_REPLY: 129 + dev_info(dev, "received echo reply from %s\n", name); 130 + break; 131 + default: 132 + /* silently handle all other valid messages */ 133 + if (msg >= RP_MBOX_READY && msg < RP_MBOX_END_MSG) 134 + return; 135 + if (msg > kproc->rproc->max_notifyid) { 136 + dev_dbg(dev, "dropping unknown message 0x%x", msg); 137 + return; 138 + } 139 + /* msg contains the index of the triggered vring */ 140 + if (rproc_vq_interrupt(kproc->rproc, msg) == IRQ_NONE) 141 + dev_dbg(dev, "no message was found in vqid %d\n", msg); 142 + } 143 + } 144 + 145 + /* 146 + * Kick the remote processor to notify about pending unprocessed messages. 147 + * The vqid usage is not used and is inconsequential, as the kick is performed 148 + * through a simulated GPIO (a bit in an IPC interrupt-triggering register), 149 + * the remote processor is expected to process both its Tx and Rx virtqueues. 150 + */ 151 + static void k3_dsp_rproc_kick(struct rproc *rproc, int vqid) 152 + { 153 + struct k3_dsp_rproc *kproc = rproc->priv; 154 + struct device *dev = rproc->dev.parent; 155 + mbox_msg_t msg = (mbox_msg_t)vqid; 156 + int ret; 157 + 158 + /* send the index of the triggered virtqueue in the mailbox payload */ 159 + ret = mbox_send_message(kproc->mbox, (void *)msg); 160 + if (ret < 0) 161 + dev_err(dev, "failed to send mailbox message, status = %d\n", 162 + ret); 163 + } 164 + 165 + /* Put the DSP processor into reset */ 166 + static int k3_dsp_rproc_reset(struct k3_dsp_rproc *kproc) 167 + { 168 + struct device *dev = kproc->dev; 169 + int ret; 170 + 171 + ret = reset_control_assert(kproc->reset); 172 + if (ret) { 173 + dev_err(dev, "local-reset assert failed, ret = %d\n", ret); 174 + return ret; 175 + } 176 + 177 + if (kproc->data->uses_lreset) 178 + return ret; 179 + 180 + ret = kproc->ti_sci->ops.dev_ops.put_device(kproc->ti_sci, 181 + kproc->ti_sci_id); 182 + if (ret) { 183 + dev_err(dev, "module-reset assert failed, ret = %d\n", ret); 184 + if (reset_control_deassert(kproc->reset)) 185 + dev_warn(dev, "local-reset deassert back failed\n"); 186 + } 187 + 188 + return ret; 189 + } 190 + 191 + /* Release the DSP processor from reset */ 192 + static int k3_dsp_rproc_release(struct k3_dsp_rproc *kproc) 193 + { 194 + struct device *dev = kproc->dev; 195 + int ret; 196 + 197 + if (kproc->data->uses_lreset) 198 + goto lreset; 199 + 200 + ret = kproc->ti_sci->ops.dev_ops.get_device(kproc->ti_sci, 201 + kproc->ti_sci_id); 202 + if (ret) { 203 + dev_err(dev, "module-reset deassert failed, ret = %d\n", ret); 204 + return ret; 205 + } 206 + 207 + lreset: 208 + ret = reset_control_deassert(kproc->reset); 209 + if (ret) { 210 + dev_err(dev, "local-reset deassert failed, ret = %d\n", ret); 211 + if (kproc->ti_sci->ops.dev_ops.put_device(kproc->ti_sci, 212 + kproc->ti_sci_id)) 213 + dev_warn(dev, "module-reset assert back failed\n"); 214 + } 215 + 216 + return ret; 217 + } 218 + 219 + /* 220 + * The C66x DSP cores have a local reset that affects only the CPU, and a 221 + * generic module reset that powers on the device and allows the DSP internal 222 + * memories to be accessed while the local reset is asserted. This function is 223 + * used to release the global reset on C66x DSPs to allow loading into the DSP 224 + * internal RAMs. The .prepare() ops is invoked by remoteproc core before any 225 + * firmware loading, and is followed by the .start() ops after loading to 226 + * actually let the C66x DSP cores run. 227 + */ 228 + static int k3_dsp_rproc_prepare(struct rproc *rproc) 229 + { 230 + struct k3_dsp_rproc *kproc = rproc->priv; 231 + struct device *dev = kproc->dev; 232 + int ret; 233 + 234 + ret = kproc->ti_sci->ops.dev_ops.get_device(kproc->ti_sci, 235 + kproc->ti_sci_id); 236 + if (ret) 237 + dev_err(dev, "module-reset deassert failed, cannot enable internal RAM loading, ret = %d\n", 238 + ret); 239 + 240 + return ret; 241 + } 242 + 243 + /* 244 + * This function implements the .unprepare() ops and performs the complimentary 245 + * operations to that of the .prepare() ops. The function is used to assert the 246 + * global reset on applicable C66x cores. This completes the second portion of 247 + * powering down the C66x DSP cores. The cores themselves are only halted in the 248 + * .stop() callback through the local reset, and the .unprepare() ops is invoked 249 + * by the remoteproc core after the remoteproc is stopped to balance the global 250 + * reset. 251 + */ 252 + static int k3_dsp_rproc_unprepare(struct rproc *rproc) 253 + { 254 + struct k3_dsp_rproc *kproc = rproc->priv; 255 + struct device *dev = kproc->dev; 256 + int ret; 257 + 258 + ret = kproc->ti_sci->ops.dev_ops.put_device(kproc->ti_sci, 259 + kproc->ti_sci_id); 260 + if (ret) 261 + dev_err(dev, "module-reset assert failed, ret = %d\n", ret); 262 + 263 + return ret; 264 + } 265 + 266 + /* 267 + * Power up the DSP remote processor. 268 + * 269 + * This function will be invoked only after the firmware for this rproc 270 + * was loaded, parsed successfully, and all of its resource requirements 271 + * were met. 272 + */ 273 + static int k3_dsp_rproc_start(struct rproc *rproc) 274 + { 275 + struct k3_dsp_rproc *kproc = rproc->priv; 276 + struct mbox_client *client = &kproc->client; 277 + struct device *dev = kproc->dev; 278 + u32 boot_addr; 279 + int ret; 280 + 281 + client->dev = dev; 282 + client->tx_done = NULL; 283 + client->rx_callback = k3_dsp_rproc_mbox_callback; 284 + client->tx_block = false; 285 + client->knows_txdone = false; 286 + 287 + kproc->mbox = mbox_request_channel(client, 0); 288 + if (IS_ERR(kproc->mbox)) { 289 + ret = -EBUSY; 290 + dev_err(dev, "mbox_request_channel failed: %ld\n", 291 + PTR_ERR(kproc->mbox)); 292 + return ret; 293 + } 294 + 295 + /* 296 + * Ping the remote processor, this is only for sanity-sake for now; 297 + * there is no functional effect whatsoever. 298 + * 299 + * Note that the reply will _not_ arrive immediately: this message 300 + * will wait in the mailbox fifo until the remote processor is booted. 301 + */ 302 + ret = mbox_send_message(kproc->mbox, (void *)RP_MBOX_ECHO_REQUEST); 303 + if (ret < 0) { 304 + dev_err(dev, "mbox_send_message failed: %d\n", ret); 305 + goto put_mbox; 306 + } 307 + 308 + boot_addr = rproc->bootaddr; 309 + if (boot_addr & (kproc->data->boot_align_addr - 1)) { 310 + dev_err(dev, "invalid boot address 0x%x, must be aligned on a 0x%x boundary\n", 311 + boot_addr, kproc->data->boot_align_addr); 312 + ret = -EINVAL; 313 + goto put_mbox; 314 + } 315 + 316 + dev_err(dev, "booting DSP core using boot addr = 0x%x\n", boot_addr); 317 + ret = ti_sci_proc_set_config(kproc->tsp, boot_addr, 0, 0); 318 + if (ret) 319 + goto put_mbox; 320 + 321 + ret = k3_dsp_rproc_release(kproc); 322 + if (ret) 323 + goto put_mbox; 324 + 325 + return 0; 326 + 327 + put_mbox: 328 + mbox_free_channel(kproc->mbox); 329 + return ret; 330 + } 331 + 332 + /* 333 + * Stop the DSP remote processor. 334 + * 335 + * This function puts the DSP processor into reset, and finishes processing 336 + * of any pending messages. 337 + */ 338 + static int k3_dsp_rproc_stop(struct rproc *rproc) 339 + { 340 + struct k3_dsp_rproc *kproc = rproc->priv; 341 + 342 + mbox_free_channel(kproc->mbox); 343 + 344 + k3_dsp_rproc_reset(kproc); 345 + 346 + return 0; 347 + } 348 + 349 + /* 350 + * Custom function to translate a DSP device address (internal RAMs only) to a 351 + * kernel virtual address. The DSPs can access their RAMs at either an internal 352 + * address visible only from a DSP, or at the SoC-level bus address. Both these 353 + * addresses need to be looked through for translation. The translated addresses 354 + * can be used either by the remoteproc core for loading (when using kernel 355 + * remoteproc loader), or by any rpmsg bus drivers. 356 + */ 357 + static void *k3_dsp_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len) 358 + { 359 + struct k3_dsp_rproc *kproc = rproc->priv; 360 + void __iomem *va = NULL; 361 + phys_addr_t bus_addr; 362 + u32 dev_addr, offset; 363 + size_t size; 364 + int i; 365 + 366 + if (len == 0) 367 + return NULL; 368 + 369 + for (i = 0; i < kproc->num_mems; i++) { 370 + bus_addr = kproc->mem[i].bus_addr; 371 + dev_addr = kproc->mem[i].dev_addr; 372 + size = kproc->mem[i].size; 373 + 374 + if (da < KEYSTONE_RPROC_LOCAL_ADDRESS_MASK) { 375 + /* handle DSP-view addresses */ 376 + if (da >= dev_addr && 377 + ((da + len) <= (dev_addr + size))) { 378 + offset = da - dev_addr; 379 + va = kproc->mem[i].cpu_addr + offset; 380 + return (__force void *)va; 381 + } 382 + } else { 383 + /* handle SoC-view addresses */ 384 + if (da >= bus_addr && 385 + (da + len) <= (bus_addr + size)) { 386 + offset = da - bus_addr; 387 + va = kproc->mem[i].cpu_addr + offset; 388 + return (__force void *)va; 389 + } 390 + } 391 + } 392 + 393 + /* handle static DDR reserved memory regions */ 394 + for (i = 0; i < kproc->num_rmems; i++) { 395 + dev_addr = kproc->rmem[i].dev_addr; 396 + size = kproc->rmem[i].size; 397 + 398 + if (da >= dev_addr && ((da + len) <= (dev_addr + size))) { 399 + offset = da - dev_addr; 400 + va = kproc->rmem[i].cpu_addr + offset; 401 + return (__force void *)va; 402 + } 403 + } 404 + 405 + return NULL; 406 + } 407 + 408 + static const struct rproc_ops k3_dsp_rproc_ops = { 409 + .start = k3_dsp_rproc_start, 410 + .stop = k3_dsp_rproc_stop, 411 + .kick = k3_dsp_rproc_kick, 412 + .da_to_va = k3_dsp_rproc_da_to_va, 413 + }; 414 + 415 + static int k3_dsp_rproc_of_get_memories(struct platform_device *pdev, 416 + struct k3_dsp_rproc *kproc) 417 + { 418 + const struct k3_dsp_dev_data *data = kproc->data; 419 + struct device *dev = &pdev->dev; 420 + struct resource *res; 421 + int num_mems = 0; 422 + int i; 423 + 424 + num_mems = kproc->data->num_mems; 425 + kproc->mem = devm_kcalloc(kproc->dev, num_mems, 426 + sizeof(*kproc->mem), GFP_KERNEL); 427 + if (!kproc->mem) 428 + return -ENOMEM; 429 + 430 + for (i = 0; i < num_mems; i++) { 431 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, 432 + data->mems[i].name); 433 + if (!res) { 434 + dev_err(dev, "found no memory resource for %s\n", 435 + data->mems[i].name); 436 + return -EINVAL; 437 + } 438 + if (!devm_request_mem_region(dev, res->start, 439 + resource_size(res), 440 + dev_name(dev))) { 441 + dev_err(dev, "could not request %s region for resource\n", 442 + data->mems[i].name); 443 + return -EBUSY; 444 + } 445 + 446 + kproc->mem[i].cpu_addr = devm_ioremap_wc(dev, res->start, 447 + resource_size(res)); 448 + if (IS_ERR(kproc->mem[i].cpu_addr)) { 449 + dev_err(dev, "failed to map %s memory\n", 450 + data->mems[i].name); 451 + return PTR_ERR(kproc->mem[i].cpu_addr); 452 + } 453 + kproc->mem[i].bus_addr = res->start; 454 + kproc->mem[i].dev_addr = data->mems[i].dev_addr; 455 + kproc->mem[i].size = resource_size(res); 456 + 457 + dev_dbg(dev, "memory %8s: bus addr %pa size 0x%zx va %pK da 0x%x\n", 458 + data->mems[i].name, &kproc->mem[i].bus_addr, 459 + kproc->mem[i].size, kproc->mem[i].cpu_addr, 460 + kproc->mem[i].dev_addr); 461 + } 462 + kproc->num_mems = num_mems; 463 + 464 + return 0; 465 + } 466 + 467 + static int k3_dsp_reserved_mem_init(struct k3_dsp_rproc *kproc) 468 + { 469 + struct device *dev = kproc->dev; 470 + struct device_node *np = dev->of_node; 471 + struct device_node *rmem_np; 472 + struct reserved_mem *rmem; 473 + int num_rmems; 474 + int ret, i; 475 + 476 + num_rmems = of_property_count_elems_of_size(np, "memory-region", 477 + sizeof(phandle)); 478 + if (num_rmems <= 0) { 479 + dev_err(dev, "device does not reserved memory regions, ret = %d\n", 480 + num_rmems); 481 + return -EINVAL; 482 + } 483 + if (num_rmems < 2) { 484 + dev_err(dev, "device needs atleast two memory regions to be defined, num = %d\n", 485 + num_rmems); 486 + return -EINVAL; 487 + } 488 + 489 + /* use reserved memory region 0 for vring DMA allocations */ 490 + ret = of_reserved_mem_device_init_by_idx(dev, np, 0); 491 + if (ret) { 492 + dev_err(dev, "device cannot initialize DMA pool, ret = %d\n", 493 + ret); 494 + return ret; 495 + } 496 + 497 + num_rmems--; 498 + kproc->rmem = kcalloc(num_rmems, sizeof(*kproc->rmem), GFP_KERNEL); 499 + if (!kproc->rmem) { 500 + ret = -ENOMEM; 501 + goto release_rmem; 502 + } 503 + 504 + /* use remaining reserved memory regions for static carveouts */ 505 + for (i = 0; i < num_rmems; i++) { 506 + rmem_np = of_parse_phandle(np, "memory-region", i + 1); 507 + if (!rmem_np) { 508 + ret = -EINVAL; 509 + goto unmap_rmem; 510 + } 511 + 512 + rmem = of_reserved_mem_lookup(rmem_np); 513 + if (!rmem) { 514 + of_node_put(rmem_np); 515 + ret = -EINVAL; 516 + goto unmap_rmem; 517 + } 518 + of_node_put(rmem_np); 519 + 520 + kproc->rmem[i].bus_addr = rmem->base; 521 + /* 64-bit address regions currently not supported */ 522 + kproc->rmem[i].dev_addr = (u32)rmem->base; 523 + kproc->rmem[i].size = rmem->size; 524 + kproc->rmem[i].cpu_addr = ioremap_wc(rmem->base, rmem->size); 525 + if (!kproc->rmem[i].cpu_addr) { 526 + dev_err(dev, "failed to map reserved memory#%d at %pa of size %pa\n", 527 + i + 1, &rmem->base, &rmem->size); 528 + ret = -ENOMEM; 529 + goto unmap_rmem; 530 + } 531 + 532 + dev_dbg(dev, "reserved memory%d: bus addr %pa size 0x%zx va %pK da 0x%x\n", 533 + i + 1, &kproc->rmem[i].bus_addr, 534 + kproc->rmem[i].size, kproc->rmem[i].cpu_addr, 535 + kproc->rmem[i].dev_addr); 536 + } 537 + kproc->num_rmems = num_rmems; 538 + 539 + return 0; 540 + 541 + unmap_rmem: 542 + for (i--; i >= 0; i--) 543 + iounmap(kproc->rmem[i].cpu_addr); 544 + kfree(kproc->rmem); 545 + release_rmem: 546 + of_reserved_mem_device_release(kproc->dev); 547 + return ret; 548 + } 549 + 550 + static void k3_dsp_reserved_mem_exit(struct k3_dsp_rproc *kproc) 551 + { 552 + int i; 553 + 554 + for (i = 0; i < kproc->num_rmems; i++) 555 + iounmap(kproc->rmem[i].cpu_addr); 556 + kfree(kproc->rmem); 557 + 558 + of_reserved_mem_device_release(kproc->dev); 559 + } 560 + 561 + static 562 + struct ti_sci_proc *k3_dsp_rproc_of_get_tsp(struct device *dev, 563 + const struct ti_sci_handle *sci) 564 + { 565 + struct ti_sci_proc *tsp; 566 + u32 temp[2]; 567 + int ret; 568 + 569 + ret = of_property_read_u32_array(dev->of_node, "ti,sci-proc-ids", 570 + temp, 2); 571 + if (ret < 0) 572 + return ERR_PTR(ret); 573 + 574 + tsp = kzalloc(sizeof(*tsp), GFP_KERNEL); 575 + if (!tsp) 576 + return ERR_PTR(-ENOMEM); 577 + 578 + tsp->dev = dev; 579 + tsp->sci = sci; 580 + tsp->ops = &sci->ops.proc_ops; 581 + tsp->proc_id = temp[0]; 582 + tsp->host_id = temp[1]; 583 + 584 + return tsp; 585 + } 586 + 587 + static int k3_dsp_rproc_probe(struct platform_device *pdev) 588 + { 589 + struct device *dev = &pdev->dev; 590 + struct device_node *np = dev->of_node; 591 + const struct k3_dsp_dev_data *data; 592 + struct k3_dsp_rproc *kproc; 593 + struct rproc *rproc; 594 + const char *fw_name; 595 + int ret = 0; 596 + int ret1; 597 + 598 + data = of_device_get_match_data(dev); 599 + if (!data) 600 + return -ENODEV; 601 + 602 + ret = rproc_of_parse_firmware(dev, 0, &fw_name); 603 + if (ret) { 604 + dev_err(dev, "failed to parse firmware-name property, ret = %d\n", 605 + ret); 606 + return ret; 607 + } 608 + 609 + rproc = rproc_alloc(dev, dev_name(dev), &k3_dsp_rproc_ops, fw_name, 610 + sizeof(*kproc)); 611 + if (!rproc) 612 + return -ENOMEM; 613 + 614 + rproc->has_iommu = false; 615 + rproc->recovery_disabled = true; 616 + if (data->uses_lreset) { 617 + rproc->ops->prepare = k3_dsp_rproc_prepare; 618 + rproc->ops->unprepare = k3_dsp_rproc_unprepare; 619 + } 620 + kproc = rproc->priv; 621 + kproc->rproc = rproc; 622 + kproc->dev = dev; 623 + kproc->data = data; 624 + 625 + kproc->ti_sci = ti_sci_get_by_phandle(np, "ti,sci"); 626 + if (IS_ERR(kproc->ti_sci)) { 627 + ret = PTR_ERR(kproc->ti_sci); 628 + if (ret != -EPROBE_DEFER) { 629 + dev_err(dev, "failed to get ti-sci handle, ret = %d\n", 630 + ret); 631 + } 632 + kproc->ti_sci = NULL; 633 + goto free_rproc; 634 + } 635 + 636 + ret = of_property_read_u32(np, "ti,sci-dev-id", &kproc->ti_sci_id); 637 + if (ret) { 638 + dev_err(dev, "missing 'ti,sci-dev-id' property\n"); 639 + goto put_sci; 640 + } 641 + 642 + kproc->reset = devm_reset_control_get_exclusive(dev, NULL); 643 + if (IS_ERR(kproc->reset)) { 644 + ret = PTR_ERR(kproc->reset); 645 + dev_err(dev, "failed to get reset, status = %d\n", ret); 646 + goto put_sci; 647 + } 648 + 649 + kproc->tsp = k3_dsp_rproc_of_get_tsp(dev, kproc->ti_sci); 650 + if (IS_ERR(kproc->tsp)) { 651 + dev_err(dev, "failed to construct ti-sci proc control, ret = %d\n", 652 + ret); 653 + ret = PTR_ERR(kproc->tsp); 654 + goto put_sci; 655 + } 656 + 657 + ret = ti_sci_proc_request(kproc->tsp); 658 + if (ret < 0) { 659 + dev_err(dev, "ti_sci_proc_request failed, ret = %d\n", ret); 660 + goto free_tsp; 661 + } 662 + 663 + ret = k3_dsp_rproc_of_get_memories(pdev, kproc); 664 + if (ret) 665 + goto release_tsp; 666 + 667 + ret = k3_dsp_reserved_mem_init(kproc); 668 + if (ret) { 669 + dev_err(dev, "reserved memory init failed, ret = %d\n", ret); 670 + goto release_tsp; 671 + } 672 + 673 + /* 674 + * ensure the DSP local reset is asserted to ensure the DSP doesn't 675 + * execute bogus code in .prepare() when the module reset is released. 676 + */ 677 + if (data->uses_lreset) { 678 + ret = reset_control_status(kproc->reset); 679 + if (ret < 0) { 680 + dev_err(dev, "failed to get reset status, status = %d\n", 681 + ret); 682 + goto release_mem; 683 + } else if (ret == 0) { 684 + dev_warn(dev, "local reset is deasserted for device\n"); 685 + k3_dsp_rproc_reset(kproc); 686 + } 687 + } 688 + 689 + ret = rproc_add(rproc); 690 + if (ret) { 691 + dev_err(dev, "failed to add register device with remoteproc core, status = %d\n", 692 + ret); 693 + goto release_mem; 694 + } 695 + 696 + platform_set_drvdata(pdev, kproc); 697 + 698 + return 0; 699 + 700 + release_mem: 701 + k3_dsp_reserved_mem_exit(kproc); 702 + release_tsp: 703 + ret1 = ti_sci_proc_release(kproc->tsp); 704 + if (ret1) 705 + dev_err(dev, "failed to release proc, ret = %d\n", ret1); 706 + free_tsp: 707 + kfree(kproc->tsp); 708 + put_sci: 709 + ret1 = ti_sci_put_handle(kproc->ti_sci); 710 + if (ret1) 711 + dev_err(dev, "failed to put ti_sci handle, ret = %d\n", ret1); 712 + free_rproc: 713 + rproc_free(rproc); 714 + return ret; 715 + } 716 + 717 + static int k3_dsp_rproc_remove(struct platform_device *pdev) 718 + { 719 + struct k3_dsp_rproc *kproc = platform_get_drvdata(pdev); 720 + struct device *dev = &pdev->dev; 721 + int ret; 722 + 723 + rproc_del(kproc->rproc); 724 + 725 + ret = ti_sci_proc_release(kproc->tsp); 726 + if (ret) 727 + dev_err(dev, "failed to release proc, ret = %d\n", ret); 728 + 729 + kfree(kproc->tsp); 730 + 731 + ret = ti_sci_put_handle(kproc->ti_sci); 732 + if (ret) 733 + dev_err(dev, "failed to put ti_sci handle, ret = %d\n", ret); 734 + 735 + k3_dsp_reserved_mem_exit(kproc); 736 + rproc_free(kproc->rproc); 737 + 738 + return 0; 739 + } 740 + 741 + static const struct k3_dsp_mem_data c66_mems[] = { 742 + { .name = "l2sram", .dev_addr = 0x800000 }, 743 + { .name = "l1pram", .dev_addr = 0xe00000 }, 744 + { .name = "l1dram", .dev_addr = 0xf00000 }, 745 + }; 746 + 747 + /* C71x cores only have a L1P Cache, there are no L1P SRAMs */ 748 + static const struct k3_dsp_mem_data c71_mems[] = { 749 + { .name = "l2sram", .dev_addr = 0x800000 }, 750 + { .name = "l1dram", .dev_addr = 0xe00000 }, 751 + }; 752 + 753 + static const struct k3_dsp_dev_data c66_data = { 754 + .mems = c66_mems, 755 + .num_mems = ARRAY_SIZE(c66_mems), 756 + .boot_align_addr = SZ_1K, 757 + .uses_lreset = true, 758 + }; 759 + 760 + static const struct k3_dsp_dev_data c71_data = { 761 + .mems = c71_mems, 762 + .num_mems = ARRAY_SIZE(c71_mems), 763 + .boot_align_addr = SZ_2M, 764 + .uses_lreset = false, 765 + }; 766 + 767 + static const struct of_device_id k3_dsp_of_match[] = { 768 + { .compatible = "ti,j721e-c66-dsp", .data = &c66_data, }, 769 + { .compatible = "ti,j721e-c71-dsp", .data = &c71_data, }, 770 + { /* sentinel */ }, 771 + }; 772 + MODULE_DEVICE_TABLE(of, k3_dsp_of_match); 773 + 774 + static struct platform_driver k3_dsp_rproc_driver = { 775 + .probe = k3_dsp_rproc_probe, 776 + .remove = k3_dsp_rproc_remove, 777 + .driver = { 778 + .name = "k3-dsp-rproc", 779 + .of_match_table = k3_dsp_of_match, 780 + }, 781 + }; 782 + 783 + module_platform_driver(k3_dsp_rproc_driver); 784 + 785 + MODULE_AUTHOR("Suman Anna <s-anna@ti.com>"); 786 + MODULE_LICENSE("GPL v2"); 787 + MODULE_DESCRIPTION("TI K3 DSP Remoteproc driver");
+104
drivers/remoteproc/ti_sci_proc.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Texas Instruments TI-SCI Processor Controller Helper Functions 4 + * 5 + * Copyright (C) 2018-2020 Texas Instruments Incorporated - https://www.ti.com/ 6 + * Suman Anna <s-anna@ti.com> 7 + */ 8 + 9 + #ifndef REMOTEPROC_TI_SCI_PROC_H 10 + #define REMOTEPROC_TI_SCI_PROC_H 11 + 12 + #include <linux/soc/ti/ti_sci_protocol.h> 13 + 14 + /** 15 + * struct ti_sci_proc - structure representing a processor control client 16 + * @sci: cached TI-SCI protocol handle 17 + * @ops: cached TI-SCI proc ops 18 + * @dev: cached client device pointer 19 + * @proc_id: processor id for the consumer remoteproc device 20 + * @host_id: host id to pass the control over for this consumer remoteproc 21 + * device 22 + */ 23 + struct ti_sci_proc { 24 + const struct ti_sci_handle *sci; 25 + const struct ti_sci_proc_ops *ops; 26 + struct device *dev; 27 + u8 proc_id; 28 + u8 host_id; 29 + }; 30 + 31 + static inline int ti_sci_proc_request(struct ti_sci_proc *tsp) 32 + { 33 + int ret; 34 + 35 + ret = tsp->ops->request(tsp->sci, tsp->proc_id); 36 + if (ret) 37 + dev_err(tsp->dev, "ti-sci processor request failed: %d\n", 38 + ret); 39 + return ret; 40 + } 41 + 42 + static inline int ti_sci_proc_release(struct ti_sci_proc *tsp) 43 + { 44 + int ret; 45 + 46 + ret = tsp->ops->release(tsp->sci, tsp->proc_id); 47 + if (ret) 48 + dev_err(tsp->dev, "ti-sci processor release failed: %d\n", 49 + ret); 50 + return ret; 51 + } 52 + 53 + static inline int ti_sci_proc_handover(struct ti_sci_proc *tsp) 54 + { 55 + int ret; 56 + 57 + ret = tsp->ops->handover(tsp->sci, tsp->proc_id, tsp->host_id); 58 + if (ret) 59 + dev_err(tsp->dev, "ti-sci processor handover of %d to %d failed: %d\n", 60 + tsp->proc_id, tsp->host_id, ret); 61 + return ret; 62 + } 63 + 64 + static inline int ti_sci_proc_set_config(struct ti_sci_proc *tsp, 65 + u64 boot_vector, 66 + u32 cfg_set, u32 cfg_clr) 67 + { 68 + int ret; 69 + 70 + ret = tsp->ops->set_config(tsp->sci, tsp->proc_id, boot_vector, 71 + cfg_set, cfg_clr); 72 + if (ret) 73 + dev_err(tsp->dev, "ti-sci processor set_config failed: %d\n", 74 + ret); 75 + return ret; 76 + } 77 + 78 + static inline int ti_sci_proc_set_control(struct ti_sci_proc *tsp, 79 + u32 ctrl_set, u32 ctrl_clr) 80 + { 81 + int ret; 82 + 83 + ret = tsp->ops->set_control(tsp->sci, tsp->proc_id, ctrl_set, ctrl_clr); 84 + if (ret) 85 + dev_err(tsp->dev, "ti-sci processor set_control failed: %d\n", 86 + ret); 87 + return ret; 88 + } 89 + 90 + static inline int ti_sci_proc_get_status(struct ti_sci_proc *tsp, 91 + u64 *boot_vector, u32 *cfg_flags, 92 + u32 *ctrl_flags, u32 *status_flags) 93 + { 94 + int ret; 95 + 96 + ret = tsp->ops->get_status(tsp->sci, tsp->proc_id, boot_vector, 97 + cfg_flags, ctrl_flags, status_flags); 98 + if (ret) 99 + dev_err(tsp->dev, "ti-sci processor get_status failed: %d\n", 100 + ret); 101 + return ret; 102 + } 103 + 104 + #endif /* REMOTEPROC_TI_SCI_PROC_H */
+33 -3
include/linux/remoteproc.h
··· 38 38 #include <linux/types.h> 39 39 #include <linux/mutex.h> 40 40 #include <linux/virtio.h> 41 + #include <linux/cdev.h> 41 42 #include <linux/completion.h> 42 43 #include <linux/idr.h> 43 44 #include <linux/of.h> ··· 360 359 * @unprepare: unprepare device after stop 361 360 * @start: power on the device and boot it 362 361 * @stop: power off the device 362 + * @attach: attach to a device that his already powered up 363 363 * @kick: kick a virtqueue (virtqueue id given as a parameter) 364 364 * @da_to_va: optional platform hook to perform address translations 365 365 * @parse_fw: parse firmware to extract information (e.g. resource table) ··· 381 379 int (*unprepare)(struct rproc *rproc); 382 380 int (*start)(struct rproc *rproc); 383 381 int (*stop)(struct rproc *rproc); 382 + int (*attach)(struct rproc *rproc); 384 383 void (*kick)(struct rproc *rproc, int vqid); 385 384 void * (*da_to_va)(struct rproc *rproc, u64 da, size_t len); 386 385 int (*parse_fw)(struct rproc *rproc, const struct firmware *fw); ··· 403 400 * @RPROC_RUNNING: device is up and running 404 401 * @RPROC_CRASHED: device has crashed; need to start recovery 405 402 * @RPROC_DELETED: device is deleted 403 + * @RPROC_DETACHED: device has been booted by another entity and waiting 404 + * for the core to attach to it 406 405 * @RPROC_LAST: just keep this one at the end 407 406 * 408 407 * Please note that the values of these states are used as indices ··· 419 414 RPROC_RUNNING = 2, 420 415 RPROC_CRASHED = 3, 421 416 RPROC_DELETED = 4, 422 - RPROC_LAST = 5, 417 + RPROC_DETACHED = 5, 418 + RPROC_LAST = 6, 423 419 }; 424 420 425 421 /** ··· 441 435 }; 442 436 443 437 /** 438 + * enum rproc_dump_mechanism - Coredump options for core 439 + * @RPROC_COREDUMP_DEFAULT: Copy dump to separate buffer and carry on with 440 + recovery 441 + * @RPROC_COREDUMP_INLINE: Read segments directly from device memory. Stall 442 + recovery until all segments are read 443 + * @RPROC_COREDUMP_DISABLED: Don't perform any dump 444 + */ 445 + enum rproc_dump_mechanism { 446 + RPROC_COREDUMP_DEFAULT, 447 + RPROC_COREDUMP_INLINE, 448 + RPROC_COREDUMP_DISABLED, 449 + }; 450 + 451 + /** 444 452 * struct rproc_dump_segment - segment info from ELF header 445 453 * @node: list node related to the rproc segment list 446 454 * @da: device address of the segment ··· 471 451 472 452 void *priv; 473 453 void (*dump)(struct rproc *rproc, struct rproc_dump_segment *segment, 474 - void *dest); 454 + void *dest, size_t offset, size_t size); 475 455 loff_t offset; 476 456 }; 477 457 ··· 486 466 * @dev: virtual device for refcounting and common remoteproc behavior 487 467 * @power: refcount of users who need this rproc powered up 488 468 * @state: state of the device 469 + * @dump_conf: Currently selected coredump configuration 489 470 * @lock: lock which protects concurrent manipulations of the rproc 490 471 * @dbg_dir: debugfs directory of this rproc device 491 472 * @traces: list of trace buffers ··· 507 486 * @table_sz: size of @cached_table 508 487 * @has_iommu: flag to indicate if remote processor is behind an MMU 509 488 * @auto_boot: flag to indicate if remote processor should be auto-started 489 + * @autonomous: true if an external entity has booted the remote processor 510 490 * @dump_segments: list of segments in the firmware 511 491 * @nb_vdev: number of vdev currently handled by rproc 492 + * @char_dev: character device of the rproc 493 + * @cdev_put_on_release: flag to indicate if remoteproc should be shutdown on @char_dev release 512 494 */ 513 495 struct rproc { 514 496 struct list_head node; ··· 523 499 struct device dev; 524 500 atomic_t power; 525 501 unsigned int state; 502 + enum rproc_dump_mechanism dump_conf; 526 503 struct mutex lock; 527 504 struct dentry *dbg_dir; 528 505 struct list_head traces; ··· 544 519 size_t table_sz; 545 520 bool has_iommu; 546 521 bool auto_boot; 522 + bool autonomous; 547 523 struct list_head dump_segments; 548 524 int nb_vdev; 549 525 u8 elf_class; 550 526 u16 elf_machine; 527 + struct cdev cdev; 528 + bool cdev_put_on_release; 551 529 }; 552 530 553 531 /** ··· 631 603 int rproc_add(struct rproc *rproc); 632 604 int rproc_del(struct rproc *rproc); 633 605 void rproc_free(struct rproc *rproc); 606 + void rproc_resource_cleanup(struct rproc *rproc); 634 607 635 608 struct rproc *devm_rproc_alloc(struct device *dev, const char *name, 636 609 const struct rproc_ops *ops, ··· 659 630 dma_addr_t da, size_t size, 660 631 void (*dumpfn)(struct rproc *rproc, 661 632 struct rproc_dump_segment *segment, 662 - void *dest), 633 + void *dest, size_t offset, 634 + size_t size), 663 635 void *priv); 664 636 int rproc_coredump_set_elf_info(struct rproc *rproc, u8 class, u16 machine); 665 637
-82
include/linux/remoteproc/qcom_q6v5_ipa_notify.h
··· 1 - /* SPDX-License-Identifier: GPL-2.0 */ 2 - 3 - /* Copyright (C) 2019 Linaro Ltd. */ 4 - 5 - #ifndef __QCOM_Q6V5_IPA_NOTIFY_H__ 6 - #define __QCOM_Q6V5_IPA_NOTIFY_H__ 7 - 8 - #if IS_ENABLED(CONFIG_QCOM_Q6V5_IPA_NOTIFY) 9 - 10 - #include <linux/remoteproc.h> 11 - 12 - enum qcom_rproc_event { 13 - MODEM_STARTING = 0, /* Modem is about to be started */ 14 - MODEM_RUNNING = 1, /* Startup complete; modem is operational */ 15 - MODEM_STOPPING = 2, /* Modem is about to shut down */ 16 - MODEM_CRASHED = 3, /* Modem has crashed (implies stopping) */ 17 - MODEM_OFFLINE = 4, /* Modem is now offline */ 18 - MODEM_REMOVING = 5, /* Modem is about to be removed */ 19 - }; 20 - 21 - typedef void (*qcom_ipa_notify_t)(void *data, enum qcom_rproc_event event); 22 - 23 - struct qcom_rproc_ipa_notify { 24 - struct rproc_subdev subdev; 25 - 26 - qcom_ipa_notify_t notify; 27 - void *data; 28 - }; 29 - 30 - /** 31 - * qcom_add_ipa_notify_subdev() - Register IPA notification subdevice 32 - * @rproc: rproc handle 33 - * @ipa_notify: IPA notification subdevice handle 34 - * 35 - * Register the @ipa_notify subdevice with the @rproc so modem events 36 - * can be sent to IPA when they occur. 37 - * 38 - * This is defined in "qcom_q6v5_ipa_notify.c". 39 - */ 40 - void qcom_add_ipa_notify_subdev(struct rproc *rproc, 41 - struct qcom_rproc_ipa_notify *ipa_notify); 42 - 43 - /** 44 - * qcom_remove_ipa_notify_subdev() - Remove IPA SSR subdevice 45 - * @rproc: rproc handle 46 - * @ipa_notify: IPA notification subdevice handle 47 - * 48 - * This is defined in "qcom_q6v5_ipa_notify.c". 49 - */ 50 - void qcom_remove_ipa_notify_subdev(struct rproc *rproc, 51 - struct qcom_rproc_ipa_notify *ipa_notify); 52 - 53 - /** 54 - * qcom_register_ipa_notify() - Register IPA notification function 55 - * @rproc: Remote processor handle 56 - * @notify: Non-null IPA notification callback function pointer 57 - * @data: Data supplied to IPA notification callback function 58 - * 59 - * @Return: 0 if successful, or a negative error code otherwise 60 - * 61 - * This is defined in "qcom_q6v5_mss.c". 62 - */ 63 - int qcom_register_ipa_notify(struct rproc *rproc, qcom_ipa_notify_t notify, 64 - void *data); 65 - /** 66 - * qcom_deregister_ipa_notify() - Deregister IPA notification function 67 - * @rproc: Remote processor handle 68 - * 69 - * This is defined in "qcom_q6v5_mss.c". 70 - */ 71 - void qcom_deregister_ipa_notify(struct rproc *rproc); 72 - 73 - #else /* !IS_ENABLED(CONFIG_QCOM_Q6V5_IPA_NOTIFY) */ 74 - 75 - struct qcom_rproc_ipa_notify { /* empty */ }; 76 - 77 - #define qcom_add_ipa_notify_subdev(rproc, ipa_notify) /* no-op */ 78 - #define qcom_remove_ipa_notify_subdev(rproc, ipa_notify) /* no-op */ 79 - 80 - #endif /* !IS_ENABLED(CONFIG_QCOM_Q6V5_IPA_NOTIFY) */ 81 - 82 - #endif /* !__QCOM_Q6V5_IPA_NOTIFY_H__ */
+31 -5
include/linux/remoteproc/qcom_rproc.h
··· 5 5 6 6 #if IS_ENABLED(CONFIG_QCOM_RPROC_COMMON) 7 7 8 - int qcom_register_ssr_notifier(struct notifier_block *nb); 9 - void qcom_unregister_ssr_notifier(struct notifier_block *nb); 8 + /** 9 + * enum qcom_ssr_notify_type - Startup/Shutdown events related to a remoteproc 10 + * processor. 11 + * 12 + * @QCOM_SSR_BEFORE_POWERUP: Remoteproc about to start (prepare stage) 13 + * @QCOM_SSR_AFTER_POWERUP: Remoteproc is running (start stage) 14 + * @QCOM_SSR_BEFORE_SHUTDOWN: Remoteproc crashed or shutting down (stop stage) 15 + * @QCOM_SSR_AFTER_SHUTDOWN: Remoteproc is down (unprepare stage) 16 + */ 17 + enum qcom_ssr_notify_type { 18 + QCOM_SSR_BEFORE_POWERUP, 19 + QCOM_SSR_AFTER_POWERUP, 20 + QCOM_SSR_BEFORE_SHUTDOWN, 21 + QCOM_SSR_AFTER_SHUTDOWN, 22 + }; 23 + 24 + struct qcom_ssr_notify_data { 25 + const char *name; 26 + bool crashed; 27 + }; 28 + 29 + void *qcom_register_ssr_notifier(const char *name, struct notifier_block *nb); 30 + int qcom_unregister_ssr_notifier(void *notify, struct notifier_block *nb); 10 31 11 32 #else 12 33 13 - static inline int qcom_register_ssr_notifier(struct notifier_block *nb) 34 + static inline void *qcom_register_ssr_notifier(const char *name, 35 + struct notifier_block *nb) 36 + { 37 + return NULL; 38 + } 39 + 40 + static inline int qcom_unregister_ssr_notifier(void *notify, 41 + struct notifier_block *nb) 14 42 { 15 43 return 0; 16 44 } 17 - 18 - static inline void qcom_unregister_ssr_notifier(struct notifier_block *nb) {} 19 45 20 46 #endif 21 47
+37
include/uapi/linux/remoteproc_cdev.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ 2 + /* 3 + * IOCTLs for Remoteproc's character device interface. 4 + * 5 + * Copyright (c) 2020, The Linux Foundation. All rights reserved. 6 + */ 7 + 8 + #ifndef _UAPI_REMOTEPROC_CDEV_H_ 9 + #define _UAPI_REMOTEPROC_CDEV_H_ 10 + 11 + #include <linux/ioctl.h> 12 + #include <linux/types.h> 13 + 14 + #define RPROC_MAGIC 0xB7 15 + 16 + /* 17 + * The RPROC_SET_SHUTDOWN_ON_RELEASE ioctl allows to enable/disable the shutdown of a remote 18 + * processor automatically when the controlling userpsace closes the char device interface. 19 + * 20 + * input parameter: integer 21 + * 0 : disable automatic shutdown 22 + * other : enable automatic shutdown 23 + */ 24 + #define RPROC_SET_SHUTDOWN_ON_RELEASE _IOW(RPROC_MAGIC, 1, __s32) 25 + 26 + /* 27 + * The RPROC_GET_SHUTDOWN_ON_RELEASE ioctl gets information about whether the automatic shutdown of 28 + * a remote processor is enabled or disabled when the controlling userspace closes the char device 29 + * interface. 30 + * 31 + * output parameter: integer 32 + * 0 : automatic shutdown disable 33 + * other : automatic shutdown enable 34 + */ 35 + #define RPROC_GET_SHUTDOWN_ON_RELEASE _IOR(RPROC_MAGIC, 2, __s32) 36 + 37 + #endif