controller.h 37.5 KB
Newer Older
1 2 3 4 5 6 7 8
/* SPDX-License-Identifier: GPL-2.0+ */
/*
 * Surface System Aggregator Module (SSAM) controller interface.
 *
 * Main communication interface for the SSAM EC. Provides a controller
 * managing access and communication to and from the SSAM EC, as well as main
 * communication structures and definitions.
 *
9
 * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com>
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
 */

#ifndef _LINUX_SURFACE_AGGREGATOR_CONTROLLER_H
#define _LINUX_SURFACE_AGGREGATOR_CONTROLLER_H

#include <linux/completion.h>
#include <linux/device.h>
#include <linux/types.h>

#include <linux/surface_aggregator/serial_hub.h>


/* -- Main data types and definitions --------------------------------------- */

/**
 * enum ssam_event_flags - Flags for enabling/disabling SAM events
 * @SSAM_EVENT_SEQUENCED: The event will be sent via a sequenced data frame.
 */
enum ssam_event_flags {
	SSAM_EVENT_SEQUENCED = BIT(0),
};

/**
 * struct ssam_event - SAM event sent from the EC to the host.
 * @target_category: Target category of the event source. See &enum ssam_ssh_tc.
 * @target_id:       Target ID of the event source.
 * @command_id:      Command ID of the event.
 * @instance_id:     Instance ID of the event source.
 * @length:          Length of the event payload in bytes.
 * @data:            Event payload data.
 */
struct ssam_event {
	u8 target_category;
	u8 target_id;
	u8 command_id;
	u8 instance_id;
	u16 length;
	u8 data[];
};

/**
 * enum ssam_request_flags - Flags for SAM requests.
 *
 * @SSAM_REQUEST_HAS_RESPONSE:
 *	Specifies that the request expects a response. If not set, the request
 *	will be directly completed after its underlying packet has been
 *	transmitted. If set, the request transport system waits for a response
 *	of the request.
 *
 * @SSAM_REQUEST_UNSEQUENCED:
 *	Specifies that the request should be transmitted via an unsequenced
 *	packet. If set, the request must not have a response, meaning that this
 *	flag and the %SSAM_REQUEST_HAS_RESPONSE flag are mutually exclusive.
 */
enum ssam_request_flags {
	SSAM_REQUEST_HAS_RESPONSE = BIT(0),
	SSAM_REQUEST_UNSEQUENCED  = BIT(1),
};

/**
 * struct ssam_request - SAM request description.
 * @target_category: Category of the request's target. See &enum ssam_ssh_tc.
 * @target_id:       ID of the request's target.
 * @command_id:      Command ID of the request.
 * @instance_id:     Instance ID of the request's target.
 * @flags:           Flags for the request. See &enum ssam_request_flags.
 * @length:          Length of the request payload in bytes.
 * @payload:         Request payload data.
 *
 * This struct fully describes a SAM request with payload. It is intended to
 * help set up the actual transport struct, e.g. &struct ssam_request_sync,
 * and specifically its raw message data via ssam_request_write_data().
 */
struct ssam_request {
	u8 target_category;
	u8 target_id;
	u8 command_id;
	u8 instance_id;
	u16 flags;
	u16 length;
	const u8 *payload;
};

/**
 * struct ssam_response - Response buffer for SAM request.
 * @capacity: Capacity of the buffer, in bytes.
 * @length:   Length of the actual data stored in the memory pointed to by
 *            @pointer, in bytes. Set by the transport system.
 * @pointer:  Pointer to the buffer's memory, storing the response payload data.
 */
struct ssam_response {
	size_t capacity;
	size_t length;
	u8 *pointer;
};

struct ssam_controller;

struct ssam_controller *ssam_get_controller(void);
struct ssam_controller *ssam_client_bind(struct device *client);
int ssam_client_link(struct ssam_controller *ctrl, struct device *client);

struct device *ssam_controller_device(struct ssam_controller *c);

struct ssam_controller *ssam_controller_get(struct ssam_controller *c);
void ssam_controller_put(struct ssam_controller *c);

void ssam_controller_statelock(struct ssam_controller *c);
void ssam_controller_stateunlock(struct ssam_controller *c);

ssize_t ssam_request_write_data(struct ssam_span *buf,
				struct ssam_controller *ctrl,
				const struct ssam_request *spec);


/* -- Synchronous request interface. ---------------------------------------- */

/**
 * struct ssam_request_sync - Synchronous SAM request struct.
 * @base:   Underlying SSH request.
 * @comp:   Completion used to signal full completion of the request. After the
 *          request has been submitted, this struct may only be modified or
 *          deallocated after the completion has been signaled.
 *          request has been submitted,
 * @resp:   Buffer to store the response.
 * @status: Status of the request, set after the base request has been
 *          completed or has failed.
 */
struct ssam_request_sync {
	struct ssh_request base;
	struct completion comp;
	struct ssam_response *resp;
	int status;
};

int ssam_request_sync_alloc(size_t payload_len, gfp_t flags,
			    struct ssam_request_sync **rqst,
			    struct ssam_span *buffer);

void ssam_request_sync_free(struct ssam_request_sync *rqst);

int ssam_request_sync_init(struct ssam_request_sync *rqst,
			   enum ssam_request_flags flags);

/**
 * ssam_request_sync_set_data - Set message data of a synchronous request.
 * @rqst: The request.
 * @ptr:  Pointer to the request message data.
 * @len:  Length of the request message data.
 *
 * Set the request message data of a synchronous request. The provided buffer
 * needs to live until the request has been completed.
 */
static inline void ssam_request_sync_set_data(struct ssam_request_sync *rqst,
					      u8 *ptr, size_t len)
{
	ssh_request_set_data(&rqst->base, ptr, len);
}

/**
 * ssam_request_sync_set_resp - Set response buffer of a synchronous request.
 * @rqst: The request.
 * @resp: The response buffer.
 *
 * Sets the response buffer of a synchronous request. This buffer will store
 * the response of the request after it has been completed. May be %NULL if no
 * response is expected.
 */
static inline void ssam_request_sync_set_resp(struct ssam_request_sync *rqst,
					      struct ssam_response *resp)
{
	rqst->resp = resp;
}

int ssam_request_sync_submit(struct ssam_controller *ctrl,
			     struct ssam_request_sync *rqst);

/**
 * ssam_request_sync_wait - Wait for completion of a synchronous request.
 * @rqst: The request to wait for.
 *
 * Wait for completion and release of a synchronous request. After this
 * function terminates, the request is guaranteed to have left the transport
 * system. After successful submission of a request, this function must be
 * called before accessing the response of the request, freeing the request,
 * or freeing any of the buffers associated with the request.
 *
 * This function must not be called if the request has not been submitted yet
 * and may lead to a deadlock/infinite wait if a subsequent request submission
 * fails in that case, due to the completion never triggering.
 *
 * Return: Returns the status of the given request, which is set on completion
 * of the packet. This value is zero on success and negative on failure.
 */
static inline int ssam_request_sync_wait(struct ssam_request_sync *rqst)
{
	wait_for_completion(&rqst->comp);
	return rqst->status;
}

210 211 212
int ssam_request_do_sync(struct ssam_controller *ctrl,
			 const struct ssam_request *spec,
			 struct ssam_response *rsp);
213

214 215 216 217
int ssam_request_do_sync_with_buffer(struct ssam_controller *ctrl,
				     const struct ssam_request *spec,
				     struct ssam_response *rsp,
				     struct ssam_span *buf);
218 219

/**
220
 * ssam_request_do_sync_onstack - Execute a synchronous request on the stack.
221 222 223 224 225 226 227 228 229
 * @ctrl: The controller via which the request is submitted.
 * @rqst: The request specification.
 * @rsp:  The response buffer.
 * @payload_len: The (maximum) request payload length.
 *
 * Allocates a synchronous request with specified payload length on the stack,
 * fully initializes it via the provided request specification, submits it,
 * and finally waits for its completion before returning its status. This
 * helper macro essentially allocates the request message buffer on the stack
230
 * and then calls ssam_request_do_sync_with_buffer().
231 232 233 234 235 236 237
 *
 * Note: The @payload_len parameter specifies the maximum payload length, used
 * for buffer allocation. The actual payload length may be smaller.
 *
 * Return: Returns the status of the request or any failure during setup, i.e.
 * zero on success and a negative value on failure.
 */
238
#define ssam_request_do_sync_onstack(ctrl, rqst, rsp, payload_len)		\
239 240 241 242
	({									\
		u8 __data[SSH_COMMAND_MESSAGE_LENGTH(payload_len)];		\
		struct ssam_span __buf = { &__data[0], ARRAY_SIZE(__data) };	\
										\
243
		ssam_request_do_sync_with_buffer(ctrl, rqst, rsp, &__buf);	\
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346
	})

/**
 * __ssam_retry - Retry request in case of I/O errors or timeouts.
 * @request: The request function to execute. Must return an integer.
 * @n:       Number of tries.
 * @args:    Arguments for the request function.
 *
 * Executes the given request function, i.e. calls @request. In case the
 * request returns %-EREMOTEIO (indicates I/O error) or %-ETIMEDOUT (request
 * or underlying packet timed out), @request will be re-executed again, up to
 * @n times in total.
 *
 * Return: Returns the return value of the last execution of @request.
 */
#define __ssam_retry(request, n, args...)				\
	({								\
		int __i, __s = 0;					\
									\
		for (__i = (n); __i > 0; __i--) {			\
			__s = request(args);				\
			if (__s != -ETIMEDOUT && __s != -EREMOTEIO)	\
				break;					\
		}							\
		__s;							\
	})

/**
 * ssam_retry - Retry request in case of I/O errors or timeouts up to three
 * times in total.
 * @request: The request function to execute. Must return an integer.
 * @args:    Arguments for the request function.
 *
 * Executes the given request function, i.e. calls @request. In case the
 * request returns %-EREMOTEIO (indicates I/O error) or -%ETIMEDOUT (request
 * or underlying packet timed out), @request will be re-executed again, up to
 * three times in total.
 *
 * See __ssam_retry() for a more generic macro for this purpose.
 *
 * Return: Returns the return value of the last execution of @request.
 */
#define ssam_retry(request, args...) \
	__ssam_retry(request, 3, args)

/**
 * struct ssam_request_spec - Blue-print specification of SAM request.
 * @target_category: Category of the request's target. See &enum ssam_ssh_tc.
 * @target_id:       ID of the request's target.
 * @command_id:      Command ID of the request.
 * @instance_id:     Instance ID of the request's target.
 * @flags:           Flags for the request. See &enum ssam_request_flags.
 *
 * Blue-print specification for a SAM request. This struct describes the
 * unique static parameters of a request (i.e. type) without specifying any of
 * its instance-specific data (e.g. payload). It is intended to be used as base
 * for defining simple request functions via the
 * ``SSAM_DEFINE_SYNC_REQUEST_x()`` family of macros.
 */
struct ssam_request_spec {
	u8 target_category;
	u8 target_id;
	u8 command_id;
	u8 instance_id;
	u8 flags;
};

/**
 * struct ssam_request_spec_md - Blue-print specification for multi-device SAM
 * request.
 * @target_category: Category of the request's target. See &enum ssam_ssh_tc.
 * @command_id:      Command ID of the request.
 * @flags:           Flags for the request. See &enum ssam_request_flags.
 *
 * Blue-print specification for a multi-device SAM request, i.e. a request
 * that is applicable to multiple device instances, described by their
 * individual target and instance IDs. This struct describes the unique static
 * parameters of a request (i.e. type) without specifying any of its
 * instance-specific data (e.g. payload) and without specifying any of its
 * device specific IDs (i.e. target and instance ID). It is intended to be
 * used as base for defining simple multi-device request functions via the
 * ``SSAM_DEFINE_SYNC_REQUEST_MD_x()`` and ``SSAM_DEFINE_SYNC_REQUEST_CL_x()``
 * families of macros.
 */
struct ssam_request_spec_md {
	u8 target_category;
	u8 command_id;
	u8 flags;
};

/**
 * SSAM_DEFINE_SYNC_REQUEST_N() - Define synchronous SAM request function
 * with neither argument nor return value.
 * @name: Name of the generated function.
 * @spec: Specification (&struct ssam_request_spec) defining the request.
 *
 * Defines a function executing the synchronous SAM request specified by
 * @spec, with the request having neither argument nor return value. The
 * generated function takes care of setting up the request struct and buffer
 * allocation, as well as execution of the request itself, returning once the
 * request has been fully completed. The required transport buffer will be
 * allocated on the stack.
 *
347 348 349 350
 * The generated function is defined as ``static int name(struct
 * ssam_controller *ctrl)``, returning the status of the request, which is
 * zero on success and negative on failure. The ``ctrl`` parameter is the
 * controller via which the request is being sent.
351
 *
352
 * Refer to ssam_request_do_sync_onstack() for more details on the behavior of
353 354 355
 * the generated function.
 */
#define SSAM_DEFINE_SYNC_REQUEST_N(name, spec...)				\
356
	static int name(struct ssam_controller *ctrl)				\
357 358 359 360 361 362 363 364 365 366 367 368
	{									\
		struct ssam_request_spec s = (struct ssam_request_spec)spec;	\
		struct ssam_request rqst;					\
										\
		rqst.target_category = s.target_category;			\
		rqst.target_id = s.target_id;					\
		rqst.command_id = s.command_id;					\
		rqst.instance_id = s.instance_id;				\
		rqst.flags = s.flags;						\
		rqst.length = 0;						\
		rqst.payload = NULL;						\
										\
369
		return ssam_request_do_sync_onstack(ctrl, &rqst, NULL, 0);	\
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
	}

/**
 * SSAM_DEFINE_SYNC_REQUEST_W() - Define synchronous SAM request function with
 * argument.
 * @name:  Name of the generated function.
 * @atype: Type of the request's argument.
 * @spec:  Specification (&struct ssam_request_spec) defining the request.
 *
 * Defines a function executing the synchronous SAM request specified by
 * @spec, with the request taking an argument of type @atype and having no
 * return value. The generated function takes care of setting up the request
 * struct, buffer allocation, as well as execution of the request itself,
 * returning once the request has been fully completed. The required transport
 * buffer will be allocated on the stack.
 *
386 387 388 389 390
 * The generated function is defined as ``static int name(struct
 * ssam_controller *ctrl, const atype *arg)``, returning the status of the
 * request, which is zero on success and negative on failure. The ``ctrl``
 * parameter is the controller via which the request is sent. The request
 * argument is specified via the ``arg`` pointer.
391
 *
392
 * Refer to ssam_request_do_sync_onstack() for more details on the behavior of
393 394 395
 * the generated function.
 */
#define SSAM_DEFINE_SYNC_REQUEST_W(name, atype, spec...)			\
396
	static int name(struct ssam_controller *ctrl, const atype *arg)		\
397 398 399 400 401 402 403 404 405 406 407 408
	{									\
		struct ssam_request_spec s = (struct ssam_request_spec)spec;	\
		struct ssam_request rqst;					\
										\
		rqst.target_category = s.target_category;			\
		rqst.target_id = s.target_id;					\
		rqst.command_id = s.command_id;					\
		rqst.instance_id = s.instance_id;				\
		rqst.flags = s.flags;						\
		rqst.length = sizeof(atype);					\
		rqst.payload = (u8 *)arg;					\
										\
409 410
		return ssam_request_do_sync_onstack(ctrl, &rqst, NULL,		\
						    sizeof(atype));		\
411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
	}

/**
 * SSAM_DEFINE_SYNC_REQUEST_R() - Define synchronous SAM request function with
 * return value.
 * @name:  Name of the generated function.
 * @rtype: Type of the request's return value.
 * @spec:  Specification (&struct ssam_request_spec) defining the request.
 *
 * Defines a function executing the synchronous SAM request specified by
 * @spec, with the request taking no argument but having a return value of
 * type @rtype. The generated function takes care of setting up the request
 * and response structs, buffer allocation, as well as execution of the
 * request itself, returning once the request has been fully completed. The
 * required transport buffer will be allocated on the stack.
 *
427 428 429 430 431
 * The generated function is defined as ``static int name(struct
 * ssam_controller *ctrl, rtype *ret)``, returning the status of the request,
 * which is zero on success and negative on failure. The ``ctrl`` parameter is
 * the controller via which the request is sent. The request's return value is
 * written to the memory pointed to by the ``ret`` parameter.
432
 *
433
 * Refer to ssam_request_do_sync_onstack() for more details on the behavior of
434 435 436
 * the generated function.
 */
#define SSAM_DEFINE_SYNC_REQUEST_R(name, rtype, spec...)			\
437
	static int name(struct ssam_controller *ctrl, rtype *ret)		\
438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455
	{									\
		struct ssam_request_spec s = (struct ssam_request_spec)spec;	\
		struct ssam_request rqst;					\
		struct ssam_response rsp;					\
		int status;							\
										\
		rqst.target_category = s.target_category;			\
		rqst.target_id = s.target_id;					\
		rqst.command_id = s.command_id;					\
		rqst.instance_id = s.instance_id;				\
		rqst.flags = s.flags | SSAM_REQUEST_HAS_RESPONSE;		\
		rqst.length = 0;						\
		rqst.payload = NULL;						\
										\
		rsp.capacity = sizeof(rtype);					\
		rsp.length = 0;							\
		rsp.pointer = (u8 *)ret;					\
										\
456
		status = ssam_request_do_sync_onstack(ctrl, &rqst, &rsp, 0);	\
457 458 459 460 461 462 463 464 465 466 467 468 469 470 471
		if (status)							\
			return status;						\
										\
		if (rsp.length != sizeof(rtype)) {				\
			struct device *dev = ssam_controller_device(ctrl);	\
			dev_err(dev,						\
				"rqst: invalid response length, expected %zu, got %zu (tc: %#04x, cid: %#04x)", \
				sizeof(rtype), rsp.length, rqst.target_category,\
				rqst.command_id);				\
			return -EIO;						\
		}								\
										\
		return 0;							\
	}

472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
/**
 * SSAM_DEFINE_SYNC_REQUEST_WR() - Define synchronous SAM request function with
 * both argument and return value.
 * @name:  Name of the generated function.
 * @atype: Type of the request's argument.
 * @rtype: Type of the request's return value.
 * @spec:  Specification (&struct ssam_request_spec) defining the request.
 *
 * Defines a function executing the synchronous SAM request specified by @spec,
 * with the request taking an argument of type @atype and having a return value
 * of type @rtype. The generated function takes care of setting up the request
 * and response structs, buffer allocation, as well as execution of the request
 * itself, returning once the request has been fully completed. The required
 * transport buffer will be allocated on the stack.
 *
 * The generated function is defined as ``static int name(struct
 * ssam_controller *ctrl, const atype *arg, rtype *ret)``, returning the status
 * of the request, which is zero on success and negative on failure. The
 * ``ctrl`` parameter is the controller via which the request is sent. The
 * request argument is specified via the ``arg`` pointer. The request's return
 * value is written to the memory pointed to by the ``ret`` parameter.
 *
494
 * Refer to ssam_request_do_sync_onstack() for more details on the behavior of
495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516
 * the generated function.
 */
#define SSAM_DEFINE_SYNC_REQUEST_WR(name, atype, rtype, spec...)		\
	static int name(struct ssam_controller *ctrl, const atype *arg, rtype *ret) \
	{									\
		struct ssam_request_spec s = (struct ssam_request_spec)spec;	\
		struct ssam_request rqst;					\
		struct ssam_response rsp;					\
		int status;							\
										\
		rqst.target_category = s.target_category;			\
		rqst.target_id = s.target_id;					\
		rqst.command_id = s.command_id;					\
		rqst.instance_id = s.instance_id;				\
		rqst.flags = s.flags | SSAM_REQUEST_HAS_RESPONSE;		\
		rqst.length = sizeof(atype);					\
		rqst.payload = (u8 *)arg;					\
										\
		rsp.capacity = sizeof(rtype);					\
		rsp.length = 0;							\
		rsp.pointer = (u8 *)ret;					\
										\
517
		status = ssam_request_do_sync_onstack(ctrl, &rqst, &rsp, sizeof(atype)); \
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532
		if (status)							\
			return status;						\
										\
		if (rsp.length != sizeof(rtype)) {				\
			struct device *dev = ssam_controller_device(ctrl);	\
			dev_err(dev,						\
				"rqst: invalid response length, expected %zu, got %zu (tc: %#04x, cid: %#04x)", \
				sizeof(rtype), rsp.length, rqst.target_category,\
				rqst.command_id);				\
			return -EIO;						\
		}								\
										\
		return 0;							\
	}

