8dc947cc6ba5ad6ffe1a88fc8a9d2a7aae532282
[tpg/acess2.git] / Kernel / drv / pci.c
1 /*\r
2  * AcessOS/AcessBasic v0.1\r
3  * PCI Bus Driver\r
4  */\r
5 #define DEBUG   0\r
6 #include <acess.h>\r
7 #include <modules.h>\r
8 #include <vfs.h>\r
9 #include <fs_devfs.h>\r
10 #include <drv_pci.h>\r
11 \r
12 #define LIST_DEVICES    1\r
13 \r
14 // === IMPORTS ===\r
15 extern Uint32   PCI_CfgReadDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset);\r
16 extern void     PCI_CfgWriteDWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset, Uint32 data);\r
17 extern Uint16   PCI_CfgReadWord(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset);\r
18 extern Uint8    PCI_CfgReadByte(Uint16 bus, Uint16 dev, Uint16 func, Uint16 offset);\r
19 \r
20 // === STRUCTURES ===\r
21 typedef struct sPCIDevice\r
22 {\r
23         Uint16  bus, slot, fcn;\r
24         Uint16  vendor, device;\r
25         union {\r
26                 struct {\r
27                         Uint8 class, subclass;\r
28                 };\r
29                 Uint16  oc;\r
30         };\r
31         Uint16  revision;\r
32         Uint32  ConfigCache[256/4];\r
33         char    Name[8];\r
34         tVFS_Node       Node;\r
35 } tPCIDevice;\r
36 \r
37 // === CONSTANTS ===\r
38 #define SPACE_STEP      5\r
39 #define MAX_RESERVED_PORT       0xD00\r
40 \r
41 // === PROTOTYPES ===\r
42  int    PCI_Install(char **Arguments);\r
43  int    PCI_ScanBus(int ID, int bFill);\r
44  \r
45 char    *PCI_ReadDirRoot(tVFS_Node *node, int pos);\r
46 tVFS_Node       *PCI_FindDirRoot(tVFS_Node *node, const char *filename);\r
47 Uint64  PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer);\r
48 \r
49 #if 0\r
50  int    PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn);\r
51  int    PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx);\r
52  int    PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev);\r
53 Uint8   PCI_GetIRQ(int id);\r
54 Uint32  PCI_GetBAR0(int id);\r
55 Uint32  PCI_GetBAR1(int id);\r
56 Uint32  PCI_GetBAR2(int id);\r
57 Uint32  PCI_GetBAR3(int id);\r
58 Uint32  PCI_GetBAR4(int id);\r
59 Uint32  PCI_GetBAR5(int id);\r
60 Uint16  PCI_AssignPort(int id, int bar, int count);\r
61 #endif\r
62 \r
63  int    PCI_EnumDevice(Uint16 bus, Uint16 dev, Uint16 fcn, tPCIDevice *info);\r
64 \r
65 // === GLOBALS ===\r
66 MODULE_DEFINE(0, 0x0100, PCI, PCI_Install, NULL, NULL);\r
67  int    giPCI_BusCount = 1;\r
68  int    giPCI_InodeHandle = -1;\r
69  int    giPCI_DeviceCount = 0;\r
70 tPCIDevice      *gPCI_Devices = NULL;\r
71 tDevFS_Driver   gPCI_DriverStruct = {\r
72         NULL, "pci",\r
73         {\r
74         .Flags = VFS_FFLAG_DIRECTORY,\r
75         .Size = -1,\r
76         .NumACLs = 1,\r
77         .ACLs = &gVFS_ACL_EveryoneRX,\r
78         .ReadDir = PCI_ReadDirRoot,\r
79         .FindDir = PCI_FindDirRoot\r
80         }\r
81 };\r
82 Uint32  *gaPCI_PortBitmap = NULL;\r
83 Uint32  gaPCI_BusBitmap[256/32];\r
84  \r
85 // === CODE ===\r
86 /**\r
87  * \brief Scan the PCI Bus for devices\r
88  * \param Arguments     Boot-time parameters\r
89  */\r
90 int PCI_Install(char **Arguments)\r
91 {\r
92          int    i;\r
93         void    *tmpPtr;\r
94         \r
95         // Build Portmap\r
96         gaPCI_PortBitmap = malloc( 1 << 13 );\r
97         if( !gaPCI_PortBitmap ) {\r
98                 Log_Error("PCI", "Unable to allocate %i bytes for bitmap", 1 << 13);\r
99                 return MODULE_ERR_MALLOC;\r
100         }\r
101         memset( gaPCI_PortBitmap, 0, 1 << 13 );\r
102         for( i = 0; i < MAX_RESERVED_PORT / 32; i ++ )\r
103                 gaPCI_PortBitmap[i] = -1;\r
104         for( i = 0; i < MAX_RESERVED_PORT % 32; i ++ )\r
105                 gaPCI_PortBitmap[MAX_RESERVED_PORT / 32] = 1 << i;\r
106         \r
107         // Scan Bus (Bus 0, Don't fill gPCI_Devices)\r
108         i = PCI_ScanBus(0, 0);\r
109         if(i != MODULE_ERR_OK)  return i;\r
110                 \r
111         if(giPCI_DeviceCount == 0) {\r
112                 Log_Notice("PCI", "No devices were found");\r
113                 return MODULE_ERR_NOTNEEDED;\r
114         }\r
115         \r
116         // Allocate device buffer\r
117         tmpPtr = malloc(giPCI_DeviceCount * sizeof(tPCIDevice));\r
118         if(tmpPtr == NULL) {\r
119                 Log_Warning("PCI", "Malloc ERROR");\r
120                 return MODULE_ERR_MALLOC;\r
121         }\r
122         gPCI_Devices = tmpPtr;\r
123         \r
124         Log_Log("PCI", "%i devices, filling structure", giPCI_DeviceCount);\r
125         \r
126         // Reset counts\r
127         giPCI_DeviceCount = 0;\r
128         giPCI_BusCount = 0;\r
129         memset(gaPCI_BusBitmap, 0, sizeof(gaPCI_BusBitmap));\r
130         // Rescan, filling the PCI device array\r
131         PCI_ScanBus(0, 1);\r
132         \r
133         // Complete Driver Structure\r
134         gPCI_DriverStruct.RootNode.Size = giPCI_DeviceCount;\r
135         \r
136         // And add to DevFS\r
137         DevFS_AddDevice(&gPCI_DriverStruct);\r
138         \r
139         return MODULE_ERR_OK;\r
140 }\r
141 \r
142 /**\r
143  * \brief Scans a specific PCI Bus\r
144  * \param BusID PCI Bus ID to scan\r
145  * \param bFill Fill the \a gPCI_Devices array?\r
146  */\r
147 int PCI_ScanBus(int BusID, int bFill)\r
148 {\r
149          int    dev, fcn;\r
150         tPCIDevice      devInfo;\r
151         \r
152         if( gaPCI_BusBitmap[BusID/32] & (1 << (BusID%32)) )\r
153                 return MODULE_ERR_OK;\r
154         \r
155         gaPCI_BusBitmap[BusID/32] |= (1 << (BusID%32));\r
156         \r
157         for( dev = 0; dev < 32; dev++ ) // 32 Devices per bus\r
158         {\r
159                 for( fcn = 0; fcn < 8; fcn++ )  // Max 8 functions per device\r
160                 {\r
161                         // Check if the device/function exists\r
162                         if(!PCI_EnumDevice(BusID, dev, fcn, &devInfo))\r
163                                 continue;\r
164                         \r
165                         if(devInfo.oc == PCI_OC_PCIBRIDGE)\r
166                         {\r
167                                 #if LIST_DEVICES\r
168                                 Log_Log("PCI", "Bridge @ %i,%i:%i (0x%x:0x%x)",\r
169                                         BusID, dev, fcn, devInfo.vendor, devInfo.device);\r
170                                 #endif\r
171                                 //TODO: Handle PCI-PCI Bridges\r
172                                 //PCI_ScanBus(devInfo.???, bFill);\r
173                                 giPCI_BusCount ++;\r
174                         }\r
175                         else\r
176                         {\r
177                                 #if LIST_DEVICES\r
178                                 Log_Log("PCI", "Device %i,%i:%i %04x => 0x%04x:0x%04x",\r
179                                         BusID, dev, fcn, devInfo.oc, devInfo.vendor, devInfo.device);\r
180                                 #endif\r
181                         }\r
182                         \r
183                         if( bFill ) {\r
184                                 devInfo.Node.Inode = giPCI_DeviceCount;\r
185                                 memcpy(&gPCI_Devices[giPCI_DeviceCount], &devInfo, sizeof(tPCIDevice));\r
186                         }\r
187                         giPCI_DeviceCount ++;\r
188                         \r
189                         // If bit 23 of (soemthing) is set, there are sub-functions\r
190                         if(fcn == 0 && !(devInfo.ConfigCache[3] & 0x00800000) )\r
191                                 break;\r
192                 }\r
193         }\r
194         \r
195         return MODULE_ERR_OK;\r
196 }\r
197 \r
198 /**\r
199  * \fn char *PCI_ReadDirRoot(tVFS_Node *Node, int Pos)\r
200  * \brief Read from Root of PCI Driver\r
201 */\r
202 char *PCI_ReadDirRoot(tVFS_Node *Node, int Pos)\r
203 {\r
204         ENTER("pNode iPos", Node, Pos);\r
205         if(Pos < 0 || Pos >= giPCI_DeviceCount) {\r
206                 LEAVE('n');\r
207                 return NULL;\r
208         }\r
209         \r
210         LEAVE('s', gPCI_Devices[Pos].Name);\r
211         return strdup( gPCI_Devices[Pos].Name );\r
212 }\r
213 /**\r
214  * \fn tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, const char *filename)\r
215  */\r
216 tVFS_Node *PCI_FindDirRoot(tVFS_Node *node, const char *filename)\r
217 {\r
218          int    bus,slot,fcn;\r
219          int    i;\r
220         // Validate Filename (Pointer and length)\r
221         if(!filename || strlen(filename) != 7)\r
222                 return NULL;\r
223         // Check for spacers\r
224         if(filename[2] != '.' || filename[5] != ':')\r
225                 return NULL;\r
226         \r
227         // Get Information\r
228         if(filename[0] < '0' || filename[0] > '9')      return NULL;\r
229         bus = (filename[0] - '0')*10;\r
230         if(filename[1] < '0' || filename[1] > '9')      return NULL;\r
231         bus += filename[1] - '0';\r
232         if(filename[3] < '0' || filename[3] > '9')      return NULL;\r
233         slot = (filename[3] - '0')*10;\r
234         if(filename[4] < '0' || filename[4] > '9')      return NULL;\r
235         slot += filename[4] - '0';\r
236         if(filename[6] < '0' || filename[6] > '9')      return NULL;\r
237         fcn = filename[6] - '0';\r
238         \r
239         // Find Match\r
240         for(i=0;i<giPCI_DeviceCount;i++)\r
241         {\r
242                 if(gPCI_Devices[i].bus != bus)          continue;\r
243                 if(gPCI_Devices[i].slot != slot)        continue;\r
244                 if(gPCI_Devices[i].fcn != fcn)  continue;\r
245                 \r
246                 return &gPCI_Devices[i].Node;\r
247         }\r
248         \r
249         // Error Return\r
250         return NULL;\r
251 }\r
252 \r
253 /**\r
254  * \fn Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer)\r
255  */\r
256 Uint64 PCI_ReadDevice(tVFS_Node *node, Uint64 pos, Uint64 length, void *buffer)\r
257 {       \r
258         if( pos + length > 256 )        return 0;\r
259         \r
260         memcpy(\r
261                 buffer,\r
262                 (char*)gPCI_Devices[node->Inode].ConfigCache + pos,\r
263                 length);\r
264         \r
265         return length;\r
266 }\r
267 \r
268 // --- Kernel Code Interface ---\r
269 /**\r
270  \fn int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn)\r
271  \brief Counts the devices with the specified codes\r
272  \param vendor  Vendor ID\r
273  \param device  Device ID\r
274  \param fcn     Function ID\r
275 */\r
276 int PCI_CountDevices(Uint16 vendor, Uint16 device, Uint16 fcn)\r
277 {\r
278         int i, ret=0;\r
279         for(i=0;i<giPCI_DeviceCount;i++)\r
280         {\r
281                 if(gPCI_Devices[i].vendor != vendor)    continue;\r
282                 if(gPCI_Devices[i].device != device)    continue;\r
283                 if(gPCI_Devices[i].fcn != fcn)  continue;\r
284                 ret ++;\r
285         }\r
286         return ret;\r
287 }\r
288 \r
289 /**\r
290  \fn int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx)\r
291  \brief Gets the ID of the specified PCI device\r
292  \param vendor  Vendor ID\r
293  \param device  Device ID\r
294  \param fcn     Function IDs\r
295  \param idx     Number of matching entry wanted\r
296 */\r
297 int PCI_GetDevice(Uint16 vendor, Uint16 device, Uint16 fcn, int idx)\r
298 {\r
299          int    i, j=0;\r
300         for(i=0;i<giPCI_DeviceCount;i++)\r
301         {\r
302                 if(gPCI_Devices[i].vendor != vendor)    continue;\r
303                 if(gPCI_Devices[i].device != device)    continue;\r
304                 if(gPCI_Devices[i].fcn != fcn)  continue;\r
305                 if(j == idx)    return i;\r
306                 j ++;\r
307         }\r
308         return -1;\r
309 }\r
310 \r
311 /**\r
312  * \fn int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev)\r
313  * \brief Gets the ID of a device by it's class code\r
314  * \param class Class Code\r
315  * \param mask  Mask for class comparison\r
316  * \param prev  ID of previous device (-1 for no previous)\r
317  */\r
318 int PCI_GetDeviceByClass(Uint16 class, Uint16 mask, int prev)\r
319 {\r
320          int    i;\r
321         // Check if prev is negative (meaning get first)\r
322         if(prev < 0)    i = 0;\r
323         else    i = prev+1;\r
324         \r
325         for( ; i < giPCI_DeviceCount; i++ )\r
326         {\r
327                 if((gPCI_Devices[i].oc & mask) == class)\r
328                         return i;\r
329         }\r
330         return -1;\r
331 }\r
332 \r
333 /**\r
334  \fn Uint8 PCI_GetIRQ(int id)\r
335 */\r
336 Uint8 PCI_GetIRQ(int id)\r
337 {\r
338         if(id < 0 || id >= giPCI_DeviceCount)\r
339                 return 0;\r
340         return gPCI_Devices[id].ConfigCache[15];\r
341         //return PCI_CfgReadByte( gPCI_Devices[id].bus, gPCI_Devices[id].slot, gPCI_Devices[id].fcn, 0x3C);\r
342 }\r
343 \r
344 /**\r
345  \fn Uint32 PCI_GetBAR0(int id)\r
346 */\r
347 Uint32 PCI_GetBAR0(int id)\r
348 {\r
349         if(id < 0 || id >= giPCI_DeviceCount)\r
350                 return 0;\r
351         return gPCI_Devices[id].ConfigCache[4];\r
352 }\r
353 \r
354 /**\r
355  \fn Uint32 PCI_GetBAR1(int id)\r
356 */\r
357 Uint32 PCI_GetBAR1(int id)\r
358 {\r
359         if(id < 0 || id >= giPCI_DeviceCount)\r
360                 return 0;\r
361         return gPCI_Devices[id].ConfigCache[5];\r
362 }\r
363 \r
364 /**\r
365  \fn Uint32 PCI_GetBAR2(int id)\r
366 */\r
367 Uint32 PCI_GetBAR2(int id)\r
368 {\r
369         if(id < 0 || id >= giPCI_DeviceCount)\r
370                 return 0;\r
371         return gPCI_Devices[id].ConfigCache[6];\r
372 }\r
373 \r
374 /**\r
375  \fn Uint32 PCI_GetBAR3(int id)\r
376 */\r
377 Uint32 PCI_GetBAR3(int id)\r
378 {\r
379         if(id < 0 || id >= giPCI_DeviceCount)\r
380                 return 0;\r
381         return gPCI_Devices[id].ConfigCache[7];\r
382 }\r
383 \r
384 /**\r
385  \fn Uint32 PCI_GetBAR4(int id)\r
386 */\r
387 Uint32 PCI_GetBAR4(int id)\r
388 {\r
389         if(id < 0 || id >= giPCI_DeviceCount)\r
390                 return 0;\r
391         return gPCI_Devices[id].ConfigCache[8];\r
392 }\r
393 \r
394 /**\r
395  \fn Uint32 PCI_GetBAR5(int id)\r
396 */\r
397 Uint32 PCI_GetBAR5(int id)\r
398 {\r
399         if(id < 0 || id >= giPCI_DeviceCount)\r
400                 return 0;\r
401         return gPCI_Devices[id].ConfigCache[9];\r
402 }\r
403 \r
404 Uint16 PCI_AssignPort(int id, int bar, int count)\r
405 {\r
406         #if 1\r
407         Uint16  rv;\r
408         tPCIDevice      *dev;\r
409         \r
410         if(id < 0 || id >= giPCI_DeviceCount)   return 0;\r
411         if(bar < 0 || bar > 5)  return 0;\r
412         dev = &gPCI_Devices[id];\r
413         \r
414         rv = PCI_CfgReadDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4 );\r
415         if(rv & 1)      return rv & ~1;\r
416         return 0;\r
417         #else\r
418         Uint16  portVals;\r
419          int    gran=0;\r
420          int    i, j;\r
421         tPCIDevice      *dev;\r
422         \r
423         //LogF("PCI_AssignPort: (id=%i,bar=%i,count=%i)\n", id, bar, count);\r
424         \r
425         if(id < 0 || id >= giPCI_DeviceCount)   return 0;\r
426         if(bar < 0 || bar > 5)  return 0;\r
427         \r
428         dev = &gPCI_Devices[id];\r
429         \r
430         PCI_CfgWriteDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4, -1 );\r
431         portVals = PCI_CfgReadDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4 );\r
432         dev->ConfigCache[4+bar] = portVals;\r
433         //LogF(" PCI_AssignPort: portVals = 0x%x\n", portVals);\r
434         \r
435         // Check for IO port\r
436         if( !(portVals & 1) )   return 0;\r
437         \r
438         // Mask out final bit\r
439         portVals &= ~1;\r
440         \r
441         // Get Granuality\r
442         #if ARCHDIR_IS_x86 || ARCHDIR_IS_x86_64\r
443         __asm__ __volatile__ ("bsf %%eax, %%ecx" : "=c" (gran) : "a" (portVals) );\r
444         gran = 1 << gran;\r
445         #else\r
446         {\r
447                 for(gran = 1; gran && !(portVals & gran); gran <<= 1);\r
448         }\r
449         #endif\r
450         //LogF(" PCI_AssignPort: gran = 0x%x\n", gran);\r
451         \r
452         // Find free space\r
453         portVals = 0;\r
454         for( i = 0; i < 1<<16; i += gran )\r
455         {\r
456                 for( j = 0; j < count; j ++ )\r
457                 {\r
458                         if( gaPCI_PortBitmap[ (i+j)>>5 ] & 1 << ((i+j)&0x1F) )\r
459                                 break;\r
460                 }\r
461                 if(j == count) {\r
462                         portVals = i;\r
463                         break;\r
464                 }\r
465         }\r
466         \r
467         if(portVals)\r
468         {\r
469                 for( j = 0; j < count; j ++ )\r
470                 {\r
471                         if( gaPCI_PortBitmap[ (portVals+j)>>5 ] |= 1 << ((portVals+j)&0x1F) )\r
472                                 break;\r
473                 }\r
474                 PCI_CfgWriteDWord( dev->bus, dev->slot, dev->fcn, 0x10+bar*4, portVals|1 );\r
475                 dev->ConfigCache[4+bar] = portVals|1;\r
476         }\r
477         \r
478         // Return\r
479         //LogF("PCI_AssignPort: RETURN 0x%x\n", portVals);\r
480         return portVals;\r
481         #endif\r
482 }\r
483 \r
484 /**\r
485  * \fn int PCI_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, tPCIDevice *info)\r
486  * \brief Get device information for a slot/function\r
487  */\r
488 int PCI_EnumDevice(Uint16 bus, Uint16 slot, Uint16 fcn, tPCIDevice *info)\r
489 {\r
490         Uint16  vendor;\r
491          int    i;\r
492         \r
493         vendor = PCI_CfgReadWord(bus, slot, fcn, 0x0|0);\r
494         if(vendor == 0xFFFF)    // Invalid Device\r
495                 return 0;\r
496                 \r
497         info->bus = bus;\r
498         info->slot = slot;\r
499         info->fcn = fcn;\r
500         info->vendor = vendor;\r
501         info->device = PCI_CfgReadWord(bus, slot, fcn, 0x0|2);\r
502         info->revision = PCI_CfgReadWord(bus, slot, fcn, 0x8|0);\r
503         info->oc = PCI_CfgReadWord(bus, slot, fcn, 0x8|2);\r
504         \r
505         // Load Config Bytes\r
506         for(i=0;i<256/4;i++)\r
507         {\r
508                 info->ConfigCache[i] = PCI_CfgReadDWord(bus, slot, fcn, i*4);\r
509         }\r
510         \r
511         //#if LIST_DEVICES\r
512         //Log("BAR0 0x%08x BAR1 0x%08x BAR2 0x%08x", info->ConfigCache[4], info->ConfigCache[5], info->ConfigCache[6]);\r
513         //Log("BAR3 0x%08x BAR4 0x%08x BAR5 0x%08x", info->ConfigCache[7], info->ConfigCache[8], info->ConfigCache[9]);\r
514         //Log("Class: 0x%04x", info->oc);\r
515         //#endif\r
516         \r
517         // Make node name\r
518         info->Name[0] = '0' + bus/10;\r
519         info->Name[1] = '0' + bus%10;\r
520         info->Name[2] = '.';\r
521         info->Name[3] = '0' + slot/10;\r
522         info->Name[4] = '0' + slot%10;\r
523         info->Name[5] = ':';\r
524         info->Name[6] = '0' + fcn;\r
525         info->Name[7] = '\0';\r
526         \r
527         // Create VFS Node\r
528         memset( &info->Node, 0, sizeof(tVFS_Node) );\r
529         info->Node.Size = 256;\r
530         \r
531         info->Node.NumACLs = 1;\r
532         info->Node.ACLs = &gVFS_ACL_EveryoneRO;\r
533         \r
534         info->Node.Read = PCI_ReadDevice;\r
535         \r
536         return 1;\r
537 }\r
538 \r
539 // === EXPORTS ===\r
540 //*\r
541 EXPORT(PCI_CountDevices);\r
542 EXPORT(PCI_GetDevice);\r
543 EXPORT(PCI_GetDeviceByClass);\r
544 EXPORT(PCI_AssignPort);\r
545 EXPORT(PCI_GetIRQ);\r
546 //*/\r

UCC git Repository :: git.ucc.asn.au