Merge tag 'nf-23-09-13' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf
[linux-2.6-microblaze.git] / drivers / scsi / aic94xx / aic94xx_reg.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Aic94xx SAS/SATA driver register access.
4  *
5  * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
6  * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
7  */
8
9 #include <linux/pci.h>
10 #include "aic94xx_reg.h"
11 #include "aic94xx.h"
12
13 /* Writing to device address space.
14  * Offset comes before value to remind that the operation of
15  * this function is *offs = val.
16  */
17 static void asd_write_byte(struct asd_ha_struct *asd_ha,
18                            unsigned long offs, u8 val)
19 {
20         if (unlikely(asd_ha->iospace))
21                 outb(val,
22                      (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF));
23         else
24                 writeb(val, asd_ha->io_handle[0].addr + offs);
25         wmb();
26 }
27
28 static void asd_write_word(struct asd_ha_struct *asd_ha,
29                            unsigned long offs, u16 val)
30 {
31         if (unlikely(asd_ha->iospace))
32                 outw(val,
33                      (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF));
34         else
35                 writew(val, asd_ha->io_handle[0].addr + offs);
36         wmb();
37 }
38
39 static void asd_write_dword(struct asd_ha_struct *asd_ha,
40                             unsigned long offs, u32 val)
41 {
42         if (unlikely(asd_ha->iospace))
43                 outl(val,
44                      (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF));
45         else
46                 writel(val, asd_ha->io_handle[0].addr + offs);
47         wmb();
48 }
49
50 /* Reading from device address space.
51  */
52 static u8 asd_read_byte(struct asd_ha_struct *asd_ha, unsigned long offs)
53 {
54         u8 val;
55         if (unlikely(asd_ha->iospace))
56                 val = inb((unsigned long) asd_ha->io_handle[0].addr
57                           + (offs & 0xFF));
58         else
59                 val = readb(asd_ha->io_handle[0].addr + offs);
60         rmb();
61         return val;
62 }
63
64 static u16 asd_read_word(struct asd_ha_struct *asd_ha,
65                          unsigned long offs)
66 {
67         u16 val;
68         if (unlikely(asd_ha->iospace))
69                 val = inw((unsigned long)asd_ha->io_handle[0].addr
70                           + (offs & 0xFF));
71         else
72                 val = readw(asd_ha->io_handle[0].addr + offs);
73         rmb();
74         return val;
75 }
76
77 static u32 asd_read_dword(struct asd_ha_struct *asd_ha,
78                           unsigned long offs)
79 {
80         u32 val;
81         if (unlikely(asd_ha->iospace))
82                 val = inl((unsigned long) asd_ha->io_handle[0].addr
83                           + (offs & 0xFF));
84         else
85                 val = readl(asd_ha->io_handle[0].addr + offs);
86         rmb();
87         return val;
88 }
89
90 static inline u32 asd_mem_offs_swa(void)
91 {
92         return 0;
93 }
94
95 static inline u32 asd_mem_offs_swc(void)
96 {
97         return asd_mem_offs_swa() + MBAR0_SWA_SIZE;
98 }
99
100 static inline u32 asd_mem_offs_swb(void)
101 {
102         return asd_mem_offs_swc() + MBAR0_SWC_SIZE + 0x20;
103 }
104
105 /* We know that the register wanted is in the range
106  * of the sliding window.
107  */
108 #define ASD_READ_SW(ww, type, ord)                                      \
109 static type asd_read_##ww##_##ord(struct asd_ha_struct *asd_ha,         \
110                                    u32 reg)                             \
111 {                                                                       \
112         struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0];     \
113         u32 map_offs = (reg - io_handle->ww##_base) + asd_mem_offs_##ww();\
114         return asd_read_##ord(asd_ha, (unsigned long)map_offs); \
115 }
116
117 #define ASD_WRITE_SW(ww, type, ord)                                     \
118 static void asd_write_##ww##_##ord(struct asd_ha_struct *asd_ha,        \
119                                     u32 reg, type val)                  \
120 {                                                                       \
121         struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0];     \
122         u32 map_offs = (reg - io_handle->ww##_base) + asd_mem_offs_##ww();\
123         asd_write_##ord(asd_ha, (unsigned long)map_offs, val);          \
124 }
125
126 ASD_READ_SW(swa, u8,  byte);
127 ASD_READ_SW(swa, u16, word);
128 ASD_READ_SW(swa, u32, dword);
129
130 ASD_READ_SW(swb, u8,  byte);
131 ASD_READ_SW(swb, u16, word);
132 ASD_READ_SW(swb, u32, dword);
133
134 ASD_READ_SW(swc, u8,  byte);
135 ASD_READ_SW(swc, u16, word);
136 ASD_READ_SW(swc, u32, dword);
137
138 ASD_WRITE_SW(swa, u8,  byte);
139 ASD_WRITE_SW(swa, u16, word);
140 ASD_WRITE_SW(swa, u32, dword);
141
142 ASD_WRITE_SW(swb, u8,  byte);
143 ASD_WRITE_SW(swb, u16, word);
144 ASD_WRITE_SW(swb, u32, dword);
145
146 ASD_WRITE_SW(swc, u8,  byte);
147 ASD_WRITE_SW(swc, u16, word);
148 ASD_WRITE_SW(swc, u32, dword);
149
150 /*
151  * A word about sliding windows:
152  * MBAR0 is divided into sliding windows A, C and B, in that order.
153  * SWA starts at offset 0 of MBAR0, up to 0x57, with size 0x58 bytes.
154  * SWC starts at offset 0x58 of MBAR0, up to 0x60, with size 0x8 bytes.
155  * From 0x60 to 0x7F, we have a copy of PCI config space 0x60-0x7F.
156  * SWB starts at offset 0x80 of MBAR0 and extends to the end of MBAR0.
157  * See asd_init_sw() in aic94xx_hwi.c
158  *
159  * We map the most common registers we'd access of the internal 4GB
160  * host adapter memory space.  If a register/internal memory location
161  * is wanted which is not mapped, we slide SWB, by paging it,
162  * see asd_move_swb() in aic94xx_reg.c.
163  */
164
165 /**
166  * asd_move_swb -- move sliding window B
167  * @asd_ha: pointer to host adapter structure
168  * @reg: register desired to be within range of the new window
169  */
170 static void asd_move_swb(struct asd_ha_struct *asd_ha, u32 reg)
171 {
172         u32 base = reg & ~(MBAR0_SWB_SIZE-1);
173         pci_write_config_dword(asd_ha->pcidev, PCI_CONF_MBAR0_SWB, base);
174         asd_ha->io_handle[0].swb_base = base;
175 }
176
177 static void __asd_write_reg_byte(struct asd_ha_struct *asd_ha, u32 reg, u8 val)
178 {
179         struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0];
180         BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);
181         if (io_handle->swa_base <= reg
182             && reg < io_handle->swa_base + MBAR0_SWA_SIZE)
183                 asd_write_swa_byte (asd_ha, reg,val);
184         else if (io_handle->swb_base <= reg
185                  && reg < io_handle->swb_base + MBAR0_SWB_SIZE)
186                 asd_write_swb_byte (asd_ha, reg, val);
187         else if (io_handle->swc_base <= reg
188                  && reg < io_handle->swc_base + MBAR0_SWC_SIZE)
189                 asd_write_swc_byte (asd_ha, reg, val);
190         else {
191                 /* Ok, we have to move SWB */
192                 asd_move_swb(asd_ha, reg);
193                 asd_write_swb_byte (asd_ha, reg, val);
194         }
195 }
196
197 #define ASD_WRITE_REG(type, ord)                                  \
198 void asd_write_reg_##ord (struct asd_ha_struct *asd_ha, u32 reg, type val)\
199 {                                                                 \
200         struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; \
201         unsigned long flags;                                      \
202         BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);         \
203         spin_lock_irqsave(&asd_ha->iolock, flags);                \
204         if (io_handle->swa_base <= reg                            \
205             && reg < io_handle->swa_base + MBAR0_SWA_SIZE)        \
206                 asd_write_swa_##ord (asd_ha, reg,val);            \
207         else if (io_handle->swb_base <= reg                       \
208                  && reg < io_handle->swb_base + MBAR0_SWB_SIZE)   \
209                 asd_write_swb_##ord (asd_ha, reg, val);           \
210         else if (io_handle->swc_base <= reg                       \
211                  && reg < io_handle->swc_base + MBAR0_SWC_SIZE)   \
212                 asd_write_swc_##ord (asd_ha, reg, val);           \
213         else {                                                    \
214                 /* Ok, we have to move SWB */                     \
215                 asd_move_swb(asd_ha, reg);                        \
216                 asd_write_swb_##ord (asd_ha, reg, val);           \
217         }                                                         \
218         spin_unlock_irqrestore(&asd_ha->iolock, flags);           \
219 }
220
221 ASD_WRITE_REG(u8, byte);
222 ASD_WRITE_REG(u16,word);
223 ASD_WRITE_REG(u32,dword);
224
225 static u8 __asd_read_reg_byte(struct asd_ha_struct *asd_ha, u32 reg)
226 {
227         struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0];
228         u8 val;
229         BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);
230         if (io_handle->swa_base <= reg
231             && reg < io_handle->swa_base + MBAR0_SWA_SIZE)
232                 val = asd_read_swa_byte (asd_ha, reg);
233         else if (io_handle->swb_base <= reg
234                  && reg < io_handle->swb_base + MBAR0_SWB_SIZE)
235                 val = asd_read_swb_byte (asd_ha, reg);
236         else if (io_handle->swc_base <= reg
237                  && reg < io_handle->swc_base + MBAR0_SWC_SIZE)
238                 val = asd_read_swc_byte (asd_ha, reg);
239         else {
240                 /* Ok, we have to move SWB */
241                 asd_move_swb(asd_ha, reg);
242                 val = asd_read_swb_byte (asd_ha, reg);
243         }
244         return val;
245 }
246
247 #define ASD_READ_REG(type, ord)                                   \
248 type asd_read_reg_##ord (struct asd_ha_struct *asd_ha, u32 reg)   \
249 {                                                                 \
250         struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; \
251         type val;                                                 \
252         unsigned long flags;                                      \
253         BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);         \
254         spin_lock_irqsave(&asd_ha->iolock, flags);                \
255         if (io_handle->swa_base <= reg                            \
256             && reg < io_handle->swa_base + MBAR0_SWA_SIZE)        \
257                 val = asd_read_swa_##ord (asd_ha, reg);           \
258         else if (io_handle->swb_base <= reg                       \
259                  && reg < io_handle->swb_base + MBAR0_SWB_SIZE)   \
260                 val = asd_read_swb_##ord (asd_ha, reg);           \
261         else if (io_handle->swc_base <= reg                       \
262                  && reg < io_handle->swc_base + MBAR0_SWC_SIZE)   \
263                 val = asd_read_swc_##ord (asd_ha, reg);           \
264         else {                                                    \
265                 /* Ok, we have to move SWB */                     \
266                 asd_move_swb(asd_ha, reg);                        \
267                 val = asd_read_swb_##ord (asd_ha, reg);           \
268         }                                                         \
269         spin_unlock_irqrestore(&asd_ha->iolock, flags);           \
270         return val;                                               \
271 }
272
273 ASD_READ_REG(u8, byte);
274 ASD_READ_REG(u16,word);
275 ASD_READ_REG(u32,dword);
276
277 /**
278  * asd_read_reg_string -- read a string of bytes from io space memory
279  * @asd_ha: pointer to host adapter structure
280  * @dst: pointer to a destination buffer where data will be written to
281  * @offs: start offset (register) to read from
282  * @count: number of bytes to read
283  */
284 void asd_read_reg_string(struct asd_ha_struct *asd_ha, void *dst,
285                          u32 offs, int count)
286 {
287         u8 *p = dst;
288         unsigned long flags;
289
290         spin_lock_irqsave(&asd_ha->iolock, flags);
291         for ( ; count > 0; count--, offs++, p++)
292                 *p = __asd_read_reg_byte(asd_ha, offs);
293         spin_unlock_irqrestore(&asd_ha->iolock, flags);
294 }
295
296 /**
297  * asd_write_reg_string -- write a string of bytes to io space memory
298  * @asd_ha: pointer to host adapter structure
299  * @src: pointer to source buffer where data will be read from
300  * @offs: start offset (register) to write to
301  * @count: number of bytes to write
302  */
303 void asd_write_reg_string(struct asd_ha_struct *asd_ha, void *src,
304                           u32 offs, int count)
305 {
306         u8 *p = src;
307         unsigned long flags;
308
309         spin_lock_irqsave(&asd_ha->iolock, flags);
310         for ( ; count > 0; count--, offs++, p++)
311                 __asd_write_reg_byte(asd_ha, offs, *p);
312         spin_unlock_irqrestore(&asd_ha->iolock, flags);
313 }