mirror of
https://github.com/FEX-Emu/linux.git
synced 2025-01-02 15:21:03 +00:00
ioatdma: channel reset scheme fixup on Intel Atom S1200 platforms
The Intel Atom S1200 family ioatdma changed the channel reset behavior. It does a reset similar to PCI FLR by resetting all the MSIX registers. We have to re-init msix interrupts because of this. This workaround is only specific to this platform and is not expected to carry over to the later generations. Signed-off-by: Dave Jiang <dave.jiang@intel.com> Acked-by: Dan Williams <djbw@fb.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
This commit is contained in:
parent
d92a8d7cbb
commit
8a52b9ff11
@ -892,7 +892,7 @@ MODULE_PARM_DESC(ioat_interrupt_style,
|
||||
* ioat_dma_setup_interrupts - setup interrupt handler
|
||||
* @device: ioat device
|
||||
*/
|
||||
static int ioat_dma_setup_interrupts(struct ioatdma_device *device)
|
||||
int ioat_dma_setup_interrupts(struct ioatdma_device *device)
|
||||
{
|
||||
struct ioat_chan_common *chan;
|
||||
struct pci_dev *pdev = device->pdev;
|
||||
@ -941,6 +941,7 @@ msix:
|
||||
}
|
||||
}
|
||||
intrctrl |= IOAT_INTRCTRL_MSIX_VECTOR_CONTROL;
|
||||
device->irq_mode = IOAT_MSIX;
|
||||
goto done;
|
||||
|
||||
msix_single_vector:
|
||||
@ -956,6 +957,7 @@ msix_single_vector:
|
||||
pci_disable_msix(pdev);
|
||||
goto msi;
|
||||
}
|
||||
device->irq_mode = IOAT_MSIX_SINGLE;
|
||||
goto done;
|
||||
|
||||
msi:
|
||||
@ -969,6 +971,7 @@ msi:
|
||||
pci_disable_msi(pdev);
|
||||
goto intx;
|
||||
}
|
||||
device->irq_mode = IOAT_MSIX;
|
||||
goto done;
|
||||
|
||||
intx:
|
||||
@ -977,6 +980,7 @@ intx:
|
||||
if (err)
|
||||
goto err_no_irq;
|
||||
|
||||
device->irq_mode = IOAT_INTX;
|
||||
done:
|
||||
if (device->intr_quirk)
|
||||
device->intr_quirk(device);
|
||||
@ -987,9 +991,11 @@ done:
|
||||
err_no_irq:
|
||||
/* Disable all interrupt generation */
|
||||
writeb(0, device->reg_base + IOAT_INTRCTRL_OFFSET);
|
||||
device->irq_mode = IOAT_NOIRQ;
|
||||
dev_err(dev, "no usable interrupts\n");
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(ioat_dma_setup_interrupts);
|
||||
|
||||
static void ioat_disable_interrupts(struct ioatdma_device *device)
|
||||
{
|
||||
|
@ -48,6 +48,14 @@
|
||||
*/
|
||||
#define NULL_DESC_BUFFER_SIZE 1
|
||||
|
||||
enum ioat_irq_mode {
|
||||
IOAT_NOIRQ = 0,
|
||||
IOAT_MSIX,
|
||||
IOAT_MSIX_SINGLE,
|
||||
IOAT_MSI,
|
||||
IOAT_INTX
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ioatdma_device - internal representation of a IOAT device
|
||||
* @pdev: PCI-Express device
|
||||
@ -77,6 +85,7 @@ struct ioatdma_device {
|
||||
struct msix_entry msix_entries[4];
|
||||
struct ioat_chan_common *idx[4];
|
||||
struct dca_provider *dca;
|
||||
enum ioat_irq_mode irq_mode;
|
||||
void (*intr_quirk)(struct ioatdma_device *device);
|
||||
int (*enumerate_channels)(struct ioatdma_device *device);
|
||||
int (*reset_hw)(struct ioat_chan_common *chan);
|
||||
@ -341,6 +350,7 @@ bool ioat_cleanup_preamble(struct ioat_chan_common *chan,
|
||||
dma_addr_t *phys_complete);
|
||||
void ioat_kobject_add(struct ioatdma_device *device, struct kobj_type *type);
|
||||
void ioat_kobject_del(struct ioatdma_device *device);
|
||||
int ioat_dma_setup_interrupts(struct ioatdma_device *device);
|
||||
extern const struct sysfs_ops ioat_sysfs_ops;
|
||||
extern struct ioat_sysfs_entry ioat_version_attr;
|
||||
extern struct ioat_sysfs_entry ioat_cap_attr;
|
||||
|
@ -111,6 +111,103 @@ static void pq_set_src(struct ioat_raw_descriptor *descs[2],
|
||||
pq->coef[idx] = coef;
|
||||
}
|
||||
|
||||
static bool is_jf_ioat(struct pci_dev *pdev)
|
||||
{
|
||||
switch (pdev->device) {
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_JSF0:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_JSF1:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_JSF2:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_JSF3:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_JSF4:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_JSF5:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_JSF6:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_JSF7:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_JSF8:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_JSF9:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_snb_ioat(struct pci_dev *pdev)
|
||||
{
|
||||
switch (pdev->device) {
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_SNB0:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_SNB1:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_SNB2:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_SNB3:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_SNB4:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_SNB5:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_SNB6:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_SNB7:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_SNB8:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_SNB9:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_ivb_ioat(struct pci_dev *pdev)
|
||||
{
|
||||
switch (pdev->device) {
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_IVB0:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_IVB1:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_IVB2:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_IVB3:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_IVB4:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_IVB5:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_IVB6:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_IVB7:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_IVB8:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_IVB9:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static bool is_hsw_ioat(struct pci_dev *pdev)
|
||||
{
|
||||
switch (pdev->device) {
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_HSW0:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_HSW1:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_HSW2:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_HSW3:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_HSW4:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_HSW5:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_HSW6:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_HSW7:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_HSW8:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_HSW9:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static bool is_xeon_cb32(struct pci_dev *pdev)
|
||||
{
|
||||
return is_jf_ioat(pdev) || is_snb_ioat(pdev) || is_ivb_ioat(pdev) ||
|
||||
is_hsw_ioat(pdev);
|
||||
}
|
||||
|
||||
static bool is_bwd_ioat(struct pci_dev *pdev)
|
||||
{
|
||||
switch (pdev->device) {
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_BWD0:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_BWD1:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_BWD2:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_BWD3:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void ioat3_dma_unmap(struct ioat2_dma_chan *ioat,
|
||||
struct ioat_ring_ent *desc, int idx)
|
||||
{
|
||||
@ -1168,6 +1265,56 @@ static int ioat3_dma_self_test(struct ioatdma_device *device)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ioat3_irq_reinit(struct ioatdma_device *device)
|
||||
{
|
||||
int msixcnt = device->common.chancnt;
|
||||
struct pci_dev *pdev = device->pdev;
|
||||
int i;
|
||||
struct msix_entry *msix;
|
||||
struct ioat_chan_common *chan;
|
||||
int err = 0;
|
||||
|
||||
switch (device->irq_mode) {
|
||||
case IOAT_MSIX:
|
||||
|
||||
for (i = 0; i < msixcnt; i++) {
|
||||
msix = &device->msix_entries[i];
|
||||
chan = ioat_chan_by_index(device, i);
|
||||
devm_free_irq(&pdev->dev, msix->vector, chan);
|
||||
}
|
||||
|
||||
pci_disable_msix(pdev);
|
||||
break;
|
||||
|
||||
case IOAT_MSIX_SINGLE:
|
||||
msix = &device->msix_entries[0];
|
||||
chan = ioat_chan_by_index(device, 0);
|
||||
devm_free_irq(&pdev->dev, msix->vector, chan);
|
||||
pci_disable_msix(pdev);
|
||||
break;
|
||||
|
||||
case IOAT_MSI:
|
||||
chan = ioat_chan_by_index(device, 0);
|
||||
devm_free_irq(&pdev->dev, pdev->irq, chan);
|
||||
pci_disable_msi(pdev);
|
||||
break;
|
||||
|
||||
case IOAT_INTX:
|
||||
chan = ioat_chan_by_index(device, 0);
|
||||
devm_free_irq(&pdev->dev, pdev->irq, chan);
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
device->irq_mode = IOAT_NOIRQ;
|
||||
|
||||
err = ioat_dma_setup_interrupts(device);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ioat3_reset_hw(struct ioat_chan_common *chan)
|
||||
{
|
||||
/* throw away whatever the channel was doing and get it
|
||||
@ -1199,91 +1346,16 @@ static int ioat3_reset_hw(struct ioat_chan_common *chan)
|
||||
if (dev_id == PCI_DEVICE_ID_INTEL_IOAT_TBG0)
|
||||
pci_write_config_dword(pdev, IOAT_PCI_DMAUNCERRSTS_OFFSET, 0x10);
|
||||
|
||||
return ioat2_reset_sync(chan, msecs_to_jiffies(200));
|
||||
}
|
||||
|
||||
static bool is_jf_ioat(struct pci_dev *pdev)
|
||||
{
|
||||
switch (pdev->device) {
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_JSF0:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_JSF1:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_JSF2:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_JSF3:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_JSF4:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_JSF5:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_JSF6:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_JSF7:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_JSF8:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_JSF9:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_snb_ioat(struct pci_dev *pdev)
|
||||
{
|
||||
switch (pdev->device) {
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_SNB0:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_SNB1:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_SNB2:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_SNB3:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_SNB4:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_SNB5:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_SNB6:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_SNB7:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_SNB8:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_SNB9:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_ivb_ioat(struct pci_dev *pdev)
|
||||
{
|
||||
switch (pdev->device) {
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_IVB0:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_IVB1:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_IVB2:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_IVB3:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_IVB4:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_IVB5:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_IVB6:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_IVB7:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_IVB8:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_IVB9:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
err = ioat2_reset_sync(chan, msecs_to_jiffies(200));
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "Failed to reset!\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
}
|
||||
if (device->irq_mode != IOAT_NOIRQ && is_bwd_ioat(pdev))
|
||||
err = ioat3_irq_reinit(device);
|
||||
|
||||
static bool is_hsw_ioat(struct pci_dev *pdev)
|
||||
{
|
||||
switch (pdev->device) {
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_HSW0:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_HSW1:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_HSW2:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_HSW3:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_HSW4:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_HSW5:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_HSW6:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_HSW7:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_HSW8:
|
||||
case PCI_DEVICE_ID_INTEL_IOAT_HSW9:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static bool is_xeon_cb32(struct pci_dev *pdev)
|
||||
{
|
||||
return is_jf_ioat(pdev) || is_snb_ioat(pdev) || is_ivb_ioat(pdev) ||
|
||||
is_hsw_ioat(pdev);
|
||||
return err;
|
||||
}
|
||||
|
||||
int ioat3_dma_probe(struct ioatdma_device *device, int dca)
|
||||
|
Loading…
Reference in New Issue
Block a user