// SPDX-License-Identifier: GPL-2.0-or-later /* * rrunner.c: Linux driver for the Essential RoadRunner HIPPI board. * * Copyright (C) 1998-2002 by Jes Sorensen, <jes@wildopensource.com>. * * Thanks to Essential Communication for providing us with hardware * and very comprehensive documentation without which I would not have * been able to write this driver. A special thank you to John Gibbon * for sorting out the legal issues, with the NDA, allowing the code to * be released under the GPL. * * Thanks to Jayaram Bhat from ODS/Essential for fixing some of the * stupid bugs in my code. * * Softnet support and various other patches from Val Henson of * ODS/Essential. * * PCI DMA mapping code partly based on work by Francois Romieu.
*/
/* * Implementation notes: * * The DMA engine only allows for DMA within physical 64KB chunks of * memory. The current approach of the driver (and stack) is to use * linear blocks of memory for the skbuffs. However, as the data block * is always the first part of the skb and skbs are 2^n aligned so we * are guarantted to get the whole block within one 64KB align 64KB * chunk. * * On the long term, relying on being able to allocate 64KB linear * chunks of memory is not feasible and the skb handling code and the * stack will need to know about I/O vectors or something similar.
*/
dev = alloc_hippi_dev(sizeof(struct rr_private)); if (!dev) goto out3;
ret = pci_enable_device(pdev); if (ret) {
ret = -ENODEV; goto out2;
}
rrpriv = netdev_priv(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
ret = pci_request_regions(pdev, "rrunner"); if (ret < 0) goto out;
pci_set_drvdata(pdev, dev);
rrpriv->pci_dev = pdev;
spin_lock_init(&rrpriv->lock);
dev->netdev_ops = &rr_netdev_ops;
/* display version info if adapter is found */ if (!version_disp) { /* set display flag to TRUE so that */ /* we only display this string ONCE */
version_disp = 1;
printk(version);
}
/* * Don't access any register before this point!
*/ #ifdef __BIG_ENDIAN
writel(readl(&rrpriv->regs->HostCtrl) | NO_SWAP,
&rrpriv->regs->HostCtrl); #endif /* * Need to add a case for little-endian 64-bit hosts here.
*/
rr_init(dev);
ret = register_netdev(dev); if (ret) goto out; return 0;
out: if (rrpriv->evt_ring)
dma_free_coherent(&pdev->dev, EVT_RING_SIZE, rrpriv->evt_ring,
rrpriv->evt_ring_dma); if (rrpriv->rx_ring)
dma_free_coherent(&pdev->dev, RX_TOTAL_SIZE, rrpriv->rx_ring,
rrpriv->rx_ring_dma); if (rrpriv->tx_ring)
dma_free_coherent(&pdev->dev, TX_TOTAL_SIZE, rrpriv->tx_ring,
rrpriv->tx_ring_dma); if (rrpriv->regs)
pci_iounmap(pdev, rrpriv->regs); if (pdev)
pci_release_regions(pdev);
pci_disable_device(pdev);
out2:
free_netdev(dev);
out3: return ret;
}
/* * Commands are considered to be slow, thus there is no reason to * inline this.
*/ staticvoid rr_issue_cmd(struct rr_private *rrpriv, struct cmd *cmd)
{ struct rr_regs __iomem *regs;
u32 idx;
regs = rrpriv->regs; /* * This is temporary - it will go away in the final version. * We probably also want to make this function inline.
*/ if (readl(®s->HostCtrl) & NIC_HALTED){
printk("issuing command for halted NIC, code 0x%x, " "HostCtrl %08x\n", cmd->code, readl(®s->HostCtrl)); if (readl(®s->Mode) & FATAL_ERR)
printk("error codes Fail1 %02x, Fail2 %02x\n",
readl(®s->Fail1), readl(®s->Fail2));
}
if (readl(®s->Mode) & FATAL_ERR)
printk("error code %02x\n", readl(®s->Fail1));
}
/* * Reset the board in a sensible manner. The NIC is already halted * when we get here and a spin-lock is held.
*/ staticint rr_reset(struct net_device *dev)
{ struct rr_private *rrpriv; struct rr_regs __iomem *regs;
u32 start_pc; int i;
/* * Shortcut to read one word (4 bytes) out of the EEPROM and convert * it to our CPU byte-order.
*/ static u32 rr_read_eeprom_word(struct rr_private *rrpriv,
size_t offset)
{
__be32 word;
/* * Write a string to the EEPROM. * * This is only called when the firmware is not running.
*/ staticunsignedint write_eeprom(struct rr_private *rrpriv, unsignedlong offset, unsignedchar *buf, unsignedlong length)
{ struct rr_regs __iomem *regs = rrpriv->regs;
u32 misc, io, data, i, j, ready, error = 0;
for (i = 0; i < length; i++){
writel((EEPROM_BASE + ((offset+i) << 3)), ®s->WinBase);
mb();
data = buf[i] << 24; /* * Only try to write the data if it is not the same * value already.
*/ if ((readl(®s->WinData) & 0xff000000) != data){
writel(data, ®s->WinData);
ready = 0;
j = 0;
mb(); while(!ready){
udelay(20); if ((readl(®s->WinData) & 0xff000000) ==
data)
ready = 1;
mb(); if (j++ > 5000){
printk("data mismatch: %08x, " "WinData %08x\n", data,
readl(®s->WinData));
ready = 1;
error = 1;
}
}
}
}
/* * Read the hardware address from the eeprom. The HW address * is not really necessary for HIPPI but awfully convenient. * The pointer arithmetic to put it in dev_addr is ugly, but * Donald Becker does it this way for the GigE version of this * card and it's shorter and more portable than any * other method I've seen. -VAL
*/
/* * Set dirty_tx before we start receiving interrupts, otherwise * the interrupt handler might think it is supposed to process * tx ints before we are up and running, which may cause a null * pointer access in the int handler.
*/
rrpriv->tx_full = 0;
rrpriv->cur_rx = 0;
rrpriv->dirty_rx = rrpriv->dirty_tx = 0;
/* * Now start the FirmWare.
*/
cmd.code = C_START_FW;
cmd.ring = 0;
cmd.index = 0;
rr_issue_cmd(rrpriv, &cmd);
/* * Give the FirmWare time to chew on the `get running' command.
*/
myjif = jiffies + 5 * HZ; while (time_before(jiffies, myjif) && !rrpriv->fw_running)
cpu_relax();
netif_start_queue(dev);
return ecode;
error: /* * We might have gotten here because we are out of memory, * make sure we release everything we allocated before failing
*/ for (i = 0; i < RX_RING_ENTRIES; i++) { struct sk_buff *skb = rrpriv->rx_skbuff[i];
/* * All events are considered to be slow (RX/TX ints do not generate * events) and are handled here, outside the main interrupt handler, * to reduce the size of the handler.
*/ static u32 rr_handle_event(struct net_device *dev, u32 prodidx, u32 eidx)
{ struct rr_private *rrpriv; struct rr_regs __iomem *regs;
u32 tmp;
rrpriv = netdev_priv(dev);
regs = rrpriv->regs;
while (prodidx != eidx){ switch (rrpriv->evt_ring[eidx].code){ case E_NIC_UP:
tmp = readl(®s->FwRev);
printk(KERN_INFO "%s: Firmware revision %i.%i.%i " "up and running\n", dev->name,
(tmp >> 16), ((tmp >> 8) & 0xff), (tmp & 0xff));
rrpriv->fw_running = 1;
writel(RX_RING_ENTRIES - 1, ®s->IpRxPi);
wmb(); break; case E_LINK_ON:
printk(KERN_INFO "%s: Optical link ON\n", dev->name); break; case E_LINK_OFF:
printk(KERN_INFO "%s: Optical link OFF\n", dev->name); break; case E_RX_IDLE:
printk(KERN_WARNING "%s: RX data not moving\n",
dev->name); goto drop; case E_WATCHDOG:
printk(KERN_INFO "%s: The watchdog is here to see " "us\n", dev->name); break; case E_INTERN_ERR:
printk(KERN_ERR "%s: HIPPI Internal NIC error\n",
dev->name);
writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
®s->HostCtrl);
wmb(); break; case E_HOST_ERR:
printk(KERN_ERR "%s: Host software error\n",
dev->name);
writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
®s->HostCtrl);
wmb(); break; /* * TX events.
*/ case E_CON_REJ:
printk(KERN_WARNING "%s: Connection rejected\n",
dev->name);
dev->stats.tx_aborted_errors++; break; case E_CON_TMOUT:
printk(KERN_WARNING "%s: Connection timeout\n",
dev->name); break; case E_DISC_ERR:
printk(KERN_WARNING "%s: HIPPI disconnect error\n",
dev->name);
dev->stats.tx_aborted_errors++; break; case E_INT_PRTY:
printk(KERN_ERR "%s: HIPPI Internal Parity error\n",
dev->name);
writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
®s->HostCtrl);
wmb(); break; case E_TX_IDLE:
printk(KERN_WARNING "%s: Transmitter idle\n",
dev->name); break; case E_TX_LINK_DROP:
printk(KERN_WARNING "%s: Link lost during transmit\n",
dev->name);
dev->stats.tx_aborted_errors++;
writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
®s->HostCtrl);
wmb(); break; case E_TX_INV_RNG:
printk(KERN_ERR "%s: Invalid send ring block\n",
dev->name);
writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
®s->HostCtrl);
wmb(); break; case E_TX_INV_BUF:
printk(KERN_ERR "%s: Invalid send buffer address\n",
dev->name);
writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
®s->HostCtrl);
wmb(); break; case E_TX_INV_DSC:
printk(KERN_ERR "%s: Invalid descriptor address\n",
dev->name);
writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
®s->HostCtrl);
wmb(); break; /* * RX events.
*/ case E_RX_RNG_OUT:
printk(KERN_INFO "%s: Receive ring full\n", dev->name); break;
case E_RX_PAR_ERR:
printk(KERN_WARNING "%s: Receive parity error\n",
dev->name); goto drop; case E_RX_LLRC_ERR:
printk(KERN_WARNING "%s: Receive LLRC error\n",
dev->name); goto drop; case E_PKT_LN_ERR:
printk(KERN_WARNING "%s: Receive packet length " "error\n", dev->name); goto drop; case E_DTA_CKSM_ERR:
printk(KERN_WARNING "%s: Data checksum error\n",
dev->name); goto drop; case E_SHT_BST:
printk(KERN_WARNING "%s: Unexpected short burst " "error\n", dev->name); goto drop; case E_STATE_ERR:
printk(KERN_WARNING "%s: Recv. state transition" " error\n", dev->name); goto drop; case E_UNEXP_DATA:
printk(KERN_WARNING "%s: Unexpected data error\n",
dev->name); goto drop; case E_LST_LNK_ERR:
printk(KERN_WARNING "%s: Link lost error\n",
dev->name); goto drop; case E_FRM_ERR:
printk(KERN_WARNING "%s: Framing Error\n",
dev->name); goto drop; case E_FLG_SYN_ERR:
printk(KERN_WARNING "%s: Flag sync. lost during " "packet\n", dev->name); goto drop; case E_RX_INV_BUF:
printk(KERN_ERR "%s: Invalid receive buffer " "address\n", dev->name);
writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
®s->HostCtrl);
wmb(); break; case E_RX_INV_DSC:
printk(KERN_ERR "%s: Invalid receive descriptor " "address\n", dev->name);
writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
®s->HostCtrl);
wmb(); break; case E_RNG_BLK:
printk(KERN_ERR "%s: Invalid ring block\n",
dev->name);
writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
®s->HostCtrl);
wmb(); break;
drop: /* Label packet to be dropped. * Actual dropping occurs in rx * handling. * * The index of packet we get to drop is * the index of the packet following * the bad packet. -kbf
*/
{
u16 index = rrpriv->evt_ring[eidx].index;
index = (index + (RX_RING_ENTRIES - 1)) %
RX_RING_ENTRIES;
rrpriv->rx_ring[index].mode |=
(PACKET_BAD | PACKET_END);
} break; default:
printk(KERN_WARNING "%s: Unhandled event 0x%02x\n",
dev->name, rrpriv->evt_ring[eidx].code);
}
eidx = (eidx + 1) % EVT_RING_ENTRIES;
}
#if (DEBUG > 2)
printk("%s: interrupt, prodidx = %i, eidx = %i\n", dev->name,
prodidx, rrpriv->info->evt_ctrl.pi); #endif /* * Order here is important. We must handle events * before doing anything else in order to catch * such things as LLRC errors, etc -kbf
*/
rxindex = rrpriv->cur_rx; if (rxindex != rxlimit)
rx_int(dev, rxlimit, rxindex);
txcon = rrpriv->dirty_tx; if (txcsmr != txcon) { do { /* Due to occational firmware TX producer/consumer out * of sync. error need to check entry in ring -kbf
*/ if(rrpriv->tx_skbuff[txcon]){ struct tx_desc *desc; struct sk_buff *skb;
/* Set the timer to switch to check for link beat and perhaps switch
to an alternate media type. */
timer_setup(&rrpriv->timer, rr_timer, 0);
rrpriv->timer.expires = RUN_AT(5*HZ); /* 5 sec. watchdog */
add_timer(&rrpriv->timer);
index = (((readl(®s->EvtPrd) >> 8) & 0xff) - 1) % TX_RING_ENTRIES;
cons = rrpriv->dirty_tx;
printk("TX ring index %i, TX consumer %i\n",
index, cons);
if (rrpriv->tx_skbuff[index]){
len = min_t(int, 0x80, rrpriv->tx_skbuff[index]->len);
printk("skbuff for index %i is valid - dumping data (0x%x bytes - DMA len 0x%x)\n", index, len, rrpriv->tx_ring[index].size); for (i = 0; i < len; i++){ if (!(i & 7))
printk("\n");
printk("%02x ", (unsignedchar) rrpriv->tx_skbuff[index]->data[i]);
}
printk("\n");
}
if (rrpriv->tx_skbuff[cons]){
len = min_t(int, 0x80, rrpriv->tx_skbuff[cons]->len);
printk("skbuff for cons %i is valid - dumping data (0x%x bytes - skbuff len 0x%x)\n", cons, len, rrpriv->tx_skbuff[cons]->len);
printk("mode 0x%x, size 0x%x,\n phys %08Lx, skbuff-addr %p, truesize 0x%x\n",
rrpriv->tx_ring[cons].mode,
rrpriv->tx_ring[cons].size,
(unsignedlonglong) rrpriv->tx_ring[cons].addr.addrlo,
rrpriv->tx_skbuff[cons]->data,
(unsignedint)rrpriv->tx_skbuff[cons]->truesize); for (i = 0; i < len; i++){ if (!(i & 7))
printk("\n");
printk("%02x ", (unsignedchar)rrpriv->tx_ring[cons].size);
}
printk("\n");
}
printk("dumping TX ring info:\n"); for (i = 0; i < TX_RING_ENTRIES; i++)
printk("mode 0x%x, size 0x%x, phys-addr %08Lx\n",
rrpriv->tx_ring[i].mode,
rrpriv->tx_ring[i].size,
(unsignedlonglong) rrpriv->tx_ring[i].addr.addrlo);
if (txctrl->pi == rrpriv->dirty_tx){
rrpriv->tx_full = 1;
netif_stop_queue(dev);
}
spin_unlock_irqrestore(&rrpriv->lock, flags);
return NETDEV_TX_OK;
}
/* * Read the firmware out of the EEPROM and put it into the SRAM * (or from user space - later) * * This operation requires the NIC to be halted and is performed with * interrupts disabled and with the spinlock hold.
*/ staticint rr_load_firmware(struct net_device *dev)
{ struct rr_private *rrpriv; struct rr_regs __iomem *regs;
size_t eptr, segptr; int i, j;
u32 localctrl, sptr, len, tmp;
u32 p2len, p2size, nr_seg, revision, io, sram_size;
rrpriv = netdev_priv(dev);
regs = rrpriv->regs;
if (dev->flags & IFF_UP) return -EBUSY;
if (!(readl(®s->HostCtrl) & NIC_HALTED)){
printk("%s: Trying to load firmware to a running NIC.\n",
dev->name); return -EBUSY;
}
/* * First wipe the entire SRAM, otherwise we might run into all * kinds of trouble ... sigh, this took almost all afternoon * to track down ;-(
*/
io = readl(®s->ExtIo);
writel(0, ®s->ExtIo);
sram_size = rr_read_eeprom_word(rrpriv, 8);
for (i = 200; i < sram_size / 4; i++){
writel(i * 4, ®s->WinBase);
mb();
writel(0, ®s->WinData);
mb();
}
writel(io, ®s->ExtIo);
mb();
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.