提交 04578e84 编写于 作者: L Linus Torvalds

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
......@@ -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 @@ static int ntb_netdev_probe(struct device *client_dev)
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);
......
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_get_deg() - convert millidegree Celsius value to just degree
* @mdegC: IN - millidegree Celsius value
*
* Return: Degree corresponding to the passed millidegree value
*/
static inline s8 idt_get_deg(long mdegC)
{
return mdegC / 1000;
}
/*
* idt_get_frac() - retrieve 0/0.5 fraction of the millidegree Celsius value
* @mdegC: IN - millidegree Celsius value
*
* Return: 0/0.5 degree fraction of the passed millidegree value
*/
static inline u8 idt_get_deg_frac(long mdegC)
{
return (mdegC % 1000) >= 500 ? 5 : 0;
}
/*
* 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);
}
/*
* 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);
}
/*
* 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);
}
/*
* idt_read_temp() - read temperature from chip sensor
* @ntb: NTB device context.
* @val: OUT - integer value of temperature
* @frac: OUT - fraction
* @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, unsigned char *val,
unsigned char *frac)
static void idt_read_temp(struct idt_ntb_dev *ndev,
const enum idt_temp_val type, long *val)
{
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);
/* 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_temp_isr() - temperature sensor alarm events ISR
* @ndev: IDT NTB hardware driver descriptor
* @ntint_sts: NT-function interrupt status
* 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
*
* 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: Number of written symbols or negative error
*/
static void idt_temp_isr(struct idt_ntb_dev *ndev, u32 ntint_sts)
static ssize_t idt_sysfs_show_temp(struct device *dev,
struct device_attribute *da, char *buf)
{
unsigned char val, frac;
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;
/* Read the current temperature value */
idt_read_temp(ndev, &val, &frac);
idt_read_temp(ndev, type, &mdeg);
return sprintf(buf, "%ld\n", mdeg);
}
/* Read the temperature alarm to clean the alarm status out */
/*(void)idt_sw_read(ndev, IDT_SW_TMPALARM);*/
/*
* 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;
/* Clean the corresponding interrupt bit */
idt_nt_write(ndev, IDT_NT_NTINTSTS, IDT_NTINTSTS_TMPSENSOR);
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);
dev_dbg(&ndev->ntb.pdev->dev,
"Temp sensor IRQ detected %#08x", ntint_sts);
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);
/* Print temperature value to log */
dev_warn(&ndev->ntb.pdev->dev, "Temperature %hhu.%hhu", val, frac);
/*
* 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 @@ static int idt_init_isr(struct idt_ntb_dev *ndev)
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 =
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册