Hardware Self-Discovery
更新时间: 2024/12/19
在Gitcode上查看源码

In openUBMC, service components can manage hardware through the combination of the MDS data model and CSR. However, fixed configurations are not conducive to diversified hardware adaptation. Therefore, openUBMC introduces the hardware self-discovery framework to implement flexible self-discovery management for hardware components.

Hardware Self-Discovery Framework

Hardware self-discovery belongs to the openUBMC framework and is part of southbound hardware access. Self-discovery management of hardware components is implemented based on the hwproxy hardware proxy to provide services with object data, data references, and synchronization relationships. The hwdiscovery app is the implementation of hardware self-discovery.

Hardware Self-Discovery Service Process

  • When the hwdiscovery app is started, MDS description files are searched in specified paths to obtain definitions of classes, properties, and resource collaboration interfaces, and construct mappings between classes and components.
  • Hwdiscovery accesses the system flash partition to obtain root.sr files describing link topology information of product chips; it also obtains platform.sr files that describe software configuration object information.
  • Hwdiscovery parses object information, identifies objects' owning components based on their mappings with classes, and releases object data as groups.
  • After receiving the object group release signals, other components obtain the owning component's object information through hwdiscovery interfaces, add objects, and provide services for external systems. Meanwhile, the hardware proxy has to obtain topology link information through the interfaces and establish hardware topology links.
  • Hwdiscovery loads connector objects, and executes concurrent discovery of lower-level components based on the connector identification mode and presence status. The process includes reading EEPROM data, obtaining CSR file data, parsing object data, releasing object groups, and repeating the preceding self-discovery process.

CSR Parsing Process

Parsing, verifying, and decompressing CSR data is a cyclic process performed in hierarchical loading mode. See the following figure.

openUBMC cards are connected directly to the system extension unit (EXU), which is then connected to the basic computing unit (BCU), heat dissipation component (CLU), storage expansion component (SEU), and onboard network interface card (NIC). BCU is then connected to riser cards, where various PCIe cards are inserted. The connection between boards and cards is represented by Connector, and the self-discovery process is performed in the preceding loading sequence.

After a CSR is parsed, the data is placed in the ObjectGroup based on mappings between classes and components, and the owning component of the class is marked as Owner. The ObjectGroup is distributed to each service app after assembled.

The next-level self-discovery is then started, and the Connector object defined in the CSR is checked. The Connector defines the type and source of the CSR at the next level. For Tianchi components, specified chips are required to read the CSRs stored in EEPROM, the packed CSRs must be obtained using bom_id_auxid, and multiple versions of CSRs have to be compared to determine the latest record.

Once determined, the parsing, verification, and decompression in the next phase are started.

Renaming Rules for Self-Described Objects

To ensure the object name defined by CSR is globally unique, the self-described object in each CSR has to be renamed. The renamed object name consists of the name defined by CSR and the _${Position} suffix. For example:

NetworkPort_1_010105
ExpBoard_1_0101
RiserCard_1_01010103

The Position suffix is composed of multiple two-digit hexadecimal numbers. Each number represents the Position property of the corresponding Connector in different CSRs.

The first number is the entry for parsing CSR data and has a fixed name. "00" indicates platform.sr, and "01" indicates root.sr.

GroupPosition of a Connector object, which is the Position suffix for lower-level CSR objects, is formed by combining the Position suffix (GroupPosition property of the upper-level Connector) of the Connector object with the Connector object's Position property configured in CSRs. For example, the Position of the Connector configured in BCU is the Position 1 of the Connector_BCU_1 configured in EXU (the CSR Position is 0101). After combining these two parts, the Position of the Connector in BCU becomes 010101.

External Interfaces

The hwdiscovery app provides interfaces for obtaining the owning component's object data after releasing object groups, and interfaces for obtaining topology links.

The app displays the objects of each CSR as ObjectGroup on resource collaboration interfaces. The ID is named by Position. For example:

├─/bmc/kepler/ObjectGroup
│ ├─/bmc/kepler/ObjectGroup/00
│ ├─/bmc/kepler/ObjectGroup/01
│ ├─/bmc/kepler/ObjectGroup/0101
│ ├─ ...
└─/bmc/kepler/hwdiscovery

ObjectGroup provides the GetObjects interface. The input parameters are a{ss}(context parameter)s(owner, which is the name of the app obtaining specified objects), and the output parameters are s(component Position)a{ssss(class name, object name, object property, and extended property)}u(component object lifecycle ID). For example, to view the ObjectGroup distributed to network_adapter, run the following command:

shell
busctl --user call bmc.kepler.hwdiscovery /bmc/kepler/ObjectGroup/010109 bmc.kepler.ObjectGroup GetObjects 'a{ss}s' 0 network_adapter

010109 is the position of the NIC CSR distributed to network_adapter. The object position under the resource collaboration interface can be viewed through busctl --user tree bmc.kepler.network_adapter. 0 following a{ss}s indicates that the number of context parameters is 0 and no context parameter needs to be input. network_adapter is the filter criterion for viewing the object information distributed by ObjectGroup to the network_adapter component.

The ObjectGroup distributed to hwdiscovery can also be obtained using this method. Run the following command:

shell
busctl --user call bmc.kepler.hwdiscovery /bmc/kepler/ObjectGroup/01 bmc.kepler.ObjectGroup GetObjects 'a{ss}s' 0 'hwdiscovery'

sa(ssss)u "01" 2 "Connector" "Connector_xxx_01" "{\"Position\":2,\"ChassisId\":\"1\",\"ManagerId\":\"1\",\"SystemId\":1,\"AuxId\":\"0\",\"Buses\":[],\"Id\":\"Sensor\",\"Presence\":1,\"Slot\":99,\"GroupId\":4,\"GroupPosition\":\"0102\",\"IdentifyMode\":2,\"Bom\":\"9999\"}" "{\"Path\":\"\\/bmc\\/kepler\\/Connector\\/Connector_Sensor_01\",\"Position\":\"01\",\"ChassisId\":\"\",\"ManagerId\":\"1\",\"SystemId\":0,\"Framework\":true}" "Connector" "Connector_xxx_1_01" "{ ... } 1
``
The hardware information of other components can be obtained using similar methods. In addition, the built-in properties of ObjectGroup can be viewed through `introspect`.
shell
busctl --user introspect bmc.kepler.hwdiscovery /bmc/kepler/ObjectGroup/01

(output)
NAME                                TYPE      SIGNATURE   RESULT/VALUE                             FLAGS
bmc.kepler.Object.Properties        interface -           -                                        -
.GetAllWithContext                  method    a{ss}s      a{sv}                                    -
.GetOptions                         method    a{ss}ss     a{ss}                                    -
.GetPropertiesByNames               method    a{ss}sas    a{sv}a{sv}                               -
.GetPropertiesByOptions             method    a{ss}sa{ss} as                                       -
.GetWithContext                     method    a{ss}ss     v                                        -
.SetWithContext                     method    a{ss}ssv    -                                        -
.ClassName                          property  s           "ObjectGroup"                            emits-change
.ObjectIdentifier                   property  (ysss)      0 "" "" ""                               emits-change
.ObjectName                         property  s           "ObjectGroup_01"                         emits-change
bmc.kepler.ObjectGroup              interface -           -                                        -
.GetObjects                         method    a{ss}s      sa(ssss)u                                -
.GetTopology                        method    a{ss}       s                                        -
.OnlineTimestamp                    property  t           99999                                    emits-change
.Owners                             property  as          5 "hwdiscovery" "general_hardware"       emits-change
.Position                           property  s           "01"                                     emits-change
org.freedesktop.DBus.Introspectable interface -           -                                        -
.Introspect                         method    -           s                                        -
org.freedesktop.DBus.ObjectManager  interface -           -                                        -
.GetManagedObjects                  method    -           a{oa{sa{sv}}}                            -
org.freedesktop.DBus.Peer           interface -           -                                        -
.GetMachineId                       method    -           s                                        -
.Ping                               method    -           -                                        -
org.freedesktop.DBus.Properties     interface -           -                                        -
.Get                                method    ss          v                                        -
.GetAll                             method    s           a{sv}                                    -
.Set                                method    ssv         -                                        -
.PropertiesChanged                  signal    sa{sv}as    -                                        -

Obtaining Service-Side Objects

Some MDS properties come from CSRs. For example:

json
"SlotNumber":{
    "usage":[
        "CSR"
    ]
}

For details about the MDS definition, see MDS.

On the service side, registered objects can be distributed in either of the following ways: object_manage that allows developers to customize service processes, or ORM that inherits the advantages of object_manage and supports the database index mode.

object_manage

Registered objects can be distributed using object_manage. For example, to load GPUs in general_hardware, use the following definition in app.lua:

lua
local object_manage = require 'mc.mdb.object_manage'

function gen_hw_app:init_on_add_object()
    object_manage.on_add_object(self.bus, function(class_name, object, position)  -- object_manage registration framework
        self.gpu_service.on_add_object(class_name, object, position) --object receiving and processing process
    end) 
end

During object_manage registration, three parameters are input: class_name, object, and position. They are distributed by the hwdiscovery app.

class_name: The object is generally defined in CSRs in the format of class_name + index, for example, GPU_1. Therefore, the corresponding class_name is GPU.

object: This object is distributed by the hwdiscovery app. Its value can be found in the corresponding ObjectGroup.

position: The position is corresponding to the ObjectGroup distribution.

In gpu_service, on_add_object completes object receiving in the following process:

lua
function gpu_service:on_add_object(class_name, object, position)
    local switch = {
        ['GPU'] = function ()
            self:add_object(object, position)
        end
    }

    if switch[class_name] then
        switch[class_name]()
        log:info('[gpu_service] Add object, Class: %s', class_name)
    end
end

function gpu_service:add_object(obj, position)
    local gpu = gpu_object.new_for_csr(obj, position)
    table.insert(self.gpu_collection, gpu)
    ...
end

In the process of receiving service objects, use switch to filter class_name, parse the obj object in gpu_object.new_for_csr, and obtain obj properties through obj.property. Finally, add the gpu object to self.gpu_collection for unified management. During service processing, changes to objects in self.gpu_collection are reflected on resource collaboration interfaces.

ORM

When using ORM, the tableName of objects has to be clarified in model.json. For example, the following is defined in network_adapter:

json
"NetworkAdapter": {
    "tableName": "t_network_adapter",
    "tableType": "PoweroffPer",
    ...
    "interfaces": {
        "bmc.kepler.Systems.NetworkAdapter": {
            "properties": {
                "ID": {
                    "primaryKey": true
                },
                "SystemID": {
                    "usage": [
                        "CSR"
                    ]
                },
                ...
            }
        }
    }
}

On the service side, the use of orm_object_manage has to be defined in app.lua. For example:

lua
local c_object_manage = require 'mc.orm.object_manage'

function app:init()
    ...
    self.object_manage = c_object_manage.new(self.db, self.bus)
    self.objcet_mage.app = app
    self.object_manage.per_db = self.db
    ...
    self.object_manage:start() -- Start processing ORM objects from the hwdiscovery app.
end

On the service side, a method of the ORM object has to be overridden. For example, in network_adapter, the object definition is as follows:

lua
function c_network_adapter.create_mdb_object(value)
    local app = c_object_manage.get_instance().app
    return app:CreateNetworkAdapter(1, value.ID, function (obj)  -- Resource object creation
        log:debug("create network adapter id(%s), nodeid(%s), type(%d), RootBDF(%s)",
            value.ID, value.NodeId, value.Type, value.RootBDF)
        obj.ID = value.ID
        obj.NodeId = value.NodeId
        obj.Type = value.Type
        obj.RootBDF = value.RootBDF
    end)
end

obj is the object from the hwdiscovery app, and value is persistent information in the database. In this way, resource objects can be preprocessed and the property values can be modified when creating objects.

In the service, collection.find can be used to query and invoke any method in ORM objects. For details about the ORM database, see the ORM Object Management Framework User Guide.