Skip to content

Commit 178dfd2

Browse files
committed
Merge: bnx2i/bnx2x issues with cnic uio interface
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/3770 # Merge Request Required Information ## Summary of Changes Some upstream bnx2x/cnic and DMA mapping changes were reverted from in order to avoid a regression in bnx2i functionality (https://issues.redhat.com/browse/RHEL-2542) Additionally, the bnx2x/cnic uio interface used by bnx2i has not functioned with an iommu enabled in Centos Stream 9 at all. I'd like to restore the previously reverted changes, and correctly fix the bnx2x/cnic interface to work correctly, including with an iommu enabled. This is the latest posting and upstream discussion on my fixes. https://lore.kernel.org/all/20240201233400.3394996-1-cleech@redhat.com/ I've addressed all feedback, but it's still not 100% that Greg KH will take the uio api changes or if he will just leave this driver as unfixable upstream. ## Approved Development Ticket JIRA: https://issues.redhat.com/browse/RHEL-26081 Signed-off-by: Chris Leech <cleech@redhat.com> Approved-by: Aristeu Rozanski <arozansk@redhat.com> Approved-by: John Meneghini <jmeneghi@redhat.com> Approved-by: Ewan D. Milne <emilne@redhat.com> Approved-by: Jerry Snitselaar <jsnitsel@redhat.com> Merged-by: Lucas Zampieri <lzampier@redhat.com>
2 parents ff70b77 + caac3d0 commit 178dfd2

File tree

10 files changed

+92
-32
lines changed

10 files changed

+92
-32
lines changed

arch/arm/mm/dma-mapping.c

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -695,14 +695,6 @@ static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
695695
if (mask < 0xffffffffULL)
696696
gfp |= GFP_DMA;
697697

698-
/*
699-
* Following is a work-around (a.k.a. hack) to prevent pages
700-
* with __GFP_COMP being passed to split_page() which cannot
701-
* handle them. The real problem is that this flag probably
702-
* should be 0 on ARM as it is not supported on this
703-
* platform; see CONFIG_HUGETLBFS.
704-
*/
705-
gfp &= ~(__GFP_COMP);
706698
args.gfp = gfp;
707699

