简体   繁体   中英

How is the 'data' field provided by the device tree (for platform devce case)?

I can't understand how the device tree information is used in a specific driver.
This is a code snippet from linux-6.15.68 drivers/pci/controller/dwc/pcie-designware-plat.c.

static int dw_plat_pcie_probe(struct platform_device *pdev)
{
    struct device *dev = &pdev->dev;
    struct dw_plat_pcie *dw_plat_pcie;
    struct dw_pcie *pci;
    int ret;
    const struct of_device_id *match;
    const struct dw_plat_pcie_of_data *data;
    enum dw_pcie_device_mode mode;
    
    match = of_match_device(dw_plat_pcie_of_match, dev);
    if (!match) 
        return -EINVAL;

    data = (struct dw_plat_pcie_of_data *)match->data;
    mode = (enum dw_pcie_device_mode)data->mode;
    
    ... (skip)

    return 0;
}

static const struct dw_plat_pcie_of_data dw_plat_pcie_rc_of_data = {
    .mode = DW_PCIE_RC_TYPE,
};

static const struct dw_plat_pcie_of_data dw_plat_pcie_ep_of_data = {
    .mode = DW_PCIE_EP_TYPE,
};

static const struct of_device_id dw_plat_pcie_of_match[] = {
    {
        .compatible = "snps,dw-pcie",
        .data = &dw_plat_pcie_rc_of_data,
    },
    {
        .compatible = "snps,dw-pcie-ep",
        .data = &dw_plat_pcie_ep_of_data,
    },
    {},
};

So the kernel parses the device tree (connected to the struct dev) while running this probe function for a platform device. It compares the 'compatible' field of the device tree's node with the match data of this driver (=dw_plat_pcie_of_match) and extracts the of_device_id data from the device node of the device tree. Then, shouldn't the device tree have this 'data' field in the of_device_id information somewhere?

But this is an example device tree node with 'snps,dw-pcie-ep' in the compatible field (from arch/arm/boot/dts/uniphier-pro5.dtsi).

pcie_ep: pcie-ep@66000000 {
    compatible = "socionext,uniphier-pro5-pcie-ep",
             "snps,dw-pcie-ep";
    status = "disabled";
    reg-names = "dbi", "dbi2", "link", "addr_space";
    reg = <0x66000000 0x1000>, <0x66001000 0x1000>,
          <0x66010000 0x10000>, <0x67000000 0x400000>;
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_pcie>;
    clock-names = "gio", "link";
    clocks = <&sys_clk 12>, <&sys_clk 24>;
    reset-names = "gio", "link";
    resets = <&sys_rst 12>, <&sys_rst 24>;
    num-ib-windows = <16>;
    num-ob-windows = <16>;
    num-lanes = <4>;
    phy-names = "pcie-phy";
    phys = <&pcie_phy>;
};

It doesn't have any data field with specific 'RC' or 'EP' mode indication. Where is this 'data' field kept in the device tree??

It doesn't have any data field with specific 'RC' or 'EP' mode indication. Where is this 'data' field kept in the device tree??

The DT node doesn't have to supply such a "data" field because the " 'RC' or 'EP' mode indication " is already conveyed to the device driver using the compatible property.

In the driver, there is more than one acceptable compatible string (ie there is more than one struct of_device_id element). Each compatible string (specified by the .compatible =... ) in the driver is also associated with a data structure (specified by the .data =... ) that specifies attributes (ie the mode in question) of the particular device that has to be supported.

    static const struct of_device_id dw_plat_pcie_of_match[] = {
        {
            .compatible = "snps,dw-pcie",
            .data = &dw_plat_pcie_rc_of_data,
        },
        {
            .compatible = "snps,dw-pcie-ep",
            .data = &dw_plat_pcie_ep_of_data,
        },
        {},
    };

Since your DT node uses

    compatible = "socionext,uniphier-pro5-pcie-ep",
             "snps,dw-pcie-ep"; 

the second string in that property should be a match for the compatible string in the 2nd element of the dw_plat_pcie_of_match[] array.
So when execution returns from the

        match = of_match_device(dw_plat_pcie_of_match, dev);

match should be pointing to the following structure:

        {
            .compatible = "snps,dw-pcie-ep",
            .data = &dw_plat_pcie_ep_of_data,
        },

Then the assignment

        data = (struct dw_plat_pcie_of_data *)match->data;

will refer to

    static const struct dw_plat_pcie_of_data dw_plat_pcie_ep_of_data = {
        .mode = DW_PCIE_EP_TYPE,
    };

So the assignment

        mode = (enum dw_pcie_device_mode)data->mode;

will fetch the value DW_PCIE_EP_TYPE from that structure, and set the mode .


Associating a data structure with the compatible string allows a device driver to covertly support more than a single version of a device. The DT is relieved from having to specify (any and all) the distinguishing aspects of that particular version of the device. The DT node will only have properties that describe configurable or board-specific attributes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM