Merge branch 'pci/peer-to-peer'
- Add PCI support for peer-to-peer DMA (Logan Gunthorpe) - Add sysfs group for PCI peer-to-peer memory statistics (Logan Gunthorpe) - Add PCI peer-to-peer DMA scatterlist mapping interface (Logan Gunthorpe) - Add PCI configfs/sysfs helpers for use by peer-to-peer users (Logan Gunthorpe) - Add PCI peer-to-peer DMA driver writer's documentation (Logan Gunthorpe) - Add block layer flag to indicate driver support for PCI peer-to-peer DMA (Logan Gunthorpe) - Map Infiniband scatterlists for peer-to-peer DMA if they contain P2P memory (Logan Gunthorpe) - Register nvme-pci CMB buffer as PCI peer-to-peer memory (Logan Gunthorpe) - Add nvme-pci support for PCI peer-to-peer memory in requests (Logan Gunthorpe) - Use PCI peer-to-peer memory in nvme (Stephen Bates, Steve Wise, Christoph Hellwig, Logan Gunthorpe) * pci/peer-to-peer: nvmet: Optionally use PCI P2P memory nvmet: Introduce helper functions to allocate and free request SGLs nvme-pci: Add support for P2P memory in requests nvme-pci: Use PCI p2pmem subsystem to manage the CMB IB/core: Ensure we map P2P memory correctly in rdma_rw_ctx_[init|destroy]() block: Add PCI P2P flag for request queue PCI/P2PDMA: Add P2P DMA driver writer's documentation docs-rst: Add a new directory for PCI documentation PCI/P2PDMA: Introduce configfs/sysfs enable attribute helpers PCI/P2PDMA: Add PCI p2pmem DMA mappings to adjust the bus offset PCI/P2PDMA: Add sysfs group to display p2pmem stats PCI/P2PDMA: Support peer-to-peer memory
This commit is contained in:
@@ -699,6 +699,7 @@ struct request_queue {
|
||||
#define QUEUE_FLAG_SCSI_PASSTHROUGH 27 /* queue supports SCSI commands */
|
||||
#define QUEUE_FLAG_QUIESCED 28 /* queue has been quiesced */
|
||||
#define QUEUE_FLAG_PREEMPT_ONLY 29 /* only process REQ_PREEMPT requests */
|
||||
#define QUEUE_FLAG_PCI_P2PDMA 30 /* device supports PCI p2p requests */
|
||||
|
||||
#define QUEUE_FLAG_DEFAULT ((1 << QUEUE_FLAG_IO_STAT) | \
|
||||
(1 << QUEUE_FLAG_SAME_COMP) | \
|
||||
@@ -731,6 +732,8 @@ bool blk_queue_flag_test_and_clear(unsigned int flag, struct request_queue *q);
|
||||
#define blk_queue_dax(q) test_bit(QUEUE_FLAG_DAX, &(q)->queue_flags)
|
||||
#define blk_queue_scsi_passthrough(q) \
|
||||
test_bit(QUEUE_FLAG_SCSI_PASSTHROUGH, &(q)->queue_flags)
|
||||
#define blk_queue_pci_p2pdma(q) \
|
||||
test_bit(QUEUE_FLAG_PCI_P2PDMA, &(q)->queue_flags)
|
||||
|
||||
#define blk_noretry_request(rq) \
|
||||
((rq)->cmd_flags & (REQ_FAILFAST_DEV|REQ_FAILFAST_TRANSPORT| \
|
||||
|
@@ -53,11 +53,16 @@ struct vmem_altmap {
|
||||
* wakeup event whenever a page is unpinned and becomes idle. This
|
||||
* wakeup is used to coordinate physical address space management (ex:
|
||||
* fs truncate/hole punch) vs pinned pages (ex: device dma).
|
||||
*
|
||||
* MEMORY_DEVICE_PCI_P2PDMA:
|
||||
* Device memory residing in a PCI BAR intended for use with Peer-to-Peer
|
||||
* transactions.
|
||||
*/
|
||||
enum memory_type {
|
||||
MEMORY_DEVICE_PRIVATE = 1,
|
||||
MEMORY_DEVICE_PUBLIC,
|
||||
MEMORY_DEVICE_FS_DAX,
|
||||
MEMORY_DEVICE_PCI_P2PDMA,
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -120,6 +125,7 @@ struct dev_pagemap {
|
||||
struct device *dev;
|
||||
void *data;
|
||||
enum memory_type type;
|
||||
u64 pci_p2pdma_bus_offset;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ZONE_DEVICE
|
||||
|
@@ -890,6 +890,19 @@ static inline bool is_device_public_page(const struct page *page)
|
||||
page->pgmap->type == MEMORY_DEVICE_PUBLIC;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PCI_P2PDMA
|
||||
static inline bool is_pci_p2pdma_page(const struct page *page)
|
||||
{
|
||||
return is_zone_device_page(page) &&
|
||||
page->pgmap->type == MEMORY_DEVICE_PCI_P2PDMA;
|
||||
}
|
||||
#else /* CONFIG_PCI_P2PDMA */
|
||||
static inline bool is_pci_p2pdma_page(const struct page *page)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif /* CONFIG_PCI_P2PDMA */
|
||||
|
||||
#else /* CONFIG_DEV_PAGEMAP_OPS */
|
||||
static inline void dev_pagemap_get_ops(void)
|
||||
{
|
||||
@@ -913,6 +926,11 @@ static inline bool is_device_public_page(const struct page *page)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool is_pci_p2pdma_page(const struct page *page)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif /* CONFIG_DEV_PAGEMAP_OPS */
|
||||
|
||||
static inline void get_page(struct page *page)
|
||||
|
114
include/linux/pci-p2pdma.h
Normal file
114
include/linux/pci-p2pdma.h
Normal file
@@ -0,0 +1,114 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* PCI Peer 2 Peer DMA support.
|
||||
*
|
||||
* Copyright (c) 2016-2018, Logan Gunthorpe
|
||||
* Copyright (c) 2016-2017, Microsemi Corporation
|
||||
* Copyright (c) 2017, Christoph Hellwig
|
||||
* Copyright (c) 2018, Eideticom Inc.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_PCI_P2PDMA_H
|
||||
#define _LINUX_PCI_P2PDMA_H
|
||||
|
||||
#include <linux/pci.h>
|
||||
|
||||
struct block_device;
|
||||
struct scatterlist;
|
||||
|
||||
#ifdef CONFIG_PCI_P2PDMA
|
||||
int pci_p2pdma_add_resource(struct pci_dev *pdev, int bar, size_t size,
|
||||
u64 offset);
|
||||
int pci_p2pdma_distance_many(struct pci_dev *provider, struct device **clients,
|
||||
int num_clients, bool verbose);
|
||||
bool pci_has_p2pmem(struct pci_dev *pdev);
|
||||
struct pci_dev *pci_p2pmem_find_many(struct device **clients, int num_clients);
|
||||
void *pci_alloc_p2pmem(struct pci_dev *pdev, size_t size);
|
||||
void pci_free_p2pmem(struct pci_dev *pdev, void *addr, size_t size);
|
||||
pci_bus_addr_t pci_p2pmem_virt_to_bus(struct pci_dev *pdev, void *addr);
|
||||
struct scatterlist *pci_p2pmem_alloc_sgl(struct pci_dev *pdev,
|
||||
unsigned int *nents, u32 length);
|
||||
void pci_p2pmem_free_sgl(struct pci_dev *pdev, struct scatterlist *sgl);
|
||||
void pci_p2pmem_publish(struct pci_dev *pdev, bool publish);
|
||||
int pci_p2pdma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
|
||||
enum dma_data_direction dir);
|
||||
int pci_p2pdma_enable_store(const char *page, struct pci_dev **p2p_dev,
|
||||
bool *use_p2pdma);
|
||||
ssize_t pci_p2pdma_enable_show(char *page, struct pci_dev *p2p_dev,
|
||||
bool use_p2pdma);
|
||||
#else /* CONFIG_PCI_P2PDMA */
|
||||
static inline int pci_p2pdma_add_resource(struct pci_dev *pdev, int bar,
|
||||
size_t size, u64 offset)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
static inline int pci_p2pdma_distance_many(struct pci_dev *provider,
|
||||
struct device **clients, int num_clients, bool verbose)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
static inline bool pci_has_p2pmem(struct pci_dev *pdev)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
static inline struct pci_dev *pci_p2pmem_find_many(struct device **clients,
|
||||
int num_clients)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
static inline void *pci_alloc_p2pmem(struct pci_dev *pdev, size_t size)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
static inline void pci_free_p2pmem(struct pci_dev *pdev, void *addr,
|
||||
size_t size)
|
||||
{
|
||||
}
|
||||
static inline pci_bus_addr_t pci_p2pmem_virt_to_bus(struct pci_dev *pdev,
|
||||
void *addr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline struct scatterlist *pci_p2pmem_alloc_sgl(struct pci_dev *pdev,
|
||||
unsigned int *nents, u32 length)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
static inline void pci_p2pmem_free_sgl(struct pci_dev *pdev,
|
||||
struct scatterlist *sgl)
|
||||
{
|
||||
}
|
||||
static inline void pci_p2pmem_publish(struct pci_dev *pdev, bool publish)
|
||||
{
|
||||
}
|
||||
static inline int pci_p2pdma_map_sg(struct device *dev,
|
||||
struct scatterlist *sg, int nents, enum dma_data_direction dir)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int pci_p2pdma_enable_store(const char *page,
|
||||
struct pci_dev **p2p_dev, bool *use_p2pdma)
|
||||
{
|
||||
*use_p2pdma = false;
|
||||
return 0;
|
||||
}
|
||||
static inline ssize_t pci_p2pdma_enable_show(char *page,
|
||||
struct pci_dev *p2p_dev, bool use_p2pdma)
|
||||
{
|
||||
return sprintf(page, "none\n");
|
||||
}
|
||||
#endif /* CONFIG_PCI_P2PDMA */
|
||||
|
||||
|
||||
static inline int pci_p2pdma_distance(struct pci_dev *provider,
|
||||
struct device *client, bool verbose)
|
||||
{
|
||||
return pci_p2pdma_distance_many(provider, &client, 1, verbose);
|
||||
}
|
||||
|
||||
static inline struct pci_dev *pci_p2pmem_find(struct device *client)
|
||||
{
|
||||
return pci_p2pmem_find_many(&client, 1);
|
||||
}
|
||||
|
||||
#endif /* _LINUX_PCI_P2P_H */
|
@@ -281,6 +281,7 @@ struct pcie_link_state;
|
||||
struct pci_vpd;
|
||||
struct pci_sriov;
|
||||
struct pci_ats;
|
||||
struct pci_p2pdma;
|
||||
|
||||
/* The pci_dev structure describes PCI devices */
|
||||
struct pci_dev {
|
||||
@@ -440,6 +441,9 @@ struct pci_dev {
|
||||
#endif
|
||||
#ifdef CONFIG_PCI_PASID
|
||||
u16 pasid_features;
|
||||
#endif
|
||||
#ifdef CONFIG_PCI_P2PDMA
|
||||
struct pci_p2pdma *p2pdma;
|
||||
#endif
|
||||
phys_addr_t rom; /* Physical address if not from BAR */
|
||||
size_t romlen; /* Length if not from BAR */
|
||||
|
Reference in New Issue
Block a user