drivers/net/ethernet/smsc/smsc9420.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/smsc/smsc9420.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/smsc/smsc9420.c
Extension
.c
Size
42417 bytes
Lines
1671
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

static const struct net_device_ops smsc9420_netdev_ops = {
	.ndo_open		= smsc9420_open,
	.ndo_stop		= smsc9420_stop,
	.ndo_start_xmit		= smsc9420_hard_start_xmit,
	.ndo_get_stats		= smsc9420_get_stats,
	.ndo_set_rx_mode	= smsc9420_set_multicast_list,
	.ndo_eth_ioctl		= phy_do_ioctl_running,
	.ndo_validate_addr	= eth_validate_addr,
	.ndo_set_mac_address 	= eth_mac_addr,
#ifdef CONFIG_NET_POLL_CONTROLLER
	.ndo_poll_controller	= smsc9420_poll_controller,
#endif /* CONFIG_NET_POLL_CONTROLLER */
};

static int
smsc9420_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
	struct net_device *dev;
	struct smsc9420_pdata *pd;
	void __iomem *virt_addr;
	int result = 0;
	u32 id_rev;

	pr_info("%s version %s\n", DRV_DESCRIPTION, DRV_VERSION);

	/* First do the PCI initialisation */
	result = pci_enable_device(pdev);
	if (unlikely(result)) {
		pr_err("Cannot enable smsc9420\n");
		goto out_0;
	}

	pci_set_master(pdev);

	dev = alloc_etherdev(sizeof(*pd));
	if (!dev)
		goto out_disable_pci_device_1;

	SET_NETDEV_DEV(dev, &pdev->dev);

	if (!(pci_resource_flags(pdev, SMSC_BAR) & IORESOURCE_MEM)) {
		netdev_err(dev, "Cannot find PCI device base address\n");
		goto out_free_netdev_2;
	}

	if ((pci_request_regions(pdev, DRV_NAME))) {
		netdev_err(dev, "Cannot obtain PCI resources, aborting\n");
		goto out_free_netdev_2;
	}

	if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) {
		netdev_err(dev, "No usable DMA configuration, aborting\n");
		goto out_free_regions_3;
	}

	virt_addr = ioremap(pci_resource_start(pdev, SMSC_BAR),
		pci_resource_len(pdev, SMSC_BAR));
	if (!virt_addr) {
		netdev_err(dev, "Cannot map device registers, aborting\n");
		goto out_free_regions_3;
	}

	/* registers are double mapped with 0 offset for LE and 0x200 for BE */
	virt_addr += LAN9420_CPSR_ENDIAN_OFFSET;

	pd = netdev_priv(dev);

	/* pci descriptors are created in the PCI consistent area */
	pd->rx_ring = dma_alloc_coherent(&pdev->dev,
		sizeof(struct smsc9420_dma_desc) * (RX_RING_SIZE + TX_RING_SIZE),
		&pd->rx_dma_addr, GFP_KERNEL);

	if (!pd->rx_ring)
		goto out_free_io_4;

	/* descriptors are aligned due to the nature of dma_alloc_coherent */
	pd->tx_ring = (pd->rx_ring + RX_RING_SIZE);
	pd->tx_dma_addr = pd->rx_dma_addr +
	    sizeof(struct smsc9420_dma_desc) * RX_RING_SIZE;

	pd->pdev = pdev;
	pd->dev = dev;
	pd->ioaddr = virt_addr;
	pd->msg_enable = smsc_debug;
	pd->rx_csum = true;

	netif_dbg(pd, probe, pd->dev, "lan_base=0x%08lx\n", (ulong)virt_addr);

	id_rev = smsc9420_reg_read(pd, ID_REV);
	switch (id_rev & 0xFFFF0000) {

Annotation

Implementation Notes