314 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*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 of15 * this function is *offs = val.16 */17static 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 else24 writeb(val, asd_ha->io_handle[0].addr + offs);25 wmb();26}27 28static 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 else35 writew(val, asd_ha->io_handle[0].addr + offs);36 wmb();37}38 39static 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 else46 writel(val, asd_ha->io_handle[0].addr + offs);47 wmb();48}49 50/* Reading from device address space.51 */52static 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].addr57 + (offs & 0xFF));58 else59 val = readb(asd_ha->io_handle[0].addr + offs);60 rmb();61 return val;62}63 64static 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].addr70 + (offs & 0xFF));71 else72 val = readw(asd_ha->io_handle[0].addr + offs);73 rmb();74 return val;75}76 77static 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].addr83 + (offs & 0xFF));84 else85 val = readl(asd_ha->io_handle[0].addr + offs);86 rmb();87 return val;88}89 90static inline u32 asd_mem_offs_swa(void)91{92 return 0;93}94 95static inline u32 asd_mem_offs_swc(void)96{97 return asd_mem_offs_swa() + MBAR0_SWA_SIZE;98}99 100static 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 range106 * of the sliding window.107 */108#define ASD_READ_SW(ww, type, ord) \109static 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) \118static 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 126ASD_READ_SW(swa, u8, byte);127ASD_READ_SW(swa, u16, word);128ASD_READ_SW(swa, u32, dword);129 130ASD_READ_SW(swb, u8, byte);131ASD_READ_SW(swb, u16, word);132ASD_READ_SW(swb, u32, dword);133 134ASD_READ_SW(swc, u8, byte);135ASD_READ_SW(swc, u16, word);136ASD_READ_SW(swc, u32, dword);137 138ASD_WRITE_SW(swa, u8, byte);139ASD_WRITE_SW(swa, u16, word);140ASD_WRITE_SW(swa, u32, dword);141 142ASD_WRITE_SW(swb, u8, byte);143ASD_WRITE_SW(swb, u16, word);144ASD_WRITE_SW(swb, u32, dword);145 146ASD_WRITE_SW(swc, u8, byte);147ASD_WRITE_SW(swc, u16, word);148ASD_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.c158 *159 * We map the most common registers we'd access of the internal 4GB160 * host adapter memory space. If a register/internal memory location161 * 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 B167 * @asd_ha: pointer to host adapter structure168 * @reg: register desired to be within range of the new window169 */170static 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 177static 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 <= reg182 && reg < io_handle->swa_base + MBAR0_SWA_SIZE)183 asd_write_swa_byte (asd_ha, reg,val);184 else if (io_handle->swb_base <= reg185 && reg < io_handle->swb_base + MBAR0_SWB_SIZE)186 asd_write_swb_byte (asd_ha, reg, val);187 else if (io_handle->swc_base <= reg188 && 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) \198void 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 221ASD_WRITE_REG(u8, byte);222ASD_WRITE_REG(u16,word);223ASD_WRITE_REG(u32,dword);224 225static 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 <= reg231 && reg < io_handle->swa_base + MBAR0_SWA_SIZE)232 val = asd_read_swa_byte (asd_ha, reg);233 else if (io_handle->swb_base <= reg234 && reg < io_handle->swb_base + MBAR0_SWB_SIZE)235 val = asd_read_swb_byte (asd_ha, reg);236 else if (io_handle->swc_base <= reg237 && 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) \248type 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 273ASD_READ_REG(u8, byte);274ASD_READ_REG(u16,word);275ASD_READ_REG(u32,dword);276 277/**278 * asd_read_reg_string -- read a string of bytes from io space memory279 * @asd_ha: pointer to host adapter structure280 * @dst: pointer to a destination buffer where data will be written to281 * @offs: start offset (register) to read from282 * @count: number of bytes to read283 */284void 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 memory298 * @asd_ha: pointer to host adapter structure299 * @src: pointer to source buffer where data will be read from300 * @offs: start offset (register) to write to301 * @count: number of bytes to write302 */303void 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}314