From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga07.intel.com (mga07.intel.com []) by mx.groups.io with SMTP id smtpd.web12.2899.1612411009177556091 for ; Wed, 03 Feb 2021 19:56:56 -0800 Authentication-Results: mx.groups.io; dkim=pass header.i=@intel.onmicrosoft.com header.s=selector2-intel-onmicrosoft-com header.b=fDKi5bj6; spf=fail (domain: intel.com, ip: , mailfrom: nathaniel.l.desimone@intel.com) IronPort-SDR: /eVzcuNx2AaiTXVrjrXkNThmdZq/FI00i+Es+sTuVAhhbTqXWolyIDyUDlF92SX/Qs2fZyaHl0 RJ4u/LJQkteg== X-IronPort-AV: E=McAfee;i="6000,8403,9884"; a="245240191" X-IronPort-AV: E=Sophos;i="5.79,400,1602572400"; d="scan'208";a="245240191" Received: from orsmga008.jf.intel.com ([10.7.209.65]) by orsmga105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Feb 2021 19:56:55 -0800 IronPort-SDR: b2phh5jQwiPdcDObOrRnkxmfwjtLEgCC50Vy/lkQyAyq09o8z4B/F4t1KMepsRQdAjQ7bP78qx qcqykI/iBwsA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.79,400,1602572400"; d="scan'208";a="392968619" Received: from orsmsx605.amr.corp.intel.com ([10.22.229.18]) by orsmga008.jf.intel.com with ESMTP; 03 Feb 2021 19:56:54 -0800 Received: from orsmsx607.amr.corp.intel.com (10.22.229.20) by ORSMSX605.amr.corp.intel.com (10.22.229.18) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2106.2; Wed, 3 Feb 2021 19:56:54 -0800 Received: from orsmsx601.amr.corp.intel.com (10.22.229.14) by ORSMSX607.amr.corp.intel.com (10.22.229.20) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2106.2; Wed, 3 Feb 2021 19:56:53 -0800 Received: from ORSEDG601.ED.cps.intel.com (10.7.248.6) by orsmsx601.amr.corp.intel.com (10.22.229.14) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2106.2 via Frontend Transport; Wed, 3 Feb 2021 19:56:53 -0800 Received: from NAM12-DM6-obe.outbound.protection.outlook.com (104.47.59.174) by edgegateway.intel.com (134.134.137.102) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.1713.5; Wed, 3 Feb 2021 19:56:52 -0800 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=LYSyasogz3JiXHzuEFRUA/CLrf3Gdxzbot+ZILh/aQ5lj0lr8Gm01hDVl8gOeEPp9EFgVymy1TIu5bgsEno1Ah3d8Q29xTCJPkfFQIcJgYnaOpoB/a3WQEdT0lozNMBXaFP+3FlfWuTRIt6A8Z7SkPYcMY3klH2hgMaoN3fqaEVQ7iUX11xi7c1HC2Wr+JM3Le0dYr0519P+HlGa4EevAmn05LUoL8q+stcQSBUVa1wxYyOH2O1IkUDK0nBt0vaa7MVRW10yxgA5E6WmVjl0DwkjqmdL8lBmcB97rmS1F4oemEwbRp4EUNKq07/BFO0j70UNNegYE55EQN+ysk2qkw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=R7XhHw0V8JBndHcXoRndSEd8HV79xA+DIBLU0SEsQKo=; b=jMGipuTBy6USNHW7sP58hAiE0ldm9FVvv59BSZhIcMcO0itKD5tDkON0MG8jGx58emhWx3mFfb4qBi+Du1THEGwECa4sVH3AuvsQ9BSMzqWOtF5IRZFCMWxo4yfStlPF5ZVBxG3cCn+Uadhf21lpOcE1wk7Z/3PiSj1N9k8Yf0V/v3Yzb1aswRA3u2kWBVhTqz/sYss8KIwbtXhB5prIGrwG5hTh0kU5z2cPl4NwP3J2mY1FyUay08Qym+i3ph+NgCrGhtXjJyNoRcNguvu+CCLDtJ9Uyw/zpfGCqZGJeVMABMtcCvQcr3e2sm5Z9YfzFX0OrAfODxRo6fQ3FnMrew== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=intel.com; dmarc=pass action=none header.from=intel.com; dkim=pass header.d=intel.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=intel.onmicrosoft.com; s=selector2-intel-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=R7XhHw0V8JBndHcXoRndSEd8HV79xA+DIBLU0SEsQKo=; b=fDKi5bj62cb1eNdtlI9VtoBsGcjRO9MxzUZ+ngQ35oDismVt+4fK8/j7AH6bJ8CBHiQchydKqjpV/UbsteaF4IagwnBg4t0fjePbXyIq4N3Hfk6T1TCmcCWilT/2J6YhVlvi773V0fTMWKyuHl1gSeULejuEIGe2i+ibDcXc/10= Received: from BN6PR1101MB2147.namprd11.prod.outlook.com (2603:10b6:405:57::23) by BN8PR11MB3843.namprd11.prod.outlook.com (2603:10b6:408:88::29) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3805.16; Thu, 4 Feb 2021 03:56:43 +0000 Received: from BN6PR1101MB2147.namprd11.prod.outlook.com ([fe80::203e:ed6b:a572:6453]) by BN6PR1101MB2147.namprd11.prod.outlook.com ([fe80::203e:ed6b:a572:6453%3]) with mapi id 15.20.3805.024; Thu, 4 Feb 2021 03:56:43 +0000 From: "Nate DeSimone" To: "Luo, Heng" , "devel@edk2.groups.io" CC: "Chaganty, Rangasai V" Subject: Re: [PATCH 36/40] TigerlakeSiliconPkg/Pch: Add Pch modules Thread-Topic: [PATCH 36/40] TigerlakeSiliconPkg/Pch: Add Pch modules Thread-Index: AQHW+DruS/o/B82Pk0+L3Otf4U3WIqpHWlBA Date: Thu, 4 Feb 2021 03:56:42 +0000 Message-ID: References: <20210201013657.1833-1-heng.luo@intel.com> <20210201013657.1833-36-heng.luo@intel.com> In-Reply-To: <20210201013657.1833-36-heng.luo@intel.com> Accept-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: dlp-reaction: no-action dlp-version: 11.5.1.3 dlp-product: dlpe-windows authentication-results: intel.com; dkim=none (message not signed) header.d=none;intel.com; dmarc=none action=none header.from=intel.com; x-originating-ip: [50.53.190.176] x-ms-publictraffictype: Email x-ms-office365-filtering-correlation-id: 28b24135-b38e-4e32-c7c5-08d8c8c0e276 x-ms-traffictypediagnostic: BN8PR11MB3843: x-ms-exchange-transport-forked: True x-microsoft-antispam-prvs: x-ms-oob-tlc-oobclassifiers: OLM:8882; x-ms-exchange-senderadcheck: 1 x-microsoft-antispam: BCL:0; x-microsoft-antispam-message-info: /VzY9t2Q1yrhWrl7CL8CDiErYZRfoAHEJjszI1qro+fijjKYKczvcb4qorYh83lsYZW7oTQePHLPDZBmwqljj3VMueu22gZ8XDz5SYxHILCzheFGe46TcXnS5QXv99SwZ+PO4o0zyD7lfsJHLUwIGwzwT0FU2nUk/fdjc8NiRF29FMyNImnWwdrsZbo571DLagNFcThWv9AxpGdP2gzKGm6Td+Z01ruQN3LHCcuXhsL8J1a5lzILC+nzamx80armIIzH9VSe3BxpjoZNQHt75cmvX6DosFVtT+iVtrwbj8Af+WMC/sfZ1cJeeo7ybRjm08hWshA06xTatMr9HEKhItNXmLfzcM0DJKjuVLAyIZUZ5tML6dvGRUj1iewdmPG0z7fYPI0kpB2psPY2DUOSXmAyVVoqTLjp3YDQkCJZyyjRpr/70oFqJ7sd0sKl9MtCbPS+YkWOAcMDapr3YjN4ziBip6w+d0EJ8+RA+rOI662v27pvHJSTAIiwGtUaSVHY/y/TeToPHM/Xe1NGpfnTdF7fCXqOaBBx09Xbz3Y1chMq4/Znlz88y+MQ4SPTeiui6Y8AMiTtiGKAHe9aORtdKA9K+pBh1+lbk1/5fVmegiui7nvQ2TcVWYMIL5kXXpI1b27z5Ulbtc1x6X/hcELfSg== x-forefront-antispam-report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:BN6PR1101MB2147.namprd11.prod.outlook.com;PTR:;CAT:NONE;SFS:(346002)(366004)(396003)(376002)(136003)(39860400002)(9686003)(55016002)(8676002)(33656002)(30864003)(110136005)(7696005)(86362001)(52536014)(66946007)(4326008)(316002)(186003)(19627235002)(83380400001)(66476007)(478600001)(76116006)(8936002)(26005)(66556008)(53546011)(6506007)(966005)(5660300002)(107886003)(2906002)(64756008)(71200400001)(66446008)(579004)(569008);DIR:OUT;SFP:1102; x-ms-exchange-antispam-messagedata: =?us-ascii?Q?6CMzAqLfMlxcvx+SVWj81MNDnsfhirMyXIrt1DqhzprJ6TD2eu5Zms3BQlMi?= =?us-ascii?Q?QaU6vG9JZIpj5LfEUd55sQDyQO9In5prf+wV/FVg8m/fMxp2BHXPra8yvs6Y?= =?us-ascii?Q?7NO8GE+NIub+0mcgA91YhIDAU6Aw1PEvH6hKmtooK7yqyOmEtIgBZ0C1tbX0?= =?us-ascii?Q?vN/u94S9XOFztwLm3rCpW3U9BTO9aanC0n8rQMSRcLZ9gLRMeQ+kYc5xvPMt?= =?us-ascii?Q?pOZuKyB4PeyFLJSqR8aGVjKAdu6zAtULwbW+00k0CTxVmPmOrmlhgvkDJyEK?= =?us-ascii?Q?si9gr/ws+8Usr/SuIhhO7TMjP/mM4ZhWrZ3diu3Nnt19kEHKdTc+2BczPpcD?= =?us-ascii?Q?d41i8gZUIY494JnbM9zqY2U2Bfe2WTP8aIP+Dn1GmgCbH1NpWT2Bwa7ycTBM?= =?us-ascii?Q?G04ZMCsT3yq9K1Otf6p19NGxmp+7NaOcED5awWtahsmkMfR7l1NApM8lNMdX?= =?us-ascii?Q?pxh4s6wguCMJJTvq4CAqK2++5EscU2JlOpuJNwKJjbr8gcY5KuJT4caPSFbJ?= =?us-ascii?Q?VGzOXOEkk3IsLwn8UoDhDzAmOvvFC3dUiFHY4Ij7+o4TO3kzzqsywDzgPWN+?= =?us-ascii?Q?qnkiDMiJCSXJi98UDYcyPI0kVMN2oVMAEoLyGXbyzYgtDN1Vukkf61V7ZqNE?= =?us-ascii?Q?IqTlvkToR24Crtke0uWPgjYcKMi+O8TQOFyyLuYMRpO+BV8I64+E7DboGfkS?= =?us-ascii?Q?uLwLNyeXVKt3St6+9MLy/uAvwMZ8Hv4bmaXaO7dh9XpvWImobQCNH72WYheE?= =?us-ascii?Q?Ffx1kHkuB6ArafOh8DvpIsUfcO+o7d78F1mCXS3Vb0FOoZqIfS7BoL/NaV4b?= =?us-ascii?Q?br6ipK75ZQMvrl+FFE4rE36Z96C7KCvgKycldQY0Ds7jbCYxvjtVLVl5jpS9?= =?us-ascii?Q?CkystTwMVX7wzcpJeMuTeupjmKgH9di5cCVjwskvCIu/jbb2vpi2bmWPjgl8?= =?us-ascii?Q?OP1isXXZK6xIaZW4E4QKj7LNeF/yHCyq9rYaWWtpJ3H6TGx8fEMmeRhVCvGX?= =?us-ascii?Q?fXvpJpF/1ROmnw0exVNxHlUAueYUZOuW457JhZNi7UyfQLPIwUEzPiqsikPa?= =?us-ascii?Q?TP3m/Ak818eWVsjvL+44lUDg3OiqHsSjvSPJJRxr2biIF8FLzt+OtyKvXvlo?= =?us-ascii?Q?6Fi0QZIN9IR046QJSit8xmZeKFdYpb88MeicXqMHGsSm7bFx+H/WGoqNruwa?= =?us-ascii?Q?kpDYOz2ksdhM7Q5qP1ynCWOcJl7rCpPohpVZclZI8bIMbnxrBWxwNtehdDug?= =?us-ascii?Q?s1JThWPwEHuDZ3jYpA4irFJCZN0qXAYZenKBv33UtHszTaJI4WasGij3kH9T?= =?us-ascii?Q?Pn+PGi8qhsm5YBDq5iVNG436?= MIME-Version: 1.0 X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-AuthSource: BN6PR1101MB2147.namprd11.prod.outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: 28b24135-b38e-4e32-c7c5-08d8c8c0e276 X-MS-Exchange-CrossTenant-originalarrivaltime: 04 Feb 2021 03:56:42.6248 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 46c98d88-e344-4ed4-8496-4ed7712e255d X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: Jw6z1Xcpdl8DL1mXxCJ9qoOla28N0e2J/xG0RVYerk29AXNm3FSDQwtWIRga/qGnm7otaqqGO0hAKKBpMcmjVvdbEftX6DP2y9dIYxK88IU= X-MS-Exchange-Transport-CrossTenantHeadersStamped: BN8PR11MB3843 Return-Path: nathaniel.l.desimone@intel.com X-OriginatorOrg: intel.com Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Hi Heng, Please see comments inline. Thanks, Nate > -----Original Message----- > From: Luo, Heng > Sent: Sunday, January 31, 2021 5:37 PM > To: devel@edk2.groups.io > Cc: Chaganty, Rangasai V ; Desimone, > Nathaniel L > Subject: [PATCH 36/40] TigerlakeSiliconPkg/Pch: Add Pch modules >=20 > REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3D3171 >=20 > Adds the following files: > * Pch/PchInit/Dxe > * Pch/PchInit/Smm > * Pch/PchSmiDispatcher/Smm > * Pch/SmmControl/RuntimeDxe >=20 > Cc: Sai Chaganty > Cc: Nate DeSimone > Signed-off-by: Heng Luo > --- > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchAcpi.c = | 494 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++ > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchCnviAcpi.c = | > 41 ++++++++++++++++ > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchHdaAcpi.c = | > 201 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > +++++++++++++++++ > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInit.c = | 314 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > + > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInit.h = | 122 > ++++++++++++++++++++++++++++++++++++++++++++++ > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxe.c = | > 354 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++ > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxeTgl.inf = | > 96 ++++++++++++++++++++++++++++++++++++ > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSata.c = | 89 > ++++++++++++++++++++++++++++++++++ > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIo.c = | 33 > +++++++++++++ > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIoDxe.c = | > 134 ++++++++++++++++++++++++++++++++++++++++++++++++++ > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/GbeSxSmm.c = | > 266 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++ > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchBiosWriteProtect.c > | 137 +++++++++++++++++++++++++++++++++++++++++++++++++++ > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchHdaSxSmm.c > | 33 +++++++++++++ > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.c = | > 285 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > +++++++++++++++++++++++++++++++++++++++++++++++++ > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.h = | > 254 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > +++++++++++++++++++++++++++++++++++++ > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.inf = | > 110 +++++++++++++++++++++++++++++++++++++++++ > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchPcieSmm.c = | > 451 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++ > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchSpiAsync.c = | > 67 +++++++++++++++++++++++++ > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.c > | 1284 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++ > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.h > | 226 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > +++++++++++++++++++++++++++ >=20 > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispatc > h.c | 2442 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++ >=20 > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispatc > her.inf | 116 ++++++++++++++++++++++++++++++++++++++++++++ >=20 > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelper. > h | 40 +++++++++++++++ >=20 > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelper > Client.c | 57 ++++++++++++++++++++++ > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmm.h > | 1043 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > +++++++++++++++++++++++++++++++++++++++++ >=20 > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmCore. > c | 926 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > +++++++++++++++++++++++++++++++++++++++++++++++++++++++ > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEspi.c > | 1588 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++ >=20 > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEspi.h > | 341 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > +++++++++++ > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmGpi.c > | 263 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++ >=20 > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelpe > rs.c | 332 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++ >=20 > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelpe > rs.h | 155 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ >=20 > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPerio > dicTimer.c | 667 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > +++++++++++++++++ >=20 > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPowe > rButton.c | 81 +++++++++++++++++++++++++++++++ > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSw.c > | 381 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++ > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSx.c > | 224 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++ > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmUsb.c > | 230 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++ >=20 > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHelp > ers.c | 778 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ >=20 > Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHelp > ers.h | 107 ++++++++++++++++++++++++++++++++++++++++ >=20 > Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControl > .inf | 54 +++++++++++++++++++++ >=20 > Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControl > Driver.c | 394 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > +++++++++++++++++++++++++++++++ >=20 > Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControl > Driver.h | 130 > +++++++++++++++++++++++++++++++++++++++++++++++++ > 41 files changed, 15340 insertions(+) >=20 > diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchAcpi.c > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchAcpi.c > new file mode 100644 > index 0000000000..e88afa5ded > --- /dev/null > +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchAcpi.c > @@ -0,0 +1,494 @@ > +/** @file >=20 > + This is the driver that initializes the Intel PCH. >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > + >=20 > +#include "PchInit.h" >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > + >=20 > +// >=20 > +// Module variables >=20 > +// >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED PCH_NVS_AREA_PROTOCOL > mPchNvsAreaProtocol; >=20 > + >=20 > +/** >=20 > + Retrieve interrupt information about a PCH device from policy >=20 > + >=20 > + @param[in] UartNumber Uart number >=20 > + >=20 > + @retval PCH_DEVICE_INTERRUPT_CONFIG structure with device's > interrupt information >=20 > +**/ >=20 > +PCH_DEVICE_INTERRUPT_CONFIG >=20 > +GetUartInterrupt ( >=20 > + IN UINT8 UartNumber >=20 > + ) >=20 > +{ >=20 > + PCH_DEVICE_INTERRUPT_CONFIG EmptyRecord; >=20 > + UINT8 DevNum; >=20 > + UINT8 FuncNum; >=20 > + UINT8 Index; >=20 > + >=20 > + ZeroMem (&EmptyRecord, sizeof (PCH_DEVICE_INTERRUPT_CONFIG)); >=20 > + DevNum =3D SerialIoUartDevNumber (UartNumber); >=20 > + FuncNum =3D SerialIoUartFuncNumber (UartNumber); >=20 > + >=20 > + for (Index =3D 0; Index < mPchConfigHob->Interrupt.NumOfDevIntConfig; > Index++) { >=20 > + if ((mPchConfigHob->Interrupt.DevIntConfig[Index].Device =3D=3D DevN= um) > && >=20 > + (mPchConfigHob->Interrupt.DevIntConfig[Index].Function =3D=3D > FuncNum)) { >=20 > + return mPchConfigHob->Interrupt.DevIntConfig[Index]; >=20 > + } >=20 > + } >=20 > + return EmptyRecord; >=20 > +} >=20 > + >=20 > +/** >=20 > + Update ASL definitions for SerialIo devices. >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +UpdateSerialIoAcpiData ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + UINT8 Index; >=20 > + >=20 > + for (Index =3D 0; Index < GetPchMaxSerialIoSpiControllersNum (); Index= ++) { >=20 > + mPchNvsAreaProtocol.Area->SM0[Index] =3D mPchConfigHob- > >SerialIo.SpiDeviceConfig[Index].Mode; >=20 > + mPchNvsAreaProtocol.Area->SC0[Index] =3D GetSerialIoSpiPciCfg (Index= ); >=20 > + } >=20 > + for (Index =3D 0; Index < GetPchMaxSerialIoI2cControllersNum (); Index= ++) { >=20 > + mPchNvsAreaProtocol.Area->IM0[Index] =3D mPchConfigHob- > >SerialIo.I2cDeviceConfig[Index].Mode; >=20 > + mPchNvsAreaProtocol.Area->IC0[Index] =3D GetSerialIoI2cPciCfg (Index= ); >=20 > + } >=20 > + for (Index =3D 0; Index < GetPchMaxSerialIoUartControllersNum (); Inde= x++) > { >=20 > + mPchNvsAreaProtocol.Area->UM0[Index] =3D mPchConfigHob- > >SerialIo.UartDeviceConfig[Index].Mode; >=20 > + mPchNvsAreaProtocol.Area->UC0[Index] =3D GetSerialIoUartPciCfg > (Index); >=20 > + mPchNvsAreaProtocol.Area->UD0[Index] =3D mPchConfigHob- > >SerialIo.UartDeviceConfig[Index].DmaEnable; >=20 > + mPchNvsAreaProtocol.Area->UP0[Index] =3D mPchConfigHob- > >SerialIo.UartDeviceConfig[Index].PowerGating; >=20 > + mPchNvsAreaProtocol.Area->UI0[Index] =3D (GetUartInterrupt > (Index)).Irq; >=20 > + } >=20 > +} >=20 > + >=20 > +#if FixedPcdGet8(PcdEmbeddedEnable) =3D=3D 0x1 >=20 > +/** >=20 > + Update NVS Area for Timed GPIO devices. >=20 > +**/ >=20 > +VOID >=20 > +UpdateTimedGpioSetup ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + mPchNvsAreaProtocol.Area->EnableTimedGpio0 =3D > (UINT8)mPchConfigHob->Pm.EnableTimedGpio0; >=20 > + mPchNvsAreaProtocol.Area->EnableTimedGpio1 =3D > (UINT8)mPchConfigHob->Pm.EnableTimedGpio1; >=20 > +} >=20 > +#endif >=20 > + >=20 > +/** >=20 > + Update NVS Area after RST PCIe Storage Remapping and before Boot >=20 > + >=20 > + @retval EFI_SUCCESS The function completed successfully >=20 > + @retval EFI_NOT_FOUND Couldn't fetch RstHob >=20 > +**/ >=20 > +EFI_STATUS >=20 > +PchUpdateNvsAreaAfterRemapping ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + UINTN Index; >=20 > + VOID *Hob; >=20 > + PCH_RST_HOB *RstHob; >=20 > + >=20 > + Hob =3D GetFirstGuidHob (&gPchRstHobGuid); >=20 > + if (Hob =3D=3D NULL) { >=20 > + return EFI_NOT_FOUND; >=20 > + } >=20 > + >=20 > + RstHob =3D (PCH_RST_HOB *) GET_GUID_HOB_DATA (Hob); >=20 > + >=20 > + for (Index =3D 0; Index < PCH_MAX_RST_PCIE_STORAGE_CR; Index++) { >=20 > + mPchNvsAreaProtocol.Area->RstPcieStorageInterfaceType[Index] = =3D > RstHob->RstCrConfiguration[Index].DeviceInterface; >=20 > + mPchNvsAreaProtocol.Area->RstPcieStoragePmCapPtr[Index] = =3D > RstHob->SavedRemapedDeviceConfigSpace[Index].PmCapPtr; >=20 > + mPchNvsAreaProtocol.Area->RstPcieStoragePcieCapPtr[Index] = =3D > RstHob->SavedRemapedDeviceConfigSpace[Index].PcieCapPtr; >=20 > + mPchNvsAreaProtocol.Area->RstPcieStorageL1ssCapPtr[Index] = =3D > RstHob->SavedRemapedDeviceConfigSpace[Index].L1ssCapPtr; >=20 > + mPchNvsAreaProtocol.Area->RstPcieStorageEpL1ssControl2[Index] = =3D > RstHob->SavedRemapedDeviceConfigSpace[Index].EndpointL1ssControl2; >=20 > + mPchNvsAreaProtocol.Area->RstPcieStorageEpL1ssControl1[Index] = =3D > RstHob->SavedRemapedDeviceConfigSpace[Index].EndpointL1ssControl1; >=20 > + mPchNvsAreaProtocol.Area->RstPcieStorageLtrCapPtr[Index] = =3D > RstHob->SavedRemapedDeviceConfigSpace[Index].LtrCapPtr; >=20 > + mPchNvsAreaProtocol.Area->RstPcieStorageEpLtrData[Index] = =3D > RstHob->SavedRemapedDeviceConfigSpace[Index].EndpointLtrData; >=20 > + mPchNvsAreaProtocol.Area->RstPcieStorageEpLctlData16[Index] = =3D > RstHob->SavedRemapedDeviceConfigSpace[Index].EndpointLctlData16; >=20 > + mPchNvsAreaProtocol.Area->RstPcieStorageEpDctlData16[Index] = =3D > RstHob->SavedRemapedDeviceConfigSpace[Index].EndpointDctlData16; >=20 > + mPchNvsAreaProtocol.Area->RstPcieStorageEpDctl2Data16[Index] = =3D > RstHob->SavedRemapedDeviceConfigSpace[Index].EndpointDctl2Data16; >=20 > + mPchNvsAreaProtocol.Area->RstPcieStorageRpDctl2Data16[Index] = =3D > RstHob->SavedRemapedDeviceConfigSpace[Index].RootPortDctl2Data16; >=20 > + mPchNvsAreaProtocol.Area->RstPcieStorageUniqueTableBar[Index] = =3D > RstHob->RstCrConfiguration[Index].EndPointUniqueMsixTableBar; >=20 > + mPchNvsAreaProtocol.Area- > >RstPcieStorageUniqueTableBarValue[Index] =3D RstHob- > >RstCrConfiguration[Index].EndPointUniqueMsixTableBarValue; >=20 > + mPchNvsAreaProtocol.Area->RstPcieStorageUniquePbaBar[Index] = =3D > RstHob->RstCrConfiguration[Index].EndPointUniqueMsixPbaBar; >=20 > + mPchNvsAreaProtocol.Area->RstPcieStorageUniquePbaBarValue[Index] > =3D RstHob->RstCrConfiguration[Index].EndPointUniqueMsixPbaBarValue; >=20 > + mPchNvsAreaProtocol.Area->RstPcieStorageRootPortNum[Index] = =3D > RstHob->RstCrConfiguration[Index].RootPortNum; >=20 > + } >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > + >=20 > +/** >=20 > + Update the Hybrid storage location NVS Area if Hybrid Storage device i= s > present >=20 > +**/ >=20 > +EFI_STATUS >=20 > +UpdateHybridStorageLocation ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + VOID *Hob; >=20 > + PCH_HYBRIDSTORAGE_HOB *HybridStorageHob; >=20 > + >=20 > + Hob =3D GetFirstGuidHob (&gHybridStorageHobGuid); >=20 > + if (Hob =3D=3D NULL) { >=20 > + return EFI_NOT_FOUND; >=20 > + } >=20 > + >=20 > + HybridStorageHob =3D (PCH_HYBRIDSTORAGE_HOB *) > GET_GUID_HOB_DATA (Hob); >=20 > + mPchNvsAreaProtocol.Area->HybridStorageLocation =3D HybridStorageHob- > >HybridStorageLocation; >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > + >=20 > +/** >=20 > + PCH ACPI initialization before Boot Sript Table is closed >=20 > + It update ACPI table and ACPI NVS area. >=20 > + >=20 > + @param[in] Event A pointer to the Event that triggered = the > callback. >=20 > + @param[in] Context A pointer to private data registered w= ith the > callback function. >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +PchAcpiOnEndOfDxe ( >=20 > + IN EFI_EVENT Event, >=20 > + IN VOID *Context >=20 > + ) >=20 > +{ >=20 > + DEBUG ((DEBUG_INFO, "PchAcpiOnEndOfDxe() Start\n")); >=20 > + >=20 > + /// >=20 > + /// Closed the event to avoid call twice when launch shell >=20 > + /// >=20 > + gBS->CloseEvent (Event); >=20 > + >=20 > + // >=20 > + // Init HDA Audio ACPI tables >=20 > + // >=20 > + PchHdAudioAcpiInit (); >=20 > + // >=20 > + // Update ASL definitions for SerialIo devices. >=20 > + // >=20 > + UpdateSerialIoAcpiData (); >=20 > + UpdateCnviAcpiData (); >=20 > +#if FixedPcdGet8(PcdEmbeddedEnable) =3D=3D 0x1 >=20 > + UpdateTimedGpioSetup(); >=20 > +#endif >=20 > + >=20 > + // >=20 > + // Update Pch Nvs Area >=20 > + // >=20 > + PchUpdateNvsArea (); >=20 > + >=20 > + DEBUG ((DEBUG_INFO, "PchAcpiOnEndOfDxe() End\n")); >=20 > + >=20 > + return; >=20 > +} >=20 > + >=20 > +/** >=20 > + Initialize Pch acpi >=20 > + @param[in] ImageHandle Handle for the image of this driver >=20 > + >=20 > + @retval EFI_SUCCESS The function completed successfully >=20 > + @retval EFI_OUT_OF_RESOURCES Do not have enough resources to > initialize the driver >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchAcpiInit ( >=20 > + IN EFI_HANDLE ImageHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + EFI_EVENT EndOfDxeEvent; >=20 > + >=20 > + DEBUG ((DEBUG_INFO, "Install PCH NVS protocol\n")); >=20 > + >=20 > + Status =3D (gBS->AllocatePool) (EfiACPIMemoryNVS, sizeof > (PCH_NVS_AREA), (VOID **) &mPchNvsAreaProtocol.Area); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + ZeroMem ((VOID *) mPchNvsAreaProtocol.Area, sizeof > (PCH_NVS_AREA)); >=20 > + Status =3D gBS->InstallMultipleProtocolInterfaces ( >=20 > + &ImageHandle, >=20 > + &gPchNvsAreaProtocolGuid, >=20 > + &mPchNvsAreaProtocol, >=20 > + NULL >=20 > + ); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + /// >=20 > + /// Update the NVS Area after RST PCIe Storage Remapping >=20 > + /// >=20 > + PchUpdateNvsAreaAfterRemapping (); >=20 > + >=20 > + UpdateHybridStorageLocation (); >=20 > + // >=20 > + // Register an end of DXE event for PCH ACPI to do tasks before invoki= ng > any UEFI drivers, >=20 > + // applications, or connecting consoles,... >=20 > + // >=20 > + Status =3D gBS->CreateEventEx ( >=20 > + EVT_NOTIFY_SIGNAL, >=20 > + TPL_CALLBACK, >=20 > + PchAcpiOnEndOfDxe, >=20 > + NULL, >=20 > + &gEfiEndOfDxeEventGroupGuid, >=20 > + &EndOfDxeEvent >=20 > + ); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + return Status; >=20 > +} >=20 > + >=20 > + >=20 > +/** >=20 > + Update NVS area for PCIe root ports. >=20 > +**/ >=20 > +STATIC >=20 > +VOID >=20 > +PcieRpUpdateNvsArea ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + UINT32 Index; >=20 > + >=20 > + for (Index =3D 0; Index < PCH_MAX_PCIE_CLOCKS; Index++) { >=20 > + mPchNvsAreaProtocol.Area->ClockToRootPortMap[Index] =3D > mPchConfigHob->PcieRp.PcieClock[Index].Usage; >=20 > + } >=20 > +} >=20 > + >=20 > +/** >=20 > + Update ASL object before Boot >=20 > + >=20 > + @retval EFI_STATUS >=20 > + @retval EFI_NOT_READY The Acpi protocols are not ready. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +PchUpdateNvsArea ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + UINTN Index; >=20 > + UINT32 HpetBaseAdress; >=20 > + GPIO_GROUP GroupToGpeDwX[3]; >=20 > + UINT32 GroupDw[3]; >=20 > + UINTN RpDev; >=20 > + UINTN RpFun; >=20 > + UINT32 Data32; >=20 > + PCH_POLICY_PROTOCOL *PchPolicy; >=20 > + GPIO_DXE_CONFIG *GpioDxeConfig; >=20 > + UINT64 XdciPciBase; >=20 > + UINT64 XdciBar; >=20 > + UINT16 PciMemConfig; >=20 > + UINT16 TcoBase; >=20 > + UINT8 ClearXdciBar =3D FALSE; >=20 > + >=20 > + /// >=20 > + /// Get PCH Policy Protocol >=20 > + /// >=20 > + Status =3D gBS->LocateProtocol (&gPchPolicyProtocolGuid, NULL, (VOID > **)&PchPolicy); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + /// >=20 > + /// Get GPIO DXE Config Block >=20 > + /// >=20 > + Status =3D GetConfigBlock ((VOID *)PchPolicy, &gGpioDxeConfigGuid, (VO= ID > *)&GpioDxeConfig); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + // >=20 > + // Update ASL PCIE port address according to root port device and func= tion >=20 > + // >=20 > + for (Index =3D 0; Index < GetPchMaxPciePortNum (); Index++) { >=20 > + RpDev =3D PchPcieRpDevNumber (Index); >=20 > + RpFun =3D PchPcieRpFuncNumber (Index); >=20 > + Data32 =3D ((UINT8) RpDev << 16) | (UINT8) RpFun; >=20 > + mPchNvsAreaProtocol.Area->RpAddress[Index] =3D Data32; >=20 > + >=20 > + // >=20 > + // Update Maximum Snoop Latency and Maximum No-Snoop Latency > values for PCIE >=20 > + // >=20 > + mPchNvsAreaProtocol.Area->PcieLtrMaxSnoopLatency[Index] =3D > mPchConfigHob- > >PcieRp.RootPort[Index].PcieRpCommonConfig.PcieRpLtrConfig.LtrMaxSno > opLatency; >=20 > + mPchNvsAreaProtocol.Area->PcieLtrMaxNoSnoopLatency[Index] =3D > mPchConfigHob- > >PcieRp.RootPort[Index].PcieRpCommonConfig.PcieRpLtrConfig.LtrMaxNoS > noopLatency; >=20 > + } >=20 > + >=20 > + // >=20 > + // Update PCHS. >=20 > + // >=20 > + mPchNvsAreaProtocol.Area->PchSeries =3D PchSeries (); >=20 > + // >=20 > + // Update PCHG. >=20 > + // >=20 > + mPchNvsAreaProtocol.Area->PchGeneration =3D (UINT16) PchGeneration (); >=20 > + // >=20 > + // Update PSTP. >=20 > + // >=20 > + mPchNvsAreaProtocol.Area->PchStepping =3D (UINT16) PchStepping (); >=20 > + // >=20 > + // Update HPET base address. >=20 > + // >=20 > + PchHpetBaseGet (&HpetBaseAdress); >=20 > + mPchNvsAreaProtocol.Area->HPTE =3D TRUE; // @todo remove the > NVS, since it's always enabled. >=20 > + mPchNvsAreaProtocol.Area->HPTB =3D HpetBaseAdress; >=20 > + // >=20 > + // Update SBREG_BAR. >=20 > + // >=20 > + mPchNvsAreaProtocol.Area->SBRG =3D PCH_PCR_BASE_ADDRESS; >=20 > + >=20 > + // >=20 > + // Update base address >=20 > + // >=20 > + mPchNvsAreaProtocol.Area->PMBS =3D PmcGetAcpiBase (); >=20 > + mPchNvsAreaProtocol.Area->PWRM =3D PmcGetPwrmBase (); >=20 > + PchTcoBaseGet (&TcoBase); >=20 > + mPchNvsAreaProtocol.Area->TcoBase =3D TcoBase; >=20 > + >=20 > + // >=20 > + // Update PCH PID info >=20 > + // >=20 > + mPchNvsAreaProtocol.Area->IclkPid =3D PchPcrGetPid (PchIpIclk); >=20 > + >=20 > + // >=20 > + // Update GPIO device ACPI variables >=20 > + // >=20 > + mPchNvsAreaProtocol.Area->SGIR =3D mPchConfigHob- > >Interrupt.GpioIrqRoute; >=20 > + mPchNvsAreaProtocol.Area->GPHD =3D (UINT8)GpioDxeConfig- > >HideGpioAcpiDevice; >=20 > + >=20 > + // >=20 > + // Update GPP_X to GPE_DWX mapping. >=20 > + // >=20 > + GpioGetGroupDwToGpeDwX ( >=20 > + &GroupToGpeDwX[0], &GroupDw[0], >=20 > + &GroupToGpeDwX[1], &GroupDw[1], >=20 > + &GroupToGpeDwX[2], &GroupDw[2] >=20 > + ); >=20 > + >=20 > + // >=20 > + // GEI0/1/2 and GED0/1/2 are objects for informing how GPIO groups are > mapped to GPE0. >=20 > + // If Group is mapped to 1-Tier GPE information is also stored on what > Group DW >=20 > + // is mapped to GPE_DWx. Because GPE_DWx register is 32 bits large if > groups have more than >=20 > + // 32 pads only part of it can be mapped. >=20 > + // >=20 > + // GEIx - GroupIndex mapped to GPE0_DWx >=20 > + // GEDx - DoubleWorld part of Group: 0 - pins 31-0, 1 - pins 63-32, .= .. >=20 > + // >=20 > + mPchNvsAreaProtocol.Area->GEI0 =3D (UINT8) > GpioGetGroupIndexFromGroup (GroupToGpeDwX[0]); >=20 > + mPchNvsAreaProtocol.Area->GEI1 =3D (UINT8) > GpioGetGroupIndexFromGroup (GroupToGpeDwX[1]); >=20 > + mPchNvsAreaProtocol.Area->GEI2 =3D (UINT8) > GpioGetGroupIndexFromGroup (GroupToGpeDwX[2]); >=20 > + mPchNvsAreaProtocol.Area->GED0 =3D (UINT8) GroupDw[0]; >=20 > + mPchNvsAreaProtocol.Area->GED1 =3D (UINT8) GroupDw[1]; >=20 > + mPchNvsAreaProtocol.Area->GED2 =3D (UINT8) GroupDw[2]; >=20 > + >=20 > + // >=20 > + // SCS Configuration >=20 > + // >=20 > + >=20 > + PcieRpUpdateNvsArea (); >=20 > + >=20 > + // >=20 > + // SATA configuration. >=20 > + // >=20 > + mPchNvsAreaProtocol.Area->SataPortPresence =3D > GetSataPortPresentStatus (0); >=20 > + DEBUG ((DEBUG_INFO, "SataPortPresence: 0x%x\n", > mPchNvsAreaProtocol.Area->SataPortPresence)); >=20 > + >=20 > + // >=20 > + // CPU SKU >=20 > + // >=20 > + mPchNvsAreaProtocol.Area->CpuSku =3D 0; >=20 > + mPchNvsAreaProtocol.Area->PsOnEnable =3D (UINT8)mPchConfigH= ob- > >Pm.PsOnEnable; >=20 > + >=20 > + for (Index =3D 0; Index < GetPchMaxPciePortNum (); Index++) { >=20 > + mPchNvsAreaProtocol.Area->LtrEnable[Index] =3D > (UINT8)mPchConfigHob- > >PcieRp.RootPort[Index].PcieRpCommonConfig.LtrEnable; >=20 > + } >=20 > + >=20 > + mPchNvsAreaProtocol.Area->GBES =3D IsGbePresent (); >=20 > + >=20 > + // >=20 > + // Update PCH Trace Hub Mode >=20 > + // >=20 > + mPchNvsAreaProtocol.Area->PchTraceHubMode =3D (UINT8) > mPchConfigHob->PchTraceHub.PchTraceHubMode; >=20 > + >=20 > + // >=20 > + // Saving GCTL value into PCH NVS area >=20 > + // >=20 > + >=20 > + XdciPciBase =3D PchXdciPciCfgBase (); >=20 > + >=20 > + // >=20 > + // Determine Base address for Base address register (Offset 0x10) >=20 > + // >=20 > + if (PciSegmentRead32 (XdciPciBase) !=3D 0xFFFFFFFF) { >=20 > + >=20 > + XdciBar =3D PciSegmentRead32 (XdciPciBase + > PCI_BASE_ADDRESSREG_OFFSET) & 0xFFFFFFF0; >=20 > + >=20 > + if ((PciSegmentRead32 (XdciPciBase + PCI_BASE_ADDRESSREG_OFFSET) & > B_PCI_BAR_MEMORY_TYPE_MASK) =3D=3D B_PCI_BAR_MEMORY_TYPE_64) { >=20 > + XdciBar +=3D (UINT64)PciSegmentRead32 (XdciPciBase + > (PCI_BASE_ADDRESSREG_OFFSET + 4)) << 32; >=20 > + } >=20 > + >=20 > + if (XdciBar =3D=3D 0x0) { >=20 > + ClearXdciBar =3D TRUE; >=20 > + PciSegmentWrite32 ((XdciPciBase + PCI_BASE_ADDRESSREG_OFFSET), > PcdGet32 (PcdSiliconInitTempMemBaseAddr)); >=20 > + XdciBar =3D PciSegmentRead32 (XdciPciBase + > PCI_BASE_ADDRESSREG_OFFSET) & 0xFFFFFFF0; >=20 > + >=20 > + if ((PciSegmentRead32 (XdciPciBase + PCI_BASE_ADDRESSREG_OFFSET) > & B_PCI_BAR_MEMORY_TYPE_MASK) =3D=3D B_PCI_BAR_MEMORY_TYPE_64) { >=20 > + XdciBar +=3D (UINT64)PciSegmentRead32 (XdciPciBase + > (PCI_BASE_ADDRESSREG_OFFSET + 4)) << 32; >=20 > + } >=20 > + } >=20 > + >=20 > + // >=20 > + // Enable Pci Memconfig to read the correct value for GCTL register >=20 > + // >=20 > + PciMemConfig =3D PciSegmentRead16 (XdciPciBase + > PCI_COMMAND_OFFSET); >=20 > + PciSegmentWrite16 (XdciPciBase + PCI_COMMAND_OFFSET, > PciMemConfig | (EFI_PCI_COMMAND_BUS_MASTER | > EFI_PCI_COMMAND_MEMORY_SPACE)); >=20 > + >=20 > + mPchNvsAreaProtocol.Area->PchxDCIPwrDnScale =3D MmioRead32(XdciBar > + R_XDCI_MEM_GCTL); >=20 > + DEBUG ((DEBUG_INFO, "PchxDCIPwrDnScale 0x%x\n", > (UINT64)mPchNvsAreaProtocol.Area->PchxDCIPwrDnScale)); >=20 > + // >=20 > + // Disable Pci Memconfig & clear Base address >=20 > + // >=20 > + PciSegmentWrite16(XdciPciBase + PCI_COMMAND_OFFSET, > PciMemConfig); >=20 > + >=20 > + if (ClearXdciBar =3D=3D TRUE) { >=20 > + PciSegmentWrite32 ((XdciPciBase + PCI_BASE_ADDRESSREG_OFFSET), > 0x0); >=20 > + PciSegmentWrite32 ((XdciPciBase + (PCI_BASE_ADDRESSREG_OFFSET + > 4)), 0x0); >=20 > + } >=20 > + } >=20 > + >=20 > + return Status; >=20 > +} >=20 > diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchCnviAcp= i.c > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchCnviAcpi.c > new file mode 100644 > index 0000000000..5c8e1ce5b4 > --- /dev/null > +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchCnviAcpi.c > @@ -0,0 +1,41 @@ > +/** @file >=20 > + Initializes PCH CNVi device ACPI data. >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > + >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include "PchInit.h" >=20 > +#include >=20 > + >=20 > +/** >=20 > + Update ASL definitions for CNVi device. >=20 > + >=20 > + @retval EFI_SUCCESS The function completed successfully >=20 > +**/ >=20 > +EFI_STATUS >=20 > +UpdateCnviAcpiData ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + EFI_PEI_HOB_POINTERS HobPtr; >=20 > + CNVI_CONFIG_HOB *CnviConfigHob; >=20 > + >=20 > + DEBUG ((DEBUG_INFO, "UpdateCnviAcpiData() Start\n")); >=20 > + >=20 > + // Get CNVi Config HOB. >=20 > + HobPtr.Guid =3D GetFirstGuidHob (&gCnviConfigHobGuid); >=20 > + if (HobPtr.Guid !=3D NULL) { >=20 > + CnviConfigHob =3D (CNVI_CONFIG_HOB *) GET_GUID_HOB_DATA > (HobPtr.Guid); >=20 > + mPchNvsAreaProtocol.Area->CnviMode =3D (UINT8)CnviConfigHo= b- > >Mode; >=20 > + mPchNvsAreaProtocol.Area->CnviBtCore =3D (UINT8)CnviConfigHo= b- > >BtCore; >=20 > + mPchNvsAreaProtocol.Area->CnviBtAudioOffload =3D > (UINT8)CnviConfigHob->BtAudioOffload; >=20 > + } >=20 > + mPchNvsAreaProtocol.Area->CnviPortId =3D PID_CNVI; >=20 > + DEBUG ((DEBUG_INFO, "UpdateCnviAcpiData() End\n")); >=20 > + >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchHdaAcpi= .c > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchHdaAcpi.c > new file mode 100644 > index 0000000000..dbdb028483 > --- /dev/null > +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchHdaAcpi.c > @@ -0,0 +1,201 @@ > + >=20 > +/** @file >=20 > + Initializes the PCH HD Audio ACPI Tables. >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > + >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include "PchInit.h" >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > + >=20 > +#define XTAL_FREQ_38P4MHZ 1 >=20 > + >=20 > +/** >=20 > + Retrieves address of NHLT table from XSDT/RSDT. >=20 > + >=20 > + @retval NHLT_ACPI_TABLE* Pointer to NHLT table if found >=20 > + @retval NULL NHLT could not be found >=20 > +**/ >=20 > +NHLT_ACPI_TABLE * >=20 > +LocateNhltAcpiTable ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp; >=20 > + EFI_ACPI_DESCRIPTION_HEADER *Xsdt; >=20 > + NHLT_ACPI_TABLE *Nhlt; >=20 > + UINTN Index; >=20 > + UINT64 Data64; >=20 > + EFI_STATUS Status; >=20 > + Rsdp =3D NULL; >=20 > + Xsdt =3D NULL; >=20 > + Nhlt =3D NULL; >=20 > + >=20 > + /// >=20 > + /// Find the AcpiSupport protocol returns RSDP (or RSD PTR) address. >=20 > + /// >=20 > + DEBUG ((DEBUG_INFO, "LocateNhltAcpiTable() Start\n")); >=20 > + >=20 > + Status =3D EfiGetSystemConfigurationTable (&gEfiAcpiTableGuid, (VOID *= ) > &Rsdp); >=20 > + if (EFI_ERROR (Status) || (Rsdp =3D=3D NULL)) { >=20 > + DEBUG ((DEBUG_ERROR, "EFI_ERROR or Rsdp =3D=3D NULL\n")); >=20 > + return NULL; >=20 > + } >=20 > + >=20 > + Xsdt =3D (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Rsdp->XsdtAddress; >=20 > + if (Xsdt =3D=3D NULL || Xsdt->Signature !=3D > EFI_ACPI_5_0_EXTENDED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) { >=20 > + // If XSDT has not been found, check RSDT >=20 > + Xsdt =3D (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Rsdp->RsdtAddress; >=20 > + if (Xsdt =3D=3D NULL || Xsdt->Signature !=3D > EFI_ACPI_5_0_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) { >=20 > + DEBUG ((DEBUG_ERROR, "XSDT/RSDT =3D=3D NULL or wrong signature\n")= ); >=20 > + return NULL; >=20 > + } >=20 > + } >=20 > + >=20 > + for (Index =3D sizeof (EFI_ACPI_DESCRIPTION_HEADER); Index < Xsdt- > >Length; Index =3D Index + sizeof (UINT64)) { >=20 > + Data64 =3D *(UINT64 *) ((UINT8 *) Xsdt + Index); >=20 > + Nhlt =3D (NHLT_ACPI_TABLE *) (UINTN) Data64; >=20 > + if (Nhlt !=3D NULL && Nhlt->Header.Signature =3D=3D > NHLT_ACPI_TABLE_SIGNATURE) { >=20 > + break; >=20 > + } >=20 > + Nhlt =3D NULL; >=20 > + } >=20 > + >=20 > + if (Nhlt =3D=3D NULL || Nhlt->Header.Signature !=3D > NHLT_ACPI_TABLE_SIGNATURE) { >=20 > + DEBUG ((DEBUG_ERROR, "Nhlt =3D=3D NULL or wrong signature\n")); >=20 > + return NULL; >=20 > + } >=20 > + >=20 > + DEBUG ((DEBUG_INFO, "Found NhltTable, Address =3D 0x%016x\n", Nhlt)); >=20 > + >=20 > + return Nhlt; >=20 > +} >=20 > + >=20 > +/** >=20 > + Sets NVS ACPI variables for HDAS._DSM and SNDW._DSD accordingly to > policy. >=20 > + >=20 > + @param[in] NhltAcpiTableAddress >=20 > + @param[in] NhltAcpiTableLength >=20 > + @param[in] *HdAudioConfigHob >=20 > + @param[in] *HdAudioDxeConfig >=20 > +**/ >=20 > +VOID >=20 > +UpdateHdaAcpiData ( >=20 > + IN UINT64 NhltAcpiTableAddress, >=20 > + IN UINT32 NhltAcpiTableLength, >=20 > + IN CONST HDAUDIO_HOB *HdAudioConfigHob, >=20 > + IN CONST HDAUDIO_DXE_CONFIG *HdAudioDxeConfig >=20 > + ) >=20 > +{ >=20 > + DEBUG ((DEBUG_INFO, "UpdateHdaAcpiData():\n NHLT Address =3D > 0x%016x, Length =3D 0x%08x\n", NhltAcpiTableAddress, > NhltAcpiTableLength)); >=20 > + DEBUG ((DEBUG_INFO, " FeatureMask =3D 0x%08x\n", HdAudioDxeConfig- > >DspFeatureMask)); >=20 > + >=20 > + mPchNvsAreaProtocol.Area->XTAL =3D XTAL_FREQ_38P4MHZ; >=20 > + mPchNvsAreaProtocol.Area->NHLA =3D NhltAcpiTableAddress; >=20 > + mPchNvsAreaProtocol.Area->NHLL =3D NhltAcpiTableLength; >=20 > + mPchNvsAreaProtocol.Area->ADFM =3D HdAudioDxeConfig- > >DspFeatureMask; >=20 > + >=20 > + if (HdAudioConfigHob->DspEnable || HdAudioConfigHob- > >DspUaaCompliance =3D=3D FALSE) { >=20 > + mPchNvsAreaProtocol.Area->SWQ0 =3D HdAudioConfigHob- > >AudioLinkSndw1 ? 0 : BIT1; >=20 > + mPchNvsAreaProtocol.Area->SWQ1 =3D HdAudioConfigHob- > >AudioLinkSndw2 ? 0 : BIT1; >=20 > + mPchNvsAreaProtocol.Area->SWQ2 =3D HdAudioConfigHob- > >AudioLinkSndw3 ? 0 : BIT1; >=20 > + mPchNvsAreaProtocol.Area->SWQ3 =3D HdAudioConfigHob- > >AudioLinkSndw4 ? 0 : BIT1; >=20 > + } else { >=20 > + mPchNvsAreaProtocol.Area->SWQ0 =3D BIT1; >=20 > + mPchNvsAreaProtocol.Area->SWQ1 =3D BIT1; >=20 > + mPchNvsAreaProtocol.Area->SWQ2 =3D BIT1; >=20 > + mPchNvsAreaProtocol.Area->SWQ3 =3D BIT1; >=20 > + } >=20 > + >=20 > + mPchNvsAreaProtocol.Area->SWMC =3D GetPchHdaMaxSndwLinkNum (); >=20 > + >=20 > + mPchNvsAreaProtocol.Area->ACS0 =3D (UINT8)HdAudioDxeConfig- > >SndwConfig[0].AutonomousClockStop; >=20 > + mPchNvsAreaProtocol.Area->ACS1 =3D (UINT8)HdAudioDxeConfig- > >SndwConfig[1].AutonomousClockStop; >=20 > + mPchNvsAreaProtocol.Area->ACS2 =3D (UINT8)HdAudioDxeConfig- > >SndwConfig[2].AutonomousClockStop; >=20 > + mPchNvsAreaProtocol.Area->ACS3 =3D (UINT8)HdAudioDxeConfig- > >SndwConfig[3].AutonomousClockStop; >=20 > + >=20 > + mPchNvsAreaProtocol.Area->DAI0 =3D (UINT8)HdAudioDxeConfig- > >SndwConfig[0].DataOnActiveIntervalSelect; >=20 > + mPchNvsAreaProtocol.Area->DAI1 =3D (UINT8)HdAudioDxeConfig- > >SndwConfig[1].DataOnActiveIntervalSelect; >=20 > + mPchNvsAreaProtocol.Area->DAI2 =3D (UINT8)HdAudioDxeConfig- > >SndwConfig[2].DataOnActiveIntervalSelect; >=20 > + mPchNvsAreaProtocol.Area->DAI3 =3D (UINT8)HdAudioDxeConfig- > >SndwConfig[3].DataOnActiveIntervalSelect; >=20 > + >=20 > + mPchNvsAreaProtocol.Area->DOD0 =3D (UINT8)HdAudioDxeConfig- > >SndwConfig[0].DataOnDelaySelect; >=20 > + mPchNvsAreaProtocol.Area->DOD1 =3D (UINT8)HdAudioDxeConfig- > >SndwConfig[1].DataOnDelaySelect; >=20 > + mPchNvsAreaProtocol.Area->DOD2 =3D (UINT8)HdAudioDxeConfig- > >SndwConfig[2].DataOnDelaySelect; >=20 > + mPchNvsAreaProtocol.Area->DOD3 =3D (UINT8)HdAudioDxeConfig- > >SndwConfig[3].DataOnDelaySelect; >=20 > +} >=20 > + >=20 > +/** >=20 > + Initialize Intel High Definition Audio ACPI Tables >=20 > + >=20 > + @retval EFI_SUCCESS The function completed successfully >=20 > + @retval EFI_LOAD_ERROR ACPI table cannot be installed >=20 > + @retval EFI_UNSUPPORTED ACPI table not set because DSP is disa= bled >=20 > +**/ >=20 > +EFI_STATUS >=20 > +PchHdAudioAcpiInit ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + UINT64 HdaPciBase; >=20 > + CONST HDAUDIO_HOB *HdAudioConfigHob; >=20 > + PCH_POLICY_PROTOCOL *PchPolicy; >=20 > + HDAUDIO_DXE_CONFIG *HdAudioDxeConfig; >=20 > + NHLT_ACPI_TABLE *NhltTable; >=20 > + >=20 > + >=20 > + DEBUG ((DEBUG_INFO, "PchHdAudioAcpiInit() Start\n")); >=20 > + >=20 > + HdAudioConfigHob =3D &mPchConfigHob->HdAudio; >=20 > + >=20 > + /// >=20 > + /// Get PCH Policy Protocol >=20 > + /// >=20 > + Status =3D gBS->LocateProtocol (&gPchPolicyProtocolGuid, NULL, (VOID > **)&PchPolicy); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + /// >=20 > + /// Get HD Audio DXE Config Block >=20 > + /// >=20 > + Status =3D GetConfigBlock ((VOID *)PchPolicy, &gHdAudioDxeConfigGuid, > (VOID *)&HdAudioDxeConfig); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + HdaPciBase =3D HdaPciCfgBase (); >=20 > + >=20 > + if ((PciSegmentRead16 (HdaPciBase + PCI_VENDOR_ID_OFFSET) =3D=3D > 0xFFFF) || (HdAudioConfigHob->DspEnable =3D=3D FALSE)) { >=20 > + // Do not set ACPI tables if HDAudio is Function disabled or DSP is = disabled >=20 > + DEBUG ((DEBUG_INFO, "AudioDSP: Non-HDAudio ACPI Table (NHLT) not > set!\n")); >=20 > + return EFI_UNSUPPORTED; >=20 > + } >=20 > + >=20 > + NhltTable =3D LocateNhltAcpiTable (); >=20 > + if (NhltTable =3D=3D NULL) { >=20 > + return EFI_LOAD_ERROR; >=20 > + } >=20 > + >=20 > + UpdateHdaAcpiData ((UINT64) (UINTN) NhltTable, (UINT32) (NhltTable- > >Header.Length), HdAudioConfigHob, HdAudioDxeConfig); >=20 > + DEBUG_CODE ( NhltAcpiTableDump (NhltTable); ); >=20 > + >=20 > + DEBUG ((DEBUG_INFO, "PchHdAudioAcpiInit() End - Status =3D %r\n", > Status)); >=20 > + return Status; >=20 > +} >=20 > + >=20 > diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInit.c > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInit.c > new file mode 100644 > index 0000000000..734d4e295a > --- /dev/null > +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInit.c > @@ -0,0 +1,314 @@ > +/** @file >=20 > + This is the Common driver that initializes the Intel PCH. >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > + >=20 > +#include "PchInit.h" >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > + >=20 > +// >=20 > +// Module variables >=20 > +// >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED PCH_CONFIG_HOB > *mPchConfigHob; >=20 > + >=20 > +// >=20 > +// EFI_EVENT >=20 > +// >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_EVENT mHeciEvent; >=20 > + >=20 > +/** >=20 > + Common PchInit Module Entry Point >=20 > +**/ >=20 > +VOID >=20 > +PchInitEntryPointCommon ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + EFI_PEI_HOB_POINTERS HobPtr; >=20 > + >=20 > + DEBUG ((DEBUG_INFO, "PchInitEntryPointCommon() Start\n")); >=20 > + >=20 > + // >=20 > + // Get PCH Config HOB. >=20 > + // >=20 > + HobPtr.Guid =3D GetFirstGuidHob (&gPchConfigHobGuid); >=20 > + ASSERT (HobPtr.Guid !=3D NULL); >=20 > + mPchConfigHob =3D (PCH_CONFIG_HOB *) GET_GUID_HOB_DATA > (HobPtr.Guid); >=20 > + >=20 > + DEBUG ((DEBUG_INFO, "PchInitEntryPointCommon() End\n")); >=20 > + >=20 > + return; >=20 > +} >=20 > + >=20 > +/** >=20 > + Lock SPI register before boot >=20 > +**/ >=20 > +VOID >=20 > +LockSpiConfiguration ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + UINTN Index; >=20 > + UINT16 Data16; >=20 > + UINT16 Data16And; >=20 > + UINT16 Data16Or; >=20 > + UINT32 Data32; >=20 > + UINT32 DlockValue; >=20 > + UINT64 PciSpiRegBase; >=20 > + UINT32 PchSpiBar0; >=20 > + UINT32 Timer; >=20 > + >=20 > + PciSpiRegBase =3D SpiPciCfgBase (); >=20 > + >=20 > + // >=20 > + // Check for SPI controller presence before programming >=20 > + // >=20 > + if (PciSegmentRead16 (PciSpiRegBase + PCI_VENDOR_ID_OFFSET) =3D=3D > 0xFFFF) { >=20 > + return; >=20 > + } >=20 > + >=20 > + // >=20 > + // Make sure SPI BAR0 has fixed address before writing to boot script. >=20 > + // The same base address is set in PEI and will be used during resume. >=20 > + // >=20 > + PchSpiBar0 =3D PCH_SPI_BASE_ADDRESS; >=20 > + >=20 > + PciSegmentAnd8 (PciSpiRegBase + PCI_COMMAND_OFFSET, (UINT8) > ~EFI_PCI_COMMAND_MEMORY_SPACE); >=20 > + PciSegmentWrite32 (PciSpiRegBase + R_SPI_CFG_BAR0, PchSpiBar0); >=20 > + PciSegmentOr8 (PciSpiRegBase + PCI_COMMAND_OFFSET, > EFI_PCI_COMMAND_MEMORY_SPACE); >=20 > + >=20 > + // >=20 > + // Locking for security reasons only if Extended BIOS Range Decode is > supported >=20 > + // >=20 > + if (IsExtendedBiosRangeDecodeSupported ()) { >=20 > + // >=20 > + // Before setting FLOCKDN lock Extended BIOS Range configuration >=20 > + // All configuration of this feature shall be done already at this m= oment >=20 > + // >=20 > + PciSegmentOr32 (PciSpiRegBase + R_SPI_CFG_BC, BIT28); >=20 > + S3BootScriptSavePciCfgWrite ( >=20 > + S3BootScriptWidthUint32, >=20 > + (UINTN) PciSpiRegBase + R_SPI_CFG_BC, >=20 > + 1, >=20 > + (VOID *) (UINTN) (PciSpiRegBase + R_SPI_CFG_BC) >=20 > + ); >=20 > + } >=20 > + >=20 > + // >=20 > + // Program the Flash Protection Range Register based on policy >=20 > + // >=20 > + DlockValue =3D MmioRead32 (PchSpiBar0 + R_SPI_MEM_DLOCK); >=20 > + for (Index =3D 0; Index < PCH_FLASH_PROTECTED_RANGES; ++Index) { >=20 > + if ((mPchConfigHob->ProtectRange[Index].WriteProtectionEnable || >=20 > + mPchConfigHob->ProtectRange[Index].ReadProtectionEnable) !=3D > TRUE) { >=20 > + continue; >=20 > + } >=20 > + >=20 > + // >=20 > + // Proceed to program the register after ensure it is enabled >=20 > + // >=20 > + Data32 =3D 0; >=20 > + Data32 |=3D (mPchConfigHob->ProtectRange[Index].WriteProtectionEnabl= e > =3D=3D TRUE) ? B_SPI_MEM_PRX_WPE : 0; >=20 > + Data32 |=3D (mPchConfigHob->ProtectRange[Index].ReadProtectionEnable > =3D=3D TRUE) ? B_SPI_MEM_PRX_RPE : 0; >=20 > + Data32 |=3D ((UINT32) mPchConfigHob- > >ProtectRange[Index].ProtectedRangeLimit << N_SPI_MEM_PRX_PRL) & > B_SPI_MEM_PRX_PRL_MASK; >=20 > + Data32 |=3D ((UINT32) mPchConfigHob- > >ProtectRange[Index].ProtectedRangeBase << N_SPI_MEM_PRX_PRB) & > B_SPI_MEM_PRX_PRB_MASK; >=20 > + DEBUG ((DEBUG_INFO, "Protected range %d: 0x%08x \n", Index, > Data32)); >=20 > + >=20 > + DlockValue |=3D (UINT32) (B_SPI_MEM_DLOCK_PR0LOCKDN << Index); >=20 > + MmioWrite32 ((UINTN) (PchSpiBar0 + (R_SPI_MEM_PR0 + (Index * > S_SPI_MEM_PRX))), Data32); >=20 > + S3BootScriptSaveMemWrite ( >=20 > + S3BootScriptWidthUint32, >=20 > + (UINTN) (PchSpiBar0 + (R_SPI_MEM_PR0 + (Index * > S_SPI_MEM_PRX))), >=20 > + 1, >=20 > + (VOID *) (UINTN) (PchSpiBar0 + (R_SPI_MEM_PR0 + (Index * > S_SPI_MEM_PRX))) >=20 > + ); >=20 > + } >=20 > + // >=20 > + // Program DLOCK register >=20 > + // >=20 > + MmioWrite32 ((UINTN) (PchSpiBar0 + R_SPI_MEM_DLOCK), DlockValue); >=20 > + S3BootScriptSaveMemWrite ( >=20 > + S3BootScriptWidthUint32, >=20 > + (UINTN) (PchSpiBar0 + R_SPI_MEM_DLOCK), >=20 > + 1, >=20 > + (VOID *) (UINTN) (PchSpiBar0 + R_SPI_MEM_DLOCK) >=20 > + ); >=20 > + >=20 > + /// >=20 > + /// PCH BIOS Spec Section 3.6 Flash Security Recommendation >=20 > + /// In PCH SPI controller the BIOS should set the Flash Configuration = Lock- > Down bit >=20 > + /// (SPI_BAR0 + 04[15]) at end of post. When set to 1, those Flash Pr= ogram > Registers >=20 > + /// that are locked down by this FLOCKDN bit cannot be written. >=20 > + /// Please refer to the EDS for which program registers are impacted. >=20 > + /// Additionally BIOS must program SPI_BAR0 + 0x04 BIT11 (WRSDIS) to > disable Write Status in HW sequencing >=20 > + /// >=20 > + >=20 > + // >=20 > + // Ensure there is no pending SPI trasaction before setting lock bits >=20 > + // >=20 > + Timer =3D 0; >=20 > + while (MmioRead16 (PchSpiBar0 + R_SPI_MEM_HSFSC) & > B_SPI_MEM_HSFSC_SCIP) { >=20 > + if (Timer > SPI_WAIT_TIME) { >=20 > + // >=20 > + // SPI transaction is pending too long at this point, exit with er= ror. >=20 > + // >=20 > + DEBUG ((DEBUG_ERROR, "SPI Cycle timeout\n")); >=20 > + ASSERT (FALSE); >=20 > + break; >=20 > + } >=20 > + MicroSecondDelay (SPI_WAIT_PERIOD); >=20 > + Timer +=3D SPI_WAIT_PERIOD; >=20 > + } >=20 > + >=20 > + Data16And =3D B_SPI_MEM_HSFSC_SCIP; >=20 > + Data16 =3D 0; >=20 > + S3BootScriptSaveMemPoll ( >=20 > + S3BootScriptWidthUint16, >=20 > + PchSpiBar0 + R_SPI_MEM_HSFSC, >=20 > + &Data16And, >=20 > + &Data16, >=20 > + SPI_WAIT_PERIOD, >=20 > + SPI_WAIT_TIME / SPI_WAIT_PERIOD >=20 > + ); >=20 > + >=20 > + // >=20 > + // Clear any outstanding status >=20 > + // >=20 > + Data16Or =3D B_SPI_MEM_HSFSC_SAF_DLE >=20 > + | B_SPI_MEM_HSFSC_SAF_ERROR >=20 > + | B_SPI_MEM_HSFSC_AEL >=20 > + | B_SPI_MEM_HSFSC_FCERR >=20 > + | B_SPI_MEM_HSFSC_FDONE; >=20 > + Data16And =3D 0xFFFF; >=20 > + MmioAndThenOr16 (PchSpiBar0 + R_SPI_MEM_HSFSC, Data16And, > Data16Or); >=20 > + S3BootScriptSaveMemReadWrite ( >=20 > + S3BootScriptWidthUint16, >=20 > + PchSpiBar0 + R_SPI_MEM_HSFSC, >=20 > + &Data16Or, >=20 > + &Data16And >=20 > + ); >=20 > + >=20 > + // >=20 > + // Set WRSDIS >=20 > + // >=20 > + Data16Or =3D B_SPI_MEM_HSFSC_WRSDIS; >=20 > + Data16And =3D 0xFFFF; >=20 > + MmioAndThenOr16 (PchSpiBar0 + R_SPI_MEM_HSFSC, Data16And, > Data16Or); >=20 > + S3BootScriptSaveMemReadWrite ( >=20 > + S3BootScriptWidthUint16, >=20 > + PchSpiBar0 + R_SPI_MEM_HSFSC, >=20 > + &Data16Or, >=20 > + &Data16And >=20 > + ); >=20 > + >=20 > + // >=20 > + // Set FLOCKDN >=20 > + // >=20 > + Data16Or =3D B_SPI_MEM_HSFSC_FLOCKDN; >=20 > + Data16And =3D 0xFFFF; >=20 > + MmioAndThenOr16 (PchSpiBar0 + R_SPI_MEM_HSFSC, Data16And, > Data16Or); >=20 > + S3BootScriptSaveMemReadWrite ( >=20 > + S3BootScriptWidthUint16, >=20 > + PchSpiBar0 + R_SPI_MEM_HSFSC, >=20 > + &Data16Or, >=20 > + &Data16And >=20 > + ); >=20 > + >=20 > + /// >=20 > + /// SPI Flash Programming Guide Section 5.5.2 Vendor Component Lock >=20 > + /// It is strongly recommended that BIOS sets the Vendor Component Loc= k > (VCL) bits. VCL applies >=20 > + /// the lock to both VSCC0 and VSCC1 even if VSCC0 is not used. Withou= t > the VCL bits set, it is >=20 > + /// possible to make Host/GbE VSCC register(s) changes in that can cau= se > undesired host and >=20 > + /// integrated GbE Serial Flash functionality. >=20 > + /// >=20 > + MmioOr32 ((UINTN) (PchSpiBar0 + R_SPI_MEM_SFDP0_VSCC0), > B_SPI_MEM_SFDP0_VSCC0_VCL); >=20 > + S3BootScriptSaveMemWrite ( >=20 > + S3BootScriptWidthUint32, >=20 > + (UINTN) (PchSpiBar0 + R_SPI_MEM_SFDP0_VSCC0), >=20 > + 1, >=20 > + (VOID *) (UINTN) (PchSpiBar0 + R_SPI_MEM_SFDP0_VSCC0) >=20 > + ); >=20 > +} >=20 > + >=20 > +/** >=20 > + Set HD Audio PME bit >=20 > +**/ >=20 > +VOID >=20 > +ConfigureHdAudioPme ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + UINT64 HdaPciBase; >=20 > + >=20 > + HdaPciBase =3D HdaPciCfgBase (); >=20 > + >=20 > + if (PciSegmentRead16 (HdaPciBase + PCI_VENDOR_ID_OFFSET) =3D=3D 0xFFFF= ) > { >=20 > + return; >=20 > + } >=20 > + >=20 > + /// >=20 > + /// PME Enable for Audio controller >=20 > + /// >=20 > + if (mPchConfigHob->HdAudio.Pme =3D=3D TRUE) { >=20 > + PciSegmentOr32 (HdaPciBase + R_HDA_CFG_PCS, (UINT32) > B_HDA_CFG_PCS_PMEE); >=20 > + } >=20 > +} >=20 > + >=20 > +/** >=20 > + Set eSPI BME bit >=20 > +**/ >=20 > +VOID >=20 > +ConfigureEspiBme ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + UINT64 EspiPciBase; >=20 > + >=20 > + EspiPciBase =3D EspiPciCfgBase (); >=20 > + >=20 > + if (PciSegmentRead16 (EspiPciBase + PCI_VENDOR_ID_OFFSET) =3D=3D 0xFFF= F) > { >=20 > + return; >=20 > + } >=20 > + if ((PciSegmentRead32 (EspiPciBase + R_ESPI_CFG_PCBC) & > B_ESPI_CFG_PCBC_ESPI_EN) =3D=3D 0) { >=20 > + return; >=20 > + } >=20 > + >=20 > + // >=20 > + // Refer to PCH BWG. >=20 > + // To enable eSPI bus mastering BIOS must enable BME in eSPI controlle= r >=20 > + // and also set BME bit in the respective slave devices through > Configuration >=20 > + // and Capabilities register of each slave using Get_Configuration and > Set_Configuration functionality. >=20 > + // >=20 > + // NOTE: The setting is also done in PEI, but might be cleared by PCI = bus > during PCI enumeration. >=20 > + // Therefore, reeable it after PCI enumeration done. >=20 > + // >=20 > + if (mPchConfigHob->Espi.BmeMasterSlaveEnabled =3D=3D TRUE) { >=20 > + PciSegmentOr8 (EspiPciBase + PCI_COMMAND_OFFSET, > EFI_PCI_COMMAND_BUS_MASTER); >=20 > + } >=20 > +} >=20 > diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInit.h > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInit.h > new file mode 100644 > index 0000000000..0d6647e3f3 > --- /dev/null > +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInit.h > @@ -0,0 +1,122 @@ > +/** @file >=20 > + Header file for PCH Initialization Driver. >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > +#ifndef _PCH_INIT_DXE_H_ >=20 > +#define _PCH_INIT_DXE_H_ >=20 > + >=20 > +#include >=20 > +#include >=20 > +#include >=20 > + >=20 > +// >=20 > +// Data definitions >=20 > +// >=20 > +extern EFI_HANDLE mImageHandle; >=20 > + >=20 > +// >=20 > +// Pch NVS area definition >=20 > +// >=20 > +extern PCH_NVS_AREA_PROTOCOL mPchNvsAreaProtocol; >=20 > + >=20 > +extern PCH_CONFIG_HOB *mPchConfigHob; >=20 > +extern SI_CONFIG_HOB_DATA *mSiConfigHobData; >=20 > + >=20 > +// >=20 > +// Function Prototype >=20 > +// >=20 > + >=20 > +// >=20 > +// Local function prototypes >=20 > +// >=20 > +/** >=20 > + Common PchInit Module Entry Point >=20 > +**/ >=20 > +VOID >=20 > +PchInitEntryPointCommon ( >=20 > + VOID >=20 > + ); >=20 > + >=20 > +/** >=20 > + Calls Boot Os Hand off routine for each Serial IO Controller >=20 > +**/ >=20 > +VOID >=20 > +ConfigureSerialIoAtBoot ( >=20 > + VOID >=20 > + ); >=20 > + >=20 > +/** >=20 > + Puts all SerialIo controllers (except UARTs in debug mode) in D3. >=20 > + Clears MemoryEnable for all PCI-mode controllers on S3 resume >=20 > +**/ >=20 > +VOID >=20 > +ConfigureSerialIoAtS3Resume ( >=20 > + VOID >=20 > + ); >=20 > + >=20 > +/** >=20 > + Add Serial Io UART Hidden Handles >=20 > +**/ >=20 > +VOID >=20 > +CreateSerialIoUartHiddenHandle ( >=20 > + VOID >=20 > + ); >=20 > + >=20 > +/** >=20 > + Initialize Intel High Definition Audio ACPI Tables >=20 > + >=20 > + @retval EFI_SUCCESS The function completed successfully >=20 > + @retval EFI_LOAD_ERROR ACPI table cannot be installed >=20 > + @retval EFI_UNSUPPORTED ACPI table not set because DSP is disa= bled >=20 > +**/ >=20 > +EFI_STATUS >=20 > +PchHdAudioAcpiInit ( >=20 > + VOID >=20 > + ); >=20 > + >=20 > +/** >=20 > + Perform the remaining configuration on SATA to perform device detectio= n, >=20 > + then set the SATA SPD and PxE corresponding, and set the Register Lock > on PCH SATA >=20 > +**/ >=20 > +VOID >=20 > +ConfigureSataOnEndOfDxe ( >=20 > + VOID >=20 > + ); >=20 > + >=20 > +/** >=20 > + Update ASL data for CNVI Device. >=20 > + >=20 > + @retval EFI_SUCCESS The function completed successfully >=20 > +**/ >=20 > +EFI_STATUS >=20 > +UpdateCnviAcpiData ( >=20 > + VOID >=20 > + ); >=20 > + >=20 > +/** >=20 > + Initialize Pch acpi >=20 > + @param[in] ImageHandle Handle for the image of this driver >=20 > + >=20 > + @retval EFI_SUCCESS The function completed successfully >=20 > + @retval EFI_OUT_OF_RESOURCES Do not have enough resources to > initialize the driver >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchAcpiInit ( >=20 > + IN EFI_HANDLE ImageHandle >=20 > + ); >=20 > + >=20 > +/** >=20 > + Update ASL object before Boot >=20 > + >=20 > + @retval EFI_STATUS >=20 > + @retval EFI_NOT_READY The Acpi protocols are not ready. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +PchUpdateNvsArea ( >=20 > + VOID >=20 > + ); >=20 > + >=20 > +#endif // _PCH_INIT_DXE_H_ >=20 > diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxe= .c > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxe.c > new file mode 100644 > index 0000000000..1d4f08a86c > --- /dev/null > +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxe.c > @@ -0,0 +1,354 @@ > +/** @file >=20 > + This is the Uefi driver that initializes the Intel PCH. >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > + >=20 > +#include "PchInit.h" >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > + >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_HANDLE mImageHandle; >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 > mPcieIoTrapAddress; >=20 > + >=20 > +VOID >=20 > +EFIAPI >=20 > +PchOnBootToOs ( >=20 > + IN EFI_EVENT Event, >=20 > + IN VOID *Context >=20 > + ); >=20 > + >=20 > + >=20 > +VOID >=20 > +EFIAPI >=20 > +PchOnExitBootServices ( >=20 > + IN EFI_EVENT Event, >=20 > + IN VOID *Context >=20 > + ); >=20 > + >=20 > + >=20 > +VOID >=20 > +EFIAPI >=20 > +PchOnReadyToBoot ( >=20 > + IN EFI_EVENT Event, >=20 > + IN VOID *Context >=20 > + ); >=20 > + >=20 > +/** >=20 > + Process all the lock downs >=20 > +**/ >=20 > +VOID >=20 > +ProcessSmiLocks ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + UINT32 Data32And; >=20 > + UINT32 Data32Or; >=20 > + UINT16 ABase; >=20 > + >=20 > + /// >=20 > + /// PCH BIOS Spec Section 3.6 Flash Security Recommendation >=20 > + /// BIOS needs to enables SMI_LOCK (PMC PCI offset A0h[4] =3D 1b) whic= h > prevent writes >=20 > + /// to the Global SMI Enable bit (GLB_SMI_EN ABASE + 30h[0]). Enabling > this bit will >=20 > + /// mitigate malicious software attempts to gain system management > mode privileges. >=20 > + /// >=20 > + if (mPchConfigHob->LockDown.GlobalSmi =3D=3D TRUE) { >=20 > + /// >=20 > + /// Save Global SMI Enable bit setting before BIOS enables SMI_LOCK > during S3 resume >=20 > + /// >=20 > + ABase =3D PmcGetAcpiBase (); >=20 > + Data32Or =3D IoRead32 ((UINTN) (ABase + R_ACPI_IO_SMI_EN)); >=20 > + if ((Data32Or & B_ACPI_IO_SMI_EN_GBL_SMI) !=3D 0) { >=20 > + Data32And =3D 0xFFFFFFFF; >=20 > + Data32Or |=3D B_ACPI_IO_SMI_EN_GBL_SMI; >=20 > + S3BootScriptSaveIoReadWrite ( >=20 > + S3BootScriptWidthUint32, >=20 > + (UINTN) (ABase + R_ACPI_IO_SMI_EN), >=20 > + &Data32Or, // Data to be ORed >=20 > + &Data32And // Data to be ANDed >=20 > + ); >=20 > + } >=20 > + PmcLockSmiWithS3BootScript (); >=20 > + } >=20 > +} >=20 > + >=20 > +/** >=20 > + Do PCIE power management while resume from S3 >=20 > +**/ >=20 > +VOID >=20 > +ReconfigurePciePowerManagementForS3 ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + UINT32 Data32; >=20 > + PCH_PCIE_IOTRAP_PROTOCOL *PchPcieIoTrapProtocol; >=20 > + >=20 > + Status =3D gBS->LocateProtocol (&gPchPcieIoTrapProtocolGuid, NULL, (VO= ID > **) &PchPcieIoTrapProtocol); >=20 > + if (EFI_ERROR (Status)) { >=20 > + return; >=20 > + } >=20 > + mPcieIoTrapAddress =3D PchPcieIoTrapProtocol->PcieTrapAddress; >=20 > + DEBUG ((DEBUG_INFO, "PcieIoTrapAddress: %0x\n", > mPcieIoTrapAddress)); >=20 > + >=20 > + if (mPcieIoTrapAddress !=3D 0) { >=20 > + // >=20 > + // Save PCH PCIE IoTrap address to re-config PCIE power management > setting after resume from S3 >=20 > + // >=20 > + Data32 =3D PchPciePmTrap; >=20 > + S3BootScriptSaveIoWrite ( >=20 > + S3BootScriptWidthUint32, >=20 > + (UINTN) (mPcieIoTrapAddress), >=20 > + 1, >=20 > + &Data32 >=20 > + ); >=20 > + } else { >=20 > + ASSERT (FALSE); >=20 > + } >=20 > +} >=20 > + >=20 > +/** >=20 > + This is the callback function for PCI ENUMERATION COMPLETE. >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +PchOnPciEnumComplete ( >=20 > + IN EFI_EVENT Event, >=20 > + IN VOID *Context >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + VOID *ProtocolPointer; >=20 > + >=20 > + /// >=20 > + /// Check if this is first time called by EfiCreateProtocolNotifyEvent= () or > not, >=20 > + /// if it is, we will skip it until real event is triggered >=20 > + /// >=20 > + Status =3D gBS->LocateProtocol > (&gEfiPciEnumerationCompleteProtocolGuid, NULL, (VOID **) > &ProtocolPointer); >=20 > + if (EFI_SUCCESS !=3D Status) { >=20 > + return; >=20 > + } >=20 > + gBS->CloseEvent (Event); >=20 > + >=20 > + ReconfigurePciePowerManagementForS3 (); >=20 > + ProcessSmiLocks (); >=20 > + ConfigureSerialIoAtS3Resume (); >=20 > +} >=20 > + >=20 > +/** >=20 > + Register callback functions for PCH DXE. >=20 > +**/ >=20 > +VOID >=20 > +PchRegisterNotifications ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + EFI_EVENT ReadyToBoot; >=20 > + EFI_EVENT LegacyBootEvent; >=20 > + EFI_EVENT ExitBootServicesEvent; >=20 > + VOID *Registration; >=20 > + >=20 > + /// >=20 > + /// Create PCI Enumeration Completed callback for PCH >=20 > + /// >=20 > + EfiCreateProtocolNotifyEvent ( >=20 > + &gEfiPciEnumerationCompleteProtocolGuid, >=20 > + TPL_CALLBACK, >=20 > + PchOnPciEnumComplete, >=20 > + NULL, >=20 > + &Registration >=20 > + ); >=20 > + >=20 > + // >=20 > + // Register a Ready to boot event to config PCIE power management > setting after OPROM executed >=20 > + // >=20 > + Status =3D EfiCreateEventReadyToBootEx ( >=20 > + TPL_CALLBACK, >=20 > + PchOnReadyToBoot, >=20 > + NULL, >=20 > + &ReadyToBoot >=20 > + ); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + // >=20 > + // Create events for PCH to do the task before > ExitBootServices/LegacyBoot. >=20 > + // It is guaranteed that only one of two events below will be signalle= d >=20 > + // >=20 > + Status =3D gBS->CreateEvent ( >=20 > + EVT_SIGNAL_EXIT_BOOT_SERVICES, >=20 > + TPL_CALLBACK, >=20 > + PchOnExitBootServices, >=20 > + NULL, >=20 > + &ExitBootServicesEvent >=20 > + ); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + Status =3D EfiCreateEventLegacyBootEx ( >=20 > + TPL_CALLBACK, >=20 > + PchOnBootToOs, >=20 > + NULL, >=20 > + &LegacyBootEvent >=20 > + ); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > +} >=20 > + >=20 > +/** >=20 > + PchInit DXE Module Entry Point\n >=20 > + - Introduction\n >=20 > + The PchInit module is a DXE driver that initializes the Intel Plat= form > Controller Hub >=20 > + following the PCH BIOS specification and EDS requirements and > recommendations. It consumes >=20 > + the PCH_POLICY_HOB SI_POLICY_HOB for expected configurations per > policy. >=20 > + This is the standard EFI driver point that detects whether there i= s an > supported PCH in >=20 > + the system and if so, initializes the chipset. >=20 > + >=20 > + - Details\n >=20 > + This module is required for initializing the Intel Platform Controll= er Hub to >=20 > + follow the PCH BIOS specification and EDS. >=20 > + This includes some initialization sequences, enabling and disabling = PCH > devices, >=20 > + configuring clock gating, RST PCIe Storage Remapping, SATA controlle= r, > ASPM of PCIE devices. Right before end of DXE, >=20 > + it's responsible to lock down registers for security requirement. >=20 > + >=20 > + - @pre >=20 > + - PCH PCR base address configured >=20 > + - EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL >=20 > + - This is to ensure that PCI MMIO and IO resource has been prepare= d > and available for this driver to allocate. >=20 > + >=20 > + - @result >=20 > + - Publishes the @link _PCH_INFO_PROTOCOL PCH_INFO_PROTOCOL > @endlink >=20 > + - Publishes the @link _PCH_EMMC_TUNING_PROTOCOL > PCH_EMMC_TUNING_PROTOCOL @endlink >=20 > + >=20 > + - References\n >=20 > + - @link _PCH_POLICY PCH_POLICY_HOB @endlink. >=20 > + - @link _SI_POLICY_STRUCT SI_POLICY_HOB @endlink. >=20 > + >=20 > + - Integration Checklists\n >=20 > + - Verify prerequisites are met. Porting Recommendations. >=20 > + - No modification of this module should be necessary >=20 > + - Any modification of this module should follow the PCH BIOS > Specification and EDS >=20 > + >=20 > + @param[in] ImageHandle Handle for the image of this driver >=20 > + @param[in] SystemTable Pointer to the EFI System Table >=20 > + >=20 > + @retval EFI_SUCCESS The function completed successfully >=20 > + @retval EFI_OUT_OF_RESOURCES Do not have enough resources to > initialize the driver >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchInitEntryPointDxe ( >=20 > + IN EFI_HANDLE ImageHandle, >=20 > + IN EFI_SYSTEM_TABLE *SystemTable >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + >=20 > + DEBUG ((DEBUG_INFO, "PchInitEntryPointDxe() Start\n")); >=20 > + >=20 > + mImageHandle =3D ImageHandle; >=20 > + >=20 > + PchInitEntryPointCommon (); >=20 > + >=20 > + Status =3D PchAcpiInit (ImageHandle); >=20 > + >=20 > + PchRegisterNotifications (); >=20 > + >=20 > + CreateSerialIoUartHiddenHandle (); >=20 > + >=20 > + DEBUG ((DEBUG_INFO, "PchInitEntryPointDxe() End\n")); >=20 > + >=20 > + return Status; >=20 > +} >=20 > + >=20 > +/** >=20 > + PCH initialization before ExitBootServices / LegacyBoot events >=20 > + Useful for operations which must happen later than at EndOfPost event >=20 > + >=20 > + @param[in] Event A pointer to the Event that triggered = the > callback. >=20 > + @param[in] Context A pointer to private data registered w= ith the > callback function. >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +PchOnBootToOs ( >=20 > + IN EFI_EVENT Event, >=20 > + IN VOID *Context >=20 > + ) >=20 > +{ >=20 > + /// >=20 > + /// Closed the event to avoid call twice >=20 > + /// >=20 > + if (Event !=3D NULL) { >=20 > + gBS->CloseEvent (Event); >=20 > + } >=20 > + >=20 > + ConfigureSerialIoAtBoot (); >=20 > + >=20 > + return; >=20 > +} >=20 > + >=20 > +/** >=20 > + PCH initialization on ExitBootService. This event is used if only > ExitBootService is used >=20 > + and not in legacy boot >=20 > + >=20 > + @param[in] Event A pointer to the Event that triggered = the > callback. >=20 > + @param[in] Context A pointer to private data registered w= ith the > callback function. >=20 > + >=20 > + @retval None >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +PchOnExitBootServices ( >=20 > + IN EFI_EVENT Event, >=20 > + IN VOID *Context >=20 > + ) >=20 > +{ >=20 > + PchOnBootToOs (NULL, NULL); >=20 > + >=20 > + return; >=20 > +} >=20 > + >=20 > +/** >=20 > + PCH initialization before boot to OS >=20 > + >=20 > + @param[in] Event A pointer to the Event that triggered = the > callback. >=20 > + @param[in] Context A pointer to private data registered w= ith the > callback function. >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +PchOnReadyToBoot ( >=20 > + IN EFI_EVENT Event, >=20 > + IN VOID *Context >=20 > + ) >=20 > +{ >=20 > + DEBUG ((DEBUG_INFO, "Uefi PchOnReadyToBoot() Start\n")); >=20 > + >=20 > + if (Event !=3D NULL) { >=20 > + gBS->CloseEvent (Event); >=20 > + } >=20 > + >=20 > + // >=20 > + // Trigger an Iotrap SMI to config PCIE power management setting after > PCI enumrate is done >=20 > + // >=20 > + if (mPcieIoTrapAddress !=3D 0) { >=20 > + IoWrite32 ((UINTN) mPcieIoTrapAddress, PchPciePmTrap); >=20 > + } else { >=20 > + ASSERT (FALSE); >=20 > + } >=20 > + >=20 > + DEBUG ((DEBUG_INFO, "Uefi PchOnReadyToBoot() End\n")); >=20 > +} >=20 > + >=20 > diff --git > a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxeTgl.inf > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxeTgl.inf > new file mode 100644 > index 0000000000..4941ff0f49 > --- /dev/null > +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxeTgl.inf > @@ -0,0 +1,96 @@ > +## @file >=20 > +# Component description file for Pch Initialization driver >=20 > +# >=20 > +# Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > +# SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +# >=20 > +## >=20 > + >=20 > + >=20 > +[Defines] >=20 > +INF_VERSION =3D 0x00010017 >=20 > +BASE_NAME =3D PchInitDxeTgl >=20 > +FILE_GUID =3D 4BD0EB2F-3A2D-442E-822D-753516F75424 >=20 > +VERSION_STRING =3D 1.0 >=20 > +MODULE_TYPE =3D DXE_DRIVER >=20 > +ENTRY_POINT =3D PchInitEntryPointDxe >=20 > + >=20 > + >=20 > +[LibraryClasses] >=20 > +S3BootScriptLib >=20 > +PchCycleDecodingLib >=20 > +PchPcieRpLib >=20 > +PchPcrLib >=20 > +PchInfoLib >=20 > +PciExpressHelpersLib >=20 > +UefiBootServicesTableLib >=20 > +DebugLib >=20 > +IoLib >=20 > +TimerLib >=20 > +HobLib >=20 > +BaseMemoryLib >=20 > +MemoryAllocationLib >=20 > +UefiLib >=20 > +DxeServicesTableLib >=20 > +UefiDriverEntryPoint >=20 > +UefiRuntimeServicesTableLib >=20 > +GpioLib >=20 > +SerialIoAccessLib >=20 > +ConfigBlockLib >=20 > +PmcLib >=20 > +PmcPrivateLibWithS3 >=20 > +SataLib >=20 > +PchDmiWithS3Lib >=20 > +GbeLib >=20 > +SiScheduleResetLib >=20 > +DxeHdaNhltLib >=20 > +SpiAccessPrivateLib >=20 > +PchPciBdfLib >=20 > + >=20 > +[Packages] >=20 > +MdePkg/MdePkg.dec >=20 > +TigerlakeSiliconPkg/SiPkg.dec >=20 > + >=20 > + >=20 > +[Pcd] >=20 > +gSiPkgTokenSpaceGuid.PcdSiPciExpressBaseAddress >=20 > +gSiPkgTokenSpaceGuid.PcdSiliconInitTempMemBaseAddr ## CONSUMES >=20 > +gSiPkgTokenSpaceGuid.PcdEmbeddedEnable ## CONSUMES >=20 > + >=20 > +[Sources] >=20 > +PchInitDxe.c >=20 > +PchInit.h >=20 > +PchInit.c >=20 > +PchSata.c >=20 > +PchSerialIo.c >=20 > +PchSerialIoDxe.c >=20 > +PchHdaAcpi.c >=20 > +PchCnviAcpi.c >=20 > +PchAcpi.c >=20 > + >=20 > + >=20 > +[Protocols] >=20 > +gPchNvsAreaProtocolGuid ## PRODUCES >=20 > +gEfiPciIoProtocolGuid ## CONSUMES >=20 > +gEfiAcpiTableProtocolGuid ## CONSUMES >=20 > +gEfiBlockIoProtocolGuid ## CONSUMES >=20 > +gHeciProtocolGuid >=20 > +gEfiPciEnumerationCompleteProtocolGuid ## CONSUMES >=20 > +gPchPcieIoTrapProtocolGuid ## CONSUMES >=20 > +gPchPolicyProtocolGuid ## CONSUMES >=20 > + >=20 > + >=20 > +[Guids] >=20 > +gEfiEndOfDxeEventGroupGuid >=20 > +gEfiAcpiTableGuid >=20 > +gEmmcDxeConfigGuid ## CONSUMES >=20 > +gSiConfigHobGuid ## CONSUMES >=20 > +gPchConfigHobGuid ## CONSUMES >=20 > +gPchRstHobGuid ## CONSUMES >=20 > +gHdAudioDxeConfigGuid ## CONSUMES >=20 > +gGpioDxeConfigGuid ## CONSUMES >=20 > +gCnviConfigHobGuid ## CONSUMES >=20 > +gHybridStorageHobGuid ## CONSUMES >=20 > + >=20 > +[Depex] >=20 > +gEfiPciHostBridgeResourceAllocationProtocolGuid ## This is to ensure tha= t > PCI MMIO and IO resource has been prepared and available for this driver = to > allocate. >=20 > diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSata.c > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSata.c > new file mode 100644 > index 0000000000..886f3b4bc0 > --- /dev/null > +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSata.c > @@ -0,0 +1,89 @@ > +/** @file >=20 > + Perform related functions for PCH Sata in DXE phase >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > + >=20 > +#include >=20 > +#include >=20 > +#include >=20 > + >=20 > +#include "PchInit.h" >=20 > +#include >=20 > +#include >=20 > +#include >=20 > + >=20 > +/** >=20 > + Perform the remaining configuration on SATA to perform device detectio= n, >=20 > + then set the SATA SPD and PxE corresponding, and set the Register Lock > on PCH SATA >=20 > + >=20 > + @retval None >=20 > +**/ >=20 > +VOID >=20 > +ConfigureSataOnEndOfDxe ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + UINT64 PciSataRegBase; >=20 > + UINT16 SataPortsEnabled; >=20 > + UINT32 DwordReg; >=20 > + UINTN Index; >=20 > + UINT32 SataCtrlIndex; >=20 > + >=20 > + for (SataCtrlIndex =3D 0; SataCtrlIndex < MaxSataControllerNum (); > SataCtrlIndex++) { >=20 > + /// >=20 > + /// SATA PCS: Enable the port in any of below condition: >=20 > + /// i.) Hot plug is enabled >=20 > + /// ii.) A device is attached >=20 > + /// iii.) Test mode is enabled >=20 > + /// iv.) Configured as eSATA port >=20 > + /// >=20 > + PciSataRegBase =3D SataPciCfgBase (SataCtrlIndex); >=20 > + SataPortsEnabled =3D 0; >=20 > + >=20 > + DwordReg =3D PciSegmentRead32 (PciSataRegBase + R_SATA_CFG_PCS); >=20 > + for (Index =3D 0; Index < MaxSataPortNum (SataCtrlIndex); Index++) { >=20 > + if ((mPchConfigHob->Sata[SataCtrlIndex].PortSettings[Index].HotPlu= g > =3D=3D TRUE) || >=20 > + (DwordReg & (B_SATA_CFG_PCS_P0P << Index)) || >=20 > + (mPchConfigHob->Sata[SataCtrlIndex].TestMode =3D=3D TRUE) || >=20 > + (mPchConfigHob->Sata[SataCtrlIndex].PortSettings[Index].Exte= rnal > =3D=3D TRUE)) { >=20 > + SataPortsEnabled |=3D (mPchConfigHob- > >Sata[SataCtrlIndex].PortSettings[Index].Enable << Index); >=20 > + } >=20 > + } >=20 > + >=20 > + /// >=20 > + /// Set MAP."Sata PortX Disable", SATA PCI offset 90h[23:16] to 1b i= f SATA > Port 0/1/2/3/4/5/6/7 is disabled >=20 > + /// >=20 > + PciSegmentOr32 (PciSataRegBase + R_SATA_CFG_MAP, > (~SataPortsEnabled << N_SATA_CFG_MAP_SPD)); >=20 > + S3BootScriptSaveMemWrite ( >=20 > + S3BootScriptWidthUint32, >=20 > + PcdGet64 (PcdSiPciExpressBaseAddress) + PciSataRegBase + > R_SATA_CFG_MAP, >=20 > + 1, >=20 > + (VOID *) (UINTN) (PcdGet64 (PcdSiPciExpressBaseAddress) + > PciSataRegBase + R_SATA_CFG_MAP) >=20 > + ); >=20 > + >=20 > + /// >=20 > + /// Program PCS "Port X Enabled", SATA PCI offset 94h[7:0] =3D Port = 0~7 > Enabled bit as per SataPortsEnabled value. >=20 > + /// >=20 > + PciSegmentOr16 (PciSataRegBase + R_SATA_CFG_PCS, > SataPortsEnabled); >=20 > + S3BootScriptSaveMemWrite ( >=20 > + S3BootScriptWidthUint16, >=20 > + PcdGet64 (PcdSiPciExpressBaseAddress) + PciSataRegBase + > R_SATA_CFG_PCS, >=20 > + 1, >=20 > + (VOID *) (UINTN) (PcdGet64 (PcdSiPciExpressBaseAddress) + > PciSataRegBase + R_SATA_CFG_PCS) >=20 > + ); >=20 > + >=20 > + /// >=20 > + /// Step 14 >=20 > + /// Program SATA PCI offset 9Ch [31] to 1b >=20 > + /// >=20 > + PciSegmentOr32 ((UINTN) (PciSataRegBase + R_SATA_CFG_SATAGC), > BIT31); >=20 > + S3BootScriptSaveMemWrite ( >=20 > + S3BootScriptWidthUint32, >=20 > + PcdGet64 (PcdSiPciExpressBaseAddress) + PciSataRegBase + > R_SATA_CFG_SATAGC, >=20 > + 1, >=20 > + (VOID *) (UINTN) (PcdGet64 (PcdSiPciExpressBaseAddress) + > PciSataRegBase + R_SATA_CFG_SATAGC) >=20 > + ); >=20 > + } >=20 > +} >=20 > diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSerialI= o.c > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIo.c > new file mode 100644 > index 0000000000..9409a9a387 > --- /dev/null > +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIo.c > @@ -0,0 +1,33 @@ > +/** @file >=20 > + Initializes Serial IO Controllers. >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > +#include "PchInit.h" >=20 > +#include >=20 > +#include >=20 > + >=20 > +/** >=20 > + Calls Boot Os Hand off routine for each Serial IO Controller >=20 > +**/ >=20 > +VOID >=20 > +ConfigureSerialIoAtBoot ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + UINT8 Index; >=20 > + >=20 > + for (Index =3D 0; Index < GetPchMaxSerialIoSpiControllersNum (); Index= ++) { >=20 > + SerialIoSpiBootHandler (Index, &mPchConfigHob- > >SerialIo.SpiDeviceConfig[Index]); >=20 > + } >=20 > + >=20 > + for (Index =3D 0; Index < GetPchMaxSerialIoI2cControllersNum (); Index= ++) { >=20 > + SerialIoI2cBootHandler (Index, &mPchConfigHob- > >SerialIo.I2cDeviceConfig[Index]); >=20 > + } >=20 > + >=20 > + for (Index =3D 0; Index < GetPchMaxSerialIoUartControllersNum (); Inde= x++) > { >=20 > + SerialIoUartBootHandler (Index, &mPchConfigHob- > >SerialIo.UartDeviceConfig[Index]); >=20 > + } >=20 > +} >=20 > + >=20 > diff --git > a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIoDxe.c > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIoDxe.c > new file mode 100644 > index 0000000000..fde7da6b96 > --- /dev/null > +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIoDxe.c > @@ -0,0 +1,134 @@ > +/** @file >=20 > + Initializes Serial IO Controllers. >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > + >=20 > +typedef struct { >=20 > + ACPI_HID_DEVICE_PATH RootPort; >=20 > + ACPI_EXTENDED_HID_DEVICE_PATH AcpiDev; >=20 > + CHAR8 HidString[8]; >=20 > + UINT16 DeviceId; >=20 > + UINT8 UartIndex; >=20 > + EFI_DEVICE_PATH_PROTOCOL End; >=20 > +} SERIALIO_UART_DEVICE_PATH; >=20 > + >=20 > +#define mPciRootBridge {{ACPI_DEVICE_PATH, ACPI_DP, {(UINT8)(sizeof > (ACPI_HID_DEVICE_PATH)), 0}}, EISA_PNP_ID (0x0A03), 0} >=20 > +#define mAcpiDev {{ACPI_DEVICE_PATH, ACPI_EXTENDED_DP, > {(UINT8)(sizeof (ACPI_EXTENDED_HID_DEVICE_PATH) + (sizeof(CHAR8) * 8) > + sizeof (UINT16) + sizeof (UINT8)), 0}},0,0,0} >=20 > +#define mEndEntire {END_DEVICE_PATH_TYPE, > END_ENTIRE_DEVICE_PATH_SUBTYPE, {END_DEVICE_PATH_LENGTH, 0}} >=20 > + >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED SERIALIO_UART_DEVICE_PATH > mSerialIoUartPath =3D { >=20 > + mPciRootBridge, >=20 > + mAcpiDev, >=20 > + "UART\0\0\0", >=20 > + 0xFFFF, >=20 > + 0xFF, >=20 > + mEndEntire >=20 > +}; >=20 > + >=20 > +/** >=20 > + Add Serial Io UART Hidden Handles >=20 > +**/ >=20 > +VOID >=20 > +CreateSerialIoUartHiddenHandle ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + EFI_HANDLE NewHandle; >=20 > + EFI_DEVICE_PATH_PROTOCOL *NewPath; >=20 > + EFI_STATUS Status; >=20 > + UINT8 Index; >=20 > + UINT16 DeviceId; >=20 > + >=20 > + DEBUG ((DEBUG_INFO, "CreateSerialIoUartHandle\n")); >=20 > + >=20 > + for (Index =3D 0; Index < GetPchMaxSerialIoUartControllersNum (); Inde= x++) > { >=20 > + DEBUG ((DEBUG_INFO, "UART Index: %d Mode: %d\n", Index, > mPchConfigHob->SerialIo.UartDeviceConfig[Index].Mode)); >=20 > + if (mPchConfigHob->SerialIo.UartDeviceConfig[Index].Mode =3D=3D > SerialIoUartHidden) { >=20 > + NewHandle =3D NULL; >=20 > + DeviceId =3D MmioRead16 (GetSerialIoUartFixedPciCfgAddress (Index)= + > PCI_DEVICE_ID_OFFSET); >=20 > + DEBUG ((DEBUG_INFO, "Creating Handle for UART DEVICE_ID: 0x%X \n", > DeviceId)); >=20 > + mSerialIoUartPath.AcpiDev.HID =3D 0x5432 + (Index << 16); //UAR >=20 > + mSerialIoUartPath.HidString[4] =3D (CHAR8)('0' + Index); >=20 > + mSerialIoUartPath.DeviceId =3D DeviceId; >=20 > + mSerialIoUartPath.UartIndex =3D Index; >=20 > + NewPath =3D DuplicateDevicePath ((EFI_DEVICE_PATH_PROTOCOL*) > &mSerialIoUartPath); >=20 > + Status =3D gBS->InstallMultipleProtocolInterfaces ( >=20 > + &NewHandle, >=20 > + &gEfiDevicePathProtocolGuid, >=20 > + NewPath, >=20 > + NULL >=20 > + ); >=20 > + DEBUG ((DEBUG_INFO, "CreateSerialIoUartHandle Status: %r\n", > Status)); >=20 > + } >=20 > + } >=20 > +} >=20 > + >=20 > +/** >=20 > + Stores Pme Control Status and Command register values in S3 Boot Scrip= t >=20 > + >=20 > + @param[in] S3PciCfgBase S3 Boot Script Pci Config Base >=20 > + @param[in] Command Pci Command register data to save >=20 > + @param[in] Pme Pci Pme Control register data to save >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +STATIC >=20 > +SerialIoS3Save ( >=20 > + IN UINTN S3PciCfgBase, >=20 > + IN UINTN Command, >=20 > + IN UINTN Pme >=20 > + ) >=20 > +{ >=20 > + if (S3PciCfgBase !=3D 0) { >=20 > + S3BootScriptSavePciCfgWrite (S3BootScriptWidthUint32, S3PciCfgBase + > R_SERIAL_IO_CFG_PME_CTRL_STS, 1, &Pme); >=20 > + S3BootScriptSavePciCfgWrite (S3BootScriptWidthUint32, S3PciCfgBase + > PCI_COMMAND_OFFSET, 1, &Command); >=20 > + } >=20 > +} >=20 > + >=20 > +/** >=20 > + Puts all SerialIo controllers (except UARTs in debug mode) in D3. >=20 > + Clears MemoryEnable for all PCI-mode controllers on S3 resume >=20 > +**/ >=20 > +VOID >=20 > +ConfigureSerialIoAtS3Resume ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + UINT8 Index; >=20 > + UINTN S3PciCfgBase; >=20 > + UINT32 Command; >=20 > + UINT32 Pme; >=20 > + >=20 > + S3PciCfgBase =3D 0; >=20 > + for (Index =3D 0; Index < GetPchMaxSerialIoSpiControllersNum (); Index= ++) { >=20 > + SerialIoSpiS3Handler (Index, &mPchConfigHob- > >SerialIo.SpiDeviceConfig[Index], &S3PciCfgBase, &Command, &Pme); >=20 > + SerialIoS3Save (S3PciCfgBase, Command, Pme); >=20 > + } >=20 > + >=20 > + S3PciCfgBase =3D 0; >=20 > + for (Index =3D 0; Index < GetPchMaxSerialIoI2cControllersNum (); Index= ++) { >=20 > + SerialIoI2cS3Handler (Index, &mPchConfigHob- > >SerialIo.I2cDeviceConfig[Index], &S3PciCfgBase, &Command, &Pme); >=20 > + SerialIoS3Save (S3PciCfgBase, Command, Pme); >=20 > + } >=20 > + >=20 > + S3PciCfgBase =3D 0; >=20 > + for (Index =3D 0; Index < GetPchMaxSerialIoUartControllersNum (); Inde= x++) > { >=20 > + SerialIoUartS3Handler (Index, &mPchConfigHob- > >SerialIo.UartDeviceConfig[Index], &S3PciCfgBase, &Command, &Pme); >=20 > + SerialIoS3Save (S3PciCfgBase, Command, Pme); >=20 > + } >=20 > +} >=20 > + >=20 > diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/GbeSxSmm.c > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/GbeSxSmm.c > new file mode 100644 > index 0000000000..786ce13915 > --- /dev/null > +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/GbeSxSmm.c > @@ -0,0 +1,266 @@ > +/** @file >=20 > + Gbe Sx handler implementation. >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > + >=20 > +#include >=20 > +#include "PchInitSmm.h" >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > + >=20 > + >=20 > +/** >=20 > + Configure WOL during Sx entry. >=20 > + >=20 > + @param [in] GbeBar GbE MMIO space >=20 > +**/ >=20 > +VOID >=20 > +GbeWolWorkaround ( >=20 > + IN UINT32 GbeBar >=20 > + ) >=20 > +{ >=20 > + UINT32 RAL0; >=20 > + UINT32 RAH0; >=20 > + UINT16 WUC; >=20 > + EFI_STATUS Status; >=20 > + UINT16 Data16; >=20 > + >=20 > + // >=20 > + // 1. Set page to 769 Port Control Registers >=20 > + // 2. Wait 4 mSec >=20 > + // >=20 > + Status =3D GbeMdiSetPage (GbeBar, > PHY_MDI_PAGE_769_PORT_CONTROL_REGISTERS); >=20 > + if (EFI_ERROR (Status)) return; >=20 > + >=20 > + // >=20 > + // 3. Set registry to 17 Port General Configuration >=20 > + // 4. Copy all settings from Port General Configuration >=20 > + // >=20 > + Status =3D GbeMdiRead (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, > MDI_REG_SHIFT (R_PHY_MDI_PAGE_769_REGISETER_17_PGC), &Data16); >=20 > + if (EFI_ERROR (Status)) return; >=20 > + >=20 > + // >=20 > + // 5. Modify BIT 4 and BIT 2 to disable host wake up and set MACPD >=20 > + // >=20 > + Status =3D GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, > MDI_REG_SHIFT (R_PHY_MDI_PAGE_769_REGISETER_17_PGC), (Data16 | > B_PHY_MDI_PAGE_769_REGISETER_17_PGC_MACPD_ENABLE) & > (~B_PHY_MDI_PAGE_769_REGISETER_17_PGC_HOST_WAKE_UP)); >=20 > + if (EFI_ERROR (Status)) return; >=20 > + >=20 > + // >=20 > + // 6. Read Receive Address Low and Receive Address High from MMIO >=20 > + // >=20 > + RAL0 =3D MmioRead32 (GbeBar + R_GBE_MEM_CSR_RAL); >=20 > + RAH0 =3D MmioRead32 (GbeBar + R_GBE_MEM_CSR_RAH); >=20 > + >=20 > + // >=20 > + // 7. Set page to 800 Wake Up Registers >=20 > + // 8. Wait 4 mSec >=20 > + // >=20 > + Status =3D GbeMdiSetPage (GbeBar, > PHY_MDI_PAGE_800_WAKE_UP_REGISTERS); >=20 > + if (EFI_ERROR (Status)) return; >=20 > + >=20 > + // >=20 > + // 9. Set registry to 16 Receive Address Low 1/2 >=20 > + // >=20 > + Status =3D GbeMdiSetRegister (GbeBar, > R_PHY_MDI_PAGE_800_REGISETER_16_RAL0); >=20 > + if (EFI_ERROR (Status)) return; >=20 > + >=20 > + // >=20 > + // 10. Program first 16 bits [0:15] out of 48 in Receive Address Low 1= /2 >=20 > + // >=20 > + Status =3D GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, > R_PHY_MDI_PHY_REG_DATA_READ_WRITE, (RAL0 & 0xFFFF)); >=20 > + if (EFI_ERROR (Status)) return; >=20 > + >=20 > + // >=20 > + // 11. Set registry to 17 Receive Address Low 2/2 >=20 > + // >=20 > + Status =3D GbeMdiSetRegister (GbeBar, > R_PHY_MDI_PAGE_800_REGISETER_17_RAL1); >=20 > + if (EFI_ERROR (Status)) return; >=20 > + >=20 > + // >=20 > + // 12. Program second 16 bits [16:31] out of 48 in Receive Address Low= 2/2 >=20 > + // >=20 > + Status =3D GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, > R_PHY_MDI_PHY_REG_DATA_READ_WRITE, (RAL0 >> 16)); >=20 > + if (EFI_ERROR (Status)) return; >=20 > + >=20 > + // >=20 > + // 13. Set registry to 18 Receive Address High 1/2 >=20 > + // >=20 > + Status =3D GbeMdiSetRegister (GbeBar, > R_PHY_MDI_PAGE_800_REGISETER_18_RAH0); >=20 > + if (EFI_ERROR (Status)) return; >=20 > + >=20 > + // >=20 > + // 14. Program last 16 bits [32:47] out of 48 >=20 > + // >=20 > + Status =3D GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, > R_PHY_MDI_PHY_REG_DATA_READ_WRITE, (RAH0 & > B_GBE_MEM_CSR_RAH_RAH)); >=20 > + if (EFI_ERROR (Status)) return; >=20 > + >=20 > + // >=20 > + // 15. Set registry to 19 Receive Address High 2/2 >=20 > + // >=20 > + Status =3D GbeMdiSetRegister (GbeBar, > R_PHY_MDI_PAGE_800_REGISETER_19_RAH1); >=20 > + if (EFI_ERROR (Status)) return; >=20 > + >=20 > + // >=20 > + // 16. Set Address Valid >=20 > + // >=20 > + Status =3D GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, > R_PHY_MDI_PHY_REG_DATA_READ_WRITE, > B_PHY_MDI_PAGE_800_REGISETER_19_RAH1_ADDRESS_VALID); >=20 > + if (EFI_ERROR (Status)) return; >=20 > + >=20 > + // >=20 > + // 17. Set Wake Up Control Register 1 >=20 > + // >=20 > + Status =3D GbeMdiSetRegister (GbeBar, > R_PHY_MDI_PAGE_800_REGISETER_1_WUC); >=20 > + if (EFI_ERROR (Status)) return; >=20 > + >=20 > + // >=20 > + // 18. Copy WakeUp Control from MAC MMIO >=20 > + // >=20 > + WUC =3D (UINT16) MmioRead32 (GbeBar + R_GBE_MEM_CSR_WUC); >=20 > + >=20 > + // >=20 > + // 19. Store WakeUp Contorl into LCD >=20 > + // Modify APME bit to enable APM wake up >=20 > + // >=20 > + Status =3D GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, > R_PHY_MDI_PHY_REG_DATA_READ_WRITE, (WUC & 0xFFFF)); >=20 > + if (EFI_ERROR (Status)) return; >=20 > + >=20 > + // >=20 > + // 20. Set page to 803 Host Wol Packet >=20 > + // 21. Wait 4 mSec >=20 > + // >=20 > + Status =3D GbeMdiSetPage (GbeBar, > PHY_MDI_PAGE_803_HOST_WOL_PACKET); >=20 > + if (EFI_ERROR (Status)) return; >=20 > + >=20 > + // >=20 > + // 22. Set registry to 66 Host WoL Packet Clear >=20 > + // >=20 > + Status =3D GbeMdiSetRegister (GbeBar, > R_PHY_MDI_PAGE_803_REGISETER_66_HWPC); >=20 > + if (EFI_ERROR (Status)) return; >=20 > + >=20 > + // >=20 > + // 23. Clear WOL Packet >=20 > + // >=20 > + Status =3D GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, > R_PHY_MDI_PHY_REG_DATA_READ_WRITE, 0); >=20 > + if (EFI_ERROR (Status)) return; >=20 > + // >=20 > + // 24. Set page to 769 Port Control Registers >=20 > + // 25. Wait 4 mSec >=20 > + // >=20 > + Status =3D GbeMdiSetPage (GbeBar, > PHY_MDI_PAGE_769_PORT_CONTROL_REGISTERS); >=20 > + if (EFI_ERROR (Status)) return; >=20 > + >=20 > + // >=20 > + // 26. Set registry to 17 Port General Configuration >=20 > + // >=20 > + Status =3D GbeMdiSetRegister (GbeBar, > R_PHY_MDI_PAGE_769_REGISETER_17_PGC); >=20 > + if (EFI_ERROR (Status)) return; >=20 > + >=20 > + // >=20 > + // 27. Copy all settings from Port General Configuration >=20 > + // >=20 > + Status =3D GbeMdiRead (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, > MDI_REG_SHIFT (R_PHY_MDI_PAGE_769_REGISETER_17_PGC), &Data16); >=20 > + if (EFI_ERROR (Status)) return; >=20 > + >=20 > + // >=20 > + // 28. Modify BIT 4 and BIT 2 to enable host wake up and clear MACPD >=20 > + // >=20 > + Status =3D GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01, > MDI_REG_SHIFT (R_PHY_MDI_PAGE_769_REGISETER_17_PGC), (Data16 | > B_PHY_MDI_PAGE_769_REGISETER_17_PGC_HOST_WAKE_UP) & > (~B_PHY_MDI_PAGE_769_REGISETER_17_PGC_MACPD_ENABLE)); >=20 > + if (EFI_ERROR (Status)) return; >=20 > +} >=20 > + >=20 > +/** >=20 > + Additional Internal GbE Controller special cases WOL Support. >=20 > + >=20 > + System BIOS is required perform additional steps upon S0 to S3,4,5 > transition >=20 > + when ME is off and GbE device in D0. This is needed to enable LAN wake >=20 > + in particular when platform is shut-down from EFI. >=20 > +**/ >=20 > +VOID >=20 > +GbeSxWorkaround ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + UINT64 LanRegBase; >=20 > + UINT32 GbeBar; >=20 > + EFI_STATUS Status; >=20 > + >=20 > + LanRegBase =3D GbePciCfgBase (); >=20 > + >=20 > + if (PciSegmentRead16 (LanRegBase + PCI_VENDOR_ID_OFFSET) =3D=3D > 0xFFFF) { >=20 > + return; >=20 > + } >=20 > + >=20 > + // >=20 > + // Check if GbE device is in D0 >=20 > + // >=20 > + if ((PciSegmentRead16 (LanRegBase + R_GBE_CFG_PMCS) & > B_GBE_CFG_PMCS_PS) !=3D V_GBE_CFG_PMCS_PS0) { >=20 > + return; >=20 > + } >=20 > + >=20 > + ASSERT (mResvMmioSize >=3D (1 << N_GBE_CFG_MBARA_ALIGN)); >=20 > + GbeBar =3D (UINT32) mResvMmioBaseAddr; >=20 > + if (GbeBar =3D=3D 0) { >=20 > + ASSERT (FALSE); >=20 > + return; >=20 > + } >=20 > + >=20 > + // >=20 > + // Enable MMIO decode using reserved range. >=20 > + // >=20 > + PciSegmentAnd16 (LanRegBase + PCI_COMMAND_OFFSET, (UINT16) > ~EFI_PCI_COMMAND_MEMORY_SPACE); >=20 > + PciSegmentWrite32 (LanRegBase + R_GBE_CFG_MBARA, GbeBar); >=20 > + PciSegmentOr16 (LanRegBase + PCI_COMMAND_OFFSET, > EFI_PCI_COMMAND_MEMORY_SPACE); >=20 > + >=20 > + // >=20 > + // If MBARA offset 5800h [0] =3D 1b then proceed with the w/a >=20 > + // >=20 > + if (MmioRead32 (GbeBar + R_GBE_MEM_CSR_WUC) & > B_GBE_MEM_CSR_WUC_APME) { >=20 > + Status =3D GbeMdiAcquireMdio (GbeBar); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + if (!EFI_ERROR (Status)) { >=20 > + GbeWolWorkaround (GbeBar); >=20 > + GbeMdiReleaseMdio (GbeBar); >=20 > + } >=20 > + } >=20 > + >=20 > + // >=20 > + // Disable MMIO decode. >=20 > + // >=20 > + PciSegmentAnd16 (LanRegBase + PCI_COMMAND_OFFSET, (UINT16) > ~EFI_PCI_COMMAND_MEMORY_SPACE); >=20 > + PciSegmentWrite32 (LanRegBase + R_GBE_CFG_MBARA, 0); >=20 > +} >=20 > + >=20 > +/** >=20 > + Enable platform wake from LAN when in DeepSx if platform supports it. >=20 > + Called upon Sx entry. >=20 > +**/ >=20 > +VOID >=20 > +GbeConfigureDeepSxWake ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + if (PmcIsLanDeepSxWakeEnabled ()) { >=20 > + IoOr32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_GPE0_EN_127_96), > (UINT32) B_ACPI_IO_GPE0_EN_127_96_LAN_WAKE); >=20 > + } >=20 > +} >=20 > + >=20 > +/** >=20 > + GbE Sx entry handler >=20 > +**/ >=20 > +VOID >=20 > +PchLanSxCallback ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + if (IsGbeEnabled ()) { >=20 > + GbeSxWorkaround (); >=20 > + GbeConfigureDeepSxWake (); >=20 > + >=20 > + } >=20 > +} >=20 > diff --git > a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchBiosWriteProtect.c > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchBiosWriteProtect.c > new file mode 100644 > index 0000000000..f435af434a > --- /dev/null > +++ > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchBiosWriteProtect.c > @@ -0,0 +1,137 @@ > +/** @file >=20 > + PCH BIOS Write Protect Driver. >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > +#include "PchInitSmm.h" >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > + >=20 > +// >=20 > +// Global variables >=20 > +// >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED > PCH_TCO_SMI_DISPATCH_PROTOCOL *mPchTcoSmiDispatchProtocol; >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED > PCH_ESPI_SMI_DISPATCH_PROTOCOL *mEspiSmmDispatchProtocol; >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED UINT64 mLpcRegB= ase; >=20 > + >=20 > +/** >=20 > + This hardware SMI handler will be run every time the BIOS Write Enable= bit > is set. >=20 > + >=20 > + @param[in] DispatchHandle Not used >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +PchSpiBiosWpCallback ( >=20 > + IN EFI_HANDLE DispatchHandle >=20 > + ) >=20 > +{ >=20 > + SpiClearBiosWriteProtectDisable (); >=20 > +} >=20 > + >=20 > +/** >=20 > + This hardware SMI handler will be run every time the BIOS Write Enable= bit > is set. >=20 > + >=20 > + @param[in] DispatchHandle Not used >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +PchLpcBiosWpCallback ( >=20 > + IN EFI_HANDLE DispatchHandle >=20 > + ) >=20 > +{ >=20 > + // >=20 > + // Disable BIOSWE bit to protect BIOS >=20 > + // >=20 > + PciSegmentAnd8 ((UINTN) (mLpcRegBase + R_LPC_CFG_BC), (UINT8) > ~B_LPC_CFG_BC_WPD); >=20 > +} >=20 > + >=20 > +/** >=20 > + Entry point for Pch Bios Write Protect driver. >=20 > + >=20 > + @param[in] ImageHandle Image handle of this driver. >=20 > + @param[in] SystemTable Global system service table. >=20 > + >=20 > + @retval EFI_SUCCESS Initialization complete. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +InstallPchBiosWriteProtect ( >=20 > + IN EFI_HANDLE ImageHandle, >=20 > + IN EFI_SYSTEM_TABLE *SystemTable >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + EFI_HANDLE Handle; >=20 > + >=20 > + DEBUG ((DEBUG_INFO, "InstallPchBiosWriteProtect()\n")); >=20 > + >=20 > + if (mPchConfigHob->LockDown.BiosLock !=3D TRUE) { >=20 > + return EFI_SUCCESS; >=20 > + } >=20 > + >=20 > + mLpcRegBase =3D LpcPciCfgBase (); >=20 > + >=20 > + DEBUG ((DEBUG_INFO, "Installing BIOS Write Protect SMI handler\n")); >=20 > + // >=20 > + // Get the PCH TCO SMM dispatch protocol >=20 > + // >=20 > + mPchTcoSmiDispatchProtocol =3D NULL; >=20 > + Status =3D gSmst->SmmLocateProtocol (&gPchTcoSmiDispatchProtocolGuid, > NULL, (VOID **) &mPchTcoSmiDispatchProtocol); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + // >=20 > + // Always register an SPI BiosWp callback function to handle TCO BIOSW= R > SMI >=20 > + // NOTE: No matter the BIOS resides behind SPI or not, it needs to han= dle > the SPI BIOS WP SMI >=20 > + // to avoid SMI deadloop on SPI WPD write. >=20 > + // >=20 > + Handle =3D NULL; >=20 > + Status =3D mPchTcoSmiDispatchProtocol->SpiBiosWpRegister ( >=20 > + mPchTcoSmiDispatchProtocol, >=20 > + PchSpiBiosWpCallback, >=20 > + &Handle >=20 > + ); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + // >=20 > + // Always register an LPC/eSPI BiosWp callback function to handle TCO > BIOSWR SMI >=20 > + // NOTE: No matter the BIOS resides behind LPC/eSPI or not, it needs t= o > handle the BIOS WP SMI >=20 > + // to avoid SMI deadloop on LPC/eSPI WPD write. >=20 > + // >=20 > + if (IsEspiEnabled ()) { >=20 > + // >=20 > + // Get the PCH ESPI SMM dispatch protocol >=20 > + // >=20 > + mEspiSmmDispatchProtocol =3D NULL; >=20 > + Status =3D gSmst->SmmLocateProtocol > (&gPchEspiSmiDispatchProtocolGuid, NULL, (VOID **) > &mEspiSmmDispatchProtocol); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + // >=20 > + // Register an ESpiBiosWp callback function to handle BIOSWR SMI >=20 > + // >=20 > + Handle =3D NULL; >=20 > + Status =3D mEspiSmmDispatchProtocol->BiosWrProtectRegister ( >=20 > + mEspiSmmDispatchProtocol, >=20 > + PchLpcBiosWpCallback, >=20 > + &Handle >=20 > + ); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + } else { >=20 > + // >=20 > + // Register an LPC BiosWp callback function to handle TCO BIOSWR SMI >=20 > + // >=20 > + Handle =3D NULL; >=20 > + Status =3D mPchTcoSmiDispatchProtocol->LpcBiosWpRegister ( >=20 > + mPchTcoSmiDispatchProtocol, >=20 > + PchLpcBiosWpCallback, >=20 > + &Handle >=20 > + ); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + } >=20 > + >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > + >=20 > diff --git > a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchHdaSxSmm.c > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchHdaSxSmm.c > new file mode 100644 > index 0000000000..f3d11ab204 > --- /dev/null > +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchHdaSxSmm.c > @@ -0,0 +1,33 @@ > +/** @file >=20 > + PCH HD Audio Sx handler implementation. >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > + >=20 > +#include "PchInitSmm.h" >=20 > +#include >=20 > +#include >=20 > +#include >=20 > + >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED UINT64 mHdaPciBase; >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN > mHdaCodecSxWakeCapability =3D FALSE; >=20 > + >=20 > +/** >=20 > + Updates Codec Sx Wake Capability setting: disabled/enabled >=20 > +**/ >=20 > +VOID >=20 > +UpdateHdaCodecSxWakeCapabilitySetting ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + mHdaPciBase =3D HdaPciCfgBase (); >=20 > + >=20 > + if ((mPchConfigHob->HdAudio.CodecSxWakeCapability =3D=3D FALSE) || >=20 > + (PciSegmentRead16 (mHdaPciBase + PCI_VENDOR_ID_OFFSET) =3D=3D > 0xFFFF)) { >=20 > + mHdaCodecSxWakeCapability =3D FALSE; >=20 > + } else { >=20 > + mHdaCodecSxWakeCapability =3D TRUE; >=20 > + } >=20 > +} >=20 > + >=20 > diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm= .c > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.c > new file mode 100644 > index 0000000000..9c2475e3a1 > --- /dev/null > +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.c > @@ -0,0 +1,285 @@ > +/** @file >=20 > + PCH Init Smm module for PCH specific SMI handlers. >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > +#include "PchInitSmm.h" >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > + >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED > EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL *mPchIoTrap; >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED > EFI_SMM_SX_DISPATCH2_PROTOCOL *mSxDispatch; >=20 > + >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED PCH_NVS_AREA > *mPchNvsArea; >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 > mAcpiBaseAddr; >=20 > + >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED FIVR_EXT_RAIL_CONFIG > mFivrExtVnnRailSxConfig; >=20 > + >=20 > +// >=20 > +// NOTE: The module variables of policy here are only valid in post time= , but > not runtime time. >=20 > +// >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED PCH_CONFIG_HOB > *mPchConfigHob; >=20 > + >=20 > +// >=20 > +// The reserved MMIO range to be used in Sx handler >=20 > +// >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_PHYSICAL_ADDRESS > mResvMmioBaseAddr; >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED UINTN > mResvMmioSize; >=20 > + >=20 > +/** >=20 > + SMBUS Sx entry SMI handler. >=20 > +**/ >=20 > +VOID >=20 > +SmbusSxCallback ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + UINT64 SmbusRegBase; >=20 > + UINT16 SmbusIoBase; >=20 > + >=20 > + SmbusRegBase =3D SmbusPciCfgBase (); >=20 > + >=20 > + if (PciSegmentRead32 (SmbusRegBase) =3D=3D 0xFFFFFFFF) { >=20 > + return; >=20 > + } >=20 > + >=20 > + SmbusIoBase =3D PciSegmentRead16 (SmbusRegBase + > R_SMBUS_CFG_BASE) & B_SMBUS_CFG_BASE_BAR; >=20 > + if (SmbusIoBase =3D=3D 0) { >=20 > + return; >=20 > + } >=20 > + >=20 > + PciSegmentOr8 (SmbusRegBase + PCI_COMMAND_OFFSET, > EFI_PCI_COMMAND_IO_SPACE); >=20 > + // >=20 > + // Clear SMBUS status and SMB_WAK_STS of GPE0 >=20 > + // >=20 > + IoWrite8 (SmbusIoBase + R_SMBUS_IO_HSTS, > B_SMBUS_IO_SMBALERT_STS); >=20 > + IoWrite32 (mAcpiBaseAddr + R_ACPI_IO_GPE0_STS_127_96, > B_ACPI_IO_GPE0_STS_127_96_SMB_WAK); >=20 > +} >=20 > + >=20 > +/* >=20 > + PCH xHCI Sx entry SMI handler >=20 > +*/ >=20 > +VOID >=20 > +PchXhciSxCallback ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + UINTN XhciPciBase; >=20 > + >=20 > + XhciPciBase =3D PchXhciPciCfgBase (); >=20 > + >=20 > + // >=20 > + // Safety check for xHCI existense >=20 > + // >=20 > + if (PciSegmentRead32 (XhciPciBase) =3D=3D 0xFFFFFFFF) { >=20 > + return; >=20 > + } >=20 > + >=20 > + // >=20 > + // If xHCI is in D0 that means OS didn't put it to D3 during Sx entry = i.e. USB > kernel debug is enabled. >=20 > + // Unless it is put manually to D3, USB wake functionality will not wo= rk. >=20 > + // >=20 > + if ((PciSegmentRead8 (XhciPciBase + R_XHCI_CFG_PWR_CNTL_STS) & > V_XHCI_CFG_PWR_CNTL_STS_PWR_STS_D3) =3D=3D 0) { >=20 > + // >=20 > + // Put device to D3 to enable wake functionality for USB devices >=20 > + // >=20 > + PciSegmentOr8 (XhciPciBase + R_XHCI_CFG_PWR_CNTL_STS, > (UINT8)(B_XHCI_CFG_PWR_CNTL_STS_PWR_STS)); >=20 > + } >=20 > +} >=20 > + >=20 > +/** >=20 > + Cache PCH FIVR policy. >=20 > +**/ >=20 > +VOID >=20 > +UpdatePchFivrSettings ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + CopyMem ( >=20 > + &mFivrExtVnnRailSxConfig, >=20 > + &mPchConfigHob->Fivr.ExtVnnRailSx, >=20 > + sizeof (mFivrExtVnnRailSxConfig) >=20 > + ); >=20 > +} >=20 > + >=20 > +/** >=20 > + PCH Sx entry SMI handler. >=20 > + >=20 > + @param[in] Handle Handle of the callback >=20 > + @param[in] Context The dispatch context >=20 > + @param[in,out] CommBuffer A pointer to a collection of data in > memory that will >=20 > + be conveyed from a non-SMM environment = into an SMM > environment. >=20 > + @param[in,out] CommBufferSize The size of the CommBuffer. >=20 > + >=20 > + @retval EFI_SUCCESS >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchSxHandler ( >=20 > + IN EFI_HANDLE Handle, >=20 > + IN CONST VOID *Context OPTIONAL, >=20 > + IN OUT VOID *CommBuffer OPTIONAL, >=20 > + IN OUT UINTN *CommBufferSize OPTIONAL >=20 > + ) >=20 > +{ >=20 > + PchLanSxCallback (); >=20 > + PchXhciSxCallback (); >=20 > + >=20 > + SmbusSxCallback (); >=20 > + >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > + >=20 > +/** >=20 > + Initialize PCH Sx entry SMI handler. >=20 > + >=20 > + @param[in] ImageHandle - Handle for the image of this driver >=20 > +**/ >=20 > +VOID >=20 > +InitializeSxHandler ( >=20 > + IN EFI_HANDLE ImageHandle >=20 > + ) >=20 > +{ >=20 > + EFI_SMM_SX_REGISTER_CONTEXT SxDispatchContext; >=20 > + EFI_HANDLE SxDispatchHandle; >=20 > + EFI_SLEEP_TYPE SxType; >=20 > + EFI_STATUS Status; >=20 > + >=20 > + DEBUG ((DEBUG_INFO, "InitializeSxHandler() Start\n")); >=20 > + >=20 > + // >=20 > + // Register the callback for S3/S4/S5 entry >=20 > + // >=20 > + SxDispatchContext.Phase =3D SxEntry; >=20 > + for (SxType =3D SxS3; SxType <=3D SxS5; SxType++) { >=20 > + SxDispatchContext.Type =3D SxType; >=20 > + Status =3D mSxDispatch->Register ( >=20 > + mSxDispatch, >=20 > + PchSxHandler, >=20 > + &SxDispatchContext, >=20 > + &SxDispatchHandle >=20 > + ); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + } >=20 > + >=20 > + DEBUG ((DEBUG_INFO, "InitializeSxHandler() End\n")); >=20 > +} >=20 > + >=20 > +/** >=20 > + Allocates reserved MMIO for Sx SMI handler use. >=20 > +**/ >=20 > +VOID >=20 > +AllocateReservedMmio ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + mResvMmioBaseAddr =3D PcdGet32 (PcdSiliconInitTempMemBaseAddr); >=20 > + mResvMmioSize =3D PcdGet32 (PcdSiliconInitTempMemSize); >=20 > + DEBUG ((DEBUG_INFO, "mResvMmioBaseAddr %x, mResvMmioSize > %x\n", mResvMmioBaseAddr, mResvMmioSize)); >=20 > +} >=20 > + >=20 > +/** >=20 > + Initializes the PCH SMM handler for for PCIE hot plug support >=20 > + PchInit SMM Module Entry Point\n >=20 > + - Introduction\n >=20 > + The PchInitSmm module is a SMM driver that initializes the Intel P= latform > Controller Hub >=20 > + SMM requirements and services. It consumes the PCH_POLICY_HOB and > SI_POLICY_HOB for expected >=20 > + configurations per policy. >=20 > + >=20 > + - Details\n >=20 > + This module provides SMI handlers to services PCIE HotPlug SMI, > LinkActive SMI, and LinkEq SMI. >=20 > + And also provides port 0x61 emulation support, registers BIOS WP han= dler > to process BIOSWP status, >=20 > + and registers SPI Async SMI handler to handler SPI Async SMI. >=20 > + This module also registers Sx SMI callback function to detail with G= PIO Sx > Isolation and LAN requirement. >=20 > + >=20 > + - @pre >=20 > + - PCH PCR base address configured >=20 > + - EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL >=20 > + - This is to ensure that PCI MMIO and IO resource has been prepare= d > and available for this driver to allocate. >=20 > + - EFI_SMM_BASE2_PROTOCOL >=20 > + - EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL >=20 > + - EFI_SMM_SX_DISPATCH2_PROTOCOL >=20 > + - EFI_SMM_CPU_PROTOCOL >=20 > + - @link _PCH_SMM_IO_TRAP_CONTROL_PROTOCOL > PCH_SMM_IO_TRAP_CONTROL_PROTOCOL @endlink >=20 > + - @link _PCH_SMI_DISPATCH_PROTOCOL > PCH_SMI_DISPATCH_PROTOCOL @endlink >=20 > + - @link _PCH_PCIE_SMI_DISPATCH_PROTOCOL > PCH_PCIE_SMI_DISPATCH_PROTOCOL @endlink >=20 > + - @link _PCH_TCO_SMI_DISPATCH_PROTOCOL > PCH_TCO_SMI_DISPATCH_PROTOCOL @endlink >=20 > + - @link _PCH_ESPI_SMI_DISPATCH_PROTOCOL > PCH_ESPI_SMI_DISPATCH_PROTOCOL @endlink >=20 > + >=20 > + - References\n >=20 > + - @link _PCH_POLICY PCH_POLICY_HOB @endlink. >=20 > + - @link _SI_POLICY_STRUCT SI_POLICY_HOB @endlink. >=20 > + >=20 > + - Integration Checklists\n >=20 > + - Verify prerequisites are met. Porting Recommendations. >=20 > + - No modification of this module should be necessary >=20 > + - Any modification of this module should follow the PCH BIOS > Specification and EDS >=20 > + >=20 > + @param[in] ImageHandle - Handle for the image of this driver >=20 > + @param[in] SystemTable - Pointer to the EFI System Table >=20 > + >=20 > + @retval EFI_SUCCESS - PCH SMM handler was installed >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchInitSmmEntryPoint ( >=20 > + IN EFI_HANDLE ImageHandle, >=20 > + IN EFI_SYSTEM_TABLE *SystemTable >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + PCH_NVS_AREA_PROTOCOL *PchNvsAreaProtocol; >=20 > + EFI_PEI_HOB_POINTERS HobPtr; >=20 > + >=20 > + DEBUG ((DEBUG_INFO, "PchInitSmmEntryPoint()\n")); >=20 > + >=20 > + Status =3D gSmst->SmmLocateProtocol ( >=20 > + &gEfiSmmIoTrapDispatch2ProtocolGuid, >=20 > + NULL, >=20 > + (VOID **) &mPchIoTrap >=20 > + ); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + Status =3D gSmst->SmmLocateProtocol ( >=20 > + &gEfiSmmSxDispatch2ProtocolGuid, >=20 > + NULL, >=20 > + (VOID**) &mSxDispatch >=20 > + ); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + Status =3D gBS->LocateProtocol (&gPchNvsAreaProtocolGuid, NULL, (VOID > **) &PchNvsAreaProtocol); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + mPchNvsArea =3D PchNvsAreaProtocol->Area; >=20 > + >=20 > + // >=20 > + // Get PCH Data HOB. >=20 > + // >=20 > + HobPtr.Guid =3D GetFirstGuidHob (&gPchConfigHobGuid); >=20 > + ASSERT (HobPtr.Guid !=3D NULL); >=20 > + mPchConfigHob =3D (PCH_CONFIG_HOB *) GET_GUID_HOB_DATA > (HobPtr.Guid); >=20 > + >=20 > + mAcpiBaseAddr =3D PmcGetAcpiBase (); >=20 > + >=20 > + AllocateReservedMmio (); >=20 > + >=20 > + InitializeSxHandler (ImageHandle); >=20 > + >=20 > + Status =3D InitializePchPcieSmm (ImageHandle, SystemTable); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + Status =3D InstallPchBiosWriteProtect (ImageHandle, SystemTable); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + Status =3D InstallPchSpiAsyncSmiHandler (); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + UpdateHdaCodecSxWakeCapabilitySetting (); >=20 > + >=20 > + UpdatePchFivrSettings (); >=20 > + >=20 > + >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm= .h > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.h > new file mode 100644 > index 0000000000..c2a09acd11 > --- /dev/null > +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.h > @@ -0,0 +1,254 @@ > +/** @file >=20 > + Header file for PCH Init SMM Handler >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > + >=20 > +#ifndef _PCH_INIT_SMM_H_ >=20 > +#define _PCH_INIT_SMM_H_ >=20 > + >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > + >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > + >=20 > +extern EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL *mPchIoTrap; >=20 > +extern EFI_SMM_SX_DISPATCH2_PROTOCOL *mSxDispatch; >=20 > + >=20 > +extern PCH_NVS_AREA *mPchNvsArea; >=20 > +extern UINT16 mAcpiBaseAddr; >=20 > + >=20 > +extern EFI_PHYSICAL_ADDRESS mResvMmioBaseAddr; >=20 > +extern UINTN mResvMmioSize; >=20 > + >=20 > +// >=20 > +// NOTE: The module variables of policy here are only valid in post time= , but > not runtime time. >=20 > +// >=20 > +extern PCH_CONFIG_HOB *mPchConfigHob; >=20 > +extern SI_CONFIG_HOB_DATA *mSiConfigHobData; >=20 > + >=20 > +/** >=20 > + Register PCIE Hotplug SMI dispatch function to handle Hotplug enabling >=20 > + >=20 > + @param[in] ImageHandle The image handle of this module >=20 > + @param[in] SystemTable The EFI System Table >=20 > + >=20 > + @retval EFI_SUCCESS The function completes successfully >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +InitializePchPcieSmm ( >=20 > + IN EFI_HANDLE ImageHandle, >=20 > + IN EFI_SYSTEM_TABLE *SystemTable >=20 > + ); >=20 > + >=20 > +/** >=20 > + Program Common Clock and ASPM of Downstream Devices >=20 > + >=20 > + @param[in] PortIndex Pcie Root Port Number >=20 > + @param[in] RpDevice Pcie Root Pci Device Number >=20 > + @param[in] RpFunction Pcie Root Pci Function Number >=20 > + >=20 > + @retval EFI_SUCCESS Root port complete successfully >=20 > + @retval EFI_UNSUPPORTED PMC has invalid vendor ID >=20 > +**/ >=20 > +EFI_STATUS >=20 > +PchPcieSmi ( >=20 > + IN UINT8 PortIndex, >=20 > + IN UINT8 RpDevice, >=20 > + IN UINT8 RpFunction >=20 > + ); >=20 > + >=20 > +/** >=20 > + PCIE Hotplug SMI call back function for each Root port >=20 > + >=20 > + @param[in] DispatchHandle Handle of this dispatch function >=20 > + @param[in] RpContext Rootport context, which contains= RootPort > Index, >=20 > + and RootPort PCI BDF. >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +PchPcieSmiRpHandlerFunction ( >=20 > + IN EFI_HANDLE DispatchHandle, >=20 > + IN PCH_PCIE_SMI_RP_CONTEXT *RpContext >=20 > + ); >=20 > + >=20 > +/** >=20 > + PCIE Link Active State Change Hotplug SMI call back function for all R= oot > ports >=20 > + >=20 > + @param[in] DispatchHandle Handle of this dispatch function >=20 > + @param[in] RpContext Rootport context, which contains= RootPort > Index, >=20 > + and RootPort PCI BDF. >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +PchPcieLinkActiveStateChange ( >=20 > + IN EFI_HANDLE DispatchHandle, >=20 > + IN PCH_PCIE_SMI_RP_CONTEXT *RpContext >=20 > + ); >=20 > + >=20 > +/** >=20 > + PCIE Link Equalization Request SMI call back function for all Root por= ts >=20 > + >=20 > + @param[in] DispatchHandle Handle of this dispatch function >=20 > + @param[in] RpContext Rootport context, which contains= RootPort > Index, >=20 > + and RootPort PCI BDF. >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +PchPcieLinkEqHandlerFunction ( >=20 > + IN EFI_HANDLE DispatchHandle, >=20 > + IN PCH_PCIE_SMI_RP_CONTEXT *RpContext >=20 > + ); >=20 > + >=20 > +/** >=20 > + An IoTrap callback to config PCIE power management settings >=20 > + >=20 > + @param[in] DispatchHandle - The handle of this callback, obtained whe= n > registering >=20 > + @param[in] DispatchContext - Pointer to the > EFI_SMM_IO_TRAP_DISPATCH_CALLBACK_CONTEXT >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +PchPcieIoTrapSmiCallback ( >=20 > + IN EFI_HANDLE DispatchHandle, >=20 > + IN EFI_SMM_IO_TRAP_CONTEXT *CallbackContext, >=20 > + IN OUT VOID *CommBuffer, >=20 > + IN OUT UINTN *CommBufferSize >=20 > + ); >=20 > + >=20 > +/** >=20 > + Initializes the PCH SMM handler for PCH save and restore >=20 > + >=20 > + @param[in] ImageHandle - Handle for the image of this driver >=20 > + @param[in] SystemTable - Pointer to the EFI System Table >=20 > + >=20 > + @retval EFI_SUCCESS - PCH SMM handler was installed >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchInitLateSmm ( >=20 > + IN EFI_HANDLE ImageHandle, >=20 > + IN EFI_SYSTEM_TABLE *SystemTable >=20 > + ); >=20 > + >=20 > +/** >=20 > + Initialize PCH Sx entry SMI handler. >=20 > + >=20 > + @param[in] ImageHandle - Handle for the image of this driver >=20 > +**/ >=20 > +VOID >=20 > +InitializeSxHandler ( >=20 > + IN EFI_HANDLE ImageHandle >=20 > + ); >=20 > + >=20 > +/** >=20 > + PCH Sx entry SMI handler. >=20 > + >=20 > + @param[in] Handle Handle of the callback >=20 > + @param[in] Context The dispatch context >=20 > + @param[in,out] CommBuffer A pointer to a collection of data in > memory that will >=20 > + be conveyed from a non-SMM environment = into an SMM > environment. >=20 > + @param[in,out] CommBufferSize The size of the CommBuffer. >=20 > + >=20 > + @retval EFI_SUCCESS >=20 > +**/ >=20 > + >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchSxHandler ( >=20 > + IN EFI_HANDLE Handle, >=20 > + IN CONST VOID *Context OPTIONAL, >=20 > + IN OUT VOID *CommBuffer OPTIONAL, >=20 > + IN OUT UINTN *CommBufferSize OPTIONAL >=20 > + ); >=20 > + >=20 > +/** >=20 > + GbE Sx entry handler >=20 > +**/ >=20 > +VOID >=20 > +PchLanSxCallback ( >=20 > + VOID >=20 > + ); >=20 > + >=20 > +/** >=20 > + Updates Codec Sx Wake Capability setting: disabled/enabled >=20 > +**/ >=20 > +VOID >=20 > +UpdateHdaCodecSxWakeCapabilitySetting ( >=20 > + VOID >=20 > + ); >=20 > + >=20 > +/** >=20 > + Register dispatch function to handle GPIO pads Sx isolation >=20 > +**/ >=20 > +VOID >=20 > +InitializeGpioSxIsolationSmm ( >=20 > + VOID >=20 > + ); >=20 > + >=20 > +/** >=20 > + Entry point for Pch Bios Write Protect driver. >=20 > + >=20 > + @param[in] ImageHandle Image handle of this driver. >=20 > + @param[in] SystemTable Global system service table. >=20 > + >=20 > + @retval EFI_SUCCESS Initialization complete. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +InstallPchBiosWriteProtect ( >=20 > + IN EFI_HANDLE ImageHandle, >=20 > + IN EFI_SYSTEM_TABLE *SystemTable >=20 > + ); >=20 > + >=20 > +/** >=20 > + This fuction install SPI ASYNC SMI handler. >=20 > + >=20 > + @retval EFI_SUCCESS Initialization complete. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +InstallPchSpiAsyncSmiHandler ( >=20 > + VOID >=20 > + ); >=20 > + >=20 > + >=20 > + >=20 > + >=20 > + >=20 > +#endif >=20 > diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm= .inf > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.inf > new file mode 100644 > index 0000000000..aaf36a7b2a > --- /dev/null > +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.inf > @@ -0,0 +1,110 @@ > +## @file >=20 > +# Component description file for PchInitSmm driver >=20 > +# >=20 > +# Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > +# SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +# >=20 > +## >=20 > + >=20 > + >=20 > +[Defines] >=20 > +INF_VERSION =3D 0x00010017 >=20 > +BASE_NAME =3D PchInitSmm >=20 > +FILE_GUID =3D D7B10D4E-67E6-4C74-83E9-F9AF0ACC33CC >=20 > +VERSION_STRING =3D 1.0 >=20 > +MODULE_TYPE =3D DXE_SMM_DRIVER >=20 > +PI_SPECIFICATION_VERSION =3D 1.10 >=20 > +ENTRY_POINT =3D PchInitSmmEntryPoint >=20 > +# >=20 > +# The following information is for reference only and not required by th= e > build tools. >=20 > +# >=20 > +# VALID_ARCHITECTURES =3D IA32 X64 >=20 > +# >=20 > + >=20 > + >=20 > +[LibraryClasses] >=20 > +UefiBootServicesTableLib >=20 > +UefiDriverEntryPoint >=20 > +DxeServicesTableLib >=20 > +IoLib >=20 > +DebugLib >=20 > +BaseLib >=20 > +BaseMemoryLib >=20 > +S3BootScriptLib >=20 > +PciExpressHelpersLib >=20 > +SmmServicesTableLib >=20 > +PciSegmentLib >=20 > +HobLib >=20 > +GpioLib >=20 > +GpioPrivateLib >=20 > +ReportStatusCodeLib >=20 > +DevicePathLib >=20 > +PmcLib >=20 > +PchPcieRpLib >=20 > +PchInfoLib >=20 > +EspiLib >=20 > +TimerLib >=20 > +ConfigBlockLib >=20 > +PmcPrivateLib >=20 > +SataLib >=20 > +GbeLib >=20 > +GbeMdiLib >=20 > +SpiAccessPrivateLib >=20 > +PchPciBdfLib >=20 > + >=20 > +[Packages] >=20 > +MdePkg/MdePkg.dec >=20 > +TigerlakeSiliconPkg/SiPkg.dec >=20 > + >=20 > + >=20 > +[Pcd] >=20 > +gSiPkgTokenSpaceGuid.PcdSiPciExpressBaseAddress >=20 > +gSiPkgTokenSpaceGuid.PcdSiliconInitTempPciBusMin >=20 > +gSiPkgTokenSpaceGuid.PcdSiliconInitTempPciBusMax >=20 > +gSiPkgTokenSpaceGuid.PcdSiliconInitTempMemBaseAddr >=20 > +gSiPkgTokenSpaceGuid.PcdSiliconInitTempMemSize >=20 > + >=20 > + >=20 > +[Sources] >=20 > +PchInitSmm.c >=20 > +PchPcieSmm.c >=20 > +GbeSxSmm.c >=20 > +PchInitSmm.h >=20 > +PchBiosWriteProtect.c >=20 > +PchSpiAsync.c >=20 > +PchHdaSxSmm.c >=20 > + >=20 > + >=20 > +[Protocols] >=20 > +gEfiSmmIoTrapDispatch2ProtocolGuid ## CONSUMES >=20 > +gEfiSmmSxDispatch2ProtocolGuid ## CONSUMES >=20 > +gPchSmmIoTrapControlGuid ## CONSUMES >=20 > +gEfiSmmCpuProtocolGuid ## CONSUMES >=20 > +gPchNvsAreaProtocolGuid ## CONSUMES >=20 > +gPchPcieSmiDispatchProtocolGuid ## CONSUMES >=20 > +gPchTcoSmiDispatchProtocolGuid ## CONSUMES >=20 > +gPchSmiDispatchProtocolGuid ## CONSUMES >=20 > +gPchEspiSmiDispatchProtocolGuid ## CONSUMES >=20 > +gPchPcieIoTrapProtocolGuid ## PRODUCES >=20 > +gPchPolicyProtocolGuid ##CONSUMES >=20 > + >=20 > + >=20 > +[Guids] >=20 > +gSiConfigHobGuid ## CONSUMES >=20 > +gPchConfigHobGuid ## CONSUMES >=20 > +gPchDeviceTableHobGuid >=20 > +gPchPcieRpDxeConfigGuid ## CONSUMES >=20 > + >=20 > + >=20 > +[Depex] >=20 > +gEfiSmmIoTrapDispatch2ProtocolGuid AND >=20 > +gEfiSmmSxDispatch2ProtocolGuid AND >=20 > +gPchSmmIoTrapControlGuid AND >=20 > +gPchPcieSmiDispatchProtocolGuid AND >=20 > +gPchTcoSmiDispatchProtocolGuid AND >=20 > +gEfiSmmCpuProtocolGuid AND >=20 > +gPchNvsAreaProtocolGuid AND >=20 > +gEfiPciHostBridgeResourceAllocationProtocolGuid AND # This is to ensure > that PCI MMIO resource has been prepared and available for this driver to > allocate. >=20 > +gEfiSmmBase2ProtocolGuid AND # This is for SmmServicesTableLib >=20 > +gPchPolicyProtocolGuid >=20 > + >=20 > diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchPcieSmm= .c > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchPcieSmm.c > new file mode 100644 > index 0000000000..e885a342a7 > --- /dev/null > +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchPcieSmm.c > @@ -0,0 +1,451 @@ > +/** @file >=20 > + PCH Pcie SMM Driver Entry >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > +#include "PchInitSmm.h" >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > + >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED PCH_PCIE_DEVICE_OVERRIDE > *mDevAspmOverride; >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED UINT32 > mNumOfDevAspmOverride; >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED UINT8 > mPchBusNumber; >=20 > +// >=20 > +// @note: >=20 > +// These temp bus numbers cannot be used in runtime (hot-plug). >=20 > +// These can be used only during boot. >=20 > +// >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED UINT8 > mTempRootPortBusNumMin; >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED UINT8 > mTempRootPortBusNumMax; >=20 > + >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED PCH_PCIE_ROOT_PORT_CONFIG > mPcieRootPortConfig[PCH_MAX_PCIE_ROOT_PORTS]; >=20 > + >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN > mPchPciePmTrapExecuted =3D FALSE; >=20 > + >=20 > +extern EFI_GUID gPchDeviceTableHobGuid; >=20 > + >=20 > +/** >=20 > + Program Common Clock and ASPM of Downstream Devices >=20 > + >=20 > + @param[in] PortIndex Pcie Root Port Number >=20 > + @param[in] RpDevice Pcie Root Pci Device Number >=20 > + @param[in] RpFunction Pcie Root Pci Function Number >=20 > + >=20 > + @retval EFI_SUCCESS Root port complete successfully >=20 > + @retval EFI_UNSUPPORTED PMC has invalid vendor ID >=20 > +**/ >=20 > +EFI_STATUS >=20 > +PchPcieSmi ( >=20 > + IN UINT8 PortIndex, >=20 > + IN UINT8 RpDevice, >=20 > + IN UINT8 RpFunction >=20 > + ) >=20 > +{ >=20 > + UINT8 SecBus; >=20 > + UINT8 SubBus; >=20 > + UINT64 RpBase; >=20 > + UINT64 EpBase; >=20 > + UINT8 EpPcieCapPtr; >=20 > + UINT8 EpMaxSpeed; >=20 > + BOOLEAN DownstreamDevicePresent; >=20 > + UINT32 Timeout; >=20 > + >=20 > + RpBase =3D PCI_SEGMENT_LIB_ADDRESS ( >=20 > + DEFAULT_PCI_SEGMENT_NUMBER_PCH, >=20 > + mPchBusNumber, >=20 > + (UINT32) RpDevice, >=20 > + (UINT32) RpFunction, >=20 > + 0 >=20 > + ); >=20 > + >=20 > + if (PciSegmentRead16 (RpBase + PCI_VENDOR_ID_OFFSET) =3D=3D 0xFFFF) { >=20 > + return EFI_SUCCESS; >=20 > + } >=20 > + // >=20 > + // Check presence detect state. Here the endpoint must be detected usi= ng > PDS rather than >=20 > + // the usual LinkActive check, because PDS changes immediately and LA > takes a few milliseconds to stabilize >=20 > + // >=20 > + DownstreamDevicePresent =3D !!(PciSegmentRead16 (RpBase + > R_PCH_PCIE_CFG_SLSTS) & B_PCIE_SLSTS_PDS); >=20 > + >=20 > + if (DownstreamDevicePresent) { >=20 > + /// >=20 > + /// Make sure the link is active before trying to talk to device beh= ind it >=20 > + /// Wait up to 100ms, according to PCIE spec chapter 6.7.3.3 >=20 > + /// >=20 > + Timeout =3D 100 * 1000; >=20 > + while ((PciSegmentRead16 (RpBase + R_PCH_PCIE_CFG_LSTS) & > B_PCIE_LSTS_LA) =3D=3D 0 ) { >=20 > + MicroSecondDelay (10); >=20 > + Timeout-=3D10; >=20 > + if (Timeout =3D=3D 0) { >=20 > + return EFI_NOT_FOUND; >=20 > + } >=20 > + } >=20 > + SecBus =3D PciSegmentRead8 (RpBase + > PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET); >=20 > + SubBus =3D PciSegmentRead8 (RpBase + > PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET); >=20 > + ASSERT (SecBus !=3D 0 && SubBus !=3D 0); >=20 > + RootportDownstreamConfiguration ( >=20 > + DEFAULT_PCI_SEGMENT_NUMBER_PCH, >=20 > + DEFAULT_PCI_BUS_NUMBER_PCH, >=20 > + RpDevice, >=20 > + RpFunction, >=20 > + mTempRootPortBusNumMin, >=20 > + mTempRootPortBusNumMax, >=20 > + EnumPchPcie >=20 > + ); >=20 > + RootportDownstreamPmConfiguration ( >=20 > + DEFAULT_PCI_SEGMENT_NUMBER_PCH, >=20 > + DEFAULT_PCI_BUS_NUMBER_PCH, >=20 > + RpDevice, >=20 > + RpFunction, >=20 > + mTempRootPortBusNumMin, >=20 > + mTempRootPortBusNumMax, >=20 > + &mPcieRootPortConfig[PortIndex].PcieRpCommonConfig, >=20 > + mNumOfDevAspmOverride, >=20 > + mDevAspmOverride >=20 > + ); >=20 > + // >=20 > + // Perform Equalization >=20 > + // >=20 > + EpBase =3D PCI_SEGMENT_LIB_ADDRESS > (DEFAULT_PCI_SEGMENT_NUMBER_PCH, SecBus, 0, 0, 0); >=20 > + EpPcieCapPtr =3D PcieFindCapId (DEFAULT_PCI_SEGMENT_NUMBER_PCH, > SecBus, 0, 0, EFI_PCI_CAPABILITY_ID_PCIEXP); >=20 > + EpMaxSpeed =3D PciSegmentRead8 (EpBase + EpPcieCapPtr + > R_PCIE_LCAP_OFFSET) & B_PCIE_LCAP_MLS; >=20 > + if (EpMaxSpeed >=3D 3) { >=20 > + PciSegmentOr32 (RpBase + R_PCH_PCIE_CFG_EX_LCTL3, > B_PCIE_EX_LCTL3_PE); >=20 > + PciSegmentOr32 (RpBase + R_PCH_PCIE_CFG_LCTL, B_PCIE_LCTL_RL); >=20 > + } >=20 > + } >=20 > + >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > + >=20 > +/** >=20 > + PCIE Hotplug SMI call back function for each Root port >=20 > + >=20 > + @param[in] DispatchHandle Handle of this dispatch function >=20 > + @param[in] RpContext Rootport context, which contains= RootPort > Index, >=20 > + and RootPort PCI BDF. >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +PchPcieSmiRpHandlerFunction ( >=20 > + IN EFI_HANDLE DispatchHandle, >=20 > + IN PCH_PCIE_SMI_RP_CONTEXT *RpContext >=20 > + ) >=20 > +{ >=20 > + PchPcieSmi (RpContext->RpIndex, RpContext->DevNum, RpContext- > >FuncNum); >=20 > +} >=20 > + >=20 > +/** >=20 > + PCIE Link Active State Change Hotplug SMI call back function for all R= oot > ports >=20 > + >=20 > + @param[in] DispatchHandle Handle of this dispatch function >=20 > + @param[in] RpContext Rootport context, which contains= RootPort > Index, >=20 > + and RootPort PCI BDF. >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +PchPcieLinkActiveStateChange ( >=20 > + IN EFI_HANDLE DispatchHandle, >=20 > + IN PCH_PCIE_SMI_RP_CONTEXT *RpContext >=20 > + ) >=20 > +{ >=20 > + return; >=20 > +} >=20 > + >=20 > +/** >=20 > + PCIE Link Equalization Request SMI call back function for all Root por= ts >=20 > + >=20 > + @param[in] DispatchHandle Handle of this dispatch function >=20 > + @param[in] RpContext Rootport context, which contains= RootPort > Index, >=20 > + and RootPort PCI BDF. >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +PchPcieLinkEqHandlerFunction ( >=20 > + IN EFI_HANDLE DispatchHandle, >=20 > + IN PCH_PCIE_SMI_RP_CONTEXT *RpContext >=20 > + ) >=20 > +{ >=20 > + /// >=20 > + /// From PCI Express specification, the PCIe device can request for Li= nk > Equalization. When the >=20 > + /// Link Equalization is requested by the device, an SMI will be gener= ated > by PCIe RP when >=20 > + /// enabled and the SMI subroutine would invoke the Software > Preset/Coefficient Search >=20 > + /// software to re-equalize the link. >=20 > + /// >=20 > + >=20 > + return; >=20 > + >=20 > +} >=20 > + >=20 > +/** >=20 > + An IoTrap callback to config PCIE power management settings >=20 > +**/ >=20 > +VOID >=20 > +PchPciePmIoTrapSmiCallback ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + UINT32 PortIndex; >=20 > + UINT64 RpBase; >=20 > + UINT8 MaxPciePortNum; >=20 > + >=20 > + MaxPciePortNum =3D GetPchMaxPciePortNum (); >=20 > + >=20 > + for (PortIndex =3D 0; PortIndex < MaxPciePortNum; PortIndex++) { >=20 > + RpBase =3D PchPcieRpPciCfgBase (PortIndex); >=20 > + >=20 > + if (PciSegmentRead16 (RpBase) !=3D 0xFFFF) { >=20 > + RootportDownstreamPmConfiguration ( >=20 > + DEFAULT_PCI_SEGMENT_NUMBER_PCH, >=20 > + DEFAULT_PCI_BUS_NUMBER_PCH, >=20 > + PchPcieRpDevNumber (PortIndex), >=20 > + PchPcieRpFuncNumber (PortIndex), >=20 > + mTempRootPortBusNumMin, >=20 > + mTempRootPortBusNumMax, >=20 > + &mPcieRootPortConfig[PortIndex].PcieRpCommonConfig, >=20 > + mNumOfDevAspmOverride, >=20 > + mDevAspmOverride >=20 > + ); >=20 > + >=20 > + } >=20 > + } >=20 > +} >=20 > + >=20 > +/** >=20 > + An IoTrap callback to config PCIE power management settings >=20 > + >=20 > + @param[in] DispatchHandle - The handle of this callback, obtained whe= n > registering >=20 > + @param[in] DispatchContext - Pointer to the > EFI_SMM_IO_TRAP_DISPATCH_CALLBACK_CONTEXT >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +PchPcieIoTrapSmiCallback ( >=20 > + IN EFI_HANDLE DispatchHandle, >=20 > + IN EFI_SMM_IO_TRAP_CONTEXT *CallbackContext, >=20 > + IN OUT VOID *CommBuffer, >=20 > + IN OUT UINTN *CommBufferSize >=20 > + ) >=20 > +{ >=20 > + if (CallbackContext->WriteData =3D=3D PchPciePmTrap) { >=20 > + if (mPchPciePmTrapExecuted =3D=3D FALSE) { >=20 > + PchPciePmIoTrapSmiCallback (); >=20 > + mPchPciePmTrapExecuted =3D TRUE; >=20 > + } >=20 > + } else { >=20 > + ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER); >=20 > + } >=20 > +} >=20 > + >=20 > +/** >=20 > + This function clear the Io trap executed flag before enter S3 >=20 > + >=20 > + @param[in] Handle Handle of the callback >=20 > + @param[in] Context The dispatch context >=20 > + >=20 > + @retval EFI_SUCCESS PCH register saved >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchPcieS3EntryCallBack ( >=20 > + IN EFI_HANDLE Handle, >=20 > + IN CONST VOID *Context OPTIONAL, >=20 > + IN OUT VOID *CommBuffer OPTIONAL, >=20 > + IN OUT UINTN *CommBufferSize OPTIONAL >=20 > + ) >=20 > +{ >=20 > + mPchPciePmTrapExecuted =3D FALSE; >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > +/** >=20 > + Register PCIE Hotplug SMI dispatch function to handle Hotplug enabling >=20 > + >=20 > + @param[in] ImageHandle The image handle of this module >=20 > + @param[in] SystemTable The EFI System Table >=20 > + >=20 > + @retval EFI_SUCCESS The function completes successfully >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +InitializePchPcieSmm ( >=20 > + IN EFI_HANDLE ImageHandle, >=20 > + IN EFI_SYSTEM_TABLE *SystemTable >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + UINT8 PortIndex; >=20 > + UINT8 Data8; >=20 > + UINT32 Data32Or; >=20 > + UINT32 Data32And; >=20 > + UINT64 RpBase; >=20 > + EFI_HANDLE PcieHandle; >=20 > + PCH_PCIE_SMI_DISPATCH_PROTOCOL *PchPcieSmiDispatchProtocol; >=20 > + EFI_HANDLE PchIoTrapHandle; >=20 > + EFI_SMM_IO_TRAP_REGISTER_CONTEXT PchIoTrapContext; >=20 > + EFI_SMM_SX_REGISTER_CONTEXT SxDispatchContext; >=20 > + PCH_PCIE_IOTRAP_PROTOCOL *PchPcieIoTrapProtocol; >=20 > + EFI_HANDLE SxDispatchHandle; >=20 > + UINT8 MaxPciePortNum; >=20 > + PCH_POLICY_PROTOCOL *PchPolicy; >=20 > + PCIE_RP_DXE_CONFIG *PchPcieRpDxeConfig; >=20 > + UINTN PcieDeviceTableSize; >=20 > + PCH_PCIE_DEVICE_OVERRIDE *DevAspmOverride; >=20 > + UINTN Count; >=20 > + >=20 > + DEBUG ((DEBUG_INFO, "InitializePchPcieSmm () Start\n")); >=20 > + >=20 > + MaxPciePortNum =3D GetPchMaxPciePortNum (); >=20 > + >=20 > + // >=20 > + // Locate Pch Pcie Smi Dispatch Protocol >=20 > + // >=20 > + Status =3D gSmst->SmmLocateProtocol (&gPchPcieSmiDispatchProtocolGuid, > NULL, (VOID**) &PchPcieSmiDispatchProtocol); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + mPchBusNumber =3D DEFAULT_PCI_BUS_NUMBER_PCH; >=20 > + mTempRootPortBusNumMin =3D PcdGet8 (PcdSiliconInitTempPciBusMin); >=20 > + mTempRootPortBusNumMax =3D PcdGet8 (PcdSiliconInitTempPciBusMax); >=20 > + >=20 > + ASSERT (sizeof mPcieRootPortConfig =3D=3D sizeof mPchConfigHob- > >PcieRp.RootPort); >=20 > + CopyMem ( >=20 > + mPcieRootPortConfig, >=20 > + &(mPchConfigHob->PcieRp.RootPort), >=20 > + sizeof (mPcieRootPortConfig) >=20 > + ); >=20 > + >=20 > + DevAspmOverride =3D NULL; >=20 > + mDevAspmOverride =3D NULL; >=20 > + mNumOfDevAspmOverride =3D 0; >=20 > + >=20 > + Status =3D gBS->LocateProtocol (&gPchPolicyProtocolGuid, NULL, (VOID *= *) > &PchPolicy); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + Status =3D GetConfigBlock ((VOID*) PchPolicy, &gPchPcieRpDxeConfigGuid= , > (VOID*) &PchPcieRpDxeConfig); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + DevAspmOverride =3D PchPcieRpDxeConfig->PcieDeviceOverrideTablePtr; >=20 > + >=20 > + Count =3D 0; >=20 > + if (DevAspmOverride !=3D NULL) { >=20 > + for (Count =3D 0; DevAspmOverride[Count].DeviceId !=3D 0; Count++) {= } >=20 > + } >=20 > + >=20 > + if (Count !=3D0) { >=20 > + PcieDeviceTableSize =3D Count * sizeof (PCH_PCIE_DEVICE_OVERRIDE); >=20 > + Status =3D gSmst->SmmAllocatePool ( >=20 > + EfiRuntimeServicesData, >=20 > + PcieDeviceTableSize, >=20 > + (VOID **) &mDevAspmOverride >=20 > + ); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + CopyMem (mDevAspmOverride, DevAspmOverride, > PcieDeviceTableSize); >=20 > + mNumOfDevAspmOverride =3D (UINT32) Count; >=20 > + } >=20 > + // >=20 > + // Throught all PCIE root port function and register the SMI Handler f= or > enabled ports. >=20 > + // >=20 > + for (PortIndex =3D 0; PortIndex < MaxPciePortNum; PortIndex++) { >=20 > + RpBase =3D PchPcieRpPciCfgBase (PortIndex); >=20 > + // >=20 > + // Skip the root port function which is not enabled >=20 > + // >=20 > + if (PciSegmentRead32 (RpBase) =3D=3D 0xFFFFFFFF) { >=20 > + continue; >=20 > + } >=20 > + >=20 > + // >=20 > + // Register SMI Handlers for Hot Plug and Link Active State Change >=20 > + // >=20 > + Data8 =3D PciSegmentRead8 (RpBase + R_PCH_PCIE_CFG_SLCAP); >=20 > + if (Data8 & B_PCIE_SLCAP_HPC) { >=20 > + PcieHandle =3D NULL; >=20 > + Status =3D PchPcieSmiDispatchProtocol->HotPlugRegister ( >=20 > + PchPcieSmiDispatchProtocol, >=20 > + PchPcieSmiRpHandlerFunction= , >=20 > + PortIndex, >=20 > + &PcieHandle >=20 > + ); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + Status =3D PchPcieSmiDispatchProtocol->LinkActiveRegister ( >=20 > + PchPcieSmiDispatchProtocol, >=20 > + PchPcieLinkActiveStateChang= e, >=20 > + PortIndex, >=20 > + &PcieHandle >=20 > + ); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + Data32Or =3D B_PCH_PCIE_CFG_MPC_HPME; >=20 > + Data32And =3D (UINT32) ~B_PCH_PCIE_CFG_MPC_HPME; >=20 > + PciSegmentOr32 (RpBase + R_PCH_PCIE_CFG_MPC, Data32Or); >=20 > + S3BootScriptSaveMemReadWrite ( >=20 > + S3BootScriptWidthUint32, >=20 > + PcdGet64 (PcdSiPciExpressBaseAddress) + RpBase + > R_PCH_PCIE_CFG_MPC, >=20 > + &Data32Or, /// Data to be ORed >=20 > + &Data32And /// Data to be ANDed >=20 > + ); >=20 > + } >=20 > + >=20 > + // >=20 > + // Register SMI Handler for Link Equalization Request from Gen 3 Dev= ices. >=20 > + // >=20 > + Data8 =3D PciSegmentRead8 (RpBase + R_PCH_PCIE_CFG_LCAP); >=20 > + if ((Data8 & B_PCIE_LCAP_MLS) =3D=3D V_PCIE_LCAP_MLS_GEN3) { >=20 > + Status =3D PchPcieSmiDispatchProtocol->LinkEqRegister ( >=20 > + PchPcieSmiDispatchProtocol, >=20 > + PchPcieLinkEqHandlerFunctio= n, >=20 > + PortIndex, >=20 > + &PcieHandle >=20 > + ); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + } >=20 > + } >=20 > + >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + PchIoTrapContext.Type =3D WriteTrap; >=20 > + PchIoTrapContext.Length =3D 4; >=20 > + PchIoTrapContext.Address =3D 0; >=20 > + Status =3D mPchIoTrap->Register ( >=20 > + mPchIoTrap, >=20 > + (EFI_SMM_HANDLER_ENTRY_POINT2) > PchPcieIoTrapSmiCallback, >=20 > + &PchIoTrapContext, >=20 > + &PchIoTrapHandle >=20 > + ); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + // >=20 > + // Install the PCH Pcie IoTrap protocol >=20 > + // >=20 > + (gBS->AllocatePool) (EfiBootServicesData, sizeof > (PCH_PCIE_IOTRAP_PROTOCOL), (VOID **)&PchPcieIoTrapProtocol); >=20 > + PchPcieIoTrapProtocol->PcieTrapAddress =3D PchIoTrapContext.Address; >=20 > + >=20 > + Status =3D gBS->InstallMultipleProtocolInterfaces ( >=20 > + &ImageHandle, >=20 > + &gPchPcieIoTrapProtocolGuid, >=20 > + PchPcieIoTrapProtocol, >=20 > + NULL >=20 > + ); >=20 > + >=20 > + // >=20 > + // Register the callback for S3 entry >=20 > + // >=20 > + SxDispatchContext.Type =3D SxS3; >=20 > + SxDispatchContext.Phase =3D SxEntry; >=20 > + Status =3D mSxDispatch->Register ( >=20 > + mSxDispatch, >=20 > + PchPcieS3EntryCallBack, >=20 > + &SxDispatchContext, >=20 > + &SxDispatchHandle >=20 > + ); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + DEBUG ((DEBUG_INFO, "InitializePchPcieSmm, IoTrap @ %x () End\n", > PchIoTrapContext.Address)); >=20 > + >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchSpiAsyn= c.c > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchSpiAsync.c > new file mode 100644 > index 0000000000..bdae6fe918 > --- /dev/null > +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchSpiAsync.c > @@ -0,0 +1,67 @@ > +/** @file >=20 > + PCH SPI Async SMI handler. >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > +#include "PchInitSmm.h" >=20 > + >=20 > +/// >=20 > +/// Global variables >=20 > +/// >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMI_DISPATCH_PROTOCOL > *mPchSmiDispatchProtocol; >=20 > + >=20 > +/** >=20 > + This hardware SMI handler will be run every time the flash write/earse > happens. >=20 > + >=20 > + @param[in] DispatchHandle Not used >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +PchSpiAsyncCallback ( >=20 > + IN EFI_HANDLE DispatchHandle >=20 > + ) >=20 > +{ >=20 > + // >=20 > + // Dummy SMI handler >=20 > + // >=20 > +} >=20 > + >=20 > +/** >=20 > + This fuction install SPI ASYNC SMI handler. >=20 > + >=20 > + @retval EFI_SUCCESS Initialization complete. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +InstallPchSpiAsyncSmiHandler ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + EFI_HANDLE Handle; >=20 > + >=20 > + DEBUG ((DEBUG_INFO, "InstallPchSpiAsyncSmiHandler()\n")); >=20 > + >=20 > + /// >=20 > + /// Get the PCH SMM dispatch protocol >=20 > + /// >=20 > + mPchSmiDispatchProtocol =3D NULL; >=20 > + Status =3D gSmst->SmmLocateProtocol (&gPchSmiDispatchProtocolGuid, > NULL, (VOID **) &mPchSmiDispatchProtocol); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + /// >=20 > + /// Register an SpiAsync callback function >=20 > + /// >=20 > + Handle =3D NULL; >=20 > + Status =3D mPchSmiDispatchProtocol->SpiAsyncRegister ( >=20 > + mPchSmiDispatchProtocol, >=20 > + PchSpiAsyncCallback, >=20 > + &Handle >=20 > + ); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > + >=20 > diff --git > a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.c > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.c > new file mode 100644 > index 0000000000..54a1575f2c > --- /dev/null > +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.c > @@ -0,0 +1,1284 @@ > +/** @file >=20 > + Main implementation source file for the Io Trap SMM driver >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > +#include "PchSmmHelpers.h" >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > + >=20 > +#define GENERIC_IOTRAP_SIZE 0x100 >=20 > + >=20 > +// >=20 > +// Module global variables >=20 > +// >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_HANDLE > mDriverImageHandle; >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_HANDLE > mIoTrapHandle; >=20 > + >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED IO_TRAP_INSTANCE > mIoTrapData; >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED IO_TRAP_RECORD > *mIoTrapRecord; >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED PCH_NVS_AREA > *mPchNvsArea; >=20 > + >=20 > + >=20 > +static CONST UINT16 mLengthTable[10] =3D { 1, 2, 3, 4, 8, 16= , 32, 64, 128, > 256 }; >=20 > + >=20 > +/** >=20 > + Helper function that encapsulates IoTrap register access. >=20 > + IO trap related register updates must be made in 2 registers, IOTRAP a= nd > DMI source decode. >=20 > + >=20 > + @param[in] TrapHandlerNum trap number (0-3) >=20 > + @param[in] Value value to be written in both registers >=20 > + @param[in] SaveToBootscript if true, this register write will be save= d to > bootscript >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +SetIoTrapLowDword ( >=20 > + IN UINT8 TrapHandlerNum, >=20 > + IN UINT32 Value, >=20 > + IN BOOLEAN SaveToBootscript >=20 > + ) >=20 > +{ >=20 > + UINT32 BitMask; >=20 > + UINT32 BitValue; >=20 > + // >=20 > + // To provide sequentially consistent programming model for IO trap >=20 > + // all pending IO cycles must be flushed before enabling and before > disabling a trap. >=20 > + // Without this the trap may trigger due to IO cycle issued before the= trap > is enabled or a cycle issued before the trap is disabled might be missed. >=20 > + // a. Issues a MemRd to PSTH IO Trap Enable bit -> This serves to flus= h all > previous IO cycles. >=20 > + // b. Then only issues a MemWr to PSTH IO Trap Enable =3D=3D Value >=20 > + // c. Issues another MemRd to PSTH IO Trap Enable bit -> This serves t= o > push the MemWr to PSTH and confirmed that IO Trap is in fact enabled >=20 > + // >=20 > + PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8); >=20 > + PchPcrWrite32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8, > Value); >=20 > + PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8); >=20 > + >=20 > + PchPcrWrite32 (PID_DMI, R_PCH_DMI_PCR_IOT1 + TrapHandlerNum * 8, > Value); >=20 > + // >=20 > + // Read back DMI IOTRAP register to enforce ordering so DMI write is > completed before any IO reads >=20 > + // from other threads which may occur after this point (after SMI exit= ). >=20 > + // >=20 > + PchPcrRead32 (PID_DMI, R_PCH_DMI_PCR_IOT1 + TrapHandlerNum * 8); >=20 > + if (SaveToBootscript) { >=20 > + // >=20 > + // Ignore the value check of PCH_PCR_BOOT_SCRIPT_READ >=20 > + // >=20 > + BitMask =3D 0; >=20 > + BitValue =3D 0; >=20 > + >=20 > + PCH_PCR_BOOT_SCRIPT_READ (S3BootScriptWidthUint32, PID_PSTH, > R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8, &BitMask, &BitValue); >=20 > + PCH_PCR_BOOT_SCRIPT_WRITE (S3BootScriptWidthUint32, PID_PSTH, > R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8, 1, &Value); >=20 > + PCH_PCR_BOOT_SCRIPT_READ (S3BootScriptWidthUint32, PID_PSTH, > R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8, &BitMask, &BitValue); >=20 > + PCH_PCR_BOOT_SCRIPT_WRITE (S3BootScriptWidthUint32, PID_DMI, > R_PCH_DMI_PCR_IOT1 + TrapHandlerNum * 8, 1, &Value); >=20 > + } >=20 > +} >=20 > + >=20 > +/** >=20 > + Helper function that encapsulates IoTrap register access. >=20 > + IO trap related register updates must be made in 2 registers, IOTRAP a= nd > DMI source decode. >=20 > + >=20 > + @param[in] TrapHandlerNum trap number (0-3) >=20 > + @param[in] Value value to be written in both registers >=20 > + @param[in] SaveToBootscript if true, this register write will be save= d to > bootscript >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +SetIoTrapHighDword ( >=20 > + IN UINT8 TrapHandlerNum, >=20 > + IN UINT32 Value, >=20 > + IN BOOLEAN SaveToBootscript >=20 > + ) >=20 > +{ >=20 > + PchPcrWrite32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8 > + 4, Value); >=20 > + PchPcrWrite32 (PID_DMI, R_PCH_DMI_PCR_IOT1 + TrapHandlerNum * 8 + > 4, Value); >=20 > + if (SaveToBootscript) { >=20 > + PCH_PCR_BOOT_SCRIPT_WRITE (S3BootScriptWidthUint32, PID_PSTH, > R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8 + 4, 1, &Value); >=20 > + PCH_PCR_BOOT_SCRIPT_WRITE (S3BootScriptWidthUint32, PID_DMI, > R_PCH_DMI_PCR_IOT1 + TrapHandlerNum * 8 + 4, 1, &Value); >=20 > + } >=20 > +} >=20 > + >=20 > +/** >=20 > + Clear pending IOTRAP status. >=20 > + If IOTRAP status is pending and IOTRAP is disabled, then BIOS will not= find a > match SMI source >=20 > + and will not dispatch any SMI handler for it. The pending status will = lead to > SMI storm. >=20 > + This prevents that IOTRAP gets triggered by pending IO cycles even aft= er > it's disabled. >=20 > + >=20 > + @param[in] TrapHandlerNum trap number (0-3) >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +ClearPendingIoTrapStatus ( >=20 > + IN UINT8 TrapHandlerNum >=20 > + ) >=20 > +{ >=20 > + PchPcrWrite32 (PID_PSTH, R_PSTH_PCR_TRPST, (UINT32)(1 << > TrapHandlerNum)); >=20 > +} >=20 > + >=20 > +/** >=20 > + IO resources allocated to IO traps need to be reported to OS so that t= hey > don't get reused. >=20 > + This function makes IO trap allocation data available to ACPI >=20 > + >=20 > + @param[in] TrapHandlerNum trap number (0-3) >=20 > + @param[in] BaseAddress address of allocated IO resource >=20 > + @param[in] Track TRUE =3D resource allocated, FALSE =3D reso= urce freed >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +UpdateIoTrapAcpiResources ( >=20 > + IN UINT8 TrapHandlerNum, >=20 > + IN EFI_PHYSICAL_ADDRESS BaseAddress, >=20 > + IN BOOLEAN Track >=20 > + ) >=20 > +{ >=20 > + >=20 > + if (Track =3D=3D TRUE) { >=20 > + mPchNvsArea->IoTrapAddress[TrapHandlerNum] =3D (UINT16) > BaseAddress; >=20 > + mPchNvsArea->IoTrapStatus[TrapHandlerNum] =3D 1; >=20 > + } else { >=20 > + mPchNvsArea->IoTrapStatus[TrapHandlerNum] =3D 0; >=20 > + } >=20 > +} >=20 > + >=20 > +/** >=20 > + Get address from IOTRAP low dword. >=20 > + >=20 > + @param[in] IoTrapRegLowDword IOTRAP register low dword >=20 > + >=20 > + @retval Address of IOTRAP setting. >=20 > +**/ >=20 > +STATIC >=20 > +UINT16 >=20 > +AddressFromLowDword ( >=20 > + UINT32 IoTrapRegLowDword >=20 > + ) >=20 > +{ >=20 > + return (UINT16) (IoTrapRegLowDword & B_PSTH_PCR_TRPREG_AD); >=20 > +} >=20 > + >=20 > +/** >=20 > + Get length from IOTRAP low dword. >=20 > + >=20 > + @param[in] IoTrapRegLowDword IOTRAP register low dword >=20 > + >=20 > + @retval Length of IOTRAP setting. >=20 > +**/ >=20 > +STATIC >=20 > +UINT16 >=20 > +LengthFromLowDword ( >=20 > + UINT32 IoTrapRegLowDword >=20 > + ) >=20 > +{ >=20 > + return (UINT16) (((IoTrapRegLowDword >> 16) & 0xFC) + 4); >=20 > +} >=20 > + >=20 > +/** >=20 > + Get ByteEnable from IOTRAP high dword. >=20 > + >=20 > + @param[in] IoTrapRegHighDword IOTRAP register high dword >=20 > + >=20 > + @retval ByteEnable of IOTRAP setting. >=20 > +**/ >=20 > +STATIC >=20 > +UINT8 >=20 > +ByteEnableFromHighDword ( >=20 > + UINT32 IoTrapRegHighDword >=20 > + ) >=20 > +{ >=20 > + return (UINT8) (IoTrapRegHighDword & 0x0F); >=20 > +} >=20 > + >=20 > +/** >=20 > + Get ByteEnableMask from IOTRAP high dword. >=20 > + >=20 > + @param[in] IoTrapRegHighDword IOTRAP register high dword >=20 > + >=20 > + @retval ByteEnableMask of IOTRAP setting. >=20 > +**/ >=20 > +STATIC >=20 > +UINT8 >=20 > +ByteEnableMaskFromHighDword ( >=20 > + UINT32 IoTrapRegHighDword >=20 > + ) >=20 > +{ >=20 > + return (UINT8) ((IoTrapRegHighDword & 0xF0) >> 4); >=20 > +} >=20 > + >=20 > +/** >=20 > + Check the IoTrap register matches the IOTRAP EX content. >=20 > + >=20 > + @param[in] IoTrapRecord IOTRAP registration record structure >=20 > + @param[in] IoTrapRegLowDword IOTRAP register low dword >=20 > + @param[in] IoTrapRegHighDword IOTRAP register high dword >=20 > + >=20 > + @retval TRUE Content matched >=20 > + FALSE Content mismatched >=20 > +**/ >=20 > +STATIC >=20 > +BOOLEAN >=20 > +IsIoTrapExContentMatched ( >=20 > + IO_TRAP_RECORD *IoTrapRecord, >=20 > + UINT32 IoTrapRegLowDword, >=20 > + UINT32 IoTrapRegHighDword >=20 > + ) >=20 > +{ >=20 > + if ((IoTrapRecord->Context.Address =3D=3D AddressFromLowDword > (IoTrapRegLowDword)) && >=20 > + (IoTrapRecord->Context.Length =3D=3D LengthFromLowDword > (IoTrapRegLowDword)) && >=20 > + (IoTrapRecord->Context.ByteEnable =3D=3D ByteEnableFromHighDword > (IoTrapRegHighDword)) && >=20 > + (IoTrapRecord->Context.ByteEnableMask =3D=3D > ByteEnableMaskFromHighDword (IoTrapRegHighDword))) >=20 > + { >=20 > + return TRUE; >=20 > + } >=20 > + return FALSE; >=20 > +} >=20 > + >=20 > + >=20 > +/** >=20 > + The helper function for IoTrap callback dispacther >=20 > + >=20 > + @param[in] TrapHandlerNum trap number (0-3) >=20 > +**/ >=20 > +VOID >=20 > +IoTrapDispatcherHelper ( >=20 > + UINTN TrapHandlerNum >=20 > + ) >=20 > +{ >=20 > + IO_TRAP_RECORD *RecordInDb; >=20 > + LIST_ENTRY *LinkInDb; >=20 > + EFI_SMM_IO_TRAP_REGISTER_CONTEXT CurrentIoTrapRegisterData; >=20 > + EFI_SMM_IO_TRAP_CONTEXT CurrentIoTrapContextData; >=20 > + UINT16 BaseAddress; >=20 > + UINT16 StartAddress; >=20 > + UINT16 EndAddress; >=20 > + UINT32 Data32; >=20 > + UINT8 ActiveHighByteEnable; >=20 > + BOOLEAN ReadCycle; >=20 > + UINT32 WriteData; >=20 > + >=20 > + if (!IsListEmpty > (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase))) { >=20 > + Data32 =3D PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPC); >=20 > + WriteData =3D PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPD); >=20 > + >=20 > + BaseAddress =3D (UINT16) (Data32 & B_PSTH_PCR_TRPC_IOA); >=20 > + ActiveHighByteEnable =3D (UINT8)((Data32 & B_PSTH_PCR_TRPC_AHBE) >> > 16); >=20 > + ReadCycle =3D (BOOLEAN) ((Data32 & B_PSTH_PCR_TRPC_RW) = =3D=3D > B_PSTH_PCR_TRPC_RW); >=20 > + // >=20 > + // StartAddress and EndAddress will be equal if it's byte access >=20 > + // >=20 > + EndAddress =3D (UINT16) (HighBitSet32 ((UINT32) > (ActiveHighByteEnable))) + BaseAddress; >=20 > + StartAddress =3D (UINT16) (LowBitSet32 ((UINT32) > (ActiveHighByteEnable))) + BaseAddress; >=20 > + >=20 > + CurrentIoTrapRegisterData.Type =3D > (EFI_SMM_IO_TRAP_DISPATCH_TYPE)ReadCycle; >=20 > + CurrentIoTrapContextData.WriteData =3D WriteData; >=20 > + >=20 > + LinkInDb =3D GetFirstNode > (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase)); >=20 > + >=20 > + while (!IsNull > (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase), LinkInDb)) { >=20 > + RecordInDb =3D IO_TRAP_RECORD_FROM_LINK (LinkInDb); >=20 > + >=20 > + // >=20 > + // If MergeDisable is TRUE, no need to check the address range, di= spatch > the callback function directly. >=20 > + // >=20 > + if (mIoTrapData.Entry[TrapHandlerNum].MergeDisable) { >=20 > + if (RecordInDb->IoTrapCallback !=3D NULL) { >=20 > + RecordInDb->IoTrapCallback (&RecordInDb->Link, > &CurrentIoTrapContextData, NULL, NULL); >=20 > + } >=20 > + if (RecordInDb->IoTrapExCallback !=3D NULL) { >=20 > + RecordInDb->IoTrapExCallback (BaseAddress, ActiveHighByteEnabl= e, > !ReadCycle, WriteData); >=20 > + } >=20 > + // >=20 > + // Expect only one callback available. So break immediately. >=20 > + // >=20 > + break; >=20 > + // >=20 > + // If MergeDisable is FALSE, check the address range and trap type= . >=20 > + // >=20 > + } else { >=20 > + if ((RecordInDb->Context.Address <=3D StartAddress) && >=20 > + (RecordInDb->Context.Address + RecordInDb->Context.Length > > EndAddress)) { >=20 > + if ((RecordInDb->Context.Type =3D=3D IoTrapExTypeReadWrite) || > (RecordInDb->Context.Type =3D=3D (IO_TRAP_EX_DISPATCH_TYPE) > CurrentIoTrapRegisterData.Type)) { >=20 > + // >=20 > + // Pass the IO trap context information >=20 > + // >=20 > + RecordInDb->IoTrapCallback (&RecordInDb->Link, > &CurrentIoTrapContextData, NULL, NULL); >=20 > + } >=20 > + // >=20 > + // Break if the address is match >=20 > + // >=20 > + break; >=20 > + } else { >=20 > + LinkInDb =3D GetNextNode > (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase), &RecordInDb- > >Link); >=20 > + if (IsNull (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBa= se), > LinkInDb)) { >=20 > + // >=20 > + // An IO access was trapped that does not have a handler reg= istered. >=20 > + // This indicates an error condition. >=20 > + // >=20 > + ASSERT (FALSE); >=20 > + } >=20 > + } >=20 > + } // end of if else block >=20 > + } // end of while loop >=20 > + } // end of if else block >=20 > +} >=20 > + >=20 > +/** >=20 > + IoTrap dispatcher for IoTrap register 0. >=20 > + >=20 > + @param[in] DispatchHandle Handle of dispatch function >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +IoTrapDispatcher0 ( >=20 > + IN EFI_HANDLE DispatchHandle >=20 > + ) >=20 > +{ >=20 > + IoTrapDispatcherHelper (0); >=20 > +} >=20 > + >=20 > +/** >=20 > + IoTrap dispatcher for IoTrap register 1. >=20 > + >=20 > + @param[in] DispatchHandle Handle of dispatch function >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +IoTrapDispatcher1 ( >=20 > + IN EFI_HANDLE DispatchHandle >=20 > + ) >=20 > +{ >=20 > + IoTrapDispatcherHelper (1); >=20 > +} >=20 > + >=20 > +/** >=20 > + IoTrap dispatcher for IoTrap register 2. >=20 > + >=20 > + @param[in] DispatchHandle Handle of dispatch function >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +IoTrapDispatcher2 ( >=20 > + IN EFI_HANDLE DispatchHandle >=20 > + ) >=20 > +{ >=20 > + IoTrapDispatcherHelper (2); >=20 > +} >=20 > + >=20 > +/** >=20 > + IoTrap dispatcher for IoTrap register 3. >=20 > + >=20 > + @param[in] DispatchHandle Handle of dispatch function >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +IoTrapDispatcher3 ( >=20 > + IN EFI_HANDLE DispatchHandle >=20 > + ) >=20 > +{ >=20 > + IoTrapDispatcherHelper (3); >=20 > +} >=20 > + >=20 > +/** >=20 > + IoTrap registratrion helper fucntion. >=20 > + >=20 > + @param[in] DispatchHandle Handle of dispatch function >=20 > + @param[in] IoTrapDispatchFunction Dispatch function of > IoTrapDispatch2Protocol. >=20 > + This could be NULL if it's not f= rom > IoTrapDispatch2Protocol. >=20 > + @param[in] IoTrapExDispatchFunction Dispatch function of > IoTrapExDispatchProtocol. >=20 > + This could be NULL if it's not f= rom > IoTrapExDispatchProtocol. >=20 > + @param[in out] Address The pointer of IO Address. >=20 > + If the input Addres is 0, it wil= l return the address > assigned >=20 > + by registration to this caller. >=20 > + @param[in] Length Length of IO address range. >=20 > + @param[in] Type Read/Write type of IO trap. >=20 > + @param[in] ByteEnable Bitmap to enable trap for each b= yte of > every dword alignment address. >=20 > + @param[in] ByteEnableMask ByteEnableMask bitwise to ignore= the > ByteEnable setting. >=20 > + >=20 > + @retval EFI_INVALID_PARAMETER If Type is invalid, >=20 > + If Length is invalid, >=20 > + If Address is invalid, >=20 > + EFI_ACCESS_DENIED If the SmmReadyToLock event has = been > triggered, >=20 > + EFI_OUT_OF_RESOURCES If run out of IoTrap register re= source, >=20 > + If run out of SMM memory pool, >=20 > + EFI_SUCCESS IoTrap register successfully. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +IoTrapRegisterHelper ( >=20 > + OUT EFI_HANDLE *DispatchHandle, >=20 > + IN EFI_SMM_HANDLER_ENTRY_POINT2 IoTrapDispatchFunctio= n, >=20 > + IN IO_TRAP_EX_DISPATCH_CALLBACK IoTrapExDispatchFunct= ion, >=20 > + IN OUT UINT16 *Address, >=20 > + IN UINT16 Length, >=20 > + IN IO_TRAP_EX_DISPATCH_TYPE Type, >=20 > + IN UINT8 ByteEnable, >=20 > + IN UINT8 ByteEnableMask >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + EFI_PHYSICAL_ADDRESS BaseAddress; >=20 > + UINT32 UsedLength; >=20 > + UINT8 TrapHandlerNum; >=20 > + UINT32 IoTrapRegLowDword; >=20 > + UINT32 IoTrapRegHighDword; >=20 > + BOOLEAN TempMergeDisable; >=20 > + >=20 > + DEBUG ((DEBUG_INFO, "IoTrapRegisterHelper\n")); >=20 > + DEBUG ((DEBUG_INFO, "Address:%x \n", *Address)); >=20 > + DEBUG ((DEBUG_INFO, "Length:%x \n", Length)); >=20 > + DEBUG ((DEBUG_INFO, "Type:%x \n", Type)); >=20 > + DEBUG ((DEBUG_INFO, "ByteEnable:%x \n", ByteEnable)); >=20 > + DEBUG ((DEBUG_INFO, "ByteEnableMask:%x \n", ByteEnableMask)); >=20 > + >=20 > + // >=20 > + // Return error if the type is invalid >=20 > + // >=20 > + if (Type >=3D IoTrapExTypeMaximum) { >=20 > + DEBUG ((DEBUG_ERROR, "The Dispatch Type %0X is invalid! \n", Type)); >=20 > + return EFI_INVALID_PARAMETER; >=20 > + } >=20 > + // >=20 > + // Return error if the Length is invalid >=20 > + // >=20 > + if (Length < 1 || Length > GENERIC_IOTRAP_SIZE) { >=20 > + DEBUG ((DEBUG_ERROR, "The Dispatch Length %0X is invalid! \n", > Length)); >=20 > + return EFI_INVALID_PARAMETER; >=20 > + } >=20 > + // >=20 > + // Return error if the address is invalid >=20 > + // PCH supports non-aligned address but (Address % 4 + Length) must no= t > be more than 4 >=20 > + // >=20 > + if (((Length & (Length - 1)) !=3D 0) && (Length !=3D 3)) { >=20 > + DEBUG ((DEBUG_ERROR, "The Dispatch Length is not power of 2 \n")); >=20 > + return EFI_INVALID_PARAMETER; >=20 > + } >=20 > + >=20 > + if (((Length >=3D 4) && (*Address & 0x3)) || >=20 > + ((Length < 4) && (((*Address & 0x3) + Length) > 4))) { >=20 > + DEBUG ((DEBUG_ERROR, "PCH does not support Dispatch Address %0X > and Length %0X combination \n", *Address, Length)); >=20 > + return EFI_INVALID_PARAMETER; >=20 > + } >=20 > + >=20 > + if ((Length >=3D 4) && ((*Address & (Length - 1)) !=3D 0)) { >=20 > + DEBUG ((DEBUG_ERROR, "Dispatch Address %0X is not aligned to the > Length %0X \n", *Address, Length)); >=20 > + return EFI_INVALID_PARAMETER; >=20 > + } >=20 > + >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + if (*Address) { >=20 > + TempMergeDisable =3D TRUE; >=20 > + }else { >=20 > + TempMergeDisable =3D FALSE; >=20 > + } >=20 > + // >=20 > + // Loop through the first IO Trap handler, looking for the suitable ha= ndler >=20 > + // >=20 > + for (TrapHandlerNum =3D 0; TrapHandlerNum < IO_TRAP_HANDLER_NUM; > TrapHandlerNum++) { >=20 > + // >=20 > + // Get information from Io Trap handler register >=20 > + // >=20 > + IoTrapRegLowDword =3D PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 > + TrapHandlerNum * 8); >=20 > + >=20 > + // >=20 > + // Check if the IO Trap handler is not used >=20 > + // >=20 > + if (AddressFromLowDword (IoTrapRegLowDword) =3D=3D 0) { >=20 > + // >=20 > + // Search available IO address and allocate it if the IO address = is 0 >=20 > + // >=20 > + BaseAddress =3D *Address; >=20 > + if (BaseAddress =3D=3D 0) { >=20 > + // >=20 > + // Allocate 256 byte range from GCD for common pool usage >=20 > + // >=20 > + if ((PcdGet8 (PcdEfiGcdAllocateType) =3D=3D > EfiGcdAllocateMaxAddressSearchBottomUp) || (PcdGet8 > (PcdEfiGcdAllocateType) =3D=3D EfiGcdAllocateMaxAddressSearchTopDown)) { >=20 > + BaseAddress =3D 0xFFFF; >=20 > + } >=20 > + Status =3D gDS->AllocateIoSpace ( >=20 > + PcdGet8 (PcdEfiGcdAllocateType), >=20 > + EfiGcdIoTypeIo, >=20 > + 8, >=20 > + GENERIC_IOTRAP_SIZE, >=20 > + &BaseAddress, >=20 > + mDriverImageHandle, >=20 > + NULL >=20 > + ); >=20 > + if (EFI_ERROR (Status)) { >=20 > + DEBUG ((DEBUG_ERROR, "Can't find any available IO address! \n"= )); >=20 > + return EFI_OUT_OF_RESOURCES; >=20 > + } >=20 > + >=20 > + *Address =3D (UINT16) BaseAddress; >=20 > + UsedLength =3D GENERIC_IOTRAP_SIZE; >=20 > + mIoTrapData.Entry[TrapHandlerNum].TrapUsedLength =3D Length; >=20 > + mIoTrapData.Entry[TrapHandlerNum].ReservedAcpiIoResource =3D TRU= E; >=20 > + UpdateIoTrapAcpiResources (TrapHandlerNum, BaseAddress, TRUE); >=20 > + } else { >=20 > + BaseAddress &=3D B_PSTH_PCR_TRPREG_AD; >=20 > + UsedLength =3D Length; >=20 > + } >=20 > + >=20 > + Status =3D PchInternalIoTrapSmiRegister ( >=20 > + mIoTrapData.Entry[TrapHandlerNum].CallbackDispatcher, >=20 > + TrapHandlerNum, >=20 > + &mIoTrapHandle >=20 > + ); >=20 > + >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + mIoTrapData.Entry[TrapHandlerNum].IoTrapHandle =3D mIoTrapHandle; >=20 > + >=20 > + // >=20 > + // Fill in the Length, address and Enable the IO Trap SMI >=20 > + // >=20 > + IoTrapRegLowDword =3D (UINT32) (((UsedLength - 1) & ~(BIT1 + BIT0)= ) << > 16) | >=20 > + (UINT16) BaseAddress | >=20 > + B_PSTH_PCR_TRPREG_TSE; >=20 > + >=20 > + if (UsedLength < 4) { >=20 > + // >=20 > + // The 4 bits is the Byte Enable Mask bits to indicate which byt= e that are > trapped. >=20 > + // The input ByteEnable and ByteEnableMask are ignored in this c= ase. >=20 > + // >=20 > + IoTrapRegHighDword =3D (((1 << UsedLength) - 1) << ((*Address &= 0x3) + > (N_PSTH_PCR_TRPREG_BEM - 32))) | >=20 > + (UINT32) (Type << N_PSTH_PCR_TRPREG_RWIO); >=20 > + } else { >=20 > + // >=20 > + // Fill in the ByteEnable, ByteEnableMask, and Type of Io Trap r= egister >=20 > + // >=20 > + IoTrapRegHighDword =3D ((ByteEnableMask & 0xF) << > (N_PSTH_PCR_TRPREG_BEM - 32)) | >=20 > + ((ByteEnable & 0xF) << (N_PSTH_PCR_TRPREG_BE - 32)) | >=20 > + (UINT32) (Type << N_PSTH_PCR_TRPREG_RWIO); >=20 > + } >=20 > + SetIoTrapHighDword (TrapHandlerNum, IoTrapRegHighDword, TRUE); >=20 > + SetIoTrapLowDword (TrapHandlerNum, IoTrapRegLowDword, TRUE); >=20 > + // >=20 > + // Set MergeDisable flag of the registered IoTrap >=20 > + // >=20 > + mIoTrapData.Entry[TrapHandlerNum].MergeDisable =3D > TempMergeDisable; >=20 > + } else { >=20 > + // >=20 > + // Check next handler if MergeDisable is TRUE or the registered Io= Trap if > MergeDisable is TRUE >=20 > + // If the Io Trap register is used by IoTrapEx protocol, then the > MergeDisable will be FALSE. >=20 > + // >=20 > + if ((TempMergeDisable =3D=3D TRUE) || > (mIoTrapData.Entry[TrapHandlerNum].MergeDisable =3D=3D TRUE)) { >=20 > + continue; >=20 > + } >=20 > + // >=20 > + // The IO Trap handler is used, calculate the Length >=20 > + // >=20 > + UsedLength =3D LengthFromLowDword (IoTrapRegLowDword); >=20 > + BaseAddress =3D AddressFromLowDword (IoTrapRegLowDword); >=20 > + // >=20 > + // Assign an addfress from common pool if the caller's address is= 0 >=20 > + // >=20 > + if (*Address =3D=3D 0) { >=20 > + // >=20 > + // Check next handler if it's fully used >=20 > + // >=20 > + if (mIoTrapData.Entry[TrapHandlerNum].TrapUsedLength >=3D > GENERIC_IOTRAP_SIZE) { >=20 > + continue; >=20 > + } >=20 > + // >=20 > + // Check next handler if it's not for a common pool >=20 > + // >=20 > + if (UsedLength < GENERIC_IOTRAP_SIZE) { >=20 > + continue; >=20 > + } >=20 > + // >=20 > + // Check next handler if the size is too big >=20 > + // >=20 > + if (Length >=3D (UINT16) GENERIC_IOTRAP_SIZE - > mIoTrapData.Entry[TrapHandlerNum].TrapUsedLength) { >=20 > + continue; >=20 > + } >=20 > + // >=20 > + // For common pool, we don't need to change the BaseAddress and > UsedLength >=20 > + // >=20 > + *Address =3D (UINT16) (BaseAddress + > mIoTrapData.Entry[TrapHandlerNum].TrapUsedLength); >=20 > + mIoTrapData.Entry[TrapHandlerNum].TrapUsedLength +=3D Length; >=20 > + } >=20 > + // >=20 > + // Only set RWM bit when we need both read and write cycles. >=20 > + // >=20 > + IoTrapRegHighDword =3D PchPcrRead32 (PID_PSTH, > R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8 + 4); >=20 > + if ((IoTrapRegHighDword & B_PSTH_PCR_TRPREG_RWM) =3D=3D 0 && >=20 > + (UINT32) ((IoTrapRegHighDword & B_PSTH_PCR_TRPREG_RWIO) >> > N_PSTH_PCR_TRPREG_RWIO) !=3D >=20 > + (UINT32) Type) { >=20 > + IoTrapRegHighDword =3D ((IoTrapRegHighDword | > B_PSTH_PCR_TRPREG_RWM) & ~B_PSTH_PCR_TRPREG_RWIO); >=20 > + SetIoTrapHighDword (TrapHandlerNum, IoTrapRegHighDword, TRUE); >=20 > + } >=20 > + } >=20 > + break; >=20 > + } >=20 > + >=20 > + if (TrapHandlerNum >=3D IO_TRAP_HANDLER_NUM) { >=20 > + DEBUG ((DEBUG_ERROR, "All IO Trap handler is used, no available IO T= rap > handler! \n")); >=20 > + return EFI_OUT_OF_RESOURCES; >=20 > + } >=20 > + // >=20 > + // Create database record and add to database >=20 > + // >=20 > + Status =3D gSmst->SmmAllocatePool ( >=20 > + EfiRuntimeServicesData, >=20 > + sizeof (IO_TRAP_RECORD), >=20 > + (VOID **) &mIoTrapRecord >=20 > + ); >=20 > + >=20 > + if (EFI_ERROR (Status)) { >=20 > + DEBUG ((DEBUG_ERROR, "Failed to allocate memory for mIoTrapRecord! > \n")); >=20 > + return EFI_OUT_OF_RESOURCES; >=20 > + } >=20 > + // >=20 > + // Gather information about the registration request >=20 > + // >=20 > + mIoTrapRecord->Signature =3D IO_TRAP_RECORD_SIGNATURE; >=20 > + mIoTrapRecord->Context.Address =3D *Address; >=20 > + mIoTrapRecord->Context.Length =3D Length; >=20 > + mIoTrapRecord->Context.Type =3D Type; >=20 > + mIoTrapRecord->Context.ByteEnable =3D ByteEnable; >=20 > + mIoTrapRecord->Context.ByteEnableMask =3D ByteEnableMask; >=20 > + mIoTrapRecord->IoTrapCallback =3D IoTrapDispatchFunction; >=20 > + mIoTrapRecord->IoTrapExCallback =3D IoTrapExDispatchFunction; >=20 > + mIoTrapRecord->IoTrapNumber =3D TrapHandlerNum; >=20 > + >=20 > + InsertTailList (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase), > &mIoTrapRecord->Link); >=20 > + >=20 > + // >=20 > + // Child's handle will be the address linked list link in the record >=20 > + // >=20 > + *DispatchHandle =3D (EFI_HANDLE) (&mIoTrapRecord->Link); >=20 > + >=20 > + DEBUG ((DEBUG_INFO, "Result Address:%x \n", *Address)); >=20 > + DEBUG ((DEBUG_INFO, "Result Length:%x \n", Length)); >=20 > + >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > + >=20 > +/** >=20 > + IoTrap unregistratrion helper fucntion. >=20 > + >=20 > + @param[in] DispatchHandle Handle of dispatch function >=20 > + >=20 > + @retval EFI_INVALID_PARAMETER If DispatchHandle is invalid, >=20 > + EFI_ACCESS_DENIED If the SmmReadyToLock event has = been > triggered, >=20 > + EFI_SUCCESS IoTrap unregister successfully. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +IoTrapUnRegisterHelper ( >=20 > + IN EFI_HANDLE DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + IO_TRAP_RECORD *RecordToDelete; >=20 > + UINT32 IoTrapRegLowDword; >=20 > + EFI_PHYSICAL_ADDRESS BaseAddress; >=20 > + UINT32 UsedLength; >=20 > + UINT8 TrapHandlerNum; >=20 > + UINT8 LengthIndex; >=20 > + BOOLEAN RequireToDisableIoTrapHandler; >=20 > + >=20 > + if (DispatchHandle =3D=3D 0) { >=20 > + return EFI_INVALID_PARAMETER; >=20 > + } >=20 > + >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the > SmmReadyToLock event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + RecordToDelete =3D IO_TRAP_RECORD_FROM_LINK (DispatchHandle); >=20 > + // >=20 > + // Take the entry out of the linked list >=20 > + // >=20 > + if (RecordToDelete->Link.ForwardLink =3D=3D (LIST_ENTRY *) > EFI_BAD_POINTER) { >=20 > + return EFI_INVALID_PARAMETER; >=20 > + } >=20 > + >=20 > + RequireToDisableIoTrapHandler =3D FALSE; >=20 > + // >=20 > + // Loop through the first IO Trap handler, looking for the suitable ha= ndler >=20 > + // >=20 > + TrapHandlerNum =3D RecordToDelete->IoTrapNumber; >=20 > + >=20 > + if (mIoTrapData.Entry[TrapHandlerNum].MergeDisable) { >=20 > + // >=20 > + // Disable the IO Trap handler if it's the only child of the Trap ha= ndler >=20 > + // >=20 > + RequireToDisableIoTrapHandler =3D TRUE; >=20 > + } else { >=20 > + // >=20 > + // Get information from Io Trap handler register >=20 > + // >=20 > + IoTrapRegLowDword =3D PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 > + TrapHandlerNum * 8); >=20 > + >=20 > + // >=20 > + // Check next Io Trap handler if the IO Trap handler is not used >=20 > + // >=20 > + if (AddressFromLowDword (IoTrapRegLowDword) !=3D 0) { >=20 > + >=20 > + UsedLength =3D LengthFromLowDword (IoTrapRegLowDword); >=20 > + BaseAddress =3D AddressFromLowDword (IoTrapRegLowDword); >=20 > + >=20 > + // >=20 > + // Check if it's the maximum address of the Io Trap handler >=20 > + // >=20 > + if ((UINTN)(BaseAddress + UsedLength) =3D=3D (UINTN)(RecordToDelet= e- > >Context.Address + RecordToDelete->Context.Length)) { >=20 > + >=20 > + if (BaseAddress =3D=3D RecordToDelete->Context.Address) { >=20 > + // >=20 > + // Disable the IO Trap handler if it's the only child of the T= rap handler >=20 > + // >=20 > + RequireToDisableIoTrapHandler =3D TRUE; >=20 > + } else { >=20 > + // >=20 > + // Calculate the new IO Trap handler Length >=20 > + // >=20 > + UsedLength =3D UsedLength - RecordToDelete->Context.Length; >=20 > + // >=20 > + // Check the alignment is dword * power of 2 or not >=20 > + // >=20 > + for (LengthIndex =3D 0; LengthIndex < sizeof (mLengthTable) / = sizeof > (UINT16); LengthIndex++) { >=20 > + if (UsedLength =3D=3D mLengthTable[LengthIndex]) { >=20 > + break; >=20 > + } >=20 > + } >=20 > + // >=20 > + // Do not decrease the length if the alignment is not dword * = power of > 2 >=20 > + // >=20 > + if (LengthIndex < sizeof (mLengthTable) / sizeof (UINT16)) { >=20 > + // >=20 > + // Decrease the length to prevent the IO trap SMI >=20 > + // >=20 > + IoTrapRegLowDword =3D (UINT32) ((((UsedLength - 1) &~(BIT1 += BIT0)) > << 16) | BaseAddress | B_PSTH_PCR_TRPREG_TSE); >=20 > + } >=20 > + SetIoTrapLowDword (TrapHandlerNum, IoTrapRegLowDword, TRUE); >=20 > + } >=20 > + } >=20 > + } >=20 > + } >=20 > + >=20 > + if (RequireToDisableIoTrapHandler) { >=20 > + mIoTrapHandle =3D mIoTrapData.Entry[TrapHandlerNum].IoTrapHandle; >=20 > + Status =3D PchInternalIoTrapSmiUnRegister (mIoTrapHandle); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + SetIoTrapLowDword (TrapHandlerNum, 0, TRUE); >=20 > + SetIoTrapHighDword (TrapHandlerNum, 0, TRUE); >=20 > + // >=20 > + // Also clear pending IOTRAP status. >=20 > + // >=20 > + ClearPendingIoTrapStatus (TrapHandlerNum); >=20 > + >=20 > + mIoTrapData.Entry[TrapHandlerNum].IoTrapHandle =3D 0; >=20 > + mIoTrapData.Entry[TrapHandlerNum].MergeDisable =3D FALSE; >=20 > + if (mIoTrapData.Entry[TrapHandlerNum].ReservedAcpiIoResource =3D=3D > TRUE) { >=20 > + mIoTrapData.Entry[TrapHandlerNum].ReservedAcpiIoResource =3D FALSE= ; >=20 > + UpdateIoTrapAcpiResources (TrapHandlerNum, 0, FALSE); >=20 > + } >=20 > + } >=20 > + >=20 > + RemoveEntryList (&RecordToDelete->Link); >=20 > + Status =3D gSmst->SmmFreePool (RecordToDelete); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > + >=20 > +/** >=20 > + Register a new IO Trap SMI dispatch function with a parent SMM driver. >=20 > + The caller will provide information about the IO trap characteristics = via >=20 > + the context. This includes base address, length, read vs. r/w, etc. >=20 > + This function will autoallocate IO base address from a common pool if = the > base address is 0, >=20 > + and the RegisterContext Address field will be updated. >=20 > + The service will not perform GCD allocation if the base address is non= -zero. >=20 > + In this case, the caller is responsible for the existence and allocati= on of the >=20 > + specific IO range. >=20 > + This function looks for the suitable handler and Register a new IoTrap > handler >=20 > + if the IO Trap handler is not used. It also enable the IO Trap Range t= o > generate >=20 > + SMI. >=20 > + >=20 > + @param[in] This Pointer to the > EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL instance. >=20 > + @param[in] DispatchFunction Pointer to dispatch function to be inv= oked > for >=20 > + this SMI source. >=20 > + @param[in, out] RegisterContext Pointer to the dispatch function's > context. >=20 > + The caller fills this context in befor= e calling >=20 > + the register function to indicate to t= he register >=20 > + function the IO trap SMI source for wh= ich the dispatch >=20 > + function should be invoked. This may = not be NULL. >=20 > + If the registration address is not 0, = it's caller's responsibility >=20 > + to reserve the IO resource in ACPI. >=20 > + @param[out] DispatchHandle Handle of dispatch function, for when > interfacing >=20 > + with the parent SMM driver, will be th= e address of linked >=20 > + list link in the call back record. Th= is may not be NULL. >=20 > + >=20 > + @retval EFI_SUCCESS The dispatch function has been success= fully >=20 > + registered and the SMI source has been= enabled. >=20 > + @retval EFI_DEVICE_ERROR The driver was unable to enable the SM= I > source. >=20 > + @retval EFI_OUT_OF_RESOURCES Insufficient resources are available >=20 > + @retval EFI_INVALID_PARAMETER Address requested is already in use. >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +IoTrapRegister ( >=20 > + IN CONST EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL *This, >=20 > + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, >=20 > + IN OUT EFI_SMM_IO_TRAP_REGISTER_CONTEXT *RegisterContext, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + >=20 > + DEBUG ((DEBUG_INFO, "IoTrapRegister\n")); >=20 > + Status =3D IoTrapRegisterHelper ( >=20 > + DispatchHandle, >=20 > + DispatchFunction, >=20 > + NULL, >=20 > + &(RegisterContext->Address), >=20 > + RegisterContext->Length, >=20 > + (IO_TRAP_EX_DISPATCH_TYPE) RegisterContext->Type, >=20 > + 0x00, >=20 > + 0x0F); >=20 > + >=20 > + if (!EFI_ERROR (Status)) { >=20 > + SmiHandlerProfileRegisterHandler ( >=20 > + &gEfiSmmIoTrapDispatch2ProtocolGuid, >=20 > + DispatchFunction, >=20 > + (UINTN)RETURN_ADDRESS (0), >=20 > + RegisterContext, >=20 > + sizeof (EFI_SMM_IO_TRAP_REGISTER_CONTEXT) >=20 > + ); >=20 > + } >=20 > + return Status; >=20 > +} >=20 > + >=20 > +/** >=20 > + Unregister a child SMI source dispatch function with a parent SMM driv= er. >=20 > + >=20 > + @param[in] This Pointer to the > EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL instance. >=20 > + @param[in] DispatchHandle Handle of dispatch function to deregis= ter. >=20 > + >=20 > + @retval EFI_SUCCESS The dispatch function has been success= fully >=20 > + unregistered and the SMI source has be= en disabled >=20 > + if there are no other registered child= dispatch >=20 > + functions for this SMI source. >=20 > + @retval EFI_INVALID_PARAMETER Handle is invalid. >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +IoTrapUnRegister ( >=20 > + IN CONST EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL *This, >=20 > + IN EFI_HANDLE DispatchHandle >=20 > + ) >=20 > +{ >=20 > + IO_TRAP_RECORD *RecordToDelete; >=20 > + >=20 > + RecordToDelete =3D IO_TRAP_RECORD_FROM_LINK (DispatchHandle); >=20 > + SmiHandlerProfileUnregisterHandler ( >=20 > + &gIoTrapExDispatchProtocolGuid, >=20 > + RecordToDelete->IoTrapCallback, >=20 > + &RecordToDelete->Context, >=20 > + sizeof (EFI_SMM_IO_TRAP_REGISTER_CONTEXT) >=20 > + ); >=20 > + return IoTrapUnRegisterHelper (DispatchHandle); >=20 > +} >=20 > + >=20 > +/** >=20 > + Register a new IO Trap Ex SMI dispatch function. >=20 > + >=20 > + @param[in] This Pointer to the > IO_TRAP_EX_DISPATCH_PROTOCOL instance. >=20 > + @param[in] DispatchFunction Pointer to dispatch function to be inv= oked > for >=20 > + this SMI source. >=20 > + @param[in] RegisterContext Pointer to the dispatch function's con= text. >=20 > + The caller fills this context in befor= e calling >=20 > + the register function to indicate to t= he register >=20 > + function the IO trap Ex SMI source for= which the dispatch >=20 > + function should be invoked. This MUST= not be NULL. >=20 > + @param[out] DispatchHandle Handle of dispatch function. >=20 > + >=20 > + @retval EFI_SUCCESS The dispatch function has been success= fully >=20 > + registered and the SMI source has been= enabled. >=20 > + @retval EFI_OUT_OF_RESOURCES Insufficient resources are available >=20 > + @retval EFI_INVALID_PARAMETER Address requested is already in use. >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +IoTrapExRegister ( >=20 > + IN IO_TRAP_EX_DISPATCH_PROTOCOL *This, >=20 > + IN IO_TRAP_EX_DISPATCH_CALLBACK DispatchFunction, >=20 > + IN IO_TRAP_EX_REGISTER_CONTEXT *RegisterContext, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + >=20 > + DEBUG ((DEBUG_INFO, "PchSmmIoTrapExRegister\n")); >=20 > + // >=20 > + // Return error if length is less than 4 and not power of 2. >=20 > + // >=20 > + if ((RegisterContext->Length < 4) || ((RegisterContext->Length & > (RegisterContext->Length - 1)) !=3D 0)) { >=20 > + DEBUG ((DEBUG_ERROR, "The Dispatch Length is not power of 2 \n")); >=20 > + return EFI_INVALID_PARAMETER; >=20 > + } >=20 > + >=20 > + Status =3D IoTrapRegisterHelper ( >=20 > + DispatchHandle, >=20 > + NULL, >=20 > + DispatchFunction, >=20 > + &(RegisterContext->Address), >=20 > + RegisterContext->Length, >=20 > + RegisterContext->Type, >=20 > + RegisterContext->ByteEnable, >=20 > + RegisterContext->ByteEnableMask); >=20 > + >=20 > + if (!EFI_ERROR (Status)) { >=20 > + SmiHandlerProfileRegisterHandler ( >=20 > + &gIoTrapExDispatchProtocolGuid, >=20 > + (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, >=20 > + (UINTN)RETURN_ADDRESS (0), >=20 > + RegisterContext, >=20 > + sizeof (*RegisterContext) >=20 > + ); >=20 > + } >=20 > + return Status; >=20 > +} >=20 > + >=20 > +/** >=20 > + Unregister a SMI source dispatch function. >=20 > + This function is unsupported. >=20 > + >=20 > + @param[in] This Pointer to the > IO_TRAP_EX_DISPATCH_PROTOCOL instance. >=20 > + @param[in] DispatchHandle Handle of dispatch function to deregis= ter. >=20 > + >=20 > + @retval EFI_UNSUPPORTED The function is unsupported. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +IoTrapExUnRegister ( >=20 > + IN IO_TRAP_EX_DISPATCH_PROTOCOL *This, >=20 > + IN EFI_HANDLE DispatchHandle >=20 > + ) >=20 > +{ >=20 > + IO_TRAP_RECORD *RecordToDelete; >=20 > + >=20 > + RecordToDelete =3D IO_TRAP_RECORD_FROM_LINK (DispatchHandle); >=20 > + SmiHandlerProfileUnregisterHandler ( >=20 > + &gIoTrapExDispatchProtocolGuid, >=20 > + RecordToDelete->IoTrapCallback, >=20 > + &RecordToDelete->Context, >=20 > + sizeof (RecordToDelete->Context) >=20 > + ); >=20 > + return IoTrapUnRegisterHelper (DispatchHandle); >=20 > +} >=20 > + >=20 > +/** >=20 > + Pause IoTrap callback function. >=20 > + >=20 > + This function disables the SMI enable of IoTrap according to the > DispatchHandle, >=20 > + which is returned by IoTrap callback registration. It only supports th= e > DispatchHandle >=20 > + with MergeDisable TRUE and address not zero. >=20 > + >=20 > + NOTE: This call does not guarantee all pending IO cycles to be synchro= nized >=20 > + and pending IO cycles issued before this call might not be trapp= ed. >=20 > + >=20 > + @param[in] This Pointer to the > PCH_SMM_IO_TRAP_CONTROL_PROTOCOL instance. >=20 > + @param[in] DispatchHandle Handle of the child service to change = state. >=20 > + >=20 > + @retval EFI_SUCCESS This operation is complete. >=20 > + @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid. >=20 > + @retval EFI_ACCESS_DENIED The SMI status is alrady PAUSED. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +IoTrapControlPause ( >=20 > + IN PCH_SMM_IO_TRAP_CONTROL_PROTOCOL *This, >=20 > + IN EFI_HANDLE DispatchHandle >=20 > + ) >=20 > +{ >=20 > + IO_TRAP_RECORD *IoTrapRecord; >=20 > + UINT32 IoTrapRegLowDword; >=20 > + UINT32 IoTrapRegHighDword; >=20 > + EFI_PHYSICAL_ADDRESS BaseAddress; >=20 > + UINT32 UsedLength; >=20 > + UINT8 TrapHandlerNum; >=20 > + BOOLEAN TempMergeDisable; >=20 > + BOOLEAN DisableIoTrap; >=20 > + >=20 > + if (DispatchHandle =3D=3D 0) { >=20 > + return EFI_INVALID_PARAMETER; >=20 > + } >=20 > + >=20 > + IoTrapRecord =3D IO_TRAP_RECORD_FROM_LINK (DispatchHandle); >=20 > + >=20 > + if (IoTrapRecord->Context.Address) { >=20 > + TempMergeDisable =3DTRUE; >=20 > + }else { >=20 > + TempMergeDisable =3D FALSE; >=20 > + } >=20 > + >=20 > + if ((IoTrapRecord->Signature !=3D IO_TRAP_RECORD_SIGNATURE) || >=20 > + (TempMergeDisable !=3D TRUE) || >=20 > + (IoTrapRecord->Context.Address =3D=3D 0) || >=20 > + (IoTrapRecord->Context.Length =3D=3D 0)) { >=20 > + return EFI_INVALID_PARAMETER; >=20 > + } >=20 > + >=20 > + for (TrapHandlerNum =3D 0; TrapHandlerNum < IO_TRAP_HANDLER_NUM; > TrapHandlerNum++) { >=20 > + // >=20 > + // This IoTrap register should be merge disabled. >=20 > + // >=20 > + if (mIoTrapData.Entry[TrapHandlerNum].MergeDisable !=3D TRUE) { >=20 > + continue; >=20 > + } >=20 > + IoTrapRegLowDword =3D PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 > + TrapHandlerNum * 8); >=20 > + IoTrapRegHighDword =3D PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 > + TrapHandlerNum * 8 + 4); >=20 > + // >=20 > + // Depending on the usage, we will obtain the UsedLength and > BaseAddress differently >=20 > + // If the registered trap length is less than 4, we obtain the lengt= h from > Byte Enable Mask >=20 > + // In the other hand, we obtain the length from Address Mask >=20 > + // >=20 > + if (ByteEnableMaskFromHighDword (IoTrapRegHighDword) !=3D 0xF) { >=20 > + UsedLength =3D (UINT32) (HighBitSet32 (IoTrapRegHighDword & 0xF0) = - > LowBitSet32 (IoTrapRegHighDword & 0xF0) + 1); >=20 > + BaseAddress =3D AddressFromLowDword (IoTrapRegLowDword) + > LowBitSet32 (ByteEnableMaskFromHighDword (IoTrapRegHighDword)); >=20 > + } else { >=20 > + UsedLength =3D LengthFromLowDword (IoTrapRegLowDword); >=20 > + BaseAddress =3D AddressFromLowDword (IoTrapRegLowDword); >=20 > + } >=20 > + >=20 > + // >=20 > + // The address and length of record matches the IoTrap register's. >=20 > + // >=20 > + DisableIoTrap =3D FALSE; >=20 > + if ((IoTrapRecord->IoTrapExCallback !=3D NULL) && >=20 > + IsIoTrapExContentMatched (IoTrapRecord, IoTrapRegLowDword, > IoTrapRegHighDword)) { >=20 > + DisableIoTrap =3D TRUE; >=20 > + } else if ((BaseAddress =3D=3D IoTrapRecord->Context.Address) && >=20 > + (UsedLength =3D=3D IoTrapRecord->Context.Length )) { >=20 > + DisableIoTrap =3D TRUE; >=20 > + } >=20 > + >=20 > + if (DisableIoTrap) { >=20 > + // >=20 > + // Check if status matched. >=20 > + // If this is already Paused, return warning status. >=20 > + // >=20 > + if ((IoTrapRegLowDword & B_PSTH_PCR_TRPREG_TSE) =3D=3D 0) { >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + // >=20 > + // Clear IoTrap register SMI enable bit >=20 > + // >=20 > + IoTrapRegLowDword &=3D (~B_PSTH_PCR_TRPREG_TSE); >=20 > + SetIoTrapLowDword (TrapHandlerNum, IoTrapRegLowDword, FALSE); >=20 > + // >=20 > + // Also clear pending IOTRAP status. >=20 > + // >=20 > + ClearPendingIoTrapStatus (TrapHandlerNum); >=20 > + return EFI_SUCCESS; >=20 > + } >=20 > + } >=20 > + return EFI_INVALID_PARAMETER; >=20 > +} >=20 > + >=20 > +/** >=20 > + Resume IoTrap callback function. >=20 > + >=20 > + This function enables the SMI enable of IoTrap according to the > DispatchHandle, >=20 > + which is returned by IoTrap callback registration. It only supports th= e > DispatchHandle >=20 > + with MergeDisable TRUE and address not zero. >=20 > + >=20 > + @param[in] This Pointer to the > PCH_SMM_IO_TRAP_CONTROL_PROTOCOL instance. >=20 > + @param[in] DispatchHandle Handle of the child service to change = state. >=20 > + >=20 > + @retval EFI_SUCCESS This operation is complete. >=20 > + @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid. >=20 > + @retval EFI_ACCESS_DENIED The SMI status is alrady RESUMED. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +IoTrapControlResume ( >=20 > + IN PCH_SMM_IO_TRAP_CONTROL_PROTOCOL *This, >=20 > + IN EFI_HANDLE DispatchHandle >=20 > + ) >=20 > +{ >=20 > + IO_TRAP_RECORD *IoTrapRecord; >=20 > + UINT32 IoTrapRegLowDword; >=20 > + UINT32 IoTrapRegHighDword; >=20 > + EFI_PHYSICAL_ADDRESS BaseAddress; >=20 > + UINT32 UsedLength; >=20 > + UINT8 TrapHandlerNum; >=20 > + BOOLEAN TempMergeDisable; >=20 > + BOOLEAN EnableIoTrap; >=20 > + >=20 > + if (DispatchHandle =3D=3D 0) { >=20 > + return EFI_INVALID_PARAMETER; >=20 > + } >=20 > + IoTrapRecord =3D IO_TRAP_RECORD_FROM_LINK (DispatchHandle); >=20 > + >=20 > + if (IoTrapRecord->Context.Address) { >=20 > + TempMergeDisable =3D TRUE; >=20 > + }else { >=20 > + TempMergeDisable =3D FALSE; >=20 > + } >=20 > + >=20 > + if ((IoTrapRecord->Signature !=3D IO_TRAP_RECORD_SIGNATURE) || >=20 > + (TempMergeDisable !=3D TRUE) || >=20 > + (IoTrapRecord->Context.Address =3D=3D 0) || >=20 > + (IoTrapRecord->Context.Length =3D=3D 0)) { >=20 > + return EFI_INVALID_PARAMETER; >=20 > + } >=20 > + >=20 > + for (TrapHandlerNum =3D 0; TrapHandlerNum < IO_TRAP_HANDLER_NUM; > TrapHandlerNum++) { >=20 > + // >=20 > + // This IoTrap register should be merge disabled. >=20 > + // >=20 > + if (mIoTrapData.Entry[TrapHandlerNum].MergeDisable !=3D TRUE) { >=20 > + continue; >=20 > + } >=20 > + IoTrapRegLowDword =3D PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 > + TrapHandlerNum * 8); >=20 > + IoTrapRegHighDword =3D PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 > + TrapHandlerNum * 8 + 4); >=20 > + // >=20 > + // Depending on the usage, we will obtain the UsedLength and > BaseAddress differently >=20 > + // If the registered trap length is less than 4, we obtain the lengt= h from > Byte Enable Mask >=20 > + // In the other hand, we obtain the length from Address Mask >=20 > + // >=20 > + if (ByteEnableMaskFromHighDword (IoTrapRegHighDword) !=3D 0xF) { >=20 > + UsedLength =3D (UINT32) (HighBitSet32 (IoTrapRegHighDword & 0xF0)= - > LowBitSet32 (IoTrapRegHighDword & 0xF0) + 1); >=20 > + BaseAddress =3D AddressFromLowDword (IoTrapRegLowDword) + > LowBitSet32 (ByteEnableMaskFromHighDword (IoTrapRegHighDword)); >=20 > + } else { >=20 > + UsedLength =3D LengthFromLowDword (IoTrapRegLowDword); >=20 > + BaseAddress =3D AddressFromLowDword (IoTrapRegLowDword); >=20 > + } >=20 > + >=20 > + // >=20 > + // The address and length of record matches the IoTrap register's. >=20 > + // >=20 > + EnableIoTrap =3D FALSE; >=20 > + if ((IoTrapRecord->IoTrapExCallback !=3D NULL) && >=20 > + IsIoTrapExContentMatched (IoTrapRecord, IoTrapRegLowDword, > IoTrapRegHighDword)) { >=20 > + EnableIoTrap =3D TRUE; >=20 > + } else if ((BaseAddress =3D=3D IoTrapRecord->Context.Address) && >=20 > + (UsedLength =3D=3D IoTrapRecord->Context.Length )) { >=20 > + EnableIoTrap =3D TRUE; >=20 > + } >=20 > + >=20 > + if (EnableIoTrap) { >=20 > + // >=20 > + // Check if status matched. >=20 > + // If this is already Resume, return warning status. >=20 > + // >=20 > + if ((IoTrapRegLowDword & B_PSTH_PCR_TRPREG_TSE) !=3D 0) { >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + // >=20 > + // Set IoTrap register SMI enable bit >=20 > + // >=20 > + IoTrapRegLowDword |=3D (B_PSTH_PCR_TRPREG_TSE); >=20 > + SetIoTrapLowDword (TrapHandlerNum, IoTrapRegLowDword, FALSE); >=20 > + return EFI_SUCCESS; >=20 > + } >=20 > + } >=20 > + return EFI_INVALID_PARAMETER; >=20 > +} >=20 > + >=20 > +/** >=20 > + The IoTrap module abstracts PCH I/O trapping capabilities for other dr= ivers. >=20 > + This driver manages the limited I/O trap resources. >=20 > + >=20 > + @param[in] ImageHandle Image handle for this driver ima= ge >=20 > + >=20 > + @retval EFI_SUCCESS Driver initialization completed = successfully >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +InstallIoTrap ( >=20 > + IN EFI_HANDLE ImageHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + PCH_NVS_AREA_PROTOCOL *PchNvsAreaProtocol; >=20 > + UINTN TrapHandlerNum; >=20 > + >=20 > + // >=20 > + // Initialize the EFI SMM driver library >=20 > + // >=20 > + mDriverImageHandle =3D ImageHandle; >=20 > + >=20 > + // >=20 > + // Initialize the IO TRAP protocol we produce >=20 > + // >=20 > + mIoTrapData.Signature =3D IO_TRAP_INSTANCE_SIGNATURE; >=20 > + mIoTrapData.EfiSmmIoTrapDispatchProtocol.Register =3D IoTrapRegister= ; >=20 > + mIoTrapData.EfiSmmIoTrapDispatchProtocol.UnRegister =3D > IoTrapUnRegister; >=20 > + >=20 > + // >=20 > + // Initialize the IO TRAP EX protocol >=20 > + // >=20 > + mIoTrapData.IoTrapExDispatchProtocol.Register =3D IoTrapExRegist= er; >=20 > + mIoTrapData.IoTrapExDispatchProtocol.UnRegister =3D > IoTrapExUnRegister; >=20 > + >=20 > + // >=20 > + // Initialize the IO TRAP control protocol. >=20 > + // >=20 > + mIoTrapData.PchSmmIoTrapControlProtocol.Pause =3D > IoTrapControlPause; >=20 > + mIoTrapData.PchSmmIoTrapControlProtocol.Resume =3D > IoTrapControlResume; >=20 > + >=20 > + for (TrapHandlerNum =3D 0; TrapHandlerNum < IO_TRAP_HANDLER_NUM; > TrapHandlerNum++) { >=20 > + // >=20 > + // Initialize IO TRAP Callback DataBase >=20 > + // >=20 > + InitializeListHead > (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase)); >=20 > + } >=20 > + mIoTrapData.Entry[0].CallbackDispatcher =3D IoTrapDispatcher0; >=20 > + mIoTrapData.Entry[1].CallbackDispatcher =3D IoTrapDispatcher1; >=20 > + mIoTrapData.Entry[2].CallbackDispatcher =3D IoTrapDispatcher2; >=20 > + mIoTrapData.Entry[3].CallbackDispatcher =3D IoTrapDispatcher3; >=20 > + >=20 > + // >=20 > + // Get address of PchNvs structure for later use >=20 > + // >=20 > + Status =3D gBS->LocateProtocol (&gPchNvsAreaProtocolGuid, NULL, (VOID > **) &PchNvsAreaProtocol); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + mPchNvsArea =3D PchNvsAreaProtocol->Area; >=20 > + >=20 > + // >=20 > + // Install protocol interface >=20 > + // >=20 > + mIoTrapData.Handle =3D NULL; >=20 > + Status =3D gSmst->SmmInstallProtocolInterface ( >=20 > + &mIoTrapData.Handle, >=20 > + &gEfiSmmIoTrapDispatch2ProtocolGuid, >=20 > + EFI_NATIVE_INTERFACE, >=20 > + &mIoTrapData.EfiSmmIoTrapDispatchProtocol >=20 > + ); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + Status =3D gSmst->SmmInstallProtocolInterface ( >=20 > + &mIoTrapData.Handle, >=20 > + &gIoTrapExDispatchProtocolGuid, >=20 > + EFI_NATIVE_INTERFACE, >=20 > + &mIoTrapData.IoTrapExDispatchProtocol >=20 > + ); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + Status =3D gSmst->SmmInstallProtocolInterface ( >=20 > + &mIoTrapData.Handle, >=20 > + &gPchSmmIoTrapControlGuid, >=20 > + EFI_NATIVE_INTERFACE, >=20 > + &mIoTrapData.PchSmmIoTrapControlProtocol >=20 > + ); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > diff --git > a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.h > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.h > new file mode 100644 > index 0000000000..e69d2e2d4d > --- /dev/null > +++ > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.h > @@ -0,0 +1,226 @@ > +/** @file >=20 > + Defines and prototypes for the IoTrap SMM driver >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > +#ifndef _IO_TRAP_H_ >=20 > +#define _IO_TRAP_H_ >=20 > + >=20 > +// >=20 > +// Include files >=20 > +// >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > + >=20 > +#define IO_TRAP_HANDLER_NUM 4 >=20 > + >=20 > +// >=20 > +// Driver private data >=20 > +// >=20 > +#define IO_TRAP_INSTANCE_SIGNATURE SIGNATURE_32 ('I', 'O', 'T', 'P') >=20 > + >=20 > +typedef struct { >=20 > + EFI_HANDLE IoTrapHandle; >=20 > + /** >=20 > + The callback linked list for all "merged" IoTrap callbacks. >=20 > + **/ >=20 > + LIST_ENTRY CallbackDataBase; >=20 > + /** >=20 > + The IoTrap IO range used length tracking for "merged" IoTrap registe= r. >=20 > + **/ >=20 > + UINT32 TrapUsedLength; >=20 > + /** >=20 > + Determine if IoTrap can be merged with other IoTrap callbacks. >=20 > + If MergeDisable is TRUE, then there is only one callback function fo= r one > IoTrap register. >=20 > + If MergeDisable is FALSE, then there are multiple callbacks in the > "CallbackDataBase" for one IoTrap register. >=20 > + **/ >=20 > + BOOLEAN MergeDisable; >=20 > + /** >=20 > + Indicator of the resource tracking in ACPI. >=20 > + If the registration address is not 0, it's caller's responsibility t= o reserve the > IO resource in ACPI. >=20 > + **/ >=20 > + BOOLEAN ReservedAcpiIoResource; >=20 > + /** >=20 > + Dispatcher for each IoTrap register. >=20 > + **/ >=20 > + PCH_SMI_DISPATCH_CALLBACK CallbackDispatcher; >=20 > +} IO_TRAP_ENTRY_ATTRIBUTES; >=20 > + >=20 > +typedef struct { >=20 > + UINT32 Signature; >=20 > + EFI_HANDLE Handle; >=20 > + EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL > EfiSmmIoTrapDispatchProtocol; >=20 > + PCH_SMM_IO_TRAP_CONTROL_PROTOCOL > PchSmmIoTrapControlProtocol; ///< Protocol for runtime control the > IoTrap state >=20 > + IO_TRAP_EX_DISPATCH_PROTOCOL IoTrapExDispatchProtocol; > ///< Protocol for IoTrap Extension >=20 > + IO_TRAP_ENTRY_ATTRIBUTES Entry[IO_TRAP_HANDLER_NUM]; >=20 > +} IO_TRAP_INSTANCE; >=20 > + >=20 > +#define IO_TRAP_INSTANCE_FROM_THIS(a) CR (a, IO_TRAP_INSTANCE, > EfiSmmIoTrapDispatchProtocol, IO_TRAP_INSTANCE_SIGNATURE) >=20 > + >=20 > +/// >=20 > +/// "IOTRAP" RECORD >=20 > +/// Linked list data structures >=20 > +/// >=20 > +#define IO_TRAP_RECORD_SIGNATURE SIGNATURE_32 ('I', 'T', 'R', 'C') >=20 > + >=20 > +typedef struct _IO_TRAP_RECORD { >=20 > + UINT32 Signature; >=20 > + LIST_ENTRY Link; >=20 > + IO_TRAP_EX_REGISTER_CONTEXT Context; >=20 > + /** >=20 > + The callback function of IoTrap protocol. >=20 > + This also indicate it's the record for IoTrapProtocol. >=20 > + Only one of IoTrapCallback or IoTrapExCallback is valid at a time. >=20 > + **/ >=20 > + EFI_SMM_HANDLER_ENTRY_POINT2 IoTrapCallback; >=20 > + /** >=20 > + The callback function of IoTrapEx protocol >=20 > + This also indicate it's the record for IoTrapExProtocol. >=20 > + Only one of IoTrapCallback or IoTrapExCallback is valid at a time. >=20 > + **/ >=20 > + IO_TRAP_EX_DISPATCH_CALLBACK IoTrapExCallback; >=20 > + UINT8 IoTrapNumber; >=20 > +} IO_TRAP_RECORD; >=20 > + >=20 > +#define IO_TRAP_RECORD_FROM_LINK(_record) CR (_record, > IO_TRAP_RECORD, Link, IO_TRAP_RECORD_SIGNATURE) >=20 > + >=20 > +// >=20 > +// Prototypes >=20 > +// >=20 > +/** >=20 > + The IoTrap module abstracts PCH I/O trapping capabilities for other dr= ivers. >=20 > + This driver manages the limited I/O trap resources. >=20 > + >=20 > + @param[in] ImageHandle Image handle for this driver ima= ge >=20 > + >=20 > + @retval EFI_SUCCESS Driver initialization completed = successfully >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +InstallIoTrap ( >=20 > + IN EFI_HANDLE ImageHandle >=20 > + ); >=20 > + >=20 > +/** >=20 > + Register a new IO Trap SMI dispatch function with a parent SMM driver. >=20 > + The caller will provide information about the IO trap characteristics = via >=20 > + the context. This includes base address, length, read vs. r/w, etc. >=20 > + This function will autoallocate IO base address from a common pool if = the > base address is 0, >=20 > + and the RegisterContext Address field will be updated. >=20 > + The service will not perform GCD allocation if the base address is non= -zero. >=20 > + In this case, the caller is responsible for the existence and allocati= on of the >=20 > + specific IO range. >=20 > + This function looks for the suitable handler and Register a new IoTrap > handler >=20 > + if the IO Trap handler is not used. It also enable the IO Trap Range t= o > generate >=20 > + SMI. >=20 > + >=20 > + @param[in] This Pointer to the > EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL instance. >=20 > + @param[in] DispatchFunction Pointer to dispatch function to be inv= oked > for >=20 > + this SMI source. >=20 > + @param[in, out] RegisterContext Pointer to the dispatch function's > context. >=20 > + The caller fills this context in befor= e calling >=20 > + the register function to indicate to t= he register >=20 > + function the IO trap SMI source for wh= ich the dispatch >=20 > + function should be invoked. This may = not be NULL. >=20 > + If the registration address is not 0, = it's caller's responsibility >=20 > + to reserve the IO resource in ACPI. >=20 > + @param[out] DispatchHandle Handle of dispatch function, for when > interfacing >=20 > + with the parent SMM driver, will be th= e address of linked >=20 > + list link in the call back record. Th= is may not be NULL. >=20 > + >=20 > + @retval EFI_SUCCESS The dispatch function has been success= fully >=20 > + registered and the SMI source has been= enabled. >=20 > + @retval EFI_DEVICE_ERROR The driver was unable to enable the SM= I > source. >=20 > + @retval EFI_OUT_OF_RESOURCES Insufficient resources are available >=20 > + @retval EFI_INVALID_PARAMETER Address requested is already in use. >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +IoTrapRegister ( >=20 > + IN CONST EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL *This, >=20 > + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, >=20 > + IN OUT EFI_SMM_IO_TRAP_REGISTER_CONTEXT *RegisterContext, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ); >=20 > + >=20 > +/** >=20 > + Unregister a child SMI source dispatch function with a parent SMM driv= er. >=20 > + >=20 > + @param[in] This Pointer to the > EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL instance. >=20 > + @param[in] DispatchHandle Handle of dispatch function to deregis= ter. >=20 > + >=20 > + @retval EFI_SUCCESS The dispatch function has been success= fully >=20 > + unregistered and the SMI source has be= en disabled >=20 > + if there are no other registered child= dispatch >=20 > + functions for this SMI source. >=20 > + @retval EFI_INVALID_PARAMETER Handle is invalid. >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +IoTrapUnRegister ( >=20 > + IN CONST EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL *This, >=20 > + IN EFI_HANDLE DispatchHandle >=20 > + ); >=20 > + >=20 > +/** >=20 > + This I/O Trap SMI handler invokes the ACPI reference code to handle th= e > SMI. >=20 > + It currently assumes it owns all of the IO trap SMI. >=20 > + >=20 > + @param[in] DispatchHandle Not used >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +IoTrapCallback ( >=20 > + IN EFI_HANDLE DispatchHandle >=20 > + ); >=20 > + >=20 > +/** >=20 > + Pause IoTrap callback function. >=20 > + >=20 > + This function disables the SMI enable of IoTrap according to the > DispatchHandle, >=20 > + which is returned by IoTrap callback registration. It only supports th= e > DispatchHandle >=20 > + with MergeDisable TRUE and address not zero. >=20 > + >=20 > + @param[in] This Pointer to the > PCH_SMM_IO_TRAP_CONTROL_PROTOCOL instance. >=20 > + @param[in] DispatchHandle Handle of the child service to change = state. >=20 > + >=20 > + @retval EFI_SUCCESS This operation is complete. >=20 > + @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid. >=20 > + @retval EFI_ACCESS_DENIED The SMI status is alrady PAUSED. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +IoTrapControlPause ( >=20 > + IN PCH_SMM_IO_TRAP_CONTROL_PROTOCOL * This, >=20 > + IN EFI_HANDLE DispatchHandle >=20 > + ); >=20 > + >=20 > +/** >=20 > + Resume IoTrap callback function. >=20 > + >=20 > + This function enables the SMI enable of IoTrap according to the > DispatchHandle, >=20 > + which is returned by IoTrap callback registration. It only supports th= e > DispatchHandle >=20 > + with MergeDisable TRUE and address not zero. >=20 > + >=20 > + @param[in] This Pointer to the > PCH_SMM_IO_TRAP_CONTROL_PROTOCOL instance. >=20 > + @param[in] DispatchHandle Handle of the child service to change = state. >=20 > + >=20 > + @retval EFI_SUCCESS This operation is complete. >=20 > + @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid. >=20 > + @retval EFI_ACCESS_DENIED The SMI status is alrady RESUMED. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +IoTrapControlResume ( >=20 > + IN PCH_SMM_IO_TRAP_CONTROL_PROTOCOL * This, >=20 > + IN EFI_HANDLE DispatchHandle >=20 > + ); >=20 > + >=20 > +#endif >=20 > diff --git > a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispa > tch.c > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispa > tch.c > new file mode 100644 > index 0000000000..affbe94eb7 > --- /dev/null > +++ > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispa > tch.c > @@ -0,0 +1,2442 @@ > +/** @file >=20 > + This function handle the register/unregister of PCH specific SMI event= s. >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > +#include "PchSmmHelpers.h" >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include "PchSmiHelper.h" >=20 > + >=20 > +/** >=20 > + The internal function used to create and insert a database record >=20 > + for SMI record of Pch Smi types. >=20 > + >=20 > + @param[in] SrcDesc The pointer to the SMI source de= scription >=20 > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source >=20 > + @param[in] PchSmiType Specific SMI type of PCH SMI >=20 > + @param[out] DispatchHandle Handle of dispatch function to r= egister. >=20 > + >=20 > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description >=20 > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record >=20 > + @retval EFI_SUCCESS The database record is created s= uccessfully. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +PchSmiRecordInsert ( >=20 > + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc, >=20 > + IN PCH_SMI_CALLBACK_FUNCTIONS DispatchFunction, >=20 > + IN PCH_SMI_TYPES PchSmiType, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + DATABASE_RECORD Record; >=20 > + >=20 > + if (SrcDesc =3D=3D NULL) { >=20 > + return EFI_INVALID_PARAMETER; >=20 > + } >=20 > + >=20 > + ZeroMem (&Record, sizeof (DATABASE_RECORD)); >=20 > + // >=20 > + // Gather information about the registration request >=20 > + // >=20 > + Record.Signature =3D DATABASE_RECORD_SIGNATURE; >=20 > + Record.PchSmiCallback =3D DispatchFunction; >=20 > + Record.ProtocolType =3D PchSmiDispatchType; >=20 > + Record.PchSmiType =3D PchSmiType; >=20 > + >=20 > + CopyMem (&Record.SrcDesc, SrcDesc, sizeof > (PCH_SMM_SOURCE_DESC)); >=20 > + Status =3D SmmCoreInsertRecord ( >=20 > + &Record, >=20 > + DispatchHandle >=20 > + ); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > + >=20 > + >=20 > +// >=20 > +// TCO_STS bit that needs to be cleared >=20 > +// >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mDescSrcTcoSts =3D { >=20 > + PCH_SMM_NO_FLAGS, >=20 > + { >=20 > + NULL_BIT_DESC_INITIALIZER, >=20 > + NULL_BIT_DESC_INITIALIZER >=20 > + }, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_TCO >=20 > + } >=20 > + }, >=20 > + NULL_BIT_DESC_INITIALIZER >=20 > +}; >=20 > + >=20 > +/** >=20 > + Clear the TCO SMI status bit and block after the SMI handling is done >=20 > + >=20 > + @param[in] SrcDesc Pointer to the PCH SMI source de= scription > table >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +PchTcoSmiClearSourceAndBlock ( >=20 > + CONST PCH_SMM_SOURCE_DESC *SrcDesc >=20 > + ) >=20 > +{ >=20 > + PchSmmClearSourceAndBlock (SrcDesc); >=20 > + // >=20 > + // Any TCO-based status bits require special handling. >=20 > + // SMI_STS.TCO_STS must be cleared in addition to the status bit in th= e > TCO registers >=20 > + // >=20 > + PchSmmClearSource (&mDescSrcTcoSts); >=20 > +} >=20 > + >=20 > +/** >=20 > + Clear the TCO SMI status bit after the SMI handling is done >=20 > + >=20 > + @param[in] SrcDesc Pointer to the PCH SMI source de= scription > table >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +PchTcoSmiClearSource ( >=20 > + CONST PCH_SMM_SOURCE_DESC *SrcDesc >=20 > + ) >=20 > +{ >=20 > + PchSmmClearSource (SrcDesc); >=20 > + // >=20 > + // Any TCO-based status bits require special handling. >=20 > + // SMI_STS.TCO_STS must be cleared in addition to the status bit in th= e > TCO registers >=20 > + // >=20 > + PchSmmClearSource (&mDescSrcTcoSts); >=20 > +} >=20 > + >=20 > +/** >=20 > + Initialize Source descriptor structure >=20 > + >=20 > + @param[in] SrcDesc Pointer to the PCH SMI source d= escription > table >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +NullInitSourceDesc ( >=20 > + PCH_SMM_SOURCE_DESC *SrcDesc >=20 > + ) >=20 > +{ >=20 > + ZeroMem (SrcDesc, sizeof (PCH_SMM_SOURCE_DESC)); >=20 > + SrcDesc->En[0].Reg.Type =3D PCH_SMM_ADDR_TYPE_NULL; >=20 > + SrcDesc->En[1].Reg.Type =3D PCH_SMM_ADDR_TYPE_NULL; >=20 > + SrcDesc->Sts[0].Reg.Type =3D PCH_SMM_ADDR_TYPE_NULL; >=20 > + SrcDesc->PmcSmiSts.Reg.Type =3D PCH_SMM_ADDR_TYPE_NULL; >=20 > +} >=20 > + >=20 > +// >=20 > +// Mch srcdesc >=20 > +// >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescMch =3D { >=20 > + PCH_SMM_NO_FLAGS, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_EN} >=20 > + }, >=20 > + S_ACPI_IO_SMI_EN, >=20 > + N_ACPI_IO_SMI_EN_TCO >=20 > + }, >=20 > + NULL_BIT_DESC_INITIALIZER >=20 > + }, >=20 > + { >=20 > + { >=20 > + { >=20 > + TCO_ADDR_TYPE, >=20 > + {R_TCO_IO_TCO1_STS} >=20 > + }, >=20 > + S_TCO_IO_TCO1_STS, >=20 > + N_TCO_IO_TCO1_STS_DMISMI >=20 > + } >=20 > + }, >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_TCO >=20 > + } >=20 > +}; >=20 > + >=20 > +/** >=20 > + The register function used to register SMI handler of MCH event. >=20 > + >=20 > + @param[in] This The pointer to the protocol itse= lf >=20 > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source >=20 > + @param[out] DispatchHandle Handle of dispatch function to r= egister. >=20 > + >=20 > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description >=20 > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record >=20 > + @retval EFI_SUCCESS The database record is created s= uccessfully. >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchTcoSmiMchRegister ( >=20 > + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + DATABASE_RECORD *Record; >=20 > + >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + Status =3D PchSmiRecordInsert ( >=20 > + &mSrcDescMch, >=20 > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, >=20 > + PchTcoSmiMchType, >=20 > + DispatchHandle >=20 > + ); >=20 > + if (!EFI_ERROR (Status)) { >=20 > + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle); >=20 > + Record->ClearSource =3D PchTcoSmiClearSource; >=20 > + PchSmmClearSource (&Record->SrcDesc); >=20 > + PchSmmEnableSource (&Record->SrcDesc); >=20 > + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); >=20 > + } >=20 > + return Status; >=20 > +} >=20 > + >=20 > +// >=20 > +// TcoTimeout srcdesc >=20 > +// >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescTcoTimeout =3D { >=20 > + PCH_SMM_NO_FLAGS, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_EN} >=20 > + }, >=20 > + S_ACPI_IO_SMI_EN, >=20 > + N_ACPI_IO_SMI_EN_TCO >=20 > + }, >=20 > + NULL_BIT_DESC_INITIALIZER >=20 > + }, >=20 > + { >=20 > + { >=20 > + { >=20 > + TCO_ADDR_TYPE, >=20 > + {R_TCO_IO_TCO1_STS} >=20 > + }, >=20 > + S_TCO_IO_TCO1_STS, >=20 > + N_TCO_IO_TCO1_STS_TIMEOUT >=20 > + } >=20 > + }, >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_TCO >=20 > + } >=20 > +}; >=20 > + >=20 > +/** >=20 > + The register function used to register SMI handler of TcoTimeout event= . >=20 > + >=20 > + @param[in] This The pointer to the protocol itse= lf >=20 > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source >=20 > + @param[out] DispatchHandle Handle of dispatch function to r= egister. >=20 > + >=20 > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description >=20 > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record >=20 > + @retval EFI_SUCCESS The database record is created s= uccessfully. >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchTcoSmiTcoTimeoutRegister ( >=20 > + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + DATABASE_RECORD *Record; >=20 > + >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + Status =3D PchSmiRecordInsert ( >=20 > + &mSrcDescTcoTimeout, >=20 > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, >=20 > + PchTcoSmiTcoTimeoutType, >=20 > + DispatchHandle >=20 > + ); >=20 > + if (!EFI_ERROR (Status)) { >=20 > + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle); >=20 > + Record->ClearSource =3D PchTcoSmiClearSource; >=20 > + PchSmmClearSource (&Record->SrcDesc); >=20 > + PchSmmEnableSource (&Record->SrcDesc); >=20 > + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); >=20 > + } >=20 > + return Status; >=20 > +} >=20 > + >=20 > +// >=20 > +// OsTco srcdesc >=20 > +// >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescOsTco =3D { >=20 > + PCH_SMM_NO_FLAGS, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_EN} >=20 > + }, >=20 > + S_ACPI_IO_SMI_EN, >=20 > + N_ACPI_IO_SMI_EN_TCO >=20 > + }, >=20 > + NULL_BIT_DESC_INITIALIZER >=20 > + }, >=20 > + { >=20 > + { >=20 > + { >=20 > + TCO_ADDR_TYPE, >=20 > + {R_TCO_IO_TCO1_STS} >=20 > + }, >=20 > + S_TCO_IO_TCO1_STS, >=20 > + N_TCO_IO_TCO1_STS_SW_TCO_SMI >=20 > + } >=20 > + }, >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_TCO >=20 > + } >=20 > +}; >=20 > + >=20 > +/** >=20 > + The register function used to register SMI handler of OS TCO event. >=20 > + >=20 > + @param[in] This The pointer to the protocol itse= lf >=20 > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source >=20 > + @param[out] DispatchHandle Handle of dispatch function to r= egister. >=20 > + >=20 > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description >=20 > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record >=20 > + @retval EFI_SUCCESS The database record is created s= uccessfully. >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchTcoSmiOsTcoRegister ( >=20 > + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + DATABASE_RECORD *Record; >=20 > + >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + Status =3D PchSmiRecordInsert ( >=20 > + &mSrcDescOsTco, >=20 > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, >=20 > + PchTcoSmiOsTcoType, >=20 > + DispatchHandle >=20 > + ); >=20 > + if (!EFI_ERROR (Status)) { >=20 > + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle); >=20 > + Record->ClearSource =3D PchTcoSmiClearSource; >=20 > + PchSmmClearSource (&Record->SrcDesc); >=20 > + PchSmmEnableSource (&Record->SrcDesc); >=20 > + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); >=20 > + } >=20 > + return Status; >=20 > +} >=20 > + >=20 > +// >=20 > +// Nmi >=20 > +// >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescNmi =3D { >=20 > + PCH_SMM_NO_FLAGS, >=20 > + { >=20 > + { >=20 > + { >=20 > + TCO_ADDR_TYPE, >=20 > + {R_TCO_IO_TCO1_CNT} >=20 > + }, >=20 > + S_TCO_IO_TCO1_CNT, >=20 > + N_TCO_IO_TCO1_CNT_NMI2SMI_EN >=20 > + }, >=20 > + NULL_BIT_DESC_INITIALIZER >=20 > + }, >=20 > + { >=20 > + { >=20 > + { >=20 > + TCO_ADDR_TYPE, >=20 > + {R_TCO_IO_TCO1_STS} >=20 > + }, >=20 > + S_TCO_IO_TCO1_STS, >=20 > + N_TCO_IO_TCO1_STS_NMI2SMI >=20 > + } >=20 > + }, >=20 > + // >=20 > + // NOTE: The status of NMI2SMI won't reflect to PMC SMI_STS. >=20 > + // So skip the top level status check and check the TCO1_STS dir= ectly. >=20 > + // >=20 > + NULL_BIT_DESC_INITIALIZER >=20 > +}; >=20 > + >=20 > +/** >=20 > + The register function used to register SMI handler of NMI event. >=20 > + >=20 > + @param[in] This The pointer to the protocol itse= lf >=20 > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source >=20 > + @param[out] DispatchHandle Handle of dispatch function to r= egister. >=20 > + >=20 > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description >=20 > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record >=20 > + @retval EFI_SUCCESS The database record is created s= uccessfully. >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchTcoSmiNmiRegister ( >=20 > + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + DATABASE_RECORD *Record; >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + Status =3D PchSmiRecordInsert ( >=20 > + &mSrcDescNmi, >=20 > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, >=20 > + PchTcoSmiNmiType, >=20 > + DispatchHandle >=20 > + ); >=20 > + if (!EFI_ERROR (Status)) { >=20 > + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle); >=20 > + Record->ClearSource =3D PchTcoSmiClearSource; >=20 > + PchSmmClearSource (&Record->SrcDesc); >=20 > + PchSmmEnableSource (&Record->SrcDesc); >=20 > + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); >=20 > + } >=20 > + return Status; >=20 > +} >=20 > + >=20 > +// >=20 > +// IntruderDetect srcdesc >=20 > +// >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescIntruderDet =3D { >=20 > + PCH_SMM_NO_FLAGS, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_EN} >=20 > + }, >=20 > + S_ACPI_IO_SMI_EN, >=20 > + N_ACPI_IO_SMI_EN_TCO >=20 > + }, >=20 > + { >=20 > + { >=20 > + TCO_ADDR_TYPE, >=20 > + {R_TCO_IO_TCO2_CNT} >=20 > + }, >=20 > + S_TCO_IO_TCO2_CNT, >=20 > + N_TCO_IO_TCO2_CNT_INTRD_SEL >=20 > + } >=20 > + }, >=20 > + { >=20 > + { >=20 > + { >=20 > + TCO_ADDR_TYPE, >=20 > + {R_TCO_IO_TCO2_STS} >=20 > + }, >=20 > + S_TCO_IO_TCO2_STS, >=20 > + N_TCO_IO_TCO2_STS_INTRD_DET >=20 > + } >=20 > + }, >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_TCO >=20 > + } >=20 > +}; >=20 > + >=20 > +/** >=20 > + The register function used to register SMI handler of Intruder Detect > event. >=20 > + >=20 > + @param[in] This The pointer to the protocol itse= lf >=20 > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source >=20 > + @param[out] DispatchHandle Handle of dispatch function to r= egister. >=20 > + >=20 > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description >=20 > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record >=20 > + @retval EFI_SUCCESS The database record is created s= uccessfully. >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchTcoSmiIntruderDetRegister ( >=20 > + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + DATABASE_RECORD *Record; >=20 > + >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + Status =3D PchSmiRecordInsert ( >=20 > + &mSrcDescIntruderDet, >=20 > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, >=20 > + PchTcoSmiIntruderDetectType, >=20 > + DispatchHandle >=20 > + ); >=20 > + if (!EFI_ERROR (Status)) { >=20 > + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle); >=20 > + Record->ClearSource =3D PchTcoSmiClearSourceAndBlock; >=20 > + PchSmmClearSource (&Record->SrcDesc); >=20 > + PchSmmEnableSource (&Record->SrcDesc); >=20 > + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); >=20 > + } >=20 > + return Status; >=20 > +} >=20 > + >=20 > +// >=20 > +// SpiBiosWp srcdesc >=20 > +// >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescSpiBiosWp =3D { >=20 > + PCH_SMM_NO_FLAGS, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_EN} >=20 > + }, >=20 > + S_ACPI_IO_SMI_EN, >=20 > + N_ACPI_IO_SMI_EN_TCO >=20 > + }, >=20 > + { >=20 > + { >=20 > + PCIE_ADDR_TYPE, >=20 > + { ( >=20 > + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | >=20 > + (PCI_DEVICE_NUMBER_PCH_SPI << 19) | >=20 > + (PCI_FUNCTION_NUMBER_PCH_SPI << 16) | >=20 > + R_SPI_CFG_BC >=20 > + ) } >=20 > + }, >=20 > + S_SPI_CFG_BC, >=20 > + N_SPI_CFG_BC_BLE >=20 > + }, >=20 > + }, >=20 > + { >=20 > + { >=20 > + { >=20 > + PCIE_ADDR_TYPE, >=20 > + { ( >=20 > + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | >=20 > + (PCI_DEVICE_NUMBER_PCH_SPI << 19) | >=20 > + (PCI_FUNCTION_NUMBER_PCH_SPI << 16) | >=20 > + R_SPI_CFG_BC >=20 > + ) } >=20 > + }, >=20 > + S_SPI_CFG_BC, >=20 > + N_SPI_CFG_BC_SYNC_SS >=20 > + } >=20 > + }, >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_TCO >=20 > + } >=20 > +}; >=20 > + >=20 > +/** >=20 > + Special handling for SPI Write Protect >=20 > + >=20 > + @param[in] SrcDesc Not used >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +PchTcoSpiWpClearSource ( >=20 > + CONST PCH_SMM_SOURCE_DESC *SrcDesc >=20 > + ) >=20 > +{ >=20 > + UINT64 SpiRegBase; >=20 > + UINT32 BiosControl; >=20 > + UINT32 Timeout; >=20 > + >=20 > + SpiRegBase =3D SpiPciCfgBase (); >=20 > + PciSegmentAndThenOr32 ( >=20 > + SpiRegBase + R_SPI_CFG_BC, >=20 > + (UINT32) ~B_SPI_CFG_BC_ASYNC_SS, >=20 > + B_SPI_CFG_BC_SYNC_SS >=20 > + ); >=20 > + // >=20 > + // Ensure the SYNC is cleared >=20 > + // >=20 > + Timeout =3D 1000; >=20 > + do { >=20 > + BiosControl =3D PciSegmentRead32 (SpiRegBase + R_SPI_CFG_BC); >=20 > + Timeout--; >=20 > + } while ((BiosControl & B_SPI_CFG_BC_SYNC_SS) && (Timeout > 0)); >=20 > + >=20 > + // >=20 > + // Any TCO-based status bits require special handling. >=20 > + // SMI_STS.TCO_STS must be cleared in addition to the status bit in th= e > TCO registers >=20 > + // >=20 > + PchSmmClearSource (&mDescSrcTcoSts); >=20 > +} >=20 > + >=20 > +/** >=20 > + Set SMI_EN_TCO to enable TCO SMI. >=20 > +**/ >=20 > +STATIC >=20 > +VOID >=20 > +PchSetSmiEnTco ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + IoOr32 (mAcpiBaseAddr + R_ACPI_IO_SMI_EN, > B_ACPI_IO_SMI_EN_TCO); >=20 > +} >=20 > + >=20 > +/** >=20 > + The register function used to register SMI handler of BIOS write prote= ct > event. >=20 > + >=20 > + @param[in] This The pointer to the protocol itse= lf >=20 > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source >=20 > + @param[out] DispatchHandle Handle of dispatch function to r= egister. >=20 > + >=20 > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description >=20 > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record >=20 > + @retval EFI_SUCCESS The database record is created s= uccessfully. >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchTcoSmiSpiBiosWpRegister ( >=20 > + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + DATABASE_RECORD *Record; >=20 > + >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + Status =3D PchSmiRecordInsert ( >=20 > + &mSrcDescSpiBiosWp, >=20 > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, >=20 > + PchTcoSmiSpiBiosWpType, >=20 > + DispatchHandle >=20 > + ); >=20 > + if (!EFI_ERROR (Status)) { >=20 > + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle); >=20 > + Record->ClearSource =3D PchTcoSpiWpClearSource; >=20 > + PchTcoSpiWpClearSource (NULL); >=20 > + // >=20 > + // It doesn't enable the BIOSLOCK here. Enable it by policy in DXE. >=20 > + // Only enable SMI_EN_TCO. >=20 > + // >=20 > + PchSetSmiEnTco (); >=20 > + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); >=20 > + } >=20 > + return Status; >=20 > +} >=20 > + >=20 > +// >=20 > +// LpcBiosWp srcdesc >=20 > +// >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescLpcBiosWp =3D { >=20 > + PCH_SMM_NO_FLAGS, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_EN} >=20 > + }, >=20 > + S_ACPI_IO_SMI_EN, >=20 > + N_ACPI_IO_SMI_EN_TCO >=20 > + }, >=20 > + { >=20 > + { >=20 > + PCIE_ADDR_TYPE, >=20 > + { ( >=20 > + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | >=20 > + (PCI_DEVICE_NUMBER_PCH_LPC << 19) | >=20 > + (PCI_FUNCTION_NUMBER_PCH_LPC << 16) | >=20 > + R_LPC_CFG_BC >=20 > + ) } >=20 > + }, >=20 > + S_LPC_CFG_BC, >=20 > + N_LPC_CFG_BC_LE >=20 > + } >=20 > + }, >=20 > + { >=20 > + { >=20 > + { >=20 > + TCO_ADDR_TYPE, >=20 > + {R_TCO_IO_TCO1_STS} >=20 > + }, >=20 > + S_TCO_IO_TCO1_STS, >=20 > + N_TCO_IO_TCO1_STS_BIOSWR >=20 > + } >=20 > + }, >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_TCO >=20 > + } >=20 > +}; >=20 > + >=20 > +/** >=20 > + The register function used to register SMI handler of LPC BIOS write > protect event. >=20 > + >=20 > + @param[in] This The pointer to the protocol itse= lf >=20 > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source >=20 > + @param[out] DispatchHandle Handle of dispatch function to r= egister. >=20 > + >=20 > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description >=20 > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record >=20 > + @retval EFI_SUCCESS The database record is created s= uccessfully. >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchTcoSmiLpcBiosWpRegister ( >=20 > + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + DATABASE_RECORD *Record; >=20 > + >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + if (IsEspiEnabled ()) { >=20 > + // >=20 > + // Status is D31F0's PCBC.BWPDS >=20 > + // >=20 > + ASSERT (FALSE); >=20 > + return EFI_UNSUPPORTED; >=20 > + } >=20 > + >=20 > + Status =3D PchSmiRecordInsert ( >=20 > + &mSrcDescLpcBiosWp, >=20 > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, >=20 > + PchTcoSmiLpcBiosWpType, >=20 > + DispatchHandle >=20 > + ); >=20 > + if (!EFI_ERROR (Status)) { >=20 > + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle); >=20 > + Record->ClearSource =3D PchTcoSmiClearSource; >=20 > + PchSmmClearSource (&Record->SrcDesc); >=20 > + // >=20 > + // It doesn't enable the BIOSLOCK here. Enable it by policy in DXE. >=20 > + // Only enable SMI_EN_TCO. >=20 > + // >=20 > + PchSetSmiEnTco (); >=20 > + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); >=20 > + } >=20 > + return Status; >=20 > +} >=20 > + >=20 > +// >=20 > +// NEWCENTURY_STS bit that needs to be cleared >=20 > +// >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescNewCentury =3D { >=20 > + PCH_SMM_NO_FLAGS, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_EN} >=20 > + }, >=20 > + S_ACPI_IO_SMI_EN, >=20 > + N_ACPI_IO_SMI_EN_TCO >=20 > + }, >=20 > + NULL_BIT_DESC_INITIALIZER >=20 > + }, >=20 > + { >=20 > + { >=20 > + { >=20 > + TCO_ADDR_TYPE, >=20 > + {R_TCO_IO_TCO1_STS} >=20 > + }, >=20 > + S_TCO_IO_TCO1_STS, >=20 > + N_TCO_IO_TCO1_STS_NEWCENTURY >=20 > + } >=20 > + }, >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_TCO >=20 > + } >=20 > +}; >=20 > + >=20 > +/** >=20 > + The register function used to register SMI handler of NEW CENTURY even= t. >=20 > + >=20 > + @param[in] This The pointer to the protocol itse= lf >=20 > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source >=20 > + @param[out] DispatchHandle Handle of dispatch function to r= egister. >=20 > + >=20 > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description >=20 > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record >=20 > + @retval EFI_SUCCESS The database record is created s= uccessfully. >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchTcoSmiNewCenturyRegister ( >=20 > + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + DATABASE_RECORD *Record; >=20 > + >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + Status =3D PchSmiRecordInsert ( >=20 > + &mSrcDescNewCentury, >=20 > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, >=20 > + PchTcoSmiNewCenturyType, >=20 > + DispatchHandle >=20 > + ); >=20 > + if (!EFI_ERROR (Status)) { >=20 > + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle); >=20 > + Record->ClearSource =3D PchTcoSmiClearSourceAndBlock; >=20 > + PchSmmClearSource (&Record->SrcDesc); >=20 > + PchSmmEnableSource (&Record->SrcDesc); >=20 > + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); >=20 > + } >=20 > + return Status; >=20 > +} >=20 > + >=20 > +/** >=20 > + Unregister a child SMI source dispatch function with a parent SMM driv= er >=20 > + >=20 > + @param[in] This Protocol instance pointer. >=20 > + @param[in] DispatchHandle Handle of dispatch function to > deregister. >=20 > + >=20 > + @retval EFI_SUCCESS The dispatch function has been s= uccessfully >=20 > + unregistered and the SMI source = has been disabled >=20 > + if there are no other registered= child dispatch >=20 > + functions for this SMI source. >=20 > + @retval EFI_INVALID_PARAMETER Handle is invalid. >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchTcoSmiUnRegister ( >=20 > + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN EFI_HANDLE DispatchHandle >=20 > + ) >=20 > +{ >=20 > + DATABASE_RECORD *Record; >=20 > + EFI_STATUS Status; >=20 > + >=20 > + Record =3D DATABASE_RECORD_FROM_LINK (DispatchHandle); >=20 > + if ((Record->SrcDesc.En[1].Reg.Type =3D=3D ACPI_ADDR_TYPE) && >=20 > + (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Dev =3D=3D SpiDevNumbe= r ()) > && >=20 > + (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Fnc =3D=3D SpiFuncNumb= er ()) > && >=20 > + (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Reg =3D=3D R_SPI_CFG_B= C) && >=20 > + (Record->SrcDesc.En[1].Bit =3D=3D N_SPI_CFG_BC_BLE)) { >=20 > + // >=20 > + // SPI Write Protect cannot be disabled >=20 > + // >=20 > + return EFI_ACCESS_DENIED; >=20 > + } else if ((Record->SrcDesc.En[1].Reg.Type =3D=3D ACPI_ADDR_TYPE) && >=20 > + (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Dev =3D=3D LpcD= evNumber > ()) && >=20 > + (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Fnc =3D=3D LpcF= uncNumber > ()) && >=20 > + (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Reg =3D=3D R_LP= C_CFG_BC) > && >=20 > + (Record->SrcDesc.En[1].Bit =3D=3D N_LPC_CFG_BC_LE)) { >=20 > + // >=20 > + // eSPI/LPC Write Protect cannot be disabled >=20 > + // >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + Status =3D PchSmmCoreUnRegister (NULL, DispatchHandle); >=20 > + if (!EFI_ERROR (Status)) { >=20 > + SmiHandlerProfileUnregisterHandler (&gPchTcoSmiDispatchProtocolGuid, > Record->Callback, NULL, 0); >=20 > + } >=20 > + return Status; >=20 > +} >=20 > + >=20 > + >=20 > +// >=20 > +// PcieRpHotPlug srcdesc >=20 > +// >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMM_SOURCE_DESC > PchPcieSmiRpHotPlugTemplate =3D { >=20 > + PCH_SMM_NO_FLAGS, >=20 > + { >=20 > + { >=20 > + { >=20 > + PCIE_ADDR_TYPE, >=20 > + {R_PCH_PCIE_CFG_MPC} >=20 > + }, >=20 > + S_PCH_PCIE_CFG_MPC, >=20 > + N_PCH_PCIE_CFG_MPC_HPME >=20 > + }, >=20 > + NULL_BIT_DESC_INITIALIZER >=20 > + }, >=20 > + { >=20 > + { >=20 > + { >=20 > + PCIE_ADDR_TYPE, >=20 > + {R_PCH_PCIE_CFG_SMSCS} >=20 > + }, >=20 > + S_PCH_PCIE_CFG_SMSCS, >=20 > + N_PCH_PCIE_CFG_SMSCS_HPPDM >=20 > + } >=20 > + }, >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_PCI_EXP >=20 > + } >=20 > +}; >=20 > + >=20 > +/** >=20 > + The register function used to register SMI handler of PCIE RP hotplug > event. >=20 > + >=20 > + @param[in] This The pointer to the protocol itse= lf >=20 > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source >=20 > + @param[in] RpIndex Refer PCIE_COMBINED_RPINDEX for = PCH > RP index and CPU RP index. >=20 > + @param[out] DispatchHandle Handle of dispatch function to r= egister. >=20 > + >=20 > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description >=20 > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record >=20 > + @retval EFI_SUCCESS The database record is created s= uccessfully. >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchPcieSmiHotPlugRegister ( >=20 > + IN PCH_PCIE_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_PCIE_SMI_RP_DISPATCH_CALLBACK DispatchFunction, >=20 > + IN UINTN RpIndex, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + UINTN RpDev; >=20 > + UINTN RpFun; >=20 > + PCH_SMM_PCIE_REGISTER_CONTEXT Context; >=20 > + DATABASE_RECORD *Record; >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + GetPcieRpDevFun (RpIndex, &RpDev, &RpFun); >=20 > + >=20 > + PchPcieSmiRpHotPlugTemplate.En[0].Reg.Data.pcie.Fields.Dev =3D (UINT8) > RpDev; >=20 > + PchPcieSmiRpHotPlugTemplate.En[0].Reg.Data.pcie.Fields.Fnc =3D (UINT8) > RpFun; >=20 > + PchPcieSmiRpHotPlugTemplate.Sts[0].Reg.Data.pcie.Fields.Dev =3D (UINT8= ) > RpDev; >=20 > + PchPcieSmiRpHotPlugTemplate.Sts[0].Reg.Data.pcie.Fields.Fnc =3D (UINT8= ) > RpFun; >=20 > + >=20 > + Status =3D PchSmiRecordInsert ( >=20 > + &PchPcieSmiRpHotPlugTemplate, >=20 > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, >=20 > + PchPcieSmiRpHotplugType, >=20 > + DispatchHandle >=20 > + ); >=20 > + if (!EFI_ERROR (Status)) { >=20 > + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle); >=20 > + Record->ChildContext.Pcie.PchSmiType =3D PchPcieSmiRpHotplugType; >=20 > + Record->ChildContext.Pcie.RpIndex =3D RpIndex; >=20 > + Record->ContextSize =3D sizeof (PCH_SMM_PCIE_REGISTER_CONTEXT); >=20 > + SmiHandlerProfileRegisterHandler ( >=20 > + &gPchPcieSmiDispatchProtocolGuid, >=20 > + (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, >=20 > + (UINTN)RETURN_ADDRESS (0), >=20 > + &Context, >=20 > + sizeof (Context) >=20 > + ); >=20 > + } >=20 > + PchSmmClearSource (&PchPcieSmiRpHotPlugTemplate); >=20 > + PchSmmEnableSource (&PchPcieSmiRpHotPlugTemplate); >=20 > + >=20 > + return Status; >=20 > +} >=20 > + >=20 > +// >=20 > +// PcieRpLinkActive srcdesc >=20 > +// >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMM_SOURCE_DESC > PchPcieSmiRpLinkActiveTemplate =3D { >=20 > + PCH_SMM_NO_FLAGS, >=20 > + { >=20 > + { >=20 > + { >=20 > + PCIE_ADDR_TYPE, >=20 > + {R_PCH_PCIE_CFG_MPC} >=20 > + }, >=20 > + S_PCH_PCIE_CFG_MPC, >=20 > + N_PCH_PCIE_CFG_MPC_HPME >=20 > + }, >=20 > + NULL_BIT_DESC_INITIALIZER >=20 > + }, >=20 > + { >=20 > + { >=20 > + { >=20 > + PCIE_ADDR_TYPE, >=20 > + {R_PCH_PCIE_CFG_SMSCS} >=20 > + }, >=20 > + S_PCH_PCIE_CFG_SMSCS, >=20 > + N_PCH_PCIE_CFG_SMSCS_HPLAS >=20 > + } >=20 > + }, >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_PCI_EXP >=20 > + } >=20 > +}; >=20 > + >=20 > +/** >=20 > + The register function used to register SMI handler of PCIE RP link act= ive > event. >=20 > + >=20 > + @param[in] This The pointer to the protocol itse= lf >=20 > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source >=20 > + @param[in] RpIndex Refer PCIE_COMBINED_RPINDEX for = PCH > RP index and CPU RP index. >=20 > + @param[out] DispatchHandle Handle of dispatch function to r= egister. >=20 > + >=20 > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description >=20 > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record >=20 > + @retval EFI_SUCCESS The database record is created s= uccessfully. >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchPcieSmiLinkActiveRegister ( >=20 > + IN PCH_PCIE_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_PCIE_SMI_RP_DISPATCH_CALLBACK DispatchFunction, >=20 > + IN UINTN RpIndex, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + UINTN RpDev; >=20 > + UINTN RpFun; >=20 > + PCH_SMM_PCIE_REGISTER_CONTEXT Context; >=20 > + DATABASE_RECORD *Record; >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + GetPcieRpDevFun (RpIndex, &RpDev, &RpFun); >=20 > + >=20 > + >=20 > + PchPcieSmiRpLinkActiveTemplate.En[0].Reg.Data.pcie.Fields.Dev =3D > (UINT8) RpDev; >=20 > + PchPcieSmiRpLinkActiveTemplate.En[0].Reg.Data.pcie.Fields.Fnc =3D (UIN= T8) > RpFun; >=20 > + PchPcieSmiRpLinkActiveTemplate.Sts[0].Reg.Data.pcie.Fields.Dev =3D > (UINT8) RpDev; >=20 > + PchPcieSmiRpLinkActiveTemplate.Sts[0].Reg.Data.pcie.Fields.Fnc =3D > (UINT8) RpFun; >=20 > + >=20 > + Status =3D PchSmiRecordInsert ( >=20 > + &PchPcieSmiRpLinkActiveTemplate, >=20 > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, >=20 > + PchPcieSmiRpLinkActiveType, >=20 > + DispatchHandle >=20 > + ); >=20 > + if (!EFI_ERROR (Status)) { >=20 > + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle); >=20 > + Record->ChildContext.Pcie.PchSmiType =3D PchPcieSmiRpLinkActiveType; >=20 > + Record->ChildContext.Pcie.RpIndex =3D RpIndex; >=20 > + Record->ContextSize =3D sizeof (PCH_SMM_PCIE_REGISTER_CONTEXT); >=20 > + SmiHandlerProfileRegisterHandler ( >=20 > + &gPchPcieSmiDispatchProtocolGuid, >=20 > + (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, >=20 > + (UINTN)RETURN_ADDRESS (0), >=20 > + &Context, >=20 > + sizeof (Context) >=20 > + ); >=20 > + } >=20 > + PchSmmClearSource (&PchPcieSmiRpLinkActiveTemplate); >=20 > + PchSmmEnableSource (&PchPcieSmiRpLinkActiveTemplate); >=20 > + >=20 > + return Status; >=20 > +} >=20 > + >=20 > +// >=20 > +// PcieRpLinkEq srcdesc >=20 > +// >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMM_SOURCE_DESC > PchPcieSmiRpLinkEqTemplate =3D { >=20 > + PCH_SMM_NO_FLAGS, >=20 > + { >=20 > + { >=20 > + { >=20 > + PCIE_ADDR_TYPE, >=20 > + {R_PCH_PCIE_CFG_EQCFG1} >=20 > + }, >=20 > + S_PCH_PCIE_CFG_EQCFG1, >=20 > + N_PCH_PCIE_CFG_EQCFG1_LERSMIE >=20 > + }, >=20 > + NULL_BIT_DESC_INITIALIZER >=20 > + }, >=20 > + { >=20 > + { >=20 > + { >=20 > + PCIE_ADDR_TYPE, >=20 > + {R_PCH_PCIE_CFG_SMSCS} >=20 > + }, >=20 > + S_PCH_PCIE_CFG_SMSCS, >=20 > + N_PCH_PCIE_CFG_SMSCS_LERSMIS >=20 > + } >=20 > + }, >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_PCI_EXP >=20 > + } >=20 > +}; >=20 > +/** >=20 > + The register function used to register SMI handler of PCIE RP Link > Equalization Request event. >=20 > + >=20 > + @param[in] This The pointer to the protocol itse= lf >=20 > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source >=20 > + @param[in] RpIndex Refer PCIE_COMBINED_RPINDEX for = PCH > RP index and CPU RP index. >=20 > + @param[out] DispatchHandle Handle of dispatch function to r= egister. >=20 > + >=20 > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description >=20 > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record >=20 > + @retval EFI_SUCCESS The database record is created s= uccessfully. >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchPcieSmiLinkEqRegister ( >=20 > + IN PCH_PCIE_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_PCIE_SMI_RP_DISPATCH_CALLBACK DispatchFunction, >=20 > + IN UINTN RpIndex, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + UINTN RpDev; >=20 > + UINTN RpFun; >=20 > + EFI_STATUS Status; >=20 > + PCH_SMM_PCIE_REGISTER_CONTEXT Context; >=20 > + DATABASE_RECORD *Record; >=20 > + >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + GetPcieRpDevFun (RpIndex, &RpDev, &RpFun); >=20 > + >=20 > + // >=20 > + // Patch the RP device number and function number of srcdesc. >=20 > + // >=20 > + PchPcieSmiRpLinkEqTemplate.En[0].Reg.Data.pcie.Fields.Dev =3D (UINT8) > RpDev; >=20 > + PchPcieSmiRpLinkEqTemplate.En[0].Reg.Data.pcie.Fields.Fnc =3D (UINT8) > RpFun; >=20 > + PchPcieSmiRpLinkEqTemplate.Sts[0].Reg.Data.pcie.Fields.Dev =3D (UINT8) > RpDev; >=20 > + PchPcieSmiRpLinkEqTemplate.Sts[0].Reg.Data.pcie.Fields.Fnc =3D (UINT8) > RpFun; >=20 > + >=20 > + Status =3D PchSmiRecordInsert ( >=20 > + &PchPcieSmiRpLinkEqTemplate, >=20 > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, >=20 > + PchPcieSmiRpLinkEqType, >=20 > + DispatchHandle >=20 > + ); >=20 > + if (!EFI_ERROR (Status)) { >=20 > + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle); >=20 > + Record->ChildContext.Pcie.PchSmiType =3D PchPcieSmiRpLinkEqType; >=20 > + Record->ChildContext.Pcie.RpIndex =3D RpIndex; >=20 > + Record->ContextSize =3D sizeof (PCH_SMM_PCIE_REGISTER_CONTEXT); >=20 > + SmiHandlerProfileRegisterHandler ( >=20 > + &gPchPcieSmiDispatchProtocolGuid, >=20 > + (EFI_SMM_HANDLER_ENTRY_POINT2) DispatchFunction, >=20 > + (UINTN)RETURN_ADDRESS (0), >=20 > + &Context, >=20 > + sizeof (Context) >=20 > + ); >=20 > + } >=20 > + return Status; >=20 > +} >=20 > + >=20 > +/** >=20 > + Unregister a child SMI source dispatch function with a parent SMM driv= er >=20 > + >=20 > + @param[in] This Protocol instance pointer. >=20 > + @param[in] DispatchHandle Handle of dispatch function to > deregister. >=20 > + >=20 > + @retval EFI_SUCCESS The dispatch function has been s= uccessfully >=20 > + unregistered and the SMI source = has been disabled >=20 > + if there are no other registered= child dispatch >=20 > + functions for this SMI source. >=20 > + @retval EFI_INVALID_PARAMETER Handle is invalid. >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchPcieSmiUnRegister ( >=20 > + IN PCH_PCIE_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN EFI_HANDLE DispatchHandle >=20 > + ) >=20 > +{ >=20 > + DATABASE_RECORD *RecordToDelete; >=20 > + EFI_STATUS Status; >=20 > + >=20 > + RecordToDelete =3D DATABASE_RECORD_FROM_LINK (DispatchHandle); >=20 > + Status =3D PchSmmCoreUnRegister (NULL, DispatchHandle); >=20 > + if (!EFI_ERROR (Status)) { >=20 > + SmiHandlerProfileUnregisterHandler ( >=20 > + &gPchPcieSmiDispatchProtocolGuid, >=20 > + RecordToDelete->Callback, >=20 > + &RecordToDelete->ChildContext, >=20 > + sizeof (RecordToDelete->ContextSize) >=20 > + ); >=20 > + } >=20 > + return Status; >=20 > +} >=20 > + >=20 > +// >=20 > +// Pme srcdesc >=20 > +// >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescPme =3D { >=20 > + PCH_SMM_SCI_EN_DEPENDENT, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_GPE0_EN_127_96} >=20 > + }, >=20 > + S_ACPI_IO_GPE0_EN_127_96, >=20 > + N_ACPI_IO_GPE0_EN_127_96_PME >=20 > + }, >=20 > + NULL_BIT_DESC_INITIALIZER >=20 > + }, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_GPE0_STS_127_96} >=20 > + }, >=20 > + S_ACPI_IO_GPE0_STS_127_96, >=20 > + N_ACPI_IO_GPE0_STS_127_96_PME >=20 > + } >=20 > + }, >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_GPE0 >=20 > + } >=20 > +}; >=20 > + >=20 > +/** >=20 > + The register function used to register SMI handler of PME event. >=20 > + >=20 > + @param[in] This The pointer to the protocol itse= lf >=20 > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source >=20 > + @param[out] DispatchHandle Handle of dispatch function to r= egister. >=20 > + >=20 > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description >=20 > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record >=20 > + @retval EFI_SUCCESS The database record is created s= uccessfully. >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchAcpiSmiPmeRegister ( >=20 > + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_ACPI_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + Status =3D PchSmiRecordInsert ( >=20 > + &mSrcDescPme, >=20 > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, >=20 > + PchAcpiSmiPmeType, >=20 > + DispatchHandle >=20 > + ); >=20 > + PchSmmClearSource (&mSrcDescPme); >=20 > + PchSmmEnableSource (&mSrcDescPme); >=20 > + if (!EFI_ERROR (Status)) { >=20 > + SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); >=20 > + } >=20 > + return Status; >=20 > +} >=20 > + >=20 > +// >=20 > +// PmeB0 srcdesc >=20 > +// >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescPmeB0 =3D { >=20 > + PCH_SMM_SCI_EN_DEPENDENT, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_GPE0_EN_127_96} >=20 > + }, >=20 > + S_ACPI_IO_GPE0_EN_127_96, >=20 > + N_ACPI_IO_GPE0_EN_127_96_PME_B0 >=20 > + }, >=20 > + NULL_BIT_DESC_INITIALIZER >=20 > + }, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_GPE0_STS_127_96} >=20 > + }, >=20 > + S_ACPI_IO_GPE0_STS_127_96, >=20 > + N_ACPI_IO_GPE0_STS_127_96_PME_B0 >=20 > + } >=20 > + }, >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_GPE0 >=20 > + } >=20 > +}; >=20 > +/** >=20 > + The register function used to register SMI handler of PME B0 event. >=20 > + >=20 > + @param[in] This The pointer to the protocol itse= lf >=20 > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source >=20 > + @param[out] DispatchHandle Handle of dispatch function to r= egister. >=20 > + >=20 > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description >=20 > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record >=20 > + @retval EFI_SUCCESS The database record is created s= uccessfully. >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchAcpiSmiPmeB0Register ( >=20 > + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_ACPI_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + Status =3D PchSmiRecordInsert ( >=20 > + &mSrcDescPmeB0, >=20 > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, >=20 > + PchAcpiSmiPmeB0Type, >=20 > + DispatchHandle >=20 > + ); >=20 > + PchSmmClearSource (&mSrcDescPmeB0); >=20 > + PchSmmEnableSource (&mSrcDescPmeB0); >=20 > + if (!EFI_ERROR (Status)) { >=20 > + SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); >=20 > + } >=20 > + return Status; >=20 > +} >=20 > + >=20 > +// >=20 > +// RtcAlarm srcdesc >=20 > +// >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescRtcAlarm =3D { >=20 > + PCH_SMM_SCI_EN_DEPENDENT, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_PM1_EN} >=20 > + }, >=20 > + S_ACPI_IO_PM1_EN, >=20 > + N_ACPI_IO_PM1_EN_RTC >=20 > + }, >=20 > + NULL_BIT_DESC_INITIALIZER >=20 > + }, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_PM1_STS} >=20 > + }, >=20 > + S_ACPI_IO_PM1_STS, >=20 > + N_ACPI_IO_PM1_STS_RTC >=20 > + } >=20 > + }, >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_PM1_STS_REG >=20 > + } >=20 > +}; >=20 > + >=20 > +/** >=20 > + The register function used to register SMI handler of RTC alarm event. >=20 > + >=20 > + @param[in] This The pointer to the protocol itse= lf >=20 > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source >=20 > + @param[out] DispatchHandle Handle of dispatch function to r= egister. >=20 > + >=20 > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description >=20 > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record >=20 > + @retval EFI_SUCCESS The database record is created s= uccessfully. >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchAcpiSmiRtcAlarmRegister ( >=20 > + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_ACPI_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + Status =3D PchSmiRecordInsert ( >=20 > + &mSrcDescRtcAlarm, >=20 > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, >=20 > + PchAcpiSmiRtcAlarmType, >=20 > + DispatchHandle >=20 > + ); >=20 > + >=20 > + PchSmmClearSource (&mSrcDescRtcAlarm); >=20 > + PchSmmEnableSource (&mSrcDescRtcAlarm); >=20 > + if (!EFI_ERROR (Status)) { >=20 > + SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); >=20 > + } >=20 > + return Status; >=20 > +} >=20 > + >=20 > +// >=20 > +// TmrOverflow srcdesc >=20 > +// >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescTmrOverflow =3D { >=20 > + PCH_SMM_SCI_EN_DEPENDENT, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_PM1_EN} >=20 > + }, >=20 > + S_ACPI_IO_PM1_EN, >=20 > + N_ACPI_IO_PM1_EN_TMROF >=20 > + }, >=20 > + NULL_BIT_DESC_INITIALIZER >=20 > + }, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_PM1_STS} >=20 > + }, >=20 > + S_ACPI_IO_PM1_STS, >=20 > + N_ACPI_IO_PM1_STS_TMROF >=20 > + } >=20 > + }, >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_PM1_STS_REG >=20 > + } >=20 > +}; >=20 > + >=20 > +/** >=20 > + The register function used to register SMI handler of Timer Overflow > event. >=20 > + >=20 > + @param[in] This The pointer to the protocol itse= lf >=20 > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source >=20 > + @param[out] DispatchHandle Handle of dispatch function to r= egister. >=20 > + >=20 > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description >=20 > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record >=20 > + @retval EFI_SUCCESS The database record is created s= uccessfully. >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchAcpiSmiTmrOverflowRegister ( >=20 > + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_ACPI_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + Status =3D PchSmiRecordInsert ( >=20 > + &mSrcDescTmrOverflow, >=20 > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, >=20 > + PchAcpiSmiTmrOverflowType, >=20 > + DispatchHandle >=20 > + ); >=20 > + PchSmmClearSource (&mSrcDescTmrOverflow); >=20 > + PchSmmEnableSource (&mSrcDescTmrOverflow); >=20 > + if (!EFI_ERROR (Status)) { >=20 > + SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); >=20 > + } >=20 > + >=20 > + return Status; >=20 > +} >=20 > + >=20 > +/** >=20 > + Unregister a child SMI source dispatch function with a parent SMM driv= er >=20 > + >=20 > + @param[in] This Protocol instance pointer. >=20 > + @param[in] DispatchHandle Handle of dispatch function to > deregister. >=20 > + >=20 > + @retval EFI_SUCCESS The dispatch function has been s= uccessfully >=20 > + unregistered and the SMI source = has been disabled >=20 > + if there are no other registered= child dispatch >=20 > + functions for this SMI source. >=20 > + @retval EFI_INVALID_PARAMETER Handle is invalid. >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchAcpiSmiUnRegister ( >=20 > + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN EFI_HANDLE DispatchHandle >=20 > + ) >=20 > +{ >=20 > + DATABASE_RECORD *RecordToDelete; >=20 > + EFI_STATUS Status; >=20 > + >=20 > + RecordToDelete =3D DATABASE_RECORD_FROM_LINK (DispatchHandle); >=20 > + Status =3D PchSmmCoreUnRegister (NULL, DispatchHandle); >=20 > + if (!EFI_ERROR (Status)) { >=20 > + SmiHandlerProfileUnregisterHandler > (&gPchAcpiSmiDispatchProtocolGuid, RecordToDelete->Callback, NULL, 0); >=20 > + } >=20 > + return Status; >=20 > +} >=20 > + >=20 > +// >=20 > +// SerialIrq srcdesc >=20 > +// >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescSerialIrq =3D { >=20 > + PCH_SMM_NO_FLAGS, >=20 > + { >=20 > + NULL_BIT_DESC_INITIALIZER, >=20 > + NULL_BIT_DESC_INITIALIZER >=20 > + }, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_SERIRQ >=20 > + } >=20 > + }, >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_SERIRQ >=20 > + } >=20 > +}; >=20 > + >=20 > +/** >=20 > + The register function used to register SMI handler of Serial IRQ event= . >=20 > + >=20 > + @param[in] This The pointer to the protocol itse= lf >=20 > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source >=20 > + @param[out] DispatchHandle Handle of dispatch function to r= egister. >=20 > + >=20 > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description >=20 > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record >=20 > + @retval EFI_SUCCESS The database record is created s= uccessfully. >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchSmiSerialIrqRegister ( >=20 > + IN PCH_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + Status =3D PchSmiRecordInsert ( >=20 > + &mSrcDescSerialIrq, >=20 > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, >=20 > + PchSmiSerialIrqType, >=20 > + DispatchHandle >=20 > + ); >=20 > + PchSmmClearSource (&mSrcDescSerialIrq); >=20 > + PchSmmEnableSource (&mSrcDescSerialIrq); >=20 > + if (!EFI_ERROR (Status)) { >=20 > + SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); >=20 > + } >=20 > + return Status; >=20 > +} >=20 > + >=20 > +// >=20 > +// McSmi srcdesc >=20 > +// >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescMcSmi =3D { >=20 > + PCH_SMM_NO_FLAGS, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_EN} >=20 > + }, >=20 > + S_ACPI_IO_SMI_EN, >=20 > + N_ACPI_IO_SMI_EN_MCSMI >=20 > + }, >=20 > + NULL_BIT_DESC_INITIALIZER >=20 > + }, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_MCSMI >=20 > + } >=20 > + }, >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_MCSMI >=20 > + } >=20 > +}; >=20 > + >=20 > +/** >=20 > + The register function used to register SMI handler of MCSMI event. >=20 > + >=20 > + @param[in] This The pointer to the protocol itse= lf >=20 > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source >=20 > + @param[out] DispatchHandle Handle of dispatch function to r= egister. >=20 > + >=20 > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description >=20 > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record >=20 > + @retval EFI_SUCCESS The database record is created s= uccessfully. >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchSmiMcSmiRegister ( >=20 > + IN PCH_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + Status =3D PchSmiRecordInsert ( >=20 > + &mSrcDescMcSmi, >=20 > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, >=20 > + PchSmiMcSmiType, >=20 > + DispatchHandle >=20 > + ); >=20 > + PchSmmClearSource (&mSrcDescMcSmi); >=20 > + PchSmmEnableSource (&mSrcDescMcSmi); >=20 > + if (!EFI_ERROR (Status)) { >=20 > + SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); >=20 > + } >=20 > + return Status; >=20 > +} >=20 > + >=20 > +// >=20 > +// SmBus srcdesc >=20 > +// >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescSmbus =3D { >=20 > + PCH_SMM_NO_FLAGS, >=20 > + { >=20 > + NULL_BIT_DESC_INITIALIZER, >=20 > + NULL_BIT_DESC_INITIALIZER >=20 > + }, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_SMBUS >=20 > + } >=20 > + }, >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_SMBUS >=20 > + } >=20 > +}; >=20 > + >=20 > +/** >=20 > + The register function used to register SMI handler of SMBUS event. >=20 > + >=20 > + @param[in] This The pointer to the protocol itse= lf >=20 > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source >=20 > + @param[out] DispatchHandle Handle of dispatch function to r= egister. >=20 > + >=20 > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description >=20 > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record >=20 > + @retval EFI_SUCCESS The database record is created s= uccessfully. >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchSmiSmbusRegister ( >=20 > + IN PCH_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + Status =3D PchSmiRecordInsert ( >=20 > + &mSrcDescSmbus, >=20 > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, >=20 > + PchSmiSmBusType, >=20 > + DispatchHandle >=20 > + ); >=20 > + PchSmmClearSource (&mSrcDescSmbus); >=20 > + PchSmmEnableSource (&mSrcDescSmbus); >=20 > + if (!EFI_ERROR (Status)) { >=20 > + SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); >=20 > + } >=20 > + return Status; >=20 > +} >=20 > + >=20 > +// >=20 > +// SpiAsyncSmi srcdesc >=20 > +// >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescSpiAsyncSmi =3D { >=20 > + PCH_SMM_NO_FLAGS, >=20 > + { >=20 > + { >=20 > + { >=20 > + PCIE_ADDR_TYPE, >=20 > + { ( >=20 > + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | >=20 > + (PCI_DEVICE_NUMBER_PCH_SPI << 19) | >=20 > + (PCI_FUNCTION_NUMBER_PCH_SPI << 16) | >=20 > + R_SPI_CFG_BC >=20 > + ) } >=20 > + }, >=20 > + S_SPI_CFG_BC, >=20 > + N_SPI_CFG_BC_ASE_BWP >=20 > + }, >=20 > + NULL_BIT_DESC_INITIALIZER >=20 > + }, >=20 > + { >=20 > + { >=20 > + { >=20 > + PCIE_ADDR_TYPE, >=20 > + { ( >=20 > + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | >=20 > + (PCI_DEVICE_NUMBER_PCH_SPI << 19) | >=20 > + (PCI_FUNCTION_NUMBER_PCH_SPI << 16) | >=20 > + R_SPI_CFG_BC >=20 > + ) } >=20 > + }, >=20 > + S_SPI_CFG_BC, >=20 > + N_SPI_CFG_BC_ASYNC_SS >=20 > + } >=20 > + }, >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_SPI >=20 > + } >=20 > +}; >=20 > + >=20 > +/** >=20 > + Special handling for SPI Asynchronous SMI. >=20 > + If SPI ASYNC SMI is enabled, De-assert SMI is sent when Flash Cycle Do= ne >=20 > + transitions from 1 to 0 or when the SMI enable becomes false. >=20 > + >=20 > + @param[in] SrcDesc Not used >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +PchSmiSpiAsyncClearSource ( >=20 > + CONST PCH_SMM_SOURCE_DESC *SrcDesc >=20 > + ) >=20 > +{ >=20 > + UINT64 SpiRegBase; >=20 > + UINT32 SpiBar0; >=20 > + >=20 > + SpiRegBase =3D SpiPciCfgBase (); >=20 > + SpiBar0 =3D PciSegmentRead32 (SpiRegBase + R_SPI_CFG_BAR0) & > ~(B_SPI_CFG_BAR0_MASK); >=20 > + if (SpiBar0 !=3D PCH_SPI_BASE_ADDRESS) { >=20 > + // >=20 > + // Temporary disable MSE, and override with SPI reserved MMIO > address, then enable MSE. >=20 > + // >=20 > + SpiBar0 =3D PCH_SPI_BASE_ADDRESS; >=20 > + PciSegmentAnd8 (SpiRegBase + PCI_COMMAND_OFFSET, (UINT8) > ~EFI_PCI_COMMAND_MEMORY_SPACE); >=20 > + PciSegmentWrite32 (SpiRegBase + R_SPI_CFG_BAR0, SpiBar0); >=20 > + PciSegmentOr8 (SpiRegBase + PCI_COMMAND_OFFSET, > EFI_PCI_COMMAND_MEMORY_SPACE); >=20 > + } >=20 > + >=20 > + MmioOr32 (SpiBar0 + R_SPI_MEM_HSFSC, B_SPI_MEM_HSFSC_FDONE); >=20 > +} >=20 > + >=20 > +/** >=20 > + Special handling to enable SPI Asynchronous SMI >=20 > +**/ >=20 > +VOID >=20 > +PchSmiSpiAsyncEnableSource ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + UINT64 SpiRegBase; >=20 > + UINT32 Data32And; >=20 > + UINT32 Data32Or; >=20 > + >=20 > + SpiRegBase =3D SpiPciCfgBase (); >=20 > + Data32And =3D (UINT32) ~B_SPI_CFG_BC_SYNC_SS; >=20 > + Data32Or =3D B_SPI_CFG_BC_ASE_BWP; >=20 > + >=20 > + PciSegmentAndThenOr32 ( >=20 > + SpiRegBase + R_SPI_CFG_BC, >=20 > + Data32And, >=20 > + Data32Or >=20 > + ); >=20 > + S3BootScriptSavePciCfgReadWrite ( >=20 > + S3BootScriptWidthUint32, >=20 > + SpiRegBase + R_SPI_CFG_BC, >=20 > + (VOID*) &Data32Or, >=20 > + (VOID*) &Data32And >=20 > + ); >=20 > + >=20 > + // >=20 > + // Clear the source >=20 > + // >=20 > + PchSmiSpiAsyncClearSource (NULL); >=20 > +} >=20 > + >=20 > +/** >=20 > + The register function used to register SMI handler of SPI Asynchronous > event. >=20 > + >=20 > + @param[in] This The pointer to the protocol itse= lf >=20 > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source >=20 > + @param[out] DispatchHandle Handle of dispatch function to r= egister. >=20 > + >=20 > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description >=20 > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record >=20 > + @retval EFI_SUCCESS The database record is created s= uccessfully. >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchSmiSpiAsyncRegister ( >=20 > + IN PCH_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + DATABASE_RECORD *Record; >=20 > + >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + Status =3D PchSmiRecordInsert ( >=20 > + &mSrcDescSpiAsyncSmi, >=20 > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, >=20 > + PchSmiSpiAsyncType, >=20 > + DispatchHandle >=20 > + ); >=20 > + >=20 > + if (!EFI_ERROR (Status)) { >=20 > + Record =3D DATABASE_RECORD_FROM_LINK (*DispatchHandle); >=20 > + Record->ClearSource =3D PchSmiSpiAsyncClearSource; >=20 > + PchSmiSpiAsyncClearSource (NULL); >=20 > + PchSmiSpiAsyncEnableSource (); >=20 > + SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); >=20 > + } >=20 > + return Status; >=20 > +} >=20 > + >=20 > +/** >=20 > + Unregister a child SMI source dispatch function with a parent SMM driv= er >=20 > + >=20 > + @param[in] This Protocol instance pointer. >=20 > + @param[in] DispatchHandle Handle of dispatch function to > deregister. >=20 > + >=20 > + @retval EFI_SUCCESS The dispatch function has been s= uccessfully >=20 > + unregistered and the SMI source = has been disabled >=20 > + if there are no other registered= child dispatch >=20 > + functions for this SMI source. >=20 > + @retval EFI_INVALID_PARAMETER Handle is invalid. >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > + @retval EFI_ACCESS_DENIED Return access denied since SPI a= ync > SMI handler is not able to disabled. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchSmiUnRegister ( >=20 > + IN PCH_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN EFI_HANDLE DispatchHandle >=20 > + ) >=20 > +{ >=20 > + DATABASE_RECORD *Record; >=20 > + UINT64 SpiRegBase; >=20 > + EFI_STATUS Status; >=20 > + >=20 > + Record =3D DATABASE_RECORD_FROM_LINK (DispatchHandle); >=20 > + if ((Record->SrcDesc.En[0].Reg.Type =3D=3D PCIE_ADDR_TYPE) && >=20 > + (Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Dev =3D=3D SpiDevNumbe= r ()) > && >=20 > + (Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Fnc =3D=3D SpiFuncNumb= er ()) > && >=20 > + (Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Reg =3D=3D R_SPI_CFG_B= C) && >=20 > + (Record->SrcDesc.En[0].Bit =3D=3D N_SPI_CFG_BC_ASE_BWP)) { >=20 > + SpiRegBase =3D SpiPciCfgBase (); >=20 > + if (PciSegmentRead8 (SpiRegBase + R_SPI_CFG_BC) & > B_SPI_CFG_BC_BILD) { >=20 > + // >=20 > + // SPI Asynchronous SMI cannot be disabled >=20 > + // >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + } >=20 > + Status =3D PchSmmCoreUnRegister (NULL, DispatchHandle); >=20 > + if (!EFI_ERROR (Status)) { >=20 > + SmiHandlerProfileUnregisterHandler (&gPchSmiDispatchProtocolGuid, > Record->Callback, NULL, 0); >=20 > + } >=20 > + return Status; >=20 > +} >=20 > + >=20 > + >=20 > +/** >=20 > + Declaration of PCH TCO SMI DISPATCH PROTOCOL instance >=20 > +**/ >=20 > +PCH_TCO_SMI_DISPATCH_PROTOCOL mPchTcoSmiDispatchProtocol =3D { >=20 > + PCH_TCO_SMI_DISPATCH_REVISION, // Revision >=20 > + PchTcoSmiUnRegister, // Unregister >=20 > + PchTcoSmiMchRegister, // Mch >=20 > + PchTcoSmiTcoTimeoutRegister, // TcoTimeout >=20 > + PchTcoSmiOsTcoRegister, // OsTco >=20 > + PchTcoSmiNmiRegister, // Nmi >=20 > + PchTcoSmiIntruderDetRegister, // IntruderDectect >=20 > + PchTcoSmiSpiBiosWpRegister, // SpiBiosWp >=20 > + PchTcoSmiLpcBiosWpRegister, // LpcBiosWp >=20 > + PchTcoSmiNewCenturyRegister // NewCentury >=20 > +}; >=20 > + >=20 > +/** >=20 > + Declaration of PCH PCIE SMI DISPATCH PROTOCOL instance >=20 > +**/ >=20 > +PCH_PCIE_SMI_DISPATCH_PROTOCOL mPchPcieSmiDispatchProtocol =3D { >=20 > + PCH_PCIE_SMI_DISPATCH_REVISION, // Revision >=20 > + PchPcieSmiUnRegister, // Unregister >=20 > + PchPcieSmiHotPlugRegister, // PcieRpXHotPlug >=20 > + PchPcieSmiLinkActiveRegister, // PcieRpXLinkActive >=20 > + PchPcieSmiLinkEqRegister // PcieRpXLinkEq >=20 > +}; >=20 > + >=20 > +/** >=20 > + Declaration of PCH ACPI SMI DISPATCH PROTOCOL instance >=20 > +**/ >=20 > +PCH_ACPI_SMI_DISPATCH_PROTOCOL mPchAcpiSmiDispatchProtocol =3D { >=20 > + PCH_ACPI_SMI_DISPATCH_REVISION, // Revision >=20 > + PchAcpiSmiUnRegister, // Unregister >=20 > + PchAcpiSmiPmeRegister, // Pme >=20 > + PchAcpiSmiPmeB0Register, // PmeB0 >=20 > + PchAcpiSmiRtcAlarmRegister, // RtcAlarm >=20 > + PchAcpiSmiTmrOverflowRegister // TmrOverflow >=20 > +}; >=20 > + >=20 > +/** >=20 > + Declaration of MISC PCH SMI DISPATCH PROTOCOL instance >=20 > +**/ >=20 > +PCH_SMI_DISPATCH_PROTOCOL mPchSmiDispatchProtocol =3D { >=20 > + PCH_SMI_DISPATCH_REVISION, // Revision >=20 > + PchSmiUnRegister, // Unregister >=20 > + PchSmiSerialIrqRegister, // SerialIrq >=20 > + PchSmiMcSmiRegister, // McSmi >=20 > + PchSmiSmbusRegister, // SmBus >=20 > + PchSmiSpiAsyncRegister // SpiAsync >=20 > +}; >=20 > + >=20 > +/** >=20 > + Install protocols of PCH specifics SMI types, including >=20 > + PCH TCO SMI types, PCH PCIE SMI types, PCH ACPI SMI types, PCH MISC > SMI types. >=20 > + >=20 > + @retval the result of protocol installat= ion >=20 > +**/ >=20 > +EFI_STATUS >=20 > +InstallPchSmiDispatchProtocols ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + EFI_HANDLE Handle; >=20 > + EFI_STATUS Status; >=20 > + >=20 > + Handle =3D NULL; >=20 > + Status =3D gSmst->SmmInstallProtocolInterface ( >=20 > + &Handle, >=20 > + &gPchTcoSmiDispatchProtocolGuid, >=20 > + EFI_NATIVE_INTERFACE, >=20 > + &mPchTcoSmiDispatchProtocol >=20 > + ); >=20 > + Status =3D gSmst->SmmInstallProtocolInterface ( >=20 > + &Handle, >=20 > + &gPchPcieSmiDispatchProtocolGuid, >=20 > + EFI_NATIVE_INTERFACE, >=20 > + &mPchPcieSmiDispatchProtocol >=20 > + ); >=20 > + Status =3D gSmst->SmmInstallProtocolInterface ( >=20 > + &Handle, >=20 > + &gPchAcpiSmiDispatchProtocolGuid, >=20 > + EFI_NATIVE_INTERFACE, >=20 > + &mPchAcpiSmiDispatchProtocol >=20 > + ); >=20 > + Status =3D gSmst->SmmInstallProtocolInterface ( >=20 > + &Handle, >=20 > + &gPchSmiDispatchProtocolGuid, >=20 > + EFI_NATIVE_INTERFACE, >=20 > + &mPchSmiDispatchProtocol >=20 > + ); >=20 > + >=20 > + return Status; >=20 > +} >=20 > + >=20 > +/** >=20 > + The function to dispatch all callback function of PCH SMI types. >=20 > + >=20 > + @retval EFI_SUCCESS Function successfully completed >=20 > + @retval EFI_UNSUPPORTED no >=20 > +**/ >=20 > +EFI_STATUS >=20 > +PchSmiTypeCallbackDispatcher ( >=20 > + IN DATABASE_RECORD *Record >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + PCH_SMI_TYPES PchSmiType; >=20 > + UINTN RpIndex; >=20 > + PCH_PCIE_SMI_RP_CONTEXT RpContext; >=20 > + >=20 > + PchSmiType =3D Record->PchSmiType; >=20 > + Status =3D EFI_SUCCESS; >=20 > + >=20 > + switch (PchSmiType) { >=20 > + case PchTcoSmiMchType: >=20 > + case PchTcoSmiTcoTimeoutType: >=20 > + case PchTcoSmiOsTcoType: >=20 > + case PchTcoSmiNmiType: >=20 > + case PchTcoSmiIntruderDetectType: >=20 > + case PchTcoSmiSpiBiosWpType: >=20 > + case PchTcoSmiLpcBiosWpType: >=20 > + case PchTcoSmiNewCenturyType: >=20 > + ((PCH_TCO_SMI_DISPATCH_CALLBACK) (Record->PchSmiCallback)) > ((EFI_HANDLE)&Record->Link); >=20 > + break; >=20 > + case PchPcieSmiRpHotplugType: >=20 > + case PchPcieSmiRpLinkActiveType: >=20 > + case PchPcieSmiRpLinkEqType: >=20 > + RpContext.BusNum =3D DEFAULT_PCI_BUS_NUMBER_PCH; >=20 > + RpContext.DevNum =3D (UINT8) Record- > >SrcDesc.En[0].Reg.Data.pcie.Fields.Dev; >=20 > + RpContext.FuncNum =3D (UINT8) Record- > >SrcDesc.En[0].Reg.Data.pcie.Fields.Fnc; >=20 > + GetPcieRpNumber (RpContext.DevNum, RpContext.FuncNum, > &RpIndex); >=20 > + RpContext.RpIndex =3D (UINT8) RpIndex; >=20 > + ((PCH_PCIE_SMI_RP_DISPATCH_CALLBACK) (Record->PchSmiCallback)) > ((EFI_HANDLE)&Record->Link, &RpContext); >=20 > + break; >=20 > + case PchAcpiSmiPmeType: >=20 > + case PchAcpiSmiPmeB0Type: >=20 > + case PchAcpiSmiRtcAlarmType: >=20 > + case PchAcpiSmiTmrOverflowType: >=20 > + ((PCH_ACPI_SMI_DISPATCH_CALLBACK) (Record->PchSmiCallback)) > ((EFI_HANDLE)&Record->Link); >=20 > + break; >=20 > + case PchEspiSmiEspiSlaveType: >=20 > + ((PCH_ESPI_SMI_DISPATCH_CALLBACK) (Record->PchSmiCallback)) > ((EFI_HANDLE)&Record->Link); >=20 > + break; >=20 > + case PchSmiSerialIrqType: >=20 > + case PchSmiMcSmiType: >=20 > + case PchSmiSmBusType: >=20 > + case PchSmiSpiAsyncType: >=20 > + case PchIoTrapSmiType: ///< internal type for IoTrap >=20 > + ((PCH_SMI_DISPATCH_CALLBACK) (Record->PchSmiCallback)) > ((EFI_HANDLE)&Record->Link); >=20 > + break; >=20 > + default: >=20 > + Status =3D EFI_UNSUPPORTED; >=20 > + break; >=20 > + } >=20 > + >=20 > + return Status; >=20 > +} >=20 > + >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescIoTrap[4] =3D { >=20 > + // >=20 > + // PCH I/O Trap register 0 monitor >=20 > + // >=20 > + { >=20 > + PCH_SMM_NO_FLAGS, >=20 > + { >=20 > + { >=20 > + { >=20 > + PCR_ADDR_TYPE, >=20 > + {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPREG0) } >=20 > + }, >=20 > + 4, >=20 > + 0 >=20 > + }, >=20 > + NULL_BIT_DESC_INITIALIZER >=20 > + }, >=20 > + { >=20 > + { >=20 > + { >=20 > + PCR_ADDR_TYPE, >=20 > + {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPST) } >=20 > + }, >=20 > + 1, >=20 > + 0 >=20 > + } >=20 > + }, >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_MONITOR >=20 > + } >=20 > + }, >=20 > + // >=20 > + // PCH I/O Trap register 1 monitor >=20 > + // >=20 > + { >=20 > + PCH_SMM_NO_FLAGS, >=20 > + { >=20 > + { >=20 > + { >=20 > + PCR_ADDR_TYPE, >=20 > + {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPREG1) } >=20 > + }, >=20 > + 4, >=20 > + 0 >=20 > + }, >=20 > + NULL_BIT_DESC_INITIALIZER >=20 > + }, >=20 > + { >=20 > + { >=20 > + { >=20 > + PCR_ADDR_TYPE, >=20 > + {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPST) } >=20 > + }, >=20 > + 1, >=20 > + 1 >=20 > + } >=20 > + }, >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_MONITOR >=20 > + } >=20 > + }, >=20 > + // >=20 > + // PCH I/O Trap register 2 monitor >=20 > + // >=20 > + { >=20 > + PCH_SMM_NO_FLAGS, >=20 > + { >=20 > + { >=20 > + { >=20 > + PCR_ADDR_TYPE, >=20 > + {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPREG2) } >=20 > + }, >=20 > + 4, >=20 > + 0 >=20 > + }, >=20 > + NULL_BIT_DESC_INITIALIZER >=20 > + }, >=20 > + { >=20 > + { >=20 > + { >=20 > + PCR_ADDR_TYPE, >=20 > + {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPST) } >=20 > + }, >=20 > + 1, >=20 > + 2 >=20 > + } >=20 > + }, >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_MONITOR >=20 > + } >=20 > + }, >=20 > + // >=20 > + // PCH I/O Trap register 3 monitor, >=20 > + // >=20 > + { >=20 > + PCH_SMM_NO_FLAGS, >=20 > + { >=20 > + { >=20 > + { >=20 > + PCR_ADDR_TYPE, >=20 > + {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPREG3) } >=20 > + }, >=20 > + 4, >=20 > + 0 >=20 > + }, >=20 > + NULL_BIT_DESC_INITIALIZER >=20 > + }, >=20 > + { >=20 > + { >=20 > + { >=20 > + PCR_ADDR_TYPE, >=20 > + {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPST) } >=20 > + }, >=20 > + 1, >=20 > + 3 >=20 > + } >=20 > + }, >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_MONITOR >=20 > + } >=20 > + } >=20 > +}; >=20 > + >=20 > +/** >=20 > + The register function used to register SMI handler of IoTrap event. >=20 > + This is internal function and only used by Iotrap module. >=20 > + >=20 > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source >=20 > + @param[in] IoTrapIndex Index number of IOTRAP register >=20 > + @param[out] DispatchHandle Handle of dispatch function to r= egister. >=20 > + >=20 > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description >=20 > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record >=20 > + @retval EFI_SUCCESS The database record is created s= uccessfully. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +PchInternalIoTrapSmiRegister ( >=20 > + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + IN UINTN IoTrapIndex, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + >=20 > + Status =3D PchSmiRecordInsert ( >=20 > + &mSrcDescIoTrap[IoTrapIndex], >=20 > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, >=20 > + PchIoTrapSmiType, >=20 > + DispatchHandle >=20 > + ); >=20 > + PchSmmClearSource (&mSrcDescIoTrap[IoTrapIndex]); >=20 > + PchSmmEnableSource (&mSrcDescIoTrap[IoTrapIndex]); >=20 > + return Status; >=20 > +} >=20 > + >=20 > +/** >=20 > + Unregister a child SMI source dispatch function with a parent SMM driv= er >=20 > + >=20 > + @param[in] DispatchHandle Handle of dispatch function to > deregister. >=20 > + >=20 > + @retval EFI_SUCCESS The dispatch function has been s= uccessfully >=20 > + unregistered and the SMI source = has been disabled >=20 > + if there are no other registered= child dispatch >=20 > + functions for this SMI source. >=20 > + @retval EFI_INVALID_PARAMETER Handle is invalid. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +PchInternalIoTrapSmiUnRegister ( >=20 > + IN EFI_HANDLE DispatchHandle >=20 > + ) >=20 > +{ >=20 > + return PchSmmCoreUnRegister (NULL, DispatchHandle); >=20 > +} >=20 > diff --git > a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispa > tcher.inf > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispa > tcher.inf > new file mode 100644 > index 0000000000..97ad2f457e > --- /dev/null > +++ > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispa > tcher.inf > @@ -0,0 +1,116 @@ > +## @file >=20 > +# Component description file for the Pch SMI Dispatch Handlers module >=20 > +# >=20 > +# Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > +# SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +# >=20 > +## >=20 > + >=20 > + >=20 > +[Defines] >=20 > +INF_VERSION =3D 0x00010017 >=20 > +BASE_NAME =3D PchSmiDispatcher >=20 > +FILE_GUID =3D B0D6ED53-B844-43f5-BD2F-61095264E77E >=20 > +VERSION_STRING =3D 1.0 >=20 > +MODULE_TYPE =3D DXE_SMM_DRIVER >=20 > +PI_SPECIFICATION_VERSION =3D 1.10 >=20 > +ENTRY_POINT =3D InitializePchSmmDispatcher >=20 > + >=20 > + >=20 > +[LibraryClasses] >=20 > +UefiBootServicesTableLib >=20 > +UefiDriverEntryPoint >=20 > +IoLib >=20 > +DebugLib >=20 > +PcdLib >=20 > +BaseLib >=20 > +BaseMemoryLib >=20 > +HobLib >=20 > +DevicePathLib >=20 > +PchCycleDecodingLib >=20 > +PchPcieRpLib >=20 > +PchPcrLib >=20 > +SmmServicesTableLib >=20 > +ReportStatusCodeLib >=20 > +PerformanceLib >=20 > +DxeServicesTableLib >=20 > +GpioLib >=20 > +GpioPrivateLib >=20 > +EspiLib >=20 > +S3BootScriptLib >=20 > +ConfigBlockLib >=20 > +PmcPrivateLib >=20 > +PmcLib >=20 > +SmiHandlerProfileLib >=20 > +CpuPcieRpLib >=20 > +PchPciBdfLib >=20 > +PmcPrivateLibWithS3 >=20 > +CpuPcieInfoFruLib >=20 > + >=20 > +[Packages] >=20 > +MdePkg/MdePkg.dec >=20 > +TigerlakeSiliconPkg/SiPkg.dec >=20 > + >=20 > + >=20 > +[Pcd] >=20 > +# Progress Code for S3 Suspend start. >=20 > +# PROGRESS_CODE_S3_SUSPEND_START =3D (EFI_SOFTWARE_SMM_DRIVER > | (EFI_OEM_SPECIFIC | 0x00000000)) =3D 0x03078000 >=20 > +gSiPkgTokenSpaceGuid.PcdProgressCodeS3SuspendStart >=20 > +# Progress Code for S3 Suspend end. >=20 > +# PROGRESS_CODE_S3_SUSPEND_END =3D (EFI_SOFTWARE_SMM_DRIVER > | (EFI_OEM_SPECIFIC | 0x00000001)) =3D 0x03078001 >=20 > +gSiPkgTokenSpaceGuid.PcdProgressCodeS3SuspendEnd >=20 > +gSiPkgTokenSpaceGuid.PcdEfiGcdAllocateType >=20 > + >=20 > + >=20 > +[Sources] >=20 > +PchSmm.h >=20 > +PchSmmCore.c >=20 > +PchSmmHelpers.h >=20 > +PchSmmHelpers.c >=20 > +PchxSmmHelpers.h >=20 > +PchxSmmHelpers.c >=20 > +PchSmmUsb.c >=20 > +PchSmmGpi.c >=20 > +PchSmmPowerButton.c >=20 > +PchSmmSw.c >=20 > +PchSmmSx.c >=20 > +PchSmmPeriodicTimer.c >=20 > +IoTrap.c >=20 > +PchSmiDispatch.c >=20 > +PchSmmEspi.c >=20 > +PchSmiHelperClient.c >=20 > + >=20 > + >=20 > +[Protocols] >=20 > +gEfiPciRootBridgeIoProtocolGuid ## CONSUMES >=20 > +gEfiSmmGpiDispatch2ProtocolGuid ## PRODUCES >=20 > +gEfiSmmSxDispatch2ProtocolGuid ## PRODUCES >=20 > +gEfiSmmSwDispatch2ProtocolGuid ## PRODUCES >=20 > +gEfiSmmUsbDispatch2ProtocolGuid ## PRODUCES >=20 > +gEfiSmmPowerButtonDispatch2ProtocolGuid ## PRODUCES >=20 > +gEfiSmmPeriodicTimerDispatch2ProtocolGuid ## PRODUCES >=20 > +gEfiSmmBase2ProtocolGuid ## CONSUMES >=20 > +gEfiSmmCpuProtocolGuid ## CONSUMES >=20 > +gEfiSmmReadyToLockProtocolGuid ## CONSUMES >=20 > +gEfiSmmIoTrapDispatch2ProtocolGuid ## PRODUCES >=20 > +gPchSmmIoTrapControlGuid ## PRODUCES >=20 > +gPchTcoSmiDispatchProtocolGuid ## PRODUCES >=20 > +gPchPcieSmiDispatchProtocolGuid ## PRODUCES >=20 > +gPchAcpiSmiDispatchProtocolGuid ## PRODUCES >=20 > +gPchSmiDispatchProtocolGuid ## PRODUCES >=20 > +gPchEspiSmiDispatchProtocolGuid ## PRODUCES >=20 > +gPchSmmPeriodicTimerControlGuid ## PRODUCES >=20 > +gIoTrapExDispatchProtocolGuid ## PRODUCES >=20 > +gPchNvsAreaProtocolGuid ## CONSUMES >=20 > + >=20 > + >=20 > +[Guids] >=20 > + >=20 > + >=20 > +[Depex] >=20 > +gEfiPciRootBridgeIoProtocolGuid AND >=20 > +gEfiPciHostBridgeResourceAllocationProtocolGuid AND ## This is to ensure > that PCI MMIO resource has been prepared and available for this driver to > allocate. >=20 > +gEfiSmmCpuProtocolGuid AND >=20 > +gEfiSmmBase2ProtocolGuid AND ## This is for SmmServicesTableLib >=20 > +gPchNvsAreaProtocolGuid >=20 > + >=20 > diff --git > a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelp > er.h > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelp > er.h > new file mode 100644 > index 0000000000..189197f4a2 > --- /dev/null > +++ > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelp > er.h > @@ -0,0 +1,40 @@ > +/** @file >=20 > + eSPI SMI Dispatch header PCH SMI Helper Header >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > + >=20 > +#ifndef _PCH_SMI_HELPER_H_ >=20 > +#define _PCH_SMI_HELPER_H_ >=20 > +#include >=20 > + >=20 > +/** >=20 > + Get Root Port physical Number by CPU or PCH Pcie Root Port Device and > Function Number >=20 > + >=20 > + @param[in] RpDev Root port device number. >=20 > + @param[in] RpFun Root port function number. >=20 > + @param[out] RpNumber Return corresponding physical Root P= ort > index (0-based) >=20 > +**/ >=20 > +VOID >=20 > +GetPcieRpNumber ( >=20 > + IN UINTN RpDev, >=20 > + IN UINTN RpFun, >=20 > + OUT UINTN *RpNumber >=20 > + ); >=20 > + >=20 > +/** >=20 > + Get CPU or PCH Pcie Root Port Device and Function Number by Root Port > physical Number >=20 > + >=20 > + @param[in] RpNumber Root port physical number. (0-based) >=20 > + @param[out] RpDev Return corresponding root port devic= e > number. >=20 > + @param[out] RpFun Return corresponding root port funct= ion > number. >=20 > +**/ >=20 > +VOID >=20 > +GetPcieRpDevFun ( >=20 > + IN UINTN RpIndex, >=20 > + OUT UINTN *RpDev, >=20 > + OUT UINTN *RpFun >=20 > + ); >=20 > + >=20 > +#endif >=20 > diff --git > a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelp > erClient.c > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelp > erClient.c > new file mode 100644 > index 0000000000..7693e76683 > --- /dev/null > +++ > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelp > erClient.c > @@ -0,0 +1,57 @@ > +/** @file >=20 > + This file provides function to handle client-server differences. >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > +#include "PchSmmHelpers.h" >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > + >=20 > +/** >=20 > + Get Root Port physical Number by CPU or PCH Pcie Root Port Device and > Function Number >=20 > + >=20 > + @param[in] RpDev Root port device number. >=20 > + @param[in] RpFun Root port function number. >=20 > + @param[out] RpNumber Return corresponding physical Root P= ort > index (0-based) >=20 > +**/ >=20 > +VOID >=20 > +GetPcieRpNumber ( >=20 > + IN UINTN RpDev, >=20 > + IN UINTN RpFun, >=20 > + OUT UINTN *RpNumber >=20 > + ) >=20 > +{ >=20 > + UINT64 RpBase; >=20 > + RpBase =3D PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM, SA_MC_BUS, > RpDev, RpFun, 0); >=20 > + GetPchPcieRpNumber (RpDev, RpFun, RpNumber); >=20 > +} >=20 > + >=20 > +/** >=20 > + Get CPU or PCH Pcie Root Port Device and Function Number by Root Port > physical Number >=20 > + >=20 > + @param[in] RpNumber Root port physical number. (0-based) >=20 > + @param[out] RpDev Return corresponding root port devic= e > number. >=20 > + @param[out] RpFun Return corresponding root port funct= ion > number. >=20 > +**/ >=20 > +VOID >=20 > +GetPcieRpDevFun ( >=20 > + IN UINTN RpIndex, >=20 > + OUT UINTN *RpDev, >=20 > + OUT UINTN *RpFun >=20 > + ) >=20 > +{ >=20 > + if (RpIndex >=3D CpuRpIndex0 && RpIndex <=3D CpuRpIndex3) { >=20 > + GetCpuPcieRpDevFun ((RpIndex - CpuRpIndex0), RpDev, RpFun); >=20 > + } else { >=20 > + *RpDev =3D PchPcieRpDevNumber (RpIndex); >=20 > + *RpFun =3D PchPcieRpFuncNumber (RpIndex); >=20 > + } >=20 > +} >=20 > diff --git > a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmm.h > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmm.h > new file mode 100644 > index 0000000000..6a23de2bc9 > --- /dev/null > +++ > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmm.h > @@ -0,0 +1,1043 @@ > +/** @file >=20 > + Prototypes and defines for the PCH SMM Dispatcher. >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > +#ifndef _PCH_SMM_H_ >=20 > +#define _PCH_SMM_H_ >=20 > + >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include "IoTrap.h" >=20 > + >=20 > +#define EFI_BAD_POINTER 0xAFAFAFAFAFAFAFAFULL >=20 > + >=20 > +extern BOOLEAN mReadyToLock; >=20 > + >=20 > +/// >=20 > +/// Define an enumeration for all the supported protocols >=20 > +/// >=20 > +#define PCH_SMM_PROTOCOL_TYPE_MAX 6 >=20 > + >=20 > +typedef enum { >=20 > + UsbType, >=20 > + SxType, >=20 > + SwType, >=20 > + GpiType, >=20 > + PowerButtonType, >=20 > + PeriodicTimerType, >=20 > + PchSmiDispatchType, >=20 > + PchSmmProtocolTypeMax >=20 > +} PCH_SMM_PROTOCOL_TYPE; >=20 > + >=20 > +/// >=20 > +/// Define all the supported types of PCH SMI >=20 > +/// >=20 > +typedef enum { >=20 > + PchTcoSmiMchType, >=20 > + PchTcoSmiTcoTimeoutType, >=20 > + PchTcoSmiOsTcoType, >=20 > + PchTcoSmiNmiType, >=20 > + PchTcoSmiIntruderDetectType, >=20 > + PchTcoSmiSpiBiosWpType, >=20 > + PchTcoSmiLpcBiosWpType, >=20 > + PchTcoSmiNewCenturyType, >=20 > + PchPcieSmiRpHotplugType, >=20 > + PchPcieSmiRpLinkActiveType, >=20 > + PchPcieSmiRpLinkEqType, >=20 > + PchAcpiSmiPmeType, >=20 > + PchAcpiSmiPmeB0Type, >=20 > + PchAcpiSmiRtcAlarmType, >=20 > + PchAcpiSmiTmrOverflowType, >=20 > + PchEspiSmiEspiSlaveType, >=20 > + PchSmiSerialIrqType, >=20 > + PchSmiMcSmiType, >=20 > + PchSmiSmBusType, >=20 > + PchSmiSpiAsyncType, >=20 > + PchIoTrapSmiType ///< internal SMI type >=20 > +} PCH_SMI_TYPES; >=20 > + >=20 > +/// >=20 > +/// Generic funciton pointer to cover all Pch SMI function pointer types >=20 > +/// >=20 > +typedef >=20 > +VOID >=20 > +(EFIAPI *PCH_SMI_CALLBACK_FUNCTIONS) ( >=20 > + IN EFI_HANDLE DispatchHandle, >=20 > + ... >=20 > + ); >=20 > + >=20 > + >=20 > +/// >=20 > +/// SPECIFYING A REGISTER >=20 > +/// We want a general way of referring to addresses. For this case, we'= ll > only >=20 > +/// need addresses in the ACPI table (and the TCO entries within the ACP= I > table). >=20 > +/// However, it's interesting to consider what it would take to support = other > types >=20 > +/// of addresses. To address Will's concern, I think it prudent to > accommodate it >=20 > +/// early on in the design. >=20 > +/// >=20 > +/// Addresses we need to consider: >=20 > +/// >=20 > +/// Type: Required: >=20 > +/// I/O Yes >=20 > +/// ACPI (special case of I/O) Only if we want to >=20 > +/// TCO (special case of I/O) Only if we want to >=20 > +/// GPIO (special case of MMIO) Only if we want to >=20 > +/// Memory (or Memory Mapped I/O) Only if we want to >=20 > +/// PCIE Yes, for BiosWp >=20 > +/// >=20 > +typedef enum { >=20 > + /// >=20 > + /// IO_ADDR_TYPE, /// unimplemented >=20 > + /// >=20 > + ACPI_ADDR_TYPE, >=20 > + TCO_ADDR_TYPE, >=20 > + /// >=20 > + /// MEMORY_ADDR_TYPE, /// unimplemented >=20 > + /// >=20 > + GPIO_ADDR_TYPE, >=20 > + MEMORY_MAPPED_IO_ADDRESS_TYPE, >=20 > + PCIE_ADDR_TYPE, >=20 > + PCR_ADDR_TYPE, >=20 > + NUM_ADDR_TYPES, ///< count of items in this enum >=20 > + PCH_SMM_ADDR_TYPE_NULL =3D -1 ///< sentinel to indicate NULL o= r to > signal end of arrays >=20 > +} ADDR_TYPE; >=20 > + >=20 > +// >=20 > +// Assumption: 32-bits -- enum's evaluate to integer >=20 > +// Assumption: This code will only run on IA-32. Justification: IA-64 d= oesn't > have SMIs. >=20 > +// We don't have to worry about 64-bit addresses. >=20 > +// Typedef the size of addresses in case the numbers I'm using are wrong= or > in case >=20 > +// this changes. This is a good idea because PCI_ADDR will change, for > example, when >=20 > +// we add support for PciExpress. >=20 > +// >=20 > +typedef UINT16 IO_ADDR; >=20 > +typedef IO_ADDR ACPI_ADDR; ///< can omit >=20 > +typedef IO_ADDR TCO_ADDR; ///< can omit >=20 > +typedef UINTN MEM_ADDR; >=20 > +typedef MEM_ADDR *MEMORY_MAPPED_IO_ADDRESS; >=20 > +typedef MEM_ADDR *GPIO_ADDR; >=20 > +typedef union { >=20 > + UINT32 Raw; >=20 > + struct { >=20 > + UINT32 Reg: 16; >=20 > + UINT32 Fnc: 3; >=20 > + UINT32 Dev: 5; >=20 > + UINT32 Bus: 8; >=20 > + } Fields; >=20 > +} PCIE_ADDR; >=20 > + >=20 > +typedef union { >=20 > + UINT32 Raw; >=20 > + struct { >=20 > + UINT16 Offset; >=20 > + UINT8 Pid; >=20 > + UINT8 Base; >=20 > + } Fields; >=20 > +} PCR_ADDR; >=20 > + >=20 > +typedef struct { >=20 > + ADDR_TYPE Type; >=20 > + union { >=20 > + /// >=20 > + /// used to initialize during declaration/definition >=20 > + /// >=20 > + UINT32 raw; >=20 > + >=20 > + /// >=20 > + /// used to access useful data >=20 > + /// >=20 > + IO_ADDR io; >=20 > + ACPI_ADDR acpi; >=20 > + TCO_ADDR tco; >=20 > + GPIO_ADDR gpio; >=20 > + MEM_ADDR mem; >=20 > + MEMORY_MAPPED_IO_ADDRESS Mmio; >=20 > + PCIE_ADDR pcie; >=20 > + PCR_ADDR Pcr; >=20 > + >=20 > + } Data; >=20 > + >=20 > +} PCH_SMM_ADDRESS; >=20 > + >=20 > +/// >=20 > +/// SPECIFYING BITS WITHIN A REGISTER >=20 > +/// Here's a struct that helps us specify a source or enable bit. >=20 > +/// >=20 > +typedef struct { >=20 > + PCH_SMM_ADDRESS Reg; >=20 > + UINT8 SizeInBytes; ///< of the register >=20 > + UINT8 Bit; >=20 > +} PCH_SMM_BIT_DESC; >=20 > + >=20 > +// >=20 > +// Sometimes, we'll have bit descriptions that are unused. It'd be grea= t to > have a >=20 > +// way to easily identify them: >=20 > +// >=20 > +#define IS_BIT_DESC_NULL(BitDesc) ((BitDesc).Reg.Type =3D=3D > PCH_SMM_ADDR_TYPE_NULL) ///< "returns" true when BitDesc is NULL >=20 > +#define NULL_THIS_BIT_DESC(BitDesc) ((BitDesc).Reg.Type =3D > PCH_SMM_ADDR_TYPE_NULL) ///< will "return" an integer w/ value of 0 >=20 > +#define NULL_BIT_DESC_INITIALIZER \ >=20 > + { \ >=20 > + { \ >=20 > + PCH_SMM_ADDR_TYPE_NULL, \ >=20 > + { \ >=20 > + 0 \ >=20 > + } \ >=20 > + }, \ >=20 > + 0, 0 \ >=20 > + } >=20 > +// >=20 > +// I'd like a type to specify the callback's Sts & En bits because they'= ll >=20 > +// be commonly used together: >=20 > +// >=20 > +#define NUM_EN_BITS 2 >=20 > +#define NUM_STS_BITS 1 >=20 > + >=20 > +// >=20 > +// Flags >=20 > +// >=20 > +typedef UINT8 PCH_SMM_SOURCE_FLAGS; >=20 > + >=20 > +// >=20 > +// Flags required to describe the event source >=20 > +// >=20 > +#define PCH_SMM_NO_FLAGS 0 >=20 > +#define PCH_SMM_SCI_EN_DEPENDENT 1 >=20 > + >=20 > +typedef struct { >=20 > + PCH_SMM_SOURCE_FLAGS Flags; >=20 > + PCH_SMM_BIT_DESC En[NUM_EN_BITS]; ///< Describes the enable > bit(s) for the SMI event >=20 > + PCH_SMM_BIT_DESC Sts[NUM_STS_BITS]; ///< Describes the > secondary status bit for the SMI event. Might be the same as TopLevelSmi >=20 > + PCH_SMM_BIT_DESC PmcSmiSts; ///< Refereing to the top le= vel > status bit in PMC SMI_STS, i.e. R_PCH_SMI_STS >=20 > +} PCH_SMM_SOURCE_DESC; >=20 > + >=20 > +/// >=20 > +/// Used to initialize null source descriptor >=20 > +/// >=20 > +#define NULL_SOURCE_DESC_INITIALIZER \ >=20 > + { \ >=20 > + PCH_SMM_NO_FLAGS, \ >=20 > + { \ >=20 > + NULL_BIT_DESC_INITIALIZER, NULL_BIT_DESC_INITIALIZER \ >=20 > + }, \ >=20 > + { \ >=20 > + NULL_BIT_DESC_INITIALIZER \ >=20 > + }, \ >=20 > + NULL_BIT_DESC_INITIALIZER \ >=20 > + } >=20 > + >=20 > +/// >=20 > +/// Define a PCIE RP event context for SmiProfileHandlerInfo tool >=20 > +/// >=20 > +typedef struct { >=20 > + PCH_SMI_TYPES PchSmiType; >=20 > + UINTN RpIndex; >=20 > +} PCH_SMM_PCIE_REGISTER_CONTEXT; >=20 > + >=20 > +/// >=20 > +/// CHILD CONTEXTS >=20 > +/// To keep consistent w/ the architecture, we'll need to provide the > context >=20 > +/// to the child when we call its callback function. After talking with= Will, >=20 > +/// we agreed that we'll need functions to "dig" the context out of the > hardware >=20 > +/// in many cases (Sx, Trap, Gpi, etc), and we'll need a function to com= pare > those >=20 > +/// contexts to prevent unnecessary dispatches. I'd like a general type= for > these >=20 > +/// "GetContext" functions, so I'll need a union of all the protocol con= texts > for >=20 > +/// our internal use: >=20 > +/// >=20 > +typedef union { >=20 > + // >=20 > + // (in no particular order) >=20 > + // >=20 > + EFI_SMM_SX_REGISTER_CONTEXT Sx; >=20 > + EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT PeriodicTimer; >=20 > + EFI_SMM_SW_REGISTER_CONTEXT Sw; >=20 > + EFI_SMM_POWER_BUTTON_REGISTER_CONTEXT PowerButton; >=20 > + EFI_SMM_USB_REGISTER_CONTEXT Usb; >=20 > + EFI_SMM_GPI_REGISTER_CONTEXT Gpi; >=20 > + PCH_SMM_PCIE_REGISTER_CONTEXT Pcie; >=20 > +} PCH_SMM_CONTEXT; >=20 > + >=20 > +/// >=20 > +/// Misc data for PchDispatcher usage. >=20 > +/// For PeriodicTimer, since the ElapsedTime is removed from > EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT of EDKII, >=20 > +/// and PchDispatcher needs it for every record. Thus move it here to > support ElapsedTime. >=20 > +/// >=20 > +typedef struct { >=20 > + UINTN ElapsedTime; >=20 > + /// >=20 > + /// A switch to control periodic timer SMI enabling >=20 > + /// >=20 > + BOOLEAN TimerSmiEnabled; >=20 > +} PCH_SMM_MISC_DATA; >=20 > + >=20 > +// >=20 > +// Assumption: PeriodicTimer largest at 3x64-bits or 24 bytes >=20 > +// >=20 > +typedef struct _DATABASE_RECORD DATABASE_RECORD; >=20 > + >=20 > +/// >=20 > +/// Assumption: the GET_CONTEXT function will be as small and simple as > possible. >=20 > +/// Assumption: We don't need to pass in an enumeration for the protocol > because each >=20 > +/// GET_CONTEXT function is written for only one protocol. >=20 > +/// We also need a function to compare contexts to see if the child shou= ld > be dispatched >=20 > +/// In addition, we need a function to acquire CommBuffer and > CommBufferSize for >=20 > +/// dispatch callback function of EDKII native support. >=20 > +/// >=20 > +typedef >=20 > +VOID >=20 > +(EFIAPI *GET_CONTEXT) ( >=20 > + IN DATABASE_RECORD * Record, >=20 > + OUT PCH_SMM_CONTEXT * Context >=20 > + ); >=20 > + >=20 > +typedef >=20 > +BOOLEAN >=20 > +(EFIAPI *CMP_CONTEXT) ( >=20 > + IN PCH_SMM_CONTEXT * Context1, >=20 > + IN PCH_SMM_CONTEXT * Context2 >=20 > + ); >=20 > + >=20 > +typedef >=20 > +VOID >=20 > +(EFIAPI *GET_COMMBUFFER) ( >=20 > + IN DATABASE_RECORD * Record, >=20 > + OUT VOID **CommBuffer, >=20 > + OUT UINTN * CommBufferSize >=20 > + ); >=20 > + >=20 > +/// >=20 > +/// Finally, every protocol will require a "Get Context" and "Compare > Context" call, so >=20 > +/// we may as well wrap that up in a table, too. >=20 > +/// >=20 > +typedef struct { >=20 > + GET_CONTEXT GetContext; >=20 > + CMP_CONTEXT CmpContext; >=20 > + GET_COMMBUFFER GetCommBuffer; >=20 > +} CONTEXT_FUNCTIONS; >=20 > + >=20 > +extern CONTEXT_FUNCTIONS > ContextFunctions[PCH_SMM_PROTOCOL_TYPE_MAX]; >=20 > + >=20 > +/// >=20 > +/// MAPPING CONTEXT TO BIT DESCRIPTIONS >=20 > +/// I'd like to have a general approach to mapping contexts to bit > descriptions. >=20 > +/// Sometimes, we'll find that we can use table lookups or constant > assignments; >=20 > +/// other times, we'll find that we'll need to use a function to perform= the > mapping. >=20 > +/// If we define a macro to mask that process, we'll never have to chang= e > the code. >=20 > +/// I don't know if this is desirable or not -- if it isn't, then we can= get rid >=20 > +/// of the macros and just use function calls or variable assignments. > Doesn't matter >=20 > +/// to me. >=20 > +/// Mapping complex contexts requires a function >=20 > +/// >=20 > + >=20 > +/** >=20 > + Maps a USB context to a source description. >=20 > + >=20 > + @param[in] Context The context we need to map. Type must= be > USB. >=20 > + @param[out] SrcDesc The source description that correspond= s to > the given context. >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +MapUsbToSrcDesc ( >=20 > + IN PCH_SMM_CONTEXT *Context, >=20 > + OUT PCH_SMM_SOURCE_DESC *SrcDesc >=20 > + ); >=20 > + >=20 > +/** >=20 > + Figure out which timer the child is requesting and >=20 > + send back the source description >=20 > + >=20 > + @param[in] DispatchContext The pointer to the Dispatch Context > instances >=20 > + @param[out] SrcDesc The pointer to the source description >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +MapPeriodicTimerToSrcDesc ( >=20 > + IN PCH_SMM_CONTEXT *DispatchC= ontext, >=20 > + OUT PCH_SMM_SOURCE_DESC *SrcDesc >=20 > + ); >=20 > + >=20 > +// >=20 > +// Mapping simple contexts can be done by assignment or lookup table >=20 > +// >=20 > +extern CONST PCH_SMM_SOURCE_DESC mSxSourceDesc; >=20 > +extern CONST PCH_SMM_SOURCE_DESC mPowerButtonSourceDesc; >=20 > +extern CONST PCH_SMM_SOURCE_DESC mSrcDescNewCentury; >=20 > +extern CONST PCH_SMM_SOURCE_DESC mGpiSourceDescTemplate; >=20 > + >=20 > +/// >=20 > +/// For PCHx, APMC is UINT8 port, so the MAX SWI Value is 0xFF. >=20 > +/// >=20 > +#define MAXIMUM_SWI_VALUE 0xFF >=20 > +/// >=20 > +/// Open: Need to make sure this kind of type cast will actually work. >=20 > +/// May need an intermediate form w/ two VOID* arguments. I'll figure >=20 > +/// that out when I start compiling. >=20 > +/// >=20 > +typedef >=20 > +VOID >=20 > +(EFIAPI *PCH_SMM_CLEAR_SOURCE) ( >=20 > + CONST PCH_SMM_SOURCE_DESC * SrcDesc >=20 > + ); >=20 > + >=20 > +/// >=20 > +/// "DATABASE" RECORD >=20 > +/// Linked list data structures >=20 > +/// >=20 > +#define DATABASE_RECORD_SIGNATURE SIGNATURE_32 ('D', 'B', 'R', 'C') >=20 > + >=20 > +struct _DATABASE_RECORD { >=20 > + UINT32 Signature; >=20 > + LIST_ENTRY Link; >=20 > + BOOLEAN Processed; >=20 > + /// >=20 > + /// Status and Enable bit description >=20 > + /// >=20 > + PCH_SMM_SOURCE_DESC SrcDesc; >=20 > + >=20 > + /// >=20 > + /// Callback function >=20 > + /// >=20 > + EFI_SMM_HANDLER_ENTRY_POINT2 Callback; >=20 > + PCH_SMM_CONTEXT ChildContext; >=20 > + UINTN ContextSize; >=20 > + >=20 > + /// >=20 > + /// Special handling hooks -- init them to NULL if unused/unneeded >=20 > + /// >=20 > + PCH_SMM_CLEAR_SOURCE ClearSource; >=20 > + >=20 > + /// >=20 > + /// Functions required to make callback code general >=20 > + /// >=20 > + CONTEXT_FUNCTIONS ContextFunctions; >=20 > + >=20 > + /// >=20 > + /// The protocol that this record dispatches >=20 > + /// >=20 > + PCH_SMM_PROTOCOL_TYPE ProtocolType; >=20 > + >=20 > + /// >=20 > + /// Misc data for private usage >=20 > + /// >=20 > + PCH_SMM_MISC_DATA MiscData; >=20 > + >=20 > + /// >=20 > + /// PCH SMI callback function >=20 > + /// >=20 > + PCH_SMI_CALLBACK_FUNCTIONS PchSmiCallback; >=20 > + /// >=20 > + /// Indicate the PCH SMI types. >=20 > + /// >=20 > + PCH_SMI_TYPES PchSmiType; >=20 > +}; >=20 > + >=20 > +#define DATABASE_RECORD_FROM_LINK(_record) CR (_record, > DATABASE_RECORD, Link, DATABASE_RECORD_SIGNATURE) >=20 > +#define DATABASE_RECORD_FROM_CHILDCONTEXT(_record) CR (_record, > DATABASE_RECORD, ChildContext, DATABASE_RECORD_SIGNATURE) >=20 > + >=20 > +/// >=20 > +/// HOOKING INTO THE ARCHITECTURE >=20 > +/// >=20 > +typedef >=20 > +EFI_STATUS >=20 > +(EFIAPI *PCH_SMM_GENERIC_REGISTER) ( >=20 > + IN VOID **This, >=20 > + IN VOID *DispatchFunction, >=20 > + IN VOID *DispatchContext, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ); >=20 > +typedef >=20 > +EFI_STATUS >=20 > +(EFIAPI *PCH_SMM_GENERIC_UNREGISTER) ( >=20 > + IN VOID **This, >=20 > + IN EFI_HANDLE DispatchHandle >=20 > + ); >=20 > + >=20 > +/// >=20 > +/// Define a memory "stamp" equivalent in size and function to most of t= he > protocols >=20 > +/// >=20 > +typedef struct { >=20 > + PCH_SMM_GENERIC_REGISTER Register; >=20 > + PCH_SMM_GENERIC_UNREGISTER Unregister; >=20 > + UINTN Extra1; >=20 > + UINTN Extra2; ///< may not need this one >=20 > +} PCH_SMM_GENERIC_PROTOCOL; >=20 > + >=20 > +/** >=20 > + Register a child SMI dispatch function with a parent SMM driver. >=20 > + >=20 > + @param[in] This Pointer to the PCH_SMM_GENERIC_PROTOCO= L > instance. >=20 > + @param[in] DispatchFunction Pointer to dispatch function to be inv= oked > for this SMI source. >=20 > + @param[in] DispatchContext Pointer to the dispatch function's con= text. >=20 > + @param[out] DispatchHandle Handle of dispatch function, for when > interfacing >=20 > + with the parent SMM driver, will be th= e address of linked >=20 > + list link in the call back record. >=20 > + >=20 > + @retval EFI_OUT_OF_RESOURCES Insufficient resources to create > database record >=20 > + @retval EFI_INVALID_PARAMETER The input parameter is invalid >=20 > + @retval EFI_SUCCESS The dispatch function has been success= fully >=20 > + registered and the SMI source has been= enabled. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchPiSmmCoreRegister ( >=20 > + IN PCH_SMM_GENERIC_PROTOCOL *This, >=20 > + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction= , >=20 > + IN PCH_SMM_CONTEXT *DispatchContext= , >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ); >=20 > + >=20 > +/** >=20 > + Unregister a child SMI source dispatch function with a parent SMM driv= er >=20 > + >=20 > + @param[in] This Protocol instance pointer. >=20 > + @param[in] DispatchHandle Handle of dispatch function to > deregister. >=20 > + >=20 > + @retval EFI_SUCCESS The dispatch function has been s= uccessfully >=20 > + unregistered and the SMI source = has been disabled >=20 > + if there are no other registered= child dispatch >=20 > + functions for this SMI source. >=20 > + @retval EFI_INVALID_PARAMETER Handle is invalid. >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchPiSmmCoreUnRegister ( >=20 > + IN PCH_SMM_GENERIC_PROTOCOL *This, >=20 > + IN EFI_HANDLE *DispatchHandle >=20 > + ); >=20 > + >=20 > + >=20 > +/** >=20 > + Unregister a child SMI source dispatch function with a parent SMM driv= er. >=20 > + >=20 > + @param[in] This Pointer to the PCH_SMM_GENERIC_PROTOCO= L > instance. >=20 > + @param[in] DispatchHandle Handle of dispatch function to deregis= ter. >=20 > + >=20 > + @retval EFI_SUCCESS The dispatch function has been success= fully >=20 > + unregistered and the SMI source has be= en disabled >=20 > + if there are no other registered child= dispatch >=20 > + functions for this SMI source. >=20 > + @retval EFI_INVALID_PARAMETER Handle is invalid. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchSmmCoreUnRegister ( >=20 > + IN PCH_SMM_GENERIC_PROTOCOL *This, >=20 > + IN EFI_HANDLE *DispatchHandle >=20 > + ); >=20 > + >=20 > +typedef union { >=20 > + PCH_SMM_GENERIC_PROTOCOL Generic; >=20 > + EFI_SMM_USB_DISPATCH2_PROTOCOL Usb; >=20 > + EFI_SMM_SX_DISPATCH2_PROTOCOL Sx; >=20 > + EFI_SMM_SW_DISPATCH2_PROTOCOL Sw; >=20 > + EFI_SMM_GPI_DISPATCH2_PROTOCOL Gpi; >=20 > + EFI_SMM_POWER_BUTTON_DISPATCH2_PROTOCOL PowerButton; >=20 > + EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL PeriodicTimer; >=20 > +} PCH_SMM_PROTOCOL; >=20 > + >=20 > +/// >=20 > +/// Define a structure to help us identify the generic protocol >=20 > +/// >=20 > +#define PROTOCOL_SIGNATURE SIGNATURE_32 ('P', 'R', 'O', 'T') >=20 > + >=20 > +typedef struct { >=20 > + UINTN Signature; >=20 > + >=20 > + PCH_SMM_PROTOCOL_TYPE Type; >=20 > + EFI_GUID *Guid; >=20 > + PCH_SMM_PROTOCOL Protocols; >=20 > +} PCH_SMM_QUALIFIED_PROTOCOL; >=20 > + >=20 > +#define QUALIFIED_PROTOCOL_FROM_GENERIC(_generic) \ >=20 > + CR ( \ >=20 > + _generic, \ >=20 > + PCH_SMM_QUALIFIED_PROTOCOL, \ >=20 > + Protocols, \ >=20 > + PROTOCOL_SIGNATURE \ >=20 > + ) >=20 > + >=20 > +/// >=20 > +/// Create private data for the protocols that we'll publish >=20 > +/// >=20 > +typedef struct { >=20 > + LIST_ENTRY CallbackDataBase; >=20 > + EFI_HANDLE SmiHandle; >=20 > + EFI_HANDLE InstallMultProtHandle; >=20 > + PCH_SMM_QUALIFIED_PROTOCOL > Protocols[PCH_SMM_PROTOCOL_TYPE_MAX]; >=20 > +} PRIVATE_DATA; >=20 > + >=20 > +extern PRIVATE_DATA mPrivateData; >=20 > +extern UINT16 mAcpiBaseAddr; >=20 > +extern UINT16 mTcoBaseAddr; >=20 > + >=20 > +/** >=20 > + The internal function used to create and insert a database record >=20 > + >=20 > + @param[in] InsertRecord Record to insert to database. >=20 > + @param[out] DispatchHandle Handle of dispatch function to r= egister. >=20 > + >=20 > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description >=20 > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record >=20 > + @retval EFI_SUCCESS The database record is created s= uccessfully. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +SmmCoreInsertRecord ( >=20 > + IN DATABASE_RECORD *NewRecord, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ); >=20 > + >=20 > +/** >=20 > + Get the Sleep type >=20 > + >=20 > + @param[in] Record No use >=20 > + @param[out] Context The context that includes SLP_TYP bits= to be > filled >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +SxGetContext ( >=20 > + IN DATABASE_RECORD *Record, >=20 > + OUT PCH_SMM_CONTEXT *Context >=20 > + ); >=20 > + >=20 > +/** >=20 > + Register a child SMI source dispatch function for the specified softwa= re > SMI. >=20 > + >=20 > + This service registers a function (DispatchFunction) which will be cal= led > when the software >=20 > + SMI source specified by RegisterContext->SwSmiCpuIndex is detected. On > return, >=20 > + DispatchHandle contains a unique handle which may be used later to > unregister the function >=20 > + using UnRegister(). >=20 > + >=20 > + @param[in] This Pointer to the > EFI_SMM_SW_DISPATCH2_PROTOCOL instance. >=20 > + @param[in] DispatchFunction Function to register for handler when= the > specified software >=20 > + SMI is generated. >=20 > + @param[in, out] RegisterContext Pointer to the dispatch function's > context. >=20 > + The caller fills this context in befo= re calling >=20 > + the register function to indicate to = the register >=20 > + function which Software SMI input val= ue the >=20 > + dispatch function should be invoked f= or. >=20 > + @param[out] DispatchHandle Handle generated by the dispatcher to > track the >=20 > + function instance. >=20 > + >=20 > + @retval EFI_SUCCESS The dispatch function has been successf= ully >=20 > + registered and the SMI source has been = enabled. >=20 > + @retval EFI_DEVICE_ERROR The SW driver was unable to enable the > SMI source. >=20 > + @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The SW SMI > input value >=20 > + is not within a valid range or is alrea= dy in use. >=20 > + @retval EFI_OUT_OF_RESOURCES There is not enough memory (system > or SMM) to manage this >=20 > + child. >=20 > + @retval EFI_OUT_OF_RESOURCES A unique software SMI value could not > be assigned >=20 > + for this dispatch. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchSwSmiRegister ( >=20 > + IN EFI_SMM_SW_DISPATCH2_PROTOCOL *This, >=20 > + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, >=20 > + IN EFI_SMM_SW_REGISTER_CONTEXT *DispatchContext, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ); >=20 > + >=20 > +/** >=20 > + Unregister a child SMI source dispatch function for the specified soft= ware > SMI. >=20 > + >=20 > + This service removes the handler associated with DispatchHandle so tha= t it > will no longer be >=20 > + called in response to a software SMI. >=20 > + >=20 > + @param[in] This Pointer to the > EFI_SMM_SW_DISPATCH2_PROTOCOL instance. >=20 > + @param[in] DispatchHandle Handle of dispatch function to deregist= er. >=20 > + >=20 > + @retval EFI_SUCCESS The dispatch function has been successf= ully > unregistered. >=20 > + @retval EFI_INVALID_PARAMETER The DispatchHandle was not valid. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchSwSmiUnRegister ( >=20 > + IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL *This, >=20 > + IN EFI_HANDLE DispatchHandle >=20 > + ); >=20 > + >=20 > +/** >=20 > + Init required protocol for Pch Sw Dispatch protocol. >=20 > +**/ >=20 > +VOID >=20 > +PchSwDispatchInit ( >=20 > + VOID >=20 > + ); >=20 > + >=20 > +/** >=20 > + Check whether sleep type of two contexts match >=20 > + >=20 > + @param[in] Context1 Context 1 that includes sleep type 1 >=20 > + @param[in] Context2 Context 2 that includes sleep type 2 >=20 > + >=20 > + @retval FALSE Sleep types match >=20 > + @retval TRUE Sleep types don't match >=20 > +**/ >=20 > +BOOLEAN >=20 > +EFIAPI >=20 > +SxCmpContext ( >=20 > + IN PCH_SMM_CONTEXT *Context1, >=20 > + IN PCH_SMM_CONTEXT *Context2 >=20 > + ); >=20 > + >=20 > +/** >=20 > + Update the elapsed time from the Interval data of DATABASE_RECORD >=20 > + >=20 > + @param[in] Record The pointer to the DATABASE_RECORD. >=20 > + @param[out] HwContext The Context to be updated. >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +PeriodicTimerGetContext ( >=20 > + IN DATABASE_RECORD *Record, >=20 > + OUT PCH_SMM_CONTEXT *Context >=20 > + ); >=20 > + >=20 > +/** >=20 > + Check whether Periodic Timer of two contexts match >=20 > + >=20 > + @param[in] Context1 Context 1 that includes Periodic Timer= 1 >=20 > + @param[in] Context2 Context 2 that includes Periodic Timer= 2 >=20 > + >=20 > + @retval FALSE Periodic Timer match >=20 > + @retval TRUE Periodic Timer don't match >=20 > +**/ >=20 > +BOOLEAN >=20 > +EFIAPI >=20 > +PeriodicTimerCmpContext ( >=20 > + IN PCH_SMM_CONTEXT *Context1, >=20 > + IN PCH_SMM_CONTEXT *Context2 >=20 > + ); >=20 > + >=20 > +/** >=20 > + Gather the CommBuffer information of SmmPeriodicTimerDispatch2. >=20 > + >=20 > + @param[in] Record No use >=20 > + @param[out] CommBuffer Point to the CommBuffer structure >=20 > + @param[out] CommBufferSize Point to the Size of CommBuffer > structure >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +PeriodicTimerGetCommBuffer ( >=20 > + IN DATABASE_RECORD *Record, >=20 > + OUT VOID **CommBuffer, >=20 > + OUT UINTN *CommBufferSize >=20 > + ); >=20 > + >=20 > +/** >=20 > + Get the power button status. >=20 > + >=20 > + @param[in] Record The pointer to the DATABASE_RECORD. >=20 > + @param[out] Context Calling context from the hardware, wil= l be > updated with the current power button status. >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +PowerButtonGetContext ( >=20 > + IN DATABASE_RECORD *Record, >=20 > + OUT PCH_SMM_CONTEXT *Context >=20 > + ); >=20 > + >=20 > +/** >=20 > + Check whether Power Button status of two contexts match >=20 > + >=20 > + @param[in] Context1 Context 1 that includes Power Button s= tatus 1 >=20 > + @param[in] Context2 Context 2 that includes Power Button s= tatus 2 >=20 > + >=20 > + @retval FALSE Power Button status match >=20 > + @retval TRUE Power Button status don't match >=20 > +**/ >=20 > +BOOLEAN >=20 > +EFIAPI >=20 > +PowerButtonCmpContext ( >=20 > + IN PCH_SMM_CONTEXT *Context1, >=20 > + IN PCH_SMM_CONTEXT *Context2 >=20 > + ); >=20 > + >=20 > +/** >=20 > + This function is responsible for calculating and enabling any timers t= hat are > required >=20 > + to dispatch messages to children. The SrcDesc argument isn't acutally = used. >=20 > + >=20 > + @param[in] SrcDesc Pointer to the PCH_SMM_SOURCE_DESC > instance. >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +PchSmmPeriodicTimerClearSource ( >=20 > + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc >=20 > + ); >=20 > + >=20 > +/** >=20 > + This services returns the next SMI tick period that is supported by th= e > chipset. >=20 > + The order returned is from longest to shortest interval period. >=20 > + >=20 > + @param[in] This Pointer to the > EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL instance. >=20 > + @param[in, out] SmiTickInterval Pointer to pointer of the next shorter= SMI > interval period that is supported by the child. >=20 > + >=20 > + @retval EFI_SUCCESS The service returned successfully. >=20 > + @retval EFI_INVALID_PARAMETER The parameter SmiTickInterval is > invalid. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +PchSmmPeriodicTimerDispatchGetNextShorterInterval ( >=20 > + IN CONST EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL *This, >=20 > + IN OUT UINT64 **SmiTickInterva= l >=20 > + ); >=20 > + >=20 > +/** >=20 > + Install PCH SMM periodic timer control protocol >=20 > + >=20 > + @param[in] Handle handle for this driver >=20 > + >=20 > + @retval EFI_SUCCESS Driver initialization completed = successfully >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +InstallPchSmmPeriodicTimerControlProtocol ( >=20 > + IN EFI_HANDLE Handle >=20 > + ); >=20 > + >=20 > +/** >=20 > + When we get an SMI that indicates that we are transitioning to a sleep > state, >=20 > + we need to actually transition to that state. We do this by disabling= the >=20 > + "SMI on sleep enable" feature, which generates an SMI when the > operating system >=20 > + tries to put the system to sleep, and then physically putting the syst= em to > sleep. >=20 > +**/ >=20 > +VOID >=20 > +PchSmmSxGoToSleep ( >=20 > + VOID >=20 > + ); >=20 > + >=20 > +/** >=20 > + Install protocols of PCH specifics SMI types, including >=20 > + PCH TCO SMI types, PCH PCIE SMI types, PCH ACPI SMI types, PCH MISC > SMI types. >=20 > + >=20 > + @retval the result of protocol installat= ion >=20 > +**/ >=20 > +EFI_STATUS >=20 > +InstallPchSmiDispatchProtocols ( >=20 > + VOID >=20 > + ); >=20 > + >=20 > +/** >=20 > + The function to dispatch all callback function of PCH SMI types. >=20 > + >=20 > + @retval EFI_SUCCESS Function successfully completed >=20 > + @retval EFI_UNSUPPORTED no >=20 > +**/ >=20 > +EFI_STATUS >=20 > +PchSmiTypeCallbackDispatcher ( >=20 > + IN DATABASE_RECORD *Record >=20 > + ); >=20 > + >=20 > +/** >=20 > + The register function used to register SMI handler of IoTrap event. >=20 > + This is internal function and only used by Iotrap module. >=20 > + >=20 > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source >=20 > + @param[in] IoTrapIndex Index number of IOTRAP register >=20 > + @param[out] DispatchHandle Handle of dispatch function to r= egister. >=20 > + >=20 > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description >=20 > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record >=20 > + @retval EFI_SUCCESS The database record is created s= uccessfully. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +PchInternalIoTrapSmiRegister ( >=20 > + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + IN UINTN IoTrapIndex, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ); >=20 > + >=20 > +/** >=20 > + Unregister a child SMI source dispatch function with a parent SMM driv= er >=20 > + >=20 > + @param[in] DispatchHandle Handle of dispatch function to > deregister. >=20 > + >=20 > + @retval EFI_SUCCESS The dispatch function has been s= uccessfully >=20 > + unregistered and the SMI source = has been disabled >=20 > + if there are no other registered= child dispatch >=20 > + functions for this SMI source. >=20 > + @retval EFI_INVALID_PARAMETER Handle is invalid. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +PchInternalIoTrapSmiUnRegister ( >=20 > + IN EFI_HANDLE DispatchHandle >=20 > + ); >=20 > + >=20 > +/** >=20 > + Register an eSPI SMI handler based on the type >=20 > + >=20 > + @param[in] DispatchFunction Callback in an event of eSPI SMI >=20 > + @param[in] PchSmiTypes The eSPI type published by > PchSmiDispatch >=20 > + @param[out] DispatchHandle The callback handle >=20 > + >=20 > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description >=20 > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database > record >=20 > + @retval EFI_SUCCESS Registration is successful. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +PchInternalEspiSmiRegister ( >=20 > + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + IN PCH_SMI_TYPES PchSmiTypes, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ); >=20 > + >=20 > +/** >=20 > + Unregister an eSPI SMI handler >=20 > + >=20 > + @param[in] DispatchHandle Handle of dispatch function to > deregister. >=20 > + >=20 > + @retval EFI_SUCCESS The dispatch function has been s= uccessfully >=20 > + unregistered and the SMI source = has been disabled >=20 > + if there are no other registered= child dispatch >=20 > + functions for this SMI source. >=20 > + @retval EFI_INVALID_PARAMETER Handle is invalid. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +PchInternalEspiSmiUnRegister ( >=20 > + IN EFI_HANDLE DispatchHandle >=20 > + ); >=20 > + >=20 > +/** >=20 > + The internal function used to create and insert a database record >=20 > + for SMI record of Pch Smi types. >=20 > + >=20 > + @param[in] SrcDesc The pointer to the SMI source de= scription >=20 > + @param[in] DispatchFunction Pointer to dispatch function to = be > invoked for this SMI source >=20 > + @param[in] PchSmiType Specific SMI type of PCH SMI >=20 > + @param[out] DispatchHandle Handle of dispatch function to r= egister. >=20 > + >=20 > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description >=20 > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record >=20 > + @retval EFI_SUCCESS The database record is created s= uccessfully. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +PchSmiRecordInsert ( >=20 > + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc, >=20 > + IN PCH_SMI_CALLBACK_FUNCTIONS DispatchFunction, >=20 > + IN PCH_SMI_TYPES PchSmiType, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ); >=20 > + >=20 > +extern CONST PCH_SMM_SOURCE_DESC mSrcDescSerialIrq; >=20 > +extern CONST PCH_SMM_SOURCE_DESC mSrcDescLpcBiosWp; >=20 > + >=20 > +/** >=20 > + Clear the TCO SMI status bit and block after the SMI handling is done >=20 > + >=20 > + @param[in] SrcDesc Pointer to the PCH SMI source de= scription > table >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +PchTcoSmiClearSourceAndBlock ( >=20 > + CONST PCH_SMM_SOURCE_DESC *SrcDesc >=20 > + ); >=20 > + >=20 > +/** >=20 > + Clear the TCO SMI status bit after the SMI handling is done >=20 > + >=20 > + @param[in] SrcDesc Pointer to the PCH SMI source de= scription > table >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +PchTcoSmiClearSource ( >=20 > + CONST PCH_SMM_SOURCE_DESC *SrcDesc >=20 > + ); >=20 > + >=20 > +/** >=20 > + Initialize Source descriptor structure >=20 > + >=20 > + @param[in] SrcDesc Pointer to the PCH SMI source de= scription > table >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +NullInitSourceDesc ( >=20 > + PCH_SMM_SOURCE_DESC *SrcDesc >=20 > + ); >=20 > + >=20 > +/** >=20 > + The register function used to register SMI handler of GPI SMI event. >=20 > + >=20 > + @param[in] This Pointer to the > EFI_SMM_GPI_DISPATCH2_PROTOCOL instance. >=20 > + @param[in] DispatchFunction Function to register for handler when t= he > specified GPI causes an SMI. >=20 > + @param[in] RegisterContext Pointer to the dispatch function's cont= ext. >=20 > + The caller fills this context in before= calling >=20 > + the register function to indicate to th= e register >=20 > + function the GPI(s) for which the dispa= tch function >=20 > + should be invoked. >=20 > + @param[out] DispatchHandle Handle generated by the dispatcher to > track the >=20 > + function instance. >=20 > + >=20 > + @retval EFI_SUCCESS The dispatch function has been successf= ully >=20 > + registered and the SMI source has been = enabled. >=20 > + @retval EFI_ACCESS_DENIED Register is not allowed >=20 > + @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The GPI > input value >=20 > + is not within valid range. >=20 > + @retval EFI_OUT_OF_RESOURCES There is not enough memory (system > or SMM) to manage this child. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchGpiSmiRegister ( >=20 > + IN CONST EFI_SMM_GPI_DISPATCH2_PROTOCOL *This, >=20 > + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, >=20 > + IN EFI_SMM_GPI_REGISTER_CONTEXT *RegisterContext, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ); >=20 > + >=20 > +/** >=20 > + Unregister a GPI SMI source dispatch function with a parent SMM driver >=20 > + >=20 > + @param[in] This Pointer to the > EFI_SMM_GPI_DISPATCH2_PROTOCOL instance. >=20 > + @param[in] DispatchHandle Handle of dispatch function to deregis= ter. >=20 > + >=20 > + @retval EFI_SUCCESS The dispatch function has been success= fully >=20 > + unregistered and the SMI source has be= en disabled >=20 > + if there are no other registered child= dispatch >=20 > + functions for this SMI source. >=20 > + @retval EFI_INVALID_PARAMETER Handle is invalid. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchGpiSmiUnRegister ( >=20 > + IN CONST EFI_SMM_GPI_DISPATCH2_PROTOCOL *This, >=20 > + IN EFI_HANDLE DispatchHandle >=20 > + ); >=20 > + >=20 > +#endif >=20 > diff --git > a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmCor > e.c > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmCor > e.c > new file mode 100644 > index 0000000000..b2e76a8b72 > --- /dev/null > +++ > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmCor > e.c > @@ -0,0 +1,926 @@ > +/** @file >=20 > + This driver is responsible for the registration of child drivers >=20 > + and the abstraction of the PCH SMI sources. >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > +#include "PchSmm.h" >=20 > +#include "PchSmmHelpers.h" >=20 > +#include "PchSmmEspi.h" >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > + >=20 > +#define PROGRESS_CODE_S3_SUSPEND_START PcdGet32 > (PcdProgressCodeS3SuspendStart) >=20 > +// >=20 > +// MODULE / GLOBAL DATA >=20 > +// >=20 > +// Module variables used by the both the main dispatcher and the source > dispatchers >=20 > +// Declared in PchSmm.h >=20 > +// >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mAcpiBaseAddr; >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mTcoBaseAddr; >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mReadyToLock; >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mS3SusStart; >=20 > + >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED PRIVATE_DATA mPrivateData =3D > { >=20 > + { >=20 > + NULL, >=20 > + NULL >=20 > + }, // CallbackDataBase linked list = head >=20 > + NULL, // EFI handle returned when call= ing > InstallMultipleProtocolInterfaces >=20 > + NULL, // >=20 > + { // protocol arrays >=20 > + // >=20 > + // elements within the array >=20 > + // >=20 > + { >=20 > + PROTOCOL_SIGNATURE, >=20 > + UsbType, >=20 > + &gEfiSmmUsbDispatch2ProtocolGuid, >=20 > + {{ >=20 > + (PCH_SMM_GENERIC_REGISTER) PchPiSmmCoreRegister, >=20 > + (PCH_SMM_GENERIC_UNREGISTER) PchPiSmmCoreUnRegister >=20 > + }} >=20 > + }, >=20 > + { >=20 > + PROTOCOL_SIGNATURE, >=20 > + SxType, >=20 > + &gEfiSmmSxDispatch2ProtocolGuid, >=20 > + {{ >=20 > + (PCH_SMM_GENERIC_REGISTER) PchPiSmmCoreRegister, >=20 > + (PCH_SMM_GENERIC_UNREGISTER) PchPiSmmCoreUnRegister >=20 > + }} >=20 > + }, >=20 > + { >=20 > + PROTOCOL_SIGNATURE, >=20 > + SwType, >=20 > + &gEfiSmmSwDispatch2ProtocolGuid, >=20 > + {{ >=20 > + (PCH_SMM_GENERIC_REGISTER) PchSwSmiRegister, >=20 > + (PCH_SMM_GENERIC_UNREGISTER) PchSwSmiUnRegister, >=20 > + (UINTN) MAXIMUM_SWI_VALUE >=20 > + }} >=20 > + }, >=20 > + { >=20 > + PROTOCOL_SIGNATURE, >=20 > + GpiType, >=20 > + &gEfiSmmGpiDispatch2ProtocolGuid, >=20 > + {{ >=20 > + (PCH_SMM_GENERIC_REGISTER) PchGpiSmiRegister, >=20 > + (PCH_SMM_GENERIC_UNREGISTER) PchGpiSmiUnRegister, >=20 > + (UINTN) PCH_GPIO_NUM_SUPPORTED_GPIS >=20 > + }} >=20 > + }, >=20 > + { >=20 > + PROTOCOL_SIGNATURE, >=20 > + PowerButtonType, >=20 > + &gEfiSmmPowerButtonDispatch2ProtocolGuid, >=20 > + {{ >=20 > + (PCH_SMM_GENERIC_REGISTER) PchPiSmmCoreRegister, >=20 > + (PCH_SMM_GENERIC_UNREGISTER) PchPiSmmCoreUnRegister >=20 > + }} >=20 > + }, >=20 > + { >=20 > + PROTOCOL_SIGNATURE, >=20 > + PeriodicTimerType, >=20 > + &gEfiSmmPeriodicTimerDispatch2ProtocolGuid, >=20 > + {{ >=20 > + (PCH_SMM_GENERIC_REGISTER) PchPiSmmCoreRegister, >=20 > + (PCH_SMM_GENERIC_UNREGISTER) PchPiSmmCoreUnRegister, >=20 > + (UINTN) PchSmmPeriodicTimerDispatchGetNextShorterInterval >=20 > + }} >=20 > + }, >=20 > + } >=20 > +}; >=20 > + >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED CONTEXT_FUNCTIONS > mContextFunctions[PCH_SMM_PROTOCOL_TYPE_MAX] =3D { >=20 > + { >=20 > + NULL, >=20 > + NULL, >=20 > + NULL >=20 > + }, >=20 > + { >=20 > + SxGetContext, >=20 > + SxCmpContext, >=20 > + NULL >=20 > + }, >=20 > + { >=20 > + NULL, >=20 > + NULL, >=20 > + NULL >=20 > + }, >=20 > + { >=20 > + NULL, >=20 > + NULL, >=20 > + NULL >=20 > + }, >=20 > + { >=20 > + PowerButtonGetContext, >=20 > + PowerButtonCmpContext, >=20 > + NULL >=20 > + }, >=20 > + { >=20 > + PeriodicTimerGetContext, >=20 > + PeriodicTimerCmpContext, >=20 > + PeriodicTimerGetCommBuffer >=20 > + }, >=20 > +}; >=20 > + >=20 > +// >=20 > +// PROTOTYPES >=20 > +// >=20 > +// Functions use only in this file >=20 > +// >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchSmmCoreDispatcher ( >=20 > + IN EFI_HANDLE SmmImageHandle, >=20 > + IN CONST VOID *PchSmmCore, OPTIONAL >=20 > + IN OUT VOID *CommunicationBuffer, >=20 > + IN OUT UINTN *SourceSize >=20 > + ); >=20 > + >=20 > +// >=20 > +// FUNCTIONS >=20 > +// >=20 > +/** >=20 > + SMM ready to lock notification event handler. >=20 > + >=20 > + @param Protocol Points to the protocol's unique identifier >=20 > + @param Interface Points to the interface instance >=20 > + @param Handle The handle on which the interface was installed >=20 > + >=20 > + @retval EFI_SUCCESS SmmReadyToLockCallback runs successfully >=20 > + >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +SmmReadyToLockCallback ( >=20 > + IN CONST EFI_GUID *Protocol, >=20 > + IN VOID *Interface, >=20 > + IN EFI_HANDLE Handle >=20 > + ) >=20 > +{ >=20 > + mReadyToLock =3D TRUE; >=20 > + >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > + >=20 > +/** >=20 > + PchSmiDispatcher SMM Module Entry Point\n >=20 > + - Introduction\n >=20 > + The PchSmiDispatcher module is an SMM driver which provides SMI > handler registration >=20 > + services for PCH generated SMIs. >=20 > + >=20 > + - Details\n >=20 > + This module provides SMI handler registration servicies for PCH SMIs= . >=20 > + NOTE: All the register/unregister functions will be locked after SMM > ready to boot signal event. >=20 > + Please make sure no handler is installed after that. >=20 > + >=20 > + - @pre >=20 > + - EFI_SMM_BASE2_PROTOCOL >=20 > + - Documented in the System Management Mode Core Interface > Specification >=20 > + - EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL >=20 > + - Documented in the UEFI 2.0 Specification and above >=20 > + - EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL >=20 > + - This is to ensure that PCI MMIO and IO resource has been prepare= d > and available for this driver to allocate. >=20 > + - EFI_SMM_CPU_PROTOCOL >=20 > + >=20 > + - @result >=20 > + The PchSmiDispatcher driver produces: >=20 > + - EFI_SMM_USB_DISPATCH2_PROTOCOL >=20 > + - EFI_SMM_SX_DISPATCH2_PROTOCOL >=20 > + - EFI_SMM_SW_DISPATCH2_PROTOCOL >=20 > + - EFI_SMM_GPI_DISPATCH2_PROTOCOL >=20 > + - EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL >=20 > + - EFI_SMM_POWER_BUTTON_DISPATCH2_PROTOCOL >=20 > + - EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL >=20 > + - @link _PCH_SMM_IO_TRAP_CONTROL_PROTOCOL > PCH_SMM_IO_TRAP_CONTROL_PROTOCOL @endlink >=20 > + - @link _PCH_PCIE_SMI_DISPATCH_PROTOCOL > PCH_PCIE_SMI_DISPATCH_PROTOCOL @endlink >=20 > + - @link _PCH_TCO_SMI_DISPATCH_PROTOCOL > PCH_TCO_SMI_DISPATCH_PROTOCOL @endlink >=20 > + - @link _PCH_ACPI_SMI_DISPATCH_PROTOCOL > PCH_ACPI_SMI_DISPATCH_PROTOCOL @endlink >=20 > + - @link _PCH_SMI_DISPATCH_PROTOCOL > PCH_SMI_DISPATCH_PROTOCOL @endlink >=20 > + - @link _PCH_ESPI_SMI_DISPATCH_PROTOCOL > PCH_ESPI_SMI_DISPATCH_PROTOCOL @endlink >=20 > + >=20 > + @param[in] ImageHandle Pointer to the loaded image protocol f= or > this driver >=20 > + @param[in] SystemTable Pointer to the EFI System Table >=20 > + >=20 > + @retval EFI_SUCCESS PchSmmDispatcher Initialization comple= ted. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +InitializePchSmmDispatcher ( >=20 > + IN EFI_HANDLE ImageHandle, >=20 > + IN EFI_SYSTEM_TABLE *SystemTable >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + VOID *SmmReadyToLockRegistration; >=20 > + >=20 > + mS3SusStart =3D FALSE; >=20 > + // >=20 > + // Access ACPI Base Addresses Register >=20 > + // >=20 > + >=20 > + mAcpiBaseAddr =3D PmcGetAcpiBase (); >=20 > + ASSERT (mAcpiBaseAddr !=3D 0); >=20 > + >=20 > + // >=20 > + // Access TCO Base Addresses Register >=20 > + // >=20 > + PchTcoBaseGet (&mTcoBaseAddr); >=20 > + ASSERT (mTcoBaseAddr !=3D 0); >=20 > + >=20 > + // >=20 > + // Register a callback function to handle subsequent SMIs. This callb= ack >=20 > + // will be called by SmmCoreDispatcher. >=20 > + // >=20 > + Status =3D gSmst->SmiHandlerRegister (PchSmmCoreDispatcher, NULL, > &mPrivateData.SmiHandle); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + // >=20 > + // Initialize Callback DataBase >=20 > + // >=20 > + InitializeListHead (&mPrivateData.CallbackDataBase); >=20 > + >=20 > + // >=20 > + // Enable SMIs on the PCH now that we have a callback >=20 > + // >=20 > + PchSmmInitHardware (); >=20 > + >=20 > + // >=20 > + // Install and initialize all the needed protocols >=20 > + // >=20 > + PchSwDispatchInit (); >=20 > + PchSmmPublishDispatchProtocols (); >=20 > + InstallPchSmiDispatchProtocols (); >=20 > + InstallIoTrap (ImageHandle); >=20 > + InstallEspiSmi (ImageHandle); >=20 > + InstallPchSmmPeriodicTimerControlProtocol > (mPrivateData.InstallMultProtHandle); >=20 > + >=20 > + // >=20 > + // Register EFI_SMM_READY_TO_LOCK_PROTOCOL_GUID notify function. >=20 > + // >=20 > + Status =3D gSmst->SmmRegisterProtocolNotify ( >=20 > + &gEfiSmmReadyToLockProtocolGuid, >=20 > + SmmReadyToLockCallback, >=20 > + &SmmReadyToLockRegistration >=20 > + ); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > + >=20 > +/** >=20 > + The internal function used to create and insert a database record >=20 > + >=20 > + @param[in] InsertRecord Record to insert to database. >=20 > + @param[out] DispatchHandle Handle of dispatch function to r= egister. >=20 > + >=20 > + @retval EFI_INVALID_PARAMETER Error with NULL SMI source > description >=20 > + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for databa= se > record >=20 > + @retval EFI_SUCCESS The database record is created s= uccessfully. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +SmmCoreInsertRecord ( >=20 > + IN DATABASE_RECORD *NewRecord, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + DATABASE_RECORD *Record; >=20 > + >=20 > + if ((NewRecord =3D=3D NULL) || >=20 > + (NewRecord->Signature !=3D DATABASE_RECORD_SIGNATURE)) >=20 > + { >=20 > + ASSERT (FALSE); >=20 > + return EFI_INVALID_PARAMETER; >=20 > + } >=20 > + >=20 > + Status =3D gSmst->SmmAllocatePool (EfiRuntimeServicesData, sizeof > (DATABASE_RECORD), (VOID **) &Record); >=20 > + if (EFI_ERROR (Status)) { >=20 > + ASSERT (FALSE); >=20 > + return EFI_OUT_OF_RESOURCES; >=20 > + } >=20 > + CopyMem (Record, NewRecord, sizeof (DATABASE_RECORD)); >=20 > + >=20 > + // >=20 > + // After ensuring the source of event is not null, we will insert the = record > into the database >=20 > + // >=20 > + InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link); >=20 > + >=20 > + // >=20 > + // Child's handle will be the address linked list link in the record >=20 > + // >=20 > + *DispatchHandle =3D (EFI_HANDLE) (&Record->Link); >=20 > + >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > + >=20 > +/** >=20 > + Unregister a child SMI source dispatch function with a parent SMM driv= er >=20 > + >=20 > + @param[in] This Protocol instance pointer. >=20 > + @param[in] DispatchHandle Handle of dispatch function to > deregister. >=20 > + >=20 > + @retval EFI_SUCCESS The dispatch function has been s= uccessfully >=20 > + unregistered and the SMI source = has been disabled >=20 > + if there are no other registered= child dispatch >=20 > + functions for this SMI source. >=20 > + @retval EFI_INVALID_PARAMETER Handle is invalid. >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchPiSmmCoreUnRegister ( >=20 > + IN PCH_SMM_GENERIC_PROTOCOL *This, >=20 > + IN EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + DATABASE_RECORD *RecordToDelete; >=20 > + EFI_STATUS Status; >=20 > + PCH_SMM_QUALIFIED_PROTOCOL *Qualified; >=20 > + >=20 > + Qualified =3D QUALIFIED_PROTOCOL_FROM_GENERIC (This); >=20 > + RecordToDelete =3D DATABASE_RECORD_FROM_LINK (DispatchHandle); >=20 > + Status =3D PchSmmCoreUnRegister (NULL, DispatchHandle); >=20 > + if (!EFI_ERROR (Status)) { >=20 > + SmiHandlerProfileUnregisterHandler ( >=20 > + Qualified->Guid, >=20 > + RecordToDelete->Callback, >=20 > + &RecordToDelete->ChildContext, >=20 > + RecordToDelete->ContextSize >=20 > + ); >=20 > + } >=20 > + return Status; >=20 > +} >=20 > + >=20 > +/** >=20 > + Register a child SMI dispatch function with a parent SMM driver. >=20 > + >=20 > + @param[in] This Pointer to the PCH_SMM_GENERIC_PROTOCO= L > instance. >=20 > + @param[in] DispatchFunction Pointer to dispatch function to be inv= oked > for this SMI source. >=20 > + @param[in] DispatchContext Pointer to the dispatch function's con= text. >=20 > + @param[out] DispatchHandle Handle of dispatch function, for when > interfacing >=20 > + with the parent SMM driver, will be th= e address of linked >=20 > + list link in the call back record. >=20 > + >=20 > + @retval EFI_OUT_OF_RESOURCES Insufficient resources to create > database record >=20 > + @retval EFI_INVALID_PARAMETER The input parameter is invalid >=20 > + @retval EFI_SUCCESS The dispatch function has been success= fully >=20 > + registered and the SMI source has been= enabled. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchPiSmmCoreRegister ( >=20 > + IN PCH_SMM_GENERIC_PROTOCOL *This, >=20 > + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction= , >=20 > + IN PCH_SMM_CONTEXT *DispatchContext= , >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + DATABASE_RECORD Record; >=20 > + PCH_SMM_QUALIFIED_PROTOCOL *Qualified; >=20 > + PCH_SMM_SOURCE_DESC NullSourceDesc; >=20 > + >=20 > + // >=20 > + // Initialize NullSourceDesc >=20 > + // >=20 > + NullInitSourceDesc (&NullSourceDesc); >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the EndOfDxe event > has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + ZeroMem (&Record, sizeof (DATABASE_RECORD)); >=20 > + >=20 > + // >=20 > + // Gather information about the registration request >=20 > + // >=20 > + Record.Callback =3D DispatchFunction; >=20 > + >=20 > + Qualified =3D QUALIFIED_PROTOCOL_FROM_GENERIC (This); >=20 > + >=20 > + Record.ProtocolType =3D Qualified->Type; >=20 > + >=20 > + Record.ContextFunctions =3D mContextFunctions[Qualified->Type]; >=20 > + // >=20 > + // Perform linked list housekeeping >=20 > + // >=20 > + Record.Signature =3D DATABASE_RECORD_SIGNATURE; >=20 > + >=20 > + switch (Qualified->Type) { >=20 > + // >=20 > + // By the end of this switch statement, we'll know the >=20 > + // source description the child is registering for >=20 > + // >=20 > + case UsbType: >=20 > + Record.ContextSize =3D sizeof (EFI_SMM_USB_REGISTER_CONTEXT); >=20 > + CopyMem (&Record.ChildContext, DispatchContext, > Record.ContextSize); >=20 > + // >=20 > + // Check the validity of Context Type >=20 > + // >=20 > + if ((Record.ChildContext.Usb.Type < UsbLegacy) || > (Record.ChildContext.Usb.Type > UsbWake)) { >=20 > + return EFI_INVALID_PARAMETER; >=20 > + } >=20 > + >=20 > + MapUsbToSrcDesc (DispatchContext, &Record.SrcDesc); >=20 > + Record.ClearSource =3D NULL; >=20 > + // >=20 > + // use default clear source function >=20 > + // >=20 > + break; >=20 > + >=20 > + case SxType: >=20 > + Record.ContextSize =3D sizeof (EFI_SMM_SX_REGISTER_CONTEXT); >=20 > + CopyMem (&Record.ChildContext, DispatchContext, > Record.ContextSize); >=20 > + // >=20 > + // Check the validity of Context Type and Phase >=20 > + // >=20 > + if ((Record.ChildContext.Sx.Type < SxS0) || >=20 > + (Record.ChildContext.Sx.Type >=3D EfiMaximumSleepType) || >=20 > + (Record.ChildContext.Sx.Phase < SxEntry) || >=20 > + (Record.ChildContext.Sx.Phase >=3D EfiMaximumPhase) >=20 > + ) { >=20 > + return EFI_INVALID_PARAMETER; >=20 > + } >=20 > + >=20 > + CopyMem (&Record.SrcDesc, &mSxSourceDesc, sizeof > (PCH_SMM_SOURCE_DESC)); >=20 > + Record.ClearSource =3D NULL; >=20 > + // >=20 > + // use default clear source function >=20 > + // >=20 > + break; >=20 > + >=20 > + case PowerButtonType: >=20 > + Record.ContextSize =3D sizeof > (EFI_SMM_POWER_BUTTON_REGISTER_CONTEXT); >=20 > + CopyMem (&Record.ChildContext, DispatchContext, > Record.ContextSize); >=20 > + // >=20 > + // Check the validity of Context Phase >=20 > + // >=20 > + if ((Record.ChildContext.PowerButton.Phase < EfiPowerButtonEntry) = || >=20 > + (Record.ChildContext.PowerButton.Phase > EfiPowerButtonExit)) >=20 > + { >=20 > + return EFI_INVALID_PARAMETER; >=20 > + } >=20 > + >=20 > + CopyMem (&Record.SrcDesc, &mPowerButtonSourceDesc, sizeof > (PCH_SMM_SOURCE_DESC)); >=20 > + Record.ClearSource =3D NULL; >=20 > + // >=20 > + // use default clear source function >=20 > + // >=20 > + break; >=20 > + >=20 > + case PeriodicTimerType: >=20 > + Record.ContextSize =3D sizeof > (EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT); >=20 > + CopyMem (&Record.ChildContext, DispatchContext, > Record.ContextSize); >=20 > + // >=20 > + // Check the validity of timer value >=20 > + // >=20 > + if (DispatchContext->PeriodicTimer.SmiTickInterval <=3D 0) { >=20 > + return EFI_INVALID_PARAMETER; >=20 > + } >=20 > + >=20 > + MapPeriodicTimerToSrcDesc (DispatchContext, &Record.SrcDesc); >=20 > + Record.MiscData.TimerSmiEnabled =3D TRUE; >=20 > + Record.ClearSource =3D PchSmmPeriodicTimerClearSource; >=20 > + break; >=20 > + >=20 > + default: >=20 > + return EFI_INVALID_PARAMETER; >=20 > + break; >=20 > + } >=20 > + >=20 > + if (CompareSources (&Record.SrcDesc, &NullSourceDesc)) { >=20 > + return EFI_INVALID_PARAMETER; >=20 > + } >=20 > + >=20 > + // >=20 > + // After ensuring the source of event is not null, we will insert the = record > into the database >=20 > + // Child's handle will be the address linked list link in the record >=20 > + // >=20 > + Status =3D SmmCoreInsertRecord ( >=20 > + &Record, >=20 > + DispatchHandle >=20 > + ); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + if (Record.ClearSource =3D=3D NULL) { >=20 > + // >=20 > + // Clear the SMI associated w/ the source using the default function >=20 > + // >=20 > + PchSmmClearSource (&Record.SrcDesc); >=20 > + } else { >=20 > + // >=20 > + // This source requires special handling to clear >=20 > + // >=20 > + Record.ClearSource (&Record.SrcDesc); >=20 > + } >=20 > + >=20 > + PchSmmEnableSource (&Record.SrcDesc); >=20 > + SmiHandlerProfileRegisterHandler ( >=20 > + Qualified->Guid, >=20 > + DispatchFunction, >=20 > + (UINTN)RETURN_ADDRESS (0), >=20 > + DispatchContext, >=20 > + Record.ContextSize >=20 > + ); >=20 > + >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > + >=20 > +/** >=20 > + Unregister a child SMI source dispatch function with a parent SMM driv= er. >=20 > + >=20 > + @param[in] This Pointer to the PCH_SMM_GENERIC_PROTOCO= L > instance. >=20 > + @param[in] DispatchHandle Handle of dispatch function to deregis= ter. >=20 > + >=20 > + @retval EFI_SUCCESS The dispatch function has been success= fully >=20 > + unregistered and the SMI source has be= en disabled >=20 > + if there are no other registered child= dispatch >=20 > + functions for this SMI source. >=20 > + @retval EFI_INVALID_PARAMETER Handle is invalid. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchSmmCoreUnRegister ( >=20 > + IN PCH_SMM_GENERIC_PROTOCOL *This, >=20 > + IN EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + BOOLEAN NeedClearEnable; >=20 > + UINTN DescIndex; >=20 > + DATABASE_RECORD *RecordToDelete; >=20 > + DATABASE_RECORD *RecordInDb; >=20 > + LIST_ENTRY *LinkInDb; >=20 > + >=20 > + if (DispatchHandle =3D=3D NULL) { >=20 > + return EFI_INVALID_PARAMETER; >=20 > + } >=20 > + >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the > SmmReadyToLock event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + RecordToDelete =3D DATABASE_RECORD_FROM_LINK (DispatchHandle); >=20 > + >=20 > + // >=20 > + // Take the entry out of the linked list >=20 > + // >=20 > + if (RecordToDelete->Link.ForwardLink =3D=3D (LIST_ENTRY *) > EFI_BAD_POINTER) { >=20 > + return EFI_INVALID_PARAMETER; >=20 > + } >=20 > + >=20 > + RemoveEntryList (&RecordToDelete->Link); >=20 > + >=20 > + // >=20 > + // Loop through all the souces in record linked list to see if any sou= rce > enable is equal. >=20 > + // If any source enable is equal, we do not want to disable it. >=20 > + // >=20 > + for (DescIndex =3D 0; DescIndex < NUM_EN_BITS; ++DescIndex) { >=20 > + if (IS_BIT_DESC_NULL (RecordToDelete->SrcDesc.En[DescIndex])) { >=20 > + continue; >=20 > + } >=20 > + NeedClearEnable =3D TRUE; >=20 > + LinkInDb =3D GetFirstNode (&mPrivateData.CallbackDataBase); >=20 > + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { >=20 > + RecordInDb =3D DATABASE_RECORD_FROM_LINK (LinkInDb); >=20 > + if (IsBitEqualToAnySourceEn (&RecordToDelete- > >SrcDesc.En[DescIndex], &RecordInDb->SrcDesc)) { >=20 > + NeedClearEnable =3D FALSE; >=20 > + break; >=20 > + } >=20 > + LinkInDb =3D GetNextNode (&mPrivateData.CallbackDataBase, > &RecordInDb->Link); >=20 > + } >=20 > + if (NeedClearEnable =3D=3D FALSE) { >=20 > + continue; >=20 > + } >=20 > + WriteBitDesc (&RecordToDelete->SrcDesc.En[DescIndex], 0, FALSE); >=20 > + } >=20 > + Status =3D gSmst->SmmFreePool (RecordToDelete); >=20 > + if (EFI_ERROR (Status)) { >=20 > + ASSERT (FALSE); >=20 > + return Status; >=20 > + } >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > + >=20 > +/** >=20 > + This function clears the pending SMI status before set EOS. >=20 > + NOTE: This only clears the pending SMI with known reason. >=20 > + Please do not clear unknown pending SMI status since that will h= ide > potential issues. >=20 > + >=20 > + @param[in] SmiStsValue SMI status >=20 > + @param[in] SciEn Sci Enable status >=20 > +**/ >=20 > +STATIC >=20 > +VOID >=20 > +ClearPendingSmiStatus ( >=20 > + UINT32 SmiStsValue, >=20 > + BOOLEAN SciEn >=20 > + ) >=20 > +{ >=20 > + // >=20 > + // Clear NewCentury status if it's not handled. >=20 > + // >=20 > + if (SmiStsValue & B_ACPI_IO_SMI_STS_TCO) { >=20 > + if (IoRead16 (mTcoBaseAddr + R_TCO_IO_TCO1_STS) & > B_TCO_IO_TCO1_STS_NEWCENTURY) { >=20 > + PchTcoSmiClearSourceAndBlock (&mSrcDescNewCentury); >=20 > + } >=20 > + } >=20 > + // Clear PWRBTNOR_STS if it's not handled. >=20 > + // >=20 > + if (IoRead16 (mAcpiBaseAddr + R_ACPI_IO_PM1_STS) & > B_ACPI_IO_PM1_STS_PRBTNOR) { >=20 > + IoWrite16 (mAcpiBaseAddr + R_ACPI_IO_PM1_STS, > B_ACPI_IO_PM1_STS_PRBTNOR); >=20 > + } >=20 > + // >=20 > + // Clear WADT_STS if this is triggered by WADT timer. >=20 > + // >=20 > + if (!SciEn) { >=20 > + if (IoRead32 (mAcpiBaseAddr + R_ACPI_IO_GPE0_STS_127_96) & > B_ACPI_IO_GPE0_STS_127_96_WADT) { >=20 > + IoWrite32 (mAcpiBaseAddr + R_ACPI_IO_GPE0_STS_127_96, > B_ACPI_IO_GPE0_STS_127_96_WADT); >=20 > + } >=20 > + } >=20 > + // >=20 > + // Clear GPIO_UNLOCK_SMI_STS in case it is set as GPIO Unlock SMI is n= ot > supported >=20 > + // >=20 > + if (SmiStsValue & B_ACPI_IO_SMI_STS_GPIO_UNLOCK) { >=20 > + IoWrite32 (mAcpiBaseAddr + R_ACPI_IO_SMI_STS, > B_ACPI_IO_SMI_STS_GPIO_UNLOCK); >=20 > + } >=20 > +} >=20 > + >=20 > +/** >=20 > + The callback function to handle subsequent SMIs. This callback will b= e > called by SmmCoreDispatcher. >=20 > + >=20 > + @param[in] SmmImageHandle Not used >=20 > + @param[in] PchSmmCore Not used >=20 > + @param[in, out] CommunicationBuffer Not used >=20 > + @param[in, out] SourceSize Not used >=20 > + >=20 > + @retval EFI_SUCCESS Function successfully completed >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchSmmCoreDispatcher ( >=20 > + IN EFI_HANDLE SmmImageHandle, >=20 > + IN CONST VOID *PchSmmCore, >=20 > + IN OUT VOID *CommunicationBuffer, >=20 > + IN OUT UINTN *SourceSize >=20 > + ) >=20 > +{ >=20 > + // >=20 > + // Used to prevent infinite loops >=20 > + // >=20 > + UINTN EscapeCount; >=20 > + >=20 > + BOOLEAN ContextsMatch; >=20 > + BOOLEAN EosSet; >=20 > + BOOLEAN SxChildWasDispatched; >=20 > + >=20 > + DATABASE_RECORD *RecordInDb; >=20 > + LIST_ENTRY *LinkInDb; >=20 > + DATABASE_RECORD *RecordToExhaust; >=20 > + LIST_ENTRY *LinkToExhaust; >=20 > + >=20 > + PCH_SMM_CONTEXT Context; >=20 > + VOID *CommBuffer; >=20 > + UINTN CommBufferSize; >=20 > + >=20 > + EFI_STATUS Status; >=20 > + BOOLEAN SciEn; >=20 > + UINT32 SmiEnValue; >=20 > + UINT32 SmiStsValue; >=20 > + UINT8 Port74Save; >=20 > + UINT8 Port76Save; >=20 > + >=20 > + PCH_SMM_SOURCE_DESC ActiveSource; >=20 > + >=20 > + // >=20 > + // Initialize ActiveSource >=20 > + // >=20 > + NullInitSourceDesc (&ActiveSource); >=20 > + >=20 > + EscapeCount =3D 3; >=20 > + ContextsMatch =3D FALSE; >=20 > + EosSet =3D FALSE; >=20 > + SxChildWasDispatched =3D FALSE; >=20 > + Status =3D EFI_SUCCESS; >=20 > + >=20 > + // >=20 > + // Save IO index registers >=20 > + // @note: Save/Restore port 70h directly might break NMI_EN# setting, >=20 > + // then save/restore 74h/76h instead. >=20 > + // @note: CF8 is not saved. Prefer method is to use MMIO instead of CF= 8 >=20 > + // >=20 > + Port76Save =3D IoRead8 (R_RTC_IO_EXT_INDEX_ALT); >=20 > + Port74Save =3D IoRead8 (R_RTC_IO_INDEX_ALT); >=20 > + >=20 > + if (!IsListEmpty (&mPrivateData.CallbackDataBase)) { >=20 > + // >=20 > + // We have children registered w/ us -- continue >=20 > + // >=20 > + while ((!EosSet) && (EscapeCount > 0)) { >=20 > + EscapeCount--; >=20 > + >=20 > + LinkInDb =3D GetFirstNode (&mPrivateData.CallbackDataBase); >=20 > + >=20 > + // >=20 > + // Cache SciEn, SmiEnValue and SmiStsValue to determine if source = is > active >=20 > + // >=20 > + SciEn =3D PchSmmGetSciEn (); >=20 > + SmiEnValue =3D IoRead32 ((UINTN) (mAcpiBaseAddr + > R_ACPI_IO_SMI_EN)); >=20 > + SmiStsValue =3D IoRead32 ((UINTN) (mAcpiBaseAddr + > R_ACPI_IO_SMI_STS)); >=20 > + >=20 > + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { >=20 > + RecordInDb =3D DATABASE_RECORD_FROM_LINK (LinkInDb); >=20 > + >=20 > + // >=20 > + // look for the first active source >=20 > + // >=20 > + if (!SourceIsActive (&RecordInDb->SrcDesc, SciEn, SmiEnValue, > SmiStsValue)) { >=20 > + // >=20 > + // Didn't find the source yet, keep looking >=20 > + // >=20 > + LinkInDb =3D GetNextNode (&mPrivateData.CallbackDataBase, > &RecordInDb->Link); >=20 > + >=20 > + // >=20 > + // if it's the last one, try to clear EOS >=20 > + // >=20 > + if (IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { >=20 > + // >=20 > + // Clear pending SMI status before EOS >=20 > + // >=20 > + ClearPendingSmiStatus (SmiStsValue, SciEn); >=20 > + EosSet =3D PchSmmSetAndCheckEos (); >=20 > + } >=20 > + } else { >=20 > + // >=20 > + // We found a source. If this is a sleep type, we have to go t= o >=20 > + // appropriate sleep state anyway.No matter there is sleep chi= ld or not >=20 > + // >=20 > + if (RecordInDb->ProtocolType =3D=3D SxType) { >=20 > + SxChildWasDispatched =3D TRUE; >=20 > + } >=20 > + // >=20 > + // "cache" the source description and don't query I/O anymore >=20 > + // >=20 > + CopyMem ((VOID *) &ActiveSource, (VOID *) &(RecordInDb- > >SrcDesc), sizeof (PCH_SMM_SOURCE_DESC)); >=20 > + LinkToExhaust =3D LinkInDb; >=20 > + >=20 > + // >=20 > + // exhaust the rest of the queue looking for the same source >=20 > + // >=20 > + while (!IsNull (&mPrivateData.CallbackDataBase, LinkToExhaust)= ) { >=20 > + RecordToExhaust =3D DATABASE_RECORD_FROM_LINK > (LinkToExhaust); >=20 > + // >=20 > + // RecordToExhaust->Link might be removed (unregistered) by > Callback function, and then the >=20 > + // system will hang in ASSERT() while calling GetNextNode(). >=20 > + // To prevent the issue, we need to get next record in DB he= re > (before Callback function). >=20 > + // >=20 > + LinkToExhaust =3D GetNextNode (&mPrivateData.CallbackDataBas= e, > &RecordToExhaust->Link); >=20 > + >=20 > + if (CompareSources (&RecordToExhaust->SrcDesc, &ActiveSource= )) { >=20 > + // >=20 > + // These source descriptions are equal, so this callback s= hould be >=20 > + // dispatched. >=20 > + // >=20 > + if (RecordToExhaust->ContextFunctions.GetContext !=3D NULL= ) { >=20 > + // >=20 > + // This child requires that we get a calling context fro= m >=20 > + // hardware and compare that context to the one supplied >=20 > + // by the child. >=20 > + // >=20 > + ASSERT (RecordToExhaust->ContextFunctions.CmpContext != =3D > NULL); >=20 > + >=20 > + // >=20 > + // Make sure contexts match before dispatching event to = child >=20 > + // >=20 > + RecordToExhaust->ContextFunctions.GetContext > (RecordToExhaust, &Context); >=20 > + ContextsMatch =3D RecordToExhaust- > >ContextFunctions.CmpContext (&Context, &RecordToExhaust- > >ChildContext); >=20 > + >=20 > + } else { >=20 > + // >=20 > + // This child doesn't require any more calling context b= eyond what >=20 > + // it supplied in registration. Simply pass back what i= t gave us. >=20 > + // >=20 > + Context =3D RecordToExhaust->ChildContext; >=20 > + ContextsMatch =3D TRUE; >=20 > + } >=20 > + >=20 > + if (ContextsMatch) { >=20 > + if (RecordToExhaust->ProtocolType =3D=3D PchSmiDispatchT= ype) { >=20 > + // >=20 > + // For PCH SMI dispatch protocols >=20 > + // >=20 > + PchSmiTypeCallbackDispatcher (RecordToExhaust); >=20 > + } else { >=20 > + if ((RecordToExhaust->ProtocolType =3D=3D SxType) && > (Context.Sx.Type =3D=3D SxS3) && (Context.Sx.Phase =3D=3D SxEntry) && > !mS3SusStart) { >=20 > + REPORT_STATUS_CODE (EFI_PROGRESS_CODE, > PROGRESS_CODE_S3_SUSPEND_START); >=20 > + mS3SusStart =3D TRUE; >=20 > + } >=20 > + // >=20 > + // For EFI standard SMI dispatch protocols >=20 > + // >=20 > + if (RecordToExhaust->Callback !=3D NULL) { >=20 > + if (RecordToExhaust->ContextFunctions.GetCommBuffer = !=3D > NULL) { >=20 > + // >=20 > + // This callback function needs CommBuffer and > CommBufferSize. >=20 > + // Get those from child and then pass to callback = function. >=20 > + // >=20 > + RecordToExhaust->ContextFunctions.GetCommBuffer > (RecordToExhaust, &CommBuffer, &CommBufferSize); >=20 > + } else { >=20 > + // >=20 > + // Child doesn't support the CommBuffer and CommBu= fferSize. >=20 > + // Just pass NULL value to callback function. >=20 > + // >=20 > + CommBuffer =3D NULL; >=20 > + CommBufferSize =3D 0; >=20 > + } >=20 > + >=20 > + PERF_START_EX (NULL, "SmmFunction", NULL, AsmReadTsc= (), > RecordToExhaust->ProtocolType); >=20 > + RecordToExhaust->Callback ((EFI_HANDLE) & RecordToEx= haust- > >Link, &Context, CommBuffer, &CommBufferSize); >=20 > + PERF_END_EX (NULL, "SmmFunction", NULL, AsmReadTsc (= ), > RecordToExhaust->ProtocolType); >=20 > + if (RecordToExhaust->ProtocolType =3D=3D SxType) { >=20 > + SxChildWasDispatched =3D TRUE; >=20 > + } >=20 > + } else { >=20 > + ASSERT (FALSE); >=20 > + } >=20 > + } >=20 > + } >=20 > + } >=20 > + } >=20 > + >=20 > + if (RecordInDb->ClearSource =3D=3D NULL) { >=20 > + // >=20 > + // Clear the SMI associated w/ the source using the default = function >=20 > + // >=20 > + PchSmmClearSource (&ActiveSource); >=20 > + } else { >=20 > + // >=20 > + // This source requires special handling to clear >=20 > + // >=20 > + RecordInDb->ClearSource (&ActiveSource); >=20 > + } >=20 > + // >=20 > + // Clear pending SMI status before EOS >=20 > + // >=20 > + ClearPendingSmiStatus (SmiStsValue, SciEn); >=20 > + // >=20 > + // Also, try to clear EOS >=20 > + // >=20 > + EosSet =3D PchSmmSetAndCheckEos (); >=20 > + // >=20 > + // Queue is empty, reset the search >=20 > + // >=20 > + break; >=20 > + } >=20 > + } >=20 > + } >=20 > + } >=20 > + // >=20 > + // If you arrive here, there are two possible reasons: >=20 > + // (1) you've got problems with clearing the SMI status bits in the >=20 > + // ACPI table. If you don't properly clear the SMI bits, then you won= 't be > able to set the >=20 > + // EOS bit. If this happens too many times, the loop exits. >=20 > + // (2) there was a SMM communicate for callback messages that was > received prior >=20 > + // to this driver. >=20 > + // If there is an asynchronous SMI that occurs while processing the > Callback, let >=20 > + // all of the drivers (including this one) have an opportunity to scan= for the > SMI >=20 > + // and handle it. >=20 > + // If not, we don't want to exit and have the foreground app. clear EO= S > without letting >=20 > + // these other sources get serviced. >=20 > + // >=20 > + // This assert is not valid with CSM legacy solution because it genera= tes > software SMI >=20 > + // to test for legacy USB support presence. >=20 > + // This may not be illegal, so we cannot assert at this time. >=20 > + // >=20 > + // ASSERT (EscapeCount > 0); >=20 > + // >=20 > + if (SxChildWasDispatched) { >=20 > + // >=20 > + // A child of the SmmSxDispatch protocol was dispatched during this = call; >=20 > + // put the system to sleep. >=20 > + // >=20 > + PchSmmSxGoToSleep (); >=20 > + } >=20 > + // >=20 > + // Restore IO index registers >=20 > + // @note: Save/Restore port 70h directly might break NMI_EN# setting, >=20 > + // then save/restore 74h/76h instead. >=20 > + // >=20 > + IoWrite8 (R_RTC_IO_EXT_INDEX_ALT, Port76Save); >=20 > + IoWrite8 (R_RTC_IO_INDEX_ALT, Port74Save); >=20 > + >=20 > + return Status; >=20 > +} >=20 > diff --git > a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEspi > .c > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEspi > .c > new file mode 100644 > index 0000000000..9ce4072e37 > --- /dev/null > +++ > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEspi > .c > @@ -0,0 +1,1588 @@ > +/** @file >=20 > + eSPI SMI implementation >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > + >=20 > +#include "PchSmmEspi.h" >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > + >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED ESPI_SMI_INSTANCE > mEspiSmiInstance =3D { >=20 > + // >=20 > + // Signature >=20 > + // >=20 > + ESPI_SMI_INSTANCE_SIGNATURE, >=20 > + // >=20 > + // Handle >=20 > + // >=20 > + NULL, >=20 > + // >=20 > + // PchEspiSmiDispatchProtocol >=20 > + // >=20 > + { >=20 > + PCH_ESPI_SMI_DISPATCH_REVISION, >=20 > + EspiSmiUnRegister, >=20 > + BiosWrProtectRegister, >=20 > + BiosWrReportRegister, >=20 > + PcNonFatalErrRegister, >=20 > + PcFatalErrRegister, >=20 > + VwNonFatalErrRegister, >=20 > + VwFatalErrRegister, >=20 > + FlashNonFatalErrRegister, >=20 > + FlashFatalErrRegister, >=20 > + LnkType1ErrRegister, >=20 > + EspiSlaveSmiRegister >=20 > + }, >=20 > + // >=20 > + // PchSmiEspiHandle[EspiTopLevelTypeMax] >=20 > + // >=20 > + { >=20 > + NULL, NULL, NULL >=20 > + }, >=20 > + // >=20 > + // CallbackDataBase[EspiSmiTypeMax] >=20 > + // >=20 > + { >=20 > + {NULL, NULL}, {NULL, NULL}, {NULL, NULL}, {NULL, NULL}, {NULL, NULL}= , >=20 > + {NULL, NULL}, {NULL, NULL}, {NULL, NULL}, {NULL, NULL}, {NULL, NULL} >=20 > + }, >=20 > + // >=20 > + // EspiSmiEventCounter[EspiSmiTypeMax] >=20 > + // >=20 > + { >=20 > + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 >=20 > + }, >=20 > + // >=20 > + // Barrier[EspiTopLevelTypeMax] >=20 > + // >=20 > + { >=20 > + { >=20 > + BiosWrProtect, >=20 > + BiosWrProtect >=20 > + }, >=20 > + { >=20 > + BiosWrReport, >=20 > + LnkType1Err >=20 > + }, >=20 > + { >=20 > + EspiSlaveSmi, >=20 > + EspiSlaveSmi >=20 > + } >=20 > + } >=20 > +}; >=20 > + >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED CONST ESPI_DESCRIPTOR > mEspiDescriptor[EspiSmiTypeMax] =3D { >=20 > + // >=20 > + // BiosWrProtect >=20 > + // >=20 > + { >=20 > + { >=20 > + PCIE_ADDR_TYPE, >=20 > + { ( >=20 > + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | >=20 > + (PCI_DEVICE_NUMBER_PCH_LPC << 19) | >=20 > + (PCI_FUNCTION_NUMBER_PCH_LPC << 16) | >=20 > + R_ESPI_CFG_PCBC >=20 > + ) } >=20 > + }, >=20 > + // >=20 > + // SourceIsActiveAndMask and SourceIsActiveValue >=20 > + // >=20 > + B_ESPI_CFG_PCBC_BWPDS | B_ESPI_CFG_PCBC_LE, >=20 > + B_ESPI_CFG_PCBC_BWPDS | B_ESPI_CFG_PCBC_LE, >=20 > + // >=20 > + // ClearStatusAndMask and ClearStatusOrMask >=20 > + // >=20 > + (UINT32) ~B_ESPI_CFG_PCBC_BWRS, >=20 > + B_ESPI_CFG_PCBC_BWPDS >=20 > + }, >=20 > + // >=20 > + // BiosWrReport >=20 > + // >=20 > + { >=20 > + { >=20 > + PCIE_ADDR_TYPE, >=20 > + { ( >=20 > + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | >=20 > + (PCI_DEVICE_NUMBER_PCH_LPC << 19) | >=20 > + (PCI_FUNCTION_NUMBER_PCH_LPC << 16) | >=20 > + R_ESPI_CFG_PCBC >=20 > + ) } >=20 > + }, >=20 > + B_ESPI_CFG_PCBC_BWRS | B_ESPI_CFG_PCBC_BWRE, >=20 > + B_ESPI_CFG_PCBC_BWRS | B_ESPI_CFG_PCBC_BWRE, >=20 > + (UINT32) ~B_ESPI_CFG_PCBC_BWPDS, >=20 > + B_ESPI_CFG_PCBC_BWRS >=20 > + }, >=20 > + // >=20 > + // PcNonFatalErr >=20 > + // >=20 > + { >=20 > + { >=20 > + PCR_ADDR_TYPE, >=20 > + {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_PCERR_SLV0) } >=20 > + }, >=20 > + (B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XNFEE), >=20 > + (B_ESPI_PCR_XERR_XNFES | (V_ESPI_PCR_XERR_XNFEE_SMI << > N_ESPI_PCR_XERR_XNFEE)), >=20 > + (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD | > B_ESPI_PCR_XERR_XFES), >=20 > + B_ESPI_PCR_XERR_XNFES >=20 > + }, >=20 > + // >=20 > + // PcFatalErr >=20 > + // >=20 > + { >=20 > + { >=20 > + PCR_ADDR_TYPE, >=20 > + {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_PCERR_SLV0) } >=20 > + }, >=20 > + (B_ESPI_PCR_XERR_XFES | B_ESPI_PCR_XERR_XFEE), >=20 > + (B_ESPI_PCR_XERR_XFES | (V_ESPI_PCR_XERR_XFEE_SMI << > N_ESPI_PCR_XERR_XFEE)), >=20 > + (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD | > B_ESPI_PCR_XERR_XNFES), >=20 > + B_ESPI_PCR_XERR_XFES >=20 > + }, >=20 > + // >=20 > + // VwNonFatalErr >=20 > + // >=20 > + { >=20 > + { >=20 > + PCR_ADDR_TYPE, >=20 > + {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_VWERR_SLV0) } >=20 > + }, >=20 > + (B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XNFEE), >=20 > + (B_ESPI_PCR_XERR_XNFES | (V_ESPI_PCR_XERR_XNFEE_SMI << > N_ESPI_PCR_XERR_XNFEE)), >=20 > + (UINT32) ~B_ESPI_PCR_XERR_XFES, >=20 > + B_ESPI_PCR_XERR_XNFES >=20 > + }, >=20 > + // >=20 > + // VwFatalErr >=20 > + // >=20 > + { >=20 > + { >=20 > + PCR_ADDR_TYPE, >=20 > + {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_VWERR_SLV0) } >=20 > + }, >=20 > + (B_ESPI_PCR_XERR_XFES | B_ESPI_PCR_XERR_XFEE), >=20 > + (B_ESPI_PCR_XERR_XFES | (V_ESPI_PCR_XERR_XFEE_SMI << > N_ESPI_PCR_XERR_XFEE)), >=20 > + (UINT32) ~B_ESPI_PCR_XERR_XNFES, >=20 > + B_ESPI_PCR_XERR_XFES >=20 > + }, >=20 > + // >=20 > + // FlashNonFatalErr >=20 > + // >=20 > + { >=20 > + { >=20 > + PCR_ADDR_TYPE, >=20 > + {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_FCERR_SLV0) } >=20 > + }, >=20 > + (B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XNFEE), >=20 > + (B_ESPI_PCR_XERR_XNFES | (V_ESPI_PCR_XERR_XNFEE_SMI << > N_ESPI_PCR_XERR_XNFEE)), >=20 > + (UINT32) ~B_ESPI_PCR_XERR_XFES, >=20 > + B_ESPI_PCR_XERR_XNFES >=20 > + }, >=20 > + // >=20 > + // FlashFatalErr >=20 > + // >=20 > + { >=20 > + { >=20 > + PCR_ADDR_TYPE, >=20 > + {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_FCERR_SLV0) } >=20 > + }, >=20 > + (B_ESPI_PCR_XERR_XFES | B_ESPI_PCR_XERR_XFEE), >=20 > + (B_ESPI_PCR_XERR_XFES | (V_ESPI_PCR_XERR_XFEE_SMI << > N_ESPI_PCR_XERR_XFEE)), >=20 > + (UINT32) ~B_ESPI_PCR_XERR_XNFES, >=20 > + B_ESPI_PCR_XERR_XFES >=20 > + }, >=20 > + // >=20 > + // LnkType1Err >=20 > + // >=20 > + { >=20 > + { >=20 > + PCR_ADDR_TYPE, >=20 > + {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_LNKERR_SLV0) } >=20 > + }, >=20 > + B_ESPI_PCR_LNKERR_SLV0_LFET1S | B_ESPI_PCR_LNKERR_SLV0_LFET1E, >=20 > + B_ESPI_PCR_LNKERR_SLV0_LFET1S | > (V_ESPI_PCR_LNKERR_SLV0_LFET1E_SMI << > N_ESPI_PCR_LNKERR_SLV0_LFET1E), >=20 > + (UINT32) ~B_ESPI_PCR_LNKERR_SLV0_SLCRR, >=20 > + B_ESPI_PCR_LNKERR_SLV0_LFET1S >=20 > + }, >=20 > +}; >=20 > + >=20 > +/** >=20 > + Enable eSPI SMI source >=20 > + >=20 > + @param[in] EspiSmiType Type based on ESPI_SMI_TYPE >=20 > +**/ >=20 > +STATIC >=20 > +VOID >=20 > +EspiSmiEnableSource ( >=20 > + IN CONST ESPI_SMI_TYPE EspiSmiType >=20 > + ) >=20 > +{ >=20 > + UINT64 PciBaseAddress; >=20 > + >=20 > + switch (EspiSmiType) { >=20 > + case BiosWrProtect: >=20 > + // >=20 > + // It doesn't enable the BIOSLOCK here. Enable it by policy in DXE= . >=20 > + // >=20 > + break; >=20 > + case BiosWrReport: >=20 > + PciBaseAddress =3D EspiPciCfgBase (); >=20 > + PciSegmentAndThenOr32 ( >=20 > + PciBaseAddress + R_ESPI_CFG_PCBC, >=20 > + (UINT32) ~(B_ESPI_CFG_PCBC_BWRS | B_ESPI_CFG_PCBC_BWPDS), >=20 > + B_ESPI_CFG_PCBC_BWRE >=20 > + ); >=20 > + break; >=20 > + case PcNonFatalErr: >=20 > + PchPcrAndThenOr32 ( >=20 > + PID_ESPISPI, >=20 > + (UINT16) R_ESPI_PCR_PCERR_SLV0, >=20 > + (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD | > B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES), >=20 > + B_ESPI_PCR_XERR_XNFEE >=20 > + ); >=20 > + break; >=20 > + >=20 > + case PcFatalErr: >=20 > + PchPcrAndThenOr32 ( >=20 > + PID_ESPISPI, >=20 > + (UINT16) R_ESPI_PCR_PCERR_SLV0, >=20 > + (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD | > B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES), >=20 > + B_ESPI_PCR_XERR_XFEE >=20 > + ); >=20 > + break; >=20 > + >=20 > + case VwNonFatalErr: >=20 > + PchPcrAndThenOr32 ( >=20 > + PID_ESPISPI, >=20 > + (UINT16) R_ESPI_PCR_VWERR_SLV0, >=20 > + (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES), >=20 > + B_ESPI_PCR_XERR_XNFEE >=20 > + ); >=20 > + break; >=20 > + >=20 > + case VwFatalErr: >=20 > + PchPcrAndThenOr32 ( >=20 > + PID_ESPISPI, >=20 > + (UINT16) R_ESPI_PCR_VWERR_SLV0, >=20 > + (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES), >=20 > + B_ESPI_PCR_XERR_XFEE >=20 > + ); >=20 > + break; >=20 > + >=20 > + case FlashNonFatalErr: >=20 > + PchPcrAndThenOr32 ( >=20 > + PID_ESPISPI, >=20 > + (UINT16) R_ESPI_PCR_FCERR_SLV0, >=20 > + (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES), >=20 > + B_ESPI_PCR_XERR_XNFEE >=20 > + ); >=20 > + break; >=20 > + >=20 > + case FlashFatalErr: >=20 > + PchPcrAndThenOr32 ( >=20 > + PID_ESPISPI, >=20 > + (UINT16) R_ESPI_PCR_FCERR_SLV0, >=20 > + (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES), >=20 > + B_ESPI_PCR_XERR_XFEE >=20 > + ); >=20 > + break; >=20 > + >=20 > + case LnkType1Err: >=20 > + PchPcrAndThenOr32 ( >=20 > + PID_ESPISPI, >=20 > + (UINT16) R_ESPI_PCR_LNKERR_SLV0, >=20 > + (UINT32) ~(B_ESPI_PCR_LNKERR_SLV0_SLCRR | > B_ESPI_PCR_LNKERR_SLV0_LFET1S), >=20 > + (UINT32) (V_ESPI_PCR_LNKERR_SLV0_LFET1E_SMI << > N_ESPI_PCR_LNKERR_SLV0_LFET1E) >=20 > + ); >=20 > + >=20 > + if (IsEspiSecondSlaveSupported ()) { >=20 > + PchPcrAndThenOr32 ( >=20 > + PID_ESPISPI, >=20 > + (UINT16) R_ESPI_PCR_LNKERR_SLV1, >=20 > + (UINT32) ~(B_ESPI_PCR_LNKERR_SLV0_SLCRR | > B_ESPI_PCR_LNKERR_SLV0_LFET1S), >=20 > + (UINT32) (V_ESPI_PCR_LNKERR_SLV0_LFET1E_SMI << > N_ESPI_PCR_LNKERR_SLV0_LFET1E) >=20 > + ); >=20 > + } >=20 > + break; >=20 > + >=20 > + default: >=20 > + DEBUG ((DEBUG_ERROR, "Unsupported EspiSmiType \n")); >=20 > + ASSERT (FALSE); >=20 > + break; >=20 > + } >=20 > +} >=20 > + >=20 > + >=20 > +/** >=20 > + Disable eSPI SMI source >=20 > + >=20 > + @param[in] EspiSmiType Type based on ESPI_SMI_TYPE >=20 > +**/ >=20 > +STATIC >=20 > +VOID >=20 > +EspiSmiDisableSource ( >=20 > + IN CONST ESPI_SMI_TYPE EspiSmiType >=20 > + ) >=20 > +{ >=20 > + >=20 > + switch (EspiSmiType) { >=20 > + case BiosWrProtect: >=20 > + case BiosWrReport: >=20 > + DEBUG ((DEBUG_ERROR, "Bit is write lock, thus BWRE/BWPDS source > cannot be disabled \n")); >=20 > + ASSERT (FALSE); >=20 > + break; >=20 > + case PcNonFatalErr: >=20 > + PchPcrAndThenOr32 ( >=20 > + PID_ESPISPI, >=20 > + (UINT16) R_ESPI_PCR_PCERR_SLV0, >=20 > + (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD | > B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES | > B_ESPI_PCR_XERR_XNFEE), >=20 > + 0 >=20 > + ); >=20 > + break; >=20 > + >=20 > + case PcFatalErr: >=20 > + PchPcrAndThenOr32 ( >=20 > + PID_ESPISPI, >=20 > + (UINT16) R_ESPI_PCR_PCERR_SLV0, >=20 > + (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD | > B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES | > B_ESPI_PCR_XERR_XFEE), >=20 > + 0 >=20 > + ); >=20 > + break; >=20 > + >=20 > + case VwNonFatalErr: >=20 > + PchPcrAndThenOr32 ( >=20 > + PID_ESPISPI, >=20 > + (UINT16) R_ESPI_PCR_VWERR_SLV0, >=20 > + (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES | > B_ESPI_PCR_XERR_XNFEE), >=20 > + 0 >=20 > + ); >=20 > + break; >=20 > + >=20 > + case VwFatalErr: >=20 > + PchPcrAndThenOr32 ( >=20 > + PID_ESPISPI, >=20 > + (UINT16) R_ESPI_PCR_VWERR_SLV0, >=20 > + (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES | > B_ESPI_PCR_XERR_XFEE), >=20 > + 0 >=20 > + ); >=20 > + break; >=20 > + >=20 > + case FlashNonFatalErr: >=20 > + PchPcrAndThenOr32 ( >=20 > + PID_ESPISPI, >=20 > + (UINT16) R_ESPI_PCR_FCERR_SLV0, >=20 > + (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES | > B_ESPI_PCR_XERR_XNFEE), >=20 > + 0 >=20 > + ); >=20 > + break; >=20 > + >=20 > + case FlashFatalErr: >=20 > + PchPcrAndThenOr32 ( >=20 > + PID_ESPISPI, >=20 > + (UINT16) R_ESPI_PCR_FCERR_SLV0, >=20 > + (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES | > B_ESPI_PCR_XERR_XFEE), >=20 > + 0 >=20 > + ); >=20 > + break; >=20 > + >=20 > + case LnkType1Err: >=20 > + PchPcrAndThenOr32 ( >=20 > + PID_ESPISPI, >=20 > + (UINT16) R_ESPI_PCR_LNKERR_SLV0, >=20 > + (UINT32) ~(B_ESPI_PCR_LNKERR_SLV0_SLCRR | > B_ESPI_PCR_LNKERR_SLV0_LFET1S), >=20 > + 0 >=20 > + ); >=20 > + >=20 > + if (IsEspiSecondSlaveSupported ()) { >=20 > + PchPcrAndThenOr32 ( >=20 > + PID_ESPISPI, >=20 > + (UINT16) R_ESPI_PCR_LNKERR_SLV1, >=20 > + (UINT32) ~(B_ESPI_PCR_LNKERR_SLV0_SLCRR | > B_ESPI_PCR_LNKERR_SLV0_LFET1S), >=20 > + 0 >=20 > + ); >=20 > + } >=20 > + break; >=20 > + >=20 > + default: >=20 > + DEBUG ((DEBUG_ERROR, "Unsupported EspiSmiType \n")); >=20 > + ASSERT (FALSE); >=20 > + break; >=20 > + } >=20 > +} >=20 > + >=20 > +/** >=20 > + Clear a status for the SMI event >=20 > + >=20 > + @param[in] EspiSmiType Type based on ESPI_SMI_TYPE >=20 > +**/ >=20 > +STATIC >=20 > +VOID >=20 > +EspiSmiClearStatus ( >=20 > + IN CONST ESPI_SMI_TYPE EspiSmiType >=20 > + ) >=20 > +{ >=20 > + UINT32 PciBus; >=20 > + UINT32 PciDev; >=20 > + UINT32 PciFun; >=20 > + UINT32 PciReg; >=20 > + UINT64 PciBaseAddress; >=20 > + CONST ESPI_DESCRIPTOR *Desc; >=20 > + >=20 > + Desc =3D &mEspiDescriptor[EspiSmiType]; >=20 > + >=20 > + switch (Desc->Address.Type) { >=20 > + case PCIE_ADDR_TYPE: >=20 > + PciBus =3D Desc->Address.Data.pcie.Fields.Bus; >=20 > + PciDev =3D Desc->Address.Data.pcie.Fields.Dev; >=20 > + PciFun =3D Desc->Address.Data.pcie.Fields.Fnc; >=20 > + PciReg =3D Desc->Address.Data.pcie.Fields.Reg; >=20 > + PciBaseAddress =3D PCI_SEGMENT_LIB_ADDRESS > (DEFAULT_PCI_SEGMENT_NUMBER_PCH, PciBus, PciDev, PciFun, 0); >=20 > + PciSegmentAndThenOr32 (PciBaseAddress + PciReg, Desc- > >ClearStatusAndMask, Desc->ClearStatusOrMask); >=20 > + break; >=20 > + case PCR_ADDR_TYPE: >=20 > + PchPcrAndThenOr32 ( >=20 > + Desc->Address.Data.Pcr.Fields.Pid, >=20 > + Desc->Address.Data.Pcr.Fields.Offset, >=20 > + Desc->ClearStatusAndMask, >=20 > + Desc->ClearStatusOrMask >=20 > + ); >=20 > + break; >=20 > + default: >=20 > + DEBUG ((DEBUG_ERROR, "Address type for eSPI SMI is invalid \n")); >=20 > + ASSERT (FALSE); >=20 > + break; >=20 > + } >=20 > +} >=20 > + >=20 > +/** >=20 > + Checks if a source is active by looking at the enable and status bits >=20 > + >=20 > + @param[in] EspiSmiType Type based on ESPI_SMI_TYPE >=20 > +**/ >=20 > +STATIC >=20 > +BOOLEAN >=20 > +EspiSmiSourceIsActive ( >=20 > + IN CONST ESPI_SMI_TYPE EspiSmiType >=20 > + ) >=20 > +{ >=20 > + BOOLEAN Active; >=20 > + UINT32 PciBus; >=20 > + UINT32 PciDev; >=20 > + UINT32 PciFun; >=20 > + UINT32 PciReg; >=20 > + UINT64 PciBaseAddress; >=20 > + UINT32 Data32; >=20 > + CONST ESPI_DESCRIPTOR *Desc; >=20 > + >=20 > + Desc =3D &mEspiDescriptor[EspiSmiType]; >=20 > + >=20 > + Active =3D FALSE; >=20 > + switch (Desc->Address.Type) { >=20 > + case PCIE_ADDR_TYPE: >=20 > + PciBus =3D Desc->Address.Data.pcie.Fields.Bus; >=20 > + PciDev =3D Desc->Address.Data.pcie.Fields.Dev; >=20 > + PciFun =3D Desc->Address.Data.pcie.Fields.Fnc; >=20 > + PciReg =3D Desc->Address.Data.pcie.Fields.Reg; >=20 > + PciBaseAddress =3D PCI_SEGMENT_LIB_ADDRESS > (DEFAULT_PCI_SEGMENT_NUMBER_PCH, PciBus, PciDev, PciFun, 0); >=20 > + Data32 =3D PciSegmentRead32 (PciBaseAddress + PciReg); >=20 > + break; >=20 > + >=20 > + case PCR_ADDR_TYPE: >=20 > + Data32 =3D PchPcrRead32 ( >=20 > + Desc->Address.Data.Pcr.Fields.Pid, >=20 > + Desc->Address.Data.Pcr.Fields.Offset >=20 > + ); >=20 > + break; >=20 > + >=20 > + default: >=20 > + Data32 =3D 0; >=20 > + DEBUG ((DEBUG_ERROR, "Address type for eSPI SMI is invalid \n")); >=20 > + ASSERT (FALSE); >=20 > + break; >=20 > + } >=20 > + >=20 > + if ((Data32 & Desc->SourceIsActiveAndMask) =3D=3D Desc- > >SourceIsActiveValue) { >=20 > + Active =3D TRUE; >=20 > + } >=20 > + >=20 > + return Active; >=20 > +} >=20 > + >=20 > +/** >=20 > + Insert a handler into the corresponding linked list based on EspiSmiTy= pe >=20 > + >=20 > + @param[in] DispatchFunction The callback to execute >=20 > + @param[in] EspiSmiType Type based on ESPI_SMI_TYPE to > determine which linked list to use >=20 > + @param[out] DispatchHandle The link to the record in the databa= se >=20 > + >=20 > + @retval EFI_SUCCESS Record was successfully inserted int= o master > database >=20 > + @retval EFI_OUT_OF_RESOURCES Cannot allocate pool to insert recor= d >=20 > +**/ >=20 > +STATIC >=20 > +EFI_STATUS >=20 > +InsertEspiRecord ( >=20 > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + IN ESPI_SMI_TYPE EspiSmiType, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + ESPI_SMI_RECORD *Record; >=20 > + >=20 > + Status =3D gSmst->SmmAllocatePool (EfiRuntimeServicesData, sizeof > (ESPI_SMI_RECORD), (VOID **) &Record); >=20 > + if (EFI_ERROR (Status)) { >=20 > + ASSERT (FALSE); >=20 > + return EFI_OUT_OF_RESOURCES; >=20 > + } >=20 > + SetMem (Record, sizeof (ESPI_SMI_RECORD), 0); >=20 > + >=20 > + Record->Callback =3D DispatchFunction; >=20 > + Record->Signature =3D ESPI_SMI_RECORD_SIGNATURE; >=20 > + >=20 > + InsertTailList (&mEspiSmiInstance.CallbackDataBase[EspiSmiType], > &Record->Link); >=20 > + EspiSmiClearStatus (EspiSmiType); >=20 > + EspiSmiEnableSource (EspiSmiType); >=20 > + >=20 > + ++mEspiSmiInstance.EspiSmiEventCounter[EspiSmiType]; >=20 > + >=20 > + *DispatchHandle =3D (EFI_HANDLE) (&Record->Link); >=20 > + >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > + >=20 > +/** >=20 > + This callback is registered to PchSmiDispatch >=20 > + >=20 > + @param[in] DispatchHandle Used to determine which source have been > triggered >=20 > +**/ >=20 > +VOID >=20 > +EspiSmiCallback ( >=20 > + IN EFI_HANDLE DispatchHandle >=20 > + ) >=20 > +{ >=20 > + DATABASE_RECORD *PchSmiRecord; >=20 > + ESPI_TOP_LEVEL_TYPE EspiTopLevelType; >=20 > + ESPI_SMI_TYPE EspiSmiType; >=20 > + ESPI_SMI_RECORD *RecordInDb; >=20 > + LIST_ENTRY *LinkInDb; >=20 > + >=20 > + PchSmiRecord =3D DATABASE_RECORD_FROM_LINK (DispatchHandle); >=20 > + >=20 > + if (PchSmiRecord->PchSmiType =3D=3D PchTcoSmiLpcBiosWpType) { >=20 > + EspiTopLevelType =3D EspiBiosWrProtect; >=20 > + } else if (PchSmiRecord->PchSmiType =3D=3D PchSmiSerialIrqType) { >=20 > + EspiTopLevelType =3D EspiSerialIrq; >=20 > + } else { >=20 > + DEBUG ((DEBUG_ERROR, "EspiSmiCallback was dispatched with a wrong > DispatchHandle")); >=20 > + ASSERT (FALSE); >=20 > + return; >=20 > + } >=20 > + >=20 > + for (EspiSmiType =3D mEspiSmiInstance.Barrier[EspiTopLevelType].Start; > EspiSmiType <=3D mEspiSmiInstance.Barrier[EspiTopLevelType].End; > ++EspiSmiType) { >=20 > + if (!EspiSmiSourceIsActive (EspiSmiType)) { >=20 > + continue; >=20 > + } >=20 > + // >=20 > + // The source is active, so walk the callback database and dispatch >=20 > + // >=20 > + if (!IsListEmpty (&mEspiSmiInstance.CallbackDataBase[EspiSmiType])) = { >=20 > + // >=20 > + // We have children registered w/ us -- continue >=20 > + // >=20 > + LinkInDb =3D GetFirstNode > (&mEspiSmiInstance.CallbackDataBase[EspiSmiType]); >=20 > + >=20 > + while (!IsNull (&mEspiSmiInstance.CallbackDataBase[EspiSmiType], > LinkInDb)) { >=20 > + RecordInDb =3D ESPI_RECORD_FROM_LINK (LinkInDb); >=20 > + >=20 > + // >=20 > + // RecordInDb->Link might be removed (unregistered) by Callback > function, and then the >=20 > + // system will hang in ASSERT() while calling GetNextNode(). >=20 > + // To prevent the issue, we need to get next record in DB here (= before > Callback function). >=20 > + // >=20 > + LinkInDb =3D GetNextNode > (&mEspiSmiInstance.CallbackDataBase[EspiSmiType], &RecordInDb->Link); >=20 > + >=20 > + // >=20 > + // Callback >=20 > + // >=20 > + if (RecordInDb->Callback !=3D NULL) { >=20 > + RecordInDb->Callback ((EFI_HANDLE) &RecordInDb->Link); >=20 > + } else { >=20 > + ASSERT (FALSE); >=20 > + } >=20 > + } >=20 > + } else if (EspiSmiType =3D=3D LnkType1Err) { >=20 > + // >=20 > + // If no proper handler registered for Link Type 1 Error >=20 > + // Call default SMI handler recover otherwise >=20 > + // >=20 > + EspiDefaultFatalErrorHandler (); >=20 > + } >=20 > + >=20 > + // >=20 > + // Finish walking the linked list for the EspiSmiType, so clear stat= us >=20 > + // >=20 > + EspiSmiClearStatus (EspiSmiType); >=20 > + } >=20 > +} >=20 > + >=20 > +// >=20 > +// EspiBiosWp srcdesc >=20 > +// >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescEspiBiosWp =3D { >=20 > + PCH_SMM_NO_FLAGS, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_EN} >=20 > + }, >=20 > + S_ACPI_IO_SMI_EN, >=20 > + N_ACPI_IO_SMI_EN_TCO >=20 > + }, >=20 > + { >=20 > + { >=20 > + PCIE_ADDR_TYPE, >=20 > + { ( >=20 > + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | >=20 > + (PCI_DEVICE_NUMBER_PCH_LPC << 19) | >=20 > + (PCI_FUNCTION_NUMBER_PCH_LPC << 16) | >=20 > + R_ESPI_CFG_PCBC >=20 > + ) } >=20 > + }, >=20 > + S_ESPI_CFG_PCBC, >=20 > + N_ESPI_CFG_PCBC_LE >=20 > + } >=20 > + }, >=20 > + { >=20 > + { >=20 > + { >=20 > + PCIE_ADDR_TYPE, >=20 > + { ( >=20 > + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) | >=20 > + (PCI_DEVICE_NUMBER_PCH_LPC << 19) | >=20 > + (PCI_FUNCTION_NUMBER_PCH_LPC << 16) | >=20 > + R_ESPI_CFG_PCBC >=20 > + ) } >=20 > + }, >=20 > + S_ESPI_CFG_PCBC, >=20 > + N_ESPI_CFG_PCBC_BWPDS >=20 > + } >=20 > + }, >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_TCO >=20 > + } >=20 > +}; >=20 > + >=20 > +/** >=20 > + This function will register EspiSmiCallback with mSrcDescEspiBiosWp so= urce > decriptor >=20 > + This function make sure there is only one BIOS WP SMI handler is > registered. >=20 > + While any ESPI sub BIOS WP SMI type is registered, all the BIOS WP SMI >=20 > + will go to callback function EspiSmiCallback first, and then dispatchs= the > callbacks >=20 > + recorded in mEspiSmiInstance. >=20 > + >=20 > + @retval EFI_SUCCESS Registration succeed >=20 > + @retval others Registration failed >=20 > +**/ >=20 > +STATIC >=20 > +EFI_STATUS >=20 > +RegisterBiosWrProtectIfNull ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + DATABASE_RECORD *Record; >=20 > + >=20 > + if (mEspiSmiInstance.PchSmiEspiHandle[EspiBiosWrProtect] =3D=3D NULL) = { >=20 > + Status =3D PchSmiRecordInsert ( >=20 > + &mSrcDescEspiBiosWp, >=20 > + (PCH_SMI_CALLBACK_FUNCTIONS) EspiSmiCallback, >=20 > + PchTcoSmiLpcBiosWpType, >=20 > + &mEspiSmiInstance.PchSmiEspiHandle[EspiBiosWrProtect] >=20 > + ); >=20 > + if (EFI_ERROR (Status)) { >=20 > + DEBUG ((DEBUG_ERROR, "Fail to register BIOS WP SMI handler \n")); >=20 > + return Status; >=20 > + } >=20 > + Record =3D DATABASE_RECORD_FROM_LINK > (mEspiSmiInstance.PchSmiEspiHandle[EspiBiosWrProtect]); >=20 > + Record->ClearSource =3D PchTcoSmiClearSource; >=20 > + } >=20 > + >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > + >=20 > +/** >=20 > + This function will register EspiSmiCallback with mSrcDescSerialIrq sou= rce > decriptor >=20 > + This function make sure there is only one Serial IRQ SMI handler is > registered. >=20 > + While any ESPI sub Serial IRQ SMI type is registered, all the Serial I= RQ SMI >=20 > + will go to callback function EspiSmiCallback first, and then dispatchs= the > callbacks >=20 > + recorded in mEspiSmiInstance. >=20 > + >=20 > + @retval EFI_SUCCESS Registration succeed >=20 > + @retval others Registration failed >=20 > +**/ >=20 > +STATIC >=20 > +EFI_STATUS >=20 > +RegisterSerialIrqIfNull ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + >=20 > + if (mEspiSmiInstance.PchSmiEspiHandle[EspiSerialIrq] =3D=3D NULL) { >=20 > + Status =3D PchSmiRecordInsert ( >=20 > + &mSrcDescSerialIrq, >=20 > + (PCH_SMI_CALLBACK_FUNCTIONS) EspiSmiCallback, >=20 > + PchSmiSerialIrqType, >=20 > + &mEspiSmiInstance.PchSmiEspiHandle[EspiSerialIrq] >=20 > + ); >=20 > + if (EFI_ERROR (Status)) { >=20 > + DEBUG ((DEBUG_ERROR, "Fail to register Serial IRQ SMI handler \n")= ); >=20 > + return Status; >=20 > + } >=20 > + } >=20 > + >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > + >=20 > +/** >=20 > + Installs and initialize this protocol >=20 > + >=20 > + @param[in] ImageHandle Not used >=20 > + >=20 > + @retval EFI_SUCCESS Installation succeed >=20 > + @retval others Installation failed >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +InstallEspiSmi ( >=20 > + IN EFI_HANDLE ImageHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + ESPI_SMI_TYPE EspiSmiType; >=20 > + >=20 > + DEBUG ((DEBUG_INFO, "[InstallEspiSmi] Enter\n")); >=20 > + >=20 > + // >=20 > + // InitializeListHead for > mEspiSmiInstance.CallBackDataBase[EspiTopLevelTypeMax] >=20 > + // >=20 > + for (EspiSmiType =3D 0; EspiSmiType < EspiSmiTypeMax; ++EspiSmiType) { >=20 > + InitializeListHead (&mEspiSmiInstance.CallbackDataBase[EspiSmiType])= ; >=20 > + } >=20 > + >=20 > + // >=20 > + // Install EfiEspiSmiDispatchProtocol >=20 > + // >=20 > + Status =3D gSmst->SmmInstallProtocolInterface ( >=20 > + &mEspiSmiInstance.Handle, >=20 > + &gPchEspiSmiDispatchProtocolGuid, >=20 > + EFI_NATIVE_INTERFACE, >=20 > + &mEspiSmiInstance.PchEspiSmiDispatchProtocol >=20 > + ); >=20 > + if (EFI_ERROR (Status)) { >=20 > + DEBUG ((DEBUG_ERROR, "Failed to install eSPI SMI Dispatch > Protocol\n")); >=20 > + ASSERT (FALSE); >=20 > + return Status; >=20 > + } >=20 > + >=20 > + // Register eSPI SMM callback to enable Fatal Error handling by defaul= t > handler >=20 > + Status =3D RegisterSerialIrqIfNull (); >=20 > + if (EFI_ERROR (Status)) { >=20 > + return Status; >=20 > + } >=20 > + >=20 > + // Enable LnkType1Err SMI generation for default handler >=20 > + EspiSmiClearStatus (LnkType1Err); >=20 > + EspiSmiEnableSource (LnkType1Err); >=20 > + >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > + >=20 > +/** >=20 > + eSPI SMI Dispatch Protocol instance to register a BIOS Write Protect e= vent >=20 > + >=20 > + @param[in] This Not used >=20 > + @param[in] DispatchFunction The callback to execute >=20 > + @param[out] DispatchHandle The handle for this callback registratio= n >=20 > + >=20 > + @retval EFI_SUCCESS Registration succeed >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > + @retval others Registration failed >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +BiosWrProtectRegister ( >=20 > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + Status =3D RegisterBiosWrProtectIfNull (); >=20 > + if (EFI_ERROR (Status)) { >=20 > + return Status; >=20 > + } >=20 > + // >=20 > + // Insert a record >=20 > + // >=20 > + Status =3D InsertEspiRecord (DispatchFunction, BiosWrProtect, > DispatchHandle); >=20 > + if (!EFI_ERROR (Status)) { >=20 > + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); >=20 > + } >=20 > + return Status; >=20 > +} >=20 > + >=20 > +/** >=20 > + eSPI SMI Dispatch Protocol instance to register a BIOS Write Report ev= ent >=20 > + >=20 > + @param[in] This Not used >=20 > + @param[in] DispatchFunction The callback to execute >=20 > + @param[out] DispatchHandle The handle for this callback registratio= n >=20 > + >=20 > + @retval EFI_SUCCESS Registration succeed >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > + @retval others Registration failed >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +BiosWrReportRegister ( >=20 > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + Status =3D RegisterSerialIrqIfNull (); >=20 > + if (EFI_ERROR (Status)) { >=20 > + return Status; >=20 > + } >=20 > + // >=20 > + // Insert a record >=20 > + // >=20 > + Status =3D InsertEspiRecord (DispatchFunction, BiosWrReport, > DispatchHandle); >=20 > + if (!EFI_ERROR (Status)) { >=20 > + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); >=20 > + } >=20 > + return Status; >=20 > +} >=20 > + >=20 > +/** >=20 > + eSPI SMI Dispatch Protocol instance to register a Peripheral Channel N= on > Fatal Error event >=20 > + >=20 > + @param[in] This Not used >=20 > + @param[in] DispatchFunction The callback to execute >=20 > + @param[out] DispatchHandle The handle for this callback registratio= n >=20 > + >=20 > + @retval EFI_SUCCESS Registration succeed >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > + @retval others Registration failed >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PcNonFatalErrRegister ( >=20 > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + Status =3D RegisterSerialIrqIfNull (); >=20 > + if (EFI_ERROR (Status)) { >=20 > + return Status; >=20 > + } >=20 > + // >=20 > + // Insert a record >=20 > + // >=20 > + Status =3D InsertEspiRecord (DispatchFunction, PcNonFatalErr, > DispatchHandle); >=20 > + if (!EFI_ERROR (Status)) { >=20 > + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); >=20 > + } >=20 > + return Status; >=20 > +} >=20 > + >=20 > +/** >=20 > + eSPI SMI Dispatch Protocol instance to register a Peripheral Channel F= atal > Error event >=20 > + >=20 > + @param[in] This Not used >=20 > + @param[in] DispatchFunction The callback to execute >=20 > + @param[out] DispatchHandle The handle for this callback registratio= n >=20 > + >=20 > + @retval EFI_SUCCESS Registration succeed >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > + @retval others Registration failed >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PcFatalErrRegister ( >=20 > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + Status =3D RegisterSerialIrqIfNull (); >=20 > + if (EFI_ERROR (Status)) { >=20 > + return Status; >=20 > + } >=20 > + // >=20 > + // Insert a record >=20 > + // >=20 > + Status =3D InsertEspiRecord (DispatchFunction, PcFatalErr, DispatchHan= dle); >=20 > + if (!EFI_ERROR (Status)) { >=20 > + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); >=20 > + } >=20 > + return Status; >=20 > +} >=20 > + >=20 > +/** >=20 > + eSPI SMI Dispatch Protocol instance to register a Virtual Wire Non Fat= al > Error event >=20 > + >=20 > + @param[in] This Not used >=20 > + @param[in] DispatchFunction The callback to execute >=20 > + @param[out] DispatchHandle The handle for this callback registratio= n >=20 > + >=20 > + @retval EFI_SUCCESS Registration succeed >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > + @retval others Registration failed >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +VwNonFatalErrRegister ( >=20 > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + Status =3D RegisterSerialIrqIfNull (); >=20 > + if (EFI_ERROR (Status)) { >=20 > + return Status; >=20 > + } >=20 > + // >=20 > + // Insert a record >=20 > + // >=20 > + Status =3D InsertEspiRecord (DispatchFunction, VwNonFatalErr, > DispatchHandle); >=20 > + if (!EFI_ERROR (Status)) { >=20 > + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); >=20 > + } >=20 > + return Status; >=20 > +} >=20 > + >=20 > +/** >=20 > + eSPI SMI Dispatch Protocol instance to register a Virtual Wire Fatal E= rror > event >=20 > + >=20 > + @param[in] This Not used >=20 > + @param[in] DispatchFunction The callback to execute >=20 > + @param[out] DispatchHandle The handle for this callback registratio= n >=20 > + >=20 > + @retval EFI_SUCCESS Registration succeed >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > + @retval others Registration failed >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +VwFatalErrRegister ( >=20 > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + Status =3D RegisterSerialIrqIfNull (); >=20 > + if (EFI_ERROR (Status)) { >=20 > + return Status; >=20 > + } >=20 > + // >=20 > + // Insert a record >=20 > + // >=20 > + Status =3D InsertEspiRecord (DispatchFunction, VwFatalErr, DispatchHan= dle); >=20 > + if (!EFI_ERROR (Status)) { >=20 > + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); >=20 > + } >=20 > + return Status; >=20 > +} >=20 > + >=20 > +/** >=20 > + eSPI SMI Dispatch Protocol instance to register a Flash Channel Non Fa= tal > Error event >=20 > + >=20 > + @param[in] This Not used >=20 > + @param[in] DispatchFunction The callback to execute >=20 > + @param[out] DispatchHandle The handle for this callback registratio= n >=20 > + >=20 > + @retval EFI_SUCCESS Registration succeed >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > + @retval others Registration failed >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +FlashNonFatalErrRegister ( >=20 > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + Status =3D RegisterSerialIrqIfNull (); >=20 > + if (EFI_ERROR (Status)) { >=20 > + return Status; >=20 > + } >=20 > + // >=20 > + // Insert a record >=20 > + // >=20 > + Status =3D InsertEspiRecord (DispatchFunction, FlashNonFatalErr, > DispatchHandle); >=20 > + if (!EFI_ERROR (Status)) { >=20 > + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); >=20 > + } >=20 > + return Status; >=20 > +} >=20 > + >=20 > +/** >=20 > + eSPI SMI Dispatch Protocol instance to register a Flash Channel Fatal = Error > event >=20 > + >=20 > + @param[in] This Not used >=20 > + @param[in] DispatchFunction The callback to execute >=20 > + @param[out] DispatchHandle The handle for this callback registratio= n >=20 > + >=20 > + @retval EFI_SUCCESS Registration succeed >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > + @retval others Registration failed >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +FlashFatalErrRegister ( >=20 > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + Status =3D RegisterSerialIrqIfNull (); >=20 > + if (EFI_ERROR (Status)) { >=20 > + return Status; >=20 > + } >=20 > + // >=20 > + // Insert a record >=20 > + // >=20 > + Status =3D InsertEspiRecord (DispatchFunction, FlashFatalErr, > DispatchHandle); >=20 > + if (!EFI_ERROR (Status)) { >=20 > + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); >=20 > + } >=20 > + return Status; >=20 > +} >=20 > + >=20 > +/** >=20 > + eSPI SMI Dispatch Protocol instance to register a Link Error event >=20 > + >=20 > + @param[in] This Not used >=20 > + @param[in] DispatchFunction The callback to execute >=20 > + @param[out] DispatchHandle The handle for this callback registratio= n >=20 > + >=20 > + @retval EFI_SUCCESS Registration succeed >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > + @retval others Registration failed >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +LnkType1ErrRegister ( >=20 > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + Status =3D RegisterSerialIrqIfNull (); >=20 > + if (EFI_ERROR (Status)) { >=20 > + return Status; >=20 > + } >=20 > + // >=20 > + // Insert a record >=20 > + // >=20 > + Status =3D InsertEspiRecord (DispatchFunction, LnkType1Err, > DispatchHandle); >=20 > + if (!EFI_ERROR (Status)) { >=20 > + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); >=20 > + } >=20 > + return Status; >=20 > +} >=20 > + >=20 > +// >=20 > +// EspiSlave srcdesc >=20 > +// >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSrcDescEspiSlave =3D { >=20 > + PCH_SMM_NO_FLAGS, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_EN} >=20 > + }, >=20 > + S_ACPI_IO_SMI_EN, >=20 > + N_ACPI_IO_SMI_EN_ESPI >=20 > + }, >=20 > + NULL_BIT_DESC_INITIALIZER >=20 > + }, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_ESPI >=20 > + } >=20 > + }, >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_ESPI >=20 > + } >=20 > +}; >=20 > + >=20 > +/** >=20 > + eSPI SMI Dispatch Protocol instance to register a eSPI slave SMI >=20 > + This routine will also lock down ESPI_SMI_LOCK bit after registration = and > prevent >=20 > + this handler from unregistration. >=20 > + On platform that supports more than 1 device through another chip sele= ct > (SPT-H), >=20 > + the SMI handler itself needs to inspect both the eSPI devices' interru= pt > status registers >=20 > + (implementation specific for each Slave) in order to identify and serv= ice > the cause. >=20 > + After servicing it, it has to clear the Slaves' internal SMI# status r= egisters >=20 > + >=20 > + @param[in] This Not used >=20 > + @param[in] DispatchFunction The callback to execute >=20 > + @param[out] DispatchHandle The handle for this callback reg= istration >=20 > + >=20 > + @retval EFI_SUCCESS Registration succeed >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > + @retval EFI_ACCESS_DENIED The ESPI_SMI_LOCK is set and reg= ister > is blocked. >=20 > + @retval others Registration failed >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +EspiSlaveSmiRegister ( >=20 > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + // >=20 > + // If ESPI_SMI_LOCK is set, the register is blocked. >=20 > + // >=20 > + if (PmcIsEspiSmiLockSet ()) { >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + // >=20 > + // @note: This service doesn't utilize the data base of mEspiSmiInstan= ce. >=20 > + // While SMI is triggered it directly goes to the registing > DispatchFunction >=20 > + // instead of EspiSmiCallback. >=20 > + // >=20 > + Status =3D PchSmiRecordInsert ( >=20 > + &mSrcDescEspiSlave, >=20 > + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction, >=20 > + PchEspiSmiEspiSlaveType, >=20 > + DispatchHandle >=20 > + ); >=20 > + PchSmmClearSource (&mSrcDescEspiSlave); >=20 > + PchSmmEnableSource (&mSrcDescEspiSlave); >=20 > + >=20 > + // >=20 > + // Lock down the ESPI_SMI_LOCK after ESPI SMI is enabled. >=20 > + // >=20 > + PmcLockEspiSmiWithS3BootScript (); >=20 > + // >=20 > + // Keep the DispatchHandle which will be used for unregister function. >=20 > + // >=20 > + mEspiSmiInstance.PchSmiEspiHandle[EspiPmc] =3D *DispatchHandle; >=20 > + >=20 > + if (!EFI_ERROR (Status)) { >=20 > + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid, > (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction, > (UINTN)RETURN_ADDRESS (0), NULL, 0); >=20 > + } >=20 > + >=20 > + return Status; >=20 > +} >=20 > + >=20 > +/** >=20 > + eSPI SMI Dispatch Protocol instance to unregister a callback based on > handle >=20 > + >=20 > + @param[in] This Not used >=20 > + @param[in] DispatchHandle Handle acquired during registratio= n >=20 > + >=20 > + @retval EFI_SUCCESS Unregister successful >=20 > + @retval EFI_INVALID_PARAMETER DispatchHandle is null >=20 > + @retval EFI_INVALID_PARAMETER DispatchHandle's forward link has > bad pointer >=20 > + @retval EFI_INVALID_PARAMETER DispatchHandle does not exist in > database >=20 > + @retval EFI_ACCESS_DENIED Unregistration is done after end o= f DXE >=20 > + @retval EFI_ACCESS_DENIED DispatchHandle is not allowed to > unregistered >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +EspiSmiUnRegister ( >=20 > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN EFI_HANDLE DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + ESPI_TOP_LEVEL_TYPE EspiTopLevelType; >=20 > + ESPI_SMI_TYPE EspiSmiType; >=20 > + BOOLEAN SafeToDisable; >=20 > + LIST_ENTRY *LinkInDb; >=20 > + ESPI_SMI_RECORD *RecordPointer; >=20 > + DATABASE_RECORD *RecordToDelete; >=20 > + >=20 > + if (DispatchHandle =3D=3D NULL) { >=20 > + return EFI_INVALID_PARAMETER; >=20 > + } >=20 > + >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the > SmmReadyToLock event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + if (((LIST_ENTRY *) DispatchHandle)->ForwardLink =3D=3D (LIST_ENTRY *) > EFI_BAD_POINTER) { >=20 > + return EFI_INVALID_PARAMETER; >=20 > + } >=20 > + >=20 > + // >=20 > + // For DispatchHandle belongs to Espi Slave SMI, refuses the request o= f > unregistration. >=20 > + // >=20 > + if (mEspiSmiInstance.PchSmiEspiHandle[EspiPmc] =3D=3D DispatchHandle) = { >=20 > + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed for ESPI Slave SMI > handle! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + // >=20 > + // Iterate through all the database to find the record >=20 > + // >=20 > + for (EspiSmiType =3D 0; EspiSmiType < EspiSmiTypeMax; ++EspiSmiType) { >=20 > + LinkInDb =3D GetFirstNode > (&mEspiSmiInstance.CallbackDataBase[EspiSmiType]); >=20 > + >=20 > + while (!IsNull (&mEspiSmiInstance.CallbackDataBase[EspiSmiType], > LinkInDb)) { >=20 > + if (LinkInDb !=3D (LIST_ENTRY *) DispatchHandle) { >=20 > + LinkInDb =3D GetNextNode > (&mEspiSmiInstance.CallbackDataBase[EspiSmiType], LinkInDb); >=20 > + >=20 > + } else { >=20 > + // >=20 > + // Found the source to be from this list >=20 > + // >=20 > + RemoveEntryList (LinkInDb); >=20 > + RecordPointer =3D (ESPI_RECORD_FROM_LINK (LinkInDb)); >=20 > + >=20 > + if (mEspiSmiInstance.EspiSmiEventCounter[EspiSmiType] !=3D 0) { >=20 > + if (--mEspiSmiInstance.EspiSmiEventCounter[EspiSmiType] =3D=3D= 0) { >=20 > + EspiSmiDisableSource (EspiSmiType); >=20 > + } >=20 > + } >=20 > + >=20 > + Status =3D gSmst->SmmFreePool (RecordPointer); >=20 > + if (EFI_ERROR (Status)) { >=20 > + ASSERT (FALSE); >=20 > + } >=20 > + >=20 > + goto EspiSmiUnRegisterEnd; >=20 > + } >=20 > + } >=20 > + } >=20 > + // >=20 > + // If the code reach here, the handle passed in cannot be found >=20 > + // >=20 > + DEBUG ((DEBUG_ERROR, "eSPI SMI handle is not in record database \n")); >=20 > + ASSERT (FALSE); >=20 > + return EFI_INVALID_PARAMETER; >=20 > + >=20 > +EspiSmiUnRegisterEnd: >=20 > + >=20 > + // >=20 > + // Unregister and clear the handle from PchSmiDispatch >=20 > + // >=20 > + for (EspiTopLevelType =3D 0; EspiTopLevelType < EspiTopLevelTypeMax; > ++EspiTopLevelType) { >=20 > + SafeToDisable =3D TRUE; >=20 > + // >=20 > + // Checks all the child events that belongs to a top level status in= PMC >=20 > + // >=20 > + for (EspiSmiType =3D mEspiSmiInstance.Barrier[EspiTopLevelType].Star= t; > EspiSmiType <=3D mEspiSmiInstance.Barrier[EspiTopLevelType].End; > ++EspiSmiType) { >=20 > + if (mEspiSmiInstance.EspiSmiEventCounter[EspiSmiType] !=3D 0) { >=20 > + SafeToDisable =3D FALSE; >=20 > + } >=20 > + } >=20 > + // >=20 > + // Finally, disable the top level event in PMC >=20 > + // >=20 > + if (SafeToDisable) { >=20 > + if (mEspiSmiInstance.PchSmiEspiHandle[EspiTopLevelType] !=3D NULL)= { >=20 > + Status =3D PchSmmCoreUnRegister (NULL, > mEspiSmiInstance.PchSmiEspiHandle[EspiTopLevelType]); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + mEspiSmiInstance.PchSmiEspiHandle[EspiTopLevelType] =3D NULL; >=20 > + } >=20 > + } >=20 > + } >=20 > + RecordToDelete =3D DATABASE_RECORD_FROM_LINK (DispatchHandle); >=20 > + if (!EFI_ERROR (Status)) { >=20 > + SmiHandlerProfileUnregisterHandler > (&gPchEspiSmiDispatchProtocolGuid, RecordToDelete->Callback, NULL, 0); >=20 > + } >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > + >=20 > +/** >=20 > + Returns AND maks for clearing eSPI channel registers errors statuses >=20 > + In addition to common status bit we add channel specific erro bits to = avoid > clearing them >=20 > + >=20 > + @param[in] ChannelNumber Channel number (0 for PC, 1 for VW= , 2 > for OOB, 3 for FA) >=20 > + >=20 > + @retval UINT32 AND mask with all the status bit m= asked to not > clear them by mistake >=20 > +**/ >=20 > +UINT32 >=20 > +GetEspiChannelStatusClearMask ( >=20 > + UINT8 ChannelNumber >=20 > + ) >=20 > +{ >=20 > + UINT32 Data32; >=20 > + >=20 > + // Common error status bits for all channel registers >=20 > + Data32 =3D B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES; >=20 > + >=20 > + // Check channels for channel specific status bits >=20 > + switch(ChannelNumber) { >=20 > + case 0: // Peripheral Channel specific status bits >=20 > + Data32 |=3D B_ESPI_PCR_PCERR_PCURD; >=20 > + break; >=20 > + case 3: // Flash Access Channel specific status bits >=20 > + Data32 |=3D B_ESPI_PCR_FCERR_SAFBLK; >=20 > + break; >=20 > + } >=20 > + >=20 > + // Return the expected AND mask >=20 > + return (UINT32)~(Data32); >=20 > +} >=20 > + >=20 > +/** >=20 > + Checks if channel error register data has Fatal Error bit set >=20 > + If yes then reset the channel on slave >=20 > + >=20 > + @param[in] ChannelBaseAddress Base address >=20 > + @param[in] ChannelNumber Channel number (0 for PC, 1 for VW= , 2 > for OOB, 3 for FA) >=20 > + @param[in] SlaveId Slave ID of which channel is to be= reset >=20 > +**/ >=20 > +VOID >=20 > +CheckSlaveChannelErrorAndReset ( >=20 > + UINT16 ChannelBaseAddress, >=20 > + UINT8 ChannelNumber, >=20 > + UINT8 SlaveId >=20 > + ) >=20 > +{ >=20 > + UINT32 Data32; >=20 > + UINT16 ChannelAddress; >=20 > + EFI_STATUS Status; >=20 > + >=20 > + if (ChannelNumber =3D=3D 2) { >=20 > + DEBUG ((DEBUG_INFO, "Channel %d is not supported by this function > due to lack of error register\n", ChannelNumber)); >=20 > + return; >=20 > + } >=20 > + >=20 > + if (!IsEspiSlaveChannelSupported (SlaveId, ChannelNumber)) { >=20 > + DEBUG ((DEBUG_WARN, "Channel %d is not supported by slave > device\n", ChannelNumber)); >=20 > + return; >=20 > + } >=20 > + >=20 > + // Calculate channel address based on slave id >=20 > + ChannelAddress =3D (UINT16) (ChannelBaseAddress + (SlaveId * > S_ESPI_PCR_XERR)); >=20 > + >=20 > + // Reading channel error register data >=20 > + Data32 =3D PchPcrRead32 (PID_ESPISPI, ChannelAddress); >=20 > + >=20 > + DEBUG ((DEBUG_INFO, "eSPI channel error register (0x%4X) has value > 0x%8X\n", ChannelAddress, Data32)); >=20 > + >=20 > + // Check Fatal Error status bit in channel error register data >=20 > + if ((Data32 & B_ESPI_PCR_XERR_XFES) !=3D 0) { >=20 > + Status =3D PchEspiSlaveChannelReset (SlaveId, ChannelNumber); >=20 > + >=20 > + if (EFI_ERROR (Status)) { >=20 > + switch (Status) { >=20 > + case EFI_UNSUPPORTED: >=20 > + DEBUG ((DEBUG_ERROR, "Slave doesn't support channel %d\n", > ChannelNumber)); >=20 > + break; >=20 > + case EFI_TIMEOUT: >=20 > + DEBUG ((DEBUG_ERROR, "Timeout occured during channel %d reset > on slave %d\n", ChannelNumber, SlaveId)); >=20 > + break; >=20 > + default: >=20 > + DEBUG ((DEBUG_ERROR, "Error occured during channel %d reset\n"= , > ChannelNumber)); >=20 > + break; >=20 > + } >=20 > + } else { >=20 > + DEBUG ((DEBUG_INFO, "eSPI Slave %d channel %d reset ended > successfully\n", SlaveId, ChannelNumber)); >=20 > + // If channel reset was successfull clear the fatal error flag by = writing one >=20 > + // we should be aware not to clear other status bits by mistake an= d mask > them >=20 > + PchPcrAndThenOr32 ( >=20 > + PID_ESPISPI, >=20 > + ChannelAddress, >=20 > + GetEspiChannelStatusClearMask (ChannelNumber), >=20 > + B_ESPI_PCR_XERR_XFES >=20 > + ); >=20 > + } >=20 > + } >=20 > +} >=20 > + >=20 > +/** >=20 > + eSPI SMI handler for Fatal Error recovery flow >=20 > +**/ >=20 > +VOID >=20 > +EspiDefaultFatalErrorHandler ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + UINT32 Data32; >=20 > + UINT8 SlaveId; >=20 > + UINT8 MaxSlavesCount; >=20 > + >=20 > + DEBUG ((DEBUG_INFO, "[EspiRecoverFromFatalError] Enter\n")); >=20 > + >=20 > + MaxSlavesCount =3D IsEspiSecondSlaveSupported () ? 2 : 1; >=20 > + >=20 > + DEBUG ((DEBUG_INFO, "[EspiRecoverFromFatalError] MaxSlavesCount > %d\n", MaxSlavesCount)); >=20 > + >=20 > + for (SlaveId =3D 0; SlaveId < MaxSlavesCount; ++SlaveId) { >=20 > + // >=20 > + // Check if slave has SLCRR bit set. If it does it means it needs re= covery. >=20 > + // >=20 > + Data32 =3D PchPcrRead32 (PID_ESPISPI, (UINT16) > (R_ESPI_PCR_LNKERR_SLV0 + (SlaveId * S_ESPI_PCR_XERR))); >=20 > + >=20 > + DEBUG ((DEBUG_INFO, "[EspiRecoverFromFatalError] Slave %d LNKERR > reg 0x%8X\n", SlaveId, Data32)); >=20 > + // >=20 > + // If SLCRR[31] bit is set we need to recover that slave >=20 > + // >=20 > + if ((Data32 & B_ESPI_PCR_LNKERR_SLV0_SLCRR) !=3D 0) { >=20 > + // 1. Perform in-band reset >=20 > + PchEspiSlaveInBandReset (SlaveId); >=20 > + >=20 > + // 2. Channels reset >=20 > + CheckSlaveChannelErrorAndReset (R_ESPI_PCR_PCERR_SLV0, 0, > SlaveId); // Peripheral channel reset >=20 > + CheckSlaveChannelErrorAndReset (R_ESPI_PCR_VWERR_SLV0, 1, > SlaveId); // Virtual Wire channel reset >=20 > + >=20 > + // Flash Access channel is not supported for CS1# >=20 > + if (SlaveId =3D=3D 0) { >=20 > + CheckSlaveChannelErrorAndReset (R_ESPI_PCR_PCERR_SLV0, 3, > SlaveId); // Flash Access channel reset >=20 > + } >=20 > + >=20 > + // Clear SLCRR bit of slave after all channels recovery was done >=20 > + PchPcrAndThenOr32 ( >=20 > + PID_ESPISPI, >=20 > + (UINT16) (R_ESPI_PCR_LNKERR_SLV0 + (SlaveId * S_ESPI_PCR_XERR)), >=20 > + (UINT32)~(B_ESPI_PCR_LNKERR_SLV0_LFET1S), >=20 > + (UINT32) (B_ESPI_PCR_LNKERR_SLV0_SLCRR) >=20 > + ); >=20 > + } >=20 > + } >=20 > + >=20 > + DEBUG ((DEBUG_INFO, "[EspiRecoverFromFatalError] Exit\n")); >=20 > +} >=20 > + >=20 > + >=20 > diff --git > a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEspi > .h > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEspi > .h > new file mode 100644 > index 0000000000..4903464fae > --- /dev/null > +++ > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEspi > .h > @@ -0,0 +1,341 @@ > +/** @file >=20 > + eSPI SMI Dispatch header >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > + >=20 > +#ifndef _PCH_SMM_ESPI_H_ >=20 > +#define _PCH_SMM_ESPI_H_ >=20 > + >=20 > +#include "PchSmmHelpers.h" >=20 > + >=20 > +#define ESPI_SMI_INSTANCE_SIGNATURE SIGNATURE_32 ('E', 'S', 'P', '= I') >=20 > +#define ESPI_SMI_RECORD_SIGNATURE SIGNATURE_32 ('E', 'S', 'R', '= C') >=20 > + >=20 > +#define ESPI_INSTANCE_FROM_THIS(_this) CR (_this, > ESPI_SMI_INSTANCE, EfiEspiSmiDispatchProtocol, > ESPI_SMI_INSTANCE_SIGNATURE) >=20 > +#define ESPI_RECORD_FROM_LINK(_link) CR (_link, ESPI_SMI_RECORD, > Link, ESPI_SMI_RECORD_SIGNATURE) >=20 > + >=20 > +typedef enum { >=20 > + EspiBiosWrProtect, ///< BIOS Write Protect >=20 > + EspiSerialIrq, ///< eSPI Master Asserted SMI >=20 > + EspiPmc, ///< eSPI PMC SMI >=20 > + EspiTopLevelTypeMax >=20 > +} ESPI_TOP_LEVEL_TYPE; >=20 > + >=20 > +typedef enum { >=20 > + BiosWrProtect, ///< BIOS Write Protect >=20 > + BiosWrReport, ///< Peripheral Channel BIOS Write Protect >=20 > + PcNonFatalErr, ///< Peripheral Channel Non Fatal Error >=20 > + PcFatalErr, ///< Peripheral Channel Fatal Error >=20 > + VwNonFatalErr, ///< Virtual Wire Non Fatal Error >=20 > + VwFatalErr, ///< Virtual Wire Fatal Error >=20 > + FlashNonFatalErr, ///< Flash Channel Non Fatal Error >=20 > + FlashFatalErr, ///< Flash Channel Fatal Error >=20 > + LnkType1Err, ///< Link Error >=20 > + EspiSlaveSmi, ///< Espi Slave SMI >=20 > + EspiSmiTypeMax >=20 > +} ESPI_SMI_TYPE; >=20 > + >=20 > +/// >=20 > +/// This is used to classify ESPI_SMI_TYPE to ESPI_TOP_LEVEL_TYPE. >=20 > +/// Used during dispatching and unregistering >=20 > +/// >=20 > +typedef struct { >=20 > + ESPI_SMI_TYPE Start; >=20 > + ESPI_SMI_TYPE End; >=20 > +} ESPI_SMI_TYPE_BARRIER; >=20 > + >=20 > +typedef struct _ESPI_SMI_INSTANCE { >=20 > + /// >=20 > + /// Signature associated with this instance >=20 > + /// >=20 > + UINT32 Signature; >=20 > + /// >=20 > + /// EFI_HANDLE acquired when installing PchEspiSmiDispatchProtocol >=20 > + /// >=20 > + EFI_HANDLE Handle; >=20 > + /// >=20 > + /// The protocol to register or unregister eSPI SMI callbacks >=20 > + /// >=20 > + PCH_ESPI_SMI_DISPATCH_PROTOCOL PchEspiSmiDispatchProtocol; >=20 > + /// >=20 > + /// The handle acquired when registering eSPI SMI callback to > PchSmiDispatch >=20 > + /// >=20 > + EFI_HANDLE PchSmiEspiHandle[EspiTopLevelTypeMax]; >=20 > + /// >=20 > + /// The linked list for record database. >=20 > + /// >=20 > + LIST_ENTRY CallbackDataBase[EspiSmiTypeMax]; >=20 > + /// >=20 > + /// This is an internal counter to track the number of eSPI master eve= nts > have been registered. >=20 > + /// When unregistering, we can disable the SMI if the counter is zero >=20 > + /// >=20 > + UINTN EspiSmiEventCounter[EspiSmiTypeMax]; >=20 > + /// >=20 > + /// Instance of barrier >=20 > + /// >=20 > + CONST ESPI_SMI_TYPE_BARRIER Barrier[EspiTopLevelTypeMax]; >=20 > +} ESPI_SMI_INSTANCE; >=20 > + >=20 > +typedef struct _ESPI_DESCRIPTOR { >=20 > + PCH_SMM_ADDRESS Address; >=20 > + UINT32 SourceIsActiveAndMask; >=20 > + UINT32 SourceIsActiveValue; >=20 > + UINT32 ClearStatusAndMask; >=20 > + UINT32 ClearStatusOrMask; >=20 > +} ESPI_DESCRIPTOR; >=20 > + >=20 > +/// >=20 > +/// A simple record to store the callbacks associated with an eSPI SMI > source >=20 > +/// >=20 > +typedef struct _ESPI_SMI_RECORD { >=20 > + UINT32 Signature; >=20 > + LIST_ENTRY Link; >=20 > + PCH_ESPI_SMI_DISPATCH_CALLBACK Callback; >=20 > +} ESPI_SMI_RECORD; >=20 > + >=20 > +/** >=20 > + Installs and initialize this protocol >=20 > + >=20 > + @param[in] ImageHandle Not used >=20 > + >=20 > + @retval EFI_SUCCESS Installation succeed >=20 > + @retval others Installation failed >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +InstallEspiSmi ( >=20 > + IN EFI_HANDLE ImageHandle >=20 > + ); >=20 > + >=20 > +/** >=20 > + eSPI SMI Dispatch Protocol instance to register a BIOS Write Protect e= vent >=20 > + >=20 > + @param[in] This Not used >=20 > + @param[in] DispatchFunction The callback to execute >=20 > + @param[out] DispatchHandle The handle for this callback registratio= n >=20 > + >=20 > + @retval EFI_SUCCESS Registration succeed >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > + @retval others Registration failed >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +BiosWrProtectRegister ( >=20 > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ); >=20 > + >=20 > +/** >=20 > + eSPI SMI Dispatch Protocol instance to register a BIOS Write Report ev= ent >=20 > + >=20 > + @param[in] This Not used >=20 > + @param[in] DispatchFunction The callback to execute >=20 > + @param[out] DispatchHandle The handle for this callback registratio= n >=20 > + >=20 > + @retval EFI_SUCCESS Registration succeed >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > + @retval others Registration failed >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +BiosWrReportRegister ( >=20 > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ); >=20 > + >=20 > +/** >=20 > + eSPI SMI Dispatch Protocol instance to register a Peripheral Channel N= on > Fatal Error event >=20 > + >=20 > + @param[in] This Not used >=20 > + @param[in] DispatchFunction The callback to execute >=20 > + @param[out] DispatchHandle The handle for this callback registratio= n >=20 > + >=20 > + @retval EFI_SUCCESS Registration succeed >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > + @retval others Registration failed >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PcNonFatalErrRegister ( >=20 > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ); >=20 > + >=20 > +/** >=20 > + eSPI SMI Dispatch Protocol instance to register a Peripheral Channel F= atal > Error event >=20 > + >=20 > + @param[in] This Not used >=20 > + @param[in] DispatchFunction The callback to execute >=20 > + @param[out] DispatchHandle The handle for this callback registratio= n >=20 > + >=20 > + @retval EFI_SUCCESS Registration succeed >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > + @retval others Registration failed >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PcFatalErrRegister ( >=20 > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ); >=20 > + >=20 > +/** >=20 > + eSPI SMI Dispatch Protocol instance to register a Virtual Wire Non Fat= al > Error event >=20 > + >=20 > + @param[in] This Not used >=20 > + @param[in] DispatchFunction The callback to execute >=20 > + @param[out] DispatchHandle The handle for this callback registratio= n >=20 > + >=20 > + @retval EFI_SUCCESS Registration succeed >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > + @retval others Registration failed >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +VwNonFatalErrRegister ( >=20 > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ); >=20 > + >=20 > +/** >=20 > + eSPI SMI Dispatch Protocol instance to register a Virtual Wire Fatal E= rror > event >=20 > + >=20 > + @param[in] This Not used >=20 > + @param[in] DispatchFunction The callback to execute >=20 > + @param[out] DispatchHandle The handle for this callback registratio= n >=20 > + >=20 > + @retval EFI_SUCCESS Registration succeed >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > + @retval others Registration failed >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +VwFatalErrRegister ( >=20 > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ); >=20 > + >=20 > +/** >=20 > + eSPI SMI Dispatch Protocol instance to register a Flash Channel Non Fa= tal > Error event >=20 > + >=20 > + @param[in] This Not used >=20 > + @param[in] DispatchFunction The callback to execute >=20 > + @param[out] DispatchHandle The handle for this callback registratio= n >=20 > + >=20 > + @retval EFI_SUCCESS Registration succeed >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > + @retval others Registration failed >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +FlashNonFatalErrRegister ( >=20 > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ); >=20 > + >=20 > +/** >=20 > + eSPI SMI Dispatch Protocol instance to register a Flash Channel Fatal = Error > event >=20 > + >=20 > + @param[in] This Not used >=20 > + @param[in] DispatchFunction The callback to execute >=20 > + @param[out] DispatchHandle The handle for this callback registratio= n >=20 > + >=20 > + @retval EFI_SUCCESS Registration succeed >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > + @retval others Registration failed >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +FlashFatalErrRegister ( >=20 > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ); >=20 > + >=20 > +/** >=20 > + eSPI SMI Dispatch Protocol instance to register a Link Error event >=20 > + >=20 > + @param[in] This Not used >=20 > + @param[in] DispatchFunction The callback to execute >=20 > + @param[out] DispatchHandle The handle for this callback registratio= n >=20 > + >=20 > + @retval EFI_SUCCESS Registration succeed >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > + @retval others Registration failed >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +LnkType1ErrRegister ( >=20 > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ); >=20 > + >=20 > +/** >=20 > + eSPI SMI Dispatch Protocol instance to register a eSPI slave SMI >=20 > + NOTE: The register function is not available when the ESPI_SMI_LOCK bi= t is > set. >=20 > + This runtine will also lock donw ESPI_SMI_LOCK bit after registr= ation > and >=20 > + prevent this handler from unregistration. >=20 > + On platform that supports more than 1 device through another chip sele= ct > (SPT-H), >=20 > + the SMI handler itself needs to inspect both the eSPI devices' interru= pt > status registers >=20 > + (implementation specific for each Slave) in order to identify and serv= ice > the cause. >=20 > + After servicing it, it has to clear the Slaves' internal SMI# status r= egisters >=20 > + >=20 > + @param[in] This Not used >=20 > + @param[in] DispatchFunction The callback to execute >=20 > + @param[out] DispatchHandle The handle for this callback reg= istration >=20 > + >=20 > + @retval EFI_SUCCESS Registration succeed >=20 > + @retval EFI_ACCESS_DENIED Return access denied if the > SmmReadyToLock event has been triggered >=20 > + @retval EFI_ACCESS_DENIED The ESPI_SMI_LOCK is set and reg= ister > is blocked. >=20 > + @retval others Registration failed >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +EspiSlaveSmiRegister ( >=20 > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ); >=20 > + >=20 > +/** >=20 > + eSPI SMI Dispatch Protocol instance to unregister a callback based on > handle >=20 > + >=20 > + @param[in] This Not used >=20 > + @param[in] DispatchHandle Handle acquired during registratio= n >=20 > + >=20 > + @retval EFI_SUCCESS Unregister successful >=20 > + @retval EFI_INVALID_PARAMETER DispatchHandle is null >=20 > + @retval EFI_INVALID_PARAMETER DispatchHandle's forward link has > bad pointer >=20 > + @retval EFI_INVALID_PARAMETER DispatchHandle does not exist in > database >=20 > + @retval EFI_ACCESS_DENIED Unregistration is done after end o= f DXE >=20 > + @retval EFI_ACCESS_DENIED DispatchHandle is not allowed to > unregistered >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +EspiSmiUnRegister ( >=20 > + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This, >=20 > + IN EFI_HANDLE DispatchHandle >=20 > + ); >=20 > + >=20 > +/** >=20 > + eSPI SMI handler for Fatal Error recovery flow >=20 > + >=20 > + @param[in] DispatchHandle Handle acquired during registratio= n >=20 > +**/ >=20 > +VOID >=20 > +EspiDefaultFatalErrorHandler ( >=20 > + VOID >=20 > + ); >=20 > + >=20 > + >=20 > +#endif >=20 > diff --git > a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmGpi. > c > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmGpi > .c > new file mode 100644 > index 0000000000..61f925c860 > --- /dev/null > +++ > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmGpi > .c > @@ -0,0 +1,263 @@ > +/** @file >=20 > + File to contain all the hardware specific stuff for the Smm Gpi dispat= ch > protocol. >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > +#include "PchSmm.h" >=20 > +#include "PchSmmHelpers.h" >=20 > +#include >=20 > +#include >=20 > +#include >=20 > + >=20 > +// >=20 > +// Structure for GPI SMI is a template which needs to have >=20 > +// GPI Smi bit offset and Smi Status & Enable registers updated (accordi= ngly >=20 > +// to choosen group and pad number) after adding it to SMM Callback > database >=20 > +// >=20 > + >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mPchGpiSourceDescTemplate =3D { >=20 > + PCH_SMM_NO_FLAGS, >=20 > + { >=20 > + NULL_BIT_DESC_INITIALIZER, >=20 > + NULL_BIT_DESC_INITIALIZER >=20 > + }, >=20 > + { >=20 > + { >=20 > + { >=20 > + GPIO_ADDR_TYPE, {0x0} >=20 > + }, >=20 > + S_GPIO_PCR_GP_SMI_STS, 0x0, >=20 > + } >=20 > + }, >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_GPIO_SMI >=20 > + } >=20 > +}; >=20 > + >=20 > +/** >=20 > + The register function used to register SMI handler of GPI SMI event. >=20 > + >=20 > + @param[in] This Pointer to the > EFI_SMM_GPI_DISPATCH2_PROTOCOL instance. >=20 > + @param[in] DispatchFunction Function to register for handler when t= he > specified GPI causes an SMI. >=20 > + @param[in] RegisterContext Pointer to the dispatch function's cont= ext. >=20 > + The caller fills this context in before= calling >=20 > + the register function to indicate to th= e register >=20 > + function the GPI(s) for which the dispa= tch function >=20 > + should be invoked. >=20 > + @param[out] DispatchHandle Handle generated by the dispatcher to > track the >=20 > + function instance. >=20 > + >=20 > + @retval EFI_SUCCESS The dispatch function has been successf= ully >=20 > + registered and the SMI source has been = enabled. >=20 > + @retval EFI_ACCESS_DENIED Register is not allowed >=20 > + @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The GPI > input value >=20 > + is not within valid range. >=20 > + @retval EFI_OUT_OF_RESOURCES There is not enough memory (system > or SMM) to manage this child. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchGpiSmiRegister ( >=20 > + IN CONST EFI_SMM_GPI_DISPATCH2_PROTOCOL *This, >=20 > + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, >=20 > + IN EFI_SMM_GPI_REGISTER_CONTEXT *RegisterContext, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + DATABASE_RECORD Record; >=20 > + GPIO_PAD GpioPad; >=20 > + UINT8 GpiSmiBitOffset; >=20 > + UINT32 GpiHostSwOwnRegAddress; >=20 > + UINT32 GpiSmiStsRegAddress; >=20 > + UINT32 Data32Or; >=20 > + UINT32 Data32And; >=20 > + >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the EndOfDxe event > has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + Status =3D GpioGetPadAndSmiRegs ( >=20 > + (UINT32) RegisterContext->GpiNum, >=20 > + &GpioPad, >=20 > + &GpiSmiBitOffset, >=20 > + &GpiHostSwOwnRegAddress, >=20 > + &GpiSmiStsRegAddress >=20 > + ); >=20 > + >=20 > + if (EFI_ERROR (Status)) { >=20 > + return Status; >=20 > + } >=20 > + >=20 > + ZeroMem (&Record, sizeof (DATABASE_RECORD)); >=20 > + >=20 > + // >=20 > + // Gather information about the registration request >=20 > + // >=20 > + Record.Callback =3D DispatchFunction; >=20 > + Record.ChildContext.Gpi =3D *RegisterContext; >=20 > + Record.ProtocolType =3D GpiType; >=20 > + Record.Signature =3D DATABASE_RECORD_SIGNATURE; >=20 > + >=20 > + CopyMem (&Record.SrcDesc, &mPchGpiSourceDescTemplate, sizeof > (PCH_SMM_SOURCE_DESC) ); >=20 > + >=20 > + Record.SrcDesc.Sts[0].Reg.Data.raw =3D GpiSmiStsRegAddress; // GPI SM= I > Status register >=20 > + Record.SrcDesc.Sts[0].Bit =3D GpiSmiBitOffset; // Bit po= sition for > selected pad >=20 > + >=20 > + // >=20 > + // Insert GpiSmi handler to PchSmmCore database >=20 > + // >=20 > + *DispatchHandle =3D NULL; >=20 > + >=20 > + Status =3D SmmCoreInsertRecord ( >=20 > + &Record, >=20 > + DispatchHandle >=20 > + ); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + SmiHandlerProfileRegisterHandler ( >=20 > + &gEfiSmmGpiDispatch2ProtocolGuid, >=20 > + (EFI_SMM_HANDLER_ENTRY_POINT2) DispatchFunction, >=20 > + (UINTN)RETURN_ADDRESS (0), >=20 > + RegisterContext, >=20 > + sizeof(*RegisterContext) >=20 > + ); >=20 > + >=20 > + // >=20 > + // Enable GPI SMI >=20 > + // HOSTSW_OWN with respect to generating GPI SMI has negative logic: >=20 > + // - 0 (ACPI mode) - GPIO pad will be capable of generating SMI/NMI/S= CI >=20 > + // - 1 (GPIO mode) - GPIO pad will not generate SMI/NMI/SCI >=20 > + // >=20 > + Data32And =3D (UINT32)~(1u << GpiSmiBitOffset); >=20 > + MmioAnd32 (GpiHostSwOwnRegAddress, Data32And); >=20 > + >=20 > + // >=20 > + // Add HOSTSW_OWN programming into S3 boot script >=20 > + // >=20 > + Data32Or =3D 0; >=20 > + S3BootScriptSaveMemReadWrite (S3BootScriptWidthUint32, > GpiHostSwOwnRegAddress, &Data32Or, &Data32And); >=20 > + >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > + >=20 > +/** >=20 > + Unregister a GPI SMI source dispatch function with a parent SMM driver >=20 > + >=20 > + @param[in] This Pointer to the > EFI_SMM_GPI_DISPATCH2_PROTOCOL instance. >=20 > + @param[in] DispatchHandle Handle of dispatch function to deregis= ter. >=20 > + >=20 > + @retval EFI_SUCCESS The dispatch function has been success= fully >=20 > + unregistered and the SMI source has be= en disabled >=20 > + if there are no other registered child= dispatch >=20 > + functions for this SMI source. >=20 > + @retval EFI_INVALID_PARAMETER Handle is invalid. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchGpiSmiUnRegister ( >=20 > + IN CONST EFI_SMM_GPI_DISPATCH2_PROTOCOL *This, >=20 > + IN EFI_HANDLE DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + DATABASE_RECORD *RecordToDelete; >=20 > + DATABASE_RECORD *RecordInDb; >=20 > + LIST_ENTRY *LinkInDb; >=20 > + GPIO_PAD GpioPad; >=20 > + UINT8 GpiSmiBitOffset; >=20 > + UINT32 GpiHostSwOwnRegAddress; >=20 > + UINT32 GpiSmiStsRegAddress; >=20 > + UINT32 Data32Or; >=20 > + UINT32 Data32And; >=20 > + BOOLEAN DisableGpiSmiSource; >=20 > + >=20 > + >=20 > + if (DispatchHandle =3D=3D NULL) { >=20 > + return EFI_INVALID_PARAMETER; >=20 > + } >=20 > + >=20 > + RecordToDelete =3D DATABASE_RECORD_FROM_LINK (DispatchHandle); >=20 > + if ((RecordToDelete->Signature !=3D DATABASE_RECORD_SIGNATURE) || >=20 > + (RecordToDelete->ProtocolType !=3D GpiType)) { >=20 > + return EFI_INVALID_PARAMETER; >=20 > + } >=20 > + >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the > SmmReadyToLock event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + DisableGpiSmiSource =3D TRUE; >=20 > + // >=20 > + // Loop through all sources in record linked list to see if any other = GPI SMI >=20 > + // is installed on the same pin. If no then disable GPI SMI capability= on this > pad >=20 > + // >=20 > + LinkInDb =3D GetFirstNode (&mPrivateData.CallbackDataBase); >=20 > + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { >=20 > + RecordInDb =3D DATABASE_RECORD_FROM_LINK (LinkInDb); >=20 > + LinkInDb =3D GetNextNode (&mPrivateData.CallbackDataBase, > &RecordInDb->Link); >=20 > + // >=20 > + // If this is the record to delete skip it >=20 > + // >=20 > + if (RecordInDb =3D=3D RecordToDelete) { >=20 > + continue; >=20 > + } >=20 > + // >=20 > + // Check if record is GPI SMI type >=20 > + // >=20 > + if (RecordInDb->ProtocolType =3D=3D GpiType) { >=20 > + // >=20 > + // Check if same GPIO pad is the source of this SMI >=20 > + // >=20 > + if (RecordInDb->ChildContext.Gpi.GpiNum =3D=3D RecordToDelete- > >ChildContext.Gpi.GpiNum) { >=20 > + DisableGpiSmiSource =3D FALSE; >=20 > + break; >=20 > + } >=20 > + } >=20 > + } >=20 > + >=20 > + if (DisableGpiSmiSource) { >=20 > + GpioGetPadAndSmiRegs ( >=20 > + (UINT32) RecordToDelete->ChildContext.Gpi.GpiNum, >=20 > + &GpioPad, >=20 > + &GpiSmiBitOffset, >=20 > + &GpiHostSwOwnRegAddress, >=20 > + &GpiSmiStsRegAddress >=20 > + ); >=20 > + >=20 > + Data32Or =3D 1u << GpiSmiBitOffset; >=20 > + Data32And =3D 0xFFFFFFFF; >=20 > + MmioOr32 (GpiHostSwOwnRegAddress, Data32Or); >=20 > + S3BootScriptSaveMemReadWrite (S3BootScriptWidthUint32, > GpiHostSwOwnRegAddress, &Data32Or, &Data32And); >=20 > + } >=20 > + >=20 > + >=20 > + RemoveEntryList (&RecordToDelete->Link); >=20 > + ZeroMem (RecordToDelete, sizeof (DATABASE_RECORD)); >=20 > + Status =3D gSmst->SmmFreePool (RecordToDelete); >=20 > + >=20 > + if (EFI_ERROR (Status)) { >=20 > + ASSERT (FALSE); >=20 > + return Status; >=20 > + } >=20 > + SmiHandlerProfileUnregisterHandler ( >=20 > + &gEfiSmmGpiDispatch2ProtocolGuid, >=20 > + RecordToDelete->Callback, >=20 > + &RecordToDelete->ChildContext, >=20 > + RecordToDelete->ContextSize >=20 > + ); >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > diff --git > a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHel > pers.c > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHel > pers.c > new file mode 100644 > index 0000000000..6bbf9ea8e8 > --- /dev/null > +++ > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHel > pers.c > @@ -0,0 +1,332 @@ > +/** @file >=20 > + Helper functions for PCH SMM dispatcher. >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > +#include "PchSmmHelpers.h" >=20 > +#include >=20 > + >=20 > +/// >=20 > +/// #define BIT_ZERO 0x00000001 >=20 > +/// >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED CONST UINT32 BIT_ZERO =3D > 0x00000001; >=20 > + >=20 > +/// >=20 > +/// SUPPORT / HELPER FUNCTIONS (PCH version-independent) >=20 > +/// >=20 > + >=20 > +/** >=20 > + Compare 2 SMM source descriptors' enable settings. >=20 > + >=20 > + @param[in] Src1 Pointer to the PCH SMI source descript= ion table 1 >=20 > + @param[in] Src2 Pointer to the PCH SMI source descript= ion table 2 >=20 > + >=20 > + @retval TRUE The enable settings of the 2 SMM sourc= e > descriptors are identical. >=20 > + @retval FALSE The enable settings of the 2 SMM sourc= e > descriptors are not identical. >=20 > +**/ >=20 > +BOOLEAN >=20 > +CompareEnables ( >=20 > + CONST IN PCH_SMM_SOURCE_DESC *Src1, >=20 > + CONST IN PCH_SMM_SOURCE_DESC *Src2 >=20 > + ) >=20 > +{ >=20 > + BOOLEAN IsEqual; >=20 > + UINTN DescIndex; >=20 > + >=20 > + IsEqual =3D TRUE; >=20 > + for (DescIndex =3D 0; DescIndex < NUM_EN_BITS; DescIndex++) { >=20 > + /// >=20 > + /// It's okay to compare a NULL bit description to a non-NULL bit > description. >=20 > + /// They are unequal and these tests will generate the correct resul= t. >=20 > + /// >=20 > + if (Src1->En[DescIndex].Bit !=3D Src2->En[DescIndex].Bit || >=20 > + Src1->En[DescIndex].Reg.Type !=3D Src2->En[DescIndex].Reg.Type |= | >=20 > + Src1->En[DescIndex].Reg.Data.raw !=3D Src2- > >En[DescIndex].Reg.Data.raw >=20 > + ) { >=20 > + IsEqual =3D FALSE; >=20 > + break; >=20 > + /// >=20 > + /// out of for loop >=20 > + /// >=20 > + } >=20 > + } >=20 > + >=20 > + return IsEqual; >=20 > +} >=20 > + >=20 > +/** >=20 > + Compare a bit descriptor to the enables of source descriptor. Includes= null > address type. >=20 > + >=20 > + @param[in] BitDesc Pointer to the PCH SMI bit descriptor >=20 > + @param[in] Src Pointer to the PCH SMI source descript= ion table 2 >=20 > + >=20 > + @retval TRUE The bit desc is equal to any of the en= ables in source > descriptor >=20 > + @retval FALSE The bid desc is not equal to all of th= e enables in > source descriptor >=20 > +**/ >=20 > +BOOLEAN >=20 > +IsBitEqualToAnySourceEn ( >=20 > + CONST IN PCH_SMM_BIT_DESC *BitDesc, >=20 > + CONST IN PCH_SMM_SOURCE_DESC *Src >=20 > + ) >=20 > +{ >=20 > + BOOLEAN IsEqual; >=20 > + UINTN DescIndex; >=20 > + >=20 > + IsEqual =3D FALSE; >=20 > + >=20 > + for (DescIndex =3D 0; DescIndex < NUM_EN_BITS; ++DescIndex) { >=20 > + if ((BitDesc->Reg.Type =3D=3D Src->En[DescIndex].Reg.Type) && >=20 > + (BitDesc->Reg.Data.raw =3D=3D Src->En[DescIndex].Reg.Data.raw) &= & >=20 > + (BitDesc->Bit =3D=3D Src->En[DescIndex].Bit)) { >=20 > + IsEqual =3D TRUE; >=20 > + break; >=20 > + } >=20 > + } >=20 > + return IsEqual; >=20 > +} >=20 > + >=20 > +/** >=20 > + Compare 2 SMM source descriptors' statuses. >=20 > + >=20 > + @param[in] Src1 Pointer to the PCH SMI source descript= ion table 1 >=20 > + @param[in] Src2 Pointer to the PCH SMI source descript= ion table 2 >=20 > + >=20 > + @retval TRUE The statuses of the 2 SMM source descr= iptors are > identical. >=20 > + @retval FALSE The statuses of the 2 SMM source descr= iptors are > not identical. >=20 > +**/ >=20 > +BOOLEAN >=20 > +CompareStatuses ( >=20 > + CONST IN PCH_SMM_SOURCE_DESC *Src1, >=20 > + CONST IN PCH_SMM_SOURCE_DESC *Src2 >=20 > + ) >=20 > +{ >=20 > + BOOLEAN IsEqual; >=20 > + UINTN DescIndex; >=20 > + >=20 > + IsEqual =3D TRUE; >=20 > + >=20 > + for (DescIndex =3D 0; DescIndex < NUM_STS_BITS; DescIndex++) { >=20 > + /// >=20 > + /// It's okay to compare a NULL bit description to a non-NULL bit > description. >=20 > + /// They are unequal and these tests will generate the correct resul= t. >=20 > + /// >=20 > + if (Src1->Sts[DescIndex].Bit !=3D Src2->Sts[DescIndex].Bit || >=20 > + Src1->Sts[DescIndex].Reg.Type !=3D Src2->Sts[DescIndex].Reg.Type= || >=20 > + Src1->Sts[DescIndex].Reg.Data.raw !=3D Src2- > >Sts[DescIndex].Reg.Data.raw >=20 > + ) { >=20 > + IsEqual =3D FALSE; >=20 > + break; >=20 > + /// >=20 > + /// out of for loop >=20 > + /// >=20 > + } >=20 > + } >=20 > + >=20 > + return IsEqual; >=20 > +} >=20 > + >=20 > +/** >=20 > + Compare 2 SMM source descriptors, based on Enable settings and Status > settings of them. >=20 > + >=20 > + @param[in] Src1 Pointer to the PCH SMI source descript= ion table 1 >=20 > + @param[in] Src2 Pointer to the PCH SMI source descript= ion table 2 >=20 > + >=20 > + @retval TRUE The 2 SMM source descriptors are ident= ical. >=20 > + @retval FALSE The 2 SMM source descriptors are not i= dentical. >=20 > +**/ >=20 > +BOOLEAN >=20 > +CompareSources ( >=20 > + CONST IN PCH_SMM_SOURCE_DESC *Src1, >=20 > + CONST IN PCH_SMM_SOURCE_DESC *Src2 >=20 > + ) >=20 > +{ >=20 > + return (BOOLEAN) (CompareEnables (Src1, Src2) && CompareStatuses > (Src1, Src2)); >=20 > +} >=20 > + >=20 > +/** >=20 > + Check if an SMM source is active. >=20 > + >=20 > + @param[in] Src Pointer to the PCH SMI source descript= ion table >=20 > + @param[in] SciEn Indicate if SCI is enabled or not >=20 > + @param[in] SmiEnValue Value from R_ACPI_IO_SMI_EN >=20 > + @param[in] SmiStsValue Value from R_ACPI_IO_SMI_STS >=20 > + >=20 > + @retval TRUE It is active. >=20 > + @retval FALSE It is inactive. >=20 > +**/ >=20 > +BOOLEAN >=20 > +SourceIsActive ( >=20 > + CONST IN PCH_SMM_SOURCE_DESC *Src, >=20 > + CONST IN BOOLEAN SciEn, >=20 > + CONST IN UINT32 SmiEnValue, >=20 > + CONST IN UINT32 SmiStsValue >=20 > + ) >=20 > +{ >=20 > + UINTN DescIndex; >=20 > + >=20 > + /// >=20 > + /// This source is dependent on SciEn, and SciEn =3D=3D 1. An ACPI OS= is > present, >=20 > + /// so we shouldn't do anything w/ this source until SciEn =3D=3D 0. >=20 > + /// >=20 > + if ((Src->Flags =3D=3D PCH_SMM_SCI_EN_DEPENDENT) && (SciEn)) { >=20 > + return FALSE; >=20 > + } >=20 > + >=20 > + /// >=20 > + /// Checking top level SMI status. If the status is not active, return= false > immediately >=20 > + /// >=20 > + if (!IS_BIT_DESC_NULL (Src->PmcSmiSts)) { >=20 > + if ((Src->PmcSmiSts.Reg.Type =3D=3D ACPI_ADDR_TYPE) && >=20 > + (Src->PmcSmiSts.Reg.Data.acpi =3D=3D R_ACPI_IO_SMI_STS) && >=20 > + ((SmiStsValue & (1u << Src->PmcSmiSts.Bit)) =3D=3D 0)) { >=20 > + return FALSE; >=20 > + } >=20 > + } >=20 > + >=20 > + /// >=20 > + /// Read each bit desc from hardware and make sure it's a one >=20 > + /// >=20 > + for (DescIndex =3D 0; DescIndex < NUM_EN_BITS; DescIndex++) { >=20 > + if (!IS_BIT_DESC_NULL (Src->En[DescIndex])) { >=20 > + if ((Src->En[DescIndex].Reg.Type =3D=3D ACPI_ADDR_TYPE) && >=20 > + (Src->En[DescIndex].Reg.Data.acpi =3D=3D R_ACPI_IO_SMI_EN) && >=20 > + ((SmiEnValue & (1u << Src->En[DescIndex].Bit)) =3D=3D 0)) { >=20 > + return FALSE; >=20 > + } else if (ReadBitDesc (&Src->En[DescIndex]) =3D=3D 0) { >=20 > + return FALSE; >=20 > + } >=20 > + } >=20 > + } >=20 > + >=20 > + /// >=20 > + /// Read each bit desc from hardware and make sure it's a one >=20 > + /// >=20 > + for (DescIndex =3D 0; DescIndex < NUM_STS_BITS; DescIndex++) { >=20 > + if (!IS_BIT_DESC_NULL (Src->Sts[DescIndex])) { >=20 > + if ((Src->Sts[DescIndex].Reg.Type =3D=3D ACPI_ADDR_TYPE) && >=20 > + (Src->Sts[DescIndex].Reg.Data.acpi =3D=3D R_ACPI_IO_SMI_STS) &= & >=20 > + ((SmiStsValue & (1u << Src->Sts[DescIndex].Bit)) =3D=3D 0)) { >=20 > + return FALSE; >=20 > + } else if (ReadBitDesc (&Src->Sts[DescIndex]) =3D=3D 0) { >=20 > + return FALSE; >=20 > + } >=20 > + } >=20 > + } >=20 > + >=20 > + return TRUE; >=20 > +} >=20 > + >=20 > +/** >=20 > + Enable the SMI source event by set the SMI enable bit, this function w= ould > also clear SMI >=20 > + status bit to make initial state is correct >=20 > + >=20 > + @param[in] SrcDesc Pointer to the PCH SMI source descript= ion table >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +PchSmmEnableSource ( >=20 > + CONST PCH_SMM_SOURCE_DESC *SrcDesc >=20 > + ) >=20 > +{ >=20 > + UINTN DescIndex; >=20 > + >=20 > + /// >=20 > + /// Set enables to 1 by writing a 1 >=20 > + /// >=20 > + for (DescIndex =3D 0; DescIndex < NUM_EN_BITS; DescIndex++) { >=20 > + if (!IS_BIT_DESC_NULL (SrcDesc->En[DescIndex])) { >=20 > + WriteBitDesc (&SrcDesc->En[DescIndex], 1, FALSE); >=20 > + } >=20 > + } >=20 > + /// >=20 > + /// Clear statuses to 0 by writing a 1 >=20 > + /// >=20 > + for (DescIndex =3D 0; DescIndex < NUM_STS_BITS; DescIndex++) { >=20 > + if (!IS_BIT_DESC_NULL (SrcDesc->Sts[DescIndex])) { >=20 > + WriteBitDesc (&SrcDesc->Sts[DescIndex], 1, TRUE); >=20 > + } >=20 > + } >=20 > +} >=20 > + >=20 > +/** >=20 > + Disable the SMI source event by clear the SMI enable bit >=20 > + >=20 > + @param[in] SrcDesc Pointer to the PCH SMI source descript= ion table >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +PchSmmDisableSource ( >=20 > + CONST PCH_SMM_SOURCE_DESC *SrcDesc >=20 > + ) >=20 > +{ >=20 > + UINTN DescIndex; >=20 > + >=20 > + for (DescIndex =3D 0; DescIndex < NUM_EN_BITS; DescIndex++) { >=20 > + if (!IS_BIT_DESC_NULL (SrcDesc->En[DescIndex])) { >=20 > + WriteBitDesc (&SrcDesc->En[DescIndex], 0, FALSE); >=20 > + } >=20 > + } >=20 > +} >=20 > + >=20 > +/** >=20 > + Clear the SMI status bit by set the source bit of SMI status register >=20 > + >=20 > + @param[in] SrcDesc Pointer to the PCH SMI source descript= ion table >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +PchSmmClearSource ( >=20 > + CONST PCH_SMM_SOURCE_DESC *SrcDesc >=20 > + ) >=20 > +{ >=20 > + UINTN DescIndex; >=20 > + >=20 > + for (DescIndex =3D 0; DescIndex < NUM_STS_BITS; DescIndex++) { >=20 > + if (!IS_BIT_DESC_NULL (SrcDesc->Sts[DescIndex])) { >=20 > + WriteBitDesc (&SrcDesc->Sts[DescIndex], 1, TRUE); >=20 > + } >=20 > + } >=20 > +} >=20 > + >=20 > +/** >=20 > + Sets the source to a 1 and then waits for it to clear. >=20 > + Be very careful when calling this function -- it will not >=20 > + ASSERT. An acceptable case to call the function is when >=20 > + waiting for the NEWCENTURY_STS bit to clear (which takes >=20 > + 3 RTCCLKs). >=20 > + >=20 > + @param[in] SrcDesc Pointer to the PCH SMI source descript= ion table >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +PchSmmClearSourceAndBlock ( >=20 > + CONST PCH_SMM_SOURCE_DESC *SrcDesc >=20 > + ) >=20 > +{ >=20 > + UINTN DescIndex; >=20 > + BOOLEAN IsSet; >=20 > + >=20 > + for (DescIndex =3D 0; DescIndex < NUM_STS_BITS; DescIndex++) { >=20 > + >=20 > + if (!IS_BIT_DESC_NULL (SrcDesc->Sts[DescIndex])) { >=20 > + /// >=20 > + /// Write the bit >=20 > + /// >=20 > + WriteBitDesc (&SrcDesc->Sts[DescIndex], 1, TRUE); >=20 > + >=20 > + /// >=20 > + /// Don't return until the bit actually clears. >=20 > + /// >=20 > + IsSet =3D TRUE; >=20 > + while (IsSet) { >=20 > + IsSet =3D ReadBitDesc (&SrcDesc->Sts[DescIndex]); >=20 > + /// >=20 > + /// IsSet will eventually clear -- or else we'll have >=20 > + /// an infinite loop. >=20 > + /// >=20 > + } >=20 > + } >=20 > + } >=20 > +} >=20 > + >=20 > diff --git > a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHel > pers.h > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHel > pers.h > new file mode 100644 > index 0000000000..db7713fa02 > --- /dev/null > +++ > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHel > pers.h > @@ -0,0 +1,155 @@ > +/** @file >=20 > + Helper functions for PCH SMM >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > +#ifndef PCH_SMM_HELPERS_H >=20 > +#define PCH_SMM_HELPERS_H >=20 > + >=20 > +#include "PchSmm.h" >=20 > +#include "PchxSmmHelpers.h" >=20 > +// >=20 > +// > /////////////////////////////////////////////////////////////////////////= ///// > ///////////////////////////////////// >=20 > +// SUPPORT / HELPER FUNCTIONS (PCH version-independent) >=20 > +// >=20 > + >=20 > +/** >=20 > + Publish SMI Dispatch protocols. >=20 > + >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +PchSmmPublishDispatchProtocols ( >=20 > + VOID >=20 > + ); >=20 > + >=20 > +/** >=20 > + Compare 2 SMM source descriptors' enable settings. >=20 > + >=20 > + @param[in] Src1 Pointer to the PCH SMI source descript= ion table 1 >=20 > + @param[in] Src2 Pointer to the PCH SMI source descript= ion table 2 >=20 > + >=20 > + @retval TRUE The enable settings of the 2 SMM sourc= e > descriptors are identical. >=20 > + @retval FALSE The enable settings of the 2 SMM sourc= e > descriptors are not identical. >=20 > +**/ >=20 > +BOOLEAN >=20 > +CompareEnables ( >=20 > + CONST IN PCH_SMM_SOURCE_DESC *Src1, >=20 > + CONST IN PCH_SMM_SOURCE_DESC *Src2 >=20 > + ); >=20 > + >=20 > +/** >=20 > + Compare a bit descriptor to the enables of source descriptor. Includes= null > address type. >=20 > + >=20 > + @param[in] BitDesc Pointer to the PCH SMI bit descriptor >=20 > + @param[in] Src Pointer to the PCH SMI source descript= ion table 2 >=20 > + >=20 > + @retval TRUE The bit desc is equal to any of the en= ables in source > descriptor >=20 > + @retval FALSE The bid desc is not equal to all of th= e enables in > source descriptor >=20 > +**/ >=20 > +BOOLEAN >=20 > +IsBitEqualToAnySourceEn ( >=20 > + CONST IN PCH_SMM_BIT_DESC *BitDesc, >=20 > + CONST IN PCH_SMM_SOURCE_DESC *Src >=20 > + ); >=20 > + >=20 > +/** >=20 > + Compare 2 SMM source descriptors' statuses. >=20 > + >=20 > + @param[in] Src1 Pointer to the PCH SMI source descript= ion table 1 >=20 > + @param[in] Src2 Pointer to the PCH SMI source descript= ion table 2 >=20 > + >=20 > + @retval TRUE The statuses of the 2 SMM source descr= iptors are > identical. >=20 > + @retval FALSE The statuses of the 2 SMM source descr= iptors are > not identical. >=20 > +**/ >=20 > +BOOLEAN >=20 > +CompareStatuses ( >=20 > + CONST IN PCH_SMM_SOURCE_DESC *Src1, >=20 > + CONST IN PCH_SMM_SOURCE_DESC *Src2 >=20 > + ); >=20 > + >=20 > +/** >=20 > + Compare 2 SMM source descriptors, based on Enable settings and Status > settings of them. >=20 > + >=20 > + @param[in] Src1 Pointer to the PCH SMI source descript= ion table 1 >=20 > + @param[in] Src2 Pointer to the PCH SMI source descript= ion table 2 >=20 > + >=20 > + @retval TRUE The 2 SMM source descriptors are ident= ical. >=20 > + @retval FALSE The 2 SMM source descriptors are not i= dentical. >=20 > +**/ >=20 > +BOOLEAN >=20 > +CompareSources ( >=20 > + CONST IN PCH_SMM_SOURCE_DESC *Src1, >=20 > + CONST IN PCH_SMM_SOURCE_DESC *Src2 >=20 > + ); >=20 > + >=20 > +/** >=20 > + Check if an SMM source is active. >=20 > + >=20 > + @param[in] Src Pointer to the PCH SMI source descript= ion table >=20 > + @param[in] SciEn Indicate if SCI is enabled or not >=20 > + @param[in] SmiEnValue Value from R_PCH_SMI_EN >=20 > + @param[in] SmiStsValue Value from R_PCH_SMI_STS >=20 > + >=20 > + @retval TRUE It is active. >=20 > + @retval FALSE It is inactive. >=20 > +**/ >=20 > +BOOLEAN >=20 > +SourceIsActive ( >=20 > + CONST IN PCH_SMM_SOURCE_DESC *Src, >=20 > + CONST IN BOOLEAN SciEn, >=20 > + CONST IN UINT32 SmiEnValue, >=20 > + CONST IN UINT32 SmiStsValue >=20 > + ); >=20 > + >=20 > +/** >=20 > + Enable the SMI source event by set the SMI enable bit, this function w= ould > also clear SMI >=20 > + status bit to make initial state is correct >=20 > + >=20 > + @param[in] SrcDesc Pointer to the PCH SMI source descript= ion table >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +PchSmmEnableSource ( >=20 > + CONST PCH_SMM_SOURCE_DESC *SrcDesc >=20 > + ); >=20 > + >=20 > +/** >=20 > + Disable the SMI source event by clear the SMI enable bit >=20 > + >=20 > + @param[in] SrcDesc Pointer to the PCH SMI source descript= ion table >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +PchSmmDisableSource ( >=20 > + CONST PCH_SMM_SOURCE_DESC *SrcDesc >=20 > + ); >=20 > + >=20 > +/** >=20 > + Clear the SMI status bit by set the source bit of SMI status register >=20 > + >=20 > + @param[in] SrcDesc Pointer to the PCH SMI source descript= ion table >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +PchSmmClearSource ( >=20 > + CONST PCH_SMM_SOURCE_DESC *SrcDesc >=20 > + ); >=20 > + >=20 > +/** >=20 > + Sets the source to a 1 and then waits for it to clear. >=20 > + Be very careful when calling this function -- it will not >=20 > + ASSERT. An acceptable case to call the function is when >=20 > + waiting for the NEWCENTURY_STS bit to clear (which takes >=20 > + 3 RTCCLKs). >=20 > + >=20 > + @param[in] SrcDesc Pointer to the PCH SMI source descript= ion table >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +PchSmmClearSourceAndBlock ( >=20 > + CONST PCH_SMM_SOURCE_DESC *SrcDesc >=20 > + ); >=20 > + >=20 > +#endif >=20 > diff --git > a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPeri > odicTimer.c > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPeri > odicTimer.c > new file mode 100644 > index 0000000000..3c3e638cbf > --- /dev/null > +++ > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPeri > odicTimer.c > @@ -0,0 +1,667 @@ > +/** @file >=20 > + File to contain all the hardware specific stuff for the Periodical Tim= er > dispatch protocol. >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > +#include "PchSmmHelpers.h" >=20 > +#include >=20 > +#include >=20 > + >=20 > +// >=20 > +// There is only one instance for PeriodicTimerCommBuffer. >=20 > +// It's safe in SMM since there is no re-entry for the function. >=20 > +// >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED > EFI_SMM_PERIODIC_TIMER_CONTEXT mPchPeriodicTimerCommBuffer; >=20 > + >=20 > +typedef enum { >=20 > + PERIODIC_TIMER=3D 0, >=20 > + SWSMI_TIMER, >=20 > + NUM_TIMERS >=20 > +} SUPPORTED_TIMER; >=20 > + >=20 > +typedef struct _TIMER_INTERVAL { >=20 > + UINT64 Interval; >=20 > + UINT8 AssociatedTimer; >=20 > +} TIMER_INTERVAL; >=20 > + >=20 > +#define NUM_INTERVALS 8 >=20 > + >=20 > +// >=20 > +// Time constants, in 100 nano-second units >=20 > +// >=20 > +#define TIME_64s 640000000 ///< 64 s >=20 > +#define TIME_32s 320000000 ///< 32 s >=20 > +#define TIME_16s 160000000 ///< 16 s >=20 > +#define TIME_8s 80000000 ///< 8 s >=20 > +#define TIME_64ms 640000 ///< 64 ms >=20 > +#define TIME_32ms 320000 ///< 32 ms >=20 > +#define TIME_16ms 160000 ///< 16 ms >=20 > +#define TIME_1_5ms 15000 ///< 1.5 ms >=20 > + >=20 > +typedef enum { >=20 > + INDEX_TIME_64s =3D 0, >=20 > + INDEX_TIME_32s, >=20 > + INDEX_TIME_16s, >=20 > + INDEX_TIME_8s, >=20 > + INDEX_TIME_64ms, >=20 > + INDEX_TIME_32ms, >=20 > + INDEX_TIME_16ms, >=20 > + INDEX_TIME_1_5ms, >=20 > + INDEX_TIME_MAX >=20 > +} TIMER_INTERVAL_INDEX; >=20 > + >=20 > +static TIMER_INTERVAL mSmmPeriodicTimerIntervals[NUM_INTERVALS] =3D { >=20 > + { >=20 > + TIME_64s, >=20 > + PERIODIC_TIMER >=20 > + }, >=20 > + { >=20 > + TIME_32s, >=20 > + PERIODIC_TIMER >=20 > + }, >=20 > + { >=20 > + TIME_16s, >=20 > + PERIODIC_TIMER >=20 > + }, >=20 > + { >=20 > + TIME_8s, >=20 > + PERIODIC_TIMER >=20 > + }, >=20 > + { >=20 > + TIME_64ms, >=20 > + SWSMI_TIMER >=20 > + }, >=20 > + { >=20 > + TIME_32ms, >=20 > + SWSMI_TIMER >=20 > + }, >=20 > + { >=20 > + TIME_16ms, >=20 > + SWSMI_TIMER >=20 > + }, >=20 > + { >=20 > + TIME_1_5ms, >=20 > + SWSMI_TIMER >=20 > + }, >=20 > +}; >=20 > + >=20 > +typedef struct _TIMER_INFO { >=20 > + UINTN NumChildren; ///< number of children using this timer >=20 > + UINT64 MinReqInterval; ///< minimum interval required by children >=20 > + UINTN CurrentSetting; ///< interval this timer is set at right n= ow (index > into interval table) >=20 > +} TIMER_INFO; >=20 > + >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED TIMER_INFO > mTimers[NUM_TIMERS]; >=20 > + >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mTimerSourceDesc[NUM_TIMERS] =3D { >=20 > + { >=20 > + PCH_SMM_NO_FLAGS, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_EN} >=20 > + }, >=20 > + S_ACPI_IO_SMI_EN, >=20 > + N_ACPI_IO_SMI_EN_PERIODIC >=20 > + }, >=20 > + NULL_BIT_DESC_INITIALIZER >=20 > + }, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_PERIODIC >=20 > + } >=20 > + }, >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_PERIODIC >=20 > + } >=20 > + }, >=20 > + { >=20 > + PCH_SMM_NO_FLAGS, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_EN} >=20 > + }, >=20 > + S_ACPI_IO_SMI_EN, >=20 > + N_ACPI_IO_SMI_EN_SWSMI_TMR >=20 > + }, >=20 > + NULL_BIT_DESC_INITIALIZER >=20 > + }, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_SWSMI_TMR >=20 > + } >=20 > + }, >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_SWSMI_TMR >=20 > + } >=20 > + } >=20 > +}; >=20 > + >=20 > +/** >=20 > + Program Smm Periodic Timer >=20 > + >=20 > + @param[in] SrcDesc Pointer to the PCH_SMM_SOURCE_DESC > instance. >=20 > +**/ >=20 > +VOID >=20 > +PchSmmPeriodicTimerProgramTimers ( >=20 > + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc >=20 > + ); >=20 > + >=20 > +/** >=20 > + Convert the dispatch context to the timer interval, this function will= assert > if then either: >=20 > + (1) The context contains an invalid interval >=20 > + (2) The timer interval table is corrupt >=20 > + >=20 > + @param[in] DispatchContext The pointer to the Dispatch Context >=20 > + >=20 > + @retval TIMER_INTERVAL The timer interval of input dispatch c= ontext >=20 > +**/ >=20 > +TIMER_INTERVAL * >=20 > +ContextToTimerInterval ( >=20 > + IN PCH_SMM_CONTEXT *DispatchContext >=20 > + ) >=20 > +{ >=20 > + UINTN loopvar; >=20 > + >=20 > + /// >=20 > + /// Determine which timer this child is using >=20 > + /// >=20 > + for (loopvar =3D 0; loopvar < NUM_INTERVALS; loopvar++) { >=20 > + if (((DispatchContext->PeriodicTimer.SmiTickInterval =3D=3D 0) && >=20 > + (DispatchContext->PeriodicTimer.Period >=3D > mSmmPeriodicTimerIntervals[loopvar].Interval)) || >=20 > + (DispatchContext->PeriodicTimer.SmiTickInterval =3D=3D > mSmmPeriodicTimerIntervals[loopvar].Interval)) { >=20 > + return &mSmmPeriodicTimerIntervals[loopvar]; >=20 > + } >=20 > + } >=20 > + /// >=20 > + /// If this assertion fires, then either: >=20 > + /// (1) the context contains an invalid interval >=20 > + /// (2) the timer interval table is corrupt >=20 > + /// >=20 > + ASSERT (FALSE); >=20 > + >=20 > + return NULL; >=20 > +} >=20 > + >=20 > +/** >=20 > + Figure out which timer the child is requesting and >=20 > + send back the source description >=20 > + >=20 > + @param[in] DispatchContext The pointer to the Dispatch Context > instances >=20 > + @param[out] SrcDesc The pointer to the source description >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +MapPeriodicTimerToSrcDesc ( >=20 > + IN PCH_SMM_CONTEXT *DispatchContext, >=20 > + OUT PCH_SMM_SOURCE_DESC *SrcDesc >=20 > + ) >=20 > +{ >=20 > + TIMER_INTERVAL *TimerInterval; >=20 > + >=20 > + /// >=20 > + /// Figure out which timer the child is requesting and >=20 > + /// send back the source description >=20 > + /// >=20 > + TimerInterval =3D ContextToTimerInterval (DispatchContext); >=20 > + if (TimerInterval =3D=3D NULL) { >=20 > + return; >=20 > + } >=20 > + >=20 > + CopyMem ( >=20 > + (VOID *) SrcDesc, >=20 > + (VOID *) (&mTimerSourceDesc[TimerInterval->AssociatedTimer]), >=20 > + sizeof (PCH_SMM_SOURCE_DESC) >=20 > + ); >=20 > + >=20 > + /// >=20 > + /// Program the value of the interval into hardware >=20 > + /// >=20 > + PchSmmPeriodicTimerProgramTimers (SrcDesc); >=20 > +} >=20 > + >=20 > +/** >=20 > + Update the elapsed time from the Interval data of DATABASE_RECORD >=20 > + >=20 > + @param[in] Record The pointer to the DATABASE_RECORD. >=20 > + @param[out] HwContext The Context to be updated. >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +PeriodicTimerGetContext ( >=20 > + IN DATABASE_RECORD *Record, >=20 > + OUT PCH_SMM_CONTEXT *HwContext >=20 > + ) >=20 > +{ >=20 > + TIMER_INTERVAL *TimerInterval; >=20 > + >=20 > + ASSERT (Record->ProtocolType =3D=3D PeriodicTimerType); >=20 > + >=20 > + TimerInterval =3D ContextToTimerInterval (&Record->ChildContext); >=20 > + if (TimerInterval =3D=3D NULL) { >=20 > + return; >=20 > + } >=20 > + /// >=20 > + /// Ignore the hardware context. It's not required for this protocol. >=20 > + /// Instead, just increment the child's context. >=20 > + /// Update the elapsed time w/ the data from our tables >=20 > + /// >=20 > + Record->MiscData.ElapsedTime +=3D mTimers[TimerInterval- > >AssociatedTimer].MinReqInterval; >=20 > + *HwContext =3D Record->ChildContext; >=20 > +} >=20 > + >=20 > +/** >=20 > + Check whether Periodic Timer of two contexts match >=20 > + >=20 > + @param[in] Context1 Context 1 that includes Periodic Timer= 1 >=20 > + @param[in] Context2 Context 2 that includes Periodic Timer= 2 >=20 > + >=20 > + @retval FALSE Periodic Timer match >=20 > + @retval TRUE Periodic Timer don't match >=20 > +**/ >=20 > +BOOLEAN >=20 > +EFIAPI >=20 > +PeriodicTimerCmpContext ( >=20 > + IN PCH_SMM_CONTEXT *HwContext, >=20 > + IN PCH_SMM_CONTEXT *ChildContext >=20 > + ) >=20 > +{ >=20 > + DATABASE_RECORD *Record; >=20 > + Record =3D DATABASE_RECORD_FROM_CHILDCONTEXT (ChildContext); >=20 > + >=20 > + if (!Record->MiscData.TimerSmiEnabled) { >=20 > + return FALSE; >=20 > + } >=20 > + if (Record->MiscData.ElapsedTime >=3D ChildContext->PeriodicTimer.Peri= od) > { >=20 > + /// >=20 > + /// For EDKII, the ElapsedTime is reset when > PeriodicTimerGetCommBuffer >=20 > + /// >=20 > + return TRUE; >=20 > + } else { >=20 > + return FALSE; >=20 > + } >=20 > +} >=20 > + >=20 > +/** >=20 > + Gather the CommBuffer information of SmmPeriodicTimerDispatch2. >=20 > + >=20 > + @param[in] Record No use >=20 > + @param[out] CommBuffer Point to the CommBuffer structure >=20 > + @param[out] CommBufferSize Point to the Size of CommBuffer > structure >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +PeriodicTimerGetCommBuffer ( >=20 > + IN DATABASE_RECORD *Record, >=20 > + OUT VOID **CommBuffer, >=20 > + OUT UINTN *CommBufferSize >=20 > + ) >=20 > +{ >=20 > + ASSERT (Record->ProtocolType =3D=3D PeriodicTimerType); >=20 > + >=20 > + mPchPeriodicTimerCommBuffer.ElapsedTime =3D Record- > >MiscData.ElapsedTime; >=20 > + >=20 > + /// >=20 > + /// For EDKII, the ElapsedTime is reset here >=20 > + /// >=20 > + Record->MiscData.ElapsedTime =3D 0; >=20 > + >=20 > + /// >=20 > + /// Return the CommBuffer >=20 > + /// >=20 > + *CommBuffer =3D (VOID *) &mPchPeriodicTimerCommBuffer; >=20 > + *CommBufferSize =3D sizeof (EFI_SMM_PERIODIC_TIMER_CONTEXT); >=20 > +} >=20 > + >=20 > +/** >=20 > + Program Smm Periodic Timer >=20 > + >=20 > + @param[in] SrcDesc Pointer to the PCH_SMM_SOURCE_DESC > instance. >=20 > +**/ >=20 > +VOID >=20 > +PchSmmPeriodicTimerProgramTimers ( >=20 > + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc >=20 > + ) >=20 > +{ >=20 > + SUPPORTED_TIMER Timer; >=20 > + DATABASE_RECORD *RecordInDb; >=20 > + LIST_ENTRY *LinkInDb; >=20 > + TIMER_INTERVAL *TimerInterval; >=20 > + >=20 > + /// >=20 > + /// Find the minimum required interval for each timer >=20 > + /// >=20 > + for (Timer =3D 0; Timer < NUM_TIMERS; Timer++) { >=20 > + mTimers[Timer].MinReqInterval =3D ~ (UINT64) 0x0; >=20 > + mTimers[Timer].NumChildren =3D 0; >=20 > + } >=20 > + >=20 > + LinkInDb =3D GetFirstNode (&mPrivateData.CallbackDataBase); >=20 > + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { >=20 > + RecordInDb =3D DATABASE_RECORD_FROM_LINK (LinkInDb); >=20 > + if (RecordInDb->ProtocolType =3D=3D PeriodicTimerType) { >=20 > + if (RecordInDb->MiscData.TimerSmiEnabled) { >=20 > + /// >=20 > + /// This child is registerd with the PeriodicTimer protocol >=20 > + /// >=20 > + TimerInterval =3D ContextToTimerInterval (&RecordInDb->ChildCont= ext); >=20 > + if (TimerInterval =3D=3D NULL) { >=20 > + return; >=20 > + } >=20 > + >=20 > + Timer =3D TimerInterval->AssociatedTimer; >=20 > + if (Timer < 0 || Timer >=3D NUM_TIMERS) { >=20 > + ASSERT (FALSE); >=20 > + CpuDeadLoop (); >=20 > + return; >=20 > + } >=20 > + if (mTimers[Timer].MinReqInterval > RecordInDb- > >ChildContext.PeriodicTimer.SmiTickInterval) { >=20 > + mTimers[Timer].MinReqInterval =3D RecordInDb- > >ChildContext.PeriodicTimer.SmiTickInterval; >=20 > + } >=20 > + mTimers[Timer].NumChildren++; >=20 > + } >=20 > + } >=20 > + LinkInDb =3D GetNextNode (&mPrivateData.CallbackDataBase, > &RecordInDb->Link); >=20 > + } >=20 > + /// >=20 > + /// Program the hardware >=20 > + /// >=20 > + if (mTimers[PERIODIC_TIMER].NumChildren > 0) { >=20 > + switch (mTimers[PERIODIC_TIMER].MinReqInterval) { >=20 > + case TIME_64s: >=20 > + PmcSetPeriodicSmiRate (PmcPeriodicSmiRate64s); >=20 > + mTimers[PERIODIC_TIMER].CurrentSetting =3D INDEX_TIME_64s; >=20 > + break; >=20 > + >=20 > + case TIME_32s: >=20 > + PmcSetPeriodicSmiRate (PmcPeriodicSmiRate32s); >=20 > + mTimers[PERIODIC_TIMER].CurrentSetting =3D INDEX_TIME_32s; >=20 > + break; >=20 > + >=20 > + case TIME_16s: >=20 > + PmcSetPeriodicSmiRate (PmcPeriodicSmiRate16s); >=20 > + mTimers[PERIODIC_TIMER].CurrentSetting =3D INDEX_TIME_16s; >=20 > + break; >=20 > + >=20 > + case TIME_8s: >=20 > + PmcSetPeriodicSmiRate (PmcPeriodicSmiRate8s); >=20 > + mTimers[PERIODIC_TIMER].CurrentSetting =3D INDEX_TIME_8s; >=20 > + break; >=20 > + >=20 > + default: >=20 > + ASSERT (FALSE); >=20 > + break; >=20 > + } >=20 > + >=20 > + /// >=20 > + /// Restart the timer here, just need to clear the SMI >=20 > + /// >=20 > + if (SrcDesc->Sts[0].Bit =3D=3D N_ACPI_IO_SMI_STS_PERIODIC) { >=20 > + PchSmmClearSource (&mTimerSourceDesc[PERIODIC_TIMER]); >=20 > + } >=20 > + } else { >=20 > + PchSmmDisableSource (&mTimerSourceDesc[PERIODIC_TIMER]); >=20 > + } >=20 > + >=20 > + if (mTimers[SWSMI_TIMER].NumChildren > 0) { >=20 > + switch (mTimers[SWSMI_TIMER].MinReqInterval) { >=20 > + case TIME_64ms: >=20 > + PmcSetSwSmiRate (PmcSwSmiRate64ms); >=20 > + mTimers[SWSMI_TIMER].CurrentSetting =3D INDEX_TIME_64ms; >=20 > + break; >=20 > + >=20 > + case TIME_32ms: >=20 > + PmcSetSwSmiRate (PmcSwSmiRate32ms); >=20 > + mTimers[SWSMI_TIMER].CurrentSetting =3D INDEX_TIME_32ms; >=20 > + break; >=20 > + >=20 > + case TIME_16ms: >=20 > + PmcSetSwSmiRate (PmcSwSmiRate16ms); >=20 > + mTimers[SWSMI_TIMER].CurrentSetting =3D INDEX_TIME_16ms; >=20 > + break; >=20 > + >=20 > + case TIME_1_5ms: >=20 > + PmcSetSwSmiRate (PmcSwSmiRate1p5ms); >=20 > + mTimers[SWSMI_TIMER].CurrentSetting =3D INDEX_TIME_1_5ms; >=20 > + break; >=20 > + >=20 > + default: >=20 > + ASSERT (FALSE); >=20 > + break; >=20 > + } >=20 > + >=20 > + /// >=20 > + /// Restart the timer here, need to disable, clear, then enable to r= estart > this timer >=20 > + /// >=20 > + if (SrcDesc->Sts[0].Bit =3D=3D N_ACPI_IO_SMI_STS_SWSMI_TMR) { >=20 > + PchSmmDisableSource (&mTimerSourceDesc[SWSMI_TIMER]); >=20 > + PchSmmClearSource (&mTimerSourceDesc[SWSMI_TIMER]); >=20 > + PchSmmEnableSource (&mTimerSourceDesc[SWSMI_TIMER]); >=20 > + } >=20 > + } else { >=20 > + PchSmmDisableSource (&mTimerSourceDesc[SWSMI_TIMER]); >=20 > + } >=20 > +} >=20 > + >=20 > +/** >=20 > + This services returns the next SMI tick period that is supported by th= e > chipset. >=20 > + The order returned is from longest to shortest interval period. >=20 > + >=20 > + @param[in] This Pointer to the > EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL instance. >=20 > + @param[in, out] SmiTickInterval Pointer to pointer of the next shorter= SMI > interval period that is supported by the child. >=20 > + >=20 > + @retval EFI_SUCCESS The service returned successfully. >=20 > + @retval EFI_INVALID_PARAMETER The parameter SmiTickInterval is > invalid. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +PchSmmPeriodicTimerDispatchGetNextShorterInterval ( >=20 > + IN CONST EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL *This, >=20 > + IN OUT UINT64 **SmiTickInterval >=20 > + ) >=20 > +{ >=20 > + TIMER_INTERVAL *IntervalPointer; >=20 > + >=20 > + ASSERT (SmiTickInterval !=3D NULL); >=20 > + >=20 > + IntervalPointer =3D (TIMER_INTERVAL *) *SmiTickInterval; >=20 > + >=20 > + if (IntervalPointer =3D=3D NULL) { >=20 > + /// >=20 > + /// The first time child requesting an interval >=20 > + /// >=20 > + IntervalPointer =3D &mSmmPeriodicTimerIntervals[0]; >=20 > + } else if (IntervalPointer =3D=3D > &mSmmPeriodicTimerIntervals[NUM_INTERVALS - 1]) { >=20 > + /// >=20 > + /// At end of the list >=20 > + /// >=20 > + IntervalPointer =3D NULL; >=20 > + } else { >=20 > + if ((IntervalPointer >=3D &mSmmPeriodicTimerIntervals[0]) && >=20 > + (IntervalPointer < &mSmmPeriodicTimerIntervals[NUM_INTERVALS - > 1]) >=20 > + ) { >=20 > + /// >=20 > + /// Get the next interval in the list >=20 > + /// >=20 > + IntervalPointer++; >=20 > + } else { >=20 > + /// >=20 > + /// Input is out of range >=20 > + /// >=20 > + return EFI_INVALID_PARAMETER; >=20 > + } >=20 > + } >=20 > + >=20 > + if (IntervalPointer !=3D NULL) { >=20 > + *SmiTickInterval =3D &IntervalPointer->Interval; >=20 > + } else { >=20 > + *SmiTickInterval =3D NULL; >=20 > + } >=20 > + >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > + >=20 > +/** >=20 > + This function is responsible for calculating and enabling any timers t= hat are > required >=20 > + to dispatch messages to children. The SrcDesc argument isn't acutally = used. >=20 > + >=20 > + @param[in] SrcDesc Pointer to the PCH_SMM_SOURCE_DESC > instance. >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +PchSmmPeriodicTimerClearSource ( >=20 > + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc >=20 > + ) >=20 > +{ >=20 > + PchSmmPeriodicTimerProgramTimers (SrcDesc); >=20 > +} >=20 > + >=20 > + >=20 > +/** >=20 > + Check if the handle is in type of PeriodicTimer >=20 > + >=20 > + @retval TRUE The handle is in type of Periodi= cTimer. >=20 > + @retval FALSE The handle is not in type of Per= iodicTimer. >=20 > +**/ >=20 > +BOOLEAN >=20 > +IsSmmPeriodicTimerHandle ( >=20 > + IN EFI_HANDLE DispatchHandle >=20 > + ) >=20 > +{ >=20 > + DATABASE_RECORD *RecordInDb; >=20 > + LIST_ENTRY *LinkInDb; >=20 > + >=20 > + LinkInDb =3D GetFirstNode (&mPrivateData.CallbackDataBase); >=20 > + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) { >=20 > + if (DispatchHandle =3D=3D (EFI_HANDLE) LinkInDb) { >=20 > + RecordInDb =3D DATABASE_RECORD_FROM_LINK (LinkInDb); >=20 > + if (RecordInDb->ProtocolType =3D=3D PeriodicTimerType) { >=20 > + return TRUE; >=20 > + } >=20 > + } >=20 > + LinkInDb =3D GetNextNode (&mPrivateData.CallbackDataBase, LinkInDb); >=20 > + } >=20 > + return FALSE; >=20 > +} >=20 > + >=20 > +/** >=20 > + Pause SMM periodic timer callback function. >=20 > + >=20 > + This function disable the SMI enable of SMI timer according to the > DispatchHandle, >=20 > + which is returned by SMM periodic timer callback registration. >=20 > + >=20 > + @retval EFI_SUCCESS This operation is complete. >=20 > + @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchSmmPeriodicTimerControlPause ( >=20 > + IN PCH_SMM_PERIODIC_TIMER_CONTROL_PROTOCOL *This, >=20 > + IN EFI_HANDLE DispatchHandle >=20 > + ) >=20 > +{ >=20 > + DATABASE_RECORD *RecordInDb; >=20 > + >=20 > + if (IsSmmPeriodicTimerHandle (DispatchHandle) =3D=3D FALSE) { >=20 > + return EFI_INVALID_PARAMETER; >=20 > + } >=20 > + >=20 > + RecordInDb =3D DATABASE_RECORD_FROM_LINK (DispatchHandle); >=20 > + RecordInDb->MiscData.TimerSmiEnabled =3D FALSE; >=20 > + // >=20 > + // reset the timer interval per SMI trigger due to stop a periodic tim= er SMI >=20 > + // >=20 > + PchSmmPeriodicTimerProgramTimers (&RecordInDb->SrcDesc); >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > + >=20 > +/** >=20 > + Resume SMM periodic timer callback function. >=20 > + >=20 > + This function enable the SMI enable of SMI timer according to the > DispatchHandle, >=20 > + which is returned by SMM periodic timer callback registration. >=20 > + >=20 > + @retval EFI_SUCCESS This operation is complete. >=20 > + @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchSmmPeriodicTimerControlResume ( >=20 > + IN PCH_SMM_PERIODIC_TIMER_CONTROL_PROTOCOL *This, >=20 > + IN EFI_HANDLE DispatchHandle >=20 > + ) >=20 > +{ >=20 > + DATABASE_RECORD *RecordInDb; >=20 > + >=20 > + if (IsSmmPeriodicTimerHandle (DispatchHandle) =3D=3D FALSE) { >=20 > + return EFI_INVALID_PARAMETER; >=20 > + } >=20 > + RecordInDb =3D DATABASE_RECORD_FROM_LINK (DispatchHandle); >=20 > + RecordInDb->MiscData.TimerSmiEnabled =3D TRUE; >=20 > + // >=20 > + // reset the timer interval per SMI trigger due to resume a periodic t= imer > SMI >=20 > + // >=20 > + PchSmmPeriodicTimerProgramTimers (&RecordInDb->SrcDesc); >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > + >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED > PCH_SMM_PERIODIC_TIMER_CONTROL_PROTOCOL > mPchSmmPeriodicTimerControlProtocol =3D { >=20 > + PchSmmPeriodicTimerControlPause, >=20 > + PchSmmPeriodicTimerControlResume >=20 > +}; >=20 > + >=20 > +/** >=20 > + Install PCH SMM periodic timer control protocol >=20 > + >=20 > + @param[in] Handle handle for this driver >=20 > + >=20 > + @retval EFI_SUCCESS Driver initialization completed = successfully >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +InstallPchSmmPeriodicTimerControlProtocol ( >=20 > + IN EFI_HANDLE Handle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + >=20 > + // >=20 > + // Install protocol interface >=20 > + // >=20 > + Status =3D gSmst->SmmInstallProtocolInterface ( >=20 > + &Handle, >=20 > + &gPchSmmPeriodicTimerControlGuid, >=20 > + EFI_NATIVE_INTERFACE, >=20 > + &mPchSmmPeriodicTimerControlProtocol >=20 > + ); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > + >=20 > diff --git > a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPo > werButton.c > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPo > werButton.c > new file mode 100644 > index 0000000000..bfed944848 > --- /dev/null > +++ > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPo > werButton.c > @@ -0,0 +1,81 @@ > +/** @file >=20 > + File to contain all the hardware specific stuff for the Smm Power Butt= on > dispatch protocol. >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > +#include >=20 > +#include >=20 > + >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mPowerButtonSourceDesc =3D { >=20 > + PCH_SMM_SCI_EN_DEPENDENT, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_PM1_EN} >=20 > + }, >=20 > + S_ACPI_IO_PM1_EN, >=20 > + N_ACPI_IO_PM1_EN_PWRBTN >=20 > + }, >=20 > + NULL_BIT_DESC_INITIALIZER >=20 > + }, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_PM1_STS} >=20 > + }, >=20 > + S_ACPI_IO_PM1_STS, >=20 > + N_ACPI_IO_PM1_STS_PWRBTN >=20 > + } >=20 > + }, >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_PM1_STS_REG >=20 > + } >=20 > +}; >=20 > + >=20 > +/** >=20 > + Get the power button status. >=20 > + >=20 > + @param[in] Record The pointer to the DATABASE_RECORD. >=20 > + @param[out] Context Calling context from the hardware, wil= l be > updated with the current power button status. >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +PowerButtonGetContext ( >=20 > + IN DATABASE_RECORD *Record, >=20 > + OUT PCH_SMM_CONTEXT *Context >=20 > + ) >=20 > +{ >=20 > + if (PmcGetPwrBtnLevel ()) { >=20 > + Context->PowerButton.Phase =3D EfiPowerButtonExit; >=20 > + } else { >=20 > + Context->PowerButton.Phase =3D EfiPowerButtonEntry; >=20 > + } >=20 > +} >=20 > + >=20 > +/** >=20 > + Check whether Power Button status of two contexts match >=20 > + >=20 > + @param[in] Context1 Context 1 that includes Power Button s= tatus 1 >=20 > + @param[in] Context2 Context 2 that includes Power Button s= tatus 2 >=20 > + >=20 > + @retval FALSE Power Button status match >=20 > + @retval TRUE Power Button status don't match >=20 > +**/ >=20 > +BOOLEAN >=20 > +EFIAPI >=20 > +PowerButtonCmpContext ( >=20 > + IN PCH_SMM_CONTEXT *Context1, >=20 > + IN PCH_SMM_CONTEXT *Context2 >=20 > + ) >=20 > +{ >=20 > + return (BOOLEAN) (Context1->PowerButton.Phase =3D=3D Context2- > >PowerButton.Phase); >=20 > +} >=20 > diff --git > a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSw. > c > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSw. > c > new file mode 100644 > index 0000000000..9b13bf6308 > --- /dev/null > +++ > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSw. > c > @@ -0,0 +1,381 @@ > +/** @file >=20 > + File to contain all the hardware specific stuff for the Smm Sw dispatc= h > protocol. >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > +#include "PchSmmHelpers.h" >=20 > +#include >=20 > +#include >=20 > +#include >=20 > + >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED EFI_SMM_CPU_PROTOCOL > *mSmmCpuProtocol; >=20 > + >=20 > +STATIC LIST_ENTRY mSwSmiCallbackDataBase; >=20 > + >=20 > +// >=20 > +// "SWSMI" RECORD >=20 > +// Linked list data structures >=20 > +// >=20 > +#define SW_SMI_RECORD_SIGNATURE SIGNATURE_32 ('S', 'W', 'S', 'M'= ) >=20 > + >=20 > +#define SW_SMI_RECORD_FROM_LINK(_record) CR (_record, > SW_SMI_RECORD, Link, SW_SMI_RECORD_SIGNATURE) >=20 > + >=20 > +typedef struct { >=20 > + UINT32 Signature; >=20 > + LIST_ENTRY Link; >=20 > + EFI_SMM_SW_REGISTER_CONTEXT Context; >=20 > + EFI_SMM_HANDLER_ENTRY_POINT2 Callback; >=20 > +} SW_SMI_RECORD; >=20 > + >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSwSourceDesc =3D { >=20 > + PCH_SMM_NO_FLAGS, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_EN} >=20 > + }, >=20 > + S_ACPI_IO_SMI_EN, >=20 > + N_ACPI_IO_SMI_EN_APMC >=20 > + }, >=20 > + NULL_BIT_DESC_INITIALIZER >=20 > + }, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_APM >=20 > + } >=20 > + }, >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_APM >=20 > + } >=20 > +}; >=20 > + >=20 > +/** >=20 > + Check the SwSmiInputValue to see if there is a duplicated one in the > database >=20 > + >=20 > + @param[in] SwSmiInputValue SwSmiInputValue >=20 > + >=20 > + @retval EFI_SUCCESS There is no duplicated SwSmiInputValue >=20 > + @retval EFI_INVALID_PARAMETER There is a duplicated > SwSmiInputValue >=20 > +**/ >=20 > +EFI_STATUS >=20 > +SmiInputValueDuplicateCheck ( >=20 > + IN UINTN SwSmiInputValue >=20 > + ) >=20 > +{ >=20 > + SW_SMI_RECORD *SwSmiRecord; >=20 > + LIST_ENTRY *LinkInDb; >=20 > + >=20 > + LinkInDb =3D GetFirstNode (&mSwSmiCallbackDataBase); >=20 > + while (!IsNull (&mSwSmiCallbackDataBase, LinkInDb)) { >=20 > + SwSmiRecord =3D SW_SMI_RECORD_FROM_LINK (LinkInDb); >=20 > + if (SwSmiRecord->Context.SwSmiInputValue =3D=3D SwSmiInputValue) { >=20 > + return EFI_INVALID_PARAMETER; >=20 > + } >=20 > + LinkInDb =3D GetNextNode (&mSwSmiCallbackDataBase, &SwSmiRecord- > >Link); >=20 > + } >=20 > + >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > + >=20 > +/** >=20 > + Register a child SMI source dispatch function for the specified softwa= re > SMI. >=20 > + >=20 > + This service registers a function (DispatchFunction) which will be cal= led > when the software >=20 > + SMI source specified by RegisterContext->SwSmiCpuIndex is detected. On > return, >=20 > + DispatchHandle contains a unique handle which may be used later to > unregister the function >=20 > + using UnRegister(). >=20 > + >=20 > + @param[in] This Pointer to the > EFI_SMM_SW_DISPATCH2_PROTOCOL instance. >=20 > + @param[in] DispatchFunction Function to register for handler when= the > specified software >=20 > + SMI is generated. >=20 > + @param[in, out] RegisterContext Pointer to the dispatch function's > context. >=20 > + The caller fills this context in befo= re calling >=20 > + the register function to indicate to = the register >=20 > + function which Software SMI input val= ue the >=20 > + dispatch function should be invoked f= or. >=20 > + @param[out] DispatchHandle Handle generated by the dispatcher to > track the >=20 > + function instance. >=20 > + >=20 > + @retval EFI_SUCCESS The dispatch function has been successf= ully >=20 > + registered and the SMI source has been = enabled. >=20 > + @retval EFI_DEVICE_ERROR The SW driver was unable to enable the > SMI source. >=20 > + @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The SW SMI > input value >=20 > + is not within a valid range or is alrea= dy in use. >=20 > + @retval EFI_OUT_OF_RESOURCES There is not enough memory (system > or SMM) to manage this >=20 > + child. >=20 > + @retval EFI_OUT_OF_RESOURCES A unique software SMI value could not > be assigned >=20 > + for this dispatch. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchSwSmiRegister ( >=20 > + IN EFI_SMM_SW_DISPATCH2_PROTOCOL *This, >=20 > + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction, >=20 > + IN EFI_SMM_SW_REGISTER_CONTEXT *DispatchContext, >=20 > + OUT EFI_HANDLE *DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + SW_SMI_RECORD *SwSmiRecord; >=20 > + UINTN Index; >=20 > + >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock > event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + // >=20 > + // Find available SW SMI value if the input is -1 >=20 > + // >=20 > + if (DispatchContext->SwSmiInputValue =3D=3D (UINTN) -1) { >=20 > + for (Index =3D 1; Index < MAXIMUM_SWI_VALUE; Index++) { >=20 > + if (!EFI_ERROR (SmiInputValueDuplicateCheck (Index))) { >=20 > + DispatchContext->SwSmiInputValue =3D Index; >=20 > + break; >=20 > + } >=20 > + } >=20 > + if (DispatchContext->SwSmiInputValue =3D=3D (UINTN) -1) { >=20 > + return EFI_OUT_OF_RESOURCES; >=20 > + } >=20 > + } >=20 > + // >=20 > + // Check if it's a valid SW SMI value. >=20 > + // The value must not bigger than 0xFF. >=20 > + // And the value must not be 0xFF sincie it's used for SmmControll > protocol. >=20 > + // >=20 > + if (DispatchContext->SwSmiInputValue >=3D MAXIMUM_SWI_VALUE) { >=20 > + return EFI_INVALID_PARAMETER; >=20 > + } >=20 > + >=20 > + if (EFI_ERROR (SmiInputValueDuplicateCheck (DispatchContext- > >SwSmiInputValue))) { >=20 > + return EFI_INVALID_PARAMETER; >=20 > + } >=20 > + >=20 > + // >=20 > + // Create database record and add to database >=20 > + // >=20 > + Status =3D gSmst->SmmAllocatePool ( >=20 > + EfiRuntimeServicesData, >=20 > + sizeof (SW_SMI_RECORD), >=20 > + (VOID **) &SwSmiRecord >=20 > + ); >=20 > + if (EFI_ERROR (Status)) { >=20 > + DEBUG ((DEBUG_ERROR, "Failed to allocate memory for SwSmiRecord! > \n")); >=20 > + return EFI_OUT_OF_RESOURCES; >=20 > + } >=20 > + // >=20 > + // Gather information about the registration request >=20 > + // >=20 > + SwSmiRecord->Signature =3D SW_SMI_RECORD_SIGNATURE; >=20 > + SwSmiRecord->Context.SwSmiInputValue =3D DispatchContext- > >SwSmiInputValue; >=20 > + SwSmiRecord->Callback =3D DispatchFunction; >=20 > + // >=20 > + // Publish the S/W SMI numbers in Serial logs used for Debug build. >=20 > + // >=20 > + DEBUG ((DEBUG_INFO, "SW SMI NUM %x Sw Record at Address 0x%X\n", > SwSmiRecord->Context.SwSmiInputValue, SwSmiRecord)); >=20 > + >=20 > + InsertTailList (&mSwSmiCallbackDataBase, &SwSmiRecord->Link); >=20 > + >=20 > + // >=20 > + // Child's handle will be the address linked list link in the record >=20 > + // >=20 > + *DispatchHandle =3D (EFI_HANDLE) (&SwSmiRecord->Link); >=20 > + >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > + >=20 > +/** >=20 > + Unregister a child SMI source dispatch function for the specified soft= ware > SMI. >=20 > + >=20 > + This service removes the handler associated with DispatchHandle so tha= t it > will no longer be >=20 > + called in response to a software SMI. >=20 > + >=20 > + @param[in] This Pointer to the > EFI_SMM_SW_DISPATCH2_PROTOCOL instance. >=20 > + @param[in] DispatchHandle Handle of dispatch function to deregist= er. >=20 > + >=20 > + @retval EFI_SUCCESS The dispatch function has been successf= ully > unregistered. >=20 > + @retval EFI_INVALID_PARAMETER The DispatchHandle was not valid. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchSwSmiUnRegister ( >=20 > + IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL *This, >=20 > + IN EFI_HANDLE DispatchHandle >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + SW_SMI_RECORD *RecordToDelete; >=20 > + >=20 > + if (DispatchHandle =3D=3D 0) { >=20 > + return EFI_INVALID_PARAMETER; >=20 > + } >=20 > + >=20 > + // >=20 > + // Return access denied if the SmmReadyToLock event has been triggered >=20 > + // >=20 > + if (mReadyToLock =3D=3D TRUE) { >=20 > + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the > SmmReadyToLock event has been triggered! \n")); >=20 > + return EFI_ACCESS_DENIED; >=20 > + } >=20 > + >=20 > + RecordToDelete =3D SW_SMI_RECORD_FROM_LINK (DispatchHandle); >=20 > + // >=20 > + // Take the entry out of the linked list >=20 > + // >=20 > + if (RecordToDelete->Signature !=3D SW_SMI_RECORD_SIGNATURE) { >=20 > + return EFI_INVALID_PARAMETER; >=20 > + } >=20 > + >=20 > + RemoveEntryList (&RecordToDelete->Link); >=20 > + ZeroMem (RecordToDelete, sizeof (SW_SMI_RECORD)); >=20 > + Status =3D gSmst->SmmFreePool (RecordToDelete); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > + >=20 > +/** >=20 > + Main entry point for an SMM handler dispatch or communicate-based > callback. >=20 > + >=20 > + @param[in] DispatchHandle The unique handle assigned to this hand= ler > by SmiHandlerRegister(). >=20 > + @param[in] Context Points to an optional handler context w= hich was > specified when the >=20 > + handler was registered. >=20 > + @param[in,out] CommBuffer A pointer to a collection of data in > memory that will >=20 > + be conveyed from a non-SMM environment = into an SMM > environment. >=20 > + @param[in,out] CommBufferSize The size of the CommBuffer. >=20 > + >=20 > + @retval EFI_SUCCESS The interrupt was handled = and quiesced. > No other handlers >=20 > + should still be called. >=20 > + @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has > been quiesced but other handlers should >=20 > + still be called. >=20 > + @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still > pending and other handlers should still >=20 > + be called. >=20 > + @retval EFI_INTERRUPT_PENDING The interrupt could not be > quiesced. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +PchSwSmiDispatcher ( >=20 > + IN EFI_HANDLE DispatchHandle, >=20 > + IN CONST VOID *Context, >=20 > + IN OUT VOID *CommBuffer, >=20 > + IN OUT UINTN *CommBufferSize >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + EFI_SMM_SAVE_STATE_IO_INFO SmiIoInfo; >=20 > + UINTN CpuIndex; >=20 > + SW_SMI_RECORD *SwSmiRecord; >=20 > + LIST_ENTRY *LinkInDb; >=20 > + EFI_SMM_SW_CONTEXT SwSmiCommBuffer; >=20 > + UINTN SwSmiCommBufferSize; >=20 > + >=20 > + SwSmiCommBufferSize =3D sizeof (EFI_SMM_SW_CONTEXT); >=20 > + // >=20 > + // The value in DataPort might not be accurate in multiple thread > environment. >=20 > + // There might be racing condition for R_PCH_IO_APM_STS port. >=20 > + // Therefor, this is just for reference. >=20 > + // >=20 > + SwSmiCommBuffer.DataPort =3D IoRead8 (R_PCH_IO_APM_STS); >=20 > + >=20 > + for (CpuIndex =3D 0; CpuIndex < gSmst->NumberOfCpus; CpuIndex++) { >=20 > + Status =3D mSmmCpuProtocol->ReadSaveState ( >=20 > + mSmmCpuProtocol, >=20 > + sizeof (EFI_SMM_SAVE_STATE_IO_INFO), >=20 > + EFI_SMM_SAVE_STATE_REGISTER_IO, >=20 > + CpuIndex, >=20 > + &SmiIoInfo >=20 > + ); >=20 > + // >=20 > + // If this is not the SMI source, skip it. >=20 > + // >=20 > + if (EFI_ERROR (Status)) { >=20 > + continue; >=20 > + } >=20 > + // >=20 > + // If the IO address is not "BYTE" "WRITE" to "R_PCH_IO_APM_CNT > (0xB2)", skip it. >=20 > + // >=20 > + if ((SmiIoInfo.IoPort !=3D R_PCH_IO_APM_CNT) || >=20 > + (SmiIoInfo.IoType !=3D EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT) || >=20 > + (SmiIoInfo.IoWidth !=3D EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8)) >=20 > + { >=20 > + continue; >=20 > + } >=20 > + // >=20 > + // If the IO data is used for SmmControl protocol, skip it. >=20 > + // >=20 > + if (SmiIoInfo.IoData =3D=3D 0xFF) { >=20 > + continue; >=20 > + } >=20 > + >=20 > + SwSmiCommBuffer.SwSmiCpuIndex =3D CpuIndex; >=20 > + SwSmiCommBuffer.CommandPort =3D (UINT8) SmiIoInfo.IoData; >=20 > + >=20 > + LinkInDb =3D GetFirstNode (&mSwSmiCallbackDataBase); >=20 > + while (!IsNull (&mSwSmiCallbackDataBase, LinkInDb)) { >=20 > + SwSmiRecord =3D SW_SMI_RECORD_FROM_LINK (LinkInDb); >=20 > + if (SwSmiRecord->Context.SwSmiInputValue =3D=3D SmiIoInfo.IoData) = { >=20 > + SwSmiRecord->Callback ((EFI_HANDLE) &SwSmiRecord->Link, > &SwSmiRecord->Context, &SwSmiCommBuffer, &SwSmiCommBufferSize); >=20 > + } >=20 > + LinkInDb =3D GetNextNode (&mSwSmiCallbackDataBase, &SwSmiRecord- > >Link); >=20 > + } >=20 > + } >=20 > + >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > + >=20 > +/** >=20 > + Init required protocol for Pch Sw Dispatch protocol. >=20 > +**/ >=20 > +VOID >=20 > +PchSwDispatchInit ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + EFI_HANDLE DispatchHandle; >=20 > + DATABASE_RECORD Record; >=20 > + >=20 > + // >=20 > + // Locate PI SMM CPU protocol >=20 > + // >=20 > + Status =3D gSmst->SmmLocateProtocol (&gEfiSmmCpuProtocolGuid, NULL, > (VOID **)&mSmmCpuProtocol); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + // >=20 > + // Initialize SW SMI Callback DataBase >=20 > + // >=20 > + InitializeListHead (&mSwSmiCallbackDataBase); >=20 > + >=20 > + // >=20 > + // Insert SwSmi handler to PchSmmCore database >=20 > + // There will always be one SwType record in PchSmmCore database >=20 > + // >=20 > + ZeroMem (&Record, sizeof (DATABASE_RECORD)); >=20 > + Record.Signature =3D DATABASE_RECORD_SIGNATURE; >=20 > + Record.Callback =3D PchSwSmiDispatcher; >=20 > + Record.ProtocolType =3D SwType; >=20 > + >=20 > + CopyMem (&Record.SrcDesc, &mSwSourceDesc, sizeof > (PCH_SMM_SOURCE_DESC)); >=20 > + >=20 > + DispatchHandle =3D NULL; >=20 > + Status =3D SmmCoreInsertRecord ( >=20 > + &Record, >=20 > + &DispatchHandle >=20 > + ); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > +} >=20 > diff --git > a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSx.c > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSx.c > new file mode 100644 > index 0000000000..7d79f21dbd > --- /dev/null > +++ > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSx.c > @@ -0,0 +1,224 @@ > +/** @file >=20 > + File to contain all the hardware specific stuff for the Smm Sx dispatc= h > protocol. >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > +#include "PchSmmHelpers.h" >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include "PchSmiHelper.h" >=20 > + >=20 > +extern BOOLEAN mS3SusStart; >=20 > +#define PROGRESS_CODE_S3_SUSPEND_END PcdGet32 > (PcdProgressCodeS3SuspendEnd) >=20 > + >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mSxSourceDesc =3D { >=20 > + PCH_SMM_NO_FLAGS, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_EN} >=20 > + }, >=20 > + S_ACPI_IO_SMI_EN, >=20 > + N_ACPI_IO_SMI_EN_ON_SLP_EN >=20 > + }, >=20 > + NULL_BIT_DESC_INITIALIZER >=20 > + }, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_ON_SLP_EN >=20 > + } >=20 > + }, >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_ON_SLP_EN >=20 > + } >=20 > +}; >=20 > + >=20 > +/** >=20 > + Get the Sleep type >=20 > + >=20 > + @param[in] Record No use >=20 > + @param[out] Context The context that includes SLP_TYP bits= to be > filled >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +SxGetContext ( >=20 > + IN DATABASE_RECORD *Record, >=20 > + OUT PCH_SMM_CONTEXT *Context >=20 > + ) >=20 > +{ >=20 > + UINT32 Pm1Cnt; >=20 > + >=20 > + Pm1Cnt =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT)); >=20 > + >=20 > + /// >=20 > + /// By design, the context phase will always be ENTRY >=20 > + /// >=20 > + Context->Sx.Phase =3D SxEntry; >=20 > + >=20 > + /// >=20 > + /// Map the PM1_CNT register's SLP_TYP bits to the context type >=20 > + /// >=20 > + switch (Pm1Cnt & B_ACPI_IO_PM1_CNT_SLP_TYP) { >=20 > + case V_ACPI_IO_PM1_CNT_S0: >=20 > + Context->Sx.Type =3D SxS0; >=20 > + break; >=20 > + >=20 > + case V_ACPI_IO_PM1_CNT_S1: >=20 > + Context->Sx.Type =3D SxS1; >=20 > + break; >=20 > + >=20 > + case V_ACPI_IO_PM1_CNT_S3: >=20 > + Context->Sx.Type =3D SxS3; >=20 > + break; >=20 > + >=20 > + case V_ACPI_IO_PM1_CNT_S4: >=20 > + Context->Sx.Type =3D SxS4; >=20 > + break; >=20 > + >=20 > + case V_ACPI_IO_PM1_CNT_S5: >=20 > + Context->Sx.Type =3D SxS5; >=20 > + break; >=20 > + >=20 > + default: >=20 > + ASSERT (FALSE); >=20 > + break; >=20 > + } >=20 > +} >=20 > + >=20 > +/** >=20 > + Check whether sleep type of two contexts match >=20 > + >=20 > + @param[in] Context1 Context 1 that includes sleep type 1 >=20 > + @param[in] Context2 Context 2 that includes sleep type 2 >=20 > + >=20 > + @retval FALSE Sleep types match >=20 > + @retval TRUE Sleep types don't match >=20 > +**/ >=20 > +BOOLEAN >=20 > +EFIAPI >=20 > +SxCmpContext ( >=20 > + IN PCH_SMM_CONTEXT *Context1, >=20 > + IN PCH_SMM_CONTEXT *Context2 >=20 > + ) >=20 > +{ >=20 > + return (BOOLEAN) (Context1->Sx.Type =3D=3D Context2->Sx.Type); >=20 > +} >=20 > + >=20 > +/** >=20 > + For each PCIE RP clear PME SCI status and disable SCI, then > PCIEXP_WAKE_STS from PMC. >=20 > + This prevents platform from waking more than one time due to a single > PCIE wake event. >=20 > + Normally it's up to OS to clear SCI statuses. But in a scenario where > platform wakes >=20 > + and goes to S5 instead of booting to OS, the SCI status would remain s= et > and would trigger another wake. >=20 > +**/ >=20 > +VOID >=20 > +ClearPcieSci ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + UINT32 MaxPorts; >=20 > + UINT32 RpIndex; >=20 > + UINT64 RpBase; >=20 > + >=20 > + MaxPorts =3D GetPchMaxPciePortNum (); >=20 > + for (RpIndex =3D 0; RpIndex < MaxPorts; RpIndex++) { >=20 > + RpBase =3D PchPcieRpPciCfgBase (RpIndex); >=20 > + if (PciSegmentRead16 (RpBase + PCI_VENDOR_ID_OFFSET) !=3D 0xFFFF) { >=20 > + PciSegmentAnd8 ((RpBase + R_PCH_PCIE_CFG_MPC + 3), > (UINT8)~((UINT8)(B_PCH_PCIE_CFG_MPC_PMCE >> 24))); >=20 > + PciSegmentWrite32 (RpBase + R_PCH_PCIE_CFG_SMSCS, > B_PCH_PCIE_CFG_SMSCS_PMCS); >=20 > + } >=20 > + } >=20 > + IoWrite16 (mAcpiBaseAddr + R_ACPI_IO_PM1_STS, > B_ACPI_IO_PM1_STS_PCIEXP_WAKE_STS); >=20 > +} >=20 > + >=20 > + >=20 > +/** >=20 > + When we get an SMI that indicates that we are transitioning to a sleep > state, >=20 > + we need to actually transition to that state. We do this by disabling= the >=20 > + "SMI on sleep enable" feature, which generates an SMI when the > operating system >=20 > + tries to put the system to sleep, and then physically putting the syst= em to > sleep. >=20 > + >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +PchSmmSxGoToSleep ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + UINT32 Pm1Cnt; >=20 > + >=20 > + ClearPcieSci (); >=20 > + >=20 > + /// >=20 > + /// Disable SMIs >=20 > + /// >=20 > + PchSmmClearSource (&mSxSourceDesc); >=20 > + PchSmmDisableSource (&mSxSourceDesc); >=20 > + >=20 > + /// >=20 > + /// Get Power Management 1 Control Register Value >=20 > + /// >=20 > + Pm1Cnt =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT)); >=20 > + >=20 > + /// >=20 > + /// Record S3 suspend performance data >=20 > + /// >=20 > + if ((Pm1Cnt & B_ACPI_IO_PM1_CNT_SLP_TYP) =3D=3D > V_ACPI_IO_PM1_CNT_S3) { >=20 > + /// >=20 > + /// Report status code before goto S3 sleep >=20 > + /// >=20 > + REPORT_STATUS_CODE (EFI_PROGRESS_CODE, > PROGRESS_CODE_S3_SUSPEND_END); >=20 > + mS3SusStart =3D FALSE; >=20 > + /// >=20 > + /// Write back cache into memory and invalidate cache before going t= o > sleep. >=20 > + /// >=20 > + AsmWbinvd (); >=20 > + } >=20 > + >=20 > + /// >=20 > + /// Now that SMIs are disabled, write to the SLP_EN bit again to trigg= er the > sleep >=20 > + /// >=20 > + Pm1Cnt |=3D B_ACPI_IO_PM1_CNT_SLP_EN; >=20 > + >=20 > + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT), Pm1Cnt); >=20 > + >=20 > + /// >=20 > + /// Should only proceed if wake event is generated. >=20 > + /// >=20 > + if ((Pm1Cnt & B_ACPI_IO_PM1_CNT_SLP_TYP) =3D=3D > V_ACPI_IO_PM1_CNT_S1) { >=20 > + while (((IoRead16 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_STS))) & > B_ACPI_IO_PM1_STS_WAK) =3D=3D 0x0); >=20 > + } else { >=20 > + CpuDeadLoop (); >=20 > + } >=20 > + /// >=20 > + /// The system just went to sleep. If the sleep state was S1, then cod= e > execution will resume >=20 > + /// here when the system wakes up. >=20 > + /// >=20 > + Pm1Cnt =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT)); >=20 > + >=20 > + if ((Pm1Cnt & B_ACPI_IO_PM1_CNT_SCI_EN) =3D=3D 0) { >=20 > + /// >=20 > + /// An ACPI OS isn't present, clear the sleep information >=20 > + /// >=20 > + Pm1Cnt &=3D ~B_ACPI_IO_PM1_CNT_SLP_TYP; >=20 > + Pm1Cnt |=3D V_ACPI_IO_PM1_CNT_S0; >=20 > + >=20 > + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT), Pm1Cnt); >=20 > + } >=20 > + >=20 > + PchSmmClearSource (&mSxSourceDesc); >=20 > + PchSmmEnableSource (&mSxSourceDesc); >=20 > +} >=20 > diff --git > a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmUsb > .c > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmUsb > .c > new file mode 100644 > index 0000000000..a0c67bd959 > --- /dev/null > +++ > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmUsb > .c > @@ -0,0 +1,230 @@ > +/** @file >=20 > + File to contain all the hardware specific stuff for the Smm USB dispat= ch > protocol. >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > +#include "PchSmmHelpers.h" >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > + >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mUsb1Legacy =3D { >=20 > + PCH_SMM_NO_FLAGS, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_EN} >=20 > + }, >=20 > + S_ACPI_IO_SMI_EN, >=20 > + N_ACPI_IO_SMI_EN_LEGACY_USB >=20 > + }, >=20 > + NULL_BIT_DESC_INITIALIZER >=20 > + }, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_LEGACY_USB >=20 > + } >=20 > + }, >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_LEGACY_USB >=20 > + } >=20 > +}; >=20 > + >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC > mUsb3Legacy =3D { >=20 > + PCH_SMM_NO_FLAGS, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_EN} >=20 > + }, >=20 > + S_ACPI_IO_SMI_EN, >=20 > + N_ACPI_IO_SMI_EN_LEGACY_USB3 >=20 > + }, >=20 > + NULL_BIT_DESC_INITIALIZER >=20 > + }, >=20 > + { >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_LEGACY_USB3 >=20 > + } >=20 > + }, >=20 > + { >=20 > + { >=20 > + ACPI_ADDR_TYPE, >=20 > + {R_ACPI_IO_SMI_STS} >=20 > + }, >=20 > + S_ACPI_IO_SMI_STS, >=20 > + N_ACPI_IO_SMI_STS_LEGACY_USB3 >=20 > + } >=20 > +}; >=20 > + >=20 > +typedef enum { >=20 > + PchUsbControllerLpc0 =3D 0, >=20 > + PchUsbControllerXhci, >=20 > + PchUsbControllerTypeMax >=20 > +} PCH_USB_CONTROLLER_TYPE; >=20 > + >=20 > +typedef struct { >=20 > + UINT8 Function; >=20 > + UINT8 Device; >=20 > + PCH_USB_CONTROLLER_TYPE UsbConType; >=20 > +} USB_CONTROLLER; >=20 > + >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED USB_CONTROLLER > mUsbControllersMap[] =3D { >=20 > + { >=20 > + PCI_FUNCTION_NUMBER_PCH_LPC, >=20 > + PCI_DEVICE_NUMBER_PCH_LPC, >=20 > + PchUsbControllerLpc0 >=20 > + }, >=20 > + { >=20 > + PCI_FUNCTION_NUMBER_PCH_XHCI, >=20 > + PCI_DEVICE_NUMBER_PCH_XHCI, >=20 > + PchUsbControllerXhci >=20 > + } >=20 > +}; >=20 > + >=20 > +/** >=20 > + Find the handle that best matches the input Device Path and return the > USB controller type >=20 > + >=20 > + @param[in] DevicePath Pointer to the device Path table >=20 > + @param[out] Controller Returned with the USB controller type = of the > input device path >=20 > + >=20 > + @retval EFI_SUCCESS Find the handle that best matches the = input > Device Path >=20 > + @exception EFI_UNSUPPORTED Invalid device Path table or can't fin= d > any match USB device path >=20 > + PCH_USB_CONTROLLER_TYPE The USB contro= ller type of > the input >=20 > + device path >=20 > +**/ >=20 > +EFI_STATUS >=20 > +DevicePathToSupportedController ( >=20 > + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, >=20 > + OUT PCH_USB_CONTROLLER_TYPE *Controller >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + EFI_HANDLE DeviceHandle; >=20 > + ACPI_HID_DEVICE_PATH *AcpiNode; >=20 > + PCI_DEVICE_PATH *PciNode; >=20 > + EFI_DEVICE_PATH_PROTOCOL *RemaingDevicePath; >=20 > + UINT8 UsbIndex; >=20 > + /// >=20 > + /// Find the handle that best matches the Device Path. If it is only a >=20 > + /// partial match the remaining part of the device path is returned in >=20 > + /// RemainingDevicePath. >=20 > + /// >=20 > + RemaingDevicePath =3D DevicePath; >=20 > + Status =3D gBS->LocateDevicePath ( >=20 > + &gEfiPciRootBridgeIoProtocolGuid, >=20 > + &DevicePath, >=20 > + &DeviceHandle >=20 > + ); >=20 > + if (EFI_ERROR (Status)) { >=20 > + return EFI_UNSUPPORTED; >=20 > + } >=20 > + >=20 > + DevicePath =3D RemaingDevicePath; >=20 > + >=20 > + /// >=20 > + /// Get first node: Acpi Node >=20 > + /// >=20 > + AcpiNode =3D (ACPI_HID_DEVICE_PATH *) RemaingDevicePath; >=20 > + >=20 > + if (AcpiNode->Header.Type !=3D ACPI_DEVICE_PATH || >=20 > + AcpiNode->Header.SubType !=3D ACPI_DP || >=20 > + DevicePathNodeLength (&AcpiNode->Header) !=3D sizeof > (ACPI_HID_DEVICE_PATH) || >=20 > + AcpiNode->HID !=3D EISA_PNP_ID (0x0A03) || >=20 > + AcpiNode->UID !=3D 0 >=20 > + ) { >=20 > + return EFI_UNSUPPORTED; >=20 > + } else { >=20 > + /// >=20 > + /// Get the next node: Pci Node >=20 > + /// >=20 > + RemaingDevicePath =3D NextDevicePathNode (RemaingDevicePath); >=20 > + PciNode =3D (PCI_DEVICE_PATH *) RemaingDevicePath; >=20 > + if (PciNode->Header.Type !=3D HARDWARE_DEVICE_PATH || >=20 > + PciNode->Header.SubType !=3D HW_PCI_DP || >=20 > + DevicePathNodeLength (&PciNode->Header) !=3D sizeof > (PCI_DEVICE_PATH) >=20 > + ) { >=20 > + return EFI_UNSUPPORTED; >=20 > + } >=20 > + >=20 > + for (UsbIndex =3D 0; UsbIndex < sizeof (mUsbControllersMap) / sizeof > (USB_CONTROLLER); UsbIndex++) { >=20 > + if ((PciNode->Device =3D=3D mUsbControllersMap[UsbIndex].Device) &= & >=20 > + (PciNode->Function =3D=3D mUsbControllersMap[UsbIndex].Functio= n)) { >=20 > + *Controller =3D mUsbControllersMap[UsbIndex].UsbConType; >=20 > + return EFI_SUCCESS; >=20 > + } >=20 > + } >=20 > + >=20 > + return EFI_UNSUPPORTED; >=20 > + } >=20 > +} >=20 > + >=20 > +/** >=20 > + Maps a USB context to a source description. >=20 > + >=20 > + @param[in] Context The context we need to map. Type must= be > USB. >=20 > + @param[in] SrcDesc The source description that correspond= s to the > given context. >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +MapUsbToSrcDesc ( >=20 > + IN PCH_SMM_CONTEXT *Context, >=20 > + OUT PCH_SMM_SOURCE_DESC *SrcDesc >=20 > + ) >=20 > +{ >=20 > + PCH_USB_CONTROLLER_TYPE Controller; >=20 > + EFI_STATUS Status; >=20 > + >=20 > + Status =3D DevicePathToSupportedController (Context->Usb.Device, > &Controller); >=20 > + /// >=20 > + /// Either the device path passed in by the child is incorrect or >=20 > + /// the ones stored here internally are incorrect. >=20 > + /// >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + switch (Context->Usb.Type) { >=20 > + case UsbLegacy: >=20 > + switch (Controller) { >=20 > + case PchUsbControllerLpc0: >=20 > + CopyMem ((VOID *) SrcDesc, (VOID *) (&mUsb1Legacy), sizeof > (PCH_SMM_SOURCE_DESC)); >=20 > + break; >=20 > + >=20 > + case PchUsbControllerXhci: >=20 > + CopyMem ((VOID *) SrcDesc, (VOID *) (&mUsb3Legacy), sizeof > (PCH_SMM_SOURCE_DESC)); >=20 > + break; >=20 > + >=20 > + default: >=20 > + ASSERT (FALSE); >=20 > + break; >=20 > + } >=20 > + break; >=20 > + >=20 > + case UsbWake: >=20 > + ASSERT (FALSE); >=20 > + break; >=20 > + >=20 > + default: >=20 > + ASSERT (FALSE); >=20 > + break; >=20 > + } >=20 > +} >=20 > diff --git > a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHe > lpers.c > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHe > lpers.c > new file mode 100644 > index 0000000000..a0b7e37d46 > --- /dev/null > +++ > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHe > lpers.c > @@ -0,0 +1,778 @@ > +/** @file >=20 > + This driver is responsible for the registration of child drivers >=20 > + and the abstraction of the PCH SMI sources. >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > +#include "PchSmmHelpers.h" >=20 > +#include >=20 > +#include >=20 > + >=20 > +// >=20 > +// Help handle porting bit shifts to IA-64. >=20 > +// >=20 > +#define BIT_ZERO 0x00000001 >=20 > + >=20 > +/** >=20 > + Publish SMI Dispatch protocols. >=20 > + >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +PchSmmPublishDispatchProtocols ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status =3D EFI_SUCCESS; >=20 > + UINTN Index; >=20 > + // >=20 > + // Install protocol interfaces. >=20 > + // >=20 > + for (Index =3D 0; Index < PCH_SMM_PROTOCOL_TYPE_MAX; Index++) { >=20 > + Status =3D gSmst->SmmInstallProtocolInterface ( >=20 > + &mPrivateData.InstallMultProtHandle, >=20 > + mPrivateData.Protocols[Index].Guid, >=20 > + EFI_NATIVE_INTERFACE, >=20 > + &mPrivateData.Protocols[Index].Protocols.Generic >=20 > + ); >=20 > + } >=20 > + ASSERT_EFI_ERROR (Status); >=20 > +} >=20 > + >=20 > +/** >=20 > + Initialize bits that aren't necessarily related to an SMI source. >=20 > + >=20 > + >=20 > + @retval EFI_SUCCESS SMI source initialization completed. >=20 > + @retval Asserts Global Smi Bit is not enabled successf= ully. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +PchSmmInitHardware ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + >=20 > + // >=20 > + // Clear all SMIs >=20 > + // >=20 > + PchSmmClearSmi (); >=20 > + >=20 > + Status =3D PchSmmEnableGlobalSmiBit (); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + // >=20 > + // Be *really* sure to clear all SMIs >=20 > + // >=20 > + PchSmmClearSmi (); >=20 > + >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > + >=20 > +/** >=20 > + Enables the PCH to generate SMIs. Note that no SMIs will be generated >=20 > + if no SMI sources are enabled. Conversely, no enabled SMI source will >=20 > + generate SMIs if SMIs are not globally enabled. This is the main >=20 > + switchbox for SMI generation. >=20 > + >=20 > + >=20 > + @retval EFI_SUCCESS Enable Global Smi Bit completed >=20 > +**/ >=20 > +EFI_STATUS >=20 > +PchSmmEnableGlobalSmiBit ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + UINT32 SmiEn; >=20 > + >=20 > + SmiEn =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN)); >=20 > + >=20 > + // >=20 > + // Set the "global smi enable" bit >=20 > + // >=20 > + SmiEn |=3D B_ACPI_IO_SMI_EN_GBL_SMI; >=20 > + >=20 > + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN), SmiEn); >=20 > + >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > + >=20 > +/** >=20 > + Clears the SMI after all SMI source have been processed. >=20 > + Note that this function will not work correctly (as it is >=20 > + written) unless all SMI sources have been processed. >=20 > + A revision of this function could manually clear all SMI >=20 > + status bits to guarantee success. >=20 > + >=20 > + >=20 > + @retval EFI_SUCCESS Clears the SMIs completed >=20 > + @retval Asserts EOS was not set to a 1 >=20 > +**/ >=20 > +EFI_STATUS >=20 > +PchSmmClearSmi ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + BOOLEAN EosSet; >=20 > + BOOLEAN SciEn; >=20 > + UINT32 Pm1Cnt; >=20 > + UINT16 Pm1Sts; >=20 > + UINT32 Gpe0Sts; >=20 > + UINT32 SmiSts; >=20 > + UINT16 DevActSts; >=20 > + UINT16 Tco1Sts; >=20 > + >=20 > + Gpe0Sts =3D 0; >=20 > + // >=20 > + // Determine whether an ACPI OS is present (via the SCI_EN bit) >=20 > + // >=20 > + Pm1Cnt =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT)); >=20 > + SciEn =3D (BOOLEAN) ((Pm1Cnt & B_ACPI_IO_PM1_CNT_SCI_EN) =3D=3D > B_ACPI_IO_PM1_CNT_SCI_EN); >=20 > + if (!SciEn) { >=20 > + // >=20 > + // Clear any SMIs that double as SCIs (when SCI_EN=3D=3D0) >=20 > + // >=20 > + Pm1Sts =3D IoRead16 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_STS)); >=20 > + Gpe0Sts =3D IoRead32 ((UINTN) (mAcpiBaseAddr + > R_ACPI_IO_GPE0_STS_127_96)); >=20 > + >=20 > + Pm1Sts |=3D >=20 > + ( >=20 > + B_ACPI_IO_PM1_STS_WAK | >=20 > + B_ACPI_IO_PM1_STS_PRBTNOR | >=20 > + B_ACPI_IO_PM1_STS_RTC | >=20 > + B_ACPI_IO_PM1_STS_PWRBTN | >=20 > + B_ACPI_IO_PM1_STS_GBL | >=20 > + B_ACPI_IO_PM1_STS_TMROF >=20 > + ); >=20 > + >=20 > + Gpe0Sts |=3D >=20 > + ( >=20 > + B_ACPI_IO_GPE0_STS_127_96_WADT | >=20 > + B_ACPI_IO_GPE0_STS_127_96_USB_CON_DSX_STS | >=20 > + B_ACPI_IO_GPE0_STS_127_96_LAN_WAKE | >=20 > + B_ACPI_IO_GPE0_STS_127_96_PME_B0 | >=20 > + B_ACPI_IO_GPE0_STS_127_96_PME | >=20 > + B_ACPI_IO_GPE0_STS_127_96_BATLOW | >=20 > + B_ACPI_IO_GPE0_STS_127_96_RI | >=20 > + B_ACPI_IO_GPE0_STS_127_96_SWGPE >=20 > + ); >=20 > + >=20 > + IoWrite16 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_STS), (UINT16) > Pm1Sts); >=20 > + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_GPE0_STS_127_96), > (UINT32) Gpe0Sts); >=20 > + } >=20 > + // >=20 > + // Clear all SMIs that are unaffected by SCI_EN >=20 > + // >=20 > + SmiSts =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_STS= )); >=20 > + DevActSts =3D IoRead16 ((UINTN) (mAcpiBaseAddr + > R_ACPI_IO_DEVACT_STS)); >=20 > + Tco1Sts =3D IoRead16 ((UINTN) (mTcoBaseAddr + R_TCO_IO_TCO1_STS)= ); >=20 > + >=20 > + SmiSts |=3D >=20 > + ( >=20 > + B_ACPI_IO_SMI_STS_SMBUS | >=20 > + B_ACPI_IO_SMI_STS_PERIODIC | >=20 > + B_ACPI_IO_SMI_STS_TCO | >=20 > + B_ACPI_IO_SMI_STS_MCSMI | >=20 > + B_ACPI_IO_SMI_STS_SWSMI_TMR | >=20 > + B_ACPI_IO_SMI_STS_APM | >=20 > + B_ACPI_IO_SMI_STS_ON_SLP_EN | >=20 > + B_ACPI_IO_SMI_STS_BIOS >=20 > + ); >=20 > + DevActSts |=3D >=20 > + ( >=20 > + B_ACPI_IO_DEVACT_STS_KBC | >=20 > + B_ACPI_IO_DEVACT_STS_PIRQDH | >=20 > + B_ACPI_IO_DEVACT_STS_PIRQCG | >=20 > + B_ACPI_IO_DEVACT_STS_PIRQBF | >=20 > + B_ACPI_IO_DEVACT_STS_PIRQAE >=20 > + ); >=20 > + Tco1Sts |=3D >=20 > + ( >=20 > + B_TCO_IO_TCO1_STS_DMISERR | >=20 > + B_TCO_IO_TCO1_STS_DMISMI | >=20 > + B_TCO_IO_TCO1_STS_DMISCI | >=20 > + B_TCO_IO_TCO1_STS_BIOSWR | >=20 > + B_TCO_IO_TCO1_STS_NEWCENTURY | >=20 > + B_TCO_IO_TCO1_STS_TIMEOUT | >=20 > + B_TCO_IO_TCO1_STS_TCO_INT | >=20 > + B_TCO_IO_TCO1_STS_SW_TCO_SMI >=20 > + ); >=20 > + >=20 > + GpioClearAllGpiSmiSts (); >=20 > + >=20 > + IoWrite16 ((UINTN) (mTcoBaseAddr + R_TCO_IO_TCO1_STS), Tco1Sts); >=20 > + >=20 > + // >=20 > + // We do not want to write 1 to clear INTRD_DET bit. >=20 > + // >=20 > + IoWrite16 ((UINTN) (mTcoBaseAddr + R_TCO_IO_TCO2_STS), (UINT16) > ~B_TCO_IO_TCO2_STS_INTRD_DET); >=20 > + >=20 > + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_STS), SmiSts); >=20 > + >=20 > + IoWrite16 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_DEVACT_STS), > DevActSts); >=20 > + >=20 > + // >=20 > + // Try to clear the EOS bit. ASSERT on an error >=20 > + // >=20 > + EosSet =3D PchSmmSetAndCheckEos (); >=20 > + ASSERT (EosSet); >=20 > + >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > + >=20 > +/** >=20 > + Set the SMI EOS bit after all SMI source have been processed. >=20 > + >=20 > + >=20 > + @retval FALSE EOS was not set to a 1; this is an err= or >=20 > + @retval TRUE EOS was correctly set to a 1 >=20 > +**/ >=20 > +BOOLEAN >=20 > +PchSmmSetAndCheckEos ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + UINT32 SmiEn; >=20 > + >=20 > + SmiEn =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN)); >=20 > + >=20 > + // >=20 > + // Reset the PCH to generate subsequent SMIs >=20 > + // >=20 > + SmiEn |=3D B_ACPI_IO_SMI_EN_EOS; >=20 > + >=20 > + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN), SmiEn); >=20 > + >=20 > + // >=20 > + // Double check that the assert worked >=20 > + // >=20 > + SmiEn =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN)); >=20 > + >=20 > + // >=20 > + // Return TRUE if EOS is set correctly >=20 > + // >=20 > + if ((SmiEn & B_ACPI_IO_SMI_EN_EOS) =3D=3D 0) { >=20 > + // >=20 > + // EOS was not set to a 1; this is an error >=20 > + // >=20 > + return FALSE; >=20 > + } else { >=20 > + // >=20 > + // EOS was correctly set to a 1 >=20 > + // >=20 > + return TRUE; >=20 > + } >=20 > +} >=20 > + >=20 > +/** >=20 > + Determine whether an ACPI OS is present (via the SCI_EN bit) >=20 > + >=20 > + >=20 > + @retval TRUE ACPI OS is present >=20 > + @retval FALSE ACPI OS is not present >=20 > +**/ >=20 > +BOOLEAN >=20 > +PchSmmGetSciEn ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + BOOLEAN SciEn; >=20 > + UINT32 Pm1Cnt; >=20 > + >=20 > + // >=20 > + // Determine whether an ACPI OS is present (via the SCI_EN bit) >=20 > + // >=20 > + Pm1Cnt =3D IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT)); >=20 > + SciEn =3D (BOOLEAN) ((Pm1Cnt & B_ACPI_IO_PM1_CNT_SCI_EN) =3D=3D > B_ACPI_IO_PM1_CNT_SCI_EN); >=20 > + >=20 > + return SciEn; >=20 > +} >=20 > + >=20 > +/** >=20 > + Read a specifying bit with the register >=20 > + These may or may not need to change w/ the PCH version; they're highly > IA-32 dependent, though. >=20 > + >=20 > + @param[in] BitDesc The struct that includes register addr= ess, size in > byte and bit number >=20 > + >=20 > + @retval TRUE The bit is enabled >=20 > + @retval FALSE The bit is disabled >=20 > +**/ >=20 > +BOOLEAN >=20 > +ReadBitDesc ( >=20 > + CONST PCH_SMM_BIT_DESC *BitDesc >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + UINT64 Register; >=20 > + UINT32 PciBus; >=20 > + UINT32 PciDev; >=20 > + UINT32 PciFun; >=20 > + UINT32 PciReg; >=20 > + UINTN RegSize; >=20 > + BOOLEAN BitWasOne; >=20 > + UINTN ShiftCount; >=20 > + UINTN RegisterOffset; >=20 > + UINT32 BaseAddr; >=20 > + UINT64 PciBaseAddress; >=20 > + >=20 > + ASSERT (BitDesc !=3D NULL); >=20 > + ASSERT (!IS_BIT_DESC_NULL (*BitDesc)); >=20 > + >=20 > + RegSize =3D 0; >=20 > + Register =3D 0; >=20 > + ShiftCount =3D 0; >=20 > + BitWasOne =3D FALSE; >=20 > + >=20 > + switch (BitDesc->Reg.Type) { >=20 > + >=20 > + case ACPI_ADDR_TYPE: >=20 > + case TCO_ADDR_TYPE: >=20 > + if (BitDesc->Reg.Type =3D=3D ACPI_ADDR_TYPE) { >=20 > + RegisterOffset =3D BitDesc->Reg.Data.acpi; >=20 > + BaseAddr =3D mAcpiBaseAddr; >=20 > + } else { >=20 > + RegisterOffset =3D BitDesc->Reg.Data.tco; >=20 > + BaseAddr =3D mTcoBaseAddr; >=20 > + } >=20 > + switch (BitDesc->SizeInBytes) { >=20 > + >=20 > + case 0: >=20 > + // >=20 > + // Chances are that this field didn't get initialized. >=20 > + // Check your assignments to bit descriptions. >=20 > + // >=20 > + ASSERT (FALSE); >=20 > + break; >=20 > + >=20 > + case 1: >=20 > + RegSize =3D SMM_IO_UINT8; >=20 > + break; >=20 > + >=20 > + case 2: >=20 > + RegSize =3D SMM_IO_UINT16; >=20 > + break; >=20 > + >=20 > + case 4: >=20 > + RegSize =3D SMM_IO_UINT32; >=20 > + break; >=20 > + >=20 > + case 8: >=20 > + RegSize =3D SMM_IO_UINT64; >=20 > + break; >=20 > + >=20 > + default: >=20 > + // >=20 > + // Unsupported or invalid register size >=20 > + // >=20 > + ASSERT (FALSE); >=20 > + break; >=20 > + } >=20 > + // >=20 > + // Double check that we correctly read in the acpi base address >=20 > + // >=20 > + ASSERT ((BaseAddr !=3D 0x0) && ((BaseAddr & 0x1) !=3D 0x1)); >=20 > + >=20 > + ShiftCount =3D BitDesc->Bit; >=20 > + // >=20 > + // As current CPU Smm Io can only support at most >=20 > + // 32-bit read/write,if Operation is 64 bit, >=20 > + // we do a 32 bit operation according to BitDesc->Bit >=20 > + // >=20 > + if (RegSize =3D=3D SMM_IO_UINT64) { >=20 > + RegSize =3D SMM_IO_UINT32; >=20 > + // >=20 > + // If the operation is for high 32 bits >=20 > + // >=20 > + if (BitDesc->Bit >=3D 32) { >=20 > + RegisterOffset +=3D 4; >=20 > + ShiftCount -=3D 32; >=20 > + } >=20 > + } >=20 > + >=20 > + Status =3D gSmst->SmmIo.Io.Read ( >=20 > + &gSmst->SmmIo, >=20 > + RegSize, >=20 > + BaseAddr + RegisterOffset, >=20 > + 1, >=20 > + &Register >=20 > + ); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + if ((Register & (LShiftU64 (BIT_ZERO, ShiftCount))) !=3D 0) { >=20 > + BitWasOne =3D TRUE; >=20 > + } else { >=20 > + BitWasOne =3D FALSE; >=20 > + } >=20 > + break; >=20 > + >=20 > + case GPIO_ADDR_TYPE: >=20 > + case MEMORY_MAPPED_IO_ADDRESS_TYPE: >=20 > + // >=20 > + // Read the register, and it with the bit to read >=20 > + // >=20 > + switch (BitDesc->SizeInBytes) { >=20 > + case 1: >=20 > + Register =3D (UINT64) MmioRead8 ((UINTN) BitDesc->Reg.Data.Mmi= o); >=20 > + break; >=20 > + >=20 > + case 2: >=20 > + Register =3D (UINT64) MmioRead16 ((UINTN) BitDesc->Reg.Data.Mm= io); >=20 > + break; >=20 > + >=20 > + case 4: >=20 > + Register =3D (UINT64) MmioRead32 ((UINTN) BitDesc->Reg.Data.Mm= io); >=20 > + break; >=20 > + >=20 > + case 8: >=20 > + Register =3D (UINT64) MmioRead32 ((UINTN)= BitDesc- > >Reg.Data.Mmio); >=20 > + *((UINT32 *) (&Register) + 1) =3D MmioRead32 ((UINTN) BitDesc- > >Reg.Data.Mmio + 4); >=20 > + break; >=20 > + >=20 > + default: >=20 > + // >=20 > + // Unsupported or invalid register size >=20 > + // >=20 > + ASSERT (FALSE); >=20 > + break; >=20 > + } >=20 > + >=20 > + Register =3D Register & (LShiftU64 (BIT0, BitDesc->Bit)); >=20 > + if (Register) { >=20 > + BitWasOne =3D TRUE; >=20 > + } else { >=20 > + BitWasOne =3D FALSE; >=20 > + } >=20 > + break; >=20 > + >=20 > + case PCIE_ADDR_TYPE: >=20 > + PciBus =3D BitDesc->Reg.Data.pcie.Fields.Bus; >=20 > + PciDev =3D BitDesc->Reg.Data.pcie.Fields.Dev; >=20 > + PciFun =3D BitDesc->Reg.Data.pcie.Fields.Fnc; >=20 > + PciReg =3D BitDesc->Reg.Data.pcie.Fields.Reg; >=20 > + PciBaseAddress =3D PCI_SEGMENT_LIB_ADDRESS > (DEFAULT_PCI_SEGMENT_NUMBER_PCH, PciBus, PciDev, PciFun, 0); >=20 > + switch (BitDesc->SizeInBytes) { >=20 > + >=20 > + case 0: >=20 > + // >=20 > + // Chances are that this field didn't get initialized. >=20 > + // Check your assignments to bit descriptions. >=20 > + // >=20 > + ASSERT (FALSE); >=20 > + break; >=20 > + >=20 > + case 1: >=20 > + Register =3D (UINT64) PciSegmentRead8 (PciBaseAddress + PciReg= ); >=20 > + break; >=20 > + >=20 > + case 2: >=20 > + Register =3D (UINT64) PciSegmentRead16 (PciBaseAddress + PciRe= g); >=20 > + break; >=20 > + >=20 > + case 4: >=20 > + Register =3D (UINT64) PciSegmentRead32 (PciBaseAddress + PciRe= g); >=20 > + break; >=20 > + >=20 > + default: >=20 > + // >=20 > + // Unsupported or invalid register size >=20 > + // >=20 > + ASSERT (FALSE); >=20 > + break; >=20 > + } >=20 > + >=20 > + if ((Register & (LShiftU64 (BIT_ZERO, BitDesc->Bit))) !=3D 0) { >=20 > + BitWasOne =3D TRUE; >=20 > + } else { >=20 > + BitWasOne =3D FALSE; >=20 > + } >=20 > + break; >=20 > + >=20 > + case PCR_ADDR_TYPE: >=20 > + // >=20 > + // Read the register, and it with the bit to read >=20 > + // >=20 > + switch (BitDesc->SizeInBytes) { >=20 > + case 1: >=20 > + Register =3D PchPcrRead8 (BitDesc->Reg.Data.Pcr.Fields.Pid, B= itDesc- > >Reg.Data.Pcr.Fields.Offset); >=20 > + break; >=20 > + >=20 > + case 2: >=20 > + Register =3D PchPcrRead16 (BitDesc->Reg.Data.Pcr.Fields.Pid, B= itDesc- > >Reg.Data.Pcr.Fields.Offset); >=20 > + break; >=20 > + >=20 > + case 4: >=20 > + Register =3D PchPcrRead32 (BitDesc->Reg.Data.Pcr.Fields.Pid, B= itDesc- > >Reg.Data.Pcr.Fields.Offset); >=20 > + break; >=20 > + >=20 > + default: >=20 > + // >=20 > + // Unsupported or invalid register size >=20 > + // >=20 > + ASSERT (FALSE); >=20 > + break; >=20 > + } >=20 > + >=20 > + Register =3D Register & (LShiftU64 (BIT0, BitDesc->Bit)); >=20 > + if (Register) { >=20 > + BitWasOne =3D TRUE; >=20 > + } else { >=20 > + BitWasOne =3D FALSE; >=20 > + } >=20 > + break; >=20 > + >=20 > + default: >=20 > + // >=20 > + // This address type is not yet implemented >=20 > + // >=20 > + ASSERT (FALSE); >=20 > + break; >=20 > + } >=20 > + >=20 > + return BitWasOne; >=20 > +} >=20 > + >=20 > +/** >=20 > + Write a specifying bit with the register >=20 > + >=20 > + @param[in] BitDesc The struct that includes register addr= ess, size in > byte and bit number >=20 > + @param[in] ValueToWrite The value to be wrote >=20 > + @param[in] WriteClear If the rest bits of the register is wr= ite clear >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +WriteBitDesc ( >=20 > + CONST PCH_SMM_BIT_DESC *BitDesc, >=20 > + CONST BOOLEAN ValueToWrite, >=20 > + CONST BOOLEAN WriteClear >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + UINT64 Register; >=20 > + UINT64 AndVal; >=20 > + UINT64 OrVal; >=20 > + UINT32 RegSize; >=20 > + UINT32 PciBus; >=20 > + UINT32 PciDev; >=20 > + UINT32 PciFun; >=20 > + UINT32 PciReg; >=20 > + UINTN RegisterOffset; >=20 > + UINT32 BaseAddr; >=20 > + UINT64 PciBaseAddress; >=20 > + >=20 > + ASSERT (BitDesc !=3D NULL); >=20 > + ASSERT (!IS_BIT_DESC_NULL (*BitDesc)); >=20 > + >=20 > + RegSize =3D 0; >=20 > + Register =3D 0; >=20 > + >=20 > + if (WriteClear) { >=20 > + AndVal =3D LShiftU64 (BIT_ZERO, BitDesc->Bit); >=20 > + } else { >=20 > + AndVal =3D ~(LShiftU64 (BIT_ZERO, BitDesc->Bit)); >=20 > + } >=20 > + >=20 > + OrVal =3D (LShiftU64 ((UINT32) ValueToWrite, BitDesc->Bit)); >=20 > + >=20 > + switch (BitDesc->Reg.Type) { >=20 > + >=20 > + case ACPI_ADDR_TYPE: >=20 > + case TCO_ADDR_TYPE: >=20 > + if (BitDesc->Reg.Type =3D=3D ACPI_ADDR_TYPE) { >=20 > + RegisterOffset =3D BitDesc->Reg.Data.acpi; >=20 > + BaseAddr =3D mAcpiBaseAddr; >=20 > + } else { >=20 > + RegisterOffset =3D BitDesc->Reg.Data.tco; >=20 > + BaseAddr =3D mTcoBaseAddr; >=20 > + } >=20 > + >=20 > + switch (BitDesc->SizeInBytes) { >=20 > + >=20 > + case 0: >=20 > + // >=20 > + // Chances are that this field didn't get initialized. >=20 > + // Check your assignments to bit descriptions. >=20 > + // >=20 > + ASSERT (FALSE); >=20 > + break; >=20 > + >=20 > + case 1: >=20 > + RegSize =3D SMM_IO_UINT8; >=20 > + break; >=20 > + >=20 > + case 2: >=20 > + RegSize =3D SMM_IO_UINT16; >=20 > + break; >=20 > + >=20 > + case 4: >=20 > + RegSize =3D SMM_IO_UINT32; >=20 > + break; >=20 > + >=20 > + case 8: >=20 > + RegSize =3D SMM_IO_UINT64; >=20 > + break; >=20 > + >=20 > + default: >=20 > + // >=20 > + // Unsupported or invalid register size >=20 > + // >=20 > + ASSERT (FALSE); >=20 > + break; >=20 > + } >=20 > + // >=20 > + // Double check that we correctly read in the acpi base address >=20 > + // >=20 > + ASSERT ((BaseAddr !=3D 0x0) && ((BaseAddr & 0x1) !=3D 0x1)); >=20 > + >=20 > + // >=20 > + // As current CPU Smm Io can only support at most >=20 > + // 32-bit read/write,if Operation is 64 bit, >=20 > + // we do a 32 bit operation according to BitDesc->Bit >=20 > + // >=20 > + if (RegSize =3D=3D SMM_IO_UINT64) { >=20 > + RegSize =3D SMM_IO_UINT32; >=20 > + // >=20 > + // If the operation is for high 32 bits >=20 > + // >=20 > + if (BitDesc->Bit >=3D 32) { >=20 > + RegisterOffset +=3D 4; >=20 > + >=20 > + if (WriteClear) { >=20 > + AndVal =3D LShiftU64 (BIT_ZERO, BitDesc->Bit - 32); >=20 > + } else { >=20 > + AndVal =3D ~(LShiftU64 (BIT_ZERO, BitDesc->Bit - 32)); >=20 > + } >=20 > + >=20 > + OrVal =3D LShiftU64 ((UINT32) ValueToWrite, BitDesc->Bit - 32)= ; >=20 > + } >=20 > + } >=20 > + >=20 > + Status =3D gSmst->SmmIo.Io.Read ( >=20 > + &gSmst->SmmIo, >=20 > + RegSize, >=20 > + BaseAddr + RegisterOffset, >=20 > + 1, >=20 > + &Register >=20 > + ); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + >=20 > + Register &=3D AndVal; >=20 > + Register |=3D OrVal; >=20 > + >=20 > + Status =3D gSmst->SmmIo.Io.Write ( >=20 > + &gSmst->SmmIo, >=20 > + RegSize, >=20 > + BaseAddr + RegisterOffset, >=20 > + 1, >=20 > + &Register >=20 > + ); >=20 > + ASSERT_EFI_ERROR (Status); >=20 > + break; >=20 > + >=20 > + case GPIO_ADDR_TYPE: >=20 > + case MEMORY_MAPPED_IO_ADDRESS_TYPE: >=20 > + // >=20 > + // Read the register, or it with the bit to set, then write it bac= k. >=20 > + // >=20 > + switch (BitDesc->SizeInBytes) { >=20 > + case 1: >=20 > + MmioAndThenOr8 ((UINTN) BitDesc->Reg.Data.Mmio, (UINT8) > AndVal, (UINT8) OrVal); >=20 > + break; >=20 > + >=20 > + case 2: >=20 > + MmioAndThenOr16 ((UINTN) BitDesc->Reg.Data.Mmio, (UINT16) > AndVal, (UINT16) OrVal); >=20 > + break; >=20 > + >=20 > + case 4: >=20 > + MmioAndThenOr32 ((UINTN) BitDesc->Reg.Data.Mmio, (UINT32) > AndVal, (UINT32) OrVal); >=20 > + break; >=20 > + >=20 > + case 8: >=20 > + Register =3D (UINT64) MmioRead32 ((UINTN)= BitDesc- > >Reg.Data.Mmio); >=20 > + *((UINT32 *) (&Register) + 1) =3D MmioRead32 ((UINTN) BitDesc- > >Reg.Data.Mmio + 4); >=20 > + Register &=3D AndVal; >=20 > + Register |=3D OrVal; >=20 > + MmioWrite32 ((UINTN) BitDesc->Reg.Data.Mmio, (UINT32) Register= ); >=20 > + MmioWrite32 ((UINTN) BitDesc->Reg.Data.Mmio + 4, *((UINT32 *) > (&Register) + 1)); >=20 > + break; >=20 > + >=20 > + default: >=20 > + // >=20 > + // Unsupported or invalid register size >=20 > + // >=20 > + ASSERT (FALSE); >=20 > + break; >=20 > + } >=20 > + break; >=20 > + >=20 > + case PCIE_ADDR_TYPE: >=20 > + PciBus =3D BitDesc->Reg.Data.pcie.Fields.Bus; >=20 > + PciDev =3D BitDesc->Reg.Data.pcie.Fields.Dev; >=20 > + PciFun =3D BitDesc->Reg.Data.pcie.Fields.Fnc; >=20 > + PciReg =3D BitDesc->Reg.Data.pcie.Fields.Reg; >=20 > + PciBaseAddress =3D PCI_SEGMENT_LIB_ADDRESS > (DEFAULT_PCI_SEGMENT_NUMBER_PCH, PciBus, PciDev, PciFun, 0); >=20 > + switch (BitDesc->SizeInBytes) { >=20 > + >=20 > + case 0: >=20 > + // >=20 > + // Chances are that this field didn't get initialized -- check= your > assignments >=20 > + // to bit descriptions. >=20 > + // >=20 > + ASSERT (FALSE); >=20 > + break; >=20 > + >=20 > + case 1: >=20 > + PciSegmentAndThenOr8 (PciBaseAddress + PciReg, (UINT8) AndVal, > (UINT8) OrVal); >=20 > + break; >=20 > + >=20 > + case 2: >=20 > + PciSegmentAndThenOr16 (PciBaseAddress + PciReg, (UINT16) AndVa= l, > (UINT16) OrVal); >=20 > + break; >=20 > + >=20 > + case 4: >=20 > + PciSegmentAndThenOr32 (PciBaseAddress + PciReg, (UINT32) AndVa= l, > (UINT32) OrVal); >=20 > + break; >=20 > + >=20 > + default: >=20 > + // >=20 > + // Unsupported or invalid register size >=20 > + // >=20 > + ASSERT (FALSE); >=20 > + break; >=20 > + } >=20 > + break; >=20 > + >=20 > + case PCR_ADDR_TYPE: >=20 > + // >=20 > + // Read the register, or it with the bit to set, then write it bac= k. >=20 > + // >=20 > + switch (BitDesc->SizeInBytes) { >=20 > + case 1: >=20 > + PchPcrAndThenOr8 ((PCH_SBI_PID) BitDesc->Reg.Data.Pcr.Fields.= Pid, > (UINT16) BitDesc->Reg.Data.Pcr.Fields.Offset, (UINT8) AndVal, (UINT8) > OrVal); >=20 > + break; >=20 > + >=20 > + case 2: >=20 > + PchPcrAndThenOr16 ((PCH_SBI_PID) BitDesc->Reg.Data.Pcr.Fields.= Pid, > (UINT16) BitDesc->Reg.Data.Pcr.Fields.Offset, (UINT16) AndVal, (UINT16) > OrVal); >=20 > + break; >=20 > + >=20 > + case 4: >=20 > + PchPcrAndThenOr32 ((PCH_SBI_PID) BitDesc->Reg.Data.Pcr.Fields.= Pid, > (UINT16) BitDesc->Reg.Data.Pcr.Fields.Offset, (UINT32) AndVal, (UINT32) > OrVal); >=20 > + break; >=20 > + >=20 > + default: >=20 > + // >=20 > + // Unsupported or invalid register size >=20 > + // >=20 > + ASSERT (FALSE); >=20 > + break; >=20 > + } >=20 > + break; >=20 > + >=20 > + default: >=20 > + // >=20 > + // This address type is not yet implemented >=20 > + // >=20 > + ASSERT (FALSE); >=20 > + break; >=20 > + } >=20 > +} >=20 > diff --git > a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHe > lpers.h > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHe > lpers.h > new file mode 100644 > index 0000000000..6dd6f2027d > --- /dev/null > +++ > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHe > lpers.h > @@ -0,0 +1,107 @@ > +/** @file >=20 > + This driver is responsible for the registration of child drivers >=20 > + and the abstraction of the PCH SMI sources. >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > +#ifndef _PCHX_SMM_HELPERS_H_ >=20 > +#define _PCHX_SMM_HELPERS_H_ >=20 > + >=20 > +#include "PchSmm.h" >=20 > + >=20 > +/** >=20 > + Initialize bits that aren't necessarily related to an SMI source. >=20 > + >=20 > + >=20 > + @retval EFI_SUCCESS SMI source initialization completed. >=20 > + @retval Asserts Global Smi Bit is not enabled successf= ully. >=20 > +**/ >=20 > +EFI_STATUS >=20 > +PchSmmInitHardware ( >=20 > + VOID >=20 > + ); >=20 > + >=20 > +/** >=20 > + Enables the PCH to generate SMIs. Note that no SMIs will be generated >=20 > + if no SMI sources are enabled. Conversely, no enabled SMI source will >=20 > + generate SMIs if SMIs are not globally enabled. This is the main >=20 > + switchbox for SMI generation. >=20 > + >=20 > + >=20 > + @retval EFI_SUCCESS Enable Global Smi Bit completed >=20 > +**/ >=20 > +EFI_STATUS >=20 > +PchSmmEnableGlobalSmiBit ( >=20 > + VOID >=20 > + ); >=20 > + >=20 > +/** >=20 > + Clears the SMI after all SMI source have been processed. >=20 > + Note that this function will not work correctly (as it is >=20 > + written) unless all SMI sources have been processed. >=20 > + A revision of this function could manually clear all SMI >=20 > + status bits to guarantee success. >=20 > + >=20 > + >=20 > + @retval EFI_SUCCESS Clears the SMIs completed >=20 > + @retval Asserts EOS was not set to a 1 >=20 > +**/ >=20 > +EFI_STATUS >=20 > +PchSmmClearSmi ( >=20 > + VOID >=20 > + ); >=20 > + >=20 > +/** >=20 > + Set the SMI EOS bit after all SMI source have been processed. >=20 > + >=20 > + >=20 > + @retval FALSE EOS was not set to a 1; this is an err= or >=20 > + @retval TRUE EOS was correctly set to a 1 >=20 > +**/ >=20 > +BOOLEAN >=20 > +PchSmmSetAndCheckEos ( >=20 > + VOID >=20 > + ); >=20 > + >=20 > +/** >=20 > + Determine whether an ACPI OS is present (via the SCI_EN bit) >=20 > + >=20 > + >=20 > + @retval TRUE ACPI OS is present >=20 > + @retval FALSE ACPI OS is not present >=20 > +**/ >=20 > +BOOLEAN >=20 > +PchSmmGetSciEn ( >=20 > + VOID >=20 > + ); >=20 > + >=20 > +/** >=20 > + Read a specifying bit with the register >=20 > + >=20 > + @param[in] BitDesc The struct that includes register addr= ess, size in > byte and bit number >=20 > + >=20 > + @retval TRUE The bit is enabled >=20 > + @retval FALSE The bit is disabled >=20 > +**/ >=20 > +BOOLEAN >=20 > +ReadBitDesc ( >=20 > + CONST PCH_SMM_BIT_DESC *BitDesc >=20 > + ); >=20 > + >=20 > +/** >=20 > + Write a specifying bit with the register >=20 > + >=20 > + @param[in] BitDesc The struct that includes register addr= ess, size in > byte and bit number >=20 > + @param[in] ValueToWrite The value to be wrote >=20 > + @param[in] WriteClear If the rest bits of the register is wr= ite clear >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +WriteBitDesc ( >=20 > + CONST PCH_SMM_BIT_DESC *BitDesc, >=20 > + CONST BOOLEAN ValueToWrite, >=20 > + CONST BOOLEAN WriteClear >=20 > + ); >=20 > + >=20 > +#endif >=20 > diff --git > a/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmContr > ol.inf > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmContr > ol.inf > new file mode 100644 > index 0000000000..a142cfa95a > --- /dev/null > +++ > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmContr > ol.inf > @@ -0,0 +1,54 @@ > +## @file >=20 > +# Component description file for SmmControl module >=20 > +# >=20 > +# Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > +# SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +# >=20 > +## >=20 > + >=20 > + >=20 > +[Defines] >=20 > +INF_VERSION =3D 0x00010017 >=20 > +BASE_NAME =3D SmmControl >=20 > +FILE_GUID =3D A0BAD9F7-AB78-491b-B583-C52B7F84B9E0 >=20 > +VERSION_STRING =3D 1.0 >=20 > +MODULE_TYPE =3D DXE_RUNTIME_DRIVER >=20 > +ENTRY_POINT =3D SmmControlDriverEntryInit >=20 > +# >=20 > +# The following information is for reference only and not required by th= e > build tools. >=20 > +# >=20 > +# VALID_ARCHITECTURES =3D IA32 X64 >=20 > +# >=20 > + >=20 > + >=20 > + >=20 > +[LibraryClasses] >=20 > +IoLib >=20 > +UefiDriverEntryPoint >=20 > +DebugLib >=20 > +UefiBootServicesTableLib >=20 > +UefiRuntimeServicesTableLib >=20 > +PmcLib >=20 > +GpioLib >=20 > + >=20 > + >=20 > +[Packages] >=20 > +MdePkg/MdePkg.dec >=20 > +TigerlakeSiliconPkg/SiPkg.dec >=20 > + >=20 > + >=20 > +[Sources] >=20 > +SmmControlDriver.h >=20 > +SmmControlDriver.c >=20 > + >=20 > + >=20 > +[Protocols] >=20 > +gEfiSmmControl2ProtocolGuid ## PRODUCES >=20 > + >=20 > + >=20 > +[Guids] >=20 > +gEfiEventVirtualAddressChangeGuid >=20 > + >=20 > + >=20 > +[Depex] >=20 > +TRUE >=20 > diff --git > a/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmContr > olDriver.c > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmContr > olDriver.c > new file mode 100644 > index 0000000000..5822f42165 > --- /dev/null > +++ > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmContr > olDriver.c > @@ -0,0 +1,394 @@ > +/** @file >=20 > + This is the driver that publishes the SMM Control Protocol. >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include >=20 > +#include "SmmControlDriver.h" >=20 > + >=20 > +STATIC SMM_CONTROL_PRIVATE_DATA mSmmControl; >=20 > +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mABase; >=20 > + >=20 > +VOID >=20 > +EFIAPI >=20 > +DisablePendingSmis ( >=20 > + VOID >=20 > + ); >=20 > + >=20 > +/** >=20 > + Fixup internal data pointers so that the services can be called in vir= tual > mode. >=20 > + >=20 > + @param[in] Event The event registered. >=20 > + @param[in] Context Event context. >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +SmmControlVirtualAddressChangeEvent ( >=20 > + IN EFI_EVENT Event, >=20 > + IN VOID *Context >=20 > + ) >=20 > +{ >=20 > + gRT->ConvertPointer (0, (VOID *) &(mSmmControl.SmmControl.Trigger)); >=20 > + gRT->ConvertPointer (0, (VOID *) &(mSmmControl.SmmControl.Clear)); >=20 > +} >=20 > + >=20 > +/** >=20 > + SmmControl DXE RUNTIME Module Entry Point\n >=20 > + - Introduction\n >=20 > + The SmmControl module is a DXE RUNTIME driver that provides a > standard way >=20 > + for other drivers to trigger software SMIs. >=20 > + >=20 > + - @pre >=20 > + - PCH Power Management I/O space base address has already been > programmed. >=20 > + If SmmControl Runtime DXE driver is run before Status Code Runtime > Protocol >=20 > + is installed and there is the need to use Status code in the drive= r, it will >=20 > + be necessary to add EFI_STATUS_CODE_RUNTIME_PROTOCOL_GUID to > the dependency file. >=20 > + - EFI_SMM_BASE2_PROTOCOL >=20 > + - Documented in the System Management Mode Core Interface > Specification. >=20 > + >=20 > + - @result >=20 > + The SmmControl driver produces the EFI_SMM_CONTROL_PROTOCOL > documented in >=20 > + System Management Mode Core Interface Specification. >=20 > + >=20 > + @param[in] ImageHandle Handle for the image of this driver >=20 > + @param[in] SystemTable Pointer to the EFI System Table >=20 > + >=20 > + @retval EFI_STATUS Results of the installation of the SMM= Control > Protocol >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +SmmControlDriverEntryInit ( >=20 > + IN EFI_HANDLE ImageHandle, >=20 > + IN EFI_SYSTEM_TABLE *SystemTable >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + EFI_EVENT Event; >=20 > + >=20 > + DEBUG ((DEBUG_INFO, "SmmControlDriverEntryInit() Start\n")); >=20 > + >=20 > + // >=20 > + // Get the Power Management I/O space base address. We assume that >=20 > + // this base address has already been programmed if this driver is >=20 > + // being run. >=20 > + // >=20 > + mABase =3D PmcGetAcpiBase (); >=20 > + >=20 > + Status =3D EFI_SUCCESS; >=20 > + if (mABase !=3D 0) { >=20 > + // >=20 > + // Install the instance of the protocol >=20 > + // >=20 > + mSmmControl.Signature =3D > SMM_CONTROL_PRIVATE_DATA_SIGNATURE; >=20 > + mSmmControl.Handle =3D ImageHandle; >=20 > + >=20 > + mSmmControl.SmmControl.Trigger =3D Activate; >=20 > + mSmmControl.SmmControl.Clear =3D Deactivate; >=20 > + mSmmControl.SmmControl.MinimumTriggerPeriod =3D 0; >=20 > + >=20 > + // >=20 > + // Install our protocol interfaces on the device's handle >=20 > + // >=20 > + Status =3D gBS->InstallMultipleProtocolInterfaces ( >=20 > + &mSmmControl.Handle, >=20 > + &gEfiSmmControl2ProtocolGuid, >=20 > + &mSmmControl.SmmControl, >=20 > + NULL >=20 > + ); >=20 > + } else { >=20 > + Status =3D EFI_DEVICE_ERROR; >=20 > + return Status; >=20 > + } >=20 > + >=20 > + Status =3D gBS->CreateEventEx ( >=20 > + EVT_NOTIFY_SIGNAL, >=20 > + TPL_NOTIFY, >=20 > + SmmControlVirtualAddressChangeEvent, >=20 > + NULL, >=20 > + &gEfiEventVirtualAddressChangeGuid, >=20 > + &Event >=20 > + ); >=20 > + // >=20 > + // Disable any PCH SMIs that, for whatever reason, are asserted after = the > boot. >=20 > + // >=20 > + DisablePendingSmis (); >=20 > + >=20 > + DEBUG ((DEBUG_INFO, "SmmControlDriverEntryInit() End\n")); >=20 > + >=20 > + return Status; >=20 > +} >=20 > + >=20 > +/** >=20 > + Trigger the software SMI >=20 > + >=20 > + @param[in] Data The value to be set on the software SM= I data > port >=20 > + >=20 > + @retval EFI_SUCCESS Function completes successfully >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +SmmTrigger ( >=20 > + IN UINT8 Data >=20 > + ) >=20 > +{ >=20 > + UINT32 OutputData; >=20 > + UINT32 OutputPort; >=20 > + >=20 > + // >=20 > + // Enable the APMC SMI >=20 > + // >=20 > + OutputPort =3D mABase + R_ACPI_IO_SMI_EN; >=20 > + OutputData =3D IoRead32 ((UINTN) OutputPort); >=20 > + OutputData |=3D (B_ACPI_IO_SMI_EN_APMC | > B_ACPI_IO_SMI_EN_GBL_SMI); >=20 > + DEBUG ( >=20 > + (DEBUG_VERBOSE, >=20 > + "The SMI Control Port at address %x will be written to %x.\n", >=20 > + OutputPort, >=20 > + OutputData) >=20 > + ); >=20 > + IoWrite32 ( >=20 > + (UINTN) OutputPort, >=20 > + (UINT32) (OutputData) >=20 > + ); >=20 > + >=20 > + OutputPort =3D R_PCH_IO_APM_CNT; >=20 > + OutputData =3D Data; >=20 > + >=20 > + // >=20 > + // Generate the APMC SMI >=20 > + // >=20 > + IoWrite8 ( >=20 > + (UINTN) OutputPort, >=20 > + (UINT8) (OutputData) >=20 > + ); >=20 > + >=20 > + return EFI_SUCCESS; >=20 > +} >=20 > + >=20 > +/** >=20 > + Clear the SMI status >=20 > + >=20 > + >=20 > + @retval EFI_SUCCESS The function completes successfully >=20 > + @retval EFI_DEVICE_ERROR Something error occurred >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +SmmClear ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + UINT32 OutputData; >=20 > + UINT32 OutputPort; >=20 > + >=20 > + Status =3D EFI_SUCCESS; >=20 > + >=20 > + // >=20 > + // Clear the Power Button Override Status Bit, it gates EOS from being= set. >=20 > + // >=20 > + OutputPort =3D mABase + R_ACPI_IO_PM1_STS; >=20 > + OutputData =3D B_ACPI_IO_PM1_STS_PRBTNOR; >=20 > + DEBUG ( >=20 > + (DEBUG_VERBOSE, >=20 > + "The PM1 Status Port at address %x will be written to %x.\n", >=20 > + OutputPort, >=20 > + OutputData) >=20 > + ); >=20 > + IoWrite16 ( >=20 > + (UINTN) OutputPort, >=20 > + (UINT16) (OutputData) >=20 > + ); >=20 > + >=20 > + // >=20 > + // Clear the APM SMI Status Bit >=20 > + // >=20 > + OutputPort =3D mABase + R_ACPI_IO_SMI_STS; >=20 > + OutputData =3D B_ACPI_IO_SMI_STS_APM; >=20 > + DEBUG ( >=20 > + (DEBUG_VERBOSE, >=20 > + "The SMI Status Port at address %x will be written to %x.\n", >=20 > + OutputPort, >=20 > + OutputData) >=20 > + ); >=20 > + IoWrite32 ( >=20 > + (UINTN) OutputPort, >=20 > + (UINT32) (OutputData) >=20 > + ); >=20 > + >=20 > + // >=20 > + // Set the EOS Bit >=20 > + // >=20 > + OutputPort =3D mABase + R_ACPI_IO_SMI_EN; >=20 > + OutputData =3D IoRead32 ((UINTN) OutputPort); >=20 > + OutputData |=3D B_ACPI_IO_SMI_EN_EOS; >=20 > + DEBUG ( >=20 > + (DEBUG_VERBOSE, >=20 > + "The SMI Control Port at address %x will be written to %x.\n", >=20 > + OutputPort, >=20 > + OutputData) >=20 > + ); >=20 > + IoWrite32 ( >=20 > + (UINTN) OutputPort, >=20 > + (UINT32) (OutputData) >=20 > + ); >=20 > + >=20 > + // >=20 > + // There is no need to read EOS back and check if it is set. >=20 > + // This can lead to a reading of zero if an SMI occurs right after the= SMI_EN > port read >=20 > + // but before the data is returned to the CPU. >=20 > + // SMM Dispatcher should make sure that EOS is set after all SMI sourc= es > are processed. >=20 > + // >=20 > + return Status; >=20 > +} >=20 > + >=20 > +/** >=20 > + This routine generates an SMI >=20 > + >=20 > + @param[in] This The EFI SMM Control protocol ins= tance >=20 > + @param[in, out] CommandPort The buffer contains data to the > command port >=20 > + @param[in, out] DataPort The buffer contains data to the = data port >=20 > + @param[in] Periodic Periodic or not >=20 > + @param[in] ActivationInterval Interval of periodic SMI >=20 > + >=20 > + @retval EFI Status Describing the result of the ope= ration >=20 > + @retval EFI_INVALID_PARAMETER Some parameter value passed is > not supported >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +Activate ( >=20 > + IN CONST EFI_SMM_CONTROL2_PROTOCOL * This, >=20 > + IN OUT UINT8 *CommandPort = OPTIONAL, >=20 > + IN OUT UINT8 *DataPort = OPTIONAL, >=20 > + IN BOOLEAN Periodic = OPTIONAL, >=20 > + IN UINTN ActivationInterv= al OPTIONAL >=20 > + ) >=20 > +{ >=20 > + EFI_STATUS Status; >=20 > + UINT8 Data; >=20 > + >=20 > + if (Periodic) { >=20 > + DEBUG ((DEBUG_WARN, "Invalid parameter\n")); >=20 > + return EFI_INVALID_PARAMETER; >=20 > + } >=20 > + >=20 > + if (CommandPort =3D=3D NULL) { >=20 > + Data =3D 0xFF; >=20 > + } else { >=20 > + Data =3D *CommandPort; >=20 > + } >=20 > + // >=20 > + // Clear any pending the APM SMI >=20 > + // >=20 > + Status =3D SmmClear (); >=20 > + if (EFI_ERROR (Status)) { >=20 > + return Status; >=20 > + } >=20 > + >=20 > + return SmmTrigger (Data); >=20 > +} >=20 > + >=20 > +/** >=20 > + This routine clears an SMI >=20 > + >=20 > + @param[in] This The EFI SMM Control protocol instance >=20 > + @param[in] Periodic Periodic or not >=20 > + >=20 > + @retval EFI Status Describing the result of the operation >=20 > + @retval EFI_INVALID_PARAMETER Some parameter value passed is not > supported >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +Deactivate ( >=20 > + IN CONST EFI_SMM_CONTROL2_PROTOCOL *This, >=20 > + IN BOOLEAN Periodic OPTIONAL >=20 > + ) >=20 > +{ >=20 > + if (Periodic) { >=20 > + return EFI_INVALID_PARAMETER; >=20 > + } >=20 > + >=20 > + return SmmClear (); >=20 > +} >=20 > +/** >=20 > + Disable all pending SMIs >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +DisablePendingSmis ( >=20 > + VOID >=20 > + ) >=20 > +{ >=20 > + UINT32 Data; >=20 > + BOOLEAN SciEn; >=20 > + >=20 > + // >=20 > + // Determine whether an ACPI OS is present (via the SCI_EN bit) >=20 > + // >=20 > + Data =3D IoRead16 ((UINTN) mABase + R_ACPI_IO_PM1_CNT); >=20 > + SciEn =3D (BOOLEAN) ((Data & B_ACPI_IO_PM1_CNT_SCI_EN) =3D=3D > B_ACPI_IO_PM1_CNT_SCI_EN); >=20 > + >=20 > + if (!SciEn) { >=20 > + // >=20 > + // Clear any SMIs that double as SCIs (when SCI_EN=3D=3D0) >=20 > + // >=20 > + IoWrite16 ((UINTN) mABase + R_ACPI_IO_PM1_STS, 0xFFFF); >=20 > + IoWrite16 ((UINTN) mABase + R_ACPI_IO_PM1_EN, 0); >=20 > + IoWrite16 ((UINTN) mABase + R_ACPI_IO_PM1_CNT, 0); >=20 > + IoWrite32 ( >=20 > + (UINTN) mABase + R_ACPI_IO_GPE0_STS_127_96, >=20 > + (UINT32)( B_ACPI_IO_GPE0_STS_127_96_WADT | >=20 > + B_ACPI_IO_GPE0_STS_127_96_USB_CON_DSX_STS | >=20 > + B_ACPI_IO_GPE0_STS_127_96_LAN_WAKE | >=20 > + B_ACPI_IO_GPE0_STS_127_96_PME_B0 | >=20 > + B_ACPI_IO_GPE0_STS_127_96_PME | >=20 > + B_ACPI_IO_GPE0_STS_127_96_BATLOW | >=20 > + B_ACPI_IO_GPE0_STS_127_96_RI | >=20 > + B_ACPI_IO_GPE0_STS_127_96_SWGPE) >=20 > + ); >=20 > + IoWrite32 ((UINTN) mABase + R_ACPI_IO_GPE0_EN_127_96, (UINT32) > B_ACPI_IO_GPE0_EN_127_96_WADT); >=20 > + } >=20 > + // >=20 > + // Clear and disable all SMIs that are unaffected by SCI_EN >=20 > + // >=20 > + GpioDisableAllGpiSmi (); >=20 > + >=20 > + GpioClearAllGpiSmiSts (); >=20 > + >=20 > + IoWrite32 ((UINTN) mABase + R_ACPI_IO_DEVACT_STS, 0x0000FFFF); >=20 > + >=20 > + IoWrite32 ((UINTN) mABase + R_ACPI_IO_SMI_STS, ~0u); >=20 > + >=20 > + // >=20 > + // (Make sure to write this register last -- EOS re-enables SMIs for t= he PCH) >=20 > + // >=20 > + Data =3D IoRead32 ((UINTN) mABase + R_ACPI_IO_SMI_EN); >=20 > + // >=20 > + // clear all bits except those tied to SCI_EN >=20 > + // >=20 > + Data &=3D B_ACPI_IO_SMI_EN_BIOS_RLS; >=20 > + // >=20 > + // enable SMIs and specifically enable writes to APM_CNT. >=20 > + // >=20 > + Data |=3D B_ACPI_IO_SMI_EN_GBL_SMI | B_ACPI_IO_SMI_EN_APMC; >=20 > + // >=20 > + // NOTE: Default value of EOS is set in PCH, it will be automatically= cleared > Once the PCH asserts SMI# low, >=20 > + // we don't need to do anything to clear it >=20 > + // >=20 > + IoWrite32 ((UINTN) mABase + R_ACPI_IO_SMI_EN, Data); >=20 > +} >=20 > + >=20 > diff --git > a/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmContr > olDriver.h > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmContr > olDriver.h > new file mode 100644 > index 0000000000..af368e6945 > --- /dev/null > +++ > b/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmContr > olDriver.h > @@ -0,0 +1,130 @@ > +/** @file >=20 > + Header file for SMM Control Driver. >=20 > + >=20 > + Copyright (c) 2021, Intel Corporation. All rights reserved.
>=20 > + SPDX-License-Identifier: BSD-2-Clause-Patent >=20 > +**/ >=20 > +#ifndef _SMM_CONTROL_DRIVER_H_ >=20 > +#define _SMM_CONTROL_DRIVER_H_ >=20 > + >=20 > +#include >=20 > + >=20 > + >=20 > +#define SMM_CONTROL_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('i', > '4', 's', 'c') >=20 > + >=20 > +typedef struct { >=20 > + UINTN Signature; >=20 > + EFI_HANDLE Handle; >=20 > + EFI_SMM_CONTROL2_PROTOCOL SmmControl; >=20 > +} SMM_CONTROL_PRIVATE_DATA; >=20 > + >=20 > +#define SMM_CONTROL_PRIVATE_DATA_FROM_THIS(a) CR (a, > SMM_CONTROL_PRIVATE_DATA, SmmControl, > SMM_CONTROL_DEV_SIGNATURE) >=20 > + >=20 > +// >=20 > +// Prototypes >=20 > +// >=20 > + >=20 > +/** >=20 > + SmmControl DXE RUNTIME Module Entry Point\n >=20 > + - Introduction\n >=20 > + The SmmControl module is a DXE RUNTIME driver that provides a > standard way >=20 > + for other drivers to trigger software SMIs. >=20 > + >=20 > + - @pre >=20 > + - PCH Power Management I/O space base address has already been > programmed. >=20 > + If SmmControl Runtime DXE driver is run before Status Code Runtime > Protocol >=20 > + is installed and there is the need to use Status code in the drive= r, it will >=20 > + be necessary to add EFI_STATUS_CODE_RUNTIME_PROTOCOL_GUID to > the dependency file. >=20 > + - EFI_SMM_BASE2_PROTOCOL >=20 > + - Documented in the System Management Mode Core Interface > Specification. >=20 > + >=20 > + - @result >=20 > + The SmmControl driver produces the EFI_SMM_CONTROL_PROTOCOL > documented in >=20 > + System Management Mode Core Interface Specification. >=20 > + >=20 > + @param[in] ImageHandle Handle for the image of this driver >=20 > + @param[in] SystemTable Pointer to the EFI System Table >=20 > + >=20 > + @retval EFI_STATUS Results of the installation of the SMM= Control > Protocol >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +SmmControlDriverEntryInit ( >=20 > + IN EFI_HANDLE ImageHandle, >=20 > + IN EFI_SYSTEM_TABLE *SystemTable >=20 > + ); >=20 > + >=20 > +/** >=20 > + Trigger the software SMI >=20 > + >=20 > + @param[in] Data The value to be set on the software SM= I data > port >=20 > + >=20 > + @retval EFI_SUCCESS Function completes successfully >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +SmmTrigger ( >=20 > + UINT8 Data >=20 > + ); >=20 > + >=20 > +/** >=20 > + Clear the SMI status >=20 > + >=20 > + >=20 > + @retval EFI_SUCCESS The function completes successfully >=20 > + @retval EFI_DEVICE_ERROR Something error occurred >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +SmmClear ( >=20 > + VOID >=20 > + ); >=20 > + >=20 > +/** >=20 > + This routine generates an SMI >=20 > + >=20 > + @param[in] This The EFI SMM Control protocol ins= tance >=20 > + @param[in, out] ArgumentBuffer The buffer of argument >=20 > + @param[in, out] ArgumentBufferSize The size of the argument buffer >=20 > + @param[in] Periodic Periodic or not >=20 > + @param[in] ActivationInterval Interval of periodic SMI >=20 > + >=20 > + @retval EFI Status Describing the result of the ope= ration >=20 > + @retval EFI_INVALID_PARAMETER Some parameter value passed is > not supported >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +Activate ( >=20 > + IN CONST EFI_SMM_CONTROL2_PROTOCOL *This, >=20 > + IN OUT UINT8 *ArgumentBuffer OPTIONAL, >=20 > + IN OUT UINT8 *ArgumentBufferSize OPTIONAL, >=20 > + IN BOOLEAN Periodic OPTIONAL, >=20 > + IN UINTN ActivationInterval OPTIONAL >=20 > + ); >=20 > + >=20 > +/** >=20 > + This routine clears an SMI >=20 > + >=20 > + @param[in] This The EFI SMM Control protocol instance >=20 > + @param[in] Periodic Periodic or not >=20 > + >=20 > + @retval EFI Status Describing the result of the operation >=20 > + @retval EFI_INVALID_PARAMETER Some parameter value passed is not > supported >=20 > +**/ >=20 > +EFI_STATUS >=20 > +EFIAPI >=20 > +Deactivate ( >=20 > + IN CONST EFI_SMM_CONTROL2_PROTOCOL *This, >=20 > + IN BOOLEAN Periodic OPTIONAL >=20 > + ); >=20 > +/** >=20 > + Disable all pending SMIs >=20 > + >=20 > +**/ >=20 > +VOID >=20 > +EFIAPI >=20 > +DisablePendingSmis ( >=20 > + VOID >=20 > + ); >=20 > + >=20 > +#endif >=20 > -- > 2.24.0.windows.2