Rev 3022 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1301 | jermar | 1 | /* |
2 | * The PCI Library -- Direct Configuration access via i386 Ports |
||
3 | * |
||
4 | * Copyright (c) 1997--2004 Martin Mares <mj@ucw.cz> |
||
5 | * |
||
1324 | jermar | 6 | * May 8, 2006 - Modified and ported to HelenOS by Jakub Jermar. |
1301 | jermar | 7 | * |
8 | * Can be freely distributed and used under the terms of the GNU GPL. |
||
9 | */ |
||
10 | |||
11 | #include <unistd.h> |
||
4204 | trochtova | 12 | #include <ddi.h> |
13 | #include <libarch/ddi.h> |
||
1301 | jermar | 14 | |
15 | #include "internal.h" |
||
16 | |||
17 | |||
1302 | jermar | 18 | static void conf12_init(struct pci_access *a) |
1301 | jermar | 19 | { |
20 | } |
||
21 | |||
1302 | jermar | 22 | static void conf12_cleanup(struct pci_access *a UNUSED) |
1301 | jermar | 23 | { |
24 | } |
||
25 | |||
26 | /* |
||
27 | * Before we decide to use direct hardware access mechanisms, we try to do some |
||
28 | * trivial checks to ensure it at least _seems_ to be working -- we just test |
||
29 | * whether bus 00 contains a host bridge (this is similar to checking |
||
30 | * techniques used in XFree86, but ours should be more reliable since we |
||
31 | * attempt to make use of direct access hints provided by the PCI BIOS). |
||
32 | * |
||
33 | * This should be close to trivial, but it isn't, because there are buggy |
||
34 | * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID. |
||
35 | */ |
||
36 | |||
1302 | jermar | 37 | static int intel_sanity_check(struct pci_access *a, struct pci_methods *m) |
1301 | jermar | 38 | { |
1302 | jermar | 39 | struct pci_dev d; |
1301 | jermar | 40 | |
1302 | jermar | 41 | a->debug("...sanity check"); |
42 | d.bus = 0; |
||
43 | d.func = 0; |
||
44 | for (d.dev = 0; d.dev < 32; d.dev++) { |
||
45 | u16 class, vendor; |
||
1307 | jermar | 46 | if (m->read(&d, PCI_CLASS_DEVICE, (byte *) & class, |
1302 | jermar | 47 | sizeof(class)) |
48 | && (class == cpu_to_le16(PCI_CLASS_BRIDGE_HOST) |
||
49 | || class == cpu_to_le16(PCI_CLASS_DISPLAY_VGA)) |
||
50 | || m->read(&d, PCI_VENDOR_ID, (byte *) & vendor, |
||
51 | sizeof(vendor)) |
||
52 | && (vendor == cpu_to_le16(PCI_VENDOR_ID_INTEL) |
||
53 | || vendor == cpu_to_le16(PCI_VENDOR_ID_COMPAQ))) { |
||
54 | a->debug("...outside the Asylum at 0/%02x/0", |
||
55 | d.dev); |
||
56 | return 1; |
||
57 | } |
||
1301 | jermar | 58 | } |
1302 | jermar | 59 | a->debug("...insane"); |
60 | return 0; |
||
1301 | jermar | 61 | } |
62 | |||
63 | /* |
||
64 | * Configuration type 1 |
||
65 | */ |
||
66 | |||
67 | #define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3)) |
||
68 | |||
1302 | jermar | 69 | static int conf1_detect(struct pci_access *a) |
1301 | jermar | 70 | { |
1302 | jermar | 71 | unsigned int tmp; |
72 | int res = 0; |
||
1301 | jermar | 73 | |
4204 | trochtova | 74 | pio_write_8(0xCFB, 0x01); |
75 | tmp = pio_read_32(0xCF8); |
||
76 | pio_write_32(0xCF8, 0x80000000); |
||
77 | if (pio_read_32(0xCF8) == 0x80000000) { |
||
1302 | jermar | 78 | res = 1; |
4204 | trochtova | 79 | } |
80 | pio_write_32(0xCF8, tmp); |
||
81 | if (res) { |
||
1302 | jermar | 82 | res = intel_sanity_check(a, &pm_intel_conf1); |
4204 | trochtova | 83 | } |
1302 | jermar | 84 | return res; |
1301 | jermar | 85 | } |
86 | |||
1302 | jermar | 87 | static int conf1_read(struct pci_dev *d, int pos, byte * buf, int len) |
1301 | jermar | 88 | { |
1302 | jermar | 89 | int addr = 0xcfc + (pos & 3); |
1301 | jermar | 90 | |
1302 | jermar | 91 | if (pos >= 256) |
92 | return 0; |
||
1301 | jermar | 93 | |
4204 | trochtova | 94 | pio_write_32(0xcf8, 0x80000000 | ((d->bus & 0xff) << 16) | |
95 | (PCI_DEVFN(d->dev, d->func) << 8) | (pos & ~3)); |
||
1301 | jermar | 96 | |
1302 | jermar | 97 | switch (len) { |
98 | case 1: |
||
4204 | trochtova | 99 | buf[0] = pio_read_8(addr); |
1302 | jermar | 100 | break; |
101 | case 2: |
||
4204 | trochtova | 102 | ((u16 *) buf)[0] = cpu_to_le16(pio_read_16(addr)); |
1302 | jermar | 103 | break; |
104 | case 4: |
||
4204 | trochtova | 105 | ((u32 *) buf)[0] = cpu_to_le32(pio_read_32(addr)); |
1302 | jermar | 106 | break; |
107 | default: |
||
108 | return pci_generic_block_read(d, pos, buf, len); |
||
109 | } |
||
110 | return 1; |
||
1301 | jermar | 111 | } |
112 | |||
1302 | jermar | 113 | static int conf1_write(struct pci_dev *d, int pos, byte * buf, int len) |
1301 | jermar | 114 | { |
1302 | jermar | 115 | int addr = 0xcfc + (pos & 3); |
1301 | jermar | 116 | |
1302 | jermar | 117 | if (pos >= 256) |
118 | return 0; |
||
1301 | jermar | 119 | |
4204 | trochtova | 120 | pio_write_32(0xcf8, 0x80000000 | ((d->bus & 0xff) << 16) | |
121 | (PCI_DEVFN(d->dev, d->func) << 8) | (pos & ~3)); |
||
1301 | jermar | 122 | |
1302 | jermar | 123 | switch (len) { |
124 | case 1: |
||
4204 | trochtova | 125 | pio_write_8(addr, buf[0]); |
1302 | jermar | 126 | break; |
127 | case 2: |
||
4204 | trochtova | 128 | pio_write_16(addr, le16_to_cpu(((u16 *) buf)[0])); |
1302 | jermar | 129 | break; |
130 | case 4: |
||
4204 | trochtova | 131 | pio_write_32(addr, le32_to_cpu(((u32 *) buf)[0])); |
1302 | jermar | 132 | break; |
133 | default: |
||
134 | return pci_generic_block_write(d, pos, buf, len); |
||
135 | } |
||
136 | return 1; |
||
1301 | jermar | 137 | } |
138 | |||
139 | /* |
||
140 | * Configuration type 2. Obsolete and brain-damaged, but existing. |
||
141 | */ |
||
142 | |||
1302 | jermar | 143 | static int conf2_detect(struct pci_access *a) |
1301 | jermar | 144 | { |
1302 | jermar | 145 | /* This is ugly and tends to produce false positives. Beware. */ |
4204 | trochtova | 146 | pio_write_8(0xCFB, 0x00); |
147 | pio_write_8(0xCF8, 0x00); |
||
148 | pio_write_8(0xCFA, 0x00); |
||
149 | if (pio_read_8(0xCF8) == 0x00 && pio_read_8(0xCFA) == 0x00) |
||
1302 | jermar | 150 | return intel_sanity_check(a, &pm_intel_conf2); |
151 | else |
||
152 | return 0; |
||
1301 | jermar | 153 | } |
154 | |||
1302 | jermar | 155 | static int conf2_read(struct pci_dev *d, int pos, byte * buf, int len) |
1301 | jermar | 156 | { |
1302 | jermar | 157 | int addr = 0xc000 | (d->dev << 8) | pos; |
1301 | jermar | 158 | |
1302 | jermar | 159 | if (pos >= 256) |
160 | return 0; |
||
1301 | jermar | 161 | |
1302 | jermar | 162 | if (d->dev >= 16) |
163 | /* conf2 supports only 16 devices per bus */ |
||
164 | return 0; |
||
4204 | trochtova | 165 | pio_write_8(0xcf8, (d->func << 1) | 0xf0); |
166 | pio_write_8(0xcfa, d->bus); |
||
1302 | jermar | 167 | switch (len) { |
168 | case 1: |
||
4204 | trochtova | 169 | buf[0] = pio_read_8(addr); |
1302 | jermar | 170 | break; |
171 | case 2: |
||
4204 | trochtova | 172 | ((u16 *) buf)[0] = cpu_to_le16(pio_read_16(addr)); |
1302 | jermar | 173 | break; |
174 | case 4: |
||
4204 | trochtova | 175 | ((u32 *) buf)[0] = cpu_to_le32(pio_read_32(addr)); |
1302 | jermar | 176 | break; |
177 | default: |
||
4204 | trochtova | 178 | pio_write_8(0xcf8, 0); |
1302 | jermar | 179 | return pci_generic_block_read(d, pos, buf, len); |
180 | } |
||
4204 | trochtova | 181 | pio_write_8((void *)0xcf8, 0); |
1302 | jermar | 182 | return 1; |
1301 | jermar | 183 | } |
184 | |||
1302 | jermar | 185 | static int conf2_write(struct pci_dev *d, int pos, byte * buf, int len) |
1301 | jermar | 186 | { |
1302 | jermar | 187 | int addr = 0xc000 | (d->dev << 8) | pos; |
1301 | jermar | 188 | |
1302 | jermar | 189 | if (pos >= 256) |
190 | return 0; |
||
1301 | jermar | 191 | |
1302 | jermar | 192 | if (d->dev >= 16) |
1307 | jermar | 193 | d->access->error("conf2_write: only first 16 devices exist."); |
4204 | trochtova | 194 | pio_write_8(0xcf8, (d->func << 1) | 0xf0); |
195 | pio_write_8(0xcfa, d->bus); |
||
1302 | jermar | 196 | switch (len) { |
197 | case 1: |
||
4204 | trochtova | 198 | pio_write_8(addr, buf[0]); |
1302 | jermar | 199 | break; |
200 | case 2: |
||
4204 | trochtova | 201 | pio_write_16(addr, le16_to_cpu(*(u16 *) buf)); |
1302 | jermar | 202 | break; |
203 | case 4: |
||
4204 | trochtova | 204 | pio_write_32(addr, le32_to_cpu(*(u32 *) buf)); |
1302 | jermar | 205 | break; |
206 | default: |
||
4204 | trochtova | 207 | pio_write_8(0xcf8, 0); |
1302 | jermar | 208 | return pci_generic_block_write(d, pos, buf, len); |
209 | } |
||
4204 | trochtova | 210 | pio_write_8(0xcf8, 0); |
1302 | jermar | 211 | return 1; |
1301 | jermar | 212 | } |
213 | |||
214 | struct pci_methods pm_intel_conf1 = { |
||
1302 | jermar | 215 | "Intel-conf1", |
216 | NULL, /* config */ |
||
217 | conf1_detect, |
||
218 | conf12_init, |
||
219 | conf12_cleanup, |
||
220 | pci_generic_scan, |
||
221 | pci_generic_fill_info, |
||
222 | conf1_read, |
||
223 | conf1_write, |
||
224 | NULL, /* init_dev */ |
||
225 | NULL /* cleanup_dev */ |
||
1301 | jermar | 226 | }; |
227 | |||
228 | struct pci_methods pm_intel_conf2 = { |
||
1302 | jermar | 229 | "Intel-conf2", |
230 | NULL, /* config */ |
||
231 | conf2_detect, |
||
232 | conf12_init, |
||
233 | conf12_cleanup, |
||
234 | pci_generic_scan, |
||
235 | pci_generic_fill_info, |
||
236 | conf2_read, |
||
237 | conf2_write, |
||
238 | NULL, /* init_dev */ |
||
239 | NULL /* cleanup_dev */ |
||
1301 | jermar | 240 | }; |