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