Commit ab3998ef authored by Thomas Bogendoerfer's avatar Thomas Bogendoerfer Committed by Sasha Levin

parisc: DMA API: return error instead of BUG_ON for dma ops on non dma devs

[ Upstream commit 33f9e024 ]

Enabling parport pc driver on a B2600 (and probably other 64bit PARISC
systems) produced following BUG:

CPU: 0 PID: 1 Comm: swapper Not tainted 4.12.0-rc5-30198-g1132d5e7 #156
task: 000000009e050000 task.stack: 000000009e04c000

     YZrvWESTHLNXBCVMcbcbcbcbOGFRQPDI
PSW: 00001000000001101111111100001111 Not tainted
r00-03  000000ff0806ff0f 000000009e04c990 0000000040871b78 000000009e04cac0
r04-07  0000000040c14de0 ffffffffffffffff 000000009e07f098 000000009d82d200
r08-11  000000009d82d210 0000000000000378 0000000000000000 0000000040c345e0
r12-15  0000000000000005 0000000040c345e0 0000000000000000 0000000040c9d5e0
r16-19  0000000040c345e0 00000000f00001c4 00000000f00001bc 0000000000000061
r20-23  000000009e04ce28 0000000000000010 0000000000000010 0000000040b89e40
r24-27  0000000000000003 0000000000ffffff 000000009d82d210 0000000040c14de0
r28-31  0000000000000000 000000009e04ca90 000000009e04cb40 0000000000000000
sr00-03  0000000000000000 0000000000000000 0000000000000000 0000000000000000
sr04-07  0000000000000000 0000000000000000 0000000000000000 0000000000000000

IASQ: 0000000000000000 0000000000000000 IAOQ: 00000000404aece0 00000000404aece4
 IIR: 03ffe01f    ISR: 0000000010340000  IOR: 000001781304cac8
 CPU:        0   CR30: 000000009e04c000 CR31: 00000000e2976de2
 ORIG_R28: 0000000000000200
 IAOQ[0]: sba_dma_supported+0x80/0xd0
 IAOQ[1]: sba_dma_supported+0x84/0xd0
 RP(r2): parport_pc_probe_port+0x178/0x1200

Cause is a call to dma_coerce_mask_and_coherenet in parport_pc_probe_port,
which PARISC DMA API doesn't handle very nicely. This commit gives back
DMA_ERROR_CODE for DMA API calls, if device isn't capable of DMA
transaction.

