X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fnet%2Fspider_net.c;fp=drivers%2Fnet%2Fspider_net.c;h=1f5975a61e1f1526d8a43869c760ccd96e47753b;hb=64ba3f394c830ec48a1c31b53dcae312c56f1604;hp=88907218457a639d95a313b580631f8fc7e35b1a;hpb=be1e6109ac94a859551f8e1774eb9a8469fe055c;p=linux-2.6.git diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 889072184..1f5975a61 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -21,6 +21,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #include #include #include @@ -84,7 +85,7 @@ MODULE_DEVICE_TABLE(pci, spider_net_pci_tbl); * * returns the content of the specified SMMIO register. */ -static inline u32 +static u32 spider_net_read_reg(struct spider_net_card *card, u32 reg) { u32 value; @@ -101,7 +102,7 @@ spider_net_read_reg(struct spider_net_card *card, u32 reg) * @reg: register to write to * @value: value to write into the specified SMMIO register */ -static inline void +static void spider_net_write_reg(struct spider_net_card *card, u32 reg, u32 value) { value = cpu_to_le32(value); @@ -259,10 +260,39 @@ spider_net_get_mac_address(struct net_device *netdev) * * returns the status as in the dmac_cmd_status field of the descriptor */ -static inline int +static enum spider_net_descr_status spider_net_get_descr_status(struct spider_net_descr *descr) { - return descr->dmac_cmd_status & SPIDER_NET_DESCR_IND_PROC_MASK; + u32 cmd_status; + + cmd_status = descr->dmac_cmd_status; + cmd_status >>= SPIDER_NET_DESCR_IND_PROC_SHIFT; + /* no need to mask out any bits, as cmd_status is 32 bits wide only + * (and unsigned) */ + return cmd_status; +} + +/** + * spider_net_set_descr_status -- sets the status of a descriptor + * @descr: descriptor to change + * @status: status to set in the descriptor + * + * changes the status to the specified value. Doesn't change other bits + * in the status + */ +static void +spider_net_set_descr_status(struct spider_net_descr *descr, + enum spider_net_descr_status status) +{ + u32 cmd_status; + /* read the status */ + cmd_status = descr->dmac_cmd_status; + /* clean the upper 4 bits */ + cmd_status &= SPIDER_NET_DESCR_IND_PROC_MASKO; + /* add the status to it */ + cmd_status |= ((u32)status)<dmac_cmd_status = cmd_status; } /** @@ -299,23 +329,24 @@ spider_net_free_chain(struct spider_net_card *card, static int spider_net_init_chain(struct spider_net_card *card, struct spider_net_descr_chain *chain, - struct spider_net_descr *start_descr, - int direction, int no) + struct spider_net_descr *start_descr, int no) { int i; struct spider_net_descr *descr; dma_addr_t buf; + atomic_set(&card->rx_chain_refill,0); + descr = start_descr; memset(descr, 0, sizeof(*descr) * no); /* set up the hardware pointers in each descriptor */ for (i=0; idmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE; + spider_net_set_descr_status(descr, SPIDER_NET_DESCR_NOT_IN_USE); buf = pci_map_single(card->pdev, descr, SPIDER_NET_DESCR_SIZE, - direction); + PCI_DMA_BIDIRECTIONAL); if (buf == DMA_ERROR_CODE) goto iommu_error; @@ -330,11 +361,10 @@ spider_net_init_chain(struct spider_net_card *card, start_descr->prev = descr-1; descr = start_descr; - if (direction == PCI_DMA_FROMDEVICE) - for (i=0; i < no; i++, descr++) - descr->next_descr_addr = descr->next->bus_addr; + for (i=0; i < no; i++, descr++) { + descr->next_descr_addr = descr->next->bus_addr; + } - spin_lock_init(&chain->lock); chain->head = start_descr; chain->tail = start_descr; @@ -346,7 +376,7 @@ iommu_error: if (descr->bus_addr) pci_unmap_single(card->pdev, descr->bus_addr, SPIDER_NET_DESCR_SIZE, - direction); + PCI_DMA_BIDIRECTIONAL); return -ENOMEM; } @@ -367,7 +397,7 @@ spider_net_free_rx_chain_contents(struct spider_net_card *card) dev_kfree_skb(descr->skb); pci_unmap_single(card->pdev, descr->buf_addr, SPIDER_NET_MAX_FRAME, - PCI_DMA_FROMDEVICE); + PCI_DMA_BIDIRECTIONAL); } descr = descr->next; } @@ -417,16 +447,15 @@ spider_net_prepare_rx_descr(struct spider_net_card *card, skb_reserve(descr->skb, SPIDER_NET_RXBUF_ALIGN - offset); /* io-mmu-map the skb */ buf = pci_map_single(card->pdev, descr->skb->data, - SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE); + SPIDER_NET_MAX_FRAME, PCI_DMA_BIDIRECTIONAL); descr->buf_addr = buf; if (buf == DMA_ERROR_CODE) { dev_kfree_skb_any(descr->skb); if (netif_msg_rx_err(card) && net_ratelimit()) pr_err("Could not iommu-map rx buffer\n"); - descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE; + spider_net_set_descr_status(descr, SPIDER_NET_DESCR_NOT_IN_USE); } else { - descr->dmac_cmd_status = SPIDER_NET_DESCR_CARDOWNED | - SPIDER_NET_DMAC_NOINTR_COMPLETE; + descr->dmac_cmd_status = SPIDER_NET_DMAC_RX_CARDOWNED; } return error; @@ -440,7 +469,7 @@ spider_net_prepare_rx_descr(struct spider_net_card *card, * chip by writing to the appropriate register. DMA is enabled in * spider_net_enable_rxdmac. */ -static inline void +static void spider_net_enable_rxchtails(struct spider_net_card *card) { /* assume chain is aligned correctly */ @@ -455,7 +484,7 @@ spider_net_enable_rxchtails(struct spider_net_card *card) * spider_net_enable_rxdmac enables the DMA controller by setting RX_DMA_EN * in the GDADMACCNTR register */ -static inline void +static void spider_net_enable_rxdmac(struct spider_net_card *card) { wmb(); @@ -472,24 +501,23 @@ spider_net_enable_rxdmac(struct spider_net_card *card) static void spider_net_refill_rx_chain(struct spider_net_card *card) { - struct spider_net_descr_chain *chain = &card->rx_chain; - unsigned long flags; + struct spider_net_descr_chain *chain; + + chain = &card->rx_chain; /* one context doing the refill (and a second context seeing that * and omitting it) is ok. If called by NAPI, we'll be called again * as spider_net_decode_one_descr is called several times. If some * interrupt calls us, the NAPI is about to clean up anyway. */ - if (!spin_trylock_irqsave(&chain->lock, flags)) - return; - - while (spider_net_get_descr_status(chain->head) == - SPIDER_NET_DESCR_NOT_IN_USE) { - if (spider_net_prepare_rx_descr(card, chain->head)) - break; - chain->head = chain->head->next; - } + if (atomic_inc_return(&card->rx_chain_refill) == 1) + while (spider_net_get_descr_status(chain->head) == + SPIDER_NET_DESCR_NOT_IN_USE) { + if (spider_net_prepare_rx_descr(card, chain->head)) + break; + chain->head = chain->head->next; + } - spin_unlock_irqrestore(&chain->lock, flags); + atomic_dec(&card->rx_chain_refill); } /** @@ -526,6 +554,111 @@ error: return result; } +/** + * spider_net_release_tx_descr - processes a used tx descriptor + * @card: card structure + * @descr: descriptor to release + * + * releases a used tx descriptor (unmapping, freeing of skb) + */ +static void +spider_net_release_tx_descr(struct spider_net_card *card, + struct spider_net_descr *descr) +{ + struct sk_buff *skb; + + /* unmap the skb */ + skb = descr->skb; + pci_unmap_single(card->pdev, descr->buf_addr, skb->len, + PCI_DMA_BIDIRECTIONAL); + + dev_kfree_skb_any(skb); + + /* set status to not used */ + spider_net_set_descr_status(descr, SPIDER_NET_DESCR_NOT_IN_USE); +} + +/** + * spider_net_release_tx_chain - processes sent tx descriptors + * @card: adapter structure + * @brutal: if set, don't care about whether descriptor seems to be in use + * + * returns 0 if the tx ring is empty, otherwise 1. + * + * spider_net_release_tx_chain releases the tx descriptors that spider has + * finished with (if non-brutal) or simply release tx descriptors (if brutal). + * If some other context is calling this function, we return 1 so that we're + * scheduled again (if we were scheduled) and will not loose initiative. + */ +static int +spider_net_release_tx_chain(struct spider_net_card *card, int brutal) +{ + struct spider_net_descr_chain *tx_chain = &card->tx_chain; + enum spider_net_descr_status status; + + if (atomic_inc_return(&card->tx_chain_release) != 1) { + atomic_dec(&card->tx_chain_release); + return 1; + } + + for (;;) { + status = spider_net_get_descr_status(tx_chain->tail); + switch (status) { + case SPIDER_NET_DESCR_CARDOWNED: + if (!brutal) + goto out; + /* fallthrough, if we release the descriptors + * brutally (then we don't care about + * SPIDER_NET_DESCR_CARDOWNED) */ + case SPIDER_NET_DESCR_RESPONSE_ERROR: + case SPIDER_NET_DESCR_PROTECTION_ERROR: + case SPIDER_NET_DESCR_FORCE_END: + if (netif_msg_tx_err(card)) + pr_err("%s: forcing end of tx descriptor " + "with status x%02x\n", + card->netdev->name, status); + card->netdev_stats.tx_dropped++; + break; + + case SPIDER_NET_DESCR_COMPLETE: + card->netdev_stats.tx_packets++; + card->netdev_stats.tx_bytes += + tx_chain->tail->skb->len; + break; + + default: /* any other value (== SPIDER_NET_DESCR_NOT_IN_USE) */ + goto out; + } + spider_net_release_tx_descr(card, tx_chain->tail); + tx_chain->tail = tx_chain->tail->next; + } +out: + atomic_dec(&card->tx_chain_release); + + netif_wake_queue(card->netdev); + + if (status == SPIDER_NET_DESCR_CARDOWNED) + return 1; + return 0; +} + +/** + * spider_net_cleanup_tx_ring - cleans up the TX ring + * @card: card structure + * + * spider_net_cleanup_tx_ring is called by the tx_timer (as we don't use + * interrupts to cleanup our TX ring) and returns sent packets to the stack + * by freeing them + */ +static void +spider_net_cleanup_tx_ring(struct spider_net_card *card) +{ + if ( (spider_net_release_tx_chain(card, 0)) && + (card->netdev->flags & IFF_UP) ) { + mod_timer(&card->tx_timer, jiffies + SPIDER_NET_TX_TIMER); + } +} + /** * spider_net_get_multicast_hash - generates hash for multicast filter table * @addr: multicast address @@ -629,128 +762,129 @@ spider_net_disable_rxdmac(struct spider_net_card *card) } /** - * spider_net_prepare_tx_descr - fill tx descriptor with skb data - * @card: card structure - * @descr: descriptor structure to fill out - * @skb: packet to use - * - * returns 0 on success, <0 on failure. + * spider_net_stop - called upon ifconfig down + * @netdev: interface device structure * - * fills out the descriptor structure with skb data and len. Copies data, - * if needed (32bit DMA!) + * always returns 0 */ -static int -spider_net_prepare_tx_descr(struct spider_net_card *card, - struct sk_buff *skb) +int +spider_net_stop(struct net_device *netdev) { - struct spider_net_descr *descr = card->tx_chain.head; - dma_addr_t buf; + struct spider_net_card *card = netdev_priv(netdev); - buf = pci_map_single(card->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); - if (buf == DMA_ERROR_CODE) { - if (netif_msg_tx_err(card) && net_ratelimit()) - pr_err("could not iommu-map packet (%p, %i). " - "Dropping packet\n", skb->data, skb->len); - return -ENOMEM; - } + tasklet_kill(&card->rxram_full_tl); + netif_poll_disable(netdev); + netif_carrier_off(netdev); + netif_stop_queue(netdev); + del_timer_sync(&card->tx_timer); - descr->buf_addr = buf; - descr->buf_size = skb->len; - descr->next_descr_addr = 0; - descr->skb = skb; - descr->data_status = 0; + /* disable/mask all interrupts */ + spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, 0); + spider_net_write_reg(card, SPIDER_NET_GHIINT1MSK, 0); + spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK, 0); - descr->dmac_cmd_status = - SPIDER_NET_DESCR_CARDOWNED | SPIDER_NET_DMAC_NOCS; - if (skb->protocol == htons(ETH_P_IP)) - switch (skb->nh.iph->protocol) { - case IPPROTO_TCP: - descr->dmac_cmd_status |= SPIDER_NET_DMAC_TCP; - break; - case IPPROTO_UDP: - descr->dmac_cmd_status |= SPIDER_NET_DMAC_UDP; - break; - } + /* free_irq(netdev->irq, netdev);*/ + free_irq(to_pci_dev(netdev->class_dev.dev)->irq, netdev); - descr->prev->next_descr_addr = descr->bus_addr; + spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR, + SPIDER_NET_DMA_TX_FEND_VALUE); + + /* turn off DMA, force end */ + spider_net_disable_rxdmac(card); + + /* release chains */ + spider_net_release_tx_chain(card, 1); + + spider_net_free_chain(card, &card->tx_chain); + spider_net_free_chain(card, &card->rx_chain); return 0; } /** - * spider_net_release_tx_descr - processes a used tx descriptor - * @card: card structure - * @descr: descriptor to release + * spider_net_get_next_tx_descr - returns the next available tx descriptor + * @card: device structure to get descriptor from * - * releases a used tx descriptor (unmapping, freeing of skb) + * returns the address of the next descriptor, or NULL if not available. */ -static inline void -spider_net_release_tx_descr(struct spider_net_card *card) +static struct spider_net_descr * +spider_net_get_next_tx_descr(struct spider_net_card *card) { - struct spider_net_descr *descr = card->tx_chain.tail; - struct sk_buff *skb; + /* check, if head points to not-in-use descr */ + if ( spider_net_get_descr_status(card->tx_chain.head) == + SPIDER_NET_DESCR_NOT_IN_USE ) { + return card->tx_chain.head; + } else { + return NULL; + } +} + +/** + * spider_net_set_txdescr_cmdstat - sets the tx descriptor command field + * @descr: descriptor structure to fill out + * @skb: packet to consider + * + * fills out the command and status field of the descriptor structure, + * depending on hardware checksum settings. + */ +static void +spider_net_set_txdescr_cmdstat(struct spider_net_descr *descr, + struct sk_buff *skb) +{ + /* make sure the other fields in the descriptor are written */ + wmb(); - card->tx_chain.tail = card->tx_chain.tail->next; - descr->dmac_cmd_status |= SPIDER_NET_DESCR_NOT_IN_USE; + if (skb->ip_summed != CHECKSUM_HW) { + descr->dmac_cmd_status = SPIDER_NET_DMAC_CMDSTAT_NOCS; + return; + } - /* unmap the skb */ - skb = descr->skb; - pci_unmap_single(card->pdev, descr->buf_addr, skb->len, - PCI_DMA_TODEVICE); - dev_kfree_skb_any(skb); + /* is packet ip? + * if yes: tcp? udp? */ + if (skb->protocol == htons(ETH_P_IP)) { + if (skb->nh.iph->protocol == IPPROTO_TCP) + descr->dmac_cmd_status = SPIDER_NET_DMAC_CMDSTAT_TCPCS; + else if (skb->nh.iph->protocol == IPPROTO_UDP) + descr->dmac_cmd_status = SPIDER_NET_DMAC_CMDSTAT_UDPCS; + else /* the stack should checksum non-tcp and non-udp + packets on his own: NETIF_F_IP_CSUM */ + descr->dmac_cmd_status = SPIDER_NET_DMAC_CMDSTAT_NOCS; + } } /** - * spider_net_release_tx_chain - processes sent tx descriptors - * @card: adapter structure - * @brutal: if set, don't care about whether descriptor seems to be in use + * spider_net_prepare_tx_descr - fill tx descriptor with skb data + * @card: card structure + * @descr: descriptor structure to fill out + * @skb: packet to use * - * returns 0 if the tx ring is empty, otherwise 1. + * returns 0 on success, <0 on failure. * - * spider_net_release_tx_chain releases the tx descriptors that spider has - * finished with (if non-brutal) or simply release tx descriptors (if brutal). - * If some other context is calling this function, we return 1 so that we're - * scheduled again (if we were scheduled) and will not loose initiative. + * fills out the descriptor structure with skb data and len. Copies data, + * if needed (32bit DMA!) */ static int -spider_net_release_tx_chain(struct spider_net_card *card, int brutal) +spider_net_prepare_tx_descr(struct spider_net_card *card, + struct spider_net_descr *descr, + struct sk_buff *skb) { - struct spider_net_descr_chain *chain = &card->tx_chain; - int status; - - spider_net_read_reg(card, SPIDER_NET_GDTDMACCNTR); - - while (chain->tail != chain->head) { - status = spider_net_get_descr_status(chain->tail); - switch (status) { - case SPIDER_NET_DESCR_COMPLETE: - card->netdev_stats.tx_packets++; - card->netdev_stats.tx_bytes += chain->tail->skb->len; - break; + dma_addr_t buf; - case SPIDER_NET_DESCR_CARDOWNED: - if (!brutal) - return 1; - /* fallthrough, if we release the descriptors - * brutally (then we don't care about - * SPIDER_NET_DESCR_CARDOWNED) */ + buf = pci_map_single(card->pdev, skb->data, + skb->len, PCI_DMA_BIDIRECTIONAL); + if (buf == DMA_ERROR_CODE) { + if (netif_msg_tx_err(card) && net_ratelimit()) + pr_err("could not iommu-map packet (%p, %i). " + "Dropping packet\n", skb->data, skb->len); + return -ENOMEM; + } - case SPIDER_NET_DESCR_RESPONSE_ERROR: - case SPIDER_NET_DESCR_PROTECTION_ERROR: - case SPIDER_NET_DESCR_FORCE_END: - if (netif_msg_tx_err(card)) - pr_err("%s: forcing end of tx descriptor " - "with status x%02x\n", - card->netdev->name, status); - card->netdev_stats.tx_errors++; - break; + descr->buf_addr = buf; + descr->buf_size = skb->len; + descr->skb = skb; + descr->data_status = 0; - default: - card->netdev_stats.tx_dropped++; - return 1; - } - spider_net_release_tx_descr(card); - } + spider_net_set_txdescr_cmdstat(descr,skb); return 0; } @@ -763,32 +897,18 @@ spider_net_release_tx_chain(struct spider_net_card *card, int brutal) * spider_net_kick_tx_dma writes the current tx chain head as start address * of the tx descriptor chain and enables the transmission DMA engine */ -static inline void -spider_net_kick_tx_dma(struct spider_net_card *card) +static void +spider_net_kick_tx_dma(struct spider_net_card *card, + struct spider_net_descr *descr) { - struct spider_net_descr *descr; - - if (spider_net_read_reg(card, SPIDER_NET_GDTDMACCNTR) & - SPIDER_NET_TX_DMA_EN) - goto out; + /* this is the only descriptor in the output chain. + * Enable TX DMA */ - descr = card->tx_chain.tail; - for (;;) { - if (spider_net_get_descr_status(descr) == - SPIDER_NET_DESCR_CARDOWNED) { - spider_net_write_reg(card, SPIDER_NET_GDTDCHA, - descr->bus_addr); - spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR, - SPIDER_NET_DMA_TX_VALUE); - break; - } - if (descr == card->tx_chain.head) - break; - descr = descr->next; - } + spider_net_write_reg(card, SPIDER_NET_GDTDCHA, + descr->bus_addr); -out: - mod_timer(&card->tx_timer, jiffies + SPIDER_NET_TX_TIMER); + spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR, + SPIDER_NET_DMA_TX_VALUE); } /** @@ -796,69 +916,47 @@ out: * @skb: packet to send out * @netdev: interface device structure * - * returns 0 on success, !0 on failure + * returns 0 on success, <0 on failure */ static int spider_net_xmit(struct sk_buff *skb, struct net_device *netdev) { struct spider_net_card *card = netdev_priv(netdev); - struct spider_net_descr_chain *chain = &card->tx_chain; - struct spider_net_descr *descr = chain->head; - unsigned long flags; + struct spider_net_descr *descr; int result; - spin_lock_irqsave(&chain->lock, flags); - spider_net_release_tx_chain(card, 0); - if (chain->head->next == chain->tail->prev) { - card->netdev_stats.tx_dropped++; - result = NETDEV_TX_LOCKED; - goto out; - } - - if (spider_net_get_descr_status(descr) != SPIDER_NET_DESCR_NOT_IN_USE) { - result = NETDEV_TX_LOCKED; - goto out; - } + descr = spider_net_get_next_tx_descr(card); - if (spider_net_prepare_tx_descr(card, skb) != 0) { - card->netdev_stats.tx_dropped++; - result = NETDEV_TX_BUSY; - goto out; - } + if (!descr) + goto error; - result = NETDEV_TX_OK; + result = spider_net_prepare_tx_descr(card, descr, skb); + if (result) + goto error; - spider_net_kick_tx_dma(card); card->tx_chain.head = card->tx_chain.head->next; -out: - spin_unlock_irqrestore(&chain->lock, flags); - netif_wake_queue(netdev); - return result; -} - -/** - * spider_net_cleanup_tx_ring - cleans up the TX ring - * @card: card structure - * - * spider_net_cleanup_tx_ring is called by the tx_timer (as we don't use - * interrupts to cleanup our TX ring) and returns sent packets to the stack - * by freeing them - */ -static void -spider_net_cleanup_tx_ring(struct spider_net_card *card) -{ - unsigned long flags; + if (spider_net_get_descr_status(descr->prev) != + SPIDER_NET_DESCR_CARDOWNED) { + /* make sure the current descriptor is in memory. Then + * kicking it on again makes sense, if the previous is not + * card-owned anymore. Check the previous descriptor twice + * to omit an mb() in heavy traffic cases */ + mb(); + if (spider_net_get_descr_status(descr->prev) != + SPIDER_NET_DESCR_CARDOWNED) + spider_net_kick_tx_dma(card, descr); + } - spin_lock_irqsave(&card->tx_chain.lock, flags); + mod_timer(&card->tx_timer, jiffies + SPIDER_NET_TX_TIMER); - if ((spider_net_release_tx_chain(card, 0) != 0) && - (card->netdev->flags & IFF_UP)) - spider_net_kick_tx_dma(card); + return NETDEV_TX_OK; - spin_unlock_irqrestore(&card->tx_chain.lock, flags); +error: + card->netdev_stats.tx_dropped++; + return NETDEV_TX_BUSY; } /** @@ -905,7 +1003,7 @@ spider_net_pass_skb_up(struct spider_net_descr *descr, /* unmap descriptor */ pci_unmap_single(card->pdev, descr->buf_addr, SPIDER_NET_MAX_FRAME, - PCI_DMA_FROMDEVICE); + PCI_DMA_BIDIRECTIONAL); /* the cases we'll throw away the packet immediately */ if (data_error & SPIDER_NET_DESTROY_RX_FLAGS) { @@ -970,11 +1068,14 @@ spider_net_pass_skb_up(struct spider_net_descr *descr, static int spider_net_decode_one_descr(struct spider_net_card *card, int napi) { - struct spider_net_descr_chain *chain = &card->rx_chain; - struct spider_net_descr *descr = chain->tail; - int status; + enum spider_net_descr_status status; + struct spider_net_descr *descr; + struct spider_net_descr_chain *chain; int result; + chain = &card->rx_chain; + descr = chain->tail; + status = spider_net_get_descr_status(descr); if (status == SPIDER_NET_DESCR_CARDOWNED) { @@ -1003,7 +1104,7 @@ spider_net_decode_one_descr(struct spider_net_card *card, int napi) card->netdev->name, status); card->netdev_stats.rx_dropped++; pci_unmap_single(card->pdev, descr->buf_addr, - SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE); + SPIDER_NET_MAX_FRAME, PCI_DMA_BIDIRECTIONAL); dev_kfree_skb_irq(descr->skb); goto refill; } @@ -1019,7 +1120,7 @@ spider_net_decode_one_descr(struct spider_net_card *card, int napi) /* ok, we've got a packet in descr */ result = spider_net_pass_skb_up(descr, card, napi); refill: - descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE; + spider_net_set_descr_status(descr, SPIDER_NET_DESCR_NOT_IN_USE); /* change the descriptor state: */ if (!napi) spider_net_refill_rx_chain(card); @@ -1190,6 +1291,21 @@ spider_net_set_mac(struct net_device *netdev, void *p) return 0; } +/** + * spider_net_enable_txdmac - enables a TX DMA controller + * @card: card structure + * + * spider_net_enable_txdmac enables the TX DMA controller by setting the + * descriptor chain tail address + */ +static void +spider_net_enable_txdmac(struct spider_net_card *card) +{ + /* assume chain is aligned correctly */ + spider_net_write_reg(card, SPIDER_NET_GDTDCHA, + card->tx_chain.tail->bus_addr); +} + /** * spider_net_handle_rxram_full - cleans up RX ring upon RX RAM full interrupt * @card: card structure @@ -1326,7 +1442,7 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg) case SPIDER_NET_GRFAFLLINT: /* fallthrough */ case SPIDER_NET_GRMFLLINT: if (netif_msg_intr(card) && net_ratelimit()) - pr_debug("Spider RX RAM full, incoming packets " + pr_err("Spider RX RAM full, incoming packets " "might be discarded!\n"); spider_net_rx_irq_off(card); tasklet_schedule(&card->rxram_full_tl); @@ -1536,8 +1652,7 @@ spider_net_enable_card(struct spider_net_card *card) { SPIDER_NET_GFTRESTRT, SPIDER_NET_RESTART_VALUE }, { SPIDER_NET_GMRWOLCTRL, 0 }, - { SPIDER_NET_GTESTMD, 0x10000000 }, - { SPIDER_NET_GTTQMSK, 0x00400040 }, + { SPIDER_NET_GTESTMD, 0 }, { SPIDER_NET_GMACINTEN, 0 }, @@ -1576,6 +1691,9 @@ spider_net_enable_card(struct spider_net_card *card) spider_net_write_reg(card, SPIDER_NET_GRXDMAEN, SPIDER_NET_WOL_VALUE); + /* set chain tail adress for TX chain */ + spider_net_enable_txdmac(card); + spider_net_write_reg(card, SPIDER_NET_GMACLENLMT, SPIDER_NET_LENLMT_VALUE); spider_net_write_reg(card, SPIDER_NET_GMACMODE, @@ -1590,9 +1708,6 @@ spider_net_enable_card(struct spider_net_card *card) SPIDER_NET_INT1_MASK_VALUE); spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK, SPIDER_NET_INT2_MASK_VALUE); - - spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR, - SPIDER_NET_GDTDCEIDIS); } /** @@ -1611,12 +1726,11 @@ spider_net_open(struct net_device *netdev) int result; result = -ENOMEM; - if (spider_net_init_chain(card, &card->tx_chain, card->descr, - PCI_DMA_TODEVICE, card->tx_desc)) + if (spider_net_init_chain(card, &card->tx_chain, + card->descr, tx_descriptors)) goto alloc_tx_failed; if (spider_net_init_chain(card, &card->rx_chain, - card->descr + card->rx_desc, - PCI_DMA_FROMDEVICE, card->rx_desc)) + card->descr + tx_descriptors, rx_descriptors)) goto alloc_rx_failed; /* allocate rx skbs */ @@ -1629,7 +1743,7 @@ spider_net_open(struct net_device *netdev) result = -EBUSY; if (request_irq(netdev->irq, spider_net_interrupt, - IRQF_SHARED, netdev->name, netdev)) + SA_SHIRQ, netdev->name, netdev)) goto register_int_failed; spider_net_enable_card(card); @@ -1678,7 +1792,15 @@ spider_net_setup_phy(struct spider_net_card *card) if (phy->def->ops->setup_forced) phy->def->ops->setup_forced(phy, SPEED_1000, DUPLEX_FULL); - phy->def->ops->enable_fiber(phy); + /* the following two writes could be moved to sungem_phy.c */ + /* enable fiber mode */ + spider_net_write_phy(card->netdev, 1, MII_NCONFIG, 0x9020); + /* LEDs active in both modes, autosense prio = fiber */ + spider_net_write_phy(card->netdev, 1, MII_NCONFIG, 0x945f); + + /* switch off fibre autoneg */ + spider_net_write_phy(card->netdev, 1, MII_NCONFIG, 0xfc01); + spider_net_write_phy(card->netdev, 1, 0x0b, 0x0004); phy->def->ops->read_link(phy); pr_info("Found %s with %i Mbps, %s-duplex.\n", phy->def->name, @@ -1823,7 +1945,7 @@ spider_net_workaround_rxramfull(struct spider_net_card *card) /* empty sequencer data */ for (sequencer = 0; sequencer < SPIDER_NET_FIRMWARE_SEQS; sequencer++) { - spider_net_write_reg(card, SPIDER_NET_GSnPRGADR + + spider_net_write_reg(card, SPIDER_NET_GSnPRGDAT + sequencer * 8, 0x0); for (i = 0; i < SPIDER_NET_FIRMWARE_SEQWORDS; i++) { spider_net_write_reg(card, SPIDER_NET_GSnPRGDAT + @@ -1839,49 +1961,6 @@ spider_net_workaround_rxramfull(struct spider_net_card *card) SPIDER_NET_CKRCTRL_STOP_VALUE); } -/** - * spider_net_stop - called upon ifconfig down - * @netdev: interface device structure - * - * always returns 0 - */ -int -spider_net_stop(struct net_device *netdev) -{ - struct spider_net_card *card = netdev_priv(netdev); - - tasklet_kill(&card->rxram_full_tl); - netif_poll_disable(netdev); - netif_carrier_off(netdev); - netif_stop_queue(netdev); - del_timer_sync(&card->tx_timer); - - /* disable/mask all interrupts */ - spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, 0); - spider_net_write_reg(card, SPIDER_NET_GHIINT1MSK, 0); - spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK, 0); - - /* free_irq(netdev->irq, netdev);*/ - free_irq(to_pci_dev(netdev->class_dev.dev)->irq, netdev); - - spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR, - SPIDER_NET_DMA_TX_FEND_VALUE); - - /* turn off DMA, force end */ - spider_net_disable_rxdmac(card); - - /* release chains */ - if (spin_trylock(&card->tx_chain.lock)) { - spider_net_release_tx_chain(card, 1); - spin_unlock(&card->tx_chain.lock); - } - - spider_net_free_chain(card, &card->tx_chain); - spider_net_free_chain(card, &card->rx_chain); - - return 0; -} - /** * spider_net_tx_timeout_task - task scheduled by the watchdog timeout * function (to be called not under interrupt status) @@ -1910,7 +1989,7 @@ spider_net_tx_timeout_task(void *data) goto out; spider_net_open(netdev); - spider_net_kick_tx_dma(card); + spider_net_kick_tx_dma(card, card->tx_chain.head); netif_device_attach(netdev); out: @@ -1993,6 +2072,7 @@ spider_net_setup_netdev(struct spider_net_card *card) pci_set_drvdata(card->pdev, netdev); + atomic_set(&card->tx_chain_release,0); card->rxram_full_tl.data = (unsigned long) card; card->rxram_full_tl.func = (void (*)(unsigned long)) spider_net_handle_rxram_full; @@ -2004,12 +2084,9 @@ spider_net_setup_netdev(struct spider_net_card *card) card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT; - card->tx_desc = tx_descriptors; - card->rx_desc = rx_descriptors; - spider_net_setup_netdev_ops(netdev); - netdev->features = NETIF_F_HW_CSUM | NETIF_F_LLTX; + netdev->features = 0; /* some time: NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | * NETIF_F_HW_VLAN_FILTER */