Merge pull request #12 from opencomputeproject/master

merge from upstream
This commit is contained in:
Lewis Kang
2018-04-19 16:56:52 +08:00
committed by GitHub
1475 changed files with 106568 additions and 19355 deletions

12
.gitmodules vendored
View File

@@ -1,21 +1,21 @@
[submodule "packages/base/any/initrds/buildroot/builds/buildroot-mirror"]
path = packages/base/any/initrds/buildroot/builds/buildroot-mirror
url = git://github.com/opennetworklinux/buildroot-mirror
url = http://github.com/opennetworklinux/buildroot-mirror
[submodule "packages/base/any/kernels/legacy/linux-3.9.6"]
path = packages/base/any/kernels/legacy/linux-3.9.6
url = git://github.com/opennetworklinux/linux-3.9.6
url = http://github.com/opennetworklinux/linux-3.9.6
[submodule "sm/infra"]
path = sm/infra
url = git://github.com/floodlight/infra
url = http://github.com/floodlight/infra
[submodule "sm/bigcode"]
path = sm/bigcode
url = git://github.com/floodlight/bigcode
url = http://github.com/floodlight/bigcode
[submodule "packages/base/any/kernels/legacy/linux-3.8.13"]
path = packages/base/any/kernels/legacy/linux-3.8.13
url = git://github.com/opennetworklinux/linux-3.8.13
url = http://github.com/opennetworklinux/linux-3.8.13
[submodule "packages/platforms-closed"]
path = packages/platforms-closed
url = git@github.com:opennetworklinux/platforms-closed
[submodule "sm/build-artifacts"]
path = sm/build-artifacts
url = git://github.com/opennetworklinux/build-artifacts
url = http://github.com/opennetworklinux/build-artifacts

View File

@@ -144,7 +144,19 @@ if test "$installer_debug"; then
fi
# Pickup ONIE defines for this machine.
if test -r /etc/machine.conf; then
if test "$onie_platform"; then
:
else
onie_platform=$(onie-sysinfo -p 2>/dev/null) || :
fi
if test "$onie_arch"; then
:
else
onie_arch=$(onie-sysinfo -c 2>/dev/null) || :
fi
if test "$onie_platform"; then
:
elif test -r /etc/machine.conf; then
. /etc/machine.conf
fi
@@ -252,7 +264,7 @@ if test "${onie_platform}"; then
}
else
if test "$ARCH_X86"; then
echo "Missing onie_platform (invalid /etc/machine.conf)" 1>&2
echo "Missing onie_platform (invalid or missing onie-sysinfo or /etc/machine.conf)" 1>&2
exit 1
fi
#
@@ -472,6 +484,11 @@ mkdir -p "${rootdir}/etc/onl"
cp /dev/null "${rootdir}/etc/onl/installer.conf"
echo "onl_version=\"$onl_version\"" >> "${rootdir}/etc/onl/installer.conf"
# pass in the platform identifier, otherwise encoded in
# machine-XXX.conf and onie-sysinfo
echo "onie_platform=$onie_platform" >> "${rootdir}/etc/onl/installer.conf"
echo "onie_arch=$onie_arch" >> "${rootdir}/etc/onl/installer.conf"
# Generate the MD5 signature for ourselves for future reference.
installer_md5=$(md5sum "$0" | awk '{print $1}')
echo "installer_md5=\"$installer_md5\"" >> "${rootdir}/etc/onl/installer.conf"
@@ -561,7 +578,7 @@ if test -f "$postinst"; then
fi
installer_unzip $installer_zip postinstall.sh || :
if test -f preinstall.sh; then
if test -f postinstall.sh; then
chmod +x postinstall.sh
./postinstall.sh $rootdir
fi

View File

@@ -78,3 +78,4 @@
- tcpdump
- strace
- sysstat
- ipmitool

View File

@@ -11,5 +11,7 @@
- hw-management
- sx-kernel
- onl-kernel-3.16-lts-x86-64-all-modules
- onl-kernel-4.9-lts-x86-64-all-modules
- onl-kernel-4.14-lts-x86-64-all-modules
- efibootmgr
- gdisk

View File

@@ -23,7 +23,7 @@ Multistrap:
noauth: true
explicitsuite: false
unpack: true
debootstrap: Debian-Local Local-All Local-Arch ONL
debootstrap: Debian-Local Local-All Local-Arch ONL-Local
aptsources: Debian ONL
Debian:
@@ -46,6 +46,12 @@ Multistrap:
suite: unstable
omitdebsrc: true
ONL-Local:
packages: *Packages
source: http://${APT_CACHE}apt.opennetlinux.org/debian
suite: unstable
omitdebsrc: true
Local-All:
source: ${ONLPM_OPTION_REPO}/${ONL_DEBIAN_SUITE}/packages/binary-all
omitdebsrc: true

View File

@@ -41,6 +41,7 @@
- usbutils
- mtd-utils
- i2c-tools
- kmod
- isc-dhcp-client
- ntp
- wget

View File

@@ -9,7 +9,7 @@
- grub2
- onl-upgrade
- hw-management
- sx-kernel
- onl-kernel-3.16-lts-x86-64-all-modules
- onl-kernel-4.9-lts-x86-64-all-modules
- onl-kernel-4.14-lts-x86-64-all-modules
- efibootmgr
- gdisk

View File

@@ -23,7 +23,7 @@ Multistrap:
noauth: true
explicitsuite: false
unpack: true
debootstrap: Debian-Local Local-All Local-Arch ONL
debootstrap: Debian-Local Local-All Local-Arch ONL-Local
aptsources: Debian ONL
Debian:
@@ -46,6 +46,12 @@ Multistrap:
suite: unstable
omitdebsrc: true
ONL-Local:
packages: *Packages
source: http://${APT_CACHE}apt.opennetlinux.org/debian
suite: unstable
omitdebsrc: true
Local-All:
source: ${ONLPM_OPTION_REPO}/${ONL_DEBIAN_SUITE}/packages/binary-all
omitdebsrc: true

View File

@@ -42,7 +42,7 @@ Multistrap:
ONL:
packages: *Packages
source: http://apt.opennetlinux.org/debian
source: http://${APT_CACHE}apt.opennetlinux.org/debian
suite: unstable
omitdebsrc: true

24
docs/README-proxy.md Normal file
View File

@@ -0,0 +1,24 @@
# How to build ONL behind an HTTP Proxy
Many corporate environments don't provide native access to the Internet
and instead all access must go through an HTTP proxy. Since the ONL
build process dynamically pulls lots of things, this can be a pain.
While everyone's setup is different, hopefully these directions help
reduce that pain.
* Make sure you have apt-cacher-ng installed in your host (non-docker)
environment and that docker starts it. Next, configure it to use
your proxy:
$ grep Proxy /etc/apt-cacher-ng/acng.conf
Proxy: http://myproxy.mycompany.com:8080
$ sudo /etc/init.d/apt-cacher-ng restart
* Make sure your git config is configured correctly for
proxies:
$ cat ~/.gitconfig
[https]
proxy = myproxy.mycompany.com:8080
[https]
proxy = myproxy.mycompany.com:8080

View File

@@ -1,107 +1,114 @@
Hardware Support
================
Because of the HTML formatting, this page may be best viewed from
<http://opennetlinux.org/hcl>
Quanta
------
<table class="table table-striped table-hover">
<thead>
<tr class="info">
<th> Device <th> Ports <th> CPU <th> Forwarding <th> ONL Certified <th> In Lab <th> OF-DPA <th> OpenNSL <th> SAI </tr>
</thead>
<tr> <td> QuantaMesh T1048-LB9 <td> 48x1G + 4x10G <td> FreeScale P2020 <td> Broadcom BCM56534 (Firebolt3) <td> Yes <td> Yes <td> No <td> No <td> No </tr>
<tr> <td> QuantaMesh T3048-LY2 <td> 48x10G + 4x40G <td> FreeScale P2020 <td> Broadcom BCM56846 (Trident+) <td> Yes <td> Yes <td> No <td> No <td> No </tr>
<tr> <td> QuantaMesh T3048-LY8 <td> 48x10G + 6x40G <td> Intel Rangeley C2758 x86 <td> Broadcom BCM56854 (Trident2) <td> Yes <td> Yes <td> No <td> No <td> No </tr>
<tr> <td> QuantaMesh T5032-LY6 <td> 32x40G <td> Intel Rangeley C2758 x86 <td> Broadcom BCM56850 (Trident2) <td> Yes <td> Yes <td> No <td> No <td> No </tr>
<tr> <td> QuantaMesh T3048-LY9 <td> 48x10GT + 6x40G <td> Intel Rangeley C2758 x86 <td> Broadcom BCM56850 (Trident2) <td> Yes <td> Yes <td> No <td> No <td> No </tr>
</table>
Accton/Edge-Core
------
<table class="table table-striped table-hover">
<thead>
<tr class="info">
<th> Device <th> Ports <th> CPU <th> Forwarding <th> ONL Certified <th> In Lab <th> OF-DPA <th> OpenNSL <th> SAI </tr>
</thead>
<tr> <td> Accton AS4600-54T <td> 48x1G + 4x10G <td> FreeScale P2020 <td> Broadcom BCM56540 (Apollo2) <td> Yes <td> Yes <td> Yes*** <td> Yes*** <td> No </tr>
<tr> <td> Accton AS4610-54P <td> 48x1G + 4x10G + 2x20G <td> Dual-core ARM Cortex A9 1GHz <td> Broadcom BCM56340 (Helix4) <td> Yes <td> Yes <td> No <td> No <td> No </tr>
<tr> <td> Accton AS5610-52X <td> 48x10G + 4x40G <td> FreeScale P2020 <td> Broadcom BCM56846 (Trident+) <td> Yes <td> Yes <td> No <td> No <td> No </tr>
<tr> <td> Accton AS5710-54X <td> 48x10G + 6x40G <td> FreeScale P2041 <td> Broadcom BCM56854 (Trident2) <td> Yes <td> Yes <td> Yes*** <td> Yes*** <td> No </tr>
<tr> <td> Accton AS6700-32X <td> 32x40G <td> FreeScale P2041 <td> Broadcom BCM56850 (Trident2) <td> Yes <td> Yes <td> No <td> No <td> No </tr>
<tr> <td> Accton AS5512-54X <td> 48x10G + 6x40G <td> Intel Rangeley C2538 x86 <td> MediaTek/Nephos MT3258 <td> Yes <td> Yes <td> No <td> No <td> No </tr>
<tr> <td> Accton AS5712-54X <td> 48x10G + 6x40G <td> Intel Rangeley C2538 x86 <td> Broadcom BCM56854 (Trident2) <td> Yes <td> Yes <td> Yes*** <td> Yes*** <td> No </tr>
<tr> <td> Accton AS6712-32X <td> 32x40G <td> Intel Rangeley C2538 x86 <td> Broadcom BCM56850 (Trident2) <td> Yes <td> Yes <td> Yes*** <td> Yes*** <td> No </tr>
<tr> <td> Accton AS5812-54T <td> 48x10G + 6x40G <td> Intel Rangeley C2538 x86 <td> Broadcom BCM56864 (Trident2+) <td> Yes <td> Yes <td> No <td> No <td> No </tr>
<tr> <td> Accton AS5812-54X <td> 48x10G + 6x40G <td> Intel Rangeley C2538 x86 <td> Broadcom BCM56864 (Trident2+) <td> Yes <td> Yes <td> Yes*** <td> Yes*** <td> No </tr>
<tr> <td> Accton AS6812-32X <td> 32x40G <td> Intel Rangeley C2538 x86 <td> Broadcom BCM56864 (Trident2+) <td> Yes <td> Yes <td> Yes*** <td> Yes*** <td> No </tr>
<tr> <td> Accton AS7712-32X <td> 32x100G <td> Intel Rangeley C2538 x86 <td> Broadcom BCM56960 (Tomahawk) <td> Yes <td> Yes <td> Yes*** <td> Yes*** <td> No </tr>
<tr> <td> Accton AS7716-32X <td> 32x100G <td> Intel Xeon D-1518 x86 <td> Broadcom BCM56960 (Tomahawk) <td> Yes <td> Yes <td> Yes*** <td> Yes*** <td> No </tr>
<tr> <td> Accton Wedge-16X <td> 16x40G <td> Intel Rangeley C2550 x86 <td> Broadcom BCM56864 (Trident2+) <td> Work In Progress** <td> Yes <td> No <td> Yes <td> No </tr>
<tr> <td> Accton (FB) Wedge 100 <td> 32x100G <td> Intel Bay Trail E3845 x86 <td> Broadcom BCM56960 (Tomahawk) <td> Work In Progress** <td> Yes <td> No <td> Yes <td> No </tr>
</table>
Device Ports CPU Forwarding In Lab
Accton AS4600-54T 48x1G + 4x10G FreeScale P2020 Broadcom BCM56540 (Apollo2) Yes
Accton AS4610-54P 48x1G + 4x10G + 2x20G Dual-core ARM Cortex A9 Broadcom BCM56340 (Helix4) Yes
Accton AS5512-54X 48x10G + 6x40G Intel C2538 MediaTek/Nephos MT3258 Yes
Accton AS5610-52X 48x10G + 4x40G FreeScale P2020 Broadcom BCM56846 (Trident+) Yes
Accton AS5710-54X 48x10G + 6x40G FreeScale P2041 Broadcom BCM56854 (Trident2) Yes
Accton AS5712-54X 48x10G + 6x40G Intel C2538 Broadcom BCM56854 (Trident2) Yes
Accton AS5812-54T 48x10G + 6x40G Intel C2538 Broadcom BCM56864 (Trident2+) Yes
Accton AS5812-54X 48x10G + 6x40G Intel C2538 Broadcom BCM56864 (Trident2+) Yes
Accton AS5822-32X 48x10G + 6x100G Intel C2558 Broadcom BCM88375 (Qumran) Yes
Accton AS5912-54X 48x10G + 6x100G Intel C2558 Broadcom BCM88375 (Qumran) Yes
Accton AS5912-54XK 48x10G + 6x100G Intel C2558 Broadcom BCM88375 (Qumran) Yes
Accton AS5916-54XM 48x10G + 6x100G Intel C2558 Broadcom BCM88375 (Qumran) No
Accton AS5916-54X 48x10G + 6x100G Intel C2558 Broadcom BCM88375 (Qumran) No
Accton AS6700-32X 32x40G FreeScale P2041 Broadcom BCM56850 (Trident2) Yes
Accton AS6712-32X 32x40G Intel C2538 Broadcom BCM56850 (Trident2) Yes
Accton AS6812-32X 32x40G Intel C2538 Broadcom BCM56864 (Trident2+) Yes
Accton AS7312-54X 48x25G + 6x100G Intel C2558 Broadcom BCM88375 (Qumran) Yes
Accton AS7712-32X 32x100G Intel C2538 Broadcom BCM56960 (Tomahawk) Yes
Accton AS7716-32X 32x100G Intel Xeon D-1518 Broadcom BCM56960 (Tomahawk) Yes
Accton AS7816-64X 64x100 Intel C2558 Broadcom BCM56970 (Tomahawk II) Yes
Accton Wedge-16X 16x40G Intel C2550 Broadcom BCM56864 (Trident2+) Yes
Accton Wedge 100-32X 32x100G Intel E3845 Broadcom BCM56960 (Tomahawk) Yes
Accton Wedge 100S-32X 32x100G Intel D1508 Broadcom BCM56960 (Tomahawk) Yes
Alpha Networks
---
Device Ports CPU Forwarding In Lab
SNX-60A0-486F 48x10G + 6x40G Intel C2558 Broadcom BCM56850 (Trident2) Yes
Celestica
---
Device Ports CPU Forwarding In Lab
Redstone-XP 48x10G + 6x40G Intel C2558 Broadcom BCM56854 (Trident2) Yes
Seastone 32x100G Intel C2558 Broadcom BCM56960 (Tomahawk) No
DNI/Agema
---
<table class="table table-striped table-hover">
<thead>
<tr class="info">
<th> Device <th> Ports <th> CPU <th> Forwarding <th> ONL Certified <th> In Lab <th> OF-DPA <th> OpenNSL <th> SAI </tr>
</thead>
<tr> <td> AG-7448CU <td> 48x10G + 4x40G <td> FreeScale P2020 <td> Broadcom BCM56845 (Trident) <td> Yes <td> Yes <td> No <td> No <td> No </tr>
</table>
Device Ports CPU Forwarding In Lab
AG-7448CU 48x10G + 4x40G FreeScale P2020 Broadcom BCM56845 (Trident) Yes
AG-5648 48x25G + 6x100G Intel D1548 Broadcom BCM56960 (Tomahawk) No
AG-5648v1 48x25G + 6x100G Intel D1548 Broadcom BCM56963 (Tomahawk+) No
AG-7648 48x10G + 6x40G Intel D1548 Broadcom BCM56854 (Trident2) Yes
AG-9032v1 32x100G Intel D1548 Broadcom BCM56960 (Tomahawk) Yes
AG-9032v2 32x100G Intel D1548 Broadcom BCM56963 (Tomahawk+) No
AG-9064 64x100G Intel D1547 Broadcom BCM56970 (Tomahawk II) No
AGC-5648S 48x25G + 6x100G Intel D1548 Broadcom BCM88680 (Jericho+) No
AGC-7648A 48x10G + 6x100G Intel D1548 Broadcom BCM88370 (Qumran MX) No
WB-2448 48x1GT + 4x10G Intel E3805 Broadcom BCM56150 (Hurricane2) No
AG-6248C 48x1GT + 2x10G ARM A9 1GHz Broadcom BCM56340 (Helix4) Yes
Dell
---
<table class="table table-striped table-hover">
<thead>
<tr class="info">
<th> Device <th> Ports <th> CPU <th> Forwarding <th> ONL Certified <th> In Lab <th> OF-DPA <th> OpenNSL <th> SAI </tr>
</thead>
<tr> <td> S4810-ON <td> 48x10G + 4x40G <td> FreeScale P2020 <td> Broadcom BCM56845 (Trident) <td> Yes <td> Yes <td> No <td> No <td> No </tr>
<tr> <td> S4048-ON <td> 48x10G + 6x40G <td> Intel Atom C2338 <td> Broadcom BCM56854 (Trident2) <td> Yes <td> Yes <td> No <td> No <td> No </tr>
<tr> <td> S6000-ON <td> 32x40G <td> Intel Atom S1220 <td> Broadcom BCM56850 (Trident2) <td> Yes <td> Yes <td> No <td> No <td> No </tr>
<tr> <td> Z9100-ON <td> 32x100G <td> Intel Atom C2538 <td> Broadcom BCM56960 (Tomahawk) <td> Yes <td> Yes <td> No <td> No <td> No </tr>
</table>
Device Ports CPU Forwarding In Lab
S4000-ON 48x10G + 6x40G Intel C2338 Broadcom BCM56854 (Trident2) Yes
S4810-ON 48x10G + 4x40G FreeScale P2020 Broadcom BCM56845 (Trident) Yes
S4048-ON 48x10G + 6x40G Intel C2338 Broadcom BCM56854 (Trident2) Yes
S6000-ON 32x40G Intel S1220 Broadcom BCM56850 (Trident2) Yes
S6010-ON 32x40G Intel S1220 Broadcom BCM56850 (Trident2) Yes
S6100-ON 64x50G/128x25G Intel C2538 Broadcom BCM56960 (Tomahawk) Yes
Z9100-ON 32x100G Intel C2538 Broadcom BCM56960 (Tomahawk) Yes
Interface Masters Technologies, Inc.
HPE
---
<table class="table table-striped table-hover">
<thead>
<tr class="info">
<th> Device <th> Ports <th> CPU <th> Forwarding <th> ONL Certified <th> In Lab <th> OF-DPA <th> OpenNSL <th> SAI </tr>
</thead>
<tr> <td> Niagara 2948X12XLm <td> 48x10G + 12x40G <td> Intel/AMD x86 <td> Broadcom BCM56850 (Trident2) <td> Work In Progress** <td> No <td> Yes*** <td> Yes*** <td> No </tr>
<tr> <td> Niagara 2960X6XLm <td> 60x10G + 6x40G <td> Intel/AMD x86 <td> Broadcom BCM56850 (Trident2) <td> Work In Progress** <td> No <td> Yes*** <td> Yes*** <td> No </tr>
<tr> <td> Niagara 2972Xm <td> 72x10G <td> Intel/AMD x86 <td> Broadcom BCM56850 (Trident2) <td> Work In Progress** <td> Yes <td> Yes*** <td> Yes*** <td> No </tr>
<tr> <td> Niagara 2932XL <td> 32x40G <td> Intel/AMD x86 <td> Broadcom BCM56850 (Trident2) <td> Work In Progress** <td> No <td> Yes*** <td> Yes*** <td> No </tr>
<tr> <td> Niagara 2948X6XL <td> 48x10G + 6x40G <td> Intel/AMD x86 <td> Broadcom BCM56850 (Trident2) <td> Work In Progress** <td> No <td> Yes*** <td> Yes <td> No </tr>
</table>
Device Ports CPU Forwarding In Lab
Altoline 6921 48x10G + 6x40G Intel C2538 Broadcom BCM56864 (Trident2+) Yes
Altoline 6921T 48x10G + 6x40G Intel C2538 Broadcom BCM56864 (Trident2+) Yes
Altoline 6941 32x40G Intel C2538 Broadcom BCM56864 (Trident2+) Yes
Altoline 6960 32x100G Intel C2538 Broadcom BCM56960 (Tomahawk) Yes
Ingrasys
---
Device Ports CPU Forwarding In Lab
S9100-32X 32x100G Intel Broadcom BCM56960 (Tomahawk) No
Inventec
---
Device Ports CPU Forwarding In Lab
D7032Q28B 32x100G Intel No
Mellanox
---
<table class="table table-striped table-hover">
<thead>
<tr class="info">
<th> Device <th> Ports <th> CPU <th> Forwarding <th> ONL Certified <th> In Lab <th> SAI </tr>
</thead>
<tr> <td> SN2100 <td> 16x100G <td> Intel Rangeley C2558 <td> Mellanox Spectrum <td> Yes <td> Yes <td> Yes </tr>
<tr> <td> SN2100B <td> 16x40G <td> Intel Rangeley C2558 <td> Mellanox Spectrum <td> Yes <td> No <td> Yes </tr>
<tr> <td> SN2410 <td> 48x25G + 8x100G <td> Intel Ivybridge 1047UE <td> Mellanox Spectrum <td> Yes <td> Yes <td> Yes </tr>
<tr> <td> SN2410B <td> 48x10G + 8x100G <td> Intel Ivybridge 1047UE <td> Mellanox Spectrum <td> Yes <td> No <td> Yes </tr>
<tr> <td> SN2700 <td> 32x100G <td> Intel Ivybridge 1047UE <td> Mellanox Spectrum <td> Yes <td> Yes <td> Yes </tr>
<tr> <td> SN2700B <td> 32x40G <td> Intel Ivybridge 1047UE <td> Mellanox Spectrum <td> Yes <td> No <td> Yes </tr>
</table>
Device Ports CPU Forwarding In Lab
SN2100 16x100G Intel C2558 Mellanox Spectrum Yes
SN2100B 16x40G Intel C2558 Mellanox Spectrum No
SN2410 48x25G + 8x100G Intel 1047UE Mellanox Spectrum Yes
SN2410B 48x10G + 8x100G Intel 1047UE Mellanox Spectrum No
SN2700 32x100G Intel 1047UE Mellanox Spectrum Yes
SN2700B 32x40G Intel 1047UE Mellanox Spectrum No
Notes:
Netberg
---
Device Ports CPU Forwarding In Lab
Aurora 620 32x100G Intel C2558 Broadcom BCM56960 (Tomahawk) Yes
Aurora 720 48x10/25G + 6x40/100G Intel C2558 Broadcom BCM56960 (Tomahawk) Yes
ONL Certified means that the system runs ONIE, is able to install a generic version of ONL and has the ONL Platform drivers necessary to manage the system.
\* Systems no longer in the lab cannot be certified post removal
\** Developing ONL Platform Drivers
\*** Vendor provided
Quanta
------
Device Ports CPU Forwarding In Lab
QuantaMesh T1048-LB9 48x1G + 4x10G FreeScale P2020 Broadcom BCM56534 (Firebolt3) Yes
QuantaMesh T3048-LY2 48x10G + 4x40G FreeScale P2020 Broadcom BCM56846 (Trident+) Yes
QuantaMesh T5032-LY6 32x40G Intel C2758 Broadcom BCM56850 (Trident2) Yes
QuantaMesh T3048-LY7 48x10G + 4x100G Intel C2558 Broadcom BCM56768 (Maverick) Yes
QuantaMesh T3048-LY8 48x10G + 6x40G Intel C2758 Broadcom BCM56854 (Trident2) Yes
QuantaMesh T3048-LY9 48x10GT + 6x40G Intel C2758 Broadcom BCM56850 (Trident2) Yes
QuantaMesh T7032-IX1 32x100G Intel C2758 Broadcom BCM56960 (Tomahawk) Yes
QuantaMesh T7032-IX1B 32x100G Intel C2758 Broadcom BCM56960 (Tomahawk) Yes
QuantaMesh T4048-IX2 48xSFP28 + 8xQSFP28 Intel C2758 Broadcom BCM56960 (Tomahawk) Yes
QuantaMesh T4048-IX8 48x10G + 8x100G Intel Broadcom BCM56870 (Trident 3) Yes

View File

@@ -176,7 +176,7 @@ MODSYNCLIST_DEFAULT := .config Module.symvers Makefile include scripts drivers \
arch/powerpc/include arch/powerpc/Makefile arch/powerpc/lib arch/powerpc/boot/dts \
arch/arm/include arch/arm/Makefile arch/arm/lib arch/arm/boot/dts
MODSYNCLIST := $(MODSYNCLIST_DEFAULT) $(MODSYNCLIST_EXTRA)
MODSYNCLIST := $(MODSYNCLIST_DEFAULT) $(MODSYNCLIST_EXTRA) $(K_MODSYNCLIST)
# This file must be preserved for PPC module builds.
MODSYNCKEEP := arch/powerpc/lib/crtsavres.o

View File

@@ -33,7 +33,7 @@ RFS_MANIFEST := etc/onl/rootfs/manifest.json
endif
RFS:
$(ONL_V_at) rm -rf manifest.json
$(ONL_V_at) sudo rm -rf manifest.json
$(ONL_V_at) $(RFS_COMMAND)
$(ONL_V_at) [ -f $(RFS_DIR)/$(RFS_MANIFEST) ] && cp $(RFS_DIR)/$(RFS_MANIFEST) .
@@ -44,3 +44,6 @@ clean:
show-packages:
$(ONL_V_at) $(RFS_COMMAND) --show-packages
build-packages:
$(ONL_V_at) $(RFS_COMMAND) --only-build-packages

View File

@@ -21,6 +21,9 @@ if [ -f /etc/onl/abort ]; then
exit 1
fi
if [ -f /mnt/onl/boot/autoboot ]; then
. /mnt/onl/boot/autoboot
fi
#
# The maximum number of times we will retry autobooting before
@@ -118,4 +121,3 @@ else
msg_error "BOOTMODE $BOOTMODE is not implemented. Autobooting cannot continue."
exit 1
fi

View File

@@ -19,6 +19,7 @@ import zipfile
import onl.install.InstallUtils
MountContext = onl.install.InstallUtils.MountContext
BlkidParser = onl.install.InstallUtils.BlkidParser
UbinfoParser = onl.install.InstallUtils.UbinfoParser
ProcMountsParser = onl.install.InstallUtils.ProcMountsParser
import onl.mounts
@@ -221,7 +222,7 @@ class Runner(onl.install.InstallUtils.SubprocessMixin):
blkid = BlkidParser(log=self.log)
if ':' in SWI:
if not SWI.startswith('/') and ':' in SWI:
devspec, sep, r = SWI.partition(':')
p = "/dev/%s" % devspec
@@ -247,6 +248,14 @@ class Runner(onl.install.InstallUtils.SubprocessMixin):
part = blkid[label]
except IndexError:
part = None
if part is None:
ubinfo = UbinfoParser(log=self.log)
part = {}
part = ubinfo[label]
device = "/dev/" + part['device'] + "_" + part['Volume ID']
return self.blockdevCopy(device, r, dir=mpt)
if part is not None:
return self.blockdevCopy(part.device, r, dir=mpt)

View File

@@ -11,6 +11,7 @@ import logging
import onl.install.InstallUtils
BlkidParser = onl.install.InstallUtils.BlkidParser
UbinfoParser = onl.install.InstallUtils.UbinfoParser
import onl.mounts
MountContext = onl.install.InstallUtils.MountContext
@@ -26,6 +27,7 @@ class Runner(onl.install.InstallUtils.SubprocessMixin):
self.log = log
self.blkid = BlkidParser(log=self.log)
self.ubinfo = UbinfoParser(log=self.log)
def mount(self, SWI):
@@ -125,6 +127,13 @@ class Runner(onl.install.InstallUtils.SubprocessMixin):
part = self.blkid[label]
except IndexError:
part = None
if part is None:
part = {}
part = self.ubinfo[label]
device = "/dev/" + part['device'] + "_" + part['Volume ID']
return self.blockdevMount(device, path, dir=mpt)
if part is not None:
return self.blockdevMount(part.device, path, dir=mpt)
@@ -141,7 +150,12 @@ class Runner(onl.install.InstallUtils.SubprocessMixin):
if not os.path.exists(dst):
self.log.error("missing SWI: %s", dst)
return None
self.check_call(('mount', '-o', 'rw,remount', dst,))
p = dev.find('ubi')
if p < 0:
self.check_call(('mount', '-o', 'rw,remount', dst,))
else:
self.check_call(('mount', '-t', 'ubifs', '-o', 'rw,remount', dst,))
return dst
with MountContext(device=dev, log=self.log) as ctx:
@@ -154,7 +168,12 @@ class Runner(onl.install.InstallUtils.SubprocessMixin):
# move to its proper location as per mtab
# XXX perms may not be right here
if dir is not None:
self.check_call(('mount', '-o', 'rw,remount', ctx.dir,))
p = dev.find('ubi')
if p < 0:
self.check_call(('mount', '-o', 'rw,remount', ctx.dir,))
else:
self.check_call(('mount', '-t', 'ubifs', '-o', 'rw,remount', ctx.dir,))
self.check_call(('mount', '--move', ctx.dir, dir,))
ctx.mounted = False
dst = dir

View File

@@ -15,8 +15,8 @@ if [ ! -d /mnt/onl/data ]; then
fi
# make sure it's mounted as per mtab.yml
d1=$(stat -f -c '%d' /mnt/onl)
d2=$(stat -f -c '%d' /mnt/onl/data)
d1=$(stat -f -c '%b' /mnt/onl)
d2=$(stat -f -c '%b' /mnt/onl/data)
if [ "$d1" -eq "$d2" ]; then
msg_error "Unmounted /mnt/onl/data, disk boot cannot continue"
exit 200

View File

@@ -0,0 +1,7 @@
#!/usr/bin/python
"""Run native onie-sysinfo
"""
import onl.install.ShellApp
onl.install.ShellApp.OnieSysinfoApp.main()

View File

@@ -0,0 +1,9 @@
#!/bin/bash
/bin/echo -e "#!/bin/sh\\nexit 101" >/usr/sbin/policy-rc.d
chmod +x /usr/sbin/policy-rc.d
export DEBIAN_FRONTEND=noninteractive
export DEBCONF_NONINTERACTIVE_SEEN=true
$@
rc=$?
rm -f /usr/sbin/policy-rc.d
exit $rc

View File

@@ -122,10 +122,8 @@ installer_mkchroot() {
mkdir -p "${rootdir}${TMPDIR}"
fi
# export ONIE defines to the installer
if test -r /etc/machine.conf; then
cp /etc/machine.conf "${rootdir}/etc/machine.conf"
fi
# export ONIE defines to the installer, if they exist
cp /etc/machine*.conf "${rootdir}/etc/."
# export ONL defines to the installer
mkdir -p "${rootdir}/etc/onl"

View File

@@ -129,6 +129,13 @@ default:
- ext2load mmc 0:1 $onl_loadaddr $onl_itb
- "bootm $onl_loadaddr#$onl_platform"
#ubifs to boot onl
flash_bootcmds: &flash_bootcmds
- ubi part open
- ubifsmount ONL-BOOT
- ubifsload $loadaddr $onl_itb
- "bootm $onl_loadaddr#$onl_platform"
nos_bootcmds: *ide_bootcmds
# Configure the fw_env.config file,

View File

@@ -31,6 +31,11 @@ default:
=: kernel-4.9-lts-x86_64-all
package: onl-kernel-4.9-lts-x86-64-all:amd64
kernel-4.14: &kernel-4-14
=: kernel-4.14-lts-x86_64-all
package: onl-kernel-4.14-lts-x86-64-all:amd64
# pick one of the above kernels
kernel:
<<: *kernel-3-16

View File

@@ -111,6 +111,8 @@ class OnlBootConfigNet(OnlBootConfig):
self.delete('NETIP')
self.delete('NETMASK')
self.delete('NETGW')
self.delete('NETDNS')
self.delete('NETDOMAIN')
self.set('NETAUTO', 'dhcp')
def netauto_get(self):
@@ -137,13 +139,27 @@ class OnlBootConfigNet(OnlBootConfig):
def netgw_get(self):
return self.keys.get('NETGW', None)
def netdns_set(self, dns):
self.delete('NETAUTO')
self.keys['NETDNS'] = dns
def netdns_get(self):
return self.keys.get('NETDNS', None)
def netdomain_set(self, domain):
self.delete('NETAUTO')
self.keys['NETDOMAIN'] = domain
def netdomain_get(self):
return self.keys.get('NETDOMAIN', None)
def __validate(self):
if 'NETAUTO' not in self.keys:
netip = self.keys.get('NETIP', None)
if netip:
if not self.is_ip_address(netip):
raise ValueError("NETIP=%s is not a valid ip-address" % (netup))
raise ValueError("NETIP=%s is not a valid ip-address" % (netip))
elif self.NET_REQUIRED:
raise ValueError("No IP configuration set for the management interface.")
@@ -168,6 +184,11 @@ class OnlBootConfigNet(OnlBootConfig):
elif netip or netmask or netgw:
raise ValueError("Incomplete static network configuration. NETIP, NETMASK, and NETGW must all be set.")
netdns = self.keys.get('NETDNS', None)
if netdns:
if not self.is_ip_address(netdns):
raise ValueError("NETDNS=%s is not a valid ip-address" % (netdns))
elif self.keys['NETAUTO'] not in ['dhcp', 'up']:
raise ValueError("The NETAUTO value '%s' is invalid." % self.keys['NETAUTO'])
elif self.keys['NETAUTO'] == 'up' and self.NET_REQUIRED:
@@ -214,7 +235,8 @@ class OnlBootConfigNet(OnlBootConfig):
ap.add_argument("--ip", help='Set static IP address for the management interface.', type=OnlBootConfigNet.argparse_type_is_ip_address)
ap.add_argument("--netmask", help='Set the static netmask for the management interface.', type=OnlBootConfigNet.argparse_type_is_netmask)
ap.add_argument("--gateway", help='Set the gateway address.', type=OnlBootConfigNet.argparse_type_is_ip_address)
ap.add_argument("--dns", help='Set the dns server.', type=OnlBootConfigNet.argparse_type_is_ip_address)
ap.add_argument("--domain", help='Set the dns domain.')
def __argparse_process(self, ops):
if ops.dhcp:
@@ -229,6 +251,12 @@ class OnlBootConfigNet(OnlBootConfig):
if ops.gateway:
self.netgw_set(ops.gateway)
if ops.dns:
self.netdns_set(ops.dns)
if ops.domain:
self.netdomain_set(ops.domain)
if __name__ == '__main__':
bc = OnlBootConfigNet()

View File

@@ -17,7 +17,7 @@ import time
from InstallUtils import InitrdContext
from InstallUtils import SubprocessMixin
from InstallUtils import ProcMountsParser
from ShellApp import OnieBootContext
from ShellApp import OnieBootContext, OnieSysinfo
import ConfUtils, BaseInstall
class App(SubprocessMixin, object):
@@ -129,7 +129,7 @@ class App(SubprocessMixin, object):
def runLocalOrChroot(self):
if self.machineConf is None:
self.log.error("missing machine.conf")
self.log.error("missing onie-sysinfo or machine.conf")
return 1
if self.installerConf is None:
self.log.error("missing installer.conf")
@@ -230,10 +230,17 @@ class App(SubprocessMixin, object):
def runLocal(self):
self.log.info("getting installer configuration")
if os.path.exists(ConfUtils.MachineConf.PATH):
osi = OnieSysinfo(log=self.log.getChild("onie-sysinfo"))
try:
halp = osi.help
except AttributeError:
halp = None
if halp is not None:
self.machineConf = osi
elif os.path.exists(ConfUtils.MachineConf.PATH):
self.machineConf = ConfUtils.MachineConf()
else:
self.log.warn("missing /etc/machine.conf from ONIE runtime")
self.log.warn("missing onie-sysinfo or /etc/machine.conf from ONIE runtime")
self.machineConf = ConfUtils.MachineConf(path='/dev/null')
self.installerConf = ConfUtils.InstallerConf()
@@ -243,21 +250,38 @@ class App(SubprocessMixin, object):
def findPlatform(self):
plat = arch = None
if os.path.exists(ConfUtils.MachineConf.PATH):
def _p2a(plat):
if plat.startswith('x86-64'):
return 'x86_64'
else:
return plat.partition('-')[0]
# recover platform specifier from installer configuration
if plat is None:
plat = getattr(self.installerConf, 'onie_platform', None)
if plat:
self.log.info("ONL installer running chrooted.")
plat = plat.replace('_', '-').replace('.', '-')
arch = getattr(self.installerConf, 'onie_arch', None)
# recover platform specifier from legacy ONIE machine.conf
if plat is None and self.machineConf is not None:
plat = getattr(self.machineConf, 'onie_platform', None)
arch = getattr(self.machineConf, 'onie_arch', None)
if plat and arch:
if plat:
self.log.info("ONL installer running under ONIE.")
plat = plat.replace('_', '-').replace('.', '-')
elif os.path.exists("/etc/onl/platform"):
# recover platform specifier from ONL runtime
if plat is None and os.path.exists("/etc/onl/platform"):
with open("/etc/onl/platform") as fd:
plat = fd.read().strip()
if plat.startswith('x86-64'):
arch = 'x86_64'
else:
arch = plat.partition('-')[0]
self.log.info("ONL installer running under ONL or ONL loader.")
if plat is not None and arch is None:
arch = _p2a(plat)
if plat and arch:
self.installerConf.installer_platform = plat
self.installerConf.installer_arch = arch

View File

@@ -17,7 +17,7 @@ import imp
import fnmatch, glob
from InstallUtils import SubprocessMixin
from InstallUtils import MountContext, BlkidParser, PartedParser
from InstallUtils import MountContext, BlkidParser, PartedParser, UbinfoParser
from InstallUtils import ProcMountsParser
from InstallUtils import GdiskParser
from InstallUtils import OnieSubprocess
@@ -83,6 +83,7 @@ class Base:
# keep track of next partition/next block
self.blkidParts = []
self.ubiParts = []
# current scan of partitions and labels
self.partedDevice = None
@@ -853,7 +854,203 @@ class GrubInstaller(SubprocessMixin, Base):
def shutdown(self):
Base.shutdown(self)
class UbootInstaller(SubprocessMixin, Base):
class UBIfsCreater(SubprocessMixin, Base):
def __init__(self, *args, **kwargs):
Base.__init__(self, *args, **kwargs)
self.log = logging.getLogger("ubinfo -a")
self.device = self.im.getDevice()
self.ubiParts = None
"""Set up an UBI file system."""
def ubifsinit(self):
UNITS = {
'GiB' : 1024 * 1024 * 1024,
'G' : 1000 * 1000 * 1000,
'MiB' : 1024 * 1024,
'M' : 1000 * 1000,
'KiB' : 1024,
'K' : 1000,
}
try:
code = 0
if not code:
mtd_num = self.device[-1]
cmd = ('ubiformat', '/dev/mtd' + mtd_num)
self.check_call(cmd, vmode=self.V2)
cmd = ('ubiattach', '-m', mtd_num, '-d', '0', '/dev/ubi_ctrl',)
self.check_call(cmd, vmode=self.V2)
for part in self.im.platformConf['installer']:
label, partData = list(part.items())[0]
if type(partData) == dict:
sz, fmt = partData['='], partData.get('format', 'ubifs')
else:
sz, fmt = partData, 'ubifs'
cnt = None
for ul, ub in UNITS.items():
if sz.endswith(ul):
cnt = int(sz[:-len(ul)], 10) * ub
break
if cnt is None:
self.log.error("invalid size (no units) for %s: %s",part, sz)
return 1
label = label.strip()
cmd = ('ubimkvol', '/dev/ubi0', '-N', label, '-s', bytes(cnt),)
self.check_call(cmd, vmode=self.V2)
except Exception:
self.log.exception("cannot create UBI file systemfrom %s",self.device)
return 0
def ubi_mount(self, dir, devpart):
if devpart is None:
self.log.error("Mount failed.no given mount device part")
return 1
if dir is None:
self.log.error("Mount failed.no given mount directory")
return 1
if self.ubiParts is None:
try:
self.ubiParts = UbinfoParser(log=self.log.getChild("ubinfo -a"))
except Exception:
self.log.exception("Mount failed.No UBIfs")
return 1
try:
dev = self.ubiParts[devpart]
except IndexError as ex:
self.log.error("Mount failed.cannot find %s partition", str(devpart))
return 1
self.makedirs(dir)
device = "/dev/" + dev['device'] + "_" + dev['Volume ID']
if dev['fsType']:
cmd = ('mount', '-t', dev['fsType'], device, dir,)
else:
cmd = ('mount', device, dir,)
code = self.check_call(cmd, vmode=self.V2)
if code:
self.log.error("Mount failed.mount command exect failed")
return 1
return 0
def ubi_unmount(self,dir=None):
if dir is None:
self.log.error("Unmount failed.no given unmount directory")
return 1
cmd = ('umount', dir)
code = self.check_call(cmd, vmode=self.V2)
if code:
self.log.error("Unmount failed.umount command exect failed")
return 1
return 0
def ubi_getinfo(self):
try:
self.ubiParts = UbinfoParser(log=self.log.getChild("ubinfo -a"))
except Exception:
self.log.exception("UBI info get failed.No UBIfs")
return 1
return 0
def ubi_installSwi(self):
files = os.listdir(self.im.installerConf.installer_dir) + self.zf.namelist()
swis = [x for x in files if x.endswith('.swi')]
if not swis:
self.log.warn("No ONL Software Image available for ubi installation.")
self.log.warn("Post-install ZTN installation will be required.")
if len(swis) > 1:
self.log.error("Multiple SWIs found in ubi installer: %s", " ".join(swis))
return 1
base = swis[0]
self.log.info("Installing ONL Software Image (%s)...", base)
dev = "ONL-IMAGES"
dstDir = "/tmp/ubifs"
code = self.ubi_mount(dstDir,dev)
if code :
return 1
dst = os.path.join(dstDir, base)
self.installerCopy(base, dst)
self.log.info("syncing block devices(%s)...",dev)
self.check_call(('sync',))
self.ubi_unmount(dstDir)
return 0
def ubi_installLoader(self):
loaderBasename = None
for c in sysconfig.installer.fit:
if self.installerExists(c):
loaderBasename = c
break
if not loaderBasename:
self.log.error("The platform loader file is missing.")
return 1
self.log.info("Installing the ONL loader from %s...", loaderBasename)
dev = "ONL-BOOT"
dstDir = "/tmp/ubiloader"
code = self.ubi_mount(dstDir,dev)
if code :
return 1
dst = os.path.join(dstDir, "%s.itb" % self.im.installerConf.installer_platform)
self.installerCopy(loaderBasename, dst)
self.log.info("syncing block devices(%s)...",dev)
self.check_call(('sync',))
self.ubi_unmount(dstDir)
return 0
def ubi_installBootConfig(self):
basename = 'boot-config'
self.log.info("Installing boot-config to ONL-BOOT partion")
dev = "ONL-BOOT"
dstDir = "/tmp/ubibootcon"
code = self.ubi_mount(dstDir,dev)
if code :
return 1
dst = os.path.join(dstDir, basename)
self.installerCopy(basename, dst, True)
with open(dst) as fd:
buf = fd.read()
ecf = buf.encode('base64', 'strict').strip()
if self.im.grub and self.im.grubEnv is not None:
setattr(self.im.grubEnv, 'boot_config_default', ecf)
if self.im.uboot and self.im.ubootEnv is not None:
setattr(self.im.ubootEnv, 'boot-config-default', ecf)
self.log.info("syncing block devices(%s)...",dev)
self.check_call(('sync',))
self.ubi_unmount(dstDir)
return 0
def ubi_installOnlConfig(self):
self.log.info("Installing onl-config to ONL-CONFIG partion")
dev = "ONL-CONFIG"
dstDir = "/tmp/ubionlconfig"
code = self.ubi_mount(dstDir,dev)
if code :
return 1
for f in self.zf.namelist():
d = 'config/'
if f.startswith(d) and f != d:
dst = os.path.join(dstDir, os.path.basename(f))
if not os.path.exists(dst):
self.installerCopy(f, dst)
self.log.info("syncing block devices(%s)...",dev)
self.check_call(('sync',))
self.ubi_unmount(dstDir)
return 0
class UbootInstaller(SubprocessMixin, UBIfsCreater):
class installmeta(Base.installmeta):
@@ -874,13 +1071,16 @@ class UbootInstaller(SubprocessMixin, Base):
cmds.append("setenv onl_itb %s" % itb)
for item in self.platformConf['loader']['setenv']:
k, v = list(item.items())[0]
cmds.append("setenv %s %s" % (k, v,))
device = self.getDevice()
if "mtdblock" in device:
cmds.append("setenv %s %s ${platformargs} ubi.mtd=%s root=/dev/ram ethaddr=$ethaddr" % (k, v, device[-1],))
else:
cmds.append("setenv %s %s" % (k, v,))
cmds.extend(self.platformConf['loader']['nos_bootcmds'])
return "; ".join(cmds)
def __init__(self, *args, **kwargs):
Base.__init__(self, *args, **kwargs)
UBIfsCreater.__init__(self, *args, **kwargs)
self.device = self.im.getDevice()
self.rawLoaderDevice = None
@@ -1014,6 +1214,24 @@ class UbootInstaller(SubprocessMixin, Base):
code = self.assertUnmounted()
if code: return code
if "mtdblock" in self.device:
code = self.ubifsinit()
if code: return code
code = self.ubi_getinfo()
if code: return code
code = self.ubi_installSwi()
if code: return code
code = self.ubi_installLoader()
if code: return code
code = self.ubi_installBootConfig()
if code: return code
code = self.ubi_installOnlConfig()
if code: return code
code = self.runPlugins(Plugin.PLUGIN_POSTINSTALL)
if code: return code
code = self.installUbootEnv()
return code
code = self.maybeCreateLabel()
if code: return code
@@ -1035,6 +1253,7 @@ class UbootInstaller(SubprocessMixin, Base):
self.log.info("found a disk with %d blocks",
self.partedDevice.getLength())
self.blkidParts = BlkidParser(log=self.log.getChild("blkid"))
code = self.findMsdos()
if code: return code

View File

@@ -63,18 +63,30 @@ class ConfFileBase(ConfBase):
PATH = None
# Override me
def __init__(self, path=None):
SHELL = False
# override me
def __init__(self, path=None, shell=False):
self.__dict__['path'] = path or self.PATH
self.__dict__['shell'] = shell or self.SHELL
ConfBase.__init__(self)
def _parse(self):
self.__dict__['_data'] = {}
with open(self.path) as fd:
for line in fd.xreadlines():
if self.SHELL:
cmd = "IFS=; set -e; . '%s'; set +e; set | egrep ^[a-zA-Z][a-zA-Z0-9_]*=" % self.path
buf = subprocess.check_output(cmd, shell=True)
for line in buf.splitlines(False):
self._feedLine(line)
else:
with open(self.path) as fd:
for line in fd.xreadlines():
self._feedLine(line)
class MachineConf(ConfFileBase):
"""XXX roth -- deprecated, machine.conf is executable shell now."""
PATH = "/etc/machine.conf"
SHELL = True
class InstallerConf(ConfFileBase):
PATH = "/etc/onl/installer.conf"

View File

@@ -388,6 +388,63 @@ class BlkidParser(SubprocessMixin):
def __len__(self):
return len(self.parts)
class UbinfoParser(SubprocessMixin):
def __init__(self, log=None):
self.log = log or logging.getLogger("ubinfo -a")
self.parse()
def parse(self):
self.parts = []
lines = ''
try:
cmd = ('ubinfo', '-a',)
lines = self.check_output(cmd).splitlines()
except Exception as ex:
return self
dev = None
volId = None
name = None
attrs = {}
for line in lines:
line = line.strip()
p = line.find(':')
if p < 0: continue
name, value = line[:p], line[p+1:].strip()
if 'Volume ID' in name:
p = value.find('(')
if p < 0: continue
volumeId = value[:p].strip()
attrs['Volume ID'] = volumeId
p = value.find('on')
if p < 0: continue
dev = value[p+2:-1].strip()
attrs['device'] = dev
if 'Name' in name:
dev = "/dev/" + dev + "_" + volumeId
p = line.find(':')
if p < 0: continue
attrs['Name'] = line[p+1:].strip()
attrs['fsType'] = 'ubifs'
self.parts.append(attrs)
dev = None
volId = None
name = None
attrs = {}
def __getitem__(self, idxOrName):
if type(idxOrName) == int:
return self.parts[idxOrName]
for part in self.parts:
if part['Name'] == idxOrName: return part
raise IndexError("cannot find partition %s" % repr(idxOrName))
def __len__(self):
return len(self.parts)
class ProcMtdEntry:
def __init__(self,

View File

@@ -15,9 +15,6 @@ from InstallUtils import ProcMountsParser, ProcMtdParser
from InstallUtils import BlkidParser
from InstallUtils import UbootInitrdContext
import onl.platform.current
from onl.sysconfig import sysconfig
class AppBase(SubprocessMixin, object):
@property
@@ -228,6 +225,105 @@ class Onie(AppBase):
with OnieBootContext(log=self.log) as ctx:
return self._runInitrdShell(ctx.initrd)
class OnieSysinfoApp(SubprocessMixin, object):
PROG = "onie-sysinfo"
def __init__(self, args=[], log=None):
if log is not None:
self.log = log
else:
self.log = logging.getLogger(self.__class__.__name__)
self.args = args or ['-p',]
self.output = None
def _runInitrdShell(self, initrd):
with InitrdContext(initrd=initrd, log=self.log) as ctx:
cmd = ['onie-sysinfo',]
cmd.extend(self.args)
cmd = ('chroot', ctx.dir,
'/bin/sh', '-c', 'IFS=;' + " ".join(cmd))
try:
self.output = self.check_output(cmd)
ret = 0
except subprocess.CalledProcessError, what:
self.log.error("failed command: %s", " ".join(what.cmd))
for line in (what.output or "").splitlines():
self.log.error(">>> %s", line)
ret = what.returncode
return ret
def run(self):
with OnieBootContext(log=self.log) as ctx:
ret = self._runInitrdShell(ctx.initrd)
if self.output is not None:
sys.stdout.write(self.output)
return ret
def shutdown(self):
pass
@classmethod
def main(cls):
logging.basicConfig()
logger = logging.getLogger(cls.PROG)
logger.setLevel(logging.INFO)
args = list(sys.argv[1:])
sysinfoArgs = []
while args:
if args[0] in ('-v', '--verbose',):
logger.setLevel(logging.DEBUG)
args.pop(0)
continue
if args[0] in ('-q', '--quiet',):
logger.setLevel(logging.ERROR)
args.pop(0)
continue
sysinfoArgs.append(args.pop(0))
app = cls(args=sysinfoArgs, log=logger)
try:
code = app.run()
except:
logger.exception("runner failed")
code = 1
app.shutdown()
sys.exit(code)
class OnieSysinfo(OnieSysinfoApp):
def _runArgs(self, *args):
self.args = args
with OnieBootContext(log=self.log) as ctx:
ret = self._runInitrdShell(ctx.initrd)
if self.output is not None:
return self.output.rstrip()
raise AttributeError("cannot retrieve onie-sysinfo attribute via %s" % str(args))
@property
def help(self):
return self._runArgs('-h')
@property
def onie_platform(self):
return self._runArgs('-p')
@property
def onie_arch(self):
return self._runArgs('-c')
@property
def onie_version(self):
return self._runArgs('-v')
# XXX roth other switches too
class Loader(AppBase):
"""Application shell that uses the (installed) loader runtime."""
@@ -331,6 +427,7 @@ class Loader(AppBase):
def run(self):
import onl.platform.current
self.platform = onl.platform.current.OnlPlatform()
self.pc = self.platform.platform_config
@@ -353,6 +450,7 @@ class Upgrader(AppBase):
def runGrub(self):
from onl.sysconfig import sysconfig
d = sysconfig.upgrade.loader.package.dir
for b in sysconfig.upgrade.loader.package.grub:
p = os.path.join(d, b)
@@ -365,6 +463,7 @@ class Upgrader(AppBase):
def runUboot(self):
from onl.sysconfig import sysconfig
d = sysconfig.upgrade.loader.package.dir
for b in sysconfig.upgrade.loader.package.fit:
p = os.path.join(d, b)
@@ -377,6 +476,7 @@ class Upgrader(AppBase):
def run(self):
import onl.platform.current
self.platform = onl.platform.current.OnlPlatform()
self.pc = self.platform.platform_config

View File

@@ -12,6 +12,7 @@ import shutil
import argparse
import fnmatch
import subprocess
import glob
from onl.install.InstallUtils import InitrdContext
from onl.install.InstallUtils import ProcMountsParser
@@ -58,10 +59,11 @@ class App(SubprocessMixin):
self.log.info("onie directory is %s", octx.onieDir)
self.log.info("initrd directory is %s", octx.initrdDir)
src = os.path.join(octx.initrdDir, "etc/machine.conf")
dst = os.path.join(ctx.dir, "etc/machine.conf")
self.log.debug("+ /bin/cp %s %s", src, dst)
shutil.copy2(src, dst)
srcPat = os.path.join(octx.initrdDir, "etc/machine*.conf")
for src in glob.glob(srcPat):
dst = os.path.join(ctx.dir, "etc", os.path.split(src)[1])
self.log.debug("+ /bin/cp %s %s", src, dst)
shutil.copy2(src, dst)
src = "/etc/fw_env.config"
if os.path.exists(src):
@@ -98,6 +100,13 @@ class App(SubprocessMixin):
pass
installerConf.installer_zip = os.path.split(zipPath)[1]
import onl.platform.current
plat = onl.platform.current.OnlPlatformName
if plat.startswith('x86-64'):
plat = 'x86_64' + plat[6:]
installerConf.onie_platform = plat
installerConf.onie_arch = plat.partition('-')[0]
# finalize the local installer.conf
dst = os.path.join(ctx.dir, "etc/onl/installer.conf")
with open(dst, "w") as fd:
@@ -195,7 +204,7 @@ class App(SubprocessMixin):
pdir,))
for m in pm.mounts:
if m.dir.startswith('/mnt/onl'):
if m.dir.startswith('/mnt/onl') or m.dir.startswith('/boot'):
if not self.force:
self.log.error("directory %s is still mounted (try --force)", m.dir)
return 1

View File

@@ -63,7 +63,12 @@ class MountManager(object):
self.logger.debug("%s not mounted @ %s. It will be mounted %s" % (device, directory, mode))
try:
cmd = "mount -o %s %s %s" % (','.join(mountargs), device, directory)
p = device.find('ubi')
if p < 0:
cmd = "mount -o %s %s %s" % (','.join(mountargs), device, directory)
else:
cmd = "mount -o %s -t %s %s %s" % (','.join(mountargs), 'ubifs', device, directory)
self.logger.debug("+ %s" % cmd)
subprocess.check_call(cmd, shell=True)
except subprocess.CalledProcessError, e:
@@ -148,11 +153,42 @@ class OnlMountManager(object):
def _discover(k):
v = md[k]
lbl = v.get('label', k)
useUbiDev = False
try:
v['device'] = subprocess.check_output(('blkid', '-L', lbl,)).strip()
except subprocess.CalledProcessError:
return False
useUbiDev = True
if useUbiDev == True:
if k == 'EFI-BOOT':
return False
try:
output = subprocess.check_output("ubinfo -d 0 -N %s" % k, shell=True).splitlines()
except subprocess.CalledProcessError:
return False
volumeId = None
device = None
for line in output:
line = line.strip()
p = line.find(':')
if p < 0:
self.logger.debug("Invalid ubinfo output %s" % line)
name, value = line[:p], line[p+1:].strip()
if 'Volume ID' in name:
p = value.find('(')
if p < 0:
self.logger.debug("Invalid Volume ID %s" % value)
volumeId = value[:p].strip()
p = value.find('on')
if p < 0:
self.logger.debug("Invalid ubi devicde %s" % value)
device = value[p+2:-1].strip()
if 'Name' in name:
v['device'] = "/dev/" + device + "_" + volumeId
if not os.path.isdir(v['dir']):
self.logger.debug("Make directory '%s'...", v['dir'])

View File

@@ -17,6 +17,7 @@ import yaml
import onl.YamlUtils
import subprocess
import platform
import ast
class OnlInfoObject(object):
DEFAULT_INDENT=" "
@@ -164,6 +165,7 @@ class OnlPlatformBase(object):
except ValueError, e:
if required:
raise e
self.add_info_dict(name, {}, klass)
elif required:
raise RuntimeError("A required system file (%s) is missing." % f)
@@ -255,9 +257,11 @@ class OnlPlatformBase(object):
mc = self.basedir_onl("etc/onie/machine.json")
if not os.path.exists(mc):
data = {}
mcconf = subprocess.check_output("""onie-shell -c "cat /etc/machine.conf" """, shell=True)
mcconf = subprocess.check_output("""onie-shell -c "IFS=; . /etc/machine.conf; set | egrep ^onie_.*=" """, shell=True)
for entry in mcconf.split():
(k,e,v) = entry.partition('=')
if v and (v.startswith("'") or v.startswith('"')):
v = ast.literal_eval(v)
if e:
data[k] = v
@@ -473,6 +477,10 @@ class OnlPlatformPortConfig_48x1_4x10(object):
PORT_COUNT=52
PORT_CONFIG="48x1 + 4x10"
class OnlPlatformPortConfig_48x1_2x10(object):
PORT_COUNT=50
PORT_CONFIG="48x1 + 2x10"
class OnlPlatformPortConfig_48x10_4x40(object):
PORT_COUNT=52
PORT_CONFIG="48x10 + 4x40"
@@ -481,6 +489,10 @@ class OnlPlatformPortConfig_48x10_6x40(object):
PORT_COUNT=54
PORT_CONFIG="48x10 + 6x40"
class OnlPlatformPortConfig_48x10_4x100(object):
PORT_COUNT=52
PORT_CONFIG="48x10 + 4x100"
class OnlPlatformPortConfig_48x25_6x100(object):
PORT_COUNT=54
PORT_CONFIG="48x25 + 6x100"
@@ -501,6 +513,10 @@ class OnlPlatformPortConfig_32x100(object):
PORT_COUNT=32
PORT_CONFIG="32x100"
class OnlPlatformPortConfig_64x100(object):
PORT_COUNT=64
PORT_CONFIG="64x100"
class OnlPlatformPortConfig_24x1_4x10(object):
PORT_COUNT=28
PORT_CONFIG="24x1 + 4x10"

View File

@@ -61,6 +61,13 @@ def baseconfig():
ONLPDUMP = "%s/bin/onlpdump" % (platform.basedir_onl())
try:
import dmidecode
with open("%s/dmi-system-version" % platform.basedir_onl(), "w") as f:
f.write(dmidecode.QuerySection('system')['0x0001']['data']['Version'])
except:
pass
if not platform.baseconfig():
msg("*** platform class baseconfig failed.\n", fatal=True)

View File

@@ -14,21 +14,57 @@
# platform-config packages.
#
############################################################
import os
import os, sys
import importlib
import subprocess
import ast
def platform_name_get():
# Determine the current platform name.
platform = None
if os.path.exists("/etc/onl/platform"):
# running ONL proper
if platform is None and os.path.exists("/etc/onl/platform"):
with open("/etc/onl/platform", 'r') as f:
platform=f.read().strip()
elif os.path.exists("/etc/machine.conf"):
with open("/etc/machine.conf", 'r') as f:
# in the middle of an ONL install
if platform is None and os.path.exists("/etc/onl/installer.conf"):
with open("/etc/onl/installer.conf") as f:
lines = f.readlines(False)
lines = [x for x in lines if x.startswith('onie_platform=')]
lines = [x for x in lines if x.startswith('onie_platform')]
if lines:
platform = lines[0].partition('=')[2].strip()
# running ONIE
if platform is None and os.path.exists("/bin/onie-sysinfo"):
try:
platform = subprocess.check_output(('/bin/onie-sysinfo', '-p',)).strip()
except subprocess.CalledProcessError as what:
for line in (what.output or "").splitlines():
sys.stderr.write(">>> %s\n" % line)
sys.stderr.write("onie-sysinfo failed with code %d\n" % what.returncode)
platform = None
# running ONL loader, with access to ONIE
if platform is None and os.path.exists("/usr/bin/onie-shell"):
try:
platform = subprocess.check_output(('/usr/bin/onie-shell', '-c', "onie-sysinfo -p",)).strip()
except subprocess.CalledProcessError as what:
for line in (what.output or "").splitlines():
sys.stderr.write(">>> %s\n" % line)
sys.stderr.write("onie-sysinfo (onie-shell) failed with code %d\n" % what.returncode)
platform = None
# legacy ONIE environment (including parsable shell in machine.conf)
if platform is None and os.path.exists("/etc/machine.conf"):
cmd = "IFS=; . /tmp/machine.conf; set | egrep ^onie_platform="
buf = subprocess.check_output(cmd)
if buf:
platform = buf.partition('=')[2].strip()
if platform.startswith('"') or platform.startswith("'"):
platform = ast.literal_eval(platform)
if platform is None:
raise RuntimeError("cannot find a platform declaration")

View File

@@ -12,7 +12,7 @@ from onl.upgrade import ubase
from onl.sysconfig import sysconfig
from onl.mounts import OnlMountManager, OnlMountContextReadOnly, OnlMountContextReadWrite
from onl.install import BaseInstall, ConfUtils, InstallUtils
from onl.install.ShellApp import OnieBootContext
from onl.install.ShellApp import OnieBootContext, OnieSysinfo
import onl.platform.current
import onl.versions
@@ -83,8 +83,12 @@ class LoaderUpgrade_Fit(LoaderUpgradeBase):
onlPlatform = onl.platform.current.OnlPlatform()
with OnieBootContext(log=self.logger) as octx:
path = os.path.join(octx.initrdDir, "etc/machine.conf")
machineConf = ConfUtils.MachineConf(path=path)
if os.path.exists("/usr/bin/onie-shell"):
machineConf = OnieSysinfo(log=self.logger.getChild("onie-sysinfo"))
else:
path = os.path.join(octx.initrdDir, "etc/machine.conf")
if os.path.exists(path):
machineConf = ConfUtils.MachineConf(path=path)
installerConf = ConfUtils.InstallerConf(path="/dev/null")
# start with an empty installerConf, fill it in piece by piece

View File

@@ -15,7 +15,7 @@ include $(ONL)/make/config.mk
kernel:
rm -rf lib
$(MAKE) -C $(ONL)/packages/base/any/kernels/3.16-lts/configs/x86_64-all K_TARGET_DIR=$(THIS_DIR) $(ONL_MAKE_PARALLEL)
ARCH=x86_64 $(ONL)/tools/scripts/kmodbuild.sh linux-3.16.39-mbuild "$(wildcard $(ONL)/packages/base/any/kernels/modules/*)" onl/onl/common
ARCH=x86_64 $(ONL)/tools/scripts/kmodbuild.sh linux-3.16.*-mbuild "$(wildcard $(ONL)/packages/base/any/kernels/modules/*)" onl/onl/common
clean:
rm -rf linux-3.16* kernel-3.16*

View File

@@ -0,0 +1 @@
include $(ONL)/make/pkg.mk

View File

@@ -0,0 +1,30 @@
variables:
basename: onl-kernel-4.14-lts-x86-64-all
common:
arch: amd64
version: 1.0.0
copyright: Copyright 2013, 2014, 2015 Big Switch Networks
maintainer: support@bigswitch.com
support: opennetworklinux@googlegroups.com
packages:
- name: $basename
version: 1.0.0
summary: Open Network Linux 4.14 LTS Kernel for X86_64 Platforms.
symlinks: True
files:
builds/kernel-4.14* : $$PKG_INSTALL/
builds/linux-*mbuild : $$PKG_INSTALL/mbuilds
changelog: Change changes changes.,
- name: $basename-modules
version: 1.0.0
summary: Open Network Linux 4.14 LTS Kernel Modules for X86_64 Platforms
files:
builds/lib: /lib
changelog: Change changes changes.,

View File

@@ -0,0 +1,3 @@
linux-*
kernel-*
lib

View File

@@ -0,0 +1,22 @@
# -*- Makefile -*-
############################################################
# <bsn.cl fy=2013 v=none>
#
# Copyright 2013, 2014 BigSwitch Networks, Inc.
#
#
#
# </bsn.cl>
############################################################
THIS_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST))))
include $(ONL)/make/config.mk
kernel:
rm -rf lib
dpkg -l libelf-dev > /dev/null 2>&1 || sudo apt-get install libelf-dev
$(MAKE) -C $(ONL)/packages/base/any/kernels/4.14-lts/configs/x86_64-all K_TARGET_DIR=$(THIS_DIR) $(ONL_MAKE_PARALLEL)
ARCH=x86_64 $(ONL)/tools/scripts/kmodbuild.sh linux-4.14.*-mbuild "$(wildcard $(ONL)/packages/base/any/kernels/modules/*)" onl/onl/common
clean:
rm -rf linux-4.14* kernel-4.14* lib

View File

@@ -15,7 +15,7 @@ include $(ONL)/make/config.mk
kernel:
rm -rf lib
$(MAKE) -C $(ONL)/packages/base/any/kernels/4.9-lts/configs/x86_64-all K_TARGET_DIR=$(THIS_DIR) $(ONL_MAKE_PARALLEL)
ARCH=x86_64 $(ONL)/tools/scripts/kmodbuild.sh linux-4.9.30-mbuild "$(wildcard $(ONL)/packages/base/any/kernels/modules/*)" onl/onl/common
ARCH=x86_64 $(ONL)/tools/scripts/kmodbuild.sh linux-4.9.*-mbuild "$(wildcard $(ONL)/packages/base/any/kernels/modules/*)" onl/onl/common
clean:
rm -rf linux-4.9* kernel-4.9*

View File

@@ -2,7 +2,8 @@ include $(ONL)/make/config.amd64.mk
# All amd64 kernels
KERNELS := $(shell $(ONLPM) --find-file onl-kernel-3.16-lts-x86-64-all:amd64 kernel-3.16-lts-x86_64-all) \
$(shell $(ONLPM) --find-file onl-kernel-4.9-lts-x86-64-all:amd64 kernel-4.9-lts-x86_64-all)
$(shell $(ONLPM) --find-file onl-kernel-4.9-lts-x86-64-all:amd64 kernel-4.9-lts-x86_64-all) \
$(shell $(ONLPM) --find-file onl-kernel-4.14-lts-x86-64-all:amd64 kernel-4.14-lts-x86_64-all)
# Loader initrd

View File

@@ -16,7 +16,4 @@ packages:
init: ${ONL}/packages/base/any/faultd/faultd.init
changelog: Change changes changes.,
asr: True

View File

@@ -110,7 +110,7 @@ faultd_config_lookup(const char* setting)
{
int i;
for(i = 0; faultd_config_settings[i].name; i++) {
if(strcmp(faultd_config_settings[i].name, setting)) {
if(!strcmp(faultd_config_settings[i].name, setting)) {
return faultd_config_settings[i].value;
}
}

View File

@@ -1,6 +1,6 @@
#
# Automatically generated file; DO NOT EDIT.
# Linux/powerpc 3.16.39 Kernel Configuration
# Linux/powerpc 3.16.53 Kernel Configuration
#
# CONFIG_PPC64 is not set
@@ -732,7 +732,6 @@ CONFIG_VLAN_8021Q=y
# CONFIG_BATMAN_ADV is not set
# CONFIG_OPENVSWITCH is not set
# CONFIG_VSOCKETS is not set
# CONFIG_NETLINK_MMAP is not set
# CONFIG_NETLINK_DIAG is not set
# CONFIG_NET_MPLS_GSO is not set
# CONFIG_HSR is not set

View File

@@ -1,6 +1,6 @@
#
# Automatically generated file; DO NOT EDIT.
# Linux/x86_64 3.16.39 Kernel Configuration
# Linux/x86_64 3.16.53 Kernel Configuration
#
CONFIG_64BIT=y
CONFIG_X86_64=y
@@ -1054,7 +1054,6 @@ CONFIG_DNS_RESOLVER=y
# CONFIG_BATMAN_ADV is not set
# CONFIG_OPENVSWITCH is not set
# CONFIG_VSOCKETS is not set
CONFIG_NETLINK_MMAP=y
CONFIG_NETLINK_DIAG=y
# CONFIG_NET_MPLS_GSO is not set
# CONFIG_HSR is not set
@@ -2004,7 +2003,7 @@ CONFIG_GPIO_GENERIC_PLATFORM=y
# CONFIG_GPIO_F7188X is not set
# CONFIG_GPIO_SCH311X is not set
CONFIG_GPIO_SCH=y
# CONFIG_GPIO_ICH is not set
CONFIG_GPIO_ICH=m
# CONFIG_GPIO_VX855 is not set
# CONFIG_GPIO_LYNXPOINT is not set
@@ -2451,7 +2450,7 @@ CONFIG_HID_GENERIC=y
# CONFIG_HID_BELKIN is not set
# CONFIG_HID_CHERRY is not set
# CONFIG_HID_CHICONY is not set
# CONFIG_HID_CP2112 is not set
CONFIG_HID_CP2112=y
# CONFIG_HID_CYPRESS is not set
# CONFIG_HID_DRAGONRISE is not set
# CONFIG_HID_EMS_FF is not set
@@ -2562,7 +2561,7 @@ CONFIG_USB_UHCI_HCD=y
#
# USB Device Class drivers
#
# CONFIG_USB_ACM is not set
CONFIG_USB_ACM=y
# CONFIG_USB_PRINTER is not set
# CONFIG_USB_WDM is not set
# CONFIG_USB_TMC is not set
@@ -3412,6 +3411,7 @@ CONFIG_KEYS=y
# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
# CONFIG_SECURITY_DMESG_RESTRICT is not set
# CONFIG_SECURITY is not set
CONFIG_PAGE_TABLE_ISOLATION=y
# CONFIG_SECURITYFS is not set
CONFIG_DEFAULT_SECURITY_DAC=y
CONFIG_DEFAULT_SECURITY=""
@@ -3630,3 +3630,4 @@ CONFIG_AVERAGE=y
CONFIG_CORDIC=y
# CONFIG_DDR is not set
CONFIG_OID_REGISTRY=y
CONFIG_UCS2_STRING=y

View File

@@ -25,6 +25,6 @@
THIS_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST))))
K_MAJOR_VERSION := 3
K_PATCH_LEVEL := 16
K_SUB_LEVEL := 39
K_SUB_LEVEL := 53
K_SUFFIX :=
K_PATCH_DIR := $(THIS_DIR)/patches

View File

@@ -0,0 +1,196 @@
diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c
index bc37acd..fee4c66 100644
--- a/drivers/hid/hid-cp2112.c
+++ b/drivers/hid/hid-cp2112.c
@@ -156,6 +156,7 @@ struct cp2112_device {
wait_queue_head_t wait;
u8 read_data[61];
u8 read_length;
+ u8 hwversion;
int xfer_status;
atomic_t read_avail;
atomic_t xfer_avail;
@@ -427,6 +428,156 @@ static int cp2112_write_req(void *buf, u8 slave_address, u8 command, u8 *data,
return data_length + 4;
}
+static int cp2112_i2c_write_req(void *buf, u8 slave_address, u8 *data,
+ u8 data_length)
+{
+ struct cp2112_write_req_report *report = buf;
+
+ if (data_length > sizeof(report->data))
+ return -EINVAL;
+
+ report->report = CP2112_DATA_WRITE_REQUEST;
+ report->slave_address = slave_address << 1;
+ report->length = data_length;
+ memcpy(report->data, data, data_length);
+ return data_length + 3;
+}
+
+static int cp2112_i2c_write_read_req(void *buf, u8 slave_address,
+ u8 *addr, int addr_length,
+ int read_length)
+{
+ struct cp2112_write_read_req_report *report = buf;
+
+ if (read_length < 1 || read_length > 512 ||
+ addr_length > sizeof(report->target_address))
+ return -EINVAL;
+
+ report->report = CP2112_DATA_WRITE_READ_REQUEST;
+ report->slave_address = slave_address << 1;
+ report->length = cpu_to_be16(read_length);
+ report->target_address_length = addr_length;
+ memcpy(report->target_address, addr, addr_length);
+ return addr_length + 5;
+}
+
+static int cp2112_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ int num)
+{
+ struct cp2112_device *dev = (struct cp2112_device *)adap->algo_data;
+ struct hid_device *hdev = dev->hdev;
+ u8 buf[64];
+ ssize_t count;
+ ssize_t read_length = 0;
+ u8 *read_buf = NULL;
+ unsigned int retries;
+ int ret;
+
+ hid_dbg(hdev, "I2C %d messages\n", num);
+
+ if (num == 1) {
+ if (msgs->flags & I2C_M_RD) {
+ hid_dbg(hdev, "I2C read %#04x len %d\n",
+ msgs->addr, msgs->len);
+ read_length = msgs->len;
+ read_buf = msgs->buf;
+ count = cp2112_read_req(buf, msgs->addr, msgs->len);
+ } else {
+ hid_dbg(hdev, "I2C write %#04x len %d\n",
+ msgs->addr, msgs->len);
+ count = cp2112_i2c_write_req(buf, msgs->addr,
+ msgs->buf, msgs->len);
+ }
+ if (count < 0)
+ return count;
+ } else if (dev->hwversion > 1 && /* no repeated start in rev 1 */
+ num == 2 &&
+ msgs[0].addr == msgs[1].addr &&
+ !(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD)) {
+ hid_dbg(hdev, "I2C write-read %#04x wlen %d rlen %d\n",
+ msgs[0].addr, msgs[0].len, msgs[1].len);
+ read_length = msgs[1].len;
+ read_buf = msgs[1].buf;
+ count = cp2112_i2c_write_read_req(buf, msgs[0].addr,
+ msgs[0].buf, msgs[0].len, msgs[1].len);
+ if (count < 0)
+ return count;
+ } else {
+ hid_err(hdev,
+ "Multi-message I2C transactions not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ ret = hid_hw_power(hdev, PM_HINT_FULLON);
+ if (ret < 0) {
+ hid_err(hdev, "power management error: %d\n", ret);
+ return ret;
+ }
+
+ ret = cp2112_hid_output(hdev, buf, count, HID_OUTPUT_REPORT);
+ if (ret < 0) {
+ hid_warn(hdev, "Error starting transaction: %d\n", ret);
+ goto power_normal;
+ }
+
+ for (retries = 0; retries < XFER_STATUS_RETRIES; ++retries) {
+ ret = cp2112_xfer_status(dev);
+ if (-EBUSY == ret)
+ continue;
+ if (ret < 0)
+ goto power_normal;
+ break;
+ }
+
+ if (XFER_STATUS_RETRIES <= retries) {
+ hid_warn(hdev, "Transfer timed out, cancelling.\n");
+ buf[0] = CP2112_CANCEL_TRANSFER;
+ buf[1] = 0x01;
+
+ ret = cp2112_hid_output(hdev, buf, 2, HID_OUTPUT_REPORT);
+ if (ret < 0)
+ hid_warn(hdev, "Error cancelling transaction: %d\n",
+ ret);
+
+ ret = -ETIMEDOUT;
+ goto power_normal;
+ }
+
+ for (count = 0; count < read_length;) {
+ ret = cp2112_read(dev, read_buf + count, read_length - count);
+ if (ret < 0)
+ goto power_normal;
+ if (ret == 0) {
+ hid_err(hdev, "read returned 0\n");
+ ret = -EIO;
+ goto power_normal;
+ }
+ count += ret;
+ if (count > read_length) {
+ /*
+ * The hardware returned too much data.
+ * This is mostly harmless because cp2112_read()
+ * has a limit check so didn't overrun our
+ * buffer. Nevertheless, we return an error
+ * because something is seriously wrong and
+ * it shouldn't go unnoticed.
+ */
+ hid_err(hdev, "long read: %d > %zd\n",
+ ret, read_length - count + ret);
+ ret = -EIO;
+ goto power_normal;
+ }
+ }
+
+ /* return the number of transferred messages */
+ ret = num;
+
+power_normal:
+ hid_hw_power(hdev, PM_HINT_NORMAL);
+ hid_dbg(hdev, "I2C transfer finished: %d\n", ret);
+ return ret;
+}
+
static int cp2112_xfer(struct i2c_adapter *adap, u16 addr,
unsigned short flags, char read_write, u8 command,
int size, union i2c_smbus_data *data)
@@ -593,7 +744,8 @@ power_normal:
static u32 cp2112_functionality(struct i2c_adapter *adap)
{
- return I2C_FUNC_SMBUS_BYTE |
+ return I2C_FUNC_I2C |
+ I2C_FUNC_SMBUS_BYTE |
I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA |
I2C_FUNC_SMBUS_BLOCK_DATA |
@@ -603,6 +755,7 @@ static u32 cp2112_functionality(struct i2c_adapter *adap)
}
static const struct i2c_algorithm smbus_algorithm = {
+ .master_xfer = cp2112_i2c_xfer,
.smbus_xfer = cp2112_xfer,
.functionality = cp2112_functionality,
};
@@ -925,6 +1078,7 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
dev->adap.dev.parent = &hdev->dev;
snprintf(dev->adap.name, sizeof(dev->adap.name),
"CP2112 SMBus Bridge on hiddev%d", hdev->minor);
+ dev->hwversion = buf[2];
init_waitqueue_head(&dev->wait);
hid_device_io_start(hdev);

View File

@@ -350,19 +350,6 @@ diff -urpN a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
diff -urpN a/fs/ext4/namei.c b/fs/ext4/namei.c
--- a/fs/ext4/namei.c 2016-11-20 01:17:41.000000000 +0000
+++ b/fs/ext4/namei.c 2016-12-21 21:06:34.010677297 +0000
@@ -1849,10 +1849,10 @@ static int make_indexed_dir(handle_t *ha
retval = ext4_handle_dirty_dx_node(handle, dir, frame->bh);
if (retval)
- goto out_frames;
+ goto out_frames;
retval = ext4_handle_dirty_dirent_node(handle, dir, bh);
if (retval)
- goto out_frames;
+ goto out_frames;
de = do_split(handle,dir, &bh, frame, &hinfo);
if (IS_ERR(de)) {
@@ -2905,7 +2905,7 @@ retry:
* for transaction commit if we are running out of space
* and thus we deadlock. So we have to stop transaction now
@@ -4075,20 +4062,6 @@ diff -urpN a/include/linux/fs.h b/include/linux/fs.h
*
* @AOP_TRUNCATED_PAGE: The AOP method that was handed a locked page has
* unlocked it and the page might have been truncated.
@@ -806,10 +826,10 @@ static inline struct file *get_file(stru
#define MAX_NON_LFS ((1UL<<31) - 1)
-/* Page cache limit. The filesystems should put that into their s_maxbytes
- limits, otherwise bad things can happen in VM. */
+/* Page cache limit. The filesystems should put that into their s_maxbytes
+ limits, otherwise bad things can happen in VM. */
#if BITS_PER_LONG==32
-#define MAX_LFS_FILESIZE (((loff_t)PAGE_CACHE_SIZE << (BITS_PER_LONG-1))-1)
+#define MAX_LFS_FILESIZE (((loff_t)PAGE_CACHE_SIZE << (BITS_PER_LONG-1))-1)
#elif BITS_PER_LONG==64
#define MAX_LFS_FILESIZE ((loff_t)0x7fffffffffffffffLL)
#endif
@@ -1401,6 +1421,7 @@ extern int vfs_link(struct dentry *, str
extern int vfs_rmdir(struct inode *, struct dentry *);
extern int vfs_unlink(struct inode *, struct dentry *, struct inode **);

View File

@@ -26,4 +26,5 @@ platform-powerpc-dni-7448-r0.patch
platform-powerpc-quanta-lb9-r0.patch
driver-support-intel-igb-bcm50210-phy.patch
driver-igb-netberg-aurora.patch
driver-hid-cp2112-mods.patch
gcc-no-pie.patch

View File

@@ -38,6 +38,6 @@ K_COPY_DST := kernel-3.2-lts-arm-iproc-all.bin.gz
endif
export ARCH=arm
DTS_LIST := accton_as4610_54
DTS_LIST := accton_as4610_54 delta_ag6248c
include $(ONL)/make/kbuild.mk

View File

@@ -289,6 +289,7 @@ CONFIG_BCM_RAM_START_RESERVED_SIZE=0x200000
# CONFIG_MACH_GH is not set
# CONFIG_MACH_DNI_3448P is not set
CONFIG_MACH_ACCTON_AS4610_54=y
CONFIG_MACH_DELTA_AG6248C=y
# CONFIG_MACH_IPROC_EMULATION is not set
#
@@ -1938,7 +1939,8 @@ CONFIG_IPROC_QSPI_SINGLE_MODE=y
# CONFIG_IPROC_QSPI_DUAL_MODE is not set
# CONFIG_IPROC_QSPI_QUAD_MODE is not set
CONFIG_IPROC_QSPI_MAX_HZ=62500000
# CONFIG_IPROC_MTD_NAND is not set
CONFIG_IPROC_MTD_NAND=y
# CONFIG_IPROC_MTD_NAND_USE_JFFS2 is not set
# CONFIG_IPROC_PWM is not set
CONFIG_IPROC_USB2H=y
CONFIG_USB_EHCI_BCM=y

View File

@@ -0,0 +1,181 @@
diff --git a/arch/arm/boot/dts/delta_ag6248c.dts b/arch/arm/boot/dts/delta_ag6248c.dts
new file mode 100755
index 0000000..f86c35b
--- /dev/null
+++ b/arch/arm/boot/dts/delta_ag6248c.dts
@@ -0,0 +1,78 @@
+/*
+ * Delta Networks, Inc. AG6248C Device Tree Source
+ *
+ * Copyright 2015, Cumulus Networks, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+/dts-v1/;
+/include/ "helix4.dtsi"
+
+/ {
+ model = "delta,ag6248c";
+ compatible = "delta,ag6248c";
+
+ aliases {
+ serial0 = &uart0;
+ i2c-controller0 = &i2c0;
+ i2c-controller1 = &i2c1;
+ };
+
+ memory {
+ reg = <0x61000000 0x7f000000>;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ next-level-cache = <&L2>;
+ reg = <0x00>;
+ };
+ cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ next-level-cache = <&L2>;
+ reg = <0x01>;
+ };
+ };
+
+ localbus@1e000000{
+ address-cells = <0x2>;
+ #size-cells = <0x1>;
+ compatible = "simple-bus";
+ ranges = <0x0 0x0 0x1e000000 0x02000000>;
+
+ };
+
+ i2c0: i2c@18038000 {
+ compatible = "iproc-smb";
+ reg = <0x18038000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = < 127 >;
+ clock-frequency = <400000>;
+ rtc@68 {
+ compatible = "m41st85";
+ reg = <0x68>;
+ };
+ };
+
+
+ i2c1: i2c@1803b000 {
+ compatible = "iproc-smb";
+ reg = <0x1803b000 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = < 128 >;
+ clock-frequency = <100000>;
+
+ };
+};
diff --git a/arch/arm/mach-iproc/Kconfig b/arch/arm/mach-iproc/Kconfig
index c77208d..c6a87fc 100644
--- a/arch/arm/mach-iproc/Kconfig
+++ b/arch/arm/mach-iproc/Kconfig
@@ -49,6 +49,12 @@ config MACH_ACCTON_AS4610_54
help
Support for Accton AS4610-54 POE and non -POE board.
+config MACH_DELTA_AG6248C
+ select ARM_L1_CACHE_SHIFT_6
+ bool "Support Delta AG6248C board"
+ help
+ Support for Delta AG6248C board.
+
config MACH_IPROC_P7
bool "Support iProc Profile 7 architecture"
depends on MACH_GH
diff --git a/arch/arm/mach-iproc/board_bu.c b/arch/arm/mach-iproc/board_bu.c
index 7e07ed1..5479020 100644
--- a/arch/arm/mach-iproc/board_bu.c
+++ b/arch/arm/mach-iproc/board_bu.c
@@ -1083,6 +1083,7 @@ MACHINE_END
static const char * helix4_dt_board_compat[] = {
"dni,dni_3448p",
"accton,as4610_54",
+ "delta,ag6248c",
NULL
};
diff --git a/arch/arm/mach-iproc/common.c b/arch/arm/mach-iproc/common.c
index b116ffc..e911a2b 100644
--- a/arch/arm/mach-iproc/common.c
+++ b/arch/arm/mach-iproc/common.c
@@ -187,7 +187,8 @@ static struct platform_device wdt_device =
enum {
HX4_NONE = 0,
HX4_DNI_3448P,
- HX4_ACCTON_AS4610_54
+ HX4_ACCTON_AS4610_54,
+ HX4_DELTA_AG6248C,
};
/*
@@ -212,6 +213,8 @@ int brcm_get_hx4_model(void)
return HX4_DNI_3448P;
else if (!strcmp(model, "accton,as4610_54"))
return HX4_ACCTON_AS4610_54;
+ else if (!strcmp(model, "delta,ag6248c"))
+ return HX4_DELTA_AG6248C;
printk( KERN_ERR "Unknown Model %s\n", model );
return HX4_NONE;
diff --git a/arch/arm/mach-iproc/include/mach/iproc_regs.h b/arch/arm/mach-iproc/include/mach/iproc_regs.h
index 460c436..50ea557 100644
--- a/arch/arm/mach-iproc/include/mach/iproc_regs.h
+++ b/arch/arm/mach-iproc/include/mach/iproc_regs.h
@@ -364,7 +364,11 @@
#define IPROC_GMAC3_INT 182
#elif (defined(CONFIG_MACH_HX4) || defined(CONFIG_MACH_KT2) || defined(CONFIG_MACH_DNI_3448P) || \
defined(CONFIG_MACH_ACCTON_AS4610_54))
+#if defined(CONFIG_MACH_DELTA_AG6248C)
+#define IPROC_NUM_GMACS 1
+#else
#define IPROC_NUM_GMACS 2
+#endif
#define IPROC_GMAC0_REG_BASE (GMAC0_DEVCONTROL) //(0x18022000)
#define IPROC_GMAC1_REG_BASE (GMAC1_DEVCONTROL) //(0x18023000)
#define IPROC_GMAC2_REG_BASE (0) // n/a
diff --git a/drivers/bcmdrivers/gmac/src/shared/nvramstubs.c b/drivers/bcmdrivers/gmac/src/shared/nvramstubs.c
index d5b400d..a823697 100644
--- a/drivers/bcmdrivers/gmac/src/shared/nvramstubs.c
+++ b/drivers/bcmdrivers/gmac/src/shared/nvramstubs.c
@@ -143,7 +143,8 @@ __setup("envaddr=", envaddr_setup);
enum {
HX4_NONE = 0,
HX4_DNI_3448P,
- HX4_ACCTON_AS4610_54
+ HX4_ACCTON_AS4610_54,
+ HX4_DELTA_AG6248C
};
static void
@@ -158,7 +159,10 @@ setup_uboot_vars(void) {
} else if (modelnum == HX4_ACCTON_AS4610_54) {
env_offset = 0x000f0000;
uboot_vars_start = CONFIG_SPI_BASE + env_offset;
- }
+ }else if (modelnum == HX4_DELTA_AG6248C) {
+ env_offset = 0x00300000;
+ uboot_vars_start = CONFIG_NAND_BASE + env_offset;
+ }
}
/*
--
2.1.4

View File

@@ -506,3 +506,4 @@ scripts_package_Makefile.patch
tools_include_tools_be_byteshift.h.patch
tools_include_tools_le_byteshift.h.patch
platform-accton-as4610-device-drivers.patch
platform-delta-ag6248c-device-drivers.patch

View File

@@ -1,2 +1,3 @@
kernel-3.2*
linux-*
lib

View File

@@ -22,7 +22,7 @@
THIS_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST))))
K_MAJOR_VERSION := 3
K_PATCH_LEVEL := 2
K_SUB_LEVEL := 84
K_SUB_LEVEL := 98
K_SUFFIX :=
ifndef K_PATCH_DIR
K_PATCH_DIR := $(THIS_DIR)/patches

View File

@@ -0,0 +1,3 @@
kernel-*
linux-*
lib

View File

@@ -0,0 +1,37 @@
############################################################
# <bsn.cl fy=2015 v=onl>
#
# Copyright 2015 Big Switch Networks, Inc.
#
# Licensed under the Eclipse Public License, Version 1.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.eclipse.org/legal/epl-v10.html
#
# 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.
#
# </bsn.cl>
############################################################
THIS_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST))))
include $(ONL)/make/config.mk
export ARCH := x86_64
ifndef K_TARGET_DIR
K_TARGET_DIR := $(THIS_DIR)
endif
include ../../kconfig.mk
K_CONFIG := x86_64-all.config
K_BUILD_TARGET := bzImage
K_COPY_SRC := arch/x86/boot/bzImage
ifndef K_COPY_DST
K_COPY_DST := kernel-4.14-lts-x86_64-all
endif
include $(ONL)/make/kbuild.mk

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,27 @@
############################################################
# <bsn.cl fy=2015 v=onl>
#
# Copyright 2015 Big Switch Networks, Inc.
#
# Licensed under the Eclipse Public License, Version 1.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.eclipse.org/legal/epl-v10.html
#
# 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.
#
# </bsn.cl>
############################################################
THIS_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST))))
K_MAJOR_VERSION := 4
K_PATCH_LEVEL := 14
K_SUB_LEVEL := 34
K_SUFFIX :=
K_PATCH_DIR := $(THIS_DIR)/patches
K_MODSYNCLIST := tools/objtool

View File

@@ -0,0 +1 @@

View File

@@ -25,6 +25,6 @@
THIS_DIR := $(abspath $(dir $(lastword $(MAKEFILE_LIST))))
K_MAJOR_VERSION := 4
K_PATCH_LEVEL := 9
K_SUB_LEVEL := 30
K_SUB_LEVEL := 75
K_SUFFIX :=
K_PATCH_DIR := $(THIS_DIR)/patches

View File

@@ -0,0 +1,544 @@
Linux backport patch. Includes following commits:
899e11216e1c215b97f2f8f92c7b010a4e88f38e
diff -Nur a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
--- a/drivers/i2c/busses/Kconfig 2017-11-12 08:08:32.136039784 +0000
+++ b/drivers/i2c/busses/Kconfig 2017-11-12 08:08:40.776039899 +0000
@@ -1150,6 +1150,17 @@
This support is also available as a module. If so, the module
will be called i2c-elektor.
+config I2C_MLXCPLD
+ tristate "Mellanox I2C driver"
+ depends on X86_64
+ help
+ This exposes the Mellanox platform I2C busses to the linux I2C layer
+ for X86 based systems.
+ Controller is implemented as CPLD logic.
+
+ This driver can also be built as a module. If so, the module will be
+ called as i2c-mlxcpld.
+
config I2C_PCA_ISA
tristate "PCA9564/PCA9665 on an ISA bus"
depends on ISA
diff -Nur a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
--- a/drivers/i2c/busses/Makefile 2017-11-12 08:08:32.140039784 +0000
+++ b/drivers/i2c/busses/Makefile 2017-11-12 08:08:40.780039899 +0000
@@ -116,6 +116,7 @@
obj-$(CONFIG_I2C_BRCMSTB) += i2c-brcmstb.o
obj-$(CONFIG_I2C_CROS_EC_TUNNEL) += i2c-cros-ec-tunnel.o
obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o
+obj-$(CONFIG_I2C_MLXCPLD) += i2c-mlxcpld.o
obj-$(CONFIG_I2C_OPAL) += i2c-opal.o
obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o
diff -Nur a/drivers/i2c/busses/i2c-mlxcpld.c b/drivers/i2c/busses/i2c-mlxcpld.c
--- a/drivers/i2c/busses/i2c-mlxcpld.c 1970-01-01 00:00:00.000000000 +0000
+++ b/drivers/i2c/busses/i2c-mlxcpld.c 2017-11-12 08:08:40.780039899 +0000
@@ -0,0 +1,504 @@
+/*
+ * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2016 Michael Shych <michaels@mellanox.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+/* General defines */
+#define MLXPLAT_CPLD_LPC_I2C_BASE_ADDR 0x2000
+#define MLXCPLD_I2C_DEVICE_NAME "i2c_mlxcpld"
+#define MLXCPLD_I2C_VALID_FLAG (I2C_M_RECV_LEN | I2C_M_RD)
+#define MLXCPLD_I2C_BUS_NUM 1
+#define MLXCPLD_I2C_DATA_REG_SZ 36
+#define MLXCPLD_I2C_MAX_ADDR_LEN 4
+#define MLXCPLD_I2C_RETR_NUM 2
+#define MLXCPLD_I2C_XFER_TO 500000 /* usec */
+#define MLXCPLD_I2C_POLL_TIME 2000 /* usec */
+
+/* LPC I2C registers */
+#define MLXCPLD_LPCI2C_LPF_REG 0x0
+#define MLXCPLD_LPCI2C_CTRL_REG 0x1
+#define MLXCPLD_LPCI2C_HALF_CYC_REG 0x4
+#define MLXCPLD_LPCI2C_I2C_HOLD_REG 0x5
+#define MLXCPLD_LPCI2C_CMD_REG 0x6
+#define MLXCPLD_LPCI2C_NUM_DAT_REG 0x7
+#define MLXCPLD_LPCI2C_NUM_ADDR_REG 0x8
+#define MLXCPLD_LPCI2C_STATUS_REG 0x9
+#define MLXCPLD_LPCI2C_DATA_REG 0xa
+
+/* LPC I2C masks and parametres */
+#define MLXCPLD_LPCI2C_RST_SEL_MASK 0x1
+#define MLXCPLD_LPCI2C_TRANS_END 0x1
+#define MLXCPLD_LPCI2C_STATUS_NACK 0x10
+#define MLXCPLD_LPCI2C_NO_IND 0
+#define MLXCPLD_LPCI2C_ACK_IND 1
+#define MLXCPLD_LPCI2C_NACK_IND 2
+
+struct mlxcpld_i2c_curr_xfer {
+ u8 cmd;
+ u8 addr_width;
+ u8 data_len;
+ u8 msg_num;
+ struct i2c_msg *msg;
+};
+
+struct mlxcpld_i2c_priv {
+ struct i2c_adapter adap;
+ u32 base_addr;
+ struct mutex lock;
+ struct mlxcpld_i2c_curr_xfer xfer;
+ struct device *dev;
+};
+
+static void mlxcpld_i2c_lpc_write_buf(u8 *data, u8 len, u32 addr)
+{
+ int i;
+
+ for (i = 0; i < len - len % 4; i += 4)
+ outl(*(u32 *)(data + i), addr + i);
+ for (; i < len; ++i)
+ outb(*(data + i), addr + i);
+}
+
+static void mlxcpld_i2c_lpc_read_buf(u8 *data, u8 len, u32 addr)
+{
+ int i;
+
+ for (i = 0; i < len - len % 4; i += 4)
+ *(u32 *)(data + i) = inl(addr + i);
+ for (; i < len; ++i)
+ *(data + i) = inb(addr + i);
+}
+
+static void mlxcpld_i2c_read_comm(struct mlxcpld_i2c_priv *priv, u8 offs,
+ u8 *data, u8 datalen)
+{
+ u32 addr = priv->base_addr + offs;
+
+ switch (datalen) {
+ case 1:
+ *(data) = inb(addr);
+ break;
+ case 2:
+ *((u16 *)data) = inw(addr);
+ break;
+ case 3:
+ *((u16 *)data) = inw(addr);
+ *(data + 2) = inb(addr + 2);
+ break;
+ case 4:
+ *((u32 *)data) = inl(addr);
+ break;
+ default:
+ mlxcpld_i2c_lpc_read_buf(data, datalen, addr);
+ break;
+ }
+}
+
+static void mlxcpld_i2c_write_comm(struct mlxcpld_i2c_priv *priv, u8 offs,
+ u8 *data, u8 datalen)
+{
+ u32 addr = priv->base_addr + offs;
+
+ switch (datalen) {
+ case 1:
+ outb(*(data), addr);
+ break;
+ case 2:
+ outw(*((u16 *)data), addr);
+ break;
+ case 3:
+ outw(*((u16 *)data), addr);
+ outb(*(data + 2), addr + 2);
+ break;
+ case 4:
+ outl(*((u32 *)data), addr);
+ break;
+ default:
+ mlxcpld_i2c_lpc_write_buf(data, datalen, addr);
+ break;
+ }
+}
+
+/*
+ * Check validity of received i2c messages parameters.
+ * Returns 0 if OK, other - in case of invalid parameters.
+ */
+static int mlxcpld_i2c_check_msg_params(struct mlxcpld_i2c_priv *priv,
+ struct i2c_msg *msgs, int num)
+{
+ int i;
+
+ if (!num) {
+ dev_err(priv->dev, "Incorrect 0 num of messages\n");
+ return -EINVAL;
+ }
+
+ if (unlikely(msgs[0].addr > 0x7f)) {
+ dev_err(priv->dev, "Invalid address 0x%03x\n",
+ msgs[0].addr);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < num; ++i) {
+ if (unlikely(!msgs[i].buf)) {
+ dev_err(priv->dev, "Invalid buf in msg[%d]\n",
+ i);
+ return -EINVAL;
+ }
+ if (unlikely(msgs[0].addr != msgs[i].addr)) {
+ dev_err(priv->dev, "Invalid addr in msg[%d]\n",
+ i);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Check if transfer is completed and status of operation.
+ * Returns 0 - transfer completed (both ACK or NACK),
+ * negative - transfer isn't finished.
+ */
+static int mlxcpld_i2c_check_status(struct mlxcpld_i2c_priv *priv, int *status)
+{
+ u8 val;
+
+ mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_STATUS_REG, &val, 1);
+
+ if (val & MLXCPLD_LPCI2C_TRANS_END) {
+ if (val & MLXCPLD_LPCI2C_STATUS_NACK)
+ /*
+ * The slave is unable to accept the data. No such
+ * slave, command not understood, or unable to accept
+ * any more data.
+ */
+ *status = MLXCPLD_LPCI2C_NACK_IND;
+ else
+ *status = MLXCPLD_LPCI2C_ACK_IND;
+ return 0;
+ }
+ *status = MLXCPLD_LPCI2C_NO_IND;
+
+ return -EIO;
+}
+
+static void mlxcpld_i2c_set_transf_data(struct mlxcpld_i2c_priv *priv,
+ struct i2c_msg *msgs, int num,
+ u8 comm_len)
+{
+ priv->xfer.msg = msgs;
+ priv->xfer.msg_num = num;
+
+ /*
+ * All upper layers currently are never use transfer with more than
+ * 2 messages. Actually, it's also not so relevant in Mellanox systems
+ * because of HW limitation. Max size of transfer is not more than 32
+ * bytes in the current x86 LPCI2C bridge.
+ */
+ priv->xfer.cmd = msgs[num - 1].flags & I2C_M_RD;
+
+ if (priv->xfer.cmd == I2C_M_RD && comm_len != msgs[0].len) {
+ priv->xfer.addr_width = msgs[0].len;
+ priv->xfer.data_len = comm_len - priv->xfer.addr_width;
+ } else {
+ priv->xfer.addr_width = 0;
+ priv->xfer.data_len = comm_len;
+ }
+}
+
+/* Reset CPLD LPCI2C block */
+static void mlxcpld_i2c_reset(struct mlxcpld_i2c_priv *priv)
+{
+ u8 val;
+
+ mutex_lock(&priv->lock);
+
+ mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_CTRL_REG, &val, 1);
+ val &= ~MLXCPLD_LPCI2C_RST_SEL_MASK;
+ mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_CTRL_REG, &val, 1);
+
+ mutex_unlock(&priv->lock);
+}
+
+/* Make sure the CPLD is ready to start transmitting. */
+static int mlxcpld_i2c_check_busy(struct mlxcpld_i2c_priv *priv)
+{
+ u8 val;
+
+ mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_STATUS_REG, &val, 1);
+
+ if (val & MLXCPLD_LPCI2C_TRANS_END)
+ return 0;
+
+ return -EIO;
+}
+
+static int mlxcpld_i2c_wait_for_free(struct mlxcpld_i2c_priv *priv)
+{
+ int timeout = 0;
+
+ do {
+ if (!mlxcpld_i2c_check_busy(priv))
+ break;
+ usleep_range(MLXCPLD_I2C_POLL_TIME / 2, MLXCPLD_I2C_POLL_TIME);
+ timeout += MLXCPLD_I2C_POLL_TIME;
+ } while (timeout <= MLXCPLD_I2C_XFER_TO);
+
+ if (timeout > MLXCPLD_I2C_XFER_TO)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+/*
+ * Wait for master transfer to complete.
+ * It puts current process to sleep until we get interrupt or timeout expires.
+ * Returns the number of transferred or read bytes or error (<0).
+ */
+static int mlxcpld_i2c_wait_for_tc(struct mlxcpld_i2c_priv *priv)
+{
+ int status, i, timeout = 0;
+ u8 datalen;
+
+ do {
+ usleep_range(MLXCPLD_I2C_POLL_TIME / 2, MLXCPLD_I2C_POLL_TIME);
+ if (!mlxcpld_i2c_check_status(priv, &status))
+ break;
+ timeout += MLXCPLD_I2C_POLL_TIME;
+ } while (status == 0 && timeout < MLXCPLD_I2C_XFER_TO);
+
+ switch (status) {
+ case MLXCPLD_LPCI2C_NO_IND:
+ return -ETIMEDOUT;
+
+ case MLXCPLD_LPCI2C_ACK_IND:
+ if (priv->xfer.cmd != I2C_M_RD)
+ return (priv->xfer.addr_width + priv->xfer.data_len);
+
+ if (priv->xfer.msg_num == 1)
+ i = 0;
+ else
+ i = 1;
+
+ if (!priv->xfer.msg[i].buf)
+ return -EINVAL;
+
+ /*
+ * Actual read data len will be always the same as
+ * requested len. 0xff (line pull-up) will be returned
+ * if slave has no data to return. Thus don't read
+ * MLXCPLD_LPCI2C_NUM_DAT_REG reg from CPLD.
+ */
+ datalen = priv->xfer.data_len;
+
+ mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_DATA_REG,
+ priv->xfer.msg[i].buf, datalen);
+
+ return datalen;
+
+ case MLXCPLD_LPCI2C_NACK_IND:
+ return -ENXIO;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static void mlxcpld_i2c_xfer_msg(struct mlxcpld_i2c_priv *priv)
+{
+ int i, len = 0;
+ u8 cmd;
+
+ mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_NUM_DAT_REG,
+ &priv->xfer.data_len, 1);
+ mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_NUM_ADDR_REG,
+ &priv->xfer.addr_width, 1);
+
+ for (i = 0; i < priv->xfer.msg_num; i++) {
+ if ((priv->xfer.msg[i].flags & I2C_M_RD) != I2C_M_RD) {
+ /* Don't write to CPLD buffer in read transaction */
+ mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_DATA_REG +
+ len, priv->xfer.msg[i].buf,
+ priv->xfer.msg[i].len);
+ len += priv->xfer.msg[i].len;
+ }
+ }
+
+ /*
+ * Set target slave address with command for master transfer.
+ * It should be latest executed function before CPLD transaction.
+ */
+ cmd = (priv->xfer.msg[0].addr << 1) | priv->xfer.cmd;
+ mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_CMD_REG, &cmd, 1);
+}
+
+/*
+ * Generic lpc-i2c transfer.
+ * Returns the number of processed messages or error (<0).
+ */
+static int mlxcpld_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ int num)
+{
+ struct mlxcpld_i2c_priv *priv = i2c_get_adapdata(adap);
+ u8 comm_len = 0;
+ int i, err;
+
+ err = mlxcpld_i2c_check_msg_params(priv, msgs, num);
+ if (err) {
+ dev_err(priv->dev, "Incorrect message\n");
+ return err;
+ }
+
+ for (i = 0; i < num; ++i)
+ comm_len += msgs[i].len;
+
+ /* Check bus state */
+ if (mlxcpld_i2c_wait_for_free(priv)) {
+ dev_err(priv->dev, "LPCI2C bridge is busy\n");
+
+ /*
+ * Usually it means something serious has happened.
+ * We can not have unfinished previous transfer
+ * so it doesn't make any sense to try to stop it.
+ * Probably we were not able to recover from the
+ * previous error.
+ * The only reasonable thing - is soft reset.
+ */
+ mlxcpld_i2c_reset(priv);
+ if (mlxcpld_i2c_check_busy(priv)) {
+ dev_err(priv->dev, "LPCI2C bridge is busy after reset\n");
+ return -EIO;
+ }
+ }
+
+ mlxcpld_i2c_set_transf_data(priv, msgs, num, comm_len);
+
+ mutex_lock(&priv->lock);
+
+ /* Do real transfer. Can't fail */
+ mlxcpld_i2c_xfer_msg(priv);
+
+ /* Wait for transaction complete */
+ err = mlxcpld_i2c_wait_for_tc(priv);
+
+ mutex_unlock(&priv->lock);
+
+ return err < 0 ? err : num;
+}
+
+static u32 mlxcpld_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+static const struct i2c_algorithm mlxcpld_i2c_algo = {
+ .master_xfer = mlxcpld_i2c_xfer,
+ .functionality = mlxcpld_i2c_func
+};
+
+static struct i2c_adapter_quirks mlxcpld_i2c_quirks = {
+ .flags = I2C_AQ_COMB_WRITE_THEN_READ,
+ .max_read_len = MLXCPLD_I2C_DATA_REG_SZ - MLXCPLD_I2C_MAX_ADDR_LEN,
+ .max_write_len = MLXCPLD_I2C_DATA_REG_SZ,
+ .max_comb_1st_msg_len = 4,
+};
+
+static struct i2c_adapter mlxcpld_i2c_adapter = {
+ .owner = THIS_MODULE,
+ .name = "i2c-mlxcpld",
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .algo = &mlxcpld_i2c_algo,
+ .quirks = &mlxcpld_i2c_quirks,
+ .retries = MLXCPLD_I2C_RETR_NUM,
+ .nr = MLXCPLD_I2C_BUS_NUM,
+};
+
+static int mlxcpld_i2c_probe(struct platform_device *pdev)
+{
+ struct mlxcpld_i2c_priv *priv;
+ int err;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ mutex_init(&priv->lock);
+ platform_set_drvdata(pdev, priv);
+
+ priv->dev = &pdev->dev;
+
+ /* Register with i2c layer */
+ mlxcpld_i2c_adapter.timeout = usecs_to_jiffies(MLXCPLD_I2C_XFER_TO);
+ priv->adap = mlxcpld_i2c_adapter;
+ priv->adap.dev.parent = &pdev->dev;
+ priv->base_addr = MLXPLAT_CPLD_LPC_I2C_BASE_ADDR;
+ i2c_set_adapdata(&priv->adap, priv);
+
+ err = i2c_add_numbered_adapter(&priv->adap);
+ if (err)
+ mutex_destroy(&priv->lock);
+
+ return err;
+}
+
+static int mlxcpld_i2c_remove(struct platform_device *pdev)
+{
+ struct mlxcpld_i2c_priv *priv = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&priv->adap);
+ mutex_destroy(&priv->lock);
+
+ return 0;
+}
+
+static struct platform_driver mlxcpld_i2c_driver = {
+ .probe = mlxcpld_i2c_probe,
+ .remove = mlxcpld_i2c_remove,
+ .driver = {
+ .name = MLXCPLD_I2C_DEVICE_NAME,
+ },
+};
+
+module_platform_driver(mlxcpld_i2c_driver);
+
+MODULE_AUTHOR("Michael Shych <michaels@mellanox.com>");
+MODULE_DESCRIPTION("Mellanox I2C-CPLD controller driver");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_ALIAS("platform:i2c-mlxcpld");

View File

@@ -0,0 +1,317 @@
Linux backport patch. Includes following commits:
e3448e71adb1fdd7f403c568ef5c2ed5adf2b197
c3bb77620da428884807fb2f6f3485644e146f84
db5f807ee3dcc779b78f59982cc3e89863069e9c
diff -Nur a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig
--- a/drivers/i2c/muxes/Kconfig 2017-11-12 08:13:59.176044126 +0000
+++ b/drivers/i2c/muxes/Kconfig 2017-11-12 08:14:27.992044509 +0000
@@ -82,4 +82,15 @@
demultiplexer that uses the pinctrl subsystem. This is useful if you
want to change the I2C master at run-time depending on features.
+config I2C_MUX_MLXCPLD
+ tristate "Mellanox CPLD based I2C multiplexer"
+ help
+ If you say yes to this option, support will be included for a
+ CPLD based I2C multiplexer. This driver provides access to
+ I2C busses connected through a MUX, which is controlled
+ by a CPLD register.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-mux-mlxcpld.
+
endmenu
diff -Nur a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile
--- a/drivers/i2c/muxes/Makefile 2017-11-12 08:13:59.176044126 +0000
+++ b/drivers/i2c/muxes/Makefile 2017-11-12 08:14:27.992044509 +0000
@@ -6,6 +6,7 @@
obj-$(CONFIG_I2C_DEMUX_PINCTRL) += i2c-demux-pinctrl.o
obj-$(CONFIG_I2C_MUX_GPIO) += i2c-mux-gpio.o
+obj-$(CONFIG_I2C_MUX_MLXCPLD) += i2c-mux-mlxcpld.o
obj-$(CONFIG_I2C_MUX_PCA9541) += i2c-mux-pca9541.o
obj-$(CONFIG_I2C_MUX_PCA954x) += i2c-mux-pca954x.o
obj-$(CONFIG_I2C_MUX_PINCTRL) += i2c-mux-pinctrl.o
diff -Nur a/drivers/i2c/muxes/i2c-mux-mlxcpld.c b/drivers/i2c/muxes/i2c-mux-mlxcpld.c
--- a/drivers/i2c/muxes/i2c-mux-mlxcpld.c 1970-01-01 00:00:00.000000000 +0000
+++ b/drivers/i2c/muxes/i2c-mux-mlxcpld.c 2017-11-12 08:14:27.992044509 +0000
@@ -0,0 +1,221 @@
+/*
+ * drivers/i2c/muxes/i2c-mux-mlxcpld.c
+ * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2016 Michael Shych <michaels@mellanox.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/i2c-mux.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/i2c/mlxcpld.h>
+
+#define CPLD_MUX_MAX_NCHANS 8
+
+/* mlxcpld_mux - mux control structure:
+ * @last_chan - last register value
+ * @client - I2C device client
+ */
+struct mlxcpld_mux {
+ u8 last_chan;
+ struct i2c_client *client;
+};
+
+/* MUX logic description.
+ * Driver can support different mux control logic, according to CPLD
+ * implementation.
+ *
+ * Connectivity schema.
+ *
+ * i2c-mlxcpld Digital Analog
+ * driver
+ * *--------* * -> mux1 (virt bus2) -> mux -> |
+ * | I2CLPC | i2c physical * -> mux2 (virt bus3) -> mux -> |
+ * | bridge | bus 1 *---------* |
+ * | logic |---------------------> * mux reg * |
+ * | in CPLD| *---------* |
+ * *--------* i2c-mux-mlxpcld ^ * -> muxn (virt busn) -> mux -> |
+ * | driver | |
+ * | *---------------* | Devices
+ * | * CPLD (i2c bus)* select |
+ * | * registers for *--------*
+ * | * mux selection * deselect
+ * | *---------------*
+ * | |
+ * <--------> <----------->
+ * i2c cntrl Board cntrl reg
+ * reg space space (mux select,
+ * IO, LED, WD, info)
+ *
+ */
+
+static const struct i2c_device_id mlxcpld_mux_id[] = {
+ { "mlxcpld_mux_module", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mlxcpld_mux_id);
+
+/* Write to mux register. Don't use i2c_transfer() and i2c_smbus_xfer()
+ * for this as they will try to lock adapter a second time.
+ */
+static int mlxcpld_mux_reg_write(struct i2c_adapter *adap,
+ struct i2c_client *client, u8 val)
+{
+ struct mlxcpld_mux_plat_data *pdata = dev_get_platdata(&client->dev);
+ int ret = -ENODEV;
+
+ if (adap->algo->master_xfer) {
+ struct i2c_msg msg;
+ u8 msgbuf[] = {pdata->sel_reg_addr, val};
+
+ msg.addr = client->addr;
+ msg.flags = 0;
+ msg.len = 2;
+ msg.buf = msgbuf;
+ ret = __i2c_transfer(adap, &msg, 1);
+
+ if (ret >= 0 && ret != 1)
+ ret = -EREMOTEIO;
+ } else if (adap->algo->smbus_xfer) {
+ union i2c_smbus_data data;
+
+ data.byte = val;
+ ret = adap->algo->smbus_xfer(adap, client->addr,
+ client->flags, I2C_SMBUS_WRITE,
+ pdata->sel_reg_addr,
+ I2C_SMBUS_BYTE_DATA, &data);
+ }
+
+ return ret;
+}
+
+static int mlxcpld_mux_select_chan(struct i2c_mux_core *muxc, u32 chan)
+{
+ struct mlxcpld_mux *data = i2c_mux_priv(muxc);
+ struct i2c_client *client = data->client;
+ u8 regval = chan + 1;
+ int err = 0;
+
+ /* Only select the channel if its different from the last channel */
+ if (data->last_chan != regval) {
+ err = mlxcpld_mux_reg_write(muxc->parent, client, regval);
+ data->last_chan = err < 0 ? 0 : regval;
+ }
+
+ return err;
+}
+
+static int mlxcpld_mux_deselect(struct i2c_mux_core *muxc, u32 chan)
+{
+ struct mlxcpld_mux *data = i2c_mux_priv(muxc);
+ struct i2c_client *client = data->client;
+
+ /* Deselect active channel */
+ data->last_chan = 0;
+
+ return mlxcpld_mux_reg_write(muxc->parent, client, data->last_chan);
+}
+
+/* Probe/reomove functions */
+static int mlxcpld_mux_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
+ struct mlxcpld_mux_plat_data *pdata = dev_get_platdata(&client->dev);
+ struct i2c_mux_core *muxc;
+ int num, force;
+ struct mlxcpld_mux *data;
+ int err;
+
+ if (!pdata)
+ return -EINVAL;
+
+ if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
+ return -ENODEV;
+
+ muxc = i2c_mux_alloc(adap, &client->dev, CPLD_MUX_MAX_NCHANS,
+ sizeof(*data), 0, mlxcpld_mux_select_chan,
+ mlxcpld_mux_deselect);
+ if (!muxc)
+ return -ENOMEM;
+
+ data = i2c_mux_priv(muxc);
+ i2c_set_clientdata(client, muxc);
+ data->client = client;
+ data->last_chan = 0; /* force the first selection */
+
+ /* Create an adapter for each channel. */
+ for (num = 0; num < CPLD_MUX_MAX_NCHANS; num++) {
+ if (num >= pdata->num_adaps)
+ /* discard unconfigured channels */
+ break;
+
+ force = pdata->adap_ids[num];
+
+ err = i2c_mux_add_adapter(muxc, force, num, 0);
+ if (err)
+ goto virt_reg_failed;
+ }
+
+ return 0;
+
+virt_reg_failed:
+ i2c_mux_del_adapters(muxc);
+ return err;
+}
+
+static int mlxcpld_mux_remove(struct i2c_client *client)
+{
+ struct i2c_mux_core *muxc = i2c_get_clientdata(client);
+
+ i2c_mux_del_adapters(muxc);
+ return 0;
+}
+
+static struct i2c_driver mlxcpld_mux_driver = {
+ .driver = {
+ .name = "mlxcpld-mux",
+ },
+ .probe = mlxcpld_mux_probe,
+ .remove = mlxcpld_mux_remove,
+ .id_table = mlxcpld_mux_id,
+};
+
+module_i2c_driver(mlxcpld_mux_driver);
+
+MODULE_AUTHOR("Michael Shych (michaels@mellanox.com)");
+MODULE_DESCRIPTION("Mellanox I2C-CPLD-MUX driver");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_ALIAS("platform:i2c-mux-mlxcpld");
diff -Nur a/include/linux/i2c/mlxcpld.h b/include/linux/i2c/mlxcpld.h
--- a/include/linux/i2c/mlxcpld.h 1970-01-01 00:00:00.000000000 +0000
+++ b/include/linux/i2c/mlxcpld.h 2017-11-12 08:17:03.032046568 +0000
@@ -0,0 +1,52 @@
+/*
+ * mlxcpld.h - Mellanox I2C multiplexer support in CPLD
+ *
+ * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2016 Michael Shych <michaels@mellanox.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _LINUX_I2C_MLXCPLD_H
+#define _LINUX_I2C_MLXCPLD_H
+
+/* Platform data for the CPLD I2C multiplexers */
+
+/* mlxcpld_mux_plat_data - per mux data, used with i2c_register_board_info
+ * @adap_ids - adapter array
+ * @num_adaps - number of adapters
+ * @sel_reg_addr - mux select register offset in CPLD space
+ */
+struct mlxcpld_mux_plat_data {
+ int *adap_ids;
+ int num_adaps;
+ int sel_reg_addr;
+};
+
+#endif /* _LINUX_I2C_MLXCPLD_H */

View File

@@ -0,0 +1,905 @@
Linux backport patch. Includes following commits:
2926024b5081fc8d4b086677bafa1ac55ea0b911
6124fdf76488681713f278f3fdf2ba2dfe760211
c84002d15210ca130263e23911cc399202124eb4
07b89c2b2a5e8ce30166b96f87b324c6b419f108
91973760712f350048a0fa8e0363e260bf874313
c2e714e56360e34f88e0a75ee74e467d8b82de75
af4779be0f2cec63f4cb15d3db78c5de3523756a
d53bc5dc941653f0ed93b11a647bd6ff40f40ef2
diff -Nur a/drivers/platform/mellanox/Kconfig b/drivers/platform/mellanox/Kconfig
--- a/drivers/platform/mellanox/Kconfig 1970-01-01 00:00:00.000000000 +0000
+++ b/drivers/platform/mellanox/Kconfig 2017-11-12 08:54:58.200076777 +0000
@@ -0,0 +1,25 @@
+#
+# Platform support for Mellanox hardware
+#
+
+menuconfig MELLANOX_PLATFORM
+ bool "Platform support for Mellanox hardware"
+ depends on X86 || ARM || COMPILE_TEST
+ ---help---
+ Say Y here to get to see options for platform support for
+ Mellanox systems. This option alone does not add any kernel code.
+
+ If you say N, all options in this submenu will be skipped and disabled.
+
+if MELLANOX_PLATFORM
+
+config MLXREG_HOTPLUG
+ tristate "Mellanox platform hotplug driver support"
+ depends on REGMAP
+ depends on HWMON
+ depends on I2C
+ ---help---
+ This driver handles hot-plug events for the power suppliers, power
+ cables and fans on the wide range Mellanox IB and Ethernet systems.
+
+endif # MELLANOX_PLATFORM
diff -Nur a/drivers/platform/mellanox/Makefile b/drivers/platform/mellanox/Makefile
--- a/drivers/platform/mellanox/Makefile 1970-01-01 00:00:00.000000000 +0000
+++ b/drivers/platform/mellanox/Makefile 2017-11-12 08:54:58.200076777 +0000
@@ -0,0 +1 @@
+obj-$(CONFIG_MLXREG_HOTPLUG) += mlxreg-hotplug.o
diff -Nur a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c
--- a/drivers/platform/mellanox/mlxreg-hotplug.c 1970-01-01 00:00:00.000000000 +0000
+++ b/drivers/platform/mellanox/mlxreg-hotplug.c 2017-11-12 08:54:58.200076777 +0000
@@ -0,0 +1,710 @@
+/*
+ * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2017 Vadim Pasternak <vadimp@mellanox.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_data/mlxreg.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/workqueue.h>
+
+/* Offset of event and mask registers from status register. */
+#define MLXREG_HOTPLUG_EVENT_OFF 1
+#define MLXREG_HOTPLUG_MASK_OFF 2
+#define MLXREG_HOTPLUG_AGGR_MASK_OFF 1
+
+/* ASIC health parameters. */
+#define MLXREG_HOTPLUG_HEALTH_MASK 0x02
+#define MLXREG_HOTPLUG_RST_CNTR 3
+
+#define MLXREG_HOTPLUG_PROP_OKAY "okay"
+#define MLXREG_HOTPLUG_PROP_DISABLED "disabled"
+#define MLXREG_HOTPLUG_PROP_STATUS "status"
+
+#define MLXREG_HOTPLUG_ATTRS_MAX 24
+
+/**
+ * struct mlxreg_hotplug_priv_data - platform private data:
+ * @irq: platform device interrupt number;
+ * @pdev: platform device;
+ * @plat: platform data;
+ * @dwork: delayed work template;
+ * @lock: spin lock;
+ * @hwmon: hwmon device;
+ * @mlxreg_hotplug_attr: sysfs attributes array;
+ * @mlxreg_hotplug_dev_attr: sysfs sensor device attribute array;
+ * @group: sysfs attribute group;
+ * @groups: list of sysfs attribute group for hwmon registration;
+ * @cell: location of top aggregation interrupt register;
+ * @mask: top aggregation interrupt common mask;
+ * @aggr_cache: last value of aggregation register status;
+ */
+struct mlxreg_hotplug_priv_data {
+ int irq;
+ struct device *dev;
+ struct platform_device *pdev;
+ struct mlxreg_hotplug_platform_data *plat;
+ struct regmap *regmap;
+ struct delayed_work dwork_irq;
+ struct delayed_work dwork;
+ spinlock_t lock; /* sync with interrupt */
+ struct device *hwmon;
+ struct attribute *mlxreg_hotplug_attr[MLXREG_HOTPLUG_ATTRS_MAX + 1];
+ struct sensor_device_attribute_2
+ mlxreg_hotplug_dev_attr[MLXREG_HOTPLUG_ATTRS_MAX];
+ struct attribute_group group;
+ const struct attribute_group *groups[2];
+ u32 cell;
+ u32 mask;
+ u32 aggr_cache;
+ bool after_probe;
+};
+
+#if defined(CONFIG_OF_DYNAMIC)
+/**
+ * struct mlxreg_hotplug_device_en - Open Firmware property for enabling device
+ *
+ * @name - property name;
+ * @value - property value string;
+ * @length - length of proprty value string;
+ *
+ * The structure is used for the devices, which require some dynamic
+ * selection operation allowing access to them.
+ */
+static struct property mlxreg_hotplug_device_en = {
+ .name = MLXREG_HOTPLUG_PROP_STATUS,
+ .value = MLXREG_HOTPLUG_PROP_OKAY,
+ .length = sizeof(MLXREG_HOTPLUG_PROP_OKAY),
+};
+
+/**
+ * struct mlxreg_hotplug_device_dis - Open Firmware property for disabling
+ * device
+ *
+ * @name - property name;
+ * @value - property value string;
+ * @length - length of proprty value string;
+ *
+ * The structure is used for the devices, which require some dynamic
+ * selection operation disallowing access to them.
+ */
+static struct property mlxreg_hotplug_device_dis = {
+ .name = MLXREG_HOTPLUG_PROP_STATUS,
+ .value = MLXREG_HOTPLUG_PROP_DISABLED,
+ .length = sizeof(MLXREG_HOTPLUG_PROP_DISABLED),
+};
+
+static int mlxreg_hotplug_of_device_create(struct mlxreg_core_data *data)
+{
+ return of_update_property(data->np, &mlxreg_hotplug_device_en);
+}
+
+static void mlxreg_hotplug_of_device_destroy(struct mlxreg_core_data *data)
+{
+ of_update_property(data->np, &mlxreg_hotplug_device_dis);
+ of_node_clear_flag(data->np, OF_POPULATED);
+}
+#else
+static int mlxreg_hotplug_of_device_create(struct mlxreg_core_data *data)
+{
+ return 0;
+}
+
+static void mlxreg_hotplug_of_device_destroy(struct mlxreg_core_data *data)
+{
+}
+#endif
+
+static int mlxreg_hotplug_device_create(struct mlxreg_core_data *data)
+{
+ data->hpdev.adapter = i2c_get_adapter(data->hpdev.nr);
+ if (!data->hpdev.adapter)
+ return -EFAULT;
+
+ data->hpdev.client = i2c_new_device(data->hpdev.adapter,
+ data->hpdev.brdinfo);
+ if (!data->hpdev.client) {
+ i2c_put_adapter(data->hpdev.adapter);
+ data->hpdev.adapter = NULL;
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static void mlxreg_hotplug_device_destroy(struct mlxreg_core_data *data)
+{
+ if (data->hpdev.client) {
+ i2c_unregister_device(data->hpdev.client);
+ data->hpdev.client = NULL;
+ }
+
+ if (data->hpdev.adapter) {
+ i2c_put_adapter(data->hpdev.adapter);
+ data->hpdev.adapter = NULL;
+ }
+}
+
+static int mlxreg_hotplug_dev_enable(struct mlxreg_core_data *data)
+{
+ int err;
+
+ /* Enable and create device. */
+ if (data->np)
+ err = mlxreg_hotplug_of_device_create(data);
+ else
+ err = mlxreg_hotplug_device_create(data);
+
+ return err;
+}
+
+static void mlxreg_hotplug_dev_disable(struct mlxreg_core_data *data)
+{
+ /* Disable and unregister platform device. */
+ if (data->np)
+ mlxreg_hotplug_of_device_destroy(data);
+ else
+ mlxreg_hotplug_device_destroy(data);
+}
+
+static ssize_t mlxreg_hotplug_attr_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(dev);
+ struct mlxreg_core_hotplug_platform_data *pdata;
+ int index = to_sensor_dev_attr_2(attr)->index;
+ int nr = to_sensor_dev_attr_2(attr)->nr;
+ struct mlxreg_core_item *item;
+ struct mlxreg_core_data *data;
+ u32 regval;
+ int ret;
+
+ pdata = dev_get_platdata(&priv->pdev->dev);
+ item = pdata->items + nr;
+ data = item->data + index;
+
+ ret = regmap_read(priv->regmap, data->reg, &regval);
+ if (ret)
+ return ret;
+
+ if (item->health) {
+ regval &= data->mask;
+ } else {
+ /* Bit = 0 : functional if item->inversed is true. */
+ if (item->inversed)
+ regval = !(regval & data->mask);
+ else
+ regval = !!(regval & data->mask);
+ }
+
+ return sprintf(buf, "%u\n", regval);
+}
+
+#define PRIV_ATTR(i) priv->mlxreg_hotplug_attr[i]
+#define PRIV_DEV_ATTR(i) priv->mlxreg_hotplug_dev_attr[i]
+
+static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv)
+{
+ struct mlxreg_core_hotplug_platform_data *pdata;
+ struct mlxreg_core_item *item;
+ struct mlxreg_core_data *data;
+ int num_attrs = 0, id = 0, i, j;
+
+ pdata = dev_get_platdata(&priv->pdev->dev);
+ item = pdata->items;
+
+ /* Go over all kinds of items - psu, pwr, fan. */
+ for (i = 0; i < pdata->counter; i++, item++) {
+ num_attrs += item->count;
+ data = item->data;
+ /* Go over all units within the item. */
+ for (j = 0; j < item->count; j++, data++, id++) {
+ PRIV_ATTR(id) = &PRIV_DEV_ATTR(id).dev_attr.attr;
+ PRIV_ATTR(id)->name = devm_kasprintf(&priv->pdev->dev,
+ GFP_KERNEL,
+ data->label);
+
+ if (!PRIV_ATTR(id)->name) {
+ dev_err(priv->dev, "Memory allocation failed for attr %d.\n",
+ id);
+ return -ENOMEM;
+ }
+
+ PRIV_DEV_ATTR(id).dev_attr.attr.name =
+ PRIV_ATTR(id)->name;
+ PRIV_DEV_ATTR(id).dev_attr.attr.mode = 0444;
+ PRIV_DEV_ATTR(id).dev_attr.show =
+ mlxreg_hotplug_attr_show;
+ PRIV_DEV_ATTR(id).nr = i;
+ PRIV_DEV_ATTR(id).index = j;
+ sysfs_attr_init(&PRIV_DEV_ATTR(id).dev_attr.attr);
+ }
+ }
+
+ priv->group.attrs = devm_kzalloc(&priv->pdev->dev, num_attrs *
+ sizeof(struct attribute *),
+ GFP_KERNEL);
+ if (!priv->group.attrs)
+ return -ENOMEM;
+
+ priv->group.attrs = priv->mlxreg_hotplug_attr;
+ priv->groups[0] = &priv->group;
+ priv->groups[1] = NULL;
+
+ return 0;
+}
+
+static void
+mlxreg_hotplug_work_helper(struct mlxreg_hotplug_priv_data *priv,
+ struct mlxreg_core_item *item)
+{
+ struct mlxreg_core_data *data;
+ u32 asserted, regval, bit;
+ int ret;
+
+ /*
+ * Validate if item related to received signal type is valid.
+ * It should never happen, excepted the situation when some
+ * piece of hardware is broken. In such situation just produce
+ * error message and return. Caller must continue to handle the
+ * signals from other devices if any.
+ */
+ if (unlikely(!item)) {
+ dev_err(priv->dev, "False signal: at offset:mask 0x%02x:0x%02x.\n",
+ item->reg, item->mask);
+
+ return;
+ }
+
+ /* Mask event. */
+ ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF,
+ 0);
+ if (ret)
+ goto access_error;
+
+ /* Read status. */
+ ret = regmap_read(priv->regmap, item->reg, &regval);
+ if (ret)
+ goto access_error;
+
+ /* Set asserted bits and save last status. */
+ regval &= item->mask;
+ asserted = item->cache ^ regval;
+ item->cache = regval;
+
+ for_each_set_bit(bit, (unsigned long *)&asserted, 8) {
+ data = item->data + bit;
+ if (regval & BIT(bit)) {
+ if (item->inversed)
+ mlxreg_hotplug_dev_disable(data);
+ else
+ mlxreg_hotplug_dev_enable(data);
+ } else {
+ if (item->inversed)
+ mlxreg_hotplug_dev_enable(data);
+ else
+ mlxreg_hotplug_dev_disable(data);
+ }
+ }
+
+ /* Acknowledge event. */
+ ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_EVENT_OFF,
+ 0);
+ if (ret)
+ goto access_error;
+
+ /* Unmask event. */
+ ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF,
+ item->mask);
+ if (ret)
+ goto access_error;
+
+ return;
+
+access_error:
+ dev_err(priv->dev, "Failed to complete workqueue.\n");
+}
+
+static void
+mlxreg_hotplug_health_work_helper(struct mlxreg_hotplug_priv_data *priv,
+ struct mlxreg_core_item *item)
+{
+ struct mlxreg_core_data *data = item->data;
+ u32 regval;
+ int i, ret;
+
+ for (i = 0; i < item->count; i++, data++) {
+ /* Mask event. */
+ ret = regmap_write(priv->regmap, data->reg +
+ MLXREG_HOTPLUG_MASK_OFF, 0);
+ if (ret)
+ goto access_error;
+
+ /* Read status. */
+ ret = regmap_read(priv->regmap, data->reg, &regval);
+ if (ret)
+ goto access_error;
+
+ regval &= data->mask;
+ item->cache = regval;
+ if (regval == MLXREG_HOTPLUG_HEALTH_MASK) {
+ if ((data->health_cntr++ == MLXREG_HOTPLUG_RST_CNTR) ||
+ !priv->after_probe) {
+ mlxreg_hotplug_dev_enable(data);
+ data->attached = true;
+ }
+ } else {
+ if (data->attached) {
+ mlxreg_hotplug_dev_disable(data);
+ data->attached = false;
+ data->health_cntr = 0;
+ }
+ }
+
+ /* Acknowledge event. */
+ ret = regmap_write(priv->regmap, data->reg +
+ MLXREG_HOTPLUG_EVENT_OFF, 0);
+ if (ret)
+ goto access_error;
+
+ /* Unmask event. */
+ ret = regmap_write(priv->regmap, data->reg +
+ MLXREG_HOTPLUG_MASK_OFF, data->mask);
+ if (ret)
+ goto access_error;
+ }
+
+ return;
+
+access_error:
+ dev_err(priv->dev, "Failed to complete workqueue.\n");
+}
+
+/*
+ * mlxreg_hotplug_work_handler - performs traversing of device interrupt
+ * registers according to the below hierarchy schema:
+ *
+ * Aggregation registers (status/mask)
+ * PSU registers: *---*
+ * *-----------------* | |
+ * |status/event/mask|-----> | * |
+ * *-----------------* | |
+ * Power registers: | |
+ * *-----------------* | |
+ * |status/event/mask|-----> | * |
+ * *-----------------* | |
+ * FAN registers: | |--> CPU
+ * *-----------------* | |
+ * |status/event/mask|-----> | * |
+ * *-----------------* | |
+ * ASIC registers: | |
+ * *-----------------* | |
+ * |status/event/mask|-----> | * |
+ * *-----------------* | |
+ * *---*
+ *
+ * In case some system changed are detected: FAN in/out, PSU in/out, power
+ * cable attached/detached, ASIC helath good/bad, relevant device is created
+ * or destroyed.
+ */
+static void mlxreg_hotplug_work_handler(struct work_struct *work)
+{
+ struct mlxreg_hotplug_priv_data *priv = container_of(work,
+ struct mlxreg_hotplug_priv_data, dwork_irq.work);
+ struct mlxreg_core_hotplug_platform_data *pdata;
+ struct mlxreg_core_item *item;
+ unsigned long flags;
+ u32 regval, aggr_asserted;
+ int i;
+ int ret;
+
+ pdata = dev_get_platdata(&priv->pdev->dev);
+ item = pdata->items;
+ /* Mask aggregation event. */
+ ret = regmap_write(priv->regmap, pdata->cell +
+ MLXREG_HOTPLUG_AGGR_MASK_OFF, 0);
+ if (ret < 0)
+ goto access_error;
+
+ /* Read aggregation status. */
+ ret = regmap_read(priv->regmap, pdata->cell, &regval);
+ if (ret)
+ goto access_error;
+
+ regval &= pdata->mask;
+ aggr_asserted = priv->aggr_cache ^ regval;
+ priv->aggr_cache = regval;
+
+ /* Handle topology and health configuration changes. */
+ for (i = 0; i < pdata->counter; i++, item++) {
+ if (aggr_asserted & item->aggr_mask) {
+ if (item->health)
+ mlxreg_hotplug_health_work_helper(priv, item);
+ else
+ mlxreg_hotplug_work_helper(priv, item);
+ }
+ }
+
+ if (aggr_asserted) {
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /*
+ * It is possible, that some signals have been inserted, while
+ * interrupt has been masked by mlxreg_hotplug_work_handler.
+ * In this case such signals will be missed. In order to handle
+ * these signals delayed work is canceled and work task
+ * re-scheduled for immediate execution. It allows to handle
+ * missed signals, if any. In other case work handler just
+ * validates that no new signals have been received during
+ * masking.
+ */
+ cancel_delayed_work(&priv->dwork_irq);
+ schedule_delayed_work(&priv->dwork_irq, 0);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return;
+ }
+
+ /* Unmask aggregation event (no need acknowledge). */
+ ret = regmap_write(priv->regmap, pdata->cell +
+ MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask);
+ if (ret)
+ goto access_error;
+
+ return;
+
+access_error:
+ dev_err(priv->dev, "Failed to complete workqueue.\n");
+}
+
+static int mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv)
+{
+ struct mlxreg_core_hotplug_platform_data *pdata;
+ struct mlxreg_core_item *item;
+ int i;
+ int ret;
+
+ pdata = dev_get_platdata(&priv->pdev->dev);
+ item = pdata->items;
+
+ for (i = 0; i < pdata->counter; i++, item++) {
+ /* Clear group presense event. */
+ ret = regmap_write(priv->regmap, item->reg +
+ MLXREG_HOTPLUG_EVENT_OFF, 0);
+ if (ret)
+ goto access_error;
+
+ /* Set group initial status as mask and unmask group event. */
+ if (item->inversed) {
+ item->cache = item->mask;
+ ret = regmap_write(priv->regmap, item->reg +
+ MLXREG_HOTPLUG_MASK_OFF,
+ item->mask);
+ if (ret)
+ goto access_error;
+ }
+ }
+
+ /* Keep aggregation initial status as zero and unmask events. */
+ ret = regmap_write(priv->regmap, pdata->cell +
+ MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask);
+ if (ret)
+ goto access_error;
+
+ /* Keep low aggregation initial status as zero and unmask events. */
+ ret = regmap_write(priv->regmap, pdata->cell_low +
+ MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask_low);
+ if (ret)
+ goto access_error;
+
+ /* Invoke work handler for initializing hot plug devices setting. */
+ mlxreg_hotplug_work_handler(&priv->dwork_irq.work);
+
+ enable_irq(priv->irq);
+
+ return 0;
+
+access_error:
+ dev_err(priv->dev, "Failed to set interrupts.\n");
+
+ enable_irq(priv->irq);
+
+ return ret;
+}
+
+static void mlxreg_hotplug_unset_irq(struct mlxreg_hotplug_priv_data *priv)
+{
+ struct mlxreg_core_hotplug_platform_data *pdata;
+ struct mlxreg_core_item *item;
+ struct mlxreg_core_data *data;
+ int count, i, j;
+
+ pdata = dev_get_platdata(&priv->pdev->dev);
+ item = pdata->items;
+ disable_irq(priv->irq);
+ cancel_delayed_work_sync(&priv->dwork_irq);
+
+ /* Mask low aggregation event. */
+ regmap_write(priv->regmap, pdata->cell_low +
+ MLXREG_HOTPLUG_AGGR_MASK_OFF, 0);
+
+ /* Mask aggregation event. */
+ regmap_write(priv->regmap, pdata->cell + MLXREG_HOTPLUG_AGGR_MASK_OFF,
+ 0);
+
+ /* Clear topology configurations. */
+ for (i = 0; i < pdata->counter; i++, item++) {
+ data = item->data;
+ /* Mask group presense event. */
+ regmap_write(priv->regmap, data->reg + MLXREG_HOTPLUG_MASK_OFF,
+ 0);
+ /* Clear group presense event. */
+ regmap_write(priv->regmap, data->reg +
+ MLXREG_HOTPLUG_EVENT_OFF, 0);
+
+ /* Remove all the attached devices in group. */
+ count = item->count;
+ for (j = 0; j < count; j++, data++)
+ mlxreg_hotplug_dev_disable(data);
+ }
+}
+
+static irqreturn_t mlxreg_hotplug_irq_handler(int irq, void *dev)
+{
+ struct mlxreg_hotplug_priv_data *priv =
+ (struct mlxreg_hotplug_priv_data *)dev;
+
+ /* Schedule work task for immediate execution.*/
+ schedule_delayed_work(&priv->dwork_irq, 0);
+
+ return IRQ_HANDLED;
+}
+
+static int mlxreg_hotplug_probe(struct platform_device *pdev)
+{
+ struct mlxreg_core_hotplug_platform_data *pdata;
+ struct mlxreg_hotplug_priv_data *priv;
+ int err;
+
+ pdata = dev_get_platdata(&pdev->dev);
+ if (!pdata) {
+ dev_err(&pdev->dev, "Failed to get platform data.\n");
+ return -EINVAL;
+ }
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ if (pdata->irq) {
+ priv->irq = pdata->irq;
+ } else {
+ priv->irq = platform_get_irq(pdev, 0);
+ if (priv->irq < 0) {
+ dev_err(&pdev->dev, "Failed to get platform irq: %d\n",
+ priv->irq);
+ return priv->irq;
+ }
+ }
+
+ priv->regmap = pdata->regmap;
+ priv->dev = pdev->dev.parent;
+ priv->pdev = pdev;
+
+ err = devm_request_irq(&pdev->dev, priv->irq,
+ mlxreg_hotplug_irq_handler, IRQF_TRIGGER_FALLING
+ | IRQF_SHARED, "mlxreg-hotplug", priv);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to request irq: %d\n", err);
+ return err;
+ }
+
+ disable_irq(priv->irq);
+ spin_lock_init(&priv->lock);
+ INIT_DELAYED_WORK(&priv->dwork_irq, mlxreg_hotplug_work_handler);
+ /* Perform initial interrupts setup. */
+ mlxreg_hotplug_set_irq(priv);
+
+ priv->after_probe = true;
+ dev_set_drvdata(&pdev->dev, priv);
+
+ err = mlxreg_hotplug_attr_init(priv);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to allocate attributes: %d\n",
+ err);
+ return err;
+ }
+
+ priv->hwmon = devm_hwmon_device_register_with_groups(&pdev->dev,
+ "mlxreg_hotplug", priv, priv->groups);
+ if (IS_ERR(priv->hwmon)) {
+ dev_err(&pdev->dev, "Failed to register hwmon device %ld\n",
+ PTR_ERR(priv->hwmon));
+ return PTR_ERR(priv->hwmon);
+ }
+
+ return 0;
+}
+
+static int mlxreg_hotplug_remove(struct platform_device *pdev)
+{
+ struct mlxreg_hotplug_priv_data *priv = dev_get_drvdata(&pdev->dev);
+
+ /* Clean interrupts setup. */
+ mlxreg_hotplug_unset_irq(priv);
+
+ return 0;
+}
+
+static struct platform_driver mlxreg_hotplug_driver = {
+ .driver = {
+ .name = "mlxreg-hotplug",
+ },
+ .probe = mlxreg_hotplug_probe,
+ .remove = mlxreg_hotplug_remove,
+};
+
+module_platform_driver(mlxreg_hotplug_driver);
+
+MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
+MODULE_DESCRIPTION("Mellanox regmap hotplug platform driver");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_ALIAS("platform:mlxreg-hotplug");
diff -Nur a/include/linux/platform_data/mlxreg.h b/include/linux/platform_data/mlxreg.h
--- a/include/linux/platform_data/mlxreg.h 1970-01-01 00:00:00.000000000 +0000
+++ b/include/linux/platform_data/mlxreg.h 2017-11-12 09:04:09.796084101 +0000
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2017 Vadim Pasternak <vadimp@mellanox.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __LINUX_PLATFORM_DATA_MLXREG_H
+#define __LINUX_PLATFORM_DATA_MLXREG_H
+
+#define MLXREG_CORE_LABEL_MAX_SIZE 32
+
+/**
+ * struct mlxreg_hotplug_device - I2C device data:
+ *
+ * @adapter: I2C device adapter;
+ * @client: I2C device client;
+ * @brdinfo: device board information;
+ * @nr: I2C device adapter number, to which device is to be attached;
+ *
+ * Structure represents I2C hotplug device static data (board topology) and
+ * dynamic data (related kernel objects handles).
+ */
+struct mlxreg_hotplug_device {
+ struct i2c_adapter *adapter;
+ struct i2c_client *client;
+ struct i2c_board_info *brdinfo;
+ int nr;
+};
+
+/**
+ * struct mlxreg_core_data - attributes control data:
+ *
+ * @label: attribute label;
+ * @label: attribute register offset;
+ * @reg: attribute register;
+ * @mask: attribute access mask;
+ * @bit: attribute effective bit;
+ * @np - pointer to node platform associated with attribute;
+ * @hpdev - hotplug device data;
+ * @health_cntr: dynamic device health indication counter;
+ * @attached: true if device has been attached after good helath indication;
+ */
+struct mlxreg_core_data {
+ char label[MLXREG_CORE_LABEL_MAX_SIZE];
+ u32 reg;
+ u32 mask;
+ u32 bit;
+ struct device_node *np;
+ struct mlxreg_hotplug_device hpdev;
+ u8 health_cntr;
+ bool attached;
+};
+
+/**
+ * struct mlxreg_core_item - same type components controlled by the driver:
+ *
+ * @data: component data;
+ * @aggr_mask: group aggregation mask;
+ * @reg: group interrupt status register;
+ * @mask: group interrupt mask;
+ * @cache: last status value for elements fro the same group;
+ * @count: number of available elements in the group;
+ * @ind: element's index inside the group;
+ * @inversed: if 0: 0 for signal status is OK, if 1 - 1 is OK;
+ * @health: true if device has health indication, false in other case;
+ */
+struct mlxreg_core_item {
+ struct mlxreg_core_data *data;
+ u32 aggr_mask;
+ u32 reg;
+ u32 mask;
+ u32 cache;
+ u8 count;
+ u8 ind;
+ u8 inversed;
+ u8 health;
+};
+
+/**
+ * struct mlxreg_core_led_platform_data - led platform data:
+ *
+ * @led_data: led private data;
+ * @regmap: register map of parent device;
+ * @counter: number of led instances;
+ */
+struct mlxreg_core_led_platform_data {
+ struct mlxreg_core_data *data;
+ void *regmap;
+ int counter;
+};
+
+/**
+ * struct mlxreg_core_hotplug_platform_data - hotplug platform data:
+ *
+ * @items: same type components with the hotplug capability;
+ * @irq: platform interrupt number;
+ * @regmap: register map of parent device;
+ * @counter: number of the components with the hotplug capability;
+ * @cell: location of top aggregation interrupt register;
+ * @mask: top aggregation interrupt common mask;
+ * @cell_low: location of low aggregation interrupt register;
+ * @mask_low: low aggregation interrupt common mask;
+ */
+struct mlxreg_core_hotplug_platform_data {
+ struct mlxreg_core_item *items;
+ int irq;
+ void *regmap;
+ int counter;
+ u32 cell;
+ u32 mask;
+ u32 cell_low;
+ u32 mask_low;
+};
+
+#endif /* __LINUX_PLATFORM_DATA_MLXREG_H */

View File

@@ -0,0 +1,398 @@
Linux backport patch. Includes following commits:
7dc37aeb560416771cbdc286357157c7565dc1fe
9244ef4cb79a8411656cb8fc2366f32f2294a0c9
daf155fe70c9d69c28bba632b6a758ac8feab6e7
diff -Nur a/drivers/leds/Kconfig b/drivers/leds/Kconfig
--- a/drivers/leds/Kconfig 2017-11-12 09:08:40.740087699 +0000
+++ b/drivers/leds/Kconfig 2017-11-12 09:06:54.580086289 +0000
@@ -659,6 +659,35 @@
This option enabled support for the LEDs on the Mellanox
boards. Say Y to enabled these.
+config LEDS_MLXREG
+ tristate "LED support for the Mellanox BMC cards"
+ depends on LEDS_CLASS
+ help
+ This option enabled support for the LEDs on the Mellanox BMC cards.
+ The driver can be activated from the device tree or by the direct
+ platform device add call. Say Y to enabled these. To compile this
+ driver as a module, choose 'M' here: the module will be called
+ leds-mlxreg.
+
+config LEDS_USER
+ tristate "Userspace LED support"
+ depends on LEDS_CLASS
+ help
+ This option enables support for userspace LEDs. Say 'y' to enable this
+ support in kernel. To compile this driver as a module, choose 'm' here:
+ the module will be called uleds.
+
+config LEDS_NIC78BX
+ tristate "LED support for NI PXI NIC78bx devices"
+ depends on LEDS_CLASS
+ depends on X86 && ACPI
+ help
+ This option enables support for the User1 and User2 LEDs on NI
+ PXI NIC78bx devices.
+
+ To compile this driver as a module, choose M here: the module
+ will be called leds-nic78bx.
+
comment "LED Triggers"
source "drivers/leds/trigger/Kconfig"
diff -Nur a/drivers/leds/Makefile b/drivers/leds/Makefile
--- a/drivers/leds/Makefile 2017-11-12 09:08:40.740087699 +0000
+++ b/drivers/leds/Makefile 2017-11-12 09:06:54.580086289 +0000
@@ -71,6 +71,7 @@
obj-$(CONFIG_LEDS_IS31FL32XX) += leds-is31fl32xx.o
obj-$(CONFIG_LEDS_PM8058) += leds-pm8058.o
obj-$(CONFIG_LEDS_MLXCPLD) += leds-mlxcpld.o
+obj-$(CONFIG_LEDS_MLXREG) += leds-mlxreg.o
# LED SPI Drivers
obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
diff -Nur a/drivers/leds/leds-mlxcpld.c b/drivers/leds/leds-mlxcpld.c
--- a/drivers/leds/leds-mlxcpld.c 2017-11-12 09:08:40.740087699 +0000
+++ b/drivers/leds/leds-mlxcpld.c 2017-11-12 09:08:05.620087233 +0000
@@ -400,6 +400,9 @@
struct platform_device *pdev;
int err;
+ if (!dmi_match(DMI_CHASSIS_VENDOR, "Mellanox Technologies Ltd."))
+ return -ENODEV;
+
pdev = platform_device_register_simple(KBUILD_MODNAME, -1, NULL, 0);
if (IS_ERR(pdev)) {
pr_err("Device allocation failed\n");
@@ -426,5 +429,5 @@
MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
MODULE_DESCRIPTION("Mellanox board LED driver");
-MODULE_LICENSE("GPL v2");
+MODULE_LICENSE("Dual BSD/GPL");
MODULE_ALIAS("platform:leds_mlxcpld");
diff -Nur a/drivers/leds/leds-mlxreg.c b/drivers/leds/leds-mlxreg.c
--- a/drivers/leds/leds-mlxreg.c 1970-01-01 00:00:00.000000000 +0000
+++ b/drivers/leds/leds-mlxreg.c 2017-11-12 09:06:54.580086289 +0000
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2017 Vadim Pasternak <vadimp@mellanox.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the names of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_data/mlxreg.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+/* Codes for LEDs. */
+#define MLXREG_LED_OFFSET_BLINK_3HZ 0x01 /* Offset from solid: 3Hz blink */
+#define MLXREG_LED_OFFSET_BLINK_6HZ 0x02 /* Offset from solid: 6Hz blink */
+#define MLXREG_LED_IS_OFF 0x00 /* Off */
+#define MLXREG_LED_RED_SOLID 0x05 /* Solid red */
+#define MLXREG_LED_GREEN_SOLID 0x0D /* Solid green */
+#define MLXREG_LED_AMBER_SOLID 0x09 /* Solid amber */
+#define MLXREG_LED_BLINK_3HZ 167 /* ~167 msec off/on - HW support */
+#define MLXREG_LED_BLINK_6HZ 83 /* ~83 msec off/on - HW support */
+
+/**
+ * struct mlxreg_led_data - led control data:
+ *
+ * @data: led configuration data;
+ * @led_classdev: led class data;
+ * @base_color: base led color (other colors have constant offset from base);
+ * @led_data: led data;
+ * @data_parent: pointer to private device control data of parent;
+ */
+struct mlxreg_led_data {
+ struct mlxreg_core_data *data;
+ struct led_classdev led_cdev;
+ u8 base_color;
+ void *data_parent;
+ char led_cdev_name[MLXREG_CORE_LABEL_MAX_SIZE];
+};
+
+#define cdev_to_priv(c) container_of(c, struct mlxreg_led_data, led_cdev)
+
+/**
+ * struct mlxreg_led_priv_data - platform private data:
+ *
+ * @pdev: platform device;
+ * @pdata: platform data;
+ * @access_lock: mutex for attribute IO access;
+ */
+struct mlxreg_led_priv_data {
+ struct platform_device *pdev;
+ struct mlxreg_core_led_platform_data *pdata;
+ struct mutex access_lock; /* protect IO operations */
+};
+
+static int
+mlxreg_led_store_hw(struct mlxreg_led_data *led_data, u8 vset)
+{
+ struct mlxreg_led_priv_data *priv = led_data->data_parent;
+ struct mlxreg_core_led_platform_data *led_pdata = priv->pdata;
+ struct mlxreg_core_data *data = led_data->data;
+ u32 regval;
+ u32 nib;
+ int ret;
+
+ /*
+ * Each LED is controlled through low or high nibble of the relevant
+ * register byte. Register offset is specified by off parameter.
+ * Parameter vset provides color code: 0x0 for off, 0x5 for solid red,
+ * 0x6 for 3Hz blink red, 0xd for solid green, 0xe for 3Hz blink
+ * green.
+ * Parameter mask specifies which nibble is used for specific LED: mask
+ * 0xf0 - lower nibble is to be used (bits from 0 to 3), mask 0x0f -
+ * higher nibble (bits from 4 to 7).
+ */
+ mutex_lock(&priv->access_lock);
+
+ ret = regmap_read(led_pdata->regmap, data->reg, &regval);
+ if (ret)
+ goto access_error;
+
+ nib = (ror32(data->mask, data->bit) == 0xf0) ? rol32(vset, data->bit) :
+ rol32(vset, data->bit + 4);
+ regval = (regval & data->mask) | nib;
+
+ ret = regmap_write(led_pdata->regmap, data->reg, regval);
+
+access_error:
+ mutex_unlock(&priv->access_lock);
+
+ return ret;
+}
+
+static enum led_brightness
+mlxreg_led_get_hw(struct mlxreg_led_data *led_data)
+{
+ struct mlxreg_led_priv_data *priv = led_data->data_parent;
+ struct mlxreg_core_led_platform_data *led_pdata = priv->pdata;
+ struct mlxreg_core_data *data = led_data->data;
+ u32 regval;
+ int ret;
+
+ /*
+ * Each LED is controlled through low or high nibble of the relevant
+ * register byte. Register offset is specified by off parameter.
+ * Parameter vset provides color code: 0x0 for off, 0x5 for solid red,
+ * 0x6 for 3Hz blink red, 0xd for solid green, 0xe for 3Hz blink
+ * green.
+ * Parameter mask specifies which nibble is used for specific LED: mask
+ * 0xf0 - lower nibble is to be used (bits from 0 to 3), mask 0x0f -
+ * higher nibble (bits from 4 to 7).
+ */
+ ret = regmap_read(led_pdata->regmap, data->reg, &regval);
+ if (ret < 0) {
+ dev_warn(led_data->led_cdev.dev, "Failed to get current brightness, error: %d\n",
+ ret);
+ /* Assume the LED is OFF */
+ return LED_OFF;
+ }
+
+ regval = regval & ~data->mask;
+ regval = (ror32(data->mask, data->bit) == 0xf0) ? ror32(regval,
+ data->bit) : ror32(regval, data->bit + 4);
+ if (regval >= led_data->base_color &&
+ regval <= (led_data->base_color + MLXREG_LED_OFFSET_BLINK_6HZ))
+ ret = LED_FULL;
+ else
+ ret = LED_OFF;
+
+ return ret;
+}
+
+static int
+mlxreg_led_brightness_set(struct led_classdev *cled, enum led_brightness value)
+{
+ struct mlxreg_led_data *led_data = cdev_to_priv(cled);
+
+ if (value)
+ return mlxreg_led_store_hw(led_data, led_data->base_color);
+ else
+ return mlxreg_led_store_hw(led_data, MLXREG_LED_IS_OFF);
+}
+
+static enum led_brightness
+mlxreg_led_brightness_get(struct led_classdev *cled)
+{
+ struct mlxreg_led_data *led_data = cdev_to_priv(cled);
+
+ return mlxreg_led_get_hw(led_data);
+}
+
+static int
+mlxreg_led_blink_set(struct led_classdev *cled, unsigned long *delay_on,
+ unsigned long *delay_off)
+{
+ struct mlxreg_led_data *led_data = cdev_to_priv(cled);
+ int err;
+
+ /*
+ * HW supports two types of blinking: full (6Hz) and half (3Hz).
+ * For delay on/off zero LED is setting to solid color. For others
+ * combination blinking is to be controlled by the software timer.
+ */
+ if (!(*delay_on == 0 && *delay_off == 0) &&
+ !(*delay_on == MLXREG_LED_BLINK_3HZ &&
+ *delay_off == MLXREG_LED_BLINK_3HZ) &&
+ !(*delay_on == MLXREG_LED_BLINK_6HZ &&
+ *delay_off == MLXREG_LED_BLINK_6HZ))
+ return -EINVAL;
+
+ if (*delay_on == MLXREG_LED_BLINK_6HZ)
+ err = mlxreg_led_store_hw(led_data, led_data->base_color +
+ MLXREG_LED_OFFSET_BLINK_6HZ);
+ else if (*delay_on == MLXREG_LED_BLINK_3HZ)
+ err = mlxreg_led_store_hw(led_data, led_data->base_color +
+ MLXREG_LED_OFFSET_BLINK_3HZ);
+ else
+ err = mlxreg_led_store_hw(led_data, led_data->base_color);
+
+ return err;
+}
+
+static int mlxreg_led_config(struct mlxreg_led_priv_data *priv)
+{
+ struct mlxreg_core_led_platform_data *led_pdata = priv->pdata;
+ struct mlxreg_core_data *data = led_pdata->data;
+ struct mlxreg_led_data *led_data;
+ struct led_classdev *led_cdev;
+ int brightness;
+ int i;
+ int err;
+
+ for (i = 0; i < led_pdata->counter; i++, data++) {
+ led_data = devm_kzalloc(&priv->pdev->dev, sizeof(*led_data),
+ GFP_KERNEL);
+ if (!led_data)
+ return -ENOMEM;
+
+ led_cdev = &led_data->led_cdev;
+ led_data->data_parent = priv;
+ if (strstr(data->label, "red") ||
+ strstr(data->label, "orange")) {
+ brightness = LED_OFF;
+ led_data->base_color = MLXREG_LED_RED_SOLID;
+ } else if (strstr(data->label, "amber")) {
+ brightness = LED_OFF;
+ led_data->base_color = MLXREG_LED_AMBER_SOLID;
+ } else {
+ brightness = LED_OFF;
+ led_data->base_color = MLXREG_LED_GREEN_SOLID;
+ }
+ sprintf(led_data->led_cdev_name, "%s:%s", "mlxreg",
+ data->label);
+ led_cdev->name = led_data->led_cdev_name;
+ led_cdev->brightness = brightness;
+ led_cdev->max_brightness = 1;
+ led_cdev->brightness_set_blocking =
+ mlxreg_led_brightness_set;
+ led_cdev->brightness_get = mlxreg_led_brightness_get;
+ led_cdev->blink_set = mlxreg_led_blink_set;
+ led_cdev->flags = LED_CORE_SUSPENDRESUME;
+ led_data->data = data;
+ err = devm_led_classdev_register(&priv->pdev->dev, led_cdev);
+ if (err)
+ return err;
+
+ if (led_cdev->brightness)
+ mlxreg_led_brightness_set(led_cdev,
+ led_cdev->brightness);
+ dev_info(led_cdev->dev, "label: %s, mask: 0x%02x, offset:0x%02x\n",
+ data->label, data->mask, data->reg);
+ }
+
+ return 0;
+}
+
+static int mlxreg_led_probe(struct platform_device *pdev)
+{
+ struct mlxreg_core_led_platform_data *led_pdata;
+ struct mlxreg_led_priv_data *priv;
+
+ led_pdata = dev_get_platdata(&pdev->dev);
+ if (!led_pdata) {
+ dev_err(&pdev->dev, "Failed to get platform data.\n");
+ return -EINVAL;
+ }
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ mutex_init(&priv->access_lock);
+ priv->pdev = pdev;
+ priv->pdata = led_pdata;
+
+ return mlxreg_led_config(priv);
+}
+
+static int mlxreg_led_remove(struct platform_device *pdev)
+{
+ struct mlxreg_led_priv_data *priv = dev_get_drvdata(&pdev->dev);
+
+ mutex_destroy(&priv->access_lock);
+
+ return 0;
+}
+
+static const struct of_device_id mlxreg_led_dt_match[] = {
+ { .compatible = "mellanox,leds-mlxreg" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, mlxreg_led_dt_match);
+
+static struct platform_driver mlxreg_led_driver = {
+ .driver = {
+ .name = "leds-mlxreg",
+ .of_match_table = of_match_ptr(mlxreg_led_dt_match),
+ },
+ .probe = mlxreg_led_probe,
+ .remove = mlxreg_led_remove,
+};
+
+module_platform_driver(mlxreg_led_driver);
+
+MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
+MODULE_DESCRIPTION("Mellanox LED regmap driver");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_ALIAS("platform:leds-mlxreg");

View File

@@ -0,0 +1,30 @@
Linux backport patch. Includes following commits:
a4dffccb72a7fa46bb0d7f29e607375387e09956
diff -Nur a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h
--- a/drivers/hwmon/pmbus/pmbus.h 2017-11-09 16:25:22.760993964 +0000
+++ b/drivers/hwmon/pmbus/pmbus.h 2017-11-09 16:26:02.568994492 +0000
@@ -341,7 +341,7 @@
#define PMBUS_HAVE_STATUS_VMON BIT(19)
enum pmbus_data_format { linear = 0, direct, vid };
-enum vrm_version { vr11 = 0, vr12 };
+enum vrm_version { vr11 = 0, vr12, vr13 };
struct pmbus_driver_info {
int pages; /* Total number of pages */
diff -Nur a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
--- a/drivers/hwmon/pmbus/pmbus_core.c 2017-11-09 16:25:22.760993964 +0000
+++ b/drivers/hwmon/pmbus/pmbus_core.c 2017-11-09 16:26:02.568994492 +0000
@@ -531,6 +531,10 @@
if (val >= 0x01)
rv = 250 + (val - 1) * 5;
break;
+ case vr13:
+ if (val >= 0x01)
+ rv = 500 + (val - 1) * 10;
+ break;
}
return rv;
}

View File

@@ -0,0 +1,151 @@
Linux backport patch. Includes following commits:
f7caf758e26ab84b2b9def9ec68235c85d645597
diff -Nur a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig
--- a/drivers/hwmon/pmbus/Kconfig 2017-11-09 16:34:05.269000902 +0000
+++ b/drivers/hwmon/pmbus/Kconfig 2017-11-09 16:35:49.701002288 +0000
@@ -125,6 +125,15 @@
This driver can also be built as a module. If so, the module will
be called tps40422.
+config SENSORS_TPS53679
+ tristate "TI TPS53679"
+ help
+ If you say yes here you get hardware monitoring support for TI
+ TPS53679.
+
+ This driver can also be built as a module. If so, the module will
+ be called tps53679.
+
config SENSORS_UCD9000
tristate "TI UCD90120, UCD90124, UCD90160, UCD9090, UCD90910"
default n
diff -Nur a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile
--- a/drivers/hwmon/pmbus/Makefile 2017-11-09 16:34:05.269000902 +0000
+++ b/drivers/hwmon/pmbus/Makefile 2017-11-09 16:35:49.701002288 +0000
@@ -13,6 +13,7 @@
obj-$(CONFIG_SENSORS_MAX34440) += max34440.o
obj-$(CONFIG_SENSORS_MAX8688) += max8688.o
obj-$(CONFIG_SENSORS_TPS40422) += tps40422.o
+obj-$(CONFIG_SENSORS_TPS53679) += tps53679.o
obj-$(CONFIG_SENSORS_UCD9000) += ucd9000.o
obj-$(CONFIG_SENSORS_UCD9200) += ucd9200.o
obj-$(CONFIG_SENSORS_ZL6100) += zl6100.o
diff -Nur a/drivers/hwmon/pmbus/tps53679.c b/drivers/hwmon/pmbus/tps53679.c
--- a/drivers/hwmon/pmbus/tps53679.c 1970-01-01 00:00:00.000000000 +0000
+++ b/drivers/hwmon/pmbus/tps53679.c 2017-11-09 16:35:49.701002288 +0000
@@ -0,0 +1,113 @@
+/*
+ * Hardware monitoring driver for Texas Instruments TPS53679
+ *
+ * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2017 Vadim Pasternak <vadimp@mellanox.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include "pmbus.h"
+
+#define TPS53679_PROT_VR12_5MV 0x01 /* VR12.0 mode, 5-mV DAC */
+#define TPS53679_PROT_VR12_5_10MV 0x02 /* VR12.5 mode, 10-mV DAC */
+#define TPS53679_PROT_VR13_10MV 0x04 /* VR13.0 mode, 10-mV DAC */
+#define TPS53679_PROT_IMVP8_5MV 0x05 /* IMVP8 mode, 5-mV DAC */
+#define TPS53679_PROT_VR13_5MV 0x07 /* VR13.0 mode, 5-mV DAC */
+#define TPS53679_PAGE_NUM 2
+
+static int tps53679_identify(struct i2c_client *client,
+ struct pmbus_driver_info *info)
+{
+ u8 vout_params;
+ int ret;
+
+ /* Read the register with VOUT scaling value.*/
+ ret = pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE);
+ if (ret < 0)
+ return ret;
+
+ vout_params = ret & GENMASK(4, 0);
+
+ switch (vout_params) {
+ case TPS53679_PROT_VR13_10MV:
+ case TPS53679_PROT_VR12_5_10MV:
+ info->vrm_version = vr13;
+ break;
+ case TPS53679_PROT_VR13_5MV:
+ case TPS53679_PROT_VR12_5MV:
+ case TPS53679_PROT_IMVP8_5MV:
+ info->vrm_version = vr12;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct pmbus_driver_info tps53679_info = {
+ .pages = TPS53679_PAGE_NUM,
+ .format[PSC_VOLTAGE_IN] = linear,
+ .format[PSC_VOLTAGE_OUT] = vid,
+ .format[PSC_TEMPERATURE] = linear,
+ .format[PSC_CURRENT_OUT] = linear,
+ .format[PSC_POWER] = linear,
+ .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
+ PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
+ PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP |
+ PMBUS_HAVE_POUT,
+ .func[1] = PMBUS_HAVE_VIN | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT |
+ PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT |
+ PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP |
+ PMBUS_HAVE_POUT,
+ .identify = tps53679_identify,
+};
+
+static int tps53679_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ return pmbus_do_probe(client, id, &tps53679_info);
+}
+
+static const struct i2c_device_id tps53679_id[] = {
+ {"tps53679", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, tps53679_id);
+
+static const struct of_device_id tps53679_of_match[] = {
+ {.compatible = "ti,tps53679"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, tps53679_of_match);
+
+static struct i2c_driver tps53679_driver = {
+ .driver = {
+ .name = "tps53679",
+ .of_match_table = of_match_ptr(tps53679_of_match),
+ },
+ .probe = tps53679_probe,
+ .remove = pmbus_do_remove,
+ .id_table = tps53679_id,
+};
+
+module_i2c_driver(tps53679_driver);
+
+MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
+MODULE_DESCRIPTION("PMBus driver for Texas Instruments TPS53679");
+MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,685 @@
From 2c7476ab57dd42d8cba6c417ff32a77252964858 Mon Sep 17 00:00:00 2001
From: Vadim Pasternak <vadimp@mellanox.com>
Date: Thu, 16 Nov 2017 17:22:56 +0000
Subject: [v4.9 backport 38/38] platform: mellonox: introduce mlxreg-io driver
and add driver activation to mlx-platform
Patch introduces new module mlxreg-io, which exposes the registers of the
programmable devices, equipped on Melanox systems to sysfs. These are the
registers, which are used for system resets operation, system reset causes
monitoring, select operation and version info.
Signed-off-by: Vadim Pasternak <vadimp@mellanox.com>
---
drivers/leds/leds-mlxreg.c | 10 +-
drivers/platform/mellanox/Kconfig | 11 ++
drivers/platform/mellanox/Makefile | 1 +
drivers/platform/mellanox/mlxreg-io.c | 211 ++++++++++++++++++++++++++++++++++
drivers/platform/x86/mlx-platform.c | 193 +++++++++++++++++++++++++++++--
include/linux/platform_data/mlxreg.h | 6 +-
6 files changed, 418 insertions(+), 14 deletions(-)
create mode 100644 drivers/platform/mellanox/mlxreg-io.c
diff --git a/drivers/leds/leds-mlxreg.c b/drivers/leds/leds-mlxreg.c
index a932f20..036c214 100644
--- a/drivers/leds/leds-mlxreg.c
+++ b/drivers/leds/leds-mlxreg.c
@@ -79,7 +79,7 @@ struct mlxreg_led_data {
*/
struct mlxreg_led_priv_data {
struct platform_device *pdev;
- struct mlxreg_core_led_platform_data *pdata;
+ struct mlxreg_core_platform_data *pdata;
struct mutex access_lock; /* protect IO operations */
};
@@ -87,7 +87,7 @@ static int
mlxreg_led_store_hw(struct mlxreg_led_data *led_data, u8 vset)
{
struct mlxreg_led_priv_data *priv = led_data->data_parent;
- struct mlxreg_core_led_platform_data *led_pdata = priv->pdata;
+ struct mlxreg_core_platform_data *led_pdata = priv->pdata;
struct mlxreg_core_data *data = led_data->data;
u32 regval;
u32 nib;
@@ -125,7 +125,7 @@ static enum led_brightness
mlxreg_led_get_hw(struct mlxreg_led_data *led_data)
{
struct mlxreg_led_priv_data *priv = led_data->data_parent;
- struct mlxreg_core_led_platform_data *led_pdata = priv->pdata;
+ struct mlxreg_core_platform_data *led_pdata = priv->pdata;
struct mlxreg_core_data *data = led_data->data;
u32 regval;
int ret;
@@ -212,7 +212,7 @@ mlxreg_led_blink_set(struct led_classdev *cled, unsigned long *delay_on,
static int mlxreg_led_config(struct mlxreg_led_priv_data *priv)
{
- struct mlxreg_core_led_platform_data *led_pdata = priv->pdata;
+ struct mlxreg_core_platform_data *led_pdata = priv->pdata;
struct mlxreg_core_data *data = led_pdata->data;
struct mlxreg_led_data *led_data;
struct led_classdev *led_cdev;
@@ -266,7 +266,7 @@ static int mlxreg_led_config(struct mlxreg_led_priv_data *priv)
static int mlxreg_led_probe(struct platform_device *pdev)
{
- struct mlxreg_core_led_platform_data *led_pdata;
+ struct mlxreg_core_platform_data *led_pdata;
struct mlxreg_led_priv_data *priv;
led_pdata = dev_get_platdata(&pdev->dev);
diff --git a/drivers/platform/mellanox/Kconfig b/drivers/platform/mellanox/Kconfig
index b197cc1..5c6dc29 100644
--- a/drivers/platform/mellanox/Kconfig
+++ b/drivers/platform/mellanox/Kconfig
@@ -22,4 +22,15 @@ config MLXREG_HOTPLUG
This driver handles hot-plug events for the power suppliers, power
cables and fans on the wide range Mellanox IB and Ethernet systems.
+config MLXREG_IO
+ tristate "Mellanox platform register driver support"
+ depends on REGMAP
+ depends on HWMON
+ ---help---
+ This driver allows access to Mellanox programmable device register
+ space trough sysfs interface. The set of registers for sysfs access
+ are defined per system type bases and includes the registers related
+ to system resets operation, system reset causes monitoring and some
+ kinds of mux selection.
+
endif # MELLANOX_PLATFORM
diff --git a/drivers/platform/mellanox/Makefile b/drivers/platform/mellanox/Makefile
index f58d089..b9a2692 100644
--- a/drivers/platform/mellanox/Makefile
+++ b/drivers/platform/mellanox/Makefile
@@ -1 +1,2 @@
obj-$(CONFIG_MLXREG_HOTPLUG) += mlxreg-hotplug.o
+obj-$(CONFIG_MLXREG_IO) += mlxreg-io.o
diff --git a/drivers/platform/mellanox/mlxreg-io.c b/drivers/platform/mellanox/mlxreg-io.c
new file mode 100644
index 0000000..f7434ca
--- /dev/null
+++ b/drivers/platform/mellanox/mlxreg-io.c
@@ -0,0 +1,211 @@
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_data/mlxreg.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+/* Attribute parameters. */
+#define MLXREG_IO_ATT_SIZE 10
+#define MLXREG_IO_ATT_NUM 48
+
+/**
+ * struct mlxreg_io_priv_data - driver's private data:
+ *
+ * @pdev: platform device;
+ * @pdata: platform data;
+ * @hwmon: hwmon device;
+ * @mlxreg_io_attr: sysfs attributes array;
+ * @mlxreg_io_dev_attr: sysfs sensor device attribute array;
+ * @group: sysfs attribute group;
+ * @groups: list of sysfs attribute group for hwmon registration;
+ */
+struct mlxreg_io_priv_data {
+ struct platform_device *pdev;
+ struct mlxreg_core_platform_data *pdata;
+ struct device *hwmon;
+ struct attribute *mlxreg_io_attr[MLXREG_IO_ATT_NUM + 1];
+ struct sensor_device_attribute mlxreg_io_dev_attr[MLXREG_IO_ATT_NUM];
+ struct attribute_group group;
+ const struct attribute_group *groups[2];
+};
+
+static ssize_t
+mlxreg_io_attr_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct mlxreg_io_priv_data *priv = dev_get_drvdata(dev);
+ int index = to_sensor_dev_attr(attr)->index;
+ struct mlxreg_core_data *data = priv->pdata->data + index;
+ u32 regval = 0;
+ int ret;
+
+ ret = regmap_read(priv->pdata->regmap, data->reg, &regval);
+ if (ret)
+ goto access_error;
+
+ if (!data->bit)
+ regval = !!(regval & ~data->mask);
+
+ return sprintf(buf, "%u\n", regval);
+
+access_error:
+ return ret;
+}
+
+static ssize_t
+mlxreg_io_attr_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct mlxreg_io_priv_data *priv = dev_get_drvdata(dev);
+ int index = to_sensor_dev_attr(attr)->index;
+ struct mlxreg_core_data *data = priv->pdata->data + index;
+ u32 val, regval;
+ int ret;
+
+ ret = kstrtou32(buf, MLXREG_IO_ATT_SIZE, &val);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(priv->pdata->regmap, data->reg, &regval);
+ if (ret)
+ goto access_error;
+
+ regval &= data->mask;
+
+ val = !!val;
+ if (val)
+ regval |= ~data->mask;
+ else
+ regval &= data->mask;
+
+ ret = regmap_write(priv->pdata->regmap, data->reg, regval);
+ if (ret)
+ goto access_error;
+
+ return len;
+
+access_error:
+ dev_err(&priv->pdev->dev, "Bus access error\n");
+ return ret;
+}
+
+static int mlxreg_io_attr_init(struct mlxreg_io_priv_data *priv)
+{
+ int i;
+
+ priv->group.attrs = devm_kzalloc(&priv->pdev->dev,
+ priv->pdata->counter *
+ sizeof(struct attribute *),
+ GFP_KERNEL);
+ if (!priv->group.attrs)
+ return -ENOMEM;
+
+ for (i = 0; i < priv->pdata->counter; i++) {
+ priv->mlxreg_io_attr[i] =
+ &priv->mlxreg_io_dev_attr[i].dev_attr.attr;
+
+ /* Set attribute name as a label. */
+ priv->mlxreg_io_attr[i]->name =
+ devm_kasprintf(&priv->pdev->dev, GFP_KERNEL,
+ priv->pdata->data[i].label);
+
+ if (!priv->mlxreg_io_attr[i]->name) {
+ dev_err(&priv->pdev->dev, "Memory allocation failed for sysfs attribute %d.\n",
+ i + 1);
+ return -ENOMEM;
+ }
+
+ priv->mlxreg_io_dev_attr[i].dev_attr.attr.mode =
+ priv->pdata->data[i].mode;
+ switch (priv->pdata->data[i].mode) {
+ case 0200:
+ priv->mlxreg_io_dev_attr[i].dev_attr.store =
+ mlxreg_io_attr_store;
+ break;
+
+ case 0444:
+ priv->mlxreg_io_dev_attr[i].dev_attr.show =
+ mlxreg_io_attr_show;
+ break;
+
+ case 0644:
+ priv->mlxreg_io_dev_attr[i].dev_attr.show =
+ mlxreg_io_attr_show;
+ priv->mlxreg_io_dev_attr[i].dev_attr.store =
+ mlxreg_io_attr_store;
+ break;
+
+ default:
+ dev_err(&priv->pdev->dev, "Bad access mode %u for attribute %s.\n",
+ priv->pdata->data[i].mode,
+ priv->mlxreg_io_attr[i]->name);
+ return -EINVAL;
+ }
+
+ priv->mlxreg_io_dev_attr[i].dev_attr.attr.name =
+ priv->mlxreg_io_attr[i]->name;
+ priv->mlxreg_io_dev_attr[i].index = i;
+ sysfs_attr_init(&priv->mlxreg_io_dev_attr[i].dev_attr.attr);
+ }
+
+ priv->group.attrs = priv->mlxreg_io_attr;
+ priv->groups[0] = &priv->group;
+ priv->groups[1] = NULL;
+
+ return 0;
+}
+
+static int mlxreg_io_probe(struct platform_device *pdev)
+{
+ struct mlxreg_io_priv_data *priv;
+ int err;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->pdata = dev_get_platdata(&pdev->dev);
+ if (!priv->pdata) {
+ dev_err(&pdev->dev, "Failed to get platform data.\n");
+ return -EINVAL;
+ }
+
+ priv->pdev = pdev;
+
+ err = mlxreg_io_attr_init(priv);
+ if (err) {
+ dev_err(&priv->pdev->dev, "Failed to allocate attributes: %d\n",
+ err);
+ return err;
+ }
+
+ priv->hwmon = devm_hwmon_device_register_with_groups(&pdev->dev,
+ "mlxreg_io", priv, priv->groups);
+ if (IS_ERR(priv->hwmon)) {
+ dev_err(&pdev->dev, "Failed to register hwmon device %ld\n",
+ PTR_ERR(priv->hwmon));
+ return PTR_ERR(priv->hwmon);
+ }
+
+ dev_set_drvdata(&pdev->dev, priv);
+
+ return 0;
+}
+
+static struct platform_driver mlxreg_io_driver = {
+ .driver = {
+ .name = "mlxreg-io",
+ },
+ .probe = mlxreg_io_probe,
+};
+
+module_platform_driver(mlxreg_io_driver);
+
+MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
+MODULE_DESCRIPTION("Mellanox regmap I/O access driver");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_ALIAS("platform:mlxreg-io");
diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c
index 49721c2..61cbe35 100644
--- a/drivers/platform/x86/mlx-platform.c
+++ b/drivers/platform/x86/mlx-platform.c
@@ -47,16 +47,31 @@
/* LPC bus IO offsets */
#define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR 0x2000
#define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500
+#define MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFF 0x00
+#define MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFF 0x01
+#define MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF 0x1d
#define MLXPLAT_CPLD_LPC_REG_LED1_OFF 0x20
#define MLXPLAT_CPLD_LPC_REG_LED2_OFF 0x21
#define MLXPLAT_CPLD_LPC_REG_LED3_OFF 0x22
#define MLXPLAT_CPLD_LPC_REG_LED4_OFF 0x23
#define MLXPLAT_CPLD_LPC_REG_LED5_OFF 0x24
+#define MLXPLAT_CPLD_LPC_REG_GP1_OFF 0x30
+#define MLXPLAT_CPLD_LPC_REG_WP1_OFF 0x31
+#define MLXPLAT_CPLD_LPC_REG_GP2_OFF 0x32
+#define MLXPLAT_CPLD_LPC_REG_WP2_OFF 0x33
#define MLXPLAT_CPLD_LPC_REG_AGGR_OFF 0x3a
+#define MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFF 0x3b
#define MLXPLAT_CPLD_LPC_REG_AGGR_LOW_OFF 0x40
+#define MLXPLAT_CPLD_LPC_REG_AGGR_LOW_MASK_OFF 0x41
#define MLXPLAT_CPLD_LPC_REG_PSU_OFF 0x58
+#define MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFF 0x59
+#define MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFF 0x5a
#define MLXPLAT_CPLD_LPC_REG_PWR_OFF 0x64
+#define MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFF 0x65
+#define MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFF 0x66
#define MLXPLAT_CPLD_LPC_REG_FAN_OFF 0x88
+#define MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFF 0x89
+#define MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFF 0x8a
#define MLXPLAT_CPLD_LPC_IO_RANGE 0x100
#define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb
#define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda
@@ -100,12 +115,14 @@
* @pdev_mux - array of mux platform devices
* @pdev_hotplug - hotplug platform devices
* @pdev_led - led platform devices
+ * @pdev_io_regs - register access platform devices
*/
struct mlxplat_priv {
struct platform_device *pdev_i2c;
struct platform_device *pdev_mux[MLXPLAT_CPLD_LPC_MUX_DEVS];
struct platform_device *pdev_hotplug;
struct platform_device *pdev_led;
+ struct platform_device *pdev_io_regs;
};
/* Regions for LPC I2C controller and LPC base register space */
@@ -643,7 +660,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_led_data[] = {
},
};
-static struct mlxreg_core_led_platform_data mlxplat_default_led_data = {
+static struct mlxreg_core_platform_data mlxplat_default_led_data = {
.data = mlxplat_mlxcpld_default_led_data,
.counter = ARRAY_SIZE(mlxplat_mlxcpld_default_led_data),
};
@@ -697,7 +714,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_led_data[] = {
},
};
-static struct mlxreg_core_led_platform_data mlxplat_msn21xx_led_data = {
+static struct mlxreg_core_platform_data mlxplat_msn21xx_led_data = {
.data = mlxplat_mlxcpld_msn21xx_led_data,
.counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_led_data),
};
@@ -786,11 +803,105 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_led_data[] = {
},
};
-static struct mlxreg_core_led_platform_data mlxplat_default_ng_led_data = {
+static struct mlxreg_core_platform_data mlxplat_default_ng_led_data = {
.data = mlxplat_mlxcpld_default_ng_led_data,
.counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_led_data),
};
+static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MLXPLAT_CPLD_LPC_REG_LED1_OFF:
+ case MLXPLAT_CPLD_LPC_REG_LED2_OFF:
+ case MLXPLAT_CPLD_LPC_REG_LED3_OFF:
+ case MLXPLAT_CPLD_LPC_REG_LED4_OFF:
+ case MLXPLAT_CPLD_LPC_REG_LED5_OFF:
+ case MLXPLAT_CPLD_LPC_REG_GP1_OFF:
+ case MLXPLAT_CPLD_LPC_REG_WP1_OFF:
+ case MLXPLAT_CPLD_LPC_REG_GP2_OFF:
+ case MLXPLAT_CPLD_LPC_REG_WP2_OFF:
+ case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFF:
+ case MLXPLAT_CPLD_LPC_REG_AGGR_LOW_MASK_OFF:
+ case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFF:
+ case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFF:
+ case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFF:
+ case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFF:
+ case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFF:
+ case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFF:
+ return true;
+ }
+ return false;
+}
+
+static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFF:
+ case MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFF:
+ case MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF:
+ case MLXPLAT_CPLD_LPC_REG_LED1_OFF:
+ case MLXPLAT_CPLD_LPC_REG_LED2_OFF:
+ case MLXPLAT_CPLD_LPC_REG_LED3_OFF:
+ case MLXPLAT_CPLD_LPC_REG_LED4_OFF:
+ case MLXPLAT_CPLD_LPC_REG_LED5_OFF:
+ case MLXPLAT_CPLD_LPC_REG_GP1_OFF:
+ case MLXPLAT_CPLD_LPC_REG_WP1_OFF:
+ case MLXPLAT_CPLD_LPC_REG_GP2_OFF:
+ case MLXPLAT_CPLD_LPC_REG_WP2_OFF:
+ case MLXPLAT_CPLD_LPC_REG_AGGR_OFF:
+ case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFF:
+ case MLXPLAT_CPLD_LPC_REG_AGGR_LOW_OFF:
+ case MLXPLAT_CPLD_LPC_REG_AGGR_LOW_MASK_OFF:
+ case MLXPLAT_CPLD_LPC_REG_PSU_OFF:
+ case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFF:
+ case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFF:
+ case MLXPLAT_CPLD_LPC_REG_PWR_OFF:
+ case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFF:
+ case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFF:
+ case MLXPLAT_CPLD_LPC_REG_FAN_OFF:
+ case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFF:
+ case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFF:
+ return true;
+ }
+ return false;
+}
+
+static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFF:
+ case MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFF:
+ case MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF:
+ case MLXPLAT_CPLD_LPC_REG_LED1_OFF:
+ case MLXPLAT_CPLD_LPC_REG_LED2_OFF:
+ case MLXPLAT_CPLD_LPC_REG_LED3_OFF:
+ case MLXPLAT_CPLD_LPC_REG_LED4_OFF:
+ case MLXPLAT_CPLD_LPC_REG_LED5_OFF:
+ case MLXPLAT_CPLD_LPC_REG_GP1_OFF:
+ case MLXPLAT_CPLD_LPC_REG_GP2_OFF:
+ case MLXPLAT_CPLD_LPC_REG_AGGR_OFF:
+ case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFF:
+ case MLXPLAT_CPLD_LPC_REG_AGGR_LOW_OFF:
+ case MLXPLAT_CPLD_LPC_REG_AGGR_LOW_MASK_OFF:
+ case MLXPLAT_CPLD_LPC_REG_PSU_OFF:
+ case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFF:
+ case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFF:
+ case MLXPLAT_CPLD_LPC_REG_PWR_OFF:
+ case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFF:
+ case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFF:
+ case MLXPLAT_CPLD_LPC_REG_FAN_OFF:
+ case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFF:
+ case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFF:
+ return true;
+ }
+ return false;
+}
+
+static const struct reg_default mlxplat_mlxcpld_regmap_default[] = {
+ { MLXPLAT_CPLD_LPC_REG_WP1_OFF, 0x00 },
+ { MLXPLAT_CPLD_LPC_REG_WP2_OFF, 0x00 },
+};
+
static int
mlxplat_mlxcpld_reg_read(void *context, unsigned int reg, unsigned int *val)
{
@@ -809,6 +920,12 @@ const struct regmap_config mlxplat_mlxcpld_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 255,
+ .cache_type = REGCACHE_FLAT,
+ .writeable_reg = mlxplat_mlxcpld_writeable_reg,
+ .readable_reg = mlxplat_mlxcpld_readable_reg,
+ .volatile_reg = mlxplat_mlxcpld_volatile_reg,
+ .reg_defaults = mlxplat_mlxcpld_regmap_default,
+ .num_reg_defaults = ARRAY_SIZE(mlxplat_mlxcpld_regmap_default),
.reg_read = mlxplat_mlxcpld_reg_read,
.reg_write = mlxplat_mlxcpld_reg_write,
};
@@ -817,9 +934,38 @@ static struct resource mlxplat_mlxcpld_resources[] = {
[0] = DEFINE_RES_IRQ_NAMED(17, "mlxreg-hotplug"),
};
-struct platform_device *mlxplat_dev;
-struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug;
-struct mlxreg_core_led_platform_data *mlxplat_led;
+static struct mlxreg_core_data mlxplat_mlxcpld_default_regs_io_data[] = {
+ { "cpld1_version", MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFF, 0x00,
+ GENMASK(7, 0), 0444 },
+ { "cpld2_version", MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFF, 0x00,
+ GENMASK(7, 0), 0444 },
+ { "cause_long_pb", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF,
+ GENMASK(7, 0) & ~BIT(0), 0x00, 0444 },
+ { "cause_short_pb", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF,
+ GENMASK(7, 0) & ~BIT(1), 0x00, 0444 },
+ { "cause_pwr_aux", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF,
+ GENMASK(7, 0) & ~BIT(2), 0x00, 0444 },
+ { "cause_pwr_fail", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF,
+ GENMASK(7, 0) & ~BIT(3), 0x00, 0444 },
+ { "psu1_on", MLXPLAT_CPLD_LPC_REG_GP1_OFF, GENMASK(7, 0) & ~BIT(0),
+ 0x00, 0200 },
+ { "psu2_on", MLXPLAT_CPLD_LPC_REG_GP1_OFF, GENMASK(7, 0) & ~BIT(1),
+ 0x00, 0200 },
+ { "pwr_cycle", MLXPLAT_CPLD_LPC_REG_GP1_OFF, GENMASK(7, 0) & ~BIT(2),
+ 0x00, 0200 },
+ { "select_iio", MLXPLAT_CPLD_LPC_REG_GP2_OFF, GENMASK(7, 0) & ~BIT(6),
+ 0x00, 0644 },
+};
+
+static struct mlxreg_core_platform_data mlxplat_default_regs_io_data = {
+ .data = mlxplat_mlxcpld_default_regs_io_data,
+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_regs_io_data),
+};
+
+static struct platform_device *mlxplat_dev;
+static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug;
+static struct mlxreg_core_platform_data *mlxplat_led;
+static struct mlxreg_core_platform_data *mlxplat_regs_io;
static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
{
@@ -832,6 +978,7 @@ static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
}
mlxplat_hotplug = &mlxplat_mlxcpld_default_data;
mlxplat_led = &mlxplat_default_led_data;
+ mlxplat_regs_io = &mlxplat_default_regs_io_data;
return 1;
};
@@ -847,6 +994,7 @@ static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi)
}
mlxplat_hotplug = &mlxplat_mlxcpld_msn21xx_data;
mlxplat_led = &mlxplat_msn21xx_led_data;
+ mlxplat_regs_io = &mlxplat_default_regs_io_data;
return 1;
};
@@ -862,6 +1010,7 @@ static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi)
}
mlxplat_hotplug = &mlxplat_mlxcpld_msn274x_data;
mlxplat_led = &mlxplat_default_led_data;
+ mlxplat_regs_io = &mlxplat_default_regs_io_data;
return 1;
};
@@ -877,6 +1026,7 @@ static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi)
}
mlxplat_hotplug = &mlxplat_mlxcpld_default_ng_data;
mlxplat_led = &mlxplat_default_ng_led_data;
+ mlxplat_regs_io = &mlxplat_default_regs_io_data;
return 1;
};
@@ -892,6 +1042,7 @@ static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi)
}
mlxplat_hotplug = &mlxplat_mlxcpld_msn201x_data;
mlxplat_led = &mlxplat_msn21xx_led_data;
+ mlxplat_regs_io = &mlxplat_default_regs_io_data;
return 1;
};
@@ -974,7 +1125,7 @@ static int __init mlxplat_init(void)
{
struct mlxplat_priv *priv;
void __iomem *base;
- int i, err = 0;
+ int i, j, err = 0;
if (!dmi_check_system(mlxplat_dmi_table))
return -ENODEV;
@@ -1023,6 +1174,15 @@ static int __init mlxplat_init(void)
if (IS_ERR(mlxplat_hotplug->regmap))
goto fail_platform_mux_register;
+ /* Set default registers. */
+ for (j = 0; j < mlxplat_mlxcpld_regmap_config.num_reg_defaults; j++) {
+ err = regmap_write(mlxplat_hotplug->regmap,
+ mlxplat_mlxcpld_regmap_default[j].reg,
+ mlxplat_mlxcpld_regmap_default[j].def);
+ if (err)
+ goto fail_platform_mux_register;
+ }
+
priv->pdev_hotplug = platform_device_register_resndata(
&mlxplat_dev->dev, "mlxreg-hotplug",
PLATFORM_DEVID_NONE,
@@ -1044,8 +1204,26 @@ static int __init mlxplat_init(void)
goto fail_platform_hotplug_register;
}
+ mlxplat_regs_io->regmap = mlxplat_hotplug->regmap;
+ priv->pdev_io_regs = platform_device_register_resndata(
+ &mlxplat_dev->dev, "mlxreg-io",
+ PLATFORM_DEVID_NONE, NULL, 0,
+ mlxplat_regs_io, sizeof(*mlxplat_regs_io));
+ if (IS_ERR(priv->pdev_io_regs)) {
+ err = PTR_ERR(priv->pdev_io_regs);
+ goto fail_platform_led_register;
+ }
+
+ /* Sync registers with hardware. */
+ regcache_mark_dirty(mlxplat_hotplug->regmap);
+ err = regcache_sync(mlxplat_hotplug->regmap);
+ if (err)
+ goto fail_platform_led_register;
+
return 0;
+fail_platform_led_register:
+ platform_device_unregister(priv->pdev_led);
fail_platform_hotplug_register:
platform_device_unregister(priv->pdev_hotplug);
fail_platform_mux_register:
@@ -1064,6 +1242,7 @@ static void __exit mlxplat_exit(void)
struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
int i;
+ platform_device_unregister(priv->pdev_io_regs);
platform_device_unregister(priv->pdev_led);
platform_device_unregister(priv->pdev_hotplug);
diff --git a/include/linux/platform_data/mlxreg.h b/include/linux/platform_data/mlxreg.h
index dd471c5..c25623b 100644
--- a/include/linux/platform_data/mlxreg.h
+++ b/include/linux/platform_data/mlxreg.h
@@ -61,6 +61,7 @@ struct mlxreg_hotplug_device {
* @label: attribute register offset;
* @reg: attribute register;
* @mask: attribute access mask;
+ * @mode: access mode;
* @bit: attribute effective bit;
* @np - pointer to node platform associated with attribute;
* @hpdev - hotplug device data;
@@ -72,6 +73,7 @@ struct mlxreg_core_data {
u32 reg;
u32 mask;
u32 bit;
+ umode_t mode;
struct device_node *np;
struct mlxreg_hotplug_device hpdev;
u8 health_cntr;
@@ -104,13 +106,13 @@ struct mlxreg_core_item {
};
/**
- * struct mlxreg_core_led_platform_data - led platform data:
+ * struct mlxreg_core_platform_data - platform data:
*
* @led_data: led private data;
* @regmap: register map of parent device;
* @counter: number of led instances;
*/
-struct mlxreg_core_led_platform_data {
+struct mlxreg_core_platform_data {
struct mlxreg_core_data *data;
void *regmap;
int counter;
--
2.1.4

View File

@@ -0,0 +1,53 @@
From c794f8ffa6521c47bfbff813e7f713561d7da7bd Mon Sep 17 00:00:00 2001
From: Vadim Pasternak <vadimp@mellanox.com>
Date: Mon, 11 Dec 2017 19:02:19 +0000
Subject: [v4.9 backport 09/29] platform/mellanox: mlxreg-hotplug driver add
check for low aggregation register mask
It adds verification for low aggregation register mask offset. Only
non-zero offset is considered as valid.
Signed-off-by: Vadim Pasternak <vadimp@mellanox.com>
---
drivers/platform/mellanox/mlxreg-hotplug.c | 18 +++++++++++-------
1 file changed, 11 insertions(+), 7 deletions(-)
diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c
index 94fdb6b..ba9241e 100644
--- a/drivers/platform/mellanox/mlxreg-hotplug.c
+++ b/drivers/platform/mellanox/mlxreg-hotplug.c
@@ -550,10 +550,13 @@ static int mlxreg_hotplug_set_irq(struct mlxreg_hotplug_priv_data *priv)
goto access_error;
/* Keep low aggregation initial status as zero and unmask events. */
- ret = regmap_write(priv->regmap, pdata->cell_low +
- MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask_low);
- if (ret)
- goto access_error;
+ if (pdata->cell_low) {
+ ret = regmap_write(priv->regmap, pdata->cell_low +
+ MLXREG_HOTPLUG_AGGR_MASK_OFF,
+ pdata->mask_low);
+ if (ret)
+ goto access_error;
+ }
/* Invoke work handler for initializing hot plug devices setting. */
mlxreg_hotplug_work_handler(&priv->dwork_irq.work);
@@ -582,9 +585,10 @@ static void mlxreg_hotplug_unset_irq(struct mlxreg_hotplug_priv_data *priv)
disable_irq(priv->irq);
cancel_delayed_work_sync(&priv->dwork_irq);
- /* Mask low aggregation event. */
- regmap_write(priv->regmap, pdata->cell_low +
- MLXREG_HOTPLUG_AGGR_MASK_OFF, 0);
+ /* Mask low aggregation event, if defined. */
+ if (pdata->cell_low)
+ regmap_write(priv->regmap, pdata->cell_low +
+ MLXREG_HOTPLUG_AGGR_MASK_OFF, 0);
/* Mask aggregation event. */
regmap_write(priv->regmap, pdata->cell + MLXREG_HOTPLUG_AGGR_MASK_OFF,
--
2.1.4

View File

@@ -0,0 +1,472 @@
diff --git a/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c b/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c
index 3bc6cf8..07cc7ea 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/qsfp_sysfs.c
@@ -33,6 +33,7 @@
*/
#include <linux/device.h>
+#include <linux/dmi.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/sysfs.h>
@@ -49,7 +50,8 @@
#define MLXSW_QSFP_MAX_NUM 64
#define MLXSW_QSFP_MIN_REQ_LEN 4
#define MLXSW_QSFP_STATUS_VALID_TIME (120 * HZ)
-#define MLXSW_QSFP_MAX_CPLD_NUM 1
+#define MLXSW_QSFP_MAX_CPLD_NUM 3
+#define MLXSW_QSFP_MIN_CPLD_NUM 1
static const u8 mlxsw_qsfp_page_number[] = { 0xa0, 0x00, 0x01, 0x02, 0x03 };
static const u16 mlxsw_qsfp_page_shift[] = { 0x00, 0x80, 0x80, 0x80, 0x80 };
@@ -85,6 +87,8 @@ struct mlxsw_qsfp {
struct device_attribute *cpld_dev_attrs;
};
+static int mlxsw_qsfp_cpld_num = MLXSW_QSFP_MIN_CPLD_NUM;
+
static int
mlxsw_qsfp_query_module_eeprom(struct mlxsw_qsfp *mlxsw_qsfp, u8 index,
loff_t off, size_t count, int page, char *buf)
@@ -210,11 +214,11 @@ mlxsw_qsfp_cpld_show(struct device *dev, struct device_attribute *attr,
u32 version, i;
int err;
- for (i = 0; i < MLXSW_QSFP_MAX_CPLD_NUM; i++) {
+ for (i = 0; i < mlxsw_qsfp_cpld_num; i++) {
if ((mlxsw_qsfp->cpld_dev_attrs + i) == attr)
break;
}
- if (i == MLXSW_QSFP_MAX_CPLD_NUM)
+ if (i == mlxsw_qsfp_cpld_num)
return -EINVAL;
mlxsw_reg_msci_pack(msci_pl, i);
@@ -227,6 +231,32 @@ mlxsw_qsfp_cpld_show(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%u\n", version);
}
+static int __init mlxsw_qsfp_dmi_set_cpld_num(const struct dmi_system_id *dmi)
+{
+ mlxsw_qsfp_cpld_num = MLXSW_QSFP_MAX_CPLD_NUM;
+
+ return 1;
+};
+
+static struct dmi_system_id mlxsw_qsfp_dmi_table[] __initdata = {
+ {
+ .callback = mlxsw_qsfp_dmi_set_cpld_num,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MSN24"),
+ },
+ },
+ {
+ .callback = mlxsw_qsfp_dmi_set_cpld_num,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MSN27"),
+ },
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(dmi, mlxsw_qsfp_dmi_table);
+
int mlxsw_qsfp_init(struct mlxsw_core *mlxsw_core,
const struct mlxsw_bus_info *mlxsw_bus_info,
struct mlxsw_qsfp **p_qsfp)
@@ -242,6 +272,8 @@ int mlxsw_qsfp_init(struct mlxsw_core *mlxsw_core,
if (!strcmp(mlxsw_bus_info->device_kind, "i2c"))
return 0;
+ dmi_check_system(mlxsw_qsfp_dmi_table);
+
mlxsw_qsfp = devm_kzalloc(mlxsw_bus_info->dev, sizeof(*mlxsw_qsfp),
GFP_KERNEL);
if (!mlxsw_qsfp)
@@ -285,7 +317,7 @@ int mlxsw_qsfp_init(struct mlxsw_core *mlxsw_core,
return -ENOMEM;
mlxsw_qsfp->cpld_dev_attrs = devm_kzalloc(mlxsw_bus_info->dev,
- MLXSW_QSFP_MAX_CPLD_NUM *
+ mlxsw_qsfp_cpld_num *
sizeof(*mlxsw_qsfp->cpld_dev_attrs),
GFP_KERNEL);
if (!mlxsw_qsfp->cpld_dev_attrs)
@@ -323,7 +355,7 @@ int mlxsw_qsfp_init(struct mlxsw_core *mlxsw_core,
}
cpld_dev_attr = mlxsw_qsfp->cpld_dev_attrs;
- for (i = 0; i < MLXSW_QSFP_MAX_CPLD_NUM; i++, cpld_dev_attr++) {
+ for (i = 0; i < mlxsw_qsfp_cpld_num; i++, cpld_dev_attr++) {
cpld_dev_attr->show = mlxsw_qsfp_cpld_show;
cpld_dev_attr->attr.mode = 0444;
cpld_dev_attr->attr.name = devm_kasprintf(mlxsw_bus_info->dev,
diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c
index ba9241e..5c13591 100644
--- a/drivers/platform/mellanox/mlxreg-hotplug.c
+++ b/drivers/platform/mellanox/mlxreg-hotplug.c
@@ -58,6 +58,7 @@
#define MLXREG_HOTPLUG_PROP_STATUS "status"
#define MLXREG_HOTPLUG_ATTRS_MAX 24
+#define MLXREG_HOTPLUG_NOT_ASSERT 3
/**
* struct mlxreg_hotplug_priv_data - platform private data:
@@ -74,6 +75,7 @@
* @cell: location of top aggregation interrupt register;
* @mask: top aggregation interrupt common mask;
* @aggr_cache: last value of aggregation register status;
+ * @not_asserted: number of entries in workqueue with no signal assertion;
*/
struct mlxreg_hotplug_priv_data {
int irq;
@@ -94,6 +96,7 @@ struct mlxreg_hotplug_priv_data {
u32 mask;
u32 aggr_cache;
bool after_probe;
+ u8 not_asserted;
};
#if defined(CONFIG_OF_DYNAMIC)
@@ -441,7 +444,7 @@ mlxreg_hotplug_health_work_helper(struct mlxreg_hotplug_priv_data *priv,
* *---*
*
* In case some system changed are detected: FAN in/out, PSU in/out, power
- * cable attached/detached, ASIC helath good/bad, relevant device is created
+ * cable attached/detached, ASIC health good/bad, relevant device is created
* or destroyed.
*/
static void mlxreg_hotplug_work_handler(struct work_struct *work)
@@ -472,6 +475,13 @@ static void mlxreg_hotplug_work_handler(struct work_struct *work)
aggr_asserted = priv->aggr_cache ^ regval;
priv->aggr_cache = regval;
+ if (priv->not_asserted == MLXREG_HOTPLUG_NOT_ASSERT) {
+ priv->not_asserted = 0;
+ aggr_asserted = pdata->mask;
+ }
+ if (!aggr_asserted)
+ goto unmask_event;
+
/* Handle topology and health configuration changes. */
for (i = 0; i < pdata->counter; i++, item++) {
if (aggr_asserted & item->aggr_mask) {
@@ -503,6 +513,8 @@ static void mlxreg_hotplug_work_handler(struct work_struct *work)
return;
}
+unmask_event:
+ priv->not_asserted++;
/* Unmask aggregation event (no need acknowledge). */
ret = regmap_write(priv->regmap, pdata->cell +
MLXREG_HOTPLUG_AGGR_MASK_OFF, pdata->mask);
@@ -626,6 +638,7 @@ static int mlxreg_hotplug_probe(struct platform_device *pdev)
{
struct mlxreg_core_hotplug_platform_data *pdata;
struct mlxreg_hotplug_priv_data *priv;
+ struct i2c_adapter *deferred_adap;
int err;
pdata = dev_get_platdata(&pdev->dev);
@@ -634,6 +647,12 @@ static int mlxreg_hotplug_probe(struct platform_device *pdev)
return -EINVAL;
}
+ /* Defer probing if the necessary adapter is not configured yet. */
+ deferred_adap = i2c_get_adapter(pdata->deferred_nr);
+ if (!deferred_adap)
+ return -EPROBE_DEFER;
+ i2c_put_adapter(deferred_adap);
+
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c
index 61cbe35..e03f03f 100644
--- a/drivers/platform/x86/mlx-platform.c
+++ b/drivers/platform/x86/mlx-platform.c
@@ -99,6 +99,15 @@
#define MLXPLAT_CPLD_LED_LO_NIBBLE_MASK GENMASK(7, 4)
#define MLXPLAT_CPLD_LED_HI_NIBBLE_MASK GENMASK(3, 0)
+/* Default I2C parent bus number */
+#define MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR 1
+
+/* Maximum number of possible physical buses equipped on system */
+#define MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM 16
+
+/* Number of channels in group */
+#define MLXPLAT_CPLD_GRP_CHNL_NUM 8
+
/* Start channel numbers */
#define MLXPLAT_CPLD_CH1 2
#define MLXPLAT_CPLD_CH2 10
@@ -106,7 +115,8 @@
/* Number of LPC attached MUX platform devices */
#define MLXPLAT_CPLD_LPC_MUX_DEVS 2
-/* PSU adapter numbers */
+/* Hotplug devices adapter numbers */
+#define MLXPLAT_CPLD_NR_NONE -1
#define MLXPLAT_CPLD_PSU_DEFAULT_NR 10
#define MLXPLAT_CPLD_PSU_MSNXXXX_NR 4
@@ -137,7 +147,7 @@ static const struct resource mlxplat_lpc_resources[] = {
};
/* Platform default channels */
-static const int mlxplat_default_channels[][8] = {
+static const int mlxplat_default_channels[][MLXPLAT_CPLD_GRP_CHNL_NUM] = {
{
MLXPLAT_CPLD_CH1, MLXPLAT_CPLD_CH1 + 1, MLXPLAT_CPLD_CH1 + 2,
MLXPLAT_CPLD_CH1 + 3, MLXPLAT_CPLD_CH1 + 4, MLXPLAT_CPLD_CH1 +
@@ -472,14 +482,14 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_fan_items_data[] = {
{
.label = "fan5",
.reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF,
- .mask = BIT(3),
+ .mask = BIT(4),
.hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan,
.hpdev.nr = 15,
},
{
.label = "fan6",
.reg = MLXPLAT_CPLD_LPC_REG_FAN_OFF,
- .mask = BIT(3),
+ .mask = BIT(5),
.hpdev.brdinfo = &mlxplat_mlxcpld_ng_fan,
.hpdev.nr = 16,
},
@@ -943,10 +953,18 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_regs_io_data[] = {
GENMASK(7, 0) & ~BIT(0), 0x00, 0444 },
{ "cause_short_pb", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF,
GENMASK(7, 0) & ~BIT(1), 0x00, 0444 },
- { "cause_pwr_aux", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF,
+ { "cause_aux_pwr_or_refresh", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF,
GENMASK(7, 0) & ~BIT(2), 0x00, 0444 },
- { "cause_pwr_fail", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF,
+ { "cause_main_pwr_fail", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF,
GENMASK(7, 0) & ~BIT(3), 0x00, 0444 },
+ { "cause_sw_reset", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF,
+ GENMASK(7, 0) & ~BIT(4), 0x00, 0444 },
+ { "cause_fw_reset", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF,
+ GENMASK(7, 0) & ~BIT(5), 0x00, 0444 },
+ { "cause_hotswap_or_wd", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF,
+ GENMASK(7, 0) & ~BIT(6), 0x00, 0444 },
+ { "cause_asic_thermal", MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFF,
+ GENMASK(7, 0) & ~BIT(7), 0x00, 0444 },
{ "psu1_on", MLXPLAT_CPLD_LPC_REG_GP1_OFF, GENMASK(7, 0) & ~BIT(0),
0x00, 0200 },
{ "psu2_on", MLXPLAT_CPLD_LPC_REG_GP1_OFF, GENMASK(7, 0) & ~BIT(1),
@@ -977,6 +995,8 @@ static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
ARRAY_SIZE(mlxplat_default_channels[i]);
}
mlxplat_hotplug = &mlxplat_mlxcpld_default_data;
+ mlxplat_hotplug->deferred_nr =
+ mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
mlxplat_led = &mlxplat_default_led_data;
mlxplat_regs_io = &mlxplat_default_regs_io_data;
@@ -993,6 +1013,8 @@ static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi)
ARRAY_SIZE(mlxplat_msn21xx_channels);
}
mlxplat_hotplug = &mlxplat_mlxcpld_msn21xx_data;
+ mlxplat_hotplug->deferred_nr =
+ mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
mlxplat_led = &mlxplat_msn21xx_led_data;
mlxplat_regs_io = &mlxplat_default_regs_io_data;
@@ -1009,6 +1031,8 @@ static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi)
ARRAY_SIZE(mlxplat_msn21xx_channels);
}
mlxplat_hotplug = &mlxplat_mlxcpld_msn274x_data;
+ mlxplat_hotplug->deferred_nr =
+ mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
mlxplat_led = &mlxplat_default_led_data;
mlxplat_regs_io = &mlxplat_default_regs_io_data;
@@ -1025,6 +1049,8 @@ static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi)
ARRAY_SIZE(mlxplat_msn21xx_channels);
}
mlxplat_hotplug = &mlxplat_mlxcpld_default_ng_data;
+ mlxplat_hotplug->deferred_nr =
+ mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
mlxplat_led = &mlxplat_default_ng_led_data;
mlxplat_regs_io = &mlxplat_default_regs_io_data;
@@ -1041,13 +1067,15 @@ static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi)
ARRAY_SIZE(mlxplat_msn21xx_channels);
}
mlxplat_hotplug = &mlxplat_mlxcpld_msn201x_data;
+ mlxplat_hotplug->deferred_nr =
+ mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
mlxplat_led = &mlxplat_msn21xx_led_data;
mlxplat_regs_io = &mlxplat_default_regs_io_data;
return 1;
};
-static struct dmi_system_id mlxplat_dmi_table[] __initdata = {
+static const struct dmi_system_id mlxplat_dmi_table[] __initconst = {
{
.callback = mlxplat_dmi_msn274x_matched,
.matches = {
@@ -1118,14 +1146,84 @@ static struct dmi_system_id mlxplat_dmi_table[] __initdata = {
DMI_MATCH(DMI_PRODUCT_NAME, "SN34"),
},
},
+ {
+ .callback = mlxplat_dmi_default_matched,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "VMOD0001"),
+ },
+ },
+ {
+ .callback = mlxplat_dmi_msn21xx_matched,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "VMOD0002"),
+ },
+ },
+ {
+ .callback = mlxplat_dmi_msn274x_matched,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "VMOD0003"),
+ },
+ },
+ {
+ .callback = mlxplat_dmi_msn201x_matched,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "VMOD0004"),
+ },
+ },
+ {
+ .callback = mlxplat_dmi_qmb7xx_matched,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "VMOD0005"),
+ },
+ },
{ }
};
+MODULE_DEVICE_TABLE(dmi, mlxplat_dmi_table);
+
+static int mlxplat_mlxcpld_verify_bus_topology(int *nr)
+{
+ struct i2c_adapter *search_adap;
+ int shift, i;
+
+ /* Scan adapters from expected id to verify it is free. */
+ *nr = MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR;
+ for (i = MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR; i <
+ MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM; i++) {
+ search_adap = i2c_get_adapter(i);
+ if (search_adap) {
+ i2c_put_adapter(search_adap);
+ continue;
+ }
+
+ /* Return if expected parent adapter is free. */
+ if (i == MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR)
+ return 0;
+ break;
+ }
+
+ /* Return with error if free id for adapter is not found. */
+ if (i == MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM)
+ return -ENODEV;
+
+ /* Shift adapter ids, since expected parent adapter is not free. */
+ *nr = i;
+ for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
+ shift = *nr - mlxplat_mux_data[i].parent;
+ mlxplat_mux_data[i].parent = *nr;
+ mlxplat_mux_data[i].base_nr += shift;
+ if (shift > 0)
+ mlxplat_hotplug->shift_nr = shift;
+ }
+
+ return 0;
+}
+
static int __init mlxplat_init(void)
{
struct mlxplat_priv *priv;
void __iomem *base;
- int i, j, err = 0;
+ int i, j, nr, err = 0;
if (!dmi_check_system(mlxplat_dmi_table))
return -ENODEV;
@@ -1145,7 +1243,12 @@ static int __init mlxplat_init(void)
}
platform_set_drvdata(mlxplat_dev, priv);
- priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", -1,
+ err = mlxplat_mlxcpld_verify_bus_topology(&nr);
+ if (nr < 0)
+ goto fail_alloc;
+
+ nr = (nr == MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM) ? -1 : nr;
+ priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", nr,
NULL, 0);
if (IS_ERR(priv->pdev_i2c)) {
err = PTR_ERR(priv->pdev_i2c);
@@ -1166,13 +1269,17 @@ static int __init mlxplat_init(void)
base = devm_ioport_map(&mlxplat_dev->dev,
mlxplat_lpc_resources[1].start, 1);
- if (IS_ERR(base))
+ if (!base) {
+ err = -ENOMEM;
goto fail_platform_mux_register;
+ }
mlxplat_hotplug->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL,
base, &mlxplat_mlxcpld_regmap_config);
- if (IS_ERR(mlxplat_hotplug->regmap))
+ if (IS_ERR(mlxplat_hotplug->regmap)) {
+ err = PTR_ERR(mlxplat_hotplug->regmap);
goto fail_platform_mux_register;
+ }
/* Set default registers. */
for (j = 0; j < mlxplat_mlxcpld_regmap_config.num_reg_defaults; j++) {
@@ -1257,13 +1364,3 @@ module_exit(mlxplat_exit);
MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)");
MODULE_DESCRIPTION("Mellanox platform driver");
MODULE_LICENSE("Dual BSD/GPL");
-MODULE_ALIAS("dmi:*:*Mellanox*:MSN24*:");
-MODULE_ALIAS("dmi:*:*Mellanox*:MSN27*:");
-MODULE_ALIAS("dmi:*:*Mellanox*:MSB*:");
-MODULE_ALIAS("dmi:*:*Mellanox*:MSX*:");
-MODULE_ALIAS("dmi:*:*Mellanox*:MSN21*:");
-MODULE_ALIAS("dmi:*:*Mellanox*MSN274*:");
-MODULE_ALIAS("dmi:*:*Mellanox*MSN201*:");
-MODULE_ALIAS("dmi:*:*Mellanox*QMB7*:");
-MODULE_ALIAS("dmi:*:*Mellanox*SN37*:");
-MODULE_ALIAS("dmi:*:*Mellanox*QM34*:");
diff --git a/include/linux/platform_data/mlxreg.h b/include/linux/platform_data/mlxreg.h
index c25623b..b77c7a5 100644
--- a/include/linux/platform_data/mlxreg.h
+++ b/include/linux/platform_data/mlxreg.h
@@ -129,6 +129,8 @@ struct mlxreg_core_platform_data {
* @mask: top aggregation interrupt common mask;
* @cell_low: location of low aggregation interrupt register;
* @mask_low: low aggregation interrupt common mask;
+ * @deferred_nr: I2C adapter number must be exist prior probing execution;
+ * @shift_nr: I2C adapter numbers must be incremented by this value;
*/
struct mlxreg_core_hotplug_platform_data {
struct mlxreg_core_item *items;
@@ -139,6 +141,8 @@ struct mlxreg_core_hotplug_platform_data {
u32 mask;
u32 cell_low;
u32 mask_low;
+ int deferred_nr;
+ int shift_nr;
};
#endif /* __LINUX_PLATFORM_DATA_MLXREG_H */

View File

@@ -0,0 +1,199 @@
From 23c8535af1dd9dcaecb5aaf4097129bfb7e24570 Mon Sep 17 00:00:00 2001
From: Vadim Pasternak <vadimp@mellanox.com>
Date: Thu, 15 Mar 2018 18:38:18 +0000
Subject: [backport 4.9 7/7] i2c: busses: Add capabilities to i2c-mlxcpld
It adds support for extended length of read and write transactions.
New CPLD logic allows double size of the read and write transactions
length. This feature is verified through capability register, which is
renamed from unclear LPF_REG to CPBLTY_REG. Two bits 5 and 6 of these
register are used for length capability detection, while only 01
combination indicates support of extended transaction length. Others mean
lack of such support.
It adds support for smbus block read transaction. CPLD smbus block read
bit of capability register is verified during driver initialization, and
driver data is updated if such capability is available. In case an upper
layer requests a read transaction of length one and expects that length
will be the first received byte, driver will notify CPLD about SMBus block
read transaction flavor, so CPLD will know to execute such kind of
transaction.
It fixes report about supported functionality.
Functionality can be different up to CPLD capability.
It allows mlxcpld driver to be connected to pre-defined adapter number
equal or greater than one, in order to avoid current limitation, assuming
usage of id number one only.
Author: Michael Shych <michaelsh@mellanox.com>
Patches are sent to i2c-next.
Signed-off-by: Vadim Pasternak <vadimp@mellanox.com>
---
drivers/i2c/busses/i2c-mlxcpld.c | 70 ++++++++++++++++++++++++++++++++++------
1 file changed, 60 insertions(+), 10 deletions(-)
diff --git a/drivers/i2c/busses/i2c-mlxcpld.c b/drivers/i2c/busses/i2c-mlxcpld.c
index d271e6a..745ed43 100644
--- a/drivers/i2c/busses/i2c-mlxcpld.c
+++ b/drivers/i2c/busses/i2c-mlxcpld.c
@@ -45,13 +45,16 @@
#define MLXCPLD_I2C_VALID_FLAG (I2C_M_RECV_LEN | I2C_M_RD)
#define MLXCPLD_I2C_BUS_NUM 1
#define MLXCPLD_I2C_DATA_REG_SZ 36
+#define MLXCPLD_I2C_DATA_SZ_BIT BIT(5)
+#define MLXCPLD_I2C_DATA_SZ_MASK GENMASK(6, 5)
+#define MLXCPLD_I2C_SMBUS_BLK_BIT BIT(7)
#define MLXCPLD_I2C_MAX_ADDR_LEN 4
#define MLXCPLD_I2C_RETR_NUM 2
#define MLXCPLD_I2C_XFER_TO 500000 /* usec */
#define MLXCPLD_I2C_POLL_TIME 2000 /* usec */
/* LPC I2C registers */
-#define MLXCPLD_LPCI2C_LPF_REG 0x0
+#define MLXCPLD_LPCI2C_CPBLTY_REG 0x0
#define MLXCPLD_LPCI2C_CTRL_REG 0x1
#define MLXCPLD_LPCI2C_HALF_CYC_REG 0x4
#define MLXCPLD_LPCI2C_I2C_HOLD_REG 0x5
@@ -83,6 +86,7 @@ struct mlxcpld_i2c_priv {
struct mutex lock;
struct mlxcpld_i2c_curr_xfer xfer;
struct device *dev;
+ bool smbus_block;
};
static void mlxcpld_i2c_lpc_write_buf(u8 *data, u8 len, u32 addr)
@@ -230,7 +234,7 @@ static void mlxcpld_i2c_set_transf_data(struct mlxcpld_i2c_priv *priv,
* All upper layers currently are never use transfer with more than
* 2 messages. Actually, it's also not so relevant in Mellanox systems
* because of HW limitation. Max size of transfer is not more than 32
- * bytes in the current x86 LPCI2C bridge.
+ * or 68 bytes in the current x86 LPCI2C bridge.
*/
priv->xfer.cmd = msgs[num - 1].flags & I2C_M_RD;
@@ -295,7 +299,7 @@ static int mlxcpld_i2c_wait_for_free(struct mlxcpld_i2c_priv *priv)
static int mlxcpld_i2c_wait_for_tc(struct mlxcpld_i2c_priv *priv)
{
int status, i, timeout = 0;
- u8 datalen;
+ u8 datalen, val;
do {
usleep_range(MLXCPLD_I2C_POLL_TIME / 2, MLXCPLD_I2C_POLL_TIME);
@@ -324,9 +328,22 @@ static int mlxcpld_i2c_wait_for_tc(struct mlxcpld_i2c_priv *priv)
* Actual read data len will be always the same as
* requested len. 0xff (line pull-up) will be returned
* if slave has no data to return. Thus don't read
- * MLXCPLD_LPCI2C_NUM_DAT_REG reg from CPLD.
+ * MLXCPLD_LPCI2C_NUM_DAT_REG reg from CPLD. Only in case of
+ * SMBus block read transaction data len can be different,
+ * check this case.
*/
- datalen = priv->xfer.data_len;
+ mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_NUM_ADDR_REG, &val,
+ 1);
+ if (priv->smbus_block && (val & MLXCPLD_I2C_SMBUS_BLK_BIT)) {
+ mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_NUM_DAT_REG,
+ &datalen, 1);
+ if (unlikely(datalen > (I2C_SMBUS_BLOCK_MAX + 1))) {
+ dev_err(priv->dev, "Incorrect smbus block read message len\n");
+ return -E2BIG;
+ }
+ } else {
+ datalen = priv->xfer.data_len;
+ }
mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_DATA_REG,
priv->xfer.msg[i].buf, datalen);
@@ -344,12 +361,20 @@ static int mlxcpld_i2c_wait_for_tc(struct mlxcpld_i2c_priv *priv)
static void mlxcpld_i2c_xfer_msg(struct mlxcpld_i2c_priv *priv)
{
int i, len = 0;
- u8 cmd;
+ u8 cmd, val;
mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_NUM_DAT_REG,
&priv->xfer.data_len, 1);
- mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_NUM_ADDR_REG,
- &priv->xfer.addr_width, 1);
+
+ val = priv->xfer.addr_width;
+ /* Notify HW about SMBus block read transaction */
+ if (priv->smbus_block && priv->xfer.msg_num >= 2 &&
+ priv->xfer.msg[1].len == 1 &&
+ (priv->xfer.msg[1].flags & I2C_M_RECV_LEN) &&
+ (priv->xfer.msg[1].flags & I2C_M_RD))
+ val |= MLXCPLD_I2C_SMBUS_BLK_BIT;
+
+ mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_NUM_ADDR_REG, &val, 1);
for (i = 0; i < priv->xfer.msg_num; i++) {
if ((priv->xfer.msg[i].flags & I2C_M_RD) != I2C_M_RD) {
@@ -425,7 +450,14 @@ static int mlxcpld_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
static u32 mlxcpld_i2c_func(struct i2c_adapter *adap)
{
- return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_BLOCK_DATA;
+ struct mlxcpld_i2c_priv *priv = i2c_get_adapdata(adap);
+
+ if (priv->smbus_block)
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+ I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_BLOCK_DATA;
+ else
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+ I2C_FUNC_SMBUS_I2C_BLOCK;
}
static const struct i2c_algorithm mlxcpld_i2c_algo = {
@@ -433,13 +465,20 @@ static const struct i2c_algorithm mlxcpld_i2c_algo = {
.functionality = mlxcpld_i2c_func
};
-static struct i2c_adapter_quirks mlxcpld_i2c_quirks = {
+static const struct i2c_adapter_quirks mlxcpld_i2c_quirks = {
.flags = I2C_AQ_COMB_WRITE_THEN_READ,
.max_read_len = MLXCPLD_I2C_DATA_REG_SZ - MLXCPLD_I2C_MAX_ADDR_LEN,
.max_write_len = MLXCPLD_I2C_DATA_REG_SZ,
.max_comb_1st_msg_len = 4,
};
+static const struct i2c_adapter_quirks mlxcpld_i2c_quirks_ext = {
+ .flags = I2C_AQ_COMB_WRITE_THEN_READ,
+ .max_read_len = MLXCPLD_I2C_DATA_REG_SZ * 2 - MLXCPLD_I2C_MAX_ADDR_LEN,
+ .max_write_len = MLXCPLD_I2C_DATA_REG_SZ * 2,
+ .max_comb_1st_msg_len = 4,
+};
+
static struct i2c_adapter mlxcpld_i2c_adapter = {
.owner = THIS_MODULE,
.name = "i2c-mlxcpld",
@@ -454,6 +493,7 @@ static int mlxcpld_i2c_probe(struct platform_device *pdev)
{
struct mlxcpld_i2c_priv *priv;
int err;
+ u8 val;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -466,6 +506,16 @@ static int mlxcpld_i2c_probe(struct platform_device *pdev)
/* Register with i2c layer */
mlxcpld_i2c_adapter.timeout = usecs_to_jiffies(MLXCPLD_I2C_XFER_TO);
+ /* Read capability register */
+ mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_CPBLTY_REG, &val, 1);
+ /* Check support for extended transaction length */
+ if ((val & MLXCPLD_I2C_DATA_SZ_MASK) == MLXCPLD_I2C_DATA_SZ_BIT)
+ mlxcpld_i2c_adapter.quirks = &mlxcpld_i2c_quirks_ext;
+ /* Check support for smbus block transaction */
+ if (val & MLXCPLD_I2C_SMBUS_BLK_BIT)
+ priv->smbus_block = true;
+ if (pdev->id >= -1)
+ mlxcpld_i2c_adapter.nr = pdev->id;
priv->adap = mlxcpld_i2c_adapter;
priv->adap.dev.parent = &pdev->dev;
priv->base_addr = MLXPLAT_CPLD_LPC_I2C_BASE_ADDR;
--
2.1.4

View File

@@ -1 +1,13 @@
driver-support-intel-igb-bcm5461-phy.patch
0001-i2c-mlxcpld-add-master-driver-for-Mellanox-systems.patch
0002-i2c-mux-mlxcpld-add-driver-for-Mellanox-systems.patch
0003-platform-mellanox-Introduce-Mellanox-hardware-platfo.patch
0004-platform-x86-Introduce-support-for-Mellanox-hotplug-.patch
0005-leds-add-driver-for-support-Mellanox-regmap-LEDs-for.patch
0006-Mellanox-switch-drivers-changes.patch
0007-hwmon-pmbus-Add-support-for-Intel-VID-protocol-VR13.patch
0008-hwmon-pmbus-Add-support-for-Texas-Instruments-tps536.patch
0009-platform-mellonox-introduce-mlxreg-io-driver-and-add.patch
0010-platform-mellanox-mlxreg-hotplug-driver-add-check-fo.patch
0011-platform-x86-mlx-platform-new-features.patch
0012-i2c-busses-Add-capabilities-to-i2c-mlxcpld.patch

View File

@@ -31,8 +31,11 @@
#include <linux/mutex.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/delay.h>
#define MAX_FAN_DUTY_CYCLE 100
#define MAX_FAN_DUTY_CYCLE 100
#define I2C_RW_RETRY_COUNT 10
#define I2C_RW_RETRY_INTERVAL 60 /* ms */
/* Addresses scanned
*/
@@ -41,6 +44,7 @@ static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
enum chips {
YM2651,
YM2401,
YM2851,
};
/* Each client has this additional data
@@ -67,6 +71,7 @@ struct ym2651y_data {
u8 mfr_id[10]; /* Register value */
u8 mfr_model[16]; /* Register value */
u8 mfr_revsion[3]; /* Register value */
u8 mfr_serial[20]; /* Register value */
u16 mfr_vin_min; /* Register value */
u16 mfr_vin_max; /* Register value */
u16 mfr_iin_max; /* Register value */
@@ -112,6 +117,7 @@ enum ym2651y_sysfs_attributes {
PSU_MFR_ID,
PSU_MFR_MODEL,
PSU_MFR_REVISION,
PSU_MFR_SERIAL,
PSU_MFR_VIN_MIN,
PSU_MFR_VIN_MAX,
PSU_MFR_VOUT_MIN,
@@ -140,6 +146,7 @@ static SENSOR_DEVICE_ATTR(psu_pmbus_revision,S_IRUGO, show_byte, NULL, PSU_PMB
static SENSOR_DEVICE_ATTR(psu_mfr_id, S_IRUGO, show_ascii, NULL, PSU_MFR_ID);
static SENSOR_DEVICE_ATTR(psu_mfr_model, S_IRUGO, show_ascii, NULL, PSU_MFR_MODEL);
static SENSOR_DEVICE_ATTR(psu_mfr_revision, S_IRUGO, show_ascii, NULL, PSU_MFR_REVISION);
static SENSOR_DEVICE_ATTR(psu_mfr_serial, S_IRUGO, show_ascii, NULL, PSU_MFR_SERIAL);
static SENSOR_DEVICE_ATTR(psu_mfr_vin_min, S_IRUGO, show_linear, NULL, PSU_MFR_VIN_MIN);
static SENSOR_DEVICE_ATTR(psu_mfr_vin_max, S_IRUGO, show_linear, NULL, PSU_MFR_VIN_MAX);
static SENSOR_DEVICE_ATTR(psu_mfr_vout_min, S_IRUGO, show_linear, NULL, PSU_MFR_VOUT_MIN);
@@ -166,6 +173,7 @@ static struct attribute *ym2651y_attributes[] = {
&sensor_dev_attr_psu_mfr_id.dev_attr.attr,
&sensor_dev_attr_psu_mfr_model.dev_attr.attr,
&sensor_dev_attr_psu_mfr_revision.dev_attr.attr,
&sensor_dev_attr_psu_mfr_serial.dev_attr.attr,
&sensor_dev_attr_psu_mfr_vin_min.dev_attr.attr,
&sensor_dev_attr_psu_mfr_vin_max.dev_attr.attr,
&sensor_dev_attr_psu_mfr_pout_max.dev_attr.attr,
@@ -370,6 +378,9 @@ static ssize_t show_ascii(struct device *dev, struct device_attribute *da,
case PSU_MFR_REVISION: /* psu_mfr_revision */
ptr = data->mfr_revsion + 1; /* The first byte is the count byte of string. */
break;
case PSU_MFR_SERIAL: /* psu_mfr_serial */
ptr = data->mfr_serial + 1; /* The first byte is the count byte of string. */
break;
default:
return 0;
}
@@ -477,6 +488,7 @@ static int ym2651y_remove(struct i2c_client *client)
static const struct i2c_device_id ym2651y_id[] = {
{ "ym2651", YM2651 },
{ "ym2401", YM2401 },
{ "ym2851", YM2851 },
{}
};
MODULE_DEVICE_TABLE(i2c, ym2651y_id);
@@ -494,35 +506,75 @@ static struct i2c_driver ym2651y_driver = {
static int ym2651y_read_byte(struct i2c_client *client, u8 reg)
{
return i2c_smbus_read_byte_data(client, reg);
int status = 0, retry = I2C_RW_RETRY_COUNT;
while (retry) {
status = i2c_smbus_read_byte_data(client, reg);
if (unlikely(status < 0)) {
msleep(I2C_RW_RETRY_INTERVAL);
retry--;
continue;
}
break;
}
return status;
}
static int ym2651y_read_word(struct i2c_client *client, u8 reg)
{
return i2c_smbus_read_word_data(client, reg);
int status = 0, retry = I2C_RW_RETRY_COUNT;
while (retry) {
status = i2c_smbus_read_word_data(client, reg);
if (unlikely(status < 0)) {
msleep(I2C_RW_RETRY_INTERVAL);
retry--;
continue;
}
break;
}
return status;
}
static int ym2651y_write_word(struct i2c_client *client, u8 reg, u16 value)
{
return i2c_smbus_write_word_data(client, reg, value);
int status = 0, retry = I2C_RW_RETRY_COUNT;
while (retry) {
status = i2c_smbus_write_word_data(client, reg, value);
if (unlikely(status < 0)) {
msleep(I2C_RW_RETRY_INTERVAL);
retry--;
continue;
}
break;
}
return status;
}
static int ym2651y_read_block(struct i2c_client *client, u8 command, u8 *data,
int data_len)
{
int result = i2c_smbus_read_i2c_block_data(client, command, data_len, data);
int status = 0, retry = I2C_RW_RETRY_COUNT;
if (unlikely(result < 0))
goto abort;
if (unlikely(result != data_len)) {
result = -EIO;
goto abort;
while (retry) {
status = i2c_smbus_read_i2c_block_data(client, command, data_len, data);
if (unlikely(status < 0)) {
msleep(I2C_RW_RETRY_INTERVAL);
retry--;
continue;
}
break;
}
result = 0;
abort:
return result;
return status;
}
struct reg_data_byte {
@@ -651,6 +703,17 @@ static struct ym2651y_data *ym2651y_update_device(struct device *dev)
goto exit;
}
/* Read mfr_serial */
command = 0x9e;
status = ym2651y_read_block(client, command, data->mfr_serial,
ARRAY_SIZE(data->mfr_serial)-1);
data->mfr_serial[ARRAY_SIZE(data->mfr_serial)-1] = '\0';
if (status < 0) {
dev_dbg(&client->dev, "reg %d, err %d\n", command, status);
goto exit;
}
data->last_updated = jiffies;
data->valid = 1;
}

View File

@@ -21,5 +21,4 @@ packages:
init: ${ONL}/packages/base/any/onlp-snmpd/onlp-snmpd.init
changelog: Change changes changes.,
asr: True

View File

@@ -110,7 +110,7 @@ onlp_snmp_config_lookup(const char* setting)
{
int i;
for(i = 0; onlp_snmp_config_settings[i].name; i++) {
if(strcmp(onlp_snmp_config_settings[i].name, setting)) {
if(!strcmp(onlp_snmp_config_settings[i].name, setting)) {
return onlp_snmp_config_settings[i].value;
}
}

View File

@@ -259,9 +259,29 @@ us_to_next_update(void)
return MIN(period - deltat, period);
}
#include <onlplib/file_uds.h>
static int
cpu_utilization_handler__(int fd, void* cookie)
{
char svalue[64];
resources_t *curr = get_curr_resources();
sprintf(svalue, "%d", curr->utilization_percent);
write(fd, svalue, strlen(svalue));
close(fd);
return 0;
}
static void *
do_update(void *arg)
{
onlp_file_uds_t* uds;
if(ONLP_SUCCESS(onlp_file_uds_create(&uds))) {
onlp_file_uds_add(uds,
"/var/run/onl/cpu-utilization",
cpu_utilization_handler__, NULL);
}
for (;;) {
resource_update();
usleep(us_to_next_update());

View File

@@ -26,11 +26,14 @@ packages:
builds/onlp-platform/$BUILD_DIR/${TOOLCHAIN}/bin/libonlp-platform.so : $libdir/
builds/onlp-platform-defaults/$BUILD_DIR/${TOOLCHAIN}/bin/libonlp-platform-defaults.so : $libdir/
builds/onlpd/$BUILD_DIR/${TOOLCHAIN}/bin/onlpd : $bindir/
${ONL}/packages/base/any/onlp/src/onlpdump.py: $bindir/
${ONL}/packages/base/any/onlp/src/onlp/module/python/onlp/__init__.py: ${PY_INSTALL}/onlp/
${ONL}/packages/base/any/onlp/src/onlp/module/python/onlp/onlp: ${PY_INSTALL}/onlp/onlp
${ONL}/packages/base/any/onlp/src/onlp/module/python/onlp/test: ${PY_INSTALL}/onlp/test
${ONL}/packages/base/any/onlp/src/onlplib/module/python/onlp/onlplib: ${PY_INSTALL}/onlp/onlplib
${ONL}/packages/base/any/onlp/src/sff/module/python/onlp/sff: ${PY_INSTALL}/onlp/sff
init: $ONL/packages/base/any/onlp/src/onlpd.init
changelog: Change changes changes.,
asr: True

View File

@@ -0,0 +1 @@
*.mk

View File

@@ -24,5 +24,5 @@
############################################################
onlp_AUTO_DEFS := module/auto/onlp.yml
onlp_AUTO_DIRS := module/inc/onlp module/src module/py
onlp_AUTO_DIRS := module/inc/onlp module/src module/python/onlp/onlp
include $(BUILDER)/auto.mk

View File

@@ -109,6 +109,17 @@ oid_types: &oid_types
- MODULE : 6
- RTC : 7
# OID dump options
oid_dump: &oid_dump
- RECURSE
- EVEN_IF_ABSENT
# OID show options
oid_show: &oid_show
- RECURSE
- EXTENDED
- YAML
# SFP Control
sfp_control: &sfp_control
- RESET
@@ -255,6 +266,14 @@ definitions:
onlp_oid_type:
tag: oid
members: *oid_types
onlp_oid_show:
tag: oid
members: *oid_show
flags: True
onlp_oid_dump:
tag: oid
members: *oid_dump
flags: True
onlp_thermal_status:
tag: thermal
members: *thermal_status

View File

@@ -47,6 +47,19 @@
typedef uint32_t onlp_oid_t;
/* <auto.start.enum(tag:oid).define> */
/** onlp_oid_dump */
typedef enum onlp_oid_dump_e {
ONLP_OID_DUMP_RECURSE = (1 << 0),
ONLP_OID_DUMP_EVEN_IF_ABSENT = (1 << 1),
} onlp_oid_dump_t;
/** onlp_oid_show */
typedef enum onlp_oid_show_e {
ONLP_OID_SHOW_RECURSE = (1 << 0),
ONLP_OID_SHOW_EXTENDED = (1 << 1),
ONLP_OID_SHOW_YAML = (1 << 2),
} onlp_oid_show_t;
/** onlp_oid_type */
typedef enum onlp_oid_type_e {
ONLP_OID_TYPE_SYS = 1,
@@ -121,13 +134,6 @@ typedef struct onlp_oid_hdr_s {
} onlp_oid_hdr_t;
#define ONLP_OID_DUMP_F_RECURSE 0x1
#define ONLP_OID_DUMP_F_EVEN_IF_ABSENT 0x2
#define ONLP_OID_SHOW_F_RECURSE 0x1
#define ONLP_OID_SHOW_F_EXTENDED 0x2
#define ONLP_OID_SHOW_F_YAML 0x4
void onlp_oid_dump(onlp_oid_t oid, aim_pvs_t* pvs, uint32_t flags);
void onlp_oid_table_dump(onlp_oid_table_t table, aim_pvs_t* pvs,
uint32_t flags);
@@ -199,6 +205,48 @@ int onlp_oid_hdr_get(onlp_oid_t oid, onlp_oid_hdr_t* hdr);
*
*****************************************************************************/
/* <auto.start.enum(tag:oid).supportheader> */
/** Enum names. */
const char* onlp_oid_dump_name(onlp_oid_dump_t e);
/** Enum values. */
int onlp_oid_dump_value(const char* str, onlp_oid_dump_t* e, int substr);
/** Enum descriptions. */
const char* onlp_oid_dump_desc(onlp_oid_dump_t e);
/** Enum validator. */
int onlp_oid_dump_valid(onlp_oid_dump_t e);
/** validator */
#define ONLP_OID_DUMP_VALID(_e) \
(onlp_oid_dump_valid((_e)))
/** onlp_oid_dump_map table. */
extern aim_map_si_t onlp_oid_dump_map[];
/** onlp_oid_dump_desc_map table. */
extern aim_map_si_t onlp_oid_dump_desc_map[];
/** Enum names. */
const char* onlp_oid_show_name(onlp_oid_show_t e);
/** Enum values. */
int onlp_oid_show_value(const char* str, onlp_oid_show_t* e, int substr);
/** Enum descriptions. */
const char* onlp_oid_show_desc(onlp_oid_show_t e);
/** Enum validator. */
int onlp_oid_show_valid(onlp_oid_show_t e);
/** validator */
#define ONLP_OID_SHOW_VALID(_e) \
(onlp_oid_show_valid((_e)))
/** onlp_oid_show_map table. */
extern aim_map_si_t onlp_oid_show_map[];
/** onlp_oid_show_desc_map table. */
extern aim_map_si_t onlp_oid_show_desc_map[];
/** Enum names. */
const char* onlp_oid_type_name(onlp_oid_type_t e);

View File

@@ -48,6 +48,8 @@ ONLP_ENUMERATION_ENTRY(onlp_fan_status, "")
ONLP_ENUMERATION_ENTRY(onlp_led_caps, "")
ONLP_ENUMERATION_ENTRY(onlp_led_mode, "")
ONLP_ENUMERATION_ENTRY(onlp_led_status, "")
ONLP_ENUMERATION_ENTRY(onlp_oid_dump, "")
ONLP_ENUMERATION_ENTRY(onlp_oid_show, "")
ONLP_ENUMERATION_ENTRY(onlp_oid_type, "")
ONLP_ENUMERATION_ENTRY(onlp_psu_caps, "")
ONLP_ENUMERATION_ENTRY(onlp_psu_status, "")

View File

@@ -0,0 +1,4 @@
"""__init__.py
Module init for onlp.
"""

View File

@@ -0,0 +1,662 @@
"""__init__.py
Module init for onlp.onlp
"""
import ctypes
libonlp = ctypes.cdll.LoadLibrary("libonlp.so")
libonlp.onlp_init()
import ctypes.util
libc = ctypes.cdll.LoadLibrary(ctypes.util.find_library("c"))
import onlp.onlplib
import onlp.sff
from onlp.onlp import aim_weakref
from onlp.onlp.enums import *
# AIM/aim_memory.h
class aim_void_p(aim_weakref.AimPointer):
@classmethod
def deletePointer(cls, aimPtr):
libonlp.aim_free(aimPtr)
class aim_char_p(aim_void_p):
"""AIM data that is a printable string."""
def __init__(self, stringOrAddress):
if stringOrAddress is None:
aim_void_p.__init__(self, stringOrAddress)
return
if isinstance(stringOrAddress, aim_void_p):
aim_void_p.__init__(self, stringOrAddress)
return
if isinstance(stringOrAddress, basestring):
cs = ctypes.c_char_p(stringOrAddress)
ptr = libonlp.aim_malloc(len(stringOrAddress)+1)
libc.strcpy(ptr, ctypes.addressof(cs))
aim_void_p.__init__(self, ptr)
return
if type(stringOrAddress) == int:
aim_void_p.__init__(self, stringOrAddress)
return
raise ValueError("invalid initializer for aim_char_p: %s"
% repr(stringOrAddress))
def string_at(self):
if self.value:
return ctypes.string_at(self.value)
else:
return None
def __eq__(self, other):
return (isinstance(other, aim_char_p)
and (self.string_at()==other.string_at()))
def __neq__(self, other):
return not self == other
def __hash__(self):
return hash(self.string_at())
def aim_memory_init_prototypes():
libonlp.aim_malloc.restype = aim_void_p
libonlp.aim_malloc.argtypes = (ctypes.c_size_t,)
libonlp.aim_free.restype = None
libonlp.aim_free.argtypes = (aim_void_p,)
# AIM/aim_object.h
aim_object_dtor = ctypes.CFUNCTYPE(None, ctypes.c_void_p)
class aim_object(ctypes.Structure):
_fields_ = [("_id", ctypes.c_char_p,),
("subtype", ctypes.c_int,),
("cookie", ctypes.c_void_p,),
("destructor", aim_object_dtor,),]
# AIM/aim_pvs.h
# AIM/aim_pvs_*.h
aim_vprintf_f = ctypes.CFUNCTYPE(ctypes.c_int)
class aim_pvs(ctypes.Structure):
_fields_ = [("object", aim_object,),
("description", ctypes.c_char_p,),
("vprintf", aim_vprintf_f,),
("enabled", ctypes.c_int,),
("counter", ctypes.c_uint32,),
("isatty", aim_vprintf_f,),]
def aim_pvs_init_prototypes():
libonlp.aim_pvs_buffer_create.restype = ctypes.POINTER(aim_pvs)
libonlp.aim_pvs_destroy.restype = None
libonlp.aim_pvs_destroy.argtypes = (ctypes.POINTER(aim_pvs),)
libonlp.aim_pvs_buffer_size.restype = ctypes.c_int
libonlp.aim_pvs_buffer_size.argtypes = (ctypes.POINTER(aim_pvs),)
libonlp.aim_pvs_buffer_get.restype = aim_char_p
libonlp.aim_pvs_buffer_get.argtypes = (ctypes.POINTER(aim_pvs),)
libonlp.aim_pvs_buffer_reset.restype = None
libonlp.aim_pvs_buffer_reset.argtypes = (ctypes.POINTER(aim_pvs),)
# AIM/aim_bitmap.h
aim_bitmap_word = ctypes.c_uint32
AIM_BITMAP_BITS_PER_WORD = 32
def AIM_BITMAP_WORD_COUNT(bitcount):
return ((bitcount // AIM_BITMAP_BITS_PER_WORD)
+ (1 if (bitcount % AIM_BITMAP_BITS_PER_WORD) else 0))
# ugh, most of aim_bitmap.h is inline C
def AIM_BITMAP_HDR_WORD_GET(hdr, word):
"""Return a specific ctypes word."""
return hdr.words[word]
def AIM_BITMAP_HDR_BIT_WORD_GET(hdr, bit):
"""Return the ctypes word holding this bit."""
return hdr.words[bit/AIM_BITMAP_BITS_PER_WORD]
def AIM_BITMAP_HDR_BIT_WORD_SET(hdr, bit, word):
"""Return the ctypes word holding this bit."""
hdr.words[bit/AIM_BITMAP_BITS_PER_WORD] = word
def AIM_BITMAP_BIT_POS(bit):
return (1<<(bit % AIM_BITMAP_BITS_PER_WORD))
def AIM_BITMAP_INIT(bitmap, count):
"""Initialize a static bitmap."""
libc.memset(ctypes.byref(bitmap), 0, ctypes.sizeof(bitmap))
bitmap.hdr.maxbit = count
bitmap.hdr.words = ctypes.cast(ctypes.byref(bitmap.words), ctypes.POINTER(ctypes.c_uint))
bitmap.hdr.wordcount = AIM_BITMAP_WORD_COUNT(count)
class aim_bitmap_hdr(ctypes.Structure):
_fields_ = [("wordcount", ctypes.c_int,),
("words", ctypes.POINTER(aim_bitmap_word),),
("maxbit", ctypes.c_int,),
("allocated", ctypes.c_int,),]
class aim_bitmap(ctypes.Structure):
_fields_ = [("hdr", aim_bitmap_hdr,),]
class aim_bitmap_ref(aim_weakref.AimReference):
"""Dynamically allocated aim_bitmap."""
_fields_ = aim_bitmap._fields_
def __init__(self, bitcount):
ptr = libonlp.aim_bitmap_alloc(None, bitcount)
super(aim_bitmap_ref, self).__init__(ptr)
@classmethod
def deleteReference(self, aimPtr):
libonlp.aim_free(aimPtr)
class aim_bitmap256(aim_bitmap):
"""Statically-allocated AIM bitmap."""
_fields_ = [("words", aim_bitmap_word * AIM_BITMAP_WORD_COUNT(256),),]
def __init__(self):
super(aim_bitmap256, self).__init__()
AIM_BITMAP_INIT(self, 255)
def aim_bitmap_set(hdr, bit):
word = AIM_BITMAP_HDR_BIT_WORD_GET(hdr, bit)
word |= AIM_BITMAP_BIT_POS(bit)
AIM_BITMAP_HDR_BIT_WORD_SET(hdr, bit, word)
def aim_bitmap_clr(hdr, bit):
word = AIM_BITMAP_HDR_BIT_WORD_GET(hdr, bit)
word &= ~(AIM_BITMAP_BIT_POS(bit))
AIM_BITMAP_HDR_BIT_WORD_SET(hdr, bit, word)
def aim_bitmap_mod(hdr, bit, value):
if value:
aim_bitmap_set(hdr, bit)
else:
aim_bitmap_clr(hdr, bit)
def aim_bitmap_get(hdr, bit):
val = AIM_BITMAP_HDR_BIT_WORD_GET(hdr,bit) & AIM_BITMAP_BIT_POS(bit)
return 1 if val else 0
# Huh, these is inline too, but calls into glibc memset
def aim_bitmap_set_all(hdr):
libc.memset(ctypes.byref(hdr.words), 0xFF, hdr.wordcount*ctypes.sizeof(aim_bitmap_word))
def aim_bitmap_clr_all(hdr):
libc.memset(ctypes.byref(hdr.words), 0x00, hdr.wordcount*ctypes.sizeof(aim_bitmap_word))
# XXX aim_bitmap_count is left out
def aim_bitmap_init_prototypes():
libonlp.aim_bitmap_alloc.restype = ctypes.POINTER(aim_bitmap)
libonlp.aim_bitmap_alloc.argtypes = (ctypes.POINTER(aim_bitmap), ctypes.c_int,)
libonlp.aim_bitmap_free.restype = None
libonlp.aim_bitmap_free.argtypes = (ctypes.POINTER(aim_bitmap),)
# onlp.yml
##ONLP_CONFIG_INFO_STR_MAX = int(libonlp.onlp_config_lookup("ONLP_CONFIG_INFO_STR_MAX"))
ONLP_CONFIG_INFO_STR_MAX = 64
# prototype for onlp_config_lookup is not defined yet, see below
# onlp/oids.h
onlp_oid = ctypes.c_uint32
ONLP_OID_SYS = (ONLP_OID_TYPE.SYS<<24) | 1
# XXX not a config option
ONLP_OID_DESC_SIZE = 128
ONLP_OID_TABLE_SIZE = 32
# XXX not a config option
class OidTableIterator(object):
def __init__(self, hdr):
self.hdr = hdr
self.idx = 0
def __iter__(self):
return self
def next(self):
if self.idx >= ONLP_OID_TABLE_SIZE:
raise StopIteration
oid = self.hdr.coids[self.idx]
self.idx += 1
if oid == 0:
raise StopIteration
oidHdr = onlp_oid_hdr()
libonlp.onlp_oid_hdr_get(oid, ctypes.byref(oidHdr))
return oidHdr
class onlp_oid_hdr(ctypes.Structure):
_fields_ = [("_id", onlp_oid,),
("description", ctypes.c_char * ONLP_OID_DESC_SIZE,),
("poid", onlp_oid,),
("coids", onlp_oid * ONLP_OID_TABLE_SIZE,),]
def getType(self):
return self._id >> 24
def isSystem(self):
return self.getType() == ONLP_OID_TYPE.SYS
def isThermal(self):
return self.getType() == ONLP_OID_TYPE.THERMAL
def isFan(self):
return self.getType() == ONLP_OID_TYPE.FAN
def isPsu(self):
return self.getType() == ONLP_OID_TYPE.PSU
def isLed(self):
return self.getType() == ONLP_OID_TYPE.LED
def isModule(self):
return self.getType() == ONLP_OID_TYPE.MODULE
def isRtc(self):
return self.getType() == ONLP_OID_TYPE.RTC
def children(self):
return OidTableIterator(self)
onlp_oid_iterate_f = ctypes.CFUNCTYPE(ctypes.c_int, onlp_oid, ctypes.c_void_p)
def onlp_oid_init_prototypes():
libonlp.onlp_oid_dump.restype = None
libonlp.onlp_oid_dump.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs), ctypes.c_uint32,)
libonlp.onlp_oid_table_dump.restype = None
libonlp.onlp_oid_table_dump.argtypes = (ctypes.POINTER(onlp_oid), ctypes.POINTER(aim_pvs), ctypes.c_uint32,)
libonlp.onlp_oid_show.restype = None
libonlp.onlp_oid_show.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs), ctypes.c_uint32,)
libonlp.onlp_oid_table_show.restype = None
libonlp.onlp_oid_table_show.argtypes = (ctypes.POINTER(onlp_oid), ctypes.POINTER(aim_pvs), ctypes.c_uint32,)
libonlp.onlp_oid_iterate.restype = ctypes.c_int
libonlp.onlp_oid_iterate.argtypes = (onlp_oid, ctypes.c_int,
onlp_oid_iterate_f, ctypes.c_void_p,)
libonlp.onlp_oid_hdr_get.restype = ctypes.c_int
libonlp.onlp_oid_hdr_get.argtypes = (onlp_oid, ctypes.POINTER(onlp_oid_hdr,))
# onlp/sys.h
class onlp_sys_info(aim_weakref.AimStruct):
_fields_ = [("hdr", onlp_oid_hdr,),
("onie_info", onlp.onlplib.onlp_onie_info,),
("platform_info", onlp.onlplib.onlp_platform_info,),]
def __init__(self):
self.initialized = False
super(onlp_sys_info, self).__init__()
def deleteStruct(self):
initialized, self.initialized = self.initialized, False
if initialized:
libonlp.onlp_sys_info_free(ctypes.byref(self))
def onlp_sys_init_prototypes():
libonlp.onlp_sys_init.restype = ctypes.c_int
libonlp.onlp_sys_info_get.restype = ctypes.c_int
libonlp.onlp_sys_info_get.argtypes = (ctypes.POINTER(onlp_sys_info),)
libonlp.onlp_sys_info_free.restype = None
libonlp.onlp_sys_info_get.argtypes = (ctypes.POINTER(onlp_sys_info),)
libonlp.onlp_sys_hdr_get.restype = ctypes.c_int
libonlp.onlp_sys_hdr_get.argtypes = (ctypes.POINTER(onlp_oid_hdr),)
libonlp.onlp_sys_dump.restype = None
libonlp.onlp_sys_dump.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs), ctypes.c_uint32,)
libonlp.onlp_sys_show.restype = None
libonlp.onlp_sys_show.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs), ctypes.c_uint32,)
libonlp.onlp_sys_ioctl.restype = ctypes.c_int
# leave the parameters empty (varargs)
##libonlp.onlp_sys_vioctl.restype = ctypes.c_int
# NOTE that ctypes cannot automatically handle va_list
libonlp.onlp_sys_platform_manage_start.restype = ctypes.c_int
libonlp.onlp_sys_platform_manage_start.argtypes = (ctypes.c_int,)
libonlp.onlp_sys_platform_manage_stop.restype = ctypes.c_int
libonlp.onlp_sys_platform_manage_stop.argtypes = (ctypes.c_int,)
libonlp.onlp_sys_platform_manage_join.restype = ctypes.c_int
libonlp.onlp_sys_platform_manage_now.restype = None
libonlp.onlp_sys_debug.restype = ctypes.c_int
libonlp.onlp_sys_debug.argtypes = (ctypes.POINTER(aim_pvs), ctypes.c_int,
ctypes.POINTER(ctypes.POINTER(ctypes.c_char)),)
# onlp/fan.h
class onlp_fan_info(ctypes.Structure):
_fields_ = [("hdr", onlp_oid_hdr,),
("status", ctypes.c_uint32,),
("caps", ctypes.c_uint32,),
("rpm", ctypes.c_int,),
("percentage", ctypes.c_int,),
("mode", ctypes.c_uint32,),
("model", ctypes.c_char * ONLP_CONFIG_INFO_STR_MAX,),
("serial", ctypes.c_char * ONLP_CONFIG_INFO_STR_MAX,),]
def isPresent(self):
return self.status & ONLP_FAN_STATUS.PRESENT
def isMissing(self):
return not self.PRESENT()
def isFailed(self):
return self.status & ONLP_FAN_STATUS.FAILED
def isNormal(self):
return self.isPresent() and not self.isFailed()
def onlp_fan_init_prototypes():
libonlp.onlp_fan_init.restype = None
libonlp.onlp_fan_info_get.restype = ctypes.c_int
libonlp.onlp_fan_info_get.argtypes = (onlp_oid, ctypes.POINTER(onlp_fan_info),)
libonlp.onlp_fan_status_get.restype = ctypes.c_int
libonlp.onlp_fan_status_get.argtypes = (onlp_oid, ctypes.POINTER(ctypes.c_uint32),)
libonlp.onlp_fan_hdr_get.restype = ctypes.c_int
libonlp.onlp_fan_hdr_get.argtypes = (onlp_oid, ctypes.POINTER(onlp_oid_hdr),)
libonlp.onlp_fan_rpm_set.restype = ctypes.c_int
libonlp.onlp_fan_rpm_set.argtypes = (onlp_oid, ctypes.c_int,)
libonlp.onlp_fan_percentage_set.restype = ctypes.c_int
libonlp.onlp_fan_percentage_set.argtypes = (onlp_oid, ctypes.c_int,)
libonlp.onlp_fan_mode_set.restype = ctypes.c_int
libonlp.onlp_fan_mode_set.argtypes = (onlp_oid, ctypes.c_uint32,)
libonlp.onlp_fan_dir_set.restype = ctypes.c_int
libonlp.onlp_fan_dir_set.argtypes = (onlp_oid, ctypes.c_uint32,)
libonlp.onlp_fan_dump.restype = None
libonlp.onlp_fan_dump.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs), ctypes.c_uint32,)
libonlp.onlp_fan_show.restype = None
libonlp.onlp_fan_show.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs), ctypes.c_uint32,)
# onlp/led.h
class onlp_led_info(ctypes.Structure):
_fields_ = [("hdr", onlp_oid_hdr,),
("status", ctypes.c_uint32,),
("caps", ctypes.c_uint32,),
("mode", ctypes.c_uint32,),
("character", ctypes.c_char,),]
def onlp_led_init_prototypes():
libonlp.onlp_led_init.restype = None
libonlp.onlp_led_info_get.restype = ctypes.c_int
libonlp.onlp_led_info_get.argtypes = (onlp_oid, ctypes.POINTER(onlp_led_info),)
libonlp.onlp_led_status_get.restype = ctypes.c_int
libonlp.onlp_led_status_get.argtypes = (onlp_oid, ctypes.POINTER(ctypes.c_uint32),)
libonlp.onlp_led_hdr_get.restype = ctypes.c_int
libonlp.onlp_led_hdr_get.argtypes = (onlp_oid, ctypes.POINTER(onlp_oid_hdr),)
libonlp.onlp_led_set.restype = ctypes.c_int
libonlp.onlp_led_set.argtypes = (onlp_oid, ctypes.c_int,)
libonlp.onlp_led_mode_set.restype = ctypes.c_int
libonlp.onlp_led_mode_set.argtypes = (onlp_oid, ctypes.c_uint32,)
libonlp.onlp_led_char_set.restype = ctypes.c_int
libonlp.onlp_led_char_set.argtypes = (onlp_oid, ctypes.c_char,)
libonlp.onlp_led_dump.restype = None
libonlp.onlp_led_dump.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs), ctypes.c_uint32,)
libonlp.onlp_led_show.restype = None
libonlp.onlp_led_show.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs), ctypes.c_uint32,)
# onlp/onlp_config.h
# don't need the actual config structure, since we'll be using lookups
def onlp_config_init_prototypes():
libonlp.onlp_config_lookup.restype = ctypes.c_char_p
libonlp.onlp_config_lookup.argtypes = (ctypes.c_char_p,)
libonlp.onlp_config_show.restype = ctypes.c_int
libonlp.onlp_config_show.argtypes = (ctypes.POINTER(aim_pvs),)
# onlp/thermal.h
class onlp_thermal_info_thresholds(ctypes.Structure):
_fields_ = [('warning', ctypes.c_int,),
('error', ctypes.c_int,),
('shutdown', ctypes.c_int,),]
class onlp_thermal_info(ctypes.Structure):
_fields_ = [('hdr', onlp_oid_hdr,),
('status', ctypes.c_uint32,),
('caps', ctypes.c_uint32,),
('mcelcius', ctypes.c_int,),
('thresholds', onlp_thermal_info_thresholds,),]
def onlp_thermal_init_prototypes():
libonlp.onlp_thermal_init.restype = ctypes.c_int
libonlp.onlp_thermal_info_get.restype = ctypes.c_int
libonlp.onlp_thermal_info_get.argtypes = (onlp_oid, ctypes.POINTER(onlp_thermal_info),)
libonlp.onlp_thermal_status_get.restype = ctypes.c_int
libonlp.onlp_thermal_status_get.argtypes = (onlp_oid, ctypes.POINTER(ctypes.c_uint32),)
libonlp.onlp_thermal_hdr_get.restype = ctypes.c_int
libonlp.onlp_thermal_hdr_get.argtypes = (onlp_oid, ctypes.POINTER(onlp_oid_hdr),)
libonlp.onlp_thermal_ioctl.restype = ctypes.c_int
libonlp.onlp_thermal_dump.restype = None
libonlp.onlp_thermal_dump.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs),)
libonlp.onlp_thermal_show.restype = None
libonlp.onlp_thermal_show.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs),)
# onlp/psu.h
class onlp_psu_info(ctypes.Structure):
_fields_ = [("hdr", onlp_oid_hdr,),
("model", ctypes.c_char * ONLP_CONFIG_INFO_STR_MAX,),
("serial", ctypes.c_char * ONLP_CONFIG_INFO_STR_MAX,),
("status", ctypes.c_uint32,),
("caps", ctypes.c_uint32,),
("mvin", ctypes.c_int,),
("mvout", ctypes.c_int,),
("miin", ctypes.c_int,),
("miout", ctypes.c_int,),
("mpin", ctypes.c_int,),
("mpout", ctypes.c_int,),]
def onlp_psu_init_prototypes():
libonlp.onlp_psu_init.restype = ctypes.c_int
libonlp.onlp_psu_info_get.restype = ctypes.c_int
libonlp.onlp_psu_info_get.argtypes = (onlp_oid, ctypes.POINTER(onlp_psu_info),)
libonlp.onlp_psu_status_get.restype = ctypes.c_int
libonlp.onlp_psu_status_get.argtypes = (onlp_oid, ctypes.POINTER(ctypes.c_uint32),)
libonlp.onlp_psu_hdr_get.restype = ctypes.c_int
libonlp.onlp_psu_hdr_get.argtypes = (onlp_oid, ctypes.POINTER(onlp_oid_hdr),)
libonlp.onlp_psu_ioctl.restype = ctypes.c_int
libonlp.onlp_psu_dump.restype = None
libonlp.onlp_psu_dump.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs),)
libonlp.onlp_psu_show.restype = None
libonlp.onlp_psu_show.argtypes = (onlp_oid, ctypes.POINTER(aim_pvs),)
# sff/sff.h
def sff_init_prototypes():
libonlp.sff_sfp_type_get.restype = onlp.sff.sff_sfp_type
libonlp.sff_sfp_type_get.argtypes = (ctypes.POINTER(ctypes.c_ubyte),)
libonlp.sff_module_type_get.restype = onlp.sff.sff_module_type
libonlp.sff_module_type_get.argtypes = (ctypes.POINTER(ctypes.c_ubyte),)
libonlp.sff_media_type_get.restype = onlp.sff.sff_media_type
libonlp.sff_media_type_get.argtypes = (onlp.sff.sff_module_type,)
libonlp.sff_module_caps_get.restype = ctypes.c_int
libonlp.sff_module_caps_get.argtypes = (onlp.sff.sff_module_type, ctypes.POINTER(ctypes.c_uint32),)
libonlp.sff_eeprom_parse.restype = ctypes.c_int
libonlp.sff_eeprom_parse.argtypes = (ctypes.POINTER(onlp.sff.sff_eeprom), ctypes.POINTER(ctypes.c_ubyte),)
libonlp.sff_eeprom_parse_file.restype = ctypes.c_int
libonlp.sff_eeprom_parse_file.argtypes = (ctypes.POINTER(onlp.sff.sff_eeprom), ctypes.c_char_p,)
libonlp.sff_eeprom_invalidate.restype = None
libonlp.sff_eeprom_invalidate.argtypes = (ctypes.POINTER(onlp.sff.sff_eeprom),)
libonlp.sff_eeprom_validate.restype = ctypes.c_int
libonlp.sff_eeprom_validate.argtypes = (ctypes.POINTER(onlp.sff.sff_eeprom), ctypes.c_int,)
libonlp.sff_info_show.restype = None
libonlp.sff_info_show.argtypes = (ctypes.POINTER(onlp.sff.sff_info), ctypes.POINTER(aim_pvs),)
libonlp.sff_info_init.restype = ctypes.c_int
libonlp.sff_info_init.argtypes = (ctypes.POINTER(onlp.sff.sff_info), onlp.sff.sff_module_type,
ctypes.c_char_p, ctypes.c_char_p, ctypes.c_char_p,
ctypes.c_int,)
# onlp/sff.h
onlp_sfp_bitmap = aim_bitmap256
onlp_sfp_control = ctypes.c_int
def onlp_sfp_init_prototypes():
libonlp.onlp_sfp_init.restype = ctypes.c_int
libonlp.onlp_sfp_bitmap_t_init.restype = None
libonlp.onlp_sfp_bitmap_t_init.argtypes = (ctypes.POINTER(onlp_sfp_bitmap),)
libonlp.onlp_sfp_bitmap_get.restype = ctypes.c_int
libonlp.onlp_sfp_bitmap_get.argtypes = (ctypes.POINTER(onlp_sfp_bitmap),)
libonlp.onlp_sfp_port_valid.restype = ctypes.c_int
libonlp.onlp_sfp_port_valid.argtypes = (ctypes.c_int,)
libonlp.onlp_sfp_is_present.restype = ctypes.c_int
libonlp.onlp_sfp_is_present.argtypes = (ctypes.c_int,)
libonlp.onlp_sfp_presence_bitmap_get.restype = ctypes.c_int
libonlp.onlp_sfp_presence_bitmap_get.argtypes = (ctypes.POINTER(onlp_sfp_bitmap),)
libonlp.onlp_sfp_eeprom_read.restype = ctypes.c_int
libonlp.onlp_sfp_eeprom_read.argtypes = (ctypes.c_int, ctypes.POINTER(ctypes.POINTER(ctypes.c_ubyte,)),)
libonlp.onlp_sfp_dom_read.restype = ctypes.c_int
libonlp.onlp_sfp_dom_read.argtypes = (ctypes.c_int, ctypes.POINTER(ctypes.POINTER(ctypes.c_ubyte)),)
libonlp.onlp_sfp_denit.restype = ctypes.c_int
libonlp.onlp_sfp_rx_los_bitmap_get.restype = ctypes.c_int
libonlp.onlp_sfp_rx_los_bitmap_get.argtypes = (ctypes.POINTER(onlp_sfp_bitmap),)
libonlp.onlp_sfp_dev_readb.restype = ctypes.c_int
libonlp.onlp_sfp_dev_readb.argtypes = (ctypes.c_int, ctypes.c_ubyte, ctypes.c_ubyte,)
libonlp.onlp_sfp_dev_writeb.restype = ctypes.c_int
libonlp.onlp_sfp_dev_writeb.argtypes = (ctypes.c_int, ctypes.c_ubyte, ctypes.c_ubyte, ctypes.c_ubyte)
libonlp.onlp_sfp_dev_readw.restype = ctypes.c_int
libonlp.onlp_sfp_dev_readw.argtypes = (ctypes.c_int, ctypes.c_ubyte, ctypes.c_ubyte,)
libonlp.onlp_sfp_dev_writew.restype = ctypes.c_int
libonlp.onlp_sfp_dev_writew.argtypes = (ctypes.c_int, ctypes.c_ubyte, ctypes.c_ubyte, ctypes.c_ushort)
libonlp.onlp_sfp_dump.restype = None
libonlp.onlp_sfp_dump.argtypes = (ctypes.POINTER(aim_pvs),)
libonlp.onlp_sfp_ioctl.restype = ctypes.c_int
libonlp.onlp_sfp_post_insert.restype = ctypes.c_int
libonlp.onlp_sfp_post_insert.argtypes = (ctypes.c_int, ctypes.POINTER(onlp.sff.sff_info),)
libonlp.onlp_sfp_control_set.restype = ctypes.c_int
libonlp.onlp_sfp_control_set.argtypes = (ctypes.c_int, onlp_sfp_control, ctypes.c_int,)
libonlp.onlp_sfp_control_get.restype = ctypes.c_int
libonlp.onlp_sfp_control_get.argtypes = (ctypes.c_int, onlp_sfp_control, ctypes.POINTER(ctypes.c_int))
libonlp.onlp_sfp_control_flags_get.restype = ctypes.c_int
libonlp.onlp_sfp_control_flags_get.argtyeps = (ctypes.c_int, ctypes.POINTER(ctypes.c_uint32),)
# onlp/onlp.h
def init_prototypes():
aim_memory_init_prototypes()
aim_pvs_init_prototypes()
aim_bitmap_init_prototypes()
onlp_oid_init_prototypes()
onlp_sys_init_prototypes()
onlp_fan_init_prototypes()
onlp_led_init_prototypes()
onlp_config_init_prototypes()
strMax = int(libonlp.onlp_config_lookup("ONLP_CONFIG_INFO_STR_MAX"))
if ONLP_CONFIG_INFO_STR_MAX != strMax:
raise AssertionError("ONLP_CONFIG_INFO_STR_MAX changed from %d to %d"
% (ONLP_CONFIG_INFO_STR_MAX, strMax,))
onlp_thermal_init_prototypes()
onlp_psu_init_prototypes()
sff_init_prototypes()
onlp_sfp_init_prototypes()
init_prototypes()

View File

@@ -0,0 +1,94 @@
"""aim_weakref.py
Use weakref to implement smart AIM pointers.
See e.g.
http://code.activestate.com/recipes/577242-calling-c-level-finalizers-without-__del__/
"""
import ctypes
import logging
import weakref
logger = logging.getLogger("weakref")
def getLogger():
global logger
return logger
class AimOwnerRef(weakref.ref):
pass
def _run_finalizer(ref):
"""Internal weakref callback to run finalizers"""
del _finalize_refs[id(ref)]
finalizer = ref.finalizer
item = ref.item
try:
finalizer(item)
except Exception:
getLogger().exception("finalizer failed")
_finalize_refs = {}
def track_for_finalization(owner, item, finalizer):
"""Register an object for finalization.
``owner`` is the the object which is responsible for ``item``.
``finalizer`` will be called with ``item`` as its only argument when
``owner`` is destroyed by the garbage collector.
"""
ref = AimOwnerRef(owner, _run_finalizer)
ref.item = item
ref.finalizer = finalizer
_finalize_refs[id(ref)] = ref
class AimReference(object):
"""Manage an AIM pointer using reference semantics."""
@classmethod
def deleteReference(cls, aimPtr):
"""Override this with the proper delete semantics."""
raise NotImplementedError
def __init__(self, aimPtr):
self.ptr = aimPtr
track_for_finalization(self, self.ptr, self.deleteReference)
def __getattr__(self, attr, dfl='__none__'):
if dfl == '__none__':
return getattr(self.ptr.contents, attr)
else:
return getattr(self.ptr.contents, attr, dfl)
def __setattr___(self, attr, val):
setattr(self.ptr.contents, attr, val)
class AimPointer(ctypes.c_void_p):
"""Manage an AIM pointer using pointer semantics."""
@classmethod
def deletePointer(cls, aimPtr):
"""Override this with the proper delete semantics."""
raise NotImplementedError
def __init__(self, aimPtr):
super(ctypes.c_void_p, self).__init__(aimPtr)
# XXX roth -- casting may be necessary
track_for_finalization(self, aimPtr, self.deletePointer)
class AimStruct(ctypes.Structure):
"""Manage an AIM struct with internally-allocated data."""
@classmethod
def deleteStruct(cls, aimPtr):
"""Override this with the proper delete semantics."""
raise NotImplementedError
def __init__(self):
super(ctypes.Structure, self).__init__()
track_for_finalization(self, self, self.deleteStruct)

