📄 spider_net.c
字号:
* packets, including updating the queue tail pointer. */static voidspider_net_cleanup_tx_ring(struct spider_net_card *card){ if ((spider_net_release_tx_chain(card, 0) != 0) && (card->netdev->flags & IFF_UP)) { spider_net_kick_tx_dma(card); netif_wake_queue(card->netdev); }}/** * spider_net_do_ioctl - called for device ioctls * @netdev: interface device structure * @ifr: request parameter structure for ioctl * @cmd: command code for ioctl * * returns 0 on success, <0 on failure. Currently, we have no special ioctls. * -EOPNOTSUPP is returned, if an unknown ioctl was requested */static intspider_net_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd){ switch (cmd) { default: return -EOPNOTSUPP; }}/** * spider_net_pass_skb_up - takes an skb from a descriptor and passes it on * @descr: descriptor to process * @card: card structure * * Fills out skb structure and passes the data to the stack. * The descriptor state is not changed. */static voidspider_net_pass_skb_up(struct spider_net_descr *descr, struct spider_net_card *card){ struct spider_net_hw_descr *hwdescr = descr->hwdescr; struct sk_buff *skb = descr->skb; struct net_device *netdev = card->netdev; u32 data_status = hwdescr->data_status; u32 data_error = hwdescr->data_error; skb_put(skb, hwdescr->valid_size); /* the card seems to add 2 bytes of junk in front * of the ethernet frame */#define SPIDER_MISALIGN 2 skb_pull(skb, SPIDER_MISALIGN); skb->protocol = eth_type_trans(skb, netdev); /* checksum offload */ if (card->options.rx_csum) { if ( ( (data_status & SPIDER_NET_DATA_STATUS_CKSUM_MASK) == SPIDER_NET_DATA_STATUS_CKSUM_MASK) && !(data_error & SPIDER_NET_DATA_ERR_CKSUM_MASK)) skb->ip_summed = CHECKSUM_UNNECESSARY; else skb->ip_summed = CHECKSUM_NONE; } else skb->ip_summed = CHECKSUM_NONE; if (data_status & SPIDER_NET_VLAN_PACKET) { /* further enhancements: HW-accel VLAN * vlan_hwaccel_receive_skb */ } /* update netdevice statistics */ netdev->stats.rx_packets++; netdev->stats.rx_bytes += skb->len; /* pass skb up to stack */ netif_receive_skb(skb);}static void show_rx_chain(struct spider_net_card *card){ struct spider_net_descr_chain *chain = &card->rx_chain; struct spider_net_descr *start= chain->tail; struct spider_net_descr *descr= start; struct spider_net_hw_descr *hwd = start->hwdescr; struct device *dev = &card->netdev->dev; u32 curr_desc, next_desc; int status; int tot = 0; int cnt = 0; int off = start - chain->ring; int cstat = hwd->dmac_cmd_status; dev_info(dev, "Total number of descrs=%d\n", chain->num_desc); dev_info(dev, "Chain tail located at descr=%d, status=0x%x\n", off, cstat); curr_desc = spider_net_read_reg(card, SPIDER_NET_GDACTDPA); next_desc = spider_net_read_reg(card, SPIDER_NET_GDACNEXTDA); status = cstat; do { hwd = descr->hwdescr; off = descr - chain->ring; status = hwd->dmac_cmd_status; if (descr == chain->head) dev_info(dev, "Chain head is at %d, head status=0x%x\n", off, status); if (curr_desc == descr->bus_addr) dev_info(dev, "HW curr desc (GDACTDPA) is at %d, status=0x%x\n", off, status); if (next_desc == descr->bus_addr) dev_info(dev, "HW next desc (GDACNEXTDA) is at %d, status=0x%x\n", off, status); if (hwd->next_descr_addr == 0) dev_info(dev, "chain is cut at %d\n", off); if (cstat != status) { int from = (chain->num_desc + off - cnt) % chain->num_desc; int to = (chain->num_desc + off - 1) % chain->num_desc; dev_info(dev, "Have %d (from %d to %d) descrs " "with stat=0x%08x\n", cnt, from, to, cstat); cstat = status; cnt = 0; } cnt ++; tot ++; descr = descr->next; } while (descr != start); dev_info(dev, "Last %d descrs with stat=0x%08x " "for a total of %d descrs\n", cnt, cstat, tot);#ifdef DEBUG /* Now dump the whole ring */ descr = start; do { struct spider_net_hw_descr *hwd = descr->hwdescr; status = spider_net_get_descr_status(hwd); cnt = descr - chain->ring; dev_info(dev, "Descr %d stat=0x%08x skb=%p\n", cnt, status, descr->skb); dev_info(dev, "bus addr=%08x buf addr=%08x sz=%d\n", descr->bus_addr, hwd->buf_addr, hwd->buf_size); dev_info(dev, "next=%08x result sz=%d valid sz=%d\n", hwd->next_descr_addr, hwd->result_size, hwd->valid_size); dev_info(dev, "dmac=%08x data stat=%08x data err=%08x\n", hwd->dmac_cmd_status, hwd->data_status, hwd->data_error); dev_info(dev, "\n"); descr = descr->next; } while (descr != start);#endif}/** * spider_net_resync_head_ptr - Advance head ptr past empty descrs * * If the driver fails to keep up and empty the queue, then the * hardware wil run out of room to put incoming packets. This * will cause the hardware to skip descrs that are full (instead * of halting/retrying). Thus, once the driver runs, it wil need * to "catch up" to where the hardware chain pointer is at. */static void spider_net_resync_head_ptr(struct spider_net_card *card){ unsigned long flags; struct spider_net_descr_chain *chain = &card->rx_chain; struct spider_net_descr *descr; int i, status; /* Advance head pointer past any empty descrs */ descr = chain->head; status = spider_net_get_descr_status(descr->hwdescr); if (status == SPIDER_NET_DESCR_NOT_IN_USE) return; spin_lock_irqsave(&chain->lock, flags); descr = chain->head; status = spider_net_get_descr_status(descr->hwdescr); for (i=0; i<chain->num_desc; i++) { if (status != SPIDER_NET_DESCR_CARDOWNED) break; descr = descr->next; status = spider_net_get_descr_status(descr->hwdescr); } chain->head = descr; spin_unlock_irqrestore(&chain->lock, flags);}static int spider_net_resync_tail_ptr(struct spider_net_card *card){ struct spider_net_descr_chain *chain = &card->rx_chain; struct spider_net_descr *descr; int i, status; /* Advance tail pointer past any empty and reaped descrs */ descr = chain->tail; status = spider_net_get_descr_status(descr->hwdescr); for (i=0; i<chain->num_desc; i++) { if ((status != SPIDER_NET_DESCR_CARDOWNED) && (status != SPIDER_NET_DESCR_NOT_IN_USE)) break; descr = descr->next; status = spider_net_get_descr_status(descr->hwdescr); } chain->tail = descr; if ((i == chain->num_desc) || (i == 0)) return 1; return 0;}/** * spider_net_decode_one_descr - processes an RX descriptor * @card: card structure * * Returns 1 if a packet has been sent to the stack, otherwise 0. * * Processes an RX descriptor by iommu-unmapping the data buffer * and passing the packet up to the stack. This function is called * in softirq context, e.g. either bottom half from interrupt or * NAPI polling context. */static intspider_net_decode_one_descr(struct spider_net_card *card){ struct net_device *dev = card->netdev; struct spider_net_descr_chain *chain = &card->rx_chain; struct spider_net_descr *descr = chain->tail; struct spider_net_hw_descr *hwdescr = descr->hwdescr; u32 hw_buf_addr; int status; status = spider_net_get_descr_status(hwdescr); /* Nothing in the descriptor, or ring must be empty */ if ((status == SPIDER_NET_DESCR_CARDOWNED) || (status == SPIDER_NET_DESCR_NOT_IN_USE)) return 0; /* descriptor definitively used -- move on tail */ chain->tail = descr->next; /* unmap descriptor */ hw_buf_addr = hwdescr->buf_addr; hwdescr->buf_addr = 0xffffffff; pci_unmap_single(card->pdev, hw_buf_addr, SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE); if ( (status == SPIDER_NET_DESCR_RESPONSE_ERROR) || (status == SPIDER_NET_DESCR_PROTECTION_ERROR) || (status == SPIDER_NET_DESCR_FORCE_END) ) { if (netif_msg_rx_err(card)) dev_err(&dev->dev, "dropping RX descriptor with state %d\n", status); dev->stats.rx_dropped++; goto bad_desc; } if ( (status != SPIDER_NET_DESCR_COMPLETE) && (status != SPIDER_NET_DESCR_FRAME_END) ) { if (netif_msg_rx_err(card)) dev_err(&card->netdev->dev, "RX descriptor with unknown state %d\n", status); card->spider_stats.rx_desc_unk_state++; goto bad_desc; } /* The cases we'll throw away the packet immediately */ if (hwdescr->data_error & SPIDER_NET_DESTROY_RX_FLAGS) { if (netif_msg_rx_err(card)) dev_err(&card->netdev->dev, "error in received descriptor found, " "data_status=x%08x, data_error=x%08x\n", hwdescr->data_status, hwdescr->data_error); goto bad_desc; } if (hwdescr->dmac_cmd_status & SPIDER_NET_DESCR_BAD_STATUS) { dev_err(&card->netdev->dev, "bad status, cmd_status=x%08x\n", hwdescr->dmac_cmd_status); pr_err("buf_addr=x%08x\n", hw_buf_addr); pr_err("buf_size=x%08x\n", hwdescr->buf_size); pr_err("next_descr_addr=x%08x\n", hwdescr->next_descr_addr); pr_err("result_size=x%08x\n", hwdescr->result_size); pr_err("valid_size=x%08x\n", hwdescr->valid_size); pr_err("data_status=x%08x\n", hwdescr->data_status); pr_err("data_error=x%08x\n", hwdescr->data_error); pr_err("which=%ld\n", descr - card->rx_chain.ring); card->spider_stats.rx_desc_error++; goto bad_desc; } /* Ok, we've got a packet in descr */ spider_net_pass_skb_up(descr, card); descr->skb = NULL; hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE; return 1;bad_desc: if (netif_msg_rx_err(card)) show_rx_chain(card); dev_kfree_skb_irq(descr->skb); descr->skb = NULL; hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE; return 0;}/** * spider_net_poll - NAPI poll function called by the stack to return packets * @netdev: interface device structure * @budget: number of packets we can pass to the stack at most * * returns 0 if no more packets available to the driver/stack. Returns 1, * if the quota is exceeded, but the driver has still packets. * * spider_net_poll returns all packets from the rx descriptors to the stack * (using netif_receive_skb). If all/enough packets are up, the driver * reenables interrupts and returns 0. If not, 1 is returned. */static int spider_net_poll(struct napi_struct *napi, int budget){ struct spider_net_card *card = container_of(napi, struct spider_net_card, napi); struct net_device *netdev = card->netdev; int packets_done = 0; while (packets_done < budget) { if (!spider_net_decode_one_descr(card)) break; packets_done++; } if ((packets_done == 0) && (card->num_rx_ints != 0)) { if (!spider_net_resync_tail_ptr(card)) packets_done = budget; spider_net_resync_head_ptr(card); } card->num_rx_ints = 0; spider_net_refill_rx_chain(card); spider_net_enable_rxdmac(card); spider_net_cleanup_tx_ring(card); /* if all packets are in the stack, enable interrupts and return 0 */ /* if not, return 1 */ if (packets_done < budget) { netif_rx_complete(netdev, napi); spider_net_rx_irq_on(card); card->ignore_rx_ramfull = 0; } return packets_done;}/** * spider_net_change_mtu - changes the MTU of an interface * @netdev: interface device structure * @new_mtu: new MTU value * * returns 0 on success, <0 on failure */static intspider_net_change_mtu(struct net_device *netdev, int new_mtu){ /* no need to re-alloc skbs or so -- the max mtu is about 2.3k * and mtu is outbound only anyway */ if ( (new_mtu < SPIDER_NET_MIN_MTU ) || (new_mtu > SPIDER_NET_MAX_MTU) ) return -EINVAL; netdev->mtu = new_mtu; return 0;}/** * spider_net_set_mac - sets the MAC of an interface * @netdev: interface device structure * @ptr: pointer to new MAC address * * Returns 0 on success, <0 on failure. Currently, we don't support this * and will always return EOPNOTSUPP. */static intspider_net_set_mac(struct net_device *netdev, void *p){ struct spider_net_card *card = netdev_priv(netdev); u32 macl, macu, regvalue; struct sockaddr *addr = p; if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; /* switch off GMACTPE and GMACRPE */ regvalue = spider_net_read_reg(card, SPIDER_NET_GMACOPEMD); regvalue &= ~((1 << 5) | (1 << 6)); spider_net_write_reg(card, SPIDER_NET_GMACOPEMD, regvalue); /* write mac */ macu = (addr->sa_data[0]<<24) + (addr->sa_data[1]<<16) + (addr->sa_data[2]<<8) + (addr->sa_data[3]); macl = (addr->sa_data[4]<<8) + (addr->sa_data[5]); spider_net_write_reg(card, SPIDER_NET_GMACUNIMACU, macu); spider_net_write_reg(card, SPIDER_NET_GMACUNIMACL, macl); /* switch GMACTPE and GMACRPE back on */ regvalue = spider_net_read_reg(card, SPIDER_NET_GMACOPEMD); regvalue |= ((1 << 5) | (1 << 6)); spider_net_write_reg(card, SPIDER_NET_GMACOPEMD, regvalue); spider_net_set_promisc(card); /* look up, whether we have been successful */ if (spider_net_get_mac_address(netdev)) return -EADDRNOTAVAIL; if (memcmp(netdev->dev_addr,addr->sa_data,netdev->addr_len)) return -EADDRNOTAVAIL; return 0;}/** * spider_net_link_reset * @netdev: net device structure * * This is called when the PHY_LINK signal is asserted. For the blade this is * not connected so we should never get here. * */static voidspider_net_link_reset(struct net_device *netdev){ struct spider_net_card *card = netdev_priv(netdev); del_timer_sync(&card->aneg_timer); /* clear interrupt, block further interrupts */ spider_net_write_reg(card, SPIDER_NET_GMACST, spider_net_read_reg(card, SPIDER_NET_GMACST)); spider_net_write_reg(card, SPIDER_NET_GMACINTEN, 0); /* reset phy and setup aneg */ spider_net_setup_aneg(card); mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER);}/** * spider_net_handle_error_irq - handles errors raised by an interrupt * @card: card structure * @status_reg: interrupt status register 0 (GHIINT0STS)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -