diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-trans.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-trans.c | 78 |
1 files changed, 59 insertions, 19 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.c b/drivers/net/wireless/iwlwifi/iwl-trans.c index ccf73ff63956..1f5834b8a639 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans.c | |||
@@ -60,7 +60,7 @@ | |||
60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 60 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
61 | * | 61 | * |
62 | *****************************************************************************/ | 62 | *****************************************************************************/ |
63 | #include "iwl-dev.h" | 63 | #include "iwl-dev.h" |
64 | #include "iwl-trans.h" | 64 | #include "iwl-trans.h" |
65 | 65 | ||
66 | static int iwl_trans_rx_alloc(struct iwl_priv *priv) | 66 | static int iwl_trans_rx_alloc(struct iwl_priv *priv) |
@@ -78,12 +78,11 @@ static int iwl_trans_rx_alloc(struct iwl_priv *priv) | |||
78 | return -EINVAL; | 78 | return -EINVAL; |
79 | 79 | ||
80 | /* Allocate the circular buffer of Read Buffer Descriptors (RBDs) */ | 80 | /* Allocate the circular buffer of Read Buffer Descriptors (RBDs) */ |
81 | /*Every descriptor is an __le32, hence its */ | 81 | rxq->bd = dma_alloc_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE, |
82 | rxq->bd = dma_alloc_coherent(dev, 4 * RX_QUEUE_SIZE, &rxq->bd_dma, | 82 | &rxq->bd_dma, GFP_KERNEL); |
83 | GFP_KERNEL); | ||
84 | if (!rxq->bd) | 83 | if (!rxq->bd) |
85 | goto err_bd; | 84 | goto err_bd; |
86 | memset(rxq->bd, 0, 4 * RX_QUEUE_SIZE); | 85 | memset(rxq->bd, 0, sizeof(__le32) * RX_QUEUE_SIZE); |
87 | 86 | ||
88 | /*Allocate the driver's pointer to receive buffer status */ | 87 | /*Allocate the driver's pointer to receive buffer status */ |
89 | rxq->rb_stts = dma_alloc_coherent(dev, sizeof(*rxq->rb_stts), | 88 | rxq->rb_stts = dma_alloc_coherent(dev, sizeof(*rxq->rb_stts), |
@@ -95,28 +94,18 @@ static int iwl_trans_rx_alloc(struct iwl_priv *priv) | |||
95 | return 0; | 94 | return 0; |
96 | 95 | ||
97 | err_rb_stts: | 96 | err_rb_stts: |
98 | dma_free_coherent(dev, 4 * RX_QUEUE_SIZE, rxq->bd, rxq->bd_dma); | 97 | dma_free_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE, |
98 | rxq->bd, rxq->bd_dma); | ||
99 | memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma)); | 99 | memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma)); |
100 | rxq->bd = NULL; | 100 | rxq->bd = NULL; |
101 | err_bd: | 101 | err_bd: |
102 | return -ENOMEM; | 102 | return -ENOMEM; |
103 | } | 103 | } |
104 | 104 | ||
105 | static int iwl_trans_rx_init(struct iwl_priv *priv) | 105 | static void iwl_trans_rxq_free_rx_bufs(struct iwl_priv *priv) |
106 | { | 106 | { |
107 | struct iwl_rx_queue *rxq = &priv->rxq; | 107 | struct iwl_rx_queue *rxq = &priv->rxq; |
108 | int i, err; | 108 | int i; |
109 | unsigned long flags; | ||
110 | |||
111 | if (!rxq->bd) { | ||
112 | err = iwl_trans_rx_alloc(priv); | ||
113 | if (err) | ||
114 | return err; | ||
115 | } | ||
116 | |||
117 | spin_lock_irqsave(&rxq->lock, flags); | ||
118 | INIT_LIST_HEAD(&rxq->rx_free); | ||
119 | INIT_LIST_HEAD(&rxq->rx_used); | ||
120 | 109 | ||
121 | /* Fill the rx_used queue with _all_ of the Rx buffers */ | 110 | /* Fill the rx_used queue with _all_ of the Rx buffers */ |
122 | for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) { | 111 | for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) { |
@@ -131,6 +120,25 @@ static int iwl_trans_rx_init(struct iwl_priv *priv) | |||
131 | } | 120 | } |
132 | list_add_tail(&rxq->pool[i].list, &rxq->rx_used); | 121 | list_add_tail(&rxq->pool[i].list, &rxq->rx_used); |
133 | } | 122 | } |
123 | } | ||
124 | |||
125 | static int iwl_trans_rx_init(struct iwl_priv *priv) | ||
126 | { | ||
127 | struct iwl_rx_queue *rxq = &priv->rxq; | ||
128 | int i, err; | ||
129 | unsigned long flags; | ||
130 | |||
131 | if (!rxq->bd) { | ||
132 | err = iwl_trans_rx_alloc(priv); | ||
133 | if (err) | ||
134 | return err; | ||
135 | } | ||
136 | |||
137 | spin_lock_irqsave(&rxq->lock, flags); | ||
138 | INIT_LIST_HEAD(&rxq->rx_free); | ||
139 | INIT_LIST_HEAD(&rxq->rx_used); | ||
140 | |||
141 | iwl_trans_rxq_free_rx_bufs(priv); | ||
134 | 142 | ||
135 | for (i = 0; i < RX_QUEUE_SIZE; i++) | 143 | for (i = 0; i < RX_QUEUE_SIZE; i++) |
136 | rxq->queue[i] = NULL; | 144 | rxq->queue[i] = NULL; |
@@ -145,8 +153,40 @@ static int iwl_trans_rx_init(struct iwl_priv *priv) | |||
145 | return 0; | 153 | return 0; |
146 | } | 154 | } |
147 | 155 | ||
156 | static void iwl_trans_rx_free(struct iwl_priv *priv) | ||
157 | { | ||
158 | struct iwl_rx_queue *rxq = &priv->rxq; | ||
159 | unsigned long flags; | ||
160 | |||
161 | /*if rxq->bd is NULL, it means that nothing has been allocated, | ||
162 | * exit now */ | ||
163 | if (!rxq->bd) { | ||
164 | IWL_DEBUG_INFO(priv, "Free NULL rx context\n"); | ||
165 | return; | ||
166 | } | ||
167 | |||
168 | spin_lock_irqsave(&rxq->lock, flags); | ||
169 | iwl_trans_rxq_free_rx_bufs(priv); | ||
170 | spin_unlock_irqrestore(&rxq->lock, flags); | ||
171 | |||
172 | dma_free_coherent(priv->bus.dev, sizeof(__le32) * RX_QUEUE_SIZE, | ||
173 | rxq->bd, rxq->bd_dma); | ||
174 | memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma)); | ||
175 | rxq->bd = NULL; | ||
176 | |||
177 | if (rxq->rb_stts) | ||
178 | dma_free_coherent(priv->bus.dev, | ||
179 | sizeof(struct iwl_rb_status), | ||
180 | rxq->rb_stts, rxq->rb_stts_dma); | ||
181 | else | ||
182 | IWL_DEBUG_INFO(priv, "Free rxq->rb_stts which is NULL\n"); | ||
183 | memset(&rxq->rb_stts_dma, 0, sizeof(rxq->rb_stts_dma)); | ||
184 | rxq->rb_stts = NULL; | ||
185 | } | ||
186 | |||
148 | static const struct iwl_trans_ops trans_ops = { | 187 | static const struct iwl_trans_ops trans_ops = { |
149 | .rx_init = iwl_trans_rx_init, | 188 | .rx_init = iwl_trans_rx_init, |
189 | .rx_free = iwl_trans_rx_free, | ||
150 | }; | 190 | }; |
151 | 191 | ||
152 | void iwl_trans_register(struct iwl_trans *trans) | 192 | void iwl_trans_register(struct iwl_trans *trans) |