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:
Linus Torvalds 2018-11-04 08:12:44 -08:00
commit 04578e8441
6 changed files with 433 additions and 114 deletions

View File

@ -71,7 +71,6 @@ static unsigned int tx_start = 10;
static unsigned int tx_stop = 5; static unsigned int tx_stop = 5;
struct ntb_netdev { struct ntb_netdev {
struct list_head list;
struct pci_dev *pdev; struct pci_dev *pdev;
struct net_device *ndev; struct net_device *ndev;
struct ntb_transport_qp *qp; struct ntb_transport_qp *qp;
@ -81,8 +80,6 @@ struct ntb_netdev {
#define NTB_TX_TIMEOUT_MS 1000 #define NTB_TX_TIMEOUT_MS 1000
#define NTB_RXQ_SIZE 100 #define NTB_RXQ_SIZE 100
static LIST_HEAD(dev_list);
static void ntb_netdev_event_handler(void *data, int link_is_up) static void ntb_netdev_event_handler(void *data, int link_is_up)
{ {
struct net_device *ndev = data; 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; struct net_device *ndev = dev->ndev;
if (ntb_transport_tx_free_entry(dev->qp) < tx_stop) { 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 { } else {
/* Make sure anybody stopping the queue after this sees the new /* Make sure anybody stopping the queue after this sees the new
* value of ntb_transport_tx_free_entry() * value of ntb_transport_tx_free_entry()
@ -452,7 +449,7 @@ static int ntb_netdev_probe(struct device *client_dev)
if (rc) if (rc)
goto err1; goto err1;
list_add(&dev->list, &dev_list); dev_set_drvdata(client_dev, ndev);
dev_info(&pdev->dev, "%s created\n", ndev->name); dev_info(&pdev->dev, "%s created\n", ndev->name);
return 0; return 0;
@ -465,27 +462,8 @@ err:
static void ntb_netdev_remove(struct device *client_dev) static void ntb_netdev_remove(struct device *client_dev)
{ {
struct ntb_dev *ntb; struct net_device *ndev = dev_get_drvdata(client_dev);
struct net_device *ndev; struct ntb_netdev *dev = netdev_priv(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;
unregister_netdev(ndev); unregister_netdev(ndev);
ntb_transport_free_queue(dev->qp); ntb_transport_free_queue(dev->qp);

View File

@ -1,6 +1,7 @@
config NTB_IDT config NTB_IDT
tristate "IDT PCIe-switch Non-Transparent Bridge support" tristate "IDT PCIe-switch Non-Transparent Bridge support"
depends on PCI depends on PCI
select HWMON
help help
This driver supports NTB of cappable IDT PCIe-switches. 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 BAR settings of peer NT-functions, the BAR setups can't be done over
kernel PCI fixups. That's why the alternative pre-initialization kernel PCI fixups. That's why the alternative pre-initialization
techniques like BIOS using SMBus interface or EEPROM should be techniques like BIOS using SMBus interface or EEPROM should be
utilized. Additionally if one needs to have temperature sensor utilized.
information printed to system log, the corresponding registers must
be initialized within BIOS/EEPROM as well.
If unsure, say N. If unsure, say N.

View File

@ -4,7 +4,7 @@
* *
* GPL LICENSE SUMMARY * 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 * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@ -49,11 +49,14 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/mutex.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/aer.h> #include <linux/aer.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/ntb.h> #include <linux/ntb.h>
#include "ntb_hw_idt.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 */ /* Allocate memory for memory window descriptors */
ret_mws = devm_kcalloc(&ndev->ntb.pdev->dev, *mw_cnt, ret_mws = devm_kcalloc(&ndev->ntb.pdev->dev, *mw_cnt, sizeof(*ret_mws),
sizeof(*ret_mws), GFP_KERNEL); GFP_KERNEL);
if (IS_ERR_OR_NULL(ret_mws)) if (!ret_mws)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
/* Copy the info of detected memory windows */ /* 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->ltbase, (u32)addr);
idt_nt_write(ndev, bar->utbase, (u32)(addr >> 32)); idt_nt_write(ndev, bar->utbase, (u32)(addr >> 32));
/* Set the custom BAR aperture limit */ /* 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); idt_nt_write(ndev, bar->limit, (u32)limit);
if (IS_FLD_SET(BARSETUP_TYPE, data, 64)) if (IS_FLD_SET(BARSETUP_TYPE, data, 64))
idt_nt_write(ndev, (bar + 1)->limit, (limit >> 32)); 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 * 7. Temperature sensor operations
* *
* IDT PCIe-switch has an embedded temperature sensor, which can be used to * IDT PCIe-switch has an embedded temperature sensor, which can be used to
* warn a user-space of possible chip overheating. Since workload temperature * check current chip core temperature. Since a workload environment can be
* can be different on different platforms, temperature thresholds as well as * different on different platforms, an offset and ADC/filter settings can be
* general sensor settings must be setup in the framework of BIOS/EEPROM * specified. Although the offset configuration is only exposed to the sysfs
* initializations. It includes the actual sensor enabling as well. * 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 * idt_get_deg() - convert millidegree Celsius value to just degree
* @ntb: NTB device context. * @mdegC: IN - millidegree Celsius value
* @val: OUT - integer value of temperature *
* @frac: OUT - fraction * Return: Degree corresponding to the passed millidegree value
*/ */
static void idt_read_temp(struct idt_ntb_dev *ndev, unsigned char *val, static inline s8 idt_get_deg(long mdegC)
unsigned char *frac)
{ {
u32 data; return mdegC / 1000;
/* 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);
} }
/* /*
* idt_temp_isr() - temperature sensor alarm events ISR * idt_get_frac() - retrieve 0/0.5 fraction of the millidegree Celsius value
* @ndev: IDT NTB hardware driver descriptor * @mdegC: IN - millidegree Celsius value
* @ntint_sts: NT-function interrupt status
* *
* It handles events of temperature crossing alarm thresholds. Since reading * Return: 0/0.5 degree fraction of the passed millidegree value
* 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.
*/ */
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 */ /* Alter the temperature field in accordance with the passed type */
dev_warn(&ndev->ntb.pdev->dev, "Temperature %hhu.%hhu", val, frac); 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; 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; ntint_mask = idt_nt_read(ndev, IDT_NT_NTINTMSK) & ~IDT_NTINTMSK_ALL;
idt_nt_write(ndev, IDT_NT_NTINTMSK, ntint_mask); idt_nt_write(ndev, IDT_NT_NTINTMSK, ntint_mask);
@ -1946,7 +2172,6 @@ err_free_vectors:
return ret; return ret;
} }
/* /*
* idt_deinit_ist() - deinitialize PCIe interrupt handler * idt_deinit_ist() - deinitialize PCIe interrupt handler
* @ndev: IDT NTB hardware driver descriptor * @ndev: IDT NTB hardware driver descriptor
@ -2007,12 +2232,6 @@ static irqreturn_t idt_thread_isr(int irq, void *devid)
handled = true; 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); dev_dbg(&ndev->ntb.pdev->dev, "IDT IRQs 0x%08x handled", ntint_sts);
return handled ? IRQ_HANDLED : IRQ_NONE; 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) size_t count, loff_t *offp)
{ {
struct idt_ntb_dev *ndev = filp->private_data; 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; ssize_t ret = 0, off = 0;
unsigned long irqflags;
enum ntb_speed speed; enum ntb_speed speed;
enum ntb_width width; enum ntb_width width;
char *strbuf; 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"); off += scnprintf(strbuf + off, size - off, "\n");
/* Current temperature */ /* Current temperature */
idt_read_temp(ndev, &temp, &frac); idt_read_temp(ndev, IDT_TEMP_CUR, &mdeg);
off += scnprintf(strbuf + off, size - off, 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 */ /* Copy the buffer to the User Space */
ret = simple_read_from_buffer(ubuf, count, offp, strbuf, off); 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 */ /* Allocate memory for the IDT PCIe-device descriptor */
ndev = devm_kzalloc(&pdev->dev, sizeof(*ndev), GFP_KERNEL); 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"); dev_err(&pdev->dev, "Memory allocation failed for descriptor");
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
@ -2571,6 +2791,9 @@ static int idt_pci_probe(struct pci_dev *pdev,
/* Initialize Messaging subsystem */ /* Initialize Messaging subsystem */
idt_init_msg(ndev); idt_init_msg(ndev);
/* Initialize hwmon interface */
idt_init_temp(ndev);
/* Initialize IDT interrupts handler */ /* Initialize IDT interrupts handler */
ret = idt_init_isr(ndev); ret = idt_init_isr(ndev);
if (ret != 0) if (ret != 0)

View File

@ -4,7 +4,7 @@
* *
* GPL LICENSE SUMMARY * 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 * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@ -47,9 +47,9 @@
#include <linux/pci_ids.h> #include <linux/pci_ids.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/mutex.h>
#include <linux/ntb.h> #include <linux/ntb.h>
/* /*
* Macro is used to create the struct pci_device_id that matches * Macro is used to create the struct pci_device_id that matches
* the supported IDT PCIe-switches * the supported IDT PCIe-switches
@ -688,15 +688,14 @@
* @IDT_NTINTMSK_DBELL: Doorbell interrupt mask bit * @IDT_NTINTMSK_DBELL: Doorbell interrupt mask bit
* @IDT_NTINTMSK_SEVENT: Switch Event interrupt mask bit * @IDT_NTINTMSK_SEVENT: Switch Event interrupt mask bit
* @IDT_NTINTMSK_TMPSENSOR: Temperature sensor 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_MSG 0x00000001U
#define IDT_NTINTMSK_DBELL 0x00000002U #define IDT_NTINTMSK_DBELL 0x00000002U
#define IDT_NTINTMSK_SEVENT 0x00000008U #define IDT_NTINTMSK_SEVENT 0x00000008U
#define IDT_NTINTMSK_TMPSENSOR 0x00000080U #define IDT_NTINTMSK_TMPSENSOR 0x00000080U
#define IDT_NTINTMSK_ALL \ #define IDT_NTINTMSK_ALL \
(IDT_NTINTMSK_MSG | IDT_NTINTMSK_DBELL | \ (IDT_NTINTMSK_MSG | IDT_NTINTMSK_DBELL | IDT_NTINTMSK_SEVENT)
IDT_NTINTMSK_SEVENT | IDT_NTINTMSK_TMPSENSOR)
/* /*
* NTGSIGNAL register fields related constants * NTGSIGNAL register fields related constants
@ -885,13 +884,61 @@
#define IDT_SWPxMSGCTL_PART_MASK 0x00000070U #define IDT_SWPxMSGCTL_PART_MASK 0x00000070U
#define IDT_SWPxMSGCTL_PART_FLD 4 #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 * TMPSTS register fields related constants
* @IDT_TMPSTS_TEMP_MASK: Current temperature field mask * @IDT_TMPSTS_TEMP_MASK: Current temperature field mask
* @IDT_TMPSTS_TEMP_FLD: Current temperature field offset * @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_MASK 0x000000FFU
#define IDT_TMPSTS_TEMP_FLD 0 #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 * Helper macro to get/set the corresponding field value
@ -950,6 +997,32 @@
#define IDT_TRANS_ALIGN 4 #define IDT_TRANS_ALIGN 4
#define IDT_DIR_SIZE_ALIGN 1 #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 * IDT Memory Windows type. Depending on the device settings, IDT supports
* Direct Address Translation MW registers and Lookup Table registers * Direct Address Translation MW registers and Lookup Table registers
@ -1044,6 +1117,8 @@ struct idt_ntb_peer {
* @msg_mask_lock: Message mask register lock * @msg_mask_lock: Message mask register lock
* @gasa_lock: GASA registers access lock * @gasa_lock: GASA registers access lock
* *
* @hwmon_mtx: Temperature sensor interface update mutex
*
* @dbgfs_info: DebugFS info node * @dbgfs_info: DebugFS info node
*/ */
struct idt_ntb_dev { struct idt_ntb_dev {
@ -1071,6 +1146,8 @@ struct idt_ntb_dev {
spinlock_t msg_mask_lock; spinlock_t msg_mask_lock;
spinlock_t gasa_lock; spinlock_t gasa_lock;
struct mutex hwmon_mtx;
struct dentry *dbgfs_info; struct dentry *dbgfs_info;
}; };
#define to_ndev_ntb(__ntb) container_of(__ntb, struct idt_ntb_dev, ntb) #define to_ndev_ntb(__ntb) container_of(__ntb, struct idt_ntb_dev, ntb)

View File

@ -265,7 +265,7 @@ static inline int ndev_db_clear_mask(struct intel_ntb_dev *ndev, u64 db_bits,
return 0; 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; u64 shift, mask;

View File

@ -194,6 +194,8 @@ struct ntb_transport_mw {
void __iomem *vbase; void __iomem *vbase;
size_t xlat_size; size_t xlat_size;
size_t buff_size; size_t buff_size;
size_t alloc_size;
void *alloc_addr;
void *virt_addr; void *virt_addr;
dma_addr_t dma_addr; dma_addr_t dma_addr;
}; };
@ -672,13 +674,59 @@ static void ntb_free_mw(struct ntb_transport_ctx *nt, int num_mw)
return; return;
ntb_mw_clear_trans(nt->ndev, PIDX, num_mw); ntb_mw_clear_trans(nt->ndev, PIDX, num_mw);
dma_free_coherent(&pdev->dev, mw->buff_size, dma_free_coherent(&pdev->dev, mw->alloc_size,
mw->virt_addr, mw->dma_addr); mw->alloc_addr, mw->dma_addr);
mw->xlat_size = 0; mw->xlat_size = 0;
mw->buff_size = 0; mw->buff_size = 0;
mw->alloc_size = 0;
mw->alloc_addr = NULL;
mw->virt_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, static int ntb_set_mw(struct ntb_transport_ctx *nt, int num_mw,
resource_size_t size) 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 */ /* Alloc memory for receiving data. Must be aligned */
mw->xlat_size = xlat_size; mw->xlat_size = xlat_size;
mw->buff_size = buff_size; mw->buff_size = buff_size;
mw->alloc_size = buff_size;
mw->virt_addr = dma_alloc_coherent(&pdev->dev, buff_size, rc = ntb_alloc_mw_buffer(mw, &pdev->dev, xlat_align);
&mw->dma_addr, GFP_KERNEL); if (rc) {
if (!mw->virt_addr) { mw->alloc_size *= 2;
mw->xlat_size = 0; rc = ntb_alloc_mw_buffer(mw, &pdev->dev, xlat_align);
mw->buff_size = 0; if (rc) {
dev_err(&pdev->dev, "Unable to alloc MW buff of size %zu\n", dev_err(&pdev->dev,
buff_size); "Unable to alloc aligned MW buff\n");
return -ENOMEM; mw->xlat_size = 0;
} mw->buff_size = 0;
mw->alloc_size = 0;
/* return rc;
* 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;
} }
/* Notify HW the memory location of the receive buffer */ /* 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_READ_FAILED:
case DMA_TRANS_WRITE_FAILED: case DMA_TRANS_WRITE_FAILED:
entry->errors++; entry->errors++;
/* fall through */
case DMA_TRANS_ABORTED: case DMA_TRANS_ABORTED:
{ {
struct ntb_transport_qp *qp = entry->qp; 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_READ_FAILED:
case DMA_TRANS_WRITE_FAILED: case DMA_TRANS_WRITE_FAILED:
entry->errors++; entry->errors++;
/* fall through */
case DMA_TRANS_ABORTED: case DMA_TRANS_ABORTED:
{ {
void __iomem *offset = void __iomem *offset =