brintos

brintos / linux-shallow public Read only

0
0
Text · 9.9 KiB · 392499e Raw
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