if (available > QCASPI_HW_BUF_LEN) { /* This could only happen by interferences on the SPI line. * So retry later ...
*/
qca->stats.buf_avail_err++; return -1;
}
while (qca->txr.skb[qca->txr.head]) {
pkt_len = qca->txr.skb[qca->txr.head]->len + QCASPI_HW_PKT_LEN;
if (available < pkt_len) { if (packets == 0)
qca->stats.write_buf_miss++; break;
}
if (qcaspi_tx_frame(qca, qca->txr.skb[qca->txr.head]) == -1) {
qca->stats.write_err++; return -1;
}
packets++;
n_stats->tx_packets++;
n_stats->tx_bytes += qca->txr.skb[qca->txr.head]->len;
available -= pkt_len;
/* remove the skb from the queue */ /* XXX After inconsistent lock states netif_tx_lock() * has been replaced by netif_tx_lock_bh() and so on.
*/
netif_tx_lock_bh(qca->net_dev);
dev_kfree_skb(qca->txr.skb[qca->txr.head]);
qca->txr.skb[qca->txr.head] = NULL;
qca->txr.size -= pkt_len;
new_head = qca->txr.head + 1; if (new_head >= qca->txr.count)
new_head = 0;
qca->txr.head = new_head; if (netif_queue_stopped(qca->net_dev))
netif_wake_queue(qca->net_dev);
netif_tx_unlock_bh(qca->net_dev);
}
/* Allocate rx SKB if we don't have one available. */ if (!qca->rx_skb) {
qca->rx_skb = netdev_alloc_skb_ip_align(net_dev,
net_dev->mtu +
VLAN_ETH_HLEN); if (!qca->rx_skb) {
netdev_dbg(net_dev, "out of RX resources\n");
qca->stats.out_of_mem++; return -1;
}
}
/* Read the packet size. */
qcaspi_read_register(qca, SPI_REG_RDBUF_BYTE_AVA, &available);
if (available > QCASPI_HW_BUF_LEN + QCASPI_HW_PKT_LEN) { /* This could only happen by interferences on the SPI line. * So retry later ...
*/
qca->stats.buf_avail_err++; return -1;
} elseif (available == 0) {
netdev_dbg(net_dev, "qcaspi_receive called without any data being available!\n"); return -1;
}
/* Flush the tx ring. This function is only safe to * call from the qcaspi_spi_thread.
*/
staticvoid
qcaspi_flush_tx_ring(struct qcaspi *qca)
{ int i;
/* XXX After inconsistent lock states netif_tx_lock() * has been replaced by netif_tx_lock_bh() and so on.
*/
netif_tx_lock_bh(qca->net_dev); for (i = 0; i < QCASPI_TX_RING_MAX_LEN; i++) { if (qca->txr.skb[i]) {
dev_kfree_skb(qca->txr.skb[i]);
qca->txr.skb[i] = NULL;
qca->net_dev->stats.tx_dropped++;
}
}
qca->txr.tail = 0;
qca->txr.head = 0;
qca->txr.size = 0;
netif_tx_unlock_bh(qca->net_dev);
}
if (event == QCASPI_EVENT_CPUON) { /* Read signature twice, if not valid * go back to unknown state.
*/
qcaspi_read_register(qca, SPI_REG_SIGNATURE, &signature);
qcaspi_read_register(qca, SPI_REG_SIGNATURE, &signature); if (signature != QCASPI_GOOD_SIGNATURE) { if (qca->sync == QCASPI_SYNC_READY)
qca->stats.bad_signature++;
set_bit(SPI_RESET, &qca->flags);
netdev_dbg(qca->net_dev, "sync: got CPU on, but signature was invalid, restart\n"); return;
} else { /* ensure that the WRBUF is empty */
qcaspi_read_register(qca, SPI_REG_WRBUF_SPC_AVA,
&wrbuf_space); if (wrbuf_space != QCASPI_HW_BUF_LEN) {
netdev_dbg(qca->net_dev, "sync: got CPU on, but wrbuf not empty. reset!\n");
qca->sync = QCASPI_SYNC_UNKNOWN;
qca->stats.buf_avail_err++;
} else {
netdev_dbg(qca->net_dev, "sync: got CPU on, now in sync\n");
qca->sync = QCASPI_SYNC_READY; return;
}
}
} else { /* Handle reset only on QCASPI_EVENT_UPDATE */ if (test_and_clear_bit(SPI_RESET, &qca->flags))
qca->sync = QCASPI_SYNC_UNKNOWN;
}
switch (qca->sync) { case QCASPI_SYNC_READY: /* Check signature twice, if not valid go to unknown state. */
qcaspi_read_register(qca, SPI_REG_SIGNATURE, &signature); if (signature != QCASPI_GOOD_SIGNATURE)
qcaspi_read_register(qca, SPI_REG_SIGNATURE, &signature);
if (signature != QCASPI_GOOD_SIGNATURE) {
set_bit(SPI_RESET, &qca->flags);
qca->stats.bad_signature++;
netdev_dbg(qca->net_dev, "sync: bad signature, restart\n"); /* don't reset right away */ return;
} break; case QCASPI_SYNC_UNKNOWN: /* Read signature, if not valid stay in unknown state */
qcaspi_read_register(qca, SPI_REG_SIGNATURE, &signature); if (signature != QCASPI_GOOD_SIGNATURE) {
netdev_dbg(qca->net_dev, "sync: could not read signature to reset device, retry.\n"); return;
}
/* TODO: use GPIO to reset QCA7000 in legacy mode*/
netdev_dbg(qca->net_dev, "sync: resetting device.\n");
qcaspi_read_register(qca, SPI_REG_SPI_CONFIG, &spi_config);
spi_config |= QCASPI_SLAVE_RESET_BIT;
qcaspi_write_register(qca, SPI_REG_SPI_CONFIG, spi_config, 0);
qca->sync = QCASPI_SYNC_RESET;
qca->stats.trig_reset++;
qca->reset_count = 0; break; case QCASPI_SYNC_RESET:
qca->reset_count++;
netdev_dbg(qca->net_dev, "sync: waiting for CPU on, count %u.\n",
qca->reset_count); if (qca->reset_count >= QCASPI_RESET_TIMEOUT) { /* reset did not seem to take place, try again */
set_bit(SPI_RESET, &qca->flags);
qca->stats.reset_timeout++;
netdev_dbg(qca->net_dev, "sync: reset timeout, restarting process.\n");
} break;
}
}
/* can only handle other interrupts * if sync has occurred
*/ if (qca->sync == QCASPI_SYNC_READY) { if (intr_cause & SPI_INT_PKT_AVLBL)
qcaspi_receive(qca);
}
ret = devm_request_irq(&spi->dev, spi->irq, qcaspi_intr_handler,
IRQF_NO_AUTOEN, qca->net_dev->name, qca); if (ret) {
dev_err(&spi->dev, "Unable to get IRQ %d (irqval=%d).\n",
spi->irq, ret);
free_netdev(qcaspi_devs); return ret;
}
ret = of_get_ethdev_address(spi->dev.of_node, qca->net_dev); if (ret) {
eth_hw_addr_random(qca->net_dev);
dev_info(&spi->dev, "Using random MAC address: %pM\n",
qca->net_dev->dev_addr);
}
netif_carrier_off(qca->net_dev);
if (!qcaspi_pluggable) {
qcaspi_read_register(qca, SPI_REG_SIGNATURE, &signature);
qcaspi_read_register(qca, SPI_REG_SIGNATURE, &signature);
if (register_netdev(qcaspi_devs)) {
dev_err(&spi->dev, "Unable to register net device %s\n",
qcaspi_devs->name);
free_netdev(qcaspi_devs); return -EFAULT;
}
¤ 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.0.19Bemerkung:
(vorverarbeitet am 2026-06-07)
¤
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.