mirror of https://github.com/thesofproject/sof.git
187 lines
4.4 KiB
C
187 lines
4.4 KiB
C
// SPDX-License-Identifier: BSD-3-Clause
|
|
//
|
|
// Copyright(c) 2022 Intel Corporation. All rights reserved.
|
|
//
|
|
// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
|
|
|
|
/*
|
|
* SOF pipeline in userspace.
|
|
*/
|
|
|
|
#define _GNU_SOURCE
|
|
|
|
#include <stdio.h>
|
|
#include <sys/poll.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <sys/wait.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <sys/mman.h>
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <pthread.h>
|
|
#include <limits.h>
|
|
#include <dlfcn.h>
|
|
|
|
#include "common.h"
|
|
#include "pipe.h"
|
|
|
|
/* read the CPU ID register data on x86 */
|
|
static inline void x86_cpuid(unsigned int *eax, unsigned int *ebx,
|
|
unsigned int *ecx, unsigned int *edx)
|
|
{
|
|
/* data type is passed in on eax (and sometimes ecx) */
|
|
asm volatile("cpuid"
|
|
: "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
|
|
: "0" (*eax), "2" (*ecx));
|
|
}
|
|
|
|
/*
|
|
* Check core type for E cores. If non hybrid then it does not matter.
|
|
*/
|
|
static inline int use_this_core(struct sof_pipe *sp)
|
|
{
|
|
/* CPUID - set eax to 0x1a for hybrid core types */
|
|
unsigned int eax = 0x1a, ebx = 0, ecx = 0, edx = 0;
|
|
char core_mask;
|
|
|
|
/* get the processor core type we are running on now */
|
|
x86_cpuid(&eax, &ebx, &ecx, &edx);
|
|
|
|
/* core type 0x20 is atom, 0x40 is core */
|
|
core_mask = (eax >> 24) & 0xFF;
|
|
switch (core_mask) {
|
|
case 0x20:
|
|
fprintf(sp->log, "found E core\n");
|
|
if (sp->use_E_core)
|
|
return 1;
|
|
return 0;
|
|
case 0x40:
|
|
fprintf(sp->log, "found P core\n");
|
|
if (sp->use_P_core)
|
|
return 1;
|
|
return 0;
|
|
default:
|
|
/* non hybrid arch, just use first core */
|
|
fprintf(sp->log, "found non hybrid core topology\n");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/* sof-pipe needs to be sticky to the current core for low latency */
|
|
int pipe_set_affinity(struct sof_pipe *sp)
|
|
{
|
|
cpu_set_t cpuset;
|
|
pthread_t thread;
|
|
long core_count = sysconf(_SC_NPROCESSORS_ONLN);
|
|
int i;
|
|
int err;
|
|
|
|
/* Set affinity mask to core */
|
|
thread = pthread_self();
|
|
CPU_ZERO(&cpuset);
|
|
|
|
/* find the first E core (usually come after the P cores ?) */
|
|
for (i = core_count - 1; i >= 0; i--) {
|
|
CPU_ZERO(&cpuset);
|
|
CPU_SET(i, &cpuset);
|
|
|
|
/* change our core to i */
|
|
err = pthread_setaffinity_np(thread, sizeof(cpuset), &cpuset);
|
|
if (err != 0) {
|
|
fprintf(sp->log, "error: failed to set CPU affinity to core %d: %s\n",
|
|
i, strerror(err));
|
|
return err;
|
|
}
|
|
|
|
/* should we use this core ? */
|
|
if (use_this_core(sp))
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* set ipc thread to low priority */
|
|
int pipe_set_ipc_lowpri(struct sof_pipe *sp)
|
|
{
|
|
pthread_attr_t attr;
|
|
struct sched_param param;
|
|
int err;
|
|
|
|
/* attempt to set thread priority - needs suid */
|
|
fprintf(sp->log, "pipe: set IPC low priority\n");
|
|
|
|
err = pthread_attr_init(&attr);
|
|
if (err < 0) {
|
|
fprintf(sp->log, "error: can't create thread attr %d %s\n", err, strerror(errno));
|
|
return err;
|
|
}
|
|
|
|
err = pthread_attr_setschedpolicy(&attr, SCHED_OTHER);
|
|
if (err < 0) {
|
|
fprintf(sp->log, "error: can't set thread policy %d %s\n", err, strerror(errno));
|
|
return err;
|
|
}
|
|
param.sched_priority = 0;
|
|
err = pthread_attr_setschedparam(&attr, ¶m);
|
|
if (err < 0) {
|
|
fprintf(sp->log, "error: can't set thread sched param %d %s\n",
|
|
err, strerror(errno));
|
|
return err;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* set pipeline to realtime priority */
|
|
int pipe_set_rt(struct sof_pipe *sp)
|
|
{
|
|
pthread_attr_t attr;
|
|
struct sched_param param;
|
|
int err;
|
|
uid_t uid = getuid();
|
|
uid_t euid = geteuid();
|
|
|
|
/* do we have elevated privileges to attempt RT priority */
|
|
if (uid < 0 || uid != euid) {
|
|
/* attempt to set thread priority - needs suid */
|
|
fprintf(sp->log, "pipe: set RT priority\n");
|
|
|
|
err = pthread_attr_init(&attr);
|
|
if (err < 0) {
|
|
fprintf(sp->log, "error: can't create thread attr %d %s\n",
|
|
err, strerror(errno));
|
|
return err;
|
|
}
|
|
|
|
err = pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
|
|
if (err < 0) {
|
|
fprintf(sp->log, "error: can't set thread policy %d %s\n",
|
|
err, strerror(errno));
|
|
return err;
|
|
}
|
|
param.sched_priority = 80;
|
|
err = pthread_attr_setschedparam(&attr, ¶m);
|
|
if (err < 0) {
|
|
fprintf(sp->log, "error: can't set thread sched param %d %s\n",
|
|
err, strerror(errno));
|
|
return err;
|
|
}
|
|
err = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
|
|
if (err < 0) {
|
|
fprintf(sp->log, "error: can't set thread inherit %d %s\n",
|
|
err, strerror(errno));
|
|
return err;
|
|
}
|
|
} else {
|
|
fprintf(sp->log, "error: no elevated privileges for RT. uid %d euid %d\n",
|
|
uid, euid);
|
|
}
|
|
|
|
return 0;
|
|
}
|