1*5d6d1dddSLuis R. Rodriguez /* SPDX-License-Identifier: GPL-2.0 */ 2*5d6d1dddSLuis R. Rodriguez #ifndef __FIRMWARE_LOADER_H 3*5d6d1dddSLuis R. Rodriguez #define __FIRMWARE_LOADER_H 4*5d6d1dddSLuis R. Rodriguez 5*5d6d1dddSLuis R. Rodriguez #include <linux/firmware.h> 6*5d6d1dddSLuis R. Rodriguez #include <linux/types.h> 7*5d6d1dddSLuis R. Rodriguez #include <linux/kref.h> 8*5d6d1dddSLuis R. Rodriguez #include <linux/list.h> 9*5d6d1dddSLuis R. Rodriguez #include <linux/completion.h> 10*5d6d1dddSLuis R. Rodriguez 11*5d6d1dddSLuis R. Rodriguez #include <generated/utsrelease.h> 12*5d6d1dddSLuis R. Rodriguez 13*5d6d1dddSLuis R. Rodriguez /* firmware behavior options */ 14*5d6d1dddSLuis R. Rodriguez #define FW_OPT_UEVENT (1U << 0) 15*5d6d1dddSLuis R. Rodriguez #define FW_OPT_NOWAIT (1U << 1) 16*5d6d1dddSLuis R. Rodriguez #define FW_OPT_USERHELPER (1U << 2) 17*5d6d1dddSLuis R. Rodriguez #define FW_OPT_NO_WARN (1U << 3) 18*5d6d1dddSLuis R. Rodriguez #define FW_OPT_NOCACHE (1U << 4) 19*5d6d1dddSLuis R. Rodriguez #define FW_OPT_NOFALLBACK (1U << 5) 20*5d6d1dddSLuis R. Rodriguez 21*5d6d1dddSLuis R. Rodriguez enum fw_status { 22*5d6d1dddSLuis R. Rodriguez FW_STATUS_UNKNOWN, 23*5d6d1dddSLuis R. Rodriguez FW_STATUS_LOADING, 24*5d6d1dddSLuis R. Rodriguez FW_STATUS_DONE, 25*5d6d1dddSLuis R. Rodriguez FW_STATUS_ABORTED, 26*5d6d1dddSLuis R. Rodriguez }; 27*5d6d1dddSLuis R. Rodriguez 28*5d6d1dddSLuis R. Rodriguez /* 29*5d6d1dddSLuis R. Rodriguez * Concurrent request_firmware() for the same firmware need to be 30*5d6d1dddSLuis R. Rodriguez * serialized. struct fw_state is simple state machine which hold the 31*5d6d1dddSLuis R. Rodriguez * state of the firmware loading. 32*5d6d1dddSLuis R. Rodriguez */ 33*5d6d1dddSLuis R. Rodriguez struct fw_state { 34*5d6d1dddSLuis R. Rodriguez struct completion completion; 35*5d6d1dddSLuis R. Rodriguez enum fw_status status; 36*5d6d1dddSLuis R. Rodriguez }; 37*5d6d1dddSLuis R. Rodriguez 38*5d6d1dddSLuis R. Rodriguez struct fw_priv { 39*5d6d1dddSLuis R. Rodriguez struct kref ref; 40*5d6d1dddSLuis R. Rodriguez struct list_head list; 41*5d6d1dddSLuis R. Rodriguez struct firmware_cache *fwc; 42*5d6d1dddSLuis R. Rodriguez struct fw_state fw_st; 43*5d6d1dddSLuis R. Rodriguez void *data; 44*5d6d1dddSLuis R. Rodriguez size_t size; 45*5d6d1dddSLuis R. Rodriguez size_t allocated_size; 46*5d6d1dddSLuis R. Rodriguez #ifdef CONFIG_FW_LOADER_USER_HELPER 47*5d6d1dddSLuis R. Rodriguez bool is_paged_buf; 48*5d6d1dddSLuis R. Rodriguez bool need_uevent; 49*5d6d1dddSLuis R. Rodriguez struct page **pages; 50*5d6d1dddSLuis R. Rodriguez int nr_pages; 51*5d6d1dddSLuis R. Rodriguez int page_array_size; 52*5d6d1dddSLuis R. Rodriguez struct list_head pending_list; 53*5d6d1dddSLuis R. Rodriguez #endif 54*5d6d1dddSLuis R. Rodriguez const char *fw_name; 55*5d6d1dddSLuis R. Rodriguez }; 56*5d6d1dddSLuis R. Rodriguez 57*5d6d1dddSLuis R. Rodriguez extern struct mutex fw_lock; 58*5d6d1dddSLuis R. Rodriguez 59*5d6d1dddSLuis R. Rodriguez static inline bool __fw_state_check(struct fw_priv *fw_priv, 60*5d6d1dddSLuis R. Rodriguez enum fw_status status) 61*5d6d1dddSLuis R. Rodriguez { 62*5d6d1dddSLuis R. Rodriguez struct fw_state *fw_st = &fw_priv->fw_st; 63*5d6d1dddSLuis R. Rodriguez 64*5d6d1dddSLuis R. Rodriguez return fw_st->status == status; 65*5d6d1dddSLuis R. Rodriguez } 66*5d6d1dddSLuis R. Rodriguez 67*5d6d1dddSLuis R. Rodriguez static inline int __fw_state_wait_common(struct fw_priv *fw_priv, long timeout) 68*5d6d1dddSLuis R. Rodriguez { 69*5d6d1dddSLuis R. Rodriguez struct fw_state *fw_st = &fw_priv->fw_st; 70*5d6d1dddSLuis R. Rodriguez long ret; 71*5d6d1dddSLuis R. Rodriguez 72*5d6d1dddSLuis R. Rodriguez ret = wait_for_completion_killable_timeout(&fw_st->completion, timeout); 73*5d6d1dddSLuis R. Rodriguez if (ret != 0 && fw_st->status == FW_STATUS_ABORTED) 74*5d6d1dddSLuis R. Rodriguez return -ENOENT; 75*5d6d1dddSLuis R. Rodriguez if (!ret) 76*5d6d1dddSLuis R. Rodriguez return -ETIMEDOUT; 77*5d6d1dddSLuis R. Rodriguez 78*5d6d1dddSLuis R. Rodriguez return ret < 0 ? ret : 0; 79*5d6d1dddSLuis R. Rodriguez } 80*5d6d1dddSLuis R. Rodriguez 81*5d6d1dddSLuis R. Rodriguez static inline void __fw_state_set(struct fw_priv *fw_priv, 82*5d6d1dddSLuis R. Rodriguez enum fw_status status) 83*5d6d1dddSLuis R. Rodriguez { 84*5d6d1dddSLuis R. Rodriguez struct fw_state *fw_st = &fw_priv->fw_st; 85*5d6d1dddSLuis R. Rodriguez 86*5d6d1dddSLuis R. Rodriguez WRITE_ONCE(fw_st->status, status); 87*5d6d1dddSLuis R. Rodriguez 88*5d6d1dddSLuis R. Rodriguez if (status == FW_STATUS_DONE || status == FW_STATUS_ABORTED) 89*5d6d1dddSLuis R. Rodriguez complete_all(&fw_st->completion); 90*5d6d1dddSLuis R. Rodriguez } 91*5d6d1dddSLuis R. Rodriguez 92*5d6d1dddSLuis R. Rodriguez static inline void fw_state_aborted(struct fw_priv *fw_priv) 93*5d6d1dddSLuis R. Rodriguez { 94*5d6d1dddSLuis R. Rodriguez __fw_state_set(fw_priv, FW_STATUS_ABORTED); 95*5d6d1dddSLuis R. Rodriguez } 96*5d6d1dddSLuis R. Rodriguez 97*5d6d1dddSLuis R. Rodriguez static inline bool fw_state_is_aborted(struct fw_priv *fw_priv) 98*5d6d1dddSLuis R. Rodriguez { 99*5d6d1dddSLuis R. Rodriguez return __fw_state_check(fw_priv, FW_STATUS_ABORTED); 100*5d6d1dddSLuis R. Rodriguez } 101*5d6d1dddSLuis R. Rodriguez 102*5d6d1dddSLuis R. Rodriguez static inline void fw_state_start(struct fw_priv *fw_priv) 103*5d6d1dddSLuis R. Rodriguez { 104*5d6d1dddSLuis R. Rodriguez __fw_state_set(fw_priv, FW_STATUS_LOADING); 105*5d6d1dddSLuis R. Rodriguez } 106*5d6d1dddSLuis R. Rodriguez 107*5d6d1dddSLuis R. Rodriguez static inline void fw_state_done(struct fw_priv *fw_priv) 108*5d6d1dddSLuis R. Rodriguez { 109*5d6d1dddSLuis R. Rodriguez __fw_state_set(fw_priv, FW_STATUS_DONE); 110*5d6d1dddSLuis R. Rodriguez } 111*5d6d1dddSLuis R. Rodriguez 112*5d6d1dddSLuis R. Rodriguez int assign_fw(struct firmware *fw, struct device *device, 113*5d6d1dddSLuis R. Rodriguez unsigned int opt_flags); 114*5d6d1dddSLuis R. Rodriguez 115*5d6d1dddSLuis R. Rodriguez #endif /* __FIRMWARE_LOADER_H */ 116