Commit 7fc18f94 authored by Moon Yeounsu's avatar Moon Yeounsu Committed by Jakub Kicinski
Browse files

net: dlink: enable RMON MMIO access on supported devices



Enable memory-mapped I/O access to RMON statistics registers for devices
known to work correctly. Currently, only the D-Link DGE-550T (`0x4000`)
with PCI revision A3 (`0x0c`) is allowed.

To avoid issues on other hardware, a runtime check was added to restrict
MMIO usage. The `MEM_MAPPING` macro was removed in favor of runtime
detection.

To access RMON registers, the code `dw32(RmonStatMask, 0x0007ffff);`
must also be skipped, so this patch conditionally disables it as well.

Tested-on: D-Link DGE-550T Rev-A3
Signed-off-by: default avatarMoon Yeounsu <yyyynoom@gmail.com>
Link: https://patch.msgid.link/20250610000130.49065-2-yyyynoom@gmail.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 34355b67
Loading
Loading
Loading
Loading
+30 −27
Original line number Diff line number Diff line
@@ -99,6 +99,13 @@ static const struct net_device_ops netdev_ops = {
	.ndo_tx_timeout		= rio_tx_timeout,
};

static bool is_support_rmon_mmio(struct pci_dev *pdev)
{
	return pdev->vendor == PCI_VENDOR_ID_DLINK &&
	       pdev->device == 0x4000 &&
	       pdev->revision == 0x0c;
}

static int
rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
{
@@ -131,18 +138,22 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)

	np = netdev_priv(dev);

	if (is_support_rmon_mmio(pdev))
		np->rmon_enable = true;

	/* IO registers range. */
	ioaddr = pci_iomap(pdev, 0, 0);
	if (!ioaddr)
		goto err_out_dev;
	np->eeprom_addr = ioaddr;

#ifdef MEM_MAPPING
	if (np->rmon_enable) {
		/* MM registers range. */
		ioaddr = pci_iomap(pdev, 1, 0);
		if (!ioaddr)
			goto err_out_iounmap;
#endif
	}

	np->ioaddr = ioaddr;
	np->chip_id = chip_idx;
	np->pdev = pdev;
@@ -289,9 +300,8 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
	dma_free_coherent(&pdev->dev, TX_TOTAL_SIZE, np->tx_ring,
			  np->tx_ring_dma);
err_out_iounmap:
#ifdef MEM_MAPPING
	if (np->rmon_enable)
		pci_iounmap(pdev, np->ioaddr);
#endif
	pci_iounmap(pdev, np->eeprom_addr);
err_out_dev:
	free_netdev (dev);
@@ -578,6 +588,7 @@ static void rio_hw_init(struct net_device *dev)
	dw8(TxDMAPollPeriod, 0xff);
	dw8(RxDMABurstThresh, 0x30);
	dw8(RxDMAUrgentThresh, 0x30);
	if (!np->rmon_enable)
		dw32(RmonStatMask, 0x0007ffff);
	/* clear statistics */
	clear_stats (dev);
@@ -1076,9 +1087,6 @@ get_stats (struct net_device *dev)
{
	struct netdev_private *np = netdev_priv(dev);
	void __iomem *ioaddr = np->ioaddr;
#ifdef MEM_MAPPING
	int i;
#endif
	unsigned int stat_reg;
	unsigned long flags;

@@ -1123,10 +1131,10 @@ get_stats (struct net_device *dev)
	dr16(MacControlFramesXmtd);
	dr16(FramesWEXDeferal);

#ifdef MEM_MAPPING
	for (i = 0x100; i <= 0x150; i += 4)
	if (np->rmon_enable)
		for (int i = 0x100; i <= 0x150; i += 4)
			dr32(i);
#endif

	dr16(TxJumboFrames);
	dr16(RxJumboFrames);
	dr16(TCPCheckSumErrors);
@@ -1143,9 +1151,6 @@ clear_stats (struct net_device *dev)
{
	struct netdev_private *np = netdev_priv(dev);
	void __iomem *ioaddr = np->ioaddr;
#ifdef MEM_MAPPING
	int i;
#endif

	/* All statistics registers need to be acknowledged,
	   else statistic overflow could cause problems */
@@ -1181,10 +1186,9 @@ clear_stats (struct net_device *dev)
	dr16(BcstFramesXmtdOk);
	dr16(MacControlFramesXmtd);
	dr16(FramesWEXDeferal);
#ifdef MEM_MAPPING
	for (i = 0x100; i <= 0x150; i += 4)
	if (np->rmon_enable)
		for (int i = 0x100; i <= 0x150; i += 4)
			dr32(i);
#endif
	dr16(TxJumboFrames);
	dr16(RxJumboFrames);
	dr16(TCPCheckSumErrors);
@@ -1810,9 +1814,8 @@ rio_remove1 (struct pci_dev *pdev)
				  np->rx_ring_dma);
		dma_free_coherent(&pdev->dev, TX_TOTAL_SIZE, np->tx_ring,
				  np->tx_ring_dma);
#ifdef MEM_MAPPING
		if (np->rmon_enable)
			pci_iounmap(pdev, np->ioaddr);
#endif
		pci_iounmap(pdev, np->eeprom_addr);
		free_netdev (dev);
		pci_release_regions (pdev);
+2 −0
Original line number Diff line number Diff line
@@ -403,6 +403,8 @@ struct netdev_private {
	u16 negotiate;		/* Negotiated media */
	int phy_addr;		/* PHY addresses. */
	u16 led_mode;		/* LED mode read from EEPROM (IP1000A only) */

	bool rmon_enable;
};

/* The station address location in the EEPROM. */