From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI, SPF_HELO_NONE,SPF_PASS autolearn=no autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 52E95C07E95 for ; Mon, 19 Jul 2021 20:37:18 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 0EA1A6109E for ; Mon, 19 Jul 2021 20:37:18 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 0EA1A6109E Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=roeck-us.net Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:In-Reply-To:MIME-Version:References: Message-ID:Subject:Cc:To:From:Date:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=7YBlE6iFh4vd9ALmTxfEhKQBUJiDEuSl6VEKE7O98R0=; b=u/QMLKNDMwc7jZ NXo/J0eNJWguTaxTWD+Y2KyTnwi8tlMl7UkwW37CbT5rrXJ3wnmIeVEWFDiHk4Bt/TeTjxXbJ+Nx4 TCPT80FQnL/THi8ROIAEAgSpsEMeGgCkNPUCSOB6QAtDS6XKfsHhdbntuTi502zn+JXAdq6cVr3sv tM/Wybiq6OCr5FxO0QyFOK/EEN+ffBYnALA07jWXg0YO35wK51ZRlXBl/zlM6oL52RYJhiflmHyvo WZQr9e+dDN5GN8XKANeQ7N7y31St4Z0lYl6mWMsCj0Qm5+/WZ0wLHkfiK8enCmA9GFtNaZ8cSmISg 4cgGtdVMajedfgOPkx5w==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1m5Zyr-00BHEf-JV; Mon, 19 Jul 2021 20:35:13 +0000 Received: from mail-oo1-xc33.google.com ([2607:f8b0:4864:20::c33]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1m5Zym-00BHDf-5D for linux-arm-kernel@lists.infradead.org; Mon, 19 Jul 2021 20:35:10 +0000 Received: by mail-oo1-xc33.google.com with SMTP id a17-20020a4ad5d10000b0290263c143bcb2so3362040oot.7 for ; Mon, 19 Jul 2021 13:35:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:date:from:to:cc:subject:message-id:references:mime-version :content-disposition:content-transfer-encoding:in-reply-to; bh=CnGPA9k5jAnGBAAGW5ixT1QhP02OGDK8n1UCPbob07o=; b=Pm8yu2gf+hlzn+55X/bDKWMa8As3RwFoGStNgel0D8Uyvvd6jzhTIZYZw3geqPdIMW ZGlCrHwftraox+L/LeqzJvUMCpNHt+6NdgbMimP7fHKtZmEPFZxNaQTJe2TJGLgtfuTt sU/kZaer8jaN1pvWRGZOp+Fq2Ao5s/uYzPIDq+B+z7G8AZ3PF+ZRcLD1ZpxqHh8pB+sr GS5ln6fsrSftTJgfVgGsDJ9lzNwNWOf6MCxDdZND26fB/bUWgxmNeRrsBFX3/YEvXZaX ZqWaEyAPqhsKiW4zMEpVrS24BS8QJQ3gyYVBSom/VGzLmg0eNYO3c3kKyb2UmOhSU8DD cEPg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:from:to:cc:subject:message-id :references:mime-version:content-disposition :content-transfer-encoding:in-reply-to; bh=CnGPA9k5jAnGBAAGW5ixT1QhP02OGDK8n1UCPbob07o=; b=MFnl9TlX4b4wBAgGfWk+Y+oUO7vEt6/ZZI5LKHo/NgeRcMjHbWEmzRMGUUyHAinJZD pMUgB4cG1PJ+m6hU6mPwycUbZm8tH/JpbmGI0pmeUnKDnT2ABiEHsLNL194SbxApDV1z ygGQKYetYlHAD0/1ZTs2fvtvvv5+I++x7XKRjZUL7AauPemRp+iySx6PNAKekLA/HChS lIBeL7HxYe2b1ag3OLy4VWu7B2U+XwT1EQ9SaHPdcdj9UTHa5gAN3Bj+wJGmyW7u1zoJ wBIlDk8BXE0Cn6PnOLDPayfuXZuaCrO+cfG6fGEx4n5R7ARJyFyBjv84kEKrR1JNCuMO HPqA== X-Gm-Message-State: AOAM5329ign3gmfeAY1GAxjad0JdAJPZHkuH1OcCC868doEfou7GCpCS 0ZUupND/py6LcnIKuZcOq0A= X-Google-Smtp-Source: ABdhPJwC+ITNhkPvbxptB2sPYgUDu+tCWQlgRApn/ULuEKeLsTUiChZ4F19JQXpgRQm3lOpfzE1hRQ== X-Received: by 2002:a4a:5dc6:: with SMTP id w189mr18755739ooa.1.1626726906873; Mon, 19 Jul 2021 13:35:06 -0700 (PDT) Received: from server.roeck-us.net ([2600:1700:e321:62f0:329c:23ff:fee3:9d7c]) by smtp.gmail.com with ESMTPSA id j10sm3084117oog.47.2021.07.19.13.35.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 19 Jul 2021 13:35:06 -0700 (PDT) Date: Mon, 19 Jul 2021 13:35:04 -0700 From: Guenter Roeck To: "Winiarska, Iwona" Cc: "corbet@lwn.net" , "jae.hyun.yoo@linux.intel.com" , "Lutomirski, Andy" , "linux-hwmon@vger.kernel.org" , "Luck, Tony" , "andrew@aj.id.au" , "mchehab@kernel.org" , "jdelvare@suse.com" , "linux-kernel@vger.kernel.org" , "mingo@redhat.com" , "devicetree@vger.kernel.org" , "tglx@linutronix.de" , "linux-aspeed@lists.ozlabs.org" , "linux-doc@vger.kernel.org" , "yazen.ghannam@amd.com" , "robh+dt@kernel.org" , "openbmc@lists.ozlabs.org" , "bp@alien8.de" , "linux-arm-kernel@lists.infradead.org" , "pierre-louis.bossart@linux.intel.com" , "andriy.shevchenko@linux.intel.com" , "x86@kernel.org" , "gregkh@linuxfoundation.org" Subject: Re: [PATCH 11/14] hwmon: peci: Add cputemp driver Message-ID: <20210719203504.GA2277987@roeck-us.net> References: <20210712220447.957418-1-iwona.winiarska@intel.com> <20210712220447.957418-12-iwona.winiarska@intel.com> <20210715174527.GA3012477@roeck-us.net> <66b4a0285ffada1855eb099011bed27b2750b3cc.camel@intel.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <66b4a0285ffada1855eb099011bed27b2750b3cc.camel@intel.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210719_133508_297975_D38798E1 X-CRM114-Status: GOOD ( 31.16 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org On Mon, Jul 19, 2021 at 08:12:54PM +0000, Winiarska, Iwona wrote: > > > +static const char *cputemp_label[DEFAULT_CHANNEL_NUMS] =3D { > > > +=A0=A0=A0=A0=A0=A0=A0"Die", > > > +=A0=A0=A0=A0=A0=A0=A0"DTS", > > > +=A0=A0=A0=A0=A0=A0=A0"Tcontrol", > > > +=A0=A0=A0=A0=A0=A0=A0"Tthrottle", > > > +=A0=A0=A0=A0=A0=A0=A0"Tjmax", > > > +}; > > > + > > > +static int get_temp_targets(struct peci_cputemp *priv) > > > +{ > > > +=A0=A0=A0=A0=A0=A0=A0s32 tthrottle_offset, tcontrol_margin; > > > +=A0=A0=A0=A0=A0=A0=A0u32 pcs; > > > +=A0=A0=A0=A0=A0=A0=A0int ret; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0/* > > > +=A0=A0=A0=A0=A0=A0=A0 * Just use only the tcontrol marker to determi= ne if target values > > > need > > > +=A0=A0=A0=A0=A0=A0=A0 * update. > > > +=A0=A0=A0=A0=A0=A0=A0 */ > > > +=A0=A0=A0=A0=A0=A0=A0if (!peci_sensor_need_update(&priv->temp.tcontr= ol)) > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0return 0; > > > + > > True for the entire code: Please explain how this avoids race conditions > > without locking between the condition check here and the call to > > peci_sensor_mark_updated() below. The explanation needs to be added > > as comment into the code for later reference. > > = > = > You're right, there is a race here that may cause PECI command to be trig= gered > more than once. It doesn't have any impact on correctness though. That is only correct if multiple read operations of PECI_PCS_TEMP_TARGET always return the same value. If so, reading those values multiple times would not make sense. Instead, the values could be read once and cached. If PECI_PCS_TEMP_TARGET can return different values each time it is called, the lack of mutex protection could result in inconsistent values for priv->temp.tjmax.value, priv->temp.tcontrol.value, and priv->temp.tthrottle.value. So either this needs a mutex, or the code should be changed to read the static values only once. You could instead add a comment stating that multiple unprotected reads are redundant because the returned data is static, that parallel reads are thus not racy, and that a mutex is therefore not needed, but I won't accept such code. > I could add a comment explaining that, but I guess just adding a mutex to= avoid > the race makes more sense. = > = > > > +=A0=A0=A0=A0=A0=A0=A0ret =3D peci_pcs_read(priv->peci_dev, PECI_PCS_= TEMP_TARGET, 0, &pcs); > > > +=A0=A0=A0=A0=A0=A0=A0if (ret) > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0return ret; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0priv->temp.tjmax.value =3D FIELD_GET(TEMP_TARGE= T_REF_TEMP_MASK, pcs) * > > > MILLIDEGREE_PER_DEGREE; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0tcontrol_margin =3D FIELD_GET(TEMP_TARGET_FAN_T= EMP_MASK, pcs); > > > +=A0=A0=A0=A0=A0=A0=A0tcontrol_margin =3D sign_extend32(tcontrol_marg= in, 7) * > > > MILLIDEGREE_PER_DEGREE; > > > +=A0=A0=A0=A0=A0=A0=A0priv->temp.tcontrol.value =3D priv->temp.tjmax.= value - tcontrol_margin; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0tthrottle_offset =3D FIELD_GET(TEMP_TARGET_TJ_O= FFSET_MASK, pcs) * > > > MILLIDEGREE_PER_DEGREE; > > > +=A0=A0=A0=A0=A0=A0=A0priv->temp.tthrottle.value =3D priv->temp.tjmax= .value - > > > tthrottle_offset; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0peci_sensor_mark_updated(&priv->temp.tcontrol); > > > + > > > +=A0=A0=A0=A0=A0=A0=A0return 0; > > > +} > > > + > > > +/* > > > + * Processors return a value of DTS reading in S10.6 fixed point for= mat > > > + * (sign, 10 bits signed integer value, 6 bits fractional). > > > + * Error codes: > > > + *=A0=A0 0x8000: General sensor error > > > + *=A0=A0 0x8001: Reserved > > > + *=A0=A0 0x8002: Underflow on reading value > > > + *=A0=A0 0x8003-0x81ff: Reserved > > > + */ > > > +static bool dts_valid(s32 val) > > > +{ > > > +=A0=A0=A0=A0=A0=A0=A0return val < 0x8000 || val > 0x81ff; > > > +} > > > + > > > +static s32 dts_to_millidegree(s32 val) > > > +{ > > > +=A0=A0=A0=A0=A0=A0=A0return sign_extend32(val, 15) * MILLIDEGREE_PER= _DEGREE / > > > DTS_FIXED_POINT_FRACTION; > > > +} > > > + > > > +static int get_die_temp(struct peci_cputemp *priv) > > > +{ > > > +=A0=A0=A0=A0=A0=A0=A0s16 temp; > > > +=A0=A0=A0=A0=A0=A0=A0int ret; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0if (!peci_sensor_need_update(&priv->temp.die)) > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0return 0; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0ret =3D peci_temp_read(priv->peci_dev, &temp); > > > +=A0=A0=A0=A0=A0=A0=A0if (ret) > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0return ret; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0if (!dts_valid(temp)) > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0return -EIO; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0/* Note that the tjmax should be available befo= re calling it */ > > > +=A0=A0=A0=A0=A0=A0=A0priv->temp.die.value =3D priv->temp.tjmax.value= + > > > dts_to_millidegree(temp); > > > + > > > +=A0=A0=A0=A0=A0=A0=A0peci_sensor_mark_updated(&priv->temp.die); The same is true here: Either the value returned from peci_temp_read() is static (which seems unlikely), or there is a race between reading the temperature, storing it in priv->temp.die.value, and setting the update flag. With the current code, there is no guarantee that the stored value is the value that was read by the thread that sets the updated flag. One could argue that it doesn't really matter because it is irrelevant which thread stores the temperature and which thread sets the updated flag, but that is really bad coding style, and I won't accept it. This is true for all code which reads a value from the chip, stores it locally, and then sets the updated flag. > > > + > > > +=A0=A0=A0=A0=A0=A0=A0return 0; > > > +} > > > + > > > +static int get_dts(struct peci_cputemp *priv) > > > +{ > > > +=A0=A0=A0=A0=A0=A0=A0s32 dts_margin; > > > +=A0=A0=A0=A0=A0=A0=A0u32 pcs; > > > +=A0=A0=A0=A0=A0=A0=A0int ret; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0if (!peci_sensor_need_update(&priv->temp.dts)) > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0return 0; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0ret =3D peci_pcs_read(priv->peci_dev, PECI_PCS_= THERMAL_MARGIN, 0, &pcs); > > > +=A0=A0=A0=A0=A0=A0=A0if (ret) > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0return ret; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0dts_margin =3D FIELD_GET(DTS_MARGIN_MASK, pcs); > > > +=A0=A0=A0=A0=A0=A0=A0if (!dts_valid(dts_margin)) > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0return -EIO; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0/* Note that the tcontrol should be available b= efore calling it */ > > > +=A0=A0=A0=A0=A0=A0=A0priv->temp.dts.value =3D priv->temp.tcontrol.va= lue - > > > dts_to_millidegree(dts_margin); > > > + > > > +=A0=A0=A0=A0=A0=A0=A0peci_sensor_mark_updated(&priv->temp.dts); > > > + > > > +=A0=A0=A0=A0=A0=A0=A0return 0; > > > +} > > > + > > > +static int get_core_temp(struct peci_cputemp *priv, int core_index) > > > +{ > > > +=A0=A0=A0=A0=A0=A0=A0s32 core_dts_margin; > > > +=A0=A0=A0=A0=A0=A0=A0u32 pcs; > > > +=A0=A0=A0=A0=A0=A0=A0int ret; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0if (!peci_sensor_need_update(&priv->temp.core[c= ore_index])) > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0return 0; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0ret =3D peci_pcs_read(priv->peci_dev, PECI_PCS_= MODULE_TEMP, core_index, > > > &pcs); > > > +=A0=A0=A0=A0=A0=A0=A0if (ret) > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0return ret; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0core_dts_margin =3D FIELD_GET(PCS_MODULE_TEMP_M= ASK, pcs); > > > +=A0=A0=A0=A0=A0=A0=A0if (!dts_valid(core_dts_margin)) > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0return -EIO; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0/* Note that the tjmax should be available befo= re calling it */ > > > +=A0=A0=A0=A0=A0=A0=A0priv->temp.core[core_index].value =3D > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0priv->temp.tjmax.value = + dts_to_millidegree(core_dts_margin); > > > + > > > +=A0=A0=A0=A0=A0=A0=A0peci_sensor_mark_updated(&priv->temp.core[core_= index]); > > > + > > > +=A0=A0=A0=A0=A0=A0=A0return 0; > > > +} > > > + > > > +static int cputemp_read_string(struct device *dev, enum hwmon_sensor= _types > > > type, > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0 u32 attr, int channel, const char **str) > > > +{ > > > +=A0=A0=A0=A0=A0=A0=A0struct peci_cputemp *priv =3D dev_get_drvdata(d= ev); > > > + > > > +=A0=A0=A0=A0=A0=A0=A0if (attr !=3D hwmon_temp_label) > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0return -EOPNOTSUPP; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0*str =3D channel < channel_core ? > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0cputemp_label[channel] = : priv->coretemp_label[channel - > > > channel_core]; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0return 0; > > > +} > > > + > > > +static int cputemp_read(struct device *dev, enum hwmon_sensor_types = type, > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0u32 attr, int channel, long *val) > > > +{ > > > +=A0=A0=A0=A0=A0=A0=A0struct peci_cputemp *priv =3D dev_get_drvdata(d= ev); > > > +=A0=A0=A0=A0=A0=A0=A0int ret, core_index; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0ret =3D get_temp_targets(priv); > > > +=A0=A0=A0=A0=A0=A0=A0if (ret) > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0return ret; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0switch (attr) { > > > +=A0=A0=A0=A0=A0=A0=A0case hwmon_temp_input: > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0switch (channel) { > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0case channel_die: > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0ret =3D get_die_temp(priv); > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0if (ret) > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0return ret; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0*val =3D priv->temp.die.value; > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0break; > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0case channel_dts: > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0ret =3D get_dts(priv); > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0if (ret) > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0return ret; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0*val =3D priv->temp.dts.value; > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0break; > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0case channel_tcontrol: > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0*val =3D priv->temp.tcontrol.value; > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0break; > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0case channel_tthrottle: > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0*val =3D priv->temp.tthrottle.value; > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0break; > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0case channel_tjmax: > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0*val =3D priv->temp.tjmax.value; > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0break; > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0default: > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0core_index =3D channel - channel_core; > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0ret =3D get_core_temp(priv, core_index); > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0if (ret) > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0return ret; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0*val =3D priv->temp.core[core_index].value; > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0break; > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0} > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0break; > > > +=A0=A0=A0=A0=A0=A0=A0case hwmon_temp_max: > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0*val =3D priv->temp.tco= ntrol.value; > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0break; > > > +=A0=A0=A0=A0=A0=A0=A0case hwmon_temp_crit: > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0*val =3D priv->temp.tjm= ax.value; > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0break; > > > +=A0=A0=A0=A0=A0=A0=A0case hwmon_temp_crit_hyst: > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0*val =3D priv->temp.tjm= ax.value - priv->temp.tcontrol.value; > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0break; > > > +=A0=A0=A0=A0=A0=A0=A0default: > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0return -EOPNOTSUPP; > > > +=A0=A0=A0=A0=A0=A0=A0} > > > + > > > +=A0=A0=A0=A0=A0=A0=A0return 0; > > > +} > > > + > > > +static umode_t cputemp_is_visible(const void *data, enum hwmon_senso= r_types > > > type, > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 u32 attr, int channel) > > > +{ > > > +=A0=A0=A0=A0=A0=A0=A0const struct peci_cputemp *priv =3D data; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0if (channel > CPUTEMP_CHANNEL_NUMS) > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0return 0; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0if (channel < channel_core) > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0return 0444; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0if (test_bit(channel - channel_core, priv->core= _mask)) > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0return 0444; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0return 0; > > > +} > > > + > > > +static int init_core_mask(struct peci_cputemp *priv) > > > +{ > > > +=A0=A0=A0=A0=A0=A0=A0struct peci_device *peci_dev =3D priv->peci_dev; > > > +=A0=A0=A0=A0=A0=A0=A0struct resolved_cores_reg *reg =3D priv->gen_in= fo->reg; > > > +=A0=A0=A0=A0=A0=A0=A0u64 core_mask; > > > +=A0=A0=A0=A0=A0=A0=A0u32 data; > > > +=A0=A0=A0=A0=A0=A0=A0int ret; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0/* Get the RESOLVED_CORES register value */ > > > +=A0=A0=A0=A0=A0=A0=A0switch (peci_dev->info.model) { > > > +=A0=A0=A0=A0=A0=A0=A0case INTEL_FAM6_ICELAKE_X: > > > +=A0=A0=A0=A0=A0=A0=A0case INTEL_FAM6_ICELAKE_D: > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0ret =3D peci_ep_pci_loc= al_read(peci_dev, 0, reg->bus, reg->dev, > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 reg->func, = reg->offset + 4, > > > &data); > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0if (ret) > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0return ret; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0core_mask =3D (u64)data= << 32; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0ret =3D peci_ep_pci_loc= al_read(peci_dev, 0, reg->bus, reg->dev, > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 reg->func, = reg->offset, &data); > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0if (ret) > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0return ret; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0core_mask |=3D data; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0break; > > > +=A0=A0=A0=A0=A0=A0=A0default: > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0ret =3D peci_pci_local_= read(peci_dev, reg->bus, reg->dev, > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 reg->func, reg->offs= et, &data); > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0if (ret) > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0return ret; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0core_mask =3D data; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0break; > > > +=A0=A0=A0=A0=A0=A0=A0} > > > + > > > +=A0=A0=A0=A0=A0=A0=A0if (!core_mask) > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0return -EIO; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0bitmap_from_u64(priv->core_mask, core_mask); > > > + > > > +=A0=A0=A0=A0=A0=A0=A0return 0; > > > +} > > > + > > > +static int create_temp_label(struct peci_cputemp *priv) > > > +{ > > > +=A0=A0=A0=A0=A0=A0=A0unsigned long core_max =3D find_last_bit(priv->= core_mask, > > > CORE_NUMS_MAX); > > > +=A0=A0=A0=A0=A0=A0=A0int i; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0priv->coretemp_label =3D devm_kzalloc(priv->dev= , core_max * sizeof(char > > > *), GFP_KERNEL); > > > +=A0=A0=A0=A0=A0=A0=A0if (!priv->coretemp_label) > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0return -ENOMEM; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0for_each_set_bit(i, priv->core_mask, CORE_NUMS_= MAX) { > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0priv->coretemp_label[i]= =3D devm_kasprintf(priv->dev, > > > GFP_KERNEL, "Core %d", i); > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0if (!priv->coretemp_lab= el[i]) > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0return -ENOMEM; > > > +=A0=A0=A0=A0=A0=A0=A0} > > > + > > > +=A0=A0=A0=A0=A0=A0=A0return 0; > > > +} > > > + > > > +static void check_resolved_cores(struct peci_cputemp *priv) > > > +{ > > > +=A0=A0=A0=A0=A0=A0=A0int ret; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0ret =3D init_core_mask(priv); > > > +=A0=A0=A0=A0=A0=A0=A0if (ret) > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0return; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0ret =3D create_temp_label(priv); > > > +=A0=A0=A0=A0=A0=A0=A0if (ret) > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0bitmap_zero(priv->core_= mask, CORE_NUMS_MAX); > > = > > This needs a comment explaining why it is ok to ignore the above errors. > > = > > I understand it is because the non-core data will still be available. > > Yet, it still needs to be explained so others don't need to examine > > the code to figure out the reason. > > = > = > Right - I'll add a: > /* > * Failure to resolve cores is non-critical, we're still able to > * provide other sensor data. > */ > = > > > +} > > > + > > > +static const struct hwmon_ops peci_cputemp_ops =3D { > > > +=A0=A0=A0=A0=A0=A0=A0.is_visible =3D cputemp_is_visible, > > > +=A0=A0=A0=A0=A0=A0=A0.read_string =3D cputemp_read_string, > > > +=A0=A0=A0=A0=A0=A0=A0.read =3D cputemp_read, > > > +}; > > > + > > > +static const u32 peci_cputemp_temp_channel_config[] =3D { > > > +=A0=A0=A0=A0=A0=A0=A0/* Die temperature */ > > > +=A0=A0=A0=A0=A0=A0=A0HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX | H= WMON_T_CRIT | > > > HWMON_T_CRIT_HYST, > > > +=A0=A0=A0=A0=A0=A0=A0/* DTS margin */ > > > +=A0=A0=A0=A0=A0=A0=A0HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_MAX | H= WMON_T_CRIT | > > > HWMON_T_CRIT_HYST, > > > +=A0=A0=A0=A0=A0=A0=A0/* Tcontrol temperature */ > > > +=A0=A0=A0=A0=A0=A0=A0HWMON_T_LABEL | HWMON_T_INPUT | HWMON_T_CRIT, > > > +=A0=A0=A0=A0=A0=A0=A0/* Tthrottle temperature */ > > > +=A0=A0=A0=A0=A0=A0=A0HWMON_T_LABEL | HWMON_T_INPUT, > > > +=A0=A0=A0=A0=A0=A0=A0/* Tjmax temperature */ > > > +=A0=A0=A0=A0=A0=A0=A0HWMON_T_LABEL | HWMON_T_INPUT, > > > +=A0=A0=A0=A0=A0=A0=A0/* Core temperature - for all core channels */ > > > +=A0=A0=A0=A0=A0=A0=A0[channel_core ... CPUTEMP_CHANNEL_NUMS - 1] =3D= HWMON_T_LABEL | > > > HWMON_T_INPUT, > > > +=A0=A0=A0=A0=A0=A0=A00 > > > +}; > > > + > > > +static const struct hwmon_channel_info peci_cputemp_temp_channel =3D= { > > > +=A0=A0=A0=A0=A0=A0=A0.type =3D hwmon_temp, > > > +=A0=A0=A0=A0=A0=A0=A0.config =3D peci_cputemp_temp_channel_config, > > > +}; > > > + > > > +static const struct hwmon_channel_info *peci_cputemp_info[] =3D { > > > +=A0=A0=A0=A0=A0=A0=A0&peci_cputemp_temp_channel, > > > +=A0=A0=A0=A0=A0=A0=A0NULL > > > +}; > > > + > > > +static const struct hwmon_chip_info peci_cputemp_chip_info =3D { > > > +=A0=A0=A0=A0=A0=A0=A0.ops =3D &peci_cputemp_ops, > > > +=A0=A0=A0=A0=A0=A0=A0.info =3D peci_cputemp_info, > > > +}; > > > + > > > +static int peci_cputemp_probe(struct auxiliary_device *adev, > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0 const struct auxiliary_device_id *id) > > > +{ > > > +=A0=A0=A0=A0=A0=A0=A0struct device *dev =3D &adev->dev; > > > +=A0=A0=A0=A0=A0=A0=A0struct peci_device *peci_dev =3D to_peci_device= (dev->parent); > > > +=A0=A0=A0=A0=A0=A0=A0struct peci_cputemp *priv; > > > +=A0=A0=A0=A0=A0=A0=A0struct device *hwmon_dev; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0priv =3D devm_kzalloc(dev, sizeof(*priv), GFP_K= ERNEL); > > > +=A0=A0=A0=A0=A0=A0=A0if (!priv) > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0return -ENOMEM; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0priv->name =3D devm_kasprintf(dev, GFP_KERNEL, = "peci_cputemp.cpu%d", > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0 peci_dev->info.socket_id); > > > +=A0=A0=A0=A0=A0=A0=A0if (!priv->name) > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0return -ENOMEM; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0dev_set_drvdata(dev, priv); > > = > > What is this used for ? > = > Our sensors are per-device. We need this to access the corresponding priv= in > cputemp_read_string() and cputemp_read(). > = The parameter to both cputemp_read_string() and cputemp_read() is the pointer to the hwmon device, not the pointer to the auxiliary device. It has its driver data set to 'priv' from the parameter passed to devm_hwmon_device_register_with_info(). > > = > > > +=A0=A0=A0=A0=A0=A0=A0priv->dev =3D dev; > > > +=A0=A0=A0=A0=A0=A0=A0priv->peci_dev =3D peci_dev; > > > +=A0=A0=A0=A0=A0=A0=A0priv->gen_info =3D (const struct cpu_info *)id-= >driver_data; > > > + > > > +=A0=A0=A0=A0=A0=A0=A0check_resolved_cores(priv); > > > + > > > +=A0=A0=A0=A0=A0=A0=A0hwmon_dev =3D devm_hwmon_device_register_with_i= nfo(priv->dev, priv- > > > >name, > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0= =A0=A0=A0=A0=A0=A0=A0=A0 priv, > > > &peci_cputemp_chip_info, NULL); > > > + > > > +=A0=A0=A0=A0=A0=A0=A0return PTR_ERR_OR_ZERO(hwmon_dev); > > > +} > > > + > > > +static struct resolved_cores_reg resolved_cores_reg_hsx =3D { > > > +=A0=A0=A0=A0=A0=A0=A0.bus =3D 1, > > > +=A0=A0=A0=A0=A0=A0=A0.dev =3D 30, > > > +=A0=A0=A0=A0=A0=A0=A0.func =3D 3, > > > +=A0=A0=A0=A0=A0=A0=A0.offset =3D 0xb4, > > > +}; > > > + > > > +static struct resolved_cores_reg resolved_cores_reg_icx =3D { > > > +=A0=A0=A0=A0=A0=A0=A0.bus =3D 14, > > > +=A0=A0=A0=A0=A0=A0=A0.dev =3D 30, > > > +=A0=A0=A0=A0=A0=A0=A0.func =3D 3, > > > +=A0=A0=A0=A0=A0=A0=A0.offset =3D 0xd0, > > > +}; > > = > > Please explain those magic numbers. > > = > = > Those magic numbers refer to BDF (bus, device, function) and offset of th= e PCI > config register (RESOLVED_CORES_CFG) that can be accessed via PECI to read > resolved cores configuration. > Unfortunately, the values are just platform-specific magic numbers. > Do you think this should be explained with an additional comment? > = Yes, please. Guenter > Thank you > -Iwona > = > > > + > > > +static const struct cpu_info cpu_hsx =3D { > > > +=A0=A0=A0=A0=A0=A0=A0.reg=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=3D &re= solved_cores_reg_hsx, > > > +=A0=A0=A0=A0=A0=A0=A0.min_peci_revision =3D 0x30, > > > +}; > > > + > > > +static const struct cpu_info cpu_icx =3D { > > > +=A0=A0=A0=A0=A0=A0=A0.reg=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=3D &re= solved_cores_reg_icx, > > > +=A0=A0=A0=A0=A0=A0=A0.min_peci_revision =3D 0x40, > > > +}; > > > + > > > +static const struct auxiliary_device_id peci_cputemp_ids[] =3D { > > > +=A0=A0=A0=A0=A0=A0=A0{ > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0.name =3D "peci_cpu.cpu= temp.hsx", > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0.driver_data =3D (kerne= l_ulong_t)&cpu_hsx, > > > +=A0=A0=A0=A0=A0=A0=A0}, > > > +=A0=A0=A0=A0=A0=A0=A0{ > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0.name =3D "peci_cpu.cpu= temp.bdx", > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0.driver_data =3D (kerne= l_ulong_t)&cpu_hsx, > > > +=A0=A0=A0=A0=A0=A0=A0}, > > > +=A0=A0=A0=A0=A0=A0=A0{ > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0.name =3D "peci_cpu.cpu= temp.bdxd", > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0.driver_data =3D (kerne= l_ulong_t)&cpu_hsx, > > > +=A0=A0=A0=A0=A0=A0=A0}, > > > +=A0=A0=A0=A0=A0=A0=A0{ > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0.name =3D "peci_cpu.cpu= temp.skx", > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0.driver_data =3D (kerne= l_ulong_t)&cpu_hsx, > > > +=A0=A0=A0=A0=A0=A0=A0}, > > > +=A0=A0=A0=A0=A0=A0=A0{ > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0.name =3D "peci_cpu.cpu= temp.icx", > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0.driver_data =3D (kerne= l_ulong_t)&cpu_icx, > > > +=A0=A0=A0=A0=A0=A0=A0}, > > > +=A0=A0=A0=A0=A0=A0=A0{ > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0.name =3D "peci_cpu.cpu= temp.icxd", > > > +=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0.driver_data =3D (kerne= l_ulong_t)&cpu_icx, > > > +=A0=A0=A0=A0=A0=A0=A0}, > > > +=A0=A0=A0=A0=A0=A0=A0{ } > > > +}; > > > +MODULE_DEVICE_TABLE(auxiliary, peci_cputemp_ids); > > > + > > > +static struct auxiliary_driver peci_cputemp_driver =3D { > > > +=A0=A0=A0=A0=A0=A0=A0.probe=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=3D peci_cp= utemp_probe, > > > +=A0=A0=A0=A0=A0=A0=A0.id_table=A0=A0=A0=A0=A0=A0=A0=3D peci_cputemp_= ids, > > > +}; > > > + > > > +module_auxiliary_driver(peci_cputemp_driver); > > > + > > > +MODULE_AUTHOR("Jae Hyun Yoo "); > > > +MODULE_AUTHOR("Iwona Winiarska "); > > > +MODULE_DESCRIPTION("PECI cputemp driver"); > > > +MODULE_LICENSE("GPL"); > > > +MODULE_IMPORT_NS(PECI_CPU); > = _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel