xref: /openbmc/linux/kernel/rcu/rcu_segcblist.h (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
1eb7935e4SPaul E. McKenney /* SPDX-License-Identifier: GPL-2.0+ */
245753c5fSIngo Molnar /*
398059b98SPaul E. McKenney  * RCU segmented callback lists, internal-to-rcu header file
445753c5fSIngo Molnar  *
545753c5fSIngo Molnar  * Copyright IBM Corporation, 2017
645753c5fSIngo Molnar  *
7eb7935e4SPaul E. McKenney  * Authors: Paul E. McKenney <paulmck@linux.ibm.com>
845753c5fSIngo Molnar  */
945753c5fSIngo Molnar 
1045753c5fSIngo Molnar #include <linux/rcu_segcblist.h>
1145753c5fSIngo Molnar 
12eda669a6SPaul E. McKenney /* Return number of callbacks in the specified callback list. */
rcu_cblist_n_cbs(struct rcu_cblist * rclp)13eda669a6SPaul E. McKenney static inline long rcu_cblist_n_cbs(struct rcu_cblist *rclp)
14eda669a6SPaul E. McKenney {
15eda669a6SPaul E. McKenney 	return READ_ONCE(rclp->len);
16eda669a6SPaul E. McKenney }
17eda669a6SPaul E. McKenney 
18*253cbbffSPaul E. McKenney long rcu_segcblist_get_seglen(struct rcu_segcblist *rsclp, int seg);
19*253cbbffSPaul E. McKenney 
20b4e6039eSJoel Fernandes (Google) /* Return number of callbacks in segmented callback list by summing seglen. */
21b4e6039eSJoel Fernandes (Google) long rcu_segcblist_n_segment_cbs(struct rcu_segcblist *rsclp);
22b4e6039eSJoel Fernandes (Google) 
2398059b98SPaul E. McKenney void rcu_cblist_init(struct rcu_cblist *rclp);
24d1b222c6SPaul E. McKenney void rcu_cblist_enqueue(struct rcu_cblist *rclp, struct rcu_head *rhp);
25d1b222c6SPaul E. McKenney void rcu_cblist_flush_enqueue(struct rcu_cblist *drclp,
26d1b222c6SPaul E. McKenney 			      struct rcu_cblist *srclp,
27d1b222c6SPaul E. McKenney 			      struct rcu_head *rhp);
2898059b98SPaul E. McKenney struct rcu_head *rcu_cblist_dequeue(struct rcu_cblist *rclp);
2945753c5fSIngo Molnar 
3045753c5fSIngo Molnar /*
3145753c5fSIngo Molnar  * Is the specified rcu_segcblist structure empty?
3245753c5fSIngo Molnar  *
3345753c5fSIngo Molnar  * But careful!  The fact that the ->head field is NULL does not
3445753c5fSIngo Molnar  * necessarily imply that there are no callbacks associated with
3545753c5fSIngo Molnar  * this structure.  When callbacks are being invoked, they are
3645753c5fSIngo Molnar  * removed as a group.  If callback invocation must be preempted,
3745753c5fSIngo Molnar  * the remaining callbacks will be added back to the list.  Either
3845753c5fSIngo Molnar  * way, the counts are updated later.
3945753c5fSIngo Molnar  *
4045753c5fSIngo Molnar  * So it is often the case that rcu_segcblist_n_cbs() should be used
4145753c5fSIngo Molnar  * instead.
4245753c5fSIngo Molnar  */
rcu_segcblist_empty(struct rcu_segcblist * rsclp)4345753c5fSIngo Molnar static inline bool rcu_segcblist_empty(struct rcu_segcblist *rsclp)
4445753c5fSIngo Molnar {
45e6060b41SPaul E. McKenney 	return !READ_ONCE(rsclp->head);
4645753c5fSIngo Molnar }
4745753c5fSIngo Molnar 
4845753c5fSIngo Molnar /* Return number of callbacks in segmented callback list. */
rcu_segcblist_n_cbs(struct rcu_segcblist * rsclp)4945753c5fSIngo Molnar static inline long rcu_segcblist_n_cbs(struct rcu_segcblist *rsclp)
5045753c5fSIngo Molnar {
51eda669a6SPaul E. McKenney #ifdef CONFIG_RCU_NOCB_CPU
52eda669a6SPaul E. McKenney 	return atomic_long_read(&rsclp->len);
53eda669a6SPaul E. McKenney #else
5445753c5fSIngo Molnar 	return READ_ONCE(rsclp->len);
55eda669a6SPaul E. McKenney #endif
5645753c5fSIngo Molnar }
5745753c5fSIngo Molnar 
rcu_segcblist_set_flags(struct rcu_segcblist * rsclp,int flags)5865e56032SFrederic Weisbecker static inline void rcu_segcblist_set_flags(struct rcu_segcblist *rsclp,
5965e56032SFrederic Weisbecker 					   int flags)
6065e56032SFrederic Weisbecker {
61c0992903SPaul E. McKenney 	WRITE_ONCE(rsclp->flags, rsclp->flags | flags);
6265e56032SFrederic Weisbecker }
6365e56032SFrederic Weisbecker 
rcu_segcblist_clear_flags(struct rcu_segcblist * rsclp,int flags)6465e56032SFrederic Weisbecker static inline void rcu_segcblist_clear_flags(struct rcu_segcblist *rsclp,
6565e56032SFrederic Weisbecker 					     int flags)
6665e56032SFrederic Weisbecker {
67c0992903SPaul E. McKenney 	WRITE_ONCE(rsclp->flags, rsclp->flags & ~flags);
6865e56032SFrederic Weisbecker }
6965e56032SFrederic Weisbecker 
rcu_segcblist_test_flags(struct rcu_segcblist * rsclp,int flags)7065e56032SFrederic Weisbecker static inline bool rcu_segcblist_test_flags(struct rcu_segcblist *rsclp,
7165e56032SFrederic Weisbecker 					    int flags)
7265e56032SFrederic Weisbecker {
7365e56032SFrederic Weisbecker 	return READ_ONCE(rsclp->flags) & flags;
7465e56032SFrederic Weisbecker }
7565e56032SFrederic Weisbecker 
7645753c5fSIngo Molnar /*
7745753c5fSIngo Molnar  * Is the specified rcu_segcblist enabled, for example, not corresponding
78e83e73f5SPaul E. McKenney  * to an offline CPU?
7945753c5fSIngo Molnar  */
rcu_segcblist_is_enabled(struct rcu_segcblist * rsclp)8045753c5fSIngo Molnar static inline bool rcu_segcblist_is_enabled(struct rcu_segcblist *rsclp)
8145753c5fSIngo Molnar {
8265e56032SFrederic Weisbecker 	return rcu_segcblist_test_flags(rsclp, SEGCBLIST_ENABLED);
8345753c5fSIngo Molnar }
8445753c5fSIngo Molnar 
85213d56bfSFrederic Weisbecker /*
86213d56bfSFrederic Weisbecker  * Is the specified rcu_segcblist NOCB offloaded (or in the middle of the
87213d56bfSFrederic Weisbecker  * [de]offloading process)?
88213d56bfSFrederic Weisbecker  */
rcu_segcblist_is_offloaded(struct rcu_segcblist * rsclp)89ce5215c1SPaul E. McKenney static inline bool rcu_segcblist_is_offloaded(struct rcu_segcblist *rsclp)
90ce5215c1SPaul E. McKenney {
91f759081eSPaul E. McKenney 	if (IS_ENABLED(CONFIG_RCU_NOCB_CPU) &&
92213d56bfSFrederic Weisbecker 	    rcu_segcblist_test_flags(rsclp, SEGCBLIST_LOCKING))
938d346d43SFrederic Weisbecker 		return true;
948d346d43SFrederic Weisbecker 
958d346d43SFrederic Weisbecker 	return false;
96ce5215c1SPaul E. McKenney }
97ce5215c1SPaul E. McKenney 
rcu_segcblist_completely_offloaded(struct rcu_segcblist * rsclp)9832aa2f41SFrederic Weisbecker static inline bool rcu_segcblist_completely_offloaded(struct rcu_segcblist *rsclp)
9932aa2f41SFrederic Weisbecker {
100213d56bfSFrederic Weisbecker 	if (IS_ENABLED(CONFIG_RCU_NOCB_CPU) &&
101213d56bfSFrederic Weisbecker 	    !rcu_segcblist_test_flags(rsclp, SEGCBLIST_RCU_CORE))
10232aa2f41SFrederic Weisbecker 		return true;
10332aa2f41SFrederic Weisbecker 
10432aa2f41SFrederic Weisbecker 	return false;
10532aa2f41SFrederic Weisbecker }
10632aa2f41SFrederic Weisbecker 
10745753c5fSIngo Molnar /*
10845753c5fSIngo Molnar  * Are all segments following the specified segment of the specified
10945753c5fSIngo Molnar  * rcu_segcblist structure empty of callbacks?  (The specified
11045753c5fSIngo Molnar  * segment might well contain callbacks.)
11145753c5fSIngo Molnar  */
rcu_segcblist_restempty(struct rcu_segcblist * rsclp,int seg)11245753c5fSIngo Molnar static inline bool rcu_segcblist_restempty(struct rcu_segcblist *rsclp, int seg)
11345753c5fSIngo Molnar {
11476c6927cSPaul E. McKenney 	return !READ_ONCE(*READ_ONCE(rsclp->tails[seg]));
11545753c5fSIngo Molnar }
11645753c5fSIngo Molnar 
11734169061SPaul E. McKenney /*
11834169061SPaul E. McKenney  * Is the specified segment of the specified rcu_segcblist structure
11934169061SPaul E. McKenney  * empty of callbacks?
12034169061SPaul E. McKenney  */
rcu_segcblist_segempty(struct rcu_segcblist * rsclp,int seg)12134169061SPaul E. McKenney static inline bool rcu_segcblist_segempty(struct rcu_segcblist *rsclp, int seg)
12234169061SPaul E. McKenney {
12334169061SPaul E. McKenney 	if (seg == RCU_DONE_TAIL)
12434169061SPaul E. McKenney 		return &rsclp->head == rsclp->tails[RCU_DONE_TAIL];
12534169061SPaul E. McKenney 	return rsclp->tails[seg - 1] == rsclp->tails[seg];
12634169061SPaul E. McKenney }
12734169061SPaul E. McKenney 
128d1b222c6SPaul E. McKenney void rcu_segcblist_inc_len(struct rcu_segcblist *rsclp);
1296bc33582SJoel Fernandes (Google) void rcu_segcblist_add_len(struct rcu_segcblist *rsclp, long v);
13098059b98SPaul E. McKenney void rcu_segcblist_init(struct rcu_segcblist *rsclp);
13198059b98SPaul E. McKenney void rcu_segcblist_disable(struct rcu_segcblist *rsclp);
132d97b0781SFrederic Weisbecker void rcu_segcblist_offload(struct rcu_segcblist *rsclp, bool offload);
13398059b98SPaul E. McKenney bool rcu_segcblist_ready_cbs(struct rcu_segcblist *rsclp);
13498059b98SPaul E. McKenney bool rcu_segcblist_pend_cbs(struct rcu_segcblist *rsclp);
13598059b98SPaul E. McKenney struct rcu_head *rcu_segcblist_first_cb(struct rcu_segcblist *rsclp);
13698059b98SPaul E. McKenney struct rcu_head *rcu_segcblist_first_pend_cb(struct rcu_segcblist *rsclp);
1375d6742b3SPaul E. McKenney bool rcu_segcblist_nextgp(struct rcu_segcblist *rsclp, unsigned long *lp);
13898059b98SPaul E. McKenney void rcu_segcblist_enqueue(struct rcu_segcblist *rsclp,
13977a40f97SJoel Fernandes (Google) 			   struct rcu_head *rhp);
14098059b98SPaul E. McKenney bool rcu_segcblist_entrain(struct rcu_segcblist *rsclp,
14177a40f97SJoel Fernandes (Google) 			   struct rcu_head *rhp);
14298059b98SPaul E. McKenney void rcu_segcblist_extract_done_cbs(struct rcu_segcblist *rsclp,
14398059b98SPaul E. McKenney 				    struct rcu_cblist *rclp);
14498059b98SPaul E. McKenney void rcu_segcblist_extract_pend_cbs(struct rcu_segcblist *rsclp,
14598059b98SPaul E. McKenney 				    struct rcu_cblist *rclp);
14698059b98SPaul E. McKenney void rcu_segcblist_insert_count(struct rcu_segcblist *rsclp,
14798059b98SPaul E. McKenney 				struct rcu_cblist *rclp);
14898059b98SPaul E. McKenney void rcu_segcblist_insert_done_cbs(struct rcu_segcblist *rsclp,
14998059b98SPaul E. McKenney 				   struct rcu_cblist *rclp);
15098059b98SPaul E. McKenney void rcu_segcblist_insert_pend_cbs(struct rcu_segcblist *rsclp,
15198059b98SPaul E. McKenney 				   struct rcu_cblist *rclp);
15298059b98SPaul E. McKenney void rcu_segcblist_advance(struct rcu_segcblist *rsclp, unsigned long seq);
15398059b98SPaul E. McKenney bool rcu_segcblist_accelerate(struct rcu_segcblist *rsclp, unsigned long seq);
154f2dbe4a5SPaul E. McKenney void rcu_segcblist_merge(struct rcu_segcblist *dst_rsclp,
155f2dbe4a5SPaul E. McKenney 			 struct rcu_segcblist *src_rsclp);
156