Commit 98cbf9ed authored by Mike Marciniszyn's avatar Mike Marciniszyn Committed by Stefan Bader

IB/qib: Fix DMA api warning with debug kernel

BugLink: https://bugs.launchpad.net/bugs/1784382

commit 0252f733 upstream.

The following error occurs in a debug build when running MPI PSM:

[  307.415911] WARNING: CPU: 4 PID: 23867 at lib/dma-debug.c:1158
check_unmap+0x4ee/0xa20
[  307.455661] ib_qib 0000:05:00.0: DMA-API: device driver failed to check map
error[device address=0x00000000df82b000] [size=4096 bytes] [mapped as page]
[  307.517494] Modules linked in:
[  307.531584]  ib_isert iscsi_target_mod ib_srpt target_core_mod rpcrdma
sunrpc ib_srp scsi_transport_srp scsi_tgt ib_iser libiscsi ib_ipoib
scsi_transport_iscsi rdma_ucm ib_ucm ib_uverbs ib_umad rdma_cm ib_cm iw_cm
ib_qib intel_powerclamp coretemp rdmavt intel_rapl iosf_mbi kvm_intel kvm
irqbypass crc32_pclmul ghash_clmulni_intel ipmi_ssif ib_core aesni_intel sg
ipmi_si lrw gf128mul dca glue_helper ipmi_devintf iTCO_wdt gpio_ich hpwdt
iTCO_vendor_support ablk_helper hpilo acpi_power_meter cryptd ipmi_msghandler
ie31200_edac shpchp pcc_cpufreq lpc_ich pcspkr ip_tables xfs libcrc32c sd_mod
crc_t10dif crct10dif_generic mgag200 i2c_algo_bit drm_kms_helper syscopyarea
sysfillrect sysimgblt fb_sys_fops ttm ahci crct10dif_pclmul crct10dif_common
drm crc32c_intel libahci tg3 libata serio_raw ptp i2c_core
[  307.846113]  pps_core dm_mirror dm_region_hash dm_log dm_mod
[  307.866505] CPU: 4 PID: 23867 Comm: mpitests-IMB-MP Kdump: loaded Not
tainted 3.10.0-862.el7.x86_64.debug #1
[  307.911178] Hardware name: HP ProLiant DL320e Gen8, BIOS J05 11/09/2013
[  307.944206] Call Trace:
[  307.956973]  [<ffffffffbd9e915b>] dump_stack+0x19/0x1b
[  307.982201]  [<ffffffffbd2a2f58>] __warn+0xd8/0x100
[  308.005999]  [<ffffffffbd2a2fdf>] warn_slowpath_fmt+0x5f/0x80
[  308.034260]  [<ffffffffbd5f667e>] check_unmap+0x4ee/0xa20
[  308.060801]  [<ffffffffbd41acaa>] ? page_add_file_rmap+0x2a/0x1d0
[  308.090689]  [<ffffffffbd5f6c4d>] debug_dma_unmap_page+0x9d/0xb0
[  308.120155]  [<ffffffffbd4082e0>] ? might_fault+0xa0/0xb0
[  308.146656]  [<ffffffffc07761a5>] qib_tid_free.isra.14+0x215/0x2a0 [ib_qib]
[  308.180739]  [<ffffffffc0776bf4>] qib_write+0x894/0x1280 [ib_qib]
[  308.210733]  [<ffffffffbd540b00>] ? __inode_security_revalidate+0x70/0x80
[  308.244837]  [<ffffffffbd53c2b7>] ? security_file_permission+0x27/0xb0
[  308.266025] qib_ib0.8006: multicast join failed for
ff12:401b:8006:0000:0000:0000:ffff:ffff, status -22
[  308.323421]  [<ffffffffbd46f5d3>] vfs_write+0xc3/0x1f0
[  308.347077]  [<ffffffffbd492a5c>] ? fget_light+0xfc/0x510
[  308.372533]  [<ffffffffbd47045a>] SyS_write+0x8a/0x100
[  308.396456]  [<ffffffffbd9ff355>] system_call_fastpath+0x1c/0x21

The code calls a qib_map_page() which has never correctly tested for a
mapping error.

Fix by testing for pci_dma_mapping_error() in all cases and properly
handling the failure in the caller.

Additionally, streamline qib_map_page() arguments to satisfy just
the single caller.

