A signal is a classic kernel-to-process communication in some cases. Sure, any process with appropriate UID can use
kill() to send a signal, but signals like
SIGWINCH almost always come from the kernel.
Specific to Linux, you can look at the
signalfd() system call. The usual signal handling is via an "upcall", but
signalfd() gives a process a different way of receiving signals.
The return value of system calls could be considered a kernel-to-user process communication. This varies a lot, but
fork() is an example. The parent process gets back a non-zero process ID (or -1 on error) and the child process gets back zero.
select() system calls have arguments where the kernel sets values in the arguments to indicate which file descriptors have which events/state changes available to them. That's more like an "inout" formal argument, but the kernel does set values.
inotify API allows kernel-to-process communication via a
read() on a special file descriptor.
The POSIX asynchronous I/O system seems to have multiple ways to communicate with a user process, including starting a thread when an I/O occurs, if I read the man page correctly. I've never done POSIX async I/O, and it looks tricky.