Subversion Repositories HelenOS

Rev

Rev 4438 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 4438 Rev 4667
1
#include <futex.h>
1
#include <futex.h>
2
#include <assert.h>
2
#include <assert.h>
3
 
3
 
4
#include "pci.h"
4
#include "pci.h"
5
#include "pci_bus.h"
5
#include "pci_bus.h"
6
#include "pci_regs.h"
6
#include "pci_regs.h"
7
#include "pci_conf.h"
7
#include "pci_conf.h"
8
 
8
 
-
 
9
#define NAME "PCI"
-
 
10
 
9
LIST_INITIALIZE(devices_list);
11
LIST_INITIALIZE(devices_list);
10
LIST_INITIALIZE(buses_list);
12
LIST_INITIALIZE(buses_list);
11
LIST_INITIALIZE(drivers_list);
13
LIST_INITIALIZE(drivers_list);
12
 
14
 
13
static atomic_t pci_bus_futex = FUTEX_INITIALIZER;
15
static atomic_t pci_bus_futex = FUTEX_INITIALIZER;
14
 
16
 
15
static int pci_match(pci_drv_t *drv, pci_dev_t *dev);
17
static int pci_match(pci_drv_t *drv, pci_dev_t *dev);
16
static int pci_pass_dev(pci_drv_t *drv, pci_dev_t *dev);
18
static int pci_pass_dev(pci_drv_t *drv, pci_dev_t *dev);
17
static void pci_lookup_driver(pci_dev_t *dev);
19
static void pci_lookup_driver(pci_dev_t *dev);
18
static void pci_lookup_devices(pci_drv_t *drv);
20
static void pci_lookup_devices(pci_drv_t *drv);
19
 
21
 
20
 
22
 
21
void pci_bus_scan(pci_bus_t *bus)
23
void pci_bus_scan(pci_bus_t *bus)
22
{
24
{
23
    pci_dev_t *dev = pci_alloc_dev();
25
    pci_dev_t *dev = pci_alloc_dev();
24
    pci_bus_t *child_bus = NULL;
26
    pci_bus_t *child_bus = NULL;
25
    int dnum, fnum, bus_num;
27
    int dnum, fnum, bus_num;
26
    bool multi;
28
    bool multi;
27
    uint8_t header_type;
29
    uint8_t header_type;
28
   
30
   
29
    for (dnum = 0; dnum < 32; dnum++) {
31
    for (dnum = 0; dnum < 32; dnum++) {
30
        multi = true;
32
        multi = true;
31
        for (fnum = 0; multi && fnum < 8; fnum++) {
33
        for (fnum = 0; multi && fnum < 8; fnum++) {
32
            pci_init_dev(dev, bus, dnum, fnum);
34
            pci_init_dev(dev, bus, dnum, fnum);
33
            dev->vendor_id = pci_conf_read_16(dev, PCI_VENDOR_ID);
35
            dev->vendor_id = pci_conf_read_16(dev, PCI_VENDOR_ID);
34
            dev->device_id = pci_conf_read_16(dev, PCI_DEVICE_ID);
36
            dev->device_id = pci_conf_read_16(dev, PCI_DEVICE_ID);
35
            if (dev->vendor_id == 0xFFFF) { // device is not present, go on scanning the bus
37
            if (dev->vendor_id == 0xFFFF) { // device is not present, go on scanning the bus
36
                if (fnum == 0) {
38
                if (fnum == 0) {
37
                    break;
39
                    break;
38
                } else {
40
                } else {
39
                    continue;  
41
                    continue;  
40
                }
42
                }
41
            }
43
            }
42
            header_type = pci_conf_read_8(dev, PCI_HEADER_TYPE);
44
            header_type = pci_conf_read_8(dev, PCI_HEADER_TYPE);
43
            if (fnum == 0) {
45
            if (fnum == 0) {
44
                 multi = header_type >> 7;  // is the device multifunction?
46
                 multi = header_type >> 7;  // is the device multifunction?
45
            }
47
            }
46
            header_type = header_type & 0x7F; // clear the multifunction bit
48
            header_type = header_type & 0x7F; // clear the multifunction bit
47
           
49
           
48
            printf("PCI: adding new device %d : %d : %d", dev->bus->num, dnum, fnum);
50
            printf(NAME ": adding new device %3d : %2d : %2d", dev->bus->num, dnum, fnum);
49
            printf(" - vendor = 0x%04X, device = 0x%04X.\n", dev->vendor_id, dev->device_id);
51
            printf(" - vendor = 0x%04X, device = 0x%04X.\n", dev->vendor_id, dev->device_id);
50
            pci_device_register(dev);          
52
            pci_device_register(dev);          
51
           
53
           
52
            if (header_type == PCI_HEADER_TYPE_BRIDGE || header_type == PCI_HEADER_TYPE_CARDBUS ) {
54
            if (header_type == PCI_HEADER_TYPE_BRIDGE || header_type == PCI_HEADER_TYPE_CARDBUS ) {
53
                bus_num = pci_conf_read_8(dev, PCI_BRIDGE_SEC_BUS_NUM);
55
                bus_num = pci_conf_read_8(dev, PCI_BRIDGE_SEC_BUS_NUM);
54
                printf("PCI: device is pci-to-pci bridge, secondary bus number = %d.\n", bus_num);
56
                printf(NAME ": device is pci-to-pci bridge, secondary bus number = %d.\n", bus_num);
55
                if(bus_num > bus->num) {                   
57
                if(bus_num > bus->num) {                   
56
                    child_bus = pci_alloc_bus();
58
                    child_bus = pci_alloc_bus();
57
                    pci_init_bus(child_bus, bus, bus_num);
59
                    pci_init_bus(child_bus, bus, bus_num);
58
                    pci_bus_register(child_bus);
60
                    pci_bus_register(child_bus);
59
                    pci_bus_scan(child_bus);   
61
                    pci_bus_scan(child_bus);   
60
                }                  
62
                }                  
61
            }
63
            }
62
           
64
           
63
            dev = pci_alloc_dev();  // alloc new aux. dev. structure
65
            dev = pci_alloc_dev();  // alloc new aux. dev. structure
64
        }
66
        }
65
    }
67
    }
66
   
68
   
67
    if (dev->vendor_id == 0xFFFF) {
69
    if (dev->vendor_id == 0xFFFF) {
68
        pci_free_dev(dev);  // free the auxiliary device structure
70
        pci_free_dev(dev);  // free the auxiliary device structure
69
    }  
71
    }  
70
}
72
}
71
 
73
 
72
/*
74
/*
73
 * Usage: pci_bus_futex must be down.
75
 * Usage: pci_bus_futex must be down.
74
 */
76
 */
75
static int pci_pass_dev(pci_drv_t *drv, pci_dev_t *dev)
77
static int pci_pass_dev(pci_drv_t *drv, pci_dev_t *dev)
76
{
78
{
77
    assert(dev->driver == NULL);
79
    assert(dev->driver == NULL);
-
 
80
    assert(drv->name != NULL);
78
   
81
   
-
 
82
    printf(NAME ": passing device to driver '%s'.\n", drv->name);
79
    if (drv->ops->add_device(dev)) {
83
    if (drv->ops->add_device != NULL && drv->ops->add_device(dev)) {
80
        dev->driver = drv;
84
        dev->driver = drv;
81
        return 1;
85
        return 1;
82
    }
86
    }
83
   
87
   
84
    return 0;
88
    return 0;
85
}
89
}
86
 
90
 
87
/*
91
/*
88
 * Usage: pci_bus_futex must be down.
92
 * Usage: pci_bus_futex must be down.
89
 */
93
 */
90
static void pci_lookup_driver(pci_dev_t *dev)
94
static void pci_lookup_driver(pci_dev_t *dev)
91
{
95
{
92
    link_t *item = drivers_list.next;
96
    link_t *item = drivers_list.next;
93
    pci_drv_t *drv = NULL;
97
    pci_drv_t *drv = NULL;
94
   
98
   
95
    while (item != &drivers_list) {
99
    while (item != &drivers_list) {
96
        drv = list_get_instance(item, pci_drv_t, link);
100
        drv = list_get_instance(item, pci_drv_t, link);
97
        if (pci_match(drv, dev) && pci_pass_dev(drv, dev)) {
101
        if (pci_match(drv, dev) && pci_pass_dev(drv, dev)) {
98
            break;
102
            return;
99
        }
103
        }
100
        item = item->next;
104
        item = item->next;
101
    }
105
    }
102
}
106
}
103
 
107
 
104
/*
108
/*
105
 * Usage: pci_bus_futex must be down.
109
 * Usage: pci_bus_futex must be down.
106
 */
110
 */
107
static void pci_lookup_devices(pci_drv_t *drv)
111
static void pci_lookup_devices(pci_drv_t *drv)
108
{
112
{
109
    link_t *item = devices_list.next;
113
    link_t *item = devices_list.next;
110
    pci_dev_t *dev = NULL;
114
    pci_dev_t *dev = NULL;
111
   
115
   
-
 
116
    printf(NAME ": looking up devices for a newly added driver '%s'.\n", drv->name);
-
 
117
   
112
    while (item != &devices_list) {
118
    while (item != &devices_list) {
113
        dev = list_get_instance(item, pci_dev_t, link);
119
        dev = list_get_instance(item, pci_dev_t, link);
114
        if (dev->driver == NULL && pci_match(drv, dev)) {
120
        if (dev->driver == NULL && pci_match(drv, dev)) {
115
            pci_pass_dev(drv, dev);
121
            pci_pass_dev(drv, dev);
116
        }
122
        }
117
        item = item->next;
123
        item = item->next;
118
    }
124
    }
119
}
125
}
120
 
126
 
121
static int pci_match(pci_drv_t *drv, pci_dev_t *dev)
127
static int pci_match(pci_drv_t *drv, pci_dev_t *dev)
122
{
128
{
123
    return drv->vendor_id == dev->vendor_id && drv->device_id == dev->vendor_id;
129
    return drv->vendor_id == dev->vendor_id && drv->device_id == dev->device_id;
124
}
130
}
125
 
131
 
126
void pci_bus_register(pci_bus_t *bus)
132
void pci_bus_register(pci_bus_t *bus)
127
{
133
{
128
    futex_down(&pci_bus_futex);
134
    futex_down(&pci_bus_futex);
129
   
135
   
130
    // add the device to the list of pci devices
136
    // add the device to the list of pci devices
131
    list_append(&(bus->link), &buses_list);
137
    list_append(&(bus->link), &buses_list);
132
   
138
   
133
    futex_up(&pci_bus_futex);
139
    futex_up(&pci_bus_futex);
134
}
140
}
135
 
141
 
136
void pci_device_register(pci_dev_t *dev)
142
void pci_device_register(pci_dev_t *dev)
137
{
143
{
138
    futex_down(&pci_bus_futex);
144
    futex_down(&pci_bus_futex);
139
   
145
   
140
    // add the device to the list of pci devices
146
    // add the device to the list of pci devices
141
    list_append(&(dev->link), &devices_list);
147
    list_append(&(dev->link), &devices_list);
142
   
148
   
143
    // try to find suitable driver for the device and pass the device to it
149
    // try to find suitable driver for the device and pass the device to it
144
    pci_lookup_driver(dev);
150
    pci_lookup_driver(dev);
145
   
151
   
146
    futex_up(&pci_bus_futex);  
152
    futex_up(&pci_bus_futex);  
147
}
153
}
148
 
154
 
149
void pci_driver_register(pci_drv_t *drv)
155
void pci_driver_register(pci_drv_t *drv)
150
{
156
{  
-
 
157
    assert(drv->name != NULL);
-
 
158
   
151
    futex_down(&pci_bus_futex);
159
    futex_down(&pci_bus_futex);
-
 
160
    printf(NAME ": registering new driver '%s'.\n", drv->name);
152
    list_append(&(drv->link), &drivers_list);
161
    list_append(&(drv->link), &drivers_list);
153
   
162
   
154
    // try to find compatible devices
163
    // try to find compatible devices
155
    pci_lookup_devices(drv);
164
    pci_lookup_devices(drv);
156
   
165
   
157
    futex_up(&pci_bus_futex);
166
    futex_up(&pci_bus_futex);
158
}
167
}
159
 
168
 
160
 
169