00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
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 }