533 534 535 536 537 538 539 540 541 542 543 544 545 546
/**
 * SSAM_DEFINE_SYNC_REQUEST_MD_N() - Define synchronous multi-device SAM
 * request function with neither argument nor return value.
 * @name: Name of the generated function.
 * @spec: Specification (&struct ssam_request_spec_md) defining the request.
 *
 * Defines a function executing the synchronous SAM request specified by
 * @spec, with the request having neither argument nor return value. Device
 * specifying parameters are not hard-coded, but instead must be provided to
 * the function. The generated function takes care of setting up the request
 * struct, buffer allocation, as well as execution of the request itself,
 * returning once the request has been fully completed. The required transport
 * buffer will be allocated on the stack.
 *
547 548 549 550 551
 * The generated function is defined as ``static int name(struct
 * ssam_controller *ctrl, u8 tid, u8 iid)``, returning the status of the
 * request, which is zero on success and negative on failure. The ``ctrl``
 * parameter is the controller via which the request is sent, ``tid`` the
 * target ID for the request, and ``iid`` the instance ID.
552
 *
553
 * Refer to ssam_request_do_sync_onstack() for more details on the behavior of
554 555 556
 * the generated function.
 */
#define SSAM_DEFINE_SYNC_REQUEST_MD_N(name, spec...)				\
557
	static int name(struct ssam_controller *ctrl, u8 tid, u8 iid)		\
558 559 560 561 562 563 564 565 566 567 568 569
	{									\
		struct ssam_request_spec_md s = (struct ssam_request_spec_md)spec; \
		struct ssam_request rqst;					\
										\
		rqst.target_category = s.target_category;			\
		rqst.target_id = tid;						\
		rqst.command_id = s.command_id;					\
		rqst.instance_id = iid;						\
		rqst.flags = s.flags;						\
		rqst.length = 0;						\
		rqst.payload = NULL;						\
										\
570
		return ssam_request_do_sync_onstack(ctrl, &rqst, NULL, 0);	\
571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
	}

/**
 * SSAM_DEFINE_SYNC_REQUEST_MD_W() - Define synchronous multi-device SAM
 * request function with argument.
 * @name:  Name of the generated function.
 * @atype: Type of the request's argument.
 * @spec:  Specification (&struct ssam_request_spec_md) defining the request.
 *
 * Defines a function executing the synchronous SAM request specified by
 * @spec, with the request taking an argument of type @atype and having no
 * return value. Device specifying parameters are not hard-coded, but instead
 * must be provided to the function. The generated function takes care of
 * setting up the request struct, buffer allocation, as well as execution of
 * the request itself, returning once the request has been fully completed.
 * The required transport buffer will be allocated on the stack.
 *
588 589 590 591 592 593
 * The generated function is defined as ``static int name(struct
 * ssam_controller *ctrl, u8 tid, u8 iid, const atype *arg)``, returning the
 * status of the request, which is zero on success and negative on failure.
 * The ``ctrl`` parameter is the controller via which the request is sent,
 * ``tid`` the target ID for the request, and ``iid`` the instance ID. The
 * request argument is specified via the ``arg`` pointer.
594
 *
595
 * Refer to ssam_request_do_sync_onstack() for more details on the behavior of
596 597 598
 * the generated function.
 */
#define SSAM_DEFINE_SYNC_REQUEST_MD_W(name, atype, spec...)			\
599
	static int name(struct ssam_controller *ctrl, u8 tid, u8 iid, const atype *arg) \
600 601 602 603 604 605 606 607 608 609 610 611
	{									\
		struct ssam_request_spec_md s = (struct ssam_request_spec_md)spec; \
		struct ssam_request rqst;					\
										\
		rqst.target_category = s.target_category;			\
		rqst.target_id = tid;						\
		rqst.command_id = s.command_id;					\
		rqst.instance_id = iid;						\
		rqst.flags = s.flags;						\
		rqst.length = sizeof(atype);					\
		rqst.payload = (u8 *)arg;					\
										\
612
		return ssam_request_do_sync_onstack(ctrl, &rqst, NULL,		\
613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630
						 sizeof(atype));		\
	}

/**
 * SSAM_DEFINE_SYNC_REQUEST_MD_R() - Define synchronous multi-device SAM
 * request function with return value.
 * @name:  Name of the generated function.
 * @rtype: Type of the request's return value.
 * @spec:  Specification (&struct ssam_request_spec_md) defining the request.
 *
 * Defines a function executing the synchronous SAM request specified by
 * @spec, with the request taking no argument but having a return value of
 * type @rtype. Device specifying parameters are not hard-coded, but instead
 * must be provided to the function. The generated function takes care of
 * setting up the request and response structs, buffer allocation, as well as
 * execution of the request itself, returning once the request has been fully
 * completed. The required transport buffer will be allocated on the stack.
 *
631 632 633 634 635 636
 * The generated function is defined as ``static int name(struct
 * ssam_controller *ctrl, u8 tid, u8 iid, rtype *ret)``, returning the status
 * of the request, which is zero on success and negative on failure. The
 * ``ctrl`` parameter is the controller via which the request is sent, ``tid``
 * the target ID for the request, and ``iid`` the instance ID. The request's
 * return value is written to the memory pointed to by the ``ret`` parameter.
637
 *
638
 * Refer to ssam_request_do_sync_onstack() for more details on the behavior of
639 640 641
 * the generated function.
 */
#define SSAM_DEFINE_SYNC_REQUEST_MD_R(name, rtype, spec...)			\
642
	static int name(struct ssam_controller *ctrl, u8 tid, u8 iid, rtype *ret) \
643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660
	{									\
		struct ssam_request_spec_md s = (struct ssam_request_spec_md)spec; \
		struct ssam_request rqst;					\
		struct ssam_response rsp;					\
		int status;							\
										\
		rqst.target_category = s.target_category;			\
		rqst.target_id = tid;						\
		rqst.command_id = s.command_id;					\
		rqst.instance_id = iid;						\
		rqst.flags = s.flags | SSAM_REQUEST_HAS_RESPONSE;		\
		rqst.length = 0;						\
		rqst.payload = NULL;						\
										\
		rsp.capacity = sizeof(rtype);					\
		rsp.length = 0;							\
		rsp.pointer = (u8 *)ret;					\
										\
661
		status = ssam_request_do_sync_onstack(ctrl, &rqst, &rsp, 0);	\
662 663 664 665 666 667
		if (status)							\
			return status;						\
										\
		if (rsp.length != sizeof(rtype)) {				\
			struct device *dev = ssam_controller_device(ctrl);	\
			dev_err(dev,						\
668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700
				"rqst: invalid response length, expected %zu, got %zu (tc: %#04x, cid: %#04x)", \
				sizeof(rtype), rsp.length, rqst.target_category,\
				rqst.command_id);				\
			return -EIO;						\
		}								\
										\
		return 0;							\
	}

/**
 * SSAM_DEFINE_SYNC_REQUEST_MD_WR() - Define synchronous multi-device SAM
 * request function with both argument and return value.
 * @name:  Name of the generated function.
 * @atype: Type of the request's argument.
 * @rtype: Type of the request's return value.
 * @spec:  Specification (&struct ssam_request_spec_md) defining the request.
 *
 * Defines a function executing the synchronous SAM request specified by @spec,
 * with the request taking an argument of type @atype and having a return value
 * of type @rtype. Device specifying parameters are not hard-coded, but instead
 * must be provided to the function. The generated function takes care of
 * setting up the request and response structs, buffer allocation, as well as
 * execution of the request itself, returning once the request has been fully
 * completed. The required transport buffer will be allocated on the stack.
 *
 * The generated function is defined as ``static int name(struct
 * ssam_controller *ctrl, u8 tid, u8 iid, const atype *arg, rtype *ret)``,
 * returning the status of the request, which is zero on success and negative
 * on failure. The ``ctrl`` parameter is the controller via which the request
 * is sent, ``tid`` the target ID for the request, and ``iid`` the instance ID.
 * The request argument is specified via the ``arg`` pointer. The request's
 * return value is written to the memory pointed to by the ``ret`` parameter.
 *
701
 * Refer to ssam_request_do_sync_onstack() for more details on the behavior of
702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724
 * the generated function.
 */
#define SSAM_DEFINE_SYNC_REQUEST_MD_WR(name, atype, rtype, spec...)		\
	static int name(struct ssam_controller *ctrl, u8 tid, u8 iid,		\
			const atype *arg, rtype *ret)				\
	{									\
		struct ssam_request_spec_md s = (struct ssam_request_spec_md)spec; \
		struct ssam_request rqst;					\
		struct ssam_response rsp;					\
		int status;							\
										\
		rqst.target_category = s.target_category;			\
		rqst.target_id = tid;						\
		rqst.command_id = s.command_id;					\
		rqst.instance_id = iid;						\
		rqst.flags = s.flags | SSAM_REQUEST_HAS_RESPONSE;		\
		rqst.length = sizeof(atype);					\
		rqst.payload = (u8 *)arg;					\
										\
		rsp.capacity = sizeof(rtype);					\
		rsp.length = 0;							\
		rsp.pointer = (u8 *)ret;					\
										\
725
		status = ssam_request_do_sync_onstack(ctrl, &rqst, &rsp, sizeof(atype)); \
726 727 728 729 730 731
		if (status)							\
			return status;						\
										\
		if (rsp.length != sizeof(rtype)) {				\
			struct device *dev = ssam_controller_device(ctrl);	\
			dev_err(dev,						\
732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914
				"rqst: invalid response length, expected %zu, got %zu (tc: %#04x, cid: %#04x)", \
				sizeof(rtype), rsp.length, rqst.target_category,\
				rqst.command_id);				\
			return -EIO;						\
		}								\
										\
		return 0;							\
	}


/* -- Event notifier/callbacks. --------------------------------------------- */

#define SSAM_NOTIF_STATE_SHIFT		2
#define SSAM_NOTIF_STATE_MASK		((1 << SSAM_NOTIF_STATE_SHIFT) - 1)

/**
 * enum ssam_notif_flags - Flags used in return values from SSAM notifier
 * callback functions.
 *
 * @SSAM_NOTIF_HANDLED:
 *	Indicates that the notification has been handled. This flag should be
 *	set by the handler if the handler can act/has acted upon the event
 *	provided to it. This flag should not be set if the handler is not a
 *	primary handler intended for the provided event.
 *
 *	If this flag has not been set by any handler after the notifier chain
 *	has been traversed, a warning will be emitted, stating that the event
 *	has not been handled.
 *
 * @SSAM_NOTIF_STOP:
 *	Indicates that the notifier traversal should stop. If this flag is
 *	returned from a notifier callback, notifier chain traversal will
 *	immediately stop and any remaining notifiers will not be called. This
 *	flag is automatically set when ssam_notifier_from_errno() is called
 *	with a negative error value.
 */
enum ssam_notif_flags {
	SSAM_NOTIF_HANDLED = BIT(0),
	SSAM_NOTIF_STOP    = BIT(1),
};

struct ssam_event_notifier;

typedef u32 (*ssam_notifier_fn_t)(struct ssam_event_notifier *nf,
				  const struct ssam_event *event);

/**
 * struct ssam_notifier_block - Base notifier block for SSAM event
 * notifications.
 * @node:     The node for the list of notifiers.
 * @fn:       The callback function of this notifier. This function takes the
 *            respective notifier block and event as input and should return
 *            a notifier value, which can either be obtained from the flags
 *            provided in &enum ssam_notif_flags, converted from a standard
 *            error value via ssam_notifier_from_errno(), or a combination of
 *            both (e.g. ``ssam_notifier_from_errno(e) | SSAM_NOTIF_HANDLED``).
 * @priority: Priority value determining the order in which notifier callbacks
 *            will be called. A higher value means higher priority, i.e. the
 *            associated callback will be executed earlier than other (lower
 *            priority) callbacks.
 */
struct ssam_notifier_block {
	struct list_head node;
	ssam_notifier_fn_t fn;
	int priority;
};

/**
 * ssam_notifier_from_errno() - Convert standard error value to notifier
 * return code.
 * @err: The error code to convert, must be negative (in case of failure) or
 *       zero (in case of success).
 *
 * Return: Returns the notifier return value obtained by converting the
 * specified @err value. In case @err is negative, the %SSAM_NOTIF_STOP flag
 * will be set, causing notifier call chain traversal to abort.
 */
static inline u32 ssam_notifier_from_errno(int err)
{
	if (WARN_ON(err > 0) || err == 0)
		return 0;
	else
		return ((-err) << SSAM_NOTIF_STATE_SHIFT) | SSAM_NOTIF_STOP;
}

/**
 * ssam_notifier_to_errno() - Convert notifier return code to standard error
 * value.
 * @ret: The notifier return value to convert.
 *
 * Return: Returns the negative error value encoded in @ret or zero if @ret
 * indicates success.
 */
static inline int ssam_notifier_to_errno(u32 ret)
{
	return -(ret >> SSAM_NOTIF_STATE_SHIFT);
}


/* -- Event/notification registry. ------------------------------------------ */

/**
 * struct ssam_event_registry - Registry specification used for enabling events.
 * @target_category: Target category for the event registry requests.
 * @target_id:       Target ID for the event registry requests.
 * @cid_enable:      Command ID for the event-enable request.
 * @cid_disable:     Command ID for the event-disable request.
 *
 * This struct describes a SAM event registry via the minimal collection of
 * SAM IDs specifying the requests to use for enabling and disabling an event.
 * The individual event to be enabled/disabled itself is specified via &struct
 * ssam_event_id.
 */
struct ssam_event_registry {
	u8 target_category;
	u8 target_id;
	u8 cid_enable;
	u8 cid_disable;
};

/**
 * struct ssam_event_id - Unique event ID used for enabling events.
 * @target_category: Target category of the event source.
 * @instance:        Instance ID of the event source.
 *
 * This struct specifies the event to be enabled/disabled via an externally
 * provided registry. It does not specify the registry to be used itself, this
 * is done via &struct ssam_event_registry.
 */
struct ssam_event_id {
	u8 target_category;
	u8 instance;
};

/**
 * enum ssam_event_mask - Flags specifying how events are matched to notifiers.
 *
 * @SSAM_EVENT_MASK_NONE:
 *	Run the callback for any event with matching target category. Do not
 *	do any additional filtering.
 *
 * @SSAM_EVENT_MASK_TARGET:
 *	In addition to filtering by target category, only execute the notifier
 *	callback for events with a target ID matching to the one of the
 *	registry used for enabling/disabling the event.
 *
 * @SSAM_EVENT_MASK_INSTANCE:
 *	In addition to filtering by target category, only execute the notifier
 *	callback for events with an instance ID matching to the instance ID
 *	used when enabling the event.
 *
 * @SSAM_EVENT_MASK_STRICT:
 *	Do all the filtering above.
 */
