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 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 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 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 u8 asd_read_byte(struct asd_ha_struct *asd_ha, unsigned long offs)
  66. {
  67. u8 val;
  68. if (unlikely(asd_ha->iospace))
  69. val = inb((unsigned long) asd_ha->io_handle[0].addr
  70. + (offs & 0xFF));
  71. else
  72. val = readb(asd_ha->io_handle[0].addr + offs);
  73. rmb();
  74. return val;
  75. }
  76. static u16 asd_read_word(struct asd_ha_struct *asd_ha,
  77. unsigned long offs)
  78. {
  79. u16 val;
  80. if (unlikely(asd_ha->iospace))
  81. val = inw((unsigned long)asd_ha->io_handle[0].addr
  82. + (offs & 0xFF));
  83. else
  84. val = readw(asd_ha->io_handle[0].addr + offs);
  85. rmb();
  86. return val;
  87. }
  88. static u32 asd_read_dword(struct asd_ha_struct *asd_ha,
  89. unsigned long offs)
  90. {
  91. u32 val;
  92. if (unlikely(asd_ha->iospace))
  93. val = inl((unsigned long) asd_ha->io_handle[0].addr
  94. + (offs & 0xFF));
  95. else
  96. val = readl(asd_ha->io_handle[0].addr + offs);
  97. rmb();
  98. return val;
  99. }
  100. static inline u32 asd_mem_offs_swa(void)
  101. {
  102. return 0;
  103. }
  104. static inline u32 asd_mem_offs_swc(void)
  105. {
  106. return asd_mem_offs_swa() + MBAR0_SWA_SIZE;
  107. }
  108. static inline u32 asd_mem_offs_swb(void)
  109. {
  110. return asd_mem_offs_swc() + MBAR0_SWC_SIZE + 0x20;
  111. }
  112. /* We know that the register wanted is in the range
  113. * of the sliding window.
  114. */
  115. #define ASD_READ_SW(ww, type, ord) \
  116. static type asd_read_##ww##_##ord(struct asd_ha_struct *asd_ha, \
  117. u32 reg) \
  118. { \
  119. struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0]; \
  120. u32 map_offs = (reg - io_handle->ww##_base) + asd_mem_offs_##ww();\
  121. return asd_read_##ord(asd_ha, (unsigned long)map_offs); \
  122. }
  123. #define ASD_WRITE_SW(ww, type, ord) \
  124. static void asd_write_##ww##_##ord(struct asd_ha_struct *asd_ha, \
  125. u32 reg, type val) \
  126. { \
  127. struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0]; \
  128. u32 map_offs = (reg - io_handle->ww##_base) + asd_mem_offs_##ww();\
  129. asd_write_##ord(asd_ha, (unsigned long)map_offs, val); \
  130. }
  131. ASD_READ_SW(swa, u8, byte);
  132. ASD_READ_SW(swa, u16, word);
  133. ASD_READ_SW(swa, u32, dword);
  134. ASD_READ_SW(swb, u8, byte);
  135. ASD_READ_SW(swb, u16, word);
  136. ASD_READ_SW(swb, u32, dword);
  137. ASD_READ_SW(swc, u8, byte);
  138. ASD_READ_SW(swc, u16, word);
  139. ASD_READ_SW(swc, u32, dword);
  140. ASD_WRITE_SW(swa, u8, byte);
  141. ASD_WRITE_SW(swa, u16, word);
  142. ASD_WRITE_SW(swa, u32, dword);
  143. ASD_WRITE_SW(swb, u8, byte);
  144. ASD_WRITE_SW(swb, u16, word);
  145. ASD_WRITE_SW(swb, u32, dword);
  146. ASD_WRITE_SW(swc, u8, byte);
  147. ASD_WRITE_SW(swc, u16, word);
  148. ASD_WRITE_SW(swc, u32, dword);
  149. /*
  150. * A word about sliding windows:
  151. * MBAR0 is divided into sliding windows A, C and B, in that order.
  152. * SWA starts at offset 0 of MBAR0, up to 0x57, with size 0x58 bytes.
  153. * SWC starts at offset 0x58 of MBAR0, up to 0x60, with size 0x8 bytes.
  154. * From 0x60 to 0x7F, we have a copy of PCI config space 0x60-0x7F.
  155. * SWB starts at offset 0x80 of MBAR0 and extends to the end of MBAR0.
  156. * See asd_init_sw() in aic94xx_hwi.c
  157. *
  158. * We map the most common registers we'd access of the internal 4GB
  159. * host adapter memory space. If a register/internal memory location
  160. * is wanted which is not mapped, we slide SWB, by paging it,
  161. * see asd_move_swb() in aic94xx_reg.c.
  162. */
  163. /**
  164. * asd_move_swb -- move sliding window B
  165. * @asd_ha: pointer to host adapter structure
  166. * @reg: register desired to be within range of the new window
  167. */
  168. static void asd_move_swb(struct asd_ha_struct *asd_ha, u32 reg)
  169. {
  170. u32 base = reg & ~(MBAR0_SWB_SIZE-1);
  171. pci_write_config_dword(asd_ha->pcidev, PCI_CONF_MBAR0_SWB, base);
  172. asd_ha->io_handle[0].swb_base = base;
  173. }
  174. static void __asd_write_reg_byte(struct asd_ha_struct *asd_ha, u32 reg, u8 val)
  175. {
  176. struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0];
  177. BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);
  178. if (io_handle->swa_base <= reg
  179. && reg < io_handle->swa_base + MBAR0_SWA_SIZE)
  180. asd_write_swa_byte (asd_ha, reg,val);
  181. else if (io_handle->swb_base <= reg
  182. && reg < io_handle->swb_base + MBAR0_SWB_SIZE)
  183. asd_write_swb_byte (asd_ha, reg, val);
  184. else if (io_handle->swc_base <= reg
  185. && reg < io_handle->swc_base + MBAR0_SWC_SIZE)
  186. asd_write_swc_byte (asd_ha, reg, val);
  187. else {
  188. /* Ok, we have to move SWB */
  189. asd_move_swb(asd_ha, reg);
  190. asd_write_swb_byte (asd_ha, reg, val);
  191. }
  192. }
  193. #define ASD_WRITE_REG(type, ord) \
  194. void asd_write_reg_##ord (struct asd_ha_struct *asd_ha, u32 reg, type val)\
  195. { \
  196. struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; \
  197. unsigned long flags; \
  198. BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR); \
  199. spin_lock_irqsave(&asd_ha->iolock, flags); \
  200. if (io_handle->swa_base <= reg \
  201. && reg < io_handle->swa_base + MBAR0_SWA_SIZE) \
  202. asd_write_swa_##ord (asd_ha, reg,val); \
  203. else if (io_handle->swb_base <= reg \
  204. && reg < io_handle->swb_base + MBAR0_SWB_SIZE) \
  205. asd_write_swb_##ord (asd_ha, reg, val); \
  206. else if (io_handle->swc_base <= reg \
  207. && reg < io_handle->swc_base + MBAR0_SWC_SIZE) \
  208. asd_write_swc_##ord (asd_ha, reg, val); \
  209. else { \
  210. /* Ok, we have to move SWB */ \
  211. asd_move_swb(asd_ha, reg); \
  212. asd_write_swb_##ord (asd_ha, reg, val); \
  213. } \
  214. spin_unlock_irqrestore(&asd_ha->iolock, flags); \
  215. }
  216. ASD_WRITE_REG(u8, byte);
  217. ASD_WRITE_REG(u16,word);
  218. ASD_WRITE_REG(u32,dword);
  219. static u8 __asd_read_reg_byte(struct asd_ha_struct *asd_ha, u32 reg)
  220. {
  221. struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0];
  222. u8 val;
  223. BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);
  224. if (io_handle->swa_base <= reg
  225. && reg < io_handle->swa_base + MBAR0_SWA_SIZE)
  226. val = asd_read_swa_byte (asd_ha, reg);
  227. else if (io_handle->swb_base <= reg
  228. && reg < io_handle->swb_base + MBAR0_SWB_SIZE)
  229. val = asd_read_swb_byte (asd_ha, reg);
  230. else if (io_handle->swc_base <= reg
  231. && reg < io_handle->swc_base + MBAR0_SWC_SIZE)
  232. val = asd_read_swc_byte (asd_ha, reg);
  233. else {
  234. /* Ok, we have to move SWB */
  235. asd_move_swb(asd_ha, reg);
  236. val = asd_read_swb_byte (asd_ha, reg);
  237. }
  238. return val;
  239. }
  240. #define ASD_READ_REG(type, ord) \
  241. type asd_read_reg_##ord (struct asd_ha_struct *asd_ha, u32 reg) \
  242. { \
  243. struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; \
  244. type val; \
  245. unsigned long flags; \
  246. BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR); \
  247. spin_lock_irqsave(&asd_ha->iolock, flags); \
  248. if (io_handle->swa_base <= reg \
  249. && reg < io_handle->swa_base + MBAR0_SWA_SIZE) \
  250. val = asd_read_swa_##ord (asd_ha, reg); \
  251. else if (io_handle->swb_base <= reg \
  252. && reg < io_handle->swb_base + MBAR0_SWB_SIZE) \
  253. val = asd_read_swb_##ord (asd_ha, reg); \
  254. else if (io_handle->swc_base <= reg \
  255. && reg < io_handle->swc_base + MBAR0_SWC_SIZE) \
  256. val = asd_read_swc_##ord (asd_ha, reg); \
  257. else { \
  258. /* Ok, we have to move SWB */ \
  259. asd_move_swb(asd_ha, reg); \
  260. val = asd_read_swb_##ord (asd_ha, reg); \
  261. } \
  262. spin_unlock_irqrestore(&asd_ha->iolock, flags); \
  263. return val; \
  264. }
  265. ASD_READ_REG(u8, byte);
  266. ASD_READ_REG(u16,word);
  267. ASD_READ_REG(u32,dword);
  268. /**
  269. * asd_read_reg_string -- read a string of bytes from io space memory
  270. * @asd_ha: pointer to host adapter structure
  271. * @dst: pointer to a destination buffer where data will be written to
  272. * @offs: start offset (register) to read from
  273. * @count: number of bytes to read
  274. */
  275. void asd_read_reg_string(struct asd_ha_struct *asd_ha, void *dst,
  276. u32 offs, int count)
  277. {
  278. u8 *p = dst;
  279. unsigned long flags;
  280. spin_lock_irqsave(&asd_ha->iolock, flags);
  281. for ( ; count > 0; count--, offs++, p++)
  282. *p = __asd_read_reg_byte(asd_ha, offs);
  283. spin_unlock_irqrestore(&asd_ha->iolock, flags);
  284. }
  285. /**
  286. * asd_write_reg_string -- write a string of bytes to io space memory
  287. * @asd_ha: pointer to host adapter structure
  288. * @src: pointer to source buffer where data will be read from
  289. * @offs: start offset (register) to write to
  290. * @count: number of bytes to write
  291. */
  292. void asd_write_reg_string(struct asd_ha_struct *asd_ha, void *src,
  293. u32 offs, int count)
  294. {
  295. u8 *p = src;
  296. unsigned long flags;
  297. spin_lock_irqsave(&asd_ha->iolock, flags);
  298. for ( ; count > 0; count--, offs++, p++)
  299. __asd_write_reg_byte(asd_ha, offs, *p);
  300. spin_unlock_irqrestore(&asd_ha->iolock, flags);
  301. }