drivers/net/ethernet/cortina/gemini.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/cortina/gemini.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/cortina/gemini.c
Extension
.c
Size
72523 bytes
Lines
2709
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 gmac_351x_ops = {
	.ndo_init		= gmac_init,
	.ndo_open		= gmac_open,
	.ndo_stop		= gmac_stop,
	.ndo_start_xmit		= gmac_start_xmit,
	.ndo_tx_timeout		= gmac_tx_timeout,
	.ndo_set_rx_mode	= gmac_set_rx_mode,
	.ndo_set_mac_address	= gmac_set_mac_address,
	.ndo_get_stats64	= gmac_get_stats64,
	.ndo_change_mtu		= gmac_change_mtu,
	.ndo_set_features	= gmac_set_features,
};

static const struct ethtool_ops gmac_351x_ethtool_ops = {
	.supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS |
				     ETHTOOL_COALESCE_MAX_FRAMES,
	.get_sset_count	= gmac_get_sset_count,
	.get_strings	= gmac_get_strings,
	.get_ethtool_stats = gmac_get_ethtool_stats,
	.get_link	= ethtool_op_get_link,
	.get_link_ksettings = gmac_get_ksettings,
	.set_link_ksettings = gmac_set_ksettings,
	.nway_reset	= gmac_nway_reset,
	.get_pauseparam	= gmac_get_pauseparam,
	.set_pauseparam = gmac_set_pauseparam,
	.get_ringparam	= gmac_get_ringparam,
	.set_ringparam	= gmac_set_ringparam,
	.get_coalesce	= gmac_get_coalesce,
	.set_coalesce	= gmac_set_coalesce,
	.get_msglevel	= gmac_get_msglevel,
	.set_msglevel	= gmac_set_msglevel,
	.get_drvinfo	= gmac_get_drvinfo,
};

static irqreturn_t gemini_port_irq_thread(int irq, void *data)
{
	unsigned long irqmask = SWFQ_EMPTY_INT_BIT;
	struct gemini_ethernet_port *port = data;
	struct gemini_ethernet *geth;
	unsigned long flags;

	geth = port->geth;
	/* The queue is half empty so refill it */
	geth_fill_freeq(geth, true);

	spin_lock_irqsave(&geth->irq_lock, flags);
	/* ACK queue interrupt */
	writel(irqmask, geth->base + GLOBAL_INTERRUPT_STATUS_4_REG);
	/* Enable queue interrupt again */
	irqmask |= readl(geth->base + GLOBAL_INTERRUPT_ENABLE_4_REG);
	writel(irqmask, geth->base + GLOBAL_INTERRUPT_ENABLE_4_REG);
	spin_unlock_irqrestore(&geth->irq_lock, flags);

	return IRQ_HANDLED;
}

static irqreturn_t gemini_port_irq(int irq, void *data)
{
	struct gemini_ethernet_port *port = data;
	struct gemini_ethernet *geth;
	irqreturn_t ret = IRQ_NONE;
	u32 val, en;

	geth = port->geth;
	spin_lock(&geth->irq_lock);

	val = readl(geth->base + GLOBAL_INTERRUPT_STATUS_4_REG);
	en = readl(geth->base + GLOBAL_INTERRUPT_ENABLE_4_REG);

	if (val & en & SWFQ_EMPTY_INT_BIT) {
		/* Disable the queue empty interrupt while we work on
		 * processing the queue. Also disable overrun interrupts
		 * as there is not much we can do about it here.
		 */
		en &= ~(SWFQ_EMPTY_INT_BIT | GMAC0_RX_OVERRUN_INT_BIT
					   | GMAC1_RX_OVERRUN_INT_BIT);
		writel(en, geth->base + GLOBAL_INTERRUPT_ENABLE_4_REG);
		ret = IRQ_WAKE_THREAD;
	}

	spin_unlock(&geth->irq_lock);

	return ret;
}

static void gemini_port_remove(struct gemini_ethernet_port *port)
{
	if (port->netdev) {
		phy_disconnect(port->netdev->phydev);
		unregister_netdev(port->netdev);

Annotation

Implementation Notes