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 |