mirror of
https://github.com/FEX-Emu/linux.git
synced 2025-01-05 00:41:23 +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
|
* ioat_dma_setup_interrupts - setup interrupt handler
|
||||||
* @device: ioat device
|
* @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 ioat_chan_common *chan;
|
||||||
struct pci_dev *pdev = device->pdev;
|
struct pci_dev *pdev = device->pdev;
|
||||||
@ -941,6 +941,7 @@ msix:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
intrctrl |= IOAT_INTRCTRL_MSIX_VECTOR_CONTROL;
|
intrctrl |= IOAT_INTRCTRL_MSIX_VECTOR_CONTROL;
|
||||||
|
device->irq_mode = IOAT_MSIX;
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
msix_single_vector:
|
msix_single_vector:
|
||||||
@ -956,6 +957,7 @@ msix_single_vector:
|
|||||||
pci_disable_msix(pdev);
|
pci_disable_msix(pdev);
|
||||||
goto msi;
|
goto msi;
|
||||||
}
|
}
|
||||||
|
device->irq_mode = IOAT_MSIX_SINGLE;
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
msi:
|
msi:
|
||||||
@ -969,6 +971,7 @@ msi:
|
|||||||
pci_disable_msi(pdev);
|
pci_disable_msi(pdev);
|
||||||
goto intx;
|
goto intx;
|
||||||
}
|
}
|
||||||
|
device->irq_mode = IOAT_MSIX;
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
intx:
|
intx:
|
||||||
@ -977,6 +980,7 @@ intx:
|
|||||||
if (err)
|
if (err)
|
||||||
goto err_no_irq;
|
goto err_no_irq;
|
||||||
|
|
||||||
|
device->irq_mode = IOAT_INTX;
|
||||||
done:
|
done:
|
||||||
if (device->intr_quirk)
|
if (device->intr_quirk)
|
||||||
device->intr_quirk(device);
|
device->intr_quirk(device);
|
||||||
@ -987,9 +991,11 @@ done:
|
|||||||
err_no_irq:
|
err_no_irq:
|
||||||
/* Disable all interrupt generation */
|
/* Disable all interrupt generation */
|
||||||
writeb(0, device->reg_base + IOAT_INTRCTRL_OFFSET);
|
writeb(0, device->reg_base + IOAT_INTRCTRL_OFFSET);
|
||||||
|
device->irq_mode = IOAT_NOIRQ;
|
||||||
dev_err(dev, "no usable interrupts\n");
|
dev_err(dev, "no usable interrupts\n");
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(ioat_dma_setup_interrupts);
|
||||||
|
|
||||||
static void ioat_disable_interrupts(struct ioatdma_device *device)
|
static void ioat_disable_interrupts(struct ioatdma_device *device)
|
||||||
{
|
{
|
||||||
|
@ -48,6 +48,14 @@
|
|||||||
*/
|
*/
|
||||||
#define NULL_DESC_BUFFER_SIZE 1
|
#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
|
* struct ioatdma_device - internal representation of a IOAT device
|
||||||
* @pdev: PCI-Express device
|
* @pdev: PCI-Express device
|
||||||
@ -77,6 +85,7 @@ struct ioatdma_device {
|
|||||||
struct msix_entry msix_entries[4];
|
struct msix_entry msix_entries[4];
|
||||||
struct ioat_chan_common *idx[4];
|
struct ioat_chan_common *idx[4];
|
||||||
struct dca_provider *dca;
|
struct dca_provider *dca;
|
||||||
|
enum ioat_irq_mode irq_mode;
|
||||||
void (*intr_quirk)(struct ioatdma_device *device);
|
void (*intr_quirk)(struct ioatdma_device *device);
|
||||||
int (*enumerate_channels)(struct ioatdma_device *device);
|
int (*enumerate_channels)(struct ioatdma_device *device);
|
||||||
int (*reset_hw)(struct ioat_chan_common *chan);
|
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);
|
dma_addr_t *phys_complete);
|
||||||
void ioat_kobject_add(struct ioatdma_device *device, struct kobj_type *type);
|
void ioat_kobject_add(struct ioatdma_device *device, struct kobj_type *type);
|
||||||
void ioat_kobject_del(struct ioatdma_device *device);
|
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 const struct sysfs_ops ioat_sysfs_ops;
|
||||||
extern struct ioat_sysfs_entry ioat_version_attr;
|
extern struct ioat_sysfs_entry ioat_version_attr;
|
||||||
extern struct ioat_sysfs_entry ioat_cap_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;
|
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,
|
static void ioat3_dma_unmap(struct ioat2_dma_chan *ioat,
|
||||||
struct ioat_ring_ent *desc, int idx)
|
struct ioat_ring_ent *desc, int idx)
|
||||||
{
|
{
|
||||||
@ -1168,6 +1265,56 @@ static int ioat3_dma_self_test(struct ioatdma_device *device)
|
|||||||
return 0;
|
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)
|
static int ioat3_reset_hw(struct ioat_chan_common *chan)
|
||||||
{
|
{
|
||||||
/* throw away whatever the channel was doing and get it
|
/* 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)
|
if (dev_id == PCI_DEVICE_ID_INTEL_IOAT_TBG0)
|
||||||
pci_write_config_dword(pdev, IOAT_PCI_DMAUNCERRSTS_OFFSET, 0x10);
|
pci_write_config_dword(pdev, IOAT_PCI_DMAUNCERRSTS_OFFSET, 0x10);
|
||||||
|
|
||||||
return ioat2_reset_sync(chan, msecs_to_jiffies(200));
|
err = ioat2_reset_sync(chan, msecs_to_jiffies(200));
|
||||||
}
|
if (err) {
|
||||||
|
dev_err(&pdev->dev, "Failed to reset!\n");
|
||||||
static bool is_jf_ioat(struct pci_dev *pdev)
|
return err;
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
if (device->irq_mode != IOAT_NOIRQ && is_bwd_ioat(pdev))
|
||||||
|
err = ioat3_irq_reinit(device);
|
||||||
|
|
||||||
static bool is_hsw_ioat(struct pci_dev *pdev)
|
return err;
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ioat3_dma_probe(struct ioatdma_device *device, int dca)
|
int ioat3_dma_probe(struct ioatdma_device *device, int dca)
|
||||||
|
Loading…
Reference in New Issue
Block a user