708700
*handle = DMA_MAPPING_ERROR;
@@ -1435,15 +1427,6 @@ static void *__arm_iommu_alloc_attrs(struct device *dev, size_t size,
14351427
return __iommu_alloc_simple(dev, size, gfp, handle,
14361428
coherent_flag, attrs);
14371429

1438-
/*
1439-
* Following is a work-around (a.k.a. hack) to prevent pages
1440-
* with __GFP_COMP being passed to split_page() which cannot
1441-
* handle them. The real problem is that this flag probably
1442-
* should be 0 on ARM as it is not supported on this
1443-
* platform; see CONFIG_HUGETLBFS.
1444-
*/
1445-
gfp &= ~(__GFP_COMP);
1446-
14471430
pages = __iommu_alloc_buffer(dev, size, gfp, attrs, coherent_flag);
14481431
if (!pages)
14491432
return NULL;

drivers/iommu/dma-iommu.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -791,9 +791,6 @@ static struct page **__iommu_dma_alloc_pages(struct device *dev,
791791
/* IOMMU can map any pages, so himem can also be used here */
792792
gfp |= __GFP_NOWARN | __GFP_HIGHMEM;
793793

794-
/* It makes no sense to muck about with huge pages */
795-
gfp &= ~__GFP_COMP;
796-
797794
while (count) {
798795
struct page *page = NULL;
799796
unsigned int order_size;

drivers/net/ethernet/broadcom/bnx2.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,7 @@ static void bnx2_setup_cnic_irq_info(struct bnx2 *bp)
367367
cp->irq_arr[0].status_blk = (void *)
368368
((unsigned long) bnapi->status_blk.msi +
369369
(BNX2_SBLK_MSIX_ALIGN_SIZE * sb_id));
370+
cp->irq_arr[0].status_blk_map = bp->status_blk_mapping;
370371
cp->irq_arr[0].status_blk_num = sb_id;
371372
cp->num_irq = 1;
372373
}

drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14900,9 +14900,11 @@ void bnx2x_setup_cnic_irq_info(struct bnx2x *bp)
1490014900
else
1490114901
cp->irq_arr[0].status_blk = (void *)bp->cnic_sb.e1x_sb;
1490214902

14903+
cp->irq_arr[0].status_blk_map = bp->cnic_sb_mapping;
1490314904
cp->irq_arr[0].status_blk_num = bnx2x_cnic_fw_sb_id(bp);
1490414905
cp->irq_arr[0].status_blk_num2 = bnx2x_cnic_igu_sb_id(bp);
1490514906
cp->irq_arr[1].status_blk = bp->def_status_blk;
14907+
cp->irq_arr[1].status_blk_map = bp->def_status_blk_mapping;
1490614908
cp->irq_arr[1].status_blk_num = DEF_SB_ID;
1490714909
cp->irq_arr[1].status_blk_num2 = DEF_SB_IGU_ID;
1490814910

drivers/net/ethernet/broadcom/cnic.c

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1027,16 +1027,14 @@ static int __cnic_alloc_uio_rings(struct cnic_uio_dev *udev, int pages)
10271027

10281028
udev->l2_ring_size = pages * CNIC_PAGE_SIZE;
10291029
udev->l2_ring = dma_alloc_coherent(&udev->pdev->dev, udev->l2_ring_size,
1030-
&udev->l2_ring_map,
1031-
GFP_KERNEL | __GFP_COMP);
1030+
&udev->l2_ring_map, GFP_KERNEL);
10321031
if (!udev->l2_ring)
10331032
return -ENOMEM;
10341033

10351034
udev->l2_buf_size = (cp->l2_rx_ring_size + 1) * cp->l2_single_buf_size;
10361035
udev->l2_buf_size = CNIC_PAGE_ALIGN(udev->l2_buf_size);
10371036
udev->l2_buf = dma_alloc_coherent(&udev->pdev->dev, udev->l2_buf_size,
1038-
&udev->l2_buf_map,
1039-
GFP_KERNEL | __GFP_COMP);
1037+
&udev->l2_buf_map, GFP_KERNEL);
10401038
if (!udev->l2_buf) {
10411039
__cnic_free_uio_rings(udev);
10421040
return -ENOMEM;
@@ -1109,31 +1107,38 @@ static int cnic_init_uio(struct cnic_dev *dev)
11091107
TX_MAX_TSS_RINGS + 1);
11101108
uinfo->mem[1].addr = (unsigned long) cp->status_blk.gen &
11111109
CNIC_PAGE_MASK;
1110+
uinfo->mem[1].dma_addr = cp->status_blk_map;
11121111
if (cp->ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX)
1113-
uinfo->mem[1].size = BNX2_SBLK_MSIX_ALIGN_SIZE * 9;
1112+
uinfo->mem[1].size = PAGE_ALIGN(BNX2_SBLK_MSIX_ALIGN_SIZE * 9);
11141113
else
1115-
uinfo->mem[1].size = BNX2_SBLK_MSIX_ALIGN_SIZE;
1114+
uinfo->mem[1].size = PAGE_ALIGN(BNX2_SBLK_MSIX_ALIGN_SIZE);
11161115

11171116
uinfo->name = "bnx2_cnic";
11181117
} else if (test_bit(CNIC_F_BNX2X_CLASS, &dev->flags)) {
11191118
uinfo->mem[0].size = pci_resource_len(dev->pcidev, 0);
11201119

11211120
uinfo->mem[1].addr = (unsigned long) cp->bnx2x_def_status_blk &
11221121
CNIC_PAGE_MASK;
1123-
uinfo->mem[1].size = sizeof(*cp->bnx2x_def_status_blk);
1122+
uinfo->mem[1].dma_addr = cp->status_blk_map;
1123+
uinfo->mem[1].size = PAGE_ALIGN(sizeof(*cp->bnx2x_def_status_blk));
11241124

11251125
uinfo->name = "bnx2x_cnic";
11261126
}
11271127

