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 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 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 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 u8 asd_read_byte(struct asd_ha_struct *asd_ha, unsigned long offs) 71 { 72 u8 val; 73 if (unlikely(asd_ha->iospace)) 74 val = inb((unsigned long) asd_ha->io_handle[0].addr 75 + (offs & 0xFF)); 76 else 77 val = readb(asd_ha->io_handle[0].addr + offs); 78 rmb(); 79 return val; 80 } 81 82 static u16 asd_read_word(struct asd_ha_struct *asd_ha, 83 unsigned long offs) 84 { 85 u16 val; 86 if (unlikely(asd_ha->iospace)) 87 val = inw((unsigned long)asd_ha->io_handle[0].addr 88 + (offs & 0xFF)); 89 else 90 val = readw(asd_ha->io_handle[0].addr + offs); 91 rmb(); 92 return val; 93 } 94 95 static u32 asd_read_dword(struct asd_ha_struct *asd_ha, 96 unsigned long offs) 97 { 98 u32 val; 99 if (unlikely(asd_ha->iospace)) 100 val = inl((unsigned long) asd_ha->io_handle[0].addr 101 + (offs & 0xFF)); 102 else 103 val = readl(asd_ha->io_handle[0].addr + offs); 104 rmb(); 105 return val; 106 } 107 108 static inline u32 asd_mem_offs_swa(void) 109 { 110 return 0; 111 } 112 113 static inline u32 asd_mem_offs_swc(void) 114 { 115 return asd_mem_offs_swa() + MBAR0_SWA_SIZE; 116 } 117 118 static inline u32 asd_mem_offs_swb(void) 119 { 120 return asd_mem_offs_swc() + MBAR0_SWC_SIZE + 0x20; 121 } 122 123 /* We know that the register wanted is in the range 124 * of the sliding window. 125 */ 126 #define ASD_READ_SW(ww, type, ord) \ 127 static type asd_read_##ww##_##ord(struct asd_ha_struct *asd_ha, \ 128 u32 reg) \ 129 { \ 130 struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0]; \ 131 u32 map_offs = (reg - io_handle->ww##_base) + asd_mem_offs_##ww();\ 132 return asd_read_##ord(asd_ha, (unsigned long)map_offs); \ 133 } 134 135 #define ASD_WRITE_SW(ww, type, ord) \ 136 static void asd_write_##ww##_##ord(struct asd_ha_struct *asd_ha, \ 137 u32 reg, type val) \ 138 { \ 139 struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0]; \ 140 u32 map_offs = (reg - io_handle->ww##_base) + asd_mem_offs_##ww();\ 141 asd_write_##ord(asd_ha, (unsigned long)map_offs, val); \ 142 } 143 144 ASD_READ_SW(swa, u8, byte); 145 ASD_READ_SW(swa, u16, word); 146 ASD_READ_SW(swa, u32, dword); 147 148 ASD_READ_SW(swb, u8, byte); 149 ASD_READ_SW(swb, u16, word); 150 ASD_READ_SW(swb, u32, dword); 151 152 ASD_READ_SW(swc, u8, byte); 153 ASD_READ_SW(swc, u16, word); 154 ASD_READ_SW(swc, u32, dword); 155 156 ASD_WRITE_SW(swa, u8, byte); 157 ASD_WRITE_SW(swa, u16, word); 158 ASD_WRITE_SW(swa, u32, dword); 159 160 ASD_WRITE_SW(swb, u8, byte); 161 ASD_WRITE_SW(swb, u16, word); 162 ASD_WRITE_SW(swb, u32, dword); 163 164 ASD_WRITE_SW(swc, u8, byte); 165 ASD_WRITE_SW(swc, u16, word); 166 ASD_WRITE_SW(swc, u32, dword); 167 168 /* 169 * A word about sliding windows: 170 * MBAR0 is divided into sliding windows A, C and B, in that order. 171 * SWA starts at offset 0 of MBAR0, up to 0x57, with size 0x58 bytes. 172 * SWC starts at offset 0x58 of MBAR0, up to 0x60, with size 0x8 bytes. 173 * From 0x60 to 0x7F, we have a copy of PCI config space 0x60-0x7F. 174 * SWB starts at offset 0x80 of MBAR0 and extends to the end of MBAR0. 175 * See asd_init_sw() in aic94xx_hwi.c 176 * 177 * We map the most common registers we'd access of the internal 4GB 178 * host adapter memory space. If a register/internal memory location 179 * is wanted which is not mapped, we slide SWB, by paging it, 180 * see asd_move_swb() in aic94xx_reg.c. 181 */ 182 183 /** 184 * asd_move_swb -- move sliding window B 185 * @asd_ha: pointer to host adapter structure 186 * @reg: register desired to be within range of the new window 187 */ 188 static void asd_move_swb(struct asd_ha_struct *asd_ha, u32 reg) 189 { 190 u32 base = reg & ~(MBAR0_SWB_SIZE-1); 191 pci_write_config_dword(asd_ha->pcidev, PCI_CONF_MBAR0_SWB, base); 192 asd_ha->io_handle[0].swb_base = base; 193 } 194 195 static void __asd_write_reg_byte(struct asd_ha_struct *asd_ha, u32 reg, u8 val) 196 { 197 struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; 198 BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR); 199 if (io_handle->swa_base <= reg 200 && reg < io_handle->swa_base + MBAR0_SWA_SIZE) 201 asd_write_swa_byte (asd_ha, reg,val); 202 else if (io_handle->swb_base <= reg 203 && reg < io_handle->swb_base + MBAR0_SWB_SIZE) 204 asd_write_swb_byte (asd_ha, reg, val); 205 else if (io_handle->swc_base <= reg 206 && reg < io_handle->swc_base + MBAR0_SWC_SIZE) 207 asd_write_swc_byte (asd_ha, reg, val); 208 else { 209 /* Ok, we have to move SWB */ 210 asd_move_swb(asd_ha, reg); 211 asd_write_swb_byte (asd_ha, reg, val); 212 } 213 } 214 215 #define ASD_WRITE_REG(type, ord) \ 216 void asd_write_reg_##ord (struct asd_ha_struct *asd_ha, u32 reg, type val)\ 217 { \ 218 struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; \ 219 unsigned long flags; \ 220 BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR); \ 221 spin_lock_irqsave(&asd_ha->iolock, flags); \ 222 if (io_handle->swa_base <= reg \ 223 && reg < io_handle->swa_base + MBAR0_SWA_SIZE) \ 224 asd_write_swa_##ord (asd_ha, reg,val); \ 225 else if (io_handle->swb_base <= reg \ 226 && reg < io_handle->swb_base + MBAR0_SWB_SIZE) \ 227 asd_write_swb_##ord (asd_ha, reg, val); \ 228 else if (io_handle->swc_base <= reg \ 229 && reg < io_handle->swc_base + MBAR0_SWC_SIZE) \ 230 asd_write_swc_##ord (asd_ha, reg, val); \ 231 else { \ 232 /* Ok, we have to move SWB */ \ 233 asd_move_swb(asd_ha, reg); \ 234 asd_write_swb_##ord (asd_ha, reg, val); \ 235 } \ 236 spin_unlock_irqrestore(&asd_ha->iolock, flags); \ 237 } 238 239 ASD_WRITE_REG(u8, byte); 240 ASD_WRITE_REG(u16,word); 241 ASD_WRITE_REG(u32,dword); 242 243 static u8 __asd_read_reg_byte(struct asd_ha_struct *asd_ha, u32 reg) 244 { 245 struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; 246 u8 val; 247 BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR); 248 if (io_handle->swa_base <= reg 249 && reg < io_handle->swa_base + MBAR0_SWA_SIZE) 250 val = asd_read_swa_byte (asd_ha, reg); 251 else if (io_handle->swb_base <= reg 252 && reg < io_handle->swb_base + MBAR0_SWB_SIZE) 253 val = asd_read_swb_byte (asd_ha, reg); 254 else if (io_handle->swc_base <= reg 255 && reg < io_handle->swc_base + MBAR0_SWC_SIZE) 256 val = asd_read_swc_byte (asd_ha, reg); 257 else { 258 /* Ok, we have to move SWB */ 259 asd_move_swb(asd_ha, reg); 260 val = asd_read_swb_byte (asd_ha, reg); 261 } 262 return val; 263 } 264 265 #define ASD_READ_REG(type, ord) \ 266 type asd_read_reg_##ord (struct asd_ha_struct *asd_ha, u32 reg) \ 267 { \ 268 struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; \ 269 type val; \ 270 unsigned long flags; \ 271 BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR); \ 272 spin_lock_irqsave(&asd_ha->iolock, flags); \ 273 if (io_handle->swa_base <= reg \ 274 && reg < io_handle->swa_base + MBAR0_SWA_SIZE) \ 275 val = asd_read_swa_##ord (asd_ha, reg); \ 276 else if (io_handle->swb_base <= reg \ 277 && reg < io_handle->swb_base + MBAR0_SWB_SIZE) \ 278 val = asd_read_swb_##ord (asd_ha, reg); \ 279 else if (io_handle->swc_base <= reg \ 280 && reg < io_handle->swc_base + MBAR0_SWC_SIZE) \ 281 val = asd_read_swc_##ord (asd_ha, reg); \ 282 else { \ 283 /* Ok, we have to move SWB */ \ 284 asd_move_swb(asd_ha, reg); \ 285 val = asd_read_swb_##ord (asd_ha, reg); \ 286 } \ 287 spin_unlock_irqrestore(&asd_ha->iolock, flags); \ 288 return val; \ 289 } 290 291 ASD_READ_REG(u8, byte); 292 ASD_READ_REG(u16,word); 293 ASD_READ_REG(u32,dword); 294 295 /** 296 * asd_read_reg_string -- read a string of bytes from io space memory 297 * @asd_ha: pointer to host adapter structure 298 * @dst: pointer to a destination buffer where data will be written to 299 * @offs: start offset (register) to read from 300 * @count: number of bytes to read 301 */ 302 void asd_read_reg_string(struct asd_ha_struct *asd_ha, void *dst, 303 u32 offs, int count) 304 { 305 u8 *p = dst; 306 unsigned long flags; 307 308 spin_lock_irqsave(&asd_ha->iolock, flags); 309 for ( ; count > 0; count--, offs++, p++) 310 *p = __asd_read_reg_byte(asd_ha, offs); 311 spin_unlock_irqrestore(&asd_ha->iolock, flags); 312 } 313 314 /** 315 * asd_write_reg_string -- write a string of bytes to io space memory 316 * @asd_ha: pointer to host adapter structure 317 * @src: pointer to source buffer where data will be read from 318 * @offs: start offset (register) to write to 319 * @count: number of bytes to write 320 */ 321 void asd_write_reg_string(struct asd_ha_struct *asd_ha, void *src, 322 u32 offs, int count) 323 { 324 u8 *p = src; 325 unsigned long flags; 326 327 spin_lock_irqsave(&asd_ha->iolock, flags); 328 for ( ; count > 0; count--, offs++, p++) 329 __asd_write_reg_byte(asd_ha, offs, *p); 330 spin_unlock_irqrestore(&asd_ha->iolock, flags); 331 } 332