1f21fb3edSRaghu Vatsavayi /**********************************************************************
2f21fb3edSRaghu Vatsavayi  * Author: Cavium, Inc.
3f21fb3edSRaghu Vatsavayi  *
4f21fb3edSRaghu Vatsavayi  * Contact: support@cavium.com
5f21fb3edSRaghu Vatsavayi  *          Please include "LiquidIO" in the subject.
6f21fb3edSRaghu Vatsavayi  *
750579d3dSRaghu Vatsavayi  * Copyright (c) 2003-2016 Cavium, Inc.
8f21fb3edSRaghu Vatsavayi  *
9f21fb3edSRaghu Vatsavayi  * This file is free software; you can redistribute it and/or modify
10f21fb3edSRaghu Vatsavayi  * it under the terms of the GNU General Public License, Version 2, as
11f21fb3edSRaghu Vatsavayi  * published by the Free Software Foundation.
12f21fb3edSRaghu Vatsavayi  *
13f21fb3edSRaghu Vatsavayi  * This file is distributed in the hope that it will be useful, but
14f21fb3edSRaghu Vatsavayi  * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
15f21fb3edSRaghu Vatsavayi  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
16f21fb3edSRaghu Vatsavayi  * NONINFRINGEMENT.  See the GNU General Public License for more
17f21fb3edSRaghu Vatsavayi  * details.
18f21fb3edSRaghu Vatsavayi  **********************************************************************/
19f21fb3edSRaghu Vatsavayi #include <linux/netdevice.h>
20f21fb3edSRaghu Vatsavayi #include "liquidio_common.h"
21f21fb3edSRaghu Vatsavayi #include "octeon_droq.h"
22f21fb3edSRaghu Vatsavayi #include "octeon_iq.h"
23f21fb3edSRaghu Vatsavayi #include "response_manager.h"
24f21fb3edSRaghu Vatsavayi #include "octeon_device.h"
2598cf1c67SWang Hai #include "octeon_mem_ops.h"
26f21fb3edSRaghu Vatsavayi 
2715d3afccSFelix Manlunas #define MEMOPS_IDX   BAR1_INDEX_DYNAMIC_MAP
28f21fb3edSRaghu Vatsavayi 
29f21fb3edSRaghu Vatsavayi #ifdef __BIG_ENDIAN_BITFIELD
30a7d5a3dcSRaghu Vatsavayi static inline void
octeon_toggle_bar1_swapmode(struct octeon_device * oct,u32 idx)31a7d5a3dcSRaghu Vatsavayi octeon_toggle_bar1_swapmode(struct octeon_device *oct, u32 idx)
32a7d5a3dcSRaghu Vatsavayi {
33f21fb3edSRaghu Vatsavayi 	u32 mask;
34f21fb3edSRaghu Vatsavayi 
35f21fb3edSRaghu Vatsavayi 	mask = oct->fn_list.bar1_idx_read(oct, idx);
36f21fb3edSRaghu Vatsavayi 	mask = (mask & 0x2) ? (mask & ~2) : (mask | 2);
37f21fb3edSRaghu Vatsavayi 	oct->fn_list.bar1_idx_write(oct, idx, mask);
38f21fb3edSRaghu Vatsavayi }
39a7d5a3dcSRaghu Vatsavayi #else
4097a25326SRaghu Vatsavayi #define octeon_toggle_bar1_swapmode(oct, idx)
41a7d5a3dcSRaghu Vatsavayi #endif
42f21fb3edSRaghu Vatsavayi 
43f21fb3edSRaghu Vatsavayi static void
octeon_pci_fastwrite(struct octeon_device * oct,u8 __iomem * mapped_addr,u8 * hostbuf,u32 len)44f21fb3edSRaghu Vatsavayi octeon_pci_fastwrite(struct octeon_device *oct, u8 __iomem *mapped_addr,
45f21fb3edSRaghu Vatsavayi 		     u8 *hostbuf, u32 len)
46f21fb3edSRaghu Vatsavayi {
47f21fb3edSRaghu Vatsavayi 	while ((len) && ((unsigned long)mapped_addr) & 7) {
48f21fb3edSRaghu Vatsavayi 		writeb(*(hostbuf++), mapped_addr++);
49f21fb3edSRaghu Vatsavayi 		len--;
50f21fb3edSRaghu Vatsavayi 	}
51f21fb3edSRaghu Vatsavayi 
52f21fb3edSRaghu Vatsavayi 	octeon_toggle_bar1_swapmode(oct, MEMOPS_IDX);
53f21fb3edSRaghu Vatsavayi 
54f21fb3edSRaghu Vatsavayi 	while (len >= 8) {
55f21fb3edSRaghu Vatsavayi 		writeq(*((u64 *)hostbuf), mapped_addr);
56f21fb3edSRaghu Vatsavayi 		mapped_addr += 8;
57f21fb3edSRaghu Vatsavayi 		hostbuf += 8;
58f21fb3edSRaghu Vatsavayi 		len -= 8;
59f21fb3edSRaghu Vatsavayi 	}
60f21fb3edSRaghu Vatsavayi 
61f21fb3edSRaghu Vatsavayi 	octeon_toggle_bar1_swapmode(oct, MEMOPS_IDX);
62f21fb3edSRaghu Vatsavayi 
63f21fb3edSRaghu Vatsavayi 	while (len--)
64f21fb3edSRaghu Vatsavayi 		writeb(*(hostbuf++), mapped_addr++);
65f21fb3edSRaghu Vatsavayi }
66f21fb3edSRaghu Vatsavayi 
67f21fb3edSRaghu Vatsavayi static void
octeon_pci_fastread(struct octeon_device * oct,u8 __iomem * mapped_addr,u8 * hostbuf,u32 len)68f21fb3edSRaghu Vatsavayi octeon_pci_fastread(struct octeon_device *oct, u8 __iomem *mapped_addr,
69f21fb3edSRaghu Vatsavayi 		    u8 *hostbuf, u32 len)
70f21fb3edSRaghu Vatsavayi {
71f21fb3edSRaghu Vatsavayi 	while ((len) && ((unsigned long)mapped_addr) & 7) {
72f21fb3edSRaghu Vatsavayi 		*(hostbuf++) = readb(mapped_addr++);
73f21fb3edSRaghu Vatsavayi 		len--;
74f21fb3edSRaghu Vatsavayi 	}
75f21fb3edSRaghu Vatsavayi 
76f21fb3edSRaghu Vatsavayi 	octeon_toggle_bar1_swapmode(oct, MEMOPS_IDX);
77f21fb3edSRaghu Vatsavayi 
78f21fb3edSRaghu Vatsavayi 	while (len >= 8) {
79f21fb3edSRaghu Vatsavayi 		*((u64 *)hostbuf) = readq(mapped_addr);
80f21fb3edSRaghu Vatsavayi 		mapped_addr += 8;
81f21fb3edSRaghu Vatsavayi 		hostbuf += 8;
82f21fb3edSRaghu Vatsavayi 		len -= 8;
83f21fb3edSRaghu Vatsavayi 	}
84f21fb3edSRaghu Vatsavayi 
85f21fb3edSRaghu Vatsavayi 	octeon_toggle_bar1_swapmode(oct, MEMOPS_IDX);
86f21fb3edSRaghu Vatsavayi 
87f21fb3edSRaghu Vatsavayi 	while (len--)
88f21fb3edSRaghu Vatsavayi 		*(hostbuf++) = readb(mapped_addr++);
89f21fb3edSRaghu Vatsavayi }
90f21fb3edSRaghu Vatsavayi 
91f21fb3edSRaghu Vatsavayi /* Core mem read/write with temporary bar1 settings. */
92f21fb3edSRaghu Vatsavayi /* op = 1 to read, op = 0 to write. */
93f21fb3edSRaghu Vatsavayi static void
__octeon_pci_rw_core_mem(struct octeon_device * oct,u64 addr,u8 * hostbuf,u32 len,u32 op)94f21fb3edSRaghu Vatsavayi __octeon_pci_rw_core_mem(struct octeon_device *oct, u64 addr,
95f21fb3edSRaghu Vatsavayi 			 u8 *hostbuf, u32 len, u32 op)
96f21fb3edSRaghu Vatsavayi {
97f21fb3edSRaghu Vatsavayi 	u32 copy_len = 0, index_reg_val = 0;
98f21fb3edSRaghu Vatsavayi 	unsigned long flags;
99f21fb3edSRaghu Vatsavayi 	u8 __iomem *mapped_addr;
10015d3afccSFelix Manlunas 	u64 static_mapping_base;
10115d3afccSFelix Manlunas 
10215d3afccSFelix Manlunas 	static_mapping_base = oct->console_nb_info.dram_region_base;
10315d3afccSFelix Manlunas 
10415d3afccSFelix Manlunas 	if (static_mapping_base &&
10515d3afccSFelix Manlunas 	    static_mapping_base == (addr & ~(OCTEON_BAR1_ENTRY_SIZE - 1ULL))) {
10615d3afccSFelix Manlunas 		int bar1_index = oct->console_nb_info.bar1_index;
10715d3afccSFelix Manlunas 
10815d3afccSFelix Manlunas 		mapped_addr = oct->mmio[1].hw_addr
10915d3afccSFelix Manlunas 			+ (bar1_index << ilog2(OCTEON_BAR1_ENTRY_SIZE))
11015d3afccSFelix Manlunas 			+ (addr & (OCTEON_BAR1_ENTRY_SIZE - 1ULL));
11115d3afccSFelix Manlunas 
11215d3afccSFelix Manlunas 		if (op)
11315d3afccSFelix Manlunas 			octeon_pci_fastread(oct, mapped_addr, hostbuf, len);
11415d3afccSFelix Manlunas 		else
11515d3afccSFelix Manlunas 			octeon_pci_fastwrite(oct, mapped_addr, hostbuf, len);
11615d3afccSFelix Manlunas 
11715d3afccSFelix Manlunas 		return;
11815d3afccSFelix Manlunas 	}
119f21fb3edSRaghu Vatsavayi 
120f21fb3edSRaghu Vatsavayi 	spin_lock_irqsave(&oct->mem_access_lock, flags);
121f21fb3edSRaghu Vatsavayi 
122f21fb3edSRaghu Vatsavayi 	/* Save the original index reg value. */
123f21fb3edSRaghu Vatsavayi 	index_reg_val = oct->fn_list.bar1_idx_read(oct, MEMOPS_IDX);
124f21fb3edSRaghu Vatsavayi 	do {
125f21fb3edSRaghu Vatsavayi 		oct->fn_list.bar1_idx_setup(oct, addr, MEMOPS_IDX, 1);
126f21fb3edSRaghu Vatsavayi 		mapped_addr = oct->mmio[1].hw_addr
127f21fb3edSRaghu Vatsavayi 		    + (MEMOPS_IDX << 22) + (addr & 0x3fffff);
128f21fb3edSRaghu Vatsavayi 
129f21fb3edSRaghu Vatsavayi 		/* If operation crosses a 4MB boundary, split the transfer
130f21fb3edSRaghu Vatsavayi 		 * at the 4MB
131f21fb3edSRaghu Vatsavayi 		 * boundary.
132f21fb3edSRaghu Vatsavayi 		 */
133f21fb3edSRaghu Vatsavayi 		if (((addr + len - 1) & ~(0x3fffff)) != (addr & ~(0x3fffff))) {
134f21fb3edSRaghu Vatsavayi 			copy_len = (u32)(((addr & ~(0x3fffff)) +
135f21fb3edSRaghu Vatsavayi 				   (MEMOPS_IDX << 22)) - addr);
136f21fb3edSRaghu Vatsavayi 		} else {
137f21fb3edSRaghu Vatsavayi 			copy_len = len;
138f21fb3edSRaghu Vatsavayi 		}
139f21fb3edSRaghu Vatsavayi 
140f21fb3edSRaghu Vatsavayi 		if (op) {	/* read from core */
141f21fb3edSRaghu Vatsavayi 			octeon_pci_fastread(oct, mapped_addr, hostbuf,
142f21fb3edSRaghu Vatsavayi 					    copy_len);
143f21fb3edSRaghu Vatsavayi 		} else {
144f21fb3edSRaghu Vatsavayi 			octeon_pci_fastwrite(oct, mapped_addr, hostbuf,
145f21fb3edSRaghu Vatsavayi 					     copy_len);
146f21fb3edSRaghu Vatsavayi 		}
147f21fb3edSRaghu Vatsavayi 
148f21fb3edSRaghu Vatsavayi 		len -= copy_len;
149f21fb3edSRaghu Vatsavayi 		addr += copy_len;
150f21fb3edSRaghu Vatsavayi 		hostbuf += copy_len;
151f21fb3edSRaghu Vatsavayi 
152f21fb3edSRaghu Vatsavayi 	} while (len);
153f21fb3edSRaghu Vatsavayi 
154f21fb3edSRaghu Vatsavayi 	oct->fn_list.bar1_idx_write(oct, MEMOPS_IDX, index_reg_val);
155f21fb3edSRaghu Vatsavayi 
156f21fb3edSRaghu Vatsavayi 	spin_unlock_irqrestore(&oct->mem_access_lock, flags);
157f21fb3edSRaghu Vatsavayi }
158f21fb3edSRaghu Vatsavayi 
159f21fb3edSRaghu Vatsavayi void
octeon_pci_read_core_mem(struct octeon_device * oct,u64 coreaddr,u8 * buf,u32 len)160f21fb3edSRaghu Vatsavayi octeon_pci_read_core_mem(struct octeon_device *oct,
161f21fb3edSRaghu Vatsavayi 			 u64 coreaddr,
162f21fb3edSRaghu Vatsavayi 			 u8 *buf,
163f21fb3edSRaghu Vatsavayi 			 u32 len)
164f21fb3edSRaghu Vatsavayi {
165f21fb3edSRaghu Vatsavayi 	__octeon_pci_rw_core_mem(oct, coreaddr, buf, len, 1);
166f21fb3edSRaghu Vatsavayi }
167*f71be9d0SMasahiro Yamada EXPORT_SYMBOL_GPL(octeon_pci_read_core_mem);
168f21fb3edSRaghu Vatsavayi 
169f21fb3edSRaghu Vatsavayi void
octeon_pci_write_core_mem(struct octeon_device * oct,u64 coreaddr,const u8 * buf,u32 len)170f21fb3edSRaghu Vatsavayi octeon_pci_write_core_mem(struct octeon_device *oct,
171f21fb3edSRaghu Vatsavayi 			  u64 coreaddr,
172b381f783SDenys Vlasenko 			  const u8 *buf,
173f21fb3edSRaghu Vatsavayi 			  u32 len)
174f21fb3edSRaghu Vatsavayi {
175b381f783SDenys Vlasenko 	__octeon_pci_rw_core_mem(oct, coreaddr, (u8 *)buf, len, 0);
176f21fb3edSRaghu Vatsavayi }
177*f71be9d0SMasahiro Yamada EXPORT_SYMBOL_GPL(octeon_pci_write_core_mem);
178f21fb3edSRaghu Vatsavayi 
octeon_read_device_mem64(struct octeon_device * oct,u64 coreaddr)179f21fb3edSRaghu Vatsavayi u64 octeon_read_device_mem64(struct octeon_device *oct, u64 coreaddr)
180f21fb3edSRaghu Vatsavayi {
1815b173cf9SRaghu Vatsavayi 	__be64 ret;
182f21fb3edSRaghu Vatsavayi 
183f21fb3edSRaghu Vatsavayi 	__octeon_pci_rw_core_mem(oct, coreaddr, (u8 *)&ret, 8, 1);
184f21fb3edSRaghu Vatsavayi 
185f21fb3edSRaghu Vatsavayi 	return be64_to_cpu(ret);
186f21fb3edSRaghu Vatsavayi }
187*f71be9d0SMasahiro Yamada EXPORT_SYMBOL_GPL(octeon_read_device_mem64);
188f21fb3edSRaghu Vatsavayi 
octeon_read_device_mem32(struct octeon_device * oct,u64 coreaddr)189f21fb3edSRaghu Vatsavayi u32 octeon_read_device_mem32(struct octeon_device *oct, u64 coreaddr)
190f21fb3edSRaghu Vatsavayi {
1915b173cf9SRaghu Vatsavayi 	__be32 ret;
192f21fb3edSRaghu Vatsavayi 
193f21fb3edSRaghu Vatsavayi 	__octeon_pci_rw_core_mem(oct, coreaddr, (u8 *)&ret, 4, 1);
194f21fb3edSRaghu Vatsavayi 
195f21fb3edSRaghu Vatsavayi 	return be32_to_cpu(ret);
196f21fb3edSRaghu Vatsavayi }
197*f71be9d0SMasahiro Yamada EXPORT_SYMBOL_GPL(octeon_read_device_mem32);
198f21fb3edSRaghu Vatsavayi 
octeon_write_device_mem32(struct octeon_device * oct,u64 coreaddr,u32 val)199f21fb3edSRaghu Vatsavayi void octeon_write_device_mem32(struct octeon_device *oct, u64 coreaddr,
200f21fb3edSRaghu Vatsavayi 			       u32 val)
201f21fb3edSRaghu Vatsavayi {
2025b173cf9SRaghu Vatsavayi 	__be32 t = cpu_to_be32(val);
203f21fb3edSRaghu Vatsavayi 
204f21fb3edSRaghu Vatsavayi 	__octeon_pci_rw_core_mem(oct, coreaddr, (u8 *)&t, 4, 0);
205f21fb3edSRaghu Vatsavayi }
206*f71be9d0SMasahiro Yamada EXPORT_SYMBOL_GPL(octeon_write_device_mem32);
207