[PATCH v5 RFC] nvme: improve performance for virtual NVMe devices
Helen Koike
helen.koike at collabora.co.uk
Mon Mar 27 09:25:10 PDT 2017
Sorry, the last email was a reply to Christoph (thank you all for reviewing)
On 2017-03-27 01:04 PM, Helen Koike wrote:
> Hi Keith,
>
> Thanks for your review. Please, see my comments below
>
> On 2017-03-27 06:49 AM, Christoph Hellwig wrote:
> >> +#define SQ_IDX(qid, stride) ((qid) * 2 * (stride))
> >> +#define CQ_IDX(qid, stride) (((qid) * 2 + 1) * (stride))
> >
> > Please use inline functions for these.
> >
> >> + struct {
> >> + u32 *dbs;
> >> + u32 *eis;
> >> + dma_addr_t dbs_dma_addr;
> >> + dma_addr_t eis_dma_addr;
> >> + } dbbuf;
> >
> > No need for a struct here, also please keep the field and its dma_addr_t
> > together.
> >
> >> + struct {
> >> + u32 *sq_db;
> >> + u32 *cq_db;
> >> + u32 *sq_ei;
> >> + u32 *cq_ei;
> >> + } dbbuf;
> >
> > No need for the struct here either.
> >
> >> +
> >> +static int nvme_dbbuf_dma_alloc(struct nvme_dev *dev)
> >> +{
> >> + unsigned int mem_size = nvme_dbbuf_size(dev->db_stride);
> >> +
> >> + dev->dbbuf.dbs = dma_alloc_coherent(dev->dev, mem_size,
> >> + &dev->dbbuf.dbs_dma_addr,
> >> + GFP_KERNEL);
> >> + if (!dev->dbbuf.dbs)
> >> + return -ENOMEM;
> >> + dev->dbbuf.eis = dma_alloc_coherent(dev->dev, mem_size,
> >> + &dev->dbbuf.eis_dma_addr,
> >> + GFP_KERNEL);
> >> + if (!dev->dbbuf.eis) {
> >> + dma_free_coherent(dev->dev, mem_size,
> >> + dev->dbbuf.dbs, dev->dbbuf.dbs_dma_addr);
> >> + dev->dbbuf.dbs = NULL;
> >> + return -ENOMEM;
> >> + }
> >> +
> >> + return 0;
> >
> > Please use normal kernel-style goto unwinding.
>
> I don't think it is necessary as there is only a single item to unwind.
> From my experience in other parts of the kernel code we usually use goto
> when there are several other steps to unwind. But I don't mind changing
> it if you still prefer a goto here.
>
> >
> >> +static void nvme_dbbuf_set(struct nvme_dev *dev)
> >> +{
> >> + struct nvme_command c;
> >> +
> >> + if (!dev->dbbuf.dbs)
> >> + return;
> >> +
> >> + memset(&c, 0, sizeof(c));
> >> + c.dbbuf.opcode = nvme_admin_dbbuf;
> >> + c.dbbuf.prp1 = cpu_to_le64(dev->dbbuf.dbs_dma_addr);
> >> + c.dbbuf.prp2 = cpu_to_le64(dev->dbbuf.eis_dma_addr);
> >> +
> >> + if (nvme_submit_sync_cmd(dev->ctrl.admin_q, &c, NULL, 0))
> >> + /* Free memory and continue on */
> >> + nvme_dbbuf_dma_free(dev);
> >
> > At least log a warning.
> >
> >> +static inline int nvme_dbbuf_need_event(u16 event_idx, u16 new_idx,
> >> u16 old)
> >> +{
> >> + /* Borrowed from vring_need_event */
> >
> > I don't think this comment matters.
> >
> >> +static void nvme_write_doorbell(u16 value,
> >> + u32 __iomem *db,
> >> + u32 *dbbuf_db,
> >> + volatile u32 *dbbuf_ei)
> >> +{
> >
> > Very odd formatting. Why not:
> >
> > static void nvme_write_doorbell(u16 value, u32 __iomem *db, u32
> > *dbbuf_db,
> > volatile u32 *dbbuf_ei)
> >
> > ?
> >
> >> + u16 old_value;
> >> +
> >> + if (!dbbuf_db) {
> >> + writel(value, db);
> >> + return;
> >> + }
> >
> > I'd prefer to keep this in the ultimate callers to make the flow
> > easier to read.
> >
> >> +static inline void nvme_write_doorbell_cq(struct nvme_queue *nvmeq,
> >> u16 value)
> >> +{
> >> + nvme_write_doorbell(value, nvmeq->q_db + nvmeq->dev->db_stride,
> >> + nvmeq->dbbuf.cq_db, nvmeq->dbbuf.cq_ei);
> >> +}
> >> +
> >> +static inline void nvme_write_doorbell_sq(struct nvme_queue *nvmeq,
> >> u16 value)
> >> +{
> >> + nvme_write_doorbell(value, nvmeq->q_db,
> >> + nvmeq->dbbuf.sq_db, nvmeq->dbbuf.sq_ei);
> >> }
> >
> > I'd skip these wrappers entirely.
>
> I added them to avoid future mistakes as mixing nvmeq->dbbuf.sq_db with
> nvmeq->dbbuf.sq_ei. But I don't mind to remove them either.
>
> >
> >> + if (dev->ctrl.oacs & NVME_CTRL_OACS_DBBUF_SUPP) {
> >> + result = nvme_dbbuf_dma_alloc(dev);
> >> + if (result)
> >> + goto out;
> >> + }
> >
> > Should we really fail the init here or just print a warning?
> >
More information about the Linux-nvme
mailing list