📄 myri_sbus.c
字号:
/* myri_sbus.h: MyriCOM MyriNET SBUS card driver. * * Copyright (C) 1996, 1999 David S. Miller (davem@redhat.com) */static char *version = "myri_sbus.c:v1.9 12/Sep/99 David S. Miller (davem@redhat.com)\n";#include <linux/module.h>#include <linux/config.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/types.h>#include <linux/fcntl.h>#include <linux/interrupt.h>#include <linux/ptrace.h>#include <linux/ioport.h>#include <linux/in.h>#include <linux/malloc.h>#include <linux/string.h>#include <linux/delay.h>#include <linux/init.h>#include <asm/system.h>#include <asm/bitops.h>#include <asm/io.h>#include <asm/dma.h>#include <linux/errno.h>#include <asm/byteorder.h>#include <asm/idprom.h>#include <asm/sbus.h>#include <asm/openprom.h>#include <asm/oplib.h>#include <asm/auxio.h>#include <asm/pgtable.h>#include <asm/irq.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/skbuff.h>#include <net/dst.h>#include <net/arp.h>#include <net/sock.h>#include <net/ipv6.h>#include <asm/checksum.h>#include "myri_sbus.h"#include "myri_code.h"/* #define DEBUG_DETECT *//* #define DEBUG_IRQ *//* #define DEBUG_TRANSMIT *//* #define DEBUG_RECEIVE *//* #define DEBUG_HEADER */#ifdef DEBUG_DETECT#define DET(x) printk x#else#define DET(x)#endif#ifdef DEBUG_IRQ#define DIRQ(x) printk x#else#define DIRQ(x)#endif#ifdef DEBUG_TRANSMIT#define DTX(x) printk x#else#define DTX(x)#endif#ifdef DEBUG_RECEIVE#define DRX(x) printk x#else#define DRX(x)#endif#ifdef DEBUG_HEADER#define DHDR(x) printk x#else#define DHDR(x)#endif#ifdef MODULEstatic struct myri_eth *root_myri_dev = NULL;#endifstatic void myri_reset_off(unsigned long lp, unsigned long cregs){ /* Clear IRQ mask. */ sbus_writel(0, lp + LANAI_EIMASK); /* Turn RESET function off. */ sbus_writel(CONTROL_ROFF, cregs + MYRICTRL_CTRL);}static void myri_reset_on(unsigned long cregs){ /* Enable RESET function. */ sbus_writel(CONTROL_RON, cregs + MYRICTRL_CTRL); /* Disable IRQ's. */ sbus_writel(CONTROL_DIRQ, cregs + MYRICTRL_CTRL);}static void myri_disable_irq(unsigned long lp, unsigned long cregs){ sbus_writel(CONTROL_DIRQ, cregs + MYRICTRL_CTRL); sbus_writel(0, lp + LANAI_EIMASK); sbus_writel(ISTAT_HOST, lp + LANAI_ISTAT);}static void myri_enable_irq(unsigned long lp, unsigned long cregs){ sbus_writel(CONTROL_EIRQ, cregs + MYRICTRL_CTRL); sbus_writel(ISTAT_HOST, lp + LANAI_EIMASK);}static inline void bang_the_chip(struct myri_eth *mp){ struct myri_shmem *shmem = mp->shmem; unsigned long cregs = mp->cregs; sbus_writel(1, &shmem->send); sbus_writel(CONTROL_WON, cregs + MYRICTRL_CTRL);}static int myri_do_handshake(struct myri_eth *mp){ struct myri_shmem *shmem = mp->shmem; unsigned long cregs = mp->cregs; struct myri_channel *chan = &shmem->channel; int tick = 0; DET(("myri_do_handshake: ")); if (sbus_readl(&chan->state) == STATE_READY) { DET(("Already STATE_READY, failed.\n")); return -1; /* We're hosed... */ } myri_disable_irq(mp->lregs, cregs); while (tick++ <= 25) { u32 softstate; /* Wake it up. */ DET(("shakedown, CONTROL_WON, ")); sbus_writel(1, &shmem->shakedown); sbus_writel(CONTROL_WON, cregs + MYRICTRL_CTRL); softstate = sbus_readl(&chan->state); DET(("chanstate[%08x] ", softstate)); if (softstate == STATE_READY) { DET(("wakeup successful, ")); break; } if (softstate != STATE_WFN) { DET(("not WFN setting that, ")); sbus_writel(STATE_WFN, &chan->state); } udelay(20); } myri_enable_irq(mp->lregs, cregs); if (tick > 25) { DET(("25 ticks we lose, failure.\n")); return -1; } DET(("success\n")); return 0;}static int myri_load_lanai(struct myri_eth *mp){ struct net_device *dev = mp->dev; struct myri_shmem *shmem = mp->shmem; unsigned char *rptr; int i; myri_disable_irq(mp->lregs, mp->cregs); myri_reset_on(mp->cregs); rptr = (unsigned char *) mp->lanai; for (i = 0; i < mp->eeprom.ramsz; i++) sbus_writeb(0, &rptr[i]); if (mp->eeprom.cpuvers >= CPUVERS_3_0) sbus_writel(mp->eeprom.cval, mp->lregs + LANAI_CVAL); /* Load executable code. */ for (i = 0; i < sizeof(lanai4_code); i++) sbus_writeb(lanai4_code[i], &rptr[(lanai4_code_off * 2) + i]); /* Load data segment. */ for (i = 0; i < sizeof(lanai4_data); i++) sbus_writeb(lanai4_data[i], &rptr[(lanai4_data_off * 2) + i]); /* Set device address. */ sbus_writeb(0, &shmem->addr[0]); sbus_writeb(0, &shmem->addr[1]); for (i = 0; i < 6; i++) sbus_writeb(dev->dev_addr[i], &shmem->addr[i + 2]); /* Set SBUS bursts and interrupt mask. */ sbus_writel(((mp->myri_bursts & 0xf8) >> 3), &shmem->burst); sbus_writel(SHMEM_IMASK_RX, &shmem->imask); /* Release the LANAI. */ myri_disable_irq(mp->lregs, mp->cregs); myri_reset_off(mp->lregs, mp->cregs); myri_disable_irq(mp->lregs, mp->cregs); /* Wait for the reset to complete. */ for (i = 0; i < 5000; i++) { if (sbus_readl(&shmem->channel.state) != STATE_READY) break; else udelay(10); } if (i == 5000) printk(KERN_ERR "myricom: Chip would not reset after firmware load.\n"); i = myri_do_handshake(mp); if (i) printk(KERN_ERR "myricom: Handshake with LANAI failed.\n"); if (mp->eeprom.cpuvers == CPUVERS_4_0) sbus_writel(0, mp->lregs + LANAI_VERS); return i;}static void myri_clean_rings(struct myri_eth *mp){ struct sendq *sq = mp->sq; struct recvq *rq = mp->rq; int i; sbus_writel(0, &rq->tail); sbus_writel(0, &rq->head); for (i = 0; i < (RX_RING_SIZE+1); i++) { if (mp->rx_skbs[i] != NULL) { struct myri_rxd *rxd = &rq->myri_rxd[i]; u32 dma_addr; dma_addr = sbus_readl(&rxd->myri_scatters[0].addr); sbus_unmap_single(mp->myri_sdev, dma_addr, RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE); dev_kfree_skb(mp->rx_skbs[i]); mp->rx_skbs[i] = NULL; } } mp->tx_old = 0; sbus_writel(0, &sq->tail); sbus_writel(0, &sq->head); for (i = 0; i < TX_RING_SIZE; i++) { if (mp->tx_skbs[i] != NULL) { struct sk_buff *skb = mp->tx_skbs[i]; struct myri_txd *txd = &sq->myri_txd[i]; u32 dma_addr; dma_addr = sbus_readl(&txd->myri_gathers[0].addr); sbus_unmap_single(mp->myri_sdev, dma_addr, (skb->len + 3) & ~3, SBUS_DMA_TODEVICE); dev_kfree_skb(mp->tx_skbs[i]); mp->tx_skbs[i] = NULL; } }}static void myri_init_rings(struct myri_eth *mp, int from_irq){ struct recvq *rq = mp->rq; struct myri_rxd *rxd = &rq->myri_rxd[0]; struct net_device *dev = mp->dev; int gfp_flags = GFP_KERNEL; int i; if (from_irq || in_interrupt()) gfp_flags = GFP_ATOMIC; myri_clean_rings(mp); for (i = 0; i < RX_RING_SIZE; i++) { struct sk_buff *skb = myri_alloc_skb(RX_ALLOC_SIZE, gfp_flags); u32 dma_addr; if (!skb) continue; mp->rx_skbs[i] = skb; skb->dev = dev; skb_put(skb, RX_ALLOC_SIZE); dma_addr = sbus_map_single(mp->myri_sdev, skb->data, RX_ALLOC_SIZE, SBUS_DMA_FROMDEVICE); sbus_writel(dma_addr, &rxd[i].myri_scatters[0].addr); sbus_writel(RX_ALLOC_SIZE, &rxd[i].myri_scatters[0].len); sbus_writel(i, &rxd[i].ctx); sbus_writel(1, &rxd[i].num_sg); } sbus_writel(0, &rq->head); sbus_writel(RX_RING_SIZE, &rq->tail);}static int myri_init(struct myri_eth *mp, int from_irq){ myri_init_rings(mp, from_irq); return 0;}static void myri_is_not_so_happy(struct myri_eth *mp){}#ifdef DEBUG_HEADERstatic void dump_ehdr(struct ethhdr *ehdr){ printk("ehdr[h_dst(%02x:%02x:%02x:%02x:%02x:%02x)" "h_source(%02x:%02x:%02x:%02x:%02x:%02x)h_proto(%04x)]\n", ehdr->h_dest[0], ehdr->h_dest[1], ehdr->h_dest[2], ehdr->h_dest[3], ehdr->h_dest[4], ehdr->h_dest[4], ehdr->h_source[0], ehdr->h_source[1], ehdr->h_source[2], ehdr->h_source[3], ehdr->h_source[4], ehdr->h_source[4], ehdr->h_proto);}static void dump_ehdr_and_myripad(unsigned char *stuff){ struct ethhdr *ehdr = (struct ethhdr *) (stuff + 2); printk("pad[%02x:%02x]", stuff[0], stuff[1]); printk("ehdr[h_dst(%02x:%02x:%02x:%02x:%02x:%02x)" "h_source(%02x:%02x:%02x:%02x:%02x:%02x)h_proto(%04x)]\n", ehdr->h_dest[0], ehdr->h_dest[1], ehdr->h_dest[2], ehdr->h_dest[3], ehdr->h_dest[4], ehdr->h_dest[4], ehdr->h_source[0], ehdr->h_source[1], ehdr->h_source[2], ehdr->h_source[3], ehdr->h_source[4], ehdr->h_source[4], ehdr->h_proto);}#endifstatic void myri_tx(struct myri_eth *mp, struct net_device *dev){ struct sendq *sq = mp->sq; int entry = mp->tx_old; int limit = sbus_readl(&sq->head); DTX(("entry[%d] limit[%d] ", entry, limit)); if (entry == limit) return; while (entry != limit) { struct sk_buff *skb = mp->tx_skbs[entry]; u32 dma_addr; DTX(("SKB[%d] ", entry)); dma_addr = sbus_readl(&sq->myri_txd[entry].myri_gathers[0].addr); sbus_unmap_single(mp->myri_sdev, dma_addr, skb->len, SBUS_DMA_TODEVICE); dev_kfree_skb(skb); mp->tx_skbs[entry] = NULL; mp->enet_stats.tx_packets++; entry = NEXT_TX(entry); } mp->tx_old = entry;}/* Determine the packet's protocol ID. The rule here is that we * assume 802.3 if the type field is short enough to be a length. * This is normal practice and works for any 'now in use' protocol. */static unsigned short myri_type_trans(struct sk_buff *skb, struct net_device *dev){ struct ethhdr *eth; unsigned char *rawp;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -