Message ID | b13292f1bb64e335663d5929c81369da88fa2c13.1723014611.git.siyanteng@loongson.cn (mailing list archive) |
---|---|
State | Accepted |
Commit | 126f4f96c41d2efe9ea1b949ff3e6d997010991e |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | stmmac: Add Loongson platform support | expand |
On Wed, Aug 07, 2024 at 09:48:05PM +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. > > 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> > Acked-by: Huacai Chen <chenhuacai@loongson.cn> > Signed-off-by: Yanteng Si <siyanteng@loongson.cn> No more comments from my side. Thanks. Reviewed-by: Serge Semin <fancer.lancer@gmail.com> -Serge(y) > --- > .../ethernet/stmicro/stmmac/dwmac-loongson.c | 165 +++++++++++------- > 1 file changed, 102 insertions(+), 63 deletions(-) > > diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c > index 10b49bea8e3c..c0740a41025b 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,20 +70,85 @@ static struct stmmac_pci_info loongson_gmac_pci_info = { > .setup = loongson_gmac_data, > }; > > +static int loongson_dwmac_dt_config(struct pci_dev *pdev, > + struct plat_stmmacenet_data *plat, > + struct stmmac_resources *res) > +{ > + 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"); > + ret = -ENODEV; > + goto err_put_node; > + } > + > + 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; > + goto err_put_node; > + } > + > + ret = device_get_phy_mode(&pdev->dev); > + if (ret < 0) { > + dev_err(&pdev->dev, "phy_mode not found\n"); > + ret = -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); > +} > + > +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; > - struct device_node *np; > - int ret, i, phy_mode; > - > - np = dev_of_node(&pdev->dev); > - > - if (!np) { > - pr_info("dwmac_loongson_pci: No OF node\n"); > - return -ENODEV; > - } > + int ret, i; > > plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL); > if (!plat) > @@ -90,25 +160,19 @@ 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); > if (ret) { > dev_err(&pdev->dev, "%s: ERROR: failed to enable device\n", __func__); > - 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,59 +183,32 @@ 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) > - goto err_disable_device; > + goto err_plat_clear; > > - return ret; > + return 0; > > +err_plat_clear: > + if (dev_of_node(&pdev->dev)) > + loongson_dwmac_dt_clear(pdev, plat); > err_disable_device: > pci_disable_device(pdev); > -err_put_node: > - of_node_put(plat->mdio_node); > return ret; > } > > @@ -181,9 +218,11 @@ static void loongson_dwmac_remove(struct pci_dev *pdev) > struct stmmac_priv *priv = netdev_priv(ndev); > int i; > > - of_node_put(priv->plat->mdio_node); > stmmac_dvr_remove(&pdev->dev); > > + if (dev_of_node(&pdev->dev)) > + loongson_dwmac_dt_clear(pdev, priv->plat); > + > for (i = 0; i < PCI_STD_NUM_BARS; i++) { > if (pci_resource_len(pdev, i) == 0) > continue; > -- > 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..c0740a41025b 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,20 +70,85 @@ static struct stmmac_pci_info loongson_gmac_pci_info = { .setup = loongson_gmac_data, }; +static int loongson_dwmac_dt_config(struct pci_dev *pdev, + struct plat_stmmacenet_data *plat, + struct stmmac_resources *res) +{ + 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"); + ret = -ENODEV; + goto err_put_node; + } + + 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; + goto err_put_node; + } + + ret = device_get_phy_mode(&pdev->dev); + if (ret < 0) { + dev_err(&pdev->dev, "phy_mode not found\n"); + ret = -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); +} + +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; - struct device_node *np; - int ret, i, phy_mode; - - np = dev_of_node(&pdev->dev); - - if (!np) { - pr_info("dwmac_loongson_pci: No OF node\n"); - return -ENODEV; - } + int ret, i; plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL); if (!plat) @@ -90,25 +160,19 @@ 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); if (ret) { dev_err(&pdev->dev, "%s: ERROR: failed to enable device\n", __func__); - 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,59 +183,32 @@ 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) - goto err_disable_device; + goto err_plat_clear; - return ret; + return 0; +err_plat_clear: + if (dev_of_node(&pdev->dev)) + loongson_dwmac_dt_clear(pdev, plat); err_disable_device: pci_disable_device(pdev); -err_put_node: - of_node_put(plat->mdio_node); return ret; } @@ -181,9 +218,11 @@ static void loongson_dwmac_remove(struct pci_dev *pdev) struct stmmac_priv *priv = netdev_priv(ndev); int i; - of_node_put(priv->plat->mdio_node); stmmac_dvr_remove(&pdev->dev); + if (dev_of_node(&pdev->dev)) + loongson_dwmac_dt_clear(pdev, priv->plat); + for (i = 0; i < PCI_STD_NUM_BARS; i++) { if (pci_resource_len(pdev, i) == 0) continue;