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

Configure Feed

Select the types of activity you want to include in your feed.

platform/surface: aggregator: Allow registering notifiers without enabling events

Currently, each SSAM event notifier is directly tied to one group of
events. This makes sense as registering a notifier will automatically
take care of enabling the corresponding event group and normally drivers
only need notifications for a very limited number of events, associated
with different callbacks for each group.

However, there are rare cases, especially for debugging, when we want to
get notifications for a whole event target category instead of just a
single group of events in that category. Registering multiple notifiers,
i.e. one per group, may be infeasible due to two issues: a) we might not
know every event enable/disable specification as some events are
auto-enabled by the EC and b) forwarding this to the same callback will
lead to duplicate events as we might not know the full event
specification to perform the appropriate filtering.

This commit introduces observer-notifiers, which are notifiers that are
not tied to a specific event group and do not attempt to manage any
events. In other words, they can be registered without enabling any
event group or incrementing the corresponding reference count and just
act as silent observers, listening to all currently/previously enabled
events based on their match-specification.

Essentially, this allows us to register one single notifier for a full
event target category, meaning that we can process all events of that
target category in a single callback without duplication. Specifically,
this will be used in the cdev debug interface to forward events to
user-space via a device file from which the events can be read.

Signed-off-by: Maximilian Luz <luzmaximilian@gmail.com>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Link: https://lore.kernel.org/r/20210604134755.535590-2-luzmaximilian@gmail.com
Signed-off-by: Hans de Goede <hdegoede@redhat.com>

authored by

Maximilian Luz and committed by
Hans de Goede
0e8512fa 3d9907e1

