Por que a pm_runtime_barrier do Linux 6.19 ficou mais simples para quem escreve drivers

Refatoração em Linux 6.19 transforma pm_runtime_barrier() em uma verdadeira barrier de Runtime PM, simplificando drivers e eliminando retornos racy.

Escrito por
Emanuel Negromonte
Emanuel Negromonte é Jornalista, Mestre em Tecnologia da Informação e atualmente cursa a segunda graduação em Engenharia de Software. Com 14 anos de experiência escrevendo sobre...

Menos é mais no Linux 6.19. O subsistema de gerenciamento de energia passou por um pequeno, porém simbólico, API refactoring na função pm_runtime_barrier(). A mudança, integrada em 6.19-rc1 a partir da árvore de power management de Rafael Wysocki, com patches de Brian Norris, mira diretamente o dia a dia de quem escreve drivers: tornar o uso de Runtime PM mais claro, menos racy e menos verboso. Para quem acompanha a evolução da API, esta é a atualização em torno de Linux 6.19 pm_runtime_barrier que realmente importa.

O que exatamente mudou em pm_runtime_barrier()

A alteração é simples na superfície, mas importante em termos de design de API:

  • Antes: int pm_runtime_barrier(struct device *dev);
  • Agora: void pm_runtime_barrier(struct device *dev);

A documentação de Runtime PM foi atualizada para refletir essa nova assinatura: pm_runtime_barrier() continua sendo descrita como a função que verifica se há um pedido de resume pendente para o dispositivo, força esse resume de forma síncrona se necessário, cancela outras requisições de Runtime PM em fila e espera todas as operações em andamento terminarem. Em suma, ela atua como uma barrier de sincronização para o pipeline de Runtime PM de um struct device.

Em configurações sem suporte a PM (!CONFIG_PM), o stub em include/linux/pm_runtime.h também foi ajustado: em vez de retornar 0, agora é uma função void com corpo vazio, mantendo o comportamento de “no-op” esperado e evitando que builds sem PM quebrem ao compilar drivers atualizados.

O problema do valor de retorno racy

Historicamente, pm_runtime_barrier() retornava:

  • 1 se havia um pedido de resume pendente e o dispositivo precisava ser acordado,
  • 0 caso contrário.

Na prática, isso se mostrou problemático por pelo menos três motivos:

  1. Pouco uso real
    A maioria dos chamadores simplesmente ignorava o retorno. Nas poucas ocorrências onde o valor era testado, ele raramente influenciava uma decisão robusta de fluxo de controle.
  2. Semântica confusa
    A função é, conceitualmente, uma barrier de Runtime PM, não uma primitiva de consulta de estado. Misturar “sincronização” com “descobrir se houve resume” levava desenvolvedores a tratar pm_runtime_barrier() como se fosse um atalho para saber se o dispositivo está ativo, o que nunca foi um contrato formal da API.
  3. Retorno intrinsecamente racy
    Mesmo que o código checasse o retorno e assumisse “se foi 1, então o dispositivo está acordado agora”, essa suposição é frágil. Novas requisições de Runtime PM podem chegar imediatamente após a barreira; o estado de energia é dinâmico e pode mudar logo depois da chamada. Em outras palavras, o retorno nunca foi uma fonte estável de verdade sobre o estado do dispositivo, apenas um detalhe de implementação exposto demais.

Ao migrar para um void return type, o kernel reforça a intenção correta da função: pm_runtime_barrier() é usada para garantir que as operações de Runtime PM pendentes foram drenadas até aquele ponto, não para responder “o dispositivo está ativo?”.

Como usar pm_runtime_barrier() na prática

Para o desenvolvedor de driver, o novo contrato simplifica tanto o código quanto o modelo mental. Em vez de pensar em 0/1, basta tratar a função como uma barreira que “limpa a fila” de Runtime PM.

Alguns cenários típicos de uso:

  • Antes de acessar registradores sensíveis após atividade assíncrona
    Se o driver disparou operações de Runtime PM (por exemplo, por meio de pm_runtime_get() ou caminhos que podem agendar resumes assíncronos), chamar pm_runtime_barrier(dev) garante que qualquer resume pendente terminou antes de mexer no hardware de forma crítica.
  • Nos caminhos de .remove() ou .shutdown()
    Quando o driver está desmontando o dispositivo, desativando clocks ou reguladores manualmente, é prudente garantir que não existe nenhum resume atrasado prestes a rodar contra um hardware já parcialmente desmontado. A barreira serve justamente para “esvaziar” essa fila.
  • Em caminhos de erro durante a inicialização
    Se a inicialização do driver agenda operações de Runtime PM, mas falha e precisa abortar, chamar a barreira antes de liberar recursos evita que callbacks de PM rodem depois que o estado de software/hardware já foi revertido.

Na forma nova, o padrão típico fica mais direto:

/* Garantir que não há resume/suspend pendente antes de mexer no HW */
pm_runtime_barrier(dev);

/* A partir daqui, não há operações de Runtime PM em voo para este device */

Não há mais variável temporária, nem checagem de “erro” que nunca foi realmente um erro.

Impacto em drivers existentes e árvores out-of-tree

Para quem mantém drivers no mainline, as mudanças já chegaram junto com os patches de limpeza que removem checagens de retorno desnecessárias. Para quem mantém árvores out-of-tree, o recado é:

  • Atualizar assinatura e chamadas
    Ajustar as declarações/headers locais para a nova assinatura void pm_runtime_barrier(struct device *dev); e remover qualquer atribuição do retorno a variáveis.
  • Eliminar checagens inúteis de retorno
    Códigos como: int ret; ret = pm_runtime_barrier(dev); if (ret < 0) return ret; devem ser convertidos em uma simples chamada sem validação de retorno. pm_runtime_barrier() não representa uma operação que falha com códigos de erro.
  • Não recriar consultas de estado por conta própria
    Tentar substituir a antiga checagem 0/1 por leituras diretas de campos internos de dev->power ou por combinações de pm_runtime_status_*() para tentar derivar “se houve resume” é andar para trás. O patch justamente remove essa ambiguidade; se o driver precisa de uma decisão baseada no estado de energia, deve usar as primtivas próprias de consulta de estado, não a barreira.

Em resumo, a migração correta é: manter o uso da função como barrier de sincronização e abandonar qualquer lógica que trate o retorno como sinalizador de estado.

Testes, Coccinelle e limpeza da API como um todo

A mudança em pm_runtime_barrier() não veio sozinha. O ecossistema ao redor da API de Runtime PM foi ajustado para reforçar o novo contrato:

  • KUnit / runtime-test
    O teste de Runtime PM em drivers/base/power/runtime-test.c, adicionado no ciclo anterior, foi atualizado para parar de depender do valor de retorno da função. Em vez de verificar 0 ou 1, o teste passa a observar diretamente o comportamento do dispositivo (ativo, suspenso, transições bem-sucedidas) após a chamada da barreira.
  • Coccinelle / análise estática
    O script scripts/coccinelle/api/pm_runtime.cocci deixou de listar pm_runtime_barrier() entre as funções tratadas como retornando códigos relevantes. Isso evita que novos padrões orientem o desenvolvedor a armazenar e checar retornos inexistentes, e ajuda a “educar” o código para a nova forma de uso: chamar e seguir em frente.
  • Documentação atualizada
    O arquivo Documentation/power/runtime_pm.rst foi limpo para remover a menção ao retorno 1 quando um resume era necessário e 0 caso contrário. A descrição agora reforça apenas a semântica de barreira: verificar pendências, retomar o dispositivo se preciso, cancelar requisições restantes e aguardar todas as operações em andamento.

Com testes, documentação e ferramentas alinhados, a mudança deixa de ser apenas uma alteração de assinatura e passa a ser uma pequena, porém sólida, evolução de design da API de Runtime PM.

Menos é mais no Runtime PM do Linux 6.19

No fim das contas, a refatoração de pm_runtime_barrier() em Linux 6.19 é um caso clássico de “menos é mais” aplicado à API de power management. Remover um valor de retorno pouco útil e racy:

  • reduz ruído em drivers,
  • elimina checagens de erro que nunca foram erro,
  • reforça a leitura correta da função como uma barrier de sincronização de Runtime PM,
  • e alinha documentação, testes e ferramentas de análise estática ao mesmo contrato.

Para quem vive mergulhado em código de driver, é exatamente o tipo de micro-ajuste que faz o código ficar mais legível e previsível sem exigir uma reescrita massiva.

Compartilhe este artigo