📄 3c527.c
字号:
if(lp->exec_pending) return -1; lp->exec_pending=3; lp->exec_box->mbox=0; lp->exec_box->mbox=cmd; memcpy((void *)lp->exec_box->data, data, len); barrier(); /* the memcpy forgot the volatile so be sure */ /* Send the command */ while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); outb(1<<6, ioaddr+HOST_CMD); return 0;}/** * mc32_command: * @dev: The 3c527 card to issue the command to * @cmd: The command word to write to the mailbox * @data: A data block if the command expects one * @len: Length of the data block * * Sends exec commands in a user context. This permits us to wait around * for the replies and also to wait for the command buffer to complete * from a previous command before we execute our command. After our * command completes we will complete any pending multicast reload * we blocked off by hogging the exec buffer. * * You feed the card a command, you wait, it interrupts you get a * reply. All well and good. The complication arises because you use * commands for filter list changes which come in at bh level from things * like IPV6 group stuff. * * We have a simple state machine * * 0 - nothing issued * * 1 - command issued, wait reply * * 2 - reply waiting - reader then goes to state 0 * * 3 - command issued, trash reply. In which case the irq * takes it back to state 0 * * Send command and block for results. On completion spot and reissue * multicasts */ static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len){ struct mc32_local *lp = (struct mc32_local *)dev->priv; int ioaddr = dev->base_addr; unsigned long flags; int ret = 0; /* * Wait for a command */ save_flags(flags); cli(); while(lp->exec_pending) sleep_on(&lp->event); /* * Issue mine */ lp->exec_pending=1; restore_flags(flags); lp->exec_box->mbox=0; lp->exec_box->mbox=cmd; memcpy((void *)lp->exec_box->data, data, len); barrier(); /* the memcpy forgot the volatile so be sure */ /* Send the command */ while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); outb(1<<6, ioaddr+HOST_CMD); save_flags(flags); cli(); while(lp->exec_pending!=2) sleep_on(&lp->event); lp->exec_pending=0; restore_flags(flags); if(lp->exec_box->data[0]&(1<<13)) ret = -1; /* * A multicast set got blocked - do it now */ if(lp->mc_reload_wait) mc32_reset_multicast_list(dev); return ret;}/** * mc32_rx_abort: * @dev: 3c527 to abort * * Peforms a receive abort sequence on the card. In fact after some * experimenting we now simply tell the card to suspend reception. When * issuing aborts occasionally odd things happened. */ static void mc32_rx_abort(struct net_device *dev){ struct mc32_local *lp = (struct mc32_local *)dev->priv; int ioaddr = dev->base_addr; while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); lp->rx_box->mbox=0; outb(3<<3, ioaddr+HOST_CMD); /* Suspend reception */} /** * mc32_rx_begin: * @dev: 3c527 to enable * * We wait for any pending command to complete and then issue * a start reception command to the board itself. At this point * receive handling continues as it was before. */ static void mc32_rx_begin(struct net_device *dev){ struct mc32_local *lp = (struct mc32_local *)dev->priv; int ioaddr = dev->base_addr; while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); lp->rx_box->mbox=0; outb(1<<3, ioaddr+HOST_CMD); /* GO */ mc32_ring_poll(dev); lp->rx_halted=0; lp->rx_pending=0;}/** * mc32_tx_abort: * @dev: 3c527 to abort * * Peforms a receive abort sequence on the card. In fact after some * experimenting we now simply tell the card to suspend transmits . When * issuing aborts occasionally odd things happened. In theory we want * an abort to be sure we can recycle our buffers. As it happens we * just have to be careful to shut the card down on close, and * boot it carefully from scratch on setup. */ static void mc32_tx_abort(struct net_device *dev){ struct mc32_local *lp = (struct mc32_local *)dev->priv; int ioaddr = dev->base_addr; while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); lp->tx_box->mbox=0; outb(3, ioaddr+HOST_CMD); /* Suspend */ /* Ring empty */ atomic_set(&lp->tx_count, lp->tx_len); /* Flush */ if(lp->tx_skb_top!=lp->tx_skb_end) { int i; if(lp->tx_skb_top<=lp->tx_skb_end) { for(i=lp->tx_skb_top;i<lp->tx_skb_end;i++) { dev_kfree_skb(lp->tx_skb[i]); lp->tx_skb[i]=NULL; } } else { for(i=lp->tx_skb_end;i<TX_RING_MAX;i++) { dev_kfree_skb(lp->tx_skb[i]); lp->tx_skb[i]=NULL; } for(i=0;i<lp->tx_skb_top;i++) { dev_kfree_skb(lp->tx_skb[i]); lp->tx_skb[i]=NULL; } } } lp->tx_skb_top=lp->tx_skb_end=0;}/** * mc32_tx_begin: * @dev: 3c527 to enable * * We wait for any pending command to complete and then issue * a start transmit command to the board itself. At this point * transmit handling continues as it was before. The ring must * be setup before you do this and must have an end marker in it. * It turns out we can avoid issuing this specific command when * doing our setup so we avoid it. */ static void mc32_tx_begin(struct net_device *dev){ struct mc32_local *lp = (struct mc32_local *)dev->priv; int ioaddr = dev->base_addr; while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); lp->tx_box->mbox=0;#if 0 outb(5, ioaddr+HOST_CMD); /* GO */ printk("TX=>5\n"); mc32_ring_poll(dev); if(lp->tx_box->mbox&(1<<13)) printk("TX begin error!\n");#endif lp->tx_halted=0;} /** * mc32_load_rx_ring: * @dev: 3c527 to build the ring for * * The card setups up the receive ring for us. We are required to * use the ring it provides although we can change the size of the * ring. * * We allocate an sk_buff for each ring entry in turn and set the entry * up for a single non s/g buffer. The first buffer we mark with the * end marker bits. Finally we clear the rx mailbox. */ static int mc32_load_rx_ring(struct net_device *dev){ struct mc32_local *lp = (struct mc32_local *)dev->priv; int i; u16 base; volatile struct skb_header *p; base = lp->rx_box->data[0]; /* Fix me - should use card size - also fix flush ! */ for(i=0;i<RX_RING_MAX;i++) { lp->rx_skb[i]=alloc_skb(1532, GFP_KERNEL); if(lp->rx_skb[i]==NULL) { for(;i>=0;i--) kfree_skb(lp->rx_skb[i]); return -ENOBUFS; } lp->rx_ptr[i]=lp->rx_skb[i]->data+18; p=bus_to_virt(lp->base+base); p->control=0; p->data = virt_to_bus(lp->rx_ptr[i]); p->status=0; p->length = 1532; base = p->next; } p->control = (1<<6); lp->rx_box->mbox = 0; return 0;} /** * mc32_flush_rx_ring: * @lp: Local data of 3c527 to flush the rx ring of * * Free the buffer for each ring slot. Because of the receive * algorithm we use the ring will always be loaded will a full set * of buffers. */static void mc32_flush_rx_ring(struct mc32_local *lp){ int i; for(i=0;i<RX_RING_MAX;i++) kfree_skb(lp->rx_skb[i]);}/** * mc32_flush_tx_ring: * @lp: Local data of 3c527 to flush the tx ring of * * We have to consider two cases here. We want to free the pending * buffers only. If the ring buffer head is past the start then the * ring segment we wish to free wraps through zero. */static void mc32_flush_tx_ring(struct mc32_local *lp){ int i; if(lp->tx_skb_top <= lp->tx_skb_end) { for(i=lp->tx_skb_top;i<lp->tx_skb_end;i++) dev_kfree_skb(lp->tx_skb[i]); } else { for(i=0;i<lp->tx_skb_end;i++) dev_kfree_skb(lp->tx_skb[i]); for(i=lp->tx_skb_top;i<TX_RING_MAX;i++) dev_kfree_skb(lp->tx_skb[i]); }} /** * mc32_open * @dev: device to open * * The user is trying to bring the card into ready state. This requires * a brief dialogue with the card. Firstly we enable interrupts and then * 'indications'. Without these enabled the card doesn't bother telling * us what it has done. This had me puzzled for a week. * * We then load the network address and multicast filters. Turn on the * workaround mode. This works around a bug in the 82586 - it asks the * firmware to do so. It has a performance hit but is needed on busy * [read most] lans. We load the ring with buffers then we kick it * all off. */static int mc32_open(struct net_device *dev){ int ioaddr = dev->base_addr; u16 zero_word=0; u8 one=1; u8 regs; /* * Interrupts enabled */ regs=inb(ioaddr+HOST_CTRL); regs|=HOST_CTRL_INTE; outb(regs, ioaddr+HOST_CTRL); /* * Send the indications on command */ mc32_command(dev, 4, &one, 2); /* * Send the command sequence "abort, resume" for RX and TX. * The abort cleans up the buffer chains if needed. */ mc32_rx_abort(dev); mc32_tx_abort(dev); /* Set Network Address */ mc32_command(dev, 1, dev->dev_addr, 6); /* Set the filters */ mc32_set_multicast_list(dev); /* Issue the 82586 workaround command - this is for "busy lans", but basically means for all lans now days - has a performance cost but best set */ mc32_command(dev, 0x0D, &zero_word, 2); /* 82586 bug workaround on */ /* Load the ring we just initialised */ if(mc32_load_rx_ring(dev)) { mc32_close(dev); return -ENOBUFS; } /* And the resume command goes last */ mc32_rx_begin(dev); mc32_tx_begin(dev); netif_start_queue(dev); return 0;}/** * mc32_timeout: * @dev: 3c527 that timed out * * Handle a timeout on transmit from the 3c527. This normally means * bad things as the hardware handles cable timeouts and mess for * us. * */static void mc32_timeout(struct net_device *dev){ printk(KERN_WARNING "%s: transmit timed out?\n", dev->name); /* Try to restart the adaptor. */ netif_wake_queue(dev);} /** * mc32_send_packet: * @skb: buffer to transmit * @dev: 3c527 to send it out of * * Transmit a buffer. This normally means throwing the buffer onto * the transmit queue as the queue is quite large. If the queue is * full then we set tx_busy and return. Once the interrupt handler * gets messages telling it to reclaim transmit queue entries we will * clear tx_busy and the kernel will start calling this again. * * We use cli rather than spinlocks. Since I have no access to an SMP * MCA machine I don't plan to change it. It is probably the top * performance hit for this driver on SMP however. */ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev){ struct mc32_local *lp = (struct mc32_local *)dev->priv; int ioaddr = dev->base_addr; unsigned long flags; u16 tx_head; volatile struct skb_header *p, *np; netif_stop_queue(dev); save_flags(flags); cli(); if(atomic_read(&lp->tx_count)==0) { restore_flags(flags); return 1; } tx_head = lp->tx_box->data[0]; atomic_dec(&lp->tx_count); /* We will need this to flush the buffer out */ lp->tx_skb[lp->tx_skb_end] = skb; lp->tx_skb_end++; lp->tx_skb_end&=(TX_RING_MAX-1); /* TX suspend - shouldnt be needed but apparently is. This is a research item ... */ while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); lp->tx_box->mbox=0; outb(3, ioaddr+HOST_CMD); /* Transmit now stopped */ /* P is the last sending/sent buffer as a pointer */ p=(struct skb_header *)bus_to_virt(lp->base+tx_head); /* NP is the buffer we will be loading */ np=(struct skb_header *)bus_to_virt(lp->base+p->next); np->control |= (1<<6); /* EOL */ wmb(); np->length = skb->len; if(np->length < 60) np->length = 60; np->data = virt_to_bus(skb->data); np->status = 0; np->control = (1<<7)|(1<<6); /* EOP EOL */ wmb(); p->status = 0; p->control &= ~(1<<6); while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); lp->tx_box->mbox=0; outb(5, ioaddr+HOST_CMD); /* Restart TX */ restore_flags(flags); netif_wake_queue(dev); return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -