static clockid_t clock_open(char *device) { struct sk_ts_info ts_info; char phc_device[19]; int clkid; /* check if device is CLOCK_REALTIME */ if (!strcasecmp(device, "CLOCK_REALTIME")) return CLOCK_REALTIME; /* check if device is valid phc device */ clkid = phc_open(device); if (clkid != CLOCK_INVALID) return clkid; /* check if device is a valid ethernet device */ if (sk_get_ts_info(device, &ts_info) || !ts_info.valid) { pr_err("unknown clock %s: %m", device); return CLOCK_INVALID; } if (ts_info.phc_index < 0) { pr_err("interface %s does not have a PHC", device); return CLOCK_INVALID; } sprintf(phc_device, "/dev/ptp%d", ts_info.phc_index); clkid = phc_open(phc_device); if (clkid == CLOCK_INVALID) pr_err("cannot open %s for %s: %m", phc_device, device); return clkid; }
static int add_ptp_source(struct ptp_domain *source, struct timemaster_config *config, int *shm_segment, int ***allocated_phcs, char **ntp_config, struct script *script) { struct config_file *config_file; char **command, *uds_path, **interfaces; int i, j, num_interfaces, *phc, *phcs, hw_ts; struct sk_ts_info ts_info; pr_debug("adding PTP domain %d", source->domain); hw_ts = SOF_TIMESTAMPING_TX_HARDWARE | SOF_TIMESTAMPING_RX_HARDWARE | SOF_TIMESTAMPING_RAW_HARDWARE; for (num_interfaces = 0; source->interfaces[num_interfaces]; num_interfaces++) ; if (!num_interfaces) return 0; /* get PHCs used by specified interfaces */ phcs = xmalloc(num_interfaces * sizeof(int)); for (i = 0; i < num_interfaces; i++) { phcs[i] = -1; /* check if the interface has a usable PHC */ if (sk_get_ts_info(source->interfaces[i], &ts_info)) { pr_err("failed to get time stamping info for %s", source->interfaces[i]); free(phcs); return 1; } if (!ts_info.valid || ((ts_info.so_timestamping & hw_ts) != hw_ts)) { pr_debug("interface %s: no PHC", source->interfaces[i]); continue; } pr_debug("interface %s: PHC %d", source->interfaces[i], ts_info.phc_index); /* and the PHC isn't already used in another source */ for (j = 0; (*allocated_phcs)[j]; j++) { if (*(*allocated_phcs)[j] == ts_info.phc_index) { pr_debug("PHC %d already allocated", ts_info.phc_index); break; } } if (!(*allocated_phcs)[j]) phcs[i] = ts_info.phc_index; } for (i = 0; i < num_interfaces; i++) { /* skip if already used by ptp4l in this domain */ if (phcs[i] == -2) continue; interfaces = (char **)parray_new(); parray_append((void ***)&interfaces, source->interfaces[i]); /* merge all interfaces sharing PHC to one ptp4l command */ if (phcs[i] >= 0) { for (j = i + 1; j < num_interfaces; j++) { if (phcs[i] == phcs[j]) { parray_append((void ***)&interfaces, source->interfaces[j]); /* mark the interface as used */ phcs[j] = -2; } } /* don't use this PHC in other sources */ phc = xmalloc(sizeof(int)); *phc = phcs[i]; parray_append((void ***)allocated_phcs, phc); } uds_path = string_newf("%s/ptp4l.%d.socket", config->rundir, *shm_segment); config_file = xmalloc(sizeof(*config_file)); config_file->path = string_newf("%s/ptp4l.%d.conf", config->rundir, *shm_segment); config_file->content = xstrdup("[global]\n"); extend_config_string(&config_file->content, config->ptp4l.settings); extend_config_string(&config_file->content, source->ptp4l_settings); string_appendf(&config_file->content, "slaveOnly 1\n" "domainNumber %d\n" "uds_address %s\n", source->domain, uds_path); if (phcs[i] >= 0) { /* HW time stamping */ command = get_ptp4l_command(&config->ptp4l, config_file, interfaces, 1); parray_append((void ***)&script->commands, command); command = get_phc2sys_command(&config->phc2sys, source->domain, source->phc2sys_poll, *shm_segment, uds_path); parray_append((void ***)&script->commands, command); } else { /* SW time stamping */ command = get_ptp4l_command(&config->ptp4l, config_file, interfaces, 0); parray_append((void ***)&script->commands, command); string_appendf(&config_file->content, "clock_servo ntpshm\n" "ntpshm_segment %d\n", *shm_segment); } parray_append((void ***)&script->configs, config_file); add_shm_source(*shm_segment, source->ntp_poll, source->phc2sys_poll, source->delay, source->ntp_options, "PTP", config, ntp_config); (*shm_segment)++; free(uds_path); free(interfaces); } free(phcs); return 0; }