/* * This function transfers received packets from card to driver, performing * aggregation if required. * * For data received on control port, or if aggregation is disabled, the * received buffers are uploaded as separate packets. However, if aggregation * is enabled and required, the buffers are copied onto an aggregation buffer, * provided there is space left, processed and finally uploaded. */ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, struct sk_buff *skb, u8 port) { struct sdio_mmc_card *card = adapter->card; s32 f_do_rx_aggr = 0; s32 f_do_rx_cur = 0; s32 f_aggr_cur = 0; struct sk_buff *skb_deaggr; u32 pind; u32 pkt_len, pkt_type = 0; u8 *curr_ptr; u32 rx_len = skb->len; if (port == CTRL_PORT) { /* Read the command Resp without aggr */ dev_dbg(adapter->dev, "info: %s: no aggregation for cmd " "response\n", __func__); f_do_rx_cur = 1; goto rx_curr_single; } if (!card->mpa_rx.enabled) { dev_dbg(adapter->dev, "info: %s: rx aggregation disabled\n", __func__); f_do_rx_cur = 1; goto rx_curr_single; } if (card->mp_rd_bitmap & (~((u16) CTRL_PORT_MASK))) { /* Some more data RX pending */ dev_dbg(adapter->dev, "info: %s: not last packet\n", __func__); if (MP_RX_AGGR_IN_PROGRESS(card)) { if (MP_RX_AGGR_BUF_HAS_ROOM(card, skb->len)) { f_aggr_cur = 1; } else { /* No room in Aggr buf, do rx aggr now */ f_do_rx_aggr = 1; f_do_rx_cur = 1; } } else { /* Rx aggr not in progress */ f_aggr_cur = 1; } } else { /* No more data RX pending */ dev_dbg(adapter->dev, "info: %s: last packet\n", __func__); if (MP_RX_AGGR_IN_PROGRESS(card)) { f_do_rx_aggr = 1; if (MP_RX_AGGR_BUF_HAS_ROOM(card, skb->len)) f_aggr_cur = 1; else /* No room in Aggr buf, do rx aggr now */ f_do_rx_cur = 1; } else { f_do_rx_cur = 1; } } if (f_aggr_cur) { dev_dbg(adapter->dev, "info: current packet aggregation\n"); /* Curr pkt can be aggregated */ MP_RX_AGGR_SETUP(card, skb, port); if (MP_RX_AGGR_PKT_LIMIT_REACHED(card) || MP_RX_AGGR_PORT_LIMIT_REACHED(card)) { dev_dbg(adapter->dev, "info: %s: aggregated packet " "limit reached\n", __func__); /* No more pkts allowed in Aggr buf, rx it */ f_do_rx_aggr = 1; } } if (f_do_rx_aggr) { /* do aggr RX now */ dev_dbg(adapter->dev, "info: do_rx_aggr: num of packets: %d\n", card->mpa_rx.pkt_cnt); if (mwifiex_read_data_sync(adapter, card->mpa_rx.buf, card->mpa_rx.buf_len, (adapter->ioport | 0x1000 | (card->mpa_rx.ports << 4)) + card->mpa_rx.start_port, 1)) return -1; curr_ptr = card->mpa_rx.buf; for (pind = 0; pind < card->mpa_rx.pkt_cnt; pind++) { /* get curr PKT len & type */ pkt_len = *(u16 *) &curr_ptr[0]; pkt_type = *(u16 *) &curr_ptr[2]; /* copy pkt to deaggr buf */ skb_deaggr = card->mpa_rx.skb_arr[pind]; if ((pkt_type == MWIFIEX_TYPE_DATA) && (pkt_len <= card->mpa_rx.len_arr[pind])) { memcpy(skb_deaggr->data, curr_ptr, pkt_len); skb_trim(skb_deaggr, pkt_len); /* Process de-aggr packet */ mwifiex_decode_rx_packet(adapter, skb_deaggr, pkt_type); } else { dev_err(adapter->dev, "wrong aggr pkt:" " type=%d len=%d max_len=%d\n", pkt_type, pkt_len, card->mpa_rx.len_arr[pind]); dev_kfree_skb_any(skb_deaggr); } curr_ptr += card->mpa_rx.len_arr[pind]; } MP_RX_AGGR_BUF_RESET(card); } rx_curr_single: if (f_do_rx_cur) { dev_dbg(adapter->dev, "info: RX: port: %d, rx_len: %d\n", port, rx_len); if (mwifiex_sdio_card_to_host(adapter, &pkt_type, skb->data, skb->len, adapter->ioport + port)) return -1; mwifiex_decode_rx_packet(adapter, skb, pkt_type); } return 0; }
static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, struct sk_buff *skb, u8 port) { struct sdio_mmc_card *card = adapter->card; s32 f_do_rx_aggr = 0; s32 f_do_rx_cur = 0; s32 f_aggr_cur = 0; struct sk_buff *skb_deaggr; u32 pind; u32 pkt_len, pkt_type = 0; u8 *curr_ptr; u32 rx_len = skb->len; if (port == CTRL_PORT) { dev_dbg(adapter->dev, "info: %s: no aggregation for cmd " "response\n", __func__); f_do_rx_cur = 1; goto rx_curr_single; } if (!card->mpa_rx.enabled) { dev_dbg(adapter->dev, "info: %s: rx aggregation disabled\n", __func__); f_do_rx_cur = 1; goto rx_curr_single; } if (card->mp_rd_bitmap & (~((u16) CTRL_PORT_MASK))) { dev_dbg(adapter->dev, "info: %s: not last packet\n", __func__); if (MP_RX_AGGR_IN_PROGRESS(card)) { if (MP_RX_AGGR_BUF_HAS_ROOM(card, skb->len)) { f_aggr_cur = 1; } else { f_do_rx_aggr = 1; f_do_rx_cur = 1; } } else { f_aggr_cur = 1; } } else { dev_dbg(adapter->dev, "info: %s: last packet\n", __func__); if (MP_RX_AGGR_IN_PROGRESS(card)) { f_do_rx_aggr = 1; if (MP_RX_AGGR_BUF_HAS_ROOM(card, skb->len)) f_aggr_cur = 1; else f_do_rx_cur = 1; } else { f_do_rx_cur = 1; } } if (f_aggr_cur) { dev_dbg(adapter->dev, "info: current packet aggregation\n"); MP_RX_AGGR_SETUP(card, skb, port); if (MP_RX_AGGR_PKT_LIMIT_REACHED(card) || MP_RX_AGGR_PORT_LIMIT_REACHED(card)) { dev_dbg(adapter->dev, "info: %s: aggregated packet " "limit reached\n", __func__); f_do_rx_aggr = 1; } } if (f_do_rx_aggr) { dev_dbg(adapter->dev, "info: do_rx_aggr: num of packets: %d\n", card->mpa_rx.pkt_cnt); if (mwifiex_read_data_sync(adapter, card->mpa_rx.buf, card->mpa_rx.buf_len, (adapter->ioport | 0x1000 | (card->mpa_rx.ports << 4)) + card->mpa_rx.start_port, 1)) goto error; curr_ptr = card->mpa_rx.buf; for (pind = 0; pind < card->mpa_rx.pkt_cnt; pind++) { pkt_len = *(u16 *) &curr_ptr[0]; pkt_type = *(u16 *) &curr_ptr[2]; skb_deaggr = card->mpa_rx.skb_arr[pind]; if ((pkt_type == MWIFIEX_TYPE_DATA) && (pkt_len <= card->mpa_rx.len_arr[pind])) { memcpy(skb_deaggr->data, curr_ptr, pkt_len); skb_trim(skb_deaggr, pkt_len); mwifiex_decode_rx_packet(adapter, skb_deaggr, pkt_type); } else { dev_err(adapter->dev, "wrong aggr pkt:" " type=%d len=%d max_len=%d\n", pkt_type, pkt_len, card->mpa_rx.len_arr[pind]); dev_kfree_skb_any(skb_deaggr); } curr_ptr += card->mpa_rx.len_arr[pind]; } MP_RX_AGGR_BUF_RESET(card); } rx_curr_single: if (f_do_rx_cur) { dev_dbg(adapter->dev, "info: RX: port: %d, rx_len: %d\n", port, rx_len); if (mwifiex_sdio_card_to_host(adapter, &pkt_type, skb->data, skb->len, adapter->ioport + port)) goto error; mwifiex_decode_rx_packet(adapter, skb, pkt_type); } return 0; error: if (MP_RX_AGGR_IN_PROGRESS(card)) { for (pind = 0; pind < card->mpa_rx.pkt_cnt; pind++) { skb_deaggr = card->mpa_rx.skb_arr[pind]; dev_kfree_skb_any(skb_deaggr); } MP_RX_AGGR_BUF_RESET(card); } if (f_do_rx_cur) dev_kfree_skb_any(skb); return -1; }
/** * @brief This function receives data from the card in aggregate mode. * * @param pmadapter A pointer to mlan_adapter structure * @param pmbuf A pointer to the SDIO data/cmd buffer * @param port Current port on which packet needs to be rxed * @param rx_len Length of received packet * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ static mlan_status wlan_sdio_card_to_host_mp_aggr(mlan_adapter * pmadapter, mlan_buffer * pmbuf, t_u8 port, t_u16 rx_len) { mlan_status ret = MLAN_STATUS_SUCCESS; pmlan_callbacks pcb = &pmadapter->callbacks; t_s32 f_do_rx_aggr = 0; t_s32 f_do_rx_cur = 0; t_s32 f_aggr_cur = 0; mlan_buffer mbuf_aggr; mlan_buffer *mbuf_deaggr; t_u32 pind = 0; t_u32 pkt_len, pkt_type = 0; t_u8 *curr_ptr; t_u32 cmd53_port = 0; ENTER(); if (port == CTRL_PORT) { /* Read the command response or event without aggr */ PRINTM(MINFO, "card_2_host_mp_aggr: No aggr for control port\n"); f_do_rx_cur = 1; goto rx_curr_single; } if (!pmadapter->mpa_rx.enabled) { PRINTM(MINFO, "card_2_host_mp_aggr: rx aggregation disabled !\n"); f_do_rx_cur = 1; goto rx_curr_single; } if (pmadapter->mp_rd_bitmap & (~((t_u32) CTRL_PORT_MASK))) { /* Some more data RX pending */ PRINTM(MINFO, "card_2_host_mp_aggr: Not last packet\n"); if (MP_RX_AGGR_IN_PROGRESS(pmadapter)) { if (MP_RX_AGGR_BUF_HAS_ROOM(pmadapter, rx_len)) { f_aggr_cur = 1; } else { /* No room in Aggr buf, do rx aggr now */ f_do_rx_aggr = 1; f_do_rx_cur = 1; } } else { /* Rx aggr not in progress */ f_aggr_cur = 1; } } else { /* No more data RX pending */ PRINTM(MINFO, "card_2_host_mp_aggr: Last packet\n"); if (MP_RX_AGGR_IN_PROGRESS(pmadapter)) { f_do_rx_aggr = 1; if (MP_RX_AGGR_BUF_HAS_ROOM(pmadapter, rx_len)) { f_aggr_cur = 1; } else { /* No room in Aggr buf, do rx aggr now */ f_do_rx_cur = 1; } } else { f_do_rx_cur = 1; } } if (f_aggr_cur) { PRINTM(MINFO, "Current packet aggregation.\n"); /* Curr pkt can be aggregated */ MP_RX_AGGR_SETUP(pmadapter, pmbuf, port, rx_len); if (MP_RX_AGGR_PKT_LIMIT_REACHED(pmadapter) || MP_RX_AGGR_PORT_LIMIT_REACHED(pmadapter)) { PRINTM(MINFO, "card_2_host_mp_aggr: Aggregation Packet limit reached\n"); /* No more pkts allowed in Aggr buf, rx it */ f_do_rx_aggr = 1; } } if (f_do_rx_aggr) { /* do aggr RX now */ PRINTM(MINFO, "do_rx_aggr: num of packets: %d\n", pmadapter->mpa_rx.pkt_cnt); memset(pmadapter, &mbuf_aggr, 0, sizeof(mlan_buffer)); mbuf_aggr.pbuf = (t_u8 *) pmadapter->mpa_rx.buf; mbuf_aggr.data_len = pmadapter->mpa_rx.buf_len; cmd53_port = (pmadapter->ioport | SDIO_MPA_ADDR_BASE | (pmadapter->mpa_rx.ports << 4)) + pmadapter->mpa_rx.start_port; if (MLAN_STATUS_SUCCESS != pcb->moal_read_data_sync(pmadapter->pmoal_handle, &mbuf_aggr, cmd53_port, 0)) { pmbuf->status_code = MLAN_ERROR_DATA_RX_FAIL; ret = MLAN_STATUS_FAILURE; goto done; } DBG_HEXDUMP(MIF_D, "SDIO MP-A Blk Rd", pmadapter->mpa_rx.buf, MIN(pmadapter->mpa_rx.buf_len, MAX_DATA_DUMP_LEN)); curr_ptr = pmadapter->mpa_rx.buf; for (pind = 0; pind < pmadapter->mpa_rx.pkt_cnt; pind++) { /* get curr PKT len & type */ pkt_len = wlan_le16_to_cpu(*(t_u16 *) & curr_ptr[0]); pkt_type = wlan_le16_to_cpu(*(t_u16 *) & curr_ptr[2]); PRINTM(MINFO, "RX: [%d] pktlen: %d pkt_type: 0x%x\n", pind, pkt_len, pkt_type); /* copy pkt to deaggr buf */ mbuf_deaggr = pmadapter->mpa_rx.mbuf_arr[pind]; if ((pkt_type == MLAN_TYPE_DATA) && (pkt_len <= pmadapter->mpa_rx.len_arr[pind])) { memcpy(pmadapter, mbuf_deaggr->pbuf + mbuf_deaggr->data_offset, curr_ptr, pkt_len); pmadapter->upld_len = pkt_len; /* Process de-aggr packet */ wlan_decode_rx_packet(pmadapter, mbuf_deaggr, pkt_type); } else { PRINTM(MERROR, "Wrong aggr packet: type=%d, len=%d, max_len=%d\n", pkt_type, pkt_len, pmadapter->mpa_rx.len_arr[pind]); wlan_free_mlan_buffer(pmadapter, mbuf_deaggr); } curr_ptr += pmadapter->mpa_rx.len_arr[pind]; } MP_RX_AGGR_BUF_RESET(pmadapter); } rx_curr_single: if (f_do_rx_cur) { PRINTM(MINFO, "RX: f_do_rx_cur: port: %d rx_len: %d\n", port, rx_len); if (MLAN_STATUS_SUCCESS != wlan_sdio_card_to_host(pmadapter, &pkt_type, (t_u32 *) & pmadapter->upld_len, pmbuf, rx_len, pmadapter->ioport + port)) { ret = MLAN_STATUS_FAILURE; goto done; } if ((port == CTRL_PORT) && ((pkt_type != MLAN_TYPE_EVENT) && (pkt_type != MLAN_TYPE_CMD))) { PRINTM(MERROR, "Wrong pkt from CTRL PORT: type=%d, len=%dd\n", pkt_type, pmbuf->data_len); pmbuf->status_code = MLAN_ERROR_DATA_RX_FAIL; ret = MLAN_STATUS_FAILURE; goto done; } wlan_decode_rx_packet(pmadapter, pmbuf, pkt_type); } done: if (ret == MLAN_STATUS_FAILURE) { if (MP_RX_AGGR_IN_PROGRESS(pmadapter)) { /* MP-A transfer failed - cleanup */ for (pind = 0; pind < pmadapter->mpa_rx.pkt_cnt; pind++) { wlan_free_mlan_buffer(pmadapter, pmadapter->mpa_rx. mbuf_arr[pind]); } MP_RX_AGGR_BUF_RESET(pmadapter); } if (f_do_rx_cur) { /* Single Transfer pending */ /* Free curr buff also */ wlan_free_mlan_buffer(pmadapter, pmbuf); } } LEAVE(); return ret; }