* [Buildroot] [PATCH 21/27] toolchain: introduce BR2_TOOLCHAIN_HAS_GCC_BUG_90620
From: Thomas Petazzoni @ 2019-06-20 16:14 UTC (permalink / raw)
To: buildroot
In-Reply-To: <20190614210346.121013-22-giulio.benetti@micronovasrl.com>
On Fri, 14 Jun 2019 23:03:40 +0200
Giulio Benetti <giulio.benetti@micronovasrl.com> wrote:
> GCC fails on building haproxy for the Microblaze Arch:
> http://autobuild.buildroot.org/results/64706f96db793777de9d3ec63b0a47d776cf33fd/build-end.log
>
> Originally reported for gpsd:
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90620
>
> Fixed on Gcc 8.x but regressed in Gcc 9.x.
>
> Signed-off-by: Giulio Benetti <giulio.benetti@micronovasrl.com>
> ---
> toolchain/Config.in | 8 ++++++++
> 1 file changed, 8 insertions(+)
Applied to master, thanks.
Thomas
--
Thomas Petazzoni, CTO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* [RFC PATCH 26/28] PCI/P2PDMA: Remove SGL helpers
From: Logan Gunthorpe @ 2019-06-20 16:12 UTC (permalink / raw)
To: linux-kernel, linux-block, linux-nvme, linux-pci, linux-rdma
Cc: Jens Axboe, Christoph Hellwig, Bjorn Helgaas, Dan Williams,
Sagi Grimberg, Keith Busch, Jason Gunthorpe, Stephen Bates,
Logan Gunthorpe
In-Reply-To: <20190620161240.22738-1-logang@deltatee.com>
The functions, pci_p2pmem_alloc_sgl(), pci_p2pmem_free_sgl() and
pci_p2pdma_map_sg() no longer have any callers, so remove them.
Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
---
Documentation/driver-api/pci/p2pdma.rst | 9 +--
drivers/pci/p2pdma.c | 95 -------------------------
include/linux/pci-p2pdma.h | 19 -----
3 files changed, 3 insertions(+), 120 deletions(-)
diff --git a/Documentation/driver-api/pci/p2pdma.rst b/Documentation/driver-api/pci/p2pdma.rst
index 44deb52beeb4..5b19c420d921 100644
--- a/Documentation/driver-api/pci/p2pdma.rst
+++ b/Documentation/driver-api/pci/p2pdma.rst
@@ -84,9 +84,8 @@ Client Drivers
--------------
A client driver typically only has to conditionally change its DMA map
-routine to use the mapping function :c:func:`pci_p2pdma_map_sg()` instead
-of the usual :c:func:`dma_map_sg()` function. Memory mapped in this
-way does not need to be unmapped.
+routine to use the PCI bus address with :c:func:`pci_p2pmem_virt_to_bus()`
+for the DMA address instead of the usual :c:func:`dma_map_sg()` function.
The client may also, optionally, make use of
:c:func:`is_pci_p2pdma_page()` to determine when to use the P2P mapping
@@ -117,9 +116,7 @@ returned with pci_dev_put().
Once a provider is selected, the orchestrator can then use
:c:func:`pci_alloc_p2pmem()` and :c:func:`pci_free_p2pmem()` to
-allocate P2P memory from the provider. :c:func:`pci_p2pmem_alloc_sgl()`
-and :c:func:`pci_p2pmem_free_sgl()` are convenience functions for
-allocating scatter-gather lists with P2P memory.
+allocate P2P memory from the provider.
Struct Page Caveats
-------------------
diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c
index a98126ad9c3a..9b82e13f802c 100644
--- a/drivers/pci/p2pdma.c
+++ b/drivers/pci/p2pdma.c
@@ -666,60 +666,6 @@ pci_bus_addr_t pci_p2pmem_virt_to_bus(struct pci_dev *pdev, void *addr)
}
EXPORT_SYMBOL_GPL(pci_p2pmem_virt_to_bus);
-/**
- * pci_p2pmem_alloc_sgl - allocate peer-to-peer DMA memory in a scatterlist
- * @pdev: the device to allocate memory from
- * @nents: the number of SG entries in the list
- * @length: number of bytes to allocate
- *
- * Return: %NULL on error or &struct scatterlist pointer and @nents on success
- */
-struct scatterlist *pci_p2pmem_alloc_sgl(struct pci_dev *pdev,
- unsigned int *nents, u32 length)
-{
- struct scatterlist *sg;
- void *addr;
-
- sg = kzalloc(sizeof(*sg), GFP_KERNEL);
- if (!sg)
- return NULL;
-
- sg_init_table(sg, 1);
-
- addr = pci_alloc_p2pmem(pdev, length);
- if (!addr)
- goto out_free_sg;
-
- sg_set_buf(sg, addr, length);
- *nents = 1;
- return sg;
-
-out_free_sg:
- kfree(sg);
- return NULL;
-}
-EXPORT_SYMBOL_GPL(pci_p2pmem_alloc_sgl);
-
-/**
- * pci_p2pmem_free_sgl - free a scatterlist allocated by pci_p2pmem_alloc_sgl()
- * @pdev: the device to allocate memory from
- * @sgl: the allocated scatterlist
- */
-void pci_p2pmem_free_sgl(struct pci_dev *pdev, struct scatterlist *sgl)
-{
- struct scatterlist *sg;
- int count;
-
- for_each_sg(sgl, sg, INT_MAX, count) {
- if (!sg)
- break;
-
- pci_free_p2pmem(pdev, sg_virt(sg), sg->length);
- }
- kfree(sgl);
-}
-EXPORT_SYMBOL_GPL(pci_p2pmem_free_sgl);
-
/**
* pci_p2pmem_publish - publish the peer-to-peer DMA memory for use by
* other devices with pci_p2pmem_find()
@@ -738,47 +684,6 @@ void pci_p2pmem_publish(struct pci_dev *pdev, bool publish)
}
EXPORT_SYMBOL_GPL(pci_p2pmem_publish);
-/**
- * pci_p2pdma_map_sg - map a PCI peer-to-peer scatterlist for DMA
- * @dev: device doing the DMA request
- * @sg: scatter list to map
- * @nents: elements in the scatterlist
- * @dir: DMA direction
- *
- * Scatterlists mapped with this function should not be unmapped in any way.
- *
- * Returns the number of SG entries mapped or 0 on error.
- */
-int pci_p2pdma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
- enum dma_data_direction dir)
-{
- struct dev_pagemap *pgmap;
- struct scatterlist *s;
- phys_addr_t paddr;
- int i;
-
- /*
- * p2pdma mappings are not compatible with devices that use
- * dma_virt_ops. If the upper layers do the right thing
- * this should never happen because it will be prevented
- * by the check in pci_p2pdma_add_client()
- */
- if (WARN_ON_ONCE(IS_ENABLED(CONFIG_DMA_VIRT_OPS) &&
- dev->dma_ops == &dma_virt_ops))
- return 0;
-
- for_each_sg(sg, s, nents, i) {
- pgmap = sg_page(s)->pgmap;
- paddr = sg_phys(s);
-
- s->dma_address = paddr - pgmap->pci_p2pdma_bus_offset;
- sg_dma_len(s) = s->length;
- }
-
- return nents;
-}
-EXPORT_SYMBOL_GPL(pci_p2pdma_map_sg);
-
/**
* pci_p2pdma_enable_store - parse a configfs/sysfs attribute store
* to enable p2pdma
diff --git a/include/linux/pci-p2pdma.h b/include/linux/pci-p2pdma.h
index bca9bc3e5be7..4a75a3f43444 100644
--- a/include/linux/pci-p2pdma.h
+++ b/include/linux/pci-p2pdma.h
@@ -26,12 +26,7 @@ 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,
@@ -69,23 +64,9 @@ static inline pci_bus_addr_t pci_p2pmem_virt_to_bus(struct pci_dev *pdev,
{
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)
{
--
2.20.1
^ permalink raw reply related
* [RFC PATCH 11/28] block: Create blk_segment_split_ctx
From: Logan Gunthorpe @ 2019-06-20 16:12 UTC (permalink / raw)
To: linux-kernel, linux-block, linux-nvme, linux-pci, linux-rdma
Cc: Jens Axboe, Christoph Hellwig, Bjorn Helgaas, Dan Williams,
Sagi Grimberg, Keith Busch, Jason Gunthorpe, Stephen Bates,
Logan Gunthorpe
In-Reply-To: <20190620161240.22738-1-logang@deltatee.com>
In order to support dma-direct bios, blk_bio_segment_split() will
need to operate on both bio_vecs and dma_vecs. In order to do
this the code inside bio_for_each_bvec() needs to be moved into
a generic helper. Step one to do this is to put some of the
variables used inside the loop into a context structure so we
don't need to pass a dozen variables to this new function.
Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
---
block/blk-merge.c | 55 ++++++++++++++++++++++++++++++-----------------
1 file changed, 35 insertions(+), 20 deletions(-)
diff --git a/block/blk-merge.c b/block/blk-merge.c
index 3581c7ac3c1b..414e61a714bf 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -201,63 +201,78 @@ static bool bvec_split_segs(struct request_queue *q, struct bio_vec *bv,
sectors, max_segs);
}
+struct blk_segment_split_ctx {
+ unsigned nsegs;
+ unsigned sectors;
+
+ bool prv_valid;
+ struct bio_vec bvprv;
+
+ const unsigned max_sectors;
+ const unsigned max_segs;
+};
+
static struct bio *blk_bio_segment_split(struct request_queue *q,
struct bio *bio,
struct bio_set *bs,
unsigned *segs)
{
- struct bio_vec bv, bvprv, *bvprvp = NULL;
+ struct bio_vec bv;
struct bvec_iter iter;
- unsigned nsegs = 0, sectors = 0;
bool do_split = true;
struct bio *new = NULL;
- const unsigned max_sectors = get_max_io_size(q, bio);
- const unsigned max_segs = queue_max_segments(q);
+
+ struct blk_segment_split_ctx ctx = {
+ .max_sectors = get_max_io_size(q, bio),
+ .max_segs = queue_max_segments(q),
+ };
bio_for_each_bvec(bv, bio, iter) {
/*
* If the queue doesn't support SG gaps and adding this
* offset would create a gap, disallow it.
*/
- if (bvprvp && bvec_gap_to_prev(q, bvprvp, bv.bv_offset))
+ if (ctx.prv_valid && bvec_gap_to_prev(q, &ctx.bvprv,
+ bv.bv_offset))
goto split;
- if (sectors + (bv.bv_len >> 9) > max_sectors) {
+ if (ctx.sectors + (bv.bv_len >> 9) > ctx.max_sectors) {
/*
* Consider this a new segment if we're splitting in
* the middle of this vector.
*/
- if (nsegs < max_segs &&
- sectors < max_sectors) {
+ if (ctx.nsegs < ctx.max_segs &&
+ ctx.sectors < ctx.max_sectors) {
/* split in the middle of bvec */
- bv.bv_len = (max_sectors - sectors) << 9;
- bvec_split_segs(q, &bv, &nsegs,
- §ors, max_segs);
+ bv.bv_len =
+ (ctx.max_sectors - ctx.sectors) << 9;
+ bvec_split_segs(q, &bv, &ctx.nsegs,
+ &ctx.sectors, ctx.max_segs);
}
goto split;
}
- if (nsegs == max_segs)
+ if (ctx.nsegs == ctx.max_segs)
goto split;
- bvprv = bv;
- bvprvp = &bvprv;
+ ctx.bvprv = bv;
+ ctx.prv_valid = true;
if (bv.bv_offset + bv.bv_len <= PAGE_SIZE) {
- nsegs++;
- sectors += bv.bv_len >> 9;
- } else if (bvec_split_segs(q, &bv, &nsegs, §ors,
- max_segs)) {
+ ctx.nsegs++;
+ ctx.sectors += bv.bv_len >> 9;
+ } else if (bvec_split_segs(q, &bv, &ctx.nsegs, &ctx.sectors,
+ ctx.max_segs)) {
goto split;
}
}
do_split = false;
split:
- *segs = nsegs;
+ *segs = ctx.nsegs;
if (do_split) {
- new = bio_split(bio, sectors, GFP_NOIO, bs);
+ new = bio_split(bio, ctx.sectors, GFP_NOIO, bs);
if (new)
bio = new;
}
--
2.20.1
^ permalink raw reply related
* [RFC PATCH 16/28] block: Implement mapping dma-direct requests to SGs in blk_rq_map_sg()
From: Logan Gunthorpe @ 2019-06-20 16:12 UTC (permalink / raw)
To: linux-kernel, linux-block, linux-nvme, linux-pci, linux-rdma
Cc: Jens Axboe, Christoph Hellwig, Bjorn Helgaas, Dan Williams,
Sagi Grimberg, Keith Busch, Jason Gunthorpe, Stephen Bates,
Logan Gunthorpe
In-Reply-To: <20190620161240.22738-1-logang@deltatee.com>
blk_rq_map_sg() just needs to move the dma_vec into the dma_address
of the sgl. Callers will need to ensure not to call dma_map_sg()
for dma-direct requests.
This will likely get less ugly with Christoph's proposed cleanup
to the DMA API. It will be much simpler if devices are just
calling a dma_map_bio() and don't have to worry about dma-direct
requests.
Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
---
block/blk-merge.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 65 insertions(+)
diff --git a/block/blk-merge.c b/block/blk-merge.c
index a7a5453987f9..ccd6c44b9f6e 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -545,6 +545,69 @@ static int __blk_bios_map_sg(struct request_queue *q, struct bio *bio,
return nsegs;
}
+static unsigned blk_dvec_map_sg(struct request_queue *q,
+ struct dma_vec *dvec, struct scatterlist *sglist,
+ struct scatterlist **sg)
+{
+ unsigned nbytes = dvec->dv_len;
+ unsigned nsegs = 0, total = 0;
+
+ while (nbytes > 0) {
+ unsigned seg_size;
+
+ *sg = blk_next_sg(sg, sglist);
+
+ seg_size = get_max_segment_size(q, total);
+ seg_size = min(nbytes, seg_size);
+
+ (*sg)->dma_address = dvec->dv_addr + total;
+ sg_dma_len(*sg) = seg_size;
+
+ total += seg_size;
+ nbytes -= seg_size;
+ nsegs++;
+ }
+
+ return nsegs;
+}
+
+static inline void
+__blk_segment_dma_map_sg(struct request_queue *q, struct dma_vec *dvec,
+ struct scatterlist *sglist, struct dma_vec *dvprv,
+ struct scatterlist **sg, int *nsegs)
+{
+ int nbytes = dvec->dv_len;
+
+ if (*sg) {
+ if ((*sg)->length + nbytes > queue_max_segment_size(q))
+ goto new_segment;
+ if (!dmavec_phys_mergeable(q, dvprv, dvec))
+ goto new_segment;
+
+ (*sg)->length += nbytes;
+ } else {
+new_segment:
+ (*nsegs) += blk_dvec_map_sg(q, dvec, sglist, sg);
+ }
+ *dvprv = *dvec;
+}
+
+static int __blk_dma_bios_map_sg(struct request_queue *q, struct bio *bio,
+ struct scatterlist *sglist,
+ struct scatterlist **sg)
+{
+ struct dma_vec dvec, dvprv = {};
+ struct bvec_iter iter;
+ int nsegs = 0;
+
+ for_each_bio(bio)
+ bio_for_each_dvec(dvec, bio, iter)
+ __blk_segment_dma_map_sg(q, &dvec, sglist, &dvprv,
+ sg, &nsegs);
+
+ return nsegs;
+}
+
/*
* map a request to scatterlist, return number of sg entries setup. Caller
* must make sure sg can hold rq->nr_phys_segments entries
@@ -559,6 +622,8 @@ int blk_rq_map_sg(struct request_queue *q, struct request *rq,
nsegs = __blk_bvec_map_sg(rq->special_vec, sglist, &sg);
else if (rq->bio && bio_op(rq->bio) == REQ_OP_WRITE_SAME)
nsegs = __blk_bvec_map_sg(bio_iovec(rq->bio), sglist, &sg);
+ else if (blk_rq_is_dma_direct(rq))
+ nsegs = __blk_dma_bios_map_sg(q, rq->bio, sglist, &sg);
else if (rq->bio)
nsegs = __blk_bios_map_sg(q, rq->bio, sglist, &sg);
--
2.20.1
^ permalink raw reply related
* [Buildroot] [PATCH 22/27] package/haproxy: re-enable package on microblaze
From: Thomas Petazzoni @ 2019-06-20 16:13 UTC (permalink / raw)
To: buildroot
In-Reply-To: <20190614210346.121013-23-giulio.benetti@micronovasrl.com>
On Fri, 14 Jun 2019 23:03:41 +0200
Giulio Benetti <giulio.benetti@micronovasrl.com> wrote:
> With Microblaze Gcc version < 8.x build gives:
> 'internal compiler error: in do_output_reload, at reload1.c:7978'
> This is due to bug 90620:
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90620. To avoid this, the
> haproxy package has a !BR2_microblaze dependency. However, gcc bug
> 90620 only triggers when optimization is enabled, so we can work
> around the issue by passing -O0, which is what we do in other
> Buildroot packages to work around this bug.
>
> So, this commit passes -O0 when BR2_TOOLCHAIN_HAS_GCC_BUG_90620, and
> re-enables haproxy on Microblaze.
>
> Signed-off-by: Giulio Benetti <giulio.benetti@micronovasrl.com>
> ---
> package/haproxy/Config.in | 2 --
> package/haproxy/haproxy.mk | 9 ++++++++-
> 2 files changed, 8 insertions(+), 3 deletions(-)
Applied to master, thanks.
Thomas
--
Thomas Petazzoni, CTO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* [RFC PATCH 20/28] IB/core: Introduce API for initializing a RW ctx from a DMA address
From: Logan Gunthorpe @ 2019-06-20 16:12 UTC (permalink / raw)
To: linux-kernel, linux-block, linux-nvme, linux-pci, linux-rdma
Cc: Jens Axboe, Christoph Hellwig, Bjorn Helgaas, Dan Williams,
Sagi Grimberg, Keith Busch, Jason Gunthorpe, Stephen Bates,
Logan Gunthorpe
In-Reply-To: <20190620161240.22738-1-logang@deltatee.com>
Introduce rdma_rw_ctx_dma_init() and rdma_rw_ctx_dma_destroy() which
peform the same operation as rdma_rw_ctx_init() and
rdma_rw_ctx_destroy() respectively except they operate on a DMA
address and length instead of an SGL.
This will be used for struct page-less P2PDMA, but there's also
been opinions expressed to migrate away from SGLs and struct
pages in the RDMA APIs and this will likely fit with that
effort.
Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
---
drivers/infiniband/core/rw.c | 74 ++++++++++++++++++++++++++++++------
include/rdma/rw.h | 6 +++
2 files changed, 69 insertions(+), 11 deletions(-)
diff --git a/drivers/infiniband/core/rw.c b/drivers/infiniband/core/rw.c
index 32ca8429eaae..cefa6b930bc8 100644
--- a/drivers/infiniband/core/rw.c
+++ b/drivers/infiniband/core/rw.c
@@ -319,6 +319,39 @@ int rdma_rw_ctx_init(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u8 port_num,
}
EXPORT_SYMBOL(rdma_rw_ctx_init);
+/**
+ * rdma_rw_ctx_dma_init - initialize a RDMA READ/WRITE context from a
+ * DMA address instead of SGL
+ * @ctx: context to initialize
+ * @qp: queue pair to operate on
+ * @port_num: port num to which the connection is bound
+ * @addr: DMA address to READ/WRITE from/to
+ * @len: length of memory to operate on
+ * @remote_addr:remote address to read/write (relative to @rkey)
+ * @rkey: remote key to operate on
+ * @dir: %DMA_TO_DEVICE for RDMA WRITE, %DMA_FROM_DEVICE for RDMA READ
+ *
+ * Returns the number of WQEs that will be needed on the workqueue if
+ * successful, or a negative error code.
+ */
+int rdma_rw_ctx_dma_init(struct rdma_rw_ctx *ctx, struct ib_qp *qp,
+ u8 port_num, dma_addr_t addr, u32 len, u64 remote_addr,
+ u32 rkey, enum dma_data_direction dir)
+{
+ struct scatterlist sg;
+
+ sg_dma_address(&sg) = addr;
+ sg_dma_len(&sg) = len;
+
+ if (rdma_rw_io_needs_mr(qp->device, port_num, dir, 1))
+ return rdma_rw_init_mr_wrs(ctx, qp, port_num, &sg, 1, 0,
+ remote_addr, rkey, dir);
+ else
+ return rdma_rw_init_single_wr(ctx, qp, &sg, 0, remote_addr,
+ rkey, dir);
+}
+EXPORT_SYMBOL(rdma_rw_ctx_dma_init);
+
/**
* rdma_rw_ctx_signature_init - initialize a RW context with signature offload
* @ctx: context to initialize
@@ -566,17 +599,7 @@ int rdma_rw_ctx_post(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u8 port_num,
}
EXPORT_SYMBOL(rdma_rw_ctx_post);
-/**
- * rdma_rw_ctx_destroy - release all resources allocated by rdma_rw_ctx_init
- * @ctx: context to release
- * @qp: queue pair to operate on
- * @port_num: port num to which the connection is bound
- * @sg: scatterlist that was used for the READ/WRITE
- * @sg_cnt: number of entries in @sg
- * @dir: %DMA_TO_DEVICE for RDMA WRITE, %DMA_FROM_DEVICE for RDMA READ
- */
-void rdma_rw_ctx_destroy(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u8 port_num,
- struct scatterlist *sg, u32 sg_cnt, enum dma_data_direction dir)
+static void __rdma_rw_ctx_destroy(struct rdma_rw_ctx *ctx, struct ib_qp *qp)
{
int i;
@@ -596,6 +619,21 @@ void rdma_rw_ctx_destroy(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u8 port_num,
BUG();
break;
}
+}
+
+/**
+ * rdma_rw_ctx_destroy - release all resources allocated by rdma_rw_ctx_init
+ * @ctx: context to release
+ * @qp: queue pair to operate on
+ * @port_num: port num to which the connection is bound
+ * @sg: scatterlist that was used for the READ/WRITE
+ * @sg_cnt: number of entries in @sg
+ * @dir: %DMA_TO_DEVICE for RDMA WRITE, %DMA_FROM_DEVICE for RDMA READ
+ */
+void rdma_rw_ctx_destroy(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u8 port_num,
+ struct scatterlist *sg, u32 sg_cnt, enum dma_data_direction dir)
+{
+ __rdma_rw_ctx_destroy(ctx, qp);
/* P2PDMA contexts do not need to be unmapped */
if (!is_pci_p2pdma_page(sg_page(sg)))
@@ -603,6 +641,20 @@ void rdma_rw_ctx_destroy(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u8 port_num,
}
EXPORT_SYMBOL(rdma_rw_ctx_destroy);
+/**
+ * rdma_rw_ctx_dma_destroy - release all resources allocated by
+ * rdma_rw_ctx_dma_init
+ * @ctx: context to release
+ * @qp: queue pair to operate on
+ * @port_num: port num to which the connection is bound
+ */
+void rdma_rw_ctx_dma_destroy(struct rdma_rw_ctx *ctx, struct ib_qp *qp,
+ u8 port_num)
+{
+ __rdma_rw_ctx_destroy(ctx, qp);
+}
+EXPORT_SYMBOL(rdma_rw_ctx_dma_destroy);
+
/**
* rdma_rw_ctx_destroy_signature - release all resources allocated by
* rdma_rw_ctx_init_signature
diff --git a/include/rdma/rw.h b/include/rdma/rw.h
index 494f79ca3e62..e47f8053af6e 100644
--- a/include/rdma/rw.h
+++ b/include/rdma/rw.h
@@ -58,6 +58,12 @@ void rdma_rw_ctx_destroy(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u8 port_num,
struct scatterlist *sg, u32 sg_cnt,
enum dma_data_direction dir);
+int rdma_rw_ctx_dma_init(struct rdma_rw_ctx *ctx, struct ib_qp *qp,
+ u8 port_num, dma_addr_t addr, u32 len, u64 remote_addr,
+ u32 rkey, enum dma_data_direction dir);
+void rdma_rw_ctx_dma_destroy(struct rdma_rw_ctx *ctx, struct ib_qp *qp,
+ u8 port_num);
+
int rdma_rw_ctx_signature_init(struct rdma_rw_ctx *ctx, struct ib_qp *qp,
u8 port_num, struct scatterlist *sg, u32 sg_cnt,
struct scatterlist *prot_sg, u32 prot_sg_cnt,
--
2.20.1
^ permalink raw reply related
* [RFC PATCH 25/28] IB/core: Remove P2PDMA mapping support in rdma_rw_ctx
From: Logan Gunthorpe @ 2019-06-20 16:12 UTC (permalink / raw)
To: linux-kernel, linux-block, linux-nvme, linux-pci, linux-rdma
Cc: Jens Axboe, Christoph Hellwig, Bjorn Helgaas, Dan Williams,
Sagi Grimberg, Keith Busch, Jason Gunthorpe, Stephen Bates,
Logan Gunthorpe
In-Reply-To: <20190620161240.22738-1-logang@deltatee.com>
There are no longer any users submitting P2PDMA struct pages to
rdma_rw_ctx. So it can be removed.
Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
---
drivers/infiniband/core/rw.c | 11 ++---------
1 file changed, 2 insertions(+), 9 deletions(-)
diff --git a/drivers/infiniband/core/rw.c b/drivers/infiniband/core/rw.c
index cefa6b930bc8..350b9b730ddc 100644
--- a/drivers/infiniband/core/rw.c
+++ b/drivers/infiniband/core/rw.c
@@ -4,7 +4,6 @@
*/
#include <linux/moduleparam.h>
#include <linux/slab.h>
-#include <linux/pci-p2pdma.h>
#include <rdma/mr_pool.h>
#include <rdma/rw.h>
@@ -271,11 +270,7 @@ int rdma_rw_ctx_init(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u8 port_num,
struct ib_device *dev = qp->pd->device;
int ret;
- if (is_pci_p2pdma_page(sg_page(sg)))
- ret = pci_p2pdma_map_sg(dev->dma_device, sg, sg_cnt, dir);
- else
- ret = ib_dma_map_sg(dev, sg, sg_cnt, dir);
-
+ ret = ib_dma_map_sg(dev, sg, sg_cnt, dir);
if (!ret)
return -ENOMEM;
sg_cnt = ret;
@@ -635,9 +630,7 @@ void rdma_rw_ctx_destroy(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u8 port_num,
{
__rdma_rw_ctx_destroy(ctx, qp);
- /* P2PDMA contexts do not need to be unmapped */
- if (!is_pci_p2pdma_page(sg_page(sg)))
- ib_dma_unmap_sg(qp->pd->device, sg, sg_cnt, dir);
+ ib_dma_unmap_sg(qp->pd->device, sg, sg_cnt, dir);
}
EXPORT_SYMBOL(rdma_rw_ctx_destroy);
--
2.20.1
^ permalink raw reply related
* [RFC PATCH 24/28] block: Remove PCI_P2PDMA queue flag
From: Logan Gunthorpe @ 2019-06-20 16:12 UTC (permalink / raw)
To: linux-kernel, linux-block, linux-nvme, linux-pci, linux-rdma
Cc: Jens Axboe, Christoph Hellwig, Bjorn Helgaas, Dan Williams,
Sagi Grimberg, Keith Busch, Jason Gunthorpe, Stephen Bates,
Logan Gunthorpe
In-Reply-To: <20190620161240.22738-1-logang@deltatee.com>
This flag has been superseded by the DMA_DIRECT functionality.
Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
---
include/linux/blkdev.h | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index a5b856324276..9ea800645cf5 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -615,8 +615,7 @@ struct request_queue {
#define QUEUE_FLAG_REGISTERED 22 /* queue has been registered to a disk */
#define QUEUE_FLAG_SCSI_PASSTHROUGH 23 /* queue supports SCSI commands */
#define QUEUE_FLAG_QUIESCED 24 /* queue has been quiesced */
-#define QUEUE_FLAG_PCI_P2PDMA 25 /* device supports PCI p2p requests */
-#define QUEUE_FLAG_DMA_DIRECT 26 /* device supports dma-addr requests */
+#define QUEUE_FLAG_DMA_DIRECT 25 /* device supports dma-addr requests */
#define QUEUE_FLAG_MQ_DEFAULT ((1 << QUEUE_FLAG_IO_STAT) | \
(1 << QUEUE_FLAG_SAME_COMP))
@@ -641,8 +640,6 @@ bool blk_queue_flag_test_and_set(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_queue_dma_direct(q) \
test_bit(QUEUE_FLAG_DMA_DIRECT, &(q)->queue_flags)
--
2.20.1
^ permalink raw reply related
* [RFC PATCH 21/28] nvmet: Split nvmet_bdev_execute_rw() into a helper function
From: Logan Gunthorpe @ 2019-06-20 16:12 UTC (permalink / raw)
To: linux-kernel, linux-block, linux-nvme, linux-pci, linux-rdma
Cc: Jens Axboe, Christoph Hellwig, Bjorn Helgaas, Dan Williams,
Sagi Grimberg, Keith Busch, Jason Gunthorpe, Stephen Bates,
Logan Gunthorpe
In-Reply-To: <20190620161240.22738-1-logang@deltatee.com>
Move the mapping of the SG and submission of the bio
into a static helper function to reduce the complexity.
This will be useful in the next patch which submits dma-direct bios
for P2P requests.
Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
---
drivers/nvme/target/io-cmd-bdev.c | 52 ++++++++++++++++++-------------
1 file changed, 31 insertions(+), 21 deletions(-)
diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c
index 7a1cf6437a6a..061d40b020c7 100644
--- a/drivers/nvme/target/io-cmd-bdev.c
+++ b/drivers/nvme/target/io-cmd-bdev.c
@@ -103,13 +103,41 @@ static void nvmet_bio_done(struct bio *bio)
bio_put(bio);
}
+static void nvmet_submit_sg(struct nvmet_req *req, struct bio *bio,
+ sector_t sector)
+{
+ int sg_cnt = req->sg_cnt;
+ struct scatterlist *sg;
+ int i;
+
+ for_each_sg(req->sg, sg, req->sg_cnt, i) {
+ while (bio_add_page(bio, sg_page(sg), sg->length, sg->offset)
+ != sg->length) {
+ struct bio *prev = bio;
+
+ bio = bio_alloc(GFP_KERNEL,
+ min(sg_cnt, BIO_MAX_PAGES));
+ bio_set_dev(bio, req->ns->bdev);
+ bio->bi_iter.bi_sector = sector;
+ bio->bi_opf = prev->bi_opf;
+
+ bio_chain(bio, prev);
+ submit_bio(prev);
+ }
+
+ sector += sg->length >> 9;
+ sg_cnt--;
+ }
+
+ submit_bio(bio);
+}
+
static void nvmet_bdev_execute_rw(struct nvmet_req *req)
{
int sg_cnt = req->sg_cnt;
struct bio *bio;
- struct scatterlist *sg;
sector_t sector;
- int op, op_flags = 0, i;
+ int op, op_flags = 0;
if (!req->sg_cnt) {
nvmet_req_complete(req, 0);
@@ -143,25 +171,7 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req)
bio->bi_end_io = nvmet_bio_done;
bio_set_op_attrs(bio, op, op_flags);
- for_each_sg(req->sg, sg, req->sg_cnt, i) {
- while (bio_add_page(bio, sg_page(sg), sg->length, sg->offset)
- != sg->length) {
- struct bio *prev = bio;
-
- bio = bio_alloc(GFP_KERNEL, min(sg_cnt, BIO_MAX_PAGES));
- bio_set_dev(bio, req->ns->bdev);
- bio->bi_iter.bi_sector = sector;
- bio_set_op_attrs(bio, op, op_flags);
-
- bio_chain(bio, prev);
- submit_bio(prev);
- }
-
- sector += sg->length >> 9;
- sg_cnt--;
- }
-
- submit_bio(bio);
+ nvmet_submit_sg(req, bio, sector);
}
static void nvmet_bdev_execute_flush(struct nvmet_req *req)
--
2.20.1
^ permalink raw reply related
* [RFC PATCH 22/28] nvmet: Use DMA addresses instead of struct pages for P2P
From: Logan Gunthorpe @ 2019-06-20 16:12 UTC (permalink / raw)
To: linux-kernel, linux-block, linux-nvme, linux-pci, linux-rdma
Cc: Jens Axboe, Christoph Hellwig, Bjorn Helgaas, Dan Williams,
Sagi Grimberg, Keith Busch, Jason Gunthorpe, Stephen Bates,
Logan Gunthorpe
In-Reply-To: <20190620161240.22738-1-logang@deltatee.com>
Start using the dma-direct bios and DMA address RDMA CTX API.
This removes struct pages from all P2P transactions.
Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
---
drivers/nvme/target/core.c | 12 +++++----
drivers/nvme/target/io-cmd-bdev.c | 32 ++++++++++++++++++++---
drivers/nvme/target/nvmet.h | 5 +++-
drivers/nvme/target/rdma.c | 43 +++++++++++++++++++++++--------
4 files changed, 71 insertions(+), 21 deletions(-)
diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
index 7734a6acff85..230e99b63320 100644
--- a/drivers/nvme/target/core.c
+++ b/drivers/nvme/target/core.c
@@ -420,7 +420,7 @@ static int nvmet_p2pmem_ns_enable(struct nvmet_ns *ns)
return -EINVAL;
}
- if (!blk_queue_pci_p2pdma(ns->bdev->bd_queue)) {
+ if (!blk_queue_dma_direct(ns->bdev->bd_queue)) {
pr_err("peer-to-peer DMA is not supported by the driver of %s\n",
ns->device_path);
return -EINVAL;
@@ -926,9 +926,9 @@ int nvmet_req_alloc_sgl(struct nvmet_req *req)
req->p2p_dev = NULL;
if (req->sq->qid && p2p_dev) {
- req->sg = pci_p2pmem_alloc_sgl(p2p_dev, &req->sg_cnt,
- req->transfer_len);
- if (req->sg) {
+ req->p2p_dma_buf = pci_alloc_p2pmem(p2p_dev,
+ req->transfer_len);
+ if (req->p2p_dma_buf) {
req->p2p_dev = p2p_dev;
return 0;
}
@@ -951,10 +951,12 @@ EXPORT_SYMBOL_GPL(nvmet_req_alloc_sgl);
void nvmet_req_free_sgl(struct nvmet_req *req)
{
if (req->p2p_dev)
- pci_p2pmem_free_sgl(req->p2p_dev, req->sg);
+ pci_free_p2pmem(req->p2p_dev, req->p2p_dma_buf,
+ req->transfer_len);
else
sgl_free(req->sg);
+ req->p2p_dev = NULL;
req->sg = NULL;
req->sg_cnt = 0;
}
diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c
index 061d40b020c7..f5621aeb1d6c 100644
--- a/drivers/nvme/target/io-cmd-bdev.c
+++ b/drivers/nvme/target/io-cmd-bdev.c
@@ -6,6 +6,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/blkdev.h>
#include <linux/module.h>
+#include <linux/pci-p2pdma.h>
#include "nvmet.h"
int nvmet_bdev_ns_enable(struct nvmet_ns *ns)
@@ -132,6 +133,24 @@ static void nvmet_submit_sg(struct nvmet_req *req, struct bio *bio,
submit_bio(bio);
}
+static void nvmet_submit_p2p(struct nvmet_req *req, struct bio *bio)
+{
+ dma_addr_t addr;
+ int ret;
+
+ addr = pci_p2pmem_virt_to_bus(req->p2p_dev, req->p2p_dma_buf);
+
+ ret = bio_add_dma_addr(req->ns->bdev->bd_queue, bio,
+ addr, req->transfer_len);
+ if (WARN_ON_ONCE(ret != req->transfer_len)) {
+ bio->bi_status = BLK_STS_NOTSUPP;
+ nvmet_bio_done(bio);
+ return;
+ }
+
+ submit_bio(bio);
+}
+
static void nvmet_bdev_execute_rw(struct nvmet_req *req)
{
int sg_cnt = req->sg_cnt;
@@ -139,7 +158,7 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req)
sector_t sector;
int op, op_flags = 0;
- if (!req->sg_cnt) {
+ if (!req->sg_cnt && !req->p2p_dev) {
nvmet_req_complete(req, 0);
return;
}
@@ -153,8 +172,10 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req)
op = REQ_OP_READ;
}
- if (is_pci_p2pdma_page(sg_page(req->sg)))
- op_flags |= REQ_NOMERGE;
+ if (req->p2p_dev) {
+ op_flags |= REQ_DMA_DIRECT;
+ sg_cnt = 1;
+ }
sector = le64_to_cpu(req->cmd->rw.slba);
sector <<= (req->ns->blksize_shift - 9);
@@ -171,7 +192,10 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req)
bio->bi_end_io = nvmet_bio_done;
bio_set_op_attrs(bio, op, op_flags);
- nvmet_submit_sg(req, bio, sector);
+ if (req->p2p_dev)
+ nvmet_submit_p2p(req, bio);
+ else
+ nvmet_submit_sg(req, bio, sector);
}
static void nvmet_bdev_execute_flush(struct nvmet_req *req)
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index c25d88fc9dec..5714e5b5ef04 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -288,7 +288,10 @@ struct nvmet_req {
struct nvmet_sq *sq;
struct nvmet_cq *cq;
struct nvmet_ns *ns;
- struct scatterlist *sg;
+ union {
+ struct scatterlist *sg;
+ void *p2p_dma_buf;
+ };
struct bio_vec inline_bvec[NVMET_MAX_INLINE_BIOVEC];
union {
struct {
diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c
index 36d906a7f70d..92bfc7207814 100644
--- a/drivers/nvme/target/rdma.c
+++ b/drivers/nvme/target/rdma.c
@@ -15,6 +15,7 @@
#include <linux/string.h>
#include <linux/wait.h>
#include <linux/inet.h>
+#include <linux/pci-p2pdma.h>
#include <asm/unaligned.h>
#include <rdma/ib_verbs.h>
@@ -495,6 +496,18 @@ static void nvmet_rdma_process_wr_wait_list(struct nvmet_rdma_queue *queue)
spin_unlock(&queue->rsp_wr_wait_lock);
}
+static void nvmet_rdma_ctx_destroy(struct nvmet_rdma_rsp *rsp)
+{
+ struct nvmet_rdma_queue *queue = rsp->queue;
+
+ if (rsp->req.p2p_dev)
+ rdma_rw_ctx_dma_destroy(&rsp->rw, queue->cm_id->qp,
+ queue->cm_id->port_num);
+ else
+ rdma_rw_ctx_destroy(&rsp->rw, queue->cm_id->qp,
+ queue->cm_id->port_num, rsp->req.sg,
+ rsp->req.sg_cnt, nvmet_data_dir(&rsp->req));
+}
static void nvmet_rdma_release_rsp(struct nvmet_rdma_rsp *rsp)
{
@@ -502,11 +515,8 @@ static void nvmet_rdma_release_rsp(struct nvmet_rdma_rsp *rsp)
atomic_add(1 + rsp->n_rdma, &queue->sq_wr_avail);
- if (rsp->n_rdma) {
- rdma_rw_ctx_destroy(&rsp->rw, queue->cm_id->qp,
- queue->cm_id->port_num, rsp->req.sg,
- rsp->req.sg_cnt, nvmet_data_dir(&rsp->req));
- }
+ if (rsp->n_rdma)
+ nvmet_rdma_ctx_destroy(rsp);
if (rsp->req.sg != rsp->cmd->inline_sg)
nvmet_req_free_sgl(&rsp->req);
@@ -587,9 +597,9 @@ static void nvmet_rdma_read_data_done(struct ib_cq *cq, struct ib_wc *wc)
WARN_ON(rsp->n_rdma <= 0);
atomic_add(rsp->n_rdma, &queue->sq_wr_avail);
- rdma_rw_ctx_destroy(&rsp->rw, queue->cm_id->qp,
- queue->cm_id->port_num, rsp->req.sg,
- rsp->req.sg_cnt, nvmet_data_dir(&rsp->req));
+
+ nvmet_rdma_ctx_destroy(rsp);
+
rsp->n_rdma = 0;
if (unlikely(wc->status != IB_WC_SUCCESS)) {
@@ -663,6 +673,7 @@ static u16 nvmet_rdma_map_sgl_keyed(struct nvmet_rdma_rsp *rsp,
struct rdma_cm_id *cm_id = rsp->queue->cm_id;
u64 addr = le64_to_cpu(sgl->addr);
u32 key = get_unaligned_le32(sgl->key);
+ dma_addr_t dma_addr;
int ret;
rsp->req.transfer_len = get_unaligned_le24(sgl->length);
@@ -675,9 +686,19 @@ static u16 nvmet_rdma_map_sgl_keyed(struct nvmet_rdma_rsp *rsp,
if (ret < 0)
goto error_out;
- ret = rdma_rw_ctx_init(&rsp->rw, cm_id->qp, cm_id->port_num,
- rsp->req.sg, rsp->req.sg_cnt, 0, addr, key,
- nvmet_data_dir(&rsp->req));
+ if (rsp->req.p2p_dev) {
+ dma_addr = pci_p2pmem_virt_to_bus(rsp->req.p2p_dev,
+ rsp->req.p2p_dma_buf);
+
+ ret = rdma_rw_ctx_dma_init(&rsp->rw, cm_id->qp,
+ cm_id->port_num, dma_addr,
+ rsp->req.transfer_len, addr, key,
+ nvmet_data_dir(&rsp->req));
+ } else {
+ ret = rdma_rw_ctx_init(&rsp->rw, cm_id->qp, cm_id->port_num,
+ rsp->req.sg, rsp->req.sg_cnt, 0, addr,
+ key, nvmet_data_dir(&rsp->req));
+ }
if (ret < 0)
goto error_out;
rsp->n_rdma += ret;
--
2.20.1
^ permalink raw reply related
* Re: [PATCH v2 2/3] media: stm32-dcmi: add media controller support
From: Sakari Ailus @ 2019-06-20 16:13 UTC (permalink / raw)
To: Hugues Fruchet
Cc: Alexandre Torgue, Mauro Carvalho Chehab, Hans Verkuil,
linux-media, linux-arm-kernel, linux-kernel, linux-stm32,
Benjamin Gaignard, Yannick Fertre, Philippe CORNU, Mickael GUENE
In-Reply-To: <1560242912-17138-3-git-send-email-hugues.fruchet@st.com>
Hi Hugues,
On Tue, Jun 11, 2019 at 10:48:31AM +0200, Hugues Fruchet wrote:
> Add media controller support to dcmi.
>
> Signed-off-by: Hugues Fruchet <hugues.fruchet@st.com>
> ---
> drivers/media/platform/Kconfig | 2 +-
> drivers/media/platform/stm32/stm32-dcmi.c | 83 +++++++++++++++++++++++--------
> 2 files changed, 63 insertions(+), 22 deletions(-)
>
> diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
> index 8a19654..de7e21f 100644
> --- a/drivers/media/platform/Kconfig
> +++ b/drivers/media/platform/Kconfig
> @@ -121,7 +121,7 @@ config VIDEO_S3C_CAMIF
>
> config VIDEO_STM32_DCMI
> tristate "STM32 Digital Camera Memory Interface (DCMI) support"
> - depends on VIDEO_V4L2 && OF
> + depends on VIDEO_V4L2 && OF && MEDIA_CONTROLLER
Ok, if the intent is to require MC from now on, then I think you could
simply rely on media_entity_remote_pad() in finding the image source.
> depends on ARCH_STM32 || COMPILE_TEST
> select VIDEOBUF2_DMA_CONTIG
> select V4L2_FWNODE
> diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c
> index 7a4d559..3a69783 100644
> --- a/drivers/media/platform/stm32/stm32-dcmi.c
> +++ b/drivers/media/platform/stm32/stm32-dcmi.c
> @@ -170,6 +170,9 @@ struct stm32_dcmi {
>
> /* Ensure DMA operations atomicity */
> struct mutex dma_lock;
> +
> + struct media_device mdev;
> + struct media_pad vid_cap_pad;
> };
>
> static inline struct stm32_dcmi *notifier_to_dcmi(struct v4l2_async_notifier *n)
> @@ -1545,21 +1548,12 @@ static int dcmi_graph_notify_complete(struct v4l2_async_notifier *notifier)
> dev_err(dcmi->dev, "Could not get sensor bounds\n");
> return ret;
> }
> -
> ret = dcmi_set_default_fmt(dcmi);
> if (ret) {
> dev_err(dcmi->dev, "Could not set default format\n");
> return ret;
> }
>
> - ret = video_register_device(dcmi->vdev, VFL_TYPE_GRABBER, -1);
> - if (ret) {
> - dev_err(dcmi->dev, "Failed to register video device\n");
> - return ret;
> - }
> -
> - dev_dbg(dcmi->dev, "Device registered as %s\n",
> - video_device_node_name(dcmi->vdev));
> return 0;
> }
>
> @@ -1648,6 +1642,12 @@ static int dcmi_graph_init(struct stm32_dcmi *dcmi)
> return 0;
> }
>
> +static void dcmi_graph_deinit(struct stm32_dcmi *dcmi)
> +{
> + v4l2_async_notifier_unregister(&dcmi->notifier);
> + v4l2_async_notifier_cleanup(&dcmi->notifier);
I'd just leave the calls where they are now. This doesn't improve
readability of the code, rather the opposite.
> +}
> +
> static int dcmi_probe(struct platform_device *pdev)
> {
> struct device_node *np = pdev->dev.of_node;
> @@ -1752,10 +1752,27 @@ static int dcmi_probe(struct platform_device *pdev)
>
> q = &dcmi->queue;
>
> + dcmi->v4l2_dev.mdev = &dcmi->mdev;
> +
> + /* Initialize media device */
> + strscpy(dcmi->mdev.model, DRV_NAME, sizeof(dcmi->mdev.model));
> + snprintf(dcmi->mdev.bus_info, sizeof(dcmi->mdev.bus_info),
> + "platform:%s", DRV_NAME);
> + dcmi->mdev.dev = &pdev->dev;
> + media_device_init(&dcmi->mdev);
> +
> + /* Register the media device */
> + ret = media_device_register(&dcmi->mdev);
> + if (ret) {
> + dev_err(dcmi->dev, "Failed to register media device (%d)\n",
> + ret);
> + goto err_media_device_cleanup;
> + }
> +
> /* Initialize the top-level structure */
> ret = v4l2_device_register(&pdev->dev, &dcmi->v4l2_dev);
> if (ret)
> - goto err_dma_release;
> + goto err_media_device_unregister;
>
> dcmi->vdev = video_device_alloc();
> if (!dcmi->vdev) {
> @@ -1775,6 +1792,25 @@ static int dcmi_probe(struct platform_device *pdev)
> V4L2_CAP_READWRITE;
> video_set_drvdata(dcmi->vdev, dcmi);
>
> + /* Media entity pads */
> + dcmi->vid_cap_pad.flags = MEDIA_PAD_FL_SINK;
> + ret = media_entity_pads_init(&dcmi->vdev->entity,
> + 1, &dcmi->vid_cap_pad);
> + if (ret) {
> + dev_err(dcmi->dev, "Failed to init media entity pad\n");
> + goto err_device_unregister;
> + }
> + dcmi->vdev->entity.flags |= MEDIA_ENT_FL_DEFAULT;
> +
> + ret = video_register_device(dcmi->vdev, VFL_TYPE_GRABBER, -1);
> + if (ret) {
> + dev_err(dcmi->dev, "Failed to register video device\n");
> + goto err_media_entity_cleanup;
> + }
> +
> + dev_dbg(dcmi->dev, "Device registered as %s\n",
> + video_device_node_name(dcmi->vdev));
> +
> /* Buffer queue */
> q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
> q->io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF;
> @@ -1790,18 +1826,18 @@ static int dcmi_probe(struct platform_device *pdev)
> ret = vb2_queue_init(q);
> if (ret < 0) {
> dev_err(&pdev->dev, "Failed to initialize vb2 queue\n");
> - goto err_device_release;
> + goto err_media_entity_cleanup;
> }
>
> ret = dcmi_graph_init(dcmi);
> if (ret < 0)
> - goto err_device_release;
> + goto err_media_entity_cleanup;
>
> /* Reset device */
> ret = reset_control_assert(dcmi->rstc);
> if (ret) {
> dev_err(&pdev->dev, "Failed to assert the reset line\n");
> - goto err_cleanup;
> + goto err_graph_deinit;
> }
>
> usleep_range(3000, 5000);
> @@ -1809,7 +1845,7 @@ static int dcmi_probe(struct platform_device *pdev)
> ret = reset_control_deassert(dcmi->rstc);
> if (ret) {
> dev_err(&pdev->dev, "Failed to deassert the reset line\n");
> - goto err_cleanup;
> + goto err_graph_deinit;
> }
>
> dev_info(&pdev->dev, "Probe done\n");
> @@ -1820,13 +1856,16 @@ static int dcmi_probe(struct platform_device *pdev)
>
> return 0;
>
> -err_cleanup:
> - v4l2_async_notifier_cleanup(&dcmi->notifier);
> -err_device_release:
> - video_device_release(dcmi->vdev);
> +err_graph_deinit:
> + dcmi_graph_deinit(dcmi);
> +err_media_entity_cleanup:
> + media_entity_cleanup(&dcmi->vdev->entity);
> err_device_unregister:
> v4l2_device_unregister(&dcmi->v4l2_dev);
> -err_dma_release:
> +err_media_device_unregister:
> + media_device_unregister(&dcmi->mdev);
> +err_media_device_cleanup:
> + media_device_cleanup(&dcmi->mdev);
> dma_release_channel(dcmi->dma_chan);
>
> return ret;
> @@ -1838,9 +1877,11 @@ static int dcmi_remove(struct platform_device *pdev)
>
> pm_runtime_disable(&pdev->dev);
>
> - v4l2_async_notifier_unregister(&dcmi->notifier);
> - v4l2_async_notifier_cleanup(&dcmi->notifier);
> + dcmi_graph_deinit(dcmi);
> + media_entity_cleanup(&dcmi->vdev->entity);
> v4l2_device_unregister(&dcmi->v4l2_dev);
> + media_device_unregister(&dcmi->mdev);
Please unregister the media device first before unregistering anything else
it depends on (i.e. async notifier or the entity).
> + media_device_cleanup(&dcmi->mdev);
>
> dma_release_channel(dcmi->dma_chan);
>
--
Kind regards,
Sakari Ailus
sakari.ailus@linux.intel.com
^ permalink raw reply
* Re: [PATCH V2 1/2] DT: mailbox: add binding doc for the ARM SMC mailbox
From: Andre Przywara @ 2019-06-20 16:13 UTC (permalink / raw)
To: Sudeep Holla
Cc: peng.fan, robh+dt, mark.rutland, jassisinghbrar, f.fainelli,
kernel, linux-imx, shawnguo, festevam, devicetree, linux-kernel,
linux-arm-kernel, van.freenix
In-Reply-To: <20190620092241.GC1248@e107155-lin>
On Thu, 20 Jun 2019 10:22:41 +0100
Sudeep Holla <sudeep.holla@arm.com> wrote:
> On Mon, Jun 03, 2019 at 04:30:04PM +0800, peng.fan@nxp.com wrote:
> > From: Peng Fan <peng.fan@nxp.com>
> >
> > The ARM SMC mailbox binding describes a firmware interface to trigger
> > actions in software layers running in the EL2 or EL3 exception levels.
> > The term "ARM" here relates to the SMC instruction as part of the ARM
> > instruction set, not as a standard endorsed by ARM Ltd.
> >
> > Signed-off-by: Peng Fan <peng.fan@nxp.com>
> > ---
> >
> > V2:
> > Introduce interrupts as a property.
> >
> > V1:
> > arm,func-ids is still kept as an optional property, because there is no
> > defined SMC funciton id passed from SCMI. So in my test, I still use
> > arm,func-ids for ARM SIP service.
> >
> > .../devicetree/bindings/mailbox/arm-smc.txt | 101 +++++++++++++++++++++
> > 1 file changed, 101 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/mailbox/arm-smc.txt
> >
> > diff --git a/Documentation/devicetree/bindings/mailbox/arm-smc.txt b/Documentation/devicetree/bindings/mailbox/arm-smc.txt
> > new file mode 100644
> > index 000000000000..401887118c09
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/mailbox/arm-smc.txt
> > @@ -0,0 +1,101 @@
> > +ARM SMC Mailbox Interface
> > +=========================
> > +
> > +This mailbox uses the ARM smc (secure monitor call) instruction to trigger
> > +a mailbox-connected activity in firmware, executing on the very same core
> > +as the caller. By nature this operation is synchronous and this mailbox
> > +provides no way for asynchronous messages to be delivered the other way
> > +round, from firmware to the OS, but asynchronous notification could also
> > +be supported. However the value of r0/w0/x0 the firmware returns after
> > +the smc call is delivered as a received message to the mailbox framework,
> > +so a synchronous communication can be established, for a asynchronous
> > +notification, no value will be returned. The exact meaning of both the
> > +action the mailbox triggers as well as the return value is defined by
> > +their users and is not subject to this binding.
> > +
> > +One use case of this mailbox is the SCMI interface, which uses shared memory
> > +to transfer commands and parameters, and a mailbox to trigger a function
> > +call. This allows SoCs without a separate management processor (or when
> > +such a processor is not available or used) to use this standardized
> > +interface anyway.
> > +
> > +This binding describes no hardware, but establishes a firmware interface.
> > +Upon receiving an SMC using one of the described SMC function identifiers,
> > +the firmware is expected to trigger some mailbox connected functionality.
> > +The communication follows the ARM SMC calling convention[1].
> > +Firmware expects an SMC function identifier in r0 or w0. The supported
> > +identifiers are passed from consumers, or listed in the the arm,func-ids
> > +properties as described below. The firmware can return one value in
> > +the first SMC result register, it is expected to be an error value,
> > +which shall be propagated to the mailbox client.
> > +
> > +Any core which supports the SMC or HVC instruction can be used, as long as
> > +a firmware component running in EL3 or EL2 is handling these calls.
> > +
> > +Mailbox Device Node:
> > +====================
> > +
> > +This node is expected to be a child of the /firmware node.
> > +
> > +Required properties:
> > +--------------------
> > +- compatible: Shall be "arm,smc-mbox"
> > +- #mbox-cells Shall be 1 - the index of the channel needed.
> > +- arm,num-chans The number of channels supported.
> > +- method: A string, either:
> > + "hvc": if the driver shall use an HVC call, or
> > + "smc": if the driver shall use an SMC call.
> > +
> > +Optional properties:
> > +- arm,func-ids An array of 32-bit values specifying the function
> > + IDs used by each mailbox channel. Those function IDs
> > + follow the ARM SMC calling convention standard [1].
> > + There is one identifier per channel and the number
> > + of supported channels is determined by the length
> > + of this array.
> > +- interrupts SPI interrupts may be listed for notification,
> > + each channel should use a dedicated interrupt
> > + line.
> > +
>
> I think SMC mailbox as mostly unidirectional/Tx only channel. And the
> interrupts here as stated are for notifications, so I prefer to keep
> them separate channel. I assume SMC call return indicates completion.
> Or do you plan to use these interrupts as the indication for completion
> of the command? I see in patch 2/2 the absence of IRQ is anyway dealt
> the way I mention above.
>
> Does it make sense or am I missing something here ?
I think you are right. From a mailbox point of view "completion" means
that the trigger has reached the other side. A returning smc call is a
perfect indication of this fact. Whether the action triggered by this
mailbox command has completed is a totally separate question and out of
the scope of the mailbox. This should be handled by a higher level
protocol (SCPI in this case). Which could mean that this employs a
separate return mailbox channel, which is RX only and implemented by
interrupts. Which could or could not be part of this driver.
Cheers,
Andre
^ permalink raw reply
* Re: [PATCH V2 1/2] DT: mailbox: add binding doc for the ARM SMC mailbox
From: Andre Przywara @ 2019-06-20 16:13 UTC (permalink / raw)
To: Sudeep Holla
Cc: peng.fan, robh+dt, mark.rutland, jassisinghbrar, f.fainelli,
kernel, linux-imx, shawnguo, festevam, devicetree, linux-kernel,
linux-arm-kernel, van.freenix
In-Reply-To: <20190620092241.GC1248@e107155-lin>
On Thu, 20 Jun 2019 10:22:41 +0100
Sudeep Holla <sudeep.holla@arm.com> wrote:
> On Mon, Jun 03, 2019 at 04:30:04PM +0800, peng.fan@nxp.com wrote:
> > From: Peng Fan <peng.fan@nxp.com>
> >
> > The ARM SMC mailbox binding describes a firmware interface to trigger
> > actions in software layers running in the EL2 or EL3 exception levels.
> > The term "ARM" here relates to the SMC instruction as part of the ARM
> > instruction set, not as a standard endorsed by ARM Ltd.
> >
> > Signed-off-by: Peng Fan <peng.fan@nxp.com>
> > ---
> >
> > V2:
> > Introduce interrupts as a property.
> >
> > V1:
> > arm,func-ids is still kept as an optional property, because there is no
> > defined SMC funciton id passed from SCMI. So in my test, I still use
> > arm,func-ids for ARM SIP service.
> >
> > .../devicetree/bindings/mailbox/arm-smc.txt | 101 +++++++++++++++++++++
> > 1 file changed, 101 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/mailbox/arm-smc.txt
> >
> > diff --git a/Documentation/devicetree/bindings/mailbox/arm-smc.txt b/Documentation/devicetree/bindings/mailbox/arm-smc.txt
> > new file mode 100644
> > index 000000000000..401887118c09
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/mailbox/arm-smc.txt
> > @@ -0,0 +1,101 @@
> > +ARM SMC Mailbox Interface
> > +=========================
> > +
> > +This mailbox uses the ARM smc (secure monitor call) instruction to trigger
> > +a mailbox-connected activity in firmware, executing on the very same core
> > +as the caller. By nature this operation is synchronous and this mailbox
> > +provides no way for asynchronous messages to be delivered the other way
> > +round, from firmware to the OS, but asynchronous notification could also
> > +be supported. However the value of r0/w0/x0 the firmware returns after
> > +the smc call is delivered as a received message to the mailbox framework,
> > +so a synchronous communication can be established, for a asynchronous
> > +notification, no value will be returned. The exact meaning of both the
> > +action the mailbox triggers as well as the return value is defined by
> > +their users and is not subject to this binding.
> > +
> > +One use case of this mailbox is the SCMI interface, which uses shared memory
> > +to transfer commands and parameters, and a mailbox to trigger a function
> > +call. This allows SoCs without a separate management processor (or when
> > +such a processor is not available or used) to use this standardized
> > +interface anyway.
> > +
> > +This binding describes no hardware, but establishes a firmware interface.
> > +Upon receiving an SMC using one of the described SMC function identifiers,
> > +the firmware is expected to trigger some mailbox connected functionality.
> > +The communication follows the ARM SMC calling convention[1].
> > +Firmware expects an SMC function identifier in r0 or w0. The supported
> > +identifiers are passed from consumers, or listed in the the arm,func-ids
> > +properties as described below. The firmware can return one value in
> > +the first SMC result register, it is expected to be an error value,
> > +which shall be propagated to the mailbox client.
> > +
> > +Any core which supports the SMC or HVC instruction can be used, as long as
> > +a firmware component running in EL3 or EL2 is handling these calls.
> > +
> > +Mailbox Device Node:
> > +====================
> > +
> > +This node is expected to be a child of the /firmware node.
> > +
> > +Required properties:
> > +--------------------
> > +- compatible: Shall be "arm,smc-mbox"
> > +- #mbox-cells Shall be 1 - the index of the channel needed.
> > +- arm,num-chans The number of channels supported.
> > +- method: A string, either:
> > + "hvc": if the driver shall use an HVC call, or
> > + "smc": if the driver shall use an SMC call.
> > +
> > +Optional properties:
> > +- arm,func-ids An array of 32-bit values specifying the function
> > + IDs used by each mailbox channel. Those function IDs
> > + follow the ARM SMC calling convention standard [1].
> > + There is one identifier per channel and the number
> > + of supported channels is determined by the length
> > + of this array.
> > +- interrupts SPI interrupts may be listed for notification,
> > + each channel should use a dedicated interrupt
> > + line.
> > +
>
> I think SMC mailbox as mostly unidirectional/Tx only channel. And the
> interrupts here as stated are for notifications, so I prefer to keep
> them separate channel. I assume SMC call return indicates completion.
> Or do you plan to use these interrupts as the indication for completion
> of the command? I see in patch 2/2 the absence of IRQ is anyway dealt
> the way I mention above.
>
> Does it make sense or am I missing something here ?
I think you are right. From a mailbox point of view "completion" means
that the trigger has reached the other side. A returning smc call is a
perfect indication of this fact. Whether the action triggered by this
mailbox command has completed is a totally separate question and out of
the scope of the mailbox. This should be handled by a higher level
protocol (SCPI in this case). Which could mean that this employs a
separate return mailbox channel, which is RX only and implemented by
interrupts. Which could or could not be part of this driver.
Cheers,
Andre
^ permalink raw reply
* [RFC PATCH 18/28] block: Introduce bio_add_dma_addr()
From: Logan Gunthorpe @ 2019-06-20 16:12 UTC (permalink / raw)
To: linux-kernel, linux-block, linux-nvme, linux-pci, linux-rdma
Cc: Jens Axboe, Christoph Hellwig, Bjorn Helgaas, Dan Williams,
Sagi Grimberg, Keith Busch, Jason Gunthorpe, Stephen Bates,
Logan Gunthorpe
In-Reply-To: <20190620161240.22738-1-logang@deltatee.com>
bio_add_dma_addr() is analagous to bio_add_page() except it
adds a dma address to a dma-direct bio instead of a struct page.
It also checks to ensure that the queue supports dma address bios and
that we are not mixing dma addresses and struct pages.
Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
---
block/bio.c | 38 ++++++++++++++++++++++++++++++++++++++
include/linux/bio.h | 10 ++++++++++
2 files changed, 48 insertions(+)
diff --git a/block/bio.c b/block/bio.c
index 6998fceddd36..02ae72e3ccfa 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -874,6 +874,44 @@ static void bio_release_pages(struct bio *bio)
put_page(bvec->bv_page);
}
+/**
+ * bio_add_dma_addr - attempt to add a dma address to a bio
+ * @q: the target queue
+ * @bio: destination bio
+ * @dma_addr: dma address to add
+ * @len: vec entry length
+ *
+ * Attempt to add a dma address to the dma_vec maplist. This can
+ * fail for a number of reasons, such as the bio being full or
+ * target block device limitations. The target request queue must
+ * support dma-only bios and bios can not mix pages and dma_addresses.
+ */
+int bio_add_dma_addr(struct request_queue *q, struct bio *bio,
+ dma_addr_t dma_addr, unsigned int len)
+{
+ struct dma_vec *dv = &bio->bi_dma_vec[bio->bi_vcnt];
+
+ if (!blk_queue_dma_direct(q))
+ return -EINVAL;
+
+ if (!bio_is_dma_direct(bio))
+ return -EINVAL;
+
+ if (bio_dma_full(bio))
+ return 0;
+
+ WARN_ON_ONCE(bio_flagged(bio, BIO_CLONED));
+
+ dv->dv_addr = dma_addr;
+ dv->dv_len = len;
+
+ bio->bi_iter.bi_size += len;
+ bio->bi_vcnt++;
+
+ return len;
+}
+EXPORT_SYMBOL_GPL(bio_add_dma_addr);
+
static int __bio_iov_bvec_add_pages(struct bio *bio, struct iov_iter *iter)
{
const struct bio_vec *bv = iter->bvec;
diff --git a/include/linux/bio.h b/include/linux/bio.h
index df7973932525..d775f381ae00 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -112,6 +112,13 @@ static inline bool bio_full(struct bio *bio)
return bio->bi_vcnt >= bio->bi_max_vecs;
}
+static inline bool bio_dma_full(struct bio *bio)
+{
+ size_t vec_size = bio->bi_max_vecs * sizeof(struct bio_vec);
+
+ return bio->bi_vcnt >= (vec_size / sizeof(struct dma_vec));
+}
+
static inline bool bio_next_segment(const struct bio *bio,
struct bvec_iter_all *iter)
{
@@ -438,6 +445,9 @@ void bio_chain(struct bio *, struct bio *);
extern int bio_add_page(struct bio *, struct page *, unsigned int,unsigned int);
extern int bio_add_pc_page(struct request_queue *, struct bio *, struct page *,
unsigned int, unsigned int);
+extern int bio_add_dma_addr(struct request_queue *q, struct bio *bio,
+ dma_addr_t dma_addr, unsigned int len);
+
bool __bio_try_merge_page(struct bio *bio, struct page *page,
unsigned int len, unsigned int off, bool same_page);
void __bio_add_page(struct bio *bio, struct page *page,
--
2.20.1
^ permalink raw reply related
* [PATCH v3] ARM: dts: qcom: ipq4019: fix high resolution timer
From: Christian Lamparter @ 2019-06-20 16:13 UTC (permalink / raw)
To: linux-arm-msm
Cc: David Brown, Andy Gross, Marc Gonzalez, Bjorn Andersson,
Pavel Kubelun, Sricharan R
From: Abhishek Sahu <absahu@codeaurora.org>
The kernel is not switching the timer to the high resolution
mode and clock source keeps operating in with a just a lousy
10ms resolution.
The always-on property needs to be given for xo clock source
(which is the sole external oscillator) in the device tree
node to get to the 1ns high resolution mode.
Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
Signed-off-by: Pavel Kubelun <be.dissent@gmail.com>
Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
---
v3: fixed empty line, removed changeid reference and fluff,
reworded message.
v2: fixed subject [Abhishek Sahu is bouncing]
---
arch/arm/boot/dts/qcom-ipq4019.dtsi | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/boot/dts/qcom-ipq4019.dtsi b/arch/arm/boot/dts/qcom-ipq4019.dtsi
index bbcb7db810f7..0e3e79442c50 100644
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
@@ -169,6 +169,7 @@
<1 4 0xf08>,
<1 1 0xf08>;
clock-frequency = <48000000>;
+ always-on;
};
soc {
--
2.20.1
^ permalink raw reply related
* [RFC PATCH 28/28] memremap: Remove PCI P2PDMA page memory type
From: Logan Gunthorpe @ 2019-06-20 16:12 UTC (permalink / raw)
To: linux-kernel, linux-block, linux-nvme, linux-pci, linux-rdma
Cc: Jens Axboe, Christoph Hellwig, Bjorn Helgaas, Dan Williams,
Sagi Grimberg, Keith Busch, Jason Gunthorpe, Stephen Bates,
Logan Gunthorpe
In-Reply-To: <20190620161240.22738-1-logang@deltatee.com>
There are no more users of MEMORY_DEVICE_PCI_P2PDMA and
is_pci_p2pdma_page(), so remove them.
Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
---
include/linux/memremap.h | 5 -----
include/linux/mm.h | 13 -------------
2 files changed, 18 deletions(-)
diff --git a/include/linux/memremap.h b/include/linux/memremap.h
index 1732dea030b2..2e5d9fcd4d69 100644
--- a/include/linux/memremap.h
+++ b/include/linux/memremap.h
@@ -51,16 +51,11 @@ 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,
};
/*
diff --git a/include/linux/mm.h b/include/linux/mm.h
index dd0b5f4e1e45..f5fa9ec440e3 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -966,19 +966,6 @@ 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)
{
--
2.20.1
^ permalink raw reply related
* [RFC PATCH 19/28] nvme-pci: Support dma-direct bios
From: Logan Gunthorpe @ 2019-06-20 16:12 UTC (permalink / raw)
To: linux-kernel, linux-block, linux-nvme, linux-pci, linux-rdma
Cc: Jens Axboe, Christoph Hellwig, Bjorn Helgaas, Dan Williams,
Sagi Grimberg, Keith Busch, Jason Gunthorpe, Stephen Bates,
Logan Gunthorpe
In-Reply-To: <20190620161240.22738-1-logang@deltatee.com>
Adding support for dma-direct bios only requires putting a condition
around the call to dma_map_sg() so it is skipped when the request
has the REQ_DMA_ADDR flag.
We then need to indicate support for the queue in much the same way
we did with PCI P2PDMA. Seeing this provides the same support as
PCI P2PDMA those flags will be removed in a subsequent patch.
Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
---
drivers/nvme/host/core.c | 2 ++
drivers/nvme/host/nvme.h | 1 +
drivers/nvme/host/pci.c | 10 +++++++---
3 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 120fb593d1da..8e876417c44b 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -3259,6 +3259,8 @@ static int nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
blk_queue_flag_set(QUEUE_FLAG_NONROT, ns->queue);
if (ctrl->ops->flags & NVME_F_PCI_P2PDMA)
blk_queue_flag_set(QUEUE_FLAG_PCI_P2PDMA, ns->queue);
+ if (ctrl->ops->flags & NVME_F_DMA_DIRECT)
+ blk_queue_flag_set(QUEUE_FLAG_DMA_DIRECT, ns->queue);
ns->queue->queuedata = ns;
ns->ctrl = ctrl;
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index 55553d293a98..f1dddc95c6a8 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -362,6 +362,7 @@ struct nvme_ctrl_ops {
#define NVME_F_FABRICS (1 << 0)
#define NVME_F_METADATA_SUPPORTED (1 << 1)
#define NVME_F_PCI_P2PDMA (1 << 2)
+#define NVME_F_DMA_DIRECT (1 << 3)
int (*reg_read32)(struct nvme_ctrl *ctrl, u32 off, u32 *val);
int (*reg_write32)(struct nvme_ctrl *ctrl, u32 off, u32 val);
int (*reg_read64)(struct nvme_ctrl *ctrl, u32 off, u64 *val);
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 524d6bd6d095..5957f3a4f261 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -565,7 +565,8 @@ static void nvme_unmap_data(struct nvme_dev *dev, struct request *req)
WARN_ON_ONCE(!iod->nents);
/* P2PDMA requests do not need to be unmapped */
- if (!is_pci_p2pdma_page(sg_page(iod->sg)))
+ if (!is_pci_p2pdma_page(sg_page(iod->sg)) &&
+ !blk_rq_is_dma_direct(req))
dma_unmap_sg(dev->dev, iod->sg, iod->nents, rq_dma_dir(req));
@@ -824,7 +825,7 @@ static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req,
blk_status_t ret = BLK_STS_RESOURCE;
int nr_mapped;
- if (blk_rq_nr_phys_segments(req) == 1) {
+ if (blk_rq_nr_phys_segments(req) == 1 && !blk_rq_is_dma_direct(req)) {
struct bio_vec bv = req_bvec(req);
if (!is_pci_p2pdma_page(bv.bv_page)) {
@@ -851,6 +852,8 @@ static blk_status_t nvme_map_data(struct nvme_dev *dev, struct request *req,
if (is_pci_p2pdma_page(sg_page(iod->sg)))
nr_mapped = pci_p2pdma_map_sg(dev->dev, iod->sg, iod->nents,
rq_dma_dir(req));
+ else if (blk_rq_is_dma_direct(req))
+ nr_mapped = iod->nents;
else
nr_mapped = dma_map_sg_attrs(dev->dev, iod->sg, iod->nents,
rq_dma_dir(req), DMA_ATTR_NO_WARN);
@@ -2639,7 +2642,8 @@ static const struct nvme_ctrl_ops nvme_pci_ctrl_ops = {
.name = "pcie",
.module = THIS_MODULE,
.flags = NVME_F_METADATA_SUPPORTED |
- NVME_F_PCI_P2PDMA,
+ NVME_F_PCI_P2PDMA |
+ NVME_F_DMA_DIRECT,
.reg_read32 = nvme_pci_reg_read32,
.reg_write32 = nvme_pci_reg_write32,
.reg_read64 = nvme_pci_reg_read64,
--
2.20.1
^ permalink raw reply related
* [RFC PATCH 07/28] block: Use dma_vec length in bio_cur_bytes() for dma-direct bios
From: Logan Gunthorpe @ 2019-06-20 16:12 UTC (permalink / raw)
To: linux-kernel, linux-block, linux-nvme, linux-pci, linux-rdma
Cc: Jens Axboe, Christoph Hellwig, Bjorn Helgaas, Dan Williams,
Sagi Grimberg, Keith Busch, Jason Gunthorpe, Stephen Bates,
Logan Gunthorpe
In-Reply-To: <20190620161240.22738-1-logang@deltatee.com>
For dma-direct bios, use the dv_len of the current vector
seeing the bio_vec's are not valid in such a context.
Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
---
include/linux/bio.h | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/include/linux/bio.h b/include/linux/bio.h
index e212e5958a75..df7973932525 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -91,10 +91,12 @@ static inline bool bio_mergeable(struct bio *bio)
static inline unsigned int bio_cur_bytes(struct bio *bio)
{
- if (bio_has_data(bio))
- return bio_iovec(bio).bv_len;
- else /* dataless requests such as discard */
+ if (!bio_has_data(bio)) /* dataless requests such as discard */
return bio->bi_iter.bi_size;
+ else if (op_is_dma_direct(bio->bi_opf))
+ return bio_dma_vec(bio).dv_len;
+ else
+ return bio_iovec(bio).bv_len;
}
static inline void *bio_data(struct bio *bio)
--
2.20.1
^ permalink raw reply related
* [RFC PATCH 14/28] block: Support splitting dma-direct bios
From: Logan Gunthorpe @ 2019-06-20 16:12 UTC (permalink / raw)
To: linux-kernel, linux-block, linux-nvme, linux-pci, linux-rdma
Cc: Jens Axboe, Christoph Hellwig, Bjorn Helgaas, Dan Williams,
Sagi Grimberg, Keith Busch, Jason Gunthorpe, Stephen Bates,
Logan Gunthorpe
In-Reply-To: <20190620161240.22738-1-logang@deltatee.com>
If the bio is a dma-direct bio, loop through the dma_vecs instead
of the bio_vecs when calling vec_should_split().
Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
---
block/blk-merge.c | 45 +++++++++++++++++++++++++++++++++++++--------
1 file changed, 37 insertions(+), 8 deletions(-)
diff --git a/block/blk-merge.c b/block/blk-merge.c
index 32653fca53ce..c4c016f994f6 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -257,14 +257,44 @@ static bool vec_should_split(struct request_queue *q, unsigned offset,
return false;
}
+static bool bio_should_split(struct request_queue *q, struct bio *bio,
+ struct blk_segment_split_ctx *ctx)
+{
+ struct bvec_iter iter;
+ struct bio_vec bv;
+ bool ret;
+
+ bio_for_each_bvec(bv, bio, iter) {
+ ret = vec_should_split(q, bv.bv_offset, bv.bv_len, ctx);
+ if (ret)
+ return true;
+ }
+
+ return false;
+}
+
+static bool bio_dma_should_split(struct request_queue *q, struct bio *bio,
+ struct blk_segment_split_ctx *ctx)
+{
+ struct bvec_iter iter;
+ struct dma_vec dv;
+ bool ret;
+
+ bio_for_each_dvec(dv, bio, iter) {
+ ret = vec_should_split(q, dv.dv_addr, dv.dv_len, ctx);
+ if (ret)
+ return true;
+ }
+
+ return false;
+}
+
static struct bio *blk_bio_segment_split(struct request_queue *q,
struct bio *bio,
struct bio_set *bs,
unsigned *segs)
{
- struct bio_vec bv;
- struct bvec_iter iter;
- bool do_split = false;
+ bool do_split;
struct bio *new = NULL;
struct blk_segment_split_ctx ctx = {
@@ -272,11 +302,10 @@ static struct bio *blk_bio_segment_split(struct request_queue *q,
.max_segs = queue_max_segments(q),
};
- bio_for_each_bvec(bv, bio, iter) {
- do_split = vec_should_split(q, bv.bv_offset, bv.bv_len, &ctx);
- if (do_split)
- break;
- }
+ if (bio_is_dma_direct(bio))
+ do_split = bio_dma_should_split(q, bio, &ctx);
+ else
+ do_split = bio_should_split(q, bio, &ctx);
*segs = ctx.nsegs;
--
2.20.1
^ permalink raw reply related
* Re: [dpdk-dev] [PATCH v4 8/8] app/testpmd: use rte_ether_unformat_addr
From: Stephen Hemminger @ 2019-06-20 16:12 UTC (permalink / raw)
To: Iremonger, Bernard; +Cc: dev@dpdk.org
In-Reply-To: <8CEF83825BEC744B83065625E567D7C260DB9597@IRSMSX108.ger.corp.intel.com>
On Thu, 20 Jun 2019 14:18:18 +0000
"Iremonger, Bernard" <bernard.iremonger@intel.com> wrote:
> Hi Stephen,
>
> > -----Original Message-----
> > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Stephen
> > Hemminger
> > Sent: Wednesday, June 5, 2019 7:10 PM
> > To: dev@dpdk.org
> > Cc: Stephen Hemminger <stephen@networkplumber.org>
> > Subject: [dpdk-dev] [PATCH v4 8/8] app/testpmd: use
> > rte_ether_unformat_addr
> >
> > The cmdline_parse_ether_addr does not need to be used everywhere in
> > testpmd. Can use rte_ether_unformat_addr instead.
> > As an added bonus it eliminates some code for copying.
> >
> > Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> > ---
> > app/test-pmd/cmdline_flow.c | 5 ++---
> > app/test-pmd/config.c | 10 +++-------
> > app/test-pmd/parameters.c | 15 +++------------
> > 3 files changed, 8 insertions(+), 22 deletions(-)
> >
> > diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c
> > index 201bd9de56e0..2b02ca29b7ac 100644
> > --- a/app/test-pmd/cmdline_flow.c
> > +++ b/app/test-pmd/cmdline_flow.c
> > @@ -18,7 +18,6 @@
> > #include <rte_ethdev.h>
> > #include <rte_byteorder.h>
> > #include <cmdline_parse.h>
> > -#include <cmdline_parse_etheraddr.h>
> > #include <rte_flow.h>
> >
> > #include "testpmd.h"
> > @@ -4627,8 +4626,8 @@ parse_mac_addr(struct context *ctx, const struct
> > token *token,
> > /* Only network endian is supported. */
> > if (!arg->hton)
> > goto error;
> > - ret = cmdline_parse_etheraddr(NULL, str, &tmp, size);
> > - if (ret < 0 || (unsigned int)ret != len)
> > + ret = rte_ether_unformat_addr(str, &tmp);
> > + if (ret < 0)
> > goto error;
> > if (!ctx->object)
> > return len;
> > diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c index
> > ab458c8d2837..1d804705d96c 100644
> > --- a/app/test-pmd/config.c
> > +++ b/app/test-pmd/config.c
> > @@ -49,7 +49,6 @@
> > #include <rte_pmd_bnxt.h>
> > #endif
> > #include <rte_gro.h>
> > -#include <cmdline_parse_etheraddr.h>
> > #include <rte_config.h>
> >
> > #include "testpmd.h"
> > @@ -2278,19 +2277,16 @@ pkt_fwd_config_display(struct fwd_config *cfg)
> > void set_fwd_eth_peer(portid_t port_id, char *peer_addr) {
> > - uint8_t c, new_peer_addr[6];
> > + struct rte_ether_addr new_peer_addr;
> > if (!rte_eth_dev_is_valid_port(port_id)) {
> > printf("Error: Invalid port number %i\n", port_id);
> > return;
> > }
> > - if (cmdline_parse_etheraddr(NULL, peer_addr, &new_peer_addr,
> > - sizeof(new_peer_addr)) < 0) {
> > + if (rte_ether_unformat_addr(peer_addr, &new_peer_addr) < 0) {
> > printf("Error: Invalid ethernet address: %s\n", peer_addr);
> > return;
> > }
> > - for (c = 0; c < 6; c++)
> > - peer_eth_addrs[port_id].addr_bytes[c] =
> > - new_peer_addr[c];
> > + peer_eth_addrs[port_id] = new_peer_addr;
> > }
> >
> > int
> > diff --git a/app/test-pmd/parameters.c b/app/test-pmd/parameters.c index
> > 245b610641ee..975a97807009 100644
> > --- a/app/test-pmd/parameters.c
> > +++ b/app/test-pmd/parameters.c
> > @@ -39,10 +39,6 @@
> > #include <rte_ether.h>
> > #include <rte_ethdev.h>
> > #include <rte_string_fns.h>
> > -#ifdef RTE_LIBRTE_CMDLINE
> > -#include <cmdline_parse.h>
> > -#include <cmdline_parse_etheraddr.h>
> > -#endif
> > #ifdef RTE_LIBRTE_PMD_BOND
> > #include <rte_eth_bond.h>
> > #endif
> > @@ -227,8 +223,7 @@ init_peer_eth_addrs(char *config_filename)
> > if (fgets(buf, sizeof(buf), config_file) == NULL)
> > break;
> >
> > - if (cmdline_parse_etheraddr(NULL, buf,
> > &peer_eth_addrs[i],
> > - sizeof(peer_eth_addrs[i])) < 0) {
> > + if (rte_ether_unformat_addr(buf, &peer_eth_addrs[i]) < 0) {
> > printf("Bad MAC address format on line %d\n", i+1);
> > fclose(config_file);
> > return -1;
> > @@ -727,7 +722,6 @@ launch_args_parse(int argc, char** argv)
> > }
> > if (!strcmp(lgopts[opt_idx].name, "eth-peer")) {
> > char *port_end;
> > - uint8_t c, peer_addr[6];
> >
> > errno = 0;
> > n = strtoul(optarg, &port_end, 10); @@ -
> > 739,14 +733,11 @@ launch_args_parse(int argc, char** argv)
> > "eth-peer: port %d >=
> > RTE_MAX_ETHPORTS(%d)\n",
> > n, RTE_MAX_ETHPORTS);
> >
> > - if (cmdline_parse_etheraddr(NULL,
> > port_end,
> > - &peer_addr,
> > sizeof(peer_addr)) < 0)
> > + if (rte_ether_unformat_addr(port_end,
> > +
> > &peer_eth_addrs[n]) < 0)
> > rte_exit(EXIT_FAILURE,
> > "Invalid ethernet address:
> > %s\n",
> > port_end);
> > - for (c = 0; c < 6; c++)
> > - peer_eth_addrs[n].addr_bytes[c] =
> > - peer_addr[c];
> > nb_peer_eth_addrs++;
> > }
> > #endif
> > --
> > 2.20.1
>
> ./devtools/check-git-log.sh -1
> Wrong headline format:
> app/testpmd: use rte_ether_unformat_addr
>
> Does not like the "_" in the commit message.
> This also affects four of the other patches in the set.
The tool is broken, not the patch.
This is not a restriction in other projects.
> /devtools/checkpatches.sh v4-8-8-app-testpmd-use-rte_ether_unformat_addr.patch
>
> WARNING:LONG_LINE: line over 80 characters
> #125: FILE: app/test-pmd/parameters.c:737:
> + &peer_eth_addrs[n]) < 0)
>
> total: 0 errors, 1 warnings, 88 lines checked
>
> Long line should probably be fixed.
The pre-existing code had a long line already.
^ permalink raw reply
* [RFC PATCH 28/28] memremap: Remove PCI P2PDMA page memory type
From: Logan Gunthorpe @ 2019-06-20 16:12 UTC (permalink / raw)
In-Reply-To: <20190620161240.22738-1-logang@deltatee.com>
There are no more users of MEMORY_DEVICE_PCI_P2PDMA and
is_pci_p2pdma_page(), so remove them.
Signed-off-by: Logan Gunthorpe <logang at deltatee.com>
---
include/linux/memremap.h | 5 -----
include/linux/mm.h | 13 -------------
2 files changed, 18 deletions(-)
diff --git a/include/linux/memremap.h b/include/linux/memremap.h
index 1732dea030b2..2e5d9fcd4d69 100644
--- a/include/linux/memremap.h
+++ b/include/linux/memremap.h
@@ -51,16 +51,11 @@ 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,
};
/*
diff --git a/include/linux/mm.h b/include/linux/mm.h
index dd0b5f4e1e45..f5fa9ec440e3 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -966,19 +966,6 @@ 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)
{
--
2.20.1
^ permalink raw reply related
* [RFC PATCH 27/28] PCI/P2PDMA: Remove struct pages that back P2PDMA memory
From: Logan Gunthorpe @ 2019-06-20 16:12 UTC (permalink / raw)
In-Reply-To: <20190620161240.22738-1-logang@deltatee.com>
There are no more users of the struct pages that back P2P memory,
so convert the devm_memremap_pages() call to devm_memremap() to remove
them.
The percpu_ref and completion are retained in struct p2pdma to track
when there is no memory allocated out of the genpool and it is safe
to free it.
Signed-off-by: Logan Gunthorpe <logang at deltatee.com>
---
drivers/pci/p2pdma.c | 107 +++++++++++++------------------------------
1 file changed, 33 insertions(+), 74 deletions(-)
diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c
index 9b82e13f802c..83d93911f792 100644
--- a/drivers/pci/p2pdma.c
+++ b/drivers/pci/p2pdma.c
@@ -22,10 +22,6 @@
struct pci_p2pdma {
struct gen_pool *pool;
bool p2pmem_published;
-};
-
-struct p2pdma_pagemap {
- struct dev_pagemap pgmap;
struct percpu_ref ref;
struct completion ref_done;
};
@@ -78,29 +74,12 @@ static const struct attribute_group p2pmem_group = {
.name = "p2pmem",
};
-static struct p2pdma_pagemap *to_p2p_pgmap(struct percpu_ref *ref)
-{
- return container_of(ref, struct p2pdma_pagemap, ref);
-}
-
static void pci_p2pdma_percpu_release(struct percpu_ref *ref)
{
- struct p2pdma_pagemap *p2p_pgmap = to_p2p_pgmap(ref);
+ struct pci_p2pdma *p2pdma =
+ container_of(ref, struct pci_p2pdma, ref);
- complete(&p2p_pgmap->ref_done);
-}
-
-static void pci_p2pdma_percpu_kill(struct percpu_ref *ref)
-{
- percpu_ref_kill(ref);
-}
-
-static void pci_p2pdma_percpu_cleanup(struct percpu_ref *ref)
-{
- struct p2pdma_pagemap *p2p_pgmap = to_p2p_pgmap(ref);
-
- wait_for_completion(&p2p_pgmap->ref_done);
- percpu_ref_exit(&p2p_pgmap->ref);
+ complete(&p2pdma->ref_done);
}
static void pci_p2pdma_release(void *data)
@@ -111,6 +90,10 @@ static void pci_p2pdma_release(void *data)
if (!p2pdma)
return;
+ percpu_ref_kill(&p2pdma->ref);
+ wait_for_completion(&p2pdma->ref_done);
+ percpu_ref_exit(&p2pdma->ref);
+
/* Flush and disable pci_alloc_p2p_mem() */
pdev->p2pdma = NULL;
synchronize_rcu();
@@ -128,10 +111,17 @@ static int pci_p2pdma_setup(struct pci_dev *pdev)
if (!p2p)
return -ENOMEM;
+ init_completion(&p2p->ref_done);
+
p2p->pool = gen_pool_create(PAGE_SHIFT, dev_to_node(&pdev->dev));
if (!p2p->pool)
goto out;
+ error = percpu_ref_init(&p2p->ref, pci_p2pdma_percpu_release, 0,
+ GFP_KERNEL);
+ if (error)
+ goto out_pool_destroy;
+
error = devm_add_action_or_reset(&pdev->dev, pci_p2pdma_release, pdev);
if (error)
goto out_pool_destroy;
@@ -165,8 +155,7 @@ static int pci_p2pdma_setup(struct pci_dev *pdev)
int pci_p2pdma_add_resource(struct pci_dev *pdev, int bar, size_t size,
u64 offset)
{
- struct p2pdma_pagemap *p2p_pgmap;
- struct dev_pagemap *pgmap;
+ struct resource res;
void *addr;
int error;
@@ -188,50 +177,26 @@ int pci_p2pdma_add_resource(struct pci_dev *pdev, int bar, size_t size,
return error;
}
- p2p_pgmap = devm_kzalloc(&pdev->dev, sizeof(*p2p_pgmap), GFP_KERNEL);
- if (!p2p_pgmap)
- return -ENOMEM;
+ res.start = pci_resource_start(pdev, bar) + offset;
+ res.end = res.start + size - 1;
+ res.flags = pci_resource_flags(pdev, bar);
- init_completion(&p2p_pgmap->ref_done);
- error = percpu_ref_init(&p2p_pgmap->ref,
- pci_p2pdma_percpu_release, 0, GFP_KERNEL);
- if (error)
- goto pgmap_free;
-
- pgmap = &p2p_pgmap->pgmap;
-
- pgmap->res.start = pci_resource_start(pdev, bar) + offset;
- pgmap->res.end = pgmap->res.start + size - 1;
- pgmap->res.flags = pci_resource_flags(pdev, bar);
- pgmap->ref = &p2p_pgmap->ref;
- pgmap->type = MEMORY_DEVICE_PCI_P2PDMA;
- pgmap->pci_p2pdma_bus_offset = pci_bus_address(pdev, bar) -
- pci_resource_start(pdev, bar);
- pgmap->kill = pci_p2pdma_percpu_kill;
- pgmap->cleanup = pci_p2pdma_percpu_cleanup;
-
- addr = devm_memremap_pages(&pdev->dev, pgmap);
- if (IS_ERR(addr)) {
- error = PTR_ERR(addr);
- goto pgmap_free;
- }
+ addr = devm_memremap(&pdev->dev, res.start, size, MEMREMAP_WC);
+ if (IS_ERR(addr))
+ return PTR_ERR(addr);
- error = gen_pool_add_owner(pdev->p2pdma->pool, (unsigned long)addr,
- pci_bus_address(pdev, bar) + offset,
- resource_size(&pgmap->res), dev_to_node(&pdev->dev),
- &p2p_pgmap->ref);
+ error = gen_pool_add_virt(pdev->p2pdma->pool, (unsigned long)addr,
+ pci_bus_address(pdev, bar) + offset, size,
+ dev_to_node(&pdev->dev));
if (error)
goto pages_free;
- pci_info(pdev, "added peer-to-peer DMA memory %pR\n",
- &pgmap->res);
+ pci_info(pdev, "added peer-to-peer DMA memory %pR\n", &res);
return 0;
pages_free:
- devm_memunmap_pages(&pdev->dev, pgmap);
-pgmap_free:
- devm_kfree(&pdev->dev, p2p_pgmap);
+ devm_memunmap(&pdev->dev, addr);
return error;
}
EXPORT_SYMBOL_GPL(pci_p2pdma_add_resource);
@@ -601,7 +566,6 @@ EXPORT_SYMBOL_GPL(pci_p2pmem_find_many);
void *pci_alloc_p2pmem(struct pci_dev *pdev, size_t size)
{
void *ret = NULL;
- struct percpu_ref *ref;
/*
* Pairs with synchronize_rcu() in pci_p2pdma_release() to
@@ -612,16 +576,13 @@ void *pci_alloc_p2pmem(struct pci_dev *pdev, size_t size)
if (unlikely(!pdev->p2pdma))
goto out;
- ret = (void *)gen_pool_alloc_owner(pdev->p2pdma->pool, size,
- (void **) &ref);
- if (!ret)
+ if (unlikely(!percpu_ref_tryget_live(&pdev->p2pdma->ref)))
goto out;
- if (unlikely(!percpu_ref_tryget_live(ref))) {
- gen_pool_free(pdev->p2pdma->pool, (unsigned long) ret, size);
- ret = NULL;
- goto out;
- }
+ ret = (void *)gen_pool_alloc(pdev->p2pdma->pool, size);
+ if (!ret)
+ percpu_ref_put(&pdev->p2pdma->ref);
+
out:
rcu_read_unlock();
return ret;
@@ -636,11 +597,9 @@ EXPORT_SYMBOL_GPL(pci_alloc_p2pmem);
*/
void pci_free_p2pmem(struct pci_dev *pdev, void *addr, size_t size)
{
- struct percpu_ref *ref;
+ gen_pool_free(pdev->p2pdma->pool, (uintptr_t)addr, size);
- gen_pool_free_owner(pdev->p2pdma->pool, (uintptr_t)addr, size,
- (void **) &ref);
- percpu_ref_put(ref);
+ percpu_ref_put(&pdev->p2pdma->ref);
}
EXPORT_SYMBOL_GPL(pci_free_p2pmem);
--
2.20.1
^ permalink raw reply related
* [RFC PATCH 26/28] PCI/P2PDMA: Remove SGL helpers
From: Logan Gunthorpe @ 2019-06-20 16:12 UTC (permalink / raw)
In-Reply-To: <20190620161240.22738-1-logang@deltatee.com>
The functions, pci_p2pmem_alloc_sgl(), pci_p2pmem_free_sgl() and
pci_p2pdma_map_sg() no longer have any callers, so remove them.
Signed-off-by: Logan Gunthorpe <logang at deltatee.com>
---
Documentation/driver-api/pci/p2pdma.rst | 9 +--
drivers/pci/p2pdma.c | 95 -------------------------
include/linux/pci-p2pdma.h | 19 -----
3 files changed, 3 insertions(+), 120 deletions(-)
diff --git a/Documentation/driver-api/pci/p2pdma.rst b/Documentation/driver-api/pci/p2pdma.rst
index 44deb52beeb4..5b19c420d921 100644
--- a/Documentation/driver-api/pci/p2pdma.rst
+++ b/Documentation/driver-api/pci/p2pdma.rst
@@ -84,9 +84,8 @@ Client Drivers
--------------
A client driver typically only has to conditionally change its DMA map
-routine to use the mapping function :c:func:`pci_p2pdma_map_sg()` instead
-of the usual :c:func:`dma_map_sg()` function. Memory mapped in this
-way does not need to be unmapped.
+routine to use the PCI bus address with :c:func:`pci_p2pmem_virt_to_bus()`
+for the DMA address instead of the usual :c:func:`dma_map_sg()` function.
The client may also, optionally, make use of
:c:func:`is_pci_p2pdma_page()` to determine when to use the P2P mapping
@@ -117,9 +116,7 @@ returned with pci_dev_put().
Once a provider is selected, the orchestrator can then use
:c:func:`pci_alloc_p2pmem()` and :c:func:`pci_free_p2pmem()` to
-allocate P2P memory from the provider. :c:func:`pci_p2pmem_alloc_sgl()`
-and :c:func:`pci_p2pmem_free_sgl()` are convenience functions for
-allocating scatter-gather lists with P2P memory.
+allocate P2P memory from the provider.
Struct Page Caveats
-------------------
diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c
index a98126ad9c3a..9b82e13f802c 100644
--- a/drivers/pci/p2pdma.c
+++ b/drivers/pci/p2pdma.c
@@ -666,60 +666,6 @@ pci_bus_addr_t pci_p2pmem_virt_to_bus(struct pci_dev *pdev, void *addr)
}
EXPORT_SYMBOL_GPL(pci_p2pmem_virt_to_bus);
-/**
- * pci_p2pmem_alloc_sgl - allocate peer-to-peer DMA memory in a scatterlist
- * @pdev: the device to allocate memory from
- * @nents: the number of SG entries in the list
- * @length: number of bytes to allocate
- *
- * Return: %NULL on error or &struct scatterlist pointer and @nents on success
- */
-struct scatterlist *pci_p2pmem_alloc_sgl(struct pci_dev *pdev,
- unsigned int *nents, u32 length)
-{
- struct scatterlist *sg;
- void *addr;
-
- sg = kzalloc(sizeof(*sg), GFP_KERNEL);
- if (!sg)
- return NULL;
-
- sg_init_table(sg, 1);
-
- addr = pci_alloc_p2pmem(pdev, length);
- if (!addr)
- goto out_free_sg;
-
- sg_set_buf(sg, addr, length);
- *nents = 1;
- return sg;
-
-out_free_sg:
- kfree(sg);
- return NULL;
-}
-EXPORT_SYMBOL_GPL(pci_p2pmem_alloc_sgl);
-
-/**
- * pci_p2pmem_free_sgl - free a scatterlist allocated by pci_p2pmem_alloc_sgl()
- * @pdev: the device to allocate memory from
- * @sgl: the allocated scatterlist
- */
-void pci_p2pmem_free_sgl(struct pci_dev *pdev, struct scatterlist *sgl)
-{
- struct scatterlist *sg;
- int count;
-
- for_each_sg(sgl, sg, INT_MAX, count) {
- if (!sg)
- break;
-
- pci_free_p2pmem(pdev, sg_virt(sg), sg->length);
- }
- kfree(sgl);
-}
-EXPORT_SYMBOL_GPL(pci_p2pmem_free_sgl);
-
/**
* pci_p2pmem_publish - publish the peer-to-peer DMA memory for use by
* other devices with pci_p2pmem_find()
@@ -738,47 +684,6 @@ void pci_p2pmem_publish(struct pci_dev *pdev, bool publish)
}
EXPORT_SYMBOL_GPL(pci_p2pmem_publish);
-/**
- * pci_p2pdma_map_sg - map a PCI peer-to-peer scatterlist for DMA
- * @dev: device doing the DMA request
- * @sg: scatter list to map
- * @nents: elements in the scatterlist
- * @dir: DMA direction
- *
- * Scatterlists mapped with this function should not be unmapped in any way.
- *
- * Returns the number of SG entries mapped or 0 on error.
- */
-int pci_p2pdma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
- enum dma_data_direction dir)
-{
- struct dev_pagemap *pgmap;
- struct scatterlist *s;
- phys_addr_t paddr;
- int i;
-
- /*
- * p2pdma mappings are not compatible with devices that use
- * dma_virt_ops. If the upper layers do the right thing
- * this should never happen because it will be prevented
- * by the check in pci_p2pdma_add_client()
- */
- if (WARN_ON_ONCE(IS_ENABLED(CONFIG_DMA_VIRT_OPS) &&
- dev->dma_ops == &dma_virt_ops))
- return 0;
-
- for_each_sg(sg, s, nents, i) {
- pgmap = sg_page(s)->pgmap;
- paddr = sg_phys(s);
-
- s->dma_address = paddr - pgmap->pci_p2pdma_bus_offset;
- sg_dma_len(s) = s->length;
- }
-
- return nents;
-}
-EXPORT_SYMBOL_GPL(pci_p2pdma_map_sg);
-
/**
* pci_p2pdma_enable_store - parse a configfs/sysfs attribute store
* to enable p2pdma
diff --git a/include/linux/pci-p2pdma.h b/include/linux/pci-p2pdma.h
index bca9bc3e5be7..4a75a3f43444 100644
--- a/include/linux/pci-p2pdma.h
+++ b/include/linux/pci-p2pdma.h
@@ -26,12 +26,7 @@ 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,
@@ -69,23 +64,9 @@ static inline pci_bus_addr_t pci_p2pmem_virt_to_bus(struct pci_dev *pdev,
{
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)
{
--
2.20.1
^ permalink raw reply related
* [RFC PATCH 25/28] IB/core: Remove P2PDMA mapping support in rdma_rw_ctx
From: Logan Gunthorpe @ 2019-06-20 16:12 UTC (permalink / raw)
In-Reply-To: <20190620161240.22738-1-logang@deltatee.com>
There are no longer any users submitting P2PDMA struct pages to
rdma_rw_ctx. So it can be removed.
Signed-off-by: Logan Gunthorpe <logang at deltatee.com>
---
drivers/infiniband/core/rw.c | 11 ++---------
1 file changed, 2 insertions(+), 9 deletions(-)
diff --git a/drivers/infiniband/core/rw.c b/drivers/infiniband/core/rw.c
index cefa6b930bc8..350b9b730ddc 100644
--- a/drivers/infiniband/core/rw.c
+++ b/drivers/infiniband/core/rw.c
@@ -4,7 +4,6 @@
*/
#include <linux/moduleparam.h>
#include <linux/slab.h>
-#include <linux/pci-p2pdma.h>
#include <rdma/mr_pool.h>
#include <rdma/rw.h>
@@ -271,11 +270,7 @@ int rdma_rw_ctx_init(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u8 port_num,
struct ib_device *dev = qp->pd->device;
int ret;
- if (is_pci_p2pdma_page(sg_page(sg)))
- ret = pci_p2pdma_map_sg(dev->dma_device, sg, sg_cnt, dir);
- else
- ret = ib_dma_map_sg(dev, sg, sg_cnt, dir);
-
+ ret = ib_dma_map_sg(dev, sg, sg_cnt, dir);
if (!ret)
return -ENOMEM;
sg_cnt = ret;
@@ -635,9 +630,7 @@ void rdma_rw_ctx_destroy(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u8 port_num,
{
__rdma_rw_ctx_destroy(ctx, qp);
- /* P2PDMA contexts do not need to be unmapped */
- if (!is_pci_p2pdma_page(sg_page(sg)))
- ib_dma_unmap_sg(qp->pd->device, sg, sg_cnt, dir);
+ ib_dma_unmap_sg(qp->pd->device, sg, sg_cnt, dir);
}
EXPORT_SYMBOL(rdma_rw_ctx_destroy);
--
2.20.1
^ permalink raw reply related
* [RFC PATCH 24/28] block: Remove PCI_P2PDMA queue flag
From: Logan Gunthorpe @ 2019-06-20 16:12 UTC (permalink / raw)
In-Reply-To: <20190620161240.22738-1-logang@deltatee.com>
This flag has been superseded by the DMA_DIRECT functionality.
Signed-off-by: Logan Gunthorpe <logang at deltatee.com>
---
include/linux/blkdev.h | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index a5b856324276..9ea800645cf5 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -615,8 +615,7 @@ struct request_queue {
#define QUEUE_FLAG_REGISTERED 22 /* queue has been registered to a disk */
#define QUEUE_FLAG_SCSI_PASSTHROUGH 23 /* queue supports SCSI commands */
#define QUEUE_FLAG_QUIESCED 24 /* queue has been quiesced */
-#define QUEUE_FLAG_PCI_P2PDMA 25 /* device supports PCI p2p requests */
-#define QUEUE_FLAG_DMA_DIRECT 26 /* device supports dma-addr requests */
+#define QUEUE_FLAG_DMA_DIRECT 25 /* device supports dma-addr requests */
#define QUEUE_FLAG_MQ_DEFAULT ((1 << QUEUE_FLAG_IO_STAT) | \
(1 << QUEUE_FLAG_SAME_COMP))
@@ -641,8 +640,6 @@ bool blk_queue_flag_test_and_set(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_queue_dma_direct(q) \
test_bit(QUEUE_FLAG_DMA_DIRECT, &(q)->queue_flags)
--
2.20.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.