📄 olympic.c
字号:
#if OLYMPIC_DEBUG printk("GPR = %x\n",readw(olympic_mmio + GPR) ) ; #endif /* Solo has been paused to meet the Cardbus power * specs if the adapter is cardbus. Check to * see its been paused and then restart solo. The * adapter should set the pause bit within 1 second. */ if(!(readl(olympic_mmio+BCTL) & BCTL_MODE_INDICATOR)) { t=jiffies; while (!readl(olympic_mmio+CLKCTL) & CLKCTL_PAUSE) { schedule() ; if(jiffies-t > 2*HZ) { printk(KERN_ERR "IBM Cardbus tokenring adapter not responsing.\n") ; return -ENODEV; } } writel(readl(olympic_mmio+CLKCTL) & ~CLKCTL_PAUSE, olympic_mmio+CLKCTL) ; } /* start solo init */ writel((1<<15),olympic_mmio+SISR_MASK_SUM); t=jiffies; while(!((readl(olympic_mmio+SISR_RR)) & SISR_SRB_REPLY)) { schedule(); if(jiffies-t > 15*HZ) { printk(KERN_ERR "IBM PCI tokenring card not responding.\n"); return -ENODEV; } } writel(readw(olympic_mmio+LAPWWO),olympic_mmio+LAPA);#if OLYMPIC_DEBUG printk("LAPWWO: %x, LAPA: %x\n",readl(olympic_mmio+LAPWWO), readl(olympic_mmio+LAPA));#endif init_srb=olympic_priv->olympic_lap + ((readw(olympic_mmio+LAPWWO)) & (~0xf800));#if OLYMPIC_DEBUG { int i; printk("init_srb(%p): ",init_srb); for(i=0;i<20;i++) printk("%x ",readb(init_srb+i)); printk("\n");}#endif if(readw(init_srb+6)) { printk(KERN_INFO "tokenring card initialization failed. errorcode : %x\n",readw(init_srb+6)); return -ENODEV; } if (olympic_priv->olympic_message_level) { if ( readb(init_srb +2) & 0x40) { printk(KERN_INFO "Olympic: Adapter is FDX capable.\n") ; } else { printk(KERN_INFO "Olympic: Adapter cannot do FDX.\n"); } } uaa_addr=swab16(readw(init_srb+8));#if OLYMPIC_DEBUG printk("UAA resides at %x\n",uaa_addr);#endif writel(uaa_addr,olympic_mmio+LAPA); adapter_addr=olympic_priv->olympic_lap + (uaa_addr & (~0xf800));#if OLYMPIC_DEBUG printk("adapter address: %02x:%02x:%02x:%02x:%02x:%02x\n", readb(adapter_addr), readb(adapter_addr+1),readb(adapter_addr+2), readb(adapter_addr+3),readb(adapter_addr+4),readb(adapter_addr+5));#endif memcpy_fromio(&dev->dev_addr[0], adapter_addr,6); olympic_priv->olympic_addr_table_addr = swab16(readw(init_srb + 12)); olympic_priv->olympic_parms_addr = swab16(readw(init_srb + 14)); return 0;}static int olympic_open(struct net_device *dev) { struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv; u8 __iomem *olympic_mmio=olympic_priv->olympic_mmio,*init_srb; unsigned long flags, t; int i, open_finished = 1 ; u8 resp, err; DECLARE_WAITQUEUE(wait,current) ; olympic_init(dev); if(request_irq(dev->irq, &olympic_interrupt, SA_SHIRQ , "olympic", dev)) { return -EAGAIN; }#if OLYMPIC_DEBUG printk("BMCTL: %x\n",readl(olympic_mmio+BMCTL_SUM)); printk("pending ints: %x\n",readl(olympic_mmio+SISR_RR));#endif writel(SISR_MI,olympic_mmio+SISR_MASK_SUM); writel(SISR_MI | SISR_SRB_REPLY, olympic_mmio+SISR_MASK); /* more ints later, doesn't stop arb cmd interrupt */ writel(LISR_LIE,olympic_mmio+LISR); /* more ints later */ /* adapter is closed, so SRB is pointed to by LAPWWO */ writel(readw(olympic_mmio+LAPWWO),olympic_mmio+LAPA); init_srb=olympic_priv->olympic_lap + ((readw(olympic_mmio+LAPWWO)) & (~0xf800)); #if OLYMPIC_DEBUG printk("LAPWWO: %x, LAPA: %x\n",readw(olympic_mmio+LAPWWO), readl(olympic_mmio+LAPA)); printk("SISR Mask = %04x\n", readl(olympic_mmio+SISR_MASK)); printk("Before the open command \n");#endif do { memset_io(init_srb,0,SRB_COMMAND_SIZE); writeb(SRB_OPEN_ADAPTER,init_srb) ; /* open */ writeb(OLYMPIC_CLEAR_RET_CODE,init_srb+2); /* If Network Monitor, instruct card to copy MAC frames through the ARB */ if (olympic_priv->olympic_network_monitor) writew(swab16(OPEN_ADAPTER_ENABLE_FDX | OPEN_ADAPTER_PASS_ADC_MAC | OPEN_ADAPTER_PASS_ATT_MAC | OPEN_ADAPTER_PASS_BEACON), init_srb+8); else writew(swab16(OPEN_ADAPTER_ENABLE_FDX), init_srb+8); /* Test OR of first 3 bytes as its totally possible for * someone to set the first 2 bytes to be zero, although this * is an error, the first byte must have bit 6 set to 1 */ if (olympic_priv->olympic_laa[0] | olympic_priv->olympic_laa[1] | olympic_priv->olympic_laa[2]) { writeb(olympic_priv->olympic_laa[0],init_srb+12); writeb(olympic_priv->olympic_laa[1],init_srb+13); writeb(olympic_priv->olympic_laa[2],init_srb+14); writeb(olympic_priv->olympic_laa[3],init_srb+15); writeb(olympic_priv->olympic_laa[4],init_srb+16); writeb(olympic_priv->olympic_laa[5],init_srb+17); memcpy(dev->dev_addr,olympic_priv->olympic_laa,dev->addr_len) ; } writeb(1,init_srb+30); spin_lock_irqsave(&olympic_priv->olympic_lock,flags); olympic_priv->srb_queued=1; writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM); spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags); t = jiffies ; add_wait_queue(&olympic_priv->srb_wait,&wait) ; set_current_state(TASK_INTERRUPTIBLE) ; while(olympic_priv->srb_queued) { schedule() ; if(signal_pending(current)) { printk(KERN_WARNING "%s: Signal received in open.\n", dev->name); printk(KERN_WARNING "SISR=%x LISR=%x\n", readl(olympic_mmio+SISR), readl(olympic_mmio+LISR)); olympic_priv->srb_queued=0; break; } if ((jiffies-t) > 10*HZ) { printk(KERN_WARNING "%s: SRB timed out. \n",dev->name) ; olympic_priv->srb_queued=0; break ; } set_current_state(TASK_INTERRUPTIBLE) ; } remove_wait_queue(&olympic_priv->srb_wait,&wait) ; set_current_state(TASK_RUNNING) ; olympic_priv->srb_queued = 0 ; #if OLYMPIC_DEBUG printk("init_srb(%p): ",init_srb); for(i=0;i<20;i++) printk("%02x ",readb(init_srb+i)); printk("\n");#endif /* If we get the same return response as we set, the interrupt wasn't raised and the open * timed out. */ switch (resp = readb(init_srb+2)) { case OLYMPIC_CLEAR_RET_CODE: printk(KERN_WARNING "%s: Adapter Open time out or error.\n", dev->name) ; goto out; case 0: open_finished = 1; break; case 0x07: if (!olympic_priv->olympic_ring_speed && open_finished) { /* Autosense , first time around */ printk(KERN_WARNING "%s: Retrying at different ring speed \n", dev->name); open_finished = 0 ; continue; } err = readb(init_srb+7); if (!olympic_priv->olympic_ring_speed && ((err & 0x0f) == 0x0d)) { printk(KERN_WARNING "%s: Tried to autosense ring speed with no monitors present\n",dev->name); printk(KERN_WARNING "%s: Please try again with a specified ring speed \n",dev->name); } else { printk(KERN_WARNING "%s: %s - %s\n", dev->name, open_maj_error[(err & 0xf0) >> 4], open_min_error[(err & 0x0f)]); } goto out; case 0x32: printk(KERN_WARNING "%s: Invalid LAA: %02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, olympic_priv->olympic_laa[0], olympic_priv->olympic_laa[1], olympic_priv->olympic_laa[2], olympic_priv->olympic_laa[3], olympic_priv->olympic_laa[4], olympic_priv->olympic_laa[5]) ; goto out; default: printk(KERN_WARNING "%s: Bad OPEN response: %x\n", dev->name, resp); goto out; } } while (!(open_finished)) ; /* Will only loop if ring speed mismatch re-open attempted && autosense is on */ if (readb(init_srb+18) & (1<<3)) if (olympic_priv->olympic_message_level) printk(KERN_INFO "%s: Opened in FDX Mode\n",dev->name); if (readb(init_srb+18) & (1<<1)) olympic_priv->olympic_ring_speed = 100 ; else if (readb(init_srb+18) & 1) olympic_priv->olympic_ring_speed = 16 ; else olympic_priv->olympic_ring_speed = 4 ; if (olympic_priv->olympic_message_level) printk(KERN_INFO "%s: Opened in %d Mbps mode\n",dev->name, olympic_priv->olympic_ring_speed); olympic_priv->asb = swab16(readw(init_srb+8)); olympic_priv->srb = swab16(readw(init_srb+10)); olympic_priv->arb = swab16(readw(init_srb+12)); olympic_priv->trb = swab16(readw(init_srb+16)); olympic_priv->olympic_receive_options = 0x01 ; olympic_priv->olympic_copy_all_options = 0 ; /* setup rx ring */ writel((3<<16),olympic_mmio+BMCTL_RWM); /* Ensure end of frame generated interrupts */ writel(BMCTL_RX_DIS|3,olympic_mmio+BMCTL_RWM); /* Yes, this the enables RX channel */ for(i=0;i<OLYMPIC_RX_RING_SIZE;i++) { struct sk_buff *skb; skb=dev_alloc_skb(olympic_priv->pkt_buf_sz); if(skb == NULL) break; skb->dev = dev; olympic_priv->olympic_rx_ring[i].buffer = cpu_to_le32(pci_map_single(olympic_priv->pdev, skb->data,olympic_priv->pkt_buf_sz, PCI_DMA_FROMDEVICE)) ; olympic_priv->olympic_rx_ring[i].res_length = cpu_to_le32(olympic_priv->pkt_buf_sz); olympic_priv->rx_ring_skb[i]=skb; } if (i==0) { printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers. Adapter disabled\n",dev->name); goto out; } olympic_priv->rx_ring_dma_addr = pci_map_single(olympic_priv->pdev,olympic_priv->olympic_rx_ring, sizeof(struct olympic_rx_desc) * OLYMPIC_RX_RING_SIZE, PCI_DMA_TODEVICE); writel(olympic_priv->rx_ring_dma_addr, olympic_mmio+RXDESCQ); writel(olympic_priv->rx_ring_dma_addr, olympic_mmio+RXCDA); writew(i, olympic_mmio+RXDESCQCNT); olympic_priv->rx_status_ring_dma_addr = pci_map_single(olympic_priv->pdev, olympic_priv->olympic_rx_status_ring, sizeof(struct olympic_rx_status) * OLYMPIC_RX_RING_SIZE, PCI_DMA_FROMDEVICE); writel(olympic_priv->rx_status_ring_dma_addr, olympic_mmio+RXSTATQ); writel(olympic_priv->rx_status_ring_dma_addr, olympic_mmio+RXCSA); olympic_priv->rx_ring_last_received = OLYMPIC_RX_RING_SIZE - 1; /* last processed rx status */ olympic_priv->rx_status_last_received = OLYMPIC_RX_RING_SIZE - 1; writew(i, olympic_mmio+RXSTATQCNT);#if OLYMPIC_DEBUG printk("# of rx buffers: %d, RXENQ: %x\n",i, readw(olympic_mmio+RXENQ)); printk("RXCSA: %x, rx_status_ring[0]: %p\n",readl(olympic_mmio+RXCSA),&olympic_priv->olympic_rx_status_ring[0]); printk(" stat_ring[1]: %p, stat_ring[2]: %p, stat_ring[3]: %p\n", &(olympic_priv->olympic_rx_status_ring[1]), &(olympic_priv->olympic_rx_status_ring[2]), &(olympic_priv->olympic_rx_status_ring[3]) ); printk(" stat_ring[4]: %p, stat_ring[5]: %p, stat_ring[6]: %p\n", &(olympic_priv->olympic_rx_status_ring[4]), &(olympic_priv->olympic_rx_status_ring[5]), &(olympic_priv->olympic_rx_status_ring[6]) ); printk(" stat_ring[7]: %p\n", &(olympic_priv->olympic_rx_status_ring[7]) ); printk("RXCDA: %x, rx_ring[0]: %p\n",readl(olympic_mmio+RXCDA),&olympic_priv->olympic_rx_ring[0]); printk("Rx_ring_dma_addr = %08x, rx_status_dma_addr = %08x\n", olympic_priv->rx_ring_dma_addr,olympic_priv->rx_status_ring_dma_addr) ; #endif writew((((readw(olympic_mmio+RXENQ)) & 0x8000) ^ 0x8000) | i,olympic_mmio+RXENQ);#if OLYMPIC_DEBUG printk("# of rx buffers: %d, RXENQ: %x\n",i, readw(olympic_mmio+RXENQ)); printk("RXCSA: %x, rx_ring[0]: %p\n",readl(olympic_mmio+RXCSA),&olympic_priv->olympic_rx_status_ring[0]); printk("RXCDA: %x, rx_ring[0]: %p\n",readl(olympic_mmio+RXCDA),&olympic_priv->olympic_rx_ring[0]);#endif writel(SISR_RX_STATUS | SISR_RX_NOBUF,olympic_mmio+SISR_MASK_SUM); /* setup tx ring */ writel(BMCTL_TX1_DIS,olympic_mmio+BMCTL_RWM); /* Yes, this enables TX channel 1 */ for(i=0;i<OLYMPIC_TX_RING_SIZE;i++) olympic_priv->olympic_tx_ring[i].buffer=0xdeadbeef; olympic_priv->free_tx_ring_entries=OLYMPIC_TX_RING_SIZE; olympic_priv->tx_ring_dma_addr = pci_map_single(olympic_priv->pdev,olympic_priv->olympic_tx_ring, sizeof(struct olympic_tx_desc) * OLYMPIC_TX_RING_SIZE,PCI_DMA_TODEVICE) ; writel(olympic_priv->tx_ring_dma_addr, olympic_mmio+TXDESCQ_1); writel(olympic_priv->tx_ring_dma_addr, olympic_mmio+TXCDA_1); writew(OLYMPIC_TX_RING_SIZE, olympic_mmio+TXDESCQCNT_1); olympic_priv->tx_status_ring_dma_addr = pci_map_single(olympic_priv->pdev, olympic_priv->olympic_tx_status_ring, sizeof(struct olympic_tx_status) * OLYMPIC_TX_RING_SIZE, PCI_DMA_FROMDEVICE); writel(olympic_priv->tx_status_ring_dma_addr,olympic_mmio+TXSTATQ_1); writel(olympic_priv->tx_status_ring_dma_addr,olympic_mmio+TXCSA_1); writew(OLYMPIC_TX_RING_SIZE,olympic_mmio+TXSTATQCNT_1); olympic_priv->tx_ring_free=0; /* next entry in tx ring to use */ olympic_priv->tx_ring_last_status=OLYMPIC_TX_RING_SIZE-1; /* last processed tx status */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -