pci-e转sata控制器siI3124驱动分析笔记(基于linux)

news/2024/12/2 17:37:12/

首先提纲挈领的总结下基于pci的驱动原理,摘自Understanding Linux Network Internals

原文配合三张图来讲解,这里就不附图了,相关范例的说明也加以删除

When device driver  is loaded, it registers with the PCI layer by callingpci_register_driver and
providing its instance of pci_driver. Thepci_driver structure includes a vector with the IDs of those
PCI devices it can drive. The PCI layer then uses that table to see what devices match in its list of detected
PCI devices. It thus creates the driver's device list . In addition, for each matching
device, the PCI layer invokes the probe function provided by the matching driver in itspci_driver
structure. The probe function creates and registers the associated network device.

在init初始化时会调用sata驱动的初始化函数
static int __init sil24_init(void)
{	return pci_register_driver(&sil24_pci_driver);
}
其中
static struct pci_driver sil24_pci_driver = {.name			= DRV_NAME,.id_table		= sil24_pci_tbl,.probe			= sil24_init_one,.remove			= ata_pci_remove_one,
#ifdef CONFIG_PM.suspend		= ata_pci_device_suspend,.resume			= sil24_pci_device_resume,
#endif
static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{extern int __MARKER__sil24_cmd_block_is_sized_wrongly;static int printed_version;struct ata_port_info pi = sil24_port_info[ent->driver_data];const struct ata_port_info *ppi[] = { &pi, NULL };void __iomem * const *iomap;struct ata_host *host;int rc;u32 tmp;printk(KERN_INFO"probe start here\n");/* cause link error if sil24_cmd_block is sized wrongly */if (sizeof(union sil24_cmd_block) != PAGE_SIZE)__MARKER__sil24_cmd_block_is_sized_wrongly = 1;if (!printed_version++)dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");/* acquire resources */rc = pcim_enable_device(pdev);if (rc)return rc;rc = pcim_iomap_regions(pdev,(1 << SIL24_HOST_BAR) | (1 << SIL24_PORT_BAR),DRV_NAME);if (rc)return rc;iomap = pcim_iomap_table(pdev);/* apply workaround for completion IRQ loss on PCI-X errata */if (pi.flags & SIL24_FLAG_PCIX_IRQ_WOC) {tmp = readl(iomap[SIL24_HOST_BAR] + HOST_CTRL);if (tmp & (HOST_CTRL_TRDY | HOST_CTRL_STOP | HOST_CTRL_DEVSEL))dev_printk(KERN_INFO, &pdev->dev,"Applying completion IRQ loss on PCI-X ""errata fix\n");elsepi.flags &= ~SIL24_FLAG_PCIX_IRQ_WOC;}/* allocate and fill host */host = ata_host_alloc_pinfo(&pdev->dev, ppi,SIL24_FLAG2NPORTS(ppi[0]->flags));if (!host)return -ENOMEM;host->iomap = iomap;printk(KERN_INFO,"assign iomap here:%0#10lx %0#10lx\n",pci_resource_start(pdev,0),pci_resource_start(pdev,2));/* configure and activate the device */if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));if (rc) {rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));if (rc) {dev_printk(KERN_ERR, &pdev->dev,"64-bit DMA enable failed\n");return rc;}}} else {rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));if (rc) {dev_printk(KERN_ERR, &pdev->dev,"32-bit DMA enable failed\n");return rc;}rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));if (rc) {dev_printk(KERN_ERR, &pdev->dev,"32-bit consistent DMA enable failed\n");return rc;}}/* Set max read request size to 4096.  This slightly increases* write throughput for pci-e variants.*/pcie_set_readrq(pdev, 4096);sil24_init_controller(host);if (sata_sil24_msi && !pci_enable_msi(pdev)) {dev_printk(KERN_INFO, &pdev->dev, "Using MSI\n");pci_intx(pdev, 0);}pci_set_master(pdev);return ata_host_activate(host, pdev->irq, sil24_interrupt, IRQF_SHARED,&sil24_sht);
}

/** pci_register_driver must be a macro so that KBUILD_MODNAME can be expanded*/
#define pci_register_driver(driver)		\__pci_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)

};


pci_register_driver实际是一个宏,最终的实现是

