Commit 31f02006 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'char-misc-5.10-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc

Pull char/misc fixes/removals from Greg KH:
 "Here's some small fixes for 5.10-rc2 and a big driver removal.

  The fixes are for some reported issues in the interconnect and
  coresight drivers, nothing major.

  The "big" driver removal is the MIC drivers have been asked to be
  removed as the hardware never shipped and Intel no longer wants to
  maintain something that no one can use. This is welcomed by many as
  the DMA usage of these drivers was "interesting" and the security
  people were starting to question some issues that were starting to be
  found in the codebase.

  Note, one of the subsystems for this driver, the "VOP" code, will
  probably come back in future kernel versions as it was looking to
  potentially solve some PCIe virtualization issues that a number of
  other vendors were wanting to solve. But as-is, this codebase didn't
  work for anyone else so no actual functionality is being removed.

  All of these have been in linux-next with no reported issues"

* tag 'char-misc-5.10-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc:
  coresight: cti: Initialize dynamic sysfs attributes
  coresight: Fix uninitialised pointer bug in etm_setup_aux()
  coresight: add module license
  misc: mic: remove the MIC drivers
  interconnect: qcom: use icc_sync state for sm8[12]50
  interconnect: qcom: Ensure that the floor bandwidth value is enforced
  interconnect: qcom: sc7180: Init BCMs before creating the nodes
  interconnect: qcom: sdm845: Init BCMs before creating the nodes
  interconnect: Aggregate before setting initial bandwidth
  interconnect: qcom: sdm845: Enable keepalive for the MM1 BCM
parents 9c75b68b d1b35d66
=============================================
Intel Many Integrated Core (MIC) architecture
=============================================
.. toctree::
:maxdepth: 1
mic_overview
scif_overview
.. only:: subproject and html
Indices
=======
* :ref:`genindex`
======================================================
Intel Many Integrated Core (MIC) architecture overview
======================================================
An Intel MIC X100 device is a PCIe form factor add-in coprocessor
card based on the Intel Many Integrated Core (MIC) architecture
that runs a Linux OS. It is a PCIe endpoint in a platform and therefore
implements the three required standard address spaces i.e. configuration,
memory and I/O. The host OS loads a device driver as is typical for
PCIe devices. The card itself runs a bootstrap after reset that
transfers control to the card OS downloaded from the host driver. The
host driver supports OSPM suspend and resume operations. It shuts down
the card during suspend and reboots the card OS during resume.
The card OS as shipped by Intel is a Linux kernel with modifications
for the X100 devices.
Since it is a PCIe card, it does not have the ability to host hardware
devices for networking, storage and console. We provide these devices
on X100 coprocessors thus enabling a self-bootable equivalent
environment for applications. A key benefit of our solution is that it
leverages the standard virtio framework for network, disk and console
devices, though in our case the virtio framework is used across a PCIe
bus. A Virtio Over PCIe (VOP) driver allows creating user space
backends or devices on the host which are used to probe virtio drivers
for these devices on the MIC card. The existing VRINGH infrastructure
in the kernel is used to access virtio rings from the host. The card
VOP driver allows card virtio drivers to communicate with their user
space backends on the host via a device page. Ring 3 apps on the host
can add, remove and configure virtio devices. A thin MIC specific
virtio_config_ops is implemented which is borrowed heavily from
previous similar implementations in lguest and s390.
MIC PCIe card has a dma controller with 8 channels. These channels are
shared between the host s/w and the card s/w. 0 to 3 are used by host
and 4 to 7 by card. As the dma device doesn't show up as PCIe device,
a virtual bus called mic bus is created and virtual dma devices are
created on it by the host/card drivers. On host the channels are private
and used only by the host driver to transfer data for the virtio devices.
The Symmetric Communication Interface (SCIF (pronounced as skiff)) is a
low level communications API across PCIe currently implemented for MIC.
More details are available at scif_overview.txt.
The Coprocessor State Management (COSM) driver on the host allows for
boot, shutdown and reset of Intel MIC devices. It communicates with a COSM
"client" driver on the MIC cards over SCIF to perform these functions.
Here is a block diagram of the various components described above. The
virtio backends are situated on the host rather than the card given better
single threaded performance for the host compared to MIC, the ability of
the host to initiate DMA's to/from the card using the MIC DMA engine and
the fact that the virtio block storage backend can only be on the host::
+----------+ | +----------+
| Card OS | | | Host OS |
+----------+ | +----------+
|
+-------+ +--------+ +------+ | +---------+ +--------+ +--------+
| Virtio| |Virtio | |Virtio| | |Virtio | |Virtio | |Virtio |
| Net | |Console | |Block | | |Net | |Console | |Block |
| Driver| |Driver | |Driver| | |backend | |backend | |backend |
+---+---+ +---+----+ +--+---+ | +---------+ +----+---+ +--------+
| | | | | | |
| | | |User | | |
| | | |------|------------|--+------|-------
+---------+---------+ |Kernel |
| | |
+---------+ +---+----+ +------+ | +------+ +------+ +--+---+ +-------+
|MIC DMA | | VOP | | SCIF | | | SCIF | | COSM | | VOP | |MIC DMA|
+---+-----+ +---+----+ +--+---+ | +--+---+ +--+---+ +------+ +----+--+
| | | | | | |
+---+-----+ +---+----+ +--+---+ | +--+---+ +--+---+ +------+ +----+--+
|MIC | | VOP | |SCIF | | |SCIF | | COSM | | VOP | | MIC |
|HW Bus | | HW Bus| |HW Bus| | |HW Bus| | Bus | |HW Bus| |HW Bus |
+---------+ +--------+ +--+---+ | +--+---+ +------+ +------+ +-------+
| | | | | | |
| +-----------+--+ | | | +---------------+ |
| |Intel MIC | | | | |Intel MIC | |
| |Card Driver | | | | |Host Driver | |
+---+--------------+------+ | +----+---------------+-----+
| | |
+-------------------------------------------------------------+
| |
| PCIe Bus |
+-------------------------------------------------------------+
========================================
Symmetric Communication Interface (SCIF)
========================================
The Symmetric Communication Interface (SCIF (pronounced as skiff)) is a low
level communications API across PCIe currently implemented for MIC. Currently
SCIF provides inter-node communication within a single host platform, where a
node is a MIC Coprocessor or Xeon based host. SCIF abstracts the details of
communicating over the PCIe bus while providing an API that is symmetric
across all the nodes in the PCIe network. An important design objective for SCIF
is to deliver the maximum possible performance given the communication
abilities of the hardware. SCIF has been used to implement an offload compiler
runtime and OFED support for MPI implementations for MIC coprocessors.
SCIF API Components
===================
The SCIF API has the following parts:
1. Connection establishment using a client server model
2. Byte stream messaging intended for short messages
3. Node enumeration to determine online nodes
4. Poll semantics for detection of incoming connections and messages
5. Memory registration to pin down pages
6. Remote memory mapping for low latency CPU accesses via mmap
7. Remote DMA (RDMA) for high bandwidth DMA transfers
8. Fence APIs for RDMA synchronization
SCIF exposes the notion of a connection which can be used by peer processes on
nodes in a SCIF PCIe "network" to share memory "windows" and to communicate. A
process in a SCIF node initiates a SCIF connection to a peer process on a
different node via a SCIF "endpoint". SCIF endpoints support messaging APIs
which are similar to connection oriented socket APIs. Connected SCIF endpoints
can also register local memory which is followed by data transfer using either
DMA, CPU copies or remote memory mapping via mmap. SCIF supports both user and
kernel mode clients which are functionally equivalent.
SCIF Performance for MIC
========================
DMA bandwidth comparison between the TCP (over ethernet over PCIe) stack versus
SCIF shows the performance advantages of SCIF for HPC applications and
runtimes::
Comparison of TCP and SCIF based BW
Throughput (GB/sec)
8 + PCIe Bandwidth ******
+ TCP ######
7 + ************************************** SCIF %%%%%%
| %%%%%%%%%%%%%%%%%%%
6 + %%%%
| %%
| %%%
5 + %%
| %%
4 + %%
| %%
3 + %%
| %
2 + %%
| %%
| %
1 +
+ ######################################
0 +++---+++--+--+-+--+--+-++-+--+-++-+--+-++-+-
1 10 100 1000 10000 100000
Transfer Size (KBytes)
SCIF allows memory sharing via mmap(..) between processes on different PCIe
nodes and thus provides bare-metal PCIe latency. The round trip SCIF mmap
latency from the host to an x100 MIC for an 8 byte message is 0.44 usecs.
SCIF has a user space library which is a thin IOCTL wrapper providing a user
space API similar to the kernel API in scif.h. The SCIF user space library
is distributed @ https://software.intel.com/en-us/mic-developer
Here is some pseudo code for an example of how two applications on two PCIe
nodes would typically use the SCIF API::
Process A (on node A) Process B (on node B)
/* get online node information */
scif_get_node_ids(..) scif_get_node_ids(..)
scif_open(..) scif_open(..)
scif_bind(..) scif_bind(..)
scif_listen(..)
scif_accept(..) scif_connect(..)
/* SCIF connection established */
/* Send and receive short messages */
scif_send(..)/scif_recv(..) scif_send(..)/scif_recv(..)
/* Register memory */
scif_register(..) scif_register(..)
/* RDMA */
scif_readfrom(..)/scif_writeto(..) scif_readfrom(..)/scif_writeto(..)
/* Fence DMAs */
scif_fence_signal(..) scif_fence_signal(..)
mmap(..) mmap(..)
/* Access remote registered memory */
/* Close the endpoints */
scif_close(..) scif_close(..)
......@@ -8972,22 +8972,6 @@ S: Supported
W: https://01.org/linux-acpi
F: drivers/platform/x86/intel_menlow.c
INTEL MIC DRIVERS (mic)
M: Sudeep Dutt <sudeep.dutt@intel.com>
M: Ashutosh Dixit <ashutosh.dixit@intel.com>
S: Supported
W: https://github.com/sudeepdutt/mic
W: http://software.intel.com/en-us/mic-developer
F: Documentation/misc-devices/mic/
F: drivers/dma/mic_x100_dma.c
F: drivers/dma/mic_x100_dma.h
F: drivers/misc/mic/
F: include/linux/mic_bus.h
F: include/linux/scif.h
F: include/uapi/linux/mic_common.h
F: include/uapi/linux/mic_ioctl.h
F: include/uapi/linux/scif_ioctl.h
INTEL P-Unit IPC DRIVER
M: Zha Qipeng <qipeng.zha@intel.com>
L: platform-driver-x86@vger.kernel.org
......
......@@ -318,24 +318,6 @@ config INTEL_IOP_ADMA
help
Enable support for the Intel(R) IOP Series RAID engines.
config INTEL_MIC_X100_DMA
tristate "Intel MIC X100 DMA Driver"
depends on 64BIT && X86 && INTEL_MIC_BUS
select DMA_ENGINE
help
This enables DMA support for the Intel Many Integrated Core
(MIC) family of PCIe form factor coprocessor X100 devices that
run a 64 bit Linux OS. This driver will be used by both MIC
host and card drivers.
If you are building host kernel with a MIC device or a card
kernel for a MIC device, then say M (recommended) or Y, else
say N. If unsure say N.
More information about the Intel MIC family as well as the Linux
OS and tools for MIC to use with this driver are available from
<http://software.intel.com/en-us/mic-developer>.
config K3_DMA
tristate "Hisilicon K3 DMA support"
depends on ARCH_HI3xxx || ARCH_HISI || COMPILE_TEST
......
......@@ -44,7 +44,6 @@ obj-$(CONFIG_INTEL_IDMA64) += idma64.o
obj-$(CONFIG_INTEL_IOATDMA) += ioat/
obj-$(CONFIG_INTEL_IDXD) += idxd/
obj-$(CONFIG_INTEL_IOP_ADMA) += iop-adma.o
obj-$(CONFIG_INTEL_MIC_X100_DMA) += mic_x100_dma.o
obj-$(CONFIG_K3_DMA) += k3dma.o
obj-$(CONFIG_LPC18XX_DMAMUX) += lpc18xx-dmamux.o
obj-$(CONFIG_MILBEAUT_HDMAC) += milbeaut-hdmac.o
......
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Intel MIC Platform Software Stack (MPSS)
*
* Copyright(c) 2014 Intel Corporation.
*
* Intel MIC X100 DMA Driver.
*
* Adapted from IOAT dma driver.
*/
#ifndef _MIC_X100_DMA_H_
#define _MIC_X100_DMA_H_
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/debugfs.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/mic_bus.h>
#include "dmaengine.h"
/*
* MIC has a total of 8 dma channels.
* Four channels are assigned for host SW use & the remaining for MIC SW.
* MIC DMA transfer size & addresses need to be 64 byte aligned.
*/
#define MIC_DMA_MAX_NUM_CHAN 8
#define MIC_DMA_NUM_CHAN 4
#define MIC_DMA_ALIGN_SHIFT DMAENGINE_ALIGN_64_BYTES
#define MIC_DMA_ALIGN_BYTES (1 << MIC_DMA_ALIGN_SHIFT)
#define MIC_DMA_DESC_RX_SIZE (128 * 1024 - 4)
/*
* Register descriptions
* All the registers are 32 bit registers.
* DCR is a global register and all others are per-channel.
* DCR - bits 0, 2, 4, 6, 8, 10, 12, 14 - enable bits for channels 0 to 7
* bits 1, 3, 5, 7, 9, 11, 13, 15 - owner bits for channels 0 to 7
* DCAR - bit 24 & 25 interrupt masks for mic owned & host owned channels
* DHPR - head of the descriptor ring updated by s/w
* DTPR - tail of the descriptor ring updated by h/w
* DRAR_LO - lower 32 bits of descriptor ring's mic address
* DRAR_HI - 3:0 - remaining 4 bits of descriptor ring's mic address
* 20:4 descriptor ring size
* 25:21 mic smpt entry number
* DSTAT - 16:0 h/w completion count; 31:28 dma engine status
* DCHERR - this register is non-zero on error
* DCHERRMSK - interrupt mask register
*/
#define MIC_DMA_HW_CMP_CNT_MASK 0x1ffff
#define MIC_DMA_CHAN_QUIESCE 0x20000000
#define MIC_DMA_SBOX_BASE 0x00010000
#define MIC_DMA_SBOX_DCR 0x0000A280
#define MIC_DMA_SBOX_CH_BASE 0x0001A000
#define MIC_DMA_SBOX_CHAN_OFF 0x40
#define MIC_DMA_SBOX_DCAR_IM0 (0x1 << 24)
#define MIC_DMA_SBOX_DCAR_IM1 (0x1 << 25)
#define MIC_DMA_SBOX_DRARHI_SYS_MASK (0x1 << 26)
#define MIC_DMA_REG_DCAR 0
#define MIC_DMA_REG_DHPR 4
#define MIC_DMA_REG_DTPR 8
#define MIC_DMA_REG_DRAR_LO 20
#define MIC_DMA_REG_DRAR_HI 24
#define MIC_DMA_REG_DSTAT 32
#define MIC_DMA_REG_DCHERR 44
#define MIC_DMA_REG_DCHERRMSK 48
/* HW dma desc */
struct mic_dma_desc {
u64 qw0;
u64 qw1;
};
enum mic_dma_chan_owner {
MIC_DMA_CHAN_MIC = 0,
MIC_DMA_CHAN_HOST
};
/*
* mic_dma_chan - channel specific information
* @ch_num: channel number
* @owner: owner of this channel
* @last_tail: cached value of descriptor ring tail
* @head: index of next descriptor in desc_ring
* @issued: hardware notification point
* @submitted: index that will be used to submit descriptors to h/w
* @api_ch: dma engine api channel
* @desc_ring: dma descriptor ring
* @desc_ring_micpa: mic physical address of desc_ring
* @status_dest: destination for status (fence) descriptor
* @status_dest_micpa: mic address for status_dest,
* DMA controller uses this address
* @tx_array: array of async_tx
* @cleanup_lock: lock held when processing completed tx
* @prep_lock: lock held in prep_memcpy & released in tx_submit
* @issue_lock: lock used to synchronize writes to head
* @cookie: mic_irq cookie used with mic irq request
*/
struct mic_dma_chan {
int ch_num;
enum mic_dma_chan_owner owner;
u32 last_tail;
u32 head;
u32 issued;
u32 submitted;
struct dma_chan api_ch;
struct mic_dma_desc *desc_ring;
dma_addr_t desc_ring_micpa;
u64 *status_dest;
dma_addr_t status_dest_micpa;
struct dma_async_tx_descriptor *tx_array;
spinlock_t cleanup_lock;
spinlock_t prep_lock;
spinlock_t issue_lock;
struct mic_irq *cookie;
};
/*
* struct mic_dma_device - per mic device
* @mic_ch: dma channels
* @dma_dev: underlying dma device
* @mbdev: mic bus dma device
* @mmio: virtual address of the mmio space
* @dbg_dir: debugfs directory
* @start_ch: first channel number that can be used
* @max_xfer_size: maximum transfer size per dma descriptor
*/
struct mic_dma_device {
struct mic_dma_chan mic_ch[MIC_DMA_MAX_NUM_CHAN];
struct dma_device dma_dev;
struct mbus_device *mbdev;
void __iomem *mmio;
struct dentry *dbg_dir;
int start_ch;
size_t max_xfer_size;
};
static inline struct mic_dma_chan *to_mic_dma_chan(struct dma_chan *ch)
{
return container_of(ch, struct mic_dma_chan, api_ch);
}
static inline struct mic_dma_device *to_mic_dma_dev(struct mic_dma_chan *ch)
{
return
container_of((const typeof(((struct mic_dma_device *)0)->mic_ch)*)
(ch - ch->ch_num), struct mic_dma_device, mic_ch);
}
static inline struct mbus_device *to_mbus_device(struct mic_dma_chan *ch)
{
return to_mic_dma_dev(ch)->mbdev;
}
static inline struct mbus_hw_ops *to_mbus_hw_ops(struct mic_dma_chan *ch)
{
return to_mbus_device(ch)->hw_ops;
}
static inline struct device *mic_dma_ch_to_device(struct mic_dma_chan *ch)
{
return to_mic_dma_dev(ch)->dma_dev.dev;
}
static inline void __iomem *mic_dma_chan_to_mmio(struct mic_dma_chan *ch)
{
return to_mic_dma_dev(ch)->mmio;
}
static inline u32 mic_dma_read_reg(struct mic_dma_chan *ch, u32 reg)
{
return ioread32(mic_dma_chan_to_mmio(ch) + MIC_DMA_SBOX_CH_BASE +
ch->ch_num * MIC_DMA_SBOX_CHAN_OFF + reg);
}
static inline void mic_dma_write_reg(struct mic_dma_chan *ch, u32 reg, u32 val)
{
iowrite32(val, mic_dma_chan_to_mmio(ch) + MIC_DMA_SBOX_CH_BASE +
ch->ch_num * MIC_DMA_SBOX_CHAN_OFF + reg);
}
static inline u32 mic_dma_mmio_read(struct mic_dma_chan *ch, u32 offset)
{
return ioread32(mic_dma_chan_to_mmio(ch) + offset);
}
static inline void mic_dma_mmio_write(struct mic_dma_chan *ch, u32 val,
u32 offset)
{
iowrite32(val, mic_dma_chan_to_mmio(ch) + offset);
}
static inline u32 mic_dma_read_cmp_cnt(struct mic_dma_chan *ch)
{
return mic_dma_read_reg(ch, MIC_DMA_REG_DSTAT) &
MIC_DMA_HW_CMP_CNT_MASK;
}
static inline void mic_dma_chan_set_owner(struct mic_dma_chan *ch)
{
u32 dcr = mic_dma_mmio_read(ch, MIC_DMA_SBOX_BASE + MIC_DMA_SBOX_DCR);
u32 chan_num = ch->ch_num;
dcr = (dcr & ~(0x1 << (chan_num * 2))) | (ch->owner << (chan_num * 2));
mic_dma_mmio_write(ch, dcr, MIC_DMA_SBOX_BASE + MIC_DMA_SBOX_DCR);
}
static inline void mic_dma_enable_chan(struct mic_dma_chan *ch)
{
u32 dcr = mic_dma_mmio_read(ch, MIC_DMA_SBOX_BASE + MIC_DMA_SBOX_DCR);
dcr |= 2 << (ch->ch_num << 1);
mic_dma_mmio_write(ch, dcr, MIC_DMA_SBOX_BASE + MIC_DMA_SBOX_DCR);
}
static inline void mic_dma_disable_chan(struct mic_dma_chan *ch)
{
u32 dcr = mic_dma_mmio_read(ch, MIC_DMA_SBOX_BASE + MIC_DMA_SBOX_DCR);
dcr &= ~(2 << (ch->ch_num << 1));
mic_dma_mmio_write(ch, dcr, MIC_DMA_SBOX_BASE + MIC_DMA_SBOX_DCR);
}
static void mic_dma_chan_set_desc_ring(struct mic_dma_chan *ch)
{
u32 drar_hi;
dma_addr_t desc_ring_micpa = ch->desc_ring_micpa;
drar_hi = (MIC_DMA_DESC_RX_SIZE & 0x1ffff) << 4;
if (MIC_DMA_CHAN_MIC == ch->owner) {
drar_hi |= (desc_ring_micpa >> 32) & 0xf;
} else {
drar_hi |= MIC_DMA_SBOX_DRARHI_SYS_MASK;
drar_hi |= ((desc_ring_micpa >> 34)
& 0x1f) << 21;
drar_hi |= (desc_ring_micpa >> 32) & 0x3;
}
mic_dma_write_reg(ch, MIC_DMA_REG_DRAR_LO, (u32) desc_ring_micpa);
mic_dma_write_reg(ch, MIC_DMA_REG_DRAR_HI, drar_hi);
}
static inline void mic_dma_chan_mask_intr(struct mic_dma_chan *ch)
{
u32 dcar = mic_dma_read_reg(ch, MIC_DMA_REG_DCAR);
if (MIC_DMA_CHAN_MIC == ch->owner)
dcar |= MIC_DMA_SBOX_DCAR_IM0;
else
dcar |= MIC_DMA_SBOX_DCAR_IM1;
mic_dma_write_reg(ch, MIC_DMA_REG_DCAR, dcar);
}
static inline void mic_dma_chan_unmask_intr(struct mic_dma_chan *ch)
{
u32 dcar = mic_dma_read_reg(ch, MIC_DMA_REG_DCAR);
if (MIC_DMA_CHAN_MIC == ch->owner)
dcar &= ~MIC_DMA_SBOX_DCAR_IM0;
else
dcar &= ~MIC_DMA_SBOX_DCAR_IM1;
mic_dma_write_reg(ch, MIC_DMA_REG_DCAR, dcar);
}
static void mic_dma_ack_interrupt(struct mic_dma_chan *ch)
{
if (MIC_DMA_CHAN_MIC == ch->owner) {
/* HW errata */
mic_dma_chan_mask_intr(ch);
mic_dma_chan_unmask_intr(ch);
}
to_mbus_hw_ops(ch)->ack_interrupt(to_mbus_device(ch), ch->ch_num);
}
#endif
......@@ -1689,6 +1689,7 @@ static void __exit coresight_exit(void)
module_init(coresight_init);
module_exit(coresight_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Pratik Patel <pratikp@codeaurora.org>");
MODULE_AUTHOR("Mathieu Poirier <mathieu.poirier@linaro.org>");
MODULE_DESCRIPTION("Arm CoreSight tracer driver");
......@@ -1065,6 +1065,13 @@ static int cti_create_con_sysfs_attr(struct device *dev,
}
eattr->var = con;
con->con_attrs[attr_idx] = &eattr->attr.attr;
/*
* Initialize the dynamically allocated attribute
* to avoid LOCKDEP splat. See include/linux/sysfs.h
* for more details.
*/
sysfs_attr_init(con->con_attrs[attr_idx]);
return 0;
}
......
......@@ -210,7 +210,7 @@ static void *etm_setup_aux(struct perf_event *event, void **pages,
u32 id;
int cpu = event->cpu;
cpumask_t *mask;
struct coresight_device *sink;
struct coresight_device *sink = NULL;
struct etm_event_data *event_data = NULL;
event_data = alloc_event_data(cpu);
......
......@@ -971,6 +971,9 @@ void icc_node_add(struct icc_node *node, struct icc_provider *provider)
}
node->avg_bw = node->init_avg;
node->peak_bw = node->init_peak;
if (provider->aggregate)
provider->aggregate(node, 0, node->init_avg, node->init_peak,
&node->avg_bw, &node->peak_bw);
provider->set(node, node);
node->avg_bw = 0;
node->peak_bw = 0;
......
......@@ -79,6 +79,7 @@ EXPORT_SYMBOL_GPL(qcom_icc_aggregate);
int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
{
struct qcom_icc_provider *qp;
struct qcom_icc_node *qn;
struct icc_node *node;
if (!src)
......@@ -87,6 +88,12 @@ int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
node = src;
qp = to_qcom_provider(node->provider);
qn = node->data;
qn->sum_avg[QCOM_ICC_BUCKET_AMC] = max_t(u64, qn->sum_avg[QCOM_ICC_BUCKET_AMC],
node->avg_bw);
qn->max_peak[QCOM_ICC_BUCKET_AMC] = max_t(u64, qn->max_peak[QCOM_ICC_BUCKET_AMC],
node->peak_bw);
qcom_icc_bcm_voter_commit(qp->voter);
......
......@@ -553,6 +553,9 @@ static int qnoc_probe(struct platform_device *pdev)
return ret;
}
for (i = 0; i < qp->num_bcms; i++)
qcom_icc_bcm_init(qp->bcms[i], &pdev->dev);
for (i = 0; i < num_nodes; i++) {
size_t j;
......@@ -576,9 +579,6 @@ static int qnoc_probe(struct platform_device *pdev)
}
data->num_nodes = num_nodes;
for (i = 0; i < qp->num_bcms; i++)
qcom_icc_bcm_init(qp->bcms[i], &pdev->dev);
platform_set_drvdata(pdev, qp);
return 0;
......
......@@ -151,7 +151,7 @@ DEFINE_QBCM(bcm_mc0, "MC0", true, &ebi);
DEFINE_QBCM(bcm_sh0, "SH0", true, &qns_llcc);
DEFINE_QBCM(bcm_mm0, "MM0", false, &qns_mem_noc_hf);
DEFINE_QBCM(bcm_sh1, "SH1", false, &qns_apps_io);
DEFINE_QBCM(bcm_mm1, "MM1", false, &qxm_camnoc_hf0_uncomp, &qxm_camnoc_hf1_uncomp, &qxm_camnoc_sf_uncomp, &qxm_camnoc_hf0, &qxm_camnoc_hf1, &qxm_mdp0, &qxm_mdp1);
DEFINE_QBCM(bcm_mm1, "MM1", true, &qxm_camnoc_hf0_uncomp, &qxm_camnoc_hf1_uncomp, &qxm_camnoc_sf_uncomp, &qxm_camnoc_hf0, &qxm_camnoc_hf1, &qxm_mdp0, &qxm_mdp1);
DEFINE_QBCM(bcm_sh2, "SH2", false, &qns_memnoc_snoc);
DEFINE_QBCM(bcm_mm2, "MM2", false, &qns2_mem_noc);
DEFINE_QBCM(bcm_sh3, "SH3", false, &acm_tcu);
......@@ -489,6 +489,9 @@ static int qnoc_probe(struct platform_device *pdev)
return ret;
}
for (i = 0; i < qp->num_bcms; i++)
qcom_icc_bcm_init(qp->bcms[i], &pdev->dev);
for (i = 0; i < num_nodes; i++) {
size_t j;
......@@ -512,9 +515,6 @@ static int qnoc_probe(struct platform_device *pdev)
}
data->num_nodes = num_nodes;
for (i = 0; i < qp->num_bcms; i++)
qcom_icc_bcm_init(qp->bcms[i], &pdev->dev);
platform_set_drvdata(pdev, qp);
return 0;
......
......@@ -551,6 +551,9 @@ static int qnoc_probe(struct platform_device *pdev)
return ret;
}
for (i = 0; i < qp->num_bcms; i++)
qcom_icc_bcm_init(qp->bcms[i], &pdev->dev);
for (i = 0; i < num_nodes; i++) {
size_t j;
......@@ -574,9 +577,6 @@ static int qnoc_probe(struct platform_device *pdev)
}
data->num_nodes = num_nodes;
for (i = 0; i < qp->num_bcms; i++)
qcom_icc_bcm_init(qp->bcms[i], &pdev->dev);
platform_set_drvdata(pdev, qp);
return 0;
......@@ -627,6 +627,7 @@ static struct platform_driver qnoc_driver = {
.driver = {
.name = "qnoc-sm8150",
.of_match_table = qnoc_of_match,
.sync_state = icc_sync_state,
},
};
module_platform_driver(qnoc_driver);
......
......@@ -567,6 +567,9 @@ static int qnoc_probe(struct platform_device *pdev)
return ret;
}
for (i = 0; i < qp->num_bcms; i++)
qcom_icc_bcm_init(qp->bcms[i], &pdev->dev);
for (i = 0; i < num_nodes; i++) {
size_t j;
......@@ -590,9 +593,6 @@ static int qnoc_probe(struct platform_device *pdev)
}
data->num_nodes = num_nodes;
for (i = 0; i < qp->num_bcms; i++)
qcom_icc_bcm_init(qp->bcms[i], &pdev->dev);
platform_set_drvdata(pdev, qp);
return 0;
......@@ -643,6 +643,7 @@ static struct platform_driver qnoc_driver = {
.driver = {
.name = "qnoc-sm8250",
.of_match_table = qnoc_of_match,
.sync_state = icc_sync_state,
},
};
module_platform_driver(qnoc_driver);
......
......@@ -474,7 +474,6 @@ source "drivers/misc/lis3lv02d/Kconfig"
source "drivers/misc/altera-stapl/Kconfig"
source "drivers/misc/mei/Kconfig"
source "drivers/misc/vmw_vmci/Kconfig"
source "drivers/misc/mic/Kconfig"
source "drivers/misc/genwqe/Kconfig"
source "drivers/misc/echo/Kconfig"
source "drivers/misc/cxl/Kconfig"
......
......@@ -46,7 +46,6 @@ obj-$(CONFIG_VMWARE_VMCI) += vmw_vmci/
obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o
obj-$(CONFIG_SRAM) += sram.o
obj-$(CONFIG_SRAM_EXEC) += sram-exec.o
obj-y += mic/
obj-$(CONFIG_GENWQE) += genwqe/
obj-$(CONFIG_ECHO) += echo/
obj-$(CONFIG_CXL_BASE) += cxl/
......
# SPDX-License-Identifier: GPL-2.0-only
menu "Intel MIC & related support"
config INTEL_MIC_BUS
tristate "Intel MIC Bus Driver"
depends on 64BIT && PCI && X86
select DMA_OPS
help
This option is selected by any driver which registers a
device or driver on the MIC Bus, such as CONFIG_INTEL_MIC_HOST,
CONFIG_INTEL_MIC_CARD, CONFIG_INTEL_MIC_X100_DMA etc.
If you are building a host/card kernel with an Intel MIC device
then say M (recommended) or Y, else say N. If unsure say N.
More information about the Intel MIC family as well as the Linux
OS and tools for MIC to use with this driver are available from
<http://software.intel.com/en-us/mic-developer>.
config SCIF_BUS
tristate "SCIF Bus Driver"
depends on 64BIT && PCI && X86
select DMA_OPS
help
This option is selected by any driver which registers a
device or driver on the SCIF Bus, such as CONFIG_INTEL_MIC_HOST
and CONFIG_INTEL_MIC_CARD.
If you are building a host/card kernel with an Intel MIC device
then say M (recommended) or Y, else say N. If unsure say N.
More information about the Intel MIC family as well as the Linux
OS and tools for MIC to use with this driver are available from
<http://software.intel.com/en-us/mic-developer>.
config VOP_BUS
tristate "VOP Bus Driver"
depends on HAS_DMA
select DMA_OPS
help
This option is selected by any driver which registers a
device or driver on the VOP Bus, such as CONFIG_INTEL_MIC_HOST
and CONFIG_INTEL_MIC_CARD.
If you are building a host/card kernel with an Intel MIC device
then say M (recommended) or Y, else say N. If unsure say N.
More information about the Intel MIC family as well as the Linux
OS and tools for MIC to use with this driver are available from
<http://software.intel.com/en-us/mic-developer>.
config INTEL_MIC_HOST
tristate "Intel MIC Host Driver"
depends on 64BIT && PCI && X86
depends on INTEL_MIC_BUS && SCIF_BUS && MIC_COSM && VOP_BUS
select DMA_OPS
help
This enables Host Driver support for the Intel Many Integrated
Core (MIC) family of PCIe form factor coprocessor devices that
run a 64 bit Linux OS. The driver manages card OS state and
enables communication between host and card. Intel MIC X100
devices are currently supported.
If you are building a host kernel with an Intel MIC device then
say M (recommended) or Y, else say N. If unsure say N.
More information about the Intel MIC family as well as the Linux
OS and tools for MIC to use with this driver are available from
<http://software.intel.com/en-us/mic-developer>.
config INTEL_MIC_CARD
tristate "Intel MIC Card Driver"
depends on 64BIT && X86
depends on INTEL_MIC_BUS && SCIF_BUS && MIC_COSM && VOP_BUS
select VIRTIO
help
This enables card driver support for the Intel Many Integrated
Core (MIC) device family. The card driver communicates shutdown/
crash events to the host and allows registration/configuration of
virtio devices. Intel MIC X100 devices are currently supported.
If you are building a card kernel for an Intel MIC device then
say M (recommended) or Y, else say N. If unsure say N.
For more information see
<http://software.intel.com/en-us/mic-developer>.
config SCIF
tristate "SCIF Driver"
depends on 64BIT && PCI && X86 && SCIF_BUS && IOMMU_SUPPORT
select IOMMU_IOVA
help
This enables SCIF Driver support for the Intel Many Integrated
Core (MIC) family of PCIe form factor coprocessor devices that
run a 64 bit Linux OS. The Symmetric Communication Interface
(SCIF (pronounced as skiff)) is a low level communications API
across PCIe currently implemented for MIC.
If you are building a host kernel with an Intel MIC device then
say M (recommended) or Y, else say N. If unsure say N.
More information about the Intel MIC family as well as the Linux
OS and tools for MIC to use with this driver are available from
<http://software.intel.com/en-us/mic-developer>.
config MIC_COSM
tristate "Intel MIC Coprocessor State Management (COSM) Drivers"
depends on 64BIT && PCI && X86 && SCIF
help
This enables COSM driver support for the Intel Many
Integrated Core (MIC) family of PCIe form factor coprocessor
devices. COSM drivers implement functions such as boot,
shutdown, reset and reboot of MIC devices.
If you are building a host kernel with an Intel MIC device then
say M (recommended) or Y, else say N. If unsure say N.
More information about the Intel MIC family as well as the Linux
OS and tools for MIC to use with this driver are available from
<http://software.intel.com/en-us/mic-developer>.
config VOP
tristate "VOP Driver"
depends on VOP_BUS
select VHOST_RING
select VIRTIO
help
This enables VOP (Virtio over PCIe) Driver support for the Intel
Many Integrated Core (MIC) family of PCIe form factor coprocessor
devices. The VOP driver allows virtio drivers, e.g. net, console
and block drivers, on the card connect to user space virtio
devices on the host.
If you are building a host kernel with an Intel MIC device then
say M (recommended) or Y, else say N. If unsure say N.
More information about the Intel MIC family as well as the Linux
OS and tools for MIC to use with this driver are available from
<http://software.intel.com/en-us/mic-developer>.
endmenu
# SPDX-License-Identifier: GPL-2.0
#
# Makefile - Intel MIC Linux driver.
# Copyright(c) 2013, Intel Corporation.
#
obj-$(CONFIG_INTEL_MIC_HOST) += host/
obj-$(CONFIG_INTEL_MIC_CARD) += card/
obj-y += bus/
obj-$(CONFIG_SCIF) += scif/
obj-$(CONFIG_MIC_COSM) += cosm/
obj-$(CONFIG_MIC_COSM) += cosm_client/
obj-$(CONFIG_VOP) += vop/
# SPDX-License-Identifier: GPL-2.0-only
#
# Makefile - Intel MIC Linux driver.
# Copyright(c) 2014, Intel Corporation.
#
obj-$(CONFIG_INTEL_MIC_BUS) += mic_bus.o
obj-$(CONFIG_SCIF_BUS) += scif_bus.o
obj-$(CONFIG_MIC_COSM) += cosm_bus.o
obj-$(CONFIG_VOP_BUS) += vop_bus.o
// SPDX-License-Identifier: GPL-2.0-only
/*
* Intel MIC Platform Software Stack (MPSS)
*
* Copyright(c) 2015 Intel Corporation.
*
* Intel MIC COSM Bus Driver
*/
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/idr.h>
#include "cosm_bus.h"
/* Unique numbering for cosm devices. */
static DEFINE_IDA(cosm_index_ida);
static int cosm_dev_probe(struct device *d)
{
struct cosm_device *dev = dev_to_cosm(d);
struct cosm_driver *drv = drv_to_cosm(dev->dev.driver);
return drv->probe(dev);
}
static int cosm_dev_remove(struct device *d)
{
struct cosm_device *dev = dev_to_cosm(d);
struct cosm_driver *drv = drv_to_cosm(dev->dev.driver);
drv->remove(dev);
return 0;
}
static struct bus_type cosm_bus = {
.name = "cosm_bus",
.probe = cosm_dev_probe,
.remove = cosm_dev_remove,
};
int cosm_register_driver(struct cosm_driver *driver)
{
driver->driver.bus = &cosm_bus;
return driver_register(&driver->driver);
}
EXPORT_SYMBOL_GPL(cosm_register_driver);
void cosm_unregister_driver(struct cosm_driver *driver)
{
driver_unregister(&driver->driver);
}
EXPORT_SYMBOL_GPL(cosm_unregister_driver);
static inline void cosm_release_dev(struct device *d)
{
struct cosm_device *cdev = dev_to_cosm(d);
kfree(cdev);
}
struct cosm_device *
cosm_register_device(struct device *pdev, struct cosm_hw_ops *hw_ops)
{
struct cosm_device *cdev;
int ret;
cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
if (!cdev)
return ERR_PTR(-ENOMEM);
cdev->dev.parent = pdev;
cdev->dev.release = cosm_release_dev;
cdev->hw_ops = hw_ops;
dev_set_drvdata(&cdev->dev, cdev);
cdev->dev.bus = &cosm_bus;
/* Assign a unique device index and hence name */
ret = ida_simple_get(&cosm_index_ida, 0, 0, GFP_KERNEL);
if (ret < 0)
goto free_cdev;
cdev->index = ret;
cdev->dev.id = ret;
dev_set_name(&cdev->dev, "cosm-dev%u", cdev->index);
ret = device_register(&cdev->dev);
if (ret)
goto ida_remove;
return cdev;
ida_remove:
ida_simple_remove(&cosm_index_ida, cdev->index);
free_cdev:
put_device(&cdev->dev);
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(cosm_register_device);
void cosm_unregister_device(struct cosm_device *dev)
{
int index = dev->index; /* save for after device release */
device_unregister(&dev->dev);
ida_simple_remove(&cosm_index_ida, index);
}
EXPORT_SYMBOL_GPL(cosm_unregister_device);
struct cosm_device *cosm_find_cdev_by_id(int id)
{
struct device *dev = subsys_find_device_by_id(&cosm_bus, id, NULL);
return dev ? container_of(dev, struct cosm_device, dev) : NULL;
}
EXPORT_SYMBOL_GPL(cosm_find_cdev_by_id);
static int __init cosm_init(void)
{
return bus_register(&cosm_bus);
}
static void __exit cosm_exit(void)
{
bus_unregister(&cosm_bus);
ida_destroy(&cosm_index_ida);
}
core_initcall(cosm_init);
module_exit(cosm_exit);
MODULE_AUTHOR("Intel Corporation");
MODULE_DESCRIPTION("Intel(R) MIC card OS state management bus driver");
MODULE_LICENSE("GPL v2");
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Intel MIC Platform Software Stack (MPSS)
*
* Copyright(c) 2015 Intel Corporation.
*
* Intel MIC COSM Bus Driver
*/
#ifndef _COSM_BUS_H_
#define _COSM_BUS_H_
#include <linux/scif.h>
#include <linux/mic_common.h>
#include "../common/mic_dev.h"
/**
* cosm_device - representation of a cosm device
*
* @attr_group: Pointer to list of sysfs attribute groups.
* @sdev: Device for sysfs entries.
* @state: MIC state.
* @prev_state: MIC state previous to MIC_RESETTING
* @shutdown_status: MIC status reported by card for shutdown/crashes.
* @shutdown_status_int: Internal shutdown status maintained by the driver
* @cosm_mutex: Mutex for synchronizing access to data structures.
* @reset_trigger_work: Work for triggering reset requests.
* @scif_work: Work for handling per device SCIF connections
* @cmdline: Kernel command line.
* @firmware: Firmware file name.
* @ramdisk: Ramdisk file name.
* @bootmode: Boot mode i.e. "linux" or "elf" for flash updates.
* @log_buf_addr: Log buffer address for MIC.
* @log_buf_len: Log buffer length address for MIC.
* @state_sysfs: Sysfs dirent for notifying ring 3 about MIC state changes.
* @hw_ops: the hardware bus ops for this device.
* @dev: underlying device.
* @index: unique position on the cosm bus
* @dbg_dir: debug fs directory
* @newepd: new endpoint from scif accept to be assigned to this cdev
* @epd: SCIF endpoint for this cdev
* @heartbeat_watchdog_enable: if heartbeat watchdog is enabled for this cdev
* @sysfs_heartbeat_enable: sysfs setting for disabling heartbeat notification
*/
struct cosm_device {
const struct attribute_group **attr_group;
struct device *sdev;
u8 state;
u8 prev_state;
u8 shutdown_status;
u8 shutdown_status_int;
struct mutex cosm_mutex;
struct work_struct reset_trigger_work;
struct work_struct scif_work;
char *cmdline;
char *firmware;
char *ramdisk;
char *bootmode;
void *log_buf_addr;
int *log_buf_len;
struct kernfs_node *state_sysfs;
struct cosm_hw_ops *hw_ops;
struct device dev;
int index;
struct dentry *dbg_dir;
scif_epd_t newepd;
scif_epd_t epd;
bool heartbeat_watchdog_enable;
bool sysfs_heartbeat_enable;
};
/**
* cosm_driver - operations for a cosm driver
*
* @driver: underlying device driver (populate name and owner).
* @probe: the function to call when a device is found. Returns 0 or -errno.
* @remove: the function to call when a device is removed.
*/
struct cosm_driver {
struct device_driver driver;
int (*probe)(struct cosm_device *dev);
void (*remove)(struct cosm_device *dev);
};
/**
* cosm_hw_ops - cosm bus ops
*
* @reset: trigger MIC reset
* @force_reset: force MIC reset
* @post_reset: inform MIC reset is complete
* @ready: is MIC ready for OS download
* @start: boot MIC
* @stop: prepare MIC for reset
* @family: return MIC HW family string
* @stepping: return MIC HW stepping string
* @aper: return MIC PCIe aperture
*/
struct cosm_hw_ops {
void (*reset)(struct cosm_device *cdev);
void (*force_reset)(struct cosm_device *cdev);
void (*post_reset)(struct cosm_device *cdev, enum mic_states state);
bool (*ready)(struct cosm_device *cdev);
int (*start)(struct cosm_device *cdev, int id);
void (*stop)(struct cosm_device *cdev, bool force);
ssize_t (*family)(struct cosm_device *cdev, char *buf);
ssize_t (*stepping)(struct cosm_device *cdev, char *buf);
struct mic_mw *(*aper)(struct cosm_device *cdev);
};
struct cosm_device *
cosm_register_device(struct device *pdev, struct cosm_hw_ops *hw_ops);
void cosm_unregister_device(struct cosm_device *dev);
int cosm_register_driver(struct cosm_driver *drv);
void cosm_unregister_driver(struct cosm_driver *drv);
struct cosm_device *cosm_find_cdev_by_id(int id);
static inline struct cosm_device *dev_to_cosm(struct device *dev)
{
return container_of(dev, struct cosm_device, dev);
}
static inline struct cosm_driver *drv_to_cosm(struct device_driver *drv)
{
return container_of(drv, struct cosm_driver, driver);
}
#endif /* _COSM_BUS_H */
// SPDX-License-Identifier: GPL-2.0-only
/*
* Intel MIC Platform Software Stack (MPSS)
*
* Copyright(c) 2014 Intel Corporation.
*
* Intel MIC Bus driver.
*
* This implementation is very similar to the the virtio bus driver
* implementation @ drivers/virtio/virtio.c
*/
#include <linux/dma-map-ops.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/idr.h>
#include <linux/mic_bus.h>
static ssize_t device_show(struct device *d,
struct device_attribute *attr, char *buf)
{
struct mbus_device *dev = dev_to_mbus(d);
return sprintf(buf, "0x%04x\n", dev->id.device);
}
static DEVICE_ATTR_RO(device);
static ssize_t vendor_show(struct device *d,
struct device_attribute *attr, char *buf)
{
struct mbus_device *dev = dev_to_mbus(d);
return sprintf(buf, "0x%04x\n", dev->id.vendor);
}
static DEVICE_ATTR_RO(vendor);
static ssize_t modalias_show(struct device *d,
struct device_attribute *attr, char *buf)
{
struct mbus_device *dev = dev_to_mbus(d);
return sprintf(buf, "mbus:d%08Xv%08X\n",
dev->id.device, dev->id.vendor);
}
static DEVICE_ATTR_RO(modalias);
static struct attribute *mbus_dev_attrs[] = {
&dev_attr_device.attr,
&dev_attr_vendor.attr,
&dev_attr_modalias.attr,
NULL,
};
ATTRIBUTE_GROUPS(mbus_dev);
static inline int mbus_id_match(const struct mbus_device *dev,
const struct mbus_device_id *id)
{
if (id->device != dev->id.device && id->device != MBUS_DEV_ANY_ID)
return 0;
return id->vendor == MBUS_DEV_ANY_ID || id->vendor == dev->id.vendor;
}
/*
* This looks through all the IDs a driver claims to support. If any of them
* match, we return 1 and the kernel will call mbus_dev_probe().
*/
static int mbus_dev_match(struct device *dv, struct device_driver *dr)
{
unsigned int i;
struct mbus_device *dev = dev_to_mbus(dv);
const struct mbus_device_id *ids;
ids = drv_to_mbus(dr)->id_table;
for (i = 0; ids[i].device; i++)
if (mbus_id_match(dev, &ids[i]))
return 1;
return 0;
}
static int mbus_uevent(struct device *dv, struct kobj_uevent_env *env)
{
struct mbus_device *dev = dev_to_mbus(dv);
return add_uevent_var(env, "MODALIAS=mbus:d%08Xv%08X",
dev->id.device, dev->id.vendor);
}
static int mbus_dev_probe(struct device *d)
{
int err;
struct mbus_device *dev = dev_to_mbus(d);
struct mbus_driver *drv = drv_to_mbus(dev->dev.driver);
err = drv->probe(dev);
if (!err)
if (drv->scan)
drv->scan(dev);
return err;
}
static int mbus_dev_remove(struct device *d)
{
struct mbus_device *dev = dev_to_mbus(d);
struct mbus_driver *drv = drv_to_mbus(dev->dev.driver);
drv->remove(dev);
return 0;
}
static struct bus_type mic_bus = {
.name = "mic_bus",
.match = mbus_dev_match,
.dev_groups = mbus_dev_groups,
.uevent = mbus_uevent,
.probe = mbus_dev_probe,
.remove = mbus_dev_remove,
};
int mbus_register_driver(struct mbus_driver *driver)
{
driver->driver.bus = &mic_bus;
return driver_register(&driver->driver);
}
EXPORT_SYMBOL_GPL(mbus_register_driver);
void mbus_unregister_driver(struct mbus_driver *driver)
{
driver_unregister(&driver->driver);
}
EXPORT_SYMBOL_GPL(mbus_unregister_driver);
static void mbus_release_dev(struct device *d)
{
struct mbus_device *mbdev = dev_to_mbus(d);
kfree(mbdev);
}
struct mbus_device *
mbus_register_device(struct device *pdev, int id, const struct dma_map_ops *dma_ops,
struct mbus_hw_ops *hw_ops, int index,
void __iomem *mmio_va)
{
int ret;
struct mbus_device *mbdev;
mbdev = kzalloc(sizeof(*mbdev), GFP_KERNEL);
if (!mbdev)
return ERR_PTR(-ENOMEM);
mbdev->mmio_va = mmio_va;
mbdev->dev.parent = pdev;
mbdev->id.device = id;
mbdev->id.vendor = MBUS_DEV_ANY_ID;
mbdev->dev.dma_ops = dma_ops;
mbdev->dev.dma_mask = &mbdev->dev.coherent_dma_mask;
dma_set_mask(&mbdev->dev, DMA_BIT_MASK(64));
mbdev->dev.release = mbus_release_dev;
mbdev->hw_ops = hw_ops;
mbdev->dev.bus = &mic_bus;
mbdev->index = index;
dev_set_name(&mbdev->dev, "mbus-dev%u", mbdev->index);
/*
* device_register() causes the bus infrastructure to look for a
* matching driver.
*/
ret = device_register(&mbdev->dev);
if (ret)
goto free_mbdev;
return mbdev;
free_mbdev:
put_device(&mbdev->dev);
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(mbus_register_device);
void mbus_unregister_device(struct mbus_device *mbdev)
{
device_unregister(&mbdev->dev);
}
EXPORT_SYMBOL_GPL(mbus_unregister_device);
static int __init mbus_init(void)
{
return bus_register(&mic_bus);
}
static void __exit mbus_exit(void)
{
bus_unregister(&mic_bus);
}
core_initcall(mbus_init);
module_exit(mbus_exit);
MODULE_AUTHOR("Intel Corporation");
MODULE_DESCRIPTION("Intel(R) MIC Bus driver");
MODULE_LICENSE("GPL v2");
// SPDX-License-Identifier: GPL-2.0-only
/*
* Intel MIC Platform Software Stack (MPSS)
*
* Copyright(c) 2014 Intel Corporation.
*
* Intel Symmetric Communications Interface Bus driver.
*/
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/idr.h>
#include <linux/dma-map-ops.h>
#include "scif_bus.h"
static ssize_t device_show(struct device *d,
struct device_attribute *attr, char *buf)
{
struct scif_hw_dev *dev = dev_to_scif(d);
return sprintf(buf, "0x%04x\n", dev->id.device);
}
static DEVICE_ATTR_RO(device);
static ssize_t vendor_show(struct device *d,
struct device_attribute *attr, char *buf)
{
struct scif_hw_dev *dev = dev_to_scif(d);
return sprintf(buf, "0x%04x\n", dev->id.vendor);
}
static DEVICE_ATTR_RO(vendor);
static ssize_t modalias_show(struct device *d,
struct device_attribute *attr, char *buf)
{
struct scif_hw_dev *dev = dev_to_scif(d);
return sprintf(buf, "scif:d%08Xv%08X\n",
dev->id.device, dev->id.vendor);
}
static DEVICE_ATTR_RO(modalias);
static struct attribute *scif_dev_attrs[] = {
&dev_attr_device.attr,
&dev_attr_vendor.attr,
&dev_attr_modalias.attr,
NULL,
};
ATTRIBUTE_GROUPS(scif_dev);
static inline int scif_id_match(const struct scif_hw_dev *dev,
const struct scif_hw_dev_id *id)
{
if (id->device != dev->id.device && id->device != SCIF_DEV_ANY_ID)
return 0;
return id->vendor == SCIF_DEV_ANY_ID || id->vendor == dev->id.vendor;
}
/*
* This looks through all the IDs a driver claims to support. If any of them
* match, we return 1 and the kernel will call scif_dev_probe().
*/
static int scif_dev_match(struct device *dv, struct device_driver *dr)
{
unsigned int i;
struct scif_hw_dev *dev = dev_to_scif(dv);
const struct scif_hw_dev_id *ids;
ids = drv_to_scif(dr)->id_table;
for (i = 0; ids[i].device; i++)
if (scif_id_match(dev, &ids[i]))
return 1;
return 0;
}
static int scif_uevent(struct device *dv, struct kobj_uevent_env *env)
{
struct scif_hw_dev *dev = dev_to_scif(dv);
return add_uevent_var(env, "MODALIAS=scif:d%08Xv%08X",
dev->id.device, dev->id.vendor);
}
static int scif_dev_probe(struct device *d)
{
struct scif_hw_dev *dev = dev_to_scif(d);
struct scif_driver *drv = drv_to_scif(dev->dev.driver);
return drv->probe(dev);
}
static int scif_dev_remove(struct device *d)
{
struct scif_hw_dev *dev = dev_to_scif(d);
struct scif_driver *drv = drv_to_scif(dev->dev.driver);
drv->remove(dev);
return 0;
}
static struct bus_type scif_bus = {
.name = "scif_bus",
.match = scif_dev_match,
.dev_groups = scif_dev_groups,
.uevent = scif_uevent,
.probe = scif_dev_probe,
.remove = scif_dev_remove,
};
int scif_register_driver(struct scif_driver *driver)
{
driver->driver.bus = &scif_bus;
return driver_register(&driver->driver);
}
EXPORT_SYMBOL_GPL(scif_register_driver);
void scif_unregister_driver(struct scif_driver *driver)
{
driver_unregister(&driver->driver);
}
EXPORT_SYMBOL_GPL(scif_unregister_driver);
static void scif_release_dev(struct device *d)
{
struct scif_hw_dev *sdev = dev_to_scif(d);
kfree(sdev);
}
struct scif_hw_dev *
scif_register_device(struct device *pdev, int id, const struct dma_map_ops *dma_ops,
struct scif_hw_ops *hw_ops, u8 dnode, u8 snode,
struct mic_mw *mmio, struct mic_mw *aper, void *dp,
void __iomem *rdp, struct dma_chan **chan, int num_chan,
bool card_rel_da)
{
int ret;
struct scif_hw_dev *sdev;
sdev = kzalloc(sizeof(*sdev), GFP_KERNEL);
if (!sdev)
return ERR_PTR(-ENOMEM);
sdev->dev.parent = pdev;
sdev->id.device = id;
sdev->id.vendor = SCIF_DEV_ANY_ID;
sdev->dev.dma_ops = dma_ops;
sdev->dev.release = scif_release_dev;
sdev->hw_ops = hw_ops;
sdev->dnode = dnode;
sdev->snode = snode;
dev_set_drvdata(&sdev->dev, sdev);
sdev->dev.bus = &scif_bus;
sdev->mmio = mmio;
sdev->aper = aper;
sdev->dp = dp;
sdev->rdp = rdp;
sdev->dev.dma_mask = &sdev->dev.coherent_dma_mask;
dma_set_mask(&sdev->dev, DMA_BIT_MASK(64));
sdev->dma_ch = chan;
sdev->num_dma_ch = num_chan;
sdev->card_rel_da = card_rel_da;
dev_set_name(&sdev->dev, "scif-dev%u", sdev->dnode);
/*
* device_register() causes the bus infrastructure to look for a
* matching driver.
*/
ret = device_register(&sdev->dev);
if (ret)
goto free_sdev;
return sdev;
free_sdev:
put_device(&sdev->dev);
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(scif_register_device);
void scif_unregister_device(struct scif_hw_dev *sdev)
{
device_unregister(&sdev->dev);
}
EXPORT_SYMBOL_GPL(scif_unregister_device);
static int __init scif_init(void)
{
return bus_register(&scif_bus);
}
static void __exit scif_exit(void)
{
bus_unregister(&scif_bus);
}
core_initcall(scif_init);
module_exit(scif_exit);
MODULE_AUTHOR("Intel Corporation");
MODULE_DESCRIPTION("Intel(R) SCIF Bus driver");
MODULE_LICENSE("GPL v2");
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Intel MIC Platform Software Stack (MPSS)
*
* Copyright(c) 2014 Intel Corporation.
*
* Intel Symmetric Communications Interface Bus driver.
*/
#ifndef _SCIF_BUS_H_
#define _SCIF_BUS_H_
/*
* Everything a scif driver needs to work with any particular scif
* hardware abstraction layer.
*/
#include <linux/dma-map-ops.h>
#include <linux/mic_common.h>
#include "../common/mic_dev.h"
struct scif_hw_dev_id {
u32 device;
u32 vendor;
};
#define MIC_SCIF_DEV 1
#define SCIF_DEV_ANY_ID 0xffffffff
/**
* scif_hw_dev - representation of a hardware device abstracted for scif
* @hw_ops: the hardware ops supported by this device
* @id: the device type identification (used to match it with a driver)
* @mmio: MMIO memory window
* @aper: Aperture memory window
* @dev: underlying device
* @dnode - The destination node which this device will communicate with.
* @snode - The source node for this device.
* @dp - Self device page
* @rdp - Remote device page
* @dma_ch - Array of DMA channels
* @num_dma_ch - Number of DMA channels available
* @card_rel_da - Set to true if DMA addresses programmed in the DMA engine
* are relative to the card point of view
*/
struct scif_hw_dev {
struct scif_hw_ops *hw_ops;
struct scif_hw_dev_id id;
struct mic_mw *mmio;
struct mic_mw *aper;
struct device dev;
u8 dnode;
u8 snode;
void *dp;
void __iomem *rdp;
struct dma_chan **dma_ch;
int num_dma_ch;
bool card_rel_da;
};
/**
* scif_driver - operations for a scif I/O driver
* @driver: underlying device driver (populate name and owner).
* @id_table: the ids serviced by this driver.
* @probe: the function to call when a device is found. Returns 0 or -errno.
* @remove: the function to call when a device is removed.
*/
struct scif_driver {
struct device_driver driver;
const struct scif_hw_dev_id *id_table;
int (*probe)(struct scif_hw_dev *dev);
void (*remove)(struct scif_hw_dev *dev);
};
/**
* scif_hw_ops - Hardware operations for accessing a SCIF device on the SCIF bus.
*
* @next_db: Obtain the next available doorbell.
* @request_irq: Request an interrupt on a particular doorbell.
* @free_irq: Free an interrupt requested previously.
* @ack_interrupt: acknowledge an interrupt in the ISR.
* @send_intr: Send an interrupt to the remote node on a specified doorbell.
* @send_p2p_intr: Send an interrupt to the peer node on a specified doorbell
* which is specifically targeted for a peer to peer node.
* @remap: Map a buffer with the specified physical address and length.
* @unmap: Unmap a buffer previously mapped.
*/
struct scif_hw_ops {
int (*next_db)(struct scif_hw_dev *sdev);
struct mic_irq * (*request_irq)(struct scif_hw_dev *sdev,
irqreturn_t (*func)(int irq,
void *data),
const char *name, void *data,
int db);
void (*free_irq)(struct scif_hw_dev *sdev,
struct mic_irq *cookie, void *data);
void (*ack_interrupt)(struct scif_hw_dev *sdev, int num);
void (*send_intr)(struct scif_hw_dev *sdev, int db);
void (*send_p2p_intr)(struct scif_hw_dev *sdev, int db,
struct mic_mw *mw);
void __iomem * (*remap)(struct scif_hw_dev *sdev,
phys_addr_t pa, size_t len);
void (*unmap)(struct scif_hw_dev *sdev, void __iomem *va);
};
int scif_register_driver(struct scif_driver *driver);
void scif_unregister_driver(struct scif_driver *driver);
struct scif_hw_dev *
scif_register_device(struct device *pdev, int id,
const struct dma_map_ops *dma_ops,
struct scif_hw_ops *hw_ops, u8 dnode, u8 snode,
struct mic_mw *mmio, struct mic_mw *aper,
void *dp, void __iomem *rdp,
struct dma_chan **chan, int num_chan,
bool card_rel_da);
void scif_unregister_device(struct scif_hw_dev *sdev);
static inline struct scif_hw_dev *dev_to_scif(struct device *dev)
{
return container_of(dev, struct scif_hw_dev, dev);
}
static inline struct scif_driver *drv_to_scif(struct device_driver *drv)
{
return container_of(drv, struct scif_driver, driver);
}
#endif /* _SCIF_BUS_H */
// SPDX-License-Identifier: GPL-2.0-only
/*
* Intel MIC Platform Software Stack (MPSS)
*
* Copyright(c) 2016 Intel Corporation.
*
* Intel Virtio Over PCIe (VOP) Bus driver.
*/
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/idr.h>
#include <linux/dma-map-ops.h>
#include "vop_bus.h"
static ssize_t device_show(struct device *d,
struct device_attribute *attr, char *buf)
{
struct vop_device *dev = dev_to_vop(d);
return sprintf(buf, "0x%04x\n", dev->id.device);
}
static DEVICE_ATTR_RO(device);
static ssize_t vendor_show(struct device *d,
struct device_attribute *attr, char *buf)
{
struct vop_device *dev = dev_to_vop(d);
return sprintf(buf, "0x%04x\n", dev->id.vendor);
}
static DEVICE_ATTR_RO(vendor);
static ssize_t modalias_show(struct device *d,
struct device_attribute *attr, char *buf)
{
struct vop_device *dev = dev_to_vop(d);
return sprintf(buf, "vop:d%08Xv%08X\n",
dev->id.device, dev->id.vendor);
}
static DEVICE_ATTR_RO(modalias);
static struct attribute *vop_dev_attrs[] = {
&dev_attr_device.attr,
&dev_attr_vendor.attr,
&dev_attr_modalias.attr,
NULL,
};
ATTRIBUTE_GROUPS(vop_dev);
static inline int vop_id_match(const struct vop_device *dev,
const struct vop_device_id *id)
{
if (id->device != dev->id.device && id->device != VOP_DEV_ANY_ID)
return 0;
return id->vendor == VOP_DEV_ANY_ID || id->vendor == dev->id.vendor;
}
/*
* This looks through all the IDs a driver claims to support. If any of them
* match, we return 1 and the kernel will call vop_dev_probe().
*/
static int vop_dev_match(struct device *dv, struct device_driver *dr)
{
unsigned int i;
struct vop_device *dev = dev_to_vop(dv);
const struct vop_device_id *ids;
ids = drv_to_vop(dr)->id_table;
for (i = 0; ids[i].device; i++)
if (vop_id_match(dev, &ids[i]))
return 1;
return 0;
}
static int vop_uevent(struct device *dv, struct kobj_uevent_env *env)
{
struct vop_device *dev = dev_to_vop(dv);
return add_uevent_var(env, "MODALIAS=vop:d%08Xv%08X",
dev->id.device, dev->id.vendor);
}
static int vop_dev_probe(struct device *d)
{
struct vop_device *dev = dev_to_vop(d);
struct vop_driver *drv = drv_to_vop(dev->dev.driver);
return drv->probe(dev);
}
static int vop_dev_remove(struct device *d)
{
struct vop_device *dev = dev_to_vop(d);
struct vop_driver *drv = drv_to_vop(dev->dev.driver);
drv->remove(dev);
return 0;
}
static struct bus_type vop_bus = {
.name = "vop_bus",
.match = vop_dev_match,
.dev_groups = vop_dev_groups,
.uevent = vop_uevent,
.probe = vop_dev_probe,
.remove = vop_dev_remove,
};
int vop_register_driver(struct vop_driver *driver)
{
driver->driver.bus = &vop_bus;
return driver_register(&driver->driver);
}
EXPORT_SYMBOL_GPL(vop_register_driver);
void vop_unregister_driver(struct vop_driver *driver)
{
driver_unregister(&driver->driver);
}
EXPORT_SYMBOL_GPL(vop_unregister_driver);
static void vop_release_dev(struct device *d)
{
struct vop_device *dev = dev_to_vop(d);
kfree(dev);
}
struct vop_device *
vop_register_device(struct device *pdev, int id,
const struct dma_map_ops *dma_ops,
struct vop_hw_ops *hw_ops, u8 dnode, struct mic_mw *aper,
struct dma_chan *chan)
{
int ret;
struct vop_device *vdev;
vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
if (!vdev)
return ERR_PTR(-ENOMEM);
vdev->dev.parent = pdev;
vdev->id.device = id;
vdev->id.vendor = VOP_DEV_ANY_ID;
vdev->dev.dma_ops = dma_ops;
vdev->dev.dma_mask = &vdev->dev.coherent_dma_mask;
dma_set_mask(&vdev->dev, DMA_BIT_MASK(64));
vdev->dev.release = vop_release_dev;
vdev->hw_ops = hw_ops;
vdev->dev.bus = &vop_bus;
vdev->dnode = dnode;
vdev->aper = aper;
vdev->dma_ch = chan;
vdev->index = dnode - 1;
dev_set_name(&vdev->dev, "vop-dev%u", vdev->index);
/*
* device_register() causes the bus infrastructure to look for a
* matching driver.
*/
ret = device_register(&vdev->dev);
if (ret)
goto free_vdev;
return vdev;
free_vdev:
put_device(&vdev->dev);
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(vop_register_device);
void vop_unregister_device(struct vop_device *dev)
{
device_unregister(&dev->dev);
}
EXPORT_SYMBOL_GPL(vop_unregister_device);
static int __init vop_init(void)
{
return bus_register(&vop_bus);
}
static void __exit vop_exit(void)
{
bus_unregister(&vop_bus);
}
core_initcall(vop_init);
module_exit(vop_exit);
MODULE_AUTHOR("Intel Corporation");
MODULE_DESCRIPTION("Intel(R) VOP Bus driver");
MODULE_LICENSE("GPL v2");
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Intel MIC Platform Software Stack (MPSS)
*
* Copyright(c) 2016 Intel Corporation.
*
* Intel Virtio over PCIe Bus driver.
*/
#ifndef _VOP_BUS_H_
#define _VOP_BUS_H_
/*
* Everything a vop driver needs to work with any particular vop
* implementation.
*/
#include <linux/dmaengine.h>
#include <linux/interrupt.h>
#include "../common/mic_dev.h"
struct vop_device_id {
u32 device;
u32 vendor;
};
#define VOP_DEV_TRNSP 1
#define VOP_DEV_ANY_ID 0xffffffff
/*
* Size of the internal buffer used during DMA's as an intermediate buffer
* for copy to/from user. Must be an integral number of pages.
*/
#define VOP_INT_DMA_BUF_SIZE PAGE_ALIGN(64 * 1024ULL)
/**
* vop_device - representation of a device using vop
* @hw_ops: the hardware ops supported by this device.
* @id: the device type identification (used to match it with a driver).
* @dev: underlying device.
* @dnode - The destination node which this device will communicate with.
* @aper: Aperture memory window
* @dma_ch - DMA channel
* @index: unique position on the vop bus
*/
struct vop_device {
struct vop_hw_ops *hw_ops;
struct vop_device_id id;
struct device dev;
u8 dnode;
struct mic_mw *aper;
struct dma_chan *dma_ch;
int index;
};
/**
* vop_driver - operations for a vop I/O driver
* @driver: underlying device driver (populate name and owner).
* @id_table: the ids serviced by this driver.
* @probe: the function to call when a device is found. Returns 0 or -errno.
* @remove: the function to call when a device is removed.
*/
struct vop_driver {
struct device_driver driver;
const struct vop_device_id *id_table;
int (*probe)(struct vop_device *dev);
void (*remove)(struct vop_device *dev);
};
/**
* vop_hw_ops - Hardware operations for accessing a VOP device on the VOP bus.
*
* @next_db: Obtain the next available doorbell.
* @request_irq: Request an interrupt on a particular doorbell.
* @free_irq: Free an interrupt requested previously.
* @ack_interrupt: acknowledge an interrupt in the ISR.
* @get_remote_dp: Get access to the virtio device page used by the remote
* node to add/remove/configure virtio devices.
* @get_dp: Get access to the virtio device page used by the self
* node to add/remove/configure virtio devices.
* @send_intr: Send an interrupt to the peer node on a specified doorbell.
* @remap: Map a buffer with the specified DMA address and length.
* @unmap: Unmap a buffer previously mapped.
* @dma_filter: The DMA filter function to use for obtaining access to
* a DMA channel on the peer node.
*/
struct vop_hw_ops {
int (*next_db)(struct vop_device *vpdev);
struct mic_irq *(*request_irq)(struct vop_device *vpdev,
irqreturn_t (*func)(int irq, void *data),
const char *name, void *data,
int intr_src);
void (*free_irq)(struct vop_device *vpdev,
struct mic_irq *cookie, void *data);
void (*ack_interrupt)(struct vop_device *vpdev, int num);
void __iomem * (*get_remote_dp)(struct vop_device *vpdev);
void * (*get_dp)(struct vop_device *vpdev);
void (*send_intr)(struct vop_device *vpdev, int db);
void __iomem * (*remap)(struct vop_device *vpdev,
dma_addr_t pa, size_t len);
void (*unmap)(struct vop_device *vpdev, void __iomem *va);
};
struct vop_device *
vop_register_device(struct device *pdev, int id,
const struct dma_map_ops *dma_ops,
struct vop_hw_ops *hw_ops, u8 dnode, struct mic_mw *aper,
struct dma_chan *chan);
void vop_unregister_device(struct vop_device *dev);
int vop_register_driver(struct vop_driver *drv);
void vop_unregister_driver(struct vop_driver *drv);
/*
* module_vop_driver() - Helper macro for drivers that don't do
* anything special in module init/exit. This eliminates a lot of
* boilerplate. Each module may only use this macro once, and
* calling it replaces module_init() and module_exit()
*/
#define module_vop_driver(__vop_driver) \
module_driver(__vop_driver, vop_register_driver, \
vop_unregister_driver)
static inline struct vop_device *dev_to_vop(struct device *dev)
{
return container_of(dev, struct vop_device, dev);
}
static inline struct vop_driver *drv_to_vop(struct device_driver *drv)
{
return container_of(drv, struct vop_driver, driver);
}
#endif /* _VOP_BUS_H */
# SPDX-License-Identifier: GPL-2.0
#
# Makefile - Intel MIC Linux driver.
# Copyright(c) 2013, Intel Corporation.
#
ccflags-y += -DINTEL_MIC_CARD
obj-$(CONFIG_INTEL_MIC_CARD) += mic_card.o
mic_card-y += mic_x100.o
mic_card-y += mic_device.o
mic_card-y += mic_debugfs.o
// SPDX-License-Identifier: GPL-2.0-only
/*
* Intel MIC Platform Software Stack (MPSS)
*
* Copyright(c) 2013 Intel Corporation.
*
* Disclaimer: The codes contained in these modules may be specific to
* the Intel Software Development Platform codenamed: Knights Ferry, and
* the Intel product codenamed: Knights Corner, and are not backward
* compatible with other Intel products. Additionally, Intel will NOT
* support the codes or instruction set in future products.
*
* Intel MIC Card driver.
*/
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/seq_file.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include "../common/mic_dev.h"
#include "mic_device.h"
/* Debugfs parent dir */
static struct dentry *mic_dbg;
/*
* mic_intr_show - Send interrupts to host.
*/
static int mic_intr_show(struct seq_file *s, void *unused)
{
struct mic_driver *mdrv = s->private;
struct mic_device *mdev = &mdrv->mdev;
mic_send_intr(mdev, 0);
msleep(1000);
mic_send_intr(mdev, 1);
msleep(1000);
mic_send_intr(mdev, 2);
msleep(1000);
mic_send_intr(mdev, 3);
msleep(1000);
return 0;
}
DEFINE_SHOW_ATTRIBUTE(mic_intr);
/*
* mic_create_card_debug_dir - Initialize MIC debugfs entries.
*/
void __init mic_create_card_debug_dir(struct mic_driver *mdrv)
{
if (!mic_dbg)
return;
mdrv->dbg_dir = debugfs_create_dir(mdrv->name, mic_dbg);
debugfs_create_file("intr_test", 0444, mdrv->dbg_dir, mdrv,
&mic_intr_fops);
}
/*
* mic_delete_card_debug_dir - Uninitialize MIC debugfs entries.
*/
void mic_delete_card_debug_dir(struct mic_driver *mdrv)
{
debugfs_remove_recursive(mdrv->dbg_dir);
}
/*
* mic_init_card_debugfs - Initialize global debugfs entry.
*/
void __init mic_init_card_debugfs(void)
{
mic_dbg = debugfs_create_dir(KBUILD_MODNAME, NULL);
}
/*
* mic_exit_card_debugfs - Uninitialize global debugfs entry
*/
void mic_exit_card_debugfs(void)
{
debugfs_remove(mic_dbg);
}
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Intel MIC Platform Software Stack (MPSS)
*
* Copyright(c) 2013 Intel Corporation.
*
* Disclaimer: The codes contained in these modules may be specific to
* the Intel Software Development Platform codenamed: Knights Ferry, and
* the Intel product codenamed: Knights Corner, and are not backward
* compatible with other Intel products. Additionally, Intel will NOT
* support the codes or instruction set in future products.
*
* Intel MIC Card driver.
*/
#ifndef _MIC_CARD_DEVICE_H_
#define _MIC_CARD_DEVICE_H_
#include <linux/workqueue.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/mic_bus.h>
#include "../bus/scif_bus.h"
#include "../bus/vop_bus.h"
/**
* struct mic_intr_info - Contains h/w specific interrupt sources info
*
* @num_intr: The number of irqs available
*/
struct mic_intr_info {
u32 num_intr;
};
/**
* struct mic_irq_info - OS specific irq information
*
* @irq_usage_count: usage count array tracking the number of sources
* assigned for each irq.
*/
struct mic_irq_info {
int *irq_usage_count;
};
/**
* struct mic_device - MIC device information.
*
* @mmio: MMIO bar information.
*/
struct mic_device {
struct mic_mw mmio;
};
/**
* struct mic_driver - MIC card driver information.
*
* @name: Name for MIC driver.
* @dbg_dir: debugfs directory of this MIC device.
* @dev: The device backing this MIC.
* @dp: The pointer to the virtio device page.
* @mdev: MIC device information for the host.
* @hotplug_work: Hot plug work for adding/removing virtio devices.
* @irq_info: The OS specific irq information
* @intr_info: H/W specific interrupt information.
* @dma_mbdev: dma device on the MIC virtual bus.
* @dma_ch - Array of DMA channels
* @num_dma_ch - Number of DMA channels available
* @scdev: SCIF device on the SCIF virtual bus.
* @vpdev: Virtio over PCIe device on the VOP virtual bus.
*/
struct mic_driver {
char name[20];
struct dentry *dbg_dir;
struct device *dev;
void __iomem *dp;
struct mic_device mdev;
struct work_struct hotplug_work;
struct mic_irq_info irq_info;
struct mic_intr_info intr_info;
struct mbus_device *dma_mbdev;
struct dma_chan *dma_ch[MIC_MAX_DMA_CHAN];
int num_dma_ch;
struct scif_hw_dev *scdev;
struct vop_device *vpdev;
};
/**
* struct mic_irq - opaque pointer used as cookie
*/
struct mic_irq;
/**
* mic_mmio_read - read from an MMIO register.
* @mw: MMIO register base virtual address.
* @offset: register offset.
*
* RETURNS: register value.
*/
static inline u32 mic_mmio_read(struct mic_mw *mw, u32 offset)
{
return ioread32(mw->va + offset);
}
/**
* mic_mmio_write - write to an MMIO register.
* @mw: MMIO register base virtual address.
* @val: the data value to put into the register
* @offset: register offset.
*
* RETURNS: none.
*/
static inline void
mic_mmio_write(struct mic_mw *mw, u32 val, u32 offset)
{
iowrite32(val, mw->va + offset);
}
int mic_driver_init(struct mic_driver *mdrv);
void mic_driver_uninit(struct mic_driver *mdrv);
int mic_next_card_db(void);
struct mic_irq *
mic_request_card_irq(irq_handler_t handler, irq_handler_t thread_fn,
const char *name, void *data, int db);
void mic_free_card_irq(struct mic_irq *cookie, void *data);
u32 mic_read_spad(struct mic_device *mdev, unsigned int idx);
void mic_send_intr(struct mic_device *mdev, int doorbell);
void mic_send_p2p_intr(int doorbell, struct mic_mw *mw);
int mic_db_to_irq(struct mic_driver *mdrv, int db);
u32 mic_ack_interrupt(struct mic_device *mdev);
void mic_hw_intr_init(struct mic_driver *mdrv);
void __iomem *
mic_card_map(struct mic_device *mdev, dma_addr_t addr, size_t size);
void mic_card_unmap(struct mic_device *mdev, void __iomem *addr);
void __init mic_create_card_debug_dir(struct mic_driver *mdrv);
void mic_delete_card_debug_dir(struct mic_driver *mdrv);
void __init mic_init_card_debugfs(void);
void mic_exit_card_debugfs(void);
#endif
// SPDX-License-Identifier: GPL-2.0-only
/*
* Intel MIC Platform Software Stack (MPSS)
*
* Copyright(c) 2013 Intel Corporation.
*
* Disclaimer: The codes contained in these modules may be specific to
* the Intel Software Development Platform codenamed: Knights Ferry, and
* the Intel product codenamed: Knights Corner, and are not backward
* compatible with other Intel products. Additionally, Intel will NOT
* support the codes or instruction set in future products.
*
* Intel MIC Card driver.
*/
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include "../common/mic_dev.h"
#include "mic_device.h"
#include "mic_x100.h"
static const char mic_driver_name[] = "mic";
static struct mic_driver g_drv;
/**
* mic_read_spad - read from the scratchpad register
* @mdev: pointer to mic_device instance
* @idx: index to scratchpad register, 0 based
*
* This function allows reading of the 32bit scratchpad register.
*
* RETURNS: An appropriate -ERRNO error value on error, or zero for success.
*/
u32 mic_read_spad(struct mic_device *mdev, unsigned int idx)
{
return mic_mmio_read(&mdev->mmio,
MIC_X100_SBOX_BASE_ADDRESS +
MIC_X100_SBOX_SPAD0 + idx * 4);
}
/**
* __mic_send_intr - Send interrupt to Host.
* @mdev: pointer to mic_device instance
* @doorbell: Doorbell number.
*/
void mic_send_intr(struct mic_device *mdev, int doorbell)
{
struct mic_mw *mw = &mdev->mmio;
if (doorbell > MIC_X100_MAX_DOORBELL_IDX)
return;
/* Ensure that the interrupt is ordered w.r.t previous stores. */
wmb();
mic_mmio_write(mw, MIC_X100_SBOX_SDBIC0_DBREQ_BIT,
MIC_X100_SBOX_BASE_ADDRESS +
(MIC_X100_SBOX_SDBIC0 + (4 * doorbell)));
}
/*
* mic_x100_send_sbox_intr - Send an MIC_X100_SBOX interrupt to MIC.
*/
static void mic_x100_send_sbox_intr(struct mic_mw *mw, int doorbell)
{
u64 apic_icr_offset = MIC_X100_SBOX_APICICR0 + doorbell * 8;
u32 apicicr_low = mic_mmio_read(mw, MIC_X100_SBOX_BASE_ADDRESS +
apic_icr_offset);
/* for MIC we need to make sure we "hit" the send_icr bit (13) */
apicicr_low = (apicicr_low | (1 << 13));
/*
* Ensure that the interrupt is ordered w.r.t. previous stores
* to main memory. Fence instructions are not implemented in X100
* since execution is in order but a compiler barrier is still
* required.
*/
wmb();
mic_mmio_write(mw, apicicr_low,
MIC_X100_SBOX_BASE_ADDRESS + apic_icr_offset);
}
static void mic_x100_send_rdmasr_intr(struct mic_mw *mw, int doorbell)
{
int rdmasr_offset = MIC_X100_SBOX_RDMASR0 + (doorbell << 2);
/*
* Ensure that the interrupt is ordered w.r.t. previous stores
* to main memory. Fence instructions are not implemented in X100
* since execution is in order but a compiler barrier is still
* required.
*/
wmb();
mic_mmio_write(mw, 0, MIC_X100_SBOX_BASE_ADDRESS + rdmasr_offset);
}
/**
* mic_ack_interrupt - Device specific interrupt handling.
* @mdev: pointer to mic_device instance
*
* Returns: bitmask of doorbell events triggered.
*/
u32 mic_ack_interrupt(struct mic_device *mdev)
{
return 0;
}
static inline int mic_get_sbox_irq(int db)
{
return MIC_X100_IRQ_BASE + db;
}
static inline int mic_get_rdmasr_irq(int index)
{
return MIC_X100_RDMASR_IRQ_BASE + index;
}
void mic_send_p2p_intr(int db, struct mic_mw *mw)
{
int rdmasr_index;
if (db < MIC_X100_NUM_SBOX_IRQ) {
mic_x100_send_sbox_intr(mw, db);
} else {
rdmasr_index = db - MIC_X100_NUM_SBOX_IRQ;
mic_x100_send_rdmasr_intr(mw, rdmasr_index);
}
}
/**
* mic_hw_intr_init - Initialize h/w specific interrupt
* information.
* @mdrv: pointer to mic_driver
*/
void mic_hw_intr_init(struct mic_driver *mdrv)
{
mdrv->intr_info.num_intr = MIC_X100_NUM_SBOX_IRQ +
MIC_X100_NUM_RDMASR_IRQ;
}
/**
* mic_db_to_irq - Retrieve irq number corresponding to a doorbell.
* @mdrv: pointer to mic_driver
* @db: The doorbell obtained for which the irq is needed. Doorbell
* may correspond to an sbox doorbell or an rdmasr index.
*
* Returns the irq corresponding to the doorbell.
*/
int mic_db_to_irq(struct mic_driver *mdrv, int db)
{
int rdmasr_index;
/*
* The total number of doorbell interrupts on the card are 16. Indices
* 0-8 falls in the SBOX category and 8-15 fall in the RDMASR category.
*/
if (db < MIC_X100_NUM_SBOX_IRQ) {
return mic_get_sbox_irq(db);
} else {
rdmasr_index = db - MIC_X100_NUM_SBOX_IRQ;
return mic_get_rdmasr_irq(rdmasr_index);
}
}
/*
* mic_card_map - Allocate virtual address for a remote memory region.
* @mdev: pointer to mic_device instance.
* @addr: Remote DMA address.
* @size: Size of the region.
*
* Returns: Virtual address backing the remote memory region.
*/
void __iomem *
mic_card_map(struct mic_device *mdev, dma_addr_t addr, size_t size)
{
return ioremap(addr, size);
}
/*
* mic_card_unmap - Unmap the virtual address for a remote memory region.
* @mdev: pointer to mic_device instance.
* @addr: Virtual address for remote memory region.
*
* Returns: None.
*/
void mic_card_unmap(struct mic_device *mdev, void __iomem *addr)
{
iounmap(addr);
}
static inline struct mic_driver *mbdev_to_mdrv(struct mbus_device *mbdev)
{
return dev_get_drvdata(mbdev->dev.parent);
}
static struct mic_irq *
_mic_request_threaded_irq(struct mbus_device *mbdev,
irq_handler_t handler, irq_handler_t thread_fn,
const char *name, void *data, int intr_src)
{
int rc = 0;
unsigned int irq = intr_src;
unsigned long cookie = irq;
rc = request_threaded_irq(irq, handler, thread_fn, 0, name, data);
if (rc) {
dev_err(mbdev_to_mdrv(mbdev)->dev,
"request_threaded_irq failed rc = %d\n", rc);
return ERR_PTR(rc);
}
return (struct mic_irq *)cookie;
}
static void _mic_free_irq(struct mbus_device *mbdev,
struct mic_irq *cookie, void *data)
{
unsigned long irq = (unsigned long)cookie;
free_irq(irq, data);
}
static void _mic_ack_interrupt(struct mbus_device *mbdev, int num)
{
mic_ack_interrupt(&mbdev_to_mdrv(mbdev)->mdev);
}
static struct mbus_hw_ops mbus_hw_ops = {
.request_threaded_irq = _mic_request_threaded_irq,
.free_irq = _mic_free_irq,
.ack_interrupt = _mic_ack_interrupt,
};
static int __init mic_probe(struct platform_device *pdev)
{
struct mic_driver *mdrv = &g_drv;
struct mic_device *mdev = &mdrv->mdev;
int rc = 0;
mdrv->dev = &pdev->dev;
snprintf(mdrv->name, sizeof(mic_driver_name), mic_driver_name);
/* FIXME: use dma_set_mask_and_coherent() and check result */
dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
mdev->mmio.pa = MIC_X100_MMIO_BASE;
mdev->mmio.len = MIC_X100_MMIO_LEN;
mdev->mmio.va = devm_ioremap(&pdev->dev, MIC_X100_MMIO_BASE,
MIC_X100_MMIO_LEN);
if (!mdev->mmio.va) {
dev_err(&pdev->dev, "Cannot remap MMIO BAR\n");
rc = -EIO;
goto done;
}
mic_hw_intr_init(mdrv);
platform_set_drvdata(pdev, mdrv);
mdrv->dma_mbdev = mbus_register_device(mdrv->dev, MBUS_DEV_DMA_MIC,
NULL, &mbus_hw_ops, 0,
mdrv->mdev.mmio.va);
if (IS_ERR(mdrv->dma_mbdev)) {
rc = PTR_ERR(mdrv->dma_mbdev);
dev_err(&pdev->dev, "mbus_add_device failed rc %d\n", rc);
goto done;
}
rc = mic_driver_init(mdrv);
if (rc) {
dev_err(&pdev->dev, "mic_driver_init failed rc %d\n", rc);
goto remove_dma;
}
done:
return rc;
remove_dma:
mbus_unregister_device(mdrv->dma_mbdev);
return rc;
}
static int mic_remove(struct platform_device *pdev)
{
struct mic_driver *mdrv = &g_drv;
mic_driver_uninit(mdrv);
mbus_unregister_device(mdrv->dma_mbdev);
return 0;
}
static void mic_platform_shutdown(struct platform_device *pdev)
{
mic_remove(pdev);
}
static struct platform_driver __refdata mic_platform_driver = {
.probe = mic_probe,
.remove = mic_remove,
.shutdown = mic_platform_shutdown,
.driver = {
.name = mic_driver_name,
},
};
static struct platform_device *mic_platform_dev;
static int __init mic_init(void)
{
int ret;
struct cpuinfo_x86 *c = &cpu_data(0);
if (!(c->x86 == 11 && c->x86_model == 1)) {
ret = -ENODEV;
pr_err("%s not running on X100 ret %d\n", __func__, ret);
goto done;
}
request_module("mic_x100_dma");
mic_init_card_debugfs();
mic_platform_dev = platform_device_register_simple(mic_driver_name,
0, NULL, 0);
ret = PTR_ERR_OR_ZERO(mic_platform_dev);
if (ret) {
pr_err("platform_device_register_full ret %d\n", ret);
goto cleanup_debugfs;
}
ret = platform_driver_register(&mic_platform_driver);
if (ret) {
pr_err("platform_driver_register ret %d\n", ret);
goto device_unregister;
}
return ret;
device_unregister:
platform_device_unregister(mic_platform_dev);
cleanup_debugfs:
mic_exit_card_debugfs();
done:
return ret;
}
static void __exit mic_exit(void)
{
platform_driver_unregister(&mic_platform_driver);
platform_device_unregister(mic_platform_dev);
mic_exit_card_debugfs();
}
module_init(mic_init);
module_exit(mic_exit);
MODULE_AUTHOR("Intel Corporation");
MODULE_DESCRIPTION("Intel(R) MIC X100 Card driver");
MODULE_LICENSE("GPL v2");
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Intel MIC Platform Software Stack (MPSS)
*
* Copyright(c) 2013 Intel Corporation.
*
* Disclaimer: The codes contained in these modules may be specific to
* the Intel Software Development Platform codenamed: Knights Ferry, and
* the Intel product codenamed: Knights Corner, and are not backward
* compatible with other Intel products. Additionally, Intel will NOT
* support the codes or instruction set in future products.
*
* Intel MIC Card driver.
*/
#ifndef _MIC_X100_CARD_H_
#define _MIC_X100_CARD_H_
#define MIC_X100_MMIO_BASE 0x08007C0000ULL
#define MIC_X100_MMIO_LEN 0x00020000ULL
#define MIC_X100_SBOX_BASE_ADDRESS 0x00010000ULL
#define MIC_X100_SBOX_SPAD0 0x0000AB20
#define MIC_X100_SBOX_SDBIC0 0x0000CC90
#define MIC_X100_SBOX_SDBIC0_DBREQ_BIT 0x80000000
#define MIC_X100_SBOX_RDMASR0 0x0000B180
#define MIC_X100_SBOX_APICICR0 0x0000A9D0
#define MIC_X100_MAX_DOORBELL_IDX 8
#define MIC_X100_NUM_SBOX_IRQ 8
#define MIC_X100_NUM_RDMASR_IRQ 8
#define MIC_X100_SBOX_IRQ_BASE 0
#define MIC_X100_RDMASR_IRQ_BASE 17
#define MIC_X100_IRQ_BASE 26
#endif
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Intel MIC Platform Software Stack (MPSS)
*
* Copyright(c) 2013 Intel Corporation.
*
* Intel MIC driver.
*/
#ifndef __MIC_DEV_H__
#define __MIC_DEV_H__
/* The maximum number of MIC devices supported in a single host system. */
#define MIC_MAX_NUM_DEVS 128
/**
* enum mic_hw_family - The hardware family to which a device belongs.
*/
enum mic_hw_family {
MIC_FAMILY_X100 = 0,
MIC_FAMILY_X200,
MIC_FAMILY_UNKNOWN,
MIC_FAMILY_LAST
};
/**
* struct mic_mw - MIC memory window
*
* @pa: Base physical address.
* @va: Base ioremap'd virtual address.
* @len: Size of the memory window.
*/
struct mic_mw {
phys_addr_t pa;
void __iomem *va;
resource_size_t len;
};
/*
* Scratch pad register offsets used by the host to communicate
* device page DMA address to the card.
*/
#define MIC_DPLO_SPAD 14
#define MIC_DPHI_SPAD 15
/*
* These values are supposed to be in the config_change field of the
* device page when the host sends a config change interrupt to the card.
*/
#define MIC_VIRTIO_PARAM_DEV_REMOVE 0x1
#define MIC_VIRTIO_PARAM_CONFIG_CHANGED 0x2
/* Maximum number of DMA channels */
#define MIC_MAX_DMA_CHAN 4
#endif
# SPDX-License-Identifier: GPL-2.0
#
# Makefile - Intel MIC Coprocessor State Management (COSM) Driver
# Copyright(c) 2015, Intel Corporation.
#
obj-$(CONFIG_MIC_COSM) += mic_cosm.o
mic_cosm-objs := cosm_main.o
mic_cosm-objs += cosm_debugfs.o
mic_cosm-objs += cosm_sysfs.o
mic_cosm-objs += cosm_scif_server.o
// SPDX-License-Identifier: GPL-2.0-only
/*
* Intel MIC Platform Software Stack (MPSS)
*
* Copyright(c) 2015 Intel Corporation.
*
* Intel MIC Coprocessor State Management (COSM) Driver
*/
#include <linux/debugfs.h>
#include <linux/slab.h>
#include <linux/io.h>
#include "cosm_main.h"
/* Debugfs parent dir */
static struct dentry *cosm_dbg;
/*
* log_buf_show - Display MIC kernel log buffer
*
* log_buf addr/len is read from System.map by user space
* and populated in sysfs entries.
*/
static int log_buf_show(struct seq_file *s, void *unused)
{
void __iomem *log_buf_va;
int __iomem *log_buf_len_va;
struct cosm_device *cdev = s->private;
void *kva;
int size;
u64 aper_offset;
if (!cdev || !cdev->log_buf_addr || !cdev->log_buf_len)
goto done;
mutex_lock(&cdev->cosm_mutex);
switch (cdev->state) {
case MIC_BOOTING:
case MIC_ONLINE:
case MIC_SHUTTING_DOWN:
break;
default:
goto unlock;
}
/*
* Card kernel will never be relocated and any kernel text/data mapping
* can be translated to phys address by subtracting __START_KERNEL_map.
*/
aper_offset = (u64)cdev->log_buf_len - __START_KERNEL_map;
log_buf_len_va = cdev->hw_ops->aper(cdev)->va + aper_offset;
aper_offset = (u64)cdev->log_buf_addr - __START_KERNEL_map;
log_buf_va = cdev->hw_ops->aper(cdev)->va + aper_offset;
size = ioread32(log_buf_len_va);
kva = kmalloc(size, GFP_KERNEL);
if (!kva)
goto unlock;
memcpy_fromio(kva, log_buf_va, size);
seq_write(s, kva, size);
kfree(kva);
unlock:
mutex_unlock(&cdev->cosm_mutex);
done:
return 0;
}
DEFINE_SHOW_ATTRIBUTE(log_buf);
/*
* force_reset_show - Force MIC reset
*
* Invokes the force_reset COSM bus op instead of the standard reset
* op in case a force reset of the MIC device is required
*/
static int force_reset_show(struct seq_file *s, void *pos)
{
struct cosm_device *cdev = s->private;
cosm_stop(cdev, true);
return 0;
}
DEFINE_SHOW_ATTRIBUTE(force_reset);
void cosm_create_debug_dir(struct cosm_device *cdev)
{
char name[16];
if (!cosm_dbg)
return;
scnprintf(name, sizeof(name), "mic%d", cdev->index);
cdev->dbg_dir = debugfs_create_dir(name, cosm_dbg);
debugfs_create_file("log_buf", 0444, cdev->dbg_dir, cdev,
&log_buf_fops);
debugfs_create_file("force_reset", 0444, cdev->dbg_dir, cdev,
&force_reset_fops);
}
void cosm_delete_debug_dir(struct cosm_device *cdev)
{
debugfs_remove_recursive(cdev->dbg_dir);
}
void cosm_init_debugfs(void)
{
cosm_dbg = debugfs_create_dir(KBUILD_MODNAME, NULL);
}
void cosm_exit_debugfs(void)
{
debugfs_remove(cosm_dbg);
}
// SPDX-License-Identifier: GPL-2.0-only
/*
* Intel MIC Platform Software Stack (MPSS)
*
* Copyright(c) 2015 Intel Corporation.
*
* Intel MIC Coprocessor State Management (COSM) Driver
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/idr.h>
#include <linux/slab.h>
#include <linux/cred.h>
#include "cosm_main.h"
static const char cosm_driver_name[] = "mic";
/* COSM ID allocator */
static struct ida g_cosm_ida;
/* Class of MIC devices for sysfs accessibility. */
static struct class *g_cosm_class;
/* Number of MIC devices */
static atomic_t g_num_dev;
/**
* cosm_hw_reset - Issue a HW reset for the MIC device
* @cdev: pointer to cosm_device instance
* @force: force a MIC to reset even if it is already reset and ready
*/
static void cosm_hw_reset(struct cosm_device *cdev, bool force)
{
int i;
#define MIC_RESET_TO (45)
if (force && cdev->hw_ops->force_reset)
cdev->hw_ops->force_reset(cdev);
else
cdev->hw_ops->reset(cdev);
for (i = 0; i < MIC_RESET_TO; i++) {
if (cdev->hw_ops->ready(cdev)) {
cosm_set_state(cdev, MIC_READY);
return;
}
/*
* Resets typically take 10s of seconds to complete.
* Since an MMIO read is required to check if the
* firmware is ready or not, a 1 second delay works nicely.
*/
msleep(1000);
}
cosm_set_state(cdev, MIC_RESET_FAILED);
}
/**
* cosm_start - Start the MIC
* @cdev: pointer to cosm_device instance
*
* This function prepares an MIC for boot and initiates boot.
* RETURNS: An appropriate -ERRNO error value on error, or 0 for success.
*/
int cosm_start(struct cosm_device *cdev)
{
const struct cred *orig_cred;
struct cred *override_cred;
int rc;
mutex_lock(&cdev->cosm_mutex);
if (!cdev->bootmode) {
dev_err(&cdev->dev, "%s %d bootmode not set\n",
__func__, __LINE__);
rc = -EINVAL;
goto unlock_ret;
}
retry:
if (cdev->state != MIC_READY) {
dev_err(&cdev->dev, "%s %d MIC state not READY\n",
__func__, __LINE__);
rc = -EINVAL;
goto unlock_ret;
}
if (!cdev->hw_ops->ready(cdev)) {
cosm_hw_reset(cdev, false);
/*
* The state will either be MIC_READY if the reset succeeded
* or MIC_RESET_FAILED if the firmware reset failed.
*/
goto retry;
}
/*
* Set credentials to root to allow non-root user to download initramsfs
* with 600 permissions
*/
override_cred = prepare_creds();
if (!override_cred) {
dev_err(&cdev->dev, "%s %d prepare_creds failed\n",
__func__, __LINE__);
rc = -ENOMEM;
goto unlock_ret;
}
override_cred->fsuid = GLOBAL_ROOT_UID;
orig_cred = override_creds(override_cred);
rc = cdev->hw_ops->start(cdev, cdev->index);
revert_creds(orig_cred);
put_cred(override_cred);
if (rc)
goto unlock_ret;
/*
* If linux is being booted, card is treated 'online' only
* when the scif interface in the card is up. If anything else
* is booted, we set card to 'online' immediately.
*/
if (!strcmp(cdev->bootmode, "linux"))
cosm_set_state(cdev, MIC_BOOTING);
else
cosm_set_state(cdev, MIC_ONLINE);
unlock_ret:
mutex_unlock(&cdev->cosm_mutex);
if (rc)
dev_err(&cdev->dev, "cosm_start failed rc %d\n", rc);
return rc;
}
/**
* cosm_stop - Prepare the MIC for reset and trigger reset
* @cdev: pointer to cosm_device instance
* @force: force a MIC to reset even if it is already reset and ready.
*
* RETURNS: None
*/
void cosm_stop(struct cosm_device *cdev, bool force)
{
mutex_lock(&cdev->cosm_mutex);
if (cdev->state != MIC_READY || force) {
/*
* Don't call hw_ops if they have been called previously.
* stop(..) calls device_unregister and will crash the system if
* called multiple times.
*/
u8 state = cdev->state == MIC_RESETTING ?
cdev->prev_state : cdev->state;
bool call_hw_ops = state != MIC_RESET_FAILED &&
state != MIC_READY;
if (cdev->state != MIC_RESETTING)
cosm_set_state(cdev, MIC_RESETTING);
cdev->heartbeat_watchdog_enable = false;
if (call_hw_ops)
cdev->hw_ops->stop(cdev, force);
cosm_hw_reset(cdev, force);
cosm_set_shutdown_status(cdev, MIC_NOP);
if (call_hw_ops && cdev->hw_ops->post_reset)
cdev->hw_ops->post_reset(cdev, cdev->state);
}
mutex_unlock(&cdev->cosm_mutex);
flush_work(&cdev->scif_work);
}
/**
* cosm_reset_trigger_work - Trigger MIC reset
* @work: The work structure
*
* This work is scheduled whenever the host wants to reset the MIC.
*/
static void cosm_reset_trigger_work(struct work_struct *work)
{
struct cosm_device *cdev = container_of(work, struct cosm_device,
reset_trigger_work);
cosm_stop(cdev, false);
}
/**
* cosm_reset - Schedule MIC reset
* @cdev: pointer to cosm_device instance
*
* RETURNS: An -EINVAL if the card is already READY or 0 for success.
*/
int cosm_reset(struct cosm_device *cdev)
{
int rc = 0;
mutex_lock(&cdev->cosm_mutex);
if (cdev->state != MIC_READY) {
if (cdev->state != MIC_RESETTING) {
cdev->prev_state = cdev->state;
cosm_set_state(cdev, MIC_RESETTING);
schedule_work(&cdev->reset_trigger_work);
}
} else {
dev_err(&cdev->dev, "%s %d MIC is READY\n", __func__, __LINE__);
rc = -EINVAL;
}
mutex_unlock(&cdev->cosm_mutex);
return rc;
}
/**
* cosm_shutdown - Initiate MIC shutdown.
* @cdev: pointer to cosm_device instance
*
* RETURNS: None
*/
int cosm_shutdown(struct cosm_device *cdev)
{
struct cosm_msg msg = { .id = COSM_MSG_SHUTDOWN };
int rc = 0;
mutex_lock(&cdev->cosm_mutex);
if (cdev->state != MIC_ONLINE) {
rc = -EINVAL;
dev_err(&cdev->dev, "%s %d skipping shutdown in state: %s\n",
__func__, __LINE__, cosm_state_string[cdev->state]);
goto err;
}
if (!cdev->epd) {
rc = -ENOTCONN;
dev_err(&cdev->dev, "%s %d scif endpoint not connected rc %d\n",
__func__, __LINE__, rc);
goto err;
}
rc = scif_send(cdev->epd, &msg, sizeof(msg), SCIF_SEND_BLOCK);
if (rc < 0) {
dev_err(&cdev->dev, "%s %d scif_send failed rc %d\n",
__func__, __LINE__, rc);
goto err;
}
cdev->heartbeat_watchdog_enable = false;
cosm_set_state(cdev, MIC_SHUTTING_DOWN);
rc = 0;
err:
mutex_unlock(&cdev->cosm_mutex);
return rc;
}
static int cosm_driver_probe(struct cosm_device *cdev)
{
int rc;
/* Initialize SCIF server at first probe */
if (atomic_add_return(1, &g_num_dev) == 1) {
rc = cosm_scif_init();
if (rc)
goto scif_exit;
}
mutex_init(&cdev->cosm_mutex);
INIT_WORK(&cdev->reset_trigger_work, cosm_reset_trigger_work);
INIT_WORK(&cdev->scif_work, cosm_scif_work);
cdev->sysfs_heartbeat_enable = true;
cosm_sysfs_init(cdev);
cdev->sdev = device_create_with_groups(g_cosm_class, cdev->dev.parent,
MKDEV(0, cdev->index), cdev, cdev->attr_group,
"mic%d", cdev->index);
if (IS_ERR(cdev->sdev)) {
rc = PTR_ERR(cdev->sdev);
dev_err(&cdev->dev, "device_create_with_groups failed rc %d\n",
rc);
goto scif_exit;
}
cdev->state_sysfs = sysfs_get_dirent(cdev->sdev->kobj.sd,
"state");
if (!cdev->state_sysfs) {
rc = -ENODEV;
dev_err(&cdev->dev, "sysfs_get_dirent failed rc %d\n", rc);
goto destroy_device;
}
cosm_create_debug_dir(cdev);
return 0;
destroy_device:
device_destroy(g_cosm_class, MKDEV(0, cdev->index));
scif_exit:
if (atomic_dec_and_test(&g_num_dev))
cosm_scif_exit();
return rc;
}
static void cosm_driver_remove(struct cosm_device *cdev)
{
cosm_delete_debug_dir(cdev);
sysfs_put(cdev->state_sysfs);
device_destroy(g_cosm_class, MKDEV(0, cdev->index));
flush_work(&cdev->reset_trigger_work);
cosm_stop(cdev, false);
if (atomic_dec_and_test(&g_num_dev))
cosm_scif_exit();
/* These sysfs entries might have allocated */
kfree(cdev->cmdline);
kfree(cdev->firmware);
kfree(cdev->ramdisk);
kfree(cdev->bootmode);
}
static int cosm_suspend(struct device *dev)
{
struct cosm_device *cdev = dev_to_cosm(dev);
mutex_lock(&cdev->cosm_mutex);
switch (cdev->state) {
/**
* Suspend/freeze hooks in userspace have already shutdown the card.
* Card should be 'ready' in most cases. It is however possible that
* some userspace application initiated a boot. In those cases, we
* simply reset the card.
*/
case MIC_ONLINE:
case MIC_BOOTING:
case MIC_SHUTTING_DOWN:
mutex_unlock(&cdev->cosm_mutex);
cosm_stop(cdev, false);
break;
default:
mutex_unlock(&cdev->cosm_mutex);
break;
}
return 0;
}
static const struct dev_pm_ops cosm_pm_ops = {
.suspend = cosm_suspend,
.freeze = cosm_suspend
};
static struct cosm_driver cosm_driver = {
.driver = {
.name = KBUILD_MODNAME,
.owner = THIS_MODULE,
.pm = &cosm_pm_ops,
},
.probe = cosm_driver_probe,
.remove = cosm_driver_remove
};
static int __init cosm_init(void)
{
int ret;
cosm_init_debugfs();
g_cosm_class = class_create(THIS_MODULE, cosm_driver_name);
if (IS_ERR(g_cosm_class)) {
ret = PTR_ERR(g_cosm_class);
pr_err("class_create failed ret %d\n", ret);
goto cleanup_debugfs;
}
ida_init(&g_cosm_ida);
ret = cosm_register_driver(&cosm_driver);
if (ret) {
pr_err("cosm_register_driver failed ret %d\n", ret);
goto ida_destroy;
}
return 0;
ida_destroy:
ida_destroy(&g_cosm_ida);
class_destroy(g_cosm_class);
cleanup_debugfs:
cosm_exit_debugfs();
return ret;
}
static void __exit cosm_exit(void)
{
cosm_unregister_driver(&cosm_driver);
ida_destroy(&g_cosm_ida);
class_destroy(g_cosm_class);
cosm_exit_debugfs();
}
module_init(cosm_init);
module_exit(cosm_exit);
MODULE_AUTHOR("Intel Corporation");
MODULE_DESCRIPTION("Intel(R) MIC Coprocessor State Management (COSM) Driver");
MODULE_LICENSE("GPL v2");
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Intel MIC Platform Software Stack (MPSS)
*
* Copyright(c) 2015 Intel Corporation.
*
* Intel MIC Coprocessor State Management (COSM) Driver
*/
#ifndef _COSM_COSM_H_
#define _COSM_COSM_H_
#include <linux/scif.h>
#include "../bus/cosm_bus.h"
#define COSM_HEARTBEAT_SEND_SEC 30
#define SCIF_COSM_LISTEN_PORT 201
/**
* enum COSM msg id's
* @COSM_MSG_SHUTDOWN: host->card trigger shutdown
* @COSM_MSG_SYNC_TIME: host->card send host time to card to sync time
* @COSM_MSG_HEARTBEAT: card->host heartbeat
* @COSM_MSG_SHUTDOWN_STATUS: card->host with shutdown status as payload
*/
enum cosm_msg_id {
COSM_MSG_SHUTDOWN,
COSM_MSG_SYNC_TIME,
COSM_MSG_HEARTBEAT,
COSM_MSG_SHUTDOWN_STATUS,
};
struct cosm_msg {
u64 id;
union {
u64 shutdown_status;
struct {
u64 tv_sec;
u64 tv_nsec;
} timespec;
};
};
extern const char * const cosm_state_string[];
extern const char * const cosm_shutdown_status_string[];
void cosm_sysfs_init(struct cosm_device *cdev);
int cosm_start(struct cosm_device *cdev);
void cosm_stop(struct cosm_device *cdev, bool force);
int cosm_reset(struct cosm_device *cdev);
int cosm_shutdown(struct cosm_device *cdev);
void cosm_set_state(struct cosm_device *cdev, u8 state);
void cosm_set_shutdown_status(struct cosm_device *cdev, u8 status);
void cosm_init_debugfs(void);
void cosm_exit_debugfs(void);
void cosm_create_debug_dir(struct cosm_device *cdev);
void cosm_delete_debug_dir(struct cosm_device *cdev);
int cosm_scif_init(void);
void cosm_scif_exit(void);
void cosm_scif_work(struct work_struct *work);
#endif
This diff is collapsed.
This diff is collapsed.
# SPDX-License-Identifier: GPL-2.0-only
#
# Makefile - Intel MIC COSM Client Driver
# Copyright(c) 2015, Intel Corporation.
#
obj-$(CONFIG_MIC_COSM) += cosm_client.o
cosm_client-objs += cosm_scif_client.o
This diff is collapsed.
# SPDX-License-Identifier: GPL-2.0
#
# Makefile - Intel MIC Linux driver.
# Copyright(c) 2013, Intel Corporation.
#
obj-$(CONFIG_INTEL_MIC_HOST) += mic_host.o
mic_host-objs := mic_main.o
mic_host-objs += mic_x100.o
mic_host-objs += mic_smpt.o
mic_host-objs += mic_intr.o
mic_host-objs += mic_boot.o
mic_host-objs += mic_debugfs.o
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0-only
/*
* Intel MIC Platform Software Stack (MPSS)
*
* Copyright(c) 2013 Intel Corporation.
*
* Intel MIC Host driver.
*/
#include <linux/debugfs.h>
#include <linux/pci.h>
#include <linux/seq_file.h>
#include <linux/mic_common.h>
#include "../common/mic_dev.h"
#include "mic_device.h"
#include "mic_smpt.h"
/* Debugfs parent dir */
static struct dentry *mic_dbg;
static int mic_smpt_show(struct seq_file *s, void *pos)
{
int i;
struct mic_device *mdev = s->private;
unsigned long flags;
seq_printf(s, "MIC %-2d |%-10s| %-14s %-10s\n",
mdev->id, "SMPT entry", "SW DMA addr", "RefCount");
seq_puts(s, "====================================================\n");
if (mdev->smpt) {
struct mic_smpt_info *smpt_info = mdev->smpt;
spin_lock_irqsave(&smpt_info->smpt_lock, flags);
for (i = 0; i < smpt_info->info.num_reg; i++) {
seq_printf(s, "%9s|%-10d| %-#14llx %-10lld\n",
" ", i, smpt_info->entry[i].dma_addr,
smpt_info->entry[i].ref_count);
}
spin_unlock_irqrestore(&smpt_info->smpt_lock, flags);
}
seq_puts(s, "====================================================\n");
return 0;
}
DEFINE_SHOW_ATTRIBUTE(mic_smpt);
static int mic_post_code_show(struct seq_file *s, void *pos)
{
struct mic_device *mdev = s->private;
u32 reg = mdev->ops->get_postcode(mdev);
seq_printf(s, "%c%c", reg & 0xff, (reg >> 8) & 0xff);
return 0;
}
DEFINE_SHOW_ATTRIBUTE(mic_post_code);
static int mic_msi_irq_info_show(struct seq_file *s, void *pos)
{
struct mic_device *mdev = s->private;
int reg;
int i, j;
u16 entry;
u16 vector;
struct pci_dev *pdev = mdev->pdev;
if (pci_dev_msi_enabled(pdev)) {
for (i = 0; i < mdev->irq_info.num_vectors; i++) {
if (pdev->msix_enabled) {
entry = mdev->irq_info.msix_entries[i].entry;
vector = mdev->irq_info.msix_entries[i].vector;
} else {
entry = 0;
vector = pdev->irq;
}
reg = mdev->intr_ops->read_msi_to_src_map(mdev, entry);
seq_printf(s, "%s %-10d %s %-10d MXAR[%d]: %08X\n",
"IRQ:", vector, "Entry:", entry, i, reg);
seq_printf(s, "%-10s", "offset:");
for (j = (MIC_NUM_OFFSETS - 1); j >= 0; j--)
seq_printf(s, "%4d ", j);
seq_puts(s, "\n");
seq_printf(s, "%-10s", "count:");
for (j = (MIC_NUM_OFFSETS - 1); j >= 0; j--)
seq_printf(s, "%4d ",
(mdev->irq_info.mic_msi_map[i] &
BIT(j)) ? 1 : 0);
seq_puts(s, "\n\n");
}
} else {
seq_puts(s, "MSI/MSIx interrupts not enabled\n");
}
return 0;
}
DEFINE_SHOW_ATTRIBUTE(mic_msi_irq_info);
/*
* mic_create_debug_dir - Initialize MIC debugfs entries.
*/
void mic_create_debug_dir(struct mic_device *mdev)
{
char name[16];
if (!mic_dbg)
return;
scnprintf(name, sizeof(name), "mic%d", mdev->id);
mdev->dbg_dir = debugfs_create_dir(name, mic_dbg);
debugfs_create_file("smpt", 0444, mdev->dbg_dir, mdev,
&mic_smpt_fops);
debugfs_create_file("post_code", 0444, mdev->dbg_dir, mdev,
&mic_post_code_fops);
debugfs_create_file("msi_irq_info", 0444, mdev->dbg_dir, mdev,
&mic_msi_irq_info_fops);
}
/*
* mic_delete_debug_dir - Uninitialize MIC debugfs entries.
*/
void mic_delete_debug_dir(struct mic_device *mdev)
{
debugfs_remove_recursive(mdev->dbg_dir);
}
/*
* mic_init_debugfs - Initialize global debugfs entry.
*/
void __init mic_init_debugfs(void)
{
mic_dbg = debugfs_create_dir(KBUILD_MODNAME, NULL);
}
/*
* mic_exit_debugfs - Uninitialize global debugfs entry
*/
void mic_exit_debugfs(void)
{
debugfs_remove(mic_dbg);
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
# SPDX-License-Identifier: GPL-2.0
#
# Makefile - SCIF driver.
# Copyright(c) 2014, Intel Corporation.
#
obj-$(CONFIG_SCIF) += scif.o
scif-objs := scif_main.o
scif-objs += scif_peer_bus.o
scif-objs += scif_ports.o
scif-objs += scif_debugfs.o
scif-objs += scif_fd.o
scif-objs += scif_api.o
scif-objs += scif_epd.o
scif-objs += scif_rb.o
scif-objs += scif_nodeqp.o
scif-objs += scif_nm.o
scif-objs += scif_dma.o
scif-objs += scif_fence.o
scif-objs += scif_mmap.o
scif-objs += scif_rma.o
scif-objs += scif_rma_list.o
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
# SPDX-License-Identifier: GPL-2.0-only
#
# Makefile - Intel MIC Linux driver.
# Copyright(c) 2016, Intel Corporation.
#
obj-$(CONFIG_VOP) := vop.o
vop-objs += vop_main.o
vop-objs += vop_debugfs.o
vop-objs += vop_vringh.o
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
# SPDX-License-Identifier: GPL-2.0-only
mpssd
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment