Subversion Repositories HelenOS

Rev

Rev 4399 | Rev 4438 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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