2012-08-28 15 views
9

Estoy programando un controlador PCI para Linux 2.6.36.Desarrollo del controlador de Linux: diferencia entre el controlador PCI y PCIe?

Aquí está mi código. Mi pregunta es, ¿tengo que hacer algunas modificaciones si quiero usar este controlador para un dispositivo PCIe?

#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

¿No sería pertinente llamar a 'release_mem_region' después de llamar a' pci_enable_device'? Tal como está, la región de memoria aún se asignará incluso si esta llamada falla. ¿Es quizás incluso un comportamiento sensato usar 'check_mem_region' también? – HonkyTonk

Respuesta

2

Desde el punto de vista del software, los dispositivos PCI y PCI Express son esencialmente los mismos. Los dispositivos PCIe tienen el mismo espacio de configuración, BAR y (por lo general) admiten las mismas interrupciones PCI INTx.

Ejemplo n. ° 1: Windows XP no tiene un conocimiento especial de PCIe, pero funciona bien en sistemas PCIe.

Ejemplo n. ° 2: Mi empresa ofrece versiones PCI y PCIe de una placa periférica y utilizan el mismo paquete de controladores para Windows/Linux. El conductor no "conoce" la diferencia entre las dos placas.

Sin embargo: los dispositivos PCIe frecuentemente aprovechan las características "avanzadas", como MSI, Hotplugging, espacio de configuración ampliado, etc. Muchas de estas características existían en PCI heredado, pero no se usaban. Si este es un dispositivo que está diseñando, depende de usted si implementa estas funciones avanzadas o no.

+0

No olvide que los dispositivos heredados PCIe (dispositivos PCIe que actúan como si fueran dispositivos PCI por razones de compatibilidad) implementan varias características que ya no se recomiendan. Las principales características que se me ocurren son las lecturas y escrituras de E/S, que en la práctica resultaron terriblemente ineficientes. – Joshua

3

Por lo que recuerdo, para el controlador de dispositivo que he escrito, no hay diferencia entre los dispositivos PCI y los dispositivos PCIe. El controlador de mi dispositivo usa el mismo tipo de llamadas que el tuyo: chrdev, pci_resource, irq y mem_region.

+0

¡Gracias por la respuesta! – Peter

+1

Hola @Peter, según recuerdo, los dispositivos PCIE también admiten la interrupción MSI. Entonces puede solicitar la interrupción de MSI para guardar el ciclo de la CPU. Gracias –

0

PCIe es una versión avanzada con más velocidad y capacidades. Las capacidades básicas siguen siendo las mismas para todos los estándares. El registro del controlador y el suministro de los controladores es uno y el mismo porque todos los controladores PCI se registran en el mismo subsistema PCI de Linux.

Cuestiones relacionadas