Linux驱动——sdio type card(八)

朴灿烈づ我的快乐病毒、 2022-09-16 15:29 763阅读 0赞

Linux驱动——sdio type card(八)

备注:
  1. Kernel版本:5.4
  2. 使用工具:Source Insight 4.0

文章目录

  • Linux驱动——sdio type card(八)
    • 概述
    • 数据结构
      • mmc_sdio_ops
    • 核心接口说明
      • sdio type card匹配相关
        • mmc_attach_sdio
        • mmc_sdio_init_card
      • sdio ops相关函数
        • mmc_send_io_op_cond
        • mmc_io_rw_direct
        • mmc_io_rw_extended
        • sdio_reset
      • sdio irq相关函数
        • 注册sdio_irq——sdio_claim_irq
        • 释放sdio_irq——sdio_release_irq
        • 创建sdio_irq_thread——sdio_card_irq_get
        • 实现sdio_irq_thread——sdio_irq_thread
      • sdio io相关函数
        • host相关
        • sdio func相关
        • 块配置相关
        • IO读写相关

概述

  card相关模块为对应card实现相应的操作,包括初始化操作、以及对应的总线操作集合。负责和对应card协议层相关的东西。
sdio type card相关代码:

  1. drivers/mmc/core/sdio.c(提供接口)
  2. drivers/mmc/core/sdio_ops.c(提供和sdio type card协议相关的操作)
  3. drivers/mmc/core/sdio_irq.c(提供sdio irq相关功能的操作)
  4. drivers/mmc/core/sdio_cis.c(提供sdio cis相关功能的操作)
  5. drivers/mmc/core/sdio_ops.h

数据结构

mmc_sdio_ops

  1. static const struct mmc_bus_ops mmc_sdio_ops = {
  2. .remove = mmc_sdio_remove,
  3. .detect = mmc_sdio_detect,
  4. .pre_suspend = mmc_sdio_pre_suspend,
  5. .suspend = mmc_sdio_suspend,
  6. .resume = mmc_sdio_resume,
  7. .runtime_suspend = mmc_sdio_runtime_suspend,
  8. .runtime_resume = mmc_sdio_runtime_resume,
  9. .alive = mmc_sdio_alive,
  10. .hw_reset = mmc_sdio_hw_reset,
  11. .sw_reset = mmc_sdio_sw_reset,
  12. };

核心接口说明

sdio type card匹配相关

mmc_attach_sdio

  1. /*
  2. * Starting point for SDIO card init.
  3. */
  4. int mmc_attach_sdio(struct mmc_host *host)
  5. {
  6. int err, i, funcs;
  7. u32 ocr, rocr;
  8. struct mmc_card *card;
  9. WARN_ON(!host->claimed);
  10. /*
  11. *
  12. * 以下部分,连同mmc_rescan_try_freq中的
  13. * mmc_go_idle和mmc_send_if_cond一起构成了
  14. * “尝试获取一个合适的工作电压” 的任务
  15. */
  16. // host发送参数为0的ACMD41命令,提取response中的VHS,
  17. // 得到card支持的工作电压范围
  18. err = mmc_send_io_op_cond(host, 0, &ocr);
  19. if (err)
  20. return err;
  21. //创建sd_ops,host->bus_ops指向mmc_sdio_ops
  22. mmc_attach_bus(host, &mmc_sdio_ops);
  23. if (host->ocr_avail_sdio)
  24. host->ocr_avail = host->ocr_avail_sdio;
  25. // host选择一个card和host都支持的最低的工作电压,
  26. // 并将host提供给card的工作电压设置为这个值。
  27. // 后续就以host->ocr作为工作电压对sd card进行初始化
  28. rocr = mmc_select_voltage(host, ocr);
  29. /*
  30. * Can we support the voltage(s) of the card(s)?
  31. */
  32. if (!rocr) {
  33. err = -EINVAL;
  34. goto err;
  35. }
  36. /*
  37. * Detect and init the card.
  38. */
  39. /** 上述已经完成了card的识别操作,并且为card选择了一个合适的工作电压 **/
  40. /** 后续调用mmc_sdio_init_card对sdio card进行初始化,也就是代码核心 **/
  41. err = mmc_sdio_init_card(host, rocr, NULL);
  42. if (err)
  43. goto err;
  44. card = host->card;
  45. /*
  46. * Enable runtime PM only if supported by host+card+board
  47. */
  48. if (host->caps & MMC_CAP_POWER_OFF_CARD) {
  49. /*
  50. * Do not allow runtime suspend until after SDIO function
  51. * devices are added.
  52. */
  53. pm_runtime_get_noresume(&card->dev);
  54. /*
  55. * Let runtime PM core know our card is active
  56. */
  57. err = pm_runtime_set_active(&card->dev);
  58. if (err)
  59. goto remove;
  60. /*
  61. * Enable runtime PM for this card
  62. */
  63. pm_runtime_enable(&card->dev);
  64. }
  65. /*
  66. * The number of functions on the card is encoded inside
  67. * the ocr.
  68. */
  69. // 根据ocr寄存器获取func数目
  70. funcs = (ocr & 0x70000000) >> 28;
  71. card->sdio_funcs = 0;
  72. /*
  73. * Initialize (but don't add) all present functions.
  74. */
  75. // 初始化sdio_func
  76. for (i = 0; i < funcs; i++, card->sdio_funcs++) {
  77. err = sdio_init_func(host->card, i + 1);
  78. if (err)
  79. goto remove;
  80. /*
  81. * Enable Runtime PM for this func (if supported)
  82. */
  83. if (host->caps & MMC_CAP_POWER_OFF_CARD)
  84. pm_runtime_enable(&card->sdio_func[i]->dev);
  85. }
  86. /*
  87. * First add the card to the driver model...
  88. */
  89. mmc_release_host(host);
  90. // 将sd card添加到device中
  91. err = mmc_add_card(host->card);
  92. if (err)
  93. goto remove_added;
  94. /*
  95. * ...then the SDIO functions.
  96. */
  97. //注册 sdio_func 到driver中
  98. for (i = 0;i < funcs;i++) {
  99. err = sdio_add_func(host->card->sdio_func[i]);
  100. if (err)
  101. goto remove_added;
  102. }
  103. if (host->caps & MMC_CAP_POWER_OFF_CARD)
  104. pm_runtime_put(&card->dev);
  105. mmc_claim_host(host);
  106. return 0;
  107. remove:
  108. mmc_release_host(host);
  109. remove_added:
  110. /*
  111. * The devices are being deleted so it is not necessary to disable
  112. * runtime PM. Similarly we also don't pm_runtime_put() the SDIO card
  113. * because it needs to be active to remove any function devices that
  114. * were probed, and after that it gets deleted.
  115. */
  116. mmc_sdio_remove(host);
  117. mmc_claim_host(host);
  118. err:
  119. mmc_detach_bus(host);
  120. pr_err("%s: error %d whilst initialising SDIO card\n",
  121. mmc_hostname(host), err);
  122. return err;
  123. }

mmc_sdio_init_card

  1. /*
  2. * Handle the detection and initialisation of a card.
  3. *
  4. * In the case of a resume, "oldcard" will contain the card
  5. * we're trying to reinitialise.
  6. */
  7. static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
  8. struct mmc_card *oldcard)
  9. {
  10. struct mmc_card *card;
  11. int err;
  12. int retries = 10;
  13. u32 rocr = 0;
  14. u32 ocr_card = ocr;
  15. WARN_ON(!host->claimed);
  16. /* to query card if 1.8V signalling is supported */
  17. if (mmc_host_uhs(host))
  18. ocr |= R4_18V_PRESENT;
  19. try_again:
  20. /** 在mmc_sd_get_cid中完成如下工作::: **/
  21. /** 重新复位,完成card的内部初始化 **/
  22. /** 设置信号电压,包括card和host的设置 **/
  23. /** 获取card的CID值 **/
  24. // 调用mmc_sd_get_cid进行复位、内部初始化,
  25. // 设置信号电压,然后获取CID值,
  26. // 最终card进入了identification state。
  27. if (!retries) {
  28. pr_warn("%s: Skipping voltage switch\n", mmc_hostname(host));
  29. ocr &= ~R4_18V_PRESENT;
  30. }
  31. /*
  32. * Inform the card of the voltage
  33. */
  34. err = mmc_send_io_op_cond(host, ocr, &rocr);
  35. if (err)
  36. return err;
  37. /*
  38. * For SPI, enable CRC as appropriate.
  39. */
  40. if (mmc_host_is_spi(host)) {
  41. err = mmc_spi_set_crc(host, use_spi_crc);
  42. if (err)
  43. return err;
  44. }
  45. /*
  46. * Allocate card structure.
  47. */
  48. card = mmc_alloc_card(host, NULL);
  49. if (IS_ERR(card))
  50. return PTR_ERR(card);
  51. if ((rocr & R4_MEMORY_PRESENT) &&
  52. mmc_sd_get_cid(host, ocr & rocr, card->raw_cid, NULL) == 0) {
  53. card->type = MMC_TYPE_SD_COMBO;
  54. if (oldcard && (oldcard->type != MMC_TYPE_SD_COMBO ||
  55. memcmp(card->raw_cid, oldcard->raw_cid, sizeof(card->raw_cid)) != 0)) {
  56. err = -ENOENT;
  57. goto mismatch;
  58. }
  59. } else {
  60. card->type = MMC_TYPE_SDIO;
  61. if (oldcard && oldcard->type != MMC_TYPE_SDIO) {
  62. err = -ENOENT;
  63. goto mismatch;
  64. }
  65. }
  66. /*
  67. * Call the optional HC's init_card function to handle quirks.
  68. */
  69. if (host->ops->init_card)
  70. host->ops->init_card(host, card);
  71. /*
  72. * If the host and card support UHS-I mode request the card
  73. * to switch to 1.8V signaling level. No 1.8v signalling if
  74. * UHS mode is not enabled to maintain compatibility and some
  75. * systems that claim 1.8v signalling in fact do not support
  76. * it. Per SDIO spec v3, section 3.1.2, if the voltage is already
  77. * 1.8v, the card sets S18A to 0 in the R4 response. So it will
  78. * fails to check rocr & R4_18V_PRESENT, but we still need to
  79. * try to init uhs card. sdio_read_cccr will take over this task
  80. * to make sure which speed mode should work.
  81. */
  82. if (rocr & ocr & R4_18V_PRESENT) {
  83. err = mmc_set_uhs_voltage(host, ocr_card);
  84. if (err == -EAGAIN) {
  85. mmc_sdio_resend_if_cond(host, card);
  86. retries--;
  87. goto try_again;
  88. } else if (err) {
  89. ocr &= ~R4_18V_PRESENT;
  90. }
  91. }
  92. /*
  93. * For native busses: set card RCA and quit open drain mode.
  94. */
  95. if (!mmc_host_is_spi(host)) {
  96. err = mmc_send_relative_addr(host, &card->rca);
  97. if (err)
  98. goto remove;
  99. /*
  100. * Update oldcard with the new RCA received from the SDIO
  101. * device -- we're doing this so that it's updated in the
  102. * "card" struct when oldcard overwrites that later.
  103. */
  104. if (oldcard)
  105. oldcard->rca = card->rca;
  106. }
  107. /*
  108. * Read CSD, before selecting the card
  109. */
  110. if (!oldcard && card->type == MMC_TYPE_SD_COMBO) {
  111. err = mmc_sd_get_csd(host, card);
  112. if (err)
  113. goto remove;
  114. mmc_decode_cid(card);
  115. }
  116. /*
  117. * Select card, as all following commands rely on that.
  118. */
  119. if (!mmc_host_is_spi(host)) {
  120. err = mmc_select_card(card);
  121. if (err)
  122. goto remove;
  123. }
  124. if (card->quirks & MMC_QUIRK_NONSTD_SDIO) {
  125. /*
  126. * This is non-standard SDIO device, meaning it doesn't
  127. * have any CIA (Common I/O area) registers present.
  128. * It's host's responsibility to fill cccr and cis
  129. * structures in init_card().
  130. */
  131. mmc_set_clock(host, card->cis.max_dtr);
  132. if (card->cccr.high_speed) {
  133. mmc_set_timing(card->host, MMC_TIMING_SD_HS);
  134. }
  135. if (oldcard)
  136. mmc_remove_card(card);
  137. else
  138. host->card = card;
  139. return 0;
  140. }
  141. /*
  142. * Read the common registers. Note that we should try to
  143. * validate whether UHS would work or not.
  144. */
  145. err = sdio_read_cccr(card, ocr);
  146. if (err) {
  147. mmc_sdio_resend_if_cond(host, card);
  148. if (ocr & R4_18V_PRESENT) {
  149. /* Retry init sequence, but without R4_18V_PRESENT. */
  150. retries = 0;
  151. goto try_again;
  152. }
  153. return err;
  154. }
  155. /*
  156. * Read the common CIS tuples.
  157. */
  158. // 获取card CIS 值
  159. err = sdio_read_common_cis(card);
  160. if (err)
  161. goto remove;
  162. if (oldcard) {
  163. if (card->cis.vendor == oldcard->cis.vendor &&
  164. card->cis.device == oldcard->cis.device) {
  165. mmc_remove_card(card);
  166. card = oldcard;
  167. } else {
  168. err = -ENOENT;
  169. goto mismatch;
  170. }
  171. }
  172. card->ocr = ocr_card;
  173. mmc_fixup_device(card, sdio_fixup_methods);
  174. /** 获取sd card的配置寄存器和状态寄存器 **/
  175. /** 读取card 的switch状态,也就是其支持的function **/
  176. // host发送ACMD51命令,要求card回复其SCR寄存器(SD configuration register)的值
  177. // host发送ACMD13命令,要求card回复其SSR寄存器(SD status regiter)的值
  178. // host发送CMD6命令来读取card switch status。
  179. // 通过card switch status可以得到card支持的总线速度模式以及驱动强度类型。
  180. if (card->type == MMC_TYPE_SD_COMBO) {
  181. err = mmc_sd_setup_card(host, card, oldcard != NULL);
  182. /* handle as SDIO-only card if memory init failed */
  183. if (err) {
  184. mmc_go_idle(host);
  185. if (mmc_host_is_spi(host))
  186. /* should not fail, as it worked previously */
  187. mmc_spi_set_crc(host, use_spi_crc);
  188. card->type = MMC_TYPE_SDIO;
  189. } else
  190. card->dev.type = &sd_type;
  191. }
  192. /*
  193. * If needed, disconnect card detection pull-up resistor.
  194. */
  195. // 关闭 card detection 功能
  196. err = sdio_disable_cd(card);
  197. if (err)
  198. goto remove;
  199. /* Initialization sequence for UHS-I cards */
  200. /* Only if card supports 1.8v and UHS signaling */
  201. // 切换到sdio highspeed 模式、配置时钟速率、配置数据总线宽度
  202. if ((ocr & R4_18V_PRESENT) && card->sw_caps.sd3_bus_mode) {
  203. err = mmc_sdio_init_uhs_card(card);
  204. if (err)
  205. goto remove;
  206. } else {
  207. /*
  208. * Switch to high-speed (if supported).
  209. */
  210. err = sdio_enable_hs(card);
  211. if (err > 0)
  212. mmc_set_timing(card->host, MMC_TIMING_SD_HS);
  213. else if (err)
  214. goto remove;
  215. /*
  216. * Change to the card's maximum speed.
  217. */
  218. mmc_set_clock(host, mmc_sdio_get_max_clock(card));
  219. /*
  220. * Switch to wider bus (if supported).
  221. */
  222. err = sdio_enable_4bit_bus(card);
  223. if (err)
  224. goto remove;
  225. }
  226. if (host->caps2 & MMC_CAP2_AVOID_3_3V &&
  227. host->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
  228. pr_err("%s: Host failed to negotiate down from 3.3V\n",
  229. mmc_hostname(host));
  230. err = -EINVAL;
  231. goto remove;
  232. }
  233. host->card = card;
  234. return 0;
  235. mismatch:
  236. pr_debug("%s: Perhaps the card was replaced\n", mmc_hostname(host));
  237. remove:
  238. if (oldcard != card)
  239. mmc_remove_card(card);
  240. return err;
  241. }

sdio ops相关函数

mmc_send_io_op_cond

  1. int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
  2. {
  3. struct mmc_command cmd = {};
  4. int i, err = 0;
  5. cmd.opcode = SD_IO_SEND_OP_COND;
  6. cmd.arg = ocr;
  7. cmd.flags = MMC_RSP_SPI_R4 | MMC_RSP_R4 | MMC_CMD_BCR;
  8. for (i = 100; i; i--) {
  9. err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
  10. if (err)
  11. break;
  12. /* if we're just probing, do a single pass */
  13. if (ocr == 0)
  14. break;
  15. /* otherwise wait until reset completes */
  16. if (mmc_host_is_spi(host)) {
  17. /*
  18. * Both R1_SPI_IDLE and MMC_CARD_BUSY indicate
  19. * an initialized card under SPI, but some cards
  20. * (Marvell's) only behave when looking at this
  21. * one.
  22. */
  23. if (cmd.resp[1] & MMC_CARD_BUSY)
  24. break;
  25. } else {
  26. if (cmd.resp[0] & MMC_CARD_BUSY)
  27. break;
  28. }
  29. err = -ETIMEDOUT;
  30. mmc_delay(10);
  31. }
  32. if (rocr)
  33. *rocr = cmd.resp[mmc_host_is_spi(host) ? 1 : 0];
  34. return err;
  35. }

mmc_io_rw_direct

  1. int mmc_io_rw_direct(struct mmc_card *card, int write, unsigned fn,
  2. unsigned addr, u8 in, u8 *out)
  3. {
  4. return mmc_io_rw_direct_host(card->host, write, fn, addr, in, out);
  5. }
  6. static int mmc_io_rw_direct_host(struct mmc_host *host, int write, unsigned fn,
  7. unsigned addr, u8 in, u8 *out)
  8. {
  9. struct mmc_command cmd = {};
  10. int err;
  11. if (fn > 7)
  12. return -EINVAL;
  13. /* sanity check */
  14. if (addr & ~0x1FFFF)
  15. return -EINVAL;
  16. cmd.opcode = SD_IO_RW_DIRECT;
  17. cmd.arg = write ? 0x80000000 : 0x00000000;
  18. cmd.arg |= fn << 28;
  19. cmd.arg |= (write && out) ? 0x08000000 : 0x00000000;
  20. cmd.arg |= addr << 9;
  21. cmd.arg |= in;
  22. cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC;
  23. err = mmc_wait_for_cmd(host, &cmd, 0);
  24. if (err)
  25. return err;
  26. if (mmc_host_is_spi(host)) {
  27. /* host driver already reported errors */
  28. } else {
  29. if (cmd.resp[0] & R5_ERROR)
  30. return -EIO;
  31. if (cmd.resp[0] & R5_FUNCTION_NUMBER)
  32. return -EINVAL;
  33. if (cmd.resp[0] & R5_OUT_OF_RANGE)
  34. return -ERANGE;
  35. }
  36. if (out) {
  37. if (mmc_host_is_spi(host))
  38. *out = (cmd.resp[0] >> 8) & 0xFF;
  39. else
  40. *out = cmd.resp[0] & 0xFF;
  41. }
  42. return 0;
  43. }

mmc_io_rw_extended

  1. int mmc_io_rw_extended(struct mmc_card *card, int write, unsigned fn,
  2. unsigned addr, int incr_addr, u8 *buf, unsigned blocks, unsigned blksz)
  3. {
  4. struct mmc_request mrq = {};
  5. struct mmc_command cmd = {};
  6. struct mmc_data data = {};
  7. struct scatterlist sg, *sg_ptr;
  8. struct sg_table sgtable;
  9. unsigned int nents, left_size, i;
  10. unsigned int seg_size = card->host->max_seg_size;
  11. int err;
  12. WARN_ON(blksz == 0);
  13. /* sanity check */
  14. if (addr & ~0x1FFFF)
  15. return -EINVAL;
  16. mrq.cmd = &cmd;
  17. mrq.data = &data;
  18. cmd.opcode = SD_IO_RW_EXTENDED; // cmd53
  19. cmd.arg = write ? 0x80000000 : 0x00000000; // 读写方向
  20. cmd.arg |= fn << 28; // func->num
  21. cmd.arg |= incr_addr ? 0x04000000 : 0x00000000;
  22. cmd.arg |= addr << 9; // 块地址
  23. if (blocks == 0)
  24. cmd.arg |= (blksz == 512) ? 0 : blksz; /* byte mode */
  25. else
  26. cmd.arg |= 0x08000000 | blocks; /* block mode */
  27. cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC;
  28. data.blksz = blksz; // 配置块大小
  29. /* Code in host drivers/fwk assumes that "blocks" always is >=1 */
  30. data.blocks = blocks ? blocks : 1; // 配置块数量
  31. data.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
  32. left_size = data.blksz * data.blocks;
  33. nents = DIV_ROUND_UP(left_size, seg_size);
  34. if (nents > 1) {
  35. if (sg_alloc_table(&sgtable, nents, GFP_KERNEL))
  36. return -ENOMEM;
  37. data.sg = sgtable.sgl;
  38. data.sg_len = nents;
  39. for_each_sg(data.sg, sg_ptr, data.sg_len, i) {
  40. sg_set_buf(sg_ptr, buf + i * seg_size,
  41. min(seg_size, left_size));
  42. left_size -= seg_size;
  43. }
  44. } else {
  45. data.sg = &sg;
  46. data.sg_len = 1;
  47. //初始化sg,找到buf对应的物理页地址,为DMA传输做准备
  48. sg_init_one(&sg, buf, left_size);
  49. }
  50. mmc_set_data_timeout(&data, card);
  51. mmc_pre_req(card->host, &mrq);
  52. //发送数据,并且等待返回
  53. mmc_wait_for_req(card->host, &mrq);
  54. if (cmd.error)
  55. err = cmd.error;
  56. else if (data.error)
  57. err = data.error;
  58. else if (mmc_host_is_spi(card->host))
  59. /* host driver already reported errors */
  60. err = 0;
  61. else if (cmd.resp[0] & R5_ERROR)//返回数据处理R5
  62. err = -EIO;
  63. else if (cmd.resp[0] & R5_FUNCTION_NUMBER)
  64. err = -EINVAL;
  65. else if (cmd.resp[0] & R5_OUT_OF_RANGE)
  66. err = -ERANGE;
  67. else
  68. err = 0;
  69. mmc_post_req(card->host, &mrq, err);
  70. if (nents > 1)
  71. sg_free_table(&sgtable);
  72. return err;
  73. }

sdio_reset

  1. int sdio_reset(struct mmc_host *host)
  2. {
  3. int ret;
  4. u8 abort;
  5. /* SDIO Simplified Specification V2.0, 4.4 Reset for SDIO */
  6. ret = mmc_io_rw_direct_host(host, 0, 0, SDIO_CCCR_ABORT, 0, &abort);
  7. if (ret)
  8. abort = 0x08;
  9. else
  10. abort |= 0x08;
  11. return mmc_io_rw_direct_host(host, 1, 0, SDIO_CCCR_ABORT, abort, NULL);
  12. }

sdio irq相关函数

注册sdio_irq——sdio_claim_irq

  1. /**
  2. * sdio_claim_irq - claim the IRQ for a SDIO function
  3. * @func: SDIO function
  4. * @handler: IRQ handler callback
  5. *
  6. * Claim and activate the IRQ for the given SDIO function. The provided
  7. * handler will be called when that IRQ is asserted. The host is always
  8. * claimed already when the handler is called so the handler should not
  9. * call sdio_claim_host() or sdio_release_host().
  10. */
  11. int sdio_claim_irq(struct sdio_func *func, sdio_irq_handler_t *handler)
  12. {
  13. int ret;
  14. unsigned char reg;
  15. if (!func)
  16. return -EINVAL;
  17. pr_debug("SDIO: Enabling IRQ for %s...\n", sdio_func_id(func));
  18. // sdio_func已注册中断,则为异常
  19. if (func->irq_handler) {
  20. pr_debug("SDIO: IRQ for %s already in use.\n", sdio_func_id(func));
  21. return -EBUSY;
  22. }
  23. // 获取中断使能寄存器值
  24. ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IENx, 0, &reg);
  25. if (ret)
  26. return ret;
  27. reg |= 1 << func->num;
  28. reg |= 1; /* Master interrupt enable */
  29. // 使能中断
  30. ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IENx, reg, NULL);
  31. if (ret)
  32. return ret;
  33. func->irq_handler = handler;
  34. // 创建sdio_irq_thread内核线程
  35. ret = sdio_card_irq_get(func->card);
  36. if (ret)
  37. func->irq_handler = NULL;
  38. // 配置sdio_single_irq
  39. sdio_single_irq_set(func->card);
  40. return ret;
  41. }
  42. EXPORT_SYMBOL_GPL(sdio_claim_irq);

释放sdio_irq——sdio_release_irq

  1. /**
  2. * sdio_release_irq - release the IRQ for a SDIO function
  3. * @func: SDIO function
  4. *
  5. * Disable and release the IRQ for the given SDIO function.
  6. */
  7. int sdio_release_irq(struct sdio_func *func)
  8. {
  9. int ret;
  10. unsigned char reg;
  11. if (!func)
  12. return -EINVAL;
  13. pr_debug("SDIO: Disabling IRQ for %s...\n", sdio_func_id(func));
  14. if (func->irq_handler) {
  15. func->irq_handler = NULL;
  16. sdio_card_irq_put(func->card);
  17. sdio_single_irq_set(func->card);
  18. }
  19. ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IENx, 0, &reg);
  20. if (ret)
  21. return ret;
  22. reg &= ~(1 << func->num);
  23. /* Disable master interrupt with the last function interrupt */
  24. if (!(reg & 0xFE))
  25. reg = 0;
  26. ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IENx, reg, NULL);
  27. if (ret)
  28. return ret;
  29. return 0;
  30. }
  31. EXPORT_SYMBOL_GPL(sdio_release_irq);

创建sdio_irq_thread——sdio_card_irq_get

  1. static int sdio_card_irq_get(struct mmc_card *card)
  2. {
  3. struct mmc_host *host = card->host;
  4. WARN_ON(!host->claimed);
  5. if (!host->sdio_irqs++) {
  6. if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD)) {
  7. atomic_set(&host->sdio_irq_thread_abort, 0);
  8. //创建sdio irq thread 内核线程
  9. host->sdio_irq_thread =
  10. kthread_run(sdio_irq_thread, host,
  11. "ksdioirqd/%s", mmc_hostname(host));
  12. if (IS_ERR(host->sdio_irq_thread)) {
  13. int err = PTR_ERR(host->sdio_irq_thread);
  14. host->sdio_irqs--;
  15. return err;
  16. }
  17. } else if (host->caps & MMC_CAP_SDIO_IRQ) {
  18. host->ops->enable_sdio_irq(host, 1);
  19. }
  20. }
  21. return 0;
  22. }

实现sdio_irq_thread——sdio_irq_thread

  1. static int sdio_irq_thread(void *_host)
  2. {
  3. struct mmc_host *host = _host;
  4. struct sched_param param = { .sched_priority = 1 };
  5. unsigned long period, idle_period;
  6. int ret;
  7. // 将sdio irq thread线程为实时线程FIFO,优先级为1
  8. sched_setscheduler(current, SCHED_FIFO, &param);
  9. /*
  10. * We want to allow for SDIO cards to work even on non SDIO
  11. * aware hosts. One thing that non SDIO host cannot do is
  12. * asynchronous notification of pending SDIO card interrupts
  13. * hence we poll for them in that case.
  14. */
  15. // 轮询运行时间为10ms
  16. idle_period = msecs_to_jiffies(10);
  17. // 若host支持硬件sdio_irq,则为中断模式,否则为轮询模式,10ms调度一次
  18. period = (host->caps & MMC_CAP_SDIO_IRQ) ?
  19. MAX_SCHEDULE_TIMEOUT : idle_period;
  20. pr_debug("%s: IRQ thread started (poll period = %lu jiffies)\n",
  21. mmc_hostname(host), period);
  22. do {
  23. /*
  24. * We claim the host here on drivers behalf for a couple
  25. * reasons:
  26. *
  27. * 1) it is already needed to retrieve the CCCR_INTx;
  28. * 2) we want the driver(s) to clear the IRQ condition ASAP;
  29. * 3) we need to control the abort condition locally.
  30. *
  31. * Just like traditional hard IRQ handlers, we expect SDIO
  32. * IRQ handlers to be quick and to the point, so that the
  33. * holding of the host lock does not cover too much work
  34. * that doesn't require that lock to be held.
  35. */
  36. // 获取host的使用权
  37. ret = __mmc_claim_host(host, NULL,
  38. &host->sdio_irq_thread_abort);
  39. if (ret)
  40. break;
  41. // 调用sdio_fun irq_handler函数或获取sdio card status再调用sdio_func
  42. ret = process_sdio_pending_irqs(host);
  43. // 释放host的使用权
  44. mmc_release_host(host);
  45. /*
  46. * Give other threads a chance to run in the presence of
  47. * errors.
  48. */
  49. if (ret < 0) {
  50. set_current_state(TASK_INTERRUPTIBLE);
  51. if (!kthread_should_stop())
  52. schedule_timeout(HZ);
  53. set_current_state(TASK_RUNNING);
  54. }
  55. /*
  56. * Adaptive polling frequency based on the assumption
  57. * that an interrupt will be closely followed by more.
  58. * This has a substantial benefit for network devices.
  59. */
  60. if (!(host->caps & MMC_CAP_SDIO_IRQ)) {
  61. if (ret > 0)
  62. period /= 2;
  63. else {
  64. period++;
  65. if (period > idle_period)
  66. period = idle_period;
  67. }
  68. }
  69. set_current_state(TASK_INTERRUPTIBLE);
  70. // 处理完sdio card中的数据,若支持sdio_irq,则使能sdio_irq
  71. if (host->caps & MMC_CAP_SDIO_IRQ)
  72. host->ops->enable_sdio_irq(host, 1);
  73. if (!kthread_should_stop())
  74. schedule_timeout(period);
  75. set_current_state(TASK_RUNNING);
  76. } while (!kthread_should_stop());
  77. // 支持sdio_irq,则关闭sdio_irq
  78. if (host->caps & MMC_CAP_SDIO_IRQ)
  79. host->ops->enable_sdio_irq(host, 0);
  80. pr_debug("%s: IRQ thread exiting with code %d\n",
  81. mmc_hostname(host), ret);
  82. return ret;
  83. }

process_sdio_pending_irqs:

  1. static int process_sdio_pending_irqs(struct mmc_host *host)
  2. {
  3. struct mmc_card *card = host->card;
  4. int i, ret, count;
  5. bool sdio_irq_pending = host->sdio_irq_pending;
  6. unsigned char pending;
  7. struct sdio_func *func;
  8. /* Don't process SDIO IRQs if the card is suspended. */
  9. if (mmc_card_suspended(card))
  10. return 0;
  11. /* Clear the flag to indicate that we have processed the IRQ. */
  12. host->sdio_irq_pending = false;
  13. /*
  14. * Optimization, if there is only 1 function interrupt registered
  15. * and we know an IRQ was signaled then call irq handler directly.
  16. * Otherwise do the full probe.
  17. */
  18. // sdio_single_irq已注册,则直接调用func->irq_handler处理本次中断
  19. func = card->sdio_single_irq;
  20. if (func && sdio_irq_pending) {
  21. func->irq_handler(func);
  22. return 1;
  23. }
  24. // 发送cmd5 查询irq_pending???
  25. ret = sdio_get_pending_irqs(host, &pending);
  26. if (ret)
  27. return ret;
  28. // 根据pending,调用所对应的func
  29. count = 0;
  30. for (i = 1; i <= 7; i++) {
  31. if (pending & (1 << i)) {
  32. func = card->sdio_func[i - 1];
  33. if (!func) {
  34. pr_warn("%s: pending IRQ for non-existent function\n",
  35. mmc_card_id(card));
  36. ret = -EINVAL;
  37. } else if (func->irq_handler) {
  38. func->irq_handler(func);
  39. count++;
  40. } else {
  41. pr_warn("%s: pending IRQ with no handler\n",
  42. sdio_func_id(func));
  43. ret = -EINVAL;
  44. }
  45. }
  46. }
  47. if (count)
  48. return count;
  49. return ret;
  50. }

sdio_get_pending_irqs:

  1. static int sdio_get_pending_irqs(struct mmc_host *host, u8 *pending)
  2. {
  3. struct mmc_card *card = host->card;
  4. int ret;
  5. WARN_ON(!host->claimed);
  6. ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_INTx, 0, pending);
  7. if (ret) {
  8. pr_debug("%s: error %d reading SDIO_CCCR_INTx\n",
  9. mmc_card_id(card), ret);
  10. return ret;
  11. }
  12. if (*pending && mmc_card_broken_irq_polling(card) &&
  13. !(host->caps & MMC_CAP_SDIO_IRQ)) {
  14. unsigned char dummy;
  15. /* A fake interrupt could be created when we poll SDIO_CCCR_INTx
  16. * register with a Marvell SD8797 card. A dummy CMD52 read to
  17. * function 0 register 0xff can avoid this.
  18. */
  19. mmc_io_rw_direct(card, 0, 0, 0xff, 0, &dummy);
  20. }
  21. return 0;
  22. }

sdio io相关函数

host相关