Cc: <stable@vger.kernel.org> # v3.13+
Signed-off-by: default avatarThomas Bogendoerfer <tsbogend@alpha.franken.de>
Signed-off-by: default avatarHelge Deller <deller@gmx.de>
Signed-off-by: default avatarSasha Levin <alexander.levin@verizon.com>
parent a5efe706
...@@ -39,6 +39,8 @@ struct hppa_dma_ops { ...@@ -39,6 +39,8 @@ struct hppa_dma_ops {
** flush/purge and allocate "regular" cacheable pages for everything. ** flush/purge and allocate "regular" cacheable pages for everything.
*/ */
#define DMA_ERROR_CODE (~(dma_addr_t)0)
#ifdef CONFIG_PA11 #ifdef CONFIG_PA11
extern struct hppa_dma_ops pcxl_dma_ops; extern struct hppa_dma_ops pcxl_dma_ops;
extern struct hppa_dma_ops pcx_dma_ops; extern struct hppa_dma_ops pcx_dma_ops;
...@@ -209,12 +211,13 @@ parisc_walk_tree(struct device *dev) ...@@ -209,12 +211,13 @@ parisc_walk_tree(struct device *dev)
break; break;
} }
} }
BUG_ON(!dev->platform_data);
return dev->platform_data; return dev->platform_data;
} }
#define GET_IOC(dev) (HBA_DATA(parisc_walk_tree(dev))->iommu) #define GET_IOC(dev) ({ \
void *__pdata = parisc_walk_tree(dev); \
__pdata ? HBA_DATA(__pdata)->iommu : NULL; \
})
#ifdef CONFIG_IOMMU_CCIO #ifdef CONFIG_IOMMU_CCIO
struct parisc_device; struct parisc_device;
......
...@@ -743,6 +743,8 @@ ccio_map_single(struct device *dev, void *addr, size_t size, ...@@ -743,6 +743,8 @@ ccio_map_single(struct device *dev, void *addr, size_t size,
BUG_ON(!dev); BUG_ON(!dev);
ioc = GET_IOC(dev); ioc = GET_IOC(dev);
if (!ioc)
return DMA_ERROR_CODE;
BUG_ON(size <= 0); BUG_ON(size <= 0);
...@@ -807,6 +809,10 @@ ccio_unmap_single(struct device *dev, dma_addr_t iova, size_t size, ...@@ -807,6 +809,10 @@ ccio_unmap_single(struct device *dev, dma_addr_t iova, size_t size,
BUG_ON(!dev); BUG_ON(!dev);
ioc = GET_IOC(dev); ioc = GET_IOC(dev);
if (!ioc) {
WARN_ON(!ioc);
return;
}
DBG_RUN("%s() iovp 0x%lx/%x\n", DBG_RUN("%s() iovp 0x%lx/%x\n",
__func__, (long)iova, size); __func__, (long)iova, size);
...@@ -910,6 +916,8 @@ ccio_map_sg(struct device *dev, struct scatterlist *sglist, int nents, ...@@ -910,6 +916,8 @@ ccio_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
BUG_ON(!dev); BUG_ON(!dev);
ioc = GET_IOC(dev); ioc = GET_IOC(dev);
if (!ioc)
return 0;
DBG_RUN_SG("%s() START %d entries\n", __func__, nents); DBG_RUN_SG("%s() START %d entries\n", __func__, nents);
...@@ -982,6 +990,10 @@ ccio_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents, ...@@ -982,6 +990,10 @@ ccio_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents,
BUG_ON(!dev); BUG_ON(!dev);
ioc = GET_IOC(dev); ioc = GET_IOC(dev);
if (!ioc) {
WARN_ON(!ioc);
return;
}
DBG_RUN_SG("%s() START %d entries, %p,%x\n", DBG_RUN_SG("%s() START %d entries, %p,%x\n",
__func__, nents, sg_virt(sglist), sglist->length); __func__, nents, sg_virt(sglist), sglist->length);
......
...@@ -154,7 +154,10 @@ struct dino_device ...@@ -154,7 +154,10 @@ struct dino_device
}; };
/* Looks nice and keeps the compiler happy */ /* Looks nice and keeps the compiler happy */
#define DINO_DEV(d) ((struct dino_device *) d) #define DINO_DEV(d) ({ \
void *__pdata = d; \
BUG_ON(!__pdata); \
(struct dino_device *)__pdata; })
/* /*
......
...@@ -111,8 +111,10 @@ static u32 lba_t32; ...@@ -111,8 +111,10 @@ static u32 lba_t32;
/* Looks nice and keeps the compiler happy */ /* Looks nice and keeps the compiler happy */
#define LBA_DEV(d) ((struct lba_device *) (d)) #define LBA_DEV(d) ({ \
void *__pdata = d; \
BUG_ON(!__pdata); \
(struct lba_device *)__pdata; })
/* /*
** Only allow 8 subsidiary busses per LBA ** Only allow 8 subsidiary busses per LBA
......
...@@ -691,6 +691,8 @@ static int sba_dma_supported( struct device *dev, u64 mask) ...@@ -691,6 +691,8 @@ static int sba_dma_supported( struct device *dev, u64 mask)
return 0; return 0;
ioc = GET_IOC(dev); ioc = GET_IOC(dev);
if (!ioc)
return 0;
/* /*
* check if mask is >= than the current max IO Virt Address * check if mask is >= than the current max IO Virt Address
...@@ -722,6 +724,8 @@ sba_map_single(struct device *dev, void *addr, size_t size, ...@@ -722,6 +724,8 @@ sba_map_single(struct device *dev, void *addr, size_t size,
int pide; int pide;
ioc = GET_IOC(dev); ioc = GET_IOC(dev);
if (!ioc)
return DMA_ERROR_CODE;
/* save offset bits */ /* save offset bits */
offset = ((dma_addr_t) (long) addr) & ~IOVP_MASK; offset = ((dma_addr_t) (long) addr) & ~IOVP_MASK;
...@@ -803,6 +807,10 @@ sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size, ...@@ -803,6 +807,10 @@ sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size,
DBG_RUN("%s() iovp 0x%lx/%x\n", __func__, (long) iova, size); DBG_RUN("%s() iovp 0x%lx/%x\n", __func__, (long) iova, size);
ioc = GET_IOC(dev); ioc = GET_IOC(dev);
if (!ioc) {
WARN_ON(!ioc);
return;
}
offset = iova & ~IOVP_MASK; offset = iova & ~IOVP_MASK;
iova ^= offset; /* clear offset bits */ iova ^= offset; /* clear offset bits */
size += offset; size += offset;
...@@ -942,6 +950,8 @@ sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents, ...@@ -942,6 +950,8 @@ sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
DBG_RUN_SG("%s() START %d entries\n", __func__, nents); DBG_RUN_SG("%s() START %d entries\n", __func__, nents);
ioc = GET_IOC(dev); ioc = GET_IOC(dev);
if (!ioc)
return 0;
/* Fast path single entry scatterlists. */ /* Fast path single entry scatterlists. */
if (nents == 1) { if (nents == 1) {
...@@ -1027,6 +1037,10 @@ sba_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents, ...@@ -1027,6 +1037,10 @@ sba_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents,
__func__, nents, sg_virt(sglist), sglist->length); __func__, nents, sg_virt(sglist), sglist->length);
ioc = GET_IOC(dev); ioc = GET_IOC(dev);
if (!ioc) {
WARN_ON(!ioc);
return;
}
#ifdef SBA_COLLECT_STATS #ifdef SBA_COLLECT_STATS
ioc->usg_calls++; ioc->usg_calls++;
......
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