Subversion Repositories HelenOS

Rev

Rev 1302 | Go to most recent revision | Details | 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
 *
6
 *  Modified and ported to HelenOS by Jakub Jermar.
7
 *
8
 *  Can be freely distributed and used under the terms of the GNU GPL.
9
 */
10
 
11
#include <unistd.h>
12
 
13
#include "internal.h"
14
 
15
static inline void outb(u8 b, u16 port)
16
{
17
    asm volatile ("outb %0, %1\n" : : "a" (b), "d" (port));
18
}
19
 
20
static inline void outw(u16 w, u16 port)
21
{
22
    asm volatile ("outw %0, %1\n" : : "a" (w), "d" (port));
23
}
24
 
25
static inline void outl(u32 l, u16 port)
26
{
27
    asm volatile ("outl %0, %1\n" : : "a" (l), "d" (port));
28
}
29
 
30
static inline u8 inb(u16 port)
31
{
32
    u8 val;
33
 
34
    asm volatile ("inb %1, %0 \n" : "=a" (val) : "d" (port));
35
    return val;
36
}
37
 
38
static inline u16 inw(u16 port)
39
{
40
    u16 val;
41
 
42
    asm volatile ("inw %1, %0 \n" : "=a" (val) : "d" (port));
43
    return val;
44
}
45
 
46
static inline u32 inl(u16 port)
47
{
48
    u32 val;
49
 
50
    asm volatile ("inl %1, %0 \n" : "=a" (val) : "d" (port));
51
    return val;
52
}
53
 
54
static void
55
conf12_init(struct pci_access *a)
56
{
57
}
58
 
59
static void
60
conf12_cleanup(struct pci_access *a UNUSED)
61
{
62
}
63
 
64
/*
65
 * Before we decide to use direct hardware access mechanisms, we try to do some
66
 * trivial checks to ensure it at least _seems_ to be working -- we just test
67
 * whether bus 00 contains a host bridge (this is similar to checking
68
 * techniques used in XFree86, but ours should be more reliable since we
69
 * attempt to make use of direct access hints provided by the PCI BIOS).
70
 *
71
 * 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.
73
 */
74
 
75
static int
76
intel_sanity_check(struct pci_access *a, struct pci_methods *m)
77
{
78
  struct pci_dev d;
79
 
80
  a->debug("...sanity check");
81
  d.bus = 0;
82
  d.func = 0;
83
  for(d.dev = 0; d.dev < 32; d.dev++)
84
    {
85
      u16 class, vendor;
86
      if (m->read(&d, PCI_CLASS_DEVICE, (byte *) &class, sizeof(class)) &&
87
      (class == cpu_to_le16(PCI_CLASS_BRIDGE_HOST) || class == cpu_to_le16(PCI_CLASS_DISPLAY_VGA)) ||
88
      m->read(&d, PCI_VENDOR_ID, (byte *) &vendor, sizeof(vendor)) &&
89
      (vendor == cpu_to_le16(PCI_VENDOR_ID_INTEL) || vendor == cpu_to_le16(PCI_VENDOR_ID_COMPAQ)))
90
    {
91
      a->debug("...outside the Asylum at 0/%02x/0", d.dev);
92
      return 1;
93
    }
94
    }
95
  a->debug("...insane");
96
  return 0;
97
}
98
 
99
/*
100
 *  Configuration type 1
101
 */
102
 
103
#define CONFIG_CMD(bus, device_fn, where)   (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3))
104
 
105
static int
106
conf1_detect(struct pci_access *a)
107
{
108
  unsigned int tmp;
109
  int res = 0;
110
 
111
  outb (0x01, 0xCFB);
112
  tmp = inl (0xCF8);
113
  outl (0x80000000, 0xCF8);
114
  if (inl (0xCF8) == 0x80000000)
115
    res = 1;
116
  outl (tmp, 0xCF8);
117
  if (res)
118
    res = intel_sanity_check(a, &pm_intel_conf1);
119
  return res;
120
}
121
 
122
static int
123
conf1_read(struct pci_dev *d, int pos, byte *buf, int len)
124
{
125
  int addr = 0xcfc + (pos&3);
126
 
127
  if (pos >= 256)
128
    return 0;
129
 
130
  outl(0x80000000 | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos&~3), 0xcf8);
131
 
132
  switch (len)
133
    {
134
    case 1:
135
      buf[0] = inb(addr);
136
      break;
137
    case 2:
138
      ((u16 *) buf)[0] = cpu_to_le16(inw(addr));
139
      break;
140
    case 4:
141
      ((u32 *) buf)[0] = cpu_to_le32(inl(addr));
142
      break;
143
    default:
144
      return pci_generic_block_read(d, pos, buf, len);
145
    }
146
  return 1;
147
}
148
 
149
static int
150
conf1_write(struct pci_dev *d, int pos, byte *buf, int len)
151
{
152
  int addr = 0xcfc + (pos&3);
153
 
154
  if (pos >= 256)
155
    return 0;
156
 
157
  outl(0x80000000 | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos&~3), 0xcf8);
158
 
159
  switch (len)
160
    {
161
    case 1:
162
      outb(buf[0], addr);
163
      break;
164
    case 2:
165
      outw(le16_to_cpu(((u16 *) buf)[0]), addr);
166
      break;
167
    case 4:
168
      outl(le32_to_cpu(((u32 *) buf)[0]), addr);
169
      break;
170
    default:
171
      return pci_generic_block_write(d, pos, buf, len);
172
    }
173
  return 1;
174
}
175
 
176
/*
177
 *  Configuration type 2. Obsolete and brain-damaged, but existing.
178
 */
179
 
180
static int
181
conf2_detect(struct pci_access *a)
182
{
183
  /* This is ugly and tends to produce false positives. Beware. */
184
 
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)
196
{
197
  int addr = 0xc000 | (d->dev << 8) | pos;
198
 
199
  if (pos >= 256)
200
    return 0;
201
 
202
  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:
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.");
236
  outb((d->func << 1) | 0xf0, 0xcf8);
237
  outb(d->bus, 0xcfa);
238
  switch (len)
239
    {
240
    case 1:
241
      outb(buf[0], addr);
242
      break;
243
    case 2:
244
      outw(le16_to_cpu(* (u16 *) buf), addr);
245
      break;
246
    case 4:
247
      outl(le32_to_cpu(* (u32 *) buf), addr);
248
      break;
249
    default:
250
      outb(0, 0xcf8);
251
      return pci_generic_block_write(d, pos, buf, len);
252
    }
253
  outb(0, 0xcf8);
254
  return 1;
255
}
256
 
257
struct pci_methods pm_intel_conf1 = {
258
  "Intel-conf1",
259
  NULL,                 /* config */
260
  conf1_detect,
261
  conf12_init,
262
  conf12_cleanup,
263
  pci_generic_scan,
264
  pci_generic_fill_info,
265
  conf1_read,
266
  conf1_write,
267
  NULL,                 /* init_dev */
268
  NULL                  /* cleanup_dev */
269
};
270
 
271
struct pci_methods pm_intel_conf2 = {
272
  "Intel-conf2",
273
  NULL,                 /* config */
274
  conf2_detect,
275
  conf12_init,
276
  conf12_cleanup,
277
  pci_generic_scan,
278
  pci_generic_fill_info,
279
  conf2_read,
280
  conf2_write,
281
  NULL,                 /* init_dev */
282
  NULL                  /* cleanup_dev */
283
};