该driver是静态赋值初始化完成的,之后就进入一个复杂的内核pci功能调用线:
__pci_register_driver--->driver_register-->bus_add_driver-->driver_attach-->__driver_attach-->driver_probe_device-->really_probe-->dev->bus->probe(dev)
在静态赋值时probe方法初始化为sil24_init_one。
probe函数需要实现的功能如下:
This function should enable the hardware, allocate the net_device structure, and initialize and register the new device(from ULNI)
static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{extern int __MARKER__sil24_cmd_block_is_sized_wrongly;static int printed_version;struct ata_port_info pi = sil24_port_info[ent->driver_data];const struct ata_port_info *ppi[] = { &pi, NULL };void __iomem * const *iomap;struct ata_host *host;int rc;u32 tmp;printk(KERN_INFO"probe start here\n");/* cause link error if sil24_cmd_block is sized wrongly */if (sizeof(union sil24_cmd_block) != PAGE_SIZE)__MARKER__sil24_cmd_block_is_sized_wrongly = 1;if (!printed_version++)dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");/* acquire resources */rc = pcim_enable_device(pdev);if (rc)return rc;rc = pcim_iomap_regions(pdev,(1 << SIL24_HOST_BAR) | (1 << SIL24_PORT_BAR),DRV_NAME);if (rc)return rc;iomap = pcim_iomap_table(pdev);/* apply workaround for completion IRQ loss on PCI-X errata */if (pi.flags & SIL24_FLAG_PCIX_IRQ_WOC) {tmp = readl(iomap[SIL24_HOST_BAR] + HOST_CTRL);if (tmp & (HOST_CTRL_TRDY | HOST_CTRL_STOP | HOST_CTRL_DEVSEL))dev_printk(KERN_INFO, &pdev->dev,"Applying completion IRQ loss on PCI-X ""errata fix\n");elsepi.flags &= ~SIL24_FLAG_PCIX_IRQ_WOC;}/* allocate and fill host */host = ata_host_alloc_pinfo(&pdev->dev, ppi,SIL24_FLAG2NPORTS(ppi[0]->flags));if (!host)return -ENOMEM;host->iomap = iomap;printk(KERN_INFO,"assign iomap here:%0#10lx %0#10lx\n",pci_resource_start(pdev,0),pci_resource_start(pdev,2));/* configure and activate the device */if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));if (rc) {rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));if (rc) {dev_printk(KERN_ERR, &pdev->dev,"64-bit DMA enable failed\n");return rc;}}} else {rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));if (rc) {dev_printk(KERN_ERR, &pdev->dev,"32-bit DMA enable failed\n");return rc;}rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));if (rc) {dev_printk(KERN_ERR, &pdev->dev,"32-bit consistent DMA enable failed\n");return rc;}}/* Set max read request size to 4096.  This slightly increases* write throughput for pci-e variants.*/pcie_set_readrq(pdev, 4096);sil24_init_controller(host);if (sata_sil24_msi && !pci_enable_msi(pdev)) {dev_printk(KERN_INFO, &pdev->dev, "Using MSI\n");pci_intx(pdev, 0);}pci_set_master(pdev);return ata_host_activate(host, pdev->irq, sil24_interrupt, IRQF_SHARED,&sil24_sht);
}


sil24_init_one完成设备的初始化实际工作:进行PCI的MEMORY/IO窗口映射,分配IRQ,激活设备等等。
linux的驱动开发有两部分组成:设置实现以及内核匹配。
设备实现是实际的设备相关的功能函数,集中体现在ops数组

static struct ata_port_operations sil24_ops = {.inherits		= &sata_pmp_port_ops,.qc_defer		= sil24_qc_defer,.qc_prep		= sil24_qc_prep,.qc_issue		= sil24_qc_issue,.qc_fill_rtf		= sil24_qc_fill_rtf,.freeze			= sil24_freeze,.thaw			= sil24_thaw,.softreset		= sil24_softreset,.hardreset		= sil24_hardreset,.pmp_softreset		= sil24_softreset,.pmp_hardreset		= sil24_pmp_hardreset,.error_handler		= sil24_error_handler,.post_internal_cmd	= sil24_post_internal_cmd,.dev_config		= sil24_dev_config,.scr_read		= sil24_scr_read,.scr_write		= sil24_scr_write,.pmp_attach		= sil24_pmp_attach,.pmp_detach		= sil24_pmp_detach,.port_start		= sil24_port_start,
#ifdef CONFIG_PM.port_resume		= sil24_port_resume,
#endif
};


内核匹配指的是在合适的时机用内核框架搭好的入口传入设备初始化及ops数组
这款sata控制器芯片的ops是通过下面的定义传入内核的
static const struct ata_port_info sil24_port_info[] = {/* sil_3124 */{.flags		= SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(4) |SIL24_FLAG_PCIX_IRQ_WOC,.pio_mask	= ATA_PIO4,.mwdma_mask	= ATA_MWDMA2,.udma_mask	= ATA_UDMA5,.port_ops	= &sil24_ops,},/* sil_3132 */{.flags		= SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(2),.pio_mask	= ATA_PIO4,.mwdma_mask	= ATA_MWDMA2,.udma_mask	= ATA_UDMA5,.port_ops	= &sil24_ops,},/* sil_3131/sil_3531 */{.flags		= SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(1),.pio_mask	= ATA_PIO4,.mwdma_mask	= ATA_MWDMA2,.udma_mask	= ATA_UDMA5,.port_ops	= &sil24_ops,},
};

