Implementación del código del proceso de enumeración PCIE: reimpreso para aprender a usarlo

En el proceso de depuración de PCIe, a menudo se presenta el problema de que el dispositivo EP del mismo nivel no se puede escanear.Durante el proceso de ubicación del problema, es importante comprender el proceso de enumeración de pcie en el kernel.

El proceso de enumeración de PCIe generalmente se divide en tres pasos:
1. Crear el nodo raíz
2. Escanear los dispositivos debajo del nodo raíz
3. Asignar recursos a los dispositivos debajo del nodo raíz

Entonces, ¿cómo descubrir el dispositivo?
Inicie el análisis desde la función pci_scan_child_bus del dispositivo pcie de exploración de bus

unsigned int pci_scan_child_bus (struct pci_bus * bus)
{ unsigned int devfn, pass, max = bus-> busn_res.start; struct pci_dev * dev;

dev_dbg(&bus->dev, "scanning bus\n");

/* Go find them, Rover! */
for (devfn = 0; devfn < 0x100; devfn += 8)
    pci_scan_slot(bus, devfn);

/* Reserve buses for SR-IOV capability. */
max += pci_iov_bus_range(bus);

/*
 * After performing arch-dependent fixup of the bus, look behind
 * all PCI-to-PCI bridges on this bus.
 */
if (!bus->is_added) {
    dev_dbg(&bus->dev, "fixups for bus\n");
    pcibios_fixup_bus(bus);
    bus->is_added = 1;
}

for (pass = 0; pass < 2; pass++)
    list_for_each_entry(dev, &bus->devices, bus_list) {
        if (pci_is_bridge(dev))
            max = pci_scan_bridge(bus, dev, max, pass);
    }

/*
 * Make sure a hotplug bridge has at least the minimum requested
 * number of buses.
 */
if (bus->self && bus->self->is_hotplug_bridge && pci_hotplug_bus_size) {
    if (max - bus->busn_res.start < pci_hotplug_bus_size - 1)
        max = bus->busn_res.start + pci_hotplug_bus_size - 1;
}

/*
 * We've scanned the bus and so we know all about what's on
 * the other side of any bridges that may be on this bus plus
 * any devices.
 *
 * Return how far we've got finding sub-buses.
 */
dev_dbg(&bus->dev, "bus scan returning with max=%02x\n", max);
return max;

}
EXPORT_SYMBOL_GPL (pci_scan_child_bus);

El código central de esta función es

para (devfn = 0; devfn <0x100; devfn + = 8)
pci_scan_slot (bus, devfn);

La variable de bus aquí proviene de pci_create_root_bus, que es el número de bus
devfn del bus raíz creado : número de dispositivo y función.
El método utilizado aquí es exhaustivo, pruebe todos los desarrolladores y funciones a la vez.

Función pci_scan_slot:

int pci_scan_slot (struct pci_bus * bus, int devfn)
{ unsigned fn, nr = 0; struct pci_dev * dev;

if (only_one_child(bus) && (devfn > 0))
    return 0; /* Already scanned the entire slot */

dev = pci_scan_single_device(bus, devfn);
if (!dev)
    return 0;
if (!dev->is_added)
    nr++;

for (fn = next_fn(bus, dev, 0); fn > 0; fn = next_fn(bus, dev, fn)) {
    dev = pci_scan_single_device(bus, devfn + fn);
    if (dev) {
        if (!dev->is_added)
            nr++;
        dev->multifunction = 1;
    }
}

/* only one slot has pcie device */
if (bus->self && nr)
    pcie_aspm_init_link_state(bus->self);

return nr;

}

pci_scan_single_device:

struct pci_dev * pci_scan_single_device (struct pci_bus * bus, int devfn)
{ struct pci_dev * dev;

dev = pci_get_slot(bus, devfn);
if (dev) {
    pci_dev_put(dev);
    return dev;
}

dev = pci_scan_device(bus, devfn);
if (!dev)
    return NULL;

pci_device_add(dev, bus);

return dev;

}

La función principal es pci_scan_device:

estructura estática pci_dev * pci_scan_device (struct pci_bus * bus, int devfn)
{ struct pci_dev * dev; u32 l;

if (!pci_bus_read_dev_vendor_id(bus, devfn, &l, 60*1000))
    return NULL;

dev = pci_alloc_dev(bus);
if (!dev)
    return NULL;

dev->devfn = devfn;
dev->vendor = l & 0xffff;
dev->device = (l >> 16) & 0xffff;

pci_set_of_node(dev);

if (pci_setup_device(dev)) {
    pci_bus_put(dev->bus);
    kfree(dev);
    return NULL;
}

return dev;

}

Las lecturas y escrituras de configuración de Venderid se realizan a intervalos en el ciclo while Como se puede ver en el código anterior, hay dos razones para salir del ciclo.

  1. configuración de configuración de lectura y escritura fallida (lo que indica que el enlace está bloqueado)
  2. No hay respuesta al tiempo de espera (el tiempo reservado es de 60 segundos, que ya es muy largo y es más probable que falle el primer punto)

Por lo tanto, cuando el dispositivo par no se puede escanear:
1. Confirme si el establecimiento del enlace es exitoso o no. Si el establecimiento del enlace falla, el par no debe ser escaneado
. 2. Confirme si el espacio de configuración del par se puede escribir (si el El módulo pcie del par está en estado no restablecido)
3. Confirme si los parámetros type0, type1, iatu y otros están configurados correctamente, si son correctos, confirme si el tamaño del espacio de direcciones al que accede la configuración es suficiente.
————————————————
Declaración de derechos de autor: este artículo es el artículo original del blogger de CSDN "Hober_yao" y sigue el acuerdo de derechos de autor CC 4.0 BY-SA. Adjunte la fuente original enlace y esta declaración para reimprimir.
Enlace original: https://blog.csdn.net/yhb1047818384/java/article/details/71076371

Supongo que te gusta

Origin blog.csdn.net/qq_33632004/article/details/105966445
Recomendado
Clasificación