linux/drivers/scsi/aic94xx/aic94xx_reg.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   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>
   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 */
  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        else
  24                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        else
  35                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        else
  46                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].addr
  57                          + (offs & 0xFF));
  58        else
  59                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].addr
  70                          + (offs & 0xFF));
  71        else
  72                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].addr
  83                          + (offs & 0xFF));
  84        else
  85                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 range
 106 * 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.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 */
 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 <= 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)                                  \
 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 <= 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)                                   \
 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 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 */
 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 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 */
 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