// SPDX-License-Identifier: GPL-2.0-only /* * wanXL serial card driver for Linux * host part * * Copyright (C) 2003 Krzysztof Halasa <khc@pm.waw.pl> * * Status: * - Only DTE (external clock) support with NRZ and NRZI encodings * - wanXL100 will require minor driver modifications, no access to hw
*/
if (get_status(port)->open) {
netdev_err(dev, "port already open\n"); return -EIO;
}
i = hdlc_open(dev); if (i) return i;
port->tx_in = port->tx_out = 0; for (i = 0; i < TX_BUFFERS; i++)
get_status(port)->tx_descs[i].stat = PACKET_EMPTY; /* signal the card */
writel(1 << (DOORBELL_TO_CARD_OPEN_0 + port->node), dbr);
timeout = jiffies + HZ; do { if (get_status(port)->open) {
netif_start_queue(dev); return 0;
}
} while (time_after(timeout, jiffies));
netdev_err(dev, "unable to open port\n"); /* ask the card to close the port, should it be still alive */
writel(1 << (DOORBELL_TO_CARD_CLOSE_0 + port->node), dbr); return -EFAULT;
}
staticint wanxl_close(struct net_device *dev)
{ struct port *port = dev_to_port(dev); unsignedlong timeout; int i;
hdlc_close(dev); /* signal the card */
writel(1 << (DOORBELL_TO_CARD_CLOSE_0 + port->node),
port->card->plx + PLX_DOORBELL_TO_CARD);
timeout = jiffies + HZ; do { if (!get_status(port)->open) break;
} while (time_after(timeout, jiffies));
if (get_status(port)->open)
netdev_err(dev, "unable to close port\n");
netif_stop_queue(dev);
for (i = 0; i < TX_BUFFERS; i++) {
desc_t *desc = &get_status(port)->tx_descs[i];
for (i = 0; i < card->n_ports; i++) {
unregister_hdlc_device(card->ports[i].dev);
free_netdev(card->ports[i].dev);
}
/* unregister and free all host resources */ if (card->irq)
free_irq(card->irq, card);
wanxl_reset(card);
for (i = 0; i < RX_QUEUE_LENGTH; i++) if (card->rx_skbs[i]) {
dma_unmap_single(&card->pdev->dev,
card->status->rx_descs[i].address,
BUFFER_LENGTH, DMA_FROM_DEVICE);
dev_kfree_skb(card->rx_skbs[i]);
}
if (card->plx)
iounmap(card->plx);
if (card->status)
dma_free_coherent(&pdev->dev, sizeof(struct card_status),
card->status, card->status_address);
/* QUICC can only access first 256 MB of host RAM directly, * but PLX9060 DMA does 32-bits for actual packet data transfers
*/
/* FIXME when PCI/DMA subsystems are fixed. * We set both dma_mask and consistent_dma_mask to 28 bits * and pray pci_alloc_consistent() will use this info. It should * work on most platforms
*/ if (dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(28)) ||
dma_set_mask(&pdev->dev, DMA_BIT_MASK(28))) {
pr_err("No usable DMA configuration\n");
pci_disable_device(pdev); return -EIO;
}
i = pci_request_regions(pdev, "wanXL"); if (i) {
pci_disable_device(pdev); return i;
}
switch (pdev->device) { case PCI_DEVICE_ID_SBE_WANXL100:
ports = 1; break; case PCI_DEVICE_ID_SBE_WANXL200:
ports = 2; break; default:
ports = 4;
}
#ifdef DEBUG_PCI
printk(KERN_DEBUG "wanXL %s: pci_alloc_consistent() returned memory" " at 0x%LX\n", pci_name(pdev),
(unsignedlonglong)card->status_address); #endif
/* FIXME when PCI/DMA subsystems are fixed. * We set both dma_mask and consistent_dma_mask back to 32 bits * to indicate the card can do 32-bit DMA addressing
*/ if (dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)) ||
dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) {
pr_err("No usable DMA configuration\n");
wanxl_pci_remove_one(pdev); return -EIO;
}
/* set up PLX mapping */
plx_phy = pci_resource_start(pdev, 0);
mem = ioremap(mem_phy, PDM_OFFSET + sizeof(firmware)); if (!mem) {
pr_err("ioremap() failed\n");
wanxl_pci_remove_one(pdev); return -EFAULT;
}
for (i = 0; i < sizeof(firmware); i += 4)
writel(ntohl(*(__be32 *)(firmware + i)), mem + PDM_OFFSET + i);
for (i = 0; i < ports; i++)
writel(card->status_address +
(void *)&card->status->port_status[i] -
(void *)card->status, mem + PDM_OFFSET + 4 + i * 4);
writel(card->status_address, mem + PDM_OFFSET + 20);
writel(PDM_OFFSET, mem);
iounmap(mem);
writel(0, card->plx + PLX_MAILBOX_5);
if (wanxl_puts_command(card, MBX1_CMD_ABORTJ)) {
pr_warn("%s: unable to Abort and Jump\n", pci_name(pdev));
wanxl_pci_remove_one(pdev); return -ENODEV;
}
timeout = jiffies + 5 * HZ; do {
stat = readl(card->plx + PLX_MAILBOX_5); if (stat) break;
schedule();
} while (time_after(timeout, jiffies));
if (!stat) {
pr_warn("%s: timeout while initializing card firmware\n",
pci_name(pdev));
wanxl_pci_remove_one(pdev); return -ENODEV;
}
#if DETECT_RAM
ramsize = stat; #endif
pr_info("%s: at 0x%X, %u KB of RAM at 0x%X, irq %u\n",
pci_name(pdev), plx_phy, ramsize / 1024, mem_phy, pdev->irq);
/* Allocate IRQ */ if (request_irq(pdev->irq, wanxl_intr, IRQF_SHARED, "wanXL", card)) {
pr_warn("%s: could not allocate IRQ%i\n",
pci_name(pdev), pdev->irq);
wanxl_pci_remove_one(pdev); return -EBUSY;
}
card->irq = pdev->irq;
for (i = 0; i < ports; i++) {
hdlc_device *hdlc; struct port *port = &card->ports[i]; struct net_device *dev = alloc_hdlcdev(port);
if (!dev) {
pr_err("%s: unable to allocate memory\n",
pci_name(pdev));
wanxl_pci_remove_one(pdev); return -ENOMEM;
}
MODULE_AUTHOR("Krzysztof Halasa ");
MODULE_DESCRIPTION("SBE Inc. wanXL serial port driver");
MODULE_LICENSE("GPL v2");
MODULE_DEVICE_TABLE(pci, wanxl_pci_tbl);
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.