diff options
Diffstat (limited to 'drivers/net/wireless/p54')
-rw-r--r-- | drivers/net/wireless/p54/p54.h | 78 | ||||
-rw-r--r-- | drivers/net/wireless/p54/p54common.c | 216 | ||||
-rw-r--r-- | drivers/net/wireless/p54/p54spi.c | 127 |
3 files changed, 264 insertions, 157 deletions
diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index ecf8b6ed5a4..7fda1a9e263 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -125,6 +125,7 @@ struct p54_led_dev { struct led_classdev led_dev; char name[P54_LED_MAX_NAME_LEN + 1]; + unsigned int toggled; unsigned int index; unsigned int registered; }; @@ -133,55 +134,74 @@ struct p54_led_dev { struct p54_common { struct ieee80211_hw *hw; - u32 rx_start; - u32 rx_end; - struct sk_buff_head tx_queue; + struct ieee80211_vif *vif; void (*tx)(struct ieee80211_hw *dev, struct sk_buff *skb); int (*open)(struct ieee80211_hw *dev); void (*stop)(struct ieee80211_hw *dev); - int mode; + struct sk_buff_head tx_queue; + struct mutex conf_mutex; + + /* memory management (as seen by the firmware) */ + u32 rx_start; + u32 rx_end; u16 rx_mtu; u8 headroom; u8 tailroom; - struct mutex conf_mutex; - u8 mac_addr[ETH_ALEN]; - u8 bssid[ETH_ALEN]; + + /* firmware/hardware info */ + unsigned int tx_hdr_len; + unsigned int fw_var; + unsigned int fw_interface; + u8 version; + + /* (e)DCF / QOS state */ + bool use_short_slot; + struct ieee80211_tx_queue_stats tx_stats[8]; + struct p54_edcf_queue_param qos_params[8]; + + /* Radio data */ + u16 rxhw; u8 rx_diversity_mask; u8 tx_diversity_mask; + unsigned int output_power; + int noise; + /* calibration, output power limit and rssi<->dBm conversation data */ struct pda_iq_autocal_entry *iq_autocal; unsigned int iq_autocal_len; - struct p54_cal_database *output_limit; struct p54_cal_database *curve_data; + struct p54_cal_database *output_limit; struct p54_rssi_linear_approximation rssical_db[IEEE80211_NUM_BANDS]; + + /* BBP/MAC state */ + u8 mac_addr[ETH_ALEN]; + u8 bssid[ETH_ALEN]; + u16 wakeup_timer; unsigned int filter_flags; - bool use_short_slot; - u16 rxhw; - u8 version; - unsigned int tx_hdr_len; - unsigned int fw_var; - unsigned int fw_interface; - unsigned int output_power; - u32 tsf_low32; - u32 tsf_high32; + int mode; + u32 tsf_low32, tsf_high32; u32 basic_rate_mask; - u16 wakeup_timer; u16 aid; - struct ieee80211_tx_queue_stats tx_stats[8]; - struct p54_edcf_queue_param qos_params[8]; - struct ieee80211_low_level_stats stats; - struct delayed_work work; struct sk_buff *cached_beacon; - int noise; - void *eeprom; - struct completion eeprom_comp; + + /* cryptographic engine information */ u8 privacy_caps; u8 rx_keycache_size; + unsigned long *used_rxkeys; + /* LED management */ -#ifdef CONFIG_P54_LEDS - struct p54_led_dev assoc_led; - struct p54_led_dev tx_led; -#endif /* CONFIG_P54_LEDS */ +#ifdef CONFIG_MAC80211_LEDS + struct p54_led_dev leds[4]; + struct delayed_work led_work; +#endif /* CONFIG_MAC80211_LEDS */ u16 softled_state; /* bit field of glowing LEDs */ + + /* statistics */ + struct ieee80211_low_level_stats stats; + struct delayed_work work; + + /* eeprom handling */ + void *eeprom; + struct completion eeprom_comp; }; int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb); diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index c8f0232ee5e..71394968d45 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -249,7 +249,7 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) dev->queues = P54_QUEUE_AC_NUM; } - if (!modparam_nohwcrypt) + if (!modparam_nohwcrypt) { printk(KERN_INFO "%s: cryptographic accelerator " "WEP:%s, TKIP:%s, CCMP:%s\n", wiphy_name(dev->wiphy), @@ -259,6 +259,26 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) (priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP) ? "YES" : "no"); + if (priv->rx_keycache_size) { + /* + * NOTE: + * + * The firmware provides at most 255 (0 - 254) slots + * for keys which are then used to offload decryption. + * As a result the 255 entry (aka 0xff) can be used + * safely by the driver to mark keys that didn't fit + * into the full cache. This trick saves us from + * keeping a extra list for uploaded keys. + */ + + priv->used_rxkeys = kzalloc(BITS_TO_LONGS( + priv->rx_keycache_size), GFP_KERNEL); + + if (!priv->used_rxkeys) + return -ENOMEM; + } + } + return 0; } EXPORT_SYMBOL_GPL(p54_parse_firmware); @@ -749,8 +769,6 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) rx_status.signal = p54_rssi_to_dbm(dev, hdr->rssi); rx_status.noise = priv->noise; - /* XX correct? */ - rx_status.qual = (100 * hdr->rssi) / 127; if (hdr->rate & 0x10) rx_status.flag |= RX_FLAG_SHORTPRE; if (dev->conf.channel->band == IEEE80211_BAND_5GHZ) @@ -1044,6 +1062,7 @@ static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb) static void p54_rx_trap(struct ieee80211_hw *dev, struct sk_buff *skb) { + struct p54_common *priv = dev->priv; struct p54_hdr *hdr = (struct p54_hdr *) skb->data; struct p54_trap *trap = (struct p54_trap *) hdr->data; u16 event = le16_to_cpu(trap->event); @@ -1057,6 +1076,8 @@ static void p54_rx_trap(struct ieee80211_hw *dev, struct sk_buff *skb) wiphy_name(dev->wiphy), freq); break; case P54_TRAP_NO_BEACON: + if (priv->vif) + ieee80211_beacon_loss(priv->vif); break; case P54_TRAP_SCAN: break; @@ -1452,7 +1473,8 @@ static int p54_tx_fill(struct ieee80211_hw *dev, struct sk_buff *skb, if (info->control.sta) *aid = info->control.sta->aid; - else + + if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL; break; } @@ -1939,7 +1961,8 @@ static int p54_set_ps(struct ieee80211_hw *dev) int i; if (dev->conf.flags & IEEE80211_CONF_PS) - mode = P54_PSM | P54_PSM_DTIM | P54_PSM_MCBC; + mode = P54_PSM | P54_PSM_BEACON_TIMEOUT | P54_PSM_DTIM | + P54_PSM_CHECKSUM | P54_PSM_MCBC; else mode = P54_PSM_CAM; @@ -1957,9 +1980,10 @@ static int p54_set_ps(struct ieee80211_hw *dev) psm->intervals[i].periods = cpu_to_le16(1); } - psm->beacon_rssi_skip_max = 60; + psm->beacon_rssi_skip_max = 200; psm->rssi_delta_threshold = 0; - psm->nr = 0; + psm->nr = 10; + psm->exclude[0] = 0; priv->tx(dev, skb); @@ -2088,6 +2112,9 @@ static void p54_stop(struct ieee80211_hw *dev) priv->softled_state = 0; p54_set_leds(dev); +#ifdef CONFIG_P54_LEDS + cancel_delayed_work_sync(&priv->led_work); +#endif /* CONFIG_P54_LEDS */ cancel_delayed_work_sync(&priv->work); if (priv->cached_beacon) p54_tx_cancel(dev, priv->cached_beacon); @@ -2111,6 +2138,8 @@ static int p54_add_interface(struct ieee80211_hw *dev, return -EOPNOTSUPP; } + priv->vif = conf->vif; + switch (conf->type) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: @@ -2135,6 +2164,7 @@ static void p54_remove_interface(struct ieee80211_hw *dev, struct p54_common *priv = dev->priv; mutex_lock(&priv->conf_mutex); + priv->vif = NULL; if (priv->cached_beacon) p54_tx_cancel(dev, priv->cached_beacon); priv->mode = NL80211_IFTYPE_MONITOR; @@ -2344,61 +2374,84 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, struct p54_common *priv = dev->priv; struct sk_buff *skb; struct p54_keycache *rxkey; + int slot, ret = 0; u8 algo = 0; if (modparam_nohwcrypt) return -EOPNOTSUPP; - if (cmd == DISABLE_KEY) - algo = 0; - else { + mutex_lock(&priv->conf_mutex); + if (cmd == SET_KEY) { switch (key->alg) { case ALG_TKIP: if (!(priv->privacy_caps & (BR_DESC_PRIV_CAP_MICHAEL | - BR_DESC_PRIV_CAP_TKIP))) - return -EOPNOTSUPP; + BR_DESC_PRIV_CAP_TKIP))) { + ret = -EOPNOTSUPP; + goto out_unlock; + } key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; algo = P54_CRYPTO_TKIPMICHAEL; break; case ALG_WEP: - if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP)) - return -EOPNOTSUPP; + if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP)) { + ret = -EOPNOTSUPP; + goto out_unlock; + } key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; algo = P54_CRYPTO_WEP; break; case ALG_CCMP: - if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)) - return -EOPNOTSUPP; + if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)) { + ret = -EOPNOTSUPP; + goto out_unlock; + } key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; algo = P54_CRYPTO_AESCCMP; break; default: - return -EOPNOTSUPP; + ret = -EOPNOTSUPP; + goto out_unlock; } - } + slot = bitmap_find_free_region(priv->used_rxkeys, + priv->rx_keycache_size, 0); - if (key->keyidx > priv->rx_keycache_size) { - /* - * The device supports the choosen algorithm, but the firmware - * does not provide enough key slots to store all of them. - * So, incoming frames have to be decoded by the mac80211 stack, - * but we can still offload encryption for outgoing frames. - */ + if (slot < 0) { + /* + * The device supports the choosen algorithm, but the + * firmware does not provide enough key slots to store + * all of them. + * But encryption offload for outgoing frames is always + * possible, so we just pretend that the upload was + * successful and do the decryption in software. + */ - return 0; + /* mark the key as invalid. */ + key->hw_key_idx = 0xff; + goto out_unlock; + } + } else { + slot = key->hw_key_idx; + + if (slot == 0xff) { + /* This key was not uploaded into the rx key cache. */ + + goto out_unlock; + } + + bitmap_release_region(priv->used_rxkeys, slot, 0); + algo = 0; } - mutex_lock(&priv->conf_mutex); skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*rxkey), - P54_CONTROL_TYPE_RX_KEYCACHE, GFP_ATOMIC); + P54_CONTROL_TYPE_RX_KEYCACHE, GFP_KERNEL); if (!skb) { - mutex_unlock(&priv->conf_mutex); - return -ENOMEM; + bitmap_release_region(priv->used_rxkeys, slot, 0); + ret = -ENOSPC; + goto out_unlock; } - /* TODO: some devices have 4 more free slots for rx keys */ rxkey = (struct p54_keycache *)skb_put(skb, sizeof(*rxkey)); - rxkey->entry = key->keyidx; + rxkey->entry = slot; rxkey->key_id = key->keyidx; rxkey->key_type = algo; if (sta) @@ -2416,11 +2469,51 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, } priv->tx(dev, skb); + key->hw_key_idx = slot; + +out_unlock: mutex_unlock(&priv->conf_mutex); - return 0; + return ret; } #ifdef CONFIG_P54_LEDS +static void p54_update_leds(struct work_struct *work) +{ + struct p54_common *priv = container_of(work, struct p54_common, + led_work.work); + int err, i, tmp, blink_delay = 400; + bool rerun = false; + + /* Don't toggle the LED, when the device is down. */ + if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) + return ; + + for (i = 0; i < ARRAY_SIZE(priv->leds); i++) + if (priv->leds[i].toggled) { + priv->softled_state |= BIT(i); + + tmp = 70 + 200 / (priv->leds[i].toggled); + if (tmp < blink_delay) + blink_delay = tmp; + + if (priv->leds[i].led_dev.brightness == LED_OFF) + rerun = true; + + priv->leds[i].toggled = + !!priv->leds[i].led_dev.brightness; + } else + priv->softled_state &= ~BIT(i); + + err = p54_set_leds(priv->hw); + if (err && net_ratelimit()) + printk(KERN_ERR "%s: failed to update LEDs.\n", + wiphy_name(priv->hw->wiphy)); + + if (rerun) + queue_delayed_work(priv->hw->workqueue, &priv->led_work, + msecs_to_jiffies(blink_delay)); +} + static void p54_led_brightness_set(struct led_classdev *led_dev, enum led_brightness brightness) { @@ -2428,28 +2521,23 @@ static void p54_led_brightness_set(struct led_classdev *led_dev, led_dev); struct ieee80211_hw *dev = led->hw_dev; struct p54_common *priv = dev->priv; - int err; - /* Don't toggle the LED, when the device is down. */ if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) return ; - if (brightness != LED_OFF) - priv->softled_state |= BIT(led->index); - else - priv->softled_state &= ~BIT(led->index); - - err = p54_set_leds(dev); - if (err && net_ratelimit()) - printk(KERN_ERR "%s: failed to update %s LED.\n", - wiphy_name(dev->wiphy), led_dev->name); + if (brightness) { + led->toggled++; + queue_delayed_work(priv->hw->workqueue, &priv->led_work, + HZ/10); + } } static int p54_register_led(struct ieee80211_hw *dev, - struct p54_led_dev *led, unsigned int led_index, char *name, char *trigger) { + struct p54_common *priv = dev->priv; + struct p54_led_dev *led = &priv->leds[led_index]; int err; if (led->registered) @@ -2482,19 +2570,30 @@ static int p54_init_leds(struct ieee80211_hw *dev) * TODO: * Figure out if the EEPROM contains some hints about the number * of available/programmable LEDs of the device. - * But for now, we can assume that we have two programmable LEDs. */ - err = p54_register_led(dev, &priv->assoc_led, 0, "assoc", + INIT_DELAYED_WORK(&priv->led_work, p54_update_leds); + + err = p54_register_led(dev, 0, "assoc", ieee80211_get_assoc_led_name(dev)); if (err) return err; - err = p54_register_led(dev, &priv->tx_led, 1, "tx", + err = p54_register_led(dev, 1, "tx", ieee80211_get_tx_led_name(dev)); if (err) return err; + err = p54_register_led(dev, 2, "rx", + ieee80211_get_rx_led_name(dev)); + if (err) + return err; + + err = p54_register_led(dev, 3, "radio", + ieee80211_get_radio_led_name(dev)); + if (err) + return err; + err = p54_set_leds(dev); return err; } @@ -2502,11 +2601,11 @@ static int p54_init_leds(struct ieee80211_hw *dev) static void p54_unregister_leds(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; + int i; - if (priv->tx_led.registered) - led_classdev_unregister(&priv->tx_led.led_dev); - if (priv->assoc_led.registered) - led_classdev_unregister(&priv->assoc_led.led_dev); + for (i = 0; i < ARRAY_SIZE(priv->leds); i++) + if (priv->leds[i].registered) + led_classdev_unregister(&priv->leds[i].led_dev); } #endif /* CONFIG_P54_LEDS */ @@ -2607,21 +2706,10 @@ void p54_free_common(struct ieee80211_hw *dev) kfree(priv->iq_autocal); kfree(priv->output_limit); kfree(priv->curve_data); + kfree(priv->used_rxkeys); #ifdef CONFIG_P54_LEDS p54_unregister_leds(dev); #endif /* CONFIG_P54_LEDS */ } EXPORT_SYMBOL_GPL(p54_free_common); - -static int __init p54_init(void) -{ - return 0; -} - -static void __exit p54_exit(void) -{ -} - -module_init(p54_init); -module_exit(p54_exit); diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index d1fe577de3d..59a5e778bb0 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -167,18 +167,36 @@ static const struct p54spi_spi_reg p54spi_registers_array[] = static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, __le32 bits) { int i; - __le32 buffer; for (i = 0; i < 2000; i++) { - p54spi_spi_read(priv, reg, &buffer, sizeof(buffer)); - if (buffer == bits) + __le32 buffer = p54spi_read32(priv, reg); + if ((buffer & bits) == bits) return 1; - msleep(1); + msleep(0); } return 0; } +static int p54spi_spi_write_dma(struct p54s_priv *priv, __le32 base, + const void *buf, size_t len) +{ + p54spi_write16(priv, SPI_ADRS_DMA_WRITE_CTRL, + cpu_to_le16(SPI_DMA_WRITE_CTRL_ENABLE)); + + if (!p54spi_wait_bit(priv, SPI_ADRS_DMA_WRITE_CTRL, + cpu_to_le32(HOST_ALLOWED))) { + dev_err(&priv->spi->dev, "spi_write_dma not allowed " + "to DMA write.\n"); + return -EAGAIN; + } + + p54spi_write16(priv, SPI_ADRS_DMA_WRITE_LEN, cpu_to_le16(len)); + p54spi_write32(priv, SPI_ADRS_DMA_WRITE_BASE, base); + p54spi_spi_write(priv, SPI_ADRS_DMA_DATA, buf, len); + return 0; +} + static int p54spi_request_firmware(struct ieee80211_hw *dev) { struct p54s_priv *priv = dev->priv; @@ -228,8 +246,15 @@ static int p54spi_request_eeprom(struct ieee80211_hw *dev) static int p54spi_upload_firmware(struct ieee80211_hw *dev) { struct p54s_priv *priv = dev->priv; - unsigned long fw_len, fw_addr; - long _fw_len; + unsigned long fw_len, _fw_len; + unsigned int offset = 0; + int err = 0; + u8 *fw; + + fw_len = priv->firmware->size; + fw = kmemdup(priv->firmware->data, fw_len, GFP_KERNEL); + if (!fw) + return -ENOMEM; /* stop the device */ p54spi_write16(priv, SPI_ADRS_DEV_CTRL_STAT, cpu_to_le16( @@ -244,36 +269,17 @@ static int p54spi_upload_firmware(struct ieee80211_hw *dev) msleep(TARGET_BOOT_SLEEP); - fw_addr = ISL38XX_DEV_FIRMWARE_ADDR; - fw_len = priv->firmware->size; - while (fw_len > 0) { _fw_len = min_t(long, fw_len, SPI_MAX_PACKET_SIZE); - p54spi_write16(priv, SPI_ADRS_DMA_WRITE_CTRL, - cpu_to_le16(SPI_DMA_WRITE_CTRL_ENABLE)); - - if (p54spi_wait_bit(priv, SPI_ADRS_DMA_WRITE_CTRL, - cpu_to_le32(HOST_ALLOWED)) == 0) { - dev_err(&priv->spi->dev, "fw_upload not allowed " - "to DMA write."); - return -EAGAIN; - } - - p54spi_write16(priv, SPI_ADRS_DMA_WRITE_LEN, - cpu_to_le16(_fw_len)); - p54spi_write32(priv, SPI_ADRS_DMA_WRITE_BASE, - cpu_to_le32(fw_addr)); - - p54spi_spi_write(priv, SPI_ADRS_DMA_DATA, - &priv->firmware->data, _fw_len); + err = p54spi_spi_write_dma(priv, cpu_to_le32( + ISL38XX_DEV_FIRMWARE_ADDR + offset), + (fw + offset), _fw_len); + if (err < 0) + goto out; fw_len -= _fw_len; - fw_addr += _fw_len; - - /* FIXME: I think this doesn't work if firmware is large, - * this loop goes to second round. fw->data is not - * increased at all! */ + offset += _fw_len; } BUG_ON(fw_len != 0); @@ -292,7 +298,10 @@ static int p54spi_upload_firmware(struct ieee80211_hw *dev) p54spi_write16(priv, SPI_ADRS_DEV_CTRL_STAT, cpu_to_le16( SPI_CTRL_STAT_HOST_OVERRIDE | SPI_CTRL_STAT_RAM_BOOT)); msleep(TARGET_BOOT_SLEEP); - return 0; + +out: + kfree(fw); + return err; } static void p54spi_power_off(struct p54s_priv *priv) @@ -320,21 +329,15 @@ static inline void p54spi_int_ack(struct p54s_priv *priv, u32 val) static void p54spi_wakeup(struct p54s_priv *priv) { - unsigned long timeout; - u32 ints; - /* wake the chip */ p54spi_write32(priv, SPI_ADRS_ARM_INTERRUPTS, cpu_to_le32(SPI_TARGET_INT_WAKEUP)); /* And wait for the READY interrupt */ - timeout = jiffies + HZ; - - ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS); - while (!(ints & SPI_HOST_INT_READY)) { - if (time_after(jiffies, timeout)) - goto out; - ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS); + if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS, + cpu_to_le32(SPI_HOST_INT_READY))) { + dev_err(&priv->spi->dev, "INT_READY timeout\n"); + goto out; } p54spi_int_ack(priv, SPI_HOST_INT_READY); @@ -385,7 +388,12 @@ static int p54spi_rx(struct p54s_priv *priv) return 0; } - skb = dev_alloc_skb(len); + + /* Firmware may insert up to 4 padding bytes after the lmac header, + * but it does not amend the size of SPI data transfer. + * Such packets has correct data size in header, thus referencing + * past the end of allocated skb. Reserve extra 4 bytes for this case */ + skb = dev_alloc_skb(len + 4); if (!skb) { dev_err(&priv->spi->dev, "could not alloc skb"); return 0; @@ -393,6 +401,9 @@ static int p54spi_rx(struct p54s_priv *priv) p54spi_spi_read(priv, SPI_ADRS_DMA_DATA, skb_put(skb, len), len); p54spi_sleep(priv); + /* Put additional bytes to compensate for the possible + * alignment-caused truncation */ + skb_put(skb, 4); if (p54_rx(priv->hw, skb) == 0) dev_kfree_skb(skb); @@ -414,39 +425,27 @@ static irqreturn_t p54spi_interrupt(int irq, void *config) static int p54spi_tx_frame(struct p54s_priv *priv, struct sk_buff *skb) { struct p54_hdr *hdr = (struct p54_hdr *) skb->data; - struct p54s_dma_regs dma_regs; - unsigned long timeout; int ret = 0; - u32 ints; p54spi_wakeup(priv); - dma_regs.cmd = cpu_to_le16(SPI_DMA_WRITE_CTRL_ENABLE); - dma_regs.len = cpu_to_le16(skb->len); - dma_regs.addr = hdr->req_id; - - p54spi_spi_write(priv, SPI_ADRS_DMA_WRITE_CTRL, &dma_regs, - sizeof(dma_regs)); - - p54spi_spi_write(priv, SPI_ADRS_DMA_DATA, skb->data, skb->len); + ret = p54spi_spi_write_dma(priv, hdr->req_id, skb->data, skb->len); + if (ret < 0) + goto out; - timeout = jiffies + 2 * HZ; - ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS); - while (!(ints & SPI_HOST_INT_WR_READY)) { - if (time_after(jiffies, timeout)) { - dev_err(&priv->spi->dev, "WR_READY timeout"); - ret = -1; - goto out; - } - ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS); + if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS, + cpu_to_le32(SPI_HOST_INT_WR_READY))) { + dev_err(&priv->spi->dev, "WR_READY timeout\n"); + ret = -1; + goto out; } p54spi_int_ack(priv, SPI_HOST_INT_WR_READY); p54spi_sleep(priv); -out: if (FREE_AFTER_TX(skb)) p54_free_skb(priv->hw, skb); +out: return ret; } |