diff --git a/device/device.c b/device/device.c index ecff9a286a..c63a722287 100644 --- a/device/device.c +++ b/device/device.c @@ -637,32 +637,34 @@ void dev_phase2(void) * * @return The maximum bus number found, after scanning all subordinate busses */ -unsigned int dev_phase3(struct device * bus, unsigned int max) +unsigned int dev_phase3(struct device * busdevice, unsigned int max) { unsigned int new_max; int do_phase3; - if ( !bus || - !bus->enabled || - !bus->ops || - !bus->ops->phase3) + post_code(0x42); + if ( !busdevice || + !busdevice->enabled || + !busdevice->ops || + !busdevice->ops->phase3) { return max; } do_phase3 = 1; while(do_phase3) { int link; - new_max = bus->ops->phase3(bus, max); + new_max = busdevice->ops->phase3(busdevice, max); do_phase3 = 0; - for(link = 0; link < bus->links; link++) { - if (bus->link[link].reset_needed) { - if (reset_bus(&bus->link[link])) { + for(link = 0; link < busdevice->links; link++) { + if (busdevice->link[link].reset_needed) { + if (reset_bus(&busdevice->link[link])) { do_phase3 = 1; } else { - bus->bus->reset_needed = 1; + busdevice->bus->reset_needed = 1; } } } } + post_code(0x4e); return new_max; } @@ -698,6 +700,7 @@ void dev_root_phase3(void) if (root->chip_ops && root->chip_ops->enable_dev) { root->chip_ops->enable_dev(root); } + post_code(0x41); if (!root->ops) { printk(BIOS_ERR, "dev_root_phase3 missing 'ops' initialization\nPhase 3: Failed\n"); return; @@ -740,6 +743,7 @@ void dev_phase4(void) printk(BIOS_ERR, "dev_root ops missing read_resources\nPhase 4: Failed\n"); return; } + if (!root->ops->phase4_set_resources) { printk(BIOS_ERR, "dev_root ops missing set_resources\nPhase 4: Failed\n"); return; diff --git a/device/root_device.c b/device/root_device.c index 5bfd893170..854b0b97b3 100644 --- a/device/root_device.c +++ b/device/root_device.c @@ -93,20 +93,20 @@ void root_dev_set_resources(struct device * root) * @return Largest bus number used. */ static int smbus_max = 0; -unsigned int scan_static_bus(struct device * bus, unsigned int max) +unsigned int scan_static_bus(struct device * busdevice, unsigned int max) { struct device * child; unsigned link; - printk(BIOS_SPEW, "%s for %s\n", __func__, dev_path(bus)); + printk(BIOS_SPEW, "%s for %s\n", __func__, dev_path(busdevice)); - for(link = 0; link < bus->links; link++) { + for(link = 0; link < busdevice->links; link++) { /* for smbus bus enumerate */ - child = bus->link[link].children; + child = busdevice->link[link].children; if(child && child->path.type == DEVICE_PATH_I2C) { - bus->link[link].secondary = ++smbus_max; + busdevice->link[link].secondary = ++smbus_max; } - for(child = bus->link[link].children; child; child = child->sibling) { + for(child = busdevice->link[link].children; child; child = child->sibling) { if (child->chip_ops && child->chip_ops->enable_dev) { child->chip_ops->enable_dev(child); } @@ -123,8 +123,8 @@ unsigned int scan_static_bus(struct device * bus, unsigned int max) child->enabled?"enabled": "disabled"); } } - for(link = 0; link < bus->links; link++) { - for(child = bus->link[link].children; child; child = child->sibling) { + for(link = 0; link < busdevice->links; link++) { + for(child = busdevice->link[link].children; child; child = child->sibling) { if (!child->ops || !child->ops->phase3) continue; printk(BIOS_SPEW, "%s scanning...\n", dev_path(child)); @@ -132,7 +132,7 @@ unsigned int scan_static_bus(struct device * bus, unsigned int max) } } - printk(BIOS_SPEW, "%s for %s done\n", __func__, dev_path(bus)); + printk(BIOS_SPEW, "%s for %s done\n", __func__, dev_path(busdevice)); return max; } diff --git a/doc/design/newboot.lyx b/doc/design/newboot.lyx index dd5e99b401..ca81026629 100644 --- a/doc/design/newboot.lyx +++ b/doc/design/newboot.lyx @@ -450,11 +450,33 @@ Stage 2: Device tree \begin_layout Standard Run the standard device tree code. This code runs in 6 phases. + The device tree, as set up by dts, has two ways it can be traversed. + +\end_layout + +\begin_layout Standard +The first is the hierarchy formed by busses and devices. + Devices have up to MAX_LINKS links, which are initialized as part of the + process of creating the static tree. + These links point to busses. + A bus has a child device, a device associated with it (e.g. + a PCI bridge device), and other attributes described elsewhere. + Some operations, such as enumeration, require that the tree be traversed + in the hierarchy represented by the bus/device relationship. + This traversal starts at the root device, and for each link, follows those + busses to the other devices. + +\end_layout + +\begin_layout Standard +The second is a simple traversal, via linked list, of all the devices. + This faster, less complex traversal, is performed when there is no need + to be concerned with the bus/device relationship. \end_layout \begin_layout Subparagraph* -Phase 1 +Phase 1 -- making printk work \end_layout \begin_layout Standard @@ -463,6 +485,11 @@ These are any functions that are required to make printk operational. \end_layout +\begin_layout Standard +The simple traversal (forall devices) is used for this phase. + +\end_layout + \begin_layout Standard Post codes: \end_layout @@ -476,12 +503,18 @@ Exit: 0x2f \end_layout \begin_layout Subparagraph* -Phase 2 +Phase 2 -- preparation for bus scan \end_layout \begin_layout Standard These are functions that are required before any PCI operations of any kind are run. + These functions may call printk. + +\end_layout + +\begin_layout Standard +The simple traversal (forall devices) is used for this phase. \end_layout @@ -498,7 +531,301 @@ Exit: 0x3f \end_layout \begin_layout Subparagraph* -Phase 3 +Phase 3 -- bus scan +\end_layout + +\begin_layout Standard +This phase is typical of all the phases that do a hierarchical traversal. + It starts at the root device (i.e. + the mainboard), which uses the distinguished function +\emph on +dev_root_phase3 +\emph default +. + Some root devices have special setup requirements, and there is a way to + call this special setup code. + If the dts has specified a configuration for the root device, it is possible + to set up an enable_dev function. + In other words, for any device, it is possible to call some 'preparation' + code for that device. + We show an example of such a function below, from the qemu mainboard. + First, we show the dts, to show how the chip operations can be enabled. + +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Caption +The dts for the emulation/qemu target +\end_layout + +\begin_layout LyX-Code +/{ config="mainboard,emulation,qemu-i386"; +\end_layout + +\begin_layout LyX-Code +\InsetSpace ~ +\InsetSpace ~ +\InsetSpace ~ +\InsetSpace ~ +cpus { ...}; +\end_layout + +\begin_layout LyX-Code +%% +\end_layout + +\begin_layout LyX-Code +struct mainboard_emulation_qemu_i386_config root = { .nothing = 1, }; +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +The dts has been shortened for readability. + Note the use of the 'config=' in the root. + It specifies that there is an initialized structure after the %% in the + dts file. + The structure is at the bottom. + The dts generates the code shown below. + +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Caption +Code generated for the dts +\end_layout + +\begin_layout LyX-Code +struct mainboard_emulation_qemu_i386_config root = { .nothing = 1, }; +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\begin_layout LyX-Code +struct device dev_root = { +\end_layout + +\begin_layout LyX-Code + .path = { .type = DEVICE_PATH_ROOT }, +\end_layout + +\begin_layout LyX-Code + .chip_ops = &mainboard_emulation_qemu_i386_ops, +\end_layout + +\begin_layout LyX-Code +. +\end_layout + +\begin_layout LyX-Code +. +\end_layout + +\begin_layout LyX-Code +. +\end_layout + +\begin_layout LyX-Code +}; +\end_layout + +\begin_layout LyX-Code + +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +The code after the %% is reproduced exactly. + The dts generates a generic device struct, and initializes the .chip_ops + struct member to point to the mainboard_emulation_qemu_i386_ops structure. + +\end_layout + +\begin_layout Standard +When phase 3 is run, the code checks the chip_ops structure member and, + if it is non-zero, checks the chip_ops->enable_dev pointer and, if it is + non-zero, calls it. + +\end_layout + +\begin_layout Standard +The mainboard code is shown below. + The enable_dev function will be called in phase 3, +\emph on +before +\emph default + any other enumeration is done for that device. + +\end_layout + +\begin_layout Standard +\begin_inset Float figure +wide false +sideways false +status open + +\begin_layout Caption +What the mainboard file looks like with enable_dev +\end_layout + +\begin_layout LyX-Code +static void enable_dev(struct device *dev){ +\end_layout + +\begin_layout LyX-Code + printk(BIOS_INFO, "qemu-i386 enable_dev done +\backslash +n"); +\end_layout + +\begin_layout LyX-Code +} +\end_layout + +\begin_layout LyX-Code +struct chip_operations mainboard_emulation_qemu_i386_ops = { +\end_layout + +\begin_layout LyX-Code + .name = "QEMU Mainboard", +\end_layout + +\begin_layout LyX-Code + .enable_dev = enable_dev +\end_layout + +\begin_layout LyX-Code +}; +\end_layout + +\end_inset + + +\end_layout + +\begin_layout Standard +Root_dev_phase3, which is called with the root +\emph on +device +\emph default +, calls dev_phase3, for each device attached to the root device. + The devices are, in fact, bridge devices, i.e. + the device attached to a bus. + Dev_phase3, in turn, checks the bus device to see if it is a non-NULL pointer, + if is enabled, if it has ops and a phase 3 ops; if so, the functions calls + the bus device's phase 3 op to kick off scanning of busses. + +\end_layout + +\begin_layout Standard +The phase 3 op is different for each type of bus. + For the root bus, which is statically configured, the phase 3 operation + walks the set of statically initialized pointers for the root device; for + the (e.g.) PCI device, which is much more dynamic, the code does actual probing. + +\end_layout + +\begin_layout Standard +Some busses require a reset operation after scanning. + The dev_phase3 code will scan its subordinate busses, and then test all + the busses to see if a reset is needed. + If so, for each bus that needs a reset, a reset is performed, and +\emph on +the bus scanning operation is repeated +\emph default + until a reset is no longer needed. + +\end_layout + +\begin_layout Standard +To sum up, the operation for phase 3, bus scanning, is as follows +\end_layout + +\begin_layout Itemize +The root device is the starting point for bus scanning +\end_layout + +\begin_layout Itemize +After some initial setup, including an optional call to the chip_ops->enable_dev + method for the root device, the dev_phase3 function is called with the + root device as the parameter. + +\end_layout + +\begin_layout Itemize +The dev_phase3 function, after checking that the bus has the ability to + be scanned (i.e. + the device has an ops->phase3 pointer), scans the bus by calling the phase3 + function for the bus. + +\end_layout + +\begin_layout Itemize +If scanning results in a need for a reset, the reset(s) are performed on + the links that need it, and +\emph on +the scan operation is repeated +\emph default +. + This cycle continues until no resets are needed. + +\end_layout + +\begin_layout Standard +The per-device phase 3 operation for a bus has a mutually recursive relationship + with dev_phase3. + The per-device function is called with the pointer to the device that was + passed into dev_phase3. + The per-device phase 3 iterates over the set of child links (i.e. + busses) that are attached to the device and, for each link, checks the + chip_ops of the child link device for each link, and determines whether + to call the enable_dev for each child link device. + The one quite non-intuitive action that some of these functions take is + to enable the child link device, whether the child link device is enabled + or not in the configuration. + This enable is done in order to ensure that child busses are properly enumerate +d, whether they are enabled or not. + +\end_layout + +\begin_layout Standard +Once the child link devices have been properly examined and (for some busses) + set up for enumeration, the per-device phase 3 operation iterates over + the child link devices one more time and calls dev_phase 3 for each child + link device. + This final loop completes the enumeration for this level of the hierarchy. + +\end_layout + +\begin_layout Standard +At the end of the per-device phase 3 operation, the structure of the physical + device tree has been completely determined, including both the static devices + and any dynamic devices, such as cards plugged into PCI slots. + For each level of the tree, the structure which define the devices, and + busses, have been filled in, and the presence or absence of devices has + been determined. + At the end of this pass, it is possible to determine what resources each + device will need, and to allocate those resources as needed. + \end_layout \begin_layout Subparagraph* @@ -506,17 +833,96 @@ Post codes: \end_layout \begin_layout Itemize -Entry: 0x40 +root_dev_phase3 entry: 0x40 \end_layout \begin_layout Itemize -Exit: 0x4f +After enable_dev is tested and potentially called: 0x41 +\end_layout + +\begin_layout Itemize +dev_phase3 entry: 0x42 +\end_layout + +\begin_layout Itemize +dev_phase3 entry: 0x4e (note: since this is a recursive function, the post + codes can cycle from 4e to 43 and back again) +\end_layout + +\begin_layout Itemize +root_dev_phase3 exit: 0x4f \end_layout \begin_layout Subparagraph* Phase 4 \end_layout +\begin_layout Standard +The point of phase 4 is to determine what resources are needed for each + device; to allocate those resources; and to configure the devices with + those resource values. + Resources are determined in one of two ways. + Some devices, if present, have static resource requirements (e.g. + superio parts, which have a fixed requirement for two I/O addresses). + Other devices have resource requirements that can be determined by reading + registers (such as Base Address Registers in PCI) and are hence dynamic. + +\end_layout + +\begin_layout Standard +A similarl mutual recursion is employed, starting again at the root. + The root devices phase 4 ops are called with the root device as a parameter. + For each link on the device, and for each type of resource that is needed + to be determined, the compute_allocate_resource function is called. + This function takes a bus, resource, mask, and type as a parameter. + As busses as scanned, and resources are read, the mask is applied ot the + resource and compared to the type, so as to select the type of resource + desired. + +\end_layout + +\begin_layout Standard +Once the reading of resources is done, the root device has IO resources + as resource 0, and mem resources as resource 1. + +\end_layout + +\begin_layout Standard +After the generic resource reading has been done, there is one special case, + for VGA, which overrides the standard hierarchical traversal. + If VGA console is enabled, the bridges must be configured in such a way + as to pick a +\begin_inset Quotes eld +\end_inset + +primary +\begin_inset Quotes erd +\end_inset + + VGA device. + Once the resources have been enumerated, a function called allocate_vga_resourc +e is called. + This function traverses the devices in non-hierarchical order, and selects + one of them as the VGA device for the so-called +\begin_inset Quotes eld +\end_inset + +compatibilty chain +\begin_inset Quotes erd +\end_inset + +. + Once this device is selected, the function walkss the tree from the device + to the root, enabling the VGA CTL bit in each bridge. + +\end_layout + +\begin_layout Standard +Once this phase has been done, all the memory and IO resources have been + enumerated and allocated to each device, and to each bridge, in the system. + This phase is easily the most complex of all the phases in stage 2. +\end_layout + \begin_layout Subparagraph* Post codes: \end_layout