1128-
uinfo->mem[1].memtype = UIO_MEM_LOGICAL;
1128+
uinfo->mem[1].dma_device = &dev->pcidev->dev;
1129+
uinfo->mem[1].memtype = UIO_MEM_DMA_COHERENT;
11291130

11301131
uinfo->mem[2].addr = (unsigned long) udev->l2_ring;
1131-
uinfo->mem[2].size = udev->l2_ring_size;
1132-
uinfo->mem[2].memtype = UIO_MEM_LOGICAL;
1132+
uinfo->mem[2].dma_addr = udev->l2_ring_map;
1133+
uinfo->mem[2].size = PAGE_ALIGN(udev->l2_ring_size);
1134+
uinfo->mem[2].dma_device = &dev->pcidev->dev;
1135+
uinfo->mem[2].memtype = UIO_MEM_DMA_COHERENT;
11331136

11341137
uinfo->mem[3].addr = (unsigned long) udev->l2_buf;
1135-
uinfo->mem[3].size = udev->l2_buf_size;
1136-
uinfo->mem[3].memtype = UIO_MEM_LOGICAL;
1138+
uinfo->mem[3].dma_addr = udev->l2_buf_map;
1139+
uinfo->mem[3].size = PAGE_ALIGN(udev->l2_buf_size);
1140+
uinfo->mem[3].dma_device = &dev->pcidev->dev;
1141+
uinfo->mem[3].memtype = UIO_MEM_DMA_COHERENT;
11371142

11381143
uinfo->version = CNIC_MODULE_VERSION;
11391144
uinfo->irq = UIO_IRQ_CUSTOM;
@@ -1315,6 +1320,7 @@ static int cnic_alloc_bnx2x_resc(struct cnic_dev *dev)
13151320
return 0;
13161321

13171322
cp->bnx2x_def_status_blk = cp->ethdev->irq_arr[1].status_blk;
1323+
cp->status_blk_map = cp->ethdev->irq_arr[1].status_blk_map;
13181324

13191325
cp->l2_rx_ring_size = 15;
13201326

@@ -5326,6 +5332,7 @@ static int cnic_start_hw(struct cnic_dev *dev)
53265332
pci_dev_get(dev->pcidev);
53275333
cp->func = PCI_FUNC(dev->pcidev->devfn);
53285334
cp->status_blk.gen = ethdev->irq_arr[0].status_blk;
5335+
cp->status_blk_map = ethdev->irq_arr[0].status_blk_map;
53295336
cp->status_blk_num = ethdev->irq_arr[0].status_blk_num;
53305337

53315338
err = cp->alloc_resc(dev);

drivers/net/ethernet/broadcom/cnic.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ struct cnic_local {
260260
#define SM_RX_ID 0
261261
#define SM_TX_ID 1
262262
} status_blk;
263+
dma_addr_t status_blk_map;
263264

264265
struct host_sp_status_block *bnx2x_def_status_blk;
265266

drivers/net/ethernet/broadcom/cnic_if.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ struct cnic_ops {
190190
struct cnic_irq {
191191
unsigned int vector;
192192
void *status_blk;
193+
dma_addr_t status_blk_map;
193194
u32 status_blk_num;
194195
u32 status_blk_num2;
195196
u32 irq_flags;

drivers/uio/uio.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <linux/kobject.h>
2525
#include <linux/cdev.h>
2626
#include <linux/uio_driver.h>
27+
#include <linux/dma-mapping.h>
2728

2829
#define UIO_MAX_DEVICES (1U << MINORBITS)
2930

@@ -757,6 +758,49 @@ static int uio_mmap_physical(struct vm_area_struct *vma)
757758
vma->vm_page_prot);
758759
}
759760

