Realtek 8125驱动分析第二篇——触发硬件中断
书接上文,本文讲述瑞昱2.5G网卡rtl8125的触发硬件中断相关内容。
目录
1 中断处理函数(ISR)注册
2 触发硬件中断
可以通过下面的命令来看interrupts。
howard@B150:~/Driver/test/r8125-9.010.01/src$ cat /proc/interrupts CPU0 CPU1 CPU2 CPU3 0: 9 0 0 0 IO-APIC 2-edge timer1: 2 0 0 0 IO-APIC 1-edge i80428: 0 1 0 0 IO-APIC 8-edge rtc09: 0 4 0 0 IO-APIC 9-fasteoi acpi12: 0 0 0 4 IO-APIC 12-edge i8042120: 4433 0 35 0 PCI-MSI 327680-edge xhci_hcd121: 0 0 7940 19213 PCI-MSI 376832-edge ahci[0000:00:17.0]122: 0 0 0 58 PCI-MSI 360448-edge mei_me123: 25223 42 0 0 PCI-MSI 32768-edge i915124: 0 1350 0 0 PCI-MSI 514048-edge snd_hda_intel:card0125: 0 0 33 0 PCI-MSI 1048576-edge enp2s0-0126: 0 0 0 0 PCI-MSI 1048577-edge enp2s0-1127: 0 0 0 0 PCI-MSI 1048578-edge enp2s0-2128: 0 0 0 0 PCI-MSI 1048579-edge enp2s0-3129: 0 0 0 0 PCI-MSI 1048580-edge enp2s0-4130: 0 0 0 0 PCI-MSI 1048581-edge enp2s0-5131: 0 0 0 0 PCI-MSI 1048582-edge enp2s0-6132: 0 0 0 0 PCI-MSI 1048583-edge enp2s0-7133: 0 0 0 0 PCI-MSI 1048584-edge enp2s0-8134: 0 0 0 0 PCI-MSI 1048585-edge enp2s0-9135: 0 0 0 0 PCI-MSI 1048586-edge enp2s0-10136: 0 0 0 0 PCI-MSI 1048587-edge enp2s0-11137: 0 0 0 0 PCI-MSI 1048588-edge enp2s0-12138: 0 0 0 0 PCI-MSI 1048589-edge enp2s0-13139: 0 0 0 0 PCI-MSI 1048590-edge enp2s0-14140: 0 0 0 0 PCI-MSI 1048591-edge enp2s0-15141: 0 0 45 0 PCI-MSI 1048592-edge enp2s0-16142: 0 0 0 0 PCI-MSI 1048593-edge enp2s0-17143: 0 0 0 0 PCI-MSI 1048594-edge enp2s0-18144: 0 0 0 0 PCI-MSI 1048595-edge enp2s0-19145: 0 0 0 0 PCI-MSI 1048596-edge enp2s0-20146: 0 0 0 1 PCI-MSI 1048597-edge enp2s0-21147: 0 0 0 0 PCI-MSI 1048598-edge enp2s0-22148: 0 0 0 0 PCI-MSI 1048599-edge enp2s0-23149: 0 0 0 0 PCI-MSI 1048600-edge enp2s0-24150: 0 0 0 0 PCI-MSI 1048601-edge enp2s0-25151: 0 0 0 0 PCI-MSI 1048602-edge enp2s0-26152: 0 0 0 0 PCI-MSI 1048603-edge enp2s0-27153: 0 0 0 0 PCI-MSI 1048604-edge enp2s0-28154: 0 0 0 0 PCI-MSI 1048605-edge enp2s0-29155: 0 0 0 0 PCI-MSI 1048606-edge enp2s0-30156: 0 0 0 0 PCI-MSI 1048607-edge enp2s0-31157: 0 0 31 0 PCI-MSI 1572864-edge enp3s0-0158: 0 0 0 0 PCI-MSI 1572865-edge enp3s0-1159: 0 0 0 0 PCI-MSI 1572866-edge enp3s0-2160: 0 0 0 0 PCI-MSI 1572867-edge enp3s0-3161: 0 0 0 0 PCI-MSI 1572868-edge enp3s0-4162: 0 0 0 0 PCI-MSI 1572869-edge enp3s0-5163: 0 0 0 0 PCI-MSI 1572870-edge enp3s0-6164: 0 0 0 0 PCI-MSI 1572871-edge enp3s0-7165: 0 0 0 0 PCI-MSI 1572872-edge enp3s0-8166: 0 0 0 0 PCI-MSI 1572873-edge enp3s0-9167: 0 0 0 0 PCI-MSI 1572874-edge enp3s0-10168: 0 0 0 0 PCI-MSI 1572875-edge enp3s0-11169: 0 0 0 0 PCI-MSI 1572876-edge enp3s0-12170: 0 0 0 0 PCI-MSI 1572877-edge enp3s0-13171: 0 0 0 0 PCI-MSI 1572878-edge enp3s0-14172: 0 0 0 0 PCI-MSI 1572879-edge enp3s0-15173: 0 0 48 0 PCI-MSI 1572880-edge enp3s0-16174: 0 0 0 0 PCI-MSI 1572881-edge enp3s0-17175: 0 0 0 0 PCI-MSI 1572882-edge enp3s0-18176: 0 0 0 0 PCI-MSI 1572883-edge enp3s0-19177: 0 0 0 0 PCI-MSI 1572884-edge enp3s0-20178: 0 0 0 1 PCI-MSI 1572885-edge enp3s0-21179: 0 0 0 0 PCI-MSI 1572886-edge enp3s0-22180: 0 0 0 0 PCI-MSI 1572887-edge enp3s0-23181: 0 0 0 0 PCI-MSI 1572888-edge enp3s0-24182: 0 0 0 0 PCI-MSI 1572889-edge enp3s0-25183: 0 0 0 0 PCI-MSI 1572890-edge enp3s0-26184: 0 0 0 0 PCI-MSI 1572891-edge enp3s0-27185: 0 0 0 0 PCI-MSI 1572892-edge enp3s0-28186: 0 0 0 0 PCI-MSI 1572893-edge enp3s0-29187: 0 0 0 0 PCI-MSI 1572894-edge enp3s0-30188: 0 0 0 0 PCI-MSI 1572895-edge enp3s0-31NMI: 2 1 2 2 Non-maskable interruptsLOC: 31053 22096 25488 29308 Local timer interruptsSPU: 0 0 0 0 Spurious interruptsPMI: 2 1 2 2 Performance monitoring interruptsIWI: 1942 15 8 4 IRQ work interruptsRTR: 0 0 0 0 APIC ICR read retriesRES: 3165 2717 2090 2044 Rescheduling interruptsCAL: 3450 3079 2498 3748 Function call interruptsTLB: 868 687 649 1350 TLB shootdownsTRM: 0 0 0 0 Thermal event interruptsTHR: 0 0 0 0 Threshold APIC interruptsDFR: 0 0 0 0 Deferred Error APIC interruptsMCE: 0 0 0 0 Machine check exceptionsMCP: 1 2 2 2 Machine check pollsERR: 0MIS: 0PIN: 0 0 0 0 Posted-interrupt notification eventNPI: 0 0 0 0 Nested posted-interrupt eventPIW: 0 0 0 0 Posted-interrupt wakeup event
1 中断处理函数(ISR)注册
上文中提及rtl8125_open => rtl8125_alloc_irq。rtl8125_alloc_irq即实现了中断处理函数的注册。
static int rtl8125_alloc_irq(struct rtl8125_private *tp)
{struct net_device *dev = tp->dev;int rc = 0;struct r8125_irq *irq;struct r8125_napi *r8125napi;int i = 0;const int len = sizeof(tp->irq_tbl[0].name);// 这里没有define
#if defined(RTL_USE_NEW_INTR_API)for (i=0; i<tp->irq_nvecs; i++) {irq = &tp->irq_tbl[i];if (tp->features & RTL_FEATURE_MSIX &&tp->HwCurrIsrVer == 2)irq->handler = rtl8125_interrupt_msix;elseirq->handler = rtl8125_interrupt;r8125napi = &tp->r8125napi[i];snprintf(irq->name, len, "%s-%d", dev->name, i);rc = pci_request_irq(tp->pci_dev, i, irq->handler, NULL, r8125napi,irq->name);if (rc)break;irq->vector = pci_irq_vector(tp->pci_dev, i);irq->requested = 1;}
#elseunsigned long irq_flags = 0;
#ifdef ENABLE_LIB_SUPPORTirq_flags |= IRQF_NO_SUSPEND;
#endif//正常情况下是采用MSIXif (tp->features & RTL_FEATURE_MSIX &&tp->HwCurrIsrVer == 2) {for (i=0; i<tp->irq_nvecs; i++) {irq = &tp->irq_tbl[i];//这里指定了中断处理函数是rtl8125_interrupt_msixirq->handler = rtl8125_interrupt_msix;r8125napi = &tp->r8125napi[i];//irq->name是网卡名+index,从之前的介绍里可以对应上snprintf(irq->name, len, "%s-%d", dev->name, i);rc = request_irq(irq->vector, irq->handler, irq_flags, irq->name, r8125napi);if (rc)break;irq->requested = 1;}} else {irq = &tp->irq_tbl[0];irq->handler = rtl8125_interrupt;r8125napi = &tp->r8125napi[0];snprintf(irq->name, len, "%s-0", dev->name);if (!(tp->features & RTL_FEATURE_MSIX))irq->vector = dev->irq;irq_flags |= (tp->features & (RTL_FEATURE_MSI | RTL_FEATURE_MSIX)) ? 0 : SA_SHIRQ;rc = request_irq(irq->vector, irq->handler, irq_flags, irq->name, r8125napi);if (rc == 0)irq->requested = 1;}
#endifif (rc)rtl8125_free_irq(tp);return rc;
}
2 触发硬件中断
当没有处于轮询状态时,收到包后就会触发硬件中断,调用中断处理函数rtl8125_interrupt_msix。下面需要注意CONFIG_R8125_NAPI已经在Makefile里define了。
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
static irqreturn_t rtl8125_interrupt_msix(int irq, void *dev_instance, struct pt_regs *regs)
#else
static irqreturn_t rtl8125_interrupt_msix(int irq, void *dev_instance)
#endif
{struct r8125_napi *r8125napi = dev_instance;struct rtl8125_private *tp = r8125napi->priv;struct net_device *dev = tp->dev;int message_id = r8125napi->index;
#ifndef CONFIG_R8125_NAPIu32 budget = ~(u32)0;
#endifdo {
#if defined(RTL_USE_NEW_INTR_API)if (!tp->irq_tbl[message_id].requested)break;
#endif//执行硬件中断函数的时候需要屏蔽新的硬件中断rtl8125_disable_hw_interrupt_v2(tp, message_id);//clear isrrtl8125_clear_hw_isr_v2(tp, message_id);//link changeif (message_id == 21) {//这里的bit 21是Link Change Interruptrtl8125_schedule_linkchg_work(tp);break;}#ifdef CONFIG_R8125_NAPI//napi_schedule_prep()检查是否可以调度napiif (likely(RTL_NETIF_RX_SCHEDULE_PREP(dev, &r8125napi->napi)))//__napi_schedule(napi)__RTL_NETIF_RX_SCHEDULE(dev, &r8125napi->napi);else if (netif_msg_intr(tp))printk(KERN_INFO "%s: interrupt message id %d in poll_msix\n",dev->name, message_id);
#elsertl8125_tx_interrupt_with_vector(tp, message_id, ~(u32)0);if (message_id < tp->num_rx_rings) {
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)rtl8125_rx_interrupt(dev, tp, &tp->rx_ring[message_id], &budget);
#elsertl8125_rx_interrupt(dev, tp, &tp->rx_ring[message_id], budget);
#endif //LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)}rtl8125_enable_hw_interrupt_v2(tp, message_id);
#endif} while (false);return IRQ_HANDLED;
}
NAPI 的轮询循环(poll loop)是受硬件中断触发而跑起来的。换句话说,NAPI 功能启用了 ,但是默认是没有工作的,直到第一个包到达的时候,网卡触发的一个硬件将它唤醒。
/*** __napi_schedule - schedule for receive* @n: entry to schedule** The entry's receive function will be scheduled to run.* Consider using __napi_schedule_irqoff() if hard irqs are masked.*/
void __napi_schedule(struct napi_struct *n)
{unsigned long flags;local_irq_save(flags);//获取对应这个 CPU 的 structure softnet_data 变量,作为参数传过去。____napi_schedule(this_cpu_ptr(&softnet_data), n);local_irq_restore(flags);
}
EXPORT_SYMBOL(__napi_schedule);/* Called with irq disabled */
static inline void ____napi_schedule(struct softnet_data *sd,struct napi_struct *napi)
{//将(从驱动的中断函数中传来的)napi_struct 变量,添加到 poll list,后者 attach 到这个 CPU 上的 softnet_datalist_add_tail(&napi->poll_list, &sd->poll_list);//触发一个 NET_RX_SOFTIRQ 类型软中断。这会触发执行 net_rx_action(如果没有正在执行),后者是网络设备初始化的时候注册的__raise_softirq_irqoff(NET_RX_SOFTIRQ);
}
参考文献:
Linux 网络栈接收数据(RX):原理及内核实现(2022)http://arthurchiao.art/blog/linux-net-stack-implementation-rx-zh/
如果觉得这篇文章有用的话,可以点赞、评论或者收藏,万分感谢,goodbye~
Realtek 8125驱动分析第二篇——触发硬件中断相关推荐
- Realtek 8125驱动分析第一篇——初始化
Realtek 8125是瑞昱的2.5G网卡,今天开始分析一下该网卡的驱动程序. 目录 1 驱动模块注册 2 PCI相关初始化 2.1 PCI 驱动列表注册:pci_register_driver() ...
- SAP PP COR2下达工单系统报错说-系统状态APNG是激活的- 分析第二篇
SAP PP COR2下达工单系统报错说-系统状态APNG是激活的- 分析第二篇 笔者所在的项目上启用了ECM(Engineer Change Management)功能,重要数据的修改都要事先创建一 ...
- Linux SD卡驱动开发(二) —— SD 卡驱动分析HOST篇
回顾一下前面的知识,MMC 子系统范围三个部分: HOST 部分是针对不同主机的驱动程序,这一部是驱动程序工程师需要根据自己的特点平台来完成的. CORE 部分: 这是整个MMC 的核心存,这部分完成 ...
- nutch代码分析第二篇——crawl.crawl
2021SC@SDUSC 顾名思义,org.apache.nutch.crawl.Crawl实现的是一个完整的抓取过程,包括各种方法的初始化,url集的建立 /* Perform complete c ...
- Linux SD卡驱动开发(五) —— SD 卡驱动分析Core补充篇
Core层中有两个重要函数 mmc_alloc_host 用于构造host,前面已经学习过,这里不再阐述:另一个就是 mmc_add_host,用于注册host 前面探测函数s3cmci_probe, ...
- framebuffer驱动详解4——framebuffer驱动分析2(probe函数讲解)
以下内容源于朱有鹏<物联网大讲堂>课程的学习,如有侵权,请告知删除. 主要在填充fbdev这个结构体. 二.framebuffer驱动分析2 1.probe函数分析 (1)struct s ...
- 【转】android电池(四):电池 电量计(MAX17040)驱动分析篇
关键词:android 电池 电量计 MAX17040 任务初始化宏 power_supply 平台信息: 内核:linux2.6/linux3.0 系统:android/android4.0 ...
- android电池(五):电池 充电IC(PM2301)驱动分析篇
android电池(五):电池 充电IC(PM2301)驱动分析篇 关键词:android 电池 电量计 PL2301任务初始化宏 power_supply 中断线程化 平台信息: 内核:linu ...
- Cyclone V SoC FPGA学习之路第二章:硬件篇
Cyclone V SoC FPGA学习之路第二章:硬件篇(内部资源) 前言 上一章了解了<cycloneV device datasheet>,其中数据手册里重点介绍了电源要求,时序参数 ...
最新文章
- lvs+keepalived实现双实例【双主模型】
- 第一篇 webApp启航
- python实现pdf转word详解_手把手|20行Python代码教你批量将PDF文件转为Word格式(包教包会)...
- Discuz!NT负载均衡方案
- ElementTree中的getchildren and getiterator
- 《分布式系统:概念与设计》一2.3.2 体系结构模式
- mysql+查询新的一条记录表_Mysql 查询表中每个类别最新的一条记录
- vSphere 7 With K8s系列09:部署wordpress示例
- 软银愿景叕10亿美元砸向无人车,Nuro投后估值27亿美元
- 【数据结构 严蔚敏版】 循环队列 基本操作
- Java常见异常类【整理】
- 花一天时间体验 wintogo 到最终放弃
- Python模拟用户自动登陆网易126邮箱
- 基于优化LSTM 模型的股票预测
- java输入输出流数组_详解Java中ByteArray字节数组的输入输出流的用法
- cass简码大全_cass简码实体对照表
- 联想笔记本windows10设备管理器找不到蓝牙
- vs2017 html插件推荐,收藏!推荐12个超实用的Visual Studio插件
- oracle统计日均,oracle效率优化实战——计算3个月的平均值
- 运算放大器的性能指标
热门文章
- 2022/2/15 Hand Pose Estimation:综述阅读1
- 转自MBA lib 时间管理
- 微信小程序添加底部导航栏
- R语言MIDAS(Mixed Frequency Data Sampling Regression Models)学习分享(一)从下载安装包开始
- Oracle Coherence中文教程七:设置群集
- IM比较SipDroid/IMSDroid/CSipsimple/Linphone/Webrtc
- unity 3D RPG教程(四)
- 目前国内外的一些机器视觉公司汇总(2006年11月30日更新)
- 迟到的2016年计划
- Kubernetes 资源拓扑感知调度优化