Cc: <stable@vger.kernel.org>
Reviewed-by: default avatarAlex Estrin <alex.estrin@intel.com>
Tested-by: default avatarDon Dutile <ddutile@redhat.com>
Reviewed-by: default avatarDon Dutile <ddutile@redhat.com>
Signed-off-by: default avatarMike Marciniszyn <mike.marciniszyn@intel.com>
Signed-off-by: default avatarDennis Dalessandro <dennis.dalessandro@intel.com>
Signed-off-by: default avatarDoug Ledford <dledford@redhat.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarKleber Sacilotto de Souza <kleber.souza@canonical.com>
Signed-off-by: default avatarKhalid Elmously <khalid.elmously@canonical.com>
parent 5b713363
...@@ -1451,8 +1451,7 @@ u64 qib_sps_ints(void); ...@@ -1451,8 +1451,7 @@ u64 qib_sps_ints(void);
/* /*
* dma_addr wrappers - all 0's invalid for hw * dma_addr wrappers - all 0's invalid for hw
*/ */
dma_addr_t qib_map_page(struct pci_dev *, struct page *, unsigned long, int qib_map_page(struct pci_dev *d, struct page *p, dma_addr_t *daddr);
size_t, int);
const char *qib_get_unit_name(int unit); const char *qib_get_unit_name(int unit);
/* /*
......
...@@ -364,6 +364,8 @@ static int qib_tid_update(struct qib_ctxtdata *rcd, struct file *fp, ...@@ -364,6 +364,8 @@ static int qib_tid_update(struct qib_ctxtdata *rcd, struct file *fp,
goto done; goto done;
} }
for (i = 0; i < cnt; i++, vaddr += PAGE_SIZE) { for (i = 0; i < cnt; i++, vaddr += PAGE_SIZE) {
dma_addr_t daddr;
for (; ntids--; tid++) { for (; ntids--; tid++) {
if (tid == tidcnt) if (tid == tidcnt)
tid = 0; tid = 0;
...@@ -380,12 +382,14 @@ static int qib_tid_update(struct qib_ctxtdata *rcd, struct file *fp, ...@@ -380,12 +382,14 @@ static int qib_tid_update(struct qib_ctxtdata *rcd, struct file *fp,
ret = -ENOMEM; ret = -ENOMEM;
break; break;
} }
ret = qib_map_page(dd->pcidev, pagep[i], &daddr);
if (ret)
break;
tidlist[i] = tid + tidoff; tidlist[i] = tid + tidoff;
/* we "know" system pages and TID pages are same size */ /* we "know" system pages and TID pages are same size */
dd->pageshadow[ctxttid + tid] = pagep[i]; dd->pageshadow[ctxttid + tid] = pagep[i];
dd->physshadow[ctxttid + tid] = dd->physshadow[ctxttid + tid] = daddr;
qib_map_page(dd->pcidev, pagep[i], 0, PAGE_SIZE,
PCI_DMA_FROMDEVICE);
/* /*
* don't need atomic or it's overhead * don't need atomic or it's overhead
*/ */
......
...@@ -98,23 +98,27 @@ static int __qib_get_user_pages(unsigned long start_page, size_t num_pages, ...@@ -98,23 +98,27 @@ static int __qib_get_user_pages(unsigned long start_page, size_t num_pages,
* *
* I'm sure we won't be so lucky with other iommu's, so FIXME. * I'm sure we won't be so lucky with other iommu's, so FIXME.
*/ */
dma_addr_t qib_map_page(struct pci_dev *hwdev, struct page *page, int qib_map_page(struct pci_dev *hwdev, struct page *page, dma_addr_t *daddr)
unsigned long offset, size_t size, int direction)
{ {
dma_addr_t phys; dma_addr_t phys;
phys = pci_map_page(hwdev, page, offset, size, direction); phys = pci_map_page(hwdev, page, 0, PAGE_SIZE, PCI_DMA_FROMDEVICE);
if (pci_dma_mapping_error(hwdev, phys))
return -ENOMEM;
if (phys == 0) { if (!phys) {
pci_unmap_page(hwdev, phys, size, direction); pci_unmap_page(hwdev, phys, PAGE_SIZE, PCI_DMA_FROMDEVICE);
phys = pci_map_page(hwdev, page, offset, size, direction); phys = pci_map_page(hwdev, page, 0, PAGE_SIZE,
PCI_DMA_FROMDEVICE);
if (pci_dma_mapping_error(hwdev, phys))
return -ENOMEM;
/* /*
* FIXME: If we get 0 again, we should keep this page, * FIXME: If we get 0 again, we should keep this page,
* map another, then free the 0 page. * map another, then free the 0 page.
*/ */
} }
*daddr = phys;
return phys; return 0;
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment