sonic-buildimage/platform/mellanox/integration-scripts/hwmgmt_helper.py
Vivek 6410e66f35
[Mellanox] Enhance the processing of Kconfig in the hw-mgmt integration (#16752)
- Why I did it
Add an ability to add arm64 mellanox specific kconfig using the integration tool
Fix the existing duplicate kconfig problem by using the vanilla .config
Add an ability to patch kconfig-inclusions file. Renamed series.patch to external-changes.patch to reflect the behavior
NOTE: Min hw-mgmt version to use with these changes: V.7.0030.2000 not yet upstream but required prio to it.
This option will be enabled one the new hw mgmt will be upstream.

Depends on sonic-net/sonic-linux-kernel#336

Signed-off-by: Vivek Reddy Karri <vkarri@nvidia.com>
2023-10-18 19:32:59 +03:00

201 lines
9.3 KiB
Python

#!/usr/bin/env python
#
# Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES.
# Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import os
import io
import sys
import argparse
import shutil
import copy
import difflib
import configparser
from helper import *
################################################################################
#### KConfig Processing ####
################################################################################
class KCFGData:
x86_base = OrderedDict()
x86_updated = OrderedDict()
arm_base = OrderedDict()
arm_updated = OrderedDict()
x86_incl = OrderedDict()
arm_incl = OrderedDict()
x86_excl = OrderedDict()
arm_excl = OrderedDict()
x86_down = OrderedDict()
arm_down = OrderedDict()
noarch_incl = OrderedDict()
noarch_excl = OrderedDict()
noarch_down = OrderedDict()
class KConfigTask():
def __init__(self, args):
self.args = args
def read_data(self):
KCFGData.x86_base = FileHandler.read_kconfig(self.args.config_base_amd)
KCFGData.x86_updated = FileHandler.read_kconfig(self.args.config_inc_amd)
if os.path.isfile(self.args.config_inc_down_amd):
print(" -> Downstream Config for x86 found..")
KCFGData.x86_down = FileHandler.read_kconfig(self.args.config_inc_down_amd)
KCFGData.arm_base = FileHandler.read_kconfig(self.args.config_base_arm)
KCFGData.arm_updated = FileHandler.read_kconfig(self.args.config_inc_arm)
if os.path.isfile(self.args.config_inc_down_arm):
print(" -> Downstream Config for arm64 found..")
KCFGData.arm_down = FileHandler.read_kconfig(self.args.config_inc_down_arm)
return
def parse_inc_exc(self, base: OrderedDict, updated: OrderedDict):
# parse the updates/deletions in the Kconfig
add, remove = OrderedDict(), copy.deepcopy(base)
for (key, val) in updated.items():
if val != base.get(key, "empty"):
add[key] = val
# items remaining in remove are the ones to be excluded
if key in remove:
del remove[key]
return add, remove
def parse_noarch_inc_exc(self):
# Filter the common inc/excl out from the arch specific inc/excl
x86_incl_base = copy.deepcopy(KCFGData.x86_incl)
for (key, val) in x86_incl_base.items():
if key in KCFGData.arm_incl and val == KCFGData.arm_incl[key]:
print("-> INFO: NoArch KConfig Inclusion {}:{} found and moving to common marker".format(key, val))
del KCFGData.arm_incl[key]
del KCFGData.x86_incl[key]
KCFGData.noarch_incl[key] = val
x86_excl_base = copy.deepcopy(KCFGData.x86_excl)
for (key, val) in x86_excl_base.items():
if key in KCFGData.arm_excl:
print("-> INFO: NoArch KConfig Exclusion {} found and moving to common marker".format(key))
del KCFGData.arm_excl[key]
del KCFGData.x86_excl[key]
KCFGData.noarch_excl[key] = val
if not (KCFGData.x86_down or KCFGData.arm_down):
return
# Filter the common inc config from the downstream kconfig
x86_down_base = copy.deepcopy(KCFGData.x86_down)
for (key, val) in x86_down_base.items():
if key in KCFGData.arm_down:
print("-> INFO: NoArch KConfig Downstream Inclusion {} found and moving to common marker".format(key))
del KCFGData.arm_down[key]
del KCFGData.x86_down[key]
KCFGData.noarch_down[key] = val
def insert_arm64_section(self, raw_lines: list, arm_data: OrderedDict, is_exclusion=False, section=MLNX_ARM_KFG_SECTION) -> list:
# For arm64, config is not added under markers, but it is added under the section [mellanox-arm64]
# This design decision is taken because of the possibility that there might be conflicting options
# present between two different arm64 platforms
try:
# comment_prefixes needed to also read comments under a section
configParser = configparser.ConfigParser(allow_no_value=True, strict=False, comment_prefixes='////')
configParser.optionxform = str
configParser.read_string("".join(raw_lines))
if not configParser.has_section(MLNX_ARM_KFG_SECTION):
configParser.add_section(MLNX_ARM_KFG_SECTION)
for (key, val) in arm_data.items():
if not is_exclusion:
configParser.set(MLNX_ARM_KFG_SECTION, key, val)
else:
configParser.set(MLNX_ARM_KFG_SECTION, key)
str_io = io.StringIO()
configParser.write(str_io, space_around_delimiters=False)
return str_io.getvalue().splitlines(True)
except Exception as e:
print("-> FATAL: Exception {} found while adding opts under arm".format(str(e)))
raise e
return raw_lines
def get_kconfig_inc(self) -> list:
kcfg_inc_raw = FileHandler.read_raw(os.path.join(self.args.build_root, SLK_KCONFIG))
# Insert common config
noarch_start, noarch_end = FileHandler.find_marker_indices(kcfg_inc_raw, MLNX_NOARCH_MARKER)
kcfg_inc_raw = FileHandler.insert_kcfg_data(kcfg_inc_raw, noarch_start, noarch_end, KCFGData.noarch_incl)
# Insert x86 config
x86_start, x86_end = FileHandler.find_marker_indices(kcfg_inc_raw, MLNX_KFG_MARKER)
kcfg_inc_raw = FileHandler.insert_kcfg_data(kcfg_inc_raw, x86_start, x86_end, KCFGData.x86_incl)
# Insert arm config
kcfg_inc_raw = self.insert_arm64_section(kcfg_inc_raw, KCFGData.arm_incl)
print("\n -> INFO: kconfig-inclusion file is generated \n {}".format("".join(kcfg_inc_raw)))
return kcfg_inc_raw
def get_downstream_kconfig_inc(self, new_kcfg_upstream) -> list:
kcfg_final = copy.deepcopy(new_kcfg_upstream)
# insert common Kconfig
noarch_start, noarch_end = FileHandler.find_marker_indices(kcfg_final, MLNX_NOARCH_MARKER)
noarch_final = OrderedDict(list(KCFGData.noarch_incl.items()) + list(KCFGData.noarch_down.items()))
kcfg_final = FileHandler.insert_kcfg_data(kcfg_final, noarch_start, noarch_end, noarch_final)
# insert x86 Kconfig
x86_start, x86_end = FileHandler.find_marker_indices(kcfg_final, MLNX_KFG_MARKER)
x86_final = OrderedDict(list(KCFGData.x86_incl.items()) + list(KCFGData.x86_down.items()))
kcfg_final = FileHandler.insert_kcfg_data(kcfg_final, x86_start, x86_end, x86_final)
# insert arm Kconfig
arm_final = OrderedDict(list(KCFGData.arm_incl.items()) + list(KCFGData.arm_down.items()))
kcfg_final = self.insert_arm64_section(kcfg_final, arm_final)
# generate diff
diff = difflib.unified_diff(new_kcfg_upstream, kcfg_final, fromfile='a/patch/kconfig-inclusions', tofile="b/patch/kconfig-inclusions", lineterm="\n")
lines = []
for line in diff:
lines.append(line)
print("\n -> INFO: kconfig-inclusion.patch file is generated \n{}".format("".join(lines)))
return lines
def get_kconfig_excl(self) -> list:
# noarch_excl
kcfg_excl_raw = FileHandler.read_raw(os.path.join(self.args.build_root, SLK_KCONFIG_EXCLUDE))
# insert common Kconfig
noarch_start, noarch_end = FileHandler.find_marker_indices(kcfg_excl_raw, MLNX_NOARCH_MARKER)
kcfg_excl_raw = FileHandler.insert_kcfg_excl_data(kcfg_excl_raw, noarch_start, noarch_end, KCFGData.noarch_excl)
# insert x86 Kconfig
x86_start, x86_end = FileHandler.find_marker_indices(kcfg_excl_raw, MLNX_KFG_MARKER)
kcfg_excl_raw = FileHandler.insert_kcfg_excl_data(kcfg_excl_raw, x86_start, x86_end, KCFGData.x86_excl)
# insert arm Kconfig
kcfg_excl_raw = self.insert_arm64_section(kcfg_excl_raw, KCFGData.arm_excl, True)
print("\n -> INFO: kconfig-exclusion file is generated \n{}".format("".join(kcfg_excl_raw)))
return kcfg_excl_raw
def perform(self):
self.read_data()
KCFGData.x86_incl, KCFGData.x86_excl = self.parse_inc_exc(KCFGData.x86_base, KCFGData.x86_updated)
KCFGData.arm_incl, KCFGData.arm_excl = self.parse_inc_exc(KCFGData.arm_base, KCFGData.arm_updated)
self.parse_noarch_inc_exc()
# Get the updated kconfig-inclusions
kcfg_inc_upstream = self.get_kconfig_inc()
FileHandler.write_lines(os.path.join(self.args.build_root, SLK_KCONFIG), kcfg_inc_upstream, True)
# Get the updated kconfig-exclusions
kcfg_excl_upstream = self.get_kconfig_excl()
FileHandler.write_lines(os.path.join(self.args.build_root, SLK_KCONFIG_EXCLUDE), kcfg_excl_upstream, True)
# return the kconfig-inclusions diff
return self.get_downstream_kconfig_inc(kcfg_inc_upstream)