Commit | Line | Data |
---|---|---|
65c85c83 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
2908d778 JB |
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> | |
2908d778 JB |
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 | */ | |
81e56ded AB |
17 | static void asd_write_byte(struct asd_ha_struct *asd_ha, |
18 | unsigned long offs, u8 val) | |
2908d778 JB |
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 | ||
81e56ded AB |
28 | static void asd_write_word(struct asd_ha_struct *asd_ha, |
29 | unsigned long offs, u16 val) | |
2908d778 JB |
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 | ||
81e56ded AB |
39 | static void asd_write_dword(struct asd_ha_struct *asd_ha, |
40 | unsigned long offs, u32 val) | |
2908d778 JB |
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 | */ | |
81e56ded | 52 | static u8 asd_read_byte(struct asd_ha_struct *asd_ha, unsigned long offs) |
2908d778 JB |
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 | ||
81e56ded AB |
64 | static u16 asd_read_word(struct asd_ha_struct *asd_ha, |
65 | unsigned long offs) | |
2908d778 JB |
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 | ||
81e56ded AB |
77 | static u32 asd_read_dword(struct asd_ha_struct *asd_ha, |
78 | unsigned long offs) | |
2908d778 JB |
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 | */ | |
81e56ded AB |
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); \ | |
2908d778 JB |
115 | } |
116 | ||
81e56ded AB |
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); \ | |
2908d778 JB |
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 | */ | |
81e56ded | 170 | static void asd_move_swb(struct asd_ha_struct *asd_ha, u32 reg) |
2908d778 JB |
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 | } |