From 0df155b0141939735cb6180110964df1414e277e Mon Sep 17 00:00:00 2001 From: Vivek Date: Mon, 10 Apr 2023 09:48:27 -0700 Subject: [PATCH] Made non-upstream patch design order aware (#14434) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Why I did it Currently, non upstream patches are applied only after upstream patches. Depends on sonic-net/sonic-linux-kernel#313. Can be merged in any order, preferably together - What I did it Non upstream Patches that reside in the sonic repo will not be saved in a tar file bur rather in a folder pointed out by EXTERNAL_KERNEL_PATCH_LOC. This is to make changes to the non upstream patches easily traceable. The build variable name is also updated to INCLUDE_EXTERNAL_PATCHES Files/folders expected under EXTERNAL_KERNEL_PATCH_LOC EXTERNAL_KERNEL_PATCH_LOC/ ├──── patches/ ├── 0001-xxxxx.patch ├── 0001-yyyyyyyy.patch ├── ............. ├──── series.patch series.patch should contain a diff that is applied on the sonic-linux-kernel/patch/series file. The diff should include all the non-upstream patches. How to verify it Build the Kernel and verified if all the patches are applied properly Signed-off-by: Vivek Reddy Karri --- .../mellanox/non-upstream-patches/README.md | 43 +- .../non-upstream-patches/patches.tar.gz | Bin 83191 -> 0 bytes ...-Fix-variable-names-for-hwmon-attrib.patch | 255 ++++ ...al-Rename-labels-according-to-naming.patch | 162 +++ ...al-Remove-obsolete-API-for-query-res.patch | 110 ++ ...pir_-prefix-to-MGPIR-fields-comments.patch | 51 + ...lxsw-core-Remove-unnecessary-asserts.patch | 102 ++ ...-MTMP-register-with-new-slot-number-.patch | 146 +++ ...-MTBR-register-with-new-slot-number-.patch | 87 ++ ...-MCIA-register-with-new-slot-number-.patch | 108 ++ ...-MCION-register-with-new-slot-number.patch | 68 ++ ...-PMMP-register-with-new-slot-number-.patch | 67 ++ ...-MGPIR-register-with-new-slot-fields.patch | 198 +++ ...ass-slot-index-during-PMAOS-register.patch | 66 + ...w-field-to-Management-General-Periph.patch | 38 + ...d-interfaces-for-cable-info-access-w.patch | 828 +++++++++++++ ...d-port-module-data-structures-for-li.patch | 520 ++++++++ ...port-module-events-enablement-to-a-s.patch | 92 ++ ...e_hwmon-Split-gearbox-initialization.patch | 121 ++ ...-Extend-internal-structures-to-suppo.patch | 541 +++++++++ ...-Introduce-slot-parameter-in-hwmon-i.patch | 129 ++ ...-Extend-hwmon-device-with-gearbox-ma.patch | 136 +++ ...al-Extend-internal-structures-to-sup.patch | 367 ++++++ ...thermal-Split-gearbox-initialization.patch | 137 +++ ...al-Extend-thermal-area-with-gearbox-.patch | 127 ++ ...al-Add-line-card-id-prefix-to-line-c.patch | 59 + ...al-Use-exact-name-of-cooling-devices.patch | 35 + ...al-Use-common-define-for-thermal-zon.patch | 48 + ...ort-to-create-line-card-and-expose-t.patch | 531 +++++++++ ...ink-implement-line-card-provisioning.patch | 554 +++++++++ ...ink-implement-line-card-active-state.patch | 98 ++ ...d-port-to-line-card-relationship-set.patch | 101 ++ ...-introduce-linecard-info-get-message.patch | 245 ++++ ...-introduce-linecard-info-get-message.patch | 315 +++++ ...rts-Mapping-event-Configuration-Regi.patch | 98 ++ ...nagement-DownStream-Device-Query-Reg.patch | 267 +++++ ...nagement-DownStream-Device-Control-R.patch | 70 ++ ...nagement-Binary-Code-Transfer-Regist.patch | 154 +++ ...ards-Add-line-card-objects-and-imple.patch | 1062 +++++++++++++++++ ...ards-Implement-line-card-activation-.patch | 205 ++++ ...d-driver-ops-by-remove-selected-port.patch | 98 ++ ...pectrum-Add-port-to-linecard-mapping.patch | 152 +++ ...uce-Management-Temperature-Extended-.patch | 105 ++ ...-Add-APIs-for-thermal-sensor-mapping.patch | 113 ++ ...nagement-DownStream-Device-Tunneling.patch | 126 ++ ...ards-Probe-devices-for-provisioned-l.patch | 224 ++++ ...ards-Expose-device-FW-version-over-d.patch | 177 +++ ...re-Introduce-flash-update-components.patch | 243 ++++ ...ID-value-using-op-instead-of-passing.patch | 200 ++++ ...ards-Implement-line-card-device-flas.patch | 400 +++++++ ...ards-Introduce-ops-for-linecards-sta.patch | 277 +++++ ...nterfaces-for-line-card-initializati.patch | 133 +++ ...al-Add-interfaces-for-line-card-init.patch | 213 ++++ ...-Add-interfaces-for-line-card-initia.patch | 235 ++++ ...epare-driver-for-modular-system-supp.patch | 495 ++++++++ ...d-bus-init-function-with-event-handl.patch | 90 ++ ...d-support-for-system-events-handling.patch | 198 +++ ...0154-mlxsw-core-Export-line-card-API.patch | 27 + ...xsw-minimal-Add-system-event-handler.patch | 61 + ...d-interfaces-for-line-card-initializ.patch | 119 ++ ...x-Introduce-support-for-rack-manager.patch | 420 +++++++ ...x-fix-reset_pwr_converter_fail-attri.patch | 30 + ...I-fix-description-of-fix-reset_pwr_c.patch | 38 + ...x-Introduce-support-for-next-generat.patch | 295 +++++ .../non-upstream-patches/series.patch | 86 ++ platform/mellanox/rules.mk | 4 +- rules/linux-kernel.mk | 10 +- 67 files changed, 12879 insertions(+), 31 deletions(-) delete mode 100644 platform/mellanox/non-upstream-patches/patches.tar.gz create mode 100644 platform/mellanox/non-upstream-patches/patches/0099-mlxsw-core_hwmon-Fix-variable-names-for-hwmon-attrib.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0100-mlxsw-core_thermal-Rename-labels-according-to-naming.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0101-mlxsw-core_thermal-Remove-obsolete-API-for-query-res.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0102-mlxsw-reg-Add-mgpir_-prefix-to-MGPIR-fields-comments.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0103-mlxsw-core-Remove-unnecessary-asserts.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0104-mlxsw-reg-Extend-MTMP-register-with-new-slot-number-.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0105-mlxsw-reg-Extend-MTBR-register-with-new-slot-number-.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0106-mlxsw-reg-Extend-MCIA-register-with-new-slot-number-.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0107-mlxsw-reg-Extend-MCION-register-with-new-slot-number.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0108-mlxsw-reg-Extend-PMMP-register-with-new-slot-number-.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0109-mlxsw-reg-Extend-MGPIR-register-with-new-slot-fields.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0110-mlxsw-core_env-Pass-slot-index-during-PMAOS-register.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0111-mlxsw-reg-Add-new-field-to-Management-General-Periph.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0112-mlxsw-core-Extend-interfaces-for-cable-info-access-w.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0113-mlxsw-core-Extend-port-module-data-structures-for-li.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0114-mlxsw-core-Move-port-module-events-enablement-to-a-s.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0115-mlxsw-core_hwmon-Split-gearbox-initialization.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0116-mlxsw-core_hwmon-Extend-internal-structures-to-suppo.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0117-mlxsw-core_hwmon-Introduce-slot-parameter-in-hwmon-i.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0118-mlxsw-core_hwmon-Extend-hwmon-device-with-gearbox-ma.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0119-mlxsw-core_thermal-Extend-internal-structures-to-sup.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0120-mlxsw-core_thermal-Split-gearbox-initialization.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0121-mlxsw-core_thermal-Extend-thermal-area-with-gearbox-.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0122-mlxsw-core_thermal-Add-line-card-id-prefix-to-line-c.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0123-mlxsw-core_thermal-Use-exact-name-of-cooling-devices.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0124-mlxsw-core_thermal-Use-common-define-for-thermal-zon.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0125-devlink-add-support-to-create-line-card-and-expose-t.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0126-devlink-implement-line-card-provisioning.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0127-devlink-implement-line-card-active-state.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0128-devlink-add-port-to-line-card-relationship-set.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0129-devlink-introduce-linecard-info-get-message.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0130-devlink-introduce-linecard-info-get-message.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0131-mlxsw-reg-Add-Ports-Mapping-event-Configuration-Regi.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0132-mlxsw-reg-Add-Management-DownStream-Device-Query-Reg.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0133-mlxsw-reg-Add-Management-DownStream-Device-Control-R.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0134-mlxsw-reg-Add-Management-Binary-Code-Transfer-Regist.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0135-mlxsw-core_linecards-Add-line-card-objects-and-imple.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0136-mlxsw-core_linecards-Implement-line-card-activation-.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0137-mlxsw-core-Extend-driver-ops-by-remove-selected-port.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0138-mlxsw-spectrum-Add-port-to-linecard-mapping.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0139-mlxsw-reg-Introduce-Management-Temperature-Extended-.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0140-mlxsw-core-Add-APIs-for-thermal-sensor-mapping.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0141-mlxsw-reg-Add-Management-DownStream-Device-Tunneling.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0142-mlxsw-core_linecards-Probe-devices-for-provisioned-l.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0143-mlxsw-core_linecards-Expose-device-FW-version-over-d.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0144-mlxsw-core-Introduce-flash-update-components.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0145-mlxfw-Get-the-PSID-value-using-op-instead-of-passing.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0146-mlxsw-core_linecards-Implement-line-card-device-flas.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0147-mlxsw-core_linecards-Introduce-ops-for-linecards-sta.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0148-mlxsw-core-Add-interfaces-for-line-card-initializati.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0149-mlxsw-core_thermal-Add-interfaces-for-line-card-init.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0150-mlxsw-core_hwmon-Add-interfaces-for-line-card-initia.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0151-mlxsw-minimal-Prepare-driver-for-modular-system-supp.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0152-mlxsw-core-Extend-bus-init-function-with-event-handl.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0153-mlxsw-i2c-Add-support-for-system-events-handling.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0154-mlxsw-core-Export-line-card-API.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0155-mlxsw-minimal-Add-system-event-handler.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0156-mlxsw-minimal-Add-interfaces-for-line-card-initializ.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0163-platform-mellanox-Introduce-support-for-rack-manager.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0176-platform-mellanox-fix-reset_pwr_converter_fail-attri.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0177-Documentation-ABI-fix-description-of-fix-reset_pwr_c.patch create mode 100644 platform/mellanox/non-upstream-patches/patches/0178-platform-mellanox-Introduce-support-for-next-generat.patch create mode 100644 platform/mellanox/non-upstream-patches/series.patch diff --git a/platform/mellanox/non-upstream-patches/README.md b/platform/mellanox/non-upstream-patches/README.md index 9138d750cbf4..a4393d818d78 100644 --- a/platform/mellanox/non-upstream-patches/README.md +++ b/platform/mellanox/non-upstream-patches/README.md @@ -1,31 +1,26 @@ ## Mellanox non-upstream linux kernel patches ## -To include non-upstream patches into the sonic-linux image during build time, this folder must contain a patch archive. - -### Structure of the patch archive - - 1. It should contain a file named series. series should provide an order in which the patches have to be applied - ``` - admin@build-server:/sonic-buildimage/src/sonic-linux-kernel$ cat linux-5.10.103/non_upstream_patches/series - mlx5-Refactor-module-EEPROM-query.patch - mlx5-Implement-get_module_eeprom_by_page.patch - mlx5-Add-support-for-DSFP-module-EEPROM-dumps.patch - ``` - 2. All the patches should be present in the same folder where series resides. - 3. Developers should make sure patches apply cleanly over the existing patches present in the src/sonic-linux-kernel . - 4. Name of the tarball should match with the one specified under EXTERNAL_KERNEL_PATCH_TAR +To include non-upstream patches into the sonic-linux image during build time, the `INCLUDE_EXTERNAL_PATCHES=y` flag has to be provided. By default, the directory pointed by EXTERNAL_KERNEL_PATCH_LOC will be used and it must follow the following structure. To use a publicly accessible tar of the non-upstream patches, also provide the `EXTERNAL_KERNEL_PATCH_URL` variable + +### Directory Structure -#### Example ``` -admin@build-server:/sonic-buildimage/platform/mellanox/non-upstream-patches$ tar -tf patches.tar.gz -./ -./mlx5-Implement-get_module_eeprom_by_page.patch -./mlx5-Add-support-for-DSFP-module-EEPROM-dumps.patch -./series -./mlx5-Refactor-module-EEPROM-query.patch +EXTERNAL_KERNEL_PATCH_LOC/ + ├──── patches/ + ├── 0001-mlx5-Refactor-module-EEPROM-query.patch.patch + ├── 0002-mlx5-Implement-get_module_eeprom_by_page.patch.patch + ├── 0005-mlx5-Add-support-for-DSFP-module-EEPROM-dumps.patch + ├── ............. + ├──── series.patch ``` -### Include the archive while building sonic linux kernel + 1. It should contain a file named series.patch. This should contain a diff that is applied on the sonic-linux-kernel/patch/series file. The diff should include all the non-upstream patches. + 2. All the patches should be present in the patches folder + 3. Developers should make sure patches apply cleanly over the existing patches present in the src/sonic-linux-kernel . + + +### Include the non upstream patches while building sonic linux kernel + +Set `INCLUDE_EXTERNAL_PATCHES=y` using `SONIC_OVERRIDE_BUILD_VARS` to include these changes before building the kernel. +- Eg: `NOJESSIE=1 NOSTRETCH=1 NOBUSTER=1 make SONIC_OVERRIDE_BUILD_VARS=' INCLUDE_EXTERNAL_PATCHES=y ' target/debs/bullseye/linux-headers-5.10.0-12-2-common_5.10.103-1_all.deb` -Set `INCLUDE_EXTERNAL_PATCH_TAR=y` using `SONIC_OVERRIDE_BUILD_VARS` to include these changes before building the kernel. -- Eg: `NOJESSIE=1 NOSTRETCH=1 NOBUSTER=1 make SONIC_OVERRIDE_BUILD_VARS=' INCLUDE_EXTERNAL_PATCH_TAR=y ' target/debs/bullseye/linux-headers-5.10.0-12-2-common_5.10.103-1_all.deb` diff --git a/platform/mellanox/non-upstream-patches/patches.tar.gz b/platform/mellanox/non-upstream-patches/patches.tar.gz deleted file mode 100644 index ea77e556ed0df8eddf44910896e43f9051f584ad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 83191 zcmV(=K-s?^iwFoM81G{M18`wmVIUlNH^Q|Ud8XxKAuz`{7Thor*h4c(BG2kh%)}l&Y4Q=_qp2#C zlBVej{VpmRD@9q=B>9P?Dw?F}sv=8I;1>KnL1H85cl=D_#EcMn5+`^v!a=;Kp5smK z1D*T+97W+6sXfQmWy>~2xu*fIB+1bnv5!Sj@AWmQ?>JV^(H#+;h5@?36C~+K6!+;L zl7X!)0%jlmVmjU!otZ$(C@}v-udm6C$&bOc=Xhq<4#x+rcV>e3(NW}ekb>S}8`{ef zlB9jLzpqMYPXu_ai>dVm+sQuq{p|4a?T0@QmC${ZiztBbZcr+th{`Ae8AbFdVlp~S zaNKI0N|+YP=aP&GU9DtAkzk99WS^-Nr;jWMG?NW>@c{-LE?o$2gM;r;05wxWRJ|?3Ol4e z2hwe|F1)J%J3{EXf_2-B!sqzf!!u|^8vKtJdFafG{tVIUFK}I|Spk0Rgy_N^dE+tm z(QD5MV|!GpF9<>lb-Ue{0Zv|G7*s?qptf%Y;mu2m^vj$_T^pf)kglP<^dn@S7Lt(b z0V(;YK^pqV3t}7*(!@J^ZF(uurl9L3FXvDR+V@&X6n zAV-x<*KsYU+g0>_-w|c2ha@_u5t3|xOABbR2|hpmh=iWrkyNzD3b+BXmv}acWAATl zB&aC52_8=j5YgFAoJ3PQ0dih@pb5KBc3S8ud=UARo*J3%pj~oVtO(4C(5^Lg+b#6p zmhhA}tf~vzt*RAz)7o2B`=(l(^a-kxm|lP*BXoBtDrf>$_lW6TTM2u7RXN1FaM#nJ6fsW&3|9h4D~!h~6Y zg9a!>8~P&E239oC20(g+Mm%k#4o@F-VVk-@`0}U^ThIqdR5}B+$BG8}5XFfRCjfbw zLNwF}aL^{g?#$8q>^-;(}1cKAM(;-U|F&(V98`IOZ z!~v3fy@iX3J7^yOzpMT+5c3*1i@XHiuLjaC%Ni)lDh+n=GG_;2S#e-|-9wjnu#8%v zg=^>`qFwDyDCkGc+dS?y?IXsddGkYW*P@q8DiX>IUA}^~!)cIE707`s7Wd^qR>ZL? z<2wEH?&p)Cas2V!@UwAx{1NT(@iFNklJm_%Ua}^2q#mdRE0@nwMb&7uifOuxd0fXd z)(k7EYQ|6J)nHeuADw(nGnF(NEB;PYhK!P_3>|M-WnjQR9bODedQ+n_(&ma{MO0B} z-&|1?QK8EeUN*BIHrOH0HvQ#>q+uxQ>7)5rsU+WnX(&o04z5cAlZ+w^bE@yeRAg$z zv?%3F&@Yb8jLRX|kq^i3KN!Cro`38hE+rL5ipsH~GdX5uGdad%99`kSzFj5AO{e=u zQGOKVm7;uja(I5aRF-v^izSd{R>G}C0_>X>_E$%a8v63zg|D(O4Ch7w5KYVg`{+NS zLW6QJh;)&%GK8O3Tpq3eN>C_!lZ3UDw{Rp$-B0#+Kyv6R=10L zgMn^ornq79ZVr0Q^xeE6aUN7rqAnjV>y|IPLF)fmFqG7RNFV(j2G~fwiRABc#EO2v zkC=e1@&bdv$JNJ|ABN|rhbP9bLvU0tjd#PN!=Fzs+5RkdQqgN9wuxW$^eO~(fIAcw zaGpb=E4+K^P~|mB2-a37JHDBv6zPIs0qFhKUK5b}0FLPM&KI!f9(erHEA#~&yaC|o ziy+X=h7ycvPy=O$Q4xLVAR8_yC5ju>EZvkQSg|5=`^xMh5q+|yC zxp%xNn|X5}j&LwBBe2f-*cWm>Z^Syyzc=DNufBls72r)c&zn>@TLF}FR}faQu+Vg# zjp@Usd@NK-8L83D;DIKy$#33X6&YB^tolfH*6aM9s!gNVP%Ph5t!|!9qR^t7r!m_- z6$)G;12r=F*eg8AFiK5SaVOc1(qtlz4oMe^@Ly0QracM`(@wx0fUjgDoPD7o3`#k@ zM|W-qy2f{I*Qedn^{E&8?LulSS;fMwl#&%8UqYY-B%&~0?xGk|uLOao;XxC0es&rY zCWvVFC9PB1koOHjE`z!yB&NnNN>g9v2g$bH?|qQ8TMFST7lx{NV>p~1y*)QT&@PPA z!_Ot#HW>7%whXjQwS^&nd|?dF&v&Rx!o@zN(%I#C{)`QGp-RA@JhJ#e-09&HY^EP` z(;NXBS4oqiUiO@f6gb1-EB&9di~xdp1`sBfoT%(&1zGGUee$}3EOk_IGcpy3RG7aC zpOc_bqmZ-j{VI6tLS30Ch5*U*ZYg~hH(yvUO)&4o3%(6QCyQiS|!VgD7Q zygmkLH%l-n_ff>9j&87ew|rd3z9m>>U99E{gU_%a`#PNCC0}BJ0nd7=Td$PB?`KwJ zo(R-V=hPJz(6Zh~;6$8Da~ zE84V#o@p1ADhnp2{dFer)B&8E!P>=%t=d)HsI!Kg;6&WfS{-e5stSO{}pvz)8^v8lJpq= zy^jx#|4LF{Qxw@5*p{ofx@|c!c6zeo+E#C%+E~T11K;}JJpQY!8UH0Ric%RxAfq&_ z%aWHtM#E`jV-onCua`R#pm8zNI6g-^JFw=MjXZlqPGtxK|F#ujA77i`nb4?lKq9Y# z@3|OV%skM7&w`8&FOJ{FU34*>Ou~p&1Vm%Z9-x^S0~CS>4H^R}#$JLf(dmn}C@Gex zqMc`alpNnv9!acp(u!FZ&)S$GLNa})z; ztDvN<-dpDdxR}2=`i%?JT0L50t)TI=a~Hik8&x_Z6wXSwws7 zNH&jPOY(q5bV#WYr~NwgoOJt@Qj-BRCQ#J5?)i0_Zn6(QpM5&NG%kKS{pr)mPCXpD zm=@@3PD_=Sy(_SyQ-SQEa|@c^7YcM3xPYx^%kXdi=sqFML<2&SvuJPI^AyHl628@2J*w5rK9zFAi=F3o_9HqRPcxl!#yR3hm zrAY!YX-{IWML5|)`vLcJvrXJ?cVLOOqq+Kqv(2{lbM-!bcbXL1cDJxtzC7nZF=77w z+3|Vl?Zx%PYTJ^up779(KSd=p1J`94&1lS`M4vP&vzxAjnQf#bXgc~*EV)PqMudOe z{#n1zXr=e-Xmz*Uvy^a^6L-D?2^xU82dWI@S_!H|)&3PSly0as6ryeK;ME6+L`jr+ z{0F!p96FA`XfCib4oSivoo)oz!@d&>WaWy3WQ*}1nFM?C_>V&3KTtl#f9~T$<3Hep z>9Va^T5ka2pg4}L_f*}oY|HN1JuD4W$&v^5x6l7mSHyonME4QMD0;?(^cg>ilkC+{ zDMd_5Q7Waa);o6kW=vB5OqTW+5+%v@c4A}(4jP%)cn&HL;R=fCfek zE4+VDAEg<6^T~W_HJ4AlYoLSm+RVG6b-ANw4kQq~p5%19x~tocrMUL`jvj;9+`nV> z+2*7K-ifS|-AR50w=tQ$t5%Nh0FbCj;i)3;07Beic8c&iNW2ln z4w6;iX1m;BY)oJ|>-uIqn(MasjCB5SI<`P>LN{%jU$UV?bwsP99or0$1zHCVEG)#W zTjb(d+N|B(XeQJj;X7z3Kx>8Y|s8*PGMTo3-({z7xjIm$@$;e{zySa z5tq?yuczi2wdVYlL1tmDP2Y1&V%oas1QQ2n4Fm)VC-2phqi(ptj*_<*Rl28tNi zHG@Q~5l#39I|WNsQfTEACn7?yxWoyc{nLdiz|3;{;hHD+6CV5kX6G;T9PJD*KY)jE zF}yU+KKzDWzef3uiw}qA!*@^|A6>TF#iMq_e0@t^vNk@Ezqdo4`An9h8D802ZuCvr z(po<|u!pYrrwP6>{1Ddp&*vMHvu)@@{x&D+xxUu#?D~%`F^4ovZ%ij?E}hz=XHThV zoHnQ4RYp5#Gy@%kFL-%qzJv19B}lYZk!jp_8XK0E#I?bYhauL)jLdN?985yrvu{yd zewW#r<3#$ zjk8a`4$sLKa(Qz6_BZ+pHhTV?tIiq?4}ZS=#1ou8o)|=@hUZY@;ytOggKrYk{D@( zrnqecHwycf?FSWcl4i%pyjr*y5bIUe-bMt6 z32A^_ATPiR0iFr5A0|RTV^hNR&VNufNiW2IRI>lmd))uIpAU`y^laI+G|@CwMYq&` zukT7d%j#RMCCbjgaaF}q9p@g-f9N&Y|6wwUh>Yeh=&(Z?@C*?dMNCH7j!mmoY_M}` z2Idten?vXlk0&^Sl^@K==NwQwheTVWc!F)uy(Nb~(0wEVo(34Y=n}q9rqLvfF$vWs zBQNHSJo*A0UmTE=DR4~h5ENP&&Lkj30zvf5iUKYyYlx&CGs6J#8Q(&SaolYkL7N~9 zgvtXNMtV{FA&VDi8hC$Av44v^ha6b}n6YX$jK9VEpoz{tX$s>?8kh12l=#CSWI-H{o~3qGb4p*n&v};< zfcKUI62IYT!gF~=)dPg@oYZ*djMyv94)?SO3^cgC9hEWaEReQC4K~Rs$&p z4bQk;e6np}T1VSBH+5^aL8zb4S2C5JOF$Yn?uvJjHM}1=sAo9mK*8zH`L4_Kloef; zOA1`&dz#$Y^rZym=kGAyzD7jt*(sC^-=e2Y4$-3Je^wrQnc3rcPP`{sP8lEQfeA}_ zTEw7(U_hAtX9u>f((xs&(V{~|<~iId{M5x#W*52rfGOAhzTL`-|Sqw^mk&{b5X?&jKzGL>Jb@Dj^0^1J@wkr4cmpGhd z3wOIc*|vIpTXXI+ak$@8$vY`~v}6a~)#QyPwmHePf_hbjtWlkjKNpR6!=vMmLrUK{ z@9Oy7+^v)0M+$)?ndU!po5kc>dkFL-3&WuuaUY$UUVyC7jGT6tK2MWPkJA<}TmQ%2 zoAsvBpaP$<+{wao)Y6gRD!=7O;?_1&_oj=I1sA{g%{F^ZI)N$S|p{EcfqV{rX<@9KhMJ0FIPkj10ISaNc} z@pDDto}TVGuBW`Q)x29rdIe*i_BzXyI&9{jSRv}TPSd9U`|j$g^nXs<*W&*)QUB+) zzUcp+;)D9XVRz_+k=F?aoo2^xMUmU=dd_GRj>FI&gh4ZMM#C@~Ji7j`RZ9Q&-Bn5b zAFYt4|NCw;eV?iXtk^VItdGK4z>2B`R7YN13s_Q)@UI|zcNF|GSf${_)k-@n6L){6i$~ za1a@bat$bs5EpqjRjM*rCh*Rbs<0HbhE#>F?juQ6U__Zx6?F`Qa24q?5bzfMjy{zf z92*h{JsBIi@6b&O;Uswp+IGF=(`Vt`U;@msFc8D0T0!0Q+Q# zmD7&Ho8m$Wquf>R6)%RX5DQ52WH*8gS!6efHPZz+n+`gR)1e>aifz(*$rjrr2cUIo z7svoO(*!cwW+*I>v7xVCIq}-o1|PRxQ%vR|0h0g4KaT6PEb^aMC&y1_|LruJzA66+ zTEQ3j&r^I@{=c9b3 zGFiD~cTUkB_%R*4kZc9R2X*1nyBSp-X0bc|t z+zF;+E{e_JJ)jnf2HEn+{vd`nS_)_Kq@sb;{7Jqg5Z+ zve@Uu9C)vHd3AB7SaOs@H%M2x9ny)K5~4hE9Z&#@Ys%O;nUDopZ9y$4JIbtCjs6GW z?0uiHXDmsd7z(Qnub)&3DMXKy4QRVTkLwxLj8woS~F30^kcv7|RG4v3qD)cJ4{hBF4Bh;#dN{U*83*%&R5&)axrOL9d*=am+e;t? zKJA@bl=TZN3c{3$|4xgQFO7oog# zTTqR#SilWS>8W1Oh}xonR02bRd|?^<})T0!nQ0HELnju)ePF}JX zc8Atx>)>}WdY=!rD2~kO@Xunv>?@&yaf*TBAe4Vu6nix7wpidgm)?Z+K9_pQf;pw$ zvNW_Pe%Xpm3sY`eC_Vq&??nHbKJ@&+AHDy1o^t+z90x<@v9BCw9GSiVnU+GXI9&6{cQd4xUcIlG zPk}o^CT($t;SiJru0V=J{#Nb6$BF`b$19~=_bla{6sa~ASkc+Pzh_*Ts361R(A&Tn zod5}^Q`}U*+mh(xFj}l3w}WzHLtPHNNm`~)+3f#kOpxnUE`FqU#FN)OgD-!|yPvr5 zH5x;=I~usH!T2ffe$AHe!`%*CG0?X@neg%YZ}tn;!%b8E?Teo0O`>e4+*YPD|+7jeKSEXzPWLWs_{z&eHE_xOzDk}wgD4q zPzcdtD}B-v@cCO~P_-I|GoI-5Nc|NKaW)3kn}MfQrZ-(-y2S3GH}i#n+Z8_Db>9z?Y9sKJ1z7KmZMmLyKxMQ^k5l0c5ea2?V~(f*e7KJ{xzaRt*t zPO|6z8E0*jQ6UOdl=0(fMScaX%WeyXv}E0?d8Ugn%y*O7LIW?6Q$r6-FYA&$aAJ zwrP}Yggq3-|ClH0{Xgh+em>+Y)CYUKefmb~v49}gv=yMU{{GEn|IfXv^WLeP_gA=F zpD4hFjH=OScmv9b1kL8Qh6B5Zjo)m6*=m)4=f>nN8k#xY32|uUPqZD^Te0Gr!?-TU$6Rj+^Z*UMi2``+;t z1Sx%e(j&k9R^iE-MdwBi=1&+gT!smUh%S-ifmrm@MhtIvaF0~^cSSq%?6%`~A)t=NoQxX_o4vSG5S)LO< zf8?}>-e@?c7b|Z(9*#$0r##_{TP;rW;yNNh0-!Yiwy_2xU+Qofg=@nG^-iz^2++@v zzVXq020Ww~2!xSBfSOEXqJV+>Us;;av6wua4pS;F8;z*jaa+DKep35Y*Ku1Ii;ewY z5&_h%nd_vI48z(pi)K)Y{JT(6vW6Zfv>G&RRatgam1SZon!fSsf@u^vU^+p~a}hFK zr{;B297I{itjSfMUO)QdX}G#gsA<#8P+5J5X*D17k*$=R0kMjgjhz=naVNs(+z^3s z6B^-6Qq|{|13$HOp)c*QL8t)a#W)X#FpP)6pEj(Z&4mE3tte|dMQm_mdZwvba}94( z>KQ896l+^H@DyuX1J|=Ov!H7w$#GT^1Ld?bIn+Y~e`LrzlE0Y`Rel0!ZS2{3XhCbG zH@;Q}K!3|tsu`73%;Vq&Vy({$>9jFd?Xc3&Q;g$X40#@hz;!&Q%c!2``D#RwEn&Tv zSos7HjA3ZglYmsFCn7JVPEXvR^meOiyBwO;xK&0YQrpDW=137e!J6pJ>mI3tws5kZ zFF_IY<|pzx8f@N4z1kO(fzRXPxUR$X|3dy>zYJF^rs_w+Qy*<$4eOU@#~0VqC}5ZN z-@ao1?K`0VZ@JDF{r^*ZSpN5xH;(*at23lL=5RcA+g=ofQD+d0ov;%GonX+6{Ah>z z{}lUgFUS5{py&~FvQjdM6NaM%aa6GhfINQ{0uqTz1*=GvJ+C(ZFarrMs|R$P+(y#{ z=<=uY*}D~}kI}FI_0>p6lZxIlQQ|%ytK_Y-djCcsB%RGBxoK)tKLdrT)S@;TLDOk= zM!|3k+s~c&o;u9;)JaQ?sMsW9ZlJ>6r<@Jq#>U}%Wm+3kL0$sxan=cf&;b0ZIW?<;cS1y0mK)bg;fxtvB$OJOns>TImQmt~o z<)Ukqw*(V2F>TsHP0Scu>}{k2D~{1c66*$XlJnlx@lCJa`>}U^lhR;h-)>JPqLOl{ zMxz~cLeGna!IPTV2OSs9zu{Xk|4slZ(;%Fds1el$+$&@PF4um08}N)KN*RIU4AQK? zp_47lz@gd~JMe$K5551niv9QTXoQB|Xop%~&+D4Tl4_+j9K2Kkz;Hdo*?)KmT91i2pCx_DFkd zG>Oi#>aJMLx+@jEm9Ig=BjjYrflyNTwQ5963rz0lVImEQD?;wJz75y(ia8^Lh+a@< zGdl2SMBom|jHYj5UtqLb4yPZ&doWdIHq({KSo5C+xjYL2wS-hEtF^E)rh@^4Xv|*C zjgaPWCVrT#q6$7>B7MC#bNph|u|w`;c*}=hQ4Pbn7F{(64`=smPM?>vE#p`Cjh22Y z#KoIwd@*h57t<{+qTBLBk`Zb&x}%8hr$Kj%5ath3+jU*8w(Dl3qkcN&lx3r#?&-|j zV5Hy%E2+7%4M1>vVwx5e7Sp4Vd_9_>%=*k(B6|LNiu_kNfYCd2v>blmk? z4kp8O=801Ou(R{O-SPv^JpWt%m-vrQ@?rAdX1m?(bjIxtU4-tSJ8Cw^Zg<%2_)*lM zOEzwLZmT(HKf3(aFChPw{$DYUqGfNKHAQ$!q30Hp_J+%M8(GUt2#(lciQSdV^PHd3ctV3O81w1kZPSt;=F9h$*h`6=jFrSMX3iISi~|EOSyEbu zah1_|OGL{6PcrGYwc^8B-Oe}DkunmXON-n4)nrI{qGTM7iY*QY&@&?<$Y<=^Xj!bCALpiKjs^sl*>l9CRBNNc(CA-N<^rFFLl$NbFEyGVr z(Wl9`)56S1t@iFSBk9IY>qqSDT z74r=Jksn6F6I8}ETr#05hB&Kh(@Z_XSXTmM&ly>Mj(iI&Pl+~c6pXdUwhY@dqUkKZ z36`?0#ZtCOiQm6W$~IdDw!8#dS;s@HcK>|Sx9K_AwwrD0upT{?o9Do$u6nNjID0$$ zcvQmr!xd^fE|FK_cVlP|uV#n*2RkXZ@3at;m^%h`V0N?%qdn1;B>QhJa6R$*6f>d8 z9hy>)udmz2_4Pd40s8>>8^^z7Zxbi2NoQ>wm)eO!12}UiFTq3)kHJse=P_$-qw9J7 zrR>O<#Eh-s7Dc0wU!j%gO8h^_xpHG=md3 zT299IgpOYg>dW<%D>9md?`Cs|6iK_34g`2~;K{u0a`QDtP}0%#U!NR*e|B*WH)!%4 zI;Bm_v{Lrff5`Il)l?9zW{yQI5)Vtq1{*qP_+Ueb4kN?e=B~GC?=P1ZS2z9Zzn*<} zak`({Cc9~+cB|ivX7q({4ho4qUGf7*xv>>Aej4taQZ6 z#=S9@C3fXuKrk<{aXxvCMi0*&fF%rprE9j|w<2_H5e|MjS7@ry8PV62Ia@CUtQ3#wd1G z`b#arVUa>O_=VYTV(4tYNa|lnXT4@iD3md%B6UQ_-+?De5(&{ zE|x~5C&QGSE}LDF3yXUNi%soD5pTWeWcI!veO&j!!Q_yoNkT%vavggJ@J>Pk_Xo~( zoSwA!0k^f!BkwV;S+@lmooe8;Yo7B6tM+@Lb5(EOuv6ZFTS;{njalS>kL0=HlyRX* z;@Q)Cu}JEuKo`NvVVuVf#Y83_r^v?l$l-VzzGIHQ#VT7arYTKYRhgna7Lzb;8y+ZN zLdZj7%joa49BYz0`S?g3gP_T%<95KJd;Q&fJty-GvRJ=c?~NK>Cy#S0f09}!1->;cCKeK0yWX01!=+J8(&u3^6t`vq&8mUnmko8i}$M+w|6*A~zBG78n z_0l4NZRf!Hdmf&Z%6KG1qbAPCMh@hCJN+6ZN|-g7(E5opDy8FDqG$mo@pH|tgdUM@ ztL6n1#eBEswRW2b%fzyNKW=cf1z}ZW@aedw$#(M5jhGlG!%r5xpXX>Al6%u81&S5+ zF-M)?76fxm zo3suz7dkm;z$wBmus{-*Z9u@!L=6YbiN|B%ge34l-dt@qyI|0&6Osq-d`*d4v5(_O zQuR{!_?3>3yFf+GQfV!xB8_#}MG<8uD57m|n>2QtB}=)(ZQE4t9S(WYj2j%gAF;1; z7r15{J6dU%ZB&rzfxe z+CP4KbMZnFp!|K8Nui~#lS3pXP30O+r`ho|YeaUUt6&tV3|kI}0!|4{%V}{1*A5pX z?Yd@dIRCnK8?Kn)3d;{roWHShDmglcJ;}@*F3g@agWvVQ3Cgt~);4#610cgNQ~&E!xqH+0Jj5oph7VK_(z6Gppqx5<)q_(9EW=CQsd zmojN}WNjQ6UB7=izrRR| z5wOlWg47$T1rI%_gw|_7XqRr-ifHFyxX@NJ zE67(lyda_vwhoNdOW`4Hc64f6oGzp6-`KI@u>u`ZSKs6q4{NP}QOiw_mI6b-{!hnO z=e0P64v=>U=pXC~K)C`BrM+U|q?Eg8Oo>@6sRQ*wl1jBjS$T(K0oZly1MI;qW{@Ao zBNPf~Wid`jA!#Z;Pc%CxFq1G(6sx6EftFLu7QmRXX6q&2aH-Ws2bESg(;i{Vb%rj7 z^Vxbb+e8fNd)fwgNg-d&!~7SvRWMLkgONsKCAVLyi3FHAl&x)N0-4@vF%1jdk(6+C z99JV;N{}i!qz~b8#>cgpiCCNa8LGbnwmh9eUL#k3^%I?;!iWAUjf$B*9{hp z&_(TC$8Tx0P-nlXF99j8I7)s04Sj!*HEW(TJUzFZL%6-HDje1>25l*X@`B zs)sGARTe0keF?S#ce- zj_vwx+G;!ubXkUf89gw@z&N+0NNc(7--U}Zc7G3U$?njUF#LP)a=2_c0xrGX83YQf zgJ?Au_M6%6pkK7D>Mfn4|v_-9Qp8Wm+~Zzu0=6_qI&&!^M*2XM|BPnMK}gHFh11rOqE z34#qrA1=zTqa6(8WR{dm`8Ar}lg*-0VGi04Q)_SsDK6HKxea%$(BLj%TADahmBBA^ za-T4Nif$*^?E)3uBl+|Rl3?tJJQZvzUEjAW;>3hTuH)oWr;^jR>z zTTybGD(ZUWnk6n-nNpTCc3b7GQza_}Doba5B{5qJJ9eeAk{*~-O8c1;N(xQY(bzgq zonCfRPAn2GF{MPCFSbd$DTqbkAii-09#n1=x}H05!%m~&_#?+_ciPSag36T%=c`mg z;#Lb<^gyXKL9JOyi45=}@q*bErgKY=5JKoh3PV+7+!el|!vwyg8TClq$> zR2=x?Ddd4W7NTX3c^6W&9g3aO*rc7wopvh$$cF91MF5slDeVH7bM>Pw86zFjmMl6n zR(QKxg$M;+f|uu2_|3u_41;0NY_=MW=4jju!scMx6qTakl6MPH4MQ8aAW5vkSJ!H9 zgM~Ft9-?qUhU^u;yif!#T(HI$&)HY2&Xl>5rn@*x8pL4>b)#jt-q2kV z4^MiLn*lie0K+)@L96hhW3<(1HoX5ATJ_`8K)= zmEr1kkoPj5O$dGWAtLYQYl7jel!aoMKEN1A$bK0Xe1*FWF@yZ}8~F+-F2j>d8&DgX zGR$26L$w1dU*FN2$T9s@UO$hAo@f2}InRr4TXkab5*afqz0u-qAI0!lmKQm%z43TB z9)YORb%L=w2)D_95w}`=XT^2UnWqa%m}WP{aQBWejPpe_vq>80_kpPjVpRk)$^Uvu zcpQ}l9U+j%gBOWjydOWD3atD0{;geb%BBSpcIU{lZ{v zHP#KY{3fx4Qxd3v89xL;D#6!c_u00J7TN7{Sq4ovQDj?KRv@E|R1&4w_ew2;1U578 zahomG)cr17Q}9PYc4g$-BYL8dY&Z+iFjsWg@VnJSkPC)JG?uB4_^d&0A9+cTXEjm= zW+HH2Q z;kS*dt`_`0BXm3KXY&&|3Clb#0&pDYgK8XxL~ByI!|5@caiLm(qNBBvUHmy}8xG zi*rjmQv`kiX;m^O#A^l^xynbh<(i`!mfrz><=MRD)HDp)anZ0Y+@C=8Y^t^W+ z&U&)%lpVVL&1|)Zp(v-x0V=5cDj8S91d2HTV{=)+m{TJLpE)Ee3{~SG2DYHZz!tO$ zfvrGZfyV}%ad#;N!tA;+FiB#dIygzBoSxFmh(WaF;a!z|tNXXqE$CselNNL zuRJM-3eTq%t5%e-LJw%&N!Z}0+x2*xQ%A3v~r`#;wgsn)SovX0qaEVVT)2L zhcZO%L8m)tc1E5XdPCnI`ffKIMeZQ%wA$osJ|oxBg1BwsI7j#&@#wNvpqXM>;a`XA z=!o2aV}cuy*U^wR;JK9VI%>9$JbDm0w86^tX7D%48Xb|JFOP3t{qPGT9Y=UkKOziC znPUYfa+vQVMp6Rq#gN^;g6Zv7mCDU+q*cJX+GIu6;p%-f!gvDW)f_dbkieX*Hp5#I zt{`mWnv%?l;^o1u&_X&8lqoa_b`dT4z9DeTF7L1*=xDfEE~D9cdS6+sY2T3Ehs_x~CAmTagcxi=@MwP4B^zq;eP1CI)jlKWKje zqo4=q{-hB#nEM7{jIMLgs8o(uB!n_>$HO5B2r&TBt``8F8pNrc4xGK<~))j{t14C*bcj3p$ z-R3UttHSE75bn?~o#{1ZPpZ$yCxhPPUIdOfI+ zMx#+Qk3IeTMm*0aRpnF1PldQ-3~7gkx8dwvM4{p~+Z1@KXo)DeUp=UiR*Q_HX~Z7X z4=NAve<-E5#|r$qG>*oD?qJ|}jfNMtTE5c^+7Ix5D6Ow&l~_heRMo>5H&(GnmO*QH zFr6rBPnry#|N9FT+|95T1D$({{O1M4XS0t7Fu%`s+dowfEw*kEHNk<3D6>FssTbs% zLvp#CuPI?%k*}54U-QV(nSfA!|NM)XT4JnpWYvtR;h@8heQn?bLtGm>lO%Q~j1e24 zW%~0m#&ug^<&)WPx*16aIZ4)d6%8se5G_E7>6uYAV<`^f-vE~?g-bOpj7GUk_7;zo ziJD?b#B*e6x!7;aQ^vx>I~YSHaD5)Xun6~DAm+n%X@x}4LDqrAvYES{*d7-!a+bV( znj6GHrJBIZQhuS;_!^?RBr1y^_xp=Ay9VHfjv7h4+9oFw*DmNTu!sSkj~L*09+>*( z@v`=$?=b0#B>uolX(GjscIjvNejLE}Y7n$|r0H#^4IAvMedz8v+3(%_(7)8v&HRw zeRWF#H2R-ss8nPCWRJ+;o}PBo^<*(+mzGr;$Z*Fr1D1lweHfWwTar9~N&cS!fZs|$ zBn}K#FXaecO)qWPJc+301v6N&lua$$0VHHbB+rbtqr|Heux;) zHH9R&_aK5Zf;RDd-DMfiTwYO&f3(wN7tD^lQ|nTUbi2$uY3B&3L06xGmcXSj+7Rox zWL;)i^fRKGX$dhfcCzaN)ojOFb~^T>$On{phi9hqQoy;T%xb2VjxsAI7h7_%KXgMlWZ+E;5le{O8#1M=H%h*I>k|CLenE2HcI7t^)z|$k%DY-tL34_;Ur=3 zN?-Psec1(+#PUCjAvKu|DJ!^&kmhpxJFI7dP}H5zwgV)^UjfI|8h3Vkz-o2p3&2K` zD3mdPE!K)(SujSogIRw%c|4Id*TsXA4rFmf$sQkvFG@*cvuEa%;xWx#WavAPRnps0 z;)T+DQJJ$d1*waq_t=i1FLcswdw>dUTWaPGJvD;aS1P$Hvw;lRmon_!>?4}bf@Kbf zVF9LluXfsjo@feCtYYHW!xK`l;UNAVf~N>>OCwK>Cg{V;N@}xr82=v|OuCm8+R&EF z?X)>wjb}vH{<52inlHR z!d8nT;Z7spDW*TWi+KL12v=B2%w#l-m;WQ6SBfk6N^xk*zYEt{^so6Lq=nWxcCiIb};fjR$e5V5zn-u0AWukVJbtQ40{UMICl2oMxy6^+z(T^wA z)5A#KBh#sP>pdN*QnveU(f~1sVW(a5JKP7m<3G~QNzK^vm?Whj5rH{reg-Y>4!E5E$fq6gH=WyFhcxq4B~$i5KkHz{7pjLpncDi zbJn;2-+r+uf-Gh@9JIM~h}k$+LH|>Q|Hp164uVwy^O3|TN=qp|earBwUdL78S(B4X zrZ~*kd*>Hty)*84QnhPIl+A%nX6+3`chHC=5L?0jvZF<>n4Ko<;-YgE2WpzzSS{&= zCe57REhbCD%=!DvlPhWFY=sZpCM^zmYS!Ya5zbmlZh4Pr@5?){(SxJ3c`wuj^IqOY zX8fF(ZHPy(nHggMauRr9yv>oM zx|bl&CTh|Zl;tdFoFtCPm^cZZD#9EX)tKZ|)ntjO_1MXgfQs#U$>=*fe(Wk>!-!L6 zWYlkNJZ=$>*zWqiRjBm|l13t>yQVbhYZdxmGfOzYTGa^dc(~q#Q)ZQ;M`K`QZi1U? z5JB(>5{}neFb4WE9Ihw7hU-Y7Xy*Cs{E|R5ox%}^9GN8Qfw?Q=06?gox2BI&OBgT9 zC$>x-aBeory2fqW2U%=*)+CiY7!->e=r)@+LDU10G#e$4R6Cf&-rCIM?qXX%o{41# z#@EDAL-Be!2I4T#S;Q7wgT-A7-zXMUTE=@K#n>!wNhOY#X|Zh-XnFTu3_ zl|PQ_25S7Tv-z))7X1qmb5&8=iuc!E6 z{I6~_=nj0h?S-D-88tg@XXJIgX5@_qt${Ocbz1ao;JS|=|Ep6d{udyr7R-wwDT$F3 zIH!;@P8jVfst_=|f~!WQ@^%#|Z{!PPz?Ay*25IR4!hu!bp#6qf;4xEbTgoLeT+UY@ z>}6rW?&ip=@lasvd1V=GxK*|`0wsXW=Nrf>2(&m>Jd#y1kd+^pajabD)5o!r!K)gL zZZHah(ZCHqO&lxN>7dy-e)}1A&;=!YBvVX>K{6Hbx+R8>#w%wi)(rgumn|m5XNthA z8f%*59o42cum<5ty}}l{n8=%W&A512%%1I668%c7vY6HML8V1VYmbRS#>3L)9uAIhC;HrBKrZ3&MmW!})AHdAEUJIaoh)g~)f&c#fxY z2mvmK!)S$va5eTFMM1F=4s*gB=-`_9L6fl9!J$C{w~(U?3+maz0=uZq(s;sdwNke> zdBmQlEbWnbv$pi43lEY)2D|uRXTk`!(OUt#x_8>P*hUZB=4FxtGo4fpO;r}Y9OQN{ zWhi=Sr}w|6a{uG$ORpEx$-4e73YUZV$2x#{5>6-oKnAwN#ZUB+egA6*Uemb$dF^KN z%l+>uK6w8NMs9O7YL8ppL8lw~ZKv(K1E(___+!_P=&NSe9lD+FK2ugp}n0hm! z?^y+Kyu~u}aYa;KMpHPD2+n{&?&HZ|vyLdIGr@2!^wRfAgo)<9HL(M|XvC}xK%uwJ z1?@NvnOvD809S<4rXhGr;6a&)uX-KcMYaYv^ae|3A5K?uqXjj@>QA?D--9*{_>RF8 zN*w7G7NR=jaM2H01R5Pgje97oz{OT3E4(B|0F(v~h*8_dfDrL z-#fng?&2@~*C##j&aJZut1&WFAJ8C5LnLBy|JGsx5zAIcvi;U=^-sOg)a_MxXDP6d zws|=lrCMMM7-Bax=TY{s9^Du=i0Yco_Q_DJ_fAJ{vIeVP7sTfC1{t?Z```VHk_Eb2*b_=6Jbuk9wwlmDI5l{|@7l|}i z7CchNYl=YAsJez{l4_*e_9R+J3O2Jx7Sog*p@-VQ3+osJV6=6tfBSAZ-z-3)1}4AB zH!rN^8^F@8Ow`7Qe6_on`mE!&Ow)`qi>+-ZmiX91hc@X9k)vwyAUb-a=8O#k0>f~K#?e*(z=gr-GIJ}I?c||rI*FWmjC!p3HcAt0w$1D&He>pAeq>t z!UE}Y83z}NWJy^<0+NHNkcx2jgJt<*q-X`H4Iq+#B}WEBehrtC`DP`$CFA*Krio#= zXhdWg1KNyTaVi#pG~zUtmkh%hxeb4fq|`*TTqAT8WHXyi-baRv2mZXTK+ORpV;Dsv zKAF4uuaNglig04f{N-jgla>p74iyc6+DulFmPhQC3y+up47-T1TqV}d3?hmPU=03i zIGLg@2*$*1*OV$GQKhn($x2)t6b`@~M9gq_JBfZ}DHN6w&xr<0B6E-NWM;JUSg@47 z*iiKw5}!jnvqhmfK|OV_mzaGmVuCRRD|xpZ1!3eX5ME-!xv!I_=GTDob7Fl%hi}8KUy7} zS+{ffPA*a(Z(~H>)U>ggr4IR355SAD-+jpPS8aMVuayX`DL|nblBhBZTar6bCo|1m zQShas6+M8>WO6GILiF{*EYRWY{KLKhQJK4o$>GxQ{}6tv1zGI4!DeiWkDzR-!^D%9 zGHx#&JLHug?_=X>`?4lC-$B~$(`7Mc1NZXr{R+2*@1q5tN-~=mI zliO66L0M#K=Jrp{Bc?RMdPce)rb*?bpNd|R&B#_-6M^F#Q8vtG%K~dNl7ulm`B$zd zD<59Mp_MiZ{;aHZO*F(qXY*7e5I97Q(V4nYKrWiTS-znABcnUO{|m}L4CP&?S%Xj? zu2<_8L3zrp_c3Ag9~c8y{u)lj-bii~X4KX}hd{5T zr3Bd)0TdT)kw)>e-i^uqsA{+%^Gv)qnfdXqwju&Qa1i)GM`P7(z#oUR{&I2m<-B=} z^JcudGj`OQ>oe`VQBuOXO-!N#{+mS>4FeKrm+j5PRZlJ(<^VwGCy8E% z?Ypj%yM&7mU-sN1?YUuM&%H|9bDo0>=DBXM1^eT3D1W#WOXWM{uJb&MVqNw84mW4W zHe2I5>h+g}eA4TclwBG7u+ClPtmBNCHB#4^G|o>+uemK6VUy4s%DqQPqp_UKWuz)Y z@3SkHtSGKth`X%-Ll%4OHqQf}L4s8L{c`+29vTl!>&%<)uC&XWg3Ps;6@Vl_ur`l@ z-@~CsP)m3)>d{@T$){n=Q*w4?EX)T3{qy^*u+=?v!=v43`sHB%FRZes;QV z|0qXGmY1oFsjyOF8f)0?$lRII=e0(z-(2=@di4B(&~1H4DWsNKVA}#?1D9cJvsD~p zqq}JNE}9MRzo6_Flzj}8Jw83YI!njdF4sA?)STFCyl9P!1DS?{X!?a2GBH$<&*owR z@DC(c5Go=vnnhD2p{%&#%Dq}F>5#_zgUy(py291(KOBEU4^~AI%3_)YEf+Lq)u4@e zJ?JCFD<_@^bE|+gX6OG8Kb>8i_m6LGu9!y!;#%*lclCYm973#fghQoyJsFBbX*e8> za$Ov3@rrYsur8|5Z)Z$W{^Fu*l48VB(_eteI*%(|rV2Q0l-M{4qmoz*&nR2`x7AwR z*S|ca%wGWX@mF#d7~*=W(2UTA=+k(ENh z3$(SlUyWBntpmYVb6V6gPN+DhE}*&CmUdoP8)5jvQ<_*YtaLYN4aHq$x=u>>hEjf$ zg`2RFD;_Lj2lwq^n2;O2I=(b++<25FWPi<08}!UAR5zz{v?bu9+zqvr7v@m7blQ~> zqI1U)xuGk5SzNK(qUi-mcc_6?D$}LibQx^a*NoHRAVYp55hgm7FO0J~WU_rFN07`X zkN4UH|K1Vs7!Pki}t ziZ{ovez>>>q*KdCQUcPwbvV48_c0(=M4prHPHvRe4-U|nxFDXELDVcveRF)?zq&lr zN~%0Jb0+;H!+LZ4_VgxeU=+5Tt|2xAP1IDhKx5JR)Yx$O(^)ny0KTVU!qWqsj<*1) zOAxVAAvn^=Sau_iOUUx_*QA)bYq@F=FWYVn0_wK9_`S2BCFGE3OcA&=h0|pej_%23 zJ(*7a!Q8Kyn-H>l5ZGrH4Z$01eY>1*-rcfxfHRSn`viw1X?6sx>UXYxo@ z7`0iTr!b4@Tq2KQk>n+l4GLDS;OSpLU}V7?V|LYe6Io_hwa(D4ud>ZDWn5}Pv|Vyg zsQvn+JRH-%sb>KL%cmaEtE&@a@6<7U(gC3W@v{Qa>G5~H)6Zi>uv(fV{}YcVDeW}} zML1j2cEI$j+VO6uu}RG77VOZwthPMRSdnh3D8uc9Xn3x?L8Qg%0yMmckYRi z$8WO8XUz`Z^*aI}$%#W%FC2%ez9%P~TbfjrI8jxrS40Y1!_xy6uc38C_E=nneQ`mP zZE>bhT`1Z-`~HvI*#Ke6ubMhSX=s-;()%7Ft4R~R7Z$N%!fi?&NR3czh}ggEZfu$+ zeOOM`kwp{E&@SlU6&eDIF@5IF&~8tM*h2)AS<*(Xb;NU2ICZn`c6-QIi-|tiKK>mi(Z+2*nTpuB zgF~d5%zjvzWcE_CH(rh>*GBT8bQ*_><7}rAtPaIP3DRO@-ZV-`cYaYy_3BTIDn;*W z58xLIE>u|BqxV_Ma!9DQnUzE&!K@I1v7|A71lF>7BaoHSMxfpb^2d-;x)2;nL{uyk zBC%w3Hb%XXl;K+9ES8G^sl{0=6QEHHviKO|;c3m}#$mLT&y2%p-E8UIDDSiC+Ph>0 zc*meRjrsMLME-{Rmyk*JA$`E>j_t$VUcGwwOgZz1)OF|R9h>21@(fd zkdy0sa^3G;UG2xWB(4ZxsB=kAE&cTi4H?*TCBZG4&=^Z>g<%#EO_s&Xz;*(gA6+wn zwnv8DPHq&<;-zDPwA;v=)nrsk*;UnY=EaFm^{FHhppu6K}sGyGPwv+KcPiE^S#ou96hfGy<$dz~((RHcQgBQ~Q9$k=E& zqjoe32V?is#b#_e5a++?h!8a?K>{si?W@>B2C_&RPBV7f1q|pPZ-^J%1;HNckLfrd zI6>RbjZKgfUazu)NIBAWC0_!2V7jXok49C^u9xUr$t|k4D0N$p80V_Ir7&|YRV;*K zcTyIkzndTXr9gzZFYEpJuea-UFz2K1?j}Cg6E8SPE}e1I7gJPHBNv?hg&PJM& z?8uNuS;J;qSuT$^YG^>nig9Cd&VvFZsWo388`0XdY&coI!VOaoxN zW3O`604Hmn*Q&Bu&go=Ck}ckbk{+JXQg&KE&ZKvfU!$3P%Vh8g3BPD)vSLY~R_q1< z>8zO4e}(R;kjK2nGj`EFD~kAkZc6nbNtHveZ!ZVBJsy4F#oJrb0B40z)gllWE5KU8jl~@-)?#}Kh=3{E3g9>p+f4bm&Am}>)wwiuX@Z2;pic#+P^IWKrhI&y85qJYfUEu?QBurS zF-ih=tx)}9RcE`ZE#N?M7lBj99S)$6gV~quNii*x9x;y(%48hqFLK;HQg^R1+Svbt zLF^5ro1JggnNVvm7?{FWIeaE)HC=vEM)ULJ7xI!%E0Z~-%;N-;J(_V!G+)_tj4bWz zYO!a{B8aAEEEBQ1NToVKI+c2mi1l;ua7|JuzzKy)WjUrYD0R^hzUw^_l*+iJl27cG znlAGe%GrFGchZTq&_=9Qf64bt%~u=kP~!bBU>)wbZdaB6g1~@MeIWrx1KJt=TMENg z_4T~I+AMY^|MlIb?j~ktfNu&{l}cL2CrqQp_6eYT%{6FS1#%+bGM&;FJxr}D(DY9nCA|za`=0j*`#6;1e#2lxyBFN4~ zqYAv7%(xU;$blQ=dNaJ0Wud(x?G_pvZI-~_Fxg%OPMb+Mo%{n?L$EL>%jj&3XYg*J)d|D+m43-ZPL5z z8i28xDJ=4hGCKk3@q9y@owN0boA~z`Thrk%TCG@2vlVNyf)@4c^rC?I_n9J==jGwK zwf%U#)mCCyF#~?ObZD;yFxW7gf4X+PaCoaBGU37aS3KI<8UyX>i>ISxWf3kZ56Bi= z_78B`05Y&mfoNs4#I^ulNj~80HY=tESwW2IioDIwyQm4uVQxa+jM zu{&%u+U+pt1YxterP3j8x}@46u81N^7i8gG5%xo4p?OJeLZs%Z5N`l4`$Dv}{s(s^ zwKlR|(#tmdv*Oo;n;&{tXUC`g^S5XHo2!${YZ(oPryn8o!gbpOATt2CrP#1d!$OGRu;Q2|e4bFpZ-{`JlAO%D=i{PM8Hu9sSix@9f$ zThP{`ZeNRZd^rR{`odHM(H3qe?`|Uy@e13P?0q52vkmh53z=3I0)@G)rWSNZp9aEm z)!!`OAht=9iN!QW80C;d((7GbU7UgR>O(}{&DZQuC$T9Y83PLn7ex`}lV8cv3=+lJ z$V>w4C6;4SQNo8CuS0`86;|T=#z^bRt9(ZKn+u=LJC=3hA zi^J^!@w|o7D(Y*f*7^gI18lJ|ut}kB+U$A!2 zta%Wpui4Z?iYq}zOceTurrJmc_<^CIus5d)+KX`^OfGF@R}c9Ql*qFV4mjP&E}v0| zb8hgj)@(A>p2;psfC+*-+T7jU^WC6qjCfxlYiJw}Y~2m{dQs=K7c$Et9R|c+l9-}# z!#}g1zr^_zd2yI^YFQ$6o)o7RA;{5C^20;NgYaS>vxCj)>-lm`R*UImeb9(mLfKdS zTUOr;Bf6)Qh@E2i)T-)R%}SdMTe}eLCHexw!=Qn$qr2haUL6tg$u%Lj(XJvZCd??_0F*kt5t@Gz$x zw+3>gb~mW`-9qFusTNKp8-)nyYHJFbO%es&EJir4dpifRoMuB(XL5m*I^048tU+{r21gh)lZ}?KRXobn6?+-WoGq3!mLpD? zwheAd%w9QfODhLjL7VZ6t&(QT$Bku(CHI|uJ=8oUD$d%NE`_W~wrOI`a%Ta8nkHnM zju<;Nu?R`xV4%sS;)sRi!BK<_n*6fG^m7@e$uDx2U)ebxOu;;vZK8y^LX!DrK4uD6 zfG&5QQ}Y~B?f9LV=cbANwmBJGC{?a)kL zG$bX=cq)aKXv=C@Ps>=UnPai9vl5liwzuu^94)CA%w$ z*k+d3X`!)qr_)hApA({te-vO28&leeCDJy2Olc}+$Z|O{wU){*r48Rw zB!#8Y2ClG5Nv294xmq-ntC;1rG8+-J&l*@pMM-Ea6xR{s#x znXP}lo_7wKhd>5er5uJTvcE_kZix<3aLabW=}nj9VPg1h!NruRT>6~J<789{SAdn- z{Sqb_n(QGx=Az>=C-pFCu{`2bK;6Kv!S(~Agq9u-q*x)uoI@qXn_IK=i1ikQ3%Tof9oWjQ(`?te+pTLN`-5$HnLTiv_95joP~lRf zpal%+lTP-o-Kf+1wiV0iSw)Z|zBbCa0J>CWqF@7-l4QZC!>z&`N`N8$s?+w^^>d5e zD0|ke|E!%egFrk~aF){J<|zIfsSKpaV1yG-9>iM{PF0h-0(?>`*?1EMfhJ}?b)61} zfJHr1ggG&}hJx6+B_b6?;w=$ycUTrz;m;_A0@Z@RKYH>v0s7rmt@RM-?_pZ7-|@6p zP#|%d^613L85ghg$4wSOPhZF8|8)(zcNy->a3U%0`o;RliT~vVEyMrI_nKe)znJJ#hrNVlFzAw1%_$MkRJHt!ZM9meBG4r1j6U3vc8?K)V}C6 ze?ng=C~vIFcsl=puroY}%w#9%?oNCB#-^j!l@; zg_1G8(&*MimuCY8nozDkn1 zgq>(O>WriC(>ghII&HLR$8T?!DxH*k=erPA7SrnFl+&bWslvKMNS0zFU=vRnd}s7@M5?Lqa!8!acqku z)kWLI(ILP6M(Z02v+9Ea^MFK7i_23@kIPdi9*+`=N3knP)$fsf?HJQYw3v@%tLC+K zt${470jsL!P`@*G$5@u1y~ERKn?@!6nI~M<`c+~^?gApa*HKqH@~G-V#9SXkxOba=ZP$pqogR%mK;uy_t>$9t4D?Xxwt{RB6wy}^b%hJ+ zcph`cTkCjShe8Eqj4dC$inrGC6qcdqNy1|eBq_nEHF58R`607JpV=a-ABLTv z<3;UZ&}oNG=yu1>s5NSi#!hS4cEYgfbw|GQ6#1W<+r$ zsx0aWmBn6~62Xzdns%knsGItXOyP9GnJHJk?ulw48B}KOy(*Ok_@|rs#B(mXC7PL^+Np z*~Gb+vWl3>D$6nfcI6AwnX@)=~e9`1pjA`cP9UH0$+{)A2=ZY3)-zO^1r9}p#0At`^})!ae}bZ z9kj=T$Zd|pt`~)!R;M*~I)iT4891FMkpHzx$^Sr{r$l@Q2^=6P$j9X4iXOxq@>ViA zATRrDI{f$9Gj2PnSUK9P8$}5o*S#X+x@%^DAi#@0hIfmp9!H-UHZrpM?_H4!fP`x` zv^3omQhookmH(9x zx?#BX7Rk3_bUjo47kobQKPmKUGy>0UHk%`V{AuNXZQsE>Nc78Q#At+^DIBwm-A`#X zOew32yZ-y)yoWKr&yUY~W+2-7-fFg3(g&2AVYOrDM)o&d(Ps?DS%?2IdWP3Ol9Vr0 zi7Pp7s}upb+~OThhyO8Bd&Ntkwc%REXrk#VD%WpDms;DJ{6l!**i^K!f|hq(5uuz@ zB$H_cq*Ry7N?K^b2(eCbOk(rVNi&Hpk5BZPP!^wfj}oCQoU@8ib_RGGlu|p!1-3U` z%NkL6tjg@wz$?u}Y#YSN!>d%Z`ojB{|4{zlxAFgPS5ciZF~fBo)`lL~b?(YpXUn(R z9slpOytc{zxBV~t|C4+e{~vfwHyX6tV}IOq!l5^6wu4T)HTL~st2ye7ykXmky2Hok z|J$Ybe~P38krdf_@Y>->%B3PKBN2i00AK}BInx6}O6MxbNCZqDWv9&sfB=F(cpT1L zO8k^Ry=OHNt%nhvYlsQ2l*_|p#wq7Bk%>#@cd88V(!j&aV(ug^!U zyVBXS226IuW?Q*K$0hVJ(}v5yAj8e`dBX$9w-wK_V$AXh^Db?{ME^#7Qnm8$G5e0( zyZ8BU?~-M2G(yh_yRO&y#EF*NfH}1XZi@O8GJPBF`jgSeA~wn29Fk*npJP6Y+RaqK z!Ei>=muKoT@D>9sn*!(KtE=O`_ODO=ySJ~ieWH~PYJ zmLUMMUdQqnXmg!2vRDD3_-%hj)uD+CR|JyErl`$){jn==mR{o&R*# zLb6k4qfw{JBh3N-QOXHC=lu8mrsDq{xRC#oR`_!MKg9>n|7Odl=lgi%HN#PpvH=5n z_6N;TyWJg8PM}SfWk?BFD|r0#zf=1BXGlu8A(5H5lgaxC-Nf(Kx0T9Ow3vn>*Jmr>b7qLQs+kw=#s1LX-yaf?Gklu~tD3v)ll|TL|PH4?tXSM>1t>U!+1=AIkqV zL8L=>$@@CJA=de&7!+7BIe*wKIwGIByZ+Y$){_iP1EdEd6 zjard6aGcO|ZS&abNAT>-hs;|?Iz z_$Z=8Z+?%RF^w}liozKPP*DB@BbY&5OgInfU&RY!f$7+>^9nnr8l=a^3BhPULWAaj z^D);illiZ49r}JP2hIciz~oj7%FouAih4F*Lmqat=d;LkG8MDPAWmk(>1GrmXTsB>!a^# z7WljfurGZ$fme)E(cV!GMzxR^XaV+T8{Z?+e2TxHPFCywE#&@!U)C3}h5D&)R|EbI zlT`+otFl?^BuA|}3&hpe%W#q2IKF+ioNw~VEGYXnjF!Aq)iyh}7tIoPn>AfU@pjdp z&WG>ONn){_ufcdjugN4(8gHopo*Xjhi^e}P>)F*TT&!+^(-^65ldFmU@{E<}_}=WK zLUPlAAYt=x)E|cw>qkc}PZYqPGQVr}F;k<#BWCkB#!N?jV2{{O1uS&0FW5H0pVB;h zL22O6&M&0j52r{q_Ro7auX{iCk55m&KR*!u87N5f+vr6Sc#u6hiNr{mRR=Hco(k(c2+eSmSp#zc0|zDUx4(G|3K#xHH)@%NwEVAQ@NW{qkCdOFBB{W zvoysw-y#*4zt9baZctFIa;N;jaTx?%pT)&RX}t=+ez;y!P%Va&{$ku;MXI%D4CF)g zuNr|~ATiK#F72Gb-DWYakpUfz6u!c0X7%{%7Cla<(Xy847QTPAbf3Dihvt($JAU_5 zRyDSw*49?m78%*9+I;0}exRFEjfW$C0mv{TXS~!>eVsNmeMq#1k`PxQ1OpLeI+oFD zh1j#|BL?zf^ktNMr&U@HMGfnjXFa0_nXmZ?I2?DnL*MO;8;$YUX@{d`w`D&8t&Qjh zp|uEZ1`mT9!50hnu5Bq0y8%P@PrT((dUSen{^$Oyv)BC}ddH_XKlHD9mlszzy{rCB z@A{^OX8CHVtK%DRptz}Fx@O?cMw`0@vu{t7yQbxA&(C{5S)ae|oz~E>UVTG<^j;lb zy)M$LENkgmzO(c$-|-Qk1_t}SzfSMYb?|nWVud}InJhGpHETX z{&+JR0#DVSP5G;z#XJ!q-@H9%n5?*BTEJg_B-M!|E zXeKNZ!XbUSB4dybz~6A$BzW5-;h3I#l`4_V#E0Pl+AcK6^=5cWrt^37HaaB($}Uf6 zZB&Dym4I9X5c2_!X+)!WGO#^XN*@R`HMyF8APizDFJ-~%)VME4*zBn?Q`le-Ap z|0YI)4ZD zVX{+Do2QKI{NiS-(IrN<^}s45-VuGgu2cwJD*|gZLn#d8;)X>e?=~Sz6CKf~_po7j z%wc-$Vz>|3E>bSj5J9*YixWU%srbS~Nl?u2&M*OX^7<)DuwbvfzaT-m{_ELy7pML2 zFHiTC1{m?sS^JI2$SVzEWI_;~%PY_*8nVpX^n{f#tbZ%sGvfz-hm4d0@JI>FsQ1^W zFr~M&;cY|#CfpFhg>viTPgsTl9HEwVyWdwJXu0?( z486K;0B+`vjkzlN3s}H-P|#S7ur)y(=-{QOF3C`FIkAvfK_ zyxr}~nXn87_)z#CR_!B-??RPo;{F895ANB;Ci{xUwrtiVO^cJ6e=%e(t$6*X_s`r);ezCmZDD%j979OjJ`x2Kk&Ucqc%N*Wm;( zvE_dBk&bDVci$}n%9P>hizYE5d1Y2dTox%5oXg!!Q@lAG9x`l<_dWjoa|W0C3tu|m zQ}yA~YYcE{FcSK*NK5F#nkxoiNVkVa1Rm=9Nz`HjF4mxI;pO(rz)({PA~@#7ByscTKOUd%1eY?2pJ?)3 zG~=?lL-@DAKFFtyi5SPphLUHjO@fqr+FF(oSAw~YE0QR2h8dzsyBuDK*KM*-l zNAhkuAB0nELySQ07_Jvm|ADOPXtG*v7RbTUQ32yxhYQ@Q0j+!!8w(|%aM7oi&Oh%J zfUj1vX{4c+NCY?MWz+{C=zK74YN3PCLd)|4tM~oEW;`Z`tM`L+Qb01fiprE=`)W;Yj?CyDpg@1I zUjFR19YOUIGn-H7d7dOAb0Dz@ad1x>l%@p|z_!KX4p8~`u+xDMIS)mxr15DCfg zWI9a@;BNI!$)cWpHA$AR;FnU?s_vn1VQd6UXQCEI#aZA6_nFw!_s6KzYCLDYL^ z*WZKtN}R_*-QpX{q0z}sBi5r3e8f?mP|!?EfgQkR8HsMhW4PI1%`8E_q-Ojso7p^l zB>)l4Myzp|lOjc7p_z=TM@q#Z@H8=J@UD4Z2s^!;aDNiMH4Yn@TuTM2=Cf#`d$r|BKg)kT~?7k`)`(y%8>VIG%aKw8b%SqoG>euDJf zv6YwSW^vpU0W%qX@@E1~m(gN+&t@gK*;44Vxm#EeDn6R`v`djV1K~0^z(a62D2i7( zR#a%svJUYAG8{m#w|6Vf_emkcbPf^Ag@qN097Z2Sz)BsnlCm_(OjY+N8I;mppoP&$ zrG}gcN+hvR!&tccm8p5q4qPz(TTf;iehji2pb&`uzHcQSWJQOJkLVImTzbzvL)qC% z*M50lURszGX2&$Nh!7ix4Uqm5TOsjyk3Oqb**!>|=^noZJ!mf$-HkEL@7=I+-|Ykb zP?~tq&=@^g5?;@yx9|^aA=s>DTc>CJH~lk8g-&dhl})^7Y~xb$QRU{niIIT6!WExy z)+#__fd5`f6pM&+q+W8&4rzO|uOqp2(rzMvd&>5N!(#MN;l>bcr_s#Ni5YZgHAue_ zq~8Q$Ax%h zIX^w_UtXM^y!vbZ>iGQo-ab5d+fk{HYPg2~BG;?x(aubI}vKOW!!63EPA)KC^ zo!nd-L-_9G=FLg(^fkQ;7)`R`{U47{PhMku9AJ39`Q}gTL%{L`{(i|m6fg8nncd3i z@sAg8uMje%fp)E|_qT3~{9dzH0_&?wVSQD;>UBm{iV0~|DZ_Sib#Z!1VO_Giv;iwT zR?QyFQmYkY)uM}Bu8y?&N>-!nbN~A0>g4?U)Y_)$SlLDlO<5{bzxn1{_93p@aXM}@ z^gF)WXfz(=x+Bv9BsVy6%_|7Bj3O~*lh0*>2^PxU_ZhutJG#WKbaQm~Hkb_QCHcO0 ze%e2NeRgu*zwBL|;nr>#lBSnwk|rpPu*RdP0T;uRd*S!YG<2^4_X+)swq7}S0Ej?$ zzhUGS^NM33Rv~}js-TYiCK%?_`BkOu>mWjQXcGNO8ADJqK-95cC)4O1{hOIRq1EH> z02Bt}Bs{LaV~~KiJmq>M7U4DB`i#z@6)(l)S2yH0+q>6q&o22P((Pa_jE)z(7h4ar zK8rk_=^4V}ruEn8MbU@fAW5XWD_Ej2h$@G^>NR4q;sYZ|h2unv6v=u$#}>J%&mJ5p z{n(B$?m~L@AjgneOk*UoTjbtAmO}ljS8tVqqs3%FK>LhLh|+%-kPGj#ri&T z9VLJ|9s`hY!7DT0oL+ToE-=i*W+_ld>_o(=?4tVqF3@&NH+U);O2d+Cpb{_v*1$vi zwoa?vt~Jg0QZYfp4i>lfEA|T<{4G|1HeVxM5r?XbZw}F(HmMHcj76QiVn4)6iUPtC zcke$XYr=o9r?MdwFdT7<-1=$}4Z*(_vMNPOv}~S?AZ^+hjGO0U)Z{1nNEt(H8-T96 zJaybieNX#tuqMD{nOOwW^OCYj_w4OtMlWFzCAhk&@IFMG z8bt|oD!H7A(VCk3Vynxc%GjmP-Y@gB4nX6$UQ5P*0S}hwjvi@B%ojYFR+IS*d~k}# ze9`*Ij{g!g15b(n;{BWBxo!7L{Ff*BVEmVX6Z+0LaNJ?o9JRV*e>iG)LT4~;jYe+J zcE{~7qJKtt@n13{jPSsJx0@RAT@m=jp-mn6%_9c_|GAlgUnFuW5+fBkE0vQOnJ-6_ zQ!*mB%xB}tyA7l>n@-6rih$2rtwD}WrxT)Z8T4sL)oGP<2N8<;=c)q0-z%~g9;lri{ZghW%Mfqlc7Lukhcq3Nv)19jWxAf z7RcO0Mv7Y{4@e1)hx9sx(WgzgpGf49y#oLB&2Sop;2bEtOILib zJUaB?UKvtl4p#|gN*v>o3I~=$nv5VQCY{y}JPNx~|BK{DDZE;!nmf(|wZ()&)Qs1(eDM<$h$ueiU zIb_&n+dLphTDTmmP*I%$4+$jf2|>IFe`#t=Ssr8|5lTcN#khh&7N1(6%IctGoDBx! z^c-^Vq}{Vw@EI(%(kwDCy)iuPYY}e5IQdU-enXVFInbMW#IHPXd02dO}rZXALvk}low8~DitO4T5r;Lx~Rm&J&Vt}eZfDuN-FBbI&4#qy}P4;!i zWs(Lk{d83#;y|m4SC0j7iKKPbLCVy0(3HMsUXtfVm7gcS#QrKJp<0oyU|KIKj5Fqf zt|}6Q(ghfyz)uj&?`w4tR_(J`m~eKCR9(N79VwxduNzU^nTYPrM5OnPYSoZ_MsDl% zL<)L6>E*J#p7fG7uP37|)$1u)S@U|*jWaT!p}0qpGVW0%-93uoK@&ruxPI5Ixy_6q zC?)YA;m1@Yj2%CyEK(el%}wX?_nSp=v7k-nk!c5)c2M#|5J+8Vic*xIs7WiCNI0EH z7Aa~J8_Pr3uO9S8NvA)29#H_TQ; zs&E_Z!$sFmIiLhNx4KKGHlS55cDSLXQn}-;;34+qRQlXc zrDCwv50wY(q6Ed{T-d|+7n{A4LgKexDtaLQ_FKwc!>x#SL8b ztxLPjlJG-pr@j#7&Lstl^G>F{%;V*)ZYTKVfcex1jCmbieGU<&QqC$_i~X6nO<_=) zIH+<;cma&Sz%kMyw1>x>+A19MYw}O-L7OrD7pn zQmf{Nbg@<~9@53Eo*&Z1UL!B0OIoe0kS^9bg`=@pYnKh_Vq#yxkS_Jd3F(p=V8*^+ z##D9?52n-Zps%_UwDh3d+r)#(41z*R20*TDkb*7E@`vXQ+hc^9-S@?G#8fLuWy#jc5i5w^Md<*lk%?rypKHBv zfnVB73Ekh5EL(O+RI3QKE#tcraR>@B6enOAVP1*@or9NMvbxQn z#*BU*4&Tf$cxH=8y3=F-XiiR)(YcP+dKiZJOyfj~L;>1EZ_t=sL1|%Tc%U7+S}}gF zkd$2A(l6Rc}Nzs1K`R*RDQvt2^~)0dE6JN`JX z*UpUp6%N<*?q0{GdzAQJPOI&x@xOeC|J7`IU*dl~#Rubmb-Uf68+1Y^bh}|IYz@1u z(O}pdv|4V{>oi9lXXtfCQFjONzkY%UIxX^l!x@DCa*5kIa{Qyf-zxkU!%Y?{MTD>7 zA)4s@1`@{bFjuVfidSfm9#=_#yD6iPEUHljMe&Pp7_qQcf|7`!RVZT`hl=vV!aEVF(L`ZZg&fa2_n8N0WJ42J~{&NxvJFz8#R% z+d*o)h;0Hf7PD~I2KSA<9vy~Y%j<0KgWEOCz5>s*o(pZQ3E69M04#gccn5+vn8 z@|eO7E4|m{?t2WIKeH>IfNE~I?zB~&%yzuar4A3a(saOYK{UNo-yiJ2UU!!W7%%t#I{5;<|99m5KOBwfVCqs| z&lL#(s{|HH^>dZSS{jE3!Y+xO{3 zY#dR%qX;J$-tQcIwMJW;PNIAgs4mk;kE8?T52bMRuTu z_zu`rI_k(vpUAlM}lzY#yk6hYMS zQz2d=?y_fwU2c&bM_rauh(^O71;c3Ib)DTrU1lL@=$9p8v;OFVBAkdr9cl5Gl@eP-Zmt&b5=o0)DvwjNrC`$zT5R4y$0F$XUl6&pn(RKl z^%k=_m60Y2#Eyaqr<;Q%SL#9LU}W3Sr4P91%G+(DF$nyq>ko$y3^Uhtn(Ut2%nY-I zOShfhOjg9GL=QaHzd%wE0!zn6?i`dGFiNcz8)_tDHWi9jg@|ZxF^*uB8pNqYK%XumcCBKI$ULSm;y$M=>vNBqrGf89=*DJdz4w=_4V=5AIRF_%g6jU zuGfw2Kg1okF82cZSW|jc=l9ZWOhB^bKW?+_`HK7}0QnDP^S;P`p5lY@pYdqebwS|M z9X6wY{_OhW_NX0p+TO?;wVJJwJ947-cn9_$Z=S>WSZWi`2*K&mdD>*|?czUViW zc=i}p9;8i*q_+ZVkX$nl7hECp(_2~0JY3Vxqehy$7PCm%N~7U4yMt)d3U`y-s)fnD z;mamwk$3~llf^*8^rV87?k}UizfgSTwn&sjc9AFvr`Kjuq_&r9)>1zG5h@9$>9=W&nhL-lQtDjXVmgBu6fG`$zT%N^n$ax?XzSB{YAJ8?-1x_st_Kt8Tioa zANp@E(Hs2Y$KKUXS0`vvasB7L?@n&^-2=<0K%Y0CCDRJU`<p0C(39hkK``eTAHy0QMK!!8L;E43E@n#@*9*0D3%rJBK9g*r;MQ6LOvc#AIk*YE*M)XE^oAF4V{wXV>3fpZs@EbtqOJCNvJ4b)T~RqiLim z8S+y_JT%WmW~ztuR1T@#yt#;hB6BvRO@OXkgSJMyU_06#T2b&*8Sy`!19xN#tC-b$ zdU^%=GDSh6g$b!tjaHA8ibDu(F}2n$7jIBZKR4*0%pLkTAqP!@VRxlYBi6}y5?`e( zv%ZhiSfOBQhS*YS zMw?K`a7rAC8p;?%L{E%4N}>HHzDf}GC2i~TDk7^4{#Kx{S0bxSGRo&RJ3BMAjJdmu zTp@)}~G&v5&RI+jgb$X4f>vrB)i75@3lHQX3Q5TG9(mJTZBVFkD0ln|g@%_PQNQsW)cRSrt%WIFlVd#va$F%=%9=Yxjc&F#s|9@_3;FN)})<nc-vx9tBviLEg-lB>EUatOK46o0FT64l-O0<{wclSV1*OgWNy~ z{0)&$rz0rIB)X#p%NfMI1UMKL^VMoHm`o?@dpfB~xTcKUEgc>GM+_Cc1L7H|0i17@ zFwPBfN{QbRpbhO~cta3v3lOnEaq0411nT9<>W(lM20c#0B3!LVSQ*ltNOAEQ#gfH* z27w;nBzz`h<~&g7J^a@F9@xlXJ`5_4pqd9mzakMB!1p0vH{U80gTbbo?-(u+JJ7{T z1$?97v<5AA=#JXE(ZxHpF6iQ&n(O8%;~yMw!O-Vh5<)X95k3-DZKa~`Pa64a{Fr_ob$8)<*F{SeZwY(%(%d3<~*YXN&GY4kwa5%gOub>$ltGe)f1+;FVyaPS7 z8}PiOK`W49;6HcIi3bN!%tdW$)L_2c);Z@WYIHzIypi#Qg;+tkN-+}vc?=jJK#TYE zF%|{|7i{D~!+206`pM@NtYya*3DOLq(HMloZZPzR?(QuTnyoHV%Xhhow~StXck1@E zS~hiinrfatJ$come_!7eROYi9CEI7ZHnc_Xy+Y+-3ZI|BfV2{5H0YJX4aR{JKG>pEkaOF&sv+2B{UupnI_%na7|;(}P?^Jg0-{CJ0$% z@4@6z)2k9GPaw_Uhv7 z^5VRAek0Gwyq?m>nW=D2Nk5Th*TV0JdB|1Fd?hF6NeYH#7+oZky|@XZyT$rmRZJ)s z0S#)-gHRL+d_g?T(r@u;)`)$?nwBeF)1(ps9J;Zs1>cqAZmLGMxrAP~6heJghEg79 z_*r{a;XV=PHA6Cxso4;;ulu@_>~@9^mdex|2$vBgQn0+vo9%fLaS zA{urUwW2BJOH71)9J6k1IYF(JqlA)U+_ia}dST9?o@I>TG7G1XP)pT9HgGET*4UT# zFMX_YLjhCR!H92;VW55*A%whbjumO#76Z!DD6=;Dq;Z?wy3LqU;`Gr@i3AAMw8E@N z!W7PWi0DJLQxNZ9n{%cp<5Fb*#U^dJyDu(U%82v}kF!G_$1ti%tdNC!*52hI?ZY{r zigozg8ce5JY^3r%%{D&(y8%D=cRZf704M1@LLvSjZDmWE+?HV$x=stl@?DV2w^dNd z(LGS`8)LkdV2W&=iGvhMFtrD{igEw;Ax&@^tzbN7sZ>-%HSA(A>>|E(J-557%t{YU zm1L=IPn8r0WBsZCW&I?nmAbCuGx&P#TCgJk?=rQLrY(qbND3vlJ&B6hN?L{`RfBNE zL*5yQBY8ipydft!LZvd)&=l0MvH@!Wg@trBgrfFl77nJU_Qo1K?9LxriLxzIQmLBk zbVjZ~AyTlL#+#)SHo}$$(9Xp(A|+vAEoe&QUJ{F#)ym;2$^Yz@zwtJW)9zR^=*ebz zBE2-)`)EO#lOr|K;>BxRG+?fR%Zvf~v}(DmXxquzKM>4GQm(CV$)(V9H!702QcDq& z=B&KFrLx{ZDqVKqcwKhjPzDmun=MkR?M$P|Y-~%#RWEv!Z_k3oHML}D4@`LZ6mgXt z*LUl8(~m1iW&EywJQ~$6=gak~eikkk6eH@8=y+X!HJ^5YWr4D}YB@99H@;|xl zwqgJ2x4bX$pP%G|_Mg$P6LsB@?>WQHa5x-v!cnu^YWX9Nes^3a3Y%dx9PA?h6UP7X zx^V(1r*jlEkDP8={2#>4BSMk$h*0b#h@FIEC#KNr3B2g~mzSqk{nPKzN~HfCy-HvH@K^8(I6fsu#5oXZ z00^#(_*O52rw|vXUiyR89**JAN(Pp*>y8M&q5uRs?Vr3R&c~+XewSY4w0BO+cnPM7DuBK5ei@_+S(?paXZD8gW}S(y??N;T@Co5VZUz$-v$qCu3&5J)m0r;5oowl<*aG9o-6R77`rG#xd_#cX;HvFf8=L)rvV;k9B?s!#K$ zi@Z5T5zZ~B5#M3Cxf63+eVAaQ*YolEL%56xrFQeBm>|r{K1mq%ui^}T>yB63_4H{U0sxe5SOJhS|MW@os|ibVGW%LCG~atGY%Sh+blaX@ zlIz}0JP$J1z~tyuH}q~wTb_>7wz`X?~ z%o~B_QVf^(*p5~bk#D|$G4f^6;d}K{9()z>b|iGsgioQw49!r=Z|?P8|Mf-x{Nkqn zeeb+?1sr$pM{W(1ELy6}^~w47r*YBWEr_q|X=SUz#VC_XmH?03e01-52f9_4_0YnB z6*#q+S|bI};*uOg=f8Vb7lH)yCfVK9s2g{Iwym=F__?)Oq?eBDg^W`4{%0>pajIa+ zD7EPC>~c)E-er#;(UhefZRpmyoNnHI^LDnNUwrZ9@l47d&sYODn>>_RriB#=XZP`b zr`QDRz7ZZCu;W5k!{{|8=}0YkOFx0%6Q~CM?p8u{nL~J#5hV~93>1#3F4?B1~_~D z`oCgwj4p`i>-cvp3;dhX4rk?9+Nkv;+A67YncKdXniDB`+lR8B>bfuQ_>IP>={xRV z)EYnKb>DToE=%oUg?l>M*aC%SQy|nUp#}5yAUM6Y)pNP zwo);tB=7u)T=h~&`Jg+$%2|{~Wt16=qSa){Z=7m!GPsk0o9~QWL7*{gmKnCCFhM9io&ynL`a_VA%)p6k0tAJ%HVt|7Z`snVh*sbjNS`jdVNfw=E3VQh z%flySzy_aXfJTZ|$CIT}kWV^w@I_YD7?2_fu#8^aB}{l0OPheoavFrc8EvKu!pIH= zW#Zu_po~J~u`NhbDX9A-;>jaRu0=dNoJL2ZL+U&f(wLaY$@vLmaOlucloheT!#h;{ z(&tM3l0#H#!WdmAb&P^wYXiK#os45iKn&gea14JBBEWg2kAsrK6P?PjIhk~v9Uc}E ze$_jE{a2Kj;V%p2W+k%U_O7ljuB?=FI%It(R`2u`uFw1fG6JyQ@8DV}f^@**0(%Fn z1&01W&(b$|vdI@b!pUH>gxCU;F)ah&3zzq0!6}9*!0C0QfK8oEoGe_M%bTCbZMZ^P zuxSK7v1@j3c-7#R0$lXXW1f{98|ze#tZhZYTUcy{OxXHa__sM~be44?qNU>!faCOt zo4*Y=%O!9yVnea<{fPLALgf#@&TvL#zT}(;oYs`LDLENsoH!#+fZbMdN|V_HjCi9y zA2oLL_EBaemVe7hnIjc5bK;5FHf8MhW!ae0A-(_I+c$5HPcQnxUjoPZ-m(XiMLU1- ziWYTSe{osaD`;4Y;J-!4$Rzm^>w>U^>$p|Fp}nIjy&f zunjIv7YxVGZMEWV^;*hs68&Tz4T9&jQj zcd7V&F5*AY@d#sop3PRh5^vy7K;+?32H-)shr6QA@nB)#4O5QHMRZ z)llG`tfsuQ)iswU*??KX)=Io;iR$u|S?_m~vNBWR`G*-7=x7W&6TFBU5?Y&M$p*QA zi}HubisB)?f6;wG*H;>s3w=3D*p6}*Y-m56&7od;!)3W8W%L&QQ@e*KR@T@Dmuc~f zZhTYHbl~DNFMGw)?A!Uk?DwPbhyERKND8k+nK+%9C<_$cWFA`sF1*U*qS zZ!@}HZ3asB*PB88ZdXH)O)JN~7)1fi%$2s;)m)gYHp^ZU51kC}K zI1p8klV+{tt`s3=Jd_PPdAC=vTXdEEq(kz;zN9*nL|vHP_u-M z0>|@6){oyMYJ&TSHevJ~(P5BmP56|XiPq{HYnd(kG>QkJ#v%BuTD--5{oi>X6~1elZLC|WP;JPrLgqt6*<19 zbgJOW{&u zX)rF-zl-jMi~Ig~IlnWernID3-kiO84VE`&^VwuQ$KY)A$a)W^<&$9`0e7J9<=PIGX0SD9*stKI2ersr~SmHA9MiB^aFkbo?-d%;Ny<$ z=&Vz%LSE%rg(MJmJG+o9%a9U?o?)%=N?L39sU`BPHHNihn~6sjYmMP!Y1xNGwd}+G zl54Q9A}|Qyx4|+78?>+GYAwAEx)wppu&*haG#iu}FiKqJbB7qUjDzWet_l+zyj#-M z6&64%71K%%RU3#LbZpF@X|Ik`DJtX!ponWIe(e*V1gmk;v)K|25c-DDOn?-pcO`A zXB>8&K{)hw!T;ZG=po{W#6J#kJ4aso$lr$lXV^&qJBh$fllA}Z)s4+ob}fnzSQ|sy z#)<%IhsWm+^A%WqR^rnZJEYVav@*OdOG~qcN5k9A?EMPt7Vg52le^6wasT|?V_zIx z3caEi2Ppf=e8k0dq0#7c2cFw?olj{r&U2)HdZTeb&3bWs-r{DEX)a!H3qTVO+y<%F z3JL*ntpJH}N(pwY2vS_g?*_wlE!k+|QQ}@f>pjlB0tZy&UI8OOO$Wrz;ytW4;Z!x~ zgjZnaIk<;J48m$tSVmz%u@Hs5pxFpz&x#GIn__$jBb_fy11A9M#bv*Db$kt4wUhqI z+41*1i|IHo`1<(fxPNnXe183=cZEjda7}@IK}3)H$8iMuTFc%SIlbh zn)ceVmtrz>2;B4bI$Xg$t2oO{KXrMU=@fgoRt*hU?_YNt<0^ zB+Yh^uz#Zh@~8zD3)t}7*R{u^7D$f=;gTSY@>dZ$-Va&kk2zMx zc0PnF5`Bz@o3&!NJ6_%OSqvq#sAQ*5$+^sVkOG)WGu12>cQJFK1?&Xp-f)Sw+}hqy ztU6a49Km=qo!;YsnZ*lity%PO4a%d##KzjQVkkqZ{^jx24I(#1LeGMPyx8gSH7k~0 zgl#2A|8Ux4SWhR^TQ2F?>U22w!nJ=1F$BOY^205fPOrHsG6q`68Y*rUwpY*lZ?8oc zr+|AY0IQ){Hg-4SjQc#siDR z3q!}ZP+ZMWtSB{Ces6!dl9V)<7RflLHEZmoLqwFi(9R)f>u- z=zJ1JW@YBIrYrxScOW(^ebb^$OcBmn***!`?Nj_WtM{1x498A)5Do?{x7&)Eo_zwD3b_F4L0FO$|4lp z@fc?nEy8i7aw7Azi{fzgi`C#vtvUmbS$fSv61zdS_W1^Hx8b@`dAo|zGDCbLLR}vK z?U%=ap0XTsxQhVyLl#y}jMoUryjWprOv+AaJ_N{P$>ixN@%Tn6XW{z@CCQlG+$Yt7 z^>9u@o;{tebG1aZTV5@IH0c%6Xf!g*$LIhZ{zlsErbR5y+R5r09O3C|-^pROI@o`a zanoD#LXMlXV7e_cd3)FG>LPf0n}Q%35&XShKd2C%G2ss6GE6>R7-%XGwh-;hWiBRL z7sa`Nzti>FUf_2e$l2QVT2AN&Zg>) zq9CuIjKINvJc*V^I@*-~OwM^EW5-zJYwotBb4N!CqBxnuw0`it-nn zgDZL!IeN*q?VM4ha5(Lcr<4tTAKkC$!~dz&`OQv$4IWVtuaZ}bX1~(rtA&fwcD2Is zqU(dS%&PyxPiGhB2c*gd-oO2DH=h-#cJo8;>g@P5t_VwU7fzw71%Q{YP7d~B04|0T zTCg-aa_UhG30Pr~K6pTR<&N)m8VxUKjRwu2vxTmSH(4AJc?Cejjt4AzN2ZumSac|* z<`@=?I_eo-n9p&A$RU0uUh-8Shx`XzptJ%KHR90u$u4j~F`(rkh9`sqTB?z|@MB-T zL9xa71NWtv%=&0>6s=Y~FAd8|6VzNcedhF1#^Bk<6dNENrl;h99mUQWzSnTLG3pX^#G$FI9Q0fvJ8-zsooH%MK=g((ltj{kx`u0j2D{Py%_&-oZQ zkf2D(K*w<(;KtG=|{j!Bgy8Zh=rty#`M(#0|p4xDT=*zL>ApX<*+1 zy0SS2Vm0kqHKpVcZ&mG+ZQc5}kTvTd7Lz4kDz#vm&;{T2tZ89uOHZ}FQNI2yeJCoy zdsc(3V8>;9q}#=F{>c__Gc&PHPRqc`BPlhFVQS1UV;z%wLV*?R)D+;#T@1xpLK&@( z@Lhw4EIwew+H(Rtr#z?SDM{Mw&{SrhNy%zF`EQ)|WDzdIyA_B$Hv@WoxmBQ-1k+*} z6$cf`K~7Q_IrCAG0j$XZ*7kP_FlCrAxMX!>sHO1p0f?A~bGbMs8eoTDvW4wf!lKqk ztgv7ShtZ%t3ZrhLG4hAaQOE0aw`2*+*dOrGw>EGofby3sH$_Pp3Z{ zYC9|g<5k{3dQZH14_J35}H7h={Q{1vAAx}_6hHZ1-5 zVue}06o7r0FW>)t6K$eCe{lHW?}-&MF%##V#ZZV}FWBM_=bPC&b={SD(QBMKM|*j> zeyg9IUlfp~?uHn1gbq@64f?WNWVE|A^L-=psI8Qf<7Y)#SSRi;!c#e>bjF<`=X6BB z=t20$?%Qm2x)^_3zP)vLD;AAeykbI3u8mXCVY43R@LHui#b0r_l&~ zFBnE%;3Jdr4JH2H%r?_$Ne)Eo7>-k?=75wGgyjGEpOxx2-=qslzq@{2_v^2wA!L-g zxRQcXu;_U;U)(Pz?{3#*e|W$&IOji}ygoUmZPlXAufMQ)!RY5UD*;adWbzMW5jL~MEH`P~I51`V6I#M~K_=u+Bz{X7Uj#9kRI9>Z zOZ1u2AY^3b>-F=5AqU)5#Y1}WMnq|_h-)u3$VkgBk|++?#?7ll8J1a9v$oPGeG<0F z*4h_U%`2N+A@g`qCa*9(^=}Oh5jkUapqb3H;GSWzD1~CnWuT7{X@<8{Q@S=x`BVua zw1W0V+BM%a)gj7xtBDSE7^jbn+pt;2Chrm0wvlF9d2KAAg>g}G1CJq{cCiJFyV9d4 zj>G8+mnS0yF?JI-V3te<-dQK;h?e%a3?WHl-Ni4ZWI39nZVoNpp`G?A+<)8>!&4MK z$vvCi7Ta$s)Rd}>oMf-GR#o6oy?1i{!%d9N^$u^827y*caglZiG1&SCd1AN6oXSijDL|*lsS0dzc1|K2MqfPrw@;w zC>|-HNM%hCKlO!8!ovwWo~oh(3xk?Y>(#)3lA=CW9mt-m;cz*?p2xA{pYx#S&v|rP zQ9_H-{al%zEMeQ?5`khH3(I3=13rIF>^qZAUJdrore#y$rBItyd{T-fK*U#9VNW}dnKEy_ zS;x~sTDr|}GYPLwP8eWlw?`6wn^_tJ#fmY8CPm=0I~hR+E3J|sq8jliVr)ZZEk~b6 z8&!TvSx;b<6dDE}g}I`@==}u^2d@8m_T9zler6wrze*YiDbDxl&AJ@bPM3`(h;~ZR z#ObvYMmG)=o5|?b*qQi9{H`3~!*IcJrX}$q`#>H~KE`eh1-S@%@*@}(W`Qq*ekA@=(FkaaWR@|2ald(JJr~T{R4PaUS z?3xb#;`KfQDWxrM=3tjT6M4^6 z*7N!E3X282e<-}s5<4f=bNIL4cx460EcMNur?G`4_8VjTzKS8ery-`e*m9OoK}jZx z)um(#FIGre0Rqz<>Y{QBTLl|7RbPhG)6z-yZZAl2ZP!SJMzJqN{)}JKXuOW~!{Eos zWzaecB+G&+h|^}Ih^Y!pGMbXP@p{FjPMR5ZwZ{`X~599>LlI7witaHmCtLDDx_ zp%<(|_vA%Q4)jl{?Fc+oyVQU|o01(!{AIV8hZE5hDry87i9N96N_K#K$6(3dMz0=F` z?g?o2(U2u!OWY_Ge3w|R3(-e0#XD?`k@-^H5) zMT4+PbWgC`-JXrKs$@{bcjP(5egTW)SR|z)bfs#PNt#0!+;t^11SZRqDREJ@R-U*; z_9^yYzDb@!QkiWgSYp^EC#d6t`}Z)N)b9D4K@%`{_GVA!p|5pm;1Ahnp!9 zk-fn(3g5>>?vKowDHr-bHjgH7nY~U&WNYM8eO1+^{^pQe^X#$|&2GcRBAPL;qCE=y z>H2m#-@LnhQKU0=@E+|7jFvMua|n7M)&~uPhk=b_z~=J;{|cM{KeN>{D8;ZFb%1Q3Vplv2BDnRmBxdUZII8VmZYVn6;My zxYh1G1?-IN&;%kDOLl+^+OY`J*;EVl7${1q7dAWfl*I!tMH3|O=p|ClhTK3IS4vpJ zhQh8Uiz+X%u(CVS?1J&7QkddjT2cC{mhelot#b(%yK=fltHSO5RQ|Bz(q8z;vT%J7STG#~ z+2^EXFEamV%87$F;eFC)A;Si|jAb`Z>ZWCLD_}iXd7#N)oPaIOQmm-aU=A2dxeo7@ zplW+LH0`q>Q)yewf?T%k#bk!LrkQ`xUA!$!VsqEj{cQI`DehPPM2PqR?0Ycq^1xLX zR7Jt`=C~RRJGGwhRX~%bO&tISR`e!HS7grDjxKq4%|N8BBtX`LX3e|f< z@9G%-@|pB{+pCAAf)H ziab02@$?maT78y%o`~B>i36oT?1sm`tZ5gV@nm`TA%p>oUkQP+^yC)qSJ03&m*EC& zm~r>glN6EVbL@3-z>skT}=xCkvKqXg;fN7AuwwU_70F;Q4geImZ(W_XX(sqscNF zQXXGC&@>4-`^IXdW}1#zgo|Kp0@0hY%uQZNSsWj7+yP3a5J~>$*|Xfe{p^39)%4KU zn0g9Y9z=w4SgQ$T=Kg1<8xT9O)K|U2s}_j@V$8Jig{36m#$9wb+AQ|t!YsdxUO9m# z%V-*ft4J=BtZzdi)~042tl$zC)-9t*4|v39$H!^5CN_ZOmE1D%1_I7)y_`m~OezPY zO7V=tihokJVQd%;8By*Q`wUchP1ckq4q{$wGNY6Xa2sgKicx?#s)Vqk(}@6%qHaDF zVhqNXsb;d|TjHqhjBG}N4hX_?pm^M6k4lvs*?k`r0(n5hLhWfJF5d!J3!xxVc30IJ?ZRRDyA4`Cw^kSl={{H4)LdzPx4V%7#)7CRTa(la+O0RpPwVZ8UYXh9R+do(jWL`sT^%CNESwVns6|*;t0J?(i4Z z_tNIyHuKLgXq_rF!xY21)a?7qlPl?TTgbda+*Bn3$BeT|XaJf(Wxo^w9P1Y4ZhQna zdaS;vl=R4DIi=(*as@x;2!xTh90SusEB{s$g@8~}%c&}UV(~LZzf^$J`G_bu7G6^= zCa)C;b)+XYhktQ(XC204v>jFIvgh181Rc`XQYoOB!suo<7V<;OC_yasG9Ug<-?F1v z21MI`W?er<^m09$E|tVf*|d~-}~4@3~H;~Pq`plWqs*ly|^ZupLxKUpjFQ| z>rm1MQKJo3S>9S(PzN>Ew-^wgvw?`}zBOriqLm{#sd^oz^evlOy>5&DkO&BE8@vuS zc7UPSNI?UAm3bwxnDGIlEs*tud9uiy+^yP5^wKw>vm>mr$M@d~b=27YNq-D`(Naia zjmvHus&zr1Ec|J_pn0qKqVNhn1R7wf1PO}B3e$&C-fT6zjUZqpk4wBFARXhn0v`TS zjRrrSZdSMb`G>#nA7lb^m+@Vn2#Cc1n9gD9guVbdve6%e=-I{VwpjarA!cp_Q!9v0io{!wA63gS z>MOe>tA)%ru+Xg0#Hw)dl~g;h*)vh{@y*2<6Snf;5BN?evWZoY+{9`Dbe1m*Ca2!l zVJ>YLq`b^n6YQCixSRe@7gvAYf6iYs+$n(U2F~=w3CDJV+MKf7DZmD^;?i3?BLTsK zx3(P6!}fJNuSeh1va5&eXw~`Lww)DQ^ewhCCSKomFKfQ-Wj1o|8hoC+SWHy@Fm^Ft zijuon$LsQ2*m~l-{l$7gnX~a+J@!*!jG2#cRr#8(7mGC$=di#eGt4Y_P@%*C`3}!v ze23TeSQ;ID)2>2DpGy&E7*U=kqhEn&YC4#joRZa%njxzSNcKb~R;P@9k1_O+u#l%b zzrO7Ee(as!2oLlmQ&c0DZ(sM6^y-!>na5y_yuN;Y{iV67MJ(xvZ;;rzQ0l$ zLt6ma*z5U+8Mi%njXBH6HFNEIh3SgfT~u!jaSdDXJ(oB0-DDQhu3teSiyIMs z{13g4(Qvb-SKA(=y~#!q19_t!Z}buplJZnyJbkjQ>gCz#rKn1$#S(?`6*?b(=Z`Bbs>w4^$x=cu3hi7%P4&#o;bZzU6MYtZ`7VE>o z-ABLOR;%sf-;Up6-;UdCHiLh21Ha|A+JPUm|IP6NCvg6aIFCGc{A?&?T@vzdlrS!C zquDC0+-S0Ris3x<=go3{N5&pKH^Wxb4?2`!w*8@go;F*gz4yr$N$)$B zocGYXXJ(=AIA#+1j!Z(of-Lk;nVM1NV{9~{;i&5l2A$#4rezPvVF^(oEjo-nU{(ogG_kUXt;h5 z`0a79Wu8v0@dxJ1YPA7B=)Y?2$=xKJvD~8+Ekn87Cy1i45qC;DiMRkuiC}%j5GsC0 z9+ol%WxALjKB&14sdihnrfZiQTiP#}O(S!R1u|s_!E>5HHiE0LdsG4ED8mVAn2=Au zDiA__D7~PDd4bavC!10+324*I6Ka@is$sz{5%V)8kxD9{Evueo`u_O=J3UzaBSKs5 z*+Rg4NIOBF{I=Q~de@&(-BRqy!qU)jG#TUaB@FeE-{Z0hkegAi+in5|~U z`N?>WiLLb2%eV|NXJ*m$DeI+vl0aSgb181w>_Vb{+Ris0JVrI}jqH$!2Lr1x3s&qhU zMm&Wgng%tNR%<$K@~{wa0JFeFePht^@?f@Qd`Pn6a9<=X+!rzOWm@3RIC!FRNfoo9 zBL?96I2Xy$>Xh`lZ;8_oq#Z3lrM1WhypK_s5aYcq+@W>O$X1Uo{TZh*k*xVihT zsD-nIfITfdu#ICaW_VrSW>M;?i^4# zzpdzh>%EWbXf~=dd3k-lSk(vj^<{K7|23+wqG>c-N2B^;zFhB4{|o=c`roGWZ;t1; zo6Rr!->3MX{?}>w!_aBA+rwz!`ORjh6EvI6QMVO(LD&wQ&>K4bU^K|n|Na<`CU@jA zq_AAh!uRA)zrursMGgED=psFjypD!k4ct2NT1NrBZ~{(bs)3IPLsG6BMlcfVe5~ksCqjXY3S)ZE-$vLv+SSn0>^7v0h2%qcPyed$#v$Ir zuOU6ZS>t!%Y(weGeM5{08oA~c^TzPP8H{Cp8?NK7SJ)04c{qjf8KXztG!LxtsLJOd z;o9eJtVb@ZyN2o=Qm(e*8}S=)6H4p~@l6G`@97HcZ57sKw3Sjv=>@IPpc!<=jfOV} z#@$X347OBQm(@%P2aHbJK|@IRrU0YQl#>gvMucxBN}!fOLsZm6n5c~U`68RbxXL4;KCC=^vmx4UIw~^1 zc-p6Balg>@U&DMLQc7Vh|5e{SWGADg8~DM0bAqU=jQzY(t~hky(P)ir$z$~ ziq(LYoKNvQD1!CG06neGmFCbjHpS&{L{oK&9VYr?jv?~rr}4;?ZkUt+HV1**84sdQ zlytaE(jn`_ZqdM~XfWiVxJUA7jZ6+OX)1@z zJ_E^w2P@Mn^VL=BTFe%VMdQK0vrqy^=QdCgu1yC_yW{(eclG^Fph-k+(>2&61g!q;zBpf?5gF|v%_fk))BL7)aZ(U#GQj+VAU=NhW{H%HNIJsIB<%4U9; ztZz}+C%Ycp(<7RBj)+mPezXf>te>Md#RGC1O&8GlTUEgeBV{>xz$2h?d3N*qJ2_BH zg*J&+Pa+I-JBB>2zJ*5%cWJ2>tavw>P42=e^J*a!9}3pf1c_zpVVbhZV7q!BJ+)rT zlvR2OXPfR$oNcy~T?&C^qtWU_W5;QS+dA89DZ30h%%no_e#Yg1$yojwn~7<%7xfRg zgmT6oWiT->4{x+Hkzfc> zx5eZ-ilg&3eCh3;v)OaEdhSMNooKJMou}(cQZ~H`7ZWHP%U}0?JUu!8a~}!!o73YT zFWz4DFMs&!^~tN_Q%y*kT~Y;~AZGBkmgb`&y9O+}F{!-S#sil>PJIa8NP6ZJj4+v8EuDI=7;b4{GLuxx>1yJqi7g7;T9;h69t^#?E+TuZ=0RB zuH4CrPL{Z5DELFsOwtA5sevevZ;6Y(a`@^+5gZdrnbJsRt*BxdR^X>X{aY31^oyWT z5GF#tF&P;Pk5eAaV&P7~rIi%~<%*gu*Y!P$W=_``bVJwK2F>DTOQ2a?i5Y%5oNG%% zvdJI=%O(SfW|Kh@&;D7ORMBR(#UpFYqU1^|7q@r&fw6Ncm5N^+Xq+9L?Uty7^1d?5 z2NeV=`R>3AoBpWL7>qk%GibM4+oBRSTNahD5>hOu(?p8JzOBf_6uEucq8*<;N_6_T z6KwjpEi&0EJ^+_Krl8WtG)($~D^VSKY;pbHGJ01(nXQ);V8f_>7S6(VEdJX~bcZ4R zHqt*J8tpFro6~lhrvA@w2dyvqzo+=1{x591-B#154knb7 zm{4Bnii-rnBS5qO@iV1z?d+!a>Wb{=wQ6njph0eKC#$%z=;LC(q6N^gK&>$!!?Oy% zD1@^SS>4kbcVw+}wxXyA>UMInX0H4rS`+NuAn_MOxC7lF_%?}5Uy0iDCG;Jx(b7cMhdOQE%}YK+R6BJ!Ue!(InSh4jh20=2LS7~*x`v~`5E5n4m`K( zI^#xT=nf-i5O`ad{jnB{AK$DzJGs3s1|(xYSONxiLM0MpG0DIpyr0g)5uVY9v&~(9 zKIT_c#%qgbAjF8Rx#Gsu*Qgob4a%Td;B1H6rk=MOQ#NCj9FqD&KG*^qL($Dg5}OYj zv28$j@r{||8KW3LkNuO^#Q8`uB9X;9E^^vCr)64BdWq}a`SrzB|LpjZ7jAYiH;F9v zy7%VfytjY1j)u#cWemw@v>g`lgsu;+CRFWD=??ER;(!w)ry&?@;{$GUz&w;zB>Xj; zO!2BYQE3O*TR<=qGNu%twQ)SeWcTFig2Rf9<>aP!=6m}P!JY7dE8SDx>!U*%F}DTh zfMuwxSRW0vSwH6}Cu3exjJ&Nj3*h%6G{1!58{Q2jfTFyS z8u>m7mxK97S}0l%S>6A-esd`}N6{IO(HWX%V3VV=lUFAsX78j;UWyc1FW0e6$i8z# zHyT}&!5lPT`Y2AINbW!sc_kf2P$OQaMgq$)C=U|F(eyLqUi|s4CWI3HC#?` z-++W{Bu-uh^?7-qJ(C%>_HG%@Hd9(}eGkL)J?M1BhE13Id=8EZvl;UY#N6TQc+gnN zJtEia!AhfIcTosl(CBOk1rvboe|K`zKfby;{;LgHDew@=og{(LX;w{S0FyUK^t4pe z2JynAoKA{9nOSnjJ^pv^>Ov5|`25iV^cmX*)ycATT~+;i!EvUXqi%~FYG^1G)%Z%K zaq$~^_*!vTaac1R)1z5^q94r(3TYh8Jd!{>6xN`Mgvs`lx7Oy;CO{juz9KIb6ZIUT zVs?l&>%dxk_v%LHEUY2tB{MAOKlmE0@Ek*w0f&F*z zMgH?NAC&*NQRue@LATY4Ja^O`HM`wW*p7n8r=-kp1)YFC_1(^n?Y~`LiT~godEFxj z5M3bt0~mh;l48hoj-=uiBW=KCAx2=M*{=#q$VA8o$b?znqg~cMWv_22nO|&{aGeyF z$MIxI$vK41n&2UUnW5;kur($vH%7Iph;4A}_C*^nDwo}wAEum6n% zR+(3cc6i1J*CV`UBHKf=yOUrUeAFev=wk&gH0uVVAQ%nYu+bQL?cpf!whfxWn=KjA zpH;$O{vH|z!&lRfMQ3d5uZ1J}V*Vjo!XHrqV>>{TH^%PnjJF9Z=me2z~*Khw+?(q5iEdgLtk@ z6FjBkM1YCn+(KJ@PT_zc7GBnRu5ljHncjrnOr}$a&1jr+BwQ}T`vwmzXKnZWkfkoP z44&&a>1y#*hJWr|o%d2^z*|&7SMQx)ob}FLh(TU+i3%+WeQzNWfzZl_ASz0ciO>^k zI;79>wB=X@#rfTlKvF+?AkjM+HU!MwTF5H*7?gOWmw95?L(-vFPj!@a;=YI*sJ|5b z{|6o33*qq%@}id@l;T0|;O{@Z)Y^IeoI8XY3xb7Z;`rD(+$PjwX8IB}p_eKjkMIpo zuHDa*Y8CF6gNYI^Tu&E}PQVPh#N<7Shc5?85W4VlhF{{9jWyc>mUc1wF z8V%oX4ZBg)Y(L;wE^BDaD`93BIF!3J7t+GWC^NL~8a&l05LtR6^F zhW(QtOWKCx&kT$c34-kyf(y64rTqHsd^%dCMg7t6!$1yfmthC~ru$YFg})D>4`Hv5 z8LB*t#;zIbvx!Q!g27|oVv0(C)1SNpwQDOx$zdeM4PwhtxDNkVe9DWbp-KWlDp||X zAKX)3=3O2q8T%%rQ<29J#5r!@D)v7h{!uJ{AWi5srU|XHG@}d&}z2)(QwpsU9atoTkWtLwcBpcZ4ZazVcYLI?Jx{RyU71| zbGxY#uSwoS11|V+j@V3%dFYnv<_m ztz-ZN>jm+57v?ds6-0T&CkEnUTlvVJYAZwME=*-o3}K)IGk$Sh$8P;H8m()|MiY+` zrZ2RfvX+KHMY;in)gA%IU|3MlyI#_O0y<@2QM%>JoYQeyw`y~W1xY8_G3F_St2g#> z1@=045vLdB*Y%&~kls@3{o*pGYuTVQ840W%V|u%|=bzxu2X-AdDf$MRA>MZ~x7eEJ zARxL40b<7W&GF6K>;A=`Yn;K?Q3UI8h~bqOw7o*;pUjvJ>S2_O^UZ~ZE+4`b+%VR~ zEnFBzVc$5xR~m3_6TG7Ya6Yn4@T_<9!^P|Vf4%Kp{k4|*`ll;804oSs%jMRG)saK@ z=>Kg9$$-?Kj7p=uQdjhXhGVRk6jE||{MXZqokwNb+@i5iYynA{HT}s^*Ng$`g#yPqCpEvuc5{<{IB< zKJD;IqdMBl4BX^Mp%u@xf`IkbOXC<1HP{Mk8OZvL!8YK^@-6&KLNpanMto>{ZGAny zwH+}iWMjjy9AowDCfPVl3nxVP6ay#y5X-V}GHa;|sMk~9*lMy>)a$Tkw$jQz)vMqt zO;YOcb49NKVEu-jsAi4$I7qLeV~x(MB{!_i?CACD|H|Xl{tKC>hgcrv86PqBOdLKM zs|7v*3t;V|6;qauqSa&>jkqOJx5>C)&k4MpS|V`^BT~%5sH&S26*oH44V^~O7dxcK z`Z#XjDfT~ccANU;az2Ra+*bh2fs~Yz_37^NzqI_oG2}mi)B2MC%Rm=lerH95n~s!C<%p`Oll>gffUNMgHR-xy>V|n;%qP?d?QZ>vr-$Vk#}=4|CLeW*u^UPNJ%tE zmqfq&?}YEb0cbTruA+BG&*r%ZJjK$>fNRAEbjcc5phSbH1LD+u7|sZt-gp|WZlh7m z0yAi^=Wrcg(810gH!}=3GQl8@%r+%ct0R|)MR0T>g{<*`?h}?OuG2ANC3bcaD{-p; zJTmG|qtWd8LE9O*Pn_R^r^*S`fR0_Pavfef2y9U3OuU|N(dLnmpdR6?()RFj_fLEyK?LATLp zdrmlNjXK_znohOxlKM`yDjFjNkm8yep9RRfax`qvs*74Yj#Y zvYwfJQ6S7XoJ{k(tJ;x(le2%?P>JDC6_kCrOobwK$|7bcKsD|TzF>a~O>Q-z@;55> z8PP73TO)6nqL_JkX6k<=-hIl@M@w7E0^5YxMBFyXK`fc=f$Ku%l8yUjs`fR{?acIZlu8D6^F8?OEgy@WE8xy4}^uHRROY zw~yvPOVfUNbCp#V&9P*1)3jMI)QJsh5XZw2-LJ5Bp2uKYp}m+oSwT#(C&dt_QqAx1 zNE*c`qt$HMRGE-%m-FUEQE}8SnjSpmRM3%{<3GZSp7lDY4miqLAt2QF`IwWjvL^6; zFG46*r6@&#wCk}^Wmcl}>YhnFHl{CnHWy&3y|-1gm%bRrGhXNJ~(XIk!qw zg(QEE#YW>fH^&s&%VVG?#D=sL))U)0Y?CD{HB}p0Qyie@PFKw}b==Mzudv({BYw_D zr6fIi9)pd(SKz9Z(a1NFn)t0jc{qWUt+Fu>D202kz#{YTQQ?xHfRqK-hoc@OdBFOe z=M3LhmM3BQSAbTm$`Ol#=wF0Z)X3rbZt)@}u=LK?hZz5TdIN%N&EZ(=3zwf8okg8;KjiHiro_8cU3z;R#^}^P@`6- z%{?=KvzD?N%&F?BfLxh|c9NxzAq1-G;tgcvq$3sfvvrrSA$1Q2(p77XJU-3@%_R^bW7Y%Kps6qRkcD zlW0#zGSh-=Pn1Bbto?Z4^4S5zOD#dewj^O1iAix0vjKtIe+MoGYizn{fj^T2+D{RZ z#L^MvXxa@RiLCwvAQi*J{kNH=?LZCkECEdiLD}*1K&gmKzW~z?%qGh_+Vb5zU>3?F zpd2(xuCAAgZG(P5$LC)xg<8Fk6Tv={)2Qy9oS)qEPfxCI&?;mU zzrMeo3z3bQ7F2k4>}g3;;8LoCX}(yo1U4-fnS!>X$CI|5=>^h<#No-)#i~RBtvw-( za?)6>O&)$}$QS7x#LFuRTM+g4FQx(|K8_pscKv@3L+Eh>fcl%C>Rc~W2fb*0v^)L3 z*V5v@1{nXRpW=i1|Bl!04*a3l_Q&C{({lW7FdlS0Z`gK*zTfJ0{iro|I_+Kg zf4C0$zndA?|2L0(58A0ZUJ3m_!%m?ufAbUJ*vYi^>~RHSVpJ+D+66P}0=^UjXJ~cC ziY0&&8gg>Cn6ls*s&Mfg=5CxXpsg`@Wp5U!yGJ7`o*6RSN-1AjyY2)@caVD06U22A zi3o#TDA#wVqLq5tMq@bWw7qfH?R*w0TCiWBU%vY(G_;voRc5p&yjsT}`gh^q=F1n# z-;pq82x)>4xaT56PvH60W?w&;D>&ADQf zQ~Z#JsZ|8o%Trlz7NZoG^9QJ`?amI_s%&mL4gZ!V3lbqS$&v{rCjC%=;&Uu z@fFu_?-IHNprX?A61wm&dhZA8y$y}_a~t}@b7;IFSPbh6;45q|B-2qyN1nOav$W%= zKhTdG9Ku0)%oAJ-S_e<A6av z*qap{&ul&3r_I;Mv;WvM@V{p@Bn|I@-T%7m6@16IqPG0rj{3OfKVICOl)x*sIM5Lf1syP-LrdxxU znZD!ITvNYgj07zK3MT7R7A@CQlr43-g3>S(O&eZXGb!gzF}-_S)UbDEal934X9THn zKx8VJGl)`QC9|}^NYyW6iEO6SFdfwFDKgfppbnU24DNsq)o)Q`^LDL7{XI5H;B}Ne zGoMZGF}-0tebbm7UUN7;e@+>3Rgo+q{MF02jB($-Kd@LbD9EURxqRcQv1xiISx4KR zhPEooCOL&z?^-PgSlh_Wc^z1|dJT&d7%}|?=BR1A8NP=JOrI}SCV=1(^FVAUtDXd; z@)9tr!Hi<`u=$#VW+fu`%fj!X)S~niEJefM0aDp^QJ@z4M?6F^_Q=W%#|;8C{&$=J z4sYspM&|0$*JxEb`gflE-*X%-{!Utf|4ZXHI96gHvU*{-rj=W9*|35YJ8*_nU*cp4mt<=n$lpAZ8h6VR-gptqf&`-V$%y;!p{Th*Ud?Cp zdkr3b(rb`Bo6X~np6OGdBie8uKuAf41AkP%z9D+&Swm2l^bh=v@DS7$ksAqXaSG2I z2$LV_Qs^gK0llWFt!VGW6|jtsLTV;jooMVh?Qqy=jGIlT?RK|y9xJVn;97_-27sjh zx=z9q5YG#g6dLF1Z4^$|x0G?fBtc7ZNH0fYdhed1Nfu$R6Vm%=_A9+h&eUsREc<7o zTZzDZ;lL$Y0L45n#E=?I<6b~Kh0Eo9O?UMwMt^LV1^CxW)eb3(SP}qdcP<9D^tfVB3EP?^iPBFquH|Cus3^E)8{EzeY(> zmHuc`D7)5+6l#dZ$cr)IMF9~R*)uuwU41sqtiahfc+Z;+HI!EitGm zVhBA}jb(5en<_gZT=o!)QH6EFvw3kYW4Qwk>0s5vq~mc+&eYEa3KK`TDo~5fnkn z{1qMV@NR)cYi7ZN1M=H%qUiotqPedU#Z<|qIy*GqE~28+_eC+0v<#z4%zK80H;Zr? z-mM@45`5dLr3%>4G&g7OC4_3ZYi>=K&13TQMYH|UWJ!tW{_}Y2u?bKdpeJabt(S@# zB91Kz4ba+E-WKb+RKk*?yXda3??G;ma23gc?u#GHK1{KaPU5X{QXH`DFW~bs19)Ov zCe;yq83kZujaXk2KVsYB{Iq}Fy8-=L|Lpqv{@KOreL)+ay^^CD%_)lldH0Z;d!~x{ z!GpGUeiQqOG9yZX>#UHnKPZV;K`Phqg8-_w>5wwhwpgP_5}?9TGasaeOQ;sf*$Q02 z-xgBFoLpOp{P9T*CCKltCCitoMdVe{&PQ?&)5T-YG z+@jr~+r;J=CAm{~W`~^kza-+M)zB2sc3?b3)+*K=7_QDrLGJCGcTznBwG*cG)_zhpfOS#b*V*4lKA7J8l~b|1g5Z{IWIDU1n|L)jF`t->{Zo43PZ7 zVFxkb`iuE=GQ3al_q?!F?A6G|_sB#s2tggg48)Uq!?dLhBtV(gxZy>cMP_R?TTD30 zh9oMjm*Ij9BH}3uqNPRS7!O33_gh7*v1C zp@k|VS(oqq%$x!G-!RBsCn+!(cI)8M4u^kgVPYWFnvi2SW+ zVGGlk1(ld+b_IJR<)*8a(B0^Dg$7tPrFF}XG&~F9{Pj!@06LfzGrgd9C`dpwBL7D} zlAzKNzlRWQvK0EDou*(C3#RhcHKU`&at=H=MCw{e3oo1nD$pF}(c!sHhow2$HL?MS zWc*D!hWTbWj8?Jx5zYpkMZ|1`n-ObdvOconSg}LVTzVDLq^Cwcvi;7Yo}?}Hkx*yx z5dzJS*E=4`1O5;*6Yr3rI^qk_anT*rrQd8J%(Guvi{i(A`oQE`sIAFUgaa!<2>4pr zD2Tkq$=*Kkx}~pz&_N2bH1d=o++^IgM#Fc;jx!3K@M%N11t_!va*)~UD;o-Y9`+EM$<t(i&{w4|eGjDy-gOdy`T z^&J%Dor_5}^F^DooN~!Tp8B)A{=RscYsd>dt<|o09kn;Jl2Se{%4QxPtvre$#&Xul zgk7gJus;{M&02$&J9J0wMq?a~2hq@Ljr7fLug&(k{T*_RUB)va>s}%M&P$R%LDBJa z{-Hk~k6{jt+i%s^n{YAthPJc$7&oXDVDCP%WRCPz)qEweAM4SYJd(Y^D?@^V>;Cc8 z)$w2Z*C+qoBmYAIzTfW~#ZFJoDC>B3{1 zvuHUP_9qyT5+Z0HVqoh6GT1tKgKE&XObv=pBS<-dX#)Op{Nac!=93xbSD1_J%Zws` z87b;bSyfQQVz2)xrJ+Ymp9&%lk-8Z>lTDzTl&uN5>5i0Y@#R`pfzk|0zQ??wgMv_^ zz0j5?OYNE_Rn-kB@J*!%1pg_OCP|X{;e`=JMuNtCp$VhmatnTREY|v6xT3fHFHW`p zk{`znnqdDk{!sruTGuH`)-SJ5Ue{4>QQxd4vv>9RqCTOR5`|!hP+x?r)h_eDxh<#F zHtc`=An?A}|2)M9?SG=-xYcY9+{p92?%4C&tue)mp*IXi&bZ^!<1-vKN6}zc_CJB* z{_7lh%_F~=;r4KJF!`yG50tZy;@&1J@@~$IhAM-Idk;q=kz1bLF7NqR&b~jnibHinFQC2!U%d&1 z!zP@vxa3N&4RQ@8L1-&v&JS!1A8Z*tuJDsG8RDD^>GHrM1~1vaPhsD4UFs`iXD4U>M)T8guDT|sSlFGRTyb0CK+s3 z7wF6+q;Wi0lAx(1K~A;OR?1p7!-m0nmB1`kgX8#MIHDK2uIn}$^xiNUjopF2C64oU zOX4}Nh4CdFj4ugamUAUmI*OIZI|9w1jnV}&wZ&Bq9?*3jf1u3g2$H#1AK03So?51Q ziP~nb#Plu&C)#o7^-&IXD1XY5BDaj(n487IY$nxI5|_pG&~?zYMqGR#5LK&5{5et0 zCynVTMJF9=ofLT{e35}PW^Qo5a1)EkDM|%6h=ebc)QzEk?ma>j-eiC+y zDibU89SCqQK!AJ6c(=O%I9zJ?CunU)Cge}V7&U!ZtsZC&2?~G=BPX_4XtIh>~rasT(zA4)#UlFqKaYBj8p0|NrXgHUlCY%vX z3nQ0m;VC3&P3#G8on34JZ&G{3y<^Whb-0Sg9FlEu%z+A&2t2fk34C9R30)Q=jP*~h z{t+t!Os04#9vLG$ViqU@?njBnZOElGAHPmkoluyom7dUtO**bM8l9o*b)0smtYGPZ zK5U&X5;XYoT&ouwm^ko=b|h>E#tiL`q6~g=9-oS)LI+H(6$% zaMEB79x8YeLMMKwj?1X7A(HMS9KXy`DIzHo;H6|!O6BrGsy*xNDn(4Sm%LeJ394Mj z>!7mV3G^$4W!h}(qZ3SVcB+)jO6lxQ7`kQ%uPl4OCdIO>T)H?beWh%2Edx3Q1YAZ9 zyQGV*MiYe^PRnDmu57=t977q4t&xrT$o*~G@IFidNSp+R=0|EE{gmYV;&h55goFY&*hgrli|KD%hR%luMuG#OK@xUI0k=Y-FVbpRQx9fH+&xxZr zupdhQ?-|Dg=BWQSySt9F3(ogzrTyAYUe^ z&W9l0L&gc!K;*&OY#Mu`gz#&#`E(XsVcd@ESZ#QrWc>beJq)jF@eL0oLL-IG$J7`h z=uejmKK6bLb_CcPxGUfor5WX7NY zPX27QetD!|;029pg2&RECOCHNkc*~c+nSVW(OqMH8*+VPUR@I*6U5?Ym*@ES zbtZDVx;w`4IGo-3U>?o^K!vN= ziB8m_3RPB%Pl|SBu_T50Nb_zg#r0lW#v*7wv|4QOy()4M-{lnAO2Zln%rkjeOv0C-~)<`uu!h-A{?18(Ef3SDC2Z*9X1g=gUxTLO{ zyqs_QOrZI^YYTQQA%QT>`E*1zLgG#izw(V7(tRBAO(kxfkniCT2WF=KJ?iew4IQmD#nTQT24fhwRfc~Xt8#5ctZO;$B4 z@XVD|;z}4T`yKYj$MeI>-Xrdhe8ig_?(?i@AG58ZpwE--wmo@9?msPZ^DufM zga5no_cTHqUc)L8a4lD_coWe}-FEtQWjP;is@u}f=N+<^FoQfJK$}9$%IH5^x}olr z-%H5BL>n2@wQ`OOsWAq%vT8EQr;^8_Em9ZOSjtMM3Qo|wVeiLPa>&)%59IBFNf?hR zoo&xY+w;+eN8A41$$sx>)xq`E(KEte&?}U!ej^YZMx*R}@yK4aw5DvS#Gcn$b{! zNA=Or@@Yf-?pO*8UNEgGaO-7tg`(LE@K`VHmKIBEF@joJjg_k_rckS|(iI#9QrXeE z!AVzA&#IwJ*EtnZr-YrHQ^HQpDWPCf({WYx9N0n6ft_N{0s1mMFtWMRH4-kHdDlOh zNL)D5R^**3Tk3TZY&~Ec+I)(wiYF^evY}qb3sG34`}t93$DIng6&Xrd7r}y*FWn>5 z&8p0#k`*I2#)unmq9hG{km(u`su$0wBy zu!-x-5IDRTg@0Ybj35&`t)gY9WJW4;x0lvJ-wT$#Q{u(@zmhHqxSo=$Wn`IuB?d z`>Gd|eJ#0t7fqRN44!(C2AgxuG`r;kZ7U(~Vy(h(b~PIbAhrS}^?~%$Yn>t9FO-e- zx;)dtCmu|n16GMhgV3`*gr4US+NAYR%^&d9pqFL#$;eMagOU`%ktYl&N9987p-YfO z0Mmi)QCB4ob`1UVAME&OT5h|*|1Zr14zV5v(|IF%M-c77{Qqp*b8OZB&wBR%dzugW z|5@FB5PJi!+wKIe6WC-)Ivv*u!)~|R_quju#%`amJ`a}v+cy4Bzykn#yQZ~kw$^n3 zOw)YBg@#A;#g_&RA6H}kWyWGocwKY|td<)b{q5%HUYEMfCGi5{3zNQT=+0-rRRCiD z#u3B|p2UzGW0blgUd4+9oCH4)lOZ86ua=YSM^po^KD<`PuZ9!)rn8ZvreG7Jt=EMvZHZ4XoSc(9@FIKh^iOikX zXWiA2heD-1dBhcPYQ3C035)dmCyQfRKi$qcBg*F`GQNo?ggpMUZ#SV}-FTT@O}@*TqA7^+;!0&==ne`sgi?*~)Kd&61RB-hWGPCg$|@G$H}x{J zf--g1QA)`*!l?OlH0lRgLTACqqPD|d?&?A2^Ql2bIkFeyau|v-%fH}OD{f^f=iui9ocXs&BI^V=3WlMUEX(Jyc4 zHHs4XnhNWm2A5rV`U0p{h!YJ+Jt@jYDg6@%u$!7kv*;UCotP zNP)bP38WbSTXm4Iv`up9FHsTB3FCKLZS|xek(#FH)vgLv$q=~$A{eU+=k&Q)6x?X8 zF;guUJezWbUEs6GjP@DMW?v*V!v!a^$`6OD-l%84cdj zU#}ncTxQq&iU%?+t%a8E{9VbT{-)bPsej7q3zVp;E2Epq)Men714^9UkkC;MXe~Vh+My=sb?Hy(Ar%S{>s$Z_wOf^<@w)PdExAs zPDZ!J%a_JqvQdg>U_{PKc+D2{7ZMVx@vn- zwPGT+!3-26$}dv=G*JSly_8X$E-|p&Z<<0+OCw(K|0<@V->Ey!kLA6WgxH`oEtRBj9fryMYJGON~Ou`-x&NW0PpbR@X|jz zytwq=lkK=!d|0v_FTDTqFVYs85BguG^H2X;#>;r~g)-k4X*e9V(WD0WCbygxrbn<` zw?jdvRZUbv&|F6Xw+l1=xOaZypPoPg!ZO6;+2VH9v~lEW)*p3wXxbm>0BJy$zek5V z1voe~b_`2*rGr~Nn`}0T*Bnr7(5PCj*Qz`BgcP&&5&NLR{I5+_wMqaeu%EI4W%^h& z)~=#w$O#hhcivVO9;=qJI~gA-2TsCBi?3N@0+Nw-nLZ=q`ZCLB%GL%E!3ogAyrg9) z@49lUs&0q9AJ0zDFa3+3j=w)W+ALpN8q4h~(hvS_C{Q=H7m%u}K%(p?!GJ3eNV&DH z8#z=!Tmbe%#082BteRk#nBfAmd8NA=f6EXKPFVO z$HI>u9iH^|_s$P4d~$gB-+ut_EK=sEM=JgCECo%=?FjaNjlC#pU?lWGKp2?R?2m^3 zhr@dqjE27wX5qo?|18tCUBUjZ{l84xX_H6K_J2?CLHoZ>)Ecy-z_qM?%kI0bXGVQ1 z?)N+WR;L~HLoaYTEypy=?EiiUqT$#$3lfZ^|H=5T&+uTTF#|k?JEG+n2XV;E0PS7R z-F3hW&@3?n+%*W28X1zN)_>IYPDE0OuRn=uMie*X$F&-?0pe%Slp2HOBt#oErL7R6 z@Fxaytje{UYqnXdU0%nq%f}!Dn(jV`04d1_QD*HEHl%S`+0B9jhQsnthhM*nLVtkvRh^WrCq|JOYYMw;_xm@Nb96BD+^^-ZwiD~*>zM;+=dEGqgt>6 z(vu_8Ly?N6lty0r-vsJVB4#MSHHA0}=q7iC7E(7iiopni8()0Sh4WpSUDIxLndj$&4vZ-Xu$7m}n)*yhU~JIh1V_lf)R$V^_64-8 z;+_?Es*!7V5szp7mta0&i>2{d%vmg?ofK7OptY%2s6{SpQugqNfh-Jwt>26?ATA#b&E zVtlBU7fT~-8OlnUCE(R#xH(OxWP6dX2pa=54VlKNS*BfDV<{@a`T;@8BzE-IA5U`j zpYbs*w=4Sp0^W^-QMnxO;pBgwYqvA`U&}=KpVfMn|2@SA<$o=^Z%2XGb^6^nwoKRV zn^DUP+x?CkcL#3Eal7p}j5-e||NDsUqBbFTw^aUT+q+(S*XbHNrc>qy%y4wI9I&Pl z*xgwU$a(}ZT~JLBX!L^cS{C31Niq$GAOyn%qv&W1@v1%tlSNJJp-xkV64vR~V3GaO z5&Sxxu$hLz75N6Ux{8B&e|i%qwE^L<`uTzz1XX?jV-kI|RlHZe?G)4?zvMaH)f zm*QKHwqkMatX}(;9>0+zB1%Hxujy+7U$*K_twC#3?q80fYNf))?Pp6h3@6Gp3SR zh-@{D(+O>lQ0L?}0fi*a1uqe#@$vBLdI1>uYdoLcO{)Cx`ES`=xCGj=yBZO6UIGo} z9z+D4^}mMbH?71((Q&6`hCvj2&1R<)*n^f6cJ3&O&YE6R9Gz7J#=48XpWT)w(XEU< zC|!O{4VpBCkbLI^6@062&&YdfUbL!X9V}Fw7@6=ZGzs29V&Hq zi)YF2+u?Ldw&#^k&W?DLFfsJy``-ES-VtVk!!XQXUz5+t%g3^q4`&Aaqt-w9aO_{6 zAD&$l*F`vP!>-O*6Uap}$q&M5lHiWR3n_uYHQB=C8sR70UW>KF+W^{|MtT#ljp;1_1JVaiovb<3! z+KqE#z%(5-yrz2>oHpoa;5om`WWGRxuEJ=L-2t)mLRIaeJ&@A2xb+~Ko7au>xg?O| z_(WPSmKE`SQo}c~!@Lw4mX0nNtQZd*C--mUhMCC-Gb>XuZr@AN)*3_94kBA58MP3z zAOq&C$sY8F3!kAH6c=_8gq)X(GGSq^V1OX`6jE%;w^BDU3{xv^i6(Y>+{;y=0%E!l zf*qRxBdI)<2W4_y9b#o9=?TYY*$C9VjWk^WXzAV*0kKt?(9lSvMOqi}jJUfh^I?^lcRc_yD!c+B zqEfWrtX2_y74kg_hOL1#4}%aD^}BpPRdl?0=A&58t3$$KU9Y-F)-;XI$39T;?SZXc zA3!UdUsv%gQtD?XQNCK~Nu;TwHK<-+Rjt)h=P)WO!58Bx_0)7TX<(o_-j|Wnaz*w- zBb{_=|1OGb4e=Qw%@K9i+Ve(XCKc_qz|(~idLJqRHWui!vGYY zl&P=Kc6MACdS8wdd$wnOia<18c-N&0ZmX43a916pUi+)%BJ=9&735jEE8JC?t+}Oh zBd&Cz7QfPDG9^>VH^F5hCN)L0?T)I-t_s6k9O&Xs^K7D)dTdrvd`dvZ}~yB~K3q2~rc z)Quy{3B#DYeRTb=Ygf_#B91-8A6r&LH@kcHp%b05s%~f75whN?=7lSRz{iX zl%3T&i?_A0#d9iB$5lg% zI}Z_BJRQp#%1Ks*sY_eIz;*_1+io@kyKT9xFbwXfF69lcsVwEyklCZGUKbg?n(<8( z4*;F0itqi$W61w}d3o-i_0Ii^-pR%3x#5%)qi(Q9yQJ8=-ro85r#~8QZAVw`p!b7+ zvUl7ACmGOD8deK9^1>$fPd}Vo8k^#CI^GM^aMIV?D<`&N{Da1(5ew1TRA_`v8yW$? zx_A?Dox0!=MeQ%H;su0coKxxECNjuWxdLCACo? z^D1!Wm9^N4v5kL(mt3Ekb|Sn>PZZ_8^l;CpDR4C>oA1AfSi5sE$`VcLQj5>ilvx7Rc)2r+;3-T z4zf(lleMU;qw6Hg=cBxBe3zy3p~Kh#5f{XN<9GIiWiab62X*6xc=G<$be8{^yuc(_ zl2e6#3ZmGsyitSKkwW7zETW+vyRZ*-THS6gD3bpT=< zqs*~T%?+z9lv@-;Na71S zfXi~Z?9qq2Hf3azO(Y7NV$Pc_Bkh&zH^4|HtQ*;sQn;`biBi8?l4%Ifj3^g*y$YC0 z_Q(x}RHepBdBcr@hIh4Z#WgH7%}^1&vSCIQ^wy70*rTeUMUfA9M!WA}I`I^QTSH$n z0$yS&fsq0w?1EuSs4ocK^LY61>nz(mR6yUmTRhOIRIztZ&+%ewhdkC4+d9ZNT4d=U zF8+P>$ilhvP}U3T3RSXQP%8gz zq(uImRnp=ZiJ@JB26gszGp7z6_#W`cP)T3>nkeyG*y8>xOCdJ6#JUy{2uc z(RSBZ&RU)ZA5u!lIC z$KXxTp!x??{xe6s26e=1fE(e1>HnQp+cOpYziZjvv;O}nKB)h9+HueycyVZ2wiQ}| zXLjv@+i_ZE--#^S>;$$Qw>MD?)7OiJe*%;&+a5rl+jMwlXcirRM& zh7RLMh>3_XZ)%1?wf1Zz)Fn5T%mV5(ayWEF#zuMvnam8@#=b}sg}se~o8fpl7J7yH zVh~1f*rh#_cFuB*llS3hNp60$<0(SgxDF=K2qJWoQH|&u)&oY+XQ z*VE-F68a$3YP0LxWC&oyA{1okRy~hpg9+a9Q1x|A?hz-mir$#*qh@IQ+pxQis)EOM zR297K+NuiPv+k>d&jwOW;hmOGlYDn=Z{W3^X4C72p6NN!9pYwYtyWjPXLW!bvt3O7 zMgF*^pc2wB^8-wi!hVeT&o`(iY$nS-X?F??G}Wja`)@y<_kQp%K74IYo=MeT!Hv(xu)}{#F~kgvm88-^9)5rj?*{BV43C5jh#|?a@*$Eyq^{SoKt5QN zBH%JLv(NO*skA5uM4waK+y$KjnZlA@x>X48WIDj2PO>58d*H14SOA{{PTC!%tMIHp zosO8*R!&%{%t!q3^DnQp?)Geog5sNOA74;f<#0$Gas!5lr%(nBa$yyp7!rIoBw?<8 zjK!nn?owNHO=DmRlFF|K(@o9v$#-fOphpYo*BgVD z_CbuiNxyHc*nsIBm)7SR`7sr7NV;`VD=3ed3RcXz+7uQ+jXTD#oJLSuly8+aDYvK5 zm}xr{dQwv%@^E*U<;P{g?lemg$1}p7u2>9?zJ$~-$W~w#jO{r7I@gI!h>xDHSjkf8 zYGqQd;?*(qMfmy1fgJS{FRiszIpir>HWXTeqcN82gN=+{~Sxt8EuRkj3$ zYaqObhRK@TECL#a?>D+0E?tk7TS&U*v5-Pkw?~$aZEO!l!4+l{`bw4rN6o;S+Ybf6 z(yY;nW=g1*Xndqy66aK|ZT{hQhcNQ>*J4#WrAJ8Va_}M` z3>YW!PGKw4qG{v0%7K#nVOK^!^7U6{RXY#8GL7$M)6p=z)vi#tTerI8vPF)5#}d~F zxl=TVjH0=Qqth$_5Hn+&CErMv;k7~TuF({tn322tlw1P`qv;pw>_A!t9ynt~Y2DAk zXc;&0`zr!}w4>vLNbfdW2d;wvL}~&?>TWfSoib9CvB5=_a1>13oFSc&2@1^@T@f?zi@)+$Ck;-&UUBo%-j2i^+YL#9hbm(n0P2$@a#NQeX0p41k;)1Q zZq{jvVx%+l8>o%M-ZR85O)8OHSnoDM-Qg{6BN;53q4NVhBbtrx`28_^%Pc2yCAK6> zSeE+Hb};OlO%5H)$&s?VBP~~%Dd$86?bo>?SxaDPCSA9+r00!r1ur81Is496+vvBK z7wu+_YQ|~yRE!+?t3g9O?f}hwtK@u2LsYURAyQ;83YR15Rh1Z<-k`HTmkhD|Re49H%+ z=B4>9Raabi_nOHiA^GhNJ^1KLY*%Emz=#2K z?F#&29stZo5jysclW(=_ZJW&AvIxyHA7lRXC<7F2QOviL@m&y=$f@7_(?*xTT=9D80c!mh7A@ja@5W zM|v=knXHG#z{$!CuEaR6$=U8a3brxhGM4w6{I}oRl-EsGzZl;MyDU|mY{`bKhbKSm z9m!VJ>CKont*)bZDPRD~V~{eEH;NuaS6F1jYHHqNt+l+o=F7>tt8VDDJ^D3ex0{kl zHmqVu(%}`uGQ0ZfI#Hbl*4;9>^o47q^a@p?sIsk;SnzRN0N3#N8{gC04~~-z0Hqhd zj6|-Lv9OUz9$w}*a-C-)Y)~U-%~r38ISDmwsrPVUxm%5-|I%n?eFDE zTl|tO+1{&DVFPIB60qyW%3N>dm&)BmxYPZ&u_^m@Y#H0xg<718sI)hBb8yH}f=^@0 zFruB(DzK1^z(KLGu@V+?A6v+1so{JZg3Ym9J`3kdc!jrMDl}bkeLXPvg0+-vV}-Xt z#Uj3fpd;1P3#Rhoj?ACex`U8(wj+t)iq;iM!uq}DCi&b1yAU4eWJqs+4S>l$(ofNn zj7FzHb2m&8&rB-H%3>x7T7zb_N`Yr8z{>-vu~CFmKM#Rj8@|pKU3b+;VOZP>ffOQF z2BpRdD5dV38xO+JYz(s%TFtr;l24JQ%4{_~>5oy~en~MpNEwf+fateWoRGV|YAeAd zmSRVv0l4uU#gRs1OTYx_ZdPG|adkzL@jUGyC5kA-ZoV=l!mm>@ppKQU)03lz;9OGx zBfauwRm0rxW@BjRcxUDknx`bYDsa9!*hoxr^^L;-vW`3=DUl+1V;%_+AuTtx^WdRm~C#UnJ-nu zoPv<~%Mdhn<#neM)$mtU;b<-}!r3Oy#rSVNUlnj!3khHo7N@j>FNLw2)>Y7gDauf- zC2PW($~dL5u$x@5Bq*P&T})(Kg5**Lr|kMDsbbT|GDhaZQH5hYM%nriMhdFHO3yVQa z6oOyRR%$CF+{!cy=Lsipb|Yj1@>5!Yn|Q)$FK#Nh!wq4N4Ju!hDaigwLH5srBl@2y zyw*RX0gu>0S4kMj4zV4T9;Em#@U}H2T7Uqf9D|$PR7f8R!y?0+G0hCIvIqk@R1}P` zGf7WDpn=E zY$Yl9)~KKQf{qC{KfhfuaTPIi6X$H=osmL2olK6S={iG@T-+30@ht3Ao*Id(m%BY1 zI(n85SfFmUElm{8jL^yK3w8aY_P9a|lH^*xb&DfjRY2CqteUwrR}B>-j|RglGR7%- zXz~W-$JN3dn3iV?@&6mtJGViQ1A~A!cue#LIOsMo7D@wMg&)lS-)!5i=>KnH{D04V z_Wys15BmT22c1sfnqen0opv|2!nhN(!q5!t{=gk{9dFPz9kU%ibo_rW^Zz$HyIyzK za!dUG0Y`Va3pqhjj9#Ax?x$Ylh@{M)eO^m_&uRSo*>Vnn)PXsj#9z{vMguONgu;(sd> zbzEboa;2di(n#)WbTkWxv<^>?jni_`-#igxzN`M`t%nHtzE-gJ)X}^XT6V{5cdTYJ z==S@r({b8&3-i8qfOqaJj;v&a@*+lo6Wx2C8XGLqB~;V^}3jMP47Hi z6Qr>4Cm;TuMPT_K=Ko@BAal04JzLED#XOiKa(cB-!lY*E93Wv3w@>Cca-a(gR*KxQvrM$lo7GkW~Ph=sv z;$(9hP-ttDh7ry1xLS0$>O)Oqqf3Qhn{M;1Rs1^jQ@JakaTBr1z@Mx0#rGI?U=!9j zMHB$vZ4NlxwL&xd#SNoo>mbL!Iq%Bt8 zm$W?QWN=_V?!X_tZiE!|Md%hGowVH~A1a|Cq`PZlZE;Za6?n@k=`j}s^()@jv-fvK zUd?rpK!BHluWt+vgVcC$d)%Mi+yVP2GgNKuu`I*BsNc6*VQhQNX55LpmgSgthyisR+hAI|^fec%6~4F6LP=r3i6-su4V6f zof7#E!BLv{ks&Fn#zjd@VsIp_)tHzF&THVx*+m6qM3^^nzMN%}9dgIxZSnw;vp5_M zhGFe`x|ofYSF8iLPg1W^P-`kF3aRX(Sv#9g$(&Om(&72vX;Bz%uJ5LC1n&-`)YY^$ zqxB(D;e5KhqB$dHq+8O!7{l!tE9YJ5Y8_+ta$GN`0xbV!W@u~EW)B}`M(Vd!d7cPnlyo=tRyqKgN*3T*8zS9APkw; z={S8i?mXpn0JA8iiT_xTPvgG`-YrStas+j=~?S239@VIyS;nF|8=Mktl*yn{f2R}Nf2R6TkW9tcJIT{rB7%C8An@J-B1TyJi^MM(&o<;OU`&?E;zv3$u%5|2F|Q$k4}Q2!fjBlci#f z7ACB3TYLea0+$Z%GGRNpY4=Cd@Y8Gd8or}h%5G|Gh0oC32KAa>D2bT`3Ch=(WUI`L zQE-b9T-PqU$bsgE)bPfqx`|O{nJWBxI#>9P_U3AR?3HS#4Q897cK| zP}8*RmA{P)~BSB)Yp~ zkeRyBK7++{JPdvOtu9F#O)|ex&wG0Zggm|5^uy6GhBPYFNgk68vVTYMWXt%Ujejr^ z4z7ylwZ%XHcNez^aa_3X9I*A@NwK47sHh$BeGXpW@ufavtwOTlw5f6A!vkhbk;=~h z0uQOdjMt)5>~!j#wq8mA^F=MbA|%w#fw@!BfDKQ=7$`3socM4-x~7fI<334;|TJ-8}UsXE@@hLGJiY{6QNH!CfW+?xsH7OYH*v& zgo1K11%Y`7>^R{W<7mdV z5}HG($!7lb7LD9RH_`=zeTIgGNJnE?ud`O>mSoUM*cAWd^rTm4Lk@G62u49>G^^x+V))zD>DGU5}Ss6;9Unt$%rb`0icr+<&`wbaZ&~j@-8K@x}YS z^WH(7i330~_<~o<7O~965XZrJ$EIpz$i{6TJN(xOLnAT2)gtp#>D&SKNTm~4@$lsE zk`kHT0q)--T-P%U@&?ew(I`ayqMU7d9FP6jr)ZJty-xx0_;*dwMT=+<4aA`EGR?EhlXUi!_rwzqt^Jzb|Rfh+Z!#1`V zr!Dh}BHBTaG+KzIM%I@kXEUgs2v$zQTT+Mg6f0$QjY<3yr2~W`%t|z+dkc3*0c2p1+oBf#_h3+{ zjA~0l#$wteLQRT6C19bhIQJ|>!E6-NznJw}m@XMNsR{4p)hmF>S#_Xo16 z1_lh-J3Cxc-IwoUwf(o{c`n!gwQP89wLQmt*8e@l2lam)v)c`welYL`9jiNt23Dut zZ?(hFi6awCOq`Y(4mzF3)&Duxu47lU|3*DsrhFqv3hF+5O1_InYnJYI3-3w&81BEz zghqb-mSu7Jmfa?v$|@UzcITB>nd<6pnyb58H>W1e&1PV?!dBGjm``inY?%(tXXHT z`~#eQKz)_`pJ)Rj*nKp(n)};D`u})#%e9=K(+UP*WJRrh z(FR20p;N0By`c#t^S(RW%tLV1sVS~H z#-$`2PW6*|>ko1j8x23jHLZIP8AB8|vIouDN60K8$*du-DHqt*xtNP3nq(Xe@!v3o&;l>hD;rwYm``$uu0I?F#D7qyXvx#+s)RcO=58Ju7*~fh|QKso9n@zhN4ElB_c7Kmdl%CzDh7|3(-O=mY)`$UMtaQ;Y z(!!1Xye6sSjLu8Og+o94`bN*&DVp5-dHV8TK2h{9C6>>@!QazRK4L7^RA`%V3X+VD z%D1WYm6Ss^+iW!bBDaD__Z-9UrZ%AD8zb!xF6WpTQ;jNu(P&^MEPB&m%7O~f*29oAjt~j zBvFSfj_|jyG_-`*!JXSOyOJDK=WWHu%YHJ!E1)vkWq_oW1-y~B!j?`NJ7%(2@&>f< z(i?aHfN$nDv`{Gbu1-gTw&>7WnxsOuSI1&G*TM}dd!?CfzjprlkNzS2e@nyvqyB9W zke!5P;F&mR$aQoN=l|boTeiUex6%LKv7Y(=r}!ZMZ<~EPiduGi;M#G!8*~O??3j_= zjodH}TJE6La#|kY(jS%ocgQ5F|1%_&GYAfM(O|w@fc=1;OufBXH3)9RGBSZUk#H z>;@0=sn0QSH3bd_u&#uk(xjNs`?_&XFS`zK(;8|lsL9PBa{kl{O|d$u5=}`;kZ_N% zO0d%fnZP2)+A1BJNziYgW`*8oa4a?cJ-CY;%|F-V_&rx*O;5fQ# z9A>fl1aELaQiCC>k&t_Kcuhn9;S2fzF5~1zOg8MOZDyJh& z497N3FW#OREU(pMI%%L^9kfda3E#qC7KG5@bWpRsX6v#)BiDDVuH$JGkD8=juWmXmxDuxnjw%(sZh=F2p?ZEzM*hwFU!NWAUHbcHM+g4V**^Hl)bvf^Ed^X?YAHkGc3&u*vMd_Yvb>>-1GW30!k|el zx%;5Pn9n{E(3}8<_sh`Y-I?p3pJvU6Wfd;Y4*mW2CrAE8@2IzrRh*I$eLV2@k9vE; za)s@xRX&~xwaT{Z#{s$8q3?Z&7(|cTj?G6?+^Wx!|%U8qWG8vPr%p- z`f5L%9$iA`AI=WsN?zS?iz>Y%^TNVuX)_m|AuFBk-K@B^VnkqHzrT0pe}4!tFx`@3 z>Y$6-BHdAFx@hredn=*2|K9d{m+$@K(}NF3d*>S)MOd=`-jNHs#U)+2q*p{Kq4V>- z{lEDa9}fu|wy|M#zyR{qwsDe1B_K!xp(FxuGc=Ar{3y8IvC|&n6BObbso@{=ez+jx zrBLbMIb@TAsEbe`ogITXdpTwt4fyB`=gij@E`-R6O^hBBhAV-VA@%d+B2 zc{6Zna1Xe20wD3KX*4pRicvji01XJ5#v*^fziez^@usYVP<*_E#H};~3*>1bKhMV=`K>3XK4II}b9wib$ z!$k_vK`0gZ$s#5xSl|Wa`JyG6|#y$6_*>}N5fjYQboh%AQH!`fN5s~<#gn(J&!Q~m4%YA zCMMpP%&7~NxLw)%FZ1Cd_NSB4ZB~a20KAJ)IO6-m=@{^HOGp2+3TRA{H8G4vu@4^G ziSQ721`}`=!k-qM_-Wz2^Ygu*FhbAfs(P5P=(qa%fRO0cLjc9TA5g~0#I|m3)&huH zCj|yWM?*x%)GJybx_L~*1Y%USnf5Ze31_3opM9C9oAZBIz;PN9$hOROy{lN|m&A8b zTPJf!l40WaM?n<(%uN!FmLL>?4;O7^4UbMg`g`x*F}9KX(h>|lZJ-x2@l80fDA<_d z9JE7@=b(+5`9o+-w<||MKOT`MFQBAFioOt$s_ceB%fjqQVZs({nlw9C^BO30Gmq3K z=je;C>73g3qq$OFR|V3>okNK6sP3VhiP z%q`6g;W(0|ur73{!POO{GsG!KW6gHx$va?UN+EN0@j(X{sVtP~{YY7LS_8(?mC(!u=ZseD zD`uUmx<%{8qfyZU;EHAN*MeVNRpZ}9@AprSdq1XqYB^S+-=kBt=ZZY8hP4O#F&@a5 zGqZW;fYm$~r#BEpLb``DR=?|_?}1}>th#G!y$`B&KnNNsn2@`a+)oOAE+K1!r_Zkzz||o&~iTPyhoP6e|Ki<_MvtpEw+>RNLnzGRUF}? zjikNaNB}0`lx+Xo^1*=2Y5(-(^8EDZF#+?K!&w_TUn<;;?lKT}UAR2fK)k|%z%Dn$ zfgsNM5Yy71^c^9=JsSuRFyavaO9+uoB?4OgKWtum@XIEsqfRnq5_ z!`@V2@0KCKqm9I>K9XcM^uz1P$WP)?999^LqO&R<3=_@`1xZ~6tfbCiRyjV>NNJXY zi>~eA2}b7Is#~UjiJBH#cyn+b|#@&^L zRdslIX{qU*6@_y;?Fz-$YP`2*>%Hn=LB46fdU;aza2-I>@>25@bJ{M&oK{;30`??` zlh@dqrhkv2d!aE-Nppso7#W9@>Puo~H!7)2=4O zkA1+!%%lasF9G;UD8<)9Qy!1}$jH~RDe`sXP?k@DdtV13`O2w-+ocQC>be!E!{;ga zHGHNH&(z^TsDo#xIpnr0@7D;~n$ekx@*%p21*GV_@`b}h(LGu2>aVMHZs zCVJ;Arp~%at*BtHTR{&tCSbiI*y6=Cw`nR{H$m1%I&WD9z4KOwF&{BC#A;LG(IGfz zn=5b*MoDkdMRQ<5SP=QR6$VTluQocVJ%3k*bCtUmkdLbjpp*V^0a}9&%FI6pBl*EN zxJez($V1!ns5Bld5B3yA!B;(7p(8ylXfeMsb zQ(k;s=QCwkrqz+;_9xbwEXTf5bCtFv*T`1dH%y>lmEl!dt^zu&-b4HS{!Xk7{kJHa$^NG!*yAPmEezW?dM-#gelyX>9&Cm)Vqi*=VbtXhek z9k(~!Qfn)UQ(Yag3OB=|p`KRi2sPCpR>B~j&*KPf`D!${m(~XEXW9Jw{ERXQWd26O zuznF6AE6pF9giSt=1MTJG!s7;)DVT!Vl8lz($oNzJ};VjWSi)by=vEfi6Hzt(lUFC zI%)kLca4Tk?>5Dg+uhZD|ofLjAvux;P{YiMZ)%M!nf~F z_s$RelfC0!-FWfC@#%qSn%x&vMe&=WmnfKphJbJ(JN)3mBP#T4nJ=gm9*g#V1WqWc zaCUxr@PRzJ_}d3k zE`s%+AtBowgTyp2ap=Rvf3r=yrTTw6?z8{*lYG$sJ97FKApv3B3Y|f}Z`z^L9fY08 zj=KZfjl=%HZMC{>r_BHRcu0=vcw}5$-x9|DzsB@ua$OVv&c(*4|F^m8TDva9e|D<+ ze-k7%ijXwRZriNY_R)`*aBbm~Fd4|4LM_6XFUHe}znopo!782A8?uVVBpAoWVp=Qe zBk!nO2>|Eu=VAPX)OrlpW@D#OmRJCONAW1epN+?MWlsH2|C z+t^`$*EdU$y%mZq6LPjnaA-F2b{0B3W6E}=WFE&V7-w8C(~QirsLXD{)LC0SpV@!L z4>|waje}{p9LJLd#&~S(eSe7Oe-tO-d^p2r(}BtoJly&3xR#Lr!8I}dt7Si*|4;Fu z`G341Y)8?+@&-=FbX#V>8(Zyx8QWpE8w8!$ZMWiqGkE0lzqM;xMd!bSqOS;w(&Jyi zQSf6Wk7{eN1WNriIfNSH5DL3|QVt;pqE`uCUSE-m?I3B;!?QupzQ%A$xCPhP*=cC_ z1zQew0uMODkmNarb^GnFTZ3^DW*1VFM8Tlh3_{Oz;*J~3oW#2AQm$g%T0C2k<Z6~#n?6!8t>BVge}v^XFeoHqLqtx-_a8uxEWw?k_? z_is19m&pbL%C)g^GW{H5@B`a~a0q{cpaY{H2w#dz?={Vuu@4#H3HjP6*u4A>LwE0k z;LiSZ+`9p;js{795!YFHSUdW@&KpXd{jmfq2)t{wM1lrj4G4WC5E(8o*$nk6W?;tV zmn=>rt3vxtVV1>u;zh~We!wUSa2=r(XB-EUgr;uCG|s~8Ort^bpMM!9gkY1(r{K9g zox}#%m8N;!Er_IxAVOL^9LF%58MHN7(8v&@Tc{3YMr0wxZkm63u9xtCoyzh5Ch^Up zaTQPEd9Zje{tsfywG{r(wMemN{_hDs$p5*a+wtPoz=Ld@gzXDjU8`?~u@{UQyYF8m1`n3b!UPcBOy9r>4pwcas2M`0 zE>66bX*O&0FHkbiYT5?G>dS)Cu+k8)B7$f&te1-!ndW>sZnzi)uUR_;(lkjU5-w*z zTU+i8bl)f4Z}u+VZyAH-Xhi5>Gz4aqj4l{uVGE5Jgnl8jsnIBfXM4w_b*lVC7On~T z%=k%=1|)2`#`grYx6mK`V%Rq>4N@4Avmj|=6h$_VFM%9EaWDj33K;?f@U}l-bQDN5 z@HP$>g!(5Cp0MQ#ArDiKJhyIXoI*?5W06BNf#TL37R3g613)+vYA$hj^7eG|MKnv? zmiYpVExoRSFRRK1X<5kxuG-iL{~>_P$oFKsp<~mIKvx4mZJ8Fvx_9lm?cBrD7U1$F z%m-d72J~7@(+yZ2)`^t0s<=UG1KZ@IIrZleLRw?3lp%uoi&!PU?;+gH@x{rH5 z7kSN+_UwC&+**I+)}2PK!_3NyDMzJ|(KQ1GDFw@jB2n8$H%iOy*mbu=>#B`e1v_7i zRYfyQm0+Z{B>@Yo#k~?t{r+^}uL|e>pdoiw5s3!}^4Av+Yt{6hBV$#Xz@wmJkPO2| z1QN(}{P(@RBXY|t0~VIO6R4C)l;ac4ubV$5YIhIt3B+3r>sb^6Dkbv#)Ntsj;W$p+ zYTYZws5*qoQJ2)9PjUfR7hB2?U-|LmaUv0^F=$rAe91+w zDzSFc4F{LNwz@PFk>mazOVFwwz>F%GgV3LT5={ZuGx1wDJeFI$1cd3c{OP0|_V3Q* zkUNe;Iey1=y}DyQIn1r#Rqp=@xG-@!g^3gobIMk?d zE5?Cb%m#*mK znK8A`?w$Wx?w#oA_cc0p+U*X_YVVmceSHeYPRm-)u~Q-ucXjD>*7MPnomifIHJ?A4 zPZH0EaiP)M!+c8oKiW>K4fcO++j3f7+xuT+cX{@+|HqSjOtaes+xFy3gUYbL2)glh zc+>bC%!fcC8{p)Sp#3L(N!=)@{b$XzOjE26=5FI))Hsi!S_ApLq!EPVWi*^zH5OB7 zk9^DOTl)Ht6uU9)C(}{9h#Pxnhd6|PE#vtu_#tKWZB`$Qx%Z-|F}|7&=YC^0kHKY$ zba?#k?C`uX7{;S0A-#;jdP}J92>tVZmyotMPLhChMyM#^nS~0j&>^J0okWe}%j2^K z4^GnnL$Agp{?bTB(?w%~#y5?uzNf4I{dwj3ElvIX!@bJ&+uHi4C#xIC>UZ+>&yLra ze^=8#E>S@Pbmh|emV|Ke;sV{HSlY^ zL*vg;zUm77>O`0JA+0f{^W$5O)qJb^-SZA~n8b^&L%pw6Vq;U)%tWtwH%0 zFrCB(N5ibXE7m^-bQNpIp8>raWdD&N;5^8zNPAg*FTde0W}_iky9V?A^ris}(J&Yd ze?@!ItYRx)QJnsSz)Bc4=@tzfv-<6PeZkNi)^8Tf3E2P?7)}_u5hmU#?4SOiHY^l- z_*^^Y7`A`)Vw0uD9c6Xe)GJ=pwf+d4ai_Zb$QoV(7Rnu$?>oWhW@-AfAnYd1(nQS z!O9BF&-_?Z7AVd%S@`~@2@})AA8BT)x%!)at=;mkz$Uq3?p4R^%n$no`Nekc-Q>rx z^A6{&iQdk0uDf%;LuL9A@zFh66La!}M zzPEOk*Wq&qmdz4af0Jh#f2KpSe13s<)_y;~ZL4#%Enh9voUpg~<@A$Bn{-a^D0DEt za{uE6Ro;}Zb4y>nzdU70?`NRXWB&hs$kKQBZ>EU3-t&Vhk^)5qeIYih^)DLmt#`R8 z7+j*{A+S_{b<;21+P{aDToxLfd9~ftWKJcQU%KaFejBbLp^y%V;Fwddii4&V{Qhst zdUwNX!`Sm{W>u7=EeU40mufSw@%SMlS+SQ^Yu|T?@a$Hp2~~P~tL4LiC(CbbUafTJ z6zhJLf0-&*w|`}@pY8wKP~F^OLW%z5#{Nye`u5fJ2XVRmykD17v#hUz_kz0VqBZ+U zGSU`E_cT4(wQ-KCLkoxQ?1^=*?=HByNY^NyIlu(WS-UN4G8TMIWxlI@qG)oimqZW4 zneQhVr>R`pbKSwjj8h^gY=3Nk{anTc(oY3`SUX+X^h>t%sHmT-g?-Cn?bYjTjlFMs zzOGLDcV?YI*BZOyyA7W-u%+e5HB0K>&k2~xc}hCuTywj3Sp4xdU#D|^yDXuj{=&}L zKi121J?GXFAI?3lFyG=Vv*QK-ajO&=@i39=_llqH+ZbmSyy@$vMe~e&-*{!r+oo5r zG0r=9aZT>!U%JaT-InjTAbsVd>g)e;iHozo^H>M&UVi)0<^`{Re*RPW&!&E!{rUON Y&wqYSB=>*h{Qvw)%lL8`fLAU808gxpFaQ7m diff --git a/platform/mellanox/non-upstream-patches/patches/0099-mlxsw-core_hwmon-Fix-variable-names-for-hwmon-attrib.patch b/platform/mellanox/non-upstream-patches/patches/0099-mlxsw-core_hwmon-Fix-variable-names-for-hwmon-attrib.patch new file mode 100644 index 000000000000..c53175073e33 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0099-mlxsw-core_hwmon-Fix-variable-names-for-hwmon-attrib.patch @@ -0,0 +1,255 @@ +From 45dc72bca025600611d6d08e00758618ddb5d7d0 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Fri, 3 Dec 2021 11:48:41 +0200 +Subject: [PATCH] mlxsw: core_hwmon: Fix variable names for hwmon attributes + +Replace all local variables 'mlwsw_hwmon_attr' by 'mlxsw_hwmon_attr'. +All variable prefixes should start with 'mlxsw' according to the naming +convention, so 'mlwsw' is changed to 'mlxsw'. + +Signed-off-by: Vadim Pasternak +Reviewed-by: Jiri Pirko +Signed-off-by: Ido Schimmel +--- + .../net/ethernet/mellanox/mlxsw/core_hwmon.c | 76 +++++++++---------- + 1 file changed, 38 insertions(+), 38 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +index d41afdfbd..3788d02b5 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +@@ -57,14 +57,14 @@ static ssize_t mlxsw_hwmon_temp_show(struct device *dev, + struct device_attribute *attr, + char *buf) + { +- struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = ++ struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; + char mtmp_pl[MLXSW_REG_MTMP_LEN]; + int temp, index; + int err; + +- index = mlxsw_hwmon_get_attr_index(mlwsw_hwmon_attr->type_index, ++ index = mlxsw_hwmon_get_attr_index(mlxsw_hwmon_attr->type_index, + mlxsw_hwmon->module_sensor_max); + mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); +@@ -80,14 +80,14 @@ static ssize_t mlxsw_hwmon_temp_max_show(struct device *dev, + struct device_attribute *attr, + char *buf) + { +- struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = ++ struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; + char mtmp_pl[MLXSW_REG_MTMP_LEN]; + int temp_max, index; + int err; + +- index = mlxsw_hwmon_get_attr_index(mlwsw_hwmon_attr->type_index, ++ index = mlxsw_hwmon_get_attr_index(mlxsw_hwmon_attr->type_index, + mlxsw_hwmon->module_sensor_max); + mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); +@@ -103,9 +103,9 @@ static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) + { +- struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = ++ struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; + char mtmp_pl[MLXSW_REG_MTMP_LEN] = {0}; + unsigned long val; + int index; +@@ -117,7 +117,7 @@ static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev, + if (val != 1) + return -EINVAL; + +- index = mlxsw_hwmon_get_attr_index(mlwsw_hwmon_attr->type_index, ++ index = mlxsw_hwmon_get_attr_index(mlxsw_hwmon_attr->type_index, + mlxsw_hwmon->module_sensor_max); + + mlxsw_reg_mtmp_sensor_index_set(mtmp_pl, index); +@@ -138,13 +138,13 @@ static ssize_t mlxsw_hwmon_fan_rpm_show(struct device *dev, + struct device_attribute *attr, + char *buf) + { +- struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = ++ struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; + char mfsm_pl[MLXSW_REG_MFSM_LEN]; + int err; + +- mlxsw_reg_mfsm_pack(mfsm_pl, mlwsw_hwmon_attr->type_index); ++ mlxsw_reg_mfsm_pack(mfsm_pl, mlxsw_hwmon_attr->type_index); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mfsm), mfsm_pl); + if (err) { + dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query fan\n"); +@@ -157,9 +157,9 @@ static ssize_t mlxsw_hwmon_fan_fault_show(struct device *dev, + struct device_attribute *attr, + char *buf) + { +- struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = ++ struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; + char fore_pl[MLXSW_REG_FORE_LEN]; + bool fault; + int err; +@@ -169,7 +169,7 @@ static ssize_t mlxsw_hwmon_fan_fault_show(struct device *dev, + dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query fan\n"); + return err; + } +- mlxsw_reg_fore_unpack(fore_pl, mlwsw_hwmon_attr->type_index, &fault); ++ mlxsw_reg_fore_unpack(fore_pl, mlxsw_hwmon_attr->type_index, &fault); + + return sprintf(buf, "%u\n", fault); + } +@@ -178,13 +178,13 @@ static ssize_t mlxsw_hwmon_pwm_show(struct device *dev, + struct device_attribute *attr, + char *buf) + { +- struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = ++ struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; + char mfsc_pl[MLXSW_REG_MFSC_LEN]; + int err; + +- mlxsw_reg_mfsc_pack(mfsc_pl, mlwsw_hwmon_attr->type_index, 0); ++ mlxsw_reg_mfsc_pack(mfsc_pl, mlxsw_hwmon_attr->type_index, 0); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mfsc), mfsc_pl); + if (err) { + dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query PWM\n"); +@@ -198,9 +198,9 @@ static ssize_t mlxsw_hwmon_pwm_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) + { +- struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = ++ struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; + char mfsc_pl[MLXSW_REG_MFSC_LEN]; + unsigned long val; + int err; +@@ -211,7 +211,7 @@ static ssize_t mlxsw_hwmon_pwm_store(struct device *dev, + if (val > 255) + return -EINVAL; + +- mlxsw_reg_mfsc_pack(mfsc_pl, mlwsw_hwmon_attr->type_index, val); ++ mlxsw_reg_mfsc_pack(mfsc_pl, mlxsw_hwmon_attr->type_index, val); + err = mlxsw_reg_write(mlxsw_hwmon->core, MLXSW_REG(mfsc), mfsc_pl); + if (err) { + dev_err(mlxsw_hwmon->bus_info->dev, "Failed to write PWM\n"); +@@ -224,14 +224,14 @@ static int mlxsw_hwmon_module_temp_get(struct device *dev, + struct device_attribute *attr, + int *p_temp) + { +- struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = ++ struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; + char mtmp_pl[MLXSW_REG_MTMP_LEN]; + u8 module; + int err; + +- module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; ++ module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; + mlxsw_reg_mtmp_pack(mtmp_pl, MLXSW_REG_MTMP_MODULE_INDEX_MIN + module, + false, false); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); +@@ -261,15 +261,15 @@ static ssize_t mlxsw_hwmon_module_temp_fault_show(struct device *dev, + struct device_attribute *attr, + char *buf) + { +- struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = ++ struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; + char mtbr_pl[MLXSW_REG_MTBR_LEN] = {0}; + u8 module, fault; + u16 temp; + int err; + +- module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; ++ module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; + mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, + 1); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtbr), mtbr_pl); +@@ -303,13 +303,13 @@ static int mlxsw_hwmon_module_temp_critical_get(struct device *dev, + struct device_attribute *attr, + int *p_temp) + { +- struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = ++ struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; + u8 module; + int err; + +- module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; ++ module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; + err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, module, + SFP_TEMP_HIGH_WARN, p_temp); + if (err) { +@@ -337,13 +337,13 @@ static int mlxsw_hwmon_module_temp_emergency_get(struct device *dev, + struct device_attribute *attr, + int *p_temp) + { +- struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = ++ struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; + u8 module; + int err; + +- module = mlwsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; ++ module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; + err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, module, + SFP_TEMP_HIGH_ALARM, p_temp); + if (err) { +@@ -373,11 +373,11 @@ mlxsw_hwmon_module_temp_label_show(struct device *dev, + struct device_attribute *attr, + char *buf) + { +- struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = ++ struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); + + return sprintf(buf, "front panel %03u\n", +- mlwsw_hwmon_attr->type_index); ++ mlxsw_hwmon_attr->type_index); + } + + static ssize_t +@@ -385,10 +385,10 @@ mlxsw_hwmon_gbox_temp_label_show(struct device *dev, + struct device_attribute *attr, + char *buf) + { +- struct mlxsw_hwmon_attr *mlwsw_hwmon_attr = ++ struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlwsw_hwmon_attr->hwmon; +- int index = mlwsw_hwmon_attr->type_index - ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; ++ int index = mlxsw_hwmon_attr->type_index - + mlxsw_hwmon->module_sensor_max + 1; + + return sprintf(buf, "gearbox %03u\n", index); +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0100-mlxsw-core_thermal-Rename-labels-according-to-naming.patch b/platform/mellanox/non-upstream-patches/patches/0100-mlxsw-core_thermal-Rename-labels-according-to-naming.patch new file mode 100644 index 000000000000..cf8c9365af45 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0100-mlxsw-core_thermal-Rename-labels-according-to-naming.patch @@ -0,0 +1,162 @@ +From d2d0080ec104f01fbf0d6b4750f70f1ebe013495 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Fri, 3 Dec 2021 11:48:42 +0200 +Subject: [PATCH] mlxsw: core_thermal: Rename labels according to naming + convention + +Rename labels for error flow handling in order to align with naming +convention used in rest of 'mlxsw' code. + +Signed-off-by: Vadim Pasternak +Reviewed-by: Jiri Pirko +Signed-off-by: Ido Schimmel +--- + .../ethernet/mellanox/mlxsw/core_thermal.c | 43 ++++++++++--------- + 1 file changed, 23 insertions(+), 20 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +index cc4cddbdb..e5997b6a0 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +@@ -401,11 +401,11 @@ static int mlxsw_thermal_module_bind(struct thermal_zone_device *tzdev, + trip->min_state, + THERMAL_WEIGHT_DEFAULT); + if (err < 0) +- goto err_bind_cooling_device; ++ goto err_thermal_zone_bind_cooling_device; + } + return 0; + +-err_bind_cooling_device: ++err_thermal_zone_bind_cooling_device: + for (j = i - 1; j >= 0; j--) + thermal_zone_unbind_cooling_device(tzdev, j, cdev); + return err; +@@ -807,7 +807,7 @@ mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, + for (i = 0; i < thermal->tz_module_num; i++) { + err = mlxsw_thermal_module_init(dev, core, thermal, i); + if (err) +- goto err_unreg_tz_module_arr; ++ goto err_thermal_module_init; + } + + for (i = 0; i < thermal->tz_module_num; i++) { +@@ -816,12 +816,13 @@ mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, + continue; + err = mlxsw_thermal_module_tz_init(module_tz); + if (err) +- goto err_unreg_tz_module_arr; ++ goto err_thermal_module_tz_init; + } + + return 0; + +-err_unreg_tz_module_arr: ++err_thermal_module_tz_init: ++err_thermal_module_init: + for (i = thermal->tz_module_num - 1; i >= 0; i--) + mlxsw_thermal_module_fini(&thermal->tz_module_arr[i]); + kfree(thermal->tz_module_arr); +@@ -912,12 +913,12 @@ mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core, + gearbox_tz->parent = thermal; + err = mlxsw_thermal_gearbox_tz_init(gearbox_tz); + if (err) +- goto err_unreg_tz_gearbox; ++ goto err_thermal_gearbox_tz_init; + } + + return 0; + +-err_unreg_tz_gearbox: ++err_thermal_gearbox_tz_init: + for (i--; i >= 0; i--) + mlxsw_thermal_gearbox_tz_fini(&thermal->tz_gearbox_arr[i]); + kfree(thermal->tz_gearbox_arr); +@@ -961,7 +962,7 @@ int mlxsw_thermal_init(struct mlxsw_core *core, + err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfcr), mfcr_pl); + if (err) { + dev_err(dev, "Failed to probe PWMs\n"); +- goto err_free_thermal; ++ goto err_reg_query; + } + mlxsw_reg_mfcr_unpack(mfcr_pl, &freq, &tacho_active, &pwm_active); + +@@ -975,14 +976,14 @@ int mlxsw_thermal_init(struct mlxsw_core *core, + err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfsl), + mfsl_pl); + if (err) +- goto err_free_thermal; ++ goto err_reg_query; + + /* set the minimal RPMs to 0 */ + mlxsw_reg_mfsl_tach_min_set(mfsl_pl, 0); + err = mlxsw_reg_write(thermal->core, MLXSW_REG(mfsl), + mfsl_pl); + if (err) +- goto err_free_thermal; ++ goto err_reg_write; + } + } + for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++) { +@@ -995,7 +996,7 @@ int mlxsw_thermal_init(struct mlxsw_core *core, + if (IS_ERR(cdev)) { + err = PTR_ERR(cdev); + dev_err(dev, "Failed to register cooling device\n"); +- goto err_unreg_cdevs; ++ goto err_thermal_cooling_device_register; + } + thermal->cdevs[i] = cdev; + } +@@ -1020,38 +1021,40 @@ int mlxsw_thermal_init(struct mlxsw_core *core, + if (IS_ERR(thermal->tzdev)) { + err = PTR_ERR(thermal->tzdev); + dev_err(dev, "Failed to register thermal zone\n"); +- goto err_unreg_cdevs; ++ goto err_thermal_zone_device_register; + } + + err = mlxsw_thermal_modules_init(dev, core, thermal); + if (err) +- goto err_unreg_tzdev; ++ goto err_thermal_modules_init; + + err = mlxsw_thermal_gearboxes_init(dev, core, thermal); + if (err) +- goto err_unreg_modules_tzdev; ++ goto err_thermal_gearboxes_init; + + err = thermal_zone_device_enable(thermal->tzdev); + if (err) +- goto err_unreg_gearboxes; ++ goto err_thermal_zone_device_enable; + + *p_thermal = thermal; + return 0; + +-err_unreg_gearboxes: ++err_thermal_zone_device_enable: + mlxsw_thermal_gearboxes_fini(thermal); +-err_unreg_modules_tzdev: ++err_thermal_gearboxes_init: + mlxsw_thermal_modules_fini(thermal); +-err_unreg_tzdev: ++err_thermal_modules_init: + if (thermal->tzdev) { + thermal_zone_device_unregister(thermal->tzdev); + thermal->tzdev = NULL; + } +-err_unreg_cdevs: ++err_thermal_zone_device_register: ++err_thermal_cooling_device_register: + for (i = 0; i < MLXSW_MFCR_PWMS_MAX; i++) + if (thermal->cdevs[i]) + thermal_cooling_device_unregister(thermal->cdevs[i]); +-err_free_thermal: ++err_reg_write: ++err_reg_query: + devm_kfree(dev, thermal); + return err; + } +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0101-mlxsw-core_thermal-Remove-obsolete-API-for-query-res.patch b/platform/mellanox/non-upstream-patches/patches/0101-mlxsw-core_thermal-Remove-obsolete-API-for-query-res.patch new file mode 100644 index 000000000000..fd76e960d472 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0101-mlxsw-core_thermal-Remove-obsolete-API-for-query-res.patch @@ -0,0 +1,110 @@ +From 1186332d9cbf3f7cbd2ed52dfcb594ce4e2d2df8 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Fri, 3 Dec 2021 11:48:43 +0200 +Subject: [PATCH] mlxsw: core_thermal: Remove obsolete API for query resource + +Remove obsolete API mlxsw_core_res_query_enabled(), which is only +relevant for end-of-life SwitchX-2 ASICs. Support for these ASICs was +removed in commit b0d80c013b04 ("mlxsw: Remove Mellanox SwitchX-2 ASIC +support"). + +Signed-off-by: Vadim Pasternak +Signed-off-by: Ido Schimmel +--- + drivers/net/ethernet/mellanox/mlxsw/core.c | 6 ------ + drivers/net/ethernet/mellanox/mlxsw/core.h | 2 -- + drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c | 3 --- + drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 12 ------------ + 4 files changed, 23 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c +index 7938bad70..0b1888318 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.c +@@ -129,12 +129,6 @@ void *mlxsw_core_driver_priv(struct mlxsw_core *mlxsw_core) + } + EXPORT_SYMBOL(mlxsw_core_driver_priv); + +-bool mlxsw_core_res_query_enabled(const struct mlxsw_core *mlxsw_core) +-{ +- return mlxsw_core->driver->res_query_enabled; +-} +-EXPORT_SYMBOL(mlxsw_core_res_query_enabled); +- + bool mlxsw_core_temp_warn_enabled(const struct mlxsw_core *mlxsw_core) + { + return mlxsw_core->driver->temp_warn_enabled; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h +index 56efb8e48..0ceb7dae9 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.h +@@ -30,8 +30,6 @@ unsigned int mlxsw_core_max_ports(const struct mlxsw_core *mlxsw_core); + + void *mlxsw_core_driver_priv(struct mlxsw_core *mlxsw_core); + +-bool mlxsw_core_res_query_enabled(const struct mlxsw_core *mlxsw_core); +- + bool mlxsw_core_temp_warn_enabled(const struct mlxsw_core *mlxsw_core); + + bool +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +index 3788d02b5..8b170ad92 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +@@ -655,9 +655,6 @@ static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon) + u8 module_sensor_max; + int i, err; + +- if (!mlxsw_core_res_query_enabled(mlxsw_hwmon->core)) +- return 0; +- + mlxsw_reg_mgpir_pack(mgpir_pl); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mgpir), mgpir_pl); + if (err) +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +index e5997b6a0..9b0cd6f79 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +@@ -787,9 +787,6 @@ mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, + char mgpir_pl[MLXSW_REG_MGPIR_LEN]; + int i, err; + +- if (!mlxsw_core_res_query_enabled(core)) +- return 0; +- + mlxsw_reg_mgpir_pack(mgpir_pl); + err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl); + if (err) +@@ -834,9 +831,6 @@ mlxsw_thermal_modules_fini(struct mlxsw_thermal *thermal) + { + int i; + +- if (!mlxsw_core_res_query_enabled(thermal->core)) +- return; +- + for (i = thermal->tz_module_num - 1; i >= 0; i--) + mlxsw_thermal_module_fini(&thermal->tz_module_arr[i]); + kfree(thermal->tz_module_arr); +@@ -884,9 +878,6 @@ mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core, + int i; + int err; + +- if (!mlxsw_core_res_query_enabled(core)) +- return 0; +- + mlxsw_reg_mgpir_pack(mgpir_pl); + err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl); + if (err) +@@ -930,9 +921,6 @@ mlxsw_thermal_gearboxes_fini(struct mlxsw_thermal *thermal) + { + int i; + +- if (!mlxsw_core_res_query_enabled(thermal->core)) +- return; +- + for (i = thermal->tz_gearbox_num - 1; i >= 0; i--) + mlxsw_thermal_gearbox_tz_fini(&thermal->tz_gearbox_arr[i]); + kfree(thermal->tz_gearbox_arr); +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0102-mlxsw-reg-Add-mgpir_-prefix-to-MGPIR-fields-comments.patch b/platform/mellanox/non-upstream-patches/patches/0102-mlxsw-reg-Add-mgpir_-prefix-to-MGPIR-fields-comments.patch new file mode 100644 index 000000000000..8dfb08c2129e --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0102-mlxsw-reg-Add-mgpir_-prefix-to-MGPIR-fields-comments.patch @@ -0,0 +1,51 @@ +From ad972c6b6591023ddc7547bbcbc5c5e1941b29c5 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Fri, 3 Dec 2021 11:48:44 +0200 +Subject: [PATCH] mlxsw: reg: Add "mgpir_" prefix to MGPIR fields comments + +Do the same as for other registers and have "mgpir_" prefix for the +MGPIR fields. + +Signed-off-by: Jiri Pirko +Signed-off-by: Vadim Pasternak +Signed-off-by: Ido Schimmel +--- + drivers/net/ethernet/mellanox/mlxsw/reg.h | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h +index a9119451d..7f7cdb3fc 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h +@@ -10131,24 +10131,24 @@ enum mlxsw_reg_mgpir_device_type { + MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE, + }; + +-/* device_type ++/* mgpir_device_type + * Access: RO + */ + MLXSW_ITEM32(reg, mgpir, device_type, 0x00, 24, 4); + +-/* devices_per_flash ++/* mgpir_devices_per_flash + * Number of devices of device_type per flash (can be shared by few devices). + * Access: RO + */ + MLXSW_ITEM32(reg, mgpir, devices_per_flash, 0x00, 16, 8); + +-/* num_of_devices ++/* mgpir_num_of_devices + * Number of devices of device_type. + * Access: RO + */ + MLXSW_ITEM32(reg, mgpir, num_of_devices, 0x00, 0, 8); + +-/* num_of_modules ++/* mgpir_num_of_modules + * Number of modules. + * Access: RO + */ +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0103-mlxsw-core-Remove-unnecessary-asserts.patch b/platform/mellanox/non-upstream-patches/patches/0103-mlxsw-core-Remove-unnecessary-asserts.patch new file mode 100644 index 000000000000..2c6249423bbe --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0103-mlxsw-core-Remove-unnecessary-asserts.patch @@ -0,0 +1,102 @@ +From 4392d92a40328fe18d1152fae6fada74f46fa1a3 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Tue, 7 Dec 2021 16:07:31 +0200 +Subject: [PATCH] mlxsw: core: Remove unnecessary asserts + +Remove unnecessary asserts for module index validation. Leave only one +that is actually necessary in mlxsw_env_pmpe_listener_func() where the +module index is directly read from the firmware event. + +Signed-off-by: Vadim Pasternak +Signed-off-by: Ido Schimmel +--- + .../net/ethernet/mellanox/mlxsw/core_env.c | 24 ------------------- + 1 file changed, 24 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +index 61f7a40c0..4cbed2e3b 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +@@ -416,9 +416,6 @@ int mlxsw_env_reset_module(struct net_device *netdev, + !(req & (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT))) + return 0; + +- if (WARN_ON_ONCE(module >= mlxsw_env->module_count)) +- return -EINVAL; +- + mutex_lock(&mlxsw_env->module_info_lock); + + if (mlxsw_env->module_info[module].num_ports_up) { +@@ -458,9 +455,6 @@ mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 module, + u32 status_bits; + int err; + +- if (WARN_ON_ONCE(module >= mlxsw_env->module_count)) +- return -EINVAL; +- + mutex_lock(&mlxsw_env->module_info_lock); + + params->policy = mlxsw_env->module_info[module].power_mode_policy; +@@ -562,9 +556,6 @@ mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 module, + bool low_power; + int err = 0; + +- if (WARN_ON_ONCE(module >= mlxsw_env->module_count)) +- return -EINVAL; +- + if (policy != ETHTOOL_MODULE_POWER_MODE_POLICY_HIGH && + policy != ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO) { + NL_SET_ERR_MSG_MOD(extack, "Unsupported power mode policy"); +@@ -903,9 +894,6 @@ mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 module, + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); + +- if (WARN_ON_ONCE(module >= mlxsw_env->module_count)) +- return -EINVAL; +- + mutex_lock(&mlxsw_env->module_info_lock); + *p_counter = mlxsw_env->module_info[module].module_overheat_counter; + mutex_unlock(&mlxsw_env->module_info_lock); +@@ -918,9 +906,6 @@ void mlxsw_env_module_port_map(struct mlxsw_core *mlxsw_core, u8 module) + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); + +- if (WARN_ON_ONCE(module >= mlxsw_env->module_count)) +- return; +- + mutex_lock(&mlxsw_env->module_info_lock); + mlxsw_env->module_info[module].num_ports_mapped++; + mutex_unlock(&mlxsw_env->module_info_lock); +@@ -931,9 +916,6 @@ void mlxsw_env_module_port_unmap(struct mlxsw_core *mlxsw_core, u8 module) + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); + +- if (WARN_ON_ONCE(module >= mlxsw_env->module_count)) +- return; +- + mutex_lock(&mlxsw_env->module_info_lock); + mlxsw_env->module_info[module].num_ports_mapped--; + mutex_unlock(&mlxsw_env->module_info_lock); +@@ -945,9 +927,6 @@ int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 module) + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); + int err = 0; + +- if (WARN_ON_ONCE(module >= mlxsw_env->module_count)) +- return -EINVAL; +- + mutex_lock(&mlxsw_env->module_info_lock); + + if (mlxsw_env->module_info[module].power_mode_policy != +@@ -977,9 +956,6 @@ void mlxsw_env_module_port_down(struct mlxsw_core *mlxsw_core, u8 module) + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); + +- if (WARN_ON_ONCE(module >= mlxsw_env->module_count)) +- return; +- + mutex_lock(&mlxsw_env->module_info_lock); + + mlxsw_env->module_info[module].num_ports_up--; +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0104-mlxsw-reg-Extend-MTMP-register-with-new-slot-number-.patch b/platform/mellanox/non-upstream-patches/patches/0104-mlxsw-reg-Extend-MTMP-register-with-new-slot-number-.patch new file mode 100644 index 000000000000..db900ff41bd1 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0104-mlxsw-reg-Extend-MTMP-register-with-new-slot-number-.patch @@ -0,0 +1,146 @@ +From 5c2fb60aa437b4858f15bb8bfb02d9df43b4dd95 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Fri, 3 Dec 2021 11:48:45 +0200 +Subject: [PATCH] mlxsw: reg: Extend MTMP register with new slot number field + +Extend MTMP (Management Temperature Register) with new field specifying +the slot index. The purpose of this field is to support access to MTMP +register for reading temperature sensors on modular systems. +For non-modular systems the 'sensor_index' uniquely identifies the cage +sensors, while 'slot_index' is always 0. For modular systems the +sensors are identified by: +- 'slot_index', specifying the slot index, where line card is located; +- 'sensor_index', specifying cage sensor within the line card. + +Signed-off-by: Vadim Pasternak +Reviewed-by: Jiri Pirko +Signed-off-by: Ido Schimmel +--- + drivers/net/ethernet/mellanox/mlxsw/core_env.c | 2 +- + drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c | 11 ++++++----- + drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 6 +++--- + drivers/net/ethernet/mellanox/mlxsw/reg.h | 11 +++++++++-- + 4 files changed, 19 insertions(+), 11 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +index 4cbed2e3b..0b43029b2 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +@@ -143,7 +143,7 @@ int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, int module, + int page; + int err; + +- mlxsw_reg_mtmp_pack(mtmp_pl, MLXSW_REG_MTMP_MODULE_INDEX_MIN + module, ++ mlxsw_reg_mtmp_pack(mtmp_pl, 0, MLXSW_REG_MTMP_MODULE_INDEX_MIN + module, + false, false); + err = mlxsw_reg_query(core, MLXSW_REG(mtmp), mtmp_pl); + if (err) +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +index 8b170ad92..71ca3b561 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +@@ -66,7 +66,7 @@ static ssize_t mlxsw_hwmon_temp_show(struct device *dev, + + index = mlxsw_hwmon_get_attr_index(mlxsw_hwmon_attr->type_index, + mlxsw_hwmon->module_sensor_max); +- mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false); ++ mlxsw_reg_mtmp_pack(mtmp_pl, 0, index, false, false); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); + if (err) { + dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query temp sensor\n"); +@@ -89,7 +89,7 @@ static ssize_t mlxsw_hwmon_temp_max_show(struct device *dev, + + index = mlxsw_hwmon_get_attr_index(mlxsw_hwmon_attr->type_index, + mlxsw_hwmon->module_sensor_max); +- mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false); ++ mlxsw_reg_mtmp_pack(mtmp_pl, 0, index, false, false); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); + if (err) { + dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query temp sensor\n"); +@@ -232,8 +232,9 @@ static int mlxsw_hwmon_module_temp_get(struct device *dev, + int err; + + module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; +- mlxsw_reg_mtmp_pack(mtmp_pl, MLXSW_REG_MTMP_MODULE_INDEX_MIN + module, +- false, false); ++ mlxsw_reg_mtmp_pack(mtmp_pl, 0, ++ MLXSW_REG_MTMP_MODULE_INDEX_MIN + module, false, ++ false); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); + if (err) { + dev_err(dev, "Failed to query module temperature\n"); +@@ -721,7 +722,7 @@ static int mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon) + while (index < max_index) { + sensor_index = index % mlxsw_hwmon->module_sensor_max + + MLXSW_REG_MTMP_GBOX_INDEX_MIN; +- mlxsw_reg_mtmp_pack(mtmp_pl, sensor_index, true, true); ++ mlxsw_reg_mtmp_pack(mtmp_pl, 0, sensor_index, true, true); + err = mlxsw_reg_write(mlxsw_hwmon->core, + MLXSW_REG(mtmp), mtmp_pl); + if (err) { +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +index 9b0cd6f79..8d88633c9 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +@@ -280,7 +280,7 @@ static int mlxsw_thermal_get_temp(struct thermal_zone_device *tzdev, + int temp; + int err; + +- mlxsw_reg_mtmp_pack(mtmp_pl, 0, false, false); ++ mlxsw_reg_mtmp_pack(mtmp_pl, 0, 0, false, false); + + err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl); + if (err) { +@@ -440,7 +440,7 @@ mlxsw_thermal_module_temp_and_thresholds_get(struct mlxsw_core *core, + int err; + + /* Read module temperature and thresholds. */ +- mlxsw_reg_mtmp_pack(mtmp_pl, sensor_index, false, false); ++ mlxsw_reg_mtmp_pack(mtmp_pl, 0, sensor_index, false, false); + err = mlxsw_reg_query(core, MLXSW_REG(mtmp), mtmp_pl); + if (err) { + /* Set temperature and thresholds to zero to avoid passing +@@ -585,7 +585,7 @@ static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev, + int err; + + index = MLXSW_REG_MTMP_GBOX_INDEX_MIN + tz->module; +- mlxsw_reg_mtmp_pack(mtmp_pl, index, false, false); ++ mlxsw_reg_mtmp_pack(mtmp_pl, 0, index, false, false); + + err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl); + if (err) +diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h +index 7f7cdb3fc..52cb58c6d 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h +@@ -8541,6 +8541,12 @@ MLXSW_ITEM32(reg, mtcap, sensor_count, 0x00, 0, 7); + + MLXSW_REG_DEFINE(mtmp, MLXSW_REG_MTMP_ID, MLXSW_REG_MTMP_LEN); + ++/* reg_mtmp_slot_index ++ * Slot index (0: Main board). ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, mtmp, slot_index, 0x00, 16, 4); ++ + #define MLXSW_REG_MTMP_MODULE_INDEX_MIN 64 + #define MLXSW_REG_MTMP_GBOX_INDEX_MIN 256 + /* reg_mtmp_sensor_index +@@ -8630,11 +8636,12 @@ MLXSW_ITEM32(reg, mtmp, temperature_threshold_lo, 0x10, 0, 16); + */ + MLXSW_ITEM_BUF(reg, mtmp, sensor_name, 0x18, MLXSW_REG_MTMP_SENSOR_NAME_SIZE); + +-static inline void mlxsw_reg_mtmp_pack(char *payload, u16 sensor_index, +- bool max_temp_enable, ++static inline void mlxsw_reg_mtmp_pack(char *payload, u8 slot_index, ++ u16 sensor_index, bool max_temp_enable, + bool max_temp_reset) + { + MLXSW_REG_ZERO(mtmp, payload); ++ mlxsw_reg_mtmp_slot_index_set(payload, slot_index); + mlxsw_reg_mtmp_sensor_index_set(payload, sensor_index); + mlxsw_reg_mtmp_mte_set(payload, max_temp_enable); + mlxsw_reg_mtmp_mtr_set(payload, max_temp_reset); +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0105-mlxsw-reg-Extend-MTBR-register-with-new-slot-number-.patch b/platform/mellanox/non-upstream-patches/patches/0105-mlxsw-reg-Extend-MTBR-register-with-new-slot-number-.patch new file mode 100644 index 000000000000..3c8cfdd7be40 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0105-mlxsw-reg-Extend-MTBR-register-with-new-slot-number-.patch @@ -0,0 +1,87 @@ +From c9c0ae28ab85836ee15920ddafaa3ba45e0dcaeb Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Fri, 3 Dec 2021 11:48:46 +0200 +Subject: [PATCH] mlxsw: reg: Extend MTBR register with new slot number field + +Extend MTBR (Management Temperature Bulk Register) with new field +specifying the slot number. The purpose of this field is to support +access to MTBR register for reading temperature sensors on modular +system. For non-modular systems the 'sensor_index' uniquely identifies +the cage sensors. For modular systems the sensors are identified by two +indexes: +- 'slot_index', specifying the slot number, where line card is located; +- 'sensor_index', specifying cage sensor within the line card. + +Signed-off-by: Vadim Pasternak +Reviewed-by: Jiri Pirko +Signed-off-by: Ido Schimmel +--- + drivers/net/ethernet/mellanox/mlxsw/core_env.c | 4 ++-- + drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c | 4 ++-- + drivers/net/ethernet/mellanox/mlxsw/reg.h | 11 +++++++++-- + 3 files changed, 13 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +index 0b43029b2..7feefb38b 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +@@ -593,8 +593,8 @@ static int mlxsw_env_module_has_temp_sensor(struct mlxsw_core *mlxsw_core, + u16 temp; + int err; + +- mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, +- 1); ++ mlxsw_reg_mtbr_pack(mtbr_pl, 0, ++ MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, 1); + err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mtbr), mtbr_pl); + if (err) + return err; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +index 71ca3b561..f4bc711a1 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +@@ -271,8 +271,8 @@ static ssize_t mlxsw_hwmon_module_temp_fault_show(struct device *dev, + int err; + + module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; +- mlxsw_reg_mtbr_pack(mtbr_pl, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, +- 1); ++ mlxsw_reg_mtbr_pack(mtbr_pl, 0, ++ MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, 1); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtbr), mtbr_pl); + if (err) { + dev_err(dev, "Failed to query module temperature sensor\n"); +diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h +index 52cb58c6d..56927c772 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h +@@ -8707,6 +8707,12 @@ MLXSW_ITEM_BIT_ARRAY(reg, mtwe, sensor_warning, 0x0, 0x10, 1); + + MLXSW_REG_DEFINE(mtbr, MLXSW_REG_MTBR_ID, MLXSW_REG_MTBR_LEN); + ++/* reg_mtbr_slot_index ++ * Slot index (0: Main board). ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, mtbr, slot_index, 0x00, 16, 4); ++ + /* reg_mtbr_base_sensor_index + * Base sensors index to access (0 - ASIC sensor, 1-63 - ambient sensors, + * 64-127 are mapped to the SFP+/QSFP modules sequentially). +@@ -8739,10 +8745,11 @@ MLXSW_ITEM32_INDEXED(reg, mtbr, rec_max_temp, MLXSW_REG_MTBR_BASE_LEN, 16, + MLXSW_ITEM32_INDEXED(reg, mtbr, rec_temp, MLXSW_REG_MTBR_BASE_LEN, 0, 16, + MLXSW_REG_MTBR_REC_LEN, 0x00, false); + +-static inline void mlxsw_reg_mtbr_pack(char *payload, u16 base_sensor_index, +- u8 num_rec) ++static inline void mlxsw_reg_mtbr_pack(char *payload, u8 slot_index, ++ u16 base_sensor_index, u8 num_rec) + { + MLXSW_REG_ZERO(mtbr, payload); ++ mlxsw_reg_mtbr_slot_index_set(payload, slot_index); + mlxsw_reg_mtbr_base_sensor_index_set(payload, base_sensor_index); + mlxsw_reg_mtbr_num_rec_set(payload, num_rec); + } +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0106-mlxsw-reg-Extend-MCIA-register-with-new-slot-number-.patch b/platform/mellanox/non-upstream-patches/patches/0106-mlxsw-reg-Extend-MCIA-register-with-new-slot-number-.patch new file mode 100644 index 000000000000..bf6f065a9c33 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0106-mlxsw-reg-Extend-MCIA-register-with-new-slot-number-.patch @@ -0,0 +1,108 @@ +From d494bb0c59dd1f6150f189e2878babf53b67e111 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Fri, 3 Dec 2021 11:48:47 +0200 +Subject: [PATCH] mlxsw: reg: Extend MCIA register with new slot number field + +Extend MCIA (Management Cable Info Access Register) with new field +specifying the slot number. The purpose of this field is to support +access to MCIA register for reading cage cable information on modular +system. For non-modular systems the 'module' number uniquely identifies +the transceiver location. For modular systems the transceivers are +identified by two indexes: +- 'slot_index', specifying the slot number, where line card is located; +- 'module', specifying cage transceiver within the line card. + +Signed-off-by: Vadim Pasternak +Reviewed-by: Jiri Pirko +Signed-off-by: Ido Schimmel +--- + drivers/net/ethernet/mellanox/mlxsw/core_env.c | 13 +++++++------ + drivers/net/ethernet/mellanox/mlxsw/reg.h | 14 +++++++++++--- + 2 files changed, 18 insertions(+), 9 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +index 7feefb38b..21eacbe0a 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +@@ -35,8 +35,8 @@ static int mlxsw_env_validate_cable_ident(struct mlxsw_core *core, int id, + u8 ident; + int err; + +- mlxsw_reg_mcia_pack(mcia_pl, id, 0, MLXSW_REG_MCIA_PAGE0_LO_OFF, 0, 1, +- MLXSW_REG_MCIA_I2C_ADDR_LOW); ++ mlxsw_reg_mcia_pack(mcia_pl, 0, id, 0, MLXSW_REG_MCIA_PAGE0_LO_OFF, 0, ++ 1, MLXSW_REG_MCIA_I2C_ADDR_LOW); + err = mlxsw_reg_query(core, MLXSW_REG(mcia), mcia_pl); + if (err) + return err; +@@ -111,7 +111,8 @@ mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, int module, + } + } + +- mlxsw_reg_mcia_pack(mcia_pl, module, 0, page, offset, size, i2c_addr); ++ mlxsw_reg_mcia_pack(mcia_pl, 0, module, 0, page, offset, size, ++ i2c_addr); + + err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcia), mcia_pl); + if (err) +@@ -185,12 +186,12 @@ int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, int module, + page = MLXSW_REG_MCIA_TH_PAGE_CMIS_NUM; + else + page = MLXSW_REG_MCIA_TH_PAGE_NUM; +- mlxsw_reg_mcia_pack(mcia_pl, module, 0, page, ++ mlxsw_reg_mcia_pack(mcia_pl, 0, module, 0, page, + MLXSW_REG_MCIA_TH_PAGE_OFF + off, + MLXSW_REG_MCIA_TH_ITEM_SIZE, + MLXSW_REG_MCIA_I2C_ADDR_LOW); + } else { +- mlxsw_reg_mcia_pack(mcia_pl, module, 0, ++ mlxsw_reg_mcia_pack(mcia_pl, 0, module, 0, + MLXSW_REG_MCIA_PAGE0_LO, + off, MLXSW_REG_MCIA_TH_ITEM_SIZE, + MLXSW_REG_MCIA_I2C_ADDR_HIGH); +@@ -371,7 +372,7 @@ mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, u8 module, + size = min_t(u8, page->length - bytes_read, + MLXSW_REG_MCIA_EEPROM_SIZE); + +- mlxsw_reg_mcia_pack(mcia_pl, module, 0, page->page, ++ mlxsw_reg_mcia_pack(mcia_pl, 0, module, 0, page->page, + device_addr + bytes_read, size, + page->i2c_address); + mlxsw_reg_mcia_bank_number_set(mcia_pl, page->bank); +diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h +index 56927c772..2714e316c 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h +@@ -8798,6 +8798,12 @@ MLXSW_ITEM32(reg, mcia, l, 0x00, 31, 1); + */ + MLXSW_ITEM32(reg, mcia, module, 0x00, 16, 8); + ++/* reg_mcia_slot_index ++ * Slot index (0: Main board) ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, mcia, slot, 0x00, 12, 4); ++ + enum { + MLXSW_REG_MCIA_STATUS_GOOD = 0, + /* No response from module's EEPROM. */ +@@ -8897,11 +8903,13 @@ MLXSW_ITEM_BUF(reg, mcia, eeprom, 0x10, MLXSW_REG_MCIA_EEPROM_SIZE); + MLXSW_REG_MCIA_EEPROM_PAGE_LENGTH) / \ + MLXSW_REG_MCIA_EEPROM_UP_PAGE_LENGTH + 1) + +-static inline void mlxsw_reg_mcia_pack(char *payload, u8 module, u8 lock, +- u8 page_number, u16 device_addr, +- u8 size, u8 i2c_device_addr) ++static inline void mlxsw_reg_mcia_pack(char *payload, u8 slot_index, u8 module, ++ u8 lock, u8 page_number, ++ u16 device_addr, u8 size, ++ u8 i2c_device_addr) + { + MLXSW_REG_ZERO(mcia, payload); ++ mlxsw_reg_mcia_slot_set(payload, slot_index); + mlxsw_reg_mcia_module_set(payload, module); + mlxsw_reg_mcia_l_set(payload, lock); + mlxsw_reg_mcia_page_number_set(payload, page_number); +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0107-mlxsw-reg-Extend-MCION-register-with-new-slot-number.patch b/platform/mellanox/non-upstream-patches/patches/0107-mlxsw-reg-Extend-MCION-register-with-new-slot-number.patch new file mode 100644 index 000000000000..46f34b6a2fa4 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0107-mlxsw-reg-Extend-MCION-register-with-new-slot-number.patch @@ -0,0 +1,68 @@ +From 9c4ce1a56515e927399a87b63deeacd77ada6b3b Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Fri, 3 Dec 2021 11:48:50 +0200 +Subject: [PATCH] mlxsw: reg: Extend MCION register with new slot number field + +Extend MCION (Management Cable IO and Notifications Register) with new +field specifying the slot number. The purpose of this field is to +support access to MCION register for query cage transceiver on modular +system. + +For non-modular systems the 'module' number uniquely identifies the +transceiver location. For modular systems the transceivers are +identified by two indexes: +- 'slot_index', specifying the slot number, where line card is located; +- 'module', specifying cage transceiver within the line card. + +Signed-off-by: Vadim Pasternak +Signed-off-by: Ido Schimmel +--- + drivers/net/ethernet/mellanox/mlxsw/core_env.c | 2 +- + drivers/net/ethernet/mellanox/mlxsw/reg.h | 9 ++++++++- + 2 files changed, 9 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +index 21eacbe0a..d88033ec6 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +@@ -460,7 +460,7 @@ mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 module, + + params->policy = mlxsw_env->module_info[module].power_mode_policy; + +- mlxsw_reg_mcion_pack(mcion_pl, module); ++ mlxsw_reg_mcion_pack(mcion_pl, 0, module); + err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcion), mcion_pl); + if (err) { + NL_SET_ERR_MSG_MOD(extack, "Failed to retrieve module's power mode"); +diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h +index 2714e316c..243d91f1d 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h +@@ -9328,6 +9328,12 @@ MLXSW_REG_DEFINE(mcion, MLXSW_REG_MCION_ID, MLXSW_REG_MCION_LEN); + */ + MLXSW_ITEM32(reg, mcion, module, 0x00, 16, 8); + ++/* reg_mcion_slot_index ++ * Slot index. ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, mcion, slot_index, 0x00, 12, 4); ++ + enum { + MLXSW_REG_MCION_MODULE_STATUS_BITS_PRESENT_MASK = BIT(0), + MLXSW_REG_MCION_MODULE_STATUS_BITS_LOW_POWER_MASK = BIT(8), +@@ -9339,9 +9345,10 @@ enum { + */ + MLXSW_ITEM32(reg, mcion, module_status_bits, 0x04, 0, 16); + +-static inline void mlxsw_reg_mcion_pack(char *payload, u8 module) ++static inline void mlxsw_reg_mcion_pack(char *payload, u8 slot_index, u8 module) + { + MLXSW_REG_ZERO(mcion, payload); ++ mlxsw_reg_mcion_slot_index_set(payload, slot_index); + mlxsw_reg_mcion_module_set(payload, module); + } + +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0108-mlxsw-reg-Extend-PMMP-register-with-new-slot-number-.patch b/platform/mellanox/non-upstream-patches/patches/0108-mlxsw-reg-Extend-PMMP-register-with-new-slot-number-.patch new file mode 100644 index 000000000000..8eff1b9973ad --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0108-mlxsw-reg-Extend-PMMP-register-with-new-slot-number-.patch @@ -0,0 +1,67 @@ +From d707ce17ce596c2deb97b481dffb24b8c4537fa2 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Fri, 3 Dec 2021 11:48:51 +0200 +Subject: [PATCH] mlxsw: reg: Extend PMMP register with new slot number field + +Extend PMMP (Port Module Memory Map Properties Register) with new +field specifying the slot number. The purpose of this field is to +enable overriding the cable/module memory map advertisement. + +For non-modular systems the 'module' number uniquely identifies the +transceiver location. For modular systems the transceivers are +identified by two indexes: +- 'slot_index', specifying the slot number, where line card is located; +- 'module', specifying cage transceiver within the line card. + +Signed-off-by: Vadim Pasternak +Signed-off-by: Ido Schimmel +--- + drivers/net/ethernet/mellanox/mlxsw/core_env.c | 2 +- + drivers/net/ethernet/mellanox/mlxsw/reg.h | 9 ++++++++- + 2 files changed, 9 insertions(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +index d88033ec6..49c58197b 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +@@ -503,7 +503,7 @@ static int mlxsw_env_module_low_power_set(struct mlxsw_core *mlxsw_core, + u16 eeprom_override_mask, eeprom_override; + char pmmp_pl[MLXSW_REG_PMMP_LEN]; + +- mlxsw_reg_pmmp_pack(pmmp_pl, module); ++ mlxsw_reg_pmmp_pack(pmmp_pl, 0, module); + mlxsw_reg_pmmp_sticky_set(pmmp_pl, true); + /* Mask all the bits except low power mode. */ + eeprom_override_mask = ~MLXSW_REG_PMMP_EEPROM_OVERRIDE_LOW_POWER_MASK; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h +index 243d91f1d..c19db16bf 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h +@@ -5633,6 +5633,12 @@ MLXSW_REG_DEFINE(pmmp, MLXSW_REG_PMMP_ID, MLXSW_REG_PMMP_LEN); + */ + MLXSW_ITEM32(reg, pmmp, module, 0x00, 16, 8); + ++/* reg_pmmp_slot_index ++ * Slot index. ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, pmmp, slot_index, 0x00, 24, 4); ++ + /* reg_pmmp_sticky + * When set, will keep eeprom_override values after plug-out event. + * Access: OP +@@ -5660,9 +5666,10 @@ enum { + */ + MLXSW_ITEM32(reg, pmmp, eeprom_override, 0x04, 0, 16); + +-static inline void mlxsw_reg_pmmp_pack(char *payload, u8 module) ++static inline void mlxsw_reg_pmmp_pack(char *payload, u8 slot_index, u8 module) + { + MLXSW_REG_ZERO(pmmp, payload); ++ mlxsw_reg_pmmp_slot_index_set(payload, slot_index); + mlxsw_reg_pmmp_module_set(payload, module); + } + +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0109-mlxsw-reg-Extend-MGPIR-register-with-new-slot-fields.patch b/platform/mellanox/non-upstream-patches/patches/0109-mlxsw-reg-Extend-MGPIR-register-with-new-slot-fields.patch new file mode 100644 index 000000000000..95a723bd2649 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0109-mlxsw-reg-Extend-MGPIR-register-with-new-slot-fields.patch @@ -0,0 +1,198 @@ +From 1373ed22ae41e92c081bb80df4b3c4c0630edbb9 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 22 Dec 2021 06:11:50 +0000 +Subject: [PATCH] mlxsw: reg: Extend MGPIR register with new slot fields + +Extend MGPIR (Management General Peripheral Information Register) with +new fields specifying the slot number and number of the slots available +on system. The purpose of these fields is: +- to support access to MPGIR register on modular system for getting the + number of cages, equipped on the line card, inserted at specified + slot. In case slot number is set zero, MGPIR will provide the + information for the main board. For Top of the Rack (non-modular) + system it will provide the same as before. +- to provide the number of slots supported by system. This data is + relevant only in case slot number is set zero. + +Signed-off-by: Vadim Pasternak +Signed-off-by: Ido Schimmel +--- + .../net/ethernet/mellanox/mlxsw/core_env.c | 4 ++-- + .../net/ethernet/mellanox/mlxsw/core_hwmon.c | 9 +++++---- + .../ethernet/mellanox/mlxsw/core_thermal.c | 8 ++++---- + drivers/net/ethernet/mellanox/mlxsw/minimal.c | 4 ++-- + drivers/net/ethernet/mellanox/mlxsw/reg.h | 20 +++++++++++++++++-- + 5 files changed, 31 insertions(+), 14 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +index 49c58197b..b1a1204e7 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +@@ -985,12 +985,12 @@ int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env) + u8 module_count; + int i, err; + +- mlxsw_reg_mgpir_pack(mgpir_pl); ++ mlxsw_reg_mgpir_pack(mgpir_pl, 0); + err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mgpir), mgpir_pl); + if (err) + return err; + +- mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, &module_count); ++ mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, &module_count, NULL); + + env = kzalloc(struct_size(env, module_info, module_count), GFP_KERNEL); + if (!env) +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +index f4bc711a1..2bc4c4556 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +@@ -656,13 +656,13 @@ static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon) + u8 module_sensor_max; + int i, err; + +- mlxsw_reg_mgpir_pack(mgpir_pl); ++ mlxsw_reg_mgpir_pack(mgpir_pl, 0); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mgpir), mgpir_pl); + if (err) + return err; + + mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, +- &module_sensor_max); ++ &module_sensor_max, NULL); + + /* Add extra attributes for module temperature. Sensor index is + * assigned to sensor_count value, while all indexed before +@@ -707,12 +707,13 @@ static int mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon) + u8 gbox_num; + int err; + +- mlxsw_reg_mgpir_pack(mgpir_pl); ++ mlxsw_reg_mgpir_pack(mgpir_pl, 0); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mgpir), mgpir_pl); + if (err) + return err; + +- mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, &device_type, NULL, NULL); ++ mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, &device_type, NULL, NULL, ++ NULL); + if (device_type != MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE || + !gbox_num) + return 0; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +index 8d88633c9..56e0291f1 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +@@ -787,13 +787,13 @@ mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, + char mgpir_pl[MLXSW_REG_MGPIR_LEN]; + int i, err; + +- mlxsw_reg_mgpir_pack(mgpir_pl); ++ mlxsw_reg_mgpir_pack(mgpir_pl, 0); + err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl); + if (err) + return err; + + mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, +- &thermal->tz_module_num); ++ &thermal->tz_module_num, NULL); + + thermal->tz_module_arr = kcalloc(thermal->tz_module_num, + sizeof(*thermal->tz_module_arr), +@@ -878,13 +878,13 @@ mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core, + int i; + int err; + +- mlxsw_reg_mgpir_pack(mgpir_pl); ++ mlxsw_reg_mgpir_pack(mgpir_pl, 0); + err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl); + if (err) + return err; + + mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, &device_type, NULL, +- NULL); ++ NULL, NULL); + if (device_type != MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE || + !gbox_num) + return 0; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +index 3d07c2dcf..b2ffcfda8 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +@@ -280,13 +280,13 @@ static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m) + char mgpir_pl[MLXSW_REG_MGPIR_LEN]; + int i, err; + +- mlxsw_reg_mgpir_pack(mgpir_pl); ++ mlxsw_reg_mgpir_pack(mgpir_pl, 0); + err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(mgpir), mgpir_pl); + if (err) + return err; + + mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, +- &mlxsw_m->max_ports); ++ &mlxsw_m->max_ports, NULL); + if (!mlxsw_m->max_ports) + return 0; + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h +index c19db16bf..e981630fd 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h +@@ -10167,6 +10167,12 @@ enum mlxsw_reg_mgpir_device_type { + MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE, + }; + ++/* mgpir_slot_index ++ * Slot index (0: Main board). ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, mgpir, slot_index, 0x00, 28, 4); ++ + /* mgpir_device_type + * Access: RO + */ +@@ -10184,21 +10190,29 @@ MLXSW_ITEM32(reg, mgpir, devices_per_flash, 0x00, 16, 8); + */ + MLXSW_ITEM32(reg, mgpir, num_of_devices, 0x00, 0, 8); + ++/* mgpir_num_of_slots ++ * Number of slots in the system. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mgpir, num_of_slots, 0x04, 8, 8); ++ + /* mgpir_num_of_modules + * Number of modules. + * Access: RO + */ + MLXSW_ITEM32(reg, mgpir, num_of_modules, 0x04, 0, 8); + +-static inline void mlxsw_reg_mgpir_pack(char *payload) ++static inline void mlxsw_reg_mgpir_pack(char *payload, u8 slot_index) + { + MLXSW_REG_ZERO(mgpir, payload); ++ mlxsw_reg_mgpir_slot_index_set(payload, slot_index); + } + + static inline void + mlxsw_reg_mgpir_unpack(char *payload, u8 *num_of_devices, + enum mlxsw_reg_mgpir_device_type *device_type, +- u8 *devices_per_flash, u8 *num_of_modules) ++ u8 *devices_per_flash, u8 *num_of_modules, ++ u8 *num_of_slots) + { + if (num_of_devices) + *num_of_devices = mlxsw_reg_mgpir_num_of_devices_get(payload); +@@ -10209,6 +10223,8 @@ mlxsw_reg_mgpir_unpack(char *payload, u8 *num_of_devices, + mlxsw_reg_mgpir_devices_per_flash_get(payload); + if (num_of_modules) + *num_of_modules = mlxsw_reg_mgpir_num_of_modules_get(payload); ++ if (num_of_slots) ++ *num_of_slots = mlxsw_reg_mgpir_num_of_slots_get(payload); + } + + /* MFDE - Monitoring FW Debug Register +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0110-mlxsw-core_env-Pass-slot-index-during-PMAOS-register.patch b/platform/mellanox/non-upstream-patches/patches/0110-mlxsw-core_env-Pass-slot-index-during-PMAOS-register.patch new file mode 100644 index 000000000000..ae90d51ca88b --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0110-mlxsw-core_env-Pass-slot-index-during-PMAOS-register.patch @@ -0,0 +1,66 @@ +From 562fe3c68c9dbcff172eeae8b4f0a84484b5e3e9 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Fri, 3 Dec 2021 11:48:52 +0200 +Subject: [PATCH] mlxsw: core_env: Pass slot index during PMAOS register write + call + +Pass the slot index down to PMAOS pack helper alongside with the module. + +Signed-off-by: Jiri Pirko +Signed-off-by: Vadim Pasternak +Signed-off-by: Ido Schimmel +--- + drivers/net/ethernet/mellanox/mlxsw/core_env.c | 6 +++--- + drivers/net/ethernet/mellanox/mlxsw/reg.h | 3 ++- + 2 files changed, 5 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +index b1a1204e7..45058d4cf 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +@@ -400,7 +400,7 @@ static int mlxsw_env_module_reset(struct mlxsw_core *mlxsw_core, u8 module) + { + char pmaos_pl[MLXSW_REG_PMAOS_LEN]; + +- mlxsw_reg_pmaos_pack(pmaos_pl, module); ++ mlxsw_reg_pmaos_pack(pmaos_pl, 0, module); + mlxsw_reg_pmaos_rst_set(pmaos_pl, true); + + return mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmaos), pmaos_pl); +@@ -488,7 +488,7 @@ static int mlxsw_env_module_enable_set(struct mlxsw_core *mlxsw_core, + enum mlxsw_reg_pmaos_admin_status admin_status; + char pmaos_pl[MLXSW_REG_PMAOS_LEN]; + +- mlxsw_reg_pmaos_pack(pmaos_pl, module); ++ mlxsw_reg_pmaos_pack(pmaos_pl, 0, module); + admin_status = enable ? MLXSW_REG_PMAOS_ADMIN_STATUS_ENABLED : + MLXSW_REG_PMAOS_ADMIN_STATUS_DISABLED; + mlxsw_reg_pmaos_admin_status_set(pmaos_pl, admin_status); +@@ -878,7 +878,7 @@ mlxsw_env_module_oper_state_event_enable(struct mlxsw_core *mlxsw_core, + for (i = 0; i < module_count; i++) { + char pmaos_pl[MLXSW_REG_PMAOS_LEN]; + +- mlxsw_reg_pmaos_pack(pmaos_pl, i); ++ mlxsw_reg_pmaos_pack(pmaos_pl, 0, i); + mlxsw_reg_pmaos_e_set(pmaos_pl, + MLXSW_REG_PMAOS_E_GENERATE_EVENT); + mlxsw_reg_pmaos_ee_set(pmaos_pl, true); +diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h +index e981630fd..748a22ec4 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h +@@ -5481,9 +5481,10 @@ enum mlxsw_reg_pmaos_e { + */ + MLXSW_ITEM32(reg, pmaos, e, 0x04, 0, 2); + +-static inline void mlxsw_reg_pmaos_pack(char *payload, u8 module) ++static inline void mlxsw_reg_pmaos_pack(char *payload, u8 slot_index, u8 module) + { + MLXSW_REG_ZERO(pmaos, payload); ++ mlxsw_reg_pmaos_slot_index_set(payload, slot_index); + mlxsw_reg_pmaos_module_set(payload, module); + } + +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0111-mlxsw-reg-Add-new-field-to-Management-General-Periph.patch b/platform/mellanox/non-upstream-patches/patches/0111-mlxsw-reg-Add-new-field-to-Management-General-Periph.patch new file mode 100644 index 000000000000..e785735732e0 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0111-mlxsw-reg-Add-new-field-to-Management-General-Periph.patch @@ -0,0 +1,38 @@ +From fe27f006de6b428fe59acb1960373b32e59adf0b Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Fri, 3 Dec 2021 11:48:49 +0200 +Subject: [PATCH] mlxsw: reg: Add new field to Management General Peripheral + Information Register + +Add new field 'max_modules_per_slot' to provide maximum number of +modules that can be connected per slot. This field will always be zero, +if 'slot_index' in query request is set to non-zero value, otherwise +value in this field will provide maximum modules number, which can be +equipped on device inserted at any slot. + +Signed-off-by: Vadim Pasternak +Signed-off-by: Ido Schimmel +--- + drivers/net/ethernet/mellanox/mlxsw/reg.h | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h +index 748a22ec4..9de037b9a 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h +@@ -10191,6 +10191,12 @@ MLXSW_ITEM32(reg, mgpir, devices_per_flash, 0x00, 16, 8); + */ + MLXSW_ITEM32(reg, mgpir, num_of_devices, 0x00, 0, 8); + ++/* max_modules_per_slot ++ * Maximum number of modules that can be connected per slot. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mgpir, max_modules_per_slot, 0x04, 16, 8); ++ + /* mgpir_num_of_slots + * Number of slots in the system. + * Access: RO +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0112-mlxsw-core-Extend-interfaces-for-cable-info-access-w.patch b/platform/mellanox/non-upstream-patches/patches/0112-mlxsw-core-Extend-interfaces-for-cable-info-access-w.patch new file mode 100644 index 000000000000..8b4290613cde --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0112-mlxsw-core-Extend-interfaces-for-cable-info-access-w.patch @@ -0,0 +1,828 @@ +From 5577988f783619b9d55f19c983ee8667f52165b7 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Fri, 3 Dec 2021 11:48:53 +0200 +Subject: [PATCH] mlxsw: core: Extend interfaces for cable info access with + slot argument + +Extend all cable info APIs with 'slot_index' argument. + +For main board, slot will always be set to zero and these APIs will work +as before. If reading cable information is required from cages located +on line cards, slot should be set to the physical slot number, where +line card is located in modular systems. + +Signed-off-by: Vadim Pasternak +Signed-off-by: Ido Schimmel +--- + .../net/ethernet/mellanox/mlxsw/core_env.c | 172 +++++++++++------- + .../net/ethernet/mellanox/mlxsw/core_env.h | 43 +++-- + .../net/ethernet/mellanox/mlxsw/core_hwmon.c | 10 +- + .../ethernet/mellanox/mlxsw/core_thermal.c | 4 +- + drivers/net/ethernet/mellanox/mlxsw/minimal.c | 21 ++- + .../net/ethernet/mellanox/mlxsw/spectrum.c | 2 +- + .../mellanox/mlxsw/spectrum_ethtool.c | 10 +- + 7 files changed, 155 insertions(+), 107 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +index 45058d4cf..fefb9bb02 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +@@ -27,16 +27,18 @@ struct mlxsw_env { + struct mlxsw_env_module_info module_info[]; + }; + +-static int mlxsw_env_validate_cable_ident(struct mlxsw_core *core, int id, +- bool *qsfp, bool *cmis) ++static int ++mlxsw_env_validate_cable_ident(struct mlxsw_core *core, u8 slot_index, int id, ++ bool *qsfp, bool *cmis) + { + char mcia_pl[MLXSW_REG_MCIA_LEN]; + char *eeprom_tmp; + u8 ident; + int err; + +- mlxsw_reg_mcia_pack(mcia_pl, 0, id, 0, MLXSW_REG_MCIA_PAGE0_LO_OFF, 0, +- 1, MLXSW_REG_MCIA_I2C_ADDR_LOW); ++ mlxsw_reg_mcia_pack(mcia_pl, slot_index, id, 0, ++ MLXSW_REG_MCIA_PAGE0_LO_OFF, 0, 1, ++ MLXSW_REG_MCIA_I2C_ADDR_LOW); + err = mlxsw_reg_query(core, MLXSW_REG(mcia), mcia_pl); + if (err) + return err; +@@ -65,8 +67,8 @@ static int mlxsw_env_validate_cable_ident(struct mlxsw_core *core, int id, + } + + static int +-mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, int module, +- u16 offset, u16 size, void *data, ++mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ int module, u16 offset, u16 size, void *data, + bool qsfp, unsigned int *p_read_size) + { + char mcia_pl[MLXSW_REG_MCIA_LEN]; +@@ -111,7 +113,7 @@ mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, int module, + } + } + +- mlxsw_reg_mcia_pack(mcia_pl, 0, module, 0, page, offset, size, ++ mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, 0, page, offset, size, + i2c_addr); + + err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcia), mcia_pl); +@@ -129,8 +131,9 @@ mlxsw_env_query_module_eeprom(struct mlxsw_core *mlxsw_core, int module, + return 0; + } + +-int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, int module, +- int off, int *temp) ++int ++mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, u8 slot_index, ++ int module, int off, int *temp) + { + unsigned int module_temp, module_crit, module_emerg; + union { +@@ -144,8 +147,9 @@ int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, int module, + int page; + int err; + +- mlxsw_reg_mtmp_pack(mtmp_pl, 0, MLXSW_REG_MTMP_MODULE_INDEX_MIN + module, +- false, false); ++ mlxsw_reg_mtmp_pack(mtmp_pl, slot_index, ++ MLXSW_REG_MTMP_MODULE_INDEX_MIN + module, false, ++ false); + err = mlxsw_reg_query(core, MLXSW_REG(mtmp), mtmp_pl); + if (err) + return err; +@@ -174,7 +178,8 @@ int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, int module, + */ + + /* Validate module identifier value. */ +- err = mlxsw_env_validate_cable_ident(core, module, &qsfp, &cmis); ++ err = mlxsw_env_validate_cable_ident(core, slot_index, module, &qsfp, ++ &cmis); + if (err) + return err; + +@@ -186,12 +191,12 @@ int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, int module, + page = MLXSW_REG_MCIA_TH_PAGE_CMIS_NUM; + else + page = MLXSW_REG_MCIA_TH_PAGE_NUM; +- mlxsw_reg_mcia_pack(mcia_pl, 0, module, 0, page, ++ mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, 0, page, + MLXSW_REG_MCIA_TH_PAGE_OFF + off, + MLXSW_REG_MCIA_TH_ITEM_SIZE, + MLXSW_REG_MCIA_I2C_ADDR_LOW); + } else { +- mlxsw_reg_mcia_pack(mcia_pl, 0, module, 0, ++ mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, 0, + MLXSW_REG_MCIA_PAGE0_LO, + off, MLXSW_REG_MCIA_TH_ITEM_SIZE, + MLXSW_REG_MCIA_I2C_ADDR_HIGH); +@@ -208,8 +213,8 @@ int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, int module, + return 0; + } + +-int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module, +- struct ethtool_modinfo *modinfo) ++int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ int module, struct ethtool_modinfo *modinfo) + { + u8 module_info[MLXSW_REG_MCIA_EEPROM_MODULE_INFO_SIZE]; + u16 offset = MLXSW_REG_MCIA_EEPROM_MODULE_INFO_SIZE; +@@ -217,8 +222,9 @@ int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module, + unsigned int read_size; + int err; + +- err = mlxsw_env_query_module_eeprom(mlxsw_core, module, 0, offset, +- module_info, false, &read_size); ++ err = mlxsw_env_query_module_eeprom(mlxsw_core, slot_index, module, 0, ++ offset, module_info, false, ++ &read_size); + if (err) + return err; + +@@ -247,9 +253,10 @@ int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module, + break; + case MLXSW_REG_MCIA_EEPROM_MODULE_INFO_ID_SFP: + /* Verify if transceiver provides diagnostic monitoring page */ +- err = mlxsw_env_query_module_eeprom(mlxsw_core, module, +- SFP_DIAGMON, 1, &diag_mon, +- false, &read_size); ++ err = mlxsw_env_query_module_eeprom(mlxsw_core, slot_index, ++ module, SFP_DIAGMON, 1, ++ &diag_mon, false, ++ &read_size); + if (err) + return err; + +@@ -288,8 +295,9 @@ int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module, + EXPORT_SYMBOL(mlxsw_env_get_module_info); + + int mlxsw_env_get_module_eeprom(struct net_device *netdev, +- struct mlxsw_core *mlxsw_core, int module, +- struct ethtool_eeprom *ee, u8 *data) ++ struct mlxsw_core *mlxsw_core, u8 slot_index, ++ int module, struct ethtool_eeprom *ee, ++ u8 *data) + { + int offset = ee->offset; + unsigned int read_size; +@@ -302,12 +310,14 @@ int mlxsw_env_get_module_eeprom(struct net_device *netdev, + + memset(data, 0, ee->len); + /* Validate module identifier value. */ +- err = mlxsw_env_validate_cable_ident(mlxsw_core, module, &qsfp, &cmis); ++ err = mlxsw_env_validate_cable_ident(mlxsw_core, slot_index, module, ++ &qsfp, &cmis); + if (err) + return err; + + while (i < ee->len) { +- err = mlxsw_env_query_module_eeprom(mlxsw_core, module, offset, ++ err = mlxsw_env_query_module_eeprom(mlxsw_core, slot_index, ++ module, offset, + ee->len - i, data + i, + qsfp, &read_size); + if (err) { +@@ -353,7 +363,8 @@ static int mlxsw_env_mcia_status_process(const char *mcia_pl, + } + + int +-mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, u8 module, ++mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, ++ u8 slot_index, u8 module, + const struct ethtool_module_eeprom *page, + struct netlink_ext_ack *extack) + { +@@ -372,7 +383,7 @@ mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, u8 module, + size = min_t(u8, page->length - bytes_read, + MLXSW_REG_MCIA_EEPROM_SIZE); + +- mlxsw_reg_mcia_pack(mcia_pl, 0, module, 0, page->page, ++ mlxsw_reg_mcia_pack(mcia_pl, slot_index, module, 0, page->page, + device_addr + bytes_read, size, + page->i2c_address); + mlxsw_reg_mcia_bank_number_set(mcia_pl, page->bank); +@@ -396,18 +407,20 @@ mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, u8 module, + } + EXPORT_SYMBOL(mlxsw_env_get_module_eeprom_by_page); + +-static int mlxsw_env_module_reset(struct mlxsw_core *mlxsw_core, u8 module) ++static int mlxsw_env_module_reset(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u8 module) + { + char pmaos_pl[MLXSW_REG_PMAOS_LEN]; + +- mlxsw_reg_pmaos_pack(pmaos_pl, 0, module); ++ mlxsw_reg_pmaos_pack(pmaos_pl, slot_index, module); + mlxsw_reg_pmaos_rst_set(pmaos_pl, true); + + return mlxsw_reg_write(mlxsw_core, MLXSW_REG(pmaos), pmaos_pl); + } + + int mlxsw_env_reset_module(struct net_device *netdev, +- struct mlxsw_core *mlxsw_core, u8 module, u32 *flags) ++ struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u8 module, u32 *flags) + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); + u32 req = *flags; +@@ -432,7 +445,7 @@ int mlxsw_env_reset_module(struct net_device *netdev, + goto out; + } + +- err = mlxsw_env_module_reset(mlxsw_core, module); ++ err = mlxsw_env_module_reset(mlxsw_core, slot_index, module); + if (err) { + netdev_err(netdev, "Failed to reset module\n"); + goto out; +@@ -447,7 +460,8 @@ int mlxsw_env_reset_module(struct net_device *netdev, + EXPORT_SYMBOL(mlxsw_env_reset_module); + + int +-mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 module, ++mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u8 module, + struct ethtool_module_power_mode_params *params, + struct netlink_ext_ack *extack) + { +@@ -460,7 +474,7 @@ mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 module, + + params->policy = mlxsw_env->module_info[module].power_mode_policy; + +- mlxsw_reg_mcion_pack(mcion_pl, 0, module); ++ mlxsw_reg_mcion_pack(mcion_pl, slot_index, module); + err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcion), mcion_pl); + if (err) { + NL_SET_ERR_MSG_MOD(extack, "Failed to retrieve module's power mode"); +@@ -483,12 +497,12 @@ mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 module, + EXPORT_SYMBOL(mlxsw_env_get_module_power_mode); + + static int mlxsw_env_module_enable_set(struct mlxsw_core *mlxsw_core, +- u8 module, bool enable) ++ u8 slot_index, u8 module, bool enable) + { + enum mlxsw_reg_pmaos_admin_status admin_status; + char pmaos_pl[MLXSW_REG_PMAOS_LEN]; + +- mlxsw_reg_pmaos_pack(pmaos_pl, 0, module); ++ mlxsw_reg_pmaos_pack(pmaos_pl, slot_index, module); + admin_status = enable ? MLXSW_REG_PMAOS_ADMIN_STATUS_ENABLED : + MLXSW_REG_PMAOS_ADMIN_STATUS_DISABLED; + mlxsw_reg_pmaos_admin_status_set(pmaos_pl, admin_status); +@@ -498,12 +512,13 @@ static int mlxsw_env_module_enable_set(struct mlxsw_core *mlxsw_core, + } + + static int mlxsw_env_module_low_power_set(struct mlxsw_core *mlxsw_core, +- u8 module, bool low_power) ++ u8 slot_index, u8 module, ++ bool low_power) + { + u16 eeprom_override_mask, eeprom_override; + char pmmp_pl[MLXSW_REG_PMMP_LEN]; + +- mlxsw_reg_pmmp_pack(pmmp_pl, 0, module); ++ mlxsw_reg_pmmp_pack(pmmp_pl, slot_index, module); + mlxsw_reg_pmmp_sticky_set(pmmp_pl, true); + /* Mask all the bits except low power mode. */ + eeprom_override_mask = ~MLXSW_REG_PMMP_EEPROM_OVERRIDE_LOW_POWER_MASK; +@@ -516,24 +531,26 @@ static int mlxsw_env_module_low_power_set(struct mlxsw_core *mlxsw_core, + } + + static int __mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, +- u8 module, bool low_power, ++ u8 slot_index, u8 module, ++ bool low_power, + struct netlink_ext_ack *extack) + { + int err; + +- err = mlxsw_env_module_enable_set(mlxsw_core, module, false); ++ err = mlxsw_env_module_enable_set(mlxsw_core, slot_index, module, false); + if (err) { + NL_SET_ERR_MSG_MOD(extack, "Failed to disable module"); + return err; + } + +- err = mlxsw_env_module_low_power_set(mlxsw_core, module, low_power); ++ err = mlxsw_env_module_low_power_set(mlxsw_core, slot_index, module, ++ low_power); + if (err) { + NL_SET_ERR_MSG_MOD(extack, "Failed to set module's power mode"); + goto err_module_low_power_set; + } + +- err = mlxsw_env_module_enable_set(mlxsw_core, module, true); ++ err = mlxsw_env_module_enable_set(mlxsw_core, slot_index, module, true); + if (err) { + NL_SET_ERR_MSG_MOD(extack, "Failed to enable module"); + goto err_module_enable_set; +@@ -542,14 +559,16 @@ static int __mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, + return 0; + + err_module_enable_set: +- mlxsw_env_module_low_power_set(mlxsw_core, module, !low_power); ++ mlxsw_env_module_low_power_set(mlxsw_core, slot_index, module, ++ !low_power); + err_module_low_power_set: +- mlxsw_env_module_enable_set(mlxsw_core, module, true); ++ mlxsw_env_module_enable_set(mlxsw_core, slot_index, module, true); + return err; + } + + int +-mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 module, ++mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u8 module, + enum ethtool_module_power_mode_policy policy, + struct netlink_ext_ack *extack) + { +@@ -573,8 +592,8 @@ mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 module, + goto out_set_policy; + + low_power = policy == ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO; +- err = __mlxsw_env_set_module_power_mode(mlxsw_core, module, low_power, +- extack); ++ err = __mlxsw_env_set_module_power_mode(mlxsw_core, slot_index, module, ++ low_power, extack); + if (err) + goto out; + +@@ -587,14 +606,14 @@ mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 module, + EXPORT_SYMBOL(mlxsw_env_set_module_power_mode); + + static int mlxsw_env_module_has_temp_sensor(struct mlxsw_core *mlxsw_core, +- u8 module, ++ u8 slot_index, u8 module, + bool *p_has_temp_sensor) + { + char mtbr_pl[MLXSW_REG_MTBR_LEN]; + u16 temp; + int err; + +- mlxsw_reg_mtbr_pack(mtbr_pl, 0, ++ mlxsw_reg_mtbr_pack(mtbr_pl, slot_index, + MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, 1); + err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mtbr), mtbr_pl); + if (err) +@@ -615,13 +634,15 @@ static int mlxsw_env_module_has_temp_sensor(struct mlxsw_core *mlxsw_core, + return 0; + } + +-static int mlxsw_env_temp_event_set(struct mlxsw_core *mlxsw_core, +- u16 sensor_index, bool enable) ++static int ++mlxsw_env_temp_event_set(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u16 sensor_index, bool enable) + { + char mtmp_pl[MLXSW_REG_MTMP_LEN] = {0}; + enum mlxsw_reg_mtmp_tee tee; + int err, threshold_hi; + ++ mlxsw_reg_mtmp_slot_index_set(mtmp_pl, slot_index); + mlxsw_reg_mtmp_sensor_index_set(mtmp_pl, sensor_index); + err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mtmp), mtmp_pl); + if (err) +@@ -629,6 +650,7 @@ static int mlxsw_env_temp_event_set(struct mlxsw_core *mlxsw_core, + + if (enable) { + err = mlxsw_env_module_temp_thresholds_get(mlxsw_core, ++ slot_index, + sensor_index - + MLXSW_REG_MTMP_MODULE_INDEX_MIN, + SFP_TEMP_HIGH_WARN, +@@ -656,14 +678,14 @@ static int mlxsw_env_temp_event_set(struct mlxsw_core *mlxsw_core, + } + + static int mlxsw_env_module_temp_event_enable(struct mlxsw_core *mlxsw_core, +- u8 module_count) ++ u8 slot_index, u8 module_count) + { + int i, err, sensor_index; + bool has_temp_sensor; + + for (i = 0; i < module_count; i++) { +- err = mlxsw_env_module_has_temp_sensor(mlxsw_core, i, +- &has_temp_sensor); ++ err = mlxsw_env_module_has_temp_sensor(mlxsw_core, slot_index, ++ i, &has_temp_sensor); + if (err) + return err; + +@@ -671,7 +693,8 @@ static int mlxsw_env_module_temp_event_enable(struct mlxsw_core *mlxsw_core, + continue; + + sensor_index = i + MLXSW_REG_MTMP_MODULE_INDEX_MIN; +- err = mlxsw_env_temp_event_set(mlxsw_core, sensor_index, true); ++ err = mlxsw_env_temp_event_set(mlxsw_core, slot_index, ++ sensor_index, true); + if (err) + return err; + } +@@ -778,6 +801,7 @@ static void mlxsw_env_temp_warn_event_unregister(struct mlxsw_env *mlxsw_env) + + struct mlxsw_env_module_plug_unplug_event { + struct mlxsw_env *mlxsw_env; ++ u8 slot_index; + u8 module; + struct work_struct work; + }; +@@ -798,7 +822,9 @@ static void mlxsw_env_pmpe_event_work(struct work_struct *work) + mlxsw_env->module_info[event->module].is_overheat = false; + mutex_unlock(&mlxsw_env->module_info_lock); + +- err = mlxsw_env_module_has_temp_sensor(mlxsw_env->core, event->module, ++ err = mlxsw_env_module_has_temp_sensor(mlxsw_env->core, ++ event->slot_index, ++ event->module, + &has_temp_sensor); + /* Do not disable events on modules without sensors or faulty sensors + * because FW returns errors. +@@ -810,7 +836,8 @@ static void mlxsw_env_pmpe_event_work(struct work_struct *work) + goto out; + + sensor_index = event->module + MLXSW_REG_MTMP_MODULE_INDEX_MIN; +- mlxsw_env_temp_event_set(mlxsw_env->core, sensor_index, true); ++ mlxsw_env_temp_event_set(mlxsw_env->core, event->slot_index, ++ sensor_index, true); + + out: + kfree(event); +@@ -837,6 +864,7 @@ mlxsw_env_pmpe_listener_func(const struct mlxsw_reg_info *reg, char *pmpe_pl, + return; + + event->mlxsw_env = mlxsw_env; ++ event->slot_index = 0; + event->module = module; + INIT_WORK(&event->work, mlxsw_env_pmpe_event_work); + mlxsw_core_schedule_work(&event->work); +@@ -871,14 +899,14 @@ mlxsw_env_module_plug_event_unregister(struct mlxsw_env *mlxsw_env) + + static int + mlxsw_env_module_oper_state_event_enable(struct mlxsw_core *mlxsw_core, +- u8 module_count) ++ u8 slot_index, u8 module_count) + { + int i, err; + + for (i = 0; i < module_count; i++) { + char pmaos_pl[MLXSW_REG_PMAOS_LEN]; + +- mlxsw_reg_pmaos_pack(pmaos_pl, 0, i); ++ mlxsw_reg_pmaos_pack(pmaos_pl, slot_index, i); + mlxsw_reg_pmaos_e_set(pmaos_pl, + MLXSW_REG_PMAOS_E_GENERATE_EVENT); + mlxsw_reg_pmaos_ee_set(pmaos_pl, true); +@@ -890,8 +918,8 @@ mlxsw_env_module_oper_state_event_enable(struct mlxsw_core *mlxsw_core, + } + + int +-mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 module, +- u64 *p_counter) ++mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u8 module, u64 *p_counter) + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); + +@@ -903,7 +931,8 @@ mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 module, + } + EXPORT_SYMBOL(mlxsw_env_module_overheat_counter_get); + +-void mlxsw_env_module_port_map(struct mlxsw_core *mlxsw_core, u8 module) ++void mlxsw_env_module_port_map(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u8 module) + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); + +@@ -913,7 +942,8 @@ void mlxsw_env_module_port_map(struct mlxsw_core *mlxsw_core, u8 module) + } + EXPORT_SYMBOL(mlxsw_env_module_port_map); + +-void mlxsw_env_module_port_unmap(struct mlxsw_core *mlxsw_core, u8 module) ++void mlxsw_env_module_port_unmap(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u8 module) + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); + +@@ -923,7 +953,8 @@ void mlxsw_env_module_port_unmap(struct mlxsw_core *mlxsw_core, u8 module) + } + EXPORT_SYMBOL(mlxsw_env_module_port_unmap); + +-int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 module) ++int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u8 module) + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); + int err = 0; +@@ -940,8 +971,8 @@ int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 module) + /* Transition to high power mode following first port using the module + * being put administratively up. + */ +- err = __mlxsw_env_set_module_power_mode(mlxsw_core, module, false, +- NULL); ++ err = __mlxsw_env_set_module_power_mode(mlxsw_core, slot_index, module, ++ false, NULL); + if (err) + goto out_unlock; + +@@ -953,7 +984,8 @@ int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 module) + } + EXPORT_SYMBOL(mlxsw_env_module_port_up); + +-void mlxsw_env_module_port_down(struct mlxsw_core *mlxsw_core, u8 module) ++void mlxsw_env_module_port_down(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u8 module) + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); + +@@ -971,7 +1003,8 @@ void mlxsw_env_module_port_down(struct mlxsw_core *mlxsw_core, u8 module) + /* Transition to low power mode following last port using the module + * being put administratively down. + */ +- __mlxsw_env_set_module_power_mode(mlxsw_core, module, true, NULL); ++ __mlxsw_env_set_module_power_mode(mlxsw_core, slot_index, module, true, ++ NULL); + + out_unlock: + mutex_unlock(&mlxsw_env->module_info_lock); +@@ -1016,12 +1049,13 @@ int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env) + if (err) + goto err_module_plug_event_register; + +- err = mlxsw_env_module_oper_state_event_enable(mlxsw_core, ++ err = mlxsw_env_module_oper_state_event_enable(mlxsw_core, 0, + env->module_count); + if (err) + goto err_oper_state_event_enable; + +- err = mlxsw_env_module_temp_event_enable(mlxsw_core, env->module_count); ++ err = mlxsw_env_module_temp_event_enable(mlxsw_core, 0, ++ env->module_count); + if (err) + goto err_temp_event_enable; + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.h b/drivers/net/ethernet/mellanox/mlxsw/core_env.h +index da121b1a8..03d027870 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.h +@@ -9,46 +9,55 @@ + struct ethtool_modinfo; + struct ethtool_eeprom; + +-int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, int module, +- int off, int *temp); ++int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, ++ u8 slot_index, int module, int off, ++ int *temp); + +-int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, int module, +- struct ethtool_modinfo *modinfo); ++int mlxsw_env_get_module_info(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ int module, struct ethtool_modinfo *modinfo); + + int mlxsw_env_get_module_eeprom(struct net_device *netdev, +- struct mlxsw_core *mlxsw_core, int module, +- struct ethtool_eeprom *ee, u8 *data); ++ struct mlxsw_core *mlxsw_core, u8 slot_index, ++ int module, struct ethtool_eeprom *ee, ++ u8 *data); + + int +-mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, u8 module, ++mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, ++ u8 slot_index, u8 module, + const struct ethtool_module_eeprom *page, + struct netlink_ext_ack *extack); + + int mlxsw_env_reset_module(struct net_device *netdev, +- struct mlxsw_core *mlxsw_core, u8 module, +- u32 *flags); ++ struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u8 module, u32 *flags); + + int +-mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 module, ++mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u8 module, + struct ethtool_module_power_mode_params *params, + struct netlink_ext_ack *extack); + + int +-mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 module, ++mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u8 module, + enum ethtool_module_power_mode_policy policy, + struct netlink_ext_ack *extack); + + int +-mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 module, +- u64 *p_counter); ++mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u8 module, u64 *p_counter); + +-void mlxsw_env_module_port_map(struct mlxsw_core *mlxsw_core, u8 module); ++void mlxsw_env_module_port_map(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u8 module); + +-void mlxsw_env_module_port_unmap(struct mlxsw_core *mlxsw_core, u8 module); ++void mlxsw_env_module_port_unmap(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u8 module); + +-int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 module); ++int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u8 module); + +-void mlxsw_env_module_port_down(struct mlxsw_core *mlxsw_core, u8 module); ++void mlxsw_env_module_port_down(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ u8 module); + + int mlxsw_env_init(struct mlxsw_core *core, struct mlxsw_env **p_env); + void mlxsw_env_fini(struct mlxsw_env *env); +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +index 2bc4c4556..5df54a5bf 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +@@ -311,8 +311,9 @@ static int mlxsw_hwmon_module_temp_critical_get(struct device *dev, + int err; + + module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; +- err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, module, +- SFP_TEMP_HIGH_WARN, p_temp); ++ err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, 0, ++ module, SFP_TEMP_HIGH_WARN, ++ p_temp); + if (err) { + dev_err(dev, "Failed to query module temperature thresholds\n"); + return err; +@@ -345,8 +346,9 @@ static int mlxsw_hwmon_module_temp_emergency_get(struct device *dev, + int err; + + module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; +- err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, module, +- SFP_TEMP_HIGH_ALARM, p_temp); ++ err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, 0, ++ module, SFP_TEMP_HIGH_ALARM, ++ p_temp); + if (err) { + dev_err(dev, "Failed to query module temperature thresholds\n"); + return err; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +index 56e0291f1..3f9062f1c 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +@@ -159,13 +159,13 @@ mlxsw_thermal_module_trips_update(struct device *dev, struct mlxsw_core *core, + * EEPROM if we got valid thresholds from MTMP. + */ + if (!emerg_temp || !crit_temp) { +- err = mlxsw_env_module_temp_thresholds_get(core, tz->module, ++ err = mlxsw_env_module_temp_thresholds_get(core, 0, tz->module, + SFP_TEMP_HIGH_WARN, + &crit_temp); + if (err) + return err; + +- err = mlxsw_env_module_temp_thresholds_get(core, tz->module, ++ err = mlxsw_env_module_temp_thresholds_get(core, 0, tz->module, + SFP_TEMP_HIGH_ALARM, + &emerg_temp); + if (err) +diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +index b2ffcfda8..104f1ba02 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +@@ -59,7 +59,8 @@ static int mlxsw_m_port_open(struct net_device *dev) + struct mlxsw_m_port *mlxsw_m_port = netdev_priv(dev); + struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m; + +- return mlxsw_env_module_port_up(mlxsw_m->core, mlxsw_m_port->module); ++ return mlxsw_env_module_port_up(mlxsw_m->core, 0, ++ mlxsw_m_port->module); + } + + static int mlxsw_m_port_stop(struct net_device *dev) +@@ -67,7 +68,7 @@ static int mlxsw_m_port_stop(struct net_device *dev) + struct mlxsw_m_port *mlxsw_m_port = netdev_priv(dev); + struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m; + +- mlxsw_env_module_port_down(mlxsw_m->core, mlxsw_m_port->module); ++ mlxsw_env_module_port_down(mlxsw_m->core, 0, mlxsw_m_port->module); + return 0; + } + +@@ -110,7 +111,8 @@ static int mlxsw_m_get_module_info(struct net_device *netdev, + struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev); + struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core; + +- return mlxsw_env_get_module_info(core, mlxsw_m_port->module, modinfo); ++ return mlxsw_env_get_module_info(core, 0, mlxsw_m_port->module, ++ modinfo); + } + + static int +@@ -120,8 +122,8 @@ mlxsw_m_get_module_eeprom(struct net_device *netdev, struct ethtool_eeprom *ee, + struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev); + struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core; + +- return mlxsw_env_get_module_eeprom(netdev, core, mlxsw_m_port->module, +- ee, data); ++ return mlxsw_env_get_module_eeprom(netdev, core, 0, ++ mlxsw_m_port->module, ee, data); + } + + static int +@@ -132,7 +134,8 @@ mlxsw_m_get_module_eeprom_by_page(struct net_device *netdev, + struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev); + struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core; + +- return mlxsw_env_get_module_eeprom_by_page(core, mlxsw_m_port->module, ++ return mlxsw_env_get_module_eeprom_by_page(core, 0, ++ mlxsw_m_port->module, + page, extack); + } + +@@ -141,7 +144,7 @@ static int mlxsw_m_reset(struct net_device *netdev, u32 *flags) + struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev); + struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core; + +- return mlxsw_env_reset_module(netdev, core, mlxsw_m_port->module, ++ return mlxsw_env_reset_module(netdev, core, 0, mlxsw_m_port->module, + flags); + } + +@@ -153,7 +156,7 @@ mlxsw_m_get_module_power_mode(struct net_device *netdev, + struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev); + struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core; + +- return mlxsw_env_get_module_power_mode(core, mlxsw_m_port->module, ++ return mlxsw_env_get_module_power_mode(core, 0, mlxsw_m_port->module, + params, extack); + } + +@@ -165,7 +168,7 @@ mlxsw_m_set_module_power_mode(struct net_device *netdev, + struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev); + struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core; + +- return mlxsw_env_set_module_power_mode(core, mlxsw_m_port->module, ++ return mlxsw_env_set_module_power_mode(core, 0, mlxsw_m_port->module, + params->policy, extack); + } + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +index 9f068c030..5066fcc46 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +@@ -1377,7 +1377,7 @@ static int mlxsw_sp_port_overheat_init_val_set(struct mlxsw_sp_port *mlxsw_sp_po + u64 overheat_counter; + int err; + +- err = mlxsw_env_module_overheat_counter_get(mlxsw_sp->core, module, ++ err = mlxsw_env_module_overheat_counter_get(mlxsw_sp->core, 0, module, + &overheat_counter); + if (err) + return err; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ethtool.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ethtool.c +index 369b9d0dc..c9298b236 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ethtool.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ethtool.c +@@ -566,7 +566,7 @@ mlxsw_sp_port_get_transceiver_overheat_stats(struct mlxsw_sp_port *mlxsw_sp_port + u64 stats; + int err; + +- err = mlxsw_env_module_overheat_counter_get(mlxsw_core, ++ err = mlxsw_env_module_overheat_counter_get(mlxsw_core, 0, + port_mapping.module, + &stats); + if (err) +@@ -1032,7 +1032,7 @@ static int mlxsw_sp_get_module_info(struct net_device *netdev, + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + int err; + +- err = mlxsw_env_get_module_info(mlxsw_sp->core, ++ err = mlxsw_env_get_module_info(mlxsw_sp->core, 0, + mlxsw_sp_port->mapping.module, + modinfo); + +@@ -1046,7 +1046,7 @@ static int mlxsw_sp_get_module_eeprom(struct net_device *netdev, + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + int err; + +- err = mlxsw_env_get_module_eeprom(netdev, mlxsw_sp->core, ++ err = mlxsw_env_get_module_eeprom(netdev, mlxsw_sp->core, 0, + mlxsw_sp_port->mapping.module, ee, + data); + +@@ -1062,8 +1062,8 @@ mlxsw_sp_get_module_eeprom_by_page(struct net_device *dev, + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + u8 module = mlxsw_sp_port->mapping.module; + +- return mlxsw_env_get_module_eeprom_by_page(mlxsw_sp->core, module, page, +- extack); ++ return mlxsw_env_get_module_eeprom_by_page(mlxsw_sp->core, 0, module, ++ page, extack); + } + + static int +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0113-mlxsw-core-Extend-port-module-data-structures-for-li.patch b/platform/mellanox/non-upstream-patches/patches/0113-mlxsw-core-Extend-port-module-data-structures-for-li.patch new file mode 100644 index 000000000000..d2e9385ffa3c --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0113-mlxsw-core-Extend-port-module-data-structures-for-li.patch @@ -0,0 +1,520 @@ +From 8e7c606209b97b89b58d21a2c33c319ade1ba867 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Tue, 14 Dec 2021 10:57:27 +0200 +Subject: [PATCH] mlxsw: core: Extend port module data structures for line + cards + +The port module core is tasked with module operations such as setting +power mode policy and reset. The per-module information is currently +stored in one large array suited for non-modular systems where only the +main board is present (i.e., slot index 0). + +As a preparation for line cards support, allocate a per line card array +according to the queried number of slots in the system. For each line +card, allocate a module array according to the queried maximum number of +modules per-slot. + +Signed-off-by: Vadim Pasternak +Signed-off-by: Ido Schimmel +--- + .../net/ethernet/mellanox/mlxsw/core_env.c | 223 ++++++++++++------ + 1 file changed, 157 insertions(+), 66 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +index fefb9bb02..2a6630547 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +@@ -20,13 +20,19 @@ struct mlxsw_env_module_info { + enum ethtool_module_power_mode_policy power_mode_policy; + }; + +-struct mlxsw_env { +- struct mlxsw_core *core; ++struct mlxsw_env_module_line_cards { + u8 module_count; +- struct mutex module_info_lock; /* Protects 'module_info'. */ + struct mlxsw_env_module_info module_info[]; + }; + ++struct mlxsw_env { ++ struct mlxsw_core *core; ++ u8 max_module_count; /* Maximum number of modules per-slot. */ ++ u8 num_of_slots; /* Including the main board. */ ++ struct mutex line_cards_lock; /* Protects line cards. */ ++ struct mlxsw_env_module_line_cards *line_cards[]; ++}; ++ + static int + mlxsw_env_validate_cable_ident(struct mlxsw_core *core, u8 slot_index, int id, + bool *qsfp, bool *cmis) +@@ -407,6 +413,15 @@ mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, + } + EXPORT_SYMBOL(mlxsw_env_get_module_eeprom_by_page); + ++static struct ++mlxsw_env_module_info *mlxsw_env_module_info_get(struct mlxsw_core *mlxsw_core, ++ u8 slot_index, u8 module) ++{ ++ struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); ++ ++ return &mlxsw_env->line_cards[slot_index]->module_info[module]; ++} ++ + static int mlxsw_env_module_reset(struct mlxsw_core *mlxsw_core, u8 slot_index, + u8 module) + { +@@ -423,6 +438,7 @@ int mlxsw_env_reset_module(struct net_device *netdev, + u8 module, u32 *flags) + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); ++ struct mlxsw_env_module_info *module_info; + u32 req = *flags; + int err; + +@@ -430,15 +446,16 @@ int mlxsw_env_reset_module(struct net_device *netdev, + !(req & (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT))) + return 0; + +- mutex_lock(&mlxsw_env->module_info_lock); ++ mutex_lock(&mlxsw_env->line_cards_lock); + +- if (mlxsw_env->module_info[module].num_ports_up) { ++ module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module); ++ if (module_info->num_ports_up) { + netdev_err(netdev, "Cannot reset module when ports using it are administratively up\n"); + err = -EINVAL; + goto out; + } + +- if (mlxsw_env->module_info[module].num_ports_mapped > 1 && ++ if (module_info->num_ports_mapped > 1 && + !(req & (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT))) { + netdev_err(netdev, "Cannot reset module without \"phy-shared\" flag when shared by multiple ports\n"); + err = -EINVAL; +@@ -454,7 +471,7 @@ int mlxsw_env_reset_module(struct net_device *netdev, + *flags &= ~(ETH_RESET_PHY | (ETH_RESET_PHY << ETH_RESET_SHARED_SHIFT)); + + out: +- mutex_unlock(&mlxsw_env->module_info_lock); ++ mutex_unlock(&mlxsw_env->line_cards_lock); + return err; + } + EXPORT_SYMBOL(mlxsw_env_reset_module); +@@ -466,13 +483,15 @@ mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index, + struct netlink_ext_ack *extack) + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); ++ struct mlxsw_env_module_info *module_info; + char mcion_pl[MLXSW_REG_MCION_LEN]; + u32 status_bits; + int err; + +- mutex_lock(&mlxsw_env->module_info_lock); ++ mutex_lock(&mlxsw_env->line_cards_lock); + +- params->policy = mlxsw_env->module_info[module].power_mode_policy; ++ module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module); ++ params->policy = module_info->power_mode_policy; + + mlxsw_reg_mcion_pack(mcion_pl, slot_index, module); + err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mcion), mcion_pl); +@@ -491,7 +510,7 @@ mlxsw_env_get_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index, + params->mode = ETHTOOL_MODULE_POWER_MODE_HIGH; + + out: +- mutex_unlock(&mlxsw_env->module_info_lock); ++ mutex_unlock(&mlxsw_env->line_cards_lock); + return err; + } + EXPORT_SYMBOL(mlxsw_env_get_module_power_mode); +@@ -573,6 +592,7 @@ mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index, + struct netlink_ext_ack *extack) + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); ++ struct mlxsw_env_module_info *module_info; + bool low_power; + int err = 0; + +@@ -582,13 +602,14 @@ mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index, + return -EOPNOTSUPP; + } + +- mutex_lock(&mlxsw_env->module_info_lock); ++ mutex_lock(&mlxsw_env->line_cards_lock); + +- if (mlxsw_env->module_info[module].power_mode_policy == policy) ++ module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module); ++ if (module_info->power_mode_policy == policy) + goto out; + + /* If any ports are up, we are already in high power mode. */ +- if (mlxsw_env->module_info[module].num_ports_up) ++ if (module_info->num_ports_up) + goto out_set_policy; + + low_power = policy == ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO; +@@ -598,9 +619,9 @@ mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index, + goto out; + + out_set_policy: +- mlxsw_env->module_info[module].power_mode_policy = policy; ++ module_info->power_mode_policy = policy; + out: +- mutex_unlock(&mlxsw_env->module_info_lock); ++ mutex_unlock(&mlxsw_env->line_cards_lock); + return err; + } + EXPORT_SYMBOL(mlxsw_env_set_module_power_mode); +@@ -711,6 +732,7 @@ struct mlxsw_env_module_temp_warn_event { + static void mlxsw_env_mtwe_event_work(struct work_struct *work) + { + struct mlxsw_env_module_temp_warn_event *event; ++ struct mlxsw_env_module_info *module_info; + struct mlxsw_env *mlxsw_env; + int i, sensor_warning; + bool is_overheat; +@@ -719,7 +741,7 @@ static void mlxsw_env_mtwe_event_work(struct work_struct *work) + work); + mlxsw_env = event->mlxsw_env; + +- for (i = 0; i < mlxsw_env->module_count; i++) { ++ for (i = 0; i < mlxsw_env->max_module_count; i++) { + /* 64-127 of sensor_index are mapped to the port modules + * sequentially (module 0 is mapped to sensor_index 64, + * module 1 to sensor_index 65 and so on) +@@ -727,9 +749,10 @@ static void mlxsw_env_mtwe_event_work(struct work_struct *work) + sensor_warning = + mlxsw_reg_mtwe_sensor_warning_get(event->mtwe_pl, + i + MLXSW_REG_MTMP_MODULE_INDEX_MIN); +- mutex_lock(&mlxsw_env->module_info_lock); +- is_overheat = +- mlxsw_env->module_info[i].is_overheat; ++ mutex_lock(&mlxsw_env->line_cards_lock); ++ /* MTWE only supports main board. */ ++ module_info = mlxsw_env_module_info_get(mlxsw_env->core, 0, i); ++ is_overheat = module_info->is_overheat; + + if ((is_overheat && sensor_warning) || + (!is_overheat && !sensor_warning)) { +@@ -737,21 +760,21 @@ static void mlxsw_env_mtwe_event_work(struct work_struct *work) + * warning OR current state in "no warning" and MTWE + * does not report warning. + */ +- mutex_unlock(&mlxsw_env->module_info_lock); ++ mutex_unlock(&mlxsw_env->line_cards_lock); + continue; + } else if (is_overheat && !sensor_warning) { + /* MTWE reports "no warning", turn is_overheat off. + */ +- mlxsw_env->module_info[i].is_overheat = false; +- mutex_unlock(&mlxsw_env->module_info_lock); ++ module_info->is_overheat = false; ++ mutex_unlock(&mlxsw_env->line_cards_lock); + } else { + /* Current state is "no warning" and MTWE reports + * "warning", increase the counter and turn is_overheat + * on. + */ +- mlxsw_env->module_info[i].is_overheat = true; +- mlxsw_env->module_info[i].module_overheat_counter++; +- mutex_unlock(&mlxsw_env->module_info_lock); ++ module_info->is_overheat = true; ++ module_info->module_overheat_counter++; ++ mutex_unlock(&mlxsw_env->line_cards_lock); + } + } + +@@ -809,6 +832,7 @@ struct mlxsw_env_module_plug_unplug_event { + static void mlxsw_env_pmpe_event_work(struct work_struct *work) + { + struct mlxsw_env_module_plug_unplug_event *event; ++ struct mlxsw_env_module_info *module_info; + struct mlxsw_env *mlxsw_env; + bool has_temp_sensor; + u16 sensor_index; +@@ -818,9 +842,12 @@ static void mlxsw_env_pmpe_event_work(struct work_struct *work) + work); + mlxsw_env = event->mlxsw_env; + +- mutex_lock(&mlxsw_env->module_info_lock); +- mlxsw_env->module_info[event->module].is_overheat = false; +- mutex_unlock(&mlxsw_env->module_info_lock); ++ mutex_lock(&mlxsw_env->line_cards_lock); ++ module_info = mlxsw_env_module_info_get(mlxsw_env->core, ++ event->slot_index, ++ event->module); ++ module_info->is_overheat = false; ++ mutex_unlock(&mlxsw_env->line_cards_lock); + + err = mlxsw_env_module_has_temp_sensor(mlxsw_env->core, + event->slot_index, +@@ -847,12 +874,14 @@ static void + mlxsw_env_pmpe_listener_func(const struct mlxsw_reg_info *reg, char *pmpe_pl, + void *priv) + { ++ u8 slot_index = mlxsw_reg_pmpe_slot_index_get(pmpe_pl); + struct mlxsw_env_module_plug_unplug_event *event; + enum mlxsw_reg_pmpe_module_status module_status; + u8 module = mlxsw_reg_pmpe_module_get(pmpe_pl); + struct mlxsw_env *mlxsw_env = priv; + +- if (WARN_ON_ONCE(module >= mlxsw_env->module_count)) ++ if (WARN_ON_ONCE(module >= mlxsw_env->max_module_count || ++ slot_index >= mlxsw_env->num_of_slots)) + return; + + module_status = mlxsw_reg_pmpe_module_status_get(pmpe_pl); +@@ -864,7 +893,7 @@ mlxsw_env_pmpe_listener_func(const struct mlxsw_reg_info *reg, char *pmpe_pl, + return; + + event->mlxsw_env = mlxsw_env; +- event->slot_index = 0; ++ event->slot_index = slot_index; + event->module = module; + INIT_WORK(&event->work, mlxsw_env_pmpe_event_work); + mlxsw_core_schedule_work(&event->work); +@@ -922,10 +951,12 @@ mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 slot_ind + u8 module, u64 *p_counter) + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); ++ struct mlxsw_env_module_info *module_info; + +- mutex_lock(&mlxsw_env->module_info_lock); +- *p_counter = mlxsw_env->module_info[module].module_overheat_counter; +- mutex_unlock(&mlxsw_env->module_info_lock); ++ mutex_lock(&mlxsw_env->line_cards_lock); ++ module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module); ++ *p_counter = module_info->module_overheat_counter; ++ mutex_unlock(&mlxsw_env->line_cards_lock); + + return 0; + } +@@ -935,10 +966,12 @@ void mlxsw_env_module_port_map(struct mlxsw_core *mlxsw_core, u8 slot_index, + u8 module) + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); ++ struct mlxsw_env_module_info *module_info; + +- mutex_lock(&mlxsw_env->module_info_lock); +- mlxsw_env->module_info[module].num_ports_mapped++; +- mutex_unlock(&mlxsw_env->module_info_lock); ++ mutex_lock(&mlxsw_env->line_cards_lock); ++ module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module); ++ module_info->num_ports_mapped++; ++ mutex_unlock(&mlxsw_env->line_cards_lock); + } + EXPORT_SYMBOL(mlxsw_env_module_port_map); + +@@ -946,10 +979,12 @@ void mlxsw_env_module_port_unmap(struct mlxsw_core *mlxsw_core, u8 slot_index, + u8 module) + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); ++ struct mlxsw_env_module_info *module_info; + +- mutex_lock(&mlxsw_env->module_info_lock); +- mlxsw_env->module_info[module].num_ports_mapped--; +- mutex_unlock(&mlxsw_env->module_info_lock); ++ mutex_lock(&mlxsw_env->line_cards_lock); ++ module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module); ++ module_info->num_ports_mapped--; ++ mutex_unlock(&mlxsw_env->line_cards_lock); + } + EXPORT_SYMBOL(mlxsw_env_module_port_unmap); + +@@ -957,15 +992,17 @@ int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 slot_index, + u8 module) + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); ++ struct mlxsw_env_module_info *module_info; + int err = 0; + +- mutex_lock(&mlxsw_env->module_info_lock); ++ mutex_lock(&mlxsw_env->line_cards_lock); + +- if (mlxsw_env->module_info[module].power_mode_policy != ++ module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module); ++ if (module_info->power_mode_policy != + ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO) + goto out_inc; + +- if (mlxsw_env->module_info[module].num_ports_up != 0) ++ if (module_info->num_ports_up != 0) + goto out_inc; + + /* Transition to high power mode following first port using the module +@@ -977,9 +1014,9 @@ int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 slot_index, + goto out_unlock; + + out_inc: +- mlxsw_env->module_info[module].num_ports_up++; ++ module_info->num_ports_up++; + out_unlock: +- mutex_unlock(&mlxsw_env->module_info_lock); ++ mutex_unlock(&mlxsw_env->line_cards_lock); + return err; + } + EXPORT_SYMBOL(mlxsw_env_module_port_up); +@@ -988,16 +1025,18 @@ void mlxsw_env_module_port_down(struct mlxsw_core *mlxsw_core, u8 slot_index, + u8 module) + { + struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core); ++ struct mlxsw_env_module_info *module_info; + +- mutex_lock(&mlxsw_env->module_info_lock); ++ mutex_lock(&mlxsw_env->line_cards_lock); + +- mlxsw_env->module_info[module].num_ports_up--; ++ module_info = mlxsw_env_module_info_get(mlxsw_core, slot_index, module); ++ module_info->num_ports_up--; + +- if (mlxsw_env->module_info[module].power_mode_policy != ++ if (module_info->power_mode_policy != + ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO) + goto out_unlock; + +- if (mlxsw_env->module_info[module].num_ports_up != 0) ++ if (module_info->num_ports_up != 0) + goto out_unlock; + + /* Transition to low power mode following last port using the module +@@ -1007,38 +1046,83 @@ void mlxsw_env_module_port_down(struct mlxsw_core *mlxsw_core, u8 slot_index, + NULL); + + out_unlock: +- mutex_unlock(&mlxsw_env->module_info_lock); ++ mutex_unlock(&mlxsw_env->line_cards_lock); + } + EXPORT_SYMBOL(mlxsw_env_module_port_down); + ++static int mlxsw_env_line_cards_alloc(struct mlxsw_env *env) ++{ ++ struct mlxsw_env_module_info *module_info; ++ int i, j; ++ ++ for (i = 0; i < env->num_of_slots; i++) { ++ env->line_cards[i] = kzalloc(struct_size(env->line_cards[i], ++ module_info, ++ env->max_module_count), ++ GFP_KERNEL); ++ if (!env->line_cards[i]) ++ goto kzalloc_err; ++ ++ /* Firmware defaults to high power mode policy where modules ++ * are transitioned to high power mode following plug-in. ++ */ ++ for (j = 0; j < env->max_module_count; j++) { ++ module_info = &env->line_cards[i]->module_info[j]; ++ module_info->power_mode_policy = ++ ETHTOOL_MODULE_POWER_MODE_POLICY_HIGH; ++ } ++ } ++ ++ return 0; ++ ++kzalloc_err: ++ for (i--; i >= 0; i--) ++ kfree(env->line_cards[i]); ++ return -ENOMEM; ++} ++ ++static void mlxsw_env_line_cards_free(struct mlxsw_env *env) ++{ ++ int i = env->num_of_slots; ++ ++ for (i--; i >= 0; i--) ++ kfree(env->line_cards[i]); ++} ++ + int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env) + { ++ u8 module_count, num_of_slots, max_module_count; + char mgpir_pl[MLXSW_REG_MGPIR_LEN]; + struct mlxsw_env *env; +- u8 module_count; +- int i, err; ++ int err; + + mlxsw_reg_mgpir_pack(mgpir_pl, 0); + err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mgpir), mgpir_pl); + if (err) + return err; + +- mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, &module_count, NULL); ++ mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, &module_count, ++ &num_of_slots); ++ /* If the system is modular, get the maximum number of modules per-slot. ++ * Otherwise, get the maximum number of modules on the main board. ++ */ ++ max_module_count = num_of_slots ? ++ mlxsw_reg_mgpir_max_modules_per_slot_get(mgpir_pl) : ++ module_count; + +- env = kzalloc(struct_size(env, module_info, module_count), GFP_KERNEL); ++ env = kzalloc(struct_size(env, line_cards, num_of_slots + 1), ++ GFP_KERNEL); + if (!env) + return -ENOMEM; + +- /* Firmware defaults to high power mode policy where modules are +- * transitioned to high power mode following plug-in. +- */ +- for (i = 0; i < module_count; i++) +- env->module_info[i].power_mode_policy = +- ETHTOOL_MODULE_POWER_MODE_POLICY_HIGH; +- +- mutex_init(&env->module_info_lock); + env->core = mlxsw_core; +- env->module_count = module_count; ++ env->num_of_slots = num_of_slots + 1; ++ env->max_module_count = max_module_count; ++ err = mlxsw_env_line_cards_alloc(env); ++ if (err) ++ goto err_mlxsw_env_line_cards_alloc; ++ ++ mutex_init(&env->line_cards_lock); + *p_env = env; + + err = mlxsw_env_temp_warn_event_register(mlxsw_core); +@@ -1049,13 +1133,17 @@ int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env) + if (err) + goto err_module_plug_event_register; + ++ /* Set 'module_count' only for main board. Actual count for line card ++ * is to be set after line card is activated. ++ */ ++ env->line_cards[0]->module_count = num_of_slots ? 0 : module_count; + err = mlxsw_env_module_oper_state_event_enable(mlxsw_core, 0, +- env->module_count); ++ module_count); + if (err) + goto err_oper_state_event_enable; + + err = mlxsw_env_module_temp_event_enable(mlxsw_core, 0, +- env->module_count); ++ module_count); + if (err) + goto err_temp_event_enable; + +@@ -1067,7 +1155,9 @@ int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env) + err_module_plug_event_register: + mlxsw_env_temp_warn_event_unregister(env); + err_temp_warn_event_register: +- mutex_destroy(&env->module_info_lock); ++ mutex_destroy(&env->line_cards_lock); ++ mlxsw_env_line_cards_free(env); ++err_mlxsw_env_line_cards_alloc: + kfree(env); + return err; + } +@@ -1078,6 +1168,7 @@ void mlxsw_env_fini(struct mlxsw_env *env) + /* Make sure there is no more event work scheduled. */ + mlxsw_core_flush_owq(); + mlxsw_env_temp_warn_event_unregister(env); +- mutex_destroy(&env->module_info_lock); ++ mutex_destroy(&env->line_cards_lock); ++ mlxsw_env_line_cards_free(env); + kfree(env); + } +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0114-mlxsw-core-Move-port-module-events-enablement-to-a-s.patch b/platform/mellanox/non-upstream-patches/patches/0114-mlxsw-core-Move-port-module-events-enablement-to-a-s.patch new file mode 100644 index 000000000000..77ebf2610814 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0114-mlxsw-core-Move-port-module-events-enablement-to-a-s.patch @@ -0,0 +1,92 @@ +From 9eb9b3172a238d5818d2925e2db6b0f686b31411 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Tue, 14 Dec 2021 10:57:28 +0200 +Subject: [PATCH] mlxsw: core: Move port module events enablement to a separate + function + +Use a separate function for enablement of port module events such +plug/unplug and temperature threshold crossing. The motivation is to +reuse the function for line cards. + +Signed-off-by: Vadim Pasternak +Signed-off-by: Ido Schimmel +--- + .../net/ethernet/mellanox/mlxsw/core_env.c | 44 ++++++++++++++----- + 1 file changed, 34 insertions(+), 10 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +index 2a6630547..94d44db1a 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +@@ -1089,6 +1089,32 @@ static void mlxsw_env_line_cards_free(struct mlxsw_env *env) + kfree(env->line_cards[i]); + } + ++static int ++mlxsw_env_module_event_enable(struct mlxsw_env *mlxsw_env, u8 slot_index) ++{ ++ u8 module_count; ++ int err; ++ ++ module_count = mlxsw_env->line_cards[slot_index]->module_count; ++ err = mlxsw_env_module_oper_state_event_enable(mlxsw_env->core, ++ slot_index, ++ module_count); ++ if (err) ++ return err; ++ ++ err = mlxsw_env_module_temp_event_enable(mlxsw_env->core, slot_index, ++ module_count); ++ if (err) ++ return err; ++ ++ return 0; ++} ++ ++static void ++mlxsw_env_module_event_disable(struct mlxsw_env *mlxsw_env, u8 slot_index) ++{ ++} ++ + int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env) + { + u8 module_count, num_of_slots, max_module_count; +@@ -1137,20 +1163,17 @@ int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env) + * is to be set after line card is activated. + */ + env->line_cards[0]->module_count = num_of_slots ? 0 : module_count; +- err = mlxsw_env_module_oper_state_event_enable(mlxsw_core, 0, +- module_count); +- if (err) +- goto err_oper_state_event_enable; +- +- err = mlxsw_env_module_temp_event_enable(mlxsw_core, 0, +- module_count); ++ /* Enable events only for main board. Line card events are to be ++ * configured only after line card is activated. Before that, access to ++ * modules on line cards is not allowed. ++ */ ++ err = mlxsw_env_module_event_enable(env, 0); + if (err) +- goto err_temp_event_enable; ++ goto err_mlxsw_env_module_event_enable; + + return 0; + +-err_temp_event_enable: +-err_oper_state_event_enable: ++err_mlxsw_env_module_event_enable: + mlxsw_env_module_plug_event_unregister(env); + err_module_plug_event_register: + mlxsw_env_temp_warn_event_unregister(env); +@@ -1164,6 +1187,7 @@ int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env) + + void mlxsw_env_fini(struct mlxsw_env *env) + { ++ mlxsw_env_module_event_disable(env, 0); + mlxsw_env_module_plug_event_unregister(env); + /* Make sure there is no more event work scheduled. */ + mlxsw_core_flush_owq(); +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0115-mlxsw-core_hwmon-Split-gearbox-initialization.patch b/platform/mellanox/non-upstream-patches/patches/0115-mlxsw-core_hwmon-Split-gearbox-initialization.patch new file mode 100644 index 000000000000..1365785ff9db --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0115-mlxsw-core_hwmon-Split-gearbox-initialization.patch @@ -0,0 +1,121 @@ +From 4d15dd7f69b89a370731b08cb3f13e5dd591c189 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Tue, 14 Dec 2021 10:57:29 +0200 +Subject: [PATCH] mlxsw: core_hwmon: Split gearbox initialization + +Split gearbox initialization in two functions - the first one is to be +used for gearbox configuration validation, the second for creation of +gearbox related hwmon attributes, if any. + +Currently, mlxsw supports gearbox hwmon attributes corresponding to the +objects discovered on the main board. Same hwmon attributes could be +also discovered on line cards. While the initialization flow for main +board and for line cards is the same, the configuration flow is +different. + +The purpose of this patch is to allow reusing of initialization flow by +main board and line cards. + +Signed-off-by: Vadim Pasternak +Reviewed-by: Jiri Pirko +Signed-off-by: Ido Schimmel +--- + .../net/ethernet/mellanox/mlxsw/core_hwmon.c | 43 ++++++++++++++----- + 1 file changed, 33 insertions(+), 10 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +index 5df54a5bf..7061c18b7 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +@@ -700,13 +700,11 @@ static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon) + return 0; + } + +-static int mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon) ++static int ++mlxsw_hwmon_gearbox_main_init(struct mlxsw_hwmon *mlxsw_hwmon, u8 *gbox_num) + { + enum mlxsw_reg_mgpir_device_type device_type; +- int index, max_index, sensor_index; + char mgpir_pl[MLXSW_REG_MGPIR_LEN]; +- char mtmp_pl[MLXSW_REG_MTMP_LEN]; +- u8 gbox_num; + int err; + + mlxsw_reg_mgpir_pack(mgpir_pl, 0); +@@ -714,10 +712,27 @@ static int mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon) + if (err) + return err; + +- mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, &device_type, NULL, NULL, ++ mlxsw_reg_mgpir_unpack(mgpir_pl, gbox_num, &device_type, NULL, NULL, + NULL); +- if (device_type != MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE || +- !gbox_num) ++ if (device_type != MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE) ++ *gbox_num = 0; ++ ++ return 0; ++} ++ ++static void ++mlxsw_hwmon_gearbox_main_fini(struct mlxsw_hwmon *mlxsw_hwmon) ++{ ++} ++ ++static int ++mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon, u8 gbox_num) ++{ ++ int index, max_index, sensor_index; ++ char mtmp_pl[MLXSW_REG_MTMP_LEN]; ++ int err; ++ ++ if (!gbox_num) + return 0; + + index = mlxsw_hwmon->module_sensor_max; +@@ -756,6 +771,7 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core, + { + struct mlxsw_hwmon *mlxsw_hwmon; + struct device *hwmon_dev; ++ u8 gbox_num; + int err; + + mlxsw_hwmon = kzalloc(sizeof(*mlxsw_hwmon), GFP_KERNEL); +@@ -776,9 +792,13 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core, + if (err) + goto err_temp_module_init; + +- err = mlxsw_hwmon_gearbox_init(mlxsw_hwmon); ++ err = mlxsw_hwmon_gearbox_main_init(mlxsw_hwmon, &gbox_num); ++ if (err) ++ goto err_gearbox_main_init; ++ ++ err = mlxsw_hwmon_gearbox_init(mlxsw_hwmon, gbox_num); + if (err) +- goto err_temp_gearbox_init; ++ goto err_gearbox_init; + + mlxsw_hwmon->groups[0] = &mlxsw_hwmon->group; + mlxsw_hwmon->group.attrs = mlxsw_hwmon->attrs; +@@ -796,7 +816,9 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core, + return 0; + + err_hwmon_register: +-err_temp_gearbox_init: ++err_gearbox_init: ++ mlxsw_hwmon_gearbox_main_fini(mlxsw_hwmon); ++err_gearbox_main_init: + err_temp_module_init: + err_fans_init: + err_temp_init: +@@ -807,5 +829,6 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core, + void mlxsw_hwmon_fini(struct mlxsw_hwmon *mlxsw_hwmon) + { + hwmon_device_unregister(mlxsw_hwmon->hwmon_dev); ++ mlxsw_hwmon_gearbox_main_fini(mlxsw_hwmon); + kfree(mlxsw_hwmon); + } +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0116-mlxsw-core_hwmon-Extend-internal-structures-to-suppo.patch b/platform/mellanox/non-upstream-patches/patches/0116-mlxsw-core_hwmon-Extend-internal-structures-to-suppo.patch new file mode 100644 index 000000000000..2c1eafe70367 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0116-mlxsw-core_hwmon-Extend-internal-structures-to-suppo.patch @@ -0,0 +1,541 @@ +From 9780cd7afe3455d0ee428f5009514780e858c133 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Tue, 14 Dec 2021 10:57:30 +0200 +Subject: [PATCH] mlxsw: core_hwmon: Extend internal structures to support + multi hwmon objects + +Currently, mlxsw supports a single hwmon device and registers it with +attributes corresponding to the various objects found on the main +board such as fans and gearboxes. + +Line cards can have the same objects, but unlike the main board they +can be added and removed while the system is running. The various +hwmon objects found on these line cards should be created when the +line card becomes available and destroyed when the line card becomes +unavailable. + +The above can be achieved by representing each line card as a +different hwmon device and registering / unregistering it when the +line card becomes available / unavailable. + +Prepare for multi hwmon device support by splitting +'struct mlxsw_hwmon' into 'struct mlxsw_hwmon' and +'struct mlxsw_hwmon_dev'. The first will hold information relevant to +all hwmon devices, whereas the second will hold per-hwmon device +information. + +Signed-off-by: Vadim Pasternak +Reviewed-by: Jiri Pirko +Signed-off-by: Ido Schimmel +--- + .../net/ethernet/mellanox/mlxsw/core_hwmon.c | 192 ++++++++++-------- + 1 file changed, 112 insertions(+), 80 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +index 7061c18b7..31b370862 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +@@ -27,7 +27,7 @@ + + struct mlxsw_hwmon_attr { + struct device_attribute dev_attr; +- struct mlxsw_hwmon *hwmon; ++ struct mlxsw_hwmon_dev *mlxsw_hwmon_dev; + unsigned int type_index; + char name[32]; + }; +@@ -40,9 +40,8 @@ static int mlxsw_hwmon_get_attr_index(int index, int count) + return index; + } + +-struct mlxsw_hwmon { +- struct mlxsw_core *core; +- const struct mlxsw_bus_info *bus_info; ++struct mlxsw_hwmon_dev { ++ struct mlxsw_hwmon *hwmon; + struct device *hwmon_dev; + struct attribute_group group; + const struct attribute_group *groups[2]; +@@ -53,19 +52,26 @@ struct mlxsw_hwmon { + u8 module_sensor_max; + }; + ++struct mlxsw_hwmon { ++ struct mlxsw_core *core; ++ const struct mlxsw_bus_info *bus_info; ++ struct mlxsw_hwmon_dev *main; ++}; ++ + static ssize_t mlxsw_hwmon_temp_show(struct device *dev, + struct device_attribute *attr, + char *buf) + { + struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; + char mtmp_pl[MLXSW_REG_MTMP_LEN]; + int temp, index; + int err; + + index = mlxsw_hwmon_get_attr_index(mlxsw_hwmon_attr->type_index, +- mlxsw_hwmon->module_sensor_max); ++ mlxsw_hwmon_dev->module_sensor_max); + mlxsw_reg_mtmp_pack(mtmp_pl, 0, index, false, false); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); + if (err) { +@@ -82,13 +88,14 @@ static ssize_t mlxsw_hwmon_temp_max_show(struct device *dev, + { + struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; + char mtmp_pl[MLXSW_REG_MTMP_LEN]; + int temp_max, index; + int err; + + index = mlxsw_hwmon_get_attr_index(mlxsw_hwmon_attr->type_index, +- mlxsw_hwmon->module_sensor_max); ++ mlxsw_hwmon_dev->module_sensor_max); + mlxsw_reg_mtmp_pack(mtmp_pl, 0, index, false, false); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); + if (err) { +@@ -105,8 +112,9 @@ static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev, + { + struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; +- char mtmp_pl[MLXSW_REG_MTMP_LEN] = {0}; ++ struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; ++ char mtmp_pl[MLXSW_REG_MTMP_LEN]; + unsigned long val; + int index; + int err; +@@ -118,7 +126,7 @@ static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev, + return -EINVAL; + + index = mlxsw_hwmon_get_attr_index(mlxsw_hwmon_attr->type_index, +- mlxsw_hwmon->module_sensor_max); ++ mlxsw_hwmon_dev->module_sensor_max); + + mlxsw_reg_mtmp_sensor_index_set(mtmp_pl, index); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); +@@ -140,7 +148,8 @@ static ssize_t mlxsw_hwmon_fan_rpm_show(struct device *dev, + { + struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; + char mfsm_pl[MLXSW_REG_MFSM_LEN]; + int err; + +@@ -159,7 +168,8 @@ static ssize_t mlxsw_hwmon_fan_fault_show(struct device *dev, + { + struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; + char fore_pl[MLXSW_REG_FORE_LEN]; + bool fault; + int err; +@@ -180,7 +190,8 @@ static ssize_t mlxsw_hwmon_pwm_show(struct device *dev, + { + struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; + char mfsc_pl[MLXSW_REG_MFSC_LEN]; + int err; + +@@ -200,7 +211,8 @@ static ssize_t mlxsw_hwmon_pwm_store(struct device *dev, + { + struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; + char mfsc_pl[MLXSW_REG_MFSC_LEN]; + unsigned long val; + int err; +@@ -226,12 +238,13 @@ static int mlxsw_hwmon_module_temp_get(struct device *dev, + { + struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; + char mtmp_pl[MLXSW_REG_MTMP_LEN]; + u8 module; + int err; + +- module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; ++ module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon_dev->sensor_count; + mlxsw_reg_mtmp_pack(mtmp_pl, 0, + MLXSW_REG_MTMP_MODULE_INDEX_MIN + module, false, + false); +@@ -264,15 +277,16 @@ static ssize_t mlxsw_hwmon_module_temp_fault_show(struct device *dev, + { + struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; + char mtbr_pl[MLXSW_REG_MTBR_LEN] = {0}; + u8 module, fault; + u16 temp; + int err; + +- module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; +- mlxsw_reg_mtbr_pack(mtbr_pl, 0, +- MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, 1); ++ module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon_dev->sensor_count; ++ mlxsw_reg_mtbr_pack(mtbr_pl, 0, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, ++ 1); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtbr), mtbr_pl); + if (err) { + dev_err(dev, "Failed to query module temperature sensor\n"); +@@ -306,11 +320,12 @@ static int mlxsw_hwmon_module_temp_critical_get(struct device *dev, + { + struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; + u8 module; + int err; + +- module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; ++ module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon_dev->sensor_count; + err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, 0, + module, SFP_TEMP_HIGH_WARN, + p_temp); +@@ -341,11 +356,12 @@ static int mlxsw_hwmon_module_temp_emergency_get(struct device *dev, + { + struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev; ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; + u8 module; + int err; + +- module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon->sensor_count; ++ module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon_dev->sensor_count; + err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, 0, + module, SFP_TEMP_HIGH_ALARM, + p_temp); +@@ -390,9 +406,9 @@ mlxsw_hwmon_gbox_temp_label_show(struct device *dev, + { + struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); +- struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_attr->hwmon; ++ struct mlxsw_hwmon_dev *mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev; + int index = mlxsw_hwmon_attr->type_index - +- mlxsw_hwmon->module_sensor_max + 1; ++ mlxsw_hwmon_dev->module_sensor_max + 1; + + return sprintf(buf, "gearbox %03u\n", index); + } +@@ -461,14 +477,15 @@ enum mlxsw_hwmon_attr_type { + MLXSW_HWMON_ATTR_TYPE_TEMP_EMERGENCY_ALARM, + }; + +-static void mlxsw_hwmon_attr_add(struct mlxsw_hwmon *mlxsw_hwmon, ++static void mlxsw_hwmon_attr_add(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev, + enum mlxsw_hwmon_attr_type attr_type, +- unsigned int type_index, unsigned int num) { ++ unsigned int type_index, unsigned int num) ++{ + struct mlxsw_hwmon_attr *mlxsw_hwmon_attr; + unsigned int attr_index; + +- attr_index = mlxsw_hwmon->attrs_count; +- mlxsw_hwmon_attr = &mlxsw_hwmon->hwmon_attrs[attr_index]; ++ attr_index = mlxsw_hwmon_dev->attrs_count; ++ mlxsw_hwmon_attr = &mlxsw_hwmon_dev->hwmon_attrs[attr_index]; + + switch (attr_type) { + case MLXSW_HWMON_ATTR_TYPE_TEMP: +@@ -568,16 +585,17 @@ static void mlxsw_hwmon_attr_add(struct mlxsw_hwmon *mlxsw_hwmon, + } + + mlxsw_hwmon_attr->type_index = type_index; +- mlxsw_hwmon_attr->hwmon = mlxsw_hwmon; ++ mlxsw_hwmon_attr->mlxsw_hwmon_dev = mlxsw_hwmon_dev; + mlxsw_hwmon_attr->dev_attr.attr.name = mlxsw_hwmon_attr->name; + sysfs_attr_init(&mlxsw_hwmon_attr->dev_attr.attr); + +- mlxsw_hwmon->attrs[attr_index] = &mlxsw_hwmon_attr->dev_attr.attr; +- mlxsw_hwmon->attrs_count++; ++ mlxsw_hwmon_dev->attrs[attr_index] = &mlxsw_hwmon_attr->dev_attr.attr; ++ mlxsw_hwmon_dev->attrs_count++; + } + +-static int mlxsw_hwmon_temp_init(struct mlxsw_hwmon *mlxsw_hwmon) ++static int mlxsw_hwmon_temp_init(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev) + { ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; + char mtcap_pl[MLXSW_REG_MTCAP_LEN] = {0}; + int i; + int err; +@@ -587,8 +605,8 @@ static int mlxsw_hwmon_temp_init(struct mlxsw_hwmon *mlxsw_hwmon) + dev_err(mlxsw_hwmon->bus_info->dev, "Failed to get number of temp sensors\n"); + return err; + } +- mlxsw_hwmon->sensor_count = mlxsw_reg_mtcap_sensor_count_get(mtcap_pl); +- for (i = 0; i < mlxsw_hwmon->sensor_count; i++) { ++ mlxsw_hwmon_dev->sensor_count = mlxsw_reg_mtcap_sensor_count_get(mtcap_pl); ++ for (i = 0; i < mlxsw_hwmon_dev->sensor_count; i++) { + char mtmp_pl[MLXSW_REG_MTMP_LEN] = {0}; + + mlxsw_reg_mtmp_sensor_index_set(mtmp_pl, i); +@@ -605,18 +623,19 @@ static int mlxsw_hwmon_temp_init(struct mlxsw_hwmon *mlxsw_hwmon) + i); + return err; + } +- mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ mlxsw_hwmon_attr_add(mlxsw_hwmon_dev, + MLXSW_HWMON_ATTR_TYPE_TEMP, i, i); +- mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ mlxsw_hwmon_attr_add(mlxsw_hwmon_dev, + MLXSW_HWMON_ATTR_TYPE_TEMP_MAX, i, i); +- mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ mlxsw_hwmon_attr_add(mlxsw_hwmon_dev, + MLXSW_HWMON_ATTR_TYPE_TEMP_RST, i, i); + } + return 0; + } + +-static int mlxsw_hwmon_fans_init(struct mlxsw_hwmon *mlxsw_hwmon) ++static int mlxsw_hwmon_fans_init(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev) + { ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; + char mfcr_pl[MLXSW_REG_MFCR_LEN] = {0}; + enum mlxsw_reg_mfcr_pwm_frequency freq; + unsigned int type_index; +@@ -634,10 +653,10 @@ static int mlxsw_hwmon_fans_init(struct mlxsw_hwmon *mlxsw_hwmon) + num = 0; + for (type_index = 0; type_index < MLXSW_MFCR_TACHOS_MAX; type_index++) { + if (tacho_active & BIT(type_index)) { +- mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ mlxsw_hwmon_attr_add(mlxsw_hwmon_dev, + MLXSW_HWMON_ATTR_TYPE_FAN_RPM, + type_index, num); +- mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ mlxsw_hwmon_attr_add(mlxsw_hwmon_dev, + MLXSW_HWMON_ATTR_TYPE_FAN_FAULT, + type_index, num++); + } +@@ -645,15 +664,16 @@ static int mlxsw_hwmon_fans_init(struct mlxsw_hwmon *mlxsw_hwmon) + num = 0; + for (type_index = 0; type_index < MLXSW_MFCR_PWMS_MAX; type_index++) { + if (pwm_active & BIT(type_index)) +- mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ mlxsw_hwmon_attr_add(mlxsw_hwmon_dev, + MLXSW_HWMON_ATTR_TYPE_PWM, + type_index, num++); + } + return 0; + } + +-static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon) ++static int mlxsw_hwmon_module_init(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev) + { ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; + char mgpir_pl[MLXSW_REG_MGPIR_LEN]; + u8 module_sensor_max; + int i, err; +@@ -671,28 +691,28 @@ static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon) + * sensor_count are already utilized by the sensors connected through + * mtmp register by mlxsw_hwmon_temp_init(). + */ +- mlxsw_hwmon->module_sensor_max = mlxsw_hwmon->sensor_count + +- module_sensor_max; +- for (i = mlxsw_hwmon->sensor_count; +- i < mlxsw_hwmon->module_sensor_max; i++) { +- mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ mlxsw_hwmon_dev->module_sensor_max = mlxsw_hwmon_dev->sensor_count + ++ module_sensor_max; ++ for (i = mlxsw_hwmon_dev->sensor_count; ++ i < mlxsw_hwmon_dev->module_sensor_max; i++) { ++ mlxsw_hwmon_attr_add(mlxsw_hwmon_dev, + MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE, i, i); +- mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ mlxsw_hwmon_attr_add(mlxsw_hwmon_dev, + MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_FAULT, + i, i); +- mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ mlxsw_hwmon_attr_add(mlxsw_hwmon_dev, + MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_CRIT, i, + i); +- mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ mlxsw_hwmon_attr_add(mlxsw_hwmon_dev, + MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_EMERG, + i, i); +- mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ mlxsw_hwmon_attr_add(mlxsw_hwmon_dev, + MLXSW_HWMON_ATTR_TYPE_TEMP_MODULE_LABEL, + i, i); +- mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ mlxsw_hwmon_attr_add(mlxsw_hwmon_dev, + MLXSW_HWMON_ATTR_TYPE_TEMP_CRIT_ALARM, + i, i); +- mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ mlxsw_hwmon_attr_add(mlxsw_hwmon_dev, + MLXSW_HWMON_ATTR_TYPE_TEMP_EMERGENCY_ALARM, + i, i); + } +@@ -701,8 +721,10 @@ static int mlxsw_hwmon_module_init(struct mlxsw_hwmon *mlxsw_hwmon) + } + + static int +-mlxsw_hwmon_gearbox_main_init(struct mlxsw_hwmon *mlxsw_hwmon, u8 *gbox_num) ++mlxsw_hwmon_gearbox_main_init(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev, ++ u8 *gbox_num) + { ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; + enum mlxsw_reg_mgpir_device_type device_type; + char mgpir_pl[MLXSW_REG_MGPIR_LEN]; + int err; +@@ -721,13 +743,14 @@ mlxsw_hwmon_gearbox_main_init(struct mlxsw_hwmon *mlxsw_hwmon, u8 *gbox_num) + } + + static void +-mlxsw_hwmon_gearbox_main_fini(struct mlxsw_hwmon *mlxsw_hwmon) ++mlxsw_hwmon_gearbox_main_fini(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev) + { + } + + static int +-mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon, u8 gbox_num) ++mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev, u8 gbox_num) + { ++ struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; + int index, max_index, sensor_index; + char mtmp_pl[MLXSW_REG_MTMP_LEN]; + int err; +@@ -735,10 +758,10 @@ mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon, u8 gbox_num) + if (!gbox_num) + return 0; + +- index = mlxsw_hwmon->module_sensor_max; +- max_index = mlxsw_hwmon->module_sensor_max + gbox_num; ++ index = mlxsw_hwmon_dev->module_sensor_max; ++ max_index = mlxsw_hwmon_dev->module_sensor_max + gbox_num; + while (index < max_index) { +- sensor_index = index % mlxsw_hwmon->module_sensor_max + ++ sensor_index = index % mlxsw_hwmon_dev->module_sensor_max + + MLXSW_REG_MTMP_GBOX_INDEX_MIN; + mlxsw_reg_mtmp_pack(mtmp_pl, 0, sensor_index, true, true); + err = mlxsw_reg_write(mlxsw_hwmon->core, +@@ -748,15 +771,15 @@ mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon *mlxsw_hwmon, u8 gbox_num) + sensor_index); + return err; + } +- mlxsw_hwmon_attr_add(mlxsw_hwmon, MLXSW_HWMON_ATTR_TYPE_TEMP, +- index, index); +- mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ mlxsw_hwmon_attr_add(mlxsw_hwmon_dev, ++ MLXSW_HWMON_ATTR_TYPE_TEMP, index, index); ++ mlxsw_hwmon_attr_add(mlxsw_hwmon_dev, + MLXSW_HWMON_ATTR_TYPE_TEMP_MAX, index, + index); +- mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ mlxsw_hwmon_attr_add(mlxsw_hwmon_dev, + MLXSW_HWMON_ATTR_TYPE_TEMP_RST, index, + index); +- mlxsw_hwmon_attr_add(mlxsw_hwmon, ++ mlxsw_hwmon_attr_add(mlxsw_hwmon_dev, + MLXSW_HWMON_ATTR_TYPE_TEMP_GBOX_LABEL, + index, index); + index++; +@@ -777,58 +800,67 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core, + mlxsw_hwmon = kzalloc(sizeof(*mlxsw_hwmon), GFP_KERNEL); + if (!mlxsw_hwmon) + return -ENOMEM; ++ mlxsw_hwmon->main = kzalloc(sizeof(*mlxsw_hwmon->main), GFP_KERNEL); ++ if (!mlxsw_hwmon->main) { ++ err = -ENOMEM; ++ goto err_hwmon_main_init; ++ } + mlxsw_hwmon->core = mlxsw_core; + mlxsw_hwmon->bus_info = mlxsw_bus_info; ++ mlxsw_hwmon->main->hwmon = mlxsw_hwmon; + +- err = mlxsw_hwmon_temp_init(mlxsw_hwmon); ++ err = mlxsw_hwmon_temp_init(mlxsw_hwmon->main); + if (err) + goto err_temp_init; + +- err = mlxsw_hwmon_fans_init(mlxsw_hwmon); ++ err = mlxsw_hwmon_fans_init(mlxsw_hwmon->main); + if (err) + goto err_fans_init; + +- err = mlxsw_hwmon_module_init(mlxsw_hwmon); ++ err = mlxsw_hwmon_module_init(mlxsw_hwmon->main); + if (err) + goto err_temp_module_init; + +- err = mlxsw_hwmon_gearbox_main_init(mlxsw_hwmon, &gbox_num); ++ err = mlxsw_hwmon_gearbox_main_init(mlxsw_hwmon->main, &gbox_num); + if (err) + goto err_gearbox_main_init; + +- err = mlxsw_hwmon_gearbox_init(mlxsw_hwmon, gbox_num); ++ err = mlxsw_hwmon_gearbox_init(mlxsw_hwmon->main, gbox_num); + if (err) + goto err_gearbox_init; + +- mlxsw_hwmon->groups[0] = &mlxsw_hwmon->group; +- mlxsw_hwmon->group.attrs = mlxsw_hwmon->attrs; ++ mlxsw_hwmon->main->groups[0] = &mlxsw_hwmon->main->group; ++ mlxsw_hwmon->main->group.attrs = mlxsw_hwmon->main->attrs; + + hwmon_dev = hwmon_device_register_with_groups(mlxsw_bus_info->dev, +- "mlxsw", mlxsw_hwmon, +- mlxsw_hwmon->groups); ++ "mlxsw", mlxsw_hwmon->main, ++ mlxsw_hwmon->main->groups); + if (IS_ERR(hwmon_dev)) { + err = PTR_ERR(hwmon_dev); + goto err_hwmon_register; + } + +- mlxsw_hwmon->hwmon_dev = hwmon_dev; ++ mlxsw_hwmon->main->hwmon_dev = hwmon_dev; + *p_hwmon = mlxsw_hwmon; + return 0; + + err_hwmon_register: + err_gearbox_init: +- mlxsw_hwmon_gearbox_main_fini(mlxsw_hwmon); ++ mlxsw_hwmon_gearbox_main_fini(mlxsw_hwmon->main); + err_gearbox_main_init: + err_temp_module_init: + err_fans_init: + err_temp_init: ++ kfree(mlxsw_hwmon->main); ++err_hwmon_main_init: + kfree(mlxsw_hwmon); + return err; + } + + void mlxsw_hwmon_fini(struct mlxsw_hwmon *mlxsw_hwmon) + { +- hwmon_device_unregister(mlxsw_hwmon->hwmon_dev); +- mlxsw_hwmon_gearbox_main_fini(mlxsw_hwmon); ++ hwmon_device_unregister(mlxsw_hwmon->main->hwmon_dev); ++ mlxsw_hwmon_gearbox_main_fini(mlxsw_hwmon->main); ++ kfree(mlxsw_hwmon->main); + kfree(mlxsw_hwmon); + } +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0117-mlxsw-core_hwmon-Introduce-slot-parameter-in-hwmon-i.patch b/platform/mellanox/non-upstream-patches/patches/0117-mlxsw-core_hwmon-Introduce-slot-parameter-in-hwmon-i.patch new file mode 100644 index 000000000000..43208f6d2c3a --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0117-mlxsw-core_hwmon-Introduce-slot-parameter-in-hwmon-i.patch @@ -0,0 +1,129 @@ +From aa8cdb2df37cbfb7bb37f90879d385428e32ae23 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Tue, 14 Dec 2021 10:57:31 +0200 +Subject: [PATCH] mlxsw: core_hwmon: Introduce slot parameter in hwmon + interfaces + +Add 'slot' parameter to 'mlxsw_hwmon_dev' structure. Use this parameter +in mlxsw_reg_mtmp_pack(), mlxsw_reg_mtbr_pack() and +Use mlxsw_reg_mtmp_slot_index_set() routines. +For main board it'll always be zero, for line cards it'll be set to +the physical slot number in modular systems. + +Signed-off-by: Vadim Pasternak +Reviewed-by: Jiri Pirko +Signed-off-by: Ido Schimmel +--- + .../net/ethernet/mellanox/mlxsw/core_hwmon.c | 26 +++++++++++++------ + 1 file changed, 18 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +index 31b370862..0d7edabf1 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +@@ -50,6 +50,7 @@ struct mlxsw_hwmon_dev { + unsigned int attrs_count; + u8 sensor_count; + u8 module_sensor_max; ++ u8 slot_index; + }; + + struct mlxsw_hwmon { +@@ -72,7 +73,8 @@ static ssize_t mlxsw_hwmon_temp_show(struct device *dev, + + index = mlxsw_hwmon_get_attr_index(mlxsw_hwmon_attr->type_index, + mlxsw_hwmon_dev->module_sensor_max); +- mlxsw_reg_mtmp_pack(mtmp_pl, 0, index, false, false); ++ mlxsw_reg_mtmp_pack(mtmp_pl, mlxsw_hwmon_dev->slot_index, index, false, ++ false); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); + if (err) { + dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query temp sensor\n"); +@@ -96,7 +98,8 @@ static ssize_t mlxsw_hwmon_temp_max_show(struct device *dev, + + index = mlxsw_hwmon_get_attr_index(mlxsw_hwmon_attr->type_index, + mlxsw_hwmon_dev->module_sensor_max); +- mlxsw_reg_mtmp_pack(mtmp_pl, 0, index, false, false); ++ mlxsw_reg_mtmp_pack(mtmp_pl, mlxsw_hwmon_dev->slot_index, index, false, ++ false); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); + if (err) { + dev_err(mlxsw_hwmon->bus_info->dev, "Failed to query temp sensor\n"); +@@ -128,6 +131,7 @@ static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev, + index = mlxsw_hwmon_get_attr_index(mlxsw_hwmon_attr->type_index, + mlxsw_hwmon_dev->module_sensor_max); + ++ mlxsw_reg_mtmp_slot_index_set(mtmp_pl, mlxsw_hwmon_dev->slot_index); + mlxsw_reg_mtmp_sensor_index_set(mtmp_pl, index); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); + if (err) +@@ -245,7 +249,7 @@ static int mlxsw_hwmon_module_temp_get(struct device *dev, + int err; + + module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon_dev->sensor_count; +- mlxsw_reg_mtmp_pack(mtmp_pl, 0, ++ mlxsw_reg_mtmp_pack(mtmp_pl, mlxsw_hwmon_dev->slot_index, + MLXSW_REG_MTMP_MODULE_INDEX_MIN + module, false, + false); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); +@@ -285,8 +289,8 @@ static ssize_t mlxsw_hwmon_module_temp_fault_show(struct device *dev, + int err; + + module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon_dev->sensor_count; +- mlxsw_reg_mtbr_pack(mtbr_pl, 0, MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, +- 1); ++ mlxsw_reg_mtbr_pack(mtbr_pl, mlxsw_hwmon_dev->slot_index, ++ MLXSW_REG_MTBR_BASE_MODULE_INDEX + module, 1); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtbr), mtbr_pl); + if (err) { + dev_err(dev, "Failed to query module temperature sensor\n"); +@@ -326,7 +330,8 @@ static int mlxsw_hwmon_module_temp_critical_get(struct device *dev, + int err; + + module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon_dev->sensor_count; +- err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, 0, ++ err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, ++ mlxsw_hwmon_dev->slot_index, + module, SFP_TEMP_HIGH_WARN, + p_temp); + if (err) { +@@ -362,7 +367,8 @@ static int mlxsw_hwmon_module_temp_emergency_get(struct device *dev, + int err; + + module = mlxsw_hwmon_attr->type_index - mlxsw_hwmon_dev->sensor_count; +- err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, 0, ++ err = mlxsw_env_module_temp_thresholds_get(mlxsw_hwmon->core, ++ mlxsw_hwmon_dev->slot_index, + module, SFP_TEMP_HIGH_ALARM, + p_temp); + if (err) { +@@ -609,6 +615,8 @@ static int mlxsw_hwmon_temp_init(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev) + for (i = 0; i < mlxsw_hwmon_dev->sensor_count; i++) { + char mtmp_pl[MLXSW_REG_MTMP_LEN] = {0}; + ++ mlxsw_reg_mtmp_slot_index_set(mtmp_pl, ++ mlxsw_hwmon_dev->slot_index); + mlxsw_reg_mtmp_sensor_index_set(mtmp_pl, i); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), + mtmp_pl); +@@ -763,7 +771,8 @@ mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev, u8 gbox_num) + while (index < max_index) { + sensor_index = index % mlxsw_hwmon_dev->module_sensor_max + + MLXSW_REG_MTMP_GBOX_INDEX_MIN; +- mlxsw_reg_mtmp_pack(mtmp_pl, 0, sensor_index, true, true); ++ mlxsw_reg_mtmp_pack(mtmp_pl, mlxsw_hwmon_dev->slot_index, ++ sensor_index, true, true); + err = mlxsw_reg_write(mlxsw_hwmon->core, + MLXSW_REG(mtmp), mtmp_pl); + if (err) { +@@ -808,6 +817,7 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core, + mlxsw_hwmon->core = mlxsw_core; + mlxsw_hwmon->bus_info = mlxsw_bus_info; + mlxsw_hwmon->main->hwmon = mlxsw_hwmon; ++ mlxsw_hwmon->main->slot_index = 0; + + err = mlxsw_hwmon_temp_init(mlxsw_hwmon->main); + if (err) +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0118-mlxsw-core_hwmon-Extend-hwmon-device-with-gearbox-ma.patch b/platform/mellanox/non-upstream-patches/patches/0118-mlxsw-core_hwmon-Extend-hwmon-device-with-gearbox-ma.patch new file mode 100644 index 000000000000..f88c8721bcbd --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0118-mlxsw-core_hwmon-Extend-hwmon-device-with-gearbox-ma.patch @@ -0,0 +1,136 @@ +From 94d3b63c64fc202bfe525cc3b500c23e92d38fbf Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Tue, 14 Dec 2021 10:57:32 +0200 +Subject: [PATCH] mlxsw: core_hwmon: Extend hwmon device with gearbox mapping + field + +Add gearbox mapping field to 'mlxsw_hwmon_dev' structure. It should +provide the mapping for gearbox sensor indexes, given gearbox number. +For main board mapping is supposed to be always sequential, while for +line cards on modular system it could be non-sequential. + +Signed-off-by: Vadim Pasternak +Reviewed-by: Jiri Pirko +Signed-off-by: Ido Schimmel +--- + .../net/ethernet/mellanox/mlxsw/core_hwmon.c | 40 ++++++++++++++----- + 1 file changed, 31 insertions(+), 9 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +index 0d7edabf1..6af23f472 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +@@ -32,10 +32,11 @@ struct mlxsw_hwmon_attr { + char name[32]; + }; + +-static int mlxsw_hwmon_get_attr_index(int index, int count) ++static int ++mlxsw_hwmon_get_attr_index(int index, int count, u16 *gearbox_sensor_map) + { + if (index >= count) +- return index % count + MLXSW_REG_MTMP_GBOX_INDEX_MIN; ++ return gearbox_sensor_map[index % count]; + + return index; + } +@@ -50,6 +51,7 @@ struct mlxsw_hwmon_dev { + unsigned int attrs_count; + u8 sensor_count; + u8 module_sensor_max; ++ u16 *gearbox_sensor_map; + u8 slot_index; + }; + +@@ -72,7 +74,8 @@ static ssize_t mlxsw_hwmon_temp_show(struct device *dev, + int err; + + index = mlxsw_hwmon_get_attr_index(mlxsw_hwmon_attr->type_index, +- mlxsw_hwmon_dev->module_sensor_max); ++ mlxsw_hwmon_dev->module_sensor_max, ++ mlxsw_hwmon_dev->gearbox_sensor_map); + mlxsw_reg_mtmp_pack(mtmp_pl, mlxsw_hwmon_dev->slot_index, index, false, + false); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); +@@ -97,7 +100,8 @@ static ssize_t mlxsw_hwmon_temp_max_show(struct device *dev, + int err; + + index = mlxsw_hwmon_get_attr_index(mlxsw_hwmon_attr->type_index, +- mlxsw_hwmon_dev->module_sensor_max); ++ mlxsw_hwmon_dev->module_sensor_max, ++ mlxsw_hwmon_dev->gearbox_sensor_map); + mlxsw_reg_mtmp_pack(mtmp_pl, mlxsw_hwmon_dev->slot_index, index, false, + false); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mtmp), mtmp_pl); +@@ -129,7 +133,8 @@ static ssize_t mlxsw_hwmon_temp_rst_store(struct device *dev, + return -EINVAL; + + index = mlxsw_hwmon_get_attr_index(mlxsw_hwmon_attr->type_index, +- mlxsw_hwmon_dev->module_sensor_max); ++ mlxsw_hwmon_dev->module_sensor_max, ++ mlxsw_hwmon_dev->gearbox_sensor_map); + + mlxsw_reg_mtmp_slot_index_set(mtmp_pl, mlxsw_hwmon_dev->slot_index); + mlxsw_reg_mtmp_sensor_index_set(mtmp_pl, index); +@@ -735,7 +740,7 @@ mlxsw_hwmon_gearbox_main_init(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev, + struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; + enum mlxsw_reg_mgpir_device_type device_type; + char mgpir_pl[MLXSW_REG_MGPIR_LEN]; +- int err; ++ int i, err; + + mlxsw_reg_mgpir_pack(mgpir_pl, 0); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mgpir), mgpir_pl); +@@ -747,12 +752,30 @@ mlxsw_hwmon_gearbox_main_init(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev, + if (device_type != MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE) + *gbox_num = 0; + ++ /* Skip gearbox sensor mapping array allocation, if no gearboxes are ++ * available. ++ */ ++ if (!*gbox_num) ++ return 0; ++ ++ mlxsw_hwmon_dev->gearbox_sensor_map = kmalloc_array(*gbox_num, ++ sizeof(u16), ++ GFP_KERNEL); ++ if (!mlxsw_hwmon_dev->gearbox_sensor_map) ++ return -ENOMEM; ++ ++ /* Fill out gearbox sensor mapping array. */ ++ for (i = 0; i < *gbox_num; i++) ++ mlxsw_hwmon_dev->gearbox_sensor_map[i] = ++ MLXSW_REG_MTMP_GBOX_INDEX_MIN + i; ++ + return 0; + } + + static void + mlxsw_hwmon_gearbox_main_fini(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev) + { ++ kfree(mlxsw_hwmon_dev->gearbox_sensor_map); + } + + static int +@@ -761,7 +784,7 @@ mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev, u8 gbox_num) + struct mlxsw_hwmon *mlxsw_hwmon = mlxsw_hwmon_dev->hwmon; + int index, max_index, sensor_index; + char mtmp_pl[MLXSW_REG_MTMP_LEN]; +- int err; ++ int i = 0, err; + + if (!gbox_num) + return 0; +@@ -769,8 +792,7 @@ mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev, u8 gbox_num) + index = mlxsw_hwmon_dev->module_sensor_max; + max_index = mlxsw_hwmon_dev->module_sensor_max + gbox_num; + while (index < max_index) { +- sensor_index = index % mlxsw_hwmon_dev->module_sensor_max + +- MLXSW_REG_MTMP_GBOX_INDEX_MIN; ++ sensor_index = mlxsw_hwmon_dev->gearbox_sensor_map[i++]; + mlxsw_reg_mtmp_pack(mtmp_pl, mlxsw_hwmon_dev->slot_index, + sensor_index, true, true); + err = mlxsw_reg_write(mlxsw_hwmon->core, +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0119-mlxsw-core_thermal-Extend-internal-structures-to-sup.patch b/platform/mellanox/non-upstream-patches/patches/0119-mlxsw-core_thermal-Extend-internal-structures-to-sup.patch new file mode 100644 index 000000000000..cf6199aa186f --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0119-mlxsw-core_thermal-Extend-internal-structures-to-sup.patch @@ -0,0 +1,367 @@ +From ab0f9b9dd1f7326242eee0b0a643d6d34e557ae3 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Tue, 14 Dec 2021 10:57:33 +0200 +Subject: [PATCH] mlxsw: core_thermal: Extend internal structures to support + multi thermal areas + +Introduce intermediate level for thermal zones areas. +Currently all thermal zones are associated with thermal objects located +within the main board. Such objects are created during driver +initialization and removed during driver de-initialization. + +For line cards in modular system the thermal zones are to be associated +with the specific line card. They should be created whenever new line +card is available (inserted, validated, powered and enabled) and +removed, when line card is getting unavailable. +The thermal objects found on the line card #n are accessed by setting +slot index to #n, while for access to objects found on the main board +slot index should be set to default value zero. + +Each thermal area contains the set of thermal zones associated with +particular slot index. +Thus introduction of thermal zone areas allows to use the same APIs for +the main board and line cards, by adding slot index argument. + +Signed-off-by: Vadim Pasternak +Signed-off-by: Ido Schimmel +--- + .../ethernet/mellanox/mlxsw/core_thermal.c | 134 +++++++++++------- + 1 file changed, 83 insertions(+), 51 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +index 3f9062f1c..77a484a55 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +@@ -91,6 +91,15 @@ struct mlxsw_thermal_module { + struct thermal_zone_device *tzdev; + struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS]; + int module; /* Module or gearbox number */ ++ u8 slot_index; ++}; ++ ++struct mlxsw_thermal_area { ++ struct mlxsw_thermal_module *tz_module_arr; ++ u8 tz_module_num; ++ struct mlxsw_thermal_module *tz_gearbox_arr; ++ u8 tz_gearbox_num; ++ u8 slot_index; + }; + + struct mlxsw_thermal { +@@ -101,10 +110,7 @@ struct mlxsw_thermal { + struct thermal_cooling_device *cdevs[MLXSW_MFCR_PWMS_MAX]; + u8 cooling_levels[MLXSW_THERMAL_MAX_STATE + 1]; + struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS]; +- struct mlxsw_thermal_module *tz_module_arr; +- u8 tz_module_num; +- struct mlxsw_thermal_module *tz_gearbox_arr; +- u8 tz_gearbox_num; ++ struct mlxsw_thermal_area *main; + unsigned int tz_highest_score; + struct thermal_zone_device *tz_highest_dev; + }; +@@ -159,13 +165,15 @@ mlxsw_thermal_module_trips_update(struct device *dev, struct mlxsw_core *core, + * EEPROM if we got valid thresholds from MTMP. + */ + if (!emerg_temp || !crit_temp) { +- err = mlxsw_env_module_temp_thresholds_get(core, 0, tz->module, ++ err = mlxsw_env_module_temp_thresholds_get(core, tz->slot_index, ++ tz->module, + SFP_TEMP_HIGH_WARN, + &crit_temp); + if (err) + return err; + +- err = mlxsw_env_module_temp_thresholds_get(core, 0, tz->module, ++ err = mlxsw_env_module_temp_thresholds_get(core, tz->slot_index, ++ tz->module, + SFP_TEMP_HIGH_ALARM, + &emerg_temp); + if (err) +@@ -432,15 +440,16 @@ static int mlxsw_thermal_module_unbind(struct thermal_zone_device *tzdev, + + static void + mlxsw_thermal_module_temp_and_thresholds_get(struct mlxsw_core *core, +- u16 sensor_index, int *p_temp, +- int *p_crit_temp, ++ u8 slot_index, u16 sensor_index, ++ int *p_temp, int *p_crit_temp, + int *p_emerg_temp) + { + char mtmp_pl[MLXSW_REG_MTMP_LEN]; + int err; + + /* Read module temperature and thresholds. */ +- mlxsw_reg_mtmp_pack(mtmp_pl, 0, sensor_index, false, false); ++ mlxsw_reg_mtmp_pack(mtmp_pl, slot_index, sensor_index, ++ false, false); + err = mlxsw_reg_query(core, MLXSW_REG(mtmp), mtmp_pl); + if (err) { + /* Set temperature and thresholds to zero to avoid passing +@@ -471,6 +480,7 @@ static int mlxsw_thermal_module_temp_get(struct thermal_zone_device *tzdev, + + /* Read module temperature and thresholds. */ + mlxsw_thermal_module_temp_and_thresholds_get(thermal->core, ++ tz->slot_index, + sensor_index, &temp, + &crit_temp, &emerg_temp); + *p_temp = temp; +@@ -585,7 +595,7 @@ static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev, + int err; + + index = MLXSW_REG_MTMP_GBOX_INDEX_MIN + tz->module; +- mlxsw_reg_mtmp_pack(mtmp_pl, 0, index, false, false); ++ mlxsw_reg_mtmp_pack(mtmp_pl, tz->slot_index, index, false, false); + + err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl); + if (err) +@@ -745,25 +755,28 @@ static void mlxsw_thermal_module_tz_fini(struct thermal_zone_device *tzdev) + + static int + mlxsw_thermal_module_init(struct device *dev, struct mlxsw_core *core, +- struct mlxsw_thermal *thermal, u8 module) ++ struct mlxsw_thermal *thermal, ++ struct mlxsw_thermal_area *area, u8 module) + { + struct mlxsw_thermal_module *module_tz; + int dummy_temp, crit_temp, emerg_temp; + u16 sensor_index; + + sensor_index = MLXSW_REG_MTMP_MODULE_INDEX_MIN + module; +- module_tz = &thermal->tz_module_arr[module]; ++ module_tz = &area->tz_module_arr[module]; + /* Skip if parent is already set (case of port split). */ + if (module_tz->parent) + return 0; + module_tz->module = module; ++ module_tz->slot_index = area->slot_index; + module_tz->parent = thermal; + memcpy(module_tz->trips, default_thermal_trips, + sizeof(thermal->trips)); + /* Initialize all trip point. */ + mlxsw_thermal_module_trips_reset(module_tz); + /* Read module temperature and thresholds. */ +- mlxsw_thermal_module_temp_and_thresholds_get(core, sensor_index, &dummy_temp, ++ mlxsw_thermal_module_temp_and_thresholds_get(core, area->slot_index, ++ sensor_index, &dummy_temp, + &crit_temp, &emerg_temp); + /* Update trip point according to the module data. */ + return mlxsw_thermal_module_trips_update(dev, core, module_tz, +@@ -781,34 +794,39 @@ static void mlxsw_thermal_module_fini(struct mlxsw_thermal_module *module_tz) + + static int + mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, +- struct mlxsw_thermal *thermal) ++ struct mlxsw_thermal *thermal, ++ struct mlxsw_thermal_area *area) + { + struct mlxsw_thermal_module *module_tz; + char mgpir_pl[MLXSW_REG_MGPIR_LEN]; + int i, err; + +- mlxsw_reg_mgpir_pack(mgpir_pl, 0); ++ mlxsw_reg_mgpir_pack(mgpir_pl, area->slot_index); + err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl); + if (err) + return err; + + mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, +- &thermal->tz_module_num, NULL); ++ &area->tz_module_num, NULL); + +- thermal->tz_module_arr = kcalloc(thermal->tz_module_num, +- sizeof(*thermal->tz_module_arr), +- GFP_KERNEL); +- if (!thermal->tz_module_arr) ++ /* For modular system module counter could be zero. */ ++ if (!area->tz_module_num) ++ return 0; ++ ++ area->tz_module_arr = kcalloc(area->tz_module_num, ++ sizeof(*area->tz_module_arr), ++ GFP_KERNEL); ++ if (!area->tz_module_arr) + return -ENOMEM; + +- for (i = 0; i < thermal->tz_module_num; i++) { +- err = mlxsw_thermal_module_init(dev, core, thermal, i); ++ for (i = 0; i < area->tz_module_num; i++) { ++ err = mlxsw_thermal_module_init(dev, core, thermal, area, i); + if (err) + goto err_thermal_module_init; + } + +- for (i = 0; i < thermal->tz_module_num; i++) { +- module_tz = &thermal->tz_module_arr[i]; ++ for (i = 0; i < area->tz_module_num; i++) { ++ module_tz = &area->tz_module_arr[i]; + if (!module_tz->parent) + continue; + err = mlxsw_thermal_module_tz_init(module_tz); +@@ -820,20 +838,21 @@ mlxsw_thermal_modules_init(struct device *dev, struct mlxsw_core *core, + + err_thermal_module_tz_init: + err_thermal_module_init: +- for (i = thermal->tz_module_num - 1; i >= 0; i--) +- mlxsw_thermal_module_fini(&thermal->tz_module_arr[i]); +- kfree(thermal->tz_module_arr); ++ for (i = area->tz_module_num - 1; i >= 0; i--) ++ mlxsw_thermal_module_fini(&area->tz_module_arr[i]); ++ kfree(area->tz_module_arr); + return err; + } + + static void +-mlxsw_thermal_modules_fini(struct mlxsw_thermal *thermal) ++mlxsw_thermal_modules_fini(struct mlxsw_thermal *thermal, ++ struct mlxsw_thermal_area *area) + { + int i; + +- for (i = thermal->tz_module_num - 1; i >= 0; i--) +- mlxsw_thermal_module_fini(&thermal->tz_module_arr[i]); +- kfree(thermal->tz_module_arr); ++ for (i = area->tz_module_num - 1; i >= 0; i--) ++ mlxsw_thermal_module_fini(&area->tz_module_arr[i]); ++ kfree(area->tz_module_arr); + } + + static int +@@ -869,7 +888,8 @@ mlxsw_thermal_gearbox_tz_fini(struct mlxsw_thermal_module *gearbox_tz) + + static int + mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core, +- struct mlxsw_thermal *thermal) ++ struct mlxsw_thermal *thermal, ++ struct mlxsw_thermal_area *area) + { + enum mlxsw_reg_mgpir_device_type device_type; + struct mlxsw_thermal_module *gearbox_tz; +@@ -889,19 +909,20 @@ mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core, + !gbox_num) + return 0; + +- thermal->tz_gearbox_num = gbox_num; +- thermal->tz_gearbox_arr = kcalloc(thermal->tz_gearbox_num, +- sizeof(*thermal->tz_gearbox_arr), +- GFP_KERNEL); +- if (!thermal->tz_gearbox_arr) ++ area->tz_gearbox_num = gbox_num; ++ area->tz_gearbox_arr = kcalloc(area->tz_gearbox_num, ++ sizeof(*area->tz_gearbox_arr), ++ GFP_KERNEL); ++ if (!area->tz_gearbox_arr) + return -ENOMEM; + +- for (i = 0; i < thermal->tz_gearbox_num; i++) { +- gearbox_tz = &thermal->tz_gearbox_arr[i]; ++ for (i = 0; i < area->tz_gearbox_num; i++) { ++ gearbox_tz = &area->tz_gearbox_arr[i]; + memcpy(gearbox_tz->trips, default_thermal_trips, + sizeof(thermal->trips)); + gearbox_tz->module = i; + gearbox_tz->parent = thermal; ++ gearbox_tz->slot_index = area->slot_index; + err = mlxsw_thermal_gearbox_tz_init(gearbox_tz); + if (err) + goto err_thermal_gearbox_tz_init; +@@ -911,19 +932,20 @@ mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core, + + err_thermal_gearbox_tz_init: + for (i--; i >= 0; i--) +- mlxsw_thermal_gearbox_tz_fini(&thermal->tz_gearbox_arr[i]); +- kfree(thermal->tz_gearbox_arr); ++ mlxsw_thermal_gearbox_tz_fini(&area->tz_gearbox_arr[i]); ++ kfree(area->tz_gearbox_arr); + return err; + } + + static void +-mlxsw_thermal_gearboxes_fini(struct mlxsw_thermal *thermal) ++mlxsw_thermal_gearboxes_fini(struct mlxsw_thermal *thermal, ++ struct mlxsw_thermal_area *area) + { + int i; + +- for (i = thermal->tz_gearbox_num - 1; i >= 0; i--) +- mlxsw_thermal_gearbox_tz_fini(&thermal->tz_gearbox_arr[i]); +- kfree(thermal->tz_gearbox_arr); ++ for (i = area->tz_gearbox_num - 1; i >= 0; i--) ++ mlxsw_thermal_gearbox_tz_fini(&area->tz_gearbox_arr[i]); ++ kfree(area->tz_gearbox_arr); + } + + int mlxsw_thermal_init(struct mlxsw_core *core, +@@ -943,9 +965,16 @@ int mlxsw_thermal_init(struct mlxsw_core *core, + if (!thermal) + return -ENOMEM; + ++ thermal->main = devm_kzalloc(dev, sizeof(*thermal->main), GFP_KERNEL); ++ if (!thermal->main) { ++ err = -ENOMEM; ++ goto err_devm_kzalloc; ++ } ++ + thermal->core = core; + thermal->bus_info = bus_info; + memcpy(thermal->trips, default_thermal_trips, sizeof(thermal->trips)); ++ thermal->main->slot_index = 0; + + err = mlxsw_reg_query(thermal->core, MLXSW_REG(mfcr), mfcr_pl); + if (err) { +@@ -1012,11 +1041,11 @@ int mlxsw_thermal_init(struct mlxsw_core *core, + goto err_thermal_zone_device_register; + } + +- err = mlxsw_thermal_modules_init(dev, core, thermal); ++ err = mlxsw_thermal_modules_init(dev, core, thermal, thermal->main); + if (err) + goto err_thermal_modules_init; + +- err = mlxsw_thermal_gearboxes_init(dev, core, thermal); ++ err = mlxsw_thermal_gearboxes_init(dev, core, thermal, thermal->main); + if (err) + goto err_thermal_gearboxes_init; + +@@ -1028,9 +1057,9 @@ int mlxsw_thermal_init(struct mlxsw_core *core, + return 0; + + err_thermal_zone_device_enable: +- mlxsw_thermal_gearboxes_fini(thermal); ++ mlxsw_thermal_gearboxes_fini(thermal, thermal->main); + err_thermal_gearboxes_init: +- mlxsw_thermal_modules_fini(thermal); ++ mlxsw_thermal_modules_fini(thermal, thermal->main); + err_thermal_modules_init: + if (thermal->tzdev) { + thermal_zone_device_unregister(thermal->tzdev); +@@ -1043,6 +1072,8 @@ int mlxsw_thermal_init(struct mlxsw_core *core, + thermal_cooling_device_unregister(thermal->cdevs[i]); + err_reg_write: + err_reg_query: ++ devm_kfree(dev, thermal->main); ++err_devm_kzalloc: + devm_kfree(dev, thermal); + return err; + } +@@ -1051,8 +1082,8 @@ void mlxsw_thermal_fini(struct mlxsw_thermal *thermal) + { + int i; + +- mlxsw_thermal_gearboxes_fini(thermal); +- mlxsw_thermal_modules_fini(thermal); ++ mlxsw_thermal_gearboxes_fini(thermal, thermal->main); ++ mlxsw_thermal_modules_fini(thermal, thermal->main); + if (thermal->tzdev) { + thermal_zone_device_unregister(thermal->tzdev); + thermal->tzdev = NULL; +@@ -1065,5 +1096,6 @@ void mlxsw_thermal_fini(struct mlxsw_thermal *thermal) + } + } + ++ devm_kfree(thermal->bus_info->dev, thermal->main); + devm_kfree(thermal->bus_info->dev, thermal); + } +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0120-mlxsw-core_thermal-Split-gearbox-initialization.patch b/platform/mellanox/non-upstream-patches/patches/0120-mlxsw-core_thermal-Split-gearbox-initialization.patch new file mode 100644 index 000000000000..299d03e4c5d6 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0120-mlxsw-core_thermal-Split-gearbox-initialization.patch @@ -0,0 +1,137 @@ +From 219381cde0a7294834aff7e3f30584182b26a2b6 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Tue, 14 Dec 2021 10:57:34 +0200 +Subject: [PATCH] mlxsw: core_thermal: Split gearbox initialization + +Split gearbox initialization in two routines - the first one is to be +used for gearbox configuration validation, the second for creation of +gearbox related thermal zones if any. + +Currently, mlxsw supports gearbox thermal zones corresponding to the +main board. For system equipped with the line cards assembled with the +gearboxes, thermal zones will be associated with the gearboxes found on +those line cards. + +While the initialization flow for main board and for line cards is the +same, the configuration flow is different. + +The purpose of this patch is to allow reusing of initialization flow by +main board and line cards. + +Signed-off-by: Vadim Pasternak +Reviewed-by: Jiri Pirko +Signed-off-by: Ido Schimmel +--- + .../ethernet/mellanox/mlxsw/core_thermal.c | 43 +++++++++++++++---- + 1 file changed, 34 insertions(+), 9 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +index 77a484a55..a8ecd8fea 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +@@ -887,15 +887,12 @@ mlxsw_thermal_gearbox_tz_fini(struct mlxsw_thermal_module *gearbox_tz) + } + + static int +-mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core, +- struct mlxsw_thermal *thermal, +- struct mlxsw_thermal_area *area) ++mlxsw_thermal_gearboxes_main_init(struct device *dev, struct mlxsw_core *core, ++ struct mlxsw_thermal_area *area) + { + enum mlxsw_reg_mgpir_device_type device_type; +- struct mlxsw_thermal_module *gearbox_tz; + char mgpir_pl[MLXSW_REG_MGPIR_LEN]; + u8 gbox_num; +- int i; + int err; + + mlxsw_reg_mgpir_pack(mgpir_pl, 0); +@@ -905,8 +902,11 @@ mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core, + + mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, &device_type, NULL, + NULL, NULL); +- if (device_type != MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE || +- !gbox_num) ++ if (device_type != MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE) ++ gbox_num = 0; ++ ++ /* Skip gearbox sensor array allocation, if no gearboxes are available. */ ++ if (!gbox_num) + return 0; + + area->tz_gearbox_num = gbox_num; +@@ -916,6 +916,26 @@ mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core, + if (!area->tz_gearbox_arr) + return -ENOMEM; + ++ return 0; ++} ++ ++static void ++mlxsw_thermal_gearboxes_main_fini(struct mlxsw_thermal_area *area) ++{ ++ kfree(area->tz_gearbox_arr); ++} ++ ++static int ++mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core, ++ struct mlxsw_thermal *thermal, ++ struct mlxsw_thermal_area *area) ++{ ++ struct mlxsw_thermal_module *gearbox_tz; ++ int i, err; ++ ++ if (!area->tz_gearbox_num) ++ return 0; ++ + for (i = 0; i < area->tz_gearbox_num; i++) { + gearbox_tz = &area->tz_gearbox_arr[i]; + memcpy(gearbox_tz->trips, default_thermal_trips, +@@ -933,7 +953,6 @@ mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core, + err_thermal_gearbox_tz_init: + for (i--; i >= 0; i--) + mlxsw_thermal_gearbox_tz_fini(&area->tz_gearbox_arr[i]); +- kfree(area->tz_gearbox_arr); + return err; + } + +@@ -945,7 +964,6 @@ mlxsw_thermal_gearboxes_fini(struct mlxsw_thermal *thermal, + + for (i = area->tz_gearbox_num - 1; i >= 0; i--) + mlxsw_thermal_gearbox_tz_fini(&area->tz_gearbox_arr[i]); +- kfree(area->tz_gearbox_arr); + } + + int mlxsw_thermal_init(struct mlxsw_core *core, +@@ -1045,6 +1063,10 @@ int mlxsw_thermal_init(struct mlxsw_core *core, + if (err) + goto err_thermal_modules_init; + ++ err = mlxsw_thermal_gearboxes_main_init(dev, core, thermal->main); ++ if (err) ++ goto err_thermal_gearboxes_main_init; ++ + err = mlxsw_thermal_gearboxes_init(dev, core, thermal, thermal->main); + if (err) + goto err_thermal_gearboxes_init; +@@ -1059,6 +1081,8 @@ int mlxsw_thermal_init(struct mlxsw_core *core, + err_thermal_zone_device_enable: + mlxsw_thermal_gearboxes_fini(thermal, thermal->main); + err_thermal_gearboxes_init: ++ mlxsw_thermal_gearboxes_main_fini(thermal->main); ++err_thermal_gearboxes_main_init: + mlxsw_thermal_modules_fini(thermal, thermal->main); + err_thermal_modules_init: + if (thermal->tzdev) { +@@ -1083,6 +1107,7 @@ void mlxsw_thermal_fini(struct mlxsw_thermal *thermal) + int i; + + mlxsw_thermal_gearboxes_fini(thermal, thermal->main); ++ mlxsw_thermal_gearboxes_main_fini(thermal->main); + mlxsw_thermal_modules_fini(thermal, thermal->main); + if (thermal->tzdev) { + thermal_zone_device_unregister(thermal->tzdev); +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0121-mlxsw-core_thermal-Extend-thermal-area-with-gearbox-.patch b/platform/mellanox/non-upstream-patches/patches/0121-mlxsw-core_thermal-Extend-thermal-area-with-gearbox-.patch new file mode 100644 index 000000000000..7157375e9ca5 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0121-mlxsw-core_thermal-Extend-thermal-area-with-gearbox-.patch @@ -0,0 +1,127 @@ +From 9c8482e7c487a0a19f0d6d5df06c70aa529d3023 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Tue, 14 Dec 2021 10:57:35 +0200 +Subject: [PATCH] mlxsw: core_thermal: Extend thermal area with gearbox mapping + field + +Add gearbox mapping field 'gearbox_sensor_map' to +'mlxsw_thermal_module' structure. It should provide the mapping for +gearbox sensor indexes, given gearbox number. For main board mapping is +supposed to be always sequential, while for line cards on modular +system it could be non-sequential. + +Signed-off-by: Vadim Pasternak +Reviewed-by: Jiri Pirko +Signed-off-by: Ido Schimmel +--- + .../ethernet/mellanox/mlxsw/core_thermal.c | 33 ++++++++++++++----- + 1 file changed, 25 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +index a8ecd8fea..2efedd35b 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +@@ -85,9 +85,11 @@ static const struct mlxsw_thermal_trip default_thermal_trips[] = { + #define MLXSW_THERMAL_TRIP_MASK (BIT(MLXSW_THERMAL_NUM_TRIPS) - 1) + + struct mlxsw_thermal; ++struct mlxsw_thermal_area; + + struct mlxsw_thermal_module { + struct mlxsw_thermal *parent; ++ struct mlxsw_thermal_area *area; + struct thermal_zone_device *tzdev; + struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS]; + int module; /* Module or gearbox number */ +@@ -100,6 +102,7 @@ struct mlxsw_thermal_area { + struct mlxsw_thermal_module *tz_gearbox_arr; + u8 tz_gearbox_num; + u8 slot_index; ++ u16 *gearbox_sensor_map; + }; + + struct mlxsw_thermal { +@@ -594,7 +597,7 @@ static int mlxsw_thermal_gearbox_temp_get(struct thermal_zone_device *tzdev, + int temp; + int err; + +- index = MLXSW_REG_MTMP_GBOX_INDEX_MIN + tz->module; ++ index = tz->area->gearbox_sensor_map[tz->module]; + mlxsw_reg_mtmp_pack(mtmp_pl, tz->slot_index, index, false, false); + + err = mlxsw_reg_query(thermal->core, MLXSW_REG(mtmp), mtmp_pl); +@@ -768,6 +771,7 @@ mlxsw_thermal_module_init(struct device *dev, struct mlxsw_core *core, + if (module_tz->parent) + return 0; + module_tz->module = module; ++ module_tz->area = area; + module_tz->slot_index = area->slot_index; + module_tz->parent = thermal; + memcpy(module_tz->trips, default_thermal_trips, +@@ -892,36 +896,48 @@ mlxsw_thermal_gearboxes_main_init(struct device *dev, struct mlxsw_core *core, + { + enum mlxsw_reg_mgpir_device_type device_type; + char mgpir_pl[MLXSW_REG_MGPIR_LEN]; +- u8 gbox_num; +- int err; ++ int i = 0, err; + + mlxsw_reg_mgpir_pack(mgpir_pl, 0); + err = mlxsw_reg_query(core, MLXSW_REG(mgpir), mgpir_pl); + if (err) + return err; + +- mlxsw_reg_mgpir_unpack(mgpir_pl, &gbox_num, &device_type, NULL, +- NULL, NULL); ++ mlxsw_reg_mgpir_unpack(mgpir_pl, &area->tz_gearbox_num, &device_type, ++ NULL, NULL, NULL); + if (device_type != MLXSW_REG_MGPIR_DEVICE_TYPE_GEARBOX_DIE) +- gbox_num = 0; ++ area->tz_gearbox_num = 0; + + /* Skip gearbox sensor array allocation, if no gearboxes are available. */ +- if (!gbox_num) ++ if (!area->tz_gearbox_num) + return 0; + +- area->tz_gearbox_num = gbox_num; + area->tz_gearbox_arr = kcalloc(area->tz_gearbox_num, + sizeof(*area->tz_gearbox_arr), + GFP_KERNEL); + if (!area->tz_gearbox_arr) + return -ENOMEM; + ++ area->gearbox_sensor_map = kmalloc_array(area->tz_gearbox_num, ++ sizeof(u16), GFP_KERNEL); ++ if (!area->gearbox_sensor_map) ++ goto mlxsw_thermal_gearbox_sensor_map; ++ ++ /* Fill out gearbox sensor mapping array. */ ++ for (i = 0; i < area->tz_gearbox_num; i++) ++ area->gearbox_sensor_map[i] = MLXSW_REG_MTMP_GBOX_INDEX_MIN + i; ++ + return 0; ++ ++mlxsw_thermal_gearbox_sensor_map: ++ kfree(area->tz_gearbox_arr); ++ return err; + } + + static void + mlxsw_thermal_gearboxes_main_fini(struct mlxsw_thermal_area *area) + { ++ kfree(area->gearbox_sensor_map); + kfree(area->tz_gearbox_arr); + } + +@@ -942,6 +958,7 @@ mlxsw_thermal_gearboxes_init(struct device *dev, struct mlxsw_core *core, + sizeof(thermal->trips)); + gearbox_tz->module = i; + gearbox_tz->parent = thermal; ++ gearbox_tz->area = area; + gearbox_tz->slot_index = area->slot_index; + err = mlxsw_thermal_gearbox_tz_init(gearbox_tz); + if (err) +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0122-mlxsw-core_thermal-Add-line-card-id-prefix-to-line-c.patch b/platform/mellanox/non-upstream-patches/patches/0122-mlxsw-core_thermal-Add-line-card-id-prefix-to-line-c.patch new file mode 100644 index 000000000000..d6aa7a49ca8d --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0122-mlxsw-core_thermal-Add-line-card-id-prefix-to-line-c.patch @@ -0,0 +1,59 @@ +From 3f3548804a89b7fbe15fa92ea8686f08b990b083 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Tue, 14 Dec 2021 10:57:36 +0200 +Subject: [PATCH] mlxsw: core_thermal: Add line card id prefix to line card + thermal zone name + +Add prefix "lc#n" to thermal zones associated with the thermal objects +found on line cards. + +For example thermal zone for module #9 located at line card #7 will +have type: +mlxsw-lc7-module9. +And thermal zone for gearbox #3 located at line card #5 will have type: +mlxsw-lc5-gearbox3. + +Signed-off-by: Vadim Pasternak +Reviewed-by: Jiri Pirko +Signed-off-by: Ido Schimmel +--- + .../net/ethernet/mellanox/mlxsw/core_thermal.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +index 2efedd35b..421555d3f 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +@@ -730,8 +730,12 @@ mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz) + char tz_name[MLXSW_THERMAL_ZONE_MAX_NAME]; + int err; + +- snprintf(tz_name, sizeof(tz_name), "mlxsw-module%d", +- module_tz->module + 1); ++ if (module_tz->slot_index) ++ snprintf(tz_name, sizeof(tz_name), "mlxsw-lc%d-module%d", ++ module_tz->slot_index, module_tz->module + 1); ++ else ++ snprintf(tz_name, sizeof(tz_name), "mlxsw-module%d", ++ module_tz->module + 1); + module_tz->tzdev = thermal_zone_device_register(tz_name, + MLXSW_THERMAL_NUM_TRIPS, + MLXSW_THERMAL_TRIP_MASK, +@@ -865,8 +869,12 @@ mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz) + char tz_name[MLXSW_THERMAL_ZONE_MAX_NAME]; + int ret; + +- snprintf(tz_name, sizeof(tz_name), "mlxsw-gearbox%d", +- gearbox_tz->module + 1); ++ if (gearbox_tz->slot_index) ++ snprintf(tz_name, sizeof(tz_name), "mlxsw-lc%d-gearbox%d", ++ gearbox_tz->slot_index, gearbox_tz->module + 1); ++ else ++ snprintf(tz_name, sizeof(tz_name), "mlxsw-gearbox%d", ++ gearbox_tz->module + 1); + gearbox_tz->tzdev = thermal_zone_device_register(tz_name, + MLXSW_THERMAL_NUM_TRIPS, + MLXSW_THERMAL_TRIP_MASK, +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0123-mlxsw-core_thermal-Use-exact-name-of-cooling-devices.patch b/platform/mellanox/non-upstream-patches/patches/0123-mlxsw-core_thermal-Use-exact-name-of-cooling-devices.patch new file mode 100644 index 000000000000..423827598825 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0123-mlxsw-core_thermal-Use-exact-name-of-cooling-devices.patch @@ -0,0 +1,35 @@ +From 34251eb77f3f50ac2d574876f33c65d8d2c70e9c Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Tue, 14 Dec 2021 10:57:37 +0200 +Subject: [PATCH] mlxsw: core_thermal: Use exact name of cooling devices for + binding + +Modular system supports additional cooling devices "mlxreg_fan1", +"mlxreg_fan2", etcetera. Thermal zones in "mlxsw" driver should be +bound to the same device as before called "mlxreg_fan". Used exact +match for cooling device name to avoid binding to new additional +cooling devices. + +Signed-off-by: Vadim Pasternak +Signed-off-by: Ido Schimmel +--- + drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +index 421555d3f..a20a91285 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +@@ -141,8 +141,7 @@ static int mlxsw_get_cooling_device_idx(struct mlxsw_thermal *thermal, + + /* Allow mlxsw thermal zone binding to an external cooling device */ + for (i = 0; i < ARRAY_SIZE(mlxsw_thermal_external_allowed_cdev); i++) { +- if (strnstr(cdev->type, mlxsw_thermal_external_allowed_cdev[i], +- strlen(cdev->type))) ++ if (!strcmp(cdev->type, mlxsw_thermal_external_allowed_cdev[i])) + return 0; + } + +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0124-mlxsw-core_thermal-Use-common-define-for-thermal-zon.patch b/platform/mellanox/non-upstream-patches/patches/0124-mlxsw-core_thermal-Use-common-define-for-thermal-zon.patch new file mode 100644 index 000000000000..711f4d62dc4e --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0124-mlxsw-core_thermal-Use-common-define-for-thermal-zon.patch @@ -0,0 +1,48 @@ +From 56370efd25ad5b77b87645d779dd577674c12864 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Tue, 14 Dec 2021 10:57:38 +0200 +Subject: [PATCH] mlxsw: core_thermal: Use common define for thermal zone name + length + +Replace internal define 'MLXSW_THERMAL_ZONE_MAX_NAME' by common +'THERMAL_NAME_LENGTH'. + +Signed-off-by: Vadim Pasternak +Signed-off-by: Ido Schimmel +--- + drivers/net/ethernet/mellanox/mlxsw/core_thermal.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +index a20a91285..e860cade5 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +@@ -21,7 +21,6 @@ + #define MLXSW_THERMAL_ASIC_TEMP_HOT 105000 /* 105C */ + #define MLXSW_THERMAL_HYSTERESIS_TEMP 5000 /* 5C */ + #define MLXSW_THERMAL_MODULE_TEMP_SHIFT (MLXSW_THERMAL_HYSTERESIS_TEMP * 2) +-#define MLXSW_THERMAL_ZONE_MAX_NAME 16 + #define MLXSW_THERMAL_TEMP_SCORE_MAX GENMASK(31, 0) + #define MLXSW_THERMAL_MAX_STATE 10 + #define MLXSW_THERMAL_MAX_DUTY 255 +@@ -726,7 +725,7 @@ static const struct thermal_cooling_device_ops mlxsw_cooling_ops = { + static int + mlxsw_thermal_module_tz_init(struct mlxsw_thermal_module *module_tz) + { +- char tz_name[MLXSW_THERMAL_ZONE_MAX_NAME]; ++ char tz_name[THERMAL_NAME_LENGTH]; + int err; + + if (module_tz->slot_index) +@@ -865,7 +864,7 @@ mlxsw_thermal_modules_fini(struct mlxsw_thermal *thermal, + static int + mlxsw_thermal_gearbox_tz_init(struct mlxsw_thermal_module *gearbox_tz) + { +- char tz_name[MLXSW_THERMAL_ZONE_MAX_NAME]; ++ char tz_name[THERMAL_NAME_LENGTH]; + int ret; + + if (gearbox_tz->slot_index) +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0125-devlink-add-support-to-create-line-card-and-expose-t.patch b/platform/mellanox/non-upstream-patches/patches/0125-devlink-add-support-to-create-line-card-and-expose-t.patch new file mode 100644 index 000000000000..849645848a0d --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0125-devlink-add-support-to-create-line-card-and-expose-t.patch @@ -0,0 +1,531 @@ +From 242d6e2b00a25ec4184a63cec76c9f7f7c235594 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 22 Dec 2021 08:57:27 +0000 +Subject: [PATCH] devlink: add support to create line card and expose to user + +Extend the devlink API so the driver is going to be able to create and +destroy linecard instances. There can be multiple line cards per devlink +device. Expose this new type of object over devlink netlink API to the +userspace, with notifications. + +Signed-off-by: Jiri Pirko +--- + include/net/devlink.h | 15 ++ + include/uapi/linux/devlink.h | 22 +++ + net/core/devlink.c | 303 ++++++++++++++++++++++++++++++++++- + 3 files changed, 339 insertions(+), 1 deletion(-) + +diff --git a/include/net/devlink.h b/include/net/devlink.h +index b01bb9bca..e8f046590 100644 +--- a/include/net/devlink.h ++++ b/include/net/devlink.h +@@ -31,6 +31,7 @@ struct devlink_dev_stats { + struct devlink_ops; + + struct devlink { ++ u32 index; + struct list_head list; + struct list_head port_list; + struct list_head sb_list; +@@ -44,6 +45,8 @@ struct devlink { + struct list_head trap_list; + struct list_head trap_group_list; + struct list_head trap_policer_list; ++ struct list_head linecard_list; ++ struct mutex linecards_lock; /* protects linecard_list */ + const struct devlink_ops *ops; + struct xarray snapshot_ids; + struct devlink_dev_stats stats; +@@ -55,6 +58,8 @@ struct devlink { + u8 reload_failed:1, + reload_enabled:1, + registered:1; ++ refcount_t refcount; ++ struct completion comp; + char priv[0] __aligned(NETDEV_ALIGN); + }; + +@@ -137,6 +142,13 @@ struct devlink_port { + struct mutex reporters_lock; /* Protects reporter_list */ + }; + ++struct devlink_linecard { ++ struct list_head list; ++ struct devlink *devlink; ++ unsigned int index; ++ refcount_t refcount; ++}; ++ + struct devlink_sb_pool_info { + enum devlink_sb_pool_type pool_type; + u32 size; +@@ -1401,6 +1413,9 @@ void devlink_port_attrs_pci_pf_set(struct devlink_port *devlink_port, u32 contro + u16 pf, bool external); + void devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port, u32 controller, + u16 pf, u16 vf, bool external); ++struct devlink_linecard *devlink_linecard_create(struct devlink *devlink, ++ unsigned int linecard_index); ++void devlink_linecard_destroy(struct devlink_linecard *linecard); + int devlink_sb_register(struct devlink *devlink, unsigned int sb_index, + u32 size, u16 ingress_pools_count, + u16 egress_pools_count, u16 ingress_tc_count, +diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h +index cf89c318f..ff07ad596 100644 +--- a/include/uapi/linux/devlink.h ++++ b/include/uapi/linux/devlink.h +@@ -126,6 +126,16 @@ enum devlink_command { + + DEVLINK_CMD_HEALTH_REPORTER_TEST, + ++ DEVLINK_CMD_RATE_GET, /* can dump */ ++ DEVLINK_CMD_RATE_SET, ++ DEVLINK_CMD_RATE_NEW, ++ DEVLINK_CMD_RATE_DEL, ++ ++ DEVLINK_CMD_LINECARD_GET, /* can dump */ ++ DEVLINK_CMD_LINECARD_SET, ++ DEVLINK_CMD_LINECARD_NEW, ++ DEVLINK_CMD_LINECARD_DEL, ++ + /* add new commands above here */ + __DEVLINK_CMD_MAX, + DEVLINK_CMD_MAX = __DEVLINK_CMD_MAX - 1 +@@ -529,6 +539,18 @@ enum devlink_attr { + DEVLINK_ATTR_RELOAD_ACTION_INFO, /* nested */ + DEVLINK_ATTR_RELOAD_ACTION_STATS, /* nested */ + ++ DEVLINK_ATTR_PORT_PCI_SF_NUMBER, /* u32 */ ++ ++ DEVLINK_ATTR_RATE_TYPE, /* u16 */ ++ DEVLINK_ATTR_RATE_TX_SHARE, /* u64 */ ++ DEVLINK_ATTR_RATE_TX_MAX, /* u64 */ ++ DEVLINK_ATTR_RATE_NODE_NAME, /* string */ ++ DEVLINK_ATTR_RATE_PARENT_NODE_NAME, /* string */ ++ ++ DEVLINK_ATTR_REGION_MAX_SNAPSHOTS, /* u32 */ ++ ++ DEVLINK_ATTR_LINECARD_INDEX, /* u32 */ ++ + /* add new attributes above here, update the policy in devlink.c */ + + __DEVLINK_ATTR_MAX, +diff --git a/net/core/devlink.c b/net/core/devlink.c +index 72047750d..645fe0612 100644 +--- a/net/core/devlink.c ++++ b/net/core/devlink.c +@@ -91,6 +91,25 @@ static const struct nla_policy devlink_function_nl_policy[DEVLINK_PORT_FUNCTION_ + + static LIST_HEAD(devlink_list); + ++static DEFINE_XARRAY_FLAGS(devlinks, XA_FLAGS_ALLOC); ++#define DEVLINK_REGISTERED XA_MARK_1 ++ ++/* devlink instances are open to the access from the user space after ++ * devlink_register() call. Such logical barrier allows us to have certain ++ * expectations related to locking. ++ * ++ * Before *_register() - we are in initialization stage and no parallel ++ * access possible to the devlink instance. All drivers perform that phase ++ * by implicitly holding device_lock. ++ * ++ * After *_register() - users and driver can access devlink instance at ++ * the same time. ++ */ ++#define ASSERT_DEVLINK_REGISTERED(d) \ ++ WARN_ON_ONCE(!xa_get_mark(&devlinks, (d)->index, DEVLINK_REGISTERED)) ++#define ASSERT_DEVLINK_NOT_REGISTERED(d) \ ++ WARN_ON_ONCE(xa_get_mark(&devlinks, (d)->index, DEVLINK_REGISTERED)) ++ + /* devlink_mutex + * + * An overall lock guarding every operation coming from userspace. +@@ -105,6 +124,19 @@ struct net *devlink_net(const struct devlink *devlink) + } + EXPORT_SYMBOL_GPL(devlink_net); + ++void devlink_put(struct devlink *devlink) ++{ ++ if (refcount_dec_and_test(&devlink->refcount)) ++ complete(&devlink->comp); ++} ++ ++struct devlink *__must_check devlink_try_get(struct devlink *devlink) ++{ ++ if (refcount_inc_not_zero(&devlink->refcount)) ++ return devlink; ++ return NULL; ++} ++ + static void __devlink_net_set(struct devlink *devlink, struct net *net) + { + write_pnet(&devlink->_net, net); +@@ -187,6 +219,56 @@ static struct devlink_port *devlink_port_get_from_info(struct devlink *devlink, + return devlink_port_get_from_attrs(devlink, info->attrs); + } + ++static struct devlink_linecard * ++devlink_linecard_get_by_index(struct devlink *devlink, ++ unsigned int linecard_index) ++{ ++ struct devlink_linecard *devlink_linecard; ++ ++ list_for_each_entry(devlink_linecard, &devlink->linecard_list, list) { ++ if (devlink_linecard->index == linecard_index) ++ return devlink_linecard; ++ } ++ return NULL; ++} ++ ++static bool devlink_linecard_index_exists(struct devlink *devlink, ++ unsigned int linecard_index) ++{ ++ return devlink_linecard_get_by_index(devlink, linecard_index); ++} ++ ++static struct devlink_linecard * ++devlink_linecard_get_from_attrs(struct devlink *devlink, struct nlattr **attrs) ++{ ++ if (attrs[DEVLINK_ATTR_LINECARD_INDEX]) { ++ u32 linecard_index = nla_get_u32(attrs[DEVLINK_ATTR_LINECARD_INDEX]); ++ struct devlink_linecard *linecard; ++ ++ mutex_lock(&devlink->linecards_lock); ++ linecard = devlink_linecard_get_by_index(devlink, linecard_index); ++ if (linecard) ++ refcount_inc(&linecard->refcount); ++ mutex_unlock(&devlink->linecards_lock); ++ if (!linecard) ++ return ERR_PTR(-ENODEV); ++ return linecard; ++ } ++ return ERR_PTR(-EINVAL); ++} ++ ++static struct devlink_linecard * ++devlink_linecard_get_from_info(struct devlink *devlink, struct genl_info *info) ++{ ++ return devlink_linecard_get_from_attrs(devlink, info->attrs); ++} ++ ++static void devlink_linecard_put(struct devlink_linecard *linecard) ++{ ++ if (refcount_dec_and_test(&linecard->refcount)) ++ kfree(linecard); ++} ++ + struct devlink_sb { + struct list_head list; + unsigned int index; +@@ -405,16 +487,20 @@ devlink_region_snapshot_get_by_id(struct devlink_region *region, u32 id) + + #define DEVLINK_NL_FLAG_NEED_PORT BIT(0) + #define DEVLINK_NL_FLAG_NEED_DEVLINK_OR_PORT BIT(1) ++#define DEVLINK_NL_FLAG_NEED_RATE BIT(2) ++#define DEVLINK_NL_FLAG_NEED_RATE_NODE BIT(3) ++#define DEVLINK_NL_FLAG_NEED_LINECARD BIT(4) + + /* The per devlink instance lock is taken by default in the pre-doit + * operation, yet several commands do not require this. The global + * devlink lock is taken and protects from disruption by user-calls. + */ +-#define DEVLINK_NL_FLAG_NO_LOCK BIT(2) ++#define DEVLINK_NL_FLAG_NO_LOCK BIT(5) + + static int devlink_nl_pre_doit(const struct genl_ops *ops, + struct sk_buff *skb, struct genl_info *info) + { ++ struct devlink_linecard *linecard; + struct devlink_port *devlink_port; + struct devlink *devlink; + int err; +@@ -439,6 +525,13 @@ static int devlink_nl_pre_doit(const struct genl_ops *ops, + devlink_port = devlink_port_get_from_info(devlink, info); + if (!IS_ERR(devlink_port)) + info->user_ptr[1] = devlink_port; ++ } else if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_LINECARD) { ++ linecard = devlink_linecard_get_from_info(devlink, info); ++ if (IS_ERR(linecard)) { ++ err = PTR_ERR(linecard); ++ goto unlock; ++ } ++ info->user_ptr[1] = linecard; + } + return 0; + +@@ -452,9 +545,14 @@ static int devlink_nl_pre_doit(const struct genl_ops *ops, + static void devlink_nl_post_doit(const struct genl_ops *ops, + struct sk_buff *skb, struct genl_info *info) + { ++ struct devlink_linecard *linecard; + struct devlink *devlink; + + devlink = info->user_ptr[0]; ++ if (ops->internal_flags & DEVLINK_NL_FLAG_NEED_LINECARD) { ++ linecard = info->user_ptr[1]; ++ devlink_linecard_put(linecard); ++ } + if (~ops->internal_flags & DEVLINK_NL_FLAG_NO_LOCK) + mutex_unlock(&devlink->lock); + mutex_unlock(&devlink_mutex); +@@ -1135,6 +1233,132 @@ static int devlink_nl_cmd_port_unsplit_doit(struct sk_buff *skb, + return devlink_port_unsplit(devlink, port_index, info->extack); + } + ++static int devlink_nl_linecard_fill(struct sk_buff *msg, ++ struct devlink *devlink, ++ struct devlink_linecard *linecard, ++ enum devlink_command cmd, u32 portid, ++ u32 seq, int flags, ++ struct netlink_ext_ack *extack) ++{ ++ void *hdr; ++ ++ hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); ++ if (!hdr) ++ return -EMSGSIZE; ++ ++ if (devlink_nl_put_handle(msg, devlink)) ++ goto nla_put_failure; ++ if (nla_put_u32(msg, DEVLINK_ATTR_LINECARD_INDEX, linecard->index)) ++ goto nla_put_failure; ++ ++ genlmsg_end(msg, hdr); ++ return 0; ++ ++nla_put_failure: ++ genlmsg_cancel(msg, hdr); ++ return -EMSGSIZE; ++} ++ ++static void devlink_linecard_notify(struct devlink_linecard *linecard, ++ enum devlink_command cmd) ++{ ++ struct devlink *devlink = linecard->devlink; ++ struct sk_buff *msg; ++ int err; ++ ++ WARN_ON(cmd != DEVLINK_CMD_LINECARD_NEW && ++ cmd != DEVLINK_CMD_LINECARD_DEL); ++ ++ if (!xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED)) ++ return; ++ ++ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); ++ if (!msg) ++ return; ++ ++ err = devlink_nl_linecard_fill(msg, devlink, linecard, cmd, 0, 0, 0, ++ NULL); ++ if (err) { ++ nlmsg_free(msg); ++ return; ++ } ++ ++ genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink), ++ msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL); ++} ++ ++static int devlink_nl_cmd_linecard_get_doit(struct sk_buff *skb, ++ struct genl_info *info) ++{ ++ struct devlink_linecard *linecard = info->user_ptr[1]; ++ struct devlink *devlink = linecard->devlink; ++ struct sk_buff *msg; ++ int err; ++ ++ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); ++ if (!msg) ++ return -ENOMEM; ++ ++ err = devlink_nl_linecard_fill(msg, devlink, linecard, ++ DEVLINK_CMD_LINECARD_NEW, ++ info->snd_portid, info->snd_seq, 0, ++ info->extack); ++ if (err) { ++ nlmsg_free(msg); ++ return err; ++ } ++ ++ return genlmsg_reply(msg, info); ++} ++ ++static int devlink_nl_cmd_linecard_get_dumpit(struct sk_buff *msg, ++ struct netlink_callback *cb) ++{ ++ struct devlink_linecard *linecard; ++ struct devlink *devlink; ++ int start = cb->args[0]; ++ unsigned long index; ++ int idx = 0; ++ int err; ++ ++ mutex_lock(&devlink_mutex); ++ xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) { ++ if (!devlink_try_get(devlink)) ++ continue; ++ ++ if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) ++ goto retry; ++ ++ mutex_lock(&devlink->linecards_lock); ++ list_for_each_entry(linecard, &devlink->linecard_list, list) { ++ if (idx < start) { ++ idx++; ++ continue; ++ } ++ err = devlink_nl_linecard_fill(msg, devlink, linecard, ++ DEVLINK_CMD_LINECARD_NEW, ++ NETLINK_CB(cb->skb).portid, ++ cb->nlh->nlmsg_seq, ++ NLM_F_MULTI, ++ cb->extack); ++ if (err) { ++ mutex_unlock(&devlink->linecards_lock); ++ devlink_put(devlink); ++ goto out; ++ } ++ idx++; ++ } ++ mutex_unlock(&devlink->linecards_lock); ++retry: ++ devlink_put(devlink); ++ } ++out: ++ mutex_unlock(&devlink_mutex); ++ ++ cb->args[0] = idx; ++ return msg->len; ++} ++ + static int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink, + struct devlink_sb *devlink_sb, + enum devlink_command cmd, u32 portid, +@@ -7594,6 +7818,19 @@ static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = { + [DEVLINK_ATTR_RELOAD_ACTION] = NLA_POLICY_RANGE(NLA_U8, DEVLINK_RELOAD_ACTION_DRIVER_REINIT, + DEVLINK_RELOAD_ACTION_MAX), + [DEVLINK_ATTR_RELOAD_LIMITS] = NLA_POLICY_BITFIELD32(DEVLINK_RELOAD_LIMITS_VALID_MASK), ++//<<<<<<< HEAD ++//======= ++ [DEVLINK_ATTR_PORT_FLAVOUR] = { .type = NLA_U16 }, ++ [DEVLINK_ATTR_PORT_PCI_PF_NUMBER] = { .type = NLA_U16 }, ++ [DEVLINK_ATTR_PORT_PCI_SF_NUMBER] = { .type = NLA_U32 }, ++ [DEVLINK_ATTR_PORT_CONTROLLER_NUMBER] = { .type = NLA_U32 }, ++ [DEVLINK_ATTR_RATE_TYPE] = { .type = NLA_U16 }, ++ [DEVLINK_ATTR_RATE_TX_SHARE] = { .type = NLA_U64 }, ++ [DEVLINK_ATTR_RATE_TX_MAX] = { .type = NLA_U64 }, ++ [DEVLINK_ATTR_RATE_NODE_NAME] = { .type = NLA_NUL_STRING }, ++ [DEVLINK_ATTR_RATE_PARENT_NODE_NAME] = { .type = NLA_NUL_STRING }, ++ [DEVLINK_ATTR_LINECARD_INDEX] = { .type = NLA_U32 }, ++//>>>>>>> 1180815a3831... devlink: add support to create line card and expose to user + }; + + static const struct genl_small_ops devlink_nl_ops[] = { +@@ -7633,6 +7870,14 @@ static const struct genl_small_ops devlink_nl_ops[] = { + .flags = GENL_ADMIN_PERM, + .internal_flags = DEVLINK_NL_FLAG_NO_LOCK, + }, ++ { ++ .cmd = DEVLINK_CMD_LINECARD_GET, ++ .doit = devlink_nl_cmd_linecard_get_doit, ++ .dumpit = devlink_nl_cmd_linecard_get_dumpit, ++ .internal_flags = DEVLINK_NL_FLAG_NEED_LINECARD | ++ DEVLINK_NL_FLAG_NO_LOCK, ++ /* can be retrieved by unprivileged users */ ++ }, + { + .cmd = DEVLINK_CMD_SB_GET, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, +@@ -7980,6 +8225,7 @@ struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size) + xa_init_flags(&devlink->snapshot_ids, XA_FLAGS_ALLOC); + __devlink_net_set(devlink, &init_net); + INIT_LIST_HEAD(&devlink->port_list); ++ INIT_LIST_HEAD(&devlink->linecard_list); + INIT_LIST_HEAD(&devlink->sb_list); + INIT_LIST_HEAD_RCU(&devlink->dpipe_table_list); + INIT_LIST_HEAD(&devlink->resource_list); +@@ -7991,6 +8237,8 @@ struct devlink *devlink_alloc(const struct devlink_ops *ops, size_t priv_size) + INIT_LIST_HEAD(&devlink->trap_policer_list); + mutex_init(&devlink->lock); + mutex_init(&devlink->reporters_lock); ++ mutex_init(&devlink->linecards_lock); ++ + return devlink; + } + EXPORT_SYMBOL_GPL(devlink_alloc); +@@ -8071,6 +8319,7 @@ EXPORT_SYMBOL_GPL(devlink_reload_disable); + */ + void devlink_free(struct devlink *devlink) + { ++ mutex_destroy(&devlink->linecards_lock); + mutex_destroy(&devlink->reporters_lock); + mutex_destroy(&devlink->lock); + WARN_ON(!list_empty(&devlink->trap_policer_list)); +@@ -8082,6 +8331,7 @@ void devlink_free(struct devlink *devlink) + WARN_ON(!list_empty(&devlink->resource_list)); + WARN_ON(!list_empty(&devlink->dpipe_table_list)); + WARN_ON(!list_empty(&devlink->sb_list)); ++ WARN_ON(!list_empty(&devlink->linecard_list)); + WARN_ON(!list_empty(&devlink->port_list)); + + xa_destroy(&devlink->snapshot_ids); +@@ -8427,6 +8677,57 @@ static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port, + return 0; + } + ++/** ++ * devlink_linecard_create - Create devlink linecard ++ * ++ * @devlink: devlink ++ * @linecard_index: driver-specific numerical identifier of the linecard ++ * ++ * Create devlink linecard instance with provided linecard index. ++ * Caller can use any indexing, even hw-related one. ++ */ ++struct devlink_linecard *devlink_linecard_create(struct devlink *devlink, ++ unsigned int linecard_index) ++{ ++ struct devlink_linecard *linecard; ++ ++ mutex_lock(&devlink->linecards_lock); ++ if (devlink_linecard_index_exists(devlink, linecard_index)) { ++ mutex_unlock(&devlink->linecards_lock); ++ return ERR_PTR(-EEXIST); ++ } ++ ++ linecard = kzalloc(sizeof(*linecard), GFP_KERNEL); ++ if (!linecard) ++ return ERR_PTR(-ENOMEM); ++ ++ linecard->devlink = devlink; ++ linecard->index = linecard_index; ++ list_add_tail(&linecard->list, &devlink->linecard_list); ++ refcount_set(&linecard->refcount, 1); ++ devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); ++ mutex_unlock(&devlink->linecards_lock); ++ return linecard; ++} ++EXPORT_SYMBOL_GPL(devlink_linecard_create); ++ ++/** ++ * devlink_linecard_destroy - Destroy devlink linecard ++ * ++ * @linecard: devlink linecard ++ */ ++void devlink_linecard_destroy(struct devlink_linecard *linecard) ++{ ++ struct devlink *devlink = linecard->devlink; ++ ++ devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_DEL); ++ mutex_lock(&devlink->linecards_lock); ++ list_del(&linecard->list); ++ mutex_unlock(&devlink->linecards_lock); ++ devlink_linecard_put(linecard); ++} ++EXPORT_SYMBOL_GPL(devlink_linecard_destroy); ++ + int devlink_sb_register(struct devlink *devlink, unsigned int sb_index, + u32 size, u16 ingress_pools_count, + u16 egress_pools_count, u16 ingress_tc_count, +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0126-devlink-implement-line-card-provisioning.patch b/platform/mellanox/non-upstream-patches/patches/0126-devlink-implement-line-card-provisioning.patch new file mode 100644 index 000000000000..e5ea9d5d231e --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0126-devlink-implement-line-card-provisioning.patch @@ -0,0 +1,554 @@ +From b0a30f401ca5d69f3cd78a0bf6dd1471f7aea0be Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Thu, 31 Dec 2020 17:35:08 +0100 +Subject: [PATCH] devlink: implement line card provisioning + +In order to be able to configure all needed stuff on a port/netdevice +of a line card without the line card being present, introduce line card +provisioning. Basically by setting a type, provisioning process will +start and driver is supposed to create a placeholder for instances +(ports/netdevices) for a line card type. + +Allow the user to query the supported line card types over line card +get command. Then implement two netlink command SET to allow user to +set/unset the card type. + +On the driver API side, add provision/unprovision ops and supported +types array to be advertised. Upon provision op call, the driver should +take care of creating the instances for the particular line card type. +Introduce provision_set/clear() functions to be called by the driver +once the provisioning/unprovisioning is done on its side. These helpers +are not to be called directly due to the async nature of provisioning. + +Signed-off-by: Jiri Pirko +--- + include/net/devlink.h | 41 ++++- + include/uapi/linux/devlink.h | 15 ++ + net/core/devlink.c | 311 ++++++++++++++++++++++++++++++++--- + 3 files changed, 346 insertions(+), 21 deletions(-) + +diff --git a/include/net/devlink.h b/include/net/devlink.h +index e8f046590..44b60085e 100644 +--- a/include/net/devlink.h ++++ b/include/net/devlink.h +@@ -142,11 +142,43 @@ struct devlink_port { + struct mutex reporters_lock; /* Protects reporter_list */ + }; + ++struct devlink_linecard_ops; ++struct devlink_linecard_type; ++ + struct devlink_linecard { + struct list_head list; + struct devlink *devlink; + unsigned int index; + refcount_t refcount; ++ const struct devlink_linecard_ops *ops; ++ void *priv; ++ enum devlink_linecard_state state; ++ struct mutex state_lock; /* Protects state */ ++ const char *type; ++ struct devlink_linecard_type *types; ++ unsigned int types_count; ++}; ++ ++/** ++ * struct devlink_linecard_ops - Linecard operations ++ * @provision: callback to provision the linecard slot with certain ++ * type of linecard ++ * @unprovision: callback to unprovision the linecard slot ++ * @types_init: callback to initialize types list ++ * @types_fini: callback to finalize types list ++ * @types_get: callback to get next type in list ++ */ ++struct devlink_linecard_ops { ++ int (*provision)(struct devlink_linecard *linecard, void *priv, ++ const char *type, const void *type_priv, ++ struct netlink_ext_ack *extack); ++ int (*unprovision)(struct devlink_linecard *linecard, void *priv, ++ struct netlink_ext_ack *extack); ++ unsigned int (*types_count)(struct devlink_linecard *linecard, ++ void *priv); ++ void (*types_get)(struct devlink_linecard *linecard, ++ void *priv, unsigned int index, const char **type, ++ const void **type_priv); + }; + + struct devlink_sb_pool_info { +@@ -1413,9 +1445,14 @@ void devlink_port_attrs_pci_pf_set(struct devlink_port *devlink_port, u32 contro + u16 pf, bool external); + void devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port, u32 controller, + u16 pf, u16 vf, bool external); +-struct devlink_linecard *devlink_linecard_create(struct devlink *devlink, +- unsigned int linecard_index); ++struct devlink_linecard * ++devlink_linecard_create(struct devlink *devlink, unsigned int linecard_index, ++ const struct devlink_linecard_ops *ops, void *priv); + void devlink_linecard_destroy(struct devlink_linecard *linecard); ++void devlink_linecard_provision_set(struct devlink_linecard *linecard, ++ const char *type); ++void devlink_linecard_provision_clear(struct devlink_linecard *linecard); ++void devlink_linecard_provision_fail(struct devlink_linecard *linecard); + int devlink_sb_register(struct devlink *devlink, unsigned int sb_index, + u32 size, u16 ingress_pools_count, + u16 egress_pools_count, u16 ingress_tc_count, +diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h +index ff07ad596..d88336645 100644 +--- a/include/uapi/linux/devlink.h ++++ b/include/uapi/linux/devlink.h +@@ -334,6 +334,18 @@ enum devlink_reload_limit { + + #define DEVLINK_RELOAD_LIMITS_VALID_MASK (_BITUL(__DEVLINK_RELOAD_LIMIT_MAX) - 1) + ++enum devlink_linecard_state { ++ DEVLINK_LINECARD_STATE_UNSPEC, ++ DEVLINK_LINECARD_STATE_UNPROVISIONED, ++ DEVLINK_LINECARD_STATE_UNPROVISIONING, ++ DEVLINK_LINECARD_STATE_PROVISIONING, ++ DEVLINK_LINECARD_STATE_PROVISIONING_FAILED, ++ DEVLINK_LINECARD_STATE_PROVISIONED, ++ ++ __DEVLINK_LINECARD_STATE_MAX, ++ DEVLINK_LINECARD_STATE_MAX = __DEVLINK_LINECARD_STATE_MAX - 1 ++}; ++ + enum devlink_attr { + /* don't change the order or add anything between, this is ABI! */ + DEVLINK_ATTR_UNSPEC, +@@ -550,6 +562,9 @@ enum devlink_attr { + DEVLINK_ATTR_REGION_MAX_SNAPSHOTS, /* u32 */ + + DEVLINK_ATTR_LINECARD_INDEX, /* u32 */ ++ DEVLINK_ATTR_LINECARD_STATE, /* u8 */ ++ DEVLINK_ATTR_LINECARD_TYPE, /* string */ ++ DEVLINK_ATTR_LINECARD_SUPPORTED_TYPES, /* nested */ + + /* add new attributes above here, update the policy in devlink.c */ + +diff --git a/net/core/devlink.c b/net/core/devlink.c +index 645fe0612..943973ffc 100644 +--- a/net/core/devlink.c ++++ b/net/core/devlink.c +@@ -265,8 +265,10 @@ devlink_linecard_get_from_info(struct devlink *devlink, struct genl_info *info) + + static void devlink_linecard_put(struct devlink_linecard *linecard) + { +- if (refcount_dec_and_test(&linecard->refcount)) ++ if (refcount_dec_and_test(&linecard->refcount)) { ++ mutex_destroy(&linecard->state_lock); + kfree(linecard); ++ } + } + + struct devlink_sb { +@@ -1233,6 +1235,12 @@ static int devlink_nl_cmd_port_unsplit_doit(struct sk_buff *skb, + return devlink_port_unsplit(devlink, port_index, info->extack); + } + ++struct devlink_linecard_type { ++ struct list_head list; ++ const char *type; ++ const void *priv; ++}; ++ + static int devlink_nl_linecard_fill(struct sk_buff *msg, + struct devlink *devlink, + struct devlink_linecard *linecard, +@@ -1240,7 +1248,10 @@ static int devlink_nl_linecard_fill(struct sk_buff *msg, + u32 seq, int flags, + struct netlink_ext_ack *extack) + { ++ struct devlink_linecard_type *linecard_type; ++ struct nlattr *attr; + void *hdr; ++ int i; + + hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); + if (!hdr) +@@ -1250,6 +1261,25 @@ static int devlink_nl_linecard_fill(struct sk_buff *msg, + goto nla_put_failure; + if (nla_put_u32(msg, DEVLINK_ATTR_LINECARD_INDEX, linecard->index)) + goto nla_put_failure; ++ if (nla_put_u8(msg, DEVLINK_ATTR_LINECARD_STATE, linecard->state)) ++ goto nla_put_failure; ++ if (linecard->state >= DEVLINK_LINECARD_STATE_PROVISIONED && ++ nla_put_string(msg, DEVLINK_ATTR_LINECARD_TYPE, linecard->type)) ++ goto nla_put_failure; ++ ++ if (linecard->types_count) { ++ attr = nla_nest_start(msg, ++ DEVLINK_ATTR_LINECARD_SUPPORTED_TYPES); ++ if (!attr) ++ goto nla_put_failure; ++ for (i = 0; i < linecard->types_count; i++) { ++ linecard_type = &linecard->types[i]; ++ if (nla_put_string(msg, DEVLINK_ATTR_LINECARD_TYPE, ++ linecard_type->type)) ++ goto nla_put_failure; ++ } ++ nla_nest_end(msg, attr); ++ } + + genlmsg_end(msg, hdr); + return 0; +@@ -1335,12 +1365,14 @@ static int devlink_nl_cmd_linecard_get_dumpit(struct sk_buff *msg, + idx++; + continue; + } ++ mutex_lock(&linecard->state_lock); + err = devlink_nl_linecard_fill(msg, devlink, linecard, + DEVLINK_CMD_LINECARD_NEW, + NETLINK_CB(cb->skb).portid, + cb->nlh->nlmsg_seq, + NLM_F_MULTI, + cb->extack); ++ mutex_unlock(&linecard->state_lock); + if (err) { + mutex_unlock(&devlink->linecards_lock); + devlink_put(devlink); +@@ -1359,6 +1391,153 @@ static int devlink_nl_cmd_linecard_get_dumpit(struct sk_buff *msg, + return msg->len; + } + ++static struct devlink_linecard_type * ++devlink_linecard_type_lookup(struct devlink_linecard *linecard, ++ const char *type) ++{ ++ struct devlink_linecard_type *linecard_type; ++ int i; ++ ++ for (i = 0; i < linecard->types_count; i++) { ++ linecard_type = &linecard->types[i]; ++ if (!strcmp(type, linecard_type->type)) ++ return linecard_type; ++ } ++ return NULL; ++} ++ ++static int devlink_linecard_type_set(struct devlink_linecard *linecard, ++ const char *type, ++ struct netlink_ext_ack *extack) ++{ ++ struct devlink_linecard_type *linecard_type; ++ int err; ++ ++ mutex_lock(&linecard->state_lock); ++ if (linecard->state == DEVLINK_LINECARD_STATE_PROVISIONING) { ++ NL_SET_ERR_MSG_MOD(extack, "Linecard is currently being provisioned"); ++ err = -EBUSY; ++ goto out; ++ } ++ if (linecard->state == DEVLINK_LINECARD_STATE_UNPROVISIONING) { ++ NL_SET_ERR_MSG_MOD(extack, "Linecard is currently being unprovisioned"); ++ err = -EBUSY; ++ goto out; ++ } ++ if (linecard->state != DEVLINK_LINECARD_STATE_UNPROVISIONED && ++ linecard->state != DEVLINK_LINECARD_STATE_PROVISIONING_FAILED) { ++ NL_SET_ERR_MSG_MOD(extack, "Linecard already provisioned"); ++ err = -EBUSY; ++ goto out; ++ } ++ ++ linecard_type = devlink_linecard_type_lookup(linecard, type); ++ if (!linecard_type) { ++ NL_SET_ERR_MSG_MOD(extack, "Unsupported provision type provided"); ++ err = -EINVAL; ++ goto out; ++ } ++ ++ linecard->state = DEVLINK_LINECARD_STATE_PROVISIONING; ++ linecard->type = linecard_type->type; ++ devlink_linecard_notify(linecard, ++ DEVLINK_CMD_LINECARD_NEW); ++ mutex_unlock(&linecard->state_lock); ++ err = linecard->ops->provision(linecard, linecard->priv, ++ linecard_type->type, linecard_type->priv, ++ extack); ++ if (err) { ++ /* Provisioning failed. Assume the linecard is unprovisioned ++ * for future operations. ++ */ ++ mutex_lock(&linecard->state_lock); ++ linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED; ++ devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); ++ mutex_unlock(&linecard->state_lock); ++ } ++ return err; ++ ++out: ++ mutex_unlock(&linecard->state_lock); ++ return err; ++} ++ ++static int devlink_linecard_type_unset(struct devlink_linecard *linecard, ++ struct netlink_ext_ack *extack) ++{ ++ int err; ++ ++ mutex_lock(&linecard->state_lock); ++ if (linecard->state == DEVLINK_LINECARD_STATE_PROVISIONING) { ++ NL_SET_ERR_MSG_MOD(extack, "Linecard is currently being provisioned"); ++ err = -EBUSY; ++ goto out; ++ } ++ if (linecard->state == DEVLINK_LINECARD_STATE_UNPROVISIONING) { ++ NL_SET_ERR_MSG_MOD(extack, "Linecard is currently being unprovisioned"); ++ err = -EBUSY; ++ goto out; ++ } ++ if (linecard->state == DEVLINK_LINECARD_STATE_PROVISIONING_FAILED) { ++ linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED; ++ linecard->type = NULL; ++ devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); ++ err = 0; ++ goto out; ++ } ++ ++ if (linecard->state == DEVLINK_LINECARD_STATE_UNPROVISIONED || ++ linecard->state == DEVLINK_LINECARD_STATE_UNSPEC) { ++ NL_SET_ERR_MSG_MOD(extack, "Linecard is not provisioned"); ++ err = -EOPNOTSUPP; ++ goto out; ++ } ++ linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONING; ++ devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); ++ mutex_unlock(&linecard->state_lock); ++ err = linecard->ops->unprovision(linecard, linecard->priv, ++ extack); ++ if (err) { ++ /* Unprovisioning failed. Assume the linecard is unprovisioned ++ * for future operations. ++ */ ++ mutex_lock(&linecard->state_lock); ++ linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED; ++ devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); ++ mutex_unlock(&linecard->state_lock); ++ } ++ return err; ++ ++out: ++ mutex_unlock(&linecard->state_lock); ++ return err; ++} ++ ++static int devlink_nl_cmd_linecard_set_doit(struct sk_buff *skb, ++ struct genl_info *info) ++{ ++ struct devlink_linecard *linecard = info->user_ptr[1]; ++ struct netlink_ext_ack *extack = info->extack; ++ int err; ++ ++ if (info->attrs[DEVLINK_ATTR_LINECARD_TYPE]) { ++ const char *type; ++ ++ type = nla_data(info->attrs[DEVLINK_ATTR_LINECARD_TYPE]); ++ if (strcmp(type, "")) { ++ err = devlink_linecard_type_set(linecard, type, extack); ++ if (err) ++ return err; ++ } else { ++ err = devlink_linecard_type_unset(linecard, extack); ++ if (err) ++ return err; ++ } ++ } ++ ++ return 0; ++} ++ + static int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink, + struct devlink_sb *devlink_sb, + enum devlink_command cmd, u32 portid, +@@ -7818,19 +7997,8 @@ static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = { + [DEVLINK_ATTR_RELOAD_ACTION] = NLA_POLICY_RANGE(NLA_U8, DEVLINK_RELOAD_ACTION_DRIVER_REINIT, + DEVLINK_RELOAD_ACTION_MAX), + [DEVLINK_ATTR_RELOAD_LIMITS] = NLA_POLICY_BITFIELD32(DEVLINK_RELOAD_LIMITS_VALID_MASK), +-//<<<<<<< HEAD +-//======= +- [DEVLINK_ATTR_PORT_FLAVOUR] = { .type = NLA_U16 }, +- [DEVLINK_ATTR_PORT_PCI_PF_NUMBER] = { .type = NLA_U16 }, +- [DEVLINK_ATTR_PORT_PCI_SF_NUMBER] = { .type = NLA_U32 }, +- [DEVLINK_ATTR_PORT_CONTROLLER_NUMBER] = { .type = NLA_U32 }, +- [DEVLINK_ATTR_RATE_TYPE] = { .type = NLA_U16 }, +- [DEVLINK_ATTR_RATE_TX_SHARE] = { .type = NLA_U64 }, +- [DEVLINK_ATTR_RATE_TX_MAX] = { .type = NLA_U64 }, +- [DEVLINK_ATTR_RATE_NODE_NAME] = { .type = NLA_NUL_STRING }, +- [DEVLINK_ATTR_RATE_PARENT_NODE_NAME] = { .type = NLA_NUL_STRING }, + [DEVLINK_ATTR_LINECARD_INDEX] = { .type = NLA_U32 }, +-//>>>>>>> 1180815a3831... devlink: add support to create line card and expose to user ++ [DEVLINK_ATTR_LINECARD_TYPE] = { .type = NLA_NUL_STRING }, + }; + + static const struct genl_small_ops devlink_nl_ops[] = { +@@ -7878,6 +8046,13 @@ static const struct genl_small_ops devlink_nl_ops[] = { + DEVLINK_NL_FLAG_NO_LOCK, + /* can be retrieved by unprivileged users */ + }, ++ { ++ .cmd = DEVLINK_CMD_LINECARD_SET, ++ .doit = devlink_nl_cmd_linecard_set_doit, ++ .flags = GENL_ADMIN_PERM, ++ .internal_flags = DEVLINK_NL_FLAG_NEED_LINECARD | ++ DEVLINK_NL_FLAG_NO_LOCK, ++ }, + { + .cmd = DEVLINK_CMD_SB_GET, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, +@@ -8677,35 +8852,85 @@ static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port, + return 0; + } + ++static int devlink_linecard_types_init(struct devlink_linecard *linecard) ++{ ++ struct devlink_linecard_type *linecard_type; ++ unsigned int count; ++ int i; ++ ++ count = linecard->ops->types_count(linecard, linecard->priv); ++ linecard->types = kmalloc_array(count, sizeof(*linecard_type), ++ GFP_KERNEL); ++ if (!linecard->types) ++ return -ENOMEM; ++ linecard->types_count = count; ++ ++ for (i = 0; i < count; i++) { ++ linecard_type = &linecard->types[i]; ++ linecard->ops->types_get(linecard, linecard->priv, i, ++ &linecard_type->type, ++ &linecard_type->priv); ++ } ++ return 0; ++} ++ ++static void devlink_linecard_types_fini(struct devlink_linecard *linecard) ++{ ++ kfree(linecard->types); ++} ++ + /** + * devlink_linecard_create - Create devlink linecard + * + * @devlink: devlink + * @linecard_index: driver-specific numerical identifier of the linecard ++ * @ops: linecards ops ++ * @priv: user priv pointer + * + * Create devlink linecard instance with provided linecard index. + * Caller can use any indexing, even hw-related one. + */ +-struct devlink_linecard *devlink_linecard_create(struct devlink *devlink, +- unsigned int linecard_index) ++struct devlink_linecard * ++devlink_linecard_create(struct devlink *devlink, unsigned int linecard_index, ++ const struct devlink_linecard_ops *ops, void *priv) + { + struct devlink_linecard *linecard; ++ int err; ++ ++ if (WARN_ON(!ops || !ops->provision || !ops->unprovision || ++ !ops->types_count || !ops->types_get)) ++ return ERR_PTR(-EINVAL); + + mutex_lock(&devlink->linecards_lock); + if (devlink_linecard_index_exists(devlink, linecard_index)) { +- mutex_unlock(&devlink->linecards_lock); +- return ERR_PTR(-EEXIST); ++ linecard = ERR_PTR(-EEXIST); ++ goto unlock; + } + + linecard = kzalloc(sizeof(*linecard), GFP_KERNEL); +- if (!linecard) +- return ERR_PTR(-ENOMEM); ++ if (!linecard) { ++ linecard = ERR_PTR(-ENOMEM); ++ goto unlock; ++ } + + linecard->devlink = devlink; + linecard->index = linecard_index; ++ linecard->ops = ops; ++ linecard->priv = priv; ++ linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED; ++ mutex_init(&linecard->state_lock); ++ ++ err = devlink_linecard_types_init(linecard); ++ if (err) { ++ kfree(linecard); ++ linecard = ERR_PTR(err); ++ goto unlock; ++ } ++ + list_add_tail(&linecard->list, &devlink->linecard_list); + refcount_set(&linecard->refcount, 1); + devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); ++unlock: + mutex_unlock(&devlink->linecards_lock); + return linecard; + } +@@ -8721,6 +8946,7 @@ void devlink_linecard_destroy(struct devlink_linecard *linecard) + struct devlink *devlink = linecard->devlink; + + devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_DEL); ++ devlink_linecard_types_fini(linecard); + mutex_lock(&devlink->linecards_lock); + list_del(&linecard->list); + mutex_unlock(&devlink->linecards_lock); +@@ -8728,6 +8954,53 @@ void devlink_linecard_destroy(struct devlink_linecard *linecard) + } + EXPORT_SYMBOL_GPL(devlink_linecard_destroy); + ++/** ++ * devlink_linecard_provision_set - Set provisioning on linecard ++ * ++ * @linecard: devlink linecard ++ * @type: linecard type ++ */ ++void devlink_linecard_provision_set(struct devlink_linecard *linecard, ++ const char *type) ++{ ++ mutex_lock(&linecard->state_lock); ++ WARN_ON(linecard->type && linecard->type != type); ++ linecard->state = DEVLINK_LINECARD_STATE_PROVISIONED; ++ linecard->type = type; ++ devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); ++ mutex_unlock(&linecard->state_lock); ++} ++EXPORT_SYMBOL_GPL(devlink_linecard_provision_set); ++ ++/** ++ * devlink_linecard_provision_clear - Clear provisioning on linecard ++ * ++ * @linecard: devlink linecard ++ */ ++void devlink_linecard_provision_clear(struct devlink_linecard *linecard) ++{ ++ mutex_lock(&linecard->state_lock); ++ linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED; ++ linecard->type = NULL; ++ devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); ++ mutex_unlock(&linecard->state_lock); ++} ++EXPORT_SYMBOL_GPL(devlink_linecard_provision_clear); ++ ++/** ++ * devlink_linecard_provision_fail - Fail provisioning on linecard ++ * ++ * @linecard: devlink linecard ++ */ ++void devlink_linecard_provision_fail(struct devlink_linecard *linecard) ++{ ++ mutex_lock(&linecard->state_lock); ++ linecard->state = DEVLINK_LINECARD_STATE_PROVISIONING_FAILED; ++ devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); ++ mutex_unlock(&linecard->state_lock); ++} ++EXPORT_SYMBOL_GPL(devlink_linecard_provision_fail); ++ + int devlink_sb_register(struct devlink *devlink, unsigned int sb_index, + u32 size, u16 ingress_pools_count, + u16 egress_pools_count, u16 ingress_tc_count, +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0127-devlink-implement-line-card-active-state.patch b/platform/mellanox/non-upstream-patches/patches/0127-devlink-implement-line-card-active-state.patch new file mode 100644 index 000000000000..857f84b45b7d --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0127-devlink-implement-line-card-active-state.patch @@ -0,0 +1,98 @@ +From 999c148a0a19a6a6c96dbc5b6615285d80c28de9 Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Wed, 6 Jan 2021 16:03:43 +0100 +Subject: [PATCH] devlink: implement line card active state + +Allow driver to mark a linecard as active. Expose this state to the +userspace over devlink netlink interface with proper notifications. + +Signed-off-by: Jiri Pirko +--- + include/net/devlink.h | 3 +++ + include/uapi/linux/devlink.h | 1 + + net/core/devlink.c | 36 ++++++++++++++++++++++++++++++++++++ + 3 files changed, 40 insertions(+) + +diff --git a/include/net/devlink.h b/include/net/devlink.h +index 44b60085e..d9b2b559c 100644 +--- a/include/net/devlink.h ++++ b/include/net/devlink.h +@@ -157,6 +157,7 @@ struct devlink_linecard { + const char *type; + struct devlink_linecard_type *types; + unsigned int types_count; ++ bool active; + }; + + /** +@@ -1453,6 +1454,8 @@ void devlink_linecard_provision_set(struct devlink_linecard *linecard, + const char *type); + void devlink_linecard_provision_clear(struct devlink_linecard *linecard); + void devlink_linecard_provision_fail(struct devlink_linecard *linecard); ++void devlink_linecard_activate(struct devlink_linecard *linecard); ++void devlink_linecard_deactivate(struct devlink_linecard *linecard); + int devlink_sb_register(struct devlink *devlink, unsigned int sb_index, + u32 size, u16 ingress_pools_count, + u16 egress_pools_count, u16 ingress_tc_count, +diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h +index d88336645..5ace55666 100644 +--- a/include/uapi/linux/devlink.h ++++ b/include/uapi/linux/devlink.h +@@ -341,6 +341,7 @@ enum devlink_linecard_state { + DEVLINK_LINECARD_STATE_PROVISIONING, + DEVLINK_LINECARD_STATE_PROVISIONING_FAILED, + DEVLINK_LINECARD_STATE_PROVISIONED, ++ DEVLINK_LINECARD_STATE_ACTIVE, + + __DEVLINK_LINECARD_STATE_MAX, + DEVLINK_LINECARD_STATE_MAX = __DEVLINK_LINECARD_STATE_MAX - 1 +diff --git a/net/core/devlink.c b/net/core/devlink.c +index 943973ffc..724633810 100644 +--- a/net/core/devlink.c ++++ b/net/core/devlink.c +@@ -9001,6 +9001,42 @@ void devlink_linecard_provision_fail(struct devlink_linecard *linecard) + } + EXPORT_SYMBOL_GPL(devlink_linecard_provision_fail); + ++/** ++ * devlink_linecard_activate - Set linecard active ++ * ++ * @devlink_linecard: devlink linecard ++ */ ++void devlink_linecard_activate(struct devlink_linecard *linecard) ++{ ++ mutex_lock(&linecard->state_lock); ++ WARN_ON(linecard->state != DEVLINK_LINECARD_STATE_PROVISIONED); ++ linecard->state = DEVLINK_LINECARD_STATE_ACTIVE; ++ devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); ++ mutex_unlock(&linecard->state_lock); ++} ++EXPORT_SYMBOL_GPL(devlink_linecard_activate); ++ ++/** ++ * devlink_linecard_deactivate - Set linecard inactive ++ * ++ * @devlink_linecard: devlink linecard ++ */ ++void devlink_linecard_deactivate(struct devlink_linecard *linecard) ++{ ++ bool should_notify = false; ++ ++ mutex_lock(&linecard->state_lock); ++ if (linecard->state != DEVLINK_LINECARD_STATE_UNPROVISIONING) { ++ WARN_ON(linecard->state != DEVLINK_LINECARD_STATE_ACTIVE); ++ linecard->state = DEVLINK_LINECARD_STATE_PROVISIONED; ++ should_notify = true; ++ } ++ if (should_notify) ++ devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); ++ mutex_unlock(&linecard->state_lock); ++} ++EXPORT_SYMBOL_GPL(devlink_linecard_deactivate); ++ + int devlink_sb_register(struct devlink *devlink, unsigned int sb_index, + u32 size, u16 ingress_pools_count, + u16 egress_pools_count, u16 ingress_tc_count, +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0128-devlink-add-port-to-line-card-relationship-set.patch b/platform/mellanox/non-upstream-patches/patches/0128-devlink-add-port-to-line-card-relationship-set.patch new file mode 100644 index 000000000000..eeae6ea472d2 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0128-devlink-add-port-to-line-card-relationship-set.patch @@ -0,0 +1,101 @@ +From ce052dd9aec77733b55fe1285a9be5c4cbcc87b3 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 22 Dec 2021 14:10:14 +0000 +Subject: [PATCH] devlink: add port to line card relationship set + +In order to properly inform user about relationship between port and +line card, introduce a driver API to set line card for a port. Use this +information to extend port devlink netlink message by line card index +and also include the line card index into phys_port_name and by that +into a netdevice name. + +Signed-off-by: Jiri Pirko +--- + include/net/devlink.h | 4 ++++ + net/core/devlink.c | 34 ++++++++++++++++++++++++++++------ + 2 files changed, 32 insertions(+), 6 deletions(-) + +diff --git a/include/net/devlink.h b/include/net/devlink.h +index d9b2b559c..3d4ceb290 100644 +--- a/include/net/devlink.h ++++ b/include/net/devlink.h +@@ -140,6 +140,8 @@ struct devlink_port { + struct delayed_work type_warn_dw; + struct list_head reporter_list; + struct mutex reporters_lock; /* Protects reporter_list */ ++ ++ struct devlink_linecard *linecard; + }; + + struct devlink_linecard_ops; +@@ -1446,6 +1448,8 @@ void devlink_port_attrs_pci_pf_set(struct devlink_port *devlink_port, u32 contro + u16 pf, bool external); + void devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port, u32 controller, + u16 pf, u16 vf, bool external); ++void devlink_port_linecard_set(struct devlink_port *devlink_port, ++ struct devlink_linecard *linecard); + struct devlink_linecard * + devlink_linecard_create(struct devlink *devlink, unsigned int linecard_index, + const struct devlink_linecard_ops *ops, void *priv); +diff --git a/net/core/devlink.c b/net/core/devlink.c +index 724633810..b43e93ccc 100644 +--- a/net/core/devlink.c ++++ b/net/core/devlink.c +@@ -905,6 +905,10 @@ static int devlink_nl_port_fill(struct sk_buff *msg, struct devlink *devlink, + goto nla_put_failure; + if (devlink_nl_port_function_attrs_put(msg, devlink_port, extack)) + goto nla_put_failure; ++ if (devlink_port->linecard && ++ nla_put_u32(msg, DEVLINK_ATTR_LINECARD_INDEX, ++ devlink_port->linecard->index)) ++ goto nla_put_failure; + + genlmsg_end(msg, hdr); + return 0; +@@ -8795,6 +8799,21 @@ void devlink_port_attrs_pci_vf_set(struct devlink_port *devlink_port, u32 contro + } + EXPORT_SYMBOL_GPL(devlink_port_attrs_pci_vf_set); + ++/** ++ * devlink_port_linecard_set - Link port with a linecard ++ * ++ * @devlink_port: devlink port ++ * @devlink_linecard: devlink linecard ++ */ ++void devlink_port_linecard_set(struct devlink_port *devlink_port, ++ struct devlink_linecard *linecard) ++{ ++ if (WARN_ON(devlink_port->devlink)) ++ return; ++ devlink_port->linecard = linecard; ++} ++EXPORT_SYMBOL_GPL(devlink_port_linecard_set); ++ + static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port, + char *name, size_t len) + { +@@ -8806,12 +8825,15 @@ static int __devlink_port_phys_port_name_get(struct devlink_port *devlink_port, + + switch (attrs->flavour) { + case DEVLINK_PORT_FLAVOUR_PHYSICAL: +- if (!attrs->split) +- n = snprintf(name, len, "p%u", attrs->phys.port_number); +- else +- n = snprintf(name, len, "p%us%u", +- attrs->phys.port_number, +- attrs->phys.split_subport_number); ++ if (devlink_port->linecard) ++ n = snprintf(name, len, "l%u", ++ devlink_port->linecard->index); ++ if (n < len) ++ n += snprintf(name + n, len - n, "p%u", ++ attrs->phys.port_number); ++ if (n < len && attrs->split) ++ n += snprintf(name + n, len - n, "s%u", ++ attrs->phys.split_subport_number); + break; + case DEVLINK_PORT_FLAVOUR_CPU: + case DEVLINK_PORT_FLAVOUR_DSA: +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0129-devlink-introduce-linecard-info-get-message.patch b/platform/mellanox/non-upstream-patches/patches/0129-devlink-introduce-linecard-info-get-message.patch new file mode 100644 index 000000000000..9efc8b2aa038 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0129-devlink-introduce-linecard-info-get-message.patch @@ -0,0 +1,245 @@ +From fdc91e1289c5e491e93f7d7a872d2d656d1d0e7f Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Fri, 19 Feb 2021 09:36:15 +0100 +Subject: [PATCH] devlink: introduce linecard info get message + +Allow the driver to provide per line card info get op to fill-up info, +similar to the "devlink dev info". + +Signed-off-by: Jiri Pirko +--- + include/net/devlink.h | 7 +- + include/uapi/linux/devlink.h | 3 + + net/core/devlink.c | 135 +++++++++++++++++++++++++++++++++-- + 3 files changed, 140 insertions(+), 5 deletions(-) + +diff --git a/include/net/devlink.h b/include/net/devlink.h +index 3d4ceb290..059bed6ae 100644 +--- a/include/net/devlink.h ++++ b/include/net/devlink.h +@@ -162,6 +162,8 @@ struct devlink_linecard { + bool active; + }; + ++struct devlink_info_req; ++ + /** + * struct devlink_linecard_ops - Linecard operations + * @provision: callback to provision the linecard slot with certain +@@ -170,6 +172,7 @@ struct devlink_linecard { + * @types_init: callback to initialize types list + * @types_fini: callback to finalize types list + * @types_get: callback to get next type in list ++ * @info_get: callback to get linecard info + */ + struct devlink_linecard_ops { + int (*provision)(struct devlink_linecard *linecard, void *priv, +@@ -182,6 +185,9 @@ struct devlink_linecard_ops { + void (*types_get)(struct devlink_linecard *linecard, + void *priv, unsigned int index, const char **type, + const void **type_priv); ++ int (*info_get)(struct devlink_linecard *linecard, void *priv, ++ struct devlink_info_req *req, ++ struct netlink_ext_ack *extack); + }; + + struct devlink_sb_pool_info { +@@ -630,7 +636,6 @@ struct devlink_flash_update_params { + #define DEVLINK_SUPPORT_FLASH_UPDATE_OVERWRITE_MASK BIT(1) + + struct devlink_region; +-struct devlink_info_req; + + /** + * struct devlink_region_ops - Region operations +diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h +index 5ace55666..2c9f7d584 100644 +--- a/include/uapi/linux/devlink.h ++++ b/include/uapi/linux/devlink.h +@@ -136,6 +136,8 @@ enum devlink_command { + DEVLINK_CMD_LINECARD_NEW, + DEVLINK_CMD_LINECARD_DEL, + ++ DEVLINK_CMD_LINECARD_INFO_GET, /* can dump */ ++ + /* add new commands above here */ + __DEVLINK_CMD_MAX, + DEVLINK_CMD_MAX = __DEVLINK_CMD_MAX - 1 +@@ -566,6 +568,7 @@ enum devlink_attr { + DEVLINK_ATTR_LINECARD_STATE, /* u8 */ + DEVLINK_ATTR_LINECARD_TYPE, /* string */ + DEVLINK_ATTR_LINECARD_SUPPORTED_TYPES, /* nested */ ++ DEVLINK_ATTR_LINECARD_INFO, /* nested */ + + /* add new attributes above here, update the policy in devlink.c */ + +diff --git a/net/core/devlink.c b/net/core/devlink.c +index b43e93ccc..04f8038f8 100644 +--- a/net/core/devlink.c ++++ b/net/core/devlink.c +@@ -1245,6 +1245,10 @@ struct devlink_linecard_type { + const void *priv; + }; + ++struct devlink_info_req { ++ struct sk_buff *msg; ++}; ++ + static int devlink_nl_linecard_fill(struct sk_buff *msg, + struct devlink *devlink, + struct devlink_linecard *linecard, +@@ -1542,6 +1546,125 @@ static int devlink_nl_cmd_linecard_set_doit(struct sk_buff *skb, + return 0; + } + ++static int ++devlink_nl_linecard_info_fill(struct sk_buff *msg, struct devlink *devlink, ++ struct devlink_linecard *linecard, ++ enum devlink_command cmd, u32 portid, ++ u32 seq, int flags, struct netlink_ext_ack *extack) ++{ ++ struct devlink_info_req req; ++ struct nlattr *attr; ++ void *hdr; ++ int err; ++ ++ hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); ++ if (!hdr) ++ return -EMSGSIZE; ++ ++ err = -EMSGSIZE; ++ if (devlink_nl_put_handle(msg, devlink)) ++ goto nla_put_failure; ++ if (nla_put_u32(msg, DEVLINK_ATTR_LINECARD_INDEX, linecard->index)) ++ goto nla_put_failure; ++ ++ attr = nla_nest_start(msg, DEVLINK_ATTR_LINECARD_INFO); ++ if (!attr) ++ goto nla_put_failure; ++ req.msg = msg; ++ err = linecard->ops->info_get(linecard, linecard->priv, &req, extack); ++ if (err) ++ goto nla_put_failure; ++ nla_nest_end(msg, attr); ++ ++ genlmsg_end(msg, hdr); ++ return 0; ++ ++nla_put_failure: ++ genlmsg_cancel(msg, hdr); ++ return err; ++} ++ ++static int devlink_nl_cmd_linecard_info_get_doit(struct sk_buff *skb, ++ struct genl_info *info) ++{ ++ struct devlink_linecard *linecard = info->user_ptr[1]; ++ struct devlink *devlink = linecard->devlink; ++ struct sk_buff *msg; ++ int err; ++ ++ if (!linecard->ops->info_get) ++ return -EOPNOTSUPP; ++ ++ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); ++ if (!msg) ++ return -ENOMEM; ++ ++ err = devlink_nl_linecard_info_fill(msg, devlink, linecard, ++ DEVLINK_CMD_LINECARD_INFO_GET, ++ info->snd_portid, info->snd_seq, 0, ++ info->extack); ++ if (err) { ++ nlmsg_free(msg); ++ return err; ++ } ++ ++ return genlmsg_reply(msg, info); ++} ++ ++static int devlink_nl_cmd_linecard_info_get_dumpit(struct sk_buff *msg, ++ struct netlink_callback *cb) ++{ ++ struct devlink_linecard *linecard; ++ struct devlink *devlink; ++ int start = cb->args[0]; ++ unsigned long index; ++ int idx = 0; ++ int err = 0; ++ ++ mutex_lock(&devlink_mutex); ++ xa_for_each_marked(&devlinks, index, devlink, DEVLINK_REGISTERED) { ++ if (!devlink_try_get(devlink)) ++ continue; ++ ++ if (!net_eq(devlink_net(devlink), sock_net(msg->sk))) ++ goto retry; ++ ++ mutex_lock(&devlink->linecards_lock); ++ list_for_each_entry(linecard, &devlink->linecard_list, list) { ++ if (idx < start || !linecard->ops->info_get) { ++ idx++; ++ continue; ++ } ++ mutex_lock(&linecard->state_lock); ++ err = devlink_nl_linecard_info_fill(msg, devlink, linecard, ++ DEVLINK_CMD_LINECARD_INFO_GET, ++ NETLINK_CB(cb->skb).portid, ++ cb->nlh->nlmsg_seq, ++ NLM_F_MULTI, ++ cb->extack); ++ mutex_unlock(&linecard->state_lock); ++ if (err) { ++ mutex_unlock(&devlink->linecards_lock); ++ devlink_put(devlink); ++ goto out; ++ } ++ idx++; ++ } ++ mutex_unlock(&devlink->linecards_lock); ++retry: ++ devlink_put(devlink); ++ } ++out: ++ mutex_unlock(&devlink_mutex); ++ ++ if (err != -EMSGSIZE) ++ return err; ++ ++ cb->args[0] = idx; ++ return msg->len; ++} ++ ++ + static int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink, + struct devlink_sb *devlink_sb, + enum devlink_command cmd, u32 portid, +@@ -5455,10 +5578,6 @@ static int devlink_nl_cmd_region_read_dumpit(struct sk_buff *skb, + return err; + } + +-struct devlink_info_req { +- struct sk_buff *msg; +-}; +- + int devlink_info_driver_name_put(struct devlink_info_req *req, const char *name) + { + return nla_put_string(req->msg, DEVLINK_ATTR_INFO_DRIVER_NAME, name); +@@ -8057,6 +8176,14 @@ static const struct genl_small_ops devlink_nl_ops[] = { + .internal_flags = DEVLINK_NL_FLAG_NEED_LINECARD | + DEVLINK_NL_FLAG_NO_LOCK, + }, ++ { ++ .cmd = DEVLINK_CMD_LINECARD_INFO_GET, ++ .doit = devlink_nl_cmd_linecard_info_get_doit, ++ .dumpit = devlink_nl_cmd_linecard_info_get_dumpit, ++ .internal_flags = DEVLINK_NL_FLAG_NEED_LINECARD | ++ DEVLINK_NL_FLAG_NO_LOCK, ++ /* can be retrieved by unprivileged users */ ++ }, + { + .cmd = DEVLINK_CMD_SB_GET, + .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0130-devlink-introduce-linecard-info-get-message.patch b/platform/mellanox/non-upstream-patches/patches/0130-devlink-introduce-linecard-info-get-message.patch new file mode 100644 index 000000000000..f6ea2b2f4946 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0130-devlink-introduce-linecard-info-get-message.patch @@ -0,0 +1,315 @@ +From 7a39de95203f7dc033bdc81703989d627f2ca0de Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 22 Dec 2021 15:11:36 +0000 +Subject: [PATCH] devlink: introduce linecard info get message + +Allow the driver to provide per line card info get op to fill-up info, +similar to the "devlink dev info". + +devlink: introduce line card devices support + +Line card can contain a device. For example, this can be a gearbox with +flash. This flash could be updated. Provide the driver possibility to +attach such devices to a line card and expose those to user. Leverage +the existing devlink flash update mechanism and allow driver to pass a +custom "component name" string identifying the line card device to +flash. + +Signed-off-by: Jiri Pirko +--- + include/net/devlink.h | 12 +++ + include/uapi/linux/devlink.h | 4 + + net/core/devlink.c | 166 +++++++++++++++++++++++++++++++++++ + 3 files changed, 182 insertions(+) + +diff --git a/include/net/devlink.h b/include/net/devlink.h +index 059bed6ae..06b61c1d7 100644 +--- a/include/net/devlink.h ++++ b/include/net/devlink.h +@@ -160,9 +160,11 @@ struct devlink_linecard { + struct devlink_linecard_type *types; + unsigned int types_count; + bool active; ++ struct list_head device_list; + }; + + struct devlink_info_req; ++struct devlink_linecard_device; + + /** + * struct devlink_linecard_ops - Linecard operations +@@ -188,6 +190,9 @@ struct devlink_linecard_ops { + int (*info_get)(struct devlink_linecard *linecard, void *priv, + struct devlink_info_req *req, + struct netlink_ext_ack *extack); ++ int (*device_info_get)(struct devlink_linecard_device *device, ++ void *priv, struct devlink_info_req *req, ++ struct netlink_ext_ack *extack); + }; + + struct devlink_sb_pool_info { +@@ -1459,6 +1464,13 @@ struct devlink_linecard * + devlink_linecard_create(struct devlink *devlink, unsigned int linecard_index, + const struct devlink_linecard_ops *ops, void *priv); + void devlink_linecard_destroy(struct devlink_linecard *linecard); ++struct devlink_linecard_device * ++devlink_linecard_device_create(struct devlink_linecard *linecard, ++ unsigned int device_index, ++ const char *flash_component, void *priv); ++void ++devlink_linecard_device_destroy(struct devlink_linecard *linecard, ++ struct devlink_linecard_device *linecard_device); + void devlink_linecard_provision_set(struct devlink_linecard *linecard, + const char *type); + void devlink_linecard_provision_clear(struct devlink_linecard *linecard); +diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h +index 2c9f7d584..bac94c3c1 100644 +--- a/include/uapi/linux/devlink.h ++++ b/include/uapi/linux/devlink.h +@@ -569,6 +569,10 @@ enum devlink_attr { + DEVLINK_ATTR_LINECARD_TYPE, /* string */ + DEVLINK_ATTR_LINECARD_SUPPORTED_TYPES, /* nested */ + DEVLINK_ATTR_LINECARD_INFO, /* nested */ ++ DEVLINK_ATTR_LINECARD_DEVICE_LIST, /* nested */ ++ DEVLINK_ATTR_LINECARD_DEVICE, /* nested */ ++ DEVLINK_ATTR_LINECARD_DEVICE_INDEX, /* u32 */ ++ DEVLINK_ATTR_LINECARD_DEVICE_INFO, /* nested */ + + /* add new attributes above here, update the policy in devlink.c */ + +diff --git a/net/core/devlink.c b/net/core/devlink.c +index 04f8038f8..ca014f40a 100644 +--- a/net/core/devlink.c ++++ b/net/core/devlink.c +@@ -1249,6 +1249,59 @@ struct devlink_info_req { + struct sk_buff *msg; + }; + ++struct devlink_linecard_device { ++ struct list_head list; ++ unsigned int index; ++ const char *flash_component; ++ void *priv; ++}; ++ ++static int ++devlink_nl_linecard_device_fill(struct sk_buff *msg, ++ struct devlink_linecard *linecard, ++ struct devlink_linecard_device *linecard_device) ++{ ++ struct nlattr *attr; ++ ++ attr = nla_nest_start(msg, DEVLINK_ATTR_LINECARD_DEVICE); ++ if (!attr) ++ return -EMSGSIZE; ++ if (nla_put_u32(msg, DEVLINK_ATTR_LINECARD_DEVICE_INDEX, ++ linecard_device->index)) ++ return -EMSGSIZE; ++ if (linecard_device->flash_component && ++ nla_put_string(msg, DEVLINK_ATTR_FLASH_UPDATE_COMPONENT, ++ linecard_device->flash_component)) ++ return -EMSGSIZE; ++ nla_nest_end(msg, attr); ++ ++ return 0; ++} ++ ++static int devlink_nl_linecard_devices_fill(struct sk_buff *msg, ++ struct devlink_linecard *linecard) ++{ ++ struct devlink_linecard_device *linecard_device; ++ struct nlattr *attr; ++ int err; ++ ++ if (list_empty(&linecard->device_list)) ++ return 0; ++ ++ attr = nla_nest_start(msg, DEVLINK_ATTR_LINECARD_DEVICE_LIST); ++ if (!attr) ++ return -EMSGSIZE; ++ list_for_each_entry(linecard_device, &linecard->device_list, list) { ++ err = devlink_nl_linecard_device_fill(msg, linecard, ++ linecard_device); ++ if (err) ++ return err; ++ } ++ nla_nest_end(msg, attr); ++ ++ return 0; ++} ++ + static int devlink_nl_linecard_fill(struct sk_buff *msg, + struct devlink *devlink, + struct devlink_linecard *linecard, +@@ -1259,6 +1312,7 @@ static int devlink_nl_linecard_fill(struct sk_buff *msg, + struct devlink_linecard_type *linecard_type; + struct nlattr *attr; + void *hdr; ++ int err; + int i; + + hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd); +@@ -1289,6 +1343,10 @@ static int devlink_nl_linecard_fill(struct sk_buff *msg, + nla_nest_end(msg, attr); + } + ++ err = devlink_nl_linecard_devices_fill(msg, linecard); ++ if (err) ++ goto nla_put_failure; ++ + genlmsg_end(msg, hdr); + return 0; + +@@ -1546,6 +1604,66 @@ static int devlink_nl_cmd_linecard_set_doit(struct sk_buff *skb, + return 0; + } + ++static int ++devlink_nl_linecard_device_info_fill(struct sk_buff *msg, ++ struct devlink_linecard *linecard, ++ struct devlink_linecard_device *linecard_device, ++ struct netlink_ext_ack *extack) ++{ ++ struct nlattr *attr, *attr2; ++ ++ attr = nla_nest_start(msg, DEVLINK_ATTR_LINECARD_DEVICE); ++ if (!attr) ++ return -EMSGSIZE; ++ if (nla_put_u32(msg, DEVLINK_ATTR_LINECARD_DEVICE_INDEX, ++ linecard_device->index)) ++ return -EMSGSIZE; ++ if (linecard->ops->device_info_get) { ++ struct devlink_info_req req; ++ int err; ++ ++ attr2 = nla_nest_start(msg, DEVLINK_ATTR_LINECARD_DEVICE_INFO); ++ if (!attr2) ++ return -EMSGSIZE; ++ req.msg = msg; ++ err = linecard->ops->device_info_get(linecard_device, ++ linecard_device->priv, ++ &req, extack); ++ if (err) ++ return -EMSGSIZE; ++ nla_nest_end(msg, attr2); ++ } ++ nla_nest_end(msg, attr); ++ ++ return 0; ++} ++ ++static int devlink_nl_linecard_devices_info_fill(struct sk_buff *msg, ++ struct devlink_linecard *linecard, ++ struct netlink_ext_ack *extack) ++{ ++ struct devlink_linecard_device *linecard_device; ++ struct nlattr *attr; ++ int err; ++ ++ if (list_empty(&linecard->device_list)) ++ return 0; ++ ++ attr = nla_nest_start(msg, DEVLINK_ATTR_LINECARD_DEVICE_LIST); ++ if (!attr) ++ return -EMSGSIZE; ++ list_for_each_entry(linecard_device, &linecard->device_list, list) { ++ err = devlink_nl_linecard_device_info_fill(msg, linecard, ++ linecard_device, ++ extack); ++ if (err) ++ return err; ++ } ++ nla_nest_end(msg, attr); ++ ++ return 0; ++} ++ + static int + devlink_nl_linecard_info_fill(struct sk_buff *msg, struct devlink *devlink, + struct devlink_linecard *linecard, +@@ -1576,6 +1694,10 @@ devlink_nl_linecard_info_fill(struct sk_buff *msg, struct devlink *devlink, + goto nla_put_failure; + nla_nest_end(msg, attr); + ++ err = devlink_nl_linecard_devices_info_fill(msg, linecard, extack); ++ if (err) ++ goto nla_put_failure; ++ + genlmsg_end(msg, hdr); + return 0; + +@@ -9068,6 +9190,7 @@ devlink_linecard_create(struct devlink *devlink, unsigned int linecard_index, + linecard->priv = priv; + linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED; + mutex_init(&linecard->state_lock); ++ INIT_LIST_HEAD(&linecard->device_list); + + err = devlink_linecard_types_init(linecard); + if (err) { +@@ -9096,6 +9219,7 @@ void devlink_linecard_destroy(struct devlink_linecard *linecard) + + devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_DEL); + devlink_linecard_types_fini(linecard); ++ WARN_ON(!list_empty(&linecard->device_list)); + mutex_lock(&devlink->linecards_lock); + list_del(&linecard->list); + mutex_unlock(&devlink->linecards_lock); +@@ -9103,6 +9227,47 @@ void devlink_linecard_destroy(struct devlink_linecard *linecard) + } + EXPORT_SYMBOL_GPL(devlink_linecard_destroy); + ++/** ++ * devlink_linecard_device_create - Create a device on linecard ++ * ++ * @devlink_linecard: devlink linecard ++ * @device_index: index of the linecard device ++ * @flash_component: name of flash update component, ++ * NULL if unable to flash ++ */ ++struct devlink_linecard_device * ++devlink_linecard_device_create(struct devlink_linecard *linecard, ++ unsigned int device_index, ++ const char *flash_component, void *priv) ++{ ++ struct devlink_linecard_device *linecard_device; ++ ++ linecard_device = kzalloc(sizeof(*linecard_device), GFP_KERNEL); ++ if (!linecard_device) ++ return ERR_PTR(-ENOMEM); ++ linecard_device->index = device_index; ++ linecard_device->flash_component = flash_component; ++ linecard_device->priv = priv; ++ mutex_lock(&linecard->devlink->lock); ++ list_add_tail(&linecard_device->list, &linecard->device_list); ++ devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); ++ mutex_unlock(&linecard->devlink->lock); ++ return linecard_device; ++} ++EXPORT_SYMBOL_GPL(devlink_linecard_device_create); ++ ++void ++devlink_linecard_device_destroy(struct devlink_linecard *linecard, ++ struct devlink_linecard_device *linecard_device) ++{ ++ mutex_lock(&linecard->devlink->lock); ++ devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); ++ list_del(&linecard_device->list); ++ mutex_unlock(&linecard->devlink->lock); ++ kfree(linecard_device); ++} ++EXPORT_SYMBOL_GPL(devlink_linecard_device_destroy); ++ + /** + * devlink_linecard_provision_set - Set provisioning on linecard + * +@@ -9129,6 +9294,7 @@ EXPORT_SYMBOL_GPL(devlink_linecard_provision_set); + void devlink_linecard_provision_clear(struct devlink_linecard *linecard) + { + mutex_lock(&linecard->state_lock); ++ WARN_ON(!list_empty(&linecard->device_list)); + linecard->state = DEVLINK_LINECARD_STATE_UNPROVISIONED; + linecard->type = NULL; + devlink_linecard_notify(linecard, DEVLINK_CMD_LINECARD_NEW); +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0131-mlxsw-reg-Add-Ports-Mapping-event-Configuration-Regi.patch b/platform/mellanox/non-upstream-patches/patches/0131-mlxsw-reg-Add-Ports-Mapping-event-Configuration-Regi.patch new file mode 100644 index 000000000000..446d2c8d8aed --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0131-mlxsw-reg-Add-Ports-Mapping-event-Configuration-Regi.patch @@ -0,0 +1,98 @@ +From ec8e91d320c8cccb8ad59663d2d59810ea5aecb9 Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Fri, 29 Jan 2021 08:45:09 +0100 +Subject: [PATCH] mlxsw: reg: Add Ports Mapping event Configuration Register + +The PMECR register use to enable/disable event trigger in case of +local port mapping change. + +Signed-off-by: Jiri Pirko +--- + drivers/net/ethernet/mellanox/mlxsw/reg.h | 64 +++++++++++++++++++++++ + 1 file changed, 64 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h +index 9de037b9a..42169957c 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h +@@ -5524,6 +5524,69 @@ static inline void mlxsw_reg_pplr_pack(char *payload, u8 local_port, + MLXSW_REG_PPLR_LB_TYPE_BIT_PHY_LOCAL : 0); + } + ++/* PMECR - Ports Mapping event Configuration Register ++ * -------------------------------------------------- ++ * The PMECR register use to enable/disable event trigger in case of ++ * local port mapping change. ++ */ ++#define MLXSW_REG_PMECR_ID 0x501B ++#define MLXSW_REG_PMECR_LEN 0x20 ++ ++MLXSW_REG_DEFINE(pmecr, MLXSW_REG_PMECR_ID, MLXSW_REG_PMECR_LEN); ++ ++/* reg_pmecr_local_port ++ * Local port number. ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, pmecr, local_port, 0x00, 16, 8); ++ ++/* reg_pmecr_ee ++ * Event update enable. If this bit is set, event generation will be updated ++ * based on the e field. Only relevant on Set operations. ++ * Access: WO ++ */ ++MLXSW_ITEM32(reg, pmecr, ee, 0x04, 30, 1); ++ ++/* reg_pmecr_eswi ++ * Software ignore enable bit. If this bit is set, the value if swi is used. ++ * If this bit is clear, the value of swi is ignored. ++ * Only relevant on Set operations. ++ * Access: WO ++ */ ++MLXSW_ITEM32(reg, pmecr, eswi, 0x04, 24, 1); ++ ++/* reg_pmecr_swi ++ * Software ignore. If this bit is set, the device shouldn't generate events ++ * in case of PMLP SET operation but only upon self local port mapping change ++ * (if applicable according to e configuration). This is supplementary ++ * configuration on top of e value. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, pmecr, swi, 0x04, 8, 1); ++ ++enum mlxsw_reg_pmecr_e { ++ MLXSW_REG_PMECR_E_DO_NOT_GENERATE_EVENT, ++ MLXSW_REG_PMECR_E_GENERATE_EVENT, ++ MLXSW_REG_PMECR_E_GENERATE_SINGLE_EVENT, ++}; ++ ++/* reg_pmecr_e ++ * Event generation on local port mapping change. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, pmecr, e, 0x04, 0, 2); ++ ++static inline void mlxsw_reg_pmecr_pack(char *payload, u8 local_port, ++ enum mlxsw_reg_pmecr_e e) ++{ ++ MLXSW_REG_ZERO(pmecr, payload); ++ mlxsw_reg_pmecr_local_port_set(payload, local_port); ++ mlxsw_reg_pmecr_e_set(payload, e); ++ mlxsw_reg_pmecr_ee_set(payload, true); ++ mlxsw_reg_pmecr_swi_set(payload, true); ++ mlxsw_reg_pmecr_eswi_set(payload, true); ++} ++ + /* PMPE - Port Module Plug/Unplug Event Register + * --------------------------------------------- + * This register reports any operational status change of a module. +@@ -11376,6 +11439,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = { + MLXSW_REG(pspa), + MLXSW_REG(pmaos), + MLXSW_REG(pplr), ++ MLXSW_REG(pmecr), + MLXSW_REG(pmpe), + MLXSW_REG(pddr), + MLXSW_REG(pmtm), +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0132-mlxsw-reg-Add-Management-DownStream-Device-Query-Reg.patch b/platform/mellanox/non-upstream-patches/patches/0132-mlxsw-reg-Add-Management-DownStream-Device-Query-Reg.patch new file mode 100644 index 000000000000..b0d35e83878b --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0132-mlxsw-reg-Add-Management-DownStream-Device-Query-Reg.patch @@ -0,0 +1,267 @@ +From e46f9bfa89b8b9caced49a74db695e86e963b35d Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Mon, 3 Jan 2022 10:20:49 +0000 +Subject: [PATCH] mlxsw: reg: Add Management DownStream Device Query Register + +The MDDQ register allows to query the DownStream device properties. + +Signed-off-by: Jiri Pirko +--- + drivers/net/ethernet/mellanox/mlxsw/reg.h | 234 ++++++++++++++++++++++ + 1 file changed, 234 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h +index 42169957c..d5301bd6f 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h +@@ -10297,6 +10297,239 @@ mlxsw_reg_mgpir_unpack(char *payload, u8 *num_of_devices, + *num_of_slots = mlxsw_reg_mgpir_num_of_slots_get(payload); + } + ++/* MDDQ - Management DownStream Device Query Register ++ * -------------------------------------------------- ++ * This register allows to query the DownStream device properties. The desired ++ * information is chosen upon the query_type field and is delivered by 32B ++ * of data blocks. ++ */ ++#define MLXSW_REG_MDDQ_ID 0x9161 ++#define MLXSW_REG_MDDQ_LEN 0x30 ++ ++MLXSW_REG_DEFINE(mddq, MLXSW_REG_MDDQ_ID, MLXSW_REG_MDDQ_LEN); ++ ++/* reg_mddq_sie ++ * Slot info event enable. ++ * When set to '1', each change in the slot_info.provisioned / sr_valid / ++ * active / ready will generate an event. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, mddq, sie, 0x00, 31, 1); ++ ++enum mlxsw_reg_mddq_query_type { ++ MLXSW_REG_MDDQ_QUERY_TYPE_SLOT_INFO = 1, ++ MLXSW_REG_MDDQ_QUERY_TYPE_DEVICE_INFO, /* If there are no devices ++ * on the slot, data_valid ++ * will be '0'. ++ */ ++ MLXSW_REG_MDDQ_QUERY_TYPE_SLOT_NAME, ++}; ++ ++/* reg_mddq_query_type ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, mddq, query_type, 0x00, 16, 8); ++ ++/* reg_mddq_slot_index ++ * Slot index. 0 is reserved. ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, mddq, slot_index, 0x00, 0, 4); ++ ++/* reg_mddq_response_msg_seq ++ * Response message sequential number. For a specific request, the response ++ * message sequential number is the following one. In addition, the last ++ * message should be 0. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mddq, response_msg_seq, 0x04, 16, 8); ++ ++/* reg_mddq_request_msg_seq ++ * Request message sequential number. ++ * The first message number should be 0. ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, mddq, request_msg_seq, 0x04, 0, 8); ++ ++/* reg_mddq_data_valid ++ * If set, the data in the data field is valid and contain the information ++ * for the queried index. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mddq, data_valid, 0x08, 31, 1); ++ ++/* reg_mddq_provisioned ++ * If set, the INI file is applied and the card is provisioned. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mddq, provisioned, 0x10, 31, 1); ++ ++/* reg_mddq_sr_valid ++ * If set, Shift Register is valid (after being provisioned). ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mddq, sr_valid, 0x10, 30, 1); ++ ++enum mlxsw_reg_mddq_ready { ++ MLXSW_REG_MDDQ_READY_NOT_READY, ++ MLXSW_REG_MDDQ_READY_READY, ++ MLXSW_REG_MDDQ_READY_ERROR, ++}; ++ ++/* reg_mddq_lc_ready ++ * If set, the LC is powered on, matching the INI version and a new FW ++ * version can be burnt (if necessary). ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mddq, lc_ready, 0x10, 28, 2); ++ ++/* reg_mddq_active ++ * If set, the FW has completed the MDDC.device_enable command. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mddq, active, 0x10, 27, 1); ++ ++/* reg_mddq_hw_revision ++ * Major user-configured version number of the current INI file. ++ * Valid only when active or ready are '1'. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mddq, hw_revision, 0x14, 16, 16); ++ ++/* reg_mddq_ini_file_version ++ * User-configured version number of the current INI file. ++ * Valid only when active or lc_ready are '1'. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mddq, ini_file_version, 0x14, 0, 16); ++ ++enum mlxsw_reg_mddq_card_type { ++ MLXSW_REG_MDDQ_CARD_TYPE_BUFFALO_4X400G, ++ MLXSW_REG_MDDQ_CARD_TYPE_BUFFALO_8X200G, ++ MLXSW_REG_MDDQ_CARD_TYPE_BUFFALO_16X100G, ++}; ++ ++/* reg_mddq_card_type ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mddq, card_type, 0x18, 0, 8); ++ ++static inline void ++__mlxsw_reg_mddq_pack(char *payload, u8 slot_index, ++ enum mlxsw_reg_mddq_query_type query_type) ++{ ++ MLXSW_REG_ZERO(mddq, payload); ++ mlxsw_reg_mddq_slot_index_set(payload, slot_index); ++ mlxsw_reg_mddq_query_type_set(payload, query_type); ++} ++ ++static inline void ++mlxsw_reg_mddq_slot_info_pack(char *payload, u8 slot_index, bool sie) ++{ ++ __mlxsw_reg_mddq_pack(payload, slot_index, ++ MLXSW_REG_MDDQ_QUERY_TYPE_SLOT_INFO); ++ mlxsw_reg_mddq_sie_set(payload, sie); ++} ++ ++static inline void ++mlxsw_reg_mddq_slot_info_unpack(const char *payload, u8 *p_slot_index, ++ bool *p_provisioned, bool *p_sr_valid, ++ enum mlxsw_reg_mddq_ready *p_lc_ready, ++ bool *p_active, u16 *p_hw_revision, ++ u16 *p_ini_file_version, ++ enum mlxsw_reg_mddq_card_type *p_card_type) ++{ ++ *p_slot_index = mlxsw_reg_mddq_slot_index_get(payload); ++ *p_provisioned = mlxsw_reg_mddq_provisioned_get(payload); ++ *p_sr_valid = mlxsw_reg_mddq_sr_valid_get(payload); ++ *p_lc_ready = mlxsw_reg_mddq_lc_ready_get(payload); ++ *p_active = mlxsw_reg_mddq_active_get(payload); ++ *p_hw_revision = mlxsw_reg_mddq_hw_revision_get(payload); ++ *p_ini_file_version = mlxsw_reg_mddq_ini_file_version_get(payload); ++ *p_card_type = mlxsw_reg_mddq_card_type_get(payload); ++} ++ ++/* reg_mddq_flash_owner ++ * If set, the device is the flash owner. Otherwise, a shared flash ++ * is used by this device (another device is the flash owner). ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mddq, flash_owner, 0x10, 30, 1); ++ ++/* reg_mddq_device_index ++ * Device index. The first device should number 0. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mddq, device_index, 0x10, 0, 8); ++ ++/* reg_mddq_fw_major ++ * Major FW version number. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mddq, fw_major, 0x14, 16, 16); ++ ++/* reg_mddq_fw_minor ++ * Minor FW version number. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mddq, fw_minor, 0x18, 16, 16); ++ ++/* reg_mddq_fw_sub_minor ++ * Sub-minor FW version number. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mddq, fw_sub_minor, 0x18, 0, 16); ++ ++static inline void ++mlxsw_reg_mddq_device_info_pack(char *payload, u8 slot_index, ++ u8 request_msg_seq) ++{ ++ __mlxsw_reg_mddq_pack(payload, slot_index, ++ MLXSW_REG_MDDQ_QUERY_TYPE_DEVICE_INFO); ++ mlxsw_reg_mddq_request_msg_seq_set(payload, request_msg_seq); ++} ++ ++static inline void ++mlxsw_reg_mddq_device_info_unpack(const char *payload, u8 *p_response_msg_seq, ++ bool *p_data_valid, bool *p_flash_owner, ++ u8 *p_device_index, u16 *p_fw_major, ++ u16 *p_fw_minor, u16 *p_fw_sub_minor) ++{ ++ *p_response_msg_seq = mlxsw_reg_mddq_response_msg_seq_get(payload); ++ *p_data_valid = mlxsw_reg_mddq_data_valid_get(payload); ++ if (p_flash_owner) ++ *p_flash_owner = mlxsw_reg_mddq_flash_owner_get(payload); ++ *p_device_index = mlxsw_reg_mddq_device_index_get(payload); ++ if (p_fw_major) ++ *p_fw_major = mlxsw_reg_mddq_fw_major_get(payload); ++ if (p_fw_minor) ++ *p_fw_minor = mlxsw_reg_mddq_fw_minor_get(payload); ++ if (p_fw_sub_minor) ++ *p_fw_sub_minor = mlxsw_reg_mddq_fw_sub_minor_get(payload); ++} ++ ++#define MLXSW_REG_MDDQ_SLOT_ACII_NAME_LEN 20 ++ ++/* reg_mddq_slot_ascii_name ++ * Slot's ASCII name. ++ * Access: RO ++ */ ++MLXSW_ITEM_BUF(reg, mddq, slot_ascii_name, 0x10, ++ MLXSW_REG_MDDQ_SLOT_ACII_NAME_LEN); ++ ++static inline void ++mlxsw_reg_mddq_slot_name_pack(char *payload, u8 slot_index) ++{ ++ __mlxsw_reg_mddq_pack(payload, slot_index, ++ MLXSW_REG_MDDQ_QUERY_TYPE_SLOT_NAME); ++} ++ ++static inline void ++mlxsw_reg_mddq_slot_name_unpack(const char *payload, char *slot_ascii_name) ++{ ++ mlxsw_reg_mddq_slot_ascii_name_memcpy_from(payload, slot_ascii_name); ++} ++ + /* MFDE - Monitoring FW Debug Register + * ----------------------------------- + */ +@@ -11496,6 +11729,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = { + MLXSW_REG(mtptpt), + MLXSW_REG(mfgd), + MLXSW_REG(mgpir), ++ MLXSW_REG(mddq), + MLXSW_REG(mfde), + MLXSW_REG(tngcr), + MLXSW_REG(tnumt), +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0133-mlxsw-reg-Add-Management-DownStream-Device-Control-R.patch b/platform/mellanox/non-upstream-patches/patches/0133-mlxsw-reg-Add-Management-DownStream-Device-Control-R.patch new file mode 100644 index 000000000000..bd3c3680e0d8 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0133-mlxsw-reg-Add-Management-DownStream-Device-Control-R.patch @@ -0,0 +1,70 @@ +From ab25c37ca20274cbf51ab603aa44f682cf5b51b5 Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Tue, 19 Jan 2021 12:16:58 +0100 +Subject: [PATCH] mlxsw: reg: Add Management DownStream Device Control Register + +The MDDC register allows control downstream devices and line cards. + +Signed-off-by: Jiri Pirko +--- + drivers/net/ethernet/mellanox/mlxsw/reg.h | 37 +++++++++++++++++++++++ + 1 file changed, 37 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h +index d5301bd6f..9cbdf407f 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h +@@ -10530,6 +10530,42 @@ mlxsw_reg_mddq_slot_name_unpack(const char *payload, char *slot_ascii_name) + mlxsw_reg_mddq_slot_ascii_name_memcpy_from(payload, slot_ascii_name); + } + ++/* MDDC - Management DownStream Device Control Register ++ * ---------------------------------------------------- ++ * This register allows control downstream devices and line cards. ++ */ ++#define MLXSW_REG_MDDC_ID 0x9163 ++#define MLXSW_REG_MDDC_LEN 0x30 ++ ++MLXSW_REG_DEFINE(mddc, MLXSW_REG_MDDC_ID, MLXSW_REG_MDDC_LEN); ++ ++/* reg_mddc_slot_index ++ * Slot index. 0 is reserved. ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, mddc, slot_index, 0x00, 0, 4); ++ ++/* reg_mddc_rst ++ * Reset request. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, mddc, rst, 0x04, 29, 1); ++ ++/* reg_mddc_device_enable ++ * When set, FW is the manager and allowed to program the Downstream Device. ++ * Access: RW ++ */ ++MLXSW_ITEM32(reg, mddc, device_enable, 0x04, 28, 1); ++ ++static inline void mlxsw_reg_mddc_pack(char *payload, u8 slot_index, bool rst, ++ bool device_enable) ++{ ++ MLXSW_REG_ZERO(mddc, payload); ++ mlxsw_reg_mddc_slot_index_set(payload, slot_index); ++ mlxsw_reg_mddc_rst_set(payload, rst); ++ mlxsw_reg_mddc_device_enable_set(payload, device_enable); ++} ++ + /* MFDE - Monitoring FW Debug Register + * ----------------------------------- + */ +@@ -11730,6 +11766,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = { + MLXSW_REG(mfgd), + MLXSW_REG(mgpir), + MLXSW_REG(mddq), ++ MLXSW_REG(mddc), + MLXSW_REG(mfde), + MLXSW_REG(tngcr), + MLXSW_REG(tnumt), +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0134-mlxsw-reg-Add-Management-Binary-Code-Transfer-Regist.patch b/platform/mellanox/non-upstream-patches/patches/0134-mlxsw-reg-Add-Management-Binary-Code-Transfer-Regist.patch new file mode 100644 index 000000000000..b8569f2ac2c7 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0134-mlxsw-reg-Add-Management-Binary-Code-Transfer-Regist.patch @@ -0,0 +1,154 @@ +From 618665ccbf600c2838fb2e181246aef0fa90bac2 Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Thu, 10 Dec 2020 18:27:38 +0100 +Subject: [PATCH] mlxsw: reg: Add Management Binary Code Transfer Register + +The MBCT register allows to transfer binary codes from the Host to +the management FW by transferring it by chunks of maximum 1KB. + +Signed-off-by: Jiri Pirko +--- + drivers/net/ethernet/mellanox/mlxsw/reg.h | 120 ++++++++++++++++++++++ + 1 file changed, 120 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h +index 9cbdf407f..89b21910f 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h +@@ -10297,6 +10297,125 @@ mlxsw_reg_mgpir_unpack(char *payload, u8 *num_of_devices, + *num_of_slots = mlxsw_reg_mgpir_num_of_slots_get(payload); + } + ++/* MBCT - Management Binary Code Transfer Register ++ * ----------------------------------------------- ++ * This register allows to transfer binary codes from the Host to ++ * the management FW by transferring it by chunks of maximum 1KB. ++ */ ++#define MLXSW_REG_MBCT_ID 0x9120 ++#define MLXSW_REG_MBCT_LEN 0x420 ++ ++MLXSW_REG_DEFINE(mbct, MLXSW_REG_MBCT_ID, MLXSW_REG_MBCT_LEN); ++ ++/* reg_mbct_slot_index ++ * Slot index. 0 is reserved. ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, mbct, slot_index, 0x00, 0, 4); ++ ++/* reg_mbct_data_size ++ * Actual data field size in bytes for the current data transfer. ++ * Access: WO ++ */ ++MLXSW_ITEM32(reg, mbct, data_size, 0x04, 0, 11); ++ ++enum mlxsw_reg_mbct_op { ++ MLXSW_REG_MBCT_OP_ERASE_INI_IMAGE = 1, ++ MLXSW_REG_MBCT_OP_DATA_TRANSFER, /* Download */ ++ MLXSW_REG_MBCT_OP_ACTIVATE, ++ MLXSW_REG_MBCT_OP_CLEAR_ERRORS = 6, ++ MLXSW_REG_MBCT_OP_QUERY_STATUS, ++}; ++ ++/* reg_mbct_op ++ * Access: OP ++ */ ++MLXSW_ITEM32(reg, mbct, op, 0x08, 28, 4); ++ ++/* reg_mbct_last ++ * Indicates that the current data field is the last chunk of the INI. ++ * Access: WO ++ */ ++MLXSW_ITEM32(reg, mbct, last, 0x08, 26, 1); ++ ++/* reg_mbct_oee ++ * Opcode Event Enable. When set an event will be sent once the opcode ++ * was executed and the fsm_state has changed. ++ * Access: WO ++ */ ++MLXSW_ITEM32(reg, mbct, oee, 0x08, 25, 1); ++ ++enum mlxsw_reg_mbct_status { ++ /* Partial data transfer completed successfully and ready for next ++ * data transfer. ++ */ ++ MLXSW_REG_MBCT_STATUS_PART_DATA = 2, ++ MLXSW_REG_MBCT_STATUS_LAST_DATA, ++ MLXSW_REG_MBCT_STATUS_ERASE_COMPLETE, ++ /* Error - trying to erase INI while it being used. */ ++ MLXSW_REG_MBCT_STATUS_ERROR_INI_IN_USE, ++ /* Last data transfer completed, applying magic pattern. */ ++ MLXSW_REG_MBCT_STATUS_ERASE_FAILED = 7, ++ MLXSW_REG_MBCT_STATUS_INI_ERROR, ++ MLXSW_REG_MBCT_STATUS_ACTIVATION_FAILED, ++ MLXSW_REG_MBCT_STATUS_ILLEGAL_OPERATION = 11, ++}; ++ ++/* reg_mbct_status ++ * Status. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mbct, status, 0x0C, 24, 5); ++ ++enum mlxsw_reg_mbct_fsm_state { ++ MLXSW_REG_MBCT_FSM_STATE_INI_IN_USE = 5, ++ MLXSW_REG_MBCT_FSM_STATE_ERROR = 6, ++}; ++ ++/* reg_mbct_fsm_state ++ * FSM state. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mbct, fsm_state, 0x0C, 16, 4); ++ ++#define MLXSW_REG_MBCT_DATA_LEN 1024 ++ ++/* reg_mbct_data ++ * Up to 1KB of data. ++ * Access: WO ++ */ ++MLXSW_ITEM_BUF(reg, mbct, data, 0x20, MLXSW_REG_MBCT_DATA_LEN); ++ ++static inline void mlxsw_reg_mbct_pack(char *payload, u8 slot_index, ++ enum mlxsw_reg_mbct_op op, ++ u16 data_size, bool last, bool oee, ++ const char *data) ++{ ++ MLXSW_REG_ZERO(mbct, payload); ++ mlxsw_reg_mbct_slot_index_set(payload, slot_index); ++ mlxsw_reg_mbct_op_set(payload, op); ++ mlxsw_reg_mbct_oee_set(payload, oee); ++ if (op == MLXSW_REG_MBCT_OP_DATA_TRANSFER) { ++ if (WARN_ON(data_size > MLXSW_REG_MBCT_DATA_LEN)) ++ return; ++ mlxsw_reg_mbct_data_size_set(payload, data_size); ++ mlxsw_reg_mbct_last_set(payload, last); ++ mlxsw_reg_mbct_data_memcpy_to(payload, data); ++ } ++} ++ ++static inline void ++mlxsw_reg_mbct_unpack(const char *payload, u8 *p_slot_index, ++ enum mlxsw_reg_mbct_status *p_status, ++ enum mlxsw_reg_mbct_fsm_state *p_fsm_state) ++{ ++ if (p_slot_index) ++ *p_slot_index = mlxsw_reg_mbct_slot_index_get(payload); ++ *p_status = mlxsw_reg_mbct_status_get(payload); ++ if (p_fsm_state) ++ *p_fsm_state = mlxsw_reg_mbct_fsm_state_get(payload); ++} ++ + /* MDDQ - Management DownStream Device Query Register + * -------------------------------------------------- + * This register allows to query the DownStream device properties. The desired +@@ -11765,6 +11884,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = { + MLXSW_REG(mtptpt), + MLXSW_REG(mfgd), + MLXSW_REG(mgpir), ++ MLXSW_REG(mbct), + MLXSW_REG(mddq), + MLXSW_REG(mddc), + MLXSW_REG(mfde), +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0135-mlxsw-core_linecards-Add-line-card-objects-and-imple.patch b/platform/mellanox/non-upstream-patches/patches/0135-mlxsw-core_linecards-Add-line-card-objects-and-imple.patch new file mode 100644 index 000000000000..79a82fec6981 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0135-mlxsw-core_linecards-Add-line-card-objects-and-imple.patch @@ -0,0 +1,1062 @@ +From 3c23c52a44d6f87f7caaf09babb6196e523d1e7c Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 22 Dec 2021 16:06:54 +0000 +Subject: [PATCH] mlxsw: core_linecards: Add line card objects and implement + provisioning + +Introduce objects for line cards and an infrastructure around that. +Use devlink_linecard_create/destroy() to register the line card with +devlink core. Implement provisioning ops with a list of supported +line cards. + +Signed-off-by: Jiri Pirko +--- + drivers/net/ethernet/mellanox/mlxsw/Makefile | 3 +- + drivers/net/ethernet/mellanox/mlxsw/core.c | 22 + + drivers/net/ethernet/mellanox/mlxsw/core.h | 46 ++ + .../ethernet/mellanox/mlxsw/core_linecards.c | 775 ++++++++++++++++++ + .../net/ethernet/mellanox/mlxsw/spectrum.c | 68 ++ + drivers/net/ethernet/mellanox/mlxsw/trap.h | 6 + + 6 files changed, 919 insertions(+), 1 deletion(-) + create mode 100644 drivers/net/ethernet/mellanox/mlxsw/core_linecards.c + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/Makefile b/drivers/net/ethernet/mellanox/mlxsw/Makefile +index 892724380..ca7260a14 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/Makefile ++++ b/drivers/net/ethernet/mellanox/mlxsw/Makefile +@@ -1,7 +1,8 @@ + # SPDX-License-Identifier: GPL-2.0 + obj-$(CONFIG_MLXSW_CORE) += mlxsw_core.o + mlxsw_core-objs := core.o core_acl_flex_keys.o \ +- core_acl_flex_actions.o core_env.o ++ core_acl_flex_actions.o core_env.o \ ++ core_linecards.o + mlxsw_core-$(CONFIG_MLXSW_CORE_HWMON) += core_hwmon.o + mlxsw_core-$(CONFIG_MLXSW_CORE_THERMAL) += core_thermal.o + obj-$(CONFIG_MLXSW_PCI) += mlxsw_pci.o +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c +index 0b1888318..246db548f 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.c +@@ -82,6 +82,7 @@ struct mlxsw_core { + struct mlxsw_res res; + struct mlxsw_hwmon *hwmon; + struct mlxsw_thermal *thermal; ++ struct mlxsw_linecards *linecards; + struct mlxsw_core_port *ports; + unsigned int max_ports; + bool fw_flash_in_progress; +@@ -93,6 +94,11 @@ struct mlxsw_core { + /* driver_priv has to be always the last item */ + }; + ++struct mlxsw_linecards *mlxsw_core_linecards(struct mlxsw_core *mlxsw_core) ++{ ++ return mlxsw_core->linecards; ++} ++ + #define MLXSW_PORT_MAX_PORTS_DEFAULT 0x40 + + static int mlxsw_ports_init(struct mlxsw_core *mlxsw_core) +@@ -1918,6 +1924,11 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, + if (err) + goto err_emad_init; + ++ err = mlxsw_linecards_init(mlxsw_core, mlxsw_bus_info, ++ &mlxsw_core->linecards); ++ if (err) ++ goto err_linecards_init; ++ + if (!reload) { + err = devlink_register(devlink, mlxsw_bus_info->dev); + if (err) +@@ -1963,8 +1974,15 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, + if (!reload) + devlink_reload_enable(devlink); + ++ err = mlxsw_linecards_post_init(mlxsw_core, mlxsw_core->linecards); ++ if (err) ++ goto err_linecards_post_init; ++ + return 0; + ++err_linecards_post_init: ++ if (mlxsw_core->driver->fini) ++ mlxsw_core->driver->fini(mlxsw_core); + err_driver_init: + mlxsw_env_fini(mlxsw_core->env); + err_env_init: +@@ -1981,6 +1999,8 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, + if (!reload) + devlink_unregister(devlink); + err_devlink_register: ++ mlxsw_linecards_fini(mlxsw_core, mlxsw_core->linecards); ++err_linecards_init: + mlxsw_emad_fini(mlxsw_core); + err_emad_init: + kfree(mlxsw_core->lag.mapping); +@@ -2042,6 +2062,7 @@ void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core, + } + + devlink_params_unpublish(devlink); ++ mlxsw_linecards_pre_fini(mlxsw_core, mlxsw_core->linecards); + if (mlxsw_core->driver->fini) + mlxsw_core->driver->fini(mlxsw_core); + mlxsw_env_fini(mlxsw_core->env); +@@ -2052,6 +2073,7 @@ void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core, + mlxsw_core_params_unregister(mlxsw_core); + if (!reload) + devlink_unregister(devlink); ++ mlxsw_linecards_fini(mlxsw_core, mlxsw_core->linecards); + mlxsw_emad_fini(mlxsw_core); + kfree(mlxsw_core->lag.mapping); + mlxsw_ports_fini(mlxsw_core); +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h +index 0ceb7dae9..d3c5d8289 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.h +@@ -30,6 +30,8 @@ unsigned int mlxsw_core_max_ports(const struct mlxsw_core *mlxsw_core); + + void *mlxsw_core_driver_priv(struct mlxsw_core *mlxsw_core); + ++struct mlxsw_linecards *mlxsw_core_linecards(struct mlxsw_core *mlxsw_core); ++ + bool mlxsw_core_temp_warn_enabled(const struct mlxsw_core *mlxsw_core); + + bool +@@ -509,4 +511,48 @@ static inline struct mlxsw_skb_cb *mlxsw_skb_cb(struct sk_buff *skb) + return (struct mlxsw_skb_cb *) skb->cb; + } + ++struct mlxsw_linecards; ++ ++struct mlxsw_linecard { ++ u8 slot_index; ++ struct mlxsw_linecards *linecards; ++ struct devlink_linecard *devlink_linecard; ++ struct mutex lock; /* Locks accesses to the linecard structure */ ++ char read_name[MLXSW_REG_MDDQ_SLOT_ACII_NAME_LEN]; ++ char mbct_pl[MLXSW_REG_MBCT_LEN]; /* too big for stack */ ++ bool provisioned; ++}; ++ ++struct mlxsw_linecard_types_info; ++ ++struct mlxsw_linecards { ++ struct list_head event_ops_list; ++ struct workqueue_struct *wq; ++ struct mlxsw_core *mlxsw_core; ++ const struct mlxsw_bus_info *bus_info; ++ u8 count; ++ struct mlxsw_linecard_types_info *types_info; ++ struct mlxsw_linecard linecards[0]; ++}; ++ ++static inline struct mlxsw_linecard * ++mlxsw_linecard_get(struct mlxsw_linecards *linecards, u8 slot_index) ++{ ++ return &linecards->linecards[slot_index - 1]; ++} ++ ++int mlxsw_linecards_init(struct mlxsw_core *mlxsw_core, ++ const struct mlxsw_bus_info *bus_info, ++ struct mlxsw_linecards **p_linecards); ++int mlxsw_linecards_post_init(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards); ++void mlxsw_linecards_pre_fini(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards); ++void mlxsw_linecards_fini(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards); ++int mlxsw_linecard_status_process(struct mlxsw_core *mlxsw_core, ++ const char *mddq_pl); ++int mlxsw_linecard_bct_process(struct mlxsw_core *mlxsw_core, ++ const char *mbct_pl); ++ + #endif +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c b/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c +new file mode 100644 +index 000000000..a324ce243 +--- /dev/null ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c +@@ -0,0 +1,775 @@ ++// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 ++/* Copyright (c) 2021 NVIDIA Corporation and Mellanox Technologies. All rights reserved */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "core.h" ++#include "../mlxfw/mlxfw.h" ++ ++struct mlxsw_linecard_ini_file { ++ __le16 size; ++ union { ++ u8 data[0]; ++ struct { ++ u8 __dontcare[7]; ++ u8 type; ++ u8 name[20]; ++ } format; ++ }; ++}; ++ ++struct mlxsw_linecard_types_info { ++ struct mlxsw_linecard_ini_file **ini_files; ++ unsigned int count; ++ size_t data_size; ++ char *data; ++}; ++ ++static const char * ++mlxsw_linecard_types_lookup(struct mlxsw_linecards *linecards, ++ enum mlxsw_reg_mddq_card_type card_type) ++{ ++ struct mlxsw_linecard_types_info *types_info; ++ struct mlxsw_linecard_ini_file *ini_file; ++ int i; ++ ++ types_info = linecards->types_info; ++ for (i = 0; i < types_info->count; i++) { ++ ini_file = linecards->types_info->ini_files[i]; ++ if (ini_file->format.type == card_type) ++ return ini_file->format.name; ++ } ++ return NULL; ++} ++ ++static const char *mlxsw_linecard_type_name(struct mlxsw_linecard *linecard) ++{ ++ struct mlxsw_core *mlxsw_core = linecard->linecards->mlxsw_core; ++ char mddq_pl[MLXSW_REG_MDDQ_LEN]; ++ int err; ++ ++ mlxsw_reg_mddq_slot_name_pack(mddq_pl, linecard->slot_index); ++ err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mddq), mddq_pl); ++ if (err) ++ return NULL; ++ mlxsw_reg_mddq_slot_name_unpack(mddq_pl, linecard->read_name); ++ return linecard->read_name; ++} ++ ++static void mlxsw_linecard_provision_fail(struct mlxsw_linecard *linecard) ++{ ++ linecard->provisioned = false; ++ devlink_linecard_provision_fail(linecard->devlink_linecard); ++} ++ ++static int ++mlxsw_linecard_provision_set(struct mlxsw_linecards *linecards, ++ struct mlxsw_linecard *linecard, ++ enum mlxsw_reg_mddq_card_type card_type) ++{ ++ const char *type = mlxsw_linecard_types_lookup(linecards, card_type); ++ ++ if (!type) ++ type = mlxsw_linecard_type_name(linecard); ++ if (!type) { ++ mlxsw_linecard_provision_fail(linecard); ++ return -EINVAL; ++ } ++ linecard->provisioned = true; ++ devlink_linecard_provision_set(linecard->devlink_linecard, type); ++ return 0; ++} ++ ++static void mlxsw_linecard_provision_clear(struct mlxsw_linecard *linecard) ++{ ++ linecard->provisioned = false; ++ devlink_linecard_provision_clear(linecard->devlink_linecard); ++} ++ ++static int __mlxsw_linecard_status_process(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards, ++ struct mlxsw_linecard *linecard, ++ const char *mddq_pl) ++{ ++ enum mlxsw_reg_mddq_card_type card_type; ++ enum mlxsw_reg_mddq_ready ready; ++ bool provisioned; ++ u16 ini_version; ++ u16 hw_revision; ++ bool sr_valid; ++ u8 slot_index; ++ int err = 0; ++ bool active; ++ ++ mlxsw_reg_mddq_slot_info_unpack(mddq_pl, &slot_index, &provisioned, ++ &sr_valid, &ready, &active, ++ &hw_revision, &ini_version, ++ &card_type); ++ ++ if (linecard) { ++ if (slot_index != linecard->slot_index) ++ return -EINVAL; ++ } else { ++ if (slot_index > linecards->count) ++ return -EINVAL; ++ linecard = mlxsw_linecard_get(linecards, slot_index); ++ } ++ ++ mutex_lock(&linecard->lock); ++ ++ if (provisioned && linecard->provisioned != provisioned) { ++ err = mlxsw_linecard_provision_set(linecards, linecard, ++ card_type); ++ if (err) ++ goto out; ++ } ++ ++ if (!provisioned && linecard->provisioned != provisioned) ++ mlxsw_linecard_provision_clear(linecard); ++ ++out: ++ mutex_unlock(&linecard->lock); ++ return err; ++} ++ ++int mlxsw_linecard_status_process(struct mlxsw_core *mlxsw_core, ++ const char *mddq_pl) ++{ ++ struct mlxsw_linecards *linecards = mlxsw_core_linecards(mlxsw_core); ++ ++ return __mlxsw_linecard_status_process(mlxsw_core, linecards, NULL, ++ mddq_pl); ++} ++EXPORT_SYMBOL(mlxsw_linecard_status_process); ++ ++static int mlxsw_linecard_status_get_and_process(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards, ++ struct mlxsw_linecard *linecard) ++{ ++ char mddq_pl[MLXSW_REG_MDDQ_LEN]; ++ int err; ++ ++ mlxsw_reg_mddq_slot_info_pack(mddq_pl, linecard->slot_index, false); ++ err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mddq), mddq_pl); ++ if (err) ++ return err; ++ ++ return __mlxsw_linecard_status_process(mlxsw_core, linecards, linecard, ++ mddq_pl); ++} ++ ++static int __mlxsw_linecard_fix_fsm_state(struct mlxsw_linecard *linecard) ++{ ++ dev_info(linecard->linecards->bus_info->dev, "linecard %u: Clearing FSM state error", ++ linecard->slot_index); ++ mlxsw_reg_mbct_pack(linecard->mbct_pl, linecard->slot_index, ++ MLXSW_REG_MBCT_OP_CLEAR_ERRORS, 0, ++ false, false, NULL); ++ return mlxsw_reg_write(linecard->linecards->mlxsw_core, ++ MLXSW_REG(mbct), linecard->mbct_pl); ++} ++ ++static int mlxsw_linecard_fix_fsm_state(struct mlxsw_linecard *linecard, ++ enum mlxsw_reg_mbct_fsm_state fsm_state) ++{ ++ if (fsm_state != MLXSW_REG_MBCT_FSM_STATE_ERROR) ++ return 0; ++ return __mlxsw_linecard_fix_fsm_state(linecard); ++} ++ ++static int mlxsw_linecard_query_status(struct mlxsw_linecard *linecard, ++ enum mlxsw_reg_mbct_status *status, ++ enum mlxsw_reg_mbct_fsm_state *fsm_state, ++ struct netlink_ext_ack *extack) ++{ ++ bool second_try = false; ++ int err; ++ ++another_try: ++ mlxsw_reg_mbct_pack(linecard->mbct_pl, linecard->slot_index, ++ MLXSW_REG_MBCT_OP_QUERY_STATUS, 0, ++ false, false, NULL); ++ err = mlxsw_reg_query(linecard->linecards->mlxsw_core, MLXSW_REG(mbct), ++ linecard->mbct_pl); ++ if (err) { ++ NL_SET_ERR_MSG_MOD(extack, "Failed to query linecard INI status"); ++ return err; ++ } ++ mlxsw_reg_mbct_unpack(linecard->mbct_pl, NULL, status, fsm_state); ++ if (!second_try && ++ (*status == MLXSW_REG_MBCT_STATUS_ILLEGAL_OPERATION || ++ *fsm_state == MLXSW_REG_MBCT_FSM_STATE_ERROR)) { ++ err = __mlxsw_linecard_fix_fsm_state(linecard); ++ if (!err) { ++ second_try = true; ++ goto another_try; ++ } ++ } ++ return err; ++} ++ ++static int ++mlxsw_linecard_provision_data(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards, ++ struct mlxsw_linecard *linecard, ++ const struct mlxsw_linecard_ini_file *ini_file, ++ struct netlink_ext_ack *extack) ++{ ++ enum mlxsw_reg_mbct_fsm_state fsm_state; ++ enum mlxsw_reg_mbct_status status; ++ size_t size_left; ++ const u8 *data; ++ int err; ++ ++ size_left = le16_to_cpu(ini_file->size); ++ data = ini_file->data; ++ while (size_left) { ++ size_t data_size = MLXSW_REG_MBCT_DATA_LEN; ++ bool is_last = false; ++ ++ if (size_left <= MLXSW_REG_MBCT_DATA_LEN) { ++ data_size = size_left; ++ is_last = true; ++ } ++ ++ mlxsw_reg_mbct_pack(linecard->mbct_pl, linecard->slot_index, ++ MLXSW_REG_MBCT_OP_DATA_TRANSFER, data_size, ++ is_last, false, data); ++ err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(mbct), ++ linecard->mbct_pl); ++ if (err) { ++ NL_SET_ERR_MSG_MOD(extack, "Failed to transfer linecard INI data"); ++ return err; ++ } ++ mlxsw_reg_mbct_unpack(linecard->mbct_pl, NULL, ++ &status, &fsm_state); ++ if ((!is_last && status != MLXSW_REG_MBCT_STATUS_PART_DATA) || ++ (is_last && status != MLXSW_REG_MBCT_STATUS_LAST_DATA)) { ++ NL_SET_ERR_MSG_MOD(extack, "Failed to transfer linecard INI data"); ++ mlxsw_linecard_fix_fsm_state(linecard, fsm_state); ++ return -EINVAL; ++ } ++ size_left -= data_size; ++ data += data_size; ++ } ++ ++ return 0; ++} ++ ++int mlxsw_linecard_bct_process(struct mlxsw_core *mlxsw_core, ++ const char *mbct_pl) ++{ ++ struct mlxsw_linecards *linecards = mlxsw_core_linecards(mlxsw_core); ++ enum mlxsw_reg_mbct_fsm_state fsm_state; ++ enum mlxsw_reg_mbct_status status; ++ struct mlxsw_linecard *linecard; ++ u8 slot_index; ++ int err; ++ ++ mlxsw_reg_mbct_unpack(mbct_pl, &slot_index, &status, &fsm_state); ++ if (slot_index > linecards->count) ++ return -EINVAL; ++ linecard = mlxsw_linecard_get(linecards, slot_index); ++ if (status == MLXSW_REG_MBCT_STATUS_ACTIVATION_FAILED) { ++ dev_err(linecards->bus_info->dev, "linecard %u: Failed to activate INI", ++ linecard->slot_index); ++ err = -EINVAL; ++ goto fix_fsm_err_out; ++ } ++ return 0; ++ ++fix_fsm_err_out: ++ mlxsw_linecard_fix_fsm_state(linecard, fsm_state); ++ mlxsw_linecard_provision_fail(linecard); ++ return err; ++} ++EXPORT_SYMBOL(mlxsw_linecard_bct_process); ++ ++static int mlxsw_linecard_provision(struct devlink_linecard *devlink_linecard, ++ void *priv, const char *type, ++ const void *type_priv, ++ struct netlink_ext_ack *extack) ++{ ++ const struct mlxsw_linecard_ini_file *ini_file = type_priv; ++ enum mlxsw_reg_mbct_fsm_state fsm_state; ++ struct mlxsw_linecard *linecard = priv; ++ struct mlxsw_linecards *linecards; ++ enum mlxsw_reg_mbct_status status; ++ struct mlxsw_core *mlxsw_core; ++ int err; ++ ++ mutex_lock(&linecard->lock); ++ ++ linecards = linecard->linecards; ++ mlxsw_core = linecards->mlxsw_core; ++ mlxsw_reg_mbct_pack(linecard->mbct_pl, linecard->slot_index, ++ MLXSW_REG_MBCT_OP_ERASE_INI_IMAGE, 0, ++ false, false, NULL); ++ err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(mbct), linecard->mbct_pl); ++ if (err) { ++ NL_SET_ERR_MSG_MOD(extack, "Failed to erase linecard INI"); ++ goto err_out; ++ } ++ mlxsw_reg_mbct_unpack(linecard->mbct_pl, NULL, &status, &fsm_state); ++ if (status == MLXSW_REG_MBCT_STATUS_ERASE_FAILED) { ++ NL_SET_ERR_MSG_MOD(extack, "Failed to erase linecard INI"); ++ err = -EINVAL; ++ goto fix_fsm_err_out; ++ } ++ ++ err = mlxsw_linecard_provision_data(mlxsw_core, linecards, ++ linecard, ini_file, extack); ++ if (err) ++ goto err_out; ++ ++ mlxsw_reg_mbct_pack(linecard->mbct_pl, linecard->slot_index, ++ MLXSW_REG_MBCT_OP_ACTIVATE, 0, ++ false, true, NULL); ++ err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(mbct), linecard->mbct_pl); ++ if (err) { ++ NL_SET_ERR_MSG_MOD(extack, "Failed to activate linecard INI"); ++ goto err_out; ++ } ++ mlxsw_reg_mbct_unpack(linecard->mbct_pl, NULL, &status, &fsm_state); ++ if (status == MLXSW_REG_MBCT_STATUS_ACTIVATION_FAILED) { ++ NL_SET_ERR_MSG_MOD(extack, "Failed to activate linecard INI"); ++ goto fix_fsm_err_out; ++ } ++ ++ goto out; ++ ++fix_fsm_err_out: ++ mlxsw_linecard_fix_fsm_state(linecard, fsm_state); ++err_out: ++ mlxsw_linecard_provision_fail(linecard); ++out: ++ mutex_unlock(&linecard->lock); ++ return err; ++} ++ ++#define MLXSW_LINECARD_INI_WAIT_RETRIES 10 ++#define MLXSW_LINECARD_INI_WAIT_MS 500 ++ ++static int mlxsw_linecard_unprovision(struct devlink_linecard *devlink_linecard, ++ void *priv, ++ struct netlink_ext_ack *extack) ++{ ++ enum mlxsw_reg_mbct_fsm_state fsm_state; ++ struct mlxsw_linecard *linecard = priv; ++ struct mlxsw_linecards *linecards; ++ enum mlxsw_reg_mbct_status status; ++ unsigned int ini_wait_retries = 0; ++ struct mlxsw_core *mlxsw_core; ++ int err; ++ ++ mutex_lock(&linecard->lock); ++ ++ linecards = linecard->linecards; ++ mlxsw_core = linecard->linecards->mlxsw_core; ++ ++query_ini_status: ++ err = mlxsw_linecard_query_status(linecard, &status, ++ &fsm_state, extack); ++ if (err) ++ goto err_out; ++ ++ switch (fsm_state) { ++ case MLXSW_REG_MBCT_FSM_STATE_INI_IN_USE: ++ if (ini_wait_retries++ > MLXSW_LINECARD_INI_WAIT_RETRIES) { ++ NL_SET_ERR_MSG_MOD(extack, "Failed to wait for linecard INI to be not used"); ++ goto err_out; ++ } ++ mdelay(MLXSW_LINECARD_INI_WAIT_MS); ++ goto query_ini_status; ++ default: ++ break; ++ } ++ ++ mlxsw_reg_mbct_pack(linecard->mbct_pl, linecard->slot_index, ++ MLXSW_REG_MBCT_OP_ERASE_INI_IMAGE, 0, ++ false, false, NULL); ++ err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(mbct), ++ linecard->mbct_pl); ++ if (err) { ++ NL_SET_ERR_MSG_MOD(extack, "Failed to erase linecard INI"); ++ goto err_out; ++ } ++ mlxsw_reg_mbct_unpack(linecard->mbct_pl, NULL, &status, &fsm_state); ++ switch (status) { ++ case MLXSW_REG_MBCT_STATUS_ERASE_COMPLETE: ++ break; ++ default: ++ /* Should not happen */ ++ fallthrough; ++ case MLXSW_REG_MBCT_STATUS_ERASE_FAILED: ++ NL_SET_ERR_MSG_MOD(extack, "Failed to erase linecard INI"); ++ goto fix_fsm_err_out; ++ case MLXSW_REG_MBCT_STATUS_ERROR_INI_IN_USE: ++ NL_SET_ERR_MSG_MOD(extack, "Failed to erase linecard INI while being used"); ++ goto fix_fsm_err_out; ++ } ++ goto out; ++ ++fix_fsm_err_out: ++ mlxsw_linecard_fix_fsm_state(linecard, fsm_state); ++err_out: ++ mlxsw_linecard_provision_fail(linecard); ++out: ++ mutex_unlock(&linecard->lock); ++ return err; ++} ++ ++static unsigned int ++mlxsw_linecard_types_count(struct devlink_linecard *devlink_linecard, ++ void *priv) ++{ ++ struct mlxsw_linecard *linecard = priv; ++ ++ return linecard->linecards->types_info->count; ++} ++ ++static void mlxsw_linecard_types_get(struct devlink_linecard *devlink_linecard, ++ void *priv, unsigned int index, ++ const char **type, const void **type_priv) ++{ ++ struct mlxsw_linecard_types_info *types_info; ++ struct mlxsw_linecard_ini_file *ini_file; ++ struct mlxsw_linecard *linecard = priv; ++ ++ types_info = linecard->linecards->types_info; ++ ini_file = types_info->ini_files[index]; ++ *type = ini_file->format.name; ++ *type_priv = ini_file; ++} ++ ++static const struct devlink_linecard_ops mlxsw_linecard_ops = { ++ .provision = mlxsw_linecard_provision, ++ .unprovision = mlxsw_linecard_unprovision, ++ .types_count = mlxsw_linecard_types_count, ++ .types_get = mlxsw_linecard_types_get, ++}; ++ ++static int mlxsw_linecard_init(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards, ++ u8 slot_index) ++{ ++ struct devlink_linecard *devlink_linecard; ++ struct mlxsw_linecard *linecard; ++ int err; ++ ++ linecard = mlxsw_linecard_get(linecards, slot_index); ++ linecard->slot_index = slot_index; ++ linecard->linecards = linecards; ++ mutex_init(&linecard->lock); ++ ++ devlink_linecard = devlink_linecard_create(priv_to_devlink(mlxsw_core), ++ slot_index, &mlxsw_linecard_ops, ++ linecard); ++ if (IS_ERR(devlink_linecard)) ++ return PTR_ERR(devlink_linecard); ++ linecard->devlink_linecard = devlink_linecard; ++ ++ err = mlxsw_linecard_status_get_and_process(mlxsw_core, linecards, ++ linecard); ++ if (err) ++ goto err_status_get_and_process; ++ ++ return 0; ++ ++err_status_get_and_process: ++ devlink_linecard_destroy(linecard->devlink_linecard); ++ return err; ++} ++ ++static int mlxsw_linecard_event_delivery_set(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecard *linecard, ++ bool enable) ++{ ++ char mddq_pl[MLXSW_REG_MDDQ_LEN]; ++ ++ mlxsw_reg_mddq_slot_info_pack(mddq_pl, linecard->slot_index, enable); ++ return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mddq), mddq_pl); ++} ++ ++static int mlxsw_linecard_post_init(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards, ++ u8 slot_index) ++{ ++ struct mlxsw_linecard *linecard; ++ int err; ++ ++ linecard = mlxsw_linecard_get(linecards, slot_index); ++ linecard->slot_index = slot_index; ++ ++ err = mlxsw_linecard_event_delivery_set(mlxsw_core, linecard, true); ++ if (err) ++ return err; ++ ++ err = mlxsw_linecard_status_get_and_process(mlxsw_core, linecards, ++ linecard); ++ if (err) ++ goto err_status_get_and_process; ++ ++ return 0; ++ ++err_status_get_and_process: ++ mlxsw_linecard_event_delivery_set(mlxsw_core, linecard, false); ++ return err; ++} ++ ++static void mlxsw_linecard_pre_fini(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards, ++ u8 slot_index) ++{ ++ struct mlxsw_linecard *linecard; ++ ++ linecard = mlxsw_linecard_get(linecards, slot_index); ++ mlxsw_linecard_event_delivery_set(mlxsw_core, linecard, false); ++} ++ ++static void mlxsw_linecard_fini(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards, ++ u8 slot_index) ++{ ++ struct mlxsw_linecard *linecard; ++ ++ linecard = mlxsw_linecard_get(linecards, slot_index); ++ devlink_linecard_destroy(linecard->devlink_linecard); ++ mutex_destroy(&linecard->lock); ++} ++ ++#define MLXSW_LINECARDS_INI_BUNDLE_MINOR 2008 ++#define MLXSW_LINECARDS_INI_BUNDLE_MINOR_SUBMINOR 9999 ++#define MLXSW_LINECARDS_INI_BUNDLE_FILE \ ++ "mellanox/lc_ini_bundle_" \ ++ __stringify(MLXSW_LINECARDS_INI_BUNDLE_MINOR) "_" \ ++ __stringify(MLXSW_LINECARDS_INI_BUNDLE_MINOR_SUBMINOR) ".bin" ++#define MLXSW_LINECARDS_INI_BUNDLE_MAGIC "NVLCINI+" ++ ++static int mlxsw_linecard_types_init(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards) ++{ ++ struct mlxsw_linecard_types_info *types_info; ++ struct mlxsw_linecard_ini_file *ini_file; ++ const struct firmware *firmware; ++ unsigned int count; ++ u16 ini_file_size; ++ size_t magic_size; ++ const u8 *data; ++ size_t size; ++ int err; ++ ++ types_info = kzalloc(sizeof(*types_info), GFP_KERNEL); ++ if (!types_info) ++ return -ENOMEM; ++ linecards->types_info = types_info; ++ return 0; /* Skip for non-upstream flow. */ ++ err = request_firmware_direct(&firmware, ++ MLXSW_LINECARDS_INI_BUNDLE_FILE, ++ linecards->bus_info->dev); ++ if (err) { ++ dev_warn(linecards->bus_info->dev, "Could not request linecards INI file \"" MLXSW_LINECARDS_INI_BUNDLE_FILE "\", provisioning will not be possible\n"); ++ return 0; ++ } ++ ++ types_info->data_size = firmware->size; ++ types_info->data = kmemdup(firmware->data, firmware->size, GFP_KERNEL); ++ release_firmware(firmware); ++ if (!types_info->data) { ++ err = -ENOMEM; ++ goto free_types_info; ++ } ++ ++ data = types_info->data; ++ size = types_info->data_size; ++ magic_size = strlen(MLXSW_LINECARDS_INI_BUNDLE_MAGIC); ++ ++ if (size < magic_size || ++ memcmp(data, MLXSW_LINECARDS_INI_BUNDLE_MAGIC, magic_size)) ++ goto incorrect_inis_file_format; ++ data += magic_size; ++ size -= magic_size; ++ count = 0; ++ ++ while (size > 0) { ++ if (size < sizeof(*ini_file)) ++ goto incorrect_inis_file_format; ++ ini_file = (struct mlxsw_linecard_ini_file *) data; ++ ini_file_size = le16_to_cpu(ini_file->size); ++ if (ini_file_size > size || ini_file_size % 4) ++ goto incorrect_inis_file_format; ++ data += ini_file_size + sizeof(__le16); ++ size -= ini_file_size + sizeof(__le16); ++ count++; ++ } ++ if (size) ++ goto incorrect_inis_file_format; ++ ++ types_info->ini_files = kmalloc_array(count, sizeof(ini_file), ++ GFP_KERNEL); ++ if (!types_info->ini_files) { ++ err = -ENOMEM; ++ goto free_types_info; ++ } ++ ++ data = types_info->data + magic_size; ++ size = types_info->data_size - magic_size; ++ count = 0; ++ ++ while (size) { ++ int i; ++ ++ ini_file = (struct mlxsw_linecard_ini_file *) data; ++ ini_file_size = le16_to_cpu(ini_file->size); ++ for (i = 0; i < ini_file_size / 4; i++) { ++ u32 *val = &((u32 *) ini_file->data)[i]; ++ ++ *val = swab32(*val); ++ } ++ types_info->ini_files[count] = ini_file; ++ data += ini_file_size + sizeof(__le16); ++ size -= ini_file_size + sizeof(__le16); ++ count++; ++ } ++ ++ types_info->count = count; ++ return 0; ++ ++incorrect_inis_file_format: ++ dev_warn(linecards->bus_info->dev, "Incorrect linecards INIs file format, provisioning will not be possible\n"); ++ return 0; ++ ++free_types_info: ++ kfree(types_info); ++ return err; ++} ++ ++static void mlxsw_linecard_types_fini(struct mlxsw_linecards *linecards) ++{ ++ struct mlxsw_linecard_types_info *types_info = linecards->types_info; ++ ++ kfree(types_info->ini_files); ++ kfree(types_info->data); ++ kfree(types_info); ++} ++ ++int mlxsw_linecards_init(struct mlxsw_core *mlxsw_core, ++ const struct mlxsw_bus_info *bus_info, ++ struct mlxsw_linecards **p_linecards) ++{ ++ char mgpir_pl[MLXSW_REG_MGPIR_LEN]; ++ struct mlxsw_linecards *linecards; ++ u8 slot_count; ++ int err; ++ int i; ++ ++ mlxsw_reg_mgpir_pack(mgpir_pl, 0); ++ err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mgpir), mgpir_pl); ++ if (err) ++ return err; ++ ++ mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, ++ NULL, &slot_count); ++ if (!slot_count) { ++ *p_linecards = NULL; ++ return 0; ++ } ++ ++ linecards = kzalloc(struct_size(linecards, linecards, slot_count), ++ GFP_KERNEL); ++ if (!linecards) ++ return -ENOMEM; ++ linecards->count = slot_count; ++ linecards->mlxsw_core = mlxsw_core; ++ linecards->bus_info = bus_info; ++ ++ linecards->wq = alloc_workqueue("mlxsw_linecards", 0, 0); ++ if (!linecards->wq) { ++ err = ENOMEM; ++ goto err_wq_alloc; ++ } ++ ++ err = mlxsw_linecard_types_init(mlxsw_core, linecards); ++ if (err) ++ goto err_types_init; ++ ++ for (i = 0; i < linecards->count; i++) { ++ err = mlxsw_linecard_init(mlxsw_core, linecards, i + 1); ++ if (err) ++ goto err_linecard_init; ++ } ++ ++ *p_linecards = linecards; ++ ++ return 0; ++ ++err_linecard_init: ++ for (i--; i >= 0; i--) ++ mlxsw_linecard_fini(mlxsw_core, linecards, i + 1); ++err_types_init: ++ destroy_workqueue(linecards->wq); ++err_wq_alloc: ++ kfree(linecards); ++ ++ return err; ++} ++ ++int mlxsw_linecards_post_init(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards) ++{ ++ int err; ++ int i; ++ ++ if (!linecards) ++ return 0; ++ ++ for (i = 0; i < linecards->count; i++) { ++ err = mlxsw_linecard_post_init(mlxsw_core, linecards, i + 1); ++ if (err) ++ goto err_linecard_post_init; ++ } ++ return 0; ++ ++err_linecard_post_init: ++ for (i--; i >= 0; i--) ++ mlxsw_linecard_pre_fini(mlxsw_core, linecards, i + 1); ++ ++ return err; ++} ++ ++void mlxsw_linecards_pre_fini(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards) ++{ ++ int i; ++ ++ if (!linecards) ++ return; ++ for (i = 0; i < linecards->count; i++) ++ mlxsw_linecard_pre_fini(mlxsw_core, linecards, i + 1); ++ /* Make sure all scheduled events are processed */ ++ mlxsw_core_flush_owq(); ++} ++ ++void mlxsw_linecards_fini(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards) ++{ ++ int i; ++ ++ if (!linecards) ++ return; ++ for (i = 0; i < linecards->count; i++) ++ mlxsw_linecard_fini(mlxsw_core, linecards, i + 1); ++ mlxsw_linecard_types_fini(linecards); ++ destroy_workqueue(linecards->wq); ++ kfree(linecards); ++} ++ ++MODULE_FIRMWARE(MLXSW_LINECARDS_INI_BUNDLE_FILE); +diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +index 5066fcc46..d7a230828 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +@@ -2076,6 +2076,72 @@ static void mlxsw_sp_pude_event_func(const struct mlxsw_reg_info *reg, + } + } + ++struct mlxsw_sp_linecard_status_event { ++ struct mlxsw_core *mlxsw_core; ++ char mddq_pl[MLXSW_REG_MDDQ_LEN]; ++ struct work_struct work; ++}; ++ ++static void mlxsw_sp_linecard_status_event_work(struct work_struct *work) ++{ ++ struct mlxsw_sp_linecard_status_event *event; ++ struct mlxsw_core *mlxsw_core; ++ ++ event = container_of(work, struct mlxsw_sp_linecard_status_event, work); ++ mlxsw_core = event->mlxsw_core; ++ mlxsw_linecard_status_process(mlxsw_core, event->mddq_pl); ++ kfree(event); ++} ++ ++static void ++mlxsw_sp_linecard_status_listener_func(const struct mlxsw_reg_info *reg, ++ char *mddq_pl, void *priv) ++{ ++ struct mlxsw_sp_linecard_status_event *event; ++ struct mlxsw_sp *mlxsw_sp = priv; ++ ++ event = kmalloc(sizeof(*event), GFP_ATOMIC); ++ if (!event) ++ return; ++ event->mlxsw_core = mlxsw_sp->core; ++ memcpy(event->mddq_pl, mddq_pl, sizeof(event->mddq_pl)); ++ INIT_WORK(&event->work, mlxsw_sp_linecard_status_event_work); ++ mlxsw_core_schedule_work(&event->work); ++} ++ ++struct mlxsw_sp_linecard_bct_event { ++ struct mlxsw_core *mlxsw_core; ++ char mbct_pl[MLXSW_REG_MBCT_LEN]; ++ struct work_struct work; ++}; ++ ++static void mlxsw_sp_linecard_bct_event_work(struct work_struct *work) ++{ ++ struct mlxsw_sp_linecard_bct_event *event; ++ struct mlxsw_core *mlxsw_core; ++ ++ event = container_of(work, struct mlxsw_sp_linecard_bct_event, work); ++ mlxsw_core = event->mlxsw_core; ++ mlxsw_linecard_bct_process(mlxsw_core, event->mbct_pl); ++ kfree(event); ++} ++ ++static void ++mlxsw_sp_linecard_bct_listener_func(const struct mlxsw_reg_info *reg, ++ char *mbct_pl, void *priv) ++{ ++ struct mlxsw_sp_linecard_bct_event *event; ++ struct mlxsw_sp *mlxsw_sp = priv; ++ ++ event = kmalloc(sizeof(*event), GFP_ATOMIC); ++ if (!event) ++ return; ++ event->mlxsw_core = mlxsw_sp->core; ++ memcpy(event->mbct_pl, mbct_pl, sizeof(event->mbct_pl)); ++ INIT_WORK(&event->work, mlxsw_sp_linecard_bct_event_work); ++ mlxsw_core_schedule_work(&event->work); ++} ++ + static void mlxsw_sp1_ptp_fifo_event_func(struct mlxsw_sp *mlxsw_sp, + char *mtpptr_pl, bool ingress) + { +@@ -2206,6 +2272,8 @@ void mlxsw_sp_sample_receive(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb, + static const struct mlxsw_listener mlxsw_sp_listener[] = { + /* Events */ + MLXSW_SP_EVENTL(mlxsw_sp_pude_event_func, PUDE), ++ MLXSW_SP_EVENTL(mlxsw_sp_linecard_status_listener_func, DSDSC), ++ MLXSW_SP_EVENTL(mlxsw_sp_linecard_bct_listener_func, BCTOE), + /* L2 traps */ + MLXSW_SP_RXL_NO_MARK(FID_MISS, TRAP_TO_CPU, FID_MISS, false), + /* L3 traps */ +diff --git a/drivers/net/ethernet/mellanox/mlxsw/trap.h b/drivers/net/ethernet/mellanox/mlxsw/trap.h +index 57f9e2460..f3e522de2 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/trap.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/trap.h +@@ -132,6 +132,12 @@ enum mlxsw_event_trap_id { + MLXSW_TRAP_ID_PTP_ING_FIFO = 0x2D, + /* PTP Egress FIFO has a new entry */ + MLXSW_TRAP_ID_PTP_EGR_FIFO = 0x2E, ++ /* Downstream Device Status Change */ ++ MLXSW_TRAP_ID_DSDSC = 0x321, ++ /* Binary Code Transfer Operation Executed Event */ ++ MLXSW_TRAP_ID_BCTOE = 0x322, ++ /* Port mapping change */ ++ MLXSW_TRAP_ID_PMLPE = 0x32E, + }; + + #endif /* _MLXSW_TRAP_H */ +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0136-mlxsw-core_linecards-Implement-line-card-activation-.patch b/platform/mellanox/non-upstream-patches/patches/0136-mlxsw-core_linecards-Implement-line-card-activation-.patch new file mode 100644 index 000000000000..b889ad938776 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0136-mlxsw-core_linecards-Implement-line-card-activation-.patch @@ -0,0 +1,205 @@ +From f2ecea65348e527345e9e7a59766162eb2297a53 Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Fri, 22 Jan 2021 14:45:06 +0100 +Subject: [PATCH] mlxsw: core_linecards: Implement line card activation process + +Allow to process events generated upon line card getting "ready" and +"active". + +Signed-off-by: Jiri Pirko +--- + drivers/net/ethernet/mellanox/mlxsw/core.h | 3 + + .../ethernet/mellanox/mlxsw/core_linecards.c | 85 +++++++++++++++++-- + 2 files changed, 80 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h +index d3c5d8289..ecd91bb8c 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.h +@@ -521,6 +521,9 @@ struct mlxsw_linecard { + char read_name[MLXSW_REG_MDDQ_SLOT_ACII_NAME_LEN]; + char mbct_pl[MLXSW_REG_MBCT_LEN]; /* too big for stack */ + bool provisioned; ++ bool ready; ++ bool active; ++ bool unprovision_done; + }; + + struct mlxsw_linecard_types_info; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c b/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c +index a324ce243..134437f49 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c +@@ -67,6 +67,8 @@ static const char *mlxsw_linecard_type_name(struct mlxsw_linecard *linecard) + static void mlxsw_linecard_provision_fail(struct mlxsw_linecard *linecard) + { + linecard->provisioned = false; ++ linecard->ready = false; ++ linecard->active = false; + devlink_linecard_provision_fail(linecard->devlink_linecard); + } + +@@ -94,10 +96,51 @@ static void mlxsw_linecard_provision_clear(struct mlxsw_linecard *linecard) + devlink_linecard_provision_clear(linecard->devlink_linecard); + } + ++static int mlxsw_linecard_ready_set(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecard *linecard) ++{ ++ char mddc_pl[MLXSW_REG_MDDC_LEN]; ++ int err; ++ ++ mlxsw_reg_mddc_pack(mddc_pl, linecard->slot_index, false, true); ++ err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(mddc), mddc_pl); ++ if (err) ++ return err; ++ linecard->ready = true; ++ return 0; ++} ++ ++static int mlxsw_linecard_ready_clear(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecard *linecard) ++{ ++ char mddc_pl[MLXSW_REG_MDDC_LEN]; ++ int err; ++ ++ mlxsw_reg_mddc_pack(mddc_pl, linecard->slot_index, false, false); ++ err = mlxsw_reg_write(mlxsw_core, MLXSW_REG(mddc), mddc_pl); ++ if (err) ++ return err; ++ linecard->ready = false; ++ return 0; ++} ++ ++static void mlxsw_linecard_active_set(struct mlxsw_linecard *linecard) ++{ ++ linecard->active = true; ++ devlink_linecard_activate(linecard->devlink_linecard); ++} ++ ++static void mlxsw_linecard_active_clear(struct mlxsw_linecard *linecard) ++{ ++ linecard->active = false; ++ devlink_linecard_deactivate(linecard->devlink_linecard); ++} ++ + static int __mlxsw_linecard_status_process(struct mlxsw_core *mlxsw_core, + struct mlxsw_linecards *linecards, + struct mlxsw_linecard *linecard, +- const char *mddq_pl) ++ const char *mddq_pl, ++ bool process_provision_only) + { + enum mlxsw_reg_mddq_card_type card_type; + enum mlxsw_reg_mddq_ready ready; +@@ -132,6 +175,27 @@ static int __mlxsw_linecard_status_process(struct mlxsw_core *mlxsw_core, + goto out; + } + ++ if (!process_provision_only && !linecard->unprovision_done && ++ ready == MLXSW_REG_MDDQ_READY_READY && !linecard->ready) { ++ err = mlxsw_linecard_ready_set(mlxsw_core, linecard); ++ if (err) ++ goto out; ++ } ++ ++ if (!process_provision_only && !linecard->unprovision_done && active && ++ linecard->active != active && linecard->ready) ++ mlxsw_linecard_active_set(linecard); ++ ++ if (!process_provision_only && !active && linecard->active != active) ++ mlxsw_linecard_active_clear(linecard); ++ ++ if (!process_provision_only && ready != MLXSW_REG_MDDQ_READY_READY && ++ linecard->ready) { ++ err = mlxsw_linecard_ready_clear(mlxsw_core, linecard); ++ if (err) ++ goto out; ++ } ++ + if (!provisioned && linecard->provisioned != provisioned) + mlxsw_linecard_provision_clear(linecard); + +@@ -146,13 +210,14 @@ int mlxsw_linecard_status_process(struct mlxsw_core *mlxsw_core, + struct mlxsw_linecards *linecards = mlxsw_core_linecards(mlxsw_core); + + return __mlxsw_linecard_status_process(mlxsw_core, linecards, NULL, +- mddq_pl); ++ mddq_pl, false); + } + EXPORT_SYMBOL(mlxsw_linecard_status_process); + + static int mlxsw_linecard_status_get_and_process(struct mlxsw_core *mlxsw_core, + struct mlxsw_linecards *linecards, +- struct mlxsw_linecard *linecard) ++ struct mlxsw_linecard *linecard, ++ bool process_provision_only) + { + char mddq_pl[MLXSW_REG_MDDQ_LEN]; + int err; +@@ -163,7 +228,7 @@ static int mlxsw_linecard_status_get_and_process(struct mlxsw_core *mlxsw_core, + return err; + + return __mlxsw_linecard_status_process(mlxsw_core, linecards, linecard, +- mddq_pl); ++ mddq_pl, process_provision_only); + } + + static int __mlxsw_linecard_fix_fsm_state(struct mlxsw_linecard *linecard) +@@ -308,6 +373,7 @@ static int mlxsw_linecard_provision(struct devlink_linecard *devlink_linecard, + + mutex_lock(&linecard->lock); + ++ linecard->unprovision_done = false; + linecards = linecard->linecards; + mlxsw_core = linecards->mlxsw_core; + mlxsw_reg_mbct_pack(linecard->mbct_pl, linecard->slot_index, +@@ -416,6 +482,7 @@ static int mlxsw_linecard_unprovision(struct devlink_linecard *devlink_linecard, + NL_SET_ERR_MSG_MOD(extack, "Failed to erase linecard INI while being used"); + goto fix_fsm_err_out; + } ++ linecard->unprovision_done = true; + goto out; + + fix_fsm_err_out: +@@ -478,7 +545,7 @@ static int mlxsw_linecard_init(struct mlxsw_core *mlxsw_core, + linecard->devlink_linecard = devlink_linecard; + + err = mlxsw_linecard_status_get_and_process(mlxsw_core, linecards, +- linecard); ++ linecard, true); + if (err) + goto err_status_get_and_process; + +@@ -514,7 +581,7 @@ static int mlxsw_linecard_post_init(struct mlxsw_core *mlxsw_core, + return err; + + err = mlxsw_linecard_status_get_and_process(mlxsw_core, linecards, +- linecard); ++ linecard, false); + if (err) + goto err_status_get_and_process; + +@@ -533,6 +600,10 @@ static void mlxsw_linecard_pre_fini(struct mlxsw_core *mlxsw_core, + + linecard = mlxsw_linecard_get(linecards, slot_index); + mlxsw_linecard_event_delivery_set(mlxsw_core, linecard, false); ++ /* Make sure all scheduled events are processed */ ++ mlxsw_core_flush_owq(); ++ if (linecard->active) ++ mlxsw_linecard_active_clear(linecard); + } + + static void mlxsw_linecard_fini(struct mlxsw_core *mlxsw_core, +@@ -754,8 +825,6 @@ void mlxsw_linecards_pre_fini(struct mlxsw_core *mlxsw_core, + return; + for (i = 0; i < linecards->count; i++) + mlxsw_linecard_pre_fini(mlxsw_core, linecards, i + 1); +- /* Make sure all scheduled events are processed */ +- mlxsw_core_flush_owq(); + } + + void mlxsw_linecards_fini(struct mlxsw_core *mlxsw_core, +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0137-mlxsw-core-Extend-driver-ops-by-remove-selected-port.patch b/platform/mellanox/non-upstream-patches/patches/0137-mlxsw-core-Extend-driver-ops-by-remove-selected-port.patch new file mode 100644 index 000000000000..d8abff2cb1c2 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0137-mlxsw-core-Extend-driver-ops-by-remove-selected-port.patch @@ -0,0 +1,98 @@ +From 063ca0577ceb2355884555d96a24a740a2c03bdb Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 22 Dec 2021 16:26:43 +0000 +Subject: [PATCH] mlxsw: core: Extend driver ops by remove selected ports op + +In case of line card implementation, the core has to have a way to +remove relevant ports manually. Extend the Spectrum driver ops by an op +that implements port removal of selected ports upon request. + +Signed-off-by: Jiri Pirko +--- + drivers/net/ethernet/mellanox/mlxsw/core.c | 9 +++++++++ + drivers/net/ethernet/mellanox/mlxsw/core.h | 8 ++++++++ + drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 15 +++++++++++++++ + 3 files changed, 32 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c +index 246db548f..2b4f9844b 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.c +@@ -2870,6 +2870,15 @@ mlxsw_core_port_devlink_port_get(struct mlxsw_core *mlxsw_core, + } + EXPORT_SYMBOL(mlxsw_core_port_devlink_port_get); + ++void mlxsw_core_ports_remove_selected(struct mlxsw_core *mlxsw_core, ++ bool (*selector)(void *priv, u16 local_port), ++ void *priv) ++{ ++ if (WARN_ON(!mlxsw_core->driver->ports_remove_selected)) ++ return; ++ mlxsw_core->driver->ports_remove_selected(mlxsw_core, selector, priv); ++} ++ + struct mlxsw_env *mlxsw_core_env(const struct mlxsw_core *mlxsw_core) + { + return mlxsw_core->env; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h +index ecd91bb8c..70f97ef74 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.h +@@ -223,6 +223,10 @@ enum devlink_port_type mlxsw_core_port_type_get(struct mlxsw_core *mlxsw_core, + struct devlink_port * + mlxsw_core_port_devlink_port_get(struct mlxsw_core *mlxsw_core, + u8 local_port); ++void mlxsw_core_ports_remove_selected(struct mlxsw_core *mlxsw_core, ++ bool (*selector)(void *priv, ++ u16 local_port), ++ void *priv); + struct mlxsw_env *mlxsw_core_env(const struct mlxsw_core *mlxsw_core); + int mlxsw_core_module_max_width(struct mlxsw_core *mlxsw_core, u8 module); + +@@ -296,6 +300,10 @@ struct mlxsw_driver { + unsigned int count, struct netlink_ext_ack *extack); + int (*port_unsplit)(struct mlxsw_core *mlxsw_core, u8 local_port, + struct netlink_ext_ack *extack); ++ void (*ports_remove_selected)(struct mlxsw_core *mlxsw_core, ++ bool (*selector)(void *priv, ++ u16 local_port), ++ void *priv); + int (*sb_pool_get)(struct mlxsw_core *mlxsw_core, + unsigned int sb_index, u16 pool_index, + struct devlink_sb_pool_info *pool_info); +diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +index d7a230828..75b418fbe 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +@@ -1736,6 +1736,20 @@ static void mlxsw_sp_ports_remove(struct mlxsw_sp *mlxsw_sp) + mlxsw_sp->ports = NULL; + } + ++static void ++mlxsw_sp_ports_remove_selected(struct mlxsw_core *mlxsw_core, ++ bool (*selector)(void *priv, u16 local_port), ++ void *priv) ++{ ++ struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); ++ unsigned int max_ports = mlxsw_core_max_ports(mlxsw_core); ++ int i; ++ ++ for (i = 1; i < max_ports; i++) ++ if (mlxsw_sp_port_created(mlxsw_sp, i) && selector(priv, i)) ++ mlxsw_sp_port_remove(mlxsw_sp, i); ++} ++ + static int mlxsw_sp_ports_create(struct mlxsw_sp *mlxsw_sp) + { + unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core); +@@ -3370,6 +3384,7 @@ static struct mlxsw_driver mlxsw_sp3_driver = { + .basic_trap_groups_set = mlxsw_sp_basic_trap_groups_set, + .port_split = mlxsw_sp_port_split, + .port_unsplit = mlxsw_sp_port_unsplit, ++ .ports_remove_selected = mlxsw_sp_ports_remove_selected, + .sb_pool_get = mlxsw_sp_sb_pool_get, + .sb_pool_set = mlxsw_sp_sb_pool_set, + .sb_port_pool_get = mlxsw_sp_sb_port_pool_get, +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0138-mlxsw-spectrum-Add-port-to-linecard-mapping.patch b/platform/mellanox/non-upstream-patches/patches/0138-mlxsw-spectrum-Add-port-to-linecard-mapping.patch new file mode 100644 index 000000000000..0e886cc29040 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0138-mlxsw-spectrum-Add-port-to-linecard-mapping.patch @@ -0,0 +1,152 @@ +From fd68af1d7a7c58c3f7db6ec95aba528137ec4c2d Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Mon, 3 Jan 2022 11:22:42 +0000 +Subject: [PATCH] mlxsw: spectrum: Add port to linecard mapping + +For each port get slot_index using PMLP register. For ports residing +on a linecard, identify it with the linecard by setting mapping +using devlink_port_linecard_set() helper. Use linecard slot index for +PMTDB register queries. + +Signed-off-by: Jiri Pirko +--- + drivers/net/ethernet/mellanox/mlxsw/core.c | 18 ++++++++++++++---- + drivers/net/ethernet/mellanox/mlxsw/core.h | 3 ++- + drivers/net/ethernet/mellanox/mlxsw/minimal.c | 2 +- + drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 2 +- + drivers/net/ethernet/mellanox/mlxsw/switchib.c | 2 +- + drivers/net/ethernet/mellanox/mlxsw/switchx2.c | 2 +- + 6 files changed, 20 insertions(+), 9 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c +index 2b4f9844b..68ef007ac 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.c +@@ -48,6 +48,7 @@ struct mlxsw_core_port { + struct devlink_port devlink_port; + void *port_driver_priv; + u8 local_port; ++ struct mlxsw_linecard *linecard; + }; + + void *mlxsw_core_port_driver_priv(struct mlxsw_core_port *mlxsw_core_port) +@@ -2723,7 +2724,7 @@ EXPORT_SYMBOL(mlxsw_core_res_get); + + static int __mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u8 local_port, + enum devlink_port_flavour flavour, +- u32 port_number, bool split, ++ u8 slot_index, u32 port_number, bool split, + u32 split_port_subnumber, + bool splittable, u32 lanes, + const unsigned char *switch_id, +@@ -2746,6 +2747,15 @@ static int __mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u8 local_port, + attrs.switch_id.id_len = switch_id_len; + mlxsw_core_port->local_port = local_port; + devlink_port_attrs_set(devlink_port, &attrs); ++ if (slot_index) { ++ struct mlxsw_linecard *linecard; ++ ++ linecard = mlxsw_linecard_get(mlxsw_core->linecards, ++ slot_index); ++ mlxsw_core_port->linecard = linecard; ++ devlink_port_linecard_set(devlink_port, ++ linecard->devlink_linecard); ++ } + err = devlink_port_register(devlink, devlink_port, local_port); + if (err) + memset(mlxsw_core_port, 0, sizeof(*mlxsw_core_port)); +@@ -2763,14 +2773,14 @@ static void __mlxsw_core_port_fini(struct mlxsw_core *mlxsw_core, u8 local_port) + } + + int mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u8 local_port, +- u32 port_number, bool split, ++ u8 slot_index, u32 port_number, bool split, + u32 split_port_subnumber, + bool splittable, u32 lanes, + const unsigned char *switch_id, + unsigned char switch_id_len) + { + return __mlxsw_core_port_init(mlxsw_core, local_port, +- DEVLINK_PORT_FLAVOUR_PHYSICAL, ++ DEVLINK_PORT_FLAVOUR_PHYSICAL, slot_index, + port_number, split, split_port_subnumber, + splittable, lanes, + switch_id, switch_id_len); +@@ -2794,7 +2804,7 @@ int mlxsw_core_cpu_port_init(struct mlxsw_core *mlxsw_core, + + err = __mlxsw_core_port_init(mlxsw_core, MLXSW_PORT_CPU_PORT, + DEVLINK_PORT_FLAVOUR_CPU, +- 0, false, 0, false, 0, ++ 0, 0, false, 0, false, 0, + switch_id, switch_id_len); + if (err) + return err; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h +index 70f97ef74..8e738ddb3 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.h +@@ -202,7 +202,8 @@ void mlxsw_core_lag_mapping_clear(struct mlxsw_core *mlxsw_core, + + void *mlxsw_core_port_driver_priv(struct mlxsw_core_port *mlxsw_core_port); + int mlxsw_core_port_init(struct mlxsw_core *mlxsw_core, u8 local_port, +- u32 port_number, bool split, u32 split_port_subnumber, ++ u8 slot_index, u32 port_number, bool split, ++ u32 split_port_subnumber, + bool splittable, u32 lanes, + const unsigned char *switch_id, + unsigned char switch_id_len); +diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +index 104f1ba02..30925f573 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +@@ -210,7 +210,7 @@ mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u8 local_port, u8 module) + struct net_device *dev; + int err; + +- err = mlxsw_core_port_init(mlxsw_m->core, local_port, ++ err = mlxsw_core_port_init(mlxsw_m->core, local_port, 0, + module + 1, false, 0, false, + 0, mlxsw_m->base_mac, + sizeof(mlxsw_m->base_mac)); +diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +index 75b418fbe..31eec40a3 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +@@ -1399,7 +1399,7 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, + int err; + + splittable = lanes > 1 && !split; +- err = mlxsw_core_port_init(mlxsw_sp->core, local_port, ++ err = mlxsw_core_port_init(mlxsw_sp->core, local_port, 0, + port_mapping->module + 1, split, + port_mapping->lane / lanes, + splittable, lanes, +diff --git a/drivers/net/ethernet/mellanox/mlxsw/switchib.c b/drivers/net/ethernet/mellanox/mlxsw/switchib.c +index 1e561132e..090b9a103 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/switchib.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/switchib.c +@@ -280,7 +280,7 @@ static int mlxsw_sib_port_create(struct mlxsw_sib *mlxsw_sib, u8 local_port, + { + int err; + +- err = mlxsw_core_port_init(mlxsw_sib->core, local_port, ++ err = mlxsw_core_port_init(mlxsw_sib->core, local_port, 0, + module + 1, false, 0, false, 0, + mlxsw_sib->hw_id, sizeof(mlxsw_sib->hw_id)); + if (err) { +diff --git a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c +index 131b2a53d..bf8a54776 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c +@@ -1085,7 +1085,7 @@ static int mlxsw_sx_port_eth_create(struct mlxsw_sx *mlxsw_sx, u8 local_port, + { + int err; + +- err = mlxsw_core_port_init(mlxsw_sx->core, local_port, ++ err = mlxsw_core_port_init(mlxsw_sx->core, local_port, 0, + module + 1, false, 0, false, 0, + mlxsw_sx->hw_id, sizeof(mlxsw_sx->hw_id)); + if (err) { +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0139-mlxsw-reg-Introduce-Management-Temperature-Extended-.patch b/platform/mellanox/non-upstream-patches/patches/0139-mlxsw-reg-Introduce-Management-Temperature-Extended-.patch new file mode 100644 index 000000000000..1a532d88fa61 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0139-mlxsw-reg-Introduce-Management-Temperature-Extended-.patch @@ -0,0 +1,105 @@ +From a719653b2a7f0943e757c04dab73df324e469436 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 12 May 2021 22:57:37 +0300 +Subject: [PATCH] mlxsw: reg: Introduce Management Temperature Extended + Capabilities Register + +Introduce new register MTECR (Management Temperature Extended +Capabilities Register). This register exposes the capabilities of the +device and system temperature sensing. It provides information for +all possible temperature sensors that are on the system. + +Signed-off-by: Vadim Pasternak +Signed-off-by: Jiri Pirko +--- + drivers/net/ethernet/mellanox/mlxsw/reg.h | 67 +++++++++++++++++++++++ + 1 file changed, 67 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h +index 89b21910f..c1ce0b42e 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h +@@ -10297,6 +10297,72 @@ mlxsw_reg_mgpir_unpack(char *payload, u8 *num_of_devices, + *num_of_slots = mlxsw_reg_mgpir_num_of_slots_get(payload); + } + ++/* MTECR - Management Temperature Extended Capabilities Register ++ * ------------------------------------------------------------- ++ * MTECR register exposes the capabilities of the device and system ++ * temperature sensing. ++ */ ++#define MLXSW_REG_MTECR_ID 0x9109 ++#define MLXSW_REG_MTECR_LEN 0x60 ++#define MLXSW_REG_MTECR_SENSOR_MAP_LEN 0x58 ++ ++MLXSW_REG_DEFINE(mtecr, MLXSW_REG_MTECR_ID, MLXSW_REG_MTECR_LEN); ++ ++/* reg_mtecr_last_sensor. ++ * Last sensor index that is available in the system to read from. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mtecr, last_sensor, 0x00, 16, 12); ++ ++/* reg_mtecr_sensor_count. ++ * Number of sensors supported by the device. ++ * This includes the ASIC, ambient sensors, Gearboxes etc. ++ * QSFP module sensors are not included. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mtecr, sensor_count, 0x00, 0, 12); ++ ++/* reg_mtecr_slot_index. ++ * Slot index (0: Main board). ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, mtecr, slot_index, 0x04, 28, 4); ++ ++/* reg_mtecr_internal_sensor_count. ++ * Number of sensors supported by the device that are in the ASIC. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mtecr, internal_sensor_count, 0x04, 0, 7); ++ ++/* reg_mtecr_sensor_map. ++ * Mapping of system sensors supported by the device. Each bit represents a ++ * sensor. This field is size variable based on the last_sensor field and in ++ * granularity of 32 bits. ++ * 0: Not connected or not supported ++ * 1: Supports temperature measurements ++ * ++ */ ++MLXSW_ITEM_BIT_ARRAY(reg, mtecr, sensor_map, 0x08, MLXSW_REG_MTECR_SENSOR_MAP_LEN, 1); ++ ++static inline void mlxsw_reg_mtecr_pack(char *payload, u8 slot_index) ++{ ++ MLXSW_REG_ZERO(mtecr, payload); ++ mlxsw_reg_mtecr_slot_index_set(payload, slot_index); ++} ++ ++static inline void mlxsw_reg_mtecr_unpack(char *payload, u16 *sensor_count, ++ u16 *last_sensor, ++ u8 *internal_sensor_count) ++{ ++ if (sensor_count) ++ *sensor_count = mlxsw_reg_mtecr_sensor_count_get(payload); ++ if (last_sensor) ++ *last_sensor = mlxsw_reg_mtecr_last_sensor_get(payload); ++ if (internal_sensor_count) ++ *internal_sensor_count = ++ mlxsw_reg_mtecr_internal_sensor_count_get(payload); ++} ++ + /* MBCT - Management Binary Code Transfer Register + * ----------------------------------------------- + * This register allows to transfer binary codes from the Host to +@@ -11884,6 +11950,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = { + MLXSW_REG(mtptpt), + MLXSW_REG(mfgd), + MLXSW_REG(mgpir), ++ MLXSW_REG(mtecr), + MLXSW_REG(mbct), + MLXSW_REG(mddq), + MLXSW_REG(mddc), +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0140-mlxsw-core-Add-APIs-for-thermal-sensor-mapping.patch b/platform/mellanox/non-upstream-patches/patches/0140-mlxsw-core-Add-APIs-for-thermal-sensor-mapping.patch new file mode 100644 index 000000000000..d48940325e53 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0140-mlxsw-core-Add-APIs-for-thermal-sensor-mapping.patch @@ -0,0 +1,113 @@ +From 1ea36b4966e21d9d599da7e4e3195364841d9318 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Mon, 13 Dec 2021 12:29:10 +0000 +Subject: [PATCH] mlxsw: core: Add APIs for thermal sensor mapping + +Add APIs mlxsw_env_sensor_map_init() and mlxsw_env_sensor_map_fini((). +The purpose of the first one is to allocate and create thermal sensors +mapping for temperature sensors, presented within the main board or +line card. It obtains mapping information from the Management +Temperature Extended Capabilities Register, by specifying the relevant +device by the number of a slot at which this device is located. Slot +zero is used for the main board. The second API just free allocated +memory. +The motivation is to create dynamic mapping for gearbox thermal sensors +access. + +Signed-off-by: Vadim Pasternak +--- + .../net/ethernet/mellanox/mlxsw/core_env.c | 47 +++++++++++++++++++ + .../net/ethernet/mellanox/mlxsw/core_env.h | 12 +++++ + 2 files changed, 59 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +index 94d44db1a..c27cd424b 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +@@ -626,6 +626,53 @@ mlxsw_env_set_module_power_mode(struct mlxsw_core *mlxsw_core, u8 slot_index, + } + EXPORT_SYMBOL(mlxsw_env_set_module_power_mode); + ++int mlxsw_env_sensor_map_create(struct mlxsw_core *core, ++ const struct mlxsw_bus_info *bus_info, ++ u8 slot_index, ++ struct mlxsw_env_gearbox_sensors_map *map) ++{ ++ char mtecr_pl[MLXSW_REG_MTECR_LEN]; ++ u16 last_sensor, offset; ++ int i, bit, err; ++ ++ mlxsw_reg_mtecr_pack(mtecr_pl, slot_index); ++ err = mlxsw_reg_query(core, MLXSW_REG(mtecr), mtecr_pl); ++ if (err) ++ return err; ++ ++ mlxsw_reg_mtecr_unpack(mtecr_pl, &map->sensor_count, &last_sensor, NULL); ++ if (!map->sensor_count) { ++ map->sensor_bit_map = NULL; ++ return 0; ++ } ++ ++ /* Fill out sensor mapping array. */ ++ map->sensor_bit_map = kcalloc(map->sensor_count, sizeof(u16), GFP_KERNEL); ++ if (!map->sensor_bit_map) ++ return -ENOMEM; ++ ++ /* Sensors bitmap is size variable based on the last_sensor field and ++ * in granularity of 32 bits. Calculate an offset in payload buffer to ++ * start from. ++ */ ++ offset = MLXSW_REG_MTECR_SENSOR_MAP_LEN * 8 - last_sensor - 1; ++ offset -= offset % 32; ++ for (bit = 0, i = 0; bit <= last_sensor && i < map->sensor_count; bit++) { ++ if (mlxsw_reg_mtecr_sensor_map_get(mtecr_pl, bit + offset)) ++ map->sensor_bit_map[i++] = bit; ++ } ++ ++ return 0; ++} ++EXPORT_SYMBOL(mlxsw_env_sensor_map_create); ++ ++void mlxsw_env_sensor_map_destroy(const struct mlxsw_bus_info *bus_info, ++ u16 *sensor_bit_map) ++{ ++ kfree(sensor_bit_map); ++} ++EXPORT_SYMBOL(mlxsw_env_sensor_map_destroy); ++ + static int mlxsw_env_module_has_temp_sensor(struct mlxsw_core *mlxsw_core, + u8 slot_index, u8 module, + bool *p_has_temp_sensor) +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.h b/drivers/net/ethernet/mellanox/mlxsw/core_env.h +index 03d027870..336c9ee57 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.h +@@ -9,6 +9,11 @@ + struct ethtool_modinfo; + struct ethtool_eeprom; + ++struct mlxsw_env_gearbox_sensors_map { ++ u16 sensor_count; ++ u16 *sensor_bit_map; ++}; ++ + int mlxsw_env_module_temp_thresholds_get(struct mlxsw_core *core, + u8 slot_index, int module, int off, + int *temp); +@@ -21,6 +26,13 @@ int mlxsw_env_get_module_eeprom(struct net_device *netdev, + int module, struct ethtool_eeprom *ee, + u8 *data); + ++int mlxsw_env_sensor_map_create(struct mlxsw_core *core, ++ const struct mlxsw_bus_info *bus_info, ++ u8 slot_index, ++ struct mlxsw_env_gearbox_sensors_map *map); ++void mlxsw_env_sensor_map_destroy(const struct mlxsw_bus_info *bus_info, ++ u16 *sensor_bit_map); ++ + int + mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, + u8 slot_index, u8 module, +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0141-mlxsw-reg-Add-Management-DownStream-Device-Tunneling.patch b/platform/mellanox/non-upstream-patches/patches/0141-mlxsw-reg-Add-Management-DownStream-Device-Tunneling.patch new file mode 100644 index 000000000000..2c1bd96646ea --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0141-mlxsw-reg-Add-Management-DownStream-Device-Tunneling.patch @@ -0,0 +1,126 @@ +From 46563dcd511270f67a9e771497ccfc73907aa4d3 Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Thu, 25 Feb 2021 10:17:53 +0100 +Subject: [PATCH] mlxsw: reg: Add Management DownStream Device Tunneling + Register + +The MDDT register allows deliver query and request messages +(PRM registers, commands) to a DownStream device. + +Signed-off-by: Jiri Pirko +--- + drivers/net/ethernet/mellanox/mlxsw/reg.h | 91 +++++++++++++++++++++++ + 1 file changed, 91 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h +index c1ce0b42e..f8c828e05 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h +@@ -10482,6 +10482,96 @@ mlxsw_reg_mbct_unpack(const char *payload, u8 *p_slot_index, + *p_fsm_state = mlxsw_reg_mbct_fsm_state_get(payload); + } + ++/* MDDT - Management DownStream Device Tunneling Register ++ * ------------------------------------------------------ ++ * This register allows deliver query and request messages (PRM registers, ++ * commands) to a DownStream device. ++ */ ++#define MLXSW_REG_MDDT_ID 0x9160 ++#define MLXSW_REG_MDDT_LEN 0x110 ++ ++MLXSW_REG_DEFINE(mddt, MLXSW_REG_MDDT_ID, MLXSW_REG_MDDT_LEN); ++ ++/* reg_mddt_slot_index ++ * Slot index. ++ * Access: Index ++ */ ++ ++MLXSW_ITEM32(reg, mddt, slot_index, 0x00, 8, 4); ++ ++/* reg_mddt_device_index ++ * Device index. ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, mddt, device_index, 0x00, 0, 8); ++ ++/* reg_mddt_read_size ++ * Read size in D-Words. ++ * Access: OP ++ */ ++MLXSW_ITEM32(reg, mddt, read_size, 0x04, 24, 8); ++ ++/* reg_mddt_write_size ++ * Write size in D-Words. ++ * Access: OP ++ */ ++MLXSW_ITEM32(reg, mddt, write_size, 0x04, 16, 8); ++ ++enum mlxsw_reg_mddt_status { ++ MLXSW_REG_MDDT_STATUS_OK, ++}; ++ ++/* reg_mddt_status ++ * Return code of the Downstream Device to the register that was sent. ++ * Access: RO ++ */ ++MLXSW_ITEM32(reg, mddt, status, 0x0C, 24, 8); ++ ++enum mlxsw_reg_mddt_method { ++ MLXSW_REG_MDDT_METHOD_QUERY, ++ MLXSW_REG_MDDT_METHOD_WRITE, ++}; ++ ++/* reg_mddt_method ++ * Access: OP ++ */ ++MLXSW_ITEM32(reg, mddt, method, 0x0C, 22, 2); ++ ++/* reg_mddt_register_id ++ * Access: Index ++ */ ++MLXSW_ITEM32(reg, mddt, register_id, 0x0C, 0, 16); ++ ++#define MLXSW_REG_MDDT_PAYLOAD_OFFSET 0x0C ++#define MLXSW_REG_MDDT_PRM_REGISTER_HEADER_LEN 4 ++ ++static inline char *mlxsw_reg_mddt_inner_payload(char *payload) ++{ ++ return payload + MLXSW_REG_MDDT_PAYLOAD_OFFSET + ++ MLXSW_REG_MDDT_PRM_REGISTER_HEADER_LEN; ++} ++ ++static inline void mlxsw_reg_mddt_pack(char *payload, u8 slot_index, ++ u8 device_index, ++ enum mlxsw_reg_mddt_method method, ++ const struct mlxsw_reg_info *reg, ++ char **inner_payload) ++{ ++ int len = reg->len + MLXSW_REG_MDDT_PRM_REGISTER_HEADER_LEN; ++ ++ if (WARN_ON(len + MLXSW_REG_MDDT_PAYLOAD_OFFSET > MLXSW_REG_MDDT_LEN)) ++ len = MLXSW_REG_MDDT_LEN - MLXSW_REG_MDDT_PAYLOAD_OFFSET; ++ ++ MLXSW_REG_ZERO(mddt, payload); ++ mlxsw_reg_mddt_slot_index_set(payload, slot_index); ++ mlxsw_reg_mddt_device_index_set(payload, device_index); ++ mlxsw_reg_mddt_method_set(payload, method); ++ mlxsw_reg_mddt_register_id_set(payload, reg->id); ++ mlxsw_reg_mddt_read_size_set(payload, len / 4); ++ mlxsw_reg_mddt_write_size_set(payload, len / 4); ++ *inner_payload = mlxsw_reg_mddt_inner_payload(payload); ++} ++ + /* MDDQ - Management DownStream Device Query Register + * -------------------------------------------------- + * This register allows to query the DownStream device properties. The desired +@@ -11952,6 +12042,7 @@ static const struct mlxsw_reg_info *mlxsw_reg_infos[] = { + MLXSW_REG(mgpir), + MLXSW_REG(mtecr), + MLXSW_REG(mbct), ++ MLXSW_REG(mddt), + MLXSW_REG(mddq), + MLXSW_REG(mddc), + MLXSW_REG(mfde), +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0142-mlxsw-core_linecards-Probe-devices-for-provisioned-l.patch b/platform/mellanox/non-upstream-patches/patches/0142-mlxsw-core_linecards-Probe-devices-for-provisioned-l.patch new file mode 100644 index 000000000000..1126d7013e46 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0142-mlxsw-core_linecards-Probe-devices-for-provisioned-l.patch @@ -0,0 +1,224 @@ +From 70bc337251ccbfe095a89457ded233c3ad5b9bbc Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Fri, 26 Feb 2021 13:15:09 +0100 +Subject: [PATCH] mlxsw: core_linecards: Probe devices for provisioned line + card and attach them + +In case the line card is provisioned, go over all possible existing +devices (gearboxes) on it and attach them, so devlink core is aware of +them. In case the device can be flashed, register mlxsw flash component. + +Signed-off-by: Jiri Pirko +--- + drivers/net/ethernet/mellanox/mlxsw/core.h | 3 + + .../ethernet/mellanox/mlxsw/core_linecards.c | 113 ++++++++++++++++-- + 2 files changed, 108 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h +index 8e738ddb3..593470d14 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.h +@@ -533,6 +533,9 @@ struct mlxsw_linecard { + bool ready; + bool active; + bool unprovision_done; ++ u16 hw_revision; ++ u16 ini_version; ++ struct list_head device_list; + }; + + struct mlxsw_linecard_types_info; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c b/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c +index 134437f49..720ad6d82 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c +@@ -64,27 +64,120 @@ static const char *mlxsw_linecard_type_name(struct mlxsw_linecard *linecard) + return linecard->read_name; + } + +-static void mlxsw_linecard_provision_fail(struct mlxsw_linecard *linecard) ++struct mlxsw_linecard_device { ++ struct list_head list; ++ u8 index; ++ struct mlxsw_linecard *linecard; ++ struct devlink_linecard_device *devlink_device; ++}; ++ ++static int mlxsw_linecard_device_attach(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecard *linecard, ++ u8 device_index, bool flash_owner) ++{ ++ struct mlxsw_linecard_device *device; ++ int err; ++ ++ device = kzalloc(sizeof(*device), GFP_KERNEL); ++ if (!device) ++ return -ENOMEM; ++ device->index = device_index; ++ device->linecard = linecard; ++ ++ device->devlink_device = devlink_linecard_device_create(linecard->devlink_linecard, ++ device_index, ++ NULL, NULL); ++ if (IS_ERR(device->devlink_device)) { ++ err = PTR_ERR(device->devlink_device); ++ goto err_devlink_linecard_device_attach; ++ } ++ ++ list_add_tail(&device->list, &linecard->device_list); ++ return 0; ++ ++err_devlink_linecard_device_attach: ++ kfree(device); ++ return err; ++} ++ ++static void mlxsw_linecard_device_detach(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecard *linecard, ++ struct mlxsw_linecard_device *device) ++{ ++ list_del(&device->list); ++ devlink_linecard_device_destroy(linecard->devlink_linecard, ++ device->devlink_device); ++ kfree(device); ++} ++ ++static int mlxsw_linecard_devices_attach(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecard *linecard) ++{ ++ char mddq_pl[MLXSW_REG_MDDQ_LEN]; ++ bool flash_owner; ++ bool data_valid; ++ u8 device_index; ++ u8 msg_seq = 0; ++ int err; ++ ++ do { ++ mlxsw_reg_mddq_device_info_pack(mddq_pl, linecard->slot_index, ++ msg_seq); ++ err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mddq), mddq_pl); ++ if (err) ++ return err; ++ mlxsw_reg_mddq_device_info_unpack(mddq_pl, &msg_seq, ++ &data_valid, &flash_owner, ++ &device_index, NULL, ++ NULL, NULL); ++ if (!data_valid) ++ break; ++ err = mlxsw_linecard_device_attach(mlxsw_core, linecard, ++ device_index, flash_owner); ++ if (err) ++ return err; ++ } while (msg_seq); ++ ++ return 0; ++} ++ ++static void mlxsw_linecard_devices_detach(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecard *linecard) ++{ ++ struct mlxsw_linecard_device *device, *tmp; ++ ++ list_for_each_entry_safe(device, tmp, &linecard->device_list, list) ++ mlxsw_linecard_device_detach(mlxsw_core, linecard, device); ++} ++ ++static void mlxsw_linecard_provision_fail(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecard *linecard) + { + linecard->provisioned = false; + linecard->ready = false; + linecard->active = false; ++ mlxsw_linecard_devices_detach(mlxsw_core, linecard); + devlink_linecard_provision_fail(linecard->devlink_linecard); + } + + static int +-mlxsw_linecard_provision_set(struct mlxsw_linecards *linecards, ++mlxsw_linecard_provision_set(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards, + struct mlxsw_linecard *linecard, + enum mlxsw_reg_mddq_card_type card_type) + { + const char *type = mlxsw_linecard_types_lookup(linecards, card_type); ++ int err; + + if (!type) + type = mlxsw_linecard_type_name(linecard); + if (!type) { +- mlxsw_linecard_provision_fail(linecard); ++ mlxsw_linecard_provision_fail(mlxsw_core, linecard); + return -EINVAL; + } ++ err = mlxsw_linecard_devices_attach(mlxsw_core, linecard); ++ if (err) ++ return err; + linecard->provisioned = true; + devlink_linecard_provision_set(linecard->devlink_linecard, type); + return 0; +@@ -93,6 +186,8 @@ mlxsw_linecard_provision_set(struct mlxsw_linecards *linecards, + static void mlxsw_linecard_provision_clear(struct mlxsw_linecard *linecard) + { + linecard->provisioned = false; ++ mlxsw_linecard_devices_detach(linecard->linecards->mlxsw_core, ++ linecard); + devlink_linecard_provision_clear(linecard->devlink_linecard); + } + +@@ -169,8 +264,8 @@ static int __mlxsw_linecard_status_process(struct mlxsw_core *mlxsw_core, + mutex_lock(&linecard->lock); + + if (provisioned && linecard->provisioned != provisioned) { +- err = mlxsw_linecard_provision_set(linecards, linecard, +- card_type); ++ err = mlxsw_linecard_provision_set(mlxsw_core, linecards, ++ linecard, card_type); + if (err) + goto out; + } +@@ -353,7 +448,7 @@ int mlxsw_linecard_bct_process(struct mlxsw_core *mlxsw_core, + + fix_fsm_err_out: + mlxsw_linecard_fix_fsm_state(linecard, fsm_state); +- mlxsw_linecard_provision_fail(linecard); ++ mlxsw_linecard_provision_fail(mlxsw_core, linecard); + return err; + } + EXPORT_SYMBOL(mlxsw_linecard_bct_process); +@@ -415,7 +510,7 @@ static int mlxsw_linecard_provision(struct devlink_linecard *devlink_linecard, + fix_fsm_err_out: + mlxsw_linecard_fix_fsm_state(linecard, fsm_state); + err_out: +- mlxsw_linecard_provision_fail(linecard); ++ mlxsw_linecard_provision_fail(mlxsw_core, linecard); + out: + mutex_unlock(&linecard->lock); + return err; +@@ -488,7 +583,7 @@ static int mlxsw_linecard_unprovision(struct devlink_linecard *devlink_linecard, + fix_fsm_err_out: + mlxsw_linecard_fix_fsm_state(linecard, fsm_state); + err_out: +- mlxsw_linecard_provision_fail(linecard); ++ mlxsw_linecard_provision_fail(mlxsw_core, linecard); + out: + mutex_unlock(&linecard->lock); + return err; +@@ -536,6 +631,7 @@ static int mlxsw_linecard_init(struct mlxsw_core *mlxsw_core, + linecard->slot_index = slot_index; + linecard->linecards = linecards; + mutex_init(&linecard->lock); ++ INIT_LIST_HEAD(&linecard->device_list); + + devlink_linecard = devlink_linecard_create(priv_to_devlink(mlxsw_core), + slot_index, &mlxsw_linecard_ops, +@@ -613,6 +709,7 @@ static void mlxsw_linecard_fini(struct mlxsw_core *mlxsw_core, + struct mlxsw_linecard *linecard; + + linecard = mlxsw_linecard_get(linecards, slot_index); ++ mlxsw_linecard_devices_detach(mlxsw_core, linecard); + devlink_linecard_destroy(linecard->devlink_linecard); + mutex_destroy(&linecard->lock); + } +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0143-mlxsw-core_linecards-Expose-device-FW-version-over-d.patch b/platform/mellanox/non-upstream-patches/patches/0143-mlxsw-core_linecards-Expose-device-FW-version-over-d.patch new file mode 100644 index 000000000000..f4dc89aec2f9 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0143-mlxsw-core_linecards-Expose-device-FW-version-over-d.patch @@ -0,0 +1,177 @@ +From 8279b3c273fac860394fb922c70c336993e6f087 Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Thu, 10 Jun 2021 15:32:00 +0200 +Subject: [PATCH] mlxsw: core_linecards: Expose device FW version over device + info + +Extend MDDQ to obtain FW version of line card device and implement +device_info_get() op to fill up the info with that. + +Signed-off-by: Jiri Pirko +--- + .../ethernet/mellanox/mlxsw/core_linecards.c | 104 +++++++++++++++++- + 1 file changed, 100 insertions(+), 4 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c b/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c +index 720ad6d82..cb872f918 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c +@@ -64,13 +64,31 @@ static const char *mlxsw_linecard_type_name(struct mlxsw_linecard *linecard) + return linecard->read_name; + } + ++struct mlxsw_linecard_device_info { ++ u16 fw_major; ++ u16 fw_minor; ++ u16 fw_sub_minor; ++}; ++ + struct mlxsw_linecard_device { + struct list_head list; + u8 index; + struct mlxsw_linecard *linecard; + struct devlink_linecard_device *devlink_device; ++ struct mlxsw_linecard_device_info info; + }; + ++static struct mlxsw_linecard_device * ++mlxsw_linecard_device_lookup(struct mlxsw_linecard *linecard, u8 index) ++{ ++ struct mlxsw_linecard_device *device; ++ ++ list_for_each_entry(device, &linecard->device_list, list) ++ if (device->index == index) ++ return device; ++ return NULL; ++} ++ + static int mlxsw_linecard_device_attach(struct mlxsw_core *mlxsw_core, + struct mlxsw_linecard *linecard, + u8 device_index, bool flash_owner) +@@ -86,7 +104,7 @@ static int mlxsw_linecard_device_attach(struct mlxsw_core *mlxsw_core, + + device->devlink_device = devlink_linecard_device_create(linecard->devlink_linecard, + device_index, +- NULL, NULL); ++ NULL, device); + if (IS_ERR(device->devlink_device)) { + err = PTR_ERR(device->devlink_device); + goto err_devlink_linecard_device_attach; +@@ -150,6 +168,71 @@ static void mlxsw_linecard_devices_detach(struct mlxsw_core *mlxsw_core, + mlxsw_linecard_device_detach(mlxsw_core, linecard, device); + } + ++static void mlxsw_linecard_device_update(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecard *linecard, ++ u8 device_index, ++ struct mlxsw_linecard_device_info *info) ++{ ++ struct mlxsw_linecard_device *device; ++ ++ device = mlxsw_linecard_device_lookup(linecard, device_index); ++ if (!device) ++ return; ++ device->info = *info; ++} ++ ++static int mlxsw_linecard_devices_update(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecard *linecard) ++{ ++ struct mlxsw_linecard_device_info info; ++ char mddq_pl[MLXSW_REG_MDDQ_LEN]; ++ bool data_valid; ++ u8 device_index; ++ u8 msg_seq = 0; ++ int err; ++ ++ do { ++ mlxsw_reg_mddq_device_info_pack(mddq_pl, linecard->slot_index, ++ msg_seq); ++ err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mddq), mddq_pl); ++ if (err) ++ return err; ++ mlxsw_reg_mddq_device_info_unpack(mddq_pl, &msg_seq, ++ &data_valid, NULL, ++ &device_index, ++ &info.fw_major, ++ &info.fw_minor, ++ &info.fw_sub_minor); ++ if (!data_valid) ++ break; ++ mlxsw_linecard_device_update(mlxsw_core, linecard, ++ device_index, &info); ++ } while (msg_seq); ++ ++ return 0; ++} ++ ++static int ++mlxsw_linecard_device_info_get(struct devlink_linecard_device *devlink_linecard_device, ++ void *priv, struct devlink_info_req *req, ++ struct netlink_ext_ack *extack) ++{ ++ struct mlxsw_linecard_device *device = priv; ++ struct mlxsw_linecard_device_info *info; ++ char buf[32]; ++ ++ if (!device->linecard->active) ++ return 0; ++ ++ info = &device->info; ++ ++ sprintf(buf, "%u.%u.%u", info->fw_major, info->fw_minor, ++ info->fw_sub_minor); ++ return devlink_info_version_running_put(req, ++ DEVLINK_INFO_VERSION_GENERIC_FW, ++ buf); ++} ++ + static void mlxsw_linecard_provision_fail(struct mlxsw_core *mlxsw_core, + struct mlxsw_linecard *linecard) + { +@@ -219,10 +302,18 @@ static int mlxsw_linecard_ready_clear(struct mlxsw_core *mlxsw_core, + return 0; + } + +-static void mlxsw_linecard_active_set(struct mlxsw_linecard *linecard) ++static int mlxsw_linecard_active_set(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecard *linecard, ++ u16 hw_revision, u16 ini_version) + { ++ int err; ++ ++ err = mlxsw_linecard_devices_update(mlxsw_core, linecard); ++ if (err) ++ return err; + linecard->active = true; + devlink_linecard_activate(linecard->devlink_linecard); ++ return 0; + } + + static void mlxsw_linecard_active_clear(struct mlxsw_linecard *linecard) +@@ -278,8 +369,12 @@ static int __mlxsw_linecard_status_process(struct mlxsw_core *mlxsw_core, + } + + if (!process_provision_only && !linecard->unprovision_done && active && +- linecard->active != active && linecard->ready) +- mlxsw_linecard_active_set(linecard); ++ linecard->active != active && linecard->ready) { ++ err = mlxsw_linecard_active_set(mlxsw_core, linecard, ++ hw_revision, ini_version); ++ if (err) ++ goto out; ++ } + + if (!process_provision_only && !active && linecard->active != active) + mlxsw_linecard_active_clear(linecard); +@@ -617,6 +712,7 @@ static const struct devlink_linecard_ops mlxsw_linecard_ops = { + .unprovision = mlxsw_linecard_unprovision, + .types_count = mlxsw_linecard_types_count, + .types_get = mlxsw_linecard_types_get, ++ .device_info_get = mlxsw_linecard_device_info_get, + }; + + static int mlxsw_linecard_init(struct mlxsw_core *mlxsw_core, +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0144-mlxsw-core-Introduce-flash-update-components.patch b/platform/mellanox/non-upstream-patches/patches/0144-mlxsw-core-Introduce-flash-update-components.patch new file mode 100644 index 000000000000..642cd79ca4f5 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0144-mlxsw-core-Introduce-flash-update-components.patch @@ -0,0 +1,243 @@ +From a1421cadee435540d09a5526525f692821a271cd Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Fri, 26 Feb 2021 18:40:28 +0100 +Subject: [PATCH] mlxsw: core: Introduce flash update components + +Introduce an infrastructure allowing to have multiple components for +flashing purposes that can be registered from inside the driver. Convert +the existing "no component" flash update to use the new infra. + +Signed-off-by: Jiri Pirko +--- + drivers/net/ethernet/mellanox/mlxsw/core.c | 117 +++++++++++++++++++-- + drivers/net/ethernet/mellanox/mlxsw/core.h | 12 +++ + include/net/devlink.h | 3 + + 3 files changed, 125 insertions(+), 7 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c +index 68ef007ac..f55071982 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.c +@@ -91,6 +91,10 @@ struct mlxsw_core { + struct devlink_health_reporter *fw_fatal; + } health; + struct mlxsw_env *env; ++ struct list_head flash_component_list; ++ struct mutex flash_update_lock; /* Protects component list and component ++ * callbacks. ++ */ + unsigned long driver_priv[]; + /* driver_priv has to be always the last item */ + }; +@@ -1113,21 +1117,101 @@ static int mlxsw_core_fw_rev_validate(struct mlxsw_core *mlxsw_core, + return 0; + } + ++static int mlxsw_core_fw_flash_cb(struct mlxsw_core *mlxsw_core, ++ const struct firmware *firmware, ++ struct netlink_ext_ack *extack, void *priv) ++{ ++ return mlxsw_core_fw_flash(mlxsw_core, firmware, extack); ++} ++ ++struct mlxsw_core_flash_component { ++ struct list_head list; ++ const char *name; ++ mlxsw_core_flash_update_cb cb; ++ void *priv; ++}; ++ ++static struct mlxsw_core_flash_component * ++mlxsw_core_flash_component_lookup(struct mlxsw_core *mlxsw_core, ++ const char *name) ++{ ++ struct mlxsw_core_flash_component *component; ++ ++ list_for_each_entry(component, &mlxsw_core->flash_component_list, ++ list) { ++ if ((name && component->name && ++ !strcmp(name, component->name)) || ++ (!name && !component->name)) ++ return component; ++ } ++ return NULL; ++} ++ + static int mlxsw_core_fw_flash_update(struct mlxsw_core *mlxsw_core, + struct devlink_flash_update_params *params, + struct netlink_ext_ack *extack) + { +- const struct firmware *firmware; ++ struct mlxsw_core_flash_component *component; + int err; + +- err = request_firmware_direct(&firmware, params->file_name, mlxsw_core->bus_info->dev); +- if (err) +- return err; +- err = mlxsw_core_fw_flash(mlxsw_core, firmware, extack); +- release_firmware(firmware); ++ mutex_lock(&mlxsw_core->flash_update_lock); ++ component = mlxsw_core_flash_component_lookup(mlxsw_core, ++ params->component); ++ if (!component) { ++ NL_SET_ERR_MSG_MOD(extack, "Component does not exist"); ++ err = -ENOENT; ++ goto unlock; ++ } ++ err = component->cb(mlxsw_core, params->fw, extack, component->priv); ++unlock: ++ mutex_unlock(&mlxsw_core->flash_update_lock); ++ return err; ++} + ++int mlxsw_core_flash_component_register(struct mlxsw_core *mlxsw_core, ++ const char *name, ++ mlxsw_core_flash_update_cb cb, ++ void *priv) ++{ ++ struct mlxsw_core_flash_component *component; ++ int err = 0; ++ ++ mutex_lock(&mlxsw_core->flash_update_lock); ++ component = mlxsw_core_flash_component_lookup(mlxsw_core, name); ++ if (WARN_ON(component)) { ++ err = -EEXIST; ++ goto unlock; ++ } ++ component = kzalloc(sizeof(*component), GFP_KERNEL); ++ if (!component) { ++ err = -ENOMEM; ++ goto unlock; ++ } ++ component->name = name; ++ component->cb = cb; ++ component->priv = priv; ++ list_add_tail(&component->list, &mlxsw_core->flash_component_list); ++unlock: ++ mutex_unlock(&mlxsw_core->flash_update_lock); + return err; + } ++EXPORT_SYMBOL(mlxsw_core_flash_component_register); ++ ++void mlxsw_core_flash_component_unregister(struct mlxsw_core *mlxsw_core, ++ const char *name) ++{ ++ struct mlxsw_core_flash_component *component; ++ ++ mutex_lock(&mlxsw_core->flash_update_lock); ++ component = mlxsw_core_flash_component_lookup(mlxsw_core, name); ++ if (WARN_ON(!component)) ++ goto unlock; ++ list_del(&component->list); ++unlock: ++ mutex_unlock(&mlxsw_core->flash_update_lock); ++ kfree(component); ++} ++EXPORT_SYMBOL(mlxsw_core_flash_component_unregister); + + static int mlxsw_core_devlink_param_fw_load_policy_validate(struct devlink *devlink, u32 id, + union devlink_param_value val, +@@ -1572,6 +1656,7 @@ mlxsw_devlink_trap_policer_counter_get(struct devlink *devlink, + } + + static const struct devlink_ops mlxsw_devlink_ops = { ++ .supported_flash_update_params = DEVLINK_SUPPORT_FLASH_UPDATE_COMPONENT, + .reload_actions = BIT(DEVLINK_RELOAD_ACTION_DRIVER_REINIT) | + BIT(DEVLINK_RELOAD_ACTION_FW_ACTIVATE), + .reload_down = mlxsw_devlink_core_bus_device_reload_down, +@@ -1894,6 +1979,16 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, + mlxsw_core->bus_priv = bus_priv; + mlxsw_core->bus_info = mlxsw_bus_info; + ++ if (!reload) { ++ INIT_LIST_HEAD(&mlxsw_core->flash_component_list); ++ mutex_init(&mlxsw_core->flash_update_lock); ++ err = mlxsw_core_flash_component_register(mlxsw_core, NULL, ++ mlxsw_core_fw_flash_cb, ++ NULL); ++ if (err) ++ goto err_flash_component_register; ++ } ++ + res = mlxsw_driver->res_query_enabled ? &mlxsw_core->res : NULL; + err = mlxsw_bus->init(bus_priv, mlxsw_core, mlxsw_driver->profile, res); + if (err) +@@ -2013,6 +2108,11 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, + err_register_resources: + mlxsw_bus->fini(bus_priv); + err_bus_init: ++ if (!reload) { ++ mlxsw_core_flash_component_unregister(mlxsw_core, NULL); ++ mutex_destroy(&mlxsw_core->flash_update_lock); ++ } ++err_flash_component_register: + if (!reload) + devlink_free(devlink); + err_devlink_alloc: +@@ -2081,8 +2181,11 @@ void mlxsw_core_bus_device_unregister(struct mlxsw_core *mlxsw_core, + if (!reload) + devlink_resources_unregister(devlink, NULL); + mlxsw_core->bus->fini(mlxsw_core->bus_priv); +- if (!reload) ++ if (!reload) { ++ mlxsw_core_flash_component_unregister(mlxsw_core, NULL); ++ mutex_destroy(&mlxsw_core->flash_update_lock); + devlink_free(devlink); ++ } + + return; + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h +index 593470d14..30f00da0a 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.h +@@ -41,6 +41,18 @@ mlxsw_core_fw_rev_minor_subminor_validate(const struct mlxsw_fw_rev *rev, + int mlxsw_core_driver_register(struct mlxsw_driver *mlxsw_driver); + void mlxsw_core_driver_unregister(struct mlxsw_driver *mlxsw_driver); + ++typedef int (*mlxsw_core_flash_update_cb)(struct mlxsw_core *mlxsw_core, ++ const struct firmware *firmware, ++ struct netlink_ext_ack *extack, ++ void *priv); ++ ++int mlxsw_core_flash_component_register(struct mlxsw_core *mlxsw_core, ++ const char *name, ++ mlxsw_core_flash_update_cb cb, ++ void *priv); ++void mlxsw_core_flash_component_unregister(struct mlxsw_core *mlxsw_core, ++ const char *name); ++ + int mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, + const struct mlxsw_bus *mlxsw_bus, + void *bus_priv, bool reload, +diff --git a/include/net/devlink.h b/include/net/devlink.h +index 06b61c1d7..fafbec26d 100644 +--- a/include/net/devlink.h ++++ b/include/net/devlink.h +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + + #define DEVLINK_RELOAD_STATS_ARRAY_SIZE \ + (__DEVLINK_RELOAD_LIMIT_MAX * __DEVLINK_RELOAD_ACTION_MAX) +@@ -624,6 +625,7 @@ enum devlink_param_generic_id { + + /** + * struct devlink_flash_update_params - Flash Update parameters ++ * @fw: pointer to the firmware data to update from + * @file_name: the name of the flash firmware file to update from + * @component: the flash component to update + * +@@ -632,6 +634,7 @@ enum devlink_param_generic_id { + * their devlink_ops structure. + */ + struct devlink_flash_update_params { ++ const struct firmware *fw; + const char *file_name; + const char *component; + u32 overwrite_mask; +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0145-mlxfw-Get-the-PSID-value-using-op-instead-of-passing.patch b/platform/mellanox/non-upstream-patches/patches/0145-mlxfw-Get-the-PSID-value-using-op-instead-of-passing.patch new file mode 100644 index 000000000000..1fc1f2c96dc2 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0145-mlxfw-Get-the-PSID-value-using-op-instead-of-passing.patch @@ -0,0 +1,200 @@ +From ecf655b1e2329f2376f014c2cad0f81ec2ac5deb Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Fri, 4 Jun 2021 10:25:35 +0200 +Subject: [PATCH] mlxfw: Get the PSID value using op instead of passing it in + struct + +In preparation for line card device flashing, where the PSID is going to +be obtained dynamically using MGIR register for each individual line +card device. So convert the PSID value get to an extra op. + +Signed-off-by: Jiri Pirko +--- + drivers/net/ethernet/mellanox/mlx5/core/fw.c | 18 +++++++++++++-- + drivers/net/ethernet/mellanox/mlxfw/mlxfw.h | 4 ++-- + .../net/ethernet/mellanox/mlxfw/mlxfw_fsm.c | 23 ++++++++++++++----- + drivers/net/ethernet/mellanox/mlxsw/core.c | 19 +++++++++++++-- + 4 files changed, 52 insertions(+), 12 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c +index 02558ac2a..06edfd5b1 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c +@@ -494,6 +494,20 @@ struct mlx5_mlxfw_dev { + struct mlx5_core_dev *mlx5_core_dev; + }; + ++static const char *mlx5_psid_get(struct mlxfw_dev *mlxfw_dev, u16 *psid_size) ++{ ++ struct mlx5_mlxfw_dev *mlx5_mlxfw_dev = ++ container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev); ++ struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev; ++ ++ *psid_size = MLX5_BOARD_ID_LEN; ++ return dev->board_id; ++} ++ ++static void mlx5_psid_put(const char *psid) ++{ ++} ++ + static int mlx5_component_query(struct mlxfw_dev *mlxfw_dev, + u16 component_index, u32 *p_max_size, + u8 *p_align_bits, u16 *p_max_write_size) +@@ -651,6 +665,8 @@ static int mlx5_fsm_reactivate(struct mlxfw_dev *mlxfw_dev, u8 *status) + } + + static const struct mlxfw_dev_ops mlx5_mlxfw_dev_ops = { ++ .psid_get = mlx5_psid_get, ++ .psid_put = mlx5_psid_put, + .component_query = mlx5_component_query, + .fsm_lock = mlx5_fsm_lock, + .fsm_component_update = mlx5_fsm_component_update, +@@ -670,8 +686,6 @@ int mlx5_firmware_flash(struct mlx5_core_dev *dev, + struct mlx5_mlxfw_dev mlx5_mlxfw_dev = { + .mlxfw_dev = { + .ops = &mlx5_mlxfw_dev_ops, +- .psid = dev->board_id, +- .psid_size = strlen(dev->board_id), + .devlink = priv_to_devlink(dev), + }, + .mlx5_core_dev = dev +diff --git a/drivers/net/ethernet/mellanox/mlxfw/mlxfw.h b/drivers/net/ethernet/mellanox/mlxfw/mlxfw.h +index 7654841a0..b83651246 100644 +--- a/drivers/net/ethernet/mellanox/mlxfw/mlxfw.h ++++ b/drivers/net/ethernet/mellanox/mlxfw/mlxfw.h +@@ -11,8 +11,6 @@ + + struct mlxfw_dev { + const struct mlxfw_dev_ops *ops; +- const char *psid; +- u16 psid_size; + struct devlink *devlink; + }; + +@@ -70,6 +68,8 @@ enum mlxfw_fsm_reactivate_status { + }; + + struct mlxfw_dev_ops { ++ const char * (*psid_get)(struct mlxfw_dev *mlxfw_dev, u16 *psid_size); ++ void (*psid_put)(const char *psid); + int (*component_query)(struct mlxfw_dev *mlxfw_dev, u16 component_index, + u32 *p_max_size, u8 *p_align_bits, + u16 *p_max_write_size); +diff --git a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c +index bcd166911..329ddf1b3 100644 +--- a/drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c ++++ b/drivers/net/ethernet/mellanox/mlxfw/mlxfw_fsm.c +@@ -303,7 +303,8 @@ static int mlxfw_flash_component(struct mlxfw_dev *mlxfw_dev, + return err; + } + +-static int mlxfw_flash_components(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, ++static int mlxfw_flash_components(struct mlxfw_dev *mlxfw_dev, const char *psid, ++ u16 psid_size, u32 fwhandle, + struct mlxfw_mfa2_file *mfa2_file, + bool reactivate_supp, + struct netlink_ext_ack *extack) +@@ -312,8 +313,7 @@ static int mlxfw_flash_components(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, + int err; + int i; + +- err = mlxfw_mfa2_file_component_count(mfa2_file, mlxfw_dev->psid, +- mlxfw_dev->psid_size, ++ err = mlxfw_mfa2_file_component_count(mfa2_file, psid, psid_size, + &component_count); + if (err) { + MLXFW_ERR_MSG(mlxfw_dev, extack, +@@ -324,8 +324,8 @@ static int mlxfw_flash_components(struct mlxfw_dev *mlxfw_dev, u32 fwhandle, + for (i = 0; i < component_count; i++) { + struct mlxfw_mfa2_component *comp; + +- comp = mlxfw_mfa2_file_component_get(mfa2_file, mlxfw_dev->psid, +- mlxfw_dev->psid_size, i); ++ comp = mlxfw_mfa2_file_component_get(mfa2_file, psid, ++ psid_size, i); + if (IS_ERR(comp)) { + err = PTR_ERR(comp); + MLXFW_ERR_MSG(mlxfw_dev, extack, +@@ -350,6 +350,8 @@ int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev, + { + struct mlxfw_mfa2_file *mfa2_file; + bool reactivate_supp = true; ++ const char *psid; ++ u16 psid_size; + u32 fwhandle; + int err; + +@@ -392,8 +394,16 @@ int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev, + if (err) + goto err_state_wait_reactivate_to_locked; + +- err = mlxfw_flash_components(mlxfw_dev, fwhandle, mfa2_file, ++ psid = mlxfw_dev->ops->psid_get(mlxfw_dev, &psid_size); ++ if (IS_ERR(psid)) { ++ err = PTR_ERR(psid); ++ goto err_psid_get; ++ } ++ ++ err = mlxfw_flash_components(mlxfw_dev, psid, psid_size, ++ fwhandle, mfa2_file, + reactivate_supp, extack); ++ mlxfw_dev->ops->psid_put(psid); + if (err) + goto err_flash_components; + +@@ -423,6 +433,7 @@ int mlxfw_firmware_flash(struct mlxfw_dev *mlxfw_dev, + err_state_wait_activate_to_locked: + err_fsm_activate: + err_flash_components: ++err_psid_get: + err_state_wait_reactivate_to_locked: + err_fsm_reactivate: + err_state_wait_idle_to_locked: +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c +index f55071982..8c1280781 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.c +@@ -890,6 +890,21 @@ struct mlxsw_core_fw_info { + struct mlxsw_core *mlxsw_core; + }; + ++static const char *mlxsw_core_fw_psid_get(struct mlxfw_dev *mlxfw_dev, ++ u16 *psid_size) ++{ ++ struct mlxsw_core_fw_info *mlxsw_core_fw_info = ++ container_of(mlxfw_dev, struct mlxsw_core_fw_info, mlxfw_dev); ++ struct mlxsw_core *mlxsw_core = mlxsw_core_fw_info->mlxsw_core; ++ ++ *psid_size = strlen(mlxsw_core->bus_info->psid); ++ return mlxsw_core->bus_info->psid; ++} ++ ++static void mlxsw_core_fw_psid_put(const char *psid) ++{ ++} ++ + static int mlxsw_core_fw_component_query(struct mlxfw_dev *mlxfw_dev, + u16 component_index, u32 *p_max_size, + u8 *p_align_bits, u16 *p_max_write_size) +@@ -1028,6 +1043,8 @@ static void mlxsw_core_fw_fsm_release(struct mlxfw_dev *mlxfw_dev, u32 fwhandle) + } + + static const struct mlxfw_dev_ops mlxsw_core_fw_mlxsw_dev_ops = { ++ .psid_get = mlxsw_core_fw_psid_get, ++ .psid_put = mlxsw_core_fw_psid_put, + .component_query = mlxsw_core_fw_component_query, + .fsm_lock = mlxsw_core_fw_fsm_lock, + .fsm_component_update = mlxsw_core_fw_fsm_component_update, +@@ -1045,8 +1062,6 @@ static int mlxsw_core_fw_flash(struct mlxsw_core *mlxsw_core, const struct firmw + struct mlxsw_core_fw_info mlxsw_core_fw_info = { + .mlxfw_dev = { + .ops = &mlxsw_core_fw_mlxsw_dev_ops, +- .psid = mlxsw_core->bus_info->psid, +- .psid_size = strlen(mlxsw_core->bus_info->psid), + .devlink = priv_to_devlink(mlxsw_core), + }, + .mlxsw_core = mlxsw_core +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0146-mlxsw-core_linecards-Implement-line-card-device-flas.patch b/platform/mellanox/non-upstream-patches/patches/0146-mlxsw-core_linecards-Implement-line-card-device-flas.patch new file mode 100644 index 000000000000..c55126871721 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0146-mlxsw-core_linecards-Implement-line-card-device-flas.patch @@ -0,0 +1,400 @@ +From b721c11b90bb0ef2fcd0bfccd6334948153edea2 Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Fri, 5 Mar 2021 09:33:21 +0100 +Subject: [PATCH] mlxsw: core_linecards: Implement line card device flashing + +Generate flash component name and register it internally within mlxsw +for flashing. Also, propagate the component name to devlink core which +exposes the information about device being flashable and the component +name to use to the user. Implement flashing using MDDT register and +mlxfw. + +Signed-off-by: Jiri Pirko +--- + .../ethernet/mellanox/mlxsw/core_linecards.c | 335 +++++++++++++++++- + 1 file changed, 334 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c b/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c +index cb872f918..9f9ee582f 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c +@@ -73,6 +73,7 @@ struct mlxsw_linecard_device_info { + struct mlxsw_linecard_device { + struct list_head list; + u8 index; ++ char component_name[16]; + struct mlxsw_linecard *linecard; + struct devlink_linecard_device *devlink_device; + struct mlxsw_linecard_device_info info; +@@ -89,11 +90,322 @@ mlxsw_linecard_device_lookup(struct mlxsw_linecard *linecard, u8 index) + return NULL; + } + ++struct mlxsw_linecard_device_fw_info { ++ struct mlxfw_dev mlxfw_dev; ++ struct mlxsw_core *mlxsw_core; ++ struct mlxsw_linecard_device *device; ++}; ++ ++static const char * ++mlxsw_linecard_device_fw_psid_get(struct mlxfw_dev *mlxfw_dev, u16 *psid_size) ++{ ++ struct mlxsw_linecard_device_fw_info *info = ++ container_of(mlxfw_dev, struct mlxsw_linecard_device_fw_info, ++ mlxfw_dev); ++ struct mlxsw_linecard_device *device = info->device; ++ struct mlxsw_core *mlxsw_core = info->mlxsw_core; ++ char mddt_pl[MLXSW_REG_MDDT_LEN]; ++ char *mgir_pl; ++ char *psid; ++ int err; ++ ++ mlxsw_reg_mddt_pack(mddt_pl, device->linecard->slot_index, ++ device->index, ++ MLXSW_REG_MDDT_METHOD_QUERY, ++ MLXSW_REG(mgir), &mgir_pl); ++ ++ mlxsw_reg_mgir_pack(mgir_pl); ++ err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mddt), mddt_pl); ++ if (err) ++ return ERR_PTR(err); ++ psid = kzalloc(MLXSW_REG_MGIR_FW_INFO_PSID_SIZE, GFP_KERNEL); ++ if (!psid) ++ return ERR_PTR(-ENOMEM); ++ ++ mlxsw_reg_mgir_fw_info_psid_memcpy_from(mgir_pl, psid); ++ *psid_size = strlen(psid); ++ return psid; ++} ++ ++static void mlxsw_linecard_device_fw_psid_put(const char *psid) ++{ ++ kfree(psid); ++} ++ ++static int mlxsw_linecard_device_fw_component_query(struct mlxfw_dev *mlxfw_dev, ++ u16 component_index, ++ u32 *p_max_size, ++ u8 *p_align_bits, ++ u16 *p_max_write_size) ++{ ++ struct mlxsw_linecard_device_fw_info *info = ++ container_of(mlxfw_dev, struct mlxsw_linecard_device_fw_info, ++ mlxfw_dev); ++ struct mlxsw_linecard_device *device = info->device; ++ struct mlxsw_core *mlxsw_core = info->mlxsw_core; ++ char mddt_pl[MLXSW_REG_MDDT_LEN]; ++ char *mcqi_pl; ++ int err; ++ ++ mlxsw_reg_mddt_pack(mddt_pl, device->linecard->slot_index, ++ device->index, ++ MLXSW_REG_MDDT_METHOD_QUERY, ++ MLXSW_REG(mcqi), &mcqi_pl); ++ ++ mlxsw_reg_mcqi_pack(mcqi_pl, component_index); ++ err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mddt), mddt_pl); ++ if (err) ++ return err; ++ mlxsw_reg_mcqi_unpack(mcqi_pl, p_max_size, p_align_bits, ++ p_max_write_size); ++ ++ *p_align_bits = max_t(u8, *p_align_bits, 2); ++ *p_max_write_size = min_t(u16, *p_max_write_size, ++ MLXSW_REG_MCDA_MAX_DATA_LEN); ++ return 0; ++} ++ ++static int mlxsw_linecard_device_fw_fsm_lock(struct mlxfw_dev *mlxfw_dev, ++ u32 *fwhandle) ++{ ++ struct mlxsw_linecard_device_fw_info *info = ++ container_of(mlxfw_dev, struct mlxsw_linecard_device_fw_info, ++ mlxfw_dev); ++ struct mlxsw_linecard_device *device = info->device; ++ struct mlxsw_core *mlxsw_core = info->mlxsw_core; ++ char mddt_pl[MLXSW_REG_MDDT_LEN]; ++ u8 control_state; ++ char *mcc_pl; ++ int err; ++ ++ mlxsw_reg_mddt_pack(mddt_pl, device->linecard->slot_index, ++ device->index, ++ MLXSW_REG_MDDT_METHOD_QUERY, ++ MLXSW_REG(mcc), &mcc_pl); ++ mlxsw_reg_mcc_pack(mcc_pl, 0, 0, 0, 0); ++ err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mddt), mddt_pl); ++ if (err) ++ return err; ++ ++ mlxsw_reg_mcc_unpack(mcc_pl, fwhandle, NULL, &control_state); ++ if (control_state != MLXFW_FSM_STATE_IDLE) ++ return -EBUSY; ++ ++ mlxsw_reg_mddt_pack(mddt_pl, device->linecard->slot_index, ++ device->index, ++ MLXSW_REG_MDDT_METHOD_QUERY, ++ MLXSW_REG(mcc), &mcc_pl); ++ mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_LOCK_UPDATE_HANDLE, ++ 0, *fwhandle, 0); ++ return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mddt), mddt_pl); ++} ++ ++static int ++mlxsw_linecard_device_fw_fsm_component_update(struct mlxfw_dev *mlxfw_dev, ++ u32 fwhandle, ++ u16 component_index, ++ u32 component_size) ++{ ++ struct mlxsw_linecard_device_fw_info *info = ++ container_of(mlxfw_dev, struct mlxsw_linecard_device_fw_info, ++ mlxfw_dev); ++ struct mlxsw_linecard_device *device = info->device; ++ struct mlxsw_core *mlxsw_core = info->mlxsw_core; ++ char mddt_pl[MLXSW_REG_MDDT_LEN]; ++ char *mcc_pl; ++ ++ mlxsw_reg_mddt_pack(mddt_pl, device->linecard->slot_index, ++ device->index, ++ MLXSW_REG_MDDT_METHOD_WRITE, ++ MLXSW_REG(mcc), &mcc_pl); ++ mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_UPDATE_COMPONENT, ++ component_index, fwhandle, component_size); ++ return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mddt), mddt_pl); ++} ++ ++static int ++mlxsw_linecard_device_fw_fsm_block_download(struct mlxfw_dev *mlxfw_dev, ++ u32 fwhandle, u8 *data, ++ u16 size, u32 offset) ++{ ++ struct mlxsw_linecard_device_fw_info *info = ++ container_of(mlxfw_dev, struct mlxsw_linecard_device_fw_info, ++ mlxfw_dev); ++ struct mlxsw_linecard_device *device = info->device; ++ struct mlxsw_core *mlxsw_core = info->mlxsw_core; ++ char mddt_pl[MLXSW_REG_MDDT_LEN]; ++ char *mcda_pl; ++ ++ mlxsw_reg_mddt_pack(mddt_pl, device->linecard->slot_index, ++ device->index, ++ MLXSW_REG_MDDT_METHOD_WRITE, ++ MLXSW_REG(mcda), &mcda_pl); ++ mlxsw_reg_mcda_pack(mcda_pl, fwhandle, offset, size, data); ++ return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mddt), mddt_pl); ++} ++ ++static int ++mlxsw_linecard_device_fw_fsm_component_verify(struct mlxfw_dev *mlxfw_dev, ++ u32 fwhandle, u16 component_index) ++{ ++ struct mlxsw_linecard_device_fw_info *info = ++ container_of(mlxfw_dev, struct mlxsw_linecard_device_fw_info, ++ mlxfw_dev); ++ struct mlxsw_linecard_device *device = info->device; ++ struct mlxsw_core *mlxsw_core = info->mlxsw_core; ++ char mddt_pl[MLXSW_REG_MDDT_LEN]; ++ char *mcc_pl; ++ ++ mlxsw_reg_mddt_pack(mddt_pl, device->linecard->slot_index, ++ device->index, ++ MLXSW_REG_MDDT_METHOD_WRITE, ++ MLXSW_REG(mcc), &mcc_pl); ++ mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_VERIFY_COMPONENT, ++ component_index, fwhandle, 0); ++ return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mddt), mddt_pl); ++} ++ ++static int mlxsw_linecard_device_fw_fsm_activate(struct mlxfw_dev *mlxfw_dev, ++ u32 fwhandle) ++{ ++ struct mlxsw_linecard_device_fw_info *info = ++ container_of(mlxfw_dev, struct mlxsw_linecard_device_fw_info, ++ mlxfw_dev); ++ struct mlxsw_linecard_device *device = info->device; ++ struct mlxsw_core *mlxsw_core = info->mlxsw_core; ++ char mddt_pl[MLXSW_REG_MDDT_LEN]; ++ char *mcc_pl; ++ ++ mlxsw_reg_mddt_pack(mddt_pl, device->linecard->slot_index, ++ device->index, ++ MLXSW_REG_MDDT_METHOD_WRITE, ++ MLXSW_REG(mcc), &mcc_pl); ++ mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_ACTIVATE, ++ 0, fwhandle, 0); ++ return mlxsw_reg_write(mlxsw_core, MLXSW_REG(mddt), mddt_pl); ++} ++ ++static int ++mlxsw_linecard_device_fw_fsm_query_state(struct mlxfw_dev *mlxfw_dev, ++ u32 fwhandle, ++ enum mlxfw_fsm_state *fsm_state, ++ enum mlxfw_fsm_state_err *fsm_state_err) ++{ ++ struct mlxsw_linecard_device_fw_info *info = ++ container_of(mlxfw_dev, struct mlxsw_linecard_device_fw_info, ++ mlxfw_dev); ++ struct mlxsw_linecard_device *device = info->device; ++ struct mlxsw_core *mlxsw_core = info->mlxsw_core; ++ char mddt_pl[MLXSW_REG_MDDT_LEN]; ++ u8 control_state; ++ u8 error_code; ++ char *mcc_pl; ++ int err; ++ ++ mlxsw_reg_mddt_pack(mddt_pl, device->linecard->slot_index, ++ device->index, ++ MLXSW_REG_MDDT_METHOD_QUERY, ++ MLXSW_REG(mcc), &mcc_pl); ++ mlxsw_reg_mcc_pack(mcc_pl, 0, 0, fwhandle, 0); ++ err = mlxsw_reg_query(mlxsw_core, MLXSW_REG(mddt), mddt_pl); ++ if (err) ++ return err; ++ ++ mlxsw_reg_mcc_unpack(mcc_pl, NULL, &error_code, &control_state); ++ *fsm_state = control_state; ++ *fsm_state_err = min_t(enum mlxfw_fsm_state_err, error_code, ++ MLXFW_FSM_STATE_ERR_MAX); ++ return 0; ++} ++ ++static void mlxsw_linecard_device_fw_fsm_cancel(struct mlxfw_dev *mlxfw_dev, ++ u32 fwhandle) ++{ ++ struct mlxsw_linecard_device_fw_info *info = ++ container_of(mlxfw_dev, struct mlxsw_linecard_device_fw_info, ++ mlxfw_dev); ++ struct mlxsw_linecard_device *device = info->device; ++ struct mlxsw_core *mlxsw_core = info->mlxsw_core; ++ char mddt_pl[MLXSW_REG_MDDT_LEN]; ++ char *mcc_pl; ++ ++ mlxsw_reg_mddt_pack(mddt_pl, device->linecard->slot_index, ++ device->index, ++ MLXSW_REG_MDDT_METHOD_WRITE, ++ MLXSW_REG(mcc), &mcc_pl); ++ mlxsw_reg_mcc_pack(mcc_pl, MLXSW_REG_MCC_INSTRUCTION_CANCEL, ++ 0, fwhandle, 0); ++ mlxsw_reg_write(mlxsw_core, MLXSW_REG(mddt), mddt_pl); ++} ++ ++static void mlxsw_linecard_device_fw_fsm_release(struct mlxfw_dev *mlxfw_dev, ++ u32 fwhandle) ++{ ++ struct mlxsw_linecard_device_fw_info *info = ++ container_of(mlxfw_dev, struct mlxsw_linecard_device_fw_info, ++ mlxfw_dev); ++ struct mlxsw_linecard_device *device = info->device; ++ struct mlxsw_core *mlxsw_core = info->mlxsw_core; ++ char mddt_pl[MLXSW_REG_MDDT_LEN]; ++ char *mcc_pl; ++ ++ mlxsw_reg_mddt_pack(mddt_pl, device->linecard->slot_index, ++ device->index, ++ MLXSW_REG_MDDT_METHOD_WRITE, ++ MLXSW_REG(mcc), &mcc_pl); ++ mlxsw_reg_mcc_pack(mcc_pl, ++ MLXSW_REG_MCC_INSTRUCTION_RELEASE_UPDATE_HANDLE, ++ 0, fwhandle, 0); ++ mlxsw_reg_write(mlxsw_core, MLXSW_REG(mddt), mddt_pl); ++} ++ ++static const struct mlxfw_dev_ops mlxsw_linecard_device_dev_ops = { ++ .psid_get = mlxsw_linecard_device_fw_psid_get, ++ .psid_put = mlxsw_linecard_device_fw_psid_put, ++ .component_query = mlxsw_linecard_device_fw_component_query, ++ .fsm_lock = mlxsw_linecard_device_fw_fsm_lock, ++ .fsm_component_update = mlxsw_linecard_device_fw_fsm_component_update, ++ .fsm_block_download = mlxsw_linecard_device_fw_fsm_block_download, ++ .fsm_component_verify = mlxsw_linecard_device_fw_fsm_component_verify, ++ .fsm_activate = mlxsw_linecard_device_fw_fsm_activate, ++ .fsm_query_state = mlxsw_linecard_device_fw_fsm_query_state, ++ .fsm_cancel = mlxsw_linecard_device_fw_fsm_cancel, ++ .fsm_release = mlxsw_linecard_device_fw_fsm_release, ++}; ++ ++static int mlxsw_linecard_device_fw_flash(struct mlxsw_core *mlxsw_core, ++ const struct firmware *firmware, ++ struct mlxsw_linecard_device *device, ++ struct netlink_ext_ack *extack) ++{ ++ struct mlxsw_linecard_device_fw_info info = { ++ .mlxfw_dev = { ++ .ops = &mlxsw_linecard_device_dev_ops, ++ .devlink = priv_to_devlink(mlxsw_core), ++ }, ++ .mlxsw_core = mlxsw_core, ++ .device = device, ++ }; ++ ++ return mlxfw_firmware_flash(&info.mlxfw_dev, firmware, extack); ++} ++ ++static int mlxsw_linecard_device_flash_cb(struct mlxsw_core *mlxsw_core, ++ const struct firmware *firmware, ++ struct netlink_ext_ack *extack, void *priv) ++{ ++ struct mlxsw_linecard_device *device = priv; ++ ++ return mlxsw_linecard_device_fw_flash(mlxsw_core, firmware, ++ device, extack); ++} ++ + static int mlxsw_linecard_device_attach(struct mlxsw_core *mlxsw_core, + struct mlxsw_linecard *linecard, + u8 device_index, bool flash_owner) + { + struct mlxsw_linecard_device *device; ++ char *component_name = NULL; + int err; + + device = kzalloc(sizeof(*device), GFP_KERNEL); +@@ -102,9 +414,23 @@ static int mlxsw_linecard_device_attach(struct mlxsw_core *mlxsw_core, + device->index = device_index; + device->linecard = linecard; + ++ if (flash_owner) { ++ snprintf(device->component_name, ++ sizeof(device->component_name), "lc%u_dev%u", ++ linecard->slot_index, device->index); ++ component_name = device->component_name; ++ err = mlxsw_core_flash_component_register(mlxsw_core, ++ component_name, ++ mlxsw_linecard_device_flash_cb, ++ device); ++ if (err) ++ goto err_flash_component_register; ++ } ++ + device->devlink_device = devlink_linecard_device_create(linecard->devlink_linecard, + device_index, +- NULL, device); ++ component_name, ++ device); + if (IS_ERR(device->devlink_device)) { + err = PTR_ERR(device->devlink_device); + goto err_devlink_linecard_device_attach; +@@ -114,6 +440,10 @@ static int mlxsw_linecard_device_attach(struct mlxsw_core *mlxsw_core, + return 0; + + err_devlink_linecard_device_attach: ++ if (flash_owner) ++ mlxsw_core_flash_component_unregister(mlxsw_core, ++ device->component_name); ++err_flash_component_register: + kfree(device); + return err; + } +@@ -125,6 +455,9 @@ static void mlxsw_linecard_device_detach(struct mlxsw_core *mlxsw_core, + list_del(&device->list); + devlink_linecard_device_destroy(linecard->devlink_linecard, + device->devlink_device); ++ if (strlen(device->component_name)) ++ mlxsw_core_flash_component_unregister(mlxsw_core, ++ device->component_name); + kfree(device); + } + +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0147-mlxsw-core_linecards-Introduce-ops-for-linecards-sta.patch b/platform/mellanox/non-upstream-patches/patches/0147-mlxsw-core_linecards-Introduce-ops-for-linecards-sta.patch new file mode 100644 index 000000000000..e7b719158e93 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0147-mlxsw-core_linecards-Introduce-ops-for-linecards-sta.patch @@ -0,0 +1,277 @@ +From 19bae5f5978a43a22258843cc999b592d0e4b414 Mon Sep 17 00:00:00 2001 +From: Jiri Pirko +Date: Fri, 22 Jan 2021 15:01:06 +0100 +Subject: [PATCH] mlxsw: core_linecards: Introduce ops for linecards status + change tracking + +Introduce an infrastructure allowing the core to register set of ops +which are called whenever line card gets provisione/unprovisioned +and active/inactive. + +Signed-off-by: Jiri Pirko +--- + drivers/net/ethernet/mellanox/mlxsw/core.h | 22 +++ + .../ethernet/mellanox/mlxsw/core_linecards.c | 134 +++++++++++++++++- + 2 files changed, 150 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h +index 30f00da0a..10ea541bb 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.h +@@ -582,4 +582,26 @@ int mlxsw_linecard_status_process(struct mlxsw_core *mlxsw_core, + int mlxsw_linecard_bct_process(struct mlxsw_core *mlxsw_core, + const char *mbct_pl); + ++struct mlxsw_linecards_event_ops { ++ int (*got_provisioned)(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ const struct mlxsw_linecard *linecard, ++ void *priv); ++ void (*got_unprovisioned)(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ const struct mlxsw_linecard *linecard, ++ void *priv); ++ void (*got_active)(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ const struct mlxsw_linecard *linecard, ++ void *priv); ++ void (*got_inactive)(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ const struct mlxsw_linecard *linecard, ++ void *priv); ++}; ++ ++int mlxsw_linecards_event_ops_register(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards_event_ops *ops, ++ void *priv); ++void mlxsw_linecards_event_ops_unregister(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards_event_ops *ops, ++ void *priv); ++ + #endif +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c b/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c +index 9f9ee582f..3a2fdd22d 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_linecards.c +@@ -576,6 +576,59 @@ static void mlxsw_linecard_provision_fail(struct mlxsw_core *mlxsw_core, + devlink_linecard_provision_fail(linecard->devlink_linecard); + } + ++struct mlxsw_linecards_event_ops_item { ++ struct list_head list; ++ struct mlxsw_linecards_event_ops *event_ops; ++ void *priv; ++}; ++ ++static int ++mlxsw_linecard_provision_cbs_call(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards, ++ struct mlxsw_linecard *linecard) ++{ ++ struct mlxsw_linecards_event_ops_item *item; ++ int err; ++ ++ list_for_each_entry(item, &linecards->event_ops_list, list) { ++ if (!item->event_ops->got_provisioned) ++ continue; ++ err = item->event_ops->got_provisioned(mlxsw_core, ++ linecard->slot_index, ++ linecard, item->priv); ++ if (err) ++ goto rollback; ++ } ++ return 0; ++ ++rollback: ++ list_for_each_entry_continue_reverse(item, &linecards->event_ops_list, ++ list) { ++ if (!item->event_ops->got_unprovisioned) ++ continue; ++ item->event_ops->got_unprovisioned(mlxsw_core, ++ linecard->slot_index, ++ linecard, item->priv); ++ } ++ return err; ++} ++ ++static void ++mlxsw_linecard_unprovision_cbs_call(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards, ++ struct mlxsw_linecard *linecard) ++{ ++ struct mlxsw_linecards_event_ops_item *item; ++ ++ list_for_each_entry(item, &linecards->event_ops_list, list) { ++ if (!item->event_ops->got_unprovisioned) ++ continue; ++ item->event_ops->got_unprovisioned(mlxsw_core, ++ linecard->slot_index, ++ linecard, item->priv); ++ } ++} ++ + static int + mlxsw_linecard_provision_set(struct mlxsw_core *mlxsw_core, + struct mlxsw_linecards *linecards, +@@ -594,14 +647,27 @@ mlxsw_linecard_provision_set(struct mlxsw_core *mlxsw_core, + err = mlxsw_linecard_devices_attach(mlxsw_core, linecard); + if (err) + return err; ++ err = mlxsw_linecard_provision_cbs_call(mlxsw_core, linecards, ++ linecard); ++ if (err) ++ goto err_cbs_call; + linecard->provisioned = true; + devlink_linecard_provision_set(linecard->devlink_linecard, type); + return 0; ++ ++err_cbs_call: ++ mlxsw_linecard_devices_detach(linecard->linecards->mlxsw_core, ++ linecard); ++ return err; + } + +-static void mlxsw_linecard_provision_clear(struct mlxsw_linecard *linecard) ++static void mlxsw_linecard_provision_clear(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards, ++ struct mlxsw_linecard *linecard) + { + linecard->provisioned = false; ++ mlxsw_linecard_unprovision_cbs_call(mlxsw_core, linecards, ++ linecard); + mlxsw_linecard_devices_detach(linecard->linecards->mlxsw_core, + linecard); + devlink_linecard_provision_clear(linecard->devlink_linecard); +@@ -636,22 +702,43 @@ static int mlxsw_linecard_ready_clear(struct mlxsw_core *mlxsw_core, + } + + static int mlxsw_linecard_active_set(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards, + struct mlxsw_linecard *linecard, + u16 hw_revision, u16 ini_version) + { ++ struct mlxsw_linecards_event_ops_item *item; + int err; + + err = mlxsw_linecard_devices_update(mlxsw_core, linecard); + if (err) + return err; ++ + linecard->active = true; ++ linecard->hw_revision = hw_revision; ++ linecard->ini_version = ini_version; ++ list_for_each_entry(item, &linecards->event_ops_list, list) { ++ if (!item->event_ops->got_active) ++ continue; ++ item->event_ops->got_active(mlxsw_core, linecard->slot_index, ++ linecard, item->priv); ++ } + devlink_linecard_activate(linecard->devlink_linecard); + return 0; + } + +-static void mlxsw_linecard_active_clear(struct mlxsw_linecard *linecard) ++static void mlxsw_linecard_active_clear(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards *linecards, ++ struct mlxsw_linecard *linecard) + { ++ struct mlxsw_linecards_event_ops_item *item; ++ + linecard->active = false; ++ list_for_each_entry(item, &linecards->event_ops_list, list) { ++ if (!item->event_ops->got_inactive) ++ continue; ++ item->event_ops->got_inactive(mlxsw_core, linecard->slot_index, ++ linecard, item->priv); ++ } + devlink_linecard_deactivate(linecard->devlink_linecard); + } + +@@ -703,14 +790,14 @@ static int __mlxsw_linecard_status_process(struct mlxsw_core *mlxsw_core, + + if (!process_provision_only && !linecard->unprovision_done && active && + linecard->active != active && linecard->ready) { +- err = mlxsw_linecard_active_set(mlxsw_core, linecard, ++ err = mlxsw_linecard_active_set(mlxsw_core, linecards, linecard, + hw_revision, ini_version); + if (err) + goto out; + } + + if (!process_provision_only && !active && linecard->active != active) +- mlxsw_linecard_active_clear(linecard); ++ mlxsw_linecard_active_clear(mlxsw_core, linecards, linecard); + + if (!process_provision_only && ready != MLXSW_REG_MDDQ_READY_READY && + linecard->ready) { +@@ -720,7 +807,7 @@ static int __mlxsw_linecard_status_process(struct mlxsw_core *mlxsw_core, + } + + if (!provisioned && linecard->provisioned != provisioned) +- mlxsw_linecard_provision_clear(linecard); ++ mlxsw_linecard_provision_clear(mlxsw_core, linecards, linecard); + + out: + mutex_unlock(&linecard->lock); +@@ -1128,7 +1215,7 @@ static void mlxsw_linecard_pre_fini(struct mlxsw_core *mlxsw_core, + /* Make sure all scheduled events are processed */ + mlxsw_core_flush_owq(); + if (linecard->active) +- mlxsw_linecard_active_clear(linecard); ++ mlxsw_linecard_active_clear(mlxsw_core, linecards, linecard); + } + + static void mlxsw_linecard_fini(struct mlxsw_core *mlxsw_core, +@@ -1287,6 +1374,7 @@ int mlxsw_linecards_init(struct mlxsw_core *mlxsw_core, + linecards->count = slot_count; + linecards->mlxsw_core = mlxsw_core; + linecards->bus_info = bus_info; ++ INIT_LIST_HEAD(&linecards->event_ops_list); + + linecards->wq = alloc_workqueue("mlxsw_linecards", 0, 0); + if (!linecards->wq) { +@@ -1360,6 +1448,7 @@ void mlxsw_linecards_fini(struct mlxsw_core *mlxsw_core, + + if (!linecards) + return; ++ WARN_ON(!list_empty(&linecards->event_ops_list)); + for (i = 0; i < linecards->count; i++) + mlxsw_linecard_fini(mlxsw_core, linecards, i + 1); + mlxsw_linecard_types_fini(linecards); +@@ -1367,4 +1456,37 @@ void mlxsw_linecards_fini(struct mlxsw_core *mlxsw_core, + kfree(linecards); + } + ++int mlxsw_linecards_event_ops_register(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards_event_ops *ops, ++ void *priv) ++{ ++ struct mlxsw_linecards *linecards = mlxsw_core_linecards(mlxsw_core); ++ struct mlxsw_linecards_event_ops_item *item; ++ ++ item = kzalloc(sizeof(*item), GFP_KERNEL); ++ if (!item) ++ return -ENOMEM; ++ item->event_ops = ops; ++ item->priv = priv; ++ list_add_tail(&item->list, &linecards->event_ops_list); ++ return 0; ++} ++EXPORT_SYMBOL(mlxsw_linecards_event_ops_register); ++ ++void mlxsw_linecards_event_ops_unregister(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_linecards_event_ops *ops, ++ void *priv) ++{ ++ struct mlxsw_linecards *linecards = mlxsw_core_linecards(mlxsw_core); ++ struct mlxsw_linecards_event_ops_item *item, *tmp; ++ ++ list_for_each_entry_safe(item, tmp, &linecards->event_ops_list, list) { ++ if (item->event_ops == ops && item->priv == priv) { ++ list_del(&item->list); ++ kfree(item); ++ } ++ } ++} ++EXPORT_SYMBOL(mlxsw_linecards_event_ops_unregister); ++ + MODULE_FIRMWARE(MLXSW_LINECARDS_INI_BUNDLE_FILE); +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0148-mlxsw-core-Add-interfaces-for-line-card-initializati.patch b/platform/mellanox/non-upstream-patches/patches/0148-mlxsw-core-Add-interfaces-for-line-card-initializati.patch new file mode 100644 index 000000000000..f9e7a010e6fc --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0148-mlxsw-core-Add-interfaces-for-line-card-initializati.patch @@ -0,0 +1,133 @@ +From 8d6f7da411b62b4450db1ebb8b687dbc5a386300 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Mon, 13 Dec 2021 12:54:36 +0000 +Subject: [PATCH] mlxsw: core: Add interfaces for line card initialization and + de-initialization + +Add callback functions for line card cables info initialization and +de-initialization. + +The line card initialization / de-initialization APIs are to be called +when line card is set to active / inactive state by got_active() / +got_inactive() callbacks from line card state machine. +Access to cable info and real number of modules is available only after +line card is activated. + +Signed-off-by: Vadim Pasternak +--- + .../net/ethernet/mellanox/mlxsw/core_env.c | 78 +++++++++++++++++++ + 1 file changed, 78 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_env.c b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +index c27cd424b..f9c770eec 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_env.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_env.c +@@ -1162,6 +1162,77 @@ mlxsw_env_module_event_disable(struct mlxsw_env *mlxsw_env, u8 slot_index) + { + } + ++static void ++mlxsw_env_got_active(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ const struct mlxsw_linecard *linecard, void *priv) ++{ ++ struct mlxsw_env *mlxsw_env = priv; ++ char mgpir_pl[MLXSW_REG_MGPIR_LEN]; ++ int err; ++ ++ mlxsw_reg_mgpir_pack(mgpir_pl, slot_index); ++ err = mlxsw_reg_query(mlxsw_env->core, MLXSW_REG(mgpir), mgpir_pl); ++ if (err) ++ return; ++ ++ mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, ++ &mlxsw_env->line_cards[slot_index]->module_count, ++ NULL); ++ mlxsw_env_module_event_enable(mlxsw_env, slot_index); ++} ++ ++static void ++mlxsw_env_got_inactive(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ const struct mlxsw_linecard *linecard, void *priv) ++{ ++ struct mlxsw_env *mlxsw_env = priv; ++ ++ mlxsw_env_module_event_disable(mlxsw_env, slot_index); ++} ++ ++static struct mlxsw_linecards_event_ops mlxsw_env_event_ops = { ++ .got_active = mlxsw_env_got_active, ++ .got_inactive = mlxsw_env_got_inactive, ++}; ++ ++static int mlxsw_env_linecards_register(struct mlxsw_env *mlxsw_env) ++{ ++ struct mlxsw_linecards *linecards = mlxsw_core_linecards(mlxsw_env->core); ++ int err; ++ ++ if (!linecards || !linecards->count) ++ return 0; ++ ++ err = mlxsw_linecards_event_ops_register(mlxsw_env->core, ++ &mlxsw_env_event_ops, ++ mlxsw_env); ++ if (err) ++ goto err_linecards_event_ops_register; ++ ++ return 0; ++ ++err_linecards_event_ops_register: ++ return err; ++} ++ ++static void mlxsw_env_linecards_unregister(struct mlxsw_env *mlxsw_env) ++{ ++ struct mlxsw_linecards *linecards = mlxsw_core_linecards(mlxsw_env->core); ++ int i; ++ ++ if (!linecards || !linecards->count) ++ return; ++ ++ for (i = 1; i <= linecards->count; i++) { ++ if (mlxsw_env->line_cards[i]->module_count) ++ mlxsw_env_got_inactive(mlxsw_env->core, i, NULL, ++ mlxsw_env); ++ } ++ ++ mlxsw_linecards_event_ops_unregister(mlxsw_env->core, ++ &mlxsw_env_event_ops, mlxsw_env); ++} ++ + int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env) + { + u8 module_count, num_of_slots, max_module_count; +@@ -1198,6 +1269,10 @@ int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env) + mutex_init(&env->line_cards_lock); + *p_env = env; + ++ err = mlxsw_env_linecards_register(env); ++ if (err) ++ goto err_linecards_register; ++ + err = mlxsw_env_temp_warn_event_register(mlxsw_core); + if (err) + goto err_temp_warn_event_register; +@@ -1225,6 +1300,8 @@ int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env) + err_module_plug_event_register: + mlxsw_env_temp_warn_event_unregister(env); + err_temp_warn_event_register: ++ mlxsw_env_linecards_unregister(env); ++err_linecards_register: + mutex_destroy(&env->line_cards_lock); + mlxsw_env_line_cards_free(env); + err_mlxsw_env_line_cards_alloc: +@@ -1239,6 +1316,7 @@ void mlxsw_env_fini(struct mlxsw_env *env) + /* Make sure there is no more event work scheduled. */ + mlxsw_core_flush_owq(); + mlxsw_env_temp_warn_event_unregister(env); ++ mlxsw_env_linecards_unregister(env); + mutex_destroy(&env->line_cards_lock); + mlxsw_env_line_cards_free(env); + kfree(env); +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0149-mlxsw-core_thermal-Add-interfaces-for-line-card-init.patch b/platform/mellanox/non-upstream-patches/patches/0149-mlxsw-core_thermal-Add-interfaces-for-line-card-init.patch new file mode 100644 index 000000000000..c64cbb6cbd44 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0149-mlxsw-core_thermal-Add-interfaces-for-line-card-init.patch @@ -0,0 +1,213 @@ +From 62b2da593b9ee1042b0d65c7b84e9f463497ecd8 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 12 May 2021 22:57:39 +0300 +Subject: [PATCH] mlxsw: core_thermal: Add interfaces for line card + initialization and de-initialization + +Add callback functions for line card thermal area initialization and +de-initialization. Each line card is associated with the relevant +thermal area, which may contain thermal zones for cages and gearboxes +found on this line card. + +The line card thermal initialization / de-initialization APIs are to be +called when line card is set to active / inactive state by +got_active() / got_inactive() callbacks from line card state machine. + +For example thermal zone for module #9 located at line card #7 will +have type: +mlxsw-lc7-module9. +And thermal zone for gearbox #2 located at line card #5 will have type: +mlxsw-lc5-gearbox2. + +For now the slot index is always 0 and field 'name' of the structure +'mlxsw_hwmon_dev' is empty. For line card this field is supposed to +be initialized to 'lc#n', when line card in slot #n is enabled. + +Add validation of modules number found on main board in function +mlxsw_thermal_modules_init(). On modular system this counter might be +zero. + +Signed-off-by: Vadim Pasternak +Signed-off-by: Jiri Pirko +--- + .../ethernet/mellanox/mlxsw/core_thermal.c | 129 ++++++++++++++++++ + 1 file changed, 129 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +index e860cade5..88a2f63c8 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_thermal.c +@@ -96,6 +96,7 @@ struct mlxsw_thermal_module { + }; + + struct mlxsw_thermal_area { ++ struct mlxsw_thermal *parent; + struct mlxsw_thermal_module *tz_module_arr; + u8 tz_module_num; + struct mlxsw_thermal_module *tz_gearbox_arr; +@@ -113,6 +114,7 @@ struct mlxsw_thermal { + u8 cooling_levels[MLXSW_THERMAL_MAX_STATE + 1]; + struct mlxsw_thermal_trip trips[MLXSW_THERMAL_NUM_TRIPS]; + struct mlxsw_thermal_area *main; ++ struct mlxsw_thermal_area **linecards; + unsigned int tz_highest_score; + struct thermal_zone_device *tz_highest_dev; + }; +@@ -989,6 +991,126 @@ mlxsw_thermal_gearboxes_fini(struct mlxsw_thermal *thermal, + mlxsw_thermal_gearbox_tz_fini(&area->tz_gearbox_arr[i]); + } + ++static void ++mlxsw_thermal_got_active(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ const struct mlxsw_linecard *linecard, void *priv) ++{ ++ struct mlxsw_env_gearbox_sensors_map map; ++ struct mlxsw_thermal *thermal = priv; ++ struct mlxsw_thermal_area *lc; ++ int err; ++ ++ lc = kzalloc(sizeof(*lc), GFP_KERNEL); ++ if (!lc) ++ return; ++ ++ lc->slot_index = slot_index; ++ lc->parent = thermal; ++ thermal->linecards[slot_index - 1] = lc; ++ err = mlxsw_thermal_modules_init(thermal->bus_info->dev, thermal->core, ++ thermal, lc); ++ if (err) ++ goto err_thermal_linecard_modules_init; ++ ++ err = mlxsw_env_sensor_map_create(thermal->core, thermal->bus_info, ++ linecard->slot_index, &map); ++ if (err) ++ goto err_thermal_linecard_env_sensor_map_create; ++ ++ lc->gearbox_sensor_map = map.sensor_bit_map; ++ lc->tz_gearbox_num = map.sensor_count; ++ lc->tz_gearbox_arr = kcalloc(lc->tz_gearbox_num, sizeof(*lc->tz_gearbox_arr), ++ GFP_KERNEL); ++ if (!lc->tz_gearbox_arr) { ++ err = -ENOMEM; ++ goto err_tz_gearbox_arr_alloc; ++ } ++ ++ err = mlxsw_thermal_gearboxes_init(thermal->bus_info->dev, thermal->core, ++ thermal, lc); ++ if (err) ++ goto err_thermal_linecard_gearboxes_init; ++ ++ return; ++ ++err_thermal_linecard_gearboxes_init: ++ kfree(lc->tz_gearbox_arr); ++err_tz_gearbox_arr_alloc: ++ mlxsw_env_sensor_map_destroy(thermal->bus_info, ++ lc->gearbox_sensor_map); ++err_thermal_linecard_env_sensor_map_create: ++ mlxsw_thermal_modules_fini(thermal, lc); ++err_thermal_linecard_modules_init: ++ kfree(lc); ++ thermal->linecards[slot_index - 1] = NULL; ++} ++ ++static void mlxsw_thermal_got_inactive(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ const struct mlxsw_linecard *linecard, void *priv) ++{ ++ struct mlxsw_thermal *thermal = priv; ++ struct mlxsw_thermal_area *lc = thermal->linecards[slot_index - 1]; ++ ++ mlxsw_thermal_gearboxes_fini(thermal, lc); ++ kfree(lc->tz_gearbox_arr); ++ mlxsw_env_sensor_map_destroy(thermal->bus_info, ++ lc->gearbox_sensor_map); ++ mlxsw_thermal_modules_fini(thermal, lc); ++ kfree(lc); ++ thermal->linecards[slot_index - 1] = NULL; ++} ++ ++static struct mlxsw_linecards_event_ops mlxsw_thermal_event_ops = { ++ .got_active = mlxsw_thermal_got_active, ++ .got_inactive = mlxsw_thermal_got_inactive, ++}; ++ ++static int mlxsw_thermal_linecards_register(struct mlxsw_core *mlxsw_core, ++ struct mlxsw_thermal *thermal) ++{ ++ struct mlxsw_linecards *linecards = mlxsw_core_linecards(mlxsw_core); ++ int err; ++ ++ if (!linecards || !linecards->count) ++ return 0; ++ ++ thermal->linecards = kcalloc(linecards->count, sizeof(*thermal->linecards), ++ GFP_KERNEL); ++ if (!thermal->linecards) ++ return -ENOMEM; ++ ++ err = mlxsw_linecards_event_ops_register(mlxsw_core, ++ &mlxsw_thermal_event_ops, ++ thermal); ++ if (err) ++ goto err_linecards_event_ops_register; ++ ++ return 0; ++ ++err_linecards_event_ops_register: ++ kfree(thermal->linecards); ++ return err; ++} ++ ++static void mlxsw_thermal_linecards_unregister(struct mlxsw_thermal *thermal) ++{ ++ struct mlxsw_linecards *linecards = mlxsw_core_linecards(thermal->core); ++ int i; ++ ++ if (!linecards || !linecards->count) ++ return; ++ ++ for (i = 1; i <= linecards->count; i++) { ++ if (thermal->linecards[i - 1]) ++ mlxsw_thermal_got_inactive(thermal->core, i, NULL, ++ thermal); ++ } ++ ++ mlxsw_linecards_event_ops_unregister(thermal->core, ++ &mlxsw_thermal_event_ops, thermal); ++ kfree(thermal->linecards); ++} ++ + int mlxsw_thermal_init(struct mlxsw_core *core, + const struct mlxsw_bus_info *bus_info, + struct mlxsw_thermal **p_thermal) +@@ -1094,6 +1216,10 @@ int mlxsw_thermal_init(struct mlxsw_core *core, + if (err) + goto err_thermal_gearboxes_init; + ++ err = mlxsw_thermal_linecards_register(core, thermal); ++ if (err) ++ goto err_linecards_register; ++ + err = thermal_zone_device_enable(thermal->tzdev); + if (err) + goto err_thermal_zone_device_enable; +@@ -1102,6 +1228,8 @@ int mlxsw_thermal_init(struct mlxsw_core *core, + return 0; + + err_thermal_zone_device_enable: ++ mlxsw_thermal_linecards_unregister(thermal); ++err_linecards_register: + mlxsw_thermal_gearboxes_fini(thermal, thermal->main); + err_thermal_gearboxes_init: + mlxsw_thermal_gearboxes_main_fini(thermal->main); +@@ -1129,6 +1257,7 @@ void mlxsw_thermal_fini(struct mlxsw_thermal *thermal) + { + int i; + ++ mlxsw_thermal_linecards_unregister(thermal); + mlxsw_thermal_gearboxes_fini(thermal, thermal->main); + mlxsw_thermal_gearboxes_main_fini(thermal->main); + mlxsw_thermal_modules_fini(thermal, thermal->main); +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0150-mlxsw-core_hwmon-Add-interfaces-for-line-card-initia.patch b/platform/mellanox/non-upstream-patches/patches/0150-mlxsw-core_hwmon-Add-interfaces-for-line-card-initia.patch new file mode 100644 index 000000000000..9b9e5133860f --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0150-mlxsw-core_hwmon-Add-interfaces-for-line-card-initia.patch @@ -0,0 +1,235 @@ +From 97f2a14ec9543588b37be8fc54aad9ed13cceec9 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 12 May 2021 22:57:42 +0300 +Subject: [PATCH] mlxsw: core_hwmon: Add interfaces for line card + initialization and de-initialization + +Add callback functions for line card 'hwmon' initialization and +de-initialization. Each line card is associated with the relevant +'hwmon' device, which may contain thermal attributes for the cages +and gearboxes found on this line card. + +The line card 'hwmon' initialization / de-initialization APIs are to be +called when line card is set to active / inactive state by +got_active() / got_inactive() callbacks from line card state machine. + +For example cage temperature for module #9 located at line card #7 will +be exposed by utility 'sensors' like: +linecard#07 +front panel 009: +32.0C (crit = +70.0C, emerg = +80.0C) +And temperature for gearbox #3 located at line card #5 will be exposed +like: +linecard#05 +gearbox 003: +41.0C (highest = +41.0C) + +Signed-off-by: Vadim Pasternak +Signed-off-by: Jiri Pirko +--- + .../net/ethernet/mellanox/mlxsw/core_hwmon.c | 137 +++++++++++++++++- + 1 file changed, 134 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +index 6af23f472..a27146cca 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core_hwmon.c +@@ -19,6 +19,7 @@ + #define MLXSW_HWMON_ATTR_PER_SENSOR 3 + #define MLXSW_HWMON_ATTR_PER_MODULE 7 + #define MLXSW_HWMON_ATTR_PER_GEARBOX 4 ++#define MLXSW_HWMON_DEV_NAME_LEN_MAX 16 + + #define MLXSW_HWMON_ATTR_COUNT (MLXSW_HWMON_SENSORS_MAX_COUNT * MLXSW_HWMON_ATTR_PER_SENSOR + \ + MLXSW_HWMON_MODULES_MAX_COUNT * MLXSW_HWMON_ATTR_PER_MODULE + \ +@@ -42,6 +43,7 @@ mlxsw_hwmon_get_attr_index(int index, int count, u16 *gearbox_sensor_map) + } + + struct mlxsw_hwmon_dev { ++ char name[MLXSW_HWMON_DEV_NAME_LEN_MAX]; + struct mlxsw_hwmon *hwmon; + struct device *hwmon_dev; + struct attribute_group group; +@@ -59,6 +61,7 @@ struct mlxsw_hwmon { + struct mlxsw_core *core; + const struct mlxsw_bus_info *bus_info; + struct mlxsw_hwmon_dev *main; ++ struct mlxsw_hwmon_dev **linecards; + }; + + static ssize_t mlxsw_hwmon_temp_show(struct device *dev, +@@ -405,9 +408,14 @@ mlxsw_hwmon_module_temp_label_show(struct device *dev, + { + struct mlxsw_hwmon_attr *mlxsw_hwmon_attr = + container_of(attr, struct mlxsw_hwmon_attr, dev_attr); ++ struct mlxsw_hwmon_dev *mlxsw_hwmon_dev; ++ int index = mlxsw_hwmon_attr->type_index; ++ ++ mlxsw_hwmon_dev = mlxsw_hwmon_attr->mlxsw_hwmon_dev; ++ if (strlen(mlxsw_hwmon_dev->name)) ++ index += 1; + +- return sprintf(buf, "front panel %03u\n", +- mlxsw_hwmon_attr->type_index); ++ return sprintf(buf, "front panel %03u\n", index); + } + + static ssize_t +@@ -691,7 +699,7 @@ static int mlxsw_hwmon_module_init(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev) + u8 module_sensor_max; + int i, err; + +- mlxsw_reg_mgpir_pack(mgpir_pl, 0); ++ mlxsw_reg_mgpir_pack(mgpir_pl, mlxsw_hwmon_dev->slot_index); + err = mlxsw_reg_query(mlxsw_hwmon->core, MLXSW_REG(mgpir), mgpir_pl); + if (err) + return err; +@@ -819,6 +827,122 @@ mlxsw_hwmon_gearbox_init(struct mlxsw_hwmon_dev *mlxsw_hwmon_dev, u8 gbox_num) + return 0; + } + ++static void ++mlxsw_hwmon_got_active(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ const struct mlxsw_linecard *linecard, void *priv) ++{ ++ struct mlxsw_hwmon *hwmon = priv; ++ struct device *dev = hwmon->bus_info->dev; ++ struct mlxsw_env_gearbox_sensors_map map; ++ struct mlxsw_hwmon_dev *lc; ++ int err; ++ ++ lc = kzalloc(sizeof(*lc), GFP_KERNEL); ++ if (!lc) ++ return; ++ lc->slot_index = slot_index; ++ lc->hwmon = hwmon; ++ err = mlxsw_hwmon_module_init(lc); ++ if (err) ++ goto err_hwmon_linecard_module_init; ++ ++ err = mlxsw_env_sensor_map_create(hwmon->core, ++ hwmon->bus_info, slot_index, ++ &map); ++ if (err) ++ goto err_hwmon_linecard_env_sensor_map_create; ++ ++ lc->gearbox_sensor_map = map.sensor_bit_map; ++ err = mlxsw_hwmon_gearbox_init(lc, map.sensor_count); ++ if (err) ++ goto err_hwmon_linecard_gearbox_init; ++ ++ lc->groups[0] = &lc->group; ++ lc->group.attrs = lc->attrs; ++ sprintf(lc->name, "%s#%02u", "linecard", slot_index); ++ lc->hwmon_dev = hwmon_device_register_with_groups(dev, (const char *) lc->name, ++ lc, lc->groups); ++ if (IS_ERR(lc->hwmon_dev)) { ++ err = PTR_ERR(lc->hwmon_dev); ++ goto err_hwmon_linecard_register; ++ } ++ hwmon->linecards[slot_index - 1] = lc; ++ ++ return; ++ ++err_hwmon_linecard_register: ++err_hwmon_linecard_gearbox_init: ++ mlxsw_env_sensor_map_destroy(hwmon->bus_info, ++ lc->gearbox_sensor_map); ++err_hwmon_linecard_env_sensor_map_create: ++err_hwmon_linecard_module_init: ++ kfree(lc); ++} ++ ++static void ++mlxsw_hwmon_got_inactive(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ const struct mlxsw_linecard *linecard, void *priv) ++{ ++ struct mlxsw_hwmon *hwmon = priv; ++ struct mlxsw_hwmon_dev *lc = hwmon->linecards[slot_index - 1]; ++ ++ if (lc->hwmon_dev) ++ hwmon_device_unregister(lc->hwmon_dev); ++ mlxsw_env_sensor_map_destroy(hwmon->bus_info, ++ lc->gearbox_sensor_map); ++ kfree(lc); ++ hwmon->linecards[slot_index - 1] = NULL; ++} ++ ++static struct mlxsw_linecards_event_ops mlxsw_hwmon_event_ops = { ++ .got_active = mlxsw_hwmon_got_active, ++ .got_inactive = mlxsw_hwmon_got_inactive, ++}; ++ ++static int mlxsw_hwmon_linecards_register(struct mlxsw_hwmon *hwmon) ++{ ++ struct mlxsw_linecards *linecards = mlxsw_core_linecards(hwmon->core); ++ int err; ++ ++ if (!linecards || !linecards->count) ++ return 0; ++ ++ hwmon->linecards = kcalloc(linecards->count, sizeof(*hwmon->linecards), ++ GFP_KERNEL); ++ if (!hwmon->linecards) ++ return -ENOMEM; ++ ++ err = mlxsw_linecards_event_ops_register(hwmon->core, ++ &mlxsw_hwmon_event_ops, ++ hwmon); ++ if (err) ++ goto err_linecards_event_ops_register; ++ ++ return 0; ++ ++err_linecards_event_ops_register: ++ kfree(hwmon->linecards); ++ return err; ++} ++ ++static void mlxsw_hwmon_linecards_unregister(struct mlxsw_hwmon *hwmon) ++{ ++ struct mlxsw_linecards *linecards = mlxsw_core_linecards(hwmon->core); ++ int i; ++ ++ if (!linecards || !linecards->count) ++ return; ++ ++ for (i = 1; i <= linecards->count; i++) { ++ if (hwmon->linecards[i - 1]) ++ mlxsw_hwmon_got_inactive(hwmon->core, i, NULL, hwmon); ++ } ++ ++ mlxsw_linecards_event_ops_unregister(hwmon->core, ++ &mlxsw_hwmon_event_ops, hwmon); ++ kfree(hwmon->linecards); ++} ++ + int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core, + const struct mlxsw_bus_info *mlxsw_bus_info, + struct mlxsw_hwmon **p_hwmon) +@@ -872,10 +996,16 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core, + goto err_hwmon_register; + } + ++ err = mlxsw_hwmon_linecards_register(mlxsw_hwmon); ++ if (err) ++ goto err_linecards_register; ++ + mlxsw_hwmon->main->hwmon_dev = hwmon_dev; + *p_hwmon = mlxsw_hwmon; + return 0; + ++err_linecards_register: ++ hwmon_device_unregister(mlxsw_hwmon->main->hwmon_dev); + err_hwmon_register: + err_gearbox_init: + mlxsw_hwmon_gearbox_main_fini(mlxsw_hwmon->main); +@@ -891,6 +1021,7 @@ int mlxsw_hwmon_init(struct mlxsw_core *mlxsw_core, + + void mlxsw_hwmon_fini(struct mlxsw_hwmon *mlxsw_hwmon) + { ++ mlxsw_hwmon_linecards_unregister(mlxsw_hwmon); + hwmon_device_unregister(mlxsw_hwmon->main->hwmon_dev); + mlxsw_hwmon_gearbox_main_fini(mlxsw_hwmon->main); + kfree(mlxsw_hwmon->main); +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0151-mlxsw-minimal-Prepare-driver-for-modular-system-supp.patch b/platform/mellanox/non-upstream-patches/patches/0151-mlxsw-minimal-Prepare-driver-for-modular-system-supp.patch new file mode 100644 index 000000000000..dc18597031be --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0151-mlxsw-minimal-Prepare-driver-for-modular-system-supp.patch @@ -0,0 +1,495 @@ +From 37eabf5ec0121c1a5092f48360b3d1208a22e655 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Thu, 30 Dec 2021 16:02:59 +0000 +Subject: [PATCH] mlxsw: minimal: Prepare driver for modular system support + +As a preparation for line cards support: +- Allocate per line card array according to the queried number of slots + in the system. For each line card, allocate a port mapping array + according to the queried maximum number of ports available in system. + Port mapping array includes port object handle, local port number and + module number. +- Extend port creation APIs with 'slot_index' argument. +- Extend port structure with slot index and module offset for this slot + index. + +For main board, slot will always be set to zero and these APIs will work +as before. For the ports located on line cards, slot should be set to the +physical slot number, where line card is located in modular systems. + +Signed-off-by: Vadim Pasternak +--- + drivers/net/ethernet/mellanox/mlxsw/minimal.c | 293 +++++++++++++++--- + 1 file changed, 242 insertions(+), 51 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +index 30925f573..59c5053dc 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +@@ -24,22 +24,40 @@ static const struct mlxsw_fw_rev mlxsw_m_fw_rev = { + .subminor = MLXSW_M_FWREV_SUBMINOR, + }; + ++struct mlxsw_m_line_card; + struct mlxsw_m_port; + + struct mlxsw_m { +- struct mlxsw_m_port **ports; +- int *module_to_port; + struct mlxsw_core *core; + const struct mlxsw_bus_info *bus_info; + u8 base_mac[ETH_ALEN]; + u8 max_ports; ++ u8 max_module_count; /* Maximum number of modules per-slot. */ ++ u8 num_of_slots; /* Including the main board. */ ++ struct mlxsw_m_line_card **line_cards; ++}; ++ ++struct mlxsw_m_port_mapping { ++ struct mlxsw_m_port *port; ++ int module_to_port; ++ u8 module; ++}; ++ ++struct mlxsw_m_line_card { ++ struct mlxsw_m *mlxsw_m; ++ u8 max_ports; ++ u8 module_offset; ++ bool active; ++ struct mlxsw_m_port_mapping port_mapping[]; + }; + + struct mlxsw_m_port { + struct net_device *dev; + struct mlxsw_m *mlxsw_m; +- u8 local_port; ++ u16 local_port; + u8 module; ++ u8 slot_index; ++ u8 module_offset; + }; + + static int mlxsw_m_base_mac_get(struct mlxsw_m *mlxsw_m) +@@ -111,8 +129,8 @@ static int mlxsw_m_get_module_info(struct net_device *netdev, + struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev); + struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core; + +- return mlxsw_env_get_module_info(core, 0, mlxsw_m_port->module, +- modinfo); ++ return mlxsw_env_get_module_info(core, mlxsw_m_port->slot_index, ++ mlxsw_m_port->module, modinfo); + } + + static int +@@ -122,7 +140,8 @@ mlxsw_m_get_module_eeprom(struct net_device *netdev, struct ethtool_eeprom *ee, + struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev); + struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core; + +- return mlxsw_env_get_module_eeprom(netdev, core, 0, ++ return mlxsw_env_get_module_eeprom(netdev, core, ++ mlxsw_m_port->slot_index, + mlxsw_m_port->module, ee, data); + } + +@@ -134,7 +153,8 @@ mlxsw_m_get_module_eeprom_by_page(struct net_device *netdev, + struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev); + struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core; + +- return mlxsw_env_get_module_eeprom_by_page(core, 0, ++ return mlxsw_env_get_module_eeprom_by_page(core, ++ mlxsw_m_port->slot_index, + mlxsw_m_port->module, + page, extack); + } +@@ -144,7 +164,8 @@ static int mlxsw_m_reset(struct net_device *netdev, u32 *flags) + struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev); + struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core; + +- return mlxsw_env_reset_module(netdev, core, 0, mlxsw_m_port->module, ++ return mlxsw_env_reset_module(netdev, core, mlxsw_m_port->slot_index, ++ mlxsw_m_port->module, + flags); + } + +@@ -156,7 +177,8 @@ mlxsw_m_get_module_power_mode(struct net_device *netdev, + struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev); + struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core; + +- return mlxsw_env_get_module_power_mode(core, 0, mlxsw_m_port->module, ++ return mlxsw_env_get_module_power_mode(core, mlxsw_m_port->slot_index, ++ mlxsw_m_port->module, + params, extack); + } + +@@ -168,7 +190,8 @@ mlxsw_m_set_module_power_mode(struct net_device *netdev, + struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev); + struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core; + +- return mlxsw_env_set_module_power_mode(core, 0, mlxsw_m_port->module, ++ return mlxsw_env_set_module_power_mode(core, mlxsw_m_port->slot_index, ++ mlxsw_m_port->module, + params->policy, extack); + } + +@@ -199,19 +222,31 @@ mlxsw_m_port_dev_addr_get(struct mlxsw_m_port *mlxsw_m_port) + * to be such it does not overflow when adding local_port + * value. + */ +- dev->dev_addr[ETH_ALEN - 1] = mlxsw_m_port->module + 1; ++ dev->dev_addr[ETH_ALEN - 1] = mlxsw_m_port->module + 1 + ++ mlxsw_m_port->module_offset; + return 0; + } + ++static struct ++mlxsw_m_port_mapping *mlxsw_m_port_mapping_get(struct mlxsw_m *mlxsw_m, ++ u8 slot_index, u8 local_port) ++{ ++ return &mlxsw_m->line_cards[slot_index]->port_mapping[local_port]; ++} ++ + static int +-mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u8 local_port, u8 module) ++mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u8 slot_index, u16 local_port, ++ u8 module) + { ++ struct mlxsw_m_port_mapping *port_mapping; + struct mlxsw_m_port *mlxsw_m_port; + struct net_device *dev; ++ u8 module_offset; + int err; + +- err = mlxsw_core_port_init(mlxsw_m->core, local_port, 0, +- module + 1, false, 0, false, ++ module_offset = mlxsw_m->line_cards[slot_index]->module_offset; ++ err = mlxsw_core_port_init(mlxsw_m->core, local_port, slot_index, ++ module + 1 + module_offset, false, 0, false, + 0, mlxsw_m->base_mac, + sizeof(mlxsw_m->base_mac)); + if (err) { +@@ -233,6 +268,13 @@ mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u8 local_port, u8 module) + mlxsw_m_port->mlxsw_m = mlxsw_m; + mlxsw_m_port->local_port = local_port; + mlxsw_m_port->module = module; ++ mlxsw_m_port->slot_index = slot_index; ++ /* Add module offset for line card. Offset for main board iz zero. ++ * For line card in slot #n offset is calculated as (#n - 1) ++ * multiplied by maximum modules number, which could be found on a line ++ * card. ++ */ ++ mlxsw_m_port->module_offset = module_offset; + + dev->netdev_ops = &mlxsw_m_port_netdev_ops; + dev->ethtool_ops = &mlxsw_m_port_ethtool_ops; +@@ -245,7 +287,9 @@ mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u8 local_port, u8 module) + } + + netif_carrier_off(dev); +- mlxsw_m->ports[local_port] = mlxsw_m_port; ++ port_mapping = mlxsw_m_port_mapping_get(mlxsw_m, slot_index, ++ local_port); ++ port_mapping->port = mlxsw_m_port; + err = register_netdev(dev); + if (err) { + dev_err(mlxsw_m->bus_info->dev, "Port %d: Failed to register netdev\n", +@@ -259,7 +303,7 @@ mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u8 local_port, u8 module) + return 0; + + err_register_netdev: +- mlxsw_m->ports[local_port] = NULL; ++ port_mapping->port = NULL; + err_dev_addr_get: + free_netdev(dev); + err_alloc_etherdev: +@@ -267,72 +311,130 @@ mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u8 local_port, u8 module) + return err; + } + +-static void mlxsw_m_port_remove(struct mlxsw_m *mlxsw_m, u8 local_port) ++static void mlxsw_m_port_remove(struct mlxsw_m *mlxsw_m, u8 slot_index, ++ u16 local_port) + { +- struct mlxsw_m_port *mlxsw_m_port = mlxsw_m->ports[local_port]; ++ struct mlxsw_m_port_mapping *port_mapping; ++ struct mlxsw_m_port *mlxsw_m_port; + ++ port_mapping = mlxsw_m_port_mapping_get(mlxsw_m, slot_index, ++ local_port); ++ mlxsw_m_port = port_mapping->port; + mlxsw_core_port_clear(mlxsw_m->core, local_port, mlxsw_m); + unregister_netdev(mlxsw_m_port->dev); /* This calls ndo_stop */ +- mlxsw_m->ports[local_port] = NULL; ++ port_mapping->port = NULL; + free_netdev(mlxsw_m_port->dev); + mlxsw_core_port_fini(mlxsw_m->core, local_port); + } + +-static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m) ++static int mlxsw_m_port_module_map(struct mlxsw_m *mlxsw_m, u8 slot_index, ++ u16 local_port, u8 module) ++{ ++ struct mlxsw_m_port_mapping *port_mapping; ++ ++ port_mapping = mlxsw_m_port_mapping_get(mlxsw_m, slot_index, ++ local_port); ++ ++ if (WARN_ON_ONCE(port_mapping->module_to_port >= mlxsw_m->max_ports)) ++ return -EINVAL; ++ mlxsw_env_module_port_map(mlxsw_m->core, slot_index, module); ++ port_mapping->module_to_port = local_port; ++ port_mapping->module = module; ++ ++ return 0; ++} ++ ++static void ++mlxsw_m_port_module_unmap(struct mlxsw_m *mlxsw_m, u8 slot_index, ++ struct mlxsw_m_port_mapping *port_mapping) + { ++ port_mapping->module_to_port = -1; ++ mlxsw_env_module_port_unmap(mlxsw_m->core, slot_index, ++ port_mapping->module); ++} ++ ++static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m, u8 slot_index) ++{ ++ struct mlxsw_m_port_mapping *port_mapping; ++ struct mlxsw_m_line_card *line_card; + char mgpir_pl[MLXSW_REG_MGPIR_LEN]; + int i, err; + +- mlxsw_reg_mgpir_pack(mgpir_pl, 0); ++ mlxsw_reg_mgpir_pack(mgpir_pl, slot_index); + err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(mgpir), mgpir_pl); + if (err) + return err; + ++ line_card = mlxsw_m->line_cards[slot_index]; + mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, +- &mlxsw_m->max_ports, NULL); +- if (!mlxsw_m->max_ports) ++ &line_card->max_ports, NULL); ++ if (!line_card->max_ports) + return 0; + +- mlxsw_m->ports = kcalloc(mlxsw_m->max_ports, sizeof(*mlxsw_m->ports), +- GFP_KERNEL); +- if (!mlxsw_m->ports) +- return -ENOMEM; ++ line_card->max_ports += 1; ++ line_card->module_offset = slot_index ? (slot_index - 1) * ++ mlxsw_m->max_module_count : 0; + +- mlxsw_m->module_to_port = kmalloc_array(mlxsw_m->max_ports, sizeof(int), +- GFP_KERNEL); +- if (!mlxsw_m->module_to_port) { +- err = -ENOMEM; +- goto err_module_to_port_alloc; ++ /* Fill out module to local port mapping array */ ++ for (i = 1; i < mlxsw_m->line_cards[slot_index]->max_ports; i++) { ++ err = mlxsw_m_port_module_map(mlxsw_m, slot_index, i + ++ line_card->module_offset, i - 1); ++ if (err) ++ goto err_module_to_port_map; + } + +- /* Create port objects for each entry. */ ++ /* Create port objects for each valid entry */ + for (i = 0; i < mlxsw_m->max_ports; i++) { +- mlxsw_m->module_to_port[i] = i; +- err = mlxsw_m_port_create(mlxsw_m, mlxsw_m->module_to_port[i], i); +- if (err) +- goto err_module_to_port_create; ++ port_mapping = mlxsw_m_port_mapping_get(mlxsw_m, slot_index, ++ i); ++ if (port_mapping->module_to_port > 0) { ++ err = mlxsw_m_port_create(mlxsw_m, slot_index, ++ port_mapping->module_to_port, ++ port_mapping->module); ++ if (err) ++ goto err_module_to_port_create; ++ } + } + + return 0; + + err_module_to_port_create: +- for (i--; i >= 0; i--) +- mlxsw_m_port_remove(mlxsw_m, mlxsw_m->module_to_port[i]); +- kfree(mlxsw_m->module_to_port); +-err_module_to_port_alloc: +- kfree(mlxsw_m->ports); ++ for (i--; i >= 0; i--) { ++ port_mapping = mlxsw_m_port_mapping_get(mlxsw_m, slot_index, ++ i); ++ if (port_mapping->module_to_port > 0) ++ mlxsw_m_port_remove(mlxsw_m, slot_index, ++ port_mapping->module_to_port); ++ } ++ i = mlxsw_m->max_ports; ++err_module_to_port_map: ++ for (i--; i > 0; i--) { ++ port_mapping = mlxsw_m_port_mapping_get(mlxsw_m, slot_index, ++ i); ++ if (port_mapping->module_to_port > 0) ++ mlxsw_m_port_module_unmap(mlxsw_m, slot_index, ++ port_mapping); ++ } + return err; + } + +-static void mlxsw_m_ports_remove(struct mlxsw_m *mlxsw_m) ++static void mlxsw_m_ports_remove(struct mlxsw_m *mlxsw_m, u8 slot_index) + { ++ struct mlxsw_m_port_mapping *port_mapping; ++ u8 module; + int i; + +- for (i = 0; i < mlxsw_m->max_ports; i++) +- mlxsw_m_port_remove(mlxsw_m, mlxsw_m->module_to_port[i]); +- +- kfree(mlxsw_m->module_to_port); +- kfree(mlxsw_m->ports); ++ for (i = 0; i < mlxsw_m->max_ports; i++) { ++ port_mapping = mlxsw_m_port_mapping_get(mlxsw_m, slot_index, ++ i); ++ if (port_mapping->module_to_port > 0) { ++ module = port_mapping->port->module; ++ mlxsw_m_port_remove(mlxsw_m, slot_index, ++ port_mapping->module_to_port); ++ mlxsw_m_port_module_unmap(mlxsw_m, slot_index, ++ port_mapping); ++ } ++ } + } + + static int mlxsw_m_fw_rev_validate(struct mlxsw_m *mlxsw_m) +@@ -353,6 +455,78 @@ static int mlxsw_m_fw_rev_validate(struct mlxsw_m *mlxsw_m) + return -EINVAL; + } + ++static int mlxsw_m_get_peripheral_info(struct mlxsw_m *mlxsw_m) ++{ ++ char mgpir_pl[MLXSW_REG_MGPIR_LEN]; ++ u8 module_count; ++ int err; ++ ++ mlxsw_reg_mgpir_pack(mgpir_pl, 0); ++ err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(mgpir), mgpir_pl); ++ if (err) ++ return err; ++ ++ mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, &module_count, ++ &mlxsw_m->num_of_slots); ++ /* If the system is modular, get the maximum number of modules per-slot. ++ * Otherwise, get the maximum number of modules on the main board. ++ */ ++ mlxsw_m->max_module_count = mlxsw_m->num_of_slots ? ++ mlxsw_reg_mgpir_max_modules_per_slot_get(mgpir_pl) : ++ module_count; ++ /* Add slot for main board. */ ++ mlxsw_m->num_of_slots += 1; ++ ++ return 0; ++} ++ ++static int mlxsw_env_line_cards_alloc(struct mlxsw_m *mlxsw_m) ++{ ++ unsigned int max_ports = mlxsw_core_max_ports(mlxsw_m->core); ++ struct mlxsw_m_port_mapping *port_mapping; ++ int i, j; ++ ++ mlxsw_m->line_cards = kcalloc(mlxsw_m->num_of_slots, ++ sizeof(*mlxsw_m->line_cards), ++ GFP_KERNEL); ++ if (!mlxsw_m->line_cards) ++ goto err_kcalloc; ++ ++ for (i = 0; i < mlxsw_m->num_of_slots; i++) { ++ mlxsw_m->line_cards[i] = kzalloc(struct_size(mlxsw_m->line_cards[i], ++ port_mapping, max_ports), ++ GFP_KERNEL); ++ if (!mlxsw_m->line_cards[i]) ++ goto kzalloc_err; ++ ++ /* Invalidate the entries of module to local port mapping array */ ++ for (j = 0; j < mlxsw_m->max_ports; j++) { ++ port_mapping = mlxsw_m_port_mapping_get(mlxsw_m, i, j); ++ port_mapping->module_to_port = -1; ++ } ++ } ++ ++ mlxsw_m->max_ports = max_ports; ++ ++ return 0; ++ ++kzalloc_err: ++ for (i--; i >= 0; i--) ++ kfree(mlxsw_m->line_cards[i]); ++err_kcalloc: ++ kfree(mlxsw_m->line_cards); ++ return -ENOMEM; ++} ++ ++static void mlxsw_m_line_cards_free(struct mlxsw_m *mlxsw_m) ++{ ++ int i = mlxsw_m->num_of_slots; ++ ++ for (i--; i >= 0; i--) ++ kfree(mlxsw_m->line_cards[i]); ++ kfree(mlxsw_m->line_cards); ++} ++ + static int mlxsw_m_init(struct mlxsw_core *mlxsw_core, + const struct mlxsw_bus_info *mlxsw_bus_info, + struct netlink_ext_ack *extack) +@@ -367,26 +541,43 @@ static int mlxsw_m_init(struct mlxsw_core *mlxsw_core, + if (err) + return err; + ++ err = mlxsw_m_get_peripheral_info(mlxsw_m); ++ if (err) { ++ dev_err(mlxsw_m->bus_info->dev, "Failed to get peripheral info\n"); ++ return err; ++ } ++ + err = mlxsw_m_base_mac_get(mlxsw_m); + if (err) { + dev_err(mlxsw_m->bus_info->dev, "Failed to get base mac\n"); + return err; + } + +- err = mlxsw_m_ports_create(mlxsw_m); ++ err = mlxsw_env_line_cards_alloc(mlxsw_m); + if (err) { +- dev_err(mlxsw_m->bus_info->dev, "Failed to create ports\n"); ++ dev_err(mlxsw_m->bus_info->dev, "Failed to allocate memory\n"); + return err; + } + ++ err = mlxsw_m_ports_create(mlxsw_m, 0); ++ if (err) { ++ dev_err(mlxsw_m->bus_info->dev, "Failed to create ports\n"); ++ goto err_mlxsw_m_ports_create; ++ } ++ + return 0; ++ ++err_mlxsw_m_ports_create: ++ mlxsw_m_line_cards_free(mlxsw_m); ++ return err; + } + + static void mlxsw_m_fini(struct mlxsw_core *mlxsw_core) + { + struct mlxsw_m *mlxsw_m = mlxsw_core_driver_priv(mlxsw_core); + +- mlxsw_m_ports_remove(mlxsw_m); ++ mlxsw_m_ports_remove(mlxsw_m, 0); ++ mlxsw_m_line_cards_free(mlxsw_m); + } + + static const struct mlxsw_config_profile mlxsw_m_config_profile; +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0152-mlxsw-core-Extend-bus-init-function-with-event-handl.patch b/platform/mellanox/non-upstream-patches/patches/0152-mlxsw-core-Extend-bus-init-function-with-event-handl.patch new file mode 100644 index 000000000000..99c1af62b794 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0152-mlxsw-core-Extend-bus-init-function-with-event-handl.patch @@ -0,0 +1,90 @@ +From bf88a40c8d0379e1ce8a6cc0a2bf4f935f90307c Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Wed, 15 Dec 2021 08:59:14 +0000 +Subject: [PATCH] mlxsw: core: Extend bus init function with event handler + argument + +The purpose of new argument - is to introduce system event handler for +treating line card activation / deactivation signals on modular system. + +Signed-off-by: Vadim Pasternak +--- + drivers/net/ethernet/mellanox/mlxsw/core.c | 3 ++- + drivers/net/ethernet/mellanox/mlxsw/core.h | 4 +++- + drivers/net/ethernet/mellanox/mlxsw/i2c.c | 3 ++- + drivers/net/ethernet/mellanox/mlxsw/pci.c | 9 ++++++--- + 4 files changed, 13 insertions(+), 6 deletions(-) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c +index 8c1280781..a9bb43837 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.c +@@ -2005,7 +2005,8 @@ __mlxsw_core_bus_device_register(const struct mlxsw_bus_info *mlxsw_bus_info, + } + + res = mlxsw_driver->res_query_enabled ? &mlxsw_core->res : NULL; +- err = mlxsw_bus->init(bus_priv, mlxsw_core, mlxsw_driver->profile, res); ++ err = mlxsw_bus->init(bus_priv, mlxsw_core, mlxsw_driver->profile, res, ++ mlxsw_driver->sys_event_handler); + if (err) + goto err_bus_init; + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.h b/drivers/net/ethernet/mellanox/mlxsw/core.h +index 10ea541bb..b09f9013d 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.h ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.h +@@ -390,6 +390,7 @@ struct mlxsw_driver { + */ + void (*ptp_transmitted)(struct mlxsw_core *mlxsw_core, + struct sk_buff *skb, u8 local_port); ++ void (*sys_event_handler)(struct mlxsw_core *mlxsw_core); + + u8 txhdr_len; + const struct mlxsw_config_profile *profile; +@@ -432,7 +433,8 @@ struct mlxsw_bus { + const char *kind; + int (*init)(void *bus_priv, struct mlxsw_core *mlxsw_core, + const struct mlxsw_config_profile *profile, +- struct mlxsw_res *res); ++ struct mlxsw_res *res, ++ void (*sys_event_handler)(struct mlxsw_core *mlxsw_core)); + void (*fini)(void *bus_priv); + bool (*skb_transmit_busy)(void *bus_priv, + const struct mlxsw_tx_info *tx_info); +diff --git a/drivers/net/ethernet/mellanox/mlxsw/i2c.c b/drivers/net/ethernet/mellanox/mlxsw/i2c.c +index b8a5c0cbb..b75416561 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/i2c.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/i2c.c +@@ -530,7 +530,8 @@ static int mlxsw_i2c_skb_transmit(void *bus_priv, struct sk_buff *skb, + static int + mlxsw_i2c_init(void *bus_priv, struct mlxsw_core *mlxsw_core, + const struct mlxsw_config_profile *profile, +- struct mlxsw_res *res) ++ struct mlxsw_res *res, ++ void (*sys_event_handler)(struct mlxsw_core *mlxsw_core)) + { + struct mlxsw_i2c *mlxsw_i2c = bus_priv; + char *mbox; +diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c +index dbb16ce25..e8e91130c 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/pci.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c +@@ -1411,9 +1411,12 @@ static void mlxsw_pci_free_irq_vectors(struct mlxsw_pci *mlxsw_pci) + pci_free_irq_vectors(mlxsw_pci->pdev); + } + +-static int mlxsw_pci_init(void *bus_priv, struct mlxsw_core *mlxsw_core, +- const struct mlxsw_config_profile *profile, +- struct mlxsw_res *res) ++static int ++mlxsw_pci_init(void *bus_priv, struct mlxsw_core *mlxsw_core, ++ const struct mlxsw_config_profile *profile, ++ struct mlxsw_res *res, ++ void (*sys_event_handler)(struct mlxsw_core *mlxsw_core)) ++ + { + struct mlxsw_pci *mlxsw_pci = bus_priv; + struct pci_dev *pdev = mlxsw_pci->pdev; +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0153-mlxsw-i2c-Add-support-for-system-events-handling.patch b/platform/mellanox/non-upstream-patches/patches/0153-mlxsw-i2c-Add-support-for-system-events-handling.patch new file mode 100644 index 000000000000..43bda72b4d1e --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0153-mlxsw-i2c-Add-support-for-system-events-handling.patch @@ -0,0 +1,198 @@ +From c5235b3c4a8ab2b758140d75a7422117e917478c Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Sun, 19 Dec 2021 09:12:58 +0000 +Subject: [PATCH] mlxsw: i2c: Add support for system events handling + +Extend i2c bus driver with interrupt handler to support system specific +hotplug events, related to line card state change. +Provide system IRQ line for interrupt handler. Line Id could be +provided through the platform data if available, or could be set to the +default value. +Handler is supposed to be set by "mlxsw" driver through bus driver init() +call. + +Signed-off-by: Vadim Pasternak +--- + drivers/net/ethernet/mellanox/mlxsw/i2c.c | 110 ++++++++++++++++++++++ + 1 file changed, 110 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/i2c.c b/drivers/net/ethernet/mellanox/mlxsw/i2c.c +index b75416561..e5883b4e8 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/i2c.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/i2c.c +@@ -9,6 +9,7 @@ + #include + #include + #include ++#include + #include + + #include "cmd.h" +@@ -51,6 +52,12 @@ + #define MLXSW_I2C_TIMEOUT_MSECS 5000 + #define MLXSW_I2C_MAX_DATA_SIZE 256 + ++#define MLXSW_I2C_WORK_ARMED 1 ++#define MLXSW_I2C_WORK_CLOSED GENMASK(31, 0) ++#define MLXSW_I2C_WORK_DELAY (usecs_to_jiffies(100)) ++#define MLXSW_I2C_DEFAULT_IRQ 17 ++#define MLXSW_I2C_VIRT_SLAVE 0x37 ++ + /** + * struct mlxsw_i2c - device private data: + * @cmd: command attributes; +@@ -64,6 +71,12 @@ + * @bus_info: bus info block; + * @block_size: maximum block size allowed to pass to under layer; + * @status: status to indicate chip reset or in-service update; ++ * @pdata: device platform data; ++ * @dwork_irq: interrupts delayed work queue; ++ * @lock - lock for interrupts sync; ++ * @sys_event_handler: system events handler callback; ++ * @irq: IRQ line number; ++ * @irq_unhandled_count: number of unhandled interrupts; + */ + struct mlxsw_i2c { + struct { +@@ -78,6 +91,12 @@ struct mlxsw_i2c { + struct mlxsw_bus_info bus_info; + u16 block_size; + u8 status; ++ struct mlxreg_core_hotplug_platform_data *pdata; ++ struct delayed_work dwork_irq; ++ spinlock_t lock; /* sync with interrupt */ ++ void (*sys_event_handler)(struct mlxsw_core *mlxsw_core); ++ int irq; ++ atomic_t irq_unhandled_count; + }; + + #define MLXSW_I2C_READ_MSG(_client, _addr_buf, _buf, _len) { \ +@@ -538,6 +557,7 @@ mlxsw_i2c_init(void *bus_priv, struct mlxsw_core *mlxsw_core, + int err; + + mlxsw_i2c->core = mlxsw_core; ++ mlxsw_i2c->sys_event_handler = sys_event_handler; + + mbox = mlxsw_cmd_mbox_alloc(); + if (!mbox) +@@ -568,6 +588,87 @@ static void mlxsw_i2c_fini(void *bus_priv) + mlxsw_i2c->core = NULL; + } + ++static void mlxsw_i2c_work_handler(struct work_struct *work) ++{ ++ struct mlxsw_i2c *mlxsw_i2c; ++ unsigned long flags; ++ ++ mlxsw_i2c = container_of(work, struct mlxsw_i2c, dwork_irq.work); ++ ++ if (atomic_read(&mlxsw_i2c->irq_unhandled_count)) { ++ if (atomic_dec_and_test(&mlxsw_i2c->irq_unhandled_count)) ++ return; ++ } ++ ++ mlxsw_i2c->sys_event_handler(mlxsw_i2c->core); ++ ++ spin_lock_irqsave(&mlxsw_i2c->lock, flags); ++ ++ /* It is possible, that some signals have been inserted, while ++ * interrupts has been masked. In this case such signals could 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(&mlxsw_i2c->dwork_irq); ++ schedule_delayed_work(&mlxsw_i2c->dwork_irq, MLXSW_I2C_WORK_DELAY); ++ ++ spin_unlock_irqrestore(&mlxsw_i2c->lock, flags); ++ ++ if (!atomic_read(&mlxsw_i2c->irq_unhandled_count)) ++ atomic_set(&mlxsw_i2c->irq_unhandled_count, MLXSW_I2C_WORK_ARMED); ++} ++ ++static irqreturn_t mlxsw_i2c_irq_handler(int irq, void *dev) ++{ ++ struct mlxsw_i2c *mlxsw_i2c = (struct mlxsw_i2c *)dev; ++ ++ /* Schedule work task for immediate execution.*/ ++ schedule_delayed_work(&mlxsw_i2c->dwork_irq, 0); ++ ++ return IRQ_NONE; ++} ++ ++static int mlxsw_i2c_event_handler_register(struct mlxsw_i2c *mlxsw_i2c) ++{ ++ int err; ++ ++ /* Initialize interrupt handler if system hotplug driver is reachable ++ * and platform data is available. ++ */ ++ if (!IS_REACHABLE(CONFIG_MLXREG_HOTPLUG)) ++ return 0; ++ ++ if (mlxsw_i2c->pdata && mlxsw_i2c->pdata->irq) ++ mlxsw_i2c->irq = mlxsw_i2c->pdata->irq; ++ ++ if (!mlxsw_i2c->irq) ++ return 0; ++ ++ err = request_irq(mlxsw_i2c->irq, mlxsw_i2c_irq_handler, ++ IRQF_TRIGGER_FALLING | IRQF_SHARED, "mlxsw-i2c", ++ mlxsw_i2c); ++ if (err) { ++ dev_err(mlxsw_i2c->bus_info.dev, "Failed to request irq: %d\n", ++ err); ++ return err; ++ } ++ ++ spin_lock_init(&mlxsw_i2c->lock); ++ INIT_DELAYED_WORK(&mlxsw_i2c->dwork_irq, mlxsw_i2c_work_handler); ++ ++ return 0; ++} ++ ++static void mlxsw_i2c_event_handler_unregister(struct mlxsw_i2c *mlxsw_i2c) ++{ ++ if (!IS_REACHABLE(CONFIG_MLXREG_HOTPLUG) || !mlxsw_i2c->irq) ++ return; ++ cancel_delayed_work_sync(&mlxsw_i2c->dwork_irq); ++ free_irq(mlxsw_i2c->irq, mlxsw_i2c); ++} ++ + static const struct mlxsw_bus mlxsw_i2c_bus = { + .kind = "i2c", + .init = mlxsw_i2c_init, +@@ -662,6 +763,7 @@ static int mlxsw_i2c_probe(struct i2c_client *client, + mlxsw_i2c->bus_info.dev = &client->dev; + mlxsw_i2c->bus_info.low_frequency = true; + mlxsw_i2c->dev = &client->dev; ++ mlxsw_i2c->pdata = client->dev.platform_data; + + err = mlxsw_core_bus_device_register(&mlxsw_i2c->bus_info, + &mlxsw_i2c_bus, mlxsw_i2c, false, +@@ -671,6 +773,12 @@ static int mlxsw_i2c_probe(struct i2c_client *client, + return err; + } + ++ if (client->addr == MLXSW_I2C_VIRT_SLAVE) ++ mlxsw_i2c->irq = MLXSW_I2C_DEFAULT_IRQ; ++ err = mlxsw_i2c_event_handler_register(mlxsw_i2c); ++ if (err) ++ return err; ++ + return 0; + + errout: +@@ -684,6 +792,8 @@ static int mlxsw_i2c_remove(struct i2c_client *client) + { + struct mlxsw_i2c *mlxsw_i2c = i2c_get_clientdata(client); + ++ atomic_set(&mlxsw_i2c->irq_unhandled_count, MLXSW_I2C_WORK_CLOSED); ++ mlxsw_i2c_event_handler_unregister(mlxsw_i2c); + mlxsw_core_bus_device_unregister(mlxsw_i2c->core, false); + mutex_destroy(&mlxsw_i2c->cmd.lock); + +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0154-mlxsw-core-Export-line-card-API.patch b/platform/mellanox/non-upstream-patches/patches/0154-mlxsw-core-Export-line-card-API.patch new file mode 100644 index 000000000000..6500a0db878c --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0154-mlxsw-core-Export-line-card-API.patch @@ -0,0 +1,27 @@ +From 8099c3baf5f819fdf187b67cc3ed0ce25360cf88 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Sun, 19 Dec 2021 09:31:32 +0000 +Subject: [PATCH] mlxsw: core: Export line card API + +Export API mlxsw_core_linecards() for being used by 'minimal' driver. + +Signed-off-by: Vadim Pasternak +--- + drivers/net/ethernet/mellanox/mlxsw/core.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c +index a9bb43837..a26c6d880 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/core.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/core.c +@@ -103,6 +103,7 @@ struct mlxsw_linecards *mlxsw_core_linecards(struct mlxsw_core *mlxsw_core) + { + return mlxsw_core->linecards; + } ++EXPORT_SYMBOL(mlxsw_core_linecards); + + #define MLXSW_PORT_MAX_PORTS_DEFAULT 0x40 + +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0155-mlxsw-minimal-Add-system-event-handler.patch b/platform/mellanox/non-upstream-patches/patches/0155-mlxsw-minimal-Add-system-event-handler.patch new file mode 100644 index 000000000000..7bce0a016dfb --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0155-mlxsw-minimal-Add-system-event-handler.patch @@ -0,0 +1,61 @@ +From b526413a86afcd1d6bd3f4e05f25631c8103f617 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Sun, 19 Dec 2021 09:25:35 +0000 +Subject: [PATCH] mlxsw: minimal: Add system event handler + +Add system event handler for treating line card specific signals on +modular system. These signals indicate line card state changes, like +line card activation or de-activation. +When such signals are received, driver should create or destroy "hwmon" +"thermal" and module info objects, associated with line card in a slot, +for which signal has been received. + +Signed-off-by: Vadim Pasternak +--- + drivers/net/ethernet/mellanox/mlxsw/minimal.c | 23 +++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +index 59c5053dc..27afb28e4 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +@@ -527,6 +527,28 @@ static void mlxsw_m_line_cards_free(struct mlxsw_m *mlxsw_m) + kfree(mlxsw_m->line_cards); + } + ++static void mlxsw_m_sys_event_handler(struct mlxsw_core *mlxsw_core) ++{ ++ struct mlxsw_linecards *linecards = mlxsw_core_linecards(mlxsw_core); ++ struct mlxsw_m *mlxsw_m = mlxsw_core_driver_priv(mlxsw_core); ++ char mddq_pl[MLXSW_REG_MDDQ_LEN]; ++ int i, err; ++ ++ if (!linecards) ++ return; ++ ++ /* Handle line cards, for which active status has been changed. */ ++ for (i = 1; i <= linecards->count; i++) { ++ mlxsw_reg_mddq_slot_info_pack(mddq_pl, i, false); ++ err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(mddq), mddq_pl); ++ if (err) ++ dev_err(mlxsw_m->bus_info->dev, "Fail to query MDDQ register for slot %d\n", ++ i); ++ ++ mlxsw_linecard_status_process(mlxsw_m->core, mddq_pl); ++ } ++} ++ + static int mlxsw_m_init(struct mlxsw_core *mlxsw_core, + const struct mlxsw_bus_info *mlxsw_bus_info, + struct netlink_ext_ack *extack) +@@ -587,6 +609,7 @@ static struct mlxsw_driver mlxsw_m_driver = { + .priv_size = sizeof(struct mlxsw_m), + .init = mlxsw_m_init, + .fini = mlxsw_m_fini, ++ .sys_event_handler = mlxsw_m_sys_event_handler, + .profile = &mlxsw_m_config_profile, + .res_query_enabled = true, + }; +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0156-mlxsw-minimal-Add-interfaces-for-line-card-initializ.patch b/platform/mellanox/non-upstream-patches/patches/0156-mlxsw-minimal-Add-interfaces-for-line-card-initializ.patch new file mode 100644 index 000000000000..6b1049f6d1c1 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0156-mlxsw-minimal-Add-interfaces-for-line-card-initializ.patch @@ -0,0 +1,119 @@ +From 20b2dd627f42e79a8fce30d29d4cea64f6636521 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Sun, 19 Dec 2021 09:40:34 +0000 +Subject: [PATCH] mlxsw: minimal: Add interfaces for line card initialization + and de-initialization + +Add callback functions for line card 'netdevice' objects initialization +and de-initialization. Each line card is associated with the set of +'netdevices', which are created/destroyed dynamically, when line card +is getting to active / inactive states. + +Add APIs for line card registration and de-registration during init and +de-init. + +Signed-off-by: Vadim Pasternak +--- + drivers/net/ethernet/mellanox/mlxsw/minimal.c | 70 +++++++++++++++++++ + 1 file changed, 70 insertions(+) + +diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +index 27afb28e4..0b605c6aa 100644 +--- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c ++++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c +@@ -549,6 +549,69 @@ static void mlxsw_m_sys_event_handler(struct mlxsw_core *mlxsw_core) + } + } + ++static void ++mlxsw_m_got_active(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ const struct mlxsw_linecard *linecard, void *priv) ++{ ++ struct mlxsw_m *mlxsw_m = priv; ++ int err; ++ ++ err = mlxsw_m_ports_create(mlxsw_m, slot_index); ++ if (err) { ++ dev_err(mlxsw_m->bus_info->dev, "Failed to set line card at slot %d\n", ++ slot_index); ++ goto mlxsw_m_ports_create_fail; ++ } ++ mlxsw_m->line_cards[slot_index]->active = true; ++ ++mlxsw_m_ports_create_fail: ++ return; ++} ++ ++static void ++mlxsw_m_got_inactive(struct mlxsw_core *mlxsw_core, u8 slot_index, ++ const struct mlxsw_linecard *linecard, void *priv) ++{ ++ struct mlxsw_m *mlxsw_m = priv; ++ ++ mlxsw_m_ports_remove(mlxsw_m, slot_index); ++ mlxsw_m->line_cards[slot_index]->active = false; ++} ++ ++static struct mlxsw_linecards_event_ops mlxsw_m_event_ops = { ++ .got_active = mlxsw_m_got_active, ++ .got_inactive = mlxsw_m_got_inactive, ++}; ++ ++static int mlxsw_m_linecards_register(struct mlxsw_m *mlxsw_m) ++{ ++ struct mlxsw_linecards *linecards = mlxsw_core_linecards(mlxsw_m->core); ++ ++ if (!linecards || !linecards->count) ++ return 0; ++ ++ return mlxsw_linecards_event_ops_register(mlxsw_m->core, ++ &mlxsw_m_event_ops, ++ mlxsw_m); ++} ++ ++static void mlxsw_m_linecards_unregister(struct mlxsw_m *mlxsw_m) ++{ ++ struct mlxsw_linecards *linecards = mlxsw_core_linecards(mlxsw_m->core); ++ int i; ++ ++ if (!linecards || !linecards->count) ++ return; ++ ++ for (i = 1; i <= linecards->count; i++) { ++ if (mlxsw_m->line_cards[i]->active) ++ mlxsw_m_got_inactive(mlxsw_m->core, i, NULL, mlxsw_m); ++ } ++ ++ mlxsw_linecards_event_ops_unregister(mlxsw_m->core, ++ &mlxsw_m_event_ops, mlxsw_m); ++} ++ + static int mlxsw_m_init(struct mlxsw_core *mlxsw_core, + const struct mlxsw_bus_info *mlxsw_bus_info, + struct netlink_ext_ack *extack) +@@ -587,8 +650,14 @@ static int mlxsw_m_init(struct mlxsw_core *mlxsw_core, + goto err_mlxsw_m_ports_create; + } + ++ err = mlxsw_m_linecards_register(mlxsw_m); ++ if (err) ++ goto err_linecards_register; ++ + return 0; + ++err_linecards_register: ++ mlxsw_m_ports_remove(mlxsw_m, 0); + err_mlxsw_m_ports_create: + mlxsw_m_line_cards_free(mlxsw_m); + return err; +@@ -598,6 +667,7 @@ static void mlxsw_m_fini(struct mlxsw_core *mlxsw_core) + { + struct mlxsw_m *mlxsw_m = mlxsw_core_driver_priv(mlxsw_core); + ++ mlxsw_m_linecards_unregister(mlxsw_m); + mlxsw_m_ports_remove(mlxsw_m, 0); + mlxsw_m_line_cards_free(mlxsw_m); + } +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0163-platform-mellanox-Introduce-support-for-rack-manager.patch b/platform/mellanox/non-upstream-patches/patches/0163-platform-mellanox-Introduce-support-for-rack-manager.patch new file mode 100644 index 000000000000..aa9f7fceb42a --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0163-platform-mellanox-Introduce-support-for-rack-manager.patch @@ -0,0 +1,420 @@ +From bb18ddc163092447e40f8aba96140280e2201409 Mon Sep 17 00:00:00 2001 +From: Vadim Pasternak +Date: Mon, 14 Feb 2022 13:24:44 +0200 +Subject: [PATCH] platform: mellanox: Introduce support for rack manager switch + +The rack switch is designed to provide high bandwidth, low latency +connectivity using optical fiber as the primary interconnect. + +System supports 32 OSFP ports, non-blocking switching capacity of +25.6Tbps. +System equipped with: +- 2 replaceable power supplies (AC) with 1+1 redundancy model. +- 7 replaceable fan drawers with 6+1 redundancy model. +- 2 External Root of Trust or EROT (Glacier) devices for securing + ASICs firmware. + +Signed-off-by: Vadim Pasternak +--- + drivers/platform/x86/mlx-platform.c | 259 ++++++++++++++++++++++++++++ + 1 file changed, 259 insertions(+) + +diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c +index d0bb2becf..f1d0cc1aa 100644 +--- a/drivers/platform/x86/mlx-platform.c ++++ b/drivers/platform/x86/mlx-platform.c +@@ -90,6 +90,12 @@ + #define MLXPLAT_CPLD_LPC_REG_FAN_OFFSET 0x88 + #define MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET 0x89 + #define MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET 0x8a ++#define MLXPLAT_CPLD_LPC_REG_EROT_OFFSET 0x91 ++#define MLXPLAT_CPLD_LPC_REG_EROT_EVENT_OFFSET 0x92 ++#define MLXPLAT_CPLD_LPC_REG_EROT_MASK_OFFSET 0x93 ++#define MLXPLAT_CPLD_LPC_REG_EROTE_OFFSET 0x94 ++#define MLXPLAT_CPLD_LPC_REG_EROTE_EVENT_OFFSET 0x95 ++#define MLXPLAT_CPLD_LPC_REG_EROTE_MASK_OFFSET 0x96 + #define MLXPLAT_CPLD_LPC_REG_LC_VR_OFFSET 0x9a + #define MLXPLAT_CPLD_LPC_REG_LC_VR_EVENT_OFFSET 0x9b + #define MLXPLAT_CPLD_LPC_REG_LC_VR_MASK_OFFSET 0x9c +@@ -109,6 +115,8 @@ + #define MLXPLAT_CPLD_LPC_REG_LC_SD_EVENT_OFFSET 0xaa + #define MLXPLAT_CPLD_LPC_REG_LC_SD_MASK_OFFSET 0xab + #define MLXPLAT_CPLD_LPC_REG_LC_PWR_ON 0xb2 ++#define MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET 0xc2 ++#define MLXPLAT_CPLD_LPC_REG_SPI_CHNL_SELECT 0xc3 + #define MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET 0xc7 + #define MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET 0xc8 + #define MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET 0xc9 +@@ -214,6 +222,7 @@ + #define MLXPLAT_CPLD_LED_HI_NIBBLE_MASK GENMASK(3, 0) + #define MLXPLAT_CPLD_VOLTREG_UPD_MASK GENMASK(5, 4) + #define MLXPLAT_CPLD_GWP_MASK GENMASK(0, 0) ++#define MLXPLAT_CPLD_EROT_MASK GENMASK(1, 0) + #define MLXPLAT_CPLD_I2C_CAP_BIT 0x04 + #define MLXPLAT_CPLD_I2C_CAP_MASK GENMASK(5, MLXPLAT_CPLD_I2C_CAP_BIT) + +@@ -243,6 +252,7 @@ + #define MLXPLAT_CPLD_CH2_ETH_MODULAR 3 + #define MLXPLAT_CPLD_CH3_ETH_MODULAR 43 + #define MLXPLAT_CPLD_CH4_ETH_MODULAR 51 ++#define MLXPLAT_CPLD_CH2_RACK_SWITCH 18 + + /* Number of LPC attached MUX platform devices */ + #define MLXPLAT_CPLD_LPC_MUX_DEVS 4 +@@ -280,6 +290,9 @@ + /* Minimum power required for turning on Ethernet modular system (WATT) */ + #define MLXPLAT_CPLD_ETH_MODULAR_PWR_MIN 50 + ++/* Default value for PWM control register for rack switch system */ ++#define MLXPLAT_REGMAP_NVSWITCH_PWM_DEFAULT 0xf4 ++ + /* mlxplat_priv - platform private data + * @pdev_i2c - i2c controller platform device + * @pdev_mux - array of mux platform devices +@@ -460,6 +473,36 @@ static struct i2c_mux_reg_platform_data mlxplat_modular_mux_data[] = { + }, + }; + ++/* Platform channels for rack swicth system family */ ++static const int mlxplat_rack_switch_channels[] = { ++ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, ++}; ++ ++/* Platform rack switch mux data */ ++static struct i2c_mux_reg_platform_data mlxplat_rack_switch_mux_data[] = { ++ { ++ .parent = 1, ++ .base_nr = MLXPLAT_CPLD_CH1, ++ .write_only = 1, ++ .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1, ++ .reg_size = 1, ++ .idle_in_use = 1, ++ .values = mlxplat_rack_switch_channels, ++ .n_values = ARRAY_SIZE(mlxplat_rack_switch_channels), ++ }, ++ { ++ .parent = 1, ++ .base_nr = MLXPLAT_CPLD_CH2_RACK_SWITCH, ++ .write_only = 1, ++ .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2, ++ .reg_size = 1, ++ .idle_in_use = 1, ++ .values = mlxplat_msn21xx_channels, ++ .n_values = ARRAY_SIZE(mlxplat_msn21xx_channels), ++ }, ++ ++}; ++ + /* Platform hotplug devices */ + static struct i2c_board_info mlxplat_mlxcpld_pwr[] = { + { +@@ -2064,6 +2107,97 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_chassis_blade_data = { + .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, + }; + ++/* Platform hotplug for switch systems family data */ ++static struct mlxreg_core_data mlxplat_mlxcpld_erot_ap_items_data[] = { ++ { ++ .label = "erot1_ap", ++ .reg = MLXPLAT_CPLD_LPC_REG_EROT_OFFSET, ++ .mask = BIT(0), ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, ++ }, ++ { ++ .label = "erot2_ap", ++ .reg = MLXPLAT_CPLD_LPC_REG_EROT_OFFSET, ++ .mask = BIT(1), ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, ++ }, ++}; ++ ++static struct mlxreg_core_data mlxplat_mlxcpld_erot_error_items_data[] = { ++ { ++ .label = "erot1_error", ++ .reg = MLXPLAT_CPLD_LPC_REG_EROTE_OFFSET, ++ .mask = BIT(0), ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, ++ }, ++ { ++ .label = "erot2_error", ++ .reg = MLXPLAT_CPLD_LPC_REG_EROTE_OFFSET, ++ .mask = BIT(1), ++ .hpdev.nr = MLXPLAT_CPLD_NR_NONE, ++ }, ++}; ++ ++static struct mlxreg_core_item mlxplat_mlxcpld_rack_switch_items[] = { ++ { ++ .data = mlxplat_mlxcpld_ext_psu_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, ++ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, ++ .mask = MLXPLAT_CPLD_PSU_EXT_MASK, ++ .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_ext_psu_items_data), ++ .inversed = 1, ++ .health = false, ++ }, ++ { ++ .data = mlxplat_mlxcpld_ext_pwr_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, ++ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, ++ .mask = MLXPLAT_CPLD_PWR_EXT_MASK, ++ .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_ext_pwr_items_data), ++ .inversed = 0, ++ .health = false, ++ }, ++ { ++ .data = mlxplat_mlxcpld_default_ng_fan_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, ++ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, ++ .mask = MLXPLAT_CPLD_FAN_NG_MASK, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_fan_items_data), ++ .inversed = 1, ++ .health = false, ++ }, ++ { ++ .data = mlxplat_mlxcpld_erot_ap_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, ++ .reg = MLXPLAT_CPLD_LPC_REG_EROT_OFFSET, ++ .mask = MLXPLAT_CPLD_EROT_MASK, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_erot_ap_items_data), ++ .inversed = 1, ++ .health = false, ++ }, ++ { ++ .data = mlxplat_mlxcpld_erot_error_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, ++ .reg = MLXPLAT_CPLD_LPC_REG_EROTE_OFFSET, ++ .mask = MLXPLAT_CPLD_EROT_MASK, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_erot_error_items_data), ++ .inversed = 1, ++ .health = false, ++ }, ++}; ++ ++static ++struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_rack_switch_data = { ++ .items = mlxplat_mlxcpld_rack_switch_items, ++ .counter = ARRAY_SIZE(mlxplat_mlxcpld_rack_switch_items), ++ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, ++ .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF | MLXPLAT_CPLD_AGGR_MASK_COMEX, ++ .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, ++ .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, ++}; ++ + /* Platform led default data */ + static struct mlxreg_core_data mlxplat_mlxcpld_default_led_data[] = { + { +@@ -2947,6 +3081,42 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { + .mask = GENMASK(7, 0) & ~BIT(2), + .mode = 0444, + }, ++ { ++ .label = "erot1_reset", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_GP2_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(6), ++ .mode = 0644, ++ }, ++ { ++ .label = "erot2_reset", ++ .reg = MLXPLAT_CPLD_LPC_REG_RESET_GP2_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(7), ++ .mode = 0644, ++ }, ++ { ++ .label = "erot1_recovery", ++ .reg = MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(6), ++ .mode = 0644, ++ }, ++ { ++ .label = "erot2_recovery", ++ .reg = MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(7), ++ .mode = 0644, ++ }, ++ { ++ .label = "erot1_wp", ++ .reg = MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(4), ++ .mode = 0644, ++ }, ++ { ++ .label = "erot2_wp", ++ .reg = MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(5), ++ .mode = 0644, ++ }, + { + .label = "reset_long_pb", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, +@@ -3142,6 +3312,25 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { + .mask = GENMASK(7, 0) & ~BIT(4), + .mode = 0644, + }, ++ { ++ .label = "erot1_ap_reset", ++ .reg = MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(0), ++ .mode = 0444, ++ }, ++ { ++ .label = "erot2_ap_reset", ++ .reg = MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(1), ++ .mode = 0444, ++ }, ++ { ++ .label = "spi_chnl_select", ++ .reg = MLXPLAT_CPLD_LPC_REG_SPI_CHNL_SELECT, ++ .mask = GENMASK(7, 0), ++ .bit = 1, ++ .mode = 0644, ++ }, + { + .label = "config1", + .reg = MLXPLAT_CPLD_LPC_REG_CONFIG1_OFFSET, +@@ -4257,6 +4446,10 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_EROT_EVENT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_EROT_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_EROTE_EVENT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_EROTE_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLC_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_IN_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_IN_MASK_OFFSET: +@@ -4274,6 +4467,8 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_REG_LC_SD_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_SD_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_PWR_ON: ++ case MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_SPI_CHNL_SELECT: + case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET: +@@ -4358,6 +4553,12 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET: + case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_EROT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_EROT_EVENT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_EROT_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_EROTE_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_EROTE_EVENT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_EROTE_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLC_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLC_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_IN_OFFSET: +@@ -4382,6 +4583,7 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_REG_LC_SD_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_SD_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_PWR_ON: ++ case MLXPLAT_CPLD_LPC_REG_SPI_CHNL_SELECT: + case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET: +@@ -4492,6 +4694,12 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET: + case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_EROT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_EROT_EVENT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_EROT_MASK_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_EROTE_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_EROTE_EVENT_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_EROTE_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLC_OFFSET: + case MLXPLAT_CPLD_LPC_REG_AGGRLC_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_IN_OFFSET: +@@ -4516,6 +4724,8 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) + case MLXPLAT_CPLD_LPC_REG_LC_SD_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_SD_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_LC_PWR_ON: ++ case MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET: ++ case MLXPLAT_CPLD_LPC_REG_SPI_CHNL_SELECT: + case MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD2_TLEFT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET: +@@ -4583,6 +4793,13 @@ static const struct reg_default mlxplat_mlxcpld_regmap_ng400[] = { + { MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET, 0x00 }, + }; + ++static const struct reg_default mlxplat_mlxcpld_regmap_rack_switch[] = { ++ { MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, MLXPLAT_REGMAP_NVSWITCH_PWM_DEFAULT }, ++ { MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET, 0x00 }, ++ { MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET, 0x00 }, ++ { MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET, 0x00 }, ++}; ++ + static const struct reg_default mlxplat_mlxcpld_regmap_eth_modular[] = { + { MLXPLAT_CPLD_LPC_REG_GP2_OFFSET, 0x61 }, + { MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, 0x00 }, +@@ -4676,6 +4893,20 @@ static const struct regmap_config mlxplat_mlxcpld_regmap_config_ng400 = { + .reg_write = mlxplat_mlxcpld_reg_write, + }; + ++static const struct regmap_config mlxplat_mlxcpld_regmap_config_rack_switch = { ++ .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_rack_switch, ++ .num_reg_defaults = ARRAY_SIZE(mlxplat_mlxcpld_regmap_rack_switch), ++ .reg_read = mlxplat_mlxcpld_reg_read, ++ .reg_write = mlxplat_mlxcpld_reg_write, ++}; ++ + static const struct regmap_config mlxplat_mlxcpld_regmap_config_eth_modular = { + .reg_bits = 8, + .val_bits = 8, +@@ -4957,6 +5188,27 @@ static int __init mlxplat_dmi_modular_matched(const struct dmi_system_id *dmi) + return 1; + } + ++static int __init mlxplat_dmi_rack_switch_matched(const struct dmi_system_id *dmi) ++{ ++ int i; ++ ++ mlxplat_max_adap_num = MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM; ++ mlxplat_mux_num = ARRAY_SIZE(mlxplat_rack_switch_mux_data); ++ mlxplat_mux_data = mlxplat_rack_switch_mux_data; ++ mlxplat_hotplug = &mlxplat_mlxcpld_rack_switch_data; ++ mlxplat_hotplug->deferred_nr = ++ mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; ++ mlxplat_led = &mlxplat_default_ng_led_data; ++ mlxplat_regs_io = &mlxplat_default_ng_regs_io_data; ++ mlxplat_fan = &mlxplat_default_fan_data; ++ for (i = 0; i < ARRAY_SIZE(mlxplat_mlxcpld_wd_set_type2); i++) ++ mlxplat_wd_data[i] = &mlxplat_mlxcpld_wd_set_type2[i]; ++ mlxplat_i2c = &mlxplat_mlxcpld_i2c_ng_data; ++ mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config_rack_switch; ++ ++ return 1; ++} ++ + static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { + { + .callback = mlxplat_dmi_default_wc_matched, +@@ -5007,6 +5259,13 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { + DMI_MATCH(DMI_BOARD_NAME, "VMOD0009"), + }, + }, ++ { ++ .callback = mlxplat_dmi_rack_switch_matched, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "VMOD0010"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "HI142"), ++ }, ++ }, + { + .callback = mlxplat_dmi_ng400_matched, + .matches = { +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0176-platform-mellanox-fix-reset_pwr_converter_fail-attri.patch b/platform/mellanox/non-upstream-patches/patches/0176-platform-mellanox-fix-reset_pwr_converter_fail-attri.patch new file mode 100644 index 000000000000..17d55632e848 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0176-platform-mellanox-fix-reset_pwr_converter_fail-attri.patch @@ -0,0 +1,30 @@ +From d3b1142ce6c3fbb02c39fc8d2e9f24ecbf466973 Mon Sep 17 00:00:00 2001 +From: Michael Shych +Date: Sun, 4 Sep 2022 10:41:45 +0300 +Subject: [PATCH] platform: mellanox: fix reset_pwr_converter_fail attribute. + +Change incorrect reset_voltmon_upgrade_fail atitribute name to +reset_pwr_converter_fail. + +Signed-off-by: Michael Shych +Reviewed-by: Vadim Pasternak +--- + drivers/platform/x86/mlx-platform.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c +index f1d0cc1aa..31c5cc10f 100644 +--- a/drivers/platform/x86/mlx-platform.c ++++ b/drivers/platform/x86/mlx-platform.c +@@ -3904,7 +3904,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_chassis_blade_regs_io_data[] = { + .mode = 0444, + }, + { +- .label = "reset_voltmon_upgrade_fail", ++ .label = "reset_pwr_converter_fail", + .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(0), + .mode = 0444, +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0177-Documentation-ABI-fix-description-of-fix-reset_pwr_c.patch b/platform/mellanox/non-upstream-patches/patches/0177-Documentation-ABI-fix-description-of-fix-reset_pwr_c.patch new file mode 100644 index 000000000000..7fd978b051c4 --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0177-Documentation-ABI-fix-description-of-fix-reset_pwr_c.patch @@ -0,0 +1,38 @@ +From 85ac7ddf15f380460b9e17f0e2c99aa8e476ef3f Mon Sep 17 00:00:00 2001 +From: Michael Shych +Date: Sun, 4 Sep 2022 10:46:01 +0300 +Subject: [PATCH] Documentation/ABI: fix description of fix + reset_pwr_converter_fail attribute. + +Change description of incorrect reset_voltmon_upgrade_fail atitribute +name to reset_pwr_converter_fail. + +Signed-off-by: Michael Shych +Reviewed-by: Vadim Pasternak +--- + Documentation/ABI/stable/sysfs-driver-mlxreg-io | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/Documentation/ABI/stable/sysfs-driver-mlxreg-io b/Documentation/ABI/stable/sysfs-driver-mlxreg-io +index 0913a8daf..ac503e84e 100644 +--- a/Documentation/ABI/stable/sysfs-driver-mlxreg-io ++++ b/Documentation/ABI/stable/sysfs-driver-mlxreg-io +@@ -103,13 +103,13 @@ Description: These files show the system reset cause, as following: power + What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_comex_pwr_fail + What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_from_comex + What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_system +-What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_voltmon_upgrade_fail ++What: /sys/devices/platform/mlxplat/mlxreg-io/hwmon/hwmon*/reset_pwr_converter_fail + Date: November 2018 + KernelVersion: 5.0 + Contact: Vadim Pasternak + Description: These files show the system reset cause, as following: ComEx + power fail, reset from ComEx, system platform reset, reset +- due to voltage monitor devices upgrade failure, ++ due to power converter devices failure, + Value 1 in file means this is reset cause, 0 - otherwise. + Only one bit could be 1 at the same time, representing only + the last reset cause. +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/patches/0178-platform-mellanox-Introduce-support-for-next-generat.patch b/platform/mellanox/non-upstream-patches/patches/0178-platform-mellanox-Introduce-support-for-next-generat.patch new file mode 100644 index 000000000000..922bc84b746d --- /dev/null +++ b/platform/mellanox/non-upstream-patches/patches/0178-platform-mellanox-Introduce-support-for-next-generat.patch @@ -0,0 +1,295 @@ +From 4c485e6f50001f0ea691b0ce5c0d90a118e8d360 Mon Sep 17 00:00:00 2001 +From: Michael Shych +Date: Sun, 4 Sep 2022 14:03:58 +0300 +Subject: [PATCH] platform: mellanox: Introduce support for next-generation + 800GB/s ethernet switch. + +Introduce support for Nvidia next-generation 800GB/s ethernet switch - SN5600. +SN5600 is 51.2 Tbps Ethernet switch based on Nvidia Spectrum-4 ASIC. +It can provide up to 64x800Gb/s (ETH) full bidirectional bandwidth per port +using PAM-4 modulations. The system supports 64 Belly to Belly 2x4 OSFP cages. +The switch was designed to fit standard 2U racks. + +Features: +- 64 OSFP ports support 800GbE - 10GbE speed. +- Additional 25GbE - 1GbE service port on the front panel. +- Air-cooled with 3 + 1 redundant fan units. +- 1 + 1 redundant 3000W or 3600W PSUs. +- System management board is based on Intel Coffee-lake CPU E-2276 + with secure-boot support. + +Signed-off-by: Michael Shych +Reviewed-by: Vadim Pasternak +--- + drivers/platform/x86/mlx-platform.c | 178 ++++++++++++++++++++++++++++ + 1 file changed, 178 insertions(+) + +diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c +index 31c5cc10f..7e9f2a5ab 100644 +--- a/drivers/platform/x86/mlx-platform.c ++++ b/drivers/platform/x86/mlx-platform.c +@@ -253,6 +253,7 @@ + #define MLXPLAT_CPLD_CH3_ETH_MODULAR 43 + #define MLXPLAT_CPLD_CH4_ETH_MODULAR 51 + #define MLXPLAT_CPLD_CH2_RACK_SWITCH 18 ++#define MLXPLAT_CPLD_CH2_NG800 34 + + /* Number of LPC attached MUX platform devices */ + #define MLXPLAT_CPLD_LPC_MUX_DEVS 4 +@@ -503,6 +504,37 @@ static struct i2c_mux_reg_platform_data mlxplat_rack_switch_mux_data[] = { + + }; + ++/* Platform channels for ng800 system family */ ++static const int mlxplat_ng800_channels[] = { ++ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, ++ 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 ++}; ++ ++/* Platform ng800 mux data */ ++static struct i2c_mux_reg_platform_data mlxplat_ng800_mux_data[] = { ++ { ++ .parent = 1, ++ .base_nr = MLXPLAT_CPLD_CH1, ++ .write_only = 1, ++ .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1, ++ .reg_size = 1, ++ .idle_in_use = 1, ++ .values = mlxplat_ng800_channels, ++ .n_values = ARRAY_SIZE(mlxplat_ng800_channels), ++ }, ++ { ++ .parent = 1, ++ .base_nr = MLXPLAT_CPLD_CH2_NG800, ++ .write_only = 1, ++ .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2, ++ .reg_size = 1, ++ .idle_in_use = 1, ++ .values = mlxplat_msn21xx_channels, ++ .n_values = ARRAY_SIZE(mlxplat_msn21xx_channels), ++ }, ++ ++}; ++ + /* Platform hotplug devices */ + static struct i2c_board_info mlxplat_mlxcpld_pwr[] = { + { +@@ -522,6 +554,15 @@ static struct i2c_board_info mlxplat_mlxcpld_ext_pwr[] = { + }, + }; + ++static struct i2c_board_info mlxplat_mlxcpld_pwr_ng800[] = { ++ { ++ I2C_BOARD_INFO("dps460", 0x59), ++ }, ++ { ++ I2C_BOARD_INFO("dps460", 0x5a), ++ }, ++}; ++ + static struct i2c_board_info mlxplat_mlxcpld_fan[] = { + { + I2C_BOARD_INFO("24c32", 0x50), +@@ -601,6 +642,23 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_wc_items_data[] = { + }, + }; + ++static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_ng800_items_data[] = { ++ { ++ .label = "pwr1", ++ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, ++ .mask = BIT(0), ++ .hpdev.brdinfo = &mlxplat_mlxcpld_pwr_ng800[0], ++ .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, ++ }, ++ { ++ .label = "pwr2", ++ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, ++ .mask = BIT(1), ++ .hpdev.brdinfo = &mlxplat_mlxcpld_pwr_ng800[1], ++ .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR, ++ }, ++}; ++ + static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_items_data[] = { + { + .label = "fan1", +@@ -1224,6 +1282,47 @@ static struct mlxreg_core_item mlxplat_mlxcpld_ext_items[] = { + } + }; + ++static struct mlxreg_core_item mlxplat_mlxcpld_ng800_items[] = { ++ { ++ .data = mlxplat_mlxcpld_default_ng_psu_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, ++ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET, ++ .mask = MLXPLAT_CPLD_PSU_EXT_MASK, ++ .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_psu_items_data), ++ .inversed = 1, ++ .health = false, ++ }, ++ { ++ .data = mlxplat_mlxcpld_default_pwr_ng800_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, ++ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET, ++ .mask = MLXPLAT_CPLD_PWR_EXT_MASK, ++ .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_default_pwr_ng800_items_data), ++ .inversed = 0, ++ .health = false, ++ }, ++ { ++ .data = mlxplat_mlxcpld_default_ng_fan_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, ++ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET, ++ .mask = MLXPLAT_CPLD_FAN_NG_MASK, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_fan_items_data), ++ .inversed = 1, ++ .health = false, ++ }, ++ { ++ .data = mlxplat_mlxcpld_default_asic_items_data, ++ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, ++ .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, ++ .mask = MLXPLAT_CPLD_ASIC_MASK, ++ .count = ARRAY_SIZE(mlxplat_mlxcpld_default_asic_items_data), ++ .inversed = 0, ++ .health = true, ++ }, ++}; ++ + static + struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_ext_data = { + .items = mlxplat_mlxcpld_ext_items, +@@ -1234,6 +1333,16 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_ext_data = { + .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW | MLXPLAT_CPLD_LOW_AGGR_MASK_ASIC2, + }; + ++static ++struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_ng800_data = { ++ .items = mlxplat_mlxcpld_ng800_items, ++ .counter = ARRAY_SIZE(mlxplat_mlxcpld_ng800_items), ++ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, ++ .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF | MLXPLAT_CPLD_AGGR_MASK_COMEX, ++ .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, ++ .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW | MLXPLAT_CPLD_LOW_AGGR_MASK_ASIC2, ++}; ++ + static struct mlxreg_core_data mlxplat_mlxcpld_modular_pwr_items_data[] = { + { + .label = "pwr1", +@@ -3093,6 +3202,12 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { + .mask = GENMASK(7, 0) & ~BIT(7), + .mode = 0644, + }, ++ { ++ .label = "clk_brd_prog_en", ++ .reg = MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(1), ++ .mode = 0644, ++ }, + { + .label = "erot1_recovery", + .reg = MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, +@@ -3219,6 +3334,12 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { + .mask = GENMASK(7, 0) & ~BIT(6), + .mode = 0444, + }, ++ { ++ .label = "reset_ac_ok_fail", ++ .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(7), ++ .mode = 0444, ++ }, + { + .label = "psu1_on", + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, +@@ -3324,6 +3445,30 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = { + .mask = GENMASK(7, 0) & ~BIT(1), + .mode = 0444, + }, ++ { ++ .label = "clk_brd1_boot_fail", ++ .reg = MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(4), ++ .mode = 0444, ++ }, ++ { ++ .label = "clk_brd2_boot_fail", ++ .reg = MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(5), ++ .mode = 0444, ++ }, ++ { ++ .label = "clk_brd_fail", ++ .reg = MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(6), ++ .mode = 0444, ++ }, ++ { ++ .label = "asic_pg_fail", ++ .reg = MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(7), ++ .mode = 0444, ++ }, + { + .label = "spi_chnl_select", + .reg = MLXPLAT_CPLD_LPC_REG_SPI_CHNL_SELECT, +@@ -3621,6 +3766,12 @@ static struct mlxreg_core_data mlxplat_mlxcpld_modular_regs_io_data[] = { + .bit = 5, + .mode = 0444, + }, ++ { ++ .label = "pwr_converter_prog_en", ++ .reg = MLXPLAT_CPLD_LPC_REG_GP0_OFFSET, ++ .mask = GENMASK(7, 0) & ~BIT(0), ++ .mode = 0644, ++ }, + { + .label = "vpd_wp", + .reg = MLXPLAT_CPLD_LPC_REG_GP0_OFFSET, +@@ -5209,6 +5360,27 @@ static int __init mlxplat_dmi_rack_switch_matched(const struct dmi_system_id *dm + return 1; + } + ++static int __init mlxplat_dmi_ng800_matched(const struct dmi_system_id *dmi) ++{ ++ int i; ++ ++ mlxplat_max_adap_num = MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM; ++ mlxplat_mux_num = ARRAY_SIZE(mlxplat_ng800_mux_data); ++ mlxplat_mux_data = mlxplat_ng800_mux_data; ++ mlxplat_hotplug = &mlxplat_mlxcpld_ng800_data; ++ mlxplat_hotplug->deferred_nr = ++ mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; ++ mlxplat_led = &mlxplat_default_ng_led_data; ++ mlxplat_regs_io = &mlxplat_default_ng_regs_io_data; ++ mlxplat_fan = &mlxplat_default_fan_data; ++ for (i = 0; i < ARRAY_SIZE(mlxplat_mlxcpld_wd_set_type2); i++) ++ mlxplat_wd_data[i] = &mlxplat_mlxcpld_wd_set_type2[i]; ++ mlxplat_i2c = &mlxplat_mlxcpld_i2c_ng_data; ++ mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config_ng400; ++ ++ return 1; ++} ++ + static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { + { + .callback = mlxplat_dmi_default_wc_matched, +@@ -5278,6 +5450,12 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = { + DMI_MATCH(DMI_BOARD_NAME, "VMOD0011"), + }, + }, ++ { ++ .callback = mlxplat_dmi_ng800_matched, ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "VMOD0013"), ++ }, ++ }, + { + .callback = mlxplat_dmi_chassis_blade_matched, + .matches = { +-- +2.30.2 + diff --git a/platform/mellanox/non-upstream-patches/series.patch b/platform/mellanox/non-upstream-patches/series.patch new file mode 100644 index 000000000000..80cb652afb5a --- /dev/null +++ b/platform/mellanox/non-upstream-patches/series.patch @@ -0,0 +1,86 @@ +diff --git a/patch/series b/patch/series +index e86f858..61144ff 100755 +--- a/patch/series ++++ b/patch/series +@@ -155,12 +155,71 @@ kernel-compat-always-include-linux-compat.h-from-net-compat.patch + 0097-hwmon-mlxreg-fan-Support-distinctive-names-per-.patch + 0999-Revert-mlxsw-thermal-Fix-out-of-bounds-memory-a.patch + 0098-mlxsw-i2c-Prevent-transaction-execution-for.patch ++0099-mlxsw-core_hwmon-Fix-variable-names-for-hwmon-attrib.patch ++0100-mlxsw-core_thermal-Rename-labels-according-to-naming.patch ++0101-mlxsw-core_thermal-Remove-obsolete-API-for-query-res.patch ++0102-mlxsw-reg-Add-mgpir_-prefix-to-MGPIR-fields-comments.patch ++0103-mlxsw-core-Remove-unnecessary-asserts.patch ++0104-mlxsw-reg-Extend-MTMP-register-with-new-slot-number-.patch ++0105-mlxsw-reg-Extend-MTBR-register-with-new-slot-number-.patch ++0106-mlxsw-reg-Extend-MCIA-register-with-new-slot-number-.patch ++0107-mlxsw-reg-Extend-MCION-register-with-new-slot-number.patch ++0108-mlxsw-reg-Extend-PMMP-register-with-new-slot-number-.patch ++0109-mlxsw-reg-Extend-MGPIR-register-with-new-slot-fields.patch ++0110-mlxsw-core_env-Pass-slot-index-during-PMAOS-register.patch ++0111-mlxsw-reg-Add-new-field-to-Management-General-Periph.patch ++0112-mlxsw-core-Extend-interfaces-for-cable-info-access-w.patch ++0113-mlxsw-core-Extend-port-module-data-structures-for-li.patch ++0114-mlxsw-core-Move-port-module-events-enablement-to-a-s.patch ++0115-mlxsw-core_hwmon-Split-gearbox-initialization.patch ++0116-mlxsw-core_hwmon-Extend-internal-structures-to-suppo.patch ++0117-mlxsw-core_hwmon-Introduce-slot-parameter-in-hwmon-i.patch ++0118-mlxsw-core_hwmon-Extend-hwmon-device-with-gearbox-ma.patch ++0119-mlxsw-core_thermal-Extend-internal-structures-to-sup.patch ++0120-mlxsw-core_thermal-Split-gearbox-initialization.patch ++0121-mlxsw-core_thermal-Extend-thermal-area-with-gearbox-.patch ++0122-mlxsw-core_thermal-Add-line-card-id-prefix-to-line-c.patch ++0123-mlxsw-core_thermal-Use-exact-name-of-cooling-devices.patch ++0124-mlxsw-core_thermal-Use-common-define-for-thermal-zon.patch ++0125-devlink-add-support-to-create-line-card-and-expose-t.patch ++0126-devlink-implement-line-card-provisioning.patch ++0127-devlink-implement-line-card-active-state.patch ++0128-devlink-add-port-to-line-card-relationship-set.patch ++0129-devlink-introduce-linecard-info-get-message.patch ++0130-devlink-introduce-linecard-info-get-message.patch ++0131-mlxsw-reg-Add-Ports-Mapping-event-Configuration-Regi.patch ++0132-mlxsw-reg-Add-Management-DownStream-Device-Query-Reg.patch ++0133-mlxsw-reg-Add-Management-DownStream-Device-Control-R.patch ++0134-mlxsw-reg-Add-Management-Binary-Code-Transfer-Regist.patch ++0135-mlxsw-core_linecards-Add-line-card-objects-and-imple.patch ++0136-mlxsw-core_linecards-Implement-line-card-activation-.patch ++0137-mlxsw-core-Extend-driver-ops-by-remove-selected-port.patch ++0138-mlxsw-spectrum-Add-port-to-linecard-mapping.patch ++0139-mlxsw-reg-Introduce-Management-Temperature-Extended-.patch ++0140-mlxsw-core-Add-APIs-for-thermal-sensor-mapping.patch ++0141-mlxsw-reg-Add-Management-DownStream-Device-Tunneling.patch ++0142-mlxsw-core_linecards-Probe-devices-for-provisioned-l.patch ++0143-mlxsw-core_linecards-Expose-device-FW-version-over-d.patch ++0144-mlxsw-core-Introduce-flash-update-components.patch ++0145-mlxfw-Get-the-PSID-value-using-op-instead-of-passing.patch ++0146-mlxsw-core_linecards-Implement-line-card-device-flas.patch ++0147-mlxsw-core_linecards-Introduce-ops-for-linecards-sta.patch ++0148-mlxsw-core-Add-interfaces-for-line-card-initializati.patch ++0149-mlxsw-core_thermal-Add-interfaces-for-line-card-init.patch ++0150-mlxsw-core_hwmon-Add-interfaces-for-line-card-initia.patch ++0151-mlxsw-minimal-Prepare-driver-for-modular-system-supp.patch ++0152-mlxsw-core-Extend-bus-init-function-with-event-handl.patch ++0153-mlxsw-i2c-Add-support-for-system-events-handling.patch ++0154-mlxsw-core-Export-line-card-API.patch ++0155-mlxsw-minimal-Add-system-event-handler.patch ++0156-mlxsw-minimal-Add-interfaces-for-line-card-initializ.patch + 0157-platform-x86-mlx-platform-Make-activation-of-some-dr.patch + 0158-platform-x86-mlx-platform-Add-cosmetic-changes-for-a.patch + 0159-mlx-platform-Add-support-for-systems-equipped-with-t.patch + 0160-platform-mellanox-Introduce-support-for-COMe-NVSwitc.patch + 0161-platform-x86-mlx-platform-Add-support-for-new-system.patch + 0162-platform-mellanox-Add-COME-board-revision-register.patch ++0163-platform-mellanox-Introduce-support-for-rack-manager.patch + 0164-hwmon-jc42-Add-support-for-Seiko-Instruments-S-34TS0.patch + 0165-platform-mellanox-mlxreg-io-Add-locking-for-io-opera.patch + 0167-leds-mlxreg-Send-udev-change-event.patch +@@ -168,6 +227,9 @@ kernel-compat-always-include-linux-compat.h-from-net-compat.patch + 0171-platform-mellanox-mlxreg-lc-Fix-cleanup-on-failure-a.patch + 0173-core-Add-support-for-OSFP-transceiver-modules.patch + 0175-hwmon-pmbus-Add-support-for-Infineon-Digital-Multi-p.patch ++0176-platform-mellanox-fix-reset_pwr_converter_fail-attri.patch ++0177-Documentation-ABI-fix-description-of-fix-reset_pwr_c.patch ++0178-platform-mellanox-Introduce-support-for-next-generat.patch + 0180-hwmon-pmbus-Fix-sensors-readouts-for-MPS-Multi-phase.patch + ###-> mellanox_hw_mgmt-end + diff --git a/platform/mellanox/rules.mk b/platform/mellanox/rules.mk index 43aa1829953e..721118ea1699 100644 --- a/platform/mellanox/rules.mk +++ b/platform/mellanox/rules.mk @@ -51,7 +51,7 @@ $(DOCKER_PLATFORM_MONITOR)_DEPENDS += $(APPLIBS) $(SX_COMPLIB) $(SXD_LIBS) $(SX_ # Force the target bootloader for mellanox platforms to grub regardless of arch TARGET_BOOTLOADER = grub -# location for the platform specific external kernel patches tarball -override EXTERNAL_KERNEL_PATCH_TAR := $(BUILD_WORKDIR)/$(PLATFORM_PATH)/non-upstream-patches/patches.tar.gz +# location for the platform specific external kernel patches +override EXTERNAL_KERNEL_PATCH_LOC := $(BUILD_WORKDIR)/$(PLATFORM_PATH)/non-upstream-patches/ export SONIC_BUFFER_MODEL=dynamic diff --git a/rules/linux-kernel.mk b/rules/linux-kernel.mk index ffc735b4dc95..8e7b7c337a97 100644 --- a/rules/linux-kernel.mk +++ b/rules/linux-kernel.mk @@ -12,14 +12,14 @@ endif # Place an URL here to .tar.gz file if you want to include those patches EXTERNAL_KERNEL_PATCH_URL = # Set y to include non upstream patches tarball provided by the corresponding platform -INCLUDE_EXTERNAL_PATCH_TAR = n -# platforms should override this and provide an absolute path to the tarball -EXTERNAL_KERNEL_PATCH_TAR = +INCLUDE_EXTERNAL_PATCHES = n +# platforms should override this and provide an absolute location to the patches +EXTERNAL_KERNEL_PATCH_LOC = export KVERSION_SHORT KVERSION KERNEL_VERSION KERNEL_SUBVERSION export EXTERNAL_KERNEL_PATCH_URL -export INCLUDE_EXTERNAL_PATCH_TAR -export EXTERNAL_KERNEL_PATCH_TAR +export INCLUDE_EXTERNAL_PATCHES +export EXTERNAL_KERNEL_PATCH_LOC LINUX_HEADERS_COMMON = linux-headers-$(KVERSION_SHORT)-common_$(KERNEL_VERSION)-$(KERNEL_SUBVERSION)_all.deb $(LINUX_HEADERS_COMMON)_SRC_PATH = $(SRC_PATH)/sonic-linux-kernel