aic94xx_reg.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  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. #include <linux/pci.h>
  27. #include "aic94xx_reg.h"
  28. #include "aic94xx.h"
  29. /* Writing to device address space.
  30. * Offset comes before value to remind that the operation of
  31. * this function is *offs = val.
  32. */
  33. static inline void asd_write_byte(struct asd_ha_struct *asd_ha,
  34. unsigned long offs, u8 val)
  35. {
  36. if (unlikely(asd_ha->iospace))
  37. outb(val,
  38. (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF));
  39. else
  40. writeb(val, asd_ha->io_handle[0].addr + offs);
  41. wmb();
  42. }
  43. static inline void asd_write_word(struct asd_ha_struct *asd_ha,
  44. unsigned long offs, u16 val)
  45. {
  46. if (unlikely(asd_ha->iospace))
  47. outw(val,
  48. (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF));
  49. else
  50. writew(val, asd_ha->io_handle[0].addr + offs);
  51. wmb();
  52. }
  53. static inline void asd_write_dword(struct asd_ha_struct *asd_ha,
  54. unsigned long offs, u32 val)
  55. {
  56. if (unlikely(asd_ha->iospace))
  57. outl(val,
  58. (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF));
  59. else
  60. writel(val, asd_ha->io_handle[0].addr + offs);
  61. wmb();
  62. }
  63. /* Reading from device address space.
  64. */
  65. static inline u8 asd_read_byte(struct asd_ha_struct *asd_ha,
  66. unsigned long offs)
  67. {
  68. u8 val;
  69. if (unlikely(asd_ha->iospace))
  70. val = inb((unsigned long) asd_ha->io_handle[0].addr
  71. + (offs & 0xFF));
  72. else
  73. val = readb(asd_ha->io_handle[0].addr + offs);
  74. rmb();
  75. return val;
  76. }
  77. static inline u16 asd_read_word(struct asd_ha_struct *asd_ha,
  78. unsigned long offs)
  79. {
  80. u16 val;
  81. if (unlikely(asd_ha->iospace))
  82. val = inw((unsigned long)asd_ha->io_handle[0].addr
  83. + (offs & 0xFF));
  84. else
  85. val = readw(asd_ha->io_handle[0].addr + offs);
  86. rmb();
  87. return val;
  88. }
  89. static inline u32 asd_read_dword(struct asd_ha_struct *asd_ha,
  90. unsigned long offs)
  91. {
  92. u32 val;
  93. if (unlikely(asd_ha->iospace))
  94. val = inl((unsigned long) asd_ha->io_handle[0].addr
  95. + (offs & 0xFF));
  96. else
  97. val = readl(asd_ha->io_handle[0].addr + offs);
  98. rmb();
  99. return val;
  100. }
  101. static inline u32 asd_mem_offs_swa(void)
  102. {
  103. return 0;
  104. }
  105. static inline u32 asd_mem_offs_swc(void)
  106. {
  107. return asd_mem_offs_swa() + MBAR0_SWA_SIZE;
  108. }
  109. static inline u32 asd_mem_offs_swb(void)
  110. {
  111. return asd_mem_offs_swc() + MBAR0_SWC_SIZE + 0x20;
  112. }
  113. /* We know that the register wanted is in the range
  114. * of the sliding window.
  115. */
  116. #define ASD_READ_SW(ww, type, ord) \
  117. static inline type asd_read_##ww##_##ord (struct asd_ha_struct *asd_ha,\
  118. u32 reg) \
  119. { \
  120. struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0]; \
  121. u32 map_offs=(reg - io_handle-> ww##_base )+asd_mem_offs_##ww ();\
  122. return asd_read_##ord (asd_ha, (unsigned long) map_offs); \
  123. }
  124. #define ASD_WRITE_SW(ww, type, ord) \
  125. static inline void asd_write_##ww##_##ord (struct asd_ha_struct *asd_ha,\
  126. u32 reg, type val) \
  127. { \
  128. struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0]; \
  129. u32 map_offs=(reg - io_handle-> ww##_base )+asd_mem_offs_##ww ();\
  130. asd_write_##ord (asd_ha, (unsigned long) map_offs, val); \
  131. }
  132. ASD_READ_SW(swa, u8, byte);
  133. ASD_READ_SW(swa, u16, word);
  134. ASD_READ_SW(swa, u32, dword);
  135. ASD_READ_SW(swb, u8, byte);
  136. ASD_READ_SW(swb, u16, word);
  137. ASD_READ_SW(swb, u32, dword);
  138. ASD_READ_SW(swc, u8, byte);
  139. ASD_READ_SW(swc, u16, word);
  140. ASD_READ_SW(swc, u32, dword);
  141. ASD_WRITE_SW(swa, u8, byte);
  142. ASD_WRITE_SW(swa, u16, word);
  143. ASD_WRITE_SW(swa, u32, dword);
  144. ASD_WRITE_SW(swb, u8, byte);
  145. ASD_WRITE_SW(swb, u16, word);
  146. ASD_WRITE_SW(swb, u32, dword);
  147. ASD_WRITE_SW(swc, u8, byte);
  148. ASD_WRITE_SW(swc, u16, word);
  149. ASD_WRITE_SW(swc, u32, dword);
  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. * asd_move_swb -- move sliding window B
  166. * @asd_ha: pointer to host adapter structure
  167. * @reg: register desired to be within range of the new window
  168. */
  169. static inline void asd_move_swb(struct asd_ha_struct *asd_ha, u32 reg)
  170. {
  171. u32 base = reg & ~(MBAR0_SWB_SIZE-1);
  172. pci_write_config_dword(asd_ha->pcidev, PCI_CONF_MBAR0_SWB, base);
  173. asd_ha->io_handle[0].swb_base = base;
  174. }
  175. static void __asd_write_reg_byte(struct asd_ha_struct *asd_ha, u32 reg, u8 val)
  176. {
  177. struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0];
  178. BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);
  179. if (io_handle->swa_base <= reg
  180. && reg < io_handle->swa_base + MBAR0_SWA_SIZE)
  181. asd_write_swa_byte (asd_ha, reg,val);
  182. else if (io_handle->swb_base <= reg
  183. && reg < io_handle->swb_base + MBAR0_SWB_SIZE)
  184. asd_write_swb_byte (asd_ha, reg, val);
  185. else if (io_handle->swc_base <= reg
  186. && reg < io_handle->swc_base + MBAR0_SWC_SIZE)
  187. asd_write_swc_byte (asd_ha, reg, val);
  188. else {
  189. /* Ok, we have to move SWB */
  190. asd_move_swb(asd_ha, reg);
  191. asd_write_swb_byte (asd_ha, reg, val);
  192. }
  193. }
  194. #define ASD_WRITE_REG(type, ord) \
  195. void asd_write_reg_##ord (struct asd_ha_struct *asd_ha, u32 reg, type val)\
  196. { \
  197. struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; \
  198. unsigned long flags; \
  199. BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR); \
  200. spin_lock_irqsave(&asd_ha->iolock, flags); \
  201. if (io_handle->swa_base <= reg \
  202. && reg < io_handle->swa_base + MBAR0_SWA_SIZE) \
  203. asd_write_swa_##ord (asd_ha, reg,val); \
  204. else if (io_handle->swb_base <= reg \
  205. && reg < io_handle->swb_base + MBAR0_SWB_SIZE) \
  206. asd_write_swb_##ord (asd_ha, reg, val); \
  207. else if (io_handle->swc_base <= reg \
  208. && reg < io_handle->swc_base + MBAR0_SWC_SIZE) \
  209. asd_write_swc_##ord (asd_ha, reg, val); \
  210. else { \
  211. /* Ok, we have to move SWB */ \
  212. asd_move_swb(asd_ha, reg); \
  213. asd_write_swb_##ord (asd_ha, reg, val); \
  214. } \
  215. spin_unlock_irqrestore(&asd_ha->iolock, flags); \
  216. }
  217. ASD_WRITE_REG(u8, byte);
  218. ASD_WRITE_REG(u16,word);
  219. ASD_WRITE_REG(u32,dword);
  220. static u8 __asd_read_reg_byte(struct asd_ha_struct *asd_ha, u32 reg)
  221. {
  222. struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0];
  223. u8 val;
  224. BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);
  225. if (io_handle->swa_base <= reg
  226. && reg < io_handle->swa_base + MBAR0_SWA_SIZE)
  227. val = asd_read_swa_byte (asd_ha, reg);
  228. else if (io_handle->swb_base <= reg
  229. && reg < io_handle->swb_base + MBAR0_SWB_SIZE)
  230. val = asd_read_swb_byte (asd_ha, reg);
  231. else if (io_handle->swc_base <= reg
  232. && reg < io_handle->swc_base + MBAR0_SWC_SIZE)
  233. val = asd_read_swc_byte (asd_ha, reg);
  234. else {
  235. /* Ok, we have to move SWB */
  236. asd_move_swb(asd_ha, reg);
  237. val = asd_read_swb_byte (asd_ha, reg);
  238. }
  239. return val;
  240. }
  241. #define ASD_READ_REG(type, ord) \
  242. type asd_read_reg_##ord (struct asd_ha_struct *asd_ha, u32 reg) \
  243. { \
  244. struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; \
  245. type val; \
  246. unsigned long flags; \
  247. BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR); \
  248. spin_lock_irqsave(&asd_ha->iolock, flags); \
  249. if (io_handle->swa_base <= reg \
  250. && reg < io_handle->swa_base + MBAR0_SWA_SIZE) \
  251. val = asd_read_swa_##ord (asd_ha, reg); \
  252. else if (io_handle->swb_base <= reg \
  253. && reg < io_handle->swb_base + MBAR0_SWB_SIZE) \
  254. val = asd_read_swb_##ord (asd_ha, reg); \
  255. else if (io_handle->swc_base <= reg \
  256. && reg < io_handle->swc_base + MBAR0_SWC_SIZE) \
  257. val = asd_read_swc_##ord (asd_ha, reg); \
  258. else { \
  259. /* Ok, we have to move SWB */ \
  260. asd_move_swb(asd_ha, reg); \
  261. val = asd_read_swb_##ord (asd_ha, reg); \
  262. } \
  263. spin_unlock_irqrestore(&asd_ha->iolock, flags); \
  264. return val; \
  265. }
  266. ASD_READ_REG(u8, byte);
  267. ASD_READ_REG(u16,word);
  268. ASD_READ_REG(u32,dword);
  269. /**
  270. * asd_read_reg_string -- read a string of bytes from io space memory
  271. * @asd_ha: pointer to host adapter structure
  272. * @dst: pointer to a destination buffer where data will be written to
  273. * @offs: start offset (register) to read from
  274. * @count: number of bytes to read
  275. */
  276. void asd_read_reg_string(struct asd_ha_struct *asd_ha, void *dst,
  277. u32 offs, int count)
  278. {
  279. u8 *p = dst;
  280. unsigned long flags;
  281. spin_lock_irqsave(&asd_ha->iolock, flags);
  282. for ( ; count > 0; count--, offs++, p++)
  283. *p = __asd_read_reg_byte(asd_ha, offs);
  284. spin_unlock_irqrestore(&asd_ha->iolock, flags);
  285. }
  286. /**
  287. * asd_write_reg_string -- write a string of bytes to io space memory
  288. * @asd_ha: pointer to host adapter structure
  289. * @src: pointer to source buffer where data will be read from
  290. * @offs: start offset (register) to write to
  291. * @count: number of bytes to write
  292. */
  293. void asd_write_reg_string(struct asd_ha_struct *asd_ha, void *src,
  294. u32 offs, int count)
  295. {
  296. u8 *p = src;
  297. unsigned long flags;
  298. spin_lock_irqsave(&asd_ha->iolock, flags);
  299. for ( ; count > 0; count--, offs++, p++)
  300. __asd_write_reg_byte(asd_ha, offs, *p);
  301. spin_unlock_irqrestore(&asd_ha->iolock, flags);
  302. }