Como testar Standard Hotplug Controller

1. Como testar Standard Hotplug Controller

Guilherme Giacomo Simoes
simoes_png

(usa elementary OS)

Enviado em 14/11/2024 - 15:51h

Contextualizando o problema
Eu sou um contribuidor iniciante do kernel linux.
Recentemente fiz uma alteracao nos drivers de shpc (standard hotplug controller), aonde eu substitui a funcao request_irq() pela funcao request_threaded_irq(). Isso foi uma sugestao de Lukas Wunner no commit a0d58937404f5.
Dessa forma, quando receber uma interrupcao com o numero de irq fornecido para a request_threaded_irq(), ele executa uma pequena parte no contexto de interrupcao, e a maior parte do processamento de hotplug e executado em uma thread separada. Entao e precisei criar duas funcoes, uma funcao com algumas regras basicas para lidar com a interrupcao no contexto de interrupcao, e uma outra funcao com o "resto" do codigo de hotplug para ser executada fora do contetxto de interrupcao, em uma thread.

Vou deixar aqui o diff completo da minha alteracao:

diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c
index 012b9e3fe5b0..b82d2bc4b777 100644
--- a/drivers/pci/hotplug/shpchp_hpc.c
+++ b/drivers/pci/hotplug/shpchp_hpc.c
@@ -166,6 +166,8 @@
#define SLOT_SERR_INT_MASK 0x3

static irqreturn_t shpc_isr(int irq, void *dev_id);
+static irqreturn_t shpc_ist(int irq, void *dev_id);
+
static void start_int_poll_timer(struct controller *ctrl, int sec);

static inline u8 shpc_readb(struct controller *ctrl, int reg)
@@ -746,7 +748,7 @@ int shpchp_set_bus_speed_mode(struct slot *slot, enum pci_bus_speed value)
return retval;
}

-static irqreturn_t shpc_isr(int irq, void *dev_id)
+static irqreturn_t shpc_ist(int irq, void *dev_id)
{
struct controller *ctrl = (struct controller *)dev_id;
u32 serr_int, slot_reg, intr_loc, intr_loc2;
@@ -825,6 +827,21 @@ static irqreturn_t shpc_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}

+static irqreturn_t shpc_isr(int irq, void *dev_id)
+{
+ pr_info("%s: isr for interrupt handler\n", __func__);
+
+ struct controller *ctrl = dev_id;
+ struct pci_dev *pdev = ctrl->pci_dev;
+
+ if (pdev->ignore_hotplug) {
+ pr_info("ignoring hotplug");
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_WAKE_THREAD;
+}
+
static int shpc_get_max_bus_speed(struct controller *ctrl)
{
int retval = 0;
@@ -1001,8 +1018,9 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev)
pci_set_master(pdev);
}

- rc = request_irq(ctrl->pci_dev->irq, shpc_isr, IRQF_SHARED,
- MY_NAME, (void *)ctrl);
+ rc = request_threaded_irq(ctrl->pci_dev->irq, shpc_isr, shpc_ist,
+ IRQF_SHARED, MY_NAME, (void *)ctrl);
+
ctrl_dbg(ctrl, "request_irq %d (returns %d)\n",
ctrl->pci_dev->irq, rc);
if (rc) {


Caso queira testar voce mesmo pode executar o
git apply <caminho-do-arquiv-com-o-diff> 
.

Bom, a minha dificuldade e de fato testar essa mudanca. Nao consigo achar uma forma de simular a conexao de um dispositivo que e compativel com shpc, e que consiga assumir o controle do hotplug de pci para entao, executar as funcoes passadas para o request_threaded_irq().

O que ja tentei
QEMU:
Estou acostumado a testar no qemu, e tambem na minha propria maquina. Estive pesquisando muito sobre dispositivos que sao compativeis com shpc no qemu, e o mais perto que cheguei de conseguir testar e com o pci-bridge passando o parametro shpc=on.
Comando completo usado para inicializar o kernel recem compilado no qemu com uma bridge shpc:
qemu-system-x86_64 -kernel arch/x86_64/boot/bzImage -append "root=/dev/sda1 console=ttyS0 earlyprintk=serial" -drive file=ubuntu.qcow2,format=qcow2 -m 1024 -enable-kvm -net nic -net user,hostfwd=tcp::2222-:22 -nographic -d int,cpu_reset -device pci-bridge,id=pci.1,chassis_nr=1,shpc=on 


, o kernel e iniciado normalmente, e o driver do shpc e iniciado. Porem, ele e interrompido, e nao "pega" o controle do hotplug porque ele e uma root bridge. E uma coisa obvia, ela somente e uma "ponte" para outras conexoes de PCI, nao e ela que deve ser responsavel por lidar com o hotplug dos dispositivos conectados a ela. Entao, aonde tem minha alteracao relacionada a request_threaded_irq() nem chega a ser executada. Pois a bridge n assumo o controle do hotplug de PCI.

Pesquisei muito e nao consegui achar outro dispositivo no qual eu consiga conectar e acionar o driver para o shpc.

QEMU + TELNET
Tentei iniciar o qemu com o comando anterior, mas sem a bridge, passando um "monitor" como parametro:
qemu-system-x86_64 -kernel arch/x86_64/boot/bzImage -append "root=/dev/sda1 console=ttyS0 earlyprintk=serial" -drive file=ubuntu.qcow2,format=qcow2 -m 1024 -enable-kvm -monitor telnet:127.0.0.1:5555,server,nowait -nographic 


E entao, conectei ao telnet
telnet localhost 


E tentei conectar uma bridge no telnet:
device_add pci-bridge,id=pci.1,chassis_nr=1,shpc=on 


Sem sucesso tambem, porque obviamente, ela e uma root bridge como mencionei anteriormente.

QEMU + TELNET + E1000 (e outros devices)
Tentei iniciar o qemu com a bridge e conectar via telent um device e1000:
qemu-system-x86_64 -kernel arch/x86_64/boot/bzImage -append "root=/dev/sda1 console=ttyS0 earlyprintk=serial" -drive file=ubuntu.qcow2,format=qcow2 -m 1024 -enable-kvm -monitor telnet:127.0.0.1:5555,server,nowait -nographic -device pci-bridge,id=pci.1,chassis_nr=1,shpc=on 

device_add e1000 id=net1,bus=pci.1 


Sem sucesso pq o e1000 nao e compativel com shpc.
Tentei tambem outros devicess que nao o e1000, mas nenhum alem da bridge sao compativeis com shpc.

TENTEI CONECTAR UMA BRIDGE EM UMA BRIDGE.
qemu-system-x86_64 -kernel arch/x86_64/boot/bzImage -append "root=/dev/sda1 console=ttyS0 earlyprintk=serial" -drive file=ubuntu.qcow2,format=qcow2 -m 1024 -enable-kvm -monitor telnet:127.0.0.1:5555,server,nowait -nographic -device pci-bridge,id=pci.1,chassis_nr=1,shpc=on 

device_add  pci-bridge,id=pci.2,bus=pci.1,shpc=on 


Sem sucesso pq a segunda bridge tambem e uma root bridge e nao pega o controle das irq's.

OUTRAS MAQUINAS VIRTUAL:
KVM + Libvirt + Virt-Manager : Resultado identico ao que tive no qemu

vmware e virtualbox: Nao tem muito suporte para simulacao de conexao pcie .

NA MINHA PROPRIA MAQUINA (Dell latitude e7450)
Nenhum PCIe era compativel com shpc


Arquivo .config
CONFIG_PCI=y
CONFIG_HOTPLUG_PCI=y
CONFIG_HOTPLUG_PCI_SHPC=y
# CONFIG_HOTPLUG_PCI_ACPI is not set
# CONFIG_HOTPLUG_PCI_CPCI is not set







  






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts