LoginSignup
1
1

More than 5 years have passed since last update.

Marvell Wi-Fi Driver SDIO card割り込みを読む

Posted at

Marvell Wi-Fi driverのSDIO card割り込みの処理 についてLinuxカーネルに含まれているソースコードを調べてみました。

まとめ

  • 割り込みが入るとレジスタをまとめてmp_regsに読み出す。
  • 各レジスタの使い方についてまとめた。
  • host_int_status_regが正なら、割り込みをハンドリングする必要がある
  • mwifiex_process_int_status()が割り込みを処理する関数
  • コマンド受信割り込み、データ送信割り込み、データ受信割り込みの順で処理する。
  • mpaでaggregateの受信が可能なら、まとめて読みむ

対象

  • Linux kernel 4.6.2
  • drivers/net/wireless/marvell/mwiflex

レジスタ

  • 割り込み処理で使うレジスタです。

mp_regs

  • 割り込みでまとめて読み出すレジスタ
  • チップごとに読み出すサイズが異なる。max_mp_regsで定義。 87xxは64 88xxは184 89xxは196
  • アドレス REG_PORT | MWIFIEX_SDIO_BYTE_MODE_MASK から長さ max_mp_regs だけ読む
        if (mwifiex_read_data_sync(adapter, card->mp_regs,
                                   card->reg->max_mp_regs,
                                   REG_PORT | MWIFIEX_SDIO_BYTE_MODE_MASK, 0)) {
                mwifiex_dbg(adapter, ERROR, "read mp_regs failed\n");

status_reg0 status_reg1

  • firmware stautus 16bit
  • mwifiex_sdio_read_fw_status() で読み出す
  • ファームウェアダウンロード後の起動確認で使う
  • 正常な場合の期待値は 0xfedc
101:#define FIRMWARE_READY_SDIO                         0xfedc

host_int_status_reg

  • int status reg
  • 割り込みステータス
  • DN_LD_CMD_PORT_HOST_INT_STATUS コマンド送信完了
  • UP_LD_CMD_PORT_HOST_INT_STATUS コマンド受信
  • DN_LD_HOST_INT_STATUS データ送信完了
  • UP_LD_HOST_INT_STATUS データ受信

io_port_0_reg io_port_1_reg io_port_2_reg

  • multiport aggregation で使うio_portを示す

rd_bitmap_l rd_bitmap_u

  • 受信バッファのビットマップ
  • ビットが1なら受信データあり、0ならデータ無し
  • 0ビット目が、mpaでない受信ポート状態
  • 1ビット目以降が、mpaの各ポートの状態

wr_bitmap_l wr_bitmap_u

  • 送信バッファのビットマップ
  • 1なら送信待ちのデータあり、0ならデータ無し
  • 0ビット目以降が、mpaの各ポートの状態

rd_len_p0_l rd_len_p0_u

  • port 0の受信データ長
  • port nの受信データ長は、rd_len_p0_l +(n<<1), rd_len_p0_u + (n<<1) のアドレスにある

card_misc_cfg_reg

  • その他の設定
  • 割り込みの自動再有効の設定で使う
        /* Dnld/Upld ready set to auto reset */
        if (!mwifiex_read_reg(adapter, card->reg->card_misc_cfg_reg, &reg))
                mwifiex_write_reg(adapter, card->reg->card_misc_cfg_reg,
                                  reg | AUTO_RE_ENABLE_INT);
        else
                return -1;

        return 0;

SDIO カード割り込みハンドラの登録

  • カード割り込みはsdio_claim_irq()でハンドラを登録します。
static int mwifiex_sdio_enable_host_int(struct mwifiex_adapter *adapter)
{
        struct sdio_mmc_card *card = adapter->card;
        struct sdio_func *func = card->func;
        int ret;

        sdio_claim_host(func);

        /* Request the SDIO IRQ */
        ret = sdio_claim_irq(func, mwifiex_sdio_interrupt);
  • 解除は、sdio_release_irq()です。

SDIO card割り込みハンドラ 1

  • SIO deviceからカード割り込みが入ると、sdio_claim_irq()で登録したハンドラが呼ばれます。
  • card構造体とadapter構造体のポインタを取得
  • adapter->ps_stateはカードのPS状態を表します。割り込みが入ったということは起き上がったと等価なので、PS_SATE_AWAKEを設定
  • mwifiex_interrupt_status()
  • mwifiex_main_process()
/*
 * SDIO interrupt handler.
 *
 * This function reads the interrupt status from firmware and handles
 * the interrupt in current thread (ksdioirqd) right away.
 */
static void
mwifiex_sdio_interrupt(struct sdio_func *func)
{
        struct mwifiex_adapter *adapter;
        struct sdio_mmc_card *card;

        card = sdio_get_drvdata(func);
        if (!card || !card->adapter) {
                pr_err("int: func=%p card=%p adapter=%p\n",
                       func, card, card ? card->adapter : NULL);
                return;
        }
        adapter = card->adapter;

        if (!adapter->pps_uapsd_mode && adapter->ps_state == PS_STATE_SLEEP)
                adapter->ps_state = PS_STATE_AWAKE;

        mwifiex_interrupt_status(adapter);
        mwifiex_main_process(adapter);
}

SDIO card割り込みハンドラ 2

  • mwifiex_interrupt_status()
  • 割り込みステータスをアップデート
    • card->reg->max_mp_regs
    • adapter->int_status
  • sdio_iregが正なら、なんらなかの処理すべき割り込みがある。
/*
 * This function reads the interrupt status from card.
 */
static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
{
        struct sdio_mmc_card *card = adapter->card;
        u8 sdio_ireg;
        unsigned long flags;

        if (mwifiex_read_data_sync(adapter, card->mp_regs,
                                   card->reg->max_mp_regs,
                                   REG_PORT | MWIFIEX_SDIO_BYTE_MODE_MASK, 0)) {
                mwifiex_dbg(adapter, ERROR, "read mp_regs failed\n");
                return;
        }

        sdio_ireg = card->mp_regs[card->reg->host_int_status_reg];
        if (sdio_ireg) {
                /*
                 * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS
                 * For SDIO new mode CMD port interrupts
                 *      DN_LD_CMD_PORT_HOST_INT_STATUS and/or
                 *      UP_LD_CMD_PORT_HOST_INT_STATUS
                 * Clear the interrupt status register
                 */
                mwifiex_dbg(adapter, INTR,
                            "int: sdio_ireg = %#x\n", sdio_ireg);
                spin_lock_irqsave(&adapter->int_lock, flags);
                adapter->int_status |= sdio_ireg;
                spin_unlock_irqrestore(&adapter->int_lock, flags);
        }
}

SDIO card割り込みハンドラ 2

  • mwifiex_main_process()
  • これはドライバのメインプロセスです。
  • データ送受信に関わらないところは省略する
  • 割り込みが入ったら、adapter->if_ops.process_int_status(adapter);を呼ぶ
  • この実体はsdio.cのmwifiex_process_int_status()
/*
 * The main process.
 *
 * This function is the main procedure of the driver and handles various driver
 * operations. It runs in a loop and provides the core functionalities.
 *
 * The main responsibilities of this function are -
 *      - Ensure concurrency control
 *      - Handle pending interrupts and call interrupt handlers
 *      - Wake up the card if required
 *      - Handle command responses and call response handlers
 *      - Handle events and call event handlers
 *      - Execute pending commands
 *      - Transmit pending data packets
 */
int mwifiex_main_process(struct mwifiex_adapter *adapter)
{
    int ret = 0;
    unsigned long flags;

    spin_lock_irqsave(&adapter->main_proc_lock, flags);

    /* Check if already processing */
    if (adapter->mwifiex_processing || adapter->main_locked) {
        adapter->more_task_flag = true;
        spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
        goto exit_main_proc;
    } else {
        adapter->mwifiex_processing = true;
        spin_unlock_irqrestore(&adapter->main_proc_lock, flags);
    }
process_start:
    do {
...
        /* Handle pending interrupt if any */
        if (adapter->int_status) {
            if (adapter->hs_activated)
                mwifiex_process_hs_config(adapter);
            if (adapter->if_ops.process_int_status)
                adapter->if_ops.process_int_status(adapter);
        }
...
      } while (true);

...

exit_main_proc:
    if (adapter->hw_status == MWIFIEX_HW_STATUS_CLOSING)
        mwifiex_shutdown_drv(adapter);
    return ret;
}
EXPORT_SYMBOL_GPL(mwifiex_main_process);

# SDIO card割り込みハンドラ 3

  • mwifiex_process_int_status()の概要
  • UP_LD_CMD_PORT_HOST_INT_STATUS コマンド受信割り込み
    • cmd_rd_len_1とcmd_rd_len_0を読み、受信長を知る
    • 受信長分のskbを確保
    • CMD53でコマンドを読み出し
    • mwifiex_decode_rx_packet()でコマンドを解析
  • DN_LD_HOST_INT_STATUS データ送信完了割り込み
    • wr_bitmap_l と wr_bitmap_u を読み card->mp_wr_bitmapに上書き
  • not generate download ready interrupt の対応
  • UP_LD_HOST_INT_STATUS データ受信割り込み
    • rd_bitmap_l と rd_bitmap_u を読む
    • mwifiex_get_rd_port(adapter, &port)で読みだすportを知る。
    • mwifiex_sdio_card_to_host_mp_aggr()データを読み出す。 mpa可能ならmpaで読み出す。
  • 終了処理

参考

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1