sdio_claim_host:

  1. void sdio_claim_host(struct sdio_func *func)
  2. {
  3. if (WARN_ON(!func))
  4. return;
  5. mmc_claim_host(func->card->host);
  6. }
  7. EXPORT_SYMBOL_GPL(sdio_claim_host);

sdio_release_host:

  1. void sdio_release_host(struct sdio_func *func)
  2. {
  3. if (WARN_ON(!func))
  4. return;
  5. mmc_release_host(func->card->host);
  6. }
  7. EXPORT_SYMBOL_GPL(sdio_release_host);

sdio func相关

  1. int sdio_enable_func(struct sdio_func *func);
  2. int sdio_disable_func(struct sdio_func *func);

块配置相关

  1. int sdio_set_block_size(struct sdio_func *func, unsigned blksz);
  2. unsigned int sdio_align_size(struct sdio_func *func, unsigned int sz);

IO读写相关

  1. // 读写1byte
  2. u8 sdio_readb(struct sdio_func *func, unsigned int addr, int *err_ret);
  3. void sdio_writeb(struct sdio_func *func, u8 b, unsigned int addr, int *err_ret);
  4. u8 sdio_writeb_readb(struct sdio_func *func, u8 write_byte, unsigned int addr, int *err_ret);
  5. // 读写块数据
  6. int sdio_memcpy_fromio(struct sdio_func *func, void *dst, unsigned int addr, int count);
  7. int sdio_memcpy_toio(struct sdio_func *func, unsigned int addr, void *src, int count);
  8. // 读写FIFO 1byte
  9. int sdio_readsb(struct sdio_func *func, void *dst, unsigned int addr, int count);
  10. int sdio_writesb(struct sdio_func *func, unsigned int addr, void *src, int count);
  11. // 读写16bit(2byte)
  12. u16 sdio_readw(struct sdio_func *func, unsigned int addr, int *err_ret);
  13. void sdio_writew(struct sdio_func *func, u16 b, unsigned int addr, int *err_ret);
  14. // 读写32bit(4byte)
  15. u32 sdio_readl(struct sdio_func *func, unsigned int addr, int *err_ret);
  16. void sdio_writel(struct sdio_func *func, u32 b, unsigned int addr, int *err_ret);
  17. // sdio func0 读取1byte
  18. unsigned char sdio_f0_readb(struct sdio_func *func, unsigned int addr, int *err_ret);
  19. void sdio_f0_writeb(struct sdio_func *func, unsigned char b, unsigned int addr, int *err_ret);

  
sdio_io_rw_ext_helper:
  以上IO相关的函数,最终都是调用本函数来实现相关的功能,具体实现方式如下:

  1. /* Split an arbitrarily sized data transfer into several
  2. * IO_RW_EXTENDED commands. */
  3. static int sdio_io_rw_ext_helper(struct sdio_func *func, int write,
  4. unsigned addr, int incr_addr, u8 *buf, unsigned size)
  5. {
  6. unsigned remainder = size;
  7. unsigned max_blocks;
  8. int ret;
  9. if (!func || (func->num > 7))
  10. return -EINVAL;
  11. /* Do the bulk of the transfer using block mode (if supported). */
  12. // 支持多块传输,且当前传输数据大于一块大小
  13. if (func->card->cccr.multi_block && (size > sdio_max_byte_size(func))) {
  14. /* Blocks per command is limited by host count, host transfer
  15. * size and the maximum for IO_RW_EXTENDED of 511 blocks. */
  16. max_blocks = min(func->card->host->max_blk_count, 511u);
  17. // 快对齐收发数据
  18. while (remainder >= func->cur_blksize) {
  19. unsigned blocks;
  20. blocks = remainder / func->cur_blksize;
  21. if (blocks > max_blocks)
  22. blocks = max_blocks;
  23. size = blocks * func->cur_blksize;
  24. ret = mmc_io_rw_extended(func->card, write,
  25. func->num, addr, incr_addr, buf,
  26. blocks, func->cur_blksize);
  27. if (ret)
  28. return ret;
  29. remainder -= size;
  30. buf += size;
  31. if (incr_addr)
  32. addr += size;
  33. }
  34. }
  35. /* Write the remainder using byte mode. */
  36. // 收发剩余数据
  37. while (remainder > 0) {
  38. size = min(remainder, sdio_max_byte_size(func));
  39. /* Indicate byte mode by setting "blocks" = 0 */
  40. ret = mmc_io_rw_extended(func->card, write, func->num, addr,
  41. incr_addr, buf, 0, size);
  42. if (ret)
  43. return ret;
  44. remainder -= size;
  45. buf += size;
  46. if (incr_addr)
  47. addr += size;
  48. }
  49. return 0;
  50. }

发表评论

表情:
评论列表 (有 0 条评论,763人围观)

还没有评论,来说两句吧...

相关阅读

    相关 SDIO定义(七)

    SDIO定义 SDIO,全称: Secure Digital Input and Output ,即安全数字输入输出接口。它是在SD卡接口的基础上发展而来,它可以兼容之前的S