<linux kernel> RT8139c+ driver

本文详细解析了8139网卡驱动的工作原理,包括DMA数据传输过程、NAPI模式下的中断处理机制及ring descriptors的管理。探讨了如何通过dma_alloc_coherent分配内存、设置中断屏蔽寄存器以及具体的DMA数据搬运流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

 

NIC register 

 

IntrStatus = 0x3E, /* Interrupt status */


 

 

int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)

|- dev->irq = pdev->irq;

 

 

Int Cp_open(struct net_device *dev)

|-Request_irq(dev->irq, cp_interrupt, IRQF_SHARED, dev->name , dev);

 

#define cpr16(reg) readw(cp->regs + (reg))

 


 

cp_norx_intr_mask = PciErr | LinkChg | TxOK | TxErr | TxEmpty,

 

Irqreturn_t cp_interrupt(int irq, void *dev_instance){

//...

if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr))

if (napi_schedule_prep(&cp->napi)) {

// 关闭 recv中断相关寄存器  进入NAPI模式

cpw16_f(IntrMask, cp_norx_intr_mask); 

__napi_schedule(&cp->napi);

|-____napi_schedule(&__get_cpu_var(softnet_data), n);

|- __raise_softirq_irqoff(NET_RX_SOFTIRQ);

}

status = cpr16(IntrStatus);

//...

}

static inline int napi_schedule_prep(struct napi_struct *n)

|-test_and_set_bit(NAPI_STATE_SCHED, &n->state);

 

 

 


 

 

 

:/proc/sys/net/core$ cat netdev_budget  300

 

Static void net_rx_action(struct softirq_action *h){

struct softnet_data *sd = &__get_cpu_var(softnet_data);

while (!list_empty(&sd->poll_list)) {

//...

if (test_bit(NAPI_STATE_SCHED, &n->state)) {

work = n->poll(n, weight);

trace_napi_poll(n);

}

WARN_ON_ONCE(work > weight);

budget -= work; //你懂的

//..

}

}

 

Recall to :

 

process_backlog()

|-struct softnet_data *sd = container_of(napi, struct softnet_data, backlog);

|-__netif_receive_skb

 

// ok 忘记吧!  

 

 

-----------------------------------------------------------------------------------------------------

Here we back to  8139 driver : 

// 开始从DMA 搬运到 cp->rx_skb

