@@ -156,6 +156,8 @@ static inline int con_debug_leave(void)
156156 * /dev/kmesg which requires a larger output buffer.
157157 * @CON_SUSPENDED: Indicates if a console is suspended. If true, the
158158 * printing callbacks must not be called.
159+ * @CON_NBCON: Console can operate outside of the legacy style console_lock
160+ * constraints.
159161 */
160162enum cons_flags {
161163 CON_PRINTBUFFER = BIT (0 ),
@@ -166,6 +168,111 @@ enum cons_flags {
166168 CON_BRL = BIT (5 ),
167169 CON_EXTENDED = BIT (6 ),
168170 CON_SUSPENDED = BIT (7 ),
171+ CON_NBCON = BIT (8 ),
172+ };
173+
174+ /**
175+ * struct nbcon_state - console state for nbcon consoles
176+ * @atom: Compound of the state fields for atomic operations
177+ *
178+ * @req_prio: The priority of a handover request
179+ * @prio: The priority of the current owner
180+ * @unsafe: Console is busy in a non takeover region
181+ * @unsafe_takeover: A hostile takeover in an unsafe state happened in the
182+ * past. The console cannot be safe until re-initialized.
183+ * @cpu: The CPU on which the owner runs
184+ *
185+ * To be used for reading and preparing of the value stored in the nbcon
186+ * state variable @console::nbcon_state.
187+ *
188+ * The @prio and @req_prio fields are particularly important to allow
189+ * spin-waiting to timeout and give up without the risk of a waiter being
190+ * assigned the lock after giving up.
191+ */
192+ struct nbcon_state {
193+ union {
194+ unsigned int atom ;
195+ struct {
196+ unsigned int prio : 2 ;
197+ unsigned int req_prio : 2 ;
198+ unsigned int unsafe : 1 ;
199+ unsigned int unsafe_takeover : 1 ;
200+ unsigned int cpu : 24 ;
201+ };
202+ };
203+ };
204+
205+ /*
206+ * The nbcon_state struct is used to easily create and interpret values that
207+ * are stored in the @console::nbcon_state variable. Ensure this struct stays
208+ * within the size boundaries of the atomic variable's underlying type in
209+ * order to avoid any accidental truncation.
210+ */
211+ static_assert (sizeof (struct nbcon_state ) <= sizeof (int ));
212+
213+ /**
214+ * nbcon_prio - console owner priority for nbcon consoles
215+ * @NBCON_PRIO_NONE: Unused
216+ * @NBCON_PRIO_NORMAL: Normal (non-emergency) usage
217+ * @NBCON_PRIO_EMERGENCY: Emergency output (WARN/OOPS...)
218+ * @NBCON_PRIO_PANIC: Panic output
219+ * @NBCON_PRIO_MAX: The number of priority levels
220+ *
221+ * A higher priority context can takeover the console when it is
222+ * in the safe state. The final attempt to flush consoles in panic()
223+ * can be allowed to do so even in an unsafe state (Hope and pray).
224+ */
225+ enum nbcon_prio {
226+ NBCON_PRIO_NONE = 0 ,
227+ NBCON_PRIO_NORMAL ,
228+ NBCON_PRIO_EMERGENCY ,
229+ NBCON_PRIO_PANIC ,
230+ NBCON_PRIO_MAX ,
231+ };
232+
233+ struct console ;
234+ struct printk_buffers ;
235+
236+ /**
237+ * struct nbcon_context - Context for console acquire/release
238+ * @console: The associated console
239+ * @spinwait_max_us: Limit for spin-wait acquire
240+ * @prio: Priority of the context
241+ * @allow_unsafe_takeover: Allow performing takeover even if unsafe. Can
242+ * be used only with NBCON_PRIO_PANIC @prio. It
243+ * might cause a system freeze when the console
244+ * is used later.
245+ * @backlog: Ringbuffer has pending records
246+ * @pbufs: Pointer to the text buffer for this context
247+ * @seq: The sequence number to print for this context
248+ */
249+ struct nbcon_context {
250+ /* members set by caller */
251+ struct console * console ;
252+ unsigned int spinwait_max_us ;
253+ enum nbcon_prio prio ;
254+ unsigned int allow_unsafe_takeover : 1 ;
255+
256+ /* members set by emit */
257+ unsigned int backlog : 1 ;
258+
259+ /* members set by acquire */
260+ struct printk_buffers * pbufs ;
261+ u64 seq ;
262+ };
263+
264+ /**
265+ * struct nbcon_write_context - Context handed to the nbcon write callbacks
266+ * @ctxt: The core console context
267+ * @outbuf: Pointer to the text buffer for output
268+ * @len: Length to write
269+ * @unsafe_takeover: If a hostile takeover in an unsafe state has occurred
270+ */
271+ struct nbcon_write_context {
272+ struct nbcon_context __private ctxt ;
273+ char * outbuf ;
274+ unsigned int len ;
275+ bool unsafe_takeover ;
169276};
170277
171278/**
@@ -187,6 +294,11 @@ enum cons_flags {
187294 * @dropped: Number of unreported dropped ringbuffer records
188295 * @data: Driver private data
189296 * @node: hlist node for the console list
297+ *
298+ * @write_atomic: Write callback for atomic context
299+ * @nbcon_state: State for nbcon consoles
300+ * @nbcon_seq: Sequence number of the next record for nbcon to print
301+ * @pbufs: Pointer to nbcon private buffer
190302 */
191303struct console {
192304 char name [16 ];
@@ -206,6 +318,13 @@ struct console {
206318 unsigned long dropped ;
207319 void * data ;
208320 struct hlist_node node ;
321+
322+ /* nbcon console specific members */
323+ bool (* write_atomic )(struct console * con ,
324+ struct nbcon_write_context * wctxt );
325+ atomic_t __private nbcon_state ;
326+ atomic_long_t __private nbcon_seq ;
327+ struct printk_buffers * pbufs ;
209328};
210329
211330#ifdef CONFIG_LOCKDEP
@@ -332,6 +451,16 @@ static inline bool console_is_registered(const struct console *con)
332451 lockdep_assert_console_list_lock_held(); \
333452 hlist_for_each_entry(con, &console_list, node)
334453
454+ #ifdef CONFIG_PRINTK
455+ extern bool nbcon_can_proceed (struct nbcon_write_context * wctxt );
456+ extern bool nbcon_enter_unsafe (struct nbcon_write_context * wctxt );
457+ extern bool nbcon_exit_unsafe (struct nbcon_write_context * wctxt );
458+ #else
459+ static inline bool nbcon_can_proceed (struct nbcon_write_context * wctxt ) { return false; }
460+ static inline bool nbcon_enter_unsafe (struct nbcon_write_context * wctxt ) { return false; }
461+ static inline bool nbcon_exit_unsafe (struct nbcon_write_context * wctxt ) { return false; }
462+ #endif
463+
335464extern int console_set_on_cmdline ;
336465extern struct console * early_console ;
337466
0 commit comments