.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * RapidIO mport character device |
---|
3 | 4 | * |
---|
.. | .. |
---|
8 | 9 | * Jerry Jacobs <jerry.jacobs@prodrive-technologies.com> |
---|
9 | 10 | * Copyright (C) 2014 Texas Instruments Incorporated |
---|
10 | 11 | * Aurelien Jacquiot <a-jacquiot@ti.com> |
---|
11 | | - * |
---|
12 | | - * This program is free software; you can redistribute it and/or modify it |
---|
13 | | - * under the terms of the GNU General Public License as published by the |
---|
14 | | - * Free Software Foundation; either version 2 of the License, or (at your |
---|
15 | | - * option) any later version. |
---|
16 | 12 | */ |
---|
17 | 13 | #include <linux/module.h> |
---|
18 | 14 | #include <linux/kernel.h> |
---|
.. | .. |
---|
576 | 572 | struct mport_dma_req *req = container_of(ref, struct mport_dma_req, |
---|
577 | 573 | refcount); |
---|
578 | 574 | struct mport_cdev_priv *priv = req->priv; |
---|
579 | | - unsigned int i; |
---|
580 | 575 | |
---|
581 | 576 | dma_unmap_sg(req->dmach->device->dev, |
---|
582 | 577 | req->sgt.sgl, req->sgt.nents, req->dir); |
---|
583 | 578 | sg_free_table(&req->sgt); |
---|
584 | 579 | if (req->page_list) { |
---|
585 | | - for (i = 0; i < req->nr_pages; i++) |
---|
586 | | - put_page(req->page_list[i]); |
---|
| 580 | + unpin_user_pages(req->page_list, req->nr_pages); |
---|
587 | 581 | kfree(req->page_list); |
---|
588 | 582 | } |
---|
589 | 583 | |
---|
.. | .. |
---|
819 | 813 | struct mport_dma_req *req; |
---|
820 | 814 | struct mport_dev *md = priv->md; |
---|
821 | 815 | struct dma_chan *chan; |
---|
822 | | - int i, ret; |
---|
| 816 | + int ret; |
---|
823 | 817 | int nents; |
---|
824 | 818 | |
---|
825 | 819 | if (xfer->length == 0) |
---|
.. | .. |
---|
866 | 860 | goto err_req; |
---|
867 | 861 | } |
---|
868 | 862 | |
---|
869 | | - pinned = get_user_pages_fast( |
---|
| 863 | + pinned = pin_user_pages_fast( |
---|
870 | 864 | (unsigned long)xfer->loc_addr & PAGE_MASK, |
---|
871 | | - nr_pages, dir == DMA_FROM_DEVICE, page_list); |
---|
| 865 | + nr_pages, |
---|
| 866 | + dir == DMA_FROM_DEVICE ? FOLL_WRITE : 0, |
---|
| 867 | + page_list); |
---|
872 | 868 | |
---|
873 | 869 | if (pinned != nr_pages) { |
---|
874 | 870 | if (pinned < 0) { |
---|
875 | | - rmcd_error("get_user_pages_unlocked err=%ld", |
---|
| 871 | + rmcd_error("pin_user_pages_fast err=%ld", |
---|
876 | 872 | pinned); |
---|
877 | 873 | nr_pages = 0; |
---|
878 | 874 | } else { |
---|
.. | .. |
---|
954 | 950 | |
---|
955 | 951 | err_pg: |
---|
956 | 952 | if (!req->page_list) { |
---|
957 | | - for (i = 0; i < nr_pages; i++) |
---|
958 | | - put_page(page_list[i]); |
---|
| 953 | + unpin_user_pages(page_list, nr_pages); |
---|
959 | 954 | kfree(page_list); |
---|
960 | 955 | } |
---|
961 | 956 | err_req: |
---|
.. | .. |
---|
987 | 982 | |
---|
988 | 983 | if (unlikely(copy_from_user(transfer, |
---|
989 | 984 | (void __user *)(uintptr_t)transaction.block, |
---|
990 | | - transaction.count * sizeof(*transfer)))) { |
---|
| 985 | + array_size(sizeof(*transfer), transaction.count)))) { |
---|
991 | 986 | ret = -EFAULT; |
---|
992 | 987 | goto out_free; |
---|
993 | 988 | } |
---|
.. | .. |
---|
1000 | 995 | |
---|
1001 | 996 | if (unlikely(copy_to_user((void __user *)(uintptr_t)transaction.block, |
---|
1002 | 997 | transfer, |
---|
1003 | | - transaction.count * sizeof(*transfer)))) |
---|
| 998 | + array_size(sizeof(*transfer), transaction.count)))) |
---|
1004 | 999 | ret = -EFAULT; |
---|
1005 | 1000 | |
---|
1006 | 1001 | out_free: |
---|
.. | .. |
---|
1719 | 1714 | if (rval & RIO_PEF_SWITCH) { |
---|
1720 | 1715 | rio_mport_read_config_32(mport, destid, hopcount, |
---|
1721 | 1716 | RIO_SWP_INFO_CAR, &swpinfo); |
---|
1722 | | - size += (RIO_GET_TOTAL_PORTS(swpinfo) * |
---|
1723 | | - sizeof(rswitch->nextdev[0])) + sizeof(*rswitch); |
---|
| 1717 | + size += struct_size(rswitch, nextdev, RIO_GET_TOTAL_PORTS(swpinfo)); |
---|
1724 | 1718 | } |
---|
1725 | 1719 | |
---|
1726 | 1720 | rdev = kzalloc(size, GFP_KERNEL); |
---|
.. | .. |
---|
1809 | 1803 | rio_init_dbell_res(&rdev->riores[RIO_DOORBELL_RESOURCE], |
---|
1810 | 1804 | 0, 0xffff); |
---|
1811 | 1805 | err = rio_add_device(rdev); |
---|
1812 | | - if (err) |
---|
1813 | | - goto cleanup; |
---|
| 1806 | + if (err) { |
---|
| 1807 | + put_device(&rdev->dev); |
---|
| 1808 | + return err; |
---|
| 1809 | + } |
---|
| 1810 | + |
---|
1814 | 1811 | rio_dev_get(rdev); |
---|
1815 | 1812 | |
---|
1816 | 1813 | return 0; |
---|
.. | .. |
---|
1906 | 1903 | |
---|
1907 | 1904 | priv->md = chdev; |
---|
1908 | 1905 | |
---|
1909 | | - mutex_lock(&chdev->file_mutex); |
---|
1910 | | - list_add_tail(&priv->list, &chdev->file_list); |
---|
1911 | | - mutex_unlock(&chdev->file_mutex); |
---|
1912 | | - |
---|
1913 | 1906 | INIT_LIST_HEAD(&priv->db_filters); |
---|
1914 | 1907 | INIT_LIST_HEAD(&priv->pw_filters); |
---|
1915 | 1908 | spin_lock_init(&priv->fifo_lock); |
---|
.. | .. |
---|
1918 | 1911 | sizeof(struct rio_event) * MPORT_EVENT_DEPTH, |
---|
1919 | 1912 | GFP_KERNEL); |
---|
1920 | 1913 | if (ret < 0) { |
---|
| 1914 | + put_device(&chdev->dev); |
---|
1921 | 1915 | dev_err(&chdev->dev, DRV_NAME ": kfifo_alloc failed\n"); |
---|
1922 | 1916 | ret = -ENOMEM; |
---|
1923 | 1917 | goto err_fifo; |
---|
.. | .. |
---|
1928 | 1922 | spin_lock_init(&priv->req_lock); |
---|
1929 | 1923 | mutex_init(&priv->dma_lock); |
---|
1930 | 1924 | #endif |
---|
| 1925 | + mutex_lock(&chdev->file_mutex); |
---|
| 1926 | + list_add_tail(&priv->list, &chdev->file_list); |
---|
| 1927 | + mutex_unlock(&chdev->file_mutex); |
---|
1931 | 1928 | |
---|
1932 | 1929 | filp->private_data = priv; |
---|
1933 | 1930 | goto out; |
---|
.. | .. |
---|
2160 | 2157 | switch (map->dir) { |
---|
2161 | 2158 | case MAP_INBOUND: |
---|
2162 | 2159 | rio_unmap_inb_region(mport, map->phys_addr); |
---|
| 2160 | + fallthrough; |
---|
2163 | 2161 | case MAP_DMA: |
---|
2164 | 2162 | dma_free_coherent(mport->dev.parent, map->size, |
---|
2165 | 2163 | map->virt_addr, map->phys_addr); |
---|