在初始化设备时,会调用 host =  ata_host_alloc_pinfo(&pdev->dev, ppi, SIL24_FLAG2NPORTS(ppi[0]->flags));
将芯片的控制函数ops穿入内核
struct ata_host *ata_host_alloc_pinfo(struct device *dev,const struct ata_port_info * const * ppi,int n_ports)
{const struct ata_port_info *pi;struct ata_host *host;int i, j;host = ata_host_alloc(dev, n_ports);if (!host)return NULL;for (i = 0, j = 0, pi = NULL; i < host->n_ports; i++) {struct ata_port *ap = host->ports[i];if (ppi[j])pi = ppi[j++];ap->pio_mask = pi->pio_mask;ap->mwdma_mask = pi->mwdma_mask;ap->udma_mask = pi->udma_mask;ap->flags |= pi->flags;ap->link.flags |= pi->link_flags;ap->ops = pi->port_ops;if (!host->ops && (pi->port_ops != &ata_dummy_port_ops))host->ops = pi->port_ops;}return host;
}
中断处理由sil24_init_one在最后结束的时候调用return  ata_host_activate(host, pdev->irq,  sil24_interrupt, IRQF_SHARED, &sil24_sht);传入内核


http://www.ppmy.cn/news/170142.html

相关文章

处理E160004: Corrupt node-revision 'lx-249.0-248.r1186/2192'

今天遇到SVN 的 repository 被一哥们提交搞坏了&#xff0c;这个目录任何操作都是显示&#xff1a; E160004: Corrupt node-revision lx-249.0-248.r1186/2192 无奈在svn server上跑了下 svnadmin verify c:\Repositories\project * Verified revision 1183. * Verified revis…

Spartan6 LX45上的(串口)UART+DDR3读写操作

XILINX 公司率先在FPGA芯片中集成了MCB硬核&#xff0c;它可以支持到DDR3&#xff0c;对于用户控制接口以通用FIFO的读写方式&#xff0c;代替复杂的ddr2读写逻辑。以sram的地址映射方式代替复杂的行列地址选择。比如Spartan6 FPGA芯片中集成了MCB硬核&#xff0c;它可以支持到…

Arduino IDE for esp8266 :解决关于xtensa-lx106-elf-g++: no such file or directory

一般出现这个问题都是没有从boards manager下载ESP8622&#xff0c;导致版本不同&#xff0c;lib库的缺少。 之前不知道怎么回事&#xff08;墙的原因&#xff09;&#xff0c;导致只能从百度云下载之前的8266版本&#xff0c;随便编译一个例子都过不了。 主要解决方法是翻墙从…

E类(class E)功放的原理及设计

转自&#xff1a;https://www.kechuang.org/t/78392 不少人第一次听说E类功放都是因为那个class E SSTC&#xff0c;从网上查询却发现资料少的可怜&#xff0c;其原理和设计方法就更无从谈及。下面我就根据书中所写以及自己的理解讲一下。讲之前还需说一下&#xff0c;因为电路…

lx-0721-1003统计元音

Problem Description 统计每个元音字母在字符串中出现的次数。 Input 输入数据首先包括一个整数n&#xff0c;表示测试实例的个数&#xff0c;然后是n行长度不超过100的字符串。 Output 对于每个测试实例输出5行&#xff0c;格式如下&#xff1a; a:num1 e:num2 i:num3 o:num4 …

CF983E NN country

NN country 题目描述 传送门&#xff1a;http://codeforces.com/contest/983/problem/E 题解 首先有一个很显然的贪心策略&#xff0c;我们对于每个节点预处理出从它出发向上乘一次车最远能到哪。 对于一次询问&#xff0c;两个点x,y&#xff0c;我们先让这两个点贪心地往…

Spartan6 LX45 DDR3调试与分析

新的一年&#xff0c;新的开始。本文对最近的学习做个总结吧。最近在做spartan6的ddr3开发&#xff0c;FPGA采用的是spartan6的XC6LX45T&#xff0c;平台工具为ISE14.6&#xff0c;MIG的版本为3.92。采用的DDR3芯片为MT41J128M16XX-187E&#xff0c;并使用chipscope完成仿真调试…

linux主机风扇速度控制 解决记录 it8613E z490 GTN ubuntu 20.04

OS: ubuntu 20.04、主板&#xff1a;biostar z490 GTN、风扇IO芯片&#xff1a;it8613E lmsensors 可以获取 温度传感器 与 风扇的转速&#xff0c;也可以自定义调整风扇速度。 1、运行sensors-detect显示it8613E无驱动&#xff08;如图&#xff09; it8613E不是一个新的芯片…