2012-08-28 28 views
9

Linux 2.6.36 için bir PCI sürücüsü programlıyorum.Linux sürücü gelişimi: PCI ve PCIe sürücüsü arasındaki fark nedir?

İşte kodum. Sorum şu: Bu sürücüyü bir PCIe aygıtı için kullanmak istersem bazı değişiklikler yapmak zorunda mıyım?

#include <linux/fs.h> 
#include <linux/module.h> 
#include <linux/init.h> 
#include <linux/pci.h> 
#include <linux/interrupt.h> 
#include <asm-generic/signal.h> 
#undef debug 


// ATTENTION copied from /uboot_for_mpc/arch/powerpc/include/asm/signal.h 
// Maybe it don't work with that 
//____________________________________________________________ 
#define SA_INTERRUPT 0x20000000 /* dummy -- ignored */ 
#define SA_SHIRQ  0x04000000 
//____________________________________________________________ 

#define pci_module_init pci_register_driver // function is obsoleted 

// Hardware specific part 
#define MY_VENDOR_ID 0x5333 
#define MY_DEVICE_ID 0x8e40 
#define MAJOR_NR  240 
#define DRIVER_NAME "PCI-Driver" 

static unsigned long ioport=0L, iolen=0L, memstart=0L, memlen=0L,flag0,flag1,flag2,temp=0L; 

// private_data 
struct _instance_data { 

    int counter; // just as a example (5-27) 

    // other instance specific data 
}; 

// Interrupt Service Routine 
static irqreturn_t pci_isr(int irq, void *dev_id, struct pt_regs *regs) 
{ 
    return IRQ_HANDLED; 
} 


// Check if this driver is for the new device 
static int device_init(struct pci_dev *dev, 
     const struct pci_device_id *id) 
{ 
    int err=0; // temp variable 

    #ifdef debug 

    flag0=pci_resource_flags(dev, 0); 
    flag1=pci_resource_flags(dev, 1); 
    flag2=pci_resource_flags(dev, 2); 
    printk("DEBUG: FLAGS0 = %u\n",flag0); 
    printk("DEBUG: FLAGS1 = %u\n",flag1); 
    printk("DEBUG: FLAGS2 = %u\n",flag2); 

    /* 
    * The following sequence checks if the resource is in the 
    * IO/Storage/Interrupt/DMA address space 
    * and prints the result in the dmesg log 
    */ 
    if(pci_resource_flags(dev,0) & IORESOURCE_IO) 
    { 
     // Ressource is in the IO address space 
     printk("DEBUG: IORESOURCE_IO\n"); 
    } 
    else if (pci_resource_flags(dev,0) & IORESOURCE_MEM) 
    { 
     // Resource is in the Storage address space 
     printk("DEBUG: IORESOURCE_MEM\n"); 
    } 
    else if (pci_resource_flags(dev,0) & IORESOURCE_IRQ) 
    { 
     // Resource is in the IRQ address space 
     printk("DEBUG: IORESOURCE_IRQ\n"); 
    } 
    else if (pci_resource_flags(dev,0) & IORESOURCE_DMA) 
    { 
     // Resource is in the DMA address space 
     printk("DEBUG: IORESOURCE_DMA\n"); 
    } 
    else 
    { 
     printk("DEBUG: NOTHING\n"); 
    } 

    #endif /* debug */ 

    // allocate memory_region 
    memstart = pci_resource_start(dev, 0); 
    memlen = pci_resource_len(dev, 0); 
    if(request_mem_region(memstart, memlen, dev->dev.kobj.name)==NULL) { 
     printk(KERN_ERR "Memory address conflict for device \"%s\"\n", 
       dev->dev.kobj.name); 
     return -EIO; 
    } 
    // allocate a interrupt 
    if(request_irq(dev->irq,pci_isr,SA_INTERRUPT|SA_SHIRQ, 
      "pci_drv",dev)) { 
     printk(KERN_ERR "pci_drv: IRQ %d not free.\n", dev->irq); 
    } 
    else 
    { 
     err=pci_enable_device(dev); 
     if(err==0)  // enable device successful 
     { 
      return 0; 
     } 
     else  // enable device not successful 
     { 
      return err; 
     } 

    } 
    // cleanup_mem 
    release_mem_region(memstart, memlen); 
    return -EIO; 
} 
// Function for deinitialization of the device 
static void device_deinit(struct pci_dev *pdev) 
{ 
    free_irq(pdev->irq, pdev); 
    if(memstart) 
     release_mem_region(memstart, memlen); 
} 

static struct file_operations pci_fops; 

static struct pci_device_id pci_drv_tbl[] __devinitdata = { 
    {  MY_VENDOR_ID,   // manufacturer identifier 
     MY_DEVICE_ID,   // device identifier 
     PCI_ANY_ID,    // subsystem manufacturer identifier 
     PCI_ANY_ID,    // subsystem device identifier 
     0,      // device class 
     0,      // mask for device class 
     0 },     // driver specific data 
     { 0, } 
}; 

static int driver_open(struct inode *geraetedatei, struct file *instance) 
{ 
    struct _instance_data *iptr; 

    iptr = (struct _instance_data *)kmalloc(sizeof(struct _instance_data), 
      GFP_KERNEL); 
    if(iptr==0) { 
     printk("not enough kernel mem\n"); 
     return -ENOMEM; 
    } 
    /* replace the following line with your instructions */ 
    iptr->counter= strlen("Hello World\n")+1; // just as a example (5-27) 

    instance->private_data = (void *)iptr; 
    return 0; 
} 

static void driver_close(struct file *instance) 
{ 
    if(instance->private_data) 
     kfree(instance->private_data); 
} 


static struct pci_driver pci_drv = { 
    .name= "pci_drv", 
      .id_table= pci_drv_tbl, 
      .probe= device_init, 
      .remove= device_deinit, 
}; 

static int __init pci_drv_init(void) 
{ // register the driver by the OS 
    if(register_chrdev(MAJOR_NR, DRIVER_NAME, &pci_fops)==0) { 
     if(pci_module_init(&pci_drv) == 0) // register by the subsystem 
      return 0; 
     unregister_chrdev(MAJOR_NR,DRIVER_NAME); // unregister if no subsystem support 
    } 
    return -EIO; 
} 

static void __exit pci_drv_exit(void) 
{ 
    pci_unregister_driver(&pci_drv); 
    unregister_chrdev(MAJOR_NR,DRIVER_NAME); 
} 

module_init(pci_drv_init); 
module_exit(pci_drv_exit); 

MODULE_LICENSE("GPL"); 
+0

'pci_enable_device' çağrıldıktan sonra' release_mem_region'ı çağırmak uygun olmaz mıydı? Bu arama başarısız olursa bile bellek bölgesi yine de tahsis edilecektir. 'Check_mem_region' da kullanmak için belki de sadece aklı başında davranış mı? – HonkyTonk

cevap

2

Yazılım açısından, PCI ve PCI Express aygıtları esas olarak aynıdır. PCIe aygıtları aynı yapılandırma alanına sahip, BAR'lar ve (genellikle) aynı PCI INTx kesmelerini destekler.

Örnek 1: Windows XP'nin PCIe hakkında özel bir bilgisi yoktur, ancak PCIe sistemlerinde düzgün çalışır.

Örnek 2: Şirketim, çevre bir anakartın hem PCI hem de PCIe sürümlerini sunar ve aynı Windows/Linux sürücü paketini kullanırlar. Sürücü, iki kart arasındaki farkı "bilmez".

Ancak, PCIe aygıtları sık sık MSI, Hotplugging, genişletilmiş yapılandırma alanı vb. "Gelişmiş" özelliklerden yararlanır. Bu özelliklerin çoğu eski PCI üzerinde var, ancak kullanılmamışlardı. Bu, tasarladığınız bir cihazsa, bu gelişmiş özellikleri uygulayıp uygulamadığınız size kalmış.

+0

PCIe eski aygıtlarının (uyumluluk nedeniyle PCI aygıtları gibi davranan PCIe aygıtları) artık tavsiye edilmeyen bir dizi özelliği uyguladıklarını unutmayın. Akla gelen ana özellikler, uygulamada çok verimsiz olduğu görülen G/Ç okumaları ve yazmalarıdır. – Joshua

3

Hatırladığım kadarıyla, yazdığım aygıt sürücüsü için, PCI aygıtları ile PCIe aygıtları arasında fark yoktur. Cihazımın sürücüsü aynı tür çağrıları kullanıyor: chrdev, pci_resource, irq ve mem_region.

+0

Cevabınız için teşekkürler! – Peter

+1

Hi @Peter, hatırladığım gibi PCIE cihazları da MSI kesintisini destekliyor. Böylece, CPU döngüsünü kaydetmek için MSI kesintisini isteyebilirsiniz. Teşekkürler –

0

PCIe, daha hızlı ve yetenekli gelişmiş bir sürümdür. Temel özellikler tüm standartlar için aynı kalır. Sürücü kaydı ve işleyicilerin sağlanması bir ve aynıdır çünkü tüm PCI sürücüleri aynı Linux PCI alt sistemine kaydolur.

İlgili konular