staticvoid spu_transaction_init(struct if_spi_card *card)
{ if (!time_after(jiffies, card->prev_xfer_time + 1)) { /* Unfortunately, the SPU requires a delay between successive *transactions.Ifourlasttransactionwasmorethanajiffy *ago,wehaveobviouslyalreadydelayedenough.
* If not, we have to busy-wait to be on the safe side. */
ndelay(400);
}
}
staticint spu_set_bus_mode(struct if_spi_card *card, u16 mode)
{ int err = 0;
u16 rval; /* set bus mode */
err = spu_write_u16(card, IF_SPI_SPU_BUS_MODE_REG, mode); if (err) return err; /* Check that we were able to read back what we just wrote. */
err = spu_read_u16(card, IF_SPI_SPU_BUS_MODE_REG, &rval); if (err) return err; if ((rval & 0xF) != mode) {
pr_err("Can't read bus mode register\n"); return -EIO;
} return0;
}
staticint spu_init(struct if_spi_card *card, int use_dummy_writes)
{ int err = 0;
u32 delay;
/* If dummy clock delay mode has been requested, switch to it now */ if (use_dummy_writes) {
card->use_dummy_writes = 1;
err = spu_set_bus_mode(card,
IF_SPI_BUS_MODE_SPI_CLOCK_PHASE_RISING |
IF_SPI_BUS_MODE_DELAY_METHOD_DUMMY_CLOCK |
IF_SPI_BUS_MODE_16_BIT_ADDRESS_16_BIT_DATA); if (err) return err;
}
/* *Oncethehelper/singlestagefirmwaredownloadiscomplete, *write0toscratchpad1andinterruptthe *bootloader.Thiscompletesthehelperdownload.
*/
err = spu_write_u16(card, IF_SPI_SCRATCH_1_REG, FIRMWARE_DNLD_OK); if (err) goto out;
err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_REG, 0); if (err) goto out;
err = spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG,
IF_SPI_CIC_CMD_DOWNLOAD_OVER);
out: if (err)
pr_err("failed to load helper firmware (err=%d)\n", err);
return err;
}
/* *Returnsthelengthofthenextpacketthefirmwareexpectsustosend. *Setscrc_erriftheprevioustransferhadaCRCerror.
*/ staticint if_spi_prog_main_firmware_check_len(struct if_spi_card *card, int *crc_err)
{
u16 len; int err = 0;
/* *waituntilthehostinterruptstatusregisterindicates *thatwearereadytodownload
*/
err = spu_wait_for_u16(card, IF_SPI_HOST_INT_STATUS_REG,
IF_SPI_HIST_CMD_DOWNLOAD_RDY,
IF_SPI_HIST_CMD_DOWNLOAD_RDY); if (err) {
pr_err("timed out waiting for host_int_status\n"); return err;
}
/* Ask the device how many bytes of firmware it wants. */
err = spu_read_u16(card, IF_SPI_SCRATCH_1_REG, &len); if (err) return err;
if (len > IF_SPI_CMD_BUF_SIZE) {
pr_err("firmware load device requested a larger transfer than we are prepared to handle (len = %d)\n",
len); return -EIO;
} if (len & 0x1) {
lbs_deb_spi("%s: crc error\n", __func__);
len &= ~0x1;
*crc_err = 1;
} else
*crc_err = 0;
/* How many bytes are there to read? */
err = spu_read_u16(card, IF_SPI_SCRATCH_2_REG, &len); if (err) goto out; if (!len) {
netdev_err(priv->dev, "%s: error: card has no data for host\n",
__func__);
err = -EINVAL; goto out;
} elseif (len > IF_SPI_CMD_BUF_SIZE) {
netdev_err(priv->dev, "%s: error: response packet too large: %d bytes, but maximum is %d\n",
__func__, len, IF_SPI_CMD_BUF_SIZE);
err = -EINVAL; goto out;
}
/* Read the data from the WLAN module into our command buffer */
err = spu_read(card, IF_SPI_CMD_RDWRPORT_REG,
card->cmd_buffer, ALIGN(len, 4)); if (err) goto out;
out: if (err)
netdev_err(priv->dev, "%s: err=%d\n", __func__, err);
return err;
}
/* Move data from the card to the host */ staticint if_spi_c2h_data(struct if_spi_card *card)
{ struct lbs_private *priv = card->priv; struct sk_buff *skb; char *data;
u16 len; int err = 0;
/* How many bytes are there to read? */
err = spu_read_u16(card, IF_SPI_SCRATCH_1_REG, &len); if (err) goto out; if (!len) {
netdev_err(priv->dev, "%s: error: card has no data for host\n",
__func__);
err = -EINVAL; goto out;
} elseif (len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
netdev_err(priv->dev, "%s: error: card has %d bytes of data, but our maximum skb size is %zu\n",
__func__, len, MRVDRV_ETH_RX_PACKET_BUFFER_SIZE);
err = -EINVAL; goto out;
}
/* TODO: should we allocate a smaller skb if we have less data? */
skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE); if (!skb) {
err = -ENOBUFS; goto out;
}
skb_reserve(skb, IPFIELD_ALIGN_OFFSET);
data = skb_put(skb, len);
/* Read the data from the WLAN module into our skb... */
err = spu_read(card, IF_SPI_DATA_RDWRPORT_REG, data, ALIGN(len, 4)); if (err) {
dev_kfree_skb(skb); goto out;
}
/* pass the SKB to libertas */
err = lbs_process_rxed_packet(card->priv, skb); /* lbs_process_rxed_packet() consumes the skb */
out: if (err)
netdev_err(priv->dev, "%s: err=%d\n", __func__, err);
return err;
}
/* Move data or a command from the host to the card. */ staticvoid if_spi_h2c(struct if_spi_card *card, struct if_spi_packet *packet, int type)
{ struct lbs_private *priv = card->priv; int err = 0;
u16 port_reg;
switch (type) { case MVMS_DAT:
port_reg = IF_SPI_DATA_RDWRPORT_REG; break; case MVMS_CMD:
port_reg = IF_SPI_CMD_RDWRPORT_REG; break; default:
netdev_err(priv->dev, "can't transfer buffer of type %d\n",
type);
err = -EINVAL; goto out;
}
/* Write the data to the card */
err = spu_write(card, port_reg, packet->buffer, packet->blen); if (err) goto out;
out:
kfree(packet);
if (err)
netdev_err(priv->dev, "%s: error %d\n", __func__, err);
}
/* Inform the host about a card event */ staticvoid if_spi_e2h(struct if_spi_card *card)
{ int err = 0;
u32 cause; struct lbs_private *priv = card->priv;
err = spu_read_u32(card, IF_SPI_SCRATCH_3_REG, &cause); if (err) goto out;
/* re-enable the card event interrupt */
err = spu_write_u16(card, IF_SPI_HOST_INT_STATUS_REG,
~IF_SPI_HICU_CARD_EVENT); if (err) goto out;
/* generate a card interrupt */
err = spu_write_u16(card, IF_SPI_CARD_INT_CAUSE_REG,
IF_SPI_CIC_HOST_EVENT); if (err) goto out;
lbs_queue_event(priv, cause & 0xff);
out: if (err)
netdev_err(priv->dev, "%s: error %d\n", __func__, err);
}
/* Do we have any command packets from the host to send? */
packet = NULL;
spin_lock_irqsave(&card->buffer_lock, flags); if (!list_empty(&card->cmd_packet_list)) {
packet = (struct if_spi_packet *)(card->
cmd_packet_list.next);
list_del(&packet->list);
}
spin_unlock_irqrestore(&card->buffer_lock, flags);
if (packet)
if_spi_h2c(card, packet, MVMS_CMD);
} if (hiStatus & IF_SPI_HIST_TX_DOWNLOAD_RDY) { /* Do we have any data packets from the host to send? */
packet = NULL;
spin_lock_irqsave(&card->buffer_lock, flags); if (!list_empty(&card->data_packet_list)) {
packet = (struct if_spi_packet *)(card->
data_packet_list.next);
list_del(&packet->list);
}
spin_unlock_irqrestore(&card->buffer_lock, flags);
if (packet)
if_spi_h2c(card, packet, MVMS_DAT);
} if (hiStatus & IF_SPI_HIST_CARD_EVENT)
if_spi_e2h(card);
err = spu_init(card, card->pdata->use_dummy_writes); if (err) goto out;
err = spu_get_chip_revision(card, &card->card_id, &card->card_rev); if (err) goto out;
err = spu_read_u32(card, IF_SPI_SCRATCH_4_REG, &scratch); if (err) goto out; if (scratch == SUCCESSFUL_FW_DOWNLOAD_MAGIC)
lbs_deb_spi("Firmware is already loaded for " "Marvell WLAN 802.11 adapter\n"); else { /* Check if we support this card */ for (i = 0; i < ARRAY_SIZE(fw_table); i++) { if (card->card_id == fw_table[i].model) break;
} if (i == ARRAY_SIZE(fw_table)) {
netdev_err(priv->dev, "Unsupported chip_id: 0x%02x\n",
card->card_id);
err = -ENODEV; goto out;
}
err = lbs_get_firmware(&card->spi->dev, card->card_id,
&fw_table[0], &helper, &mainfw); if (err) {
netdev_err(priv->dev, "failed to find firmware (%d)\n",
err); goto out;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.