View File

@@ -88,6 +88,17 @@ class ONLP_LED_STATUS(Enumeration):
ON = (1 << 2)
class ONLP_OID_DUMP(Enumeration):
RECURSE = (1 << 0)
EVEN_IF_ABSENT = (1 << 1)
class ONLP_OID_SHOW(Enumeration):
RECURSE = (1 << 0)
EXTENDED = (1 << 1)
YAML = (1 << 2)
class ONLP_OID_TYPE(Enumeration):
SYS = 1
THERMAL = 2

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,4 @@
"""__init__.py
Test code for the onlp Python bindings.
"""

View File

@@ -281,7 +281,7 @@ onlp_fan_show(onlp_oid_t oid, aim_pvs_t* pvs, uint32_t flags)
rv = onlp_fan_info_get(oid, &fi);
yaml = flags & ONLP_OID_SHOW_F_YAML;
yaml = flags & ONLP_OID_SHOW_YAML;
if(yaml) {
iof_push(&iof, "- ");

View File

@@ -215,7 +215,7 @@ onlp_led_show(onlp_oid_t id, aim_pvs_t* pvs, uint32_t flags)
VALIDATENR(id);
onlp_oid_show_iof_init_default(&iof, pvs, flags);
yaml = flags & ONLP_OID_SHOW_F_YAML;
yaml = flags & ONLP_OID_SHOW_YAML;
if(yaml) {
iof_push(&iof, " -");

View File

@@ -216,7 +216,7 @@ onlp_oid_iterate(onlp_oid_t oid, onlp_oid_type_t type,
}
ONLP_OID_TABLE_ITER(hdr.coids, oidp) {
if(type == 0 || ONLP_OID_IS_TYPE(*oidp, type)) {
if(type == 0 || ONLP_OID_IS_TYPE(type, *oidp)) {
int rv = itf(*oidp, cookie);
if(rv < 0) {
return rv;

View File

@@ -145,7 +145,7 @@ onlp_config_lookup(const char* setting)
{
int i;
for(i = 0; onlp_config_settings[i].name; i++) {
if(strcmp(onlp_config_settings[i].name, setting)) {
if(!strcmp(onlp_config_settings[i].name, setting)) {
return onlp_config_settings[i].value;
}
}

View File

@@ -519,6 +519,128 @@ onlp_led_status_valid(onlp_led_status_t e)
}
aim_map_si_t onlp_oid_dump_map[] =
{
{ "RECURSE", ONLP_OID_DUMP_RECURSE },
{ "EVEN_IF_ABSENT", ONLP_OID_DUMP_EVEN_IF_ABSENT },
{ NULL, 0 }
};
aim_map_si_t onlp_oid_dump_desc_map[] =
{
{ "None", ONLP_OID_DUMP_RECURSE },
{ "None", ONLP_OID_DUMP_EVEN_IF_ABSENT },
{ NULL, 0 }
};
const char*
onlp_oid_dump_name(onlp_oid_dump_t e)
{
const char* name;
if(aim_map_si_i(&name, e, onlp_oid_dump_map, 0)) {
return name;
}
else {
return "-invalid value for enum type 'onlp_oid_dump'";
}
}
int
onlp_oid_dump_value(const char* str, onlp_oid_dump_t* e, int substr)
{
int i;
AIM_REFERENCE(substr);
if(aim_map_si_s(&i, str, onlp_oid_dump_map, 0)) {
/* Enum Found */
*e = i;
return 0;
}
else {
return -1;
}
}
const char*
onlp_oid_dump_desc(onlp_oid_dump_t e)
{
const char* name;
if(aim_map_si_i(&name, e, onlp_oid_dump_desc_map, 0)) {
return name;
}
else {
return "-invalid value for enum type 'onlp_oid_dump'";
}
}
int
onlp_oid_dump_valid(onlp_oid_dump_t e)
{
return aim_map_si_i(NULL, e, onlp_oid_dump_map, 0) ? 1 : 0;
}
aim_map_si_t onlp_oid_show_map[] =
{
{ "RECURSE", ONLP_OID_SHOW_RECURSE },
{ "EXTENDED", ONLP_OID_SHOW_EXTENDED },
{ "YAML", ONLP_OID_SHOW_YAML },
{ NULL, 0 }
};
aim_map_si_t onlp_oid_show_desc_map[] =
{
{ "None", ONLP_OID_SHOW_RECURSE },
{ "None", ONLP_OID_SHOW_EXTENDED },
{ "None", ONLP_OID_SHOW_YAML },
{ NULL, 0 }
};
const char*
onlp_oid_show_name(onlp_oid_show_t e)
{
const char* name;
if(aim_map_si_i(&name, e, onlp_oid_show_map, 0)) {
return name;
}
else {
return "-invalid value for enum type 'onlp_oid_show'";
}
}
int
onlp_oid_show_value(const char* str, onlp_oid_show_t* e, int substr)
{
int i;
AIM_REFERENCE(substr);
if(aim_map_si_s(&i, str, onlp_oid_show_map, 0)) {
/* Enum Found */
*e = i;
return 0;
}
else {
return -1;
}
}
const char*
onlp_oid_show_desc(onlp_oid_show_t e)
{
const char* name;
if(aim_map_si_i(&name, e, onlp_oid_show_desc_map, 0)) {
return name;
}
else {
return "-invalid value for enum type 'onlp_oid_show'";
}
}
int
onlp_oid_show_valid(onlp_oid_show_t e)
{
return aim_map_si_i(NULL, e, onlp_oid_show_map, 0) ? 1 : 0;
}
aim_map_si_t onlp_oid_type_map[] =
{
{ "SYS", ONLP_OID_TYPE_SYS },

View File

@@ -203,8 +203,8 @@ onlpdump_main(int argc, char* argv[])
switch(c)
{
case 's': show=1; break;
case 'r': show=1; showflags |= ONLP_OID_SHOW_F_RECURSE; break;
case 'e': show=1; showflags |= ONLP_OID_SHOW_F_EXTENDED; break;
case 'r': show=1; showflags |= ONLP_OID_SHOW_RECURSE; break;
case 'e': show=1; showflags |= ONLP_OID_SHOW_EXTENDED; break;
case 'd': show=0; break;
case 'h': help=1; rv = 0; break;
case 'j': j=1; break;
@@ -220,7 +220,7 @@ onlpdump_main(int argc, char* argv[])
case 'l': l=1; break;
case 'b': b=1; break;
case 'J': J = optarg; break;
case 'y': show=1; showflags |= ONLP_OID_SHOW_F_YAML; break;
case 'y': show=1; showflags |= ONLP_OID_SHOW_YAML; break;
default: help=1; rv = 1; break;
}
}
@@ -305,8 +305,8 @@ onlpdump_main(int argc, char* argv[])
int oid;
if(sscanf(O, "0x%x", &oid) == 1) {
onlp_oid_dump(oid, &aim_pvs_stdout,
ONLP_OID_DUMP_F_RECURSE |
ONLP_OID_DUMP_F_EVEN_IF_ABSENT);
ONLP_OID_DUMP_RECURSE |
ONLP_OID_DUMP_EVEN_IF_ABSENT);
}
return 0;
}
@@ -349,7 +349,7 @@ onlpdump_main(int argc, char* argv[])
if(show == 0) {
/* Default to full dump */
onlp_platform_dump(&aim_pvs_stdout,
ONLP_OID_DUMP_F_RECURSE | ONLP_OID_DUMP_F_EVEN_IF_ABSENT);
ONLP_OID_DUMP_RECURSE | ONLP_OID_DUMP_EVEN_IF_ABSENT);
}
else {
onlp_platform_show(&aim_pvs_stdout,

View File

@@ -69,7 +69,7 @@ onlp_psu_status_get_locked__(onlp_oid_t id, uint32_t* status)
}
if(ONLP_UNSUPPORTED(rv)) {
onlp_psu_info_t pi;
rv = onlp_psu_info_get(id, &pi);
rv = onlp_psui_info_get(id, &pi);
*status = pi.status;
}
return rv;
@@ -143,7 +143,7 @@ onlp_psu_dump(onlp_oid_t id, aim_pvs_t* pvs, uint32_t flags)
iof_iprintf(&iof, "Iout: %d", info.miout);
iof_iprintf(&iof, "Pin: %d", info.mpin);
iof_iprintf(&iof, "Pout: %d", info.mpout);
if(flags & ONLP_OID_DUMP_F_RECURSE) {
if(flags & ONLP_OID_DUMP_RECURSE) {
onlp_oid_table_dump(info.hdr.coids, &iof.inherit, flags);
}
}
@@ -165,7 +165,7 @@ onlp_psu_show(onlp_oid_t id, aim_pvs_t* pvs, uint32_t flags)
onlp_oid_show_iof_init_default(&iof, pvs, flags);
rv = onlp_psu_info_get(id, &pi);
yaml = flags & ONLP_OID_SHOW_F_YAML;
yaml = flags & ONLP_OID_SHOW_YAML;
if(yaml) {
iof_push(&iof, "- ");
@@ -235,7 +235,7 @@ onlp_psu_show(onlp_oid_t id, aim_pvs_t* pvs, uint32_t flags)
ONLP_MILLI_NORMAL_INTEGER_TENTHS(pi.mpout));
}
if(flags & ONLP_OID_SHOW_F_RECURSE) {
if(flags & ONLP_OID_SHOW_RECURSE) {
/*
* Display sub oids.
*
@@ -264,7 +264,7 @@ onlp_psu_show(onlp_oid_t id, aim_pvs_t* pvs, uint32_t flags)
iof_pop(&iof);
}
if(flags & ONLP_OID_SHOW_F_EXTENDED) {
if(flags & ONLP_OID_SHOW_EXTENDED) {
/* Include all other types as well. */
ONLP_OID_TABLE_ITER_TYPE(pi.hdr.coids, oidp, LED) {
onlp_oid_show(*oidp, &iof.inherit, flags);

View File

@@ -143,7 +143,8 @@ onlp_sys_info_get_locked__(onlp_sys_info_t* rv)
}
else {
if(onlp_sysi_onie_info_get(&rv->onie_info) != 0) {
return ONLP_STATUS_E_INTERNAL;
memset(&rv->onie_info, 0, sizeof(rv->onie_info));
list_init(&rv->onie_info.vx_list);
}
}
@@ -214,7 +215,7 @@ onlp_sys_show(onlp_oid_t id, aim_pvs_t* pvs, uint32_t flags)
int yaml;
onlp_oid_show_iof_init_default(&iof, pvs, flags);
yaml = (flags & ONLP_OID_SHOW_F_YAML);
yaml = (flags & ONLP_OID_SHOW_YAML);
if(id && ONLP_OID_TYPE_GET(id) != ONLP_OID_TYPE_SYS) {
return;
@@ -234,14 +235,14 @@ onlp_sys_show(onlp_oid_t id, aim_pvs_t* pvs, uint32_t flags)
* unless you specify EXTENDED or !RECURSIVE
*/
if(yaml ||
flags & ONLP_OID_SHOW_F_EXTENDED ||
(flags & ONLP_OID_SHOW_F_RECURSE) == 0) {
flags & ONLP_OID_SHOW_EXTENDED ||
(flags & ONLP_OID_SHOW_RECURSE) == 0) {
iof_push(&iof, "System Information:");
onlp_onie_show(&si.onie_info, &iof.inherit);
iof_pop(&iof);
}
if(flags & ONLP_OID_SHOW_F_RECURSE) {
if(flags & ONLP_OID_SHOW_RECURSE) {
onlp_oid_t* oidp;
@@ -266,7 +267,7 @@ onlp_sys_show(onlp_oid_t id, aim_pvs_t* pvs, uint32_t flags)
}
YPOP();
if(flags & ONLP_OID_SHOW_F_EXTENDED) {
if(flags & ONLP_OID_SHOW_EXTENDED) {
/** Show all LEDs */
YPUSH("LEDs:");
ONLP_OID_TABLE_ITER_TYPE(si.hdr.coids, oidp, LED) {

View File

@@ -202,7 +202,7 @@ onlp_thermal_show(onlp_oid_t id, aim_pvs_t* pvs, uint32_t flags)
rv = onlp_thermal_info_get(id, &ti);
yaml = flags & ONLP_OID_SHOW_F_YAML;
yaml = flags & ONLP_OID_SHOW_YAML;
if(yaml) {
iof_push(&iof, "- ");

Some files were not shown because too many files have changed in this diff Show More