18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci** ccio-dma.c: 48c2ecf20Sopenharmony_ci** DMA management routines for first generation cache-coherent machines. 58c2ecf20Sopenharmony_ci** Program U2/Uturn in "Virtual Mode" and use the I/O MMU. 68c2ecf20Sopenharmony_ci** 78c2ecf20Sopenharmony_ci** (c) Copyright 2000 Grant Grundler 88c2ecf20Sopenharmony_ci** (c) Copyright 2000 Ryan Bradetich 98c2ecf20Sopenharmony_ci** (c) Copyright 2000 Hewlett-Packard Company 108c2ecf20Sopenharmony_ci** 118c2ecf20Sopenharmony_ci** 128c2ecf20Sopenharmony_ci** 138c2ecf20Sopenharmony_ci** "Real Mode" operation refers to U2/Uturn chip operation. 148c2ecf20Sopenharmony_ci** U2/Uturn were designed to perform coherency checks w/o using 158c2ecf20Sopenharmony_ci** the I/O MMU - basically what x86 does. 168c2ecf20Sopenharmony_ci** 178c2ecf20Sopenharmony_ci** Philipp Rumpf has a "Real Mode" driver for PCX-W machines at: 188c2ecf20Sopenharmony_ci** CVSROOT=:pserver:anonymous@198.186.203.37:/cvsroot/linux-parisc 198c2ecf20Sopenharmony_ci** cvs -z3 co linux/arch/parisc/kernel/dma-rm.c 208c2ecf20Sopenharmony_ci** 218c2ecf20Sopenharmony_ci** I've rewritten his code to work under TPG's tree. See ccio-rm-dma.c. 228c2ecf20Sopenharmony_ci** 238c2ecf20Sopenharmony_ci** Drawbacks of using Real Mode are: 248c2ecf20Sopenharmony_ci** o outbound DMA is slower - U2 won't prefetch data (GSC+ XQL signal). 258c2ecf20Sopenharmony_ci** o Inbound DMA less efficient - U2 can't use DMA_FAST attribute. 268c2ecf20Sopenharmony_ci** o Ability to do scatter/gather in HW is lost. 278c2ecf20Sopenharmony_ci** o Doesn't work under PCX-U/U+ machines since they didn't follow 288c2ecf20Sopenharmony_ci** the coherency design originally worked out. Only PCX-W does. 298c2ecf20Sopenharmony_ci*/ 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include <linux/types.h> 328c2ecf20Sopenharmony_ci#include <linux/kernel.h> 338c2ecf20Sopenharmony_ci#include <linux/init.h> 348c2ecf20Sopenharmony_ci#include <linux/mm.h> 358c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 368c2ecf20Sopenharmony_ci#include <linux/slab.h> 378c2ecf20Sopenharmony_ci#include <linux/string.h> 388c2ecf20Sopenharmony_ci#include <linux/pci.h> 398c2ecf20Sopenharmony_ci#include <linux/reboot.h> 408c2ecf20Sopenharmony_ci#include <linux/proc_fs.h> 418c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 428c2ecf20Sopenharmony_ci#include <linux/dma-map-ops.h> 438c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 448c2ecf20Sopenharmony_ci#include <linux/iommu-helper.h> 458c2ecf20Sopenharmony_ci#include <linux/export.h> 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#include <asm/byteorder.h> 488c2ecf20Sopenharmony_ci#include <asm/cache.h> /* for L1_CACHE_BYTES */ 498c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 508c2ecf20Sopenharmony_ci#include <asm/page.h> 518c2ecf20Sopenharmony_ci#include <asm/dma.h> 528c2ecf20Sopenharmony_ci#include <asm/io.h> 538c2ecf20Sopenharmony_ci#include <asm/hardware.h> /* for register_module() */ 548c2ecf20Sopenharmony_ci#include <asm/parisc-device.h> 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#include "iommu.h" 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* 598c2ecf20Sopenharmony_ci** Choose "ccio" since that's what HP-UX calls it. 608c2ecf20Sopenharmony_ci** Make it easier for folks to migrate from one to the other :^) 618c2ecf20Sopenharmony_ci*/ 628c2ecf20Sopenharmony_ci#define MODULE_NAME "ccio" 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#undef DEBUG_CCIO_RES 658c2ecf20Sopenharmony_ci#undef DEBUG_CCIO_RUN 668c2ecf20Sopenharmony_ci#undef DEBUG_CCIO_INIT 678c2ecf20Sopenharmony_ci#undef DEBUG_CCIO_RUN_SG 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS 708c2ecf20Sopenharmony_ci/* depends on proc fs support. But costs CPU performance. */ 718c2ecf20Sopenharmony_ci#undef CCIO_COLLECT_STATS 728c2ecf20Sopenharmony_ci#endif 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci#include <asm/runway.h> /* for proc_runway_root */ 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci#ifdef DEBUG_CCIO_INIT 778c2ecf20Sopenharmony_ci#define DBG_INIT(x...) printk(x) 788c2ecf20Sopenharmony_ci#else 798c2ecf20Sopenharmony_ci#define DBG_INIT(x...) 808c2ecf20Sopenharmony_ci#endif 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci#ifdef DEBUG_CCIO_RUN 838c2ecf20Sopenharmony_ci#define DBG_RUN(x...) printk(x) 848c2ecf20Sopenharmony_ci#else 858c2ecf20Sopenharmony_ci#define DBG_RUN(x...) 868c2ecf20Sopenharmony_ci#endif 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci#ifdef DEBUG_CCIO_RES 898c2ecf20Sopenharmony_ci#define DBG_RES(x...) printk(x) 908c2ecf20Sopenharmony_ci#else 918c2ecf20Sopenharmony_ci#define DBG_RES(x...) 928c2ecf20Sopenharmony_ci#endif 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci#ifdef DEBUG_CCIO_RUN_SG 958c2ecf20Sopenharmony_ci#define DBG_RUN_SG(x...) printk(x) 968c2ecf20Sopenharmony_ci#else 978c2ecf20Sopenharmony_ci#define DBG_RUN_SG(x...) 988c2ecf20Sopenharmony_ci#endif 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci#define CCIO_INLINE inline 1018c2ecf20Sopenharmony_ci#define WRITE_U32(value, addr) __raw_writel(value, addr) 1028c2ecf20Sopenharmony_ci#define READ_U32(addr) __raw_readl(addr) 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci#define U2_IOA_RUNWAY 0x580 1058c2ecf20Sopenharmony_ci#define U2_BC_GSC 0x501 1068c2ecf20Sopenharmony_ci#define UTURN_IOA_RUNWAY 0x581 1078c2ecf20Sopenharmony_ci#define UTURN_BC_GSC 0x502 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci#define IOA_NORMAL_MODE 0x00020080 /* IO_CONTROL to turn on CCIO */ 1108c2ecf20Sopenharmony_ci#define CMD_TLB_DIRECT_WRITE 35 /* IO_COMMAND for I/O TLB Writes */ 1118c2ecf20Sopenharmony_ci#define CMD_TLB_PURGE 33 /* IO_COMMAND to Purge I/O TLB entry */ 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistruct ioa_registers { 1148c2ecf20Sopenharmony_ci /* Runway Supervisory Set */ 1158c2ecf20Sopenharmony_ci int32_t unused1[12]; 1168c2ecf20Sopenharmony_ci uint32_t io_command; /* Offset 12 */ 1178c2ecf20Sopenharmony_ci uint32_t io_status; /* Offset 13 */ 1188c2ecf20Sopenharmony_ci uint32_t io_control; /* Offset 14 */ 1198c2ecf20Sopenharmony_ci int32_t unused2[1]; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci /* Runway Auxiliary Register Set */ 1228c2ecf20Sopenharmony_ci uint32_t io_err_resp; /* Offset 0 */ 1238c2ecf20Sopenharmony_ci uint32_t io_err_info; /* Offset 1 */ 1248c2ecf20Sopenharmony_ci uint32_t io_err_req; /* Offset 2 */ 1258c2ecf20Sopenharmony_ci uint32_t io_err_resp_hi; /* Offset 3 */ 1268c2ecf20Sopenharmony_ci uint32_t io_tlb_entry_m; /* Offset 4 */ 1278c2ecf20Sopenharmony_ci uint32_t io_tlb_entry_l; /* Offset 5 */ 1288c2ecf20Sopenharmony_ci uint32_t unused3[1]; 1298c2ecf20Sopenharmony_ci uint32_t io_pdir_base; /* Offset 7 */ 1308c2ecf20Sopenharmony_ci uint32_t io_io_low_hv; /* Offset 8 */ 1318c2ecf20Sopenharmony_ci uint32_t io_io_high_hv; /* Offset 9 */ 1328c2ecf20Sopenharmony_ci uint32_t unused4[1]; 1338c2ecf20Sopenharmony_ci uint32_t io_chain_id_mask; /* Offset 11 */ 1348c2ecf20Sopenharmony_ci uint32_t unused5[2]; 1358c2ecf20Sopenharmony_ci uint32_t io_io_low; /* Offset 14 */ 1368c2ecf20Sopenharmony_ci uint32_t io_io_high; /* Offset 15 */ 1378c2ecf20Sopenharmony_ci}; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci/* 1408c2ecf20Sopenharmony_ci** IOA Registers 1418c2ecf20Sopenharmony_ci** ------------- 1428c2ecf20Sopenharmony_ci** 1438c2ecf20Sopenharmony_ci** Runway IO_CONTROL Register (+0x38) 1448c2ecf20Sopenharmony_ci** 1458c2ecf20Sopenharmony_ci** The Runway IO_CONTROL register controls the forwarding of transactions. 1468c2ecf20Sopenharmony_ci** 1478c2ecf20Sopenharmony_ci** | 0 ... 13 | 14 15 | 16 ... 21 | 22 | 23 24 | 25 ... 31 | 1488c2ecf20Sopenharmony_ci** | HV | TLB | reserved | HV | mode | reserved | 1498c2ecf20Sopenharmony_ci** 1508c2ecf20Sopenharmony_ci** o mode field indicates the address translation of transactions 1518c2ecf20Sopenharmony_ci** forwarded from Runway to GSC+: 1528c2ecf20Sopenharmony_ci** Mode Name Value Definition 1538c2ecf20Sopenharmony_ci** Off (default) 0 Opaque to matching addresses. 1548c2ecf20Sopenharmony_ci** Include 1 Transparent for matching addresses. 1558c2ecf20Sopenharmony_ci** Peek 3 Map matching addresses. 1568c2ecf20Sopenharmony_ci** 1578c2ecf20Sopenharmony_ci** + "Off" mode: Runway transactions which match the I/O range 1588c2ecf20Sopenharmony_ci** specified by the IO_IO_LOW/IO_IO_HIGH registers will be ignored. 1598c2ecf20Sopenharmony_ci** + "Include" mode: all addresses within the I/O range specified 1608c2ecf20Sopenharmony_ci** by the IO_IO_LOW and IO_IO_HIGH registers are transparently 1618c2ecf20Sopenharmony_ci** forwarded. This is the I/O Adapter's normal operating mode. 1628c2ecf20Sopenharmony_ci** + "Peek" mode: used during system configuration to initialize the 1638c2ecf20Sopenharmony_ci** GSC+ bus. Runway Write_Shorts in the address range specified by 1648c2ecf20Sopenharmony_ci** IO_IO_LOW and IO_IO_HIGH are forwarded through the I/O Adapter 1658c2ecf20Sopenharmony_ci** *AND* the GSC+ address is remapped to the Broadcast Physical 1668c2ecf20Sopenharmony_ci** Address space by setting the 14 high order address bits of the 1678c2ecf20Sopenharmony_ci** 32 bit GSC+ address to ones. 1688c2ecf20Sopenharmony_ci** 1698c2ecf20Sopenharmony_ci** o TLB field affects transactions which are forwarded from GSC+ to Runway. 1708c2ecf20Sopenharmony_ci** "Real" mode is the poweron default. 1718c2ecf20Sopenharmony_ci** 1728c2ecf20Sopenharmony_ci** TLB Mode Value Description 1738c2ecf20Sopenharmony_ci** Real 0 No TLB translation. Address is directly mapped and the 1748c2ecf20Sopenharmony_ci** virtual address is composed of selected physical bits. 1758c2ecf20Sopenharmony_ci** Error 1 Software fills the TLB manually. 1768c2ecf20Sopenharmony_ci** Normal 2 IOA fetches IO TLB misses from IO PDIR (in host memory). 1778c2ecf20Sopenharmony_ci** 1788c2ecf20Sopenharmony_ci** 1798c2ecf20Sopenharmony_ci** IO_IO_LOW_HV +0x60 (HV dependent) 1808c2ecf20Sopenharmony_ci** IO_IO_HIGH_HV +0x64 (HV dependent) 1818c2ecf20Sopenharmony_ci** IO_IO_LOW +0x78 (Architected register) 1828c2ecf20Sopenharmony_ci** IO_IO_HIGH +0x7c (Architected register) 1838c2ecf20Sopenharmony_ci** 1848c2ecf20Sopenharmony_ci** IO_IO_LOW and IO_IO_HIGH set the lower and upper bounds of the 1858c2ecf20Sopenharmony_ci** I/O Adapter address space, respectively. 1868c2ecf20Sopenharmony_ci** 1878c2ecf20Sopenharmony_ci** 0 ... 7 | 8 ... 15 | 16 ... 31 | 1888c2ecf20Sopenharmony_ci** 11111111 | 11111111 | address | 1898c2ecf20Sopenharmony_ci** 1908c2ecf20Sopenharmony_ci** Each LOW/HIGH pair describes a disjoint address space region. 1918c2ecf20Sopenharmony_ci** (2 per GSC+ port). Each incoming Runway transaction address is compared 1928c2ecf20Sopenharmony_ci** with both sets of LOW/HIGH registers. If the address is in the range 1938c2ecf20Sopenharmony_ci** greater than or equal to IO_IO_LOW and less than IO_IO_HIGH the transaction 1948c2ecf20Sopenharmony_ci** for forwarded to the respective GSC+ bus. 1958c2ecf20Sopenharmony_ci** Specify IO_IO_LOW equal to or greater than IO_IO_HIGH to avoid specifying 1968c2ecf20Sopenharmony_ci** an address space region. 1978c2ecf20Sopenharmony_ci** 1988c2ecf20Sopenharmony_ci** In order for a Runway address to reside within GSC+ extended address space: 1998c2ecf20Sopenharmony_ci** Runway Address [0:7] must identically compare to 8'b11111111 2008c2ecf20Sopenharmony_ci** Runway Address [8:11] must be equal to IO_IO_LOW(_HV)[16:19] 2018c2ecf20Sopenharmony_ci** Runway Address [12:23] must be greater than or equal to 2028c2ecf20Sopenharmony_ci** IO_IO_LOW(_HV)[20:31] and less than IO_IO_HIGH(_HV)[20:31]. 2038c2ecf20Sopenharmony_ci** Runway Address [24:39] is not used in the comparison. 2048c2ecf20Sopenharmony_ci** 2058c2ecf20Sopenharmony_ci** When the Runway transaction is forwarded to GSC+, the GSC+ address is 2068c2ecf20Sopenharmony_ci** as follows: 2078c2ecf20Sopenharmony_ci** GSC+ Address[0:3] 4'b1111 2088c2ecf20Sopenharmony_ci** GSC+ Address[4:29] Runway Address[12:37] 2098c2ecf20Sopenharmony_ci** GSC+ Address[30:31] 2'b00 2108c2ecf20Sopenharmony_ci** 2118c2ecf20Sopenharmony_ci** All 4 Low/High registers must be initialized (by PDC) once the lower bus 2128c2ecf20Sopenharmony_ci** is interrogated and address space is defined. The operating system will 2138c2ecf20Sopenharmony_ci** modify the architectural IO_IO_LOW and IO_IO_HIGH registers following 2148c2ecf20Sopenharmony_ci** the PDC initialization. However, the hardware version dependent IO_IO_LOW 2158c2ecf20Sopenharmony_ci** and IO_IO_HIGH registers should not be subsequently altered by the OS. 2168c2ecf20Sopenharmony_ci** 2178c2ecf20Sopenharmony_ci** Writes to both sets of registers will take effect immediately, bypassing 2188c2ecf20Sopenharmony_ci** the queues, which ensures that subsequent Runway transactions are checked 2198c2ecf20Sopenharmony_ci** against the updated bounds values. However reads are queued, introducing 2208c2ecf20Sopenharmony_ci** the possibility of a read being bypassed by a subsequent write to the same 2218c2ecf20Sopenharmony_ci** register. This sequence can be avoided by having software wait for read 2228c2ecf20Sopenharmony_ci** returns before issuing subsequent writes. 2238c2ecf20Sopenharmony_ci*/ 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistruct ioc { 2268c2ecf20Sopenharmony_ci struct ioa_registers __iomem *ioc_regs; /* I/O MMU base address */ 2278c2ecf20Sopenharmony_ci u8 *res_map; /* resource map, bit == pdir entry */ 2288c2ecf20Sopenharmony_ci u64 *pdir_base; /* physical base address */ 2298c2ecf20Sopenharmony_ci u32 pdir_size; /* bytes, function of IOV Space size */ 2308c2ecf20Sopenharmony_ci u32 res_hint; /* next available IOVP - 2318c2ecf20Sopenharmony_ci circular search */ 2328c2ecf20Sopenharmony_ci u32 res_size; /* size of resource map in bytes */ 2338c2ecf20Sopenharmony_ci spinlock_t res_lock; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci#ifdef CCIO_COLLECT_STATS 2368c2ecf20Sopenharmony_ci#define CCIO_SEARCH_SAMPLE 0x100 2378c2ecf20Sopenharmony_ci unsigned long avg_search[CCIO_SEARCH_SAMPLE]; 2388c2ecf20Sopenharmony_ci unsigned long avg_idx; /* current index into avg_search */ 2398c2ecf20Sopenharmony_ci unsigned long used_pages; 2408c2ecf20Sopenharmony_ci unsigned long msingle_calls; 2418c2ecf20Sopenharmony_ci unsigned long msingle_pages; 2428c2ecf20Sopenharmony_ci unsigned long msg_calls; 2438c2ecf20Sopenharmony_ci unsigned long msg_pages; 2448c2ecf20Sopenharmony_ci unsigned long usingle_calls; 2458c2ecf20Sopenharmony_ci unsigned long usingle_pages; 2468c2ecf20Sopenharmony_ci unsigned long usg_calls; 2478c2ecf20Sopenharmony_ci unsigned long usg_pages; 2488c2ecf20Sopenharmony_ci#endif 2498c2ecf20Sopenharmony_ci unsigned short cujo20_bug; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci /* STUFF We don't need in performance path */ 2528c2ecf20Sopenharmony_ci u32 chainid_shift; /* specify bit location of chain_id */ 2538c2ecf20Sopenharmony_ci struct ioc *next; /* Linked list of discovered iocs */ 2548c2ecf20Sopenharmony_ci const char *name; /* device name from firmware */ 2558c2ecf20Sopenharmony_ci unsigned int hw_path; /* the hardware path this ioc is associatd with */ 2568c2ecf20Sopenharmony_ci struct pci_dev *fake_pci_dev; /* the fake pci_dev for non-pci devs */ 2578c2ecf20Sopenharmony_ci struct resource mmio_region[2]; /* The "routed" MMIO regions */ 2588c2ecf20Sopenharmony_ci}; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic struct ioc *ioc_list; 2618c2ecf20Sopenharmony_cistatic int ioc_count; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci/************************************************************** 2648c2ecf20Sopenharmony_ci* 2658c2ecf20Sopenharmony_ci* I/O Pdir Resource Management 2668c2ecf20Sopenharmony_ci* 2678c2ecf20Sopenharmony_ci* Bits set in the resource map are in use. 2688c2ecf20Sopenharmony_ci* Each bit can represent a number of pages. 2698c2ecf20Sopenharmony_ci* LSbs represent lower addresses (IOVA's). 2708c2ecf20Sopenharmony_ci* 2718c2ecf20Sopenharmony_ci* This was was copied from sba_iommu.c. Don't try to unify 2728c2ecf20Sopenharmony_ci* the two resource managers unless a way to have different 2738c2ecf20Sopenharmony_ci* allocation policies is also adjusted. We'd like to avoid 2748c2ecf20Sopenharmony_ci* I/O TLB thrashing by having resource allocation policy 2758c2ecf20Sopenharmony_ci* match the I/O TLB replacement policy. 2768c2ecf20Sopenharmony_ci* 2778c2ecf20Sopenharmony_ci***************************************************************/ 2788c2ecf20Sopenharmony_ci#define IOVP_SIZE PAGE_SIZE 2798c2ecf20Sopenharmony_ci#define IOVP_SHIFT PAGE_SHIFT 2808c2ecf20Sopenharmony_ci#define IOVP_MASK PAGE_MASK 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci/* Convert from IOVP to IOVA and vice versa. */ 2838c2ecf20Sopenharmony_ci#define CCIO_IOVA(iovp,offset) ((iovp) | (offset)) 2848c2ecf20Sopenharmony_ci#define CCIO_IOVP(iova) ((iova) & IOVP_MASK) 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci#define PDIR_INDEX(iovp) ((iovp)>>IOVP_SHIFT) 2878c2ecf20Sopenharmony_ci#define MKIOVP(pdir_idx) ((long)(pdir_idx) << IOVP_SHIFT) 2888c2ecf20Sopenharmony_ci#define MKIOVA(iovp,offset) (dma_addr_t)((long)iovp | (long)offset) 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci/* 2918c2ecf20Sopenharmony_ci** Don't worry about the 150% average search length on a miss. 2928c2ecf20Sopenharmony_ci** If the search wraps around, and passes the res_hint, it will 2938c2ecf20Sopenharmony_ci** cause the kernel to panic anyhow. 2948c2ecf20Sopenharmony_ci*/ 2958c2ecf20Sopenharmony_ci#define CCIO_SEARCH_LOOP(ioc, res_idx, mask, size) \ 2968c2ecf20Sopenharmony_ci for(; res_ptr < res_end; ++res_ptr) { \ 2978c2ecf20Sopenharmony_ci int ret;\ 2988c2ecf20Sopenharmony_ci unsigned int idx;\ 2998c2ecf20Sopenharmony_ci idx = (unsigned int)((unsigned long)res_ptr - (unsigned long)ioc->res_map); \ 3008c2ecf20Sopenharmony_ci ret = iommu_is_span_boundary(idx << 3, pages_needed, 0, boundary_size);\ 3018c2ecf20Sopenharmony_ci if ((0 == (*res_ptr & mask)) && !ret) { \ 3028c2ecf20Sopenharmony_ci *res_ptr |= mask; \ 3038c2ecf20Sopenharmony_ci res_idx = idx;\ 3048c2ecf20Sopenharmony_ci ioc->res_hint = res_idx + (size >> 3); \ 3058c2ecf20Sopenharmony_ci goto resource_found; \ 3068c2ecf20Sopenharmony_ci } \ 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci#define CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, size) \ 3108c2ecf20Sopenharmony_ci u##size *res_ptr = (u##size *)&((ioc)->res_map[ioa->res_hint & ~((size >> 3) - 1)]); \ 3118c2ecf20Sopenharmony_ci u##size *res_end = (u##size *)&(ioc)->res_map[ioa->res_size]; \ 3128c2ecf20Sopenharmony_ci CCIO_SEARCH_LOOP(ioc, res_idx, mask, size); \ 3138c2ecf20Sopenharmony_ci res_ptr = (u##size *)&(ioc)->res_map[0]; \ 3148c2ecf20Sopenharmony_ci CCIO_SEARCH_LOOP(ioa, res_idx, mask, size); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci/* 3178c2ecf20Sopenharmony_ci** Find available bit in this ioa's resource map. 3188c2ecf20Sopenharmony_ci** Use a "circular" search: 3198c2ecf20Sopenharmony_ci** o Most IOVA's are "temporary" - avg search time should be small. 3208c2ecf20Sopenharmony_ci** o keep a history of what happened for debugging 3218c2ecf20Sopenharmony_ci** o KISS. 3228c2ecf20Sopenharmony_ci** 3238c2ecf20Sopenharmony_ci** Perf optimizations: 3248c2ecf20Sopenharmony_ci** o search for log2(size) bits at a time. 3258c2ecf20Sopenharmony_ci** o search for available resource bits using byte/word/whatever. 3268c2ecf20Sopenharmony_ci** o use different search for "large" (eg > 4 pages) or "very large" 3278c2ecf20Sopenharmony_ci** (eg > 16 pages) mappings. 3288c2ecf20Sopenharmony_ci*/ 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci/** 3318c2ecf20Sopenharmony_ci * ccio_alloc_range - Allocate pages in the ioc's resource map. 3328c2ecf20Sopenharmony_ci * @ioc: The I/O Controller. 3338c2ecf20Sopenharmony_ci * @pages_needed: The requested number of pages to be mapped into the 3348c2ecf20Sopenharmony_ci * I/O Pdir... 3358c2ecf20Sopenharmony_ci * 3368c2ecf20Sopenharmony_ci * This function searches the resource map of the ioc to locate a range 3378c2ecf20Sopenharmony_ci * of available pages for the requested size. 3388c2ecf20Sopenharmony_ci */ 3398c2ecf20Sopenharmony_cistatic int 3408c2ecf20Sopenharmony_ciccio_alloc_range(struct ioc *ioc, struct device *dev, size_t size) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci unsigned int pages_needed = size >> IOVP_SHIFT; 3438c2ecf20Sopenharmony_ci unsigned int res_idx; 3448c2ecf20Sopenharmony_ci unsigned long boundary_size; 3458c2ecf20Sopenharmony_ci#ifdef CCIO_COLLECT_STATS 3468c2ecf20Sopenharmony_ci unsigned long cr_start = mfctl(16); 3478c2ecf20Sopenharmony_ci#endif 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci BUG_ON(pages_needed == 0); 3508c2ecf20Sopenharmony_ci BUG_ON((pages_needed * IOVP_SIZE) > DMA_CHUNK_SIZE); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci DBG_RES("%s() size: %d pages_needed %d\n", 3538c2ecf20Sopenharmony_ci __func__, size, pages_needed); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci /* 3568c2ecf20Sopenharmony_ci ** "seek and ye shall find"...praying never hurts either... 3578c2ecf20Sopenharmony_ci ** ggg sacrifices another 710 to the computer gods. 3588c2ecf20Sopenharmony_ci */ 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci boundary_size = dma_get_seg_boundary_nr_pages(dev, IOVP_SHIFT); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci if (pages_needed <= 8) { 3638c2ecf20Sopenharmony_ci /* 3648c2ecf20Sopenharmony_ci * LAN traffic will not thrash the TLB IFF the same NIC 3658c2ecf20Sopenharmony_ci * uses 8 adjacent pages to map separate payload data. 3668c2ecf20Sopenharmony_ci * ie the same byte in the resource bit map. 3678c2ecf20Sopenharmony_ci */ 3688c2ecf20Sopenharmony_ci#if 0 3698c2ecf20Sopenharmony_ci /* FIXME: bit search should shift it's way through 3708c2ecf20Sopenharmony_ci * an unsigned long - not byte at a time. As it is now, 3718c2ecf20Sopenharmony_ci * we effectively allocate this byte to this mapping. 3728c2ecf20Sopenharmony_ci */ 3738c2ecf20Sopenharmony_ci unsigned long mask = ~(~0UL >> pages_needed); 3748c2ecf20Sopenharmony_ci CCIO_FIND_FREE_MAPPING(ioc, res_idx, mask, 8); 3758c2ecf20Sopenharmony_ci#else 3768c2ecf20Sopenharmony_ci CCIO_FIND_FREE_MAPPING(ioc, res_idx, 0xff, 8); 3778c2ecf20Sopenharmony_ci#endif 3788c2ecf20Sopenharmony_ci } else if (pages_needed <= 16) { 3798c2ecf20Sopenharmony_ci CCIO_FIND_FREE_MAPPING(ioc, res_idx, 0xffff, 16); 3808c2ecf20Sopenharmony_ci } else if (pages_needed <= 32) { 3818c2ecf20Sopenharmony_ci CCIO_FIND_FREE_MAPPING(ioc, res_idx, ~(unsigned int)0, 32); 3828c2ecf20Sopenharmony_ci#ifdef __LP64__ 3838c2ecf20Sopenharmony_ci } else if (pages_needed <= 64) { 3848c2ecf20Sopenharmony_ci CCIO_FIND_FREE_MAPPING(ioc, res_idx, ~0UL, 64); 3858c2ecf20Sopenharmony_ci#endif 3868c2ecf20Sopenharmony_ci } else { 3878c2ecf20Sopenharmony_ci panic("%s: %s() Too many pages to map. pages_needed: %u\n", 3888c2ecf20Sopenharmony_ci __FILE__, __func__, pages_needed); 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci panic("%s: %s() I/O MMU is out of mapping resources.\n", __FILE__, 3928c2ecf20Sopenharmony_ci __func__); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ciresource_found: 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci DBG_RES("%s() res_idx %d res_hint: %d\n", 3978c2ecf20Sopenharmony_ci __func__, res_idx, ioc->res_hint); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci#ifdef CCIO_COLLECT_STATS 4008c2ecf20Sopenharmony_ci { 4018c2ecf20Sopenharmony_ci unsigned long cr_end = mfctl(16); 4028c2ecf20Sopenharmony_ci unsigned long tmp = cr_end - cr_start; 4038c2ecf20Sopenharmony_ci /* check for roll over */ 4048c2ecf20Sopenharmony_ci cr_start = (cr_end < cr_start) ? -(tmp) : (tmp); 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci ioc->avg_search[ioc->avg_idx++] = cr_start; 4078c2ecf20Sopenharmony_ci ioc->avg_idx &= CCIO_SEARCH_SAMPLE - 1; 4088c2ecf20Sopenharmony_ci ioc->used_pages += pages_needed; 4098c2ecf20Sopenharmony_ci#endif 4108c2ecf20Sopenharmony_ci /* 4118c2ecf20Sopenharmony_ci ** return the bit address. 4128c2ecf20Sopenharmony_ci */ 4138c2ecf20Sopenharmony_ci return res_idx << 3; 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci#define CCIO_FREE_MAPPINGS(ioc, res_idx, mask, size) \ 4178c2ecf20Sopenharmony_ci u##size *res_ptr = (u##size *)&((ioc)->res_map[res_idx]); \ 4188c2ecf20Sopenharmony_ci BUG_ON((*res_ptr & mask) != mask); \ 4198c2ecf20Sopenharmony_ci *res_ptr &= ~(mask); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci/** 4228c2ecf20Sopenharmony_ci * ccio_free_range - Free pages from the ioc's resource map. 4238c2ecf20Sopenharmony_ci * @ioc: The I/O Controller. 4248c2ecf20Sopenharmony_ci * @iova: The I/O Virtual Address. 4258c2ecf20Sopenharmony_ci * @pages_mapped: The requested number of pages to be freed from the 4268c2ecf20Sopenharmony_ci * I/O Pdir. 4278c2ecf20Sopenharmony_ci * 4288c2ecf20Sopenharmony_ci * This function frees the resouces allocated for the iova. 4298c2ecf20Sopenharmony_ci */ 4308c2ecf20Sopenharmony_cistatic void 4318c2ecf20Sopenharmony_ciccio_free_range(struct ioc *ioc, dma_addr_t iova, unsigned long pages_mapped) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci unsigned long iovp = CCIO_IOVP(iova); 4348c2ecf20Sopenharmony_ci unsigned int res_idx = PDIR_INDEX(iovp) >> 3; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci BUG_ON(pages_mapped == 0); 4378c2ecf20Sopenharmony_ci BUG_ON((pages_mapped * IOVP_SIZE) > DMA_CHUNK_SIZE); 4388c2ecf20Sopenharmony_ci BUG_ON(pages_mapped > BITS_PER_LONG); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci DBG_RES("%s(): res_idx: %d pages_mapped %d\n", 4418c2ecf20Sopenharmony_ci __func__, res_idx, pages_mapped); 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci#ifdef CCIO_COLLECT_STATS 4448c2ecf20Sopenharmony_ci ioc->used_pages -= pages_mapped; 4458c2ecf20Sopenharmony_ci#endif 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci if(pages_mapped <= 8) { 4488c2ecf20Sopenharmony_ci#if 0 4498c2ecf20Sopenharmony_ci /* see matching comments in alloc_range */ 4508c2ecf20Sopenharmony_ci unsigned long mask = ~(~0UL >> pages_mapped); 4518c2ecf20Sopenharmony_ci CCIO_FREE_MAPPINGS(ioc, res_idx, mask, 8); 4528c2ecf20Sopenharmony_ci#else 4538c2ecf20Sopenharmony_ci CCIO_FREE_MAPPINGS(ioc, res_idx, 0xffUL, 8); 4548c2ecf20Sopenharmony_ci#endif 4558c2ecf20Sopenharmony_ci } else if(pages_mapped <= 16) { 4568c2ecf20Sopenharmony_ci CCIO_FREE_MAPPINGS(ioc, res_idx, 0xffffUL, 16); 4578c2ecf20Sopenharmony_ci } else if(pages_mapped <= 32) { 4588c2ecf20Sopenharmony_ci CCIO_FREE_MAPPINGS(ioc, res_idx, ~(unsigned int)0, 32); 4598c2ecf20Sopenharmony_ci#ifdef __LP64__ 4608c2ecf20Sopenharmony_ci } else if(pages_mapped <= 64) { 4618c2ecf20Sopenharmony_ci CCIO_FREE_MAPPINGS(ioc, res_idx, ~0UL, 64); 4628c2ecf20Sopenharmony_ci#endif 4638c2ecf20Sopenharmony_ci } else { 4648c2ecf20Sopenharmony_ci panic("%s:%s() Too many pages to unmap.\n", __FILE__, 4658c2ecf20Sopenharmony_ci __func__); 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci} 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci/**************************************************************** 4708c2ecf20Sopenharmony_ci** 4718c2ecf20Sopenharmony_ci** CCIO dma_ops support routines 4728c2ecf20Sopenharmony_ci** 4738c2ecf20Sopenharmony_ci*****************************************************************/ 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_citypedef unsigned long space_t; 4768c2ecf20Sopenharmony_ci#define KERNEL_SPACE 0 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci/* 4798c2ecf20Sopenharmony_ci** DMA "Page Type" and Hints 4808c2ecf20Sopenharmony_ci** o if SAFE_DMA isn't set, mapping is for FAST_DMA. SAFE_DMA should be 4818c2ecf20Sopenharmony_ci** set for subcacheline DMA transfers since we don't want to damage the 4828c2ecf20Sopenharmony_ci** other part of a cacheline. 4838c2ecf20Sopenharmony_ci** o SAFE_DMA must be set for "memory" allocated via pci_alloc_consistent(). 4848c2ecf20Sopenharmony_ci** This bit tells U2 to do R/M/W for partial cachelines. "Streaming" 4858c2ecf20Sopenharmony_ci** data can avoid this if the mapping covers full cache lines. 4868c2ecf20Sopenharmony_ci** o STOP_MOST is needed for atomicity across cachelines. 4878c2ecf20Sopenharmony_ci** Apparently only "some EISA devices" need this. 4888c2ecf20Sopenharmony_ci** Using CONFIG_ISA is hack. Only the IOA with EISA under it needs 4898c2ecf20Sopenharmony_ci** to use this hint iff the EISA devices needs this feature. 4908c2ecf20Sopenharmony_ci** According to the U2 ERS, STOP_MOST enabled pages hurt performance. 4918c2ecf20Sopenharmony_ci** o PREFETCH should *not* be set for cases like Multiple PCI devices 4928c2ecf20Sopenharmony_ci** behind GSCtoPCI (dino) bus converter. Only one cacheline per GSC 4938c2ecf20Sopenharmony_ci** device can be fetched and multiply DMA streams will thrash the 4948c2ecf20Sopenharmony_ci** prefetch buffer and burn memory bandwidth. See 6.7.3 "Prefetch Rules 4958c2ecf20Sopenharmony_ci** and Invalidation of Prefetch Entries". 4968c2ecf20Sopenharmony_ci** 4978c2ecf20Sopenharmony_ci** FIXME: the default hints need to be per GSC device - not global. 4988c2ecf20Sopenharmony_ci** 4998c2ecf20Sopenharmony_ci** HP-UX dorks: linux device driver programming model is totally different 5008c2ecf20Sopenharmony_ci** than HP-UX's. HP-UX always sets HINT_PREFETCH since it's drivers 5018c2ecf20Sopenharmony_ci** do special things to work on non-coherent platforms...linux has to 5028c2ecf20Sopenharmony_ci** be much more careful with this. 5038c2ecf20Sopenharmony_ci*/ 5048c2ecf20Sopenharmony_ci#define IOPDIR_VALID 0x01UL 5058c2ecf20Sopenharmony_ci#define HINT_SAFE_DMA 0x02UL /* used for pci_alloc_consistent() pages */ 5068c2ecf20Sopenharmony_ci#ifdef CONFIG_EISA 5078c2ecf20Sopenharmony_ci#define HINT_STOP_MOST 0x04UL /* LSL support */ 5088c2ecf20Sopenharmony_ci#else 5098c2ecf20Sopenharmony_ci#define HINT_STOP_MOST 0x00UL /* only needed for "some EISA devices" */ 5108c2ecf20Sopenharmony_ci#endif 5118c2ecf20Sopenharmony_ci#define HINT_UDPATE_ENB 0x08UL /* not used/supported by U2 */ 5128c2ecf20Sopenharmony_ci#define HINT_PREFETCH 0x10UL /* for outbound pages which are not SAFE */ 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci/* 5168c2ecf20Sopenharmony_ci** Use direction (ie PCI_DMA_TODEVICE) to pick hint. 5178c2ecf20Sopenharmony_ci** ccio_alloc_consistent() depends on this to get SAFE_DMA 5188c2ecf20Sopenharmony_ci** when it passes in BIDIRECTIONAL flag. 5198c2ecf20Sopenharmony_ci*/ 5208c2ecf20Sopenharmony_cistatic u32 hint_lookup[] = { 5218c2ecf20Sopenharmony_ci [PCI_DMA_BIDIRECTIONAL] = HINT_STOP_MOST | HINT_SAFE_DMA | IOPDIR_VALID, 5228c2ecf20Sopenharmony_ci [PCI_DMA_TODEVICE] = HINT_STOP_MOST | HINT_PREFETCH | IOPDIR_VALID, 5238c2ecf20Sopenharmony_ci [PCI_DMA_FROMDEVICE] = HINT_STOP_MOST | IOPDIR_VALID, 5248c2ecf20Sopenharmony_ci}; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci/** 5278c2ecf20Sopenharmony_ci * ccio_io_pdir_entry - Initialize an I/O Pdir. 5288c2ecf20Sopenharmony_ci * @pdir_ptr: A pointer into I/O Pdir. 5298c2ecf20Sopenharmony_ci * @sid: The Space Identifier. 5308c2ecf20Sopenharmony_ci * @vba: The virtual address. 5318c2ecf20Sopenharmony_ci * @hints: The DMA Hint. 5328c2ecf20Sopenharmony_ci * 5338c2ecf20Sopenharmony_ci * Given a virtual address (vba, arg2) and space id, (sid, arg1), 5348c2ecf20Sopenharmony_ci * load the I/O PDIR entry pointed to by pdir_ptr (arg0). Each IO Pdir 5358c2ecf20Sopenharmony_ci * entry consists of 8 bytes as shown below (MSB == bit 0): 5368c2ecf20Sopenharmony_ci * 5378c2ecf20Sopenharmony_ci * 5388c2ecf20Sopenharmony_ci * WORD 0: 5398c2ecf20Sopenharmony_ci * +------+----------------+-----------------------------------------------+ 5408c2ecf20Sopenharmony_ci * | Phys | Virtual Index | Phys | 5418c2ecf20Sopenharmony_ci * | 0:3 | 0:11 | 4:19 | 5428c2ecf20Sopenharmony_ci * |4 bits| 12 bits | 16 bits | 5438c2ecf20Sopenharmony_ci * +------+----------------+-----------------------------------------------+ 5448c2ecf20Sopenharmony_ci * WORD 1: 5458c2ecf20Sopenharmony_ci * +-----------------------+-----------------------------------------------+ 5468c2ecf20Sopenharmony_ci * | Phys | Rsvd | Prefetch |Update |Rsvd |Lock |Safe |Valid | 5478c2ecf20Sopenharmony_ci * | 20:39 | | Enable |Enable | |Enable|DMA | | 5488c2ecf20Sopenharmony_ci * | 20 bits | 5 bits | 1 bit |1 bit |2 bits|1 bit |1 bit |1 bit | 5498c2ecf20Sopenharmony_ci * +-----------------------+-----------------------------------------------+ 5508c2ecf20Sopenharmony_ci * 5518c2ecf20Sopenharmony_ci * The virtual index field is filled with the results of the LCI 5528c2ecf20Sopenharmony_ci * (Load Coherence Index) instruction. The 8 bits used for the virtual 5538c2ecf20Sopenharmony_ci * index are bits 12:19 of the value returned by LCI. 5548c2ecf20Sopenharmony_ci */ 5558c2ecf20Sopenharmony_cistatic void CCIO_INLINE 5568c2ecf20Sopenharmony_ciccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba, 5578c2ecf20Sopenharmony_ci unsigned long hints) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci register unsigned long pa; 5608c2ecf20Sopenharmony_ci register unsigned long ci; /* coherent index */ 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci /* We currently only support kernel addresses */ 5638c2ecf20Sopenharmony_ci BUG_ON(sid != KERNEL_SPACE); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci /* 5668c2ecf20Sopenharmony_ci ** WORD 1 - low order word 5678c2ecf20Sopenharmony_ci ** "hints" parm includes the VALID bit! 5688c2ecf20Sopenharmony_ci ** "dep" clobbers the physical address offset bits as well. 5698c2ecf20Sopenharmony_ci */ 5708c2ecf20Sopenharmony_ci pa = lpa(vba); 5718c2ecf20Sopenharmony_ci asm volatile("depw %1,31,12,%0" : "+r" (pa) : "r" (hints)); 5728c2ecf20Sopenharmony_ci ((u32 *)pdir_ptr)[1] = (u32) pa; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci /* 5758c2ecf20Sopenharmony_ci ** WORD 0 - high order word 5768c2ecf20Sopenharmony_ci */ 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci#ifdef __LP64__ 5798c2ecf20Sopenharmony_ci /* 5808c2ecf20Sopenharmony_ci ** get bits 12:15 of physical address 5818c2ecf20Sopenharmony_ci ** shift bits 16:31 of physical address 5828c2ecf20Sopenharmony_ci ** and deposit them 5838c2ecf20Sopenharmony_ci */ 5848c2ecf20Sopenharmony_ci asm volatile ("extrd,u %1,15,4,%0" : "=r" (ci) : "r" (pa)); 5858c2ecf20Sopenharmony_ci asm volatile ("extrd,u %1,31,16,%0" : "+r" (pa) : "r" (pa)); 5868c2ecf20Sopenharmony_ci asm volatile ("depd %1,35,4,%0" : "+r" (pa) : "r" (ci)); 5878c2ecf20Sopenharmony_ci#else 5888c2ecf20Sopenharmony_ci pa = 0; 5898c2ecf20Sopenharmony_ci#endif 5908c2ecf20Sopenharmony_ci /* 5918c2ecf20Sopenharmony_ci ** get CPU coherency index bits 5928c2ecf20Sopenharmony_ci ** Grab virtual index [0:11] 5938c2ecf20Sopenharmony_ci ** Deposit virt_idx bits into I/O PDIR word 5948c2ecf20Sopenharmony_ci */ 5958c2ecf20Sopenharmony_ci asm volatile ("lci %%r0(%1), %0" : "=r" (ci) : "r" (vba)); 5968c2ecf20Sopenharmony_ci asm volatile ("extru %1,19,12,%0" : "+r" (ci) : "r" (ci)); 5978c2ecf20Sopenharmony_ci asm volatile ("depw %1,15,12,%0" : "+r" (pa) : "r" (ci)); 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci ((u32 *)pdir_ptr)[0] = (u32) pa; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci /* FIXME: PCX_W platforms don't need FDC/SYNC. (eg C360) 6038c2ecf20Sopenharmony_ci ** PCX-U/U+ do. (eg C200/C240) 6048c2ecf20Sopenharmony_ci ** PCX-T'? Don't know. (eg C110 or similar K-class) 6058c2ecf20Sopenharmony_ci ** 6068c2ecf20Sopenharmony_ci ** See PDC_MODEL/option 0/SW_CAP word for "Non-coherent IO-PDIR bit". 6078c2ecf20Sopenharmony_ci ** 6088c2ecf20Sopenharmony_ci ** "Since PCX-U employs an offset hash that is incompatible with 6098c2ecf20Sopenharmony_ci ** the real mode coherence index generation of U2, the PDIR entry 6108c2ecf20Sopenharmony_ci ** must be flushed to memory to retain coherence." 6118c2ecf20Sopenharmony_ci */ 6128c2ecf20Sopenharmony_ci asm_io_fdc(pdir_ptr); 6138c2ecf20Sopenharmony_ci asm_io_sync(); 6148c2ecf20Sopenharmony_ci} 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci/** 6178c2ecf20Sopenharmony_ci * ccio_clear_io_tlb - Remove stale entries from the I/O TLB. 6188c2ecf20Sopenharmony_ci * @ioc: The I/O Controller. 6198c2ecf20Sopenharmony_ci * @iovp: The I/O Virtual Page. 6208c2ecf20Sopenharmony_ci * @byte_cnt: The requested number of bytes to be freed from the I/O Pdir. 6218c2ecf20Sopenharmony_ci * 6228c2ecf20Sopenharmony_ci * Purge invalid I/O PDIR entries from the I/O TLB. 6238c2ecf20Sopenharmony_ci * 6248c2ecf20Sopenharmony_ci * FIXME: Can we change the byte_cnt to pages_mapped? 6258c2ecf20Sopenharmony_ci */ 6268c2ecf20Sopenharmony_cistatic CCIO_INLINE void 6278c2ecf20Sopenharmony_ciccio_clear_io_tlb(struct ioc *ioc, dma_addr_t iovp, size_t byte_cnt) 6288c2ecf20Sopenharmony_ci{ 6298c2ecf20Sopenharmony_ci u32 chain_size = 1 << ioc->chainid_shift; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci iovp &= IOVP_MASK; /* clear offset bits, just want pagenum */ 6328c2ecf20Sopenharmony_ci byte_cnt += chain_size; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci while(byte_cnt > chain_size) { 6358c2ecf20Sopenharmony_ci WRITE_U32(CMD_TLB_PURGE | iovp, &ioc->ioc_regs->io_command); 6368c2ecf20Sopenharmony_ci iovp += chain_size; 6378c2ecf20Sopenharmony_ci byte_cnt -= chain_size; 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci/** 6428c2ecf20Sopenharmony_ci * ccio_mark_invalid - Mark the I/O Pdir entries invalid. 6438c2ecf20Sopenharmony_ci * @ioc: The I/O Controller. 6448c2ecf20Sopenharmony_ci * @iova: The I/O Virtual Address. 6458c2ecf20Sopenharmony_ci * @byte_cnt: The requested number of bytes to be freed from the I/O Pdir. 6468c2ecf20Sopenharmony_ci * 6478c2ecf20Sopenharmony_ci * Mark the I/O Pdir entries invalid and blow away the corresponding I/O 6488c2ecf20Sopenharmony_ci * TLB entries. 6498c2ecf20Sopenharmony_ci * 6508c2ecf20Sopenharmony_ci * FIXME: at some threshold it might be "cheaper" to just blow 6518c2ecf20Sopenharmony_ci * away the entire I/O TLB instead of individual entries. 6528c2ecf20Sopenharmony_ci * 6538c2ecf20Sopenharmony_ci * FIXME: Uturn has 256 TLB entries. We don't need to purge every 6548c2ecf20Sopenharmony_ci * PDIR entry - just once for each possible TLB entry. 6558c2ecf20Sopenharmony_ci * (We do need to maker I/O PDIR entries invalid regardless). 6568c2ecf20Sopenharmony_ci * 6578c2ecf20Sopenharmony_ci * FIXME: Can we change byte_cnt to pages_mapped? 6588c2ecf20Sopenharmony_ci */ 6598c2ecf20Sopenharmony_cistatic CCIO_INLINE void 6608c2ecf20Sopenharmony_ciccio_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt) 6618c2ecf20Sopenharmony_ci{ 6628c2ecf20Sopenharmony_ci u32 iovp = (u32)CCIO_IOVP(iova); 6638c2ecf20Sopenharmony_ci size_t saved_byte_cnt; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci /* round up to nearest page size */ 6668c2ecf20Sopenharmony_ci saved_byte_cnt = byte_cnt = ALIGN(byte_cnt, IOVP_SIZE); 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci while(byte_cnt > 0) { 6698c2ecf20Sopenharmony_ci /* invalidate one page at a time */ 6708c2ecf20Sopenharmony_ci unsigned int idx = PDIR_INDEX(iovp); 6718c2ecf20Sopenharmony_ci char *pdir_ptr = (char *) &(ioc->pdir_base[idx]); 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci BUG_ON(idx >= (ioc->pdir_size / sizeof(u64))); 6748c2ecf20Sopenharmony_ci pdir_ptr[7] = 0; /* clear only VALID bit */ 6758c2ecf20Sopenharmony_ci /* 6768c2ecf20Sopenharmony_ci ** FIXME: PCX_W platforms don't need FDC/SYNC. (eg C360) 6778c2ecf20Sopenharmony_ci ** PCX-U/U+ do. (eg C200/C240) 6788c2ecf20Sopenharmony_ci ** See PDC_MODEL/option 0/SW_CAP for "Non-coherent IO-PDIR bit". 6798c2ecf20Sopenharmony_ci */ 6808c2ecf20Sopenharmony_ci asm_io_fdc(pdir_ptr); 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci iovp += IOVP_SIZE; 6838c2ecf20Sopenharmony_ci byte_cnt -= IOVP_SIZE; 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci asm_io_sync(); 6878c2ecf20Sopenharmony_ci ccio_clear_io_tlb(ioc, CCIO_IOVP(iova), saved_byte_cnt); 6888c2ecf20Sopenharmony_ci} 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci/**************************************************************** 6918c2ecf20Sopenharmony_ci** 6928c2ecf20Sopenharmony_ci** CCIO dma_ops 6938c2ecf20Sopenharmony_ci** 6948c2ecf20Sopenharmony_ci*****************************************************************/ 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci/** 6978c2ecf20Sopenharmony_ci * ccio_dma_supported - Verify the IOMMU supports the DMA address range. 6988c2ecf20Sopenharmony_ci * @dev: The PCI device. 6998c2ecf20Sopenharmony_ci * @mask: A bit mask describing the DMA address range of the device. 7008c2ecf20Sopenharmony_ci */ 7018c2ecf20Sopenharmony_cistatic int 7028c2ecf20Sopenharmony_ciccio_dma_supported(struct device *dev, u64 mask) 7038c2ecf20Sopenharmony_ci{ 7048c2ecf20Sopenharmony_ci if(dev == NULL) { 7058c2ecf20Sopenharmony_ci printk(KERN_ERR MODULE_NAME ": EISA/ISA/et al not supported\n"); 7068c2ecf20Sopenharmony_ci BUG(); 7078c2ecf20Sopenharmony_ci return 0; 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci /* only support 32-bit or better devices (ie PCI/GSC) */ 7118c2ecf20Sopenharmony_ci return (int)(mask >= 0xffffffffUL); 7128c2ecf20Sopenharmony_ci} 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci/** 7158c2ecf20Sopenharmony_ci * ccio_map_single - Map an address range into the IOMMU. 7168c2ecf20Sopenharmony_ci * @dev: The PCI device. 7178c2ecf20Sopenharmony_ci * @addr: The start address of the DMA region. 7188c2ecf20Sopenharmony_ci * @size: The length of the DMA region. 7198c2ecf20Sopenharmony_ci * @direction: The direction of the DMA transaction (to/from device). 7208c2ecf20Sopenharmony_ci * 7218c2ecf20Sopenharmony_ci * This function implements the pci_map_single function. 7228c2ecf20Sopenharmony_ci */ 7238c2ecf20Sopenharmony_cistatic dma_addr_t 7248c2ecf20Sopenharmony_ciccio_map_single(struct device *dev, void *addr, size_t size, 7258c2ecf20Sopenharmony_ci enum dma_data_direction direction) 7268c2ecf20Sopenharmony_ci{ 7278c2ecf20Sopenharmony_ci int idx; 7288c2ecf20Sopenharmony_ci struct ioc *ioc; 7298c2ecf20Sopenharmony_ci unsigned long flags; 7308c2ecf20Sopenharmony_ci dma_addr_t iovp; 7318c2ecf20Sopenharmony_ci dma_addr_t offset; 7328c2ecf20Sopenharmony_ci u64 *pdir_start; 7338c2ecf20Sopenharmony_ci unsigned long hint = hint_lookup[(int)direction]; 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci BUG_ON(!dev); 7368c2ecf20Sopenharmony_ci ioc = GET_IOC(dev); 7378c2ecf20Sopenharmony_ci if (!ioc) 7388c2ecf20Sopenharmony_ci return DMA_MAPPING_ERROR; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci BUG_ON(size <= 0); 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci /* save offset bits */ 7438c2ecf20Sopenharmony_ci offset = ((unsigned long) addr) & ~IOVP_MASK; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci /* round up to nearest IOVP_SIZE */ 7468c2ecf20Sopenharmony_ci size = ALIGN(size + offset, IOVP_SIZE); 7478c2ecf20Sopenharmony_ci spin_lock_irqsave(&ioc->res_lock, flags); 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci#ifdef CCIO_COLLECT_STATS 7508c2ecf20Sopenharmony_ci ioc->msingle_calls++; 7518c2ecf20Sopenharmony_ci ioc->msingle_pages += size >> IOVP_SHIFT; 7528c2ecf20Sopenharmony_ci#endif 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci idx = ccio_alloc_range(ioc, dev, size); 7558c2ecf20Sopenharmony_ci iovp = (dma_addr_t)MKIOVP(idx); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci pdir_start = &(ioc->pdir_base[idx]); 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci DBG_RUN("%s() 0x%p -> 0x%lx size: %0x%x\n", 7608c2ecf20Sopenharmony_ci __func__, addr, (long)iovp | offset, size); 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci /* If not cacheline aligned, force SAFE_DMA on the whole mess */ 7638c2ecf20Sopenharmony_ci if((size % L1_CACHE_BYTES) || ((unsigned long)addr % L1_CACHE_BYTES)) 7648c2ecf20Sopenharmony_ci hint |= HINT_SAFE_DMA; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci while(size > 0) { 7678c2ecf20Sopenharmony_ci ccio_io_pdir_entry(pdir_start, KERNEL_SPACE, (unsigned long)addr, hint); 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci DBG_RUN(" pdir %p %08x%08x\n", 7708c2ecf20Sopenharmony_ci pdir_start, 7718c2ecf20Sopenharmony_ci (u32) (((u32 *) pdir_start)[0]), 7728c2ecf20Sopenharmony_ci (u32) (((u32 *) pdir_start)[1])); 7738c2ecf20Sopenharmony_ci ++pdir_start; 7748c2ecf20Sopenharmony_ci addr += IOVP_SIZE; 7758c2ecf20Sopenharmony_ci size -= IOVP_SIZE; 7768c2ecf20Sopenharmony_ci } 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ioc->res_lock, flags); 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci /* form complete address */ 7818c2ecf20Sopenharmony_ci return CCIO_IOVA(iovp, offset); 7828c2ecf20Sopenharmony_ci} 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_cistatic dma_addr_t 7868c2ecf20Sopenharmony_ciccio_map_page(struct device *dev, struct page *page, unsigned long offset, 7878c2ecf20Sopenharmony_ci size_t size, enum dma_data_direction direction, 7888c2ecf20Sopenharmony_ci unsigned long attrs) 7898c2ecf20Sopenharmony_ci{ 7908c2ecf20Sopenharmony_ci return ccio_map_single(dev, page_address(page) + offset, size, 7918c2ecf20Sopenharmony_ci direction); 7928c2ecf20Sopenharmony_ci} 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci/** 7968c2ecf20Sopenharmony_ci * ccio_unmap_page - Unmap an address range from the IOMMU. 7978c2ecf20Sopenharmony_ci * @dev: The PCI device. 7988c2ecf20Sopenharmony_ci * @addr: The start address of the DMA region. 7998c2ecf20Sopenharmony_ci * @size: The length of the DMA region. 8008c2ecf20Sopenharmony_ci * @direction: The direction of the DMA transaction (to/from device). 8018c2ecf20Sopenharmony_ci */ 8028c2ecf20Sopenharmony_cistatic void 8038c2ecf20Sopenharmony_ciccio_unmap_page(struct device *dev, dma_addr_t iova, size_t size, 8048c2ecf20Sopenharmony_ci enum dma_data_direction direction, unsigned long attrs) 8058c2ecf20Sopenharmony_ci{ 8068c2ecf20Sopenharmony_ci struct ioc *ioc; 8078c2ecf20Sopenharmony_ci unsigned long flags; 8088c2ecf20Sopenharmony_ci dma_addr_t offset = iova & ~IOVP_MASK; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci BUG_ON(!dev); 8118c2ecf20Sopenharmony_ci ioc = GET_IOC(dev); 8128c2ecf20Sopenharmony_ci if (!ioc) { 8138c2ecf20Sopenharmony_ci WARN_ON(!ioc); 8148c2ecf20Sopenharmony_ci return; 8158c2ecf20Sopenharmony_ci } 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci DBG_RUN("%s() iovp 0x%lx/%x\n", 8188c2ecf20Sopenharmony_ci __func__, (long)iova, size); 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci iova ^= offset; /* clear offset bits */ 8218c2ecf20Sopenharmony_ci size += offset; 8228c2ecf20Sopenharmony_ci size = ALIGN(size, IOVP_SIZE); 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci spin_lock_irqsave(&ioc->res_lock, flags); 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci#ifdef CCIO_COLLECT_STATS 8278c2ecf20Sopenharmony_ci ioc->usingle_calls++; 8288c2ecf20Sopenharmony_ci ioc->usingle_pages += size >> IOVP_SHIFT; 8298c2ecf20Sopenharmony_ci#endif 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci ccio_mark_invalid(ioc, iova, size); 8328c2ecf20Sopenharmony_ci ccio_free_range(ioc, iova, (size >> IOVP_SHIFT)); 8338c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ioc->res_lock, flags); 8348c2ecf20Sopenharmony_ci} 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci/** 8378c2ecf20Sopenharmony_ci * ccio_alloc - Allocate a consistent DMA mapping. 8388c2ecf20Sopenharmony_ci * @dev: The PCI device. 8398c2ecf20Sopenharmony_ci * @size: The length of the DMA region. 8408c2ecf20Sopenharmony_ci * @dma_handle: The DMA address handed back to the device (not the cpu). 8418c2ecf20Sopenharmony_ci * 8428c2ecf20Sopenharmony_ci * This function implements the pci_alloc_consistent function. 8438c2ecf20Sopenharmony_ci */ 8448c2ecf20Sopenharmony_cistatic void * 8458c2ecf20Sopenharmony_ciccio_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag, 8468c2ecf20Sopenharmony_ci unsigned long attrs) 8478c2ecf20Sopenharmony_ci{ 8488c2ecf20Sopenharmony_ci void *ret; 8498c2ecf20Sopenharmony_ci#if 0 8508c2ecf20Sopenharmony_ci/* GRANT Need to establish hierarchy for non-PCI devs as well 8518c2ecf20Sopenharmony_ci** and then provide matching gsc_map_xxx() functions for them as well. 8528c2ecf20Sopenharmony_ci*/ 8538c2ecf20Sopenharmony_ci if(!hwdev) { 8548c2ecf20Sopenharmony_ci /* only support PCI */ 8558c2ecf20Sopenharmony_ci *dma_handle = 0; 8568c2ecf20Sopenharmony_ci return 0; 8578c2ecf20Sopenharmony_ci } 8588c2ecf20Sopenharmony_ci#endif 8598c2ecf20Sopenharmony_ci ret = (void *) __get_free_pages(flag, get_order(size)); 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci if (ret) { 8628c2ecf20Sopenharmony_ci memset(ret, 0, size); 8638c2ecf20Sopenharmony_ci *dma_handle = ccio_map_single(dev, ret, size, PCI_DMA_BIDIRECTIONAL); 8648c2ecf20Sopenharmony_ci } 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci return ret; 8678c2ecf20Sopenharmony_ci} 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci/** 8708c2ecf20Sopenharmony_ci * ccio_free - Free a consistent DMA mapping. 8718c2ecf20Sopenharmony_ci * @dev: The PCI device. 8728c2ecf20Sopenharmony_ci * @size: The length of the DMA region. 8738c2ecf20Sopenharmony_ci * @cpu_addr: The cpu address returned from the ccio_alloc_consistent. 8748c2ecf20Sopenharmony_ci * @dma_handle: The device address returned from the ccio_alloc_consistent. 8758c2ecf20Sopenharmony_ci * 8768c2ecf20Sopenharmony_ci * This function implements the pci_free_consistent function. 8778c2ecf20Sopenharmony_ci */ 8788c2ecf20Sopenharmony_cistatic void 8798c2ecf20Sopenharmony_ciccio_free(struct device *dev, size_t size, void *cpu_addr, 8808c2ecf20Sopenharmony_ci dma_addr_t dma_handle, unsigned long attrs) 8818c2ecf20Sopenharmony_ci{ 8828c2ecf20Sopenharmony_ci ccio_unmap_page(dev, dma_handle, size, 0, 0); 8838c2ecf20Sopenharmony_ci free_pages((unsigned long)cpu_addr, get_order(size)); 8848c2ecf20Sopenharmony_ci} 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci/* 8878c2ecf20Sopenharmony_ci** Since 0 is a valid pdir_base index value, can't use that 8888c2ecf20Sopenharmony_ci** to determine if a value is valid or not. Use a flag to indicate 8898c2ecf20Sopenharmony_ci** the SG list entry contains a valid pdir index. 8908c2ecf20Sopenharmony_ci*/ 8918c2ecf20Sopenharmony_ci#define PIDE_FLAG 0x80000000UL 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci#ifdef CCIO_COLLECT_STATS 8948c2ecf20Sopenharmony_ci#define IOMMU_MAP_STATS 8958c2ecf20Sopenharmony_ci#endif 8968c2ecf20Sopenharmony_ci#include "iommu-helpers.h" 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci/** 8998c2ecf20Sopenharmony_ci * ccio_map_sg - Map the scatter/gather list into the IOMMU. 9008c2ecf20Sopenharmony_ci * @dev: The PCI device. 9018c2ecf20Sopenharmony_ci * @sglist: The scatter/gather list to be mapped in the IOMMU. 9028c2ecf20Sopenharmony_ci * @nents: The number of entries in the scatter/gather list. 9038c2ecf20Sopenharmony_ci * @direction: The direction of the DMA transaction (to/from device). 9048c2ecf20Sopenharmony_ci * 9058c2ecf20Sopenharmony_ci * This function implements the pci_map_sg function. 9068c2ecf20Sopenharmony_ci */ 9078c2ecf20Sopenharmony_cistatic int 9088c2ecf20Sopenharmony_ciccio_map_sg(struct device *dev, struct scatterlist *sglist, int nents, 9098c2ecf20Sopenharmony_ci enum dma_data_direction direction, unsigned long attrs) 9108c2ecf20Sopenharmony_ci{ 9118c2ecf20Sopenharmony_ci struct ioc *ioc; 9128c2ecf20Sopenharmony_ci int coalesced, filled = 0; 9138c2ecf20Sopenharmony_ci unsigned long flags; 9148c2ecf20Sopenharmony_ci unsigned long hint = hint_lookup[(int)direction]; 9158c2ecf20Sopenharmony_ci unsigned long prev_len = 0, current_len = 0; 9168c2ecf20Sopenharmony_ci int i; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci BUG_ON(!dev); 9198c2ecf20Sopenharmony_ci ioc = GET_IOC(dev); 9208c2ecf20Sopenharmony_ci if (!ioc) 9218c2ecf20Sopenharmony_ci return 0; 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci DBG_RUN_SG("%s() START %d entries\n", __func__, nents); 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci /* Fast path single entry scatterlists. */ 9268c2ecf20Sopenharmony_ci if (nents == 1) { 9278c2ecf20Sopenharmony_ci sg_dma_address(sglist) = ccio_map_single(dev, 9288c2ecf20Sopenharmony_ci sg_virt(sglist), sglist->length, 9298c2ecf20Sopenharmony_ci direction); 9308c2ecf20Sopenharmony_ci sg_dma_len(sglist) = sglist->length; 9318c2ecf20Sopenharmony_ci return 1; 9328c2ecf20Sopenharmony_ci } 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci for(i = 0; i < nents; i++) 9358c2ecf20Sopenharmony_ci prev_len += sglist[i].length; 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci spin_lock_irqsave(&ioc->res_lock, flags); 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci#ifdef CCIO_COLLECT_STATS 9408c2ecf20Sopenharmony_ci ioc->msg_calls++; 9418c2ecf20Sopenharmony_ci#endif 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci /* 9448c2ecf20Sopenharmony_ci ** First coalesce the chunks and allocate I/O pdir space 9458c2ecf20Sopenharmony_ci ** 9468c2ecf20Sopenharmony_ci ** If this is one DMA stream, we can properly map using the 9478c2ecf20Sopenharmony_ci ** correct virtual address associated with each DMA page. 9488c2ecf20Sopenharmony_ci ** w/o this association, we wouldn't have coherent DMA! 9498c2ecf20Sopenharmony_ci ** Access to the virtual address is what forces a two pass algorithm. 9508c2ecf20Sopenharmony_ci */ 9518c2ecf20Sopenharmony_ci coalesced = iommu_coalesce_chunks(ioc, dev, sglist, nents, ccio_alloc_range); 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci /* 9548c2ecf20Sopenharmony_ci ** Program the I/O Pdir 9558c2ecf20Sopenharmony_ci ** 9568c2ecf20Sopenharmony_ci ** map the virtual addresses to the I/O Pdir 9578c2ecf20Sopenharmony_ci ** o dma_address will contain the pdir index 9588c2ecf20Sopenharmony_ci ** o dma_len will contain the number of bytes to map 9598c2ecf20Sopenharmony_ci ** o page/offset contain the virtual address. 9608c2ecf20Sopenharmony_ci */ 9618c2ecf20Sopenharmony_ci filled = iommu_fill_pdir(ioc, sglist, nents, hint, ccio_io_pdir_entry); 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ioc->res_lock, flags); 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci BUG_ON(coalesced != filled); 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci DBG_RUN_SG("%s() DONE %d mappings\n", __func__, filled); 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci for (i = 0; i < filled; i++) 9708c2ecf20Sopenharmony_ci current_len += sg_dma_len(sglist + i); 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci BUG_ON(current_len != prev_len); 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci return filled; 9758c2ecf20Sopenharmony_ci} 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci/** 9788c2ecf20Sopenharmony_ci * ccio_unmap_sg - Unmap the scatter/gather list from the IOMMU. 9798c2ecf20Sopenharmony_ci * @dev: The PCI device. 9808c2ecf20Sopenharmony_ci * @sglist: The scatter/gather list to be unmapped from the IOMMU. 9818c2ecf20Sopenharmony_ci * @nents: The number of entries in the scatter/gather list. 9828c2ecf20Sopenharmony_ci * @direction: The direction of the DMA transaction (to/from device). 9838c2ecf20Sopenharmony_ci * 9848c2ecf20Sopenharmony_ci * This function implements the pci_unmap_sg function. 9858c2ecf20Sopenharmony_ci */ 9868c2ecf20Sopenharmony_cistatic void 9878c2ecf20Sopenharmony_ciccio_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents, 9888c2ecf20Sopenharmony_ci enum dma_data_direction direction, unsigned long attrs) 9898c2ecf20Sopenharmony_ci{ 9908c2ecf20Sopenharmony_ci struct ioc *ioc; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci BUG_ON(!dev); 9938c2ecf20Sopenharmony_ci ioc = GET_IOC(dev); 9948c2ecf20Sopenharmony_ci if (!ioc) { 9958c2ecf20Sopenharmony_ci WARN_ON(!ioc); 9968c2ecf20Sopenharmony_ci return; 9978c2ecf20Sopenharmony_ci } 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci DBG_RUN_SG("%s() START %d entries, %p,%x\n", 10008c2ecf20Sopenharmony_ci __func__, nents, sg_virt(sglist), sglist->length); 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci#ifdef CCIO_COLLECT_STATS 10038c2ecf20Sopenharmony_ci ioc->usg_calls++; 10048c2ecf20Sopenharmony_ci#endif 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci while (nents && sg_dma_len(sglist)) { 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci#ifdef CCIO_COLLECT_STATS 10098c2ecf20Sopenharmony_ci ioc->usg_pages += sg_dma_len(sglist) >> PAGE_SHIFT; 10108c2ecf20Sopenharmony_ci#endif 10118c2ecf20Sopenharmony_ci ccio_unmap_page(dev, sg_dma_address(sglist), 10128c2ecf20Sopenharmony_ci sg_dma_len(sglist), direction, 0); 10138c2ecf20Sopenharmony_ci ++sglist; 10148c2ecf20Sopenharmony_ci nents--; 10158c2ecf20Sopenharmony_ci } 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci DBG_RUN_SG("%s() DONE (nents %d)\n", __func__, nents); 10188c2ecf20Sopenharmony_ci} 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_cistatic const struct dma_map_ops ccio_ops = { 10218c2ecf20Sopenharmony_ci .dma_supported = ccio_dma_supported, 10228c2ecf20Sopenharmony_ci .alloc = ccio_alloc, 10238c2ecf20Sopenharmony_ci .free = ccio_free, 10248c2ecf20Sopenharmony_ci .map_page = ccio_map_page, 10258c2ecf20Sopenharmony_ci .unmap_page = ccio_unmap_page, 10268c2ecf20Sopenharmony_ci .map_sg = ccio_map_sg, 10278c2ecf20Sopenharmony_ci .unmap_sg = ccio_unmap_sg, 10288c2ecf20Sopenharmony_ci .get_sgtable = dma_common_get_sgtable, 10298c2ecf20Sopenharmony_ci .alloc_pages = dma_common_alloc_pages, 10308c2ecf20Sopenharmony_ci .free_pages = dma_common_free_pages, 10318c2ecf20Sopenharmony_ci}; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS 10348c2ecf20Sopenharmony_cistatic int ccio_proc_info(struct seq_file *m, void *p) 10358c2ecf20Sopenharmony_ci{ 10368c2ecf20Sopenharmony_ci struct ioc *ioc = ioc_list; 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci while (ioc != NULL) { 10398c2ecf20Sopenharmony_ci unsigned int total_pages = ioc->res_size << 3; 10408c2ecf20Sopenharmony_ci#ifdef CCIO_COLLECT_STATS 10418c2ecf20Sopenharmony_ci unsigned long avg = 0, min, max; 10428c2ecf20Sopenharmony_ci int j; 10438c2ecf20Sopenharmony_ci#endif 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci seq_printf(m, "%s\n", ioc->name); 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci seq_printf(m, "Cujo 2.0 bug : %s\n", 10488c2ecf20Sopenharmony_ci (ioc->cujo20_bug ? "yes" : "no")); 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci seq_printf(m, "IO PDIR size : %d bytes (%d entries)\n", 10518c2ecf20Sopenharmony_ci total_pages * 8, total_pages); 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci#ifdef CCIO_COLLECT_STATS 10548c2ecf20Sopenharmony_ci seq_printf(m, "IO PDIR entries : %ld free %ld used (%d%%)\n", 10558c2ecf20Sopenharmony_ci total_pages - ioc->used_pages, ioc->used_pages, 10568c2ecf20Sopenharmony_ci (int)(ioc->used_pages * 100 / total_pages)); 10578c2ecf20Sopenharmony_ci#endif 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci seq_printf(m, "Resource bitmap : %d bytes (%d pages)\n", 10608c2ecf20Sopenharmony_ci ioc->res_size, total_pages); 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci#ifdef CCIO_COLLECT_STATS 10638c2ecf20Sopenharmony_ci min = max = ioc->avg_search[0]; 10648c2ecf20Sopenharmony_ci for(j = 0; j < CCIO_SEARCH_SAMPLE; ++j) { 10658c2ecf20Sopenharmony_ci avg += ioc->avg_search[j]; 10668c2ecf20Sopenharmony_ci if(ioc->avg_search[j] > max) 10678c2ecf20Sopenharmony_ci max = ioc->avg_search[j]; 10688c2ecf20Sopenharmony_ci if(ioc->avg_search[j] < min) 10698c2ecf20Sopenharmony_ci min = ioc->avg_search[j]; 10708c2ecf20Sopenharmony_ci } 10718c2ecf20Sopenharmony_ci avg /= CCIO_SEARCH_SAMPLE; 10728c2ecf20Sopenharmony_ci seq_printf(m, " Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n", 10738c2ecf20Sopenharmony_ci min, avg, max); 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci seq_printf(m, "pci_map_single(): %8ld calls %8ld pages (avg %d/1000)\n", 10768c2ecf20Sopenharmony_ci ioc->msingle_calls, ioc->msingle_pages, 10778c2ecf20Sopenharmony_ci (int)((ioc->msingle_pages * 1000)/ioc->msingle_calls)); 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci /* KLUGE - unmap_sg calls unmap_page for each mapped page */ 10808c2ecf20Sopenharmony_ci min = ioc->usingle_calls - ioc->usg_calls; 10818c2ecf20Sopenharmony_ci max = ioc->usingle_pages - ioc->usg_pages; 10828c2ecf20Sopenharmony_ci seq_printf(m, "pci_unmap_single: %8ld calls %8ld pages (avg %d/1000)\n", 10838c2ecf20Sopenharmony_ci min, max, (int)((max * 1000)/min)); 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci seq_printf(m, "pci_map_sg() : %8ld calls %8ld pages (avg %d/1000)\n", 10868c2ecf20Sopenharmony_ci ioc->msg_calls, ioc->msg_pages, 10878c2ecf20Sopenharmony_ci (int)((ioc->msg_pages * 1000)/ioc->msg_calls)); 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci seq_printf(m, "pci_unmap_sg() : %8ld calls %8ld pages (avg %d/1000)\n\n\n", 10908c2ecf20Sopenharmony_ci ioc->usg_calls, ioc->usg_pages, 10918c2ecf20Sopenharmony_ci (int)((ioc->usg_pages * 1000)/ioc->usg_calls)); 10928c2ecf20Sopenharmony_ci#endif /* CCIO_COLLECT_STATS */ 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci ioc = ioc->next; 10958c2ecf20Sopenharmony_ci } 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci return 0; 10988c2ecf20Sopenharmony_ci} 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_cistatic int ccio_proc_bitmap_info(struct seq_file *m, void *p) 11018c2ecf20Sopenharmony_ci{ 11028c2ecf20Sopenharmony_ci struct ioc *ioc = ioc_list; 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci while (ioc != NULL) { 11058c2ecf20Sopenharmony_ci seq_hex_dump(m, " ", DUMP_PREFIX_NONE, 32, 4, ioc->res_map, 11068c2ecf20Sopenharmony_ci ioc->res_size, false); 11078c2ecf20Sopenharmony_ci seq_putc(m, '\n'); 11088c2ecf20Sopenharmony_ci ioc = ioc->next; 11098c2ecf20Sopenharmony_ci break; /* XXX - remove me */ 11108c2ecf20Sopenharmony_ci } 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci return 0; 11138c2ecf20Sopenharmony_ci} 11148c2ecf20Sopenharmony_ci#endif /* CONFIG_PROC_FS */ 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci/** 11178c2ecf20Sopenharmony_ci * ccio_find_ioc - Find the ioc in the ioc_list 11188c2ecf20Sopenharmony_ci * @hw_path: The hardware path of the ioc. 11198c2ecf20Sopenharmony_ci * 11208c2ecf20Sopenharmony_ci * This function searches the ioc_list for an ioc that matches 11218c2ecf20Sopenharmony_ci * the provide hardware path. 11228c2ecf20Sopenharmony_ci */ 11238c2ecf20Sopenharmony_cistatic struct ioc * ccio_find_ioc(int hw_path) 11248c2ecf20Sopenharmony_ci{ 11258c2ecf20Sopenharmony_ci int i; 11268c2ecf20Sopenharmony_ci struct ioc *ioc; 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci ioc = ioc_list; 11298c2ecf20Sopenharmony_ci for (i = 0; i < ioc_count; i++) { 11308c2ecf20Sopenharmony_ci if (ioc->hw_path == hw_path) 11318c2ecf20Sopenharmony_ci return ioc; 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci ioc = ioc->next; 11348c2ecf20Sopenharmony_ci } 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci return NULL; 11378c2ecf20Sopenharmony_ci} 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci/** 11408c2ecf20Sopenharmony_ci * ccio_get_iommu - Find the iommu which controls this device 11418c2ecf20Sopenharmony_ci * @dev: The parisc device. 11428c2ecf20Sopenharmony_ci * 11438c2ecf20Sopenharmony_ci * This function searches through the registered IOMMU's and returns 11448c2ecf20Sopenharmony_ci * the appropriate IOMMU for the device based on its hardware path. 11458c2ecf20Sopenharmony_ci */ 11468c2ecf20Sopenharmony_civoid * ccio_get_iommu(const struct parisc_device *dev) 11478c2ecf20Sopenharmony_ci{ 11488c2ecf20Sopenharmony_ci dev = find_pa_parent_type(dev, HPHW_IOA); 11498c2ecf20Sopenharmony_ci if (!dev) 11508c2ecf20Sopenharmony_ci return NULL; 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci return ccio_find_ioc(dev->hw_path); 11538c2ecf20Sopenharmony_ci} 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci#define CUJO_20_STEP 0x10000000 /* inc upper nibble */ 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci/* Cujo 2.0 has a bug which will silently corrupt data being transferred 11588c2ecf20Sopenharmony_ci * to/from certain pages. To avoid this happening, we mark these pages 11598c2ecf20Sopenharmony_ci * as `used', and ensure that nothing will try to allocate from them. 11608c2ecf20Sopenharmony_ci */ 11618c2ecf20Sopenharmony_civoid __init ccio_cujo20_fixup(struct parisc_device *cujo, u32 iovp) 11628c2ecf20Sopenharmony_ci{ 11638c2ecf20Sopenharmony_ci unsigned int idx; 11648c2ecf20Sopenharmony_ci struct parisc_device *dev = parisc_parent(cujo); 11658c2ecf20Sopenharmony_ci struct ioc *ioc = ccio_get_iommu(dev); 11668c2ecf20Sopenharmony_ci u8 *res_ptr; 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci ioc->cujo20_bug = 1; 11698c2ecf20Sopenharmony_ci res_ptr = ioc->res_map; 11708c2ecf20Sopenharmony_ci idx = PDIR_INDEX(iovp) >> 3; 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci while (idx < ioc->res_size) { 11738c2ecf20Sopenharmony_ci res_ptr[idx] |= 0xff; 11748c2ecf20Sopenharmony_ci idx += PDIR_INDEX(CUJO_20_STEP) >> 3; 11758c2ecf20Sopenharmony_ci } 11768c2ecf20Sopenharmony_ci} 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci#if 0 11798c2ecf20Sopenharmony_ci/* GRANT - is this needed for U2 or not? */ 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci/* 11828c2ecf20Sopenharmony_ci** Get the size of the I/O TLB for this I/O MMU. 11838c2ecf20Sopenharmony_ci** 11848c2ecf20Sopenharmony_ci** If spa_shift is non-zero (ie probably U2), 11858c2ecf20Sopenharmony_ci** then calculate the I/O TLB size using spa_shift. 11868c2ecf20Sopenharmony_ci** 11878c2ecf20Sopenharmony_ci** Otherwise we are supposed to get the IODC entry point ENTRY TLB 11888c2ecf20Sopenharmony_ci** and execute it. However, both U2 and Uturn firmware supplies spa_shift. 11898c2ecf20Sopenharmony_ci** I think only Java (K/D/R-class too?) systems don't do this. 11908c2ecf20Sopenharmony_ci*/ 11918c2ecf20Sopenharmony_cistatic int 11928c2ecf20Sopenharmony_ciccio_get_iotlb_size(struct parisc_device *dev) 11938c2ecf20Sopenharmony_ci{ 11948c2ecf20Sopenharmony_ci if (dev->spa_shift == 0) { 11958c2ecf20Sopenharmony_ci panic("%s() : Can't determine I/O TLB size.\n", __func__); 11968c2ecf20Sopenharmony_ci } 11978c2ecf20Sopenharmony_ci return (1 << dev->spa_shift); 11988c2ecf20Sopenharmony_ci} 11998c2ecf20Sopenharmony_ci#else 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci/* Uturn supports 256 TLB entries */ 12028c2ecf20Sopenharmony_ci#define CCIO_CHAINID_SHIFT 8 12038c2ecf20Sopenharmony_ci#define CCIO_CHAINID_MASK 0xff 12048c2ecf20Sopenharmony_ci#endif /* 0 */ 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci/* We *can't* support JAVA (T600). Venture there at your own risk. */ 12078c2ecf20Sopenharmony_cistatic const struct parisc_device_id ccio_tbl[] __initconst = { 12088c2ecf20Sopenharmony_ci { HPHW_IOA, HVERSION_REV_ANY_ID, U2_IOA_RUNWAY, 0xb }, /* U2 */ 12098c2ecf20Sopenharmony_ci { HPHW_IOA, HVERSION_REV_ANY_ID, UTURN_IOA_RUNWAY, 0xb }, /* UTurn */ 12108c2ecf20Sopenharmony_ci { 0, } 12118c2ecf20Sopenharmony_ci}; 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_cistatic int ccio_probe(struct parisc_device *dev); 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_cistatic struct parisc_driver ccio_driver __refdata = { 12168c2ecf20Sopenharmony_ci .name = "ccio", 12178c2ecf20Sopenharmony_ci .id_table = ccio_tbl, 12188c2ecf20Sopenharmony_ci .probe = ccio_probe, 12198c2ecf20Sopenharmony_ci}; 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci/** 12228c2ecf20Sopenharmony_ci * ccio_ioc_init - Initialize the I/O Controller 12238c2ecf20Sopenharmony_ci * @ioc: The I/O Controller. 12248c2ecf20Sopenharmony_ci * 12258c2ecf20Sopenharmony_ci * Initialize the I/O Controller which includes setting up the 12268c2ecf20Sopenharmony_ci * I/O Page Directory, the resource map, and initalizing the 12278c2ecf20Sopenharmony_ci * U2/Uturn chip into virtual mode. 12288c2ecf20Sopenharmony_ci */ 12298c2ecf20Sopenharmony_cistatic void __init 12308c2ecf20Sopenharmony_ciccio_ioc_init(struct ioc *ioc) 12318c2ecf20Sopenharmony_ci{ 12328c2ecf20Sopenharmony_ci int i; 12338c2ecf20Sopenharmony_ci unsigned int iov_order; 12348c2ecf20Sopenharmony_ci u32 iova_space_size; 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci /* 12378c2ecf20Sopenharmony_ci ** Determine IOVA Space size from memory size. 12388c2ecf20Sopenharmony_ci ** 12398c2ecf20Sopenharmony_ci ** Ideally, PCI drivers would register the maximum number 12408c2ecf20Sopenharmony_ci ** of DMA they can have outstanding for each device they 12418c2ecf20Sopenharmony_ci ** own. Next best thing would be to guess how much DMA 12428c2ecf20Sopenharmony_ci ** can be outstanding based on PCI Class/sub-class. Both 12438c2ecf20Sopenharmony_ci ** methods still require some "extra" to support PCI 12448c2ecf20Sopenharmony_ci ** Hot-Plug/Removal of PCI cards. (aka PCI OLARD). 12458c2ecf20Sopenharmony_ci */ 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci iova_space_size = (u32) (totalram_pages() / count_parisc_driver(&ccio_driver)); 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci /* limit IOVA space size to 1MB-1GB */ 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci if (iova_space_size < (1 << (20 - PAGE_SHIFT))) { 12528c2ecf20Sopenharmony_ci iova_space_size = 1 << (20 - PAGE_SHIFT); 12538c2ecf20Sopenharmony_ci#ifdef __LP64__ 12548c2ecf20Sopenharmony_ci } else if (iova_space_size > (1 << (30 - PAGE_SHIFT))) { 12558c2ecf20Sopenharmony_ci iova_space_size = 1 << (30 - PAGE_SHIFT); 12568c2ecf20Sopenharmony_ci#endif 12578c2ecf20Sopenharmony_ci } 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci /* 12608c2ecf20Sopenharmony_ci ** iova space must be log2() in size. 12618c2ecf20Sopenharmony_ci ** thus, pdir/res_map will also be log2(). 12628c2ecf20Sopenharmony_ci */ 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci /* We could use larger page sizes in order to *decrease* the number 12658c2ecf20Sopenharmony_ci ** of mappings needed. (ie 8k pages means 1/2 the mappings). 12668c2ecf20Sopenharmony_ci ** 12678c2ecf20Sopenharmony_ci ** Note: Grant Grunder says "Using 8k I/O pages isn't trivial either 12688c2ecf20Sopenharmony_ci ** since the pages must also be physically contiguous - typically 12698c2ecf20Sopenharmony_ci ** this is the case under linux." 12708c2ecf20Sopenharmony_ci */ 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci iov_order = get_order(iova_space_size << PAGE_SHIFT); 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci /* iova_space_size is now bytes, not pages */ 12758c2ecf20Sopenharmony_ci iova_space_size = 1 << (iov_order + PAGE_SHIFT); 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci ioc->pdir_size = (iova_space_size / IOVP_SIZE) * sizeof(u64); 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci BUG_ON(ioc->pdir_size > 8 * 1024 * 1024); /* max pdir size <= 8MB */ 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci /* Verify it's a power of two */ 12828c2ecf20Sopenharmony_ci BUG_ON((1 << get_order(ioc->pdir_size)) != (ioc->pdir_size >> PAGE_SHIFT)); 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci DBG_INIT("%s() hpa 0x%p mem %luMB IOV %dMB (%d bits)\n", 12858c2ecf20Sopenharmony_ci __func__, ioc->ioc_regs, 12868c2ecf20Sopenharmony_ci (unsigned long) totalram_pages() >> (20 - PAGE_SHIFT), 12878c2ecf20Sopenharmony_ci iova_space_size>>20, 12888c2ecf20Sopenharmony_ci iov_order + PAGE_SHIFT); 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci ioc->pdir_base = (u64 *)__get_free_pages(GFP_KERNEL, 12918c2ecf20Sopenharmony_ci get_order(ioc->pdir_size)); 12928c2ecf20Sopenharmony_ci if(NULL == ioc->pdir_base) { 12938c2ecf20Sopenharmony_ci panic("%s() could not allocate I/O Page Table\n", __func__); 12948c2ecf20Sopenharmony_ci } 12958c2ecf20Sopenharmony_ci memset(ioc->pdir_base, 0, ioc->pdir_size); 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci BUG_ON((((unsigned long)ioc->pdir_base) & PAGE_MASK) != (unsigned long)ioc->pdir_base); 12988c2ecf20Sopenharmony_ci DBG_INIT(" base %p\n", ioc->pdir_base); 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci /* resource map size dictated by pdir_size */ 13018c2ecf20Sopenharmony_ci ioc->res_size = (ioc->pdir_size / sizeof(u64)) >> 3; 13028c2ecf20Sopenharmony_ci DBG_INIT("%s() res_size 0x%x\n", __func__, ioc->res_size); 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci ioc->res_map = (u8 *)__get_free_pages(GFP_KERNEL, 13058c2ecf20Sopenharmony_ci get_order(ioc->res_size)); 13068c2ecf20Sopenharmony_ci if(NULL == ioc->res_map) { 13078c2ecf20Sopenharmony_ci panic("%s() could not allocate resource map\n", __func__); 13088c2ecf20Sopenharmony_ci } 13098c2ecf20Sopenharmony_ci memset(ioc->res_map, 0, ioc->res_size); 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci /* Initialize the res_hint to 16 */ 13128c2ecf20Sopenharmony_ci ioc->res_hint = 16; 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci /* Initialize the spinlock */ 13158c2ecf20Sopenharmony_ci spin_lock_init(&ioc->res_lock); 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci /* 13188c2ecf20Sopenharmony_ci ** Chainid is the upper most bits of an IOVP used to determine 13198c2ecf20Sopenharmony_ci ** which TLB entry an IOVP will use. 13208c2ecf20Sopenharmony_ci */ 13218c2ecf20Sopenharmony_ci ioc->chainid_shift = get_order(iova_space_size) + PAGE_SHIFT - CCIO_CHAINID_SHIFT; 13228c2ecf20Sopenharmony_ci DBG_INIT(" chainid_shift 0x%x\n", ioc->chainid_shift); 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci /* 13258c2ecf20Sopenharmony_ci ** Initialize IOA hardware 13268c2ecf20Sopenharmony_ci */ 13278c2ecf20Sopenharmony_ci WRITE_U32(CCIO_CHAINID_MASK << ioc->chainid_shift, 13288c2ecf20Sopenharmony_ci &ioc->ioc_regs->io_chain_id_mask); 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci WRITE_U32(virt_to_phys(ioc->pdir_base), 13318c2ecf20Sopenharmony_ci &ioc->ioc_regs->io_pdir_base); 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci /* 13348c2ecf20Sopenharmony_ci ** Go to "Virtual Mode" 13358c2ecf20Sopenharmony_ci */ 13368c2ecf20Sopenharmony_ci WRITE_U32(IOA_NORMAL_MODE, &ioc->ioc_regs->io_control); 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci /* 13398c2ecf20Sopenharmony_ci ** Initialize all I/O TLB entries to 0 (Valid bit off). 13408c2ecf20Sopenharmony_ci */ 13418c2ecf20Sopenharmony_ci WRITE_U32(0, &ioc->ioc_regs->io_tlb_entry_m); 13428c2ecf20Sopenharmony_ci WRITE_U32(0, &ioc->ioc_regs->io_tlb_entry_l); 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci for(i = 1 << CCIO_CHAINID_SHIFT; i ; i--) { 13458c2ecf20Sopenharmony_ci WRITE_U32((CMD_TLB_DIRECT_WRITE | (i << ioc->chainid_shift)), 13468c2ecf20Sopenharmony_ci &ioc->ioc_regs->io_command); 13478c2ecf20Sopenharmony_ci } 13488c2ecf20Sopenharmony_ci} 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_cistatic void __init 13518c2ecf20Sopenharmony_ciccio_init_resource(struct resource *res, char *name, void __iomem *ioaddr) 13528c2ecf20Sopenharmony_ci{ 13538c2ecf20Sopenharmony_ci int result; 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci res->parent = NULL; 13568c2ecf20Sopenharmony_ci res->flags = IORESOURCE_MEM; 13578c2ecf20Sopenharmony_ci /* 13588c2ecf20Sopenharmony_ci * bracing ((signed) ...) are required for 64bit kernel because 13598c2ecf20Sopenharmony_ci * we only want to sign extend the lower 16 bits of the register. 13608c2ecf20Sopenharmony_ci * The upper 16-bits of range registers are hardcoded to 0xffff. 13618c2ecf20Sopenharmony_ci */ 13628c2ecf20Sopenharmony_ci res->start = (unsigned long)((signed) READ_U32(ioaddr) << 16); 13638c2ecf20Sopenharmony_ci res->end = (unsigned long)((signed) (READ_U32(ioaddr + 4) << 16) - 1); 13648c2ecf20Sopenharmony_ci res->name = name; 13658c2ecf20Sopenharmony_ci /* 13668c2ecf20Sopenharmony_ci * Check if this MMIO range is disable 13678c2ecf20Sopenharmony_ci */ 13688c2ecf20Sopenharmony_ci if (res->end + 1 == res->start) 13698c2ecf20Sopenharmony_ci return; 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci /* On some platforms (e.g. K-Class), we have already registered 13728c2ecf20Sopenharmony_ci * resources for devices reported by firmware. Some are children 13738c2ecf20Sopenharmony_ci * of ccio. 13748c2ecf20Sopenharmony_ci * "insert" ccio ranges in the mmio hierarchy (/proc/iomem). 13758c2ecf20Sopenharmony_ci */ 13768c2ecf20Sopenharmony_ci result = insert_resource(&iomem_resource, res); 13778c2ecf20Sopenharmony_ci if (result < 0) { 13788c2ecf20Sopenharmony_ci printk(KERN_ERR "%s() failed to claim CCIO bus address space (%08lx,%08lx)\n", 13798c2ecf20Sopenharmony_ci __func__, (unsigned long)res->start, (unsigned long)res->end); 13808c2ecf20Sopenharmony_ci } 13818c2ecf20Sopenharmony_ci} 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_cistatic int __init ccio_init_resources(struct ioc *ioc) 13848c2ecf20Sopenharmony_ci{ 13858c2ecf20Sopenharmony_ci struct resource *res = ioc->mmio_region; 13868c2ecf20Sopenharmony_ci char *name = kmalloc(14, GFP_KERNEL); 13878c2ecf20Sopenharmony_ci if (unlikely(!name)) 13888c2ecf20Sopenharmony_ci return -ENOMEM; 13898c2ecf20Sopenharmony_ci snprintf(name, 14, "GSC Bus [%d/]", ioc->hw_path); 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci ccio_init_resource(res, name, &ioc->ioc_regs->io_io_low); 13928c2ecf20Sopenharmony_ci ccio_init_resource(res + 1, name, &ioc->ioc_regs->io_io_low_hv); 13938c2ecf20Sopenharmony_ci return 0; 13948c2ecf20Sopenharmony_ci} 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_cistatic int new_ioc_area(struct resource *res, unsigned long size, 13978c2ecf20Sopenharmony_ci unsigned long min, unsigned long max, unsigned long align) 13988c2ecf20Sopenharmony_ci{ 13998c2ecf20Sopenharmony_ci if (max <= min) 14008c2ecf20Sopenharmony_ci return -EBUSY; 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci res->start = (max - size + 1) &~ (align - 1); 14038c2ecf20Sopenharmony_ci res->end = res->start + size; 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci /* We might be trying to expand the MMIO range to include 14068c2ecf20Sopenharmony_ci * a child device that has already registered it's MMIO space. 14078c2ecf20Sopenharmony_ci * Use "insert" instead of request_resource(). 14088c2ecf20Sopenharmony_ci */ 14098c2ecf20Sopenharmony_ci if (!insert_resource(&iomem_resource, res)) 14108c2ecf20Sopenharmony_ci return 0; 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci return new_ioc_area(res, size, min, max - size, align); 14138c2ecf20Sopenharmony_ci} 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_cistatic int expand_ioc_area(struct resource *res, unsigned long size, 14168c2ecf20Sopenharmony_ci unsigned long min, unsigned long max, unsigned long align) 14178c2ecf20Sopenharmony_ci{ 14188c2ecf20Sopenharmony_ci unsigned long start, len; 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci if (!res->parent) 14218c2ecf20Sopenharmony_ci return new_ioc_area(res, size, min, max, align); 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci start = (res->start - size) &~ (align - 1); 14248c2ecf20Sopenharmony_ci len = res->end - start + 1; 14258c2ecf20Sopenharmony_ci if (start >= min) { 14268c2ecf20Sopenharmony_ci if (!adjust_resource(res, start, len)) 14278c2ecf20Sopenharmony_ci return 0; 14288c2ecf20Sopenharmony_ci } 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci start = res->start; 14318c2ecf20Sopenharmony_ci len = ((size + res->end + align) &~ (align - 1)) - start; 14328c2ecf20Sopenharmony_ci if (start + len <= max) { 14338c2ecf20Sopenharmony_ci if (!adjust_resource(res, start, len)) 14348c2ecf20Sopenharmony_ci return 0; 14358c2ecf20Sopenharmony_ci } 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci return -EBUSY; 14388c2ecf20Sopenharmony_ci} 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci/* 14418c2ecf20Sopenharmony_ci * Dino calls this function. Beware that we may get called on systems 14428c2ecf20Sopenharmony_ci * which have no IOC (725, B180, C160L, etc) but do have a Dino. 14438c2ecf20Sopenharmony_ci * So it's legal to find no parent IOC. 14448c2ecf20Sopenharmony_ci * 14458c2ecf20Sopenharmony_ci * Some other issues: one of the resources in the ioc may be unassigned. 14468c2ecf20Sopenharmony_ci */ 14478c2ecf20Sopenharmony_ciint ccio_allocate_resource(const struct parisc_device *dev, 14488c2ecf20Sopenharmony_ci struct resource *res, unsigned long size, 14498c2ecf20Sopenharmony_ci unsigned long min, unsigned long max, unsigned long align) 14508c2ecf20Sopenharmony_ci{ 14518c2ecf20Sopenharmony_ci struct resource *parent = &iomem_resource; 14528c2ecf20Sopenharmony_ci struct ioc *ioc = ccio_get_iommu(dev); 14538c2ecf20Sopenharmony_ci if (!ioc) 14548c2ecf20Sopenharmony_ci goto out; 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci parent = ioc->mmio_region; 14578c2ecf20Sopenharmony_ci if (parent->parent && 14588c2ecf20Sopenharmony_ci !allocate_resource(parent, res, size, min, max, align, NULL, NULL)) 14598c2ecf20Sopenharmony_ci return 0; 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci if ((parent + 1)->parent && 14628c2ecf20Sopenharmony_ci !allocate_resource(parent + 1, res, size, min, max, align, 14638c2ecf20Sopenharmony_ci NULL, NULL)) 14648c2ecf20Sopenharmony_ci return 0; 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci if (!expand_ioc_area(parent, size, min, max, align)) { 14678c2ecf20Sopenharmony_ci __raw_writel(((parent->start)>>16) | 0xffff0000, 14688c2ecf20Sopenharmony_ci &ioc->ioc_regs->io_io_low); 14698c2ecf20Sopenharmony_ci __raw_writel(((parent->end)>>16) | 0xffff0000, 14708c2ecf20Sopenharmony_ci &ioc->ioc_regs->io_io_high); 14718c2ecf20Sopenharmony_ci } else if (!expand_ioc_area(parent + 1, size, min, max, align)) { 14728c2ecf20Sopenharmony_ci parent++; 14738c2ecf20Sopenharmony_ci __raw_writel(((parent->start)>>16) | 0xffff0000, 14748c2ecf20Sopenharmony_ci &ioc->ioc_regs->io_io_low_hv); 14758c2ecf20Sopenharmony_ci __raw_writel(((parent->end)>>16) | 0xffff0000, 14768c2ecf20Sopenharmony_ci &ioc->ioc_regs->io_io_high_hv); 14778c2ecf20Sopenharmony_ci } else { 14788c2ecf20Sopenharmony_ci return -EBUSY; 14798c2ecf20Sopenharmony_ci } 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci out: 14828c2ecf20Sopenharmony_ci return allocate_resource(parent, res, size, min, max, align, NULL,NULL); 14838c2ecf20Sopenharmony_ci} 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ciint ccio_request_resource(const struct parisc_device *dev, 14868c2ecf20Sopenharmony_ci struct resource *res) 14878c2ecf20Sopenharmony_ci{ 14888c2ecf20Sopenharmony_ci struct resource *parent; 14898c2ecf20Sopenharmony_ci struct ioc *ioc = ccio_get_iommu(dev); 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci if (!ioc) { 14928c2ecf20Sopenharmony_ci parent = &iomem_resource; 14938c2ecf20Sopenharmony_ci } else if ((ioc->mmio_region->start <= res->start) && 14948c2ecf20Sopenharmony_ci (res->end <= ioc->mmio_region->end)) { 14958c2ecf20Sopenharmony_ci parent = ioc->mmio_region; 14968c2ecf20Sopenharmony_ci } else if (((ioc->mmio_region + 1)->start <= res->start) && 14978c2ecf20Sopenharmony_ci (res->end <= (ioc->mmio_region + 1)->end)) { 14988c2ecf20Sopenharmony_ci parent = ioc->mmio_region + 1; 14998c2ecf20Sopenharmony_ci } else { 15008c2ecf20Sopenharmony_ci return -EBUSY; 15018c2ecf20Sopenharmony_ci } 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci /* "transparent" bus bridges need to register MMIO resources 15048c2ecf20Sopenharmony_ci * firmware assigned them. e.g. children of hppb.c (e.g. K-class) 15058c2ecf20Sopenharmony_ci * registered their resources in the PDC "bus walk" (See 15068c2ecf20Sopenharmony_ci * arch/parisc/kernel/inventory.c). 15078c2ecf20Sopenharmony_ci */ 15088c2ecf20Sopenharmony_ci return insert_resource(parent, res); 15098c2ecf20Sopenharmony_ci} 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci/** 15128c2ecf20Sopenharmony_ci * ccio_probe - Determine if ccio should claim this device. 15138c2ecf20Sopenharmony_ci * @dev: The device which has been found 15148c2ecf20Sopenharmony_ci * 15158c2ecf20Sopenharmony_ci * Determine if ccio should claim this chip (return 0) or not (return 1). 15168c2ecf20Sopenharmony_ci * If so, initialize the chip and tell other partners in crime they 15178c2ecf20Sopenharmony_ci * have work to do. 15188c2ecf20Sopenharmony_ci */ 15198c2ecf20Sopenharmony_cistatic int __init ccio_probe(struct parisc_device *dev) 15208c2ecf20Sopenharmony_ci{ 15218c2ecf20Sopenharmony_ci int i; 15228c2ecf20Sopenharmony_ci struct ioc *ioc, **ioc_p = &ioc_list; 15238c2ecf20Sopenharmony_ci struct pci_hba_data *hba; 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci ioc = kzalloc(sizeof(struct ioc), GFP_KERNEL); 15268c2ecf20Sopenharmony_ci if (ioc == NULL) { 15278c2ecf20Sopenharmony_ci printk(KERN_ERR MODULE_NAME ": memory allocation failure\n"); 15288c2ecf20Sopenharmony_ci return -ENOMEM; 15298c2ecf20Sopenharmony_ci } 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci ioc->name = dev->id.hversion == U2_IOA_RUNWAY ? "U2" : "UTurn"; 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci printk(KERN_INFO "Found %s at 0x%lx\n", ioc->name, 15348c2ecf20Sopenharmony_ci (unsigned long)dev->hpa.start); 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci for (i = 0; i < ioc_count; i++) { 15378c2ecf20Sopenharmony_ci ioc_p = &(*ioc_p)->next; 15388c2ecf20Sopenharmony_ci } 15398c2ecf20Sopenharmony_ci *ioc_p = ioc; 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci ioc->hw_path = dev->hw_path; 15428c2ecf20Sopenharmony_ci ioc->ioc_regs = ioremap(dev->hpa.start, 4096); 15438c2ecf20Sopenharmony_ci if (!ioc->ioc_regs) { 15448c2ecf20Sopenharmony_ci kfree(ioc); 15458c2ecf20Sopenharmony_ci return -ENOMEM; 15468c2ecf20Sopenharmony_ci } 15478c2ecf20Sopenharmony_ci ccio_ioc_init(ioc); 15488c2ecf20Sopenharmony_ci if (ccio_init_resources(ioc)) { 15498c2ecf20Sopenharmony_ci iounmap(ioc->ioc_regs); 15508c2ecf20Sopenharmony_ci kfree(ioc); 15518c2ecf20Sopenharmony_ci return -ENOMEM; 15528c2ecf20Sopenharmony_ci } 15538c2ecf20Sopenharmony_ci hppa_dma_ops = &ccio_ops; 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci hba = kzalloc(sizeof(*hba), GFP_KERNEL); 15568c2ecf20Sopenharmony_ci /* if this fails, no I/O cards will work, so may as well bug */ 15578c2ecf20Sopenharmony_ci BUG_ON(hba == NULL); 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci hba->iommu = ioc; 15608c2ecf20Sopenharmony_ci dev->dev.platform_data = hba; 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS 15638c2ecf20Sopenharmony_ci if (ioc_count == 0) { 15648c2ecf20Sopenharmony_ci proc_create_single(MODULE_NAME, 0, proc_runway_root, 15658c2ecf20Sopenharmony_ci ccio_proc_info); 15668c2ecf20Sopenharmony_ci proc_create_single(MODULE_NAME"-bitmap", 0, proc_runway_root, 15678c2ecf20Sopenharmony_ci ccio_proc_bitmap_info); 15688c2ecf20Sopenharmony_ci } 15698c2ecf20Sopenharmony_ci#endif 15708c2ecf20Sopenharmony_ci ioc_count++; 15718c2ecf20Sopenharmony_ci return 0; 15728c2ecf20Sopenharmony_ci} 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci/** 15758c2ecf20Sopenharmony_ci * ccio_init - ccio initialization procedure. 15768c2ecf20Sopenharmony_ci * 15778c2ecf20Sopenharmony_ci * Register this driver. 15788c2ecf20Sopenharmony_ci */ 15798c2ecf20Sopenharmony_civoid __init ccio_init(void) 15808c2ecf20Sopenharmony_ci{ 15818c2ecf20Sopenharmony_ci register_parisc_driver(&ccio_driver); 15828c2ecf20Sopenharmony_ci} 15838c2ecf20Sopenharmony_ci 1584