X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fspider_net.c;h=8aa3ebe2a0ec20fd2f19de5cd744376b6251a400;hb=abdb66b566fce5641c90100e0a113a94bab43fda;hp=f97251a9c850948917f3e2f90cfda91cc405558c;hpb=1cd173f66c392ede57fa10f614fca22d79501424;p=powerpc.git diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index f97251a9c8..8aa3ebe2a0 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -165,6 +165,41 @@ spider_net_read_phy(struct net_device *netdev, int mii_id, int reg) return readvalue; } +/** + * spider_net_setup_aneg - initial auto-negotiation setup + * @card: device structure + **/ +static void +spider_net_setup_aneg(struct spider_net_card *card) +{ + struct mii_phy *phy = &card->phy; + u32 advertise = 0; + u16 bmcr, bmsr, stat1000, estat; + + bmcr = spider_net_read_phy(card->netdev, phy->mii_id, MII_BMCR); + bmsr = spider_net_read_phy(card->netdev, phy->mii_id, MII_BMSR); + stat1000 = spider_net_read_phy(card->netdev, phy->mii_id, MII_STAT1000); + estat = spider_net_read_phy(card->netdev, phy->mii_id, MII_ESTATUS); + + if (bmsr & BMSR_10HALF) + advertise |= ADVERTISED_10baseT_Half; + if (bmsr & BMSR_10FULL) + advertise |= ADVERTISED_10baseT_Full; + if (bmsr & BMSR_100HALF) + advertise |= ADVERTISED_100baseT_Half; + if (bmsr & BMSR_100FULL) + advertise |= ADVERTISED_100baseT_Full; + + if ((bmsr & BMSR_ESTATEN) && (estat & ESTATUS_1000_TFULL)) + advertise |= SUPPORTED_1000baseT_Full; + if ((bmsr & BMSR_ESTATEN) && (estat & ESTATUS_1000_THALF)) + advertise |= SUPPORTED_1000baseT_Half; + + mii_phy_probe(phy, phy->mii_id); + phy->def->ops->setup_aneg(phy, advertise); + +} + /** * spider_net_rx_irq_off - switch off rx irq on this spider card * @card: device structure @@ -367,21 +402,20 @@ spider_net_free_rx_chain_contents(struct spider_net_card *card) } /** - * spider_net_prepare_rx_descr - reinitializes a rx descriptor + * spider_net_prepare_rx_descr - Reinitialize RX descriptor * @card: card structure * @descr: descriptor to re-init * - * return 0 on succes, <0 on failure + * Return 0 on succes, <0 on failure. * - * allocates a new rx skb, iommu-maps it and attaches it to the descriptor. - * Activate the descriptor state-wise + * Allocates a new rx skb, iommu-maps it and attaches it to the + * descriptor. Mark the descriptor as activated, ready-to-use. */ static int spider_net_prepare_rx_descr(struct spider_net_card *card, struct spider_net_descr *descr) { dma_addr_t buf; - int error = 0; int offset; int bufsize; @@ -409,7 +443,7 @@ spider_net_prepare_rx_descr(struct spider_net_card *card, (SPIDER_NET_RXBUF_ALIGN - 1); if (offset) skb_reserve(descr->skb, SPIDER_NET_RXBUF_ALIGN - offset); - /* io-mmu-map the skb */ + /* iommu-map the skb */ buf = pci_map_single(card->pdev, descr->skb->data, SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE); descr->buf_addr = buf; @@ -420,11 +454,16 @@ spider_net_prepare_rx_descr(struct spider_net_card *card, card->spider_stats.rx_iommu_map_error++; descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE; } else { + descr->next_descr_addr = 0; + wmb(); descr->dmac_cmd_status = SPIDER_NET_DESCR_CARDOWNED | SPIDER_NET_DMAC_NOINTR_COMPLETE; + + wmb(); + descr->prev->next_descr_addr = descr->bus_addr; } - return error; + return 0; } /** @@ -488,10 +527,10 @@ spider_net_refill_rx_chain(struct spider_net_card *card) } /** - * spider_net_alloc_rx_skbs - allocates rx skbs in rx descriptor chains + * spider_net_alloc_rx_skbs - Allocates rx skbs in rx descriptor chains * @card: card structure * - * returns 0 on success, <0 on failure + * Returns 0 on success, <0 on failure. */ static int spider_net_alloc_rx_skbs(struct spider_net_card *card) @@ -502,16 +541,16 @@ spider_net_alloc_rx_skbs(struct spider_net_card *card) result = -ENOMEM; chain = &card->rx_chain; - /* put at least one buffer into the chain. if this fails, - * we've got a problem. if not, spider_net_refill_rx_chain - * will do the rest at the end of this function */ + /* Put at least one buffer into the chain. if this fails, + * we've got a problem. If not, spider_net_refill_rx_chain + * will do the rest at the end of this function. */ if (spider_net_prepare_rx_descr(card, chain->head)) goto error; else chain->head = chain->head->next; - /* this will allocate the rest of the rx buffers; if not, it's - * business as usual later on */ + /* This will allocate the rest of the rx buffers; + * if not, it's business as usual later on. */ spider_net_refill_rx_chain(card); spider_net_enable_rxdmac(card); return 0; @@ -911,12 +950,10 @@ spider_net_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) * @descr: descriptor to process * @card: card structure * - * returns 1 on success, 0 if no packet was passed to the stack - * - * iommu-unmaps the skb, fills out skb structure and passes the data to the - * stack. The descriptor state is not changed. + * Fills out skb structure and passes the data to the stack. + * The descriptor state is not changed. */ -static int +static void spider_net_pass_skb_up(struct spider_net_descr *descr, struct spider_net_card *card) { @@ -926,23 +963,8 @@ spider_net_pass_skb_up(struct spider_net_descr *descr, data_status = descr->data_status; data_error = descr->data_error; - netdev = card->netdev; - /* unmap descriptor */ - pci_unmap_single(card->pdev, descr->buf_addr, SPIDER_NET_MAX_FRAME, - PCI_DMA_FROMDEVICE); - - /* the cases we'll throw away the packet immediately */ - if (data_error & SPIDER_NET_DESTROY_RX_FLAGS) { - if (netif_msg_rx_err(card)) - pr_err("error in received descriptor found, " - "data_status=x%08x, data_error=x%08x\n", - data_status, data_error); - card->spider_stats.rx_desc_error++; - return 0; - } - skb = descr->skb; skb->dev = netdev; skb_put(skb, descr->valid_size); @@ -976,9 +998,35 @@ spider_net_pass_skb_up(struct spider_net_descr *descr, /* update netdevice statistics */ card->netdev_stats.rx_packets++; card->netdev_stats.rx_bytes += skb->len; +} - return 1; +#ifdef DEBUG +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; + int status; + + int cnt = 0; + int cstat = spider_net_get_descr_status(descr); + printk(KERN_INFO "RX chain tail at descr=%ld\n", + (start - card->descr) - card->tx_chain.num_desc); + status = cstat; + do + { + status = spider_net_get_descr_status(descr); + if (cstat != status) { + printk(KERN_INFO "Have %d descrs with stat=x%08x\n", cnt, cstat); + cstat = status; + cnt = 0; + } + cnt ++; + descr = descr->next; + } while (descr != start); + printk(KERN_INFO "Last %d descrs with stat=x%08x\n", cnt, cstat); } +#endif /** * spider_net_decode_one_descr - processes an rx descriptor @@ -996,25 +1044,21 @@ spider_net_decode_one_descr(struct spider_net_card *card) struct spider_net_descr_chain *chain = &card->rx_chain; struct spider_net_descr *descr = chain->tail; int status; - int result; status = spider_net_get_descr_status(descr); - /* nothing in the descriptor yet */ - if (status == SPIDER_NET_DESCR_CARDOWNED) - return 0; - - if (status == SPIDER_NET_DESCR_NOT_IN_USE) { - /* not initialized yet, the ring must be empty */ - spider_net_refill_rx_chain(card); - spider_net_enable_rxdmac(card); + /* 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; - result = 0; + /* unmap descriptor */ + pci_unmap_single(card->pdev, descr->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) ) { @@ -1022,27 +1066,55 @@ spider_net_decode_one_descr(struct spider_net_card *card) pr_err("%s: dropping RX descriptor with state %d\n", card->netdev->name, status); card->netdev_stats.rx_dropped++; - pci_unmap_single(card->pdev, descr->buf_addr, - SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE); - dev_kfree_skb_irq(descr->skb); - goto refill; + goto bad_desc; } if ( (status != SPIDER_NET_DESCR_COMPLETE) && (status != SPIDER_NET_DESCR_FRAME_END) ) { if (netif_msg_rx_err(card)) - pr_err("%s: RX descriptor with state %d\n", + pr_err("%s: RX descriptor with unkown state %d\n", card->netdev->name, status); card->spider_stats.rx_desc_unk_state++; - goto refill; + goto bad_desc; } - /* ok, we've got a packet in descr */ - result = spider_net_pass_skb_up(descr, card); -refill: - /* change the descriptor state: */ + /* The cases we'll throw away the packet immediately */ + if (descr->data_error & SPIDER_NET_DESTROY_RX_FLAGS) { + if (netif_msg_rx_err(card)) + pr_err("%s: error in received descriptor found, " + "data_status=x%08x, data_error=x%08x\n", + card->netdev->name, + descr->data_status, descr->data_error); + goto bad_desc; + } + + if (descr->dmac_cmd_status & 0xfefe) { + pr_err("%s: bad status, cmd_status=x%08x\n", + card->netdev->name, + descr->dmac_cmd_status); + pr_err("buf_addr=x%08x\n", descr->buf_addr); + pr_err("buf_size=x%08x\n", descr->buf_size); + pr_err("next_descr_addr=x%08x\n", descr->next_descr_addr); + pr_err("result_size=x%08x\n", descr->result_size); + pr_err("valid_size=x%08x\n", descr->valid_size); + pr_err("data_status=x%08x\n", descr->data_status); + pr_err("data_error=x%08x\n", descr->data_error); + pr_err("bus_addr=x%08x\n", descr->bus_addr); + 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->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE; - return result; + return 1; + +bad_desc: + dev_kfree_skb_irq(descr->skb); + descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE; + return 0; } /** @@ -1081,6 +1153,7 @@ spider_net_poll(struct net_device *netdev, int *budget) netdev->quota -= packets_done; *budget -= packets_done; spider_net_refill_rx_chain(card); + spider_net_enable_rxdmac(card); /* if all packets are in the stack, enable interrupts and return 0 */ /* if not, return 1 */ @@ -1209,6 +1282,33 @@ spider_net_set_mac(struct net_device *netdev, void *p) 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 void +spider_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 @@ -1462,6 +1562,9 @@ spider_net_interrupt(int irq, void *ptr) if (status_reg & SPIDER_NET_TXINT) netif_rx_schedule(netdev); + if (status_reg & SPIDER_NET_LINKINT) + spider_net_link_reset(netdev); + if (status_reg & SPIDER_NET_ERRINT ) spider_net_handle_error_irq(card, status_reg); @@ -1586,8 +1689,6 @@ spider_net_enable_card(struct spider_net_card *card) spider_net_write_reg(card, SPIDER_NET_GMACLENLMT, SPIDER_NET_LENLMT_VALUE); - spider_net_write_reg(card, SPIDER_NET_GMACMODE, - SPIDER_NET_MACMODE_VALUE); spider_net_write_reg(card, SPIDER_NET_GMACOPEMD, SPIDER_NET_OPMODE_VALUE); @@ -1616,9 +1717,13 @@ int spider_net_open(struct net_device *netdev) { struct spider_net_card *card = netdev_priv(netdev); - struct spider_net_descr *descr; int result; + /* start probing with copper */ + spider_net_setup_aneg(card); + if (card->phy.def->phy_id) + mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER); + result = spider_net_init_chain(card, &card->tx_chain); if (result) goto alloc_tx_failed; @@ -1628,13 +1733,6 @@ spider_net_open(struct net_device *netdev) if (result) goto alloc_rx_failed; - /* Make a ring of of bus addresses */ - descr = card->rx_chain.ring; - do { - descr->next_descr_addr = descr->next->bus_addr; - descr = descr->next; - } while (descr != card->rx_chain.ring); - /* Allocate rx skbs */ if (spider_net_alloc_rx_skbs(card)) goto alloc_skbs_failed; @@ -1663,17 +1761,88 @@ alloc_skbs_failed: alloc_rx_failed: spider_net_free_chain(card, &card->tx_chain); alloc_tx_failed: + del_timer_sync(&card->aneg_timer); return result; } +/** + * spider_net_link_phy + * @data: used for pointer to card structure + * + */ +static void spider_net_link_phy(unsigned long data) +{ + struct spider_net_card *card = (struct spider_net_card *)data; + struct mii_phy *phy = &card->phy; + + /* if link didn't come up after SPIDER_NET_ANEG_TIMEOUT tries, setup phy again */ + if (card->aneg_count > SPIDER_NET_ANEG_TIMEOUT) { + + pr_info("%s: link is down trying to bring it up\n", card->netdev->name); + + switch (phy->medium) { + case GMII_COPPER: + /* enable fiber with autonegotiation first */ + if (phy->def->ops->enable_fiber) + phy->def->ops->enable_fiber(phy, 1); + phy->medium = GMII_FIBER; + break; + + case GMII_FIBER: + /* fiber didn't come up, try to disable fiber autoneg */ + if (phy->def->ops->enable_fiber) + phy->def->ops->enable_fiber(phy, 0); + phy->medium = GMII_UNKNOWN; + break; + + case GMII_UNKNOWN: + /* copper, fiber with and without failed, + * retry from beginning */ + spider_net_setup_aneg(card); + phy->medium = GMII_COPPER; + break; + } + + card->aneg_count = 0; + mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER); + return; + } + + /* link still not up, try again later */ + if (!(phy->def->ops->poll_link(phy))) { + card->aneg_count++; + mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER); + return; + } + + /* link came up, get abilities */ + phy->def->ops->read_link(phy); + + spider_net_write_reg(card, SPIDER_NET_GMACST, + spider_net_read_reg(card, SPIDER_NET_GMACST)); + spider_net_write_reg(card, SPIDER_NET_GMACINTEN, 0x4); + + if (phy->speed == 1000) + spider_net_write_reg(card, SPIDER_NET_GMACMODE, 0x00000001); + else + spider_net_write_reg(card, SPIDER_NET_GMACMODE, 0); + + card->aneg_count = 0; + + pr_debug("Found %s with %i Mbps, %s-duplex %sautoneg.\n", + phy->def->name, phy->speed, phy->duplex==1 ? "Full" : "Half", + phy->autoneg==1 ? "" : "no "); + + return; +} + /** * spider_net_setup_phy - setup PHY * @card: card structure * * returns 0 on success, <0 on failure * - * spider_net_setup_phy is used as part of spider_net_probe. Sets - * the PHY to 1000 Mbps + * spider_net_setup_phy is used as part of spider_net_probe. **/ static int spider_net_setup_phy(struct spider_net_card *card) @@ -1684,21 +1853,21 @@ spider_net_setup_phy(struct spider_net_card *card) SPIDER_NET_DMASEL_VALUE); spider_net_write_reg(card, SPIDER_NET_GPCCTRL, SPIDER_NET_PHY_CTRL_VALUE); - phy->mii_id = 1; + phy->dev = card->netdev; phy->mdio_read = spider_net_read_phy; phy->mdio_write = spider_net_write_phy; - mii_phy_probe(phy, phy->mii_id); - - if (phy->def->ops->setup_forced) - phy->def->ops->setup_forced(phy, SPEED_1000, DUPLEX_FULL); - - phy->def->ops->enable_fiber(phy); - - phy->def->ops->read_link(phy); - pr_info("Found %s with %i Mbps, %s-duplex.\n", phy->def->name, - phy->speed, phy->duplex==1 ? "Full" : "Half"); + for (phy->mii_id = 1; phy->mii_id <= 31; phy->mii_id++) { + unsigned short id; + id = spider_net_read_phy(card->netdev, phy->mii_id, MII_BMSR); + if (id != 0x0000 && id != 0xffff) { + if (!mii_phy_probe(phy, phy->mii_id)) { + pr_info("Found %s.\n", phy->def->name); + break; + } + } + } return 0; } @@ -1870,14 +2039,15 @@ spider_net_stop(struct net_device *netdev) netif_carrier_off(netdev); netif_stop_queue(netdev); del_timer_sync(&card->tx_timer); + del_timer_sync(&card->aneg_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); + spider_net_write_reg(card, SPIDER_NET_GMACINTEN, 0); - /* free_irq(netdev->irq, netdev);*/ - free_irq(to_pci_dev(netdev->class_dev.dev)->irq, netdev); + free_irq(netdev->irq, netdev); spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR, SPIDER_NET_DMA_TX_FEND_VALUE); @@ -1889,8 +2059,6 @@ spider_net_stop(struct net_device *netdev) spider_net_release_tx_chain(card, 1); spider_net_free_rx_chain_contents(card); - spider_net_free_rx_chain_contents(card); - spider_net_free_chain(card, &card->tx_chain); spider_net_free_chain(card, &card->rx_chain); @@ -2016,6 +2184,11 @@ spider_net_setup_netdev(struct spider_net_card *card) card->tx_timer.data = (unsigned long) card; netdev->irq = card->pdev->irq; + card->aneg_count = 0; + init_timer(&card->aneg_timer); + card->aneg_timer.function = spider_net_link_phy; + card->aneg_timer.data = (unsigned long) card; + card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT; card->tx_chain.num_desc = tx_descriptors;