pm8001_pci_probe分析(一)

来源:互联网 发布:网上商城开源代码java 编辑:程序博客网 时间:2024/06/04 18:59
/** * pm8001_pci_probe - probe supported device * @pdev: pci device which kernel has been prepared for. * @ent: pci device id * * This function is the main initialization function, when register a new * pci driver it is invoked, all struct and hardware initialization should be * done here, also, register interrupt */static int __devinit pm8001_pci_probe(struct pci_dev *pdev,const struct pci_device_id *ent){int rc;u32pci_reg;struct pm8001_hba_info *pm8001_ha;//HBA在LLD中的表示struct Scsi_Host *shost = NULL;const struct pm8001_chip_info *chip;dev_printk(KERN_INFO, &pdev->dev,"pm8001: driver version %s, %s\n", DRV_VERSION, DRV_DATE);rc = pci_enable_device(pdev);//使能pci设备,即开启设备的地址映射和中断等if (rc) {dev_printk(KERN_INFO, &pdev->dev,"pm8001: failed to enable device \n");goto err_out_enable;}pci_set_master(pdev);//set pci device dma master mode/* * Enable pci slot busmaster by setting pci command register. * This is required by FW for Cyclone card. */pci_read_config_dword(pdev, PCI_COMMAND, &pci_reg);pci_reg |= 0x157;pci_write_config_dword(pdev, PCI_COMMAND, pci_reg);rc = pci_request_regions(pdev, DRV_NAME);//request regions(virtual address) for pci deviceif (rc) {dev_printk(KERN_INFO, &pdev->dev,"pm8001: failed to request regions\n");goto err_out_disable;}rc = pci_go_44(pdev);//set dma maskif (rc) {dev_printk(KERN_INFO, &pdev->dev,"pm8001: failed to set dma mask\n");goto err_out_regions;}shost = scsi_host_alloc(&pm8001_sht, sizeof(void *));//register pm8001_sht to kernel and alloc and then init scsi_hostif (!shost) {rc = -ENOMEM;dev_printk(KERN_INFO, &pdev->dev,"pm8001: failed to alloc memory for shost\n");goto err_out_regions;}chip = &pm8001_chips[ent->driver_data];SHOST_TO_SAS_HA(shost) =kzalloc(sizeof(struct sas_ha_struct), GFP_KERNEL);//SHOST_TO_SAS_HA(shost) is a PTR to sas_ha_structif (!SHOST_TO_SAS_HA(shost)) {rc = -ENOMEM;dev_printk(KERN_INFO, &pdev->dev,"pm8001: failed to alloc memory for sas host\n");goto err_out_free_host;}rc = pm8001_prep_sas_ha_init(shost, chip);// 初始化SHOST_TO_SAS_HA(shost),进一步初始化shostif (rc) {rc = -ENOMEM;dev_printk(KERN_INFO, &pdev->dev,"pm8001: failed to alloc memory for sas layer\n");goto err_out_free;}pci_set_drvdata(pdev, SHOST_TO_SAS_HA(shost));// pdev->dev->p->driver_data = SHOST_TO_SAS_HA(shost);pm8001_ha = pm8001_pci_alloc(pdev, ent->driver_data, shost);//后面会重点介绍if (!pm8001_ha) {rc = -ENOMEM;dev_printk(KERN_INFO, &pdev->dev,"pm8001: failed to alloc memory for pm8001_ha\n");goto err_out_free;}/* * Make sure we have at least a sane region 0 * * We do this here because a failure in pm8001_pci_alloc * is just interpreted as a memory allocation failure. */if (pm8001_ha->io_mem[0].memvirtaddr == NULL || pm8001_ha->io_mem[0].memsize < (1 << 15)) {//?? memsize must large 32kB,why?printk(KERN_ERR "BAR0 access bad: %p,%x\n",pm8001_ha->io_mem[0].memvirtaddr,pm8001_ha->io_mem[0].memsize);rc = -ENXIO;goto err_out_free;}list_add_tail(&pm8001_ha->list, &hba_list);//下面调用 pm8001_init_table_addresses(struct pm8001_hba_info *pm8001_ha)PM8001_CHIP_DISP->chip_pre_init(pm8001_ha);/* HDA SEEPROM Force HDA Mode */if (PM8001_CHIP_DISP->chip_in_hda_mode(pm8001_ha)) {rc = PM8001_CHIP_DISP->chip_hda_mode(pm8001_ha);if (!rc) {rc = -EBUSY;goto err_out_ha_free;}pm8001_ha->rst_signature = SPC_HDASOFT_RESET_SIGNATURE;} else {if (IS_SPCV(pm8001_ha))rc = spcv_chip_soft_rst(pm8001_ha, SPC_SOFT_RESET_SIGNATURE);elserc = PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha, SPC_SOFT_RESET_SIGNATURE);if (rc) {dev_printk(KERN_INFO, &pdev->dev,"pm8001: failed to chip soft reset\n");goto err_out_ha_free;}pm8001_ha->rst_signature = SPC_SOFT_RESET_SIGNATURE;}//下面调用pm8001_chip_init(struct pm8001_hba_info *pm8001_ha)rc = PM8001_CHIP_DISP->chip_init(pm8001_ha);if (rc) {dev_printk(KERN_INFO, &pdev->dev,"pm8001: failed to init chip\n");goto err_out_ha_free;}rc = scsi_add_host(shost, &pdev->dev);//register host to kernel,add struct device within shost to kernelif (rc) {dev_printk(KERN_INFO, &pdev->dev,"pm8001: failed to add shost\n");goto err_out_ha_free;}rc = pm8001_request_irq(pm8001_ha);//request irqif (rc) {dev_printk(KERN_INFO, &pdev->dev,"pm8001: failed to request irq\n");goto err_out_shost;}if(use_tasklet)tasklet_init(&pm8001_ha->tasklet, pm8001_tasklet,(unsigned long)pm8001_ha);//init taskle#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 31)blk_iopoll_init(&pm8001_ha->iopoll, pm8001_iopoll_w, pm8001_iopoll);blk_iopoll_enable(&pm8001_ha->iopoll);#endifPM8001_CHIP_DISP->interrupt_enable(pm8001_ha);pm8001_init_sas_add(pm8001_ha);pm8001_post_sas_ha_init(shost, chip);rc = sas_register_ha(SHOST_TO_SAS_HA(shost));//add phy->dev to system and init port and prep port discoveryif (rc) {dev_printk(KERN_INFO, &pdev->dev,"pm8001: failed to register  sas host\n");goto err_out_shost;}if (dif_support && IS_SPCV(pm8001_ha)) {/*turn on DIF support*//* register EEDP capabilities with SCSI layer */if (prot_mask)scsi_host_set_prot(shost, prot_mask);elsescsi_host_set_prot(shost, SHOST_DIF_TYPE1_PROTECTION |SHOST_DIF_TYPE2_PROTECTION | SHOST_DIF_TYPE3_PROTECTION);scsi_host_set_guard(shost,SHOST_DIX_GUARD_CRC);}scsi_scan_host(pm8001_ha->shost);//后面重点介绍return 0;err_out_shost:#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 31)blk_iopoll_disable(&pm8001_ha->iopoll);#endifscsi_remove_host(pm8001_ha->shost);err_out_ha_free:pm8001_free(pm8001_ha);err_out_free:KFREE(SHOST_TO_SAS_HA(shost));err_out_free_host:KFREE(shost);err_out_regions:pci_release_regions(pdev);err_out_disable:pci_disable_device(pdev);err_out_enable:return rc;}

上面是pm8001_pci_probe函数的代码和部分分析,全部的代码请到资源里下载。

标记为红色的函数在下一篇文章中介绍

原创粉丝点击