1 /* $NetBSD: scmi.c,v 1.1 2025/01/08 22:55:35 jmcneill Exp $ */ 2 /* $OpenBSD: scmi.c,v 1.2 2024/11/25 22:12:18 tobhe Exp $ */ 3 4 /* 5 * Copyright (c) 2023 Mark Kettenis <kettenis@openbsd.org> 6 * Copyright (c) 2024 Tobias Heider <tobhe@openbsd.org> 7 * Copyright (c) 2025 Jared McNeill <jmcneill@invisible.ca> 8 * 9 * Permission to use, copy, modify, and distribute this software for any 10 * purpose with or without fee is hereby granted, provided that the above 11 * copyright notice and this permission notice appear in all copies. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 */ 21 22 #include <sys/param.h> 23 #include <sys/device.h> 24 #include <sys/systm.h> 25 #include <sys/kmem.h> 26 #include <sys/sysctl.h> 27 #include <sys/cpu.h> 28 29 #include <arm/arm/smccc.h> 30 #include <dev/ic/scmi.h> 31 32 #define SCMI_SUCCESS 0 33 #define SCMI_NOT_SUPPORTED -1 34 #define SCMI_DENIED -3 35 #define SCMI_BUSY -6 36 #define SCMI_COMMS_ERROR -7 37 38 /* Protocols */ 39 #define SCMI_BASE 0x10 40 #define SCMI_PERF 0x13 41 #define SCMI_CLOCK 0x14 42 43 /* Common messages */ 44 #define SCMI_PROTOCOL_VERSION 0x0 45 #define SCMI_PROTOCOL_ATTRIBUTES 0x1 46 #define SCMI_PROTOCOL_MESSAGE_ATTRIBUTES 0x2 47 48 /* Clock management messages */ 49 #define SCMI_CLOCK_ATTRIBUTES 0x3 50 #define SCMI_CLOCK_DESCRIBE_RATES 0x4 51 #define SCMI_CLOCK_RATE_SET 0x5 52 #define SCMI_CLOCK_RATE_GET 0x6 53 #define SCMI_CLOCK_CONFIG_SET 0x7 54 #define SCMI_CLOCK_CONFIG_SET_ENABLE (1U << 0) 55 56 /* Performance management messages */ 57 #define SCMI_PERF_DOMAIN_ATTRIBUTES 0x3 58 #define SCMI_PERF_DESCRIBE_LEVELS 0x4 59 #define SCMI_PERF_LIMITS_GET 0x6 60 #define SCMI_PERF_LEVEL_SET 0x7 61 #define SCMI_PERF_LEVEL_GET 0x8 62 63 struct scmi_resp_perf_domain_attributes_40 { 64 uint32_t pa_attrs; 65 #define SCMI_PERF_ATTR_CAN_LEVEL_SET (1U << 30) 66 #define SCMI_PERF_ATTR_LEVEL_INDEX_MODE (1U << 25) 67 uint32_t pa_ratelimit; 68 uint32_t pa_sustifreq; 69 uint32_t pa_sustperf; 70 char pa_name[16]; 71 }; 72 73 struct scmi_resp_perf_describe_levels_40 { 74 uint16_t pl_nret; 75 uint16_t pl_nrem; 76 struct { 77 uint32_t pe_perf; 78 uint32_t pe_cost; 79 uint16_t pe_latency; 80 uint16_t pe_reserved; 81 uint32_t pe_ifreq; 82 uint32_t pe_lindex; 83 } pl_entry[]; 84 }; 85 86 static void scmi_cpufreq_init_sysctl(struct scmi_softc *, uint32_t); 87 88 static inline void 89 scmi_message_header(volatile struct scmi_shmem *shmem, 90 uint32_t protocol_id, uint32_t message_id) 91 { 92 shmem->message_header = (protocol_id << 10) | (message_id << 0); 93 } 94 95 int32_t scmi_smc_command(struct scmi_softc *); 96 int32_t scmi_mbox_command(struct scmi_softc *); 97 98 int 99 scmi_init_smc(struct scmi_softc *sc) 100 { 101 volatile struct scmi_shmem *shmem; 102 int32_t status; 103 uint32_t vers; 104 105 if (sc->sc_smc_id == 0) { 106 aprint_error_dev(sc->sc_dev, "no SMC id\n"); 107 return -1; 108 } 109 110 shmem = sc->sc_shmem_tx; 111 112 sc->sc_command = scmi_smc_command; 113 114 if ((shmem->channel_status & SCMI_CHANNEL_FREE) == 0) { 115 aprint_error_dev(sc->sc_dev, "channel busy\n"); 116 return -1; 117 } 118 119 scmi_message_header(shmem, SCMI_BASE, SCMI_PROTOCOL_VERSION); 120 shmem->length = sizeof(uint32_t); 121 status = sc->sc_command(sc); 122 if (status != SCMI_SUCCESS) { 123 aprint_error_dev(sc->sc_dev, "protocol version command failed\n"); 124 return -1; 125 } 126 127 vers = shmem->message_payload[1]; 128 sc->sc_ver_major = vers >> 16; 129 sc->sc_ver_minor = vers & 0xfffff; 130 aprint_normal_dev(sc->sc_dev, "SCMI %d.%d\n", 131 sc->sc_ver_major, sc->sc_ver_minor); 132 133 mutex_init(&sc->sc_shmem_tx_lock, MUTEX_DEFAULT, IPL_NONE); 134 mutex_init(&sc->sc_shmem_rx_lock, MUTEX_DEFAULT, IPL_NONE); 135 136 return 0; 137 } 138 139 int 140 scmi_init_mbox(struct scmi_softc *sc) 141 { 142 int32_t status; 143 uint32_t vers; 144 145 if (sc->sc_mbox_tx == NULL) { 146 aprint_error_dev(sc->sc_dev, "no tx mbox\n"); 147 return -1; 148 } 149 if (sc->sc_mbox_rx == NULL) { 150 aprint_error_dev(sc->sc_dev, "no rx mbox\n"); 151 return -1; 152 } 153 154 sc->sc_command = scmi_mbox_command; 155 156 scmi_message_header(sc->sc_shmem_tx, SCMI_BASE, SCMI_PROTOCOL_VERSION); 157 sc->sc_shmem_tx->length = sizeof(uint32_t); 158 status = sc->sc_command(sc); 159 if (status != SCMI_SUCCESS) { 160 aprint_error_dev(sc->sc_dev, 161 "protocol version command failed\n"); 162 return -1; 163 } 164 165 vers = sc->sc_shmem_tx->message_payload[1]; 166 sc->sc_ver_major = vers >> 16; 167 sc->sc_ver_minor = vers & 0xfffff; 168 aprint_normal_dev(sc->sc_dev, "SCMI %d.%d\n", 169 sc->sc_ver_major, sc->sc_ver_minor); 170 171 mutex_init(&sc->sc_shmem_tx_lock, MUTEX_DEFAULT, IPL_NONE); 172 mutex_init(&sc->sc_shmem_rx_lock, MUTEX_DEFAULT, IPL_NONE); 173 174 return 0; 175 } 176 177 int32_t 178 scmi_smc_command(struct scmi_softc *sc) 179 { 180 volatile struct scmi_shmem *shmem = sc->sc_shmem_tx; 181 int32_t status; 182 183 shmem->channel_status = 0; 184 status = smccc_call(sc->sc_smc_id, 0, 0, 0, 0, 185 NULL, NULL, NULL, NULL); 186 if (status != SMCCC_SUCCESS) 187 return SCMI_NOT_SUPPORTED; 188 if ((shmem->channel_status & SCMI_CHANNEL_ERROR)) 189 return SCMI_COMMS_ERROR; 190 if ((shmem->channel_status & SCMI_CHANNEL_FREE) == 0) 191 return SCMI_BUSY; 192 return shmem->message_payload[0]; 193 } 194 195 int32_t 196 scmi_mbox_command(struct scmi_softc *sc) 197 { 198 volatile struct scmi_shmem *shmem = sc->sc_shmem_tx; 199 int ret; 200 int i; 201 202 shmem->channel_status = 0; 203 ret = sc->sc_mbox_tx_send(sc->sc_mbox_tx); 204 if (ret != 0) 205 return SCMI_NOT_SUPPORTED; 206 207 /* XXX: poll for now */ 208 for (i = 0; i < 20; i++) { 209 if (shmem->channel_status & SCMI_CHANNEL_FREE) 210 break; 211 delay(10); 212 } 213 if ((shmem->channel_status & SCMI_CHANNEL_ERROR)) 214 return SCMI_COMMS_ERROR; 215 if ((shmem->channel_status & SCMI_CHANNEL_FREE) == 0) 216 return SCMI_BUSY; 217 218 return shmem->message_payload[0]; 219 } 220 221 #if notyet 222 /* Clock management. */ 223 224 void scmi_clock_enable(void *, uint32_t *, int); 225 uint32_t scmi_clock_get_frequency(void *, uint32_t *); 226 int scmi_clock_set_frequency(void *, uint32_t *, uint32_t); 227 228 void 229 scmi_attach_clock(struct scmi_softc *sc, int node) 230 { 231 volatile struct scmi_shmem *shmem = sc->sc_shmem_tx; 232 int32_t status; 233 int nclocks; 234 235 scmi_message_header(shmem, SCMI_CLOCK, SCMI_PROTOCOL_ATTRIBUTES); 236 shmem->length = sizeof(uint32_t); 237 status = sc->sc_command(sc); 238 if (status != SCMI_SUCCESS) 239 return; 240 241 nclocks = shmem->message_payload[1] & 0xffff; 242 if (nclocks == 0) 243 return; 244 245 sc->sc_cd.cd_node = node; 246 sc->sc_cd.cd_cookie = sc; 247 sc->sc_cd.cd_enable = scmi_clock_enable; 248 sc->sc_cd.cd_get_frequency = scmi_clock_get_frequency; 249 sc->sc_cd.cd_set_frequency = scmi_clock_set_frequency; 250 clock_register(&sc->sc_cd); 251 } 252 253 void 254 scmi_clock_enable(void *cookie, uint32_t *cells, int on) 255 { 256 struct scmi_softc *sc = cookie; 257 volatile struct scmi_shmem *shmem = sc->sc_shmem_tx; 258 uint32_t idx = cells[0]; 259 260 scmi_message_header(shmem, SCMI_CLOCK, SCMI_CLOCK_CONFIG_SET); 261 shmem->length = 3 * sizeof(uint32_t); 262 shmem->message_payload[0] = idx; 263 shmem->message_payload[1] = on ? SCMI_CLOCK_CONFIG_SET_ENABLE : 0; 264 sc->sc_command(sc); 265 } 266 267 uint32_t 268 scmi_clock_get_frequency(void *cookie, uint32_t *cells) 269 { 270 struct scmi_softc *sc = cookie; 271 volatile struct scmi_shmem *shmem = sc->sc_shmem_tx; 272 uint32_t idx = cells[0]; 273 int32_t status; 274 275 scmi_message_header(shmem, SCMI_CLOCK, SCMI_CLOCK_RATE_GET); 276 shmem->length = 2 * sizeof(uint32_t); 277 shmem->message_payload[0] = idx; 278 status = sc->sc_command(sc); 279 if (status != SCMI_SUCCESS) 280 return 0; 281 if (shmem->message_payload[2] != 0) 282 return 0; 283 284 return shmem->message_payload[1]; 285 } 286 287 int 288 scmi_clock_set_frequency(void *cookie, uint32_t *cells, uint32_t freq) 289 { 290 struct scmi_softc *sc = cookie; 291 volatile struct scmi_shmem *shmem = sc->sc_shmem_tx; 292 uint32_t idx = cells[0]; 293 int32_t status; 294 295 scmi_message_header(shmem, SCMI_CLOCK, SCMI_CLOCK_RATE_SET); 296 shmem->length = 5 * sizeof(uint32_t); 297 shmem->message_payload[0] = 0; 298 shmem->message_payload[1] = idx; 299 shmem->message_payload[2] = freq; 300 shmem->message_payload[3] = 0; 301 status = sc->sc_command(sc); 302 if (status != SCMI_SUCCESS) 303 return -1; 304 305 return 0; 306 } 307 #endif 308 309 /* Performance management */ 310 void scmi_perf_descr_levels(struct scmi_softc *, int); 311 312 void 313 scmi_attach_perf(struct scmi_softc *sc) 314 { 315 volatile struct scmi_shmem *shmem = sc->sc_shmem_tx; 316 int32_t status; 317 uint32_t vers; 318 int i; 319 320 scmi_message_header(sc->sc_shmem_tx, SCMI_PERF, SCMI_PROTOCOL_VERSION); 321 sc->sc_shmem_tx->length = sizeof(uint32_t); 322 status = sc->sc_command(sc); 323 if (status != SCMI_SUCCESS) { 324 aprint_error_dev(sc->sc_dev, 325 "SCMI_PROTOCOL_VERSION failed\n"); 326 return; 327 } 328 329 vers = shmem->message_payload[1]; 330 if (vers != 0x40000) { 331 aprint_error_dev(sc->sc_dev, 332 "invalid perf protocol version (0x%x != 0x4000)", vers); 333 return; 334 } 335 336 scmi_message_header(shmem, SCMI_PERF, SCMI_PROTOCOL_ATTRIBUTES); 337 shmem->length = sizeof(uint32_t); 338 status = sc->sc_command(sc); 339 if (status != SCMI_SUCCESS) { 340 aprint_error_dev(sc->sc_dev, 341 "SCMI_PROTOCOL_ATTRIBUTES failed\n"); 342 return; 343 } 344 345 sc->sc_perf_ndomains = shmem->message_payload[1] & 0xffff; 346 sc->sc_perf_domains = kmem_zalloc(sc->sc_perf_ndomains * 347 sizeof(struct scmi_perf_domain), KM_SLEEP); 348 sc->sc_perf_power_unit = (shmem->message_payload[1] >> 16) & 0x3; 349 350 /* Add one frequency sensor per perf domain */ 351 for (i = 0; i < sc->sc_perf_ndomains; i++) { 352 volatile struct scmi_resp_perf_domain_attributes_40 *pa; 353 354 scmi_message_header(shmem, SCMI_PERF, 355 SCMI_PERF_DOMAIN_ATTRIBUTES); 356 shmem->length = 2 * sizeof(uint32_t); 357 shmem->message_payload[0] = i; 358 status = sc->sc_command(sc); 359 if (status != SCMI_SUCCESS) { 360 aprint_error_dev(sc->sc_dev, 361 "SCMI_PERF_DOMAIN_ATTRIBUTES failed\n"); 362 return; 363 } 364 365 pa = (volatile struct scmi_resp_perf_domain_attributes_40 *) 366 &shmem->message_payload[1]; 367 aprint_debug_dev(sc->sc_dev, 368 "dom %u attr %#x rate_limit %u sfreq %u sperf %u " 369 "name \"%s\"\n", 370 i, pa->pa_attrs, pa->pa_ratelimit, pa->pa_sustifreq, 371 pa->pa_sustperf, pa->pa_name); 372 373 sc->sc_perf_domains[i].pd_domain_id = i; 374 sc->sc_perf_domains[i].pd_sc = sc; 375 for (int map = 0; map < sc->sc_perf_ndmap; map++) { 376 if (sc->sc_perf_dmap[map].pm_domain == i) { 377 sc->sc_perf_domains[i].pd_ci = 378 sc->sc_perf_dmap[map].pm_ci; 379 break; 380 } 381 } 382 snprintf(sc->sc_perf_domains[i].pd_name, 383 sizeof(sc->sc_perf_domains[i].pd_name), "%s", pa->pa_name); 384 sc->sc_perf_domains[i].pd_can_level_set = 385 (pa->pa_attrs & SCMI_PERF_ATTR_CAN_LEVEL_SET) != 0; 386 sc->sc_perf_domains[i].pd_level_index_mode = 387 (pa->pa_attrs & SCMI_PERF_ATTR_LEVEL_INDEX_MODE) != 0; 388 sc->sc_perf_domains[i].pd_rate_limit = pa->pa_ratelimit; 389 sc->sc_perf_domains[i].pd_sustained_perf = pa->pa_sustperf; 390 391 scmi_perf_descr_levels(sc, i); 392 393 if (sc->sc_perf_domains[i].pd_can_level_set && 394 sc->sc_perf_domains[i].pd_nlevels > 0 && 395 sc->sc_perf_domains[i].pd_levels[0].pl_ifreq != 0) { 396 scmi_cpufreq_init_sysctl(sc, i); 397 } 398 } 399 return; 400 } 401 402 void 403 scmi_perf_descr_levels(struct scmi_softc *sc, int domain) 404 { 405 volatile struct scmi_shmem *shmem = sc->sc_shmem_tx; 406 volatile struct scmi_resp_perf_describe_levels_40 *pl; 407 struct scmi_perf_domain *pd = &sc->sc_perf_domains[domain]; 408 int status, i, idx; 409 410 idx = 0; 411 do { 412 scmi_message_header(shmem, SCMI_PERF, 413 SCMI_PERF_DESCRIBE_LEVELS); 414 shmem->length = sizeof(uint32_t) * 3; 415 shmem->message_payload[0] = domain; 416 shmem->message_payload[1] = idx; 417 status = sc->sc_command(sc); 418 if (status != SCMI_SUCCESS) { 419 aprint_error_dev(sc->sc_dev, 420 "SCMI_PERF_DESCRIBE_LEVELS failed\n"); 421 return; 422 } 423 424 pl = (volatile struct scmi_resp_perf_describe_levels_40 *) 425 &shmem->message_payload[1]; 426 427 if (pd->pd_levels == NULL) { 428 pd->pd_nlevels = pl->pl_nret + pl->pl_nrem; 429 pd->pd_levels = kmem_zalloc(pd->pd_nlevels * 430 sizeof(struct scmi_perf_level), 431 KM_SLEEP); 432 } 433 434 for (i = 0; i < pl->pl_nret; i++) { 435 pd->pd_levels[idx + i].pl_cost = 436 pl->pl_entry[i].pe_cost; 437 pd->pd_levels[idx + i].pl_perf = 438 pl->pl_entry[i].pe_perf; 439 pd->pd_levels[idx + i].pl_ifreq = 440 pl->pl_entry[i].pe_ifreq; 441 aprint_debug_dev(sc->sc_dev, 442 "dom %u pl %u cost %u perf %i ifreq %u\n", 443 domain, idx + i, 444 pl->pl_entry[i].pe_cost, 445 pl->pl_entry[i].pe_perf, 446 pl->pl_entry[i].pe_ifreq); 447 } 448 idx += pl->pl_nret; 449 } while (pl->pl_nrem); 450 } 451 452 static int32_t 453 scmi_perf_limits_get(struct scmi_perf_domain *pd, uint32_t *max_level, 454 uint32_t *min_level) 455 { 456 struct scmi_softc *sc = pd->pd_sc; 457 volatile struct scmi_shmem *shmem = sc->sc_shmem_tx; 458 int32_t status; 459 460 if (pd->pd_levels == NULL) { 461 return SCMI_NOT_SUPPORTED; 462 } 463 464 mutex_enter(&sc->sc_shmem_tx_lock); 465 scmi_message_header(shmem, SCMI_PERF, SCMI_PERF_LIMITS_GET); 466 shmem->length = sizeof(uint32_t) * 2; 467 shmem->message_payload[0] = pd->pd_domain_id; 468 status = sc->sc_command(sc); 469 if (status == SCMI_SUCCESS) { 470 *max_level = shmem->message_payload[1]; 471 *min_level = shmem->message_payload[2]; 472 } 473 mutex_exit(&sc->sc_shmem_tx_lock); 474 475 return status; 476 } 477 478 static int32_t 479 scmi_perf_level_get(struct scmi_perf_domain *pd, uint32_t *perf_level) 480 { 481 struct scmi_softc *sc = pd->pd_sc; 482 volatile struct scmi_shmem *shmem = sc->sc_shmem_tx; 483 int32_t status; 484 485 if (pd->pd_levels == NULL) { 486 return SCMI_NOT_SUPPORTED; 487 } 488 489 mutex_enter(&sc->sc_shmem_tx_lock); 490 scmi_message_header(shmem, SCMI_PERF, SCMI_PERF_LEVEL_GET); 491 shmem->length = sizeof(uint32_t) * 2; 492 shmem->message_payload[0] = pd->pd_domain_id; 493 status = sc->sc_command(sc); 494 if (status == SCMI_SUCCESS) { 495 *perf_level = shmem->message_payload[1]; 496 } 497 mutex_exit(&sc->sc_shmem_tx_lock); 498 499 return status; 500 } 501 502 static int32_t 503 scmi_perf_level_set(struct scmi_perf_domain *pd, uint32_t perf_level) 504 { 505 struct scmi_softc *sc = pd->pd_sc; 506 volatile struct scmi_shmem *shmem = sc->sc_shmem_tx; 507 int32_t status; 508 509 if (pd->pd_levels == NULL) { 510 return SCMI_NOT_SUPPORTED; 511 } 512 513 mutex_enter(&sc->sc_shmem_tx_lock); 514 scmi_message_header(shmem, SCMI_PERF, SCMI_PERF_LEVEL_SET); 515 shmem->length = sizeof(uint32_t) * 3; 516 shmem->message_payload[0] = pd->pd_domain_id; 517 shmem->message_payload[1] = perf_level; 518 status = sc->sc_command(sc); 519 mutex_exit(&sc->sc_shmem_tx_lock); 520 521 return status; 522 } 523 524 static u_int 525 scmi_cpufreq_level_to_mhz(struct scmi_perf_domain *pd, uint32_t level) 526 { 527 ssize_t n; 528 529 if (pd->pd_level_index_mode) { 530 if (level < pd->pd_nlevels) { 531 return pd->pd_levels[level].pl_ifreq / 1000; 532 } 533 } else { 534 for (n = 0; n < pd->pd_nlevels; n++) { 535 if (pd->pd_levels[n].pl_perf == level) { 536 return pd->pd_levels[n].pl_ifreq / 1000; 537 } 538 } 539 } 540 541 return 0; 542 } 543 544 static int 545 scmi_cpufreq_set_rate(struct scmi_softc *sc, struct scmi_perf_domain *pd, 546 u_int freq_mhz) 547 { 548 uint32_t perf_level = -1; 549 int32_t status; 550 ssize_t n; 551 552 for (n = 0; n < pd->pd_nlevels; n++) { 553 if (pd->pd_levels[n].pl_ifreq / 1000 == freq_mhz) { 554 perf_level = pd->pd_level_index_mode ? 555 n : pd->pd_levels[n].pl_perf; 556 break; 557 } 558 } 559 if (n == pd->pd_nlevels) 560 return EINVAL; 561 562 status = scmi_perf_level_set(pd, perf_level); 563 if (status != SCMI_SUCCESS) { 564 return EIO; 565 } 566 567 if (pd->pd_rate_limit > 0) 568 delay(pd->pd_rate_limit); 569 570 return 0; 571 } 572 573 static int 574 scmi_cpufreq_sysctl_helper(SYSCTLFN_ARGS) 575 { 576 struct scmi_perf_domain * const pd = rnode->sysctl_data; 577 struct scmi_softc * const sc = pd->pd_sc; 578 struct sysctlnode node; 579 u_int fq, oldfq = 0, old_target; 580 uint32_t level; 581 int32_t status; 582 int error; 583 584 node = *rnode; 585 node.sysctl_data = &fq; 586 587 if (rnode->sysctl_num == pd->pd_node_target) { 588 if (pd->pd_freq_target == 0) { 589 status = scmi_perf_level_get(pd, &level); 590 if (status != SCMI_SUCCESS) { 591 return EIO; 592 } 593 pd->pd_freq_target = 594 scmi_cpufreq_level_to_mhz(pd, level); 595 } 596 fq = pd->pd_freq_target; 597 } else { 598 status = scmi_perf_level_get(pd, &level); 599 if (status != SCMI_SUCCESS) { 600 return EIO; 601 } 602 fq = scmi_cpufreq_level_to_mhz(pd, level); 603 } 604 605 if (rnode->sysctl_num == pd->pd_node_target) 606 oldfq = fq; 607 608 if (pd->pd_freq_target == 0) 609 pd->pd_freq_target = fq; 610 611 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 612 if (error || newp == NULL) 613 return error; 614 615 if (fq == oldfq || rnode->sysctl_num != pd->pd_node_target) 616 return 0; 617 618 if (atomic_cas_uint(&pd->pd_busy, 0, 1) != 0) 619 return EBUSY; 620 621 old_target = pd->pd_freq_target; 622 pd->pd_freq_target = fq; 623 624 error = scmi_cpufreq_set_rate(sc, pd, fq); 625 if (error != 0) { 626 pd->pd_freq_target = old_target; 627 } 628 629 atomic_dec_uint(&pd->pd_busy); 630 631 return error; 632 } 633 634 static void 635 scmi_cpufreq_init_sysctl(struct scmi_softc *sc, uint32_t domain_id) 636 { 637 const struct sysctlnode *node, *cpunode; 638 struct scmi_perf_domain *pd = &sc->sc_perf_domains[domain_id]; 639 struct cpu_info *ci = pd->pd_ci; 640 struct sysctllog *cpufreq_log = NULL; 641 uint32_t max_level, min_level; 642 int32_t status; 643 int error, i; 644 645 if (ci == NULL) 646 return; 647 648 status = scmi_perf_limits_get(pd, &max_level, &min_level); 649 if (status != SCMI_SUCCESS) { 650 /* 651 * Not supposed to happen, but at least one implementation 652 * returns DENIED here. Assume that there are no limits. 653 */ 654 min_level = 0; 655 max_level = UINT32_MAX; 656 } 657 aprint_debug_dev(sc->sc_dev, "dom %u limits max %u min %u\n", 658 domain_id, max_level, min_level); 659 660 pd->pd_freq_available = kmem_zalloc(strlen("XXXX ") * 661 pd->pd_nlevels, KM_SLEEP); 662 for (i = 0; i < pd->pd_nlevels; i++) { 663 char buf[6]; 664 uint32_t level = pd->pd_level_index_mode ? 665 i : pd->pd_levels[i].pl_perf; 666 667 if (level < min_level) { 668 continue; 669 } else if (level > max_level) { 670 break; 671 } 672 673 snprintf(buf, sizeof(buf), i ? " %u" : "%u", 674 pd->pd_levels[i].pl_ifreq / 1000); 675 strcat(pd->pd_freq_available, buf); 676 if (level == pd->pd_sustained_perf) { 677 break; 678 } 679 } 680 681 error = sysctl_createv(&cpufreq_log, 0, NULL, &node, 682 CTLFLAG_PERMANENT, CTLTYPE_NODE, "machdep", NULL, 683 NULL, 0, NULL, 0, CTL_MACHDEP, CTL_EOL); 684 if (error) 685 goto sysctl_failed; 686 error = sysctl_createv(&cpufreq_log, 0, &node, &node, 687 0, CTLTYPE_NODE, "cpufreq", NULL, 688 NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL); 689 if (error) 690 goto sysctl_failed; 691 error = sysctl_createv(&cpufreq_log, 0, &node, &cpunode, 692 0, CTLTYPE_NODE, cpu_name(ci), NULL, 693 NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL); 694 if (error) 695 goto sysctl_failed; 696 697 error = sysctl_createv(&cpufreq_log, 0, &cpunode, &node, 698 CTLFLAG_READWRITE, CTLTYPE_INT, "target", NULL, 699 scmi_cpufreq_sysctl_helper, 0, (void *)pd, 0, 700 CTL_CREATE, CTL_EOL); 701 if (error) 702 goto sysctl_failed; 703 pd->pd_node_target = node->sysctl_num; 704 705 error = sysctl_createv(&cpufreq_log, 0, &cpunode, &node, 706 CTLFLAG_READWRITE, CTLTYPE_INT, "current", NULL, 707 scmi_cpufreq_sysctl_helper, 0, (void *)pd, 0, 708 CTL_CREATE, CTL_EOL); 709 if (error) 710 goto sysctl_failed; 711 pd->pd_node_current = node->sysctl_num; 712 713 error = sysctl_createv(&cpufreq_log, 0, &cpunode, &node, 714 0, CTLTYPE_STRING, "available", NULL, 715 NULL, 0, pd->pd_freq_available, 0, 716 CTL_CREATE, CTL_EOL); 717 if (error) 718 goto sysctl_failed; 719 pd->pd_node_available = node->sysctl_num; 720 721 return; 722 723 sysctl_failed: 724 aprint_error_dev(sc->sc_dev, "couldn't create sysctl nodes: %d\n", 725 error); 726 sysctl_teardown(&cpufreq_log); 727 } 728