enum ssam_event_mask {
	SSAM_EVENT_MASK_TARGET   = BIT(0),
	SSAM_EVENT_MASK_INSTANCE = BIT(1),

	SSAM_EVENT_MASK_NONE = 0,
	SSAM_EVENT_MASK_STRICT =
		  SSAM_EVENT_MASK_TARGET
		| SSAM_EVENT_MASK_INSTANCE,
};

/**
 * SSAM_EVENT_REGISTRY() - Define a new event registry.
 * @tc:      Target category for the event registry requests.
 * @tid:     Target ID for the event registry requests.
 * @cid_en:  Command ID for the event-enable request.
 * @cid_dis: Command ID for the event-disable request.
 *
 * Return: Returns the &struct ssam_event_registry specified by the given
 * parameters.
 */
#define SSAM_EVENT_REGISTRY(tc, tid, cid_en, cid_dis)	\
	((struct ssam_event_registry) {			\
		.target_category = (tc),		\
		.target_id = (tid),			\
		.cid_enable = (cid_en),			\
		.cid_disable = (cid_dis),		\
	})

#define SSAM_EVENT_REGISTRY_SAM	\
915
	SSAM_EVENT_REGISTRY(SSAM_SSH_TC_SAM, SSAM_SSH_TID_SAM, 0x0b, 0x0c)
916 917

#define SSAM_EVENT_REGISTRY_KIP	\
918
	SSAM_EVENT_REGISTRY(SSAM_SSH_TC_KIP, SSAM_SSH_TID_KIP, 0x27, 0x28)
919

920 921
#define SSAM_EVENT_REGISTRY_REG(tid)\
	SSAM_EVENT_REGISTRY(SSAM_SSH_TC_REG, tid, 0x01, 0x02)
922

923 924 925 926 927 928 929 930 931 932 933 934 935 936
/**
 * enum ssam_event_notifier_flags - Flags for event notifiers.
 * @SSAM_EVENT_NOTIFIER_OBSERVER:
 *	The corresponding notifier acts as observer. Registering a notifier
 *	with this flag set will not attempt to enable any event. Equally,
 *	unregistering will not attempt to disable any event. Note that a
 *	notifier with this flag may not even correspond to a certain event at
 *	all, only to a specific event target category. Event matching will not
 *	be influenced by this flag.
 */
enum ssam_event_notifier_flags {
	SSAM_EVENT_NOTIFIER_OBSERVER = BIT(0),
};

937 938 939 940 941 942 943 944
/**
 * struct ssam_event_notifier - Notifier block for SSAM events.
 * @base:        The base notifier block with callback function and priority.
 * @event:       The event for which this block will receive notifications.
 * @event.reg:   Registry via which the event will be enabled/disabled.
 * @event.id:    ID specifying the event.
 * @event.mask:  Flags determining how events are matched to the notifier.
 * @event.flags: Flags used for enabling the event.
945
 * @flags:       Notifier flags (see &enum ssam_event_notifier_flags).
946 947 948 949 950 951 952 953 954 955
 */
struct ssam_event_notifier {
	struct ssam_notifier_block base;

	struct {
		struct ssam_event_registry reg;
		struct ssam_event_id id;
		enum ssam_event_mask mask;
		u8 flags;
	} event;
956 957

	unsigned long flags;
958 959 960 961 962
};

int ssam_notifier_register(struct ssam_controller *ctrl,
			   struct ssam_event_notifier *n);

963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984
int __ssam_notifier_unregister(struct ssam_controller *ctrl,
			       struct ssam_event_notifier *n, bool disable);

/**
 * ssam_notifier_unregister() - Unregister an event notifier.
 * @ctrl:    The controller the notifier has been registered on.
 * @n:       The event notifier to unregister.
 *
 * Unregister an event notifier. Decrement the usage counter of the associated
 * SAM event if the notifier is not marked as an observer. If the usage counter
 * reaches zero, the event will be disabled.
 *
 * Return: Returns zero on success, %-ENOENT if the given notifier block has
 * not been registered on the controller. If the given notifier block was the
 * last one associated with its specific event, returns the status of the
 * event-disable EC-command.
 */
static inline int ssam_notifier_unregister(struct ssam_controller *ctrl,
					   struct ssam_event_notifier *n)
{
	return __ssam_notifier_unregister(ctrl, n, true);
}
985

986 987 988 989 990 991 992 993
int ssam_controller_event_enable(struct ssam_controller *ctrl,
				 struct ssam_event_registry reg,
				 struct ssam_event_id id, u8 flags);

int ssam_controller_event_disable(struct ssam_controller *ctrl,
				  struct ssam_event_registry reg,
				  struct ssam_event_id id, u8 flags);

994
#endif /* _LINUX_SURFACE_AGGREGATOR_CONTROLLER_H */