Main Page | Directories | File List | Globals

pcibus_ops.c

Go to the documentation of this file.
00001 /*
00002  * kernel_drivers/adi_buses/pci/pcibus_ops.c
00003  *
00004  * Copyright (c) 2003-2004 Lukasz Dembinski <dembol@nasa.com.pl>
00005  * All Rights Reserved
00006  * 
00007  * Date:        2004/06
00008  * Author:      Lukasz Dembinski
00009  * Info:        pcibus_ops.c core file
00010  * Contact:     mailto: <dembol@nasa.com.pl>
00011  *
00012  */
00013 
00014 #include <agnix/agnix.h>
00015 #include <agnix/adi/adi.h>
00016 #include <agnix/ioport.h>
00017 #include <agnix/console.h>
00018 
00019 #define MOD_NAME        "PCI: \t\t"
00020 
00021 #define PCIBUS_ADDRESS_1(bus, device, fn, reg)  ((u32)(0x80000000 | (bus << 16) | (device << 11) | (fn << 8) | (reg & ~3)))
00022 #define PCIBUS_ADDRESS_2(device, reg)           ((u16)(0xC000 | (device << 8) | (reg & 0xFF)))
00023 
00024 #define PCIBUS_CONF_ADDR_1      0xCF8
00025 #define PCIBUS_CONF_DATA_1      0xCFC
00026 
00027 #define PCIBUS_CONF_FN_2        0xCF8
00028 #define PCIBUS_CONF_BUS_2       0xCFA
00029 
00030 struct pcibus_ops_s pcibus_primary_ops;
00031 
00032 int pcibus_direct_send_address_1(struct pcidev_s *pcidev, int reg)
00033 {
00034     int dev_bus  = PCIDEV_BUS(pcidev);
00035     int dev_slot = PCIDEV_SLOT(pcidev);
00036     int dev_fn   = PCIDEV_FN(pcidev);  
00037 
00038     if (reg < 0 || reg > 255) {
00039         printk(MOD_NAME "wrong values in pcibus_direct_read_1 (bus=%02x slot=%02x fn=%01x reg=%d\n", 
00040                dev_bus, dev_slot, dev_fn, reg);
00041         return -1;
00042     }
00043 
00044     outl(PCIBUS_ADDRESS_1(dev_bus, dev_slot, dev_fn, reg), PCIBUS_CONF_ADDR_1);
00045     
00046     return 0;
00047 }
00048 
00049 int pcibus_read_config_1(struct pcidev_s *pcidev, int reg, u32 *value, int len)
00050 {
00051     pcibus_direct_send_address_1(pcidev, reg);
00052     
00053     switch(len) {
00054         case 4: *value = inl(PCIBUS_CONF_DATA_1);
00055                 break;
00056         case 2: *(u16 *)value = inw(PCIBUS_CONF_DATA_1 + (reg & 0x02)); 
00057                 break;
00058         case 1: *(u8  *)value = inb(PCIBUS_CONF_DATA_1 + (reg & 0x03));
00059     }
00060         
00061     return 0;    
00062 }
00063 
00064 int pcibus_write_config_1(struct pcidev_s *pcidev, int reg, u32 value, int len)
00065 {
00066     pcibus_direct_send_address_1(pcidev, reg);
00067     
00068     switch(len) {
00069         case 4: outl(value, PCIBUS_CONF_DATA_1);
00070                 break;
00071         case 2: outw((u16)(value), PCIBUS_CONF_DATA_1 + (reg & 0x02));
00072                 break;
00073         case 1: outb((u8) (value), PCIBUS_CONF_DATA_1 + (reg & 0x03));
00074     }
00075         
00076     return 0;    
00077 }
00078 
00079 int pcibus_direct_send_address_2(struct pcidev_s *pcidev, int reg)
00080 {
00081     int dev_bus  = PCIDEV_BUS(pcidev);
00082     int dev_slot = PCIDEV_SLOT(pcidev);
00083     int dev_fn   = PCIDEV_FN(pcidev);  
00084 
00085     if (reg > 255) {
00086         printk(MOD_NAME "wrong values in pcibus_direct_read_1 (bus=%02x slot=%02x fn=%01x reg=%02x\n", 
00087                dev_bus, dev_slot, dev_fn, reg);
00088         return -1;
00089     }
00090 
00091     outl(0xF0 | (dev_fn << 1), PCIBUS_CONF_BUS_2);
00092     outl(dev_bus, PCIBUS_CONF_BUS_2);
00093     
00094     return 0;
00095 }
00096 
00097 int pcibus_read_config_2(struct pcidev_s *pcidev, int reg, u32 *value, int len)
00098 {
00099     int dev_slot = PCIDEV_SLOT(pcidev);
00100 
00101     pcibus_direct_send_address_2(pcidev, reg);
00102     
00103     switch(len) {
00104         case 4: *value = inl(PCIBUS_ADDRESS_2(dev_slot, reg));
00105                 break;
00106         case 2: *(u16 *)value = inw(PCIBUS_ADDRESS_2(dev_slot, reg));
00107                 break;
00108         case 1: *(u8  *)value = inb(PCIBUS_ADDRESS_2(dev_slot, reg));
00109     }
00110         
00111     return 0;    
00112 }
00113 
00114 int pcibus_write_config_2(struct pcidev_s *pcidev, int reg, u32 value, int len)
00115 {
00116     int dev_slot = PCIDEV_SLOT(pcidev);
00117 
00118     pcibus_direct_send_address_2(pcidev, reg);
00119     
00120     switch(len) {
00121         case 4: outl((u32)(value), PCIBUS_ADDRESS_2(dev_slot, reg));
00122                 break;
00123         case 2: outw((u16)(value), PCIBUS_ADDRESS_2(dev_slot, reg));
00124                 break;
00125         case 1: outb((u8) (value), PCIBUS_ADDRESS_2(dev_slot, reg));
00126     }
00127         
00128     return 0;    
00129 }
00130 
00131 int pcibus_check_direct_access_1(void)
00132 {
00133     u32 saved_value;
00134     u32 write_value = 0x80000000;
00135     u32 read_value;
00136 
00137     outb(0x01, 0xCFB);    
00138     saved_value = inl(PCIBUS_CONF_ADDR_1);
00139     
00140     outl(write_value, PCIBUS_CONF_ADDR_1);
00141     read_value = inl(PCIBUS_CONF_ADDR_1);
00142     
00143     if (read_value == write_value) {
00144         outl(saved_value, PCIBUS_CONF_ADDR_1);
00145         printk(MOD_NAME "detected type 1 direct access to PCI configuration space\n");
00146         return 0;
00147     }
00148     
00149     outl(saved_value, PCIBUS_CONF_ADDR_1);
00150     
00151     return -1;
00152 }
00153 
00154 int pcibus_check_direct_access_2(void)
00155 {
00156     u8 saved_bus;
00157     u8 saved_fn;
00158     u8 read_bus;
00159     u8 read_fn;
00160     
00161     outb(0x00, 0xCFB);    
00162     
00163     saved_fn  = inb(PCIBUS_CONF_FN_2);
00164     saved_bus = inb(PCIBUS_CONF_BUS_2);
00165 
00166     outb(0x00, PCIBUS_CONF_FN_2);
00167     outb(0x00, PCIBUS_CONF_BUS_2);
00168 
00169     read_fn  = inb(PCIBUS_CONF_FN_2);
00170     read_bus = inb(PCIBUS_CONF_BUS_2);
00171 
00172     if (read_fn == 0x00 && read_bus == 0x00) {
00173         outl(saved_fn, PCIBUS_CONF_FN_2);
00174         outl(saved_bus, PCIBUS_CONF_BUS_2);
00175         printk(MOD_NAME "detected type 2 direct access to PCI configuration space\n");
00176         return 0;
00177     }
00178     
00179     return -1;
00180 }
00181 
00182 int pcibus_check_direct_access(void)
00183 {
00184     if (pcibus_check_direct_access_1() == 0) {
00185         pcibus_primary_ops.pcibus_read_config  = pcibus_read_config_1;
00186         pcibus_primary_ops.pcibus_write_config = pcibus_write_config_1;
00187         return 0;
00188     } else
00189     if (pcibus_check_direct_access_2() == 0) {
00190         pcibus_primary_ops.pcibus_read_config  = pcibus_read_config_2;
00191         pcibus_primary_ops.pcibus_write_config = pcibus_write_config_2;
00192         return 0;
00193     }
00194     
00195     return -1;
00196 }
00197 
00198 int pcibus_ops_init(void)
00199 {
00200     printk(MOD_NAME "initializing pcibus_ops\n");
00201 
00202     if (pcibus_check_direct_access() < 0) {
00203         printk(MOD_NAME "can not detect access to PCI configuration space\n");
00204         return -1;
00205     }
00206 
00207     return 0;
00208 }
Dokumentacje wygenerowano programem Doxygen 1.4.2 dla projektu Agnix