mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-24 20:54:10 +08:00
NTB IDT thermal changes and hook into hwmon, ntb_netdev clean-up of
private struct, and a few bug fixes. -----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJb2zRKAAoJEG5mS6x6i9IjMMQP/1Xf2x27O0nb2NoKCyDbBAL9 LXUR7NYiATg3BKOWZS1MVcxmhLlUYNUNsiHenzER++tIt0Jbx70k1oKJrskKPbNR G3eN1uUhceioiSYDcE/02VERtwL3P+6RIBbiRcvzihv/nhPNtcD4mTI5nkM/5wPY 8I5PMzMJkQAezvYyXTPkk1TvycHOkFge+LNCtXRRRdemik5FIU3PlEM+8jLAFEmH DpiYr+g4Nvl8U+aqwXc/ffvDP9Ky5iRq48ifbWORXUVGNTckuTWL6DpYByuOimXL pzmIjzSc9tWJ/wXU71pHdTjQSRSixxdD7m2b91XLNBNvdz3G842E78vd1yH4Y8zp 9rTijHwfybhT3cUQnGJ+i6fw0TYUGhoQ/6/TXHDXFy6u01jIHVD30GFmRUpNH96O egItTbnANnhh+XxZMZpwum8K0a9/NMP5DKInBfyXmiEwFzOR8QG23ufjL52RLWwj KNgovXC+Y5NWpZ6PR2EP7UfHHe8ppZKO7RpWwe+1ZKkz1gFHEM6I3Es4AjNsPRO+ epBCetPc8Ib1NK3W9WCBa3LuuoZhSmym4jDuDejWsECCvrY/lNe5UIRtiH/1sI76 O6O0e6ncmUdJslJsY2KK2RWn1+tlORhcm8/1ARCVxr9nTgD0vRmPn82iX+L57Kih nOnsHDBroOszI5xCvQ76 =EhpD -----END PGP SIGNATURE----- Merge tag 'ntb-4.20' of git://github.com/jonmason/ntb Pull NTB updates from Jon Mason: "Fairly minor changes and bug fixes: NTB IDT thermal changes and hook into hwmon, ntb_netdev clean-up of private struct, and a few bug fixes" * tag 'ntb-4.20' of git://github.com/jonmason/ntb: ntb: idt: Alter the driver info comments ntb: idt: Discard temperature sensor IRQ handler ntb: idt: Add basic hwmon sysfs interface ntb: idt: Alter temperature read method ntb_netdev: Simplify remove with client device drvdata NTB: transport: Try harder to alloc an aligned MW buffer ntb: ntb_transport: Mark expected switch fall-throughs ntb: idt: Set PCIe bus address to BARLIMITx NTB: ntb_hw_idt: replace IS_ERR_OR_NULL with regular NULL checks ntb: intel: fix return value for ndev_vec_mask() ntb_netdev: fix sleep time mismatch
This commit is contained in:
commit
04578e8441
@ -71,7 +71,6 @@ static unsigned int tx_start = 10;
|
||||
static unsigned int tx_stop = 5;
|
||||
|
||||
struct ntb_netdev {
|
||||
struct list_head list;
|
||||
struct pci_dev *pdev;
|
||||
struct net_device *ndev;
|
||||
struct ntb_transport_qp *qp;
|
||||
@ -81,8 +80,6 @@ struct ntb_netdev {
|
||||
#define NTB_TX_TIMEOUT_MS 1000
|
||||
#define NTB_RXQ_SIZE 100
|
||||
|
||||
static LIST_HEAD(dev_list);
|
||||
|
||||
static void ntb_netdev_event_handler(void *data, int link_is_up)
|
||||
{
|
||||
struct net_device *ndev = data;
|
||||
@ -236,7 +233,7 @@ static void ntb_netdev_tx_timer(struct timer_list *t)
|
||||
struct net_device *ndev = dev->ndev;
|
||||
|
||||
if (ntb_transport_tx_free_entry(dev->qp) < tx_stop) {
|
||||
mod_timer(&dev->tx_timer, jiffies + msecs_to_jiffies(tx_time));
|
||||
mod_timer(&dev->tx_timer, jiffies + usecs_to_jiffies(tx_time));
|
||||
} else {
|
||||
/* Make sure anybody stopping the queue after this sees the new
|
||||
* value of ntb_transport_tx_free_entry()
|
||||
@ -452,7 +449,7 @@ static int ntb_netdev_probe(struct device *client_dev)
|
||||
if (rc)
|
||||
goto err1;
|
||||
|
||||
list_add(&dev->list, &dev_list);
|
||||
dev_set_drvdata(client_dev, ndev);
|
||||
dev_info(&pdev->dev, "%s created\n", ndev->name);
|
||||
return 0;
|
||||
|
||||
@ -465,27 +462,8 @@ err:
|
||||
|
||||
static void ntb_netdev_remove(struct device *client_dev)
|
||||
{
|
||||
struct ntb_dev *ntb;
|
||||
struct net_device *ndev;
|
||||
struct pci_dev *pdev;
|
||||
struct ntb_netdev *dev;
|
||||
bool found = false;
|
||||
|
||||
ntb = dev_ntb(client_dev->parent);
|
||||
pdev = ntb->pdev;
|
||||
|
||||
list_for_each_entry(dev, &dev_list, list) {
|
||||
if (dev->pdev == pdev) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
return;
|
||||
|
||||
list_del(&dev->list);
|
||||
|
||||
ndev = dev->ndev;
|
||||
struct net_device *ndev = dev_get_drvdata(client_dev);
|
||||
struct ntb_netdev *dev = netdev_priv(ndev);
|
||||
|
||||
unregister_netdev(ndev);
|
||||
ntb_transport_free_queue(dev->qp);
|
||||
|
@ -1,6 +1,7 @@
|
||||
config NTB_IDT
|
||||
tristate "IDT PCIe-switch Non-Transparent Bridge support"
|
||||
depends on PCI
|
||||
select HWMON
|
||||
help
|
||||
This driver supports NTB of cappable IDT PCIe-switches.
|
||||
|
||||
@ -23,9 +24,7 @@ config NTB_IDT
|
||||
BAR settings of peer NT-functions, the BAR setups can't be done over
|
||||
kernel PCI fixups. That's why the alternative pre-initialization
|
||||
techniques like BIOS using SMBus interface or EEPROM should be
|
||||
utilized. Additionally if one needs to have temperature sensor
|
||||
information printed to system log, the corresponding registers must
|
||||
be initialized within BIOS/EEPROM as well.
|
||||
utilized.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright (C) 2016 T-Platforms All Rights Reserved.
|
||||
* Copyright (C) 2016-2018 T-Platforms JSC All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@ -49,11 +49,14 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/aer.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/ntb.h>
|
||||
|
||||
#include "ntb_hw_idt.h"
|
||||
@ -1105,9 +1108,9 @@ static struct idt_mw_cfg *idt_scan_mws(struct idt_ntb_dev *ndev, int port,
|
||||
}
|
||||
|
||||
/* Allocate memory for memory window descriptors */
|
||||
ret_mws = devm_kcalloc(&ndev->ntb.pdev->dev, *mw_cnt,
|
||||
sizeof(*ret_mws), GFP_KERNEL);
|
||||
if (IS_ERR_OR_NULL(ret_mws))
|
||||
ret_mws = devm_kcalloc(&ndev->ntb.pdev->dev, *mw_cnt, sizeof(*ret_mws),
|
||||
GFP_KERNEL);
|
||||
if (!ret_mws)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
/* Copy the info of detected memory windows */
|
||||
@ -1320,7 +1323,7 @@ static int idt_ntb_peer_mw_set_trans(struct ntb_dev *ntb, int pidx, int widx,
|
||||
idt_nt_write(ndev, bar->ltbase, (u32)addr);
|
||||
idt_nt_write(ndev, bar->utbase, (u32)(addr >> 32));
|
||||
/* Set the custom BAR aperture limit */
|
||||
limit = pci_resource_start(ntb->pdev, mw_cfg->bar) + size;
|
||||
limit = pci_bus_address(ntb->pdev, mw_cfg->bar) + size;
|
||||
idt_nt_write(ndev, bar->limit, (u32)limit);
|
||||
if (IS_FLD_SET(BARSETUP_TYPE, data, 64))
|
||||
idt_nt_write(ndev, (bar + 1)->limit, (limit >> 32));
|
||||
@ -1821,61 +1824,284 @@ static int idt_ntb_peer_msg_write(struct ntb_dev *ntb, int pidx, int midx,
|
||||
* 7. Temperature sensor operations
|
||||
*
|
||||
* IDT PCIe-switch has an embedded temperature sensor, which can be used to
|
||||
* warn a user-space of possible chip overheating. Since workload temperature
|
||||
* can be different on different platforms, temperature thresholds as well as
|
||||
* general sensor settings must be setup in the framework of BIOS/EEPROM
|
||||
* initializations. It includes the actual sensor enabling as well.
|
||||
* check current chip core temperature. Since a workload environment can be
|
||||
* different on different platforms, an offset and ADC/filter settings can be
|
||||
* specified. Although the offset configuration is only exposed to the sysfs
|
||||
* hwmon interface at the moment. The rest of the settings can be adjusted
|
||||
* for instance by the BIOS/EEPROM firmware.
|
||||
*=============================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
* idt_read_temp() - read temperature from chip sensor
|
||||
* @ntb: NTB device context.
|
||||
* @val: OUT - integer value of temperature
|
||||
* @frac: OUT - fraction
|
||||
* idt_get_deg() - convert millidegree Celsius value to just degree
|
||||
* @mdegC: IN - millidegree Celsius value
|
||||
*
|
||||
* Return: Degree corresponding to the passed millidegree value
|
||||
*/
|
||||
static void idt_read_temp(struct idt_ntb_dev *ndev, unsigned char *val,
|
||||
unsigned char *frac)
|
||||
static inline s8 idt_get_deg(long mdegC)
|
||||
{
|
||||
u32 data;
|
||||
|
||||
/* Read the data from TEMP field of the TMPSTS register */
|
||||
data = idt_sw_read(ndev, IDT_SW_TMPSTS);
|
||||
data = GET_FIELD(TMPSTS_TEMP, data);
|
||||
/* TEMP field has one fractional bit and seven integer bits */
|
||||
*val = data >> 1;
|
||||
*frac = ((data & 0x1) ? 5 : 0);
|
||||
return mdegC / 1000;
|
||||
}
|
||||
|
||||
/*
|
||||
* idt_temp_isr() - temperature sensor alarm events ISR
|
||||
* @ndev: IDT NTB hardware driver descriptor
|
||||
* @ntint_sts: NT-function interrupt status
|
||||
* idt_get_frac() - retrieve 0/0.5 fraction of the millidegree Celsius value
|
||||
* @mdegC: IN - millidegree Celsius value
|
||||
*
|
||||
* It handles events of temperature crossing alarm thresholds. Since reading
|
||||
* of TMPALARM register clears it up, the function doesn't analyze the
|
||||
* read value, instead the current temperature value just warningly printed to
|
||||
* log.
|
||||
* The method is called from PCIe ISR bottom-half routine.
|
||||
* Return: 0/0.5 degree fraction of the passed millidegree value
|
||||
*/
|
||||
static void idt_temp_isr(struct idt_ntb_dev *ndev, u32 ntint_sts)
|
||||
static inline u8 idt_get_deg_frac(long mdegC)
|
||||
{
|
||||
unsigned char val, frac;
|
||||
return (mdegC % 1000) >= 500 ? 5 : 0;
|
||||
}
|
||||
|
||||
/* Read the current temperature value */
|
||||
idt_read_temp(ndev, &val, &frac);
|
||||
/*
|
||||
* idt_get_temp_fmt() - convert millidegree Celsius value to 0:7:1 format
|
||||
* @mdegC: IN - millidegree Celsius value
|
||||
*
|
||||
* Return: 0:7:1 format acceptable by the IDT temperature sensor
|
||||
*/
|
||||
static inline u8 idt_temp_get_fmt(long mdegC)
|
||||
{
|
||||
return (idt_get_deg(mdegC) << 1) | (idt_get_deg_frac(mdegC) ? 1 : 0);
|
||||
}
|
||||
|
||||
/* Read the temperature alarm to clean the alarm status out */
|
||||
/*(void)idt_sw_read(ndev, IDT_SW_TMPALARM);*/
|
||||
/*
|
||||
* idt_get_temp_sval() - convert temp sample to signed millidegree Celsius
|
||||
* @data: IN - shifted to LSB 8-bits temperature sample
|
||||
*
|
||||
* Return: signed millidegree Celsius
|
||||
*/
|
||||
static inline long idt_get_temp_sval(u32 data)
|
||||
{
|
||||
return ((s8)data / 2) * 1000 + (data & 0x1 ? 500 : 0);
|
||||
}
|
||||
|
||||
/* Clean the corresponding interrupt bit */
|
||||
idt_nt_write(ndev, IDT_NT_NTINTSTS, IDT_NTINTSTS_TMPSENSOR);
|
||||
/*
|
||||
* idt_get_temp_sval() - convert temp sample to unsigned millidegree Celsius
|
||||
* @data: IN - shifted to LSB 8-bits temperature sample
|
||||
*
|
||||
* Return: unsigned millidegree Celsius
|
||||
*/
|
||||
static inline long idt_get_temp_uval(u32 data)
|
||||
{
|
||||
return (data / 2) * 1000 + (data & 0x1 ? 500 : 0);
|
||||
}
|
||||
|
||||
dev_dbg(&ndev->ntb.pdev->dev,
|
||||
"Temp sensor IRQ detected %#08x", ntint_sts);
|
||||
/*
|
||||
* idt_read_temp() - read temperature from chip sensor
|
||||
* @ntb: NTB device context.
|
||||
* @type: IN - type of the temperature value to read
|
||||
* @val: OUT - integer value of temperature in millidegree Celsius
|
||||
*/
|
||||
static void idt_read_temp(struct idt_ntb_dev *ndev,
|
||||
const enum idt_temp_val type, long *val)
|
||||
{
|
||||
u32 data;
|
||||
|
||||
/* Print temperature value to log */
|
||||
dev_warn(&ndev->ntb.pdev->dev, "Temperature %hhu.%hhu", val, frac);
|
||||
/* Alter the temperature field in accordance with the passed type */
|
||||
switch (type) {
|
||||
case IDT_TEMP_CUR:
|
||||
data = GET_FIELD(TMPSTS_TEMP,
|
||||
idt_sw_read(ndev, IDT_SW_TMPSTS));
|
||||
break;
|
||||
case IDT_TEMP_LOW:
|
||||
data = GET_FIELD(TMPSTS_LTEMP,
|
||||
idt_sw_read(ndev, IDT_SW_TMPSTS));
|
||||
break;
|
||||
case IDT_TEMP_HIGH:
|
||||
data = GET_FIELD(TMPSTS_HTEMP,
|
||||
idt_sw_read(ndev, IDT_SW_TMPSTS));
|
||||
break;
|
||||
case IDT_TEMP_OFFSET:
|
||||
/* This is the only field with signed 0:7:1 format */
|
||||
data = GET_FIELD(TMPADJ_OFFSET,
|
||||
idt_sw_read(ndev, IDT_SW_TMPADJ));
|
||||
*val = idt_get_temp_sval(data);
|
||||
return;
|
||||
default:
|
||||
data = GET_FIELD(TMPSTS_TEMP,
|
||||
idt_sw_read(ndev, IDT_SW_TMPSTS));
|
||||
break;
|
||||
}
|
||||
|
||||
/* The rest of the fields accept unsigned 0:7:1 format */
|
||||
*val = idt_get_temp_uval(data);
|
||||
}
|
||||
|
||||
/*
|
||||
* idt_write_temp() - write temperature to the chip sensor register
|
||||
* @ntb: NTB device context.
|
||||
* @type: IN - type of the temperature value to change
|
||||
* @val: IN - integer value of temperature in millidegree Celsius
|
||||
*/
|
||||
static void idt_write_temp(struct idt_ntb_dev *ndev,
|
||||
const enum idt_temp_val type, const long val)
|
||||
{
|
||||
unsigned int reg;
|
||||
u32 data;
|
||||
u8 fmt;
|
||||
|
||||
/* Retrieve the properly formatted temperature value */
|
||||
fmt = idt_temp_get_fmt(val);
|
||||
|
||||
mutex_lock(&ndev->hwmon_mtx);
|
||||
switch (type) {
|
||||
case IDT_TEMP_LOW:
|
||||
reg = IDT_SW_TMPALARM;
|
||||
data = SET_FIELD(TMPALARM_LTEMP, idt_sw_read(ndev, reg), fmt) &
|
||||
~IDT_TMPALARM_IRQ_MASK;
|
||||
break;
|
||||
case IDT_TEMP_HIGH:
|
||||
reg = IDT_SW_TMPALARM;
|
||||
data = SET_FIELD(TMPALARM_HTEMP, idt_sw_read(ndev, reg), fmt) &
|
||||
~IDT_TMPALARM_IRQ_MASK;
|
||||
break;
|
||||
case IDT_TEMP_OFFSET:
|
||||
reg = IDT_SW_TMPADJ;
|
||||
data = SET_FIELD(TMPADJ_OFFSET, idt_sw_read(ndev, reg), fmt);
|
||||
break;
|
||||
default:
|
||||
goto inval_spin_unlock;
|
||||
}
|
||||
|
||||
idt_sw_write(ndev, reg, data);
|
||||
|
||||
inval_spin_unlock:
|
||||
mutex_unlock(&ndev->hwmon_mtx);
|
||||
}
|
||||
|
||||
/*
|
||||
* idt_sysfs_show_temp() - printout corresponding temperature value
|
||||
* @dev: Pointer to the NTB device structure
|
||||
* @da: Sensor device attribute structure
|
||||
* @buf: Buffer to print temperature out
|
||||
*
|
||||
* Return: Number of written symbols or negative error
|
||||
*/
|
||||
static ssize_t idt_sysfs_show_temp(struct device *dev,
|
||||
struct device_attribute *da, char *buf)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct idt_ntb_dev *ndev = dev_get_drvdata(dev);
|
||||
enum idt_temp_val type = attr->index;
|
||||
long mdeg;
|
||||
|
||||
idt_read_temp(ndev, type, &mdeg);
|
||||
return sprintf(buf, "%ld\n", mdeg);
|
||||
}
|
||||
|
||||
/*
|
||||
* idt_sysfs_set_temp() - set corresponding temperature value
|
||||
* @dev: Pointer to the NTB device structure
|
||||
* @da: Sensor device attribute structure
|
||||
* @buf: Buffer to print temperature out
|
||||
* @count: Size of the passed buffer
|
||||
*
|
||||
* Return: Number of written symbols or negative error
|
||||
*/
|
||||
static ssize_t idt_sysfs_set_temp(struct device *dev,
|
||||
struct device_attribute *da, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
|
||||
struct idt_ntb_dev *ndev = dev_get_drvdata(dev);
|
||||
enum idt_temp_val type = attr->index;
|
||||
long mdeg;
|
||||
int ret;
|
||||
|
||||
ret = kstrtol(buf, 10, &mdeg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Clamp the passed value in accordance with the type */
|
||||
if (type == IDT_TEMP_OFFSET)
|
||||
mdeg = clamp_val(mdeg, IDT_TEMP_MIN_OFFSET,
|
||||
IDT_TEMP_MAX_OFFSET);
|
||||
else
|
||||
mdeg = clamp_val(mdeg, IDT_TEMP_MIN_MDEG, IDT_TEMP_MAX_MDEG);
|
||||
|
||||
idt_write_temp(ndev, type, mdeg);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* idt_sysfs_reset_hist() - reset temperature history
|
||||
* @dev: Pointer to the NTB device structure
|
||||
* @da: Sensor device attribute structure
|
||||
* @buf: Buffer to print temperature out
|
||||
* @count: Size of the passed buffer
|
||||
*
|
||||
* Return: Number of written symbols or negative error
|
||||
*/
|
||||
static ssize_t idt_sysfs_reset_hist(struct device *dev,
|
||||
struct device_attribute *da,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct idt_ntb_dev *ndev = dev_get_drvdata(dev);
|
||||
|
||||
/* Just set the maximal value to the lowest temperature field and
|
||||
* minimal value to the highest temperature field
|
||||
*/
|
||||
idt_write_temp(ndev, IDT_TEMP_LOW, IDT_TEMP_MAX_MDEG);
|
||||
idt_write_temp(ndev, IDT_TEMP_HIGH, IDT_TEMP_MIN_MDEG);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Hwmon IDT sysfs attributes
|
||||
*/
|
||||
static SENSOR_DEVICE_ATTR(temp1_input, 0444, idt_sysfs_show_temp, NULL,
|
||||
IDT_TEMP_CUR);
|
||||
static SENSOR_DEVICE_ATTR(temp1_lowest, 0444, idt_sysfs_show_temp, NULL,
|
||||
IDT_TEMP_LOW);
|
||||
static SENSOR_DEVICE_ATTR(temp1_highest, 0444, idt_sysfs_show_temp, NULL,
|
||||
IDT_TEMP_HIGH);
|
||||
static SENSOR_DEVICE_ATTR(temp1_offset, 0644, idt_sysfs_show_temp,
|
||||
idt_sysfs_set_temp, IDT_TEMP_OFFSET);
|
||||
static DEVICE_ATTR(temp1_reset_history, 0200, NULL, idt_sysfs_reset_hist);
|
||||
|
||||
/*
|
||||
* Hwmon IDT sysfs attributes group
|
||||
*/
|
||||
static struct attribute *idt_temp_attrs[] = {
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_lowest.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_highest.dev_attr.attr,
|
||||
&sensor_dev_attr_temp1_offset.dev_attr.attr,
|
||||
&dev_attr_temp1_reset_history.attr,
|
||||
NULL
|
||||
};
|
||||
ATTRIBUTE_GROUPS(idt_temp);
|
||||
|
||||
/*
|
||||
* idt_init_temp() - initialize temperature sensor interface
|
||||
* @ndev: IDT NTB hardware driver descriptor
|
||||
*
|
||||
* Simple sensor initializarion method is responsible for device switching
|
||||
* on and resource management based hwmon interface registration. Note, that
|
||||
* since the device is shared we won't disable it on remove, but leave it
|
||||
* working until the system is powered off.
|
||||
*/
|
||||
static void idt_init_temp(struct idt_ntb_dev *ndev)
|
||||
{
|
||||
struct device *hwmon;
|
||||
|
||||
/* Enable sensor if it hasn't been already */
|
||||
idt_sw_write(ndev, IDT_SW_TMPCTL, 0x0);
|
||||
|
||||
/* Initialize hwmon interface fields */
|
||||
mutex_init(&ndev->hwmon_mtx);
|
||||
|
||||
hwmon = devm_hwmon_device_register_with_groups(&ndev->ntb.pdev->dev,
|
||||
ndev->swcfg->name, ndev, idt_temp_groups);
|
||||
if (IS_ERR(hwmon)) {
|
||||
dev_err(&ndev->ntb.pdev->dev, "Couldn't create hwmon device");
|
||||
return;
|
||||
}
|
||||
|
||||
dev_dbg(&ndev->ntb.pdev->dev, "Temperature HWmon interface registered");
|
||||
}
|
||||
|
||||
/*=============================================================================
|
||||
@ -1931,7 +2157,7 @@ static int idt_init_isr(struct idt_ntb_dev *ndev)
|
||||
goto err_free_vectors;
|
||||
}
|
||||
|
||||
/* Unmask Message/Doorbell/SE/Temperature interrupts */
|
||||
/* Unmask Message/Doorbell/SE interrupts */
|
||||
ntint_mask = idt_nt_read(ndev, IDT_NT_NTINTMSK) & ~IDT_NTINTMSK_ALL;
|
||||
idt_nt_write(ndev, IDT_NT_NTINTMSK, ntint_mask);
|
||||
|
||||
@ -1946,7 +2172,6 @@ err_free_vectors:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* idt_deinit_ist() - deinitialize PCIe interrupt handler
|
||||
* @ndev: IDT NTB hardware driver descriptor
|
||||
@ -2007,12 +2232,6 @@ static irqreturn_t idt_thread_isr(int irq, void *devid)
|
||||
handled = true;
|
||||
}
|
||||
|
||||
/* Handle temperature sensor interrupt */
|
||||
if (ntint_sts & IDT_NTINTSTS_TMPSENSOR) {
|
||||
idt_temp_isr(ndev, ntint_sts);
|
||||
handled = true;
|
||||
}
|
||||
|
||||
dev_dbg(&ndev->ntb.pdev->dev, "IDT IRQs 0x%08x handled", ntint_sts);
|
||||
|
||||
return handled ? IRQ_HANDLED : IRQ_NONE;
|
||||
@ -2123,9 +2342,9 @@ static ssize_t idt_dbgfs_info_read(struct file *filp, char __user *ubuf,
|
||||
size_t count, loff_t *offp)
|
||||
{
|
||||
struct idt_ntb_dev *ndev = filp->private_data;
|
||||
unsigned char temp, frac, idx, pidx, cnt;
|
||||
unsigned char idx, pidx, cnt;
|
||||
unsigned long irqflags, mdeg;
|
||||
ssize_t ret = 0, off = 0;
|
||||
unsigned long irqflags;
|
||||
enum ntb_speed speed;
|
||||
enum ntb_width width;
|
||||
char *strbuf;
|
||||
@ -2274,9 +2493,10 @@ static ssize_t idt_dbgfs_info_read(struct file *filp, char __user *ubuf,
|
||||
off += scnprintf(strbuf + off, size - off, "\n");
|
||||
|
||||
/* Current temperature */
|
||||
idt_read_temp(ndev, &temp, &frac);
|
||||
idt_read_temp(ndev, IDT_TEMP_CUR, &mdeg);
|
||||
off += scnprintf(strbuf + off, size - off,
|
||||
"Switch temperature\t\t- %hhu.%hhuC\n", temp, frac);
|
||||
"Switch temperature\t\t- %hhd.%hhuC\n",
|
||||
idt_get_deg(mdeg), idt_get_deg_frac(mdeg));
|
||||
|
||||
/* Copy the buffer to the User Space */
|
||||
ret = simple_read_from_buffer(ubuf, count, offp, strbuf, off);
|
||||
@ -2390,7 +2610,7 @@ static struct idt_ntb_dev *idt_create_dev(struct pci_dev *pdev,
|
||||
|
||||
/* Allocate memory for the IDT PCIe-device descriptor */
|
||||
ndev = devm_kzalloc(&pdev->dev, sizeof(*ndev), GFP_KERNEL);
|
||||
if (IS_ERR_OR_NULL(ndev)) {
|
||||
if (!ndev) {
|
||||
dev_err(&pdev->dev, "Memory allocation failed for descriptor");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
@ -2571,6 +2791,9 @@ static int idt_pci_probe(struct pci_dev *pdev,
|
||||
/* Initialize Messaging subsystem */
|
||||
idt_init_msg(ndev);
|
||||
|
||||
/* Initialize hwmon interface */
|
||||
idt_init_temp(ndev);
|
||||
|
||||
/* Initialize IDT interrupts handler */
|
||||
ret = idt_init_isr(ndev);
|
||||
if (ret != 0)
|
||||
|
@ -4,7 +4,7 @@
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright (C) 2016 T-Platforms All Rights Reserved.
|
||||
* Copyright (C) 2016-2018 T-Platforms JSC All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
@ -47,9 +47,9 @@
|
||||
#include <linux/pci_ids.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/ntb.h>
|
||||
|
||||
|
||||
/*
|
||||
* Macro is used to create the struct pci_device_id that matches
|
||||
* the supported IDT PCIe-switches
|
||||
@ -688,15 +688,14 @@
|
||||
* @IDT_NTINTMSK_DBELL: Doorbell interrupt mask bit
|
||||
* @IDT_NTINTMSK_SEVENT: Switch Event interrupt mask bit
|
||||
* @IDT_NTINTMSK_TMPSENSOR: Temperature sensor interrupt mask bit
|
||||
* @IDT_NTINTMSK_ALL: All the useful interrupts mask
|
||||
* @IDT_NTINTMSK_ALL: NTB-related interrupts mask
|
||||
*/
|
||||
#define IDT_NTINTMSK_MSG 0x00000001U
|
||||
#define IDT_NTINTMSK_DBELL 0x00000002U
|
||||
#define IDT_NTINTMSK_SEVENT 0x00000008U
|
||||
#define IDT_NTINTMSK_TMPSENSOR 0x00000080U
|
||||
#define IDT_NTINTMSK_ALL \
|
||||
(IDT_NTINTMSK_MSG | IDT_NTINTMSK_DBELL | \
|
||||
IDT_NTINTMSK_SEVENT | IDT_NTINTMSK_TMPSENSOR)
|
||||
(IDT_NTINTMSK_MSG | IDT_NTINTMSK_DBELL | IDT_NTINTMSK_SEVENT)
|
||||
|
||||
/*
|
||||
* NTGSIGNAL register fields related constants
|
||||
@ -885,13 +884,61 @@
|
||||
#define IDT_SWPxMSGCTL_PART_MASK 0x00000070U
|
||||
#define IDT_SWPxMSGCTL_PART_FLD 4
|
||||
|
||||
/*
|
||||
* TMPCTL register fields related constants
|
||||
* @IDT_TMPCTL_LTH_MASK: Low temperature threshold field mask
|
||||
* @IDT_TMPCTL_LTH_FLD: Low temperature threshold field offset
|
||||
* @IDT_TMPCTL_MTH_MASK: Middle temperature threshold field mask
|
||||
* @IDT_TMPCTL_MTH_FLD: Middle temperature threshold field offset
|
||||
* @IDT_TMPCTL_HTH_MASK: High temperature threshold field mask
|
||||
* @IDT_TMPCTL_HTH_FLD: High temperature threshold field offset
|
||||
* @IDT_TMPCTL_PDOWN: Temperature sensor power down
|
||||
*/
|
||||
#define IDT_TMPCTL_LTH_MASK 0x000000FFU
|
||||
#define IDT_TMPCTL_LTH_FLD 0
|
||||
#define IDT_TMPCTL_MTH_MASK 0x0000FF00U
|
||||
#define IDT_TMPCTL_MTH_FLD 8
|
||||
#define IDT_TMPCTL_HTH_MASK 0x00FF0000U
|
||||
#define IDT_TMPCTL_HTH_FLD 16
|
||||
#define IDT_TMPCTL_PDOWN 0x80000000U
|
||||
|
||||
/*
|
||||
* TMPSTS register fields related constants
|
||||
* @IDT_TMPSTS_TEMP_MASK: Current temperature field mask
|
||||
* @IDT_TMPSTS_TEMP_FLD: Current temperature field offset
|
||||
* @IDT_TMPSTS_LTEMP_MASK: Lowest temperature field mask
|
||||
* @IDT_TMPSTS_LTEMP_FLD: Lowest temperature field offset
|
||||
* @IDT_TMPSTS_HTEMP_MASK: Highest temperature field mask
|
||||
* @IDT_TMPSTS_HTEMP_FLD: Highest temperature field offset
|
||||
*/
|
||||
#define IDT_TMPSTS_TEMP_MASK 0x000000FFU
|
||||
#define IDT_TMPSTS_TEMP_FLD 0
|
||||
#define IDT_TMPSTS_LTEMP_MASK 0x0000FF00U
|
||||
#define IDT_TMPSTS_LTEMP_FLD 8
|
||||
#define IDT_TMPSTS_HTEMP_MASK 0x00FF0000U
|
||||
#define IDT_TMPSTS_HTEMP_FLD 16
|
||||
|
||||
/*
|
||||
* TMPALARM register fields related constants
|
||||
* @IDT_TMPALARM_LTEMP_MASK: Lowest temperature field mask
|
||||
* @IDT_TMPALARM_LTEMP_FLD: Lowest temperature field offset
|
||||
* @IDT_TMPALARM_HTEMP_MASK: Highest temperature field mask
|
||||
* @IDT_TMPALARM_HTEMP_FLD: Highest temperature field offset
|
||||
* @IDT_TMPALARM_IRQ_MASK: Alarm IRQ status mask
|
||||
*/
|
||||
#define IDT_TMPALARM_LTEMP_MASK 0x0000FF00U
|
||||
#define IDT_TMPALARM_LTEMP_FLD 8
|
||||
#define IDT_TMPALARM_HTEMP_MASK 0x00FF0000U
|
||||
#define IDT_TMPALARM_HTEMP_FLD 16
|
||||
#define IDT_TMPALARM_IRQ_MASK 0x3F000000U
|
||||
|
||||
/*
|
||||
* TMPADJ register fields related constants
|
||||
* @IDT_TMPADJ_OFFSET_MASK: Temperature value offset field mask
|
||||
* @IDT_TMPADJ_OFFSET_FLD: Temperature value offset field offset
|
||||
*/
|
||||
#define IDT_TMPADJ_OFFSET_MASK 0x000000FFU
|
||||
#define IDT_TMPADJ_OFFSET_FLD 0
|
||||
|
||||
/*
|
||||
* Helper macro to get/set the corresponding field value
|
||||
@ -950,6 +997,32 @@
|
||||
#define IDT_TRANS_ALIGN 4
|
||||
#define IDT_DIR_SIZE_ALIGN 1
|
||||
|
||||
/*
|
||||
* IDT PCIe-switch temperature sensor value limits
|
||||
* @IDT_TEMP_MIN_MDEG: Minimal integer value of temperature
|
||||
* @IDT_TEMP_MAX_MDEG: Maximal integer value of temperature
|
||||
* @IDT_TEMP_MIN_OFFSET:Minimal integer value of temperature offset
|
||||
* @IDT_TEMP_MAX_OFFSET:Maximal integer value of temperature offset
|
||||
*/
|
||||
#define IDT_TEMP_MIN_MDEG 0
|
||||
#define IDT_TEMP_MAX_MDEG 127500
|
||||
#define IDT_TEMP_MIN_OFFSET -64000
|
||||
#define IDT_TEMP_MAX_OFFSET 63500
|
||||
|
||||
/*
|
||||
* Temperature sensor values enumeration
|
||||
* @IDT_TEMP_CUR: Current temperature
|
||||
* @IDT_TEMP_LOW: Lowest historical temperature
|
||||
* @IDT_TEMP_HIGH: Highest historical temperature
|
||||
* @IDT_TEMP_OFFSET: Current temperature offset
|
||||
*/
|
||||
enum idt_temp_val {
|
||||
IDT_TEMP_CUR,
|
||||
IDT_TEMP_LOW,
|
||||
IDT_TEMP_HIGH,
|
||||
IDT_TEMP_OFFSET
|
||||
};
|
||||
|
||||
/*
|
||||
* IDT Memory Windows type. Depending on the device settings, IDT supports
|
||||
* Direct Address Translation MW registers and Lookup Table registers
|
||||
@ -1044,6 +1117,8 @@ struct idt_ntb_peer {
|
||||
* @msg_mask_lock: Message mask register lock
|
||||
* @gasa_lock: GASA registers access lock
|
||||
*
|
||||
* @hwmon_mtx: Temperature sensor interface update mutex
|
||||
*
|
||||
* @dbgfs_info: DebugFS info node
|
||||
*/
|
||||
struct idt_ntb_dev {
|
||||
@ -1071,6 +1146,8 @@ struct idt_ntb_dev {
|
||||
spinlock_t msg_mask_lock;
|
||||
spinlock_t gasa_lock;
|
||||
|
||||
struct mutex hwmon_mtx;
|
||||
|
||||
struct dentry *dbgfs_info;
|
||||
};
|
||||
#define to_ndev_ntb(__ntb) container_of(__ntb, struct idt_ntb_dev, ntb)
|
||||
|
@ -265,7 +265,7 @@ static inline int ndev_db_clear_mask(struct intel_ntb_dev *ndev, u64 db_bits,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ndev_vec_mask(struct intel_ntb_dev *ndev, int db_vector)
|
||||
static inline u64 ndev_vec_mask(struct intel_ntb_dev *ndev, int db_vector)
|
||||
{
|
||||
u64 shift, mask;
|
||||
|
||||
|
@ -194,6 +194,8 @@ struct ntb_transport_mw {
|
||||
void __iomem *vbase;
|
||||
size_t xlat_size;
|
||||
size_t buff_size;
|
||||
size_t alloc_size;
|
||||
void *alloc_addr;
|
||||
void *virt_addr;
|
||||
dma_addr_t dma_addr;
|
||||
};
|
||||
@ -672,13 +674,59 @@ static void ntb_free_mw(struct ntb_transport_ctx *nt, int num_mw)
|
||||
return;
|
||||
|
||||
ntb_mw_clear_trans(nt->ndev, PIDX, num_mw);
|
||||
dma_free_coherent(&pdev->dev, mw->buff_size,
|
||||
mw->virt_addr, mw->dma_addr);
|
||||
dma_free_coherent(&pdev->dev, mw->alloc_size,
|
||||
mw->alloc_addr, mw->dma_addr);
|
||||
mw->xlat_size = 0;
|
||||
mw->buff_size = 0;
|
||||
mw->alloc_size = 0;
|
||||
mw->alloc_addr = NULL;
|
||||
mw->virt_addr = NULL;
|
||||
}
|
||||
|
||||
static int ntb_alloc_mw_buffer(struct ntb_transport_mw *mw,
|
||||
struct device *dma_dev, size_t align)
|
||||
{
|
||||
dma_addr_t dma_addr;
|
||||
void *alloc_addr, *virt_addr;
|
||||
int rc;
|
||||
|
||||
alloc_addr = dma_alloc_coherent(dma_dev, mw->alloc_size,
|
||||
&dma_addr, GFP_KERNEL);
|
||||
if (!alloc_addr) {
|
||||
dev_err(dma_dev, "Unable to alloc MW buff of size %zu\n",
|
||||
mw->alloc_size);
|
||||
return -ENOMEM;
|
||||
}
|
||||
virt_addr = alloc_addr;
|
||||
|
||||
/*
|
||||
* we must ensure that the memory address allocated is BAR size
|
||||
* aligned in order for the XLAT register to take the value. This
|
||||
* is a requirement of the hardware. It is recommended to setup CMA
|
||||
* for BAR sizes equal or greater than 4MB.
|
||||
*/
|
||||
if (!IS_ALIGNED(dma_addr, align)) {
|
||||
if (mw->alloc_size > mw->buff_size) {
|
||||
virt_addr = PTR_ALIGN(alloc_addr, align);
|
||||
dma_addr = ALIGN(dma_addr, align);
|
||||
} else {
|
||||
rc = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
mw->alloc_addr = alloc_addr;
|
||||
mw->virt_addr = virt_addr;
|
||||
mw->dma_addr = dma_addr;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
dma_free_coherent(dma_dev, mw->alloc_size, alloc_addr, dma_addr);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw,
|
||||
resource_size_t size)
|
||||
{
|
||||
@ -710,28 +758,20 @@ static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw,
|
||||
/* Alloc memory for receiving data. Must be aligned */
|
||||
mw->xlat_size = xlat_size;
|
||||
mw->buff_size = buff_size;
|
||||
mw->alloc_size = buff_size;
|
||||
|
||||
mw->virt_addr = dma_alloc_coherent(&pdev->dev, buff_size,
|
||||
&mw->dma_addr, GFP_KERNEL);
|
||||
if (!mw->virt_addr) {
|
||||
mw->xlat_size = 0;
|
||||
mw->buff_size = 0;
|
||||
dev_err(&pdev->dev, "Unable to alloc MW buff of size %zu\n",
|
||||
buff_size);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/*
|
||||
* we must ensure that the memory address allocated is BAR size
|
||||
* aligned in order for the XLAT register to take the value. This
|
||||
* is a requirement of the hardware. It is recommended to setup CMA
|
||||
* for BAR sizes equal or greater than 4MB.
|
||||
*/
|
||||
if (!IS_ALIGNED(mw->dma_addr, xlat_align)) {
|
||||
dev_err(&pdev->dev, "DMA memory %pad is not aligned\n",
|
||||
&mw->dma_addr);
|
||||
ntb_free_mw(nt, num_mw);
|
||||
return -ENOMEM;
|
||||
rc = ntb_alloc_mw_buffer(mw, &pdev->dev, xlat_align);
|
||||
if (rc) {
|
||||
mw->alloc_size *= 2;
|
||||
rc = ntb_alloc_mw_buffer(mw, &pdev->dev, xlat_align);
|
||||
if (rc) {
|
||||
dev_err(&pdev->dev,
|
||||
"Unable to alloc aligned MW buff\n");
|
||||
mw->xlat_size = 0;
|
||||
mw->buff_size = 0;
|
||||
mw->alloc_size = 0;
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
/* Notify HW the memory location of the receive buffer */
|
||||
@ -1278,6 +1318,7 @@ static void ntb_rx_copy_callback(void *data,
|
||||
case DMA_TRANS_READ_FAILED:
|
||||
case DMA_TRANS_WRITE_FAILED:
|
||||
entry->errors++;
|
||||
/* fall through */
|
||||
case DMA_TRANS_ABORTED:
|
||||
{
|
||||
struct ntb_transport_qp *qp = entry->qp;
|
||||
@ -1533,6 +1574,7 @@ static void ntb_tx_copy_callback(void *data,
|
||||
case DMA_TRANS_READ_FAILED:
|
||||
case DMA_TRANS_WRITE_FAILED:
|
||||
entry->errors++;
|
||||
/* fall through */
|
||||
case DMA_TRANS_ABORTED:
|
||||
{
|
||||
void __iomem *offset =
|
||||
|
Loading…
Reference in New Issue
Block a user