
Esta questão vem de minhas tentativas de entender como um driver integrado platform device
é inicializado no momento da inicialização.
Estou usando uma distribuição Linux incorporada (Yocto) em um SoC (ARM + FPGA). O driver do dispositivo é escrito para a platform device
e o IP pode ser encontrado na árvore de dispositivos, descrito como dispositivo de plataforma. A propriedade "compatível" corresponde ao driver C, tudo bem até agora.
Citando a documentação do kernel para dispositivos de plataforma[1],
Geralmente é assumido que qualquer nó com uma propriedade 'compatível' representa algum tipo de dispositivo e, em segundo lugar, pode-se assumir que qualquer nó na raiz da árvore está diretamente conectado ao barramento do processador ou é um sistema diverso dispositivo que não pode ser descrito de outra forma.Para cada um desses nós, o Linux aloca e registra um platform_device, que por sua vez pode ser vinculado a um platform_driver.
mas também
2.4 População de dispositivos
Após a identificação da placa e a análise dos dados de configuração iniciais, a inicialização do kernel pode prosseguir normalmente. [...] É também quando os ganchos de configuração específicos da máquina serão chamados, como os ganchos machine_desc .init_early(), .init_irq() e .init_machine() no ARM.
[...]
O gancho mais interessante no contexto DT é .init_machine() que é o principal responsável por preencher o modelo de dispositivo Linux com dados sobre a plataforma
e eventualmente (seguindo o exemplo da documentação com a placa Tegra)
No momento .init_machine(), o código de suporte da placa Tegra precisará examinar este DT e decidir para quais nós criar platform_devices
E com certeza, olhando para arch/arm
[2] Posso encontrar a init_machine
função que "olha" na árvore de dispositivos. No entanto, esta função não existe para a arquitetura arm64. A machine_desc
estruturasó existe para arco de braço.
Navegando pelo código fonte consegui localizar algumas operações na árvore de dispositivos, nenhuma delas de fácil entendimento, acontecendo em setup_machine_fdt [4] que chama, early_dt_scan
mas elesnão parecem preencher os dispositivos:
/* Retrieve various information from the /chosen node */
rc = of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);
/* Initialize {size,address}-cells info */
of_scan_flat_dt(early_init_dt_scan_root, NULL);
/* Setup memory, calling early_init_dt_add_memory_arch */
of_scan_flat_dt(early_init_dt_scan_memory, NULL);
O problema aqui é que, se eu continuar seguindo o processo de inicialização, chego ao do_basic_setup
qual, por sua vez, chama driver init
, e bus_init
, platform_bus_init
eventualmente of_core_init
, .
Eu tinha algumas esperanças com o último, que cria um kset chamado "devicetree". No entanto, não entendo se a árvore é realmente analisada aqui.
Depois disso, os initcalls
são chamados, o que significa que a inicialização do driver acontecerá, mas onde estava envolvida a análise do DT aqui? Onde a propriedade “compatível” foi realmente usada? Novamente dos documentos:
O truque é que o kernel começa na raiz da árvore e procura nós que possuem uma propriedade 'compatível'. Primeiro, é geralmente assumido que qualquer nó com uma propriedade 'compatível' representa algum tipo de dispositivo e, segundo, pode ser assumido que qualquer nó na raiz da árvore está diretamente conectado ao barramento do processador ou é um dispositivo de sistema diverso que não pode ser descrito de outra forma. Para cada um desses nós,O Linux aloca e registra um platform_device, que por sua vez pode ser vinculado a um platform_drive.
A parte "vinculado ao drive da plataforma" é feita pelo initcall definido pelo código do driver, o que não entendo é o "aloca e registra um dispositivo da plataforma".
[1]Linux e a árvore de dispositivos