aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/libertas/if_cs.c
diff options
context:
space:
mode:
authorHolger Schurig <hs4233@mail.mn-solutions.de>2008-04-01 08:50:43 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-04-16 15:59:56 -0400
commit7919b89c8276d657976d4d4d6b7cb58ea1aa08c3 (patch)
tree31fc24e2f8b7d8eeee67347333e078591796d4b7 /drivers/net/wireless/libertas/if_cs.c
parent98dd6a575928ed9c42130d208e6bfb0f7a914d5a (diff)
libertas: convert libertas driver to use an event/cmdresp queue
This patch (co-developed by Dan Williams and Holger Schurig) uses a kfifo object for events and a swapping buffer scheme for the command response to preserve the zero-copy semantics of the CF driver and keep memory usage low. The main thread should only ever touch the buffer indexed by priv->resp_idx, while the interface code is free to write to the second buffer, then swap priv->resp_idx under the driver spinlock. The firmware specs only permit one in-flight command, so there will only ever be one command response to process at a time. Signed-off-by: Holger Schurig <hs4233@mail.mn-solutions.de> Signed-off-by: Dan Williams <dcbw@redhat.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/libertas/if_cs.c')
-rw-r--r--drivers/net/wireless/libertas/if_cs.c244
1 files changed, 105 insertions, 139 deletions
diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
index 53afebac7146..54280e292ea5 100644
--- a/drivers/net/wireless/libertas/if_cs.c
+++ b/drivers/net/wireless/libertas/if_cs.c
@@ -83,14 +83,14 @@ static inline unsigned int if_cs_read8(struct if_cs_card *card, uint reg)
83{ 83{
84 unsigned int val = ioread8(card->iobase + reg); 84 unsigned int val = ioread8(card->iobase + reg);
85 if (debug_output) 85 if (debug_output)
86 printk(KERN_INFO "##inb %08x<%02x\n", reg, val); 86 printk(KERN_INFO "inb %08x<%02x\n", reg, val);
87 return val; 87 return val;
88} 88}
89static inline unsigned int if_cs_read16(struct if_cs_card *card, uint reg) 89static inline unsigned int if_cs_read16(struct if_cs_card *card, uint reg)
90{ 90{
91 unsigned int val = ioread16(card->iobase + reg); 91 unsigned int val = ioread16(card->iobase + reg);
92 if (debug_output) 92 if (debug_output)
93 printk(KERN_INFO "##inw %08x<%04x\n", reg, val); 93 printk(KERN_INFO "inw %08x<%04x\n", reg, val);
94 return val; 94 return val;
95} 95}
96static inline void if_cs_read16_rep( 96static inline void if_cs_read16_rep(
@@ -100,7 +100,7 @@ static inline void if_cs_read16_rep(
100 unsigned long count) 100 unsigned long count)
101{ 101{
102 if (debug_output) 102 if (debug_output)
103 printk(KERN_INFO "##insw %08x<(0x%lx words)\n", 103 printk(KERN_INFO "insw %08x<(0x%lx words)\n",
104 reg, count); 104 reg, count);
105 ioread16_rep(card->iobase + reg, buf, count); 105 ioread16_rep(card->iobase + reg, buf, count);
106} 106}
@@ -108,14 +108,14 @@ static inline void if_cs_read16_rep(
108static inline void if_cs_write8(struct if_cs_card *card, uint reg, u8 val) 108static inline void if_cs_write8(struct if_cs_card *card, uint reg, u8 val)
109{ 109{
110 if (debug_output) 110 if (debug_output)
111 printk(KERN_INFO "##outb %08x>%02x\n", reg, val); 111 printk(KERN_INFO "outb %08x>%02x\n", reg, val);
112 iowrite8(val, card->iobase + reg); 112 iowrite8(val, card->iobase + reg);
113} 113}
114 114
115static inline void if_cs_write16(struct if_cs_card *card, uint reg, u16 val) 115static inline void if_cs_write16(struct if_cs_card *card, uint reg, u16 val)
116{ 116{
117 if (debug_output) 117 if (debug_output)
118 printk(KERN_INFO "##outw %08x>%04x\n", reg, val); 118 printk(KERN_INFO "outw %08x>%04x\n", reg, val);
119 iowrite16(val, card->iobase + reg); 119 iowrite16(val, card->iobase + reg);
120} 120}
121 121
@@ -126,7 +126,7 @@ static inline void if_cs_write16_rep(
126 unsigned long count) 126 unsigned long count)
127{ 127{
128 if (debug_output) 128 if (debug_output)
129 printk(KERN_INFO "##outsw %08x>(0x%lx words)\n", 129 printk(KERN_INFO "outsw %08x>(0x%lx words)\n",
130 reg, count); 130 reg, count);
131 iowrite16_rep(card->iobase + reg, buf, count); 131 iowrite16_rep(card->iobase + reg, buf, count);
132} 132}
@@ -199,17 +199,6 @@ static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 r
199#define IF_CS_C_S_CARDEVENT 0x0010 199#define IF_CS_C_S_CARDEVENT 0x0010
200#define IF_CS_C_S_MASK 0x001f 200#define IF_CS_C_S_MASK 0x001f
201#define IF_CS_C_S_STATUS_MASK 0x7f00 201#define IF_CS_C_S_STATUS_MASK 0x7f00
202/* The following definitions should be the same as the MRVDRV_ ones */
203
204#if MRVDRV_CMD_DNLD_RDY != IF_CS_C_S_CMD_DNLD_RDY
205#error MRVDRV_CMD_DNLD_RDY and IF_CS_C_S_CMD_DNLD_RDY not in sync
206#endif
207#if MRVDRV_CMD_UPLD_RDY != IF_CS_C_S_CMD_UPLD_RDY
208#error MRVDRV_CMD_UPLD_RDY and IF_CS_C_S_CMD_UPLD_RDY not in sync
209#endif
210#if MRVDRV_CARDEVENT != IF_CS_C_S_CARDEVENT
211#error MRVDRV_CARDEVENT and IF_CS_C_S_CARDEVENT not in sync
212#endif
213 202
214#define IF_CS_C_INT_CAUSE 0x00000022 203#define IF_CS_C_INT_CAUSE 0x00000022
215#define IF_CS_C_IC_MASK 0x001f 204#define IF_CS_C_IC_MASK 0x001f
@@ -226,55 +215,6 @@ static int if_cs_poll_while_fw_download(struct if_cs_card *card, uint addr, u8 r
226 215
227 216
228/********************************************************************/ 217/********************************************************************/
229/* Interrupts */
230/********************************************************************/
231
232static inline void if_cs_enable_ints(struct if_cs_card *card)
233{
234 lbs_deb_enter(LBS_DEB_CS);
235 if_cs_write16(card, IF_CS_H_INT_MASK, 0);
236}
237
238static inline void if_cs_disable_ints(struct if_cs_card *card)
239{
240 lbs_deb_enter(LBS_DEB_CS);
241 if_cs_write16(card, IF_CS_H_INT_MASK, IF_CS_H_IM_MASK);
242}
243
244static irqreturn_t if_cs_interrupt(int irq, void *data)
245{
246 struct if_cs_card *card = data;
247 u16 int_cause;
248
249 lbs_deb_enter(LBS_DEB_CS);
250
251 int_cause = if_cs_read16(card, IF_CS_C_INT_CAUSE);
252 if (int_cause == 0x0) {
253 /* Not for us */
254 return IRQ_NONE;
255
256 } else if (int_cause == 0xffff) {
257 /* Read in junk, the card has probably been removed */
258 card->priv->surpriseremoved = 1;
259 return IRQ_HANDLED;
260 } else {
261 if (int_cause & IF_CS_H_IC_TX_OVER)
262 lbs_host_to_card_done(card->priv);
263
264 /* clear interrupt */
265 if_cs_write16(card, IF_CS_C_INT_CAUSE, int_cause & IF_CS_C_IC_MASK);
266 }
267 spin_lock(&card->priv->driver_lock);
268 lbs_interrupt(card->priv);
269 spin_unlock(&card->priv->driver_lock);
270
271 return IRQ_HANDLED;
272}
273
274
275
276
277/********************************************************************/
278/* I/O */ 218/* I/O */
279/********************************************************************/ 219/********************************************************************/
280 220
@@ -351,6 +291,7 @@ static void if_cs_send_data(struct lbs_private *priv, u8 *buf, u16 nb)
351 */ 291 */
352static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len) 292static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len)
353{ 293{
294 unsigned long flags;
354 int ret = -1; 295 int ret = -1;
355 u16 val; 296 u16 val;
356 297
@@ -378,6 +319,12 @@ static int if_cs_receive_cmdres(struct lbs_private *priv, u8 *data, u32 *len)
378 * bytes */ 319 * bytes */
379 *len -= 8; 320 *len -= 8;
380 ret = 0; 321 ret = 0;
322
323 /* Clear this flag again */
324 spin_lock_irqsave(&priv->driver_lock, flags);
325 priv->dnld_sent = DNLD_RES_RECEIVED;
326 spin_unlock_irqrestore(&priv->driver_lock, flags);
327
381out: 328out:
382 lbs_deb_leave_args(LBS_DEB_CS, "ret %d, len %d", ret, *len); 329 lbs_deb_leave_args(LBS_DEB_CS, "ret %d, len %d", ret, *len);
383 return ret; 330 return ret;
@@ -396,11 +343,9 @@ static struct sk_buff *if_cs_receive_data(struct lbs_private *priv)
396 if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) { 343 if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
397 lbs_pr_err("card data buffer has invalid # of bytes (%d)\n", len); 344 lbs_pr_err("card data buffer has invalid # of bytes (%d)\n", len);
398 priv->stats.rx_dropped++; 345 priv->stats.rx_dropped++;
399 printk(KERN_INFO "##HS %s:%d TODO\n", __FUNCTION__, __LINE__);
400 goto dat_err; 346 goto dat_err;
401 } 347 }
402 348
403 //TODO: skb = dev_alloc_skb(len+ETH_FRAME_LEN+MRVDRV_SNAP_HEADER_LEN+EXTRA_LEN);
404 skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + 2); 349 skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + 2);
405 if (!skb) 350 if (!skb)
406 goto out; 351 goto out;
@@ -425,6 +370,96 @@ out:
425 370
426 371
427/********************************************************************/ 372/********************************************************************/
373/* Interrupts */
374/********************************************************************/
375
376static inline void if_cs_enable_ints(struct if_cs_card *card)
377{
378 lbs_deb_enter(LBS_DEB_CS);
379 if_cs_write16(card, IF_CS_H_INT_MASK, 0);
380}
381
382static inline void if_cs_disable_ints(struct if_cs_card *card)
383{
384 lbs_deb_enter(LBS_DEB_CS);
385 if_cs_write16(card, IF_CS_H_INT_MASK, IF_CS_H_IM_MASK);
386}
387
388
389static irqreturn_t if_cs_interrupt(int irq, void *data)
390{
391 struct if_cs_card *card = data;
392 struct lbs_private *priv = card->priv;
393 u16 cause;
394
395 lbs_deb_enter(LBS_DEB_CS);
396
397 cause = if_cs_read16(card, IF_CS_C_INT_CAUSE);
398 if_cs_write16(card, IF_CS_C_INT_CAUSE, cause & IF_CS_C_IC_MASK);
399
400 lbs_deb_cs("cause 0x%04x\n", cause);
401 if (cause == 0) {
402 /* Not for us */
403 return IRQ_NONE;
404 }
405
406 if (cause == 0xffff) {
407 /* Read in junk, the card has probably been removed */
408 card->priv->surpriseremoved = 1;
409 return IRQ_HANDLED;
410 }
411
412 /* TODO: I'm not sure what the best ordering is */
413
414 cause = if_cs_read16(card, IF_CS_C_STATUS) & IF_CS_C_S_MASK;
415
416 if (cause & IF_CS_C_S_RX_UPLD_RDY) {
417 struct sk_buff *skb;
418 lbs_deb_cs("rx packet\n");
419 skb = if_cs_receive_data(priv);
420 if (skb)
421 lbs_process_rxed_packet(priv, skb);
422 }
423
424 if (cause & IF_CS_H_IC_TX_OVER) {
425 lbs_deb_cs("tx over\n");
426 lbs_host_to_card_done(priv);
427 }
428
429 if (cause & IF_CS_C_S_CMD_UPLD_RDY) {
430 unsigned long flags;
431 u8 i;
432
433 lbs_deb_cs("cmd upload ready\n");
434 spin_lock_irqsave(&priv->driver_lock, flags);
435 i = (priv->resp_idx == 0) ? 1 : 0;
436 spin_unlock_irqrestore(&priv->driver_lock, flags);
437
438 BUG_ON(priv->resp_len[i]);
439 if_cs_receive_cmdres(priv, priv->resp_buf[i],
440 &priv->resp_len[i]);
441
442 spin_lock_irqsave(&priv->driver_lock, flags);
443 lbs_notify_command_response(priv, i);
444 spin_unlock_irqrestore(&priv->driver_lock, flags);
445 }
446
447 if (cause & IF_CS_H_IC_HOST_EVENT) {
448 u16 event = if_cs_read16(priv->card, IF_CS_C_STATUS)
449 & IF_CS_C_S_STATUS_MASK;
450 if_cs_write16(priv->card, IF_CS_H_INT_CAUSE,
451 IF_CS_H_IC_HOST_EVENT);
452 lbs_deb_cs("eventcause 0x%04x\n", event);
453 lbs_queue_event(priv, event >> 8 & 0xff);
454 }
455
456 return IRQ_HANDLED;
457}
458
459
460
461
462/********************************************************************/
428/* Firmware */ 463/* Firmware */
429/********************************************************************/ 464/********************************************************************/
430 465
@@ -476,8 +511,6 @@ static int if_cs_prog_helper(struct if_cs_card *card)
476 511
477 if (remain < count) 512 if (remain < count)
478 count = remain; 513 count = remain;
479 /* printk(KERN_INFO "//HS %d loading %d of %d bytes\n",
480 __LINE__, sent, fw->size); */
481 514
482 /* "write the number of bytes to be sent to the I/O Command 515 /* "write the number of bytes to be sent to the I/O Command
483 * write length register" */ 516 * write length register" */
@@ -544,18 +577,12 @@ static int if_cs_prog_real(struct if_cs_card *card)
544 577
545 ret = if_cs_poll_while_fw_download(card, IF_CS_C_SQ_READ_LOW, IF_CS_C_SQ_HELPER_OK); 578 ret = if_cs_poll_while_fw_download(card, IF_CS_C_SQ_READ_LOW, IF_CS_C_SQ_HELPER_OK);
546 if (ret < 0) { 579 if (ret < 0) {
547 int i;
548 lbs_pr_err("helper firmware doesn't answer\n"); 580 lbs_pr_err("helper firmware doesn't answer\n");
549 for (i = 0; i < 0x50; i += 2)
550 printk(KERN_INFO "## HS %02x: %04x\n",
551 i, if_cs_read16(card, i));
552 goto err_release; 581 goto err_release;
553 } 582 }
554 583
555 for (sent = 0; sent < fw->size; sent += len) { 584 for (sent = 0; sent < fw->size; sent += len) {
556 len = if_cs_read16(card, IF_CS_C_SQ_READ_LOW); 585 len = if_cs_read16(card, IF_CS_C_SQ_READ_LOW);
557 /* printk(KERN_INFO "//HS %d loading %d of %d bytes\n",
558 __LINE__, sent, fw->size); */
559 if (len & 1) { 586 if (len & 1) {
560 retry++; 587 retry++;
561 lbs_pr_info("odd, need to retry this firmware block\n"); 588 lbs_pr_info("odd, need to retry this firmware block\n");
@@ -642,64 +669,6 @@ static int if_cs_host_to_card(struct lbs_private *priv,
642} 669}
643 670
644 671
645static int if_cs_get_int_status(struct lbs_private *priv, u8 *ireg)
646{
647 struct if_cs_card *card = (struct if_cs_card *)priv->card;
648 int ret = 0;
649 u16 int_cause;
650 *ireg = 0;
651
652 lbs_deb_enter(LBS_DEB_CS);
653
654 if (priv->surpriseremoved)
655 goto out;
656
657 int_cause = if_cs_read16(card, IF_CS_C_INT_CAUSE) & IF_CS_C_IC_MASK;
658 if_cs_write16(card, IF_CS_C_INT_CAUSE, int_cause);
659
660 *ireg = if_cs_read16(card, IF_CS_C_STATUS) & IF_CS_C_S_MASK;
661
662 if (!*ireg)
663 goto sbi_get_int_status_exit;
664
665sbi_get_int_status_exit:
666
667 /* is there a data packet for us? */
668 if (*ireg & IF_CS_C_S_RX_UPLD_RDY) {
669 struct sk_buff *skb = if_cs_receive_data(priv);
670 lbs_process_rxed_packet(priv, skb);
671 *ireg &= ~IF_CS_C_S_RX_UPLD_RDY;
672 }
673
674 if (*ireg & IF_CS_C_S_TX_DNLD_RDY) {
675 priv->dnld_sent = DNLD_RES_RECEIVED;
676 }
677
678 /* Card has a command result for us */
679 if (*ireg & IF_CS_C_S_CMD_UPLD_RDY) {
680 ret = if_cs_receive_cmdres(priv, priv->upld_buf, &priv->upld_len);
681 if (ret < 0)
682 lbs_pr_err("could not receive cmd from card\n");
683 }
684
685out:
686 lbs_deb_leave_args(LBS_DEB_CS, "ret %d, ireg 0x%x, hisregcpy 0x%x", ret, *ireg, priv->hisregcpy);
687 return ret;
688}
689
690
691static int if_cs_read_event_cause(struct lbs_private *priv)
692{
693 lbs_deb_enter(LBS_DEB_CS);
694
695 priv->eventcause = (if_cs_read16(priv->card, IF_CS_C_STATUS) & IF_CS_C_S_STATUS_MASK) >> 5;
696 if_cs_write16(priv->card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_HOST_EVENT);
697
698 return 0;
699}
700
701
702
703/********************************************************************/ 672/********************************************************************/
704/* Card Services */ 673/* Card Services */
705/********************************************************************/ 674/********************************************************************/
@@ -852,13 +821,10 @@ static int if_cs_probe(struct pcmcia_device *p_dev)
852 goto out2; 821 goto out2;
853 } 822 }
854 823
855 /* Store pointers to our call-back functions */ 824 /* Finish setting up fields in lbs_private */
856 card->priv = priv; 825 card->priv = priv;
857 priv->card = card; 826 priv->card = card;
858 priv->hw_host_to_card = if_cs_host_to_card; 827 priv->hw_host_to_card = if_cs_host_to_card;
859 priv->hw_get_int_status = if_cs_get_int_status;
860 priv->hw_read_event_cause = if_cs_read_event_cause;
861
862 priv->fw_ready = 1; 828 priv->fw_ready = 1;
863 829
864 /* Now actually get the IRQ */ 830 /* Now actually get the IRQ */