Rev 1301 | Rev 1307 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1301 | Rev 1302 | ||
---|---|---|---|
Line 12... | Line 12... | ||
12 | 12 | ||
13 | #include "internal.h" |
13 | #include "internal.h" |
14 | 14 | ||
15 | static inline void outb(u8 b, u16 port) |
15 | static inline void outb(u8 b, u16 port) |
16 | { |
16 | { |
17 | asm volatile ("outb %0, %1\n" : : "a" (b), "d" (port)); |
17 | asm volatile ("outb %0, %1\n" :: "a" (b), "d" (port)); |
18 | } |
18 | } |
19 | 19 | ||
20 | static inline void outw(u16 w, u16 port) |
20 | static inline void outw(u16 w, u16 port) |
21 | { |
21 | { |
22 | asm volatile ("outw %0, %1\n" : : "a" (w), "d" (port)); |
22 | asm volatile ("outw %0, %1\n" :: "a" (w), "d" (port)); |
23 | } |
23 | } |
24 | 24 | ||
25 | static inline void outl(u32 l, u16 port) |
25 | static inline void outl(u32 l, u16 port) |
26 | { |
26 | { |
27 | asm volatile ("outl %0, %1\n" : : "a" (l), "d" (port)); |
27 | asm volatile ("outl %0, %1\n" :: "a" (l), "d" (port)); |
28 | } |
28 | } |
29 | 29 | ||
30 | static inline u8 inb(u16 port) |
30 | static inline u8 inb(u16 port) |
31 | { |
31 | { |
32 | u8 val; |
32 | u8 val; |
33 | 33 | ||
34 | asm volatile ("inb %1, %0 \n" : "=a" (val) : "d" (port)); |
34 | asm volatile ("inb %1, %0 \n" : "=a" (val) : "d"(port)); |
35 | return val; |
35 | return val; |
36 | } |
36 | } |
37 | 37 | ||
38 | static inline u16 inw(u16 port) |
38 | static inline u16 inw(u16 port) |
39 | { |
39 | { |
40 | u16 val; |
40 | u16 val; |
41 | 41 | ||
42 | asm volatile ("inw %1, %0 \n" : "=a" (val) : "d" (port)); |
42 | asm volatile ("inw %1, %0 \n" : "=a" (val) : "d"(port)); |
43 | return val; |
43 | return val; |
44 | } |
44 | } |
45 | 45 | ||
46 | static inline u32 inl(u16 port) |
46 | static inline u32 inl(u16 port) |
47 | { |
47 | { |
48 | u32 val; |
48 | u32 val; |
49 | 49 | ||
50 | asm volatile ("inl %1, %0 \n" : "=a" (val) : "d" (port)); |
50 | asm volatile ("inl %1, %0 \n" : "=a" (val) : "d"(port)); |
51 | return val; |
51 | return val; |
52 | } |
52 | } |
53 | 53 | ||
54 | static void |
- | |
55 | conf12_init(struct pci_access *a) |
54 | static void conf12_init(struct pci_access *a) |
56 | { |
55 | { |
57 | } |
56 | } |
58 | 57 | ||
59 | static void |
- | |
60 | conf12_cleanup(struct pci_access *a UNUSED) |
58 | static void conf12_cleanup(struct pci_access *a UNUSED) |
61 | { |
59 | { |
62 | } |
60 | } |
63 | 61 | ||
64 | /* |
62 | /* |
65 | * Before we decide to use direct hardware access mechanisms, we try to do some |
63 | * Before we decide to use direct hardware access mechanisms, we try to do some |
Line 70... | Line 68... | ||
70 | * |
68 | * |
71 | * This should be close to trivial, but it isn't, because there are buggy |
69 | * This should be close to trivial, but it isn't, because there are buggy |
72 | * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID. |
70 | * chipsets (yes, you guessed it, by Intel and Compaq) that have no class ID. |
73 | */ |
71 | */ |
74 | 72 | ||
75 | static int |
- | |
76 | intel_sanity_check(struct pci_access *a, struct pci_methods *m) |
73 | static int intel_sanity_check(struct pci_access *a, struct pci_methods *m) |
77 | { |
74 | { |
78 | struct pci_dev d; |
75 | struct pci_dev d; |
79 | 76 | ||
80 | a->debug("...sanity check"); |
77 | a->debug("...sanity check"); |
81 | d.bus = 0; |
78 | d.bus = 0; |
82 | d.func = 0; |
79 | d.func = 0; |
83 | for(d.dev = 0; d.dev < 32; d.dev++) |
80 | for (d.dev = 0; d.dev < 32; d.dev++) { |
84 | { |
- | |
85 | u16 class, vendor; |
81 | u16 class, vendor; |
- | 82 | if (m-> |
|
86 | if (m->read(&d, PCI_CLASS_DEVICE, (byte *) &class, sizeof(class)) && |
83 | read(&d, PCI_CLASS_DEVICE, (byte *) & class, |
- | 84 | sizeof(class)) |
|
- | 85 | && (class == cpu_to_le16(PCI_CLASS_BRIDGE_HOST) |
|
87 | (class == cpu_to_le16(PCI_CLASS_BRIDGE_HOST) || class == cpu_to_le16(PCI_CLASS_DISPLAY_VGA)) || |
86 | || class == cpu_to_le16(PCI_CLASS_DISPLAY_VGA)) |
88 | m->read(&d, PCI_VENDOR_ID, (byte *) &vendor, sizeof(vendor)) && |
87 | || m->read(&d, PCI_VENDOR_ID, (byte *) & vendor, |
- | 88 | sizeof(vendor)) |
|
- | 89 | && (vendor == cpu_to_le16(PCI_VENDOR_ID_INTEL) |
|
89 | (vendor == cpu_to_le16(PCI_VENDOR_ID_INTEL) || vendor == cpu_to_le16(PCI_VENDOR_ID_COMPAQ))) |
90 | || vendor == cpu_to_le16(PCI_VENDOR_ID_COMPAQ))) { |
90 | { |
- | |
91 | a->debug("...outside the Asylum at 0/%02x/0", d.dev); |
91 | a->debug("...outside the Asylum at 0/%02x/0", |
- | 92 | d.dev); |
|
92 | return 1; |
93 | return 1; |
- | 94 | } |
|
93 | } |
95 | } |
94 | } |
- | |
95 | a->debug("...insane"); |
96 | a->debug("...insane"); |
96 | return 0; |
97 | return 0; |
97 | } |
98 | } |
98 | 99 | ||
99 | /* |
100 | /* |
100 | * Configuration type 1 |
101 | * Configuration type 1 |
101 | */ |
102 | */ |
102 | 103 | ||
103 | #define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3)) |
104 | #define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3)) |
104 | 105 | ||
105 | static int |
- | |
106 | conf1_detect(struct pci_access *a) |
106 | static int conf1_detect(struct pci_access *a) |
107 | { |
107 | { |
108 | unsigned int tmp; |
108 | unsigned int tmp; |
109 | int res = 0; |
109 | int res = 0; |
110 | 110 | ||
111 | outb (0x01, 0xCFB); |
111 | outb(0x01, 0xCFB); |
112 | tmp = inl (0xCF8); |
112 | tmp = inl(0xCF8); |
113 | outl (0x80000000, 0xCF8); |
113 | outl(0x80000000, 0xCF8); |
114 | if (inl (0xCF8) == 0x80000000) |
114 | if (inl(0xCF8) == 0x80000000) |
115 | res = 1; |
115 | res = 1; |
116 | outl (tmp, 0xCF8); |
116 | outl(tmp, 0xCF8); |
117 | if (res) |
117 | if (res) |
118 | res = intel_sanity_check(a, &pm_intel_conf1); |
118 | res = intel_sanity_check(a, &pm_intel_conf1); |
119 | return res; |
119 | return res; |
120 | } |
120 | } |
121 | 121 | ||
122 | static int |
- | |
123 | conf1_read(struct pci_dev *d, int pos, byte *buf, int len) |
122 | static int conf1_read(struct pci_dev *d, int pos, byte * buf, int len) |
124 | { |
123 | { |
125 | int addr = 0xcfc + (pos&3); |
124 | int addr = 0xcfc + (pos & 3); |
126 | 125 | ||
127 | if (pos >= 256) |
126 | if (pos >= 256) |
128 | return 0; |
127 | return 0; |
129 | 128 | ||
- | 129 | outl(0x80000000 | ((d->bus & 0xff) << 16) | |
|
130 | outl(0x80000000 | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos&~3), 0xcf8); |
130 | (PCI_DEVFN(d->dev, d->func) << 8) | (pos & ~3), 0xcf8); |
131 | 131 | ||
132 | switch (len) |
132 | switch (len) { |
133 | { |
- | |
134 | case 1: |
133 | case 1: |
135 | buf[0] = inb(addr); |
134 | buf[0] = inb(addr); |
136 | break; |
135 | break; |
137 | case 2: |
136 | case 2: |
138 | ((u16 *) buf)[0] = cpu_to_le16(inw(addr)); |
137 | ((u16 *) buf)[0] = cpu_to_le16(inw(addr)); |
139 | break; |
138 | break; |
140 | case 4: |
139 | case 4: |
141 | ((u32 *) buf)[0] = cpu_to_le32(inl(addr)); |
140 | ((u32 *) buf)[0] = cpu_to_le32(inl(addr)); |
142 | break; |
141 | break; |
143 | default: |
142 | default: |
144 | return pci_generic_block_read(d, pos, buf, len); |
143 | return pci_generic_block_read(d, pos, buf, len); |
145 | } |
144 | } |
146 | return 1; |
145 | return 1; |
147 | } |
146 | } |
148 | 147 | ||
149 | static int |
- | |
150 | conf1_write(struct pci_dev *d, int pos, byte *buf, int len) |
148 | static int conf1_write(struct pci_dev *d, int pos, byte * buf, int len) |
151 | { |
149 | { |
152 | int addr = 0xcfc + (pos&3); |
150 | int addr = 0xcfc + (pos & 3); |
153 | 151 | ||
154 | if (pos >= 256) |
152 | if (pos >= 256) |
155 | return 0; |
153 | return 0; |
156 | 154 | ||
- | 155 | outl(0x80000000 | ((d->bus & 0xff) << 16) | |
|
157 | outl(0x80000000 | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos&~3), 0xcf8); |
156 | (PCI_DEVFN(d->dev, d->func) << 8) | (pos & ~3), 0xcf8); |
158 | 157 | ||
159 | switch (len) |
158 | switch (len) { |
160 | { |
- | |
161 | case 1: |
159 | case 1: |
162 | outb(buf[0], addr); |
160 | outb(buf[0], addr); |
163 | break; |
161 | break; |
164 | case 2: |
162 | case 2: |
165 | outw(le16_to_cpu(((u16 *) buf)[0]), addr); |
163 | outw(le16_to_cpu(((u16 *) buf)[0]), addr); |
166 | break; |
164 | break; |
167 | case 4: |
165 | case 4: |
168 | outl(le32_to_cpu(((u32 *) buf)[0]), addr); |
166 | outl(le32_to_cpu(((u32 *) buf)[0]), addr); |
169 | break; |
167 | break; |
170 | default: |
168 | default: |
171 | return pci_generic_block_write(d, pos, buf, len); |
169 | return pci_generic_block_write(d, pos, buf, len); |
172 | } |
170 | } |
173 | return 1; |
171 | return 1; |
174 | } |
172 | } |
175 | 173 | ||
176 | /* |
174 | /* |
177 | * Configuration type 2. Obsolete and brain-damaged, but existing. |
175 | * Configuration type 2. Obsolete and brain-damaged, but existing. |
178 | */ |
176 | */ |
179 | 177 | ||
180 | static int |
- | |
181 | conf2_detect(struct pci_access *a) |
178 | static int conf2_detect(struct pci_access *a) |
182 | { |
179 | { |
183 | /* This is ugly and tends to produce false positives. Beware. */ |
180 | /* This is ugly and tends to produce false positives. Beware. */ |
- | 181 | ||
- | 182 | outb(0x00, 0xCFB); |
|
- | 183 | outb(0x00, 0xCF8); |
|
- | 184 | outb(0x00, 0xCFA); |
|
- | 185 | if (inb(0xCF8) == 0x00 && inb(0xCFA) == 0x00) |
|
- | 186 | return intel_sanity_check(a, &pm_intel_conf2); |
|
- | 187 | else |
|
- | 188 | return 0; |
|
- | 189 | } |
|
- | 190 | ||
- | 191 | static int conf2_read(struct pci_dev *d, int pos, byte * buf, int len) |
|
- | 192 | { |
|
- | 193 | int addr = 0xc000 | (d->dev << 8) | pos; |
|
- | 194 | ||
- | 195 | if (pos >= 256) |
|
- | 196 | return 0; |
|
- | 197 | ||
- | 198 | if (d->dev >= 16) |
|
- | 199 | /* conf2 supports only 16 devices per bus */ |
|
- | 200 | return 0; |
|
- | 201 | outb((d->func << 1) | 0xf0, 0xcf8); |
|
- | 202 | outb(d->bus, 0xcfa); |
|
- | 203 | switch (len) { |
|
- | 204 | case 1: |
|
- | 205 | buf[0] = inb(addr); |
|
- | 206 | break; |
|
- | 207 | case 2: |
|
- | 208 | ((u16 *) buf)[0] = cpu_to_le16(inw(addr)); |
|
- | 209 | break; |
|
- | 210 | case 4: |
|
- | 211 | ((u32 *) buf)[0] = cpu_to_le32(inl(addr)); |
|
- | 212 | break; |
|
- | 213 | default: |
|
- | 214 | outb(0, 0xcf8); |
|
- | 215 | return pci_generic_block_read(d, pos, buf, len); |
|
- | 216 | } |
|
- | 217 | outb(0, 0xcf8); |
|
- | 218 | return 1; |
|
- | 219 | } |
|
184 | 220 | ||
185 | outb(0x00, 0xCFB); |
- | |
186 | outb(0x00, 0xCF8); |
- | |
187 | outb(0x00, 0xCFA); |
- | |
188 | if (inb(0xCF8) == 0x00 && inb(0xCFA) == 0x00) |
- | |
189 | return intel_sanity_check(a, &pm_intel_conf2); |
- | |
190 | else |
- | |
191 | return 0; |
- | |
192 | } |
- | |
193 | - | ||
194 | static int |
- | |
195 | conf2_read(struct pci_dev *d, int pos, byte *buf, int len) |
221 | static int conf2_write(struct pci_dev *d, int pos, byte * buf, int len) |
196 | { |
222 | { |
197 | int addr = 0xc000 | (d->dev << 8) | pos; |
223 | int addr = 0xc000 | (d->dev << 8) | pos; |
198 | 224 | ||
199 | if (pos >= 256) |
225 | if (pos >= 256) |
200 | return 0; |
226 | return 0; |
201 | 227 | ||
202 | if (d->dev >= 16) |
228 | if (d->dev >= 16) |
203 | /* conf2 supports only 16 devices per bus */ |
- | |
204 | return 0; |
- | |
205 | outb((d->func << 1) | 0xf0, 0xcf8); |
- | |
206 | outb(d->bus, 0xcfa); |
- | |
207 | switch (len) |
- | |
208 | { |
- | |
209 | case 1: |
- | |
210 | buf[0] = inb(addr); |
- | |
211 | break; |
- | |
212 | case 2: |
- | |
213 | ((u16 *) buf)[0] = cpu_to_le16(inw(addr)); |
- | |
214 | break; |
- | |
215 | case 4: |
229 | d->access-> |
216 | ((u32 *) buf)[0] = cpu_to_le32(inl(addr)); |
- | |
217 | break; |
- | |
218 | default: |
- | |
219 | outb(0, 0xcf8); |
- | |
220 | return pci_generic_block_read(d, pos, buf, len); |
- | |
221 | } |
- | |
222 | outb(0, 0xcf8); |
- | |
223 | return 1; |
- | |
224 | } |
- | |
225 | - | ||
226 | static int |
- | |
227 | conf2_write(struct pci_dev *d, int pos, byte *buf, int len) |
- | |
228 | { |
- | |
229 | int addr = 0xc000 | (d->dev << 8) | pos; |
- | |
230 | - | ||
231 | if (pos >= 256) |
- | |
232 | return 0; |
- | |
233 | - | ||
234 | if (d->dev >= 16) |
- | |
235 | d->access->error("conf2_write: only first 16 devices exist."); |
230 | error("conf2_write: only first 16 devices exist."); |
236 | outb((d->func << 1) | 0xf0, 0xcf8); |
231 | outb((d->func << 1) | 0xf0, 0xcf8); |
237 | outb(d->bus, 0xcfa); |
232 | outb(d->bus, 0xcfa); |
238 | switch (len) |
233 | switch (len) { |
239 | { |
- | |
240 | case 1: |
234 | case 1: |
241 | outb(buf[0], addr); |
235 | outb(buf[0], addr); |
242 | break; |
236 | break; |
243 | case 2: |
237 | case 2: |
244 | outw(le16_to_cpu(* (u16 *) buf), addr); |
238 | outw(le16_to_cpu(*(u16 *) buf), addr); |
245 | break; |
239 | break; |
246 | case 4: |
240 | case 4: |
247 | outl(le32_to_cpu(* (u32 *) buf), addr); |
241 | outl(le32_to_cpu(*(u32 *) buf), addr); |
248 | break; |
242 | break; |
249 | default: |
243 | default: |
250 | outb(0, 0xcf8); |
244 | outb(0, 0xcf8); |
251 | return pci_generic_block_write(d, pos, buf, len); |
245 | return pci_generic_block_write(d, pos, buf, len); |
252 | } |
246 | } |
253 | outb(0, 0xcf8); |
247 | outb(0, 0xcf8); |
254 | return 1; |
248 | return 1; |
255 | } |
249 | } |
256 | 250 | ||
257 | struct pci_methods pm_intel_conf1 = { |
251 | struct pci_methods pm_intel_conf1 = { |
258 | "Intel-conf1", |
252 | "Intel-conf1", |
259 | NULL, /* config */ |
253 | NULL, /* config */ |
260 | conf1_detect, |
254 | conf1_detect, |
261 | conf12_init, |
255 | conf12_init, |
262 | conf12_cleanup, |
256 | conf12_cleanup, |
263 | pci_generic_scan, |
257 | pci_generic_scan, |
264 | pci_generic_fill_info, |
258 | pci_generic_fill_info, |
265 | conf1_read, |
259 | conf1_read, |
266 | conf1_write, |
260 | conf1_write, |
267 | NULL, /* init_dev */ |
261 | NULL, /* init_dev */ |
268 | NULL /* cleanup_dev */ |
262 | NULL /* cleanup_dev */ |
269 | }; |
263 | }; |
270 | 264 | ||
271 | struct pci_methods pm_intel_conf2 = { |
265 | struct pci_methods pm_intel_conf2 = { |
272 | "Intel-conf2", |
266 | "Intel-conf2", |
273 | NULL, /* config */ |
267 | NULL, /* config */ |
274 | conf2_detect, |
268 | conf2_detect, |
275 | conf12_init, |
269 | conf12_init, |
276 | conf12_cleanup, |
270 | conf12_cleanup, |
277 | pci_generic_scan, |
271 | pci_generic_scan, |
278 | pci_generic_fill_info, |
272 | pci_generic_fill_info, |
279 | conf2_read, |
273 | conf2_read, |
280 | conf2_write, |
274 | conf2_write, |
281 | NULL, /* init_dev */ |
275 | NULL, /* init_dev */ |
282 | NULL /* cleanup_dev */ |
276 | NULL /* cleanup_dev */ |
283 | }; |
277 | }; |