void cp_rx_poll(struct napi_struct *napi, int budget){

 

//...

While(1){

 

const unsigned buflen = cp->rx_buf_sz; 

skb = cp->rx_skb[rx_tail];

 

len = (status & 0x1fff) - 4; //CRC

// |- cp_change_mtu(); -> cp_set_rxbufsize();

new_skb = netdev_alloc_skb_ip_align(dev, buflen);

|-__netdev_alloc_skb+GFP_ATOMIC

|-skb_reserve+NET_IP_ALIGN

/*ummpa上次的dma 地址 last transfer is done */

dma_unmap_single(&cp->pdev->dev, mapping, buflen, PCI_DMA_FROMDEVICE);

 

skb_put(skb, len);

/*用new_skb->data做为下一次的mapping 并保存*/

mapping = dma_map_single(&cp->pdev->dev, new_skb->data, buflen,PCI_DMA_FROMDEVICE);

 

/*记录在 rx_skb数组tail*/

cp->rx_skb[rx_tail] = new_skb;

 

cp_rx_skb(cp, skb, desc);

|-__napi_gro_receive 使用GRO开始做拆包的组装

|-dev_gro_receive

|-ptype->gro_receive(&napi->gro_list, skb); 先是inet_gro_receive  接下来如果tcp 注册的是tcp4_gro_receive skb都存到了skb_shared_info frags

 

cp->rx_ring[rx_tail].opts2 = 0;

cp->rx_ring[rx_tail].addr = cpu_to_le64(mapping);

//some statistics

if (rx < budget) {// done !}

 

}

//...

 

}

 

The streaming DMA mapping routines can be called from interrupt context. 

不需要CPU device 之间 in parallel  access

This of "streaming" as "asynchronous" or "outside the coherency domain".  

 

对于 ring descriptors 需要Consistent DMA 

 

static int cp_alloc_rings (struct cp_private *cp)
{
	void *mem;

	mem = dma_alloc_coherent(&cp->pdev->dev, CP_RING_BYTES,
				 &cp->ring_dma, GFP_KERNEL);
	if (!mem)
		return -ENOMEM;
// 记住操作此mem 如果不想发生奇怪的事情一定要wmb()一下!
	cp->rx_ring = mem;
	cp->tx_ring = &cp->rx_ring[CP_RX_RING_SIZE];//64

	return cp_init_rings(cp);
 

这里就要说一下8139c+的 transmit receive mode了

 

rtl8139c+ 为收发单独提供了【64】个连续的内存描述符 有3种ring 描述符,

1 高优先级传输ring

2 正常优先级传输ring

3 正常接收ring 

每一个ring描述符 由4个连续的双字组成 ,开始地址也需要256位对齐, 这里可以看到预先用consistent DMA分配了这块

下面是区段对这个的定义,很简单? NO

struct cp_desc {
	__le32		opts1;
	__le32		opts2;
	__le64		addr;
};

 事实上应该如此:

 


 

分配ring 数组 

int cp_alloc_rings(struct cp_private *cp)

|- dma_alloc_coherent + GFP_KERNEL

|- __get_free_pages  /

 


-----------------------------------------------------------

 

 

E2prom : 

cp_get_eeprom(struct net_device *dev,

 struct ethtool_eeprom *eeprom, u8 *data)

addr_len = read_eeprom(cp->regs, 0, 8) == 0x8129 ? 8 : 6;

 

 

151.250174699999DBGC~ ~ ====1609430805.188988-D Panic#1 Part1 <5>[ 39.221003] audit: type=1325 audit(1609430702.167:25): table=filter family=2 entries=14 op=xt_replace pid=3630 subj=system_u:system_r:system_t comm="iptables" <5>[ 52.258603] audit: type=1325 audit(1609430715.203:26): table=filter family=2 entries=15 op=xt_replace pid=4407 subj=system_u:system_r:system_t comm="iptables" <5>[ 52.278549] audit: type=1325 audit(1609430715.223:27): tab le=filter family=2 entries=16 op=xt_replace pid=4412 subj=system_u:system_r:system_t comm="iptables" <5>[ 52.299842] audit: type=1325 audit(1609430715.247:28): table=filter family=2 entries=17 op=xt_replace pid=4414 subj=syste m_u:system_r:system_t comm="iptables" <5>[ 52.321002] audit: type=1325 audit(1609430715.267:29): table=filter family=2 entries=18 op=xt_replace pid=4415 subj=system_u:system_r:system_t comm="iptables" <5>[ 52.340063] audit: type=1325 audit(1609430715.287:30): table=filter family=2 entries=19 op=xt_replace pid=4420 subj=system_u:system_r:system_t comm="iptables" <5>[ 52.361228] audit: type=1325 audit(1609430715.307:31): table=filter family=2 entries=20 op=xt_replace pid=4422 subj=system_u:system_r:system_t comm="iptables" <5>[ 52.385552] audit: type=1325 audit(1609430715.331:32): table=filter family=2 entries=21 op=xt_replace pid=4424 subj=system_u:system_r:system_t comm="iptables" <4>[ 140.719362] ------------[ cut here ]------------ <4>[ 140.719393] WARNING: CPU: 4 PID: 4166 at __ioremap_caller+0x7c/0xcc <4>[ 140.719432] Modules linked in: io_registers(O) bridge nft_fib_ipv6 optee_rng tee ipv6 ipc_shm_hpe(O) ipc_shm_dev(O) virtual_ptp_clock(O) pfeng_slave(O) <4>[ 140.719491] CPU: 4 PID: 4166 Comm: sh Tainted: G O 5.10.120-rt70-eb-corbos-standard #1 <4>[ 140.719503] Hardware name: Freescale S32G399A (DT) <4>[ 140.719509] pstate: 00000005 (nzcv daif -PAN -UAO -TCO BTYPE=--) <4>[ 140.719520] pc : __ioremap_caller+0x7c/0xcc <4>[ 140.719528] lr : __ioremap_caller+0x78/0xcc <4>[ 140.719538] sp : ffffffc016363c10 <4>[ 140.719541] x29: ffffffc016363c10 x28: ffffff9808164600 <4>[ 140.719552] x27: 0000000000000000 x26: 0000000000000000 <4>[ 140.719562] x25: 0000000000000000 x24: 0000000000000000 <4>[ 140.719572] x23: ffffffdd419a50b0 x22: 0068000000000f17 <4>[ 140.719584] x21: 0000000000000000 x20: 00000000809a0000 <4>[ 140.719594] x19: 0000000000001000 x18: 0000000000000000 <4>[ 140.719605] x17: 0000000000000000 x16: 0000000000000000 <4>[ 140.719614] x15: 000000557ccac140 x14: 0000000000000000 <4>[ 140.719623] x13: 0000000000000000 x12: 0000000000000000 <4>[ 140.719632] x11: 0000000000000000 x10: 0000000000000000 <4>[ 140.719641] x9 : ffffffdd473bf9cc x8 : 00000000ffffffc9 <4>[ 140.719651] x7 : ffffffdd481e46d0 x6 : 0000000000000018 <4>[ 140.719660] x5 : ffffffdd481e46d0 x4 : 0000000003200000 <4>[ 140.719669] x3 : 0000000000000001 x2 : 0000000000000018 <4>[ 140.719680] x1 : ffffffdd481e46d0 x0 : 0000000000000001 <4>[ 140.719691] Call trace: <4>[ 140.719697] __ioremap_caller+0x7c/0xcc <4>[ 140.719706] __ioremap+0x34/0x4c <4>[ 140.719714] io_registers_write+0xb0/0x13c [io_registers] <4>[ 140.719731] kobj_attr_store+0x18/0x2c <4>[ 140.719748] sysfs_kf_write+0x44/0x58 <4>[ 140.719761] kernfs_fop_write_iter+0xc0/0x188 <4>[ 140.719773] new_sync_write+0x80/0xd8 <4>[ 140.719784] vfs_write+0x114/0x138 <4>[ 140.719794] ksys_write+0x78/0xe4 <4>[ 140.719801] __arm64_sys_write+0x20/0x2c <4>[ 140.719809] do_el0_svc+0x124/0x1b0 <4>[ 140.719819] el0_svc+0x20/0x30 <4>[ 140.719835] el0_sync_handler+0xcc/0x154 <4>[ 140.719846] el0_sync+0x160/0x180 <0>[ 140.719857] Kernel panic - not syncing: <4>[ 140.719860] panic_on_warn set ... <2>[ 141.720054] SMP: stopping secondary CPUs <0>[ 142.218066] Kernel Offset: 0x1d37200000 from 0xffffffc010000000 <0>[ 142.224116] PHYS_OFFSET: 0xffffffe8c0000000 <0>[ 142.228381] CPU features: 0x00040022,20802008 <0>[ 142.232834] Memory Limit: none 分析这段kernel panic后记录的calltrace数据
05-28
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值