IB/qib: Don't mark VL15 bufs as WC to avoid a rare 7322 chip problem
Don't set write combining via PAT on the VL15 buffers to avoid a rare problem with unaligned writes from interrupt-flushed store buffers. Signed-off-by: Dave Olson <dave.olson@qlogic.com> Signed-off-by: Roland Dreier <rolandd@cisco.com>
This commit is contained in:
parent
67a3e12b05
commit
fce24a9d28
@ -686,6 +686,7 @@ struct qib_devdata {
|
|||||||
void __iomem *piobase;
|
void __iomem *piobase;
|
||||||
/* mem-mapped pointer to base of user chip regs (if using WC PAT) */
|
/* mem-mapped pointer to base of user chip regs (if using WC PAT) */
|
||||||
u64 __iomem *userbase;
|
u64 __iomem *userbase;
|
||||||
|
void __iomem *piovl15base; /* base of VL15 buffers, if not WC */
|
||||||
/*
|
/*
|
||||||
* points to area where PIOavail registers will be DMA'ed.
|
* points to area where PIOavail registers will be DMA'ed.
|
||||||
* Has to be on a page of it's own, because the page will be
|
* Has to be on a page of it's own, because the page will be
|
||||||
|
@ -233,6 +233,7 @@ static u32 __iomem *qib_remap_ioaddr32(struct qib_devdata *dd, u32 offset,
|
|||||||
u32 __iomem *krb32 = (u32 __iomem *)dd->kregbase;
|
u32 __iomem *krb32 = (u32 __iomem *)dd->kregbase;
|
||||||
u32 __iomem *map = NULL;
|
u32 __iomem *map = NULL;
|
||||||
u32 cnt = 0;
|
u32 cnt = 0;
|
||||||
|
u32 tot4k, offs4k;
|
||||||
|
|
||||||
/* First, simplest case, offset is within the first map. */
|
/* First, simplest case, offset is within the first map. */
|
||||||
kreglen = (dd->kregend - dd->kregbase) * sizeof(u64);
|
kreglen = (dd->kregend - dd->kregbase) * sizeof(u64);
|
||||||
@ -250,7 +251,8 @@ static u32 __iomem *qib_remap_ioaddr32(struct qib_devdata *dd, u32 offset,
|
|||||||
if (dd->userbase) {
|
if (dd->userbase) {
|
||||||
/* If user regs mapped, they are after send, so set limit. */
|
/* If user regs mapped, they are after send, so set limit. */
|
||||||
u32 ulim = (dd->cfgctxts * dd->ureg_align) + dd->uregbase;
|
u32 ulim = (dd->cfgctxts * dd->ureg_align) + dd->uregbase;
|
||||||
snd_lim = dd->uregbase;
|
if (!dd->piovl15base)
|
||||||
|
snd_lim = dd->uregbase;
|
||||||
krb32 = (u32 __iomem *)dd->userbase;
|
krb32 = (u32 __iomem *)dd->userbase;
|
||||||
if (offset >= dd->uregbase && offset < ulim) {
|
if (offset >= dd->uregbase && offset < ulim) {
|
||||||
map = krb32 + (offset - dd->uregbase) / sizeof(u32);
|
map = krb32 + (offset - dd->uregbase) / sizeof(u32);
|
||||||
@ -277,14 +279,14 @@ static u32 __iomem *qib_remap_ioaddr32(struct qib_devdata *dd, u32 offset,
|
|||||||
/* If 4k buffers exist, account for them by bumping
|
/* If 4k buffers exist, account for them by bumping
|
||||||
* appropriate limit.
|
* appropriate limit.
|
||||||
*/
|
*/
|
||||||
|
tot4k = dd->piobcnt4k * dd->align4k;
|
||||||
|
offs4k = dd->piobufbase >> 32;
|
||||||
if (dd->piobcnt4k) {
|
if (dd->piobcnt4k) {
|
||||||
u32 tot4k = dd->piobcnt4k * dd->align4k;
|
|
||||||
u32 offs4k = dd->piobufbase >> 32;
|
|
||||||
if (snd_bottom > offs4k)
|
if (snd_bottom > offs4k)
|
||||||
snd_bottom = offs4k;
|
snd_bottom = offs4k;
|
||||||
else {
|
else {
|
||||||
/* 4k above 2k. Bump snd_lim, if needed*/
|
/* 4k above 2k. Bump snd_lim, if needed*/
|
||||||
if (!dd->userbase)
|
if (!dd->userbase || dd->piovl15base)
|
||||||
snd_lim = offs4k + tot4k;
|
snd_lim = offs4k + tot4k;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -298,6 +300,15 @@ static u32 __iomem *qib_remap_ioaddr32(struct qib_devdata *dd, u32 offset,
|
|||||||
cnt = snd_lim - offset;
|
cnt = snd_lim - offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!map && offs4k && dd->piovl15base) {
|
||||||
|
snd_lim = offs4k + tot4k + 2 * dd->align4k;
|
||||||
|
if (offset >= (offs4k + tot4k) && offset < snd_lim) {
|
||||||
|
map = (u32 __iomem *)dd->piovl15base +
|
||||||
|
((offset - (offs4k + tot4k)) / sizeof(u32));
|
||||||
|
cnt = snd_lim - offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mapped:
|
mapped:
|
||||||
if (cntp)
|
if (cntp)
|
||||||
*cntp = cnt;
|
*cntp = cnt;
|
||||||
|
@ -6119,9 +6119,25 @@ static int qib_init_7322_variables(struct qib_devdata *dd)
|
|||||||
qib_set_ctxtcnt(dd);
|
qib_set_ctxtcnt(dd);
|
||||||
|
|
||||||
if (qib_wc_pat) {
|
if (qib_wc_pat) {
|
||||||
ret = init_chip_wc_pat(dd, NUM_VL15_BUFS * dd->align4k);
|
resource_size_t vl15off;
|
||||||
|
/*
|
||||||
|
* We do not set WC on the VL15 buffers to avoid
|
||||||
|
* a rare problem with unaligned writes from
|
||||||
|
* interrupt-flushed store buffers, so we need
|
||||||
|
* to map those separately here. We can't solve
|
||||||
|
* this for the rarely used mtrr case.
|
||||||
|
*/
|
||||||
|
ret = init_chip_wc_pat(dd, 0);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto bail;
|
goto bail;
|
||||||
|
|
||||||
|
/* vl15 buffers start just after the 4k buffers */
|
||||||
|
vl15off = dd->physaddr + (dd->piobufbase >> 32) +
|
||||||
|
dd->piobcnt4k * dd->align4k;
|
||||||
|
dd->piovl15base = ioremap_nocache(vl15off,
|
||||||
|
NUM_VL15_BUFS * dd->align4k);
|
||||||
|
if (!dd->piovl15base)
|
||||||
|
goto bail;
|
||||||
}
|
}
|
||||||
qib_7322_set_baseaddrs(dd); /* set chip access pointers now */
|
qib_7322_set_baseaddrs(dd); /* set chip access pointers now */
|
||||||
|
|
||||||
|
@ -1499,6 +1499,12 @@ bail:
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note: Changes to this routine should be mirrored
|
||||||
|
* for the diagnostics routine qib_remap_ioaddr32().
|
||||||
|
* There is also related code for VL15 buffers in qib_init_7322_variables().
|
||||||
|
* The teardown code that unmaps is in qib_pcie_ddcleanup()
|
||||||
|
*/
|
||||||
int init_chip_wc_pat(struct qib_devdata *dd, u32 vl15buflen)
|
int init_chip_wc_pat(struct qib_devdata *dd, u32 vl15buflen)
|
||||||
{
|
{
|
||||||
u64 __iomem *qib_kregbase = NULL;
|
u64 __iomem *qib_kregbase = NULL;
|
||||||
|
@ -179,6 +179,8 @@ void qib_pcie_ddcleanup(struct qib_devdata *dd)
|
|||||||
iounmap(dd->piobase);
|
iounmap(dd->piobase);
|
||||||
if (dd->userbase)
|
if (dd->userbase)
|
||||||
iounmap(dd->userbase);
|
iounmap(dd->userbase);
|
||||||
|
if (dd->piovl15base)
|
||||||
|
iounmap(dd->piovl15base);
|
||||||
|
|
||||||
pci_disable_device(dd->pcidev);
|
pci_disable_device(dd->pcidev);
|
||||||
pci_release_regions(dd->pcidev);
|
pci_release_regions(dd->pcidev);
|
||||||
|
@ -340,9 +340,13 @@ rescan:
|
|||||||
if (i < dd->piobcnt2k)
|
if (i < dd->piobcnt2k)
|
||||||
buf = (u32 __iomem *)(dd->pio2kbase +
|
buf = (u32 __iomem *)(dd->pio2kbase +
|
||||||
i * dd->palign);
|
i * dd->palign);
|
||||||
else
|
else if (i < dd->piobcnt2k + dd->piobcnt4k || !dd->piovl15base)
|
||||||
buf = (u32 __iomem *)(dd->pio4kbase +
|
buf = (u32 __iomem *)(dd->pio4kbase +
|
||||||
(i - dd->piobcnt2k) * dd->align4k);
|
(i - dd->piobcnt2k) * dd->align4k);
|
||||||
|
else
|
||||||
|
buf = (u32 __iomem *)(dd->piovl15base +
|
||||||
|
(i - (dd->piobcnt2k + dd->piobcnt4k)) *
|
||||||
|
dd->align4k);
|
||||||
if (pbufnum)
|
if (pbufnum)
|
||||||
*pbufnum = i;
|
*pbufnum = i;
|
||||||
dd->upd_pio_shadow = 0;
|
dd->upd_pio_shadow = 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user