Message ID | c558c9ff8e5a8a3657c1e60d6dfc4fa3a121ae93.1720512634.git.siyanteng@loongson.cn (mailing list archive) |
---|---|
State | Superseded |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | stmmac: Add Loongson platform support | expand |
On Tue, Jul 09, 2024 at 05:37:04PM +0800, Yanteng Si wrote: > The Loongson GMAC driver currently supports the network controllers > installed on the LS2K1000 SoC and LS7A1000 chipset, for which the GMAC > devices are required to be defined in the platform device tree source. > But Loongson machines may have UEFI (implies ACPI) or PMON/UBOOT > (implies FDT) as the system bootloaders. In order to have both system > configurations support let's extend the driver functionality with the > case of having the Loongson GMAC probed on the PCI bus with no device > tree node defined for it. That requires to make the device DT-node > optional, to rely on the IRQ line detected by the PCI core and to > have the MDIO bus ID calculated using the PCIe Domain+BDF numbers. Let's extend the log with an additional note: "In order to have the device probe() and remove() methods less complicated let's move the DT- and ACPI-specific code to the respective sub-functions." > > Signed-off-by: Feiyang Chen <chenfeiyang@loongson.cn> > Signed-off-by: Yinggang Gu <guyinggang@loongson.cn> > Signed-off-by: Yanteng Si <siyanteng@loongson.cn> > --- > .../ethernet/stmicro/stmmac/dwmac-loongson.c | 136 ++++++++++-------- > 1 file changed, 79 insertions(+), 57 deletions(-) > > diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c > index 10b49bea8e3c..b4704068321f 100644 > --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c > +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c > @@ -12,11 +12,15 @@ > #define PCI_DEVICE_ID_LOONGSON_GMAC 0x7a03 > > struct stmmac_pci_info { > - int (*setup)(struct plat_stmmacenet_data *plat); > + int (*setup)(struct pci_dev *pdev, struct plat_stmmacenet_data *plat); > }; > > -static void loongson_default_data(struct plat_stmmacenet_data *plat) > +static void loongson_default_data(struct pci_dev *pdev, > + struct plat_stmmacenet_data *plat) > { > + /* Get bus_id, this can be overwritten later */ > + plat->bus_id = pci_dev_id(pdev); > + > plat->clk_csr = 2; /* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */ > plat->has_gmac = 1; > plat->force_sf_dma_mode = 1; > @@ -49,9 +53,10 @@ static void loongson_default_data(struct plat_stmmacenet_data *plat) > plat->dma_cfg->pblx8 = true; > } > > -static int loongson_gmac_data(struct plat_stmmacenet_data *plat) > +static int loongson_gmac_data(struct pci_dev *pdev, > + struct plat_stmmacenet_data *plat) > { > - loongson_default_data(plat); > + loongson_default_data(pdev, plat); > > plat->tx_queues_to_use = 1; > plat->rx_queues_to_use = 1; > @@ -65,21 +70,72 @@ static struct stmmac_pci_info loongson_gmac_pci_info = { > .setup = loongson_gmac_data, > }; > > -static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id *id) > +static int loongson_dwmac_dt_config(struct pci_dev *pdev, > + struct plat_stmmacenet_data *plat, > + struct stmmac_resources *res) > { > - struct plat_stmmacenet_data *plat; > - struct stmmac_pci_info *info; > - struct stmmac_resources res; > - struct device_node *np; > - int ret, i, phy_mode; > + struct device_node *np = dev_of_node(&pdev->dev); > + int ret; > + > + plat->mdio_node = of_get_child_by_name(np, "mdio"); > + if (plat->mdio_node) { > + dev_info(&pdev->dev, "Found MDIO subnode\n"); > + plat->mdio_bus_data->needs_reset = true; > + } This needs to be reverted in case if the following up code fails. So ... > + > + ret = of_alias_get_id(np, "ethernet"); > + if (ret >= 0) > + plat->bus_id = ret; > + > + res->irq = of_irq_get_byname(np, "macirq"); > + if (res->irq < 0) { > + dev_err(&pdev->dev, "IRQ macirq not found\n"); > + return -ENODEV; ret = -ENODEV; goto err_put_node; > + } > > - np = dev_of_node(&pdev->dev); > + res->wol_irq = of_irq_get_byname(np, "eth_wake_irq"); > + if (res->wol_irq < 0) { > + dev_info(&pdev->dev, > + "IRQ eth_wake_irq not found, using macirq\n"); > + res->wol_irq = res->irq; > + } > > - if (!np) { > - pr_info("dwmac_loongson_pci: No OF node\n"); > + res->lpi_irq = of_irq_get_byname(np, "eth_lpi"); > + if (res->lpi_irq < 0) { > + dev_err(&pdev->dev, "IRQ eth_lpi not found\n"); > return -ENODEV; err = -ENODEV; goto err_put_node; > } > > + ret = device_get_phy_mode(&pdev->dev); > + if (ret < 0) { > + dev_err(&pdev->dev, "phy_mode not found\n"); > + return -ENODEV; goto err_put_node; > + } > + > + plat->phy_interface = ret; > + > + return 0; err_put_node: of_node_put(plat->mdio_node); return ret; > +} static void loongson_dwmac_dt_clear(struct pci_dev *pdev, struct plat_stmmacenet_data *plat) { of_node_put(plat->mdio_node); } and ... > + > +static int loongson_dwmac_acpi_config(struct pci_dev *pdev, > + struct plat_stmmacenet_data *plat, > + struct stmmac_resources *res) > +{ > + if (!pdev->irq) > + return -EINVAL; > + > + res->irq = pdev->irq; > + > + return 0; > +} > + > +static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id *id) > +{ > + struct plat_stmmacenet_data *plat; > + struct stmmac_pci_info *info; > + struct stmmac_resources res; > + int ret, i; > + > plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL); > if (!plat) > return -ENOMEM; > @@ -90,17 +146,9 @@ static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id > if (!plat->mdio_bus_data) > return -ENOMEM; > > - plat->mdio_node = of_get_child_by_name(np, "mdio"); > - if (plat->mdio_node) { > - dev_info(&pdev->dev, "Found MDIO subnode\n"); > - plat->mdio_bus_data->needs_reset = true; > - } > - > plat->dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*plat->dma_cfg), GFP_KERNEL); > - if (!plat->dma_cfg) { > - ret = -ENOMEM; > - goto err_put_node; > - } > + if (!plat->dma_cfg) > + return -ENOMEM; > > /* Enable pci device */ > ret = pci_enable_device(pdev); > @@ -109,6 +157,8 @@ static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id > goto err_put_node; return ret; > } > > + pci_set_master(pdev); > + > /* Get the base address of device */ > for (i = 0; i < PCI_STD_NUM_BARS; i++) { > if (pci_resource_len(pdev, i) == 0) > @@ -119,48 +169,20 @@ static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id > break; > } > > - plat->bus_id = of_alias_get_id(np, "ethernet"); > - if (plat->bus_id < 0) > - plat->bus_id = pci_dev_id(pdev); > - > - phy_mode = device_get_phy_mode(&pdev->dev); > - if (phy_mode < 0) { > - dev_err(&pdev->dev, "phy_mode not found\n"); > - ret = phy_mode; > - goto err_disable_device; > - } > - > - plat->phy_interface = phy_mode; > - > - pci_set_master(pdev); > - > memset(&res, 0, sizeof(res)); > res.addr = pcim_iomap_table(pdev)[0]; > > info = (struct stmmac_pci_info *)id->driver_data; > - ret = info->setup(plat); > + ret = info->setup(pdev, plat); > if (ret) > goto err_disable_device; > > - res.irq = of_irq_get_byname(np, "macirq"); > - if (res.irq < 0) { > - dev_err(&pdev->dev, "IRQ macirq not found\n"); > - ret = -ENODEV; > - goto err_disable_device; > - } > - > - res.wol_irq = of_irq_get_byname(np, "eth_wake_irq"); > - if (res.wol_irq < 0) { > - dev_info(&pdev->dev, "IRQ eth_wake_irq not found, using macirq\n"); > - res.wol_irq = res.irq; > - } > - > - res.lpi_irq = of_irq_get_byname(np, "eth_lpi"); > - if (res.lpi_irq < 0) { > - dev_err(&pdev->dev, "IRQ eth_lpi not found\n"); > - ret = -ENODEV; > + if (dev_of_node(&pdev->dev)) > + ret = loongson_dwmac_dt_config(pdev, plat, &res); > + else > + ret = loongson_dwmac_acpi_config(pdev, plat, &res); > + if (ret) > goto err_disable_device; > - } > > ret = stmmac_dvr_probe(&pdev->dev, plat, &res); > if (ret) ... make sure loongson_dwmac_dt_clear() is called in the cleanup-on-error path: ret = stmmac_dvr_probe(&pdev->dev, plat, &res); if (ret) goto err_plat_clear; return 0; err_plat_clear: if (dev_of_node(&pdev->dev)) loongson_dwmac_dt_clear(pdev, plat); err_disable_device: pci_disable_device(pdev); return ret; ... and in the loongson_dwmac_remove() method: static void loongson_dwmac_remove(struct pci_dev *pdev) { ... stmmac_dvr_remove(&pdev->dev); if (dev_of_node(&pdev->dev)) loongson_dwmac_dt_clear(pdev, priv->plat); ... } -Serge(y) > -- > 2.31.4 >
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c index 10b49bea8e3c..b4704068321f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c @@ -12,11 +12,15 @@ #define PCI_DEVICE_ID_LOONGSON_GMAC 0x7a03 struct stmmac_pci_info { - int (*setup)(struct plat_stmmacenet_data *plat); + int (*setup)(struct pci_dev *pdev, struct plat_stmmacenet_data *plat); }; -static void loongson_default_data(struct plat_stmmacenet_data *plat) +static void loongson_default_data(struct pci_dev *pdev, + struct plat_stmmacenet_data *plat) { + /* Get bus_id, this can be overwritten later */ + plat->bus_id = pci_dev_id(pdev); + plat->clk_csr = 2; /* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */ plat->has_gmac = 1; plat->force_sf_dma_mode = 1; @@ -49,9 +53,10 @@ static void loongson_default_data(struct plat_stmmacenet_data *plat) plat->dma_cfg->pblx8 = true; } -static int loongson_gmac_data(struct plat_stmmacenet_data *plat) +static int loongson_gmac_data(struct pci_dev *pdev, + struct plat_stmmacenet_data *plat) { - loongson_default_data(plat); + loongson_default_data(pdev, plat); plat->tx_queues_to_use = 1; plat->rx_queues_to_use = 1; @@ -65,21 +70,72 @@ static struct stmmac_pci_info loongson_gmac_pci_info = { .setup = loongson_gmac_data, }; -static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id *id) +static int loongson_dwmac_dt_config(struct pci_dev *pdev, + struct plat_stmmacenet_data *plat, + struct stmmac_resources *res) { - struct plat_stmmacenet_data *plat; - struct stmmac_pci_info *info; - struct stmmac_resources res; - struct device_node *np; - int ret, i, phy_mode; + struct device_node *np = dev_of_node(&pdev->dev); + int ret; + + plat->mdio_node = of_get_child_by_name(np, "mdio"); + if (plat->mdio_node) { + dev_info(&pdev->dev, "Found MDIO subnode\n"); + plat->mdio_bus_data->needs_reset = true; + } + + ret = of_alias_get_id(np, "ethernet"); + if (ret >= 0) + plat->bus_id = ret; + + res->irq = of_irq_get_byname(np, "macirq"); + if (res->irq < 0) { + dev_err(&pdev->dev, "IRQ macirq not found\n"); + return -ENODEV; + } - np = dev_of_node(&pdev->dev); + res->wol_irq = of_irq_get_byname(np, "eth_wake_irq"); + if (res->wol_irq < 0) { + dev_info(&pdev->dev, + "IRQ eth_wake_irq not found, using macirq\n"); + res->wol_irq = res->irq; + } - if (!np) { - pr_info("dwmac_loongson_pci: No OF node\n"); + res->lpi_irq = of_irq_get_byname(np, "eth_lpi"); + if (res->lpi_irq < 0) { + dev_err(&pdev->dev, "IRQ eth_lpi not found\n"); return -ENODEV; } + ret = device_get_phy_mode(&pdev->dev); + if (ret < 0) { + dev_err(&pdev->dev, "phy_mode not found\n"); + return -ENODEV; + } + + plat->phy_interface = ret; + + return 0; +} + +static int loongson_dwmac_acpi_config(struct pci_dev *pdev, + struct plat_stmmacenet_data *plat, + struct stmmac_resources *res) +{ + if (!pdev->irq) + return -EINVAL; + + res->irq = pdev->irq; + + return 0; +} + +static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct plat_stmmacenet_data *plat; + struct stmmac_pci_info *info; + struct stmmac_resources res; + int ret, i; + plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL); if (!plat) return -ENOMEM; @@ -90,17 +146,9 @@ static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id if (!plat->mdio_bus_data) return -ENOMEM; - plat->mdio_node = of_get_child_by_name(np, "mdio"); - if (plat->mdio_node) { - dev_info(&pdev->dev, "Found MDIO subnode\n"); - plat->mdio_bus_data->needs_reset = true; - } - plat->dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*plat->dma_cfg), GFP_KERNEL); - if (!plat->dma_cfg) { - ret = -ENOMEM; - goto err_put_node; - } + if (!plat->dma_cfg) + return -ENOMEM; /* Enable pci device */ ret = pci_enable_device(pdev); @@ -109,6 +157,8 @@ static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id goto err_put_node; } + pci_set_master(pdev); + /* Get the base address of device */ for (i = 0; i < PCI_STD_NUM_BARS; i++) { if (pci_resource_len(pdev, i) == 0) @@ -119,48 +169,20 @@ static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id break; } - plat->bus_id = of_alias_get_id(np, "ethernet"); - if (plat->bus_id < 0) - plat->bus_id = pci_dev_id(pdev); - - phy_mode = device_get_phy_mode(&pdev->dev); - if (phy_mode < 0) { - dev_err(&pdev->dev, "phy_mode not found\n"); - ret = phy_mode; - goto err_disable_device; - } - - plat->phy_interface = phy_mode; - - pci_set_master(pdev); - memset(&res, 0, sizeof(res)); res.addr = pcim_iomap_table(pdev)[0]; info = (struct stmmac_pci_info *)id->driver_data; - ret = info->setup(plat); + ret = info->setup(pdev, plat); if (ret) goto err_disable_device; - res.irq = of_irq_get_byname(np, "macirq"); - if (res.irq < 0) { - dev_err(&pdev->dev, "IRQ macirq not found\n"); - ret = -ENODEV; - goto err_disable_device; - } - - res.wol_irq = of_irq_get_byname(np, "eth_wake_irq"); - if (res.wol_irq < 0) { - dev_info(&pdev->dev, "IRQ eth_wake_irq not found, using macirq\n"); - res.wol_irq = res.irq; - } - - res.lpi_irq = of_irq_get_byname(np, "eth_lpi"); - if (res.lpi_irq < 0) { - dev_err(&pdev->dev, "IRQ eth_lpi not found\n"); - ret = -ENODEV; + if (dev_of_node(&pdev->dev)) + ret = loongson_dwmac_dt_config(pdev, plat, &res); + else + ret = loongson_dwmac_acpi_config(pdev, plat, &res); + if (ret) goto err_disable_device; - } ret = stmmac_dvr_probe(&pdev->dev, plat, &res); if (ret)