drivers/net/ethernet/natsemi/sonic.c

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

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/natsemi/sonic.c
Extension
.c
Size
24552 bytes
Lines
856
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source 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

if (skb == NULL) {
			while(i > 0) { /* free any that were allocated successfully */
				i--;
				dev_kfree_skb(lp->rx_skb[i]);
				lp->rx_skb[i] = NULL;
			}
			printk(KERN_ERR "%s: couldn't allocate receive buffers\n",
			       dev->name);
			return -ENOMEM;
		}
		/* align IP header unless DMA requires otherwise */
		if (SONIC_BUS_SCALE(lp->dma_bitmode) == 2)
			skb_reserve(skb, 2);
		lp->rx_skb[i] = skb;
	}

	for (i = 0; i < SONIC_NUM_RRS; i++) {
		dma_addr_t laddr = dma_map_single(lp->device, skb_put(lp->rx_skb[i], SONIC_RBSIZE),
		                                  SONIC_RBSIZE, DMA_FROM_DEVICE);
		if (dma_mapping_error(lp->device, laddr)) {
			while(i > 0) { /* free any that were mapped successfully */
				i--;
				dma_unmap_single(lp->device, lp->rx_laddr[i], SONIC_RBSIZE, DMA_FROM_DEVICE);
				lp->rx_laddr[i] = (dma_addr_t)0;
			}
			for (i = 0; i < SONIC_NUM_RRS; i++) {
				dev_kfree_skb(lp->rx_skb[i]);
				lp->rx_skb[i] = NULL;
			}
			printk(KERN_ERR "%s: couldn't map rx DMA buffers\n",
			       dev->name);
			return -ENOMEM;
		}
		lp->rx_laddr[i] = laddr;
	}

	/*
	 * Initialize the SONIC
	 */
	sonic_init(dev, true);

	netif_start_queue(dev);

	netif_dbg(lp, ifup, dev, "%s: Initialization done\n", __func__);

	return 0;
}

/* Wait for the SONIC to become idle. */
static void sonic_quiesce(struct net_device *dev, u16 mask, bool may_sleep)
{
	struct sonic_local * __maybe_unused lp = netdev_priv(dev);
	int i;
	u16 bits;

	for (i = 0; i < 1000; ++i) {
		bits = SONIC_READ(SONIC_CMD) & mask;
		if (!bits)
			return;
		if (!may_sleep)
			udelay(20);
		else
			usleep_range(100, 200);
	}
	WARN_ONCE(1, "command deadline expired! 0x%04x\n", bits);
}

/*
 * Close the SONIC device
 */
static int sonic_close(struct net_device *dev)
{
	struct sonic_local *lp = netdev_priv(dev);
	int i;

	netif_dbg(lp, ifdown, dev, "%s\n", __func__);

	netif_stop_queue(dev);

	/*
	 * stop the SONIC, disable interrupts
	 */
	SONIC_WRITE(SONIC_CMD, SONIC_CR_RXDIS);
	sonic_quiesce(dev, SONIC_CR_ALL, true);

	SONIC_WRITE(SONIC_IMR, 0);
	SONIC_WRITE(SONIC_ISR, 0x7fff);
	SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);

	/* unmap and free skbs that haven't been transmitted */

Annotation

Implementation Notes