>> +static void nvme_pci_sgl_set_data_addr(struct nvme_sgl_desc *sge,
>> +                                   dma_addr_t addr, u32 len)
>> +{
>> +    sge->addr = cpu_to_le64(addr);
>> +    sge->length = cpu_to_le32(len);
>> +    sge->type = NVME_SGL_FMT_DATA_DESC << 4;
>> +}
>> +
>>   static void nvme_pci_sgl_set_data(struct nvme_sgl_desc *sge,
>>              struct blk_dma_iter *iter)
>>   {
>> -    sge->addr = cpu_to_le64(iter->addr);
>> -    sge->length = cpu_to_le32(iter->len);
>> -    sge->type = NVME_SGL_FMT_DATA_DESC << 4;
>> +    nvme_pci_sgl_set_data_addr(sge, iter->addr, iter->len);
>>   }
> 
> The naming is a bit confusing (and me passing the iter to
> nvme_pci_sgl_set_data is probably at faul for that).  So maybe
> spin out a prep patch to rename the old nvme_pci_sgl_set_data
> to nvme_pci_dma_iter_set_sgl or so, and then add the new one
> as nvme_pci_sgl_set_data (as before the dma_iter conversion).
>

Thanks for the detailed review! Will split the rename into a prep patch.

>>
>> +static unsigned int nvme_pci_dmabuf_sgl_nents(struct request *req,
>> +                                          dma_addr_t *first_dma,
>> +                                          u32 *first_len)
> 
> This is a really good example why the aligning to the opening braces
> produces totally unreadble code..
> 
> But I also don't understand what the use case for this function
> is to start with.  struct sg_table tells us how many segments
> exist on the DMA side in the nents member, which should be just
> fine for the SGL threshold calculation.

sg_table->nents covers the entire exported buffer (<=1GiB), while a
request only covers a subrange[bi_offset, bi_offset+payload). Using
nents would overcount the request's segments.

> 
>> +{
>> +    struct nvme_iod *iod = blk_mq_rq_to_pdu(req);
>> +    struct bio *bio = req->bio;
>> +    struct nvme_dmabuf_map *map = to_nvme_dmabuf_map(bio->bi_dmabuf_map);
>> +    size_t length = blk_rq_payload_bytes(req);
>> +    struct nvme_sgl_desc *sg_list = NULL;
>> +    dma_addr_t sgl_dma = 0, last_end = 0;
>> +    unsigned int mapped = 0;
>> +    unsigned long tmp;
>> +    struct scatterlist *sg;
>> +    size_t offset, remaining;
>> +    bool have = false;
>> +
>> +    if (!entries)
>> +            return BLK_STS_IOERR;
>> +    if (entries > NVME_MAX_SEGS)
>> +            return BLK_STS_AGAIN;
> 
> Given that the block layer enforced data in rw/command and the
> max_segments limit, why do we need the extra check here?

A dmabuf bio reports nsegs=1 (bio_split_io_at) to the block layer, so 
max_segments isn't enforced against the SG entries actually spanned by 
the request. Hence the explicit check.

> 
>> +                    continue;
>> +            }
>> +
>> +            addr += offset;
>> +            sg_len -= offset;
>> +            offset = 0;
>> +
>> +            while (sg_len && remaining) {
> 
> These can't be false on the first iteration, so maybe turn this into
> a do {} while loop?

Will do.

> 
>> +                    u32 chunk = min_t(size_t, remaining, sg_len);
>> +
>> +                    if (have && last_end == addr) {
>> +                            u32 old = le32_to_cpu(sg_list[mapped - 
>> 1].length);
>> +
>> +                            sg_list[mapped - 1].length = cpu_to_le32(old + 
>> chunk);
> 
> Overly long line.
> 
>> +                    } else {
>> +                            if (WARN_ON_ONCE(mapped == entries))
>> +                                    goto err_free;
>> +                            nvme_pci_sgl_set_data_addr(&sg_list[mapped++],
>> +                                                       addr, chunk);
>> +                    }
> 
> Why do we need this merging?  dma_map_sg should have already done
> any interesting merging, or am I missing something?

Will drop it.


Reply via email to