drivers/net/ethernet/natsemi/ns83820.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/natsemi/ns83820.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/natsemi/ns83820.c
Extension
.c
Size
61783 bytes
Lines
2266
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 netdev_ops = {
	.ndo_open		= ns83820_open,
	.ndo_stop		= ns83820_stop,
	.ndo_start_xmit		= ns83820_hard_start_xmit,
	.ndo_get_stats		= ns83820_get_stats,
	.ndo_set_rx_mode	= ns83820_set_multicast,
	.ndo_validate_addr	= eth_validate_addr,
	.ndo_set_mac_address	= eth_mac_addr,
	.ndo_tx_timeout		= ns83820_tx_timeout,
};

static int ns83820_init_one(struct pci_dev *pci_dev,
			    const struct pci_device_id *id)
{
	struct net_device *ndev;
	struct ns83820 *dev;
	long addr;
	int err;
	int using_dac = 0;

	/* See if we can set the dma mask early on; failure is fatal. */
	if (sizeof(dma_addr_t) == 8 &&
		!dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(64))) {
		using_dac = 1;
	} else if (!dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32))) {
		using_dac = 0;
	} else {
		dev_warn(&pci_dev->dev, "dma_set_mask failed!\n");
		return -ENODEV;
	}

	ndev = alloc_etherdev(sizeof(struct ns83820));
	err = -ENOMEM;
	if (!ndev)
		goto out;

	dev = PRIV(ndev);
	dev->ndev = ndev;

	spin_lock_init(&dev->rx_info.lock);
	spin_lock_init(&dev->tx_lock);
	spin_lock_init(&dev->misc_lock);
	dev->pci_dev = pci_dev;

	SET_NETDEV_DEV(ndev, &pci_dev->dev);

	INIT_WORK(&dev->tq_refill, queue_refill);
	tasklet_setup(&dev->rx_tasklet, rx_action);

	err = pci_enable_device(pci_dev);
	if (err) {
		dev_info(&pci_dev->dev, "pci_enable_dev failed: %d\n", err);
		goto out_free;
	}

	pci_set_master(pci_dev);
	addr = pci_resource_start(pci_dev, 1);
	dev->base = ioremap(addr, PAGE_SIZE);
	dev->tx_descs = dma_alloc_coherent(&pci_dev->dev,
					   4 * DESC_SIZE * NR_TX_DESC,
					   &dev->tx_phy_descs, GFP_KERNEL);
	dev->rx_info.descs = dma_alloc_coherent(&pci_dev->dev,
						4 * DESC_SIZE * NR_RX_DESC,
						&dev->rx_info.phy_descs, GFP_KERNEL);
	err = -ENOMEM;
	if (!dev->base || !dev->tx_descs || !dev->rx_info.descs)
		goto out_disable;

	dprintk("%p: %08lx  %p: %08lx\n",
		dev->tx_descs, (long)dev->tx_phy_descs,
		dev->rx_info.descs, (long)dev->rx_info.phy_descs);

	ns83820_disable_interrupts(dev);

	dev->IMR_cache = 0;

	err = request_irq(pci_dev->irq, ns83820_irq, IRQF_SHARED,
			  DRV_NAME, ndev);
	if (err) {
		dev_info(&pci_dev->dev, "unable to register irq %d, err %d\n",
			pci_dev->irq, err);
		goto out_disable;
	}

	/*
	 * FIXME: we are holding rtnl_lock() over obscenely long area only
	 * because some of the setup code uses dev->name.  It's Wrong(tm) -
	 * we should be using driver-specific names for all that stuff.
	 * For now that will do, but we really need to come back and kill
	 * most of the dev_alloc_name() users later.

Annotation

Implementation Notes