The old code misbehaved because it polled card status and always called the "tx over" code-path. The old code killed the driver/firmware after some time when doing constant data transfer while running firmware commands at the same time, (e.g. with "watch iwconfig eth1"). Also unify the mess of constants. Signed-off-by: Holger Schurig <hs4233@xxxxxxxxxxxxxxxxxxxx> Index: wireless-testing/drivers/net/wireless/libertas/if_cs.c =================================================================== --- wireless-testing.orig/drivers/net/wireless/libertas/if_cs.c 2008-05-19 14:34:53.000000000 +0200 +++ wireless-testing/drivers/net/wireless/libertas/if_cs.c 2008-05-19 15:51:49.000000000 +0200 @@ -159,56 +159,41 @@ static int if_cs_poll_while_fw_download( -/* Host control registers and their bit definitions */ - -#define IF_CS_H_STATUS 0x00000000 -#define IF_CS_H_STATUS_TX_OVER 0x0001 -#define IF_CS_H_STATUS_RX_OVER 0x0002 -#define IF_CS_H_STATUS_DNLD_OVER 0x0004 - -#define IF_CS_H_INT_CAUSE 0x00000002 -#define IF_CS_H_IC_TX_OVER 0x0001 -#define IF_CS_H_IC_RX_OVER 0x0002 -#define IF_CS_H_IC_DNLD_OVER 0x0004 -#define IF_CS_H_IC_POWER_DOWN 0x0008 -#define IF_CS_H_IC_HOST_EVENT 0x0010 -#define IF_CS_H_IC_MASK 0x001f - -#define IF_CS_H_INT_MASK 0x00000004 -#define IF_CS_H_IM_MASK 0x001f - -#define IF_CS_H_WRITE_LEN 0x00000014 - -#define IF_CS_H_WRITE 0x00000016 +/* First the bitmasks for the host/card interrupt/status registers: */ +#define IF_CS_TX_OVER 0x0001 +#define IF_CS_RX_OVER 0x0002 +#define IF_CS_CMD_DNLD_OVER 0x0004 +#define IF_CS_CMD_UPLD_OVER 0x0008 +#define IF_CS_HOST_EVENT 0x0010 -#define IF_CS_H_CMD_LEN 0x00000018 +/* And now the individual registers and assorted masks */ +#define IF_CS_HOST_STATUS 0x00000000 -#define IF_CS_H_CMD 0x0000001A +#define IF_CS_HOST_INT_CAUSE 0x00000002 -#define IF_CS_C_READ_LEN 0x00000024 +#define IF_CS_HOST_INT_MASK 0x00000004 +#define IF_CS_HOST_IM_MASK 0x001f -#define IF_CS_H_READ 0x00000010 +#define IF_CS_HOST_WRITE 0x00000016 +#define IF_CS_HOST_WRITE_LEN 0x00000014 -/* Card control registers and their bit definitions */ +#define IF_CS_HOST_CMD 0x0000001A +#define IF_CS_HOST_CMD_LEN 0x00000018 -#define IF_CS_C_STATUS 0x00000020 -#define IF_CS_C_S_TX_DNLD_RDY 0x0001 -#define IF_CS_C_S_RX_UPLD_RDY 0x0002 -#define IF_CS_C_S_CMD_DNLD_RDY 0x0004 -#define IF_CS_C_S_CMD_UPLD_RDY 0x0008 -#define IF_CS_C_S_CARDEVENT 0x0010 -#define IF_CS_C_S_MASK 0x001f -#define IF_CS_C_S_STATUS_MASK 0x7f00 +#define IF_CS_READ 0x00000010 +#define IF_CS_READ_LEN 0x00000024 -#define IF_CS_C_INT_CAUSE 0x00000022 -#define IF_CS_C_IC_MASK 0x001f +#define IF_CS_CARD_CMD 0x00000012 +#define IF_CS_CARD_CMD_LEN 0x00000030 -#define IF_CS_C_SQ_READ_LOW 0x00000028 -#define IF_CS_C_SQ_HELPER_OK 0x10 +#define IF_CS_CARD_STATUS 0x00000020 +#define IF_CS_CARD_S_STATUS_MASK 0x7f00 -#define IF_CS_C_CMD_LEN 0x00000030 +#define IF_CS_CARD_INT_CAUSE 0x00000022 +#define IF_CS_CARD_IC_MASK 0x001f -#define IF_CS_C_CMD 0x00000012 +#define IF_CS_CARD_SQ_READ_LOW 0x00000028 +#define IF_CS_CARD_SQ_HELPER_OK 0x10 #define IF_CS_SCRATCH 0x0000003F @@ -231,8 +216,8 @@ static int if_cs_send_cmd(struct lbs_pri /* Is hardware ready? */ while (1) { - u16 val = if_cs_read16(card, IF_CS_C_STATUS); - if (val & IF_CS_C_S_CMD_DNLD_RDY) + u16 val = if_cs_read16(card, IF_CS_CARD_STATUS); + if (val & IF_CS_CMD_DNLD_OVER) break; if (++loops > 100) { lbs_pr_err("card not ready for commands\n"); @@ -241,20 +226,20 @@ static int if_cs_send_cmd(struct lbs_pri mdelay(1); } - if_cs_write16(card, IF_CS_H_CMD_LEN, nb); + if_cs_write16(card, IF_CS_HOST_CMD_LEN, nb); - if_cs_write16_rep(card, IF_CS_H_CMD, buf, nb / 2); + if_cs_write16_rep(card, IF_CS_HOST_CMD, buf, nb / 2); /* Are we supposed to transfer an odd amount of bytes? */ if (nb & 1) - if_cs_write8(card, IF_CS_H_CMD, buf[nb-1]); + if_cs_write8(card, IF_CS_HOST_CMD, buf[nb-1]); /* "Assert the download over interrupt command in the Host * status register" */ - if_cs_write16(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER); + if_cs_write16(card, IF_CS_HOST_STATUS, IF_CS_CMD_DNLD_OVER); /* "Assert the download over interrupt command in the Card * interrupt case register" */ - if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER); + if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_CMD_DNLD_OVER); ret = 0; done: @@ -272,15 +257,15 @@ static void if_cs_send_data(struct lbs_p lbs_deb_enter(LBS_DEB_CS); - if_cs_write16(card, IF_CS_H_WRITE_LEN, nb); + if_cs_write16(card, IF_CS_HOST_WRITE_LEN, nb); /* write even number of bytes, then odd byte if necessary */ - if_cs_write16_rep(card, IF_CS_H_WRITE, buf, nb / 2); + if_cs_write16_rep(card, IF_CS_HOST_WRITE, buf, nb / 2); if (nb & 1) - if_cs_write8(card, IF_CS_H_WRITE, buf[nb-1]); + if_cs_write8(card, IF_CS_HOST_WRITE, buf[nb-1]); - if_cs_write16(card, IF_CS_H_STATUS, IF_CS_H_STATUS_TX_OVER); - if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_STATUS_TX_OVER); + if_cs_write16(card, IF_CS_HOST_STATUS, IF_CS_TX_OVER); + if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_TX_OVER); lbs_deb_leave(LBS_DEB_CS); } @@ -293,27 +278,27 @@ static int if_cs_receive_cmdres(struct l { unsigned long flags; int ret = -1; - u16 val; + u16 status; lbs_deb_enter(LBS_DEB_CS); /* is hardware ready? */ - val = if_cs_read16(priv->card, IF_CS_C_STATUS); - if ((val & IF_CS_C_S_CMD_UPLD_RDY) == 0) { + status = if_cs_read16(priv->card, IF_CS_CARD_STATUS); + if ((status & IF_CS_CMD_UPLD_OVER) == 0) { lbs_pr_err("card not ready for CMD\n"); goto out; } - *len = if_cs_read16(priv->card, IF_CS_C_CMD_LEN); + *len = if_cs_read16(priv->card, IF_CS_CARD_CMD_LEN); if ((*len == 0) || (*len > LBS_CMD_BUFFER_SIZE)) { lbs_pr_err("card cmd buffer has invalid # of bytes (%d)\n", *len); goto out; } /* read even number of bytes, then odd byte if necessary */ - if_cs_read16_rep(priv->card, IF_CS_C_CMD, data, *len/sizeof(u16)); + if_cs_read16_rep(priv->card, IF_CS_CARD_CMD, data, *len/sizeof(u16)); if (*len & 1) - data[*len-1] = if_cs_read8(priv->card, IF_CS_C_CMD); + data[*len-1] = if_cs_read8(priv->card, IF_CS_CARD_CMD); /* This is a workaround for a firmware that reports too much * bytes */ @@ -339,7 +324,7 @@ static struct sk_buff *if_cs_receive_dat lbs_deb_enter(LBS_DEB_CS); - len = if_cs_read16(priv->card, IF_CS_C_READ_LEN); + len = if_cs_read16(priv->card, IF_CS_READ_LEN); if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) { lbs_pr_err("card data buffer has invalid # of bytes (%d)\n", len); priv->stats.rx_dropped++; @@ -354,13 +339,13 @@ static struct sk_buff *if_cs_receive_dat data = skb->data; /* read even number of bytes, then odd byte if necessary */ - if_cs_read16_rep(priv->card, IF_CS_H_READ, data, len/sizeof(u16)); + if_cs_read16_rep(priv->card, IF_CS_READ, data, len/sizeof(u16)); if (len & 1) - data[len-1] = if_cs_read8(priv->card, IF_CS_H_READ); + data[len-1] = if_cs_read8(priv->card, IF_CS_READ); dat_err: - if_cs_write16(priv->card, IF_CS_H_STATUS, IF_CS_H_STATUS_RX_OVER); - if_cs_write16(priv->card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_RX_OVER); + if_cs_write16(priv->card, IF_CS_HOST_STATUS, IF_CS_RX_OVER); + if_cs_write16(priv->card, IF_CS_HOST_INT_CAUSE, IF_CS_RX_OVER); out: lbs_deb_leave_args(LBS_DEB_CS, "ret %p", skb); @@ -376,13 +361,13 @@ out: static inline void if_cs_enable_ints(struct if_cs_card *card) { lbs_deb_enter(LBS_DEB_CS); - if_cs_write16(card, IF_CS_H_INT_MASK, 0); + if_cs_write16(card, IF_CS_HOST_INT_MASK, 0); } static inline void if_cs_disable_ints(struct if_cs_card *card) { lbs_deb_enter(LBS_DEB_CS); - if_cs_write16(card, IF_CS_H_INT_MASK, IF_CS_H_IM_MASK); + if_cs_write16(card, IF_CS_HOST_INT_MASK, IF_CS_HOST_IM_MASK); } @@ -394,26 +379,23 @@ static irqreturn_t if_cs_interrupt(int i lbs_deb_enter(LBS_DEB_CS); - cause = if_cs_read16(card, IF_CS_C_INT_CAUSE); - if_cs_write16(card, IF_CS_C_INT_CAUSE, cause & IF_CS_C_IC_MASK); - - lbs_deb_cs("cause 0x%04x\n", cause); + cause = if_cs_read16(card, IF_CS_CARD_INT_CAUSE); if (cause == 0) { /* Not for us */ return IRQ_NONE; } + /* Clear interrupt cause */ + if_cs_write16(card, IF_CS_CARD_INT_CAUSE, cause & IF_CS_CARD_IC_MASK); + lbs_deb_cs("cause 0x%04x\n", cause); + if (cause == 0xffff) { /* Read in junk, the card has probably been removed */ card->priv->surpriseremoved = 1; return IRQ_HANDLED; } - /* TODO: I'm not sure what the best ordering is */ - - cause = if_cs_read16(card, IF_CS_C_STATUS) & IF_CS_C_S_MASK; - - if (cause & IF_CS_C_S_RX_UPLD_RDY) { + if (cause & IF_CS_RX_OVER) { struct sk_buff *skb; lbs_deb_cs("rx packet\n"); skb = if_cs_receive_data(priv); @@ -421,16 +403,16 @@ static irqreturn_t if_cs_interrupt(int i lbs_process_rxed_packet(priv, skb); } - if (cause & IF_CS_H_IC_TX_OVER) { + if (cause & IF_CS_TX_OVER) { lbs_deb_cs("tx over\n"); lbs_host_to_card_done(priv); } - if (cause & IF_CS_C_S_CMD_UPLD_RDY) { + if (cause & IF_CS_CMD_UPLD_OVER) { unsigned long flags; u8 i; - lbs_deb_cs("cmd upload ready\n"); + lbs_deb_cs("cmd upload over\n"); spin_lock_irqsave(&priv->driver_lock, flags); i = (priv->resp_idx == 0) ? 1 : 0; spin_unlock_irqrestore(&priv->driver_lock, flags); @@ -444,12 +426,10 @@ static irqreturn_t if_cs_interrupt(int i spin_unlock_irqrestore(&priv->driver_lock, flags); } - if (cause & IF_CS_H_IC_HOST_EVENT) { - u16 event = if_cs_read16(priv->card, IF_CS_C_STATUS) - & IF_CS_C_S_STATUS_MASK; - if_cs_write16(priv->card, IF_CS_H_INT_CAUSE, - IF_CS_H_IC_HOST_EVENT); - lbs_deb_cs("eventcause 0x%04x\n", event); + if (cause & IF_CS_HOST_EVENT) { + u16 event = if_cs_read16(priv->card, IF_CS_CARD_STATUS) + & IF_CS_CARD_S_STATUS_MASK; + lbs_deb_cs("event cause 0x%04x\n", event); lbs_queue_event(priv, event >> 8 & 0xff); } @@ -514,26 +494,26 @@ static int if_cs_prog_helper(struct if_c /* "write the number of bytes to be sent to the I/O Command * write length register" */ - if_cs_write16(card, IF_CS_H_CMD_LEN, count); + if_cs_write16(card, IF_CS_HOST_CMD_LEN, count); /* "write this to I/O Command port register as 16 bit writes */ if (count) - if_cs_write16_rep(card, IF_CS_H_CMD, + if_cs_write16_rep(card, IF_CS_HOST_CMD, &fw->data[sent], count >> 1); /* "Assert the download over interrupt command in the Host * status register" */ - if_cs_write8(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER); + if_cs_write8(card, IF_CS_HOST_STATUS, IF_CS_CMD_DNLD_OVER); /* "Assert the download over interrupt command in the Card * interrupt case register" */ - if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER); + if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_CMD_DNLD_OVER); /* "The host polls the Card Status register ... for 50 ms before declaring a failure */ - ret = if_cs_poll_while_fw_download(card, IF_CS_C_STATUS, - IF_CS_C_S_CMD_DNLD_RDY); + ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS, + IF_CS_CMD_DNLD_OVER); if (ret < 0) { lbs_pr_err("can't download helper at 0x%x, ret %d\n", sent, ret); @@ -575,14 +555,15 @@ static int if_cs_prog_real(struct if_cs_ } lbs_deb_cs("fw size %td\n", fw->size); - ret = if_cs_poll_while_fw_download(card, IF_CS_C_SQ_READ_LOW, IF_CS_C_SQ_HELPER_OK); + ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_SQ_READ_LOW, + IF_CS_CARD_SQ_HELPER_OK); if (ret < 0) { lbs_pr_err("helper firmware doesn't answer\n"); goto err_release; } for (sent = 0; sent < fw->size; sent += len) { - len = if_cs_read16(card, IF_CS_C_SQ_READ_LOW); + len = if_cs_read16(card, IF_CS_CARD_SQ_READ_LOW); if (len & 1) { retry++; lbs_pr_info("odd, need to retry this firmware block\n"); @@ -600,16 +581,16 @@ static int if_cs_prog_real(struct if_cs_ } - if_cs_write16(card, IF_CS_H_CMD_LEN, len); + if_cs_write16(card, IF_CS_HOST_CMD_LEN, len); - if_cs_write16_rep(card, IF_CS_H_CMD, + if_cs_write16_rep(card, IF_CS_HOST_CMD, &fw->data[sent], (len+1) >> 1); - if_cs_write8(card, IF_CS_H_STATUS, IF_CS_H_STATUS_DNLD_OVER); - if_cs_write16(card, IF_CS_H_INT_CAUSE, IF_CS_H_IC_DNLD_OVER); + if_cs_write8(card, IF_CS_HOST_STATUS, IF_CS_CMD_DNLD_OVER); + if_cs_write16(card, IF_CS_HOST_INT_CAUSE, IF_CS_CMD_DNLD_OVER); - ret = if_cs_poll_while_fw_download(card, IF_CS_C_STATUS, - IF_CS_C_S_CMD_DNLD_RDY); + ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS, + IF_CS_CMD_DNLD_OVER); if (ret < 0) { lbs_pr_err("can't download firmware at 0x%x\n", sent); goto err_release; @@ -837,7 +818,7 @@ static int if_cs_probe(struct pcmcia_dev /* Clear any interrupt cause that happend while sending * firmware/initializing card */ - if_cs_write16(card, IF_CS_C_INT_CAUSE, IF_CS_C_IC_MASK); + if_cs_write16(card, IF_CS_CARD_INT_CAUSE, IF_CS_CARD_IC_MASK); if_cs_enable_ints(card); /* And finally bring the card up */ -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html