drivers/net/ethernet/sunplus/spl2sw_int.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/sunplus/spl2sw_int.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/sunplus/spl2sw_int.c
Extension
.c
Size
7396 bytes
Lines
274
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 (unlikely((cmd & RXD_ERR_CODE) || pkg_len < ETH_ZLEN + 4)) {
				stats->rx_length_errors++;
				stats->rx_dropped++;
				goto spl2sw_rx_poll_rec_err;
			}

			dma_unmap_single(&comm->pdev->dev, sinfo->mapping,
					 comm->rx_desc_buff_size, DMA_FROM_DEVICE);

			skb = sinfo->skb;
			skb_put(skb, pkg_len - 4); /* Minus FCS */
			skb->ip_summed = CHECKSUM_NONE;
			skb->protocol = eth_type_trans(skb, comm->ndev[port]);
			len = skb->len;
			netif_receive_skb(skb);

			stats->rx_packets++;
			stats->rx_bytes += len;

			/* Allocate a new skb for receiving. */
			new_skb = netdev_alloc_skb(NULL, comm->rx_desc_buff_size);
			if (unlikely(!new_skb)) {
				desc->cmd2 = (rx_pos == comm->rx_desc_num[queue] - 1) ?
					     RXD_EOR : 0;
				sinfo->skb = NULL;
				sinfo->mapping = 0;
				desc->addr1 = 0;
				goto spl2sw_rx_poll_alloc_err;
			}

			sinfo->mapping = dma_map_single(&comm->pdev->dev, new_skb->data,
							comm->rx_desc_buff_size,
							DMA_FROM_DEVICE);
			if (dma_mapping_error(&comm->pdev->dev, sinfo->mapping)) {
				dev_kfree_skb_irq(new_skb);
				desc->cmd2 = (rx_pos == comm->rx_desc_num[queue] - 1) ?
					     RXD_EOR : 0;
				sinfo->skb = NULL;
				sinfo->mapping = 0;
				desc->addr1 = 0;
				goto spl2sw_rx_poll_alloc_err;
			}

			sinfo->skb = new_skb;
			desc->addr1 = sinfo->mapping;

spl2sw_rx_poll_rec_err:
			desc->cmd2 = (rx_pos == comm->rx_desc_num[queue] - 1) ?
				     RXD_EOR | comm->rx_desc_buff_size :
				     comm->rx_desc_buff_size;

			wmb();	/* Set RXD_OWN after other fields are effective. */
			desc->cmd1 = RXD_OWN;

spl2sw_rx_poll_alloc_err:
			/* Move rx_pos to next position */
			rx_pos = ((rx_pos + 1) == comm->rx_desc_num[queue]) ? 0 : rx_pos + 1;

			budget_left--;

			/* If there are packets in high-priority queue,
			 * stop processing low-priority queue.
			 */
			if (queue == 1 && !(h_desc->cmd1 & RXD_OWN))
				break;
		}

		comm->rx_pos[queue] = rx_pos;

		/* Save pointer to last rx descriptor of high-priority queue. */
		if (queue == 0)
			h_desc = comm->rx_desc[queue] + rx_pos;
	}

	spin_lock_irqsave(&comm->int_mask_lock, flags);
	mask = readl(comm->l2sw_reg_base + L2SW_SW_INT_MASK_0);
	mask &= ~MAC_INT_RX;
	writel(mask, comm->l2sw_reg_base + L2SW_SW_INT_MASK_0);
	spin_unlock_irqrestore(&comm->int_mask_lock, flags);

	napi_complete(napi);
	return budget - budget_left;
}

int spl2sw_tx_poll(struct napi_struct *napi, int budget)
{
	struct spl2sw_common *comm = container_of(napi, struct spl2sw_common, tx_napi);
	struct spl2sw_skb_info *skbinfo;
	struct net_device_stats *stats;
	int budget_left = budget;

Annotation

Implementation Notes