+58 -28
+41 -28
drivers/platform/surface/aggregator/controller.c
··· 2127 2127 * @ctrl: The controller to register the notifier on. 2128 2128 * @n: The event notifier to register. 2129 2129 * 2130 - * Register an event notifier and increment the usage counter of the 2131 - * associated SAM event. If the event was previously not enabled, it will be 2132 - * enabled during this call. 2130 + * Register an event notifier. Increment the usage counter of the associated 2131 + * SAM event if the notifier is not marked as an observer. If the event is not 2132 + * marked as an observer and is currently not enabled, it will be enabled 2133 + * during this call. If the notifier is marked as an observer, no attempt will 2134 + * be made at enabling any event and no reference count will be modified. 2135 + * 2136 + * Notifiers marked as observers do not need to be associated with one specific 2137 + * event, i.e. as long as no event matching is performed, only the event target 2138 + * category needs to be set. 2133 2139 * 2134 2140 * Return: Returns zero on success, %-ENOSPC if there have already been 2135 2141 * %INT_MAX notifiers for the event ID/type associated with the notifier block ··· 2144 2138 * for the specific associated event, returns the status of the event-enable 2145 2139 * EC-command. 2146 2140 */ 2147 - int ssam_notifier_register(struct ssam_controller *ctrl, 2148 - struct ssam_event_notifier *n) 2141 + int ssam_notifier_register(struct ssam_controller *ctrl, struct ssam_event_notifier *n) 2149 2142 { 2150 2143 u16 rqid = ssh_tc_to_rqid(n->event.id.target_category); 2151 - struct ssam_nf_refcount_entry *entry; 2144 + struct ssam_nf_refcount_entry *entry = NULL; 2152 2145 struct ssam_nf_head *nf_head; 2153 2146 struct ssam_nf *nf; 2154 2147 int status; ··· 2160 2155 2161 2156 mutex_lock(&nf->lock); 2162 2157 2163 - entry = ssam_nf_refcount_inc(nf, n->event.reg, n->event.id); 2164 - if (IS_ERR(entry)) { 2165 - mutex_unlock(&nf->lock); 2166 - return PTR_ERR(entry); 2167 - } 2158 + if (!(n->flags & SSAM_EVENT_NOTIFIER_OBSERVER)) { 2159 + entry = ssam_nf_refcount_inc(nf, n->event.reg, n->event.id); 2160 + if (IS_ERR(entry)) { 2161 + mutex_unlock(&nf->lock); 2162 + return PTR_ERR(entry); 2163 + } 2168 2164 2169 - ssam_dbg(ctrl, "enabling event (reg: %#04x, tc: %#04x, iid: %#04x, rc: %d)\n", 2170 - n->event.reg.target_category, n->event.id.target_category, 2171 - n->event.id.instance, entry->refcount); 2165 + ssam_dbg(ctrl, "enabling event (reg: %#04x, tc: %#04x, iid: %#04x, rc: %d)\n", 2166 + n->event.reg.target_category, n->event.id.target_category, 2167 + n->event.id.instance, entry->refcount); 2168 + } 2172 2169 2173 2170 status = ssam_nfblk_insert(nf_head, &n->base); 2174 2171 if (status) { 2175 - entry = ssam_nf_refcount_dec(nf, n->event.reg, n->event.id); 2176 - if (entry->refcount == 0) 2177 - kfree(entry); 2172 + if (entry) { 2173 + entry = ssam_nf_refcount_dec(nf, n->event.reg, n->event.id); 2174 + if (entry->refcount == 0) 2175 + kfree(entry); 2176 + } 2178 2177 2179 2178 mutex_unlock(&nf->lock); 2180 2179 return status; 2181 2180 } 2182 2181 2183 - if (entry->refcount == 1) { 2184 - status = ssam_ssh_event_enable(ctrl, n->event.reg, n->event.id, 2185 - n->event.flags); 2182 + if (entry && entry->refcount == 1) { 2183 + status = ssam_ssh_event_enable(ctrl, n->event.reg, n->event.id, n->event.flags); 2186 2184 if (status) { 2187 2185 ssam_nfblk_remove(&n->base); 2188 2186 kfree(ssam_nf_refcount_dec(nf, n->event.reg, n->event.id)); ··· 2196 2188 2197 2189 entry->flags = n->event.flags; 2198 2190 2199 - } else if (entry->flags != n->event.flags) { 2191 + } else if (entry && entry->flags != n->event.flags) { 2200 2192 ssam_warn(ctrl, 2201 2193 "inconsistent flags when enabling event: got %#04x, expected %#04x (reg: %#04x, tc: %#04x, iid: %#04x)\n", 2202 2194 n->event.flags, entry->flags, n->event.reg.target_category, ··· 2213 2205 * @ctrl: The controller the notifier has been registered on. 2214 2206 * @n: The event notifier to unregister. 2215 2207 * 2216 - * Unregister an event notifier and decrement the usage counter of the 2217 - * associated SAM event. If the usage counter reaches zero, the event will be 2218 - * disabled. 2208 + * Unregister an event notifier. Decrement the usage counter of the associated 2209 + * SAM event if the notifier is not marked as an observer. If the usage counter 2210 + * reaches zero, the event will be disabled. 2219 2211 * 2220 2212 * Return: Returns zero on success, %-ENOENT if the given notifier block has 2221 2213 * not been registered on the controller. If the given notifier block was the 2222 2214 * last one associated with its specific event, returns the status of the 2223 2215 * event-disable EC-command. 2224 2216 */ 2225 - int ssam_notifier_unregister(struct ssam_controller *ctrl, 2226 - struct ssam_event_notifier *n) 2217 + int ssam_notifier_unregister(struct ssam_controller *ctrl, struct ssam_event_notifier *n) 2227 2218 { 2228 2219 u16 rqid = ssh_tc_to_rqid(n->event.id.target_category); 2229 2220 struct ssam_nf_refcount_entry *entry; ··· 2242 2235 mutex_unlock(&nf->lock); 2243 2236 return -ENOENT; 2244 2237 } 2238 + 2239 + /* 2240 + * If this is an observer notifier, do not attempt to disable the 2241 + * event, just remove it. 2242 + */ 2243 + if (n->flags & SSAM_EVENT_NOTIFIER_OBSERVER) 2244 + goto remove; 2245 2245 2246 2246 entry = ssam_nf_refcount_dec(nf, n->event.reg, n->event.id); 2247 2247 if (WARN_ON(!entry)) { ··· 2274 2260 } 2275 2261 2276 2262 if (entry->refcount == 0) { 2277 - status = ssam_ssh_event_disable(ctrl, n->event.reg, n->event.id, 2278 - n->event.flags); 2263 + status = ssam_ssh_event_disable(ctrl, n->event.reg, n->event.id, n->event.flags); 2279 2264 kfree(entry); 2280 2265 } 2281 2266
+17
include/linux/surface_aggregator/controller.h
··· 796 796 SSAM_EVENT_REGISTRY(SSAM_SSH_TC_REG, 0x02, 0x01, 0x02) 797 797 798 798 /** 799 + * enum ssam_event_notifier_flags - Flags for event notifiers. 800 + * @SSAM_EVENT_NOTIFIER_OBSERVER: 801 + * The corresponding notifier acts as observer. Registering a notifier 802 + * with this flag set will not attempt to enable any event. Equally, 803 + * unregistering will not attempt to disable any event. Note that a 804 + * notifier with this flag may not even correspond to a certain event at 805 + * all, only to a specific event target category. Event matching will not 806 + * be influenced by this flag. 807 + */ 808 + enum ssam_event_notifier_flags { 809 + SSAM_EVENT_NOTIFIER_OBSERVER = BIT(0), 810 + }; 811 + 812 + /** 799 813 * struct ssam_event_notifier - Notifier block for SSAM events. 800 814 * @base: The base notifier block with callback function and priority. 801 815 * @event: The event for which this block will receive notifications. ··· 817 803 * @event.id: ID specifying the event. 818 804 * @event.mask: Flags determining how events are matched to the notifier. 819 805 * @event.flags: Flags used for enabling the event. 806 + * @flags: Notifier flags (see &enum ssam_event_notifier_flags). 820 807 */ 821 808 struct ssam_event_notifier { 822 809 struct ssam_notifier_block base; ··· 828 813 enum ssam_event_mask mask; 829 814 u8 flags; 830 815 } event; 816 + 817 + unsigned long flags; 831 818 }; 832 819 833 820 int ssam_notifier_register(struct ssam_controller *ctrl,