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