Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 300640
b: refs/heads/master
c: 0c19744
h: refs/heads/master
v: v3
  • Loading branch information
Johannes Berg authored and John W. Linville committed Apr 9, 2012
1 parent 9fe37c0 commit 0d9712a
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 65 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 88f10a176c7364a700c8638732e2b3110beaceb6
refs/heads/master: 0c19744c344cf1bfda04f681ff4e1e46455577bd
2 changes: 1 addition & 1 deletion trunk/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
Original file line number Diff line number Diff line change
Expand Up @@ -794,7 +794,7 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv,
return;
}

offset = (void *)hdr - rxb_addr(rxb);
offset = (void *)hdr - rxb_addr(rxb) + rxb_offset(rxb);
p = rxb_steal_page(rxb);
skb_add_rx_frag(skb, 0, p, offset, len, len);

Expand Down
129 changes: 71 additions & 58 deletions trunk/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
Original file line number Diff line number Diff line change
Expand Up @@ -362,83 +362,96 @@ static void iwl_rx_handle_rxbuf(struct iwl_trans *trans,
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_rx_queue *rxq = &trans_pcie->rxq;
struct iwl_tx_queue *txq = &trans_pcie->txq[trans_pcie->cmd_queue];
struct iwl_device_cmd *cmd;
unsigned long flags;
int len, err;
u16 sequence;
struct iwl_rx_cmd_buffer rxcb;
struct iwl_rx_packet *pkt;
bool reclaim;
int index, cmd_index;
bool page_stolen = false;
int max_len = PAGE_SIZE << hw_params(trans).rx_page_order;
u32 offset = 0;

if (WARN_ON(!rxb))
return;

dma_unmap_page(trans->dev, rxb->page_dma,
PAGE_SIZE << hw_params(trans).rx_page_order,
DMA_FROM_DEVICE);
dma_unmap_page(trans->dev, rxb->page_dma, max_len, DMA_FROM_DEVICE);

rxcb._page = rxb->page;
pkt = rxb_addr(&rxcb);
while (offset + sizeof(u32) + sizeof(struct iwl_cmd_header) < max_len) {
struct iwl_rx_packet *pkt;
struct iwl_device_cmd *cmd;
u16 sequence;
bool reclaim;
int index, cmd_index, err, len;
struct iwl_rx_cmd_buffer rxcb = {
._offset = offset,
._page = rxb->page,
._page_stolen = false,
};

IWL_DEBUG_RX(trans, "%s, 0x%02x\n",
get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd);
pkt = rxb_addr(&rxcb);

if (pkt->len_n_flags == cpu_to_le32(FH_RSCSR_FRAME_INVALID))
break;

len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
len += sizeof(u32); /* account for status word */
trace_iwlwifi_dev_rx(trans->dev, pkt, len);

/* Reclaim a command buffer only if this packet is a response
* to a (driver-originated) command.
* If the packet (e.g. Rx frame) originated from uCode,
* there is no command buffer to reclaim.
* Ucode should set SEQ_RX_FRAME bit if ucode-originated,
* but apparently a few don't get set; catch them here. */
reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME);
if (reclaim) {
int i;

for (i = 0; i < trans_pcie->n_no_reclaim_cmds; i++) {
if (trans_pcie->no_reclaim_cmds[i] == pkt->hdr.cmd) {
reclaim = false;
break;
IWL_DEBUG_RX(trans, "cmd at offset %d: %s (0x%.2x)\n",
rxcb._offset, get_cmd_string(pkt->hdr.cmd),
pkt->hdr.cmd);

len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
len += sizeof(u32); /* account for status word */
trace_iwlwifi_dev_rx(trans->dev, pkt, len);

/* Reclaim a command buffer only if this packet is a response
* to a (driver-originated) command.
* If the packet (e.g. Rx frame) originated from uCode,
* there is no command buffer to reclaim.
* Ucode should set SEQ_RX_FRAME bit if ucode-originated,
* but apparently a few don't get set; catch them here. */
reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME);
if (reclaim) {
int i;

for (i = 0; i < trans_pcie->n_no_reclaim_cmds; i++) {
if (trans_pcie->no_reclaim_cmds[i] ==
pkt->hdr.cmd) {
reclaim = false;
break;
}
}
}
}

sequence = le16_to_cpu(pkt->hdr.sequence);
index = SEQ_TO_INDEX(sequence);
cmd_index = get_cmd_index(&txq->q, index);
sequence = le16_to_cpu(pkt->hdr.sequence);
index = SEQ_TO_INDEX(sequence);
cmd_index = get_cmd_index(&txq->q, index);

if (reclaim)
cmd = txq->cmd[cmd_index];
else
cmd = NULL;
if (reclaim)
cmd = txq->cmd[cmd_index];
else
cmd = NULL;

err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd);
err = iwl_op_mode_rx(trans->op_mode, &rxcb, cmd);

/*
* XXX: After here, we should always check rxcb._page
* against NULL before touching it or its virtual
* memory (pkt). Because some rx_handler might have
* already taken or freed the pages.
*/
/*
* After here, we should always check rxcb._page_stolen,
* if it is true then one of the handlers took the page.
*/

if (reclaim) {
/* Invoke any callbacks, transfer the buffer to caller,
* and fire off the (possibly) blocking
* iwl_trans_send_cmd()
* as we reclaim the driver command queue */
if (rxcb._page)
iwl_tx_cmd_complete(trans, &rxcb, err);
else
IWL_WARN(trans, "Claim null rxb?\n");
if (reclaim) {
/* Invoke any callbacks, transfer the buffer to caller,
* and fire off the (possibly) blocking
* iwl_trans_send_cmd()
* as we reclaim the driver command queue */
if (!rxcb._page_stolen)
iwl_tx_cmd_complete(trans, &rxcb, err);
else
IWL_WARN(trans, "Claim null rxb?\n");
}

page_stolen |= rxcb._page_stolen;
offset += ALIGN(len, FH_RSCSR_FRAME_ALIGN);
}

/* page was stolen from us */
if (rxcb._page == NULL)
/* page was stolen from us -- free our reference */
if (page_stolen) {
__free_pages(rxb->page, hw_params(trans).rx_page_order);
rxb->page = NULL;
}

/* Reuse the page if possible. For notification packets and
* SKBs that fail to Rx correctly, add them back into the
Expand Down
1 change: 0 additions & 1 deletion trunk/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,6 @@ static void iwl_trans_rx_hw_init(struct iwl_trans *trans,
FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY |
FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MSK |
rb_size|
(rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)|
(rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS));
Expand Down
17 changes: 13 additions & 4 deletions trunk/drivers/net/wireless/iwlwifi/iwl-trans.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ struct iwl_cmd_header {


#define FH_RSCSR_FRAME_SIZE_MSK 0x00003FFF /* bits 0-13 */
#define FH_RSCSR_FRAME_INVALID 0x55550000
#define FH_RSCSR_FRAME_ALIGN 0x40

struct iwl_rx_packet {
/*
Expand Down Expand Up @@ -260,18 +262,25 @@ static inline void iwl_free_resp(struct iwl_host_cmd *cmd)

struct iwl_rx_cmd_buffer {
struct page *_page;
int _offset;
bool _page_stolen;
};

static inline void *rxb_addr(struct iwl_rx_cmd_buffer *r)
{
return page_address(r->_page);
return (void *)((unsigned long)page_address(r->_page) + r->_offset);
}

static inline int rxb_offset(struct iwl_rx_cmd_buffer *r)
{
return r->_offset;
}

static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r)
{
struct page *p = r->_page;
r->_page = NULL;
return p;
r->_page_stolen = true;
get_page(r->_page);
return r->_page;
}

#define MAX_NO_RECLAIM_CMDS 6
Expand Down

0 comments on commit 0d9712a

Please sign in to comment.