📄 rrunner.c
字号:
/* * rrunner.c: Linux driver for the Essential RoadRunner HIPPI board. * * Written 1998 by Jes Sorensen, <Jes.Sorensen@cern.ch>. * * 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. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */#define DEBUG 1#define RX_DMA_SKBUFF 1#define PKT_COPY_THRESHOLD 512#include <linux/module.h>#include <linux/types.h>#include <linux/errno.h>#include <linux/ioport.h>#include <linux/pci.h>#include <linux/kernel.h>#include <linux/netdevice.h>#include <linux/hippidevice.h>#include <linux/skbuff.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/mm.h>#include <net/sock.h>#include <asm/system.h>#include <asm/cache.h>#include <asm/byteorder.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/uaccess.h>#include "rrunner.h"/* * 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. */static const char *version = "rrunner.c: v0.09 12/14/98 Jes Sorensen (Jes.Sorensen@cern.ch)\n";static unsigned int read_eeprom(struct rr_private *rrpriv, unsigned long offset, unsigned char *buf, unsigned long length);static u32 read_eeprom_word(struct rr_private *rrpriv, void * offset);static int rr_load_firmware(struct device *dev);/* * These are checked at init time to see if they are at least 256KB * and increased to 256KB if they are not. This is done to avoid ending * up with socket buffers smaller than the MTU size, */extern __u32 sysctl_wmem_max;extern __u32 sysctl_rmem_max;__initfunc(int rr_hippi_probe (struct device *dev)){ static int i = 0; int boards_found = 0; int version_disp; /* was version info already displayed? */ u8 pci_bus; /* PCI bus number (0-255) */ u8 pci_dev_fun; /* PCI device and function numbers (0-255) */ u8 pci_latency; u16 command; /* PCI Configuration space Command register */ unsigned int tmp; u8 irq; struct rr_private *rrpriv; if (!pci_present()) /* is PCI BIOS even present? */ return -ENODEV; version_disp = 0; for (; i < 255; i++) { if (pcibios_find_device(PCI_VENDOR_ID_ESSENTIAL, PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER, i, &pci_bus, &pci_dev_fun) != 0) break; pcibios_read_config_word(pci_bus, pci_dev_fun, PCI_COMMAND, &command); /* Enable mastering */ command |= PCI_COMMAND_MASTER; pcibios_write_config_word(pci_bus, pci_dev_fun, PCI_COMMAND, command); if (!(command & PCI_COMMAND_MEMORY)){ printk("shared mem not enabled - unable to configure RoadRunner\n"); break; } /* * So we found our HIPPI ... time to tell the system. */ dev = init_hippi_dev(dev, sizeof(struct rr_private)); if (dev == NULL) break; if (!dev->priv) dev->priv = kmalloc(sizeof(*rrpriv), GFP_KERNEL); rrpriv = (struct rr_private *)dev->priv; /* Read register base address from PCI Configuration Space */ pcibios_read_config_dword(pci_bus, pci_dev_fun, PCI_BASE_ADDRESS_0, &tmp); pcibios_read_config_byte(pci_bus, pci_dev_fun, PCI_INTERRUPT_LINE, &irq); dev->irq = irq; rrpriv->pci_bus = pci_bus; rrpriv->pci_dev_fun = pci_dev_fun; sprintf(rrpriv->name, "RoadRunner serial HIPPI");#ifdef __SMP__ spin_lock_init(&rrpriv->lock);#endif dev->open = &rr_open; dev->hard_start_xmit = &rr_start_xmit; dev->stop = &rr_close; dev->get_stats = &rr_get_stats; dev->do_ioctl = &rr_ioctl; /* * Dummy value. */ dev->base_addr = 42; /* 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); } printk(KERN_INFO "%s: Essential RoadRunner serial HIPPI at 0x%08x, irq %i\n", dev->name, tmp, dev->irq); pcibios_read_config_byte(pci_bus, pci_dev_fun, PCI_LATENCY_TIMER, &pci_latency);#if 0 if (pci_latency <= 48){ printk(" PCI latency counter too low (%i), setting to 48 clocks\n", pci_latency); pcibios_write_config_byte(pci_bus, pci_dev_fun, PCI_LATENCY_TIMER, 48); }#else if (pci_latency <= 0x58) pcibios_write_config_byte(pci_bus, pci_dev_fun, PCI_LATENCY_TIMER, 0x58);#endif /* * Remap the regs into kernel space. */ rrpriv->regs = (struct rr_regs *)ioremap(tmp, 0x1000); if (!rrpriv->regs){ printk(KERN_ERR "%s: Unable to map I/O register, RoadRunner %i will be disabled.\n", dev->name, i); break; } /* * Don't access any registes before this point! */#ifdef __BIG_ENDIAN regs->HostCtrl |= NO_SWAP;#endif /* * Need to add a case for little-endian 64-bit hosts here. */ rr_init(dev); boards_found++; dev->base_addr = 0; dev = NULL; } /* * If we're at this point we're going through rr_hippi_probe() * for the first time. Return success (0) if we've initialized * 1 or more boards. Otherwise, return failure (-ENODEV). */ if (boards_found > 0) return 0; else return -ENODEV;}/* * Commands are considered to be slow, thus there is no reason to * inline this. */static void rr_issue_cmd(struct rr_private *rrpriv, struct cmd *cmd){ struct rr_regs *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 (regs->HostCtrl & NIC_HALTED){ printk("issuing command for halted NIC, code 0x%x, HostCtrl %08x\n", cmd->code, regs->HostCtrl); if (regs->Mode & FATAL_ERR) printk("error code %02x\n", regs->Fail1); } idx = rrpriv->info->cmd_ctrl.pi; regs->CmdRing[idx] = *(u32*)(cmd); idx = (idx - 1) % CMD_RING_ENTRIES; rrpriv->info->cmd_ctrl.pi = idx; if (regs->Mode & FATAL_ERR) printk("error code %02x\n", regs->Fail1);}/* * Reset the board in a sensible manner. The NIC is already halted * when we get here and a spin-lock is held. */static int rr_reset(struct device *dev){ struct rr_private *rrpriv; struct rr_regs *regs; struct eeprom *hw = NULL; u32 start_pc; int i; rrpriv = (struct rr_private *)dev->priv; regs = rrpriv->regs; rr_load_firmware(dev); regs->TX_state = 0x01000000; regs->RX_state = 0xff800000; regs->AssistState = 0; regs->LocalCtrl = CLEAR_INTA; regs->BrkPt = 0x01; regs->Timer = 0; regs->TimerRef = 0; regs->DmaReadState = RESET_DMA; regs->DmaWriteState = RESET_DMA; regs->DmaWriteHostHi = 0; regs->DmaWriteHostLo = 0; regs->DmaReadHostHi = 0; regs->DmaReadHostLo = 0; regs->DmaReadLen = 0; regs->DmaWriteLen = 0; regs->DmaWriteLcl = 0; regs->DmaWriteIPchecksum = 0; regs->DmaReadLcl = 0; regs->DmaReadIPchecksum = 0; regs->PciState = 0; /* 0x90 for GE? */ regs->Mode = SWAP_DATA;#if 0 /* * Don't worry, this is just black magic. */ regs->RxBase = 0xdf000; regs->RxPrd = 0xdf000; regs->RxCon = 0xdf000; regs->TxBase = 0xce000; regs->TxPrd = 0xce000; regs->TxCon = 0xce000; regs->RxIndPro = 0; regs->RxIndCon = 0; regs->RxIndRef = 0; regs->TxIndPro = 0; regs->TxIndCon = 0; regs->TxIndRef = 0; regs->pad10[0] = 0xcc000; regs->DrCmndPro = 0; regs->DrCmndCon = 0; regs->DwCmndPro = 0; regs->DwCmndCon = 0; regs->DwCmndRef = 0; regs->DrDataPro = 0; regs->DrDataCon = 0; regs->DrDataRef = 0; regs->DwDataPro = 0; regs->DwDataCon = 0; regs->DwDataRef = 0;#endif regs->MbEvent = 0xffffffff; regs->Event = 0; regs->TxPi = 0; regs->IpRxPi = 0; regs->EvtCon = 0; regs->EvtPrd = 0; rrpriv->info->evt_ctrl.pi = 0; for (i = 0; i < CMD_RING_ENTRIES; i++) regs->CmdRing[i] = 0; regs->PciState = 0; start_pc = read_eeprom_word(rrpriv, &hw->rncd_info.FwStart);#if (DEBUG > 1) printk("%s: Executing firmware at address 0x%06x\n", dev->name, start_pc);#endif regs->Pc = start_pc + 0x800; udelay(5); regs->Pc = start_pc; return 0;}/* * Read a string from the EEPROM. */static unsigned int read_eeprom(struct rr_private *rrpriv, unsigned long offset, unsigned char *buf, unsigned long length){ struct rr_regs *regs = rrpriv->regs; u32 misc, io, host, i; io = regs->ExtIo; regs->ExtIo = 0; misc = regs->LocalCtrl; regs->LocalCtrl = 0; host = regs->HostCtrl; regs->HostCtrl |= HALT_NIC; for (i = 0; i < length; i++){ regs->WinBase = (EEPROM_BASE + ((offset+i) << 3)); buf[i] = (regs->WinData >> 24) & 0xff; } regs->HostCtrl = host; regs->LocalCtrl = misc; regs->ExtIo = io; return i;}/* * Shortcut to read one word (4 bytes) out of the EEPROM and convert * it to our CPU byte-order. */static u32 read_eeprom_word(struct rr_private *rrpriv, void * offset){ u32 word; if ((read_eeprom(rrpriv, (unsigned long)offset, (char *)&word, 4) == 4)) return be32_to_cpu(word); return 0;}/* * Write a string to the EEPROM. * * This is only called when the firmware is not running. */static unsigned int write_eeprom(struct rr_private *rrpriv, unsigned long offset, unsigned char *buf, unsigned long length){ struct rr_regs *regs = rrpriv->regs; u32 misc, io, data, i, j, ready, error = 0; io = regs->ExtIo; regs->ExtIo = 0; misc = regs->LocalCtrl; regs->LocalCtrl = ENABLE_EEPROM_WRITE; for (i = 0; i < length; i++){ regs->WinBase = (EEPROM_BASE + ((offset+i) << 3)); data = buf[i] << 24; /* * Only try to write the data if it is not the same * value already. */ if ((regs->WinData & 0xff000000) != data){ regs->WinData = data; ready = 0; j = 0; mb(); while(!ready){ udelay(1000); if ((regs->WinData & 0xff000000) == data) ready = 1; if (j++ > 5000){ printk("data mismatch: %08x, " "WinData %08x\n", data, regs->WinData); ready = 1; error = 1; } } } } regs->LocalCtrl = misc; regs->ExtIo = io; return error;}__initfunc(static int rr_init(struct device *dev)){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -