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