mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-03 07:06:47 +07:00
09c8a5b85e
In order to support dynamic resizing of the descriptor ring or polling for a descriptor in the presence of a hung channel the reset handler needs to make progress while in a non-preemptible context. The current workqueue implementation precludes polling channel reset completion under spin_lock(). This conversion also allows us to return to opportunistic cleanup in the ioat2 case as the timer implementation guarantees at least one cleanup after every descriptor is submitted. This means the worst case completion latency becomes the timer frequency (for exceptional circumstances), but with the benefit of avoiding busy waiting when the lock is contended. Signed-off-by: Maciej Sosnowski <maciej.sosnowski@intel.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
145 lines
4.1 KiB
C
145 lines
4.1 KiB
C
/*
|
|
* Copyright(c) 2004 - 2009 Intel Corporation. All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the Free
|
|
* Software Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with
|
|
* this program; if not, write to the Free Software Foundation, Inc., 59
|
|
* Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
* The full GNU General Public License is included in this distribution in the
|
|
* file called COPYING.
|
|
*/
|
|
#ifndef IOATDMA_V2_H
|
|
#define IOATDMA_V2_H
|
|
|
|
#include <linux/dmaengine.h>
|
|
#include "dma.h"
|
|
#include "hw.h"
|
|
|
|
|
|
extern int ioat_pending_level;
|
|
|
|
/*
|
|
* workaround for IOAT ver.3.0 null descriptor issue
|
|
* (channel returns error when size is 0)
|
|
*/
|
|
#define NULL_DESC_BUFFER_SIZE 1
|
|
|
|
#define IOAT_MAX_ORDER 16
|
|
#define ioat_get_alloc_order() \
|
|
(min(ioat_ring_alloc_order, IOAT_MAX_ORDER))
|
|
|
|
/* struct ioat2_dma_chan - ioat v2 / v3 channel attributes
|
|
* @base: common ioat channel parameters
|
|
* @xfercap_log; log2 of channel max transfer length (for fast division)
|
|
* @head: allocated index
|
|
* @issued: hardware notification point
|
|
* @tail: cleanup index
|
|
* @pending: lock free indicator for issued != head
|
|
* @dmacount: identical to 'head' except for occasionally resetting to zero
|
|
* @alloc_order: log2 of the number of allocated descriptors
|
|
* @ring: software ring buffer implementation of hardware ring
|
|
* @ring_lock: protects ring attributes
|
|
*/
|
|
struct ioat2_dma_chan {
|
|
struct ioat_chan_common base;
|
|
size_t xfercap_log;
|
|
u16 head;
|
|
u16 issued;
|
|
u16 tail;
|
|
u16 dmacount;
|
|
u16 alloc_order;
|
|
int pending;
|
|
struct ioat_ring_ent **ring;
|
|
spinlock_t ring_lock;
|
|
};
|
|
|
|
static inline struct ioat2_dma_chan *to_ioat2_chan(struct dma_chan *c)
|
|
{
|
|
struct ioat_chan_common *chan = to_chan_common(c);
|
|
|
|
return container_of(chan, struct ioat2_dma_chan, base);
|
|
}
|
|
|
|
static inline u16 ioat2_ring_mask(struct ioat2_dma_chan *ioat)
|
|
{
|
|
return (1 << ioat->alloc_order) - 1;
|
|
}
|
|
|
|
/* count of descriptors in flight with the engine */
|
|
static inline u16 ioat2_ring_active(struct ioat2_dma_chan *ioat)
|
|
{
|
|
return (ioat->head - ioat->tail) & ioat2_ring_mask(ioat);
|
|
}
|
|
|
|
/* count of descriptors pending submission to hardware */
|
|
static inline u16 ioat2_ring_pending(struct ioat2_dma_chan *ioat)
|
|
{
|
|
return (ioat->head - ioat->issued) & ioat2_ring_mask(ioat);
|
|
}
|
|
|
|
static inline u16 ioat2_ring_space(struct ioat2_dma_chan *ioat)
|
|
{
|
|
u16 num_descs = ioat2_ring_mask(ioat) + 1;
|
|
u16 active = ioat2_ring_active(ioat);
|
|
|
|
BUG_ON(active > num_descs);
|
|
|
|
return num_descs - active;
|
|
}
|
|
|
|
/* assumes caller already checked space */
|
|
static inline u16 ioat2_desc_alloc(struct ioat2_dma_chan *ioat, u16 len)
|
|
{
|
|
ioat->head += len;
|
|
return ioat->head - len;
|
|
}
|
|
|
|
static inline u16 ioat2_xferlen_to_descs(struct ioat2_dma_chan *ioat, size_t len)
|
|
{
|
|
u16 num_descs = len >> ioat->xfercap_log;
|
|
|
|
num_descs += !!(len & ((1 << ioat->xfercap_log) - 1));
|
|
return num_descs;
|
|
}
|
|
|
|
struct ioat_ring_ent {
|
|
struct ioat_dma_descriptor *hw;
|
|
struct dma_async_tx_descriptor txd;
|
|
size_t len;
|
|
#ifdef DEBUG
|
|
int id;
|
|
#endif
|
|
};
|
|
|
|
static inline struct ioat_ring_ent *
|
|
ioat2_get_ring_ent(struct ioat2_dma_chan *ioat, u16 idx)
|
|
{
|
|
return ioat->ring[idx & ioat2_ring_mask(ioat)];
|
|
}
|
|
|
|
static inline void ioat2_set_chainaddr(struct ioat2_dma_chan *ioat, u64 addr)
|
|
{
|
|
struct ioat_chan_common *chan = &ioat->base;
|
|
|
|
writel(addr & 0x00000000FFFFFFFF,
|
|
chan->reg_base + IOAT2_CHAINADDR_OFFSET_LOW);
|
|
writel(addr >> 32,
|
|
chan->reg_base + IOAT2_CHAINADDR_OFFSET_HIGH);
|
|
}
|
|
|
|
int __devinit ioat2_dma_probe(struct ioatdma_device *dev, int dca);
|
|
int __devinit ioat3_dma_probe(struct ioatdma_device *dev, int dca);
|
|
struct dca_provider * __devinit ioat2_dca_init(struct pci_dev *pdev, void __iomem *iobase);
|
|
struct dca_provider * __devinit ioat3_dca_init(struct pci_dev *pdev, void __iomem *iobase);
|
|
#endif /* IOATDMA_V2_H */
|