Thread (23 messages) 23 messages, 4 authors, 2024-08-04

Re: [PATCH net-next v15 12/14] net: stmmac: dwmac-loongson: Add Loongson Multi-channels GMAC support

From: si.yanteng@linux.dev
Date: 2024-08-04 15:16:32

2024年8月2日 01:09, "Serge Semin" [off-list ref] 写到:


On Mon, Jul 29, 2024 at 08:23:56PM +0800, Yanteng Si wrote:
quoted
The Loongson DWMAC driver currently supports the Loongson GMAC

 devices (based on the DW GMAC v3.50a/v3.73a IP-core) installed to the

 LS2K1000 SoC and LS7A1000 chipset. But recently a new generation

 LS2K2000 SoC was released with the new version of the Loongson GMAC

 synthesized in. The new controller is based on the DW GMAC v3.73a

 IP-core with the AV-feature enabled, which implies the multi

 DMA-channels support. The multi DMA-channels feature has the next

 vendor-specific peculiarities:

 

 1. Split up Tx and Rx DMA IRQ status/mask bits:

 Name Tx Rx

 DMA_INTR_ENA_NIE = 0x00040000 | 0x00020000;

 DMA_INTR_ENA_AIE = 0x00010000 | 0x00008000;

 DMA_STATUS_NIS = 0x00040000 | 0x00020000;

 DMA_STATUS_AIS = 0x00010000 | 0x00008000;

 DMA_STATUS_FBI = 0x00002000 | 0x00001000;

 2. Custom Synopsys ID hardwired into the GMAC_VERSION.SNPSVER register

 field. It's 0x10 while it should have been 0x37 in accordance with

 the actual DW GMAC IP-core version.

 3. There are eight DMA-channels available meanwhile the Synopsys DW

 GMAC IP-core supports up to three DMA-channels.

 4. It's possible to have each DMA-channel IRQ independently delivered.

 The MSI IRQs must be utilized for that.

 

 Thus in order to have the multi-channels Loongson GMAC controllers

 supported let's modify the Loongson DWMAC driver in accordance with

 all the peculiarities described above:

 

 1. Create the multi-channels Loongson GMAC-specific

 stmmac_dma_ops::dma_interrupt()

 stmmac_dma_ops::init_chan()

 callbacks due to the non-standard DMA IRQ CSR flags layout.

 2. Create the Loongson DWMAC-specific platform setup() method

 which gets to initialize the DMA-ops with the dwmac1000_dma_ops

 instance and overrides the callbacks described in 1. The method also

 overrides the custom Synopsys ID with the real one in order to have

 the rest of the HW-specific callbacks correctly detected by the driver

 core.

 3. Make sure the platform setup() method enables the flow control and

 duplex modes supported by the controller.

 

 Signed-off-by: Feiyang Chen [off-list ref]

 Signed-off-by: Yinggang Gu [off-list ref]

 Acked-by: Huacai Chen [off-list ref]

 Signed-off-by: Yanteng Si [off-list ref]

 [...]

 @@ -146,6 +450,7 @@ static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id

 struct plat_stmmacenet_data *plat;

 struct stmmac_pci_info *info;

 struct stmmac_resources res;

 + struct loongson_data *ld;

 int ret, i;

 

 plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL);

 @@ -162,6 +467,10 @@ static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id

 if (!plat->dma_cfg)

 return -ENOMEM;

 

 + ld = devm_kzalloc(&pdev->dev, sizeof(*ld), GFP_KERNEL);

 + if (!ld)

 + return -ENOMEM;

 +

 /* Enable pci device */

 ret = pci_enable_device(pdev);

 if (ret) {

 @@ -184,6 +493,10 @@ static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id

 memset(&res, 0, sizeof(res));

 res.addr = pcim_iomap_table(pdev)[0];

 

 + plat->bsp_priv = ld;

 + plat->setup = loongson_dwmac_setup;

 + ld->loongson_id = readl(res.addr + GMAC_VERSION) & 0xff;

 +

 info = (struct stmmac_pci_info *)id->driver_data;

 ret = info->setup(pdev, plat);

 if (ret)

 @@ -196,6 +509,10 @@ static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id

 if (ret)

 goto err_disable_device;

 

 + /* Use the common MAC IRQ if per-channel MSIs allocation failed */

 + if (ld->loongson_id == DWMAC_CORE_LS_MULTICHAN)

 + loongson_dwmac_msi_config(pdev, plat, &res);

 +

 ret = stmmac_dvr_probe(&pdev->dev, plat, &res);

 if (ret)

 goto err_plat_clear;

 @@ -205,6 +522,8 @@ static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id

 err_plat_clear:

 if (dev_of_node(&pdev->dev))

 loongson_dwmac_dt_clear(pdev, plat);

 + else if (ld->loongson_id == DWMAC_CORE_LS_MULTICHAN)

 + loongson_dwmac_msi_clear(pdev);
Why implementing "else if" here if the loongson_dwmac_msi_config() is

called for both DT and ACPI cases? AFAICS it should be just "if".
Yeah, you are right!
quoted
err_disable_device:

 pci_disable_device(pdev);

 return ret;

 @@ -217,8 +536,10 @@ static void loongson_dwmac_remove(struct pci_dev *pdev)

 {

 struct net_device *ndev = dev_get_drvdata(&pdev->dev);

 struct stmmac_priv *priv = netdev_priv(ndev);

 + struct loongson_data *ld;

 int i;

 

 + ld = priv->plat->bsp_priv;

 of_node_put(priv->plat->mdio_node);

 stmmac_dvr_remove(&pdev->dev);

 

 @@ -232,6 +553,9 @@ static void loongson_dwmac_remove(struct pci_dev *pdev)

 break;

 }

 

 + if (ld->loongson_id == DWMAC_CORE_LS_MULTICHAN)

 + loongson_dwmac_msi_clear(pdev);

 +
Please do this just below the 

 if (dev_of_node(&pdev->dev))

 loongson_dwmac_dt_clear(pdev, priv->plat);

chunk so the remove() method would look similar to the

cleanup-on-error path of the probe() method.
OK.

Thanks,
Yanteng
-Serge(y)
quoted
pci_disable_device(pdev);

 }

 

 -- 

 2.31.4
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help