761+
static int uio_mmap_dma_coherent(struct vm_area_struct *vma)
762+
{
763+
struct uio_device *idev = vma->vm_private_data;
764+
struct uio_mem *mem;
765+
void *addr;
766+
int ret = 0;
767+
int mi;
768+
769+
mi = uio_find_mem_index(vma);
770+
if (mi < 0)
771+
return -EINVAL;
772+
773+
mem = idev->info->mem + mi;
774+
775+
if (mem->addr & ~PAGE_MASK)
776+
return -ENODEV;
777+
if (mem->dma_addr & ~PAGE_MASK)
778+
return -ENODEV;
779+
if (!mem->dma_device)
780+
return -ENODEV;
781+
if (vma->vm_end - vma->vm_start > mem->size)
782+
return -EINVAL;
783+
784+
dev_warn(mem->dma_device,
785+
"use of UIO_MEM_DMA_COHERENT is highly discouraged");
786+
787+
/*
788+
* UIO uses offset to index into the maps for a device.
789+
* We need to clear vm_pgoff for dma_mmap_coherent.
790+
*/
791+
vma->vm_pgoff = 0;
792+
793+
addr = (void *)mem->addr;
794+
ret = dma_mmap_coherent(mem->dma_device,
795+
vma,
796+
addr,
797+
mem->dma_addr,
798+
vma->vm_end - vma->vm_start);
799+
vma->vm_pgoff = mi;
800+
801+
return ret;
802+
}
803+
760804
static int uio_mmap(struct file *filep, struct vm_area_struct *vma)
761805
{
762806
struct uio_listener *listener = filep->private_data;
@@ -804,6 +848,9 @@ static int uio_mmap(struct file *filep, struct vm_area_struct *vma)
804848
case UIO_MEM_VIRTUAL:
805849
ret = uio_mmap_logical(vma);
806850
break;
851+
case UIO_MEM_DMA_COHERENT:
852+
ret = uio_mmap_dma_coherent(vma);
853+
break;
807854
default:
808855
ret = -EINVAL;
809856
}

include/linux/uio_driver.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,26 @@ struct uio_map;
2828
* logical, virtual, or physical & phys_addr_t
2929
* should always be large enough to handle any of
3030
* the address types)
31+
* @dma_addr: DMA handle set by dma_alloc_coherent, used with
32+
* UIO_MEM_DMA_COHERENT only (@addr should be the
33+
* void * returned from the same dma_alloc_coherent call)
3134
* @offs: offset of device memory within the page
3235
* @size: size of IO (multiple of page size)
3336
* @memtype: type of memory addr points to
3437
* @internal_addr: ioremap-ped version of addr, for driver internal use
38+
* @dma_device: device struct that was passed to dma_alloc_coherent,
39+
* used with UIO_MEM_DMA_COHERENT only
3540
* @map: for use by the UIO core only.
3641
*/
3742
struct uio_mem {
3843
const char *name;
3944
phys_addr_t addr;
45+
dma_addr_t dma_addr;
4046
unsigned long offs;
4147
resource_size_t size;
4248
int memtype;
4349
void __iomem *internal_addr;
50+
struct device *dma_device;
4451
struct uio_map *map;
4552
};
4653

@@ -158,6 +165,12 @@ extern int __must_check
158165
#define UIO_MEM_LOGICAL 2
159166
#define UIO_MEM_VIRTUAL 3
160167
#define UIO_MEM_IOVA 4
168+
/*
169+
* UIO_MEM_DMA_COHERENT exists for legacy drivers that had been getting by with
170+
* improperly mapping DMA coherent allocations through the other modes.
171+
* Do not use in new drivers.
172+
*/
173+
#define UIO_MEM_DMA_COHERENT 5
161174

162175
/* defines for uio_port->porttype */
163176
#define UIO_PORT_NONE 0

kernel/dma/mapping.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,14 @@ void *dma_alloc_attrs(struct device *dev, size_t size, dma_addr_t *dma_handle,
502502

503503
WARN_ON_ONCE(!dev->coherent_dma_mask);
504504

505+
/*
506+
* DMA allocations can never be turned back into a page pointer, so
507+
* requesting compound pages doesn't make sense (and can't even be
508+
* supported at all by various backends).
509+
*/
510+
if (WARN_ON_ONCE(flag & __GFP_COMP))
511+
return NULL;
512+
505513
if (dma_alloc_from_dev_coherent(dev, size, dma_handle, &cpu_addr))
506514
return cpu_addr;
507515

0 commit comments

Comments
 (0)